patch-1.3.67 linux/fs/nfs/file.c

Next file: linux/fs/nfs/inode.c
Previous file: linux/fs/nfs/Makefile
Back to the patch index
Back to the overall index

diff -u --recursive --new-file v1.3.66/linux/fs/nfs/file.c linux/fs/nfs/file.c
@@ -11,6 +11,8 @@
  *
  *  Expire cache on write to a file by Wai S Kok (Oct 1994).
  *
+ *  Total rewrite of read side for new NFS buffer cache.. Linus.
+ *
  *  nfs regular file handling functions
  */
 
@@ -22,13 +24,16 @@
 #include <linux/mm.h>
 #include <linux/nfs_fs.h>
 #include <linux/malloc.h>
+#include <linux/pagemap.h>
 
 #include <asm/segment.h>
 #include <asm/system.h>
 
+static int nfs_file_mmap(struct inode *, struct file *, struct vm_area_struct *);
 static int nfs_file_read(struct inode *, struct file *, char *, int);
 static int nfs_file_write(struct inode *, struct file *, const char *, int);
 static int nfs_fsync(struct inode *, struct file *);
+static int nfs_readpage(struct inode * inode, struct page * page);
 
 static struct file_operations nfs_file_operations = {
 	NULL,			/* lseek - default */
@@ -37,7 +42,7 @@
 	NULL,			/* readdir - bad */
 	NULL,			/* select - default */
 	NULL,			/* ioctl - default */
-	nfs_mmap,		/* mmap */
+	nfs_file_mmap,		/* mmap */
 	NULL,			/* no special open is needed */
 	NULL,			/* release */
 	nfs_fsync,		/* fsync */
@@ -56,136 +61,98 @@
 	NULL,			/* rename */
 	NULL,			/* readlink */
 	NULL,			/* follow_link */
-	NULL,			/* readpage */
+	nfs_readpage,		/* readpage */
 	NULL,			/* writepage */
 	NULL,			/* bmap */
 	NULL			/* truncate */
 };
 
-/* Once data is inserted, it can only be deleted, if (in_use==0). */
-struct read_cache {
-	int		in_use;		/* currently in use? */
-	unsigned long	inode_num;	/* inode number */
-	off_t		file_pos;	/* file position */
-	int		len;		/* size of data */
-	unsigned long	time;		/* time, this entry was inserted */
-	char *		buf;		/* data */
-	int		buf_size;	/* size of buffer */
-};
+static inline void revalidate_inode(struct nfs_server * server, struct inode * inode)
+{
+	struct nfs_fattr fattr;
 
-#define READ_CACHE_SIZE 5
-#define EXPIRE_CACHE (HZ * 3)		/* keep no longer than 3 seconds */
+	if (jiffies - NFS_READTIME(inode) < server->acregmax)
+		return;
+
+	NFS_READTIME(inode) = jiffies;
+	if (nfs_proc_getattr(server, NFS_FH(inode), &fattr) == 0) {
+		nfs_refresh_inode(inode, &fattr);
+		if (fattr.mtime.seconds == NFS_OLDMTIME(inode))
+			return;
+		NFS_OLDMTIME(inode) = fattr.mtime.seconds;
+	}
+	invalidate_inode_pages(inode, 0);
+}
 
-unsigned long num_requests = 0;
-unsigned long num_cache_hits = 0;
 
-static int tail = 0;	/* next cache slot to replace */
+static int nfs_file_read(struct inode * inode, struct file * file,
+	char * buf, int count)
+{
+	revalidate_inode(NFS_SERVER(inode), inode);
+	return generic_file_read(inode, file, buf, count);
+}
 
-static struct read_cache cache[READ_CACHE_SIZE] = {
-	{ 0, 0, -1, 0, 0, NULL, 0 },
-	{ 0, 0, -1, 0, 0, NULL, 0 },
-	{ 0, 0, -1, 0, 0, NULL, 0 },
-	{ 0, 0, -1, 0, 0, NULL, 0 },
-	{ 0, 0, -1, 0, 0, NULL, 0 } };
+static int nfs_file_mmap(struct inode * inode, struct file * file, struct vm_area_struct * vma)
+{
+	revalidate_inode(NFS_SERVER(inode), inode);
+	return generic_file_mmap(inode, file, vma);
+}
 
 static int nfs_fsync(struct inode *inode, struct file *file)
 {
 	return 0;
 }
 
