Skip to content

Commit bf9b802

Browse files
damien-lemoalkeithbusch
authored andcommitted
nvmet: pci-epf: Set NVMET_PCI_EPF_Q_LIVE when a queue is fully created
The function nvmet_pci_epf_create_sq() use test_and_set_bit() to check that a submission queue is not already live and if not, set the NVMET_PCI_EPF_Q_LIVE queue flag to declare the sq live (ready to use). However, this is done on entry to the function, before the submission queue is actually fully initialized and ready to use. This creates a race situation with the function nvmet_pci_epf_poll_sqs_work() which looks at the NVMET_PCI_EPF_Q_LIVE queue flag to poll the submission queue when it is live. This race can lead to invalid DMA transfers if nvmet_pci_epf_poll_sqs_work() runs after the NVMET_PCI_EPF_Q_LIVE flag is set but before setting the sq pci address and doorbell ofset. Avoid this race by only testing the NVMET_PCI_EPF_Q_LIVE flag on entry to nvmet_pci_epf_create_sq() and setting it after the submission queue is fully setup before nvmet_pci_epf_create_sq() returns success. Since the function nvmet_pci_epf_create_cq() also has the same racy flag setting pattern, also make a similar change in that function. Fixes: 0faa0fe ("nvmet: New NVMe PCI endpoint function target driver") Signed-off-by: Damien Le Moal <dlemoal@kernel.org> Reviewed-by: Christoph Hellwig <hch@lst.de> Signed-off-by: Keith Busch <kbusch@kernel.org>
1 parent 3f674e7 commit bf9b802

File tree

1 file changed

+7
-6
lines changed

1 file changed

+7
-6
lines changed

drivers/nvme/target/pci-epf.c

Lines changed: 7 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1265,7 +1265,7 @@ static u16 nvmet_pci_epf_create_cq(struct nvmet_ctrl *tctrl,
12651265
struct nvmet_pci_epf_queue *cq = &ctrl->cq[cqid];
12661266
u16 status;
12671267

1268-
if (test_and_set_bit(NVMET_PCI_EPF_Q_LIVE, &cq->flags))
1268+
if (test_bit(NVMET_PCI_EPF_Q_LIVE, &cq->flags))
12691269
return NVME_SC_QID_INVALID | NVME_STATUS_DNR;
12701270

12711271
if (!(flags & NVME_QUEUE_PHYS_CONTIG))
@@ -1300,14 +1300,15 @@ static u16 nvmet_pci_epf_create_cq(struct nvmet_ctrl *tctrl,
13001300
if (status != NVME_SC_SUCCESS)
13011301
goto err;
13021302

1303+
set_bit(NVMET_PCI_EPF_Q_LIVE, &cq->flags);
1304+
13031305
dev_dbg(ctrl->dev, "CQ[%u]: %u entries of %zu B, IRQ vector %u\n",
13041306
cqid, qsize, cq->qes, cq->vector);
13051307

13061308
return NVME_SC_SUCCESS;
13071309

13081310
err:
13091311
clear_bit(NVMET_PCI_EPF_Q_IRQ_ENABLED, &cq->flags);
1310-
clear_bit(NVMET_PCI_EPF_Q_LIVE, &cq->flags);
13111312
return status;
13121313
}
13131314

@@ -1333,7 +1334,7 @@ static u16 nvmet_pci_epf_create_sq(struct nvmet_ctrl *tctrl,
13331334
struct nvmet_pci_epf_queue *sq = &ctrl->sq[sqid];
13341335
u16 status;
13351336

1336-
if (test_and_set_bit(NVMET_PCI_EPF_Q_LIVE, &sq->flags))
1337+
if (test_bit(NVMET_PCI_EPF_Q_LIVE, &sq->flags))
13371338
return NVME_SC_QID_INVALID | NVME_STATUS_DNR;
13381339

13391340
if (!(flags & NVME_QUEUE_PHYS_CONTIG))
@@ -1355,7 +1356,7 @@ static u16 nvmet_pci_epf_create_sq(struct nvmet_ctrl *tctrl,
13551356

13561357
status = nvmet_sq_create(tctrl, &sq->nvme_sq, sqid, sq->depth);
13571358
if (status != NVME_SC_SUCCESS)
1358-
goto out_clear_bit;
1359+
return status;
13591360

13601361
sq->iod_wq = alloc_workqueue("sq%d_wq", WQ_UNBOUND,
13611362
min_t(int, sq->depth, WQ_MAX_ACTIVE), sqid);
@@ -1365,15 +1366,15 @@ static u16 nvmet_pci_epf_create_sq(struct nvmet_ctrl *tctrl,
13651366
goto out_destroy_sq;
13661367
}
13671368

1369+
set_bit(NVMET_PCI_EPF_Q_LIVE, &sq->flags);
1370+
13681371
dev_dbg(ctrl->dev, "SQ[%u]: %u entries of %zu B\n",
13691372
sqid, qsize, sq->qes);
13701373

13711374
return NVME_SC_SUCCESS;
13721375

13731376
out_destroy_sq:
13741377
nvmet_sq_destroy(&sq->nvme_sq);
1375-
out_clear_bit:
1376-
clear_bit(NVMET_PCI_EPF_Q_LIVE, &sq->flags);
13771378
return status;
13781379
}
13791380

0 commit comments

Comments
 (0)