aboutsummaryrefslogtreecommitdiffstats
path: root/fs
diff options
context:
space:
mode:
Diffstat (limited to 'fs')
-rw-r--r--fs/afs/mntpt.c5
-rw-r--r--fs/autofs4/autofs_i.h13
-rw-r--r--fs/autofs4/dev-ioctl.c2
-rw-r--r--fs/autofs4/expire.c2
-rw-r--r--fs/autofs4/root.c11
-rw-r--r--fs/cifs/cifs_dfs_ref.c5
-rw-r--r--fs/namei.c72
-rw-r--r--fs/namespace.c14
-rw-r--r--fs/nfs/namespace.c5
-rw-r--r--fs/nfsd/vfs.c5
10 files changed, 91 insertions, 43 deletions
diff --git a/fs/afs/mntpt.c b/fs/afs/mntpt.c
index e83c0336e7b5..f3e891d57a2c 100644
--- a/fs/afs/mntpt.c
+++ b/fs/afs/mntpt.c
@@ -273,10 +273,7 @@ static void *afs_mntpt_follow_link(struct dentry *dentry, struct nameidata *nd)
273 break; 273 break;
274 case -EBUSY: 274 case -EBUSY:
275 /* someone else made a mount here whilst we were busy */ 275 /* someone else made a mount here whilst we were busy */
276 while (d_mountpoint(nd->path.dentry) && 276 err = follow_down(&nd->path, false);
277 follow_down(&nd->path))
278 ;
279 err = 0;
280 default: 277 default:
281 mntput(newmnt); 278 mntput(newmnt);
282 break; 279 break;
diff --git a/fs/autofs4/autofs_i.h b/fs/autofs4/autofs_i.h
index 0fffe1c24cec..eb67953452bb 100644
--- a/fs/autofs4/autofs_i.h
+++ b/fs/autofs4/autofs_i.h
@@ -229,19 +229,6 @@ int autofs4_wait(struct autofs_sb_info *,struct dentry *, enum autofs_notify);
229int autofs4_wait_release(struct autofs_sb_info *,autofs_wqt_t,int); 229int autofs4_wait_release(struct autofs_sb_info *,autofs_wqt_t,int);
230void autofs4_catatonic_mode(struct autofs_sb_info *); 230void autofs4_catatonic_mode(struct autofs_sb_info *);
231 231
232static inline int autofs4_follow_mount(struct path *path)
233{
234 int res = 0;
235
236 while (d_mountpoint(path->dentry)) {
237 int followed = follow_down(path);
238 if (!followed)
239 break;
240 res = 1;
241 }
242 return res;
243}
244
245static inline u32 autofs4_get_dev(struct autofs_sb_info *sbi) 232static inline u32 autofs4_get_dev(struct autofs_sb_info *sbi)
246{ 233{
247 return new_encode_dev(sbi->sb->s_dev); 234 return new_encode_dev(sbi->sb->s_dev);
diff --git a/fs/autofs4/dev-ioctl.c b/fs/autofs4/dev-ioctl.c
index eff9a419469a..1442da4860e5 100644
--- a/fs/autofs4/dev-ioctl.c
+++ b/fs/autofs4/dev-ioctl.c
@@ -551,7 +551,7 @@ static int autofs_dev_ioctl_ismountpoint(struct file *fp,
551 551
552 err = have_submounts(path.dentry); 552 err = have_submounts(path.dentry);
553 553
554 if (follow_down(&path)) 554 if (follow_down_one(&path))
555 magic = path.mnt->mnt_sb->s_magic; 555 magic = path.mnt->mnt_sb->s_magic;
556 } 556 }
557 557
diff --git a/fs/autofs4/expire.c b/fs/autofs4/expire.c
index cc1d01365905..6a930b90d389 100644
--- a/fs/autofs4/expire.c
+++ b/fs/autofs4/expire.c
@@ -56,7 +56,7 @@ static int autofs4_mount_busy(struct vfsmount *mnt, struct dentry *dentry)
56 56
57 path_get(&path); 57 path_get(&path);
58 58
59 if (!follow_down(&path)) 59 if (!follow_down_one(&path))
60 goto done; 60 goto done;
61 61
62 if (is_autofs4_dentry(path.dentry)) { 62 if (is_autofs4_dentry(path.dentry)) {
diff --git a/fs/autofs4/root.c b/fs/autofs4/root.c
index 651e4ef563b1..20225636a4e9 100644
--- a/fs/autofs4/root.c
+++ b/fs/autofs4/root.c
@@ -234,7 +234,7 @@ static void *autofs4_follow_link(struct dentry *dentry, struct nameidata *nd)
234 nd->flags); 234 nd->flags);
235 /* 235 /*
236 * For an expire of a covered direct or offset mount we need 236 * For an expire of a covered direct or offset mount we need
237 * to break out of follow_down() at the autofs mount trigger 237 * to break out of follow_down_one() at the autofs mount trigger
238 * (d_mounted--), so we can see the expiring flag, and manage 238 * (d_mounted--), so we can see the expiring flag, and manage
239 * the blocking and following here until the expire is completed. 239 * the blocking and following here until the expire is completed.
240 */ 240 */
@@ -243,7 +243,7 @@ static void *autofs4_follow_link(struct dentry *dentry, struct nameidata *nd)
243 if (ino->flags & AUTOFS_INF_EXPIRING) { 243 if (ino->flags & AUTOFS_INF_EXPIRING) {
244 spin_unlock(&sbi->fs_lock); 244 spin_unlock(&sbi->fs_lock);
245 /* Follow down to our covering mount. */ 245 /* Follow down to our covering mount. */
246 if (!follow_down(&nd->path)) 246 if (!follow_down_one(&nd->path))
247 goto done; 247 goto done;
248 goto follow; 248 goto follow;
249 } 249 }
@@ -292,11 +292,10 @@ follow:
292 * multi-mount with no root offset so we don't need 292 * multi-mount with no root offset so we don't need
293 * to follow it. 293 * to follow it.
294 */ 294 */
295 if (d_mountpoint(dentry)) { 295 if (d_managed(dentry)) {
296 if (!autofs4_follow_mount(&nd->path)) { 296 status = follow_down(&nd->path, false);
297 status = -ENOENT; 297 if (status < 0)
298 goto out_error; 298 goto out_error;
299 }
300 } 299 }
301 300
302done: 301done:
diff --git a/fs/cifs/cifs_dfs_ref.c b/fs/cifs/cifs_dfs_ref.c
index c68a056f27fd..83479cf63f96 100644
--- a/fs/cifs/cifs_dfs_ref.c
+++ b/fs/cifs/cifs_dfs_ref.c
@@ -273,10 +273,7 @@ static int add_mount_helper(struct vfsmount *newmnt, struct nameidata *nd,
273 break; 273 break;
274 case -EBUSY: 274 case -EBUSY:
275 /* someone else made a mount here whilst we were busy */ 275 /* someone else made a mount here whilst we were busy */
276 while (d_mountpoint(nd->path.dentry) && 276 err = follow_down(&nd->path, false);
277 follow_down(&nd->path))
278 ;
279 err = 0;
280 default: 277 default:
281 mntput(newmnt); 278 mntput(newmnt);
282 break; 279 break;
diff --git a/fs/namei.c b/fs/namei.c
index 16109da68bbf..9d3033dc22e9 100644
--- a/fs/namei.c
+++ b/fs/namei.c
@@ -960,6 +960,7 @@ static int follow_automount(struct path *path, unsigned flags,
960 960
961/* 961/*
962 * Handle a dentry that is managed in some way. 962 * Handle a dentry that is managed in some way.
963 * - Flagged for transit management (autofs)
963 * - Flagged as mountpoint 964 * - Flagged as mountpoint
964 * - Flagged as automount point 965 * - Flagged as automount point
965 * 966 *
@@ -979,6 +980,16 @@ static int follow_managed(struct path *path, unsigned flags)
979 while (managed = ACCESS_ONCE(path->dentry->d_flags), 980 while (managed = ACCESS_ONCE(path->dentry->d_flags),
980 managed &= DCACHE_MANAGED_DENTRY, 981 managed &= DCACHE_MANAGED_DENTRY,
981 unlikely(managed != 0)) { 982 unlikely(managed != 0)) {
983 /* Allow the filesystem to manage the transit without i_mutex
984 * being held. */
985 if (managed & DCACHE_MANAGE_TRANSIT) {
986 BUG_ON(!path->dentry->d_op);
987 BUG_ON(!path->dentry->d_op->d_manage);
988 ret = path->dentry->d_op->d_manage(path->dentry, false);
989 if (ret < 0)
990 return ret == -EISDIR ? 0 : ret;
991 }
992
982 /* Transit to a mounted filesystem. */ 993 /* Transit to a mounted filesystem. */
983 if (managed & DCACHE_MOUNTED) { 994 if (managed & DCACHE_MOUNTED) {
984 struct vfsmount *mounted = lookup_mnt(path); 995 struct vfsmount *mounted = lookup_mnt(path);
@@ -1012,7 +1023,7 @@ static int follow_managed(struct path *path, unsigned flags)
1012 return 0; 1023 return 0;
1013} 1024}
1014 1025
1015int follow_down(struct path *path) 1026int follow_down_one(struct path *path)
1016{ 1027{
1017 struct vfsmount *mounted; 1028 struct vfsmount *mounted;
1018 1029
@@ -1029,14 +1040,19 @@ int follow_down(struct path *path)
1029 1040
1030/* 1041/*
1031 * Skip to top of mountpoint pile in rcuwalk mode. We abort the rcu-walk if we 1042 * Skip to top of mountpoint pile in rcuwalk mode. We abort the rcu-walk if we
1032 * meet an automount point and we're not walking to "..". True is returned to 1043 * meet a managed dentry and we're not walking to "..". True is returned to
1033 * continue, false to abort. 1044 * continue, false to abort.
1034 */ 1045 */
1035static bool __follow_mount_rcu(struct nameidata *nd, struct path *path, 1046static bool __follow_mount_rcu(struct nameidata *nd, struct path *path,
1036 struct inode **inode, bool reverse_transit) 1047 struct inode **inode, bool reverse_transit)
1037{ 1048{
1049 unsigned abort_mask =
1050 reverse_transit ? 0 : DCACHE_MANAGE_TRANSIT;
1051
1038 while (d_mountpoint(path->dentry)) { 1052 while (d_mountpoint(path->dentry)) {
1039 struct vfsmount *mounted; 1053 struct vfsmount *mounted;
1054 if (path->dentry->d_flags & abort_mask)
1055 return true;
1040 mounted = __lookup_mnt(path->mnt, path->dentry, 1); 1056 mounted = __lookup_mnt(path->mnt, path->dentry, 1);
1041 if (!mounted) 1057 if (!mounted)
1042 break; 1058 break;
@@ -1087,6 +1103,57 @@ static int follow_dotdot_rcu(struct nameidata *nd)
1087} 1103}
1088 1104
1089/* 1105/*
1106 * Follow down to the covering mount currently visible to userspace. At each
1107 * point, the filesystem owning that dentry may be queried as to whether the
1108 * caller is permitted to proceed or not.
1109 *
1110 * Care must be taken as namespace_sem may be held (indicated by mounting_here
1111 * being true).
1112 */
1113int follow_down(struct path *path, bool mounting_here)
1114{
1115 unsigned managed;
1116 int ret;
1117
1118 while (managed = ACCESS_ONCE(path->dentry->d_flags),
1119 unlikely(managed & DCACHE_MANAGED_DENTRY)) {
1120 /* Allow the filesystem to manage the transit without i_mutex
1121 * being held.
1122 *
1123 * We indicate to the filesystem if someone is trying to mount
1124 * something here. This gives autofs the chance to deny anyone
1125 * other than its daemon the right to mount on its
1126 * superstructure.
1127 *
1128 * The filesystem may sleep at this point.
1129 */
1130 if (managed & DCACHE_MANAGE_TRANSIT) {
1131 BUG_ON(!path->dentry->d_op);
1132 BUG_ON(!path->dentry->d_op->d_manage);
1133 ret = path->dentry->d_op->d_manage(path->dentry, mounting_here);
1134 if (ret < 0)
1135 return ret == -EISDIR ? 0 : ret;
1136 }
1137
1138 /* Transit to a mounted filesystem. */
1139 if (managed & DCACHE_MOUNTED) {
1140 struct vfsmount *mounted = lookup_mnt(path);
1141 if (!mounted)
1142 break;
1143 dput(path->dentry);
1144 mntput(path->mnt);
1145 path->mnt = mounted;
1146 path->dentry = dget(mounted->mnt_root);
1147 continue;
1148 }
1149
1150 /* Don't handle automount points here */
1151 break;
1152 }
1153 return 0;
1154}
1155
1156/*
1090 * Skip to top of mountpoint pile in refwalk mode for follow_dotdot() 1157 * Skip to top of mountpoint pile in refwalk mode for follow_dotdot()
1091 */ 1158 */
1092static void follow_mount(struct path *path) 1159static void follow_mount(struct path *path)
@@ -3530,6 +3597,7 @@ const struct inode_operations page_symlink_inode_operations = {
3530}; 3597};
3531 3598
3532EXPORT_SYMBOL(user_path_at); 3599EXPORT_SYMBOL(user_path_at);
3600EXPORT_SYMBOL(follow_down_one);
3533EXPORT_SYMBOL(follow_down); 3601EXPORT_SYMBOL(follow_down);
3534EXPORT_SYMBOL(follow_up); 3602EXPORT_SYMBOL(follow_up);
3535EXPORT_SYMBOL(get_write_access); /* binfmt_aout */ 3603EXPORT_SYMBOL(get_write_access); /* binfmt_aout */
diff --git a/fs/namespace.c b/fs/namespace.c
index 3ddfd9046c44..d94ccd6ddafd 100644
--- a/fs/namespace.c
+++ b/fs/namespace.c
@@ -1844,9 +1844,10 @@ static int do_move_mount(struct path *path, char *old_name)
1844 return err; 1844 return err;
1845 1845
1846 down_write(&namespace_sem); 1846 down_write(&namespace_sem);
1847 while (d_mountpoint(path->dentry) && 1847 err = follow_down(path, true);
1848 follow_down(path)) 1848 if (err < 0)
1849 ; 1849 goto out;
1850
1850 err = -EINVAL; 1851 err = -EINVAL;
1851 if (!check_mnt(path->mnt) || !check_mnt(old_path.mnt)) 1852 if (!check_mnt(path->mnt) || !check_mnt(old_path.mnt))
1852 goto out; 1853 goto out;
@@ -1940,9 +1941,10 @@ int do_add_mount(struct vfsmount *newmnt, struct path *path,
1940 1941
1941 down_write(&namespace_sem); 1942 down_write(&namespace_sem);
1942 /* Something was mounted here while we slept */ 1943 /* Something was mounted here while we slept */
1943 while (d_mountpoint(path->dentry) && 1944 err = follow_down(path, true);
1944 follow_down(path)) 1945 if (err < 0)
1945 ; 1946 goto unlock;
1947
1946 err = -EINVAL; 1948 err = -EINVAL;
1947 if (!(mnt_flags & MNT_SHRINKABLE) && !check_mnt(path->mnt)) 1949 if (!(mnt_flags & MNT_SHRINKABLE) && !check_mnt(path->mnt))
1948 goto unlock; 1950 goto unlock;
diff --git a/fs/nfs/namespace.c b/fs/nfs/namespace.c
index 74aaf3963c10..bfcb933e5755 100644
--- a/fs/nfs/namespace.c
+++ b/fs/nfs/namespace.c
@@ -176,10 +176,7 @@ out_err:
176 path_put(&nd->path); 176 path_put(&nd->path);
177 goto out; 177 goto out;
178out_follow: 178out_follow:
179 while (d_mountpoint(nd->path.dentry) && 179 err = follow_down(&nd->path, false);
180 follow_down(&nd->path))
181 ;
182 err = 0;
183 goto out; 180 goto out;
184} 181}
185 182
diff --git a/fs/nfsd/vfs.c b/fs/nfsd/vfs.c
index 230b79fbf005..0f79e33a65d7 100644
--- a/fs/nfsd/vfs.c
+++ b/fs/nfsd/vfs.c
@@ -88,8 +88,9 @@ nfsd_cross_mnt(struct svc_rqst *rqstp, struct dentry **dpp,
88 .dentry = dget(dentry)}; 88 .dentry = dget(dentry)};
89 int err = 0; 89 int err = 0;
90 90
91 while (d_mountpoint(path.dentry) && follow_down(&path)) 91 err = follow_down(&path, false);
92 ; 92 if (err < 0)
93 goto out;
93 94
94 exp2 = rqst_exp_get_by_name(rqstp, &path); 95 exp2 = rqst_exp_get_by_name(rqstp, &path);
95 if (IS_ERR(exp2)) { 96 if (IS_ERR(exp2)) {