[LTP] [PATCH] testcases/nvme: Add NVMe device discovery and identification test

priyama2 priyama2@linux.ibm.com
Wed Apr 29 12:51:14 CEST 2026


This patch introduces the first test case (nvme01) for NVMe device
testing in LTP. The test verifies:

- Detection of NVMe controllers in the system
- Enumeration of NVMe namespaces
- PCI bus enumeration verification
- Driver binding validation

The test uses the LTP test framework (tst_test.h) and follows LTP
coding standards. It provides comprehensive coverage for basic NVMe
device discovery functionality.

Tested on:
- System: ppc64le, RHEL 10.2
- Kernel: 6.12.0-210.el10.ppc64le
- Hardware: Samsung PM1735a NVMe devices
- Result: All 4 test cases passed

This is the first in a series of patches to add comprehensive NVMe
testing support to LTP.

Signed-off-by: priyama2 <priyama2@linux.ibm.com>
---
 testcases/kernel/device-drivers/nvme/Makefile |  42 ++++
 testcases/kernel/device-drivers/nvme/README   | 155 ++++++++++++
 testcases/kernel/device-drivers/nvme/nvme01.c | 236 ++++++++++++++++++
 3 files changed, 433 insertions(+)
 create mode 100644 testcases/kernel/device-drivers/nvme/Makefile
 create mode 100644 testcases/kernel/device-drivers/nvme/README
 create mode 100644 testcases/kernel/device-drivers/nvme/nvme01.c

