Commit ee0827cd authored by Al Viro's avatar Al Viro

sanitize path_walk() mess

New helper: path_lookupat().  Basically, what do_path_lookup() boils to
modulo -ECHILD/-ESTALE handler.  path_walk* family is gone; vfs_path_lookup()
is using link_path_walk() directly, do_path_lookup() and do_filp_open()
are using path_lookupat().
Signed-off-by: default avatarAl Viro <viro@zeniv.linux.org.uk>
parent 52094c8a
...@@ -1520,59 +1520,6 @@ static int link_path_walk(const char *name, struct nameidata *nd) ...@@ -1520,59 +1520,6 @@ static int link_path_walk(const char *name, struct nameidata *nd)
return err; return err;
} }
static inline int path_walk_rcu(const char *name, struct nameidata *nd)
{
current->total_link_count = 0;
return link_path_walk(name, nd);
}
static inline int path_walk_simple(const char *name, struct nameidata *nd)
{
current->total_link_count = 0;
return link_path_walk(name, nd);
}
static int path_walk(const char *name, struct nameidata *nd)
{
struct path save = nd->path;
int result;
current->total_link_count = 0;
/* make sure the stuff we saved doesn't go away */
path_get(&save);
result = link_path_walk(name, nd);
if (result == -ESTALE) {
/* nd->path had been dropped */
current->total_link_count = 0;
nd->path = save;
nd->inode = save.dentry->d_inode;
path_get(&nd->path);
nd->flags |= LOOKUP_REVAL;
result = link_path_walk(name, nd);
}
path_put(&save);
return result;
}
static void path_finish_rcu(struct nameidata *nd)
{
if (nd->flags & LOOKUP_RCU) {
/* RCU dangling. Cancel it. */
nd->flags &= ~LOOKUP_RCU;
nd->root.mnt = NULL;
rcu_read_unlock();
br_read_unlock(vfsmount_lock);
}
if (nd->file)
fput(nd->file);
}
static int path_init_rcu(int dfd, const char *name, unsigned int flags, struct nameidata *nd) static int path_init_rcu(int dfd, const char *name, unsigned int flags, struct nameidata *nd)
{ {
int retval = 0; int retval = 0;
...@@ -1697,7 +1644,7 @@ static int path_init(int dfd, const char *name, unsigned int flags, struct namei ...@@ -1697,7 +1644,7 @@ static int path_init(int dfd, const char *name, unsigned int flags, struct namei
} }
/* Returns 0 and nd will be valid on success; Retuns error, otherwise. */ /* Returns 0 and nd will be valid on success; Retuns error, otherwise. */
static int do_path_lookup(int dfd, const char *name, static int path_lookupat(int dfd, const char *name,
unsigned int flags, struct nameidata *nd) unsigned int flags, struct nameidata *nd)
{ {
int retval; int retval;
...@@ -1716,29 +1663,45 @@ static int do_path_lookup(int dfd, const char *name, ...@@ -1716,29 +1663,45 @@ static int do_path_lookup(int dfd, const char *name,
* be handled by restarting a traditional ref-walk (which will always * be handled by restarting a traditional ref-walk (which will always
* be able to complete). * be able to complete).
*/ */
retval = path_init_rcu(dfd, name, flags, nd); if (flags & LOOKUP_RCU)
retval = path_init_rcu(dfd, name, flags, nd);
else
retval = path_init(dfd, name, flags, nd);
if (unlikely(retval)) if (unlikely(retval))
return retval; return retval;
retval = path_walk_rcu(name, nd);
path_finish_rcu(nd); current->total_link_count = 0;
retval = link_path_walk(name, nd);
if (nd->flags & LOOKUP_RCU) {
/* RCU dangling. Cancel it. */
nd->flags &= ~LOOKUP_RCU;
nd->root.mnt = NULL;
rcu_read_unlock();
br_read_unlock(vfsmount_lock);
}
if (nd->file) {
fput(nd->file);
nd->file = NULL;
}
if (nd->root.mnt) { if (nd->root.mnt) {
path_put(&nd->root); path_put(&nd->root);
nd->root.mnt = NULL; nd->root.mnt = NULL;
} }
return retval;
}
if (unlikely(retval == -ECHILD || retval == -ESTALE)) { static int do_path_lookup(int dfd, const char *name,
/* slower, locked walk */ unsigned int flags, struct nameidata *nd)
if (retval == -ESTALE) {
flags |= LOOKUP_REVAL; int retval = path_lookupat(dfd, name, flags | LOOKUP_RCU, nd);
retval = path_init(dfd, name, flags, nd); if (unlikely(retval == -ECHILD))
if (unlikely(retval)) retval = path_lookupat(dfd, name, flags, nd);
return retval; if (unlikely(retval == -ESTALE))
retval = path_walk(name, nd); retval = path_lookupat(dfd, name, flags | LOOKUP_REVAL, nd);
if (nd->root.mnt) {
path_put(&nd->root);
nd->root.mnt = NULL;
}
}
if (likely(!retval)) { if (likely(!retval)) {
if (unlikely(!audit_dummy_context())) { if (unlikely(!audit_dummy_context())) {
...@@ -1746,7 +1709,6 @@ static int do_path_lookup(int dfd, const char *name, ...@@ -1746,7 +1709,6 @@ static int do_path_lookup(int dfd, const char *name,
audit_inode(name, nd->path.dentry); audit_inode(name, nd->path.dentry);
} }
} }
return retval; return retval;
} }
...@@ -1776,7 +1738,7 @@ int vfs_path_lookup(struct dentry *dentry, struct vfsmount *mnt, ...@@ -1776,7 +1738,7 @@ int vfs_path_lookup(struct dentry *dentry, struct vfsmount *mnt,
const char *name, unsigned int flags, const char *name, unsigned int flags,
struct nameidata *nd) struct nameidata *nd)
{ {
int retval; int result;
/* same as do_path_lookup */ /* same as do_path_lookup */
nd->last_type = LAST_ROOT; nd->last_type = LAST_ROOT;
...@@ -1790,15 +1752,27 @@ int vfs_path_lookup(struct dentry *dentry, struct vfsmount *mnt, ...@@ -1790,15 +1752,27 @@ int vfs_path_lookup(struct dentry *dentry, struct vfsmount *mnt,
path_get(&nd->root); path_get(&nd->root);
nd->inode = nd->path.dentry->d_inode; nd->inode = nd->path.dentry->d_inode;
retval = path_walk(name, nd); current->total_link_count = 0;
if (unlikely(!retval && !audit_dummy_context() && nd->path.dentry &&
result = link_path_walk(name, nd);
if (result == -ESTALE) {
/* nd->path had been dropped */
current->total_link_count = 0;
nd->path.dentry = dentry;
nd->path.mnt = mnt;
nd->inode = dentry->d_inode;
path_get(&nd->path);
nd->flags |= LOOKUP_REVAL;
result = link_path_walk(name, nd);
}
if (unlikely(!result && !audit_dummy_context() && nd->path.dentry &&
nd->inode)) nd->inode))
audit_inode(name, nd->path.dentry); audit_inode(name, nd->path.dentry);
path_put(&nd->root); path_put(&nd->root);
nd->root.mnt = NULL; nd->root.mnt = NULL;
return retval; return result;
} }
static struct dentry *__lookup_hash(struct qstr *name, static struct dentry *__lookup_hash(struct qstr *name,
...@@ -2483,24 +2457,14 @@ struct file *do_filp_open(int dfd, const char *pathname, ...@@ -2483,24 +2457,14 @@ struct file *do_filp_open(int dfd, const char *pathname,
creat: creat:
/* OK, have to create the file. Find the parent. */ /* OK, have to create the file. Find the parent. */
error = path_init_rcu(dfd, pathname, error = path_lookupat(dfd, pathname, LOOKUP_PARENT | LOOKUP_RCU, &nd);
LOOKUP_PARENT | (flags & LOOKUP_REVAL), &nd); if (unlikely(error == -ECHILD))
if (error) error = path_lookupat(dfd, pathname, LOOKUP_PARENT, &nd);
goto out_filp; if (unlikely(error == -ESTALE)) {
error = path_walk_rcu(pathname, &nd);
path_finish_rcu(&nd);
if (unlikely(error == -ECHILD || error == -ESTALE)) {
/* slower, locked walk */
if (error == -ESTALE) {
reval: reval:
flags |= LOOKUP_REVAL; flags |= LOOKUP_REVAL;
} error = path_lookupat(dfd, pathname,
error = path_init(dfd, pathname, LOOKUP_PARENT | LOOKUP_REVAL, &nd);
LOOKUP_PARENT | (flags & LOOKUP_REVAL), &nd);
if (error)
goto out_filp;
error = path_walk_simple(pathname, &nd);
} }
if (unlikely(error)) if (unlikely(error))
goto out_filp; goto out_filp;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment