fs: force_reval_path drop rcu-walk before d_invalidate
authorNick Piggin <npiggin@kernel.dk>
Fri, 14 Jan 2011 02:35:53 +0000 (02:35 +0000)
committerNick Piggin <npiggin@hera.kernel.org>
Fri, 14 Jan 2011 02:35:53 +0000 (02:35 +0000)
d_revalidate can return in rcu-walk mode even when it returns 0.  We can't just
call any old dcache function on rcu-walk dentry (the dentry is unstable, so
even through d_lock can safely be taken, the result may no longer be what we
expect -- careful re-checks would be required). So just drop rcu in this case.

(I missed this conversion when switching to the rcu-walk convention that Linus
suggested)

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

index 19433cdba0118d9a4bfda3dfbd654279e6928409..0f02359ce685c54652e56b870c4e1dde988b0679 100644 (file)
@@ -583,6 +583,13 @@ void release_open_intent(struct nameidata *nd)
                fput(nd->intent.open.file);
 }
 
+/*
+ * Call d_revalidate and handle filesystems that request rcu-walk
+ * to be dropped. This may be called and return in rcu-walk mode,
+ * regardless of success or error. If -ECHILD is returned, the caller
+ * must return -ECHILD back up the path walk stack so path walk may
+ * be restarted in ref-walk mode.
+ */
 static int d_revalidate(struct dentry *dentry, struct nameidata *nd)
 {
        int status;
@@ -673,6 +680,9 @@ force_reval_path(struct path *path, struct nameidata *nd)
                return 0;
 
        if (!status) {
+               /* Don't d_invalidate in rcu-walk mode */
+               if (nameidata_drop_rcu(nd))
+                       return -ECHILD;
                d_invalidate(dentry);
                status = -ESTALE;
        }