aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--fs/file_table.c2
-rw-r--r--fs/inode.c2
-rw-r--r--fs/namespace.c40
-rw-r--r--fs/open.c4
-rw-r--r--fs/xattr.c4
-rw-r--r--include/linux/mount.h4
6 files changed, 50 insertions, 6 deletions
diff --git a/fs/file_table.c b/fs/file_table.c
index 54018fe48840..3d66dbcebef6 100644
--- a/fs/file_table.c
+++ b/fs/file_table.c
@@ -214,7 +214,7 @@ int init_file(struct file *file, struct vfsmount *mnt, struct dentry *dentry,
214 */ 214 */
215 if ((mode & FMODE_WRITE) && !special_file(dentry->d_inode->i_mode)) { 215 if ((mode & FMODE_WRITE) && !special_file(dentry->d_inode->i_mode)) {
216 file_take_write(file); 216 file_take_write(file);
217 error = mnt_want_write(mnt); 217 error = mnt_clone_write(mnt);
218 WARN_ON(error); 218 WARN_ON(error);
219 } 219 }
220 return error; 220 return error;
diff --git a/fs/inode.c b/fs/inode.c
index ca337014ae29..a88baebf77cf 100644
--- a/fs/inode.c
+++ b/fs/inode.c
@@ -1422,7 +1422,7 @@ void file_update_time(struct file *file)
1422 if (IS_NOCMTIME(inode)) 1422 if (IS_NOCMTIME(inode))
1423 return; 1423 return;
1424 1424
1425 err = mnt_want_write(file->f_path.mnt); 1425 err = mnt_want_write_file(file);
1426 if (err) 1426 if (err)
1427 return; 1427 return;
1428 1428
diff --git a/fs/namespace.c b/fs/namespace.c
index 22ae06ad751d..120b8a6b99ed 100644
--- a/fs/namespace.c
+++ b/fs/namespace.c
@@ -265,6 +265,46 @@ out:
265EXPORT_SYMBOL_GPL(mnt_want_write); 265EXPORT_SYMBOL_GPL(mnt_want_write);
266 266
267/** 267/**
268 * mnt_clone_write - get write access to a mount
269 * @mnt: the mount on which to take a write
270 *
271 * This is effectively like mnt_want_write, except
272 * it must only be used to take an extra write reference
273 * on a mountpoint that we already know has a write reference
274 * on it. This allows some optimisation.
275 *
276 * After finished, mnt_drop_write must be called as usual to
277 * drop the reference.
278 */
279int mnt_clone_write(struct vfsmount *mnt)
280{
281 /* superblock may be r/o */
282 if (__mnt_is_readonly(mnt))
283 return -EROFS;
284 preempt_disable();
285 inc_mnt_writers(mnt);
286 preempt_enable();
287 return 0;
288}
289EXPORT_SYMBOL_GPL(mnt_clone_write);
290
291/**
292 * mnt_want_write_file - get write access to a file's mount
293 * @file: the file who's mount on which to take a write
294 *
295 * This is like mnt_want_write, but it takes a file and can
296 * do some optimisations if the file is open for write already
297 */
298int mnt_want_write_file(struct file *file)
299{
300 if (!(file->f_mode & FMODE_WRITE))
301 return mnt_want_write(file->f_path.mnt);
302 else
303 return mnt_clone_write(file->f_path.mnt);
304}
305EXPORT_SYMBOL_GPL(mnt_want_write_file);
306
307/**
268 * mnt_drop_write - give up write access to a mount 308 * mnt_drop_write - give up write access to a mount
269 * @mnt: the mount on which to give up write access 309 * @mnt: the mount on which to give up write access
270 * 310 *
diff --git a/fs/open.c b/fs/open.c
index bdfbf03615a4..7200e23d9258 100644
--- a/fs/open.c
+++ b/fs/open.c
@@ -612,7 +612,7 @@ SYSCALL_DEFINE2(fchmod, unsigned int, fd, mode_t, mode)
612 612
613 audit_inode(NULL, dentry); 613 audit_inode(NULL, dentry);
614 614
615 err = mnt_want_write(file->f_path.mnt); 615 err = mnt_want_write_file(file);
616 if (err) 616 if (err)
617 goto out_putf; 617 goto out_putf;
618 mutex_lock(&inode->i_mutex); 618 mutex_lock(&inode->i_mutex);
@@ -761,7 +761,7 @@ SYSCALL_DEFINE3(fchown, unsigned int, fd, uid_t, user, gid_t, group)
761 if (!file) 761 if (!file)
762 goto out; 762 goto out;
763 763
764 error = mnt_want_write(file->f_path.mnt); 764 error = mnt_want_write_file(file);
765 if (error) 765 if (error)
766 goto out_fput; 766 goto out_fput;
767 dentry = file->f_path.dentry; 767 dentry = file->f_path.dentry;
diff --git a/fs/xattr.c b/fs/xattr.c
index d51b8f9db921..1c3d0af59ddf 100644
--- a/fs/xattr.c
+++ b/fs/xattr.c
@@ -297,7 +297,7 @@ SYSCALL_DEFINE5(fsetxattr, int, fd, const char __user *, name,
297 return error; 297 return error;
298 dentry = f->f_path.dentry; 298 dentry = f->f_path.dentry;
299 audit_inode(NULL, dentry); 299 audit_inode(NULL, dentry);
300 error = mnt_want_write(f->f_path.mnt); 300 error = mnt_want_write_file(f);
301 if (!error) { 301 if (!error) {
302 error = setxattr(dentry, name, value, size, flags); 302 error = setxattr(dentry, name, value, size, flags);
303 mnt_drop_write(f->f_path.mnt); 303 mnt_drop_write(f->f_path.mnt);
@@ -524,7 +524,7 @@ SYSCALL_DEFINE2(fremovexattr, int, fd, const char __user *, name)
524 return error; 524 return error;
525 dentry = f->f_path.dentry; 525 dentry = f->f_path.dentry;
526 audit_inode(NULL, dentry); 526 audit_inode(NULL, dentry);
527 error = mnt_want_write(f->f_path.mnt); 527 error = mnt_want_write_file(f);
528 if (!error) { 528 if (!error) {
529 error = removexattr(dentry, name); 529 error = removexattr(dentry, name);
530 mnt_drop_write(f->f_path.mnt); 530 mnt_drop_write(f->f_path.mnt);
diff --git a/include/linux/mount.h b/include/linux/mount.h
index ac49c1f8e5c0..5d5275364867 100644
--- a/include/linux/mount.h
+++ b/include/linux/mount.h
@@ -88,7 +88,11 @@ static inline struct vfsmount *mntget(struct vfsmount *mnt)
88 return mnt; 88 return mnt;
89} 89}
90 90
91struct file; /* forward dec */
92
91extern int mnt_want_write(struct vfsmount *mnt); 93extern int mnt_want_write(struct vfsmount *mnt);
94extern int mnt_want_write_file(struct file *file);
95extern int mnt_clone_write(struct vfsmount *mnt);
92extern void mnt_drop_write(struct vfsmount *mnt); 96extern void mnt_drop_write(struct vfsmount *mnt);
93extern void mntput_no_expire(struct vfsmount *mnt); 97extern void mntput_no_expire(struct vfsmount *mnt);
94extern void mnt_pin(struct vfsmount *mnt); 98extern void mnt_pin(struct vfsmount *mnt);