diff options
author | Alexey Dobriyan <adobriyan@gmail.com> | 2018-04-10 19:30:54 -0400 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2018-04-11 13:28:33 -0400 |
commit | 2f8974243507d9e5b0f214d7668a59a66b93f36c (patch) | |
tree | daef514c815b0989ca99ccf67d8725d9262c7d56 /fs/proc | |
parent | 68c3411ff4a4cee53cc854c11ed191eaaf1956ba (diff) |
proc: do less stuff under ->pde_unload_lock
Commit ca469f35a8e9ef ("deal with races between remove_proc_entry() and
proc_reg_release()") moved too much stuff under ->pde_unload_lock making
a problem described at series "[PATCH v5] procfs: Improve Scaling in
proc" worse.
While RCU is being figured out, move kfree() out of ->pde_unload_lock.
On my potato, difference is only 0.5% speedup with concurrent
open+read+close of /proc/cmdline, but the effect should be more
noticeable on more capable machines.
$ perf stat -r 16 -- ./proc-j 16
Performance counter stats for './proc-j 16' (16 runs):
130569.502377 task-clock (msec) # 15.872 CPUs utilized ( +- 0.05% )
19,169 context-switches # 0.147 K/sec ( +- 0.18% )
15 cpu-migrations # 0.000 K/sec ( +- 3.27% )
437 page-faults # 0.003 K/sec ( +- 1.25% )
300,172,097,675 cycles # 2.299 GHz ( +- 0.05% )
96,793,267,308 instructions # 0.32 insn per cycle ( +- 0.04% )
22,798,342,298 branches # 174.607 M/sec ( +- 0.04% )
111,764,687 branch-misses # 0.49% of all branches ( +- 0.47% )
8.226574400 seconds time elapsed ( +- 0.05% )
^^^^^^^^^^^
$ perf stat -r 16 -- ./proc-j 16
Performance counter stats for './proc-j 16' (16 runs):
129866.777392 task-clock (msec) # 15.869 CPUs utilized ( +- 0.04% )
19,154 context-switches # 0.147 K/sec ( +- 0.66% )
14 cpu-migrations # 0.000 K/sec ( +- 1.73% )
431 page-faults # 0.003 K/sec ( +- 1.09% )
298,556,520,546 cycles # 2.299 GHz ( +- 0.04% )
96,525,366,833 instructions # 0.32 insn per cycle ( +- 0.04% )
22,730,194,043 branches # 175.027 M/sec ( +- 0.04% )
111,506,074 branch-misses # 0.49% of all branches ( +- 0.18% )
8.183629778 seconds time elapsed ( +- 0.04% )
^^^^^^^^^^^
Link: http://lkml.kernel.org/r/20180213132911.GA24298@avx2
Signed-off-by: Alexey Dobriyan <adobriyan@gmail.com>
Reviewed-by: Andrew Morton <akpm@linux-foundation.org>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
Diffstat (limited to 'fs/proc')
-rw-r--r-- | fs/proc/inode.c | 14 |
1 files changed, 9 insertions, 5 deletions
diff --git a/fs/proc/inode.c b/fs/proc/inode.c index 6e8724958116..8118ce5df5c6 100644 --- a/fs/proc/inode.c +++ b/fs/proc/inode.c | |||
@@ -138,7 +138,7 @@ static void unuse_pde(struct proc_dir_entry *pde) | |||
138 | complete(pde->pde_unload_completion); | 138 | complete(pde->pde_unload_completion); |
139 | } | 139 | } |
140 | 140 | ||
141 | /* pde is locked */ | 141 | /* pde is locked on entry, unlocked on exit */ |
142 | static void close_pdeo(struct proc_dir_entry *pde, struct pde_opener *pdeo) | 142 | static void close_pdeo(struct proc_dir_entry *pde, struct pde_opener *pdeo) |
143 | { | 143 | { |
144 | /* | 144 | /* |
@@ -157,9 +157,10 @@ static void close_pdeo(struct proc_dir_entry *pde, struct pde_opener *pdeo) | |||
157 | pdeo->c = &c; | 157 | pdeo->c = &c; |
158 | spin_unlock(&pde->pde_unload_lock); | 158 | spin_unlock(&pde->pde_unload_lock); |
159 | wait_for_completion(&c); | 159 | wait_for_completion(&c); |
160 | spin_lock(&pde->pde_unload_lock); | ||
161 | } else { | 160 | } else { |
162 | struct file *file; | 161 | struct file *file; |
162 | struct completion *c; | ||
163 | |||
163 | pdeo->closing = true; | 164 | pdeo->closing = true; |
164 | spin_unlock(&pde->pde_unload_lock); | 165 | spin_unlock(&pde->pde_unload_lock); |
165 | file = pdeo->file; | 166 | file = pdeo->file; |
@@ -167,8 +168,10 @@ static void close_pdeo(struct proc_dir_entry *pde, struct pde_opener *pdeo) | |||
167 | spin_lock(&pde->pde_unload_lock); | 168 | spin_lock(&pde->pde_unload_lock); |
168 | /* After ->release. */ | 169 | /* After ->release. */ |
169 | list_del(&pdeo->lh); | 170 | list_del(&pdeo->lh); |
170 | if (unlikely(pdeo->c)) | 171 | c = pdeo->c; |
171 | complete(pdeo->c); | 172 | spin_unlock(&pde->pde_unload_lock); |
173 | if (unlikely(c)) | ||
174 | complete(c); | ||
172 | kfree(pdeo); | 175 | kfree(pdeo); |
173 | } | 176 | } |
174 | } | 177 | } |
@@ -188,6 +191,7 @@ void proc_entry_rundown(struct proc_dir_entry *de) | |||
188 | struct pde_opener *pdeo; | 191 | struct pde_opener *pdeo; |
189 | pdeo = list_first_entry(&de->pde_openers, struct pde_opener, lh); | 192 | pdeo = list_first_entry(&de->pde_openers, struct pde_opener, lh); |
190 | close_pdeo(de, pdeo); | 193 | close_pdeo(de, pdeo); |
194 | spin_lock(&de->pde_unload_lock); | ||
191 | } | 195 | } |
192 | spin_unlock(&de->pde_unload_lock); | 196 | spin_unlock(&de->pde_unload_lock); |
193 | } | 197 | } |
@@ -375,7 +379,7 @@ static int proc_reg_release(struct inode *inode, struct file *file) | |||
375 | list_for_each_entry(pdeo, &pde->pde_openers, lh) { | 379 | list_for_each_entry(pdeo, &pde->pde_openers, lh) { |
376 | if (pdeo->file == file) { | 380 | if (pdeo->file == file) { |
377 | close_pdeo(pde, pdeo); | 381 | close_pdeo(pde, pdeo); |
378 | break; | 382 | return 0; |
379 | } | 383 | } |
380 | } | 384 | } |
381 | spin_unlock(&pde->pde_unload_lock); | 385 | spin_unlock(&pde->pde_unload_lock); |