Skip to content

Commit 83373f7

Browse files
committed
Merge branch 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/viro/vfs
Pull vfs fixes from Al Viro: "double iput() on failure exit in lustre, racy removal of spliced dentries from ->s_anon in __d_materialise_dentry() plus a bunch of assorted RCU pathwalk fixes" The RCU pathwalk fixes end up fixing a couple of cases where we incorrectly dropped out of RCU walking, due to incorrect initialization and testing of the sequence locks in some corner cases. Since dropping out of RCU walk mode forces the slow locked accesses, those corner cases slowed down quite dramatically. * 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/viro/vfs: be careful with nd->inode in path_init() and follow_dotdot_rcu() don't bugger nd->seq on set_root_rcu() from follow_dotdot_rcu() fix bogus read_seqretry() checks introduced in b37199e move the call of __d_drop(anon) into __d_materialise_unique(dentry, anon) [fix] lustre: d_make_root() does iput() on dentry allocation failure
2 parents 9226b5b + 4023bfc commit 83373f7

File tree

3 files changed

+39
-23
lines changed

3 files changed

+39
-23
lines changed

drivers/staging/lustre/lustre/llite/llite_lib.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -568,7 +568,7 @@ static int client_common_fill_super(struct super_block *sb, char *md, char *dt,
568568
if (sb->s_root == NULL) {
569569
CERROR("%s: can't make root dentry\n",
570570
ll_get_fsname(sb, NULL, 0));
571-
GOTO(out_root, err = -ENOMEM);
571+
GOTO(out_lock_cn_cb, err = -ENOMEM);
572572
}
573573

574574
sbi->ll_sdev_orig = sb->s_dev;

fs/dcache.c

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2655,6 +2655,12 @@ static void __d_materialise_dentry(struct dentry *dentry, struct dentry *anon)
26552655
dentry->d_parent = dentry;
26562656
list_del_init(&dentry->d_u.d_child);
26572657
anon->d_parent = dparent;
2658+
if (likely(!d_unhashed(anon))) {
2659+
hlist_bl_lock(&anon->d_sb->s_anon);
2660+
__hlist_bl_del(&anon->d_hash);
2661+
anon->d_hash.pprev = NULL;
2662+
hlist_bl_unlock(&anon->d_sb->s_anon);
2663+
}
26582664
list_move(&anon->d_u.d_child, &dparent->d_subdirs);
26592665

26602666
write_seqcount_end(&dentry->d_seq);
@@ -2713,7 +2719,6 @@ struct dentry *d_splice_alias(struct inode *inode, struct dentry *dentry)
27132719
write_seqlock(&rename_lock);
27142720
__d_materialise_dentry(dentry, new);
27152721
write_sequnlock(&rename_lock);
2716-
__d_drop(new);
27172722
_d_rehash(new);
27182723
spin_unlock(&new->d_lock);
27192724
spin_unlock(&inode->i_lock);
@@ -2777,7 +2782,6 @@ struct dentry *d_materialise_unique(struct dentry *dentry, struct inode *inode)
27772782
* could splice into our tree? */
27782783
__d_materialise_dentry(dentry, alias);
27792784
write_sequnlock(&rename_lock);
2780-
__d_drop(alias);
27812785
goto found;
27822786
} else {
27832787
/* Nope, but we must(!) avoid directory

fs/namei.c

Lines changed: 32 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -644,24 +644,22 @@ static int complete_walk(struct nameidata *nd)
644644

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

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

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

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

667665
static void path_put_conditional(struct path *path, struct nameidata *nd)
@@ -861,7 +859,8 @@ follow_link(struct path *link, struct nameidata *nd, void **p)
861859
return PTR_ERR(s);
862860
}
863861
if (*s == '/') {
864-
set_root(nd);
862+
if (!nd->root.mnt)
863+
set_root(nd);
865864
path_put(&nd->path);
866865
nd->path = nd->root;
867866
path_get(&nd->root);
@@ -1138,13 +1137,15 @@ static bool __follow_mount_rcu(struct nameidata *nd, struct path *path,
11381137
*/
11391138
*inode = path->dentry->d_inode;
11401139
}
1141-
return read_seqretry(&mount_lock, nd->m_seq) &&
1140+
return !read_seqretry(&mount_lock, nd->m_seq) &&
11421141
!(path->dentry->d_flags & DCACHE_NEED_AUTOMOUNT);
11431142
}
11441143

