* FAILED: patch "[PATCH] nvmet: take subsys->lock while force-reconnecting in nvmet_subsys_attr_qid_max_store()" failed to apply to 6.1-stable tree
@ 2026-11-07 10:53 Sasha Levin
2026-11-11 17:26 ` [PATCH 6.1.y 1/2] nvmet: force reconnect when number of queue changes Sasha Levin
0 siblings, 1 reply; 3+ messages in thread
From: Sasha Levin @ 2026-11-07 10:53 UTC (permalink / raw)
To: yuz08559, mlombard, kbusch; +Cc: stable
The 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 <stable@vger.kernel.org>.
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 9f426f14051181e251590783e68ce589a63e2b1c
# <resolve conflicts, build, test, etc.>
git commit -s
git send-email --to '<stable@vger.kernel.org>' --in-reply-to '20261107055312-failed-6.1-9f426f140511@kernel.org' --subject-prefix 'PATCH 6.1.y' 'HEAD^..'
Thanks,
Sasha
------------------ original commit in Linus's tree ------------------
From 9f426f14051181e251590783e68ce589a63e2b1c Mon Sep 17 00:00:00 2001
From: Yu Zhang <yuz08559@gmail.com>
Date: Tue, 20 Oct 2026 12:50:47 +1000
Subject: [PATCH] nvmet: take subsys->lock while force-reconnecting in
nvmet_subsys_attr_qid_max_store()
nvmet_subsys_attr_qid_max_store() sets subsys->max_qid and then walks
subsys->ctrls to force every controller to reconnect, but it holds only
nvmet_config_sem (for write). subsys->ctrls is protected by subsys->lock:
nvmet_alloc_ctrl() adds an entry under subsys->lock, and nvmet_ctrl_free()
removes it under subsys->lock with list_del() + kfree() (not kfree_rcu).
The free path takes no nvmet_config_sem, so the two locks are independent.
A controller teardown (host disconnect, keep-alive timeout or fatal error
-> nvmet_sq_destroy() -> nvmet_ctrl_put() -> nvmet_ctrl_free()) can
therefore list_del() an entry while qid_max_store() is iterating the list,
corrupting the walk.
KASAN, concurrent "echo 128 > .../subsystems/<nqn>/attr_qid_max" racing
nvme-loop controllers connecting and disconnecting, panics in seconds:
BUG: KASAN: null-ptr-deref in nvmet_subsys_attr_qid_max_store+0x10d/0x1b0
Read of size 8 at addr 0000000000000090
Call Trace:
nvmet_subsys_attr_qid_max_store+0x10d/0x1b0
configfs_write_iter+0x1a7/0x250
vfs_write+0x5df/0x940
ksys_write+0xfd/0x1e0
(also seen as a general-protection fault dereferencing a LIST_POISON
pointer at the same instruction.)
Take subsys->lock around the list_for_each_entry() loop, matching every
other subsys->ctrls accessor. ->delete_ctrl() only queues asynchronous
controller teardown, so it does not re-enter subsys->lock under the loop.
Fixes: 3e980f5995e0 ("nvmet: expose max queues to configfs")
Cc: stable@vger.kernel.org
Reviewed-by: Maurizio Lombardi <mlombard@redhat.com>
Signed-off-by: Yu Zhang <yuz08559@gmail.com>
Tested-by: Yu Zhang <yuz08559@gmail.com>
Signed-off-by: Keith Busch <kbusch@kernel.org>
---
drivers/nvme/target/configfs.c | 2 ++
1 file changed, 2 insertions(+)
diff --git a/drivers/nvme/target/configfs.c b/drivers/nvme/target/configfs.c
index 0b12b75c6e07e..2b085327320e2 100644
--- a/drivers/nvme/target/configfs.c
+++ b/drivers/nvme/target/configfs.c
@@ -1780,8 +1780,10 @@ static ssize_t nvmet_subsys_attr_qid_max_store(struct config_item *item,
subsys->max_qid = qid_max;
/* Force reconnect */
+ mutex_lock(&subsys->lock);
list_for_each_entry(ctrl, &subsys->ctrls, subsys_entry)
ctrl->ops->delete_ctrl(ctrl);
+ mutex_unlock(&subsys->lock);
up_write(&nvmet_config_sem);
return cnt;
--
2.53.0
^ permalink raw reply related [flat|nested] 3+ messages in thread
* [PATCH 6.1.y 1/2] nvmet: force reconnect when number of queue changes
2026-11-07 10:53 FAILED: patch "[PATCH] nvmet: take subsys->lock while force-reconnecting in nvmet_subsys_attr_qid_max_store()" failed to apply to 6.1-stable tree Sasha Levin
@ 2026-11-11 17:26 ` Sasha Levin
2026-11-11 17:26 ` [PATCH 6.1.y 2/2] nvmet: take subsys->lock while force-reconnecting in nvmet_subsys_attr_qid_max_store() Sasha Levin
0 siblings, 1 reply; 3+ messages in thread
From: Sasha Levin @ 2026-11-11 17:26 UTC (permalink / raw)
To: stable
Cc: Daniel Wagner, Chaitanya Kulkarni, Hannes Reinecke, Sagi Grimberg,
Christoph Hellwig, Sasha Levin
From: Daniel Wagner <dwagner@suse.de>
[ Upstream commit 2be2cd5287152a6284b45244b6e5c2f7e0a218bd ]
In order to test queue number changes we need to make sure that the
host reconnects. Because only when the host disconnects from the
target the number of queues are allowed to change according the spec.
The initial idea was to disable and re-enable the ports and have the
host wait until the KATO timer expires, triggering error
recovery. Though the host would see a DNR reply when trying to
reconnect. Because of the DNR bit the connection is dropped
completely. There is no point in trying to reconnect with the same
parameters according the spec.
We can force to reconnect the host is by deleting all controllers. The
host will observe any newly posted request to fail and thus starts the
error recovery but this time without the DNR bit set.
Signed-off-by: Daniel Wagner <dwagner@suse.de>
Reviewed-by: Chaitanya Kulkarni <kch@nvidia.com>
Reviewed-by: Hannes Reinecke <hare@suse.de>
Acked-by: Sagi Grimberg <sagi@grimberg.me>
Signed-off-by: Christoph Hellwig <hch@lst.de>
Stable-dep-of: 9f426f140511 ("nvmet: take subsys->lock while force-reconnecting in nvmet_subsys_attr_qid_max_store()")
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
drivers/nvme/target/configfs.c | 9 ++++++++-
1 file changed, 8 insertions(+), 1 deletion(-)
diff --git a/drivers/nvme/target/configfs.c b/drivers/nvme/target/configfs.c
index c966d1e3a1354..8c12de188e992 100644
--- a/drivers/nvme/target/configfs.c
+++ b/drivers/nvme/target/configfs.c
@@ -1318,6 +1318,8 @@ static ssize_t nvmet_subsys_attr_qid_max_show(struct config_item *item,
static ssize_t nvmet_subsys_attr_qid_max_store(struct config_item *item,
const char *page, size_t cnt)
{
+ struct nvmet_subsys *subsys = to_subsys(item);
+ struct nvmet_ctrl *ctrl;
u16 qid_max;
if (sscanf(page, "%hu\n", &qid_max) != 1)
@@ -1327,8 +1329,13 @@ static ssize_t nvmet_subsys_attr_qid_max_store(struct config_item *item,
return -EINVAL;
down_write(&nvmet_config_sem);
- to_subsys(item)->max_qid = qid_max;
+ subsys->max_qid = qid_max;
+
+ /* Force reconnect */
+ list_for_each_entry(ctrl, &subsys->ctrls, subsys_entry)
+ ctrl->ops->delete_ctrl(ctrl);
up_write(&nvmet_config_sem);
+
return cnt;
}
CONFIGFS_ATTR(nvmet_subsys_, attr_qid_max);
--
2.53.0
^ permalink raw reply related [flat|nested] 3+ messages in thread
* [PATCH 6.1.y 2/2] nvmet: take subsys->lock while force-reconnecting in nvmet_subsys_attr_qid_max_store()
2026-11-11 17:26 ` [PATCH 6.1.y 1/2] nvmet: force reconnect when number of queue changes Sasha Levin
@ 2026-11-11 17:26 ` Sasha Levin
0 siblings, 0 replies; 3+ messages in thread
From: Sasha Levin @ 2026-11-11 17:26 UTC (permalink / raw)
To: stable; +Cc: Yu Zhang, Maurizio Lombardi, Keith Busch, Sasha Levin
From: Yu Zhang <yuz08559@gmail.com>
[ Upstream commit 9f426f14051181e251590783e68ce589a63e2b1c ]
nvmet_subsys_attr_qid_max_store() sets subsys->max_qid and then walks
subsys->ctrls to force every controller to reconnect, but it holds only
nvmet_config_sem (for write). subsys->ctrls is protected by subsys->lock:
nvmet_alloc_ctrl() adds an entry under subsys->lock, and nvmet_ctrl_free()
removes it under subsys->lock with list_del() + kfree() (not kfree_rcu).
The free path takes no nvmet_config_sem, so the two locks are independent.
A controller teardown (host disconnect, keep-alive timeout or fatal error
-> nvmet_sq_destroy() -> nvmet_ctrl_put() -> nvmet_ctrl_free()) can
therefore list_del() an entry while qid_max_store() is iterating the list,
corrupting the walk.
KASAN, concurrent "echo 128 > .../subsystems/<nqn>/attr_qid_max" racing
nvme-loop controllers connecting and disconnecting, panics in seconds:
BUG: KASAN: null-ptr-deref in nvmet_subsys_attr_qid_max_store+0x10d/0x1b0
Read of size 8 at addr 0000000000000090
Call Trace:
nvmet_subsys_attr_qid_max_store+0x10d/0x1b0
configfs_write_iter+0x1a7/0x250
vfs_write+0x5df/0x940
ksys_write+0xfd/0x1e0
(also seen as a general-protection fault dereferencing a LIST_POISON
pointer at the same instruction.)
Take subsys->lock around the list_for_each_entry() loop, matching every
other subsys->ctrls accessor. ->delete_ctrl() only queues asynchronous
controller teardown, so it does not re-enter subsys->lock under the loop.
Fixes: 3e980f5995e0 ("nvmet: expose max queues to configfs")
Cc: stable@vger.kernel.org
Reviewed-by: Maurizio Lombardi <mlombard@redhat.com>
Signed-off-by: Yu Zhang <yuz08559@gmail.com>
Tested-by: Yu Zhang <yuz08559@gmail.com>
Signed-off-by: Keith Busch <kbusch@kernel.org>
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
drivers/nvme/target/configfs.c | 2 ++
1 file changed, 2 insertions(+)
diff --git a/drivers/nvme/target/configfs.c b/drivers/nvme/target/configfs.c
index 8c12de188e992..cbc3693d5fc0a 100644
--- a/drivers/nvme/target/configfs.c
+++ b/drivers/nvme/target/configfs.c
@@ -1332,8 +1332,10 @@ static ssize_t nvmet_subsys_attr_qid_max_store(struct config_item *item,
subsys->max_qid = qid_max;
/* Force reconnect */
+ mutex_lock(&subsys->lock);
list_for_each_entry(ctrl, &subsys->ctrls, subsys_entry)
ctrl->ops->delete_ctrl(ctrl);
+ mutex_unlock(&subsys->lock);
up_write(&nvmet_config_sem);
return cnt;
--
2.53.0
^ permalink raw reply related [flat|nested] 3+ messages in thread
end of thread, other threads:[~2026-11-11 17:26 UTC | newest]
Thread overview: 3+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2026-11-07 10:53 FAILED: patch "[PATCH] nvmet: take subsys->lock while force-reconnecting in nvmet_subsys_attr_qid_max_store()" failed to apply to 6.1-stable tree Sasha Levin
2026-11-11 17:26 ` [PATCH 6.1.y 1/2] nvmet: force reconnect when number of queue changes Sasha Levin
2026-11-11 17:26 ` [PATCH 6.1.y 2/2] nvmet: take subsys->lock while force-reconnecting in nvmet_subsys_attr_qid_max_store() Sasha Levin
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox