From mboxrd@z Thu Jan 1 00:00:00 1970 Received: from smtp.kernel.org (aws-us-west-2-korg-mail-alma10-1.taild15c8.ts.net [100.103.45.18]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 238442459E1 for ; Tue, 29 Sep 2026 13:52:33 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=100.103.45.18 ARC-Seal:i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1790689954; cv=none; b=cnPUW4GqGc4JNBwllj5PAA+sm2/e7KP5BmGHob/mGdEF538L8eNqfy07k0bRLpBc6AUfLfLbhb5R+1KrO5llGp53UNSSzFnVroSKSACFyDyoet4z5LgVc6yOzFQLZJYbJfnLPatOZAiQQk2OAB/Htdx4RWUWzJ0MUxLSIJ8WRPQ= ARC-Message-Signature:i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1790689954; c=relaxed/simple; bh=gh8RMTVuWih0XrpmgD6nUQ0FYH/eNcVt/cp9for0IOU=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=VaOj89W4mgqsTQKvLA41x4oNvfpsmX9Vw7+iCA23fvZiald0QczLuEL9z9Ibg/pHkCxEEeUNraLA+cL/i9X4et8OUmhno/ivVNmOLiOOciriDTIspSVnrtGITT2LjRHU4T2zyHdRRX44SCxanCPTDv2qLqzbAeaL/ji8fN8zBQE= ARC-Authentication-Results:i=1; smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b=mMT8EG3J; arc=none smtp.client-ip=100.103.45.18 Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b="mMT8EG3J" Received: by smtp.kernel.org (Postfix) with ESMTPSA id 76FA61F00898; Tue, 29 Sep 2026 13:52:32 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=kernel.org; s=k20260515; t=1790689953; bh=a9GenIquV6UONHamL26TL5uckFjVXfCOrNFyy+RKlV8=; h=From:To:Cc:Subject:Date:In-Reply-To:References; b=mMT8EG3JExyKBlvfSrA1gFZex+r9tebTQN5+ila7IpR9dOWLU/qQaGsriZOy7AwAR cc59vT1EJT4aZrq04RynqFDJDmBSBpB2FBJ+ZEP2L2Iddj+GtA8AGeypjRu1VsqkYu l9aB+wPR64037odPT4NlpPuj2bDbc5uAL+IkiMQeYXcp+8EhXEKprU9M+RZYly02us idRr8+06QPInOjhkS6nGT1WSliheD0FfOt4iGmsP6uDdPXjNnFzY3XvT0cLRJrgGpt 2ro3EzvQXFCqkeyL/jrzQqgHP92dn2JLSFzPVYnj7oznVg7jUepERuv171u7sIZBao 8OdM8YW5Js9gw== From: Sasha Levin To: stable@vger.kernel.org Cc: Christian Brauner , Jan Kara , Sasha Levin Subject: [PATCH 7.2.y 2/3] super: take lock after last reference count Date: Tue, 29 Sep 2026 09:52:29 -0400 Message-ID: <20260929135230.3522081-2-sashal@kernel.org> X-Mailer: git-send-email 2.53.0 In-Reply-To: <20260929135230.3522081-1-sashal@kernel.org> References: <2026092911-clunky-same-c5c5@gregkh> <20260929135230.3522081-1-sashal@kernel.org> Precedence: bulk X-Mailing-List: stable@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Transfer-Encoding: 8bit From: Christian Brauner [ Upstream commit 9c486f28994fdfc1a83f5f60129402cf4379957b ] __put_super() required the caller to hold sb_lock, so put_super() wrapped it. The per-device superblock table introduced later drops its passive references from contexts that do not hold sb_lock, so make put_super() self-locking: drop the count first and take sb_lock only for the final list_del. With the count now dropped outside sb_lock a superblock can briefly sit on @super_blocks with s_passive == 0 before it is unlinked, so the list walkers (__iterate_supers(), iterate_supers_type(), user_get_super()) switch to refcount_inc_not_zero() and skip it. Link: https://patch.msgid.link/20260616-work-super-bdev_holder_global-v2-3-7df6b864028e@kernel.org Reviewed-by: Jan Kara Signed-off-by: Christian Brauner (Amutable) Stable-dep-of: 2d2a2d7aa987 ("super: make iterate_supers_type() deletion-safe") Signed-off-by: Sasha Levin --- fs/super.c | 63 ++++++++++++++++++++++++------------------------------ 1 file changed, 28 insertions(+), 35 deletions(-) diff --git a/fs/super.c b/fs/super.c index dae21bf03e1cd..2399bb3a17527 100644 --- a/fs/super.c +++ b/fs/super.c @@ -404,12 +404,17 @@ static struct super_block *alloc_super(struct file_system_type *type, int flags, /* Superblock refcounting */ /* - * Drop a superblock's refcount. The caller must hold sb_lock. + * Drop a superblock's passive reference. Must be called WITHOUT sb_lock held; + * put_super() acquires sb_lock itself when the final reference is dropped. */ -static void __put_super(struct super_block *s) +void put_super(struct super_block *s) { if (refcount_dec_and_test(&s->s_passive)) { + + spin_lock(&sb_lock); list_del_init(&s->s_list); + spin_unlock(&sb_lock); + WARN_ON(s->s_dentry_lru.node); WARN_ON(s->s_inode_lru.node); WARN_ON(s->s_mounts); @@ -417,20 +422,6 @@ static void __put_super(struct super_block *s) } } -/** - * put_super - drop a temporary reference to superblock - * @sb: superblock in question - * - * Drops a temporary reference, frees superblock if there's no - * references left. - */ -void put_super(struct super_block *sb) -{ - spin_lock(&sb_lock); - __put_super(sb); - spin_unlock(&sb_lock); -} - static void kill_super_notify(struct super_block *sb) { lockdep_assert_not_held(&sb->s_umount); @@ -479,11 +470,7 @@ void deactivate_locked_super(struct super_block *s) kill_super_notify(s); - /* - * Since list_lru_destroy() may sleep, we cannot call it from - * put_super(), where we hold the sb_lock. Therefore we destroy - * the lru lists right now. - */ + /* list_lru_destroy() may sleep; put_super() callers may not. */ list_lru_destroy(&s->s_dentry_lru); list_lru_destroy(&s->s_inode_lru); @@ -852,14 +839,17 @@ static void __iterate_supers(void (*f)(struct super_block *, void *), void *arg, struct super_block *sb, *p = NULL; bool excl = flags & SUPER_ITER_EXCL; - guard(spinlock)(&sb_lock); + spin_lock(&sb_lock); for (sb = first_super(flags); !list_entry_is_head(sb, &super_blocks, s_list); sb = next_super(sb, flags)) { if (super_flags(sb, SB_DYING)) continue; - refcount_inc(&sb->s_passive); + + if (!refcount_inc_not_zero(&sb->s_passive)) + continue; + spin_unlock(&sb_lock); if (flags & SUPER_ITER_UNLOCKED) { @@ -869,13 +859,14 @@ static void __iterate_supers(void (*f)(struct super_block *, void *), void *arg, super_unlock(sb, excl); } - spin_lock(&sb_lock); if (p) - __put_super(p); + put_super(p); p = sb; + spin_lock(&sb_lock); } + spin_unlock(&sb_lock); if (p) - __put_super(p); + put_super(p); } void iterate_supers(void (*f)(struct super_block *, void *), void *arg) @@ -904,7 +895,9 @@ void iterate_supers_type(struct file_system_type *type, if (super_flags(sb, SB_DYING)) continue; - refcount_inc(&sb->s_passive); + if (!refcount_inc_not_zero(&sb->s_passive)) + continue; + spin_unlock(&sb_lock); locked = super_lock_shared(sb); @@ -913,14 +906,14 @@ void iterate_supers_type(struct file_system_type *type, super_unlock_shared(sb); } - spin_lock(&sb_lock); if (p) - __put_super(p); + put_super(p); p = sb; + spin_lock(&sb_lock); } - if (p) - __put_super(p); spin_unlock(&sb_lock); + if (p) + put_super(p); } EXPORT_SYMBOL(iterate_supers_type); @@ -936,15 +929,17 @@ struct super_block *user_get_super(dev_t dev, bool excl) if (sb->s_dev != dev) continue; - refcount_inc(&sb->s_passive); + if (!refcount_inc_not_zero(&sb->s_passive)) + continue; + spin_unlock(&sb_lock); locked = super_lock(sb, excl); if (locked) return sb; + put_super(sb); spin_lock(&sb_lock); - __put_super(sb); break; } spin_unlock(&sb_lock); @@ -1375,9 +1370,7 @@ static struct super_block *bdev_super_lock(struct block_device *bdev, bool excl) lockdep_assert_not_held(&bdev->bd_disk->open_mutex); /* Make sure sb doesn't go away from under us */ - spin_lock(&sb_lock); refcount_inc(&sb->s_passive); - spin_unlock(&sb_lock); mutex_unlock(&bdev->bd_holder_lock); -- 2.53.0