1#!/usr/bin/env bash 2# SPDX-License-Identifier: BSD-3-Clause 3# Copyright (C) 2019 Intel Corporation 4# All rights reserved. 5# 6testdir=$(readlink -f $(dirname $0)) 7rootdir=$(readlink -f $testdir/../..) 8source $rootdir/test/common/autotest_common.sh 9source $rootdir/test/lvol/common.sh 10source $rootdir/test/bdev/nbd_common.sh 11 12# resize an lvol a few times 13function test_resize_lvol() { 14 # create an lvol store 15 malloc_name=$(rpc_cmd bdev_malloc_create $MALLOC_SIZE_MB $MALLOC_BS) 16 lvs_uuid=$(rpc_cmd bdev_lvol_create_lvstore "$malloc_name" lvs_test) 17 18 # calculate lvol size 19 lvol_size_mb=$(round_down $((LVS_DEFAULT_CAPACITY_MB / 4))) 20 lvol_size=$((lvol_size_mb * 1024 * 1024)) 21 22 # create an lvol on top 23 lvol_uuid=$(rpc_cmd bdev_lvol_create -u "$lvs_uuid" lvol_test "$lvol_size_mb") 24 lvol=$(rpc_cmd bdev_get_bdevs -b "$lvol_uuid") 25 [ "$(jq -r '.[0].name' <<< "$lvol")" = "$lvol_uuid" ] 26 [ "$(jq -r '.[0].uuid' <<< "$lvol")" = "$lvol_uuid" ] 27 [ "$(jq -r '.[0].aliases[0]' <<< "$lvol")" = "lvs_test/lvol_test" ] 28 [ "$(jq -r '.[0].block_size' <<< "$lvol")" = "$MALLOC_BS" ] 29 [ "$(jq -r '.[0].num_blocks' <<< "$lvol")" = "$((lvol_size / MALLOC_BS))" ] 30 31 # resize the lvol to twice its original size 32 lvol_size_mb=$((lvol_size_mb * 2)) 33 lvol_size=$((lvol_size_mb * 1024 * 1024)) 34 rpc_cmd bdev_lvol_resize "$lvol_uuid" "$lvol_size_mb" 35 lvol=$(rpc_cmd bdev_get_bdevs -b "$lvol_uuid") 36 [ "$(jq -r '.[0].num_blocks' <<< "$lvol")" = "$((lvol_size / MALLOC_BS))" ] 37 38 # resize the lvol to four times its original size, use its name instead of uuid 39 lvol_size_mb=$((lvol_size_mb * 2)) 40 lvol_size=$((lvol_size_mb * 1024 * 1024)) 41 rpc_cmd bdev_lvol_resize lvs_test/lvol_test "$lvol_size_mb" 42 lvol=$(rpc_cmd bdev_get_bdevs -b "$lvol_uuid") 43 [ "$(jq -r '.[0].num_blocks' <<< "$lvol")" = "$((lvol_size / MALLOC_BS))" ] 44 45 # resize the lvol to 0 using lvol bdev alias 46 lvol_size_mb=0 47 lvol_size=0 48 rpc_cmd bdev_lvol_resize "lvs_test/lvol_test" "$lvol_size_mb" 49 lvol=$(rpc_cmd bdev_get_bdevs -b "$lvol_uuid") 50 [ "$(jq -r '.[0].num_blocks' <<< "$lvol")" = "$((lvol_size / MALLOC_BS))" ] 51 52 # clean up 53 rpc_cmd bdev_lvol_delete "$lvol_uuid" 54 rpc_cmd bdev_get_bdevs -b "$lvol_uuid" && false 55 rpc_cmd bdev_lvol_delete_lvstore -u "$lvs_uuid" 56 rpc_cmd bdev_lvol_get_lvstores -u "$lvs_uuid" && false 57 rpc_cmd bdev_malloc_delete "$malloc_name" 58} 59 60# negative test for resizing a logical volume 61# call bdev_lvol_resize with logical volume which does not exist in configuration 62# call bdev_lvol_resize with size argument bigger than size of base bdev 63function test_resize_lvol_negative() { 64 # create an lvol store 65 malloc_name=$(rpc_cmd bdev_malloc_create $MALLOC_SIZE_MB $MALLOC_BS) 66 lvs_uuid=$(rpc_cmd bdev_lvol_create_lvstore "$malloc_name" lvs_test) 67 68 # create an lvol on top 69 lvol_uuid=$(rpc_cmd bdev_lvol_create -u "$lvs_uuid" lvol_test "$LVS_DEFAULT_CAPACITY_MB") 70 71 # try to resize another, inexistent lvol 72 dummy_uuid="00000000-0000-0000-0000-000000000000" 73 rpc_cmd bdev_lvol_resize "$dummy_uuid" 0 && false 74 # just make sure the size of the real lvol did not change 75 lvol=$(rpc_cmd bdev_get_bdevs -b "$lvol_uuid") 76 [ "$(jq -r '.[0].num_blocks' <<< "$lvol")" = "$((LVS_DEFAULT_CAPACITY / MALLOC_BS))" ] 77 78 # try to resize an lvol to a size bigger than lvs 79 rpc_cmd bdev_lvol_resize "$lvol_uuid" "$MALLOC_SIZE_MB" && false 80 # just make sure the size of the real lvol did not change 81 lvol=$(rpc_cmd bdev_get_bdevs -b "$lvol_uuid") 82 [ "$(jq -r '.[0].num_blocks' <<< "$lvol")" = "$((LVS_DEFAULT_CAPACITY / MALLOC_BS))" ] 83 84 # clean up 85 rpc_cmd bdev_lvol_delete "$lvol_uuid" 86 rpc_cmd bdev_get_bdevs -b "$lvol_uuid" && false 87 rpc_cmd bdev_lvol_delete_lvstore -u "$lvs_uuid" 88 rpc_cmd bdev_lvol_get_lvstores -u "$lvs_uuid" && false 89 rpc_cmd bdev_malloc_delete "$malloc_name" 90} 91 92# resize an lvol a few times 93function test_resize_lvol_with_io_traffic() { 94 # create an lvol store 95 malloc_name=$(rpc_cmd bdev_malloc_create $MALLOC_SIZE_MB $MALLOC_BS) 96 lvs_uuid=$(rpc_cmd bdev_lvol_create_lvstore "$malloc_name" lvs_test) 97 98 # calculate lvol size 99 lvol_size_mb=$(round_down $((LVS_DEFAULT_CAPACITY_MB / 2))) 100 lvol_size=$((lvol_size_mb * 1024 * 1024)) 101 102 # create an lvol on top 103 lvol_uuid=$(rpc_cmd bdev_lvol_create -u "$lvs_uuid" lvol_test "$lvol_size_mb") 104 lvol=$(rpc_cmd bdev_get_bdevs -b "$lvol_uuid") 105 [ "$(jq -r '.[0].name' <<< "$lvol")" = "$lvol_uuid" ] 106 [ "$(jq -r '.[0].uuid' <<< "$lvol")" = "$lvol_uuid" ] 107 [ "$(jq -r '.[0].aliases[0]' <<< "$lvol")" = "lvs_test/lvol_test" ] 108 [ "$(jq -r '.[0].block_size' <<< "$lvol")" = "$MALLOC_BS" ] 109 [ "$(jq -r '.[0].num_blocks' <<< "$lvol")" = "$((lvol_size / MALLOC_BS))" ] 110 111 # prepare to do some I/O 112 trap 'nbd_stop_disks "$DEFAULT_RPC_ADDR" /dev/nbd0; exit 1' SIGINT SIGTERM EXIT 113 nbd_start_disks "$DEFAULT_RPC_ADDR" "$lvol_uuid" /dev/nbd0 114 115 # write to the entire lvol 116 count=$((lvol_size / LVS_DEFAULT_CLUSTER_SIZE)) 117 dd if=/dev/urandom of=/dev/nbd0 oflag=direct bs="$LVS_DEFAULT_CLUSTER_SIZE" count=$count 118 119 # writing beyond lvol size should fail 120 offset=$((lvol_size / LVS_DEFAULT_CLUSTER_SIZE + 1)) 121 dd if=/dev/urandom of=/dev/nbd0 oflag=direct bs="$LVS_DEFAULT_CLUSTER_SIZE" seek=$offset count=1 && false 122 123 # resize the lvol to twice its original size 124 lvol_size_mb=$((lvol_size_mb * 2)) 125 lvol_size=$((lvol_size_mb * 1024 * 1024)) 126 rpc_cmd bdev_lvol_resize "$lvol_uuid" "$lvol_size_mb" 127 lvol=$(rpc_cmd bdev_get_bdevs -b "$lvol_uuid") 128 [ "$(jq -r '.[0].num_blocks' <<< "$lvol")" = "$((lvol_size / MALLOC_BS))" ] 129 130 # writing beyond the original lvol size should now succeed, we need 131 # to restart NBD though as it may still use the old, cached size 132 nbd_stop_disks "$DEFAULT_RPC_ADDR" /dev/nbd0 133 nbd_start_disks "$DEFAULT_RPC_ADDR" "$lvol_uuid" /dev/nbd0 134 dd if=/dev/urandom of=/dev/nbd0 oflag=direct bs="$LVS_DEFAULT_CLUSTER_SIZE" seek=$offset count=1 135 136 # lvol can't be downsized if they have any open descriptors, so close them now 137 trap - SIGINT SIGTERM EXIT 138 nbd_stop_disks "$DEFAULT_RPC_ADDR" /dev/nbd0 139 140 # resize lvol down to a single cluster 141 rpc_cmd bdev_lvol_resize "$lvol_uuid" "$LVS_DEFAULT_CLUSTER_SIZE_MB" 142 lvol=$(rpc_cmd bdev_get_bdevs -b "$lvol_uuid") 143 [ "$(jq -r '.[0].num_blocks' <<< "$lvol")" = "$((LVS_DEFAULT_CLUSTER_SIZE / MALLOC_BS))" ] 144 145 # make sure we can't write beyond the first cluster 146 trap 'nbd_stop_disks "$DEFAULT_RPC_ADDR" /dev/nbd0; exit 1' SIGINT SIGTERM EXIT 147 nbd_start_disks "$DEFAULT_RPC_ADDR" "$lvol_uuid" /dev/nbd0 148 dd if=/dev/urandom of=/dev/nbd0 oflag=direct bs="$LVS_DEFAULT_CLUSTER_SIZE" seek=1 count=1 && false 149 150 # clean up 151 trap - SIGINT SIGTERM EXIT 152 nbd_stop_disks "$DEFAULT_RPC_ADDR" /dev/nbd0 153 rpc_cmd bdev_lvol_delete "$lvol_uuid" 154 rpc_cmd bdev_get_bdevs -b "$lvol_uuid" && false 155 rpc_cmd bdev_lvol_delete_lvstore -u "$lvs_uuid" 156 rpc_cmd bdev_lvol_get_lvstores -u "$lvs_uuid" && false 157 rpc_cmd bdev_malloc_delete "$malloc_name" 158} 159 160# Positive test for destroying a logical_volume after resizing. 161# Call bdev_lvol_delete_lvstore with correct logical_volumes name. 162function test_destroy_after_bdev_lvol_resize_positive() { 163 local malloc_dev 164 local lvstore_name=lvs_test lvstore_uuid 165 local lbd_name=lbd_test bdev_uuid bdev_size 166 167 malloc_dev=$(rpc_cmd bdev_malloc_create 256 "$MALLOC_BS") 168 lvstore_uuid=$(rpc_cmd bdev_lvol_create_lvstore "$malloc_dev" "$lvstore_name") 169 170 get_lvs_jq bdev_lvol_get_lvstores -u "$lvstore_uuid" 171 [[ ${jq_out["uuid"]} == "$lvstore_uuid" ]] 172 [[ ${jq_out["name"]} == "$lvstore_name" ]] 173 174 bdev_size=$(round_down $((LVS_DEFAULT_CAPACITY_MB / 4))) 175 bdev_uuid=$(rpc_cmd bdev_lvol_create -u "$lvstore_uuid" "$lbd_name" "$bdev_size") 176 177 # start resizing in the following fashion: 178 # - size is equal to one quarter of size malloc bdev plus 4 MB 179 # - size is equal half of size malloc bdev 180 # - size is equal to three quarters of size malloc bdev 181 # - size is equal to size if malloc bdev minus 4 MB 182 # - size is equal 0 MiB 183 local resize 184 for resize in \ 185 "$bdev_size" \ 186 $((bdev_size + 4)) \ 187 $((bdev_size * 2)) \ 188 $((bdev_size * 3)) \ 189 $((bdev_size * 4 - 4)) \ 190 0; do 191 resize=$(round_down $((resize / 4))) 192 rpc_cmd bdev_lvol_resize "$bdev_uuid" "$resize" 193 194 get_bdev_jq bdev_get_bdevs -b "$bdev_uuid" 195 [[ ${jq_out["name"]} == "$bdev_uuid" ]] 196 [[ ${jq_out["name"]} == "${jq_out["uuid"]}" ]] 197 ((jq_out["block_size"] == MALLOC_BS)) 198 ((jq_out["num_blocks"] * jq_out["block_size"] == resize * 1024 ** 2)) 199 done 200 201 # cleanup 202 rpc_cmd bdev_lvol_delete "$bdev_uuid" 203 rpc_cmd bdev_lvol_delete_lvstore -u "$lvstore_uuid" 204 rpc_cmd bdev_get_bdevs -b "$bdev_uuid" && false 205 rpc_cmd bdev_lvol_get_lvstores -u "$lvstore_uuid" && false 206 rpc_cmd bdev_malloc_delete "$malloc_dev" 207 check_leftover_devices 208} 209 210modprobe nbd 211$SPDK_BIN_DIR/spdk_tgt & 212spdk_pid=$! 213trap 'killprocess "$spdk_pid"; exit 1' SIGINT SIGTERM EXIT 214waitforlisten $spdk_pid 215 216run_test "test_resize_lvol" test_resize_lvol 217run_test "test_resize_lvol_negative" test_resize_lvol_negative 218run_test "test_resize_lvol_with_io_traffic" test_resize_lvol_with_io_traffic 219run_test "test_destroy_after_bdev_lvol_resize_positive" test_destroy_after_bdev_lvol_resize_positive 220 221trap - SIGINT SIGTERM EXIT 222killprocess $spdk_pid 223