s_count is the temporary-reference count used to pin a superblock across the spinlock-to-rwsem hop in every iterator and in grab_super(). It's a plain int incremented and decremented only under sb_lock. Convert it to refcount_t. No semantic change yet: every increment still happens with sb_lock held, so observation of a live ref is still serialised by the lock. The increments use refcount_inc() rather than refcount_inc_not_zero() because every callsite is still looking at an sb known to be live under sb_lock. This prepares the ground for switching iterators to RCU readers in a later patch, at which point refcount_inc_not_zero() becomes the right primitive at the lockless pin sites. Signed-off-by: Christian Brauner (Amutable) --- fs/super.c | 14 +++++++------- include/linux/fs/super_types.h | 3 ++- 2 files changed, 9 insertions(+), 8 deletions(-) diff --git a/fs/super.c b/fs/super.c index c451f689c7b3..2fa7023010ec 100644 --- a/fs/super.c +++ b/fs/super.c @@ -366,7 +366,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_count, 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); @@ -406,7 +406,7 @@ static struct super_block *alloc_super(struct file_system_type *type, int flags, */ static void __put_super(struct super_block *s) { - if (!--s->s_count) { + if (refcount_dec_and_test(&s->s_count)) { list_del_init(&s->s_list); WARN_ON(s->s_dentry_lru.node); WARN_ON(s->s_inode_lru.node); @@ -528,7 +528,7 @@ static bool grab_super(struct super_block *sb) { bool locked; - sb->s_count++; + refcount_inc(&sb->s_count); spin_unlock(&sb_lock); locked = super_lock_excl(sb); if (locked) { @@ -857,7 +857,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_count); spin_unlock(&sb_lock); if (flags & SUPER_ITER_UNLOCKED) { @@ -902,7 +902,7 @@ void iterate_supers_type(struct file_system_type *type, if (super_flags(sb, SB_DYING)) continue; - sb->s_count++; + refcount_inc(&sb->s_count); spin_unlock(&sb_lock); locked = super_lock_shared(sb); @@ -934,7 +934,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_count); spin_unlock(&sb_lock); locked = super_lock(sb, excl); @@ -1368,7 +1368,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_count); spin_unlock(&sb_lock); mutex_unlock(&bdev->bd_holder_lock); diff --git a/include/linux/fs/super_types.h b/include/linux/fs/super_types.h index 383050e7fdf5..3a8cc0c723a8 100644 --- a/include/linux/fs/super_types.h +++ b/include/linux/fs/super_types.h @@ -11,6 +11,7 @@ #include #include #include +#include #include #include @@ -145,7 +146,7 @@ struct super_block { unsigned long s_magic; struct dentry *s_root; struct rw_semaphore s_umount; - int s_count; + refcount_t s_count; atomic_t s_active; #ifdef CONFIG_SECURITY void *s_security; -- 2.47.3