summaryrefslogtreecommitdiffstats
path: root/src/spdk/test/lvol
diff options
context:
space:
mode:
authorDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-21 11:54:28 +0000
committerDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-21 11:54:28 +0000
commite6918187568dbd01842d8d1d2c808ce16a894239 (patch)
tree64f88b554b444a49f656b6c656111a145cbbaa28 /src/spdk/test/lvol
parentInitial commit. (diff)
downloadceph-e6918187568dbd01842d8d1d2c808ce16a894239.tar.xz
ceph-e6918187568dbd01842d8d1d2c808ce16a894239.zip
Adding upstream version 18.2.2.upstream/18.2.2
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'src/spdk/test/lvol')
-rwxr-xr-xsrc/spdk/test/lvol/basic.sh568
-rw-r--r--src/spdk/test/lvol/common.sh53
-rwxr-xr-xsrc/spdk/test/lvol/hotremove.sh216
-rwxr-xr-xsrc/spdk/test/lvol/lvol2.sh19
-rwxr-xr-xsrc/spdk/test/lvol/rename.sh219
-rwxr-xr-xsrc/spdk/test/lvol/resize.sh219
-rwxr-xr-xsrc/spdk/test/lvol/snapshot_clone.sh617
-rwxr-xr-xsrc/spdk/test/lvol/tasting.sh171
-rwxr-xr-xsrc/spdk/test/lvol/thin_provisioning.sh236
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