Merge tag 'bootconfig-v6.7' of git://git.kernel.org/pub/scm/linux/kernel/git/trace...
[linux-block.git] / fs / file_table.c
index ee21b3da9d08121f4712f100cde62c5ea771faaf..fa92743ba6a91691f3621e0d8d050460c24649ef 100644 (file)
@@ -44,10 +44,10 @@ static struct kmem_cache *filp_cachep __read_mostly;
 
 static struct percpu_counter nr_files __cacheline_aligned_in_smp;
 
-/* Container for backing file with optional real path */
+/* Container for backing file with optional user path */
 struct backing_file {
        struct file file;
-       struct path real_path;
+       struct path user_path;
 };
 
 static inline struct backing_file *backing_file(struct file *f)
@@ -55,31 +55,36 @@ static inline struct backing_file *backing_file(struct file *f)
        return container_of(f, struct backing_file, file);
 }
 
-struct path *backing_file_real_path(struct file *f)
+struct path *backing_file_user_path(struct file *f)
 {
-       return &backing_file(f)->real_path;
+       return &backing_file(f)->user_path;
 }
-EXPORT_SYMBOL_GPL(backing_file_real_path);
+EXPORT_SYMBOL_GPL(backing_file_user_path);
 
-static void file_free_rcu(struct rcu_head *head)
+static inline void file_free(struct file *f)
 {
-       struct file *f = container_of(head, struct file, f_rcuhead);
-
+       security_file_free(f);
+       if (likely(!(f->f_mode & FMODE_NOACCOUNT)))
+               percpu_counter_dec(&nr_files);
        put_cred(f->f_cred);
-       if (unlikely(f->f_mode & FMODE_BACKING))
+       if (unlikely(f->f_mode & FMODE_BACKING)) {
+               path_put(backing_file_user_path(f));
                kfree(backing_file(f));
-       else
+       } else {
                kmem_cache_free(filp_cachep, f);
+       }
 }
 
-static inline void file_free(struct file *f)
+void release_empty_file(struct file *f)
 {
-       security_file_free(f);
-       if (unlikely(f->f_mode & FMODE_BACKING))
-               path_put(backing_file_real_path(f));
-       if (likely(!(f->f_mode & FMODE_NOACCOUNT)))
-               percpu_counter_dec(&nr_files);
-       call_rcu(&f->f_rcuhead, file_free_rcu);
+       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);
+       }
 }
 
 /*
@@ -164,7 +169,6 @@ static int init_file(struct file *f, int flags, const struct cred *cred)
                return error;
        }
 
-       atomic_long_set(&f->f_count, 1);
        rwlock_init(&f->f_owner.lock);
        spin_lock_init(&f->f_lock);
        mutex_init(&f->f_pos_lock);
@@ -172,6 +176,12 @@ static int init_file(struct file *f, int flags, const struct cred *cred)
        f->f_mode = OPEN_FMODE(flags);
        /* f->f_version: 0 */
 
+       /*
+        * We're SLAB_TYPESAFE_BY_RCU so initialize f_count last. While
+        * fget-rcu pattern users need to be able to handle spurious
+        * refcount bumps we should reinitialize the reused file first.
+        */
+       atomic_long_set(&f->f_count, 1);
        return 0;
 }
 
@@ -471,7 +481,8 @@ EXPORT_SYMBOL(__fput_sync);
 void __init files_init(void)
 {
        filp_cachep = kmem_cache_create("filp", sizeof(struct file), 0,
-                       SLAB_HWCACHE_ALIGN | SLAB_PANIC | SLAB_ACCOUNT, NULL);
+                               SLAB_TYPESAFE_BY_RCU | SLAB_HWCACHE_ALIGN |
+                               SLAB_PANIC | SLAB_ACCOUNT, NULL);
        percpu_counter_init(&nr_files, 0, GFP_KERNEL);
 }