11451144
static int follow_dotdot_rcu(struct nameidata *nd)
11461145
{
1147-
set_root_rcu(nd);
1146+
struct inode *inode = nd->inode;
1147+
if (!nd->root.mnt)
1148+
set_root_rcu(nd);
11481149

11491150
while (1) {
11501151
if (nd->path.dentry == nd->root.dentry &&
@@ -1156,6 +1157,7 @@ static int follow_dotdot_rcu(struct nameidata *nd)
11561157
struct dentry *parent = old->d_parent;
11571158
unsigned seq;
11581159

1160+
inode = parent->d_inode;
11591161
seq = read_seqcount_begin(&parent->d_seq);
11601162
if (read_seqcount_retry(&old->d_seq, nd->seq))
11611163
goto failed;
@@ -1165,6 +1167,7 @@ static int follow_dotdot_rcu(struct nameidata *nd)
11651167
}
11661168
if (!follow_up_rcu(&nd->path))
11671169
break;
1170+
inode = nd->path.dentry->d_inode;
11681171
nd->seq = read_seqcount_begin(&nd->path.dentry->d_seq);
11691172
}
11701173
while (d_mountpoint(nd->path.dentry)) {
@@ -1174,11 +1177,12 @@ static int follow_dotdot_rcu(struct nameidata *nd)
11741177
break;
11751178
nd->path.mnt = &mounted->mnt;
11761179
nd->path.dentry = mounted->mnt.mnt_root;
1180+
inode = nd->path.dentry->d_inode;
11771181
nd->seq = read_seqcount_begin(&nd->path.dentry->d_seq);
1178-
if (!read_seqretry(&mount_lock, nd->m_seq))
1182+
if (read_seqretry(&mount_lock, nd->m_seq))
11791183
goto failed;
11801184
}
1181-
nd->inode = nd->path.dentry->d_inode;
1185+
nd->inode = inode;
11821186
return 0;
11831187

11841188
failed:
@@ -1257,7 +1261,8 @@ static void follow_mount(struct path *path)
12571261

12581262
static void follow_dotdot(struct nameidata *nd)
12591263
{
1260-
set_root(nd);
1264+
if (!nd->root.mnt)
1265+
set_root(nd);
12611266

12621267
while(1) {
12631268
struct dentry *old = nd->path.dentry;
@@ -1853,7 +1858,7 @@ static int path_init(int dfd, const char *name, unsigned int flags,
18531858
if (*name=='/') {
18541859
if (flags & LOOKUP_RCU) {
18551860
rcu_read_lock();
1856-
set_root_rcu(nd);
1861+
nd->seq = set_root_rcu(nd);
18571862
} else {
18581863
set_root(nd);
18591864
path_get(&nd->root);
@@ -1904,7 +1909,14 @@ static int path_init(int dfd, const char *name, unsigned int flags,
19041909
}
19051910

19061911
nd->inode = nd->path.dentry->d_inode;
1907-
return 0;
1912+
if (!(flags & LOOKUP_RCU))
1913+
return 0;
1914+
if (likely(!read_seqcount_retry(&nd->path.dentry->d_seq, nd->seq)))
1915+
return 0;
1916+
if (!(nd->flags & LOOKUP_ROOT))
1917+
nd->root.mnt = NULL;
1918+
rcu_read_unlock();
1919+
return -ECHILD;
19081920
}
19091921

19101922
static inline int lookup_last(struct nameidata *nd, struct path *path)

0 commit comments

Comments
 (0)