]> git.ipfire.org Git - thirdparty/linux.git/commitdiff
file: massage cleanup of files that failed to open
authorAl Viro <viro@zeniv.linux.org.uk>
Sun, 26 Nov 2023 02:08:34 +0000 (02:08 +0000)
committerChristian Brauner <brauner@kernel.org>
Tue, 12 Dec 2023 13:24:09 +0000 (14:24 +0100)
A file that has never gotten FMODE_OPENED will never have RCU-accessed
references, its final fput() is equivalent to file_free() and if it
doesn't have FMODE_BACKING either, it can be done from any context and
won't need task_work treatment.

Now that we have SLAB_TYPESAFE_BY_RCU we can simplify this and have
other callers benefit. All of that can be achieved easier is to make
fput() recoginze that case and call file_free() directly.

No need to introduce a special primitive for that. It also allowed
things like failing dentry_open() could benefit from that as well.

Signed-off-by: Al Viro <viro@zeniv.linux.org.uk>
[Christian Brauner <brauner@kernel.org>: massage commit message]
Link: https://lore.kernel.org/r/20231126020834.GC38156@ZenIV
Signed-off-by: Christian Brauner <brauner@kernel.org>
fs/file_table.c
fs/internal.h
fs/namei.c

index de4a2915bfd4941281915be92ce7dbdd8f67ac3b..6deac386486d0244fa9e5ba51746caab946e1e9f 100644 (file)
@@ -75,18 +75,6 @@ static inline void file_free(struct file *f)
        }
 }
 
-void release_empty_file(struct file *f)
-{
-       WARN_ON_ONCE(f->f_mode & (FMODE_BACKING | FMODE_OPENED));
-       if (atomic_long_dec_and_test(&f->f_count)) {
-               security_file_free(f);
-               put_cred(f->f_cred);
-               if (likely(!(f->f_mode & FMODE_NOACCOUNT)))
-                       percpu_counter_dec(&nr_files);
-               kmem_cache_free(filp_cachep, f);
-       }
-}
-
 /*
  * Return the total number of open files in the system
  */
@@ -445,6 +433,10 @@ void fput(struct file *file)
        if (atomic_long_dec_and_test(&file->f_count)) {
                struct task_struct *task = current;
 
+               if (unlikely(!(file->f_mode & (FMODE_BACKING | FMODE_OPENED)))) {
+                       file_free(file);
+                       return;
+               }
                if (likely(!in_interrupt() && !(task->flags & PF_KTHREAD))) {
                        init_task_work(&file->f_rcuhead, ____fput);
                        if (!task_work_add(task, &file->f_rcuhead, TWA_RESUME))
index 58e43341aebf07d92245f789fd1cdf8d5415cebd..273e6fd40d1be26482c4a191d136c2391666b813 100644 (file)
@@ -94,7 +94,6 @@ extern void chroot_fs_refs(const struct path *, const struct path *);
 struct file *alloc_empty_file(int flags, const struct cred *cred);
 struct file *alloc_empty_file_noaccount(int flags, const struct cred *cred);
 struct file *alloc_empty_backing_file(int flags, const struct cred *cred);
-void release_empty_file(struct file *f);
 
 static inline void file_put_write_access(struct file *file)
 {
index 71c13b2990b44f426a778bb0ad8f969a89387b4f..f0ead1858267cfbb0ac912e9d132511605fec9fd 100644 (file)
@@ -3785,10 +3785,7 @@ static struct file *path_openat(struct nameidata *nd,
                WARN_ON(1);
                error = -EINVAL;
        }
-       if (unlikely(file->f_mode & FMODE_OPENED))
-               fput(file);
-       else
-               release_empty_file(file);
+       fput(file);
        if (error == -EOPENSTALE) {
                if (flags & LOOKUP_RCU)
                        error = -ECHILD;