NFS caching patch.

A.N.Kuznetsov (kuznet@ms2.inr.ac.ru)
Sun, 14 Jul 1996 21:35:57 +0400 (MSD)


Hello!

That's it. It worked for me for a pretty long time,
but I improved it a bit before sending.
Particulary, I discovered that Linux VFS is much
more clever than I believed (Yes, inode->i_mtime is always measured
in server clock!), so that NFS_MTIME_SECS is just removed.

Note that write/setattr hack (and old mechanism for cache
invalidation) is necessary for NFSv2 and will be removed for NFSv3,
which returns weak cache consistency data.
BTW, it is the only essential difference between v2 and v3
and it makes implementation of NFSv3 only more easy,
so that I do not understand why NFSv3 is not in 2.0.0 8)

Alexey Kuznetsov.

diff -ur linux/fs/nfs/dir.c linux-obj/fs/nfs/dir.c
--- linux/fs/nfs/dir.c Sun Jul 14 21:03:44 1996
+++ linux-obj/fs/nfs/dir.c Sun Jul 14 21:07:45 1996
@@ -695,7 +695,9 @@
inode->i_gid = fattr->gid;

/* Size changed from outside: invalidate caches on next read */
- if (inode->i_size != fattr->size)
+ if (inode->i_size != fattr->size ||
+ inode->i_mtime != fattr->mtime.seconds ||
+ NFS_MTIME_USECS(inode) != fattr->mtime.useconds)
NFS_CACHEINV(inode);
inode->i_size = fattr->size;
if (S_ISCHR(inode->i_mode) || S_ISBLK(inode->i_mode))
@@ -705,6 +707,7 @@
inode->i_blocks = fattr->blocks;
inode->i_atime = fattr->atime.seconds;
inode->i_mtime = fattr->mtime.seconds;
+ NFS_MTIME_USECS(inode) = fattr->mtime.useconds;
inode->i_ctime = fattr->ctime.seconds;
if (S_ISREG(inode->i_mode))
inode->i_op = &nfs_file_inode_operations;
diff -ur linux/fs/nfs/file.c linux-obj/fs/nfs/file.c
--- linux/fs/nfs/file.c Sun Jul 14 21:03:44 1996
+++ linux-obj/fs/nfs/file.c Sun Jul 14 21:11:36 1996
@@ -147,8 +147,23 @@
if (pos > inode->i_size)
inode->i_size = pos;
/* Avoid possible Solaris 2.5 nfsd bug */
- if (inode->i_ino == fattr.fileid)
+ if (inode->i_ino == fattr.fileid) {
+
+ /*
+ * It is hack, that cannot be avoided for NFSv2,
+ * because it has no "weak cache consistency" mechanism.
+ * We are deemed to believe, that the file
+ * was not changed since previous getattr (or
+ * another operation returning gratuitous attributes).
+ * Another solution would be to call getattr before
+ * each write :-) --ANK
+ * (see also nfs_notify_change() in inode.c)
+ */
+ inode->i_mtime = fattr.mtime.seconds;
+ NFS_MTIME_USECS(inode) = fattr.mtime.useconds;
+
nfs_refresh_inode(inode, &fattr);
+ }
return written;
}

diff -ur linux/fs/nfs/inode.c linux-obj/fs/nfs/inode.c
--- linux/fs/nfs/inode.c Tue Apr 30 18:13:25 1996
+++ linux-obj/fs/nfs/inode.c Sun Jul 14 21:07:45 1996
@@ -310,8 +310,24 @@

error = nfs_proc_setattr(NFS_SERVER(inode), NFS_FH(inode),
&sattr, &fattr);
- if (!error)
+ if (!error) {
+ /*
+ * More motivations are in file.c nfs_file_write() -- ANK
+ */
+ if ((attr->ia_valid & ATTR_MTIME) ||
+ (sattr.size != (unsigned)-1 && sattr.size != inode->i_size))
+ {
+ inode->i_mtime = fattr.mtime.seconds;
+ NFS_MTIME_USECS(inode) = fattr.mtime.useconds;
+ /*
+ * We got size what we wanted, hence we don't trash cache.
+ * (VM truncation will be done by VFS)
+ */
+ if (sattr.size == fattr.size)
+ inode->i_size = fattr.size;
+ }
nfs_refresh_inode(inode, &fattr);
+ }
inode->i_dirt = 0;
return error;
}
diff -ur linux/include/linux/nfs_fs.h linux-obj/include/linux/nfs_fs.h
--- linux/include/linux/nfs_fs.h Sun Jul 14 21:04:03 1996
+++ linux-obj/include/linux/nfs_fs.h Sun Jul 14 21:07:45 1996
@@ -46,6 +46,7 @@
#define NFS_RENAMED_DIR(inode) ((inode)->u.nfs_i.silly_rename_dir)
#define NFS_READTIME(inode) ((inode)->u.nfs_i.read_cache_jiffies)
#define NFS_OLDMTIME(inode) ((inode)->u.nfs_i.read_cache_mtime)
+#define NFS_MTIME_USECS(inode) ((inode)->u.nfs_i.mtime_usecs)
#define NFS_CACHEINV(inode) \
do { \
NFS_READTIME(inode) = jiffies - 1000000; \
diff -ur linux/include/linux/nfs_fs_i.h linux-obj/include/linux/nfs_fs_i.h
--- linux/include/linux/nfs_fs_i.h Sun Apr 14 23:19:03 1996
+++ linux-obj/include/linux/nfs_fs_i.h Sun Jul 14 21:07:45 1996
@@ -14,14 +14,19 @@
* read_cache_jiffies is when we started read-caching this inode,
* and read_cache_mtime is the mtime of the inode at that time.
*
- * We need to invalidate the cache for this inode if
+ * We force the cache invalidation for this inode if
*
- * jiffies - read_cache_jiffies > 30*HZ
+ * jiffies - read_cache_jiffies > acregmax (usually 60 sec)
* AND
* mtime != read_cache_mtime
+ *
+ * Besides that, we invalidate cache every time when mtime received
+ * from server differs of previous mtime (also received from server,
+ * we never look at our local time)
*/
unsigned long read_cache_jiffies;
unsigned long read_cache_mtime;
+ unsigned long mtime_usecs;
/*
* This is to support the clandestine rename on unlink.
* Instead of the directory inode, we might as well keep its