From: Linus Torvalds Date: Thu, 12 Sep 2013 20:24:55 +0000 (-0700) Subject: vfs: make d_path() get the root path under RCU X-Git-Tag: upstream/snapshot3+hdmi~4319 X-Git-Url: http://review.tizen.org/git/?a=commitdiff_plain;h=68f0d9d92e5430e250f2bd2a1e7a350e880d776a;p=platform%2Fadaptation%2Frenesas_rcar%2Frenesas_kernel.git vfs: make d_path() get the root path under RCU This avoids the spinlocks and refcounts in the d_path() sequence too (used by /proc and various other entities). See commit 8b19e34188a3 for the equivalent getcwd() system call path. And unlike getcwd(), d_path() doesn't copy the result to user space, so I don't need to fear _that_ particular bug happening again. Signed-off-by: Linus Torvalds --- diff --git a/fs/dcache.c b/fs/dcache.c index 91e551b..dddc67f 100644 --- a/fs/dcache.c +++ b/fs/dcache.c @@ -2869,6 +2869,16 @@ static int prepend_unreachable(char **buffer, int *buflen) return prepend(buffer, buflen, "(unreachable)", 13); } +static void get_fs_root_rcu(struct fs_struct *fs, struct path *root) +{ + unsigned seq; + + do { + seq = read_seqcount_begin(&fs->seq); + *root = fs->root; + } while (read_seqcount_retry(&fs->seq, seq)); +} + /** * d_path - return the path of a dentry * @path: path to report @@ -2901,13 +2911,15 @@ char *d_path(const struct path *path, char *buf, int buflen) if (path->dentry->d_op && path->dentry->d_op->d_dname) return path->dentry->d_op->d_dname(path->dentry, buf, buflen); - get_fs_root(current->fs, &root); + rcu_read_lock(); + get_fs_root_rcu(current->fs, &root); br_read_lock(&vfsmount_lock); error = path_with_deleted(path, &root, &res, &buflen); br_read_unlock(&vfsmount_lock); + rcu_read_unlock(); + if (error < 0) res = ERR_PTR(error); - path_put(&root); return res; } EXPORT_SYMBOL(d_path);