selftests: ublk: add test case for UBLK_U_CMD_UPDATE_SIZE
authorMing Lei <ming.lei@redhat.com>
Thu, 22 May 2025 16:35:19 +0000 (00:35 +0800)
committerJens Axboe <axboe@kernel.dk>
Fri, 23 May 2025 15:42:12 +0000 (09:42 -0600)
Add test generic_10 for covering new control command of UBLK_U_CMD_UPDATE_SIZE.

Add 'update_size -s|--size size_in_bytes' sub-command on ublk utility for
supporting this feature, then verify the feature via generic_10.

Cc: Omri Mann <omri@nvidia.com>
Cc: Jared Holzman <jholzman@nvidia.com>
Signed-off-by: Ming Lei <ming.lei@redhat.com>
Link: https://lore.kernel.org/r/20250522163523.406289-2-ming.lei@redhat.com
Signed-off-by: Jens Axboe <axboe@kernel.dk>
tools/testing/selftests/ublk/Makefile
tools/testing/selftests/ublk/kublk.c
tools/testing/selftests/ublk/kublk.h
tools/testing/selftests/ublk/test_common.sh
tools/testing/selftests/ublk/test_generic_10.sh [new file with mode: 0755]

index 2a2ef0cb54bc79a6e26f9246c9ce033875ca9250..81b8ed6b92e268f1adda4892ff129acb7c00b49d 100644 (file)
@@ -17,6 +17,7 @@ TEST_PROGS += test_generic_07.sh
 
 TEST_PROGS += test_generic_08.sh
 TEST_PROGS += test_generic_09.sh
+TEST_PROGS += test_generic_10.sh
 
 TEST_PROGS += test_null_01.sh
 TEST_PROGS += test_null_02.sh
index c429a20ab51edbcd9f0e185c4e3ff4280c004289..683a23078f43bb33b3c77c43f8a9d7816c86ecc6 100644 (file)
@@ -216,6 +216,18 @@ static int ublk_ctrl_get_features(struct ublk_dev *dev,
        return __ublk_ctrl_cmd(dev, &data);
 }
 
+static int ublk_ctrl_update_size(struct ublk_dev *dev,
+               __u64 nr_sects)
+{
+       struct ublk_ctrl_cmd_data data = {
+               .cmd_op = UBLK_U_CMD_UPDATE_SIZE,
+               .flags  = CTRL_CMD_HAS_DATA,
+       };
+
+       data.data[0] = nr_sects;
+       return __ublk_ctrl_cmd(dev, &data);
+}
+
 static const char *ublk_dev_state_desc(struct ublk_dev *dev)
 {
        switch (dev->dev_info.state) {
@@ -1236,6 +1248,7 @@ static int cmd_dev_get_features(void)
                [const_ilog2(UBLK_F_USER_COPY)] = "USER_COPY",
                [const_ilog2(UBLK_F_ZONED)] = "ZONED",
                [const_ilog2(UBLK_F_USER_RECOVERY_FAIL_IO)] = "RECOVERY_FAIL_IO",
+               [const_ilog2(UBLK_F_UPDATE_SIZE)] = "UPDATE_SIZE",
                [const_ilog2(UBLK_F_AUTO_BUF_REG)] = "AUTO_BUF_REG",
        };
        struct ublk_dev *dev;
@@ -1270,6 +1283,39 @@ static int cmd_dev_get_features(void)
        return ret;
 }
 
+static int cmd_dev_update_size(struct dev_ctx *ctx)
+{
+       struct ublk_dev *dev = ublk_ctrl_init();
+       struct ublk_params p;
+       int ret = -EINVAL;
+
+       if (!dev)
+               return -ENODEV;
+
+       if (ctx->dev_id < 0) {
+               fprintf(stderr, "device id isn't provided\n");
+               goto out;
+       }
+
+       dev->dev_info.dev_id = ctx->dev_id;
+       ret = ublk_ctrl_get_params(dev, &p);
+       if (ret < 0) {
+               ublk_err("failed to get params %d %s\n", ret, strerror(-ret));
+               goto out;
+       }
+
+       if (ctx->size & ((1 << p.basic.logical_bs_shift) - 1)) {
+               ublk_err("size isn't aligned with logical block size\n");
+               ret = -EINVAL;
+               goto out;
+       }
+
+       ret = ublk_ctrl_update_size(dev, ctx->size >> 9);
+out:
+       ublk_ctrl_deinit(dev);
+       return ret;
+}
+
 static void __cmd_create_help(char *exe, bool recovery)
 {
        int i;
@@ -1312,6 +1358,7 @@ static int cmd_dev_help(char *exe)
        printf("%s list [-n dev_id] -a \n", exe);
        printf("\t -a list all devices, -n list specified device, default -a \n\n");
        printf("%s features\n", exe);
+       printf("%s update_size -n dev_id -s|--size size_in_bytes \n", exe);
        return 0;
 }
 
