]>
Commit | Line | Data |
---|---|---|
2cb7cef9 BS |
1 | From: Nick Piggin <npiggin@suse.de> |
2 | Subject: fs: introduce mnt_clone_write | |
3 | References: bnc#436953 | |
4 | Patch-upstream: no (could be submitted) | |
5 | ||
6 | This patch speeds up lmbench lat_mmap test by about another 2% after the | |
7 | first patch. | |
8 | ||
9 | Before: | |
10 | avg = 462.286 | |
11 | std = 5.46106 | |
12 | ||
13 | After: | |
14 | avg = 453.12 | |
15 | std = 9.58257 | |
16 | ||
17 | (50 runs of each, stddev gives a reasonable confidence) | |
18 | ||
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. | |
23 | ||
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). | |
26 | ||
27 | --- | |
28 | fs/file_table.c | 2 - | |
29 | fs/inode.c | 2 - | |
30 | fs/namespace.c | 63 ++++++++++++++++++++++++++++++++++++++++++++++++++ | |
31 | fs/open.c | 4 +-- | |
32 | fs/xattr.c | 4 +-- | |
33 | include/linux/mount.h | 5 +++ | |
34 | 6 files changed, 74 insertions(+), 6 deletions(-) | |
35 | ||
36 | Index: linux-2.6.27/fs/file_table.c | |
37 | =================================================================== | |
38 | --- linux-2.6.27.orig/fs/file_table.c | |
39 | +++ linux-2.6.27/fs/file_table.c | |
40 | @@ -210,7 +210,7 @@ int init_file(struct file *file, struct | |
41 | */ | |
42 | if ((mode & FMODE_WRITE) && !special_file(dentry->d_inode->i_mode)) { | |
43 | file_take_write(file); | |
44 | - error = mnt_want_write(mnt); | |
45 | + error = mnt_clone_write_2(mnt); | |
46 | WARN_ON(error); | |
47 | } | |
48 | return error; | |
49 | Index: linux-2.6.27/fs/inode.c | |
50 | =================================================================== | |
51 | --- linux-2.6.27.orig/fs/inode.c | |
52 | +++ linux-2.6.27/fs/inode.c | |
53 | @@ -1256,7 +1256,7 @@ void file_update_time(struct file *file) | |
54 | if (IS_NOCMTIME(inode)) | |
55 | return; | |
56 | ||
57 | - err = mnt_want_write(file->f_path.mnt); | |
58 | + err = mnt_want_write_file(file->f_path.mnt, file); | |
59 | if (err) | |
60 | return; | |
61 | ||
62 | Index: linux-2.6.27/fs/namespace.c | |
63 | =================================================================== | |
64 | --- linux-2.6.27.orig/fs/namespace.c | |
65 | +++ linux-2.6.27/fs/namespace.c | |
66 | @@ -264,6 +264,69 @@ out: | |
67 | EXPORT_SYMBOL_GPL(mnt_want_write); | |
68 | ||
69 | /** | |
70 | + * mnt_clone_write - get write access to a mount | |
71 | + * @mnt: the mount on which to take a write | |
72 | + * | |
73 | + * This is effectively like mnt_want_write, except | |
74 | + * it must only be used to take an extra write reference | |
75 | + * on a mountpoint that we already know has a write reference | |
76 | + * on it. This allows some optimisation. | |
77 | + * | |
78 | + * The caller should really check __mnt_is_readonly before callint | |
79 | + * mnt_clone_write. See mnt_clone_write_2. | |
80 | + * | |
81 | + * After finished, mnt_drop_write must be called as usual to | |
82 | + * drop the reference. | |
83 | + */ | |
84 | +void mnt_clone_write(struct vfsmount *mnt) | |
85 | +{ | |
86 | + preempt_disable(); | |
87 | + inc_mnt_writers(mnt); | |
88 | + preempt_enable(); | |
89 | +} | |
90 | +EXPORT_SYMBOL_GPL(mnt_clone_write); | |
91 | + | |
92 | +/** | |
93 | + * mnt_clone_write_2 - get write access to a mount | |
94 | + * @mnt: the mount on which to take a write | |
95 | + * | |
96 | + * Same as mnt_clone_write, but it performs the __mnt_is_readonly | |
97 | + * check itself, and returns -error on failure. This is the preferred | |
98 | + * function. This is here to preserve kABI compatibility. | |
99 | + * | |
100 | + * After finished, mnt_drop_write must be called as usual to | |
101 | + * drop the reference. | |
102 | + */ | |
103 | +int mnt_clone_write_2(struct vfsmount *mnt) | |
104 | +{ | |
105 | + /* superblock may be r/o */ | |
106 | + if (__mnt_is_readonly(mnt)) | |
107 | + return -EROFS; | |
108 | + preempt_disable(); | |
109 | + inc_mnt_writers(mnt); | |
110 | + preempt_enable(); | |
111 | + return 0; | |
112 | +} | |
113 | +EXPORT_SYMBOL_GPL(mnt_clone_write_2); | |
114 | + | |
115 | +/** | |
116 | + * mnt_want_write_file - get write access to a file's mount | |
117 | + * @file: the file who's mount on which to take a write | |
118 | + * | |
119 | + * This is like mnt_want_write, but it takes a file and can | |
120 | + * do some optimisations if the file is open for write already | |
121 | + */ | |
122 | +int mnt_want_write_file(struct vfsmount *mnt, struct file *file) | |
123 | +{ | |
124 | + struct inode *inode = file->f_dentry->d_inode; | |
125 | + if (!(file->f_mode & FMODE_WRITE) || special_file(inode->i_mode)) | |
126 | + return mnt_want_write(mnt); | |
127 | + else | |
128 | + return mnt_clone_write_2(mnt); | |
129 | +} | |
130 | +EXPORT_SYMBOL_GPL(mnt_want_write_file); | |
131 | + | |
132 | +/** | |
133 | * mnt_drop_write - give up write access to a mount | |
134 | * @mnt: the mount on which to give up write access | |
135 | * | |
136 | Index: linux-2.6.27/fs/open.c | |
137 | =================================================================== | |
138 | --- linux-2.6.27.orig/fs/open.c | |
139 | +++ linux-2.6.27/fs/open.c | |
140 | @@ -616,7 +616,7 @@ SYSCALL_DEFINE2(fchmod, unsigned int, fd | |
141 | ||
142 | audit_inode(NULL, dentry); | |
143 | ||
144 | - err = mnt_want_write(file->f_path.mnt); | |
145 | + err = mnt_want_write_file(file->f_path.mnt, file); | |
146 | if (err) | |
147 | goto out_putf; | |
148 | mutex_lock(&inode->i_mutex); | |
149 | @@ -765,7 +765,7 @@ SYSCALL_DEFINE3(fchown, unsigned int, fd | |
150 | if (!file) | |
151 | goto out; | |
152 | ||
153 | - error = mnt_want_write(file->f_path.mnt); | |
154 | + error = mnt_want_write_file(file->f_path.mnt, file); | |
155 | if (error) | |
156 | goto out_fput; | |
157 | dentry = file->f_path.dentry; | |
158 | Index: linux-2.6.27/fs/xattr.c | |
159 | =================================================================== | |
160 | --- linux-2.6.27.orig/fs/xattr.c | |
161 | +++ linux-2.6.27/fs/xattr.c | |
162 | @@ -301,7 +301,7 @@ SYSCALL_DEFINE5(fsetxattr, int, fd, cons | |
163 | return error; | |
164 | dentry = f->f_path.dentry; | |
165 | audit_inode(NULL, dentry); | |
166 | - error = mnt_want_write(f->f_path.mnt); | |
167 | + error = mnt_want_write_file(f->f_path.mnt, f); | |
168 | if (!error) { | |
169 | error = setxattr(dentry, name, value, size, flags); | |
170 | mnt_drop_write(f->f_path.mnt); | |
171 | @@ -528,7 +528,7 @@ SYSCALL_DEFINE2(fremovexattr, int, fd, c | |
172 | return error; | |
173 | dentry = f->f_path.dentry; | |
174 | audit_inode(NULL, dentry); | |
175 | - error = mnt_want_write(f->f_path.mnt); | |
176 | + error = mnt_want_write_file(f->f_path.mnt, f); | |
177 | if (!error) { | |
178 | error = removexattr(dentry, name); | |
179 | mnt_drop_write(f->f_path.mnt); | |
180 | Index: linux-2.6.27/include/linux/mount.h | |
181 | =================================================================== | |
182 | --- linux-2.6.27.orig/include/linux/mount.h | |
183 | +++ linux-2.6.27/include/linux/mount.h | |
184 | @@ -98,7 +98,12 @@ static inline struct vfsmount *mntget(st | |
185 | return mnt; | |
186 | } | |
187 | ||
188 | +struct file; | |
189 | + | |
190 | extern int mnt_want_write(struct vfsmount *mnt); | |
191 | +extern int mnt_want_write_file(struct vfsmount *mnt, struct file *file); | |
192 | +extern void mnt_clone_write(struct vfsmount *mnt); | |
193 | +extern int mnt_clone_write_2(struct vfsmount *mnt); | |
194 | extern void mnt_drop_write(struct vfsmount *mnt); | |
195 | extern void mntput_no_expire(struct vfsmount *mnt); | |
196 | extern void mnt_pin(struct vfsmount *mnt); |