1 From: Nick Piggin <npiggin@suse.de>
2 Subject: fs: introduce mnt_clone_write
4 Patch-upstream: no (could be submitted)
6 This patch speeds up lmbench lat_mmap test by about another 2% after the
17 (50 runs of each, stddev gives a reasonable confidence)
19 It does this by introducing mnt_clone_write, which avoids some heavyweight
20 operations of mnt_want_write if called on a vfsmount which we know already
21 has a write count; and mnt_want_write_file, which can call mnt_clone_write
22 if the file is open for write.
24 After these two patches, mnt_want_write and mnt_drop_write go from 7% on
25 the profile down to 1.3% (including mnt_clone_write).
28 fs/file_table.c | 3 +--
30 fs/namespace.c | 38 ++++++++++++++++++++++++++++++++++++++
33 include/linux/mount.h | 2 ++
34 6 files changed, 46 insertions(+), 7 deletions(-)
38 @@ -210,8 +210,7 @@ int init_file(struct file *file, struct
40 if ((mode & FMODE_WRITE) && !special_file(dentry->d_inode->i_mode)) {
41 file_take_write(file);
42 - error = mnt_want_write(mnt);
44 + mnt_clone_write(mnt);
50 @@ -1256,7 +1256,7 @@ void file_update_time(struct file *file)
51 if (IS_NOCMTIME(inode))
54 - err = mnt_want_write(file->f_path.mnt);
55 + err = mnt_want_write_file(file->f_path.mnt, file);
61 @@ -264,6 +264,44 @@ out:
62 EXPORT_SYMBOL_GPL(mnt_want_write);
65 + * mnt_clone_write - get write access to a mount
66 + * @mnt: the mount on which to take a write
68 + * This is effectively like mnt_want_write, except
69 + * it must only be used to take an extra write reference
70 + * on a mountpoint that we already know has a write reference
71 + * on it. This allows some optimisation.
73 + * After finished, mnt_drop_write must be called as usual to
74 + * drop the reference.
76 +void mnt_clone_write(struct vfsmount *mnt)
79 + inc_mnt_writers(mnt);
82 +EXPORT_SYMBOL_GPL(mnt_clone_write);
85 + * mnt_want_write_file - get write access to a file's mount
86 + * @file: the file who's mount on which to take a write
88 + * This is like mnt_want_write, but it takes a file and can
89 + * do some optimisations if the file is open for write already
91 +int mnt_want_write_file(struct vfsmount *mnt, struct file *file)
93 + if (!(file->f_mode & FMODE_WRITE))
94 + return mnt_want_write(mnt);
96 + mnt_clone_write(mnt);
100 +EXPORT_SYMBOL_GPL(mnt_want_write_file);
103 * mnt_drop_write - give up write access to a mount
104 * @mnt: the mount on which to give up write access
108 @@ -616,7 +616,7 @@ SYSCALL_DEFINE2(fchmod, unsigned int, fd
110 audit_inode(NULL, dentry);
112 - err = mnt_want_write(file->f_path.mnt);
113 + err = mnt_want_write_file(file->f_path.mnt, file);
116 mutex_lock(&inode->i_mutex);
117 @@ -765,7 +765,7 @@ SYSCALL_DEFINE3(fchown, unsigned int, fd
121 - error = mnt_want_write(file->f_path.mnt);
122 + error = mnt_want_write_file(file->f_path.mnt, file);
125 dentry = file->f_path.dentry;
128 @@ -301,7 +301,7 @@ SYSCALL_DEFINE5(fsetxattr, int, fd, cons
130 dentry = f->f_path.dentry;
131 audit_inode(NULL, dentry);
132 - error = mnt_want_write(f->f_path.mnt);
133 + error = mnt_want_write_file(f->f_path.mnt, f);
135 error = setxattr(dentry, name, value, size, flags);
136 mnt_drop_write(f->f_path.mnt);
137 @@ -528,7 +528,7 @@ SYSCALL_DEFINE2(fremovexattr, int, fd, c
139 dentry = f->f_path.dentry;
140 audit_inode(NULL, dentry);
141 - error = mnt_want_write(f->f_path.mnt);
142 + error = mnt_want_write_file(f->f_path.mnt, f);
144 error = removexattr(dentry, name);
145 mnt_drop_write(f->f_path.mnt);
146 --- a/include/linux/mount.h
147 +++ b/include/linux/mount.h
148 @@ -99,6 +99,8 @@ static inline struct vfsmount *mntget(st
151 extern int mnt_want_write(struct vfsmount *mnt);
152 +extern int mnt_want_write_file(struct vfsmount *mnt, struct file *file);
153 +extern void mnt_clone_write(struct vfsmount *mnt);
154 extern void mnt_drop_write(struct vfsmount *mnt);
155 extern void mntput_no_expire(struct vfsmount *mnt);
156 extern void mnt_pin(struct vfsmount *mnt);