xref: /spdk/test/lvol/external_snapshot.sh (revision b3bec07939ebe2ea2e0c43931705d32aa9e06719)
1#!/usr/bin/env bash
2#  SPDX-License-Identifier: BSD-3-Clause
3#  Copyright (c) 2022-2023 NVIDIA CORPORATION & AFFILIATES. All rights reserved.
4#
5testdir=$(readlink -f "$(dirname "$0")")
6rootdir=$(readlink -f "$testdir/../..")
7source "$rootdir/test/common/autotest_common.sh"
8source "$rootdir/test/lvol/common.sh"
9source "$rootdir/test/bdev/nbd_common.sh"
10
11set -u
12
13g_nbd_dev=INVALID
14g_cluster_size=INVALID
15g_block_size=INVALID
16
17function test_esnap_reload() {
18	local bs_dev esnap_dev
19	local block_size=512
20	local esnap_size_mb=1
21	local lvs_cluster_size=$((16 * 1024))
22	local lvs_uuid esnap_uuid eclone_uuid snap_uuid clone_uuid uuid
23	local aio_bdev=test_esnap_reload_aio0
24
25	# Create the lvstore on an aio device. Can't use malloc because we need to remove
26	# the device and re-add it to trigger an lvstore unload and then load.
27	rm -f $testdir/aio_bdev_0
28	truncate -s "${AIO_SIZE_MB}M" $testdir/aio_bdev_0
29	bs_dev=$(rpc_cmd bdev_aio_create "$testdir/aio_bdev_0" "$aio_bdev" "$block_size")
30	lvs_uuid=$(rpc_cmd bdev_lvol_create_lvstore -c "$lvs_cluster_size" "$bs_dev" lvs_test)
31
32	# Create a bdev that will be the external snapshot
33	esnap_uuid=e4b40d8b-f623-416d-8234-baf5a4c83cbd
34	esnap_dev=$(rpc_cmd bdev_malloc_create -u "$esnap_uuid" "$esnap_size_mb" "$block_size")
35	eclone_uuid=$(rpc_cmd bdev_lvol_clone_bdev "$esnap_uuid" lvs_test "eclone1")
36
37	# Unload the lvstore
38	rpc_cmd bdev_aio_delete "$aio_bdev"
39	NOT rpc_cmd bdev_lvol_get_lvstores -l lvs_test
40
41	# Load the lvstore, expect to see eclone1 again
42	bs_dev=$(rpc_cmd bdev_aio_create "$testdir/aio_bdev_0" "$aio_bdev" "$block_size")
43	lvs_uuid=$(rpc_cmd bdev_lvol_get_lvstores -l lvs_test)
44	uuid=$(rpc_cmd bdev_get_bdevs -b lvs_test/eclone1 | jq -r '.[].name')
45	[[ "$uuid" == "$eclone_uuid" ]]
46
47	# Create a snapshot of the eclone, reload, and verify all is there.
48	snap_uuid=$(rpc_cmd bdev_lvol_snapshot "$eclone_uuid" snap1)
49	rpc_cmd bdev_aio_delete "$aio_bdev"
50	NOT rpc_cmd bdev_lvol_get_lvstores -l lvs_test
51	bs_dev=$(rpc_cmd bdev_aio_create "$testdir/aio_bdev_0" "$aio_bdev" "$block_size")
52	lvs_uuid=$(rpc_cmd bdev_lvol_get_lvstores -l lvs_test)
53	uuid=$(rpc_cmd bdev_get_bdevs -b lvs_test/eclone1 | jq -r '.[].name')
54	[[ "$uuid" == "$eclone_uuid" ]]
55	uuid=$(rpc_cmd bdev_get_bdevs -b lvs_test/snap1 | jq -r '.[].name')
56	[[ "$uuid" == "$snap_uuid" ]]
57
58	# Create a clone of the snapshot, reload, and verify all is there.
59	clone_uuid=$(rpc_cmd bdev_lvol_clone "$snap_uuid" clone1)
60	rpc_cmd bdev_aio_delete "$aio_bdev"
61	NOT rpc_cmd bdev_lvol_get_lvstores -l lvs_test
62	bs_dev=$(rpc_cmd bdev_aio_create "$testdir/aio_bdev_0" "$aio_bdev" "$block_size")
63	lvs_uuid=$(rpc_cmd bdev_lvol_get_lvstores -l lvs_test)
64	uuid=$(rpc_cmd bdev_get_bdevs -b lvs_test/eclone1 | jq -r '.[].name')
65	[[ "$uuid" == "$eclone_uuid" ]]
66	uuid=$(rpc_cmd bdev_get_bdevs -b lvs_test/snap1 | jq -r '.[].name')
67	[[ "$uuid" == "$snap_uuid" ]]
68	uuid=$(rpc_cmd bdev_get_bdevs -b lvs_test/clone1 | jq -r '.[].name')
69	[[ "$uuid" == "$clone_uuid" ]]
70
71	rpc_cmd bdev_lvol_delete "$clone_uuid"
72	rpc_cmd bdev_lvol_delete "$snap_uuid"
73	rpc_cmd bdev_lvol_delete "$eclone_uuid"
74	rpc_cmd bdev_aio_delete "$aio_bdev"
75	rpc_cmd bdev_malloc_delete "$esnap_dev"
76}
77
78function test_esnap_reload_missing() {
79	local bs_dev esnap_dev
80	local block_size=512
81	local esnap_size_mb=1
82	local lvs_cluster_size=$((16 * 1024))
83	local lvs_uuid esnap_uuid eclone_uuid snap_uuid clone_uuid uuid
84	local aio_bdev=test_esnap_reload_aio0
85	local lvols
86
87	# Create the lvstore on an aio device. Can't use malloc because we need to remove
88	# the device and re-add it to trigger an lvstore unload and then load.
89	rm -f $testdir/aio_bdev_0
90	truncate -s "${AIO_SIZE_MB}M" $testdir/aio_bdev_0
91	bs_dev=$(rpc_cmd bdev_aio_create "$testdir/aio_bdev_0" "$aio_bdev" "$block_size")
92	lvs_uuid=$(rpc_cmd bdev_lvol_create_lvstore -c "$lvs_cluster_size" "$bs_dev" lvs_test)
93
94	# Create a bdev that will be the external snapshot
95	# State:
96	#   esnap(present) <-- eclone(not degraded)
97	esnap_uuid=e4b40d8b-f623-416d-8234-baf5a4c83cbd
98	esnap_dev=$(rpc_cmd bdev_malloc_create -u "$esnap_uuid" "$esnap_size_mb" "$block_size")
99	eclone_uuid=$(rpc_cmd bdev_lvol_clone_bdev "$esnap_uuid" lvs_test "eclone")
100	lvols=$(rpc_cmd bdev_lvol_get_lvols)
101	[[ "$(jq -r '. | length' <<< "$lvols")" == "1" ]]
102	[[ "$(jq -r '.[] | select(.name == "eclone").is_esnap_clone' <<< "$lvols")" == "true" ]]
103	[[ "$(jq -r '.[] | select(.name == "eclone").is_degraded' <<< "$lvols")" == "false" ]]
104
105	# Unload the lvstore and delete the external snapshot
106	rpc_cmd bdev_aio_delete "$aio_bdev"
107	NOT rpc_cmd bdev_lvol_get_lvstores -l lvs_test
108	rpc_cmd bdev_malloc_delete "$esnap_uuid"
109
110	# Load the lvstore, eclone bdev should not exist but the lvol should exist.
111	# State:
112	#   esnap(missing) <-- eclone(degraded)
113	bs_dev=$(rpc_cmd bdev_aio_create "$testdir/aio_bdev_0" "$aio_bdev" "$block_size")
114	NOT rpc_cmd bdev_get_bdevs -b lvs_test/eclone
115	NOT rpc_cmd bdev_get_bdevs -b "$eclone_uuid"
116	lvols=$(rpc_cmd bdev_lvol_get_lvols)
117	[[ "$(jq -r '. | length' <<< "$lvols")" == "1" ]]
118	[[ "$(jq -r '.[] | select(.name == "eclone").is_degraded' <<< "$lvols")" == "true" ]]
119
120	# Reload the lvstore with esnap present during load. This should make the lvol not degraded.
121	# State:
122	#   esnap(present) <-- eclone(not degraded)
123	rpc_cmd bdev_aio_delete "$aio_bdev"
124	NOT rpc_cmd bdev_lvol_get_lvstores -l lvs_test
125	esnap_dev=$(rpc_cmd bdev_malloc_create -u "$esnap_uuid" "$esnap_size_mb" "$block_size")
126	bs_dev=$(rpc_cmd bdev_aio_create "$testdir/aio_bdev_0" "$aio_bdev" "$block_size")
127	rpc_cmd bdev_lvol_get_lvstores -l lvs_test
128	rpc_cmd bdev_get_bdevs -b lvs_test/eclone
129	rpc_cmd bdev_get_bdevs -b "$eclone_uuid"
130	lvols=$(rpc_cmd bdev_lvol_get_lvols)
131	[[ "$(jq -r '. | length' <<< "$lvols")" == "1" ]]
132	[[ "$(jq -r '.[] | select(.name == "eclone").is_esnap_clone' <<< "$lvols")" == "true" ]]
133	[[ "$(jq -r '.[] | select(.name == "eclone").is_degraded' <<< "$lvols")" == "false" ]]
134
135	# Create a clone of eclone, then reload without the esnap present.
136	# State:
137	#   esnap(missing) <-- eclone(degraded) <-- clone(degraded)
138	rpc_cmd bdev_lvol_set_read_only "$eclone_uuid"
139	clone_uuid=$(rpc_cmd bdev_lvol_clone "$eclone_uuid" clone)
140	rpc_cmd bdev_get_bdevs -b lvs_test/clone
141	rpc_cmd bdev_get_bdevs -b "$clone_uuid"
142	rpc_cmd bdev_aio_delete "$aio_bdev"
143	NOT rpc_cmd bdev_lvol_get_lvstores -l lvs_test
144	rpc_cmd bdev_malloc_delete "$esnap_uuid"
145	bs_dev=$(rpc_cmd bdev_aio_create "$testdir/aio_bdev_0" "$aio_bdev" "$block_size")
146	lvols=$(rpc_cmd bdev_lvol_get_lvols)
147	[[ "$(jq -r '.[] | select(.name == "eclone").is_esnap_clone' <<< "$lvols")" == "true" ]]
148	[[ "$(jq -r '.[] | select(.name == "eclone").is_degraded' <<< "$lvols")" == "true" ]]
149	[[ "$(jq -r '.[] | select(.name == "clone").is_clone' <<< "$lvols")" == "true" ]]
150	[[ "$(jq -r '.[] | select(.name == "eclone").is_degraded' <<< "$lvols")" == "true" ]]
151	NOT rpc_cmd bdev_get_bdevs -b lvs_test/eclone
152	NOT rpc_cmd bdev_get_bdevs -b "$eclone_uuid"
153	NOT rpc_cmd bdev_get_bdevs -b lvs_test/clone
154	NOT rpc_cmd bdev_get_bdevs -b "$clone_uuid"
155
156	# Reload the lvstore with esnap present during load. This should make the lvols not
157	# degraded.
158	# State:
159	#   esnap(present) <-- eclone(not degraded) <-- clone(not degraded)
160	rpc_cmd bdev_aio_delete "$aio_bdev"
161	NOT rpc_cmd bdev_lvol_get_lvstores -l lvs_test
162	esnap_dev=$(rpc_cmd bdev_malloc_create -u "$esnap_uuid" "$esnap_size_mb" "$block_size")
163	bs_dev=$(rpc_cmd bdev_aio_create "$testdir/aio_bdev_0" "$aio_bdev" "$block_size")
164	lvols=$(rpc_cmd bdev_lvol_get_lvols)
165	[[ "$(jq -r '.[] | select(.name == "eclone").is_esnap_clone' <<< "$lvols")" == "true" ]]
166	[[ "$(jq -r '.[] | select(.name == "eclone").is_degraded' <<< "$lvols")" == "false" ]]
167	[[ "$(jq -r '.[] | select(.name == "clone").is_clone' <<< "$lvols")" == "true" ]]
168	[[ "$(jq -r '.[] | select(.name == "clone").is_degraded' <<< "$lvols")" == "false" ]]
169	rpc_cmd bdev_get_bdevs -b lvs_test/eclone
170	rpc_cmd bdev_get_bdevs -b "$eclone_uuid"
171	rpc_cmd bdev_get_bdevs -b lvs_test/clone
172	rpc_cmd bdev_get_bdevs -b "$clone_uuid"
173
174	# Create a snapshot of clone, then reload without the esnap present.
175	# State:
176	#   esnap(missing) <-- eclone(degraded) <-- snap(degraded) <-- clone(degraded)
177	snap_uuid=$(rpc_cmd bdev_lvol_snapshot "$clone_uuid" snap)
178	rpc_cmd bdev_get_bdevs -b lvs_test/snap
179	rpc_cmd bdev_get_bdevs -b "$snap_uuid"
180	rpc_cmd bdev_aio_delete "$aio_bdev"
181	NOT rpc_cmd bdev_lvol_get_lvstores -l lvs_test
182	rpc_cmd bdev_malloc_delete "$esnap_uuid"
183	bs_dev=$(rpc_cmd bdev_aio_create "$testdir/aio_bdev_0" "$aio_bdev" "$block_size")
184	lvols=$(rpc_cmd bdev_lvol_get_lvols)
185	[[ "$(jq -r '.[] | select(.name == "eclone").is_esnap_clone' <<< "$lvols")" == "true" ]]
186	[[ "$(jq -r '.[] | select(.name == "eclone").is_degraded' <<< "$lvols")" == "true" ]]
187	[[ "$(jq -r '.[] | select(.name == "clone").is_clone' <<< "$lvols")" == "true" ]]
188	[[ "$(jq -r '.[] | select(.name == "clone").is_degraded' <<< "$lvols")" == "true" ]]
189	[[ "$(jq -r '.[] | select(.name == "snap").is_clone' <<< "$lvols")" == "true" ]]
190	[[ "$(jq -r '.[] | select(.name == "snap").is_snapshot' <<< "$lvols")" == "true" ]]
191	[[ "$(jq -r '.[] | select(.name == "snap").is_degraded' <<< "$lvols")" == "true" ]]
192	NOT rpc_cmd bdev_get_bdevs -b lvs_test/eclone
193	NOT rpc_cmd bdev_get_bdevs -b "$eclone_uuid"
194	NOT rpc_cmd bdev_get_bdevs -b lvs_test/clone
195	NOT rpc_cmd bdev_get_bdevs -b "$clone_uuid"
196	NOT rpc_cmd bdev_get_bdevs -b lvs_test/snap
197	NOT rpc_cmd bdev_get_bdevs -b "$snap_uuid"
198
199	# Create the esnap bdev and verify the degraded bdevs become not degraded.
200	esnap_dev=$(rpc_cmd bdev_malloc_create -u "$esnap_uuid" "$esnap_size_mb" "$block_size")
201	rpc_cmd bdev_wait_for_examine
202	lvols=$(rpc_cmd bdev_lvol_get_lvols)
203	[[ "$(jq -r '.[] | select(.name == "eclone").is_esnap_clone' <<< "$lvols")" == "true" ]]
204	[[ "$(jq -r '.[] | select(.name == "eclone").is_degraded' <<< "$lvols")" == "false" ]]
205	[[ "$(jq -r '.[] | select(.name == "clone").is_clone' <<< "$lvols")" == "true" ]]
206	[[ "$(jq -r '.[] | select(.name == "clone").is_degraded' <<< "$lvols")" == "false" ]]
207	[[ "$(jq -r '.[] | select(.name == "snap").is_clone' <<< "$lvols")" == "true" ]]
208	[[ "$(jq -r '.[] | select(.name == "snap").is_snapshot' <<< "$lvols")" == "true" ]]
209	[[ "$(jq -r '.[] | select(.name == "snap").is_degraded' <<< "$lvols")" == "false" ]]
210	rpc_cmd bdev_get_bdevs -b lvs_test/eclone
211	rpc_cmd bdev_get_bdevs -b "$eclone_uuid"
212	rpc_cmd bdev_get_bdevs -b lvs_test/clone
213	rpc_cmd bdev_get_bdevs -b "$clone_uuid"
214	rpc_cmd bdev_get_bdevs -b lvs_test/snap
215	rpc_cmd bdev_get_bdevs -b "$snap_uuid"
216
217	rpc_cmd bdev_aio_delete "$aio_bdev"
218	rpc_cmd bdev_malloc_delete "$esnap_uuid"
219}
220
221function log_jq_out() {
222	local key
223
224	xtrace_disable
225
226	while read -r key; do
227		printf '%50s = %s\n' "$key" "${jq_out[$key]}"
228	done < <(printf '%s\n' "${!jq_out[@]}" | sort)
229
230	xtrace_restore
231}
232
233function verify_clone() {
234	local bdev=$1
235	local parent=$2
236
237	rpc_cmd_simple_data_json bdev bdev_get_bdevs -b "$bdev"
238	log_jq_out
239
240	[[ "${jq_out["supported_io_types.read"]}" == true ]]
241	[[ "${jq_out["supported_io_types.write"]}" == true ]]
242	[[ "${jq_out["driver_specific.lvol.clone"]}" == true ]]
243	[[ "${jq_out["driver_specific.lvol.base_snapshot"]}" == "$parent" ]]
244	[[ "${jq_out["driver_specific.lvol.esnap_clone"]}" == false ]]
245	[[ "${jq_out["driver_specific.lvol.external_snapshot_name"]}" == null ]]
246}
247
248function verify_esnap_clone() {
249	local bdev=$1
250	local parent=$2
251	local writable=${3:-true}
252
253	rpc_cmd_simple_data_json bdev bdev_get_bdevs -b "$bdev"
254	log_jq_out
255
256	[[ "${jq_out["supported_io_types.read"]}" == true ]]
257	[[ "${jq_out["supported_io_types.write"]}" == "$writable" ]]
258	[[ "${jq_out["driver_specific.lvol.esnap_clone"]}" == true ]]
259	[[ "${jq_out["driver_specific.lvol.external_snapshot_name"]}" == "$parent" ]]
260}
261
262function test_esnap_clones() {
263	local bs_dev esnap_dev
264	local block_size=512
265	local lvs_size_mb=100
266	local esnap_size_mb=1
267	local lvs_cluster_size=$((16 * 1024))
268	local lvs_uuid esnap_uuid
269	local vol1_uuid vol2_uuid vol3_uuid vol3_uuid vol4_uuid vol5_uuid
270
271	# Create the lvstore on a malloc device.
272	bs_dev=$(rpc_cmd bdev_malloc_create $lvs_size_mb $block_size)
273	lvs_uuid=$(rpc_cmd bdev_lvol_create_lvstore -c "$lvs_cluster_size" "$bs_dev" lvs_test)
274
275	# Create a bdev that will be the external snapshot
276	# State:
277	#    esnap1
278	esnap_uuid=2abddd12-c08d-40ad-bccf-ab131586ee4c
279	esnap_dev=$(rpc_cmd bdev_malloc_create -b esnap1 -u "$esnap_uuid" "$esnap_size_mb" \
280		"$block_size")
281
282	# Create an esnap clone: vol1
283	# New state:
284	#    esnap1 <-- vol1(rw)
285	vol1_uuid=$(rpc_cmd bdev_lvol_clone_bdev "$esnap_uuid" lvs_test vol1)
286	verify_esnap_clone "$vol1_uuid" "$esnap_uuid"
287
288	# Create a snapshot of the esnap clone: vol2
289	# New state:
290	#   esnap1 <-- vol2(ro) <-- vol1(rw)
291	vol2_uuid=$(rpc_cmd bdev_lvol_snapshot "$vol1_uuid" vol2)
292	verify_esnap_clone "$vol2_uuid" "$esnap_uuid" false
293	verify_clone "$vol1_uuid" vol2
294
295	# Delete vol2.
296	# New state:
297	#   esnap1 <-- vol1(rw)
298	rpc_cmd bdev_lvol_delete "$vol2_uuid"
299	NOT rpc_cmd bdev_get_bdevs -b "$vol2_uuid"
300	verify_esnap_clone "$vol1_uuid" "$esnap_uuid"
301	vol2_uuid=
302
303	# Snapshot vol1: vol3
304	# New state:
305	#   ensap1 <-- vol3(ro) <-- vol1(rw)
306	vol3_uuid=$(rpc_cmd bdev_lvol_snapshot "$vol1_uuid" vol3)
307	verify_esnap_clone "$vol3_uuid" "$esnap_uuid" false
308	verify_clone "$vol1_uuid" vol3
309
310	# Delete vol1
311	# New state:
312	#   esnap1 <-- vol3(ro)
313	rpc_cmd bdev_lvol_delete $vol1_uuid
314	NOT rpc_cmd bdev_get_bdevs -b $vol1_uuid
315	verify_esnap_clone "$vol3_uuid" "$esnap_uuid" false
316	vol1_uuid=
317
318	# Create clone of vol3: vol4
319	# Verify vol3 is still a read-only esnap clone and vol4 is a normal clone.
320	# New state:
321	#   ensap1 <-- vol3(ro) <-- vol4(rw)
322	vol4_uuid=$(rpc_cmd bdev_lvol_clone "$vol3_uuid" vol4)
323	rpc_cmd bdev_get_bdevs -b "$vol4_uuid"
324	verify_esnap_clone "$vol3_uuid" "$esnap_uuid" false
325	verify_clone "$vol4_uuid" vol3
326
327	# Create clone of vol3 (vol5).
328	# New state:
329	#   ensap1 <-- vol3(ro) <-- vol4(rw)
330	#                      `<-- vol5(rw)
331	vol5_uuid=$(rpc_cmd bdev_lvol_clone "$vol3_uuid" vol5)
332	verify_esnap_clone "$vol3_uuid" "$esnap_uuid" false
333	verify_clone "$vol4_uuid" vol3
334	verify_clone "$vol5_uuid" vol3
335
336	# Cannot delete vol3 because it has multiple clones
337	NOT rpc_cmd bdev_lvol_delete "$vol3_uuid"
338
339	# Delete vol4
340	# New state:
341	#   ensap1 <-- vol3(ro) <-- vol5(rw)
342	rpc_cmd bdev_lvol_delete "$vol4_uuid"
343	NOT rpc_cmd bdev_get_bdevs -b "$vol4_uuid"
344	verify_esnap_clone "$vol3_uuid" "$esnap_uuid" false
345	verify_clone "$vol5_uuid" vol3
346
347	# Delete vol3.
348	# New state:
349	#   ensap1 <-- vol5(rw)
350	rpc_cmd bdev_lvol_delete "$vol3_uuid"
351	NOT rpc_cmd bdev_get_bdevs -b "$vol3_uuid"
352	verify_esnap_clone "$vol5_uuid" "$esnap_uuid"
353
354	# Delete vol5.
355	# New state:
356	#   esnap1
357	rpc_cmd bdev_lvol_delete "$vol5_uuid"
358	NOT rpc_cmd bdev_get_bdevs -b "$vol5_uuid"
359
360	rpc_cmd bdev_malloc_delete "$bs_dev"
361	rpc_cmd bdev_malloc_delete "$esnap_dev"
362}
363
364function test_esnap_late_arrival() {
365	local bs_dev esnap_dev
366	local block_size=512
367	local esnap_size_mb=1
368	local lvs_cluster_size=$((16 * 1024))
369	local lvs_uuid esnap_uuid eclone_uuid snap_uuid clone_uuid uuid
370	local aio_bdev=test_esnap_reload_aio0
371	local lvols
372
373	# Create the lvstore on an aio device. Can't use malloc because we need to remove
374	# the device and re-add it to trigger an lvstore unload and then load.
375	rm -f $testdir/aio_bdev_0
376	truncate -s "${AIO_SIZE_MB}M" $testdir/aio_bdev_0
377	bs_dev=$(rpc_cmd bdev_aio_create "$testdir/aio_bdev_0" "$aio_bdev" "$block_size")
378	lvs_uuid=$(rpc_cmd bdev_lvol_create_lvstore -c "$lvs_cluster_size" "$bs_dev" lvs_test)
379
380	# Create a bdev that will be the external snapshot
381	esnap_uuid=e4b40d8b-f623-416d-8234-baf5a4c83cbd
382	esnap_dev=$(rpc_cmd bdev_malloc_create -u "$esnap_uuid" "$esnap_size_mb" "$block_size")
383	eclone_uuid=$(rpc_cmd bdev_lvol_clone_bdev "$esnap_uuid" lvs_test "eclone1")
384
385	# Unload the lvstore
386	rpc_cmd bdev_aio_delete "$aio_bdev"
387	NOT rpc_cmd bdev_lvol_get_lvstores -l lvs_test
388
389	# Delete the external snapshot device then reload the lvstore.
390	rpc_cmd bdev_malloc_delete "$esnap_dev"
391	bs_dev=$(rpc_cmd bdev_aio_create "$testdir/aio_bdev_0" "$aio_bdev" "$block_size")
392	lvs_uuid=$(rpc_cmd bdev_lvol_get_lvstores -l lvs_test)
393
394	# Verify that the esnap clone exists but does not have the esnap loaded.
395	NOT rpc_cmd bdev_get_bdevs -b "$esnap_uuid"
396	NOT rpc_cmd bdev_get_bdevs -b "$eclone_uuid"
397	lvols=$(rpc_cmd bdev_lvol_get_lvols)
398	[[ "$(jq -r '.[] | select(.uuid == "'$eclone_uuid'").is_esnap_clone' <<< "$lvols")" == "true" ]]
399	[[ "$(jq -r '.[] | select(.uuid == "'$eclone_uuid'").is_degraded' <<< "$lvols")" == "true" ]]
400
401	# Create the esnap device and verify that the esnap clone finds it.
402	esnap_dev=$(rpc_cmd bdev_malloc_create -u "$esnap_uuid" "$esnap_size_mb" "$block_size")
403	rpc_cmd bdev_wait_for_examine
404	verify_esnap_clone "$eclone_uuid" "$esnap_uuid"
405
406	rpc_cmd bdev_aio_delete "$aio_bdev"
407	rpc_cmd bdev_malloc_delete "$esnap_dev"
408}
409
410function test_esnap_remove_degraded() {
411	local bs_dev esnap_dev
412	local block_size=512
413	local esnap_size_mb=1
414	local lvs_cluster_size=$((16 * 1024))
415	local lvs_uuid esnap_uuid eclone_uuid snap_uuid clone_uuid uuid
416	local aio_bdev=test_esnap_reload_aio0
417	local lvols
418
419	# Create the lvstore on an aio device. Can't use malloc because we need to remove
420	# the device and re-add it to trigger an lvstore unload and then load.
421	rm -f $testdir/aio_bdev_0
422	truncate -s "${AIO_SIZE_MB}M" $testdir/aio_bdev_0
423	bs_dev=$(rpc_cmd bdev_aio_create "$testdir/aio_bdev_0" "$aio_bdev" "$block_size")
424	lvs_uuid=$(rpc_cmd bdev_lvol_create_lvstore -c "$lvs_cluster_size" "$bs_dev" lvs_test)
425
426	# Create a bdev that will be the external snapshot
427	esnap_uuid=e4b40d8b-f623-416d-8234-baf5a4c83cbd
428	esnap_dev=$(rpc_cmd bdev_malloc_create -u "$esnap_uuid" "$esnap_size_mb" "$block_size")
429	eclone_uuid=$(rpc_cmd bdev_lvol_clone_bdev "$esnap_uuid" lvs_test "eclone")
430	rpc_cmd bdev_get_bdevs -b "$eclone_uuid"
431
432	# Create a clone of eclone
433	rpc_cmd bdev_lvol_set_read_only "$eclone_uuid"
434	clone_uuid=$(rpc_cmd bdev_lvol_clone "$eclone_uuid" clone)
435	rpc_cmd bdev_get_bdevs -b "$clone_uuid"
436
437	# Reload the lvolstore without the external snapshot
438	rpc_cmd bdev_aio_delete "$aio_bdev"
439	NOT rpc_cmd bdev_lvol_get_lvstores -l lvs_test
440	rpc_cmd bdev_malloc_delete "$esnap_dev"
441	bs_dev=$(rpc_cmd bdev_aio_create "$testdir/aio_bdev_0" "$aio_bdev" "$block_size")
442	lvs_uuid=$(rpc_cmd bdev_lvol_get_lvstores -l lvs_test)
443
444	# Verify clone and eclone are degraded
445	lvols=$(rpc_cmd bdev_lvol_get_lvols)
446	[[ "$(jq -r '.[] | select(.uuid == "'$eclone_uuid'").is_degraded' <<< "$lvols")" == "true" ]]
447	[[ "$(jq -r '.[] | select(.uuid == "'$clone_uuid'").is_degraded' <<< "$lvols")" == "true" ]]
448	NOT rpc_cmd bdev_get_bdevs -b "$clone_uuid"
449	NOT rpc_cmd bdev_get_bdevs -b "$eclone_uuid"
450
451	# Delete the lvols and verify they are gone.
452	rpc_cmd bdev_lvol_delete "$clone_uuid"
453	lvols=$(rpc_cmd bdev_lvol_get_lvols)
454	[[ "$(jq -r '. | length' <<< "$lvols")" == "1" ]]
455	rpc_cmd bdev_lvol_delete "$eclone_uuid"
456	lvols=$(rpc_cmd bdev_lvol_get_lvols)
457	[[ "$(jq -r '. | length' <<< "$lvols")" == "0" ]]
458
459	rpc_cmd bdev_aio_delete "$aio_bdev"
460}
461
462$SPDK_BIN_DIR/spdk_tgt &
463spdk_pid=$!
464trap 'killprocess "$spdk_pid"; rm -f "$testdir/aio_bdev_0"; exit 1' SIGINT SIGTERM SIGPIPE EXIT
465waitforlisten $spdk_pid
466modprobe nbd
467
468run_test "test_esnap_reload" test_esnap_reload
469run_test "test_esnap_reload" test_esnap_reload_missing
470run_test "test_esnap_clones" test_esnap_clones
471run_test "test_esnap_late_arrival" test_esnap_late_arrival
472run_test "test_esnap_remove_degraded" test_esnap_remove_degraded
473
474trap - SIGINT SIGTERM SIGPIPE EXIT
475killprocess $spdk_pid
476rm -f "$testdir/aio_bdev_0"
477