aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authornpiggin@suse.de <npiggin@suse.de>2009-04-26 06:25:55 -0400
committerAl Viro <viro@zeniv.linux.org.uk>2009-06-11 21:36:02 -0400
commit96029c4e09ccbd73a6d0ed2b29e80bf2586ad7ef (patch)
tree032d2ac7024250c18487a2c7122af68fe56567ff
parentd3ef3d7351ccfbef3e5d926efc5ee332136f40d4 (diff)
fs: introduce mnt_clone_write
This patch speeds up lmbench lat_mmap test by about another 2% after the first patch. Before: avg = 462.286 std = 5.46106 After: avg = 453.12 std = 9.58257 (50 runs of each, stddev gives a reasonable confidence) It does this by introducing mnt_clone_write, which avoids some heavyweight operations of mnt_want_write if called on a vfsmount which we know already has a write count; and mnt_want_write_file, which can call mnt_clone_write if the file is open for write. After these two patches, mnt_want_write and mnt_drop_write go from 7% on the profile down to 1.3% (including mnt_clone_write). [AV: mnt_want_write_file() should take file alone and derive mnt from it; not only all callers have that form, but that's the only mnt about which we know that it's already held for write if file is opened for write] Cc: Dave Hansen <haveblue@us.ibm.com> Signed-off-by: Nick Piggin <npiggin@suse.de> Signed-off-by: Al Viro <viro@zeniv.linux.org.uk>
-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);