Branch data Line data Source code
1 : : /* SPDX-License-Identifier: BSD-3-Clause
2 : : * Copyright (C) 2017 Intel Corporation.
3 : : * All rights reserved.
4 : : * Copyright (c) 2021-2023 NVIDIA CORPORATION & AFFILIATES. All rights reserved.
5 : : */
6 : :
7 : : #include "spdk/stdinc.h"
8 : :
9 : : #include "spdk_internal/cunit.h"
10 : : #include "spdk/blob.h"
11 : : #include "spdk/string.h"
12 : :
13 : : #include "common/lib/ut_multithread.c"
14 : : #include "../bs_dev_common.c"
15 : : #include "thread/thread.c"
16 : : #include "ext_dev.c"
17 : : #include "blob/blobstore.c"
18 : : #include "blob/request.c"
19 : : #include "blob/zeroes.c"
20 : : #include "blob/blob_bs_dev.c"
21 : : #include "esnap_dev.c"
22 : :
23 : : struct spdk_blob_store *g_bs;
24 : : spdk_blob_id g_blobid;
25 : : struct spdk_blob *g_blob, *g_blob2;
26 : : int g_bserrno, g_bserrno2;
27 : : struct spdk_xattr_names *g_names;
28 : : int g_done;
29 : : char *g_xattr_names[] = {"first", "second", "third"};
30 : : char *g_xattr_values[] = {"one", "two", "three"};
31 : : uint64_t g_ctx = 1729;
32 : : bool g_use_extent_table = false;
33 : : uint64_t g_copied_clusters_count = 0;
34 : :
35 : : struct spdk_bs_super_block_ver1 {
36 : : uint8_t signature[8];
37 : : uint32_t version;
38 : : uint32_t length;
39 : : uint32_t clean; /* If there was a clean shutdown, this is 1. */
40 : : spdk_blob_id super_blob;
41 : :
42 : : uint32_t cluster_size; /* In bytes */
43 : :
44 : : uint32_t used_page_mask_start; /* Offset from beginning of disk, in pages */
45 : : uint32_t used_page_mask_len; /* Count, in pages */
46 : :
47 : : uint32_t used_cluster_mask_start; /* Offset from beginning of disk, in pages */
48 : : uint32_t used_cluster_mask_len; /* Count, in pages */
49 : :
50 : : uint32_t md_start; /* Offset from beginning of disk, in pages */
51 : : uint32_t md_len; /* Count, in pages */
52 : :
53 : : uint8_t reserved[4036];
54 : : uint32_t crc;
55 : : } __attribute__((packed));
56 : : SPDK_STATIC_ASSERT(sizeof(struct spdk_bs_super_block_ver1) == 0x1000, "Invalid super block size");
57 : :
58 : : static struct spdk_blob *ut_blob_create_and_open(struct spdk_blob_store *bs,
59 : : struct spdk_blob_opts *blob_opts);
60 : : static void ut_blob_close_and_delete(struct spdk_blob_store *bs, struct spdk_blob *blob);
61 : : static void suite_blob_setup(void);
62 : : static void suite_blob_cleanup(void);
63 : :
64 [ # # ]: 0 : DEFINE_STUB(spdk_memory_domain_memzero, int, (struct spdk_memory_domain *src_domain,
65 : : void *src_domain_ctx, struct iovec *iov, uint32_t iovcnt, void (*cpl_cb)(void *, int),
66 : : void *cpl_cb_arg), 0);
67 : :
68 : : static bool
69 : 108 : is_esnap_clone(struct spdk_blob *_blob, const void *id, size_t id_len)
70 : : {
71 : 108 : const void *val = NULL;
72 : 108 : size_t len = 0;
73 : : bool c0, c1, c2, c3;
74 : :
75 : 108 : CU_ASSERT(blob_get_xattr_value(_blob, BLOB_EXTERNAL_SNAPSHOT_ID, &val, &len,
76 : : true) == 0);
77 : 108 : CU_ASSERT((c0 = (len == id_len)));
78 [ + - + + : 108 : CU_ASSERT((c1 = (val != NULL && memcmp(val, id, len) == 0)));
- + + - ]
79 : 108 : CU_ASSERT((c2 = !!(_blob->invalid_flags & SPDK_BLOB_EXTERNAL_SNAPSHOT)));
80 : 108 : CU_ASSERT((c3 = (_blob->parent_id == SPDK_BLOBID_EXTERNAL_SNAPSHOT)));
81 : :
82 [ + - + - : 108 : return c0 && c1 && c2 && c3;
+ - + - ]
83 : : }
84 : :
85 : : static bool
86 : 60 : is_not_esnap_clone(struct spdk_blob *_blob)
87 : : {
88 : 60 : const void *val = NULL;
89 : 60 : size_t len = 0;
90 : : bool c1, c2, c3, c4;
91 : :
92 : 60 : CU_ASSERT((c1 = (blob_get_xattr_value(_blob, BLOB_EXTERNAL_SNAPSHOT_ID, &val, &len,
93 : : true) == -ENOENT)));
94 : 60 : CU_ASSERT((c2 = (val == NULL)));
95 : 60 : CU_ASSERT((c3 = ((_blob->invalid_flags & SPDK_BLOB_EXTERNAL_SNAPSHOT) == 0)));
96 : 60 : CU_ASSERT((c4 = (_blob->parent_id != SPDK_BLOBID_EXTERNAL_SNAPSHOT)));
97 : :
98 [ + - + - : 60 : return c1 && c2 && c3 && c4;
+ - + - ]
99 : : }
100 : :
101 : : #define UT_ASSERT_IS_ESNAP_CLONE(_blob, _id, _len) CU_ASSERT(is_esnap_clone(_blob, _id, _len))
102 : : #define UT_ASSERT_IS_NOT_ESNAP_CLONE(_blob) CU_ASSERT(is_not_esnap_clone(_blob))
103 : :
104 : : static void
105 : 144 : _get_xattr_value(void *arg, const char *name,
106 : : const void **value, size_t *value_len)
107 : : {
108 : : uint64_t i;
109 : :
110 [ - + ]: 144 : SPDK_CU_ASSERT_FATAL(value_len != NULL);
111 [ - + ]: 144 : SPDK_CU_ASSERT_FATAL(value != NULL);
112 : 144 : CU_ASSERT(arg == &g_ctx);
113 : :
114 [ + - ]: 288 : for (i = 0; i < sizeof(g_xattr_names); i++) {
115 [ + + - + : 288 : if (!strcmp(name, g_xattr_names[i])) {
+ + ]
116 [ - + ]: 144 : *value_len = strlen(g_xattr_values[i]);
117 : 144 : *value = g_xattr_values[i];
118 : 144 : break;
119 : : }
120 : : }
121 : 144 : }
122 : :
123 : : static void
124 : 12 : _get_xattr_value_null(void *arg, const char *name,
125 : : const void **value, size_t *value_len)
126 : : {
127 [ - + ]: 12 : SPDK_CU_ASSERT_FATAL(value_len != NULL);
128 [ - + ]: 12 : SPDK_CU_ASSERT_FATAL(value != NULL);
129 : 12 : CU_ASSERT(arg == NULL);
130 : :
131 : 12 : *value_len = 0;
132 : 12 : *value = NULL;
133 : 12 : }
134 : :
135 : : static int
136 : 168 : _get_snapshots_count(struct spdk_blob_store *bs)
137 : : {
138 : 168 : struct spdk_blob_list *snapshot = NULL;
139 : 168 : int count = 0;
140 : :
141 [ + + ]: 336 : TAILQ_FOREACH(snapshot, &bs->snapshots, link) {
142 : 168 : count += 1;
143 : : }
144 : :
145 : 168 : return count;
146 : : }
147 : :
148 : : static void
149 : 4578 : ut_spdk_blob_opts_init(struct spdk_blob_opts *opts)
150 : : {
151 : 4578 : spdk_blob_opts_init(opts, sizeof(*opts));
152 [ - + ]: 4578 : opts->use_extent_table = g_use_extent_table;
153 : 4578 : }
154 : :
155 : : static void
156 : 27906 : bs_op_complete(void *cb_arg, int bserrno)
157 : : {
158 : 27906 : g_bserrno = bserrno;
159 : 27906 : }
160 : :
161 : : static void
162 : 2352 : bs_op_with_handle_complete(void *cb_arg, struct spdk_blob_store *bs,
163 : : int bserrno)
164 : : {
165 : 2352 : g_bs = bs;
166 : 2352 : g_bserrno = bserrno;
167 : 2352 : }
168 : :
169 : : static void
170 : 98862 : blob_op_complete(void *cb_arg, int bserrno)
171 : : {
172 [ + + ]: 98862 : if (cb_arg != NULL) {
173 : 60 : int *errp = cb_arg;
174 : :
175 : 60 : *errp = bserrno;
176 : : }
177 : 98862 : g_bserrno = bserrno;
178 : 98862 : }
179 : :
180 : : static void
181 : 5700 : blob_op_with_id_complete(void *cb_arg, spdk_blob_id blobid, int bserrno)
182 : : {
183 : 5700 : g_blobid = blobid;
184 : 5700 : g_bserrno = bserrno;
185 : 5700 : }
186 : :
187 : : static void
188 : 2934 : blob_op_with_handle_complete(void *cb_arg, struct spdk_blob *blb, int bserrno)
189 : : {
190 : 2934 : g_blob = blb;
191 : 2934 : g_bserrno = bserrno;
192 : 2934 : }
193 : :
194 : : static void
195 : 24 : blob_op_with_handle_complete2(void *cb_arg, struct spdk_blob *blob, int bserrno)
196 : : {
197 [ + + ]: 24 : if (g_blob == NULL) {
198 : 12 : g_blob = blob;
199 : 12 : g_bserrno = bserrno;
200 : : } else {
201 : 12 : g_blob2 = blob;
202 : 12 : g_bserrno2 = bserrno;
203 : : }
204 : 24 : }
205 : :
206 : : static void
207 : 24 : blob_shallow_copy_status_cb(uint64_t copied_clusters, void *cb_arg)
208 : : {
209 : 24 : g_copied_clusters_count = copied_clusters;
210 : 24 : }
211 : :
212 : : static void
213 : 324 : ut_bs_reload(struct spdk_blob_store **bs, struct spdk_bs_opts *opts)
214 : : {
215 : : struct spdk_bs_dev *dev;
216 : :
217 : : /* Unload the blob store */
218 : 324 : spdk_bs_unload(*bs, bs_op_complete, NULL);
219 : 324 : poll_threads();
220 : 324 : CU_ASSERT(g_bserrno == 0);
221 : :
222 : 324 : dev = init_dev();
223 : : /* Load an existing blob store */
224 : 324 : spdk_bs_load(dev, opts, bs_op_with_handle_complete, NULL);
225 : 324 : poll_threads();
226 : 324 : CU_ASSERT(g_bserrno == 0);
227 [ - + ]: 324 : SPDK_CU_ASSERT_FATAL(g_bs != NULL);
228 : 324 : *bs = g_bs;
229 : :
230 : 324 : g_bserrno = -1;
231 : 324 : }
232 : :
233 : : static void
234 : 270 : ut_bs_dirty_load(struct spdk_blob_store **bs, struct spdk_bs_opts *opts)
235 : : {
236 : : struct spdk_bs_dev *dev;
237 : :
238 : : /* Dirty shutdown */
239 : 270 : bs_free(*bs);
240 : :
241 : 270 : dev = init_dev();
242 : : /* Load an existing blob store */
243 : 270 : spdk_bs_load(dev, opts, bs_op_with_handle_complete, NULL);
244 : 270 : poll_threads();
245 : 270 : CU_ASSERT(g_bserrno == 0);
246 [ - + ]: 270 : SPDK_CU_ASSERT_FATAL(g_bs != NULL);
247 : 270 : *bs = g_bs;
248 : :
249 : 270 : g_bserrno = -1;
250 : 270 : }
251 : :
252 : : static void
253 : 12 : blob_init(void)
254 : : {
255 : : struct spdk_blob_store *bs;
256 : : struct spdk_bs_dev *dev;
257 : :
258 : 12 : dev = init_dev();
259 : :
260 : : /* should fail for an unsupported blocklen */
261 : 12 : dev->blocklen = 500;
262 : 12 : spdk_bs_init(dev, NULL, bs_op_with_handle_complete, NULL);
263 : 12 : poll_threads();
264 : 12 : CU_ASSERT(g_bserrno == -EINVAL);
265 : :
266 : 12 : dev = init_dev();
267 : 12 : spdk_bs_init(dev, NULL, bs_op_with_handle_complete, NULL);
268 : 12 : poll_threads();
269 : 12 : CU_ASSERT(g_bserrno == 0);
270 [ - + ]: 12 : SPDK_CU_ASSERT_FATAL(g_bs != NULL);
271 : 12 : bs = g_bs;
272 : :
273 : 12 : spdk_bs_unload(bs, bs_op_complete, NULL);
274 : 12 : poll_threads();
275 : 12 : CU_ASSERT(g_bserrno == 0);
276 : 12 : g_bs = NULL;
277 : 12 : }
278 : :
279 : : static void
280 : 12 : blob_super(void)
281 : : {
282 : 12 : struct spdk_blob_store *bs = g_bs;
283 : : spdk_blob_id blobid;
284 : 12 : struct spdk_blob_opts blob_opts;
285 : :
286 : : /* Get the super blob without having set one */
287 : 12 : spdk_bs_get_super(bs, blob_op_with_id_complete, NULL);
288 : 12 : poll_threads();
289 : 12 : CU_ASSERT(g_bserrno == -ENOENT);
290 : 12 : CU_ASSERT(g_blobid == SPDK_BLOBID_INVALID);
291 : :
292 : : /* Create a blob */
293 : 12 : ut_spdk_blob_opts_init(&blob_opts);
294 : 12 : spdk_bs_create_blob_ext(bs, &blob_opts, blob_op_with_id_complete, NULL);
295 : 12 : poll_threads();
296 : 12 : CU_ASSERT(g_bserrno == 0);
297 : 12 : CU_ASSERT(g_blobid != SPDK_BLOBID_INVALID);
298 : 12 : blobid = g_blobid;
299 : :
300 : : /* Set the blob as the super blob */
301 : 12 : spdk_bs_set_super(bs, blobid, blob_op_complete, NULL);
302 : 12 : poll_threads();
303 : 12 : CU_ASSERT(g_bserrno == 0);
304 : :
305 : : /* Get the super blob */
306 : 12 : spdk_bs_get_super(bs, blob_op_with_id_complete, NULL);
307 : 12 : poll_threads();
308 : 12 : CU_ASSERT(g_bserrno == 0);
309 : 12 : CU_ASSERT(blobid == g_blobid);
310 : 12 : }
311 : :
312 : : static void
313 : 12 : blob_open(void)
314 : : {
315 : 12 : struct spdk_blob_store *bs = g_bs;
316 : : struct spdk_blob *blob;
317 : 12 : struct spdk_blob_opts blob_opts;
318 : : spdk_blob_id blobid, blobid2;
319 : :
320 : 12 : ut_spdk_blob_opts_init(&blob_opts);
321 : 12 : spdk_bs_create_blob_ext(bs, &blob_opts, blob_op_with_id_complete, NULL);
322 : 12 : poll_threads();
323 : 12 : CU_ASSERT(g_bserrno == 0);
324 : 12 : CU_ASSERT(g_blobid != SPDK_BLOBID_INVALID);
325 : 12 : blobid = g_blobid;
326 : :
327 : 12 : spdk_bs_open_blob(bs, blobid, blob_op_with_handle_complete, NULL);
328 : 12 : poll_threads();
329 : 12 : CU_ASSERT(g_bserrno == 0);
330 : 12 : CU_ASSERT(g_blob != NULL);
331 : 12 : blob = g_blob;
332 : :
333 : 12 : blobid2 = spdk_blob_get_id(blob);
334 : 12 : CU_ASSERT(blobid == blobid2);
335 : :
336 : : /* Try to open file again. It should return success. */
337 : 12 : spdk_bs_open_blob(bs, blobid, blob_op_with_handle_complete, NULL);
338 : 12 : poll_threads();
339 : 12 : CU_ASSERT(g_bserrno == 0);
340 : 12 : CU_ASSERT(blob == g_blob);
341 : :
342 : 12 : spdk_blob_close(blob, blob_op_complete, NULL);
343 : 12 : poll_threads();
344 : 12 : CU_ASSERT(g_bserrno == 0);
345 : :
346 : : /*
347 : : * Close the file a second time, releasing the second reference. This
348 : : * should succeed.
349 : : */
350 : 12 : blob = g_blob;
351 : 12 : spdk_blob_close(blob, blob_op_complete, NULL);
352 : 12 : poll_threads();
353 : 12 : CU_ASSERT(g_bserrno == 0);
354 : :
355 : : /*
356 : : * Try to open file again. It should succeed. This tests the case
357 : : * where the file is opened, closed, then re-opened again.
358 : : */
359 : 12 : spdk_bs_open_blob(bs, blobid, blob_op_with_handle_complete, NULL);
360 : 12 : poll_threads();
361 : 12 : CU_ASSERT(g_bserrno == 0);
362 : 12 : CU_ASSERT(g_blob != NULL);
363 : 12 : blob = g_blob;
364 : 12 : spdk_blob_close(blob, blob_op_complete, NULL);
365 : 12 : poll_threads();
366 : 12 : CU_ASSERT(g_bserrno == 0);
367 : :
368 : : /* Try to open file twice in succession. This should return the same
369 : : * blob object.
370 : : */
371 : 12 : g_blob = NULL;
372 : 12 : g_blob2 = NULL;
373 : 12 : g_bserrno = -1;
374 : 12 : g_bserrno2 = -1;
375 : 12 : spdk_bs_open_blob(bs, blobid, blob_op_with_handle_complete2, NULL);
376 : 12 : spdk_bs_open_blob(bs, blobid, blob_op_with_handle_complete2, NULL);
377 : 12 : poll_threads();
378 : 12 : CU_ASSERT(g_bserrno == 0);
379 : 12 : CU_ASSERT(g_bserrno2 == 0);
380 : 12 : CU_ASSERT(g_blob != NULL);
381 : 12 : CU_ASSERT(g_blob2 != NULL);
382 : 12 : CU_ASSERT(g_blob == g_blob2);
383 : :
384 : 12 : g_bserrno = -1;
385 : 12 : spdk_blob_close(g_blob, blob_op_complete, NULL);
386 : 12 : poll_threads();
387 : 12 : CU_ASSERT(g_bserrno == 0);
388 : :
389 : 12 : ut_blob_close_and_delete(bs, g_blob);
390 : 12 : }
391 : :
392 : : static void
393 : 12 : blob_create(void)
394 : : {
395 : 12 : struct spdk_blob_store *bs = g_bs;
396 : : struct spdk_blob *blob;
397 : 12 : struct spdk_blob_opts opts;
398 : : spdk_blob_id blobid;
399 : :
400 : : /* Create blob with 10 clusters */
401 : :
402 : 12 : ut_spdk_blob_opts_init(&opts);
403 : 12 : opts.num_clusters = 10;
404 : :
405 : 12 : spdk_bs_create_blob_ext(bs, &opts, blob_op_with_id_complete, NULL);
406 : 12 : poll_threads();
407 : 12 : CU_ASSERT(g_bserrno == 0);
408 : 12 : CU_ASSERT(g_blobid != SPDK_BLOBID_INVALID);
409 : 12 : blobid = g_blobid;
410 : :
411 : 12 : spdk_bs_open_blob(bs, blobid, blob_op_with_handle_complete, NULL);
412 : 12 : poll_threads();
413 : 12 : CU_ASSERT(g_bserrno == 0);
414 [ - + ]: 12 : SPDK_CU_ASSERT_FATAL(g_blob != NULL);
415 : 12 : blob = g_blob;
416 : 12 : CU_ASSERT(spdk_blob_get_num_clusters(blob) == 10);
417 : 12 : CU_ASSERT(spdk_blob_get_num_allocated_clusters(blob) == 10);
418 : :
419 : 12 : spdk_blob_close(blob, blob_op_complete, NULL);
420 : 12 : poll_threads();
421 : 12 : CU_ASSERT(g_bserrno == 0);
422 : :
423 : : /* Create blob with 0 clusters */
424 : :
425 : 12 : ut_spdk_blob_opts_init(&opts);
426 : 12 : opts.num_clusters = 0;
427 : :
428 : 12 : spdk_bs_create_blob_ext(bs, &opts, blob_op_with_id_complete, NULL);
429 : 12 : poll_threads();
430 : 12 : CU_ASSERT(g_bserrno == 0);
431 : 12 : CU_ASSERT(g_blobid != SPDK_BLOBID_INVALID);
432 : 12 : blobid = g_blobid;
433 : :
434 : 12 : spdk_bs_open_blob(bs, blobid, blob_op_with_handle_complete, NULL);
435 : 12 : poll_threads();
436 : 12 : CU_ASSERT(g_bserrno == 0);
437 [ - + ]: 12 : SPDK_CU_ASSERT_FATAL(g_blob != NULL);
438 : 12 : blob = g_blob;
439 : 12 : CU_ASSERT(spdk_blob_get_num_clusters(blob) == 0);
440 : 12 : CU_ASSERT(spdk_blob_get_num_allocated_clusters(blob) == 0);
441 : :
442 : 12 : spdk_blob_close(blob, blob_op_complete, NULL);
443 : 12 : poll_threads();
444 : 12 : CU_ASSERT(g_bserrno == 0);
445 : :
446 : : /* Create blob with default options (opts == NULL) */
447 : :
448 : 12 : spdk_bs_create_blob_ext(bs, NULL, blob_op_with_id_complete, NULL);
449 : 12 : poll_threads();
450 : 12 : CU_ASSERT(g_bserrno == 0);
451 : 12 : CU_ASSERT(g_blobid != SPDK_BLOBID_INVALID);
452 : 12 : blobid = g_blobid;
453 : :
454 : 12 : spdk_bs_open_blob(bs, blobid, blob_op_with_handle_complete, NULL);
455 : 12 : poll_threads();
456 : 12 : CU_ASSERT(g_bserrno == 0);
457 [ - + ]: 12 : SPDK_CU_ASSERT_FATAL(g_blob != NULL);
458 : 12 : blob = g_blob;
459 : 12 : CU_ASSERT(spdk_blob_get_num_clusters(blob) == 0);
460 : 12 : CU_ASSERT(spdk_blob_get_num_allocated_clusters(blob) == 0);
461 : :
462 : 12 : spdk_blob_close(blob, blob_op_complete, NULL);
463 : 12 : poll_threads();
464 : 12 : CU_ASSERT(g_bserrno == 0);
465 : :
466 : : /* Try to create blob with size larger than blobstore */
467 : :
468 : 12 : ut_spdk_blob_opts_init(&opts);
469 : 12 : opts.num_clusters = bs->total_clusters + 1;
470 : :
471 : 12 : spdk_bs_create_blob_ext(bs, &opts, blob_op_with_id_complete, NULL);
472 : 12 : poll_threads();
473 : 12 : CU_ASSERT(g_bserrno == -ENOSPC);
474 : 12 : }
475 : :
476 : : static void
477 : 12 : blob_create_zero_extent(void)
478 : : {
479 : 12 : struct spdk_blob_store *bs = g_bs;
480 : : struct spdk_blob *blob;
481 : : spdk_blob_id blobid;
482 : :
483 : : /* Create blob with default options (opts == NULL) */
484 : 12 : spdk_bs_create_blob_ext(bs, NULL, blob_op_with_id_complete, NULL);
485 : 12 : poll_threads();
486 : 12 : CU_ASSERT(g_bserrno == 0);
487 : 12 : CU_ASSERT(g_blobid != SPDK_BLOBID_INVALID);
488 : 12 : blobid = g_blobid;
489 : :
490 : 12 : spdk_bs_open_blob(bs, blobid, blob_op_with_handle_complete, NULL);
491 : 12 : poll_threads();
492 : 12 : CU_ASSERT(g_bserrno == 0);
493 [ - + ]: 12 : SPDK_CU_ASSERT_FATAL(g_blob != NULL);
494 : 12 : blob = g_blob;
495 : 12 : CU_ASSERT(spdk_blob_get_num_clusters(blob) == 0);
496 [ - + ]: 12 : CU_ASSERT(blob->extent_table_found == true);
497 : 12 : CU_ASSERT(blob->active.extent_pages_array_size == 0);
498 : 12 : CU_ASSERT(blob->active.extent_pages == NULL);
499 : :
500 : 12 : spdk_blob_close(blob, blob_op_complete, NULL);
501 : 12 : poll_threads();
502 : 12 : CU_ASSERT(g_bserrno == 0);
503 : :
504 : : /* Create blob with NULL internal options */
505 : 12 : bs_create_blob(bs, NULL, NULL, blob_op_with_id_complete, NULL);
506 : 12 : poll_threads();
507 : 12 : CU_ASSERT(g_bserrno == 0);
508 : 12 : CU_ASSERT(g_blobid != SPDK_BLOBID_INVALID);
509 : 12 : blobid = g_blobid;
510 : :
511 : 12 : spdk_bs_open_blob(bs, blobid, blob_op_with_handle_complete, NULL);
512 : 12 : poll_threads();
513 : 12 : CU_ASSERT(g_bserrno == 0);
514 [ - + ]: 12 : SPDK_CU_ASSERT_FATAL(g_blob != NULL);
515 : 12 : blob = g_blob;
516 : 12 : CU_ASSERT(TAILQ_FIRST(&blob->xattrs_internal) == NULL);
517 : 12 : CU_ASSERT(spdk_blob_get_num_clusters(blob) == 0);
518 [ - + ]: 12 : CU_ASSERT(blob->extent_table_found == true);
519 : 12 : CU_ASSERT(blob->active.extent_pages_array_size == 0);
520 : 12 : CU_ASSERT(blob->active.extent_pages == NULL);
521 : :
522 : 12 : spdk_blob_close(blob, blob_op_complete, NULL);
523 : 12 : poll_threads();
524 : 12 : CU_ASSERT(g_bserrno == 0);
525 : 12 : }
526 : :
527 : : /*
528 : : * Create and delete one blob in a loop over and over again. This helps ensure
529 : : * that the internal bit masks tracking used clusters and md_pages are being
530 : : * tracked correctly.
531 : : */
532 : : static void
533 : 12 : blob_create_loop(void)
534 : : {
535 : 12 : struct spdk_blob_store *bs = g_bs;
536 : 12 : struct spdk_blob_opts opts;
537 : : uint32_t i, loop_count;
538 : :
539 [ - + ]: 12 : loop_count = 4 * spdk_max(spdk_bit_array_capacity(bs->used_md_pages),
540 : : spdk_bit_pool_capacity(bs->used_clusters));
541 : :
542 [ + + ]: 3084 : for (i = 0; i < loop_count; i++) {
543 : 3072 : ut_spdk_blob_opts_init(&opts);
544 : 3072 : opts.num_clusters = 1;
545 : 3072 : g_bserrno = -1;
546 : 3072 : g_blobid = SPDK_BLOBID_INVALID;
547 : 3072 : spdk_bs_create_blob_ext(bs, &opts, blob_op_with_id_complete, NULL);
548 : 3072 : poll_threads();
549 : 3072 : CU_ASSERT(g_bserrno == 0);
550 : 3072 : CU_ASSERT(g_blobid != SPDK_BLOBID_INVALID);
551 : 3072 : spdk_bs_delete_blob(bs, g_blobid, blob_op_complete, NULL);
552 : 3072 : poll_threads();
553 : 3072 : CU_ASSERT(g_bserrno == 0);
554 : : }
555 : 12 : }
556 : :
557 : : static void
558 : 12 : blob_create_fail(void)
559 : : {
560 : 12 : struct spdk_blob_store *bs = g_bs;
561 : 12 : struct spdk_blob_opts opts;
562 : : spdk_blob_id blobid;
563 : 12 : uint32_t used_blobids_count = spdk_bit_array_count_set(bs->used_blobids);
564 : 12 : uint32_t used_md_pages_count = spdk_bit_array_count_set(bs->used_md_pages);
565 : :
566 : : /* NULL callback */
567 : 12 : ut_spdk_blob_opts_init(&opts);
568 : 12 : opts.xattrs.names = g_xattr_names;
569 : 12 : opts.xattrs.get_value = NULL;
570 : 12 : opts.xattrs.count = 1;
571 : 12 : opts.xattrs.ctx = &g_ctx;
572 : :
573 : 12 : blobid = spdk_bit_array_find_first_clear(bs->used_md_pages, 0);
574 : 12 : spdk_bs_create_blob_ext(bs, &opts, blob_op_with_id_complete, NULL);
575 : 12 : poll_threads();
576 : 12 : CU_ASSERT(g_bserrno == -EINVAL);
577 : 12 : CU_ASSERT(g_blobid != SPDK_BLOBID_INVALID);
578 : 12 : CU_ASSERT(spdk_bit_array_count_set(bs->used_blobids) == used_blobids_count);
579 : 12 : CU_ASSERT(spdk_bit_array_count_set(bs->used_md_pages) == used_md_pages_count);
580 : :
581 : 12 : spdk_bs_open_blob(bs, blobid, blob_op_with_handle_complete, NULL);
582 : 12 : poll_threads();
583 : 12 : CU_ASSERT(g_bserrno == -ENOENT);
584 [ - + ]: 12 : SPDK_CU_ASSERT_FATAL(g_blob == NULL);
585 : :
586 : 12 : ut_bs_reload(&bs, NULL);
587 : 12 : CU_ASSERT(spdk_bit_array_count_set(bs->used_blobids) == used_blobids_count);
588 : 12 : CU_ASSERT(spdk_bit_array_count_set(bs->used_md_pages) == used_md_pages_count);
589 : :
590 : 12 : spdk_bs_iter_first(bs, blob_op_with_handle_complete, NULL);
591 : 12 : poll_threads();
592 : 12 : CU_ASSERT(g_blob == NULL);
593 : 12 : CU_ASSERT(g_bserrno == -ENOENT);
594 : 12 : }
595 : :
596 : : static void
597 : 12 : blob_create_internal(void)
598 : : {
599 : 12 : struct spdk_blob_store *bs = g_bs;
600 : : struct spdk_blob *blob;
601 : 12 : struct spdk_blob_opts opts;
602 : 12 : struct spdk_blob_xattr_opts internal_xattrs;
603 : 12 : const void *value;
604 : 12 : size_t value_len;
605 : : spdk_blob_id blobid;
606 : : int rc;
607 : :
608 : : /* Create blob with custom xattrs */
609 : :
610 : 12 : ut_spdk_blob_opts_init(&opts);
611 : 12 : blob_xattrs_init(&internal_xattrs);
612 : 12 : internal_xattrs.count = 3;
613 : 12 : internal_xattrs.names = g_xattr_names;
614 : 12 : internal_xattrs.get_value = _get_xattr_value;
615 : 12 : internal_xattrs.ctx = &g_ctx;
616 : :
617 : 12 : bs_create_blob(bs, &opts, &internal_xattrs, blob_op_with_id_complete, NULL);
618 : 12 : poll_threads();
619 : 12 : CU_ASSERT(g_bserrno == 0);
620 : 12 : CU_ASSERT(g_blobid != SPDK_BLOBID_INVALID);
621 : 12 : blobid = g_blobid;
622 : :
623 : 12 : spdk_bs_open_blob(bs, blobid, blob_op_with_handle_complete, NULL);
624 : 12 : poll_threads();
625 : 12 : CU_ASSERT(g_bserrno == 0);
626 [ - + ]: 12 : SPDK_CU_ASSERT_FATAL(g_blob != NULL);
627 : 12 : blob = g_blob;
628 : :
629 : 12 : rc = blob_get_xattr_value(blob, g_xattr_names[0], &value, &value_len, true);
630 : 12 : CU_ASSERT(rc == 0);
631 [ - + ]: 12 : SPDK_CU_ASSERT_FATAL(value != NULL);
632 [ - + ]: 12 : CU_ASSERT(value_len == strlen(g_xattr_values[0]));
633 [ - + - + ]: 12 : CU_ASSERT_NSTRING_EQUAL_FATAL(value, g_xattr_values[0], value_len);
634 : :
635 : 12 : rc = blob_get_xattr_value(blob, g_xattr_names[1], &value, &value_len, true);
636 : 12 : CU_ASSERT(rc == 0);
637 [ - + ]: 12 : SPDK_CU_ASSERT_FATAL(value != NULL);
638 [ - + ]: 12 : CU_ASSERT(value_len == strlen(g_xattr_values[1]));
639 [ - + - + ]: 12 : CU_ASSERT_NSTRING_EQUAL((char *)value, g_xattr_values[1], value_len);
640 : :
641 : 12 : rc = blob_get_xattr_value(blob, g_xattr_names[2], &value, &value_len, true);
642 : 12 : CU_ASSERT(rc == 0);
643 [ - + ]: 12 : SPDK_CU_ASSERT_FATAL(value != NULL);
644 [ - + ]: 12 : CU_ASSERT(value_len == strlen(g_xattr_values[2]));
645 [ - + - + ]: 12 : CU_ASSERT_NSTRING_EQUAL((char *)value, g_xattr_values[2], value_len);
646 : :
647 : 12 : rc = spdk_blob_get_xattr_value(blob, g_xattr_names[0], &value, &value_len);
648 : 12 : CU_ASSERT(rc != 0);
649 : :
650 : 12 : rc = spdk_blob_get_xattr_value(blob, g_xattr_names[1], &value, &value_len);
651 : 12 : CU_ASSERT(rc != 0);
652 : :
653 : 12 : rc = spdk_blob_get_xattr_value(blob, g_xattr_names[2], &value, &value_len);
654 : 12 : CU_ASSERT(rc != 0);
655 : :
656 : 12 : spdk_blob_close(blob, blob_op_complete, NULL);
657 : 12 : poll_threads();
658 : 12 : CU_ASSERT(g_bserrno == 0);
659 : :
660 : : /* Create blob with NULL internal options */
661 : :
662 : 12 : bs_create_blob(bs, NULL, NULL, blob_op_with_id_complete, NULL);
663 : 12 : poll_threads();
664 : 12 : CU_ASSERT(g_bserrno == 0);
665 : 12 : CU_ASSERT(g_blobid != SPDK_BLOBID_INVALID);
666 : 12 : blobid = g_blobid;
667 : :
668 : 12 : spdk_bs_open_blob(bs, blobid, blob_op_with_handle_complete, NULL);
669 : 12 : poll_threads();
670 : 12 : CU_ASSERT(g_bserrno == 0);
671 [ - + ]: 12 : SPDK_CU_ASSERT_FATAL(g_blob != NULL);
672 : 12 : CU_ASSERT(TAILQ_FIRST(&g_blob->xattrs_internal) == NULL);
673 : 12 : CU_ASSERT(spdk_blob_get_num_clusters(g_blob) == 0);
674 : :
675 : 12 : blob = g_blob;
676 : :
677 : 12 : spdk_blob_close(blob, blob_op_complete, NULL);
678 : 12 : poll_threads();
679 : 12 : CU_ASSERT(g_bserrno == 0);
680 : 12 : }
681 : :
682 : : static void
683 : 12 : blob_thin_provision(void)
684 : : {
685 : 12 : struct spdk_blob_store *bs;
686 : : struct spdk_bs_dev *dev;
687 : : struct spdk_blob *blob;
688 : 12 : struct spdk_blob_opts opts;
689 : 12 : struct spdk_bs_opts bs_opts;
690 : : spdk_blob_id blobid;
691 : :
692 : 12 : dev = init_dev();
693 : 12 : spdk_bs_opts_init(&bs_opts, sizeof(bs_opts));
694 : 12 : snprintf(bs_opts.bstype.bstype, sizeof(bs_opts.bstype.bstype), "TESTTYPE");
695 : :
696 : : /* Initialize a new blob store */
697 : 12 : spdk_bs_init(dev, &bs_opts, bs_op_with_handle_complete, NULL);
698 : 12 : poll_threads();
699 : 12 : CU_ASSERT(g_bserrno == 0);
700 [ - + ]: 12 : SPDK_CU_ASSERT_FATAL(g_bs != NULL);
701 : :
702 : 12 : bs = g_bs;
703 : :
704 : : /* Create blob with thin provisioning enabled */
705 : :
706 : 12 : ut_spdk_blob_opts_init(&opts);
707 : 12 : opts.thin_provision = true;
708 : 12 : opts.num_clusters = 10;
709 : :
710 : 12 : blob = ut_blob_create_and_open(bs, &opts);
711 : 12 : blobid = spdk_blob_get_id(blob);
712 : 12 : CU_ASSERT(blob->invalid_flags & SPDK_BLOB_THIN_PROV);
713 : 12 : CU_ASSERT(spdk_blob_get_num_allocated_clusters(blob) == 0);
714 : : /* In thin provisioning with num_clusters is set, if not using the
715 : : * extent table, there is no allocation. If extent table is used,
716 : : * there is related allocation happened. */
717 [ + + + + ]: 12 : if (blob->extent_table_found == true) {
718 : 6 : CU_ASSERT(blob->active.extent_pages_array_size > 0);
719 : 6 : CU_ASSERT(blob->active.extent_pages != NULL);
720 : : } else {
721 : 6 : CU_ASSERT(blob->active.extent_pages_array_size == 0);
722 : 6 : CU_ASSERT(blob->active.extent_pages == NULL);
723 : : }
724 : :
725 : 12 : spdk_blob_close(blob, blob_op_complete, NULL);
726 : 12 : CU_ASSERT(g_bserrno == 0);
727 : :
728 : : /* Do not shut down cleanly. This makes sure that when we load again
729 : : * and try to recover a valid used_cluster map, that blobstore will
730 : : * ignore clusters with index 0 since these are unallocated clusters.
731 : : */
732 : 12 : ut_bs_dirty_load(&bs, &bs_opts);
733 : :
734 : 12 : spdk_bs_open_blob(bs, blobid, blob_op_with_handle_complete, NULL);
735 : 12 : poll_threads();
736 : 12 : CU_ASSERT(g_bserrno == 0);
737 [ - + ]: 12 : SPDK_CU_ASSERT_FATAL(g_blob != NULL);
738 : 12 : blob = g_blob;
739 : 12 : CU_ASSERT(blob->invalid_flags & SPDK_BLOB_THIN_PROV);
740 : 12 : CU_ASSERT(spdk_blob_get_num_allocated_clusters(blob) == 0);
741 : :
742 : 12 : ut_blob_close_and_delete(bs, blob);
743 : :
744 : 12 : spdk_bs_unload(bs, bs_op_complete, NULL);
745 : 12 : poll_threads();
746 : 12 : CU_ASSERT(g_bserrno == 0);
747 : 12 : g_bs = NULL;
748 : 12 : }
749 : :
750 : : static void
751 : 12 : blob_snapshot(void)
752 : : {
753 : 12 : struct spdk_blob_store *bs = g_bs;
754 : : struct spdk_blob *blob;
755 : : struct spdk_blob *snapshot, *snapshot2;
756 : : struct spdk_blob_bs_dev *blob_bs_dev;
757 : 12 : struct spdk_blob_opts opts;
758 : 12 : struct spdk_blob_xattr_opts xattrs;
759 : : spdk_blob_id blobid;
760 : : spdk_blob_id snapshotid;
761 : : spdk_blob_id snapshotid2;
762 : 12 : const void *value;
763 : 12 : size_t value_len;
764 : : int rc;
765 : 12 : spdk_blob_id ids[2];
766 : 12 : size_t count;
767 : :
768 : : /* Create blob with 10 clusters */
769 : 12 : ut_spdk_blob_opts_init(&opts);
770 : 12 : opts.num_clusters = 10;
771 : :
772 : 12 : blob = ut_blob_create_and_open(bs, &opts);
773 : 12 : blobid = spdk_blob_get_id(blob);
774 : 12 : CU_ASSERT(spdk_blob_get_num_clusters(blob) == 10);
775 : :
776 : : /* Create snapshot from blob */
777 : 12 : CU_ASSERT_EQUAL(_get_snapshots_count(bs), 0);
778 : 12 : spdk_bs_create_snapshot(bs, blobid, NULL, blob_op_with_id_complete, NULL);
779 : 12 : poll_threads();
780 : 12 : CU_ASSERT(g_bserrno == 0);
781 : 12 : CU_ASSERT(g_blobid != SPDK_BLOBID_INVALID);
782 : 12 : CU_ASSERT_EQUAL(_get_snapshots_count(bs), 1);
783 : 12 : snapshotid = g_blobid;
784 : :
785 : 12 : spdk_bs_open_blob(bs, snapshotid, blob_op_with_handle_complete, NULL);
786 : 12 : poll_threads();
787 : 12 : CU_ASSERT(g_bserrno == 0);
788 [ - + ]: 12 : SPDK_CU_ASSERT_FATAL(g_blob != NULL);
789 : 12 : snapshot = g_blob;
790 [ - + ]: 12 : CU_ASSERT(snapshot->data_ro == true);
791 [ - + ]: 12 : CU_ASSERT(snapshot->md_ro == true);
792 : 12 : CU_ASSERT(spdk_blob_get_num_clusters(snapshot) == 10);
793 : 12 : CU_ASSERT(spdk_blob_get_num_allocated_clusters(snapshot) == 10);
794 : :
795 : 12 : CU_ASSERT(spdk_blob_get_num_clusters(blob) == 10);
796 : 12 : CU_ASSERT(spdk_blob_get_num_allocated_clusters(blob) == 0);
797 : 12 : CU_ASSERT(blob->invalid_flags & SPDK_BLOB_THIN_PROV);
798 : 12 : CU_ASSERT(spdk_mem_all_zero(blob->active.clusters,
799 : : blob->active.num_clusters * sizeof(blob->active.clusters[0])));
800 : :
801 : : /* Try to create snapshot from clone with xattrs */
802 : 12 : xattrs.names = g_xattr_names;
803 : 12 : xattrs.get_value = _get_xattr_value;
804 : 12 : xattrs.count = 3;
805 : 12 : xattrs.ctx = &g_ctx;
806 : 12 : spdk_bs_create_snapshot(bs, blobid, &xattrs, blob_op_with_id_complete, NULL);
807 : 12 : poll_threads();
808 : 12 : CU_ASSERT(g_bserrno == 0);
809 : 12 : CU_ASSERT(g_blobid != SPDK_BLOBID_INVALID);
810 : 12 : CU_ASSERT_EQUAL(_get_snapshots_count(bs), 2);
811 : 12 : snapshotid2 = g_blobid;
812 : :
813 : 12 : spdk_bs_open_blob(bs, snapshotid2, blob_op_with_handle_complete, NULL);
814 : 12 : CU_ASSERT(g_bserrno == 0);
815 [ - + ]: 12 : SPDK_CU_ASSERT_FATAL(g_blob != NULL);
816 : 12 : snapshot2 = g_blob;
817 [ - + ]: 12 : CU_ASSERT(snapshot2->data_ro == true);
818 [ - + ]: 12 : CU_ASSERT(snapshot2->md_ro == true);
819 : 12 : CU_ASSERT(spdk_blob_get_num_clusters(snapshot2) == 10);
820 : 12 : CU_ASSERT(spdk_blob_get_num_allocated_clusters(snapshot2) == 0);
821 : :
822 : : /* Confirm that blob is backed by snapshot2 and snapshot2 is backed by snapshot */
823 : 12 : CU_ASSERT(snapshot->back_bs_dev == NULL);
824 [ - + ]: 12 : SPDK_CU_ASSERT_FATAL(blob->back_bs_dev != NULL);
825 [ - + ]: 12 : SPDK_CU_ASSERT_FATAL(snapshot2->back_bs_dev != NULL);
826 : :
827 : 12 : blob_bs_dev = (struct spdk_blob_bs_dev *)blob->back_bs_dev;
828 : 12 : CU_ASSERT(blob_bs_dev->blob == snapshot2);
829 : :
830 : 12 : blob_bs_dev = (struct spdk_blob_bs_dev *)snapshot2->back_bs_dev;
831 : 12 : CU_ASSERT(blob_bs_dev->blob == snapshot);
832 : :
833 : 12 : rc = spdk_blob_get_xattr_value(snapshot2, g_xattr_names[0], &value, &value_len);
834 : 12 : CU_ASSERT(rc == 0);
835 [ - + ]: 12 : SPDK_CU_ASSERT_FATAL(value != NULL);
836 [ - + ]: 12 : CU_ASSERT(value_len == strlen(g_xattr_values[0]));
837 [ - + - + ]: 12 : CU_ASSERT_NSTRING_EQUAL_FATAL(value, g_xattr_values[0], value_len);
838 : :
839 : 12 : rc = spdk_blob_get_xattr_value(snapshot2, g_xattr_names[1], &value, &value_len);
840 : 12 : CU_ASSERT(rc == 0);
841 [ - + ]: 12 : SPDK_CU_ASSERT_FATAL(value != NULL);
842 [ - + ]: 12 : CU_ASSERT(value_len == strlen(g_xattr_values[1]));
843 [ - + - + ]: 12 : CU_ASSERT_NSTRING_EQUAL((char *)value, g_xattr_values[1], value_len);
844 : :
845 : 12 : rc = spdk_blob_get_xattr_value(snapshot2, g_xattr_names[2], &value, &value_len);
846 : 12 : CU_ASSERT(rc == 0);
847 [ - + ]: 12 : SPDK_CU_ASSERT_FATAL(value != NULL);
848 [ - + ]: 12 : CU_ASSERT(value_len == strlen(g_xattr_values[2]));
849 [ - + - + ]: 12 : CU_ASSERT_NSTRING_EQUAL((char *)value, g_xattr_values[2], value_len);
850 : :
851 : : /* Confirm that blob is clone of snapshot2, and snapshot2 is clone of snapshot */
852 : 12 : count = 2;
853 : 12 : CU_ASSERT(spdk_blob_get_clones(bs, snapshotid2, ids, &count) == 0);
854 : 12 : CU_ASSERT(count == 1);
855 : 12 : CU_ASSERT(ids[0] == blobid);
856 : :
857 : 12 : count = 2;
858 : 12 : CU_ASSERT(spdk_blob_get_clones(bs, snapshotid, ids, &count) == 0);
859 : 12 : CU_ASSERT(count == 1);
860 : 12 : CU_ASSERT(ids[0] == snapshotid2);
861 : :
862 : : /* Try to create snapshot from snapshot */
863 : 12 : spdk_bs_create_snapshot(bs, snapshotid, NULL, blob_op_with_id_complete, NULL);
864 : 12 : poll_threads();
865 : 12 : CU_ASSERT(g_bserrno == -EINVAL);
866 : 12 : CU_ASSERT(g_blobid == SPDK_BLOBID_INVALID);
867 : 12 : CU_ASSERT_EQUAL(_get_snapshots_count(bs), 2);
868 : :
869 : : /* Delete blob and confirm that it is no longer on snapshot2 clone list */
870 : 12 : ut_blob_close_and_delete(bs, blob);
871 : 12 : count = 2;
872 : 12 : CU_ASSERT(spdk_blob_get_clones(bs, snapshotid2, ids, &count) == 0);
873 : 12 : CU_ASSERT(count == 0);
874 : :
875 : : /* Delete snapshot2 and confirm that it is no longer on snapshot clone list */
876 : 12 : ut_blob_close_and_delete(bs, snapshot2);
877 : 12 : CU_ASSERT_EQUAL(_get_snapshots_count(bs), 1);
878 : 12 : count = 2;
879 : 12 : CU_ASSERT(spdk_blob_get_clones(bs, snapshotid2, ids, &count) == 0);
880 : 12 : CU_ASSERT(count == 0);
881 : :
882 : 12 : ut_blob_close_and_delete(bs, snapshot);
883 : 12 : CU_ASSERT_EQUAL(_get_snapshots_count(bs), 0);
884 : 12 : }
885 : :
886 : : static void
887 : 12 : blob_snapshot_freeze_io(void)
888 : 12 : {
889 : : struct spdk_io_channel *channel;
890 : : struct spdk_bs_channel *bs_channel;
891 : 12 : struct spdk_blob_store *bs = g_bs;
892 : : struct spdk_blob *blob;
893 : 12 : struct spdk_blob_opts opts;
894 : : spdk_blob_id blobid;
895 : 12 : uint32_t num_of_pages = 10;
896 [ - + ]: 12 : uint8_t payload_read[num_of_pages * SPDK_BS_PAGE_SIZE];
897 [ - + ]: 12 : uint8_t payload_write[num_of_pages * SPDK_BS_PAGE_SIZE];
898 [ - + ]: 12 : uint8_t payload_zero[num_of_pages * SPDK_BS_PAGE_SIZE];
899 : :
900 [ - + ]: 12 : memset(payload_write, 0xE5, sizeof(payload_write));
901 [ - + ]: 12 : memset(payload_read, 0x00, sizeof(payload_read));
902 [ - + ]: 12 : memset(payload_zero, 0x00, sizeof(payload_zero));
903 : :
904 : : /* Test freeze I/O during snapshot */
905 : 12 : channel = spdk_bs_alloc_io_channel(bs);
906 : 12 : bs_channel = spdk_io_channel_get_ctx(channel);
907 : :
908 : : /* Create blob with 10 clusters */
909 : 12 : ut_spdk_blob_opts_init(&opts);
910 : 12 : opts.num_clusters = 10;
911 : 12 : opts.thin_provision = false;
912 : :
913 : 12 : blob = ut_blob_create_and_open(bs, &opts);
914 : 12 : blobid = spdk_blob_get_id(blob);
915 : 12 : CU_ASSERT(spdk_blob_get_num_clusters(blob) == 10);
916 : :
917 : 12 : spdk_bs_create_snapshot(bs, blobid, NULL, blob_op_with_id_complete, NULL);
918 : :
919 : : /* This is implementation specific.
920 : : * Flag 'frozen_io' is set in _spdk_bs_snapshot_freeze_cpl callback.
921 : : * Four async I/O operations happen before that. */
922 : 12 : poll_thread_times(0, 5);
923 : :
924 : 12 : CU_ASSERT(TAILQ_EMPTY(&bs_channel->queued_io));
925 : :
926 : : /* Blob I/O should be frozen here */
927 : 12 : CU_ASSERT(blob->frozen_refcnt == 1);
928 : :
929 : : /* Write to the blob */
930 : 12 : spdk_blob_io_write(blob, channel, payload_write, 0, num_of_pages, blob_op_complete, NULL);
931 : :
932 : : /* Verify that I/O is queued */
933 : 12 : CU_ASSERT(!TAILQ_EMPTY(&bs_channel->queued_io));
934 : : /* Verify that payload is not written to disk, at this point the blobs already switched */
935 : 12 : CU_ASSERT(blob->active.clusters[0] == 0);
936 : :
937 : : /* Finish all operations including spdk_bs_create_snapshot */
938 : 12 : poll_threads();
939 : :
940 : : /* Verify snapshot */
941 : 12 : CU_ASSERT(g_bserrno == 0);
942 : 12 : CU_ASSERT(g_blobid != SPDK_BLOBID_INVALID);
943 : :
944 : : /* Verify that blob has unset frozen_io */
945 : 12 : CU_ASSERT(blob->frozen_refcnt == 0);
946 : :
947 : : /* Verify that postponed I/O completed successfully by comparing payload */
948 : 12 : spdk_blob_io_read(blob, channel, payload_read, 0, num_of_pages, blob_op_complete, NULL);
949 : 12 : poll_threads();
950 : 12 : CU_ASSERT(g_bserrno == 0);
951 [ - + - + ]: 12 : CU_ASSERT(memcmp(payload_write, payload_read, num_of_pages * SPDK_BS_PAGE_SIZE) == 0);
952 : :
953 : 12 : spdk_bs_free_io_channel(channel);
954 : 12 : poll_threads();
955 : :
956 : 12 : ut_blob_close_and_delete(bs, blob);
957 : 12 : }
958 : :
959 : : static void
960 : 12 : blob_clone(void)
961 : : {
962 : 12 : struct spdk_blob_store *bs = g_bs;
963 : 12 : struct spdk_blob_opts opts;
964 : : struct spdk_blob *blob, *snapshot, *clone;
965 : : spdk_blob_id blobid, cloneid, snapshotid;
966 : 12 : struct spdk_blob_xattr_opts xattrs;
967 : 12 : const void *value;
968 : 12 : size_t value_len;
969 : : int rc;
970 : :
971 : : /* Create blob with 10 clusters */
972 : :
973 : 12 : ut_spdk_blob_opts_init(&opts);
974 : 12 : opts.num_clusters = 10;
975 : :
976 : 12 : blob = ut_blob_create_and_open(bs, &opts);
977 : 12 : blobid = spdk_blob_get_id(blob);
978 : 12 : CU_ASSERT(spdk_blob_get_num_clusters(blob) == 10);
979 : :
980 : : /* Create snapshot */
981 : 12 : spdk_bs_create_snapshot(bs, blobid, NULL, blob_op_with_id_complete, NULL);
982 : 12 : poll_threads();
983 : 12 : CU_ASSERT(g_bserrno == 0);
984 : 12 : CU_ASSERT(g_blobid != SPDK_BLOBID_INVALID);
985 : 12 : snapshotid = g_blobid;
986 : :
987 : 12 : spdk_bs_open_blob(bs, snapshotid, blob_op_with_handle_complete, NULL);
988 : 12 : poll_threads();
989 : 12 : CU_ASSERT(g_bserrno == 0);
990 [ - + ]: 12 : SPDK_CU_ASSERT_FATAL(g_blob != NULL);
991 : 12 : snapshot = g_blob;
992 [ - + ]: 12 : CU_ASSERT(snapshot->data_ro == true);
993 [ - + ]: 12 : CU_ASSERT(snapshot->md_ro == true);
994 : 12 : CU_ASSERT(spdk_blob_get_num_clusters(snapshot) == 10);
995 : :
996 : 12 : spdk_blob_close(snapshot, blob_op_complete, NULL);
997 : 12 : poll_threads();
998 : 12 : CU_ASSERT(g_bserrno == 0);
999 : :
1000 : : /* Create clone from snapshot with xattrs */
1001 : 12 : xattrs.names = g_xattr_names;
1002 : 12 : xattrs.get_value = _get_xattr_value;
1003 : 12 : xattrs.count = 3;
1004 : 12 : xattrs.ctx = &g_ctx;
1005 : :
1006 : 12 : spdk_bs_create_clone(bs, snapshotid, &xattrs, blob_op_with_id_complete, NULL);
1007 : 12 : poll_threads();
1008 : 12 : CU_ASSERT(g_bserrno == 0);
1009 : 12 : CU_ASSERT(g_blobid != SPDK_BLOBID_INVALID);
1010 : 12 : cloneid = g_blobid;
1011 : :
1012 : 12 : spdk_bs_open_blob(bs, cloneid, blob_op_with_handle_complete, NULL);
1013 : 12 : poll_threads();
1014 : 12 : CU_ASSERT(g_bserrno == 0);
1015 [ - + ]: 12 : SPDK_CU_ASSERT_FATAL(g_blob != NULL);
1016 : 12 : clone = g_blob;
1017 [ - + ]: 12 : CU_ASSERT(clone->data_ro == false);
1018 [ - + ]: 12 : CU_ASSERT(clone->md_ro == false);
1019 : 12 : CU_ASSERT(spdk_blob_get_num_clusters(clone) == 10);
1020 : 12 : CU_ASSERT(spdk_blob_get_num_allocated_clusters(clone) == 0);
1021 : :
1022 : 12 : rc = spdk_blob_get_xattr_value(clone, g_xattr_names[0], &value, &value_len);
1023 : 12 : CU_ASSERT(rc == 0);
1024 [ - + ]: 12 : SPDK_CU_ASSERT_FATAL(value != NULL);
1025 [ - + ]: 12 : CU_ASSERT(value_len == strlen(g_xattr_values[0]));
1026 [ - + - + ]: 12 : CU_ASSERT_NSTRING_EQUAL_FATAL(value, g_xattr_values[0], value_len);
1027 : :
1028 : 12 : rc = spdk_blob_get_xattr_value(clone, g_xattr_names[1], &value, &value_len);
1029 : 12 : CU_ASSERT(rc == 0);
1030 [ - + ]: 12 : SPDK_CU_ASSERT_FATAL(value != NULL);
1031 [ - + ]: 12 : CU_ASSERT(value_len == strlen(g_xattr_values[1]));
1032 [ - + - + ]: 12 : CU_ASSERT_NSTRING_EQUAL((char *)value, g_xattr_values[1], value_len);
1033 : :
1034 : 12 : rc = spdk_blob_get_xattr_value(clone, g_xattr_names[2], &value, &value_len);
1035 : 12 : CU_ASSERT(rc == 0);
1036 [ - + ]: 12 : SPDK_CU_ASSERT_FATAL(value != NULL);
1037 [ - + ]: 12 : CU_ASSERT(value_len == strlen(g_xattr_values[2]));
1038 [ - + - + ]: 12 : CU_ASSERT_NSTRING_EQUAL((char *)value, g_xattr_values[2], value_len);
1039 : :
1040 : :
1041 : 12 : spdk_blob_close(clone, blob_op_complete, NULL);
1042 : 12 : poll_threads();
1043 : 12 : CU_ASSERT(g_bserrno == 0);
1044 : :
1045 : : /* Try to create clone from not read only blob */
1046 : 12 : spdk_bs_create_clone(bs, blobid, NULL, blob_op_with_id_complete, NULL);
1047 : 12 : poll_threads();
1048 : 12 : CU_ASSERT(g_bserrno == -EINVAL);
1049 : 12 : CU_ASSERT(g_blobid == SPDK_BLOBID_INVALID);
1050 : :
1051 : : /* Mark blob as read only */
1052 : 12 : spdk_blob_set_read_only(blob);
1053 : 12 : spdk_blob_sync_md(blob, blob_op_complete, NULL);
1054 : 12 : poll_threads();
1055 : 12 : CU_ASSERT(g_bserrno == 0);
1056 : :
1057 : : /* Create clone from read only blob */
1058 : 12 : spdk_bs_create_clone(bs, blobid, NULL, blob_op_with_id_complete, NULL);
1059 : 12 : poll_threads();
1060 : 12 : CU_ASSERT(g_bserrno == 0);
1061 : 12 : CU_ASSERT(g_blobid != SPDK_BLOBID_INVALID);
1062 : 12 : cloneid = g_blobid;
1063 : :
1064 : 12 : spdk_bs_open_blob(bs, cloneid, blob_op_with_handle_complete, NULL);
1065 : 12 : poll_threads();
1066 : 12 : CU_ASSERT(g_bserrno == 0);
1067 [ - + ]: 12 : SPDK_CU_ASSERT_FATAL(g_blob != NULL);
1068 : 12 : clone = g_blob;
1069 [ - + ]: 12 : CU_ASSERT(clone->data_ro == false);
1070 [ - + ]: 12 : CU_ASSERT(clone->md_ro == false);
1071 : 12 : CU_ASSERT(spdk_blob_get_num_clusters(clone) == 10);
1072 : :
1073 : 12 : ut_blob_close_and_delete(bs, clone);
1074 : 12 : ut_blob_close_and_delete(bs, blob);
1075 : 12 : }
1076 : :
1077 : : static void
1078 : 24 : _blob_inflate(bool decouple_parent)
1079 : : {
1080 : 24 : struct spdk_blob_store *bs = g_bs;
1081 : 24 : struct spdk_blob_opts opts;
1082 : : struct spdk_blob *blob, *snapshot;
1083 : : spdk_blob_id blobid, snapshotid;
1084 : : struct spdk_io_channel *channel;
1085 : : uint64_t free_clusters;
1086 : :
1087 : 24 : channel = spdk_bs_alloc_io_channel(bs);
1088 [ - + ]: 24 : SPDK_CU_ASSERT_FATAL(channel != NULL);
1089 : :
1090 : : /* Create blob with 10 clusters */
1091 : :
1092 : 24 : ut_spdk_blob_opts_init(&opts);
1093 : 24 : opts.num_clusters = 10;
1094 : 24 : opts.thin_provision = true;
1095 : :
1096 : 24 : blob = ut_blob_create_and_open(bs, &opts);
1097 : 24 : blobid = spdk_blob_get_id(blob);
1098 : 24 : CU_ASSERT(spdk_blob_get_num_clusters(blob) == 10);
1099 : 24 : CU_ASSERT(spdk_blob_is_thin_provisioned(blob) == true);
1100 : 24 : CU_ASSERT(spdk_blob_get_num_allocated_clusters(blob) == 0);
1101 : :
1102 : : /* 1) Blob with no parent */
1103 [ + + ]: 24 : if (decouple_parent) {
1104 : : /* Decouple parent of blob with no parent (should fail) */
1105 : 12 : spdk_bs_blob_decouple_parent(bs, channel, blobid, blob_op_complete, NULL);
1106 : 12 : poll_threads();
1107 : 12 : CU_ASSERT(g_bserrno != 0);
1108 : : } else {
1109 : : /* Inflate of thin blob with no parent should made it thick */
1110 : 12 : spdk_bs_inflate_blob(bs, channel, blobid, blob_op_complete, NULL);
1111 : 12 : poll_threads();
1112 : 12 : CU_ASSERT(g_bserrno == 0);
1113 : 12 : CU_ASSERT(spdk_blob_is_thin_provisioned(blob) == false);
1114 : 12 : CU_ASSERT(spdk_blob_get_num_allocated_clusters(blob) == 10);
1115 : : }
1116 : :
1117 : 24 : spdk_bs_create_snapshot(bs, blobid, NULL, blob_op_with_id_complete, NULL);
1118 : 24 : poll_threads();
1119 : 24 : CU_ASSERT(g_bserrno == 0);
1120 : 24 : CU_ASSERT(g_blobid != SPDK_BLOBID_INVALID);
1121 : 24 : snapshotid = g_blobid;
1122 : :
1123 : 24 : CU_ASSERT(spdk_blob_is_thin_provisioned(blob) == true);
1124 : 24 : CU_ASSERT(spdk_blob_get_num_clusters(blob) == 10);
1125 : :
1126 : 24 : spdk_bs_open_blob(bs, snapshotid, blob_op_with_handle_complete, NULL);
1127 : 24 : poll_threads();
1128 : 24 : CU_ASSERT(g_bserrno == 0);
1129 [ - + ]: 24 : SPDK_CU_ASSERT_FATAL(g_blob != NULL);
1130 : 24 : snapshot = g_blob;
1131 [ - + ]: 24 : CU_ASSERT(snapshot->data_ro == true);
1132 [ - + ]: 24 : CU_ASSERT(snapshot->md_ro == true);
1133 : 24 : CU_ASSERT(spdk_blob_get_num_clusters(snapshot) == 10);
1134 : :
1135 : 24 : spdk_blob_close(snapshot, blob_op_complete, NULL);
1136 : 24 : poll_threads();
1137 : 24 : CU_ASSERT(g_bserrno == 0);
1138 : :
1139 : 24 : free_clusters = spdk_bs_free_cluster_count(bs);
1140 : :
1141 : : /* 2) Blob with parent */
1142 [ + + ]: 24 : if (!decouple_parent) {
1143 : : /* Do full blob inflation */
1144 : 12 : spdk_bs_inflate_blob(bs, channel, blobid, blob_op_complete, NULL);
1145 : 12 : poll_threads();
1146 : 12 : CU_ASSERT(g_bserrno == 0);
1147 : : /* all 10 clusters should be allocated */
1148 : 12 : CU_ASSERT(spdk_bs_free_cluster_count(bs) == free_clusters - 10);
1149 : 12 : CU_ASSERT(spdk_blob_get_num_allocated_clusters(blob) == 10);
1150 : : } else {
1151 : : /* Decouple parent of blob */
1152 : 12 : spdk_bs_blob_decouple_parent(bs, channel, blobid, blob_op_complete, NULL);
1153 : 12 : poll_threads();
1154 : 12 : CU_ASSERT(g_bserrno == 0);
1155 : : /* when only parent is removed, none of the clusters should be allocated */
1156 : 12 : CU_ASSERT(spdk_bs_free_cluster_count(bs) == free_clusters);
1157 : 12 : CU_ASSERT(spdk_blob_get_num_allocated_clusters(blob) == 0);
1158 : : }
1159 : :
1160 : : /* Now, it should be possible to delete snapshot */
1161 : 24 : spdk_bs_delete_blob(bs, snapshotid, blob_op_complete, NULL);
1162 : 24 : poll_threads();
1163 : 24 : CU_ASSERT(g_bserrno == 0);
1164 : :
1165 : 24 : CU_ASSERT(spdk_blob_get_num_clusters(blob) == 10);
1166 : 24 : CU_ASSERT(spdk_blob_is_thin_provisioned(blob) == decouple_parent);
1167 : :
1168 : 24 : spdk_bs_free_io_channel(channel);
1169 : 24 : poll_threads();
1170 : :
1171 : 24 : ut_blob_close_and_delete(bs, blob);
1172 : 24 : }
1173 : :
1174 : : static void
1175 : 12 : blob_inflate(void)
1176 : : {
1177 : 12 : _blob_inflate(false);
1178 : 12 : _blob_inflate(true);
1179 : 12 : }
1180 : :
1181 : : static void
1182 : 12 : blob_delete(void)
1183 : : {
1184 : 12 : struct spdk_blob_store *bs = g_bs;
1185 : 12 : struct spdk_blob_opts blob_opts;
1186 : : spdk_blob_id blobid;
1187 : :
1188 : : /* Create a blob and then delete it. */
1189 : 12 : ut_spdk_blob_opts_init(&blob_opts);
1190 : 12 : spdk_bs_create_blob_ext(bs, &blob_opts, blob_op_with_id_complete, NULL);
1191 : 12 : poll_threads();
1192 : 12 : CU_ASSERT(g_bserrno == 0);
1193 : 12 : CU_ASSERT(g_blobid > 0);
1194 : 12 : blobid = g_blobid;
1195 : :
1196 : 12 : spdk_bs_delete_blob(bs, blobid, blob_op_complete, NULL);
1197 : 12 : poll_threads();
1198 : 12 : CU_ASSERT(g_bserrno == 0);
1199 : :
1200 : : /* Try to open the blob */
1201 : 12 : spdk_bs_open_blob(bs, blobid, blob_op_with_handle_complete, NULL);
1202 : 12 : poll_threads();
1203 : 12 : CU_ASSERT(g_bserrno == -ENOENT);
1204 : 12 : }
1205 : :
1206 : : static void
1207 : 12 : blob_resize_test(void)
1208 : : {
1209 : 12 : struct spdk_blob_store *bs = g_bs;
1210 : : struct spdk_blob *blob;
1211 : : uint64_t free_clusters;
1212 : :
1213 : 12 : free_clusters = spdk_bs_free_cluster_count(bs);
1214 : :
1215 : 12 : blob = ut_blob_create_and_open(bs, NULL);
1216 : 12 : CU_ASSERT(free_clusters == spdk_bs_free_cluster_count(bs));
1217 : 12 : CU_ASSERT(spdk_blob_get_num_allocated_clusters(blob) == 0);
1218 : :
1219 : : /* Confirm that resize fails if blob is marked read-only. */
1220 : 12 : blob->md_ro = true;
1221 : 12 : spdk_blob_resize(blob, 5, blob_op_complete, NULL);
1222 : 12 : poll_threads();
1223 : 12 : CU_ASSERT(g_bserrno == -EPERM);
1224 : 12 : blob->md_ro = false;
1225 : :
1226 : : /* The blob started at 0 clusters. Resize it to be 5. */
1227 : 12 : spdk_blob_resize(blob, 5, blob_op_complete, NULL);
1228 : 12 : poll_threads();
1229 : 12 : CU_ASSERT(g_bserrno == 0);
1230 : 12 : CU_ASSERT((free_clusters - 5) == spdk_bs_free_cluster_count(bs));
1231 : 12 : CU_ASSERT(spdk_blob_get_num_allocated_clusters(blob) == 5);
1232 : :
1233 : : /* Shrink the blob to 3 clusters. This will not actually release
1234 : : * the old clusters until the blob is synced.
1235 : : */
1236 : 12 : spdk_blob_resize(blob, 3, blob_op_complete, NULL);
1237 : 12 : poll_threads();
1238 : 12 : CU_ASSERT(g_bserrno == 0);
1239 : : /* Verify there are still 5 clusters in use */
1240 : 12 : CU_ASSERT((free_clusters - 5) == spdk_bs_free_cluster_count(bs));
1241 : 12 : CU_ASSERT(spdk_blob_get_num_allocated_clusters(blob) == 3);
1242 : :
1243 : 12 : spdk_blob_sync_md(blob, blob_op_complete, NULL);
1244 : 12 : poll_threads();
1245 : 12 : CU_ASSERT(g_bserrno == 0);
1246 : : /* Now there are only 3 clusters in use */
1247 : 12 : CU_ASSERT((free_clusters - 3) == spdk_bs_free_cluster_count(bs));
1248 : :
1249 : : /* Resize the blob to be 10 clusters. Growth takes effect immediately. */
1250 : 12 : spdk_blob_resize(blob, 10, blob_op_complete, NULL);
1251 : 12 : poll_threads();
1252 : 12 : CU_ASSERT(g_bserrno == 0);
1253 : 12 : CU_ASSERT((free_clusters - 10) == spdk_bs_free_cluster_count(bs));
1254 : 12 : CU_ASSERT(spdk_blob_get_num_allocated_clusters(blob) == 10);
1255 : :
1256 : : /* Try to resize the blob to size larger than blobstore. */
1257 : 12 : spdk_blob_resize(blob, bs->total_clusters + 1, blob_op_complete, NULL);
1258 : 12 : poll_threads();
1259 : 12 : CU_ASSERT(g_bserrno == -ENOSPC);
1260 : :
1261 : 12 : ut_blob_close_and_delete(bs, blob);
1262 : 12 : }
1263 : :
1264 : : static void
1265 : 12 : blob_resize_thin_test(void)
1266 : : {
1267 : 12 : struct spdk_blob_store *bs = g_bs;
1268 : : struct spdk_blob *blob;
1269 : 12 : struct spdk_blob_opts opts;
1270 : : struct spdk_io_channel *blob_ch;
1271 : : uint64_t free_clusters;
1272 : : uint64_t io_units_per_cluster;
1273 : : uint64_t offset;
1274 : 12 : uint8_t buf1[DEV_BUFFER_BLOCKLEN];
1275 : :
1276 : 12 : free_clusters = spdk_bs_free_cluster_count(bs);
1277 : :
1278 : 12 : blob_ch = spdk_bs_alloc_io_channel(bs);
1279 [ - + ]: 12 : SPDK_CU_ASSERT_FATAL(blob_ch != NULL);
1280 : :
1281 : : /* Create blob with thin provisioning enabled */
1282 : 12 : ut_spdk_blob_opts_init(&opts);
1283 : 12 : opts.thin_provision = true;
1284 : 12 : opts.num_clusters = 0;
1285 : :
1286 : 12 : blob = ut_blob_create_and_open(bs, &opts);
1287 : 12 : CU_ASSERT((free_clusters) == spdk_bs_free_cluster_count(bs));
1288 : 12 : CU_ASSERT(spdk_blob_get_num_allocated_clusters(blob) == 0);
1289 : 12 : io_units_per_cluster = bs_io_units_per_cluster(blob);
1290 : :
1291 : : /* The blob started at 0 clusters. Resize it to be 6. */
1292 : 12 : spdk_blob_resize(blob, 6, blob_op_complete, NULL);
1293 : 12 : poll_threads();
1294 : 12 : CU_ASSERT(g_bserrno == 0);
1295 : 12 : CU_ASSERT((free_clusters) == spdk_bs_free_cluster_count(bs));
1296 : 12 : CU_ASSERT(spdk_blob_get_num_allocated_clusters(blob) == 0);
1297 : :
1298 : : /* Write on cluster 0,2,4 and 5 of blob */
1299 [ + + ]: 3084 : for (offset = 0; offset < io_units_per_cluster; offset++) {
1300 : 3072 : spdk_blob_io_write(blob, blob_ch, buf1, offset, 1, blob_op_complete, NULL);
1301 : 3072 : poll_threads();
1302 : 3072 : CU_ASSERT(g_bserrno == 0);
1303 : : }
1304 [ + + ]: 3084 : for (offset = 2 * io_units_per_cluster; offset < 3 * io_units_per_cluster; offset++) {
1305 : 3072 : spdk_blob_io_write(blob, blob_ch, buf1, offset, 1, blob_op_complete, NULL);
1306 : 3072 : poll_threads();
1307 : 3072 : CU_ASSERT(g_bserrno == 0);
1308 : : }
1309 [ + + ]: 3084 : for (offset = 4 * io_units_per_cluster; offset < 5 * io_units_per_cluster; offset++) {
1310 : 3072 : spdk_blob_io_write(blob, blob_ch, buf1, offset, 1, blob_op_complete, NULL);
1311 : 3072 : poll_threads();
1312 : 3072 : CU_ASSERT(g_bserrno == 0);
1313 : : }
1314 [ + + ]: 3084 : for (offset = 5 * io_units_per_cluster; offset < 6 * io_units_per_cluster; offset++) {
1315 : 3072 : spdk_blob_io_write(blob, blob_ch, buf1, offset, 1, blob_op_complete, NULL);
1316 : 3072 : poll_threads();
1317 : 3072 : CU_ASSERT(g_bserrno == 0);
1318 : : }
1319 : :
1320 : : /* Check allocated clusters after write */
1321 : 12 : CU_ASSERT((free_clusters - 4) == spdk_bs_free_cluster_count(bs));
1322 : 12 : CU_ASSERT(spdk_blob_get_num_allocated_clusters(blob) == 4);
1323 : :
1324 : : /* Shrink the blob to 2 clusters. This will not actually release
1325 : : * the old clusters until the blob is synced.
1326 : : */
1327 : 12 : spdk_blob_resize(blob, 2, blob_op_complete, NULL);
1328 : 12 : poll_threads();
1329 : 12 : CU_ASSERT(g_bserrno == 0);
1330 : 12 : CU_ASSERT(spdk_blob_get_num_clusters(blob) == 2);
1331 : 12 : CU_ASSERT((free_clusters - 4) == spdk_bs_free_cluster_count(bs));
1332 : 12 : CU_ASSERT(spdk_blob_get_num_allocated_clusters(blob) == 1);
1333 : :
1334 : : /* Sync blob: 4 clusters were truncated but only 3 of them was allocated */
1335 : 12 : spdk_blob_sync_md(blob, blob_op_complete, NULL);
1336 : 12 : poll_threads();
1337 : 12 : CU_ASSERT(g_bserrno == 0);
1338 : 12 : CU_ASSERT((free_clusters - 1) == spdk_bs_free_cluster_count(bs));
1339 : 12 : CU_ASSERT(spdk_blob_get_num_clusters(blob) == 2);
1340 : 12 : CU_ASSERT(spdk_blob_get_num_allocated_clusters(blob) == 1);
1341 : :
1342 : 12 : spdk_bs_free_io_channel(blob_ch);
1343 : 12 : ut_blob_close_and_delete(bs, blob);
1344 : 12 : }
1345 : :
1346 : : static void
1347 : 12 : blob_read_only(void)
1348 : : {
1349 : 12 : struct spdk_blob_store *bs;
1350 : : struct spdk_bs_dev *dev;
1351 : : struct spdk_blob *blob;
1352 : 12 : struct spdk_bs_opts opts;
1353 : : spdk_blob_id blobid;
1354 : : int rc;
1355 : :
1356 : 12 : dev = init_dev();
1357 : 12 : spdk_bs_opts_init(&opts, sizeof(opts));
1358 : 12 : snprintf(opts.bstype.bstype, sizeof(opts.bstype.bstype), "TESTTYPE");
1359 : :
1360 : 12 : spdk_bs_init(dev, &opts, bs_op_with_handle_complete, NULL);
1361 : 12 : poll_threads();
1362 : 12 : CU_ASSERT(g_bserrno == 0);
1363 [ - + ]: 12 : SPDK_CU_ASSERT_FATAL(g_bs != NULL);
1364 : 12 : bs = g_bs;
1365 : :
1366 : 12 : blob = ut_blob_create_and_open(bs, NULL);
1367 : 12 : blobid = spdk_blob_get_id(blob);
1368 : :
1369 : 12 : rc = spdk_blob_set_read_only(blob);
1370 : 12 : CU_ASSERT(rc == 0);
1371 : :
1372 [ - + ]: 12 : CU_ASSERT(blob->data_ro == false);
1373 [ - + ]: 12 : CU_ASSERT(blob->md_ro == false);
1374 : :
1375 : 12 : spdk_blob_sync_md(blob, bs_op_complete, NULL);
1376 : 12 : poll_threads();
1377 : :
1378 [ - + ]: 12 : CU_ASSERT(blob->data_ro == true);
1379 [ - + ]: 12 : CU_ASSERT(blob->md_ro == true);
1380 : 12 : CU_ASSERT(blob->data_ro_flags & SPDK_BLOB_READ_ONLY);
1381 : :
1382 : 12 : spdk_blob_close(blob, blob_op_complete, NULL);
1383 : 12 : poll_threads();
1384 : 12 : CU_ASSERT(g_bserrno == 0);
1385 : :
1386 : 12 : spdk_bs_open_blob(bs, blobid, blob_op_with_handle_complete, NULL);
1387 : 12 : poll_threads();
1388 : 12 : CU_ASSERT(g_bserrno == 0);
1389 [ - + ]: 12 : SPDK_CU_ASSERT_FATAL(g_blob != NULL);
1390 : 12 : blob = g_blob;
1391 : :
1392 [ - + ]: 12 : CU_ASSERT(blob->data_ro == true);
1393 [ - + ]: 12 : CU_ASSERT(blob->md_ro == true);
1394 : 12 : CU_ASSERT(blob->data_ro_flags & SPDK_BLOB_READ_ONLY);
1395 : :
1396 : 12 : spdk_blob_close(blob, blob_op_complete, NULL);
1397 : 12 : poll_threads();
1398 : 12 : CU_ASSERT(g_bserrno == 0);
1399 : :
1400 : 12 : ut_bs_reload(&bs, &opts);
1401 : :
1402 : 12 : spdk_bs_open_blob(bs, blobid, blob_op_with_handle_complete, NULL);
1403 : 12 : poll_threads();
1404 : 12 : CU_ASSERT(g_bserrno == 0);
1405 [ - + ]: 12 : SPDK_CU_ASSERT_FATAL(g_blob != NULL);
1406 : 12 : blob = g_blob;
1407 : :
1408 [ - + ]: 12 : CU_ASSERT(blob->data_ro == true);
1409 [ - + ]: 12 : CU_ASSERT(blob->md_ro == true);
1410 : 12 : CU_ASSERT(blob->data_ro_flags & SPDK_BLOB_READ_ONLY);
1411 : :
1412 : 12 : ut_blob_close_and_delete(bs, blob);
1413 : :
1414 : 12 : spdk_bs_unload(bs, bs_op_complete, NULL);
1415 : 12 : poll_threads();
1416 : 12 : CU_ASSERT(g_bserrno == 0);
1417 : 12 : }
1418 : :
1419 : : static void
1420 : 12 : channel_ops(void)
1421 : : {
1422 : 12 : struct spdk_blob_store *bs = g_bs;
1423 : : struct spdk_io_channel *channel;
1424 : :
1425 : 12 : channel = spdk_bs_alloc_io_channel(bs);
1426 : 12 : CU_ASSERT(channel != NULL);
1427 : :
1428 : 12 : spdk_bs_free_io_channel(channel);
1429 : 12 : poll_threads();
1430 : 12 : }
1431 : :
1432 : : static void
1433 : 12 : blob_write(void)
1434 : : {
1435 : 12 : struct spdk_blob_store *bs = g_bs;
1436 : 12 : struct spdk_blob *blob = g_blob;
1437 : : struct spdk_io_channel *channel;
1438 : : uint64_t pages_per_cluster;
1439 : 12 : uint8_t payload[10 * 4096];
1440 : :
1441 [ - + ]: 12 : pages_per_cluster = spdk_bs_get_cluster_size(bs) / spdk_bs_get_page_size(bs);
1442 : :
1443 : 12 : channel = spdk_bs_alloc_io_channel(bs);
1444 : 12 : CU_ASSERT(channel != NULL);
1445 : :
1446 : : /* Write to a blob with 0 size */
1447 : 12 : spdk_blob_io_write(blob, channel, payload, 0, 1, blob_op_complete, NULL);
1448 : 12 : poll_threads();
1449 : 12 : CU_ASSERT(g_bserrno == -EINVAL);
1450 : :
1451 : : /* Resize the blob */
1452 : 12 : spdk_blob_resize(blob, 5, blob_op_complete, NULL);
1453 : 12 : poll_threads();
1454 : 12 : CU_ASSERT(g_bserrno == 0);
1455 : :
1456 : : /* Confirm that write fails if blob is marked read-only. */
1457 : 12 : blob->data_ro = true;
1458 : 12 : spdk_blob_io_write(blob, channel, payload, 0, 1, blob_op_complete, NULL);
1459 : 12 : poll_threads();
1460 : 12 : CU_ASSERT(g_bserrno == -EPERM);
1461 : 12 : blob->data_ro = false;
1462 : :
1463 : : /* Write to the blob */
1464 : 12 : spdk_blob_io_write(blob, channel, payload, 0, 1, blob_op_complete, NULL);
1465 : 12 : poll_threads();
1466 : 12 : CU_ASSERT(g_bserrno == 0);
1467 : :
1468 : : /* Write starting beyond the end */
1469 : 12 : spdk_blob_io_write(blob, channel, payload, 5 * pages_per_cluster, 1, blob_op_complete,
1470 : : NULL);
1471 : 12 : poll_threads();
1472 : 12 : CU_ASSERT(g_bserrno == -EINVAL);
1473 : :
1474 : : /* Write starting at a valid location but going off the end */
1475 : 12 : spdk_blob_io_write(blob, channel, payload, 4 * pages_per_cluster, pages_per_cluster + 1,
1476 : : blob_op_complete, NULL);
1477 : 12 : poll_threads();
1478 : 12 : CU_ASSERT(g_bserrno == -EINVAL);
1479 : :
1480 : 12 : spdk_bs_free_io_channel(channel);
1481 : 12 : poll_threads();
1482 : 12 : }
1483 : :
1484 : : static void
1485 : 12 : blob_read(void)
1486 : : {
1487 : 12 : struct spdk_blob_store *bs = g_bs;
1488 : 12 : struct spdk_blob *blob = g_blob;
1489 : : struct spdk_io_channel *channel;
1490 : : uint64_t pages_per_cluster;
1491 : 12 : uint8_t payload[10 * 4096];
1492 : :
1493 [ - + ]: 12 : pages_per_cluster = spdk_bs_get_cluster_size(bs) / spdk_bs_get_page_size(bs);
1494 : :
1495 : 12 : channel = spdk_bs_alloc_io_channel(bs);
1496 : 12 : CU_ASSERT(channel != NULL);
1497 : :
1498 : : /* Read from a blob with 0 size */
1499 : 12 : spdk_blob_io_read(blob, channel, payload, 0, 1, blob_op_complete, NULL);
1500 : 12 : poll_threads();
1501 : 12 : CU_ASSERT(g_bserrno == -EINVAL);
1502 : :
1503 : : /* Resize the blob */
1504 : 12 : spdk_blob_resize(blob, 5, blob_op_complete, NULL);
1505 : 12 : poll_threads();
1506 : 12 : CU_ASSERT(g_bserrno == 0);
1507 : :
1508 : : /* Confirm that read passes if blob is marked read-only. */
1509 : 12 : blob->data_ro = true;
1510 : 12 : spdk_blob_io_read(blob, channel, payload, 0, 1, blob_op_complete, NULL);
1511 : 12 : poll_threads();
1512 : 12 : CU_ASSERT(g_bserrno == 0);
1513 : 12 : blob->data_ro = false;
1514 : :
1515 : : /* Read from the blob */
1516 : 12 : spdk_blob_io_read(blob, channel, payload, 0, 1, blob_op_complete, NULL);
1517 : 12 : poll_threads();
1518 : 12 : CU_ASSERT(g_bserrno == 0);
1519 : :
1520 : : /* Read starting beyond the end */
1521 : 12 : spdk_blob_io_read(blob, channel, payload, 5 * pages_per_cluster, 1, blob_op_complete,
1522 : : NULL);
1523 : 12 : poll_threads();
1524 : 12 : CU_ASSERT(g_bserrno == -EINVAL);
1525 : :
1526 : : /* Read starting at a valid location but going off the end */
1527 : 12 : spdk_blob_io_read(blob, channel, payload, 4 * pages_per_cluster, pages_per_cluster + 1,
1528 : : blob_op_complete, NULL);
1529 : 12 : poll_threads();
1530 : 12 : CU_ASSERT(g_bserrno == -EINVAL);
1531 : :
1532 : 12 : spdk_bs_free_io_channel(channel);
1533 : 12 : poll_threads();
1534 : 12 : }
1535 : :
1536 : : static void
1537 : 12 : blob_rw_verify(void)
1538 : : {
1539 : 12 : struct spdk_blob_store *bs = g_bs;
1540 : 12 : struct spdk_blob *blob = g_blob;
1541 : : struct spdk_io_channel *channel;
1542 : 12 : uint8_t payload_read[10 * 4096];
1543 : 12 : uint8_t payload_write[10 * 4096];
1544 : :
1545 : 12 : channel = spdk_bs_alloc_io_channel(bs);
1546 : 12 : CU_ASSERT(channel != NULL);
1547 : :
1548 : 12 : spdk_blob_resize(blob, 32, blob_op_complete, NULL);
1549 : 12 : poll_threads();
1550 : 12 : CU_ASSERT(g_bserrno == 0);
1551 : :
1552 : 12 : memset(payload_write, 0xE5, sizeof(payload_write));
1553 : 12 : spdk_blob_io_write(blob, channel, payload_write, 4, 10, blob_op_complete, NULL);
1554 : 12 : poll_threads();
1555 : 12 : CU_ASSERT(g_bserrno == 0);
1556 : :
1557 : 12 : memset(payload_read, 0x00, sizeof(payload_read));
1558 : 12 : spdk_blob_io_read(blob, channel, payload_read, 4, 10, blob_op_complete, NULL);
1559 : 12 : poll_threads();
1560 : 12 : CU_ASSERT(g_bserrno == 0);
1561 : 12 : CU_ASSERT(memcmp(payload_write, payload_read, 4 * 4096) == 0);
1562 : :
1563 : 12 : spdk_bs_free_io_channel(channel);
1564 : 12 : poll_threads();
1565 : 12 : }
1566 : :
1567 : : static void
1568 : 12 : blob_rw_verify_iov(void)
1569 : : {
1570 : 12 : struct spdk_blob_store *bs = g_bs;
1571 : : struct spdk_blob *blob;
1572 : : struct spdk_io_channel *channel;
1573 : 12 : uint8_t payload_read[10 * 4096];
1574 : 12 : uint8_t payload_write[10 * 4096];
1575 : 12 : struct iovec iov_read[3];
1576 : 12 : struct iovec iov_write[3];
1577 : : void *buf;
1578 : :
1579 : 12 : channel = spdk_bs_alloc_io_channel(bs);
1580 : 12 : CU_ASSERT(channel != NULL);
1581 : :
1582 : 12 : blob = ut_blob_create_and_open(bs, NULL);
1583 : :
1584 : 12 : spdk_blob_resize(blob, 2, blob_op_complete, NULL);
1585 : 12 : poll_threads();
1586 : 12 : CU_ASSERT(g_bserrno == 0);
1587 : :
1588 : : /*
1589 : : * Manually adjust the offset of the blob's second cluster. This allows
1590 : : * us to make sure that the readv/write code correctly accounts for I/O
1591 : : * that cross cluster boundaries. Start by asserting that the allocated
1592 : : * clusters are where we expect before modifying the second cluster.
1593 : : */
1594 : 12 : CU_ASSERT(blob->active.clusters[0] == 1 * 256);
1595 : 12 : CU_ASSERT(blob->active.clusters[1] == 2 * 256);
1596 : 12 : blob->active.clusters[1] = 3 * 256;
1597 : :
1598 : 12 : memset(payload_write, 0xE5, sizeof(payload_write));
1599 : 12 : iov_write[0].iov_base = payload_write;
1600 : 12 : iov_write[0].iov_len = 1 * 4096;
1601 : 12 : iov_write[1].iov_base = payload_write + 1 * 4096;
1602 : 12 : iov_write[1].iov_len = 5 * 4096;
1603 : 12 : iov_write[2].iov_base = payload_write + 6 * 4096;
1604 : 12 : iov_write[2].iov_len = 4 * 4096;
1605 : : /*
1606 : : * Choose a page offset just before the cluster boundary. The first 6 pages of payload
1607 : : * will get written to the first cluster, the last 4 to the second cluster.
1608 : : */
1609 : 12 : spdk_blob_io_writev(blob, channel, iov_write, 3, 250, 10, blob_op_complete, NULL);
1610 : 12 : poll_threads();
1611 : 12 : CU_ASSERT(g_bserrno == 0);
1612 : :
1613 : 12 : memset(payload_read, 0xAA, sizeof(payload_read));
1614 : 12 : iov_read[0].iov_base = payload_read;
1615 : 12 : iov_read[0].iov_len = 3 * 4096;
1616 : 12 : iov_read[1].iov_base = payload_read + 3 * 4096;
1617 : 12 : iov_read[1].iov_len = 4 * 4096;
1618 : 12 : iov_read[2].iov_base = payload_read + 7 * 4096;
1619 : 12 : iov_read[2].iov_len = 3 * 4096;
1620 : 12 : spdk_blob_io_readv(blob, channel, iov_read, 3, 250, 10, blob_op_complete, NULL);
1621 : 12 : poll_threads();
1622 : 12 : CU_ASSERT(g_bserrno == 0);
1623 : 12 : CU_ASSERT(memcmp(payload_write, payload_read, 10 * 4096) == 0);
1624 : :
1625 : 12 : buf = calloc(1, 256 * 4096);
1626 [ - + ]: 12 : SPDK_CU_ASSERT_FATAL(buf != NULL);
1627 : : /* Check that cluster 2 on "disk" was not modified. */
1628 [ - + - + ]: 12 : CU_ASSERT(memcmp(buf, &g_dev_buffer[512 * 4096], 256 * 4096) == 0);
1629 : 12 : free(buf);
1630 : :
1631 : 12 : spdk_blob_close(blob, blob_op_complete, NULL);
1632 : 12 : poll_threads();
1633 : 12 : CU_ASSERT(g_bserrno == 0);
1634 : :
1635 : 12 : spdk_bs_free_io_channel(channel);
1636 : 12 : poll_threads();
1637 : 12 : }
1638 : :
1639 : : static uint32_t
1640 : 24 : bs_channel_get_req_count(struct spdk_io_channel *_channel)
1641 : : {
1642 : 24 : struct spdk_bs_channel *channel = spdk_io_channel_get_ctx(_channel);
1643 : : struct spdk_bs_request_set *set;
1644 : 24 : uint32_t count = 0;
1645 : :
1646 [ + + ]: 12312 : TAILQ_FOREACH(set, &channel->reqs, link) {
1647 : 12288 : count++;
1648 : : }
1649 : :
1650 : 24 : return count;
1651 : : }
1652 : :
1653 : : static void
1654 : 12 : blob_rw_verify_iov_nomem(void)
1655 : : {
1656 : 12 : struct spdk_blob_store *bs = g_bs;
1657 : 12 : struct spdk_blob *blob = g_blob;
1658 : : struct spdk_io_channel *channel;
1659 : 12 : uint8_t payload_write[10 * 4096];
1660 : 12 : struct iovec iov_write[3];
1661 : : uint32_t req_count;
1662 : :
1663 : 12 : channel = spdk_bs_alloc_io_channel(bs);
1664 : 12 : CU_ASSERT(channel != NULL);
1665 : :
1666 : 12 : spdk_blob_resize(blob, 2, blob_op_complete, NULL);
1667 : 12 : poll_threads();
1668 : 12 : CU_ASSERT(g_bserrno == 0);
1669 : :
1670 : : /*
1671 : : * Choose a page offset just before the cluster boundary. The first 6 pages of payload
1672 : : * will get written to the first cluster, the last 4 to the second cluster.
1673 : : */
1674 : 12 : iov_write[0].iov_base = payload_write;
1675 : 12 : iov_write[0].iov_len = 1 * 4096;
1676 : 12 : iov_write[1].iov_base = payload_write + 1 * 4096;
1677 : 12 : iov_write[1].iov_len = 5 * 4096;
1678 : 12 : iov_write[2].iov_base = payload_write + 6 * 4096;
1679 : 12 : iov_write[2].iov_len = 4 * 4096;
1680 : 12 : MOCK_SET(calloc, NULL);
1681 : 12 : req_count = bs_channel_get_req_count(channel);
1682 : 12 : spdk_blob_io_writev(blob, channel, iov_write, 3, 250, 10, blob_op_complete, NULL);
1683 : 12 : poll_threads();
1684 : 12 : CU_ASSERT(g_bserrno = -ENOMEM);
1685 : 12 : CU_ASSERT(req_count == bs_channel_get_req_count(channel));
1686 [ - - - + ]: 12 : MOCK_CLEAR(calloc);
1687 : :
1688 : 12 : spdk_bs_free_io_channel(channel);
1689 : 12 : poll_threads();
1690 : 12 : }
1691 : :
1692 : : static void
1693 : 12 : blob_rw_iov_read_only(void)
1694 : : {
1695 : 12 : struct spdk_blob_store *bs = g_bs;
1696 : 12 : struct spdk_blob *blob = g_blob;
1697 : : struct spdk_io_channel *channel;
1698 : 12 : uint8_t payload_read[4096];
1699 : 12 : uint8_t payload_write[4096];
1700 : 12 : struct iovec iov_read;
1701 : 12 : struct iovec iov_write;
1702 : :
1703 : 12 : channel = spdk_bs_alloc_io_channel(bs);
1704 : 12 : CU_ASSERT(channel != NULL);
1705 : :
1706 : 12 : spdk_blob_resize(blob, 2, blob_op_complete, NULL);
1707 : 12 : poll_threads();
1708 : 12 : CU_ASSERT(g_bserrno == 0);
1709 : :
1710 : : /* Verify that writev failed if read_only flag is set. */
1711 : 12 : blob->data_ro = true;
1712 : 12 : iov_write.iov_base = payload_write;
1713 : 12 : iov_write.iov_len = sizeof(payload_write);
1714 : 12 : spdk_blob_io_writev(blob, channel, &iov_write, 1, 0, 1, blob_op_complete, NULL);
1715 : 12 : poll_threads();
1716 : 12 : CU_ASSERT(g_bserrno == -EPERM);
1717 : :
1718 : : /* Verify that reads pass if data_ro flag is set. */
1719 : 12 : iov_read.iov_base = payload_read;
1720 : 12 : iov_read.iov_len = sizeof(payload_read);
1721 : 12 : spdk_blob_io_readv(blob, channel, &iov_read, 1, 0, 1, blob_op_complete, NULL);
1722 : 12 : poll_threads();
1723 : 12 : CU_ASSERT(g_bserrno == 0);
1724 : :
1725 : 12 : spdk_bs_free_io_channel(channel);
1726 : 12 : poll_threads();
1727 : 12 : }
1728 : :
1729 : : static void
1730 : 24 : _blob_io_read_no_split(struct spdk_blob *blob, struct spdk_io_channel *channel,
1731 : : uint8_t *payload, uint64_t offset, uint64_t length,
1732 : : spdk_blob_op_complete cb_fn, void *cb_arg)
1733 : : {
1734 : : uint64_t i;
1735 : : uint8_t *buf;
1736 : 24 : uint64_t page_size = spdk_bs_get_page_size(blob->bs);
1737 : :
1738 : : /* To be sure that operation is NOT split, read one page at the time */
1739 : 24 : buf = payload;
1740 [ + + ]: 30744 : for (i = 0; i < length; i++) {
1741 : 30720 : spdk_blob_io_read(blob, channel, buf, i + offset, 1, blob_op_complete, NULL);
1742 : 30720 : poll_threads();
1743 [ - + ]: 30720 : if (g_bserrno != 0) {
1744 : : /* Pass the error code up */
1745 : 0 : break;
1746 : : }
1747 : 30720 : buf += page_size;
1748 : : }
1749 : :
1750 : 24 : cb_fn(cb_arg, g_bserrno);
1751 : 24 : }
1752 : :
1753 : : static void
1754 : 24 : _blob_io_write_no_split(struct spdk_blob *blob, struct spdk_io_channel *channel,
1755 : : uint8_t *payload, uint64_t offset, uint64_t length,
1756 : : spdk_blob_op_complete cb_fn, void *cb_arg)
1757 : : {
1758 : : uint64_t i;
1759 : : uint8_t *buf;
1760 : 24 : uint64_t page_size = spdk_bs_get_page_size(blob->bs);
1761 : :
1762 : : /* To be sure that operation is NOT split, write one page at the time */
1763 : 24 : buf = payload;
1764 [ + + ]: 30744 : for (i = 0; i < length; i++) {
1765 : 30720 : spdk_blob_io_write(blob, channel, buf, i + offset, 1, blob_op_complete, NULL);
1766 : 30720 : poll_threads();
1767 [ - + ]: 30720 : if (g_bserrno != 0) {
1768 : : /* Pass the error code up */
1769 : 0 : break;
1770 : : }
1771 : 30720 : buf += page_size;
1772 : : }
1773 : :
1774 : 24 : cb_fn(cb_arg, g_bserrno);
1775 : 24 : }
1776 : :
1777 : : static void
1778 : 12 : blob_operation_split_rw(void)
1779 : : {
1780 : 12 : struct spdk_blob_store *bs = g_bs;
1781 : : struct spdk_blob *blob;
1782 : : struct spdk_io_channel *channel;
1783 : 12 : struct spdk_blob_opts opts;
1784 : : uint64_t cluster_size;
1785 : :
1786 : : uint64_t payload_size;
1787 : : uint8_t *payload_read;
1788 : : uint8_t *payload_write;
1789 : : uint8_t *payload_pattern;
1790 : :
1791 : : uint64_t page_size;
1792 : : uint64_t pages_per_cluster;
1793 : : uint64_t pages_per_payload;
1794 : :
1795 : : uint64_t i;
1796 : :
1797 : 12 : cluster_size = spdk_bs_get_cluster_size(bs);
1798 : 12 : page_size = spdk_bs_get_page_size(bs);
1799 [ - + ]: 12 : pages_per_cluster = cluster_size / page_size;
1800 : 12 : pages_per_payload = pages_per_cluster * 5;
1801 : 12 : payload_size = cluster_size * 5;
1802 : :
1803 : 12 : payload_read = malloc(payload_size);
1804 [ - + ]: 12 : SPDK_CU_ASSERT_FATAL(payload_read != NULL);
1805 : :
1806 : 12 : payload_write = malloc(payload_size);
1807 [ - + ]: 12 : SPDK_CU_ASSERT_FATAL(payload_write != NULL);
1808 : :
1809 : 12 : payload_pattern = malloc(payload_size);
1810 [ - + ]: 12 : SPDK_CU_ASSERT_FATAL(payload_pattern != NULL);
1811 : :
1812 : : /* Prepare random pattern to write */
1813 [ - + ]: 12 : memset(payload_pattern, 0xFF, payload_size);
1814 [ + + ]: 15372 : for (i = 0; i < pages_per_payload; i++) {
1815 : 15360 : *((uint64_t *)(payload_pattern + page_size * i)) = (i + 1);
1816 : : }
1817 : :
1818 : 12 : channel = spdk_bs_alloc_io_channel(bs);
1819 [ - + ]: 12 : SPDK_CU_ASSERT_FATAL(channel != NULL);
1820 : :
1821 : : /* Create blob */
1822 : 12 : ut_spdk_blob_opts_init(&opts);
1823 : 12 : opts.thin_provision = false;
1824 : 12 : opts.num_clusters = 5;
1825 : :
1826 : 12 : blob = ut_blob_create_and_open(bs, &opts);
1827 : 12 : CU_ASSERT(spdk_blob_get_num_clusters(blob) == 5);
1828 : :
1829 : : /* Initial read should return zeroed payload */
1830 [ - + ]: 12 : memset(payload_read, 0xFF, payload_size);
1831 : 12 : spdk_blob_io_read(blob, channel, payload_read, 0, pages_per_payload, blob_op_complete, NULL);
1832 : 12 : poll_threads();
1833 : 12 : CU_ASSERT(g_bserrno == 0);
1834 : 12 : CU_ASSERT(spdk_mem_all_zero(payload_read, payload_size));
1835 : :
1836 : : /* Fill whole blob except last page */
1837 : 12 : spdk_blob_io_write(blob, channel, payload_pattern, 0, pages_per_payload - 1,
1838 : : blob_op_complete, NULL);
1839 : 12 : poll_threads();
1840 : 12 : CU_ASSERT(g_bserrno == 0);
1841 : :
1842 : : /* Write last page with a pattern */
1843 : 12 : spdk_blob_io_write(blob, channel, payload_pattern, pages_per_payload - 1, 1,
1844 : : blob_op_complete, NULL);
1845 : 12 : poll_threads();
1846 : 12 : CU_ASSERT(g_bserrno == 0);
1847 : :
1848 : : /* Read whole blob and check consistency */
1849 [ - + ]: 12 : memset(payload_read, 0xFF, payload_size);
1850 : 12 : spdk_blob_io_read(blob, channel, payload_read, 0, pages_per_payload, blob_op_complete, NULL);
1851 : 12 : poll_threads();
1852 : 12 : CU_ASSERT(g_bserrno == 0);
1853 [ - + - + ]: 12 : CU_ASSERT(memcmp(payload_pattern, payload_read, payload_size - page_size) == 0);
1854 [ - + - + ]: 12 : CU_ASSERT(memcmp(payload_pattern, payload_read + payload_size - page_size, page_size) == 0);
1855 : :
1856 : : /* Fill whole blob except first page */
1857 : 12 : spdk_blob_io_write(blob, channel, payload_pattern, 1, pages_per_payload - 1,
1858 : : blob_op_complete, NULL);
1859 : 12 : poll_threads();
1860 : 12 : CU_ASSERT(g_bserrno == 0);
1861 : :
1862 : : /* Write first page with a pattern */
1863 : 12 : spdk_blob_io_write(blob, channel, payload_pattern, 0, 1,
1864 : : blob_op_complete, NULL);
1865 : 12 : poll_threads();
1866 : 12 : CU_ASSERT(g_bserrno == 0);
1867 : :
1868 : : /* Read whole blob and check consistency */
1869 [ - + ]: 12 : memset(payload_read, 0xFF, payload_size);
1870 : 12 : spdk_blob_io_read(blob, channel, payload_read, 0, pages_per_payload, blob_op_complete, NULL);
1871 : 12 : poll_threads();
1872 : 12 : CU_ASSERT(g_bserrno == 0);
1873 [ - + - + ]: 12 : CU_ASSERT(memcmp(payload_pattern, payload_read + page_size, payload_size - page_size) == 0);
1874 [ - + - + ]: 12 : CU_ASSERT(memcmp(payload_pattern, payload_read, page_size) == 0);
1875 : :
1876 : :
1877 : : /* Fill whole blob with a pattern (5 clusters) */
1878 : :
1879 : : /* 1. Read test. */
1880 : 12 : _blob_io_write_no_split(blob, channel, payload_pattern, 0, pages_per_payload,
1881 : : blob_op_complete, NULL);
1882 : 12 : poll_threads();
1883 : 12 : CU_ASSERT(g_bserrno == 0);
1884 : :
1885 [ - + ]: 12 : memset(payload_read, 0xFF, payload_size);
1886 : 12 : spdk_blob_io_read(blob, channel, payload_read, 0, pages_per_payload, blob_op_complete, NULL);
1887 : 12 : poll_threads();
1888 : 12 : poll_threads();
1889 : 12 : CU_ASSERT(g_bserrno == 0);
1890 [ - + - + ]: 12 : CU_ASSERT(memcmp(payload_pattern, payload_read, payload_size) == 0);
1891 : :
1892 : : /* 2. Write test. */
1893 : 12 : spdk_blob_io_write(blob, channel, payload_pattern, 0, pages_per_payload,
1894 : : blob_op_complete, NULL);
1895 : 12 : poll_threads();
1896 : 12 : CU_ASSERT(g_bserrno == 0);
1897 : :
1898 [ - + ]: 12 : memset(payload_read, 0xFF, payload_size);
1899 : 12 : _blob_io_read_no_split(blob, channel, payload_read, 0, pages_per_payload, blob_op_complete, NULL);
1900 : 12 : poll_threads();
1901 : 12 : CU_ASSERT(g_bserrno == 0);
1902 [ - + - + ]: 12 : CU_ASSERT(memcmp(payload_pattern, payload_read, payload_size) == 0);
1903 : :
1904 : 12 : spdk_bs_free_io_channel(channel);
1905 : 12 : poll_threads();
1906 : :
1907 : 12 : g_blob = NULL;
1908 : 12 : g_blobid = 0;
1909 : :
1910 : 12 : free(payload_read);
1911 : 12 : free(payload_write);
1912 : 12 : free(payload_pattern);
1913 : :
1914 : 12 : ut_blob_close_and_delete(bs, blob);
1915 : 12 : }
1916 : :
1917 : : static void
1918 : 12 : blob_operation_split_rw_iov(void)
1919 : : {
1920 : 12 : struct spdk_blob_store *bs = g_bs;
1921 : : struct spdk_blob *blob;
1922 : : struct spdk_io_channel *channel;
1923 : 12 : struct spdk_blob_opts opts;
1924 : : uint64_t cluster_size;
1925 : :
1926 : : uint64_t payload_size;
1927 : : uint8_t *payload_read;
1928 : : uint8_t *payload_write;
1929 : : uint8_t *payload_pattern;
1930 : :
1931 : : uint64_t page_size;
1932 : : uint64_t pages_per_cluster;
1933 : : uint64_t pages_per_payload;
1934 : :
1935 : 12 : struct iovec iov_read[2];
1936 : 12 : struct iovec iov_write[2];
1937 : :
1938 : : uint64_t i, j;
1939 : :
1940 : 12 : cluster_size = spdk_bs_get_cluster_size(bs);
1941 : 12 : page_size = spdk_bs_get_page_size(bs);
1942 [ - + ]: 12 : pages_per_cluster = cluster_size / page_size;
1943 : 12 : pages_per_payload = pages_per_cluster * 5;
1944 : 12 : payload_size = cluster_size * 5;
1945 : :
1946 : 12 : payload_read = malloc(payload_size);
1947 [ - + ]: 12 : SPDK_CU_ASSERT_FATAL(payload_read != NULL);
1948 : :
1949 : 12 : payload_write = malloc(payload_size);
1950 [ - + ]: 12 : SPDK_CU_ASSERT_FATAL(payload_write != NULL);
1951 : :
1952 : 12 : payload_pattern = malloc(payload_size);
1953 [ - + ]: 12 : SPDK_CU_ASSERT_FATAL(payload_pattern != NULL);
1954 : :
1955 : : /* Prepare random pattern to write */
1956 [ + + ]: 15372 : for (i = 0; i < pages_per_payload; i++) {
1957 [ + + ]: 7879680 : for (j = 0; j < page_size / sizeof(uint64_t); j++) {
1958 : : uint64_t *tmp;
1959 : :
1960 : 7864320 : tmp = (uint64_t *)payload_pattern;
1961 : 7864320 : tmp += ((page_size * i) / sizeof(uint64_t)) + j;
1962 : 7864320 : *tmp = i + 1;
1963 : : }
1964 : : }
1965 : :
1966 : 12 : channel = spdk_bs_alloc_io_channel(bs);
1967 [ - + ]: 12 : SPDK_CU_ASSERT_FATAL(channel != NULL);
1968 : :
1969 : : /* Create blob */
1970 : 12 : ut_spdk_blob_opts_init(&opts);
1971 : 12 : opts.thin_provision = false;
1972 : 12 : opts.num_clusters = 5;
1973 : :
1974 : 12 : blob = ut_blob_create_and_open(bs, &opts);
1975 : 12 : CU_ASSERT(spdk_blob_get_num_clusters(blob) == 5);
1976 : :
1977 : : /* Initial read should return zeroes payload */
1978 [ - + ]: 12 : memset(payload_read, 0xFF, payload_size);
1979 : 12 : iov_read[0].iov_base = payload_read;
1980 : 12 : iov_read[0].iov_len = cluster_size * 3;
1981 : 12 : iov_read[1].iov_base = payload_read + cluster_size * 3;
1982 : 12 : iov_read[1].iov_len = cluster_size * 2;
1983 : 12 : spdk_blob_io_readv(blob, channel, iov_read, 2, 0, pages_per_payload, blob_op_complete, NULL);
1984 : 12 : poll_threads();
1985 : 12 : CU_ASSERT(g_bserrno == 0);
1986 : 12 : CU_ASSERT(spdk_mem_all_zero(payload_read, payload_size));
1987 : :
1988 : : /* First of iovs fills whole blob except last page and second of iovs writes last page
1989 : : * with a pattern. */
1990 : 12 : iov_write[0].iov_base = payload_pattern;
1991 : 12 : iov_write[0].iov_len = payload_size - page_size;
1992 : 12 : iov_write[1].iov_base = payload_pattern;
1993 : 12 : iov_write[1].iov_len = page_size;
1994 : 12 : spdk_blob_io_writev(blob, channel, iov_write, 2, 0, pages_per_payload, blob_op_complete, NULL);
1995 : 12 : poll_threads();
1996 : 12 : CU_ASSERT(g_bserrno == 0);
1997 : :
1998 : : /* Read whole blob and check consistency */
1999 [ - + ]: 12 : memset(payload_read, 0xFF, payload_size);
2000 : 12 : iov_read[0].iov_base = payload_read;
2001 : 12 : iov_read[0].iov_len = cluster_size * 2;
2002 : 12 : iov_read[1].iov_base = payload_read + cluster_size * 2;
2003 : 12 : iov_read[1].iov_len = cluster_size * 3;
2004 : 12 : spdk_blob_io_readv(blob, channel, iov_read, 2, 0, pages_per_payload, blob_op_complete, NULL);
2005 : 12 : poll_threads();
2006 : 12 : CU_ASSERT(g_bserrno == 0);
2007 [ - + - + ]: 12 : CU_ASSERT(memcmp(payload_pattern, payload_read, payload_size - page_size) == 0);
2008 [ - + - + ]: 12 : CU_ASSERT(memcmp(payload_pattern, payload_read + payload_size - page_size, page_size) == 0);
2009 : :
2010 : : /* First of iovs fills only first page and second of iovs writes whole blob except
2011 : : * first page with a pattern. */
2012 : 12 : iov_write[0].iov_base = payload_pattern;
2013 : 12 : iov_write[0].iov_len = page_size;
2014 : 12 : iov_write[1].iov_base = payload_pattern;
2015 : 12 : iov_write[1].iov_len = payload_size - page_size;
2016 : 12 : spdk_blob_io_writev(blob, channel, iov_write, 2, 0, pages_per_payload, blob_op_complete, NULL);
2017 : 12 : poll_threads();
2018 : 12 : CU_ASSERT(g_bserrno == 0);
2019 : :
2020 : : /* Read whole blob and check consistency */
2021 [ - + ]: 12 : memset(payload_read, 0xFF, payload_size);
2022 : 12 : iov_read[0].iov_base = payload_read;
2023 : 12 : iov_read[0].iov_len = cluster_size * 4;
2024 : 12 : iov_read[1].iov_base = payload_read + cluster_size * 4;
2025 : 12 : iov_read[1].iov_len = cluster_size;
2026 : 12 : spdk_blob_io_readv(blob, channel, iov_read, 2, 0, pages_per_payload, blob_op_complete, NULL);
2027 : 12 : poll_threads();
2028 : 12 : CU_ASSERT(g_bserrno == 0);
2029 [ - + - + ]: 12 : CU_ASSERT(memcmp(payload_pattern, payload_read + page_size, payload_size - page_size) == 0);
2030 [ - + - + ]: 12 : CU_ASSERT(memcmp(payload_pattern, payload_read, page_size) == 0);
2031 : :
2032 : :
2033 : : /* Fill whole blob with a pattern (5 clusters) */
2034 : :
2035 : : /* 1. Read test. */
2036 : 12 : _blob_io_write_no_split(blob, channel, payload_pattern, 0, pages_per_payload,
2037 : : blob_op_complete, NULL);
2038 : 12 : poll_threads();
2039 : 12 : CU_ASSERT(g_bserrno == 0);
2040 : :
2041 [ - + ]: 12 : memset(payload_read, 0xFF, payload_size);
2042 : 12 : iov_read[0].iov_base = payload_read;
2043 : 12 : iov_read[0].iov_len = cluster_size;
2044 : 12 : iov_read[1].iov_base = payload_read + cluster_size;
2045 : 12 : iov_read[1].iov_len = cluster_size * 4;
2046 : 12 : spdk_blob_io_readv(blob, channel, iov_read, 2, 0, pages_per_payload, blob_op_complete, NULL);
2047 : 12 : poll_threads();
2048 : 12 : CU_ASSERT(g_bserrno == 0);
2049 [ - + - + ]: 12 : CU_ASSERT(memcmp(payload_pattern, payload_read, payload_size) == 0);
2050 : :
2051 : : /* 2. Write test. */
2052 : 12 : iov_write[0].iov_base = payload_read;
2053 : 12 : iov_write[0].iov_len = cluster_size * 2;
2054 : 12 : iov_write[1].iov_base = payload_read + cluster_size * 2;
2055 : 12 : iov_write[1].iov_len = cluster_size * 3;
2056 : 12 : spdk_blob_io_writev(blob, channel, iov_write, 2, 0, pages_per_payload, blob_op_complete, NULL);
2057 : 12 : poll_threads();
2058 : 12 : CU_ASSERT(g_bserrno == 0);
2059 : :
2060 [ - + ]: 12 : memset(payload_read, 0xFF, payload_size);
2061 : 12 : _blob_io_read_no_split(blob, channel, payload_read, 0, pages_per_payload, blob_op_complete, NULL);
2062 : 12 : poll_threads();
2063 : 12 : CU_ASSERT(g_bserrno == 0);
2064 [ - + - + ]: 12 : CU_ASSERT(memcmp(payload_pattern, payload_read, payload_size) == 0);
2065 : :
2066 : 12 : spdk_bs_free_io_channel(channel);
2067 : 12 : poll_threads();
2068 : :
2069 : 12 : g_blob = NULL;
2070 : 12 : g_blobid = 0;
2071 : :
2072 : 12 : free(payload_read);
2073 : 12 : free(payload_write);
2074 : 12 : free(payload_pattern);
2075 : :
2076 : 12 : ut_blob_close_and_delete(bs, blob);
2077 : 12 : }
2078 : :
2079 : : static void
2080 : 12 : blob_unmap(void)
2081 : : {
2082 : 12 : struct spdk_blob_store *bs = g_bs;
2083 : : struct spdk_blob *blob;
2084 : : struct spdk_io_channel *channel;
2085 : 12 : struct spdk_blob_opts opts;
2086 : 12 : uint8_t payload[4096];
2087 : : int i;
2088 : :
2089 : 12 : channel = spdk_bs_alloc_io_channel(bs);
2090 : 12 : CU_ASSERT(channel != NULL);
2091 : :
2092 : 12 : ut_spdk_blob_opts_init(&opts);
2093 : 12 : opts.num_clusters = 10;
2094 : :
2095 : 12 : blob = ut_blob_create_and_open(bs, &opts);
2096 : :
2097 : 12 : spdk_blob_resize(blob, 10, blob_op_complete, NULL);
2098 : 12 : poll_threads();
2099 : 12 : CU_ASSERT(g_bserrno == 0);
2100 : 12 : CU_ASSERT(spdk_blob_get_num_allocated_clusters(blob) == 10);
2101 : :
2102 [ - + ]: 12 : memset(payload, 0, sizeof(payload));
2103 : 12 : payload[0] = 0xFF;
2104 : :
2105 : : /*
2106 : : * Set first byte of every cluster to 0xFF.
2107 : : * First cluster on device is reserved so let's start from cluster number 1
2108 : : */
2109 [ + + ]: 132 : for (i = 1; i < 11; i++) {
2110 : 120 : g_dev_buffer[i * SPDK_BLOB_OPTS_CLUSTER_SZ] = 0xFF;
2111 : : }
2112 : :
2113 : : /* Confirm writes */
2114 [ + + ]: 132 : for (i = 0; i < 10; i++) {
2115 : 120 : payload[0] = 0;
2116 : 120 : spdk_blob_io_read(blob, channel, &payload, i * SPDK_BLOB_OPTS_CLUSTER_SZ / 4096, 1,
2117 : : blob_op_complete, NULL);
2118 : 120 : poll_threads();
2119 : 120 : CU_ASSERT(g_bserrno == 0);
2120 : 120 : CU_ASSERT(payload[0] == 0xFF);
2121 : : }
2122 : :
2123 : : /* Mark some clusters as unallocated */
2124 : 12 : blob->active.clusters[1] = 0;
2125 : 12 : blob->active.clusters[2] = 0;
2126 : 12 : blob->active.clusters[3] = 0;
2127 : 12 : blob->active.clusters[6] = 0;
2128 : 12 : blob->active.clusters[8] = 0;
2129 : 12 : blob->active.num_allocated_clusters -= 5;
2130 : :
2131 : : /* Unmap clusters by resizing to 0 */
2132 : 12 : spdk_blob_resize(blob, 0, blob_op_complete, NULL);
2133 : 12 : poll_threads();
2134 : 12 : CU_ASSERT(g_bserrno == 0);
2135 : :
2136 : 12 : spdk_blob_sync_md(blob, blob_op_complete, NULL);
2137 : 12 : poll_threads();
2138 : 12 : CU_ASSERT(g_bserrno == 0);
2139 : 12 : CU_ASSERT(spdk_blob_get_num_allocated_clusters(blob) == 0);
2140 : :
2141 : : /* Confirm that only 'allocated' clusters were unmapped */
2142 [ + + ]: 132 : for (i = 1; i < 11; i++) {
2143 [ + + ]: 120 : switch (i) {
2144 : 60 : case 2:
2145 : : case 3:
2146 : : case 4:
2147 : : case 7:
2148 : : case 9:
2149 : 60 : CU_ASSERT(g_dev_buffer[i * SPDK_BLOB_OPTS_CLUSTER_SZ] == 0xFF);
2150 : 60 : break;
2151 : 60 : default:
2152 : 60 : CU_ASSERT(g_dev_buffer[i * SPDK_BLOB_OPTS_CLUSTER_SZ] == 0);
2153 : 60 : break;
2154 : : }
2155 : : }
2156 : :
2157 : 12 : spdk_bs_free_io_channel(channel);
2158 : 12 : poll_threads();
2159 : :
2160 : 12 : ut_blob_close_and_delete(bs, blob);
2161 : 12 : }
2162 : :
2163 : : static void
2164 : 12 : blob_iter(void)
2165 : : {
2166 : 12 : struct spdk_blob_store *bs = g_bs;
2167 : : struct spdk_blob *blob;
2168 : : spdk_blob_id blobid;
2169 : 12 : struct spdk_blob_opts blob_opts;
2170 : :
2171 : 12 : spdk_bs_iter_first(bs, blob_op_with_handle_complete, NULL);
2172 : 12 : poll_threads();
2173 : 12 : CU_ASSERT(g_blob == NULL);
2174 : 12 : CU_ASSERT(g_bserrno == -ENOENT);
2175 : :
2176 : 12 : ut_spdk_blob_opts_init(&blob_opts);
2177 : 12 : spdk_bs_create_blob_ext(bs, &blob_opts, blob_op_with_id_complete, NULL);
2178 : 12 : poll_threads();
2179 : 12 : CU_ASSERT(g_bserrno == 0);
2180 : 12 : CU_ASSERT(g_blobid != SPDK_BLOBID_INVALID);
2181 : 12 : blobid = g_blobid;
2182 : :
2183 : 12 : spdk_bs_iter_first(bs, blob_op_with_handle_complete, NULL);
2184 : 12 : poll_threads();
2185 : 12 : CU_ASSERT(g_blob != NULL);
2186 : 12 : CU_ASSERT(g_bserrno == 0);
2187 : 12 : blob = g_blob;
2188 : 12 : CU_ASSERT(spdk_blob_get_id(blob) == blobid);
2189 : :
2190 : 12 : spdk_bs_iter_next(bs, blob, blob_op_with_handle_complete, NULL);
2191 : 12 : poll_threads();
2192 : 12 : CU_ASSERT(g_blob == NULL);
2193 : 12 : CU_ASSERT(g_bserrno == -ENOENT);
2194 : 12 : }
2195 : :
2196 : : static void
2197 : 12 : blob_xattr(void)
2198 : : {
2199 : 12 : struct spdk_blob_store *bs = g_bs;
2200 : 12 : struct spdk_blob *blob = g_blob;
2201 : 12 : spdk_blob_id blobid = spdk_blob_get_id(blob);
2202 : 12 : uint64_t length;
2203 : : int rc;
2204 : : const char *name1, *name2;
2205 : 12 : const void *value;
2206 : 12 : size_t value_len;
2207 : 12 : struct spdk_xattr_names *names;
2208 : :
2209 : : /* Test that set_xattr fails if md_ro flag is set. */
2210 : 12 : blob->md_ro = true;
2211 : 12 : rc = spdk_blob_set_xattr(blob, "name", "log.txt", strlen("log.txt") + 1);
2212 : 12 : CU_ASSERT(rc == -EPERM);
2213 : :
2214 : 12 : blob->md_ro = false;
2215 : 12 : rc = spdk_blob_set_xattr(blob, "name", "log.txt", strlen("log.txt") + 1);
2216 : 12 : CU_ASSERT(rc == 0);
2217 : :
2218 : 12 : length = 2345;
2219 : 12 : rc = spdk_blob_set_xattr(blob, "length", &length, sizeof(length));
2220 : 12 : CU_ASSERT(rc == 0);
2221 : :
2222 : : /* Overwrite "length" xattr. */
2223 : 12 : length = 3456;
2224 : 12 : rc = spdk_blob_set_xattr(blob, "length", &length, sizeof(length));
2225 : 12 : CU_ASSERT(rc == 0);
2226 : :
2227 : : /* get_xattr should still work even if md_ro flag is set. */
2228 : 12 : value = NULL;
2229 : 12 : blob->md_ro = true;
2230 : 12 : rc = spdk_blob_get_xattr_value(blob, "length", &value, &value_len);
2231 : 12 : CU_ASSERT(rc == 0);
2232 [ - + ]: 12 : SPDK_CU_ASSERT_FATAL(value != NULL);
2233 : 12 : CU_ASSERT(*(uint64_t *)value == length);
2234 : 12 : CU_ASSERT(value_len == 8);
2235 : 12 : blob->md_ro = false;
2236 : :
2237 : 12 : rc = spdk_blob_get_xattr_value(blob, "foobar", &value, &value_len);
2238 : 12 : CU_ASSERT(rc == -ENOENT);
2239 : :
2240 : 12 : names = NULL;
2241 : 12 : rc = spdk_blob_get_xattr_names(blob, &names);
2242 : 12 : CU_ASSERT(rc == 0);
2243 [ - + ]: 12 : SPDK_CU_ASSERT_FATAL(names != NULL);
2244 : 12 : CU_ASSERT(spdk_xattr_names_get_count(names) == 2);
2245 : 12 : name1 = spdk_xattr_names_get_name(names, 0);
2246 [ - + ]: 12 : SPDK_CU_ASSERT_FATAL(name1 != NULL);
2247 [ - + - + : 12 : CU_ASSERT(!strcmp(name1, "name") || !strcmp(name1, "length"));
- - - - ]
2248 : 12 : name2 = spdk_xattr_names_get_name(names, 1);
2249 [ - + ]: 12 : SPDK_CU_ASSERT_FATAL(name2 != NULL);
2250 [ + + + - : 12 : CU_ASSERT(!strcmp(name2, "name") || !strcmp(name2, "length"));
- + + - ]
2251 [ - + - + ]: 12 : CU_ASSERT(strcmp(name1, name2));
2252 : 12 : spdk_xattr_names_free(names);
2253 : :
2254 : : /* Confirm that remove_xattr fails if md_ro is set to true. */
2255 : 12 : blob->md_ro = true;
2256 : 12 : rc = spdk_blob_remove_xattr(blob, "name");
2257 : 12 : CU_ASSERT(rc == -EPERM);
2258 : :
2259 : 12 : blob->md_ro = false;
2260 : 12 : rc = spdk_blob_remove_xattr(blob, "name");
2261 : 12 : CU_ASSERT(rc == 0);
2262 : :
2263 : 12 : rc = spdk_blob_remove_xattr(blob, "foobar");
2264 : 12 : CU_ASSERT(rc == -ENOENT);
2265 : :
2266 : : /* Set internal xattr */
2267 : 12 : length = 7898;
2268 : 12 : rc = blob_set_xattr(blob, "internal", &length, sizeof(length), true);
2269 : 12 : CU_ASSERT(rc == 0);
2270 : 12 : rc = blob_get_xattr_value(blob, "internal", &value, &value_len, true);
2271 : 12 : CU_ASSERT(rc == 0);
2272 : 12 : CU_ASSERT(*(uint64_t *)value == length);
2273 : : /* try to get public xattr with same name */
2274 : 12 : rc = spdk_blob_get_xattr_value(blob, "internal", &value, &value_len);
2275 : 12 : CU_ASSERT(rc != 0);
2276 : 12 : rc = blob_get_xattr_value(blob, "internal", &value, &value_len, false);
2277 : 12 : CU_ASSERT(rc != 0);
2278 : : /* Check if SPDK_BLOB_INTERNAL_XATTR is set */
2279 : 12 : CU_ASSERT((blob->invalid_flags & SPDK_BLOB_INTERNAL_XATTR) ==
2280 : : SPDK_BLOB_INTERNAL_XATTR);
2281 : :
2282 : 12 : spdk_blob_close(blob, blob_op_complete, NULL);
2283 : 12 : poll_threads();
2284 : :
2285 : : /* Check if xattrs are persisted */
2286 : 12 : ut_bs_reload(&bs, NULL);
2287 : :
2288 : 12 : spdk_bs_open_blob(bs, blobid, blob_op_with_handle_complete, NULL);
2289 : 12 : poll_threads();
2290 : 12 : CU_ASSERT(g_bserrno == 0);
2291 [ - + ]: 12 : SPDK_CU_ASSERT_FATAL(g_blob != NULL);
2292 : 12 : blob = g_blob;
2293 : :
2294 : 12 : rc = blob_get_xattr_value(blob, "internal", &value, &value_len, true);
2295 : 12 : CU_ASSERT(rc == 0);
2296 : 12 : CU_ASSERT(*(uint64_t *)value == length);
2297 : :
2298 : : /* try to get internal xattr trough public call */
2299 : 12 : rc = spdk_blob_get_xattr_value(blob, "internal", &value, &value_len);
2300 : 12 : CU_ASSERT(rc != 0);
2301 : :
2302 : 12 : rc = blob_remove_xattr(blob, "internal", true);
2303 : 12 : CU_ASSERT(rc == 0);
2304 : :
2305 : 12 : CU_ASSERT((blob->invalid_flags & SPDK_BLOB_INTERNAL_XATTR) == 0);
2306 : 12 : }
2307 : :
2308 : : static void
2309 : 12 : blob_parse_md(void)
2310 : : {
2311 : 12 : struct spdk_blob_store *bs = g_bs;
2312 : : struct spdk_blob *blob;
2313 : : int rc;
2314 : : uint32_t used_pages;
2315 : : size_t xattr_length;
2316 : : char *xattr;
2317 : :
2318 : 12 : used_pages = spdk_bit_array_count_set(bs->used_md_pages);
2319 : 12 : blob = ut_blob_create_and_open(bs, NULL);
2320 : :
2321 : : /* Create large extent to force more than 1 page of metadata. */
2322 : 12 : xattr_length = SPDK_BS_MAX_DESC_SIZE - sizeof(struct spdk_blob_md_descriptor_xattr) -
2323 : : strlen("large_xattr");
2324 : 12 : xattr = calloc(xattr_length, sizeof(char));
2325 [ - + ]: 12 : SPDK_CU_ASSERT_FATAL(xattr != NULL);
2326 : 12 : rc = spdk_blob_set_xattr(blob, "large_xattr", xattr, xattr_length);
2327 : 12 : free(xattr);
2328 [ - + ]: 12 : SPDK_CU_ASSERT_FATAL(rc == 0);
2329 : :
2330 : 12 : spdk_blob_sync_md(blob, blob_op_complete, NULL);
2331 : 12 : poll_threads();
2332 : :
2333 : : /* Delete the blob and verify that number of pages returned to before its creation. */
2334 [ - + ]: 12 : SPDK_CU_ASSERT_FATAL(used_pages != spdk_bit_array_count_set(bs->used_md_pages));
2335 : 12 : ut_blob_close_and_delete(bs, blob);
2336 [ - + ]: 12 : SPDK_CU_ASSERT_FATAL(used_pages == spdk_bit_array_count_set(bs->used_md_pages));
2337 : 12 : }
2338 : :
2339 : : static void
2340 : 12 : bs_load(void)
2341 : : {
2342 : : struct spdk_blob_store *bs;
2343 : : struct spdk_bs_dev *dev;
2344 : : spdk_blob_id blobid;
2345 : : struct spdk_blob *blob;
2346 : : struct spdk_bs_super_block *super_block;
2347 : 12 : uint64_t length;
2348 : : int rc;
2349 : 12 : const void *value;
2350 : 12 : size_t value_len;
2351 : 12 : struct spdk_bs_opts opts;
2352 : 12 : struct spdk_blob_opts blob_opts;
2353 : :
2354 : 12 : dev = init_dev();
2355 : 12 : spdk_bs_opts_init(&opts, sizeof(opts));
2356 : 12 : snprintf(opts.bstype.bstype, sizeof(opts.bstype.bstype), "TESTTYPE");
2357 : :
2358 : : /* Initialize a new blob store */
2359 : 12 : spdk_bs_init(dev, &opts, bs_op_with_handle_complete, NULL);
2360 : 12 : poll_threads();
2361 : 12 : CU_ASSERT(g_bserrno == 0);
2362 [ - + ]: 12 : SPDK_CU_ASSERT_FATAL(g_bs != NULL);
2363 : 12 : bs = g_bs;
2364 : :
2365 : : /* Try to open a blobid that does not exist */
2366 : 12 : spdk_bs_open_blob(bs, 0, blob_op_with_handle_complete, NULL);
2367 : 12 : poll_threads();
2368 : 12 : CU_ASSERT(g_bserrno == -ENOENT);
2369 : 12 : CU_ASSERT(g_blob == NULL);
2370 : :
2371 : : /* Create a blob */
2372 : 12 : blob = ut_blob_create_and_open(bs, NULL);
2373 : 12 : blobid = spdk_blob_get_id(blob);
2374 : :
2375 : : /* Try again to open valid blob but without the upper bit set */
2376 : 12 : spdk_bs_open_blob(bs, blobid & 0xFFFFFFFF, blob_op_with_handle_complete, NULL);
2377 : 12 : poll_threads();
2378 : 12 : CU_ASSERT(g_bserrno == -ENOENT);
2379 : 12 : CU_ASSERT(g_blob == NULL);
2380 : :
2381 : : /* Set some xattrs */
2382 : 12 : rc = spdk_blob_set_xattr(blob, "name", "log.txt", strlen("log.txt") + 1);
2383 : 12 : CU_ASSERT(rc == 0);
2384 : :
2385 : 12 : length = 2345;
2386 : 12 : rc = spdk_blob_set_xattr(blob, "length", &length, sizeof(length));
2387 : 12 : CU_ASSERT(rc == 0);
2388 : :
2389 : : /* Resize the blob */
2390 : 12 : spdk_blob_resize(blob, 10, blob_op_complete, NULL);
2391 : 12 : poll_threads();
2392 : 12 : CU_ASSERT(g_bserrno == 0);
2393 : :
2394 : 12 : spdk_blob_close(blob, blob_op_complete, NULL);
2395 : 12 : poll_threads();
2396 : 12 : CU_ASSERT(g_bserrno == 0);
2397 : 12 : blob = NULL;
2398 : 12 : g_blob = NULL;
2399 : 12 : g_blobid = SPDK_BLOBID_INVALID;
2400 : :
2401 : : /* Unload the blob store */
2402 : 12 : spdk_bs_unload(bs, bs_op_complete, NULL);
2403 : 12 : poll_threads();
2404 : 12 : CU_ASSERT(g_bserrno == 0);
2405 : 12 : g_bs = NULL;
2406 : 12 : g_blob = NULL;
2407 : 12 : g_blobid = 0;
2408 : :
2409 : 12 : super_block = (struct spdk_bs_super_block *)g_dev_buffer;
2410 : 12 : CU_ASSERT(super_block->clean == 1);
2411 : :
2412 : : /* Load should fail for device with an unsupported blocklen */
2413 : 12 : dev = init_dev();
2414 : 12 : dev->blocklen = SPDK_BS_PAGE_SIZE * 2;
2415 : 12 : spdk_bs_load(dev, NULL, bs_op_with_handle_complete, NULL);
2416 : 12 : poll_threads();
2417 : 12 : CU_ASSERT(g_bserrno == -EINVAL);
2418 : :
2419 : : /* Load should when max_md_ops is set to zero */
2420 : 12 : dev = init_dev();
2421 : 12 : spdk_bs_opts_init(&opts, sizeof(opts));
2422 : 12 : opts.max_md_ops = 0;
2423 : 12 : spdk_bs_load(dev, &opts, bs_op_with_handle_complete, NULL);
2424 : 12 : poll_threads();
2425 : 12 : CU_ASSERT(g_bserrno == -EINVAL);
2426 : :
2427 : : /* Load should when max_channel_ops is set to zero */
2428 : 12 : dev = init_dev();
2429 : 12 : spdk_bs_opts_init(&opts, sizeof(opts));
2430 : 12 : opts.max_channel_ops = 0;
2431 : 12 : spdk_bs_load(dev, &opts, bs_op_with_handle_complete, NULL);
2432 : 12 : poll_threads();
2433 : 12 : CU_ASSERT(g_bserrno == -EINVAL);
2434 : :
2435 : : /* Load an existing blob store */
2436 : 12 : dev = init_dev();
2437 : 12 : spdk_bs_opts_init(&opts, sizeof(opts));
2438 : 12 : snprintf(opts.bstype.bstype, sizeof(opts.bstype.bstype), "TESTTYPE");
2439 : 12 : spdk_bs_load(dev, &opts, bs_op_with_handle_complete, NULL);
2440 : 12 : poll_threads();
2441 : 12 : CU_ASSERT(g_bserrno == 0);
2442 [ - + ]: 12 : SPDK_CU_ASSERT_FATAL(g_bs != NULL);
2443 : 12 : bs = g_bs;
2444 : :
2445 : 12 : super_block = (struct spdk_bs_super_block *)g_dev_buffer;
2446 : 12 : CU_ASSERT(super_block->clean == 1);
2447 : 12 : CU_ASSERT(super_block->size == dev->blockcnt * dev->blocklen);
2448 : :
2449 : 12 : spdk_bs_open_blob(bs, blobid, blob_op_with_handle_complete, NULL);
2450 : 12 : poll_threads();
2451 : 12 : CU_ASSERT(g_bserrno == 0);
2452 : 12 : CU_ASSERT(g_blob != NULL);
2453 : 12 : blob = g_blob;
2454 : :
2455 : : /* Verify that blobstore is marked dirty after first metadata sync */
2456 : 12 : spdk_blob_sync_md(blob, blob_op_complete, NULL);
2457 : 12 : CU_ASSERT(super_block->clean == 1);
2458 : :
2459 : : /* Get the xattrs */
2460 : 12 : value = NULL;
2461 : 12 : rc = spdk_blob_get_xattr_value(blob, "length", &value, &value_len);
2462 : 12 : CU_ASSERT(rc == 0);
2463 [ - + ]: 12 : SPDK_CU_ASSERT_FATAL(value != NULL);
2464 : 12 : CU_ASSERT(*(uint64_t *)value == length);
2465 : 12 : CU_ASSERT(value_len == 8);
2466 : :
2467 : 12 : rc = spdk_blob_get_xattr_value(blob, "foobar", &value, &value_len);
2468 : 12 : CU_ASSERT(rc == -ENOENT);
2469 : :
2470 : 12 : CU_ASSERT(spdk_blob_get_num_clusters(blob) == 10);
2471 : 12 : CU_ASSERT(spdk_blob_get_num_allocated_clusters(blob) == 10);
2472 : :
2473 : 12 : spdk_blob_close(blob, blob_op_complete, NULL);
2474 : 12 : poll_threads();
2475 : 12 : CU_ASSERT(g_bserrno == 0);
2476 : 12 : blob = NULL;
2477 : 12 : g_blob = NULL;
2478 : :
2479 : 12 : spdk_bs_unload(bs, bs_op_complete, NULL);
2480 : 12 : poll_threads();
2481 : 12 : CU_ASSERT(g_bserrno == 0);
2482 : 12 : g_bs = NULL;
2483 : :
2484 : : /* Load should fail: bdev size < saved size */
2485 : 12 : dev = init_dev();
2486 : 12 : dev->blockcnt /= 2;
2487 : :
2488 : 12 : spdk_bs_opts_init(&opts, sizeof(opts));
2489 : 12 : snprintf(opts.bstype.bstype, sizeof(opts.bstype.bstype), "TESTTYPE");
2490 : 12 : spdk_bs_load(dev, &opts, bs_op_with_handle_complete, NULL);
2491 : 12 : poll_threads();
2492 : :
2493 : 12 : CU_ASSERT(g_bserrno == -EILSEQ);
2494 : :
2495 : : /* Load should succeed: bdev size > saved size */
2496 : 12 : dev = init_dev();
2497 : 12 : dev->blockcnt *= 4;
2498 : :
2499 : 12 : spdk_bs_opts_init(&opts, sizeof(opts));
2500 : 12 : snprintf(opts.bstype.bstype, sizeof(opts.bstype.bstype), "TESTTYPE");
2501 : 12 : spdk_bs_load(dev, &opts, bs_op_with_handle_complete, NULL);
2502 : 12 : poll_threads();
2503 : 12 : CU_ASSERT(g_bserrno == 0);
2504 [ - + ]: 12 : SPDK_CU_ASSERT_FATAL(g_bs != NULL);
2505 : 12 : bs = g_bs;
2506 : :
2507 : 12 : CU_ASSERT(g_bserrno == 0);
2508 : 12 : spdk_bs_unload(bs, bs_op_complete, NULL);
2509 : 12 : poll_threads();
2510 : :
2511 : :
2512 : : /* Test compatibility mode */
2513 : :
2514 : 12 : dev = init_dev();
2515 : 12 : super_block->size = 0;
2516 : 12 : super_block->crc = blob_md_page_calc_crc(super_block);
2517 : :
2518 : 12 : spdk_bs_opts_init(&opts, sizeof(opts));
2519 : 12 : snprintf(opts.bstype.bstype, sizeof(opts.bstype.bstype), "TESTTYPE");
2520 : 12 : spdk_bs_load(dev, &opts, bs_op_with_handle_complete, NULL);
2521 : 12 : poll_threads();
2522 : 12 : CU_ASSERT(g_bserrno == 0);
2523 [ - + ]: 12 : SPDK_CU_ASSERT_FATAL(g_bs != NULL);
2524 : 12 : bs = g_bs;
2525 : :
2526 : : /* Create a blob */
2527 : 12 : ut_spdk_blob_opts_init(&blob_opts);
2528 : 12 : spdk_bs_create_blob_ext(bs, &blob_opts, blob_op_with_id_complete, NULL);
2529 : 12 : poll_threads();
2530 : 12 : CU_ASSERT(g_bserrno == 0);
2531 : 12 : CU_ASSERT(g_blobid != SPDK_BLOBID_INVALID);
2532 : :
2533 : : /* Blobstore should update number of blocks in super_block */
2534 : 12 : CU_ASSERT(super_block->size == dev->blockcnt * dev->blocklen);
2535 : 12 : CU_ASSERT(super_block->clean == 0);
2536 : :
2537 : 12 : spdk_bs_unload(bs, bs_op_complete, NULL);
2538 : 12 : poll_threads();
2539 : 12 : CU_ASSERT(g_bserrno == 0);
2540 : 12 : CU_ASSERT(super_block->clean == 1);
2541 : 12 : g_bs = NULL;
2542 : :
2543 : 12 : }
2544 : :
2545 : : static void
2546 : 12 : bs_load_pending_removal(void)
2547 : : {
2548 : 12 : struct spdk_blob_store *bs = g_bs;
2549 : 12 : struct spdk_blob_opts opts;
2550 : : struct spdk_blob *blob, *snapshot;
2551 : 12 : spdk_blob_id blobid, snapshotid;
2552 : 12 : const void *value;
2553 : 12 : size_t value_len;
2554 : : int rc;
2555 : :
2556 : : /* Create blob */
2557 : 12 : ut_spdk_blob_opts_init(&opts);
2558 : 12 : opts.num_clusters = 10;
2559 : :
2560 : 12 : blob = ut_blob_create_and_open(bs, &opts);
2561 : 12 : blobid = spdk_blob_get_id(blob);
2562 : :
2563 : : /* Create snapshot */
2564 : 12 : spdk_bs_create_snapshot(bs, blobid, NULL, blob_op_with_id_complete, NULL);
2565 : 12 : poll_threads();
2566 : 12 : CU_ASSERT(g_bserrno == 0);
2567 : 12 : CU_ASSERT(g_blobid != SPDK_BLOBID_INVALID);
2568 : 12 : snapshotid = g_blobid;
2569 : :
2570 : 12 : spdk_bs_open_blob(bs, snapshotid, blob_op_with_handle_complete, NULL);
2571 : 12 : poll_threads();
2572 : 12 : CU_ASSERT(g_bserrno == 0);
2573 [ - + ]: 12 : SPDK_CU_ASSERT_FATAL(g_blob != NULL);
2574 : 12 : snapshot = g_blob;
2575 : :
2576 : : /* Set SNAPSHOT_PENDING_REMOVAL xattr */
2577 : 12 : snapshot->md_ro = false;
2578 : 12 : rc = blob_set_xattr(snapshot, SNAPSHOT_PENDING_REMOVAL, &blobid, sizeof(spdk_blob_id), true);
2579 : 12 : CU_ASSERT(rc == 0);
2580 : 12 : snapshot->md_ro = true;
2581 : :
2582 : 12 : spdk_blob_close(snapshot, blob_op_complete, NULL);
2583 : 12 : poll_threads();
2584 : 12 : CU_ASSERT(g_bserrno == 0);
2585 : :
2586 : 12 : spdk_blob_close(blob, blob_op_complete, NULL);
2587 : 12 : poll_threads();
2588 : 12 : CU_ASSERT(g_bserrno == 0);
2589 : :
2590 : : /* Reload blobstore */
2591 : 12 : ut_bs_reload(&bs, NULL);
2592 : :
2593 : : /* Snapshot should not be removed as blob is still pointing to it */
2594 : 12 : spdk_bs_open_blob(bs, snapshotid, blob_op_with_handle_complete, NULL);
2595 : 12 : poll_threads();
2596 : 12 : CU_ASSERT(g_bserrno == 0);
2597 [ - + ]: 12 : SPDK_CU_ASSERT_FATAL(g_blob != NULL);
2598 : 12 : snapshot = g_blob;
2599 : :
2600 : : /* SNAPSHOT_PENDING_REMOVAL xattr should be removed during load */
2601 : 12 : rc = spdk_blob_get_xattr_value(snapshot, SNAPSHOT_PENDING_REMOVAL, &value, &value_len);
2602 : 12 : CU_ASSERT(rc != 0);
2603 : :
2604 : : /* Set SNAPSHOT_PENDING_REMOVAL xattr again */
2605 : 12 : snapshot->md_ro = false;
2606 : 12 : rc = blob_set_xattr(snapshot, SNAPSHOT_PENDING_REMOVAL, &blobid, sizeof(spdk_blob_id), true);
2607 : 12 : CU_ASSERT(rc == 0);
2608 : 12 : snapshot->md_ro = true;
2609 : :
2610 : 12 : spdk_bs_open_blob(bs, blobid, blob_op_with_handle_complete, NULL);
2611 : 12 : poll_threads();
2612 : 12 : CU_ASSERT(g_bserrno == 0);
2613 [ - + ]: 12 : SPDK_CU_ASSERT_FATAL(g_blob != NULL);
2614 : 12 : blob = g_blob;
2615 : :
2616 : : /* Remove parent_id from blob by removing BLOB_SNAPSHOT xattr */
2617 : 12 : blob_remove_xattr(blob, BLOB_SNAPSHOT, true);
2618 : :
2619 : 12 : spdk_blob_sync_md(blob, blob_op_complete, NULL);
2620 : 12 : poll_threads();
2621 : 12 : CU_ASSERT(g_bserrno == 0);
2622 : :
2623 : 12 : spdk_blob_close(snapshot, blob_op_complete, NULL);
2624 : 12 : poll_threads();
2625 : 12 : CU_ASSERT(g_bserrno == 0);
2626 : :
2627 : 12 : spdk_blob_close(blob, blob_op_complete, NULL);
2628 : 12 : poll_threads();
2629 : 12 : CU_ASSERT(g_bserrno == 0);
2630 : :
2631 : : /* Reload blobstore */
2632 : 12 : ut_bs_reload(&bs, NULL);
2633 : :
2634 : : /* Snapshot should be removed as blob is not pointing to it anymore */
2635 : 12 : spdk_bs_open_blob(bs, snapshotid, blob_op_with_handle_complete, NULL);
2636 : 12 : poll_threads();
2637 : 12 : CU_ASSERT(g_bserrno != 0);
2638 : 12 : }
2639 : :
2640 : : static void
2641 : 12 : bs_load_custom_cluster_size(void)
2642 : : {
2643 : : struct spdk_blob_store *bs;
2644 : : struct spdk_bs_dev *dev;
2645 : : struct spdk_bs_super_block *super_block;
2646 : 12 : struct spdk_bs_opts opts;
2647 : 12 : uint32_t custom_cluster_size = 4194304; /* 4MiB */
2648 : : uint32_t cluster_sz;
2649 : : uint64_t total_clusters;
2650 : :
2651 : 12 : dev = init_dev();
2652 : 12 : spdk_bs_opts_init(&opts, sizeof(opts));
2653 : 12 : opts.cluster_sz = custom_cluster_size;
2654 : 12 : snprintf(opts.bstype.bstype, sizeof(opts.bstype.bstype), "TESTTYPE");
2655 : :
2656 : : /* Initialize a new blob store */
2657 : 12 : spdk_bs_init(dev, &opts, bs_op_with_handle_complete, NULL);
2658 : 12 : poll_threads();
2659 : 12 : CU_ASSERT(g_bserrno == 0);
2660 [ - + ]: 12 : SPDK_CU_ASSERT_FATAL(g_bs != NULL);
2661 : 12 : bs = g_bs;
2662 : 12 : cluster_sz = bs->cluster_sz;
2663 : 12 : total_clusters = bs->total_clusters;
2664 : :
2665 : : /* Unload the blob store */
2666 : 12 : spdk_bs_unload(bs, bs_op_complete, NULL);
2667 : 12 : poll_threads();
2668 : 12 : CU_ASSERT(g_bserrno == 0);
2669 : 12 : g_bs = NULL;
2670 : 12 : g_blob = NULL;
2671 : 12 : g_blobid = 0;
2672 : :
2673 : 12 : super_block = (struct spdk_bs_super_block *)g_dev_buffer;
2674 : 12 : CU_ASSERT(super_block->clean == 1);
2675 : :
2676 : : /* Load an existing blob store */
2677 : 12 : dev = init_dev();
2678 : 12 : spdk_bs_opts_init(&opts, sizeof(opts));
2679 : 12 : snprintf(opts.bstype.bstype, sizeof(opts.bstype.bstype), "TESTTYPE");
2680 : 12 : spdk_bs_load(dev, &opts, bs_op_with_handle_complete, NULL);
2681 : 12 : poll_threads();
2682 : 12 : CU_ASSERT(g_bserrno == 0);
2683 [ - + ]: 12 : SPDK_CU_ASSERT_FATAL(g_bs != NULL);
2684 : 12 : bs = g_bs;
2685 : : /* Compare cluster size and number to one after initialization */
2686 : 12 : CU_ASSERT(cluster_sz == bs->cluster_sz);
2687 : 12 : CU_ASSERT(total_clusters == bs->total_clusters);
2688 : :
2689 : 12 : super_block = (struct spdk_bs_super_block *)g_dev_buffer;
2690 : 12 : CU_ASSERT(super_block->clean == 1);
2691 : 12 : CU_ASSERT(super_block->size == dev->blockcnt * dev->blocklen);
2692 : :
2693 : 12 : spdk_bs_unload(bs, bs_op_complete, NULL);
2694 : 12 : poll_threads();
2695 : 12 : CU_ASSERT(g_bserrno == 0);
2696 : 12 : CU_ASSERT(super_block->clean == 1);
2697 : 12 : g_bs = NULL;
2698 : 12 : }
2699 : :
2700 : : static void
2701 : 12 : bs_load_after_failed_grow(void)
2702 : : {
2703 : : struct spdk_blob_store *bs;
2704 : : struct spdk_bs_dev *dev;
2705 : : struct spdk_bs_super_block *super_block;
2706 : 12 : struct spdk_bs_opts opts;
2707 : : struct spdk_bs_md_mask *mask;
2708 : 12 : struct spdk_blob_opts blob_opts;
2709 : : struct spdk_blob *blob, *snapshot;
2710 : : spdk_blob_id blobid, snapshotid;
2711 : : uint64_t total_data_clusters;
2712 : :
2713 : 12 : dev = init_dev();
2714 : 12 : spdk_bs_opts_init(&opts, sizeof(opts));
2715 : 12 : snprintf(opts.bstype.bstype, sizeof(opts.bstype.bstype), "TESTTYPE");
2716 : : /*
2717 : : * The bdev_size is 64M, cluster_sz is 1M, so there are 64 clusters. The
2718 : : * blobstore will create 64 md pages by default. We set num_md_pages to 128,
2719 : : * thus the blobstore could grow to the double size.
2720 : : */
2721 : 12 : opts.num_md_pages = 128;
2722 : :
2723 : : /* Initialize a new blob store */
2724 : 12 : spdk_bs_init(dev, &opts, bs_op_with_handle_complete, NULL);
2725 : 12 : poll_threads();
2726 : 12 : CU_ASSERT(g_bserrno == 0);
2727 [ - + ]: 12 : SPDK_CU_ASSERT_FATAL(g_bs != NULL);
2728 : 12 : bs = g_bs;
2729 : :
2730 : : /* Create blob */
2731 : 12 : ut_spdk_blob_opts_init(&blob_opts);
2732 : 12 : blob_opts.num_clusters = 10;
2733 : :
2734 : 12 : blob = ut_blob_create_and_open(bs, &blob_opts);
2735 : 12 : blobid = spdk_blob_get_id(blob);
2736 : :
2737 : : /* Create snapshot */
2738 : 12 : spdk_bs_create_snapshot(bs, blobid, NULL, blob_op_with_id_complete, NULL);
2739 : 12 : poll_threads();
2740 : 12 : CU_ASSERT(g_bserrno == 0);
2741 : 12 : CU_ASSERT(g_blobid != SPDK_BLOBID_INVALID);
2742 : 12 : snapshotid = g_blobid;
2743 : :
2744 : 12 : spdk_bs_open_blob(bs, snapshotid, blob_op_with_handle_complete, NULL);
2745 : 12 : poll_threads();
2746 : 12 : CU_ASSERT(g_bserrno == 0);
2747 [ - + ]: 12 : SPDK_CU_ASSERT_FATAL(g_blob != NULL);
2748 : 12 : snapshot = g_blob;
2749 : :
2750 : 12 : spdk_blob_close(snapshot, blob_op_complete, NULL);
2751 : 12 : poll_threads();
2752 : 12 : CU_ASSERT(g_bserrno == 0);
2753 : :
2754 : 12 : spdk_blob_close(blob, blob_op_complete, NULL);
2755 : 12 : poll_threads();
2756 : 12 : CU_ASSERT(g_bserrno == 0);
2757 : :
2758 : 12 : total_data_clusters = bs->total_data_clusters;
2759 : 12 : CU_ASSERT(bs->num_free_clusters + 10 == total_data_clusters);
2760 : :
2761 : : /* Unload the blob store */
2762 : 12 : spdk_bs_unload(bs, bs_op_complete, NULL);
2763 : 12 : poll_threads();
2764 : 12 : CU_ASSERT(g_bserrno == 0);
2765 : 12 : g_bs = NULL;
2766 : 12 : g_blob = NULL;
2767 : 12 : g_blobid = 0;
2768 : :
2769 : 12 : super_block = (struct spdk_bs_super_block *)g_dev_buffer;
2770 : 12 : CU_ASSERT(super_block->clean == 1);
2771 : :
2772 : 12 : mask = (struct spdk_bs_md_mask *)(g_dev_buffer + super_block->used_cluster_mask_start * 4096);
2773 : 12 : CU_ASSERT(mask->type == SPDK_MD_MASK_TYPE_USED_CLUSTERS);
2774 [ - + ]: 12 : CU_ASSERT(mask->length == super_block->size / super_block->cluster_size);
2775 : :
2776 : : /*
2777 : : * We change the mask->length to emulate this scenario: A spdk_bs_grow failed after it changed
2778 : : * the used_cluster bitmap length, but it didn't change the super block yet.
2779 : : */
2780 : 12 : mask->length *= 2;
2781 : :
2782 : : /* Load an existing blob store */
2783 : 12 : dev = init_dev();
2784 : 12 : dev->blockcnt *= 2;
2785 : 12 : spdk_bs_opts_init(&opts, sizeof(opts));
2786 : 12 : opts.clear_method = BS_CLEAR_WITH_NONE;
2787 : 12 : snprintf(opts.bstype.bstype, sizeof(opts.bstype.bstype), "TESTTYPE");
2788 : 12 : spdk_bs_load(dev, &opts, bs_op_with_handle_complete, NULL);
2789 : 12 : poll_threads();
2790 : 12 : CU_ASSERT(g_bserrno == 0);
2791 [ - + ]: 12 : SPDK_CU_ASSERT_FATAL(g_bs != NULL);
2792 : 12 : bs = g_bs;
2793 : :
2794 : : /* Check the capacity is the same as before */
2795 : 12 : CU_ASSERT(bs->total_data_clusters == total_data_clusters);
2796 : 12 : CU_ASSERT(bs->num_free_clusters + 10 == total_data_clusters);
2797 : :
2798 : : /* Check the blob and the snapshot are still available */
2799 : 12 : spdk_bs_open_blob(bs, blobid, blob_op_with_handle_complete, NULL);
2800 : 12 : poll_threads();
2801 : 12 : CU_ASSERT(g_bserrno == 0);
2802 [ - + ]: 12 : SPDK_CU_ASSERT_FATAL(g_blob != NULL);
2803 : 12 : blob = g_blob;
2804 : :
2805 : 12 : spdk_blob_close(blob, blob_op_complete, NULL);
2806 : 12 : poll_threads();
2807 : 12 : CU_ASSERT(g_bserrno == 0);
2808 : :
2809 : 12 : spdk_bs_open_blob(bs, snapshotid, blob_op_with_handle_complete, NULL);
2810 : 12 : poll_threads();
2811 : 12 : CU_ASSERT(g_bserrno == 0);
2812 [ - + ]: 12 : SPDK_CU_ASSERT_FATAL(g_blob != NULL);
2813 : 12 : snapshot = g_blob;
2814 : :
2815 : 12 : spdk_blob_close(snapshot, blob_op_complete, NULL);
2816 : 12 : poll_threads();
2817 : 12 : CU_ASSERT(g_bserrno == 0);
2818 : :
2819 : 12 : spdk_bs_unload(bs, bs_op_complete, NULL);
2820 : 12 : poll_threads();
2821 : 12 : CU_ASSERT(g_bserrno == 0);
2822 : 12 : CU_ASSERT(super_block->clean == 1);
2823 : 12 : g_bs = NULL;
2824 : 12 : }
2825 : :
2826 : : static void
2827 : 12 : bs_type(void)
2828 : : {
2829 : : struct spdk_blob_store *bs;
2830 : : struct spdk_bs_dev *dev;
2831 : 12 : struct spdk_bs_opts opts;
2832 : :
2833 : 12 : dev = init_dev();
2834 : 12 : spdk_bs_opts_init(&opts, sizeof(opts));
2835 : 12 : snprintf(opts.bstype.bstype, sizeof(opts.bstype.bstype), "TESTTYPE");
2836 : :
2837 : : /* Initialize a new blob store */
2838 : 12 : spdk_bs_init(dev, &opts, bs_op_with_handle_complete, NULL);
2839 : 12 : poll_threads();
2840 : 12 : CU_ASSERT(g_bserrno == 0);
2841 [ - + ]: 12 : SPDK_CU_ASSERT_FATAL(g_bs != NULL);
2842 : 12 : bs = g_bs;
2843 : :
2844 : : /* Unload the blob store */
2845 : 12 : spdk_bs_unload(bs, bs_op_complete, NULL);
2846 : 12 : poll_threads();
2847 : 12 : CU_ASSERT(g_bserrno == 0);
2848 : 12 : g_bs = NULL;
2849 : 12 : g_blob = NULL;
2850 : 12 : g_blobid = 0;
2851 : :
2852 : : /* Load non existing blobstore type */
2853 : 12 : dev = init_dev();
2854 : 12 : snprintf(opts.bstype.bstype, sizeof(opts.bstype.bstype), "NONEXISTING");
2855 : 12 : spdk_bs_load(dev, &opts, bs_op_with_handle_complete, NULL);
2856 : 12 : poll_threads();
2857 : 12 : CU_ASSERT(g_bserrno != 0);
2858 : :
2859 : : /* Load with empty blobstore type */
2860 : 12 : dev = init_dev();
2861 : 12 : memset(opts.bstype.bstype, 0, sizeof(opts.bstype.bstype));
2862 : 12 : spdk_bs_load(dev, &opts, bs_op_with_handle_complete, NULL);
2863 : 12 : poll_threads();
2864 : 12 : CU_ASSERT(g_bserrno == 0);
2865 [ - + ]: 12 : SPDK_CU_ASSERT_FATAL(g_bs != NULL);
2866 : 12 : bs = g_bs;
2867 : :
2868 : 12 : spdk_bs_unload(bs, bs_op_complete, NULL);
2869 : 12 : poll_threads();
2870 : 12 : CU_ASSERT(g_bserrno == 0);
2871 : 12 : g_bs = NULL;
2872 : :
2873 : : /* Initialize a new blob store with empty bstype */
2874 : 12 : dev = init_dev();
2875 : 12 : memset(opts.bstype.bstype, 0, sizeof(opts.bstype.bstype));
2876 : 12 : spdk_bs_init(dev, NULL, bs_op_with_handle_complete, NULL);
2877 : 12 : poll_threads();
2878 : 12 : CU_ASSERT(g_bserrno == 0);
2879 [ - + ]: 12 : SPDK_CU_ASSERT_FATAL(g_bs != NULL);
2880 : 12 : bs = g_bs;
2881 : :
2882 : 12 : spdk_bs_unload(bs, bs_op_complete, NULL);
2883 : 12 : poll_threads();
2884 : 12 : CU_ASSERT(g_bserrno == 0);
2885 : 12 : g_bs = NULL;
2886 : :
2887 : : /* Load non existing blobstore type */
2888 : 12 : dev = init_dev();
2889 : 12 : snprintf(opts.bstype.bstype, sizeof(opts.bstype.bstype), "NONEXISTING");
2890 : 12 : spdk_bs_load(dev, &opts, bs_op_with_handle_complete, NULL);
2891 : 12 : poll_threads();
2892 : 12 : CU_ASSERT(g_bserrno != 0);
2893 : :
2894 : : /* Load with empty blobstore type */
2895 : 12 : dev = init_dev();
2896 : 12 : memset(opts.bstype.bstype, 0, sizeof(opts.bstype.bstype));
2897 : 12 : spdk_bs_load(dev, &opts, bs_op_with_handle_complete, NULL);
2898 : 12 : poll_threads();
2899 : 12 : CU_ASSERT(g_bserrno == 0);
2900 [ - + ]: 12 : SPDK_CU_ASSERT_FATAL(g_bs != NULL);
2901 : 12 : bs = g_bs;
2902 : :
2903 : 12 : spdk_bs_unload(bs, bs_op_complete, NULL);
2904 : 12 : poll_threads();
2905 : 12 : CU_ASSERT(g_bserrno == 0);
2906 : 12 : g_bs = NULL;
2907 : 12 : }
2908 : :
2909 : : static void
2910 : 12 : bs_super_block(void)
2911 : : {
2912 : : struct spdk_blob_store *bs;
2913 : : struct spdk_bs_dev *dev;
2914 : : struct spdk_bs_super_block *super_block;
2915 : 12 : struct spdk_bs_opts opts;
2916 : 12 : struct spdk_bs_super_block_ver1 super_block_v1;
2917 : :
2918 : 12 : dev = init_dev();
2919 : 12 : spdk_bs_opts_init(&opts, sizeof(opts));
2920 : 12 : snprintf(opts.bstype.bstype, sizeof(opts.bstype.bstype), "TESTTYPE");
2921 : :
2922 : : /* Initialize a new blob store */
2923 : 12 : spdk_bs_init(dev, &opts, bs_op_with_handle_complete, NULL);
2924 : 12 : poll_threads();
2925 : 12 : CU_ASSERT(g_bserrno == 0);
2926 [ - + ]: 12 : SPDK_CU_ASSERT_FATAL(g_bs != NULL);
2927 : 12 : bs = g_bs;
2928 : :
2929 : : /* Unload the blob store */
2930 : 12 : spdk_bs_unload(bs, bs_op_complete, NULL);
2931 : 12 : poll_threads();
2932 : 12 : CU_ASSERT(g_bserrno == 0);
2933 : 12 : g_bs = NULL;
2934 : 12 : g_blob = NULL;
2935 : 12 : g_blobid = 0;
2936 : :
2937 : : /* Load an existing blob store with version newer than supported */
2938 : 12 : super_block = (struct spdk_bs_super_block *)g_dev_buffer;
2939 : 12 : super_block->version++;
2940 : :
2941 : 12 : dev = init_dev();
2942 : 12 : memset(opts.bstype.bstype, 0, sizeof(opts.bstype.bstype));
2943 : 12 : spdk_bs_load(dev, &opts, bs_op_with_handle_complete, NULL);
2944 : 12 : poll_threads();
2945 : 12 : CU_ASSERT(g_bserrno != 0);
2946 : :
2947 : : /* Create a new blob store with super block version 1 */
2948 : 12 : dev = init_dev();
2949 : 12 : super_block_v1.version = 1;
2950 : 12 : memcpy(super_block_v1.signature, "SPDKBLOB", sizeof(super_block_v1.signature));
2951 : 12 : super_block_v1.length = 0x1000;
2952 : 12 : super_block_v1.clean = 1;
2953 : 12 : super_block_v1.super_blob = 0xFFFFFFFFFFFFFFFF;
2954 : 12 : super_block_v1.cluster_size = 0x100000;
2955 : 12 : super_block_v1.used_page_mask_start = 0x01;
2956 : 12 : super_block_v1.used_page_mask_len = 0x01;
2957 : 12 : super_block_v1.used_cluster_mask_start = 0x02;
2958 : 12 : super_block_v1.used_cluster_mask_len = 0x01;
2959 : 12 : super_block_v1.md_start = 0x03;
2960 : 12 : super_block_v1.md_len = 0x40;
2961 : 12 : memset(super_block_v1.reserved, 0, 4036);
2962 : 12 : super_block_v1.crc = blob_md_page_calc_crc(&super_block_v1);
2963 : 12 : memcpy(g_dev_buffer, &super_block_v1, sizeof(struct spdk_bs_super_block_ver1));
2964 : :
2965 : 12 : memset(opts.bstype.bstype, 0, sizeof(opts.bstype.bstype));
2966 : 12 : spdk_bs_load(dev, &opts, bs_op_with_handle_complete, NULL);
2967 : 12 : poll_threads();
2968 : 12 : CU_ASSERT(g_bserrno == 0);
2969 [ - + ]: 12 : SPDK_CU_ASSERT_FATAL(g_bs != NULL);
2970 : 12 : bs = g_bs;
2971 : :
2972 : 12 : spdk_bs_unload(bs, bs_op_complete, NULL);
2973 : 12 : poll_threads();
2974 : 12 : CU_ASSERT(g_bserrno == 0);
2975 : 12 : g_bs = NULL;
2976 : 12 : }
2977 : :
2978 : : static void
2979 : 12 : bs_test_recover_cluster_count(void)
2980 : : {
2981 : : struct spdk_blob_store *bs;
2982 : : struct spdk_bs_dev *dev;
2983 : 12 : struct spdk_bs_super_block super_block;
2984 : 12 : struct spdk_bs_opts opts;
2985 : :
2986 : 12 : dev = init_dev();
2987 : 12 : spdk_bs_opts_init(&opts, sizeof(opts));
2988 : 12 : snprintf(opts.bstype.bstype, sizeof(opts.bstype.bstype), "TESTTYPE");
2989 : :
2990 : 12 : super_block.version = 3;
2991 : 12 : memcpy(super_block.signature, "SPDKBLOB", sizeof(super_block.signature));
2992 : 12 : super_block.length = 0x1000;
2993 : 12 : super_block.clean = 0;
2994 : 12 : super_block.super_blob = 0xFFFFFFFFFFFFFFFF;
2995 : 12 : super_block.cluster_size = 4096;
2996 : 12 : super_block.used_page_mask_start = 0x01;
2997 : 12 : super_block.used_page_mask_len = 0x01;
2998 : 12 : super_block.used_cluster_mask_start = 0x02;
2999 : 12 : super_block.used_cluster_mask_len = 0x01;
3000 : 12 : super_block.used_blobid_mask_start = 0x03;
3001 : 12 : super_block.used_blobid_mask_len = 0x01;
3002 : 12 : super_block.md_start = 0x04;
3003 : 12 : super_block.md_len = 0x40;
3004 : 12 : memset(super_block.bstype.bstype, 0, sizeof(super_block.bstype.bstype));
3005 : 12 : super_block.size = dev->blockcnt * dev->blocklen;
3006 : 12 : super_block.io_unit_size = 0x1000;
3007 : 12 : memset(super_block.reserved, 0, 4000);
3008 : 12 : super_block.crc = blob_md_page_calc_crc(&super_block);
3009 : 12 : memcpy(g_dev_buffer, &super_block, sizeof(struct spdk_bs_super_block));
3010 : :
3011 : 12 : memset(opts.bstype.bstype, 0, sizeof(opts.bstype.bstype));
3012 : 12 : spdk_bs_load(dev, &opts, bs_op_with_handle_complete, NULL);
3013 : 12 : poll_threads();
3014 : 12 : CU_ASSERT(g_bserrno == 0);
3015 [ - + ]: 12 : SPDK_CU_ASSERT_FATAL(g_bs != NULL);
3016 : 12 : bs = g_bs;
3017 : 12 : CU_ASSERT(bs->num_free_clusters == bs->total_clusters - (super_block.md_start +
3018 : : super_block.md_len));
3019 : :
3020 : 12 : spdk_bs_unload(bs, bs_op_complete, NULL);
3021 : 12 : poll_threads();
3022 : 12 : CU_ASSERT(g_bserrno == 0);
3023 : 12 : g_bs = NULL;
3024 : 12 : }
3025 : :
3026 : : static void
3027 : 36 : bs_grow_live_size(uint64_t new_blockcnt)
3028 : : {
3029 : : struct spdk_blob_store *bs;
3030 : : struct spdk_bs_dev *dev;
3031 : 36 : struct spdk_bs_super_block super_block;
3032 : 36 : struct spdk_bs_opts opts;
3033 : 36 : struct spdk_bs_md_mask mask;
3034 : : uint64_t bdev_size;
3035 : : uint64_t total_data_clusters;
3036 : :
3037 : : /*
3038 : : * Further down the test the dev size will be larger than the g_dev_buffer size,
3039 : : * so we set clear_method to NONE, or the blobstore will try to clear the dev and
3040 : : * will write beyond the end of g_dev_buffer.
3041 : : */
3042 : 36 : dev = init_dev();
3043 : 36 : spdk_bs_opts_init(&opts, sizeof(opts));
3044 : 36 : opts.clear_method = BS_CLEAR_WITH_NONE;
3045 : 36 : spdk_bs_init(dev, &opts, bs_op_with_handle_complete, NULL);
3046 : 36 : poll_threads();
3047 : 36 : CU_ASSERT(g_bserrno == 0);
3048 [ - + ]: 36 : SPDK_CU_ASSERT_FATAL(g_bs != NULL);
3049 : 36 : bs = g_bs;
3050 : 36 : CU_ASSERT(spdk_bs_total_data_cluster_count(bs) == 63);
3051 : :
3052 : : /*
3053 : : * Set the dev size according to the new_blockcnt,
3054 : : * then the blobstore will adjust the metadata according to the new size.
3055 : : */
3056 : 36 : dev->blockcnt = new_blockcnt;
3057 : 36 : bdev_size = dev->blockcnt * dev->blocklen;
3058 : 36 : spdk_bs_grow_live(bs, bs_op_complete, NULL);
3059 : 36 : poll_threads();
3060 : 36 : CU_ASSERT(g_bserrno == 0);
3061 : 36 : total_data_clusters = spdk_bs_total_data_cluster_count(bs);
3062 : : /* One cluster of 1MiB size is used for metadata */
3063 : 36 : CU_ASSERT(total_data_clusters == (bdev_size / (1 * 1024 * 1024)) - 1);
3064 : :
3065 : : /* Make sure the super block is updated. */
3066 : 36 : memcpy(&super_block, g_dev_buffer, sizeof(struct spdk_bs_super_block));
3067 : 36 : CU_ASSERT(super_block.size == bdev_size);
3068 : 36 : CU_ASSERT(super_block.clean == 0);
3069 : : /* The used_cluster mask is not written out until first spdk_bs_unload. */
3070 : 36 : memcpy(&mask, g_dev_buffer + super_block.used_cluster_mask_start * 4096,
3071 : : sizeof(struct spdk_bs_md_mask));
3072 : 36 : CU_ASSERT(mask.type == 0);
3073 : 36 : CU_ASSERT(mask.length == 0);
3074 : :
3075 : 36 : spdk_bs_unload(bs, bs_op_complete, NULL);
3076 : 36 : poll_threads();
3077 : 36 : CU_ASSERT(g_bserrno == 0);
3078 : 36 : g_bs = NULL;
3079 : :
3080 : : /* Make sure all metadata is correct, super block and used_cluster mask. */
3081 : 36 : memcpy(&super_block, g_dev_buffer, sizeof(struct spdk_bs_super_block));
3082 : 36 : CU_ASSERT(super_block.size == bdev_size);
3083 : 36 : CU_ASSERT(super_block.clean == 1);
3084 : 36 : memcpy(&mask, g_dev_buffer + super_block.used_cluster_mask_start * 4096,
3085 : : sizeof(struct spdk_bs_md_mask));
3086 : 36 : CU_ASSERT(mask.type == SPDK_MD_MASK_TYPE_USED_CLUSTERS);
3087 : 36 : CU_ASSERT(mask.length == bdev_size / (1 * 1024 * 1024));
3088 : :
3089 : : /* Load blobstore and check the cluster counts again. */
3090 : 36 : dev = init_dev();
3091 : 36 : dev->blockcnt = new_blockcnt;
3092 : 36 : spdk_bs_load(dev, NULL, bs_op_with_handle_complete, NULL);
3093 : 36 : poll_threads();
3094 : 36 : CU_ASSERT(g_bserrno == 0);
3095 [ - + ]: 36 : SPDK_CU_ASSERT_FATAL(g_bs != NULL);
3096 : 36 : CU_ASSERT(super_block.clean == 1);
3097 : 36 : bs = g_bs;
3098 : 36 : CU_ASSERT(total_data_clusters == spdk_bs_total_data_cluster_count(bs));
3099 : :
3100 : : /* Perform grow without change in size, expected pass. */
3101 : 36 : spdk_bs_grow_live(bs, bs_op_complete, NULL);
3102 : 36 : poll_threads();
3103 : 36 : CU_ASSERT(g_bserrno == 0);
3104 : 36 : CU_ASSERT(total_data_clusters == spdk_bs_total_data_cluster_count(bs));
3105 : 36 : memcpy(&super_block, g_dev_buffer, sizeof(struct spdk_bs_super_block));
3106 : 36 : CU_ASSERT(super_block.size == bdev_size);
3107 : 36 : CU_ASSERT(super_block.clean == 1);
3108 : :
3109 : 36 : spdk_bs_unload(bs, bs_op_complete, NULL);
3110 : 36 : poll_threads();
3111 : 36 : CU_ASSERT(g_bserrno == 0);
3112 : 36 : g_bs = NULL;
3113 : 36 : }
3114 : :
3115 : : static void
3116 : 12 : bs_grow_live(void)
3117 : : {
3118 : : /* No change expected */
3119 : 12 : bs_grow_live_size(DEV_BUFFER_BLOCKCNT);
3120 : :
3121 : : /* Size slightly increased, but not enough to increase cluster count */
3122 : 12 : bs_grow_live_size(DEV_BUFFER_BLOCKCNT + 1);
3123 : :
3124 : : /* Size doubled, increasing the cluster count */
3125 : 12 : bs_grow_live_size(DEV_BUFFER_BLOCKCNT * 2);
3126 : 12 : }
3127 : :
3128 : : static void
3129 : 12 : bs_grow_live_no_space(void)
3130 : : {
3131 : : struct spdk_blob_store *bs;
3132 : : struct spdk_bs_dev *dev;
3133 : 12 : struct spdk_bs_super_block super_block;
3134 : 12 : struct spdk_bs_opts opts;
3135 : 12 : struct spdk_bs_md_mask mask;
3136 : : uint64_t bdev_size_init;
3137 : : uint64_t total_data_clusters, max_clusters;
3138 : :
3139 : : /*
3140 : : * Further down the test the dev size will be larger than the g_dev_buffer size,
3141 : : * so we set clear_method to NONE, or the blobstore will try to clear the dev and
3142 : : * will write beyond the end of g_dev_buffer.
3143 : : */
3144 : 12 : dev = init_dev();
3145 : 12 : bdev_size_init = dev->blockcnt * dev->blocklen;
3146 : 12 : spdk_bs_opts_init(&opts, sizeof(opts));
3147 : 12 : opts.clear_method = BS_CLEAR_WITH_NONE;
3148 : 12 : spdk_bs_init(dev, &opts, bs_op_with_handle_complete, NULL);
3149 : 12 : poll_threads();
3150 : 12 : CU_ASSERT(g_bserrno == 0);
3151 [ - + ]: 12 : SPDK_CU_ASSERT_FATAL(g_bs != NULL);
3152 : 12 : bs = g_bs;
3153 : 12 : total_data_clusters = spdk_bs_total_data_cluster_count(bs);
3154 : 12 : CU_ASSERT(total_data_clusters == 63);
3155 : :
3156 : : /*
3157 : : * The default dev size is 64M, here we set the dev size to 32M,
3158 : : * expecting EILSEQ due to super_block validation and no change in blobstore.
3159 : : */
3160 [ - + ]: 12 : dev->blockcnt = (32L * 1024L * 1024L) / dev->blocklen;
3161 : 12 : spdk_bs_grow_live(bs, bs_op_complete, NULL);
3162 : 12 : poll_threads();
3163 : : /* This error code comes from bs_super_validate() */
3164 : 12 : CU_ASSERT(g_bserrno == -EILSEQ);
3165 : 12 : CU_ASSERT(total_data_clusters == spdk_bs_total_data_cluster_count(bs));
3166 : 12 : memcpy(&super_block, g_dev_buffer, sizeof(struct spdk_bs_super_block));
3167 : 12 : CU_ASSERT(super_block.size == bdev_size_init);
3168 : :
3169 : : /*
3170 : : * Blobstore in this test has only space for single md_page for used_clusters,
3171 : : * which fits 1 bit per cluster minus the md header.
3172 : : *
3173 : : * Dev size is increased to exceed the reserved space for the used_cluster_mask
3174 : : * in the metadata, expecting ENOSPC and no change in blobstore.
3175 : : */
3176 : 12 : max_clusters = (spdk_bs_get_page_size(bs) - sizeof(struct spdk_bs_md_mask)) * 8;
3177 : 12 : max_clusters += 1;
3178 [ - + ]: 12 : dev->blockcnt = (max_clusters * spdk_bs_get_cluster_size(bs)) / dev->blocklen;
3179 : 12 : spdk_bs_grow_live(bs, bs_op_complete, NULL);
3180 : 12 : poll_threads();
3181 : 12 : CU_ASSERT(g_bserrno == -ENOSPC);
3182 : 12 : CU_ASSERT(total_data_clusters == spdk_bs_total_data_cluster_count(bs));
3183 : 12 : memcpy(&super_block, g_dev_buffer, sizeof(struct spdk_bs_super_block));
3184 : 12 : CU_ASSERT(super_block.size == bdev_size_init);
3185 : :
3186 : : /*
3187 : : * No change should have occurred for the duration of the test,
3188 : : * unload blobstore and check metadata.
3189 : : */
3190 : 12 : spdk_bs_unload(bs, bs_op_complete, NULL);
3191 : 12 : poll_threads();
3192 : 12 : CU_ASSERT(g_bserrno == 0);
3193 : 12 : g_bs = NULL;
3194 : :
3195 : : /* Make sure all metadata is correct, super block and used_cluster mask. */
3196 : 12 : memcpy(&super_block, g_dev_buffer, sizeof(struct spdk_bs_super_block));
3197 : 12 : CU_ASSERT(super_block.size == bdev_size_init);
3198 : 12 : CU_ASSERT(super_block.clean == 1);
3199 : 12 : memcpy(&mask, g_dev_buffer + super_block.used_cluster_mask_start * 4096,
3200 : : sizeof(struct spdk_bs_md_mask));
3201 : 12 : CU_ASSERT(mask.type == SPDK_MD_MASK_TYPE_USED_CLUSTERS);
3202 : 12 : CU_ASSERT(mask.length == bdev_size_init / (1 * 1024 * 1024));
3203 : :
3204 : : /* Load blobstore and check the cluster counts again. */
3205 : 12 : dev = init_dev();
3206 : 12 : spdk_bs_load(dev, NULL, bs_op_with_handle_complete, NULL);
3207 : 12 : poll_threads();
3208 : 12 : CU_ASSERT(g_bserrno == 0);
3209 [ - + ]: 12 : SPDK_CU_ASSERT_FATAL(g_bs != NULL);
3210 : 12 : bs = g_bs;
3211 : 12 : CU_ASSERT(total_data_clusters == spdk_bs_total_data_cluster_count(bs));
3212 : :
3213 : 12 : spdk_bs_unload(bs, bs_op_complete, NULL);
3214 : 12 : poll_threads();
3215 : 12 : CU_ASSERT(g_bserrno == 0);
3216 : 12 : g_bs = NULL;
3217 : 12 : }
3218 : :
3219 : : static void
3220 : 12 : bs_test_grow(void)
3221 : : {
3222 : : struct spdk_blob_store *bs;
3223 : : struct spdk_bs_dev *dev;
3224 : 12 : struct spdk_bs_super_block super_block;
3225 : 12 : struct spdk_bs_opts opts;
3226 : 12 : struct spdk_bs_md_mask mask;
3227 : : uint64_t bdev_size;
3228 : :
3229 : 12 : dev = init_dev();
3230 : 12 : bdev_size = dev->blockcnt * dev->blocklen;
3231 : 12 : spdk_bs_opts_init(&opts, sizeof(opts));
3232 : 12 : spdk_bs_init(dev, &opts, bs_op_with_handle_complete, NULL);
3233 : 12 : poll_threads();
3234 : 12 : CU_ASSERT(g_bserrno == 0);
3235 [ - + ]: 12 : SPDK_CU_ASSERT_FATAL(g_bs != NULL);
3236 : 12 : bs = g_bs;
3237 : :
3238 : 12 : spdk_bs_unload(bs, bs_op_complete, NULL);
3239 : 12 : poll_threads();
3240 : 12 : CU_ASSERT(g_bserrno == 0);
3241 : 12 : g_bs = NULL;
3242 : :
3243 : : /*
3244 : : * To make sure all the metadata are updated to the disk,
3245 : : * we check the g_dev_buffer after spdk_bs_unload.
3246 : : */
3247 : 12 : memcpy(&super_block, g_dev_buffer, sizeof(struct spdk_bs_super_block));
3248 : 12 : CU_ASSERT(super_block.size == bdev_size);
3249 : :
3250 : : /*
3251 : : * Make sure the used_cluster mask is correct.
3252 : : */
3253 : 12 : memcpy(&mask, g_dev_buffer + super_block.used_cluster_mask_start * 4096,
3254 : : sizeof(struct spdk_bs_md_mask));
3255 : 12 : CU_ASSERT(mask.type == SPDK_MD_MASK_TYPE_USED_CLUSTERS);
3256 : 12 : CU_ASSERT(mask.length == bdev_size / (1 * 1024 * 1024));
3257 : :
3258 : : /*
3259 : : * The default dev size is 64M, here we set the dev size to 128M,
3260 : : * then the blobstore will adjust the metadata according to the new size.
3261 : : * The dev size is larger than the g_dev_buffer size, so we set clear_method
3262 : : * to NONE, or the blobstore will try to clear the dev and will write beyond
3263 : : * the end of g_dev_buffer.
3264 : : */
3265 : 12 : dev = init_dev();
3266 [ - + ]: 12 : dev->blockcnt = (128L * 1024L * 1024L) / dev->blocklen;
3267 : 12 : bdev_size = dev->blockcnt * dev->blocklen;
3268 : 12 : spdk_bs_opts_init(&opts, sizeof(opts));
3269 : 12 : opts.clear_method = BS_CLEAR_WITH_NONE;
3270 : 12 : spdk_bs_grow(dev, &opts, bs_op_with_handle_complete, NULL);
3271 : 12 : poll_threads();
3272 : 12 : CU_ASSERT(g_bserrno == 0);
3273 [ - + ]: 12 : SPDK_CU_ASSERT_FATAL(g_bs != NULL);
3274 : 12 : bs = g_bs;
3275 : :
3276 : : /*
3277 : : * After spdk_bs_grow, all metadata are updated to the disk.
3278 : : * So we can check g_dev_buffer now.
3279 : : */
3280 : 12 : memcpy(&super_block, g_dev_buffer, sizeof(struct spdk_bs_super_block));
3281 : 12 : CU_ASSERT(super_block.size == bdev_size);
3282 : :
3283 : : /*
3284 : : * Make sure the used_cluster mask has been updated according to the bdev size
3285 : : */
3286 : 12 : memcpy(&mask, g_dev_buffer + super_block.used_cluster_mask_start * 4096,
3287 : : sizeof(struct spdk_bs_md_mask));
3288 : 12 : CU_ASSERT(mask.type == SPDK_MD_MASK_TYPE_USED_CLUSTERS);
3289 : 12 : CU_ASSERT(mask.length == bdev_size / (1 * 1024 * 1024));
3290 : :
3291 : 12 : spdk_bs_unload(bs, bs_op_complete, NULL);
3292 : 12 : poll_threads();
3293 : 12 : CU_ASSERT(g_bserrno == 0);
3294 : 12 : g_bs = NULL;
3295 : 12 : }
3296 : :
3297 : : /*
3298 : : * Create a blobstore and then unload it.
3299 : : */
3300 : : static void
3301 : 12 : bs_unload(void)
3302 : : {
3303 : 12 : struct spdk_blob_store *bs = g_bs;
3304 : : struct spdk_blob *blob;
3305 : :
3306 : : /* Create a blob and open it. */
3307 : 12 : blob = ut_blob_create_and_open(bs, NULL);
3308 : :
3309 : : /* Try to unload blobstore, should fail with open blob */
3310 : 12 : g_bserrno = -1;
3311 : 12 : spdk_bs_unload(bs, bs_op_complete, NULL);
3312 : 12 : poll_threads();
3313 : 12 : CU_ASSERT(g_bserrno == -EBUSY);
3314 [ - + ]: 12 : SPDK_CU_ASSERT_FATAL(g_bs != NULL);
3315 : :
3316 : : /* Close the blob, then successfully unload blobstore */
3317 : 12 : g_bserrno = -1;
3318 : 12 : spdk_blob_close(blob, blob_op_complete, NULL);
3319 : 12 : poll_threads();
3320 : 12 : CU_ASSERT(g_bserrno == 0);
3321 : 12 : }
3322 : :
3323 : : /*
3324 : : * Create a blobstore with a cluster size different than the default, and ensure it is
3325 : : * persisted.
3326 : : */
3327 : : static void
3328 : 12 : bs_cluster_sz(void)
3329 : : {
3330 : 12 : struct spdk_blob_store *bs;
3331 : : struct spdk_bs_dev *dev;
3332 : 12 : struct spdk_bs_opts opts;
3333 : : uint32_t cluster_sz;
3334 : :
3335 : : /* Set cluster size to zero */
3336 : 12 : dev = init_dev();
3337 : 12 : spdk_bs_opts_init(&opts, sizeof(opts));
3338 : 12 : opts.cluster_sz = 0;
3339 : :
3340 : : /* Initialize a new blob store */
3341 : 12 : spdk_bs_init(dev, &opts, bs_op_with_handle_complete, NULL);
3342 : 12 : poll_threads();
3343 : 12 : CU_ASSERT(g_bserrno == -EINVAL);
3344 [ - + ]: 12 : SPDK_CU_ASSERT_FATAL(g_bs == NULL);
3345 : :
3346 : : /*
3347 : : * Set cluster size to blobstore page size,
3348 : : * to work it is required to be at least twice the blobstore page size.
3349 : : */
3350 : 12 : dev = init_dev();
3351 : 12 : spdk_bs_opts_init(&opts, sizeof(opts));
3352 : 12 : opts.cluster_sz = SPDK_BS_PAGE_SIZE;
3353 : :
3354 : : /* Initialize a new blob store */
3355 : 12 : spdk_bs_init(dev, &opts, bs_op_with_handle_complete, NULL);
3356 : 12 : poll_threads();
3357 : 12 : CU_ASSERT(g_bserrno == -ENOMEM);
3358 [ - + ]: 12 : SPDK_CU_ASSERT_FATAL(g_bs == NULL);
3359 : :
3360 : : /*
3361 : : * Set cluster size to lower than page size,
3362 : : * to work it is required to be at least twice the blobstore page size.
3363 : : */
3364 : 12 : dev = init_dev();
3365 : 12 : spdk_bs_opts_init(&opts, sizeof(opts));
3366 : 12 : opts.cluster_sz = SPDK_BS_PAGE_SIZE - 1;
3367 : :
3368 : : /* Initialize a new blob store */
3369 : 12 : spdk_bs_init(dev, &opts, bs_op_with_handle_complete, NULL);
3370 : 12 : poll_threads();
3371 : 12 : CU_ASSERT(g_bserrno == -EINVAL);
3372 [ - + ]: 12 : SPDK_CU_ASSERT_FATAL(g_bs == NULL);
3373 : :
3374 : : /* Set cluster size to twice the default */
3375 : 12 : dev = init_dev();
3376 : 12 : spdk_bs_opts_init(&opts, sizeof(opts));
3377 : 12 : opts.cluster_sz *= 2;
3378 : 12 : cluster_sz = opts.cluster_sz;
3379 : :
3380 : : /* Initialize a new blob store */
3381 : 12 : spdk_bs_init(dev, &opts, bs_op_with_handle_complete, NULL);
3382 : 12 : poll_threads();
3383 : 12 : CU_ASSERT(g_bserrno == 0);
3384 [ - + ]: 12 : SPDK_CU_ASSERT_FATAL(g_bs != NULL);
3385 : 12 : bs = g_bs;
3386 : :
3387 : 12 : CU_ASSERT(spdk_bs_get_cluster_size(bs) == cluster_sz);
3388 : :
3389 : 12 : ut_bs_reload(&bs, &opts);
3390 : :
3391 : 12 : CU_ASSERT(spdk_bs_get_cluster_size(bs) == cluster_sz);
3392 : :
3393 : 12 : spdk_bs_unload(bs, bs_op_complete, NULL);
3394 : 12 : poll_threads();
3395 : 12 : CU_ASSERT(g_bserrno == 0);
3396 : 12 : g_bs = NULL;
3397 : 12 : }
3398 : :
3399 : : /*
3400 : : * Create a blobstore, reload it and ensure total usable cluster count
3401 : : * stays the same.
3402 : : */
3403 : : static void
3404 : 12 : bs_usable_clusters(void)
3405 : : {
3406 : 12 : struct spdk_blob_store *bs = g_bs;
3407 : : struct spdk_blob *blob;
3408 : : uint32_t clusters;
3409 : : int i;
3410 : :
3411 : :
3412 : 12 : clusters = spdk_bs_total_data_cluster_count(bs);
3413 : :
3414 : 12 : ut_bs_reload(&bs, NULL);
3415 : :
3416 : 12 : CU_ASSERT(spdk_bs_total_data_cluster_count(bs) == clusters);
3417 : :
3418 : : /* Create and resize blobs to make sure that useable cluster count won't change */
3419 [ + + ]: 60 : for (i = 0; i < 4; i++) {
3420 : 48 : g_bserrno = -1;
3421 : 48 : g_blobid = SPDK_BLOBID_INVALID;
3422 : 48 : blob = ut_blob_create_and_open(bs, NULL);
3423 : :
3424 : 48 : spdk_blob_resize(blob, 10, blob_op_complete, NULL);
3425 : 48 : poll_threads();
3426 : 48 : CU_ASSERT(g_bserrno == 0);
3427 : :
3428 : 48 : g_bserrno = -1;
3429 : 48 : spdk_blob_close(blob, blob_op_complete, NULL);
3430 : 48 : poll_threads();
3431 : 48 : CU_ASSERT(g_bserrno == 0);
3432 : :
3433 : 48 : CU_ASSERT(spdk_bs_total_data_cluster_count(bs) == clusters);
3434 : : }
3435 : :
3436 : : /* Reload the blob store to make sure that nothing changed */
3437 : 12 : ut_bs_reload(&bs, NULL);
3438 : :
3439 : 12 : CU_ASSERT(spdk_bs_total_data_cluster_count(bs) == clusters);
3440 : 12 : }
3441 : :
3442 : : /*
3443 : : * Test resizing of the metadata blob. This requires creating enough blobs
3444 : : * so that one cluster is not enough to fit the metadata for those blobs.
3445 : : * To induce this condition to happen more quickly, we reduce the cluster
3446 : : * size to 16KB, which means only 4 4KB blob metadata pages can fit.
3447 : : */
3448 : : static void
3449 : 12 : bs_resize_md(void)
3450 : 12 : {
3451 : 12 : struct spdk_blob_store *bs;
3452 : 12 : const int CLUSTER_PAGE_COUNT = 4;
3453 : 12 : const int NUM_BLOBS = CLUSTER_PAGE_COUNT * 4;
3454 : : struct spdk_bs_dev *dev;
3455 : 12 : struct spdk_bs_opts opts;
3456 : : struct spdk_blob *blob;
3457 : 12 : struct spdk_blob_opts blob_opts;
3458 : : uint32_t cluster_sz;
3459 [ - + ]: 12 : spdk_blob_id blobids[NUM_BLOBS];
3460 : : int i;
3461 : :
3462 : :
3463 : 12 : dev = init_dev();
3464 : 12 : spdk_bs_opts_init(&opts, sizeof(opts));
3465 : 12 : opts.cluster_sz = CLUSTER_PAGE_COUNT * 4096;
3466 : 12 : cluster_sz = opts.cluster_sz;
3467 : :
3468 : : /* Initialize a new blob store */
3469 : 12 : spdk_bs_init(dev, &opts, bs_op_with_handle_complete, NULL);
3470 : 12 : poll_threads();
3471 : 12 : CU_ASSERT(g_bserrno == 0);
3472 [ - + ]: 12 : SPDK_CU_ASSERT_FATAL(g_bs != NULL);
3473 : 12 : bs = g_bs;
3474 : :
3475 : 12 : CU_ASSERT(spdk_bs_get_cluster_size(bs) == cluster_sz);
3476 : :
3477 : 12 : ut_spdk_blob_opts_init(&blob_opts);
3478 : :
3479 [ + + ]: 204 : for (i = 0; i < NUM_BLOBS; i++) {
3480 : 192 : g_bserrno = -1;
3481 : 192 : g_blobid = SPDK_BLOBID_INVALID;
3482 : 192 : spdk_bs_create_blob_ext(bs, &blob_opts, blob_op_with_id_complete, NULL);
3483 : 192 : poll_threads();
3484 : 192 : CU_ASSERT(g_bserrno == 0);
3485 : 192 : CU_ASSERT(g_blobid != SPDK_BLOBID_INVALID);
3486 : 192 : blobids[i] = g_blobid;
3487 : : }
3488 : :
3489 : 12 : ut_bs_reload(&bs, &opts);
3490 : :
3491 : 12 : CU_ASSERT(spdk_bs_get_cluster_size(bs) == cluster_sz);
3492 : :
3493 [ + + ]: 204 : for (i = 0; i < NUM_BLOBS; i++) {
3494 : 192 : g_bserrno = -1;
3495 : 192 : g_blob = NULL;
3496 : 192 : spdk_bs_open_blob(bs, blobids[i], blob_op_with_handle_complete, NULL);
3497 : 192 : poll_threads();
3498 : 192 : CU_ASSERT(g_bserrno == 0);
3499 : 192 : CU_ASSERT(g_blob != NULL);
3500 : 192 : blob = g_blob;
3501 : 192 : g_bserrno = -1;
3502 : 192 : spdk_blob_close(blob, blob_op_complete, NULL);
3503 : 192 : poll_threads();
3504 : 192 : CU_ASSERT(g_bserrno == 0);
3505 : : }
3506 : :
3507 : 12 : spdk_bs_unload(bs, bs_op_complete, NULL);
3508 : 12 : poll_threads();
3509 : 12 : CU_ASSERT(g_bserrno == 0);
3510 : 12 : g_bs = NULL;
3511 : 12 : }
3512 : :
3513 : : static void
3514 : 12 : bs_destroy(void)
3515 : : {
3516 : : struct spdk_blob_store *bs;
3517 : : struct spdk_bs_dev *dev;
3518 : :
3519 : : /* Initialize a new blob store */
3520 : 12 : dev = init_dev();
3521 : 12 : spdk_bs_init(dev, NULL, bs_op_with_handle_complete, NULL);
3522 : 12 : poll_threads();
3523 : 12 : CU_ASSERT(g_bserrno == 0);
3524 [ - + ]: 12 : SPDK_CU_ASSERT_FATAL(g_bs != NULL);
3525 : 12 : bs = g_bs;
3526 : :
3527 : : /* Destroy the blob store */
3528 : 12 : g_bserrno = -1;
3529 : 12 : spdk_bs_destroy(bs, bs_op_complete, NULL);
3530 : 12 : poll_threads();
3531 : 12 : CU_ASSERT(g_bserrno == 0);
3532 : :
3533 : : /* Loading an non-existent blob store should fail. */
3534 : 12 : g_bs = NULL;
3535 : 12 : dev = init_dev();
3536 : :
3537 : 12 : g_bserrno = 0;
3538 : 12 : spdk_bs_load(dev, NULL, bs_op_with_handle_complete, NULL);
3539 : 12 : poll_threads();
3540 : 12 : CU_ASSERT(g_bserrno != 0);
3541 : 12 : }
3542 : :
3543 : : /* Try to hit all of the corner cases associated with serializing
3544 : : * a blob to disk
3545 : : */
3546 : : static void
3547 : 12 : blob_serialize_test(void)
3548 : : {
3549 : : struct spdk_bs_dev *dev;
3550 : 12 : struct spdk_bs_opts opts;
3551 : 12 : struct spdk_blob_store *bs;
3552 : 12 : spdk_blob_id blobid[2];
3553 : 12 : struct spdk_blob *blob[2];
3554 : : uint64_t i;
3555 : : char *value;
3556 : : int rc;
3557 : :
3558 : 12 : dev = init_dev();
3559 : :
3560 : : /* Initialize a new blobstore with very small clusters */
3561 : 12 : spdk_bs_opts_init(&opts, sizeof(opts));
3562 : 12 : opts.cluster_sz = dev->blocklen * 8;
3563 : 12 : spdk_bs_init(dev, &opts, bs_op_with_handle_complete, NULL);
3564 : 12 : poll_threads();
3565 : 12 : CU_ASSERT(g_bserrno == 0);
3566 [ - + ]: 12 : SPDK_CU_ASSERT_FATAL(g_bs != NULL);
3567 : 12 : bs = g_bs;
3568 : :
3569 : : /* Create and open two blobs */
3570 [ + + ]: 36 : for (i = 0; i < 2; i++) {
3571 : 24 : blob[i] = ut_blob_create_and_open(bs, NULL);
3572 : 24 : blobid[i] = spdk_blob_get_id(blob[i]);
3573 : :
3574 : : /* Set a fairly large xattr on both blobs to eat up
3575 : : * metadata space
3576 : : */
3577 : 24 : value = calloc(dev->blocklen - 64, sizeof(char));
3578 [ - + ]: 24 : SPDK_CU_ASSERT_FATAL(value != NULL);
3579 [ - + ]: 24 : memset(value, i, dev->blocklen / 2);
3580 : 24 : rc = spdk_blob_set_xattr(blob[i], "name", value, dev->blocklen - 64);
3581 : 24 : CU_ASSERT(rc == 0);
3582 : 24 : free(value);
3583 : : }
3584 : :
3585 : : /* Resize the blobs, alternating 1 cluster at a time.
3586 : : * This thwarts run length encoding and will cause spill
3587 : : * over of the extents.
3588 : : */
3589 [ + + ]: 84 : for (i = 0; i < 6; i++) {
3590 : 72 : spdk_blob_resize(blob[i % 2], (i / 2) + 1, blob_op_complete, NULL);
3591 : 72 : poll_threads();
3592 : 72 : CU_ASSERT(g_bserrno == 0);
3593 : : }
3594 : :
3595 [ + + ]: 36 : for (i = 0; i < 2; i++) {
3596 : 24 : spdk_blob_sync_md(blob[i], blob_op_complete, NULL);
3597 : 24 : poll_threads();
3598 : 24 : CU_ASSERT(g_bserrno == 0);
3599 : : }
3600 : :
3601 : : /* Close the blobs */
3602 [ + + ]: 36 : for (i = 0; i < 2; i++) {
3603 : 24 : spdk_blob_close(blob[i], blob_op_complete, NULL);
3604 : 24 : poll_threads();
3605 : 24 : CU_ASSERT(g_bserrno == 0);
3606 : : }
3607 : :
3608 : 12 : ut_bs_reload(&bs, &opts);
3609 : :
3610 [ + + ]: 36 : for (i = 0; i < 2; i++) {
3611 : 24 : blob[i] = NULL;
3612 : :
3613 : 24 : spdk_bs_open_blob(bs, blobid[i], blob_op_with_handle_complete, NULL);
3614 : 24 : poll_threads();
3615 : 24 : CU_ASSERT(g_bserrno == 0);
3616 : 24 : CU_ASSERT(g_blob != NULL);
3617 : 24 : blob[i] = g_blob;
3618 : :
3619 : 24 : CU_ASSERT(spdk_blob_get_num_clusters(blob[i]) == 3);
3620 : :
3621 : 24 : spdk_blob_close(blob[i], blob_op_complete, NULL);
3622 : 24 : poll_threads();
3623 : 24 : CU_ASSERT(g_bserrno == 0);
3624 : : }
3625 : :
3626 : 12 : spdk_bs_unload(bs, bs_op_complete, NULL);
3627 : 12 : poll_threads();
3628 : 12 : CU_ASSERT(g_bserrno == 0);
3629 : 12 : g_bs = NULL;
3630 : 12 : }
3631 : :
3632 : : static void
3633 : 12 : blob_crc(void)
3634 : : {
3635 : 12 : struct spdk_blob_store *bs = g_bs;
3636 : : struct spdk_blob *blob;
3637 : : spdk_blob_id blobid;
3638 : : uint32_t page_num;
3639 : : int index;
3640 : : struct spdk_blob_md_page *page;
3641 : :
3642 : 12 : blob = ut_blob_create_and_open(bs, NULL);
3643 : 12 : blobid = spdk_blob_get_id(blob);
3644 : :
3645 : 12 : spdk_blob_close(blob, blob_op_complete, NULL);
3646 : 12 : poll_threads();
3647 : 12 : CU_ASSERT(g_bserrno == 0);
3648 : :
3649 : 12 : page_num = bs_blobid_to_page(blobid);
3650 : 12 : index = DEV_BUFFER_BLOCKLEN * (bs->md_start + page_num);
3651 : 12 : page = (struct spdk_blob_md_page *)&g_dev_buffer[index];
3652 : 12 : page->crc = 0;
3653 : :
3654 : 12 : spdk_bs_open_blob(bs, blobid, blob_op_with_handle_complete, NULL);
3655 : 12 : poll_threads();
3656 : 12 : CU_ASSERT(g_bserrno == -EINVAL);
3657 : 12 : CU_ASSERT(g_blob == NULL);
3658 : 12 : g_bserrno = 0;
3659 : :
3660 : 12 : spdk_bs_delete_blob(bs, blobid, blob_op_complete, NULL);
3661 : 12 : poll_threads();
3662 : 12 : CU_ASSERT(g_bserrno == -EINVAL);
3663 : 12 : }
3664 : :
3665 : : static void
3666 : 12 : super_block_crc(void)
3667 : : {
3668 : : struct spdk_blob_store *bs;
3669 : : struct spdk_bs_dev *dev;
3670 : : struct spdk_bs_super_block *super_block;
3671 : :
3672 : 12 : dev = init_dev();
3673 : 12 : spdk_bs_init(dev, NULL, bs_op_with_handle_complete, NULL);
3674 : 12 : poll_threads();
3675 : 12 : CU_ASSERT(g_bserrno == 0);
3676 [ - + ]: 12 : SPDK_CU_ASSERT_FATAL(g_bs != NULL);
3677 : 12 : bs = g_bs;
3678 : :
3679 : 12 : spdk_bs_unload(bs, bs_op_complete, NULL);
3680 : 12 : poll_threads();
3681 : 12 : CU_ASSERT(g_bserrno == 0);
3682 : 12 : g_bs = NULL;
3683 : :
3684 : 12 : super_block = (struct spdk_bs_super_block *)g_dev_buffer;
3685 : 12 : super_block->crc = 0;
3686 : 12 : dev = init_dev();
3687 : :
3688 : : /* Load an existing blob store */
3689 : 12 : g_bserrno = 0;
3690 : 12 : spdk_bs_load(dev, NULL, bs_op_with_handle_complete, NULL);
3691 : 12 : poll_threads();
3692 : 12 : CU_ASSERT(g_bserrno == -EILSEQ);
3693 : 12 : }
3694 : :
3695 : : /* For blob dirty shutdown test case we do the following sub-test cases:
3696 : : * 1 Initialize new blob store and create 1 super blob with some xattrs, then we
3697 : : * dirty shutdown and reload the blob store and verify the xattrs.
3698 : : * 2 Resize the blob from 10 clusters to 20 clusters and then dirty shutdown,
3699 : : * reload the blob store and verify the clusters number.
3700 : : * 3 Create the second blob and then dirty shutdown, reload the blob store
3701 : : * and verify the second blob.
3702 : : * 4 Delete the second blob and then dirty shutdown, reload the blob store
3703 : : * and verify the second blob is invalid.
3704 : : * 5 Create the second blob again and also create the third blob, modify the
3705 : : * md of second blob which makes the md invalid, and then dirty shutdown,
3706 : : * reload the blob store verify the second blob, it should invalid and also
3707 : : * verify the third blob, it should correct.
3708 : : */
3709 : : static void
3710 : 12 : blob_dirty_shutdown(void)
3711 : : {
3712 : : int rc;
3713 : : int index;
3714 : 12 : struct spdk_blob_store *bs = g_bs;
3715 : : spdk_blob_id blobid1, blobid2, blobid3;
3716 : 12 : struct spdk_blob *blob = g_blob;
3717 : 12 : uint64_t length;
3718 : : uint64_t free_clusters;
3719 : 12 : const void *value;
3720 : 12 : size_t value_len;
3721 : : uint32_t page_num;
3722 : : struct spdk_blob_md_page *page;
3723 : 12 : struct spdk_blob_opts blob_opts;
3724 : :
3725 : : /* Create first blob */
3726 : 12 : blobid1 = spdk_blob_get_id(blob);
3727 : :
3728 : : /* Set some xattrs */
3729 : 12 : rc = spdk_blob_set_xattr(blob, "name", "log.txt", strlen("log.txt") + 1);
3730 : 12 : CU_ASSERT(rc == 0);
3731 : :
3732 : 12 : length = 2345;
3733 : 12 : rc = spdk_blob_set_xattr(blob, "length", &length, sizeof(length));
3734 : 12 : CU_ASSERT(rc == 0);
3735 : :
3736 : : /* Put xattr that fits exactly single page.
3737 : : * This results in adding additional pages to MD.
3738 : : * First is flags and smaller xattr, second the large xattr,
3739 : : * third are just the extents.
3740 : : */
3741 : 12 : size_t xattr_length = 4072 - sizeof(struct spdk_blob_md_descriptor_xattr) -
3742 : : strlen("large_xattr");
3743 : 12 : char *xattr = calloc(xattr_length, sizeof(char));
3744 [ - + ]: 12 : SPDK_CU_ASSERT_FATAL(xattr != NULL);
3745 : 12 : rc = spdk_blob_set_xattr(blob, "large_xattr", xattr, xattr_length);
3746 : 12 : free(xattr);
3747 [ - + ]: 12 : SPDK_CU_ASSERT_FATAL(rc == 0);
3748 : :
3749 : : /* Resize the blob */
3750 : 12 : spdk_blob_resize(blob, 10, blob_op_complete, NULL);
3751 : 12 : poll_threads();
3752 : 12 : CU_ASSERT(g_bserrno == 0);
3753 : :
3754 : : /* Set the blob as the super blob */
3755 : 12 : spdk_bs_set_super(bs, blobid1, blob_op_complete, NULL);
3756 : 12 : poll_threads();
3757 : 12 : CU_ASSERT(g_bserrno == 0);
3758 : :
3759 : 12 : free_clusters = spdk_bs_free_cluster_count(bs);
3760 : :
3761 : 12 : spdk_blob_close(blob, blob_op_complete, NULL);
3762 : 12 : poll_threads();
3763 : 12 : CU_ASSERT(g_bserrno == 0);
3764 : 12 : blob = NULL;
3765 : 12 : g_blob = NULL;
3766 : 12 : g_blobid = SPDK_BLOBID_INVALID;
3767 : :
3768 : 12 : ut_bs_dirty_load(&bs, NULL);
3769 : :
3770 : : /* Get the super blob */
3771 : 12 : spdk_bs_get_super(bs, blob_op_with_id_complete, NULL);
3772 : 12 : poll_threads();
3773 : 12 : CU_ASSERT(g_bserrno == 0);
3774 : 12 : CU_ASSERT(blobid1 == g_blobid);
3775 : :
3776 : 12 : spdk_bs_open_blob(bs, blobid1, blob_op_with_handle_complete, NULL);
3777 : 12 : poll_threads();
3778 : 12 : CU_ASSERT(g_bserrno == 0);
3779 : 12 : CU_ASSERT(g_blob != NULL);
3780 : 12 : blob = g_blob;
3781 : :
3782 : 12 : CU_ASSERT(free_clusters == spdk_bs_free_cluster_count(bs));
3783 : :
3784 : : /* Get the xattrs */
3785 : 12 : value = NULL;
3786 : 12 : rc = spdk_blob_get_xattr_value(blob, "length", &value, &value_len);
3787 : 12 : CU_ASSERT(rc == 0);
3788 [ - + ]: 12 : SPDK_CU_ASSERT_FATAL(value != NULL);
3789 : 12 : CU_ASSERT(*(uint64_t *)value == length);
3790 : 12 : CU_ASSERT(value_len == 8);
3791 : 12 : CU_ASSERT(spdk_blob_get_num_clusters(blob) == 10);
3792 : :
3793 : : /* Resize the blob */
3794 : 12 : spdk_blob_resize(blob, 20, blob_op_complete, NULL);
3795 : 12 : poll_threads();
3796 : 12 : CU_ASSERT(g_bserrno == 0);
3797 : :
3798 : 12 : free_clusters = spdk_bs_free_cluster_count(bs);
3799 : :
3800 : 12 : spdk_blob_close(blob, blob_op_complete, NULL);
3801 : 12 : poll_threads();
3802 : 12 : CU_ASSERT(g_bserrno == 0);
3803 : 12 : blob = NULL;
3804 : 12 : g_blob = NULL;
3805 : 12 : g_blobid = SPDK_BLOBID_INVALID;
3806 : :
3807 : 12 : ut_bs_dirty_load(&bs, NULL);
3808 : :
3809 : 12 : spdk_bs_open_blob(bs, blobid1, blob_op_with_handle_complete, NULL);
3810 : 12 : poll_threads();
3811 : 12 : CU_ASSERT(g_bserrno == 0);
3812 : 12 : CU_ASSERT(g_blob != NULL);
3813 : 12 : blob = g_blob;
3814 : 12 : CU_ASSERT(spdk_blob_get_num_clusters(blob) == 20);
3815 : 12 : CU_ASSERT(free_clusters == spdk_bs_free_cluster_count(bs));
3816 : :
3817 : 12 : spdk_blob_close(blob, blob_op_complete, NULL);
3818 : 12 : poll_threads();
3819 : 12 : CU_ASSERT(g_bserrno == 0);
3820 : 12 : blob = NULL;
3821 : 12 : g_blob = NULL;
3822 : 12 : g_blobid = SPDK_BLOBID_INVALID;
3823 : :
3824 : : /* Create second blob */
3825 : 12 : blob = ut_blob_create_and_open(bs, NULL);
3826 : 12 : blobid2 = spdk_blob_get_id(blob);
3827 : :
3828 : : /* Set some xattrs */
3829 : 12 : rc = spdk_blob_set_xattr(blob, "name", "log1.txt", strlen("log1.txt") + 1);
3830 : 12 : CU_ASSERT(rc == 0);
3831 : :
3832 : 12 : length = 5432;
3833 : 12 : rc = spdk_blob_set_xattr(blob, "length", &length, sizeof(length));
3834 : 12 : CU_ASSERT(rc == 0);
3835 : :
3836 : : /* Resize the blob */
3837 : 12 : spdk_blob_resize(blob, 10, blob_op_complete, NULL);
3838 : 12 : poll_threads();
3839 : 12 : CU_ASSERT(g_bserrno == 0);
3840 : :
3841 : 12 : free_clusters = spdk_bs_free_cluster_count(bs);
3842 : :
3843 : 12 : spdk_blob_close(blob, blob_op_complete, NULL);
3844 : 12 : poll_threads();
3845 : 12 : CU_ASSERT(g_bserrno == 0);
3846 : 12 : blob = NULL;
3847 : 12 : g_blob = NULL;
3848 : 12 : g_blobid = SPDK_BLOBID_INVALID;
3849 : :
3850 : 12 : ut_bs_dirty_load(&bs, NULL);
3851 : :
3852 : 12 : spdk_bs_open_blob(bs, blobid2, blob_op_with_handle_complete, NULL);
3853 : 12 : poll_threads();
3854 : 12 : CU_ASSERT(g_bserrno == 0);
3855 : 12 : CU_ASSERT(g_blob != NULL);
3856 : 12 : blob = g_blob;
3857 : :
3858 : : /* Get the xattrs */
3859 : 12 : value = NULL;
3860 : 12 : rc = spdk_blob_get_xattr_value(blob, "length", &value, &value_len);
3861 : 12 : CU_ASSERT(rc == 0);
3862 [ - + ]: 12 : SPDK_CU_ASSERT_FATAL(value != NULL);
3863 : 12 : CU_ASSERT(*(uint64_t *)value == length);
3864 : 12 : CU_ASSERT(value_len == 8);
3865 : 12 : CU_ASSERT(spdk_blob_get_num_clusters(blob) == 10);
3866 : 12 : CU_ASSERT(free_clusters == spdk_bs_free_cluster_count(bs));
3867 : :
3868 : 12 : ut_blob_close_and_delete(bs, blob);
3869 : :
3870 : 12 : free_clusters = spdk_bs_free_cluster_count(bs);
3871 : :
3872 : 12 : ut_bs_dirty_load(&bs, NULL);
3873 : :
3874 : 12 : spdk_bs_open_blob(bs, blobid2, blob_op_with_handle_complete, NULL);
3875 : 12 : poll_threads();
3876 : 12 : CU_ASSERT(g_bserrno != 0);
3877 : 12 : CU_ASSERT(g_blob == NULL);
3878 : :
3879 : 12 : spdk_bs_open_blob(bs, blobid1, blob_op_with_handle_complete, NULL);
3880 : 12 : poll_threads();
3881 : 12 : CU_ASSERT(g_bserrno == 0);
3882 : 12 : CU_ASSERT(g_blob != NULL);
3883 : 12 : blob = g_blob;
3884 : 12 : CU_ASSERT(free_clusters == spdk_bs_free_cluster_count(bs));
3885 : 12 : spdk_blob_close(blob, blob_op_complete, NULL);
3886 : 12 : poll_threads();
3887 : 12 : CU_ASSERT(g_bserrno == 0);
3888 : :
3889 : 12 : ut_bs_reload(&bs, NULL);
3890 : :
3891 : : /* Create second blob */
3892 : 12 : ut_spdk_blob_opts_init(&blob_opts);
3893 : 12 : spdk_bs_create_blob_ext(bs, &blob_opts, blob_op_with_id_complete, NULL);
3894 : 12 : poll_threads();
3895 : 12 : CU_ASSERT(g_bserrno == 0);
3896 : 12 : CU_ASSERT(g_blobid != SPDK_BLOBID_INVALID);
3897 : 12 : blobid2 = g_blobid;
3898 : :
3899 : : /* Create third blob */
3900 : 12 : spdk_bs_create_blob_ext(bs, &blob_opts, blob_op_with_id_complete, NULL);
3901 : 12 : poll_threads();
3902 : 12 : CU_ASSERT(g_bserrno == 0);
3903 : 12 : CU_ASSERT(g_blobid != SPDK_BLOBID_INVALID);
3904 : 12 : blobid3 = g_blobid;
3905 : :
3906 : 12 : spdk_bs_open_blob(bs, blobid2, blob_op_with_handle_complete, NULL);
3907 : 12 : poll_threads();
3908 : 12 : CU_ASSERT(g_bserrno == 0);
3909 : 12 : CU_ASSERT(g_blob != NULL);
3910 : 12 : blob = g_blob;
3911 : :
3912 : : /* Set some xattrs for second blob */
3913 : 12 : rc = spdk_blob_set_xattr(blob, "name", "log1.txt", strlen("log1.txt") + 1);
3914 : 12 : CU_ASSERT(rc == 0);
3915 : :
3916 : 12 : length = 5432;
3917 : 12 : rc = spdk_blob_set_xattr(blob, "length", &length, sizeof(length));
3918 : 12 : CU_ASSERT(rc == 0);
3919 : :
3920 : 12 : spdk_blob_close(blob, blob_op_complete, NULL);
3921 : 12 : poll_threads();
3922 : 12 : CU_ASSERT(g_bserrno == 0);
3923 : 12 : blob = NULL;
3924 : 12 : g_blob = NULL;
3925 : 12 : g_blobid = SPDK_BLOBID_INVALID;
3926 : :
3927 : 12 : spdk_bs_open_blob(bs, blobid3, blob_op_with_handle_complete, NULL);
3928 : 12 : poll_threads();
3929 : 12 : CU_ASSERT(g_bserrno == 0);
3930 : 12 : CU_ASSERT(g_blob != NULL);
3931 : 12 : blob = g_blob;
3932 : :
3933 : : /* Set some xattrs for third blob */
3934 : 12 : rc = spdk_blob_set_xattr(blob, "name", "log2.txt", strlen("log2.txt") + 1);
3935 : 12 : CU_ASSERT(rc == 0);
3936 : :
3937 : 12 : length = 5432;
3938 : 12 : rc = spdk_blob_set_xattr(blob, "length", &length, sizeof(length));
3939 : 12 : CU_ASSERT(rc == 0);
3940 : :
3941 : 12 : spdk_blob_close(blob, blob_op_complete, NULL);
3942 : 12 : poll_threads();
3943 : 12 : CU_ASSERT(g_bserrno == 0);
3944 : 12 : blob = NULL;
3945 : 12 : g_blob = NULL;
3946 : 12 : g_blobid = SPDK_BLOBID_INVALID;
3947 : :
3948 : : /* Mark second blob as invalid */
3949 : 12 : page_num = bs_blobid_to_page(blobid2);
3950 : :
3951 : 12 : index = DEV_BUFFER_BLOCKLEN * (bs->md_start + page_num);
3952 : 12 : page = (struct spdk_blob_md_page *)&g_dev_buffer[index];
3953 : 12 : page->sequence_num = 1;
3954 : 12 : page->crc = blob_md_page_calc_crc(page);
3955 : :
3956 : 12 : free_clusters = spdk_bs_free_cluster_count(bs);
3957 : :
3958 : 12 : ut_bs_dirty_load(&bs, NULL);
3959 : :
3960 : 12 : spdk_bs_open_blob(bs, blobid2, blob_op_with_handle_complete, NULL);
3961 : 12 : poll_threads();
3962 : 12 : CU_ASSERT(g_bserrno != 0);
3963 : 12 : CU_ASSERT(g_blob == NULL);
3964 : :
3965 : 12 : spdk_bs_open_blob(bs, blobid3, blob_op_with_handle_complete, NULL);
3966 : 12 : poll_threads();
3967 : 12 : CU_ASSERT(g_bserrno == 0);
3968 : 12 : CU_ASSERT(g_blob != NULL);
3969 : 12 : blob = g_blob;
3970 : :
3971 : 12 : CU_ASSERT(free_clusters == spdk_bs_free_cluster_count(bs));
3972 : 12 : }
3973 : :
3974 : : static void
3975 : 12 : blob_flags(void)
3976 : : {
3977 : 12 : struct spdk_blob_store *bs = g_bs;
3978 : : spdk_blob_id blobid_invalid, blobid_data_ro, blobid_md_ro;
3979 : : struct spdk_blob *blob_invalid, *blob_data_ro, *blob_md_ro;
3980 : 12 : struct spdk_blob_opts blob_opts;
3981 : : int rc;
3982 : :
3983 : : /* Create three blobs - one each for testing invalid, data_ro and md_ro flags. */
3984 : 12 : blob_invalid = ut_blob_create_and_open(bs, NULL);
3985 : 12 : blobid_invalid = spdk_blob_get_id(blob_invalid);
3986 : :
3987 : 12 : blob_data_ro = ut_blob_create_and_open(bs, NULL);
3988 : 12 : blobid_data_ro = spdk_blob_get_id(blob_data_ro);
3989 : :
3990 : 12 : ut_spdk_blob_opts_init(&blob_opts);
3991 : 12 : blob_opts.clear_method = BLOB_CLEAR_WITH_WRITE_ZEROES;
3992 : 12 : blob_md_ro = ut_blob_create_and_open(bs, &blob_opts);
3993 : 12 : blobid_md_ro = spdk_blob_get_id(blob_md_ro);
3994 : 12 : CU_ASSERT((blob_md_ro->md_ro_flags & SPDK_BLOB_MD_RO_FLAGS_MASK) == BLOB_CLEAR_WITH_WRITE_ZEROES);
3995 : :
3996 : : /* Change the size of blob_data_ro to check if flags are serialized
3997 : : * when blob has non zero number of extents */
3998 : 12 : spdk_blob_resize(blob_data_ro, 10, blob_op_complete, NULL);
3999 : 12 : poll_threads();
4000 : 12 : CU_ASSERT(g_bserrno == 0);
4001 : :
4002 : : /* Set the xattr to check if flags are serialized
4003 : : * when blob has non zero number of xattrs */
4004 : 12 : rc = spdk_blob_set_xattr(blob_md_ro, "name", "log.txt", strlen("log.txt") + 1);
4005 : 12 : CU_ASSERT(rc == 0);
4006 : :
4007 : 12 : blob_invalid->invalid_flags = (1ULL << 63);
4008 : 12 : blob_invalid->state = SPDK_BLOB_STATE_DIRTY;
4009 : 12 : blob_data_ro->data_ro_flags = (1ULL << 62);
4010 : 12 : blob_data_ro->state = SPDK_BLOB_STATE_DIRTY;
4011 : 12 : blob_md_ro->md_ro_flags = (1ULL << 61);
4012 : 12 : blob_md_ro->state = SPDK_BLOB_STATE_DIRTY;
4013 : :
4014 : 12 : g_bserrno = -1;
4015 : 12 : spdk_blob_sync_md(blob_invalid, blob_op_complete, NULL);
4016 : 12 : poll_threads();
4017 : 12 : CU_ASSERT(g_bserrno == 0);
4018 : 12 : g_bserrno = -1;
4019 : 12 : spdk_blob_sync_md(blob_data_ro, blob_op_complete, NULL);
4020 : 12 : poll_threads();
4021 : 12 : CU_ASSERT(g_bserrno == 0);
4022 : 12 : g_bserrno = -1;
4023 : 12 : spdk_blob_sync_md(blob_md_ro, blob_op_complete, NULL);
4024 : 12 : poll_threads();
4025 : 12 : CU_ASSERT(g_bserrno == 0);
4026 : :
4027 : 12 : g_bserrno = -1;
4028 : 12 : spdk_blob_close(blob_invalid, blob_op_complete, NULL);
4029 : 12 : poll_threads();
4030 : 12 : CU_ASSERT(g_bserrno == 0);
4031 : 12 : blob_invalid = NULL;
4032 : 12 : g_bserrno = -1;
4033 : 12 : spdk_blob_close(blob_data_ro, blob_op_complete, NULL);
4034 : 12 : poll_threads();
4035 : 12 : CU_ASSERT(g_bserrno == 0);
4036 : 12 : blob_data_ro = NULL;
4037 : 12 : g_bserrno = -1;
4038 : 12 : spdk_blob_close(blob_md_ro, blob_op_complete, NULL);
4039 : 12 : poll_threads();
4040 : 12 : CU_ASSERT(g_bserrno == 0);
4041 : 12 : blob_md_ro = NULL;
4042 : :
4043 : 12 : g_blob = NULL;
4044 : 12 : g_blobid = SPDK_BLOBID_INVALID;
4045 : :
4046 : 12 : ut_bs_reload(&bs, NULL);
4047 : :
4048 : 12 : g_blob = NULL;
4049 : 12 : g_bserrno = 0;
4050 : 12 : spdk_bs_open_blob(bs, blobid_invalid, blob_op_with_handle_complete, NULL);
4051 : 12 : poll_threads();
4052 : 12 : CU_ASSERT(g_bserrno != 0);
4053 : 12 : CU_ASSERT(g_blob == NULL);
4054 : :
4055 : 12 : g_blob = NULL;
4056 : 12 : g_bserrno = -1;
4057 : 12 : spdk_bs_open_blob(bs, blobid_data_ro, blob_op_with_handle_complete, NULL);
4058 : 12 : poll_threads();
4059 : 12 : CU_ASSERT(g_bserrno == 0);
4060 [ - + ]: 12 : SPDK_CU_ASSERT_FATAL(g_blob != NULL);
4061 : 12 : blob_data_ro = g_blob;
4062 : : /* If an unknown data_ro flag was found, the blob should be marked both data and md read-only. */
4063 [ - + ]: 12 : CU_ASSERT(blob_data_ro->data_ro == true);
4064 [ - + ]: 12 : CU_ASSERT(blob_data_ro->md_ro == true);
4065 : 12 : CU_ASSERT(spdk_blob_get_num_clusters(blob_data_ro) == 10);
4066 : :
4067 : 12 : g_blob = NULL;
4068 : 12 : g_bserrno = -1;
4069 : 12 : spdk_bs_open_blob(bs, blobid_md_ro, blob_op_with_handle_complete, NULL);
4070 : 12 : poll_threads();
4071 : 12 : CU_ASSERT(g_bserrno == 0);
4072 [ - + ]: 12 : SPDK_CU_ASSERT_FATAL(g_blob != NULL);
4073 : 12 : blob_md_ro = g_blob;
4074 [ - + ]: 12 : CU_ASSERT(blob_md_ro->data_ro == false);
4075 [ - + ]: 12 : CU_ASSERT(blob_md_ro->md_ro == true);
4076 : :
4077 : 12 : g_bserrno = -1;
4078 : 12 : spdk_blob_sync_md(blob_md_ro, blob_op_complete, NULL);
4079 : 12 : poll_threads();
4080 : 12 : CU_ASSERT(g_bserrno == 0);
4081 : :
4082 : 12 : ut_blob_close_and_delete(bs, blob_data_ro);
4083 : 12 : ut_blob_close_and_delete(bs, blob_md_ro);
4084 : 12 : }
4085 : :
4086 : : static void
4087 : 12 : bs_version(void)
4088 : : {
4089 : : struct spdk_bs_super_block *super;
4090 : 12 : struct spdk_blob_store *bs = g_bs;
4091 : : struct spdk_bs_dev *dev;
4092 : : struct spdk_blob *blob;
4093 : 12 : struct spdk_blob_opts blob_opts;
4094 : : spdk_blob_id blobid;
4095 : :
4096 : : /* Unload the blob store */
4097 : 12 : spdk_bs_unload(bs, bs_op_complete, NULL);
4098 : 12 : poll_threads();
4099 : 12 : CU_ASSERT(g_bserrno == 0);
4100 : 12 : g_bs = NULL;
4101 : :
4102 : : /*
4103 : : * Change the bs version on disk. This will allow us to
4104 : : * test that the version does not get modified automatically
4105 : : * when loading and unloading the blobstore.
4106 : : */
4107 : 12 : super = (struct spdk_bs_super_block *)&g_dev_buffer[0];
4108 : 12 : CU_ASSERT(super->version == SPDK_BS_VERSION);
4109 : 12 : CU_ASSERT(super->clean == 1);
4110 : 12 : super->version = 2;
4111 : : /*
4112 : : * Version 2 metadata does not have a used blobid mask, so clear
4113 : : * those fields in the super block and zero the corresponding
4114 : : * region on "disk". We will use this to ensure blob IDs are
4115 : : * correctly reconstructed.
4116 : : */
4117 [ - + ]: 12 : memset(&g_dev_buffer[super->used_blobid_mask_start * SPDK_BS_PAGE_SIZE], 0,
4118 : 12 : super->used_blobid_mask_len * SPDK_BS_PAGE_SIZE);
4119 : 12 : super->used_blobid_mask_start = 0;
4120 : 12 : super->used_blobid_mask_len = 0;
4121 : 12 : super->crc = blob_md_page_calc_crc(super);
4122 : :
4123 : : /* Load an existing blob store */
4124 : 12 : dev = init_dev();
4125 : 12 : spdk_bs_load(dev, NULL, bs_op_with_handle_complete, NULL);
4126 : 12 : poll_threads();
4127 : 12 : CU_ASSERT(g_bserrno == 0);
4128 [ - + ]: 12 : SPDK_CU_ASSERT_FATAL(g_bs != NULL);
4129 : 12 : CU_ASSERT(super->clean == 1);
4130 : 12 : bs = g_bs;
4131 : :
4132 : : /*
4133 : : * Create a blob - just to make sure that when we unload it
4134 : : * results in writing the super block (since metadata pages
4135 : : * were allocated.
4136 : : */
4137 : 12 : ut_spdk_blob_opts_init(&blob_opts);
4138 : 12 : spdk_bs_create_blob_ext(bs, &blob_opts, blob_op_with_id_complete, NULL);
4139 : 12 : poll_threads();
4140 : 12 : CU_ASSERT(g_bserrno == 0);
4141 : 12 : CU_ASSERT(g_blobid != SPDK_BLOBID_INVALID);
4142 : 12 : blobid = g_blobid;
4143 : :
4144 : : /* Unload the blob store */
4145 : 12 : spdk_bs_unload(bs, bs_op_complete, NULL);
4146 : 12 : poll_threads();
4147 : 12 : CU_ASSERT(g_bserrno == 0);
4148 : 12 : g_bs = NULL;
4149 : 12 : CU_ASSERT(super->version == 2);
4150 : 12 : CU_ASSERT(super->used_blobid_mask_start == 0);
4151 : 12 : CU_ASSERT(super->used_blobid_mask_len == 0);
4152 : :
4153 : 12 : dev = init_dev();
4154 : 12 : spdk_bs_load(dev, NULL, bs_op_with_handle_complete, NULL);
4155 : 12 : poll_threads();
4156 : 12 : CU_ASSERT(g_bserrno == 0);
4157 [ - + ]: 12 : SPDK_CU_ASSERT_FATAL(g_bs != NULL);
4158 : 12 : bs = g_bs;
4159 : :
4160 : 12 : g_blob = NULL;
4161 : 12 : spdk_bs_open_blob(bs, blobid, blob_op_with_handle_complete, NULL);
4162 : 12 : poll_threads();
4163 : 12 : CU_ASSERT(g_bserrno == 0);
4164 : 12 : CU_ASSERT(g_blob != NULL);
4165 : 12 : blob = g_blob;
4166 : :
4167 : 12 : ut_blob_close_and_delete(bs, blob);
4168 : :
4169 : 12 : CU_ASSERT(super->version == 2);
4170 : 12 : CU_ASSERT(super->used_blobid_mask_start == 0);
4171 : 12 : CU_ASSERT(super->used_blobid_mask_len == 0);
4172 : 12 : }
4173 : :
4174 : : static void
4175 : 12 : blob_set_xattrs_test(void)
4176 : : {
4177 : 12 : struct spdk_blob_store *bs = g_bs;
4178 : : struct spdk_blob *blob;
4179 : 12 : struct spdk_blob_opts opts;
4180 : 12 : const void *value;
4181 : 12 : size_t value_len;
4182 : : char *xattr;
4183 : : size_t xattr_length;
4184 : : int rc;
4185 : :
4186 : : /* Create blob with extra attributes */
4187 : 12 : ut_spdk_blob_opts_init(&opts);
4188 : :
4189 : 12 : opts.xattrs.names = g_xattr_names;
4190 : 12 : opts.xattrs.get_value = _get_xattr_value;
4191 : 12 : opts.xattrs.count = 3;
4192 : 12 : opts.xattrs.ctx = &g_ctx;
4193 : :
4194 : 12 : blob = ut_blob_create_and_open(bs, &opts);
4195 : :
4196 : : /* Get the xattrs */
4197 : 12 : value = NULL;
4198 : :
4199 : 12 : rc = spdk_blob_get_xattr_value(blob, g_xattr_names[0], &value, &value_len);
4200 : 12 : CU_ASSERT(rc == 0);
4201 [ - + ]: 12 : SPDK_CU_ASSERT_FATAL(value != NULL);
4202 [ - + ]: 12 : CU_ASSERT(value_len == strlen(g_xattr_values[0]));
4203 [ - + - + ]: 12 : CU_ASSERT_NSTRING_EQUAL_FATAL(value, g_xattr_values[0], value_len);
4204 : :
4205 : 12 : rc = spdk_blob_get_xattr_value(blob, g_xattr_names[1], &value, &value_len);
4206 : 12 : CU_ASSERT(rc == 0);
4207 [ - + ]: 12 : SPDK_CU_ASSERT_FATAL(value != NULL);
4208 [ - + ]: 12 : CU_ASSERT(value_len == strlen(g_xattr_values[1]));
4209 [ - + - + ]: 12 : CU_ASSERT_NSTRING_EQUAL((char *)value, g_xattr_values[1], value_len);
4210 : :
4211 : 12 : rc = spdk_blob_get_xattr_value(blob, g_xattr_names[2], &value, &value_len);
4212 : 12 : CU_ASSERT(rc == 0);
4213 [ - + ]: 12 : SPDK_CU_ASSERT_FATAL(value != NULL);
4214 [ - + ]: 12 : CU_ASSERT(value_len == strlen(g_xattr_values[2]));
4215 [ - + - + ]: 12 : CU_ASSERT_NSTRING_EQUAL((char *)value, g_xattr_values[2], value_len);
4216 : :
4217 : : /* Try to get non existing attribute */
4218 : :
4219 : 12 : rc = spdk_blob_get_xattr_value(blob, "foobar", &value, &value_len);
4220 : 12 : CU_ASSERT(rc == -ENOENT);
4221 : :
4222 : : /* Try xattr exceeding maximum length of descriptor in single page */
4223 : 12 : xattr_length = SPDK_BS_MAX_DESC_SIZE - sizeof(struct spdk_blob_md_descriptor_xattr) -
4224 : : strlen("large_xattr") + 1;
4225 : 12 : xattr = calloc(xattr_length, sizeof(char));
4226 [ - + ]: 12 : SPDK_CU_ASSERT_FATAL(xattr != NULL);
4227 : 12 : rc = spdk_blob_set_xattr(blob, "large_xattr", xattr, xattr_length);
4228 : 12 : free(xattr);
4229 [ - + ]: 12 : SPDK_CU_ASSERT_FATAL(rc == -ENOMEM);
4230 : :
4231 : 12 : spdk_blob_close(blob, blob_op_complete, NULL);
4232 : 12 : poll_threads();
4233 : 12 : CU_ASSERT(g_bserrno == 0);
4234 : 12 : blob = NULL;
4235 : 12 : g_blob = NULL;
4236 : 12 : g_blobid = SPDK_BLOBID_INVALID;
4237 : :
4238 : : /* NULL callback */
4239 : 12 : ut_spdk_blob_opts_init(&opts);
4240 : 12 : opts.xattrs.names = g_xattr_names;
4241 : 12 : opts.xattrs.get_value = NULL;
4242 : 12 : opts.xattrs.count = 1;
4243 : 12 : opts.xattrs.ctx = &g_ctx;
4244 : :
4245 : 12 : spdk_bs_create_blob_ext(bs, &opts, blob_op_with_id_complete, NULL);
4246 : 12 : poll_threads();
4247 : 12 : CU_ASSERT(g_bserrno == -EINVAL);
4248 : 12 : CU_ASSERT(g_blobid != SPDK_BLOBID_INVALID);
4249 : :
4250 : : /* NULL values */
4251 : 12 : ut_spdk_blob_opts_init(&opts);
4252 : 12 : opts.xattrs.names = g_xattr_names;
4253 : 12 : opts.xattrs.get_value = _get_xattr_value_null;
4254 : 12 : opts.xattrs.count = 1;
4255 : 12 : opts.xattrs.ctx = NULL;
4256 : :
4257 : 12 : spdk_bs_create_blob_ext(bs, &opts, blob_op_with_id_complete, NULL);
4258 : 12 : poll_threads();
4259 : 12 : CU_ASSERT(g_bserrno == -EINVAL);
4260 : 12 : }
4261 : :
4262 : : static void
4263 : 12 : blob_thin_prov_alloc(void)
4264 : : {
4265 : 12 : struct spdk_blob_store *bs = g_bs;
4266 : : struct spdk_blob *blob;
4267 : 12 : struct spdk_blob_opts opts;
4268 : : spdk_blob_id blobid;
4269 : : uint64_t free_clusters;
4270 : :
4271 : 12 : free_clusters = spdk_bs_free_cluster_count(bs);
4272 : :
4273 : : /* Set blob as thin provisioned */
4274 : 12 : ut_spdk_blob_opts_init(&opts);
4275 : 12 : opts.thin_provision = true;
4276 : :
4277 : 12 : blob = ut_blob_create_and_open(bs, &opts);
4278 : 12 : blobid = spdk_blob_get_id(blob);
4279 : 12 : CU_ASSERT(free_clusters == spdk_bs_free_cluster_count(bs));
4280 : :
4281 : 12 : CU_ASSERT(blob->active.num_clusters == 0);
4282 : 12 : CU_ASSERT(spdk_blob_get_num_clusters(blob) == 0);
4283 : 12 : CU_ASSERT(spdk_blob_get_num_allocated_clusters(blob) == 0);
4284 : :
4285 : : /* The blob started at 0 clusters. Resize it to be 5, but still unallocated. */
4286 : 12 : spdk_blob_resize(blob, 5, blob_op_complete, NULL);
4287 : 12 : poll_threads();
4288 : 12 : CU_ASSERT(g_bserrno == 0);
4289 : 12 : CU_ASSERT(free_clusters == spdk_bs_free_cluster_count(bs));
4290 : 12 : CU_ASSERT(blob->active.num_clusters == 5);
4291 : 12 : CU_ASSERT(spdk_blob_get_num_clusters(blob) == 5);
4292 : 12 : CU_ASSERT(spdk_blob_get_num_allocated_clusters(blob) == 0);
4293 : :
4294 : : /* Grow it to 1TB - still unallocated */
4295 : 12 : spdk_blob_resize(blob, 262144, blob_op_complete, NULL);
4296 : 12 : poll_threads();
4297 : 12 : CU_ASSERT(g_bserrno == 0);
4298 : 12 : CU_ASSERT(free_clusters == spdk_bs_free_cluster_count(bs));
4299 : 12 : CU_ASSERT(blob->active.num_clusters == 262144);
4300 : 12 : CU_ASSERT(spdk_blob_get_num_clusters(blob) == 262144);
4301 : 12 : CU_ASSERT(spdk_blob_get_num_allocated_clusters(blob) == 0);
4302 : :
4303 : 12 : spdk_blob_sync_md(blob, blob_op_complete, NULL);
4304 : 12 : poll_threads();
4305 : 12 : CU_ASSERT(g_bserrno == 0);
4306 : : /* Sync must not change anything */
4307 : 12 : CU_ASSERT(free_clusters == spdk_bs_free_cluster_count(bs));
4308 : 12 : CU_ASSERT(blob->active.num_clusters == 262144);
4309 : 12 : CU_ASSERT(spdk_blob_get_num_clusters(blob) == 262144);
4310 : 12 : CU_ASSERT(spdk_blob_get_num_allocated_clusters(blob) == 0);
4311 : : /* Since clusters are not allocated,
4312 : : * number of metadata pages is expected to be minimal.
4313 : : */
4314 : 12 : CU_ASSERT(blob->active.num_pages == 1);
4315 : :
4316 : : /* Shrink the blob to 3 clusters - still unallocated */
4317 : 12 : spdk_blob_resize(blob, 3, blob_op_complete, NULL);
4318 : 12 : poll_threads();
4319 : 12 : CU_ASSERT(g_bserrno == 0);
4320 : 12 : CU_ASSERT(free_clusters == spdk_bs_free_cluster_count(bs));
4321 : 12 : CU_ASSERT(blob->active.num_clusters == 3);
4322 : 12 : CU_ASSERT(spdk_blob_get_num_clusters(blob) == 3);
4323 : 12 : CU_ASSERT(spdk_blob_get_num_allocated_clusters(blob) == 0);
4324 : :
4325 : 12 : spdk_blob_sync_md(blob, blob_op_complete, NULL);
4326 : 12 : poll_threads();
4327 : 12 : CU_ASSERT(g_bserrno == 0);
4328 : : /* Sync must not change anything */
4329 : 12 : CU_ASSERT(free_clusters == spdk_bs_free_cluster_count(bs));
4330 : 12 : CU_ASSERT(blob->active.num_clusters == 3);
4331 : 12 : CU_ASSERT(spdk_blob_get_num_clusters(blob) == 3);
4332 : 12 : CU_ASSERT(spdk_blob_get_num_allocated_clusters(blob) == 0);
4333 : :
4334 : 12 : spdk_blob_close(blob, blob_op_complete, NULL);
4335 : 12 : poll_threads();
4336 : 12 : CU_ASSERT(g_bserrno == 0);
4337 : :
4338 : 12 : ut_bs_reload(&bs, NULL);
4339 : :
4340 : 12 : spdk_bs_open_blob(bs, blobid, blob_op_with_handle_complete, NULL);
4341 : 12 : poll_threads();
4342 : 12 : CU_ASSERT(g_bserrno == 0);
4343 [ - + ]: 12 : SPDK_CU_ASSERT_FATAL(g_blob != NULL);
4344 : 12 : blob = g_blob;
4345 : :
4346 : : /* Check that clusters allocation and size is still the same */
4347 : 12 : CU_ASSERT(free_clusters == spdk_bs_free_cluster_count(bs));
4348 : 12 : CU_ASSERT(blob->active.num_clusters == 3);
4349 : :
4350 : 12 : ut_blob_close_and_delete(bs, blob);
4351 : 12 : }
4352 : :
4353 : : static void
4354 : 12 : blob_insert_cluster_msg_test(void)
4355 : : {
4356 : 12 : struct spdk_blob_store *bs = g_bs;
4357 : : struct spdk_blob *blob;
4358 : 12 : struct spdk_blob_opts opts;
4359 : 12 : struct spdk_blob_md_page page = {};
4360 : : spdk_blob_id blobid;
4361 : : uint64_t free_clusters;
4362 : 12 : uint64_t new_cluster = 0;
4363 : 12 : uint32_t cluster_num = 3;
4364 : 12 : uint32_t extent_page = 0;
4365 : :
4366 : 12 : free_clusters = spdk_bs_free_cluster_count(bs);
4367 : :
4368 : : /* Set blob as thin provisioned */
4369 : 12 : ut_spdk_blob_opts_init(&opts);
4370 : 12 : opts.thin_provision = true;
4371 : 12 : opts.num_clusters = 4;
4372 : :
4373 : 12 : blob = ut_blob_create_and_open(bs, &opts);
4374 : 12 : blobid = spdk_blob_get_id(blob);
4375 : 12 : CU_ASSERT(free_clusters == spdk_bs_free_cluster_count(bs));
4376 : :
4377 : 12 : CU_ASSERT(blob->active.num_clusters == 4);
4378 : 12 : CU_ASSERT(spdk_blob_get_num_clusters(blob) == 4);
4379 : 12 : CU_ASSERT(blob->active.clusters[cluster_num] == 0);
4380 : :
4381 : : /* Specify cluster_num to allocate and new_cluster will be returned to insert on md_thread.
4382 : : * This is to simulate behaviour when cluster is allocated after blob creation.
4383 : : * Such as _spdk_bs_allocate_and_copy_cluster(). */
4384 : 12 : spdk_spin_lock(&bs->used_lock);
4385 : 12 : bs_allocate_cluster(blob, cluster_num, &new_cluster, &extent_page, false);
4386 : 12 : CU_ASSERT(blob->active.clusters[cluster_num] == 0);
4387 : 12 : spdk_spin_unlock(&bs->used_lock);
4388 : :
4389 : 12 : blob_insert_cluster_on_md_thread(blob, cluster_num, new_cluster, extent_page, &page,
4390 : : blob_op_complete, NULL);
4391 : 12 : poll_threads();
4392 : :
4393 : 12 : CU_ASSERT(blob->active.clusters[cluster_num] != 0);
4394 : :
4395 : 12 : spdk_blob_close(blob, blob_op_complete, NULL);
4396 : 12 : poll_threads();
4397 : 12 : CU_ASSERT(g_bserrno == 0);
4398 : :
4399 : 12 : ut_bs_reload(&bs, NULL);
4400 : :
4401 : 12 : spdk_bs_open_blob(bs, blobid, blob_op_with_handle_complete, NULL);
4402 : 12 : poll_threads();
4403 : 12 : CU_ASSERT(g_bserrno == 0);
4404 [ - + ]: 12 : SPDK_CU_ASSERT_FATAL(g_blob != NULL);
4405 : 12 : blob = g_blob;
4406 : :
4407 : 12 : CU_ASSERT(blob->active.clusters[cluster_num] != 0);
4408 : :
4409 : 12 : ut_blob_close_and_delete(bs, blob);
4410 : 12 : }
4411 : :
4412 : : static void
4413 : 12 : blob_thin_prov_rw(void)
4414 : : {
4415 : : static const uint8_t zero[10 * 4096] = { 0 };
4416 : 12 : struct spdk_blob_store *bs = g_bs;
4417 : : struct spdk_blob *blob, *blob_id0;
4418 : : struct spdk_io_channel *channel, *channel_thread1;
4419 : 12 : struct spdk_blob_opts opts;
4420 : : uint64_t free_clusters;
4421 : : uint64_t page_size;
4422 : 12 : uint8_t payload_read[10 * 4096];
4423 : 12 : uint8_t payload_write[10 * 4096];
4424 : : uint64_t write_bytes;
4425 : : uint64_t read_bytes;
4426 : :
4427 : 12 : free_clusters = spdk_bs_free_cluster_count(bs);
4428 : 12 : page_size = spdk_bs_get_page_size(bs);
4429 : :
4430 : 12 : channel = spdk_bs_alloc_io_channel(bs);
4431 : 12 : CU_ASSERT(channel != NULL);
4432 : :
4433 : 12 : ut_spdk_blob_opts_init(&opts);
4434 : 12 : opts.thin_provision = true;
4435 : :
4436 : : /* Create and delete blob at md page 0, so that next md page allocation
4437 : : * for extent will use that. */
4438 : 12 : blob_id0 = ut_blob_create_and_open(bs, &opts);
4439 : 12 : blob = ut_blob_create_and_open(bs, &opts);
4440 : 12 : ut_blob_close_and_delete(bs, blob_id0);
4441 : 12 : CU_ASSERT(free_clusters == spdk_bs_free_cluster_count(bs));
4442 : :
4443 : 12 : CU_ASSERT(blob->active.num_clusters == 0);
4444 : 12 : CU_ASSERT(spdk_blob_get_num_allocated_clusters(blob) == 0);
4445 : :
4446 : : /* The blob started at 0 clusters. Resize it to be 5, but still unallocated. */
4447 : 12 : spdk_blob_resize(blob, 5, blob_op_complete, NULL);
4448 : 12 : poll_threads();
4449 : 12 : CU_ASSERT(g_bserrno == 0);
4450 : 12 : CU_ASSERT(free_clusters == spdk_bs_free_cluster_count(bs));
4451 : 12 : CU_ASSERT(blob->active.num_clusters == 5);
4452 : 12 : CU_ASSERT(spdk_blob_get_num_allocated_clusters(blob) == 0);
4453 : :
4454 : 12 : spdk_blob_sync_md(blob, blob_op_complete, NULL);
4455 : 12 : poll_threads();
4456 : 12 : CU_ASSERT(g_bserrno == 0);
4457 : : /* Sync must not change anything */
4458 : 12 : CU_ASSERT(free_clusters == spdk_bs_free_cluster_count(bs));
4459 : 12 : CU_ASSERT(blob->active.num_clusters == 5);
4460 : 12 : CU_ASSERT(spdk_blob_get_num_allocated_clusters(blob) == 0);
4461 : :
4462 : : /* Payload should be all zeros from unallocated clusters */
4463 : 12 : memset(payload_read, 0xFF, sizeof(payload_read));
4464 : 12 : spdk_blob_io_read(blob, channel, payload_read, 4, 10, blob_op_complete, NULL);
4465 : 12 : poll_threads();
4466 : 12 : CU_ASSERT(g_bserrno == 0);
4467 : 12 : CU_ASSERT(memcmp(zero, payload_read, 10 * 4096) == 0);
4468 : :
4469 : 12 : write_bytes = g_dev_write_bytes;
4470 : 12 : read_bytes = g_dev_read_bytes;
4471 : :
4472 : : /* Perform write on thread 1. That will allocate cluster on thread 0 via send_msg */
4473 : 12 : set_thread(1);
4474 : 12 : channel_thread1 = spdk_bs_alloc_io_channel(bs);
4475 : 12 : CU_ASSERT(channel_thread1 != NULL);
4476 : 12 : memset(payload_write, 0xE5, sizeof(payload_write));
4477 : 12 : spdk_blob_io_write(blob, channel_thread1, payload_write, 4, 10, blob_op_complete, NULL);
4478 : 12 : CU_ASSERT(free_clusters - 1 == spdk_bs_free_cluster_count(bs));
4479 : : /* Perform write on thread 0. That will try to allocate cluster,
4480 : : * but fail due to another thread issuing the cluster allocation first. */
4481 : 12 : set_thread(0);
4482 : 12 : memset(payload_write, 0xE5, sizeof(payload_write));
4483 : 12 : spdk_blob_io_write(blob, channel, payload_write, 4, 10, blob_op_complete, NULL);
4484 : 12 : CU_ASSERT(free_clusters - 2 == spdk_bs_free_cluster_count(bs));
4485 : 12 : poll_threads();
4486 : 12 : CU_ASSERT(g_bserrno == 0);
4487 : 12 : CU_ASSERT(free_clusters - 1 == spdk_bs_free_cluster_count(bs));
4488 : 12 : CU_ASSERT(spdk_blob_get_num_allocated_clusters(blob) == 1);
4489 : : /* For thin-provisioned blob we need to write 20 pages plus one page metadata and
4490 : : * read 0 bytes */
4491 [ + + + + ]: 12 : if (g_use_extent_table) {
4492 : : /* Add one more page for EXTENT_PAGE write */
4493 : 6 : CU_ASSERT(g_dev_write_bytes - write_bytes == page_size * 22);
4494 : : } else {
4495 : 6 : CU_ASSERT(g_dev_write_bytes - write_bytes == page_size * 21);
4496 : : }
4497 : 12 : CU_ASSERT(g_dev_read_bytes - read_bytes == 0);
4498 : :
4499 : 12 : spdk_blob_io_read(blob, channel, payload_read, 4, 10, blob_op_complete, NULL);
4500 : 12 : poll_threads();
4501 : 12 : CU_ASSERT(g_bserrno == 0);
4502 : 12 : CU_ASSERT(memcmp(payload_write, payload_read, 10 * 4096) == 0);
4503 : :
4504 : 12 : ut_blob_close_and_delete(bs, blob);
4505 : 12 : CU_ASSERT(free_clusters == spdk_bs_free_cluster_count(bs));
4506 : :
4507 : 12 : set_thread(1);
4508 : 12 : spdk_bs_free_io_channel(channel_thread1);
4509 : 12 : set_thread(0);
4510 : 12 : spdk_bs_free_io_channel(channel);
4511 : 12 : poll_threads();
4512 : 12 : g_blob = NULL;
4513 : 12 : g_blobid = 0;
4514 : 12 : }
4515 : :
4516 : : static void
4517 : 12 : blob_thin_prov_write_count_io(void)
4518 : : {
4519 : : struct spdk_blob_store *bs;
4520 : : struct spdk_blob *blob;
4521 : : struct spdk_io_channel *ch;
4522 : : struct spdk_bs_dev *dev;
4523 : 12 : struct spdk_bs_opts bs_opts;
4524 : 12 : struct spdk_blob_opts opts;
4525 : : uint64_t free_clusters;
4526 : : uint64_t page_size;
4527 : 12 : uint8_t payload_write[4096];
4528 : : uint64_t write_bytes;
4529 : : uint64_t read_bytes;
4530 : 12 : const uint32_t CLUSTER_SZ = 16384;
4531 : : uint32_t pages_per_cluster;
4532 : : uint32_t pages_per_extent_page;
4533 : : uint32_t i;
4534 : :
4535 : : /* Use a very small cluster size for this test. This ensures we need multiple
4536 : : * extent pages to hold all of the clusters even for relatively small blobs like
4537 : : * we are restricted to for the unit tests (i.e. we don't want to allocate multi-GB
4538 : : * buffers).
4539 : : */
4540 : 12 : dev = init_dev();
4541 : 12 : spdk_bs_opts_init(&bs_opts, sizeof(bs_opts));
4542 : 12 : bs_opts.cluster_sz = CLUSTER_SZ;
4543 : :
4544 : 12 : spdk_bs_init(dev, &bs_opts, bs_op_with_handle_complete, NULL);
4545 : 12 : poll_threads();
4546 : 12 : CU_ASSERT(g_bserrno == 0);
4547 [ - + ]: 12 : SPDK_CU_ASSERT_FATAL(g_bs != NULL);
4548 : 12 : bs = g_bs;
4549 : :
4550 : 12 : free_clusters = spdk_bs_free_cluster_count(bs);
4551 : 12 : page_size = spdk_bs_get_page_size(bs);
4552 [ - + ]: 12 : pages_per_cluster = CLUSTER_SZ / page_size;
4553 : 12 : pages_per_extent_page = SPDK_EXTENTS_PER_EP * pages_per_cluster;
4554 : :
4555 : 12 : ch = spdk_bs_alloc_io_channel(bs);
4556 [ - + ]: 12 : SPDK_CU_ASSERT_FATAL(ch != NULL);
4557 : :
4558 : 12 : ut_spdk_blob_opts_init(&opts);
4559 : 12 : opts.thin_provision = true;
4560 : :
4561 : 12 : blob = ut_blob_create_and_open(bs, &opts);
4562 : 12 : CU_ASSERT(free_clusters == spdk_bs_free_cluster_count(bs));
4563 : :
4564 : : /* Resize the blob so that it will require 8 extent pages to hold all of
4565 : : * the clusters.
4566 : : */
4567 : 12 : g_bserrno = -1;
4568 : 12 : spdk_blob_resize(blob, SPDK_EXTENTS_PER_EP * 8, blob_op_complete, NULL);
4569 : 12 : poll_threads();
4570 : 12 : CU_ASSERT(g_bserrno == 0);
4571 : :
4572 : 12 : g_bserrno = -1;
4573 : 12 : spdk_blob_sync_md(blob, blob_op_complete, NULL);
4574 : 12 : poll_threads();
4575 : 12 : CU_ASSERT(g_bserrno == 0);
4576 : 12 : CU_ASSERT(free_clusters == spdk_bs_free_cluster_count(bs));
4577 : 12 : CU_ASSERT(blob->active.num_clusters == SPDK_EXTENTS_PER_EP * 8);
4578 : :
4579 : 12 : memset(payload_write, 0, sizeof(payload_write));
4580 [ + + ]: 108 : for (i = 0; i < 8; i++) {
4581 : 96 : write_bytes = g_dev_write_bytes;
4582 : 96 : read_bytes = g_dev_read_bytes;
4583 : :
4584 : 96 : g_bserrno = -1;
4585 : 96 : spdk_blob_io_write(blob, ch, payload_write, pages_per_extent_page * i, 1, blob_op_complete, NULL);
4586 : 96 : poll_threads();
4587 : 96 : CU_ASSERT(g_bserrno == 0);
4588 : 96 : CU_ASSERT(free_clusters - (2 * i + 1) == spdk_bs_free_cluster_count(bs));
4589 : :
4590 : 96 : CU_ASSERT(g_dev_read_bytes == read_bytes);
4591 [ + + + + ]: 96 : if (!g_use_extent_table) {
4592 : : /* For legacy metadata, we should have written two pages - one for the
4593 : : * write I/O itself, another for the blob's primary metadata.
4594 : : */
4595 [ - + ]: 48 : CU_ASSERT((g_dev_write_bytes - write_bytes) / page_size == 2);
4596 : : } else {
4597 : : /* For extent table metadata, we should have written three pages - one
4598 : : * for the write I/O, one for the extent page, one for the blob's primary
4599 : : * metadata.
4600 : : */
4601 [ - + ]: 48 : CU_ASSERT((g_dev_write_bytes - write_bytes) / page_size == 3);
4602 : : }
4603 : :
4604 : : /* The write should have synced the metadata already. Do another sync here
4605 : : * just to confirm.
4606 : : */
4607 : 96 : write_bytes = g_dev_write_bytes;
4608 : 96 : read_bytes = g_dev_read_bytes;
4609 : :
4610 : 96 : g_bserrno = -1;
4611 : 96 : spdk_blob_sync_md(blob, blob_op_complete, NULL);
4612 : 96 : poll_threads();
4613 : 96 : CU_ASSERT(g_bserrno == 0);
4614 : 96 : CU_ASSERT(free_clusters - (2 * i + 1) == spdk_bs_free_cluster_count(bs));
4615 : 96 : CU_ASSERT(spdk_blob_get_num_allocated_clusters(blob) == 2 * i + 1);
4616 : :
4617 : 96 : CU_ASSERT(g_dev_read_bytes == read_bytes);
4618 : 96 : CU_ASSERT(g_dev_write_bytes == write_bytes);
4619 : :
4620 : : /* Now write to another unallocated cluster that is part of the same extent page. */
4621 : 96 : g_bserrno = -1;
4622 : 96 : spdk_blob_io_write(blob, ch, payload_write, pages_per_extent_page * i + pages_per_cluster,
4623 : : 1, blob_op_complete, NULL);
4624 : 96 : poll_threads();
4625 : 96 : CU_ASSERT(g_bserrno == 0);
4626 : 96 : CU_ASSERT(free_clusters - (2 * i + 2) == spdk_bs_free_cluster_count(bs));
4627 : 96 : CU_ASSERT(spdk_blob_get_num_allocated_clusters(blob) == 2 * i + 2);
4628 : :
4629 : 96 : CU_ASSERT(g_dev_read_bytes == read_bytes);
4630 : : /*
4631 : : * For legacy metadata, we should have written the I/O and the primary metadata page.
4632 : : * For extent table metadata, we should have written the I/O and the extent metadata page.
4633 : : */
4634 [ - + ]: 96 : CU_ASSERT((g_dev_write_bytes - write_bytes) / page_size == 2);
4635 : :
4636 : : /* Send unmap aligned to the whole cluster - should free it up */
4637 : 96 : g_bserrno = -1;
4638 : 96 : spdk_blob_io_unmap(blob, ch, pages_per_extent_page * i, pages_per_cluster, blob_op_complete, NULL);
4639 : 96 : poll_threads();
4640 : 96 : CU_ASSERT(g_bserrno == 0);
4641 : 96 : CU_ASSERT(free_clusters - (2 * i + 1) == spdk_bs_free_cluster_count(bs));
4642 : :
4643 : : /* Write back to the freed cluster */
4644 : 96 : g_bserrno = -1;
4645 : 96 : spdk_blob_io_write(blob, ch, payload_write, pages_per_extent_page * i, 1, blob_op_complete, NULL);
4646 : 96 : poll_threads();
4647 : 96 : CU_ASSERT(g_bserrno == 0);
4648 : 96 : CU_ASSERT(free_clusters - (2 * i + 2) == spdk_bs_free_cluster_count(bs));
4649 : : }
4650 : :
4651 : 12 : ut_blob_close_and_delete(bs, blob);
4652 : 12 : CU_ASSERT(free_clusters == spdk_bs_free_cluster_count(bs));
4653 : :
4654 : 12 : spdk_bs_free_io_channel(ch);
4655 : 12 : poll_threads();
4656 : 12 : g_blob = NULL;
4657 : 12 : g_blobid = 0;
4658 : :
4659 : 12 : spdk_bs_unload(bs, bs_op_complete, NULL);
4660 : 12 : poll_threads();
4661 : 12 : CU_ASSERT(g_bserrno == 0);
4662 : 12 : g_bs = NULL;
4663 : 12 : }
4664 : :
4665 : : static void
4666 : 12 : blob_thin_prov_unmap_cluster(void)
4667 : : {
4668 : : struct spdk_blob_store *bs;
4669 : : struct spdk_blob *blob;
4670 : : struct spdk_io_channel *ch;
4671 : : struct spdk_bs_dev *dev;
4672 : 12 : struct spdk_bs_opts bs_opts;
4673 : 12 : struct spdk_blob_opts opts;
4674 : : uint64_t free_clusters;
4675 : : uint64_t page_size;
4676 : 12 : uint8_t payload_write[4096];
4677 : 12 : uint8_t payload_read[4096];
4678 : 12 : const uint32_t CLUSTER_COUNT = 3;
4679 : : uint32_t pages_per_cluster;
4680 : : uint32_t i;
4681 : 12 : int err;
4682 : :
4683 : : /* Use a very large cluster size for this test. Check how the unmap/release cluster code path behaves when
4684 : : * clusters are fully used.
4685 : : */
4686 : 12 : dev = init_dev();
4687 : 12 : spdk_bs_opts_init(&bs_opts, sizeof(bs_opts));
4688 [ - + ]: 12 : bs_opts.cluster_sz = dev->blocklen * dev->blockcnt / (CLUSTER_COUNT + 1);
4689 : :
4690 : 12 : spdk_bs_init(dev, &bs_opts, bs_op_with_handle_complete, NULL);
4691 : 12 : poll_threads();
4692 : 12 : CU_ASSERT(g_bserrno == 0);
4693 [ - + ]: 12 : SPDK_CU_ASSERT_FATAL(g_bs != NULL);
4694 : 12 : bs = g_bs;
4695 : :
4696 : 12 : free_clusters = spdk_bs_free_cluster_count(bs);
4697 : 12 : page_size = spdk_bs_get_page_size(bs);
4698 [ - + ]: 12 : pages_per_cluster = bs_opts.cluster_sz / page_size;
4699 : :
4700 : 12 : ch = spdk_bs_alloc_io_channel(bs);
4701 [ - + ]: 12 : SPDK_CU_ASSERT_FATAL(ch != NULL);
4702 : :
4703 : 12 : ut_spdk_blob_opts_init(&opts);
4704 : 12 : opts.thin_provision = true;
4705 : :
4706 : 12 : blob = ut_blob_create_and_open(bs, &opts);
4707 : 12 : CU_ASSERT(free_clusters == CLUSTER_COUNT);
4708 : 12 : CU_ASSERT(free_clusters == spdk_bs_free_cluster_count(bs));
4709 : :
4710 : 12 : g_bserrno = -1;
4711 : 12 : spdk_blob_resize(blob, CLUSTER_COUNT, blob_op_complete, NULL);
4712 : 12 : poll_threads();
4713 : 12 : CU_ASSERT(g_bserrno == 0);
4714 : :
4715 : 12 : g_bserrno = -1;
4716 : 12 : spdk_blob_sync_md(blob, blob_op_complete, NULL);
4717 : 12 : poll_threads();
4718 : 12 : CU_ASSERT(g_bserrno == 0);
4719 : 12 : CU_ASSERT(free_clusters == spdk_bs_free_cluster_count(bs));
4720 : 12 : CU_ASSERT(blob->active.num_clusters == CLUSTER_COUNT);
4721 : :
4722 : : /* Fill all clusters */
4723 [ + + ]: 48 : for (i = 0; i < CLUSTER_COUNT; i++) {
4724 : 36 : memset(payload_write, i + 1, sizeof(payload_write));
4725 : 36 : g_bserrno = -1;
4726 : 36 : spdk_blob_io_write(blob, ch, payload_write, pages_per_cluster * i, 1, blob_op_complete, NULL);
4727 : 36 : poll_threads();
4728 : 36 : CU_ASSERT(g_bserrno == 0);
4729 : 36 : CU_ASSERT(free_clusters - (i + 1) == spdk_bs_free_cluster_count(bs));
4730 : : }
4731 : 12 : CU_ASSERT(0 == spdk_bs_free_cluster_count(bs));
4732 : :
4733 : : /* Unmap one whole cluster */
4734 : 12 : g_bserrno = -1;
4735 : 12 : spdk_blob_io_unmap(blob, ch, pages_per_cluster, pages_per_cluster, blob_op_complete, NULL);
4736 : 12 : poll_threads();
4737 : 12 : CU_ASSERT(g_bserrno == 0);
4738 : 12 : CU_ASSERT(1 == spdk_bs_free_cluster_count(bs));
4739 : :
4740 : : /* Verify the data read from the cluster is zeroed out */
4741 : 12 : memset(payload_write, 0, sizeof(payload_write));
4742 : 12 : spdk_blob_io_read(blob, ch, payload_read, pages_per_cluster, 1, blob_op_complete, NULL);
4743 : 12 : poll_threads();
4744 : 12 : CU_ASSERT(g_bserrno == 0);
4745 : 12 : CU_ASSERT(memcmp(payload_write, payload_read, 4096) == 0);
4746 : :
4747 : : /* Fill the same cluster with data */
4748 : 12 : memset(payload_write, 3, sizeof(payload_write));
4749 : 12 : g_bserrno = -1;
4750 : 12 : spdk_blob_io_write(blob, ch, payload_write, pages_per_cluster, 1, blob_op_complete, NULL);
4751 : 12 : poll_threads();
4752 : 12 : CU_ASSERT(g_bserrno == 0);
4753 : 12 : CU_ASSERT(0 == spdk_bs_free_cluster_count(bs));
4754 : :
4755 : : /* Verify the data read from the cluster has the expected data */
4756 : 12 : spdk_blob_io_read(blob, ch, payload_read, pages_per_cluster, 1, blob_op_complete, NULL);
4757 : 12 : poll_threads();
4758 : 12 : CU_ASSERT(g_bserrno == 0);
4759 : 12 : CU_ASSERT(memcmp(payload_write, payload_read, 4096) == 0);
4760 : :
4761 : : /* Send an unaligned unmap that ecompasses one whole cluster */
4762 : 12 : g_bserrno = -1;
4763 : 12 : spdk_blob_io_unmap(blob, ch, pages_per_cluster - 1, pages_per_cluster + 2, blob_op_complete, NULL);
4764 : 12 : poll_threads();
4765 : 12 : CU_ASSERT(g_bserrno == 0);
4766 : 12 : CU_ASSERT(1 == spdk_bs_free_cluster_count(bs));
4767 : :
4768 : : /* Verify the data read from the cluster is zeroed out */
4769 : 12 : g_bserrno = -1;
4770 : 12 : memset(payload_write, 0, sizeof(payload_write));
4771 : 12 : spdk_blob_io_read(blob, ch, payload_read, pages_per_cluster, 1, blob_op_complete, NULL);
4772 : 12 : poll_threads();
4773 : 12 : CU_ASSERT(g_bserrno == 0);
4774 : 12 : CU_ASSERT(memcmp(payload_write, payload_read, 4096) == 0);
4775 : :
4776 : : /* Send a simultaneous unmap with a write to an unallocated area -
4777 : : * check that writes don't claim the currently unmapped cluster */
4778 : 12 : g_bserrno = -1;
4779 : 12 : memset(payload_write, 7, sizeof(payload_write));
4780 : 12 : spdk_blob_io_unmap(blob, ch, 0, pages_per_cluster, blob_op_complete, NULL);
4781 : 12 : spdk_blob_io_write(blob, ch, payload_write, pages_per_cluster, 1, blob_op_complete, NULL);
4782 : 12 : poll_threads();
4783 : 12 : CU_ASSERT(g_bserrno == 0);
4784 : 12 : CU_ASSERT(1 == spdk_bs_free_cluster_count(bs));
4785 : :
4786 : : /* Verify the contents of written sector */
4787 : 12 : g_bserrno = -1;
4788 : 12 : spdk_blob_io_read(blob, ch, payload_read, pages_per_cluster, 1, blob_op_complete, NULL);
4789 : 12 : poll_threads();
4790 : 12 : CU_ASSERT(g_bserrno == 0);
4791 : 12 : CU_ASSERT(memcmp(payload_write, payload_read, 4096) == 0);
4792 : :
4793 : : /* Verify the contents of unmapped sector */
4794 : 12 : g_bserrno = -1;
4795 : 12 : memset(payload_write, 0, sizeof(payload_write));
4796 : 12 : spdk_blob_io_read(blob, ch, payload_read, 0, 1, blob_op_complete, NULL);
4797 : 12 : poll_threads();
4798 : 12 : CU_ASSERT(g_bserrno == 0);
4799 : 12 : CU_ASSERT(memcmp(payload_write, payload_read, 4096) == 0);
4800 : :
4801 : : /* Make sure clusters are not freed until the unmap to the drive is done */
4802 : 12 : g_bserrno = -1;
4803 : 12 : memset(payload_write, 7, sizeof(payload_write));
4804 : 12 : spdk_blob_io_write(blob, ch, payload_write, 0, 1, blob_op_complete, NULL);
4805 : 12 : poll_threads();
4806 : 12 : CU_ASSERT(g_bserrno == 0);
4807 : 12 : CU_ASSERT(0 == spdk_bs_free_cluster_count(bs));
4808 : :
4809 : 12 : g_bserrno = -1;
4810 : 12 : spdk_blob_io_unmap(blob, ch, 0, pages_per_cluster, blob_op_complete, NULL);
4811 [ - + - + ]: 12 : while (memcmp(payload_write, &g_dev_buffer[4096 * pages_per_cluster], 4096) == 0) {
4812 : 0 : CU_ASSERT(0 == spdk_bs_free_cluster_count(bs));
4813 : 0 : poll_thread_times(0, 1);
4814 : : }
4815 : 12 : poll_threads();
4816 : 12 : CU_ASSERT(g_bserrno == 0);
4817 : 12 : CU_ASSERT(1 == spdk_bs_free_cluster_count(bs));
4818 : :
4819 : : /* Issue #3358 had a bug with concurrent trims to the same cluster causing an assert, check for regressions.
4820 : : * Send three concurrent unmaps to the same cluster.
4821 : : */
4822 : 12 : g_bserrno = -1;
4823 : 12 : memset(payload_write, 7, sizeof(payload_write));
4824 : 12 : spdk_blob_io_write(blob, ch, payload_write, 0, 1, blob_op_complete, NULL);
4825 : 12 : poll_threads();
4826 : 12 : CU_ASSERT(g_bserrno == 0);
4827 : 12 : CU_ASSERT(0 == spdk_bs_free_cluster_count(bs));
4828 : :
4829 : 12 : g_bserrno = -1;
4830 : 12 : err = -1;
4831 : 12 : spdk_blob_io_unmap(blob, ch, 0, pages_per_cluster, blob_op_complete, NULL);
4832 : 12 : spdk_blob_io_unmap(blob, ch, 0, pages_per_cluster, blob_op_complete, NULL);
4833 : 12 : spdk_blob_io_unmap(blob, ch, 0, pages_per_cluster, blob_op_complete, &err);
4834 : 12 : poll_threads();
4835 : 12 : CU_ASSERT(g_bserrno == 0);
4836 : 12 : CU_ASSERT(err == 0);
4837 : 12 : CU_ASSERT(1 == spdk_bs_free_cluster_count(bs));
4838 : :
4839 : 12 : ut_blob_close_and_delete(bs, blob);
4840 : 12 : CU_ASSERT(free_clusters == spdk_bs_free_cluster_count(bs));
4841 : :
4842 : 12 : spdk_bs_free_io_channel(ch);
4843 : 12 : poll_threads();
4844 : 12 : g_blob = NULL;
4845 : 12 : g_blobid = 0;
4846 : :
4847 : 12 : spdk_bs_unload(bs, bs_op_complete, NULL);
4848 : 12 : poll_threads();
4849 : 12 : CU_ASSERT(g_bserrno == 0);
4850 : 12 : g_bs = NULL;
4851 : 12 : }
4852 : :
4853 : : static void
4854 : 12 : blob_thin_prov_rle(void)
4855 : : {
4856 : : static const uint8_t zero[10 * 4096] = { 0 };
4857 : 12 : struct spdk_blob_store *bs = g_bs;
4858 : : struct spdk_blob *blob;
4859 : : struct spdk_io_channel *channel;
4860 : 12 : struct spdk_blob_opts opts;
4861 : : spdk_blob_id blobid;
4862 : : uint64_t free_clusters;
4863 : : uint64_t page_size;
4864 : 12 : uint8_t payload_read[10 * 4096];
4865 : 12 : uint8_t payload_write[10 * 4096];
4866 : : uint64_t write_bytes;
4867 : : uint64_t read_bytes;
4868 : : uint64_t io_unit;
4869 : :
4870 : 12 : free_clusters = spdk_bs_free_cluster_count(bs);
4871 : 12 : page_size = spdk_bs_get_page_size(bs);
4872 : :
4873 : 12 : ut_spdk_blob_opts_init(&opts);
4874 : 12 : opts.thin_provision = true;
4875 : 12 : opts.num_clusters = 5;
4876 : :
4877 : 12 : blob = ut_blob_create_and_open(bs, &opts);
4878 : 12 : blobid = spdk_blob_get_id(blob);
4879 : 12 : CU_ASSERT(free_clusters == spdk_bs_free_cluster_count(bs));
4880 : :
4881 : 12 : channel = spdk_bs_alloc_io_channel(bs);
4882 : 12 : CU_ASSERT(channel != NULL);
4883 : :
4884 : : /* Target specifically second cluster in a blob as first allocation */
4885 : 12 : io_unit = bs_cluster_to_page(bs, 1) * bs_io_unit_per_page(bs);
4886 : :
4887 : : /* Payload should be all zeros from unallocated clusters */
4888 : 12 : memset(payload_read, 0xFF, sizeof(payload_read));
4889 : 12 : spdk_blob_io_read(blob, channel, payload_read, io_unit, 10, blob_op_complete, NULL);
4890 : 12 : poll_threads();
4891 : 12 : CU_ASSERT(g_bserrno == 0);
4892 : 12 : CU_ASSERT(memcmp(zero, payload_read, 10 * 4096) == 0);
4893 : :
4894 : 12 : write_bytes = g_dev_write_bytes;
4895 : 12 : read_bytes = g_dev_read_bytes;
4896 : :
4897 : : /* Issue write to second cluster in a blob */
4898 : 12 : memset(payload_write, 0xE5, sizeof(payload_write));
4899 : 12 : spdk_blob_io_write(blob, channel, payload_write, io_unit, 10, blob_op_complete, NULL);
4900 : 12 : poll_threads();
4901 : 12 : CU_ASSERT(g_bserrno == 0);
4902 : 12 : CU_ASSERT(free_clusters - 1 == spdk_bs_free_cluster_count(bs));
4903 : : /* For thin-provisioned blob we need to write 10 pages plus one page metadata and
4904 : : * read 0 bytes */
4905 [ + + + + ]: 12 : if (g_use_extent_table) {
4906 : : /* Add one more page for EXTENT_PAGE write */
4907 : 6 : CU_ASSERT(g_dev_write_bytes - write_bytes == page_size * 12);
4908 : : } else {
4909 : 6 : CU_ASSERT(g_dev_write_bytes - write_bytes == page_size * 11);
4910 : : }
4911 : 12 : CU_ASSERT(g_dev_read_bytes - read_bytes == 0);
4912 : :
4913 : 12 : spdk_blob_io_read(blob, channel, payload_read, io_unit, 10, blob_op_complete, NULL);
4914 : 12 : poll_threads();
4915 : 12 : CU_ASSERT(g_bserrno == 0);
4916 : 12 : CU_ASSERT(memcmp(payload_write, payload_read, 10 * 4096) == 0);
4917 : :
4918 : 12 : spdk_bs_free_io_channel(channel);
4919 : 12 : poll_threads();
4920 : :
4921 : 12 : spdk_blob_close(blob, blob_op_complete, NULL);
4922 : 12 : poll_threads();
4923 : 12 : CU_ASSERT(g_bserrno == 0);
4924 : :
4925 : 12 : ut_bs_reload(&bs, NULL);
4926 : :
4927 : 12 : spdk_bs_open_blob(bs, blobid, blob_op_with_handle_complete, NULL);
4928 : 12 : poll_threads();
4929 : 12 : CU_ASSERT(g_bserrno == 0);
4930 [ - + ]: 12 : SPDK_CU_ASSERT_FATAL(g_blob != NULL);
4931 : 12 : blob = g_blob;
4932 : :
4933 : 12 : channel = spdk_bs_alloc_io_channel(bs);
4934 : 12 : CU_ASSERT(channel != NULL);
4935 : :
4936 : : /* Read second cluster after blob reload to confirm data written */
4937 : 12 : spdk_blob_io_read(blob, channel, payload_read, io_unit, 10, blob_op_complete, NULL);
4938 : 12 : poll_threads();
4939 : 12 : CU_ASSERT(g_bserrno == 0);
4940 : 12 : CU_ASSERT(memcmp(payload_write, payload_read, 10 * 4096) == 0);
4941 : :
4942 : 12 : spdk_bs_free_io_channel(channel);
4943 : 12 : poll_threads();
4944 : :
4945 : 12 : ut_blob_close_and_delete(bs, blob);
4946 : 12 : }
4947 : :
4948 : : static void
4949 : 12 : blob_thin_prov_rw_iov(void)
4950 : : {
4951 : : static const uint8_t zero[10 * 4096] = { 0 };
4952 : 12 : struct spdk_blob_store *bs = g_bs;
4953 : : struct spdk_blob *blob;
4954 : : struct spdk_io_channel *channel;
4955 : 12 : struct spdk_blob_opts opts;
4956 : : uint64_t free_clusters;
4957 : 12 : uint8_t payload_read[10 * 4096];
4958 : 12 : uint8_t payload_write[10 * 4096];
4959 : 12 : struct iovec iov_read[3];
4960 : 12 : struct iovec iov_write[3];
4961 : :
4962 : 12 : free_clusters = spdk_bs_free_cluster_count(bs);
4963 : :
4964 : 12 : channel = spdk_bs_alloc_io_channel(bs);
4965 : 12 : CU_ASSERT(channel != NULL);
4966 : :
4967 : 12 : ut_spdk_blob_opts_init(&opts);
4968 : 12 : opts.thin_provision = true;
4969 : :
4970 : 12 : blob = ut_blob_create_and_open(bs, &opts);
4971 : 12 : CU_ASSERT(free_clusters == spdk_bs_free_cluster_count(bs));
4972 : :
4973 : 12 : CU_ASSERT(blob->active.num_clusters == 0);
4974 : :
4975 : : /* The blob started at 0 clusters. Resize it to be 5, but still unallocated. */
4976 : 12 : spdk_blob_resize(blob, 5, blob_op_complete, NULL);
4977 : 12 : poll_threads();
4978 : 12 : CU_ASSERT(g_bserrno == 0);
4979 : 12 : CU_ASSERT(free_clusters == spdk_bs_free_cluster_count(bs));
4980 : 12 : CU_ASSERT(blob->active.num_clusters == 5);
4981 : :
4982 : 12 : spdk_blob_sync_md(blob, blob_op_complete, NULL);
4983 : 12 : poll_threads();
4984 : 12 : CU_ASSERT(g_bserrno == 0);
4985 : : /* Sync must not change anything */
4986 : 12 : CU_ASSERT(free_clusters == spdk_bs_free_cluster_count(bs));
4987 : 12 : CU_ASSERT(blob->active.num_clusters == 5);
4988 : :
4989 : : /* Payload should be all zeros from unallocated clusters */
4990 : 12 : memset(payload_read, 0xAA, sizeof(payload_read));
4991 : 12 : iov_read[0].iov_base = payload_read;
4992 : 12 : iov_read[0].iov_len = 3 * 4096;
4993 : 12 : iov_read[1].iov_base = payload_read + 3 * 4096;
4994 : 12 : iov_read[1].iov_len = 4 * 4096;
4995 : 12 : iov_read[2].iov_base = payload_read + 7 * 4096;
4996 : 12 : iov_read[2].iov_len = 3 * 4096;
4997 : 12 : spdk_blob_io_readv(blob, channel, iov_read, 3, 250, 10, blob_op_complete, NULL);
4998 : 12 : poll_threads();
4999 : 12 : CU_ASSERT(g_bserrno == 0);
5000 : 12 : CU_ASSERT(memcmp(zero, payload_read, 10 * 4096) == 0);
5001 : :
5002 : 12 : memset(payload_write, 0xE5, sizeof(payload_write));
5003 : 12 : iov_write[0].iov_base = payload_write;
5004 : 12 : iov_write[0].iov_len = 1 * 4096;
5005 : 12 : iov_write[1].iov_base = payload_write + 1 * 4096;
5006 : 12 : iov_write[1].iov_len = 5 * 4096;
5007 : 12 : iov_write[2].iov_base = payload_write + 6 * 4096;
5008 : 12 : iov_write[2].iov_len = 4 * 4096;
5009 : :
5010 : 12 : spdk_blob_io_writev(blob, channel, iov_write, 3, 250, 10, blob_op_complete, NULL);
5011 : 12 : poll_threads();
5012 : 12 : CU_ASSERT(g_bserrno == 0);
5013 : :
5014 : 12 : memset(payload_read, 0xAA, sizeof(payload_read));
5015 : 12 : iov_read[0].iov_base = payload_read;
5016 : 12 : iov_read[0].iov_len = 3 * 4096;
5017 : 12 : iov_read[1].iov_base = payload_read + 3 * 4096;
5018 : 12 : iov_read[1].iov_len = 4 * 4096;
5019 : 12 : iov_read[2].iov_base = payload_read + 7 * 4096;
5020 : 12 : iov_read[2].iov_len = 3 * 4096;
5021 : 12 : spdk_blob_io_readv(blob, channel, iov_read, 3, 250, 10, blob_op_complete, NULL);
5022 : 12 : poll_threads();
5023 : 12 : CU_ASSERT(g_bserrno == 0);
5024 : 12 : CU_ASSERT(memcmp(payload_write, payload_read, 10 * 4096) == 0);
5025 : :
5026 : 12 : spdk_bs_free_io_channel(channel);
5027 : 12 : poll_threads();
5028 : :
5029 : 12 : ut_blob_close_and_delete(bs, blob);
5030 : 12 : }
5031 : :
5032 : : struct iter_ctx {
5033 : : int current_iter;
5034 : : spdk_blob_id blobid[4];
5035 : : };
5036 : :
5037 : : static void
5038 : 96 : test_iter(void *arg, struct spdk_blob *blob, int bserrno)
5039 : : {
5040 : 96 : struct iter_ctx *iter_ctx = arg;
5041 : : spdk_blob_id blobid;
5042 : :
5043 : 96 : CU_ASSERT(bserrno == 0);
5044 : 96 : blobid = spdk_blob_get_id(blob);
5045 : 96 : CU_ASSERT(blobid == iter_ctx->blobid[iter_ctx->current_iter++]);
5046 : 96 : }
5047 : :
5048 : : static void
5049 : 12 : bs_load_iter_test(void)
5050 : : {
5051 : : struct spdk_blob_store *bs;
5052 : : struct spdk_bs_dev *dev;
5053 : 12 : struct iter_ctx iter_ctx = { 0 };
5054 : : struct spdk_blob *blob;
5055 : : int i, rc;
5056 : 12 : struct spdk_bs_opts opts;
5057 : :
5058 : 12 : dev = init_dev();
5059 : 12 : spdk_bs_opts_init(&opts, sizeof(opts));
5060 : 12 : snprintf(opts.bstype.bstype, sizeof(opts.bstype.bstype), "TESTTYPE");
5061 : :
5062 : : /* Initialize a new blob store */
5063 : 12 : spdk_bs_init(dev, &opts, bs_op_with_handle_complete, NULL);
5064 : 12 : poll_threads();
5065 : 12 : CU_ASSERT(g_bserrno == 0);
5066 [ - + ]: 12 : SPDK_CU_ASSERT_FATAL(g_bs != NULL);
5067 : 12 : bs = g_bs;
5068 : :
5069 [ + + ]: 60 : for (i = 0; i < 4; i++) {
5070 : 48 : blob = ut_blob_create_and_open(bs, NULL);
5071 : 48 : iter_ctx.blobid[i] = spdk_blob_get_id(blob);
5072 : :
5073 : : /* Just save the blobid as an xattr for testing purposes. */
5074 : 48 : rc = spdk_blob_set_xattr(blob, "blobid", &iter_ctx.blobid[i], sizeof(spdk_blob_id));
5075 : 48 : CU_ASSERT(rc == 0);
5076 : :
5077 : : /* Resize the blob */
5078 : 48 : spdk_blob_resize(blob, i, blob_op_complete, NULL);
5079 : 48 : poll_threads();
5080 : 48 : CU_ASSERT(g_bserrno == 0);
5081 : :
5082 : 48 : spdk_blob_close(blob, blob_op_complete, NULL);
5083 : 48 : poll_threads();
5084 : 48 : CU_ASSERT(g_bserrno == 0);
5085 : : }
5086 : :
5087 : 12 : g_bserrno = -1;
5088 : 12 : spdk_bs_unload(bs, bs_op_complete, NULL);
5089 : 12 : poll_threads();
5090 : 12 : CU_ASSERT(g_bserrno == 0);
5091 : :
5092 : 12 : dev = init_dev();
5093 : 12 : spdk_bs_opts_init(&opts, sizeof(opts));
5094 : 12 : snprintf(opts.bstype.bstype, sizeof(opts.bstype.bstype), "TESTTYPE");
5095 : 12 : opts.iter_cb_fn = test_iter;
5096 : 12 : opts.iter_cb_arg = &iter_ctx;
5097 : :
5098 : : /* Test blob iteration during load after a clean shutdown. */
5099 : 12 : spdk_bs_load(dev, &opts, bs_op_with_handle_complete, NULL);
5100 : 12 : poll_threads();
5101 : 12 : CU_ASSERT(g_bserrno == 0);
5102 [ - + ]: 12 : SPDK_CU_ASSERT_FATAL(g_bs != NULL);
5103 : 12 : bs = g_bs;
5104 : :
5105 : : /* Dirty shutdown */
5106 : 12 : bs_free(bs);
5107 : :
5108 : 12 : dev = init_dev();
5109 : 12 : spdk_bs_opts_init(&opts, sizeof(opts));
5110 : 12 : snprintf(opts.bstype.bstype, sizeof(opts.bstype.bstype), "TESTTYPE");
5111 : 12 : opts.iter_cb_fn = test_iter;
5112 : 12 : iter_ctx.current_iter = 0;
5113 : 12 : opts.iter_cb_arg = &iter_ctx;
5114 : :
5115 : : /* Test blob iteration during load after a dirty shutdown. */
5116 : 12 : spdk_bs_load(dev, &opts, bs_op_with_handle_complete, NULL);
5117 : 12 : poll_threads();
5118 : 12 : CU_ASSERT(g_bserrno == 0);
5119 [ - + ]: 12 : SPDK_CU_ASSERT_FATAL(g_bs != NULL);
5120 : 12 : bs = g_bs;
5121 : :
5122 : 12 : spdk_bs_unload(bs, bs_op_complete, NULL);
5123 : 12 : poll_threads();
5124 : 12 : CU_ASSERT(g_bserrno == 0);
5125 : 12 : g_bs = NULL;
5126 : 12 : }
5127 : :
5128 : : static void
5129 : 12 : blob_snapshot_rw(void)
5130 : : {
5131 : : static const uint8_t zero[10 * 4096] = { 0 };
5132 : 12 : struct spdk_blob_store *bs = g_bs;
5133 : : struct spdk_blob *blob, *snapshot;
5134 : : struct spdk_io_channel *channel;
5135 : 12 : struct spdk_blob_opts opts;
5136 : : spdk_blob_id blobid, snapshotid;
5137 : : uint64_t free_clusters;
5138 : : uint64_t cluster_size;
5139 : : uint64_t page_size;
5140 : 12 : uint8_t payload_read[10 * 4096];
5141 : 12 : uint8_t payload_write[10 * 4096];
5142 : : uint64_t write_bytes_start;
5143 : : uint64_t read_bytes_start;
5144 : : uint64_t copy_bytes_start;
5145 : : uint64_t write_bytes;
5146 : : uint64_t read_bytes;
5147 : : uint64_t copy_bytes;
5148 : :
5149 : 12 : free_clusters = spdk_bs_free_cluster_count(bs);
5150 : 12 : cluster_size = spdk_bs_get_cluster_size(bs);
5151 : 12 : page_size = spdk_bs_get_page_size(bs);
5152 : :
5153 : 12 : channel = spdk_bs_alloc_io_channel(bs);
5154 : 12 : CU_ASSERT(channel != NULL);
5155 : :
5156 : 12 : ut_spdk_blob_opts_init(&opts);
5157 : 12 : opts.thin_provision = true;
5158 : 12 : opts.num_clusters = 5;
5159 : :
5160 : 12 : blob = ut_blob_create_and_open(bs, &opts);
5161 : 12 : blobid = spdk_blob_get_id(blob);
5162 : 12 : CU_ASSERT(free_clusters == spdk_bs_free_cluster_count(bs));
5163 : :
5164 : 12 : CU_ASSERT(spdk_blob_get_num_clusters(blob) == 5);
5165 : :
5166 : 12 : memset(payload_read, 0xFF, sizeof(payload_read));
5167 : 12 : spdk_blob_io_read(blob, channel, payload_read, 4, 10, blob_op_complete, NULL);
5168 : 12 : poll_threads();
5169 : 12 : CU_ASSERT(g_bserrno == 0);
5170 : 12 : CU_ASSERT(memcmp(zero, payload_read, 10 * 4096) == 0);
5171 : :
5172 : 12 : memset(payload_write, 0xE5, sizeof(payload_write));
5173 : 12 : spdk_blob_io_write(blob, channel, payload_write, 4, 10, blob_op_complete, NULL);
5174 : 12 : poll_threads();
5175 : 12 : CU_ASSERT(g_bserrno == 0);
5176 : 12 : CU_ASSERT(free_clusters != spdk_bs_free_cluster_count(bs));
5177 : :
5178 : : /* Create snapshot from blob */
5179 : 12 : spdk_bs_create_snapshot(bs, blobid, NULL, blob_op_with_id_complete, NULL);
5180 : 12 : poll_threads();
5181 : 12 : CU_ASSERT(g_bserrno == 0);
5182 : 12 : CU_ASSERT(g_blobid != SPDK_BLOBID_INVALID);
5183 : 12 : snapshotid = g_blobid;
5184 : :
5185 : 12 : spdk_bs_open_blob(bs, snapshotid, blob_op_with_handle_complete, NULL);
5186 : 12 : poll_threads();
5187 : 12 : CU_ASSERT(g_bserrno == 0);
5188 [ - + ]: 12 : SPDK_CU_ASSERT_FATAL(g_blob != NULL);
5189 : 12 : snapshot = g_blob;
5190 [ - + ]: 12 : CU_ASSERT(snapshot->data_ro == true);
5191 [ - + ]: 12 : CU_ASSERT(snapshot->md_ro == true);
5192 : :
5193 : 12 : CU_ASSERT(spdk_blob_get_num_clusters(snapshot) == 5);
5194 : :
5195 : 12 : write_bytes_start = g_dev_write_bytes;
5196 : 12 : read_bytes_start = g_dev_read_bytes;
5197 : 12 : copy_bytes_start = g_dev_copy_bytes;
5198 : :
5199 : 12 : memset(payload_write, 0xAA, sizeof(payload_write));
5200 : 12 : spdk_blob_io_write(blob, channel, payload_write, 4, 10, blob_op_complete, NULL);
5201 : 12 : poll_threads();
5202 : 12 : CU_ASSERT(g_bserrno == 0);
5203 : 12 : CU_ASSERT(free_clusters != spdk_bs_free_cluster_count(bs));
5204 : :
5205 : : /* For a clone we need to allocate and copy one cluster, update one page of metadata
5206 : : * and then write 10 pages of payload.
5207 : : */
5208 : 12 : write_bytes = g_dev_write_bytes - write_bytes_start;
5209 : 12 : read_bytes = g_dev_read_bytes - read_bytes_start;
5210 : 12 : copy_bytes = g_dev_copy_bytes - copy_bytes_start;
5211 [ + + + + ]: 12 : if (g_dev_copy_enabled) {
5212 : 6 : CU_ASSERT(copy_bytes == cluster_size);
5213 : : } else {
5214 : 6 : CU_ASSERT(copy_bytes == 0);
5215 : : }
5216 [ + + + + ]: 12 : if (g_use_extent_table) {
5217 : : /* Add one more page for EXTENT_PAGE write */
5218 : 6 : CU_ASSERT(write_bytes + copy_bytes == page_size * 12 + cluster_size);
5219 : : } else {
5220 : 6 : CU_ASSERT(write_bytes + copy_bytes == page_size * 11 + cluster_size);
5221 : : }
5222 : 12 : CU_ASSERT(read_bytes + copy_bytes == cluster_size);
5223 : :
5224 : 12 : spdk_blob_io_read(blob, channel, payload_read, 4, 10, blob_op_complete, NULL);
5225 : 12 : poll_threads();
5226 : 12 : CU_ASSERT(g_bserrno == 0);
5227 : 12 : CU_ASSERT(memcmp(payload_write, payload_read, 10 * 4096) == 0);
5228 : :
5229 : : /* Data on snapshot should not change after write to clone */
5230 : 12 : memset(payload_write, 0xE5, sizeof(payload_write));
5231 : 12 : spdk_blob_io_read(snapshot, channel, payload_read, 4, 10, blob_op_complete, NULL);
5232 : 12 : poll_threads();
5233 : 12 : CU_ASSERT(g_bserrno == 0);
5234 : 12 : CU_ASSERT(memcmp(payload_write, payload_read, 10 * 4096) == 0);
5235 : :
5236 : 12 : ut_blob_close_and_delete(bs, blob);
5237 : 12 : ut_blob_close_and_delete(bs, snapshot);
5238 : :
5239 : 12 : spdk_bs_free_io_channel(channel);
5240 : 12 : poll_threads();
5241 : 12 : g_blob = NULL;
5242 : 12 : g_blobid = 0;
5243 : 12 : }
5244 : :
5245 : : static void
5246 : 12 : blob_snapshot_rw_iov(void)
5247 : : {
5248 : : static const uint8_t zero[10 * 4096] = { 0 };
5249 : 12 : struct spdk_blob_store *bs = g_bs;
5250 : : struct spdk_blob *blob, *snapshot;
5251 : : struct spdk_io_channel *channel;
5252 : 12 : struct spdk_blob_opts opts;
5253 : : spdk_blob_id blobid, snapshotid;
5254 : : uint64_t free_clusters;
5255 : 12 : uint8_t payload_read[10 * 4096];
5256 : 12 : uint8_t payload_write[10 * 4096];
5257 : 12 : struct iovec iov_read[3];
5258 : 12 : struct iovec iov_write[3];
5259 : :
5260 : 12 : free_clusters = spdk_bs_free_cluster_count(bs);
5261 : :
5262 : 12 : channel = spdk_bs_alloc_io_channel(bs);
5263 : 12 : CU_ASSERT(channel != NULL);
5264 : :
5265 : 12 : ut_spdk_blob_opts_init(&opts);
5266 : 12 : opts.thin_provision = true;
5267 : 12 : opts.num_clusters = 5;
5268 : :
5269 : 12 : blob = ut_blob_create_and_open(bs, &opts);
5270 : 12 : blobid = spdk_blob_get_id(blob);
5271 : 12 : CU_ASSERT(free_clusters == spdk_bs_free_cluster_count(bs));
5272 : :
5273 : 12 : CU_ASSERT(spdk_blob_get_num_clusters(blob) == 5);
5274 : :
5275 : : /* Create snapshot from blob */
5276 : 12 : spdk_bs_create_snapshot(bs, blobid, NULL, blob_op_with_id_complete, NULL);
5277 : 12 : poll_threads();
5278 : 12 : CU_ASSERT(g_bserrno == 0);
5279 : 12 : CU_ASSERT(g_blobid != SPDK_BLOBID_INVALID);
5280 : 12 : snapshotid = g_blobid;
5281 : :
5282 : 12 : spdk_bs_open_blob(bs, snapshotid, blob_op_with_handle_complete, NULL);
5283 : 12 : poll_threads();
5284 : 12 : CU_ASSERT(g_bserrno == 0);
5285 [ - + ]: 12 : SPDK_CU_ASSERT_FATAL(g_blob != NULL);
5286 : 12 : snapshot = g_blob;
5287 [ - + ]: 12 : CU_ASSERT(snapshot->data_ro == true);
5288 [ - + ]: 12 : CU_ASSERT(snapshot->md_ro == true);
5289 : 12 : CU_ASSERT(spdk_blob_get_num_clusters(snapshot) == 5);
5290 : :
5291 : : /* Payload should be all zeros from unallocated clusters */
5292 : 12 : memset(payload_read, 0xAA, sizeof(payload_read));
5293 : 12 : iov_read[0].iov_base = payload_read;
5294 : 12 : iov_read[0].iov_len = 3 * 4096;
5295 : 12 : iov_read[1].iov_base = payload_read + 3 * 4096;
5296 : 12 : iov_read[1].iov_len = 4 * 4096;
5297 : 12 : iov_read[2].iov_base = payload_read + 7 * 4096;
5298 : 12 : iov_read[2].iov_len = 3 * 4096;
5299 : 12 : spdk_blob_io_readv(blob, channel, iov_read, 3, 250, 10, blob_op_complete, NULL);
5300 : 12 : poll_threads();
5301 : 12 : CU_ASSERT(g_bserrno == 0);
5302 : 12 : CU_ASSERT(memcmp(zero, payload_read, 10 * 4096) == 0);
5303 : :
5304 : 12 : memset(payload_write, 0xE5, sizeof(payload_write));
5305 : 12 : iov_write[0].iov_base = payload_write;
5306 : 12 : iov_write[0].iov_len = 1 * 4096;
5307 : 12 : iov_write[1].iov_base = payload_write + 1 * 4096;
5308 : 12 : iov_write[1].iov_len = 5 * 4096;
5309 : 12 : iov_write[2].iov_base = payload_write + 6 * 4096;
5310 : 12 : iov_write[2].iov_len = 4 * 4096;
5311 : :
5312 : 12 : spdk_blob_io_writev(blob, channel, iov_write, 3, 250, 10, blob_op_complete, NULL);
5313 : 12 : poll_threads();
5314 : 12 : CU_ASSERT(g_bserrno == 0);
5315 : :
5316 : 12 : memset(payload_read, 0xAA, sizeof(payload_read));
5317 : 12 : iov_read[0].iov_base = payload_read;
5318 : 12 : iov_read[0].iov_len = 3 * 4096;
5319 : 12 : iov_read[1].iov_base = payload_read + 3 * 4096;
5320 : 12 : iov_read[1].iov_len = 4 * 4096;
5321 : 12 : iov_read[2].iov_base = payload_read + 7 * 4096;
5322 : 12 : iov_read[2].iov_len = 3 * 4096;
5323 : 12 : spdk_blob_io_readv(blob, channel, iov_read, 3, 250, 10, blob_op_complete, NULL);
5324 : 12 : poll_threads();
5325 : 12 : CU_ASSERT(g_bserrno == 0);
5326 : 12 : CU_ASSERT(memcmp(payload_write, payload_read, 10 * 4096) == 0);
5327 : :
5328 : 12 : spdk_bs_free_io_channel(channel);
5329 : 12 : poll_threads();
5330 : :
5331 : 12 : ut_blob_close_and_delete(bs, blob);
5332 : 12 : ut_blob_close_and_delete(bs, snapshot);
5333 : 12 : }
5334 : :
5335 : : /**
5336 : : * Inflate / decouple parent rw unit tests.
5337 : : *
5338 : : * --------------
5339 : : * original blob: 0 1 2 3 4
5340 : : * ,---------+---------+---------+---------+---------.
5341 : : * snapshot |xxxxxxxxx|xxxxxxxxx|xxxxxxxxx|xxxxxxxxx| - |
5342 : : * +---------+---------+---------+---------+---------+
5343 : : * snapshot2 | - |yyyyyyyyy| - |yyyyyyyyy| - |
5344 : : * +---------+---------+---------+---------+---------+
5345 : : * blob | - |zzzzzzzzz| - | - | - |
5346 : : * '---------+---------+---------+---------+---------'
5347 : : * . . . . . .
5348 : : * -------- . . . . . .
5349 : : * inflate: . . . . . .
5350 : : * ,---------+---------+---------+---------+---------.
5351 : : * blob |xxxxxxxxx|zzzzzzzzz|xxxxxxxxx|yyyyyyyyy|000000000|
5352 : : * '---------+---------+---------+---------+---------'
5353 : : *
5354 : : * NOTE: needs to allocate 4 clusters, thin provisioning removed, dependency
5355 : : * on snapshot2 and snapshot removed . . .
5356 : : * . . . . . .
5357 : : * ---------------- . . . . . .
5358 : : * decouple parent: . . . . . .
5359 : : * ,---------+---------+---------+---------+---------.
5360 : : * snapshot |xxxxxxxxx|xxxxxxxxx|xxxxxxxxx|xxxxxxxxx| - |
5361 : : * +---------+---------+---------+---------+---------+
5362 : : * blob | - |zzzzzzzzz| - |yyyyyyyyy| - |
5363 : : * '---------+---------+---------+---------+---------'
5364 : : *
5365 : : * NOTE: needs to allocate 1 cluster, 3 clusters unallocated, dependency
5366 : : * on snapshot2 removed and on snapshot still exists. Snapshot2
5367 : : * should remain a clone of snapshot.
5368 : : */
5369 : : static void
5370 : 24 : _blob_inflate_rw(bool decouple_parent)
5371 : : {
5372 : 24 : struct spdk_blob_store *bs = g_bs;
5373 : : struct spdk_blob *blob, *snapshot, *snapshot2;
5374 : : struct spdk_io_channel *channel;
5375 : 24 : struct spdk_blob_opts opts;
5376 : : spdk_blob_id blobid, snapshotid, snapshot2id;
5377 : : uint64_t free_clusters;
5378 : : uint64_t cluster_size;
5379 : :
5380 : : uint64_t payload_size;
5381 : : uint8_t *payload_read;
5382 : : uint8_t *payload_write;
5383 : : uint8_t *payload_clone;
5384 : :
5385 : : uint64_t pages_per_cluster;
5386 : : uint64_t pages_per_payload;
5387 : :
5388 : : int i;
5389 : 24 : spdk_blob_id ids[2];
5390 : 24 : size_t count;
5391 : :
5392 : 24 : free_clusters = spdk_bs_free_cluster_count(bs);
5393 : 24 : cluster_size = spdk_bs_get_cluster_size(bs);
5394 [ - + ]: 24 : pages_per_cluster = cluster_size / spdk_bs_get_page_size(bs);
5395 : 24 : pages_per_payload = pages_per_cluster * 5;
5396 : :
5397 : 24 : payload_size = cluster_size * 5;
5398 : :
5399 : 24 : payload_read = malloc(payload_size);
5400 [ - + ]: 24 : SPDK_CU_ASSERT_FATAL(payload_read != NULL);
5401 : :
5402 : 24 : payload_write = malloc(payload_size);
5403 [ - + ]: 24 : SPDK_CU_ASSERT_FATAL(payload_write != NULL);
5404 : :
5405 : 24 : payload_clone = malloc(payload_size);
5406 [ - + ]: 24 : SPDK_CU_ASSERT_FATAL(payload_clone != NULL);
5407 : :
5408 : 24 : channel = spdk_bs_alloc_io_channel(bs);
5409 [ - + ]: 24 : SPDK_CU_ASSERT_FATAL(channel != NULL);
5410 : :
5411 : : /* Create blob */
5412 : 24 : ut_spdk_blob_opts_init(&opts);
5413 : 24 : opts.thin_provision = true;
5414 : 24 : opts.num_clusters = 5;
5415 : :
5416 : 24 : blob = ut_blob_create_and_open(bs, &opts);
5417 : 24 : blobid = spdk_blob_get_id(blob);
5418 : 24 : CU_ASSERT(free_clusters == spdk_bs_free_cluster_count(bs));
5419 : :
5420 : 24 : CU_ASSERT(spdk_blob_get_num_clusters(blob) == 5);
5421 : :
5422 : : /* 1) Initial read should return zeroed payload */
5423 [ - + ]: 24 : memset(payload_read, 0xFF, payload_size);
5424 : 24 : spdk_blob_io_read(blob, channel, payload_read, 0, pages_per_payload,
5425 : : blob_op_complete, NULL);
5426 : 24 : poll_threads();
5427 : 24 : CU_ASSERT(g_bserrno == 0);
5428 : 24 : CU_ASSERT(spdk_mem_all_zero(payload_read, payload_size));
5429 : :
5430 : : /* Fill whole blob with a pattern, except last cluster (to be sure it
5431 : : * isn't allocated) */
5432 [ - + ]: 24 : memset(payload_write, 0xE5, payload_size - cluster_size);
5433 : 24 : spdk_blob_io_write(blob, channel, payload_write, 0, pages_per_payload -
5434 : : pages_per_cluster, blob_op_complete, NULL);
5435 : 24 : poll_threads();
5436 : 24 : CU_ASSERT(g_bserrno == 0);
5437 : 24 : CU_ASSERT(free_clusters != spdk_bs_free_cluster_count(bs));
5438 : :
5439 : : /* 2) Create snapshot from blob (first level) */
5440 : 24 : spdk_bs_create_snapshot(bs, blobid, NULL, blob_op_with_id_complete, NULL);
5441 : 24 : poll_threads();
5442 : 24 : CU_ASSERT(g_bserrno == 0);
5443 : 24 : CU_ASSERT(g_blobid != SPDK_BLOBID_INVALID);
5444 : 24 : snapshotid = g_blobid;
5445 : :
5446 : 24 : spdk_bs_open_blob(bs, snapshotid, blob_op_with_handle_complete, NULL);
5447 : 24 : poll_threads();
5448 : 24 : CU_ASSERT(g_bserrno == 0);
5449 [ - + ]: 24 : SPDK_CU_ASSERT_FATAL(g_blob != NULL);
5450 : 24 : snapshot = g_blob;
5451 [ - + ]: 24 : CU_ASSERT(snapshot->data_ro == true);
5452 [ - + ]: 24 : CU_ASSERT(snapshot->md_ro == true);
5453 : :
5454 : 24 : CU_ASSERT(spdk_blob_get_num_clusters(snapshot) == 5);
5455 : :
5456 : : /* Write every second cluster with a pattern.
5457 : : *
5458 : : * Last cluster shouldn't be written, to be sure that snapshot nor clone
5459 : : * doesn't allocate it.
5460 : : *
5461 : : * payload_clone stores expected result on "blob" read at the time and
5462 : : * is used only to check data consistency on clone before and after
5463 : : * inflation. Initially we fill it with a backing snapshots pattern
5464 : : * used before.
5465 : : */
5466 [ - + ]: 24 : memset(payload_clone, 0xE5, payload_size - cluster_size);
5467 [ - + ]: 24 : memset(payload_clone + payload_size - cluster_size, 0x00, cluster_size);
5468 [ - + ]: 24 : memset(payload_write, 0xAA, payload_size);
5469 [ + + ]: 72 : for (i = 1; i < 5; i += 2) {
5470 : 48 : spdk_blob_io_write(blob, channel, payload_write, i * pages_per_cluster,
5471 : : pages_per_cluster, blob_op_complete, NULL);
5472 : 48 : poll_threads();
5473 : 48 : CU_ASSERT(g_bserrno == 0);
5474 : :
5475 : : /* Update expected result */
5476 [ - + - + ]: 48 : memcpy(payload_clone + (cluster_size * i), payload_write,
5477 : : cluster_size);
5478 : : }
5479 : 24 : CU_ASSERT(free_clusters != spdk_bs_free_cluster_count(bs));
5480 : :
5481 : : /* Check data consistency on clone */
5482 [ - + ]: 24 : memset(payload_read, 0xFF, payload_size);
5483 : 24 : spdk_blob_io_read(blob, channel, payload_read, 0, pages_per_payload,
5484 : : blob_op_complete, NULL);
5485 : 24 : poll_threads();
5486 : 24 : CU_ASSERT(g_bserrno == 0);
5487 [ - + - + ]: 24 : CU_ASSERT(memcmp(payload_clone, payload_read, payload_size) == 0);
5488 : :
5489 : : /* 3) Create second levels snapshot from blob */
5490 : 24 : spdk_bs_create_snapshot(bs, blobid, NULL, blob_op_with_id_complete, NULL);
5491 : 24 : poll_threads();
5492 : 24 : CU_ASSERT(g_bserrno == 0);
5493 : 24 : CU_ASSERT(g_blobid != SPDK_BLOBID_INVALID);
5494 : 24 : snapshot2id = g_blobid;
5495 : :
5496 : 24 : spdk_bs_open_blob(bs, snapshot2id, blob_op_with_handle_complete, NULL);
5497 : 24 : poll_threads();
5498 : 24 : CU_ASSERT(g_bserrno == 0);
5499 [ - + ]: 24 : SPDK_CU_ASSERT_FATAL(g_blob != NULL);
5500 : 24 : snapshot2 = g_blob;
5501 [ - + ]: 24 : CU_ASSERT(snapshot2->data_ro == true);
5502 [ - + ]: 24 : CU_ASSERT(snapshot2->md_ro == true);
5503 : :
5504 : 24 : CU_ASSERT(spdk_blob_get_num_clusters(snapshot2) == 5);
5505 : :
5506 : 24 : CU_ASSERT(snapshot2->parent_id == snapshotid);
5507 : :
5508 : : /* Write one cluster on the top level blob. This cluster (1) covers
5509 : : * already allocated cluster in the snapshot2, so shouldn't be inflated
5510 : : * at all */
5511 : 24 : spdk_blob_io_write(blob, channel, payload_write, pages_per_cluster,
5512 : : pages_per_cluster, blob_op_complete, NULL);
5513 : 24 : poll_threads();
5514 : 24 : CU_ASSERT(g_bserrno == 0);
5515 : :
5516 : : /* Update expected result */
5517 [ - + - + ]: 24 : memcpy(payload_clone + cluster_size, payload_write, cluster_size);
5518 : :
5519 : : /* Check data consistency on clone */
5520 [ - + ]: 24 : memset(payload_read, 0xFF, payload_size);
5521 : 24 : spdk_blob_io_read(blob, channel, payload_read, 0, pages_per_payload,
5522 : : blob_op_complete, NULL);
5523 : 24 : poll_threads();
5524 : 24 : CU_ASSERT(g_bserrno == 0);
5525 [ - + - + ]: 24 : CU_ASSERT(memcmp(payload_clone, payload_read, payload_size) == 0);
5526 : :
5527 : :
5528 : : /* Close all blobs */
5529 : 24 : spdk_blob_close(blob, blob_op_complete, NULL);
5530 : 24 : poll_threads();
5531 : 24 : CU_ASSERT(g_bserrno == 0);
5532 : :
5533 : 24 : spdk_blob_close(snapshot2, blob_op_complete, NULL);
5534 : 24 : poll_threads();
5535 : 24 : CU_ASSERT(g_bserrno == 0);
5536 : :
5537 : 24 : spdk_blob_close(snapshot, blob_op_complete, NULL);
5538 : 24 : poll_threads();
5539 : 24 : CU_ASSERT(g_bserrno == 0);
5540 : :
5541 : : /* Check snapshot-clone relations */
5542 : 24 : count = 2;
5543 : 24 : CU_ASSERT(spdk_blob_get_clones(bs, snapshotid, ids, &count) == 0);
5544 : 24 : CU_ASSERT(count == 1);
5545 : 24 : CU_ASSERT(ids[0] == snapshot2id);
5546 : :
5547 : 24 : count = 2;
5548 : 24 : CU_ASSERT(spdk_blob_get_clones(bs, snapshot2id, ids, &count) == 0);
5549 : 24 : CU_ASSERT(count == 1);
5550 : 24 : CU_ASSERT(ids[0] == blobid);
5551 : :
5552 : 24 : CU_ASSERT(spdk_blob_get_parent_snapshot(bs, blobid) == snapshot2id);
5553 : :
5554 : 24 : free_clusters = spdk_bs_free_cluster_count(bs);
5555 [ + + ]: 24 : if (!decouple_parent) {
5556 : : /* Do full blob inflation */
5557 : 12 : spdk_bs_inflate_blob(bs, channel, blobid, blob_op_complete, NULL);
5558 : 12 : poll_threads();
5559 : 12 : CU_ASSERT(g_bserrno == 0);
5560 : :
5561 : : /* All clusters should be inflated (except one already allocated
5562 : : * in a top level blob) */
5563 : 12 : CU_ASSERT(spdk_bs_free_cluster_count(bs) == free_clusters - 4);
5564 : :
5565 : : /* Check if relation tree updated correctly */
5566 : 12 : count = 2;
5567 : 12 : CU_ASSERT(spdk_blob_get_clones(bs, snapshotid, ids, &count) == 0);
5568 : :
5569 : : /* snapshotid have one clone */
5570 : 12 : CU_ASSERT(count == 1);
5571 : 12 : CU_ASSERT(ids[0] == snapshot2id);
5572 : :
5573 : : /* snapshot2id have no clones */
5574 : 12 : count = 2;
5575 : 12 : CU_ASSERT(spdk_blob_get_clones(bs, snapshot2id, ids, &count) == 0);
5576 : 12 : CU_ASSERT(count == 0);
5577 : :
5578 : 12 : CU_ASSERT(spdk_blob_get_parent_snapshot(bs, blobid) == SPDK_BLOBID_INVALID);
5579 : : } else {
5580 : : /* Decouple parent of blob */
5581 : 12 : spdk_bs_blob_decouple_parent(bs, channel, blobid, blob_op_complete, NULL);
5582 : 12 : poll_threads();
5583 : 12 : CU_ASSERT(g_bserrno == 0);
5584 : :
5585 : : /* Only one cluster from a parent should be inflated (second one
5586 : : * is covered by a cluster written on a top level blob, and
5587 : : * already allocated) */
5588 : 12 : CU_ASSERT(spdk_bs_free_cluster_count(bs) == free_clusters - 1);
5589 : :
5590 : : /* Check if relation tree updated correctly */
5591 : 12 : count = 2;
5592 : 12 : CU_ASSERT(spdk_blob_get_clones(bs, snapshotid, ids, &count) == 0);
5593 : :
5594 : : /* snapshotid have two clones now */
5595 : 12 : CU_ASSERT(count == 2);
5596 [ + - + - ]: 12 : CU_ASSERT(ids[0] == blobid || ids[1] == blobid);
5597 [ - + - - ]: 12 : CU_ASSERT(ids[0] == snapshot2id || ids[1] == snapshot2id);
5598 : :
5599 : : /* snapshot2id have no clones */
5600 : 12 : count = 2;
5601 : 12 : CU_ASSERT(spdk_blob_get_clones(bs, snapshot2id, ids, &count) == 0);
5602 : 12 : CU_ASSERT(count == 0);
5603 : :
5604 : 12 : CU_ASSERT(spdk_blob_get_parent_snapshot(bs, blobid) == snapshotid);
5605 : : }
5606 : :
5607 : : /* Try to delete snapshot2 (should pass) */
5608 : 24 : spdk_bs_delete_blob(bs, snapshot2id, blob_op_complete, NULL);
5609 : 24 : poll_threads();
5610 : 24 : CU_ASSERT(g_bserrno == 0);
5611 : :
5612 : : /* Try to delete base snapshot */
5613 : 24 : spdk_bs_delete_blob(bs, snapshotid, blob_op_complete, NULL);
5614 : 24 : poll_threads();
5615 : 24 : CU_ASSERT(g_bserrno == 0);
5616 : :
5617 : : /* Reopen blob after snapshot deletion */
5618 : 24 : spdk_bs_open_blob(bs, blobid, blob_op_with_handle_complete, NULL);
5619 : 24 : poll_threads();
5620 : 24 : CU_ASSERT(g_bserrno == 0);
5621 [ - + ]: 24 : SPDK_CU_ASSERT_FATAL(g_blob != NULL);
5622 : 24 : blob = g_blob;
5623 : :
5624 : 24 : CU_ASSERT(spdk_blob_get_num_clusters(blob) == 5);
5625 : :
5626 : : /* Check data consistency on inflated blob */
5627 [ - + ]: 24 : memset(payload_read, 0xFF, payload_size);
5628 : 24 : spdk_blob_io_read(blob, channel, payload_read, 0, pages_per_payload,
5629 : : blob_op_complete, NULL);
5630 : 24 : poll_threads();
5631 : 24 : CU_ASSERT(g_bserrno == 0);
5632 [ - + - + ]: 24 : CU_ASSERT(memcmp(payload_clone, payload_read, payload_size) == 0);
5633 : :
5634 : 24 : spdk_bs_free_io_channel(channel);
5635 : 24 : poll_threads();
5636 : :
5637 : 24 : free(payload_read);
5638 : 24 : free(payload_write);
5639 : 24 : free(payload_clone);
5640 : :
5641 : 24 : ut_blob_close_and_delete(bs, blob);
5642 : 24 : }
5643 : :
5644 : : static void
5645 : 12 : blob_inflate_rw(void)
5646 : : {
5647 : 12 : _blob_inflate_rw(false);
5648 : 12 : _blob_inflate_rw(true);
5649 : 12 : }
5650 : :
5651 : : /**
5652 : : * Snapshot-clones relation test
5653 : : *
5654 : : * snapshot
5655 : : * |
5656 : : * +-----+-----+
5657 : : * | |
5658 : : * blob(ro) snapshot2
5659 : : * | |
5660 : : * clone2 clone
5661 : : */
5662 : : static void
5663 : 12 : blob_relations(void)
5664 : : {
5665 : 12 : struct spdk_blob_store *bs;
5666 : : struct spdk_bs_dev *dev;
5667 : 12 : struct spdk_bs_opts bs_opts;
5668 : 12 : struct spdk_blob_opts opts;
5669 : : struct spdk_blob *blob, *snapshot, *snapshot2, *clone, *clone2;
5670 : : spdk_blob_id blobid, cloneid, snapshotid, cloneid2, snapshotid2;
5671 : : int rc;
5672 : 12 : size_t count;
5673 : 12 : spdk_blob_id ids[10] = {};
5674 : :
5675 : 12 : dev = init_dev();
5676 : 12 : spdk_bs_opts_init(&bs_opts, sizeof(bs_opts));
5677 : 12 : snprintf(bs_opts.bstype.bstype, sizeof(bs_opts.bstype.bstype), "TESTTYPE");
5678 : :
5679 : 12 : spdk_bs_init(dev, &bs_opts, bs_op_with_handle_complete, NULL);
5680 : 12 : poll_threads();
5681 : 12 : CU_ASSERT(g_bserrno == 0);
5682 [ - + ]: 12 : SPDK_CU_ASSERT_FATAL(g_bs != NULL);
5683 : 12 : bs = g_bs;
5684 : :
5685 : : /* 1. Create blob with 10 clusters */
5686 : :
5687 : 12 : ut_spdk_blob_opts_init(&opts);
5688 : 12 : opts.num_clusters = 10;
5689 : :
5690 : 12 : blob = ut_blob_create_and_open(bs, &opts);
5691 : 12 : blobid = spdk_blob_get_id(blob);
5692 : :
5693 : 12 : CU_ASSERT(!spdk_blob_is_read_only(blob));
5694 : 12 : CU_ASSERT(!spdk_blob_is_snapshot(blob));
5695 : 12 : CU_ASSERT(!spdk_blob_is_clone(blob));
5696 : 12 : CU_ASSERT(!spdk_blob_is_thin_provisioned(blob));
5697 : :
5698 : : /* blob should not have underlying snapshot nor clones */
5699 : 12 : CU_ASSERT(blob->parent_id == SPDK_BLOBID_INVALID);
5700 : 12 : CU_ASSERT(spdk_blob_get_parent_snapshot(bs, blobid) == SPDK_BLOBID_INVALID);
5701 : 12 : count = SPDK_COUNTOF(ids);
5702 : 12 : rc = spdk_blob_get_clones(bs, blobid, ids, &count);
5703 : 12 : CU_ASSERT(rc == 0);
5704 : 12 : CU_ASSERT(count == 0);
5705 : :
5706 : :
5707 : : /* 2. Create snapshot */
5708 : :
5709 : 12 : spdk_bs_create_snapshot(bs, blobid, NULL, blob_op_with_id_complete, NULL);
5710 : 12 : poll_threads();
5711 : 12 : CU_ASSERT(g_bserrno == 0);
5712 : 12 : CU_ASSERT(g_blobid != SPDK_BLOBID_INVALID);
5713 : 12 : snapshotid = g_blobid;
5714 : :
5715 : 12 : spdk_bs_open_blob(bs, snapshotid, blob_op_with_handle_complete, NULL);
5716 : 12 : poll_threads();
5717 : 12 : CU_ASSERT(g_bserrno == 0);
5718 [ - + ]: 12 : SPDK_CU_ASSERT_FATAL(g_blob != NULL);
5719 : 12 : snapshot = g_blob;
5720 : :
5721 : 12 : CU_ASSERT(spdk_blob_is_read_only(snapshot));
5722 : 12 : CU_ASSERT(spdk_blob_is_snapshot(snapshot));
5723 : 12 : CU_ASSERT(!spdk_blob_is_clone(snapshot));
5724 : 12 : CU_ASSERT(snapshot->parent_id == SPDK_BLOBID_INVALID);
5725 : 12 : CU_ASSERT(spdk_blob_get_parent_snapshot(bs, snapshotid) == SPDK_BLOBID_INVALID);
5726 : :
5727 : : /* Check if original blob is converted to the clone of snapshot */
5728 : 12 : CU_ASSERT(!spdk_blob_is_read_only(blob));
5729 : 12 : CU_ASSERT(!spdk_blob_is_snapshot(blob));
5730 : 12 : CU_ASSERT(spdk_blob_is_clone(blob));
5731 : 12 : CU_ASSERT(spdk_blob_is_thin_provisioned(blob));
5732 : 12 : CU_ASSERT(blob->parent_id == snapshotid);
5733 : 12 : CU_ASSERT(spdk_blob_get_parent_snapshot(bs, blobid) == snapshotid);
5734 : :
5735 : 12 : count = SPDK_COUNTOF(ids);
5736 : 12 : rc = spdk_blob_get_clones(bs, snapshotid, ids, &count);
5737 : 12 : CU_ASSERT(rc == 0);
5738 : 12 : CU_ASSERT(count == 1);
5739 : 12 : CU_ASSERT(ids[0] == blobid);
5740 : :
5741 : :
5742 : : /* 3. Create clone from snapshot */
5743 : :
5744 : 12 : spdk_bs_create_clone(bs, snapshotid, NULL, blob_op_with_id_complete, NULL);
5745 : 12 : poll_threads();
5746 : 12 : CU_ASSERT(g_bserrno == 0);
5747 : 12 : CU_ASSERT(g_blobid != SPDK_BLOBID_INVALID);
5748 : 12 : cloneid = g_blobid;
5749 : :
5750 : 12 : spdk_bs_open_blob(bs, cloneid, blob_op_with_handle_complete, NULL);
5751 : 12 : poll_threads();
5752 : 12 : CU_ASSERT(g_bserrno == 0);
5753 [ - + ]: 12 : SPDK_CU_ASSERT_FATAL(g_blob != NULL);
5754 : 12 : clone = g_blob;
5755 : :
5756 : 12 : CU_ASSERT(!spdk_blob_is_read_only(clone));
5757 : 12 : CU_ASSERT(!spdk_blob_is_snapshot(clone));
5758 : 12 : CU_ASSERT(spdk_blob_is_clone(clone));
5759 : 12 : CU_ASSERT(spdk_blob_is_thin_provisioned(clone));
5760 : 12 : CU_ASSERT(clone->parent_id == snapshotid);
5761 : 12 : CU_ASSERT(spdk_blob_get_parent_snapshot(bs, cloneid) == snapshotid);
5762 : :
5763 : 12 : count = SPDK_COUNTOF(ids);
5764 : 12 : rc = spdk_blob_get_clones(bs, cloneid, ids, &count);
5765 : 12 : CU_ASSERT(rc == 0);
5766 : 12 : CU_ASSERT(count == 0);
5767 : :
5768 : : /* Check if clone is on the snapshot's list */
5769 : 12 : count = SPDK_COUNTOF(ids);
5770 : 12 : rc = spdk_blob_get_clones(bs, snapshotid, ids, &count);
5771 : 12 : CU_ASSERT(rc == 0);
5772 [ - + - - ]: 12 : CU_ASSERT(ids[0] == blobid || ids[1] == blobid);
5773 [ + - + - ]: 12 : CU_ASSERT(ids[0] == cloneid || ids[1] == cloneid);
5774 : :
5775 : :
5776 : : /* 4. Create snapshot of the clone */
5777 : :
5778 : 12 : spdk_bs_create_snapshot(bs, cloneid, NULL, blob_op_with_id_complete, NULL);
5779 : 12 : poll_threads();
5780 : 12 : CU_ASSERT(g_bserrno == 0);
5781 : 12 : CU_ASSERT(g_blobid != SPDK_BLOBID_INVALID);
5782 : 12 : snapshotid2 = g_blobid;
5783 : :
5784 : 12 : spdk_bs_open_blob(bs, snapshotid2, blob_op_with_handle_complete, NULL);
5785 : 12 : poll_threads();
5786 : 12 : CU_ASSERT(g_bserrno == 0);
5787 [ - + ]: 12 : SPDK_CU_ASSERT_FATAL(g_blob != NULL);
5788 : 12 : snapshot2 = g_blob;
5789 : :
5790 : 12 : CU_ASSERT(spdk_blob_is_read_only(snapshot2));
5791 : 12 : CU_ASSERT(spdk_blob_is_snapshot(snapshot2));
5792 : 12 : CU_ASSERT(spdk_blob_is_clone(snapshot2));
5793 : 12 : CU_ASSERT(snapshot2->parent_id == snapshotid);
5794 : 12 : CU_ASSERT(spdk_blob_get_parent_snapshot(bs, snapshotid2) == snapshotid);
5795 : :
5796 : : /* Check if clone is converted to the clone of snapshot2 and snapshot2
5797 : : * is a child of snapshot */
5798 : 12 : CU_ASSERT(!spdk_blob_is_read_only(clone));
5799 : 12 : CU_ASSERT(!spdk_blob_is_snapshot(clone));
5800 : 12 : CU_ASSERT(spdk_blob_is_clone(clone));
5801 : 12 : CU_ASSERT(spdk_blob_is_thin_provisioned(clone));
5802 : 12 : CU_ASSERT(clone->parent_id == snapshotid2);
5803 : 12 : CU_ASSERT(spdk_blob_get_parent_snapshot(bs, cloneid) == snapshotid2);
5804 : :
5805 : 12 : count = SPDK_COUNTOF(ids);
5806 : 12 : rc = spdk_blob_get_clones(bs, snapshotid2, ids, &count);
5807 : 12 : CU_ASSERT(rc == 0);
5808 : 12 : CU_ASSERT(count == 1);
5809 : 12 : CU_ASSERT(ids[0] == cloneid);
5810 : :
5811 : :
5812 : : /* 5. Try to create clone from read only blob */
5813 : :
5814 : : /* Mark blob as read only */
5815 : 12 : spdk_blob_set_read_only(blob);
5816 : 12 : spdk_blob_sync_md(blob, blob_op_complete, NULL);
5817 : 12 : poll_threads();
5818 : 12 : CU_ASSERT(g_bserrno == 0);
5819 : :
5820 : : /* Check if previously created blob is read only clone */
5821 : 12 : CU_ASSERT(spdk_blob_is_read_only(blob));
5822 : 12 : CU_ASSERT(!spdk_blob_is_snapshot(blob));
5823 : 12 : CU_ASSERT(spdk_blob_is_clone(blob));
5824 : 12 : CU_ASSERT(spdk_blob_is_thin_provisioned(blob));
5825 : :
5826 : : /* Create clone from read only blob */
5827 : 12 : spdk_bs_create_clone(bs, blobid, NULL, blob_op_with_id_complete, NULL);
5828 : 12 : poll_threads();
5829 : 12 : CU_ASSERT(g_bserrno == 0);
5830 : 12 : CU_ASSERT(g_blobid != SPDK_BLOBID_INVALID);
5831 : 12 : cloneid2 = g_blobid;
5832 : :
5833 : 12 : spdk_bs_open_blob(bs, cloneid2, blob_op_with_handle_complete, NULL);
5834 : 12 : poll_threads();
5835 : 12 : CU_ASSERT(g_bserrno == 0);
5836 [ - + ]: 12 : SPDK_CU_ASSERT_FATAL(g_blob != NULL);
5837 : 12 : clone2 = g_blob;
5838 : :
5839 : 12 : CU_ASSERT(!spdk_blob_is_read_only(clone2));
5840 : 12 : CU_ASSERT(!spdk_blob_is_snapshot(clone2));
5841 : 12 : CU_ASSERT(spdk_blob_is_clone(clone2));
5842 : 12 : CU_ASSERT(spdk_blob_is_thin_provisioned(clone2));
5843 : :
5844 : 12 : CU_ASSERT(spdk_blob_get_parent_snapshot(bs, cloneid2) == blobid);
5845 : :
5846 : 12 : count = SPDK_COUNTOF(ids);
5847 : 12 : rc = spdk_blob_get_clones(bs, blobid, ids, &count);
5848 : 12 : CU_ASSERT(rc == 0);
5849 : :
5850 : 12 : CU_ASSERT(count == 1);
5851 : 12 : CU_ASSERT(ids[0] == cloneid2);
5852 : :
5853 : : /* Close blobs */
5854 : :
5855 : 12 : spdk_blob_close(clone2, blob_op_complete, NULL);
5856 : 12 : poll_threads();
5857 : 12 : CU_ASSERT(g_bserrno == 0);
5858 : :
5859 : 12 : spdk_blob_close(blob, blob_op_complete, NULL);
5860 : 12 : poll_threads();
5861 : 12 : CU_ASSERT(g_bserrno == 0);
5862 : :
5863 : 12 : spdk_blob_close(clone, blob_op_complete, NULL);
5864 : 12 : poll_threads();
5865 : 12 : CU_ASSERT(g_bserrno == 0);
5866 : :
5867 : 12 : spdk_blob_close(snapshot, blob_op_complete, NULL);
5868 : 12 : poll_threads();
5869 : 12 : CU_ASSERT(g_bserrno == 0);
5870 : :
5871 : 12 : spdk_blob_close(snapshot2, blob_op_complete, NULL);
5872 : 12 : poll_threads();
5873 : 12 : CU_ASSERT(g_bserrno == 0);
5874 : :
5875 : : /* Try to delete snapshot with more than 1 clone */
5876 : 12 : spdk_bs_delete_blob(bs, snapshotid, blob_op_complete, NULL);
5877 : 12 : poll_threads();
5878 : 12 : CU_ASSERT(g_bserrno != 0);
5879 : :
5880 : 12 : ut_bs_reload(&bs, &bs_opts);
5881 : :
5882 : : /* NULL ids array should return number of clones in count */
5883 : 12 : count = SPDK_COUNTOF(ids);
5884 : 12 : rc = spdk_blob_get_clones(bs, snapshotid, NULL, &count);
5885 : 12 : CU_ASSERT(rc == -ENOMEM);
5886 : 12 : CU_ASSERT(count == 2);
5887 : :
5888 : : /* incorrect array size */
5889 : 12 : count = 1;
5890 : 12 : rc = spdk_blob_get_clones(bs, snapshotid, ids, &count);
5891 : 12 : CU_ASSERT(rc == -ENOMEM);
5892 : 12 : CU_ASSERT(count == 2);
5893 : :
5894 : :
5895 : : /* Verify structure of loaded blob store */
5896 : :
5897 : : /* snapshot */
5898 : 12 : CU_ASSERT(spdk_blob_get_parent_snapshot(bs, snapshotid) == SPDK_BLOBID_INVALID);
5899 : :
5900 : 12 : count = SPDK_COUNTOF(ids);
5901 : 12 : rc = spdk_blob_get_clones(bs, snapshotid, ids, &count);
5902 : 12 : CU_ASSERT(rc == 0);
5903 : 12 : CU_ASSERT(count == 2);
5904 [ - + - - ]: 12 : CU_ASSERT(ids[0] == blobid || ids[1] == blobid);
5905 [ + - + - ]: 12 : CU_ASSERT(ids[0] == snapshotid2 || ids[1] == snapshotid2);
5906 : :
5907 : : /* blob */
5908 : 12 : CU_ASSERT(spdk_blob_get_parent_snapshot(bs, blobid) == snapshotid);
5909 : 12 : count = SPDK_COUNTOF(ids);
5910 : 12 : rc = spdk_blob_get_clones(bs, blobid, ids, &count);
5911 : 12 : CU_ASSERT(rc == 0);
5912 : 12 : CU_ASSERT(count == 1);
5913 : 12 : CU_ASSERT(ids[0] == cloneid2);
5914 : :
5915 : : /* clone */
5916 : 12 : CU_ASSERT(spdk_blob_get_parent_snapshot(bs, cloneid) == snapshotid2);
5917 : 12 : count = SPDK_COUNTOF(ids);
5918 : 12 : rc = spdk_blob_get_clones(bs, cloneid, ids, &count);
5919 : 12 : CU_ASSERT(rc == 0);
5920 : 12 : CU_ASSERT(count == 0);
5921 : :
5922 : : /* snapshot2 */
5923 : 12 : CU_ASSERT(spdk_blob_get_parent_snapshot(bs, snapshotid2) == snapshotid);
5924 : 12 : count = SPDK_COUNTOF(ids);
5925 : 12 : rc = spdk_blob_get_clones(bs, snapshotid2, ids, &count);
5926 : 12 : CU_ASSERT(rc == 0);
5927 : 12 : CU_ASSERT(count == 1);
5928 : 12 : CU_ASSERT(ids[0] == cloneid);
5929 : :
5930 : : /* clone2 */
5931 : 12 : CU_ASSERT(spdk_blob_get_parent_snapshot(bs, cloneid2) == blobid);
5932 : 12 : count = SPDK_COUNTOF(ids);
5933 : 12 : rc = spdk_blob_get_clones(bs, cloneid2, ids, &count);
5934 : 12 : CU_ASSERT(rc == 0);
5935 : 12 : CU_ASSERT(count == 0);
5936 : :
5937 : : /* Try to delete blob that user should not be able to remove */
5938 : :
5939 : 12 : spdk_bs_delete_blob(bs, snapshotid, blob_op_complete, NULL);
5940 : 12 : poll_threads();
5941 : 12 : CU_ASSERT(g_bserrno != 0);
5942 : :
5943 : : /* Remove all blobs */
5944 : :
5945 : 12 : spdk_bs_delete_blob(bs, cloneid, blob_op_complete, NULL);
5946 : 12 : poll_threads();
5947 : 12 : CU_ASSERT(g_bserrno == 0);
5948 : :
5949 : 12 : spdk_bs_delete_blob(bs, snapshotid2, blob_op_complete, NULL);
5950 : 12 : poll_threads();
5951 : 12 : CU_ASSERT(g_bserrno == 0);
5952 : :
5953 : 12 : spdk_bs_delete_blob(bs, cloneid2, blob_op_complete, NULL);
5954 : 12 : poll_threads();
5955 : 12 : CU_ASSERT(g_bserrno == 0);
5956 : :
5957 : 12 : spdk_bs_delete_blob(bs, blobid, blob_op_complete, NULL);
5958 : 12 : poll_threads();
5959 : 12 : CU_ASSERT(g_bserrno == 0);
5960 : :
5961 : 12 : spdk_bs_delete_blob(bs, snapshotid, blob_op_complete, NULL);
5962 : 12 : poll_threads();
5963 : 12 : CU_ASSERT(g_bserrno == 0);
5964 : :
5965 : 12 : spdk_bs_unload(bs, bs_op_complete, NULL);
5966 : 12 : poll_threads();
5967 : 12 : CU_ASSERT(g_bserrno == 0);
5968 : :
5969 : 12 : g_bs = NULL;
5970 : 12 : }
5971 : :
5972 : : /**
5973 : : * Snapshot-clones relation test 2
5974 : : *
5975 : : * snapshot1
5976 : : * |
5977 : : * snapshot2
5978 : : * |
5979 : : * +-----+-----+
5980 : : * | |
5981 : : * blob(ro) snapshot3
5982 : : * | |
5983 : : * | snapshot4
5984 : : * | | |
5985 : : * clone2 clone clone3
5986 : : */
5987 : : static void
5988 : 12 : blob_relations2(void)
5989 : : {
5990 : 12 : struct spdk_blob_store *bs;
5991 : : struct spdk_bs_dev *dev;
5992 : 12 : struct spdk_bs_opts bs_opts;
5993 : 12 : struct spdk_blob_opts opts;
5994 : : struct spdk_blob *blob, *snapshot1, *snapshot2, *snapshot3, *snapshot4, *clone, *clone2;
5995 : : spdk_blob_id blobid, snapshotid1, snapshotid2, snapshotid3, snapshotid4, cloneid, cloneid2,
5996 : : cloneid3;
5997 : : int rc;
5998 : 12 : size_t count;
5999 : 12 : spdk_blob_id ids[10] = {};
6000 : :
6001 : 12 : dev = init_dev();
6002 : 12 : spdk_bs_opts_init(&bs_opts, sizeof(bs_opts));
6003 : 12 : snprintf(bs_opts.bstype.bstype, sizeof(bs_opts.bstype.bstype), "TESTTYPE");
6004 : :
6005 : 12 : spdk_bs_init(dev, &bs_opts, bs_op_with_handle_complete, NULL);
6006 : 12 : poll_threads();
6007 : 12 : CU_ASSERT(g_bserrno == 0);
6008 [ - + ]: 12 : SPDK_CU_ASSERT_FATAL(g_bs != NULL);
6009 : 12 : bs = g_bs;
6010 : :
6011 : : /* 1. Create blob with 10 clusters */
6012 : :
6013 : 12 : ut_spdk_blob_opts_init(&opts);
6014 : 12 : opts.num_clusters = 10;
6015 : :
6016 : 12 : blob = ut_blob_create_and_open(bs, &opts);
6017 : 12 : blobid = spdk_blob_get_id(blob);
6018 : :
6019 : : /* 2. Create snapshot1 */
6020 : :
6021 : 12 : spdk_bs_create_snapshot(bs, blobid, NULL, blob_op_with_id_complete, NULL);
6022 : 12 : poll_threads();
6023 : 12 : CU_ASSERT(g_bserrno == 0);
6024 : 12 : CU_ASSERT(g_blobid != SPDK_BLOBID_INVALID);
6025 : 12 : snapshotid1 = g_blobid;
6026 : :
6027 : 12 : spdk_bs_open_blob(bs, snapshotid1, blob_op_with_handle_complete, NULL);
6028 : 12 : poll_threads();
6029 : 12 : CU_ASSERT(g_bserrno == 0);
6030 [ - + ]: 12 : SPDK_CU_ASSERT_FATAL(g_blob != NULL);
6031 : 12 : snapshot1 = g_blob;
6032 : :
6033 : 12 : CU_ASSERT(snapshot1->parent_id == SPDK_BLOBID_INVALID);
6034 : 12 : CU_ASSERT(spdk_blob_get_parent_snapshot(bs, snapshotid1) == SPDK_BLOBID_INVALID);
6035 : :
6036 : 12 : CU_ASSERT(blob->parent_id == snapshotid1);
6037 : 12 : CU_ASSERT(spdk_blob_get_parent_snapshot(bs, blobid) == snapshotid1);
6038 : :
6039 : : /* Check if blob is the clone of snapshot1 */
6040 : 12 : CU_ASSERT(blob->parent_id == snapshotid1);
6041 : 12 : CU_ASSERT(spdk_blob_get_parent_snapshot(bs, blobid) == snapshotid1);
6042 : :
6043 : 12 : count = SPDK_COUNTOF(ids);
6044 : 12 : rc = spdk_blob_get_clones(bs, snapshotid1, ids, &count);
6045 : 12 : CU_ASSERT(rc == 0);
6046 : 12 : CU_ASSERT(count == 1);
6047 : 12 : CU_ASSERT(ids[0] == blobid);
6048 : :
6049 : : /* 3. Create another snapshot */
6050 : :
6051 : 12 : spdk_bs_create_snapshot(bs, blobid, NULL, blob_op_with_id_complete, NULL);
6052 : 12 : poll_threads();
6053 : 12 : CU_ASSERT(g_bserrno == 0);
6054 : 12 : CU_ASSERT(g_blobid != SPDK_BLOBID_INVALID);
6055 : 12 : snapshotid2 = g_blobid;
6056 : :
6057 : 12 : spdk_bs_open_blob(bs, snapshotid2, blob_op_with_handle_complete, NULL);
6058 : 12 : poll_threads();
6059 : 12 : CU_ASSERT(g_bserrno == 0);
6060 [ - + ]: 12 : SPDK_CU_ASSERT_FATAL(g_blob != NULL);
6061 : 12 : snapshot2 = g_blob;
6062 : :
6063 : 12 : CU_ASSERT(spdk_blob_is_clone(snapshot2));
6064 : 12 : CU_ASSERT(snapshot2->parent_id == snapshotid1);
6065 : 12 : CU_ASSERT(spdk_blob_get_parent_snapshot(bs, snapshotid2) == snapshotid1);
6066 : :
6067 : : /* Check if snapshot2 is the clone of snapshot1 and blob
6068 : : * is a child of snapshot2 */
6069 : 12 : CU_ASSERT(blob->parent_id == snapshotid2);
6070 : 12 : CU_ASSERT(spdk_blob_get_parent_snapshot(bs, blobid) == snapshotid2);
6071 : :
6072 : 12 : count = SPDK_COUNTOF(ids);
6073 : 12 : rc = spdk_blob_get_clones(bs, snapshotid2, ids, &count);
6074 : 12 : CU_ASSERT(rc == 0);
6075 : 12 : CU_ASSERT(count == 1);
6076 : 12 : CU_ASSERT(ids[0] == blobid);
6077 : :
6078 : : /* 4. Create clone from snapshot */
6079 : :
6080 : 12 : spdk_bs_create_clone(bs, snapshotid2, NULL, blob_op_with_id_complete, NULL);
6081 : 12 : poll_threads();
6082 : 12 : CU_ASSERT(g_bserrno == 0);
6083 : 12 : CU_ASSERT(g_blobid != SPDK_BLOBID_INVALID);
6084 : 12 : cloneid = g_blobid;
6085 : :
6086 : 12 : spdk_bs_open_blob(bs, cloneid, blob_op_with_handle_complete, NULL);
6087 : 12 : poll_threads();
6088 : 12 : CU_ASSERT(g_bserrno == 0);
6089 [ - + ]: 12 : SPDK_CU_ASSERT_FATAL(g_blob != NULL);
6090 : 12 : clone = g_blob;
6091 : :
6092 : 12 : CU_ASSERT(clone->parent_id == snapshotid2);
6093 : 12 : CU_ASSERT(spdk_blob_get_parent_snapshot(bs, cloneid) == snapshotid2);
6094 : :
6095 : : /* Check if clone is on the snapshot's list */
6096 : 12 : count = SPDK_COUNTOF(ids);
6097 : 12 : rc = spdk_blob_get_clones(bs, snapshotid2, ids, &count);
6098 : 12 : CU_ASSERT(rc == 0);
6099 : 12 : CU_ASSERT(count == 2);
6100 [ - + - - ]: 12 : CU_ASSERT(ids[0] == blobid || ids[1] == blobid);
6101 [ + - + - ]: 12 : CU_ASSERT(ids[0] == cloneid || ids[1] == cloneid);
6102 : :
6103 : : /* 5. Create snapshot of the clone */
6104 : :
6105 : 12 : spdk_bs_create_snapshot(bs, cloneid, NULL, blob_op_with_id_complete, NULL);
6106 : 12 : poll_threads();
6107 : 12 : CU_ASSERT(g_bserrno == 0);
6108 : 12 : CU_ASSERT(g_blobid != SPDK_BLOBID_INVALID);
6109 : 12 : snapshotid3 = g_blobid;
6110 : :
6111 : 12 : spdk_bs_open_blob(bs, snapshotid3, blob_op_with_handle_complete, NULL);
6112 : 12 : poll_threads();
6113 : 12 : CU_ASSERT(g_bserrno == 0);
6114 [ - + ]: 12 : SPDK_CU_ASSERT_FATAL(g_blob != NULL);
6115 : 12 : snapshot3 = g_blob;
6116 : :
6117 : 12 : CU_ASSERT(snapshot3->parent_id == snapshotid2);
6118 : 12 : CU_ASSERT(spdk_blob_get_parent_snapshot(bs, snapshotid3) == snapshotid2);
6119 : :
6120 : : /* Check if clone is converted to the clone of snapshot3 and snapshot3
6121 : : * is a child of snapshot2 */
6122 : 12 : CU_ASSERT(clone->parent_id == snapshotid3);
6123 : 12 : CU_ASSERT(spdk_blob_get_parent_snapshot(bs, cloneid) == snapshotid3);
6124 : :
6125 : 12 : count = SPDK_COUNTOF(ids);
6126 : 12 : rc = spdk_blob_get_clones(bs, snapshotid3, ids, &count);
6127 : 12 : CU_ASSERT(rc == 0);
6128 : 12 : CU_ASSERT(count == 1);
6129 : 12 : CU_ASSERT(ids[0] == cloneid);
6130 : :
6131 : : /* 6. Create another snapshot of the clone */
6132 : :
6133 : 12 : spdk_bs_create_snapshot(bs, cloneid, NULL, blob_op_with_id_complete, NULL);
6134 : 12 : poll_threads();
6135 : 12 : CU_ASSERT(g_bserrno == 0);
6136 : 12 : CU_ASSERT(g_blobid != SPDK_BLOBID_INVALID);
6137 : 12 : snapshotid4 = g_blobid;
6138 : :
6139 : 12 : spdk_bs_open_blob(bs, snapshotid4, blob_op_with_handle_complete, NULL);
6140 : 12 : poll_threads();
6141 : 12 : CU_ASSERT(g_bserrno == 0);
6142 [ - + ]: 12 : SPDK_CU_ASSERT_FATAL(g_blob != NULL);
6143 : 12 : snapshot4 = g_blob;
6144 : :
6145 : 12 : CU_ASSERT(snapshot4->parent_id == snapshotid3);
6146 : 12 : CU_ASSERT(spdk_blob_get_parent_snapshot(bs, snapshotid4) == snapshotid3);
6147 : :
6148 : : /* Check if clone is converted to the clone of snapshot4 and snapshot4
6149 : : * is a child of snapshot3 */
6150 : 12 : CU_ASSERT(clone->parent_id == snapshotid4);
6151 : 12 : CU_ASSERT(spdk_blob_get_parent_snapshot(bs, cloneid) == snapshotid4);
6152 : :
6153 : 12 : count = SPDK_COUNTOF(ids);
6154 : 12 : rc = spdk_blob_get_clones(bs, snapshotid4, ids, &count);
6155 : 12 : CU_ASSERT(rc == 0);
6156 : 12 : CU_ASSERT(count == 1);
6157 : 12 : CU_ASSERT(ids[0] == cloneid);
6158 : :
6159 : : /* 7. Remove snapshot 4 */
6160 : :
6161 : 12 : ut_blob_close_and_delete(bs, snapshot4);
6162 : :
6163 : : /* Check if relations are back to state from before creating snapshot 4 */
6164 : 12 : CU_ASSERT(clone->parent_id == snapshotid3);
6165 : 12 : CU_ASSERT(spdk_blob_get_parent_snapshot(bs, cloneid) == snapshotid3);
6166 : :
6167 : 12 : count = SPDK_COUNTOF(ids);
6168 : 12 : rc = spdk_blob_get_clones(bs, snapshotid3, ids, &count);
6169 : 12 : CU_ASSERT(rc == 0);
6170 : 12 : CU_ASSERT(count == 1);
6171 : 12 : CU_ASSERT(ids[0] == cloneid);
6172 : :
6173 : : /* 8. Create second clone of snapshot 3 and try to remove snapshot 3 */
6174 : :
6175 : 12 : spdk_bs_create_clone(bs, snapshotid3, NULL, blob_op_with_id_complete, NULL);
6176 : 12 : poll_threads();
6177 : 12 : CU_ASSERT(g_bserrno == 0);
6178 : 12 : CU_ASSERT(g_blobid != SPDK_BLOBID_INVALID);
6179 : 12 : cloneid3 = g_blobid;
6180 : :
6181 : 12 : spdk_bs_delete_blob(bs, snapshotid3, blob_op_complete, NULL);
6182 : 12 : poll_threads();
6183 : 12 : CU_ASSERT(g_bserrno != 0);
6184 : :
6185 : : /* 9. Open snapshot 3 again and try to remove it while clone 3 is closed */
6186 : :
6187 : 12 : spdk_bs_open_blob(bs, snapshotid3, blob_op_with_handle_complete, NULL);
6188 : 12 : poll_threads();
6189 : 12 : CU_ASSERT(g_bserrno == 0);
6190 [ - + ]: 12 : SPDK_CU_ASSERT_FATAL(g_blob != NULL);
6191 : 12 : snapshot3 = g_blob;
6192 : :
6193 : 12 : spdk_bs_delete_blob(bs, snapshotid3, blob_op_complete, NULL);
6194 : 12 : poll_threads();
6195 : 12 : CU_ASSERT(g_bserrno != 0);
6196 : :
6197 : 12 : spdk_blob_close(snapshot3, blob_op_complete, NULL);
6198 : 12 : poll_threads();
6199 : 12 : CU_ASSERT(g_bserrno == 0);
6200 : :
6201 : 12 : spdk_bs_delete_blob(bs, cloneid3, blob_op_complete, NULL);
6202 : 12 : poll_threads();
6203 : 12 : CU_ASSERT(g_bserrno == 0);
6204 : :
6205 : : /* 10. Remove snapshot 1 */
6206 : :
6207 : : /* Check snapshot 1 and snapshot 2 allocated clusters */
6208 : 12 : CU_ASSERT(spdk_blob_get_num_allocated_clusters(snapshot1) == 10);
6209 : 12 : CU_ASSERT(spdk_blob_get_num_allocated_clusters(snapshot2) == 0);
6210 : :
6211 : 12 : ut_blob_close_and_delete(bs, snapshot1);
6212 : :
6213 : : /* Check if relations are back to state from before creating snapshot 4 (before step 6) */
6214 : 12 : CU_ASSERT(snapshot2->parent_id == SPDK_BLOBID_INVALID);
6215 : 12 : CU_ASSERT(spdk_blob_get_parent_snapshot(bs, snapshotid2) == SPDK_BLOBID_INVALID);
6216 : :
6217 : : /* Check that snapshot 2 has the clusters that were allocated to snapshot 1 */
6218 : 12 : CU_ASSERT(spdk_blob_get_num_allocated_clusters(snapshot2) == 10);
6219 : :
6220 : 12 : count = SPDK_COUNTOF(ids);
6221 : 12 : rc = spdk_blob_get_clones(bs, snapshotid2, ids, &count);
6222 : 12 : CU_ASSERT(rc == 0);
6223 : 12 : CU_ASSERT(count == 2);
6224 [ - + - - ]: 12 : CU_ASSERT(ids[0] == blobid || ids[1] == blobid);
6225 [ + - + - ]: 12 : CU_ASSERT(ids[0] == snapshotid3 || ids[1] == snapshotid3);
6226 : :
6227 : : /* 11. Try to create clone from read only blob */
6228 : :
6229 : : /* Mark blob as read only */
6230 : 12 : spdk_blob_set_read_only(blob);
6231 : 12 : spdk_blob_sync_md(blob, blob_op_complete, NULL);
6232 : 12 : poll_threads();
6233 : 12 : CU_ASSERT(g_bserrno == 0);
6234 : :
6235 : : /* Create clone from read only blob */
6236 : 12 : spdk_bs_create_clone(bs, blobid, NULL, blob_op_with_id_complete, NULL);
6237 : 12 : poll_threads();
6238 : 12 : CU_ASSERT(g_bserrno == 0);
6239 : 12 : CU_ASSERT(g_blobid != SPDK_BLOBID_INVALID);
6240 : 12 : cloneid2 = g_blobid;
6241 : :
6242 : 12 : spdk_bs_open_blob(bs, cloneid2, blob_op_with_handle_complete, NULL);
6243 : 12 : poll_threads();
6244 : 12 : CU_ASSERT(g_bserrno == 0);
6245 [ - + ]: 12 : SPDK_CU_ASSERT_FATAL(g_blob != NULL);
6246 : 12 : clone2 = g_blob;
6247 : :
6248 : 12 : CU_ASSERT(spdk_blob_get_parent_snapshot(bs, cloneid2) == blobid);
6249 : :
6250 : 12 : count = SPDK_COUNTOF(ids);
6251 : 12 : rc = spdk_blob_get_clones(bs, blobid, ids, &count);
6252 : 12 : CU_ASSERT(rc == 0);
6253 : 12 : CU_ASSERT(count == 1);
6254 : 12 : CU_ASSERT(ids[0] == cloneid2);
6255 : :
6256 : : /* Close blobs */
6257 : :
6258 : 12 : spdk_blob_close(clone2, blob_op_complete, NULL);
6259 : 12 : poll_threads();
6260 : 12 : CU_ASSERT(g_bserrno == 0);
6261 : :
6262 : 12 : spdk_blob_close(blob, blob_op_complete, NULL);
6263 : 12 : poll_threads();
6264 : 12 : CU_ASSERT(g_bserrno == 0);
6265 : :
6266 : 12 : spdk_blob_close(clone, blob_op_complete, NULL);
6267 : 12 : poll_threads();
6268 : 12 : CU_ASSERT(g_bserrno == 0);
6269 : :
6270 : 12 : spdk_blob_close(snapshot2, blob_op_complete, NULL);
6271 : 12 : poll_threads();
6272 : 12 : CU_ASSERT(g_bserrno == 0);
6273 : :
6274 : 12 : spdk_blob_close(snapshot3, blob_op_complete, NULL);
6275 : 12 : poll_threads();
6276 : 12 : CU_ASSERT(g_bserrno == 0);
6277 : :
6278 : 12 : ut_bs_reload(&bs, &bs_opts);
6279 : :
6280 : : /* Verify structure of loaded blob store */
6281 : :
6282 : : /* snapshot2 */
6283 : 12 : CU_ASSERT(spdk_blob_get_parent_snapshot(bs, snapshotid2) == SPDK_BLOBID_INVALID);
6284 : :
6285 : 12 : count = SPDK_COUNTOF(ids);
6286 : 12 : rc = spdk_blob_get_clones(bs, snapshotid2, ids, &count);
6287 : 12 : CU_ASSERT(rc == 0);
6288 : 12 : CU_ASSERT(count == 2);
6289 [ - + - - ]: 12 : CU_ASSERT(ids[0] == blobid || ids[1] == blobid);
6290 [ + - + - ]: 12 : CU_ASSERT(ids[0] == snapshotid3 || ids[1] == snapshotid3);
6291 : :
6292 : : /* blob */
6293 : 12 : CU_ASSERT(spdk_blob_get_parent_snapshot(bs, blobid) == snapshotid2);
6294 : 12 : count = SPDK_COUNTOF(ids);
6295 : 12 : rc = spdk_blob_get_clones(bs, blobid, ids, &count);
6296 : 12 : CU_ASSERT(rc == 0);
6297 : 12 : CU_ASSERT(count == 1);
6298 : 12 : CU_ASSERT(ids[0] == cloneid2);
6299 : :
6300 : : /* clone */
6301 : 12 : CU_ASSERT(spdk_blob_get_parent_snapshot(bs, cloneid) == snapshotid3);
6302 : 12 : count = SPDK_COUNTOF(ids);
6303 : 12 : rc = spdk_blob_get_clones(bs, cloneid, ids, &count);
6304 : 12 : CU_ASSERT(rc == 0);
6305 : 12 : CU_ASSERT(count == 0);
6306 : :
6307 : : /* snapshot3 */
6308 : 12 : CU_ASSERT(spdk_blob_get_parent_snapshot(bs, snapshotid3) == snapshotid2);
6309 : 12 : count = SPDK_COUNTOF(ids);
6310 : 12 : rc = spdk_blob_get_clones(bs, snapshotid3, ids, &count);
6311 : 12 : CU_ASSERT(rc == 0);
6312 : 12 : CU_ASSERT(count == 1);
6313 : 12 : CU_ASSERT(ids[0] == cloneid);
6314 : :
6315 : : /* clone2 */
6316 : 12 : CU_ASSERT(spdk_blob_get_parent_snapshot(bs, cloneid2) == blobid);
6317 : 12 : count = SPDK_COUNTOF(ids);
6318 : 12 : rc = spdk_blob_get_clones(bs, cloneid2, ids, &count);
6319 : 12 : CU_ASSERT(rc == 0);
6320 : 12 : CU_ASSERT(count == 0);
6321 : :
6322 : : /* Try to delete all blobs in the worse possible order */
6323 : :
6324 : 12 : spdk_bs_delete_blob(bs, snapshotid2, blob_op_complete, NULL);
6325 : 12 : poll_threads();
6326 : 12 : CU_ASSERT(g_bserrno != 0);
6327 : :
6328 : 12 : spdk_bs_delete_blob(bs, snapshotid3, blob_op_complete, NULL);
6329 : 12 : poll_threads();
6330 : 12 : CU_ASSERT(g_bserrno == 0);
6331 : :
6332 : 12 : spdk_bs_delete_blob(bs, snapshotid2, blob_op_complete, NULL);
6333 : 12 : poll_threads();
6334 : 12 : CU_ASSERT(g_bserrno != 0);
6335 : :
6336 : 12 : spdk_bs_delete_blob(bs, cloneid, blob_op_complete, NULL);
6337 : 12 : poll_threads();
6338 : 12 : CU_ASSERT(g_bserrno == 0);
6339 : :
6340 : 12 : spdk_bs_delete_blob(bs, snapshotid2, blob_op_complete, NULL);
6341 : 12 : poll_threads();
6342 : 12 : CU_ASSERT(g_bserrno == 0);
6343 : :
6344 : 12 : spdk_bs_delete_blob(bs, blobid, blob_op_complete, NULL);
6345 : 12 : poll_threads();
6346 : 12 : CU_ASSERT(g_bserrno == 0);
6347 : :
6348 : 12 : spdk_bs_delete_blob(bs, cloneid2, blob_op_complete, NULL);
6349 : 12 : poll_threads();
6350 : 12 : CU_ASSERT(g_bserrno == 0);
6351 : :
6352 : 12 : spdk_bs_unload(bs, bs_op_complete, NULL);
6353 : 12 : poll_threads();
6354 : 12 : CU_ASSERT(g_bserrno == 0);
6355 : :
6356 : 12 : g_bs = NULL;
6357 : 12 : }
6358 : :
6359 : : /**
6360 : : * Snapshot-clones relation test 3
6361 : : *
6362 : : * snapshot0
6363 : : * |
6364 : : * snapshot1
6365 : : * |
6366 : : * snapshot2
6367 : : * |
6368 : : * blob
6369 : : */
6370 : : static void
6371 : 12 : blob_relations3(void)
6372 : : {
6373 : : struct spdk_blob_store *bs;
6374 : : struct spdk_bs_dev *dev;
6375 : : struct spdk_io_channel *channel;
6376 : 12 : struct spdk_bs_opts bs_opts;
6377 : 12 : struct spdk_blob_opts opts;
6378 : : struct spdk_blob *blob;
6379 : : spdk_blob_id blobid, snapshotid0, snapshotid1, snapshotid2;
6380 : :
6381 : 12 : dev = init_dev();
6382 : 12 : spdk_bs_opts_init(&bs_opts, sizeof(bs_opts));
6383 : 12 : snprintf(bs_opts.bstype.bstype, sizeof(bs_opts.bstype.bstype), "TESTTYPE");
6384 : :
6385 : 12 : spdk_bs_init(dev, &bs_opts, bs_op_with_handle_complete, NULL);
6386 : 12 : poll_threads();
6387 : 12 : CU_ASSERT(g_bserrno == 0);
6388 [ - + ]: 12 : SPDK_CU_ASSERT_FATAL(g_bs != NULL);
6389 : 12 : bs = g_bs;
6390 : :
6391 : 12 : channel = spdk_bs_alloc_io_channel(bs);
6392 [ - + ]: 12 : SPDK_CU_ASSERT_FATAL(channel != NULL);
6393 : :
6394 : : /* 1. Create blob with 10 clusters */
6395 : 12 : ut_spdk_blob_opts_init(&opts);
6396 : 12 : opts.num_clusters = 10;
6397 : :
6398 : 12 : blob = ut_blob_create_and_open(bs, &opts);
6399 : 12 : blobid = spdk_blob_get_id(blob);
6400 : :
6401 : : /* 2. Create snapshot0 */
6402 : 12 : spdk_bs_create_snapshot(bs, blobid, NULL, blob_op_with_id_complete, NULL);
6403 : 12 : poll_threads();
6404 : 12 : CU_ASSERT(g_bserrno == 0);
6405 : 12 : CU_ASSERT(g_blobid != SPDK_BLOBID_INVALID);
6406 : 12 : snapshotid0 = g_blobid;
6407 : :
6408 : : /* 3. Create snapshot1 */
6409 : 12 : spdk_bs_create_snapshot(bs, blobid, NULL, blob_op_with_id_complete, NULL);
6410 : 12 : poll_threads();
6411 : 12 : CU_ASSERT(g_bserrno == 0);
6412 : 12 : CU_ASSERT(g_blobid != SPDK_BLOBID_INVALID);
6413 : 12 : snapshotid1 = g_blobid;
6414 : :
6415 : : /* 4. Create snapshot2 */
6416 : 12 : spdk_bs_create_snapshot(bs, blobid, NULL, blob_op_with_id_complete, NULL);
6417 : 12 : poll_threads();
6418 : 12 : CU_ASSERT(g_bserrno == 0);
6419 : 12 : CU_ASSERT(g_blobid != SPDK_BLOBID_INVALID);
6420 : 12 : snapshotid2 = g_blobid;
6421 : :
6422 : : /* 5. Decouple blob */
6423 : 12 : spdk_bs_blob_decouple_parent(bs, channel, blobid, blob_op_complete, NULL);
6424 : 12 : poll_threads();
6425 : 12 : CU_ASSERT(g_bserrno == 0);
6426 : :
6427 : : /* 6. Decouple snapshot2. Make sure updating md of snapshot2 is possible */
6428 : 12 : spdk_bs_blob_decouple_parent(bs, channel, snapshotid2, blob_op_complete, NULL);
6429 : 12 : poll_threads();
6430 : 12 : CU_ASSERT(g_bserrno == 0);
6431 : :
6432 : : /* 7. Delete blob */
6433 : 12 : spdk_blob_close(blob, blob_op_complete, NULL);
6434 : 12 : poll_threads();
6435 : 12 : CU_ASSERT(g_bserrno == 0);
6436 : :
6437 : 12 : spdk_bs_delete_blob(bs, blobid, blob_op_complete, NULL);
6438 : 12 : poll_threads();
6439 : 12 : CU_ASSERT(g_bserrno == 0);
6440 : :
6441 : : /* 8. Delete snapshot2.
6442 : : * If md of snapshot 2 was updated, it should be possible to delete it */
6443 : 12 : spdk_bs_delete_blob(bs, snapshotid2, blob_op_complete, NULL);
6444 : 12 : poll_threads();
6445 : 12 : CU_ASSERT(g_bserrno == 0);
6446 : :
6447 : : /* Remove remaining blobs and unload bs */
6448 : 12 : spdk_bs_delete_blob(bs, snapshotid1, blob_op_complete, NULL);
6449 : 12 : poll_threads();
6450 : 12 : CU_ASSERT(g_bserrno == 0);
6451 : :
6452 : 12 : spdk_bs_delete_blob(bs, snapshotid0, blob_op_complete, NULL);
6453 : 12 : poll_threads();
6454 : 12 : CU_ASSERT(g_bserrno == 0);
6455 : :
6456 : 12 : spdk_bs_free_io_channel(channel);
6457 : 12 : poll_threads();
6458 : :
6459 : 12 : spdk_bs_unload(bs, bs_op_complete, NULL);
6460 : 12 : poll_threads();
6461 : 12 : CU_ASSERT(g_bserrno == 0);
6462 : :
6463 : 12 : g_bs = NULL;
6464 : 12 : }
6465 : :
6466 : : static void
6467 : 12 : blobstore_clean_power_failure(void)
6468 : : {
6469 : : struct spdk_blob_store *bs;
6470 : : struct spdk_blob *blob;
6471 : 12 : struct spdk_power_failure_thresholds thresholds = {};
6472 : 12 : bool clean = false;
6473 : 12 : struct spdk_bs_super_block *super = (struct spdk_bs_super_block *)&g_dev_buffer[0];
6474 : 12 : struct spdk_bs_super_block super_copy = {};
6475 : :
6476 : 12 : thresholds.general_threshold = 1;
6477 [ + + ]: 60 : while (!clean) {
6478 : : /* Create bs and blob */
6479 : 48 : suite_blob_setup();
6480 [ - + ]: 48 : SPDK_CU_ASSERT_FATAL(g_bs != NULL);
6481 [ - + ]: 48 : SPDK_CU_ASSERT_FATAL(g_blob != NULL);
6482 : 48 : bs = g_bs;
6483 : 48 : blob = g_blob;
6484 : :
6485 : : /* Super block should not change for rest of the UT,
6486 : : * save it and compare later. */
6487 : 48 : memcpy(&super_copy, super, sizeof(struct spdk_bs_super_block));
6488 [ - + ]: 48 : SPDK_CU_ASSERT_FATAL(super->clean == 0);
6489 [ - + - + ]: 48 : SPDK_CU_ASSERT_FATAL(bs->clean == 0);
6490 : :
6491 : : /* Force bs/super block in a clean state.
6492 : : * Along with marking blob dirty, to cause blob persist. */
6493 : 48 : blob->state = SPDK_BLOB_STATE_DIRTY;
6494 : 48 : bs->clean = 1;
6495 : 48 : super->clean = 1;
6496 : 48 : super->crc = blob_md_page_calc_crc(super);
6497 : :
6498 : 48 : g_bserrno = -1;
6499 : 48 : dev_set_power_failure_thresholds(thresholds);
6500 : 48 : spdk_blob_sync_md(blob, blob_op_complete, NULL);
6501 : 48 : poll_threads();
6502 : 48 : dev_reset_power_failure_event();
6503 : :
6504 [ + + ]: 48 : if (g_bserrno == 0) {
6505 : : /* After successful md sync, both bs and super block
6506 : : * should be marked as not clean. */
6507 [ - + - + ]: 12 : SPDK_CU_ASSERT_FATAL(bs->clean == 0);
6508 [ - + ]: 12 : SPDK_CU_ASSERT_FATAL(super->clean == 0);
6509 : 12 : clean = true;
6510 : : }
6511 : :
6512 : : /* Depending on the point of failure, super block was either updated or not. */
6513 : 48 : super_copy.clean = super->clean;
6514 : 48 : super_copy.crc = blob_md_page_calc_crc(&super_copy);
6515 : : /* Compare that the values in super block remained unchanged. */
6516 [ - + - + ]: 48 : SPDK_CU_ASSERT_FATAL(!memcmp(&super_copy, super, sizeof(struct spdk_bs_super_block)));
6517 : :
6518 : : /* Delete blob and unload bs */
6519 : 48 : suite_blob_cleanup();
6520 : :
6521 : 48 : thresholds.general_threshold++;
6522 : : }
6523 : 12 : }
6524 : :
6525 : : static void
6526 : 12 : blob_delete_snapshot_power_failure(void)
6527 : : {
6528 : : struct spdk_bs_dev *dev;
6529 : 12 : struct spdk_blob_store *bs;
6530 : 12 : struct spdk_blob_opts opts;
6531 : : struct spdk_blob *blob, *snapshot;
6532 : 12 : struct spdk_power_failure_thresholds thresholds = {};
6533 : : spdk_blob_id blobid, snapshotid;
6534 : 12 : const void *value;
6535 : 12 : size_t value_len;
6536 : 12 : size_t count;
6537 : 12 : spdk_blob_id ids[3] = {};
6538 : : int rc;
6539 : 12 : bool deleted = false;
6540 : 12 : int delete_snapshot_bserrno = -1;
6541 : :
6542 : 12 : thresholds.general_threshold = 1;
6543 [ + + ]: 120 : while (!deleted) {
6544 : 108 : dev = init_dev();
6545 : :
6546 : 108 : spdk_bs_init(dev, NULL, bs_op_with_handle_complete, NULL);
6547 : 108 : poll_threads();
6548 : 108 : CU_ASSERT(g_bserrno == 0);
6549 [ - + ]: 108 : SPDK_CU_ASSERT_FATAL(g_bs != NULL);
6550 : 108 : bs = g_bs;
6551 : :
6552 : : /* Create blob */
6553 : 108 : ut_spdk_blob_opts_init(&opts);
6554 : 108 : opts.num_clusters = 10;
6555 : :
6556 : 108 : spdk_bs_create_blob_ext(bs, &opts, blob_op_with_id_complete, NULL);
6557 : 108 : poll_threads();
6558 : 108 : CU_ASSERT(g_bserrno == 0);
6559 : 108 : CU_ASSERT(g_blobid != SPDK_BLOBID_INVALID);
6560 : 108 : blobid = g_blobid;
6561 : :
6562 : : /* Create snapshot */
6563 : 108 : spdk_bs_create_snapshot(bs, blobid, NULL, blob_op_with_id_complete, NULL);
6564 : 108 : poll_threads();
6565 : 108 : CU_ASSERT(g_bserrno == 0);
6566 : 108 : CU_ASSERT(g_blobid != SPDK_BLOBID_INVALID);
6567 : 108 : snapshotid = g_blobid;
6568 [ - + ]: 108 : SPDK_CU_ASSERT_FATAL(spdk_bit_pool_is_allocated(bs->used_clusters, 1));
6569 [ - + ]: 108 : SPDK_CU_ASSERT_FATAL(!spdk_bit_pool_is_allocated(bs->used_clusters, 11));
6570 : :
6571 : 108 : dev_set_power_failure_thresholds(thresholds);
6572 : :
6573 : 108 : spdk_bs_delete_blob(bs, snapshotid, blob_op_complete, NULL);
6574 : 108 : poll_threads();
6575 : 108 : delete_snapshot_bserrno = g_bserrno;
6576 : :
6577 : : /* Do not shut down cleanly. Assumption is that after snapshot deletion
6578 : : * reports success, changes to both blobs should already persisted. */
6579 : 108 : dev_reset_power_failure_event();
6580 : 108 : ut_bs_dirty_load(&bs, NULL);
6581 : :
6582 [ - + ]: 108 : SPDK_CU_ASSERT_FATAL(spdk_bit_pool_is_allocated(bs->used_clusters, 1));
6583 [ - + ]: 108 : SPDK_CU_ASSERT_FATAL(!spdk_bit_pool_is_allocated(bs->used_clusters, 11));
6584 : :
6585 : 108 : spdk_bs_open_blob(bs, blobid, blob_op_with_handle_complete, NULL);
6586 : 108 : poll_threads();
6587 : 108 : CU_ASSERT(g_bserrno == 0);
6588 [ - + ]: 108 : SPDK_CU_ASSERT_FATAL(g_blob != NULL);
6589 : 108 : blob = g_blob;
6590 [ - + ]: 108 : SPDK_CU_ASSERT_FATAL(spdk_blob_is_thin_provisioned(blob) == true);
6591 : :
6592 : 108 : spdk_bs_open_blob(bs, snapshotid, blob_op_with_handle_complete, NULL);
6593 : 108 : poll_threads();
6594 : :
6595 [ + + ]: 108 : if (g_bserrno == 0) {
6596 [ - + ]: 72 : SPDK_CU_ASSERT_FATAL(g_blob != NULL);
6597 : 72 : snapshot = g_blob;
6598 : 72 : CU_ASSERT(spdk_blob_get_parent_snapshot(bs, blobid) == snapshotid);
6599 : 72 : count = SPDK_COUNTOF(ids);
6600 : 72 : rc = spdk_blob_get_clones(bs, snapshotid, ids, &count);
6601 : 72 : CU_ASSERT(rc == 0);
6602 : 72 : CU_ASSERT(count == 1);
6603 : 72 : CU_ASSERT(ids[0] == blobid);
6604 : 72 : rc = spdk_blob_get_xattr_value(snapshot, SNAPSHOT_PENDING_REMOVAL, &value, &value_len);
6605 : 72 : CU_ASSERT(rc != 0);
6606 [ - + ]: 72 : SPDK_CU_ASSERT_FATAL(spdk_blob_is_thin_provisioned(snapshot) == false);
6607 : 72 : CU_ASSERT(spdk_blob_get_num_allocated_clusters(blob) == 0);
6608 : 72 : CU_ASSERT(spdk_blob_get_num_allocated_clusters(snapshot) == 10);
6609 : :
6610 : 72 : spdk_blob_close(snapshot, blob_op_complete, NULL);
6611 : 72 : poll_threads();
6612 : 72 : CU_ASSERT(g_bserrno == 0);
6613 : : } else {
6614 : 36 : CU_ASSERT(spdk_blob_get_parent_snapshot(bs, blobid) == SPDK_BLOBID_INVALID);
6615 : 36 : CU_ASSERT(spdk_blob_get_num_allocated_clusters(blob) == 10);
6616 : : /* Snapshot might have been left in unrecoverable state, so it does not open.
6617 : : * Yet delete might perform further changes to the clone after that.
6618 : : * This UT should test until snapshot is deleted and delete call succeeds. */
6619 [ + + ]: 36 : if (delete_snapshot_bserrno == 0) {
6620 : 12 : deleted = true;
6621 : : }
6622 : : }
6623 : :
6624 : 108 : spdk_blob_close(blob, blob_op_complete, NULL);
6625 : 108 : poll_threads();
6626 : 108 : CU_ASSERT(g_bserrno == 0);
6627 : :
6628 : 108 : spdk_bs_unload(bs, bs_op_complete, NULL);
6629 : 108 : poll_threads();
6630 : 108 : CU_ASSERT(g_bserrno == 0);
6631 : :
6632 : 108 : thresholds.general_threshold++;
6633 : : }
6634 : 12 : }
6635 : :
6636 : : static void
6637 : 12 : blob_create_snapshot_power_failure(void)
6638 : : {
6639 : 12 : struct spdk_blob_store *bs = g_bs;
6640 : : struct spdk_bs_dev *dev;
6641 : 12 : struct spdk_blob_opts opts;
6642 : : struct spdk_blob *blob, *snapshot;
6643 : 12 : struct spdk_power_failure_thresholds thresholds = {};
6644 : : spdk_blob_id blobid, snapshotid;
6645 : 12 : const void *value;
6646 : 12 : size_t value_len;
6647 : 12 : size_t count;
6648 : 12 : spdk_blob_id ids[3] = {};
6649 : : int rc;
6650 : 12 : bool created = false;
6651 : 12 : int create_snapshot_bserrno = -1;
6652 : :
6653 : 12 : thresholds.general_threshold = 1;
6654 [ + + ]: 102 : while (!created) {
6655 : 90 : dev = init_dev();
6656 : :
6657 : 90 : spdk_bs_init(dev, NULL, bs_op_with_handle_complete, NULL);
6658 : 90 : poll_threads();
6659 : 90 : CU_ASSERT(g_bserrno == 0);
6660 [ - + ]: 90 : SPDK_CU_ASSERT_FATAL(g_bs != NULL);
6661 : 90 : bs = g_bs;
6662 : :
6663 : : /* Create blob */
6664 : 90 : ut_spdk_blob_opts_init(&opts);
6665 : 90 : opts.num_clusters = 10;
6666 : :
6667 : 90 : spdk_bs_create_blob_ext(bs, &opts, blob_op_with_id_complete, NULL);
6668 : 90 : poll_threads();
6669 : 90 : CU_ASSERT(g_bserrno == 0);
6670 : 90 : CU_ASSERT(g_blobid != SPDK_BLOBID_INVALID);
6671 : 90 : blobid = g_blobid;
6672 [ - + ]: 90 : SPDK_CU_ASSERT_FATAL(spdk_bit_pool_is_allocated(bs->used_clusters, 1));
6673 [ - + ]: 90 : SPDK_CU_ASSERT_FATAL(!spdk_bit_pool_is_allocated(bs->used_clusters, 11));
6674 : :
6675 : 90 : dev_set_power_failure_thresholds(thresholds);
6676 : :
6677 : : /* Create snapshot */
6678 : 90 : spdk_bs_create_snapshot(bs, blobid, NULL, blob_op_with_id_complete, NULL);
6679 : 90 : poll_threads();
6680 : 90 : create_snapshot_bserrno = g_bserrno;
6681 : 90 : snapshotid = g_blobid;
6682 [ - + ]: 90 : SPDK_CU_ASSERT_FATAL(spdk_bit_pool_is_allocated(bs->used_clusters, 1));
6683 [ - + ]: 90 : SPDK_CU_ASSERT_FATAL(!spdk_bit_pool_is_allocated(bs->used_clusters, 11));
6684 : :
6685 : : /* Do not shut down cleanly. Assumption is that after create snapshot
6686 : : * reports success, both blobs should be power-fail safe. */
6687 : 90 : dev_reset_power_failure_event();
6688 : 90 : ut_bs_dirty_load(&bs, NULL);
6689 : :
6690 [ - + ]: 90 : SPDK_CU_ASSERT_FATAL(spdk_bit_pool_is_allocated(bs->used_clusters, 1));
6691 [ - + ]: 90 : SPDK_CU_ASSERT_FATAL(!spdk_bit_pool_is_allocated(bs->used_clusters, 11));
6692 : :
6693 : 90 : spdk_bs_open_blob(bs, blobid, blob_op_with_handle_complete, NULL);
6694 : 90 : poll_threads();
6695 : 90 : CU_ASSERT(g_bserrno == 0);
6696 [ - + ]: 90 : SPDK_CU_ASSERT_FATAL(g_blob != NULL);
6697 : 90 : blob = g_blob;
6698 : :
6699 [ + + ]: 90 : if (snapshotid != SPDK_BLOBID_INVALID) {
6700 : 60 : spdk_bs_open_blob(bs, snapshotid, blob_op_with_handle_complete, NULL);
6701 : 60 : poll_threads();
6702 : : }
6703 : :
6704 [ + + + + ]: 90 : if ((snapshotid != SPDK_BLOBID_INVALID) && (g_bserrno == 0)) {
6705 [ - + ]: 24 : SPDK_CU_ASSERT_FATAL(g_blob != NULL);
6706 : 24 : snapshot = g_blob;
6707 [ - + ]: 24 : SPDK_CU_ASSERT_FATAL(spdk_blob_is_thin_provisioned(blob) == true);
6708 [ - + ]: 24 : SPDK_CU_ASSERT_FATAL(spdk_blob_is_thin_provisioned(snapshot) == false);
6709 : 24 : CU_ASSERT(spdk_blob_get_num_allocated_clusters(blob) == 0);
6710 : 24 : CU_ASSERT(spdk_blob_get_num_allocated_clusters(snapshot) == 10);
6711 : 24 : CU_ASSERT(spdk_blob_get_parent_snapshot(bs, blobid) == snapshotid);
6712 : 24 : count = SPDK_COUNTOF(ids);
6713 : 24 : rc = spdk_blob_get_clones(bs, snapshotid, ids, &count);
6714 : 24 : CU_ASSERT(rc == 0);
6715 : 24 : CU_ASSERT(count == 1);
6716 : 24 : CU_ASSERT(ids[0] == blobid);
6717 : 24 : rc = spdk_blob_get_xattr_value(snapshot, SNAPSHOT_IN_PROGRESS, &value, &value_len);
6718 : 24 : CU_ASSERT(rc != 0);
6719 : :
6720 : 24 : spdk_blob_close(snapshot, blob_op_complete, NULL);
6721 : 24 : poll_threads();
6722 : 24 : CU_ASSERT(g_bserrno == 0);
6723 [ + + ]: 24 : if (create_snapshot_bserrno == 0) {
6724 : 12 : created = true;
6725 : : }
6726 : : } else {
6727 : 66 : CU_ASSERT(spdk_blob_get_parent_snapshot(bs, blobid) == SPDK_BLOBID_INVALID);
6728 [ - + ]: 66 : SPDK_CU_ASSERT_FATAL(spdk_blob_is_thin_provisioned(blob) == false);
6729 : 66 : CU_ASSERT(spdk_blob_get_num_allocated_clusters(blob) == 10);
6730 : : }
6731 : :
6732 : 90 : spdk_blob_close(blob, blob_op_complete, NULL);
6733 : 90 : poll_threads();
6734 : 90 : CU_ASSERT(g_bserrno == 0);
6735 : :
6736 : 90 : spdk_bs_unload(bs, bs_op_complete, NULL);
6737 : 90 : poll_threads();
6738 : 90 : CU_ASSERT(g_bserrno == 0);
6739 : :
6740 : 90 : thresholds.general_threshold++;
6741 : : }
6742 : 12 : }
6743 : :
6744 : : static void
6745 : 24 : test_io_write(struct spdk_bs_dev *dev, struct spdk_blob *blob, struct spdk_io_channel *channel)
6746 : : {
6747 : 24 : uint8_t payload_ff[64 * 512];
6748 : 24 : uint8_t payload_aa[64 * 512];
6749 : 24 : uint8_t payload_00[64 * 512];
6750 : : uint8_t *cluster0, *cluster1;
6751 : :
6752 : 24 : memset(payload_ff, 0xFF, sizeof(payload_ff));
6753 : 24 : memset(payload_aa, 0xAA, sizeof(payload_aa));
6754 : 24 : memset(payload_00, 0x00, sizeof(payload_00));
6755 : :
6756 : : /* Try to perform I/O with io unit = 512 */
6757 : 24 : spdk_blob_io_write(blob, channel, payload_ff, 0, 1, blob_op_complete, NULL);
6758 : 24 : poll_threads();
6759 : 24 : CU_ASSERT(g_bserrno == 0);
6760 : :
6761 : : /* If thin provisioned is set cluster should be allocated now */
6762 [ - + ]: 24 : SPDK_CU_ASSERT_FATAL(blob->active.clusters[0] != 0);
6763 : 24 : cluster0 = &g_dev_buffer[blob->active.clusters[0] * dev->blocklen];
6764 : :
6765 : : /* Each character 0-F symbolizes single io_unit containing 512 bytes block filled with that character.
6766 : : * Each page is separated by |. Whole block [...] symbolizes one cluster (containing 4 pages). */
6767 : : /* cluster0: [ F000 0000 | 0000 0000 | 0000 0000 | 0000 0000 ] */
6768 [ - + ]: 24 : CU_ASSERT(memcmp(cluster0 + 0 * 512, payload_ff, 512) == 0);
6769 [ - + ]: 24 : CU_ASSERT(memcmp(cluster0 + 1 * 512, payload_00, 31 * 512) == 0);
6770 : :
6771 : : /* Verify write with offset on first page */
6772 : 24 : spdk_blob_io_write(blob, channel, payload_ff, 2, 1, blob_op_complete, NULL);
6773 : 24 : poll_threads();
6774 : 24 : CU_ASSERT(g_bserrno == 0);
6775 : :
6776 : : /* cluster0: [ F0F0 0000 | 0000 0000 | 0000 0000 | 0000 0000 ] */
6777 [ - + ]: 24 : CU_ASSERT(memcmp(cluster0 + 0 * 512, payload_ff, 512) == 0);
6778 [ - + ]: 24 : CU_ASSERT(memcmp(cluster0 + 1 * 512, payload_00, 512) == 0);
6779 [ - + ]: 24 : CU_ASSERT(memcmp(cluster0 + 2 * 512, payload_ff, 512) == 0);
6780 [ - + ]: 24 : CU_ASSERT(memcmp(cluster0 + 3 * 512, payload_00, 512) == 0);
6781 [ - + ]: 24 : CU_ASSERT(memcmp(cluster0 + 4 * 512, payload_00, 28 * 512) == 0);
6782 : :
6783 : : /* Verify write with offset on first page */
6784 : 24 : spdk_blob_io_write(blob, channel, payload_ff, 4, 4, blob_op_complete, NULL);
6785 : 24 : poll_threads();
6786 : :
6787 : : /* cluster0: [ F0F0 FFFF | 0000 0000 | 0000 0000 | 0000 0000 ] */
6788 [ - + ]: 24 : CU_ASSERT(memcmp(cluster0 + 0 * 512, payload_ff, 512) == 0);
6789 [ - + ]: 24 : CU_ASSERT(memcmp(cluster0 + 1 * 512, payload_00, 512) == 0);
6790 [ - + ]: 24 : CU_ASSERT(memcmp(cluster0 + 2 * 512, payload_ff, 512) == 0);
6791 [ - + ]: 24 : CU_ASSERT(memcmp(cluster0 + 3 * 512, payload_00, 512) == 0);
6792 [ - + ]: 24 : CU_ASSERT(memcmp(cluster0 + 4 * 512, payload_ff, 4 * 512) == 0);
6793 [ - + ]: 24 : CU_ASSERT(memcmp(cluster0 + 8 * 512, payload_00, 24 * 512) == 0);
6794 : :
6795 : : /* Verify write with offset on second page */
6796 : 24 : spdk_blob_io_write(blob, channel, payload_ff, 8, 4, blob_op_complete, NULL);
6797 : 24 : poll_threads();
6798 : :
6799 : : /* cluster0: [ F0F0 FFFF | FFFF 0000 | 0000 0000 | 0000 0000 ] */
6800 [ - + ]: 24 : CU_ASSERT(memcmp(cluster0 + 0 * 512, payload_ff, 512) == 0);
6801 [ - + ]: 24 : CU_ASSERT(memcmp(cluster0 + 1 * 512, payload_00, 512) == 0);
6802 [ - + ]: 24 : CU_ASSERT(memcmp(cluster0 + 2 * 512, payload_ff, 512) == 0);
6803 [ - + ]: 24 : CU_ASSERT(memcmp(cluster0 + 3 * 512, payload_00, 512) == 0);
6804 [ - + ]: 24 : CU_ASSERT(memcmp(cluster0 + 4 * 512, payload_ff, 8 * 512) == 0);
6805 [ - + ]: 24 : CU_ASSERT(memcmp(cluster0 + 12 * 512, payload_00, 20 * 512) == 0);
6806 : :
6807 : : /* Verify write across multiple pages */
6808 : 24 : spdk_blob_io_write(blob, channel, payload_aa, 4, 8, blob_op_complete, NULL);
6809 : 24 : poll_threads();
6810 : :
6811 : : /* cluster0: [ F0F0 AAAA | AAAA 0000 | 0000 0000 | 0000 0000 ] */
6812 [ - + ]: 24 : CU_ASSERT(memcmp(cluster0 + 0 * 512, payload_ff, 512) == 0);
6813 [ - + ]: 24 : CU_ASSERT(memcmp(cluster0 + 1 * 512, payload_00, 512) == 0);
6814 [ - + ]: 24 : CU_ASSERT(memcmp(cluster0 + 2 * 512, payload_ff, 512) == 0);
6815 [ - + ]: 24 : CU_ASSERT(memcmp(cluster0 + 3 * 512, payload_00, 512) == 0);
6816 [ - + ]: 24 : CU_ASSERT(memcmp(cluster0 + 4 * 512, payload_aa, 8 * 512) == 0);
6817 [ - + ]: 24 : CU_ASSERT(memcmp(cluster0 + 12 * 512, payload_00, 20 * 512) == 0);
6818 : :
6819 : : /* Verify write across multiple clusters */
6820 : 24 : spdk_blob_io_write(blob, channel, payload_ff, 28, 8, blob_op_complete, NULL);
6821 : 24 : poll_threads();
6822 : :
6823 [ - + ]: 24 : SPDK_CU_ASSERT_FATAL(blob->active.clusters[1] != 0);
6824 : 24 : cluster1 = &g_dev_buffer[blob->active.clusters[1] * dev->blocklen];
6825 : :
6826 : : /* cluster0: [ F0F0 AAAA | AAAA 0000 | 0000 0000 | 0000 FFFF ]
6827 : : * cluster1: [ FFFF 0000 | 0000 0000 | 0000 0000 | 0000 0000 ] */
6828 [ - + ]: 24 : CU_ASSERT(memcmp(cluster0 + 0 * 512, payload_ff, 512) == 0);
6829 [ - + ]: 24 : CU_ASSERT(memcmp(cluster0 + 1 * 512, payload_00, 512) == 0);
6830 [ - + ]: 24 : CU_ASSERT(memcmp(cluster0 + 2 * 512, payload_ff, 512) == 0);
6831 [ - + ]: 24 : CU_ASSERT(memcmp(cluster0 + 3 * 512, payload_00, 512) == 0);
6832 [ - + ]: 24 : CU_ASSERT(memcmp(cluster0 + 4 * 512, payload_aa, 8 * 512) == 0);
6833 [ - + ]: 24 : CU_ASSERT(memcmp(cluster0 + 28 * 512, payload_ff, 4 * 512) == 0);
6834 : :
6835 [ - + ]: 24 : CU_ASSERT(memcmp(cluster1 + 0 * 512, payload_ff, 4 * 512) == 0);
6836 [ - + ]: 24 : CU_ASSERT(memcmp(cluster1 + 4 * 512, payload_00, 28 * 512) == 0);
6837 : :
6838 : : /* Verify write to second cluster */
6839 : 24 : spdk_blob_io_write(blob, channel, payload_ff, 32 + 12, 2, blob_op_complete, NULL);
6840 : 24 : poll_threads();
6841 : :
6842 [ - + ]: 24 : SPDK_CU_ASSERT_FATAL(blob->active.clusters[1] != 0);
6843 : 24 : cluster1 = &g_dev_buffer[blob->active.clusters[1] * dev->blocklen];
6844 : :
6845 : : /* cluster0: [ F0F0 AAAA | AAAA 0000 | 0000 0000 | 0000 FFFF ]
6846 : : * cluster1: [ FFFF 0000 | 0000 FF00 | 0000 0000 | 0000 0000 ] */
6847 [ - + ]: 24 : CU_ASSERT(memcmp(cluster0 + 0 * 512, payload_ff, 512) == 0);
6848 [ - + ]: 24 : CU_ASSERT(memcmp(cluster0 + 1 * 512, payload_00, 512) == 0);
6849 [ - + ]: 24 : CU_ASSERT(memcmp(cluster0 + 2 * 512, payload_ff, 512) == 0);
6850 [ - + ]: 24 : CU_ASSERT(memcmp(cluster0 + 3 * 512, payload_00, 512) == 0);
6851 [ - + ]: 24 : CU_ASSERT(memcmp(cluster0 + 4 * 512, payload_aa, 8 * 512) == 0);
6852 [ - + ]: 24 : CU_ASSERT(memcmp(cluster0 + 28 * 512, payload_ff, 4 * 512) == 0);
6853 : :
6854 [ - + ]: 24 : CU_ASSERT(memcmp(cluster1 + 0 * 512, payload_ff, 4 * 512) == 0);
6855 [ - + ]: 24 : CU_ASSERT(memcmp(cluster1 + 4 * 512, payload_00, 8 * 512) == 0);
6856 [ - + ]: 24 : CU_ASSERT(memcmp(cluster1 + 12 * 512, payload_ff, 2 * 512) == 0);
6857 [ - + ]: 24 : CU_ASSERT(memcmp(cluster1 + 14 * 512, payload_00, 18 * 512) == 0);
6858 : 24 : }
6859 : :
6860 : : static void
6861 : 72 : test_io_read(struct spdk_bs_dev *dev, struct spdk_blob *blob, struct spdk_io_channel *channel)
6862 : : {
6863 : 72 : uint8_t payload_read[64 * 512];
6864 : 72 : uint8_t payload_ff[64 * 512];
6865 : 72 : uint8_t payload_aa[64 * 512];
6866 : 72 : uint8_t payload_00[64 * 512];
6867 : :
6868 : 72 : memset(payload_ff, 0xFF, sizeof(payload_ff));
6869 : 72 : memset(payload_aa, 0xAA, sizeof(payload_aa));
6870 : 72 : memset(payload_00, 0x00, sizeof(payload_00));
6871 : :
6872 : : /* Read only first io unit */
6873 : : /* cluster0: [ (F)0F0 AAAA | AAAA 0000 | 0000 0000 | 0000 FFFF ]
6874 : : * cluster1: [ FFFF 0000 | 0000 FF00 | 0000 0000 | 0000 0000 ]
6875 : : * payload_read: F000 0000 | 0000 0000 ... */
6876 : 72 : memset(payload_read, 0x00, sizeof(payload_read));
6877 : 72 : spdk_blob_io_read(blob, channel, payload_read, 0, 1, blob_op_complete, NULL);
6878 : 72 : poll_threads();
6879 : 72 : CU_ASSERT(g_bserrno == 0);
6880 : 72 : CU_ASSERT(memcmp(payload_read + 0 * 512, payload_ff, 512) == 0);
6881 [ - + ]: 72 : CU_ASSERT(memcmp(payload_read + 1 * 512, payload_00, 31 * 512) == 0);
6882 : :
6883 : : /* Read four io_units starting from offset = 2
6884 : : * cluster0: [ F0(F0 AA)AA | AAAA 0000 | 0000 0000 | 0000 FFFF ]
6885 : : * cluster1: [ FFFF 0000 | 0000 FF00 | 0000 0000 | 0000 0000 ]
6886 : : * payload_read: F0AA 0000 | 0000 0000 ... */
6887 : :
6888 : 72 : memset(payload_read, 0x00, sizeof(payload_read));
6889 : 72 : spdk_blob_io_read(blob, channel, payload_read, 2, 4, blob_op_complete, NULL);
6890 : 72 : poll_threads();
6891 : 72 : CU_ASSERT(g_bserrno == 0);
6892 : :
6893 : 72 : CU_ASSERT(memcmp(payload_read + 0 * 512, payload_ff, 512) == 0);
6894 [ - + ]: 72 : CU_ASSERT(memcmp(payload_read + 1 * 512, payload_00, 512) == 0);
6895 [ - + ]: 72 : CU_ASSERT(memcmp(payload_read + 2 * 512, payload_aa, 512) == 0);
6896 [ - + ]: 72 : CU_ASSERT(memcmp(payload_read + 3 * 512, payload_aa, 512) == 0);
6897 [ - + ]: 72 : CU_ASSERT(memcmp(payload_read + 4 * 512, payload_00, 28 * 512) == 0);
6898 : :
6899 : : /* Read eight io_units across multiple pages
6900 : : * cluster0: [ F0F0 (AAAA | AAAA) 0000 | 0000 0000 | 0000 FFFF ]
6901 : : * cluster1: [ FFFF 0000 | 0000 FF00 | 0000 0000 | 0000 0000 ]
6902 : : * payload_read: AAAA AAAA | 0000 0000 ... */
6903 : 72 : memset(payload_read, 0x00, sizeof(payload_read));
6904 : 72 : spdk_blob_io_read(blob, channel, payload_read, 4, 8, blob_op_complete, NULL);
6905 : 72 : poll_threads();
6906 : 72 : CU_ASSERT(g_bserrno == 0);
6907 : :
6908 : 72 : CU_ASSERT(memcmp(payload_read + 0 * 512, payload_aa, 8 * 512) == 0);
6909 [ - + ]: 72 : CU_ASSERT(memcmp(payload_read + 8 * 512, payload_00, 24 * 512) == 0);
6910 : :
6911 : : /* Read eight io_units across multiple clusters
6912 : : * cluster0: [ F0F0 AAAA | AAAA 0000 | 0000 0000 | 0000 (FFFF ]
6913 : : * cluster1: [ FFFF) 0000 | 0000 FF00 | 0000 0000 | 0000 0000 ]
6914 : : * payload_read: FFFF FFFF | 0000 0000 ... */
6915 : 72 : memset(payload_read, 0x00, sizeof(payload_read));
6916 : 72 : spdk_blob_io_read(blob, channel, payload_read, 28, 8, blob_op_complete, NULL);
6917 : 72 : poll_threads();
6918 : 72 : CU_ASSERT(g_bserrno == 0);
6919 : :
6920 : 72 : CU_ASSERT(memcmp(payload_read + 0 * 512, payload_ff, 8 * 512) == 0);
6921 [ - + ]: 72 : CU_ASSERT(memcmp(payload_read + 8 * 512, payload_00, 24 * 512) == 0);
6922 : :
6923 : : /* Read four io_units from second cluster
6924 : : * cluster0: [ F0F0 AAAA | AAAA 0000 | 0000 0000 | 0000 FFFF ]
6925 : : * cluster1: [ FFFF 0000 | 00(00 FF)00 | 0000 0000 | 0000 0000 ]
6926 : : * payload_read: 00FF 0000 | 0000 0000 ... */
6927 : 72 : memset(payload_read, 0x00, sizeof(payload_read));
6928 : 72 : spdk_blob_io_read(blob, channel, payload_read, 32 + 10, 4, blob_op_complete, NULL);
6929 : 72 : poll_threads();
6930 : 72 : CU_ASSERT(g_bserrno == 0);
6931 : :
6932 : 72 : CU_ASSERT(memcmp(payload_read + 0 * 512, payload_00, 2 * 512) == 0);
6933 [ - + ]: 72 : CU_ASSERT(memcmp(payload_read + 2 * 512, payload_ff, 2 * 512) == 0);
6934 [ - + ]: 72 : CU_ASSERT(memcmp(payload_read + 4 * 512, payload_00, 28 * 512) == 0);
6935 : :
6936 : : /* Read second cluster
6937 : : * cluster0: [ F0F0 AAAA | AAAA 0000 | 0000 0000 | 0000 FFFF ]
6938 : : * cluster1: [ (FFFF 0000 | 0000 FF00 | 0000 0000 | 0000 0000) ]
6939 : : * payload_read: FFFF 0000 | 0000 FF00 ... */
6940 : 72 : memset(payload_read, 0x00, sizeof(payload_read));
6941 : 72 : spdk_blob_io_read(blob, channel, payload_read, 32, 32, blob_op_complete, NULL);
6942 : 72 : poll_threads();
6943 : 72 : CU_ASSERT(g_bserrno == 0);
6944 : 72 : CU_ASSERT(memcmp(payload_read + 0 * 512, payload_ff, 4 * 512) == 0);
6945 [ - + ]: 72 : CU_ASSERT(memcmp(payload_read + 4 * 512, payload_00, 8 * 512) == 0);
6946 [ - + ]: 72 : CU_ASSERT(memcmp(payload_read + 12 * 512, payload_ff, 2 * 512) == 0);
6947 [ - + ]: 72 : CU_ASSERT(memcmp(payload_read + 14 * 512, payload_00, 18 * 512) == 0);
6948 : :
6949 : : /* Read whole two clusters
6950 : : * cluster0: [ (F0F0 AAAA | AAAA) 0000 | 0000 0000 | 0000 FFFF ]
6951 : : * cluster1: [ FFFF 0000 | 0000 FF00 | 0000 0000 | 0000 0000) ] */
6952 : 72 : memset(payload_read, 0x00, sizeof(payload_read));
6953 : 72 : spdk_blob_io_read(blob, channel, payload_read, 0, 64, blob_op_complete, NULL);
6954 : 72 : poll_threads();
6955 : 72 : CU_ASSERT(g_bserrno == 0);
6956 : :
6957 : 72 : CU_ASSERT(memcmp(payload_read + 0 * 512, payload_ff, 512) == 0);
6958 [ - + ]: 72 : CU_ASSERT(memcmp(payload_read + 1 * 512, payload_00, 512) == 0);
6959 [ - + ]: 72 : CU_ASSERT(memcmp(payload_read + 2 * 512, payload_ff, 512) == 0);
6960 [ - + ]: 72 : CU_ASSERT(memcmp(payload_read + 3 * 512, payload_00, 512) == 0);
6961 [ - + ]: 72 : CU_ASSERT(memcmp(payload_read + 4 * 512, payload_aa, 8 * 512) == 0);
6962 [ - + ]: 72 : CU_ASSERT(memcmp(payload_read + 28 * 512, payload_ff, 4 * 512) == 0);
6963 : :
6964 [ - + ]: 72 : CU_ASSERT(memcmp(payload_read + (32 + 0) * 512, payload_ff, 4 * 512) == 0);
6965 [ - + ]: 72 : CU_ASSERT(memcmp(payload_read + (32 + 4) * 512, payload_00, 8 * 512) == 0);
6966 [ - + ]: 72 : CU_ASSERT(memcmp(payload_read + (32 + 12) * 512, payload_ff, 2 * 512) == 0);
6967 [ - + ]: 72 : CU_ASSERT(memcmp(payload_read + (32 + 14) * 512, payload_00, 18 * 512) == 0);
6968 : 72 : }
6969 : :
6970 : :
6971 : : static void
6972 : 36 : test_io_unmap(struct spdk_bs_dev *dev, struct spdk_blob *blob, struct spdk_io_channel *channel)
6973 : : {
6974 : 36 : uint8_t payload_ff[64 * 512];
6975 : 36 : uint8_t payload_aa[64 * 512];
6976 : 36 : uint8_t payload_00[64 * 512];
6977 : : uint8_t *cluster0, *cluster1;
6978 : :
6979 : 36 : memset(payload_ff, 0xFF, sizeof(payload_ff));
6980 : 36 : memset(payload_aa, 0xAA, sizeof(payload_aa));
6981 : 36 : memset(payload_00, 0x00, sizeof(payload_00));
6982 : :
6983 : 36 : cluster0 = &g_dev_buffer[blob->active.clusters[0] * dev->blocklen];
6984 : 36 : cluster1 = &g_dev_buffer[blob->active.clusters[1] * dev->blocklen];
6985 : :
6986 : : /* Unmap */
6987 : 36 : spdk_blob_io_unmap(blob, channel, 0, 64, blob_op_complete, NULL);
6988 : 36 : poll_threads();
6989 : :
6990 : 36 : CU_ASSERT(g_bserrno == 0);
6991 : :
6992 [ - + ]: 36 : CU_ASSERT(memcmp(cluster0 + 0 * 512, payload_00, 32 * 512) == 0);
6993 [ - + ]: 36 : CU_ASSERT(memcmp(cluster1 + 0 * 512, payload_00, 32 * 512) == 0);
6994 : 36 : }
6995 : :
6996 : : static void
6997 : 48 : test_io_zeroes(struct spdk_bs_dev *dev, struct spdk_blob *blob, struct spdk_io_channel *channel)
6998 : : {
6999 : 48 : uint8_t payload_ff[64 * 512];
7000 : 48 : uint8_t payload_aa[64 * 512];
7001 : 48 : uint8_t payload_00[64 * 512];
7002 : : uint8_t *cluster0, *cluster1;
7003 : :
7004 : 48 : memset(payload_ff, 0xFF, sizeof(payload_ff));
7005 : 48 : memset(payload_aa, 0xAA, sizeof(payload_aa));
7006 : 48 : memset(payload_00, 0x00, sizeof(payload_00));
7007 : :
7008 : 48 : cluster0 = &g_dev_buffer[blob->active.clusters[0] * dev->blocklen];
7009 : 48 : cluster1 = &g_dev_buffer[blob->active.clusters[1] * dev->blocklen];
7010 : :
7011 : : /* Write zeroes */
7012 : 48 : spdk_blob_io_write_zeroes(blob, channel, 0, 64, blob_op_complete, NULL);
7013 : 48 : poll_threads();
7014 : :
7015 : 48 : CU_ASSERT(g_bserrno == 0);
7016 : :
7017 [ - + ]: 48 : CU_ASSERT(memcmp(cluster0 + 0 * 512, payload_00, 32 * 512) == 0);
7018 [ - + ]: 48 : CU_ASSERT(memcmp(cluster1 + 0 * 512, payload_00, 32 * 512) == 0);
7019 : 48 : }
7020 : :
7021 : : static inline void
7022 : 360 : test_blob_io_writev(struct spdk_blob *blob, struct spdk_io_channel *channel,
7023 : : struct iovec *iov, int iovcnt, uint64_t offset, uint64_t length,
7024 : : spdk_blob_op_complete cb_fn, void *cb_arg, struct spdk_blob_ext_io_opts *io_opts)
7025 : : {
7026 [ + + ]: 360 : if (io_opts) {
7027 : 180 : g_dev_writev_ext_called = false;
7028 : 180 : memset(&g_blob_ext_io_opts, 0, sizeof(g_blob_ext_io_opts));
7029 : 180 : spdk_blob_io_writev_ext(blob, channel, iov, iovcnt, offset, length, blob_op_complete, NULL,
7030 : : io_opts);
7031 : : } else {
7032 : 180 : spdk_blob_io_writev(blob, channel, iov, iovcnt, offset, length, blob_op_complete, NULL);
7033 : : }
7034 : 360 : poll_threads();
7035 : 360 : CU_ASSERT(g_bserrno == 0);
7036 [ + + ]: 360 : if (io_opts) {
7037 [ - + ]: 180 : CU_ASSERT(g_dev_writev_ext_called);
7038 [ - + ]: 180 : CU_ASSERT(memcmp(io_opts, &g_blob_ext_io_opts, sizeof(g_blob_ext_io_opts)) == 0);
7039 : : }
7040 : 360 : }
7041 : :
7042 : : static void
7043 : 72 : test_iov_write(struct spdk_bs_dev *dev, struct spdk_blob *blob, struct spdk_io_channel *channel,
7044 : : bool ext_api)
7045 : : {
7046 : 72 : uint8_t payload_ff[64 * 512];
7047 : 72 : uint8_t payload_aa[64 * 512];
7048 : 72 : uint8_t payload_00[64 * 512];
7049 : : uint8_t *cluster0, *cluster1;
7050 : 72 : struct iovec iov[4];
7051 : 72 : struct spdk_blob_ext_io_opts ext_opts = {
7052 : : .memory_domain = (struct spdk_memory_domain *)0xfeedbeef,
7053 : : .memory_domain_ctx = (void *)0xf00df00d,
7054 : : .size = sizeof(struct spdk_blob_ext_io_opts),
7055 : : .user_ctx = (void *)123,
7056 : : };
7057 : :
7058 : 72 : memset(payload_ff, 0xFF, sizeof(payload_ff));
7059 : 72 : memset(payload_aa, 0xAA, sizeof(payload_aa));
7060 : 72 : memset(payload_00, 0x00, sizeof(payload_00));
7061 : :
7062 : : /* Try to perform I/O with io unit = 512 */
7063 : 72 : iov[0].iov_base = payload_ff;
7064 : 72 : iov[0].iov_len = 1 * 512;
7065 : :
7066 [ + + ]: 72 : test_blob_io_writev(blob, channel, iov, 1, 0, 1, blob_op_complete, NULL,
7067 : : ext_api ? &ext_opts : NULL);
7068 : :
7069 : : /* If thin provisioned is set cluster should be allocated now */
7070 [ - + ]: 72 : SPDK_CU_ASSERT_FATAL(blob->active.clusters[0] != 0);
7071 : 72 : cluster0 = &g_dev_buffer[blob->active.clusters[0] * dev->blocklen];
7072 : :
7073 : : /* Each character 0-F symbolizes single io_unit containing 512 bytes block filled with that character.
7074 : : * Each page is separated by |. Whole block [...] symbolizes one cluster (containing 4 pages). */
7075 : : /* cluster0: [ F000 0000 | 0000 0000 | 0000 0000 | 0000 0000 ] */
7076 [ - + ]: 72 : CU_ASSERT(memcmp(cluster0 + 0 * 512, payload_ff, 512) == 0);
7077 [ - + ]: 72 : CU_ASSERT(memcmp(cluster0 + 1 * 512, payload_00, 31 * 512) == 0);
7078 : :
7079 : : /* Verify write with offset on first page */
7080 : 72 : iov[0].iov_base = payload_ff;
7081 : 72 : iov[0].iov_len = 1 * 512;
7082 : :
7083 [ + + ]: 72 : test_blob_io_writev(blob, channel, iov, 1, 2, 1, blob_op_complete, NULL,
7084 : : ext_api ? &ext_opts : NULL);
7085 : :
7086 : : /* cluster0: [ F0F0 0000 | 0000 0000 | 0000 0000 | 0000 0000 ] */
7087 [ - + ]: 72 : CU_ASSERT(memcmp(cluster0 + 0 * 512, payload_ff, 512) == 0);
7088 [ - + ]: 72 : CU_ASSERT(memcmp(cluster0 + 1 * 512, payload_00, 512) == 0);
7089 [ - + ]: 72 : CU_ASSERT(memcmp(cluster0 + 2 * 512, payload_ff, 512) == 0);
7090 [ - + ]: 72 : CU_ASSERT(memcmp(cluster0 + 3 * 512, payload_00, 512) == 0);
7091 [ - + ]: 72 : CU_ASSERT(memcmp(cluster0 + 4 * 512, payload_00, 28 * 512) == 0);
7092 : :
7093 : : /* Verify write with offset on first page */
7094 : 72 : iov[0].iov_base = payload_ff;
7095 : 72 : iov[0].iov_len = 4 * 512;
7096 : 72 : spdk_blob_io_writev(blob, channel, iov, 1, 4, 4, blob_op_complete, NULL);
7097 : 72 : poll_threads();
7098 : :
7099 : : /* cluster0: [ F0F0 FFFF | 0000 0000 | 0000 0000 | 0000 0000 ] */
7100 [ - + ]: 72 : CU_ASSERT(memcmp(cluster0 + 0 * 512, payload_ff, 512) == 0);
7101 [ - + ]: 72 : CU_ASSERT(memcmp(cluster0 + 1 * 512, payload_00, 512) == 0);
7102 [ - + ]: 72 : CU_ASSERT(memcmp(cluster0 + 2 * 512, payload_ff, 512) == 0);
7103 [ - + ]: 72 : CU_ASSERT(memcmp(cluster0 + 3 * 512, payload_00, 512) == 0);
7104 [ - + ]: 72 : CU_ASSERT(memcmp(cluster0 + 4 * 512, payload_ff, 4 * 512) == 0);
7105 [ - + ]: 72 : CU_ASSERT(memcmp(cluster0 + 8 * 512, payload_00, 24 * 512) == 0);
7106 : :
7107 : : /* Verify write with offset on second page */
7108 : 72 : iov[0].iov_base = payload_ff;
7109 : 72 : iov[0].iov_len = 4 * 512;
7110 : 72 : spdk_blob_io_writev(blob, channel, iov, 1, 8, 4, blob_op_complete, NULL);
7111 : 72 : poll_threads();
7112 : :
7113 : : /* cluster0: [ F0F0 FFFF | FFFF 0000 | 0000 0000 | 0000 0000 ] */
7114 [ - + ]: 72 : CU_ASSERT(memcmp(cluster0 + 0 * 512, payload_ff, 512) == 0);
7115 [ - + ]: 72 : CU_ASSERT(memcmp(cluster0 + 1 * 512, payload_00, 512) == 0);
7116 [ - + ]: 72 : CU_ASSERT(memcmp(cluster0 + 2 * 512, payload_ff, 512) == 0);
7117 [ - + ]: 72 : CU_ASSERT(memcmp(cluster0 + 3 * 512, payload_00, 512) == 0);
7118 [ - + ]: 72 : CU_ASSERT(memcmp(cluster0 + 4 * 512, payload_ff, 8 * 512) == 0);
7119 [ - + ]: 72 : CU_ASSERT(memcmp(cluster0 + 12 * 512, payload_00, 20 * 512) == 0);
7120 : :
7121 : : /* Verify write across multiple pages */
7122 : 72 : iov[0].iov_base = payload_aa;
7123 : 72 : iov[0].iov_len = 8 * 512;
7124 : :
7125 [ + + ]: 72 : test_blob_io_writev(blob, channel, iov, 1, 4, 8, blob_op_complete, NULL,
7126 : : ext_api ? &ext_opts : NULL);
7127 : :
7128 : : /* cluster0: [ F0F0 AAAA | AAAA 0000 | 0000 0000 | 0000 0000 ] */
7129 [ - + ]: 72 : CU_ASSERT(memcmp(cluster0 + 0 * 512, payload_ff, 512) == 0);
7130 [ - + ]: 72 : CU_ASSERT(memcmp(cluster0 + 1 * 512, payload_00, 512) == 0);
7131 [ - + ]: 72 : CU_ASSERT(memcmp(cluster0 + 2 * 512, payload_ff, 512) == 0);
7132 [ - + ]: 72 : CU_ASSERT(memcmp(cluster0 + 3 * 512, payload_00, 512) == 0);
7133 [ - + ]: 72 : CU_ASSERT(memcmp(cluster0 + 4 * 512, payload_aa, 8 * 512) == 0);
7134 [ - + ]: 72 : CU_ASSERT(memcmp(cluster0 + 12 * 512, payload_00, 20 * 512) == 0);
7135 : :
7136 : : /* Verify write across multiple clusters */
7137 : :
7138 : 72 : iov[0].iov_base = payload_ff;
7139 : 72 : iov[0].iov_len = 8 * 512;
7140 : :
7141 [ + + ]: 72 : test_blob_io_writev(blob, channel, iov, 1, 28, 8, blob_op_complete, NULL,
7142 : : ext_api ? &ext_opts : NULL);
7143 : :
7144 [ - + ]: 72 : SPDK_CU_ASSERT_FATAL(blob->active.clusters[1] != 0);
7145 : 72 : cluster1 = &g_dev_buffer[blob->active.clusters[1] * dev->blocklen];
7146 : :
7147 : : /* cluster0: [ F0F0 AAAA | AAAA 0000 | 0000 0000 | 0000 FFFF ]
7148 : : * cluster1: [ FFFF 0000 | 0000 0000 | 0000 0000 | 0000 0000 ] */
7149 [ - + ]: 72 : CU_ASSERT(memcmp(cluster0 + 0 * 512, payload_ff, 512) == 0);
7150 [ - + ]: 72 : CU_ASSERT(memcmp(cluster0 + 1 * 512, payload_00, 512) == 0);
7151 [ - + ]: 72 : CU_ASSERT(memcmp(cluster0 + 2 * 512, payload_ff, 512) == 0);
7152 [ - + ]: 72 : CU_ASSERT(memcmp(cluster0 + 3 * 512, payload_00, 512) == 0);
7153 [ - + ]: 72 : CU_ASSERT(memcmp(cluster0 + 4 * 512, payload_aa, 8 * 512) == 0);
7154 [ - + ]: 72 : CU_ASSERT(memcmp(cluster0 + 12 * 512, payload_00, 16 * 512) == 0);
7155 [ - + ]: 72 : CU_ASSERT(memcmp(cluster0 + 28 * 512, payload_ff, 4 * 512) == 0);
7156 : :
7157 [ - + ]: 72 : CU_ASSERT(memcmp(cluster1 + 0 * 512, payload_ff, 4 * 512) == 0);
7158 [ - + ]: 72 : CU_ASSERT(memcmp(cluster1 + 4 * 512, payload_00, 28 * 512) == 0);
7159 : :
7160 : : /* Verify write to second cluster */
7161 : :
7162 : 72 : iov[0].iov_base = payload_ff;
7163 : 72 : iov[0].iov_len = 2 * 512;
7164 : :
7165 [ + + ]: 72 : test_blob_io_writev(blob, channel, iov, 1, 32 + 12, 2, blob_op_complete, NULL,
7166 : : ext_api ? &ext_opts : NULL);
7167 : :
7168 [ - + ]: 72 : SPDK_CU_ASSERT_FATAL(blob->active.clusters[1] != 0);
7169 : 72 : cluster1 = &g_dev_buffer[blob->active.clusters[1] * dev->blocklen];
7170 : :
7171 : : /* cluster0: [ F0F0 AAAA | AAAA 0000 | 0000 0000 | 0000 FFFF ]
7172 : : * cluster1: [ FFFF 0000 | 0000 FF00 | 0000 0000 | 0000 0000 ] */
7173 [ - + ]: 72 : CU_ASSERT(memcmp(cluster0 + 0 * 512, payload_ff, 512) == 0);
7174 [ - + ]: 72 : CU_ASSERT(memcmp(cluster0 + 1 * 512, payload_00, 512) == 0);
7175 [ - + ]: 72 : CU_ASSERT(memcmp(cluster0 + 2 * 512, payload_ff, 512) == 0);
7176 [ - + ]: 72 : CU_ASSERT(memcmp(cluster0 + 3 * 512, payload_00, 512) == 0);
7177 [ - + ]: 72 : CU_ASSERT(memcmp(cluster0 + 4 * 512, payload_aa, 8 * 512) == 0);
7178 [ - + ]: 72 : CU_ASSERT(memcmp(cluster0 + 28 * 512, payload_ff, 4 * 512) == 0);
7179 : :
7180 [ - + ]: 72 : CU_ASSERT(memcmp(cluster1 + 0 * 512, payload_ff, 4 * 512) == 0);
7181 [ - + ]: 72 : CU_ASSERT(memcmp(cluster1 + 4 * 512, payload_00, 8 * 512) == 0);
7182 [ - + ]: 72 : CU_ASSERT(memcmp(cluster1 + 12 * 512, payload_ff, 2 * 512) == 0);
7183 [ - + ]: 72 : CU_ASSERT(memcmp(cluster1 + 14 * 512, payload_00, 18 * 512) == 0);
7184 : 72 : }
7185 : :
7186 : : static inline void
7187 : 1008 : test_blob_io_readv(struct spdk_blob *blob, struct spdk_io_channel *channel,
7188 : : struct iovec *iov, int iovcnt, uint64_t offset, uint64_t length,
7189 : : spdk_blob_op_complete cb_fn, void *cb_arg, struct spdk_blob_ext_io_opts *io_opts)
7190 : : {
7191 [ + + ]: 1008 : if (io_opts) {
7192 : 504 : g_dev_readv_ext_called = false;
7193 : 504 : memset(&g_blob_ext_io_opts, 0, sizeof(g_blob_ext_io_opts));
7194 : 504 : spdk_blob_io_readv_ext(blob, channel, iov, iovcnt, offset, length, blob_op_complete, NULL, io_opts);
7195 : : } else {
7196 : 504 : spdk_blob_io_readv(blob, channel, iov, iovcnt, offset, length, blob_op_complete, NULL);
7197 : : }
7198 : 1008 : poll_threads();
7199 : 1008 : CU_ASSERT(g_bserrno == 0);
7200 [ + + ]: 1008 : if (io_opts) {
7201 [ - + ]: 504 : CU_ASSERT(g_dev_readv_ext_called);
7202 [ - + ]: 504 : CU_ASSERT(memcmp(io_opts, &g_blob_ext_io_opts, sizeof(g_blob_ext_io_opts)) == 0);
7203 : : }
7204 : 1008 : }
7205 : :
7206 : : static void
7207 : 144 : test_iov_read(struct spdk_bs_dev *dev, struct spdk_blob *blob, struct spdk_io_channel *channel,
7208 : : bool ext_api)
7209 : : {
7210 : 144 : uint8_t payload_read[64 * 512];
7211 : 144 : uint8_t payload_ff[64 * 512];
7212 : 144 : uint8_t payload_aa[64 * 512];
7213 : 144 : uint8_t payload_00[64 * 512];
7214 : 144 : struct iovec iov[4];
7215 : 144 : struct spdk_blob_ext_io_opts ext_opts = {
7216 : : .memory_domain = (struct spdk_memory_domain *)0xfeedbeef,
7217 : : .memory_domain_ctx = (void *)0xf00df00d,
7218 : : .size = sizeof(struct spdk_blob_ext_io_opts),
7219 : : .user_ctx = (void *)123,
7220 : : };
7221 : :
7222 : 144 : memset(payload_ff, 0xFF, sizeof(payload_ff));
7223 : 144 : memset(payload_aa, 0xAA, sizeof(payload_aa));
7224 : 144 : memset(payload_00, 0x00, sizeof(payload_00));
7225 : :
7226 : : /* Read only first io unit */
7227 : : /* cluster0: [ (F)0F0 AAAA | AAAA 0000 | 0000 0000 | 0000 FFFF ]
7228 : : * cluster1: [ FFFF 0000 | 0000 FF00 | 0000 0000 | 0000 0000 ]
7229 : : * payload_read: F000 0000 | 0000 0000 ... */
7230 : 144 : memset(payload_read, 0x00, sizeof(payload_read));
7231 : 144 : iov[0].iov_base = payload_read;
7232 : 144 : iov[0].iov_len = 1 * 512;
7233 : :
7234 [ + + ]: 144 : test_blob_io_readv(blob, channel, iov, 1, 0, 1, blob_op_complete, NULL, ext_api ? &ext_opts : NULL);
7235 : :
7236 : 144 : CU_ASSERT(memcmp(payload_read + 0 * 512, payload_ff, 512) == 0);
7237 [ - + ]: 144 : CU_ASSERT(memcmp(payload_read + 1 * 512, payload_00, 31 * 512) == 0);
7238 : :
7239 : : /* Read four io_units starting from offset = 2
7240 : : * cluster0: [ F0(F0 AA)AA | AAAA 0000 | 0000 0000 | 0000 FFFF ]
7241 : : * cluster1: [ FFFF 0000 | 0000 FF00 | 0000 0000 | 0000 0000 ]
7242 : : * payload_read: F0AA 0000 | 0000 0000 ... */
7243 : :
7244 : 144 : memset(payload_read, 0x00, sizeof(payload_read));
7245 : 144 : iov[0].iov_base = payload_read;
7246 : 144 : iov[0].iov_len = 4 * 512;
7247 : :
7248 [ + + ]: 144 : test_blob_io_readv(blob, channel, iov, 1, 2, 4, blob_op_complete, NULL, ext_api ? &ext_opts : NULL);
7249 : :
7250 : 144 : CU_ASSERT(memcmp(payload_read + 0 * 512, payload_ff, 512) == 0);
7251 [ - + ]: 144 : CU_ASSERT(memcmp(payload_read + 1 * 512, payload_00, 512) == 0);
7252 [ - + ]: 144 : CU_ASSERT(memcmp(payload_read + 2 * 512, payload_aa, 512) == 0);
7253 [ - + ]: 144 : CU_ASSERT(memcmp(payload_read + 3 * 512, payload_aa, 512) == 0);
7254 [ - + ]: 144 : CU_ASSERT(memcmp(payload_read + 4 * 512, payload_00, 28 * 512) == 0);
7255 : :
7256 : : /* Read eight io_units across multiple pages
7257 : : * cluster0: [ F0F0 (AAAA | AAAA) 0000 | 0000 0000 | 0000 FFFF ]
7258 : : * cluster1: [ FFFF 0000 | 0000 FF00 | 0000 0000 | 0000 0000 ]
7259 : : * payload_read: AAAA AAAA | 0000 0000 ... */
7260 : 144 : memset(payload_read, 0x00, sizeof(payload_read));
7261 : 144 : iov[0].iov_base = payload_read;
7262 : 144 : iov[0].iov_len = 4 * 512;
7263 : 144 : iov[1].iov_base = payload_read + 4 * 512;
7264 : 144 : iov[1].iov_len = 4 * 512;
7265 : :
7266 [ + + ]: 144 : test_blob_io_readv(blob, channel, iov, 2, 4, 8, blob_op_complete, NULL, ext_api ? &ext_opts : NULL);
7267 : :
7268 : 144 : CU_ASSERT(memcmp(payload_read + 0 * 512, payload_aa, 8 * 512) == 0);
7269 [ - + ]: 144 : CU_ASSERT(memcmp(payload_read + 8 * 512, payload_00, 24 * 512) == 0);
7270 : :
7271 : : /* Read eight io_units across multiple clusters
7272 : : * cluster0: [ F0F0 AAAA | AAAA 0000 | 0000 0000 | 0000 (FFFF ]
7273 : : * cluster1: [ FFFF) 0000 | 0000 FF00 | 0000 0000 | 0000 0000 ]
7274 : : * payload_read: FFFF FFFF | 0000 0000 ... */
7275 : 144 : memset(payload_read, 0x00, sizeof(payload_read));
7276 : 144 : iov[0].iov_base = payload_read;
7277 : 144 : iov[0].iov_len = 2 * 512;
7278 : 144 : iov[1].iov_base = payload_read + 2 * 512;
7279 : 144 : iov[1].iov_len = 2 * 512;
7280 : 144 : iov[2].iov_base = payload_read + 4 * 512;
7281 : 144 : iov[2].iov_len = 2 * 512;
7282 : 144 : iov[3].iov_base = payload_read + 6 * 512;
7283 : 144 : iov[3].iov_len = 2 * 512;
7284 : :
7285 [ + + ]: 144 : test_blob_io_readv(blob, channel, iov, 4, 28, 8, blob_op_complete, NULL,
7286 : : ext_api ? &ext_opts : NULL);
7287 : :
7288 : 144 : CU_ASSERT(memcmp(payload_read + 0 * 512, payload_ff, 8 * 512) == 0);
7289 [ - + ]: 144 : CU_ASSERT(memcmp(payload_read + 8 * 512, payload_00, 24 * 512) == 0);
7290 : :
7291 : : /* Read four io_units from second cluster
7292 : : * cluster0: [ F0F0 AAAA | AAAA 0000 | 0000 0000 | 0000 FFFF ]
7293 : : * cluster1: [ FFFF 0000 | 00(00 FF)00 | 0000 0000 | 0000 0000 ]
7294 : : * payload_read: 00FF 0000 | 0000 0000 ... */
7295 : 144 : memset(payload_read, 0x00, sizeof(payload_read));
7296 : 144 : iov[0].iov_base = payload_read;
7297 : 144 : iov[0].iov_len = 1 * 512;
7298 : 144 : iov[1].iov_base = payload_read + 1 * 512;
7299 : 144 : iov[1].iov_len = 3 * 512;
7300 : :
7301 [ + + ]: 144 : test_blob_io_readv(blob, channel, iov, 2, 32 + 10, 4, blob_op_complete, NULL,
7302 : : ext_api ? &ext_opts : NULL);
7303 : :
7304 : 144 : CU_ASSERT(memcmp(payload_read + 0 * 512, payload_00, 2 * 512) == 0);
7305 [ - + ]: 144 : CU_ASSERT(memcmp(payload_read + 2 * 512, payload_ff, 2 * 512) == 0);
7306 [ - + ]: 144 : CU_ASSERT(memcmp(payload_read + 4 * 512, payload_00, 28 * 512) == 0);
7307 : :
7308 : : /* Read second cluster
7309 : : * cluster0: [ F0F0 AAAA | AAAA 0000 | 0000 0000 | 0000 FFFF ]
7310 : : * cluster1: [ (FFFF 0000 | 0000 FF00 | 0000 0000 | 0000 0000) ]
7311 : : * payload_read: FFFF 0000 | 0000 FF00 ... */
7312 : 144 : memset(payload_read, 0x00, sizeof(payload_read));
7313 : 144 : iov[0].iov_base = payload_read;
7314 : 144 : iov[0].iov_len = 1 * 512;
7315 : 144 : iov[1].iov_base = payload_read + 1 * 512;
7316 : 144 : iov[1].iov_len = 2 * 512;
7317 : 144 : iov[2].iov_base = payload_read + 3 * 512;
7318 : 144 : iov[2].iov_len = 4 * 512;
7319 : 144 : iov[3].iov_base = payload_read + 7 * 512;
7320 : 144 : iov[3].iov_len = 25 * 512;
7321 : :
7322 [ + + ]: 144 : test_blob_io_readv(blob, channel, iov, 4, 32, 32, blob_op_complete, NULL,
7323 : : ext_api ? &ext_opts : NULL);
7324 : :
7325 : 144 : CU_ASSERT(memcmp(payload_read + 0 * 512, payload_ff, 4 * 512) == 0);
7326 [ - + ]: 144 : CU_ASSERT(memcmp(payload_read + 4 * 512, payload_00, 8 * 512) == 0);
7327 [ - + ]: 144 : CU_ASSERT(memcmp(payload_read + 12 * 512, payload_ff, 2 * 512) == 0);
7328 [ - + ]: 144 : CU_ASSERT(memcmp(payload_read + 14 * 512, payload_00, 18 * 512) == 0);
7329 : :
7330 : : /* Read whole two clusters
7331 : : * cluster0: [ (F0F0 AAAA | AAAA) 0000 | 0000 0000 | 0000 FFFF ]
7332 : : * cluster1: [ FFFF 0000 | 0000 FF00 | 0000 0000 | 0000 0000) ] */
7333 : 144 : memset(payload_read, 0x00, sizeof(payload_read));
7334 : 144 : iov[0].iov_base = payload_read;
7335 : 144 : iov[0].iov_len = 1 * 512;
7336 : 144 : iov[1].iov_base = payload_read + 1 * 512;
7337 : 144 : iov[1].iov_len = 8 * 512;
7338 : 144 : iov[2].iov_base = payload_read + 9 * 512;
7339 : 144 : iov[2].iov_len = 16 * 512;
7340 : 144 : iov[3].iov_base = payload_read + 25 * 512;
7341 : 144 : iov[3].iov_len = 39 * 512;
7342 : :
7343 [ + + ]: 144 : test_blob_io_readv(blob, channel, iov, 4, 0, 64, blob_op_complete, NULL,
7344 : : ext_api ? &ext_opts : NULL);
7345 : :
7346 : 144 : CU_ASSERT(memcmp(payload_read + 0 * 512, payload_ff, 512) == 0);
7347 [ - + ]: 144 : CU_ASSERT(memcmp(payload_read + 1 * 512, payload_00, 512) == 0);
7348 [ - + ]: 144 : CU_ASSERT(memcmp(payload_read + 2 * 512, payload_ff, 512) == 0);
7349 [ - + ]: 144 : CU_ASSERT(memcmp(payload_read + 3 * 512, payload_00, 512) == 0);
7350 [ - + ]: 144 : CU_ASSERT(memcmp(payload_read + 4 * 512, payload_aa, 8 * 512) == 0);
7351 [ - + ]: 144 : CU_ASSERT(memcmp(payload_read + 28 * 512, payload_ff, 4 * 512) == 0);
7352 : :
7353 [ - + ]: 144 : CU_ASSERT(memcmp(payload_read + (32 + 0) * 512, payload_ff, 4 * 512) == 0);
7354 [ - + ]: 144 : CU_ASSERT(memcmp(payload_read + (32 + 4) * 512, payload_00, 8 * 512) == 0);
7355 [ - + ]: 144 : CU_ASSERT(memcmp(payload_read + (32 + 12) * 512, payload_ff, 2 * 512) == 0);
7356 [ - + ]: 144 : CU_ASSERT(memcmp(payload_read + (32 + 14) * 512, payload_00, 18 * 512) == 0);
7357 : 144 : }
7358 : :
7359 : : static void
7360 : 12 : blob_io_unit(void)
7361 : : {
7362 : 12 : struct spdk_bs_opts bsopts;
7363 : 12 : struct spdk_blob_opts opts;
7364 : : struct spdk_blob_store *bs;
7365 : : struct spdk_bs_dev *dev;
7366 : : struct spdk_blob *blob, *snapshot, *clone;
7367 : : spdk_blob_id blobid;
7368 : : struct spdk_io_channel *channel;
7369 : :
7370 : : /* Create dev with 512 bytes io unit size */
7371 : :
7372 : 12 : spdk_bs_opts_init(&bsopts, sizeof(bsopts));
7373 : 12 : bsopts.cluster_sz = SPDK_BS_PAGE_SIZE * 4; /* 8 * 4 = 32 io_unit */
7374 : 12 : snprintf(bsopts.bstype.bstype, sizeof(bsopts.bstype.bstype), "TESTTYPE");
7375 : :
7376 : : /* Try to initialize a new blob store with unsupported io_unit */
7377 : 12 : dev = init_dev();
7378 : 12 : dev->blocklen = 512;
7379 [ - + ]: 12 : dev->blockcnt = DEV_BUFFER_SIZE / dev->blocklen;
7380 : :
7381 : : /* Initialize a new blob store */
7382 : 12 : spdk_bs_init(dev, &bsopts, bs_op_with_handle_complete, NULL);
7383 : 12 : poll_threads();
7384 : 12 : CU_ASSERT(g_bserrno == 0);
7385 [ - + ]: 12 : SPDK_CU_ASSERT_FATAL(g_bs != NULL);
7386 : 12 : bs = g_bs;
7387 : :
7388 : 12 : CU_ASSERT(spdk_bs_get_io_unit_size(bs) == 512);
7389 : 12 : channel = spdk_bs_alloc_io_channel(bs);
7390 : :
7391 : : /* Create thick provisioned blob */
7392 : 12 : ut_spdk_blob_opts_init(&opts);
7393 : 12 : opts.thin_provision = false;
7394 : 12 : opts.num_clusters = 32;
7395 : :
7396 : 12 : blob = ut_blob_create_and_open(bs, &opts);
7397 : 12 : blobid = spdk_blob_get_id(blob);
7398 : :
7399 : 12 : test_io_write(dev, blob, channel);
7400 : 12 : test_io_read(dev, blob, channel);
7401 : 12 : test_io_zeroes(dev, blob, channel);
7402 : :
7403 : 12 : test_iov_write(dev, blob, channel, false);
7404 : 12 : test_iov_read(dev, blob, channel, false);
7405 : 12 : test_io_zeroes(dev, blob, channel);
7406 : :
7407 : 12 : test_iov_write(dev, blob, channel, true);
7408 : 12 : test_iov_read(dev, blob, channel, true);
7409 : :
7410 : 12 : test_io_unmap(dev, blob, channel);
7411 : :
7412 : 12 : spdk_blob_close(blob, blob_op_complete, NULL);
7413 : 12 : poll_threads();
7414 : 12 : CU_ASSERT(g_bserrno == 0);
7415 : 12 : blob = NULL;
7416 : 12 : g_blob = NULL;
7417 : :
7418 : : /* Create thin provisioned blob */
7419 : :
7420 : 12 : ut_spdk_blob_opts_init(&opts);
7421 : 12 : opts.thin_provision = true;
7422 : 12 : opts.num_clusters = 32;
7423 : :
7424 : 12 : blob = ut_blob_create_and_open(bs, &opts);
7425 : 12 : blobid = spdk_blob_get_id(blob);
7426 : :
7427 : 12 : test_io_write(dev, blob, channel);
7428 : 12 : test_io_read(dev, blob, channel);
7429 : 12 : test_io_zeroes(dev, blob, channel);
7430 : :
7431 : 12 : test_iov_write(dev, blob, channel, false);
7432 : 12 : test_iov_read(dev, blob, channel, false);
7433 : 12 : test_io_zeroes(dev, blob, channel);
7434 : :
7435 : 12 : test_iov_write(dev, blob, channel, true);
7436 : 12 : test_iov_read(dev, blob, channel, true);
7437 : :
7438 : : /* Create snapshot */
7439 : :
7440 : 12 : spdk_bs_create_snapshot(bs, blobid, NULL, blob_op_with_id_complete, NULL);
7441 : 12 : poll_threads();
7442 : 12 : CU_ASSERT(g_bserrno == 0);
7443 : 12 : CU_ASSERT(g_blobid != SPDK_BLOBID_INVALID);
7444 : 12 : blobid = g_blobid;
7445 : :
7446 : 12 : spdk_bs_open_blob(bs, blobid, blob_op_with_handle_complete, NULL);
7447 : 12 : poll_threads();
7448 : 12 : CU_ASSERT(g_bserrno == 0);
7449 : 12 : CU_ASSERT(g_blob != NULL);
7450 : 12 : snapshot = g_blob;
7451 : :
7452 : 12 : spdk_bs_create_clone(bs, blobid, NULL, blob_op_with_id_complete, NULL);
7453 : 12 : poll_threads();
7454 : 12 : CU_ASSERT(g_bserrno == 0);
7455 : 12 : CU_ASSERT(g_blobid != SPDK_BLOBID_INVALID);
7456 : 12 : blobid = g_blobid;
7457 : :
7458 : 12 : spdk_bs_open_blob(bs, blobid, blob_op_with_handle_complete, NULL);
7459 : 12 : poll_threads();
7460 : 12 : CU_ASSERT(g_bserrno == 0);
7461 : 12 : CU_ASSERT(g_blob != NULL);
7462 : 12 : clone = g_blob;
7463 : :
7464 : 12 : test_io_read(dev, blob, channel);
7465 : 12 : test_io_read(dev, snapshot, channel);
7466 : 12 : test_io_read(dev, clone, channel);
7467 : :
7468 : 12 : test_iov_read(dev, blob, channel, false);
7469 : 12 : test_iov_read(dev, snapshot, channel, false);
7470 : 12 : test_iov_read(dev, clone, channel, false);
7471 : :
7472 : 12 : test_iov_read(dev, blob, channel, true);
7473 : 12 : test_iov_read(dev, snapshot, channel, true);
7474 : 12 : test_iov_read(dev, clone, channel, true);
7475 : :
7476 : : /* Inflate clone */
7477 : :
7478 : 12 : spdk_bs_inflate_blob(bs, channel, blobid, blob_op_complete, NULL);
7479 : 12 : poll_threads();
7480 : :
7481 : 12 : CU_ASSERT(g_bserrno == 0);
7482 : :
7483 : 12 : test_io_read(dev, clone, channel);
7484 : :
7485 : 12 : test_io_unmap(dev, clone, channel);
7486 : :
7487 : 12 : test_iov_write(dev, clone, channel, false);
7488 : 12 : test_iov_read(dev, clone, channel, false);
7489 : 12 : test_io_unmap(dev, clone, channel);
7490 : :
7491 : 12 : test_iov_write(dev, clone, channel, true);
7492 : 12 : test_iov_read(dev, clone, channel, true);
7493 : :
7494 : 12 : spdk_blob_close(blob, blob_op_complete, NULL);
7495 : 12 : spdk_blob_close(snapshot, blob_op_complete, NULL);
7496 : 12 : spdk_blob_close(clone, blob_op_complete, NULL);
7497 : 12 : poll_threads();
7498 : 12 : CU_ASSERT(g_bserrno == 0);
7499 : 12 : blob = NULL;
7500 : 12 : g_blob = NULL;
7501 : :
7502 : 12 : spdk_bs_free_io_channel(channel);
7503 : 12 : poll_threads();
7504 : :
7505 : : /* Unload the blob store */
7506 : 12 : spdk_bs_unload(bs, bs_op_complete, NULL);
7507 : 12 : poll_threads();
7508 : 12 : CU_ASSERT(g_bserrno == 0);
7509 : 12 : g_bs = NULL;
7510 : 12 : g_blob = NULL;
7511 : 12 : g_blobid = 0;
7512 : 12 : }
7513 : :
7514 : : static void
7515 : 12 : blob_io_unit_compatibility(void)
7516 : : {
7517 : 12 : struct spdk_bs_opts bsopts;
7518 : : struct spdk_blob_store *bs;
7519 : : struct spdk_bs_dev *dev;
7520 : : struct spdk_bs_super_block *super;
7521 : :
7522 : : /* Create dev with 512 bytes io unit size */
7523 : :
7524 : 12 : spdk_bs_opts_init(&bsopts, sizeof(bsopts));
7525 : 12 : bsopts.cluster_sz = SPDK_BS_PAGE_SIZE * 4; /* 8 * 4 = 32 io_unit */
7526 : 12 : snprintf(bsopts.bstype.bstype, sizeof(bsopts.bstype.bstype), "TESTTYPE");
7527 : :
7528 : : /* Try to initialize a new blob store with unsupported io_unit */
7529 : 12 : dev = init_dev();
7530 : 12 : dev->blocklen = 512;
7531 [ - + ]: 12 : dev->blockcnt = DEV_BUFFER_SIZE / dev->blocklen;
7532 : :
7533 : : /* Initialize a new blob store */
7534 : 12 : spdk_bs_init(dev, &bsopts, bs_op_with_handle_complete, NULL);
7535 : 12 : poll_threads();
7536 : 12 : CU_ASSERT(g_bserrno == 0);
7537 [ - + ]: 12 : SPDK_CU_ASSERT_FATAL(g_bs != NULL);
7538 : 12 : bs = g_bs;
7539 : :
7540 : 12 : CU_ASSERT(spdk_bs_get_io_unit_size(bs) == 512);
7541 : :
7542 : : /* Unload the blob store */
7543 : 12 : spdk_bs_unload(bs, bs_op_complete, NULL);
7544 : 12 : poll_threads();
7545 : 12 : CU_ASSERT(g_bserrno == 0);
7546 : :
7547 : : /* Modify super block to behave like older version.
7548 : : * Check if loaded io unit size equals SPDK_BS_PAGE_SIZE */
7549 : 12 : super = (struct spdk_bs_super_block *)&g_dev_buffer[0];
7550 : 12 : super->io_unit_size = 0;
7551 : 12 : super->crc = blob_md_page_calc_crc(super);
7552 : :
7553 : 12 : dev = init_dev();
7554 : 12 : dev->blocklen = 512;
7555 [ - + ]: 12 : dev->blockcnt = DEV_BUFFER_SIZE / dev->blocklen;
7556 : :
7557 : 12 : spdk_bs_load(dev, &bsopts, bs_op_with_handle_complete, NULL);
7558 : 12 : poll_threads();
7559 : 12 : CU_ASSERT(g_bserrno == 0);
7560 [ - + ]: 12 : SPDK_CU_ASSERT_FATAL(g_bs != NULL);
7561 : 12 : bs = g_bs;
7562 : :
7563 : 12 : CU_ASSERT(spdk_bs_get_io_unit_size(bs) == SPDK_BS_PAGE_SIZE);
7564 : :
7565 : : /* Unload the blob store */
7566 : 12 : spdk_bs_unload(bs, bs_op_complete, NULL);
7567 : 12 : poll_threads();
7568 : 12 : CU_ASSERT(g_bserrno == 0);
7569 : :
7570 : 12 : g_bs = NULL;
7571 : 12 : g_blob = NULL;
7572 : 12 : g_blobid = 0;
7573 : 12 : }
7574 : :
7575 : : static void
7576 : 12 : first_sync_complete(void *cb_arg, int bserrno)
7577 : : {
7578 : 12 : struct spdk_blob *blob = cb_arg;
7579 : : int rc;
7580 : :
7581 : 12 : CU_ASSERT(bserrno == 0);
7582 : 12 : rc = spdk_blob_set_xattr(blob, "sync", "second", strlen("second") + 1);
7583 : 12 : CU_ASSERT(rc == 0);
7584 : 12 : CU_ASSERT(g_bserrno == -1);
7585 : :
7586 : : /* Keep g_bserrno at -1, only the
7587 : : * second sync completion should set it at 0. */
7588 : 12 : }
7589 : :
7590 : : static void
7591 : 12 : second_sync_complete(void *cb_arg, int bserrno)
7592 : : {
7593 : 12 : struct spdk_blob *blob = cb_arg;
7594 : 12 : const void *value;
7595 : 12 : size_t value_len;
7596 : : int rc;
7597 : :
7598 : 12 : CU_ASSERT(bserrno == 0);
7599 : :
7600 : : /* Verify that the first sync completion had a chance to execute */
7601 : 12 : rc = spdk_blob_get_xattr_value(blob, "sync", &value, &value_len);
7602 : 12 : CU_ASSERT(rc == 0);
7603 [ - + ]: 12 : SPDK_CU_ASSERT_FATAL(value != NULL);
7604 : 12 : CU_ASSERT(value_len == strlen("second") + 1);
7605 [ - + ]: 12 : CU_ASSERT_NSTRING_EQUAL_FATAL(value, "second", value_len);
7606 : :
7607 : 12 : CU_ASSERT(g_bserrno == -1);
7608 : 12 : g_bserrno = bserrno;
7609 : 12 : }
7610 : :
7611 : : static void
7612 : 12 : blob_simultaneous_operations(void)
7613 : : {
7614 : 12 : struct spdk_blob_store *bs = g_bs;
7615 : 12 : struct spdk_blob_opts opts;
7616 : : struct spdk_blob *blob, *snapshot;
7617 : : spdk_blob_id blobid, snapshotid;
7618 : : struct spdk_io_channel *channel;
7619 : : int rc;
7620 : :
7621 : 12 : channel = spdk_bs_alloc_io_channel(bs);
7622 [ - + ]: 12 : SPDK_CU_ASSERT_FATAL(channel != NULL);
7623 : :
7624 : 12 : ut_spdk_blob_opts_init(&opts);
7625 : 12 : opts.num_clusters = 10;
7626 : :
7627 : 12 : blob = ut_blob_create_and_open(bs, &opts);
7628 : 12 : blobid = spdk_blob_get_id(blob);
7629 : :
7630 : : /* Create snapshot and try to remove blob in the same time:
7631 : : * - snapshot should be created successfully
7632 : : * - delete operation should fail w -EBUSY */
7633 [ - + ]: 12 : CU_ASSERT(blob->locked_operation_in_progress == false);
7634 : 12 : spdk_bs_create_snapshot(bs, blobid, NULL, blob_op_with_id_complete, NULL);
7635 [ - + ]: 12 : CU_ASSERT(blob->locked_operation_in_progress == true);
7636 : 12 : spdk_bs_delete_blob(bs, blobid, blob_op_complete, NULL);
7637 [ - + ]: 12 : CU_ASSERT(blob->locked_operation_in_progress == true);
7638 : : /* Deletion failure */
7639 : 12 : CU_ASSERT(g_bserrno == -EBUSY);
7640 : 12 : poll_threads();
7641 [ - + ]: 12 : CU_ASSERT(blob->locked_operation_in_progress == false);
7642 : : /* Snapshot creation success */
7643 : 12 : CU_ASSERT(g_bserrno == 0);
7644 : 12 : CU_ASSERT(g_blobid != SPDK_BLOBID_INVALID);
7645 : :
7646 : 12 : snapshotid = g_blobid;
7647 : :
7648 : 12 : spdk_bs_open_blob(bs, snapshotid, blob_op_with_handle_complete, NULL);
7649 : 12 : poll_threads();
7650 : 12 : CU_ASSERT(g_bserrno == 0);
7651 [ - + ]: 12 : SPDK_CU_ASSERT_FATAL(g_blob != NULL);
7652 : 12 : snapshot = g_blob;
7653 : :
7654 : : /* Inflate blob and try to remove blob in the same time:
7655 : : * - blob should be inflated successfully
7656 : : * - delete operation should fail w -EBUSY */
7657 [ - + ]: 12 : CU_ASSERT(blob->locked_operation_in_progress == false);
7658 : 12 : spdk_bs_inflate_blob(bs, channel, blobid, blob_op_complete, NULL);
7659 [ - + ]: 12 : CU_ASSERT(blob->locked_operation_in_progress == true);
7660 : 12 : spdk_bs_delete_blob(bs, blobid, blob_op_complete, NULL);
7661 [ - + ]: 12 : CU_ASSERT(blob->locked_operation_in_progress == true);
7662 : : /* Deletion failure */
7663 : 12 : CU_ASSERT(g_bserrno == -EBUSY);
7664 : 12 : poll_threads();
7665 [ - + ]: 12 : CU_ASSERT(blob->locked_operation_in_progress == false);
7666 : : /* Inflation success */
7667 : 12 : CU_ASSERT(g_bserrno == 0);
7668 : :
7669 : : /* Clone snapshot and try to remove snapshot in the same time:
7670 : : * - snapshot should be cloned successfully
7671 : : * - delete operation should fail w -EBUSY */
7672 [ - + ]: 12 : CU_ASSERT(blob->locked_operation_in_progress == false);
7673 : 12 : spdk_bs_create_clone(bs, snapshotid, NULL, blob_op_with_id_complete, NULL);
7674 : 12 : spdk_bs_delete_blob(bs, snapshotid, blob_op_complete, NULL);
7675 : : /* Deletion failure */
7676 : 12 : CU_ASSERT(g_bserrno == -EBUSY);
7677 : 12 : poll_threads();
7678 [ - + ]: 12 : CU_ASSERT(blob->locked_operation_in_progress == false);
7679 : : /* Clone created */
7680 : 12 : CU_ASSERT(g_bserrno == 0);
7681 : :
7682 : : /* Resize blob and try to remove blob in the same time:
7683 : : * - blob should be resized successfully
7684 : : * - delete operation should fail w -EBUSY */
7685 [ - + ]: 12 : CU_ASSERT(blob->locked_operation_in_progress == false);
7686 : 12 : spdk_blob_resize(blob, 50, blob_op_complete, NULL);
7687 [ - + ]: 12 : CU_ASSERT(blob->locked_operation_in_progress == true);
7688 : 12 : spdk_bs_delete_blob(bs, blobid, blob_op_complete, NULL);
7689 [ - + ]: 12 : CU_ASSERT(blob->locked_operation_in_progress == true);
7690 : : /* Deletion failure */
7691 : 12 : CU_ASSERT(g_bserrno == -EBUSY);
7692 : 12 : poll_threads();
7693 [ - + ]: 12 : CU_ASSERT(blob->locked_operation_in_progress == false);
7694 : : /* Blob resized successfully */
7695 : 12 : spdk_blob_sync_md(blob, blob_op_complete, NULL);
7696 : 12 : poll_threads();
7697 : 12 : CU_ASSERT(g_bserrno == 0);
7698 : :
7699 : : /* Issue two consecutive blob syncs, neither should fail.
7700 : : * Force sync to actually occur by marking blob dirty each time.
7701 : : * Execution of sync should not be enough to complete the operation,
7702 : : * since disk I/O is required to complete it. */
7703 : 12 : g_bserrno = -1;
7704 : :
7705 : 12 : rc = spdk_blob_set_xattr(blob, "sync", "first", strlen("first") + 1);
7706 : 12 : CU_ASSERT(rc == 0);
7707 : 12 : spdk_blob_sync_md(blob, first_sync_complete, blob);
7708 : 12 : CU_ASSERT(g_bserrno == -1);
7709 : :
7710 : 12 : spdk_blob_sync_md(blob, second_sync_complete, blob);
7711 : 12 : CU_ASSERT(g_bserrno == -1);
7712 : :
7713 : 12 : poll_threads();
7714 : 12 : CU_ASSERT(g_bserrno == 0);
7715 : :
7716 : 12 : spdk_bs_free_io_channel(channel);
7717 : 12 : poll_threads();
7718 : :
7719 : 12 : ut_blob_close_and_delete(bs, snapshot);
7720 : 12 : ut_blob_close_and_delete(bs, blob);
7721 : 12 : }
7722 : :
7723 : : static void
7724 : 12 : blob_persist_test(void)
7725 : : {
7726 : 12 : struct spdk_blob_store *bs = g_bs;
7727 : 12 : struct spdk_blob_opts opts;
7728 : : struct spdk_blob *blob;
7729 : : spdk_blob_id blobid;
7730 : : struct spdk_io_channel *channel;
7731 : 12 : char *xattr;
7732 : 12 : size_t xattr_length;
7733 : : int rc;
7734 : : uint32_t page_count_clear, page_count_xattr;
7735 : : uint64_t poller_iterations;
7736 : : bool run_poller;
7737 : :
7738 : 12 : channel = spdk_bs_alloc_io_channel(bs);
7739 [ - + ]: 12 : SPDK_CU_ASSERT_FATAL(channel != NULL);
7740 : :
7741 : 12 : ut_spdk_blob_opts_init(&opts);
7742 : 12 : opts.num_clusters = 10;
7743 : :
7744 : 12 : blob = ut_blob_create_and_open(bs, &opts);
7745 : 12 : blobid = spdk_blob_get_id(blob);
7746 : :
7747 : : /* Save the amount of md pages used after creation of a blob.
7748 : : * This should be consistent after removing xattr. */
7749 : 12 : page_count_clear = spdk_bit_array_count_set(bs->used_md_pages);
7750 [ - + ]: 12 : SPDK_CU_ASSERT_FATAL(blob->active.num_pages + blob->active.num_extent_pages == page_count_clear);
7751 [ - + ]: 12 : SPDK_CU_ASSERT_FATAL(blob->clean.num_pages + blob->clean.num_extent_pages == page_count_clear);
7752 : :
7753 : : /* Add xattr with maximum length of descriptor to exceed single metadata page. */
7754 : 12 : xattr_length = SPDK_BS_MAX_DESC_SIZE - sizeof(struct spdk_blob_md_descriptor_xattr) -
7755 : : strlen("large_xattr");
7756 : 12 : xattr = calloc(xattr_length, sizeof(char));
7757 [ - + ]: 12 : SPDK_CU_ASSERT_FATAL(xattr != NULL);
7758 : :
7759 : 12 : rc = spdk_blob_set_xattr(blob, "large_xattr", xattr, xattr_length);
7760 [ - + ]: 12 : SPDK_CU_ASSERT_FATAL(rc == 0);
7761 : 12 : spdk_blob_sync_md(blob, blob_op_complete, NULL);
7762 : 12 : poll_threads();
7763 [ - + ]: 12 : SPDK_CU_ASSERT_FATAL(g_bserrno == 0);
7764 : :
7765 : : /* Save the amount of md pages used after adding the large xattr */
7766 : 12 : page_count_xattr = spdk_bit_array_count_set(bs->used_md_pages);
7767 [ - + ]: 12 : SPDK_CU_ASSERT_FATAL(blob->active.num_pages + blob->active.num_extent_pages == page_count_xattr);
7768 [ - + ]: 12 : SPDK_CU_ASSERT_FATAL(blob->clean.num_pages + blob->clean.num_extent_pages == page_count_xattr);
7769 : :
7770 : : /* Add xattr to a blob and sync it. While sync is occurring, remove the xattr and sync again.
7771 : : * Interrupt the first sync after increasing number of poller iterations, until it succeeds.
7772 : : * Expectation is that after second sync completes no xattr is saved in metadata. */
7773 : 12 : poller_iterations = 1;
7774 : 12 : run_poller = true;
7775 [ + + ]: 84 : while (run_poller) {
7776 : 72 : rc = spdk_blob_set_xattr(blob, "large_xattr", xattr, xattr_length);
7777 [ - + ]: 72 : SPDK_CU_ASSERT_FATAL(rc == 0);
7778 : 72 : g_bserrno = -1;
7779 : 72 : spdk_blob_sync_md(blob, blob_op_complete, NULL);
7780 : 72 : poll_thread_times(0, poller_iterations);
7781 [ + + ]: 72 : if (g_bserrno == 0) {
7782 : : /* Poller iteration count was high enough for first sync to complete.
7783 : : * Verify that blob takes up enough of md_pages to store the xattr. */
7784 [ - + ]: 12 : SPDK_CU_ASSERT_FATAL(blob->active.num_pages + blob->active.num_extent_pages == page_count_xattr);
7785 [ - + ]: 12 : SPDK_CU_ASSERT_FATAL(blob->clean.num_pages + blob->clean.num_extent_pages == page_count_xattr);
7786 [ - + ]: 12 : SPDK_CU_ASSERT_FATAL(spdk_bit_array_count_set(bs->used_md_pages) == page_count_xattr);
7787 : 12 : run_poller = false;
7788 : : }
7789 : 72 : rc = spdk_blob_remove_xattr(blob, "large_xattr");
7790 [ - + ]: 72 : SPDK_CU_ASSERT_FATAL(rc == 0);
7791 : 72 : spdk_blob_sync_md(blob, blob_op_complete, NULL);
7792 : 72 : poll_threads();
7793 [ - + ]: 72 : SPDK_CU_ASSERT_FATAL(g_bserrno == 0);
7794 [ - + ]: 72 : SPDK_CU_ASSERT_FATAL(blob->active.num_pages + blob->active.num_extent_pages == page_count_clear);
7795 [ - + ]: 72 : SPDK_CU_ASSERT_FATAL(blob->clean.num_pages + blob->clean.num_extent_pages == page_count_clear);
7796 [ - + ]: 72 : SPDK_CU_ASSERT_FATAL(spdk_bit_array_count_set(bs->used_md_pages) == page_count_clear);
7797 : :
7798 : : /* Reload bs and re-open blob to verify that xattr was not persisted. */
7799 : 72 : spdk_blob_close(blob, blob_op_complete, NULL);
7800 : 72 : poll_threads();
7801 : 72 : CU_ASSERT(g_bserrno == 0);
7802 : :
7803 : 72 : ut_bs_reload(&bs, NULL);
7804 : :
7805 : 72 : spdk_bs_open_blob(bs, blobid, blob_op_with_handle_complete, NULL);
7806 : 72 : poll_threads();
7807 : 72 : CU_ASSERT(g_bserrno == 0);
7808 [ - + ]: 72 : SPDK_CU_ASSERT_FATAL(g_blob != NULL);
7809 : 72 : blob = g_blob;
7810 : :
7811 : 72 : rc = spdk_blob_get_xattr_value(blob, "large_xattr", (const void **)&xattr, &xattr_length);
7812 [ - + ]: 72 : SPDK_CU_ASSERT_FATAL(rc == -ENOENT);
7813 : :
7814 : 72 : poller_iterations++;
7815 : : /* Stop at high iteration count to prevent infinite loop.
7816 : : * This value should be enough for first md sync to complete in any case. */
7817 [ - + ]: 72 : SPDK_CU_ASSERT_FATAL(poller_iterations < 50);
7818 : : }
7819 : :
7820 : 12 : free(xattr);
7821 : :
7822 : 12 : ut_blob_close_and_delete(bs, blob);
7823 : :
7824 : 12 : spdk_bs_free_io_channel(channel);
7825 : 12 : poll_threads();
7826 : 12 : }
7827 : :
7828 : : static void
7829 : 12 : blob_decouple_snapshot(void)
7830 : : {
7831 : 12 : struct spdk_blob_store *bs = g_bs;
7832 : 12 : struct spdk_blob_opts opts;
7833 : : struct spdk_blob *blob, *snapshot1, *snapshot2;
7834 : : struct spdk_io_channel *channel;
7835 : : spdk_blob_id blobid, snapshotid;
7836 : : uint64_t cluster;
7837 : :
7838 [ + + ]: 36 : for (int delete_snapshot_first = 0; delete_snapshot_first <= 1; delete_snapshot_first++) {
7839 : 24 : channel = spdk_bs_alloc_io_channel(bs);
7840 [ - + ]: 24 : SPDK_CU_ASSERT_FATAL(channel != NULL);
7841 : :
7842 : 24 : ut_spdk_blob_opts_init(&opts);
7843 : 24 : opts.num_clusters = 10;
7844 : 24 : opts.thin_provision = false;
7845 : :
7846 : 24 : blob = ut_blob_create_and_open(bs, &opts);
7847 : 24 : blobid = spdk_blob_get_id(blob);
7848 : :
7849 : : /* Create first snapshot */
7850 : 24 : CU_ASSERT_EQUAL(_get_snapshots_count(bs), 0);
7851 : 24 : spdk_bs_create_snapshot(bs, blobid, NULL, blob_op_with_id_complete, NULL);
7852 : 24 : poll_threads();
7853 : 24 : CU_ASSERT(g_bserrno == 0);
7854 : 24 : CU_ASSERT(g_blobid != SPDK_BLOBID_INVALID);
7855 : 24 : CU_ASSERT_EQUAL(_get_snapshots_count(bs), 1);
7856 : 24 : snapshotid = g_blobid;
7857 : :
7858 : 24 : spdk_bs_open_blob(bs, snapshotid, blob_op_with_handle_complete, NULL);
7859 : 24 : poll_threads();
7860 : 24 : CU_ASSERT(g_bserrno == 0);
7861 [ - + ]: 24 : SPDK_CU_ASSERT_FATAL(g_blob != NULL);
7862 : 24 : snapshot1 = g_blob;
7863 : :
7864 : : /* Create the second one */
7865 : 24 : CU_ASSERT_EQUAL(_get_snapshots_count(bs), 1);
7866 : 24 : spdk_bs_create_snapshot(bs, blobid, NULL, blob_op_with_id_complete, NULL);
7867 : 24 : poll_threads();
7868 : 24 : CU_ASSERT(g_bserrno == 0);
7869 : 24 : CU_ASSERT(g_blobid != SPDK_BLOBID_INVALID);
7870 : 24 : CU_ASSERT_EQUAL(_get_snapshots_count(bs), 2);
7871 : 24 : snapshotid = g_blobid;
7872 : :
7873 : 24 : spdk_bs_open_blob(bs, snapshotid, blob_op_with_handle_complete, NULL);
7874 : 24 : poll_threads();
7875 : 24 : CU_ASSERT(g_bserrno == 0);
7876 [ - + ]: 24 : SPDK_CU_ASSERT_FATAL(g_blob != NULL);
7877 : 24 : snapshot2 = g_blob;
7878 : 24 : CU_ASSERT_EQUAL(spdk_blob_get_parent_snapshot(bs, snapshot2->id), snapshot1->id);
7879 : :
7880 : : /* Now decouple the second snapshot forcing it to copy the written clusters */
7881 : 24 : spdk_bs_blob_decouple_parent(bs, channel, snapshot2->id, blob_op_complete, NULL);
7882 : 24 : poll_threads();
7883 : 24 : CU_ASSERT(g_bserrno == 0);
7884 : :
7885 : : /* Verify that the snapshot has been decoupled and that the clusters have been copied */
7886 : 24 : CU_ASSERT_EQUAL(spdk_blob_get_parent_snapshot(bs, snapshot2->id), SPDK_BLOBID_INVALID);
7887 [ + + ]: 264 : for (cluster = 0; cluster < snapshot2->active.num_clusters; ++cluster) {
7888 : 240 : CU_ASSERT_NOT_EQUAL(snapshot2->active.clusters[cluster], 0);
7889 : 240 : CU_ASSERT_NOT_EQUAL(snapshot2->active.clusters[cluster],
7890 : : snapshot1->active.clusters[cluster]);
7891 : : }
7892 : :
7893 : 24 : spdk_bs_free_io_channel(channel);
7894 : :
7895 [ + + ]: 24 : if (delete_snapshot_first) {
7896 : 12 : ut_blob_close_and_delete(bs, snapshot2);
7897 : 12 : ut_blob_close_and_delete(bs, snapshot1);
7898 : 12 : ut_blob_close_and_delete(bs, blob);
7899 : : } else {
7900 : 12 : ut_blob_close_and_delete(bs, blob);
7901 : 12 : ut_blob_close_and_delete(bs, snapshot2);
7902 : 12 : ut_blob_close_and_delete(bs, snapshot1);
7903 : : }
7904 : 24 : poll_threads();
7905 : : }
7906 : 12 : }
7907 : :
7908 : : static void
7909 : 12 : blob_seek_io_unit(void)
7910 : : {
7911 : 12 : struct spdk_blob_store *bs = g_bs;
7912 : : struct spdk_blob *blob;
7913 : : struct spdk_io_channel *channel;
7914 : 12 : struct spdk_blob_opts opts;
7915 : : uint64_t free_clusters;
7916 : 12 : uint8_t payload[10 * 4096];
7917 : : uint64_t offset;
7918 : : uint64_t io_unit, io_units_per_cluster;
7919 : :
7920 : 12 : free_clusters = spdk_bs_free_cluster_count(bs);
7921 : :
7922 : 12 : channel = spdk_bs_alloc_io_channel(bs);
7923 : 12 : CU_ASSERT(channel != NULL);
7924 : :
7925 : : /* Set blob as thin provisioned */
7926 : 12 : ut_spdk_blob_opts_init(&opts);
7927 : 12 : opts.thin_provision = true;
7928 : :
7929 : : /* Create a blob */
7930 : 12 : blob = ut_blob_create_and_open(bs, &opts);
7931 : 12 : CU_ASSERT(free_clusters == spdk_bs_free_cluster_count(bs));
7932 : :
7933 : 12 : io_units_per_cluster = bs_io_units_per_cluster(blob);
7934 : :
7935 : : /* The blob started at 0 clusters. Resize it to be 5, but still unallocated. */
7936 : 12 : spdk_blob_resize(blob, 5, blob_op_complete, NULL);
7937 : 12 : poll_threads();
7938 : 12 : CU_ASSERT(g_bserrno == 0);
7939 : 12 : CU_ASSERT(free_clusters == spdk_bs_free_cluster_count(bs));
7940 : 12 : CU_ASSERT(blob->active.num_clusters == 5);
7941 : :
7942 : : /* Write at the beginning of first cluster */
7943 : 12 : offset = 0;
7944 : 12 : spdk_blob_io_write(blob, channel, payload, offset, 1, blob_op_complete, NULL);
7945 : 12 : poll_threads();
7946 : 12 : CU_ASSERT(g_bserrno == 0);
7947 : :
7948 : 12 : io_unit = spdk_blob_get_next_allocated_io_unit(blob, 0);
7949 : 12 : CU_ASSERT(io_unit == offset);
7950 : :
7951 : 12 : io_unit = spdk_blob_get_next_unallocated_io_unit(blob, 0);
7952 : 12 : CU_ASSERT(io_unit == io_units_per_cluster);
7953 : :
7954 : : /* Write in the middle of third cluster */
7955 : 12 : offset = 2 * io_units_per_cluster + io_units_per_cluster / 2;
7956 : 12 : spdk_blob_io_write(blob, channel, payload, offset, 1, blob_op_complete, NULL);
7957 : 12 : poll_threads();
7958 : 12 : CU_ASSERT(g_bserrno == 0);
7959 : :
7960 : 12 : io_unit = spdk_blob_get_next_allocated_io_unit(blob, io_units_per_cluster);
7961 : 12 : CU_ASSERT(io_unit == 2 * io_units_per_cluster);
7962 : :
7963 : 12 : io_unit = spdk_blob_get_next_unallocated_io_unit(blob, 2 * io_units_per_cluster);
7964 : 12 : CU_ASSERT(io_unit == 3 * io_units_per_cluster);
7965 : :
7966 : : /* Write at the end of last cluster */
7967 : 12 : offset = 5 * io_units_per_cluster - 1;
7968 : 12 : spdk_blob_io_write(blob, channel, payload, offset, 1, blob_op_complete, NULL);
7969 : 12 : poll_threads();
7970 : 12 : CU_ASSERT(g_bserrno == 0);
7971 : :
7972 : 12 : io_unit = spdk_blob_get_next_allocated_io_unit(blob, 3 * io_units_per_cluster);
7973 : 12 : CU_ASSERT(io_unit == 4 * io_units_per_cluster);
7974 : :
7975 : 12 : io_unit = spdk_blob_get_next_unallocated_io_unit(blob, 4 * io_units_per_cluster);
7976 : 12 : CU_ASSERT(io_unit == UINT64_MAX);
7977 : :
7978 : 12 : spdk_bs_free_io_channel(channel);
7979 : 12 : poll_threads();
7980 : :
7981 : 12 : ut_blob_close_and_delete(bs, blob);
7982 : 12 : }
7983 : :
7984 : : static void
7985 : 12 : blob_esnap_create(void)
7986 : : {
7987 : 12 : struct spdk_blob_store *bs = g_bs;
7988 : 12 : struct spdk_bs_opts bs_opts;
7989 : 12 : struct ut_esnap_opts esnap_opts;
7990 : 12 : struct spdk_blob_opts opts;
7991 : 12 : struct spdk_blob_open_opts open_opts;
7992 : : struct spdk_blob *blob;
7993 : : uint32_t cluster_sz, block_sz;
7994 : 12 : const uint32_t esnap_num_clusters = 4;
7995 : : uint64_t esnap_num_blocks;
7996 : : uint32_t sz;
7997 : : spdk_blob_id blobid;
7998 : 12 : uint32_t bs_ctx_count, blob_ctx_count;
7999 : :
8000 : 12 : cluster_sz = spdk_bs_get_cluster_size(bs);
8001 : 12 : block_sz = spdk_bs_get_io_unit_size(bs);
8002 [ - + ]: 12 : esnap_num_blocks = cluster_sz * esnap_num_clusters / block_sz;
8003 : :
8004 : : /* Create a normal blob and verify it is not an esnap clone. */
8005 : 12 : ut_spdk_blob_opts_init(&opts);
8006 : 12 : blob = ut_blob_create_and_open(bs, &opts);
8007 : 12 : CU_ASSERT(!spdk_blob_is_esnap_clone(blob));
8008 : 12 : ut_blob_close_and_delete(bs, blob);
8009 : :
8010 : : /* Create an esnap clone blob then verify it is an esnap clone and has the right size */
8011 : 12 : ut_spdk_blob_opts_init(&opts);
8012 : 12 : ut_esnap_opts_init(block_sz, esnap_num_blocks, __func__, NULL, &esnap_opts);
8013 : 12 : opts.esnap_id = &esnap_opts;
8014 : 12 : opts.esnap_id_len = sizeof(esnap_opts);
8015 : 12 : opts.num_clusters = esnap_num_clusters;
8016 : 12 : blob = ut_blob_create_and_open(bs, &opts);
8017 [ - + ]: 12 : SPDK_CU_ASSERT_FATAL(blob != NULL);
8018 [ - + ]: 12 : SPDK_CU_ASSERT_FATAL(spdk_blob_is_esnap_clone(blob));
8019 [ - + ]: 12 : SPDK_CU_ASSERT_FATAL(blob_is_esnap_clone(blob));
8020 [ - + ]: 12 : SPDK_CU_ASSERT_FATAL(!spdk_blob_is_clone(blob));
8021 : 12 : sz = spdk_blob_get_num_clusters(blob);
8022 : 12 : CU_ASSERT(sz == esnap_num_clusters);
8023 : 12 : ut_blob_close_and_delete(bs, blob);
8024 : :
8025 : : /* Create an esnap clone without the size and verify it can be grown */
8026 : 12 : ut_spdk_blob_opts_init(&opts);
8027 : 12 : ut_esnap_opts_init(block_sz, esnap_num_blocks, __func__, NULL, &esnap_opts);
8028 : 12 : opts.esnap_id = &esnap_opts;
8029 : 12 : opts.esnap_id_len = sizeof(esnap_opts);
8030 : 12 : blob = ut_blob_create_and_open(bs, &opts);
8031 [ - + ]: 12 : SPDK_CU_ASSERT_FATAL(spdk_blob_is_esnap_clone(blob));
8032 : 12 : sz = spdk_blob_get_num_clusters(blob);
8033 : 12 : CU_ASSERT(sz == 0);
8034 : 12 : spdk_blob_resize(blob, 1, blob_op_complete, NULL);
8035 : 12 : poll_threads();
8036 : 12 : CU_ASSERT(g_bserrno == 0);
8037 : 12 : sz = spdk_blob_get_num_clusters(blob);
8038 : 12 : CU_ASSERT(sz == 1);
8039 : 12 : spdk_blob_resize(blob, esnap_num_clusters, blob_op_complete, NULL);
8040 : 12 : poll_threads();
8041 : 12 : CU_ASSERT(g_bserrno == 0);
8042 : 12 : sz = spdk_blob_get_num_clusters(blob);
8043 : 12 : CU_ASSERT(sz == esnap_num_clusters);
8044 : 12 : spdk_blob_resize(blob, esnap_num_clusters + 1, blob_op_complete, NULL);
8045 : 12 : poll_threads();
8046 : 12 : CU_ASSERT(g_bserrno == 0);
8047 : 12 : sz = spdk_blob_get_num_clusters(blob);
8048 : 12 : CU_ASSERT(sz == esnap_num_clusters + 1);
8049 : :
8050 : : /* Reload the blobstore and be sure that the blob can be opened. */
8051 : 12 : blobid = spdk_blob_get_id(blob);
8052 : 12 : spdk_blob_close(blob, blob_op_complete, NULL);
8053 : 12 : poll_threads();
8054 : 12 : CU_ASSERT(g_bserrno == 0);
8055 : 12 : g_blob = NULL;
8056 : 12 : spdk_bs_opts_init(&bs_opts, sizeof(bs_opts));
8057 : 12 : bs_opts.esnap_bs_dev_create = ut_esnap_create;
8058 : 12 : ut_bs_reload(&bs, &bs_opts);
8059 : 12 : spdk_bs_open_blob(bs, blobid, blob_op_with_handle_complete, NULL);
8060 : 12 : poll_threads();
8061 : 12 : CU_ASSERT(g_bserrno == 0);
8062 : 12 : CU_ASSERT(g_blob != NULL);
8063 : 12 : blob = g_blob;
8064 [ - + ]: 12 : SPDK_CU_ASSERT_FATAL(spdk_blob_is_esnap_clone(blob));
8065 : 12 : sz = spdk_blob_get_num_clusters(blob);
8066 : 12 : CU_ASSERT(sz == esnap_num_clusters + 1);
8067 : :
8068 : : /* Reload the blobstore without esnap_bs_dev_create: should fail to open blob. */
8069 : 12 : spdk_blob_close(blob, blob_op_complete, NULL);
8070 : 12 : poll_threads();
8071 : 12 : CU_ASSERT(g_bserrno == 0);
8072 : 12 : g_blob = NULL;
8073 : 12 : spdk_bs_opts_init(&bs_opts, sizeof(bs_opts));
8074 : 12 : ut_bs_reload(&bs, &bs_opts);
8075 : 12 : spdk_bs_open_blob(bs, blobid, blob_op_with_handle_complete, NULL);
8076 : 12 : poll_threads();
8077 : 12 : CU_ASSERT(g_bserrno != 0);
8078 : 12 : CU_ASSERT(g_blob == NULL);
8079 : :
8080 : : /* Reload the blobstore with ctx set and verify it is passed to the esnap create callback */
8081 : 12 : bs_ctx_count = 0;
8082 : 12 : spdk_bs_opts_init(&bs_opts, sizeof(bs_opts));
8083 : 12 : bs_opts.esnap_bs_dev_create = ut_esnap_create_with_count;
8084 : 12 : bs_opts.esnap_ctx = &bs_ctx_count;
8085 : 12 : ut_bs_reload(&bs, &bs_opts);
8086 : : /* Loading the blobstore triggers the esnap to be loaded */
8087 : 12 : CU_ASSERT(bs_ctx_count == 1);
8088 : 12 : spdk_bs_open_blob(bs, blobid, blob_op_with_handle_complete, NULL);
8089 : 12 : poll_threads();
8090 : 12 : CU_ASSERT(g_bserrno == 0);
8091 : 12 : CU_ASSERT(g_blob != NULL);
8092 : : /* Opening the blob also triggers the esnap to be loaded */
8093 : 12 : CU_ASSERT(bs_ctx_count == 2);
8094 : 12 : blob = g_blob;
8095 [ - + ]: 12 : SPDK_CU_ASSERT_FATAL(spdk_blob_is_esnap_clone(blob));
8096 : 12 : sz = spdk_blob_get_num_clusters(blob);
8097 : 12 : CU_ASSERT(sz == esnap_num_clusters + 1);
8098 : 12 : spdk_blob_close(blob, blob_op_complete, NULL);
8099 : 12 : poll_threads();
8100 : 12 : CU_ASSERT(g_bserrno == 0);
8101 : 12 : g_blob = NULL;
8102 : : /* If open_opts.esnap_ctx is set it is passed to the esnap create callback */
8103 : 12 : blob_ctx_count = 0;
8104 : 12 : spdk_blob_open_opts_init(&open_opts, sizeof(open_opts));
8105 : 12 : open_opts.esnap_ctx = &blob_ctx_count;
8106 : 12 : spdk_bs_open_blob_ext(bs, blobid, &open_opts, blob_op_with_handle_complete, NULL);
8107 : 12 : poll_threads();
8108 : 12 : blob = g_blob;
8109 : 12 : CU_ASSERT(bs_ctx_count == 3);
8110 : 12 : CU_ASSERT(blob_ctx_count == 1);
8111 : 12 : spdk_blob_close(blob, blob_op_complete, NULL);
8112 : 12 : poll_threads();
8113 : 12 : CU_ASSERT(g_bserrno == 0);
8114 : 12 : g_blob = NULL;
8115 : 12 : }
8116 : :
8117 : : static void
8118 : 12 : blob_esnap_clone_reload(void)
8119 : 12 : {
8120 : 12 : struct spdk_blob_store *bs = g_bs;
8121 : 12 : struct spdk_bs_opts bs_opts;
8122 : 12 : struct ut_esnap_opts esnap_opts;
8123 : 12 : struct spdk_blob_opts opts;
8124 : : struct spdk_blob *eclone1, *snap1, *clone1;
8125 : 12 : uint32_t cluster_sz = spdk_bs_get_cluster_size(bs);
8126 : 12 : uint32_t block_sz = spdk_bs_get_io_unit_size(bs);
8127 : 12 : const uint32_t esnap_num_clusters = 4;
8128 [ - + ]: 12 : uint64_t esnap_num_blocks = cluster_sz * esnap_num_clusters / block_sz;
8129 : : spdk_blob_id eclone1_id, snap1_id, clone1_id;
8130 : : struct spdk_io_channel *bs_ch;
8131 [ - + ]: 12 : char buf[block_sz];
8132 : 12 : int bserr1, bserr2, bserr3, bserr4;
8133 : : struct spdk_bs_dev *dev;
8134 : :
8135 : : /* Create and open an esnap clone blob */
8136 : 12 : ut_spdk_blob_opts_init(&opts);
8137 : 12 : ut_esnap_opts_init(block_sz, esnap_num_blocks, __func__, NULL, &esnap_opts);
8138 : 12 : opts.esnap_id = &esnap_opts;
8139 : 12 : opts.esnap_id_len = sizeof(esnap_opts);
8140 : 12 : opts.num_clusters = esnap_num_clusters;
8141 : 12 : eclone1 = ut_blob_create_and_open(bs, &opts);
8142 : 12 : CU_ASSERT(eclone1 != NULL);
8143 : 12 : CU_ASSERT(spdk_blob_is_esnap_clone(eclone1));
8144 : 12 : eclone1_id = eclone1->id;
8145 : :
8146 : : /* Create and open a snapshot of eclone1 */
8147 : 12 : spdk_bs_create_snapshot(bs, eclone1_id, NULL, blob_op_with_id_complete, NULL);
8148 : 12 : poll_threads();
8149 : 12 : CU_ASSERT(g_blobid != SPDK_BLOBID_INVALID);
8150 : 12 : CU_ASSERT(g_bserrno == 0);
8151 : 12 : snap1_id = g_blobid;
8152 : 12 : spdk_bs_open_blob(bs, snap1_id, blob_op_with_handle_complete, NULL);
8153 : 12 : poll_threads();
8154 : 12 : CU_ASSERT(g_bserrno == 0);
8155 : 12 : CU_ASSERT(g_blob != NULL);
8156 : 12 : snap1 = g_blob;
8157 : :
8158 : : /* Create and open regular clone of snap1 */
8159 : 12 : spdk_bs_create_clone(bs, snap1_id, NULL, blob_op_with_id_complete, NULL);
8160 : 12 : poll_threads();
8161 : 12 : CU_ASSERT(g_blobid != SPDK_BLOBID_INVALID);
8162 [ - + ]: 12 : SPDK_CU_ASSERT_FATAL(g_bserrno == 0);
8163 : 12 : clone1_id = g_blobid;
8164 : 12 : spdk_bs_open_blob(bs, clone1_id, blob_op_with_handle_complete, NULL);
8165 : 12 : poll_threads();
8166 : 12 : CU_ASSERT(g_bserrno == 0);
8167 : 12 : CU_ASSERT(g_blob != NULL);
8168 : 12 : clone1 = g_blob;
8169 : :
8170 : : /* Close the blobs in preparation for reloading the blobstore */
8171 : 12 : spdk_blob_close(clone1, blob_op_complete, NULL);
8172 : 12 : poll_threads();
8173 : 12 : CU_ASSERT(g_bserrno == 0);
8174 : 12 : spdk_blob_close(snap1, blob_op_complete, NULL);
8175 : 12 : poll_threads();
8176 : 12 : CU_ASSERT(g_bserrno == 0);
8177 : 12 : spdk_blob_close(eclone1, blob_op_complete, NULL);
8178 : 12 : poll_threads();
8179 : 12 : CU_ASSERT(g_bserrno == 0);
8180 : 12 : g_blob = NULL;
8181 : :
8182 : : /* Reload the blobstore */
8183 : 12 : spdk_bs_opts_init(&bs_opts, sizeof(bs_opts));
8184 : 12 : bs_opts.esnap_bs_dev_create = ut_esnap_create;
8185 : 12 : ut_bs_reload(&bs, &bs_opts);
8186 : :
8187 : : /* Be sure each of the blobs can be opened */
8188 : 12 : spdk_bs_open_blob(bs, eclone1_id, blob_op_with_handle_complete, NULL);
8189 : 12 : poll_threads();
8190 : 12 : CU_ASSERT(g_bserrno == 0);
8191 : 12 : CU_ASSERT(g_blob != NULL);
8192 : 12 : eclone1 = g_blob;
8193 : 12 : spdk_bs_open_blob(bs, snap1_id, blob_op_with_handle_complete, NULL);
8194 : 12 : poll_threads();
8195 : 12 : CU_ASSERT(g_bserrno == 0);
8196 : 12 : CU_ASSERT(g_blob != NULL);
8197 : 12 : snap1 = g_blob;
8198 : 12 : spdk_bs_open_blob(bs, clone1_id, blob_op_with_handle_complete, NULL);
8199 : 12 : poll_threads();
8200 : 12 : CU_ASSERT(g_bserrno == 0);
8201 : 12 : CU_ASSERT(g_blob != NULL);
8202 : 12 : clone1 = g_blob;
8203 : :
8204 : : /* Perform some reads on each of them to cause channels to be allocated */
8205 : 12 : bs_ch = spdk_bs_alloc_io_channel(bs);
8206 : 12 : CU_ASSERT(bs_ch != NULL);
8207 : 12 : spdk_blob_io_read(eclone1, bs_ch, buf, 0, 1, bs_op_complete, NULL);
8208 : 12 : poll_threads();
8209 : 12 : CU_ASSERT(g_bserrno == 0);
8210 : 12 : spdk_blob_io_read(snap1, bs_ch, buf, 0, 1, bs_op_complete, NULL);
8211 : 12 : poll_threads();
8212 : 12 : CU_ASSERT(g_bserrno == 0);
8213 : 12 : spdk_blob_io_read(clone1, bs_ch, buf, 0, 1, bs_op_complete, NULL);
8214 : 12 : poll_threads();
8215 : 12 : CU_ASSERT(g_bserrno == 0);
8216 : :
8217 : : /*
8218 : : * Unload the blobstore in a way similar to how lvstore unloads it. This should exercise
8219 : : * the deferred unload path in spdk_bs_unload().
8220 : : */
8221 : 12 : bserr1 = 0xbad;
8222 : 12 : bserr2 = 0xbad;
8223 : 12 : bserr3 = 0xbad;
8224 : 12 : bserr4 = 0xbad;
8225 : 12 : spdk_blob_close(eclone1, blob_op_complete, &bserr1);
8226 : 12 : spdk_blob_close(snap1, blob_op_complete, &bserr2);
8227 : 12 : spdk_blob_close(clone1, blob_op_complete, &bserr3);
8228 : 12 : spdk_bs_unload(bs, blob_op_complete, &bserr4);
8229 : 12 : spdk_bs_free_io_channel(bs_ch);
8230 : 12 : poll_threads();
8231 : 12 : CU_ASSERT(bserr1 == 0);
8232 : 12 : CU_ASSERT(bserr2 == 0);
8233 : 12 : CU_ASSERT(bserr3 == 0);
8234 : 12 : CU_ASSERT(bserr4 == 0);
8235 : 12 : g_blob = NULL;
8236 : :
8237 : : /* Reload the blobstore */
8238 : 12 : spdk_bs_opts_init(&bs_opts, sizeof(bs_opts));
8239 : 12 : bs_opts.esnap_bs_dev_create = ut_esnap_create;
8240 : 12 : dev = init_dev();
8241 : 12 : spdk_bs_load(dev, &bs_opts, bs_op_with_handle_complete, NULL);
8242 : 12 : poll_threads();
8243 : 12 : CU_ASSERT(g_bserrno == 0);
8244 [ - + ]: 12 : SPDK_CU_ASSERT_FATAL(g_bs != NULL);
8245 : 12 : }
8246 : :
8247 : : static bool
8248 : 240 : blob_esnap_verify_contents(struct spdk_blob *blob, struct spdk_io_channel *ch,
8249 : : uint64_t offset, uint64_t size, uint32_t readsize, const char *how)
8250 : 240 : {
8251 : 240 : const uint32_t bs_blksz = blob->bs->io_unit_size;
8252 [ + + ]: 240 : const uint32_t esnap_blksz = blob->back_bs_dev ? blob->back_bs_dev->blocklen : bs_blksz;
8253 [ - + ]: 240 : const uint32_t start_blk = offset / bs_blksz;
8254 [ - + ]: 240 : const uint32_t num_blocks = spdk_max(size, readsize) / bs_blksz;
8255 [ - + ]: 240 : const uint32_t blocks_per_read = spdk_min(size, readsize) / bs_blksz;
8256 : : uint32_t blob_block;
8257 : 240 : struct iovec iov;
8258 [ - + ]: 240 : uint8_t buf[spdk_min(size, readsize)];
8259 : : bool block_ok;
8260 : :
8261 [ - + - + ]: 240 : SPDK_CU_ASSERT_FATAL(offset % bs_blksz == 0);
8262 [ - + - + ]: 240 : SPDK_CU_ASSERT_FATAL(size % bs_blksz == 0);
8263 [ - + - + ]: 240 : SPDK_CU_ASSERT_FATAL(readsize % bs_blksz == 0);
8264 : :
8265 [ - + ]: 240 : memset(buf, 0, readsize);
8266 : 240 : iov.iov_base = buf;
8267 : 240 : iov.iov_len = readsize;
8268 [ + + ]: 6132 : for (blob_block = start_blk; blob_block < num_blocks; blob_block += blocks_per_read) {
8269 [ + + + + ]: 5892 : if (strcmp(how, "read") == 0) {
8270 : 1980 : spdk_blob_io_read(blob, ch, buf, blob_block, blocks_per_read,
8271 : : bs_op_complete, NULL);
8272 [ + + + + ]: 3912 : } else if (strcmp(how, "readv") == 0) {
8273 : 1956 : spdk_blob_io_readv(blob, ch, &iov, 1, blob_block, blocks_per_read,
8274 : : bs_op_complete, NULL);
8275 [ + + + - ]: 1956 : } else if (strcmp(how, "readv_ext") == 0) {
8276 : : /*
8277 : : * This is currently pointless. NULL ext_opts leads to dev->readv(), not
8278 : : * dev->readv_ext().
8279 : : */
8280 : 1956 : spdk_blob_io_readv_ext(blob, ch, &iov, 1, blob_block, blocks_per_read,
8281 : : bs_op_complete, NULL, NULL);
8282 : : } else {
8283 : 0 : abort();
8284 : : }
8285 : 5892 : poll_threads();
8286 : 5892 : CU_ASSERT(g_bserrno == 0);
8287 [ - + ]: 5892 : if (g_bserrno != 0) {
8288 : 0 : return false;
8289 : : }
8290 : 5892 : block_ok = ut_esnap_content_is_correct(buf, blocks_per_read * bs_blksz, blob->id,
8291 : : blob_block * bs_blksz, esnap_blksz);
8292 : 5892 : CU_ASSERT(block_ok);
8293 [ - + ]: 5892 : if (!block_ok) {
8294 : 0 : return false;
8295 : : }
8296 : : }
8297 : :
8298 : 240 : return true;
8299 : : }
8300 : :
8301 : : static void
8302 : 36 : blob_esnap_io_size(uint32_t bs_blksz, uint32_t esnap_blksz)
8303 : : {
8304 : : struct spdk_bs_dev *dev;
8305 : : struct spdk_blob_store *bs;
8306 : 36 : struct spdk_bs_opts bsopts;
8307 : 36 : struct spdk_blob_opts opts;
8308 : 36 : struct ut_esnap_opts esnap_opts;
8309 : : struct spdk_blob *blob;
8310 : 36 : const uint32_t cluster_sz = 16 * 1024;
8311 : 36 : const uint64_t esnap_num_clusters = 4;
8312 : 36 : const uint32_t esnap_sz = cluster_sz * esnap_num_clusters;
8313 [ - + ]: 36 : const uint64_t esnap_num_blocks = esnap_sz / esnap_blksz;
8314 [ - + ]: 36 : const uint64_t blob_num_blocks = esnap_sz / bs_blksz;
8315 : : uint32_t block;
8316 : : struct spdk_io_channel *bs_ch;
8317 : :
8318 : 36 : spdk_bs_opts_init(&bsopts, sizeof(bsopts));
8319 : 36 : bsopts.cluster_sz = cluster_sz;
8320 : 36 : bsopts.esnap_bs_dev_create = ut_esnap_create;
8321 : :
8322 : : /* Create device with desired block size */
8323 : 36 : dev = init_dev();
8324 : 36 : dev->blocklen = bs_blksz;
8325 [ - + ]: 36 : dev->blockcnt = DEV_BUFFER_SIZE / dev->blocklen;
8326 : :
8327 : : /* Initialize a new blob store */
8328 : 36 : spdk_bs_init(dev, &bsopts, bs_op_with_handle_complete, NULL);
8329 : 36 : poll_threads();
8330 : 36 : CU_ASSERT(g_bserrno == 0);
8331 [ - + ]: 36 : SPDK_CU_ASSERT_FATAL(g_bs != NULL);
8332 [ - + ]: 36 : SPDK_CU_ASSERT_FATAL(g_bs->io_unit_size == bs_blksz);
8333 : 36 : bs = g_bs;
8334 : :
8335 : 36 : bs_ch = spdk_bs_alloc_io_channel(bs);
8336 [ - + ]: 36 : SPDK_CU_ASSERT_FATAL(bs_ch != NULL);
8337 : :
8338 : : /* Create and open the esnap clone */
8339 : 36 : ut_spdk_blob_opts_init(&opts);
8340 : 36 : ut_esnap_opts_init(esnap_blksz, esnap_num_blocks, __func__, NULL, &esnap_opts);
8341 : 36 : opts.esnap_id = &esnap_opts;
8342 : 36 : opts.esnap_id_len = sizeof(esnap_opts);
8343 : 36 : opts.num_clusters = esnap_num_clusters;
8344 : 36 : blob = ut_blob_create_and_open(bs, &opts);
8345 [ - + ]: 36 : SPDK_CU_ASSERT_FATAL(blob != NULL);
8346 : :
8347 : : /* Verify that large reads return the content of the esnap device */
8348 : 36 : CU_ASSERT(blob_esnap_verify_contents(blob, bs_ch, 0, esnap_sz, esnap_sz, "read"));
8349 : 36 : CU_ASSERT(blob_esnap_verify_contents(blob, bs_ch, 0, esnap_sz, esnap_sz, "readv"));
8350 : 36 : CU_ASSERT(blob_esnap_verify_contents(blob, bs_ch, 0, esnap_sz, esnap_sz, "readv_ext"));
8351 : : /* Verify that small reads return the content of the esnap device */
8352 : 36 : CU_ASSERT(blob_esnap_verify_contents(blob, bs_ch, 0, esnap_sz, bs_blksz, "read"));
8353 : 36 : CU_ASSERT(blob_esnap_verify_contents(blob, bs_ch, 0, esnap_sz, bs_blksz, "readv"));
8354 : 36 : CU_ASSERT(blob_esnap_verify_contents(blob, bs_ch, 0, esnap_sz, bs_blksz, "readv_ext"));
8355 : :
8356 : : /* Write one blob block at a time; verify that the surrounding blocks are OK */
8357 [ + + ]: 1956 : for (block = 0; block < blob_num_blocks; block++) {
8358 [ - + ]: 1920 : char buf[bs_blksz];
8359 : : union ut_word word;
8360 : :
8361 : 1920 : word.f.blob_id = 0xfedcba90;
8362 : 1920 : word.f.lba = block;
8363 : 1920 : ut_memset8(buf, word.num, bs_blksz);
8364 : :
8365 : 1920 : spdk_blob_io_write(blob, bs_ch, buf, block, 1, bs_op_complete, NULL);
8366 : 1920 : poll_threads();
8367 : 1920 : CU_ASSERT(g_bserrno == 0);
8368 [ - + ]: 1920 : if (g_bserrno != 0) {
8369 : 0 : break;
8370 : : }
8371 : :
8372 : : /* Read and verify the block before the current block */
8373 [ + + ]: 1920 : if (block != 0) {
8374 : 1884 : spdk_blob_io_read(blob, bs_ch, buf, block - 1, 1, bs_op_complete, NULL);
8375 : 1884 : poll_threads();
8376 : 1884 : CU_ASSERT(g_bserrno == 0);
8377 [ - + ]: 1884 : if (g_bserrno != 0) {
8378 : 0 : break;
8379 : : }
8380 : 1884 : CU_ASSERT(ut_esnap_content_is_correct(buf, bs_blksz, word.f.blob_id,
8381 : : (block - 1) * bs_blksz, bs_blksz));
8382 : : }
8383 : :
8384 : : /* Read and verify the current block */
8385 : 1920 : spdk_blob_io_read(blob, bs_ch, buf, block, 1, bs_op_complete, NULL);
8386 : 1920 : poll_threads();
8387 : 1920 : CU_ASSERT(g_bserrno == 0);
8388 [ - + ]: 1920 : if (g_bserrno != 0) {
8389 : 0 : break;
8390 : : }
8391 : 1920 : CU_ASSERT(ut_esnap_content_is_correct(buf, bs_blksz, word.f.blob_id,
8392 : : block * bs_blksz, bs_blksz));
8393 : :
8394 : : /* Check the block that follows */
8395 [ + + ]: 1920 : if (block + 1 < blob_num_blocks) {
8396 : 1884 : g_bserrno = 0xbad;
8397 : 1884 : spdk_blob_io_read(blob, bs_ch, buf, block + 1, 1, bs_op_complete, NULL);
8398 : 1884 : poll_threads();
8399 : 1884 : CU_ASSERT(g_bserrno == 0);
8400 [ - + ]: 1884 : if (g_bserrno != 0) {
8401 : 0 : break;
8402 : : }
8403 : 1884 : CU_ASSERT(ut_esnap_content_is_correct(buf, bs_blksz, blob->id,
8404 : : (block + 1) * bs_blksz,
8405 : : esnap_blksz));
8406 : : }
8407 : : }
8408 : :
8409 : : /* Clean up */
8410 : 36 : spdk_bs_free_io_channel(bs_ch);
8411 : 36 : g_bserrno = 0xbad;
8412 : 36 : spdk_blob_close(blob, blob_op_complete, NULL);
8413 : 36 : poll_threads();
8414 : 36 : CU_ASSERT(g_bserrno == 0);
8415 : 36 : spdk_bs_unload(g_bs, bs_op_complete, NULL);
8416 : 36 : poll_threads();
8417 : 36 : CU_ASSERT(g_bserrno == 0);
8418 : 36 : g_bs = NULL;
8419 [ - + ]: 36 : memset(g_dev_buffer, 0, DEV_BUFFER_SIZE);
8420 : 36 : }
8421 : :
8422 : : static void
8423 : 12 : blob_esnap_io_4096_4096(void)
8424 : : {
8425 : 12 : blob_esnap_io_size(4096, 4096);
8426 : 12 : }
8427 : :
8428 : : static void
8429 : 12 : blob_esnap_io_512_512(void)
8430 : : {
8431 : 12 : blob_esnap_io_size(512, 512);
8432 : 12 : }
8433 : :
8434 : : static void
8435 : 12 : blob_esnap_io_4096_512(void)
8436 : : {
8437 : 12 : blob_esnap_io_size(4096, 512);
8438 : 12 : }
8439 : :
8440 : : static void
8441 : 12 : blob_esnap_io_512_4096(void)
8442 : : {
8443 : : struct spdk_bs_dev *dev;
8444 : : struct spdk_blob_store *bs;
8445 : 12 : struct spdk_bs_opts bs_opts;
8446 : 12 : struct spdk_blob_opts blob_opts;
8447 : 12 : struct ut_esnap_opts esnap_opts;
8448 : 12 : uint64_t cluster_sz = 16 * 1024;
8449 : 12 : uint32_t bs_blksz = 512;
8450 : 12 : uint32_t esnap_blksz = 4096;
8451 : 12 : uint64_t esnap_num_blocks = 64;
8452 : : spdk_blob_id blobid;
8453 : :
8454 : : /* Create device with desired block size */
8455 : 12 : dev = init_dev();
8456 : 12 : dev->blocklen = bs_blksz;
8457 [ - + ]: 12 : dev->blockcnt = DEV_BUFFER_SIZE / dev->blocklen;
8458 : :
8459 : : /* Initialize a new blob store */
8460 : 12 : spdk_bs_opts_init(&bs_opts, sizeof(bs_opts));
8461 : 12 : bs_opts.cluster_sz = cluster_sz;
8462 : 12 : bs_opts.esnap_bs_dev_create = ut_esnap_create;
8463 : 12 : spdk_bs_init(dev, &bs_opts, bs_op_with_handle_complete, NULL);
8464 : 12 : poll_threads();
8465 : 12 : CU_ASSERT(g_bserrno == 0);
8466 [ - + ]: 12 : SPDK_CU_ASSERT_FATAL(g_bs != NULL);
8467 [ - + ]: 12 : SPDK_CU_ASSERT_FATAL(g_bs->io_unit_size == bs_blksz);
8468 : 12 : bs = g_bs;
8469 : :
8470 : : /* Try to create and open the esnap clone. Create should succeed, open should fail. */
8471 : 12 : ut_spdk_blob_opts_init(&blob_opts);
8472 : 12 : ut_esnap_opts_init(esnap_blksz, esnap_num_blocks, __func__, NULL, &esnap_opts);
8473 : 12 : blob_opts.esnap_id = &esnap_opts;
8474 : 12 : blob_opts.esnap_id_len = sizeof(esnap_opts);
8475 [ - + ]: 12 : blob_opts.num_clusters = esnap_num_blocks * esnap_blksz / bs_blksz;
8476 : 12 : spdk_bs_create_blob_ext(bs, &blob_opts, blob_op_with_id_complete, NULL);
8477 : 12 : poll_threads();
8478 : 12 : CU_ASSERT(g_bserrno == 0);
8479 : 12 : CU_ASSERT(g_blobid != SPDK_BLOBID_INVALID);
8480 : 12 : blobid = g_blobid;
8481 : 12 : spdk_bs_open_blob(bs, blobid, blob_op_with_handle_complete, NULL);
8482 : 12 : poll_threads();
8483 : 12 : CU_ASSERT(g_bserrno == -EINVAL);
8484 : 12 : CU_ASSERT(g_blob == NULL);
8485 : :
8486 : : /* Clean up */
8487 : 12 : spdk_bs_unload(bs, bs_op_complete, NULL);
8488 : 12 : poll_threads();
8489 : 12 : CU_ASSERT(g_bserrno == 0);
8490 : 12 : g_bs = NULL;
8491 [ - + ]: 12 : memset(g_dev_buffer, 0, DEV_BUFFER_SIZE);
8492 : 12 : }
8493 : :
8494 : : static void
8495 : 12 : blob_esnap_thread_add_remove(void)
8496 : 12 : {
8497 : 12 : struct spdk_blob_store *bs = g_bs;
8498 : 12 : struct spdk_blob_opts opts;
8499 : 12 : struct ut_esnap_opts ut_esnap_opts;
8500 : : struct spdk_blob *blob;
8501 : : struct ut_esnap_dev *ut_dev;
8502 : : spdk_blob_id blobid;
8503 : 12 : uint64_t start_thread = g_ut_thread_id;
8504 : 12 : bool destroyed = false;
8505 : : struct spdk_io_channel *ch0, *ch1;
8506 : : struct ut_esnap_channel *ut_ch0, *ut_ch1;
8507 : 12 : const uint32_t blocklen = bs->io_unit_size;
8508 [ - + ]: 12 : char buf[blocklen * 4];
8509 : :
8510 [ - + ]: 12 : SPDK_CU_ASSERT_FATAL(g_ut_num_threads > 1);
8511 : 12 : set_thread(0);
8512 : :
8513 : : /* Create the esnap clone */
8514 : 12 : ut_esnap_opts_init(blocklen, 2048, "add_remove_1", &destroyed, &ut_esnap_opts);
8515 : 12 : ut_spdk_blob_opts_init(&opts);
8516 : 12 : opts.esnap_id = &ut_esnap_opts;
8517 : 12 : opts.esnap_id_len = sizeof(ut_esnap_opts);
8518 : 12 : opts.num_clusters = 10;
8519 : 12 : spdk_bs_create_blob_ext(bs, &opts, blob_op_with_id_complete, NULL);
8520 : 12 : poll_threads();
8521 : 12 : CU_ASSERT(g_bserrno == 0);
8522 : 12 : CU_ASSERT(g_blobid != SPDK_BLOBID_INVALID);
8523 : 12 : blobid = g_blobid;
8524 : :
8525 : : /* Open the blob. No channels should be allocated yet. */
8526 : 12 : spdk_bs_open_blob(bs, blobid, blob_op_with_handle_complete, NULL);
8527 : 12 : poll_threads();
8528 : 12 : CU_ASSERT(g_bserrno == 0);
8529 : 12 : CU_ASSERT(g_blob != NULL);
8530 : 12 : blob = g_blob;
8531 : 12 : ut_dev = (struct ut_esnap_dev *)blob->back_bs_dev;
8532 : 12 : CU_ASSERT(ut_dev != NULL);
8533 : 12 : CU_ASSERT(ut_dev->num_channels == 0);
8534 : :
8535 : : /* Create a channel on thread 0. It is lazily created on the first read. */
8536 : 12 : ch0 = spdk_bs_alloc_io_channel(bs);
8537 : 12 : CU_ASSERT(ch0 != NULL);
8538 : 12 : ut_ch0 = ut_esnap_get_io_channel(ch0, blobid);
8539 : 12 : CU_ASSERT(ut_ch0 == NULL);
8540 : 12 : CU_ASSERT(ut_dev->num_channels == 0);
8541 : 12 : spdk_blob_io_read(blob, ch0, buf, 0, 1, bs_op_complete, NULL);
8542 : 12 : poll_threads();
8543 : 12 : CU_ASSERT(g_bserrno == 0);
8544 : 12 : CU_ASSERT(ut_dev->num_channels == 1);
8545 : 12 : ut_ch0 = ut_esnap_get_io_channel(ch0, blobid);
8546 : 12 : CU_ASSERT(ut_ch0 != NULL);
8547 : 12 : CU_ASSERT(ut_ch0->blocks_read == 1);
8548 : :
8549 : : /* Create a channel on thread 1 and verify its lazy creation too. */
8550 : 12 : set_thread(1);
8551 : 12 : ch1 = spdk_bs_alloc_io_channel(bs);
8552 : 12 : CU_ASSERT(ch1 != NULL);
8553 : 12 : ut_ch1 = ut_esnap_get_io_channel(ch1, blobid);
8554 : 12 : CU_ASSERT(ut_ch1 == NULL);
8555 : 12 : CU_ASSERT(ut_dev->num_channels == 1);
8556 : 12 : spdk_blob_io_read(blob, ch1, buf, 0, 4, bs_op_complete, NULL);
8557 : 12 : poll_threads();
8558 : 12 : CU_ASSERT(g_bserrno == 0);
8559 : 12 : CU_ASSERT(ut_dev->num_channels == 2);
8560 : 12 : ut_ch1 = ut_esnap_get_io_channel(ch1, blobid);
8561 : 12 : CU_ASSERT(ut_ch1 != NULL);
8562 : 12 : CU_ASSERT(ut_ch1->blocks_read == 4);
8563 : :
8564 : : /* Close the channel on thread 0 and verify the bs_dev channel is also gone. */
8565 : 12 : set_thread(0);
8566 : 12 : spdk_bs_free_io_channel(ch0);
8567 : 12 : poll_threads();
8568 : 12 : CU_ASSERT(ut_dev->num_channels == 1);
8569 : :
8570 : : /* Close the blob. There is no outstanding IO so it should close right away. */
8571 : 12 : g_bserrno = 0xbad;
8572 : 12 : spdk_blob_close(blob, blob_op_complete, NULL);
8573 : 12 : poll_threads();
8574 : 12 : CU_ASSERT(g_bserrno == 0);
8575 [ - + ]: 12 : CU_ASSERT(destroyed);
8576 : :
8577 : : /* The esnap channel for the blob should be gone now too. */
8578 : 12 : ut_ch1 = ut_esnap_get_io_channel(ch1, blobid);
8579 : 12 : CU_ASSERT(ut_ch1 == NULL);
8580 : :
8581 : : /* Clean up */
8582 : 12 : set_thread(1);
8583 : 12 : spdk_bs_free_io_channel(ch1);
8584 : 12 : set_thread(start_thread);
8585 : 12 : }
8586 : :
8587 : : static void
8588 : 36 : freeze_done(void *cb_arg, int bserrno)
8589 : : {
8590 : 36 : uint32_t *freeze_cnt = cb_arg;
8591 : :
8592 : 36 : CU_ASSERT(bserrno == 0);
8593 : 36 : (*freeze_cnt)++;
8594 : 36 : }
8595 : :
8596 : : static void
8597 : 36 : unfreeze_done(void *cb_arg, int bserrno)
8598 : : {
8599 : 36 : uint32_t *unfreeze_cnt = cb_arg;
8600 : :
8601 : 36 : CU_ASSERT(bserrno == 0);
8602 : 36 : (*unfreeze_cnt)++;
8603 : 36 : }
8604 : :
8605 : : static void
8606 : 12 : blob_nested_freezes(void)
8607 : : {
8608 : 12 : struct spdk_blob_store *bs = g_bs;
8609 : : struct spdk_blob *blob;
8610 : 12 : struct spdk_io_channel *channel[2];
8611 : 12 : struct spdk_blob_opts opts;
8612 : 12 : uint32_t freeze_cnt, unfreeze_cnt;
8613 : : int i;
8614 : :
8615 [ + + ]: 36 : for (i = 0; i < 2; i++) {
8616 : 24 : set_thread(i);
8617 : 24 : channel[i] = spdk_bs_alloc_io_channel(bs);
8618 [ - + ]: 24 : SPDK_CU_ASSERT_FATAL(channel[i] != NULL);
8619 : : }
8620 : :
8621 : 12 : set_thread(0);
8622 : :
8623 : 12 : ut_spdk_blob_opts_init(&opts);
8624 : 12 : blob = ut_blob_create_and_open(bs, &opts);
8625 : :
8626 : : /* First just test a single freeze/unfreeze. */
8627 : 12 : freeze_cnt = 0;
8628 : 12 : unfreeze_cnt = 0;
8629 : 12 : CU_ASSERT(blob->frozen_refcnt == 0);
8630 : 12 : blob_freeze_io(blob, freeze_done, &freeze_cnt);
8631 : 12 : CU_ASSERT(blob->frozen_refcnt == 1);
8632 : 12 : CU_ASSERT(freeze_cnt == 0);
8633 : 12 : poll_threads();
8634 : 12 : CU_ASSERT(freeze_cnt == 1);
8635 : 12 : blob_unfreeze_io(blob, unfreeze_done, &unfreeze_cnt);
8636 : 12 : CU_ASSERT(blob->frozen_refcnt == 0);
8637 : 12 : CU_ASSERT(unfreeze_cnt == 0);
8638 : 12 : poll_threads();
8639 : 12 : CU_ASSERT(unfreeze_cnt == 1);
8640 : :
8641 : : /* Now nest multiple freeze/unfreeze operations. We should
8642 : : * expect a callback for each operation, but only after
8643 : : * the threads have been polled to ensure a for_each_channel()
8644 : : * was executed.
8645 : : */
8646 : 12 : freeze_cnt = 0;
8647 : 12 : unfreeze_cnt = 0;
8648 : 12 : CU_ASSERT(blob->frozen_refcnt == 0);
8649 : 12 : blob_freeze_io(blob, freeze_done, &freeze_cnt);
8650 : 12 : CU_ASSERT(blob->frozen_refcnt == 1);
8651 : 12 : CU_ASSERT(freeze_cnt == 0);
8652 : 12 : blob_freeze_io(blob, freeze_done, &freeze_cnt);
8653 : 12 : CU_ASSERT(blob->frozen_refcnt == 2);
8654 : 12 : CU_ASSERT(freeze_cnt == 0);
8655 : 12 : poll_threads();
8656 : 12 : CU_ASSERT(freeze_cnt == 2);
8657 : 12 : blob_unfreeze_io(blob, unfreeze_done, &unfreeze_cnt);
8658 : 12 : CU_ASSERT(blob->frozen_refcnt == 1);
8659 : 12 : CU_ASSERT(unfreeze_cnt == 0);
8660 : 12 : blob_unfreeze_io(blob, unfreeze_done, &unfreeze_cnt);
8661 : 12 : CU_ASSERT(blob->frozen_refcnt == 0);
8662 : 12 : CU_ASSERT(unfreeze_cnt == 0);
8663 : 12 : poll_threads();
8664 : 12 : CU_ASSERT(unfreeze_cnt == 2);
8665 : :
8666 [ + + ]: 36 : for (i = 0; i < 2; i++) {
8667 : 24 : set_thread(i);
8668 : 24 : spdk_bs_free_io_channel(channel[i]);
8669 : : }
8670 : 12 : set_thread(0);
8671 : 12 : ut_blob_close_and_delete(bs, blob);
8672 : :
8673 : 12 : poll_threads();
8674 : 12 : g_blob = NULL;
8675 : 12 : g_blobid = 0;
8676 : 12 : }
8677 : :
8678 : : static void
8679 : 12 : blob_ext_md_pages(void)
8680 : : {
8681 : : struct spdk_blob_store *bs;
8682 : : struct spdk_bs_dev *dev;
8683 : : struct spdk_blob *blob;
8684 : 12 : struct spdk_blob_opts opts;
8685 : 12 : struct spdk_bs_opts bs_opts;
8686 : : uint64_t free_clusters;
8687 : :
8688 : 12 : dev = init_dev();
8689 : 12 : spdk_bs_opts_init(&bs_opts, sizeof(bs_opts));
8690 : 12 : snprintf(bs_opts.bstype.bstype, sizeof(bs_opts.bstype.bstype), "TESTTYPE");
8691 : : /* Issue #2932 was a bug in how we use bs_allocate_cluster() during resize.
8692 : : * It requires num_md_pages that is much smaller than the number of clusters.
8693 : : * Make sure we can create a blob that uses all of the free clusters.
8694 : : */
8695 : 12 : bs_opts.cluster_sz = 65536;
8696 : 12 : bs_opts.num_md_pages = 16;
8697 : :
8698 : : /* Initialize a new blob store */
8699 : 12 : spdk_bs_init(dev, &bs_opts, bs_op_with_handle_complete, NULL);
8700 : 12 : poll_threads();
8701 : 12 : CU_ASSERT(g_bserrno == 0);
8702 [ - + ]: 12 : SPDK_CU_ASSERT_FATAL(g_bs != NULL);
8703 : 12 : bs = g_bs;
8704 : :
8705 : 12 : free_clusters = spdk_bs_free_cluster_count(bs);
8706 : :
8707 : 12 : ut_spdk_blob_opts_init(&opts);
8708 : 12 : opts.num_clusters = free_clusters;
8709 : :
8710 : 12 : blob = ut_blob_create_and_open(bs, &opts);
8711 : 12 : spdk_blob_close(blob, blob_op_complete, NULL);
8712 : 12 : CU_ASSERT(g_bserrno == 0);
8713 : :
8714 : 12 : spdk_bs_unload(bs, bs_op_complete, NULL);
8715 : 12 : poll_threads();
8716 : 12 : CU_ASSERT(g_bserrno == 0);
8717 : 12 : g_bs = NULL;
8718 : 12 : }
8719 : :
8720 : : static void
8721 : 12 : blob_esnap_clone_snapshot(void)
8722 : : {
8723 : : /*
8724 : : * When a snapshot is created, the blob that is being snapped becomes
8725 : : * the leaf node (a clone of the snapshot) and the newly created
8726 : : * snapshot sits between the snapped blob and the external snapshot.
8727 : : *
8728 : : * Before creating snap1
8729 : : *
8730 : : * ,--------. ,----------.
8731 : : * | blob | | vbdev |
8732 : : * | blob1 |<----| nvme1n42 |
8733 : : * | (rw) | | (ro) |
8734 : : * `--------' `----------'
8735 : : * Figure 1
8736 : : *
8737 : : * After creating snap1
8738 : : *
8739 : : * ,--------. ,--------. ,----------.
8740 : : * | blob | | blob | | vbdev |
8741 : : * | blob1 |<----| snap1 |<----| nvme1n42 |
8742 : : * | (rw) | | (ro) | | (ro) |
8743 : : * `--------' `--------' `----------'
8744 : : * Figure 2
8745 : : *
8746 : : * Starting from Figure 2, if snap1 is removed, the chain reverts to
8747 : : * what it looks like in Figure 1.
8748 : : *
8749 : : * Starting from Figure 2, if blob1 is removed, the chain becomes:
8750 : : *
8751 : : * ,--------. ,----------.
8752 : : * | blob | | vbdev |
8753 : : * | snap1 |<----| nvme1n42 |
8754 : : * | (ro) | | (ro) |
8755 : : * `--------' `----------'
8756 : : * Figure 3
8757 : : *
8758 : : * In each case, the blob pointed to by the nvme vbdev is considered
8759 : : * the "esnap clone". The esnap clone must have:
8760 : : *
8761 : : * - XATTR_INTERNAL for BLOB_EXTERNAL_SNAPSHOT_ID (e.g. name or UUID)
8762 : : * - blob->invalid_flags must contain SPDK_BLOB_EXTERNAL_SNAPSHOT
8763 : : * - blob->parent_id must be SPDK_BLOBID_EXTERNAL_SNAPSHOT.
8764 : : *
8765 : : * No other blob that descends from the esnap clone may have any of
8766 : : * those set.
8767 : : */
8768 : 12 : struct spdk_blob_store *bs = g_bs;
8769 : 12 : const uint32_t blocklen = bs->io_unit_size;
8770 : 12 : struct spdk_blob_opts opts;
8771 : 12 : struct ut_esnap_opts esnap_opts;
8772 : : struct spdk_blob *blob, *snap_blob;
8773 : : spdk_blob_id blobid, snap_blobid;
8774 : 12 : bool destroyed = false;
8775 : :
8776 : : /* Create the esnap clone */
8777 : 12 : ut_esnap_opts_init(blocklen, 2048, __func__, &destroyed, &esnap_opts);
8778 : 12 : ut_spdk_blob_opts_init(&opts);
8779 : 12 : opts.esnap_id = &esnap_opts;
8780 : 12 : opts.esnap_id_len = sizeof(esnap_opts);
8781 : 12 : opts.num_clusters = 10;
8782 : 12 : spdk_bs_create_blob_ext(bs, &opts, blob_op_with_id_complete, NULL);
8783 : 12 : poll_threads();
8784 : 12 : CU_ASSERT(g_bserrno == 0);
8785 : 12 : CU_ASSERT(g_blobid != SPDK_BLOBID_INVALID);
8786 : 12 : blobid = g_blobid;
8787 : :
8788 : : /* Open the blob. */
8789 : 12 : spdk_bs_open_blob(bs, blobid, blob_op_with_handle_complete, NULL);
8790 : 12 : poll_threads();
8791 : 12 : CU_ASSERT(g_bserrno == 0);
8792 : 12 : CU_ASSERT(g_blob != NULL);
8793 : 12 : blob = g_blob;
8794 : 12 : UT_ASSERT_IS_ESNAP_CLONE(blob, &esnap_opts, sizeof(esnap_opts));
8795 : :
8796 : : /*
8797 : : * Create a snapshot of the blob. The snapshot becomes the esnap clone.
8798 : : */
8799 : 12 : spdk_bs_create_snapshot(bs, blobid, NULL, blob_op_with_id_complete, NULL);
8800 : 12 : poll_threads();
8801 : 12 : CU_ASSERT(g_bserrno == 0);
8802 : 12 : CU_ASSERT(g_blobid != SPDK_BLOBID_INVALID);
8803 : 12 : snap_blobid = g_blobid;
8804 : :
8805 : 12 : spdk_bs_open_blob(bs, snap_blobid, blob_op_with_handle_complete, NULL);
8806 : 12 : poll_threads();
8807 : 12 : CU_ASSERT(g_bserrno == 0);
8808 [ - + ]: 12 : SPDK_CU_ASSERT_FATAL(g_blob != NULL);
8809 : 12 : snap_blob = g_blob;
8810 : :
8811 : 12 : UT_ASSERT_IS_NOT_ESNAP_CLONE(blob);
8812 : 12 : UT_ASSERT_IS_ESNAP_CLONE(snap_blob, &esnap_opts, sizeof(esnap_opts));
8813 : :
8814 : : /*
8815 : : * Delete the snapshot. The original blob becomes the esnap clone.
8816 : : */
8817 : 12 : ut_blob_close_and_delete(bs, snap_blob);
8818 : 12 : snap_blob = NULL;
8819 : 12 : snap_blobid = SPDK_BLOBID_INVALID;
8820 : 12 : UT_ASSERT_IS_ESNAP_CLONE(blob, &esnap_opts, sizeof(esnap_opts));
8821 : :
8822 : : /*
8823 : : * Create the snapshot again, then delete the original blob. The
8824 : : * snapshot should survive as the esnap clone.
8825 : : */
8826 : 12 : spdk_bs_create_snapshot(bs, blobid, NULL, blob_op_with_id_complete, NULL);
8827 : 12 : poll_threads();
8828 : 12 : CU_ASSERT(g_bserrno == 0);
8829 : 12 : CU_ASSERT(g_blobid != SPDK_BLOBID_INVALID);
8830 : 12 : snap_blobid = g_blobid;
8831 : :
8832 : 12 : spdk_bs_open_blob(bs, snap_blobid, blob_op_with_handle_complete, NULL);
8833 : 12 : poll_threads();
8834 : 12 : CU_ASSERT(g_bserrno == 0);
8835 [ - + ]: 12 : SPDK_CU_ASSERT_FATAL(g_blob != NULL);
8836 : 12 : snap_blob = g_blob;
8837 : :
8838 : 12 : UT_ASSERT_IS_NOT_ESNAP_CLONE(blob);
8839 : 12 : UT_ASSERT_IS_ESNAP_CLONE(snap_blob, &esnap_opts, sizeof(esnap_opts));
8840 : :
8841 : 12 : ut_blob_close_and_delete(bs, blob);
8842 : 12 : blob = NULL;
8843 : 12 : blobid = SPDK_BLOBID_INVALID;
8844 : 12 : UT_ASSERT_IS_ESNAP_CLONE(snap_blob, &esnap_opts, sizeof(esnap_opts));
8845 : :
8846 : : /*
8847 : : * Clone the snapshot. The snapshot continues to be the esnap clone.
8848 : : */
8849 : 12 : spdk_bs_create_clone(bs, snap_blobid, NULL, blob_op_with_id_complete, NULL);
8850 : 12 : poll_threads();
8851 : 12 : CU_ASSERT(g_bserrno == 0);
8852 : 12 : CU_ASSERT(g_blobid != SPDK_BLOBID_INVALID);
8853 : 12 : blobid = g_blobid;
8854 : :
8855 : 12 : spdk_bs_open_blob(bs, blobid, blob_op_with_handle_complete, NULL);
8856 : 12 : poll_threads();
8857 : 12 : CU_ASSERT(g_bserrno == 0);
8858 [ - + ]: 12 : SPDK_CU_ASSERT_FATAL(g_blob != NULL);
8859 : 12 : blob = g_blob;
8860 : :
8861 : 12 : UT_ASSERT_IS_NOT_ESNAP_CLONE(blob);
8862 : 12 : UT_ASSERT_IS_ESNAP_CLONE(snap_blob, &esnap_opts, sizeof(esnap_opts));
8863 : :
8864 : : /*
8865 : : * Delete the snapshot. The clone becomes the esnap clone.
8866 : : */
8867 : 12 : ut_blob_close_and_delete(bs, snap_blob);
8868 : 12 : snap_blob = NULL;
8869 : 12 : snap_blobid = SPDK_BLOBID_INVALID;
8870 : 12 : UT_ASSERT_IS_ESNAP_CLONE(blob, &esnap_opts, sizeof(esnap_opts));
8871 : :
8872 : : /*
8873 : : * Clean up
8874 : : */
8875 : 12 : ut_blob_close_and_delete(bs, blob);
8876 : 12 : }
8877 : :
8878 : : static uint64_t
8879 : 24 : _blob_esnap_clone_hydrate(bool inflate)
8880 : : {
8881 : 24 : struct spdk_blob_store *bs = g_bs;
8882 : 24 : struct spdk_blob_opts opts;
8883 : 24 : struct ut_esnap_opts esnap_opts;
8884 : : struct spdk_blob *blob;
8885 : : spdk_blob_id blobid;
8886 : : struct spdk_io_channel *channel;
8887 : 24 : bool destroyed = false;
8888 : 24 : const uint32_t blocklen = spdk_bs_get_io_unit_size(bs);
8889 : 24 : const uint32_t cluster_sz = spdk_bs_get_cluster_size(bs);
8890 : 24 : const uint64_t esnap_num_clusters = 4;
8891 : 24 : const uint32_t esnap_sz = cluster_sz * esnap_num_clusters;
8892 [ - + ]: 24 : const uint64_t esnap_num_blocks = esnap_sz / blocklen;
8893 : 24 : uint64_t num_failures = CU_get_number_of_failures();
8894 : :
8895 : 24 : channel = spdk_bs_alloc_io_channel(bs);
8896 [ - + ]: 24 : SPDK_CU_ASSERT_FATAL(channel != NULL);
8897 : :
8898 : : /* Create the esnap clone */
8899 : 24 : ut_spdk_blob_opts_init(&opts);
8900 : 24 : ut_esnap_opts_init(blocklen, esnap_num_blocks, __func__, &destroyed, &esnap_opts);
8901 : 24 : opts.esnap_id = &esnap_opts;
8902 : 24 : opts.esnap_id_len = sizeof(esnap_opts);
8903 : 24 : opts.num_clusters = esnap_num_clusters;
8904 : 24 : spdk_bs_create_blob_ext(bs, &opts, blob_op_with_id_complete, NULL);
8905 : 24 : poll_threads();
8906 : 24 : CU_ASSERT(g_bserrno == 0);
8907 : 24 : CU_ASSERT(g_blobid != SPDK_BLOBID_INVALID);
8908 : 24 : blobid = g_blobid;
8909 : :
8910 : : /* Open the esnap clone */
8911 : 24 : spdk_bs_open_blob(bs, blobid, blob_op_with_handle_complete, NULL);
8912 : 24 : poll_threads();
8913 : 24 : CU_ASSERT(g_bserrno == 0);
8914 [ - + ]: 24 : SPDK_CU_ASSERT_FATAL(g_blob != NULL);
8915 : 24 : blob = g_blob;
8916 : 24 : UT_ASSERT_IS_ESNAP_CLONE(blob, &esnap_opts, sizeof(esnap_opts));
8917 : :
8918 : : /*
8919 : : * Inflate or decouple the blob then verify that it is no longer an esnap clone and has
8920 : : * right content
8921 : : */
8922 [ + + ]: 24 : if (inflate) {
8923 : 12 : spdk_bs_inflate_blob(bs, channel, blobid, blob_op_complete, NULL);
8924 : : } else {
8925 : 12 : spdk_bs_blob_decouple_parent(bs, channel, blobid, blob_op_complete, NULL);
8926 : : }
8927 : 24 : poll_threads();
8928 : 24 : CU_ASSERT(g_bserrno == 0);
8929 : 24 : UT_ASSERT_IS_NOT_ESNAP_CLONE(blob);
8930 : 24 : CU_ASSERT(blob_esnap_verify_contents(blob, channel, 0, esnap_sz, esnap_sz, "read"));
8931 : 24 : ut_blob_close_and_delete(bs, blob);
8932 : :
8933 : : /*
8934 : : * Clean up
8935 : : */
8936 : 24 : spdk_bs_free_io_channel(channel);
8937 : 24 : poll_threads();
8938 : :
8939 : : /* Return number of new failures */
8940 : 24 : return CU_get_number_of_failures() - num_failures;
8941 : : }
8942 : :
8943 : : static void
8944 : 12 : blob_esnap_clone_inflate(void)
8945 : : {
8946 : 12 : _blob_esnap_clone_hydrate(true);
8947 : 12 : }
8948 : :
8949 : : static void
8950 : 12 : blob_esnap_clone_decouple(void)
8951 : : {
8952 : 12 : _blob_esnap_clone_hydrate(false);
8953 : 12 : }
8954 : :
8955 : : static void
8956 : 12 : blob_esnap_hotplug(void)
8957 : 12 : {
8958 : 12 : struct spdk_blob_store *bs = g_bs;
8959 : 12 : struct ut_esnap_opts esnap1_opts, esnap2_opts;
8960 : 12 : struct spdk_blob_opts opts;
8961 : : struct spdk_blob *blob;
8962 : : struct spdk_bs_dev *bs_dev;
8963 : : struct ut_esnap_dev *esnap_dev;
8964 : 12 : uint32_t cluster_sz = spdk_bs_get_cluster_size(bs);
8965 : 12 : uint32_t block_sz = spdk_bs_get_io_unit_size(bs);
8966 : 12 : const uint32_t esnap_num_clusters = 4;
8967 [ - + ]: 12 : uint64_t esnap_num_blocks = cluster_sz * esnap_num_clusters / block_sz;
8968 : 12 : bool destroyed1 = false, destroyed2 = false;
8969 : 12 : uint64_t start_thread = g_ut_thread_id;
8970 : : struct spdk_io_channel *ch0, *ch1;
8971 [ - + ]: 12 : char buf[block_sz];
8972 : :
8973 : : /* Create and open an esnap clone blob */
8974 : 12 : ut_spdk_blob_opts_init(&opts);
8975 : 12 : ut_esnap_opts_init(block_sz, esnap_num_blocks, "esnap1", &destroyed1, &esnap1_opts);
8976 : 12 : opts.esnap_id = &esnap1_opts;
8977 : 12 : opts.esnap_id_len = sizeof(esnap1_opts);
8978 : 12 : opts.num_clusters = esnap_num_clusters;
8979 : 12 : blob = ut_blob_create_and_open(bs, &opts);
8980 : 12 : CU_ASSERT(blob != NULL);
8981 : 12 : CU_ASSERT(spdk_blob_is_esnap_clone(blob));
8982 [ - + ]: 12 : SPDK_CU_ASSERT_FATAL(blob->back_bs_dev != NULL);
8983 : 12 : esnap_dev = (struct ut_esnap_dev *)blob->back_bs_dev;
8984 [ - + ]: 12 : CU_ASSERT(strcmp(esnap_dev->ut_opts.name, "esnap1") == 0);
8985 : :
8986 : : /* Replace the external snapshot */
8987 : 12 : ut_esnap_opts_init(block_sz, esnap_num_blocks, "esnap2", &destroyed2, &esnap2_opts);
8988 : 12 : bs_dev = ut_esnap_dev_alloc(&esnap2_opts);
8989 [ - + ]: 12 : CU_ASSERT(!destroyed1);
8990 [ - + ]: 12 : CU_ASSERT(!destroyed2);
8991 : 12 : g_bserrno = 0xbad;
8992 : 12 : spdk_blob_set_esnap_bs_dev(blob, bs_dev, bs_op_complete, NULL);
8993 : 12 : poll_threads();
8994 : 12 : CU_ASSERT(g_bserrno == 0);
8995 [ - + ]: 12 : CU_ASSERT(destroyed1);
8996 [ - + ]: 12 : CU_ASSERT(!destroyed2);
8997 [ - + ]: 12 : SPDK_CU_ASSERT_FATAL(bs_dev == blob->back_bs_dev);
8998 [ - + ]: 12 : SPDK_CU_ASSERT_FATAL(bs_dev == spdk_blob_get_esnap_bs_dev(blob));
8999 : 12 : esnap_dev = (struct ut_esnap_dev *)blob->back_bs_dev;
9000 [ - + ]: 12 : CU_ASSERT(strcmp(esnap_dev->ut_opts.name, "esnap2") == 0);
9001 : :
9002 : : /* Create a couple channels */
9003 : 12 : set_thread(0);
9004 : 12 : ch0 = spdk_bs_alloc_io_channel(bs);
9005 : 12 : CU_ASSERT(ch0 != NULL);
9006 : 12 : spdk_blob_io_read(blob, ch0, buf, 0, 1, bs_op_complete, NULL);
9007 : 12 : set_thread(1);
9008 : 12 : ch1 = spdk_bs_alloc_io_channel(bs);
9009 : 12 : CU_ASSERT(ch1 != NULL);
9010 : 12 : spdk_blob_io_read(blob, ch1, buf, 0, 1, bs_op_complete, NULL);
9011 : 12 : set_thread(start_thread);
9012 : 12 : poll_threads();
9013 : 12 : CU_ASSERT(esnap_dev->num_channels == 2);
9014 : :
9015 : : /* Replace the external snapshot */
9016 : 12 : ut_esnap_opts_init(block_sz, esnap_num_blocks, "esnap1a", &destroyed1, &esnap1_opts);
9017 : 12 : bs_dev = ut_esnap_dev_alloc(&esnap1_opts);
9018 [ - + ]: 12 : destroyed1 = destroyed2 = false;
9019 : 12 : g_bserrno = 0xbad;
9020 : 12 : spdk_blob_set_esnap_bs_dev(blob, bs_dev, bs_op_complete, NULL);
9021 : 12 : poll_threads();
9022 : 12 : CU_ASSERT(g_bserrno == 0);
9023 [ - + ]: 12 : CU_ASSERT(!destroyed1);
9024 [ - + ]: 12 : CU_ASSERT(destroyed2);
9025 [ - + ]: 12 : SPDK_CU_ASSERT_FATAL(blob->back_bs_dev != NULL);
9026 : 12 : esnap_dev = (struct ut_esnap_dev *)blob->back_bs_dev;
9027 [ - + ]: 12 : CU_ASSERT(strcmp(esnap_dev->ut_opts.name, "esnap1a") == 0);
9028 : :
9029 : : /* Clean up */
9030 : 12 : set_thread(0);
9031 : 12 : spdk_bs_free_io_channel(ch0);
9032 : 12 : set_thread(1);
9033 : 12 : spdk_bs_free_io_channel(ch1);
9034 : 12 : set_thread(start_thread);
9035 : 12 : g_bserrno = 0xbad;
9036 : 12 : spdk_blob_close(blob, bs_op_complete, NULL);
9037 : 12 : poll_threads();
9038 : 12 : CU_ASSERT(g_bserrno == 0);
9039 : 12 : }
9040 : :
9041 : : static bool g_blob_is_degraded;
9042 : : static int g_blob_is_degraded_called;
9043 : :
9044 : : static bool
9045 : 72 : _blob_is_degraded(struct spdk_bs_dev *dev)
9046 : : {
9047 : 72 : g_blob_is_degraded_called++;
9048 [ - + ]: 72 : return g_blob_is_degraded;
9049 : : }
9050 : :
9051 : : static void
9052 : 12 : blob_is_degraded(void)
9053 : : {
9054 : 12 : struct spdk_bs_dev bs_is_degraded_null = { 0 };
9055 : 12 : struct spdk_bs_dev bs_is_degraded = { .is_degraded = _blob_is_degraded };
9056 : :
9057 : : /* No back_bs_dev, no bs->dev->is_degraded */
9058 : 12 : g_blob_is_degraded_called = 0;
9059 : 12 : CU_ASSERT(!spdk_blob_is_degraded(g_blob));
9060 : 12 : CU_ASSERT(g_blob_is_degraded_called == 0);
9061 : :
9062 : : /* No back_bs_dev, blobstore device degraded */
9063 : 12 : g_bs->dev->is_degraded = _blob_is_degraded;
9064 : 12 : g_blob_is_degraded_called = 0;
9065 : 12 : g_blob_is_degraded = true;
9066 : 12 : CU_ASSERT(spdk_blob_is_degraded(g_blob));
9067 : 12 : CU_ASSERT(g_blob_is_degraded_called == 1);
9068 : :
9069 : : /* No back_bs_dev, blobstore device not degraded */
9070 : 12 : g_bs->dev->is_degraded = _blob_is_degraded;
9071 : 12 : g_blob_is_degraded_called = 0;
9072 : 12 : g_blob_is_degraded = false;
9073 : 12 : CU_ASSERT(!spdk_blob_is_degraded(g_blob));
9074 : 12 : CU_ASSERT(g_blob_is_degraded_called == 1);
9075 : :
9076 : : /* back_bs_dev does not define is_degraded, no bs->dev->is_degraded */
9077 : 12 : g_bs->dev->is_degraded = NULL;
9078 : 12 : g_blob->back_bs_dev = &bs_is_degraded_null;
9079 : 12 : g_blob_is_degraded_called = 0;
9080 : 12 : g_blob_is_degraded = false;
9081 : 12 : CU_ASSERT(!spdk_blob_is_degraded(g_blob));
9082 : 12 : CU_ASSERT(g_blob_is_degraded_called == 0);
9083 : :
9084 : : /* back_bs_dev is not degraded, no bs->dev->is_degraded */
9085 : 12 : g_bs->dev->is_degraded = NULL;
9086 : 12 : g_blob->back_bs_dev = &bs_is_degraded;
9087 : 12 : g_blob_is_degraded_called = 0;
9088 : 12 : g_blob_is_degraded = false;
9089 : 12 : CU_ASSERT(!spdk_blob_is_degraded(g_blob));
9090 : 12 : CU_ASSERT(g_blob_is_degraded_called == 1);
9091 : :
9092 : : /* back_bs_dev is degraded, no bs->dev->is_degraded */
9093 : 12 : g_bs->dev->is_degraded = NULL;
9094 : 12 : g_blob->back_bs_dev = &bs_is_degraded;
9095 : 12 : g_blob_is_degraded_called = 0;
9096 : 12 : g_blob_is_degraded = true;
9097 : 12 : CU_ASSERT(spdk_blob_is_degraded(g_blob));
9098 : 12 : CU_ASSERT(g_blob_is_degraded_called == 1);
9099 : :
9100 : : /* back_bs_dev is not degraded, blobstore device is not degraded */
9101 : 12 : g_bs->dev->is_degraded = _blob_is_degraded;
9102 : 12 : g_blob->back_bs_dev = &bs_is_degraded;
9103 : 12 : g_blob_is_degraded_called = 0;
9104 : 12 : g_blob_is_degraded = false;
9105 : 12 : CU_ASSERT(!spdk_blob_is_degraded(g_blob));
9106 : 12 : CU_ASSERT(g_blob_is_degraded_called == 2);
9107 : :
9108 : 12 : g_blob->back_bs_dev = NULL;
9109 : 12 : }
9110 : :
9111 : : /* Resize a blob which is a clone created from snapshot. Verify read/writes to
9112 : : * expanded clone blob. Then inflate the clone blob. */
9113 : : static void
9114 : 12 : blob_clone_resize(void)
9115 : 12 : {
9116 : 12 : struct spdk_blob_store *bs = g_bs;
9117 : 12 : struct spdk_blob_opts opts;
9118 : : struct spdk_blob *blob, *clone, *snap_blob, *snap_blob_rsz;
9119 : : spdk_blob_id blobid, cloneid, snapid1, snapid2;
9120 : : uint64_t pages_per_cluster;
9121 [ - + ]: 12 : uint8_t payload_read[bs->dev->blocklen];
9122 [ - + ]: 12 : uint8_t payload_write[bs->dev->blocklen];
9123 : : struct spdk_io_channel *channel;
9124 : : uint64_t free_clusters;
9125 : :
9126 : 12 : channel = spdk_bs_alloc_io_channel(bs);
9127 [ - + ]: 12 : SPDK_CU_ASSERT_FATAL(channel != NULL);
9128 : :
9129 [ - + ]: 12 : pages_per_cluster = spdk_bs_get_cluster_size(bs) / spdk_bs_get_page_size(bs);
9130 : :
9131 : : /* Create blob with 10 clusters */
9132 : 12 : ut_spdk_blob_opts_init(&opts);
9133 : 12 : opts.num_clusters = 10;
9134 : :
9135 : 12 : blob = ut_blob_create_and_open(bs, &opts);
9136 : 12 : blobid = spdk_blob_get_id(blob);
9137 : 12 : CU_ASSERT(spdk_blob_get_num_clusters(blob) == 10);
9138 : :
9139 : : /* Create snapshot */
9140 : 12 : spdk_bs_create_snapshot(bs, blobid, NULL, blob_op_with_id_complete, NULL);
9141 : 12 : poll_threads();
9142 : 12 : CU_ASSERT(g_bserrno == 0);
9143 : 12 : CU_ASSERT(g_blobid != SPDK_BLOBID_INVALID);
9144 : 12 : snapid1 = g_blobid;
9145 : :
9146 : 12 : spdk_bs_create_clone(bs, snapid1, NULL, blob_op_with_id_complete, NULL);
9147 : 12 : poll_threads();
9148 : 12 : CU_ASSERT(g_bserrno == 0);
9149 : 12 : CU_ASSERT(g_blobid != SPDK_BLOBID_INVALID);
9150 : 12 : cloneid = g_blobid;
9151 : :
9152 : 12 : spdk_bs_open_blob(bs, cloneid, blob_op_with_handle_complete, NULL);
9153 : 12 : poll_threads();
9154 : 12 : CU_ASSERT(g_bserrno == 0);
9155 [ - + ]: 12 : SPDK_CU_ASSERT_FATAL(g_blob != NULL);
9156 : 12 : clone = g_blob;
9157 : 12 : CU_ASSERT(spdk_blob_get_num_clusters(clone) == 10);
9158 : :
9159 : 12 : g_bserrno = -1;
9160 : 12 : spdk_blob_resize(clone, 20, blob_op_complete, NULL);
9161 : 12 : poll_threads();
9162 : 12 : CU_ASSERT(g_bserrno == 0);
9163 : 12 : CU_ASSERT(spdk_blob_get_num_clusters(clone) == 20);
9164 : :
9165 : : /* Create another snapshot after resizing the clone */
9166 : 12 : spdk_bs_create_snapshot(bs, cloneid, NULL, blob_op_with_id_complete, NULL);
9167 : 12 : poll_threads();
9168 : 12 : CU_ASSERT(g_bserrno == 0);
9169 : 12 : CU_ASSERT(g_blobid != SPDK_BLOBID_INVALID);
9170 : 12 : snapid2 = g_blobid;
9171 : :
9172 : : /* Open the snapshot blobs */
9173 : 12 : spdk_bs_open_blob(bs, snapid1, blob_op_with_handle_complete, NULL);
9174 : 12 : CU_ASSERT(g_bserrno == 0);
9175 [ - + ]: 12 : SPDK_CU_ASSERT_FATAL(g_blob != NULL);
9176 : 12 : snap_blob = g_blob;
9177 [ - + ]: 12 : CU_ASSERT(snap_blob->data_ro == true);
9178 [ - + ]: 12 : CU_ASSERT(snap_blob->md_ro == true);
9179 : 12 : CU_ASSERT(spdk_blob_get_num_clusters(snap_blob) == 10);
9180 : :
9181 : 12 : spdk_bs_open_blob(bs, snapid2, blob_op_with_handle_complete, NULL);
9182 : 12 : CU_ASSERT(g_bserrno == 0);
9183 [ - + ]: 12 : SPDK_CU_ASSERT_FATAL(g_blob != NULL);
9184 : 12 : snap_blob_rsz = g_blob;
9185 [ - + ]: 12 : CU_ASSERT(snap_blob_rsz->data_ro == true);
9186 [ - + ]: 12 : CU_ASSERT(snap_blob_rsz->md_ro == true);
9187 : 12 : CU_ASSERT(spdk_blob_get_num_clusters(snap_blob_rsz) == 20);
9188 : :
9189 : : /* Confirm that clone is backed by snap_blob_rsz, and snap_blob_rsz is backed by snap_blob */
9190 [ - + ]: 12 : SPDK_CU_ASSERT_FATAL(snap_blob->back_bs_dev == NULL);
9191 [ - + ]: 12 : SPDK_CU_ASSERT_FATAL(blob->back_bs_dev != NULL);
9192 [ - + ]: 12 : SPDK_CU_ASSERT_FATAL(snap_blob_rsz->back_bs_dev != NULL);
9193 : :
9194 : : /* Write and read from pre-resize ranges */
9195 : 12 : g_bserrno = -1;
9196 [ - + ]: 12 : memset(payload_write, 0xE5, sizeof(payload_write));
9197 : 12 : spdk_blob_io_write(clone, channel, payload_write, 5 * pages_per_cluster, 1, blob_op_complete, NULL);
9198 : 12 : poll_threads();
9199 : 12 : CU_ASSERT(g_bserrno == 0);
9200 : :
9201 : 12 : g_bserrno = -1;
9202 [ - + ]: 12 : memset(payload_read, 0x00, sizeof(payload_read));
9203 : 12 : spdk_blob_io_read(clone, channel, payload_read, 5 * pages_per_cluster, 1, blob_op_complete, NULL);
9204 : 12 : poll_threads();
9205 : 12 : CU_ASSERT(g_bserrno == 0);
9206 [ - + - + ]: 12 : CU_ASSERT(memcmp(payload_write, payload_read, 4096) == 0);
9207 : :
9208 : : /* Write and read from post-resize ranges */
9209 : 12 : g_bserrno = -1;
9210 [ - + ]: 12 : memset(payload_write, 0xE5, sizeof(payload_write));
9211 : 12 : spdk_blob_io_write(clone, channel, payload_write, 15 * pages_per_cluster, 1, blob_op_complete,
9212 : : NULL);
9213 : 12 : poll_threads();
9214 : 12 : CU_ASSERT(g_bserrno == 0);
9215 : :
9216 : 12 : g_bserrno = -1;
9217 [ - + ]: 12 : memset(payload_read, 0x00, sizeof(payload_read));
9218 : 12 : spdk_blob_io_read(clone, channel, payload_read, 15 * pages_per_cluster, 1, blob_op_complete, NULL);
9219 : 12 : poll_threads();
9220 : 12 : CU_ASSERT(g_bserrno == 0);
9221 [ - + - + ]: 12 : CU_ASSERT(memcmp(payload_write, payload_read, bs->dev->blocklen) == 0);
9222 : :
9223 : : /* Now do full blob inflation of the resized blob/clone. */
9224 : 12 : free_clusters = spdk_bs_free_cluster_count(bs);
9225 : 12 : spdk_bs_inflate_blob(bs, channel, cloneid, blob_op_complete, NULL);
9226 : 12 : poll_threads();
9227 : 12 : CU_ASSERT(g_bserrno == 0);
9228 : : /* We wrote to 2 clusters earlier, all remaining 18 clusters in
9229 : : * blob should get allocated after inflation */
9230 : 12 : CU_ASSERT(spdk_bs_free_cluster_count(bs) == free_clusters - 18);
9231 : :
9232 : 12 : spdk_blob_close(clone, blob_op_complete, NULL);
9233 : 12 : poll_threads();
9234 : 12 : CU_ASSERT(g_bserrno == 0);
9235 : :
9236 : 12 : spdk_blob_close(snap_blob, blob_op_complete, NULL);
9237 : 12 : poll_threads();
9238 : 12 : CU_ASSERT(g_bserrno == 0);
9239 : :
9240 : 12 : spdk_blob_close(snap_blob_rsz, blob_op_complete, NULL);
9241 : 12 : poll_threads();
9242 : 12 : CU_ASSERT(g_bserrno == 0);
9243 : :
9244 : 12 : ut_blob_close_and_delete(bs, blob);
9245 : :
9246 : 12 : spdk_bs_free_io_channel(channel);
9247 : 12 : }
9248 : :
9249 : :
9250 : : static void
9251 : 12 : blob_esnap_clone_resize(void)
9252 : : {
9253 : : struct spdk_bs_dev *dev;
9254 : : struct spdk_blob_store *bs;
9255 : 12 : struct spdk_bs_opts bsopts;
9256 : 12 : struct spdk_blob_opts opts;
9257 : 12 : struct ut_esnap_opts esnap_opts;
9258 : : struct spdk_blob *blob;
9259 : 12 : uint32_t block, esnap_blksz = 512, bs_blksz = 512;
9260 : 12 : const uint32_t cluster_sz = 16 * 1024;
9261 : 12 : const uint64_t esnap_num_clusters = 4;
9262 : 12 : const uint32_t esnap_sz = cluster_sz * esnap_num_clusters;
9263 [ - + ]: 12 : const uint64_t esnap_num_blocks = esnap_sz / esnap_blksz;
9264 [ - + ]: 12 : uint64_t blob_num_blocks = esnap_sz / bs_blksz;
9265 : : struct spdk_io_channel *bs_ch;
9266 : :
9267 : 12 : spdk_bs_opts_init(&bsopts, sizeof(bsopts));
9268 : 12 : bsopts.cluster_sz = cluster_sz;
9269 : 12 : bsopts.esnap_bs_dev_create = ut_esnap_create;
9270 : : /* Create device with desired block size */
9271 : 12 : dev = init_dev();
9272 : 12 : dev->blocklen = bs_blksz;
9273 [ - + ]: 12 : dev->blockcnt = DEV_BUFFER_SIZE / dev->blocklen;
9274 : : /* Initialize a new blob store */
9275 : 12 : spdk_bs_init(dev, &bsopts, bs_op_with_handle_complete, NULL);
9276 : 12 : poll_threads();
9277 : 12 : CU_ASSERT(g_bserrno == 0);
9278 [ - + ]: 12 : SPDK_CU_ASSERT_FATAL(g_bs != NULL);
9279 [ - + ]: 12 : SPDK_CU_ASSERT_FATAL(g_bs->io_unit_size == bs_blksz);
9280 : 12 : bs = g_bs;
9281 : :
9282 : 12 : bs_ch = spdk_bs_alloc_io_channel(bs);
9283 [ - + ]: 12 : SPDK_CU_ASSERT_FATAL(bs_ch != NULL);
9284 : :
9285 : : /* Create and open the esnap clone */
9286 : 12 : ut_spdk_blob_opts_init(&opts);
9287 : 12 : ut_esnap_opts_init(esnap_blksz, esnap_num_blocks, __func__, NULL, &esnap_opts);
9288 : 12 : opts.esnap_id = &esnap_opts;
9289 : 12 : opts.esnap_id_len = sizeof(esnap_opts);
9290 : 12 : opts.num_clusters = esnap_num_clusters;
9291 : 12 : blob = ut_blob_create_and_open(bs, &opts);
9292 [ - + ]: 12 : SPDK_CU_ASSERT_FATAL(blob != NULL);
9293 : :
9294 : 12 : g_bserrno = -1;
9295 : 12 : spdk_blob_resize(blob, esnap_num_clusters * 2, blob_op_complete, NULL);
9296 : 12 : poll_threads();
9297 : 12 : CU_ASSERT(g_bserrno == 0);
9298 : 12 : CU_ASSERT(spdk_blob_get_num_clusters(blob) == esnap_num_clusters * 2);
9299 : :
9300 : : /* Write one blob block at a time; verify that the surrounding blocks are OK */
9301 [ - + ]: 12 : blob_num_blocks = (spdk_blob_get_num_clusters(blob) * cluster_sz) / bs_blksz;
9302 [ + + ]: 3084 : for (block = 0; block < blob_num_blocks; block++) {
9303 [ - + ]: 3072 : char buf[bs_blksz];
9304 : : union ut_word word;
9305 : 3072 : word.f.blob_id = 0xfedcba90;
9306 : 3072 : word.f.lba = block;
9307 : 3072 : ut_memset8(buf, word.num, bs_blksz);
9308 : 3072 : spdk_blob_io_write(blob, bs_ch, buf, block, 1, bs_op_complete, NULL);
9309 : 3072 : poll_threads();
9310 : 3072 : CU_ASSERT(g_bserrno == 0);
9311 [ - + ]: 3072 : if (g_bserrno != 0) {
9312 : 0 : break;
9313 : : }
9314 : : /* Read and verify the block before the current block */
9315 [ + + ]: 3072 : if (block != 0) {
9316 : 3060 : spdk_blob_io_read(blob, bs_ch, buf, block - 1, 1, bs_op_complete, NULL);
9317 : 3060 : poll_threads();
9318 : 3060 : CU_ASSERT(g_bserrno == 0);
9319 [ - + ]: 3060 : if (g_bserrno != 0) {
9320 : 0 : break;
9321 : : }
9322 : 3060 : CU_ASSERT(ut_esnap_content_is_correct(buf, bs_blksz, word.f.blob_id,
9323 : : (block - 1) * bs_blksz, bs_blksz));
9324 : : }
9325 : : /* Read and verify the current block */
9326 : 3072 : spdk_blob_io_read(blob, bs_ch, buf, block, 1, bs_op_complete, NULL);
9327 : 3072 : poll_threads();
9328 : 3072 : CU_ASSERT(g_bserrno == 0);
9329 [ - + ]: 3072 : if (g_bserrno != 0) {
9330 : 0 : break;
9331 : : }
9332 : 3072 : CU_ASSERT(ut_esnap_content_is_correct(buf, bs_blksz, word.f.blob_id,
9333 : : block * bs_blksz, bs_blksz));
9334 : : /* Check the block that follows */
9335 [ + + ]: 3072 : if (block + 1 < blob_num_blocks) {
9336 : 3060 : g_bserrno = 0xbad;
9337 : 3060 : spdk_blob_io_read(blob, bs_ch, buf, block + 1, 1, bs_op_complete, NULL);
9338 : 3060 : poll_threads();
9339 : 3060 : CU_ASSERT(g_bserrno == 0);
9340 [ - + ]: 3060 : if (g_bserrno != 0) {
9341 : 0 : break;
9342 : : }
9343 : 3060 : CU_ASSERT(ut_esnap_content_is_correct(buf, bs_blksz, blob->id,
9344 : : (block + 1) * bs_blksz,
9345 : : esnap_blksz));
9346 : : }
9347 : : }
9348 : : /* Clean up */
9349 : 12 : spdk_bs_free_io_channel(bs_ch);
9350 : 12 : g_bserrno = 0xbad;
9351 : 12 : spdk_blob_close(blob, blob_op_complete, NULL);
9352 : 12 : poll_threads();
9353 : 12 : CU_ASSERT(g_bserrno == 0);
9354 : 12 : spdk_bs_unload(g_bs, bs_op_complete, NULL);
9355 : 12 : poll_threads();
9356 : 12 : CU_ASSERT(g_bserrno == 0);
9357 : 12 : g_bs = NULL;
9358 [ - + ]: 12 : memset(g_dev_buffer, 0, DEV_BUFFER_SIZE);
9359 : 12 : }
9360 : :
9361 : : static void
9362 : 24576 : bs_dev_io_complete_cb(struct spdk_io_channel *channel, void *cb_arg, int bserrno)
9363 : : {
9364 : 24576 : g_bserrno = bserrno;
9365 : 24576 : }
9366 : :
9367 : : static void
9368 : 12 : blob_shallow_copy(void)
9369 : : {
9370 : 12 : struct spdk_blob_store *bs = g_bs;
9371 : 12 : struct spdk_blob_opts blob_opts;
9372 : : struct spdk_blob *blob;
9373 : : spdk_blob_id blobid;
9374 : 12 : uint64_t num_clusters = 4;
9375 : : struct spdk_bs_dev *ext_dev;
9376 : 12 : struct spdk_bs_dev_cb_args ext_args;
9377 : : struct spdk_io_channel *bdev_ch, *blob_ch;
9378 : 12 : uint8_t buf1[DEV_BUFFER_BLOCKLEN];
9379 : 12 : uint8_t buf2[DEV_BUFFER_BLOCKLEN];
9380 : : uint64_t io_units_per_cluster;
9381 : : uint64_t offset;
9382 : : int rc;
9383 : :
9384 : 12 : blob_ch = spdk_bs_alloc_io_channel(bs);
9385 [ - + ]: 12 : SPDK_CU_ASSERT_FATAL(blob_ch != NULL);
9386 : :
9387 : : /* Set blob dimension and as thin provisioned */
9388 : 12 : ut_spdk_blob_opts_init(&blob_opts);
9389 : 12 : blob_opts.thin_provision = true;
9390 : 12 : blob_opts.num_clusters = num_clusters;
9391 : :
9392 : : /* Create a blob */
9393 : 12 : blob = ut_blob_create_and_open(bs, &blob_opts);
9394 [ - + ]: 12 : SPDK_CU_ASSERT_FATAL(blob != NULL);
9395 : 12 : blobid = spdk_blob_get_id(blob);
9396 : 12 : io_units_per_cluster = bs_io_units_per_cluster(blob);
9397 : :
9398 : : /* Write on cluster 2 and 4 of blob */
9399 [ + + ]: 3084 : for (offset = io_units_per_cluster; offset < 2 * io_units_per_cluster; offset++) {
9400 : 3072 : memset(buf1, offset, DEV_BUFFER_BLOCKLEN);
9401 : 3072 : spdk_blob_io_write(blob, blob_ch, buf1, offset, 1, blob_op_complete, NULL);
9402 : 3072 : poll_threads();
9403 : 3072 : CU_ASSERT(g_bserrno == 0);
9404 : : }
9405 [ + + ]: 3084 : for (offset = 3 * io_units_per_cluster; offset < 4 * io_units_per_cluster; offset++) {
9406 : 3072 : memset(buf1, offset, DEV_BUFFER_BLOCKLEN);
9407 : 3072 : spdk_blob_io_write(blob, blob_ch, buf1, offset, 1, blob_op_complete, NULL);
9408 : 3072 : poll_threads();
9409 : 3072 : CU_ASSERT(g_bserrno == 0);
9410 : : }
9411 : 12 : CU_ASSERT(spdk_blob_get_num_allocated_clusters(blob) == 2);
9412 : :
9413 : : /* Make a snapshot over blob */
9414 : 12 : spdk_bs_create_snapshot(bs, blobid, NULL, blob_op_with_id_complete, NULL);
9415 : 12 : poll_threads();
9416 : 12 : CU_ASSERT(g_bserrno == 0);
9417 : 12 : CU_ASSERT(spdk_blob_get_num_allocated_clusters(blob) == 0);
9418 : :
9419 : : /* Write on cluster 1 and 3 of blob */
9420 [ + + ]: 3084 : for (offset = 0; offset < io_units_per_cluster; offset++) {
9421 : 3072 : memset(buf1, offset, DEV_BUFFER_BLOCKLEN);
9422 : 3072 : spdk_blob_io_write(blob, blob_ch, buf1, offset, 1, blob_op_complete, NULL);
9423 : 3072 : poll_threads();
9424 : 3072 : CU_ASSERT(g_bserrno == 0);
9425 : : }
9426 [ + + ]: 3084 : for (offset = 2 * io_units_per_cluster; offset < 3 * io_units_per_cluster; offset++) {
9427 : 3072 : memset(buf1, offset, DEV_BUFFER_BLOCKLEN);
9428 : 3072 : spdk_blob_io_write(blob, blob_ch, buf1, offset, 1, blob_op_complete, NULL);
9429 : 3072 : poll_threads();
9430 : 3072 : CU_ASSERT(g_bserrno == 0);
9431 : : }
9432 : 12 : CU_ASSERT(spdk_blob_get_num_allocated_clusters(blob) == 2);
9433 : :
9434 : : /* Shallow copy with a not read only blob */
9435 : 12 : ext_dev = init_ext_dev(num_clusters * 1024 * 1024, DEV_BUFFER_BLOCKLEN);
9436 : 12 : rc = spdk_bs_blob_shallow_copy(bs, blob_ch, blobid, ext_dev,
9437 : : blob_shallow_copy_status_cb, NULL,
9438 : : blob_op_complete, NULL);
9439 : 12 : CU_ASSERT(rc == 0);
9440 : 12 : poll_threads();
9441 : 12 : CU_ASSERT(g_bserrno == -EPERM);
9442 : 12 : ext_dev->destroy(ext_dev);
9443 : :
9444 : : /* Set blob read only */
9445 : 12 : spdk_blob_set_read_only(blob);
9446 : 12 : spdk_blob_sync_md(blob, blob_op_complete, NULL);
9447 : 12 : poll_threads();
9448 : 12 : CU_ASSERT(g_bserrno == 0);
9449 : :
9450 : : /* Shallow copy over a spdk_bs_dev with incorrect size */
9451 : 12 : ext_dev = init_ext_dev(1, DEV_BUFFER_BLOCKLEN);
9452 : 12 : rc = spdk_bs_blob_shallow_copy(bs, blob_ch, blobid, ext_dev,
9453 : : blob_shallow_copy_status_cb, NULL,
9454 : : blob_op_complete, NULL);
9455 : 12 : CU_ASSERT(rc == 0);
9456 : 12 : poll_threads();
9457 : 12 : CU_ASSERT(g_bserrno == -EINVAL);
9458 : 12 : ext_dev->destroy(ext_dev);
9459 : :
9460 : : /* Shallow copy over a spdk_bs_dev with incorrect block len */
9461 : 12 : ext_dev = init_ext_dev(num_clusters * 1024 * 1024, DEV_BUFFER_BLOCKLEN * 2);
9462 : 12 : rc = spdk_bs_blob_shallow_copy(bs, blob_ch, blobid, ext_dev,
9463 : : blob_shallow_copy_status_cb, NULL,
9464 : : blob_op_complete, NULL);
9465 : 12 : CU_ASSERT(rc == 0);
9466 : 12 : poll_threads();
9467 : 12 : CU_ASSERT(g_bserrno == -EINVAL);
9468 : 12 : ext_dev->destroy(ext_dev);
9469 : :
9470 : : /* Initialize ext_dev for the successuful shallow copy */
9471 : 12 : ext_dev = init_ext_dev(num_clusters * 1024 * 1024, DEV_BUFFER_BLOCKLEN);
9472 : 12 : bdev_ch = ext_dev->create_channel(ext_dev);
9473 [ - + ]: 12 : SPDK_CU_ASSERT_FATAL(bdev_ch != NULL);
9474 : 12 : ext_args.cb_fn = bs_dev_io_complete_cb;
9475 [ + + ]: 12300 : for (offset = 0; offset < 4 * io_units_per_cluster; offset++) {
9476 : 12288 : memset(buf2, 0xff, DEV_BUFFER_BLOCKLEN);
9477 : 12288 : ext_dev->write(ext_dev, bdev_ch, buf2, offset, 1, &ext_args);
9478 : 12288 : poll_threads();
9479 : 12288 : CU_ASSERT(g_bserrno == 0);
9480 : : }
9481 : :
9482 : : /* Correct shallow copy of blob over bdev */
9483 : 12 : rc = spdk_bs_blob_shallow_copy(bs, blob_ch, blobid, ext_dev,
9484 : : blob_shallow_copy_status_cb, NULL,
9485 : : blob_op_complete, NULL);
9486 : 12 : CU_ASSERT(rc == 0);
9487 : 12 : poll_thread_times(0, 1);
9488 : 12 : CU_ASSERT(g_copied_clusters_count == 1);
9489 : 12 : poll_thread_times(0, 2);
9490 : 12 : CU_ASSERT(g_bserrno == 0);
9491 : 12 : CU_ASSERT(g_copied_clusters_count == 2);
9492 : :
9493 : : /* Read from bdev */
9494 : : /* Only cluster 1 and 3 must be filled */
9495 : : /* Clusters 2 and 4 should not have been touched */
9496 [ + + ]: 3084 : for (offset = 0; offset < io_units_per_cluster; offset++) {
9497 : 3072 : memset(buf1, offset, DEV_BUFFER_BLOCKLEN);
9498 : 3072 : ext_dev->read(ext_dev, bdev_ch, buf2, offset, 1, &ext_args);
9499 : 3072 : poll_threads();
9500 : 3072 : CU_ASSERT(g_bserrno == 0);
9501 : 3072 : CU_ASSERT(memcmp(buf1, buf2, DEV_BUFFER_BLOCKLEN) == 0);
9502 : : }
9503 [ + + ]: 3084 : for (offset = io_units_per_cluster; offset < 2 * io_units_per_cluster; offset++) {
9504 : 3072 : memset(buf1, 0xff, DEV_BUFFER_BLOCKLEN);
9505 : 3072 : ext_dev->read(ext_dev, bdev_ch, buf2, offset, 1, &ext_args);
9506 : 3072 : poll_threads();
9507 : 3072 : CU_ASSERT(g_bserrno == 0);
9508 : 3072 : CU_ASSERT(memcmp(buf1, buf2, DEV_BUFFER_BLOCKLEN) == 0);
9509 : : }
9510 [ + + ]: 3084 : for (offset = 2 * io_units_per_cluster; offset < 3 * io_units_per_cluster; offset++) {
9511 : 3072 : memset(buf1, offset, DEV_BUFFER_BLOCKLEN);
9512 : 3072 : ext_dev->read(ext_dev, bdev_ch, buf2, offset, 1, &ext_args);
9513 : 3072 : poll_threads();
9514 : 3072 : CU_ASSERT(g_bserrno == 0);
9515 : 3072 : CU_ASSERT(memcmp(buf1, buf2, DEV_BUFFER_BLOCKLEN) == 0);
9516 : : }
9517 [ + + ]: 3084 : for (offset = 3 * io_units_per_cluster; offset < 4 * io_units_per_cluster; offset++) {
9518 : 3072 : memset(buf1, 0xff, DEV_BUFFER_BLOCKLEN);
9519 : 3072 : ext_dev->read(ext_dev, bdev_ch, buf2, offset, 1, &ext_args);
9520 : 3072 : poll_threads();
9521 : 3072 : CU_ASSERT(g_bserrno == 0);
9522 : 3072 : CU_ASSERT(memcmp(buf1, buf2, DEV_BUFFER_BLOCKLEN) == 0);
9523 : : }
9524 : :
9525 : : /* Clean up */
9526 : 12 : ext_dev->destroy_channel(ext_dev, bdev_ch);
9527 : 12 : ext_dev->destroy(ext_dev);
9528 : 12 : spdk_bs_free_io_channel(blob_ch);
9529 : 12 : ut_blob_close_and_delete(bs, blob);
9530 : 12 : poll_threads();
9531 : 12 : }
9532 : :
9533 : : static void
9534 : 12 : blob_set_parent(void)
9535 : : {
9536 : 12 : struct spdk_blob_store *bs = g_bs;
9537 : 12 : struct spdk_blob_opts opts;
9538 : 12 : struct ut_esnap_opts esnap_opts;
9539 : : struct spdk_blob *blob1, *blob2, *blob3, *blob4, *blob5;
9540 : : spdk_blob_id blobid1, blobid2, blobid3, blobid4, blobid5,
9541 : : snapshotid1, snapshotid2, snapshotid3;
9542 : : uint32_t cluster_sz, block_sz;
9543 : 12 : const uint32_t esnap_num_clusters = 4;
9544 : : uint64_t esnap_num_blocks;
9545 : 12 : spdk_blob_id ids[2];
9546 : 12 : size_t clone_count = 2;
9547 : :
9548 : 12 : cluster_sz = spdk_bs_get_cluster_size(bs);
9549 : 12 : block_sz = spdk_bs_get_io_unit_size(bs);
9550 [ - + ]: 12 : esnap_num_blocks = cluster_sz * esnap_num_clusters / block_sz;
9551 : :
9552 : : /* Create a normal blob and make a couple of snapshots */
9553 : 12 : ut_spdk_blob_opts_init(&opts);
9554 : 12 : blob1 = ut_blob_create_and_open(bs, &opts);
9555 [ - + ]: 12 : SPDK_CU_ASSERT_FATAL(blob1 != NULL);
9556 : 12 : blobid1 = spdk_blob_get_id(blob1);
9557 : 12 : spdk_bs_create_snapshot(bs, blobid1, NULL, blob_op_with_id_complete, NULL);
9558 : 12 : poll_threads();
9559 [ - + ]: 12 : SPDK_CU_ASSERT_FATAL(g_bserrno == 0);
9560 [ - + ]: 12 : SPDK_CU_ASSERT_FATAL(g_blobid != SPDK_BLOBID_INVALID);
9561 : 12 : snapshotid1 = g_blobid;
9562 : 12 : spdk_bs_create_snapshot(bs, blobid1, NULL, blob_op_with_id_complete, NULL);
9563 : 12 : poll_threads();
9564 [ - + ]: 12 : SPDK_CU_ASSERT_FATAL(g_bserrno == 0);
9565 [ - + ]: 12 : SPDK_CU_ASSERT_FATAL(g_blobid != SPDK_BLOBID_INVALID);
9566 : 12 : snapshotid2 = g_blobid;
9567 : :
9568 : : /* Call set_parent with an invalid snapshotid */
9569 : 12 : spdk_bs_blob_set_parent(bs, blobid1, SPDK_BLOBID_INVALID, blob_op_complete, NULL);
9570 : 12 : poll_threads();
9571 : 12 : CU_ASSERT(g_bserrno == -EINVAL);
9572 : :
9573 : : /* Call set_parent with blobid and snapshotid the same */
9574 : 12 : spdk_bs_blob_set_parent(bs, blobid1, blobid1, blob_op_complete, NULL);
9575 : 12 : poll_threads();
9576 : 12 : CU_ASSERT(g_bserrno == -EINVAL);
9577 : :
9578 : : /* Call set_parent with a blob and its parent snapshot */
9579 : 12 : spdk_bs_blob_set_parent(bs, blobid1, snapshotid2, blob_op_complete, NULL);
9580 : 12 : poll_threads();
9581 : 12 : CU_ASSERT(g_bserrno == -EEXIST);
9582 : :
9583 : : /* Create an esnap clone blob */
9584 : 12 : ut_spdk_blob_opts_init(&opts);
9585 : 12 : ut_esnap_opts_init(block_sz, esnap_num_blocks, __func__, NULL, &esnap_opts);
9586 : 12 : opts.esnap_id = &esnap_opts;
9587 : 12 : opts.esnap_id_len = sizeof(esnap_opts);
9588 : 12 : opts.num_clusters = esnap_num_clusters;
9589 : 12 : blob2 = ut_blob_create_and_open(bs, &opts);
9590 [ - + ]: 12 : SPDK_CU_ASSERT_FATAL(blob2 != NULL);
9591 : 12 : blobid2 = spdk_blob_get_id(blob2);
9592 : 12 : CU_ASSERT(spdk_blob_is_esnap_clone(blob2));
9593 : :
9594 : : /* Call set_parent with a non snapshot parent */
9595 : 12 : spdk_bs_blob_set_parent(bs, blobid2, blobid1, blob_op_complete, NULL);
9596 : 12 : poll_threads();
9597 : 12 : CU_ASSERT(g_bserrno == -EINVAL);
9598 : :
9599 : : /* Call set_parent with blob and snapshot of different size */
9600 : 12 : spdk_bs_blob_set_parent(bs, blobid2, snapshotid1, blob_op_complete, NULL);
9601 : 12 : poll_threads();
9602 : 12 : CU_ASSERT(g_bserrno == -EINVAL);
9603 : :
9604 : : /* Call set_parent correctly with a snapshot's clone blob */
9605 : 12 : spdk_bs_blob_set_parent(bs, blobid1, snapshotid1, blob_op_complete, NULL);
9606 : 12 : poll_threads();
9607 : 12 : CU_ASSERT(g_bserrno == 0);
9608 : :
9609 : : /* Check relations */
9610 : 12 : CU_ASSERT(spdk_blob_is_clone(blob1));
9611 : 12 : CU_ASSERT(spdk_blob_get_parent_snapshot(bs, blobid1) == snapshotid1);
9612 : 12 : CU_ASSERT(spdk_blob_get_clones(bs, snapshotid1, ids, &clone_count) == 0);
9613 : 12 : CU_ASSERT(clone_count == 2);
9614 : 12 : CU_ASSERT(ids[1] == blobid1);
9615 : :
9616 : : /* Create another normal blob with size equal to esnap size and make a snapshot */
9617 : 12 : ut_spdk_blob_opts_init(&opts);
9618 : 12 : opts.num_clusters = esnap_num_clusters;
9619 : 12 : opts.thin_provision = true;
9620 : 12 : blob3 = ut_blob_create_and_open(bs, &opts);
9621 [ - + ]: 12 : SPDK_CU_ASSERT_FATAL(blob3 != NULL);
9622 : 12 : blobid3 = spdk_blob_get_id(blob3);
9623 : 12 : spdk_bs_create_snapshot(bs, blobid3, NULL, blob_op_with_id_complete, NULL);
9624 : 12 : poll_threads();
9625 [ - + ]: 12 : SPDK_CU_ASSERT_FATAL(g_bserrno == 0);
9626 [ - + ]: 12 : SPDK_CU_ASSERT_FATAL(g_blobid != SPDK_BLOBID_INVALID);
9627 : 12 : snapshotid3 = g_blobid;
9628 : :
9629 : : /* Call set_parent correctly with an esnap's clone blob */
9630 : 12 : spdk_bs_blob_set_parent(bs, blobid2, snapshotid3, blob_op_complete, NULL);
9631 : 12 : poll_threads();
9632 : 12 : CU_ASSERT(g_bserrno == 0);
9633 : :
9634 : : /* Check relations */
9635 : 12 : CU_ASSERT(!spdk_blob_is_esnap_clone(blob2));
9636 : 12 : CU_ASSERT(spdk_blob_is_clone(blob2));
9637 : 12 : CU_ASSERT(spdk_blob_get_parent_snapshot(bs, blobid2) == snapshotid3);
9638 : 12 : CU_ASSERT(spdk_blob_get_clones(bs, snapshotid3, ids, &clone_count) == 0);
9639 : 12 : CU_ASSERT(clone_count == 2);
9640 : 12 : CU_ASSERT(ids[1] == blobid2);
9641 : :
9642 : : /* Create a not thin-provisioned blob that is not a clone */
9643 : 12 : ut_spdk_blob_opts_init(&opts);
9644 : 12 : opts.thin_provision = false;
9645 : 12 : blob4 = ut_blob_create_and_open(bs, &opts);
9646 [ - + ]: 12 : SPDK_CU_ASSERT_FATAL(blob4 != NULL);
9647 : 12 : blobid4 = spdk_blob_get_id(blob4);
9648 : :
9649 : : /* Call set_parent with a blob that isn't a clone and that isn't thin-provisioned */
9650 : 12 : spdk_bs_blob_set_parent(bs, blobid4, snapshotid2, blob_op_complete, NULL);
9651 : 12 : poll_threads();
9652 : 12 : CU_ASSERT(g_bserrno == -EINVAL);
9653 : :
9654 : : /* Create a thin-provisioned blob that is not a clone */
9655 : 12 : ut_spdk_blob_opts_init(&opts);
9656 : 12 : opts.thin_provision = true;
9657 : 12 : blob5 = ut_blob_create_and_open(bs, &opts);
9658 [ - + ]: 12 : SPDK_CU_ASSERT_FATAL(blob5 != NULL);
9659 : 12 : blobid5 = spdk_blob_get_id(blob5);
9660 : :
9661 : : /* Call set_parent correctly with a blob that isn't a clone */
9662 : 12 : spdk_bs_blob_set_parent(bs, blobid5, snapshotid2, blob_op_complete, NULL);
9663 : 12 : poll_threads();
9664 : 12 : CU_ASSERT(g_bserrno == 0);
9665 : :
9666 : : /* Check relations */
9667 : 12 : CU_ASSERT(spdk_blob_is_clone(blob5));
9668 : 12 : CU_ASSERT(spdk_blob_get_parent_snapshot(bs, blobid5) == snapshotid2);
9669 : 12 : CU_ASSERT(spdk_blob_get_clones(bs, snapshotid2, ids, &clone_count) == 0);
9670 : 12 : CU_ASSERT(clone_count == 1);
9671 : 12 : CU_ASSERT(ids[0] == blobid5);
9672 : :
9673 : : /* Clean up */
9674 : 12 : ut_blob_close_and_delete(bs, blob5);
9675 : 12 : ut_blob_close_and_delete(bs, blob4);
9676 : 12 : ut_blob_close_and_delete(bs, blob3);
9677 : 12 : ut_blob_close_and_delete(bs, blob2);
9678 : 12 : ut_blob_close_and_delete(bs, blob1);
9679 : 12 : spdk_bs_delete_blob(bs, snapshotid3, blob_op_complete, NULL);
9680 : 12 : poll_threads();
9681 : 12 : CU_ASSERT(g_bserrno == 0);
9682 : 12 : spdk_bs_delete_blob(bs, snapshotid2, blob_op_complete, NULL);
9683 : 12 : poll_threads();
9684 : 12 : CU_ASSERT(g_bserrno == 0);
9685 : 12 : spdk_bs_delete_blob(bs, snapshotid1, blob_op_complete, NULL);
9686 : 12 : poll_threads();
9687 : 12 : CU_ASSERT(g_bserrno == 0);
9688 : 12 : }
9689 : :
9690 : : static void
9691 : 12 : blob_set_external_parent(void)
9692 : : {
9693 : 12 : struct spdk_blob_store *bs = g_bs;
9694 : 12 : struct spdk_blob_opts opts;
9695 : 12 : struct ut_esnap_opts esnap_opts, esnap_opts2;
9696 : : struct spdk_blob *blob1, *blob2, *blob3, *blob4;
9697 : 12 : spdk_blob_id blobid1, blobid2, blobid3, blobid4, snapshotid;
9698 : : uint32_t cluster_sz, block_sz;
9699 : 12 : const uint32_t esnap_num_clusters = 4;
9700 : : uint64_t esnap_num_blocks;
9701 : : struct spdk_bs_dev *esnap_dev1, *esnap_dev2, *esnap_dev3;
9702 : 12 : const void *esnap_id;
9703 : 12 : size_t esnap_id_len;
9704 : : int rc;
9705 : :
9706 : 12 : cluster_sz = spdk_bs_get_cluster_size(bs);
9707 : 12 : block_sz = spdk_bs_get_io_unit_size(bs);
9708 [ - + ]: 12 : esnap_num_blocks = cluster_sz * esnap_num_clusters / block_sz;
9709 : 12 : esnap_dev1 = init_dev();
9710 : 12 : esnap_dev2 = init_dev();
9711 : 12 : esnap_dev3 = init_dev();
9712 : :
9713 : : /* Create an esnap clone blob */
9714 : 12 : ut_spdk_blob_opts_init(&opts);
9715 : 12 : ut_esnap_opts_init(block_sz, esnap_num_blocks, __func__, NULL, &esnap_opts);
9716 : 12 : opts.esnap_id = &esnap_opts;
9717 : 12 : opts.esnap_id_len = sizeof(esnap_opts);
9718 : 12 : opts.num_clusters = esnap_num_clusters;
9719 : 12 : blob1 = ut_blob_create_and_open(bs, &opts);
9720 [ - + ]: 12 : SPDK_CU_ASSERT_FATAL(blob1 != NULL);
9721 : 12 : blobid1 = spdk_blob_get_id(blob1);
9722 : 12 : CU_ASSERT(spdk_blob_is_esnap_clone(blob1));
9723 : :
9724 : : /* Call set_esternal_parent with blobid and esnapid the same */
9725 : 12 : spdk_bs_blob_set_external_parent(bs, blobid1, esnap_dev1, &blobid1, sizeof(blobid1),
9726 : : blob_op_complete, NULL);
9727 : 12 : CU_ASSERT(g_bserrno == -EINVAL);
9728 : :
9729 : : /* Call set_external_parent with esnap of incompatible size */
9730 : 12 : esnap_dev1->blockcnt = esnap_num_blocks - 1;
9731 : 12 : spdk_bs_blob_set_external_parent(bs, blobid1, esnap_dev1, opts.esnap_id, opts.esnap_id_len,
9732 : : blob_op_complete, NULL);
9733 : 12 : CU_ASSERT(g_bserrno == -EINVAL);
9734 : :
9735 : : /* Call set_external_parent with a blob and its parent esnap */
9736 : 12 : esnap_dev1->blocklen = block_sz;
9737 : 12 : esnap_dev1->blockcnt = esnap_num_blocks;
9738 : 12 : spdk_bs_blob_set_external_parent(bs, blobid1, esnap_dev1, opts.esnap_id, opts.esnap_id_len,
9739 : : blob_op_complete, NULL);
9740 : 12 : poll_threads();
9741 : 12 : CU_ASSERT(g_bserrno == -EEXIST);
9742 : :
9743 : : /* Create a blob that is a clone of a snapshots */
9744 : 12 : ut_spdk_blob_opts_init(&opts);
9745 : 12 : blob2 = ut_blob_create_and_open(bs, &opts);
9746 [ - + ]: 12 : SPDK_CU_ASSERT_FATAL(blob2 != NULL);
9747 : 12 : blobid2 = spdk_blob_get_id(blob2);
9748 : 12 : spdk_bs_create_snapshot(bs, blobid2, NULL, blob_op_with_id_complete, NULL);
9749 : 12 : poll_threads();
9750 [ - + ]: 12 : SPDK_CU_ASSERT_FATAL(g_bserrno == 0);
9751 [ - + ]: 12 : SPDK_CU_ASSERT_FATAL(g_blobid != SPDK_BLOBID_INVALID);
9752 : 12 : snapshotid = g_blobid;
9753 : :
9754 : : /* Call set_parent correctly with a snapshot's clone blob */
9755 : 12 : esnap_dev2->blocklen = block_sz;
9756 : 12 : esnap_dev2->blockcnt = esnap_num_blocks;
9757 : 12 : ut_esnap_opts_init(block_sz, esnap_num_blocks, __func__, NULL, &esnap_opts2);
9758 : 12 : spdk_bs_blob_set_external_parent(bs, blobid2, esnap_dev2, &esnap_opts2, sizeof(esnap_opts2),
9759 : : blob_op_complete, NULL);
9760 : 12 : poll_threads();
9761 : 12 : CU_ASSERT(g_bserrno == 0);
9762 : :
9763 : : /* Check relations */
9764 : 12 : rc = spdk_blob_get_esnap_id(blob2, &esnap_id, &esnap_id_len);
9765 : 12 : CU_ASSERT(spdk_blob_is_esnap_clone(blob2));
9766 : 12 : CU_ASSERT(!spdk_blob_is_clone(blob2));
9767 [ + - + - : 12 : CU_ASSERT(rc == 0 && esnap_id_len == sizeof(esnap_opts2) &&
+ + + - ]
9768 : : memcmp(esnap_id, &esnap_opts2, esnap_id_len) == 0);
9769 : :
9770 : : /* Create a not thin-provisioned blob that is not a clone */
9771 : 12 : ut_spdk_blob_opts_init(&opts);
9772 : 12 : opts.thin_provision = false;
9773 : 12 : blob3 = ut_blob_create_and_open(bs, &opts);
9774 [ - + ]: 12 : SPDK_CU_ASSERT_FATAL(blob3 != NULL);
9775 : 12 : blobid3 = spdk_blob_get_id(blob3);
9776 : :
9777 : : /* Call set_external_parent with a blob that isn't a clone and that isn't thin-provisioned */
9778 : 12 : spdk_bs_blob_set_external_parent(bs, blobid3, esnap_dev1, &esnap_opts, sizeof(esnap_opts),
9779 : : blob_op_complete, NULL);
9780 : 12 : poll_threads();
9781 : 12 : CU_ASSERT(g_bserrno == -EINVAL);
9782 : :
9783 : : /* Create a thin-provisioned blob that is not a clone */
9784 : 12 : ut_spdk_blob_opts_init(&opts);
9785 : 12 : opts.thin_provision = true;
9786 : 12 : blob4 = ut_blob_create_and_open(bs, &opts);
9787 [ - + ]: 12 : SPDK_CU_ASSERT_FATAL(blob4 != NULL);
9788 : 12 : blobid4 = spdk_blob_get_id(blob4);
9789 : :
9790 : : /* Call set_external_parent correctly with a blob that isn't a clone */
9791 : 12 : esnap_dev3->blocklen = block_sz;
9792 : 12 : esnap_dev3->blockcnt = esnap_num_blocks;
9793 : 12 : ut_esnap_opts_init(block_sz, esnap_num_blocks, __func__, NULL, &esnap_opts);
9794 : 12 : spdk_bs_blob_set_external_parent(bs, blobid4, esnap_dev3, &esnap_opts, sizeof(esnap_opts),
9795 : : blob_op_complete, NULL);
9796 : 12 : poll_threads();
9797 : 12 : CU_ASSERT(g_bserrno == 0);
9798 : :
9799 : : /* Check relations */
9800 : 12 : rc = spdk_blob_get_esnap_id(blob4, &esnap_id, &esnap_id_len);
9801 : 12 : CU_ASSERT(spdk_blob_is_esnap_clone(blob4));
9802 : 12 : CU_ASSERT(!spdk_blob_is_clone(blob4));
9803 [ + - + - : 12 : CU_ASSERT(rc == 0 && esnap_id_len == sizeof(esnap_opts) &&
+ + + - ]
9804 : : memcmp(esnap_id, &esnap_opts, esnap_id_len) == 0);
9805 : :
9806 : 12 : ut_blob_close_and_delete(bs, blob4);
9807 : 12 : ut_blob_close_and_delete(bs, blob3);
9808 : 12 : ut_blob_close_and_delete(bs, blob2);
9809 : 12 : ut_blob_close_and_delete(bs, blob1);
9810 : 12 : spdk_bs_delete_blob(bs, snapshotid, blob_op_complete, NULL);
9811 : 12 : dev_destroy(esnap_dev1);
9812 : 12 : poll_threads();
9813 : 12 : CU_ASSERT(g_bserrno == 0);
9814 : 12 : }
9815 : :
9816 : : static void
9817 : 660 : suite_bs_setup(void)
9818 : : {
9819 : : struct spdk_bs_dev *dev;
9820 : :
9821 : 660 : dev = init_dev();
9822 [ - + ]: 660 : memset(g_dev_buffer, 0, DEV_BUFFER_SIZE);
9823 : 660 : spdk_bs_init(dev, NULL, bs_op_with_handle_complete, NULL);
9824 : 660 : poll_threads();
9825 : 660 : CU_ASSERT(g_bserrno == 0);
9826 : 660 : CU_ASSERT(g_bs != NULL);
9827 : 660 : }
9828 : :
9829 : : static void
9830 : 108 : suite_esnap_bs_setup(void)
9831 : : {
9832 : : struct spdk_bs_dev *dev;
9833 : 108 : struct spdk_bs_opts bs_opts;
9834 : :
9835 : 108 : dev = init_dev();
9836 [ - + ]: 108 : memset(g_dev_buffer, 0, DEV_BUFFER_SIZE);
9837 : 108 : spdk_bs_opts_init(&bs_opts, sizeof(bs_opts));
9838 : 108 : bs_opts.cluster_sz = 16 * 1024;
9839 : 108 : bs_opts.esnap_bs_dev_create = ut_esnap_create;
9840 : 108 : spdk_bs_init(dev, &bs_opts, bs_op_with_handle_complete, NULL);
9841 : 108 : poll_threads();
9842 : 108 : CU_ASSERT(g_bserrno == 0);
9843 [ - + ]: 108 : SPDK_CU_ASSERT_FATAL(g_bs != NULL);
9844 : 108 : }
9845 : :
9846 : : static void
9847 : 768 : suite_bs_cleanup(void)
9848 : : {
9849 [ + - ]: 768 : if (g_bs != NULL) {
9850 : 768 : spdk_bs_unload(g_bs, bs_op_complete, NULL);
9851 : 768 : poll_threads();
9852 : 768 : CU_ASSERT(g_bserrno == 0);
9853 : 768 : g_bs = NULL;
9854 : : }
9855 [ - + ]: 768 : memset(g_dev_buffer, 0, DEV_BUFFER_SIZE);
9856 : 768 : }
9857 : :
9858 : : static struct spdk_blob *
9859 : 1080 : ut_blob_create_and_open(struct spdk_blob_store *bs, struct spdk_blob_opts *blob_opts)
9860 : : {
9861 : : struct spdk_blob *blob;
9862 : 1080 : struct spdk_blob_opts create_blob_opts;
9863 : : spdk_blob_id blobid;
9864 : :
9865 [ + + ]: 1080 : if (blob_opts == NULL) {
9866 : 384 : ut_spdk_blob_opts_init(&create_blob_opts);
9867 : 384 : blob_opts = &create_blob_opts;
9868 : : }
9869 : :
9870 : 1080 : spdk_bs_create_blob_ext(bs, blob_opts, blob_op_with_id_complete, NULL);
9871 : 1080 : poll_threads();
9872 : 1080 : CU_ASSERT(g_bserrno == 0);
9873 : 1080 : CU_ASSERT(g_blobid != SPDK_BLOBID_INVALID);
9874 : 1080 : blobid = g_blobid;
9875 : 1080 : g_blobid = -1;
9876 : :
9877 : 1080 : spdk_bs_open_blob(bs, blobid, blob_op_with_handle_complete, NULL);
9878 : 1080 : poll_threads();
9879 : 1080 : CU_ASSERT(g_bserrno == 0);
9880 : 1080 : CU_ASSERT(g_blob != NULL);
9881 : 1080 : blob = g_blob;
9882 : :
9883 : 1080 : g_blob = NULL;
9884 : 1080 : g_bserrno = -1;
9885 : :
9886 : 1080 : return blob;
9887 : : }
9888 : :
9889 : : static void
9890 : 948 : ut_blob_close_and_delete(struct spdk_blob_store *bs, struct spdk_blob *blob)
9891 : : {
9892 : 948 : spdk_blob_id blobid = spdk_blob_get_id(blob);
9893 : :
9894 : 948 : spdk_blob_close(blob, blob_op_complete, NULL);
9895 : 948 : poll_threads();
9896 : 948 : CU_ASSERT(g_bserrno == 0);
9897 : 948 : g_blob = NULL;
9898 : :
9899 : 948 : spdk_bs_delete_blob(bs, blobid, blob_op_complete, NULL);
9900 : 948 : poll_threads();
9901 : 948 : CU_ASSERT(g_bserrno == 0);
9902 : 948 : g_bserrno = -1;
9903 : 948 : }
9904 : :
9905 : : static void
9906 : 144 : suite_blob_setup(void)
9907 : : {
9908 : 144 : suite_bs_setup();
9909 : 144 : CU_ASSERT(g_bs != NULL);
9910 : :
9911 : 144 : g_blob = ut_blob_create_and_open(g_bs, NULL);
9912 : 144 : CU_ASSERT(g_blob != NULL);
9913 : 144 : }
9914 : :
9915 : : static void
9916 : 144 : suite_blob_cleanup(void)
9917 : : {
9918 : 144 : ut_blob_close_and_delete(g_bs, g_blob);
9919 : 144 : CU_ASSERT(g_blob == NULL);
9920 : :
9921 : 144 : suite_bs_cleanup();
9922 : 144 : CU_ASSERT(g_bs == NULL);
9923 : 144 : }
9924 : :
9925 : : static int
9926 : 12 : ut_setup_config_nocopy_noextent(void)
9927 : : {
9928 : 12 : g_dev_copy_enabled = false;
9929 : 12 : g_use_extent_table = false;
9930 : :
9931 : 12 : return 0;
9932 : : }
9933 : :
9934 : : static int
9935 : 12 : ut_setup_config_nocopy_extent(void)
9936 : : {
9937 : 12 : g_dev_copy_enabled = false;
9938 : 12 : g_use_extent_table = true;
9939 : :
9940 : 12 : return 0;
9941 : : }
9942 : :
9943 : : static int
9944 : 12 : ut_setup_config_copy_noextent(void)
9945 : : {
9946 : 12 : g_dev_copy_enabled = true;
9947 : 12 : g_use_extent_table = false;
9948 : :
9949 : 12 : return 0;
9950 : : }
9951 : :
9952 : : static int
9953 : 12 : ut_setup_config_copy_extent(void)
9954 : : {
9955 : 12 : g_dev_copy_enabled = true;
9956 : 12 : g_use_extent_table = true;
9957 : :
9958 : 12 : return 0;
9959 : : }
9960 : :
9961 : : struct ut_config {
9962 : : const char *suffix;
9963 : : CU_InitializeFunc setup_cb;
9964 : : };
9965 : :
9966 : : int
9967 : 3 : main(int argc, char **argv)
9968 : : {
9969 : : CU_pSuite suite, suite_bs, suite_blob, suite_esnap_bs;
9970 : : unsigned int i, num_failures;
9971 : 3 : char suite_name[4096];
9972 : : struct ut_config *config;
9973 : 3 : struct ut_config configs[] = {
9974 : : {"nocopy_noextent", ut_setup_config_nocopy_noextent},
9975 : : {"nocopy_extent", ut_setup_config_nocopy_extent},
9976 : : {"copy_noextent", ut_setup_config_copy_noextent},
9977 : : {"copy_extent", ut_setup_config_copy_extent},
9978 : : };
9979 : :
9980 : 3 : CU_initialize_registry();
9981 : :
9982 [ + + ]: 15 : for (i = 0; i < SPDK_COUNTOF(configs); ++i) {
9983 : 12 : config = &configs[i];
9984 : :
9985 [ - + ]: 12 : snprintf(suite_name, sizeof(suite_name), "blob_%s", config->suffix);
9986 : 12 : suite = CU_add_suite(suite_name, config->setup_cb, NULL);
9987 : :
9988 [ - + ]: 12 : snprintf(suite_name, sizeof(suite_name), "blob_bs_%s", config->suffix);
9989 : 12 : suite_bs = CU_add_suite_with_setup_and_teardown(suite_name, config->setup_cb, NULL,
9990 : : suite_bs_setup, suite_bs_cleanup);
9991 : :
9992 [ - + ]: 12 : snprintf(suite_name, sizeof(suite_name), "blob_blob_%s", config->suffix);
9993 : 12 : suite_blob = CU_add_suite_with_setup_and_teardown(suite_name, config->setup_cb, NULL,
9994 : : suite_blob_setup, suite_blob_cleanup);
9995 : :
9996 [ - + ]: 12 : snprintf(suite_name, sizeof(suite_name), "blob_esnap_bs_%s", config->suffix);
9997 : 12 : suite_esnap_bs = CU_add_suite_with_setup_and_teardown(suite_name, config->setup_cb, NULL,
9998 : : suite_esnap_bs_setup,
9999 : : suite_bs_cleanup);
10000 : :
10001 : 12 : CU_ADD_TEST(suite, blob_init);
10002 : 12 : CU_ADD_TEST(suite_bs, blob_open);
10003 : 12 : CU_ADD_TEST(suite_bs, blob_create);
10004 : 12 : CU_ADD_TEST(suite_bs, blob_create_loop);
10005 : 12 : CU_ADD_TEST(suite_bs, blob_create_fail);
10006 : 12 : CU_ADD_TEST(suite_bs, blob_create_internal);
10007 : 12 : CU_ADD_TEST(suite_bs, blob_create_zero_extent);
10008 : 12 : CU_ADD_TEST(suite, blob_thin_provision);
10009 : 12 : CU_ADD_TEST(suite_bs, blob_snapshot);
10010 : 12 : CU_ADD_TEST(suite_bs, blob_clone);
10011 : 12 : CU_ADD_TEST(suite_bs, blob_inflate);
10012 : 12 : CU_ADD_TEST(suite_bs, blob_delete);
10013 : 12 : CU_ADD_TEST(suite_bs, blob_resize_test);
10014 : 12 : CU_ADD_TEST(suite_bs, blob_resize_thin_test);
10015 : 12 : CU_ADD_TEST(suite, blob_read_only);
10016 : 12 : CU_ADD_TEST(suite_bs, channel_ops);
10017 : 12 : CU_ADD_TEST(suite_bs, blob_super);
10018 : 12 : CU_ADD_TEST(suite_blob, blob_write);
10019 : 12 : CU_ADD_TEST(suite_blob, blob_read);
10020 : 12 : CU_ADD_TEST(suite_blob, blob_rw_verify);
10021 : 12 : CU_ADD_TEST(suite_bs, blob_rw_verify_iov);
10022 : 12 : CU_ADD_TEST(suite_blob, blob_rw_verify_iov_nomem);
10023 : 12 : CU_ADD_TEST(suite_blob, blob_rw_iov_read_only);
10024 : 12 : CU_ADD_TEST(suite_bs, blob_unmap);
10025 : 12 : CU_ADD_TEST(suite_bs, blob_iter);
10026 : 12 : CU_ADD_TEST(suite_blob, blob_xattr);
10027 : 12 : CU_ADD_TEST(suite_bs, blob_parse_md);
10028 : 12 : CU_ADD_TEST(suite, bs_load);
10029 : 12 : CU_ADD_TEST(suite_bs, bs_load_pending_removal);
10030 : 12 : CU_ADD_TEST(suite, bs_load_custom_cluster_size);
10031 : 12 : CU_ADD_TEST(suite, bs_load_after_failed_grow);
10032 : 12 : CU_ADD_TEST(suite_bs, bs_unload);
10033 : 12 : CU_ADD_TEST(suite, bs_cluster_sz);
10034 : 12 : CU_ADD_TEST(suite_bs, bs_usable_clusters);
10035 : 12 : CU_ADD_TEST(suite, bs_resize_md);
10036 : 12 : CU_ADD_TEST(suite, bs_destroy);
10037 : 12 : CU_ADD_TEST(suite, bs_type);
10038 : 12 : CU_ADD_TEST(suite, bs_super_block);
10039 : 12 : CU_ADD_TEST(suite, bs_test_recover_cluster_count);
10040 : 12 : CU_ADD_TEST(suite, bs_grow_live);
10041 : 12 : CU_ADD_TEST(suite, bs_grow_live_no_space);
10042 : 12 : CU_ADD_TEST(suite, bs_test_grow);
10043 : 12 : CU_ADD_TEST(suite, blob_serialize_test);
10044 : 12 : CU_ADD_TEST(suite_bs, blob_crc);
10045 : 12 : CU_ADD_TEST(suite, super_block_crc);
10046 : 12 : CU_ADD_TEST(suite_blob, blob_dirty_shutdown);
10047 : 12 : CU_ADD_TEST(suite_bs, blob_flags);
10048 : 12 : CU_ADD_TEST(suite_bs, bs_version);
10049 : 12 : CU_ADD_TEST(suite_bs, blob_set_xattrs_test);
10050 : 12 : CU_ADD_TEST(suite_bs, blob_thin_prov_alloc);
10051 : 12 : CU_ADD_TEST(suite_bs, blob_insert_cluster_msg_test);
10052 : 12 : CU_ADD_TEST(suite_bs, blob_thin_prov_rw);
10053 : 12 : CU_ADD_TEST(suite, blob_thin_prov_write_count_io);
10054 : 12 : CU_ADD_TEST(suite, blob_thin_prov_unmap_cluster);
10055 : 12 : CU_ADD_TEST(suite_bs, blob_thin_prov_rle);
10056 : 12 : CU_ADD_TEST(suite_bs, blob_thin_prov_rw_iov);
10057 : 12 : CU_ADD_TEST(suite, bs_load_iter_test);
10058 : 12 : CU_ADD_TEST(suite_bs, blob_snapshot_rw);
10059 : 12 : CU_ADD_TEST(suite_bs, blob_snapshot_rw_iov);
10060 : 12 : CU_ADD_TEST(suite, blob_relations);
10061 : 12 : CU_ADD_TEST(suite, blob_relations2);
10062 : 12 : CU_ADD_TEST(suite, blob_relations3);
10063 : 12 : CU_ADD_TEST(suite, blobstore_clean_power_failure);
10064 : 12 : CU_ADD_TEST(suite, blob_delete_snapshot_power_failure);
10065 : 12 : CU_ADD_TEST(suite, blob_create_snapshot_power_failure);
10066 : 12 : CU_ADD_TEST(suite_bs, blob_inflate_rw);
10067 : 12 : CU_ADD_TEST(suite_bs, blob_snapshot_freeze_io);
10068 : 12 : CU_ADD_TEST(suite_bs, blob_operation_split_rw);
10069 : 12 : CU_ADD_TEST(suite_bs, blob_operation_split_rw_iov);
10070 : 12 : CU_ADD_TEST(suite, blob_io_unit);
10071 : 12 : CU_ADD_TEST(suite, blob_io_unit_compatibility);
10072 : 12 : CU_ADD_TEST(suite_bs, blob_simultaneous_operations);
10073 : 12 : CU_ADD_TEST(suite_bs, blob_persist_test);
10074 : 12 : CU_ADD_TEST(suite_bs, blob_decouple_snapshot);
10075 : 12 : CU_ADD_TEST(suite_bs, blob_seek_io_unit);
10076 : 12 : CU_ADD_TEST(suite_esnap_bs, blob_esnap_create);
10077 : 12 : CU_ADD_TEST(suite_bs, blob_nested_freezes);
10078 : 12 : CU_ADD_TEST(suite, blob_ext_md_pages);
10079 : 12 : CU_ADD_TEST(suite, blob_esnap_io_4096_4096);
10080 : 12 : CU_ADD_TEST(suite, blob_esnap_io_512_512);
10081 : 12 : CU_ADD_TEST(suite, blob_esnap_io_4096_512);
10082 : 12 : CU_ADD_TEST(suite, blob_esnap_io_512_4096);
10083 : 12 : CU_ADD_TEST(suite_esnap_bs, blob_esnap_thread_add_remove);
10084 : 12 : CU_ADD_TEST(suite_esnap_bs, blob_esnap_clone_snapshot);
10085 : 12 : CU_ADD_TEST(suite_esnap_bs, blob_esnap_clone_inflate);
10086 : 12 : CU_ADD_TEST(suite_esnap_bs, blob_esnap_clone_decouple);
10087 : 12 : CU_ADD_TEST(suite_esnap_bs, blob_esnap_clone_reload);
10088 : 12 : CU_ADD_TEST(suite_esnap_bs, blob_esnap_hotplug);
10089 : 12 : CU_ADD_TEST(suite_blob, blob_is_degraded);
10090 : 12 : CU_ADD_TEST(suite_bs, blob_clone_resize);
10091 : 12 : CU_ADD_TEST(suite, blob_esnap_clone_resize);
10092 : 12 : CU_ADD_TEST(suite_bs, blob_shallow_copy);
10093 : 12 : CU_ADD_TEST(suite_esnap_bs, blob_set_parent);
10094 : 12 : CU_ADD_TEST(suite_esnap_bs, blob_set_external_parent);
10095 : : }
10096 : :
10097 : 3 : allocate_threads(2);
10098 : 3 : set_thread(0);
10099 : :
10100 : 3 : g_dev_buffer = calloc(1, DEV_BUFFER_SIZE);
10101 : :
10102 : 3 : num_failures = spdk_ut_run_tests(argc, argv, NULL);
10103 : :
10104 : 3 : free(g_dev_buffer);
10105 : :
10106 : 3 : free_threads();
10107 : :
10108 : 3 : return num_failures;
10109 : : }
|