summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorRicardo Labiaga <Ricardo.Labiaga@netapp.com>2010-10-12 16:30:05 -0700
committerTrond Myklebust <Trond.Myklebust@netapp.com>2010-10-24 17:59:56 -0400
commit6b96724e507fecc3e6440e86426fe4f44359ed66 (patch)
tree5b38131405301f4dd536a11f44ff0d5e6785d266
parent118df3d17f11733b294ea2cd988d56ee376ef9fd (diff)
downloadlinux-6b96724e507fecc3e6440e86426fe4f44359ed66.tar.bz2
Revalidate caches on lock
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>
-rw-r--r--fs/nfs/client.c2
-rw-r--r--fs/nfs/file.c19
-rw-r--r--fs/nfs/nfs3xdr.c3
-rw-r--r--include/linux/nfs_fs_sb.h1
-rw-r--r--include/linux/nfs_xdr.h1
5 files changed, 22 insertions, 4 deletions
diff --git a/fs/nfs/client.c b/fs/nfs/client.c
index da2f2f024a4d..a63bce8d0596 100644
--- a/fs/nfs/client.c
+++ b/fs/nfs/client.c
@@ -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);
}
diff --git a/fs/nfs/file.c b/fs/nfs/file.c
index 39672b731736..c3f2477c16c1 100644
--- a/fs/nfs/file.c
+++ b/fs/nfs/file.c
@@ -758,6 +758,11 @@ do_unlk(struct file *filp, int cmd, struct file_lock *fl, int is_local)
}
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)
{
struct inode *inode = filp->f_mapping->host;
@@ -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;
}
diff --git a/fs/nfs/nfs3xdr.c b/fs/nfs/nfs3xdr.c
index 31a44df40aea..d9a5e832c257 100644
--- a/fs/nfs/nfs3xdr.c
+++ b/fs/nfs/nfs3xdr.c
@@ -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;
}
diff --git a/include/linux/nfs_fs_sb.h b/include/linux/nfs_fs_sb.h
index c82ee7cd6288..5eef862ec187 100644
--- a/include/linux/nfs_fs_sb.h
+++ b/include/linux/nfs_fs_sb.h
@@ -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 */
diff --git a/include/linux/nfs_xdr.h b/include/linux/nfs_xdr.h
index efe2eab8ac94..da7a1300dc60 100644
--- a/include/linux/nfs_xdr.h
+++ b/include/linux/nfs_xdr.h
@@ -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 */
};