aboutsummaryrefslogtreecommitdiffstats
path: root/fs/proc
diff options
context:
space:
mode:
authorAlexey Dobriyan <adobriyan@gmail.com>2018-04-10 19:30:54 -0400
committerLinus Torvalds <torvalds@linux-foundation.org>2018-04-11 13:28:33 -0400
commit2f8974243507d9e5b0f214d7668a59a66b93f36c (patch)
treedaef514c815b0989ca99ccf67d8725d9262c7d56 /fs/proc
parent68c3411ff4a4cee53cc854c11ed191eaaf1956ba (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.c14
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 */
142static void close_pdeo(struct proc_dir_entry *pde, struct pde_opener *pdeo) 142static 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);