提交 deb106c6 编写于 作者: A Al Viro

namei: lift terminate_walk() all the way up

Lift it from link_path_walk(), trailing_symlink(), lookup_last(),
mountpoint_last(), complete_walk() and do_last().  A _lot_ of
those suckers merge.
Signed-off-by: NAl Viro <viro@zeniv.linux.org.uk>
上级 3bdba28b
...@@ -563,8 +563,6 @@ static inline int nd_alloc_stack(struct nameidata *nd) ...@@ -563,8 +563,6 @@ static inline int nd_alloc_stack(struct nameidata *nd)
* to restart the path walk from the beginning in ref-walk mode. * to restart the path walk from the beginning in ref-walk mode.
*/ */
static void terminate_walk(struct nameidata *nd);
/** /**
* unlazy_walk - try to switch to ref-walk mode. * unlazy_walk - try to switch to ref-walk mode.
* @nd: nameidata pathwalk data * @nd: nameidata pathwalk data
...@@ -673,10 +671,8 @@ static int complete_walk(struct nameidata *nd) ...@@ -673,10 +671,8 @@ static int complete_walk(struct nameidata *nd)
if (nd->flags & LOOKUP_RCU) { if (nd->flags & LOOKUP_RCU) {
if (!(nd->flags & LOOKUP_ROOT)) if (!(nd->flags & LOOKUP_ROOT))
nd->root.mnt = NULL; nd->root.mnt = NULL;
if (unlikely(unlazy_walk(nd, NULL))) { if (unlikely(unlazy_walk(nd, NULL)))
terminate_walk(nd);
return -ECHILD; return -ECHILD;
}
} }
if (likely(!(nd->flags & LOOKUP_JUMPED))) if (likely(!(nd->flags & LOOKUP_JUMPED)))
...@@ -692,7 +688,6 @@ static int complete_walk(struct nameidata *nd) ...@@ -692,7 +688,6 @@ static int complete_walk(struct nameidata *nd)
if (!status) if (!status)
status = -ESTALE; status = -ESTALE;
terminate_walk(nd);
return status; return status;
} }
...@@ -1858,7 +1853,6 @@ static int link_path_walk(const char *name, struct nameidata *nd) ...@@ -1858,7 +1853,6 @@ static int link_path_walk(const char *name, struct nameidata *nd)
break; break;
} }
} }
terminate_walk(nd);
return err; return err;
} }
...@@ -1974,38 +1968,26 @@ static const char *trailing_symlink(struct nameidata *nd) ...@@ -1974,38 +1968,26 @@ static const char *trailing_symlink(struct nameidata *nd)
{ {
const char *s; const char *s;
int error = may_follow_link(nd); int error = may_follow_link(nd);
if (unlikely(error)) { if (unlikely(error))
terminate_walk(nd);
return ERR_PTR(error); return ERR_PTR(error);
}
nd->flags |= LOOKUP_PARENT; nd->flags |= LOOKUP_PARENT;
nd->stack[0].name = NULL; nd->stack[0].name = NULL;
s = get_link(nd); s = get_link(nd);
if (unlikely(IS_ERR(s))) { return s ? s : "";
terminate_walk(nd);
return s;
}
if (unlikely(!s))
s = "";
return s;
} }
static inline int lookup_last(struct nameidata *nd) static inline int lookup_last(struct nameidata *nd)
{ {
int err;
if (nd->last_type == LAST_NORM && nd->last.name[nd->last.len]) if (nd->last_type == LAST_NORM && nd->last.name[nd->last.len])
nd->flags |= LOOKUP_FOLLOW | LOOKUP_DIRECTORY; nd->flags |= LOOKUP_FOLLOW | LOOKUP_DIRECTORY;
nd->flags &= ~LOOKUP_PARENT; nd->flags &= ~LOOKUP_PARENT;
err = walk_component(nd, return walk_component(nd,
nd->flags & LOOKUP_FOLLOW nd->flags & LOOKUP_FOLLOW
? nd->depth ? nd->depth
? WALK_PUT | WALK_GET ? WALK_PUT | WALK_GET
: WALK_GET : WALK_GET
: 0); : 0);
if (err < 0)
terminate_walk(nd);
return err;
} }
/* Returns 0 and nd will be valid on success; Retuns error, otherwise. */ /* Returns 0 and nd will be valid on success; Retuns error, otherwise. */
...@@ -2025,16 +2007,14 @@ static int path_lookupat(int dfd, const struct filename *name, ...@@ -2025,16 +2007,14 @@ static int path_lookupat(int dfd, const struct filename *name,
break; break;
} }
} }
if (!err) if (!err)
err = complete_walk(nd); err = complete_walk(nd);
if (!err && nd->flags & LOOKUP_DIRECTORY) { if (!err && nd->flags & LOOKUP_DIRECTORY)
if (!d_can_lookup(nd->path.dentry)) { if (!d_can_lookup(nd->path.dentry))
path_put(&nd->path);
err = -ENOTDIR; err = -ENOTDIR;
} if (err)
} terminate_walk(nd);
path_cleanup(nd); path_cleanup(nd);
return err; return err;
...@@ -2069,6 +2049,8 @@ static int path_parentat(int dfd, const struct filename *name, ...@@ -2069,6 +2049,8 @@ static int path_parentat(int dfd, const struct filename *name,
err = link_path_walk(s, nd); err = link_path_walk(s, nd);
if (!err) if (!err)
err = complete_walk(nd); err = complete_walk(nd);
if (err)
terminate_walk(nd);
path_cleanup(nd); path_cleanup(nd);
return err; return err;
} }
...@@ -2320,10 +2302,8 @@ mountpoint_last(struct nameidata *nd, struct path *path) ...@@ -2320,10 +2302,8 @@ mountpoint_last(struct nameidata *nd, struct path *path)
/* If we're in rcuwalk, drop out of it to handle last component */ /* If we're in rcuwalk, drop out of it to handle last component */
if (nd->flags & LOOKUP_RCU) { if (nd->flags & LOOKUP_RCU) {
if (unlazy_walk(nd, NULL)) { if (unlazy_walk(nd, NULL))
error = -ECHILD; return -ECHILD;
goto out;
}
} }
nd->flags &= ~LOOKUP_PARENT; nd->flags &= ~LOOKUP_PARENT;
...@@ -2331,7 +2311,7 @@ mountpoint_last(struct nameidata *nd, struct path *path) ...@@ -2331,7 +2311,7 @@ mountpoint_last(struct nameidata *nd, struct path *path)
if (unlikely(nd->last_type != LAST_NORM)) { if (unlikely(nd->last_type != LAST_NORM)) {
error = handle_dots(nd, nd->last_type); error = handle_dots(nd, nd->last_type);
if (error) if (error)
goto out; return error;
dentry = dget(nd->path.dentry); dentry = dget(nd->path.dentry);
goto done; goto done;
} }
...@@ -2346,41 +2326,32 @@ mountpoint_last(struct nameidata *nd, struct path *path) ...@@ -2346,41 +2326,32 @@ mountpoint_last(struct nameidata *nd, struct path *path)
*/ */
dentry = d_alloc(dir, &nd->last); dentry = d_alloc(dir, &nd->last);
if (!dentry) { if (!dentry) {
error = -ENOMEM;
mutex_unlock(&dir->d_inode->i_mutex); mutex_unlock(&dir->d_inode->i_mutex);
goto out; return -ENOMEM;
} }
dentry = lookup_real(dir->d_inode, dentry, nd->flags); dentry = lookup_real(dir->d_inode, dentry, nd->flags);
error = PTR_ERR(dentry);
if (IS_ERR(dentry)) { if (IS_ERR(dentry)) {
mutex_unlock(&dir->d_inode->i_mutex); mutex_unlock(&dir->d_inode->i_mutex);
goto out; return PTR_ERR(dentry);
} }
} }
mutex_unlock(&dir->d_inode->i_mutex); mutex_unlock(&dir->d_inode->i_mutex);
done: done:
if (d_is_negative(dentry)) { if (d_is_negative(dentry)) {
error = -ENOENT;
dput(dentry); dput(dentry);
goto out; return -ENOENT;
} }
if (nd->depth) if (nd->depth)
put_link(nd); put_link(nd);
path->dentry = dentry; path->dentry = dentry;
path->mnt = nd->path.mnt; path->mnt = nd->path.mnt;
error = should_follow_link(nd, path, nd->flags & LOOKUP_FOLLOW); error = should_follow_link(nd, path, nd->flags & LOOKUP_FOLLOW);
if (unlikely(error)) { if (unlikely(error))
if (error < 0)
goto out;
return error; return error;
}
mntget(path->mnt); mntget(path->mnt);
follow_mount(path); follow_mount(path);
error = 0; return 0;
out:
terminate_walk(nd);
return error;
} }
/** /**
...@@ -2409,6 +2380,7 @@ path_mountpoint(int dfd, const struct filename *name, struct path *path, ...@@ -2409,6 +2380,7 @@ path_mountpoint(int dfd, const struct filename *name, struct path *path,
break; break;
} }
} }
terminate_walk(nd);
path_cleanup(nd); path_cleanup(nd);
return err; return err;
} }
...@@ -2982,10 +2954,8 @@ static int do_last(struct nameidata *nd, ...@@ -2982,10 +2954,8 @@ static int do_last(struct nameidata *nd,
if (nd->last_type != LAST_NORM) { if (nd->last_type != LAST_NORM) {
error = handle_dots(nd, nd->last_type); error = handle_dots(nd, nd->last_type);
if (unlikely(error)) { if (unlikely(error))
terminate_walk(nd);
return error; return error;
}
goto finish_open; goto finish_open;
} }
...@@ -2998,7 +2968,7 @@ static int do_last(struct nameidata *nd, ...@@ -2998,7 +2968,7 @@ static int do_last(struct nameidata *nd,
goto finish_lookup; goto finish_lookup;
if (error < 0) if (error < 0)
goto out; return error;
BUG_ON(nd->inode != dir->d_inode); BUG_ON(nd->inode != dir->d_inode);
} else { } else {
...@@ -3013,10 +2983,9 @@ static int do_last(struct nameidata *nd, ...@@ -3013,10 +2983,9 @@ static int do_last(struct nameidata *nd,
return error; return error;
audit_inode(name, dir, LOOKUP_PARENT); audit_inode(name, dir, LOOKUP_PARENT);
error = -EISDIR;
/* trailing slashes? */ /* trailing slashes? */
if (nd->last.name[nd->last.len]) if (unlikely(nd->last.name[nd->last.len]))
goto out; return -EISDIR;
} }
retry_lookup: retry_lookup:
...@@ -3071,35 +3040,31 @@ static int do_last(struct nameidata *nd, ...@@ -3071,35 +3040,31 @@ static int do_last(struct nameidata *nd,
got_write = false; got_write = false;
} }
error = -EEXIST; if (unlikely((open_flag & (O_EXCL | O_CREAT)) == (O_EXCL | O_CREAT))) {
if ((open_flag & (O_EXCL | O_CREAT)) == (O_EXCL | O_CREAT)) path_to_nameidata(&path, nd);
goto exit_dput; return -EEXIST;
}
error = follow_managed(&path, nd); error = follow_managed(&path, nd);
if (error < 0) if (unlikely(error < 0))
goto out; return error;
BUG_ON(nd->flags & LOOKUP_RCU); BUG_ON(nd->flags & LOOKUP_RCU);
inode = path.dentry->d_inode; inode = path.dentry->d_inode;
error = -ENOENT; if (unlikely(d_is_negative(path.dentry))) {
if (d_is_negative(path.dentry)) {
path_to_nameidata(&path, nd); path_to_nameidata(&path, nd);
goto out; return -ENOENT;
} }
finish_lookup: finish_lookup:
if (nd->depth) if (nd->depth)
put_link(nd); put_link(nd);
error = should_follow_link(nd, &path, nd->flags & LOOKUP_FOLLOW); error = should_follow_link(nd, &path, nd->flags & LOOKUP_FOLLOW);
if (unlikely(error)) { if (unlikely(error))
if (error < 0)
goto out;
return error; return error;
}
if (unlikely(d_is_symlink(path.dentry)) && !(open_flag & O_PATH)) { if (unlikely(d_is_symlink(path.dentry)) && !(open_flag & O_PATH)) {
path_to_nameidata(&path, nd); path_to_nameidata(&path, nd);
error = -ELOOP; return -ELOOP;
goto out;
} }
if ((nd->flags & LOOKUP_RCU) || nd->path.mnt != path.mnt) { if ((nd->flags & LOOKUP_RCU) || nd->path.mnt != path.mnt) {
...@@ -3165,12 +3130,8 @@ static int do_last(struct nameidata *nd, ...@@ -3165,12 +3130,8 @@ static int do_last(struct nameidata *nd,
if (got_write) if (got_write)
mnt_drop_write(nd->path.mnt); mnt_drop_write(nd->path.mnt);
path_put(&save_parent); path_put(&save_parent);
terminate_walk(nd);
return error; return error;
exit_dput:
path_put_conditional(&path, nd);
goto out;
exit_fput: exit_fput:
fput(file); fput(file);
goto out; goto out;
...@@ -3289,6 +3250,7 @@ static struct file *path_openat(int dfd, struct filename *pathname, ...@@ -3289,6 +3250,7 @@ static struct file *path_openat(int dfd, struct filename *pathname,
break; break;
} }
} }
terminate_walk(nd);
path_cleanup(nd); path_cleanup(nd);
out2: out2:
if (!(opened & FILE_OPENED)) { if (!(opened & FILE_OPENED)) {
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册