]> err.no Git - linux-2.6/commitdiff
NFS: Fix a potential race between umount and nfs_access_cache_shrinker()
authorTrond Myklebust <Trond.Myklebust@netapp.com>
Fri, 25 Jan 2008 21:38:17 +0000 (16:38 -0500)
committerTrond Myklebust <Trond.Myklebust@netapp.com>
Wed, 30 Jan 2008 07:06:12 +0000 (02:06 -0500)
Thanks to Yawei Niu for spotting the race.

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

index 5ca762de88bf75169186d41d842f0ebf3133667f..476cb0f837fd191d08898c87674d7a1fe51e84ee 100644 (file)
@@ -1694,13 +1694,19 @@ int nfs_access_cache_shrinker(int nr_to_scan, gfp_t gfp_mask)
 restart:
        spin_lock(&nfs_access_lru_lock);
        list_for_each_entry(nfsi, &nfs_access_lru_list, access_cache_inode_lru) {
+               struct rw_semaphore *s_umount;
                struct inode *inode;
 
                if (nr_to_scan-- == 0)
                        break;
+               s_umount = &nfsi->vfs_inode.i_sb->s_umount;
+               if (!down_read_trylock(s_umount))
+                       continue;
                inode = igrab(&nfsi->vfs_inode);
-               if (inode == NULL)
+               if (inode == NULL) {
+                       up_read(s_umount);
                        continue;
+               }
                spin_lock(&inode->i_lock);
                if (list_empty(&nfsi->access_cache_entry_lru))
                        goto remove_lru_entry;
@@ -1719,6 +1725,7 @@ remove_lru_entry:
                spin_unlock(&inode->i_lock);
                spin_unlock(&nfs_access_lru_lock);
                iput(inode);
+               up_read(s_umount);
                goto restart;
        }
        spin_unlock(&nfs_access_lru_lock);