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 stop command with --safe option

Add 'stop' subcommand to kublk utility that uses the new
UBLK_CMD_TRY_STOP_DEV command when --safe option is specified.
This allows stopping a device only if it has no active openers,
returning -EBUSY otherwise.

Also add test_generic_16.sh to test the new functionality.

Signed-off-by: Ming Lei <ming.lei@redhat.com>
Signed-off-by: Jens Axboe <axboe@kernel.dk>

authored by

Ming Lei and committed by
Jens Axboe
65955a09 93ada1b3

+112
+1
tools/testing/selftests/ublk/Makefile
··· 23 23 TEST_PROGS += test_generic_13.sh 24 24 TEST_PROGS += test_generic_14.sh 25 25 TEST_PROGS += test_generic_15.sh 26 + TEST_PROGS += test_generic_16.sh 26 27 27 28 TEST_PROGS += test_null_01.sh 28 29 TEST_PROGS += test_null_02.sh
+53
tools/testing/selftests/ublk/kublk.c
··· 108 108 return __ublk_ctrl_cmd(dev, &data); 109 109 } 110 110 111 + static int ublk_ctrl_try_stop_dev(struct ublk_dev *dev) 112 + { 113 + struct ublk_ctrl_cmd_data data = { 114 + .cmd_op = UBLK_U_CMD_TRY_STOP_DEV, 115 + }; 116 + 117 + return __ublk_ctrl_cmd(dev, &data); 118 + } 119 + 111 120 static int ublk_ctrl_start_dev(struct ublk_dev *dev, 112 121 int daemon_pid) 113 122 { ··· 1433 1424 return 0; 1434 1425 } 1435 1426 1427 + static int cmd_dev_stop(struct dev_ctx *ctx) 1428 + { 1429 + int number = ctx->dev_id; 1430 + struct ublk_dev *dev; 1431 + int ret; 1432 + 1433 + if (number < 0) { 1434 + ublk_err("%s: device id is required\n", __func__); 1435 + return -EINVAL; 1436 + } 1437 + 1438 + dev = ublk_ctrl_init(); 1439 + dev->dev_info.dev_id = number; 1440 + 1441 + ret = ublk_ctrl_get_info(dev); 1442 + if (ret < 0) 1443 + goto fail; 1444 + 1445 + if (ctx->safe_stop) { 1446 + ret = ublk_ctrl_try_stop_dev(dev); 1447 + if (ret < 0) 1448 + ublk_err("%s: try_stop dev %d failed ret %d\n", 1449 + __func__, number, ret); 1450 + } else { 1451 + ret = ublk_ctrl_stop_dev(dev); 1452 + if (ret < 0) 1453 + ublk_err("%s: stop dev %d failed ret %d\n", 1454 + __func__, number, ret); 1455 + } 1456 + 1457 + fail: 1458 + ublk_ctrl_deinit(dev); 1459 + 1460 + return ret; 1461 + } 1462 + 1436 1463 static int __cmd_dev_list(struct dev_ctx *ctx) 1437 1464 { 1438 1465 struct ublk_dev *dev = ublk_ctrl_init(); ··· 1532 1487 FEAT_NAME(UBLK_F_PER_IO_DAEMON), 1533 1488 FEAT_NAME(UBLK_F_BUF_REG_OFF_DAEMON), 1534 1489 FEAT_NAME(UBLK_F_INTEGRITY), 1490 + FEAT_NAME(UBLK_F_SAFE_STOP_DEV) 1535 1491 }; 1536 1492 struct ublk_dev *dev; 1537 1493 __u64 features = 0; ··· 1662 1616 1663 1617 printf("%s del [-n dev_id] -a \n", exe); 1664 1618 printf("\t -a delete all devices -n delete specified device\n\n"); 1619 + printf("%s stop -n dev_id [--safe]\n", exe); 1620 + printf("\t --safe only stop if device has no active openers\n\n"); 1665 1621 printf("%s list [-n dev_id] -a \n", exe); 1666 1622 printf("\t -a list all devices, -n list specified device, default -a \n\n"); 1667 1623 printf("%s features\n", exe); ··· 1701 1653 { "pi_offset", 1, NULL, 0 }, 1702 1654 { "csum_type", 1, NULL, 0 }, 1703 1655 { "tag_size", 1, NULL, 0 }, 1656 + { "safe", 0, NULL, 0 }, 1704 1657 { 0, 0, 0, 0 } 1705 1658 }; 1706 1659 const struct ublk_tgt_ops *ops = NULL; ··· 1809 1760 } 1810 1761 if (!strcmp(longopts[option_idx].name, "tag_size")) 1811 1762 ctx.tag_size = strtoul(optarg, NULL, 0); 1763 + if (!strcmp(longopts[option_idx].name, "safe")) 1764 + ctx.safe_stop = 1; 1812 1765 break; 1813 1766 case '?': 1814 1767 /* ··· 1893 1842 } 1894 1843 } else if (!strcmp(cmd, "del")) 1895 1844 ret = cmd_dev_del(&ctx); 1845 + else if (!strcmp(cmd, "stop")) 1846 + ret = cmd_dev_stop(&ctx); 1896 1847 else if (!strcmp(cmd, "list")) { 1897 1848 ctx.all = 1; 1898 1849 ret = cmd_dev_list(&ctx);
+1
tools/testing/selftests/ublk/kublk.h
··· 83 83 __u8 pi_offset; 84 84 __u8 csum_type; 85 85 __u8 tag_size; 86 + unsigned int safe_stop:1; 86 87 87 88 int _evtfd; 88 89 int _shmid;
+57
tools/testing/selftests/ublk/test_generic_16.sh
··· 1 + #!/bin/bash 2 + # SPDX-License-Identifier: GPL-2.0 3 + 4 + . "$(cd "$(dirname "$0")" && pwd)"/test_common.sh 5 + 6 + TID="generic_16" 7 + ERR_CODE=0 8 + 9 + _prep_test "null" "stop --safe command" 10 + 11 + # Check if SAFE_STOP_DEV feature is supported 12 + if ! _have_feature "SAFE_STOP_DEV"; then 13 + _cleanup_test "null" 14 + exit "$UBLK_SKIP_CODE" 15 + fi 16 + 17 + # Test 1: stop --safe on idle device should succeed 18 + dev_id=$(_add_ublk_dev -t null -q 2 -d 32) 19 + _check_add_dev $TID $? 20 + 21 + # Device is idle (no openers), stop --safe should succeed 22 + if ! ${UBLK_PROG} stop -n "${dev_id}" --safe; then 23 + echo "stop --safe on idle device failed unexpectedly!" 24 + ERR_CODE=255 25 + fi 26 + 27 + # Clean up device 28 + ${UBLK_PROG} del -n "${dev_id}" > /dev/null 2>&1 29 + udevadm settle 30 + 31 + # Test 2: stop --safe on device with active opener should fail 32 + dev_id=$(_add_ublk_dev -t null -q 2 -d 32) 33 + _check_add_dev $TID $? 34 + 35 + # Open device in background (dd reads indefinitely) 36 + dd if=/dev/ublkb${dev_id} of=/dev/null bs=4k iflag=direct > /dev/null 2>&1 & 37 + dd_pid=$! 38 + 39 + # Give dd time to start 40 + sleep 0.2 41 + 42 + # Device has active opener, stop --safe should fail with -EBUSY 43 + if ${UBLK_PROG} stop -n "${dev_id}" --safe 2>/dev/null; then 44 + echo "stop --safe on busy device succeeded unexpectedly!" 45 + ERR_CODE=255 46 + fi 47 + 48 + # Kill dd and clean up 49 + kill $dd_pid 2>/dev/null 50 + wait $dd_pid 2>/dev/null 51 + 52 + # Now device should be idle, regular delete should work 53 + ${UBLK_PROG} del -n "${dev_id}" 54 + udevadm settle 55 + 56 + _cleanup_test "null" 57 + _show_result $TID $ERR_CODE