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

Add 'quiesce -n dev_id' sub-command on ublk utility for transitioning
device state to quiesce states, then verify the feature via generic_10
by doing quiesce and recovery.

Cc: Yoav Cohen <yoav@nvidia.com>
Link: https://lore.kernel.org/linux-block/DM4PR12MB632807AB7CDCE77D1E5AB7D0A9B92@DM4PR12MB6328.namprd12.prod.outlook.com/
Signed-off-by: Ming Lei <ming.lei@redhat.com>
Link: https://lore.kernel.org/r/20250522163523.406289-4-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/test_common.sh
tools/testing/selftests/ublk/test_generic_04.sh
tools/testing/selftests/ublk/test_generic_05.sh
tools/testing/selftests/ublk/test_generic_11.sh [new file with mode: 0755]

index 81b8ed6b92e268f1adda4892ff129acb7c00b49d..4dde8838261d660ba31a07d608332d1733a6321d 100644 (file)
@@ -18,6 +18,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_generic_11.sh
 
 TEST_PROGS += test_null_01.sh
 TEST_PROGS += test_null_02.sh
index 683a23078f43bb33b3c77c43f8a9d7816c86ecc6..b5131a000795d6a8d589bd7ade6cce4216dbe182 100644 (file)
@@ -228,6 +228,18 @@ static int ublk_ctrl_update_size(struct ublk_dev *dev,
        return __ublk_ctrl_cmd(dev, &data);
 }
 
