Commit 035cbfd3 authored by Al Viro's avatar Al Viro Committed by Ben Hutchings

don't bugger nd->seq on set_root_rcu() from follow_dotdot_rcu()

commit 7bd88377 upstream.

return the value instead, and have path_init() do the assignment.  Broken by
"vfs: Fix absolute RCU path walk failures due to uninitialized seq number",
which was Cc-stable with 2.6.38+ as destination.  This one should go where
it went.

To avoid dummy value returned in case when root is already set (it would do
no harm, actually, since the only caller that doesn't ignore the return value
is guaranteed to have nd->root *not* set, but it's more obvious that way),
lift the check into callers.  And do the same to set_root(), to keep them
in sync.
Signed-off-by: default avatarAl Viro <viro@zeniv.linux.org.uk>
[bwh: Backported to 3.2: adjust context, indentation]
Signed-off-by: default avatarBen Hutchings <ben@decadent.org.uk>
parent 8601a7ad
......@@ -554,24 +554,22 @@ static int complete_walk(struct nameidata *nd)
static __always_inline void set_root(struct nameidata *nd)
{
if (!nd->root.mnt)
get_fs_root(current->fs, &nd->root);
get_fs_root(current->fs, &nd->root);
}
static int link_path_walk(const char *, struct nameidata *);
static __always_inline void set_root_rcu(struct nameidata *nd)
static __always_inline unsigned set_root_rcu(struct nameidata *nd)
{
if (!nd->root.mnt) {
struct fs_struct *fs = current->fs;
unsigned seq;
struct fs_struct *fs = current->fs;
unsigned seq, res;
do {
seq = read_seqcount_begin(&fs->seq);
nd->root = fs->root;
nd->seq = __read_seqcount_begin(&nd->root.dentry->d_seq);
} while (read_seqcount_retry(&fs->seq, seq));
}
do {
seq = read_seqcount_begin(&fs->seq);
nd->root = fs->root;
res = __read_seqcount_begin(&nd->root.dentry->d_seq);
} while (read_seqcount_retry(&fs->seq, seq));
return res;
}
static __always_inline int __vfs_follow_link(struct nameidata *nd, const char *link)
......@@ -582,7 +580,8 @@ static __always_inline int __vfs_follow_link(struct nameidata *nd, const char *l
goto fail;
if (*link == '/') {
set_root(nd);
if (!nd->root.mnt)
set_root(nd);
path_put(&nd->path);
nd->path = nd->root;
path_get(&nd->root);
......@@ -927,7 +926,8 @@ static void follow_mount_rcu(struct nameidata *nd)
static int follow_dotdot_rcu(struct nameidata *nd)
{
set_root_rcu(nd);
if (!nd->root.mnt)
set_root_rcu(nd);
while (1) {
if (nd->path.dentry == nd->root.dentry &&
......@@ -1030,7 +1030,8 @@ static void follow_mount(struct path *path)
static void follow_dotdot(struct nameidata *nd)
{
set_root(nd);
if (!nd->root.mnt)
set_root(nd);
while(1) {
struct dentry *old = nd->path.dentry;
......@@ -1504,7 +1505,7 @@ static int path_init(int dfd, const char *name, unsigned int flags,
if (flags & LOOKUP_RCU) {
br_read_lock(vfsmount_lock);
rcu_read_lock();
set_root_rcu(nd);
nd->seq = set_root_rcu(nd);
} else {
set_root(nd);
path_get(&nd->root);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment