diff options
Diffstat (limited to 'src/spdk/test/lvol')
-rwxr-xr-x | src/spdk/test/lvol/basic.sh | 568 | ||||
-rw-r--r-- | src/spdk/test/lvol/common.sh | 53 | ||||
-rwxr-xr-x | src/spdk/test/lvol/hotremove.sh | 216 | ||||
-rwxr-xr-x | src/spdk/test/lvol/lvol2.sh | 19 | ||||
-rwxr-xr-x | src/spdk/test/lvol/rename.sh | 219 | ||||
-rwxr-xr-x | src/spdk/test/lvol/resize.sh | 219 | ||||
-rwxr-xr-x | src/spdk/test/lvol/snapshot_clone.sh | 617 | ||||
-rwxr-xr-x | src/spdk/test/lvol/tasting.sh | 171 | ||||
-rwxr-xr-x | src/spdk/test/lvol/thin_provisioning.sh | 236 |
9 files changed, 2318 insertions, 0 deletions
diff --git a/src/spdk/test/lvol/basic.sh b/src/spdk/test/lvol/basic.sh new file mode 100755 index 000000000..2e25855f9 --- /dev/null +++ b/src/spdk/test/lvol/basic.sh @@ -0,0 +1,568 @@ +#!/usr/bin/env bash + +testdir=$(readlink -f $(dirname $0)) +rootdir=$(readlink -f $testdir/../..) +source $rootdir/test/common/autotest_common.sh +source $rootdir/test/lvol/common.sh +source "$rootdir/test/bdev/nbd_common.sh" + +# create empty lvol store and verify its parameters +function test_construct_lvs() { + # create a malloc bdev + malloc_name=$(rpc_cmd bdev_malloc_create $MALLOC_SIZE_MB $MALLOC_BS) + + # create a valid lvs + lvs_uuid=$(rpc_cmd bdev_lvol_create_lvstore "$malloc_name" lvs_test) + lvs=$(rpc_cmd bdev_lvol_get_lvstores -u "$lvs_uuid") + + # try to destroy inexistent lvs, this should obviously fail + dummy_uuid="00000000-0000-0000-0000-000000000000" + NOT rpc_cmd bdev_lvol_delete_lvstore -u "$dummy_uuid" + # our lvs should not be impacted + rpc_cmd bdev_lvol_get_lvstores -u "$lvs_uuid" + + # verify it's there + [ "$(jq -r '.[0].uuid' <<< "$lvs")" = "$lvs_uuid" ] + [ "$(jq -r '.[0].name' <<< "$lvs")" = "lvs_test" ] + [ "$(jq -r '.[0].base_bdev' <<< "$lvs")" = "$malloc_name" ] + + # verify some of its parameters + cluster_size=$(jq -r '.[0].cluster_size' <<< "$lvs") + [ "$cluster_size" = "$LVS_DEFAULT_CLUSTER_SIZE" ] + total_clusters=$(jq -r '.[0].total_data_clusters' <<< "$lvs") + [ "$(jq -r '.[0].free_clusters' <<< "$lvs")" = "$total_clusters" ] + [ "$((total_clusters * cluster_size))" = "$LVS_DEFAULT_CAPACITY" ] + + # remove the lvs and verify it's gone + rpc_cmd bdev_lvol_delete_lvstore -u "$lvs_uuid" + NOT rpc_cmd bdev_lvol_get_lvstores -u "$lvs_uuid" + # make sure we can't delete the same lvs again + NOT rpc_cmd bdev_lvol_delete_lvstore -u "$lvs_uuid" + + rpc_cmd bdev_malloc_delete "$malloc_name" + check_leftover_devices +} + +# call bdev_lvol_create_lvstore with base bdev name which does not +# exist in configuration +function test_construct_lvs_nonexistent_bdev() { + # make sure we can't create lvol store on nonexistent bdev + rpc_cmd bdev_lvol_create_lvstore NotMalloc lvs_test && false + return 0 +} + +# try to create two lvol stores on the same bdev +function test_construct_two_lvs_on_the_same_bdev() { + # create an lvol store + malloc_name=$(rpc_cmd bdev_malloc_create $MALLOC_SIZE_MB $MALLOC_BS) + lvs_uuid=$(rpc_cmd bdev_lvol_create_lvstore "$malloc_name" lvs_test) + + # try to create another lvs on the same malloc bdev + rpc_cmd bdev_lvol_create_lvstore "$malloc_name" lvs_test2 && false + + # clean up + rpc_cmd bdev_lvol_delete_lvstore -u "$lvs_uuid" + rpc_cmd bdev_lvol_get_lvstores -u "$lvs_uuid" && false + rpc_cmd bdev_malloc_delete "$malloc_name" + rpc_cmd bdev_get_bdevs -b "$malloc_name" && false + check_leftover_devices +} + +# try to create two lvs with conflicting aliases +function test_construct_lvs_conflict_alias() { + # create first bdev and lvs + malloc1_name=$(rpc_cmd construct_malloc_bdev $MALLOC_SIZE_MB $MALLOC_BS) + lvs1_uuid=$(rpc_cmd construct_lvol_store "$malloc1_name" lvs_test) + + # create second bdev and lvs with the same name as previously + malloc2_name=$(rpc_cmd construct_malloc_bdev $MALLOC_SIZE_MB $MALLOC_BS) + rpc_cmd construct_lvol_store "$malloc2_name" lvs_test && false + + # clean up + rpc_cmd destroy_lvol_store -u "$lvs1_uuid" + rpc_cmd get_lvol_stores -u "$lvs1_uuid" && false + rpc_cmd delete_malloc_bdev "$malloc1_name" + rpc_cmd delete_malloc_bdev "$malloc2_name" + check_leftover_devices +} + +# call bdev_lvol_create_lvstore with cluster size equals to malloc bdev size + 1B +# call bdev_lvol_create_lvstore with cluster size smaller than minimal value of 8192 +function test_construct_lvs_different_cluster_size() { + # create the first lvs + malloc1_name=$(rpc_cmd bdev_malloc_create $MALLOC_SIZE_MB $MALLOC_BS) + lvs1_uuid=$(rpc_cmd bdev_lvol_create_lvstore "$malloc1_name" lvs_test) + + # make sure we've got 1 lvs + lvol_stores=$(rpc_cmd bdev_lvol_get_lvstores) + [ "$(jq length <<< "$lvol_stores")" == "1" ] + + # use the second malloc for some more lvs creation negative tests + malloc2_name=$(rpc_cmd bdev_malloc_create $MALLOC_SIZE_MB $MALLOC_BS) + # capacity bigger than malloc's + rpc_cmd bdev_lvol_create_lvstore "$malloc2_name" lvs2_test -c $((MALLOC_SIZE + 1)) && false + # capacity equal to malloc's (no space left for metadata) + rpc_cmd bdev_lvol_create_lvstore "$malloc2_name" lvs2_test -c $MALLOC_SIZE && false + # capacity smaller than malloc's, but still no space left for metadata + rpc_cmd bdev_lvol_create_lvstore "$malloc2_name" lvs2_test -c $((MALLOC_SIZE - 1)) && false + # cluster size smaller than the minimum (8192) + rpc_cmd bdev_lvol_create_lvstore "$malloc2_name" lvs2_test -c 8191 && false + + # no additional lvol stores should have been created + lvol_stores=$(rpc_cmd bdev_lvol_get_lvstores) + [ "$(jq length <<< "$lvol_stores")" == "1" ] + + # this one should be fine + lvs2_uuid=$(rpc_cmd bdev_lvol_create_lvstore "$malloc2_name" lvs2_test -c 8192) + # we should have one more lvs + lvol_stores=$(rpc_cmd bdev_lvol_get_lvstores) + [ "$(jq length <<< "$lvol_stores")" == "2" ] + + # clean up + rpc_cmd bdev_lvol_delete_lvstore -u "$lvs1_uuid" + rpc_cmd bdev_lvol_get_lvstores -u "$lvs1_uuid" && false + + # delete the second lvs (using its name only) + rpc_cmd bdev_lvol_delete_lvstore -l lvs2_test + rpc_cmd bdev_lvol_get_lvstores -l lvs2_test && false + rpc_cmd bdev_lvol_get_lvstores -u "$lvs2_uuid" && false + + rpc_cmd bdev_malloc_delete "$malloc1_name" + rpc_cmd bdev_malloc_delete "$malloc2_name" + check_leftover_devices +} + +# test different methods of clearing the disk on lvolstore creation +function test_construct_lvs_clear_methods() { + malloc_name=$(rpc_cmd bdev_malloc_create $MALLOC_SIZE_MB $MALLOC_BS) + + # first try to provide invalid clear method + rpc_cmd bdev_lvol_create_lvstore "$malloc2_name" lvs2_test --clear-method invalid123 && false + + # no lvs should be created + lvol_stores=$(rpc_cmd bdev_lvol_get_lvstores) + [ "$(jq length <<< "$lvol_stores")" == "0" ] + + methods="none unmap write_zeroes" + for clear_method in $methods; do + lvs_uuid=$(rpc_cmd bdev_lvol_create_lvstore "$malloc_name" lvs_test --clear-method $clear_method) + + # create an lvol on top + lvol_uuid=$(rpc_cmd bdev_lvol_create -u "$lvs_uuid" lvol_test "$LVS_DEFAULT_CAPACITY_MB") + lvol=$(rpc_cmd bdev_get_bdevs -b "$lvol_uuid") + [ "$(jq -r '.[0].name' <<< "$lvol")" = "$lvol_uuid" ] + [ "$(jq -r '.[0].uuid' <<< "$lvol")" = "$lvol_uuid" ] + [ "$(jq -r '.[0].aliases[0]' <<< "$lvol")" = "lvs_test/lvol_test" ] + [ "$(jq -r '.[0].block_size' <<< "$lvol")" = "$MALLOC_BS" ] + [ "$(jq -r '.[0].num_blocks' <<< "$lvol")" = "$((LVS_DEFAULT_CAPACITY / MALLOC_BS))" ] + + # clean up + rpc_cmd bdev_lvol_delete "$lvol_uuid" + rpc_cmd bdev_get_bdevs -b "$lvol_uuid" && false + rpc_cmd bdev_lvol_delete_lvstore -u "$lvs_uuid" + rpc_cmd bdev_lvol_get_lvstores -u "$lvs_uuid" && false + done + rpc_cmd bdev_malloc_delete "$malloc_name" + check_leftover_devices +} + +# Test for clear_method equals to none +function test_construct_lvol_fio_clear_method_none() { + local nbd_name=/dev/nbd0 + local clear_method=none + + local lvstore_name=lvs_test lvstore_uuid + local lvol_name=lvol_test lvol_uuid + local malloc_dev + + malloc_dev=$(rpc_cmd bdev_malloc_create 256 "$MALLOC_BS") + lvstore_uuid=$(rpc_cmd bdev_lvol_create_lvstore "$malloc_dev" "$lvstore_name") + + get_lvs_jq bdev_lvol_get_lvstores -u "$lvstore_uuid" + + lvol_uuid=$(rpc_cmd bdev_lvol_create \ + -c "$clear_method" \ + -u "$lvstore_uuid" \ + "$lvol_name" \ + $((jq_out["cluster_size"] / 1024 ** 2))) + + nbd_start_disks "$DEFAULT_RPC_ADDR" "$lvol_uuid" "$nbd_name" + run_fio_test "$nbd_name" 0 "${jq_out["cluster_size"]}" write 0xdd + nbd_stop_disks "$DEFAULT_RPC_ADDR" "$nbd_name" + + rpc_cmd bdev_lvol_delete "$lvol_uuid" + rpc_cmd bdev_lvol_delete_lvstore -u "$lvstore_uuid" + nbd_start_disks "$DEFAULT_RPC_ADDR" "$malloc_dev" "$nbd_name" + + local metadata_pages + local last_metadata_lba + local offset_metadata_end + local last_cluster_of_metadata + local offset + local size_metadata_end + + metadata_pages=$(calc "1 + ${jq_out["total_data_clusters"]} + ceil(5 + ceil(${jq_out["total_data_clusters"]} / 8) / 4096) * 3") + + last_metadata_lba=$((metadata_pages * 4096 / MALLOC_BS)) + offset_metadata_end=$((last_metadata_lba * MALLOC_BS)) + last_cluster_of_metadata=$(calc "ceil($metadata_pages / ${jq_out["cluster_size"]} / 4096)") + last_cluster_of_metadata=$((last_cluster_of_metadata == 0 ? 1 : last_cluster_of_metadata)) + offset=$((last_cluster_of_metadata * jq_out["cluster_size"])) + size_metadata_end=$((offset - offset_metadata_end)) + + # Check if data on area between end of metadata and first cluster of lvol bdev remained unchaged. + run_fio_test "$nbd_name" "$offset_metadata_end" "$size_metadata_end" "read" 0x00 + # Check if data on first lvol bdevs remains unchanged. + run_fio_test "$nbd_name" "$offset" "${jq_out["cluster_size"]}" "read" 0xdd + + nbd_stop_disks "$DEFAULT_RPC_ADDR" "$nbd_name" + rpc_cmd bdev_malloc_delete "$malloc_dev" + + check_leftover_devices +} + +# Test for clear_method equals to unmap +function test_construct_lvol_fio_clear_method_unmap() { + local nbd_name=/dev/nbd0 + local clear_method=unmap + + local lvstore_name=lvs_test lvstore_uuid + local lvol_name=lvol_test lvol_uuid + local malloc_dev + + malloc_dev=$(rpc_cmd bdev_malloc_create 256 "$MALLOC_BS") + + nbd_start_disks "$DEFAULT_RPC_ADDR" "$malloc_dev" "$nbd_name" + run_fio_test "$nbd_name" 0 $((256 * 1024 ** 2)) write 0xdd + nbd_stop_disks "$DEFAULT_RPC_ADDR" "$nbd_name" + + lvstore_uuid=$(rpc_cmd bdev_lvol_create_lvstore --clear-method none "$malloc_dev" "$lvstore_name") + get_lvs_jq bdev_lvol_get_lvstores -u "$lvstore_uuid" + + lvol_uuid=$(rpc_cmd bdev_lvol_create \ + -c "$clear_method" \ + -u "$lvstore_uuid" \ + "$lvol_name" \ + $((jq_out["cluster_size"] / 1024 ** 2))) + + nbd_start_disks "$DEFAULT_RPC_ADDR" "$lvol_uuid" "$nbd_name" + run_fio_test "$nbd_name" 0 "${jq_out["cluster_size"]}" read 0xdd + nbd_stop_disks "$DEFAULT_RPC_ADDR" "$nbd_name" + + rpc_cmd bdev_lvol_delete "$lvol_uuid" + rpc_cmd bdev_lvol_delete_lvstore -u "$lvstore_uuid" + nbd_start_disks "$DEFAULT_RPC_ADDR" "$malloc_dev" "$nbd_name" + + local metadata_pages + local last_metadata_lba + local offset_metadata_end + local last_cluster_of_metadata + local offset + local size_metadata_end + + metadata_pages=$(calc "1 + ${jq_out["total_data_clusters"]} + ceil(5 + ceil(${jq_out["total_data_clusters"]} / 8) / 4096) * 3") + + last_metadata_lba=$((metadata_pages * 4096 / MALLOC_BS)) + offset_metadata_end=$((last_metadata_lba * MALLOC_BS)) + last_cluster_of_metadata=$(calc "ceil($metadata_pages / ${jq_out["cluster_size"]} / 4096)") + last_cluster_of_metadata=$((last_cluster_of_metadata == 0 ? 1 : last_cluster_of_metadata)) + offset=$((last_cluster_of_metadata * jq_out["cluster_size"])) + size_metadata_end=$((offset - offset_metadata_end)) + + # Check if data on area between end of metadata and first cluster of lvol bdev remained unchaged. + run_fio_test "$nbd_name" "$offset_metadata_end" "$size_metadata_end" "read" 0xdd + # Check if data on lvol bdev was zeroed. Malloc bdev should zero any data that is unmapped. + run_fio_test "$nbd_name" "$offset" "${jq_out["cluster_size"]}" "read" 0x00 + + nbd_stop_disks "$DEFAULT_RPC_ADDR" "$nbd_name" + rpc_cmd bdev_malloc_delete "$malloc_dev" + + check_leftover_devices +} + +# create lvs + lvol on top, verify lvol's parameters +function test_construct_lvol() { + # create an lvol store + malloc_name=$(rpc_cmd bdev_malloc_create $MALLOC_SIZE_MB $MALLOC_BS) + lvs_uuid=$(rpc_cmd bdev_lvol_create_lvstore "$malloc_name" lvs_test) + + # create an lvol on top + lvol_uuid=$(rpc_cmd bdev_lvol_create -u "$lvs_uuid" lvol_test "$LVS_DEFAULT_CAPACITY_MB") + lvol=$(rpc_cmd bdev_get_bdevs -b "$lvol_uuid") + + [ "$(jq -r '.[0].name' <<< "$lvol")" = "$lvol_uuid" ] + [ "$(jq -r '.[0].uuid' <<< "$lvol")" = "$lvol_uuid" ] + [ "$(jq -r '.[0].aliases[0]' <<< "$lvol")" = "lvs_test/lvol_test" ] + [ "$(jq -r '.[0].block_size' <<< "$lvol")" = "$MALLOC_BS" ] + [ "$(jq -r '.[0].num_blocks' <<< "$lvol")" = "$((LVS_DEFAULT_CAPACITY / MALLOC_BS))" ] + [ "$(jq -r '.[0].driver_specific.lvol.lvol_store_uuid' <<< "$lvol")" = "$lvs_uuid" ] + + # clean up and create another lvol, this time use lvs alias instead of uuid + rpc_cmd bdev_lvol_delete "$lvol_uuid" + rpc_cmd bdev_get_bdevs -b "$lvol_uuid" && false + lvol_uuid=$(rpc_cmd bdev_lvol_create -l lvs_test lvol_test "$LVS_DEFAULT_CAPACITY_MB") + lvol=$(rpc_cmd bdev_get_bdevs -b "$lvol_uuid") + + [ "$(jq -r '.[0].name' <<< "$lvol")" = "$lvol_uuid" ] + [ "$(jq -r '.[0].uuid' <<< "$lvol")" = "$lvol_uuid" ] + [ "$(jq -r '.[0].aliases[0]' <<< "$lvol")" = "lvs_test/lvol_test" ] + [ "$(jq -r '.[0].block_size' <<< "$lvol")" = "$MALLOC_BS" ] + [ "$(jq -r '.[0].num_blocks' <<< "$lvol")" = "$((LVS_DEFAULT_CAPACITY / MALLOC_BS))" ] + [ "$(jq -r '.[0].driver_specific.lvol.lvol_store_uuid' <<< "$lvol")" = "$lvs_uuid" ] + + # clean up + rpc_cmd bdev_lvol_delete "$lvol_uuid" + rpc_cmd bdev_get_bdevs -b "$lvol_uuid" && false + rpc_cmd bdev_lvol_delete_lvstore -u "$lvs_uuid" + rpc_cmd bdev_lvol_get_lvstores -u "$lvs_uuid" && false + rpc_cmd bdev_malloc_delete "$malloc_name" + check_leftover_devices +} + +# create lvs + multiple lvols, verify their params +function test_construct_multi_lvols() { + # create an lvol store + malloc_name=$(rpc_cmd bdev_malloc_create $MALLOC_SIZE_MB $MALLOC_BS) + lvs_uuid=$(rpc_cmd bdev_lvol_create_lvstore "$malloc_name" lvs_test) + + # create 4 lvols + lvol_size_mb=$((LVS_DEFAULT_CAPACITY_MB / 4)) + # round down lvol size to the nearest cluster size boundary + lvol_size_mb=$((lvol_size_mb / LVS_DEFAULT_CLUSTER_SIZE_MB * LVS_DEFAULT_CLUSTER_SIZE_MB)) + lvol_size=$((lvol_size_mb * 1024 * 1024)) + for i in $(seq 1 4); do + lvol_uuid=$(rpc_cmd bdev_lvol_create -u "$lvs_uuid" "lvol_test${i}" "$lvol_size_mb") + lvol=$(rpc_cmd bdev_get_bdevs -b "$lvol_uuid") + + [ "$(jq -r '.[0].name' <<< "$lvol")" = "$lvol_uuid" ] + [ "$(jq -r '.[0].uuid' <<< "$lvol")" = "$lvol_uuid" ] + [ "$(jq -r '.[0].aliases[0]' <<< "$lvol")" = "lvs_test/lvol_test${i}" ] + [ "$(jq -r '.[0].block_size' <<< "$lvol")" = "$MALLOC_BS" ] + [ "$(jq -r '.[0].num_blocks' <<< "$lvol")" = "$((lvol_size / MALLOC_BS))" ] + done + + lvols=$(rpc_cmd bdev_get_bdevs | jq -r '[ .[] | select(.product_name == "Logical Volume") ]') + [ "$(jq length <<< "$lvols")" == "4" ] + + # remove all lvols + for i in $(seq 0 3); do + lvol_uuid=$(jq -r ".[$i].name" <<< "$lvols") + rpc_cmd bdev_lvol_delete "$lvol_uuid" + done + lvols=$(rpc_cmd bdev_get_bdevs | jq -r '[ .[] | select(.product_name == "Logical Volume") ]') + [ "$(jq length <<< "$lvols")" == "0" ] + + # create the same 4 lvols again and perform the same checks + for i in $(seq 1 4); do + lvol_uuid=$(rpc_cmd bdev_lvol_create -u "$lvs_uuid" "lvol_test${i}" "$lvol_size_mb") + lvol=$(rpc_cmd bdev_get_bdevs -b "$lvol_uuid") + + [ "$(jq -r '.[0].name' <<< "$lvol")" = "$lvol_uuid" ] + [ "$(jq -r '.[0].uuid' <<< "$lvol")" = "$lvol_uuid" ] + [ "$(jq -r '.[0].aliases[0]' <<< "$lvol")" = "lvs_test/lvol_test${i}" ] + [ "$(jq -r '.[0].block_size' <<< "$lvol")" = "$MALLOC_BS" ] + [ "$(jq -r '.[0].num_blocks' <<< "$lvol")" = "$((lvol_size / MALLOC_BS))" ] + done + + lvols=$(rpc_cmd bdev_get_bdevs | jq -r '[ .[] | select(.product_name == "Logical Volume") ]') + [ "$(jq length <<< "$lvols")" == "4" ] + + # clean up + for i in $(seq 0 3); do + lvol_uuid=$(jq -r ".[$i].name" <<< "$lvols") + rpc_cmd bdev_lvol_delete "$lvol_uuid" + done + lvols=$(rpc_cmd bdev_get_bdevs | jq -r '[ .[] | select(.product_name == "Logical Volume") ]') + [ "$(jq length <<< "$lvols")" == "0" ] + + rpc_cmd bdev_lvol_delete_lvstore -u "$lvs_uuid" + rpc_cmd bdev_lvol_get_lvstores -u "$lvs_uuid" && false + rpc_cmd bdev_malloc_delete "$malloc_name" + check_leftover_devices +} + +# create 2 lvolstores, each with a single lvol on top. +# use a single alias for both lvols, there should be no conflict +# since they're in different lvolstores +function test_construct_lvols_conflict_alias() { + # create an lvol store 1 + malloc1_name=$(rpc_cmd bdev_malloc_create $MALLOC_SIZE_MB $MALLOC_BS) + lvs1_uuid=$(rpc_cmd bdev_lvol_create_lvstore "$malloc1_name" lvs_test1) + + # create an lvol on lvs1 + lvol1_uuid=$(rpc_cmd bdev_lvol_create -l lvs_test1 lvol_test "$LVS_DEFAULT_CAPACITY_MB") + lvol1=$(rpc_cmd bdev_get_bdevs -b "$lvol1_uuid") + + # use a different size for second malloc to keep those differentiable + malloc2_size_mb=$((MALLOC_SIZE_MB / 2)) + + # create an lvol store 2 + malloc2_name=$(rpc_cmd bdev_malloc_create $malloc2_size_mb $MALLOC_BS) + lvs2_uuid=$(rpc_cmd bdev_lvol_create_lvstore "$malloc2_name" lvs_test2) + + lvol2_size_mb=$(round_down $((LVS_DEFAULT_CAPACITY_MB / 2))) + + # create an lvol on lvs2 + lvol2_uuid=$(rpc_cmd bdev_lvol_create -l lvs_test2 lvol_test "$lvol2_size_mb") + lvol2=$(rpc_cmd bdev_get_bdevs -b "$lvol2_uuid") + + [ "$(jq -r '.[0].name' <<< "$lvol1")" = "$lvol1_uuid" ] + [ "$(jq -r '.[0].uuid' <<< "$lvol1")" = "$lvol1_uuid" ] + [ "$(jq -r '.[0].aliases[0]' <<< "$lvol1")" = "lvs_test1/lvol_test" ] + [ "$(jq -r '.[0].driver_specific.lvol.lvol_store_uuid' <<< "$lvol1")" = "$lvs1_uuid" ] + + [ "$(jq -r '.[0].name' <<< "$lvol2")" = "$lvol2_uuid" ] + [ "$(jq -r '.[0].uuid' <<< "$lvol2")" = "$lvol2_uuid" ] + [ "$(jq -r '.[0].aliases[0]' <<< "$lvol2")" = "lvs_test2/lvol_test" ] + [ "$(jq -r '.[0].driver_specific.lvol.lvol_store_uuid' <<< "$lvol2")" = "$lvs2_uuid" ] + + # clean up + rpc_cmd bdev_lvol_delete_lvstore -u "$lvs1_uuid" + rpc_cmd bdev_lvol_get_lvstores -u "$lvs1_uuid" && false + rpc_cmd bdev_lvol_delete_lvstore -u "$lvs2_uuid" + rpc_cmd bdev_lvol_get_lvstores -u "$lvs2_uuid" && false + rpc_cmd bdev_malloc_delete "$malloc1_name" + rpc_cmd bdev_get_bdevs -b "$malloc1_name" && false + rpc_cmd bdev_malloc_delete "$malloc2_name" + check_leftover_devices +} + +# try to create an lvol on inexistent lvs uuid +function test_construct_lvol_inexistent_lvs() { + # create an lvol store + malloc_name=$(rpc_cmd bdev_malloc_create $MALLOC_SIZE_MB $MALLOC_BS) + lvs_uuid=$(rpc_cmd bdev_lvol_create_lvstore "$malloc_name" lvs_test) + + # try to create an lvol on inexistent lvs + dummy_uuid="00000000-0000-0000-0000-000000000000" + rpc_cmd bdev_lvol_create -u "$dummy_uuid" lvol_test "$LVS_DEFAULT_CAPACITY_MB" && false + + lvols=$(rpc_cmd bdev_get_bdevs | jq -r '[ .[] | select(.product_name == "Logical Volume") ]') + [ "$(jq length <<< "$lvols")" == "0" ] + + # clean up + rpc_cmd bdev_lvol_delete_lvstore -u "$lvs_uuid" + rpc_cmd bdev_lvol_get_lvstores -u "$lvs_uuid" && false + rpc_cmd bdev_malloc_delete "$malloc_name" + check_leftover_devices +} + +# try to create lvol on full lvs +function test_construct_lvol_full_lvs() { + # create an lvol store + malloc_name=$(rpc_cmd bdev_malloc_create $MALLOC_SIZE_MB $MALLOC_BS) + lvs_uuid=$(rpc_cmd bdev_lvol_create_lvstore "$malloc_name" lvs_test) + + # create valid lvol + lvol1_uuid=$(rpc_cmd bdev_lvol_create -l lvs_test lvol_test1 "$LVS_DEFAULT_CAPACITY_MB") + lvol1=$(rpc_cmd bdev_get_bdevs -b "$lvol1_uuid") + + # try to create an lvol on lvs without enough free clusters + rpc_cmd bdev_lvol_create -l lvs_test lvol_test2 1 && false + + # clean up + rpc_cmd bdev_lvol_delete_lvstore -u "$lvs_uuid" + rpc_cmd bdev_lvol_get_lvstores -u "$lvs_uuid" && false + rpc_cmd bdev_malloc_delete "$malloc_name" + check_leftover_devices +} + +# try to create two lvols with conflicting aliases +function test_construct_lvol_alias_conflict() { + # create an lvol store + malloc_name=$(rpc_cmd bdev_malloc_create $MALLOC_SIZE_MB $MALLOC_BS) + lvs_uuid=$(rpc_cmd bdev_lvol_create_lvstore "$malloc_name" lvs_test) + + # create valid lvol + lvol_size_mb=$(round_down $((LVS_DEFAULT_CAPACITY_MB / 2))) + lvol1_uuid=$(rpc_cmd bdev_lvol_create -l lvs_test lvol_test "$lvol_size_mb") + lvol1=$(rpc_cmd bdev_get_bdevs -b "$lvol1_uuid") + + # try to create another lvol with a name that's already taken + rpc_cmd bdev_lvol_create -l lvs_test lvol_test "$lvol_size_mb" && false + + # clean up + rpc_cmd bdev_lvol_delete_lvstore -u "$lvs_uuid" + rpc_cmd bdev_lvol_get_lvstores -u "$lvs_uuid" && false + rpc_cmd bdev_malloc_delete "$malloc_name" + rpc_cmd bdev_get_bdevs -b "$malloc_name" && false + check_leftover_devices +} + +# create an lvs+lvol, create another lvs on lvol and then a nested lvol +function test_construct_nested_lvol() { + # create an lvol store + malloc_name=$(rpc_cmd bdev_malloc_create $MALLOC_SIZE_MB $MALLOC_BS) + lvs_uuid=$(rpc_cmd bdev_lvol_create_lvstore "$malloc_name" lvs_test) + + # create an lvol on top + lvol_uuid=$(rpc_cmd bdev_lvol_create -u "$lvs_uuid" lvol_test "$LVS_DEFAULT_CAPACITY_MB") + # create a nested lvs + nested_lvs_uuid=$(rpc_cmd bdev_lvol_create_lvstore "$lvol_uuid" nested_lvs) + + nested_lvol_size_mb=$((LVS_DEFAULT_CAPACITY_MB - LVS_DEFAULT_CLUSTER_SIZE_MB)) + nested_lvol_size=$((nested_lvol_size_mb * 1024 * 1024)) + + # create a nested lvol + nested_lvol1_uuid=$(rpc_cmd bdev_lvol_create -u "$nested_lvs_uuid" nested_lvol1 "$nested_lvol_size_mb") + nested_lvol1=$(rpc_cmd bdev_get_bdevs -b "$nested_lvol1_uuid") + + [ "$(jq -r '.[0].name' <<< "$nested_lvol1")" = "$nested_lvol1_uuid" ] + [ "$(jq -r '.[0].uuid' <<< "$nested_lvol1")" = "$nested_lvol1_uuid" ] + [ "$(jq -r '.[0].aliases[0]' <<< "$nested_lvol1")" = "nested_lvs/nested_lvol1" ] + [ "$(jq -r '.[0].block_size' <<< "$nested_lvol1")" = "$MALLOC_BS" ] + [ "$(jq -r '.[0].num_blocks' <<< "$nested_lvol1")" = "$((nested_lvol_size / MALLOC_BS))" ] + [ "$(jq -r '.[0].driver_specific.lvol.lvol_store_uuid' <<< "$nested_lvol1")" = "$nested_lvs_uuid" ] + + # try to create another nested lvol on a lvs that's already full + rpc_cmd bdev_lvol_create -u "$nested_lvs_uuid" nested_lvol2 "$nested_lvol_size_mb" && false + + # clean up + rpc_cmd bdev_lvol_delete "$nested_lvol1_uuid" + rpc_cmd bdev_get_bdevs -b "$nested_lvol1_uuid" && false + rpc_cmd bdev_lvol_delete_lvstore -u "$nested_lvs_uuid" + rpc_cmd bdev_lvol_get_lvstores -u "$nested_lvs_uuid" && false + rpc_cmd bdev_lvol_delete "$lvol_uuid" + rpc_cmd bdev_get_bdevs -b "$lvol_uuid" && false + rpc_cmd bdev_lvol_delete_lvstore -u "$lvs_uuid" + rpc_cmd bdev_lvol_get_lvstores -u "$lvs_uuid" && false + rpc_cmd bdev_malloc_delete "$malloc_name" + check_leftover_devices +} + +# Send SIGTERM after creating lvol store +function test_sigterm() { + # create an lvol store + malloc_name=$(rpc_cmd bdev_malloc_create $MALLOC_SIZE_MB $MALLOC_BS) + lvs_uuid=$(rpc_cmd bdev_lvol_create_lvstore "$malloc_name" lvs_test) + + # Send SIGTERM signal to the application + killprocess $spdk_pid +} + +$SPDK_BIN_DIR/spdk_tgt & +spdk_pid=$! +trap 'killprocess "$spdk_pid"; exit 1' SIGINT SIGTERM EXIT +waitforlisten $spdk_pid + +run_test "test_construct_lvs" test_construct_lvs +run_test "test_construct_lvs_nonexistent_bdev" test_construct_lvs_nonexistent_bdev +run_test "test_construct_two_lvs_on_the_same_bdev" test_construct_two_lvs_on_the_same_bdev +run_test "test_construct_lvs_conflict_alias" test_construct_lvs_conflict_alias +run_test "test_construct_lvs_different_cluster_size" test_construct_lvs_different_cluster_size +run_test "test_construct_lvs_clear_methods" test_construct_lvs_clear_methods +run_test "test_construct_lvol_fio_clear_method_none" test_construct_lvol_fio_clear_method_none +run_test "test_construct_lvol_fio_clear_method_unmap" test_construct_lvol_fio_clear_method_unmap +run_test "test_construct_lvol" test_construct_lvol +run_test "test_construct_multi_lvols" test_construct_multi_lvols +run_test "test_construct_lvols_conflict_alias" test_construct_lvols_conflict_alias +run_test "test_construct_lvol_inexistent_lvs" test_construct_lvol_inexistent_lvs +run_test "test_construct_lvol_full_lvs" test_construct_lvol_full_lvs +run_test "test_construct_lvol_alias_conflict" test_construct_lvol_alias_conflict +run_test "test_construct_nested_lvol" test_construct_nested_lvol +run_test "test_sigterm" test_sigterm + +trap - SIGINT SIGTERM EXIT +if ps -p $spdk_pid; then + killprocess $spdk_pid +fi diff --git a/src/spdk/test/lvol/common.sh b/src/spdk/test/lvol/common.sh new file mode 100644 index 000000000..b0fd119b3 --- /dev/null +++ b/src/spdk/test/lvol/common.sh @@ -0,0 +1,53 @@ +MALLOC_SIZE_MB=128 +MALLOC_BS=512 +AIO_SIZE_MB=400 +AIO_BS=4096 +LVS_DEFAULT_CLUSTER_SIZE_MB=4 +LVS_DEFAULT_CLUSTER_SIZE=$((LVS_DEFAULT_CLUSTER_SIZE_MB * 1024 * 1024)) +# reserve some MBs for lvolstore metadata +LVS_DEFAULT_CAPACITY_MB=$((MALLOC_SIZE_MB - LVS_DEFAULT_CLUSTER_SIZE_MB)) +LVS_DEFAULT_CAPACITY=$((LVS_DEFAULT_CAPACITY_MB * 1024 * 1024)) + +function get_bdev_jq() { + rpc_cmd_simple_data_json bdev "$@" +} + +function get_lvs_jq() { + rpc_cmd_simple_data_json lvs "$@" +} + +function check_leftover_devices() { + leftover_bdevs=$(rpc_cmd bdev_get_bdevs) + [ "$(jq length <<< "$leftover_bdevs")" == "0" ] + leftover_lvs=$(rpc_cmd bdev_lvol_get_lvstores) + [ "$(jq length <<< "$leftover_lvs")" == "0" ] +} + +function round_down() { + local CLUSTER_SIZE_MB=$LVS_DEFAULT_CLUSTER_SIZE_MB + if [ -n "$2" ]; then + CLUSTER_SIZE_MB=$2 + fi + echo $(($1 / CLUSTER_SIZE_MB * CLUSTER_SIZE_MB)) +} + +function run_fio_test() { + local file=$1 + local offset=$2 + local size=$3 + local rw=$4 + local pattern=$5 + local extra_params=$6 + + local pattern_template="" fio_template="" + if [[ -n "$pattern" ]]; then + pattern_template="--do_verify=1 --verify=pattern --verify_pattern=$pattern --verify_state_save=0" + fi + + fio_template="fio --name=fio_test --filename=$file --offset=$offset --size=$size --rw=$rw --direct=1 $extra_params $pattern_template" + $fio_template +} + +function calc() { + bc -l <<< "define ceil(x) { scale=0; return(x + (x % 1 > 0))/1 } $1" +} diff --git a/src/spdk/test/lvol/hotremove.sh b/src/spdk/test/lvol/hotremove.sh new file mode 100755 index 000000000..8306b301c --- /dev/null +++ b/src/spdk/test/lvol/hotremove.sh @@ -0,0 +1,216 @@ +#!/usr/bin/env bash + +testdir=$(readlink -f $(dirname $0)) +rootdir=$(readlink -f $testdir/../..) +source $rootdir/test/common/autotest_common.sh +source $rootdir/test/lvol/common.sh + +# create an lvol on lvs, then remove the lvs +function test_hotremove_lvol_store() { + # create lvs + lvol on top + malloc_name=$(rpc_cmd bdev_malloc_create $MALLOC_SIZE_MB $MALLOC_BS) + lvs_uuid=$(rpc_cmd bdev_lvol_create_lvstore "$malloc_name" lvs_test) + lvol_uuid=$(rpc_cmd bdev_lvol_create -u "$lvs_uuid" lvol_test "$LVS_DEFAULT_CAPACITY_MB") + + # remove lvs (with one lvol open) + rpc_cmd bdev_lvol_delete_lvstore -u "$lvs_uuid" + rpc_cmd bdev_lvol_get_lvstores -u "$lvs_uuid" && false + lvolstores=$(rpc_cmd bdev_lvol_get_lvstores) + [ "$(jq length <<< "$lvolstores")" == "0" ] + + # make sure we can't destroy the lvs again + rpc_cmd bdev_lvol_delete_lvstore -u "$lvs_uuid" && false + + # make sure the lvol is also gone + rpc_cmd bdev_get_bdevs -b "$lvol_uuid" && false + lvols=$(rpc_cmd bdev_get_bdevs | jq -r '[ .[] | select(.product_name == "Logical Volume") ]') + [ "$(jq length <<< "$lvols")" == "0" ] + + # clean up + rpc_cmd bdev_malloc_delete "$malloc_name" + check_leftover_devices +} + +# destroy lvs with 4 lvols on top +function test_hotremove_lvol_store_multiple_lvols() { + # create lvs + malloc_name=$(rpc_cmd bdev_malloc_create $MALLOC_SIZE_MB $MALLOC_BS) + lvs_uuid=$(rpc_cmd bdev_lvol_create_lvstore "$malloc_name" lvs_test) + + # calculate lvol size + lvol_size_mb=$(round_down $(((MALLOC_SIZE_MB - LVS_DEFAULT_CLUSTER_SIZE_MB) / 4))) + + # create 4 lvols + for i in $(seq 1 4); do + rpc_cmd bdev_lvol_create -u "$lvs_uuid" "lvol_test${i}" "$lvol_size_mb" + done + + lvols=$(rpc_cmd bdev_get_bdevs | jq -r '[ .[] | select(.product_name == "Logical Volume") ]') + [ "$(jq length <<< "$lvols")" == "4" ] + + # remove lvs (with 4 lvols open) + rpc_cmd bdev_lvol_delete_lvstore -u "$lvs_uuid" + rpc_cmd bdev_lvol_get_lvstores -u "$lvs_uuid" && false + + # make sure all lvols are gone + lvols=$(rpc_cmd bdev_get_bdevs | jq -r '[ .[] | select(.product_name == "Logical Volume") ]') + [ "$(jq length <<< "$lvols")" == "0" ] + + # clean up + rpc_cmd bdev_malloc_delete "$malloc_name" + check_leftover_devices +} + +# create an lvs on malloc, then remove just the malloc +function test_hotremove_lvol_store_base() { + # create lvs + lvol on top + malloc_name=$(rpc_cmd bdev_malloc_create $MALLOC_SIZE_MB $MALLOC_BS) + lvs_uuid=$(rpc_cmd bdev_lvol_create_lvstore "$malloc_name" lvs_test) + + # clean up + rpc_cmd bdev_malloc_delete "$malloc_name" + # make sure the lvs is gone + rpc_cmd bdev_lvol_get_lvstores -u "$lvs_uuid" && false + # make sure we can't delete the lvs again + rpc_cmd bdev_lvol_delete_lvstore -u "$lvs_uuid" && false + check_leftover_devices +} + +# create an lvs on malloc, then an lvol, then remove just the malloc +function test_hotremove_lvol_store_base_with_lvols() { + # create lvs + lvol on top + malloc_name=$(rpc_cmd bdev_malloc_create $MALLOC_SIZE_MB $MALLOC_BS) + lvs_uuid=$(rpc_cmd bdev_lvol_create_lvstore "$malloc_name" lvs_test) + lvol_uuid=$(rpc_cmd bdev_lvol_create -u "$lvs_uuid" lvol_test "$LVS_DEFAULT_CAPACITY_MB") + + rpc_cmd bdev_get_bdevs -b "$lvol_uuid" + + # clean up + rpc_cmd bdev_malloc_delete "$malloc_name" + # make sure the lvol is gone + rpc_cmd bdev_get_bdevs -b "$lvol_uuid" && false + # make sure the lvs is gone as well + rpc_cmd bdev_lvol_get_lvstores -u "$lvs_uuid" && false + + # make sure we can't delete the lvs again + rpc_cmd bdev_lvol_delete_lvstore -u "$lvs_uuid" && false + check_leftover_devices +} + +function test_bdev_lvol_delete_lvstore_with_clones() { + local snapshot_name1=snapshot1 snapshot_uuid1 + local snapshot_name2=snapshot2 snapshot_uuid2 + local clone_name=clone clone_uuid + local lbd_name=lbd_test + + local bdev_uuid + local lvstore_name=lvs_name lvstore_uuid + local malloc_dev + + malloc_dev=$(rpc_cmd bdev_malloc_create 256 "$MALLOC_BS") + lvstore_uuid=$(rpc_cmd bdev_lvol_create_lvstore "$malloc_dev" "$lvstore_name") + + get_lvs_jq bdev_lvol_get_lvstores -u "$lvstore_uuid" + [[ ${jq_out["uuid"]} == "$lvstore_uuid" ]] + [[ ${jq_out["name"]} == "$lvstore_name" ]] + [[ ${jq_out["base_bdev"]} == "$malloc_dev" ]] + + size=$((jq_out["free_clusters"] * jq_out["cluster_size"] / 4 / 1024 ** 2)) + + bdev_uuid=$(rpc_cmd bdev_lvol_create -u "$lvstore_uuid" "$lbd_name" "$size") + + get_bdev_jq bdev_get_bdevs -b "$bdev_uuid" + + snapshot_uuid1=$(rpc_cmd bdev_lvol_snapshot "${jq_out["name"]}" "$snapshot_name1") + + get_bdev_jq bdev_get_bdevs -b "$lvstore_name/$snapshot_name1" + [[ ${jq_out["name"]} == "$snapshot_uuid1" ]] + [[ ${jq_out["product_name"]} == "Logical Volume" ]] + [[ ${jq_out["aliases[0]"]} == "$lvstore_name/$snapshot_name1" ]] + + clone_uuid=$(rpc_cmd bdev_lvol_clone "$lvstore_name/$snapshot_name1" "$clone_name") + + get_bdev_jq bdev_get_bdevs -b "$lvstore_name/$clone_name" + [[ ${jq_out["name"]} == "$clone_uuid" ]] + [[ ${jq_out["product_name"]} == "Logical Volume" ]] + [[ ${jq_out["aliases[0]"]} == "$lvstore_name/$clone_name" ]] + + snapshot_uuid2=$(rpc_cmd bdev_lvol_snapshot "${jq_out["name"]}" "$snapshot_name2") + + get_bdev_jq bdev_get_bdevs -b "$lvstore_name/$snapshot_name2" + [[ ${jq_out["name"]} == "$snapshot_uuid2" ]] + [[ ${jq_out["product_name"]} == "Logical Volume" ]] + [[ ${jq_out["aliases[0]"]} == "$lvstore_name/$snapshot_name2" ]] + + rpc_cmd bdev_lvol_delete "$snapshot_uuid1" && false + rpc_cmd bdev_lvol_delete_lvstore -u "$lvstore_uuid" + rpc_cmd bdev_malloc_delete "$malloc_dev" + + check_leftover_devices +} + +# Test for unregistering the lvol bdevs. Removing malloc bdev under an lvol +# store triggers unregister of all lvol bdevs. Verify it with clones present. +function test_unregister_lvol_bdev() { + local snapshot_name1=snapshot1 snapshot_uuid1 + local snapshot_name2=snapshot2 snapshot_uuid2 + local clone_name=clone clone_uuid + local lbd_name=lbd_test + + local bdev_uuid + local lvstore_name=lvs_name lvstore_uuid + local malloc_dev + + malloc_dev=$(rpc_cmd bdev_malloc_create 256 "$MALLOC_BS") + lvstore_uuid=$(rpc_cmd bdev_lvol_create_lvstore "$malloc_dev" "$lvstore_name") + + get_lvs_jq bdev_lvol_get_lvstores -u "$lvstore_uuid" + [[ ${jq_out["uuid"]} == "$lvstore_uuid" ]] + [[ ${jq_out["name"]} == "$lvstore_name" ]] + [[ ${jq_out["base_bdev"]} == "$malloc_dev" ]] + + size=$((jq_out["free_clusters"] * jq_out["cluster_size"] / 4 / 1024 ** 2)) + + bdev_uuid=$(rpc_cmd bdev_lvol_create -u "$lvstore_uuid" "$lbd_name" "$size") + + get_bdev_jq bdev_get_bdevs -b "$bdev_uuid" + + snapshot_uuid1=$(rpc_cmd bdev_lvol_snapshot "${jq_out["name"]}" "$snapshot_name1") + + get_bdev_jq bdev_get_bdevs -b "$lvstore_name/$snapshot_name1" + [[ ${jq_out["name"]} == "$snapshot_uuid1" ]] + [[ ${jq_out["product_name"]} == "Logical Volume" ]] + [[ ${jq_out["aliases[0]"]} == "$lvstore_name/$snapshot_name1" ]] + + clone_uuid=$(rpc_cmd bdev_lvol_clone "$lvstore_name/$snapshot_name1" "$clone_name") + + get_bdev_jq bdev_get_bdevs -b "$lvstore_name/$clone_name" + [[ ${jq_out["name"]} == "$clone_uuid" ]] + [[ ${jq_out["product_name"]} == "Logical Volume" ]] + [[ ${jq_out["aliases[0]"]} == "$lvstore_name/$clone_name" ]] + + snapshot_uuid2=$(rpc_cmd bdev_lvol_snapshot "${jq_out["name"]}" "$snapshot_name2") + + get_bdev_jq bdev_get_bdevs -b "$lvstore_name/$snapshot_name2" + [[ ${jq_out["name"]} == "$snapshot_uuid2" ]] + [[ ${jq_out["product_name"]} == "Logical Volume" ]] + [[ ${jq_out["aliases[0]"]} == "$lvstore_name/$snapshot_name2" ]] + + rpc_cmd bdev_malloc_delete "$malloc_dev" + check_leftover_devices +} + +$SPDK_BIN_DIR/spdk_tgt & +spdk_pid=$! +trap 'killprocess "$spdk_pid"; exit 1' SIGINT SIGTERM EXIT +waitforlisten $spdk_pid + +run_test "test_hotremove_lvol_store" test_hotremove_lvol_store +run_test "test_hotremove_lvol_store_multiple_lvols" test_hotremove_lvol_store_multiple_lvols +run_test "test_hotremove_lvol_store_base" test_hotremove_lvol_store_base +run_test "test_hotremove_lvol_store_base_with_lvols" test_hotremove_lvol_store_base_with_lvols +run_test "test_bdev_lvol_delete_lvstore_with_clones" test_bdev_lvol_delete_lvstore_with_clones +run_test "test_unregister_lvol_bdev" test_unregister_lvol_bdev + +trap - SIGINT SIGTERM EXIT +killprocess $spdk_pid diff --git a/src/spdk/test/lvol/lvol2.sh b/src/spdk/test/lvol/lvol2.sh new file mode 100755 index 000000000..3c33ca64b --- /dev/null +++ b/src/spdk/test/lvol/lvol2.sh @@ -0,0 +1,19 @@ +#!/usr/bin/env bash + +testdir=$(readlink -f $(dirname $0)) +rootdir=$(readlink -f $testdir/../..) +source $rootdir/test/common/autotest_common.sh + +timing_enter lvol + +timing_enter basic +run_test "lvol_basic" test/lvol/basic.sh +run_test "lvol_resize" test/lvol/resize.sh +run_test "lvol_hotremove" test/lvol/hotremove.sh +run_test "lvol_tasting" test/lvol/tasting.sh +run_test "lvol_snapshot_clone" test/lvol/snapshot_clone.sh +run_test "lvol_rename" test/lvol/rename.sh +run_test "lvol_provisioning" test/lvol/thin_provisioning.sh +timing_exit basic + +timing_exit lvol diff --git a/src/spdk/test/lvol/rename.sh b/src/spdk/test/lvol/rename.sh new file mode 100755 index 000000000..607073c51 --- /dev/null +++ b/src/spdk/test/lvol/rename.sh @@ -0,0 +1,219 @@ +#!/usr/bin/env bash + +testdir=$(readlink -f $(dirname $0)) +rootdir=$(readlink -f $testdir/../..) +source $rootdir/test/common/autotest_common.sh +source $rootdir/test/lvol/common.sh + +# Positive test for lvol store and lvol bdev rename. +function test_rename_positive() { + malloc_name=$(rpc_cmd bdev_malloc_create $MALLOC_SIZE_MB $MALLOC_BS) + lvs_uuid=$(rpc_cmd bdev_lvol_create_lvstore "$malloc_name" lvs_test) + bdev_name=("lvol_test"{0..3}) + bdev_aliases=("lvs_test/lvol_test"{0..3}) + + # Calculate size and create two lvol bdevs on top + lvol_size_mb=$(round_down $((LVS_DEFAULT_CAPACITY_MB / 4))) + lvol_size=$((lvol_size_mb * 1024 * 1024)) + + # Create 4 lvol bdevs on top of previously created lvol store + bdev_uuids=() + for i in "${!bdev_name[@]}"; do + lvol_uuid=$(rpc_cmd bdev_lvol_create -u "$lvs_uuid" "${bdev_name[i]}" "$lvol_size_mb") + lvol=$(rpc_cmd bdev_get_bdevs -b $lvol_uuid) + [ "$(jq -r '.[0].driver_specific.lvol.lvol_store_uuid' <<< "$lvol")" = "$lvs_uuid" ] + [ "$(jq -r '.[0].block_size' <<< "$lvol")" = "$MALLOC_BS" ] + [ "$(jq -r '.[0].num_blocks' <<< "$lvol")" = "$((lvol_size / MALLOC_BS))" ] + [ "$(jq '.[0].aliases|sort' <<< "$lvol")" = "$(jq '.|sort' <<< '["'${bdev_aliases[i]}'"]')" ] + bdev_uuids+=("$lvol_uuid") + done + + # Rename lvol store and check if lvol store name and + # lvol bdev aliases were updated properly + new_lvs_name="lvs_new" + bdev_aliases=("$new_lvs_name/lvol_test"{0..3}) + + rpc_cmd bdev_lvol_rename_lvstore lvs_test "$new_lvs_name" + + lvs=$(rpc_cmd bdev_lvol_get_lvstores -u "$lvs_uuid") + + # verify it's there + [ "$(jq -r '.[0].uuid' <<< "$lvs")" = "$lvs_uuid" ] + [ "$(jq -r '.[0].name' <<< "$lvs")" = "$new_lvs_name" ] + [ "$(jq -r '.[0].base_bdev' <<< "$lvs")" = "$malloc_name" ] + + # verify some of its parameters + cluster_size=$(jq -r '.[0].cluster_size' <<< "$lvs") + [ "$cluster_size" = "$LVS_DEFAULT_CLUSTER_SIZE" ] + total_clusters=$(jq -r '.[0].total_data_clusters' <<< "$lvs") + [ "$((total_clusters * cluster_size))" = "$LVS_DEFAULT_CAPACITY" ] + + for i in "${!bdev_uuids[@]}"; do + lvol=$(rpc_cmd bdev_get_bdevs -b "${bdev_uuids[i]}") + [ "$(jq -r '.[0].driver_specific.lvol.lvol_store_uuid' <<< "$lvol")" = "$lvs_uuid" ] + [ "$(jq -r '.[0].block_size' <<< "$lvol")" = "$MALLOC_BS" ] + [ "$(jq -r '.[0].num_blocks' <<< "$lvol")" = "$((lvol_size / MALLOC_BS))" ] + [ "$(jq -r '.[0].aliases|sort' <<< "$lvol")" = "$(jq '.|sort' <<< '["'${bdev_aliases[i]}'"]')" ] + done + + # Now try to rename the bdevs using their uuid as "old_name" + # Verify that all bdev names were successfully updated + bdev_names=("lbd_new"{0..3}) + new_bdev_aliases=() + for bdev_name in "${bdev_names[@]}"; do + new_bdev_aliases+=("$new_lvs_name/$bdev_name") + done + for i in "${!bdev_names[@]}"; do + rpc_cmd bdev_lvol_rename "${bdev_aliases[i]}" "${bdev_names[i]}" + lvol=$(rpc_cmd bdev_get_bdevs -b "${bdev_uuids[i]}") + [ "$(jq -r '.[0].driver_specific.lvol.lvol_store_uuid' <<< "$lvol")" = "$lvs_uuid" ] + [ "$(jq -r '.[0].block_size' <<< "$lvol")" = "$MALLOC_BS" ] + [ "$(jq -r '.[0].num_blocks' <<< "$lvol")" = "$((lvol_size / MALLOC_BS))" ] + [ "$(jq -r '.[0].aliases|sort' <<< "$lvol")" = "$(jq '.|sort' <<< '["'${new_bdev_aliases[i]}'"]')" ] + done + + # Clean up + for bdev in "${new_bdev_aliases[@]}"; do + rpc_cmd bdev_lvol_delete "$bdev" + done + rpc_cmd bdev_lvol_delete_lvstore -u "$lvs_uuid" + rpc_cmd bdev_malloc_delete "$malloc_name" + check_leftover_devices +} + +# Negative test case for lvol store rename. +# Check that error is returned when trying to rename not existing lvol store. +# Check that error is returned when trying to rename to a name which is already +# used by another lvol store. +function test_rename_lvs_negative() { + # Call bdev_lvol_rename_lvstore with name pointing to not existing lvol store + rpc_cmd bdev_lvol_rename_lvstore NOTEXIST WHATEVER && false + + # Construct two malloc bdevs + malloc_name1=$(rpc_cmd bdev_malloc_create $MALLOC_SIZE_MB $MALLOC_BS) + malloc_name2=$(rpc_cmd bdev_malloc_create $MALLOC_SIZE_MB $MALLOC_BS) + + # Create lvol store on each malloc bdev + lvs_uuid1=$(rpc_cmd bdev_lvol_create_lvstore "$malloc_name1" lvs_test1) + lvs_uuid2=$(rpc_cmd bdev_lvol_create_lvstore "$malloc_name2" lvs_test2) + + # Create lists with lvol bdev names and aliases for later use + bdev_names_1=("lvol_test_1_"{0..3}) + bdev_names_2=("lvol_test_2_"{0..3}) + bdev_aliases_1=("lvs_test1/lvol_test_1_"{0..3}) + bdev_aliases_2=("lvs_test2/lvol_test_2_"{0..3}) + + # Calculate size and create two lvol bdevs on top + lvol_size_mb=$(round_down $((LVS_DEFAULT_CAPACITY_MB / 4))) + lvol_size=$((lvol_size_mb * 1024 * 1024)) + + # # Create 4 lvol bdevs on top of each lvol store + bdev_uuids_1=() + bdev_uuids_2=() + for i in "${!bdev_names_1[@]}"; do + lvol_uuid=$(rpc_cmd bdev_lvol_create -u "$lvs_uuid1" "${bdev_names_1[i]}" "$lvol_size_mb") + lvol=$(rpc_cmd bdev_get_bdevs -b "$lvol_uuid") + [ "$(jq -r '.[0].driver_specific.lvol.lvol_store_uuid' <<< "$lvol")" = "$lvs_uuid1" ] + [ "$(jq -r '.[0].block_size' <<< "$lvol")" = "$MALLOC_BS" ] + [ "$(jq -r '.[0].num_blocks' <<< "$lvol")" = "$((lvol_size / MALLOC_BS))" ] + [ "$(jq '.[0].aliases|sort' <<< "$lvol")" = "$(jq '.|sort' <<< '["'${bdev_aliases_1[i]}'"]')" ] + bdev_uuids_1+=("$lvol_uuid") + + lvol_uuid=$(rpc_cmd bdev_lvol_create -u "$lvs_uuid2" "${bdev_names_2[i]}" "$lvol_size_mb") + lvol=$(rpc_cmd bdev_get_bdevs -b "$lvol_uuid") + [ "$(jq -r '.[0].driver_specific.lvol.lvol_store_uuid' <<< "$lvol")" = "$lvs_uuid2" ] + [ "$(jq -r '.[0].block_size' <<< "$lvol")" = "$MALLOC_BS" ] + [ "$(jq -r '.[0].num_blocks' <<< "$lvol")" = "$((lvol_size / MALLOC_BS))" ] + [ "$(jq '.[0].aliases|sort' <<< "$lvol")" = "$(jq '.|sort' <<< '["'${bdev_aliases_2[i]}'"]')" ] + bdev_uuids_2+=("$lvol_uuid") + done + + # Call bdev_lvol_rename_lvstore on first lvol store and try to change its name to + # the same name as used by second lvol store + rpc_cmd bdev_lvol_rename_lvstore lvs_test1 lvs_test2 && false + + # Verify that names of lvol stores and lvol bdevs did not change + lvs=$(rpc_cmd bdev_lvol_get_lvstores -u "$lvs_uuid1") + [ "$(jq -r '.[0].uuid' <<< "$lvs")" = "$lvs_uuid1" ] + [ "$(jq -r '.[0].name' <<< "$lvs")" = "lvs_test1" ] + [ "$(jq -r '.[0].base_bdev' <<< "$lvs")" = "$malloc_name1" ] + [ "$(jq -r '.[0].cluster_size' <<< "$lvs")" = "$LVS_DEFAULT_CLUSTER_SIZE" ] + lvs=$(rpc_cmd bdev_lvol_get_lvstores -u "$lvs_uuid2") + [ "$(jq -r '.[0].uuid' <<< "$lvs")" = "$lvs_uuid2" ] + [ "$(jq -r '.[0].name' <<< "$lvs")" = "lvs_test2" ] + [ "$(jq -r '.[0].base_bdev' <<< "$lvs")" = "$malloc_name2" ] + [ "$(jq -r '.[0].cluster_size' <<< "$lvs")" = "$LVS_DEFAULT_CLUSTER_SIZE" ] + + for i in "${!bdev_uuids_1[@]}"; do + lvol=$(rpc_cmd bdev_get_bdevs -b "${bdev_uuids_1[i]}") + [ "$(jq -r '.[0].driver_specific.lvol.lvol_store_uuid' <<< "$lvol")" = "$lvs_uuid1" ] + [ "$(jq -r '.[0].block_size' <<< "$lvol")" = "$MALLOC_BS" ] + [ "$(jq -r '.[0].num_blocks' <<< "$lvol")" = "$((lvol_size / MALLOC_BS))" ] + [ "$(jq '.[0].aliases|sort' <<< "$lvol")" = "$(jq '.|sort' <<< '["'${bdev_aliases_1[i]}'"]')" ] + + lvol=$(rpc_cmd bdev_get_bdevs -b "${bdev_uuids_2[i]}") + [ "$(jq -r '.[0].driver_specific.lvol.lvol_store_uuid' <<< "$lvol")" = "$lvs_uuid2" ] + [ "$(jq -r '.[0].block_size' <<< "$lvol")" = "$MALLOC_BS" ] + [ "$(jq -r '.[0].num_blocks' <<< "$lvol")" = "$((lvol_size / MALLOC_BS))" ] + [ "$(jq '.[0].aliases|sort' <<< "$lvol")" = "$(jq '.|sort' <<< '["'${bdev_aliases_2[i]}'"]')" ] + done + + # Clean up + for bdev in "${bdev_aliases_1[@]}" "${bdev_alisaes_2[@]}"; do + rpc_cmd bdev_lvol_delete "$bdev" + done + rpc_cmd bdev_lvol_delete_lvstore -u "$lvs_uuid1" + rpc_cmd bdev_lvol_delete_lvstore -u "$lvs_uuid2" + rpc_cmd bdev_malloc_delete "$malloc_name1" + rpc_cmd bdev_malloc_delete "$malloc_name2" + check_leftover_devices +} + +# Negative test case for lvol bdev rename. +# Check that error is returned when trying to rename not existing lvol bdev +# Check that error is returned when trying to rename to a name which is already +# used by another lvol bdev. +function test_lvol_rename_negative() { + # Call bdev_lvol_rename with name pointing to not existing lvol bdev + rpc_cmd bdev_lvol_rename NOTEXIST WHATEVER && false + + malloc_name=$(rpc_cmd bdev_malloc_create $MALLOC_SIZE_MB $MALLOC_BS) + lvs_uuid=$(rpc_cmd bdev_lvol_create_lvstore "$malloc_name" lvs_test) + + # Calculate lvol bdev size + lvol_size_mb=$(round_down $((LVS_DEFAULT_CAPACITY_MB / 2))) + lvol_size=$((lvol_size_mb * 1024 * 1024)) + + # Create two lvol bdevs on top of previously created lvol store + lvol_uuid1=$(rpc_cmd bdev_lvol_create -u "$lvs_uuid" lvol_test1 "$lvol_size_mb") + lvol_uuid2=$(rpc_cmd bdev_lvol_create -u "$lvs_uuid" lvol_test2 "$lvol_size_mb") + + # Call bdev_lvol_rename on first lvol bdev and try to change its name to + # the same name as used by second lvol bdev + rpc_cmd bdev_lvol_rename lvol_test1 lvol_test2 && false + + # Verify that lvol bdev still have the same names as before + lvol=$(rpc_cmd bdev_get_bdevs -b $lvol_uuid1) + [ "$(jq -r '.[0].driver_specific.lvol.lvol_store_uuid' <<< "$lvol")" = "$lvs_uuid" ] + [ "$(jq -r '.[0].block_size' <<< "$lvol")" = "$MALLOC_BS" ] + [ "$(jq -r '.[0].num_blocks' <<< "$lvol")" = "$((lvol_size / MALLOC_BS))" ] + [ "$(jq -r '.[0].aliases|sort' <<< "$lvol")" = "$(jq '.|sort' <<< '["lvs_test/lvol_test1"]')" ] + + rpc_cmd bdev_lvol_delete lvs_test/lvol_test1 + rpc_cmd bdev_lvol_delete lvs_test/lvol_test2 + rpc_cmd bdev_lvol_delete_lvstore -u "$lvs_uuid" + rpc_cmd bdev_malloc_delete "$malloc_name" + check_leftover_devices +} + +$SPDK_BIN_DIR/spdk_tgt & +spdk_pid=$! +trap 'killprocess "$spdk_pid"; exit 1' SIGINT SIGTERM EXIT +waitforlisten $spdk_pid + +run_test "test_rename_positive" test_rename_positive +run_test "test_rename_lvs_negative" test_rename_lvs_negative +run_test "test_lvol_rename_negative" test_lvol_rename_negative + +trap - SIGINT SIGTERM EXIT +killprocess $spdk_pid diff --git a/src/spdk/test/lvol/resize.sh b/src/spdk/test/lvol/resize.sh new file mode 100755 index 000000000..be0410275 --- /dev/null +++ b/src/spdk/test/lvol/resize.sh @@ -0,0 +1,219 @@ +#!/usr/bin/env bash + +testdir=$(readlink -f $(dirname $0)) +rootdir=$(readlink -f $testdir/../..) +source $rootdir/test/common/autotest_common.sh +source $rootdir/test/lvol/common.sh +source $rootdir/test/bdev/nbd_common.sh + +# resize an lvol a few times +function test_resize_lvol() { + # create an lvol store + malloc_name=$(rpc_cmd bdev_malloc_create $MALLOC_SIZE_MB $MALLOC_BS) + lvs_uuid=$(rpc_cmd bdev_lvol_create_lvstore "$malloc_name" lvs_test) + + # calculate lvol size + lvol_size_mb=$(round_down $((LVS_DEFAULT_CAPACITY_MB / 4))) + lvol_size=$((lvol_size_mb * 1024 * 1024)) + + # create an lvol on top + lvol_uuid=$(rpc_cmd bdev_lvol_create -u "$lvs_uuid" lvol_test "$lvol_size_mb") + lvol=$(rpc_cmd bdev_get_bdevs -b "$lvol_uuid") + [ "$(jq -r '.[0].name' <<< "$lvol")" = "$lvol_uuid" ] + [ "$(jq -r '.[0].uuid' <<< "$lvol")" = "$lvol_uuid" ] + [ "$(jq -r '.[0].aliases[0]' <<< "$lvol")" = "lvs_test/lvol_test" ] + [ "$(jq -r '.[0].block_size' <<< "$lvol")" = "$MALLOC_BS" ] + [ "$(jq -r '.[0].num_blocks' <<< "$lvol")" = "$((lvol_size / MALLOC_BS))" ] + + # resize the lvol to twice its original size + lvol_size_mb=$((lvol_size_mb * 2)) + lvol_size=$((lvol_size_mb * 1024 * 1024)) + rpc_cmd bdev_lvol_resize "$lvol_uuid" "$lvol_size_mb" + lvol=$(rpc_cmd bdev_get_bdevs -b "$lvol_uuid") + [ "$(jq -r '.[0].num_blocks' <<< "$lvol")" = "$((lvol_size / MALLOC_BS))" ] + + # resize the lvol to four times its original size, use its name instead of uuid + lvol_size_mb=$((lvol_size_mb * 2)) + lvol_size=$((lvol_size_mb * 1024 * 1024)) + rpc_cmd bdev_lvol_resize lvs_test/lvol_test "$lvol_size_mb" + lvol=$(rpc_cmd bdev_get_bdevs -b "$lvol_uuid") + [ "$(jq -r '.[0].num_blocks' <<< "$lvol")" = "$((lvol_size / MALLOC_BS))" ] + + # resize the lvol to 0 using lvol bdev alias + lvol_size_mb=0 + lvol_size=0 + rpc_cmd bdev_lvol_resize "lvs_test/lvol_test" "$lvol_size_mb" + lvol=$(rpc_cmd bdev_get_bdevs -b "$lvol_uuid") + [ "$(jq -r '.[0].num_blocks' <<< "$lvol")" = "$((lvol_size / MALLOC_BS))" ] + + # clean up + rpc_cmd bdev_lvol_delete "$lvol_uuid" + rpc_cmd bdev_get_bdevs -b "$lvol_uuid" && false + rpc_cmd bdev_lvol_delete_lvstore -u "$lvs_uuid" + rpc_cmd bdev_lvol_get_lvstores -u "$lvs_uuid" && false + rpc_cmd bdev_malloc_delete "$malloc_name" +} + +# negative test for resizing a logical volume +# call bdev_lvol_resize with logical volume which does not exist in configuration +# call bdev_lvol_resize with size argument bigger than size of base bdev +function test_resize_lvol_negative() { + # create an lvol store + malloc_name=$(rpc_cmd bdev_malloc_create $MALLOC_SIZE_MB $MALLOC_BS) + lvs_uuid=$(rpc_cmd bdev_lvol_create_lvstore "$malloc_name" lvs_test) + + # create an lvol on top + lvol_uuid=$(rpc_cmd bdev_lvol_create -u "$lvs_uuid" lvol_test "$LVS_DEFAULT_CAPACITY_MB") + + # try to resize another, inexistent lvol + dummy_uuid="00000000-0000-0000-0000-000000000000" + rpc_cmd bdev_lvol_resize "$dummy_uuid" 0 && false + # just make sure the size of the real lvol did not change + lvol=$(rpc_cmd bdev_get_bdevs -b "$lvol_uuid") + [ "$(jq -r '.[0].num_blocks' <<< "$lvol")" = "$((LVS_DEFAULT_CAPACITY / MALLOC_BS))" ] + + # try to resize an lvol to a size bigger than lvs + rpc_cmd bdev_lvol_resize "$lvol_uuid" "$MALLOC_SIZE_MB" && false + # just make sure the size of the real lvol did not change + lvol=$(rpc_cmd bdev_get_bdevs -b "$lvol_uuid") + [ "$(jq -r '.[0].num_blocks' <<< "$lvol")" = "$((LVS_DEFAULT_CAPACITY / MALLOC_BS))" ] + + # clean up + rpc_cmd bdev_lvol_delete "$lvol_uuid" + rpc_cmd bdev_get_bdevs -b "$lvol_uuid" && false + rpc_cmd bdev_lvol_delete_lvstore -u "$lvs_uuid" + rpc_cmd bdev_lvol_get_lvstores -u "$lvs_uuid" && false + rpc_cmd bdev_malloc_delete "$malloc_name" +} + +# resize an lvol a few times +function test_resize_lvol_with_io_traffic() { + # create an lvol store + malloc_name=$(rpc_cmd bdev_malloc_create $MALLOC_SIZE_MB $MALLOC_BS) + lvs_uuid=$(rpc_cmd bdev_lvol_create_lvstore "$malloc_name" lvs_test) + + # calculate lvol size + lvol_size_mb=$(round_down $((LVS_DEFAULT_CAPACITY_MB / 2))) + lvol_size=$((lvol_size_mb * 1024 * 1024)) + + # create an lvol on top + lvol_uuid=$(rpc_cmd bdev_lvol_create -u "$lvs_uuid" lvol_test "$lvol_size_mb") + lvol=$(rpc_cmd bdev_get_bdevs -b "$lvol_uuid") + [ "$(jq -r '.[0].name' <<< "$lvol")" = "$lvol_uuid" ] + [ "$(jq -r '.[0].uuid' <<< "$lvol")" = "$lvol_uuid" ] + [ "$(jq -r '.[0].aliases[0]' <<< "$lvol")" = "lvs_test/lvol_test" ] + [ "$(jq -r '.[0].block_size' <<< "$lvol")" = "$MALLOC_BS" ] + [ "$(jq -r '.[0].num_blocks' <<< "$lvol")" = "$((lvol_size / MALLOC_BS))" ] + + # prepare to do some I/O + trap 'nbd_stop_disks "$DEFAULT_RPC_ADDR" /dev/nbd0; exit 1' SIGINT SIGTERM EXIT + nbd_start_disks "$DEFAULT_RPC_ADDR" "$lvol_uuid" /dev/nbd0 + + # write to the entire lvol + count=$((lvol_size / LVS_DEFAULT_CLUSTER_SIZE)) + dd if=/dev/urandom of=/dev/nbd0 oflag=direct bs="$LVS_DEFAULT_CLUSTER_SIZE" count=$count + + # writing beyond lvol size should fail + offset=$((lvol_size / LVS_DEFAULT_CLUSTER_SIZE + 1)) + dd if=/dev/urandom of=/dev/nbd0 oflag=direct bs="$LVS_DEFAULT_CLUSTER_SIZE" seek=$offset count=1 && false + + # resize the lvol to twice its original size + lvol_size_mb=$((lvol_size_mb * 2)) + lvol_size=$((lvol_size_mb * 1024 * 1024)) + rpc_cmd bdev_lvol_resize "$lvol_uuid" "$lvol_size_mb" + lvol=$(rpc_cmd bdev_get_bdevs -b "$lvol_uuid") + [ "$(jq -r '.[0].num_blocks' <<< "$lvol")" = "$((lvol_size / MALLOC_BS))" ] + + # writing beyond the original lvol size should now succeed, we need + # to restart NBD though as it may still use the old, cached size + nbd_stop_disks "$DEFAULT_RPC_ADDR" /dev/nbd0 + nbd_start_disks "$DEFAULT_RPC_ADDR" "$lvol_uuid" /dev/nbd0 + dd if=/dev/urandom of=/dev/nbd0 oflag=direct bs="$LVS_DEFAULT_CLUSTER_SIZE" seek=$offset count=1 + + # lvol can't be downsized if they have any open descriptors, so close them now + trap - SIGINT SIGTERM EXIT + nbd_stop_disks "$DEFAULT_RPC_ADDR" /dev/nbd0 + + # resize lvol down to a single cluster + rpc_cmd bdev_lvol_resize "$lvol_uuid" "$LVS_DEFAULT_CLUSTER_SIZE_MB" + lvol=$(rpc_cmd bdev_get_bdevs -b "$lvol_uuid") + [ "$(jq -r '.[0].num_blocks' <<< "$lvol")" = "$((LVS_DEFAULT_CLUSTER_SIZE / MALLOC_BS))" ] + + # make sure we can't write beyond the first cluster + trap 'nbd_stop_disks "$DEFAULT_RPC_ADDR" /dev/nbd0; exit 1' SIGINT SIGTERM EXIT + nbd_start_disks "$DEFAULT_RPC_ADDR" "$lvol_uuid" /dev/nbd0 + dd if=/dev/urandom of=/dev/nbd0 oflag=direct bs="$LVS_DEFAULT_CLUSTER_SIZE" seek=1 count=1 && false + + # clean up + trap - SIGINT SIGTERM EXIT + nbd_stop_disks "$DEFAULT_RPC_ADDR" /dev/nbd0 + rpc_cmd bdev_lvol_delete "$lvol_uuid" + rpc_cmd bdev_get_bdevs -b "$lvol_uuid" && false + rpc_cmd bdev_lvol_delete_lvstore -u "$lvs_uuid" + rpc_cmd bdev_lvol_get_lvstores -u "$lvs_uuid" && false + rpc_cmd bdev_malloc_delete "$malloc_name" +} + +# Positive test for destroying a logical_volume after resizing. +# Call bdev_lvol_delete_lvstore with correct logical_volumes name. +function test_destroy_after_bdev_lvol_resize_positive() { + local malloc_dev + local lvstore_name=lvs_test lvstore_uuid + local lbd_name=lbd_test bdev_uuid bdev_size + + malloc_dev=$(rpc_cmd bdev_malloc_create 256 "$MALLOC_BS") + lvstore_uuid=$(rpc_cmd bdev_lvol_create_lvstore "$malloc_dev" "$lvstore_name") + + get_lvs_jq bdev_lvol_get_lvstores -u "$lvstore_uuid" + [[ ${jq_out["uuid"]} == "$lvstore_uuid" ]] + [[ ${jq_out["name"]} == "$lvstore_name" ]] + + bdev_size=$(round_down $((LVS_DEFAULT_CAPACITY_MB / 4))) + bdev_uuid=$(rpc_cmd bdev_lvol_create -u "$lvstore_uuid" "$lbd_name" "$bdev_size") + + # start resizing in the following fashion: + # - size is equal to one quarter of size malloc bdev plus 4 MB + # - size is equal half of size malloc bdev + # - size is equal to three quarters of size malloc bdev + # - size is equal to size if malloc bdev minus 4 MB + # - size is equal 0 MiB + local resize + for resize in \ + "$bdev_size" \ + $((bdev_size + 4)) \ + $((bdev_size * 2)) \ + $((bdev_size * 3)) \ + $((bdev_size * 4 - 4)) \ + 0; do + resize=$(round_down $((resize / 4))) + rpc_cmd bdev_lvol_resize "$bdev_uuid" "$resize" + + get_bdev_jq bdev_get_bdevs -b "$bdev_uuid" + [[ ${jq_out["name"]} == "$bdev_uuid" ]] + [[ ${jq_out["name"]} == "${jq_out["uuid"]}" ]] + ((jq_out["block_size"] == MALLOC_BS)) + ((jq_out["num_blocks"] * jq_out["block_size"] == resize * 1024 ** 2)) + done + + # cleanup + rpc_cmd bdev_lvol_delete "$bdev_uuid" + rpc_cmd bdev_lvol_delete_lvstore -u "$lvstore_uuid" + rpc_cmd bdev_get_bdevs -b "$bdev_uuid" && false + rpc_cmd bdev_lvol_get_lvstores -u "$lvstore_uuid" && false + rpc_cmd bdev_malloc_delete "$malloc_dev" + check_leftover_devices +} + +modprobe nbd +$SPDK_BIN_DIR/spdk_tgt & +spdk_pid=$! +trap 'killprocess "$spdk_pid"; exit 1' SIGINT SIGTERM EXIT +waitforlisten $spdk_pid + +run_test "test_resize_lvol" test_resize_lvol +run_test "test_resize_lvol_negative" test_resize_lvol_negative +run_test "test_resize_lvol_with_io_traffic" test_resize_lvol_with_io_traffic +run_test "test_destroy_after_bdev_lvol_resize_positive" test_destroy_after_bdev_lvol_resize_positive + +trap - SIGINT SIGTERM EXIT +killprocess $spdk_pid diff --git a/src/spdk/test/lvol/snapshot_clone.sh b/src/spdk/test/lvol/snapshot_clone.sh new file mode 100755 index 000000000..49a98ca93 --- /dev/null +++ b/src/spdk/test/lvol/snapshot_clone.sh @@ -0,0 +1,617 @@ +#!/usr/bin/env bash + +testdir=$(readlink -f $(dirname $0)) +rootdir=$(readlink -f $testdir/../..) +source $rootdir/test/common/autotest_common.sh +source $rootdir/test/lvol/common.sh +source $rootdir/test/bdev/nbd_common.sh + +function test_snapshot_compare_with_lvol_bdev() { + malloc_name=$(rpc_cmd bdev_malloc_create $MALLOC_SIZE_MB $MALLOC_BS) + lvs_uuid=$(rpc_cmd bdev_lvol_create_lvstore "$malloc_name" lvs_test) + + # Create two lvol bdevs + lvol_size_mb=$(round_down $((LVS_DEFAULT_CAPACITY_MB / 6))) + lvol_size=$((lvol_size_mb * 1024 * 1024)) + + lvol_uuid1=$(rpc_cmd bdev_lvol_create -u "$lvs_uuid" lvol_test1 "$lvol_size_mb" -t) + lvol_uuid2=$(rpc_cmd bdev_lvol_create -u "$lvs_uuid" lvol_test2 "$lvol_size_mb") + + # Fill thin provisoned lvol bdev with 50% of its space + nbd_start_disks "$DEFAULT_RPC_ADDR" "$lvol_uuid1" /dev/nbd0 + count=$((lvol_size / LVS_DEFAULT_CLUSTER_SIZE / 2)) + dd if=/dev/urandom of=/dev/nbd0 oflag=direct bs="$LVS_DEFAULT_CLUSTER_SIZE" count=$count + nbd_stop_disks "$DEFAULT_RPC_ADDR" /dev/nbd0 + # Fill whole thick provisioned lvol bdev + nbd_start_disks "$DEFAULT_RPC_ADDR" "$lvol_uuid2" /dev/nbd0 + count=$((lvol_size / LVS_DEFAULT_CLUSTER_SIZE)) + dd if=/dev/urandom of=/dev/nbd0 oflag=direct bs="$LVS_DEFAULT_CLUSTER_SIZE" count=$count + nbd_stop_disks "$DEFAULT_RPC_ADDR" /dev/nbd0 + + # Create snapshots of lvol bdevs + snapshot_uuid1=$(rpc_cmd bdev_lvol_snapshot lvs_test/lvol_test1 lvol_snapshot1) + snapshot_uuid2=$(rpc_cmd bdev_lvol_snapshot lvs_test/lvol_test2 lvol_snapshot2) + + nbd_start_disks "$DEFAULT_RPC_ADDR" "$snapshot_uuid1" /dev/nbd0 + # Try to perform write operation on created snapshot + # Check if filling snapshot of lvol bdev fails + count=$((lvol_size / LVS_DEFAULT_CLUSTER_SIZE)) + dd if=/dev/urandom of=/dev/nbd0 oflag=direct bs="$LVS_DEFAULT_CLUSTER_SIZE" count=$count && false + nbd_stop_disks "$DEFAULT_RPC_ADDR" /dev/nbd0 + + # Declare nbd devices as vars for an easy cross-reference + local lvol_nbd1=/dev/nbd0 lvol_nbd2=/dev/nbd1 + local snapshot_nbd1=/dev/nbd2 snapshot_nbd2=/dev/nbd3 + + nbd_start_disks "$DEFAULT_RPC_ADDR" "$lvol_uuid1" "$lvol_nbd1" + nbd_start_disks "$DEFAULT_RPC_ADDR" "$lvol_uuid2" "$lvol_nbd2" + nbd_start_disks "$DEFAULT_RPC_ADDR" "$snapshot_uuid1" "$snapshot_nbd1" + nbd_start_disks "$DEFAULT_RPC_ADDR" "$snapshot_uuid2" "$snapshot_nbd2" + # Compare every lvol bdev with corresponding snapshot and check that data are the same + cmp "$lvol_nbd1" "$snapshot_nbd1" + cmp "$lvol_nbd2" "$snapshot_nbd2" + + # Fill second half of thin provisioned lvol bdev + count=$((lvol_size / LVS_DEFAULT_CLUSTER_SIZE / 2)) + dd if=/dev/urandom of="$lvol_nbd1" oflag=direct seek=$count bs="$LVS_DEFAULT_CLUSTER_SIZE" count=$count + + # Compare thin provisioned lvol bdev with its snapshot and check if it fails + cmp "$lvol_nbd1" "$snapshot_nbd1" && false + + # clean up + for bdev in "${!lvol_nbd@}" "${!snapshot_nbd@}"; do + nbd_stop_disks "$DEFAULT_RPC_ADDR" "${!bdev}" + done + + rpc_cmd bdev_lvol_delete "$lvol_uuid1" + rpc_cmd bdev_get_bdevs -b "$lvol_uuid1" && false + rpc_cmd bdev_lvol_delete "$snapshot_uuid1" + rpc_cmd bdev_get_bdevs -b "$snapshot_uuid1" && false + rpc_cmd bdev_lvol_delete "$lvol_uuid2" + rpc_cmd bdev_get_bdevs -b "$lvol_uuid2" && false + rpc_cmd bdev_lvol_delete "$snapshot_uuid2" + rpc_cmd bdev_get_bdevs -b "$snapshot_uuid2" && false + rpc_cmd bdev_lvol_delete_lvstore -u "$lvs_uuid" + rpc_cmd bdev_lvol_get_lvstores -u "$lvs_uuid" && false + rpc_cmd bdev_malloc_delete "$malloc_name" + check_leftover_devices +} + +# Check that when writing to lvol bdev +# creating snapshot ends with success +function test_create_snapshot_with_io() { + malloc_name=$(rpc_cmd bdev_malloc_create $MALLOC_SIZE_MB $MALLOC_BS) + lvs_uuid=$(rpc_cmd bdev_lvol_create_lvstore "$malloc_name" lvs_test) + + # Create lvol bdev + lvol_size_mb=$(round_down $((LVS_DEFAULT_CAPACITY_MB / 2))) + lvol_size=$((lvol_size_mb * 1024 * 1024)) + + lvol_uuid=$(rpc_cmd bdev_lvol_create -u "$lvs_uuid" lvol_test "$lvol_size_mb" -t) + + # Run fio in background that writes to lvol bdev + nbd_start_disks "$DEFAULT_RPC_ADDR" "$lvol_uuid" /dev/nbd0 + run_fio_test /dev/nbd0 0 $lvol_size "write" "0xcc" "--time_based --runtime=16" & + fio_proc=$! + sleep 4 + # Create snapshot of lvol bdev + snapshot_uuid=$(rpc_cmd bdev_lvol_snapshot lvs_test/lvol_test lvol_snapshot) + wait $fio_proc + + # Clean up + nbd_stop_disks "$DEFAULT_RPC_ADDR" /dev/nbd0 + rpc_cmd bdev_lvol_delete "$lvol_uuid" + rpc_cmd bdev_get_bdevs -b "$lvol_uuid" && false + rpc_cmd bdev_lvol_delete "$snapshot_uuid" + rpc_cmd bdev_get_bdevs -b "$snapshot_uuid" && false + rpc_cmd bdev_lvol_delete_lvstore -u "$lvs_uuid" + rpc_cmd bdev_lvol_get_lvstores -u "$lvs_uuid" && false + rpc_cmd bdev_malloc_delete "$malloc_name" + check_leftover_devices +} + +# Check that creating snapshot of snapshot will fail +function test_create_snapshot_of_snapshot() { + malloc_name=$(rpc_cmd bdev_malloc_create $MALLOC_SIZE_MB $MALLOC_BS) + lvs_uuid=$(rpc_cmd bdev_lvol_create_lvstore "$malloc_name" lvs_test) + + # Create lvol bdev + lvol_size_mb=$(round_down $((LVS_DEFAULT_CAPACITY_MB / 3))) + + lvol_uuid=$(rpc_cmd bdev_lvol_create -u "$lvs_uuid" lvol_test "$lvol_size_mb") + lvol=$(rpc_cmd bdev_get_bdevs -b "$lvol_uuid") + + # Create snapshots of lvol bdev + snapshot_uuid=$(rpc_cmd bdev_lvol_snapshot lvs_test/lvol_test lvol_snapshot) + + # Create snapshot of previously created snapshot + # and check if operation will fail + rpc_cmd bdev_lvol_snapshot lvs_test/lvol_snapshot lvol_snapshot2 && false + + # Clean up + rpc_cmd bdev_lvol_delete "$lvol_uuid" + rpc_cmd bdev_get_bdevs -b "$lvol_uuid" && false + rpc_cmd bdev_lvol_delete "$snapshot_uuid" + rpc_cmd bdev_get_bdevs -b "$snapshot_uuid" && false + rpc_cmd bdev_lvol_delete_lvstore -u "$lvs_uuid" + rpc_cmd bdev_lvol_get_lvstores -u "$lvs_uuid" && false + rpc_cmd bdev_malloc_delete "$malloc_name" + check_leftover_devices +} + +# Check if only clone of snapshot can be created. +# Check if writing to one clone doesn't affect other clone +# Check if relations between clones and snapshots are properly set in configuration +function test_clone_snapshot_relations() { + malloc_name=$(rpc_cmd bdev_malloc_create $MALLOC_SIZE_MB $MALLOC_BS) + lvs_uuid=$(rpc_cmd bdev_lvol_create_lvstore "$malloc_name" lvs_test) + + # Calculate size and create lvol bdev + lvol_size_mb=$(round_down $((LVS_DEFAULT_CAPACITY_MB / 6))) + lvol_size=$((lvol_size_mb * 1024 * 1024)) + + lvol_uuid=$(rpc_cmd bdev_lvol_create -u "$lvs_uuid" lvol_test "$lvol_size_mb") + lvol=$(rpc_cmd bdev_get_bdevs -b "$lvol_uuid") + + # Fill lvol bdev with 100% of its space + nbd_start_disks "$DEFAULT_RPC_ADDR" "$lvol_uuid" /dev/nbd0 + run_fio_test /dev/nbd0 0 $lvol_size "write" "0xcc" + nbd_stop_disks "$DEFAULT_RPC_ADDR" /dev/nbd0 + + # An attempt to create a clone from lvol that is rw capable should fail + rpc_cmd bdev_lvol_clone lvs_test/lvol_test clone_test && false + + # Create snapshots of lvol bdev + snapshot_uuid=$(rpc_cmd bdev_lvol_snapshot lvs_test/lvol_test lvol_snapshot) + + # Create again clone of lvol bdev and check if it fails + rpc_cmd bdev_lvol_clone lvs_test/lvol_test clone_test && false + + # Create two clones of snapshot and check if it ends with success + clone_uuid1=$(rpc_cmd bdev_lvol_clone lvs_test/lvol_snapshot clone_test1) + clone_uuid2=$(rpc_cmd bdev_lvol_clone lvs_test/lvol_snapshot clone_test2) + + # Perform write operation to first clone + # Change first half of its space + nbd_start_disks "$DEFAULT_RPC_ADDR" "$clone_uuid1" /dev/nbd0 + fill_size=$((lvol_size / 2)) + run_fio_test /dev/nbd0 0 $fill_size "write" "0xaa" + + # Compare snapshot with second clone. Data on both bdevs should be the same + nbd_start_disks "$DEFAULT_RPC_ADDR" "$snapshot_uuid" /dev/nbd1 + nbd_start_disks "$DEFAULT_RPC_ADDR" "$clone_uuid2" /dev/nbd2 + sleep 1 + cmp /dev/nbd1 /dev/nbd2 + # Compare snapshot with first clone + cmp /dev/nbd0 /dev/nbd1 && false + + snapshot_bdev=$(rpc_cmd bdev_get_bdevs -b "lvs_test/lvol_snapshot") + clone_bdev1=$(rpc_cmd bdev_get_bdevs -b "lvs_test/clone_test1") + clone_bdev2=$(rpc_cmd bdev_get_bdevs -b "lvs_test/lvol_test") + + # Check snapshot consistency + [ "$(jq '.[].driver_specific.lvol.snapshot' <<< "$snapshot_bdev")" = "true" ] + [ "$(jq '.[].driver_specific.lvol.clone' <<< "$snapshot_bdev")" = "false" ] + [ "$(jq '.[].driver_specific.lvol.clones|sort' <<< "$snapshot_bdev")" = "$(jq '.|sort' <<< '["lvol_test", "clone_test1", "clone_test2"]')" ] + + # Check first clone consistency + [ "$(jq '.[].driver_specific.lvol.snapshot' <<< "$clone_bdev1")" = "false" ] + [ "$(jq '.[].driver_specific.lvol.clone' <<< "$clone_bdev1")" = "true" ] + [ "$(jq '.[].driver_specific.lvol.base_snapshot' <<< "$clone_bdev1")" = '"lvol_snapshot"' ] + + # Check second clone consistency + [ "$(jq '.[].driver_specific.lvol.snapshot' <<< "$clone_bdev2")" = "false" ] + [ "$(jq '.[].driver_specific.lvol.clone' <<< "$clone_bdev2")" = "true" ] + [ "$(jq '.[].driver_specific.lvol.base_snapshot' <<< "$clone_bdev2")" = '"lvol_snapshot"' ] + + # Destroy first clone and check if it is deleted from snapshot + nbd_stop_disks "$DEFAULT_RPC_ADDR" /dev/nbd0 + rpc_cmd bdev_lvol_delete "$clone_uuid1" + snapshot_bdev=$(rpc_cmd bdev_get_bdevs -b "lvs_test/lvol_snapshot") + [ "$(jq '.[].driver_specific.lvol.clones|sort' <<< "$snapshot_bdev")" = "$(jq '.|sort' <<< '["lvol_test", "clone_test2"]')" ] + + # Clean up + nbd_stop_disks "$DEFAULT_RPC_ADDR" /dev/nbd1 + nbd_stop_disks "$DEFAULT_RPC_ADDR" /dev/nbd2 + rpc_cmd bdev_lvol_delete "$lvol_uuid" + rpc_cmd bdev_lvol_delete "$clone_uuid2" + rpc_cmd bdev_lvol_delete "$snapshot_uuid" + rpc_cmd bdev_lvol_delete_lvstore -u "$lvs_uuid" + rpc_cmd bdev_malloc_delete "$malloc_name" + check_leftover_devices +} + +# Testing usage of bdev_lvol_inflate +function test_clone_inflate() { + malloc_name=$(rpc_cmd bdev_malloc_create $MALLOC_SIZE_MB $MALLOC_BS) + lvs_uuid=$(rpc_cmd bdev_lvol_create_lvstore "$malloc_name" lvs_test) + + # Calculate size and create lvol bdev + lvol_size_mb=$(round_down $((LVS_DEFAULT_CAPACITY_MB / 4))) + + lvol_uuid=$(rpc_cmd bdev_lvol_create -u "$lvs_uuid" lvol_test "$lvol_size_mb") + lvol=$(rpc_cmd bdev_get_bdevs -b "$lvol_uuid") + + # Fill lvol bdev with 100% of its space + nbd_start_disks "$DEFAULT_RPC_ADDR" "$lvol_uuid" /dev/nbd0 + run_fio_test /dev/nbd0 0 $((lvol_size_mb * 1024 * 1024)) "write" "0xcc" + nbd_stop_disks "$DEFAULT_RPC_ADDR" /dev/nbd0 + + # Create snapshots of lvol bdev + snapshot_uuid=$(rpc_cmd bdev_lvol_snapshot lvs_test/lvol_test lvol_snapshot) + + # Create clone of snapshot + lvol=$(rpc_cmd bdev_get_bdevs -b "$lvol_uuid") + [ "$(jq '.[].driver_specific.lvol.thin_provision' <<< "$lvol")" = "true" ] + + # Fill part of clone with data of known pattern + nbd_start_disks "$DEFAULT_RPC_ADDR" "$lvol_uuid" /dev/nbd0 + first_fill=0 + second_fill=$((lvol_size_mb * 1024 * 1024 * 3 / 4)) + run_fio_test /dev/nbd0 $first_fill $((1024 * 1024)) "write" "0xdd" + run_fio_test /dev/nbd0 $second_fill $((1024 * 1024)) "write" "0xdd" + nbd_stop_disks "$DEFAULT_RPC_ADDR" /dev/nbd0 + + # Do inflate + rpc_cmd bdev_lvol_inflate lvs_test/lvol_test + lvol=$(rpc_cmd bdev_get_bdevs -b "$lvol_uuid") + [ "$(jq '.[].driver_specific.lvol.thin_provision' <<< "$lvol")" = "false" ] + + # Delete snapshot + rpc_cmd bdev_lvol_delete "$snapshot_uuid" + + # Check data consistency + nbd_start_disks "$DEFAULT_RPC_ADDR" "$lvol_uuid" /dev/nbd0 + run_fio_test /dev/nbd0 $first_fill $((1024 * 1024)) "read" "0xdd" + run_fio_test /dev/nbd0 $(((first_fill + 1) * 1024 * 1024)) $((second_fill - 1024 * 1024)) "read" "0xcc" + run_fio_test /dev/nbd0 $second_fill $((1024 * 1024)) "read" "0xdd" + run_fio_test /dev/nbd0 $((second_fill + 1024 * 1024)) $((lvol_size_mb * 1024 * 1024 - (second_fill + 1024 * 1024))) "read" "0xcc" + nbd_stop_disks "$DEFAULT_RPC_ADDR" /dev/nbd0 + + # Clean up + rpc_cmd bdev_lvol_delete "$lvol_uuid" + rpc_cmd bdev_lvol_delete_lvstore -u "$lvs_uuid" + rpc_cmd bdev_malloc_delete "$malloc_name" + check_leftover_devices +} + +# Create chain of snapshot<-snapshot2<-lvol_test lvol bdevs. +# Decouple lvol_test twice and delete the remaining snapshot lvol. +# Each time check consistency of snapshot-clone relations and written data. +function test_clone_decouple_parent() { + malloc_name=$(rpc_cmd bdev_malloc_create $MALLOC_SIZE_MB $MALLOC_BS) + lvs_uuid=$(rpc_cmd bdev_lvol_create_lvstore "$malloc_name" lvs_test) + + # Calculate size and create lvol bdev + lvol_size_mb=$((5 * LVS_DEFAULT_CLUSTER_SIZE_MB)) + lvol_uuid=$(rpc_cmd bdev_lvol_create -u "$lvs_uuid" lvol_test "$lvol_size_mb" -t) + lvol=$(rpc_cmd bdev_get_bdevs -b "$lvol_uuid") + + # Decouple_parent should fail on lvol bdev without a parent + rpc_cmd bdev_lvol_decouple_parent lvs_test/lvol_test && false + + # Fill first four out of 5 clusters of clone with data of known pattern + nbd_start_disks "$DEFAULT_RPC_ADDR" "$lvol_uuid" /dev/nbd0 + begin_fill=0 + end_fill=$((lvol_size_mb * 4 * 1024 * 1024 / 5)) + run_fio_test /dev/nbd0 $begin_fill $end_fill "write" "0xdd" + + # Create snapshot (snapshot<-lvol_bdev) + snapshot_uuid=$(rpc_cmd bdev_lvol_snapshot lvs_test/lvol_test lvol_snapshot) + + # Fill second and fourth cluster of clone with data of known pattern + start_fill=$((lvol_size_mb * 1024 * 1024 / 5)) + fill_range=$start_fill + run_fio_test /dev/nbd0 $start_fill $fill_range "write" "0xcc" + start_fill=$((lvol_size_mb * 3 * 1024 * 1024 / 5)) + run_fio_test /dev/nbd0 $start_fill $fill_range "write" "0xcc" + + # Create snapshot (snapshot<-snapshot2<-lvol_bdev) + snapshot_uuid2=$(rpc_cmd bdev_lvol_snapshot lvs_test/lvol_test lvol_snapshot2) + + # Fill second cluster of clone with data of known pattern + start_fill=$fill_range + run_fio_test /dev/nbd0 $start_fill $fill_range "write" "0xee" + + # Check data consistency + pattern=("0xdd" "0xee" "0xdd" "0xcc" "0x00") + for i in "${!pattern[@]}"; do + start_fill=$((lvol_size_mb * i * 1024 * 1024 / 5)) + run_fio_test /dev/nbd0 $start_fill $fill_range "read" "${pattern[i]}" + done + + # Decouple_parent of lvol bdev resulting in two relation chains: + # - snapshot<-lvol_bdev + # - snapshot<-snapshot2 + rpc_cmd bdev_lvol_decouple_parent lvs_test/lvol_test + lvol=$(rpc_cmd bdev_get_bdevs -b "$lvol_uuid") + snapshot=$(rpc_cmd bdev_get_bdevs -b "$snapshot_uuid") + snapshot2=$(rpc_cmd bdev_get_bdevs -b "$snapshot_uuid2") + [ "$(jq '.[].driver_specific.lvol.thin_provision' <<< "$lvol")" = "true" ] + [ "$(jq '.[].driver_specific.lvol.clone' <<< "$lvol")" = "true" ] + [ "$(jq '.[].driver_specific.lvol.snapshot' <<< "$lvol")" = "false" ] + [ "$(jq '.[].driver_specific.lvol.clone' <<< "$snapshot")" = "false" ] + [ "$(jq '.[].driver_specific.lvol.clone' <<< "$snapshot2")" = "true" ] + [ "$(jq '.[].driver_specific.lvol.snapshot' <<< "$snapshot2")" = "true" ] + + # Delete second snapshot + rpc_cmd bdev_lvol_delete "$snapshot_uuid2" + + # Check data consistency + for i in "${!pattern[@]}"; do + start_fill=$((lvol_size_mb * i * 1024 * 1024 / 5)) + run_fio_test /dev/nbd0 $start_fill $fill_range "read" "${pattern[i]}" + done + + # Decouple_parent of lvol bdev again resulting in two relation chains: + # - lvol_bdev + # - snapshot<-snapshot2 + rpc_cmd bdev_lvol_decouple_parent lvs_test/lvol_test + lvol=$(rpc_cmd bdev_get_bdevs -b "$lvol_uuid") + snapshot=$(rpc_cmd bdev_get_bdevs -b "$snapshot_uuid") + [ "$(jq '.[].driver_specific.lvol.thin_provision' <<< "$lvol")" = "true" ] + [ "$(jq '.[].driver_specific.lvol.clone' <<< "$lvol")" = "false" ] + [ "$(jq '.[].driver_specific.lvol.snapshot' <<< "$lvol")" = "false" ] + [ "$(jq '.[].driver_specific.lvol.clone' <<< "$snapshot")" = "false" ] + + # Delete first snapshot + rpc_cmd bdev_lvol_delete "$snapshot_uuid" + + # Check data consistency + for i in "${!pattern[@]}"; do + start_fill=$((lvol_size_mb * i * 1024 * 1024 / 5)) + run_fio_test /dev/nbd0 $start_fill $fill_range "read" "${pattern[i]}" + done + + # Clean up + rpc_cmd bdev_lvol_delete "$lvol_uuid" + rpc_cmd bdev_lvol_delete_lvstore -u "$lvs_uuid" + rpc_cmd bdev_malloc_delete "$malloc_name" + check_leftover_devices +} + +# Set lvol bdev as read only and perform clone on it. +function test_lvol_bdev_readonly() { + malloc_name=$(rpc_cmd bdev_malloc_create $MALLOC_SIZE_MB $MALLOC_BS) + lvs_uuid=$(rpc_cmd bdev_lvol_create_lvstore "$malloc_name" lvs_test) + + # Calculate size and create lvol bdev + lvol_size_mb=$(round_down $((LVS_DEFAULT_CAPACITY_MB / 2))) + + lvol_uuid=$(rpc_cmd bdev_lvol_create -u "$lvs_uuid" lvol_test "$lvol_size_mb") + lvol=$(rpc_cmd bdev_get_bdevs -b "$lvol_uuid") + + # Set lvol bdev as read only + rpc_cmd bdev_lvol_set_read_only lvs_test/lvol_test + + # Try to perform write operation on lvol marked as read only + nbd_start_disks "$DEFAULT_RPC_ADDR" "$lvol_uuid" /dev/nbd0 + run_fio_test /dev/nbd0 0 $lvol_size "write" "0xcc" && false + nbd_stop_disks "$DEFAULT_RPC_ADDR" /dev/nbd0 + + # Create clone of lvol set to read only + clone_uuid=$(rpc_cmd bdev_lvol_clone lvs_test/lvol_test clone_test) + + # Try to perform write operation on lvol clone + nbd_start_disks "$DEFAULT_RPC_ADDR" "$clone_uuid" /dev/nbd0 + run_fio_test /dev/nbd0 0 $lvol_size "write" "0xcc" + nbd_stop_disks "$DEFAULT_RPC_ADDR" /dev/nbd0 + + # Clean up + rpc_cmd bdev_lvol_delete "$clone_uuid" + rpc_cmd bdev_lvol_delete "$lvol_uuid" + rpc_cmd bdev_lvol_delete_lvstore -u "$lvs_uuid" + rpc_cmd bdev_malloc_delete "$malloc_name" + check_leftover_devices +} + +# Check if it is possible to delete snapshot with clone +function test_delete_snapshot_with_clone() { + malloc_name=$(rpc_cmd bdev_malloc_create $MALLOC_SIZE_MB $MALLOC_BS) + lvs_uuid=$(rpc_cmd bdev_lvol_create_lvstore "$malloc_name" lvs_test) + + # Calculate size and create lvol bdev + lvol_size_mb=$(round_down $((LVS_DEFAULT_CAPACITY_MB / 2))) + lvol_size=$((lvol_size_mb * 1024 * 1024)) + + lvol_uuid=$(rpc_cmd bdev_lvol_create -u "$lvs_uuid" lvol_test "$lvol_size_mb") + lvol=$(rpc_cmd bdev_get_bdevs -b "$lvol_uuid") + + # Perform write operation on lvol + nbd_start_disks "$DEFAULT_RPC_ADDR" "$lvol_uuid" /dev/nbd0 + run_fio_test /dev/nbd0 0 $lvol_size "write" "0xcc" + + # Create snapshots of lvol bdev + snapshot_uuid=$(rpc_cmd bdev_lvol_snapshot lvs_test/lvol_test lvol_snapshot) + + # Fill first half of lvol bdev + half_size=$((lvol_size / 2 - 1)) + run_fio_test /dev/nbd0 0 $half_size "write" "0xee" + + # Check if snapshot was unchanged + nbd_start_disks "$DEFAULT_RPC_ADDR" "$snapshot_uuid" /dev/nbd1 + run_fio_test /dev/nbd1 0 $half_size "read" "0xcc" + + # Verify lvol bdev + run_fio_test /dev/nbd0 0 $half_size "read" "0xee" + lvol=$(rpc_cmd bdev_get_bdevs -b "$lvol_uuid") + [ "$(jq '.[].driver_specific.lvol.clone' <<< "$lvol")" = "true" ] + + # Delete snapshot - should succeed + nbd_stop_disks "$DEFAULT_RPC_ADDR" /dev/nbd1 + rpc_cmd bdev_lvol_delete "$snapshot_uuid" + + # Check data consistency + lvol=$(rpc_cmd bdev_get_bdevs -b "$lvol_uuid") + [ "$(jq '.[].driver_specific.lvol.clone' <<< "$lvol")" = "false" ] + run_fio_test /dev/nbd0 0 $half_size "read" "0xee" + run_fio_test /dev/nbd0 $((half_size + 1)) $half_size "read" "0xcc" + + # Clean up + nbd_stop_disks "$DEFAULT_RPC_ADDR" /dev/nbd0 + rpc_cmd bdev_lvol_delete "$lvol_uuid" + rpc_cmd bdev_lvol_delete_lvstore -u "$lvs_uuid" + rpc_cmd bdev_malloc_delete "$malloc_name" + check_leftover_devices +} + +# Check if it is possible to delete snapshot with one snapshot on it +function test_delete_snapshot_with_snapshot() { + malloc_name=$(rpc_cmd bdev_malloc_create $MALLOC_SIZE_MB $MALLOC_BS) + lvs_uuid=$(rpc_cmd bdev_lvol_create_lvstore "$malloc_name" lvs_test) + + # Calculate size and create lvol bdev + lvol_size_mb=$(round_down $((LVS_DEFAULT_CAPACITY_MB / 5))) + lvol_size=$((lvol_size_mb * 1024 * 1024)) + + lvol_uuid=$(rpc_cmd bdev_lvol_create -u "$lvs_uuid" lvol_test "$lvol_size_mb") + lvol=$(rpc_cmd bdev_get_bdevs -b "$lvol_uuid") + + # Perform write operation on lvol + nbd_start_disks "$DEFAULT_RPC_ADDR" "$lvol_uuid" /dev/nbd0 + run_fio_test /dev/nbd0 0 $lvol_size "write" "0xcc" + + # Create snapshot of lvol bdev + snapshot_uuid=$(rpc_cmd bdev_lvol_snapshot lvs_test/lvol_test lvol_snapshot) + lvol=$(rpc_cmd bdev_get_bdevs -b "$lvol_uuid") + [ "$(jq '.[].driver_specific.lvol.base_snapshot' <<< "$lvol")" = '"lvol_snapshot"' ] + + # Fill second 1/3 of lvol bdev + first_part=$((lvol_size / 3)) + second_part=$((lvol_size * 2 / 3)) + run_fio_test /dev/nbd0 $first_part $((second_part - first_part)) "write" "0xee" + + # Check if snapshot was unchanged + nbd_start_disks "$DEFAULT_RPC_ADDR" "$snapshot_uuid" /dev/nbd1 + run_fio_test /dev/nbd1 0 $lvol_size "read" "0xcc" + + # Create second snapshot of lvol_bdev + # First snapshot becomes snapshot of second snapshot + snapshot_uuid2=$(rpc_cmd bdev_lvol_snapshot lvs_test/lvol_test lvol_snapshot2) + lvol=$(rpc_cmd bdev_get_bdevs -b "$lvol_uuid") + snapshot=$(rpc_cmd bdev_get_bdevs -b "$snapshot_uuid") + snapshot2=$(rpc_cmd bdev_get_bdevs -b "$snapshot_uuid2") + [ "$(jq '.[].driver_specific.lvol.base_snapshot' <<< "$snapshot2")" = '"lvol_snapshot"' ] + [ "$(jq '.[].driver_specific.lvol.clones|sort' <<< "$snapshot2")" = "$(jq '.|sort' <<< '["lvol_test"]')" ] + [ "$(jq '.[].driver_specific.lvol.clone' <<< "$snapshot2")" = "true" ] + [ "$(jq '.[].driver_specific.lvol.snapshot' <<< "$snapshot2")" = "true" ] + [ "$(jq '.[].driver_specific.lvol.clones|sort' <<< "$snapshot")" = "$(jq '.|sort' <<< '["lvol_snapshot2"]')" ] + + # Verify snapshots + run_fio_test /dev/nbd1 0 $size "read" "0xcc" + nbd_start_disks "$DEFAULT_RPC_ADDR" "$snapshot_uuid2" /dev/nbd2 + run_fio_test /dev/nbd2 0 $((first_part - 1)) "read" "0xcc" + run_fio_test /dev/nbd2 $first_part $((second_part - first_part)) "read" "0xee" + run_fio_test /dev/nbd2 $second_part $((lvol_size - second_part)) "read" "0xcc" + + # Verify lvol bdev + run_fio_test /dev/nbd0 $first_part $((second_part - first_part)) "read" "0xee" + run_fio_test /dev/nbd0 $second_part $((lvol_size - second_part)) "read" "0xcc" + [ "$(jq '.[].driver_specific.lvol.clone' <<< "$lvol")" = "true" ] + [ "$(jq '.[].driver_specific.lvol.base_snapshot' <<< "$lvol")" = '"lvol_snapshot2"' ] + + # Fill third part of lvol bdev + run_fio_test /dev/nbd0 $second_part $((lvol_size - second_part)) "write" "0xdd" + + # Verify snapshots + run_fio_test /dev/nbd1 0 $size "read" "0xcc" + run_fio_test /dev/nbd0 $second_part $((lvol_size - second_part)) "read" "0xdd" + nbd_stop_disks "$DEFAULT_RPC_ADDR" /dev/nbd2 + nbd_stop_disks "$DEFAULT_RPC_ADDR" /dev/nbd1 + + # Delete snapshot - should succeed + rpc_cmd bdev_lvol_delete "$snapshot_uuid2" + + # Check data consistency + lvol=$(rpc_cmd bdev_get_bdevs -b "$lvol_uuid") + snapshot=$(rpc_cmd bdev_get_bdevs -b "$snapshot_uuid") + [ "$(jq '.[].driver_specific.lvol.clone' <<< "$lvol")" = "true" ] + [ "$(jq '.[].driver_specific.lvol.base_snapshot' <<< "$lvol")" = '"lvol_snapshot"' ] + [ "$(jq '.[].driver_specific.lvol.clones|sort' <<< "$snapshot")" = "$(jq '.|sort' <<< '["lvol_test"]')" ] + run_fio_test /dev/nbd0 $first_part $((second_part - first_part)) "read" "0xee" + run_fio_test /dev/nbd0 $second_part $((lvol_size - second_part)) "read" "0xdd" + + # Clean up + nbd_stop_disks "$DEFAULT_RPC_ADDR" /dev/nbd0 + rpc_cmd bdev_lvol_delete "$snapshot_uuid" + rpc_cmd bdev_lvol_delete "$lvol_uuid" + rpc_cmd bdev_lvol_delete_lvstore -u "$lvs_uuid" + rpc_cmd bdev_malloc_delete "$malloc_name" + check_leftover_devices +} + +# Test for destroying lvol bdevs in particular order. +function test_bdev_lvol_delete_ordering() { + local snapshot_name=snapshot snapshot_uuid + local clone_name=clone clone_uuid + + local bdev_uuid + local lbd_name=lbd_test + local lvstore_uuid lvstore_name=lvs_name + local malloc_dev + local size + + malloc_dev=$(rpc_cmd bdev_malloc_create 256 "$MALLOC_BS") + lvstore_uuid=$(rpc_cmd bdev_lvol_create_lvstore "$malloc_dev" "$lvstore_name") + + get_lvs_jq bdev_lvol_get_lvstores -u "$lvstore_uuid" + [[ ${jq_out["uuid"]} == "$lvstore_uuid" ]] + [[ ${jq_out["name"]} == "$lvstore_name" ]] + [[ ${jq_out["base_bdev"]} == "$malloc_dev" ]] + + size=$((jq_out["free_clusters"] * jq_out["cluster_size"] / 4 / 1024 ** 2)) + + bdev_uuid=$(rpc_cmd bdev_lvol_create -t -u "$lvstore_uuid" "$lbd_name" "$size") + + get_bdev_jq bdev_get_bdevs -b "$bdev_uuid" + + snapshot_uuid=$(rpc_cmd bdev_lvol_snapshot "${jq_out["name"]}" "$snapshot_name") + + get_bdev_jq bdev_get_bdevs -b "$lvstore_name/$snapshot_name" + [[ ${jq_out["name"]} == "$snapshot_uuid" ]] + [[ ${jq_out["product_name"]} == "Logical Volume" ]] + [[ ${jq_out["aliases[0]"]} == "$lvstore_name/$snapshot_name" ]] + + clone_uuid=$(rpc_cmd bdev_lvol_clone "$lvstore_name/$snapshot_name" "$clone_name") + + get_bdev_jq bdev_get_bdevs -b "$lvstore_name/$clone_name" + [[ ${jq_out["name"]} == "$clone_uuid" ]] + [[ ${jq_out["product_name"]} == "Logical Volume" ]] + [[ ${jq_out["aliases[0]"]} == "$lvstore_name/$clone_name" ]] + + # Try to destroy snapshot with clones and check if it fails + rpc_cmd bdev_lvol_delete "$snapshot_uuid" && false + + # cleanup logical volumes + rpc_cmd bdev_lvol_delete "$bdev_uuid" + rpc_cmd bdev_lvol_delete "$clone_uuid" + rpc_cmd bdev_lvol_delete "$snapshot_uuid" + + # cleanup lvstore + rpc_cmd bdev_lvol_delete_lvstore -u "$lvstore_uuid" + + # cleanup malloc dev + rpc_cmd bdev_malloc_delete "$malloc_dev" + + check_leftover_devices +} + +$SPDK_BIN_DIR/spdk_tgt & +spdk_pid=$! +trap 'killprocess "$spdk_pid"; exit 1' SIGINT SIGTERM EXIT +waitforlisten $spdk_pid +modprobe nbd + +run_test "test_snapshot_compare_with_lvol_bdev" test_snapshot_compare_with_lvol_bdev +run_test "test_create_snapshot_with_io" test_create_snapshot_with_io +run_test "test_create_snapshot_of_snapshot" test_create_snapshot_of_snapshot +run_test "test_clone_snapshot_relations" test_clone_snapshot_relations +run_test "test_clone_inflate" test_clone_inflate +run_test "test_clone_decouple_parent" test_clone_decouple_parent +run_test "test_lvol_bdev_readonly" test_lvol_bdev_readonly +run_test "test_delete_snapshot_with_clone" test_delete_snapshot_with_clone +run_test "test_delete_snapshot_with_snapshot" test_delete_snapshot_with_snapshot +run_test "test_bdev_lvol_delete_ordering" test_bdev_lvol_delete_ordering + +trap - SIGINT SIGTERM EXIT +killprocess $spdk_pid diff --git a/src/spdk/test/lvol/tasting.sh b/src/spdk/test/lvol/tasting.sh new file mode 100755 index 000000000..dbb75d241 --- /dev/null +++ b/src/spdk/test/lvol/tasting.sh @@ -0,0 +1,171 @@ +#!/usr/bin/env bash + +testdir=$(readlink -f $(dirname $0)) +rootdir=$(readlink -f $testdir/../..) +source $rootdir/test/common/autotest_common.sh +source $rootdir/test/lvol/common.sh + +# Make sure lvol stores are automatically detected after base bdev detach and subsequent attach +function test_tasting() { + # Create two aio bdevs + rpc_cmd bdev_aio_create $testdir/aio_bdev_0 aio_bdev0 "$AIO_BS" + rpc_cmd bdev_aio_create $testdir/aio_bdev_1 aio_bdev1 "$AIO_BS" + # Create a valid lvs + lvs_uuid=$(rpc_cmd bdev_lvol_create_lvstore aio_bdev0 lvs_test) + # Destroy lvol store + rpc_cmd bdev_lvol_delete_lvstore -u "$lvs_uuid" + # Remove the lvol stores and make sure it's not being automatically detected after base + # bdev re-attach. + rpc_cmd bdev_aio_delete aio_bdev0 + # Create aio bdev on the same file + rpc_cmd bdev_aio_create $testdir/aio_bdev_0 aio_bdev0 "$AIO_BS" + sleep 1 + # Check if destroyed lvol store does not exist on aio bdev + rpc_cmd bdev_lvol_get_lvstores -u "$lvs_uuid" && false + + # Create a valid lvs + lvs1_cluster_size=$((1 * 1024 * 1024)) + lvs2_cluster_size=$((32 * 1024 * 1024)) + lvs_uuid1=$(rpc_cmd bdev_lvol_create_lvstore aio_bdev0 lvs_test1 -c $lvs1_cluster_size) + lvs_uuid2=$(rpc_cmd bdev_lvol_create_lvstore aio_bdev1 lvs_test2 -c $lvs2_cluster_size) + + # Create 5 lvols on first lvs + lvol_size_mb=$(round_down $((LVS_DEFAULT_CAPACITY_MB / 10))) + lvol_size=$((lvol_size_mb * 1024 * 1024)) + + for i in $(seq 1 5); do + lvol_uuid=$(rpc_cmd bdev_lvol_create -u "$lvs_uuid1" "lvol_test${i}" "$lvol_size_mb") + lvol=$(rpc_cmd bdev_get_bdevs -b "$lvol_uuid") + + [ "$(jq -r '.[0].name' <<< "$lvol")" = "$lvol_uuid" ] + [ "$(jq -r '.[0].uuid' <<< "$lvol")" = "$lvol_uuid" ] + [ "$(jq -r '.[0].aliases[0]' <<< "$lvol")" = "lvs_test1/lvol_test${i}" ] + [ "$(jq -r '.[0].block_size' <<< "$lvol")" = "$AIO_BS" ] + [ "$(jq -r '.[0].num_blocks' <<< "$lvol")" = "$((lvol_size / AIO_BS))" ] + done + + # Create 5 lvols on second lvs + lvol2_size_mb=$(round_down $(((AIO_SIZE_MB - 16) / 5)) 32) + lvol2_size=$((lvol2_size_mb * 1024 * 1024)) + + for i in $(seq 1 5); do + lvol_uuid=$(rpc_cmd bdev_lvol_create -u "$lvs_uuid2" "lvol_test${i}" "$lvol2_size_mb") + lvol=$(rpc_cmd bdev_get_bdevs -b "$lvol_uuid") + + [ "$(jq -r '.[0].name' <<< "$lvol")" = "$lvol_uuid" ] + [ "$(jq -r '.[0].uuid' <<< "$lvol")" = "$lvol_uuid" ] + [ "$(jq -r '.[0].aliases[0]' <<< "$lvol")" = "lvs_test2/lvol_test${i}" ] + [ "$(jq -r '.[0].block_size' <<< "$lvol")" = "$AIO_BS" ] + [ "$(jq -r '.[0].num_blocks' <<< "$lvol")" = "$((lvol2_size / AIO_BS))" ] + done + + old_lvols=$(rpc_cmd bdev_get_bdevs | jq -r '[ .[] | select(.product_name == "Logical Volume") ]') + [ "$(jq length <<< "$old_lvols")" == "10" ] + old_lvs=$(rpc_cmd bdev_lvol_get_lvstores | jq .) + + # Restart spdk app + killprocess $spdk_pid + $SPDK_BIN_DIR/spdk_tgt & + spdk_pid=$! + waitforlisten $spdk_pid + + # Create aio bdevs + rpc_cmd bdev_aio_create $testdir/aio_bdev_0 aio_bdev0 "$AIO_BS" + rpc_cmd bdev_aio_create $testdir/aio_bdev_1 aio_bdev1 "$AIO_BS" + sleep 1 + + # Check tasting feature + new_lvols=$(rpc_cmd bdev_get_bdevs | jq -r '[ .[] | select(.product_name == "Logical Volume") ]') + [ "$(jq length <<< "$new_lvols")" == "10" ] + new_lvs=$(rpc_cmd bdev_lvol_get_lvstores | jq .) + if ! diff <(jq '. | sort' <<< "$old_lvs") <(jq '. | sort' <<< "$new_lvs"); then + echo "ERROR: old and loaded lvol store is not the same" + return 1 + fi + if ! diff <(jq '. | sort' <<< "$old_lvols") <(jq '. | sort' <<< "$new_lvols"); then + echo "ERROR: old and loaded lvols are not the same" + return 1 + fi + + # Check if creation and deletion lvol bdevs on lvs is possible + for i in $(seq 6 10); do + lvol_uuid=$(rpc_cmd bdev_lvol_create -u "$lvs_uuid1" "lvol_test${i}" "$lvol_size_mb") + lvol=$(rpc_cmd bdev_get_bdevs -b "$lvol_uuid") + + [ "$(jq -r '.[0].name' <<< "$lvol")" = "$lvol_uuid" ] + [ "$(jq -r '.[0].uuid' <<< "$lvol")" = "$lvol_uuid" ] + [ "$(jq -r '.[0].aliases[0]' <<< "$lvol")" = "lvs_test1/lvol_test${i}" ] + [ "$(jq -r '.[0].block_size' <<< "$lvol")" = "$AIO_BS" ] + [ "$(jq -r '.[0].num_blocks' <<< "$lvol")" = "$((lvol_size / AIO_BS))" ] + done + + for i in $(seq 1 10); do + rpc_cmd bdev_lvol_delete "lvs_test1/lvol_test${i}" + done + + rpc_cmd bdev_lvol_delete_lvstore -u "$lvs_uuid1" + + # Create an lvstore and 10 lvol on top to see if deletion of such struct works as it should. + lvs_uuid1=$(rpc_cmd bdev_lvol_create_lvstore aio_bdev0 lvs_test1) + for i in $(seq 1 10); do + rpc_cmd bdev_lvol_create -u "$lvs_uuid1" "lvol_test${i}" "$lvol_size_mb" + done + + # Clean up + rpc_cmd bdev_lvol_delete_lvstore -u "$lvs_uuid1" + rpc_cmd bdev_lvol_get_lvstores -u "$lvs_uuid1" && false + rpc_cmd bdev_lvol_delete_lvstore -u "$lvs_uuid2" + rpc_cmd bdev_lvol_get_lvstores -u "$lvs_uuid2" && false + rpc_cmd bdev_aio_delete aio_bdev0 + rpc_cmd bdev_aio_delete aio_bdev1 + check_leftover_devices +} + +# Positive test for removing lvol store persistently +function test_delete_lvol_store_persistent_positive() { + local aio0=$testdir/aio_bdev_0 + local bdev_aio_name=${aio0##*/} bdev_block_size=4096 + local lvstore_name=lvstore_test lvstore_uuid + + rpc_cmd bdev_aio_create "$aio0" "$bdev_aio_name" "$bdev_block_size" + + get_bdev_jq bdev_get_bdevs -b "$bdev_aio_name" + [[ ${jq_out["name"]} == "$bdev_aio_name" ]] + [[ ${jq_out["product_name"]} == "AIO disk" ]] + ((jq_out["block_size"] == bdev_block_size)) + + lvstore_uuid=$(rpc_cmd bdev_lvol_create_lvstore "$bdev_aio_name" "$lvstore_name") + + get_lvs_jq bdev_lvol_get_lvstores -u "$lvstore_uuid" + [[ ${jq_out["uuid"]} == "$lvstore_uuid" ]] + [[ ${jq_out["name"]} == "$lvstore_name" ]] + [[ ${jq_out["base_bdev"]} == "$bdev_aio_name" ]] + + rpc_cmd bdev_lvol_delete_lvstore -u "$lvstore_uuid" + rpc_cmd bdev_aio_delete "$bdev_aio_name" + # Create aio bdev on the same file + rpc_cmd bdev_aio_create "$aio0" "$bdev_aio_name" "$bdev_block_size" + # Wait 1 second to allow time for lvolstore tasting + sleep 1 + # bdev_lvol_get_lvstores should not report any existsing lvol stores in configuration + # after deleting and adding NVMe bdev, thus check if destroyed lvol store does not exist + # on aio bdev anymore. + rpc_cmd bdev_lvol_get_lvstores -u "$lvstore_uuid" && false + + # cleanup + rpc_cmd bdev_aio_delete "$bdev_aio_name" + check_leftover_devices +} + +$SPDK_BIN_DIR/spdk_tgt & +spdk_pid=$! +trap 'killprocess "$spdk_pid"; rm -f $testdir/aio_bdev_0 $testdir/aio_bdev_1; exit 1' SIGINT SIGTERM EXIT +waitforlisten $spdk_pid +truncate -s "${AIO_SIZE_MB}M" $testdir/aio_bdev_0 $testdir/aio_bdev_1 + +run_test "test_tasting" test_tasting +run_test "test_delete_lvol_store_persistent_positive" test_delete_lvol_store_persistent_positive + +trap - SIGINT SIGTERM EXIT +killprocess $spdk_pid +rm -f $testdir/aio_bdev_0 $testdir/aio_bdev_1 diff --git a/src/spdk/test/lvol/thin_provisioning.sh b/src/spdk/test/lvol/thin_provisioning.sh new file mode 100755 index 000000000..cb7bfcb01 --- /dev/null +++ b/src/spdk/test/lvol/thin_provisioning.sh @@ -0,0 +1,236 @@ +#!/usr/bin/env bash + +testdir=$(readlink -f $(dirname $0)) +rootdir=$(readlink -f $testdir/../..) +source $rootdir/test/common/autotest_common.sh +source $rootdir/test/lvol/common.sh +source $rootdir/test/bdev/nbd_common.sh + +# Check if number of free clusters on lvol store decreases +# if we write to created thin provisioned lvol bdev +function test_thin_lvol_check_space() { + malloc_name=$(rpc_cmd bdev_malloc_create $MALLOC_SIZE_MB $MALLOC_BS) + lvs_uuid=$(rpc_cmd bdev_lvol_create_lvstore "$malloc_name" lvs_test) + lvs=$(rpc_cmd bdev_lvol_get_lvstores -u "$lvs_uuid") + free_clusters_start="$(jq -r '.[0].free_clusters' <<< "$lvs")" + + # Create thin provision lvol bdev with size equals to lvol store space + lvol_size_mb=$(round_down $((LVS_DEFAULT_CAPACITY_MB))) + lvol_uuid=$(rpc_cmd bdev_lvol_create -u "$lvs_uuid" lvol_test "$lvol_size_mb" -t) + + lvs=$(rpc_cmd bdev_lvol_get_lvstores -u "$lvs_uuid") + free_clusters_create_lvol="$(jq -r '.[0].free_clusters' <<< "$lvs")" + [ $free_clusters_start == $free_clusters_create_lvol ] + + # Write data (lvs cluster size) to created lvol bdev starting from offset 0. + size=$LVS_DEFAULT_CLUSTER_SIZE + nbd_start_disks "$DEFAULT_RPC_ADDR" "$lvol_uuid" /dev/nbd0 + run_fio_test /dev/nbd0 0 $size "write" "0xcc" + lvs=$(rpc_cmd bdev_lvol_get_lvstores -u "$lvs_uuid") + free_clusters_first_fio="$(jq -r '.[0].free_clusters' <<< "$lvs")" + [ $((free_clusters_first_fio + 1)) == $free_clusters_start ] + + # Write data (lvs cluster size) to lvol bdev with offset set to one and half of cluster size + offset=$((LVS_DEFAULT_CLUSTER_SIZE * 3 / 2)) + size=$LVS_DEFAULT_CLUSTER_SIZE + run_fio_test /dev/nbd0 $offset $size "write" "0xcc" + lvs=$(rpc_cmd bdev_lvol_get_lvstores -u "$lvs_uuid") + free_clusters_second_fio="$(jq -r '.[0].free_clusters' <<< "$lvs")" + [ $((free_clusters_second_fio + 3)) == $free_clusters_start ] + + # write data to lvol bdev to the end of its size + size=$((LVS_DEFAULT_CLUSTER_SIZE * free_clusters_first_fio)) + offset=$((3 * LVS_DEFAULT_CLUSTER_SIZE)) + run_fio_test /dev/nbd0 $offset $size "write" "0xcc" + lvs=$(rpc_cmd bdev_lvol_get_lvstores -u "$lvs_uuid") + # Check that lvol store free clusters number equals to 0 + free_clusters_third_fio="$(jq -r '.[0].free_clusters' <<< "$lvs")" + [ $((free_clusters_third_fio)) == 0 ] + + nbd_stop_disks "$DEFAULT_RPC_ADDR" /dev/nbd0 + rpc_cmd bdev_lvol_delete "$lvol_uuid" + rpc_cmd bdev_get_bdevs -b "$lvol_uuid" && false + lvs=$(rpc_cmd bdev_lvol_get_lvstores -u "$lvs_uuid") + free_clusters_end="$(jq -r '.[0].free_clusters' <<< "$lvs")" + [ $((free_clusters_end)) == $free_clusters_start ] + + # Clean up + rpc_cmd bdev_lvol_delete_lvstore -u "$lvs_uuid" + rpc_cmd bdev_lvol_get_lvstores -u "$lvs_uuid" && false + rpc_cmd bdev_malloc_delete "$malloc_name" +} + +# Check if we can create thin provisioned bdev on empty lvol store +# and check if we can read from this device and it returns zeroes. +function test_thin_lvol_check_zeroes() { + malloc_name=$(rpc_cmd bdev_malloc_create $MALLOC_SIZE_MB $MALLOC_BS) + lvs_uuid=$(rpc_cmd bdev_lvol_create_lvstore "$malloc_name" lvs_test) + lvs=$(rpc_cmd bdev_lvol_get_lvstores -u "$lvs_uuid") + free_clusters_start="$(jq -r '.[0].free_clusters' <<< "$lvs")" + + # Create thick and thin provisioned lvol bdevs with size equals to lvol store space + lbd_name0=lvol_test0 + lbd_name1=lvol_test1 + lvol_size_mb=$((LVS_DEFAULT_CAPACITY_MB)) + # Round down lvol size to the nearest cluster size boundary + lvol_size_mb=$((lvol_size_mb / LVS_DEFAULT_CLUSTER_SIZE_MB * LVS_DEFAULT_CLUSTER_SIZE_MB)) + lvol_size=$((lvol_size_mb * 1024 * 1024)) + lvol_uuid0=$(rpc_cmd bdev_lvol_create -u "$lvs_uuid" $lbd_name0 "$lvol_size_mb") + lvol_uuid1=$(rpc_cmd bdev_lvol_create -u "$lvs_uuid" $lbd_name1 "$lvol_size_mb" -t) + + nbd_start_disks "$DEFAULT_RPC_ADDR" "$lvol_uuid0" /dev/nbd0 + nbd_start_disks "$DEFAULT_RPC_ADDR" "$lvol_uuid1" /dev/nbd1 + + # Fill the whole thick provisioned lvol bdev + run_fio_test /dev/nbd0 0 $lvol_size "write" "0xcc" + + # Perform read operations on thin provisioned lvol bdev + # and check if they return zeroes + run_fio_test /dev/nbd1 0 $lvol_size "read" "0x00" + + # Clean up + nbd_stop_disks "$DEFAULT_RPC_ADDR" /dev/nbd1 + nbd_stop_disks "$DEFAULT_RPC_ADDR" /dev/nbd0 + rpc_cmd bdev_lvol_delete "$lvol_uuid1" + rpc_cmd bdev_lvol_delete "$lvol_uuid0" + rpc_cmd bdev_lvol_delete_lvstore -u "$lvs_uuid" + rpc_cmd bdev_malloc_delete "$malloc_name" +} + +# Check if data written to thin provisioned lvol bdev +# were properly written (fio test with verification) +function test_thin_lvol_check_integrity() { + malloc_name=$(rpc_cmd bdev_malloc_create $MALLOC_SIZE_MB $MALLOC_BS) + lvs_uuid=$(rpc_cmd bdev_lvol_create_lvstore "$malloc_name" lvs_test) + + # Create thin provisioned lvol bdev with size equals to lvol store space + lvol_size_mb=$((LVS_DEFAULT_CAPACITY_MB)) + # Round down lvol size to the nearest cluster size boundary + lvol_size_mb=$((lvol_size_mb / LVS_DEFAULT_CLUSTER_SIZE_MB * LVS_DEFAULT_CLUSTER_SIZE_MB)) + lvol_size=$((lvol_size_mb * 1024 * 1024)) + lvol_uuid=$(rpc_cmd bdev_lvol_create -u "$lvs_uuid" lvol_test "$lvol_size_mb" -t) + + nbd_start_disks "$DEFAULT_RPC_ADDR" "$lvol_uuid" /dev/nbd0 + run_fio_test /dev/nbd0 0 $lvol_size "write" "0xcc" + + # Clean up + nbd_stop_disks "$DEFAULT_RPC_ADDR" /dev/nbd0 + rpc_cmd bdev_lvol_delete "$lvol_uuid" + rpc_cmd bdev_lvol_delete_lvstore -u "$lvs_uuid" + rpc_cmd bdev_malloc_delete "$malloc_name" +} + +# Check thin provisioned bdev resize +function test_thin_lvol_resize() { + malloc_name=$(rpc_cmd bdev_malloc_create $MALLOC_SIZE_MB $MALLOC_BS) + lvs_uuid=$(rpc_cmd bdev_lvol_create_lvstore "$malloc_name" lvs_test) + + # Construct thin provisioned lvol bdevs on created lvol store + # with size equal to 50% of lvol store + lvol_size_mb=$(round_down $((LVS_DEFAULT_CAPACITY_MB / 2))) + lvol_size=$((lvol_size_mb * 1024 * 1024)) + lvol_uuid=$(rpc_cmd bdev_lvol_create -u "$lvs_uuid" lvol_test "$lvol_size_mb" -t) + + # Fill all free space of lvol bdev with data + nbd_start_disks "$DEFAULT_RPC_ADDR" "$lvol_uuid" /dev/nbd0 + run_fio_test /dev/nbd0 0 $lvol_size "write" "0xcc" + nbd_stop_disks "$DEFAULT_RPC_ADDR" /dev/nbd0 + + # Save number of free clusters for lvs + lvs=$(rpc_cmd bdev_lvol_get_lvstores -u "$lvs_uuid") + free_clusters_start="$(jq -r '.[0].free_clusters' <<< "$lvs")" + # Resize bdev to full size of lvs + lvol_size_full_mb=$(round_down $((LVS_DEFAULT_CAPACITY_MB))) + lvol_size_full=$((lvol_size_full_mb * 1024 * 1024)) + rpc_cmd bdev_lvol_resize $lvol_uuid $lvol_size_full_mb + + # Check if bdev size changed (total_data_clusters*cluster_size + # equals to num_blocks*block_size) + lvol=$(rpc_cmd bdev_get_bdevs -b "$lvol_uuid") + [ "$(jq -r '.[0].block_size' <<< "$lvol")" = "$MALLOC_BS" ] + [ "$(jq -r '.[0].num_blocks' <<< "$lvol")" = $((lvol_size_full / MALLOC_BS)) ] + + # Check if free_clusters on lvs remain unaffected + lvs=$(rpc_cmd bdev_lvol_get_lvstores -u "$lvs_uuid") + free_clusters_resize="$(jq -r '.[0].free_clusters' <<< "$lvs")" + [ $free_clusters_start == $free_clusters_resize ] + + # Perform write operation with verification + # to newly created free space of lvol bdev + nbd_start_disks "$DEFAULT_RPC_ADDR" "$lvol_uuid" /dev/nbd0 + run_fio_test /dev/nbd0 0 $lvol_size_full "write" "0xcc" + nbd_stop_disks "$DEFAULT_RPC_ADDR" /dev/nbd0 + + # Check if free clusters on lvs equals to zero + lvs=$(rpc_cmd bdev_lvol_get_lvstores -u "$lvs_uuid") + free_clusters_start="$(jq -r '.[0].free_clusters' <<< "$lvs")" + [ $free_clusters_start == 0 ] + + # Resize bdev to 25% of lvs and check if it ended with success + lvol_size_quarter_mb=$(round_down $((LVS_DEFAULT_CAPACITY_MB / 4))) + rpc_cmd bdev_lvol_resize $lvol_uuid $lvol_size_quarter_mb + + # Check free clusters on lvs + lvs=$(rpc_cmd bdev_lvol_get_lvstores -u "$lvs_uuid") + free_clusters_resize_quarter="$(jq -r '.[0].free_clusters' <<< "$lvs")" + free_clusters_expected=$(((lvol_size_full_mb - lvol_size_quarter_mb) / LVS_DEFAULT_CLUSTER_SIZE_MB)) + [ $free_clusters_resize_quarter == $free_clusters_expected ] + + rpc_cmd bdev_lvol_delete "$lvol_uuid" + rpc_cmd bdev_lvol_delete_lvstore -u "$lvs_uuid" + rpc_cmd bdev_malloc_delete "$malloc_name" +} + +function test_thin_overprovisioning() { + malloc_name=$(rpc_cmd bdev_malloc_create $MALLOC_SIZE_MB $MALLOC_BS) + lvs_uuid=$(rpc_cmd bdev_lvol_create_lvstore "$malloc_name" lvs_test) + + # Construct two thin provisioned lvol bdevs on created lvol store + # with size equal to free lvol store size + lvol_size_mb=$(round_down $((LVS_DEFAULT_CAPACITY_MB))) + lvol_size=$((lvol_size_mb * 1024 * 1024)) + lvol_uuid1=$(rpc_cmd bdev_lvol_create -u "$lvs_uuid" lvol_test1 "$lvol_size_mb" -t) + lvol_uuid2=$(rpc_cmd bdev_lvol_create -u "$lvs_uuid" lvol_test2 "$lvol_size_mb" -t) + + nbd_start_disks "$DEFAULT_RPC_ADDR" "$lvol_uuid1" /dev/nbd0 + nbd_start_disks "$DEFAULT_RPC_ADDR" "$lvol_uuid2" /dev/nbd1 + # Fill first bdev to 50% of its space with specific pattern + fill_size=$((lvol_size_mb * 5 / 10 / LVS_DEFAULT_CLUSTER_SIZE_MB * LVS_DEFAULT_CLUSTER_SIZE_MB)) + fill_size=$((fill_size * 1024 * 1024)) + run_fio_test /dev/nbd0 0 $fill_size "write" "0xcc" + + # Fill second bdev up to 50% of its space + run_fio_test /dev/nbd1 0 $fill_size "write" "0xcc" + + # Fill rest of second bdev + # Check that error message occured while filling second bdev with data + offset=$fill_size + fill_size_rest=$((lvol_size - fill_size)) + run_fio_test /dev/nbd1 "$offset" "$fill_size_rest" "write" "0xcc" && false + + # Check if data on first disk stayed unchanged + run_fio_test /dev/nbd0 0 $fill_size "read" "0xcc" + run_fio_test /dev/nbd0 $offset $fill_size_rest "read" "0x00" + + nbd_stop_disks "$DEFAULT_RPC_ADDR" /dev/nbd0 + nbd_stop_disks "$DEFAULT_RPC_ADDR" /dev/nbd1 + + rpc_cmd bdev_lvol_delete "$lvol_uuid2" + rpc_cmd bdev_lvol_delete "$lvol_uuid1" + rpc_cmd bdev_lvol_delete_lvstore -u "$lvs_uuid" + rpc_cmd bdev_malloc_delete "$malloc_name" +} + +$SPDK_BIN_DIR/spdk_tgt & +spdk_pid=$! +trap 'killprocess "$spdk_pid"; exit 1' SIGINT SIGTERM EXIT +waitforlisten $spdk_pid + +run_test "test_thin_lvol_check_space" test_thin_lvol_check_space +run_test "test_thin_lvol_check_zeroes" test_thin_lvol_check_zeroes +run_test "test_thin_lvol_check_integrity" test_thin_lvol_check_integrity +run_test "test_thin_lvol_resize" test_thin_lvol_resize +run_test "test_thin_overprovisioning" test_thin_overprovisioning + +trap - SIGINT SIGTERM EXIT +killprocess $spdk_pid |