diff options
Diffstat (limited to 'fs/namei.c')
-rw-r--r-- | fs/namei.c | 118 |
1 files changed, 80 insertions, 38 deletions
diff --git a/fs/namei.c b/fs/namei.c index 5f4cdf3ad913..43a97ee1d4c8 100644 --- a/fs/namei.c +++ b/fs/namei.c | |||
@@ -1275,9 +1275,7 @@ static struct dentry *lookup_dcache(struct qstr *name, struct dentry *dir, | |||
1275 | *need_lookup = false; | 1275 | *need_lookup = false; |
1276 | dentry = d_lookup(dir, name); | 1276 | dentry = d_lookup(dir, name); |
1277 | if (dentry) { | 1277 | if (dentry) { |
1278 | if (d_need_lookup(dentry)) { | 1278 | if (dentry->d_flags & DCACHE_OP_REVALIDATE) { |
1279 | *need_lookup = true; | ||
1280 | } else if (dentry->d_flags & DCACHE_OP_REVALIDATE) { | ||
1281 | error = d_revalidate(dentry, flags); | 1279 | error = d_revalidate(dentry, flags); |
1282 | if (unlikely(error <= 0)) { | 1280 | if (unlikely(error <= 0)) { |
1283 | if (error < 0) { | 1281 | if (error < 0) { |
@@ -1383,8 +1381,6 @@ static int lookup_fast(struct nameidata *nd, struct qstr *name, | |||
1383 | return -ECHILD; | 1381 | return -ECHILD; |
1384 | nd->seq = seq; | 1382 | nd->seq = seq; |
1385 | 1383 | ||
1386 | if (unlikely(d_need_lookup(dentry))) | ||
1387 | goto unlazy; | ||
1388 | if (unlikely(dentry->d_flags & DCACHE_OP_REVALIDATE)) { | 1384 | if (unlikely(dentry->d_flags & DCACHE_OP_REVALIDATE)) { |
1389 | status = d_revalidate(dentry, nd->flags); | 1385 | status = d_revalidate(dentry, nd->flags); |
1390 | if (unlikely(status <= 0)) { | 1386 | if (unlikely(status <= 0)) { |
@@ -1410,11 +1406,6 @@ unlazy: | |||
1410 | if (unlikely(!dentry)) | 1406 | if (unlikely(!dentry)) |
1411 | goto need_lookup; | 1407 | goto need_lookup; |
1412 | 1408 | ||
1413 | if (unlikely(d_need_lookup(dentry))) { | ||
1414 | dput(dentry); | ||
1415 | goto need_lookup; | ||
1416 | } | ||
1417 | |||
1418 | if (unlikely(dentry->d_flags & DCACHE_OP_REVALIDATE) && need_reval) | 1409 | if (unlikely(dentry->d_flags & DCACHE_OP_REVALIDATE) && need_reval) |
1419 | status = d_revalidate(dentry, nd->flags); | 1410 | status = d_revalidate(dentry, nd->flags); |
1420 | if (unlikely(status <= 0)) { | 1411 | if (unlikely(status <= 0)) { |
@@ -1859,7 +1850,7 @@ static int path_init(int dfd, const char *name, unsigned int flags, | |||
1859 | if (flags & LOOKUP_ROOT) { | 1850 | if (flags & LOOKUP_ROOT) { |
1860 | struct inode *inode = nd->root.dentry->d_inode; | 1851 | struct inode *inode = nd->root.dentry->d_inode; |
1861 | if (*name) { | 1852 | if (*name) { |
1862 | if (!inode->i_op->lookup) | 1853 | if (!can_lookup(inode)) |
1863 | return -ENOTDIR; | 1854 | return -ENOTDIR; |
1864 | retval = inode_permission(inode, MAY_EXEC); | 1855 | retval = inode_permission(inode, MAY_EXEC); |
1865 | if (retval) | 1856 | if (retval) |
@@ -1903,6 +1894,7 @@ static int path_init(int dfd, const char *name, unsigned int flags, | |||
1903 | get_fs_pwd(current->fs, &nd->path); | 1894 | get_fs_pwd(current->fs, &nd->path); |
1904 | } | 1895 | } |
1905 | } else { | 1896 | } else { |
1897 | /* Caller must check execute permissions on the starting path component */ | ||
1906 | struct fd f = fdget_raw(dfd); | 1898 | struct fd f = fdget_raw(dfd); |
1907 | struct dentry *dentry; | 1899 | struct dentry *dentry; |
1908 | 1900 | ||
@@ -1912,16 +1904,10 @@ static int path_init(int dfd, const char *name, unsigned int flags, | |||
1912 | dentry = f.file->f_path.dentry; | 1904 | dentry = f.file->f_path.dentry; |
1913 | 1905 | ||
1914 | if (*name) { | 1906 | if (*name) { |
1915 | if (!S_ISDIR(dentry->d_inode->i_mode)) { | 1907 | if (!can_lookup(dentry->d_inode)) { |
1916 | fdput(f); | 1908 | fdput(f); |
1917 | return -ENOTDIR; | 1909 | return -ENOTDIR; |
1918 | } | 1910 | } |
1919 | |||
1920 | retval = inode_permission(dentry->d_inode, MAY_EXEC); | ||
1921 | if (retval) { | ||
1922 | fdput(f); | ||
1923 | return retval; | ||
1924 | } | ||
1925 | } | 1911 | } |
1926 | 1912 | ||
1927 | nd->path = f.file->f_path; | 1913 | nd->path = f.file->f_path; |
@@ -2189,15 +2175,19 @@ int user_path_at(int dfd, const char __user *name, unsigned flags, | |||
2189 | * path-walking is complete. | 2175 | * path-walking is complete. |
2190 | */ | 2176 | */ |
2191 | static struct filename * | 2177 | static struct filename * |
2192 | user_path_parent(int dfd, const char __user *path, struct nameidata *nd) | 2178 | user_path_parent(int dfd, const char __user *path, struct nameidata *nd, |
2179 | unsigned int flags) | ||
2193 | { | 2180 | { |
2194 | struct filename *s = getname(path); | 2181 | struct filename *s = getname(path); |
2195 | int error; | 2182 | int error; |
2196 | 2183 | ||
2184 | /* only LOOKUP_REVAL is allowed in extra flags */ | ||
2185 | flags &= LOOKUP_REVAL; | ||
2186 | |||
2197 | if (IS_ERR(s)) | 2187 | if (IS_ERR(s)) |
2198 | return s; | 2188 | return s; |
2199 | 2189 | ||
2200 | error = filename_lookup(dfd, s, LOOKUP_PARENT, nd); | 2190 | error = filename_lookup(dfd, s, flags | LOOKUP_PARENT, nd); |
2201 | if (error) { | 2191 | if (error) { |
2202 | putname(s); | 2192 | putname(s); |
2203 | return ERR_PTR(error); | 2193 | return ERR_PTR(error); |
@@ -3044,12 +3034,22 @@ struct file *do_file_open_root(struct dentry *dentry, struct vfsmount *mnt, | |||
3044 | return file; | 3034 | return file; |
3045 | } | 3035 | } |
3046 | 3036 | ||
3047 | struct dentry *kern_path_create(int dfd, const char *pathname, struct path *path, int is_dir) | 3037 | struct dentry *kern_path_create(int dfd, const char *pathname, |
3038 | struct path *path, unsigned int lookup_flags) | ||
3048 | { | 3039 | { |
3049 | struct dentry *dentry = ERR_PTR(-EEXIST); | 3040 | struct dentry *dentry = ERR_PTR(-EEXIST); |
3050 | struct nameidata nd; | 3041 | struct nameidata nd; |
3051 | int err2; | 3042 | int err2; |
3052 | int error = do_path_lookup(dfd, pathname, LOOKUP_PARENT, &nd); | 3043 | int error; |
3044 | bool is_dir = (lookup_flags & LOOKUP_DIRECTORY); | ||
3045 | |||
3046 | /* | ||
3047 | * Note that only LOOKUP_REVAL and LOOKUP_DIRECTORY matter here. Any | ||
3048 | * other flags passed in are ignored! | ||
3049 | */ | ||
3050 | lookup_flags &= LOOKUP_REVAL; | ||
3051 | |||
3052 | error = do_path_lookup(dfd, pathname, LOOKUP_PARENT|lookup_flags, &nd); | ||
3053 | if (error) | 3053 | if (error) |
3054 | return ERR_PTR(error); | 3054 | return ERR_PTR(error); |
3055 | 3055 | ||
@@ -3113,13 +3113,14 @@ void done_path_create(struct path *path, struct dentry *dentry) | |||
3113 | } | 3113 | } |
3114 | EXPORT_SYMBOL(done_path_create); | 3114 | EXPORT_SYMBOL(done_path_create); |
3115 | 3115 | ||
3116 | struct dentry *user_path_create(int dfd, const char __user *pathname, struct path *path, int is_dir) | 3116 | struct dentry *user_path_create(int dfd, const char __user *pathname, |
3117 | struct path *path, unsigned int lookup_flags) | ||
3117 | { | 3118 | { |
3118 | struct filename *tmp = getname(pathname); | 3119 | struct filename *tmp = getname(pathname); |
3119 | struct dentry *res; | 3120 | struct dentry *res; |
3120 | if (IS_ERR(tmp)) | 3121 | if (IS_ERR(tmp)) |
3121 | return ERR_CAST(tmp); | 3122 | return ERR_CAST(tmp); |
3122 | res = kern_path_create(dfd, tmp->name, path, is_dir); | 3123 | res = kern_path_create(dfd, tmp->name, path, lookup_flags); |
3123 | putname(tmp); | 3124 | putname(tmp); |
3124 | return res; | 3125 | return res; |
3125 | } | 3126 | } |
@@ -3175,12 +3176,13 @@ SYSCALL_DEFINE4(mknodat, int, dfd, const char __user *, filename, umode_t, mode, | |||
3175 | struct dentry *dentry; | 3176 | struct dentry *dentry; |
3176 | struct path path; | 3177 | struct path path; |
3177 | int error; | 3178 | int error; |
3179 | unsigned int lookup_flags = 0; | ||
3178 | 3180 | ||
3179 | error = may_mknod(mode); | 3181 | error = may_mknod(mode); |
3180 | if (error) | 3182 | if (error) |
3181 | return error; | 3183 | return error; |
3182 | 3184 | retry: | |
3183 | dentry = user_path_create(dfd, filename, &path, 0); | 3185 | dentry = user_path_create(dfd, filename, &path, lookup_flags); |
3184 | if (IS_ERR(dentry)) | 3186 | if (IS_ERR(dentry)) |
3185 | return PTR_ERR(dentry); | 3187 | return PTR_ERR(dentry); |
3186 | 3188 | ||
@@ -3203,6 +3205,10 @@ SYSCALL_DEFINE4(mknodat, int, dfd, const char __user *, filename, umode_t, mode, | |||
3203 | } | 3205 | } |
3204 | out: | 3206 | out: |
3205 | done_path_create(&path, dentry); | 3207 | done_path_create(&path, dentry); |
3208 | if (retry_estale(error, lookup_flags)) { | ||
3209 | lookup_flags |= LOOKUP_REVAL; | ||
3210 | goto retry; | ||
3211 | } | ||
3206 | return error; | 3212 | return error; |
3207 | } | 3213 | } |
3208 | 3214 | ||
@@ -3241,8 +3247,10 @@ SYSCALL_DEFINE3(mkdirat, int, dfd, const char __user *, pathname, umode_t, mode) | |||
3241 | struct dentry *dentry; | 3247 | struct dentry *dentry; |
3242 | struct path path; | 3248 | struct path path; |
3243 | int error; | 3249 | int error; |
3250 | unsigned int lookup_flags = LOOKUP_DIRECTORY; | ||
3244 | 3251 | ||
3245 | dentry = user_path_create(dfd, pathname, &path, 1); | 3252 | retry: |
3253 | dentry = user_path_create(dfd, pathname, &path, lookup_flags); | ||
3246 | if (IS_ERR(dentry)) | 3254 | if (IS_ERR(dentry)) |
3247 | return PTR_ERR(dentry); | 3255 | return PTR_ERR(dentry); |
3248 | 3256 | ||
@@ -3252,6 +3260,10 @@ SYSCALL_DEFINE3(mkdirat, int, dfd, const char __user *, pathname, umode_t, mode) | |||
3252 | if (!error) | 3260 | if (!error) |
3253 | error = vfs_mkdir(path.dentry->d_inode, dentry, mode); | 3261 | error = vfs_mkdir(path.dentry->d_inode, dentry, mode); |
3254 | done_path_create(&path, dentry); | 3262 | done_path_create(&path, dentry); |
3263 | if (retry_estale(error, lookup_flags)) { | ||
3264 | lookup_flags |= LOOKUP_REVAL; | ||
3265 | goto retry; | ||
3266 | } | ||
3255 | return error; | 3267 | return error; |
3256 | } | 3268 | } |
3257 | 3269 | ||
@@ -3327,8 +3339,9 @@ static long do_rmdir(int dfd, const char __user *pathname) | |||
3327 | struct filename *name; | 3339 | struct filename *name; |
3328 | struct dentry *dentry; | 3340 | struct dentry *dentry; |
3329 | struct nameidata nd; | 3341 | struct nameidata nd; |
3330 | 3342 | unsigned int lookup_flags = 0; | |
3331 | name = user_path_parent(dfd, pathname, &nd); | 3343 | retry: |
3344 | name = user_path_parent(dfd, pathname, &nd, lookup_flags); | ||
3332 | if (IS_ERR(name)) | 3345 | if (IS_ERR(name)) |
3333 | return PTR_ERR(name); | 3346 | return PTR_ERR(name); |
3334 | 3347 | ||
@@ -3370,6 +3383,10 @@ exit2: | |||
3370 | exit1: | 3383 | exit1: |
3371 | path_put(&nd.path); | 3384 | path_put(&nd.path); |
3372 | putname(name); | 3385 | putname(name); |
3386 | if (retry_estale(error, lookup_flags)) { | ||
3387 | lookup_flags |= LOOKUP_REVAL; | ||
3388 | goto retry; | ||
3389 | } | ||
3373 | return error; | 3390 | return error; |
3374 | } | 3391 | } |
3375 | 3392 | ||
@@ -3423,8 +3440,9 @@ static long do_unlinkat(int dfd, const char __user *pathname) | |||
3423 | struct dentry *dentry; | 3440 | struct dentry *dentry; |
3424 | struct nameidata nd; | 3441 | struct nameidata nd; |
3425 | struct inode *inode = NULL; | 3442 | struct inode *inode = NULL; |
3426 | 3443 | unsigned int lookup_flags = 0; | |
3427 | name = user_path_parent(dfd, pathname, &nd); | 3444 | retry: |
3445 | name = user_path_parent(dfd, pathname, &nd, lookup_flags); | ||
3428 | if (IS_ERR(name)) | 3446 | if (IS_ERR(name)) |
3429 | return PTR_ERR(name); | 3447 | return PTR_ERR(name); |
3430 | 3448 | ||
@@ -3462,6 +3480,11 @@ exit2: | |||
3462 | exit1: | 3480 | exit1: |
3463 | path_put(&nd.path); | 3481 | path_put(&nd.path); |
3464 | putname(name); | 3482 | putname(name); |
3483 | if (retry_estale(error, lookup_flags)) { | ||
3484 | lookup_flags |= LOOKUP_REVAL; | ||
3485 | inode = NULL; | ||
3486 | goto retry; | ||
3487 | } | ||
3465 | return error; | 3488 | return error; |
3466 | 3489 | ||
3467 | slashes: | 3490 | slashes: |
@@ -3513,12 +3536,13 @@ SYSCALL_DEFINE3(symlinkat, const char __user *, oldname, | |||
3513 | struct filename *from; | 3536 | struct filename *from; |
3514 | struct dentry *dentry; | 3537 | struct dentry *dentry; |
3515 | struct path path; | 3538 | struct path path; |
3539 | unsigned int lookup_flags = 0; | ||
3516 | 3540 | ||
3517 | from = getname(oldname); | 3541 | from = getname(oldname); |
3518 | if (IS_ERR(from)) | 3542 | if (IS_ERR(from)) |
3519 | return PTR_ERR(from); | 3543 | return PTR_ERR(from); |
3520 | 3544 | retry: | |
3521 | dentry = user_path_create(newdfd, newname, &path, 0); | 3545 | dentry = user_path_create(newdfd, newname, &path, lookup_flags); |
3522 | error = PTR_ERR(dentry); | 3546 | error = PTR_ERR(dentry); |
3523 | if (IS_ERR(dentry)) | 3547 | if (IS_ERR(dentry)) |
3524 | goto out_putname; | 3548 | goto out_putname; |
@@ -3527,6 +3551,10 @@ SYSCALL_DEFINE3(symlinkat, const char __user *, oldname, | |||
3527 | if (!error) | 3551 | if (!error) |
3528 | error = vfs_symlink(path.dentry->d_inode, dentry, from->name); | 3552 | error = vfs_symlink(path.dentry->d_inode, dentry, from->name); |
3529 | done_path_create(&path, dentry); | 3553 | done_path_create(&path, dentry); |
3554 | if (retry_estale(error, lookup_flags)) { | ||
3555 | lookup_flags |= LOOKUP_REVAL; | ||
3556 | goto retry; | ||
3557 | } | ||
3530 | out_putname: | 3558 | out_putname: |
3531 | putname(from); | 3559 | putname(from); |
3532 | return error; | 3560 | return error; |
@@ -3613,12 +3641,13 @@ SYSCALL_DEFINE5(linkat, int, olddfd, const char __user *, oldname, | |||
3613 | 3641 | ||
3614 | if (flags & AT_SYMLINK_FOLLOW) | 3642 | if (flags & AT_SYMLINK_FOLLOW) |
3615 | how |= LOOKUP_FOLLOW; | 3643 | how |= LOOKUP_FOLLOW; |
3616 | 3644 | retry: | |
3617 | error = user_path_at(olddfd, oldname, how, &old_path); | 3645 | error = user_path_at(olddfd, oldname, how, &old_path); |
3618 | if (error) | 3646 | if (error) |
3619 | return error; | 3647 | return error; |
3620 | 3648 | ||
3621 | new_dentry = user_path_create(newdfd, newname, &new_path, 0); | 3649 | new_dentry = user_path_create(newdfd, newname, &new_path, |
3650 | (how & LOOKUP_REVAL)); | ||
3622 | error = PTR_ERR(new_dentry); | 3651 | error = PTR_ERR(new_dentry); |
3623 | if (IS_ERR(new_dentry)) | 3652 | if (IS_ERR(new_dentry)) |
3624 | goto out; | 3653 | goto out; |
@@ -3635,6 +3664,10 @@ SYSCALL_DEFINE5(linkat, int, olddfd, const char __user *, oldname, | |||
3635 | error = vfs_link(old_path.dentry, new_path.dentry->d_inode, new_dentry); | 3664 | error = vfs_link(old_path.dentry, new_path.dentry->d_inode, new_dentry); |
3636 | out_dput: | 3665 | out_dput: |
3637 | done_path_create(&new_path, new_dentry); | 3666 | done_path_create(&new_path, new_dentry); |
3667 | if (retry_estale(error, how)) { | ||
3668 | how |= LOOKUP_REVAL; | ||
3669 | goto retry; | ||
3670 | } | ||
3638 | out: | 3671 | out: |
3639 | path_put(&old_path); | 3672 | path_put(&old_path); |
3640 | 3673 | ||
@@ -3807,15 +3840,17 @@ SYSCALL_DEFINE4(renameat, int, olddfd, const char __user *, oldname, | |||
3807 | struct nameidata oldnd, newnd; | 3840 | struct nameidata oldnd, newnd; |
3808 | struct filename *from; | 3841 | struct filename *from; |
3809 | struct filename *to; | 3842 | struct filename *to; |
3843 | unsigned int lookup_flags = 0; | ||
3844 | bool should_retry = false; | ||
3810 | int error; | 3845 | int error; |
3811 | 3846 | retry: | |
3812 | from = user_path_parent(olddfd, oldname, &oldnd); | 3847 | from = user_path_parent(olddfd, oldname, &oldnd, lookup_flags); |
3813 | if (IS_ERR(from)) { | 3848 | if (IS_ERR(from)) { |
3814 | error = PTR_ERR(from); | 3849 | error = PTR_ERR(from); |
3815 | goto exit; | 3850 | goto exit; |
3816 | } | 3851 | } |
3817 | 3852 | ||
3818 | to = user_path_parent(newdfd, newname, &newnd); | 3853 | to = user_path_parent(newdfd, newname, &newnd, lookup_flags); |
3819 | if (IS_ERR(to)) { | 3854 | if (IS_ERR(to)) { |
3820 | error = PTR_ERR(to); | 3855 | error = PTR_ERR(to); |
3821 | goto exit1; | 3856 | goto exit1; |
@@ -3887,11 +3922,18 @@ exit3: | |||
3887 | unlock_rename(new_dir, old_dir); | 3922 | unlock_rename(new_dir, old_dir); |
3888 | mnt_drop_write(oldnd.path.mnt); | 3923 | mnt_drop_write(oldnd.path.mnt); |
3889 | exit2: | 3924 | exit2: |
3925 | if (retry_estale(error, lookup_flags)) | ||
3926 | should_retry = true; | ||
3890 | path_put(&newnd.path); | 3927 | path_put(&newnd.path); |
3891 | putname(to); | 3928 | putname(to); |
3892 | exit1: | 3929 | exit1: |
3893 | path_put(&oldnd.path); | 3930 | path_put(&oldnd.path); |
3894 | putname(from); | 3931 | putname(from); |
3932 | if (should_retry) { | ||
3933 | should_retry = false; | ||
3934 | lookup_flags |= LOOKUP_REVAL; | ||
3935 | goto retry; | ||
3936 | } | ||
3895 | exit: | 3937 | exit: |
3896 | return error; | 3938 | return error; |
3897 | } | 3939 | } |