aboutsummaryrefslogtreecommitdiffstats
path: root/fs/namei.c
diff options
context:
space:
mode:
Diffstat (limited to 'fs/namei.c')
-rw-r--r--fs/namei.c72
1 files changed, 70 insertions, 2 deletions
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 */