NFS: Fix a sillyrename race...
authorTrond Myklebust <Trond.Myklebust@netapp.com>
Sat, 26 Jan 2008 22:37:47 +0000 (17:37 -0500)
committerTrond Myklebust <Trond.Myklebust@netapp.com>
Wed, 30 Jan 2008 07:05:21 +0000 (02:05 -0500)
Ensure that readdir revalidates its data cache after blocking on
sillyrename.

Also fix a typo in nfs_do_call_unlink(): swap the ^= for an |=. The result
is the same, since we've already checked that the flag is unset, but it
makes the code more readable.

Signed-off-by: Trond Myklebust <Trond.Myklebust@netapp.com>
fs/nfs/dir.c
fs/nfs/unlink.c

index f697b5c..d9abdb1 100644 (file)
@@ -537,12 +537,6 @@ static int nfs_readdir(struct file *filp, void *dirent, filldir_t filldir)
 
        lock_kernel();
 
-       res = nfs_revalidate_mapping_nolock(inode, filp->f_mapping);
-       if (res < 0) {
-               unlock_kernel();
-               return res;
-       }
-
        /*
         * filp->f_pos points to the dirent entry number.
         * *desc->dir_cookie has the cookie for the next entry. We have
@@ -564,6 +558,10 @@ static int nfs_readdir(struct file *filp, void *dirent, filldir_t filldir)
        desc->entry = &my_entry;
 
        nfs_block_sillyrename(dentry);
+       res = nfs_revalidate_mapping_nolock(inode, filp->f_mapping);
+       if (res < 0)
+               goto out;
+
        while(!desc->entry->eof) {
                res = readdir_search_pagecache(desc);
 
@@ -594,6 +592,7 @@ static int nfs_readdir(struct file *filp, void *dirent, filldir_t filldir)
                        break;
                }
        }
+out:
        nfs_unblock_sillyrename(dentry);
        unlock_kernel();
        if (res > 0)
index 233ad38..c5fa6d8 100644 (file)
@@ -138,7 +138,7 @@ static int nfs_do_call_unlink(struct dentry *parent, struct inode *dir, struct n
                spin_lock(&alias->d_lock);
                if (!(alias->d_flags & DCACHE_NFSFS_RENAMED)) {
                        alias->d_fsdata = data;
-                       alias->d_flags ^= DCACHE_NFSFS_RENAMED;
+                       alias->d_flags |= DCACHE_NFSFS_RENAMED;
                        ret = 1;
                }
                spin_unlock(&alias->d_lock);