aboutsummaryrefslogtreecommitdiffstats
path: root/fs/nfs/dir.c
diff options
context:
space:
mode:
authorNeil Brown <neilb@suse.de>2007-04-15 19:35:27 -0400
committerTrond Myklebust <Trond.Myklebust@netapp.com>2007-05-01 01:17:18 -0400
commit1f4eab7e7c1d90dcd8ca4d7c064ee78dfbb345eb (patch)
tree06c431bedac14bd907e616c390743795abfb1622 /fs/nfs/dir.c
parent74dd34e6e8bb127ff4c182423154b294729b663b (diff)
NFS: Set meaningful value for fattr->time_start in readdirplus results.
Don't use uninitialsed value for fattr->time_start in readdirplus results. The 'fattr' structure filled in by nfs3_decode_direct does not get a value for ->time_start set. Thus if an entry is for an inode that we already have in cache, when nfs_readdir_lookup calls nfs_fhget, it will call nfs_refresh_inode and may update the inode with out-of-date information. Directories are read a page at a time, so each page could have a different timestamp that "should" be used to set the time_start for the fattr for info in that page. However storing the timestamp per page is awkward. (We could stick in the first 4 bytes and only read 4092 bytes, but that is a bigger code change than I am interested it). This patch ignores the readdir_plus attributes if a readdir finds the information already in cache, and otherwise sets ->time_start to the time the readdir request was sent to the server. It might be nice to store - in the directory inode - the time stamp for the earliest readdir request that is still in the page cache, so that we don't ignore attribute data that we don't have to. This patch doesn't do that. Signed-off-by: Neil Brown <neilb@suse.de> Signed-off-by: Trond Myklebust <Trond.Myklebust@netapp.com>
Diffstat (limited to 'fs/nfs/dir.c')
-rw-r--r--fs/nfs/dir.c16
1 files changed, 16 insertions, 0 deletions
diff --git a/fs/nfs/dir.c b/fs/nfs/dir.c
index cd3469720cbf..d971547ce609 100644
--- a/fs/nfs/dir.c
+++ b/fs/nfs/dir.c
@@ -154,6 +154,8 @@ typedef struct {
154 decode_dirent_t decode; 154 decode_dirent_t decode;
155 int plus; 155 int plus;
156 int error; 156 int error;
157 unsigned long timestamp;
158 int timestamp_valid;
157} nfs_readdir_descriptor_t; 159} nfs_readdir_descriptor_t;
158 160
159/* Now we cache directories properly, by stuffing the dirent 161/* Now we cache directories properly, by stuffing the dirent
@@ -195,6 +197,8 @@ int nfs_readdir_filler(nfs_readdir_descriptor_t *desc, struct page *page)
195 } 197 }
196 goto error; 198 goto error;
197 } 199 }
200 desc->timestamp = timestamp;
201 desc->timestamp_valid = 1;
198 SetPageUptodate(page); 202 SetPageUptodate(page);
199 spin_lock(&inode->i_lock); 203 spin_lock(&inode->i_lock);
200 NFS_I(inode)->cache_validity |= NFS_INO_INVALID_ATIME; 204 NFS_I(inode)->cache_validity |= NFS_INO_INVALID_ATIME;
@@ -225,6 +229,10 @@ int dir_decode(nfs_readdir_descriptor_t *desc)
225 if (IS_ERR(p)) 229 if (IS_ERR(p))
226 return PTR_ERR(p); 230 return PTR_ERR(p);
227 desc->ptr = p; 231 desc->ptr = p;
232 if (desc->timestamp_valid)
233 desc->entry->fattr->time_start = desc->timestamp;
234 else
235 desc->entry->fattr->valid &= ~NFS_ATTR_FATTR;
228 return 0; 236 return 0;
229} 237}
230 238
@@ -316,6 +324,10 @@ int find_dirent_page(nfs_readdir_descriptor_t *desc)
316 __FUNCTION__, desc->page_index, 324 __FUNCTION__, desc->page_index,
317 (long long) *desc->dir_cookie); 325 (long long) *desc->dir_cookie);
318 326
327 /* If we find the page in the page_cache, we cannot be sure
328 * how fresh the data is, so we will ignore readdir_plus attributes.
329 */
330 desc->timestamp_valid = 0;
319 page = read_cache_page(inode->i_mapping, desc->page_index, 331 page = read_cache_page(inode->i_mapping, desc->page_index,
320 (filler_t *)nfs_readdir_filler, desc); 332 (filler_t *)nfs_readdir_filler, desc);
321 if (IS_ERR(page)) { 333 if (IS_ERR(page)) {
@@ -468,6 +480,7 @@ int uncached_readdir(nfs_readdir_descriptor_t *desc, void *dirent,
468 struct rpc_cred *cred = nfs_file_cred(file); 480 struct rpc_cred *cred = nfs_file_cred(file);
469 struct page *page = NULL; 481 struct page *page = NULL;
470 int status; 482 int status;
483 unsigned long timestamp;
471 484
472 dfprintk(DIRCACHE, "NFS: uncached_readdir() searching for cookie %Lu\n", 485 dfprintk(DIRCACHE, "NFS: uncached_readdir() searching for cookie %Lu\n",
473 (unsigned long long)*desc->dir_cookie); 486 (unsigned long long)*desc->dir_cookie);
@@ -477,6 +490,7 @@ int uncached_readdir(nfs_readdir_descriptor_t *desc, void *dirent,
477 status = -ENOMEM; 490 status = -ENOMEM;
478 goto out; 491 goto out;
479 } 492 }
493 timestamp = jiffies;
480 desc->error = NFS_PROTO(inode)->readdir(file->f_path.dentry, cred, *desc->dir_cookie, 494 desc->error = NFS_PROTO(inode)->readdir(file->f_path.dentry, cred, *desc->dir_cookie,
481 page, 495 page,
482 NFS_SERVER(inode)->dtsize, 496 NFS_SERVER(inode)->dtsize,
@@ -487,6 +501,8 @@ int uncached_readdir(nfs_readdir_descriptor_t *desc, void *dirent,
487 desc->page = page; 501 desc->page = page;
488 desc->ptr = kmap(page); /* matching kunmap in nfs_do_filldir */ 502 desc->ptr = kmap(page); /* matching kunmap in nfs_do_filldir */
489 if (desc->error >= 0) { 503 if (desc->error >= 0) {
504 desc->timestamp = timestamp;
505 desc->timestamp_valid = 1;
490 if ((status = dir_decode(desc)) == 0) 506 if ((status = dir_decode(desc)) == 0)
491 desc->entry->prev_cookie = *desc->dir_cookie; 507 desc->entry->prev_cookie = *desc->dir_cookie;
492 } else 508 } else