Re: [PATCH 1/5] nvme-tcp: initialize pf_cache_lock when allocating the controller

From: Saravanan D

Date: Sat Oct 17 2026 - 17:37:41 EST


On Wed, Oct 14, 2026 at 09:46:39AM +0200, Daniel Wagner wrote:
> Since commit 61b0ed3be81b ("nvme-tcp: parallelize I/O queue allocation
> and startup") the I/O tag set is allocated before the I/O queues.
> blk_mq_alloc_tag_set calls nvme_tcp_init_request for every request,
> which takes pf_cache_lock of the request's queue, but nvme_tcp_alloc_queue
> initializes that mutex only later. With CONFIG_DEBUG_MUTEXES the first
> connect triggers DEBUG_LOCKS_WARN_ON(lock->magic != lock) in
> __mutex_lock and lock debugging is disabled.

I hit the same warning on nvme-7.4, and also a second path to it, a
reconnect that grows the queue count. Every teardown frees the I/O
queues, and nvme_tcp_free_queue() destroys their pf_cache_lock. When
a reconnect raises the queue count, blk_mq_update_nr_hw_queues()
initializes the requests of the added hardware contexts, and with them
takes pf_cache_lock of their queues, before nvme_tcp_setup_io_queues()
allocates those queues.

shrink, 4 -> 3 queues
nvme_tcp_free_queue(4) mutex_destroy(q4 pf_cache_lock)
grow, 3 -> 4 queues
blk_mq_update_nr_hw_queues()
nvme_tcp_init_request() mutex_lock(q4 pf_cache_lock) <- WARN
nvme_tcp_setup_io_queues()
nvme_tcp_alloc_queue(4) mutex_init(q4 pf_cache_lock)

WARNING: kernel/locking/mutex.c:625 at __mutex_lock+0x434/0x117c
Call trace:
__mutex_lock+0x434/0x117c (P)
mutex_lock_nested+0x24/0x30
nvme_tcp_init_request+0xb0/0x260
blk_mq_alloc_map_and_rqs+0x388/0x670
blk_mq_update_nr_hw_queues+0xb30/0x1058
nvme_tcp_setup_ctrl+0xa9c/0xda4
nvme_tcp_reconnect_ctrl_work+0x70/0x2d8
process_one_work+0x7a0/0x1b5c

Dropping the mutex_destroy() from nvme_tcp_free_queue(), as this patch
does, fixes that path too. It may be worth mentioning this fact in the
changelog.

Tested against nvmet-tcp over loopback with lockdep, KASAN and
DEBUG_KOBJECT_RELEASE, covering connect, reset loops under I/O,
shrinking and growing the queue count through attr_qid_max, and
reconnects while the port is removed.

Tested-by: Saravanan D <saravanand@xxxxxxxxx>

Thanks,
Saravanan D.