xref: /spdk/test/lvol/resize.sh (revision c680e3a05b1a903c18bf3f75b732765607126f45)
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