-static int nfs_file_read(struct inode *inode, struct file *file, char *buf,
-			 int count)
+static inline void do_read_nfs(struct inode * inode, char * buf, unsigned long pos)
 {
-	int result, hunk, i, n, fs;
+	int refresh = 0;
+	int count = PAGE_SIZE;
+	int rsize = NFS_SERVER(inode)->rsize;
 	struct nfs_fattr fattr;
-	char *data;
-	off_t pos;
 
-	if (!inode) {
-		printk("nfs_file_read: inode = NULL\n");
-		return -EINVAL;
-	}
-	if (!S_ISREG(inode->i_mode)) {
-		printk("nfs_file_read: read from non-file, mode %07o\n",
-			inode->i_mode);
-		return -EINVAL;
-	}
-	pos = file->f_pos;
-	if (pos + count > inode->i_size)
-		count = inode->i_size - pos;
-	if (count <= 0)
-		return 0;
-	++num_requests;
-	cli();
-	for (i = 0; i < READ_CACHE_SIZE; i++)
-		if ((cache[i].inode_num == inode->i_ino)
-			&& (cache[i].file_pos <= pos)
-			&& (cache[i].file_pos + cache[i].len >= pos + count)
-			&& (jiffies - cache[i].time < EXPIRE_CACHE))
-			break;
-	if (i < READ_CACHE_SIZE) {
-		++cache[i].in_use;
-		sti();
-		++num_cache_hits;
-		memcpy_tofs(buf, cache[i].buf + pos - cache[i].file_pos, count);
-		--cache[i].in_use;
-		file->f_pos += count;
-		return count;
-	}
-	sti();
-	n = NFS_SERVER(inode)->rsize;
-	for (i = 0; i < count - n; i += n) {
+	do {
+		int result;
+
+		if (count < rsize)
+			rsize = count;
 		result = nfs_proc_read(NFS_SERVER(inode), NFS_FH(inode), 
-			pos, n, buf, &fattr, 1);
+			pos, rsize, buf, &fattr);
 		if (result < 0)
-			return result;
-		pos += result;
-		buf += result;
-		if (result < n) {
-			file->f_pos = pos;
-			nfs_refresh_inode(inode, &fattr);
-			return i + result;
-		}
-	}
-	fs = 0;
-	if (!(data = (char *)kmalloc(n, GFP_KERNEL))) {
-		data = buf;
-		fs = 1;
-	}
-	result = nfs_proc_read(NFS_SERVER(inode), NFS_FH(inode),
-		pos, n, data, &fattr, fs);
-	if (result < 0) {
-		if (!fs)
-			kfree_s(data, n);
-		return result;
-	}
-	hunk = count - i;
-	if (result < hunk)
-		hunk = result;
-	if (fs) {
-		file->f_pos = pos + hunk;
+			goto partial;
+		refresh = 1;
+		count -= rsize;
+		pos += rsize;
+		buf += rsize;
+		if (result < rsize)
+			goto partial;
+	} while (count);
+	nfs_refresh_inode(inode, &fattr);
+	return;
+
+partial:
+	memset(buf, 0, count);
+	if (refresh)
 		nfs_refresh_inode(inode, &fattr);
-		return i + hunk;
+}
+
+static int nfs_readpage(struct inode * inode, struct page * page)
+{
+	unsigned long address;
+
+	address = page_address(page);
+	page->count++;
+	wait_on_page(page);
+	if (page->uptodate) {
+		free_page(address);
+		return 0;
 	}
-	memcpy_tofs(buf, data, hunk);
-	file->f_pos = pos + hunk;
-	nfs_refresh_inode(inode, &fattr);
-	cli();
-	if (cache[tail].in_use == 0) {
-		if (cache[tail].buf)
-			kfree_s(cache[tail].buf, cache[tail].buf_size);
-		cache[tail].buf = data;
-		cache[tail].buf_size = n;
-		cache[tail].inode_num = inode->i_ino;
-		cache[tail].file_pos = pos;
-		cache[tail].len = result;
-		cache[tail].time = jiffies;
-		if (++tail >= READ_CACHE_SIZE)
-			tail = 0;
-	} else
-		kfree_s(data, n);
-	sti();
-	return i + hunk;
+	page->locked = 1;
+	do_read_nfs(inode, (char *) address, page->offset);
+	page->locked = 0;
+	page->uptodate = 1;
+	wake_up(&page->wait);
+	free_page(address);
+	return 0;
 }
 
 static int nfs_file_write(struct inode *inode, struct file *file, const char *buf,
@@ -206,13 +173,6 @@
 	if (count <= 0)
 		return 0;
 
-	cli();
-	/* If hit, cache is dirty and must be expired. */
-	for (i = 0; i < READ_CACHE_SIZE; i++)
-		if(cache[i].inode_num == inode->i_ino)
-			cache[i].time -= EXPIRE_CACHE;
-        sti();
-
 	pos = file->f_pos;
 	if (file->f_flags & O_APPEND)
 		pos = inode->i_size;
@@ -221,7 +181,7 @@
 		hunk = count - i;
 		if (hunk >= n)
 			hunk = n;
-		result = nfs_proc_write(NFS_SERVER(inode), NFS_FH(inode), 
+		result = nfs_proc_write(inode,
 			pos, hunk, buf, &fattr);
 		if (result < 0)
 			return result;

FUNET's LINUX-ADM group, linux-adm@nic.funet.fi
TCL-scripts by Sam Shen, slshen@lbl.gov with Sam's (original) version
of this