aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--Documentation/filesystems/vfs.txt3
-rw-r--r--fs/namei.c27
2 files changed, 18 insertions, 12 deletions
diff --git a/Documentation/filesystems/vfs.txt b/Documentation/filesystems/vfs.txt
index a1d0d7a30165..61d65cc65c54 100644
--- a/Documentation/filesystems/vfs.txt
+++ b/Documentation/filesystems/vfs.txt
@@ -1053,7 +1053,8 @@ struct dentry_operations {
1053 If the 'rcu_walk' parameter is true, then the caller is doing a 1053 If the 'rcu_walk' parameter is true, then the caller is doing a
1054 pathwalk in RCU-walk mode. Sleeping is not permitted in this mode, 1054 pathwalk in RCU-walk mode. Sleeping is not permitted in this mode,
1055 and the caller can be asked to leave it and call again by returning 1055 and the caller can be asked to leave it and call again by returning
1056 -ECHILD. 1056 -ECHILD. -EISDIR may also be returned to tell pathwalk to
1057 ignore d_automount or any mounts.
1057 1058
1058 This function is only used if DCACHE_MANAGE_TRANSIT is set on the 1059 This function is only used if DCACHE_MANAGE_TRANSIT is set on the
1059 dentry being transited from. 1060 dentry being transited from.
diff --git a/fs/namei.c b/fs/namei.c
index 0ff23cecb1bb..8a217c48f6db 100644
--- a/fs/namei.c
+++ b/fs/namei.c
@@ -1091,10 +1091,10 @@ int follow_down_one(struct path *path)
1091} 1091}
1092EXPORT_SYMBOL(follow_down_one); 1092EXPORT_SYMBOL(follow_down_one);
1093 1093
1094static inline bool managed_dentry_might_block(struct dentry *dentry) 1094static inline int managed_dentry_rcu(struct dentry *dentry)
1095{ 1095{
1096 return (dentry->d_flags & DCACHE_MANAGE_TRANSIT && 1096 return (dentry->d_flags & DCACHE_MANAGE_TRANSIT) ?
1097 dentry->d_op->d_manage(dentry, true) < 0); 1097 dentry->d_op->d_manage(dentry, true) : 0;
1098} 1098}
1099 1099
1100/* 1100/*
@@ -1110,11 +1110,18 @@ static bool __follow_mount_rcu(struct nameidata *nd, struct path *path,
1110 * Don't forget we might have a non-mountpoint managed dentry 1110 * Don't forget we might have a non-mountpoint managed dentry
1111 * that wants to block transit. 1111 * that wants to block transit.
1112 */ 1112 */
1113 if (unlikely(managed_dentry_might_block(path->dentry))) 1113 switch (managed_dentry_rcu(path->dentry)) {
1114 case -ECHILD:
1115 default:
1114 return false; 1116 return false;
1117 case -EISDIR:
1118 return true;
1119 case 0:
1120 break;
1121 }
1115 1122
1116 if (!d_mountpoint(path->dentry)) 1123 if (!d_mountpoint(path->dentry))
1117 return true; 1124 return !(path->dentry->d_flags & DCACHE_NEED_AUTOMOUNT);
1118 1125
1119 mounted = __lookup_mnt(path->mnt, path->dentry); 1126 mounted = __lookup_mnt(path->mnt, path->dentry);
1120 if (!mounted) 1127 if (!mounted)
@@ -1130,7 +1137,8 @@ static bool __follow_mount_rcu(struct nameidata *nd, struct path *path,
1130 */ 1137 */
1131 *inode = path->dentry->d_inode; 1138 *inode = path->dentry->d_inode;
1132 } 1139 }
1133 return read_seqretry(&mount_lock, nd->m_seq); 1140 return read_seqretry(&mount_lock, nd->m_seq) &&
1141 !(path->dentry->d_flags & DCACHE_NEED_AUTOMOUNT);
1134} 1142}
1135 1143
1136static int follow_dotdot_rcu(struct nameidata *nd) 1144static int follow_dotdot_rcu(struct nameidata *nd)
@@ -1402,11 +1410,8 @@ static int lookup_fast(struct nameidata *nd,
1402 } 1410 }
1403 path->mnt = mnt; 1411 path->mnt = mnt;
1404 path->dentry = dentry; 1412 path->dentry = dentry;
1405 if (unlikely(!__follow_mount_rcu(nd, path, inode))) 1413 if (likely(__follow_mount_rcu(nd, path, inode)))
1406 goto unlazy; 1414 return 0;
1407 if (unlikely(path->dentry->d_flags & DCACHE_NEED_AUTOMOUNT))
1408 goto unlazy;
1409 return 0;
1410unlazy: 1415unlazy:
1411 if (unlazy_walk(nd, dentry)) 1416 if (unlazy_walk(nd, dentry))
1412 return -ECHILD; 1417 return -ECHILD;