[PATCH] nvme: tcp: avoid race between lock and destroy of queue_lock
Shinichiro Kawasaki
shinichiro.kawasaki at wdc.com
Thu Sep 12 06:28:35 PDT 2024
On Sep 12, 2024 / 13:20, Sagi Grimberg wrote:
>
>
>
> On 12/09/2024 12:16, Hannes Reinecke wrote:
> > On 9/12/24 08:59, Sagi Grimberg wrote:
> > >
> > >
> > >
> > > On 12/09/2024 9:27, Shin'ichiro Kawasaki wrote:
[...]
> > >
> > > This is really not needed.. You can already serialize with:
> > > --
> > > diff --git a/drivers/nvme/host/tcp.c b/drivers/nvme/host/tcp.c
> > > index a2a47d3ab99f..91c19d06cae9 100644
> > > --- a/drivers/nvme/host/tcp.c
> > > +++ b/drivers/nvme/host/tcp.c
> > > @@ -1365,6 +1365,10 @@ static void nvme_tcp_free_queue(struct
> > > nvme_ctrl *nctrl, int qid)
> > > if (!test_and_clear_bit(NVME_TCP_Q_ALLOCATED, &queue->flags))
> > > return;
> > >
> > > + /* make sure any concurrent .get_address completes */
> > > + mutex_lock(&queue->queue_lock);
> > > + mutex_unlock(&queue->queue_lock);
> > > +
> > > if (queue->hdr_digest || queue->data_digest)
> > > nvme_tcp_free_crypto(queue);
I applied this change above only on top of the kernel v6.11-rc7. Unfortunately,
the WARN was still observed.
> >
> > Wouldn't it be sufficient to check for NVME_TCP_Q_LIVE outside of the
> > mutex?
>
> I think its intentional, so this serializes against nvme_tcp_stop_queue()
IIUC, NVME_TCP_Q_LIVE in the mutex region is required in nvme_tcp_free_queue(),
and we can not simply move it out of the region.
As a similar idea, I can think of doing the NVME_TCP_Q_LIVE check both in and
out of the mutex region. The change below does it by adding the check out of the
region:
diff --git a/drivers/nvme/host/tcp.c b/drivers/nvme/host/tcp.c
index a2a47d3ab99f..ba91f98e90f7 100644
--- a/drivers/nvme/host/tcp.c
+++ b/drivers/nvme/host/tcp.c
@@ -2617,6 +2617,9 @@ static int nvme_tcp_get_address(struct nvme_ctrl *ctrl, char *buf, int size)
len = nvmf_get_address(ctrl, buf, size);
+ if (!test_bit(NVME_TCP_Q_LIVE, &queue->flags))
+ return len;
+
mutex_lock(&queue->queue_lock);
if (!test_bit(NVME_TCP_Q_LIVE, &queue->flags))
With this change, I repeated the test case 400 times and the WARN was not
observed. Good, this fix might be enough.
Actually, once I had tried the similar fix using the NMVE_TCP_Q_ALLOCATED
flag instead of nvme_TCP_Q_LIVE. In that case, the WARN had not been observed
during the 400 times repeat. Both showed good result, but as Hannes noted, I
agree that the check by NVME_TCP_Q_LIVE is the better because NVME_TCP_Q_LIVE
is cleared earlier than NVME_TCP_Q_ALLOCATED, and there will be less chance the
queue_lock gets destroyed before the mutex_lock().
Having said that, I still think there is a very tiny possibility that the
queue_lock gets destroyed between the NVME_TCP_Q_LIVE flag check and the
mutex_lock(). That is why I suggested the new flag NVME_TCP_Q_REFERRED.
Am I overthinking?
More information about the Linux-nvme
mailing list