fs: fix dropping of rcu-walk from force_reval_path
authorNick Piggin <npiggin@kernel.dk>
Fri, 14 Jan 2011 02:36:19 +0000 (02:36 +0000)
committerNick Piggin <npiggin@hera.kernel.org>
Fri, 14 Jan 2011 02:36:19 +0000 (02:36 +0000)
As J. R. Okajima noted, force_reval_path passes in the same dentry to
d_revalidate as the one in the nameidata structure (other callers pass in a
child), so the locking breaks. This can oops with a chrooted nfs mount, for
example. Similarly there can be other problems with revalidating a dentry
which is already in nameidata of the path walk.

Signed-off-by: Nick Piggin <npiggin@kernel.dk>
fs/namei.c

index 0f02359ce685c54652e56b870c4e1dde988b0679..14c73edca9ce27ca342af4a297b5dc522539e69b 100644 (file)
@@ -479,6 +479,14 @@ static int nameidata_dentry_drop_rcu(struct nameidata *nd, struct dentry *dentry
        struct fs_struct *fs = current->fs;
        struct dentry *parent = nd->path.dentry;
 
+       /*
+        * It can be possible to revalidate the dentry that we started
+        * the path walk with. force_reval_path may also revalidate the
+        * dentry already committed to the nameidata.
+        */
+       if (unlikely(parent == dentry))
+               return nameidata_drop_rcu(nd);
+
        BUG_ON(!(nd->flags & LOOKUP_RCU));
        if (nd->root.mnt) {
                spin_lock(&fs->lock);