[RFC PATCH blktests v1] nvme: check user queue limits across namespace rescans
Yao Sang
sangyao at kylinos.cn
Thu Jul 9 01:48:26 PDT 2026
NVMe namespace rescans should not reset queue user caps on the namespace
head. Add a regression test that lowers max_sectors_kb, optionally lowers
discard_max_bytes, optionally disables write_zeroes_unmap_max_bytes, runs
nvme ns-rescan, and verifies that the user values are preserved.
Mark the test as zoned-capable so it can run on ZNS devices as well.
Signed-off-by: Yao Sang <sangyao at kylinos.cn>
---
tests/nvme/068 | 151 +++++++++++++++++++++++++++++++++++++++++++++
tests/nvme/068.out | 2 +
2 files changed, 153 insertions(+)
create mode 100755 tests/nvme/068
create mode 100644 tests/nvme/068.out
diff --git a/tests/nvme/068 b/tests/nvme/068
new file mode 100755
index 0000000..a7786db
--- /dev/null
+++ b/tests/nvme/068
@@ -0,0 +1,151 @@
+#!/bin/bash
+# SPDX-License-Identifier: GPL-3.0+
+#
+# Test queue user limits across NVMe namespace rescans.
+
+. tests/nvme/rc
+
+DESCRIPTION="check queue user limits across NVMe namespace rescans"
+QUICK=1
+CAN_BE_ZONED=1
+
+requires() {
+ _nvme_requires
+ _have_program nvme
+}
+
+_test_dev_nvme_ctrl_dev() {
+ local ctrl
+
+ ctrl="$(_nvme_get_ctrl_list | head -n 1)"
+ if [[ -z "$ctrl" ]]; then
+ return 1
+ fi
+
+ echo "/dev/$(basename "$ctrl")"
+}
+
+device_requires() {
+ local ctrl_dev
+
+ _require_test_dev_is_nvme
+ _require_test_dev_sysfs queue/max_sectors_kb queue/max_hw_sectors_kb
+
+ if ! ctrl_dev="$(_test_dev_nvme_ctrl_dev)"; then
+ SKIP_REASONS+=("unable to find NVMe controller for $TEST_DEV")
+ return 1
+ fi
+ if [[ ! -c "$ctrl_dev" ]]; then
+ SKIP_REASONS+=("$ctrl_dev is not a character device")
+ return 1
+ fi
+}
+
+_cleanup_queue_limits() {
+ if [[ -z "${nvme068_queue_path:-}" ]]; then
+ return
+ fi
+
+ echo "$nvme068_max_sectors_kb" > "$nvme068_queue_path/max_sectors_kb"
+ if [[ -n "${nvme068_discard_max_bytes:-}" ]]; then
+ echo "$nvme068_discard_max_bytes" > \
+ "$nvme068_queue_path/discard_max_bytes"
+ fi
+ if [[ -n "${nvme068_wzeroes_unmap_max_bytes:-}" ]]; then
+ echo "$nvme068_wzeroes_unmap_max_bytes" > \
+ "$nvme068_queue_path/write_zeroes_unmap_max_bytes"
+ fi
+}
+
+_check_queue_limit() {
+ local queue_path=$1
+ local attr=$2
+ local expected=$3
+ local actual
+
+ actual="$(cat "$queue_path/$attr")"
+ if [[ "$actual" -ne "$expected" ]]; then
+ echo "ERROR: $attr changed from $expected to $actual"
+ fi
+}
+
+test_device() {
+ local queue_path="$TEST_DEV_SYSFS/queue"
+ local ctrl_dev
+ local max_hw_sectors_kb
+ local max_sectors_kb
+ local discard_hw_bytes
+ local discard_granularity
+ local discard_max_bytes=""
+ local wzeroes_unmap_hw_bytes
+ local wzeroes_unmap_max_bytes=""
+
+ echo "Running ${TEST_NAME}"
+
+ ctrl_dev="$(_test_dev_nvme_ctrl_dev)"
+ nvme068_queue_path="$queue_path"
+ nvme068_max_sectors_kb="$(cat "$queue_path/max_sectors_kb")"
+ nvme068_discard_max_bytes=""
+ nvme068_wzeroes_unmap_max_bytes=""
+ _register_test_cleanup _cleanup_queue_limits
+
+ max_hw_sectors_kb="$(cat "$queue_path/max_hw_sectors_kb")"
+ max_sectors_kb=$((max_hw_sectors_kb / 2))
+ if ((max_sectors_kb == 0)); then
+ max_sectors_kb=1
+ fi
+
+ if [[ -e "$queue_path/discard_max_bytes" &&
+ -e "$queue_path/discard_max_hw_bytes" &&
+ -e "$queue_path/discard_granularity" ]]; then
+ nvme068_discard_max_bytes="$(cat "$queue_path/discard_max_bytes")"
+ if echo "$nvme068_discard_max_bytes" > \
+ "$queue_path/discard_max_bytes" 2>/dev/null; then
+ discard_hw_bytes="$(cat "$queue_path/discard_max_hw_bytes")"
+ discard_granularity="$(cat "$queue_path/discard_granularity")"
+ if ((discard_granularity > 0 &&
+ discard_hw_bytes >= discard_granularity * 2)); then
+ discard_max_bytes=$(((discard_hw_bytes / 2) /
+ discard_granularity * discard_granularity))
+ fi
+ else
+ nvme068_discard_max_bytes=""
+ fi
+ fi
+
+ if [[ -e "$queue_path/write_zeroes_unmap_max_bytes" &&
+ -e "$queue_path/write_zeroes_unmap_max_hw_bytes" ]]; then
+ nvme068_wzeroes_unmap_max_bytes="$(<"$queue_path/write_zeroes_unmap_max_bytes")"
+ wzeroes_unmap_hw_bytes="$(<"$queue_path/write_zeroes_unmap_max_hw_bytes")"
+ if ((wzeroes_unmap_hw_bytes > 0)); then
+ wzeroes_unmap_max_bytes=0
+ fi
+ fi
+
+ echo "$max_sectors_kb" > "$queue_path/max_sectors_kb"
+ if [[ -n "$discard_max_bytes" ]]; then
+ echo "$discard_max_bytes" > "$queue_path/discard_max_bytes"
+ fi
+ if [[ -n "$wzeroes_unmap_max_bytes" ]]; then
+ echo "$wzeroes_unmap_max_bytes" > \
+ "$queue_path/write_zeroes_unmap_max_bytes"
+ fi
+
+ if ! nvme ns-rescan "$ctrl_dev" >> "$FULL" 2>&1; then
+ echo "ERROR: ns-rescan failed"
+ fi
+
+ _check_queue_limit "$queue_path" max_sectors_kb "$max_sectors_kb"
+ if [[ -n "$discard_max_bytes" ]]; then
+ _check_queue_limit "$queue_path" discard_max_bytes \
+ "$discard_max_bytes"
+ fi
+ if [[ -n "$wzeroes_unmap_max_bytes" ]]; then
+ _check_queue_limit "$queue_path" write_zeroes_unmap_max_bytes \
+ "$wzeroes_unmap_max_bytes"
+ fi
+
+ _cleanup_queue_limits
+
+ echo "Test complete"
+}
diff --git a/tests/nvme/068.out b/tests/nvme/068.out
new file mode 100644
index 0000000..28407c6
--- /dev/null
+++ b/tests/nvme/068.out
@@ -0,0 +1,2 @@
+Running nvme/068
+Test complete
--
2.25.1
More information about the Linux-nvme
mailing list