[PATCH] nvmet-tcp: avoid circular locking dependency on install_queue()

Sagi Grimberg sagi at grimberg.me
Thu Aug 17 04:20:41 PDT 2023


>> On 8/10/23 16:20, Hannes Reinecke wrote:
>>> nvmet_tcp_install_queue() is driven from the ->io_work workqueue
>>> function, but will call flush_workqueue() which might trigger
>>> ->release_work() which in itself calls flush_work on ->io_work.
>>>
>>> To avoid that check for pending queue in disconnecting status,
>>> and return 'controller busy' until all disconnects are completed.
>>>
>>> Signed-off-by: Hannes Reinecke <hare at suse.de>
>>> ---
>>>   drivers/nvme/target/tcp.c | 14 ++++++++++++--
>>>   1 file changed, 12 insertions(+), 2 deletions(-)
>>>
>>> diff --git a/drivers/nvme/target/tcp.c b/drivers/nvme/target/tcp.c
>>> index f131b504aa01..97d07488072d 100644
>>> --- a/drivers/nvme/target/tcp.c
>>> +++ b/drivers/nvme/target/tcp.c
>>> @@ -1845,8 +1845,18 @@ static u16 nvmet_tcp_install_queue(struct 
>>> nvmet_sq *sq)
>>>           container_of(sq, struct nvmet_tcp_queue, nvme_sq);
>>>       if (sq->qid == 0) {
>>> -        /* Let inflight controller teardown complete */
>>> -        flush_workqueue(nvmet_wq);
>>> +        struct nvmet_tcp_queue *q;
>>> +        int pending = 0;
>>> +
>>> +        mutex_lock(&nvmet_tcp_queue_mutex);
>>> +        list_for_each_entry(q, &nvmet_tcp_queue_list, queue_list) {
>>> +            if (q->state == NVMET_TCP_Q_DISCONNECTING)
>>> +                pending++;
>>> +        }
>>> +        mutex_unlock(&nvmet_tcp_queue_mutex);
>>> +        /* Retry for pending controller teardown */
>>> +        if (pending)
>>> +            return NVME_SC_CONNECT_CTRL_BUSY;
>>
>> Overall I'm fine with the approach.
>>
>> That will most likely be the case for a controller reset or a "reset
>> storm". Maybe it is better to keep it at some reasonably allowed pending
>> to say 10 or something... The whole point is to not let the removals
>> accumulate and continue creating new ones...
>>
>> Can you please test this with a host that does a loop like:
>> while true; do nvme reset /dev/nvme0; done
>>
>> And let it run for some time...
>> Or even better create a test that does this for 100 iterations
>> or a log/short variants of this?
>>
>> The same would be needed by nvmet-rdma btw.
> 
> Retested with the reset loop; no issues found after 327 iterations.

Interesting, did the host see a NVME_SC_CONNECT_CTRL_BUSY  during the
test?



More information about the Linux-nvme mailing list