summaryrefslogtreecommitdiffstats
path: root/fs
diff options
context:
space:
mode:
authorLinus Torvalds <torvalds@linux-foundation.org>2018-03-15 21:57:14 -0400
committerLinus Torvalds <torvalds@linux-foundation.org>2018-03-15 21:57:14 -0400
commitdf09348f78dc53a14faddca4414d66bea849a749 (patch)
tree79d0bda31965824ad7272118f432ddd67e4e5db5 /fs
parentcfb61b5e3e09f8b49bc4d685429df75f45127adc (diff)
parent95dd77580ccd66a0da96e6d4696945b8cea39431 (diff)
Merge branch 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/viro/vfs
Pull vfs fixes from Al Viro: - backport-friendly part of lock_parent() race fix - a fix for an assumption in the heurisic used by path_connected() that is not true on NFS - livelock fixes for d_alloc_parallel() * 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/viro/vfs: fs: Teach path_connected to handle nfs filesystems with multiple roots. fs: dcache: Use READ_ONCE when accessing i_dir_seq fs: dcache: Avoid livelock between d_alloc_parallel and __d_add lock_parent() needs to recheck if dentry got __dentry_kill'ed under it
Diffstat (limited to 'fs')
-rw-r--r--fs/dcache.c21
-rw-r--r--fs/namei.c5
-rw-r--r--fs/nfs/super.c2
3 files changed, 21 insertions, 7 deletions
diff --git a/fs/dcache.c b/fs/dcache.c
index 7c38f39958bc..8945e6cabd93 100644
--- a/fs/dcache.c
+++ b/fs/dcache.c
@@ -647,11 +647,16 @@ again:
647 spin_unlock(&parent->d_lock); 647 spin_unlock(&parent->d_lock);
648 goto again; 648 goto again;
649 } 649 }
650 rcu_read_unlock(); 650 if (parent != dentry) {
651 if (parent != dentry)
652 spin_lock_nested(&dentry->d_lock, DENTRY_D_LOCK_NESTED); 651 spin_lock_nested(&dentry->d_lock, DENTRY_D_LOCK_NESTED);
653 else 652 if (unlikely(dentry->d_lockref.count < 0)) {
653 spin_unlock(&parent->d_lock);
654 parent = NULL;
655 }
656 } else {
654 parent = NULL; 657 parent = NULL;
658 }
659 rcu_read_unlock();
655 return parent; 660 return parent;
656} 661}
657 662
@@ -2474,7 +2479,7 @@ struct dentry *d_alloc_parallel(struct dentry *parent,
2474 2479
2475retry: 2480retry:
2476 rcu_read_lock(); 2481 rcu_read_lock();
2477 seq = smp_load_acquire(&parent->d_inode->i_dir_seq) & ~1; 2482 seq = smp_load_acquire(&parent->d_inode->i_dir_seq);
2478 r_seq = read_seqbegin(&rename_lock); 2483 r_seq = read_seqbegin(&rename_lock);
2479 dentry = __d_lookup_rcu(parent, name, &d_seq); 2484 dentry = __d_lookup_rcu(parent, name, &d_seq);
2480 if (unlikely(dentry)) { 2485 if (unlikely(dentry)) {
@@ -2495,8 +2500,14 @@ retry:
2495 rcu_read_unlock(); 2500 rcu_read_unlock();
2496 goto retry; 2501 goto retry;
2497 } 2502 }
2503
2504 if (unlikely(seq & 1)) {
2505 rcu_read_unlock();
2506 goto retry;
2507 }
2508
2498 hlist_bl_lock(b); 2509 hlist_bl_lock(b);
2499 if (unlikely(parent->d_inode->i_dir_seq != seq)) { 2510 if (unlikely(READ_ONCE(parent->d_inode->i_dir_seq) != seq)) {
2500 hlist_bl_unlock(b); 2511 hlist_bl_unlock(b);
2501 rcu_read_unlock(); 2512 rcu_read_unlock();
2502 goto retry; 2513 goto retry;
diff --git a/fs/namei.c b/fs/namei.c
index 921ae32dbc80..cafa365eeb70 100644
--- a/fs/namei.c
+++ b/fs/namei.c
@@ -559,9 +559,10 @@ static int __nd_alloc_stack(struct nameidata *nd)
559static bool path_connected(const struct path *path) 559static bool path_connected(const struct path *path)
560{ 560{
561 struct vfsmount *mnt = path->mnt; 561 struct vfsmount *mnt = path->mnt;
562 struct super_block *sb = mnt->mnt_sb;
562 563
563 /* Only bind mounts can have disconnected paths */ 564 /* Bind mounts and multi-root filesystems can have disconnected paths */
564 if (mnt->mnt_root == mnt->mnt_sb->s_root) 565 if (!(sb->s_iflags & SB_I_MULTIROOT) && (mnt->mnt_root == sb->s_root))
565 return true; 566 return true;
566 567
567 return is_subdir(path->dentry, mnt->mnt_root); 568 return is_subdir(path->dentry, mnt->mnt_root);
diff --git a/fs/nfs/super.c b/fs/nfs/super.c
index 29bacdc56f6a..5e470e233c83 100644
--- a/fs/nfs/super.c
+++ b/fs/nfs/super.c
@@ -2631,6 +2631,8 @@ struct dentry *nfs_fs_mount_common(struct nfs_server *server,
2631 /* initial superblock/root creation */ 2631 /* initial superblock/root creation */
2632 mount_info->fill_super(s, mount_info); 2632 mount_info->fill_super(s, mount_info);
2633 nfs_get_cache_cookie(s, mount_info->parsed, mount_info->cloned); 2633 nfs_get_cache_cookie(s, mount_info->parsed, mount_info->cloned);
2634 if (!(server->flags & NFS_MOUNT_UNSHARED))
2635 s->s_iflags |= SB_I_MULTIROOT;
2634 } 2636 }
2635 2637
2636 mntroot = nfs_get_root(s, mount_info->mntfh, dev_name); 2638 mntroot = nfs_get_root(s, mount_info->mntfh, dev_name);