Revalidate caches on lock
authorRicardo Labiaga <Ricardo.Labiaga@netapp.com>
Tue, 12 Oct 2010 23:30:05 +0000 (16:30 -0700)
committerTrond Myklebust <Trond.Myklebust@netapp.com>
Sun, 24 Oct 2010 21:59:56 +0000 (17:59 -0400)
Instead of blindly zapping the caches, attempt to revalidate them if
the server has indicated that it uses high resolution timestamps.

NFSv4 should be able to always revalidate the cache since the
protocol requires the update of the change attribute on modification of
the data.  In reality, there are servers (the Linux NFS server
for example) that do not obey this requirement and use ctime as the
basis for change attribute.  Long term, the server needs to be fixed.
At this time, and to be on the safe side, continue zapping caches if
the server indicates that it does not have a high resolution timestamp.

Signed-off-by: Ricardo Labiaga <Ricardo.Labiaga@netapp.com>
Signed-off-by: Trond Myklebust <Trond.Myklebust@netapp.com>
fs/nfs/client.c
fs/nfs/file.c
fs/nfs/nfs3xdr.c
include/linux/nfs_fs_sb.h
include/linux/nfs_xdr.h

index da2f2f024a4de72ec9b20e8a0fdb0498d5916615..a63bce8d05961015ae856ddd00eaefeed9e175b6 100644 (file)
@@ -915,6 +915,8 @@ static void nfs_server_set_fsinfo(struct nfs_server *server, struct nfs_fsinfo *
 
        server->maxfilesize = fsinfo->maxfilesize;
 
+       server->time_delta = fsinfo->time_delta;
+
        /* We're airborne Set socket buffersize */
        rpc_setbufsize(server->client, server->wsize + 100, server->rsize + 100);
 }
index 39672b73173614c49325b15dfc1ab8df59024ce8..c3f2477c16c1de6732d0ff0178c4f6322484765d 100644 (file)
@@ -757,6 +757,11 @@ do_unlk(struct file *filp, int cmd, struct file_lock *fl, int is_local)
        return status;
 }
 
+static int
+is_time_granular(struct timespec *ts) {
+       return ((ts->tv_sec == 0) && (ts->tv_nsec <= 1000));
+}
+
 static int
 do_setlk(struct file *filp, int cmd, struct file_lock *fl, int is_local)
 {
@@ -781,13 +786,21 @@ do_setlk(struct file *filp, int cmd, struct file_lock *fl, int is_local)
                status = do_vfs_lock(filp, fl);
        if (status < 0)
                goto out;
+
        /*
-        * Make sure we clear the cache whenever we try to get the lock.
+        * Revalidate the cache if the server has time stamps granular
+        * enough to detect subsecond changes.  Otherwise, clear the
+        * cache to prevent missing any changes.
+        *
         * This makes locking act as a cache coherency point.
         */
        nfs_sync_mapping(filp->f_mapping);
-       if (!nfs_have_delegation(inode, FMODE_READ))
-               nfs_zap_caches(inode);
+       if (!nfs_have_delegation(inode, FMODE_READ)) {
+               if (is_time_granular(&NFS_SERVER(inode)->time_delta))
+                       __nfs_revalidate_inode(NFS_SERVER(inode), inode);
+               else
+                       nfs_zap_caches(inode);
+       }
 out:
        return status;
 }
index 31a44df40aeacc5f56967874e4c5f3b620099827..d9a5e832c2579f9b20c0164944ae139509d8fb79 100644 (file)
@@ -1044,8 +1044,9 @@ nfs3_xdr_fsinfores(struct rpc_rqst *req, __be32 *p, struct nfs_fsinfo *res)
        res->wtmult = ntohl(*p++);
        res->dtpref = ntohl(*p++);
        p = xdr_decode_hyper(p, &res->maxfilesize);
+       p = xdr_decode_time3(p, &res->time_delta);
 
-       /* ignore time_delta and properties */
+       /* ignore properties */
        res->lease_time = 0;
        return 0;
 }
index c82ee7cd6288573186a664d12b16bdd2a3ea07f1..5eef862ec1871f6c2c2ffc4125f22daed18540d7 100644 (file)
@@ -124,6 +124,7 @@ struct nfs_server {
 
        struct nfs_fsid         fsid;
        __u64                   maxfilesize;    /* maximum file size */
+       struct timespec         time_delta;     /* smallest time granularity */
        unsigned long           mount_time;     /* when this fs was mounted */
        dev_t                   s_dev;          /* superblock dev numbers */
 
index efe2eab8ac945a14ecc0b14be47e8e4eb1c048c2..da7a1300dc60bb01423cafd64cb8028b7de5dcb2 100644 (file)
@@ -112,6 +112,7 @@ struct nfs_fsinfo {
        __u32                   wtmult; /* writes should be multiple of this */
        __u32                   dtpref; /* pref. readdir transfer size */
        __u64                   maxfilesize;
+       struct timespec         time_delta; /* server time granularity */
        __u32                   lease_time; /* in seconds */
 };