diff options
author | Miklos Szeredi <mszeredi@suse.cz> | 2012-05-21 11:30:05 -0400 |
---|---|---|
committer | Al Viro <viro@zeniv.linux.org.uk> | 2012-06-01 12:11:56 -0400 |
commit | 697f514df10b0f46bcd7596c1be18b7e2e9b28bb (patch) | |
tree | eed5439dcc771e5ee18cab74de829e97200ea320 | |
parent | e41f941a23115e84a8550b3d901a13a14b2edc2f (diff) |
vfs: split do_lookup()
Split do_lookup() into two functions:
lookup_fast() - does cached lookup without i_mutex
lookup_slow() - does lookup with i_mutex
Both follow managed dentries.
The new functions are needed by atomic_open.
Signed-off-by: Miklos Szeredi <mszeredi@suse.cz>
Signed-off-by: Al Viro <viro@zeniv.linux.org.uk>
-rw-r--r-- | fs/namei.c | 59 |
1 files changed, 45 insertions, 14 deletions
diff --git a/fs/namei.c b/fs/namei.c index 93ac9323b1f7..7f4ab820811a 100644 --- a/fs/namei.c +++ b/fs/namei.c | |||
@@ -1125,8 +1125,8 @@ static struct dentry *__lookup_hash(struct qstr *name, | |||
1125 | * small and for now I'd prefer to have fast path as straight as possible. | 1125 | * small and for now I'd prefer to have fast path as straight as possible. |
1126 | * It _is_ time-critical. | 1126 | * It _is_ time-critical. |
1127 | */ | 1127 | */ |
1128 | static int do_lookup(struct nameidata *nd, struct qstr *name, | 1128 | static int lookup_fast(struct nameidata *nd, struct qstr *name, |
1129 | struct path *path, struct inode **inode) | 1129 | struct path *path, struct inode **inode) |
1130 | { | 1130 | { |
1131 | struct vfsmount *mnt = nd->path.mnt; | 1131 | struct vfsmount *mnt = nd->path.mnt; |
1132 | struct dentry *dentry, *parent = nd->path.dentry; | 1132 | struct dentry *dentry, *parent = nd->path.dentry; |
@@ -1208,7 +1208,7 @@ unlazy: | |||
1208 | goto need_lookup; | 1208 | goto need_lookup; |
1209 | } | 1209 | } |
1210 | } | 1210 | } |
1211 | done: | 1211 | |
1212 | path->mnt = mnt; | 1212 | path->mnt = mnt; |
1213 | path->dentry = dentry; | 1213 | path->dentry = dentry; |
1214 | err = follow_managed(path, nd->flags); | 1214 | err = follow_managed(path, nd->flags); |
@@ -1222,6 +1222,17 @@ done: | |||
1222 | return 0; | 1222 | return 0; |
1223 | 1223 | ||
1224 | need_lookup: | 1224 | need_lookup: |
1225 | return 1; | ||
1226 | } | ||
1227 | |||
1228 | /* Fast lookup failed, do it the slow way */ | ||
1229 | static int lookup_slow(struct nameidata *nd, struct qstr *name, | ||
1230 | struct path *path) | ||
1231 | { | ||
1232 | struct dentry *dentry, *parent; | ||
1233 | int err; | ||
1234 | |||
1235 | parent = nd->path.dentry; | ||
1225 | BUG_ON(nd->inode != parent->d_inode); | 1236 | BUG_ON(nd->inode != parent->d_inode); |
1226 | 1237 | ||
1227 | mutex_lock(&parent->d_inode->i_mutex); | 1238 | mutex_lock(&parent->d_inode->i_mutex); |
@@ -1229,7 +1240,16 @@ need_lookup: | |||
1229 | mutex_unlock(&parent->d_inode->i_mutex); | 1240 | mutex_unlock(&parent->d_inode->i_mutex); |
1230 | if (IS_ERR(dentry)) | 1241 | if (IS_ERR(dentry)) |
1231 | return PTR_ERR(dentry); | 1242 | return PTR_ERR(dentry); |
1232 | goto done; | 1243 | path->mnt = nd->path.mnt; |
1244 | path->dentry = dentry; | ||
1245 | err = follow_managed(path, nd->flags); | ||
1246 | if (unlikely(err < 0)) { | ||
1247 | path_put_conditional(path, nd); | ||
1248 | return err; | ||
1249 | } | ||
1250 | if (err) | ||
1251 | nd->flags |= LOOKUP_JUMPED; | ||
1252 | return 0; | ||
1233 | } | 1253 | } |
1234 | 1254 | ||
1235 | static inline int may_lookup(struct nameidata *nd) | 1255 | static inline int may_lookup(struct nameidata *nd) |
@@ -1301,21 +1321,26 @@ static inline int walk_component(struct nameidata *nd, struct path *path, | |||
1301 | */ | 1321 | */ |
1302 | if (unlikely(type != LAST_NORM)) | 1322 | if (unlikely(type != LAST_NORM)) |
1303 | return handle_dots(nd, type); | 1323 | return handle_dots(nd, type); |
1304 | err = do_lookup(nd, name, path, &inode); | 1324 | err = lookup_fast(nd, name, path, &inode); |
1305 | if (unlikely(err)) { | 1325 | if (unlikely(err)) { |
1306 | terminate_walk(nd); | 1326 | if (err < 0) |
1307 | return err; | 1327 | goto out_err; |
1308 | } | 1328 | |
1309 | if (!inode) { | 1329 | err = lookup_slow(nd, name, path); |
1310 | path_to_nameidata(path, nd); | 1330 | if (err < 0) |
1311 | terminate_walk(nd); | 1331 | goto out_err; |
1312 | return -ENOENT; | 1332 | |
1333 | inode = path->dentry->d_inode; | ||
1313 | } | 1334 | } |
1335 | err = -ENOENT; | ||
1336 | if (!inode) | ||
1337 | goto out_path_put; | ||
1338 | |||
1314 | if (should_follow_link(inode, follow)) { | 1339 | if (should_follow_link(inode, follow)) { |
1315 | if (nd->flags & LOOKUP_RCU) { | 1340 | if (nd->flags & LOOKUP_RCU) { |
1316 | if (unlikely(unlazy_walk(nd, path->dentry))) { | 1341 | if (unlikely(unlazy_walk(nd, path->dentry))) { |
1317 | terminate_walk(nd); | 1342 | err = -ECHILD; |
1318 | return -ECHILD; | 1343 | goto out_err; |
1319 | } | 1344 | } |
1320 | } | 1345 | } |
1321 | BUG_ON(inode != path->dentry->d_inode); | 1346 | BUG_ON(inode != path->dentry->d_inode); |
@@ -1324,6 +1349,12 @@ static inline int walk_component(struct nameidata *nd, struct path *path, | |||
1324 | path_to_nameidata(path, nd); | 1349 | path_to_nameidata(path, nd); |
1325 | nd->inode = inode; | 1350 | nd->inode = inode; |
1326 | return 0; | 1351 | return 0; |
1352 | |||
1353 | out_path_put: | ||
1354 | path_to_nameidata(path, nd); | ||
1355 | out_err: | ||
1356 | terminate_walk(nd); | ||
1357 | return err; | ||
1327 | } | 1358 | } |
1328 | 1359 | ||
1329 | /* | 1360 | /* |