Commit 2f897424 authored by Alexey Dobriyan's avatar Alexey Dobriyan Committed by Linus Torvalds

proc: do less stuff under ->pde_unload_lock

Commit ca469f35 ("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@avx2Signed-off-by: default avatarAlexey Dobriyan <adobriyan@gmail.com>
Reviewed-by: default avatarAndrew Morton <akpm@linux-foundation.org>
Signed-off-by: default avatarAndrew Morton <akpm@linux-foundation.org>
Signed-off-by: default avatarLinus Torvalds <torvalds@linux-foundation.org>
parent 68c3411f
...@@ -138,7 +138,7 @@ static void unuse_pde(struct proc_dir_entry *pde) ...@@ -138,7 +138,7 @@ static void unuse_pde(struct proc_dir_entry *pde)
complete(pde->pde_unload_completion); complete(pde->pde_unload_completion);
} }
/* pde is locked */ /* pde is locked on entry, unlocked on exit */
static void close_pdeo(struct proc_dir_entry *pde, struct pde_opener *pdeo) static void close_pdeo(struct proc_dir_entry *pde, struct pde_opener *pdeo)
{ {
/* /*
...@@ -157,9 +157,10 @@ static void close_pdeo(struct proc_dir_entry *pde, struct pde_opener *pdeo) ...@@ -157,9 +157,10 @@ static void close_pdeo(struct proc_dir_entry *pde, struct pde_opener *pdeo)
pdeo->c = &c; pdeo->c = &c;
spin_unlock(&pde->pde_unload_lock); spin_unlock(&pde->pde_unload_lock);
wait_for_completion(&c); wait_for_completion(&c);
spin_lock(&pde->pde_unload_lock);
} else { } else {
struct file *file; struct file *file;
struct completion *c;
pdeo->closing = true; pdeo->closing = true;
spin_unlock(&pde->pde_unload_lock); spin_unlock(&pde->pde_unload_lock);
file = pdeo->file; file = pdeo->file;
...@@ -167,8 +168,10 @@ static void close_pdeo(struct proc_dir_entry *pde, struct pde_opener *pdeo) ...@@ -167,8 +168,10 @@ static void close_pdeo(struct proc_dir_entry *pde, struct pde_opener *pdeo)
spin_lock(&pde->pde_unload_lock); spin_lock(&pde->pde_unload_lock);
/* After ->release. */ /* After ->release. */
list_del(&pdeo->lh); list_del(&pdeo->lh);
if (unlikely(pdeo->c)) c = pdeo->c;
complete(pdeo->c); spin_unlock(&pde->pde_unload_lock);
if (unlikely(c))
complete(c);
kfree(pdeo); kfree(pdeo);
} }
} }
...@@ -188,6 +191,7 @@ void proc_entry_rundown(struct proc_dir_entry *de) ...@@ -188,6 +191,7 @@ void proc_entry_rundown(struct proc_dir_entry *de)
struct pde_opener *pdeo; struct pde_opener *pdeo;
pdeo = list_first_entry(&de->pde_openers, struct pde_opener, lh); pdeo = list_first_entry(&de->pde_openers, struct pde_opener, lh);
close_pdeo(de, pdeo); close_pdeo(de, pdeo);
spin_lock(&de->pde_unload_lock);
} }
spin_unlock(&de->pde_unload_lock); spin_unlock(&de->pde_unload_lock);
} }
...@@ -375,7 +379,7 @@ static int proc_reg_release(struct inode *inode, struct file *file) ...@@ -375,7 +379,7 @@ static int proc_reg_release(struct inode *inode, struct file *file)
list_for_each_entry(pdeo, &pde->pde_openers, lh) { list_for_each_entry(pdeo, &pde->pde_openers, lh) {
if (pdeo->file == file) { if (pdeo->file == file) {
close_pdeo(pde, pdeo); close_pdeo(pde, pdeo);
break; return 0;
} }
} }
spin_unlock(&pde->pde_unload_lock); spin_unlock(&pde->pde_unload_lock);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment