[LTP] [PATCH v3] testcases/kernel/device-drivers/nvme: Add NVMe device discovery test
Daniel Wagner
dwagner@suse.de
Tue May 5 10:45:16 CEST 2026
Adding Shin'ichiro
On 5/5/26 5:46 AM, Sebastian Chlad wrote:
> Hi Priyama,
>
> Sorry for top-posting, but I have a broader question here.
>
> First of all, thanks for working on this and for looking into NVMe coverage.
>
> Before going further, could you please explain the intended LTP-specific
> value of
> this test? blktests already has a dedicated NVMe test group with much
> broader
> coverage, including controller/namespace discovery, NVMe commands,
> fabrics, etc.:
>
> https://github.com/linux-blktests/blktests/tree/master/tests/nvme
> <https://github.com/linux-blktests/blktests/tree/master/tests/nvme>
>
> So I think we should be careful not to duplicate coverage unless there
> is a clear
> reason for having a small LTP-level smoke test as well. Maybe your
> intention is
> different? Could you please clarify?
>
> Cheers,
> Sebastian
>
> On Thu, 30 Apr 2026 at 07:10, <priyama2@linux.ibm.com
> <mailto:priyama2@linux.ibm.com>> wrote:
>
> From: priyama2 <priyama2@linux.ibm.com <mailto:priyama2@linux.ibm.com>>
>
> This test fills a gap in NVMe test coverage by validating basic device
> enumeration and driver binding, which are fundamental prerequisites for
> any NVMe functionality testing.
>
> The test verifies:
> - Detection of NVMe controllers in /dev
> - Enumeration of namespaces for detected controllers
> - PCI enumeration (class code 0x010802)
> - NVMe driver binding
>
> Changes in v3:
> - Fix subject prefix to match directory path
> - Update copyright year to 2026
> - Add nvme to SUBDIRS in testcases/kernel/device-drivers/Makefile
> - Reset static variables at start of run() for -i support
> - Remove .needs_root (all operations are world-readable)
> - Use SAFE_FOPEN/SAFE_FCLOSE for PCI class file access
> - Use SAFE_READLINK for driver symlink reading
> - Add .gitignore entry for nvme01 binary
> - Add runtest/device-drivers entry for nvme01
> - Fix author field to use priyama2
>
> Changes in v2:
> - Use LTP buildsystem instead of standalone Makefile
> - Remove README file (use doc comments instead)
> - Add proper LTP documentation comment format
> - Use SAFE_OPENDIR() and SAFE_CLOSEDIR() macros
> - Remove obvious and redundant comments
> - Code cleanup and style improvements
>
> Signed-off-by: priyama2 <priyama2@linux.ibm.com
> <mailto:priyama2@linux.ibm.com>>
> ---
> runtest/device-drivers | 1 +
> testcases/kernel/device-drivers/Makefile | 1 +
> .../kernel/device-drivers/nvme/.gitignore | 1 +
> testcases/kernel/device-drivers/nvme/Makefile | 7 +
> testcases/kernel/device-drivers/nvme/nvme01.c | 205 ++++++++++++++++++
> 5 files changed, 215 insertions(+)
> create mode 100644 runtest/device-drivers
> create mode 100644 testcases/kernel/device-drivers/nvme/.gitignore
> create mode 100644 testcases/kernel/device-drivers/nvme/Makefile
> create mode 100644 testcases/kernel/device-drivers/nvme/nvme01.c
>
> diff --git a/runtest/device-drivers b/runtest/device-drivers
> new file mode 100644
> index 000000000..a7295584e
> --- /dev/null
> +++ b/runtest/device-drivers
> @@ -0,0 +1 @@
> +nvme01 nvme01
> diff --git a/testcases/kernel/device-drivers/Makefile b/testcases/
> kernel/device-drivers/Makefile
> index 229a50683..664f4cd18 100644
> --- a/testcases/kernel/device-drivers/Makefile
> +++ b/testcases/kernel/device-drivers/Makefile
> @@ -9,6 +9,7 @@ SUBDIRS := acpi \
> block \
> cpufreq \
> locking \
> + nvme \
> pci \
> rcu \
> rtc \
> diff --git a/testcases/kernel/device-drivers/nvme/.gitignore b/
> testcases/kernel/device-drivers/nvme/.gitignore
> new file mode 100644
> index 000000000..c60bc210c
> --- /dev/null
> +++ b/testcases/kernel/device-drivers/nvme/.gitignore
> @@ -0,0 +1 @@
> +nvme01
> diff --git a/testcases/kernel/device-drivers/nvme/Makefile b/
> testcases/kernel/device-drivers/nvme/Makefile
> new file mode 100644
> index 000000000..d47e99e6a
> --- /dev/null
> +++ b/testcases/kernel/device-drivers/nvme/Makefile
> @@ -0,0 +1,7 @@
> +# SPDX-License-Identifier: GPL-2.0-or-later
> +# Copyright (c) 2024 IBM Corporation
> +
> +top_srcdir ?= ../../../..
> +
> +include $(top_srcdir)/include/mk/env_pre.mk <http://env_pre.mk>
> +include $(top_srcdir)/include/mk/generic_trunk_target.mk <http://
> generic_trunk_target.mk>
> diff --git a/testcases/kernel/device-drivers/nvme/nvme01.c b/
> testcases/kernel/device-drivers/nvme/nvme01.c
> new file mode 100644
> index 000000000..3c3cb92ce
> --- /dev/null
> +++ b/testcases/kernel/device-drivers/nvme/nvme01.c
> @@ -0,0 +1,205 @@
> +// SPDX-License-Identifier: GPL-2.0-or-later
> +/*
> + * Copyright (c) 2026 IBM Corporation
> + * Author: priyama2 <priyama2@linux.ibm.com
> <mailto:priyama2@linux.ibm.com>>
> + */
> +
> +/* * [Description]
> + *
> + * Verify NVMe device discovery and identification.
> + *
> + * This test fills a gap in NVMe test coverage by validating basic
> device
> + * enumeration and driver binding, which are fundamental
> prerequisites for
> + * any NVMe functionality testing.
> + *
> + * - Detect NVMe controllers in /dev
> + * - Enumerate namespaces for detected controllers
> + * - Verify PCI enumeration (class code 0x010802)
> + * - Check NVMe driver binding
> + */
> +
> +#define _GNU_SOURCE
> +#include <stdio.h>
> +#include <stdlib.h>
> +#include <string.h>
> +#include <unistd.h>
> +#include <fcntl.h>
> +#include <sys/types.h>
> +#include <sys/stat.h>
> +#include <dirent.h>
> +#include <errno.h>
> +
> +#include "tst_test.h"
> +#include "tst_safe_stdio.h"
> +
> +#define NVME_DEV_PATH "/dev"
> +#define NVME_SYS_PATH "/sys/class/nvme"
> +#define PCI_DEVICES_PATH "/sys/bus/pci/devices"
> +
> +static int nvme_device_found;
> +static char nvme_dev_name[256];
> +
> +static void test_detect_nvme_controllers(void)
> +{
> + DIR *dir;
> + struct dirent *entry;
> + int found = 0;
> +
> + dir = SAFE_OPENDIR(NVME_DEV_PATH);
> +
> + tst_res(TINFO, "Scanning for NVMe devices in %s",
> NVME_DEV_PATH);
> +
> + while ((entry = readdir(dir)) != NULL) {
> + if (strncmp(entry->d_name, "nvme", 4) == 0 &&
> + strlen(entry->d_name) == 5) {
> + tst_res(TINFO, "Found NVMe controller: %s",
> entry->d_name);
> + strncpy(nvme_dev_name, entry->d_name,
> sizeof(nvme_dev_name) - 1);
> + found = 1;
> + nvme_device_found = 1;
> + }
> + }
> +
> + SAFE_CLOSEDIR(dir);
> +
> + if (found)
> + tst_res(TPASS, "NVMe controller(s) detected
> successfully");
> + else
> + tst_res(TCONF, "No NVMe controllers found in system");
> +}
> +
> +static void test_enumerate_namespaces(void)
> +{
> + DIR *dir;
> + struct dirent *entry;
> + int ns_count = 0;
> + char search_pattern[32];
> +
> + if (!nvme_device_found) {
> + tst_res(TCONF, "No NVMe device found, skipping
> namespace enumeration");
> + return;
> + }
> +
> + snprintf(search_pattern, sizeof(search_pattern), "%sn",
> nvme_dev_name);
> +
> + dir = SAFE_OPENDIR(NVME_DEV_PATH);
> +
> + tst_res(TINFO, "Enumerating namespaces for %s", nvme_dev_name);
> +
> + while ((entry = readdir(dir)) != NULL) {
> + if (strncmp(entry->d_name, search_pattern,
> strlen(search_pattern)) == 0) {
> + tst_res(TINFO, "Found namespace: %s", entry-
> >d_name);
> + ns_count++;
> + }
> + }
> +
> + SAFE_CLOSEDIR(dir);
> +
> + if (ns_count > 0)
> + tst_res(TPASS, "Enumerated %d namespace(s)
> successfully", ns_count);
> + else
> + tst_res(TPASS, "No namespaces found for %s (device
> may not have namespaces configured)", nvme_dev_name);
> +}
> +
> +static void test_verify_pci_enumeration(void)
> +{
> + DIR *dir;
> + struct dirent *entry;
> + int found = 0;
> + char class_path[512];
> + FILE *fp;
> + char class_id[16];
> +
> + if (!nvme_device_found) {
> + tst_res(TCONF, "No NVMe device found, skipping PCI
> enumeration check");
> + return;
> + }
> +
> + dir = SAFE_OPENDIR(PCI_DEVICES_PATH);
> +
> + tst_res(TINFO, "Checking PCI enumeration for NVMe devices");
> +
> + while ((entry = readdir(dir)) != NULL) {
> + if (entry->d_name[0] == '.')
> + continue;
> +
> + snprintf(class_path, sizeof(class_path), "%s/%s/class",
> + PCI_DEVICES_PATH, entry->d_name);
> +
> + fp = SAFE_FOPEN(class_path, "r");
> +
> + if (fgets(class_id, sizeof(class_id), fp)) {
> + if (strncmp(class_id, "0x010802", 8) == 0) {
> + tst_res(TINFO, "Found NVMe PCI
> device: %s (class: %s)",
> + entry->d_name, class_id);
> + found = 1;
> + }
> + }
> + SAFE_FCLOSE(fp);
> + }
> +
> + SAFE_CLOSEDIR(dir);
> +
> + if (found)
> + tst_res(TPASS, "NVMe device properly enumerated on
> PCI bus");
> + else
> + tst_res(TFAIL, "NVMe device not found on PCI bus");
> +}
> +
> +static void test_check_driver_binding(void)
> +{
> + char driver_path[512];
> + char driver_link[512];
> +
> + if (!nvme_device_found) {
> + tst_res(TCONF, "No NVMe device found, skipping
> driver binding check");
> + return;
> + }
> +
> + snprintf(driver_path, sizeof(driver_path), "%s/%s/device/
> driver",
> + NVME_SYS_PATH, nvme_dev_name);
> +
> + SAFE_READLINK(driver_path, driver_link, sizeof(driver_link));
> +
> + tst_res(TINFO, "Driver binding: %s", driver_link);
> +
> + if (strstr(driver_link, "nvme") != NULL)
> + tst_res(TPASS, "NVMe driver properly bound to device");
> + else
> + tst_res(TFAIL, "Unexpected driver bound to NVMe
> device: %s", driver_link);
> +}
> +
> +static void setup(void)
> +{
> + if (access("/sys/module/nvme", F_OK) != 0)
> + tst_brk(TCONF, "NVMe kernel module not loaded");
> +
> + tst_res(TINFO, "NVMe Device Discovery & Identification Test");
> +}
> +
> +static void run(unsigned int n)
> +{
> + /* Reset state for each iteration */
> + nvme_device_found = 0;
> + memset(nvme_dev_name, 0, sizeof(nvme_dev_name));
> +
> + switch (n) {
> + case 0:
> + test_detect_nvme_controllers();
> + break;
> + case 1:
> + test_enumerate_namespaces();
> + break;
> + case 2:
> + test_verify_pci_enumeration();
> + break;
> + case 3:
> + test_check_driver_binding();
> + break;
> + }
> +}
> +
> +static struct tst_test test = {
> + .test = run,
> + .tcnt = 4,
> + .setup = setup,
> +};
> --
> 2.52.0
>
>
> --
> Mailing list info: https://lists.linux.it/listinfo/ltp <https://
> lists.linux.it/listinfo/ltp>
>
More information about the ltp
mailing list