+static int ublk_ctrl_quiesce_dev(struct ublk_dev *dev,
+                                unsigned int timeout_ms)
+{
+       struct ublk_ctrl_cmd_data data = {
+               .cmd_op = UBLK_U_CMD_QUIESCE_DEV,
+               .flags  = CTRL_CMD_HAS_DATA,
+       };
+
+       data.data[0] = timeout_ms;
+       return __ublk_ctrl_cmd(dev, &data);
+}
+
 static const char *ublk_dev_state_desc(struct ublk_dev *dev)
 {
        switch (dev->dev_info.state) {
@@ -1053,6 +1065,9 @@ static int __cmd_dev_add(const struct dev_ctx *ctx)
        info->nr_hw_queues = nr_queues;
        info->queue_depth = depth;
        info->flags = ctx->flags;
+       if ((features & UBLK_F_QUIESCE) &&
+                       (info->flags & UBLK_F_USER_RECOVERY))
+               info->flags |= UBLK_F_QUIESCE;
        dev->tgt.ops = ops;
        dev->tgt.sq_depth = depth;
        dev->tgt.cq_depth = depth;
@@ -1250,6 +1265,7 @@ static int cmd_dev_get_features(void)
                [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",
+               [const_ilog2(UBLK_F_QUIESCE)] = "QUIESCE",
        };
        struct ublk_dev *dev;
        __u64 features = 0;
@@ -1316,6 +1332,26 @@ out:
        return ret;
 }
 
+static int cmd_dev_quiesce(struct dev_ctx *ctx)
+{
+       struct ublk_dev *dev = ublk_ctrl_init();
+       int ret = -EINVAL;
+
+       if (!dev)
+               return -ENODEV;
+
+       if (ctx->dev_id < 0) {
+               fprintf(stderr, "device id isn't provided for quiesce\n");
+               goto out;
+       }
+       dev->dev_info.dev_id = ctx->dev_id;
+       ret = ublk_ctrl_quiesce_dev(dev, 10000);
+
+out:
+       ublk_ctrl_deinit(dev);
+       return ret;
+}
+
 static void __cmd_create_help(char *exe, bool recovery)
 {
        int i;
@@ -1359,6 +1395,7 @@ static int cmd_dev_help(char *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);
+       printf("%s quiesce -n dev_id\n", exe);
        return 0;
 }
 
@@ -1523,6 +1560,8 @@ int main(int argc, char *argv[])
                ret = cmd_dev_get_features();
        else if (!strcmp(cmd, "update_size"))
                ret = cmd_dev_update_size(&ctx);
+       else if (!strcmp(cmd, "quiesce"))
+               ret = cmd_dev_quiesce(&ctx);
        else
                cmd_dev_help(argv[0]);
 
index 244d886b7eaed2b674aa0617411b108e462c06b7..0145569ee7e9a45b41898c2c789842b4c8380f18 100755 (executable)
@@ -220,6 +220,26 @@ _recover_ublk_dev() {
        echo "$state"
 }
 
+# quiesce device and return ublk device state
+__ublk_quiesce_dev()
+{
+       local dev_id=$1
+       local exp_state=$2
+       local state
+
+       if ! ${UBLK_PROG} quiesce -n "${dev_id}"; then
+               state=$(_get_ublk_dev_state "${dev_id}")
+               return "$state"
+       fi
+
+       for ((j=0;j<50;j++)); do
+               state=$(_get_ublk_dev_state "${dev_id}")
+               [ "$state" == "$exp_state" ] && break
+               sleep 1
+       done
+       echo "$state"
+}
+
 # kill the ublk daemon and return ublk device state
 __ublk_kill_daemon()
 {
@@ -308,20 +328,26 @@ run_io_and_kill_daemon()
 
 run_io_and_recover()
 {
+       local action=$1
        local state
        local dev_id
 
+       shift 1
        dev_id=$(_add_ublk_dev "$@")
        _check_add_dev "$TID" $?
 
        fio --name=job1 --filename=/dev/ublkb"${dev_id}" --ioengine=libaio \
-               --rw=readwrite --iodepth=256 --size="${size}" --numjobs=4 \
+               --rw=randread --iodepth=256 --size="${size}" --numjobs=4 \
                --runtime=20 --time_based > /dev/null 2>&1 &
        sleep 4
 
-       state=$(__ublk_kill_daemon "${dev_id}" "QUIESCED")
+       if [ "$action" == "kill_daemon" ]; then
+               state=$(__ublk_kill_daemon "${dev_id}" "QUIESCED")
+       elif [ "$action" == "quiesce_dev" ]; then
+               state=$(__ublk_quiesce_dev "${dev_id}" "QUIESCED")
+       fi
        if [ "$state" != "QUIESCED" ]; then
-               echo "device isn't quiesced($state) after killing daemon"
+               echo "device isn't quiesced($state) after $action"
                return 255
        fi
 
index 8a3bc080c5771e08c40b944c9c9896329e72e1b4..8b533217d4a174776714dc76331dc2d61c92c4af 100755 (executable)
@@ -8,7 +8,7 @@ ERR_CODE=0
 
 ublk_run_recover_test()
 {
-       run_io_and_recover "$@"
+       run_io_and_recover "kill_daemon" "$@"
        ERR_CODE=$?
        if [ ${ERR_CODE} -ne 0 ]; then
                echo "$TID failure: $*"
index 3bb00a3474020196e349c1173484b1ffb9163e13..398e9e2b58e159046deb64b938443a0ba2b3dd4e 100755 (executable)
@@ -8,7 +8,7 @@ ERR_CODE=0
 
 ublk_run_recover_test()
 {
-       run_io_and_recover "$@"
+       run_io_and_recover "kill_daemon" "$@"
        ERR_CODE=$?
        if [ ${ERR_CODE} -ne 0 ]; then
                echo "$TID failure: $*"
diff --git a/tools/testing/selftests/ublk/test_generic_11.sh b/tools/testing/selftests/ublk/test_generic_11.sh
new file mode 100755 (executable)
index 0000000..a00357a
--- /dev/null
@@ -0,0 +1,44 @@
+#!/bin/bash
+# SPDX-License-Identifier: GPL-2.0
+
+. "$(cd "$(dirname "$0")" && pwd)"/test_common.sh
+
+TID="generic_11"
+ERR_CODE=0
+
+ublk_run_quiesce_recover()
+{
+       run_io_and_recover "quiesce_dev" "$@"
+       ERR_CODE=$?
+       if [ ${ERR_CODE} -ne 0 ]; then
+               echo "$TID failure: $*"
+               _show_result $TID $ERR_CODE
+       fi
+}
+
+if ! _have_feature "QUIESCE"; then
+       exit "$UBLK_SKIP_CODE"
+fi
+
+if ! _have_program fio; then
+       exit "$UBLK_SKIP_CODE"
+fi
+
+_prep_test "quiesce" "basic quiesce & recover function verification"
+
+_create_backfile 0 256M
+_create_backfile 1 128M
+_create_backfile 2 128M
+
+ublk_run_quiesce_recover -t null -q 2 -r 1 &
+ublk_run_quiesce_recover -t loop -q 2 -r 1 "${UBLK_BACKFILES[0]}" &
+ublk_run_quiesce_recover -t stripe -q 2 -r 1 "${UBLK_BACKFILES[1]}" "${UBLK_BACKFILES[2]}" &
+wait
+
+ublk_run_quiesce_recover -t null -q 2 -r 1 -i 1 &
+ublk_run_quiesce_recover -t loop -q 2 -r 1 -i 1 "${UBLK_BACKFILES[0]}" &
+ublk_run_quiesce_recover -t stripe -q 2 -r 1 -i 1 "${UBLK_BACKFILES[1]}" "${UBLK_BACKFILES[2]}" &
+wait
+
+_cleanup_test "quiesce"
+_show_result $TID $ERR_CODE