diff --git a/test/lvol/lvol.sh b/test/lvol/lvol.sh index 4d0048d69..607865771 100755 --- a/test/lvol/lvol.sh +++ b/test/lvol/lvol.sh @@ -35,8 +35,6 @@ function usage() { 653: 'thin_provisioning_resize', 654: 'thin_overprovisioning', 655: 'thin_provisioning_filling_disks_less_than_lvs_size', - 758: 'clone_decouple_parent', - 759: 'clone_decouple_parent_rw', 760: 'set_read_only', 761: 'delete_snapshot', 762: 'delete_snapshot_with_snapshot', diff --git a/test/lvol/snapshot_clone.sh b/test/lvol/snapshot_clone.sh index 841616d25..17e7a3a8d 100755 --- a/test/lvol/snapshot_clone.sh +++ b/test/lvol/snapshot_clone.sh @@ -277,6 +277,101 @@ function test_clone_inflate() { 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 +} + $rootdir/app/spdk_tgt/spdk_tgt & spdk_pid=$! trap 'killprocess "$spdk_pid"; exit 1' SIGINT SIGTERM EXIT @@ -288,6 +383,7 @@ 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 trap - SIGINT SIGTERM EXIT killprocess $spdk_pid diff --git a/test/lvol/test_cases.py b/test/lvol/test_cases.py index 5f6b938da..6d1f88ebe 100644 --- a/test/lvol/test_cases.py +++ b/test/lvol/test_cases.py @@ -126,8 +126,6 @@ def case_message(func): 654: 'thin_overprovisioning', 655: 'thin_provisioning_filling_disks_less_than_lvs_size', # snapshot and clone - 758: 'decouple_parent', - 759: 'decouple_parent_rw', 760: 'set_read_only', 761: 'delete_snapshot', 762: 'delete_snapshot_with_snapshot', @@ -980,179 +978,6 @@ class TestCases(object): # - no other operation fails return fail_count - @case_message - def test_case758(self): - """ - clone_decouple_parent - - Detach parent from clone and check if parent can be safely removed. - Check data consistency. - """ - - fail_count = 0 - snapshot_name = "snapshot" - nbd_name = "/dev/nbd0" - - # Create malloc bdev - base_name = self.c.bdev_malloc_create(self.total_size, - self.block_size) - - # Create lvol store - uuid_store = self.c.bdev_lvol_create_lvstore(base_name, - self.lvs_name) - fail_count += self.c.check_bdev_lvol_get_lvstores(base_name, uuid_store, - self.cluster_size) - size = self.get_lvs_divided_size(4) - - # Construct thin provisioned lvol bdev - uuid_bdev0 = self.c.bdev_lvol_create(uuid_store, - self.lbd_name, size, thin=True) - lvol_bdev = self.c.get_lvol_bdev_with_name(uuid_bdev0) - - # Decouple parent lvol bdev and check if it fails - ret_value = self.c.bdev_lvol_decouple_parent(lvol_bdev['name']) - if ret_value == 0: - print("ERROR: Decouple parent on bdev without parent should " - "fail but didn't") - fail_count += 1 - - # Create snapshot of thin provisioned lvol bdev - fail_count += self.c.bdev_lvol_snapshot(lvol_bdev['name'], snapshot_name) - snapshot_bdev = self.c.get_lvol_bdev_with_name(self.lvs_name + "/" + snapshot_name) - - # Decouple parent lvol bdev - fail_count += self.c.bdev_lvol_decouple_parent(lvol_bdev['name']) - lvol_bdev = self.c.get_lvol_bdev_with_name(uuid_bdev0) - snapshot_bdev = self.c.get_lvol_bdev_with_name(self.lvs_name + "/" + snapshot_name) - if lvol_bdev['driver_specific']['lvol']['thin_provision'] is not True: - fail_count += 1 - if lvol_bdev['driver_specific']['lvol']['clone'] is not False: - fail_count += 1 - if lvol_bdev['driver_specific']['lvol']['snapshot'] is not False: - fail_count += 1 - if snapshot_bdev['driver_specific']['lvol']['clone'] is not False: - fail_count += 1 - - # Destroy snapshot - fail_count += self.c.bdev_lvol_delete(snapshot_bdev['name']) - - # Destroy lvol bdev - fail_count += self.c.bdev_lvol_delete(lvol_bdev['name']) - - # Destroy lvol store - fail_count += self.c.bdev_lvol_delete_lvstore(uuid_store) - - # Delete malloc - fail_count += self.c.bdev_malloc_delete(base_name) - - # Expected result: - # - calls successful, return code = 0 - # - no other operation fails - return fail_count - - @case_message - def test_case759(self): - """ - clone_decouple_parent_rw - - Create tree level snaphot-snapshot2-clone structure. - Detach snapshot2 from clone. Check if snapshot2 can be safely removed. - Each time check consistency of snapshot-clone relations and written data. - """ - fail_count = 0 - snapshot_name = "snapshot" - snapshot_name2 = "snapshot2" - nbd_name = "/dev/nbd0" - - # Create malloc bdev - base_name = self.c.bdev_malloc_create(self.total_size, - self.block_size) - - # Create lvol store - uuid_store = self.c.bdev_lvol_create_lvstore(base_name, - self.lvs_name) - fail_count += self.c.check_bdev_lvol_get_lvstores(base_name, uuid_store, - self.cluster_size) - lvs = self.c.bdev_lvol_get_lvstores() - size = int(5 * lvs[0]['cluster_size'] / MEGABYTE) - - # Construct thin provisioned lvol bdev - uuid_bdev0 = self.c.bdev_lvol_create(uuid_store, - self.lbd_name, size, thin=True) - lvol_bdev = self.c.get_lvol_bdev_with_name(uuid_bdev0) - - # Fill first four out of 5 culsters of clone with data of known pattern - fail_count += self.c.nbd_start_disk(lvol_bdev['name'], nbd_name) - begin_fill = 0 - end_fill = int(size * 4 / 5) - fail_count += self.run_fio_test(nbd_name, begin_fill * MEGABYTE, - end_fill * MEGABYTE, "write", "0xdd", 0) - - # Create snapshot of thin provisioned lvol bdev - fail_count += self.c.bdev_lvol_snapshot(lvol_bdev['name'], snapshot_name) - snapshot_bdev = self.c.get_lvol_bdev_with_name(self.lvs_name + "/" + snapshot_name) - - # Fill second and fourth cluster of clone with data of known pattern - start_fill = int(size / 5) - fill_range = int(size / 5) - fail_count += self.run_fio_test(nbd_name, start_fill * MEGABYTE, - fill_range * MEGABYTE, "write", "0xcc", 0) - start_fill = int(size * 3 / 5) - fail_count += self.run_fio_test(nbd_name, start_fill * MEGABYTE, - fill_range * MEGABYTE, "write", "0xcc", 0) - - # Create second snapshot of thin provisioned lvol bdev - fail_count += self.c.bdev_lvol_snapshot(lvol_bdev['name'], snapshot_name2) - snapshot_bdev2 = self.c.get_lvol_bdev_with_name(self.lvs_name + "/" + snapshot_name2) - - # Fill second cluster of clone with data of known pattern - start_fill = int(size / 5) - fail_count += self.run_fio_test(nbd_name, start_fill * MEGABYTE, - fill_range * MEGABYTE, "write", "0xee", 0) - - # Check data consistency - pattern = ["0xdd", "0xee", "0xdd", "0xcc", "0x00"] - for i in range(0, 5): - begin_fill = int(size * i / 5) - fail_count += self.run_fio_test(nbd_name, begin_fill * MEGABYTE, - fill_range * MEGABYTE, "read", pattern[i]) - - # Decouple parent - fail_count += self.c.bdev_lvol_decouple_parent(lvol_bdev['name']) - lvol_bdev = self.c.get_lvol_bdev_with_name(uuid_bdev0) - - # Check data consistency - for i in range(0, 5): - begin_fill = int(size * i / 5) - fail_count += self.run_fio_test(nbd_name, begin_fill * MEGABYTE, - fill_range * MEGABYTE, "read", pattern[i]) - - # Delete second snapshot - ret_value = self.c.bdev_lvol_delete(snapshot_bdev2['name']) - - # Check data consistency - for i in range(0, 5): - begin_fill = int(size * i / 5) - fail_count += self.run_fio_test(nbd_name, begin_fill * MEGABYTE, - fill_range * MEGABYTE, "read", pattern[i]) - - # Destroy lvol bdev - fail_count += self.c.bdev_lvol_delete(lvol_bdev['name']) - - # Destroy snapshot - fail_count += self.c.bdev_lvol_delete(snapshot_bdev['name']) - - # Destroy lvol store - fail_count += self.c.bdev_lvol_delete_lvstore(uuid_store) - - # Delete malloc - fail_count += self.c.bdev_malloc_delete(base_name) - - # Expected result: - # - calls successful, return code = 0 - # - no other operation fails - return fail_count - @case_message def test_case760(self): """