]> git.ipfire.org Git - thirdparty/linux.git/commitdiff
super: convert s_count to refcount_t s_passive
authorChristian Brauner <brauner@kernel.org>
Tue, 16 Jun 2026 14:08:18 +0000 (16:08 +0200)
committerChristian Brauner <brauner@kernel.org>
Mon, 29 Jun 2026 08:31:51 +0000 (10:31 +0200)
The superblock carries two counters: s_active, the active reference
count that keeps the filesystem usable, and s_count, the passive
reference count that merely keeps the structure itself alive. Turn the
passive count into a refcount_t and rename it to s_passive to make the
pairing with s_active obvious.

Everything is still serialized by sb_lock, so there is no functional
change; the conversion buys the usual refcount_t saturation and
underflow checking. The following patches start dropping passive
references without holding sb_lock and make the device-to-superblock
table hold one passive reference per registered entry, which a plain
integer cannot support.

Link: https://patch.msgid.link/20260616-work-super-bdev_holder_global-v2-2-7df6b864028e@kernel.org
Reviewed-by: Jan Kara <jack@suse.cz>
Signed-off-by: Christian Brauner (Amutable) <brauner@kernel.org>
fs/super.c
include/linux/fs/super_types.h

index a8fd61136aafe5719c9484fc343f7ddbeaf6263c..25dd72b550e0aa609ad60e8bf403552b9ed5b3de 100644 (file)
@@ -102,7 +102,7 @@ static bool super_flags(const struct super_block *sb, unsigned int flags)
  * creation will succeed and SB_BORN is set by vfs_get_tree() or we're
  * woken and we'll see SB_DYING.
  *
- * The caller must have acquired a temporary reference on @sb->s_count.
+ * The caller must have acquired a temporary reference on @sb->s_passive.
  *
  * Return: The function returns true if SB_BORN was set and with
  *         s_umount held. The function returns false if SB_DYING was
@@ -367,7 +367,7 @@ static struct super_block *alloc_super(struct file_system_type *type, int flags,
        spin_lock_init(&s->s_inode_wblist_lock);
        fserror_mount(s);
 
-       s->s_count = 1;
+       refcount_set(&s->s_passive, 1);
        atomic_set(&s->s_active, 1);
        mutex_init(&s->s_vfs_rename_mutex);
        lockdep_set_class(&s->s_vfs_rename_mutex, &type->s_vfs_rename_key);
@@ -407,7 +407,7 @@ fail:
  */
 static void __put_super(struct super_block *s)
 {
-       if (!--s->s_count) {
+       if (refcount_dec_and_test(&s->s_passive)) {
                list_del_init(&s->s_list);
                WARN_ON(s->s_dentry_lru.node);
                WARN_ON(s->s_inode_lru.node);
@@ -529,7 +529,7 @@ static bool grab_super(struct super_block *sb)
 {
        bool locked;
 
-       sb->s_count++;
+       refcount_inc(&sb->s_passive);
        spin_unlock(&sb_lock);
        locked = super_lock_excl(sb);
        if (locked) {
@@ -556,7 +556,7 @@ static bool grab_super(struct super_block *sb)
  *     lock held in read mode in case of success. On successful return,
  *     the caller must drop the s_umount lock when done.
  *
- *     Note that unlike get_super() et.al. this one does *not* bump ->s_count.
+ *     Note that unlike get_super() et.al. this one does *not* bump ->s_passive.
  *     The reason why it's safe is that we are OK with doing trylock instead
  *     of down_read().  There's a couple of places that are OK with that, but
  *     it's very much not a general-purpose interface.
@@ -858,7 +858,7 @@ static void __iterate_supers(void (*f)(struct super_block *, void *), void *arg,
             sb = next_super(sb, flags)) {
                if (super_flags(sb, SB_DYING))
                        continue;
-               sb->s_count++;
+               refcount_inc(&sb->s_passive);
                spin_unlock(&sb_lock);
 
                if (flags & SUPER_ITER_UNLOCKED) {
@@ -903,7 +903,7 @@ void iterate_supers_type(struct file_system_type *type,
                if (super_flags(sb, SB_DYING))
                        continue;
 
-               sb->s_count++;
+               refcount_inc(&sb->s_passive);
                spin_unlock(&sb_lock);
 
                locked = super_lock_shared(sb);
@@ -935,7 +935,7 @@ struct super_block *user_get_super(dev_t dev, bool excl)
                if (sb->s_dev != dev)
                        continue;
 
-               sb->s_count++;
+               refcount_inc(&sb->s_passive);
                spin_unlock(&sb_lock);
 
                locked = super_lock(sb, excl);
@@ -1369,7 +1369,7 @@ static struct super_block *bdev_super_lock(struct block_device *bdev, bool excl)
 
        /* Make sure sb doesn't go away from under us */
        spin_lock(&sb_lock);
-       sb->s_count++;
+       refcount_inc(&sb->s_passive);
        spin_unlock(&sb_lock);
 
        mutex_unlock(&bdev->bd_holder_lock);
index ef7941e9dc79ac1a36dc8d098e43d9f220d78b69..68747182abf9afcb4001a32c85e1a496484e7ee7 100644 (file)
@@ -145,7 +145,7 @@ struct super_block {
        unsigned long                           s_magic;
        struct dentry                           *s_root;
        struct rw_semaphore                     s_umount;
-       int                                     s_count;
+       refcount_t                              s_passive;
        atomic_t                                s_active;
 #ifdef CONFIG_SECURITY
        void                                    *s_security;