diff options
Diffstat (limited to 'fs')
-rw-r--r-- | fs/dcache.c | 8 | ||||
-rw-r--r-- | fs/namei.c | 52 |
2 files changed, 38 insertions, 22 deletions
diff --git a/fs/dcache.c b/fs/dcache.c index 4023e77b800e..7a5b51440afa 100644 --- a/fs/dcache.c +++ b/fs/dcache.c | |||
@@ -2655,6 +2655,12 @@ static void __d_materialise_dentry(struct dentry *dentry, struct dentry *anon) | |||
2655 | dentry->d_parent = dentry; | 2655 | dentry->d_parent = dentry; |
2656 | list_del_init(&dentry->d_u.d_child); | 2656 | list_del_init(&dentry->d_u.d_child); |
2657 | anon->d_parent = dparent; | 2657 | 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 | } | ||
2658 | list_move(&anon->d_u.d_child, &dparent->d_subdirs); | 2664 | list_move(&anon->d_u.d_child, &dparent->d_subdirs); |
2659 | 2665 | ||
2660 | write_seqcount_end(&dentry->d_seq); | 2666 | write_seqcount_end(&dentry->d_seq); |
@@ -2713,7 +2719,6 @@ struct dentry *d_splice_alias(struct inode *inode, struct dentry *dentry) | |||
2713 | write_seqlock(&rename_lock); | 2719 | write_seqlock(&rename_lock); |
2714 | __d_materialise_dentry(dentry, new); | 2720 | __d_materialise_dentry(dentry, new); |
2715 | write_sequnlock(&rename_lock); | 2721 | write_sequnlock(&rename_lock); |
2716 | __d_drop(new); | ||
2717 | _d_rehash(new); | 2722 | _d_rehash(new); |
2718 | spin_unlock(&new->d_lock); | 2723 | spin_unlock(&new->d_lock); |
2719 | spin_unlock(&inode->i_lock); | 2724 | spin_unlock(&inode->i_lock); |
@@ -2777,7 +2782,6 @@ struct dentry *d_materialise_unique(struct dentry *dentry, struct inode *inode) | |||
2777 | * could splice into our tree? */ | 2782 | * could splice into our tree? */ |
2778 | __d_materialise_dentry(dentry, alias); | 2783 | __d_materialise_dentry(dentry, alias); |
2779 | write_sequnlock(&rename_lock); | 2784 | write_sequnlock(&rename_lock); |
2780 | __d_drop(alias); | ||
2781 | goto found; | 2785 | goto found; |
2782 | } else { | 2786 | } else { |
2783 | /* Nope, but we must(!) avoid directory | 2787 | /* Nope, but we must(!) avoid directory |
diff --git a/fs/namei.c b/fs/namei.c index 2be5120b81b3..215e44254c53 100644 --- a/fs/namei.c +++ b/fs/namei.c | |||
@@ -644,24 +644,22 @@ static int complete_walk(struct nameidata *nd) | |||
644 | 644 | ||
645 | static __always_inline void set_root(struct nameidata *nd) | 645 | static __always_inline void set_root(struct nameidata *nd) |
646 | { | 646 | { |
647 | if (!nd->root.mnt) | 647 | get_fs_root(current->fs, &nd->root); |
648 | get_fs_root(current->fs, &nd->root); | ||
649 | } | 648 | } |
650 | 649 | ||
651 | static int link_path_walk(const char *, struct nameidata *); | 650 | static int link_path_walk(const char *, struct nameidata *); |
652 | 651 | ||
653 | static __always_inline void set_root_rcu(struct nameidata *nd) | 652 | static __always_inline unsigned set_root_rcu(struct nameidata *nd) |
654 | { | 653 | { |
655 | if (!nd->root.mnt) { | 654 | struct fs_struct *fs = current->fs; |
656 | struct fs_struct *fs = current->fs; | 655 | unsigned seq, res; |
657 | unsigned seq; | ||
658 | 656 | ||
659 | do { | 657 | do { |
660 | seq = read_seqcount_begin(&fs->seq); | 658 | seq = read_seqcount_begin(&fs->seq); |
661 | nd->root = fs->root; | 659 | nd->root = fs->root; |
662 | nd->seq = __read_seqcount_begin(&nd->root.dentry->d_seq); | 660 | res = __read_seqcount_begin(&nd->root.dentry->d_seq); |
663 | } while (read_seqcount_retry(&fs->seq, seq)); | 661 | } while (read_seqcount_retry(&fs->seq, seq)); |
664 | } | 662 | return res; |
665 | } | 663 | } |
666 | 664 | ||
667 | static void path_put_conditional(struct path *path, struct nameidata *nd) | 665 | 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) | |||
861 | return PTR_ERR(s); | 859 | return PTR_ERR(s); |
862 | } | 860 | } |
863 | if (*s == '/') { | 861 | if (*s == '/') { |
864 | set_root(nd); | 862 | if (!nd->root.mnt) |
863 | set_root(nd); | ||
865 | path_put(&nd->path); | 864 | path_put(&nd->path); |
866 | nd->path = nd->root; | 865 | nd->path = nd->root; |
867 | path_get(&nd->root); | 866 | path_get(&nd->root); |
@@ -1138,13 +1137,15 @@ static bool __follow_mount_rcu(struct nameidata *nd, struct path *path, | |||
1138 | */ | 1137 | */ |
1139 | *inode = path->dentry->d_inode; | 1138 | *inode = path->dentry->d_inode; |
1140 | } | 1139 | } |
1141 | return read_seqretry(&mount_lock, nd->m_seq) && | 1140 | return !read_seqretry(&mount_lock, nd->m_seq) && |
1142 | !(path->dentry->d_flags & DCACHE_NEED_AUTOMOUNT); | 1141 | !(path->dentry->d_flags & DCACHE_NEED_AUTOMOUNT); |
1143 | } | 1142 | } |
1144 | 1143 | ||
1145 | static int follow_dotdot_rcu(struct nameidata *nd) | 1144 | static int follow_dotdot_rcu(struct nameidata *nd) |
1146 | { | 1145 | { |
1147 | set_root_rcu(nd); | 1146 | struct inode *inode = nd->inode; |
1147 | if (!nd->root.mnt) | ||
1148 | set_root_rcu(nd); | ||
1148 | 1149 | ||
1149 | while (1) { | 1150 | while (1) { |
1150 | if (nd->path.dentry == nd->root.dentry && | 1151 | if (nd->path.dentry == nd->root.dentry && |
@@ -1156,6 +1157,7 @@ static int follow_dotdot_rcu(struct nameidata *nd) | |||
1156 | struct dentry *parent = old->d_parent; | 1157 | struct dentry *parent = old->d_parent; |
1157 | unsigned seq; | 1158 | unsigned seq; |
1158 | 1159 | ||
1160 | inode = parent->d_inode; | ||
1159 | seq = read_seqcount_begin(&parent->d_seq); | 1161 | seq = read_seqcount_begin(&parent->d_seq); |
1160 | if (read_seqcount_retry(&old->d_seq, nd->seq)) | 1162 | if (read_seqcount_retry(&old->d_seq, nd->seq)) |
1161 | goto failed; | 1163 | goto failed; |
@@ -1165,6 +1167,7 @@ static int follow_dotdot_rcu(struct nameidata *nd) | |||
1165 | } | 1167 | } |
1166 | if (!follow_up_rcu(&nd->path)) | 1168 | if (!follow_up_rcu(&nd->path)) |
1167 | break; | 1169 | break; |
1170 | inode = nd->path.dentry->d_inode; | ||
1168 | nd->seq = read_seqcount_begin(&nd->path.dentry->d_seq); | 1171 | nd->seq = read_seqcount_begin(&nd->path.dentry->d_seq); |
1169 | } | 1172 | } |
1170 | while (d_mountpoint(nd->path.dentry)) { | 1173 | while (d_mountpoint(nd->path.dentry)) { |
@@ -1174,11 +1177,12 @@ static int follow_dotdot_rcu(struct nameidata *nd) | |||
1174 | break; | 1177 | break; |
1175 | nd->path.mnt = &mounted->mnt; | 1178 | nd->path.mnt = &mounted->mnt; |
1176 | nd->path.dentry = mounted->mnt.mnt_root; | 1179 | nd->path.dentry = mounted->mnt.mnt_root; |
1180 | inode = nd->path.dentry->d_inode; | ||
1177 | nd->seq = read_seqcount_begin(&nd->path.dentry->d_seq); | 1181 | 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)) |
1179 | goto failed; | 1183 | goto failed; |
1180 | } | 1184 | } |
1181 | nd->inode = nd->path.dentry->d_inode; | 1185 | nd->inode = inode; |
1182 | return 0; | 1186 | return 0; |
1183 | 1187 | ||
1184 | failed: | 1188 | failed: |
@@ -1257,7 +1261,8 @@ static void follow_mount(struct path *path) | |||
1257 | 1261 | ||
1258 | static void follow_dotdot(struct nameidata *nd) | 1262 | static void follow_dotdot(struct nameidata *nd) |
1259 | { | 1263 | { |
1260 | set_root(nd); | 1264 | if (!nd->root.mnt) |
1265 | set_root(nd); | ||
1261 | 1266 | ||
1262 | while(1) { | 1267 | while(1) { |
1263 | struct dentry *old = nd->path.dentry; | 1268 | struct dentry *old = nd->path.dentry; |
@@ -1853,7 +1858,7 @@ static int path_init(int dfd, const char *name, unsigned int flags, | |||
1853 | if (*name=='/') { | 1858 | if (*name=='/') { |
1854 | if (flags & LOOKUP_RCU) { | 1859 | if (flags & LOOKUP_RCU) { |
1855 | rcu_read_lock(); | 1860 | rcu_read_lock(); |
1856 | set_root_rcu(nd); | 1861 | nd->seq = set_root_rcu(nd); |
1857 | } else { | 1862 | } else { |
1858 | set_root(nd); | 1863 | set_root(nd); |
1859 | path_get(&nd->root); | 1864 | path_get(&nd->root); |
@@ -1904,7 +1909,14 @@ static int path_init(int dfd, const char *name, unsigned int flags, | |||
1904 | } | 1909 | } |
1905 | 1910 | ||
1906 | nd->inode = nd->path.dentry->d_inode; | 1911 | 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; | ||
1908 | } | 1920 | } |
1909 | 1921 | ||
1910 | static inline int lookup_last(struct nameidata *nd, struct path *path) | 1922 | static inline int lookup_last(struct nameidata *nd, struct path *path) |