Skip to content

Commit 7bd8837

Browse files
author
Al Viro
committed
don't bugger nd->seq on set_root_rcu() from follow_dotdot_rcu()
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. Cc: [email protected] # 2.6.38+ Signed-off-by: Al Viro <[email protected]>
1 parent f5be3e2 commit 7bd8837

File tree

1 file changed

+17
-16
lines changed

1 file changed

+17
-16
lines changed

fs/namei.c

Lines changed: 17 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -643,24 +643,22 @@ static int complete_walk(struct nameidata *nd)
643643

644644
static __always_inline void set_root(struct nameidata *nd)
645645
{
646-
if (!nd->root.mnt)
647-
get_fs_root(current->fs, &nd->root);
646+
get_fs_root(current->fs, &nd->root);
648647
}
649648

650649
static int link_path_walk(const char *, struct nameidata *);
651650

652-
static __always_inline void set_root_rcu(struct nameidata *nd)
651+
static __always_inline unsigned set_root_rcu(struct nameidata *nd)
653652
{
654-
if (!nd->root.mnt) {
655-
struct fs_struct *fs = current->fs;
656-
unsigned seq;
653+
struct fs_struct *fs = current->fs;
654+
unsigned seq, res;
657655

658-
do {
659-
seq = read_seqcount_begin(&fs->seq);
660-
nd->root = fs->root;
661-
nd->seq = __read_seqcount_begin(&nd->root.dentry->d_seq);
662-
} while (read_seqcount_retry(&fs->seq, seq));
663-
}
656+
do {
657+
seq = read_seqcount_begin(&fs->seq);
658+
nd->root = fs->root;
659+
res = __read_seqcount_begin(&nd->root.dentry->d_seq);
660+
} while (read_seqcount_retry(&fs->seq, seq));
661+
return res;
664662
}
665663

666664
static void path_put_conditional(struct path *path, struct nameidata *nd)
@@ -860,7 +858,8 @@ follow_link(struct path *link, struct nameidata *nd, void **p)
860858
return PTR_ERR(s);
861859
}
862860
if (*s == '/') {
863-
set_root(nd);
861+
if (!nd->root.mnt)
862+
set_root(nd);
864863
path_put(&nd->path);
865864
nd->path = nd->root;
866865
path_get(&nd->root);
@@ -1143,7 +1142,8 @@ static bool __follow_mount_rcu(struct nameidata *nd, struct path *path,
11431142

11441143
static int follow_dotdot_rcu(struct nameidata *nd)
11451144
{
1146-
set_root_rcu(nd);
1145+
if (!nd->root.mnt)
1146+
set_root_rcu(nd);
11471147

11481148
while (1) {
11491149
if (nd->path.dentry == nd->root.dentry &&
@@ -1256,7 +1256,8 @@ static void follow_mount(struct path *path)
12561256

12571257
static void follow_dotdot(struct nameidata *nd)
12581258
{
1259-
set_root(nd);
1259+
if (!nd->root.mnt)
1260+
set_root(nd);
12601261

12611262
while(1) {
12621263
struct dentry *old = nd->path.dentry;
@@ -1852,7 +1853,7 @@ static int path_init(int dfd, const char *name, unsigned int flags,
18521853
if (*name=='/') {
18531854
if (flags & LOOKUP_RCU) {
18541855
rcu_read_lock();
1855-
set_root_rcu(nd);
1856+
nd->seq = set_root_rcu(nd);
18561857
} else {
18571858
set_root(nd);
18581859
path_get(&nd->root);

0 commit comments

Comments
 (0)