summaryrefslogtreecommitdiffstats
path: root/src/spdk/test/lvol/thin_provisioning.sh
blob: cb7bfcb01be3ee539880e3c80e8157706f55d6e4 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
#!/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

# Check if number of free clusters on lvol store decreases
# if we write to created thin provisioned lvol bdev
function test_thin_lvol_check_space() {
	malloc_name=$(rpc_cmd bdev_malloc_create $MALLOC_SIZE_MB $MALLOC_BS)
	lvs_uuid=$(rpc_cmd bdev_lvol_create_lvstore "$malloc_name" lvs_test)
	lvs=$(rpc_cmd bdev_lvol_get_lvstores -u "$lvs_uuid")
	free_clusters_start="$(jq -r '.[0].free_clusters' <<< "$lvs")"

	# Create thin provision lvol bdev with size equals to lvol store space
	lvol_size_mb=$(round_down $((LVS_DEFAULT_CAPACITY_MB)))
	lvol_uuid=$(rpc_cmd bdev_lvol_create -u "$lvs_uuid" lvol_test "$lvol_size_mb" -t)

	lvs=$(rpc_cmd bdev_lvol_get_lvstores -u "$lvs_uuid")
	free_clusters_create_lvol="$(jq -r '.[0].free_clusters' <<< "$lvs")"
	[ $free_clusters_start == $free_clusters_create_lvol ]

	# Write data (lvs cluster size) to created lvol bdev starting from offset 0.
	size=$LVS_DEFAULT_CLUSTER_SIZE
	nbd_start_disks "$DEFAULT_RPC_ADDR" "$lvol_uuid" /dev/nbd0
	run_fio_test /dev/nbd0 0 $size "write" "0xcc"
	lvs=$(rpc_cmd bdev_lvol_get_lvstores -u "$lvs_uuid")
	free_clusters_first_fio="$(jq -r '.[0].free_clusters' <<< "$lvs")"
	[ $((free_clusters_first_fio + 1)) == $free_clusters_start ]

	# Write data (lvs cluster size) to lvol bdev with offset set to one and half of cluster size
	offset=$((LVS_DEFAULT_CLUSTER_SIZE * 3 / 2))
	size=$LVS_DEFAULT_CLUSTER_SIZE
	run_fio_test /dev/nbd0 $offset $size "write" "0xcc"
	lvs=$(rpc_cmd bdev_lvol_get_lvstores -u "$lvs_uuid")
	free_clusters_second_fio="$(jq -r '.[0].free_clusters' <<< "$lvs")"
	[ $((free_clusters_second_fio + 3)) == $free_clusters_start ]

	# write data to lvol bdev to the end of its size
	size=$((LVS_DEFAULT_CLUSTER_SIZE * free_clusters_first_fio))
	offset=$((3 * LVS_DEFAULT_CLUSTER_SIZE))
	run_fio_test /dev/nbd0 $offset $size "write" "0xcc"
	lvs=$(rpc_cmd bdev_lvol_get_lvstores -u "$lvs_uuid")
	# Check that lvol store free clusters number equals to 0
	free_clusters_third_fio="$(jq -r '.[0].free_clusters' <<< "$lvs")"
	[ $((free_clusters_third_fio)) == 0 ]

	nbd_stop_disks "$DEFAULT_RPC_ADDR" /dev/nbd0
	rpc_cmd bdev_lvol_delete "$lvol_uuid"
	rpc_cmd bdev_get_bdevs -b "$lvol_uuid" && false
	lvs=$(rpc_cmd bdev_lvol_get_lvstores -u "$lvs_uuid")
	free_clusters_end="$(jq -r '.[0].free_clusters' <<< "$lvs")"
	[ $((free_clusters_end)) == $free_clusters_start ]

	# Clean up
	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 if we can create thin provisioned bdev on empty lvol store
# and check if we can read from this device and it returns zeroes.
function test_thin_lvol_check_zeroes() {
	malloc_name=$(rpc_cmd bdev_malloc_create $MALLOC_SIZE_MB $MALLOC_BS)
	lvs_uuid=$(rpc_cmd bdev_lvol_create_lvstore "$malloc_name" lvs_test)
	lvs=$(rpc_cmd bdev_lvol_get_lvstores -u "$lvs_uuid")
	free_clusters_start="$(jq -r '.[0].free_clusters' <<< "$lvs")"

	# Create thick and thin provisioned lvol bdevs with size equals to lvol store space
	lbd_name0=lvol_test0
	lbd_name1=lvol_test1
	lvol_size_mb=$((LVS_DEFAULT_CAPACITY_MB))
	# Round down lvol size to the nearest cluster size boundary
	lvol_size_mb=$((lvol_size_mb / LVS_DEFAULT_CLUSTER_SIZE_MB * LVS_DEFAULT_CLUSTER_SIZE_MB))
	lvol_size=$((lvol_size_mb * 1024 * 1024))
	lvol_uuid0=$(rpc_cmd bdev_lvol_create -u "$lvs_uuid" $lbd_name0 "$lvol_size_mb")
	lvol_uuid1=$(rpc_cmd bdev_lvol_create -u "$lvs_uuid" $lbd_name1 "$lvol_size_mb" -t)

	nbd_start_disks "$DEFAULT_RPC_ADDR" "$lvol_uuid0" /dev/nbd0
	nbd_start_disks "$DEFAULT_RPC_ADDR" "$lvol_uuid1" /dev/nbd1

	# Fill the whole thick provisioned lvol bdev
	run_fio_test /dev/nbd0 0 $lvol_size "write" "0xcc"

	# Perform read operations on thin provisioned lvol bdev
	# and check if they return zeroes
	run_fio_test /dev/nbd1 0 $lvol_size "read" "0x00"

	# Clean up
	nbd_stop_disks "$DEFAULT_RPC_ADDR" /dev/nbd1
	nbd_stop_disks "$DEFAULT_RPC_ADDR" /dev/nbd0
	rpc_cmd bdev_lvol_delete "$lvol_uuid1"
	rpc_cmd bdev_lvol_delete "$lvol_uuid0"
	rpc_cmd bdev_lvol_delete_lvstore -u "$lvs_uuid"
	rpc_cmd bdev_malloc_delete "$malloc_name"
}

# Check if data written to thin provisioned lvol bdev
# were properly written (fio test with verification)
function test_thin_lvol_check_integrity() {
	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 thin provisioned lvol bdev with size equals to lvol store space
	lvol_size_mb=$((LVS_DEFAULT_CAPACITY_MB))
	# Round down lvol size to the nearest cluster size boundary
	lvol_size_mb=$((lvol_size_mb / LVS_DEFAULT_CLUSTER_SIZE_MB * LVS_DEFAULT_CLUSTER_SIZE_MB))
	lvol_size=$((lvol_size_mb * 1024 * 1024))
	lvol_uuid=$(rpc_cmd bdev_lvol_create -u "$lvs_uuid" lvol_test "$lvol_size_mb" -t)

	nbd_start_disks "$DEFAULT_RPC_ADDR" "$lvol_uuid" /dev/nbd0
	run_fio_test /dev/nbd0 0 $lvol_size "write" "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 thin provisioned bdev resize
function test_thin_lvol_resize() {
	malloc_name=$(rpc_cmd bdev_malloc_create $MALLOC_SIZE_MB $MALLOC_BS)
	lvs_uuid=$(rpc_cmd bdev_lvol_create_lvstore "$malloc_name" lvs_test)

	# Construct thin provisioned lvol bdevs on created lvol store
	# with size equal to 50% of lvol store
	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)

	# Fill all free space of lvol bdev with data
	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

	# Save number of free clusters for lvs
	lvs=$(rpc_cmd bdev_lvol_get_lvstores -u "$lvs_uuid")
	free_clusters_start="$(jq -r '.[0].free_clusters' <<< "$lvs")"
	# Resize bdev to full size of lvs
	lvol_size_full_mb=$(round_down $((LVS_DEFAULT_CAPACITY_MB)))
	lvol_size_full=$((lvol_size_full_mb * 1024 * 1024))
	rpc_cmd bdev_lvol_resize $lvol_uuid $lvol_size_full_mb

	# Check if bdev size changed (total_data_clusters*cluster_size
	# equals to num_blocks*block_size)
	lvol=$(rpc_cmd bdev_get_bdevs -b "$lvol_uuid")
	[ "$(jq -r '.[0].block_size' <<< "$lvol")" = "$MALLOC_BS" ]
	[ "$(jq -r '.[0].num_blocks' <<< "$lvol")" = $((lvol_size_full / MALLOC_BS)) ]

	# Check if free_clusters on lvs remain unaffected
	lvs=$(rpc_cmd bdev_lvol_get_lvstores -u "$lvs_uuid")
	free_clusters_resize="$(jq -r '.[0].free_clusters' <<< "$lvs")"
	[ $free_clusters_start == $free_clusters_resize ]

	# Perform write operation with verification
	# to newly created free space of lvol bdev
	nbd_start_disks "$DEFAULT_RPC_ADDR" "$lvol_uuid" /dev/nbd0
	run_fio_test /dev/nbd0 0 $lvol_size_full "write" "0xcc"
	nbd_stop_disks "$DEFAULT_RPC_ADDR" /dev/nbd0

	# Check if free clusters on lvs equals to zero
	lvs=$(rpc_cmd bdev_lvol_get_lvstores -u "$lvs_uuid")
	free_clusters_start="$(jq -r '.[0].free_clusters' <<< "$lvs")"
	[ $free_clusters_start == 0 ]

	# Resize bdev to 25% of lvs and check if it ended with success
	lvol_size_quarter_mb=$(round_down $((LVS_DEFAULT_CAPACITY_MB / 4)))
	rpc_cmd bdev_lvol_resize $lvol_uuid $lvol_size_quarter_mb

	# Check free clusters on lvs
	lvs=$(rpc_cmd bdev_lvol_get_lvstores -u "$lvs_uuid")
	free_clusters_resize_quarter="$(jq -r '.[0].free_clusters' <<< "$lvs")"
	free_clusters_expected=$(((lvol_size_full_mb - lvol_size_quarter_mb) / LVS_DEFAULT_CLUSTER_SIZE_MB))
	[ $free_clusters_resize_quarter == $free_clusters_expected ]

	rpc_cmd bdev_lvol_delete "$lvol_uuid"
	rpc_cmd bdev_lvol_delete_lvstore -u "$lvs_uuid"
	rpc_cmd bdev_malloc_delete "$malloc_name"
}

function test_thin_overprovisioning() {
	malloc_name=$(rpc_cmd bdev_malloc_create $MALLOC_SIZE_MB $MALLOC_BS)
	lvs_uuid=$(rpc_cmd bdev_lvol_create_lvstore "$malloc_name" lvs_test)

	# Construct two thin provisioned lvol bdevs on created lvol store
	# with size equal to free lvol store size
	lvol_size_mb=$(round_down $((LVS_DEFAULT_CAPACITY_MB)))
	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" -t)

	nbd_start_disks "$DEFAULT_RPC_ADDR" "$lvol_uuid1" /dev/nbd0
	nbd_start_disks "$DEFAULT_RPC_ADDR" "$lvol_uuid2" /dev/nbd1
	# Fill first bdev to 50% of its space with specific pattern
	fill_size=$((lvol_size_mb * 5 / 10 / LVS_DEFAULT_CLUSTER_SIZE_MB * LVS_DEFAULT_CLUSTER_SIZE_MB))
	fill_size=$((fill_size * 1024 * 1024))
	run_fio_test /dev/nbd0 0 $fill_size "write" "0xcc"

	# Fill second bdev up to 50% of its space
	run_fio_test /dev/nbd1 0 $fill_size "write" "0xcc"

	# Fill rest of second bdev
	# Check that error message occured while filling second bdev with data
	offset=$fill_size
	fill_size_rest=$((lvol_size - fill_size))
	run_fio_test /dev/nbd1 "$offset" "$fill_size_rest" "write" "0xcc" && false

	# Check if data on first disk stayed unchanged
	run_fio_test /dev/nbd0 0 $fill_size "read" "0xcc"
	run_fio_test /dev/nbd0 $offset $fill_size_rest "read" "0x00"

	nbd_stop_disks "$DEFAULT_RPC_ADDR" /dev/nbd0
	nbd_stop_disks "$DEFAULT_RPC_ADDR" /dev/nbd1

	rpc_cmd bdev_lvol_delete "$lvol_uuid2"
	rpc_cmd bdev_lvol_delete "$lvol_uuid1"
	rpc_cmd bdev_lvol_delete_lvstore -u "$lvs_uuid"
	rpc_cmd bdev_malloc_delete "$malloc_name"
}

$SPDK_BIN_DIR/spdk_tgt &
spdk_pid=$!
trap 'killprocess "$spdk_pid"; exit 1' SIGINT SIGTERM EXIT
waitforlisten $spdk_pid

run_test "test_thin_lvol_check_space" test_thin_lvol_check_space
run_test "test_thin_lvol_check_zeroes" test_thin_lvol_check_zeroes
run_test "test_thin_lvol_check_integrity" test_thin_lvol_check_integrity
run_test "test_thin_lvol_resize" test_thin_lvol_resize
run_test "test_thin_overprovisioning" test_thin_overprovisioning

trap - SIGINT SIGTERM EXIT
killprocess $spdk_pid