Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

selftests/ublk: add read-only buffer registration test

Add --rdonly_shmem_buf option to kublk that registers shared memory
buffers with UBLK_SHMEM_BUF_READ_ONLY (read-only pinning without
FOLL_WRITE) and mmaps with PROT_READ only.

Add test_shmemzc_04.sh which exercises the new flag with a null target,
hugetlbfs buffer, and write workload. Write I/O works because the
server only reads from the shared buffer — the data flows from client
to kernel to the shared pages, and the server reads them out.

Signed-off-by: Ming Lei <ming.lei@redhat.com>
Link: https://patch.msgid.link/20260331153207.3635125-11-ming.lei@redhat.com
Signed-off-by: Jens Axboe <axboe@kernel.dk>

authored by

Ming Lei and committed by
Jens Axboe
affb5f67 12075992

+85 -4
+1
tools/testing/selftests/ublk/Makefile
··· 55 55 TEST_PROGS += test_shmemzc_01.sh 56 56 TEST_PROGS += test_shmemzc_02.sh 57 57 TEST_PROGS += test_shmemzc_03.sh 58 + TEST_PROGS += test_shmemzc_04.sh 58 59 59 60 TEST_PROGS += test_stress_01.sh 60 61 TEST_PROGS += test_stress_02.sh
+11 -4
tools/testing/selftests/ublk/kublk.c
··· 1219 1219 shmem_count = 0; 1220 1220 } 1221 1221 1222 - static int ublk_ctrl_reg_buf(struct ublk_dev *dev, void *addr, size_t size) 1222 + static int ublk_ctrl_reg_buf(struct ublk_dev *dev, void *addr, size_t size, 1223 + __u32 flags) 1223 1224 { 1224 1225 struct ublk_shmem_buf_reg buf_reg = { 1225 1226 .addr = (unsigned long)addr, 1226 1227 .len = size, 1228 + .flags = flags, 1227 1229 }; 1228 1230 struct ublk_ctrl_cmd_data data = { 1229 1231 .cmd_op = UBLK_U_CMD_REG_BUF, ··· 1274 1272 } 1275 1273 1276 1274 /* Register server's VA range with kernel for PFN matching */ 1277 - ret = ublk_ctrl_reg_buf(dev, base, size); 1275 + ret = ublk_ctrl_reg_buf(dev, base, size, 0); 1278 1276 if (ret < 0) { 1279 1277 ublk_dbg(UBLK_DBG_DEV, 1280 1278 "shmem_zc: kernel reg failed %d\n", ret); ··· 1359 1357 return -EINVAL; 1360 1358 } 1361 1359 1362 - base = mmap(NULL, st.st_size, PROT_READ | PROT_WRITE, 1360 + base = mmap(NULL, st.st_size, 1361 + ctx->rdonly_shmem_buf ? PROT_READ : PROT_READ | PROT_WRITE, 1363 1362 MAP_SHARED | MAP_POPULATE, fd, 0); 1364 1363 if (base == MAP_FAILED) { 1365 1364 ublk_err("htlb: mmap failed\n"); ··· 1368 1365 return -ENOMEM; 1369 1366 } 1370 1367 1371 - ret = ublk_ctrl_reg_buf(dev, base, st.st_size); 1368 + ret = ublk_ctrl_reg_buf(dev, base, st.st_size, 1369 + ctx->rdonly_shmem_buf ? UBLK_SHMEM_BUF_READ_ONLY : 0); 1372 1370 if (ret < 0) { 1373 1371 ublk_err("htlb: reg_buf failed: %d\n", ret); 1374 1372 munmap(base, st.st_size); ··· 2133 2129 { "no_auto_part_scan", 0, NULL, 0 }, 2134 2130 { "shmem_zc", 0, NULL, 0 }, 2135 2131 { "htlb", 1, NULL, 0 }, 2132 + { "rdonly_shmem_buf", 0, NULL, 0 }, 2136 2133 { 0, 0, 0, 0 } 2137 2134 }; 2138 2135 const struct ublk_tgt_ops *ops = NULL; ··· 2253 2248 ctx.flags |= UBLK_F_SHMEM_ZC; 2254 2249 if (!strcmp(longopts[option_idx].name, "htlb")) 2255 2250 ctx.htlb_path = strdup(optarg); 2251 + if (!strcmp(longopts[option_idx].name, "rdonly_shmem_buf")) 2252 + ctx.rdonly_shmem_buf = 1; 2256 2253 break; 2257 2254 case '?': 2258 2255 /*
+1
tools/testing/selftests/ublk/kublk.h
··· 81 81 unsigned int no_ublk_fixed_fd:1; 82 82 unsigned int safe_stop:1; 83 83 unsigned int no_auto_part_scan:1; 84 + unsigned int rdonly_shmem_buf:1; 84 85 __u32 integrity_flags; 85 86 __u8 metadata_size; 86 87 __u8 pi_offset;
+72
tools/testing/selftests/ublk/test_shmemzc_04.sh
··· 1 + #!/bin/bash 2 + # SPDX-License-Identifier: GPL-2.0 3 + # Test: shmem_zc with read-only buffer registration on null target 4 + # 5 + # Same as test_shmemzc_01 but with --rdonly_shmem_buf: pages are pinned 6 + # without FOLL_WRITE (UBLK_BUF_F_READ). Write I/O works because 7 + # the server only reads from the shared buffer. 8 + 9 + . "$(cd "$(dirname "$0")" && pwd)"/test_common.sh 10 + 11 + ERR_CODE=0 12 + 13 + _prep_test "shmem_zc" "null target hugetlbfs shmem zero-copy rdonly_buf test" 14 + 15 + if ! _have_program fio; then 16 + echo "SKIP: fio not available" 17 + exit "$UBLK_SKIP_CODE" 18 + fi 19 + 20 + if ! grep -q hugetlbfs /proc/filesystems; then 21 + echo "SKIP: hugetlbfs not supported" 22 + exit "$UBLK_SKIP_CODE" 23 + fi 24 + 25 + # Allocate hugepages 26 + OLD_NR_HP=$(cat /proc/sys/vm/nr_hugepages) 27 + echo 10 > /proc/sys/vm/nr_hugepages 28 + NR_HP=$(cat /proc/sys/vm/nr_hugepages) 29 + if [ "$NR_HP" -lt 2 ]; then 30 + echo "SKIP: cannot allocate hugepages" 31 + echo "$OLD_NR_HP" > /proc/sys/vm/nr_hugepages 32 + exit "$UBLK_SKIP_CODE" 33 + fi 34 + 35 + # Mount hugetlbfs 36 + HTLB_MNT=$(mktemp -d "${UBLK_TEST_DIR}/htlb_mnt_XXXXXX") 37 + if ! mount -t hugetlbfs none "$HTLB_MNT"; then 38 + echo "SKIP: cannot mount hugetlbfs" 39 + rmdir "$HTLB_MNT" 40 + echo "$OLD_NR_HP" > /proc/sys/vm/nr_hugepages 41 + exit "$UBLK_SKIP_CODE" 42 + fi 43 + 44 + HTLB_FILE="$HTLB_MNT/ublk_buf" 45 + fallocate -l 4M "$HTLB_FILE" 46 + 47 + dev_id=$(_add_ublk_dev -t null --shmem_zc --htlb "$HTLB_FILE" --rdonly_shmem_buf) 48 + _check_add_dev $TID $? 49 + 50 + fio --name=htlb_zc_rdonly \ 51 + --filename=/dev/ublkb"${dev_id}" \ 52 + --ioengine=io_uring \ 53 + --rw=randwrite \ 54 + --direct=1 \ 55 + --bs=4k \ 56 + --size=4M \ 57 + --iodepth=32 \ 58 + --mem=mmaphuge:"$HTLB_FILE" \ 59 + > /dev/null 2>&1 60 + ERR_CODE=$? 61 + 62 + # Delete device first so daemon releases the htlb mmap 63 + _ublk_del_dev "${dev_id}" 64 + 65 + rm -f "$HTLB_FILE" 66 + umount "$HTLB_MNT" 67 + rmdir "$HTLB_MNT" 68 + echo "$OLD_NR_HP" > /proc/sys/vm/nr_hugepages 69 + 70 + _cleanup_test "shmem_zc" 71 + 72 + _show_result $TID $ERR_CODE