aboutsummaryrefslogtreecommitdiffstats
path: root/fs
diff options
context:
space:
mode:
authorJan Kara <jack@suse.cz>2012-06-12 10:20:30 -0400
committerAl Viro <viro@zeniv.linux.org.uk>2012-07-30 17:02:49 -0400
commitc30dabfe5d10c5fd70d882e5afb8f59f2942b194 (patch)
tree2a643a825fb91a1ae48c5673a9f5fcba891b6122 /fs
parent4fcf1c6205fcfc7a226a144ae4d83b7f5415cab8 (diff)
fs: Push mnt_want_write() outside of i_mutex
Currently, mnt_want_write() is sometimes called with i_mutex held and sometimes without it. This isn't really a problem because mnt_want_write() is a non-blocking operation (essentially has a trylock semantics) but when the function starts to handle also frozen filesystems, it will get a full lock semantics and thus proper lock ordering has to be established. So move all mnt_want_write() calls outside of i_mutex. One non-trivial case needing conversion is kern_path_create() / user_path_create() which didn't include mnt_want_write() but now needs to because it acquires i_mutex. Because there are virtual file systems which don't bother with freeze / remount-ro protection we actually provide both versions of the function - one which calls mnt_want_write() and one which does not. [AV: scratch the previous, mnt_want_write() has been moved to kern_path_create() by now] Signed-off-by: Jan Kara <jack@suse.cz> Signed-off-by: Al Viro <viro@zeniv.linux.org.uk>
Diffstat (limited to 'fs')
-rw-r--r--fs/namei.c46
1 files changed, 25 insertions, 21 deletions
diff --git a/fs/namei.c b/fs/namei.c
index 35291ac6f42b..1b464390dde8 100644
--- a/fs/namei.c
+++ b/fs/namei.c
@@ -2975,6 +2975,7 @@ struct dentry *kern_path_create(int dfd, const char *pathname, struct path *path
2975{ 2975{
2976 struct dentry *dentry = ERR_PTR(-EEXIST); 2976 struct dentry *dentry = ERR_PTR(-EEXIST);
2977 struct nameidata nd; 2977 struct nameidata nd;
2978 int err2;
2978 int error = do_path_lookup(dfd, pathname, LOOKUP_PARENT, &nd); 2979 int error = do_path_lookup(dfd, pathname, LOOKUP_PARENT, &nd);
2979 if (error) 2980 if (error)
2980 return ERR_PTR(error); 2981 return ERR_PTR(error);
@@ -2988,6 +2989,8 @@ struct dentry *kern_path_create(int dfd, const char *pathname, struct path *path
2988 nd.flags &= ~LOOKUP_PARENT; 2989 nd.flags &= ~LOOKUP_PARENT;
2989 nd.flags |= LOOKUP_CREATE | LOOKUP_EXCL; 2990 nd.flags |= LOOKUP_CREATE | LOOKUP_EXCL;
2990 2991
2992 /* don't fail immediately if it's r/o, at least try to report other errors */
2993 err2 = mnt_want_write(nd.path.mnt);
2991 /* 2994 /*
2992 * Do the final lookup. 2995 * Do the final lookup.
2993 */ 2996 */
@@ -3009,9 +3012,10 @@ struct dentry *kern_path_create(int dfd, const char *pathname, struct path *path
3009 error = -ENOENT; 3012 error = -ENOENT;
3010 goto fail; 3013 goto fail;
3011 } 3014 }
3012 error = mnt_want_write(nd.path.mnt); 3015 if (unlikely(err2)) {
3013 if (error) 3016 error = err2;
3014 goto fail; 3017 goto fail;
3018 }
3015 *path = nd.path; 3019 *path = nd.path;
3016 return dentry; 3020 return dentry;
3017fail: 3021fail:
@@ -3019,6 +3023,8 @@ fail:
3019 dentry = ERR_PTR(error); 3023 dentry = ERR_PTR(error);
3020unlock: 3024unlock:
3021 mutex_unlock(&nd.path.dentry->d_inode->i_mutex); 3025 mutex_unlock(&nd.path.dentry->d_inode->i_mutex);
3026 if (!err2)
3027 mnt_drop_write(nd.path.mnt);
3022out: 3028out:
3023 path_put(&nd.path); 3029 path_put(&nd.path);
3024 return dentry; 3030 return dentry;
@@ -3266,6 +3272,9 @@ static long do_rmdir(int dfd, const char __user *pathname)
3266 } 3272 }
3267 3273
3268 nd.flags &= ~LOOKUP_PARENT; 3274 nd.flags &= ~LOOKUP_PARENT;
3275 error = mnt_want_write(nd.path.mnt);
3276 if (error)
3277 goto exit1;
3269 3278
3270 mutex_lock_nested(&nd.path.dentry->d_inode->i_mutex, I_MUTEX_PARENT); 3279 mutex_lock_nested(&nd.path.dentry->d_inode->i_mutex, I_MUTEX_PARENT);
3271 dentry = lookup_hash(&nd); 3280 dentry = lookup_hash(&nd);
@@ -3276,19 +3285,15 @@ static long do_rmdir(int dfd, const char __user *pathname)
3276 error = -ENOENT; 3285 error = -ENOENT;
3277 goto exit3; 3286 goto exit3;
3278 } 3287 }
3279 error = mnt_want_write(nd.path.mnt);
3280 if (error)
3281 goto exit3;
3282 error = security_path_rmdir(&nd.path, dentry); 3288 error = security_path_rmdir(&nd.path, dentry);
3283 if (error) 3289 if (error)
3284 goto exit4; 3290 goto exit3;
3285 error = vfs_rmdir(nd.path.dentry->d_inode, dentry); 3291 error = vfs_rmdir(nd.path.dentry->d_inode, dentry);
3286exit4:
3287 mnt_drop_write(nd.path.mnt);
3288exit3: 3292exit3:
3289 dput(dentry); 3293 dput(dentry);
3290exit2: 3294exit2:
3291 mutex_unlock(&nd.path.dentry->d_inode->i_mutex); 3295 mutex_unlock(&nd.path.dentry->d_inode->i_mutex);
3296 mnt_drop_write(nd.path.mnt);
3292exit1: 3297exit1:
3293 path_put(&nd.path); 3298 path_put(&nd.path);
3294 putname(name); 3299 putname(name);
@@ -3355,6 +3360,9 @@ static long do_unlinkat(int dfd, const char __user *pathname)
3355 goto exit1; 3360 goto exit1;
3356 3361
3357 nd.flags &= ~LOOKUP_PARENT; 3362 nd.flags &= ~LOOKUP_PARENT;
3363 error = mnt_want_write(nd.path.mnt);
3364 if (error)
3365 goto exit1;
3358 3366
3359 mutex_lock_nested(&nd.path.dentry->d_inode->i_mutex, I_MUTEX_PARENT); 3367 mutex_lock_nested(&nd.path.dentry->d_inode->i_mutex, I_MUTEX_PARENT);
3360 dentry = lookup_hash(&nd); 3368 dentry = lookup_hash(&nd);
@@ -3367,21 +3375,17 @@ static long do_unlinkat(int dfd, const char __user *pathname)
3367 if (!inode) 3375 if (!inode)
3368 goto slashes; 3376 goto slashes;
3369 ihold(inode); 3377 ihold(inode);
3370 error = mnt_want_write(nd.path.mnt);
3371 if (error)
3372 goto exit2;
3373 error = security_path_unlink(&nd.path, dentry); 3378 error = security_path_unlink(&nd.path, dentry);
3374 if (error) 3379 if (error)
3375 goto exit3; 3380 goto exit2;
3376 error = vfs_unlink(nd.path.dentry->d_inode, dentry); 3381 error = vfs_unlink(nd.path.dentry->d_inode, dentry);
3377exit3: 3382exit2:
3378 mnt_drop_write(nd.path.mnt);
3379 exit2:
3380 dput(dentry); 3383 dput(dentry);
3381 } 3384 }
3382 mutex_unlock(&nd.path.dentry->d_inode->i_mutex); 3385 mutex_unlock(&nd.path.dentry->d_inode->i_mutex);
3383 if (inode) 3386 if (inode)
3384 iput(inode); /* truncate the inode here */ 3387 iput(inode); /* truncate the inode here */
3388 mnt_drop_write(nd.path.mnt);
3385exit1: 3389exit1:
3386 path_put(&nd.path); 3390 path_put(&nd.path);
3387 putname(name); 3391 putname(name);
@@ -3753,6 +3757,10 @@ SYSCALL_DEFINE4(renameat, int, olddfd, const char __user *, oldname,
3753 if (newnd.last_type != LAST_NORM) 3757 if (newnd.last_type != LAST_NORM)
3754 goto exit2; 3758 goto exit2;
3755 3759
3760 error = mnt_want_write(oldnd.path.mnt);
3761 if (error)
3762 goto exit2;
3763
3756 oldnd.flags &= ~LOOKUP_PARENT; 3764 oldnd.flags &= ~LOOKUP_PARENT;
3757 newnd.flags &= ~LOOKUP_PARENT; 3765 newnd.flags &= ~LOOKUP_PARENT;
3758 newnd.flags |= LOOKUP_RENAME_TARGET; 3766 newnd.flags |= LOOKUP_RENAME_TARGET;
@@ -3788,23 +3796,19 @@ SYSCALL_DEFINE4(renameat, int, olddfd, const char __user *, oldname,
3788 if (new_dentry == trap) 3796 if (new_dentry == trap)
3789 goto exit5; 3797 goto exit5;
3790 3798
3791 error = mnt_want_write(oldnd.path.mnt);
3792 if (error)
3793 goto exit5;
3794 error = security_path_rename(&oldnd.path, old_dentry, 3799 error = security_path_rename(&oldnd.path, old_dentry,
3795 &newnd.path, new_dentry); 3800 &newnd.path, new_dentry);
3796 if (error) 3801 if (error)
3797 goto exit6; 3802 goto exit5;
3798 error = vfs_rename(old_dir->d_inode, old_dentry, 3803 error = vfs_rename(old_dir->d_inode, old_dentry,
3799 new_dir->d_inode, new_dentry); 3804 new_dir->d_inode, new_dentry);
3800exit6:
3801 mnt_drop_write(oldnd.path.mnt);
3802exit5: 3805exit5:
3803 dput(new_dentry); 3806 dput(new_dentry);
3804exit4: 3807exit4:
3805 dput(old_dentry); 3808 dput(old_dentry);
3806exit3: 3809exit3:
3807 unlock_rename(new_dir, old_dir); 3810 unlock_rename(new_dir, old_dir);
3811 mnt_drop_write(oldnd.path.mnt);
3808exit2: 3812exit2:
3809 path_put(&newnd.path); 3813 path_put(&newnd.path);
3810 putname(to); 3814 putname(to);