Skip to content

Commit ffe0398

Browse files
damien-lemoalChristoph Hellwig
authored andcommitted
nvmet: pci-epf: always fully initialize completion entries
For a command that is normally processed through the command request execute() function, the completion entry for the command is initialized by __nvmet_req_complete() and nvmet_pci_epf_cq_work() only needs to set the status field and the phase of the completion entry before posting the entry to the completion queue. However, for commands that are failed due to an internal error (e.g. the command data buffer allocation fails), the command request execute() function is not called and __nvmet_req_complete() is never executed for the command, leaving the command completion entry uninitialized. For such command failed before calling req->execute(), the host ends up seeing completion entries with an invalid submission queue ID and command ID. Avoid such issue by always fully initilizing a command completion entry in nvmet_pci_epf_cq_work(), setting the entry submission queue head, ID and command ID. Fixes: 0faa0fe ("nvmet: New NVMe PCI endpoint function target driver") Signed-off-by: Damien Le Moal <dlemoal@kernel.org> Reviewed-by: Niklas Cassel <cassel@kernel.org> Signed-off-by: Christoph Hellwig <hch@lst.de>
1 parent b1efcc4 commit ffe0398

File tree

1 file changed

+18
-7
lines changed

1 file changed

+18
-7
lines changed

drivers/nvme/target/pci-epf.c

Lines changed: 18 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1648,16 +1648,17 @@ static int nvmet_pci_epf_process_sq(struct nvmet_pci_epf_ctrl *ctrl,
16481648
{
16491649
struct nvmet_pci_epf_iod *iod;
16501650
int ret, n = 0;
1651+
u16 head = sq->head;
16511652

16521653
sq->tail = nvmet_pci_epf_bar_read32(ctrl, sq->db);
1653-
while (sq->head != sq->tail && (!ctrl->sq_ab || n < ctrl->sq_ab)) {
1654+
while (head != sq->tail && (!ctrl->sq_ab || n < ctrl->sq_ab)) {
16541655
iod = nvmet_pci_epf_alloc_iod(sq);
16551656
if (!iod)
16561657
break;
16571658

16581659
/* Get the NVMe command submitted by the host. */
16591660
ret = nvmet_pci_epf_transfer(ctrl, &iod->cmd,
1660-
sq->pci_addr + sq->head * sq->qes,
1661+
sq->pci_addr + head * sq->qes,
16611662
sq->qes, DMA_FROM_DEVICE);
16621663
if (ret) {
16631664
/* Not much we can do... */
@@ -1666,12 +1667,13 @@ static int nvmet_pci_epf_process_sq(struct nvmet_pci_epf_ctrl *ctrl,
16661667
}
16671668

16681669
dev_dbg(ctrl->dev, "SQ[%u]: head %u, tail %u, command %s\n",
1669-
sq->qid, sq->head, sq->tail,
1670+
sq->qid, head, sq->tail,
16701671
nvmet_pci_epf_iod_name(iod));
16711672

1672-
sq->head++;
1673-
if (sq->head == sq->depth)
1674-
sq->head = 0;
1673+
head++;
1674+
if (head == sq->depth)
1675+
head = 0;
1676+
WRITE_ONCE(sq->head, head);
16751677
n++;
16761678

16771679
queue_work_on(WORK_CPU_UNBOUND, sq->iod_wq, &iod->work);
@@ -1761,8 +1763,17 @@ static void nvmet_pci_epf_cq_work(struct work_struct *work)
17611763
if (!iod)
17621764
break;
17631765

1764-
/* Post the IOD completion entry. */
1766+
/*
1767+
* Post the IOD completion entry. If the IOD request was
1768+
* executed (req->execute() called), the CQE is already
1769+
* initialized. However, the IOD may have been failed before
1770+
* that, leaving the CQE not properly initialized. So always
1771+
* initialize it here.
1772+
*/
17651773
cqe = &iod->cqe;
1774+
cqe->sq_head = cpu_to_le16(READ_ONCE(iod->sq->head));
1775+
cqe->sq_id = cpu_to_le16(iod->sq->qid);
1776+
cqe->command_id = iod->cmd.common.command_id;
17661777
cqe->status = cpu_to_le16((iod->status << 1) | cq->phase);
17671778

17681779
dev_dbg(ctrl->dev,

0 commit comments

Comments
 (0)