xref: /spdk/test/lvol/thin_provisioning.sh (revision eb53c23236cccb6b698b7ca70ee783da1c574b5f)
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# Check if number of free clusters on lvol store decreases
13# if we write to created thin provisioned lvol bdev
14function test_thin_lvol_check_space() {
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	lvs=$(rpc_cmd bdev_lvol_get_lvstores -u "$lvs_uuid")
18	free_clusters_start="$(jq -r '.[0].free_clusters' <<< "$lvs")"
19
20	# Create thin provision lvol bdev with size equals to lvol store space
21	lvol_size_mb=$(round_down $((LVS_DEFAULT_CAPACITY_MB)))
22	lvol_uuid=$(rpc_cmd bdev_lvol_create -u "$lvs_uuid" lvol_test "$lvol_size_mb" -t)
23
24	lvs=$(rpc_cmd bdev_lvol_get_lvstores -u "$lvs_uuid")
25	free_clusters_create_lvol="$(jq -r '.[0].free_clusters' <<< "$lvs")"
26	[ $free_clusters_start == $free_clusters_create_lvol ]
27
28	# Write data (lvs cluster size) to created lvol bdev starting from offset 0.
29	size=$LVS_DEFAULT_CLUSTER_SIZE
30	nbd_start_disks "$DEFAULT_RPC_ADDR" "$lvol_uuid" /dev/nbd0
31	run_fio_test /dev/nbd0 0 $size "write" "0xcc"
32	lvs=$(rpc_cmd bdev_lvol_get_lvstores -u "$lvs_uuid")
33	free_clusters_first_fio="$(jq -r '.[0].free_clusters' <<< "$lvs")"
34	[ $((free_clusters_first_fio + 1)) == $free_clusters_start ]
35
36	# Write data (lvs cluster size) to lvol bdev with offset set to one and half of cluster size
37	offset=$((LVS_DEFAULT_CLUSTER_SIZE * 3 / 2))
38	size=$LVS_DEFAULT_CLUSTER_SIZE
39	run_fio_test /dev/nbd0 $offset $size "write" "0xcc"
40	lvs=$(rpc_cmd bdev_lvol_get_lvstores -u "$lvs_uuid")
41	free_clusters_second_fio="$(jq -r '.[0].free_clusters' <<< "$lvs")"
42	[ $((free_clusters_second_fio + 3)) == $free_clusters_start ]
43
44	# write data to lvol bdev to the end of its size
45	size=$((LVS_DEFAULT_CLUSTER_SIZE * free_clusters_first_fio))
46	offset=$((3 * LVS_DEFAULT_CLUSTER_SIZE))
47	run_fio_test /dev/nbd0 $offset $size "write" "0xcc"
48	lvs=$(rpc_cmd bdev_lvol_get_lvstores -u "$lvs_uuid")
49	# Check that lvol store free clusters number equals to 0
50	free_clusters_third_fio="$(jq -r '.[0].free_clusters' <<< "$lvs")"
51	[ $((free_clusters_third_fio)) == 0 ]
52
53	nbd_stop_disks "$DEFAULT_RPC_ADDR" /dev/nbd0
54	rpc_cmd bdev_lvol_delete "$lvol_uuid"
55	rpc_cmd bdev_get_bdevs -b "$lvol_uuid" && false
56	lvs=$(rpc_cmd bdev_lvol_get_lvstores -u "$lvs_uuid")
57	free_clusters_end="$(jq -r '.[0].free_clusters' <<< "$lvs")"
58	[ $((free_clusters_end)) == $free_clusters_start ]
59
60	# Clean up
61	rpc_cmd bdev_lvol_delete_lvstore -u "$lvs_uuid"
62	rpc_cmd bdev_lvol_get_lvstores -u "$lvs_uuid" && false
63	rpc_cmd bdev_malloc_delete "$malloc_name"
64}
65
66# Check if we can create thin provisioned bdev on empty lvol store
67# and check if we can read from this device and it returns zeroes.
68function test_thin_lvol_check_zeroes() {
69	malloc_name=$(rpc_cmd bdev_malloc_create $MALLOC_SIZE_MB $MALLOC_BS)
70	lvs_uuid=$(rpc_cmd bdev_lvol_create_lvstore "$malloc_name" lvs_test)
71	lvs=$(rpc_cmd bdev_lvol_get_lvstores -u "$lvs_uuid")
72	free_clusters_start="$(jq -r '.[0].free_clusters' <<< "$lvs")"
73
74	# Create thick and thin provisioned lvol bdevs with size equals to lvol store space
75	lbd_name0=lvol_test0
76	lbd_name1=lvol_test1
77	lvol_size_mb=$((LVS_DEFAULT_CAPACITY_MB))
78	# Round down lvol size to the nearest cluster size boundary
79	lvol_size_mb=$((lvol_size_mb / LVS_DEFAULT_CLUSTER_SIZE_MB * LVS_DEFAULT_CLUSTER_SIZE_MB))
80	lvol_size=$((lvol_size_mb * 1024 * 1024))
81	lvol_uuid0=$(rpc_cmd bdev_lvol_create -u "$lvs_uuid" $lbd_name0 "$lvol_size_mb")
82	lvol_uuid1=$(rpc_cmd bdev_lvol_create -u "$lvs_uuid" $lbd_name1 "$lvol_size_mb" -t)
83
84	nbd_start_disks "$DEFAULT_RPC_ADDR" "$lvol_uuid0" /dev/nbd0
85	nbd_start_disks "$DEFAULT_RPC_ADDR" "$lvol_uuid1" /dev/nbd1
86
87	# Fill the whole thick provisioned lvol bdev
88	run_fio_test /dev/nbd0 0 $lvol_size "write" "0xcc"
89
90	# Perform read operations on thin provisioned lvol bdev
91	# and check if they return zeroes
92	run_fio_test /dev/nbd1 0 $lvol_size "read" "0x00"
93
94	# Clean up
95	nbd_stop_disks "$DEFAULT_RPC_ADDR" /dev/nbd1
96	nbd_stop_disks "$DEFAULT_RPC_ADDR" /dev/nbd0
97	rpc_cmd bdev_lvol_delete "$lvol_uuid1"
98	rpc_cmd bdev_lvol_delete "$lvol_uuid0"
99	rpc_cmd bdev_lvol_delete_lvstore -u "$lvs_uuid"
100	rpc_cmd bdev_malloc_delete "$malloc_name"
101}
102
103# Check if data written to thin provisioned lvol bdev
104# were properly written (fio test with verification)
105function test_thin_lvol_check_integrity() {
106	malloc_name=$(rpc_cmd bdev_malloc_create $MALLOC_SIZE_MB $MALLOC_BS)
107	lvs_uuid=$(rpc_cmd bdev_lvol_create_lvstore "$malloc_name" lvs_test)
108
109	# Create thin provisioned lvol bdev with size equals to lvol store space
110	lvol_size_mb=$((LVS_DEFAULT_CAPACITY_MB))
111	# Round down lvol size to the nearest cluster size boundary
112	lvol_size_mb=$((lvol_size_mb / LVS_DEFAULT_CLUSTER_SIZE_MB * LVS_DEFAULT_CLUSTER_SIZE_MB))
113	lvol_size=$((lvol_size_mb * 1024 * 1024))
114	lvol_uuid=$(rpc_cmd bdev_lvol_create -u "$lvs_uuid" lvol_test "$lvol_size_mb" -t)
115
116	nbd_start_disks "$DEFAULT_RPC_ADDR" "$lvol_uuid" /dev/nbd0
117	run_fio_test /dev/nbd0 0 $lvol_size "write" "0xcc"
118
119	# Clean up
120	nbd_stop_disks "$DEFAULT_RPC_ADDR" /dev/nbd0
121	rpc_cmd bdev_lvol_delete "$lvol_uuid"
122	rpc_cmd bdev_lvol_delete_lvstore -u "$lvs_uuid"
123	rpc_cmd bdev_malloc_delete "$malloc_name"
124}
125
126# Check thin provisioned bdev resize
127function test_thin_lvol_resize() {
128	malloc_name=$(rpc_cmd bdev_malloc_create $MALLOC_SIZE_MB $MALLOC_BS)
129	lvs_uuid=$(rpc_cmd bdev_lvol_create_lvstore "$malloc_name" lvs_test)
130
131	# Construct thin provisioned lvol bdevs on created lvol store
132	# with size equal to 50% of lvol store
133	lvol_size_mb=$(round_down $((LVS_DEFAULT_CAPACITY_MB / 2)))
134	lvol_size=$((lvol_size_mb * 1024 * 1024))
135	lvol_uuid=$(rpc_cmd bdev_lvol_create -u "$lvs_uuid" lvol_test "$lvol_size_mb" -t)
136
137	# Fill all free space of lvol bdev with data
138	nbd_start_disks "$DEFAULT_RPC_ADDR" "$lvol_uuid" /dev/nbd0
139	run_fio_test /dev/nbd0 0 $lvol_size "write" "0xcc"
140	nbd_stop_disks "$DEFAULT_RPC_ADDR" /dev/nbd0
141
142	# Save number of free clusters for lvs
143	lvs=$(rpc_cmd bdev_lvol_get_lvstores -u "$lvs_uuid")
144	free_clusters_start="$(jq -r '.[0].free_clusters' <<< "$lvs")"
145	# Resize bdev to full size of lvs
146	lvol_size_full_mb=$(round_down $((LVS_DEFAULT_CAPACITY_MB)))
147	lvol_size_full=$((lvol_size_full_mb * 1024 * 1024))
148	rpc_cmd bdev_lvol_resize $lvol_uuid $lvol_size_full_mb
149
150	# Check if bdev size changed (total_data_clusters*cluster_size
151	# equals to num_blocks*block_size)
152	lvol=$(rpc_cmd bdev_get_bdevs -b "$lvol_uuid")
153	[ "$(jq -r '.[0].block_size' <<< "$lvol")" = "$MALLOC_BS" ]
154	[ "$(jq -r '.[0].num_blocks' <<< "$lvol")" = $((lvol_size_full / MALLOC_BS)) ]
155
156	# Check if free_clusters on lvs remain unaffected
157	lvs=$(rpc_cmd bdev_lvol_get_lvstores -u "$lvs_uuid")
158	free_clusters_resize="$(jq -r '.[0].free_clusters' <<< "$lvs")"
159	[ $free_clusters_start == $free_clusters_resize ]
160
161	# Perform write operation with verification
162	# to newly created free space of lvol bdev
163	nbd_start_disks "$DEFAULT_RPC_ADDR" "$lvol_uuid" /dev/nbd0
164	run_fio_test /dev/nbd0 0 $lvol_size_full "write" "0xcc"
165	nbd_stop_disks "$DEFAULT_RPC_ADDR" /dev/nbd0
166
167	# Check if free clusters on lvs equals to zero
168	lvs=$(rpc_cmd bdev_lvol_get_lvstores -u "$lvs_uuid")
169	free_clusters_start="$(jq -r '.[0].free_clusters' <<< "$lvs")"
170	[ $free_clusters_start == 0 ]
171
172	# Resize bdev to 25% of lvs and check if it ended with success
173	lvol_size_quarter_mb=$(round_down $((LVS_DEFAULT_CAPACITY_MB / 4)))
174	rpc_cmd bdev_lvol_resize $lvol_uuid $lvol_size_quarter_mb
175
176	# Check free clusters on lvs
177	lvs=$(rpc_cmd bdev_lvol_get_lvstores -u "$lvs_uuid")
178	free_clusters_resize_quarter="$(jq -r '.[0].free_clusters' <<< "$lvs")"
179	free_clusters_expected=$(((lvol_size_full_mb - lvol_size_quarter_mb) / LVS_DEFAULT_CLUSTER_SIZE_MB))
180	[ $free_clusters_resize_quarter == $free_clusters_expected ]
181
182	rpc_cmd bdev_lvol_delete "$lvol_uuid"
183	rpc_cmd bdev_lvol_delete_lvstore -u "$lvs_uuid"
184	rpc_cmd bdev_malloc_delete "$malloc_name"
185}
186
187function test_thin_overprovisioning() {
188	malloc_name=$(rpc_cmd bdev_malloc_create $MALLOC_SIZE_MB $MALLOC_BS)
189	lvs_uuid=$(rpc_cmd bdev_lvol_create_lvstore "$malloc_name" lvs_test)
190
191	# Construct two thin provisioned lvol bdevs on created lvol store
192	# with size equal to free lvol store size
193	lvol_size_mb=$(round_down $((LVS_DEFAULT_CAPACITY_MB)))
194	lvol_size=$((lvol_size_mb * 1024 * 1024))
195	lvol_uuid1=$(rpc_cmd bdev_lvol_create -u "$lvs_uuid" lvol_test1 "$lvol_size_mb" -t)
196	lvol_uuid2=$(rpc_cmd bdev_lvol_create -u "$lvs_uuid" lvol_test2 "$lvol_size_mb" -t)
197
198	nbd_start_disks "$DEFAULT_RPC_ADDR" "$lvol_uuid1" /dev/nbd0
199	nbd_start_disks "$DEFAULT_RPC_ADDR" "$lvol_uuid2" /dev/nbd1
200	# Fill first bdev to 50% of its space with specific pattern
201	fill_size=$((lvol_size_mb * 5 / 10 / LVS_DEFAULT_CLUSTER_SIZE_MB * LVS_DEFAULT_CLUSTER_SIZE_MB))
202	fill_size=$((fill_size * 1024 * 1024))
203	run_fio_test /dev/nbd0 0 $fill_size "write" "0xcc"
204
205	# Fill second bdev up to 50% of its space
206	run_fio_test /dev/nbd1 0 $fill_size "write" "0xcc"
207
208	# Fill rest of second bdev
209	# Check that error message occurred while filling second bdev with data
210	offset=$fill_size
211	fill_size_rest=$((lvol_size - fill_size))
212	run_fio_test /dev/nbd1 "$offset" "$fill_size_rest" "write" "0xcc" && false
213
214	# Check if data on first disk stayed unchanged
215	run_fio_test /dev/nbd0 0 $fill_size "read" "0xcc"
216	run_fio_test /dev/nbd0 $offset $fill_size_rest "read" "0x00"
217
218	nbd_stop_disks "$DEFAULT_RPC_ADDR" /dev/nbd0
219	nbd_stop_disks "$DEFAULT_RPC_ADDR" /dev/nbd1
220
221	rpc_cmd bdev_lvol_delete "$lvol_uuid2"
222	rpc_cmd bdev_lvol_delete "$lvol_uuid1"
223	rpc_cmd bdev_lvol_delete_lvstore -u "$lvs_uuid"
224	rpc_cmd bdev_malloc_delete "$malloc_name"
225}
226
227$SPDK_BIN_DIR/spdk_tgt &
228spdk_pid=$!
229trap 'killprocess "$spdk_pid"; exit 1' SIGINT SIGTERM EXIT
230waitforlisten $spdk_pid
231
232run_test "test_thin_lvol_check_space" test_thin_lvol_check_space
233run_test "test_thin_lvol_check_zeroes" test_thin_lvol_check_zeroes
234run_test "test_thin_lvol_check_integrity" test_thin_lvol_check_integrity
235run_test "test_thin_lvol_resize" test_thin_lvol_resize
236run_test "test_thin_overprovisioning" test_thin_overprovisioning
237
238trap - SIGINT SIGTERM EXIT
239killprocess $spdk_pid
240