FAILED: patch "[PATCH] super: make iterate_supers_type() deletion-safe" failed to apply to 6.1-stable tree
Subsystems (3)
[email protected]
maintainerThe patch below does not apply to the 6.1-stable tree.
If someone wants it applied there, or to any other stable or longterm tree, then please email the backport, including the original git commit id to <[email protected]>.
To reproduce the conflict and resubmit, you may use the following commands:
git fetch https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git/ linux-6.1.y
git checkout FETCH_HEAD
git cherry-pick -x 2d2a2d7aa98741b58f54cacc99b52024e4d865f9
# <resolve conflicts, build, test, etc.>
git commit -s
git send-email --to '<[email protected]>' --in-reply-to '2026092915-making-reviving-4190@gregkh' --subject-prefix 'PATCH 6.1.y' 'HEAD^..'
Possible dependencies:
thanks,
greg k-h
------------------ original commit in Linus's tree ------------------
From 2d2a2d7aa98741b58f54cacc99b52024e4d865f9 Mon Sep 17 00:00:00 2001
From: Christian Brauner <[email protected]>
Date: Wed, 9 Sep 2026 21:30:34 +0200
Subject: [PATCH] super: make iterate_supers_type() deletion-safe
iterate_supers_type() drops sb_lock while invoking the callback and keeps only a passive reference to the current superblock. That reference keeps the object allocated, but does not keep its s_instances node linked.
After the iterator releases s_umount, final teardown can unlink the current s_instances node. The iterator then advances through a reinitialized node. With the current hlist it stops without visiting the remaining superblocks. The unlink moved from generic_shutdown_super() to kill_super_notify(), but the cursor lifetime has been unsafe since the helper was introduced.
The CIFS DFS lookup can consequently miss a matching superblock and return -EINVAL.
Move removal from fs_supers to put_super(), alongside removal from super_blocks, so a passive reference keeps both list nodes linked. Keep the filesystem module reference until then, since unlinking s_instances may touch type->fs_supers.
Make sget_fc() skip SB_DEAD superblocks before invoking test(), and set SB_DEAD under sb_lock to serialize with those callbacks. This allows kernfs to free its private information after kill_anon_super() returns. Keep matching SB_DYING superblocks until SB_DEAD is set so concurrent mounts still wait for teardown before retrying.
fs/kernfs/mount.c +2 -2
@@ -434,8 +434,8 @@ void kernfs_kill_sb(struct super_block *sb)up_write (&root->kernfs_supers_rwsem);/* -* Remove the superblock from fs_supers/s_instances -* so we can't find it, before freeing kernfs_super_info. +* Mark the superblock dead so sget_fc() can't find it, +* before freeing kernfs_super_info. */ kill_anon_super (sb);kfree (info);
fs/super.c +19 -20
@@ -433,15 +433,19 @@ static struct super_block *alloc_super(struct file_system_type *type, int flags,void put_super (struct super_block *s) {if (refcount_dec_and_test (&s->s_passive)) { +struct file_system_type *type = s->s_type;spin_lock (&sb_lock);list_del_init (&s->s_list); +hlist_del_init (&s->s_instances);spin_unlock (&sb_lock);WARN_ON (s->s_dentry_lru.node);WARN_ON (s->s_inode_lru.node);WARN_ON (s->s_mounts);call_rcu (&s->rcu, destroy_super_rcu); +/* The unlink above may touch type->fs_supers, so drop it last. */ +put_filesystem (type); } }
@@ -558,17 +562,6 @@ static void kill_super_notify(struct super_block *sb)if (sb->s_flags &SB_DEAD )return ; -/* -* Remove it from @fs_supers so it isn't found by new -* sget_fc() walkers anymore. Any concurrent mounter still -* managing to grab a temporary reference is guaranteed to -* already see SB_DYING and will wait until we notify them about -* SB_DEAD. -*/ -spin_lock (&sb_lock); -hlist_del_init (&sb->s_instances); -spin_unlock (&sb_lock); -/* Drop sget_fc()'s claim; a never-registered entry stays with the sb. */ if (sb->s_super_dev->sd_dev) {super_dev_put (sb->s_super_dev);
@@ -577,11 +570,15 @@ static void kill_super_notify(struct super_block *sb)/* * Let concurrent mounts know that this thing is really dead. -* We don't need @sb->s_umount here as every concurrent caller -* will see SB_DYING and either discard the superblock or wait -* for SB_DEAD. +* sget_fc() skips SB_DEAD superblocks and calls test() under +* sb_lock, so set it under sb_lock: once we return no test() +* runs on this superblock anymore and none will start. Everyone +* else already saw SB_DYING and either discarded the superblock +* or waits for SB_DEAD. */ +spin_lock (&sb_lock);super_wake (sb,SB_DEAD ); +spin_unlock (&sb_lock); }/**
@@ -608,7 +605,6 @@ void deactivate_locked_super(struct super_block *s)list_lru_destroy (&s->s_dentry_lru);list_lru_destroy (&s->s_inode_lru); -put_filesystem (fs);put_super (s); }else {super_unlock_excl (s);
@@ -795,12 +791,12 @@ void generic_shutdown_super(struct super_block *sb) }/* * Broadcast to everyone that grabbed a temporary reference to this -* superblock before we removed it from @fs_supers that the superblock -* is dying. Every walker of @fs_supers outside of sget_fc() will now -* discard this superblock and treat it as dead. +* superblock that it is dying. Every walker of @fs_supers outside +* of sget_fc() will now discard this superblock and treat it as +* dead. * -* We leave the superblock on @fs_supers so it can be found by -* sget_fc() until we passed sb->kill_sb(). +* sget_fc() keeps finding the superblock until SB_DEAD is set, so +* a concurrent mounter waits until we passed sb->kill_sb(). */ super_wake (sb,SB_DYING );super_unlock_excl (sb);
@@ -879,6 +875,9 @@ struct super_block *sget_fc(struct fs_context *fc,spin_lock (&sb_lock);if (test) {hlist_for_each_entry (old, &fc->fs_type->fs_supers, s_instances) { +/* Only unlinked at the last passive reference. */ +if (super_flags (old,SB_DEAD )) +continue ;if (test (old, fc)) goto share_extant_sb; }