From: Michael Bommarito <michael.bommarito@gmail.com>
To: Christoph Hellwig <hch@lst.de>, Sagi Grimberg <sagi@grimberg.me>,
Chaitanya Kulkarni <kch@nvidia.com>
Cc: kwilczynski@kernel.org, Damien Le Moal <dlemoal@kernel.org>,
Manivannan Sadhasivam <mani@kernel.org>,
Keith Busch <kbusch@kernel.org>,
linux-nvme@lists.infradead.org, linux-kernel@vger.kernel.org,
stable@vger.kernel.org
Subject: [PATCH 2/2] nvmet-pci: add KUnit coverage for endpoint queue IDs
Date: Thu, 9 Jul 2026 22:30:15 -0400 [thread overview]
Message-ID: <20260710023015.3744082-3-michael.bommarito@gmail.com> (raw)
In-Reply-To: <20260710023015.3744082-1-michael.bommarito@gmail.com>
Add KUnit coverage for the PCI endpoint target queue-id boundary. The tests
model the case where target-core max_qid is larger than the endpoint
transport's ctrl->nr_queues, confirm the common qid check accepts the
malformed id, and verify the endpoint callbacks reject out-of-range
Create/Delete SQ/CQ requests before indexing transport-private arrays.
This covers the regression fixed by the preceding patch.
Assisted-by: Codex:gpt-5-5-xhigh
Signed-off-by: Michael Bommarito <michael.bommarito@gmail.com>
---
drivers/nvme/target/Kconfig | 11 ++++
drivers/nvme/target/pci-epf.c | 120 ++++++++++++++++++++++++++++++++++
2 files changed, 131 insertions(+)
diff --git a/drivers/nvme/target/Kconfig b/drivers/nvme/target/Kconfig
index 4904097dfd490..ea64bbe9882c5 100644
--- a/drivers/nvme/target/Kconfig
+++ b/drivers/nvme/target/Kconfig
@@ -127,3 +127,14 @@ config NVME_TARGET_PCI_EPF
capable PCI controller.
If unsure, say N.
+
+config NVMET_PCI_EPF_KUNIT_TEST
+ bool "NVMe PCI endpoint target KUnit tests" if !KUNIT_ALL_TESTS
+ depends on KUNIT
+ depends on NVME_TARGET_PCI_EPF=y
+ default KUNIT_ALL_TESTS
+ help
+ KUnit tests for the NVMe PCI endpoint target transport.
+ These tests exercise transport-private queue ID checks for
+ Create/Delete SQ/CQ commands when target-core max_qid is larger than
+ the endpoint controller's available queue arrays.
diff --git a/drivers/nvme/target/pci-epf.c b/drivers/nvme/target/pci-epf.c
index 5bddda09c0538..e2eb96f32fab5 100644
--- a/drivers/nvme/target/pci-epf.c
+++ b/drivers/nvme/target/pci-epf.c
@@ -20,6 +20,9 @@
#include <linux/pci-epf.h>
#include <linux/pci_regs.h>
#include <linux/slab.h>
+#if IS_ENABLED(CONFIG_NVMET_PCI_EPF_KUNIT_TEST)
+#include <kunit/test.h>
+#endif
#include "nvmet.h"
@@ -2667,3 +2670,120 @@ module_exit(nvmet_pci_epf_cleanup_module);
MODULE_DESCRIPTION("NVMe PCI Endpoint Function target driver");
MODULE_AUTHOR("Damien Le Moal <dlemoal@kernel.org>");
MODULE_LICENSE("GPL");
+
+#if IS_ENABLED(CONFIG_NVMET_PCI_EPF_KUNIT_TEST)
+
+struct nvmet_pci_epf_kunit_ctx {
+ struct nvmet_ctrl tctrl;
+ struct nvmet_subsys subsys;
+ struct nvmet_pci_epf_ctrl ctrl;
+ struct nvmet_pci_epf nvme_epf;
+};
+
+static int nvmet_pci_epf_kunit_init(struct kunit *test)
+{
+ struct nvmet_pci_epf_kunit_ctx *ctx;
+ unsigned int qid;
+
+ ctx = kunit_kzalloc(test, sizeof(*ctx), GFP_KERNEL);
+ KUNIT_ASSERT_NOT_NULL(test, ctx);
+
+ ctx->subsys.max_qid = 8;
+ ctx->tctrl.subsys = &ctx->subsys;
+ ctx->tctrl.drvdata = &ctx->ctrl;
+ ctx->tctrl.cqs = kunit_kcalloc(test, ctx->subsys.max_qid + 1,
+ sizeof(*ctx->tctrl.cqs), GFP_KERNEL);
+ KUNIT_ASSERT_NOT_NULL(test, ctx->tctrl.cqs);
+ ctx->tctrl.sqs = kunit_kcalloc(test, ctx->subsys.max_qid + 1,
+ sizeof(*ctx->tctrl.sqs), GFP_KERNEL);
+ KUNIT_ASSERT_NOT_NULL(test, ctx->tctrl.sqs);
+
+ ctx->ctrl.nr_queues = 2;
+ ctx->ctrl.tctrl = &ctx->tctrl;
+ ctx->ctrl.nvme_epf = &ctx->nvme_epf;
+ ctx->ctrl.sq = kunit_kcalloc(test, ctx->ctrl.nr_queues,
+ sizeof(*ctx->ctrl.sq), GFP_KERNEL);
+ KUNIT_ASSERT_NOT_NULL(test, ctx->ctrl.sq);
+ ctx->ctrl.cq = kunit_kcalloc(test, ctx->ctrl.nr_queues,
+ sizeof(*ctx->ctrl.cq), GFP_KERNEL);
+ KUNIT_ASSERT_NOT_NULL(test, ctx->ctrl.cq);
+
+ for (qid = 0; qid < ctx->ctrl.nr_queues; qid++) {
+ nvmet_pci_epf_init_queue(&ctx->ctrl, qid, true);
+ nvmet_pci_epf_init_queue(&ctx->ctrl, qid, false);
+ }
+
+ test->priv = ctx;
+ return 0;
+}
+
+static void nvmet_pci_epf_qid_control_test(struct kunit *test)
+{
+ struct nvmet_pci_epf_kunit_ctx *ctx = test->priv;
+ u16 status;
+
+ status = nvmet_check_io_cqid(&ctx->tctrl, 1, true);
+ KUNIT_EXPECT_EQ(test, status, (u16)NVME_SC_SUCCESS);
+
+ status = nvmet_pci_epf_create_cq(&ctx->tctrl, 1, 0, 1, 0, 0);
+ KUNIT_EXPECT_EQ(test, status,
+ (u16)(NVME_SC_INVALID_QUEUE | NVME_STATUS_DNR));
+}
+
+static void nvmet_pci_epf_qid_oob_test(struct kunit *test)
+{
+ struct nvmet_pci_epf_kunit_ctx *ctx = test->priv;
+ u16 bad_qid = ctx->ctrl.nr_queues;
+ u16 status;
+
+ status = nvmet_check_io_cqid(&ctx->tctrl, bad_qid, true);
+ KUNIT_EXPECT_EQ(test, status, (u16)NVME_SC_SUCCESS);
+
+ status = nvmet_pci_epf_create_cq(&ctx->tctrl, bad_qid, 0, 1, 0, 0);
+ KUNIT_EXPECT_EQ(test, status,
+ (u16)(NVME_SC_QID_INVALID | NVME_STATUS_DNR));
+}
+
+static void nvmet_pci_epf_qid_reject_all_test(struct kunit *test)
+{
+ struct nvmet_pci_epf_kunit_ctx *ctx = test->priv;
+ u16 bad_qid = ctx->ctrl.nr_queues;
+ u16 status;
+
+ status = nvmet_pci_epf_create_cq(&ctx->tctrl, bad_qid, 0, 1, 0, 0);
+ KUNIT_EXPECT_EQ(test, status,
+ (u16)(NVME_SC_QID_INVALID | NVME_STATUS_DNR));
+
+ status = nvmet_pci_epf_create_sq(&ctx->tctrl, bad_qid, 1, 0, 1, 0);
+ KUNIT_EXPECT_EQ(test, status,
+ (u16)(NVME_SC_QID_INVALID | NVME_STATUS_DNR));
+
+ status = nvmet_pci_epf_create_sq(&ctx->tctrl, 1, bad_qid, 0, 1, 0);
+ KUNIT_EXPECT_EQ(test, status,
+ (u16)(NVME_SC_QID_INVALID | NVME_STATUS_DNR));
+
+ status = nvmet_pci_epf_delete_cq(&ctx->tctrl, bad_qid);
+ KUNIT_EXPECT_EQ(test, status,
+ (u16)(NVME_SC_QID_INVALID | NVME_STATUS_DNR));
+
+ status = nvmet_pci_epf_delete_sq(&ctx->tctrl, bad_qid);
+ KUNIT_EXPECT_EQ(test, status,
+ (u16)(NVME_SC_QID_INVALID | NVME_STATUS_DNR));
+}
+
+static struct kunit_case nvmet_pci_epf_qid_test_cases[] = {
+ KUNIT_CASE(nvmet_pci_epf_qid_control_test),
+ KUNIT_CASE(nvmet_pci_epf_qid_oob_test),
+ KUNIT_CASE(nvmet_pci_epf_qid_reject_all_test),
+ {}
+};
+
+static struct kunit_suite nvmet_pci_epf_qid_test_suite = {
+ .name = "nvmet_pci_epf_qid",
+ .init = nvmet_pci_epf_kunit_init,
+ .test_cases = nvmet_pci_epf_qid_test_cases,
+};
+
+kunit_test_suite(nvmet_pci_epf_qid_test_suite);
+
+#endif
--
2.53.0
next prev parent reply other threads:[~2026-07-10 2:30 UTC|newest]
Thread overview: 5+ messages / expand[flat|nested] mbox.gz Atom feed top
2026-07-10 2:30 [PATCH 0/2] nvmet-pci: validate endpoint queue IDs Michael Bommarito
2026-07-10 2:30 ` [PATCH 1/2] nvmet-pci: validate queue IDs against endpoint queues Michael Bommarito
2026-07-10 3:27 ` Damien Le Moal
2026-07-10 2:30 ` Michael Bommarito [this message]
2026-07-10 3:29 ` [PATCH 2/2] nvmet-pci: add KUnit coverage for endpoint queue IDs Damien Le Moal
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20260710023015.3744082-3-michael.bommarito@gmail.com \
--to=michael.bommarito@gmail.com \
--cc=dlemoal@kernel.org \
--cc=hch@lst.de \
--cc=kbusch@kernel.org \
--cc=kch@nvidia.com \
--cc=kwilczynski@kernel.org \
--cc=linux-kernel@vger.kernel.org \
--cc=linux-nvme@lists.infradead.org \
--cc=mani@kernel.org \
--cc=sagi@grimberg.me \
--cc=stable@vger.kernel.org \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox