diff options
Diffstat (limited to '')
-rwxr-xr-x | src/spdk/test/lvol/snapshot_clone.sh | 617 |
1 files changed, 617 insertions, 0 deletions
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 |