@@ -1333,6 +1380,7 @@ int main(int argc, char *argv[])
                { "get_data",           1,      NULL, 'g'},
                { "auto_zc",            0,      NULL,  0 },
                { "auto_zc_fallback",   0,      NULL,  0 },
+               { "size",               1,      NULL, 's'},
                { 0, 0, 0, 0 }
        };
        const struct ublk_tgt_ops *ops = NULL;
@@ -1354,7 +1402,7 @@ int main(int argc, char *argv[])
 
        opterr = 0;
        optind = 2;
-       while ((opt = getopt_long(argc, argv, "t:n:d:q:r:e:i:gaz",
+       while ((opt = getopt_long(argc, argv, "t:n:d:q:r:e:i:s:gaz",
                                  longopts, &option_idx)) != -1) {
                switch (opt) {
                case 'a':
@@ -1394,6 +1442,9 @@ int main(int argc, char *argv[])
                case 'g':
                        ctx.flags |= UBLK_F_NEED_GET_DATA;
                        break;
+               case 's':
+                       ctx.size = strtoull(optarg, NULL, 10);
+                       break;
                case 0:
                        if (!strcmp(longopts[option_idx].name, "debug_mask"))
                                ublk_dbg_mask = strtol(optarg, NULL, 16);
@@ -1470,6 +1521,8 @@ int main(int argc, char *argv[])
                ret = cmd_dev_help(argv[0]);
        else if (!strcmp(cmd, "features"))
                ret = cmd_dev_get_features();
+       else if (!strcmp(cmd, "update_size"))
+               ret = cmd_dev_update_size(&ctx);
        else
                cmd_dev_help(argv[0]);
 
index 9af930e951a31b978962b4a53ae80ad80bb06812..e34508bf5798b539f0290e21b37b591dc5689f59 100644 (file)
@@ -92,6 +92,9 @@ struct dev_ctx {
        /* built from shmem, only for ublk_dump_dev() */
        struct ublk_dev *shadow_dev;
 
+       /* for 'update_size' command */
+       unsigned long long size;
+
        union {
                struct stripe_ctx       stripe;
                struct fault_inject_ctx fault_inject;
index c17fd66b73ac8ae2d78b8c01cd2c6c4fa818f328..244d886b7eaed2b674aa0617411b108e462c06b7 100755 (executable)
@@ -23,6 +23,11 @@ _get_disk_dev_t() {
        echo $(( (major & 0xfff) << 20 | (minor & 0xfffff) ))
 }
 
+_get_disk_size()
+{
+       lsblk -b -o SIZE -n "$1"
+}
+
 _run_fio_verify_io() {
        fio --name=verify --rw=randwrite --direct=1 --ioengine=libaio \
                --bs=8k --iodepth=32 --verify=crc32c --do_verify=1 \
diff --git a/tools/testing/selftests/ublk/test_generic_10.sh b/tools/testing/selftests/ublk/test_generic_10.sh
new file mode 100755 (executable)
index 0000000..abc11c3
--- /dev/null
@@ -0,0 +1,30 @@
+#!/bin/bash
+# SPDX-License-Identifier: GPL-2.0
+
+. "$(cd "$(dirname "$0")" && pwd)"/test_common.sh
+
+TID="generic_10"
+ERR_CODE=0
+
+if ! _have_feature "UPDATE_SIZE"; then
+       exit "$UBLK_SKIP_CODE"
+fi
+
+_prep_test "null" "check update size"
+
+dev_id=$(_add_ublk_dev -t null)
+_check_add_dev $TID $?
+
+size=$(_get_disk_size /dev/ublkb"${dev_id}")
+size=$(( size / 2 ))
+if ! "$UBLK_PROG" update_size -n "$dev_id" -s "$size"; then
+       ERR_CODE=255
+fi
+
+new_size=$(_get_disk_size /dev/ublkb"${dev_id}")
+if [ "$new_size" != "$size" ]; then
+       ERR_CODE=255
+fi
+
+_cleanup_test "null"
+_show_result $TID $ERR_CODE