diff options
author | Al Viro <viro@zeniv.linux.org.uk> | 2012-07-19 18:25:00 -0400 |
---|---|---|
committer | Al Viro <viro@zeniv.linux.org.uk> | 2012-07-29 13:24:15 -0400 |
commit | a8104a9fcdeb82e22d7acd55fca20746581067d3 (patch) | |
tree | 3036dae685f9b12a878dd02e439f0050114d7745 /fs/namei.c | |
parent | 8e4bfca1d1f0de62301dd223675717e7a5f63a27 (diff) |
pull mnt_want_write()/mnt_drop_write() into kern_path_create()/done_path_create() resp.
One side effect - attempt to create a cross-device link on a read-only fs fails
with EROFS instead of EXDEV now. Makes more sense, POSIX allows, etc.
Signed-off-by: Al Viro <viro@zeniv.linux.org.uk>
Diffstat (limited to 'fs/namei.c')
-rw-r--r-- | fs/namei.c | 57 |
1 files changed, 18 insertions, 39 deletions
diff --git a/fs/namei.c b/fs/namei.c index cf362dc9d1fd..a3fb78fd70d2 100644 --- a/fs/namei.c +++ b/fs/namei.c | |||
@@ -2865,10 +2865,11 @@ struct dentry *kern_path_create(int dfd, const char *pathname, struct path *path | |||
2865 | mutex_lock_nested(&nd.path.dentry->d_inode->i_mutex, I_MUTEX_PARENT); | 2865 | mutex_lock_nested(&nd.path.dentry->d_inode->i_mutex, I_MUTEX_PARENT); |
2866 | dentry = lookup_hash(&nd); | 2866 | dentry = lookup_hash(&nd); |
2867 | if (IS_ERR(dentry)) | 2867 | if (IS_ERR(dentry)) |
2868 | goto fail; | 2868 | goto unlock; |
2869 | 2869 | ||
2870 | error = -EEXIST; | ||
2870 | if (dentry->d_inode) | 2871 | if (dentry->d_inode) |
2871 | goto eexist; | 2872 | goto fail; |
2872 | /* | 2873 | /* |
2873 | * Special case - lookup gave negative, but... we had foo/bar/ | 2874 | * Special case - lookup gave negative, but... we had foo/bar/ |
2874 | * From the vfs_mknod() POV we just have a negative dentry - | 2875 | * From the vfs_mknod() POV we just have a negative dentry - |
@@ -2876,16 +2877,18 @@ struct dentry *kern_path_create(int dfd, const char *pathname, struct path *path | |||
2876 | * been asking for (non-existent) directory. -ENOENT for you. | 2877 | * been asking for (non-existent) directory. -ENOENT for you. |
2877 | */ | 2878 | */ |
2878 | if (unlikely(!is_dir && nd.last.name[nd.last.len])) { | 2879 | if (unlikely(!is_dir && nd.last.name[nd.last.len])) { |
2879 | dput(dentry); | 2880 | error = -ENOENT; |
2880 | dentry = ERR_PTR(-ENOENT); | ||
2881 | goto fail; | 2881 | goto fail; |
2882 | } | 2882 | } |
2883 | error = mnt_want_write(nd.path.mnt); | ||
2884 | if (error) | ||
2885 | goto fail; | ||
2883 | *path = nd.path; | 2886 | *path = nd.path; |
2884 | return dentry; | 2887 | return dentry; |
2885 | eexist: | ||
2886 | dput(dentry); | ||
2887 | dentry = ERR_PTR(-EEXIST); | ||
2888 | fail: | 2888 | fail: |
2889 | dput(dentry); | ||
2890 | dentry = ERR_PTR(error); | ||
2891 | unlock: | ||
2889 | mutex_unlock(&nd.path.dentry->d_inode->i_mutex); | 2892 | mutex_unlock(&nd.path.dentry->d_inode->i_mutex); |
2890 | out: | 2893 | out: |
2891 | path_put(&nd.path); | 2894 | path_put(&nd.path); |
@@ -2897,6 +2900,7 @@ void done_path_create(struct path *path, struct dentry *dentry) | |||
2897 | { | 2900 | { |
2898 | dput(dentry); | 2901 | dput(dentry); |
2899 | mutex_unlock(&path->dentry->d_inode->i_mutex); | 2902 | mutex_unlock(&path->dentry->d_inode->i_mutex); |
2903 | mnt_drop_write(path->mnt); | ||
2900 | path_put(path); | 2904 | path_put(path); |
2901 | } | 2905 | } |
2902 | EXPORT_SYMBOL(done_path_create); | 2906 | EXPORT_SYMBOL(done_path_create); |
@@ -2974,12 +2978,9 @@ SYSCALL_DEFINE4(mknodat, int, dfd, const char __user *, filename, umode_t, mode, | |||
2974 | 2978 | ||
2975 | if (!IS_POSIXACL(path.dentry->d_inode)) | 2979 | if (!IS_POSIXACL(path.dentry->d_inode)) |
2976 | mode &= ~current_umask(); | 2980 | mode &= ~current_umask(); |
2977 | error = mnt_want_write(path.mnt); | ||
2978 | if (error) | ||
2979 | goto out_dput; | ||
2980 | error = security_path_mknod(&path, dentry, mode, dev); | 2981 | error = security_path_mknod(&path, dentry, mode, dev); |
2981 | if (error) | 2982 | if (error) |
2982 | goto out_drop_write; | 2983 | goto out; |
2983 | switch (mode & S_IFMT) { | 2984 | switch (mode & S_IFMT) { |
2984 | case 0: case S_IFREG: | 2985 | case 0: case S_IFREG: |
2985 | error = vfs_create(path.dentry->d_inode,dentry,mode,true); | 2986 | error = vfs_create(path.dentry->d_inode,dentry,mode,true); |
@@ -2992,11 +2993,8 @@ SYSCALL_DEFINE4(mknodat, int, dfd, const char __user *, filename, umode_t, mode, | |||
2992 | error = vfs_mknod(path.dentry->d_inode,dentry,mode,0); | 2993 | error = vfs_mknod(path.dentry->d_inode,dentry,mode,0); |
2993 | break; | 2994 | break; |
2994 | } | 2995 | } |
2995 | out_drop_write: | 2996 | out: |
2996 | mnt_drop_write(path.mnt); | ||
2997 | out_dput: | ||
2998 | done_path_create(&path, dentry); | 2997 | done_path_create(&path, dentry); |
2999 | |||
3000 | return error; | 2998 | return error; |
3001 | } | 2999 | } |
3002 | 3000 | ||
@@ -3042,16 +3040,9 @@ SYSCALL_DEFINE3(mkdirat, int, dfd, const char __user *, pathname, umode_t, mode) | |||
3042 | 3040 | ||
3043 | if (!IS_POSIXACL(path.dentry->d_inode)) | 3041 | if (!IS_POSIXACL(path.dentry->d_inode)) |
3044 | mode &= ~current_umask(); | 3042 | mode &= ~current_umask(); |
3045 | error = mnt_want_write(path.mnt); | ||
3046 | if (error) | ||
3047 | goto out_dput; | ||
3048 | error = security_path_mkdir(&path, dentry, mode); | 3043 | error = security_path_mkdir(&path, dentry, mode); |
3049 | if (error) | 3044 | if (!error) |
3050 | goto out_drop_write; | 3045 | error = vfs_mkdir(path.dentry->d_inode, dentry, mode); |
3051 | error = vfs_mkdir(path.dentry->d_inode, dentry, mode); | ||
3052 | out_drop_write: | ||
3053 | mnt_drop_write(path.mnt); | ||
3054 | out_dput: | ||
3055 | done_path_create(&path, dentry); | 3046 | done_path_create(&path, dentry); |
3056 | return error; | 3047 | return error; |
3057 | } | 3048 | } |
@@ -3326,16 +3317,9 @@ SYSCALL_DEFINE3(symlinkat, const char __user *, oldname, | |||
3326 | if (IS_ERR(dentry)) | 3317 | if (IS_ERR(dentry)) |
3327 | goto out_putname; | 3318 | goto out_putname; |
3328 | 3319 | ||
3329 | error = mnt_want_write(path.mnt); | ||
3330 | if (error) | ||
3331 | goto out_dput; | ||
3332 | error = security_path_symlink(&path, dentry, from); | 3320 | error = security_path_symlink(&path, dentry, from); |
3333 | if (error) | 3321 | if (!error) |
3334 | goto out_drop_write; | 3322 | error = vfs_symlink(path.dentry->d_inode, dentry, from); |
3335 | error = vfs_symlink(path.dentry->d_inode, dentry, from); | ||
3336 | out_drop_write: | ||
3337 | mnt_drop_write(path.mnt); | ||
3338 | out_dput: | ||
3339 | done_path_create(&path, dentry); | 3323 | done_path_create(&path, dentry); |
3340 | out_putname: | 3324 | out_putname: |
3341 | putname(from); | 3325 | putname(from); |
@@ -3436,15 +3420,10 @@ SYSCALL_DEFINE5(linkat, int, olddfd, const char __user *, oldname, | |||
3436 | error = -EXDEV; | 3420 | error = -EXDEV; |
3437 | if (old_path.mnt != new_path.mnt) | 3421 | if (old_path.mnt != new_path.mnt) |
3438 | goto out_dput; | 3422 | goto out_dput; |
3439 | error = mnt_want_write(new_path.mnt); | ||
3440 | if (error) | ||
3441 | goto out_dput; | ||
3442 | error = security_path_link(old_path.dentry, &new_path, new_dentry); | 3423 | error = security_path_link(old_path.dentry, &new_path, new_dentry); |
3443 | if (error) | 3424 | if (error) |
3444 | goto out_drop_write; | 3425 | goto out_dput; |
3445 | error = vfs_link(old_path.dentry, new_path.dentry->d_inode, new_dentry); | 3426 | error = vfs_link(old_path.dentry, new_path.dentry->d_inode, new_dentry); |
3446 | out_drop_write: | ||
3447 | mnt_drop_write(new_path.mnt); | ||
3448 | out_dput: | 3427 | out_dput: |
3449 | done_path_create(&new_path, new_dentry); | 3428 | done_path_create(&new_path, new_dentry); |
3450 | out: | 3429 | out: |