proc: faster open/close of files without ->release hook
authorAlexey Dobriyan <adobriyan@gmail.com>
Tue, 10 Apr 2018 23:31:01 +0000 (16:31 -0700)
committerLinus Torvalds <torvalds@linux-foundation.org>
Wed, 11 Apr 2018 17:28:33 +0000 (10:28 -0700)
The whole point of code in fs/proc/inode.c is to make sure ->release
hook is called either at close() or at rmmod time.

All if it is unnecessary if there is no ->release hook.

Save allocation+list manipulations under spinlock in that case.

Link: http://lkml.kernel.org/r/20180214063033.GA15579@avx2
Signed-off-by: Alexey Dobriyan <adobriyan@gmail.com>
Cc: Al Viro <viro@ZenIV.linux.org.uk>
Cc: Kees Cook <keescook@chromium.org>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
fs/proc/inode.c

index 8118ce5..0331ddb 100644 (file)
@@ -342,31 +342,36 @@ static int proc_reg_open(struct inode *inode, struct file *file)
         *
         * Save every "struct file" with custom ->release hook.
         */
-       pdeo = kmalloc(sizeof(struct pde_opener), GFP_KERNEL);
-       if (!pdeo)
-               return -ENOMEM;
-
-       if (!use_pde(pde)) {
-               kfree(pdeo);
+       if (!use_pde(pde))
                return -ENOENT;
-       }
-       open = pde->proc_fops->open;
+
        release = pde->proc_fops->release;
+       if (release) {
+               pdeo = kmalloc(sizeof(struct pde_opener), GFP_KERNEL);
+               if (!pdeo) {
+                       rv = -ENOMEM;
+                       goto out_unuse;
+               }
+       }
 
+       open = pde->proc_fops->open;
        if (open)
                rv = open(inode, file);
 
-       if (rv == 0 && release) {
-               /* To know what to release. */
-               pdeo->file = file;
-               pdeo->closing = false;
-               pdeo->c = NULL;
-               spin_lock(&pde->pde_unload_lock);
-               list_add(&pdeo->lh, &pde->pde_openers);
-               spin_unlock(&pde->pde_unload_lock);
-       } else
-               kfree(pdeo);
+       if (release) {
+               if (rv == 0) {
+                       /* To know what to release. */
+                       pdeo->file = file;
+                       pdeo->closing = false;
+                       pdeo->c = NULL;
+                       spin_lock(&pde->pde_unload_lock);
+                       list_add(&pdeo->lh, &pde->pde_openers);
+                       spin_unlock(&pde->pde_unload_lock);
+               } else
+                       kfree(pdeo);
+       }
 
+out_unuse:
        unuse_pde(pde);
        return rv;
 }