diff options
author | Al Viro <viro@zeniv.linux.org.uk> | 2015-05-08 17:19:59 -0400 |
---|---|---|
committer | Al Viro <viro@zeniv.linux.org.uk> | 2015-05-11 08:10:41 -0400 |
commit | 368ee9ba565d6e13912791b05f3cc1dfa945a62a (patch) | |
tree | 132a7c04f8b8307ba478b61d8ec792a66ecd28b6 /fs/namei.c | |
parent | 34a26b99b78148ff342801e732bf20014c291d03 (diff) |
namei: path_init() calling conventions change
* lift link_path_walk() into callers; moving it down into path_init()
had been a mistake. Stack footprint, among other things...
* do _not_ call path_cleanup() after path_init() failure; on all failure
exits out of it we have nothing for path_cleanup() to do
* have path_init() return pathname or ERR_PTR(-E...)
Signed-off-by: Al Viro <viro@zeniv.linux.org.uk>
Diffstat (limited to 'fs/namei.c')
-rw-r--r-- | fs/namei.c | 69 |
1 files changed, 35 insertions, 34 deletions
diff --git a/fs/namei.c b/fs/namei.c index 497d5f4163b6..06c71200be48 100644 --- a/fs/namei.c +++ b/fs/namei.c @@ -1821,11 +1821,11 @@ static int link_path_walk(const char *name, struct nameidata *nd) } while (unlikely(*name == '/')); if (unlikely(!*name)) { OK: - /* called from path_init(), done */ + /* pathname body, done */ if (!nd->depth) return 0; name = nd->stack[nd->depth - 1].name; - /* called from trailing_symlink(), done */ + /* trailing symlink, done */ if (!name) return 0; /* last component of nested symlink */ @@ -1862,8 +1862,8 @@ OK: return err; } -static int path_init(int dfd, const struct filename *name, unsigned int flags, - struct nameidata *nd) +static const char *path_init(int dfd, const struct filename *name, + unsigned int flags, struct nameidata *nd) { int retval = 0; const char *s = name->name; @@ -1871,15 +1871,16 @@ static int path_init(int dfd, const struct filename *name, unsigned int flags, nd->last_type = LAST_ROOT; /* if there are only slashes... */ nd->flags = flags | LOOKUP_JUMPED | LOOKUP_PARENT; nd->depth = 0; + nd->total_link_count = 0; if (flags & LOOKUP_ROOT) { struct dentry *root = nd->root.dentry; struct inode *inode = root->d_inode; if (*s) { if (!d_can_lookup(root)) - return -ENOTDIR; + return ERR_PTR(-ENOTDIR); retval = inode_permission(inode, MAY_EXEC); if (retval) - return retval; + return ERR_PTR(retval); } nd->path = nd->root; nd->inode = inode; @@ -1890,7 +1891,7 @@ static int path_init(int dfd, const struct filename *name, unsigned int flags, } else { path_get(&nd->path); } - goto done; + return s; } nd->root.mnt = NULL; @@ -1926,14 +1927,14 @@ static int path_init(int dfd, const struct filename *name, unsigned int flags, struct dentry *dentry; if (!f.file) - return -EBADF; + return ERR_PTR(-EBADF); dentry = f.file->f_path.dentry; if (*s) { if (!d_can_lookup(dentry)) { fdput(f); - return -ENOTDIR; + return ERR_PTR(-ENOTDIR); } } @@ -1947,21 +1948,18 @@ static int path_init(int dfd, const struct filename *name, unsigned int flags, nd->inode = nd->path.dentry->d_inode; } fdput(f); - goto done; + return s; } nd->inode = nd->path.dentry->d_inode; if (!(flags & LOOKUP_RCU)) - goto done; + return s; if (likely(!read_seqcount_retry(&nd->path.dentry->d_seq, nd->seq))) - goto done; + return s; if (!(nd->flags & LOOKUP_ROOT)) nd->root.mnt = NULL; rcu_read_unlock(); - return -ECHILD; -done: - nd->total_link_count = 0; - return link_path_walk(s, nd); + return ERR_PTR(-ECHILD); } static void path_cleanup(struct nameidata *nd) @@ -2014,23 +2012,12 @@ static inline int lookup_last(struct nameidata *nd) static int path_lookupat(int dfd, const struct filename *name, unsigned int flags, struct nameidata *nd) { + const char *s = path_init(dfd, name, flags, nd); int err; - /* - * Path walking is largely split up into 2 different synchronisation - * schemes, rcu-walk and ref-walk (explained in - * Documentation/filesystems/path-lookup.txt). These share much of the - * path walk code, but some things particularly setup, cleanup, and - * following mounts are sufficiently divergent that functions are - * duplicated. Typically there is a function foo(), and its RCU - * analogue, foo_rcu(). - * - * -ECHILD is the error number of choice (just to avoid clashes) that - * is returned if some aspect of an rcu-walk fails. Such an error must - * be handled by restarting a traditional ref-walk (which will always - * be able to complete). - */ - err = path_init(dfd, name, flags, nd); + if (IS_ERR(s)) + return PTR_ERR(s); + err = link_path_walk(s, nd); if (!err) { while ((err = lookup_last(nd)) > 0) { err = trailing_symlink(nd); @@ -2075,7 +2062,11 @@ static int filename_lookup(int dfd, struct filename *name, static int path_parentat(int dfd, const struct filename *name, unsigned int flags, struct nameidata *nd) { - int err = path_init(dfd, name, flags | LOOKUP_PARENT, nd); + const char *s = path_init(dfd, name, flags, nd); + int err; + if (IS_ERR(s)) + return PTR_ERR(s); + err = link_path_walk(s, nd); if (!err) err = complete_walk(nd); path_cleanup(nd); @@ -2406,7 +2397,11 @@ static int path_mountpoint(int dfd, const struct filename *name, struct path *path, struct nameidata *nd, unsigned int flags) { - int err = path_init(dfd, name, flags, nd); + const char *s = path_init(dfd, name, flags, nd); + int err; + if (IS_ERR(s)) + return PTR_ERR(s); + err = link_path_walk(s, nd); if (unlikely(err)) goto out; @@ -3266,6 +3261,7 @@ out: static struct file *path_openat(int dfd, struct filename *pathname, struct nameidata *nd, const struct open_flags *op, int flags) { + const char *s; struct file *file; int opened = 0; int error; @@ -3281,7 +3277,12 @@ static struct file *path_openat(int dfd, struct filename *pathname, goto out2; } - error = path_init(dfd, pathname, flags, nd); + s = path_init(dfd, pathname, flags, nd); + if (IS_ERR(s)) { + put_filp(file); + return ERR_CAST(s); + } + error = link_path_walk(s, nd); if (unlikely(error)) goto out; |