diff --git a/testcases/kernel/device-drivers/nvme/Makefile b/testcases/kernel/device-drivers/nvme/Makefile
new file mode 100644
index 000000000..ace6696f6
--- /dev/null
+++ b/testcases/kernel/device-drivers/nvme/Makefile
@@ -0,0 +1,42 @@
+# SPDX-License-Identifier: GPL-2.0-or-later
+# Copyright (c) 2024 IBM Corporation
+#
+# Standalone Makefile for NVMe LTP test suite
+
+# Compiler and flags
+CC		= gcc
+CFLAGS		= -Wall -O2 -I/opt/ltp/include
+LDFLAGS		= -L/opt/ltp/lib
+LDLIBS		= -lltp -lrt
+
+# Test binaries
+TARGETS		= nvme01 nvme02 nvme03 nvme04
+
+# Build all tests
+all: $(TARGETS)
+
+nvme01: nvme01.c
+	$(CC) $(CFLAGS) -o $@ $< $(LDFLAGS) $(LDLIBS)
+
+nvme02: nvme02.c
+	$(CC) $(CFLAGS) -o $@ $< $(LDFLAGS) $(LDLIBS)
+
+nvme03: nvme03.c
+	$(CC) $(CFLAGS) -o $@ $< $(LDFLAGS) $(LDLIBS)
+
+nvme04: nvme04.c
+	$(CC) $(CFLAGS) -o $@ $< $(LDFLAGS) $(LDLIBS)
+
+# Install targets
+install: $(TARGETS)
+	@mkdir -p /opt/ltp/testcases/bin
+	@for target in $(TARGETS); do \
+		install -m 0755 $$target /opt/ltp/testcases/bin/; \
+	done
+	@echo "Tests installed to /opt/ltp/testcases/bin/"
+
+# Clean
+clean:
+	rm -f $(TARGETS) *.o
+
+.PHONY: all install clean
\ No newline at end of file
diff --git a/testcases/kernel/device-drivers/nvme/README b/testcases/kernel/device-drivers/nvme/README
new file mode 100644
index 000000000..6ee5796fe
--- /dev/null
+++ b/testcases/kernel/device-drivers/nvme/README
@@ -0,0 +1,155 @@
+NVMe Test Suite for Linux Test Project (LTP)
+==============================================
+
+This directory contains test cases for NVMe (Non-Volatile Memory Express) 
+device functionality testing.
+
+Test Cases
+----------
+
+1. nvme01 - Device Discovery & Identification
+   Tests:
+   - Detect NVMe controllers
+   - Enumerate namespaces
+   - Verify PCI enumeration
+   - Check driver binding
+
+2. nvme02 - Namespace Management
+   Tests:
+   - Create namespaces (various sizes)
+   - Delete namespaces
+   - Attach/detach namespaces to controllers
+   - Resize namespaces
+   - Format namespaces (different block sizes: 512B, 4KB)
+   - Namespace sharing across controllers
+
+3. nvme03 - I/O Operations
+   Tests:
+   - Sequential read/write operations
+   - Random read/write operations
+   - Mixed workloads
+   - Different block sizes (512B, 4KB, 8KB)
+   - Queue depth variations
+   - Direct I/O vs buffered I/O
+
+4. nvme04 - Multipath & Redundancy
+   Tests:
+   - Path failover testing
+   - Load balancing across paths
+   - Path recovery
+   - ANA (Asymmetric Namespace Access) states
+   - Controller failover
+
+Requirements
+------------
+
+Hardware:
+- System with NVMe storage device(s)
+- For multipath tests: NVMe device with multiple paths configured
+
+Software:
+- Linux kernel with NVMe support (CONFIG_BLK_DEV_NVME=y)
+- nvme-cli tools (for namespace management tests)
+- Root/sudo privileges
+
+Building
+--------
+
+From the LTP root directory:
+  make -C testcases/kernel/device-drivers/nvme
+
+Or from this directory:
+  make
+
+Running Tests
+-------------
+
+Individual test execution:
+  ./nvme01
+  ./nvme02
+  ./nvme03
+  ./nvme04
+
+Using LTP runtest:
+  runltp -f nvme
+
+Using runtest file:
+  runltp -f /opt/ltp/runtest/nvme
+
+Test Results
+------------
+
+Tests use standard LTP result codes:
+- TPASS: Test passed
+- TFAIL: Test failed
+- TCONF: Test not configured (e.g., no NVMe device found)
+- TBROK: Test broken (setup failure)
+- TWARN: Test warning
+
+Notes
+-----
+
+1. Some tests require specific hardware configurations:
+   - nvme02: May require namespace management support
+   - nvme04: Requires multipath configuration for full testing
+
+2. Destructive tests:
+   - nvme02 includes namespace creation/deletion which may affect data
+   - Always run on test systems or with proper backups
+
+3. Performance tests (nvme03):
+   - Results vary based on hardware and system load
+   - Tests measure relative performance, not absolute benchmarks
+
+4. Root privileges:
+   - All tests require root access for device operations
+
+Test Coverage
+-------------
+
+The test suite covers:
+- Basic NVMe device detection and enumeration
+- Namespace lifecycle management
+- I/O performance characteristics
+- Multipath and redundancy features
+- Driver and controller state verification
+
+Known Limitations
+-----------------
+
+1. Namespace management tests may not work on all NVMe devices
+   (depends on controller capabilities)
+
+2. Multipath tests require specific hardware and kernel configuration
+
+3. Some tests are informational and may show TCONF on systems
+   without full NVMe feature support
+
+Contributing
+------------
+
+When adding new tests:
+1. Follow LTP coding standards
+2. Use tst_test.h framework
+3. Include proper error handling
+4. Document test purpose and requirements
+5. Test on multiple NVMe device types if possible
+
+References
+----------
+
+- NVMe Specification: https://nvmexpress.org/specifications/
+- Linux NVMe Driver: Documentation/block/nvme.rst
+- nvme-cli: https://github.com/linux-nvme/nvme-cli
+- LTP Documentation: https://linux-test-project.github.io/
+
+Authors
+-------
+
+Copyright (c) 2024 IBM Corporation
+LTP NVMe Test Suite
+
+License
+-------
+
+SPDX-License-Identifier: GPL-2.0-or-later
\ No newline at end of file
diff --git a/testcases/kernel/device-drivers/nvme/nvme01.c b/testcases/kernel/device-drivers/nvme/nvme01.c
new file mode 100644
index 000000000..82fbd315b
--- /dev/null
+++ b/testcases/kernel/device-drivers/nvme/nvme01.c
@@ -0,0 +1,236 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * Copyright (c) 2024 IBM Corporation
+ * Author: LTP NVMe Test Suite
+ *
+ * Test: NVMe Device Discovery & Identification
+ *
+ * This test verifies:
+ * - Detection of NVMe controllers
+ * - Enumeration of namespaces
+ * - PCI enumeration verification
+ * - Driver binding check
+ */
+
+#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"
+
+#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 = 0;
+static char nvme_dev_name[256];
+
+/*
+ * Test Case 1: Detect NVMe Controllers
+ * Verifies that NVMe controllers are present in the system
+ */
+static void test_detect_nvme_controllers(void)
+{
+	DIR *dir;
+	struct dirent *entry;
+	int found = 0;
+
+	dir = opendir(NVME_DEV_PATH);
+	if (!dir) {
+		tst_brk(TBROK | TERRNO, "Failed to open %s", NVME_DEV_PATH);
+		return;
+	}
+
+	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) {  /* nvme0, nvme1, etc. */
+			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;
+		}
+	}
+
+	closedir(dir);
+
+	if (found)
+		tst_res(TPASS, "NVMe controller(s) detected successfully");
+	else
+		tst_res(TCONF, "No NVMe controllers found in system");
+}
+
+/*
+ * Test Case 2: Enumerate Namespaces
+ * Verifies that NVMe namespaces can be enumerated
+ */
+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 = opendir(NVME_DEV_PATH);
+	if (!dir) {
+		tst_brk(TBROK | TERRNO, "Failed to open %s", NVME_DEV_PATH);
+		return;
+	}
+
+	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++;
+		}
+	}
+
+	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);
+}
+
+/*
+ * Test Case 3: Verify PCI Enumeration
+ * Checks if NVMe device is properly enumerated on PCI bus
+ */
+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 = opendir(PCI_DEVICES_PATH);
+	if (!dir) {
+		tst_brk(TBROK | TERRNO, "Failed to open %s", PCI_DEVICES_PATH);
+		return;
+	}
+
+	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 = fopen(class_path, "r");
+		if (!fp)
+			continue;
+
+		if (fgets(class_id, sizeof(class_id), fp)) {
+			/* NVMe class code is 0x010802 (Mass storage controller: NVM Express) */
+			if (strncmp(class_id, "0x010802", 8) == 0) {
+				tst_res(TINFO, "Found NVMe PCI device: %s (class: %s)",
+					entry->d_name, class_id);
+				found = 1;
+			}
+		}
+		fclose(fp);
+	}
+
+	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");
+}
+
+/*
+ * Test Case 4: Check Driver Binding
+ * Verifies that NVMe driver is properly bound to the device
+ */
+static void test_check_driver_binding(void)
+{
+	char driver_path[512];
+	char driver_link[512];
+	ssize_t len;
+
+	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);
+
+	len = readlink(driver_path, driver_link, sizeof(driver_link) - 1);
+	if (len == -1) {
+		tst_res(TFAIL | TERRNO, "Failed to read driver symlink for %s", nvme_dev_name);
+		return;
+	}
+
+	driver_link[len] = '\0';
+
+	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)
+{
+	/* Check if nvme module is loaded */
+	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)
+{
+	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,
+	.needs_root = 1,
+};
+
+// Made with Bob
-- 
2.52.0



More information about the ltp mailing list