diff options
author | Al Viro <viro@zeniv.linux.org.uk> | 2015-05-08 18:05:21 -0400 |
---|---|---|
committer | Al Viro <viro@zeniv.linux.org.uk> | 2015-05-11 08:13:08 -0400 |
commit | deb106c632d73c96b6b2b5ca71bacb8aef38fc7b (patch) | |
tree | 87ffe76ba593ac0a061f2058fcb418eb6183d1a4 /fs/namei.c | |
parent | 3bdba28b72f5d2e7f3df031b04008b9a6fbdc775 (diff) |
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: Al Viro <viro@zeniv.linux.org.uk>
Diffstat (limited to 'fs/namei.c')
-rw-r--r-- | fs/namei.c | 106 |
1 files changed, 34 insertions, 72 deletions
diff --git a/fs/namei.c b/fs/namei.c index 46f4266d1f7f..27c38591b4ec 100644 --- a/fs/namei.c +++ b/fs/namei.c | |||
@@ -563,8 +563,6 @@ static inline int nd_alloc_stack(struct nameidata *nd) | |||
563 | * to restart the path walk from the beginning in ref-walk mode. | 563 | * to restart the path walk from the beginning in ref-walk mode. |
564 | */ | 564 | */ |
565 | 565 | ||
566 | static void terminate_walk(struct nameidata *nd); | ||
567 | |||
568 | /** | 566 | /** |
569 | * unlazy_walk - try to switch to ref-walk mode. | 567 | * unlazy_walk - try to switch to ref-walk mode. |
570 | * @nd: nameidata pathwalk data | 568 | * @nd: nameidata pathwalk data |
@@ -673,10 +671,8 @@ static int complete_walk(struct nameidata *nd) | |||
673 | if (nd->flags & LOOKUP_RCU) { | 671 | if (nd->flags & LOOKUP_RCU) { |
674 | if (!(nd->flags & LOOKUP_ROOT)) | 672 | if (!(nd->flags & LOOKUP_ROOT)) |
675 | nd->root.mnt = NULL; | 673 | nd->root.mnt = NULL; |
676 | if (unlikely(unlazy_walk(nd, NULL))) { | 674 | if (unlikely(unlazy_walk(nd, NULL))) |
677 | terminate_walk(nd); | ||
678 | return -ECHILD; | 675 | return -ECHILD; |
679 | } | ||
680 | } | 676 | } |
681 | 677 | ||
682 | if (likely(!(nd->flags & LOOKUP_JUMPED))) | 678 | if (likely(!(nd->flags & LOOKUP_JUMPED))) |
@@ -692,7 +688,6 @@ static int complete_walk(struct nameidata *nd) | |||
692 | if (!status) | 688 | if (!status) |
693 | status = -ESTALE; | 689 | status = -ESTALE; |
694 | 690 | ||
695 | terminate_walk(nd); | ||
696 | return status; | 691 | return status; |
697 | } | 692 | } |
698 | 693 | ||
@@ -1858,7 +1853,6 @@ OK: | |||
1858 | break; | 1853 | break; |
1859 | } | 1854 | } |
1860 | } | 1855 | } |
1861 | terminate_walk(nd); | ||
1862 | return err; | 1856 | return err; |
1863 | } | 1857 | } |
1864 | 1858 | ||
@@ -1974,38 +1968,26 @@ static const char *trailing_symlink(struct nameidata *nd) | |||
1974 | { | 1968 | { |
1975 | const char *s; | 1969 | const char *s; |
1976 | int error = may_follow_link(nd); | 1970 | int error = may_follow_link(nd); |
1977 | if (unlikely(error)) { | 1971 | if (unlikely(error)) |
1978 | terminate_walk(nd); | ||
1979 | return ERR_PTR(error); | 1972 | return ERR_PTR(error); |
1980 | } | ||
1981 | nd->flags |= LOOKUP_PARENT; | 1973 | nd->flags |= LOOKUP_PARENT; |
1982 | nd->stack[0].name = NULL; | 1974 | nd->stack[0].name = NULL; |
1983 | s = get_link(nd); | 1975 | s = get_link(nd); |
1984 | if (unlikely(IS_ERR(s))) { | 1976 | return s ? s : ""; |
1985 | terminate_walk(nd); | ||
1986 | return s; | ||
1987 | } | ||
1988 | if (unlikely(!s)) | ||
1989 | s = ""; | ||
1990 | return s; | ||
1991 | } | 1977 | } |
1992 | 1978 | ||
1993 | static inline int lookup_last(struct nameidata *nd) | 1979 | static inline int lookup_last(struct nameidata *nd) |
1994 | { | 1980 | { |
1995 | int err; | ||
1996 | if (nd->last_type == LAST_NORM && nd->last.name[nd->last.len]) | 1981 | if (nd->last_type == LAST_NORM && nd->last.name[nd->last.len]) |
1997 | nd->flags |= LOOKUP_FOLLOW | LOOKUP_DIRECTORY; | 1982 | nd->flags |= LOOKUP_FOLLOW | LOOKUP_DIRECTORY; |
1998 | 1983 | ||
1999 | nd->flags &= ~LOOKUP_PARENT; | 1984 | nd->flags &= ~LOOKUP_PARENT; |
2000 | err = walk_component(nd, | 1985 | return walk_component(nd, |
2001 | nd->flags & LOOKUP_FOLLOW | 1986 | nd->flags & LOOKUP_FOLLOW |
2002 | ? nd->depth | 1987 | ? nd->depth |
2003 | ? WALK_PUT | WALK_GET | 1988 | ? WALK_PUT | WALK_GET |
2004 | : WALK_GET | 1989 | : WALK_GET |
2005 | : 0); | 1990 | : 0); |
2006 | if (err < 0) | ||
2007 | terminate_walk(nd); | ||
2008 | return err; | ||
2009 | } | 1991 | } |
2010 | 1992 | ||
2011 | /* Returns 0 and nd will be valid on success; Retuns error, otherwise. */ | 1993 | /* 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 | break; | 2007 | break; |
2026 | } | 2008 | } |
2027 | } | 2009 | } |
2028 | |||
2029 | if (!err) | 2010 | if (!err) |
2030 | err = complete_walk(nd); | 2011 | err = complete_walk(nd); |
2031 | 2012 | ||
2032 | if (!err && nd->flags & LOOKUP_DIRECTORY) { | 2013 | if (!err && nd->flags & LOOKUP_DIRECTORY) |
2033 | if (!d_can_lookup(nd->path.dentry)) { | 2014 | if (!d_can_lookup(nd->path.dentry)) |
2034 | path_put(&nd->path); | ||
2035 | err = -ENOTDIR; | 2015 | err = -ENOTDIR; |
2036 | } | 2016 | if (err) |
2037 | } | 2017 | terminate_walk(nd); |
2038 | 2018 | ||
2039 | path_cleanup(nd); | 2019 | path_cleanup(nd); |
2040 | return err; | 2020 | return err; |
@@ -2069,6 +2049,8 @@ static int path_parentat(int dfd, const struct filename *name, | |||
2069 | err = link_path_walk(s, nd); | 2049 | err = link_path_walk(s, nd); |
2070 | if (!err) | 2050 | if (!err) |
2071 | err = complete_walk(nd); | 2051 | err = complete_walk(nd); |
2052 | if (err) | ||
2053 | terminate_walk(nd); | ||
2072 | path_cleanup(nd); | 2054 | path_cleanup(nd); |
2073 | return err; | 2055 | return err; |
2074 | } | 2056 | } |
@@ -2320,10 +2302,8 @@ mountpoint_last(struct nameidata *nd, struct path *path) | |||
2320 | 2302 | ||
2321 | /* If we're in rcuwalk, drop out of it to handle last component */ | 2303 | /* If we're in rcuwalk, drop out of it to handle last component */ |
2322 | if (nd->flags & LOOKUP_RCU) { | 2304 | if (nd->flags & LOOKUP_RCU) { |
2323 | if (unlazy_walk(nd, NULL)) { | 2305 | if (unlazy_walk(nd, NULL)) |
2324 | error = -ECHILD; | 2306 | return -ECHILD; |
2325 | goto out; | ||
2326 | } | ||
2327 | } | 2307 | } |
2328 | 2308 | ||
2329 | nd->flags &= ~LOOKUP_PARENT; | 2309 | nd->flags &= ~LOOKUP_PARENT; |
@@ -2331,7 +2311,7 @@ mountpoint_last(struct nameidata *nd, struct path *path) | |||
2331 | if (unlikely(nd->last_type != LAST_NORM)) { | 2311 | if (unlikely(nd->last_type != LAST_NORM)) { |
2332 | error = handle_dots(nd, nd->last_type); | 2312 | error = handle_dots(nd, nd->last_type); |
2333 | if (error) | 2313 | if (error) |
2334 | goto out; | 2314 | return error; |
2335 | dentry = dget(nd->path.dentry); | 2315 | dentry = dget(nd->path.dentry); |
2336 | goto done; | 2316 | goto done; |
2337 | } | 2317 | } |
@@ -2346,41 +2326,32 @@ mountpoint_last(struct nameidata *nd, struct path *path) | |||
2346 | */ | 2326 | */ |
2347 | dentry = d_alloc(dir, &nd->last); | 2327 | dentry = d_alloc(dir, &nd->last); |
2348 | if (!dentry) { | 2328 | if (!dentry) { |
2349 | error = -ENOMEM; | ||
2350 | mutex_unlock(&dir->d_inode->i_mutex); | 2329 | mutex_unlock(&dir->d_inode->i_mutex); |
2351 | goto out; | 2330 | return -ENOMEM; |
2352 | } | 2331 | } |
2353 | dentry = lookup_real(dir->d_inode, dentry, nd->flags); | 2332 | dentry = lookup_real(dir->d_inode, dentry, nd->flags); |
2354 | error = PTR_ERR(dentry); | ||
2355 | if (IS_ERR(dentry)) { | 2333 | if (IS_ERR(dentry)) { |
2356 | mutex_unlock(&dir->d_inode->i_mutex); | 2334 | mutex_unlock(&dir->d_inode->i_mutex); |
2357 | goto out; | 2335 | return PTR_ERR(dentry); |
2358 | } | 2336 | } |
2359 | } | 2337 | } |
2360 | mutex_unlock(&dir->d_inode->i_mutex); | 2338 | mutex_unlock(&dir->d_inode->i_mutex); |
2361 | 2339 | ||
2362 | done: | 2340 | done: |
2363 | if (d_is_negative(dentry)) { | 2341 | if (d_is_negative(dentry)) { |
2364 | error = -ENOENT; | ||
2365 | dput(dentry); | 2342 | dput(dentry); |
2366 | goto out; | 2343 | return -ENOENT; |
2367 | } | 2344 | } |
2368 | if (nd->depth) | 2345 | if (nd->depth) |
2369 | put_link(nd); | 2346 | put_link(nd); |
2370 | path->dentry = dentry; | 2347 | path->dentry = dentry; |
2371 | path->mnt = nd->path.mnt; | 2348 | path->mnt = nd->path.mnt; |
2372 | error = should_follow_link(nd, path, nd->flags & LOOKUP_FOLLOW); | 2349 | error = should_follow_link(nd, path, nd->flags & LOOKUP_FOLLOW); |
2373 | if (unlikely(error)) { | 2350 | if (unlikely(error)) |
2374 | if (error < 0) | ||
2375 | goto out; | ||
2376 | return error; | 2351 | return error; |
2377 | } | ||
2378 | mntget(path->mnt); | 2352 | mntget(path->mnt); |
2379 | follow_mount(path); | 2353 | follow_mount(path); |
2380 | error = 0; | 2354 | return 0; |
2381 | out: | ||
2382 | terminate_walk(nd); | ||
2383 | return error; | ||
2384 | } | 2355 | } |
2385 | 2356 | ||
2386 | /** | 2357 | /** |
@@ -2409,6 +2380,7 @@ path_mountpoint(int dfd, const struct filename *name, struct path *path, | |||
2409 | break; | 2380 | break; |
2410 | } | 2381 | } |
2411 | } | 2382 | } |
2383 | terminate_walk(nd); | ||
2412 | path_cleanup(nd); | 2384 | path_cleanup(nd); |
2413 | return err; | 2385 | return err; |
2414 | } | 2386 | } |
@@ -2982,10 +2954,8 @@ static int do_last(struct nameidata *nd, | |||
2982 | 2954 | ||
2983 | if (nd->last_type != LAST_NORM) { | 2955 | if (nd->last_type != LAST_NORM) { |
2984 | error = handle_dots(nd, nd->last_type); | 2956 | error = handle_dots(nd, nd->last_type); |
2985 | if (unlikely(error)) { | 2957 | if (unlikely(error)) |
2986 | terminate_walk(nd); | ||
2987 | return error; | 2958 | return error; |
2988 | } | ||
2989 | goto finish_open; | 2959 | goto finish_open; |
2990 | } | 2960 | } |
2991 | 2961 | ||
@@ -2998,7 +2968,7 @@ static int do_last(struct nameidata *nd, | |||
2998 | goto finish_lookup; | 2968 | goto finish_lookup; |
2999 | 2969 | ||
3000 | if (error < 0) | 2970 | if (error < 0) |
3001 | goto out; | 2971 | return error; |
3002 | 2972 | ||
3003 | BUG_ON(nd->inode != dir->d_inode); | 2973 | BUG_ON(nd->inode != dir->d_inode); |
3004 | } else { | 2974 | } else { |
@@ -3013,10 +2983,9 @@ static int do_last(struct nameidata *nd, | |||
3013 | return error; | 2983 | return error; |
3014 | 2984 | ||
3015 | audit_inode(name, dir, LOOKUP_PARENT); | 2985 | audit_inode(name, dir, LOOKUP_PARENT); |
3016 | error = -EISDIR; | ||
3017 | /* trailing slashes? */ | 2986 | /* trailing slashes? */ |
3018 | if (nd->last.name[nd->last.len]) | 2987 | if (unlikely(nd->last.name[nd->last.len])) |
3019 | goto out; | 2988 | return -EISDIR; |
3020 | } | 2989 | } |
3021 | 2990 | ||
3022 | retry_lookup: | 2991 | retry_lookup: |
@@ -3071,35 +3040,31 @@ retry_lookup: | |||
3071 | got_write = false; | 3040 | got_write = false; |
3072 | } | 3041 | } |
3073 | 3042 | ||
3074 | error = -EEXIST; | 3043 | if (unlikely((open_flag & (O_EXCL | O_CREAT)) == (O_EXCL | O_CREAT))) { |
3075 | if ((open_flag & (O_EXCL | O_CREAT)) == (O_EXCL | O_CREAT)) | 3044 | path_to_nameidata(&path, nd); |
3076 | goto exit_dput; | 3045 | return -EEXIST; |
3046 | } | ||
3077 | 3047 | ||
3078 | error = follow_managed(&path, nd); | 3048 | error = follow_managed(&path, nd); |
3079 | if (error < 0) | 3049 | if (unlikely(error < 0)) |
3080 | goto out; | 3050 | return error; |
3081 | 3051 | ||
3082 | BUG_ON(nd->flags & LOOKUP_RCU); | 3052 | BUG_ON(nd->flags & LOOKUP_RCU); |
3083 | inode = path.dentry->d_inode; | 3053 | inode = path.dentry->d_inode; |
3084 | error = -ENOENT; | 3054 | if (unlikely(d_is_negative(path.dentry))) { |
3085 | if (d_is_negative(path.dentry)) { | ||
3086 | path_to_nameidata(&path, nd); | 3055 | path_to_nameidata(&path, nd); |
3087 | goto out; | 3056 | return -ENOENT; |
3088 | } | 3057 | } |
3089 | finish_lookup: | 3058 | finish_lookup: |
3090 | if (nd->depth) | 3059 | if (nd->depth) |
3091 | put_link(nd); | 3060 | put_link(nd); |
3092 | error = should_follow_link(nd, &path, nd->flags & LOOKUP_FOLLOW); | 3061 | error = should_follow_link(nd, &path, nd->flags & LOOKUP_FOLLOW); |
3093 | if (unlikely(error)) { | 3062 | if (unlikely(error)) |
3094 | if (error < 0) | ||
3095 | goto out; | ||
3096 | return error; | 3063 | return error; |
3097 | } | ||
3098 | 3064 | ||
3099 | if (unlikely(d_is_symlink(path.dentry)) && !(open_flag & O_PATH)) { | 3065 | if (unlikely(d_is_symlink(path.dentry)) && !(open_flag & O_PATH)) { |
3100 | path_to_nameidata(&path, nd); | 3066 | path_to_nameidata(&path, nd); |
3101 | error = -ELOOP; | 3067 | return -ELOOP; |
3102 | goto out; | ||
3103 | } | 3068 | } |
3104 | 3069 | ||
3105 | if ((nd->flags & LOOKUP_RCU) || nd->path.mnt != path.mnt) { | 3070 | if ((nd->flags & LOOKUP_RCU) || nd->path.mnt != path.mnt) { |
@@ -3165,12 +3130,8 @@ out: | |||
3165 | if (got_write) | 3130 | if (got_write) |
3166 | mnt_drop_write(nd->path.mnt); | 3131 | mnt_drop_write(nd->path.mnt); |
3167 | path_put(&save_parent); | 3132 | path_put(&save_parent); |
3168 | terminate_walk(nd); | ||
3169 | return error; | 3133 | return error; |
3170 | 3134 | ||
3171 | exit_dput: | ||
3172 | path_put_conditional(&path, nd); | ||
3173 | goto out; | ||
3174 | exit_fput: | 3135 | exit_fput: |
3175 | fput(file); | 3136 | fput(file); |
3176 | goto out; | 3137 | goto out; |
@@ -3289,6 +3250,7 @@ static struct file *path_openat(int dfd, struct filename *pathname, | |||
3289 | break; | 3250 | break; |
3290 | } | 3251 | } |
3291 | } | 3252 | } |
3253 | terminate_walk(nd); | ||
3292 | path_cleanup(nd); | 3254 | path_cleanup(nd); |
3293 | out2: | 3255 | out2: |
3294 | if (!(opened & FILE_OPENED)) { | 3256 | if (!(opened & FILE_OPENED)) { |