diff options
| -rw-r--r-- | fs/dcache.c | 21 | ||||
| -rw-r--r-- | fs/namei.c | 5 | ||||
| -rw-r--r-- | fs/nfs/super.c | 2 | ||||
| -rw-r--r-- | include/linux/fs.h | 1 |
4 files changed, 22 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 | ||
| 2475 | retry: | 2480 | retry: |
| 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) | |||
| 559 | static bool path_connected(const struct path *path) | 559 | static 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); |
diff --git a/include/linux/fs.h b/include/linux/fs.h index 79c413985305..c6baf767619e 100644 --- a/include/linux/fs.h +++ b/include/linux/fs.h | |||
| @@ -1317,6 +1317,7 @@ extern int send_sigurg(struct fown_struct *fown); | |||
| 1317 | #define SB_I_CGROUPWB 0x00000001 /* cgroup-aware writeback enabled */ | 1317 | #define SB_I_CGROUPWB 0x00000001 /* cgroup-aware writeback enabled */ |
| 1318 | #define SB_I_NOEXEC 0x00000002 /* Ignore executables on this fs */ | 1318 | #define SB_I_NOEXEC 0x00000002 /* Ignore executables on this fs */ |
| 1319 | #define SB_I_NODEV 0x00000004 /* Ignore devices on this fs */ | 1319 | #define SB_I_NODEV 0x00000004 /* Ignore devices on this fs */ |
| 1320 | #define SB_I_MULTIROOT 0x00000008 /* Multiple roots to the dentry tree */ | ||
| 1320 | 1321 | ||
| 1321 | /* sb->s_iflags to limit user namespace mounts */ | 1322 | /* sb->s_iflags to limit user namespace mounts */ |
| 1322 | #define SB_I_USERNS_VISIBLE 0x00000010 /* fstype already mounted */ | 1323 | #define SB_I_USERNS_VISIBLE 0x00000010 /* fstype already mounted */ |
