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 : : #define BLOCKLEN DEV_BUFFER_BLOCKLEN
23 : :
24 : : struct spdk_blob_store *g_bs;
25 : : spdk_blob_id g_blobid;
26 : : struct spdk_blob *g_blob, *g_blob2;
27 : : int g_bserrno, g_bserrno2;
28 : : struct spdk_xattr_names *g_names;
29 : : int g_done;
30 : : char *g_xattr_names[] = {"first", "second", "third"};
31 : : char *g_xattr_values[] = {"one", "two", "three"};
32 : : uint64_t g_ctx = 1729;
33 : : bool g_use_extent_table = false;
34 : : uint64_t g_copied_clusters_count = 0;
35 : :
36 : : struct spdk_bs_super_block_ver1 {
37 : : uint8_t signature[8];
38 : : uint32_t version;
39 : : uint32_t length;
40 : : uint32_t clean; /* If there was a clean shutdown, this is 1. */
41 : : spdk_blob_id super_blob;
42 : :
43 : : uint32_t cluster_size; /* In bytes */
44 : :
45 : : uint32_t used_page_mask_start; /* Offset from beginning of disk, in pages */
46 : : uint32_t used_page_mask_len; /* Count, in pages */
47 : :
48 : : uint32_t used_cluster_mask_start; /* Offset from beginning of disk, in pages */
49 : : uint32_t used_cluster_mask_len; /* Count, in pages */
50 : :
51 : : uint32_t md_start; /* Offset from beginning of disk, in pages */
52 : : uint32_t md_len; /* Count, in pages */
53 : :
54 : : uint8_t reserved[4036];
55 : : uint32_t crc;
56 : : } __attribute__((packed));
57 : : SPDK_STATIC_ASSERT(sizeof(struct spdk_bs_super_block_ver1) == 0x1000, "Invalid super block size");
58 : :
59 : : static struct spdk_blob *ut_blob_create_and_open(struct spdk_blob_store *bs,
60 : : struct spdk_blob_opts *blob_opts);
61 : : static void ut_blob_close_and_delete(struct spdk_blob_store *bs, struct spdk_blob *blob);
62 : : static void suite_blob_setup(void);
63 : : static void suite_blob_cleanup(void);
64 : :
65 [ # # # # ]: 0 : DEFINE_STUB(spdk_memory_domain_memzero, int, (struct spdk_memory_domain *src_domain,
66 : : void *src_domain_ctx, struct iovec *iov, uint32_t iovcnt, void (*cpl_cb)(void *, int),
67 : : void *cpl_cb_arg), 0);
68 : :
69 : : static bool
70 : 36 : is_esnap_clone(struct spdk_blob *_blob, const void *id, size_t id_len)
71 : : {
72 : 36 : const void *val = NULL;
73 : 36 : size_t len = 0;
74 : : bool c0, c1, c2, c3;
75 : :
76 : 36 : CU_ASSERT(blob_get_xattr_value(_blob, BLOB_EXTERNAL_SNAPSHOT_ID, &val, &len,
77 : : true) == 0);
78 : 36 : CU_ASSERT((c0 = (len == id_len)));
79 [ - + ]: 36 : CU_ASSERT((c1 = (val != NULL && memcmp(val, id, len) == 0)));
80 : 36 : CU_ASSERT((c2 = !!(_blob->invalid_flags & SPDK_BLOB_EXTERNAL_SNAPSHOT)));
81 : 36 : CU_ASSERT((c3 = (_blob->parent_id == SPDK_BLOBID_EXTERNAL_SNAPSHOT)));
82 : :
83 [ + - + - : 36 : return c0 && c1 && c2 && c3;
- + ]
84 : : }
85 : :
86 : : static bool
87 : 20 : is_not_esnap_clone(struct spdk_blob *_blob)
88 : : {
89 : 20 : const void *val = NULL;
90 : 20 : size_t len = 0;
91 : : bool c1, c2, c3, c4;
92 : :
93 : 20 : CU_ASSERT((c1 = (blob_get_xattr_value(_blob, BLOB_EXTERNAL_SNAPSHOT_ID, &val, &len,
94 : : true) == -ENOENT)));
95 : 20 : CU_ASSERT((c2 = (val == NULL)));
96 : 20 : CU_ASSERT((c3 = ((_blob->invalid_flags & SPDK_BLOB_EXTERNAL_SNAPSHOT) == 0)));
97 : 20 : CU_ASSERT((c4 = (_blob->parent_id != SPDK_BLOBID_EXTERNAL_SNAPSHOT)));
98 : :
99 [ + - + - : 20 : return c1 && c2 && c3 && c4;
- + ]
100 : : }
101 : :
102 : : #define UT_ASSERT_IS_ESNAP_CLONE(_blob, _id, _len) CU_ASSERT(is_esnap_clone(_blob, _id, _len))
103 : : #define UT_ASSERT_IS_NOT_ESNAP_CLONE(_blob) CU_ASSERT(is_not_esnap_clone(_blob))
104 : :
105 : : static void
106 : 48 : _get_xattr_value(void *arg, const char *name,
107 : : const void **value, size_t *value_len)
108 : : {
109 : : uint64_t i;
110 : :
111 [ + - ]: 48 : SPDK_CU_ASSERT_FATAL(value_len != NULL);
112 [ - + ]: 48 : SPDK_CU_ASSERT_FATAL(value != NULL);
113 : 48 : CU_ASSERT(arg == &g_ctx);
114 : :
115 [ - + ]: 96 : for (i = 0; i < sizeof(g_xattr_names); i++) {
116 [ + + ]: 96 : if (!strcmp(name, g_xattr_names[i])) {
117 : 48 : *value_len = strlen(g_xattr_values[i]);
118 : 48 : *value = g_xattr_values[i];
119 : 48 : break;
120 : : }
121 : 48 : }
122 : 48 : }
123 : :
124 : : static void
125 : 4 : _get_xattr_value_null(void *arg, const char *name,
126 : : const void **value, size_t *value_len)
127 : : {
128 [ + - ]: 4 : SPDK_CU_ASSERT_FATAL(value_len != NULL);
129 [ - + ]: 4 : SPDK_CU_ASSERT_FATAL(value != NULL);
130 : 4 : CU_ASSERT(arg == NULL);
131 : :
132 : 4 : *value_len = 0;
133 : 4 : *value = NULL;
134 : 4 : }
135 : :
136 : : static int
137 : 64 : _get_snapshots_count(struct spdk_blob_store *bs)
138 : : {
139 : 64 : struct spdk_blob_list *snapshot = NULL;
140 : 64 : int count = 0;
141 : :
142 [ + + ]: 124 : TAILQ_FOREACH(snapshot, &bs->snapshots, link) {
143 : 60 : count += 1;
144 : 60 : }
145 : :
146 : 64 : return count;
147 : : }
148 : :
149 : : static void
150 : 1526 : ut_spdk_blob_opts_init(struct spdk_blob_opts *opts)
151 : : {
152 : 1526 : spdk_blob_opts_init(opts, sizeof(*opts));
153 : 1526 : opts->use_extent_table = g_use_extent_table;
154 : 1526 : }
155 : :
156 : : static void
157 : 9302 : bs_op_complete(void *cb_arg, int bserrno)
158 : : {
159 : 9302 : g_bserrno = bserrno;
160 : 9302 : }
161 : :
162 : : static void
163 : 784 : bs_op_with_handle_complete(void *cb_arg, struct spdk_blob_store *bs,
164 : : int bserrno)
165 : : {
166 : 784 : g_bs = bs;
167 : 784 : g_bserrno = bserrno;
168 : 784 : }
169 : :
170 : : static void
171 : 32986 : blob_op_complete(void *cb_arg, int bserrno)
172 : : {
173 [ + + ]: 32986 : if (cb_arg != NULL) {
174 : 20 : int *errp = cb_arg;
175 : :
176 : 20 : *errp = bserrno;
177 : 20 : }
178 : 32986 : g_bserrno = bserrno;
179 : 32986 : }
180 : :
181 : : static void
182 : 1904 : blob_op_with_id_complete(void *cb_arg, spdk_blob_id blobid, int bserrno)
183 : : {
184 : 1904 : g_blobid = blobid;
185 : 1904 : g_bserrno = bserrno;
186 : 1904 : }
187 : :
188 : : static void
189 : 982 : blob_op_with_handle_complete(void *cb_arg, struct spdk_blob *blb, int bserrno)
190 : : {
191 : 982 : g_blob = blb;
192 : 982 : g_bserrno = bserrno;
193 : 982 : }
194 : :
195 : : static void
196 : 8 : blob_op_with_handle_complete2(void *cb_arg, struct spdk_blob *blob, int bserrno)
197 : : {
198 [ + + ]: 8 : if (g_blob == NULL) {
199 : 4 : g_blob = blob;
200 : 4 : g_bserrno = bserrno;
201 : 4 : } else {
202 : 4 : g_blob2 = blob;
203 : 4 : g_bserrno2 = bserrno;
204 : : }
205 : 8 : }
206 : :
207 : : static void
208 : 8 : blob_shallow_copy_status_cb(uint64_t copied_clusters, void *cb_arg)
209 : : {
210 : 8 : g_copied_clusters_count = copied_clusters;
211 : 8 : }
212 : :
213 : : static void
214 : 108 : ut_bs_reload(struct spdk_blob_store **bs, struct spdk_bs_opts *opts)
215 : : {
216 : : struct spdk_bs_dev *dev;
217 : :
218 : : /* Unload the blob store */
219 : 108 : spdk_bs_unload(*bs, bs_op_complete, NULL);
220 : 108 : poll_threads();
221 : 108 : CU_ASSERT(g_bserrno == 0);
222 : :
223 : 108 : dev = init_dev();
224 : : /* Load an existing blob store */
225 : 108 : spdk_bs_load(dev, opts, bs_op_with_handle_complete, NULL);
226 : 108 : poll_threads();
227 : 108 : CU_ASSERT(g_bserrno == 0);
228 [ + - ]: 108 : SPDK_CU_ASSERT_FATAL(g_bs != NULL);
229 : 108 : *bs = g_bs;
230 : :
231 : 108 : g_bserrno = -1;
232 : 108 : }
233 : :
234 : : static void
235 : 90 : ut_bs_dirty_load(struct spdk_blob_store **bs, struct spdk_bs_opts *opts)
236 : : {
237 : : struct spdk_bs_dev *dev;
238 : :
239 : : /* Dirty shutdown */
240 : 90 : bs_free(*bs);
241 : :
242 : 90 : dev = init_dev();
243 : : /* Load an existing blob store */
244 : 90 : spdk_bs_load(dev, opts, bs_op_with_handle_complete, NULL);
245 : 90 : poll_threads();
246 : 90 : CU_ASSERT(g_bserrno == 0);
247 [ + - ]: 90 : SPDK_CU_ASSERT_FATAL(g_bs != NULL);
248 : 90 : *bs = g_bs;
249 : :
250 : 90 : g_bserrno = -1;
251 : 90 : }
252 : :
253 : : static void
254 : 4 : blob_init(void)
255 : : {
256 : : struct spdk_blob_store *bs;
257 : : struct spdk_bs_dev *dev;
258 : :
259 : 4 : dev = init_dev();
260 : :
261 : : /* should fail for an unsupported blocklen */
262 : 4 : dev->blocklen = 500;
263 : 4 : spdk_bs_init(dev, NULL, bs_op_with_handle_complete, NULL);
264 : 4 : poll_threads();
265 : 4 : CU_ASSERT(g_bserrno == -EINVAL);
266 : :
267 : 4 : dev = init_dev();
268 : 4 : spdk_bs_init(dev, NULL, bs_op_with_handle_complete, NULL);
269 : 4 : poll_threads();
270 : 4 : CU_ASSERT(g_bserrno == 0);
271 [ + - ]: 4 : SPDK_CU_ASSERT_FATAL(g_bs != NULL);
272 : 4 : bs = g_bs;
273 : :
274 : 4 : spdk_bs_unload(bs, bs_op_complete, NULL);
275 : 4 : poll_threads();
276 : 4 : CU_ASSERT(g_bserrno == 0);
277 : 4 : g_bs = NULL;
278 : 4 : }
279 : :
280 : : static void
281 : 4 : blob_super(void)
282 : : {
283 : 4 : struct spdk_blob_store *bs = g_bs;
284 : : spdk_blob_id blobid;
285 : : struct spdk_blob_opts blob_opts;
286 : :
287 : : /* Get the super blob without having set one */
288 : 4 : spdk_bs_get_super(bs, blob_op_with_id_complete, NULL);
289 : 4 : poll_threads();
290 : 4 : CU_ASSERT(g_bserrno == -ENOENT);
291 : 4 : CU_ASSERT(g_blobid == SPDK_BLOBID_INVALID);
292 : :
293 : : /* Create a blob */
294 : 4 : ut_spdk_blob_opts_init(&blob_opts);
295 : 4 : spdk_bs_create_blob_ext(bs, &blob_opts, blob_op_with_id_complete, NULL);
296 : 4 : poll_threads();
297 : 4 : CU_ASSERT(g_bserrno == 0);
298 : 4 : CU_ASSERT(g_blobid != SPDK_BLOBID_INVALID);
299 : 4 : blobid = g_blobid;
300 : :
301 : : /* Set the blob as the super blob */
302 : 4 : spdk_bs_set_super(bs, blobid, blob_op_complete, NULL);
303 : 4 : poll_threads();
304 : 4 : CU_ASSERT(g_bserrno == 0);
305 : :
306 : : /* Get the super blob */
307 : 4 : spdk_bs_get_super(bs, blob_op_with_id_complete, NULL);
308 : 4 : poll_threads();
309 : 4 : CU_ASSERT(g_bserrno == 0);
310 : 4 : CU_ASSERT(blobid == g_blobid);
311 : 4 : }
312 : :
313 : : static void
314 : 4 : blob_open(void)
315 : : {
316 : 4 : struct spdk_blob_store *bs = g_bs;
317 : : struct spdk_blob *blob;
318 : : struct spdk_blob_opts blob_opts;
319 : : spdk_blob_id blobid, blobid2;
320 : :
321 : 4 : ut_spdk_blob_opts_init(&blob_opts);
322 : 4 : spdk_bs_create_blob_ext(bs, &blob_opts, blob_op_with_id_complete, NULL);
323 : 4 : poll_threads();
324 : 4 : CU_ASSERT(g_bserrno == 0);
325 : 4 : CU_ASSERT(g_blobid != SPDK_BLOBID_INVALID);
326 : 4 : blobid = g_blobid;
327 : :
328 : 4 : spdk_bs_open_blob(bs, blobid, blob_op_with_handle_complete, NULL);
329 : 4 : poll_threads();
330 : 4 : CU_ASSERT(g_bserrno == 0);
331 : 4 : CU_ASSERT(g_blob != NULL);
332 : 4 : blob = g_blob;
333 : :
334 : 4 : blobid2 = spdk_blob_get_id(blob);
335 : 4 : CU_ASSERT(blobid == blobid2);
336 : :
337 : : /* Try to open file again. It should return success. */
338 : 4 : spdk_bs_open_blob(bs, blobid, blob_op_with_handle_complete, NULL);
339 : 4 : poll_threads();
340 : 4 : CU_ASSERT(g_bserrno == 0);
341 : 4 : CU_ASSERT(blob == g_blob);
342 : :
343 : 4 : spdk_blob_close(blob, blob_op_complete, NULL);
344 : 4 : poll_threads();
345 : 4 : CU_ASSERT(g_bserrno == 0);
346 : :
347 : : /*
348 : : * Close the file a second time, releasing the second reference. This
349 : : * should succeed.
350 : : */
351 : 4 : blob = g_blob;
352 : 4 : spdk_blob_close(blob, blob_op_complete, NULL);
353 : 4 : poll_threads();
354 : 4 : CU_ASSERT(g_bserrno == 0);
355 : :
356 : : /*
357 : : * Try to open file again. It should succeed. This tests the case
358 : : * where the file is opened, closed, then re-opened again.
359 : : */
360 : 4 : spdk_bs_open_blob(bs, blobid, blob_op_with_handle_complete, NULL);
361 : 4 : poll_threads();
362 : 4 : CU_ASSERT(g_bserrno == 0);
363 : 4 : CU_ASSERT(g_blob != NULL);
364 : 4 : blob = g_blob;
365 : 4 : spdk_blob_close(blob, blob_op_complete, NULL);
366 : 4 : poll_threads();
367 : 4 : CU_ASSERT(g_bserrno == 0);
368 : :
369 : : /* Try to open file twice in succession. This should return the same
370 : : * blob object.
371 : : */
372 : 4 : g_blob = NULL;
373 : 4 : g_blob2 = NULL;
374 : 4 : g_bserrno = -1;
375 : 4 : g_bserrno2 = -1;
376 : 4 : spdk_bs_open_blob(bs, blobid, blob_op_with_handle_complete2, NULL);
377 : 4 : spdk_bs_open_blob(bs, blobid, blob_op_with_handle_complete2, NULL);
378 : 4 : poll_threads();
379 : 4 : CU_ASSERT(g_bserrno == 0);
380 : 4 : CU_ASSERT(g_bserrno2 == 0);
381 : 4 : CU_ASSERT(g_blob != NULL);
382 : 4 : CU_ASSERT(g_blob2 != NULL);
383 : 4 : CU_ASSERT(g_blob == g_blob2);
384 : :
385 : 4 : g_bserrno = -1;
386 : 4 : spdk_blob_close(g_blob, blob_op_complete, NULL);
387 : 4 : poll_threads();
388 : 4 : CU_ASSERT(g_bserrno == 0);
389 : :
390 : 4 : ut_blob_close_and_delete(bs, g_blob);
391 : 4 : }
392 : :
393 : : static void
394 : 4 : blob_create(void)
395 : : {
396 : 4 : struct spdk_blob_store *bs = g_bs;
397 : : struct spdk_blob *blob;
398 : : struct spdk_blob_opts opts;
399 : : spdk_blob_id blobid;
400 : :
401 : : /* Create blob with 10 clusters */
402 : :
403 : 4 : ut_spdk_blob_opts_init(&opts);
404 : 4 : opts.num_clusters = 10;
405 : :
406 : 4 : spdk_bs_create_blob_ext(bs, &opts, blob_op_with_id_complete, NULL);
407 : 4 : poll_threads();
408 : 4 : CU_ASSERT(g_bserrno == 0);
409 : 4 : CU_ASSERT(g_blobid != SPDK_BLOBID_INVALID);
410 : 4 : blobid = g_blobid;
411 : :
412 : 4 : spdk_bs_open_blob(bs, blobid, blob_op_with_handle_complete, NULL);
413 : 4 : poll_threads();
414 : 4 : CU_ASSERT(g_bserrno == 0);
415 [ + - ]: 4 : SPDK_CU_ASSERT_FATAL(g_blob != NULL);
416 : 4 : blob = g_blob;
417 : 4 : CU_ASSERT(spdk_blob_get_num_clusters(blob) == 10);
418 : 4 : CU_ASSERT(spdk_blob_get_num_allocated_clusters(blob) == 10);
419 : :
420 : 4 : spdk_blob_close(blob, blob_op_complete, NULL);
421 : 4 : poll_threads();
422 : 4 : CU_ASSERT(g_bserrno == 0);
423 : :
424 : : /* Create blob with 0 clusters */
425 : :
426 : 4 : ut_spdk_blob_opts_init(&opts);
427 : 4 : opts.num_clusters = 0;
428 : :
429 : 4 : spdk_bs_create_blob_ext(bs, &opts, blob_op_with_id_complete, NULL);
430 : 4 : poll_threads();
431 : 4 : CU_ASSERT(g_bserrno == 0);
432 : 4 : CU_ASSERT(g_blobid != SPDK_BLOBID_INVALID);
433 : 4 : blobid = g_blobid;
434 : :
435 : 4 : spdk_bs_open_blob(bs, blobid, blob_op_with_handle_complete, NULL);
436 : 4 : poll_threads();
437 : 4 : CU_ASSERT(g_bserrno == 0);
438 [ + - ]: 4 : SPDK_CU_ASSERT_FATAL(g_blob != NULL);
439 : 4 : blob = g_blob;
440 : 4 : CU_ASSERT(spdk_blob_get_num_clusters(blob) == 0);
441 : 4 : CU_ASSERT(spdk_blob_get_num_allocated_clusters(blob) == 0);
442 : :
443 : 4 : spdk_blob_close(blob, blob_op_complete, NULL);
444 : 4 : poll_threads();
445 : 4 : CU_ASSERT(g_bserrno == 0);
446 : :
447 : : /* Create blob with default options (opts == NULL) */
448 : :
449 : 4 : spdk_bs_create_blob_ext(bs, NULL, blob_op_with_id_complete, NULL);
450 : 4 : poll_threads();
451 : 4 : CU_ASSERT(g_bserrno == 0);
452 : 4 : CU_ASSERT(g_blobid != SPDK_BLOBID_INVALID);
453 : 4 : blobid = g_blobid;
454 : :
455 : 4 : spdk_bs_open_blob(bs, blobid, blob_op_with_handle_complete, NULL);
456 : 4 : poll_threads();
457 : 4 : CU_ASSERT(g_bserrno == 0);
458 [ - + ]: 4 : SPDK_CU_ASSERT_FATAL(g_blob != NULL);
459 : 4 : blob = g_blob;
460 : 4 : CU_ASSERT(spdk_blob_get_num_clusters(blob) == 0);
461 : 4 : CU_ASSERT(spdk_blob_get_num_allocated_clusters(blob) == 0);
462 : :
463 : 4 : spdk_blob_close(blob, blob_op_complete, NULL);
464 : 4 : poll_threads();
465 : 4 : CU_ASSERT(g_bserrno == 0);
466 : :
467 : : /* Try to create blob with size larger than blobstore */
468 : :
469 : 4 : ut_spdk_blob_opts_init(&opts);
470 : 4 : opts.num_clusters = bs->total_clusters + 1;
471 : :
472 : 4 : spdk_bs_create_blob_ext(bs, &opts, blob_op_with_id_complete, NULL);
473 : 4 : poll_threads();
474 : 4 : CU_ASSERT(g_bserrno == -ENOSPC);
475 : 4 : }
476 : :
477 : : static void
478 : 4 : blob_create_zero_extent(void)
479 : : {
480 : 4 : struct spdk_blob_store *bs = g_bs;
481 : : struct spdk_blob *blob;
482 : : spdk_blob_id blobid;
483 : :
484 : : /* Create blob with default options (opts == NULL) */
485 : 4 : spdk_bs_create_blob_ext(bs, NULL, blob_op_with_id_complete, NULL);
486 : 4 : poll_threads();
487 : 4 : CU_ASSERT(g_bserrno == 0);
488 : 4 : CU_ASSERT(g_blobid != SPDK_BLOBID_INVALID);
489 : 4 : blobid = g_blobid;
490 : :
491 : 4 : spdk_bs_open_blob(bs, blobid, blob_op_with_handle_complete, NULL);
492 : 4 : poll_threads();
493 : 4 : CU_ASSERT(g_bserrno == 0);
494 [ + - ]: 4 : SPDK_CU_ASSERT_FATAL(g_blob != NULL);
495 : 4 : blob = g_blob;
496 : 4 : CU_ASSERT(spdk_blob_get_num_clusters(blob) == 0);
497 : 4 : CU_ASSERT(blob->extent_table_found == true);
498 : 4 : CU_ASSERT(blob->active.extent_pages_array_size == 0);
499 : 4 : CU_ASSERT(blob->active.extent_pages == NULL);
500 : :
501 : 4 : spdk_blob_close(blob, blob_op_complete, NULL);
502 : 4 : poll_threads();
503 : 4 : CU_ASSERT(g_bserrno == 0);
504 : :
505 : : /* Create blob with NULL internal options */
506 : 4 : bs_create_blob(bs, NULL, NULL, blob_op_with_id_complete, NULL);
507 : 4 : poll_threads();
508 : 4 : CU_ASSERT(g_bserrno == 0);
509 : 4 : CU_ASSERT(g_blobid != SPDK_BLOBID_INVALID);
510 : 4 : blobid = g_blobid;
511 : :
512 : 4 : spdk_bs_open_blob(bs, blobid, blob_op_with_handle_complete, NULL);
513 : 4 : poll_threads();
514 : 4 : CU_ASSERT(g_bserrno == 0);
515 [ - + ]: 4 : SPDK_CU_ASSERT_FATAL(g_blob != NULL);
516 : 4 : blob = g_blob;
517 : 4 : CU_ASSERT(TAILQ_FIRST(&blob->xattrs_internal) == NULL);
518 : 4 : CU_ASSERT(spdk_blob_get_num_clusters(blob) == 0);
519 : 4 : CU_ASSERT(blob->extent_table_found == true);
520 : 4 : CU_ASSERT(blob->active.extent_pages_array_size == 0);
521 : 4 : CU_ASSERT(blob->active.extent_pages == NULL);
522 : :
523 : 4 : spdk_blob_close(blob, blob_op_complete, NULL);
524 : 4 : poll_threads();
525 : 4 : CU_ASSERT(g_bserrno == 0);
526 : 4 : }
527 : :
528 : : /*
529 : : * Create and delete one blob in a loop over and over again. This helps ensure
530 : : * that the internal bit masks tracking used clusters and md_pages are being
531 : : * tracked correctly.
532 : : */
533 : : static void
534 : 4 : blob_create_loop(void)
535 : : {
536 : 4 : struct spdk_blob_store *bs = g_bs;
537 : : struct spdk_blob_opts opts;
538 : : uint32_t i, loop_count;
539 : :
540 [ - + ]: 4 : loop_count = 4 * spdk_max(spdk_bit_array_capacity(bs->used_md_pages),
541 : : spdk_bit_pool_capacity(bs->used_clusters));
542 : :
543 [ + + ]: 1028 : for (i = 0; i < loop_count; i++) {
544 : 1024 : ut_spdk_blob_opts_init(&opts);
545 : 1024 : opts.num_clusters = 1;
546 : 1024 : g_bserrno = -1;
547 : 1024 : g_blobid = SPDK_BLOBID_INVALID;
548 : 1024 : spdk_bs_create_blob_ext(bs, &opts, blob_op_with_id_complete, NULL);
549 : 1024 : poll_threads();
550 : 1024 : CU_ASSERT(g_bserrno == 0);
551 : 1024 : CU_ASSERT(g_blobid != SPDK_BLOBID_INVALID);
552 : 1024 : spdk_bs_delete_blob(bs, g_blobid, blob_op_complete, NULL);
553 : 1024 : poll_threads();
554 : 1024 : CU_ASSERT(g_bserrno == 0);
555 : 1024 : }
556 : 4 : }
557 : :
558 : : static void
559 : 4 : blob_create_fail(void)
560 : : {
561 : 4 : struct spdk_blob_store *bs = g_bs;
562 : : struct spdk_blob_opts opts;
563 : : spdk_blob_id blobid;
564 : 4 : uint32_t used_blobids_count = spdk_bit_array_count_set(bs->used_blobids);
565 : 4 : uint32_t used_md_pages_count = spdk_bit_array_count_set(bs->used_md_pages);
566 : :
567 : : /* NULL callback */
568 : 4 : ut_spdk_blob_opts_init(&opts);
569 : 4 : opts.xattrs.names = g_xattr_names;
570 : 4 : opts.xattrs.get_value = NULL;
571 : 4 : opts.xattrs.count = 1;
572 : 4 : opts.xattrs.ctx = &g_ctx;
573 : :
574 : 4 : blobid = spdk_bit_array_find_first_clear(bs->used_md_pages, 0);
575 : 4 : spdk_bs_create_blob_ext(bs, &opts, blob_op_with_id_complete, NULL);
576 : 4 : poll_threads();
577 : 4 : CU_ASSERT(g_bserrno == -EINVAL);
578 : 4 : CU_ASSERT(g_blobid != SPDK_BLOBID_INVALID);
579 : 4 : CU_ASSERT(spdk_bit_array_count_set(bs->used_blobids) == used_blobids_count);
580 : 4 : CU_ASSERT(spdk_bit_array_count_set(bs->used_md_pages) == used_md_pages_count);
581 : :
582 : 4 : spdk_bs_open_blob(bs, blobid, blob_op_with_handle_complete, NULL);
583 : 4 : poll_threads();
584 : 4 : CU_ASSERT(g_bserrno == -ENOENT);
585 [ + - ]: 4 : SPDK_CU_ASSERT_FATAL(g_blob == NULL);
586 : :
587 : 4 : ut_bs_reload(&bs, NULL);
588 : 4 : CU_ASSERT(spdk_bit_array_count_set(bs->used_blobids) == used_blobids_count);
589 : 4 : CU_ASSERT(spdk_bit_array_count_set(bs->used_md_pages) == used_md_pages_count);
590 : :
591 : 4 : spdk_bs_iter_first(bs, blob_op_with_handle_complete, NULL);
592 : 4 : poll_threads();
593 : 4 : CU_ASSERT(g_blob == NULL);
594 : 4 : CU_ASSERT(g_bserrno == -ENOENT);
595 : 4 : }
596 : :
597 : : static void
598 : 4 : blob_create_internal(void)
599 : : {
600 : 4 : struct spdk_blob_store *bs = g_bs;
601 : : struct spdk_blob *blob;
602 : : struct spdk_blob_opts opts;
603 : : struct spdk_blob_xattr_opts internal_xattrs;
604 : : const void *value;
605 : : size_t value_len;
606 : : spdk_blob_id blobid;
607 : : int rc;
608 : :
609 : : /* Create blob with custom xattrs */
610 : :
611 : 4 : ut_spdk_blob_opts_init(&opts);
612 : 4 : blob_xattrs_init(&internal_xattrs);
613 : 4 : internal_xattrs.count = 3;
614 : 4 : internal_xattrs.names = g_xattr_names;
615 : 4 : internal_xattrs.get_value = _get_xattr_value;
616 : 4 : internal_xattrs.ctx = &g_ctx;
617 : :
618 : 4 : bs_create_blob(bs, &opts, &internal_xattrs, blob_op_with_id_complete, NULL);
619 : 4 : poll_threads();
620 : 4 : CU_ASSERT(g_bserrno == 0);
621 : 4 : CU_ASSERT(g_blobid != SPDK_BLOBID_INVALID);
622 : 4 : blobid = g_blobid;
623 : :
624 : 4 : spdk_bs_open_blob(bs, blobid, blob_op_with_handle_complete, NULL);
625 : 4 : poll_threads();
626 : 4 : CU_ASSERT(g_bserrno == 0);
627 [ + - ]: 4 : SPDK_CU_ASSERT_FATAL(g_blob != NULL);
628 : 4 : blob = g_blob;
629 : :
630 : 4 : rc = blob_get_xattr_value(blob, g_xattr_names[0], &value, &value_len, true);
631 : 4 : CU_ASSERT(rc == 0);
632 [ + - ]: 4 : SPDK_CU_ASSERT_FATAL(value != NULL);
633 : 4 : CU_ASSERT(value_len == strlen(g_xattr_values[0]));
634 : 4 : CU_ASSERT_NSTRING_EQUAL_FATAL(value, g_xattr_values[0], value_len);
635 : :
636 : 4 : rc = blob_get_xattr_value(blob, g_xattr_names[1], &value, &value_len, true);
637 : 4 : CU_ASSERT(rc == 0);
638 [ + - ]: 4 : SPDK_CU_ASSERT_FATAL(value != NULL);
639 : 4 : CU_ASSERT(value_len == strlen(g_xattr_values[1]));
640 : 4 : CU_ASSERT_NSTRING_EQUAL((char *)value, g_xattr_values[1], value_len);
641 : :
642 : 4 : rc = blob_get_xattr_value(blob, g_xattr_names[2], &value, &value_len, true);
643 : 4 : CU_ASSERT(rc == 0);
644 [ + - ]: 4 : SPDK_CU_ASSERT_FATAL(value != NULL);
645 : 4 : CU_ASSERT(value_len == strlen(g_xattr_values[2]));
646 : 4 : CU_ASSERT_NSTRING_EQUAL((char *)value, g_xattr_values[2], value_len);
647 : :
648 : 4 : rc = spdk_blob_get_xattr_value(blob, g_xattr_names[0], &value, &value_len);
649 : 4 : CU_ASSERT(rc != 0);
650 : :
651 : 4 : rc = spdk_blob_get_xattr_value(blob, g_xattr_names[1], &value, &value_len);
652 : 4 : CU_ASSERT(rc != 0);
653 : :
654 : 4 : rc = spdk_blob_get_xattr_value(blob, g_xattr_names[2], &value, &value_len);
655 : 4 : CU_ASSERT(rc != 0);
656 : :
657 : 4 : spdk_blob_close(blob, blob_op_complete, NULL);
658 : 4 : poll_threads();
659 : 4 : CU_ASSERT(g_bserrno == 0);
660 : :
661 : : /* Create blob with NULL internal options */
662 : :
663 : 4 : bs_create_blob(bs, NULL, NULL, blob_op_with_id_complete, NULL);
664 : 4 : poll_threads();
665 : 4 : CU_ASSERT(g_bserrno == 0);
666 : 4 : CU_ASSERT(g_blobid != SPDK_BLOBID_INVALID);
667 : 4 : blobid = g_blobid;
668 : :
669 : 4 : spdk_bs_open_blob(bs, blobid, blob_op_with_handle_complete, NULL);
670 : 4 : poll_threads();
671 : 4 : CU_ASSERT(g_bserrno == 0);
672 [ - + ]: 4 : SPDK_CU_ASSERT_FATAL(g_blob != NULL);
673 : 4 : CU_ASSERT(TAILQ_FIRST(&g_blob->xattrs_internal) == NULL);
674 : 4 : CU_ASSERT(spdk_blob_get_num_clusters(g_blob) == 0);
675 : :
676 : 4 : blob = g_blob;
677 : :
678 : 4 : spdk_blob_close(blob, blob_op_complete, NULL);
679 : 4 : poll_threads();
680 : 4 : CU_ASSERT(g_bserrno == 0);
681 : 4 : }
682 : :
683 : : static void
684 : 4 : blob_thin_provision(void)
685 : : {
686 : : struct spdk_blob_store *bs;
687 : : struct spdk_bs_dev *dev;
688 : : struct spdk_blob *blob;
689 : : struct spdk_blob_opts opts;
690 : : struct spdk_bs_opts bs_opts;
691 : : spdk_blob_id blobid;
692 : :
693 : 4 : dev = init_dev();
694 : 4 : spdk_bs_opts_init(&bs_opts, sizeof(bs_opts));
695 : 4 : snprintf(bs_opts.bstype.bstype, sizeof(bs_opts.bstype.bstype), "TESTTYPE");
696 : :
697 : : /* Initialize a new blob store */
698 : 4 : spdk_bs_init(dev, &bs_opts, bs_op_with_handle_complete, NULL);
699 : 4 : poll_threads();
700 : 4 : CU_ASSERT(g_bserrno == 0);
701 [ + - ]: 4 : SPDK_CU_ASSERT_FATAL(g_bs != NULL);
702 : :
703 : 4 : bs = g_bs;
704 : :
705 : : /* Create blob with thin provisioning enabled */
706 : :
707 : 4 : ut_spdk_blob_opts_init(&opts);
708 : 4 : opts.thin_provision = true;
709 : 4 : opts.num_clusters = 10;
710 : :
711 : 4 : blob = ut_blob_create_and_open(bs, &opts);
712 : 4 : blobid = spdk_blob_get_id(blob);
713 : 4 : CU_ASSERT(blob->invalid_flags & SPDK_BLOB_THIN_PROV);
714 : 4 : CU_ASSERT(spdk_blob_get_num_allocated_clusters(blob) == 0);
715 : : /* In thin provisioning with num_clusters is set, if not using the
716 : : * extent table, there is no allocation. If extent table is used,
717 : : * there is related allocation happened. */
718 [ + + ]: 4 : if (blob->extent_table_found == true) {
719 : 2 : CU_ASSERT(blob->active.extent_pages_array_size > 0);
720 : 2 : CU_ASSERT(blob->active.extent_pages != NULL);
721 : 2 : } else {
722 : 2 : CU_ASSERT(blob->active.extent_pages_array_size == 0);
723 : 2 : CU_ASSERT(blob->active.extent_pages == NULL);
724 : : }
725 : :
726 : 4 : spdk_blob_close(blob, blob_op_complete, NULL);
727 : 4 : CU_ASSERT(g_bserrno == 0);
728 : :
729 : : /* Do not shut down cleanly. This makes sure that when we load again
730 : : * and try to recover a valid used_cluster map, that blobstore will
731 : : * ignore clusters with index 0 since these are unallocated clusters.
732 : : */
733 : 4 : ut_bs_dirty_load(&bs, &bs_opts);
734 : :
735 : 4 : spdk_bs_open_blob(bs, blobid, blob_op_with_handle_complete, NULL);
736 : 4 : poll_threads();
737 : 4 : CU_ASSERT(g_bserrno == 0);
738 [ - + ]: 4 : SPDK_CU_ASSERT_FATAL(g_blob != NULL);
739 : 4 : blob = g_blob;
740 : 4 : CU_ASSERT(blob->invalid_flags & SPDK_BLOB_THIN_PROV);
741 : 4 : CU_ASSERT(spdk_blob_get_num_allocated_clusters(blob) == 0);
742 : :
743 : 4 : ut_blob_close_and_delete(bs, blob);
744 : :
745 : 4 : spdk_bs_unload(bs, bs_op_complete, NULL);
746 : 4 : poll_threads();
747 : 4 : CU_ASSERT(g_bserrno == 0);
748 : 4 : g_bs = NULL;
749 : 4 : }
750 : :
751 : : static void
752 : 4 : blob_snapshot(void)
753 : : {
754 : 4 : struct spdk_blob_store *bs = g_bs;
755 : : struct spdk_blob *blob;
756 : : struct spdk_blob *snapshot, *snapshot2;
757 : : struct spdk_blob_bs_dev *blob_bs_dev;
758 : : struct spdk_blob_opts opts;
759 : : struct spdk_blob_xattr_opts xattrs;
760 : : spdk_blob_id blobid;
761 : : spdk_blob_id snapshotid;
762 : : spdk_blob_id snapshotid2;
763 : : const void *value;
764 : : size_t value_len;
765 : : int rc;
766 : : spdk_blob_id ids[2];
767 : : size_t count;
768 : :
769 : : /* Create blob with 10 clusters */
770 : 4 : ut_spdk_blob_opts_init(&opts);
771 : 4 : opts.num_clusters = 10;
772 : :
773 : 4 : blob = ut_blob_create_and_open(bs, &opts);
774 : 4 : blobid = spdk_blob_get_id(blob);
775 : 4 : CU_ASSERT(spdk_blob_get_num_clusters(blob) == 10);
776 : :
777 : : /* Create snapshot from blob */
778 : 4 : CU_ASSERT_EQUAL(_get_snapshots_count(bs), 0);
779 : 4 : spdk_bs_create_snapshot(bs, blobid, NULL, blob_op_with_id_complete, NULL);
780 : 4 : poll_threads();
781 : 4 : CU_ASSERT(g_bserrno == 0);
782 : 4 : CU_ASSERT(g_blobid != SPDK_BLOBID_INVALID);
783 : 4 : CU_ASSERT_EQUAL(_get_snapshots_count(bs), 1);
784 : 4 : snapshotid = g_blobid;
785 : :
786 : 4 : spdk_bs_open_blob(bs, snapshotid, blob_op_with_handle_complete, NULL);
787 : 4 : poll_threads();
788 : 4 : CU_ASSERT(g_bserrno == 0);
789 [ + - ]: 4 : SPDK_CU_ASSERT_FATAL(g_blob != NULL);
790 : 4 : snapshot = g_blob;
791 : 4 : CU_ASSERT(snapshot->data_ro == true);
792 : 4 : CU_ASSERT(snapshot->md_ro == true);
793 : 4 : CU_ASSERT(spdk_blob_get_num_clusters(snapshot) == 10);
794 : 4 : CU_ASSERT(spdk_blob_get_num_allocated_clusters(snapshot) == 10);
795 : :
796 : 4 : CU_ASSERT(spdk_blob_get_num_clusters(blob) == 10);
797 : 4 : CU_ASSERT(spdk_blob_get_num_allocated_clusters(blob) == 0);
798 : 4 : CU_ASSERT(blob->invalid_flags & SPDK_BLOB_THIN_PROV);
799 : 4 : CU_ASSERT(spdk_mem_all_zero(blob->active.clusters,
800 : : blob->active.num_clusters * sizeof(blob->active.clusters[0])));
801 : :
802 : : /* Try to create snapshot from clone with xattrs */
803 : 4 : xattrs.names = g_xattr_names;
804 : 4 : xattrs.get_value = _get_xattr_value;
805 : 4 : xattrs.count = 3;
806 : 4 : xattrs.ctx = &g_ctx;
807 : 4 : spdk_bs_create_snapshot(bs, blobid, &xattrs, blob_op_with_id_complete, NULL);
808 : 4 : poll_threads();
809 : 4 : CU_ASSERT(g_bserrno == 0);
810 : 4 : CU_ASSERT(g_blobid != SPDK_BLOBID_INVALID);
811 : 4 : CU_ASSERT_EQUAL(_get_snapshots_count(bs), 2);
812 : 4 : snapshotid2 = g_blobid;
813 : :
814 : 4 : spdk_bs_open_blob(bs, snapshotid2, blob_op_with_handle_complete, NULL);
815 : 4 : CU_ASSERT(g_bserrno == 0);
816 [ + - ]: 4 : SPDK_CU_ASSERT_FATAL(g_blob != NULL);
817 : 4 : snapshot2 = g_blob;
818 : 4 : CU_ASSERT(snapshot2->data_ro == true);
819 : 4 : CU_ASSERT(snapshot2->md_ro == true);
820 : 4 : CU_ASSERT(spdk_blob_get_num_clusters(snapshot2) == 10);
821 : 4 : CU_ASSERT(spdk_blob_get_num_allocated_clusters(snapshot2) == 0);
822 : :
823 : : /* Confirm that blob is backed by snapshot2 and snapshot2 is backed by snapshot */
824 : 4 : CU_ASSERT(snapshot->back_bs_dev == NULL);
825 [ + - ]: 4 : SPDK_CU_ASSERT_FATAL(blob->back_bs_dev != NULL);
826 [ + - ]: 4 : SPDK_CU_ASSERT_FATAL(snapshot2->back_bs_dev != NULL);
827 : :
828 : 4 : blob_bs_dev = (struct spdk_blob_bs_dev *)blob->back_bs_dev;
829 : 4 : CU_ASSERT(blob_bs_dev->blob == snapshot2);
830 : :
831 : 4 : blob_bs_dev = (struct spdk_blob_bs_dev *)snapshot2->back_bs_dev;
832 : 4 : CU_ASSERT(blob_bs_dev->blob == snapshot);
833 : :
834 : 4 : rc = spdk_blob_get_xattr_value(snapshot2, g_xattr_names[0], &value, &value_len);
835 : 4 : CU_ASSERT(rc == 0);
836 [ + - ]: 4 : SPDK_CU_ASSERT_FATAL(value != NULL);
837 : 4 : CU_ASSERT(value_len == strlen(g_xattr_values[0]));
838 : 4 : CU_ASSERT_NSTRING_EQUAL_FATAL(value, g_xattr_values[0], value_len);
839 : :
840 : 4 : rc = spdk_blob_get_xattr_value(snapshot2, g_xattr_names[1], &value, &value_len);
841 : 4 : CU_ASSERT(rc == 0);
842 [ + - ]: 4 : SPDK_CU_ASSERT_FATAL(value != NULL);
843 : 4 : CU_ASSERT(value_len == strlen(g_xattr_values[1]));
844 : 4 : CU_ASSERT_NSTRING_EQUAL((char *)value, g_xattr_values[1], value_len);
845 : :
846 : 4 : rc = spdk_blob_get_xattr_value(snapshot2, g_xattr_names[2], &value, &value_len);
847 : 4 : CU_ASSERT(rc == 0);
848 [ - + ]: 4 : SPDK_CU_ASSERT_FATAL(value != NULL);
849 : 4 : CU_ASSERT(value_len == strlen(g_xattr_values[2]));
850 : 4 : CU_ASSERT_NSTRING_EQUAL((char *)value, g_xattr_values[2], value_len);
851 : :
852 : : /* Confirm that blob is clone of snapshot2, and snapshot2 is clone of snapshot */
853 : 4 : count = 2;
854 : 4 : CU_ASSERT(spdk_blob_get_clones(bs, snapshotid2, ids, &count) == 0);
855 : 4 : CU_ASSERT(count == 1);
856 : 4 : CU_ASSERT(ids[0] == blobid);
857 : :
858 : 4 : count = 2;
859 : 4 : CU_ASSERT(spdk_blob_get_clones(bs, snapshotid, ids, &count) == 0);
860 : 4 : CU_ASSERT(count == 1);
861 : 4 : CU_ASSERT(ids[0] == snapshotid2);
862 : :
863 : : /* Try to create snapshot from snapshot */
864 : 4 : spdk_bs_create_snapshot(bs, snapshotid, NULL, blob_op_with_id_complete, NULL);
865 : 4 : poll_threads();
866 : 4 : CU_ASSERT(g_bserrno == -EINVAL);
867 : 4 : CU_ASSERT(g_blobid == SPDK_BLOBID_INVALID);
868 : 4 : CU_ASSERT_EQUAL(_get_snapshots_count(bs), 2);
869 : :
870 : : /* Delete blob and confirm that it is no longer on snapshot2 clone list */
871 : 4 : ut_blob_close_and_delete(bs, blob);
872 : 4 : count = 2;
873 : 4 : CU_ASSERT(spdk_blob_get_clones(bs, snapshotid2, ids, &count) == 0);
874 : 4 : CU_ASSERT(count == 0);
875 : :
876 : : /* Delete snapshot2 and confirm that it is no longer on snapshot clone list */
877 : 4 : ut_blob_close_and_delete(bs, snapshot2);
878 : 4 : CU_ASSERT_EQUAL(_get_snapshots_count(bs), 1);
879 : 4 : count = 2;
880 : 4 : CU_ASSERT(spdk_blob_get_clones(bs, snapshotid2, ids, &count) == 0);
881 : 4 : CU_ASSERT(count == 0);
882 : :
883 : 4 : ut_blob_close_and_delete(bs, snapshot);
884 : 4 : CU_ASSERT_EQUAL(_get_snapshots_count(bs), 0);
885 : 4 : }
886 : :
887 : : static void
888 : 4 : blob_snapshot_freeze_io(void)
889 : : {
890 : : struct spdk_io_channel *channel;
891 : : struct spdk_bs_channel *bs_channel;
892 : 4 : struct spdk_blob_store *bs = g_bs;
893 : : struct spdk_blob *blob;
894 : : struct spdk_blob_opts opts;
895 : : spdk_blob_id blobid;
896 : 4 : uint32_t num_of_pages = 10;
897 : 4 : uint8_t payload_read[num_of_pages * BLOCKLEN];
898 : 4 : uint8_t payload_write[num_of_pages * BLOCKLEN];
899 : 4 : uint8_t payload_zero[num_of_pages * BLOCKLEN];
900 : :
901 : 4 : memset(payload_write, 0xE5, sizeof(payload_write));
902 : 4 : memset(payload_read, 0x00, sizeof(payload_read));
903 : 4 : memset(payload_zero, 0x00, sizeof(payload_zero));
904 : :
905 : : /* Test freeze I/O during snapshot */
906 : 4 : channel = spdk_bs_alloc_io_channel(bs);
907 : 4 : bs_channel = spdk_io_channel_get_ctx(channel);
908 : :
909 : : /* Create blob with 10 clusters */
910 : 4 : ut_spdk_blob_opts_init(&opts);
911 : 4 : opts.num_clusters = 10;
912 : 4 : opts.thin_provision = false;
913 : :
914 : 4 : blob = ut_blob_create_and_open(bs, &opts);
915 : 4 : blobid = spdk_blob_get_id(blob);
916 : 4 : CU_ASSERT(spdk_blob_get_num_clusters(blob) == 10);
917 : :
918 : 4 : spdk_bs_create_snapshot(bs, blobid, NULL, blob_op_with_id_complete, NULL);
919 : :
920 : : /* This is implementation specific.
921 : : * Flag 'frozen_io' is set in _spdk_bs_snapshot_freeze_cpl callback.
922 : : * Four async I/O operations happen before that. */
923 : 4 : poll_thread_times(0, 5);
924 : :
925 : 4 : CU_ASSERT(TAILQ_EMPTY(&bs_channel->queued_io));
926 : :
927 : : /* Blob I/O should be frozen here */
928 : 4 : CU_ASSERT(blob->frozen_refcnt == 1);
929 : :
930 : : /* Write to the blob */
931 : 4 : spdk_blob_io_write(blob, channel, payload_write, 0, num_of_pages, blob_op_complete, NULL);
932 : :
933 : : /* Verify that I/O is queued */
934 : 4 : CU_ASSERT(!TAILQ_EMPTY(&bs_channel->queued_io));
935 : : /* Verify that payload is not written to disk, at this point the blobs already switched */
936 : 4 : CU_ASSERT(blob->active.clusters[0] == 0);
937 : :
938 : : /* Finish all operations including spdk_bs_create_snapshot */
939 : 4 : poll_threads();
940 : :
941 : : /* Verify snapshot */
942 : 4 : CU_ASSERT(g_bserrno == 0);
943 : 4 : CU_ASSERT(g_blobid != SPDK_BLOBID_INVALID);
944 : :
945 : : /* Verify that blob has unset frozen_io */
946 : 4 : CU_ASSERT(blob->frozen_refcnt == 0);
947 : :
948 : : /* Verify that postponed I/O completed successfully by comparing payload */
949 : 4 : spdk_blob_io_read(blob, channel, payload_read, 0, num_of_pages, blob_op_complete, NULL);
950 : 4 : poll_threads();
951 : 4 : CU_ASSERT(g_bserrno == 0);
952 : 4 : CU_ASSERT(memcmp(payload_write, payload_read, num_of_pages * BLOCKLEN) == 0);
953 : :
954 : 4 : spdk_bs_free_io_channel(channel);
955 : 4 : poll_threads();
956 : :
957 : 4 : ut_blob_close_and_delete(bs, blob);
958 : 4 : }
959 : :
960 : : static void
961 : 4 : blob_clone(void)
962 : : {
963 : 4 : struct spdk_blob_store *bs = g_bs;
964 : : struct spdk_blob_opts opts;
965 : : struct spdk_blob *blob, *snapshot, *clone;
966 : : spdk_blob_id blobid, cloneid, snapshotid;
967 : : struct spdk_blob_xattr_opts xattrs;
968 : : const void *value;
969 : : size_t value_len;
970 : : int rc;
971 : :
972 : : /* Create blob with 10 clusters */
973 : :
974 : 4 : ut_spdk_blob_opts_init(&opts);
975 : 4 : opts.num_clusters = 10;
976 : :
977 : 4 : blob = ut_blob_create_and_open(bs, &opts);
978 : 4 : blobid = spdk_blob_get_id(blob);
979 : 4 : CU_ASSERT(spdk_blob_get_num_clusters(blob) == 10);
980 : :
981 : : /* Create snapshot */
982 : 4 : spdk_bs_create_snapshot(bs, blobid, NULL, blob_op_with_id_complete, NULL);
983 : 4 : poll_threads();
984 : 4 : CU_ASSERT(g_bserrno == 0);
985 : 4 : CU_ASSERT(g_blobid != SPDK_BLOBID_INVALID);
986 : 4 : snapshotid = g_blobid;
987 : :
988 : 4 : spdk_bs_open_blob(bs, snapshotid, blob_op_with_handle_complete, NULL);
989 : 4 : poll_threads();
990 : 4 : CU_ASSERT(g_bserrno == 0);
991 [ + - ]: 4 : SPDK_CU_ASSERT_FATAL(g_blob != NULL);
992 : 4 : snapshot = g_blob;
993 : 4 : CU_ASSERT(snapshot->data_ro == true);
994 : 4 : CU_ASSERT(snapshot->md_ro == true);
995 : 4 : CU_ASSERT(spdk_blob_get_num_clusters(snapshot) == 10);
996 : :
997 : 4 : spdk_blob_close(snapshot, blob_op_complete, NULL);
998 : 4 : poll_threads();
999 : 4 : CU_ASSERT(g_bserrno == 0);
1000 : :
1001 : : /* Create clone from snapshot with xattrs */
1002 : 4 : xattrs.names = g_xattr_names;
1003 : 4 : xattrs.get_value = _get_xattr_value;
1004 : 4 : xattrs.count = 3;
1005 : 4 : xattrs.ctx = &g_ctx;
1006 : :
1007 : 4 : spdk_bs_create_clone(bs, snapshotid, &xattrs, blob_op_with_id_complete, NULL);
1008 : 4 : poll_threads();
1009 : 4 : CU_ASSERT(g_bserrno == 0);
1010 : 4 : CU_ASSERT(g_blobid != SPDK_BLOBID_INVALID);
1011 : 4 : cloneid = g_blobid;
1012 : :
1013 : 4 : spdk_bs_open_blob(bs, cloneid, blob_op_with_handle_complete, NULL);
1014 : 4 : poll_threads();
1015 : 4 : CU_ASSERT(g_bserrno == 0);
1016 [ + - ]: 4 : SPDK_CU_ASSERT_FATAL(g_blob != NULL);
1017 : 4 : clone = g_blob;
1018 : 4 : CU_ASSERT(clone->data_ro == false);
1019 : 4 : CU_ASSERT(clone->md_ro == false);
1020 : 4 : CU_ASSERT(spdk_blob_get_num_clusters(clone) == 10);
1021 : 4 : CU_ASSERT(spdk_blob_get_num_allocated_clusters(clone) == 0);
1022 : :
1023 : 4 : rc = spdk_blob_get_xattr_value(clone, g_xattr_names[0], &value, &value_len);
1024 : 4 : CU_ASSERT(rc == 0);
1025 [ + - ]: 4 : SPDK_CU_ASSERT_FATAL(value != NULL);
1026 : 4 : CU_ASSERT(value_len == strlen(g_xattr_values[0]));
1027 : 4 : CU_ASSERT_NSTRING_EQUAL_FATAL(value, g_xattr_values[0], value_len);
1028 : :
1029 : 4 : rc = spdk_blob_get_xattr_value(clone, g_xattr_names[1], &value, &value_len);
1030 : 4 : CU_ASSERT(rc == 0);
1031 [ + - ]: 4 : SPDK_CU_ASSERT_FATAL(value != NULL);
1032 : 4 : CU_ASSERT(value_len == strlen(g_xattr_values[1]));
1033 : 4 : CU_ASSERT_NSTRING_EQUAL((char *)value, g_xattr_values[1], value_len);
1034 : :
1035 : 4 : rc = spdk_blob_get_xattr_value(clone, g_xattr_names[2], &value, &value_len);
1036 : 4 : CU_ASSERT(rc == 0);
1037 [ + - ]: 4 : SPDK_CU_ASSERT_FATAL(value != NULL);
1038 : 4 : CU_ASSERT(value_len == strlen(g_xattr_values[2]));
1039 : 4 : CU_ASSERT_NSTRING_EQUAL((char *)value, g_xattr_values[2], value_len);
1040 : :
1041 : :
1042 : 4 : spdk_blob_close(clone, blob_op_complete, NULL);
1043 : 4 : poll_threads();
1044 : 4 : CU_ASSERT(g_bserrno == 0);
1045 : :
1046 : : /* Try to create clone from not read only blob */
1047 : 4 : spdk_bs_create_clone(bs, blobid, NULL, blob_op_with_id_complete, NULL);
1048 : 4 : poll_threads();
1049 : 4 : CU_ASSERT(g_bserrno == -EINVAL);
1050 : 4 : CU_ASSERT(g_blobid == SPDK_BLOBID_INVALID);
1051 : :
1052 : : /* Mark blob as read only */
1053 : 4 : spdk_blob_set_read_only(blob);
1054 : 4 : spdk_blob_sync_md(blob, blob_op_complete, NULL);
1055 : 4 : poll_threads();
1056 : 4 : CU_ASSERT(g_bserrno == 0);
1057 : :
1058 : : /* Create clone from read only blob */
1059 : 4 : spdk_bs_create_clone(bs, blobid, NULL, blob_op_with_id_complete, NULL);
1060 : 4 : poll_threads();
1061 : 4 : CU_ASSERT(g_bserrno == 0);
1062 : 4 : CU_ASSERT(g_blobid != SPDK_BLOBID_INVALID);
1063 : 4 : cloneid = g_blobid;
1064 : :
1065 : 4 : spdk_bs_open_blob(bs, cloneid, blob_op_with_handle_complete, NULL);
1066 : 4 : poll_threads();
1067 : 4 : CU_ASSERT(g_bserrno == 0);
1068 [ - + ]: 4 : SPDK_CU_ASSERT_FATAL(g_blob != NULL);
1069 : 4 : clone = g_blob;
1070 : 4 : CU_ASSERT(clone->data_ro == false);
1071 : 4 : CU_ASSERT(clone->md_ro == false);
1072 : 4 : CU_ASSERT(spdk_blob_get_num_clusters(clone) == 10);
1073 : :
1074 : 4 : ut_blob_close_and_delete(bs, clone);
1075 : 4 : ut_blob_close_and_delete(bs, blob);
1076 : 4 : }
1077 : :
1078 : : static void
1079 : 8 : _blob_inflate(bool decouple_parent)
1080 : : {
1081 : 8 : struct spdk_blob_store *bs = g_bs;
1082 : : struct spdk_blob_opts opts;
1083 : : struct spdk_blob *blob, *snapshot;
1084 : : spdk_blob_id blobid, snapshotid;
1085 : : struct spdk_io_channel *channel;
1086 : : uint64_t free_clusters;
1087 : :
1088 : 8 : channel = spdk_bs_alloc_io_channel(bs);
1089 [ + - ]: 8 : SPDK_CU_ASSERT_FATAL(channel != NULL);
1090 : :
1091 : : /* Create blob with 10 clusters */
1092 : :
1093 : 8 : ut_spdk_blob_opts_init(&opts);
1094 : 8 : opts.num_clusters = 10;
1095 : 8 : opts.thin_provision = true;
1096 : :
1097 : 8 : blob = ut_blob_create_and_open(bs, &opts);
1098 : 8 : blobid = spdk_blob_get_id(blob);
1099 : 8 : CU_ASSERT(spdk_blob_get_num_clusters(blob) == 10);
1100 : 8 : CU_ASSERT(spdk_blob_is_thin_provisioned(blob) == true);
1101 : 8 : CU_ASSERT(spdk_blob_get_num_allocated_clusters(blob) == 0);
1102 : :
1103 : : /* 1) Blob with no parent */
1104 [ + + ]: 8 : if (decouple_parent) {
1105 : : /* Decouple parent of blob with no parent (should fail) */
1106 : 4 : spdk_bs_blob_decouple_parent(bs, channel, blobid, blob_op_complete, NULL);
1107 : 4 : poll_threads();
1108 : 4 : CU_ASSERT(g_bserrno != 0);
1109 : 4 : } else {
1110 : : /* Inflate of thin blob with no parent should made it thick */
1111 : 4 : spdk_bs_inflate_blob(bs, channel, blobid, blob_op_complete, NULL);
1112 : 4 : poll_threads();
1113 : 4 : CU_ASSERT(g_bserrno == 0);
1114 : 4 : CU_ASSERT(spdk_blob_is_thin_provisioned(blob) == false);
1115 : 4 : CU_ASSERT(spdk_blob_get_num_allocated_clusters(blob) == 10);
1116 : : }
1117 : :
1118 : 8 : spdk_bs_create_snapshot(bs, blobid, NULL, blob_op_with_id_complete, NULL);
1119 : 8 : poll_threads();
1120 : 8 : CU_ASSERT(g_bserrno == 0);
1121 : 8 : CU_ASSERT(g_blobid != SPDK_BLOBID_INVALID);
1122 : 8 : snapshotid = g_blobid;
1123 : :
1124 : 8 : CU_ASSERT(spdk_blob_is_thin_provisioned(blob) == true);
1125 : 8 : CU_ASSERT(spdk_blob_get_num_clusters(blob) == 10);
1126 : :
1127 : 8 : spdk_bs_open_blob(bs, snapshotid, blob_op_with_handle_complete, NULL);
1128 : 8 : poll_threads();
1129 : 8 : CU_ASSERT(g_bserrno == 0);
1130 [ - + ]: 8 : SPDK_CU_ASSERT_FATAL(g_blob != NULL);
1131 : 8 : snapshot = g_blob;
1132 : 8 : CU_ASSERT(snapshot->data_ro == true);
1133 : 8 : CU_ASSERT(snapshot->md_ro == true);
1134 : 8 : CU_ASSERT(spdk_blob_get_num_clusters(snapshot) == 10);
1135 : :
1136 : 8 : spdk_blob_close(snapshot, blob_op_complete, NULL);
1137 : 8 : poll_threads();
1138 : 8 : CU_ASSERT(g_bserrno == 0);
1139 : :
1140 : 8 : free_clusters = spdk_bs_free_cluster_count(bs);
1141 : :
1142 : : /* 2) Blob with parent */
1143 [ + + ]: 8 : if (!decouple_parent) {
1144 : : /* Do full blob inflation */
1145 : 4 : spdk_bs_inflate_blob(bs, channel, blobid, blob_op_complete, NULL);
1146 : 4 : poll_threads();
1147 : 4 : CU_ASSERT(g_bserrno == 0);
1148 : : /* all 10 clusters should be allocated */
1149 : 4 : CU_ASSERT(spdk_bs_free_cluster_count(bs) == free_clusters - 10);
1150 : 4 : CU_ASSERT(spdk_blob_get_num_allocated_clusters(blob) == 10);
1151 : 4 : } else {
1152 : : /* Decouple parent of blob */
1153 : 4 : spdk_bs_blob_decouple_parent(bs, channel, blobid, blob_op_complete, NULL);
1154 : 4 : poll_threads();
1155 : 4 : CU_ASSERT(g_bserrno == 0);
1156 : : /* when only parent is removed, none of the clusters should be allocated */
1157 : 4 : CU_ASSERT(spdk_bs_free_cluster_count(bs) == free_clusters);
1158 : 4 : CU_ASSERT(spdk_blob_get_num_allocated_clusters(blob) == 0);
1159 : : }
1160 : :
1161 : : /* Now, it should be possible to delete snapshot */
1162 : 8 : spdk_bs_delete_blob(bs, snapshotid, blob_op_complete, NULL);
1163 : 8 : poll_threads();
1164 : 8 : CU_ASSERT(g_bserrno == 0);
1165 : :
1166 : 8 : CU_ASSERT(spdk_blob_get_num_clusters(blob) == 10);
1167 : 8 : CU_ASSERT(spdk_blob_is_thin_provisioned(blob) == decouple_parent);
1168 : :
1169 : 8 : spdk_bs_free_io_channel(channel);
1170 : 8 : poll_threads();
1171 : :
1172 : 8 : ut_blob_close_and_delete(bs, blob);
1173 : 8 : }
1174 : :
1175 : : static void
1176 : 4 : blob_inflate(void)
1177 : : {
1178 : 4 : _blob_inflate(false);
1179 : 4 : _blob_inflate(true);
1180 : 4 : }
1181 : :
1182 : : static void
1183 : 4 : blob_delete(void)
1184 : : {
1185 : 4 : struct spdk_blob_store *bs = g_bs;
1186 : : struct spdk_blob_opts blob_opts;
1187 : : spdk_blob_id blobid;
1188 : :
1189 : : /* Create a blob and then delete it. */
1190 : 4 : ut_spdk_blob_opts_init(&blob_opts);
1191 : 4 : spdk_bs_create_blob_ext(bs, &blob_opts, blob_op_with_id_complete, NULL);
1192 : 4 : poll_threads();
1193 : 4 : CU_ASSERT(g_bserrno == 0);
1194 : 4 : CU_ASSERT(g_blobid > 0);
1195 : 4 : blobid = g_blobid;
1196 : :
1197 : 4 : spdk_bs_delete_blob(bs, blobid, blob_op_complete, NULL);
1198 : 4 : poll_threads();
1199 : 4 : CU_ASSERT(g_bserrno == 0);
1200 : :
1201 : : /* Try to open the blob */
1202 : 4 : spdk_bs_open_blob(bs, blobid, blob_op_with_handle_complete, NULL);
1203 : 4 : poll_threads();
1204 : 4 : CU_ASSERT(g_bserrno == -ENOENT);
1205 : 4 : }
1206 : :
1207 : : static void
1208 : 4 : blob_resize_test(void)
1209 : : {
1210 : 4 : struct spdk_blob_store *bs = g_bs;
1211 : : struct spdk_blob *blob;
1212 : : uint64_t free_clusters;
1213 : :
1214 : 4 : free_clusters = spdk_bs_free_cluster_count(bs);
1215 : :
1216 : 4 : blob = ut_blob_create_and_open(bs, NULL);
1217 : 4 : CU_ASSERT(free_clusters == spdk_bs_free_cluster_count(bs));
1218 : 4 : CU_ASSERT(spdk_blob_get_num_allocated_clusters(blob) == 0);
1219 : :
1220 : : /* Confirm that resize fails if blob is marked read-only. */
1221 : 4 : blob->md_ro = true;
1222 : 4 : spdk_blob_resize(blob, 5, blob_op_complete, NULL);
1223 : 4 : poll_threads();
1224 : 4 : CU_ASSERT(g_bserrno == -EPERM);
1225 : 4 : blob->md_ro = false;
1226 : :
1227 : : /* The blob started at 0 clusters. Resize it to be 5. */
1228 : 4 : spdk_blob_resize(blob, 5, blob_op_complete, NULL);
1229 : 4 : poll_threads();
1230 : 4 : CU_ASSERT(g_bserrno == 0);
1231 : 4 : CU_ASSERT((free_clusters - 5) == spdk_bs_free_cluster_count(bs));
1232 : 4 : CU_ASSERT(spdk_blob_get_num_allocated_clusters(blob) == 5);
1233 : :
1234 : : /* Shrink the blob to 3 clusters. This will not actually release
1235 : : * the old clusters until the blob is synced.
1236 : : */
1237 : 4 : spdk_blob_resize(blob, 3, blob_op_complete, NULL);
1238 : 4 : poll_threads();
1239 : 4 : CU_ASSERT(g_bserrno == 0);
1240 : : /* Verify there are still 5 clusters in use */
1241 : 4 : CU_ASSERT((free_clusters - 5) == spdk_bs_free_cluster_count(bs));
1242 : 4 : CU_ASSERT(spdk_blob_get_num_allocated_clusters(blob) == 3);
1243 : :
1244 : 4 : spdk_blob_sync_md(blob, blob_op_complete, NULL);
1245 : 4 : poll_threads();
1246 : 4 : CU_ASSERT(g_bserrno == 0);
1247 : : /* Now there are only 3 clusters in use */
1248 : 4 : CU_ASSERT((free_clusters - 3) == spdk_bs_free_cluster_count(bs));
1249 : :
1250 : : /* Resize the blob to be 10 clusters. Growth takes effect immediately. */
1251 : 4 : spdk_blob_resize(blob, 10, blob_op_complete, NULL);
1252 : 4 : poll_threads();
1253 : 4 : CU_ASSERT(g_bserrno == 0);
1254 : 4 : CU_ASSERT((free_clusters - 10) == spdk_bs_free_cluster_count(bs));
1255 : 4 : CU_ASSERT(spdk_blob_get_num_allocated_clusters(blob) == 10);
1256 : :
1257 : : /* Try to resize the blob to size larger than blobstore. */
1258 : 4 : spdk_blob_resize(blob, bs->total_clusters + 1, blob_op_complete, NULL);
1259 : 4 : poll_threads();
1260 : 4 : CU_ASSERT(g_bserrno == -ENOSPC);
1261 : :
1262 : 4 : ut_blob_close_and_delete(bs, blob);
1263 : 4 : }
1264 : :
1265 : : static void
1266 : 4 : blob_resize_thin_test(void)
1267 : : {
1268 : 4 : struct spdk_blob_store *bs = g_bs;
1269 : : struct spdk_blob *blob;
1270 : : struct spdk_blob_opts opts;
1271 : : struct spdk_io_channel *blob_ch;
1272 : : uint64_t free_clusters;
1273 : : uint64_t io_units_per_cluster;
1274 : : uint64_t offset;
1275 : : uint8_t buf1[DEV_BUFFER_BLOCKLEN];
1276 : :
1277 : 4 : free_clusters = spdk_bs_free_cluster_count(bs);
1278 : :
1279 : 4 : blob_ch = spdk_bs_alloc_io_channel(bs);
1280 [ + - ]: 4 : SPDK_CU_ASSERT_FATAL(blob_ch != NULL);
1281 : :
1282 : : /* Create blob with thin provisioning enabled */
1283 : 4 : ut_spdk_blob_opts_init(&opts);
1284 : 4 : opts.thin_provision = true;
1285 : 4 : opts.num_clusters = 0;
1286 : :
1287 : 4 : blob = ut_blob_create_and_open(bs, &opts);
1288 : 4 : CU_ASSERT((free_clusters) == spdk_bs_free_cluster_count(bs));
1289 : 4 : CU_ASSERT(spdk_blob_get_num_allocated_clusters(blob) == 0);
1290 : 4 : io_units_per_cluster = bs_io_units_per_cluster(blob);
1291 : :
1292 : : /* The blob started at 0 clusters. Resize it to be 6. */
1293 : 4 : spdk_blob_resize(blob, 6, blob_op_complete, NULL);
1294 : 4 : poll_threads();
1295 : 4 : CU_ASSERT(g_bserrno == 0);
1296 : 4 : CU_ASSERT((free_clusters) == spdk_bs_free_cluster_count(bs));
1297 : 4 : CU_ASSERT(spdk_blob_get_num_allocated_clusters(blob) == 0);
1298 : :
1299 : : /* Write on cluster 0,2,4 and 5 of blob */
1300 [ + + ]: 1028 : for (offset = 0; offset < io_units_per_cluster; offset++) {
1301 : 1024 : spdk_blob_io_write(blob, blob_ch, buf1, offset, 1, blob_op_complete, NULL);
1302 : 1024 : poll_threads();
1303 : 1024 : CU_ASSERT(g_bserrno == 0);
1304 : 1024 : }
1305 [ + + ]: 1028 : for (offset = 2 * io_units_per_cluster; offset < 3 * io_units_per_cluster; offset++) {
1306 : 1024 : spdk_blob_io_write(blob, blob_ch, buf1, offset, 1, blob_op_complete, NULL);
1307 : 1024 : poll_threads();
1308 : 1024 : CU_ASSERT(g_bserrno == 0);
1309 : 1024 : }
1310 [ + + ]: 1028 : for (offset = 4 * io_units_per_cluster; offset < 5 * io_units_per_cluster; offset++) {
1311 : 1024 : spdk_blob_io_write(blob, blob_ch, buf1, offset, 1, blob_op_complete, NULL);
1312 : 1024 : poll_threads();
1313 : 1024 : CU_ASSERT(g_bserrno == 0);
1314 : 1024 : }
1315 [ + + ]: 1028 : for (offset = 5 * io_units_per_cluster; offset < 6 * io_units_per_cluster; offset++) {
1316 : 1024 : spdk_blob_io_write(blob, blob_ch, buf1, offset, 1, blob_op_complete, NULL);
1317 : 1024 : poll_threads();
1318 : 1024 : CU_ASSERT(g_bserrno == 0);
1319 : 1024 : }
1320 : :
1321 : : /* Check allocated clusters after write */
1322 : 4 : CU_ASSERT((free_clusters - 4) == spdk_bs_free_cluster_count(bs));
1323 : 4 : CU_ASSERT(spdk_blob_get_num_allocated_clusters(blob) == 4);
1324 : :
1325 : : /* Shrink the blob to 2 clusters. This will not actually release
1326 : : * the old clusters until the blob is synced.
1327 : : */
1328 : 4 : spdk_blob_resize(blob, 2, blob_op_complete, NULL);
1329 : 4 : poll_threads();
1330 : 4 : CU_ASSERT(g_bserrno == 0);
1331 : 4 : CU_ASSERT(spdk_blob_get_num_clusters(blob) == 2);
1332 : 4 : CU_ASSERT((free_clusters - 4) == spdk_bs_free_cluster_count(bs));
1333 : 4 : CU_ASSERT(spdk_blob_get_num_allocated_clusters(blob) == 1);
1334 : :
1335 : : /* Sync blob: 4 clusters were truncated but only 3 of them was allocated */
1336 : 4 : spdk_blob_sync_md(blob, blob_op_complete, NULL);
1337 : 4 : poll_threads();
1338 : 4 : CU_ASSERT(g_bserrno == 0);
1339 : 4 : CU_ASSERT((free_clusters - 1) == spdk_bs_free_cluster_count(bs));
1340 : 4 : CU_ASSERT(spdk_blob_get_num_clusters(blob) == 2);
1341 : 4 : CU_ASSERT(spdk_blob_get_num_allocated_clusters(blob) == 1);
1342 : :
1343 : 4 : spdk_bs_free_io_channel(blob_ch);
1344 : 4 : ut_blob_close_and_delete(bs, blob);
1345 : 4 : }
1346 : :
1347 : : static void
1348 : 4 : blob_read_only(void)
1349 : : {
1350 : : struct spdk_blob_store *bs;
1351 : : struct spdk_bs_dev *dev;
1352 : : struct spdk_blob *blob;
1353 : : struct spdk_bs_opts opts;
1354 : : spdk_blob_id blobid;
1355 : : int rc;
1356 : :
1357 : 4 : dev = init_dev();
1358 : 4 : spdk_bs_opts_init(&opts, sizeof(opts));
1359 : 4 : snprintf(opts.bstype.bstype, sizeof(opts.bstype.bstype), "TESTTYPE");
1360 : :
1361 : 4 : spdk_bs_init(dev, &opts, bs_op_with_handle_complete, NULL);
1362 : 4 : poll_threads();
1363 : 4 : CU_ASSERT(g_bserrno == 0);
1364 [ + - ]: 4 : SPDK_CU_ASSERT_FATAL(g_bs != NULL);
1365 : 4 : bs = g_bs;
1366 : :
1367 : 4 : blob = ut_blob_create_and_open(bs, NULL);
1368 : 4 : blobid = spdk_blob_get_id(blob);
1369 : :
1370 : 4 : rc = spdk_blob_set_read_only(blob);
1371 : 4 : CU_ASSERT(rc == 0);
1372 : :
1373 : 4 : CU_ASSERT(blob->data_ro == false);
1374 : 4 : CU_ASSERT(blob->md_ro == false);
1375 : :
1376 : 4 : spdk_blob_sync_md(blob, bs_op_complete, NULL);
1377 : 4 : poll_threads();
1378 : :
1379 : 4 : CU_ASSERT(blob->data_ro == true);
1380 : 4 : CU_ASSERT(blob->md_ro == true);
1381 : 4 : CU_ASSERT(blob->data_ro_flags & SPDK_BLOB_READ_ONLY);
1382 : :
1383 : 4 : spdk_blob_close(blob, blob_op_complete, NULL);
1384 : 4 : poll_threads();
1385 : 4 : CU_ASSERT(g_bserrno == 0);
1386 : :
1387 : 4 : spdk_bs_open_blob(bs, blobid, blob_op_with_handle_complete, NULL);
1388 : 4 : poll_threads();
1389 : 4 : CU_ASSERT(g_bserrno == 0);
1390 [ + - ]: 4 : SPDK_CU_ASSERT_FATAL(g_blob != NULL);
1391 : 4 : blob = g_blob;
1392 : :
1393 : 4 : CU_ASSERT(blob->data_ro == true);
1394 : 4 : CU_ASSERT(blob->md_ro == true);
1395 : 4 : CU_ASSERT(blob->data_ro_flags & SPDK_BLOB_READ_ONLY);
1396 : :
1397 : 4 : spdk_blob_close(blob, blob_op_complete, NULL);
1398 : 4 : poll_threads();
1399 : 4 : CU_ASSERT(g_bserrno == 0);
1400 : :
1401 : 4 : ut_bs_reload(&bs, &opts);
1402 : :
1403 : 4 : spdk_bs_open_blob(bs, blobid, blob_op_with_handle_complete, NULL);
1404 : 4 : poll_threads();
1405 : 4 : CU_ASSERT(g_bserrno == 0);
1406 [ - + ]: 4 : SPDK_CU_ASSERT_FATAL(g_blob != NULL);
1407 : 4 : blob = g_blob;
1408 : :
1409 : 4 : CU_ASSERT(blob->data_ro == true);
1410 : 4 : CU_ASSERT(blob->md_ro == true);
1411 : 4 : CU_ASSERT(blob->data_ro_flags & SPDK_BLOB_READ_ONLY);
1412 : :
1413 : 4 : ut_blob_close_and_delete(bs, blob);
1414 : :
1415 : 4 : spdk_bs_unload(bs, bs_op_complete, NULL);
1416 : 4 : poll_threads();
1417 : 4 : CU_ASSERT(g_bserrno == 0);
1418 : 4 : }
1419 : :
1420 : : static void
1421 : 4 : channel_ops(void)
1422 : : {
1423 : 4 : struct spdk_blob_store *bs = g_bs;
1424 : : struct spdk_io_channel *channel;
1425 : :
1426 : 4 : channel = spdk_bs_alloc_io_channel(bs);
1427 : 4 : CU_ASSERT(channel != NULL);
1428 : :
1429 : 4 : spdk_bs_free_io_channel(channel);
1430 : 4 : poll_threads();
1431 : 4 : }
1432 : :
1433 : : static void
1434 : 4 : blob_write(void)
1435 : : {
1436 : 4 : struct spdk_blob_store *bs = g_bs;
1437 : 4 : struct spdk_blob *blob = g_blob;
1438 : : struct spdk_io_channel *channel;
1439 : : uint64_t pages_per_cluster;
1440 : : uint8_t payload[10 * BLOCKLEN];
1441 : :
1442 : 4 : pages_per_cluster = spdk_bs_get_cluster_size(bs) / spdk_bs_get_page_size(bs);
1443 : :
1444 : 4 : channel = spdk_bs_alloc_io_channel(bs);
1445 : 4 : CU_ASSERT(channel != NULL);
1446 : :
1447 : : /* Write to a blob with 0 size */
1448 : 4 : spdk_blob_io_write(blob, channel, payload, 0, 1, blob_op_complete, NULL);
1449 : 4 : poll_threads();
1450 : 4 : CU_ASSERT(g_bserrno == -EINVAL);
1451 : :
1452 : : /* Resize the blob */
1453 : 4 : spdk_blob_resize(blob, 5, blob_op_complete, NULL);
1454 : 4 : poll_threads();
1455 : 4 : CU_ASSERT(g_bserrno == 0);
1456 : :
1457 : : /* Confirm that write fails if blob is marked read-only. */
1458 : 4 : blob->data_ro = true;
1459 : 4 : spdk_blob_io_write(blob, channel, payload, 0, 1, blob_op_complete, NULL);
1460 : 4 : poll_threads();
1461 : 4 : CU_ASSERT(g_bserrno == -EPERM);
1462 : 4 : blob->data_ro = false;
1463 : :
1464 : : /* Write to the blob */
1465 : 4 : spdk_blob_io_write(blob, channel, payload, 0, 1, blob_op_complete, NULL);
1466 : 4 : poll_threads();
1467 : 4 : CU_ASSERT(g_bserrno == 0);
1468 : :
1469 : : /* Write starting beyond the end */
1470 : 4 : spdk_blob_io_write(blob, channel, payload, 5 * pages_per_cluster, 1, blob_op_complete,
1471 : : NULL);
1472 : 4 : poll_threads();
1473 : 4 : CU_ASSERT(g_bserrno == -EINVAL);
1474 : :
1475 : : /* Write starting at a valid location but going off the end */
1476 : 4 : spdk_blob_io_write(blob, channel, payload, 4 * pages_per_cluster, pages_per_cluster + 1,
1477 : : blob_op_complete, NULL);
1478 : 4 : poll_threads();
1479 : 4 : CU_ASSERT(g_bserrno == -EINVAL);
1480 : :
1481 : 4 : spdk_bs_free_io_channel(channel);
1482 : 4 : poll_threads();
1483 : 4 : }
1484 : :
1485 : : static void
1486 : 4 : blob_read(void)
1487 : : {
1488 : 4 : struct spdk_blob_store *bs = g_bs;
1489 : 4 : struct spdk_blob *blob = g_blob;
1490 : : struct spdk_io_channel *channel;
1491 : : uint64_t pages_per_cluster;
1492 : : uint8_t payload[10 * BLOCKLEN];
1493 : :
1494 : 4 : pages_per_cluster = spdk_bs_get_cluster_size(bs) / spdk_bs_get_page_size(bs);
1495 : :
1496 : 4 : channel = spdk_bs_alloc_io_channel(bs);
1497 : 4 : CU_ASSERT(channel != NULL);
1498 : :
1499 : : /* Read from a blob with 0 size */
1500 : 4 : spdk_blob_io_read(blob, channel, payload, 0, 1, blob_op_complete, NULL);
1501 : 4 : poll_threads();
1502 : 4 : CU_ASSERT(g_bserrno == -EINVAL);
1503 : :
1504 : : /* Resize the blob */
1505 : 4 : spdk_blob_resize(blob, 5, blob_op_complete, NULL);
1506 : 4 : poll_threads();
1507 : 4 : CU_ASSERT(g_bserrno == 0);
1508 : :
1509 : : /* Confirm that read passes if blob is marked read-only. */
1510 : 4 : blob->data_ro = true;
1511 : 4 : spdk_blob_io_read(blob, channel, payload, 0, 1, blob_op_complete, NULL);
1512 : 4 : poll_threads();
1513 : 4 : CU_ASSERT(g_bserrno == 0);
1514 : 4 : blob->data_ro = false;
1515 : :
1516 : : /* Read from the blob */
1517 : 4 : spdk_blob_io_read(blob, channel, payload, 0, 1, blob_op_complete, NULL);
1518 : 4 : poll_threads();
1519 : 4 : CU_ASSERT(g_bserrno == 0);
1520 : :
1521 : : /* Read starting beyond the end */
1522 : 4 : spdk_blob_io_read(blob, channel, payload, 5 * pages_per_cluster, 1, blob_op_complete,
1523 : : NULL);
1524 : 4 : poll_threads();
1525 : 4 : CU_ASSERT(g_bserrno == -EINVAL);
1526 : :
1527 : : /* Read starting at a valid location but going off the end */
1528 : 4 : spdk_blob_io_read(blob, channel, payload, 4 * pages_per_cluster, pages_per_cluster + 1,
1529 : : blob_op_complete, NULL);
1530 : 4 : poll_threads();
1531 : 4 : CU_ASSERT(g_bserrno == -EINVAL);
1532 : :
1533 : 4 : spdk_bs_free_io_channel(channel);
1534 : 4 : poll_threads();
1535 : 4 : }
1536 : :
1537 : : static void
1538 : 4 : blob_rw_verify(void)
1539 : : {
1540 : 4 : struct spdk_blob_store *bs = g_bs;
1541 : 4 : struct spdk_blob *blob = g_blob;
1542 : : struct spdk_io_channel *channel;
1543 : : uint8_t payload_read[10 * BLOCKLEN];
1544 : : uint8_t payload_write[10 * BLOCKLEN];
1545 : :
1546 : 4 : channel = spdk_bs_alloc_io_channel(bs);
1547 : 4 : CU_ASSERT(channel != NULL);
1548 : :
1549 : 4 : spdk_blob_resize(blob, 32, blob_op_complete, NULL);
1550 : 4 : poll_threads();
1551 : 4 : CU_ASSERT(g_bserrno == 0);
1552 : :
1553 : 4 : memset(payload_write, 0xE5, sizeof(payload_write));
1554 : 4 : spdk_blob_io_write(blob, channel, payload_write, 4, 10, blob_op_complete, NULL);
1555 : 4 : poll_threads();
1556 : 4 : CU_ASSERT(g_bserrno == 0);
1557 : :
1558 : 4 : memset(payload_read, 0x00, sizeof(payload_read));
1559 : 4 : spdk_blob_io_read(blob, channel, payload_read, 4, 10, blob_op_complete, NULL);
1560 : 4 : poll_threads();
1561 : 4 : CU_ASSERT(g_bserrno == 0);
1562 : 4 : CU_ASSERT(memcmp(payload_write, payload_read, 4 * BLOCKLEN) == 0);
1563 : :
1564 : 4 : spdk_bs_free_io_channel(channel);
1565 : 4 : poll_threads();
1566 : 4 : }
1567 : :
1568 : : static void
1569 : 4 : blob_rw_verify_iov(void)
1570 : : {
1571 : 4 : struct spdk_blob_store *bs = g_bs;
1572 : : struct spdk_blob *blob;
1573 : : struct spdk_io_channel *channel;
1574 : : uint8_t payload_read[10 * BLOCKLEN];
1575 : : uint8_t payload_write[10 * BLOCKLEN];
1576 : : struct iovec iov_read[3];
1577 : : struct iovec iov_write[3];
1578 : : void *buf;
1579 : :
1580 : 4 : channel = spdk_bs_alloc_io_channel(bs);
1581 : 4 : CU_ASSERT(channel != NULL);
1582 : :
1583 : 4 : blob = ut_blob_create_and_open(bs, NULL);
1584 : :
1585 : 4 : spdk_blob_resize(blob, 2, blob_op_complete, NULL);
1586 : 4 : poll_threads();
1587 : 4 : CU_ASSERT(g_bserrno == 0);
1588 : :
1589 : : /*
1590 : : * Manually adjust the offset of the blob's second cluster. This allows
1591 : : * us to make sure that the readv/write code correctly accounts for I/O
1592 : : * that cross cluster boundaries. Start by asserting that the allocated
1593 : : * clusters are where we expect before modifying the second cluster.
1594 : : */
1595 : 4 : CU_ASSERT(blob->active.clusters[0] == 1 * 256);
1596 : 4 : CU_ASSERT(blob->active.clusters[1] == 2 * 256);
1597 : 4 : blob->active.clusters[1] = 3 * 256;
1598 : :
1599 : 4 : memset(payload_write, 0xE5, sizeof(payload_write));
1600 : 4 : iov_write[0].iov_base = payload_write;
1601 : 4 : iov_write[0].iov_len = 1 * BLOCKLEN;
1602 : 4 : iov_write[1].iov_base = payload_write + 1 * BLOCKLEN;
1603 : 4 : iov_write[1].iov_len = 5 * BLOCKLEN;
1604 : 4 : iov_write[2].iov_base = payload_write + 6 * BLOCKLEN;
1605 : 4 : iov_write[2].iov_len = 4 * BLOCKLEN;
1606 : : /*
1607 : : * Choose a page offset just before the cluster boundary. The first 6 pages of payload
1608 : : * will get written to the first cluster, the last 4 to the second cluster.
1609 : : */
1610 : 4 : spdk_blob_io_writev(blob, channel, iov_write, 3, 250, 10, blob_op_complete, NULL);
1611 : 4 : poll_threads();
1612 : 4 : CU_ASSERT(g_bserrno == 0);
1613 : :
1614 : 4 : memset(payload_read, 0xAA, sizeof(payload_read));
1615 : 4 : iov_read[0].iov_base = payload_read;
1616 : 4 : iov_read[0].iov_len = 3 * BLOCKLEN;
1617 : 4 : iov_read[1].iov_base = payload_read + 3 * BLOCKLEN;
1618 : 4 : iov_read[1].iov_len = 4 * BLOCKLEN;
1619 : 4 : iov_read[2].iov_base = payload_read + 7 * BLOCKLEN;
1620 : 4 : iov_read[2].iov_len = 3 * BLOCKLEN;
1621 : 4 : spdk_blob_io_readv(blob, channel, iov_read, 3, 250, 10, blob_op_complete, NULL);
1622 : 4 : poll_threads();
1623 : 4 : CU_ASSERT(g_bserrno == 0);
1624 : 4 : CU_ASSERT(memcmp(payload_write, payload_read, 10 * BLOCKLEN) == 0);
1625 : :
1626 : 4 : buf = calloc(1, 256 * BLOCKLEN);
1627 [ + - ]: 4 : SPDK_CU_ASSERT_FATAL(buf != NULL);
1628 : : /* Check that cluster 2 on "disk" was not modified. */
1629 : 4 : CU_ASSERT(memcmp(buf, &g_dev_buffer[512 * BLOCKLEN], 256 * BLOCKLEN) == 0);
1630 : 4 : free(buf);
1631 : :
1632 : 4 : spdk_blob_close(blob, blob_op_complete, NULL);
1633 : 4 : poll_threads();
1634 : 4 : CU_ASSERT(g_bserrno == 0);
1635 : :
1636 : 4 : spdk_bs_free_io_channel(channel);
1637 : 4 : poll_threads();
1638 : 4 : }
1639 : :
1640 : : static uint32_t
1641 : 8 : bs_channel_get_req_count(struct spdk_io_channel *_channel)
1642 : : {
1643 : 8 : struct spdk_bs_channel *channel = spdk_io_channel_get_ctx(_channel);
1644 : : struct spdk_bs_request_set *set;
1645 : 8 : uint32_t count = 0;
1646 : :
1647 [ + + ]: 4104 : TAILQ_FOREACH(set, &channel->reqs, link) {
1648 : 4096 : count++;
1649 : 4096 : }
1650 : :
1651 : 8 : return count;
1652 : : }
1653 : :
1654 : : static void
1655 : 4 : blob_rw_verify_iov_nomem(void)
1656 : : {
1657 : 4 : struct spdk_blob_store *bs = g_bs;
1658 : 4 : struct spdk_blob *blob = g_blob;
1659 : : struct spdk_io_channel *channel;
1660 : : uint8_t payload_write[10 * BLOCKLEN];
1661 : : struct iovec iov_write[3];
1662 : : uint32_t req_count;
1663 : :
1664 : 4 : channel = spdk_bs_alloc_io_channel(bs);
1665 : 4 : CU_ASSERT(channel != NULL);
1666 : :
1667 : 4 : spdk_blob_resize(blob, 2, blob_op_complete, NULL);
1668 : 4 : poll_threads();
1669 : 4 : CU_ASSERT(g_bserrno == 0);
1670 : :
1671 : : /*
1672 : : * Choose a page offset just before the cluster boundary. The first 6 pages of payload
1673 : : * will get written to the first cluster, the last 4 to the second cluster.
1674 : : */
1675 : 4 : iov_write[0].iov_base = payload_write;
1676 : 4 : iov_write[0].iov_len = 1 * BLOCKLEN;
1677 : 4 : iov_write[1].iov_base = payload_write + 1 * BLOCKLEN;
1678 : 4 : iov_write[1].iov_len = 5 * BLOCKLEN;
1679 : 4 : iov_write[2].iov_base = payload_write + 6 * BLOCKLEN;
1680 : 4 : iov_write[2].iov_len = 4 * BLOCKLEN;
1681 : 4 : MOCK_SET(calloc, NULL);
1682 : 4 : req_count = bs_channel_get_req_count(channel);
1683 : 4 : spdk_blob_io_writev(blob, channel, iov_write, 3, 250, 10, blob_op_complete, NULL);
1684 : 4 : poll_threads();
1685 : 4 : CU_ASSERT(g_bserrno == -ENOMEM);
1686 : 4 : CU_ASSERT(req_count == bs_channel_get_req_count(channel));
1687 [ - + # # ]: 4 : MOCK_CLEAR(calloc);
1688 : :
1689 : 4 : spdk_bs_free_io_channel(channel);
1690 : 4 : poll_threads();
1691 : 4 : }
1692 : :
1693 : : static void
1694 : 4 : blob_rw_iov_read_only(void)
1695 : : {
1696 : 4 : struct spdk_blob_store *bs = g_bs;
1697 : 4 : struct spdk_blob *blob = g_blob;
1698 : : struct spdk_io_channel *channel;
1699 : : uint8_t payload_read[BLOCKLEN];
1700 : : uint8_t payload_write[BLOCKLEN];
1701 : : struct iovec iov_read;
1702 : : struct iovec iov_write;
1703 : :
1704 : 4 : channel = spdk_bs_alloc_io_channel(bs);
1705 : 4 : CU_ASSERT(channel != NULL);
1706 : :
1707 : 4 : spdk_blob_resize(blob, 2, blob_op_complete, NULL);
1708 : 4 : poll_threads();
1709 : 4 : CU_ASSERT(g_bserrno == 0);
1710 : :
1711 : : /* Verify that writev failed if read_only flag is set. */
1712 : 4 : blob->data_ro = true;
1713 : 4 : iov_write.iov_base = payload_write;
1714 : 4 : iov_write.iov_len = sizeof(payload_write);
1715 : 4 : spdk_blob_io_writev(blob, channel, &iov_write, 1, 0, 1, blob_op_complete, NULL);
1716 : 4 : poll_threads();
1717 : 4 : CU_ASSERT(g_bserrno == -EPERM);
1718 : :
1719 : : /* Verify that reads pass if data_ro flag is set. */
1720 : 4 : iov_read.iov_base = payload_read;
1721 : 4 : iov_read.iov_len = sizeof(payload_read);
1722 : 4 : spdk_blob_io_readv(blob, channel, &iov_read, 1, 0, 1, blob_op_complete, NULL);
1723 : 4 : poll_threads();
1724 : 4 : CU_ASSERT(g_bserrno == 0);
1725 : :
1726 : 4 : spdk_bs_free_io_channel(channel);
1727 : 4 : poll_threads();
1728 : 4 : }
1729 : :
1730 : : static void
1731 : 8 : _blob_io_read_no_split(struct spdk_blob *blob, struct spdk_io_channel *channel,
1732 : : uint8_t *payload, uint64_t offset, uint64_t length,
1733 : : spdk_blob_op_complete cb_fn, void *cb_arg)
1734 : : {
1735 : : uint64_t i;
1736 : : uint8_t *buf;
1737 : 8 : uint64_t page_size = spdk_bs_get_page_size(blob->bs);
1738 : :
1739 : : /* To be sure that operation is NOT split, read one page at the time */
1740 : 8 : buf = payload;
1741 [ + + ]: 10248 : for (i = 0; i < length; i++) {
1742 : 10240 : spdk_blob_io_read(blob, channel, buf, i + offset, 1, blob_op_complete, NULL);
1743 : 10240 : poll_threads();
1744 [ - + ]: 10240 : if (g_bserrno != 0) {
1745 : : /* Pass the error code up */
1746 : 0 : break;
1747 : : }
1748 : 10240 : buf += page_size;
1749 : 10240 : }
1750 : :
1751 : 8 : cb_fn(cb_arg, g_bserrno);
1752 : 8 : }
1753 : :
1754 : : static void
1755 : 8 : _blob_io_write_no_split(struct spdk_blob *blob, struct spdk_io_channel *channel,
1756 : : uint8_t *payload, uint64_t offset, uint64_t length,
1757 : : spdk_blob_op_complete cb_fn, void *cb_arg)
1758 : : {
1759 : : uint64_t i;
1760 : : uint8_t *buf;
1761 : 8 : uint64_t page_size = spdk_bs_get_page_size(blob->bs);
1762 : :
1763 : : /* To be sure that operation is NOT split, write one page at the time */
1764 : 8 : buf = payload;
1765 [ + + ]: 10248 : for (i = 0; i < length; i++) {
1766 : 10240 : spdk_blob_io_write(blob, channel, buf, i + offset, 1, blob_op_complete, NULL);
1767 : 10240 : poll_threads();
1768 [ - + ]: 10240 : if (g_bserrno != 0) {
1769 : : /* Pass the error code up */
1770 : 0 : break;
1771 : : }
1772 : 10240 : buf += page_size;
1773 : 10240 : }
1774 : :
1775 : 8 : cb_fn(cb_arg, g_bserrno);
1776 : 8 : }
1777 : :
1778 : : static void
1779 : 4 : blob_operation_split_rw(void)
1780 : : {
1781 : 4 : struct spdk_blob_store *bs = g_bs;
1782 : : struct spdk_blob *blob;
1783 : : struct spdk_io_channel *channel;
1784 : : struct spdk_blob_opts opts;
1785 : : uint64_t cluster_size;
1786 : :
1787 : : uint64_t payload_size;
1788 : : uint8_t *payload_read;
1789 : : uint8_t *payload_write;
1790 : : uint8_t *payload_pattern;
1791 : :
1792 : : uint64_t page_size;
1793 : : uint64_t pages_per_cluster;
1794 : : uint64_t pages_per_payload;
1795 : :
1796 : : uint64_t i;
1797 : :
1798 : 4 : cluster_size = spdk_bs_get_cluster_size(bs);
1799 : 4 : page_size = spdk_bs_get_page_size(bs);
1800 : 4 : pages_per_cluster = cluster_size / page_size;
1801 : 4 : pages_per_payload = pages_per_cluster * 5;
1802 : 4 : payload_size = cluster_size * 5;
1803 : :
1804 : 4 : payload_read = malloc(payload_size);
1805 [ + - ]: 4 : SPDK_CU_ASSERT_FATAL(payload_read != NULL);
1806 : :
1807 : 4 : payload_write = malloc(payload_size);
1808 [ + - ]: 4 : SPDK_CU_ASSERT_FATAL(payload_write != NULL);
1809 : :
1810 : 4 : payload_pattern = malloc(payload_size);
1811 [ + - ]: 4 : SPDK_CU_ASSERT_FATAL(payload_pattern != NULL);
1812 : :
1813 : : /* Prepare random pattern to write */
1814 : 4 : memset(payload_pattern, 0xFF, payload_size);
1815 [ + + ]: 5124 : for (i = 0; i < pages_per_payload; i++) {
1816 : 5120 : *((uint64_t *)(payload_pattern + page_size * i)) = (i + 1);
1817 : 5120 : }
1818 : :
1819 : 4 : channel = spdk_bs_alloc_io_channel(bs);
1820 [ - + ]: 4 : SPDK_CU_ASSERT_FATAL(channel != NULL);
1821 : :
1822 : : /* Create blob */
1823 : 4 : ut_spdk_blob_opts_init(&opts);
1824 : 4 : opts.thin_provision = false;
1825 : 4 : opts.num_clusters = 5;
1826 : :
1827 : 4 : blob = ut_blob_create_and_open(bs, &opts);
1828 : 4 : CU_ASSERT(spdk_blob_get_num_clusters(blob) == 5);
1829 : :
1830 : : /* Initial read should return zeroed payload */
1831 : 4 : memset(payload_read, 0xFF, payload_size);
1832 : 4 : spdk_blob_io_read(blob, channel, payload_read, 0, pages_per_payload, blob_op_complete, NULL);
1833 : 4 : poll_threads();
1834 : 4 : CU_ASSERT(g_bserrno == 0);
1835 : 4 : CU_ASSERT(spdk_mem_all_zero(payload_read, payload_size));
1836 : :
1837 : : /* Fill whole blob except last page */
1838 : 4 : spdk_blob_io_write(blob, channel, payload_pattern, 0, pages_per_payload - 1,
1839 : : blob_op_complete, NULL);
1840 : 4 : poll_threads();
1841 : 4 : CU_ASSERT(g_bserrno == 0);
1842 : :
1843 : : /* Write last page with a pattern */
1844 : 4 : spdk_blob_io_write(blob, channel, payload_pattern, pages_per_payload - 1, 1,
1845 : : blob_op_complete, NULL);
1846 : 4 : poll_threads();
1847 : 4 : CU_ASSERT(g_bserrno == 0);
1848 : :
1849 : : /* Read whole blob and check consistency */
1850 : 4 : memset(payload_read, 0xFF, payload_size);
1851 : 4 : spdk_blob_io_read(blob, channel, payload_read, 0, pages_per_payload, blob_op_complete, NULL);
1852 : 4 : poll_threads();
1853 : 4 : CU_ASSERT(g_bserrno == 0);
1854 : 4 : CU_ASSERT(memcmp(payload_pattern, payload_read, payload_size - page_size) == 0);
1855 : 4 : CU_ASSERT(memcmp(payload_pattern, payload_read + payload_size - page_size, page_size) == 0);
1856 : :
1857 : : /* Fill whole blob except first page */
1858 : 4 : spdk_blob_io_write(blob, channel, payload_pattern, 1, pages_per_payload - 1,
1859 : : blob_op_complete, NULL);
1860 : 4 : poll_threads();
1861 : 4 : CU_ASSERT(g_bserrno == 0);
1862 : :
1863 : : /* Write first page with a pattern */
1864 : 4 : spdk_blob_io_write(blob, channel, payload_pattern, 0, 1,
1865 : : blob_op_complete, NULL);
1866 : 4 : poll_threads();
1867 : 4 : CU_ASSERT(g_bserrno == 0);
1868 : :
1869 : : /* Read whole blob and check consistency */
1870 : 4 : memset(payload_read, 0xFF, payload_size);
1871 : 4 : spdk_blob_io_read(blob, channel, payload_read, 0, pages_per_payload, blob_op_complete, NULL);
1872 : 4 : poll_threads();
1873 : 4 : CU_ASSERT(g_bserrno == 0);
1874 : 4 : CU_ASSERT(memcmp(payload_pattern, payload_read + page_size, payload_size - page_size) == 0);
1875 : 4 : CU_ASSERT(memcmp(payload_pattern, payload_read, page_size) == 0);
1876 : :
1877 : :
1878 : : /* Fill whole blob with a pattern (5 clusters) */
1879 : :
1880 : : /* 1. Read test. */
1881 : 4 : _blob_io_write_no_split(blob, channel, payload_pattern, 0, pages_per_payload,
1882 : : blob_op_complete, NULL);
1883 : 4 : poll_threads();
1884 : 4 : CU_ASSERT(g_bserrno == 0);
1885 : :
1886 : 4 : memset(payload_read, 0xFF, payload_size);
1887 : 4 : spdk_blob_io_read(blob, channel, payload_read, 0, pages_per_payload, blob_op_complete, NULL);
1888 : 4 : poll_threads();
1889 : 4 : poll_threads();
1890 : 4 : CU_ASSERT(g_bserrno == 0);
1891 : 4 : CU_ASSERT(memcmp(payload_pattern, payload_read, payload_size) == 0);
1892 : :
1893 : : /* 2. Write test. */
1894 : 4 : spdk_blob_io_write(blob, channel, payload_pattern, 0, pages_per_payload,
1895 : : blob_op_complete, NULL);
1896 : 4 : poll_threads();
1897 : 4 : CU_ASSERT(g_bserrno == 0);
1898 : :
1899 : 4 : memset(payload_read, 0xFF, payload_size);
1900 : 4 : _blob_io_read_no_split(blob, channel, payload_read, 0, pages_per_payload, blob_op_complete, NULL);
1901 : 4 : poll_threads();
1902 : 4 : CU_ASSERT(g_bserrno == 0);
1903 : 4 : CU_ASSERT(memcmp(payload_pattern, payload_read, payload_size) == 0);
1904 : :
1905 : 4 : spdk_bs_free_io_channel(channel);
1906 : 4 : poll_threads();
1907 : :
1908 : 4 : g_blob = NULL;
1909 : 4 : g_blobid = 0;
1910 : :
1911 : 4 : free(payload_read);
1912 : 4 : free(payload_write);
1913 : 4 : free(payload_pattern);
1914 : :
1915 : 4 : ut_blob_close_and_delete(bs, blob);
1916 : 4 : }
1917 : :
1918 : : static void
1919 : 4 : blob_operation_split_rw_iov(void)
1920 : : {
1921 : 4 : struct spdk_blob_store *bs = g_bs;
1922 : : struct spdk_blob *blob;
1923 : : struct spdk_io_channel *channel;
1924 : : struct spdk_blob_opts opts;
1925 : : uint64_t cluster_size;
1926 : :
1927 : : uint64_t payload_size;
1928 : : uint8_t *payload_read;
1929 : : uint8_t *payload_write;
1930 : : uint8_t *payload_pattern;
1931 : :
1932 : : uint64_t page_size;
1933 : : uint64_t pages_per_cluster;
1934 : : uint64_t pages_per_payload;
1935 : :
1936 : : struct iovec iov_read[2];
1937 : : struct iovec iov_write[2];
1938 : :
1939 : : uint64_t i, j;
1940 : :
1941 : 4 : cluster_size = spdk_bs_get_cluster_size(bs);
1942 : 4 : page_size = spdk_bs_get_page_size(bs);
1943 : 4 : pages_per_cluster = cluster_size / page_size;
1944 : 4 : pages_per_payload = pages_per_cluster * 5;
1945 : 4 : payload_size = cluster_size * 5;
1946 : :
1947 : 4 : payload_read = malloc(payload_size);
1948 [ + - ]: 4 : SPDK_CU_ASSERT_FATAL(payload_read != NULL);
1949 : :
1950 : 4 : payload_write = malloc(payload_size);
1951 [ + - ]: 4 : SPDK_CU_ASSERT_FATAL(payload_write != NULL);
1952 : :
1953 : 4 : payload_pattern = malloc(payload_size);
1954 [ + - ]: 4 : SPDK_CU_ASSERT_FATAL(payload_pattern != NULL);
1955 : :
1956 : : /* Prepare random pattern to write */
1957 [ + + ]: 5124 : for (i = 0; i < pages_per_payload; i++) {
1958 [ + + ]: 2626560 : for (j = 0; j < page_size / sizeof(uint64_t); j++) {
1959 : : uint64_t *tmp;
1960 : :
1961 : 2621440 : tmp = (uint64_t *)payload_pattern;
1962 : 2621440 : tmp += ((page_size * i) / sizeof(uint64_t)) + j;
1963 : 2621440 : *tmp = i + 1;
1964 : 2621440 : }
1965 : 5120 : }
1966 : :
1967 : 4 : channel = spdk_bs_alloc_io_channel(bs);
1968 [ - + ]: 4 : SPDK_CU_ASSERT_FATAL(channel != NULL);
1969 : :
1970 : : /* Create blob */
1971 : 4 : ut_spdk_blob_opts_init(&opts);
1972 : 4 : opts.thin_provision = false;
1973 : 4 : opts.num_clusters = 5;
1974 : :
1975 : 4 : blob = ut_blob_create_and_open(bs, &opts);
1976 : 4 : CU_ASSERT(spdk_blob_get_num_clusters(blob) == 5);
1977 : :
1978 : : /* Initial read should return zeroes payload */
1979 : 4 : memset(payload_read, 0xFF, payload_size);
1980 : 4 : iov_read[0].iov_base = payload_read;
1981 : 4 : iov_read[0].iov_len = cluster_size * 3;
1982 : 4 : iov_read[1].iov_base = payload_read + cluster_size * 3;
1983 : 4 : iov_read[1].iov_len = cluster_size * 2;
1984 : 4 : spdk_blob_io_readv(blob, channel, iov_read, 2, 0, pages_per_payload, blob_op_complete, NULL);
1985 : 4 : poll_threads();
1986 : 4 : CU_ASSERT(g_bserrno == 0);
1987 : 4 : CU_ASSERT(spdk_mem_all_zero(payload_read, payload_size));
1988 : :
1989 : : /* First of iovs fills whole blob except last page and second of iovs writes last page
1990 : : * with a pattern. */
1991 : 4 : iov_write[0].iov_base = payload_pattern;
1992 : 4 : iov_write[0].iov_len = payload_size - page_size;
1993 : 4 : iov_write[1].iov_base = payload_pattern;
1994 : 4 : iov_write[1].iov_len = page_size;
1995 : 4 : spdk_blob_io_writev(blob, channel, iov_write, 2, 0, pages_per_payload, blob_op_complete, NULL);
1996 : 4 : poll_threads();
1997 : 4 : CU_ASSERT(g_bserrno == 0);
1998 : :
1999 : : /* Read whole blob and check consistency */
2000 : 4 : memset(payload_read, 0xFF, payload_size);
2001 : 4 : iov_read[0].iov_base = payload_read;
2002 : 4 : iov_read[0].iov_len = cluster_size * 2;
2003 : 4 : iov_read[1].iov_base = payload_read + cluster_size * 2;
2004 : 4 : iov_read[1].iov_len = cluster_size * 3;
2005 : 4 : spdk_blob_io_readv(blob, channel, iov_read, 2, 0, pages_per_payload, blob_op_complete, NULL);
2006 : 4 : poll_threads();
2007 : 4 : CU_ASSERT(g_bserrno == 0);
2008 : 4 : CU_ASSERT(memcmp(payload_pattern, payload_read, payload_size - page_size) == 0);
2009 : 4 : CU_ASSERT(memcmp(payload_pattern, payload_read + payload_size - page_size, page_size) == 0);
2010 : :
2011 : : /* First of iovs fills only first page and second of iovs writes whole blob except
2012 : : * first page with a pattern. */
2013 : 4 : iov_write[0].iov_base = payload_pattern;
2014 : 4 : iov_write[0].iov_len = page_size;
2015 : 4 : iov_write[1].iov_base = payload_pattern;
2016 : 4 : iov_write[1].iov_len = payload_size - page_size;
2017 : 4 : spdk_blob_io_writev(blob, channel, iov_write, 2, 0, pages_per_payload, blob_op_complete, NULL);
2018 : 4 : poll_threads();
2019 : 4 : CU_ASSERT(g_bserrno == 0);
2020 : :
2021 : : /* Read whole blob and check consistency */
2022 : 4 : memset(payload_read, 0xFF, payload_size);
2023 : 4 : iov_read[0].iov_base = payload_read;
2024 : 4 : iov_read[0].iov_len = cluster_size * 4;
2025 : 4 : iov_read[1].iov_base = payload_read + cluster_size * 4;
2026 : 4 : iov_read[1].iov_len = cluster_size;
2027 : 4 : spdk_blob_io_readv(blob, channel, iov_read, 2, 0, pages_per_payload, blob_op_complete, NULL);
2028 : 4 : poll_threads();
2029 : 4 : CU_ASSERT(g_bserrno == 0);
2030 : 4 : CU_ASSERT(memcmp(payload_pattern, payload_read + page_size, payload_size - page_size) == 0);
2031 : 4 : CU_ASSERT(memcmp(payload_pattern, payload_read, page_size) == 0);
2032 : :
2033 : :
2034 : : /* Fill whole blob with a pattern (5 clusters) */
2035 : :
2036 : : /* 1. Read test. */
2037 : 4 : _blob_io_write_no_split(blob, channel, payload_pattern, 0, pages_per_payload,
2038 : : blob_op_complete, NULL);
2039 : 4 : poll_threads();
2040 : 4 : CU_ASSERT(g_bserrno == 0);
2041 : :
2042 : 4 : memset(payload_read, 0xFF, payload_size);
2043 : 4 : iov_read[0].iov_base = payload_read;
2044 : 4 : iov_read[0].iov_len = cluster_size;
2045 : 4 : iov_read[1].iov_base = payload_read + cluster_size;
2046 : 4 : iov_read[1].iov_len = cluster_size * 4;
2047 : 4 : spdk_blob_io_readv(blob, channel, iov_read, 2, 0, pages_per_payload, blob_op_complete, NULL);
2048 : 4 : poll_threads();
2049 : 4 : CU_ASSERT(g_bserrno == 0);
2050 : 4 : CU_ASSERT(memcmp(payload_pattern, payload_read, payload_size) == 0);
2051 : :
2052 : : /* 2. Write test. */
2053 : 4 : iov_write[0].iov_base = payload_read;
2054 : 4 : iov_write[0].iov_len = cluster_size * 2;
2055 : 4 : iov_write[1].iov_base = payload_read + cluster_size * 2;
2056 : 4 : iov_write[1].iov_len = cluster_size * 3;
2057 : 4 : spdk_blob_io_writev(blob, channel, iov_write, 2, 0, pages_per_payload, blob_op_complete, NULL);
2058 : 4 : poll_threads();
2059 : 4 : CU_ASSERT(g_bserrno == 0);
2060 : :
2061 : 4 : memset(payload_read, 0xFF, payload_size);
2062 : 4 : _blob_io_read_no_split(blob, channel, payload_read, 0, pages_per_payload, blob_op_complete, NULL);
2063 : 4 : poll_threads();
2064 : 4 : CU_ASSERT(g_bserrno == 0);
2065 : 4 : CU_ASSERT(memcmp(payload_pattern, payload_read, payload_size) == 0);
2066 : :
2067 : 4 : spdk_bs_free_io_channel(channel);
2068 : 4 : poll_threads();
2069 : :
2070 : 4 : g_blob = NULL;
2071 : 4 : g_blobid = 0;
2072 : :
2073 : 4 : free(payload_read);
2074 : 4 : free(payload_write);
2075 : 4 : free(payload_pattern);
2076 : :
2077 : 4 : ut_blob_close_and_delete(bs, blob);
2078 : 4 : }
2079 : :
2080 : : static void
2081 : 4 : blob_unmap(void)
2082 : : {
2083 : 4 : struct spdk_blob_store *bs = g_bs;
2084 : : struct spdk_blob *blob;
2085 : : struct spdk_io_channel *channel;
2086 : : struct spdk_blob_opts opts;
2087 : : uint8_t payload[BLOCKLEN];
2088 : : int i;
2089 : :
2090 : 4 : channel = spdk_bs_alloc_io_channel(bs);
2091 : 4 : CU_ASSERT(channel != NULL);
2092 : :
2093 : 4 : ut_spdk_blob_opts_init(&opts);
2094 : 4 : opts.num_clusters = 10;
2095 : :
2096 : 4 : blob = ut_blob_create_and_open(bs, &opts);
2097 : :
2098 : 4 : spdk_blob_resize(blob, 10, blob_op_complete, NULL);
2099 : 4 : poll_threads();
2100 : 4 : CU_ASSERT(g_bserrno == 0);
2101 : 4 : CU_ASSERT(spdk_blob_get_num_allocated_clusters(blob) == 10);
2102 : :
2103 : 4 : memset(payload, 0, sizeof(payload));
2104 : 4 : payload[0] = 0xFF;
2105 : :
2106 : : /*
2107 : : * Set first byte of every cluster to 0xFF.
2108 : : * First cluster on device is reserved so let's start from cluster number 1
2109 : : */
2110 [ + + ]: 44 : for (i = 1; i < 11; i++) {
2111 : 40 : g_dev_buffer[i * SPDK_BLOB_OPTS_CLUSTER_SZ] = 0xFF;
2112 : 40 : }
2113 : :
2114 : : /* Confirm writes */
2115 [ + + ]: 44 : for (i = 0; i < 10; i++) {
2116 : 40 : payload[0] = 0;
2117 : 40 : spdk_blob_io_read(blob, channel, &payload, i * SPDK_BLOB_OPTS_CLUSTER_SZ / BLOCKLEN, 1,
2118 : : blob_op_complete, NULL);
2119 : 40 : poll_threads();
2120 : 40 : CU_ASSERT(g_bserrno == 0);
2121 : 40 : CU_ASSERT(payload[0] == 0xFF);
2122 : 40 : }
2123 : :
2124 : : /* Mark some clusters as unallocated */
2125 : 4 : blob->active.clusters[1] = 0;
2126 : 4 : blob->active.clusters[2] = 0;
2127 : 4 : blob->active.clusters[3] = 0;
2128 : 4 : blob->active.clusters[6] = 0;
2129 : 4 : blob->active.clusters[8] = 0;
2130 : 4 : blob->active.num_allocated_clusters -= 5;
2131 : :
2132 : : /* Unmap clusters by resizing to 0 */
2133 : 4 : spdk_blob_resize(blob, 0, blob_op_complete, NULL);
2134 : 4 : poll_threads();
2135 : 4 : CU_ASSERT(g_bserrno == 0);
2136 : :
2137 : 4 : spdk_blob_sync_md(blob, blob_op_complete, NULL);
2138 : 4 : poll_threads();
2139 : 4 : CU_ASSERT(g_bserrno == 0);
2140 : 4 : CU_ASSERT(spdk_blob_get_num_allocated_clusters(blob) == 0);
2141 : :
2142 : : /* Confirm that only 'allocated' clusters were unmapped */
2143 [ + + ]: 44 : for (i = 1; i < 11; i++) {
2144 [ + + ]: 40 : switch (i) {
2145 : : case 2:
2146 : : case 3:
2147 : : case 4:
2148 : : case 7:
2149 : : case 9:
2150 : 20 : CU_ASSERT(g_dev_buffer[i * SPDK_BLOB_OPTS_CLUSTER_SZ] == 0xFF);
2151 : 20 : break;
2152 : : default:
2153 : 20 : CU_ASSERT(g_dev_buffer[i * SPDK_BLOB_OPTS_CLUSTER_SZ] == 0);
2154 : 20 : break;
2155 : : }
2156 : 40 : }
2157 : :
2158 : 4 : spdk_bs_free_io_channel(channel);
2159 : 4 : poll_threads();
2160 : :
2161 : 4 : ut_blob_close_and_delete(bs, blob);
2162 : 4 : }
2163 : :
2164 : : static void
2165 : 4 : blob_iter(void)
2166 : : {
2167 : 4 : struct spdk_blob_store *bs = g_bs;
2168 : : struct spdk_blob *blob;
2169 : : spdk_blob_id blobid;
2170 : : struct spdk_blob_opts blob_opts;
2171 : :
2172 : 4 : spdk_bs_iter_first(bs, blob_op_with_handle_complete, NULL);
2173 : 4 : poll_threads();
2174 : 4 : CU_ASSERT(g_blob == NULL);
2175 : 4 : CU_ASSERT(g_bserrno == -ENOENT);
2176 : :
2177 : 4 : ut_spdk_blob_opts_init(&blob_opts);
2178 : 4 : spdk_bs_create_blob_ext(bs, &blob_opts, blob_op_with_id_complete, NULL);
2179 : 4 : poll_threads();
2180 : 4 : CU_ASSERT(g_bserrno == 0);
2181 : 4 : CU_ASSERT(g_blobid != SPDK_BLOBID_INVALID);
2182 : 4 : blobid = g_blobid;
2183 : :
2184 : 4 : spdk_bs_iter_first(bs, blob_op_with_handle_complete, NULL);
2185 : 4 : poll_threads();
2186 : 4 : CU_ASSERT(g_blob != NULL);
2187 : 4 : CU_ASSERT(g_bserrno == 0);
2188 : 4 : blob = g_blob;
2189 : 4 : CU_ASSERT(spdk_blob_get_id(blob) == blobid);
2190 : :
2191 : 4 : spdk_bs_iter_next(bs, blob, blob_op_with_handle_complete, NULL);
2192 : 4 : poll_threads();
2193 : 4 : CU_ASSERT(g_blob == NULL);
2194 : 4 : CU_ASSERT(g_bserrno == -ENOENT);
2195 : 4 : }
2196 : :
2197 : : static void
2198 : 4 : blob_xattr(void)
2199 : : {
2200 : 4 : struct spdk_blob_store *bs = g_bs;
2201 : 4 : struct spdk_blob *blob = g_blob;
2202 : 4 : spdk_blob_id blobid = spdk_blob_get_id(blob);
2203 : : uint64_t length;
2204 : : int rc;
2205 : : const char *name1, *name2;
2206 : : const void *value;
2207 : : size_t value_len;
2208 : : struct spdk_xattr_names *names;
2209 : :
2210 : : /* Test that set_xattr fails if md_ro flag is set. */
2211 : 4 : blob->md_ro = true;
2212 : 4 : rc = spdk_blob_set_xattr(blob, "name", "log.txt", strlen("log.txt") + 1);
2213 : 4 : CU_ASSERT(rc == -EPERM);
2214 : :
2215 : 4 : blob->md_ro = false;
2216 : 4 : rc = spdk_blob_set_xattr(blob, "name", "log.txt", strlen("log.txt") + 1);
2217 : 4 : CU_ASSERT(rc == 0);
2218 : :
2219 : 4 : length = 2345;
2220 : 4 : rc = spdk_blob_set_xattr(blob, "length", &length, sizeof(length));
2221 : 4 : CU_ASSERT(rc == 0);
2222 : :
2223 : : /* Overwrite "length" xattr. */
2224 : 4 : length = 3456;
2225 : 4 : rc = spdk_blob_set_xattr(blob, "length", &length, sizeof(length));
2226 : 4 : CU_ASSERT(rc == 0);
2227 : :
2228 : : /* get_xattr should still work even if md_ro flag is set. */
2229 : 4 : value = NULL;
2230 : 4 : blob->md_ro = true;
2231 : 4 : rc = spdk_blob_get_xattr_value(blob, "length", &value, &value_len);
2232 : 4 : CU_ASSERT(rc == 0);
2233 [ + - ]: 4 : SPDK_CU_ASSERT_FATAL(value != NULL);
2234 : 4 : CU_ASSERT(*(uint64_t *)value == length);
2235 : 4 : CU_ASSERT(value_len == 8);
2236 : 4 : blob->md_ro = false;
2237 : :
2238 : 4 : rc = spdk_blob_get_xattr_value(blob, "foobar", &value, &value_len);
2239 : 4 : CU_ASSERT(rc == -ENOENT);
2240 : :
2241 : 4 : names = NULL;
2242 : 4 : rc = spdk_blob_get_xattr_names(blob, &names);
2243 : 4 : CU_ASSERT(rc == 0);
2244 [ + - ]: 4 : SPDK_CU_ASSERT_FATAL(names != NULL);
2245 : 4 : CU_ASSERT(spdk_xattr_names_get_count(names) == 2);
2246 : 4 : name1 = spdk_xattr_names_get_name(names, 0);
2247 [ + - ]: 4 : SPDK_CU_ASSERT_FATAL(name1 != NULL);
2248 [ + - ]: 4 : CU_ASSERT(!strcmp(name1, "name") || !strcmp(name1, "length"));
2249 : 4 : name2 = spdk_xattr_names_get_name(names, 1);
2250 [ + - ]: 4 : SPDK_CU_ASSERT_FATAL(name2 != NULL);
2251 [ - + ]: 4 : CU_ASSERT(!strcmp(name2, "name") || !strcmp(name2, "length"));
2252 : 4 : CU_ASSERT(strcmp(name1, name2));
2253 : 4 : spdk_xattr_names_free(names);
2254 : :
2255 : : /* Confirm that remove_xattr fails if md_ro is set to true. */
2256 : 4 : blob->md_ro = true;
2257 : 4 : rc = spdk_blob_remove_xattr(blob, "name");
2258 : 4 : CU_ASSERT(rc == -EPERM);
2259 : :
2260 : 4 : blob->md_ro = false;
2261 : 4 : rc = spdk_blob_remove_xattr(blob, "name");
2262 : 4 : CU_ASSERT(rc == 0);
2263 : :
2264 : 4 : rc = spdk_blob_remove_xattr(blob, "foobar");
2265 : 4 : CU_ASSERT(rc == -ENOENT);
2266 : :
2267 : : /* Set internal xattr */
2268 : 4 : length = 7898;
2269 : 4 : rc = blob_set_xattr(blob, "internal", &length, sizeof(length), true);
2270 : 4 : CU_ASSERT(rc == 0);
2271 : 4 : rc = blob_get_xattr_value(blob, "internal", &value, &value_len, true);
2272 : 4 : CU_ASSERT(rc == 0);
2273 : 4 : CU_ASSERT(*(uint64_t *)value == length);
2274 : : /* try to get public xattr with same name */
2275 : 4 : rc = spdk_blob_get_xattr_value(blob, "internal", &value, &value_len);
2276 : 4 : CU_ASSERT(rc != 0);
2277 : 4 : rc = blob_get_xattr_value(blob, "internal", &value, &value_len, false);
2278 : 4 : CU_ASSERT(rc != 0);
2279 : : /* Check if SPDK_BLOB_INTERNAL_XATTR is set */
2280 : 4 : CU_ASSERT((blob->invalid_flags & SPDK_BLOB_INTERNAL_XATTR) ==
2281 : : SPDK_BLOB_INTERNAL_XATTR);
2282 : :
2283 : 4 : spdk_blob_close(blob, blob_op_complete, NULL);
2284 : 4 : poll_threads();
2285 : :
2286 : : /* Check if xattrs are persisted */
2287 : 4 : ut_bs_reload(&bs, NULL);
2288 : :
2289 : 4 : spdk_bs_open_blob(bs, blobid, blob_op_with_handle_complete, NULL);
2290 : 4 : poll_threads();
2291 : 4 : CU_ASSERT(g_bserrno == 0);
2292 [ - + ]: 4 : SPDK_CU_ASSERT_FATAL(g_blob != NULL);
2293 : 4 : blob = g_blob;
2294 : :
2295 : 4 : rc = blob_get_xattr_value(blob, "internal", &value, &value_len, true);
2296 : 4 : CU_ASSERT(rc == 0);
2297 : 4 : CU_ASSERT(*(uint64_t *)value == length);
2298 : :
2299 : : /* try to get internal xattr through public call */
2300 : 4 : rc = spdk_blob_get_xattr_value(blob, "internal", &value, &value_len);
2301 : 4 : CU_ASSERT(rc != 0);
2302 : :
2303 : 4 : rc = blob_remove_xattr(blob, "internal", true);
2304 : 4 : CU_ASSERT(rc == 0);
2305 : :
2306 : 4 : CU_ASSERT((blob->invalid_flags & SPDK_BLOB_INTERNAL_XATTR) == 0);
2307 : 4 : }
2308 : :
2309 : : static void
2310 : 4 : blob_parse_md(void)
2311 : : {
2312 : 4 : struct spdk_blob_store *bs = g_bs;
2313 : : struct spdk_blob *blob;
2314 : : int rc;
2315 : : uint32_t used_pages;
2316 : : size_t xattr_length;
2317 : : char *xattr;
2318 : :
2319 : 4 : used_pages = spdk_bit_array_count_set(bs->used_md_pages);
2320 : 4 : blob = ut_blob_create_and_open(bs, NULL);
2321 : :
2322 : : /* Create large extent to force more than 1 page of metadata. */
2323 : 4 : xattr_length = SPDK_BS_MAX_DESC_SIZE - sizeof(struct spdk_blob_md_descriptor_xattr) -
2324 : : strlen("large_xattr");
2325 : 4 : xattr = calloc(xattr_length, sizeof(char));
2326 [ + - ]: 4 : SPDK_CU_ASSERT_FATAL(xattr != NULL);
2327 : 4 : rc = spdk_blob_set_xattr(blob, "large_xattr", xattr, xattr_length);
2328 : 4 : free(xattr);
2329 [ + - ]: 4 : SPDK_CU_ASSERT_FATAL(rc == 0);
2330 : :
2331 : 4 : spdk_blob_sync_md(blob, blob_op_complete, NULL);
2332 : 4 : poll_threads();
2333 : :
2334 : : /* Delete the blob and verify that number of pages returned to before its creation. */
2335 [ + - ]: 4 : SPDK_CU_ASSERT_FATAL(used_pages != spdk_bit_array_count_set(bs->used_md_pages));
2336 : 4 : ut_blob_close_and_delete(bs, blob);
2337 [ - + ]: 4 : SPDK_CU_ASSERT_FATAL(used_pages == spdk_bit_array_count_set(bs->used_md_pages));
2338 : 4 : }
2339 : :
2340 : : static void
2341 : 4 : bs_load(void)
2342 : : {
2343 : : struct spdk_blob_store *bs;
2344 : : struct spdk_bs_dev *dev;
2345 : : spdk_blob_id blobid;
2346 : : struct spdk_blob *blob;
2347 : : struct spdk_bs_super_block *super_block;
2348 : : uint64_t length;
2349 : : int rc;
2350 : : const void *value;
2351 : : size_t value_len;
2352 : : struct spdk_bs_opts opts;
2353 : : struct spdk_blob_opts blob_opts;
2354 : :
2355 : 4 : dev = init_dev();
2356 : 4 : spdk_bs_opts_init(&opts, sizeof(opts));
2357 : 4 : snprintf(opts.bstype.bstype, sizeof(opts.bstype.bstype), "TESTTYPE");
2358 : :
2359 : : /* Initialize a new blob store */
2360 : 4 : spdk_bs_init(dev, &opts, bs_op_with_handle_complete, NULL);
2361 : 4 : poll_threads();
2362 : 4 : CU_ASSERT(g_bserrno == 0);
2363 [ + - ]: 4 : SPDK_CU_ASSERT_FATAL(g_bs != NULL);
2364 : 4 : bs = g_bs;
2365 : :
2366 : : /* Try to open a blobid that does not exist */
2367 : 4 : spdk_bs_open_blob(bs, 0, blob_op_with_handle_complete, NULL);
2368 : 4 : poll_threads();
2369 : 4 : CU_ASSERT(g_bserrno == -ENOENT);
2370 : 4 : CU_ASSERT(g_blob == NULL);
2371 : :
2372 : : /* Create a blob */
2373 : 4 : blob = ut_blob_create_and_open(bs, NULL);
2374 : 4 : blobid = spdk_blob_get_id(blob);
2375 : :
2376 : : /* Try again to open valid blob but without the upper bit set */
2377 : 4 : spdk_bs_open_blob(bs, blobid & 0xFFFFFFFF, blob_op_with_handle_complete, NULL);
2378 : 4 : poll_threads();
2379 : 4 : CU_ASSERT(g_bserrno == -ENOENT);
2380 : 4 : CU_ASSERT(g_blob == NULL);
2381 : :
2382 : : /* Set some xattrs */
2383 : 4 : rc = spdk_blob_set_xattr(blob, "name", "log.txt", strlen("log.txt") + 1);
2384 : 4 : CU_ASSERT(rc == 0);
2385 : :
2386 : 4 : length = 2345;
2387 : 4 : rc = spdk_blob_set_xattr(blob, "length", &length, sizeof(length));
2388 : 4 : CU_ASSERT(rc == 0);
2389 : :
2390 : : /* Resize the blob */
2391 : 4 : spdk_blob_resize(blob, 10, blob_op_complete, NULL);
2392 : 4 : poll_threads();
2393 : 4 : CU_ASSERT(g_bserrno == 0);
2394 : :
2395 : 4 : spdk_blob_close(blob, blob_op_complete, NULL);
2396 : 4 : poll_threads();
2397 : 4 : CU_ASSERT(g_bserrno == 0);
2398 : 4 : blob = NULL;
2399 : 4 : g_blob = NULL;
2400 : 4 : g_blobid = SPDK_BLOBID_INVALID;
2401 : :
2402 : : /* Unload the blob store */
2403 : 4 : spdk_bs_unload(bs, bs_op_complete, NULL);
2404 : 4 : poll_threads();
2405 : 4 : CU_ASSERT(g_bserrno == 0);
2406 : 4 : g_bs = NULL;
2407 : 4 : g_blob = NULL;
2408 : 4 : g_blobid = 0;
2409 : :
2410 : 4 : super_block = (struct spdk_bs_super_block *)g_dev_buffer;
2411 : 4 : CU_ASSERT(super_block->clean == 1);
2412 : :
2413 : : /* Load should fail for device with an unsupported blocklen */
2414 : 4 : dev = init_dev();
2415 : 4 : dev->blocklen = BLOCKLEN * 2;
2416 : 4 : spdk_bs_load(dev, NULL, bs_op_with_handle_complete, NULL);
2417 : 4 : poll_threads();
2418 : 4 : CU_ASSERT(g_bserrno == -EINVAL);
2419 : :
2420 : : /* Load should when max_md_ops is set to zero */
2421 : 4 : dev = init_dev();
2422 : 4 : spdk_bs_opts_init(&opts, sizeof(opts));
2423 : 4 : opts.max_md_ops = 0;
2424 : 4 : spdk_bs_load(dev, &opts, bs_op_with_handle_complete, NULL);
2425 : 4 : poll_threads();
2426 : 4 : CU_ASSERT(g_bserrno == -EINVAL);
2427 : :
2428 : : /* Load should when max_channel_ops is set to zero */
2429 : 4 : dev = init_dev();
2430 : 4 : spdk_bs_opts_init(&opts, sizeof(opts));
2431 : 4 : opts.max_channel_ops = 0;
2432 : 4 : spdk_bs_load(dev, &opts, bs_op_with_handle_complete, NULL);
2433 : 4 : poll_threads();
2434 : 4 : CU_ASSERT(g_bserrno == -EINVAL);
2435 : :
2436 : : /* Load an existing blob store */
2437 : 4 : dev = init_dev();
2438 : 4 : spdk_bs_opts_init(&opts, sizeof(opts));
2439 : 4 : snprintf(opts.bstype.bstype, sizeof(opts.bstype.bstype), "TESTTYPE");
2440 : 4 : spdk_bs_load(dev, &opts, bs_op_with_handle_complete, NULL);
2441 : 4 : poll_threads();
2442 : 4 : CU_ASSERT(g_bserrno == 0);
2443 [ + - ]: 4 : SPDK_CU_ASSERT_FATAL(g_bs != NULL);
2444 : 4 : bs = g_bs;
2445 : :
2446 : 4 : super_block = (struct spdk_bs_super_block *)g_dev_buffer;
2447 : 4 : CU_ASSERT(super_block->clean == 1);
2448 : 4 : CU_ASSERT(super_block->size == dev->blockcnt * dev->blocklen);
2449 : :
2450 : 4 : spdk_bs_open_blob(bs, blobid, blob_op_with_handle_complete, NULL);
2451 : 4 : poll_threads();
2452 : 4 : CU_ASSERT(g_bserrno == 0);
2453 : 4 : CU_ASSERT(g_blob != NULL);
2454 : 4 : blob = g_blob;
2455 : :
2456 : : /* Verify that blobstore is marked dirty after first metadata sync */
2457 : 4 : spdk_blob_sync_md(blob, blob_op_complete, NULL);
2458 : 4 : CU_ASSERT(super_block->clean == 1);
2459 : :
2460 : : /* Get the xattrs */
2461 : 4 : value = NULL;
2462 : 4 : rc = spdk_blob_get_xattr_value(blob, "length", &value, &value_len);
2463 : 4 : CU_ASSERT(rc == 0);
2464 [ + - ]: 4 : SPDK_CU_ASSERT_FATAL(value != NULL);
2465 : 4 : CU_ASSERT(*(uint64_t *)value == length);
2466 : 4 : CU_ASSERT(value_len == 8);
2467 : :
2468 : 4 : rc = spdk_blob_get_xattr_value(blob, "foobar", &value, &value_len);
2469 : 4 : CU_ASSERT(rc == -ENOENT);
2470 : :
2471 : 4 : CU_ASSERT(spdk_blob_get_num_clusters(blob) == 10);
2472 : 4 : CU_ASSERT(spdk_blob_get_num_allocated_clusters(blob) == 10);
2473 : :
2474 : 4 : spdk_blob_close(blob, blob_op_complete, NULL);
2475 : 4 : poll_threads();
2476 : 4 : CU_ASSERT(g_bserrno == 0);
2477 : 4 : blob = NULL;
2478 : 4 : g_blob = NULL;
2479 : :
2480 : 4 : spdk_bs_unload(bs, bs_op_complete, NULL);
2481 : 4 : poll_threads();
2482 : 4 : CU_ASSERT(g_bserrno == 0);
2483 : 4 : g_bs = NULL;
2484 : :
2485 : : /* Load should fail: bdev size < saved size */
2486 : 4 : dev = init_dev();
2487 : 4 : dev->blockcnt /= 2;
2488 : :
2489 : 4 : spdk_bs_opts_init(&opts, sizeof(opts));
2490 : 4 : snprintf(opts.bstype.bstype, sizeof(opts.bstype.bstype), "TESTTYPE");
2491 : 4 : spdk_bs_load(dev, &opts, bs_op_with_handle_complete, NULL);
2492 : 4 : poll_threads();
2493 : :
2494 : 4 : CU_ASSERT(g_bserrno == -EILSEQ);
2495 : :
2496 : : /* Load should succeed: bdev size > saved size */
2497 : 4 : dev = init_dev();
2498 : 4 : dev->blockcnt *= 4;
2499 : :
2500 : 4 : spdk_bs_opts_init(&opts, sizeof(opts));
2501 : 4 : snprintf(opts.bstype.bstype, sizeof(opts.bstype.bstype), "TESTTYPE");
2502 : 4 : spdk_bs_load(dev, &opts, bs_op_with_handle_complete, NULL);
2503 : 4 : poll_threads();
2504 : 4 : CU_ASSERT(g_bserrno == 0);
2505 [ + - ]: 4 : SPDK_CU_ASSERT_FATAL(g_bs != NULL);
2506 : 4 : bs = g_bs;
2507 : :
2508 : 4 : CU_ASSERT(g_bserrno == 0);
2509 : 4 : spdk_bs_unload(bs, bs_op_complete, NULL);
2510 : 4 : poll_threads();
2511 : :
2512 : :
2513 : : /* Test compatibility mode */
2514 : :
2515 : 4 : dev = init_dev();
2516 : 4 : super_block->size = 0;
2517 : 4 : super_block->crc = blob_md_page_calc_crc(super_block);
2518 : :
2519 : 4 : spdk_bs_opts_init(&opts, sizeof(opts));
2520 : 4 : snprintf(opts.bstype.bstype, sizeof(opts.bstype.bstype), "TESTTYPE");
2521 : 4 : spdk_bs_load(dev, &opts, bs_op_with_handle_complete, NULL);
2522 : 4 : poll_threads();
2523 : 4 : CU_ASSERT(g_bserrno == 0);
2524 [ - + ]: 4 : SPDK_CU_ASSERT_FATAL(g_bs != NULL);
2525 : 4 : bs = g_bs;
2526 : :
2527 : : /* Create a blob */
2528 : 4 : ut_spdk_blob_opts_init(&blob_opts);
2529 : 4 : spdk_bs_create_blob_ext(bs, &blob_opts, blob_op_with_id_complete, NULL);
2530 : 4 : poll_threads();
2531 : 4 : CU_ASSERT(g_bserrno == 0);
2532 : 4 : CU_ASSERT(g_blobid != SPDK_BLOBID_INVALID);
2533 : :
2534 : : /* Blobstore should update number of blocks in super_block */
2535 : 4 : CU_ASSERT(super_block->size == dev->blockcnt * dev->blocklen);
2536 : 4 : CU_ASSERT(super_block->clean == 0);
2537 : :
2538 : 4 : spdk_bs_unload(bs, bs_op_complete, NULL);
2539 : 4 : poll_threads();
2540 : 4 : CU_ASSERT(g_bserrno == 0);
2541 : 4 : CU_ASSERT(super_block->clean == 1);
2542 : 4 : g_bs = NULL;
2543 : :
2544 : 4 : }
2545 : :
2546 : : static void
2547 : 4 : bs_load_pending_removal(void)
2548 : : {
2549 : 4 : struct spdk_blob_store *bs = g_bs;
2550 : : struct spdk_blob_opts opts;
2551 : : struct spdk_blob *blob, *snapshot;
2552 : : spdk_blob_id blobid, snapshotid;
2553 : : const void *value;
2554 : : size_t value_len;
2555 : : int rc;
2556 : :
2557 : : /* Create blob */
2558 : 4 : ut_spdk_blob_opts_init(&opts);
2559 : 4 : opts.num_clusters = 10;
2560 : :
2561 : 4 : blob = ut_blob_create_and_open(bs, &opts);
2562 : 4 : blobid = spdk_blob_get_id(blob);
2563 : :
2564 : : /* Create snapshot */
2565 : 4 : spdk_bs_create_snapshot(bs, blobid, NULL, blob_op_with_id_complete, NULL);
2566 : 4 : poll_threads();
2567 : 4 : CU_ASSERT(g_bserrno == 0);
2568 : 4 : CU_ASSERT(g_blobid != SPDK_BLOBID_INVALID);
2569 : 4 : snapshotid = g_blobid;
2570 : :
2571 : 4 : spdk_bs_open_blob(bs, snapshotid, blob_op_with_handle_complete, NULL);
2572 : 4 : poll_threads();
2573 : 4 : CU_ASSERT(g_bserrno == 0);
2574 [ + - ]: 4 : SPDK_CU_ASSERT_FATAL(g_blob != NULL);
2575 : 4 : snapshot = g_blob;
2576 : :
2577 : : /* Set SNAPSHOT_PENDING_REMOVAL xattr */
2578 : 4 : snapshot->md_ro = false;
2579 : 4 : rc = blob_set_xattr(snapshot, SNAPSHOT_PENDING_REMOVAL, &blobid, sizeof(spdk_blob_id), true);
2580 : 4 : CU_ASSERT(rc == 0);
2581 : 4 : snapshot->md_ro = true;
2582 : :
2583 : 4 : spdk_blob_close(snapshot, blob_op_complete, NULL);
2584 : 4 : poll_threads();
2585 : 4 : CU_ASSERT(g_bserrno == 0);
2586 : :
2587 : 4 : spdk_blob_close(blob, blob_op_complete, NULL);
2588 : 4 : poll_threads();
2589 : 4 : CU_ASSERT(g_bserrno == 0);
2590 : :
2591 : : /* Reload blobstore */
2592 : 4 : ut_bs_reload(&bs, NULL);
2593 : :
2594 : : /* Snapshot should not be removed as blob is still pointing to it */
2595 : 4 : spdk_bs_open_blob(bs, snapshotid, blob_op_with_handle_complete, NULL);
2596 : 4 : poll_threads();
2597 : 4 : CU_ASSERT(g_bserrno == 0);
2598 [ + - ]: 4 : SPDK_CU_ASSERT_FATAL(g_blob != NULL);
2599 : 4 : snapshot = g_blob;
2600 : :
2601 : : /* SNAPSHOT_PENDING_REMOVAL xattr should be removed during load */
2602 : 4 : rc = spdk_blob_get_xattr_value(snapshot, SNAPSHOT_PENDING_REMOVAL, &value, &value_len);
2603 : 4 : CU_ASSERT(rc != 0);
2604 : :
2605 : : /* Set SNAPSHOT_PENDING_REMOVAL xattr again */
2606 : 4 : snapshot->md_ro = false;
2607 : 4 : rc = blob_set_xattr(snapshot, SNAPSHOT_PENDING_REMOVAL, &blobid, sizeof(spdk_blob_id), true);
2608 : 4 : CU_ASSERT(rc == 0);
2609 : 4 : snapshot->md_ro = true;
2610 : :
2611 : 4 : spdk_bs_open_blob(bs, blobid, blob_op_with_handle_complete, NULL);
2612 : 4 : poll_threads();
2613 : 4 : CU_ASSERT(g_bserrno == 0);
2614 [ - + ]: 4 : SPDK_CU_ASSERT_FATAL(g_blob != NULL);
2615 : 4 : blob = g_blob;
2616 : :
2617 : : /* Remove parent_id from blob by removing BLOB_SNAPSHOT xattr */
2618 : 4 : blob_remove_xattr(blob, BLOB_SNAPSHOT, true);
2619 : :
2620 : 4 : spdk_blob_sync_md(blob, blob_op_complete, NULL);
2621 : 4 : poll_threads();
2622 : 4 : CU_ASSERT(g_bserrno == 0);
2623 : :
2624 : 4 : spdk_blob_close(snapshot, blob_op_complete, NULL);
2625 : 4 : poll_threads();
2626 : 4 : CU_ASSERT(g_bserrno == 0);
2627 : :
2628 : 4 : spdk_blob_close(blob, blob_op_complete, NULL);
2629 : 4 : poll_threads();
2630 : 4 : CU_ASSERT(g_bserrno == 0);
2631 : :
2632 : : /* Reload blobstore */
2633 : 4 : ut_bs_reload(&bs, NULL);
2634 : :
2635 : : /* Snapshot should be removed as blob is not pointing to it anymore */
2636 : 4 : spdk_bs_open_blob(bs, snapshotid, blob_op_with_handle_complete, NULL);
2637 : 4 : poll_threads();
2638 : 4 : CU_ASSERT(g_bserrno != 0);
2639 : 4 : }
2640 : :
2641 : : static void
2642 : 4 : bs_load_custom_cluster_size(void)
2643 : : {
2644 : : struct spdk_blob_store *bs;
2645 : : struct spdk_bs_dev *dev;
2646 : : struct spdk_bs_super_block *super_block;
2647 : : struct spdk_bs_opts opts;
2648 : 4 : uint32_t custom_cluster_size = 4194304; /* 4MiB */
2649 : : uint32_t cluster_sz;
2650 : : uint64_t total_clusters;
2651 : :
2652 : 4 : dev = init_dev();
2653 : 4 : spdk_bs_opts_init(&opts, sizeof(opts));
2654 : 4 : opts.cluster_sz = custom_cluster_size;
2655 : 4 : snprintf(opts.bstype.bstype, sizeof(opts.bstype.bstype), "TESTTYPE");
2656 : :
2657 : : /* Initialize a new blob store */
2658 : 4 : spdk_bs_init(dev, &opts, bs_op_with_handle_complete, NULL);
2659 : 4 : poll_threads();
2660 : 4 : CU_ASSERT(g_bserrno == 0);
2661 [ + - ]: 4 : SPDK_CU_ASSERT_FATAL(g_bs != NULL);
2662 : 4 : bs = g_bs;
2663 : 4 : cluster_sz = bs->cluster_sz;
2664 : 4 : total_clusters = bs->total_clusters;
2665 : :
2666 : : /* Unload the blob store */
2667 : 4 : spdk_bs_unload(bs, bs_op_complete, NULL);
2668 : 4 : poll_threads();
2669 : 4 : CU_ASSERT(g_bserrno == 0);
2670 : 4 : g_bs = NULL;
2671 : 4 : g_blob = NULL;
2672 : 4 : g_blobid = 0;
2673 : :
2674 : 4 : super_block = (struct spdk_bs_super_block *)g_dev_buffer;
2675 : 4 : CU_ASSERT(super_block->clean == 1);
2676 : :
2677 : : /* Load an existing blob store */
2678 : 4 : dev = init_dev();
2679 : 4 : spdk_bs_opts_init(&opts, sizeof(opts));
2680 : 4 : snprintf(opts.bstype.bstype, sizeof(opts.bstype.bstype), "TESTTYPE");
2681 : 4 : spdk_bs_load(dev, &opts, bs_op_with_handle_complete, NULL);
2682 : 4 : poll_threads();
2683 : 4 : CU_ASSERT(g_bserrno == 0);
2684 [ - + ]: 4 : SPDK_CU_ASSERT_FATAL(g_bs != NULL);
2685 : 4 : bs = g_bs;
2686 : : /* Compare cluster size and number to one after initialization */
2687 : 4 : CU_ASSERT(cluster_sz == bs->cluster_sz);
2688 : 4 : CU_ASSERT(total_clusters == bs->total_clusters);
2689 : :
2690 : 4 : super_block = (struct spdk_bs_super_block *)g_dev_buffer;
2691 : 4 : CU_ASSERT(super_block->clean == 1);
2692 : 4 : CU_ASSERT(super_block->size == dev->blockcnt * dev->blocklen);
2693 : :
2694 : 4 : spdk_bs_unload(bs, bs_op_complete, NULL);
2695 : 4 : poll_threads();
2696 : 4 : CU_ASSERT(g_bserrno == 0);
2697 : 4 : CU_ASSERT(super_block->clean == 1);
2698 : 4 : g_bs = NULL;
2699 : 4 : }
2700 : :
2701 : : static void
2702 : 4 : bs_load_after_failed_grow(void)
2703 : : {
2704 : : struct spdk_blob_store *bs;
2705 : : struct spdk_bs_dev *dev;
2706 : : struct spdk_bs_super_block *super_block;
2707 : : struct spdk_bs_opts opts;
2708 : : struct spdk_bs_md_mask *mask;
2709 : : struct spdk_blob_opts blob_opts;
2710 : : struct spdk_blob *blob, *snapshot;
2711 : : spdk_blob_id blobid, snapshotid;
2712 : : uint64_t total_data_clusters;
2713 : :
2714 : 4 : dev = init_dev();
2715 : 4 : spdk_bs_opts_init(&opts, sizeof(opts));
2716 : 4 : snprintf(opts.bstype.bstype, sizeof(opts.bstype.bstype), "TESTTYPE");
2717 : : /*
2718 : : * The bdev_size is 64M, cluster_sz is 1M, so there are 64 clusters. The
2719 : : * blobstore will create 64 md pages by default. We set num_md_pages to 128,
2720 : : * thus the blobstore could grow to the double size.
2721 : : */
2722 : 4 : opts.num_md_pages = 128;
2723 : :
2724 : : /* Initialize a new blob store */
2725 : 4 : spdk_bs_init(dev, &opts, bs_op_with_handle_complete, NULL);
2726 : 4 : poll_threads();
2727 : 4 : CU_ASSERT(g_bserrno == 0);
2728 [ + - ]: 4 : SPDK_CU_ASSERT_FATAL(g_bs != NULL);
2729 : 4 : bs = g_bs;
2730 : :
2731 : : /* Create blob */
2732 : 4 : ut_spdk_blob_opts_init(&blob_opts);
2733 : 4 : blob_opts.num_clusters = 10;
2734 : :
2735 : 4 : blob = ut_blob_create_and_open(bs, &blob_opts);
2736 : 4 : blobid = spdk_blob_get_id(blob);
2737 : :
2738 : : /* Create snapshot */
2739 : 4 : spdk_bs_create_snapshot(bs, blobid, NULL, blob_op_with_id_complete, NULL);
2740 : 4 : poll_threads();
2741 : 4 : CU_ASSERT(g_bserrno == 0);
2742 : 4 : CU_ASSERT(g_blobid != SPDK_BLOBID_INVALID);
2743 : 4 : snapshotid = g_blobid;
2744 : :
2745 : 4 : spdk_bs_open_blob(bs, snapshotid, blob_op_with_handle_complete, NULL);
2746 : 4 : poll_threads();
2747 : 4 : CU_ASSERT(g_bserrno == 0);
2748 [ + - ]: 4 : SPDK_CU_ASSERT_FATAL(g_blob != NULL);
2749 : 4 : snapshot = g_blob;
2750 : :
2751 : 4 : spdk_blob_close(snapshot, blob_op_complete, NULL);
2752 : 4 : poll_threads();
2753 : 4 : CU_ASSERT(g_bserrno == 0);
2754 : :
2755 : 4 : spdk_blob_close(blob, blob_op_complete, NULL);
2756 : 4 : poll_threads();
2757 : 4 : CU_ASSERT(g_bserrno == 0);
2758 : :
2759 : 4 : total_data_clusters = bs->total_data_clusters;
2760 : 4 : CU_ASSERT(bs->num_free_clusters + 10 == total_data_clusters);
2761 : :
2762 : : /* Unload the blob store */
2763 : 4 : spdk_bs_unload(bs, bs_op_complete, NULL);
2764 : 4 : poll_threads();
2765 : 4 : CU_ASSERT(g_bserrno == 0);
2766 : 4 : g_bs = NULL;
2767 : 4 : g_blob = NULL;
2768 : 4 : g_blobid = 0;
2769 : :
2770 : 4 : super_block = (struct spdk_bs_super_block *)g_dev_buffer;
2771 : 4 : CU_ASSERT(super_block->clean == 1);
2772 : :
2773 : 4 : mask = (struct spdk_bs_md_mask *)(g_dev_buffer + super_block->used_cluster_mask_start * BLOCKLEN);
2774 : 4 : CU_ASSERT(mask->type == SPDK_MD_MASK_TYPE_USED_CLUSTERS);
2775 : 4 : CU_ASSERT(mask->length == super_block->size / super_block->cluster_size);
2776 : :
2777 : : /*
2778 : : * We change the mask->length to emulate this scenario: A spdk_bs_grow failed after it changed
2779 : : * the used_cluster bitmap length, but it didn't change the super block yet.
2780 : : */
2781 : 4 : mask->length *= 2;
2782 : :
2783 : : /* Load an existing blob store */
2784 : 4 : dev = init_dev();
2785 : 4 : dev->blockcnt *= 2;
2786 : 4 : spdk_bs_opts_init(&opts, sizeof(opts));
2787 : 4 : opts.clear_method = BS_CLEAR_WITH_NONE;
2788 : 4 : snprintf(opts.bstype.bstype, sizeof(opts.bstype.bstype), "TESTTYPE");
2789 : 4 : spdk_bs_load(dev, &opts, bs_op_with_handle_complete, NULL);
2790 : 4 : poll_threads();
2791 : 4 : CU_ASSERT(g_bserrno == 0);
2792 [ + - ]: 4 : SPDK_CU_ASSERT_FATAL(g_bs != NULL);
2793 : 4 : bs = g_bs;
2794 : :
2795 : : /* Check the capacity is the same as before */
2796 : 4 : CU_ASSERT(bs->total_data_clusters == total_data_clusters);
2797 : 4 : CU_ASSERT(bs->num_free_clusters + 10 == total_data_clusters);
2798 : :
2799 : : /* Check the blob and the snapshot are still available */
2800 : 4 : spdk_bs_open_blob(bs, blobid, blob_op_with_handle_complete, NULL);
2801 : 4 : poll_threads();
2802 : 4 : CU_ASSERT(g_bserrno == 0);
2803 [ + - ]: 4 : SPDK_CU_ASSERT_FATAL(g_blob != NULL);
2804 : 4 : blob = g_blob;
2805 : :
2806 : 4 : spdk_blob_close(blob, blob_op_complete, NULL);
2807 : 4 : poll_threads();
2808 : 4 : CU_ASSERT(g_bserrno == 0);
2809 : :
2810 : 4 : spdk_bs_open_blob(bs, snapshotid, blob_op_with_handle_complete, NULL);
2811 : 4 : poll_threads();
2812 : 4 : CU_ASSERT(g_bserrno == 0);
2813 [ - + ]: 4 : SPDK_CU_ASSERT_FATAL(g_blob != NULL);
2814 : 4 : snapshot = g_blob;
2815 : :
2816 : 4 : spdk_blob_close(snapshot, blob_op_complete, NULL);
2817 : 4 : poll_threads();
2818 : 4 : CU_ASSERT(g_bserrno == 0);
2819 : :
2820 : 4 : spdk_bs_unload(bs, bs_op_complete, NULL);
2821 : 4 : poll_threads();
2822 : 4 : CU_ASSERT(g_bserrno == 0);
2823 : 4 : CU_ASSERT(super_block->clean == 1);
2824 : 4 : g_bs = NULL;
2825 : 4 : }
2826 : :
2827 : : static void
2828 : 4 : bs_type(void)
2829 : : {
2830 : : struct spdk_blob_store *bs;
2831 : : struct spdk_bs_dev *dev;
2832 : : struct spdk_bs_opts opts;
2833 : :
2834 : 4 : dev = init_dev();
2835 : 4 : spdk_bs_opts_init(&opts, sizeof(opts));
2836 : 4 : snprintf(opts.bstype.bstype, sizeof(opts.bstype.bstype), "TESTTYPE");
2837 : :
2838 : : /* Initialize a new blob store */
2839 : 4 : spdk_bs_init(dev, &opts, bs_op_with_handle_complete, NULL);
2840 : 4 : poll_threads();
2841 : 4 : CU_ASSERT(g_bserrno == 0);
2842 [ + - ]: 4 : SPDK_CU_ASSERT_FATAL(g_bs != NULL);
2843 : 4 : bs = g_bs;
2844 : :
2845 : : /* Unload the blob store */
2846 : 4 : spdk_bs_unload(bs, bs_op_complete, NULL);
2847 : 4 : poll_threads();
2848 : 4 : CU_ASSERT(g_bserrno == 0);
2849 : 4 : g_bs = NULL;
2850 : 4 : g_blob = NULL;
2851 : 4 : g_blobid = 0;
2852 : :
2853 : : /* Load non existing blobstore type */
2854 : 4 : dev = init_dev();
2855 : 4 : snprintf(opts.bstype.bstype, sizeof(opts.bstype.bstype), "NONEXISTING");
2856 : 4 : spdk_bs_load(dev, &opts, bs_op_with_handle_complete, NULL);
2857 : 4 : poll_threads();
2858 : 4 : CU_ASSERT(g_bserrno != 0);
2859 : :
2860 : : /* Load with empty blobstore type */
2861 : 4 : dev = init_dev();
2862 : 4 : memset(opts.bstype.bstype, 0, sizeof(opts.bstype.bstype));
2863 : 4 : spdk_bs_load(dev, &opts, bs_op_with_handle_complete, NULL);
2864 : 4 : poll_threads();
2865 : 4 : CU_ASSERT(g_bserrno == 0);
2866 [ + - ]: 4 : SPDK_CU_ASSERT_FATAL(g_bs != NULL);
2867 : 4 : bs = g_bs;
2868 : :
2869 : 4 : spdk_bs_unload(bs, bs_op_complete, NULL);
2870 : 4 : poll_threads();
2871 : 4 : CU_ASSERT(g_bserrno == 0);
2872 : 4 : g_bs = NULL;
2873 : :
2874 : : /* Initialize a new blob store with empty bstype */
2875 : 4 : dev = init_dev();
2876 : 4 : memset(opts.bstype.bstype, 0, sizeof(opts.bstype.bstype));
2877 : 4 : spdk_bs_init(dev, NULL, bs_op_with_handle_complete, NULL);
2878 : 4 : poll_threads();
2879 : 4 : CU_ASSERT(g_bserrno == 0);
2880 [ + - ]: 4 : SPDK_CU_ASSERT_FATAL(g_bs != NULL);
2881 : 4 : bs = g_bs;
2882 : :
2883 : 4 : spdk_bs_unload(bs, bs_op_complete, NULL);
2884 : 4 : poll_threads();
2885 : 4 : CU_ASSERT(g_bserrno == 0);
2886 : 4 : g_bs = NULL;
2887 : :
2888 : : /* Load non existing blobstore type */
2889 : 4 : dev = init_dev();
2890 : 4 : snprintf(opts.bstype.bstype, sizeof(opts.bstype.bstype), "NONEXISTING");
2891 : 4 : spdk_bs_load(dev, &opts, bs_op_with_handle_complete, NULL);
2892 : 4 : poll_threads();
2893 : 4 : CU_ASSERT(g_bserrno != 0);
2894 : :
2895 : : /* Load with empty blobstore type */
2896 : 4 : dev = init_dev();
2897 : 4 : memset(opts.bstype.bstype, 0, sizeof(opts.bstype.bstype));
2898 : 4 : spdk_bs_load(dev, &opts, bs_op_with_handle_complete, NULL);
2899 : 4 : poll_threads();
2900 : 4 : CU_ASSERT(g_bserrno == 0);
2901 [ - + ]: 4 : SPDK_CU_ASSERT_FATAL(g_bs != NULL);
2902 : 4 : bs = g_bs;
2903 : :
2904 : 4 : spdk_bs_unload(bs, bs_op_complete, NULL);
2905 : 4 : poll_threads();
2906 : 4 : CU_ASSERT(g_bserrno == 0);
2907 : 4 : g_bs = NULL;
2908 : 4 : }
2909 : :
2910 : : static void
2911 : 4 : bs_super_block(void)
2912 : : {
2913 : : struct spdk_blob_store *bs;
2914 : : struct spdk_bs_dev *dev;
2915 : : struct spdk_bs_super_block *super_block;
2916 : : struct spdk_bs_opts opts;
2917 : : struct spdk_bs_super_block_ver1 super_block_v1;
2918 : :
2919 : 4 : dev = init_dev();
2920 : 4 : spdk_bs_opts_init(&opts, sizeof(opts));
2921 : 4 : snprintf(opts.bstype.bstype, sizeof(opts.bstype.bstype), "TESTTYPE");
2922 : :
2923 : : /* Initialize a new blob store */
2924 : 4 : spdk_bs_init(dev, &opts, bs_op_with_handle_complete, NULL);
2925 : 4 : poll_threads();
2926 : 4 : CU_ASSERT(g_bserrno == 0);
2927 [ + - ]: 4 : SPDK_CU_ASSERT_FATAL(g_bs != NULL);
2928 : 4 : bs = g_bs;
2929 : :
2930 : : /* Unload the blob store */
2931 : 4 : spdk_bs_unload(bs, bs_op_complete, NULL);
2932 : 4 : poll_threads();
2933 : 4 : CU_ASSERT(g_bserrno == 0);
2934 : 4 : g_bs = NULL;
2935 : 4 : g_blob = NULL;
2936 : 4 : g_blobid = 0;
2937 : :
2938 : : /* Load an existing blob store with version newer than supported */
2939 : 4 : super_block = (struct spdk_bs_super_block *)g_dev_buffer;
2940 : 4 : super_block->version++;
2941 : :
2942 : 4 : dev = init_dev();
2943 : 4 : memset(opts.bstype.bstype, 0, sizeof(opts.bstype.bstype));
2944 : 4 : spdk_bs_load(dev, &opts, bs_op_with_handle_complete, NULL);
2945 : 4 : poll_threads();
2946 : 4 : CU_ASSERT(g_bserrno != 0);
2947 : :
2948 : : /* Create a new blob store with super block version 1 */
2949 : 4 : dev = init_dev();
2950 : 4 : super_block_v1.version = 1;
2951 : 4 : memcpy(super_block_v1.signature, "SPDKBLOB", sizeof(super_block_v1.signature));
2952 : 4 : super_block_v1.length = 0x1000;
2953 : 4 : super_block_v1.clean = 1;
2954 : 4 : super_block_v1.super_blob = 0xFFFFFFFFFFFFFFFF;
2955 : 4 : super_block_v1.cluster_size = 0x100000;
2956 : 4 : super_block_v1.used_page_mask_start = 0x01;
2957 : 4 : super_block_v1.used_page_mask_len = 0x01;
2958 : 4 : super_block_v1.used_cluster_mask_start = 0x02;
2959 : 4 : super_block_v1.used_cluster_mask_len = 0x01;
2960 : 4 : super_block_v1.md_start = 0x03;
2961 : 4 : super_block_v1.md_len = 0x40;
2962 : 4 : memset(super_block_v1.reserved, 0, 4036);
2963 : 4 : super_block_v1.crc = blob_md_page_calc_crc(&super_block_v1);
2964 : 4 : memcpy(g_dev_buffer, &super_block_v1, sizeof(struct spdk_bs_super_block_ver1));
2965 : :
2966 : 4 : memset(opts.bstype.bstype, 0, sizeof(opts.bstype.bstype));
2967 : 4 : spdk_bs_load(dev, &opts, bs_op_with_handle_complete, NULL);
2968 : 4 : poll_threads();
2969 : 4 : CU_ASSERT(g_bserrno == 0);
2970 [ - + ]: 4 : SPDK_CU_ASSERT_FATAL(g_bs != NULL);
2971 : 4 : bs = g_bs;
2972 : :
2973 : 4 : spdk_bs_unload(bs, bs_op_complete, NULL);
2974 : 4 : poll_threads();
2975 : 4 : CU_ASSERT(g_bserrno == 0);
2976 : 4 : g_bs = NULL;
2977 : 4 : }
2978 : :
2979 : : static void
2980 : 4 : bs_test_recover_cluster_count(void)
2981 : : {
2982 : : struct spdk_blob_store *bs;
2983 : : struct spdk_bs_dev *dev;
2984 : : struct spdk_bs_super_block super_block;
2985 : : struct spdk_bs_opts opts;
2986 : :
2987 : 4 : dev = init_dev();
2988 : 4 : spdk_bs_opts_init(&opts, sizeof(opts));
2989 : 4 : snprintf(opts.bstype.bstype, sizeof(opts.bstype.bstype), "TESTTYPE");
2990 : :
2991 : 4 : super_block.version = 3;
2992 : 4 : memcpy(super_block.signature, "SPDKBLOB", sizeof(super_block.signature));
2993 : 4 : super_block.length = 0x1000;
2994 : 4 : super_block.clean = 0;
2995 : 4 : super_block.super_blob = 0xFFFFFFFFFFFFFFFF;
2996 : 4 : super_block.cluster_size = BLOCKLEN;
2997 : 4 : super_block.used_page_mask_start = 0x01;
2998 : 4 : super_block.used_page_mask_len = 0x01;
2999 : 4 : super_block.used_cluster_mask_start = 0x02;
3000 : 4 : super_block.used_cluster_mask_len = 0x01;
3001 : 4 : super_block.used_blobid_mask_start = 0x03;
3002 : 4 : super_block.used_blobid_mask_len = 0x01;
3003 : 4 : super_block.md_start = 0x04;
3004 : 4 : super_block.md_len = 0x40;
3005 : 4 : memset(super_block.bstype.bstype, 0, sizeof(super_block.bstype.bstype));
3006 : 4 : super_block.size = dev->blockcnt * dev->blocklen;
3007 : 4 : super_block.io_unit_size = 0x1000;
3008 : 4 : memset(super_block.reserved, 0, 4000);
3009 : 4 : super_block.crc = blob_md_page_calc_crc(&super_block);
3010 : 4 : memcpy(g_dev_buffer, &super_block, sizeof(struct spdk_bs_super_block));
3011 : :
3012 : 4 : memset(opts.bstype.bstype, 0, sizeof(opts.bstype.bstype));
3013 : 4 : spdk_bs_load(dev, &opts, bs_op_with_handle_complete, NULL);
3014 : 4 : poll_threads();
3015 : 4 : CU_ASSERT(g_bserrno == 0);
3016 [ + - ]: 4 : SPDK_CU_ASSERT_FATAL(g_bs != NULL);
3017 : 4 : bs = g_bs;
3018 : 4 : CU_ASSERT(bs->num_free_clusters == bs->total_clusters - (super_block.md_start +
3019 : : super_block.md_len));
3020 : :
3021 : 4 : spdk_bs_unload(bs, bs_op_complete, NULL);
3022 : 4 : poll_threads();
3023 : 4 : CU_ASSERT(g_bserrno == 0);
3024 : 4 : g_bs = NULL;
3025 : 4 : }
3026 : :
3027 : : static void
3028 : 12 : bs_grow_live_size(uint64_t new_blockcnt)
3029 : : {
3030 : : struct spdk_blob_store *bs;
3031 : : struct spdk_bs_dev *dev;
3032 : : struct spdk_bs_super_block super_block;
3033 : : struct spdk_bs_opts opts;
3034 : : struct spdk_bs_md_mask mask;
3035 : : uint64_t bdev_size;
3036 : : uint64_t total_data_clusters;
3037 : :
3038 : : /*
3039 : : * Further down the test the dev size will be larger than the g_dev_buffer size,
3040 : : * so we set clear_method to NONE, or the blobstore will try to clear the dev and
3041 : : * will write beyond the end of g_dev_buffer.
3042 : : */
3043 : 12 : dev = init_dev();
3044 : 12 : spdk_bs_opts_init(&opts, sizeof(opts));
3045 : 12 : opts.clear_method = BS_CLEAR_WITH_NONE;
3046 : 12 : spdk_bs_init(dev, &opts, bs_op_with_handle_complete, NULL);
3047 : 12 : poll_threads();
3048 : 12 : CU_ASSERT(g_bserrno == 0);
3049 [ + - ]: 12 : SPDK_CU_ASSERT_FATAL(g_bs != NULL);
3050 : 12 : bs = g_bs;
3051 : 12 : CU_ASSERT(spdk_bs_total_data_cluster_count(bs) == 63);
3052 : :
3053 : : /*
3054 : : * Set the dev size according to the new_blockcnt,
3055 : : * then the blobstore will adjust the metadata according to the new size.
3056 : : */
3057 : 12 : dev->blockcnt = new_blockcnt;
3058 : 12 : bdev_size = dev->blockcnt * dev->blocklen;
3059 : 12 : spdk_bs_grow_live(bs, bs_op_complete, NULL);
3060 : 12 : poll_threads();
3061 : 12 : CU_ASSERT(g_bserrno == 0);
3062 : 12 : total_data_clusters = spdk_bs_total_data_cluster_count(bs);
3063 : : /* One cluster of 1MiB size is used for metadata */
3064 : 12 : CU_ASSERT(total_data_clusters == (bdev_size / (1 * 1024 * 1024)) - 1);
3065 : :
3066 : : /* Make sure the super block is updated. */
3067 : 12 : memcpy(&super_block, g_dev_buffer, sizeof(struct spdk_bs_super_block));
3068 : 12 : CU_ASSERT(super_block.size == bdev_size);
3069 : 12 : CU_ASSERT(super_block.clean == 0);
3070 : : /* The used_cluster mask is not written out until first spdk_bs_unload. */
3071 : 12 : memcpy(&mask, g_dev_buffer + super_block.used_cluster_mask_start * BLOCKLEN,
3072 : : sizeof(struct spdk_bs_md_mask));
3073 : 12 : CU_ASSERT(mask.type == 0);
3074 : 12 : CU_ASSERT(mask.length == 0);
3075 : :
3076 : 12 : spdk_bs_unload(bs, bs_op_complete, NULL);
3077 : 12 : poll_threads();
3078 : 12 : CU_ASSERT(g_bserrno == 0);
3079 : 12 : g_bs = NULL;
3080 : :
3081 : : /* Make sure all metadata is correct, super block and used_cluster mask. */
3082 : 12 : memcpy(&super_block, g_dev_buffer, sizeof(struct spdk_bs_super_block));
3083 : 12 : CU_ASSERT(super_block.size == bdev_size);
3084 : 12 : CU_ASSERT(super_block.clean == 1);
3085 : 12 : memcpy(&mask, g_dev_buffer + super_block.used_cluster_mask_start * BLOCKLEN,
3086 : : sizeof(struct spdk_bs_md_mask));
3087 : 12 : CU_ASSERT(mask.type == SPDK_MD_MASK_TYPE_USED_CLUSTERS);
3088 : 12 : CU_ASSERT(mask.length == bdev_size / (1 * 1024 * 1024));
3089 : :
3090 : : /* Load blobstore and check the cluster counts again. */
3091 : 12 : dev = init_dev();
3092 : 12 : dev->blockcnt = new_blockcnt;
3093 : 12 : spdk_bs_load(dev, NULL, bs_op_with_handle_complete, NULL);
3094 : 12 : poll_threads();
3095 : 12 : CU_ASSERT(g_bserrno == 0);
3096 [ - + ]: 12 : SPDK_CU_ASSERT_FATAL(g_bs != NULL);
3097 : 12 : CU_ASSERT(super_block.clean == 1);
3098 : 12 : bs = g_bs;
3099 : 12 : CU_ASSERT(total_data_clusters == spdk_bs_total_data_cluster_count(bs));
3100 : :
3101 : : /* Perform grow without change in size, expected pass. */
3102 : 12 : spdk_bs_grow_live(bs, bs_op_complete, NULL);
3103 : 12 : poll_threads();
3104 : 12 : CU_ASSERT(g_bserrno == 0);
3105 : 12 : CU_ASSERT(total_data_clusters == spdk_bs_total_data_cluster_count(bs));
3106 : 12 : memcpy(&super_block, g_dev_buffer, sizeof(struct spdk_bs_super_block));
3107 : 12 : CU_ASSERT(super_block.size == bdev_size);
3108 : 12 : CU_ASSERT(super_block.clean == 1);
3109 : :
3110 : 12 : spdk_bs_unload(bs, bs_op_complete, NULL);
3111 : 12 : poll_threads();
3112 : 12 : CU_ASSERT(g_bserrno == 0);
3113 : 12 : g_bs = NULL;
3114 : 12 : }
3115 : :
3116 : : static void
3117 : 4 : bs_grow_live(void)
3118 : : {
3119 : : /* No change expected */
3120 : 4 : bs_grow_live_size(DEV_BUFFER_BLOCKCNT);
3121 : :
3122 : : /* Size slightly increased, but not enough to increase cluster count */
3123 : 4 : bs_grow_live_size(DEV_BUFFER_BLOCKCNT + 1);
3124 : :
3125 : : /* Size doubled, increasing the cluster count */
3126 : 4 : bs_grow_live_size(DEV_BUFFER_BLOCKCNT * 2);
3127 : 4 : }
3128 : :
3129 : : static void
3130 : 4 : bs_grow_live_no_space(void)
3131 : : {
3132 : : struct spdk_blob_store *bs;
3133 : : struct spdk_bs_dev *dev;
3134 : : struct spdk_bs_super_block super_block;
3135 : : struct spdk_bs_opts opts;
3136 : : struct spdk_bs_md_mask mask;
3137 : : uint64_t bdev_size_init;
3138 : : uint64_t total_data_clusters, max_clusters;
3139 : :
3140 : : /*
3141 : : * Further down the test the dev size will be larger than the g_dev_buffer size,
3142 : : * so we set clear_method to NONE, or the blobstore will try to clear the dev and
3143 : : * will write beyond the end of g_dev_buffer.
3144 : : */
3145 : 4 : dev = init_dev();
3146 : 4 : bdev_size_init = dev->blockcnt * dev->blocklen;
3147 : 4 : spdk_bs_opts_init(&opts, sizeof(opts));
3148 : 4 : opts.clear_method = BS_CLEAR_WITH_NONE;
3149 : 4 : spdk_bs_init(dev, &opts, bs_op_with_handle_complete, NULL);
3150 : 4 : poll_threads();
3151 : 4 : CU_ASSERT(g_bserrno == 0);
3152 [ + - ]: 4 : SPDK_CU_ASSERT_FATAL(g_bs != NULL);
3153 : 4 : bs = g_bs;
3154 : 4 : total_data_clusters = spdk_bs_total_data_cluster_count(bs);
3155 : 4 : CU_ASSERT(total_data_clusters == 63);
3156 : :
3157 : : /*
3158 : : * The default dev size is 64M, here we set the dev size to 32M,
3159 : : * expecting EILSEQ due to super_block validation and no change in blobstore.
3160 : : */
3161 : 4 : dev->blockcnt = (32L * 1024L * 1024L) / dev->blocklen;
3162 : 4 : spdk_bs_grow_live(bs, bs_op_complete, NULL);
3163 : 4 : poll_threads();
3164 : : /* This error code comes from bs_super_validate() */
3165 : 4 : CU_ASSERT(g_bserrno == -EILSEQ);
3166 : 4 : CU_ASSERT(total_data_clusters == spdk_bs_total_data_cluster_count(bs));
3167 : 4 : memcpy(&super_block, g_dev_buffer, sizeof(struct spdk_bs_super_block));
3168 : 4 : CU_ASSERT(super_block.size == bdev_size_init);
3169 : :
3170 : : /*
3171 : : * Blobstore in this test has only space for single md_page for used_clusters,
3172 : : * which fits 1 bit per cluster minus the md header.
3173 : : *
3174 : : * Dev size is increased to exceed the reserved space for the used_cluster_mask
3175 : : * in the metadata, expecting ENOSPC and no change in blobstore.
3176 : : */
3177 : 4 : max_clusters = (spdk_bs_get_page_size(bs) - sizeof(struct spdk_bs_md_mask)) * 8;
3178 : 4 : max_clusters += 1;
3179 : 4 : dev->blockcnt = (max_clusters * spdk_bs_get_cluster_size(bs)) / dev->blocklen;
3180 : 4 : spdk_bs_grow_live(bs, bs_op_complete, NULL);
3181 : 4 : poll_threads();
3182 : 4 : CU_ASSERT(g_bserrno == -ENOSPC);
3183 : 4 : CU_ASSERT(total_data_clusters == spdk_bs_total_data_cluster_count(bs));
3184 : 4 : memcpy(&super_block, g_dev_buffer, sizeof(struct spdk_bs_super_block));
3185 : 4 : CU_ASSERT(super_block.size == bdev_size_init);
3186 : :
3187 : : /*
3188 : : * No change should have occurred for the duration of the test,
3189 : : * unload blobstore and check metadata.
3190 : : */
3191 : 4 : spdk_bs_unload(bs, bs_op_complete, NULL);
3192 : 4 : poll_threads();
3193 : 4 : CU_ASSERT(g_bserrno == 0);
3194 : 4 : g_bs = NULL;
3195 : :
3196 : : /* Make sure all metadata is correct, super block and used_cluster mask. */
3197 : 4 : memcpy(&super_block, g_dev_buffer, sizeof(struct spdk_bs_super_block));
3198 : 4 : CU_ASSERT(super_block.size == bdev_size_init);
3199 : 4 : CU_ASSERT(super_block.clean == 1);
3200 : 4 : memcpy(&mask, g_dev_buffer + super_block.used_cluster_mask_start * BLOCKLEN,
3201 : : sizeof(struct spdk_bs_md_mask));
3202 : 4 : CU_ASSERT(mask.type == SPDK_MD_MASK_TYPE_USED_CLUSTERS);
3203 : 4 : CU_ASSERT(mask.length == bdev_size_init / (1 * 1024 * 1024));
3204 : :
3205 : : /* Load blobstore and check the cluster counts again. */
3206 : 4 : dev = init_dev();
3207 : 4 : spdk_bs_load(dev, NULL, bs_op_with_handle_complete, NULL);
3208 : 4 : poll_threads();
3209 : 4 : CU_ASSERT(g_bserrno == 0);
3210 [ - + ]: 4 : SPDK_CU_ASSERT_FATAL(g_bs != NULL);
3211 : 4 : bs = g_bs;
3212 : 4 : CU_ASSERT(total_data_clusters == spdk_bs_total_data_cluster_count(bs));
3213 : :
3214 : 4 : spdk_bs_unload(bs, bs_op_complete, NULL);
3215 : 4 : poll_threads();
3216 : 4 : CU_ASSERT(g_bserrno == 0);
3217 : 4 : g_bs = NULL;
3218 : 4 : }
3219 : :
3220 : : static void
3221 : 4 : bs_test_grow(void)
3222 : : {
3223 : : struct spdk_blob_store *bs;
3224 : : struct spdk_bs_dev *dev;
3225 : : struct spdk_bs_super_block super_block;
3226 : : struct spdk_bs_opts opts;
3227 : : struct spdk_bs_md_mask mask;
3228 : : uint64_t bdev_size;
3229 : :
3230 : 4 : dev = init_dev();
3231 : 4 : bdev_size = dev->blockcnt * dev->blocklen;
3232 : 4 : spdk_bs_opts_init(&opts, sizeof(opts));
3233 : 4 : spdk_bs_init(dev, &opts, bs_op_with_handle_complete, NULL);
3234 : 4 : poll_threads();
3235 : 4 : CU_ASSERT(g_bserrno == 0);
3236 [ + - ]: 4 : SPDK_CU_ASSERT_FATAL(g_bs != NULL);
3237 : 4 : bs = g_bs;
3238 : :
3239 : 4 : spdk_bs_unload(bs, bs_op_complete, NULL);
3240 : 4 : poll_threads();
3241 : 4 : CU_ASSERT(g_bserrno == 0);
3242 : 4 : g_bs = NULL;
3243 : :
3244 : : /*
3245 : : * To make sure all the metadata are updated to the disk,
3246 : : * we check the g_dev_buffer after spdk_bs_unload.
3247 : : */
3248 : 4 : memcpy(&super_block, g_dev_buffer, sizeof(struct spdk_bs_super_block));
3249 : 4 : CU_ASSERT(super_block.size == bdev_size);
3250 : :
3251 : : /*
3252 : : * Make sure the used_cluster mask is correct.
3253 : : */
3254 : 4 : memcpy(&mask, g_dev_buffer + super_block.used_cluster_mask_start * BLOCKLEN,
3255 : : sizeof(struct spdk_bs_md_mask));
3256 : 4 : CU_ASSERT(mask.type == SPDK_MD_MASK_TYPE_USED_CLUSTERS);
3257 : 4 : CU_ASSERT(mask.length == bdev_size / (1 * 1024 * 1024));
3258 : :
3259 : : /*
3260 : : * The default dev size is 64M, here we set the dev size to 128M,
3261 : : * then the blobstore will adjust the metadata according to the new size.
3262 : : * The dev size is larger than the g_dev_buffer size, so we set clear_method
3263 : : * to NONE, or the blobstore will try to clear the dev and will write beyond
3264 : : * the end of g_dev_buffer.
3265 : : */
3266 : 4 : dev = init_dev();
3267 : 4 : dev->blockcnt = (128L * 1024L * 1024L) / dev->blocklen;
3268 : 4 : bdev_size = dev->blockcnt * dev->blocklen;
3269 : 4 : spdk_bs_opts_init(&opts, sizeof(opts));
3270 : 4 : opts.clear_method = BS_CLEAR_WITH_NONE;
3271 : 4 : spdk_bs_grow(dev, &opts, bs_op_with_handle_complete, NULL);
3272 : 4 : poll_threads();
3273 : 4 : CU_ASSERT(g_bserrno == 0);
3274 [ - + ]: 4 : SPDK_CU_ASSERT_FATAL(g_bs != NULL);
3275 : 4 : bs = g_bs;
3276 : :
3277 : : /*
3278 : : * After spdk_bs_grow, all metadata are updated to the disk.
3279 : : * So we can check g_dev_buffer now.
3280 : : */
3281 : 4 : memcpy(&super_block, g_dev_buffer, sizeof(struct spdk_bs_super_block));
3282 : 4 : CU_ASSERT(super_block.size == bdev_size);
3283 : :
3284 : : /*
3285 : : * Make sure the used_cluster mask has been updated according to the bdev size
3286 : : */
3287 : 4 : memcpy(&mask, g_dev_buffer + super_block.used_cluster_mask_start * BLOCKLEN,
3288 : : sizeof(struct spdk_bs_md_mask));
3289 : 4 : CU_ASSERT(mask.type == SPDK_MD_MASK_TYPE_USED_CLUSTERS);
3290 : 4 : CU_ASSERT(mask.length == bdev_size / (1 * 1024 * 1024));
3291 : :
3292 : 4 : spdk_bs_unload(bs, bs_op_complete, NULL);
3293 : 4 : poll_threads();
3294 : 4 : CU_ASSERT(g_bserrno == 0);
3295 : 4 : g_bs = NULL;
3296 : 4 : }
3297 : :
3298 : : /*
3299 : : * Create a blobstore and then unload it.
3300 : : */
3301 : : static void
3302 : 4 : bs_unload(void)
3303 : : {
3304 : 4 : struct spdk_blob_store *bs = g_bs;
3305 : : struct spdk_blob *blob;
3306 : :
3307 : : /* Create a blob and open it. */
3308 : 4 : blob = ut_blob_create_and_open(bs, NULL);
3309 : :
3310 : : /* Try to unload blobstore, should fail with open blob */
3311 : 4 : g_bserrno = -1;
3312 : 4 : spdk_bs_unload(bs, bs_op_complete, NULL);
3313 : 4 : poll_threads();
3314 : 4 : CU_ASSERT(g_bserrno == -EBUSY);
3315 [ + - ]: 4 : SPDK_CU_ASSERT_FATAL(g_bs != NULL);
3316 : :
3317 : : /* Close the blob, then successfully unload blobstore */
3318 : 4 : g_bserrno = -1;
3319 : 4 : spdk_blob_close(blob, blob_op_complete, NULL);
3320 : 4 : poll_threads();
3321 : 4 : CU_ASSERT(g_bserrno == 0);
3322 : 4 : }
3323 : :
3324 : : /*
3325 : : * Create a blobstore with a cluster size different than the default, and ensure it is
3326 : : * persisted.
3327 : : */
3328 : : static void
3329 : 4 : bs_cluster_sz(void)
3330 : : {
3331 : : struct spdk_blob_store *bs;
3332 : : struct spdk_bs_dev *dev;
3333 : : struct spdk_bs_opts opts;
3334 : : uint32_t cluster_sz;
3335 : :
3336 : : /* Set cluster size to zero */
3337 : 4 : dev = init_dev();
3338 : 4 : spdk_bs_opts_init(&opts, sizeof(opts));
3339 : 4 : opts.cluster_sz = 0;
3340 : :
3341 : : /* Initialize a new blob store */
3342 : 4 : spdk_bs_init(dev, &opts, bs_op_with_handle_complete, NULL);
3343 : 4 : poll_threads();
3344 : 4 : CU_ASSERT(g_bserrno == -EINVAL);
3345 [ + - ]: 4 : SPDK_CU_ASSERT_FATAL(g_bs == NULL);
3346 : :
3347 : : /*
3348 : : * Set cluster size to blobstore page size,
3349 : : * to work it is required to be at least twice the blobstore page size.
3350 : : */
3351 : 4 : dev = init_dev();
3352 : 4 : spdk_bs_opts_init(&opts, sizeof(opts));
3353 : 4 : opts.cluster_sz = SPDK_BS_PAGE_SIZE;
3354 : :
3355 : : /* Initialize a new blob store */
3356 : 4 : spdk_bs_init(dev, &opts, bs_op_with_handle_complete, NULL);
3357 : 4 : poll_threads();
3358 : 4 : CU_ASSERT(g_bserrno == -ENOMEM);
3359 [ + - ]: 4 : SPDK_CU_ASSERT_FATAL(g_bs == NULL);
3360 : :
3361 : : /*
3362 : : * Set cluster size to lower than page size,
3363 : : * to work it is required to be at least twice the blobstore page size.
3364 : : */
3365 : 4 : dev = init_dev();
3366 : 4 : spdk_bs_opts_init(&opts, sizeof(opts));
3367 : 4 : opts.cluster_sz = SPDK_BS_PAGE_SIZE - 1;
3368 : :
3369 : : /* Initialize a new blob store */
3370 : 4 : spdk_bs_init(dev, &opts, bs_op_with_handle_complete, NULL);
3371 : 4 : poll_threads();
3372 : 4 : CU_ASSERT(g_bserrno == -EINVAL);
3373 [ + - ]: 4 : SPDK_CU_ASSERT_FATAL(g_bs == NULL);
3374 : :
3375 : : /* Set cluster size to twice the default */
3376 : 4 : dev = init_dev();
3377 : 4 : spdk_bs_opts_init(&opts, sizeof(opts));
3378 : 4 : opts.cluster_sz *= 2;
3379 : 4 : cluster_sz = opts.cluster_sz;
3380 : :
3381 : : /* Initialize a new blob store */
3382 : 4 : spdk_bs_init(dev, &opts, bs_op_with_handle_complete, NULL);
3383 : 4 : poll_threads();
3384 : 4 : CU_ASSERT(g_bserrno == 0);
3385 [ - + ]: 4 : SPDK_CU_ASSERT_FATAL(g_bs != NULL);
3386 : 4 : bs = g_bs;
3387 : :
3388 : 4 : CU_ASSERT(spdk_bs_get_cluster_size(bs) == cluster_sz);
3389 : :
3390 : 4 : ut_bs_reload(&bs, &opts);
3391 : :
3392 : 4 : CU_ASSERT(spdk_bs_get_cluster_size(bs) == cluster_sz);
3393 : :
3394 : 4 : spdk_bs_unload(bs, bs_op_complete, NULL);
3395 : 4 : poll_threads();
3396 : 4 : CU_ASSERT(g_bserrno == 0);
3397 : 4 : g_bs = NULL;
3398 : 4 : }
3399 : :
3400 : : /*
3401 : : * Create a blobstore, reload it and ensure total usable cluster count
3402 : : * stays the same.
3403 : : */
3404 : : static void
3405 : 4 : bs_usable_clusters(void)
3406 : : {
3407 : 4 : struct spdk_blob_store *bs = g_bs;
3408 : : struct spdk_blob *blob;
3409 : : uint32_t clusters;
3410 : : int i;
3411 : :
3412 : :
3413 : 4 : clusters = spdk_bs_total_data_cluster_count(bs);
3414 : :
3415 : 4 : ut_bs_reload(&bs, NULL);
3416 : :
3417 : 4 : CU_ASSERT(spdk_bs_total_data_cluster_count(bs) == clusters);
3418 : :
3419 : : /* Create and resize blobs to make sure that usable cluster count won't change */
3420 [ + + ]: 20 : for (i = 0; i < 4; i++) {
3421 : 16 : g_bserrno = -1;
3422 : 16 : g_blobid = SPDK_BLOBID_INVALID;
3423 : 16 : blob = ut_blob_create_and_open(bs, NULL);
3424 : :
3425 : 16 : spdk_blob_resize(blob, 10, blob_op_complete, NULL);
3426 : 16 : poll_threads();
3427 : 16 : CU_ASSERT(g_bserrno == 0);
3428 : :
3429 : 16 : g_bserrno = -1;
3430 : 16 : spdk_blob_close(blob, blob_op_complete, NULL);
3431 : 16 : poll_threads();
3432 : 16 : CU_ASSERT(g_bserrno == 0);
3433 : :
3434 : 16 : CU_ASSERT(spdk_bs_total_data_cluster_count(bs) == clusters);
3435 : 16 : }
3436 : :
3437 : : /* Reload the blob store to make sure that nothing changed */
3438 : 4 : ut_bs_reload(&bs, NULL);
3439 : :
3440 : 4 : CU_ASSERT(spdk_bs_total_data_cluster_count(bs) == clusters);
3441 : 4 : }
3442 : :
3443 : : /*
3444 : : * Test resizing of the metadata blob. This requires creating enough blobs
3445 : : * so that one cluster is not enough to fit the metadata for those blobs.
3446 : : * To induce this condition to happen more quickly, we reduce the cluster
3447 : : * size to 16KB, which means only 4 4KB blob metadata pages can fit.
3448 : : */
3449 : : static void
3450 : 4 : bs_resize_md(void)
3451 : : {
3452 : : struct spdk_blob_store *bs;
3453 : 4 : const int CLUSTER_PAGE_COUNT = 4;
3454 : 4 : const int NUM_BLOBS = CLUSTER_PAGE_COUNT * 4;
3455 : : struct spdk_bs_dev *dev;
3456 : : struct spdk_bs_opts opts;
3457 : : struct spdk_blob *blob;
3458 : : struct spdk_blob_opts blob_opts;
3459 : : uint32_t cluster_sz;
3460 : 4 : spdk_blob_id blobids[NUM_BLOBS];
3461 : : int i;
3462 : :
3463 : :
3464 : 4 : dev = init_dev();
3465 : 4 : spdk_bs_opts_init(&opts, sizeof(opts));
3466 : 4 : opts.cluster_sz = CLUSTER_PAGE_COUNT * BLOCKLEN;
3467 : 4 : cluster_sz = opts.cluster_sz;
3468 : :
3469 : : /* Initialize a new blob store */
3470 : 4 : spdk_bs_init(dev, &opts, bs_op_with_handle_complete, NULL);
3471 : 4 : poll_threads();
3472 : 4 : CU_ASSERT(g_bserrno == 0);
3473 [ + - ]: 4 : SPDK_CU_ASSERT_FATAL(g_bs != NULL);
3474 : 4 : bs = g_bs;
3475 : :
3476 : 4 : CU_ASSERT(spdk_bs_get_cluster_size(bs) == cluster_sz);
3477 : :
3478 : 4 : ut_spdk_blob_opts_init(&blob_opts);
3479 : :
3480 [ + + ]: 68 : for (i = 0; i < NUM_BLOBS; i++) {
3481 : 64 : g_bserrno = -1;
3482 : 64 : g_blobid = SPDK_BLOBID_INVALID;
3483 : 64 : spdk_bs_create_blob_ext(bs, &blob_opts, blob_op_with_id_complete, NULL);
3484 : 64 : poll_threads();
3485 : 64 : CU_ASSERT(g_bserrno == 0);
3486 : 64 : CU_ASSERT(g_blobid != SPDK_BLOBID_INVALID);
3487 : 64 : blobids[i] = g_blobid;
3488 : 64 : }
3489 : :
3490 : 4 : ut_bs_reload(&bs, &opts);
3491 : :
3492 : 4 : CU_ASSERT(spdk_bs_get_cluster_size(bs) == cluster_sz);
3493 : :
3494 [ + + ]: 68 : for (i = 0; i < NUM_BLOBS; i++) {
3495 : 64 : g_bserrno = -1;
3496 : 64 : g_blob = NULL;
3497 : 64 : spdk_bs_open_blob(bs, blobids[i], blob_op_with_handle_complete, NULL);
3498 : 64 : poll_threads();
3499 : 64 : CU_ASSERT(g_bserrno == 0);
3500 : 64 : CU_ASSERT(g_blob != NULL);
3501 : 64 : blob = g_blob;
3502 : 64 : g_bserrno = -1;
3503 : 64 : spdk_blob_close(blob, blob_op_complete, NULL);
3504 : 64 : poll_threads();
3505 : 64 : CU_ASSERT(g_bserrno == 0);
3506 : 64 : }
3507 : :
3508 : 4 : spdk_bs_unload(bs, bs_op_complete, NULL);
3509 : 4 : poll_threads();
3510 : 4 : CU_ASSERT(g_bserrno == 0);
3511 : 4 : g_bs = NULL;
3512 : 4 : }
3513 : :
3514 : : static void
3515 : 4 : bs_destroy(void)
3516 : : {
3517 : : struct spdk_blob_store *bs;
3518 : : struct spdk_bs_dev *dev;
3519 : :
3520 : : /* Initialize a new blob store */
3521 : 4 : dev = init_dev();
3522 : 4 : spdk_bs_init(dev, NULL, bs_op_with_handle_complete, NULL);
3523 : 4 : poll_threads();
3524 : 4 : CU_ASSERT(g_bserrno == 0);
3525 [ + - ]: 4 : SPDK_CU_ASSERT_FATAL(g_bs != NULL);
3526 : 4 : bs = g_bs;
3527 : :
3528 : : /* Destroy the blob store */
3529 : 4 : g_bserrno = -1;
3530 : 4 : spdk_bs_destroy(bs, bs_op_complete, NULL);
3531 : 4 : poll_threads();
3532 : 4 : CU_ASSERT(g_bserrno == 0);
3533 : :
3534 : : /* Loading an non-existent blob store should fail. */
3535 : 4 : g_bs = NULL;
3536 : 4 : dev = init_dev();
3537 : :
3538 : 4 : g_bserrno = 0;
3539 : 4 : spdk_bs_load(dev, NULL, bs_op_with_handle_complete, NULL);
3540 : 4 : poll_threads();
3541 : 4 : CU_ASSERT(g_bserrno != 0);
3542 : 4 : }
3543 : :
3544 : : /* Try to hit all of the corner cases associated with serializing
3545 : : * a blob to disk
3546 : : */
3547 : : static void
3548 : 4 : blob_serialize_test(void)
3549 : : {
3550 : : struct spdk_bs_dev *dev;
3551 : : struct spdk_bs_opts opts;
3552 : : struct spdk_blob_store *bs;
3553 : : spdk_blob_id blobid[2];
3554 : : struct spdk_blob *blob[2];
3555 : : uint64_t i;
3556 : : char *value;
3557 : : int rc;
3558 : :
3559 : 4 : dev = init_dev();
3560 : :
3561 : : /* Initialize a new blobstore with very small clusters */
3562 : 4 : spdk_bs_opts_init(&opts, sizeof(opts));
3563 : 4 : opts.cluster_sz = dev->blocklen * 8;
3564 : 4 : spdk_bs_init(dev, &opts, bs_op_with_handle_complete, NULL);
3565 : 4 : poll_threads();
3566 : 4 : CU_ASSERT(g_bserrno == 0);
3567 [ + - ]: 4 : SPDK_CU_ASSERT_FATAL(g_bs != NULL);
3568 : 4 : bs = g_bs;
3569 : :
3570 : : /* Create and open two blobs */
3571 [ + + ]: 12 : for (i = 0; i < 2; i++) {
3572 : 8 : blob[i] = ut_blob_create_and_open(bs, NULL);
3573 : 8 : blobid[i] = spdk_blob_get_id(blob[i]);
3574 : :
3575 : : /* Set a fairly large xattr on both blobs to eat up
3576 : : * metadata space
3577 : : */
3578 : 8 : value = calloc(dev->blocklen - 64, sizeof(char));
3579 [ + - ]: 8 : SPDK_CU_ASSERT_FATAL(value != NULL);
3580 : 8 : memset(value, i, dev->blocklen / 2);
3581 : 8 : rc = spdk_blob_set_xattr(blob[i], "name", value, dev->blocklen - 64);
3582 : 8 : CU_ASSERT(rc == 0);
3583 : 8 : free(value);
3584 : 8 : }
3585 : :
3586 : : /* Resize the blobs, alternating 1 cluster at a time.
3587 : : * This thwarts run length encoding and will cause spill
3588 : : * over of the extents.
3589 : : */
3590 [ + + ]: 28 : for (i = 0; i < 6; i++) {
3591 : 24 : spdk_blob_resize(blob[i % 2], (i / 2) + 1, blob_op_complete, NULL);
3592 : 24 : poll_threads();
3593 : 24 : CU_ASSERT(g_bserrno == 0);
3594 : 24 : }
3595 : :
3596 [ + + ]: 12 : for (i = 0; i < 2; i++) {
3597 : 8 : spdk_blob_sync_md(blob[i], blob_op_complete, NULL);
3598 : 8 : poll_threads();
3599 : 8 : CU_ASSERT(g_bserrno == 0);
3600 : 8 : }
3601 : :
3602 : : /* Close the blobs */
3603 [ + + ]: 12 : for (i = 0; i < 2; i++) {
3604 : 8 : spdk_blob_close(blob[i], blob_op_complete, NULL);
3605 : 8 : poll_threads();
3606 : 8 : CU_ASSERT(g_bserrno == 0);
3607 : 8 : }
3608 : :
3609 : 4 : ut_bs_reload(&bs, &opts);
3610 : :
3611 [ + + ]: 12 : for (i = 0; i < 2; i++) {
3612 : 8 : blob[i] = NULL;
3613 : :
3614 : 8 : spdk_bs_open_blob(bs, blobid[i], blob_op_with_handle_complete, NULL);
3615 : 8 : poll_threads();
3616 : 8 : CU_ASSERT(g_bserrno == 0);
3617 : 8 : CU_ASSERT(g_blob != NULL);
3618 : 8 : blob[i] = g_blob;
3619 : :
3620 : 8 : CU_ASSERT(spdk_blob_get_num_clusters(blob[i]) == 3);
3621 : :
3622 : 8 : spdk_blob_close(blob[i], blob_op_complete, NULL);
3623 : 8 : poll_threads();
3624 : 8 : CU_ASSERT(g_bserrno == 0);
3625 : 8 : }
3626 : :
3627 : 4 : spdk_bs_unload(bs, bs_op_complete, NULL);
3628 : 4 : poll_threads();
3629 : 4 : CU_ASSERT(g_bserrno == 0);
3630 : 4 : g_bs = NULL;
3631 : 4 : }
3632 : :
3633 : : static void
3634 : 4 : blob_crc(void)
3635 : : {
3636 : 4 : struct spdk_blob_store *bs = g_bs;
3637 : : struct spdk_blob *blob;
3638 : : spdk_blob_id blobid;
3639 : : uint32_t page_num;
3640 : : int index;
3641 : : struct spdk_blob_md_page *page;
3642 : :
3643 : 4 : blob = ut_blob_create_and_open(bs, NULL);
3644 : 4 : blobid = spdk_blob_get_id(blob);
3645 : :
3646 : 4 : spdk_blob_close(blob, blob_op_complete, NULL);
3647 : 4 : poll_threads();
3648 : 4 : CU_ASSERT(g_bserrno == 0);
3649 : :
3650 : 4 : page_num = bs_blobid_to_page(blobid);
3651 : 4 : index = DEV_BUFFER_BLOCKLEN * (bs->md_start + page_num);
3652 : 4 : page = (struct spdk_blob_md_page *)&g_dev_buffer[index];
3653 : 4 : page->crc = 0;
3654 : :
3655 : 4 : spdk_bs_open_blob(bs, blobid, blob_op_with_handle_complete, NULL);
3656 : 4 : poll_threads();
3657 : 4 : CU_ASSERT(g_bserrno == -EINVAL);
3658 : 4 : CU_ASSERT(g_blob == NULL);
3659 : 4 : g_bserrno = 0;
3660 : :
3661 : 4 : spdk_bs_delete_blob(bs, blobid, blob_op_complete, NULL);
3662 : 4 : poll_threads();
3663 : 4 : CU_ASSERT(g_bserrno == -EINVAL);
3664 : 4 : }
3665 : :
3666 : : static void
3667 : 4 : super_block_crc(void)
3668 : : {
3669 : : struct spdk_blob_store *bs;
3670 : : struct spdk_bs_dev *dev;
3671 : : struct spdk_bs_super_block *super_block;
3672 : :
3673 : 4 : dev = init_dev();
3674 : 4 : spdk_bs_init(dev, NULL, bs_op_with_handle_complete, NULL);
3675 : 4 : poll_threads();
3676 : 4 : CU_ASSERT(g_bserrno == 0);
3677 [ + - ]: 4 : SPDK_CU_ASSERT_FATAL(g_bs != NULL);
3678 : 4 : bs = g_bs;
3679 : :
3680 : 4 : spdk_bs_unload(bs, bs_op_complete, NULL);
3681 : 4 : poll_threads();
3682 : 4 : CU_ASSERT(g_bserrno == 0);
3683 : 4 : g_bs = NULL;
3684 : :
3685 : 4 : super_block = (struct spdk_bs_super_block *)g_dev_buffer;
3686 : 4 : super_block->crc = 0;
3687 : 4 : dev = init_dev();
3688 : :
3689 : : /* Load an existing blob store */
3690 : 4 : g_bserrno = 0;
3691 : 4 : spdk_bs_load(dev, NULL, bs_op_with_handle_complete, NULL);
3692 : 4 : poll_threads();
3693 : 4 : CU_ASSERT(g_bserrno == -EILSEQ);
3694 : 4 : }
3695 : :
3696 : : /* For blob dirty shutdown test case we do the following sub-test cases:
3697 : : * 1 Initialize new blob store and create 1 super blob with some xattrs, then we
3698 : : * dirty shutdown and reload the blob store and verify the xattrs.
3699 : : * 2 Resize the blob from 10 clusters to 20 clusters and then dirty shutdown,
3700 : : * reload the blob store and verify the clusters number.
3701 : : * 3 Create the second blob and then dirty shutdown, reload the blob store
3702 : : * and verify the second blob.
3703 : : * 4 Delete the second blob and then dirty shutdown, reload the blob store
3704 : : * and verify the second blob is invalid.
3705 : : * 5 Create the second blob again and also create the third blob, modify the
3706 : : * md of second blob which makes the md invalid, and then dirty shutdown,
3707 : : * reload the blob store verify the second blob, it should invalid and also
3708 : : * verify the third blob, it should correct.
3709 : : */
3710 : : static void
3711 : 4 : blob_dirty_shutdown(void)
3712 : : {
3713 : : int rc;
3714 : : int index;
3715 : 4 : struct spdk_blob_store *bs = g_bs;
3716 : : spdk_blob_id blobid1, blobid2, blobid3;
3717 : 4 : struct spdk_blob *blob = g_blob;
3718 : : uint64_t length;
3719 : : uint64_t free_clusters;
3720 : : const void *value;
3721 : : size_t value_len;
3722 : : uint32_t page_num;
3723 : : struct spdk_blob_md_page *page;
3724 : : struct spdk_blob_opts blob_opts;
3725 : :
3726 : : /* Create first blob */
3727 : 4 : blobid1 = spdk_blob_get_id(blob);
3728 : :
3729 : : /* Set some xattrs */
3730 : 4 : rc = spdk_blob_set_xattr(blob, "name", "log.txt", strlen("log.txt") + 1);
3731 : 4 : CU_ASSERT(rc == 0);
3732 : :
3733 : 4 : length = 2345;
3734 : 4 : rc = spdk_blob_set_xattr(blob, "length", &length, sizeof(length));
3735 : 4 : CU_ASSERT(rc == 0);
3736 : :
3737 : : /* Put xattr that fits exactly single page.
3738 : : * This results in adding additional pages to MD.
3739 : : * First is flags and smaller xattr, second the large xattr,
3740 : : * third are just the extents.
3741 : : */
3742 : 4 : size_t xattr_length = 4072 - sizeof(struct spdk_blob_md_descriptor_xattr) -
3743 : : strlen("large_xattr");
3744 : 4 : char *xattr = calloc(xattr_length, sizeof(char));
3745 [ + - ]: 4 : SPDK_CU_ASSERT_FATAL(xattr != NULL);
3746 : 4 : rc = spdk_blob_set_xattr(blob, "large_xattr", xattr, xattr_length);
3747 : 4 : free(xattr);
3748 [ + - ]: 4 : SPDK_CU_ASSERT_FATAL(rc == 0);
3749 : :
3750 : : /* Resize the blob */
3751 : 4 : spdk_blob_resize(blob, 10, blob_op_complete, NULL);
3752 : 4 : poll_threads();
3753 : 4 : CU_ASSERT(g_bserrno == 0);
3754 : :
3755 : : /* Set the blob as the super blob */
3756 : 4 : spdk_bs_set_super(bs, blobid1, blob_op_complete, NULL);
3757 : 4 : poll_threads();
3758 : 4 : CU_ASSERT(g_bserrno == 0);
3759 : :
3760 : 4 : free_clusters = spdk_bs_free_cluster_count(bs);
3761 : :
3762 : 4 : spdk_blob_close(blob, blob_op_complete, NULL);
3763 : 4 : poll_threads();
3764 : 4 : CU_ASSERT(g_bserrno == 0);
3765 : 4 : blob = NULL;
3766 : 4 : g_blob = NULL;
3767 : 4 : g_blobid = SPDK_BLOBID_INVALID;
3768 : :
3769 : 4 : ut_bs_dirty_load(&bs, NULL);
3770 : :
3771 : : /* Get the super blob */
3772 : 4 : spdk_bs_get_super(bs, blob_op_with_id_complete, NULL);
3773 : 4 : poll_threads();
3774 : 4 : CU_ASSERT(g_bserrno == 0);
3775 : 4 : CU_ASSERT(blobid1 == g_blobid);
3776 : :
3777 : 4 : spdk_bs_open_blob(bs, blobid1, blob_op_with_handle_complete, NULL);
3778 : 4 : poll_threads();
3779 : 4 : CU_ASSERT(g_bserrno == 0);
3780 : 4 : CU_ASSERT(g_blob != NULL);
3781 : 4 : blob = g_blob;
3782 : :
3783 : 4 : CU_ASSERT(free_clusters == spdk_bs_free_cluster_count(bs));
3784 : :
3785 : : /* Get the xattrs */
3786 : 4 : value = NULL;
3787 : 4 : rc = spdk_blob_get_xattr_value(blob, "length", &value, &value_len);
3788 : 4 : CU_ASSERT(rc == 0);
3789 [ + - ]: 4 : SPDK_CU_ASSERT_FATAL(value != NULL);
3790 : 4 : CU_ASSERT(*(uint64_t *)value == length);
3791 : 4 : CU_ASSERT(value_len == 8);
3792 : 4 : CU_ASSERT(spdk_blob_get_num_clusters(blob) == 10);
3793 : :
3794 : : /* Resize the blob */
3795 : 4 : spdk_blob_resize(blob, 20, blob_op_complete, NULL);
3796 : 4 : poll_threads();
3797 : 4 : CU_ASSERT(g_bserrno == 0);
3798 : :
3799 : 4 : free_clusters = spdk_bs_free_cluster_count(bs);
3800 : :
3801 : 4 : spdk_blob_close(blob, blob_op_complete, NULL);
3802 : 4 : poll_threads();
3803 : 4 : CU_ASSERT(g_bserrno == 0);
3804 : 4 : blob = NULL;
3805 : 4 : g_blob = NULL;
3806 : 4 : g_blobid = SPDK_BLOBID_INVALID;
3807 : :
3808 : 4 : ut_bs_dirty_load(&bs, NULL);
3809 : :
3810 : 4 : spdk_bs_open_blob(bs, blobid1, blob_op_with_handle_complete, NULL);
3811 : 4 : poll_threads();
3812 : 4 : CU_ASSERT(g_bserrno == 0);
3813 : 4 : CU_ASSERT(g_blob != NULL);
3814 : 4 : blob = g_blob;
3815 : 4 : CU_ASSERT(spdk_blob_get_num_clusters(blob) == 20);
3816 : 4 : CU_ASSERT(free_clusters == spdk_bs_free_cluster_count(bs));
3817 : :
3818 : 4 : spdk_blob_close(blob, blob_op_complete, NULL);
3819 : 4 : poll_threads();
3820 : 4 : CU_ASSERT(g_bserrno == 0);
3821 : 4 : blob = NULL;
3822 : 4 : g_blob = NULL;
3823 : 4 : g_blobid = SPDK_BLOBID_INVALID;
3824 : :
3825 : : /* Create second blob */
3826 : 4 : blob = ut_blob_create_and_open(bs, NULL);
3827 : 4 : blobid2 = spdk_blob_get_id(blob);
3828 : :
3829 : : /* Set some xattrs */
3830 : 4 : rc = spdk_blob_set_xattr(blob, "name", "log1.txt", strlen("log1.txt") + 1);
3831 : 4 : CU_ASSERT(rc == 0);
3832 : :
3833 : 4 : length = 5432;
3834 : 4 : rc = spdk_blob_set_xattr(blob, "length", &length, sizeof(length));
3835 : 4 : CU_ASSERT(rc == 0);
3836 : :
3837 : : /* Resize the blob */
3838 : 4 : spdk_blob_resize(blob, 10, blob_op_complete, NULL);
3839 : 4 : poll_threads();
3840 : 4 : CU_ASSERT(g_bserrno == 0);
3841 : :
3842 : 4 : free_clusters = spdk_bs_free_cluster_count(bs);
3843 : :
3844 : 4 : spdk_blob_close(blob, blob_op_complete, NULL);
3845 : 4 : poll_threads();
3846 : 4 : CU_ASSERT(g_bserrno == 0);
3847 : 4 : blob = NULL;
3848 : 4 : g_blob = NULL;
3849 : 4 : g_blobid = SPDK_BLOBID_INVALID;
3850 : :
3851 : 4 : ut_bs_dirty_load(&bs, NULL);
3852 : :
3853 : 4 : spdk_bs_open_blob(bs, blobid2, blob_op_with_handle_complete, NULL);
3854 : 4 : poll_threads();
3855 : 4 : CU_ASSERT(g_bserrno == 0);
3856 : 4 : CU_ASSERT(g_blob != NULL);
3857 : 4 : blob = g_blob;
3858 : :
3859 : : /* Get the xattrs */
3860 : 4 : value = NULL;
3861 : 4 : rc = spdk_blob_get_xattr_value(blob, "length", &value, &value_len);
3862 : 4 : CU_ASSERT(rc == 0);
3863 [ - + ]: 4 : SPDK_CU_ASSERT_FATAL(value != NULL);
3864 : 4 : CU_ASSERT(*(uint64_t *)value == length);
3865 : 4 : CU_ASSERT(value_len == 8);
3866 : 4 : CU_ASSERT(spdk_blob_get_num_clusters(blob) == 10);
3867 : 4 : CU_ASSERT(free_clusters == spdk_bs_free_cluster_count(bs));
3868 : :
3869 : 4 : ut_blob_close_and_delete(bs, blob);
3870 : :
3871 : 4 : free_clusters = spdk_bs_free_cluster_count(bs);
3872 : :
3873 : 4 : ut_bs_dirty_load(&bs, NULL);
3874 : :
3875 : 4 : spdk_bs_open_blob(bs, blobid2, blob_op_with_handle_complete, NULL);
3876 : 4 : poll_threads();
3877 : 4 : CU_ASSERT(g_bserrno != 0);
3878 : 4 : CU_ASSERT(g_blob == NULL);
3879 : :
3880 : 4 : spdk_bs_open_blob(bs, blobid1, blob_op_with_handle_complete, NULL);
3881 : 4 : poll_threads();
3882 : 4 : CU_ASSERT(g_bserrno == 0);
3883 : 4 : CU_ASSERT(g_blob != NULL);
3884 : 4 : blob = g_blob;
3885 : 4 : CU_ASSERT(free_clusters == spdk_bs_free_cluster_count(bs));
3886 : 4 : spdk_blob_close(blob, blob_op_complete, NULL);
3887 : 4 : poll_threads();
3888 : 4 : CU_ASSERT(g_bserrno == 0);
3889 : :
3890 : 4 : ut_bs_reload(&bs, NULL);
3891 : :
3892 : : /* Create second blob */
3893 : 4 : ut_spdk_blob_opts_init(&blob_opts);
3894 : 4 : spdk_bs_create_blob_ext(bs, &blob_opts, blob_op_with_id_complete, NULL);
3895 : 4 : poll_threads();
3896 : 4 : CU_ASSERT(g_bserrno == 0);
3897 : 4 : CU_ASSERT(g_blobid != SPDK_BLOBID_INVALID);
3898 : 4 : blobid2 = g_blobid;
3899 : :
3900 : : /* Create third blob */
3901 : 4 : spdk_bs_create_blob_ext(bs, &blob_opts, blob_op_with_id_complete, NULL);
3902 : 4 : poll_threads();
3903 : 4 : CU_ASSERT(g_bserrno == 0);
3904 : 4 : CU_ASSERT(g_blobid != SPDK_BLOBID_INVALID);
3905 : 4 : blobid3 = g_blobid;
3906 : :
3907 : 4 : spdk_bs_open_blob(bs, blobid2, blob_op_with_handle_complete, NULL);
3908 : 4 : poll_threads();
3909 : 4 : CU_ASSERT(g_bserrno == 0);
3910 : 4 : CU_ASSERT(g_blob != NULL);
3911 : 4 : blob = g_blob;
3912 : :
3913 : : /* Set some xattrs for second blob */
3914 : 4 : rc = spdk_blob_set_xattr(blob, "name", "log1.txt", strlen("log1.txt") + 1);
3915 : 4 : CU_ASSERT(rc == 0);
3916 : :
3917 : 4 : length = 5432;
3918 : 4 : rc = spdk_blob_set_xattr(blob, "length", &length, sizeof(length));
3919 : 4 : CU_ASSERT(rc == 0);
3920 : :
3921 : 4 : spdk_blob_close(blob, blob_op_complete, NULL);
3922 : 4 : poll_threads();
3923 : 4 : CU_ASSERT(g_bserrno == 0);
3924 : 4 : blob = NULL;
3925 : 4 : g_blob = NULL;
3926 : 4 : g_blobid = SPDK_BLOBID_INVALID;
3927 : :
3928 : 4 : spdk_bs_open_blob(bs, blobid3, blob_op_with_handle_complete, NULL);
3929 : 4 : poll_threads();
3930 : 4 : CU_ASSERT(g_bserrno == 0);
3931 : 4 : CU_ASSERT(g_blob != NULL);
3932 : 4 : blob = g_blob;
3933 : :
3934 : : /* Set some xattrs for third blob */
3935 : 4 : rc = spdk_blob_set_xattr(blob, "name", "log2.txt", strlen("log2.txt") + 1);
3936 : 4 : CU_ASSERT(rc == 0);
3937 : :
3938 : 4 : length = 5432;
3939 : 4 : rc = spdk_blob_set_xattr(blob, "length", &length, sizeof(length));
3940 : 4 : CU_ASSERT(rc == 0);
3941 : :
3942 : 4 : spdk_blob_close(blob, blob_op_complete, NULL);
3943 : 4 : poll_threads();
3944 : 4 : CU_ASSERT(g_bserrno == 0);
3945 : 4 : blob = NULL;
3946 : 4 : g_blob = NULL;
3947 : 4 : g_blobid = SPDK_BLOBID_INVALID;
3948 : :
3949 : : /* Mark second blob as invalid */
3950 : 4 : page_num = bs_blobid_to_page(blobid2);
3951 : :
3952 : 4 : index = DEV_BUFFER_BLOCKLEN * (bs->md_start + page_num);
3953 : 4 : page = (struct spdk_blob_md_page *)&g_dev_buffer[index];
3954 : 4 : page->sequence_num = 1;
3955 : 4 : page->crc = blob_md_page_calc_crc(page);
3956 : :
3957 : 4 : free_clusters = spdk_bs_free_cluster_count(bs);
3958 : :
3959 : 4 : ut_bs_dirty_load(&bs, NULL);
3960 : :
3961 : 4 : spdk_bs_open_blob(bs, blobid2, blob_op_with_handle_complete, NULL);
3962 : 4 : poll_threads();
3963 : 4 : CU_ASSERT(g_bserrno != 0);
3964 : 4 : CU_ASSERT(g_blob == NULL);
3965 : :
3966 : 4 : spdk_bs_open_blob(bs, blobid3, blob_op_with_handle_complete, NULL);
3967 : 4 : poll_threads();
3968 : 4 : CU_ASSERT(g_bserrno == 0);
3969 : 4 : CU_ASSERT(g_blob != NULL);
3970 : 4 : blob = g_blob;
3971 : :
3972 : 4 : CU_ASSERT(free_clusters == spdk_bs_free_cluster_count(bs));
3973 : 4 : }
3974 : :
3975 : : static void
3976 : 4 : blob_flags(void)
3977 : : {
3978 : 4 : struct spdk_blob_store *bs = g_bs;
3979 : : spdk_blob_id blobid_invalid, blobid_data_ro, blobid_md_ro;
3980 : : struct spdk_blob *blob_invalid, *blob_data_ro, *blob_md_ro;
3981 : : struct spdk_blob_opts blob_opts;
3982 : : int rc;
3983 : :
3984 : : /* Create three blobs - one each for testing invalid, data_ro and md_ro flags. */
3985 : 4 : blob_invalid = ut_blob_create_and_open(bs, NULL);
3986 : 4 : blobid_invalid = spdk_blob_get_id(blob_invalid);
3987 : :
3988 : 4 : blob_data_ro = ut_blob_create_and_open(bs, NULL);
3989 : 4 : blobid_data_ro = spdk_blob_get_id(blob_data_ro);
3990 : :
3991 : 4 : ut_spdk_blob_opts_init(&blob_opts);
3992 : 4 : blob_opts.clear_method = BLOB_CLEAR_WITH_WRITE_ZEROES;
3993 : 4 : blob_md_ro = ut_blob_create_and_open(bs, &blob_opts);
3994 : 4 : blobid_md_ro = spdk_blob_get_id(blob_md_ro);
3995 : 4 : CU_ASSERT((blob_md_ro->md_ro_flags & SPDK_BLOB_MD_RO_FLAGS_MASK) == BLOB_CLEAR_WITH_WRITE_ZEROES);
3996 : :
3997 : : /* Change the size of blob_data_ro to check if flags are serialized
3998 : : * when blob has non zero number of extents */
3999 : 4 : spdk_blob_resize(blob_data_ro, 10, blob_op_complete, NULL);
4000 : 4 : poll_threads();
4001 : 4 : CU_ASSERT(g_bserrno == 0);
4002 : :
4003 : : /* Set the xattr to check if flags are serialized
4004 : : * when blob has non zero number of xattrs */
4005 : 4 : rc = spdk_blob_set_xattr(blob_md_ro, "name", "log.txt", strlen("log.txt") + 1);
4006 : 4 : CU_ASSERT(rc == 0);
4007 : :
4008 : 4 : blob_invalid->invalid_flags = (1ULL << 63);
4009 : 4 : blob_invalid->state = SPDK_BLOB_STATE_DIRTY;
4010 : 4 : blob_data_ro->data_ro_flags = (1ULL << 62);
4011 : 4 : blob_data_ro->state = SPDK_BLOB_STATE_DIRTY;
4012 : 4 : blob_md_ro->md_ro_flags = (1ULL << 61);
4013 : 4 : blob_md_ro->state = SPDK_BLOB_STATE_DIRTY;
4014 : :
4015 : 4 : g_bserrno = -1;
4016 : 4 : spdk_blob_sync_md(blob_invalid, blob_op_complete, NULL);
4017 : 4 : poll_threads();
4018 : 4 : CU_ASSERT(g_bserrno == 0);
4019 : 4 : g_bserrno = -1;
4020 : 4 : spdk_blob_sync_md(blob_data_ro, blob_op_complete, NULL);
4021 : 4 : poll_threads();
4022 : 4 : CU_ASSERT(g_bserrno == 0);
4023 : 4 : g_bserrno = -1;
4024 : 4 : spdk_blob_sync_md(blob_md_ro, blob_op_complete, NULL);
4025 : 4 : poll_threads();
4026 : 4 : CU_ASSERT(g_bserrno == 0);
4027 : :
4028 : 4 : g_bserrno = -1;
4029 : 4 : spdk_blob_close(blob_invalid, blob_op_complete, NULL);
4030 : 4 : poll_threads();
4031 : 4 : CU_ASSERT(g_bserrno == 0);
4032 : 4 : blob_invalid = NULL;
4033 : 4 : g_bserrno = -1;
4034 : 4 : spdk_blob_close(blob_data_ro, blob_op_complete, NULL);
4035 : 4 : poll_threads();
4036 : 4 : CU_ASSERT(g_bserrno == 0);
4037 : 4 : blob_data_ro = NULL;
4038 : 4 : g_bserrno = -1;
4039 : 4 : spdk_blob_close(blob_md_ro, blob_op_complete, NULL);
4040 : 4 : poll_threads();
4041 : 4 : CU_ASSERT(g_bserrno == 0);
4042 : 4 : blob_md_ro = NULL;
4043 : :
4044 : 4 : g_blob = NULL;
4045 : 4 : g_blobid = SPDK_BLOBID_INVALID;
4046 : :
4047 : 4 : ut_bs_reload(&bs, NULL);
4048 : :
4049 : 4 : g_blob = NULL;
4050 : 4 : g_bserrno = 0;
4051 : 4 : spdk_bs_open_blob(bs, blobid_invalid, blob_op_with_handle_complete, NULL);
4052 : 4 : poll_threads();
4053 : 4 : CU_ASSERT(g_bserrno != 0);
4054 : 4 : CU_ASSERT(g_blob == NULL);
4055 : :
4056 : 4 : g_blob = NULL;
4057 : 4 : g_bserrno = -1;
4058 : 4 : spdk_bs_open_blob(bs, blobid_data_ro, blob_op_with_handle_complete, NULL);
4059 : 4 : poll_threads();
4060 : 4 : CU_ASSERT(g_bserrno == 0);
4061 [ + - ]: 4 : SPDK_CU_ASSERT_FATAL(g_blob != NULL);
4062 : 4 : blob_data_ro = g_blob;
4063 : : /* If an unknown data_ro flag was found, the blob should be marked both data and md read-only. */
4064 : 4 : CU_ASSERT(blob_data_ro->data_ro == true);
4065 : 4 : CU_ASSERT(blob_data_ro->md_ro == true);
4066 : 4 : CU_ASSERT(spdk_blob_get_num_clusters(blob_data_ro) == 10);
4067 : :
4068 : 4 : g_blob = NULL;
4069 : 4 : g_bserrno = -1;
4070 : 4 : spdk_bs_open_blob(bs, blobid_md_ro, blob_op_with_handle_complete, NULL);
4071 : 4 : poll_threads();
4072 : 4 : CU_ASSERT(g_bserrno == 0);
4073 [ - + ]: 4 : SPDK_CU_ASSERT_FATAL(g_blob != NULL);
4074 : 4 : blob_md_ro = g_blob;
4075 : 4 : CU_ASSERT(blob_md_ro->data_ro == false);
4076 : 4 : CU_ASSERT(blob_md_ro->md_ro == true);
4077 : :
4078 : 4 : g_bserrno = -1;
4079 : 4 : spdk_blob_sync_md(blob_md_ro, blob_op_complete, NULL);
4080 : 4 : poll_threads();
4081 : 4 : CU_ASSERT(g_bserrno == 0);
4082 : :
4083 : 4 : ut_blob_close_and_delete(bs, blob_data_ro);
4084 : 4 : ut_blob_close_and_delete(bs, blob_md_ro);
4085 : 4 : }
4086 : :
4087 : : static void
4088 : 4 : bs_version(void)
4089 : : {
4090 : : struct spdk_bs_super_block *super;
4091 : 4 : struct spdk_blob_store *bs = g_bs;
4092 : : struct spdk_bs_dev *dev;
4093 : : struct spdk_blob *blob;
4094 : : struct spdk_blob_opts blob_opts;
4095 : : spdk_blob_id blobid;
4096 : :
4097 : : /* Unload the blob store */
4098 : 4 : spdk_bs_unload(bs, bs_op_complete, NULL);
4099 : 4 : poll_threads();
4100 : 4 : CU_ASSERT(g_bserrno == 0);
4101 : 4 : g_bs = NULL;
4102 : :
4103 : : /*
4104 : : * Change the bs version on disk. This will allow us to
4105 : : * test that the version does not get modified automatically
4106 : : * when loading and unloading the blobstore.
4107 : : */
4108 : 4 : super = (struct spdk_bs_super_block *)&g_dev_buffer[0];
4109 : 4 : CU_ASSERT(super->version == SPDK_BS_VERSION);
4110 : 4 : CU_ASSERT(super->clean == 1);
4111 : 4 : super->version = 2;
4112 : : /*
4113 : : * Version 2 metadata does not have a used blobid mask, so clear
4114 : : * those fields in the super block and zero the corresponding
4115 : : * region on "disk". We will use this to ensure blob IDs are
4116 : : * correctly reconstructed.
4117 : : */
4118 : 8 : memset(&g_dev_buffer[super->used_blobid_mask_start * SPDK_BS_PAGE_SIZE], 0,
4119 : 4 : super->used_blobid_mask_len * SPDK_BS_PAGE_SIZE);
4120 : 4 : super->used_blobid_mask_start = 0;
4121 : 4 : super->used_blobid_mask_len = 0;
4122 : 4 : super->crc = blob_md_page_calc_crc(super);
4123 : :
4124 : : /* Load an existing blob store */
4125 : 4 : dev = init_dev();
4126 : 4 : spdk_bs_load(dev, NULL, bs_op_with_handle_complete, NULL);
4127 : 4 : poll_threads();
4128 : 4 : CU_ASSERT(g_bserrno == 0);
4129 [ + - ]: 4 : SPDK_CU_ASSERT_FATAL(g_bs != NULL);
4130 : 4 : CU_ASSERT(super->clean == 1);
4131 : 4 : bs = g_bs;
4132 : :
4133 : : /*
4134 : : * Create a blob - just to make sure that when we unload it
4135 : : * results in writing the super block (since metadata pages
4136 : : * were allocated.
4137 : : */
4138 : 4 : ut_spdk_blob_opts_init(&blob_opts);
4139 : 4 : spdk_bs_create_blob_ext(bs, &blob_opts, blob_op_with_id_complete, NULL);
4140 : 4 : poll_threads();
4141 : 4 : CU_ASSERT(g_bserrno == 0);
4142 : 4 : CU_ASSERT(g_blobid != SPDK_BLOBID_INVALID);
4143 : 4 : blobid = g_blobid;
4144 : :
4145 : : /* Unload the blob store */
4146 : 4 : spdk_bs_unload(bs, bs_op_complete, NULL);
4147 : 4 : poll_threads();
4148 : 4 : CU_ASSERT(g_bserrno == 0);
4149 : 4 : g_bs = NULL;
4150 : 4 : CU_ASSERT(super->version == 2);
4151 : 4 : CU_ASSERT(super->used_blobid_mask_start == 0);
4152 : 4 : CU_ASSERT(super->used_blobid_mask_len == 0);
4153 : :
4154 : 4 : dev = init_dev();
4155 : 4 : spdk_bs_load(dev, NULL, bs_op_with_handle_complete, NULL);
4156 : 4 : poll_threads();
4157 : 4 : CU_ASSERT(g_bserrno == 0);
4158 [ - + ]: 4 : SPDK_CU_ASSERT_FATAL(g_bs != NULL);
4159 : 4 : bs = g_bs;
4160 : :
4161 : 4 : g_blob = NULL;
4162 : 4 : spdk_bs_open_blob(bs, blobid, blob_op_with_handle_complete, NULL);
4163 : 4 : poll_threads();
4164 : 4 : CU_ASSERT(g_bserrno == 0);
4165 : 4 : CU_ASSERT(g_blob != NULL);
4166 : 4 : blob = g_blob;
4167 : :
4168 : 4 : ut_blob_close_and_delete(bs, blob);
4169 : :
4170 : 4 : CU_ASSERT(super->version == 2);
4171 : 4 : CU_ASSERT(super->used_blobid_mask_start == 0);
4172 : 4 : CU_ASSERT(super->used_blobid_mask_len == 0);
4173 : 4 : }
4174 : :
4175 : : static void
4176 : 4 : blob_set_xattrs_test(void)
4177 : : {
4178 : 4 : struct spdk_blob_store *bs = g_bs;
4179 : : struct spdk_blob *blob;
4180 : : struct spdk_blob_opts opts;
4181 : : const void *value;
4182 : : size_t value_len;
4183 : : char *xattr;
4184 : : size_t xattr_length;
4185 : : int rc;
4186 : :
4187 : : /* Create blob with extra attributes */
4188 : 4 : ut_spdk_blob_opts_init(&opts);
4189 : :
4190 : 4 : opts.xattrs.names = g_xattr_names;
4191 : 4 : opts.xattrs.get_value = _get_xattr_value;
4192 : 4 : opts.xattrs.count = 3;
4193 : 4 : opts.xattrs.ctx = &g_ctx;
4194 : :
4195 : 4 : blob = ut_blob_create_and_open(bs, &opts);
4196 : :
4197 : : /* Get the xattrs */
4198 : 4 : value = NULL;
4199 : :
4200 : 4 : rc = spdk_blob_get_xattr_value(blob, g_xattr_names[0], &value, &value_len);
4201 : 4 : CU_ASSERT(rc == 0);
4202 [ + - ]: 4 : SPDK_CU_ASSERT_FATAL(value != NULL);
4203 : 4 : CU_ASSERT(value_len == strlen(g_xattr_values[0]));
4204 : 4 : CU_ASSERT_NSTRING_EQUAL_FATAL(value, g_xattr_values[0], value_len);
4205 : :
4206 : 4 : rc = spdk_blob_get_xattr_value(blob, g_xattr_names[1], &value, &value_len);
4207 : 4 : CU_ASSERT(rc == 0);
4208 [ + - ]: 4 : SPDK_CU_ASSERT_FATAL(value != NULL);
4209 : 4 : CU_ASSERT(value_len == strlen(g_xattr_values[1]));
4210 : 4 : CU_ASSERT_NSTRING_EQUAL((char *)value, g_xattr_values[1], value_len);
4211 : :
4212 : 4 : rc = spdk_blob_get_xattr_value(blob, g_xattr_names[2], &value, &value_len);
4213 : 4 : CU_ASSERT(rc == 0);
4214 [ + - ]: 4 : SPDK_CU_ASSERT_FATAL(value != NULL);
4215 : 4 : CU_ASSERT(value_len == strlen(g_xattr_values[2]));
4216 : 4 : CU_ASSERT_NSTRING_EQUAL((char *)value, g_xattr_values[2], value_len);
4217 : :
4218 : : /* Try to get non existing attribute */
4219 : :
4220 : 4 : rc = spdk_blob_get_xattr_value(blob, "foobar", &value, &value_len);
4221 : 4 : CU_ASSERT(rc == -ENOENT);
4222 : :
4223 : : /* Try xattr exceeding maximum length of descriptor in single page */
4224 : 4 : xattr_length = SPDK_BS_MAX_DESC_SIZE - sizeof(struct spdk_blob_md_descriptor_xattr) -
4225 : : strlen("large_xattr") + 1;
4226 : 4 : xattr = calloc(xattr_length, sizeof(char));
4227 [ + - ]: 4 : SPDK_CU_ASSERT_FATAL(xattr != NULL);
4228 : 4 : rc = spdk_blob_set_xattr(blob, "large_xattr", xattr, xattr_length);
4229 : 4 : free(xattr);
4230 [ - + ]: 4 : SPDK_CU_ASSERT_FATAL(rc == -ENOMEM);
4231 : :
4232 : 4 : spdk_blob_close(blob, blob_op_complete, NULL);
4233 : 4 : poll_threads();
4234 : 4 : CU_ASSERT(g_bserrno == 0);
4235 : 4 : blob = NULL;
4236 : 4 : g_blob = NULL;
4237 : 4 : g_blobid = SPDK_BLOBID_INVALID;
4238 : :
4239 : : /* NULL callback */
4240 : 4 : ut_spdk_blob_opts_init(&opts);
4241 : 4 : opts.xattrs.names = g_xattr_names;
4242 : 4 : opts.xattrs.get_value = NULL;
4243 : 4 : opts.xattrs.count = 1;
4244 : 4 : opts.xattrs.ctx = &g_ctx;
4245 : :
4246 : 4 : spdk_bs_create_blob_ext(bs, &opts, blob_op_with_id_complete, NULL);
4247 : 4 : poll_threads();
4248 : 4 : CU_ASSERT(g_bserrno == -EINVAL);
4249 : 4 : CU_ASSERT(g_blobid != SPDK_BLOBID_INVALID);
4250 : :
4251 : : /* NULL values */
4252 : 4 : ut_spdk_blob_opts_init(&opts);
4253 : 4 : opts.xattrs.names = g_xattr_names;
4254 : 4 : opts.xattrs.get_value = _get_xattr_value_null;
4255 : 4 : opts.xattrs.count = 1;
4256 : 4 : opts.xattrs.ctx = NULL;
4257 : :
4258 : 4 : spdk_bs_create_blob_ext(bs, &opts, blob_op_with_id_complete, NULL);
4259 : 4 : poll_threads();
4260 : 4 : CU_ASSERT(g_bserrno == -EINVAL);
4261 : 4 : }
4262 : :
4263 : : static void
4264 : 4 : blob_thin_prov_alloc(void)
4265 : : {
4266 : 4 : struct spdk_blob_store *bs = g_bs;
4267 : : struct spdk_blob *blob;
4268 : : struct spdk_blob_opts opts;
4269 : : spdk_blob_id blobid;
4270 : : uint64_t free_clusters;
4271 : :
4272 : 4 : free_clusters = spdk_bs_free_cluster_count(bs);
4273 : :
4274 : : /* Set blob as thin provisioned */
4275 : 4 : ut_spdk_blob_opts_init(&opts);
4276 : 4 : opts.thin_provision = true;
4277 : :
4278 : 4 : blob = ut_blob_create_and_open(bs, &opts);
4279 : 4 : blobid = spdk_blob_get_id(blob);
4280 : 4 : CU_ASSERT(free_clusters == spdk_bs_free_cluster_count(bs));
4281 : :
4282 : 4 : CU_ASSERT(blob->active.num_clusters == 0);
4283 : 4 : CU_ASSERT(spdk_blob_get_num_clusters(blob) == 0);
4284 : 4 : CU_ASSERT(spdk_blob_get_num_allocated_clusters(blob) == 0);
4285 : :
4286 : : /* The blob started at 0 clusters. Resize it to be 5, but still unallocated. */
4287 : 4 : spdk_blob_resize(blob, 5, blob_op_complete, NULL);
4288 : 4 : poll_threads();
4289 : 4 : CU_ASSERT(g_bserrno == 0);
4290 : 4 : CU_ASSERT(free_clusters == spdk_bs_free_cluster_count(bs));
4291 : 4 : CU_ASSERT(blob->active.num_clusters == 5);
4292 : 4 : CU_ASSERT(spdk_blob_get_num_clusters(blob) == 5);
4293 : 4 : CU_ASSERT(spdk_blob_get_num_allocated_clusters(blob) == 0);
4294 : :
4295 : : /* Grow it to 1TB - still unallocated */
4296 : 4 : spdk_blob_resize(blob, 262144, blob_op_complete, NULL);
4297 : 4 : poll_threads();
4298 : 4 : CU_ASSERT(g_bserrno == 0);
4299 : 4 : CU_ASSERT(free_clusters == spdk_bs_free_cluster_count(bs));
4300 : 4 : CU_ASSERT(blob->active.num_clusters == 262144);
4301 : 4 : CU_ASSERT(spdk_blob_get_num_clusters(blob) == 262144);
4302 : 4 : CU_ASSERT(spdk_blob_get_num_allocated_clusters(blob) == 0);
4303 : :
4304 : 4 : spdk_blob_sync_md(blob, blob_op_complete, NULL);
4305 : 4 : poll_threads();
4306 : 4 : CU_ASSERT(g_bserrno == 0);
4307 : : /* Sync must not change anything */
4308 : 4 : CU_ASSERT(free_clusters == spdk_bs_free_cluster_count(bs));
4309 : 4 : CU_ASSERT(blob->active.num_clusters == 262144);
4310 : 4 : CU_ASSERT(spdk_blob_get_num_clusters(blob) == 262144);
4311 : 4 : CU_ASSERT(spdk_blob_get_num_allocated_clusters(blob) == 0);
4312 : : /* Since clusters are not allocated,
4313 : : * number of metadata pages is expected to be minimal.
4314 : : */
4315 : 4 : CU_ASSERT(blob->active.num_pages == 1);
4316 : :
4317 : : /* Shrink the blob to 3 clusters - still unallocated */
4318 : 4 : spdk_blob_resize(blob, 3, blob_op_complete, NULL);
4319 : 4 : poll_threads();
4320 : 4 : CU_ASSERT(g_bserrno == 0);
4321 : 4 : CU_ASSERT(free_clusters == spdk_bs_free_cluster_count(bs));
4322 : 4 : CU_ASSERT(blob->active.num_clusters == 3);
4323 : 4 : CU_ASSERT(spdk_blob_get_num_clusters(blob) == 3);
4324 : 4 : CU_ASSERT(spdk_blob_get_num_allocated_clusters(blob) == 0);
4325 : :
4326 : 4 : spdk_blob_sync_md(blob, blob_op_complete, NULL);
4327 : 4 : poll_threads();
4328 : 4 : CU_ASSERT(g_bserrno == 0);
4329 : : /* Sync must not change anything */
4330 : 4 : CU_ASSERT(free_clusters == spdk_bs_free_cluster_count(bs));
4331 : 4 : CU_ASSERT(blob->active.num_clusters == 3);
4332 : 4 : CU_ASSERT(spdk_blob_get_num_clusters(blob) == 3);
4333 : 4 : CU_ASSERT(spdk_blob_get_num_allocated_clusters(blob) == 0);
4334 : :
4335 : 4 : spdk_blob_close(blob, blob_op_complete, NULL);
4336 : 4 : poll_threads();
4337 : 4 : CU_ASSERT(g_bserrno == 0);
4338 : :
4339 : 4 : ut_bs_reload(&bs, NULL);
4340 : :
4341 : 4 : spdk_bs_open_blob(bs, blobid, blob_op_with_handle_complete, NULL);
4342 : 4 : poll_threads();
4343 : 4 : CU_ASSERT(g_bserrno == 0);
4344 [ + - ]: 4 : SPDK_CU_ASSERT_FATAL(g_blob != NULL);
4345 : 4 : blob = g_blob;
4346 : :
4347 : : /* Check that clusters allocation and size is still the same */
4348 : 4 : CU_ASSERT(free_clusters == spdk_bs_free_cluster_count(bs));
4349 : 4 : CU_ASSERT(blob->active.num_clusters == 3);
4350 : :
4351 : 4 : ut_blob_close_and_delete(bs, blob);
4352 : 4 : }
4353 : :
4354 : : static void
4355 : 4 : blob_insert_cluster_msg_test(void)
4356 : : {
4357 : 4 : struct spdk_blob_store *bs = g_bs;
4358 : : struct spdk_blob *blob;
4359 : : struct spdk_blob_opts opts;
4360 : 4 : struct spdk_blob_md_page page = {};
4361 : : spdk_blob_id blobid;
4362 : : uint64_t free_clusters;
4363 : 4 : uint64_t new_cluster = 0;
4364 : 4 : uint32_t cluster_num = 3;
4365 : 4 : uint32_t extent_page = 0;
4366 : :
4367 : 4 : free_clusters = spdk_bs_free_cluster_count(bs);
4368 : :
4369 : : /* Set blob as thin provisioned */
4370 : 4 : ut_spdk_blob_opts_init(&opts);
4371 : 4 : opts.thin_provision = true;
4372 : 4 : opts.num_clusters = 4;
4373 : :
4374 : 4 : blob = ut_blob_create_and_open(bs, &opts);
4375 : 4 : blobid = spdk_blob_get_id(blob);
4376 : 4 : CU_ASSERT(free_clusters == spdk_bs_free_cluster_count(bs));
4377 : :
4378 : 4 : CU_ASSERT(blob->active.num_clusters == 4);
4379 : 4 : CU_ASSERT(spdk_blob_get_num_clusters(blob) == 4);
4380 : 4 : CU_ASSERT(blob->active.clusters[cluster_num] == 0);
4381 : :
4382 : : /* Specify cluster_num to allocate and new_cluster will be returned to insert on md_thread.
4383 : : * This is to simulate behaviour when cluster is allocated after blob creation.
4384 : : * Such as _spdk_bs_allocate_and_copy_cluster(). */
4385 : 4 : spdk_spin_lock(&bs->used_lock);
4386 : 4 : bs_allocate_cluster(blob, cluster_num, &new_cluster, &extent_page, false);
4387 : 4 : CU_ASSERT(blob->active.clusters[cluster_num] == 0);
4388 : 4 : spdk_spin_unlock(&bs->used_lock);
4389 : :
4390 : 4 : blob_insert_cluster_on_md_thread(blob, cluster_num, new_cluster, extent_page, &page,
4391 : : blob_op_complete, NULL);
4392 : 4 : poll_threads();
4393 : :
4394 : 4 : CU_ASSERT(blob->active.clusters[cluster_num] != 0);
4395 : :
4396 : 4 : spdk_blob_close(blob, blob_op_complete, NULL);
4397 : 4 : poll_threads();
4398 : 4 : CU_ASSERT(g_bserrno == 0);
4399 : :
4400 : 4 : ut_bs_reload(&bs, NULL);
4401 : :
4402 : 4 : spdk_bs_open_blob(bs, blobid, blob_op_with_handle_complete, NULL);
4403 : 4 : poll_threads();
4404 : 4 : CU_ASSERT(g_bserrno == 0);
4405 [ + - ]: 4 : SPDK_CU_ASSERT_FATAL(g_blob != NULL);
4406 : 4 : blob = g_blob;
4407 : :
4408 : 4 : CU_ASSERT(blob->active.clusters[cluster_num] != 0);
4409 : :
4410 : 4 : ut_blob_close_and_delete(bs, blob);
4411 : 4 : }
4412 : :
4413 : : static void
4414 : 4 : blob_thin_prov_rw(void)
4415 : : {
4416 : : static const uint8_t zero[10 * BLOCKLEN] = { 0 };
4417 : 4 : struct spdk_blob_store *bs = g_bs;
4418 : : struct spdk_blob *blob, *blob_id0;
4419 : : struct spdk_io_channel *channel, *channel_thread1;
4420 : : struct spdk_blob_opts opts;
4421 : : uint64_t free_clusters;
4422 : : uint64_t page_size;
4423 : : uint8_t payload_read[10 * BLOCKLEN];
4424 : : uint8_t payload_write[10 * BLOCKLEN];
4425 : : uint64_t write_bytes;
4426 : : uint64_t read_bytes;
4427 : :
4428 : 4 : free_clusters = spdk_bs_free_cluster_count(bs);
4429 : 4 : page_size = spdk_bs_get_page_size(bs);
4430 : :
4431 : 4 : channel = spdk_bs_alloc_io_channel(bs);
4432 : 4 : CU_ASSERT(channel != NULL);
4433 : :
4434 : 4 : ut_spdk_blob_opts_init(&opts);
4435 : 4 : opts.thin_provision = true;
4436 : :
4437 : : /* Create and delete blob at md page 0, so that next md page allocation
4438 : : * for extent will use that. */
4439 : 4 : blob_id0 = ut_blob_create_and_open(bs, &opts);
4440 : 4 : blob = ut_blob_create_and_open(bs, &opts);
4441 : 4 : ut_blob_close_and_delete(bs, blob_id0);
4442 : 4 : CU_ASSERT(free_clusters == spdk_bs_free_cluster_count(bs));
4443 : :
4444 : 4 : CU_ASSERT(blob->active.num_clusters == 0);
4445 : 4 : CU_ASSERT(spdk_blob_get_num_allocated_clusters(blob) == 0);
4446 : :
4447 : : /* The blob started at 0 clusters. Resize it to be 5, but still unallocated. */
4448 : 4 : spdk_blob_resize(blob, 5, blob_op_complete, NULL);
4449 : 4 : poll_threads();
4450 : 4 : CU_ASSERT(g_bserrno == 0);
4451 : 4 : CU_ASSERT(free_clusters == spdk_bs_free_cluster_count(bs));
4452 : 4 : CU_ASSERT(blob->active.num_clusters == 5);
4453 : 4 : CU_ASSERT(spdk_blob_get_num_allocated_clusters(blob) == 0);
4454 : :
4455 : 4 : spdk_blob_sync_md(blob, blob_op_complete, NULL);
4456 : 4 : poll_threads();
4457 : 4 : CU_ASSERT(g_bserrno == 0);
4458 : : /* Sync must not change anything */
4459 : 4 : CU_ASSERT(free_clusters == spdk_bs_free_cluster_count(bs));
4460 : 4 : CU_ASSERT(blob->active.num_clusters == 5);
4461 : 4 : CU_ASSERT(spdk_blob_get_num_allocated_clusters(blob) == 0);
4462 : :
4463 : : /* Payload should be all zeros from unallocated clusters */
4464 : 4 : memset(payload_read, 0xFF, sizeof(payload_read));
4465 : 4 : spdk_blob_io_read(blob, channel, payload_read, 4, 10, blob_op_complete, NULL);
4466 : 4 : poll_threads();
4467 : 4 : CU_ASSERT(g_bserrno == 0);
4468 : 4 : CU_ASSERT(memcmp(zero, payload_read, 10 * BLOCKLEN) == 0);
4469 : :
4470 : 4 : write_bytes = g_dev_write_bytes;
4471 : 4 : read_bytes = g_dev_read_bytes;
4472 : :
4473 : : /* Perform write on thread 1. That will allocate cluster on thread 0 via send_msg */
4474 : 4 : set_thread(1);
4475 : 4 : channel_thread1 = spdk_bs_alloc_io_channel(bs);
4476 : 4 : CU_ASSERT(channel_thread1 != NULL);
4477 : 4 : memset(payload_write, 0xE5, sizeof(payload_write));
4478 : 4 : spdk_blob_io_write(blob, channel_thread1, payload_write, 4, 10, blob_op_complete, NULL);
4479 : 4 : CU_ASSERT(free_clusters - 1 == spdk_bs_free_cluster_count(bs));
4480 : : /* Perform write on thread 0. That will try to allocate cluster,
4481 : : * but fail due to another thread issuing the cluster allocation first. */
4482 : 4 : set_thread(0);
4483 : 4 : memset(payload_write, 0xE5, sizeof(payload_write));
4484 : 4 : spdk_blob_io_write(blob, channel, payload_write, 4, 10, blob_op_complete, NULL);
4485 : 4 : CU_ASSERT(free_clusters - 2 == spdk_bs_free_cluster_count(bs));
4486 : 4 : poll_threads();
4487 : 4 : CU_ASSERT(g_bserrno == 0);
4488 : 4 : CU_ASSERT(free_clusters - 1 == spdk_bs_free_cluster_count(bs));
4489 : 4 : CU_ASSERT(spdk_blob_get_num_allocated_clusters(blob) == 1);
4490 : : /* For thin-provisioned blob we need to write 20 pages plus one page metadata and
4491 : : * read 0 bytes */
4492 [ + + ]: 4 : if (g_use_extent_table) {
4493 : : /* Add one more page for EXTENT_PAGE write */
4494 : 2 : CU_ASSERT(g_dev_write_bytes - write_bytes == page_size * 22);
4495 : 2 : } else {
4496 : 2 : CU_ASSERT(g_dev_write_bytes - write_bytes == page_size * 21);
4497 : : }
4498 : 4 : CU_ASSERT(g_dev_read_bytes - read_bytes == 0);
4499 : :
4500 : 4 : spdk_blob_io_read(blob, channel, payload_read, 4, 10, blob_op_complete, NULL);
4501 : 4 : poll_threads();
4502 : 4 : CU_ASSERT(g_bserrno == 0);
4503 : 4 : CU_ASSERT(memcmp(payload_write, payload_read, 10 * BLOCKLEN) == 0);
4504 : :
4505 : 4 : ut_blob_close_and_delete(bs, blob);
4506 : 4 : CU_ASSERT(free_clusters == spdk_bs_free_cluster_count(bs));
4507 : :
4508 : 4 : set_thread(1);
4509 : 4 : spdk_bs_free_io_channel(channel_thread1);
4510 : 4 : set_thread(0);
4511 : 4 : spdk_bs_free_io_channel(channel);
4512 : 4 : poll_threads();
4513 : 4 : g_blob = NULL;
4514 : 4 : g_blobid = 0;
4515 : 4 : }
4516 : :
4517 : : static void
4518 : 4 : blob_thin_prov_write_count_io(void)
4519 : : {
4520 : : struct spdk_blob_store *bs;
4521 : : struct spdk_blob *blob;
4522 : : struct spdk_io_channel *ch;
4523 : : struct spdk_bs_dev *dev;
4524 : : struct spdk_bs_opts bs_opts;
4525 : : struct spdk_blob_opts opts;
4526 : : uint64_t free_clusters;
4527 : : uint64_t page_size;
4528 : : uint8_t payload_write[BLOCKLEN];
4529 : : uint64_t write_bytes;
4530 : : uint64_t read_bytes;
4531 : 4 : const uint32_t CLUSTER_SZ = 16384;
4532 : : uint32_t pages_per_cluster;
4533 : : uint32_t pages_per_extent_page;
4534 : : uint32_t i;
4535 : :
4536 : : /* Use a very small cluster size for this test. This ensures we need multiple
4537 : : * extent pages to hold all of the clusters even for relatively small blobs like
4538 : : * we are restricted to for the unit tests (i.e. we don't want to allocate multi-GB
4539 : : * buffers).
4540 : : */
4541 : 4 : dev = init_dev();
4542 : 4 : spdk_bs_opts_init(&bs_opts, sizeof(bs_opts));
4543 : 4 : bs_opts.cluster_sz = CLUSTER_SZ;
4544 : :
4545 : 4 : spdk_bs_init(dev, &bs_opts, bs_op_with_handle_complete, NULL);
4546 : 4 : poll_threads();
4547 : 4 : CU_ASSERT(g_bserrno == 0);
4548 [ + - ]: 4 : SPDK_CU_ASSERT_FATAL(g_bs != NULL);
4549 : 4 : bs = g_bs;
4550 : :
4551 : 4 : free_clusters = spdk_bs_free_cluster_count(bs);
4552 : 4 : page_size = spdk_bs_get_page_size(bs);
4553 : 4 : pages_per_cluster = CLUSTER_SZ / page_size;
4554 : 4 : pages_per_extent_page = SPDK_EXTENTS_PER_EP * pages_per_cluster;
4555 : :
4556 : 4 : ch = spdk_bs_alloc_io_channel(bs);
4557 [ - + ]: 4 : SPDK_CU_ASSERT_FATAL(ch != NULL);
4558 : :
4559 : 4 : ut_spdk_blob_opts_init(&opts);
4560 : 4 : opts.thin_provision = true;
4561 : :
4562 : 4 : blob = ut_blob_create_and_open(bs, &opts);
4563 : 4 : CU_ASSERT(free_clusters == spdk_bs_free_cluster_count(bs));
4564 : :
4565 : : /* Resize the blob so that it will require 8 extent pages to hold all of
4566 : : * the clusters.
4567 : : */
4568 : 4 : g_bserrno = -1;
4569 : 4 : spdk_blob_resize(blob, SPDK_EXTENTS_PER_EP * 8, blob_op_complete, NULL);
4570 : 4 : poll_threads();
4571 : 4 : CU_ASSERT(g_bserrno == 0);
4572 : :
4573 : 4 : g_bserrno = -1;
4574 : 4 : spdk_blob_sync_md(blob, blob_op_complete, NULL);
4575 : 4 : poll_threads();
4576 : 4 : CU_ASSERT(g_bserrno == 0);
4577 : 4 : CU_ASSERT(free_clusters == spdk_bs_free_cluster_count(bs));
4578 : 4 : CU_ASSERT(blob->active.num_clusters == SPDK_EXTENTS_PER_EP * 8);
4579 : :
4580 : 4 : memset(payload_write, 0, sizeof(payload_write));
4581 [ + + ]: 36 : for (i = 0; i < 8; i++) {
4582 : 32 : write_bytes = g_dev_write_bytes;
4583 : 32 : read_bytes = g_dev_read_bytes;
4584 : :
4585 : 32 : g_bserrno = -1;
4586 : 32 : spdk_blob_io_write(blob, ch, payload_write, pages_per_extent_page * i, 1, blob_op_complete, NULL);
4587 : 32 : poll_threads();
4588 : 32 : CU_ASSERT(g_bserrno == 0);
4589 : 32 : CU_ASSERT(free_clusters - (2 * i + 1) == spdk_bs_free_cluster_count(bs));
4590 : :
4591 : 32 : CU_ASSERT(g_dev_read_bytes == read_bytes);
4592 [ + + ]: 32 : if (!g_use_extent_table) {
4593 : : /* For legacy metadata, we should have written two pages - one for the
4594 : : * write I/O itself, another for the blob's primary metadata.
4595 : : */
4596 : 16 : CU_ASSERT((g_dev_write_bytes - write_bytes) / page_size == 2);
4597 : 16 : } else {
4598 : : /* For extent table metadata, we should have written three pages - one
4599 : : * for the write I/O, one for the extent page, one for the blob's primary
4600 : : * metadata.
4601 : : */
4602 : 16 : CU_ASSERT((g_dev_write_bytes - write_bytes) / page_size == 3);
4603 : : }
4604 : :
4605 : : /* The write should have synced the metadata already. Do another sync here
4606 : : * just to confirm.
4607 : : */
4608 : 32 : write_bytes = g_dev_write_bytes;
4609 : 32 : read_bytes = g_dev_read_bytes;
4610 : :
4611 : 32 : g_bserrno = -1;
4612 : 32 : spdk_blob_sync_md(blob, blob_op_complete, NULL);
4613 : 32 : poll_threads();
4614 : 32 : CU_ASSERT(g_bserrno == 0);
4615 : 32 : CU_ASSERT(free_clusters - (2 * i + 1) == spdk_bs_free_cluster_count(bs));
4616 : 32 : CU_ASSERT(spdk_blob_get_num_allocated_clusters(blob) == 2 * i + 1);
4617 : :
4618 : 32 : CU_ASSERT(g_dev_read_bytes == read_bytes);
4619 : 32 : CU_ASSERT(g_dev_write_bytes == write_bytes);
4620 : :
4621 : : /* Now write to another unallocated cluster that is part of the same extent page. */
4622 : 32 : g_bserrno = -1;
4623 : 32 : spdk_blob_io_write(blob, ch, payload_write, pages_per_extent_page * i + pages_per_cluster,
4624 : : 1, blob_op_complete, NULL);
4625 : 32 : poll_threads();
4626 : 32 : CU_ASSERT(g_bserrno == 0);
4627 : 32 : CU_ASSERT(free_clusters - (2 * i + 2) == spdk_bs_free_cluster_count(bs));
4628 : 32 : CU_ASSERT(spdk_blob_get_num_allocated_clusters(blob) == 2 * i + 2);
4629 : :
4630 : 32 : CU_ASSERT(g_dev_read_bytes == read_bytes);
4631 : : /*
4632 : : * For legacy metadata, we should have written the I/O and the primary metadata page.
4633 : : * For extent table metadata, we should have written the I/O and the extent metadata page.
4634 : : */
4635 : 32 : CU_ASSERT((g_dev_write_bytes - write_bytes) / page_size == 2);
4636 : :
4637 : : /* Send unmap aligned to the whole cluster - should free it up */
4638 : 32 : g_bserrno = -1;
4639 : 32 : spdk_blob_io_unmap(blob, ch, pages_per_extent_page * i, pages_per_cluster, blob_op_complete, NULL);
4640 : 32 : poll_threads();
4641 : 32 : CU_ASSERT(g_bserrno == 0);
4642 : 32 : CU_ASSERT(free_clusters - (2 * i + 1) == spdk_bs_free_cluster_count(bs));
4643 : :
4644 : : /* Write back to the freed cluster */
4645 : 32 : g_bserrno = -1;
4646 : 32 : spdk_blob_io_write(blob, ch, payload_write, pages_per_extent_page * i, 1, blob_op_complete, NULL);
4647 : 32 : poll_threads();
4648 : 32 : CU_ASSERT(g_bserrno == 0);
4649 : 32 : CU_ASSERT(free_clusters - (2 * i + 2) == spdk_bs_free_cluster_count(bs));
4650 : 32 : }
4651 : :
4652 : 4 : ut_blob_close_and_delete(bs, blob);
4653 : 4 : CU_ASSERT(free_clusters == spdk_bs_free_cluster_count(bs));
4654 : :
4655 : 4 : spdk_bs_free_io_channel(ch);
4656 : 4 : poll_threads();
4657 : 4 : g_blob = NULL;
4658 : 4 : g_blobid = 0;
4659 : :
4660 : 4 : spdk_bs_unload(bs, bs_op_complete, NULL);
4661 : 4 : poll_threads();
4662 : 4 : CU_ASSERT(g_bserrno == 0);
4663 : 4 : g_bs = NULL;
4664 : 4 : }
4665 : :
4666 : : static void
4667 : 4 : blob_thin_prov_unmap_cluster(void)
4668 : : {
4669 : : struct spdk_blob_store *bs;
4670 : : struct spdk_blob *blob, *snapshot;
4671 : : struct spdk_io_channel *ch;
4672 : : struct spdk_bs_dev *dev;
4673 : : struct spdk_bs_opts bs_opts;
4674 : : struct spdk_blob_opts opts;
4675 : : uint64_t free_clusters;
4676 : : uint64_t page_size;
4677 : : uint8_t payload_write[BLOCKLEN];
4678 : : uint8_t payload_read[BLOCKLEN];
4679 : 4 : const uint32_t CLUSTER_COUNT = 3;
4680 : : uint32_t pages_per_cluster;
4681 : : spdk_blob_id blobid, snapshotid;
4682 : : uint32_t i;
4683 : : int err;
4684 : :
4685 : : /* Use a very large cluster size for this test. Check how the unmap/release cluster code path behaves when
4686 : : * clusters are fully used.
4687 : : */
4688 : 4 : dev = init_dev();
4689 : 4 : spdk_bs_opts_init(&bs_opts, sizeof(bs_opts));
4690 : 4 : bs_opts.cluster_sz = dev->blocklen * dev->blockcnt / (CLUSTER_COUNT + 1);
4691 : :
4692 : 4 : spdk_bs_init(dev, &bs_opts, bs_op_with_handle_complete, NULL);
4693 : 4 : poll_threads();
4694 : 4 : CU_ASSERT(g_bserrno == 0);
4695 [ + - ]: 4 : SPDK_CU_ASSERT_FATAL(g_bs != NULL);
4696 : 4 : bs = g_bs;
4697 : :
4698 : 4 : free_clusters = spdk_bs_free_cluster_count(bs);
4699 : 4 : page_size = spdk_bs_get_page_size(bs);
4700 : 4 : pages_per_cluster = bs_opts.cluster_sz / page_size;
4701 : :
4702 : 4 : ch = spdk_bs_alloc_io_channel(bs);
4703 [ + - ]: 4 : SPDK_CU_ASSERT_FATAL(ch != NULL);
4704 : :
4705 : 4 : ut_spdk_blob_opts_init(&opts);
4706 : 4 : opts.thin_provision = true;
4707 : :
4708 : 4 : blob = ut_blob_create_and_open(bs, &opts);
4709 : 4 : CU_ASSERT(free_clusters == CLUSTER_COUNT);
4710 : 4 : CU_ASSERT(free_clusters == spdk_bs_free_cluster_count(bs));
4711 : 4 : blobid = spdk_blob_get_id(blob);
4712 : :
4713 : 4 : g_bserrno = -1;
4714 : 4 : spdk_blob_resize(blob, CLUSTER_COUNT, blob_op_complete, NULL);
4715 : 4 : poll_threads();
4716 : 4 : CU_ASSERT(g_bserrno == 0);
4717 : :
4718 : 4 : g_bserrno = -1;
4719 : 4 : spdk_blob_sync_md(blob, blob_op_complete, NULL);
4720 : 4 : poll_threads();
4721 : 4 : CU_ASSERT(g_bserrno == 0);
4722 : 4 : CU_ASSERT(free_clusters == spdk_bs_free_cluster_count(bs));
4723 : 4 : CU_ASSERT(blob->active.num_clusters == CLUSTER_COUNT);
4724 : :
4725 : : /* Fill all clusters */
4726 [ + + ]: 16 : for (i = 0; i < CLUSTER_COUNT; i++) {
4727 : 12 : memset(payload_write, i + 1, sizeof(payload_write));
4728 : 12 : g_bserrno = -1;
4729 : 12 : spdk_blob_io_write(blob, ch, payload_write, pages_per_cluster * i, 1, blob_op_complete, NULL);
4730 : 12 : poll_threads();
4731 : 12 : CU_ASSERT(g_bserrno == 0);
4732 : 12 : CU_ASSERT(free_clusters - (i + 1) == spdk_bs_free_cluster_count(bs));
4733 : 12 : }
4734 : 4 : CU_ASSERT(0 == spdk_bs_free_cluster_count(bs));
4735 : :
4736 : : /* Unmap one whole cluster */
4737 : 4 : g_bserrno = -1;
4738 : 4 : spdk_blob_io_unmap(blob, ch, pages_per_cluster, pages_per_cluster, blob_op_complete, NULL);
4739 : 4 : poll_threads();
4740 : 4 : CU_ASSERT(g_bserrno == 0);
4741 : 4 : CU_ASSERT(1 == spdk_bs_free_cluster_count(bs));
4742 : :
4743 : : /* Verify the data read from the cluster is zeroed out */
4744 : 4 : memset(payload_write, 0, sizeof(payload_write));
4745 : 4 : spdk_blob_io_read(blob, ch, payload_read, pages_per_cluster, 1, blob_op_complete, NULL);
4746 : 4 : poll_threads();
4747 : 4 : CU_ASSERT(g_bserrno == 0);
4748 : 4 : CU_ASSERT(memcmp(payload_write, payload_read, BLOCKLEN) == 0);
4749 : :
4750 : : /* Fill the same cluster with data */
4751 : 4 : memset(payload_write, 3, sizeof(payload_write));
4752 : 4 : g_bserrno = -1;
4753 : 4 : spdk_blob_io_write(blob, ch, payload_write, pages_per_cluster, 1, blob_op_complete, NULL);
4754 : 4 : poll_threads();
4755 : 4 : CU_ASSERT(g_bserrno == 0);
4756 : 4 : CU_ASSERT(0 == spdk_bs_free_cluster_count(bs));
4757 : :
4758 : : /* Verify the data read from the cluster has the expected data */
4759 : 4 : spdk_blob_io_read(blob, ch, payload_read, pages_per_cluster, 1, blob_op_complete, NULL);
4760 : 4 : poll_threads();
4761 : 4 : CU_ASSERT(g_bserrno == 0);
4762 : 4 : CU_ASSERT(memcmp(payload_write, payload_read, BLOCKLEN) == 0);
4763 : :
4764 : : /* Send an unaligned unmap that ecompasses one whole cluster */
4765 : 4 : g_bserrno = -1;
4766 : 4 : spdk_blob_io_unmap(blob, ch, pages_per_cluster - 1, pages_per_cluster + 2, blob_op_complete, NULL);
4767 : 4 : poll_threads();
4768 : 4 : CU_ASSERT(g_bserrno == 0);
4769 : 4 : CU_ASSERT(1 == spdk_bs_free_cluster_count(bs));
4770 : :
4771 : : /* Verify the data read from the cluster is zeroed out */
4772 : 4 : g_bserrno = -1;
4773 : 4 : memset(payload_write, 0, sizeof(payload_write));
4774 : 4 : spdk_blob_io_read(blob, ch, payload_read, pages_per_cluster, 1, blob_op_complete, NULL);
4775 : 4 : poll_threads();
4776 : 4 : CU_ASSERT(g_bserrno == 0);
4777 : 4 : CU_ASSERT(memcmp(payload_write, payload_read, BLOCKLEN) == 0);
4778 : :
4779 : : /* Send a simultaneous unmap with a write to an unallocated area -
4780 : : * check that writes don't claim the currently unmapped cluster */
4781 : 4 : g_bserrno = -1;
4782 : 4 : memset(payload_write, 7, sizeof(payload_write));
4783 : 4 : spdk_blob_io_unmap(blob, ch, 0, pages_per_cluster, blob_op_complete, NULL);
4784 : 4 : spdk_blob_io_write(blob, ch, payload_write, pages_per_cluster, 1, blob_op_complete, NULL);
4785 : 4 : poll_threads();
4786 : 4 : CU_ASSERT(g_bserrno == 0);
4787 : 4 : CU_ASSERT(1 == spdk_bs_free_cluster_count(bs));
4788 : :
4789 : : /* Verify the contents of written sector */
4790 : 4 : g_bserrno = -1;
4791 : 4 : spdk_blob_io_read(blob, ch, payload_read, pages_per_cluster, 1, blob_op_complete, NULL);
4792 : 4 : poll_threads();
4793 : 4 : CU_ASSERT(g_bserrno == 0);
4794 : 4 : CU_ASSERT(memcmp(payload_write, payload_read, BLOCKLEN) == 0);
4795 : :
4796 : : /* Verify the contents of unmapped sector */
4797 : 4 : g_bserrno = -1;
4798 : 4 : memset(payload_write, 0, sizeof(payload_write));
4799 : 4 : spdk_blob_io_read(blob, ch, payload_read, 0, 1, blob_op_complete, NULL);
4800 : 4 : poll_threads();
4801 : 4 : CU_ASSERT(g_bserrno == 0);
4802 : 4 : CU_ASSERT(memcmp(payload_write, payload_read, BLOCKLEN) == 0);
4803 : :
4804 : : /* Make sure clusters are not freed until the unmap to the drive is done */
4805 : 4 : g_bserrno = -1;
4806 : 4 : memset(payload_write, 7, sizeof(payload_write));
4807 : 4 : spdk_blob_io_write(blob, ch, payload_write, 0, 1, blob_op_complete, NULL);
4808 : 4 : poll_threads();
4809 : 4 : CU_ASSERT(g_bserrno == 0);
4810 : 4 : CU_ASSERT(0 == spdk_bs_free_cluster_count(bs));
4811 : :
4812 : 4 : g_bserrno = -1;
4813 : 4 : spdk_blob_io_unmap(blob, ch, 0, pages_per_cluster, blob_op_complete, NULL);
4814 [ - + ]: 4 : while (memcmp(payload_write, &g_dev_buffer[BLOCKLEN * pages_per_cluster], BLOCKLEN) == 0) {
4815 : 0 : CU_ASSERT(0 == spdk_bs_free_cluster_count(bs));
4816 : 0 : poll_thread_times(0, 1);
4817 : : }
4818 : 4 : poll_threads();
4819 : 4 : CU_ASSERT(g_bserrno == 0);
4820 : 4 : CU_ASSERT(1 == spdk_bs_free_cluster_count(bs));
4821 : :
4822 : : /* Issue #3358 had a bug with concurrent trims to the same cluster causing an assert, check for regressions.
4823 : : * Send three concurrent unmaps to the same cluster.
4824 : : */
4825 : 4 : g_bserrno = -1;
4826 : 4 : memset(payload_write, 7, sizeof(payload_write));
4827 : 4 : spdk_blob_io_write(blob, ch, payload_write, 0, 1, blob_op_complete, NULL);
4828 : 4 : poll_threads();
4829 : 4 : CU_ASSERT(g_bserrno == 0);
4830 : 4 : CU_ASSERT(0 == spdk_bs_free_cluster_count(bs));
4831 : :
4832 : 4 : g_bserrno = -1;
4833 : 4 : err = -1;
4834 : 4 : spdk_blob_io_unmap(blob, ch, 0, pages_per_cluster, blob_op_complete, NULL);
4835 : 4 : spdk_blob_io_unmap(blob, ch, 0, pages_per_cluster, blob_op_complete, NULL);
4836 : 4 : spdk_blob_io_unmap(blob, ch, 0, pages_per_cluster, blob_op_complete, &err);
4837 : 4 : poll_threads();
4838 : 4 : CU_ASSERT(g_bserrno == 0);
4839 : 4 : CU_ASSERT(err == 0);
4840 : 4 : CU_ASSERT(1 == spdk_bs_free_cluster_count(bs));
4841 : :
4842 : : /* Test thin-provisioned blob that is backed */
4843 : 4 : spdk_blob_resize(blob, 1, blob_op_complete, NULL);
4844 : 4 : poll_threads();
4845 : 4 : CU_ASSERT(g_bserrno == 0);
4846 : 4 : spdk_blob_sync_md(blob, blob_op_complete, NULL);
4847 : 4 : poll_threads();
4848 : 4 : CU_ASSERT(g_bserrno == 0);
4849 : 4 : CU_ASSERT(free_clusters == spdk_bs_free_cluster_count(bs));
4850 : :
4851 : 4 : g_bserrno = -1;
4852 : 4 : memset(payload_write, 1, sizeof(payload_write));
4853 : 4 : spdk_blob_io_write(blob, ch, payload_write, 0, 1, blob_op_complete, NULL);
4854 : 4 : poll_threads();
4855 : 4 : CU_ASSERT(g_bserrno == 0);
4856 : 4 : CU_ASSERT(free_clusters - 1 == spdk_bs_free_cluster_count(bs));
4857 : :
4858 : : /* Create a snapshot */
4859 : 4 : CU_ASSERT_EQUAL(_get_snapshots_count(bs), 0);
4860 : 4 : spdk_bs_create_snapshot(bs, blobid, NULL, blob_op_with_id_complete, NULL);
4861 : 4 : poll_threads();
4862 : 4 : CU_ASSERT(g_bserrno == 0);
4863 : 4 : CU_ASSERT(g_blobid != SPDK_BLOBID_INVALID);
4864 : 4 : CU_ASSERT_EQUAL(_get_snapshots_count(bs), 1);
4865 : 4 : snapshotid = g_blobid;
4866 : 4 : CU_ASSERT(free_clusters - 1 == spdk_bs_free_cluster_count(bs));
4867 : 4 : spdk_bs_open_blob(bs, snapshotid, blob_op_with_handle_complete, NULL);
4868 : 4 : poll_threads();
4869 : 4 : CU_ASSERT(g_bserrno == 0);
4870 [ - + ]: 4 : SPDK_CU_ASSERT_FATAL(g_blob != NULL);
4871 : 4 : snapshot = g_blob;
4872 : :
4873 : : /* Write data to blob, it will alloc new cluster */
4874 : 4 : g_bserrno = -1;
4875 : 4 : memset(payload_write, 2, sizeof(payload_write));
4876 : 4 : spdk_blob_io_write(blob, ch, payload_write, 0, 1, blob_op_complete, NULL);
4877 : 4 : poll_threads();
4878 : 4 : CU_ASSERT(g_bserrno == 0);
4879 : 4 : CU_ASSERT(free_clusters - 2 == spdk_bs_free_cluster_count(bs));
4880 : :
4881 : : /* Unmap one whole cluster, but do not release this cluster */
4882 : 4 : g_bserrno = -1;
4883 : 4 : spdk_blob_io_unmap(blob, ch, 0, pages_per_cluster, blob_op_complete, NULL);
4884 : 4 : poll_threads();
4885 : 4 : CU_ASSERT(g_bserrno == 0);
4886 : 4 : CU_ASSERT(free_clusters - 2 == spdk_bs_free_cluster_count(bs));
4887 : :
4888 : : /* Verify the data read from the cluster is zeroed out */
4889 : 4 : g_bserrno = -1;
4890 : 4 : memset(payload_write, 0, sizeof(payload_write));
4891 : 4 : spdk_blob_io_read(blob, ch, payload_read, 0, 1, blob_op_complete, NULL);
4892 : 4 : poll_threads();
4893 : 4 : CU_ASSERT(g_bserrno == 0);
4894 : 4 : CU_ASSERT(memcmp(payload_write, payload_read, BLOCKLEN) == 0);
4895 : :
4896 : 4 : ut_blob_close_and_delete(bs, blob);
4897 : 4 : ut_blob_close_and_delete(bs, snapshot);
4898 : 4 : CU_ASSERT(free_clusters == spdk_bs_free_cluster_count(bs));
4899 : :
4900 : 4 : spdk_bs_free_io_channel(ch);
4901 : 4 : poll_threads();
4902 : 4 : g_blob = NULL;
4903 : 4 : g_blobid = 0;
4904 : :
4905 : 4 : spdk_bs_unload(bs, bs_op_complete, NULL);
4906 : 4 : poll_threads();
4907 : 4 : CU_ASSERT(g_bserrno == 0);
4908 : 4 : g_bs = NULL;
4909 : 4 : }
4910 : :
4911 : : static void
4912 : 4 : blob_thin_prov_rle(void)
4913 : : {
4914 : : static const uint8_t zero[10 * BLOCKLEN] = { 0 };
4915 : 4 : struct spdk_blob_store *bs = g_bs;
4916 : : struct spdk_blob *blob;
4917 : : struct spdk_io_channel *channel;
4918 : : struct spdk_blob_opts opts;
4919 : : spdk_blob_id blobid;
4920 : : uint64_t free_clusters;
4921 : : uint64_t page_size;
4922 : : uint8_t payload_read[10 * BLOCKLEN];
4923 : : uint8_t payload_write[10 * BLOCKLEN];
4924 : : uint64_t write_bytes;
4925 : : uint64_t read_bytes;
4926 : : uint64_t io_unit;
4927 : :
4928 : 4 : free_clusters = spdk_bs_free_cluster_count(bs);
4929 : 4 : page_size = spdk_bs_get_page_size(bs);
4930 : :
4931 : 4 : ut_spdk_blob_opts_init(&opts);
4932 : 4 : opts.thin_provision = true;
4933 : 4 : opts.num_clusters = 5;
4934 : :
4935 : 4 : blob = ut_blob_create_and_open(bs, &opts);
4936 : 4 : blobid = spdk_blob_get_id(blob);
4937 : 4 : CU_ASSERT(free_clusters == spdk_bs_free_cluster_count(bs));
4938 : :
4939 : 4 : channel = spdk_bs_alloc_io_channel(bs);
4940 : 4 : CU_ASSERT(channel != NULL);
4941 : :
4942 : : /* Target specifically second cluster in a blob as first allocation */
4943 : 4 : io_unit = bs_cluster_to_page(bs, 1) * bs_io_unit_per_page(bs);
4944 : :
4945 : : /* Payload should be all zeros from unallocated clusters */
4946 : 4 : memset(payload_read, 0xFF, sizeof(payload_read));
4947 : 4 : spdk_blob_io_read(blob, channel, payload_read, io_unit, 10, blob_op_complete, NULL);
4948 : 4 : poll_threads();
4949 : 4 : CU_ASSERT(g_bserrno == 0);
4950 : 4 : CU_ASSERT(memcmp(zero, payload_read, 10 * BLOCKLEN) == 0);
4951 : :
4952 : 4 : write_bytes = g_dev_write_bytes;
4953 : 4 : read_bytes = g_dev_read_bytes;
4954 : :
4955 : : /* Issue write to second cluster in a blob */
4956 : 4 : memset(payload_write, 0xE5, sizeof(payload_write));
4957 : 4 : spdk_blob_io_write(blob, channel, payload_write, io_unit, 10, blob_op_complete, NULL);
4958 : 4 : poll_threads();
4959 : 4 : CU_ASSERT(g_bserrno == 0);
4960 : 4 : CU_ASSERT(free_clusters - 1 == spdk_bs_free_cluster_count(bs));
4961 : : /* For thin-provisioned blob we need to write 10 pages plus one page metadata and
4962 : : * read 0 bytes */
4963 [ + + ]: 4 : if (g_use_extent_table) {
4964 : : /* Add one more page for EXTENT_PAGE write */
4965 : 2 : CU_ASSERT(g_dev_write_bytes - write_bytes == page_size * 12);
4966 : 2 : } else {
4967 : 2 : CU_ASSERT(g_dev_write_bytes - write_bytes == page_size * 11);
4968 : : }
4969 : 4 : CU_ASSERT(g_dev_read_bytes - read_bytes == 0);
4970 : :
4971 : 4 : spdk_blob_io_read(blob, channel, payload_read, io_unit, 10, blob_op_complete, NULL);
4972 : 4 : poll_threads();
4973 : 4 : CU_ASSERT(g_bserrno == 0);
4974 : 4 : CU_ASSERT(memcmp(payload_write, payload_read, 10 * BLOCKLEN) == 0);
4975 : :
4976 : 4 : spdk_bs_free_io_channel(channel);
4977 : 4 : poll_threads();
4978 : :
4979 : 4 : spdk_blob_close(blob, blob_op_complete, NULL);
4980 : 4 : poll_threads();
4981 : 4 : CU_ASSERT(g_bserrno == 0);
4982 : :
4983 : 4 : ut_bs_reload(&bs, NULL);
4984 : :
4985 : 4 : spdk_bs_open_blob(bs, blobid, blob_op_with_handle_complete, NULL);
4986 : 4 : poll_threads();
4987 : 4 : CU_ASSERT(g_bserrno == 0);
4988 [ + - ]: 4 : SPDK_CU_ASSERT_FATAL(g_blob != NULL);
4989 : 4 : blob = g_blob;
4990 : :
4991 : 4 : channel = spdk_bs_alloc_io_channel(bs);
4992 : 4 : CU_ASSERT(channel != NULL);
4993 : :
4994 : : /* Read second cluster after blob reload to confirm data written */
4995 : 4 : spdk_blob_io_read(blob, channel, payload_read, io_unit, 10, blob_op_complete, NULL);
4996 : 4 : poll_threads();
4997 : 4 : CU_ASSERT(g_bserrno == 0);
4998 : 4 : CU_ASSERT(memcmp(payload_write, payload_read, 10 * BLOCKLEN) == 0);
4999 : :
5000 : 4 : spdk_bs_free_io_channel(channel);
5001 : 4 : poll_threads();
5002 : :
5003 : 4 : ut_blob_close_and_delete(bs, blob);
5004 : 4 : }
5005 : :
5006 : : static void
5007 : 4 : blob_thin_prov_rw_iov(void)
5008 : : {
5009 : : static const uint8_t zero[10 * BLOCKLEN] = { 0 };
5010 : 4 : struct spdk_blob_store *bs = g_bs;
5011 : : struct spdk_blob *blob;
5012 : : struct spdk_io_channel *channel;
5013 : : struct spdk_blob_opts opts;
5014 : : uint64_t free_clusters;
5015 : : uint8_t payload_read[10 * BLOCKLEN];
5016 : : uint8_t payload_write[10 * BLOCKLEN];
5017 : : struct iovec iov_read[3];
5018 : : struct iovec iov_write[3];
5019 : :
5020 : 4 : free_clusters = spdk_bs_free_cluster_count(bs);
5021 : :
5022 : 4 : channel = spdk_bs_alloc_io_channel(bs);
5023 : 4 : CU_ASSERT(channel != NULL);
5024 : :
5025 : 4 : ut_spdk_blob_opts_init(&opts);
5026 : 4 : opts.thin_provision = true;
5027 : :
5028 : 4 : blob = ut_blob_create_and_open(bs, &opts);
5029 : 4 : CU_ASSERT(free_clusters == spdk_bs_free_cluster_count(bs));
5030 : :
5031 : 4 : CU_ASSERT(blob->active.num_clusters == 0);
5032 : :
5033 : : /* The blob started at 0 clusters. Resize it to be 5, but still unallocated. */
5034 : 4 : spdk_blob_resize(blob, 5, blob_op_complete, NULL);
5035 : 4 : poll_threads();
5036 : 4 : CU_ASSERT(g_bserrno == 0);
5037 : 4 : CU_ASSERT(free_clusters == spdk_bs_free_cluster_count(bs));
5038 : 4 : CU_ASSERT(blob->active.num_clusters == 5);
5039 : :
5040 : 4 : spdk_blob_sync_md(blob, blob_op_complete, NULL);
5041 : 4 : poll_threads();
5042 : 4 : CU_ASSERT(g_bserrno == 0);
5043 : : /* Sync must not change anything */
5044 : 4 : CU_ASSERT(free_clusters == spdk_bs_free_cluster_count(bs));
5045 : 4 : CU_ASSERT(blob->active.num_clusters == 5);
5046 : :
5047 : : /* Payload should be all zeros from unallocated clusters */
5048 : 4 : memset(payload_read, 0xAA, sizeof(payload_read));
5049 : 4 : iov_read[0].iov_base = payload_read;
5050 : 4 : iov_read[0].iov_len = 3 * BLOCKLEN;
5051 : 4 : iov_read[1].iov_base = payload_read + 3 * BLOCKLEN;
5052 : 4 : iov_read[1].iov_len = 4 * BLOCKLEN;
5053 : 4 : iov_read[2].iov_base = payload_read + 7 * BLOCKLEN;
5054 : 4 : iov_read[2].iov_len = 3 * BLOCKLEN;
5055 : 4 : spdk_blob_io_readv(blob, channel, iov_read, 3, 250, 10, blob_op_complete, NULL);
5056 : 4 : poll_threads();
5057 : 4 : CU_ASSERT(g_bserrno == 0);
5058 : 4 : CU_ASSERT(memcmp(zero, payload_read, 10 * BLOCKLEN) == 0);
5059 : :
5060 : 4 : memset(payload_write, 0xE5, sizeof(payload_write));
5061 : 4 : iov_write[0].iov_base = payload_write;
5062 : 4 : iov_write[0].iov_len = 1 * BLOCKLEN;
5063 : 4 : iov_write[1].iov_base = payload_write + 1 * BLOCKLEN;
5064 : 4 : iov_write[1].iov_len = 5 * BLOCKLEN;
5065 : 4 : iov_write[2].iov_base = payload_write + 6 * BLOCKLEN;
5066 : 4 : iov_write[2].iov_len = 4 * BLOCKLEN;
5067 : :
5068 : 4 : spdk_blob_io_writev(blob, channel, iov_write, 3, 250, 10, blob_op_complete, NULL);
5069 : 4 : poll_threads();
5070 : 4 : CU_ASSERT(g_bserrno == 0);
5071 : :
5072 : 4 : memset(payload_read, 0xAA, sizeof(payload_read));
5073 : 4 : iov_read[0].iov_base = payload_read;
5074 : 4 : iov_read[0].iov_len = 3 * BLOCKLEN;
5075 : 4 : iov_read[1].iov_base = payload_read + 3 * BLOCKLEN;
5076 : 4 : iov_read[1].iov_len = 4 * BLOCKLEN;
5077 : 4 : iov_read[2].iov_base = payload_read + 7 * BLOCKLEN;
5078 : 4 : iov_read[2].iov_len = 3 * BLOCKLEN;
5079 : 4 : spdk_blob_io_readv(blob, channel, iov_read, 3, 250, 10, blob_op_complete, NULL);
5080 : 4 : poll_threads();
5081 : 4 : CU_ASSERT(g_bserrno == 0);
5082 : 4 : CU_ASSERT(memcmp(payload_write, payload_read, 10 * BLOCKLEN) == 0);
5083 : :
5084 : 4 : spdk_bs_free_io_channel(channel);
5085 : 4 : poll_threads();
5086 : :
5087 : 4 : ut_blob_close_and_delete(bs, blob);
5088 : 4 : }
5089 : :
5090 : : struct iter_ctx {
5091 : : int current_iter;
5092 : : spdk_blob_id blobid[4];
5093 : : };
5094 : :
5095 : : static void
5096 : 32 : test_iter(void *arg, struct spdk_blob *blob, int bserrno)
5097 : : {
5098 : 32 : struct iter_ctx *iter_ctx = arg;
5099 : : spdk_blob_id blobid;
5100 : :
5101 : 32 : CU_ASSERT(bserrno == 0);
5102 : 32 : blobid = spdk_blob_get_id(blob);
5103 : 32 : CU_ASSERT(blobid == iter_ctx->blobid[iter_ctx->current_iter++]);
5104 : 32 : }
5105 : :
5106 : : static void
5107 : 4 : bs_load_iter_test(void)
5108 : : {
5109 : : struct spdk_blob_store *bs;
5110 : : struct spdk_bs_dev *dev;
5111 : 4 : struct iter_ctx iter_ctx = { 0 };
5112 : : struct spdk_blob *blob;
5113 : : int i, rc;
5114 : : struct spdk_bs_opts opts;
5115 : :
5116 : 4 : dev = init_dev();
5117 : 4 : spdk_bs_opts_init(&opts, sizeof(opts));
5118 : 4 : snprintf(opts.bstype.bstype, sizeof(opts.bstype.bstype), "TESTTYPE");
5119 : :
5120 : : /* Initialize a new blob store */
5121 : 4 : spdk_bs_init(dev, &opts, bs_op_with_handle_complete, NULL);
5122 : 4 : poll_threads();
5123 : 4 : CU_ASSERT(g_bserrno == 0);
5124 [ + - ]: 4 : SPDK_CU_ASSERT_FATAL(g_bs != NULL);
5125 : 4 : bs = g_bs;
5126 : :
5127 [ + + ]: 20 : for (i = 0; i < 4; i++) {
5128 : 16 : blob = ut_blob_create_and_open(bs, NULL);
5129 : 16 : iter_ctx.blobid[i] = spdk_blob_get_id(blob);
5130 : :
5131 : : /* Just save the blobid as an xattr for testing purposes. */
5132 : 16 : rc = spdk_blob_set_xattr(blob, "blobid", &iter_ctx.blobid[i], sizeof(spdk_blob_id));
5133 : 16 : CU_ASSERT(rc == 0);
5134 : :
5135 : : /* Resize the blob */
5136 : 16 : spdk_blob_resize(blob, i, blob_op_complete, NULL);
5137 : 16 : poll_threads();
5138 : 16 : CU_ASSERT(g_bserrno == 0);
5139 : :
5140 : 16 : spdk_blob_close(blob, blob_op_complete, NULL);
5141 : 16 : poll_threads();
5142 : 16 : CU_ASSERT(g_bserrno == 0);
5143 : 16 : }
5144 : :
5145 : 4 : g_bserrno = -1;
5146 : 4 : spdk_bs_unload(bs, bs_op_complete, NULL);
5147 : 4 : poll_threads();
5148 : 4 : CU_ASSERT(g_bserrno == 0);
5149 : :
5150 : 4 : dev = init_dev();
5151 : 4 : spdk_bs_opts_init(&opts, sizeof(opts));
5152 : 4 : snprintf(opts.bstype.bstype, sizeof(opts.bstype.bstype), "TESTTYPE");
5153 : 4 : opts.iter_cb_fn = test_iter;
5154 : 4 : opts.iter_cb_arg = &iter_ctx;
5155 : :
5156 : : /* Test blob iteration during load after a clean shutdown. */
5157 : 4 : spdk_bs_load(dev, &opts, bs_op_with_handle_complete, NULL);
5158 : 4 : poll_threads();
5159 : 4 : CU_ASSERT(g_bserrno == 0);
5160 [ + - ]: 4 : SPDK_CU_ASSERT_FATAL(g_bs != NULL);
5161 : 4 : bs = g_bs;
5162 : :
5163 : : /* Dirty shutdown */
5164 : 4 : bs_free(bs);
5165 : :
5166 : 4 : dev = init_dev();
5167 : 4 : spdk_bs_opts_init(&opts, sizeof(opts));
5168 : 4 : snprintf(opts.bstype.bstype, sizeof(opts.bstype.bstype), "TESTTYPE");
5169 : 4 : opts.iter_cb_fn = test_iter;
5170 : 4 : iter_ctx.current_iter = 0;
5171 : 4 : opts.iter_cb_arg = &iter_ctx;
5172 : :
5173 : : /* Test blob iteration during load after a dirty shutdown. */
5174 : 4 : spdk_bs_load(dev, &opts, bs_op_with_handle_complete, NULL);
5175 : 4 : poll_threads();
5176 : 4 : CU_ASSERT(g_bserrno == 0);
5177 [ - + ]: 4 : SPDK_CU_ASSERT_FATAL(g_bs != NULL);
5178 : 4 : bs = g_bs;
5179 : :
5180 : 4 : spdk_bs_unload(bs, bs_op_complete, NULL);
5181 : 4 : poll_threads();
5182 : 4 : CU_ASSERT(g_bserrno == 0);
5183 : 4 : g_bs = NULL;
5184 : 4 : }
5185 : :
5186 : : static void
5187 : 4 : blob_snapshot_rw(void)
5188 : : {
5189 : : static const uint8_t zero[10 * BLOCKLEN] = { 0 };
5190 : 4 : struct spdk_blob_store *bs = g_bs;
5191 : : struct spdk_blob *blob, *snapshot;
5192 : : struct spdk_io_channel *channel;
5193 : : struct spdk_blob_opts opts;
5194 : : spdk_blob_id blobid, snapshotid;
5195 : : uint64_t free_clusters;
5196 : : uint64_t cluster_size;
5197 : : uint64_t page_size;
5198 : : uint8_t payload_read[10 * BLOCKLEN];
5199 : : uint8_t payload_write[10 * BLOCKLEN];
5200 : : uint64_t write_bytes_start;
5201 : : uint64_t read_bytes_start;
5202 : : uint64_t copy_bytes_start;
5203 : : uint64_t write_bytes;
5204 : : uint64_t read_bytes;
5205 : : uint64_t copy_bytes;
5206 : :
5207 : 4 : free_clusters = spdk_bs_free_cluster_count(bs);
5208 : 4 : cluster_size = spdk_bs_get_cluster_size(bs);
5209 : 4 : page_size = spdk_bs_get_page_size(bs);
5210 : :
5211 : 4 : channel = spdk_bs_alloc_io_channel(bs);
5212 : 4 : CU_ASSERT(channel != NULL);
5213 : :
5214 : 4 : ut_spdk_blob_opts_init(&opts);
5215 : 4 : opts.thin_provision = true;
5216 : 4 : opts.num_clusters = 5;
5217 : :
5218 : 4 : blob = ut_blob_create_and_open(bs, &opts);
5219 : 4 : blobid = spdk_blob_get_id(blob);
5220 : 4 : CU_ASSERT(free_clusters == spdk_bs_free_cluster_count(bs));
5221 : :
5222 : 4 : CU_ASSERT(spdk_blob_get_num_clusters(blob) == 5);
5223 : :
5224 : 4 : memset(payload_read, 0xFF, sizeof(payload_read));
5225 : 4 : spdk_blob_io_read(blob, channel, payload_read, 4, 10, blob_op_complete, NULL);
5226 : 4 : poll_threads();
5227 : 4 : CU_ASSERT(g_bserrno == 0);
5228 : 4 : CU_ASSERT(memcmp(zero, payload_read, 10 * BLOCKLEN) == 0);
5229 : :
5230 : 4 : memset(payload_write, 0xE5, sizeof(payload_write));
5231 : 4 : spdk_blob_io_write(blob, channel, payload_write, 4, 10, blob_op_complete, NULL);
5232 : 4 : poll_threads();
5233 : 4 : CU_ASSERT(g_bserrno == 0);
5234 : 4 : CU_ASSERT(free_clusters != spdk_bs_free_cluster_count(bs));
5235 : :
5236 : : /* Create snapshot from blob */
5237 : 4 : spdk_bs_create_snapshot(bs, blobid, NULL, blob_op_with_id_complete, NULL);
5238 : 4 : poll_threads();
5239 : 4 : CU_ASSERT(g_bserrno == 0);
5240 : 4 : CU_ASSERT(g_blobid != SPDK_BLOBID_INVALID);
5241 : 4 : snapshotid = g_blobid;
5242 : :
5243 : 4 : spdk_bs_open_blob(bs, snapshotid, blob_op_with_handle_complete, NULL);
5244 : 4 : poll_threads();
5245 : 4 : CU_ASSERT(g_bserrno == 0);
5246 [ + - ]: 4 : SPDK_CU_ASSERT_FATAL(g_blob != NULL);
5247 : 4 : snapshot = g_blob;
5248 : 4 : CU_ASSERT(snapshot->data_ro == true);
5249 : 4 : CU_ASSERT(snapshot->md_ro == true);
5250 : :
5251 : 4 : CU_ASSERT(spdk_blob_get_num_clusters(snapshot) == 5);
5252 : :
5253 : 4 : write_bytes_start = g_dev_write_bytes;
5254 : 4 : read_bytes_start = g_dev_read_bytes;
5255 : 4 : copy_bytes_start = g_dev_copy_bytes;
5256 : :
5257 : 4 : memset(payload_write, 0xAA, sizeof(payload_write));
5258 : 4 : spdk_blob_io_write(blob, channel, payload_write, 4, 10, blob_op_complete, NULL);
5259 : 4 : poll_threads();
5260 : 4 : CU_ASSERT(g_bserrno == 0);
5261 : 4 : CU_ASSERT(free_clusters != spdk_bs_free_cluster_count(bs));
5262 : :
5263 : : /* For a clone we need to allocate and copy one cluster, update one page of metadata
5264 : : * and then write 10 pages of payload.
5265 : : */
5266 : 4 : write_bytes = g_dev_write_bytes - write_bytes_start;
5267 : 4 : read_bytes = g_dev_read_bytes - read_bytes_start;
5268 : 4 : copy_bytes = g_dev_copy_bytes - copy_bytes_start;
5269 [ + + ]: 4 : if (g_dev_copy_enabled) {
5270 : 2 : CU_ASSERT(copy_bytes == cluster_size);
5271 : 2 : } else {
5272 : 2 : CU_ASSERT(copy_bytes == 0);
5273 : : }
5274 [ + + ]: 4 : if (g_use_extent_table) {
5275 : : /* Add one more page for EXTENT_PAGE write */
5276 : 2 : CU_ASSERT(write_bytes + copy_bytes == page_size * 12 + cluster_size);
5277 : 2 : } else {
5278 : 2 : CU_ASSERT(write_bytes + copy_bytes == page_size * 11 + cluster_size);
5279 : : }
5280 : 4 : CU_ASSERT(read_bytes + copy_bytes == cluster_size);
5281 : :
5282 : 4 : spdk_blob_io_read(blob, channel, payload_read, 4, 10, blob_op_complete, NULL);
5283 : 4 : poll_threads();
5284 : 4 : CU_ASSERT(g_bserrno == 0);
5285 : 4 : CU_ASSERT(memcmp(payload_write, payload_read, 10 * BLOCKLEN) == 0);
5286 : :
5287 : : /* Data on snapshot should not change after write to clone */
5288 : 4 : memset(payload_write, 0xE5, sizeof(payload_write));
5289 : 4 : spdk_blob_io_read(snapshot, channel, payload_read, 4, 10, blob_op_complete, NULL);
5290 : 4 : poll_threads();
5291 : 4 : CU_ASSERT(g_bserrno == 0);
5292 : 4 : CU_ASSERT(memcmp(payload_write, payload_read, 10 * BLOCKLEN) == 0);
5293 : :
5294 : 4 : ut_blob_close_and_delete(bs, blob);
5295 : 4 : ut_blob_close_and_delete(bs, snapshot);
5296 : :
5297 : 4 : spdk_bs_free_io_channel(channel);
5298 : 4 : poll_threads();
5299 : 4 : g_blob = NULL;
5300 : 4 : g_blobid = 0;
5301 : 4 : }
5302 : :
5303 : : static void
5304 : 4 : blob_snapshot_rw_iov(void)
5305 : : {
5306 : : static const uint8_t zero[10 * BLOCKLEN] = { 0 };
5307 : 4 : struct spdk_blob_store *bs = g_bs;
5308 : : struct spdk_blob *blob, *snapshot;
5309 : : struct spdk_io_channel *channel;
5310 : : struct spdk_blob_opts opts;
5311 : : spdk_blob_id blobid, snapshotid;
5312 : : uint64_t free_clusters;
5313 : : uint8_t payload_read[10 * BLOCKLEN];
5314 : : uint8_t payload_write[10 * BLOCKLEN];
5315 : : struct iovec iov_read[3];
5316 : : struct iovec iov_write[3];
5317 : :
5318 : 4 : free_clusters = spdk_bs_free_cluster_count(bs);
5319 : :
5320 : 4 : channel = spdk_bs_alloc_io_channel(bs);
5321 : 4 : CU_ASSERT(channel != NULL);
5322 : :
5323 : 4 : ut_spdk_blob_opts_init(&opts);
5324 : 4 : opts.thin_provision = true;
5325 : 4 : opts.num_clusters = 5;
5326 : :
5327 : 4 : blob = ut_blob_create_and_open(bs, &opts);
5328 : 4 : blobid = spdk_blob_get_id(blob);
5329 : 4 : CU_ASSERT(free_clusters == spdk_bs_free_cluster_count(bs));
5330 : :
5331 : 4 : CU_ASSERT(spdk_blob_get_num_clusters(blob) == 5);
5332 : :
5333 : : /* Create snapshot from blob */
5334 : 4 : spdk_bs_create_snapshot(bs, blobid, NULL, blob_op_with_id_complete, NULL);
5335 : 4 : poll_threads();
5336 : 4 : CU_ASSERT(g_bserrno == 0);
5337 : 4 : CU_ASSERT(g_blobid != SPDK_BLOBID_INVALID);
5338 : 4 : snapshotid = g_blobid;
5339 : :
5340 : 4 : spdk_bs_open_blob(bs, snapshotid, blob_op_with_handle_complete, NULL);
5341 : 4 : poll_threads();
5342 : 4 : CU_ASSERT(g_bserrno == 0);
5343 [ + - ]: 4 : SPDK_CU_ASSERT_FATAL(g_blob != NULL);
5344 : 4 : snapshot = g_blob;
5345 : 4 : CU_ASSERT(snapshot->data_ro == true);
5346 : 4 : CU_ASSERT(snapshot->md_ro == true);
5347 : 4 : CU_ASSERT(spdk_blob_get_num_clusters(snapshot) == 5);
5348 : :
5349 : : /* Payload should be all zeros from unallocated clusters */
5350 : 4 : memset(payload_read, 0xAA, sizeof(payload_read));
5351 : 4 : iov_read[0].iov_base = payload_read;
5352 : 4 : iov_read[0].iov_len = 3 * BLOCKLEN;
5353 : 4 : iov_read[1].iov_base = payload_read + 3 * BLOCKLEN;
5354 : 4 : iov_read[1].iov_len = 4 * BLOCKLEN;
5355 : 4 : iov_read[2].iov_base = payload_read + 7 * BLOCKLEN;
5356 : 4 : iov_read[2].iov_len = 3 * BLOCKLEN;
5357 : 4 : spdk_blob_io_readv(blob, channel, iov_read, 3, 250, 10, blob_op_complete, NULL);
5358 : 4 : poll_threads();
5359 : 4 : CU_ASSERT(g_bserrno == 0);
5360 : 4 : CU_ASSERT(memcmp(zero, payload_read, 10 * BLOCKLEN) == 0);
5361 : :
5362 : 4 : memset(payload_write, 0xE5, sizeof(payload_write));
5363 : 4 : iov_write[0].iov_base = payload_write;
5364 : 4 : iov_write[0].iov_len = 1 * BLOCKLEN;
5365 : 4 : iov_write[1].iov_base = payload_write + 1 * BLOCKLEN;
5366 : 4 : iov_write[1].iov_len = 5 * BLOCKLEN;
5367 : 4 : iov_write[2].iov_base = payload_write + 6 * BLOCKLEN;
5368 : 4 : iov_write[2].iov_len = 4 * BLOCKLEN;
5369 : :
5370 : 4 : spdk_blob_io_writev(blob, channel, iov_write, 3, 250, 10, blob_op_complete, NULL);
5371 : 4 : poll_threads();
5372 : 4 : CU_ASSERT(g_bserrno == 0);
5373 : :
5374 : 4 : memset(payload_read, 0xAA, sizeof(payload_read));
5375 : 4 : iov_read[0].iov_base = payload_read;
5376 : 4 : iov_read[0].iov_len = 3 * BLOCKLEN;
5377 : 4 : iov_read[1].iov_base = payload_read + 3 * BLOCKLEN;
5378 : 4 : iov_read[1].iov_len = 4 * BLOCKLEN;
5379 : 4 : iov_read[2].iov_base = payload_read + 7 * BLOCKLEN;
5380 : 4 : iov_read[2].iov_len = 3 * BLOCKLEN;
5381 : 4 : spdk_blob_io_readv(blob, channel, iov_read, 3, 250, 10, blob_op_complete, NULL);
5382 : 4 : poll_threads();
5383 : 4 : CU_ASSERT(g_bserrno == 0);
5384 : 4 : CU_ASSERT(memcmp(payload_write, payload_read, 10 * BLOCKLEN) == 0);
5385 : :
5386 : 4 : spdk_bs_free_io_channel(channel);
5387 : 4 : poll_threads();
5388 : :
5389 : 4 : ut_blob_close_and_delete(bs, blob);
5390 : 4 : ut_blob_close_and_delete(bs, snapshot);
5391 : 4 : }
5392 : :
5393 : : /**
5394 : : * Inflate / decouple parent rw unit tests.
5395 : : *
5396 : : * --------------
5397 : : * original blob: 0 1 2 3 4
5398 : : * ,---------+---------+---------+---------+---------.
5399 : : * snapshot |xxxxxxxxx|xxxxxxxxx|xxxxxxxxx|xxxxxxxxx| - |
5400 : : * +---------+---------+---------+---------+---------+
5401 : : * snapshot2 | - |yyyyyyyyy| - |yyyyyyyyy| - |
5402 : : * +---------+---------+---------+---------+---------+
5403 : : * blob | - |zzzzzzzzz| - | - | - |
5404 : : * '---------+---------+---------+---------+---------'
5405 : : * . . . . . .
5406 : : * -------- . . . . . .
5407 : : * inflate: . . . . . .
5408 : : * ,---------+---------+---------+---------+---------.
5409 : : * blob |xxxxxxxxx|zzzzzzzzz|xxxxxxxxx|yyyyyyyyy|000000000|
5410 : : * '---------+---------+---------+---------+---------'
5411 : : *
5412 : : * NOTE: needs to allocate 4 clusters, thin provisioning removed, dependency
5413 : : * on snapshot2 and snapshot removed . . .
5414 : : * . . . . . .
5415 : : * ---------------- . . . . . .
5416 : : * decouple parent: . . . . . .
5417 : : * ,---------+---------+---------+---------+---------.
5418 : : * snapshot |xxxxxxxxx|xxxxxxxxx|xxxxxxxxx|xxxxxxxxx| - |
5419 : : * +---------+---------+---------+---------+---------+
5420 : : * blob | - |zzzzzzzzz| - |yyyyyyyyy| - |
5421 : : * '---------+---------+---------+---------+---------'
5422 : : *
5423 : : * NOTE: needs to allocate 1 cluster, 3 clusters unallocated, dependency
5424 : : * on snapshot2 removed and on snapshot still exists. Snapshot2
5425 : : * should remain a clone of snapshot.
5426 : : */
5427 : : static void
5428 : 8 : _blob_inflate_rw(bool decouple_parent)
5429 : : {
5430 : 8 : struct spdk_blob_store *bs = g_bs;
5431 : : struct spdk_blob *blob, *snapshot, *snapshot2;
5432 : : struct spdk_io_channel *channel;
5433 : : struct spdk_blob_opts opts;
5434 : : spdk_blob_id blobid, snapshotid, snapshot2id;
5435 : : uint64_t free_clusters;
5436 : : uint64_t cluster_size;
5437 : :
5438 : : uint64_t payload_size;
5439 : : uint8_t *payload_read;
5440 : : uint8_t *payload_write;
5441 : : uint8_t *payload_clone;
5442 : :
5443 : : uint64_t pages_per_cluster;
5444 : : uint64_t pages_per_payload;
5445 : :
5446 : : int i;
5447 : : spdk_blob_id ids[2];
5448 : : size_t count;
5449 : :
5450 : 8 : free_clusters = spdk_bs_free_cluster_count(bs);
5451 : 8 : cluster_size = spdk_bs_get_cluster_size(bs);
5452 : 8 : pages_per_cluster = cluster_size / spdk_bs_get_page_size(bs);
5453 : 8 : pages_per_payload = pages_per_cluster * 5;
5454 : :
5455 : 8 : payload_size = cluster_size * 5;
5456 : :
5457 : 8 : payload_read = malloc(payload_size);
5458 [ + - ]: 8 : SPDK_CU_ASSERT_FATAL(payload_read != NULL);
5459 : :
5460 : 8 : payload_write = malloc(payload_size);
5461 [ + - ]: 8 : SPDK_CU_ASSERT_FATAL(payload_write != NULL);
5462 : :
5463 : 8 : payload_clone = malloc(payload_size);
5464 [ + - ]: 8 : SPDK_CU_ASSERT_FATAL(payload_clone != NULL);
5465 : :
5466 : 8 : channel = spdk_bs_alloc_io_channel(bs);
5467 [ + - ]: 8 : SPDK_CU_ASSERT_FATAL(channel != NULL);
5468 : :
5469 : : /* Create blob */
5470 : 8 : ut_spdk_blob_opts_init(&opts);
5471 : 8 : opts.thin_provision = true;
5472 : 8 : opts.num_clusters = 5;
5473 : :
5474 : 8 : blob = ut_blob_create_and_open(bs, &opts);
5475 : 8 : blobid = spdk_blob_get_id(blob);
5476 : 8 : CU_ASSERT(free_clusters == spdk_bs_free_cluster_count(bs));
5477 : :
5478 : 8 : CU_ASSERT(spdk_blob_get_num_clusters(blob) == 5);
5479 : :
5480 : : /* 1) Initial read should return zeroed payload */
5481 : 8 : memset(payload_read, 0xFF, payload_size);
5482 : 8 : spdk_blob_io_read(blob, channel, payload_read, 0, pages_per_payload,
5483 : : blob_op_complete, NULL);
5484 : 8 : poll_threads();
5485 : 8 : CU_ASSERT(g_bserrno == 0);
5486 : 8 : CU_ASSERT(spdk_mem_all_zero(payload_read, payload_size));
5487 : :
5488 : : /* Fill whole blob with a pattern, except last cluster (to be sure it
5489 : : * isn't allocated) */
5490 : 8 : memset(payload_write, 0xE5, payload_size - cluster_size);
5491 : 16 : spdk_blob_io_write(blob, channel, payload_write, 0, pages_per_payload -
5492 : 8 : pages_per_cluster, blob_op_complete, NULL);
5493 : 8 : poll_threads();
5494 : 8 : CU_ASSERT(g_bserrno == 0);
5495 : 8 : CU_ASSERT(free_clusters != spdk_bs_free_cluster_count(bs));
5496 : :
5497 : : /* 2) Create snapshot from blob (first level) */
5498 : 8 : spdk_bs_create_snapshot(bs, blobid, NULL, blob_op_with_id_complete, NULL);
5499 : 8 : poll_threads();
5500 : 8 : CU_ASSERT(g_bserrno == 0);
5501 : 8 : CU_ASSERT(g_blobid != SPDK_BLOBID_INVALID);
5502 : 8 : snapshotid = g_blobid;
5503 : :
5504 : 8 : spdk_bs_open_blob(bs, snapshotid, blob_op_with_handle_complete, NULL);
5505 : 8 : poll_threads();
5506 : 8 : CU_ASSERT(g_bserrno == 0);
5507 [ + - ]: 8 : SPDK_CU_ASSERT_FATAL(g_blob != NULL);
5508 : 8 : snapshot = g_blob;
5509 : 8 : CU_ASSERT(snapshot->data_ro == true);
5510 : 8 : CU_ASSERT(snapshot->md_ro == true);
5511 : :
5512 : 8 : CU_ASSERT(spdk_blob_get_num_clusters(snapshot) == 5);
5513 : :
5514 : : /* Write every second cluster with a pattern.
5515 : : *
5516 : : * Last cluster shouldn't be written, to be sure that snapshot nor clone
5517 : : * doesn't allocate it.
5518 : : *
5519 : : * payload_clone stores expected result on "blob" read at the time and
5520 : : * is used only to check data consistency on clone before and after
5521 : : * inflation. Initially we fill it with a backing snapshots pattern
5522 : : * used before.
5523 : : */
5524 : 8 : memset(payload_clone, 0xE5, payload_size - cluster_size);
5525 : 8 : memset(payload_clone + payload_size - cluster_size, 0x00, cluster_size);
5526 : 8 : memset(payload_write, 0xAA, payload_size);
5527 [ + + ]: 24 : for (i = 1; i < 5; i += 2) {
5528 : 32 : spdk_blob_io_write(blob, channel, payload_write, i * pages_per_cluster,
5529 : 16 : pages_per_cluster, blob_op_complete, NULL);
5530 : 16 : poll_threads();
5531 : 16 : CU_ASSERT(g_bserrno == 0);
5532 : :
5533 : : /* Update expected result */
5534 : 32 : memcpy(payload_clone + (cluster_size * i), payload_write,
5535 : 16 : cluster_size);
5536 : 16 : }
5537 : 8 : CU_ASSERT(free_clusters != spdk_bs_free_cluster_count(bs));
5538 : :
5539 : : /* Check data consistency on clone */
5540 : 8 : memset(payload_read, 0xFF, payload_size);
5541 : 8 : spdk_blob_io_read(blob, channel, payload_read, 0, pages_per_payload,
5542 : : blob_op_complete, NULL);
5543 : 8 : poll_threads();
5544 : 8 : CU_ASSERT(g_bserrno == 0);
5545 : 8 : CU_ASSERT(memcmp(payload_clone, payload_read, payload_size) == 0);
5546 : :
5547 : : /* 3) Create second levels snapshot from blob */
5548 : 8 : spdk_bs_create_snapshot(bs, blobid, NULL, blob_op_with_id_complete, NULL);
5549 : 8 : poll_threads();
5550 : 8 : CU_ASSERT(g_bserrno == 0);
5551 : 8 : CU_ASSERT(g_blobid != SPDK_BLOBID_INVALID);
5552 : 8 : snapshot2id = g_blobid;
5553 : :
5554 : 8 : spdk_bs_open_blob(bs, snapshot2id, blob_op_with_handle_complete, NULL);
5555 : 8 : poll_threads();
5556 : 8 : CU_ASSERT(g_bserrno == 0);
5557 [ + - ]: 8 : SPDK_CU_ASSERT_FATAL(g_blob != NULL);
5558 : 8 : snapshot2 = g_blob;
5559 : 8 : CU_ASSERT(snapshot2->data_ro == true);
5560 : 8 : CU_ASSERT(snapshot2->md_ro == true);
5561 : :
5562 : 8 : CU_ASSERT(spdk_blob_get_num_clusters(snapshot2) == 5);
5563 : :
5564 : 8 : CU_ASSERT(snapshot2->parent_id == snapshotid);
5565 : :
5566 : : /* Write one cluster on the top level blob. This cluster (1) covers
5567 : : * already allocated cluster in the snapshot2, so shouldn't be inflated
5568 : : * at all */
5569 : 16 : spdk_blob_io_write(blob, channel, payload_write, pages_per_cluster,
5570 : 8 : pages_per_cluster, blob_op_complete, NULL);
5571 : 8 : poll_threads();
5572 : 8 : CU_ASSERT(g_bserrno == 0);
5573 : :
5574 : : /* Update expected result */
5575 : 8 : memcpy(payload_clone + cluster_size, payload_write, cluster_size);
5576 : :
5577 : : /* Check data consistency on clone */
5578 : 8 : memset(payload_read, 0xFF, payload_size);
5579 : 8 : spdk_blob_io_read(blob, channel, payload_read, 0, pages_per_payload,
5580 : : blob_op_complete, NULL);
5581 : 8 : poll_threads();
5582 : 8 : CU_ASSERT(g_bserrno == 0);
5583 : 8 : CU_ASSERT(memcmp(payload_clone, payload_read, payload_size) == 0);
5584 : :
5585 : :
5586 : : /* Close all blobs */
5587 : 8 : spdk_blob_close(blob, blob_op_complete, NULL);
5588 : 8 : poll_threads();
5589 : 8 : CU_ASSERT(g_bserrno == 0);
5590 : :
5591 : 8 : spdk_blob_close(snapshot2, blob_op_complete, NULL);
5592 : 8 : poll_threads();
5593 : 8 : CU_ASSERT(g_bserrno == 0);
5594 : :
5595 : 8 : spdk_blob_close(snapshot, blob_op_complete, NULL);
5596 : 8 : poll_threads();
5597 : 8 : CU_ASSERT(g_bserrno == 0);
5598 : :
5599 : : /* Check snapshot-clone relations */
5600 : 8 : count = 2;
5601 : 8 : CU_ASSERT(spdk_blob_get_clones(bs, snapshotid, ids, &count) == 0);
5602 : 8 : CU_ASSERT(count == 1);
5603 : 8 : CU_ASSERT(ids[0] == snapshot2id);
5604 : :
5605 : 8 : count = 2;
5606 : 8 : CU_ASSERT(spdk_blob_get_clones(bs, snapshot2id, ids, &count) == 0);
5607 : 8 : CU_ASSERT(count == 1);
5608 : 8 : CU_ASSERT(ids[0] == blobid);
5609 : :
5610 : 8 : CU_ASSERT(spdk_blob_get_parent_snapshot(bs, blobid) == snapshot2id);
5611 : :
5612 : 8 : free_clusters = spdk_bs_free_cluster_count(bs);
5613 [ + + ]: 8 : if (!decouple_parent) {
5614 : : /* Do full blob inflation */
5615 : 4 : spdk_bs_inflate_blob(bs, channel, blobid, blob_op_complete, NULL);
5616 : 4 : poll_threads();
5617 : 4 : CU_ASSERT(g_bserrno == 0);
5618 : :
5619 : : /* All clusters should be inflated (except one already allocated
5620 : : * in a top level blob) */
5621 : 4 : CU_ASSERT(spdk_bs_free_cluster_count(bs) == free_clusters - 4);
5622 : :
5623 : : /* Check if relation tree updated correctly */
5624 : 4 : count = 2;
5625 : 4 : CU_ASSERT(spdk_blob_get_clones(bs, snapshotid, ids, &count) == 0);
5626 : :
5627 : : /* snapshotid have one clone */
5628 : 4 : CU_ASSERT(count == 1);
5629 : 4 : CU_ASSERT(ids[0] == snapshot2id);
5630 : :
5631 : : /* snapshot2id have no clones */
5632 : 4 : count = 2;
5633 : 4 : CU_ASSERT(spdk_blob_get_clones(bs, snapshot2id, ids, &count) == 0);
5634 : 4 : CU_ASSERT(count == 0);
5635 : :
5636 : 4 : CU_ASSERT(spdk_blob_get_parent_snapshot(bs, blobid) == SPDK_BLOBID_INVALID);
5637 : 4 : } else {
5638 : : /* Decouple parent of blob */
5639 : 4 : spdk_bs_blob_decouple_parent(bs, channel, blobid, blob_op_complete, NULL);
5640 : 4 : poll_threads();
5641 : 4 : CU_ASSERT(g_bserrno == 0);
5642 : :
5643 : : /* Only one cluster from a parent should be inflated (second one
5644 : : * is covered by a cluster written on a top level blob, and
5645 : : * already allocated) */
5646 : 4 : CU_ASSERT(spdk_bs_free_cluster_count(bs) == free_clusters - 1);
5647 : :
5648 : : /* Check if relation tree updated correctly */
5649 : 4 : count = 2;
5650 : 4 : CU_ASSERT(spdk_blob_get_clones(bs, snapshotid, ids, &count) == 0);
5651 : :
5652 : : /* snapshotid have two clones now */
5653 : 4 : CU_ASSERT(count == 2);
5654 [ - + ]: 4 : CU_ASSERT(ids[0] == blobid || ids[1] == blobid);
5655 [ + - ]: 4 : CU_ASSERT(ids[0] == snapshot2id || ids[1] == snapshot2id);
5656 : :
5657 : : /* snapshot2id have no clones */
5658 : 4 : count = 2;
5659 : 4 : CU_ASSERT(spdk_blob_get_clones(bs, snapshot2id, ids, &count) == 0);
5660 : 4 : CU_ASSERT(count == 0);
5661 : :
5662 : 4 : CU_ASSERT(spdk_blob_get_parent_snapshot(bs, blobid) == snapshotid);
5663 : : }
5664 : :
5665 : : /* Try to delete snapshot2 (should pass) */
5666 : 8 : spdk_bs_delete_blob(bs, snapshot2id, blob_op_complete, NULL);
5667 : 8 : poll_threads();
5668 : 8 : CU_ASSERT(g_bserrno == 0);
5669 : :
5670 : : /* Try to delete base snapshot */
5671 : 8 : spdk_bs_delete_blob(bs, snapshotid, blob_op_complete, NULL);
5672 : 8 : poll_threads();
5673 : 8 : CU_ASSERT(g_bserrno == 0);
5674 : :
5675 : : /* Reopen blob after snapshot deletion */
5676 : 8 : spdk_bs_open_blob(bs, blobid, blob_op_with_handle_complete, NULL);
5677 : 8 : poll_threads();
5678 : 8 : CU_ASSERT(g_bserrno == 0);
5679 [ - + ]: 8 : SPDK_CU_ASSERT_FATAL(g_blob != NULL);
5680 : 8 : blob = g_blob;
5681 : :
5682 : 8 : CU_ASSERT(spdk_blob_get_num_clusters(blob) == 5);
5683 : :
5684 : : /* Check data consistency on inflated blob */
5685 : 8 : memset(payload_read, 0xFF, payload_size);
5686 : 8 : spdk_blob_io_read(blob, channel, payload_read, 0, pages_per_payload,
5687 : : blob_op_complete, NULL);
5688 : 8 : poll_threads();
5689 : 8 : CU_ASSERT(g_bserrno == 0);
5690 : 8 : CU_ASSERT(memcmp(payload_clone, payload_read, payload_size) == 0);
5691 : :
5692 : 8 : spdk_bs_free_io_channel(channel);
5693 : 8 : poll_threads();
5694 : :
5695 : 8 : free(payload_read);
5696 : 8 : free(payload_write);
5697 : 8 : free(payload_clone);
5698 : :
5699 : 8 : ut_blob_close_and_delete(bs, blob);
5700 : 8 : }
5701 : :
5702 : : static void
5703 : 4 : blob_inflate_rw(void)
5704 : : {
5705 : 4 : _blob_inflate_rw(false);
5706 : 4 : _blob_inflate_rw(true);
5707 : 4 : }
5708 : :
5709 : : /**
5710 : : * Snapshot-clones relation test
5711 : : *
5712 : : * snapshot
5713 : : * |
5714 : : * +-----+-----+
5715 : : * | |
5716 : : * blob(ro) snapshot2
5717 : : * | |
5718 : : * clone2 clone
5719 : : */
5720 : : static void
5721 : 4 : blob_relations(void)
5722 : : {
5723 : : struct spdk_blob_store *bs;
5724 : : struct spdk_bs_dev *dev;
5725 : : struct spdk_bs_opts bs_opts;
5726 : : struct spdk_blob_opts opts;
5727 : : struct spdk_blob *blob, *snapshot, *snapshot2, *clone, *clone2;
5728 : : spdk_blob_id blobid, cloneid, snapshotid, cloneid2, snapshotid2;
5729 : : int rc;
5730 : : size_t count;
5731 : 4 : spdk_blob_id ids[10] = {};
5732 : :
5733 : 4 : dev = init_dev();
5734 : 4 : spdk_bs_opts_init(&bs_opts, sizeof(bs_opts));
5735 : 4 : snprintf(bs_opts.bstype.bstype, sizeof(bs_opts.bstype.bstype), "TESTTYPE");
5736 : :
5737 : 4 : spdk_bs_init(dev, &bs_opts, bs_op_with_handle_complete, NULL);
5738 : 4 : poll_threads();
5739 : 4 : CU_ASSERT(g_bserrno == 0);
5740 [ + - ]: 4 : SPDK_CU_ASSERT_FATAL(g_bs != NULL);
5741 : 4 : bs = g_bs;
5742 : :
5743 : : /* 1. Create blob with 10 clusters */
5744 : :
5745 : 4 : ut_spdk_blob_opts_init(&opts);
5746 : 4 : opts.num_clusters = 10;
5747 : :
5748 : 4 : blob = ut_blob_create_and_open(bs, &opts);
5749 : 4 : blobid = spdk_blob_get_id(blob);
5750 : :
5751 : 4 : CU_ASSERT(!spdk_blob_is_read_only(blob));
5752 : 4 : CU_ASSERT(!spdk_blob_is_snapshot(blob));
5753 : 4 : CU_ASSERT(!spdk_blob_is_clone(blob));
5754 : 4 : CU_ASSERT(!spdk_blob_is_thin_provisioned(blob));
5755 : :
5756 : : /* blob should not have underlying snapshot nor clones */
5757 : 4 : CU_ASSERT(blob->parent_id == SPDK_BLOBID_INVALID);
5758 : 4 : CU_ASSERT(spdk_blob_get_parent_snapshot(bs, blobid) == SPDK_BLOBID_INVALID);
5759 : 4 : count = SPDK_COUNTOF(ids);
5760 : 4 : rc = spdk_blob_get_clones(bs, blobid, ids, &count);
5761 : 4 : CU_ASSERT(rc == 0);
5762 : 4 : CU_ASSERT(count == 0);
5763 : :
5764 : :
5765 : : /* 2. Create snapshot */
5766 : :
5767 : 4 : spdk_bs_create_snapshot(bs, blobid, NULL, blob_op_with_id_complete, NULL);
5768 : 4 : poll_threads();
5769 : 4 : CU_ASSERT(g_bserrno == 0);
5770 : 4 : CU_ASSERT(g_blobid != SPDK_BLOBID_INVALID);
5771 : 4 : snapshotid = g_blobid;
5772 : :
5773 : 4 : spdk_bs_open_blob(bs, snapshotid, blob_op_with_handle_complete, NULL);
5774 : 4 : poll_threads();
5775 : 4 : CU_ASSERT(g_bserrno == 0);
5776 [ + - ]: 4 : SPDK_CU_ASSERT_FATAL(g_blob != NULL);
5777 : 4 : snapshot = g_blob;
5778 : :
5779 : 4 : CU_ASSERT(spdk_blob_is_read_only(snapshot));
5780 : 4 : CU_ASSERT(spdk_blob_is_snapshot(snapshot));
5781 : 4 : CU_ASSERT(!spdk_blob_is_clone(snapshot));
5782 : 4 : CU_ASSERT(snapshot->parent_id == SPDK_BLOBID_INVALID);
5783 : 4 : CU_ASSERT(spdk_blob_get_parent_snapshot(bs, snapshotid) == SPDK_BLOBID_INVALID);
5784 : :
5785 : : /* Check if original blob is converted to the clone of snapshot */
5786 : 4 : CU_ASSERT(!spdk_blob_is_read_only(blob));
5787 : 4 : CU_ASSERT(!spdk_blob_is_snapshot(blob));
5788 : 4 : CU_ASSERT(spdk_blob_is_clone(blob));
5789 : 4 : CU_ASSERT(spdk_blob_is_thin_provisioned(blob));
5790 : 4 : CU_ASSERT(blob->parent_id == snapshotid);
5791 : 4 : CU_ASSERT(spdk_blob_get_parent_snapshot(bs, blobid) == snapshotid);
5792 : :
5793 : 4 : count = SPDK_COUNTOF(ids);
5794 : 4 : rc = spdk_blob_get_clones(bs, snapshotid, ids, &count);
5795 : 4 : CU_ASSERT(rc == 0);
5796 : 4 : CU_ASSERT(count == 1);
5797 : 4 : CU_ASSERT(ids[0] == blobid);
5798 : :
5799 : :
5800 : : /* 3. Create clone from snapshot */
5801 : :
5802 : 4 : spdk_bs_create_clone(bs, snapshotid, NULL, blob_op_with_id_complete, NULL);
5803 : 4 : poll_threads();
5804 : 4 : CU_ASSERT(g_bserrno == 0);
5805 : 4 : CU_ASSERT(g_blobid != SPDK_BLOBID_INVALID);
5806 : 4 : cloneid = g_blobid;
5807 : :
5808 : 4 : spdk_bs_open_blob(bs, cloneid, blob_op_with_handle_complete, NULL);
5809 : 4 : poll_threads();
5810 : 4 : CU_ASSERT(g_bserrno == 0);
5811 [ + - ]: 4 : SPDK_CU_ASSERT_FATAL(g_blob != NULL);
5812 : 4 : clone = g_blob;
5813 : :
5814 : 4 : CU_ASSERT(!spdk_blob_is_read_only(clone));
5815 : 4 : CU_ASSERT(!spdk_blob_is_snapshot(clone));
5816 : 4 : CU_ASSERT(spdk_blob_is_clone(clone));
5817 : 4 : CU_ASSERT(spdk_blob_is_thin_provisioned(clone));
5818 : 4 : CU_ASSERT(clone->parent_id == snapshotid);
5819 : 4 : CU_ASSERT(spdk_blob_get_parent_snapshot(bs, cloneid) == snapshotid);
5820 : :
5821 : 4 : count = SPDK_COUNTOF(ids);
5822 : 4 : rc = spdk_blob_get_clones(bs, cloneid, ids, &count);
5823 : 4 : CU_ASSERT(rc == 0);
5824 : 4 : CU_ASSERT(count == 0);
5825 : :
5826 : : /* Check if clone is on the snapshot's list */
5827 : 4 : count = SPDK_COUNTOF(ids);
5828 : 4 : rc = spdk_blob_get_clones(bs, snapshotid, ids, &count);
5829 : 4 : CU_ASSERT(rc == 0);
5830 [ + - ]: 4 : CU_ASSERT(ids[0] == blobid || ids[1] == blobid);
5831 [ - + ]: 4 : CU_ASSERT(ids[0] == cloneid || ids[1] == cloneid);
5832 : :
5833 : :
5834 : : /* 4. Create snapshot of the clone */
5835 : :
5836 : 4 : spdk_bs_create_snapshot(bs, cloneid, NULL, blob_op_with_id_complete, NULL);
5837 : 4 : poll_threads();
5838 : 4 : CU_ASSERT(g_bserrno == 0);
5839 : 4 : CU_ASSERT(g_blobid != SPDK_BLOBID_INVALID);
5840 : 4 : snapshotid2 = g_blobid;
5841 : :
5842 : 4 : spdk_bs_open_blob(bs, snapshotid2, blob_op_with_handle_complete, NULL);
5843 : 4 : poll_threads();
5844 : 4 : CU_ASSERT(g_bserrno == 0);
5845 [ + - ]: 4 : SPDK_CU_ASSERT_FATAL(g_blob != NULL);
5846 : 4 : snapshot2 = g_blob;
5847 : :
5848 : 4 : CU_ASSERT(spdk_blob_is_read_only(snapshot2));
5849 : 4 : CU_ASSERT(spdk_blob_is_snapshot(snapshot2));
5850 : 4 : CU_ASSERT(spdk_blob_is_clone(snapshot2));
5851 : 4 : CU_ASSERT(snapshot2->parent_id == snapshotid);
5852 : 4 : CU_ASSERT(spdk_blob_get_parent_snapshot(bs, snapshotid2) == snapshotid);
5853 : :
5854 : : /* Check if clone is converted to the clone of snapshot2 and snapshot2
5855 : : * is a child of snapshot */
5856 : 4 : CU_ASSERT(!spdk_blob_is_read_only(clone));
5857 : 4 : CU_ASSERT(!spdk_blob_is_snapshot(clone));
5858 : 4 : CU_ASSERT(spdk_blob_is_clone(clone));
5859 : 4 : CU_ASSERT(spdk_blob_is_thin_provisioned(clone));
5860 : 4 : CU_ASSERT(clone->parent_id == snapshotid2);
5861 : 4 : CU_ASSERT(spdk_blob_get_parent_snapshot(bs, cloneid) == snapshotid2);
5862 : :
5863 : 4 : count = SPDK_COUNTOF(ids);
5864 : 4 : rc = spdk_blob_get_clones(bs, snapshotid2, ids, &count);
5865 : 4 : CU_ASSERT(rc == 0);
5866 : 4 : CU_ASSERT(count == 1);
5867 : 4 : CU_ASSERT(ids[0] == cloneid);
5868 : :
5869 : :
5870 : : /* 5. Try to create clone from read only blob */
5871 : :
5872 : : /* Mark blob as read only */
5873 : 4 : spdk_blob_set_read_only(blob);
5874 : 4 : spdk_blob_sync_md(blob, blob_op_complete, NULL);
5875 : 4 : poll_threads();
5876 : 4 : CU_ASSERT(g_bserrno == 0);
5877 : :
5878 : : /* Check if previously created blob is read only clone */
5879 : 4 : CU_ASSERT(spdk_blob_is_read_only(blob));
5880 : 4 : CU_ASSERT(!spdk_blob_is_snapshot(blob));
5881 : 4 : CU_ASSERT(spdk_blob_is_clone(blob));
5882 : 4 : CU_ASSERT(spdk_blob_is_thin_provisioned(blob));
5883 : :
5884 : : /* Create clone from read only blob */
5885 : 4 : spdk_bs_create_clone(bs, blobid, NULL, blob_op_with_id_complete, NULL);
5886 : 4 : poll_threads();
5887 : 4 : CU_ASSERT(g_bserrno == 0);
5888 : 4 : CU_ASSERT(g_blobid != SPDK_BLOBID_INVALID);
5889 : 4 : cloneid2 = g_blobid;
5890 : :
5891 : 4 : spdk_bs_open_blob(bs, cloneid2, blob_op_with_handle_complete, NULL);
5892 : 4 : poll_threads();
5893 : 4 : CU_ASSERT(g_bserrno == 0);
5894 [ - + ]: 4 : SPDK_CU_ASSERT_FATAL(g_blob != NULL);
5895 : 4 : clone2 = g_blob;
5896 : :
5897 : 4 : CU_ASSERT(!spdk_blob_is_read_only(clone2));
5898 : 4 : CU_ASSERT(!spdk_blob_is_snapshot(clone2));
5899 : 4 : CU_ASSERT(spdk_blob_is_clone(clone2));
5900 : 4 : CU_ASSERT(spdk_blob_is_thin_provisioned(clone2));
5901 : :
5902 : 4 : CU_ASSERT(spdk_blob_get_parent_snapshot(bs, cloneid2) == blobid);
5903 : :
5904 : 4 : count = SPDK_COUNTOF(ids);
5905 : 4 : rc = spdk_blob_get_clones(bs, blobid, ids, &count);
5906 : 4 : CU_ASSERT(rc == 0);
5907 : :
5908 : 4 : CU_ASSERT(count == 1);
5909 : 4 : CU_ASSERT(ids[0] == cloneid2);
5910 : :
5911 : : /* Close blobs */
5912 : :
5913 : 4 : spdk_blob_close(clone2, blob_op_complete, NULL);
5914 : 4 : poll_threads();
5915 : 4 : CU_ASSERT(g_bserrno == 0);
5916 : :
5917 : 4 : spdk_blob_close(blob, blob_op_complete, NULL);
5918 : 4 : poll_threads();
5919 : 4 : CU_ASSERT(g_bserrno == 0);
5920 : :
5921 : 4 : spdk_blob_close(clone, blob_op_complete, NULL);
5922 : 4 : poll_threads();
5923 : 4 : CU_ASSERT(g_bserrno == 0);
5924 : :
5925 : 4 : spdk_blob_close(snapshot, blob_op_complete, NULL);
5926 : 4 : poll_threads();
5927 : 4 : CU_ASSERT(g_bserrno == 0);
5928 : :
5929 : 4 : spdk_blob_close(snapshot2, blob_op_complete, NULL);
5930 : 4 : poll_threads();
5931 : 4 : CU_ASSERT(g_bserrno == 0);
5932 : :
5933 : : /* Try to delete snapshot with more than 1 clone */
5934 : 4 : spdk_bs_delete_blob(bs, snapshotid, blob_op_complete, NULL);
5935 : 4 : poll_threads();
5936 : 4 : CU_ASSERT(g_bserrno != 0);
5937 : :
5938 : 4 : ut_bs_reload(&bs, &bs_opts);
5939 : :
5940 : : /* NULL ids array should return number of clones in count */
5941 : 4 : count = SPDK_COUNTOF(ids);
5942 : 4 : rc = spdk_blob_get_clones(bs, snapshotid, NULL, &count);
5943 : 4 : CU_ASSERT(rc == -ENOMEM);
5944 : 4 : CU_ASSERT(count == 2);
5945 : :
5946 : : /* incorrect array size */
5947 : 4 : count = 1;
5948 : 4 : rc = spdk_blob_get_clones(bs, snapshotid, ids, &count);
5949 : 4 : CU_ASSERT(rc == -ENOMEM);
5950 : 4 : CU_ASSERT(count == 2);
5951 : :
5952 : :
5953 : : /* Verify structure of loaded blob store */
5954 : :
5955 : : /* snapshot */
5956 : 4 : CU_ASSERT(spdk_blob_get_parent_snapshot(bs, snapshotid) == SPDK_BLOBID_INVALID);
5957 : :
5958 : 4 : count = SPDK_COUNTOF(ids);
5959 : 4 : rc = spdk_blob_get_clones(bs, snapshotid, ids, &count);
5960 : 4 : CU_ASSERT(rc == 0);
5961 : 4 : CU_ASSERT(count == 2);
5962 [ + - ]: 4 : CU_ASSERT(ids[0] == blobid || ids[1] == blobid);
5963 [ - + ]: 4 : CU_ASSERT(ids[0] == snapshotid2 || ids[1] == snapshotid2);
5964 : :
5965 : : /* blob */
5966 : 4 : CU_ASSERT(spdk_blob_get_parent_snapshot(bs, blobid) == snapshotid);
5967 : 4 : count = SPDK_COUNTOF(ids);
5968 : 4 : rc = spdk_blob_get_clones(bs, blobid, ids, &count);
5969 : 4 : CU_ASSERT(rc == 0);
5970 : 4 : CU_ASSERT(count == 1);
5971 : 4 : CU_ASSERT(ids[0] == cloneid2);
5972 : :
5973 : : /* clone */
5974 : 4 : CU_ASSERT(spdk_blob_get_parent_snapshot(bs, cloneid) == snapshotid2);
5975 : 4 : count = SPDK_COUNTOF(ids);
5976 : 4 : rc = spdk_blob_get_clones(bs, cloneid, ids, &count);
5977 : 4 : CU_ASSERT(rc == 0);
5978 : 4 : CU_ASSERT(count == 0);
5979 : :
5980 : : /* snapshot2 */
5981 : 4 : CU_ASSERT(spdk_blob_get_parent_snapshot(bs, snapshotid2) == snapshotid);
5982 : 4 : count = SPDK_COUNTOF(ids);
5983 : 4 : rc = spdk_blob_get_clones(bs, snapshotid2, ids, &count);
5984 : 4 : CU_ASSERT(rc == 0);
5985 : 4 : CU_ASSERT(count == 1);
5986 : 4 : CU_ASSERT(ids[0] == cloneid);
5987 : :
5988 : : /* clone2 */
5989 : 4 : CU_ASSERT(spdk_blob_get_parent_snapshot(bs, cloneid2) == blobid);
5990 : 4 : count = SPDK_COUNTOF(ids);
5991 : 4 : rc = spdk_blob_get_clones(bs, cloneid2, ids, &count);
5992 : 4 : CU_ASSERT(rc == 0);
5993 : 4 : CU_ASSERT(count == 0);
5994 : :
5995 : : /* Try to delete blob that user should not be able to remove */
5996 : :
5997 : 4 : spdk_bs_delete_blob(bs, snapshotid, blob_op_complete, NULL);
5998 : 4 : poll_threads();
5999 : 4 : CU_ASSERT(g_bserrno != 0);
6000 : :
6001 : : /* Remove all blobs */
6002 : :
6003 : 4 : spdk_bs_delete_blob(bs, cloneid, blob_op_complete, NULL);
6004 : 4 : poll_threads();
6005 : 4 : CU_ASSERT(g_bserrno == 0);
6006 : :
6007 : 4 : spdk_bs_delete_blob(bs, snapshotid2, blob_op_complete, NULL);
6008 : 4 : poll_threads();
6009 : 4 : CU_ASSERT(g_bserrno == 0);
6010 : :
6011 : 4 : spdk_bs_delete_blob(bs, cloneid2, blob_op_complete, NULL);
6012 : 4 : poll_threads();
6013 : 4 : CU_ASSERT(g_bserrno == 0);
6014 : :
6015 : 4 : spdk_bs_delete_blob(bs, blobid, blob_op_complete, NULL);
6016 : 4 : poll_threads();
6017 : 4 : CU_ASSERT(g_bserrno == 0);
6018 : :
6019 : 4 : spdk_bs_delete_blob(bs, snapshotid, blob_op_complete, NULL);
6020 : 4 : poll_threads();
6021 : 4 : CU_ASSERT(g_bserrno == 0);
6022 : :
6023 : 4 : spdk_bs_unload(bs, bs_op_complete, NULL);
6024 : 4 : poll_threads();
6025 : 4 : CU_ASSERT(g_bserrno == 0);
6026 : :
6027 : 4 : g_bs = NULL;
6028 : 4 : }
6029 : :
6030 : : /**
6031 : : * Snapshot-clones relation test 2
6032 : : *
6033 : : * snapshot1
6034 : : * |
6035 : : * snapshot2
6036 : : * |
6037 : : * +-----+-----+
6038 : : * | |
6039 : : * blob(ro) snapshot3
6040 : : * | |
6041 : : * | snapshot4
6042 : : * | | |
6043 : : * clone2 clone clone3
6044 : : */
6045 : : static void
6046 : 4 : blob_relations2(void)
6047 : : {
6048 : : struct spdk_blob_store *bs;
6049 : : struct spdk_bs_dev *dev;
6050 : : struct spdk_bs_opts bs_opts;
6051 : : struct spdk_blob_opts opts;
6052 : : struct spdk_blob *blob, *snapshot1, *snapshot2, *snapshot3, *snapshot4, *clone, *clone2;
6053 : : spdk_blob_id blobid, snapshotid1, snapshotid2, snapshotid3, snapshotid4, cloneid, cloneid2,
6054 : : cloneid3;
6055 : : int rc;
6056 : : size_t count;
6057 : 4 : spdk_blob_id ids[10] = {};
6058 : :
6059 : 4 : dev = init_dev();
6060 : 4 : spdk_bs_opts_init(&bs_opts, sizeof(bs_opts));
6061 : 4 : snprintf(bs_opts.bstype.bstype, sizeof(bs_opts.bstype.bstype), "TESTTYPE");
6062 : :
6063 : 4 : spdk_bs_init(dev, &bs_opts, bs_op_with_handle_complete, NULL);
6064 : 4 : poll_threads();
6065 : 4 : CU_ASSERT(g_bserrno == 0);
6066 [ + - ]: 4 : SPDK_CU_ASSERT_FATAL(g_bs != NULL);
6067 : 4 : bs = g_bs;
6068 : :
6069 : : /* 1. Create blob with 10 clusters */
6070 : :
6071 : 4 : ut_spdk_blob_opts_init(&opts);
6072 : 4 : opts.num_clusters = 10;
6073 : :
6074 : 4 : blob = ut_blob_create_and_open(bs, &opts);
6075 : 4 : blobid = spdk_blob_get_id(blob);
6076 : :
6077 : : /* 2. Create snapshot1 */
6078 : :
6079 : 4 : spdk_bs_create_snapshot(bs, blobid, NULL, blob_op_with_id_complete, NULL);
6080 : 4 : poll_threads();
6081 : 4 : CU_ASSERT(g_bserrno == 0);
6082 : 4 : CU_ASSERT(g_blobid != SPDK_BLOBID_INVALID);
6083 : 4 : snapshotid1 = g_blobid;
6084 : :
6085 : 4 : spdk_bs_open_blob(bs, snapshotid1, blob_op_with_handle_complete, NULL);
6086 : 4 : poll_threads();
6087 : 4 : CU_ASSERT(g_bserrno == 0);
6088 [ + - ]: 4 : SPDK_CU_ASSERT_FATAL(g_blob != NULL);
6089 : 4 : snapshot1 = g_blob;
6090 : :
6091 : 4 : CU_ASSERT(snapshot1->parent_id == SPDK_BLOBID_INVALID);
6092 : 4 : CU_ASSERT(spdk_blob_get_parent_snapshot(bs, snapshotid1) == SPDK_BLOBID_INVALID);
6093 : :
6094 : 4 : CU_ASSERT(blob->parent_id == snapshotid1);
6095 : 4 : CU_ASSERT(spdk_blob_get_parent_snapshot(bs, blobid) == snapshotid1);
6096 : :
6097 : : /* Check if blob is the clone of snapshot1 */
6098 : 4 : CU_ASSERT(blob->parent_id == snapshotid1);
6099 : 4 : CU_ASSERT(spdk_blob_get_parent_snapshot(bs, blobid) == snapshotid1);
6100 : :
6101 : 4 : count = SPDK_COUNTOF(ids);
6102 : 4 : rc = spdk_blob_get_clones(bs, snapshotid1, ids, &count);
6103 : 4 : CU_ASSERT(rc == 0);
6104 : 4 : CU_ASSERT(count == 1);
6105 : 4 : CU_ASSERT(ids[0] == blobid);
6106 : :
6107 : : /* 3. Create another snapshot */
6108 : :
6109 : 4 : spdk_bs_create_snapshot(bs, blobid, NULL, blob_op_with_id_complete, NULL);
6110 : 4 : poll_threads();
6111 : 4 : CU_ASSERT(g_bserrno == 0);
6112 : 4 : CU_ASSERT(g_blobid != SPDK_BLOBID_INVALID);
6113 : 4 : snapshotid2 = g_blobid;
6114 : :
6115 : 4 : spdk_bs_open_blob(bs, snapshotid2, blob_op_with_handle_complete, NULL);
6116 : 4 : poll_threads();
6117 : 4 : CU_ASSERT(g_bserrno == 0);
6118 [ + - ]: 4 : SPDK_CU_ASSERT_FATAL(g_blob != NULL);
6119 : 4 : snapshot2 = g_blob;
6120 : :
6121 : 4 : CU_ASSERT(spdk_blob_is_clone(snapshot2));
6122 : 4 : CU_ASSERT(snapshot2->parent_id == snapshotid1);
6123 : 4 : CU_ASSERT(spdk_blob_get_parent_snapshot(bs, snapshotid2) == snapshotid1);
6124 : :
6125 : : /* Check if snapshot2 is the clone of snapshot1 and blob
6126 : : * is a child of snapshot2 */
6127 : 4 : CU_ASSERT(blob->parent_id == snapshotid2);
6128 : 4 : CU_ASSERT(spdk_blob_get_parent_snapshot(bs, blobid) == snapshotid2);
6129 : :
6130 : 4 : count = SPDK_COUNTOF(ids);
6131 : 4 : rc = spdk_blob_get_clones(bs, snapshotid2, ids, &count);
6132 : 4 : CU_ASSERT(rc == 0);
6133 : 4 : CU_ASSERT(count == 1);
6134 : 4 : CU_ASSERT(ids[0] == blobid);
6135 : :
6136 : : /* 4. Create clone from snapshot */
6137 : :
6138 : 4 : spdk_bs_create_clone(bs, snapshotid2, NULL, blob_op_with_id_complete, NULL);
6139 : 4 : poll_threads();
6140 : 4 : CU_ASSERT(g_bserrno == 0);
6141 : 4 : CU_ASSERT(g_blobid != SPDK_BLOBID_INVALID);
6142 : 4 : cloneid = g_blobid;
6143 : :
6144 : 4 : spdk_bs_open_blob(bs, cloneid, blob_op_with_handle_complete, NULL);
6145 : 4 : poll_threads();
6146 : 4 : CU_ASSERT(g_bserrno == 0);
6147 [ + - ]: 4 : SPDK_CU_ASSERT_FATAL(g_blob != NULL);
6148 : 4 : clone = g_blob;
6149 : :
6150 : 4 : CU_ASSERT(clone->parent_id == snapshotid2);
6151 : 4 : CU_ASSERT(spdk_blob_get_parent_snapshot(bs, cloneid) == snapshotid2);
6152 : :
6153 : : /* Check if clone is on the snapshot's list */
6154 : 4 : count = SPDK_COUNTOF(ids);
6155 : 4 : rc = spdk_blob_get_clones(bs, snapshotid2, ids, &count);
6156 : 4 : CU_ASSERT(rc == 0);
6157 : 4 : CU_ASSERT(count == 2);
6158 [ + - ]: 4 : CU_ASSERT(ids[0] == blobid || ids[1] == blobid);
6159 [ - + ]: 4 : CU_ASSERT(ids[0] == cloneid || ids[1] == cloneid);
6160 : :
6161 : : /* 5. Create snapshot of the clone */
6162 : :
6163 : 4 : spdk_bs_create_snapshot(bs, cloneid, NULL, blob_op_with_id_complete, NULL);
6164 : 4 : poll_threads();
6165 : 4 : CU_ASSERT(g_bserrno == 0);
6166 : 4 : CU_ASSERT(g_blobid != SPDK_BLOBID_INVALID);
6167 : 4 : snapshotid3 = g_blobid;
6168 : :
6169 : 4 : spdk_bs_open_blob(bs, snapshotid3, blob_op_with_handle_complete, NULL);
6170 : 4 : poll_threads();
6171 : 4 : CU_ASSERT(g_bserrno == 0);
6172 [ + - ]: 4 : SPDK_CU_ASSERT_FATAL(g_blob != NULL);
6173 : 4 : snapshot3 = g_blob;
6174 : :
6175 : 4 : CU_ASSERT(snapshot3->parent_id == snapshotid2);
6176 : 4 : CU_ASSERT(spdk_blob_get_parent_snapshot(bs, snapshotid3) == snapshotid2);
6177 : :
6178 : : /* Check if clone is converted to the clone of snapshot3 and snapshot3
6179 : : * is a child of snapshot2 */
6180 : 4 : CU_ASSERT(clone->parent_id == snapshotid3);
6181 : 4 : CU_ASSERT(spdk_blob_get_parent_snapshot(bs, cloneid) == snapshotid3);
6182 : :
6183 : 4 : count = SPDK_COUNTOF(ids);
6184 : 4 : rc = spdk_blob_get_clones(bs, snapshotid3, ids, &count);
6185 : 4 : CU_ASSERT(rc == 0);
6186 : 4 : CU_ASSERT(count == 1);
6187 : 4 : CU_ASSERT(ids[0] == cloneid);
6188 : :
6189 : : /* 6. Create another snapshot of the clone */
6190 : :
6191 : 4 : spdk_bs_create_snapshot(bs, cloneid, NULL, blob_op_with_id_complete, NULL);
6192 : 4 : poll_threads();
6193 : 4 : CU_ASSERT(g_bserrno == 0);
6194 : 4 : CU_ASSERT(g_blobid != SPDK_BLOBID_INVALID);
6195 : 4 : snapshotid4 = g_blobid;
6196 : :
6197 : 4 : spdk_bs_open_blob(bs, snapshotid4, blob_op_with_handle_complete, NULL);
6198 : 4 : poll_threads();
6199 : 4 : CU_ASSERT(g_bserrno == 0);
6200 [ + - ]: 4 : SPDK_CU_ASSERT_FATAL(g_blob != NULL);
6201 : 4 : snapshot4 = g_blob;
6202 : :
6203 : 4 : CU_ASSERT(snapshot4->parent_id == snapshotid3);
6204 : 4 : CU_ASSERT(spdk_blob_get_parent_snapshot(bs, snapshotid4) == snapshotid3);
6205 : :
6206 : : /* Check if clone is converted to the clone of snapshot4 and snapshot4
6207 : : * is a child of snapshot3 */
6208 : 4 : CU_ASSERT(clone->parent_id == snapshotid4);
6209 : 4 : CU_ASSERT(spdk_blob_get_parent_snapshot(bs, cloneid) == snapshotid4);
6210 : :
6211 : 4 : count = SPDK_COUNTOF(ids);
6212 : 4 : rc = spdk_blob_get_clones(bs, snapshotid4, ids, &count);
6213 : 4 : CU_ASSERT(rc == 0);
6214 : 4 : CU_ASSERT(count == 1);
6215 : 4 : CU_ASSERT(ids[0] == cloneid);
6216 : :
6217 : : /* 7. Remove snapshot 4 */
6218 : :
6219 : 4 : ut_blob_close_and_delete(bs, snapshot4);
6220 : :
6221 : : /* Check if relations are back to state from before creating snapshot 4 */
6222 : 4 : CU_ASSERT(clone->parent_id == snapshotid3);
6223 : 4 : CU_ASSERT(spdk_blob_get_parent_snapshot(bs, cloneid) == snapshotid3);
6224 : :
6225 : 4 : count = SPDK_COUNTOF(ids);
6226 : 4 : rc = spdk_blob_get_clones(bs, snapshotid3, ids, &count);
6227 : 4 : CU_ASSERT(rc == 0);
6228 : 4 : CU_ASSERT(count == 1);
6229 : 4 : CU_ASSERT(ids[0] == cloneid);
6230 : :
6231 : : /* 8. Create second clone of snapshot 3 and try to remove snapshot 3 */
6232 : :
6233 : 4 : spdk_bs_create_clone(bs, snapshotid3, NULL, blob_op_with_id_complete, NULL);
6234 : 4 : poll_threads();
6235 : 4 : CU_ASSERT(g_bserrno == 0);
6236 : 4 : CU_ASSERT(g_blobid != SPDK_BLOBID_INVALID);
6237 : 4 : cloneid3 = g_blobid;
6238 : :
6239 : 4 : spdk_bs_delete_blob(bs, snapshotid3, blob_op_complete, NULL);
6240 : 4 : poll_threads();
6241 : 4 : CU_ASSERT(g_bserrno != 0);
6242 : :
6243 : : /* 9. Open snapshot 3 again and try to remove it while clone 3 is closed */
6244 : :
6245 : 4 : spdk_bs_open_blob(bs, snapshotid3, blob_op_with_handle_complete, NULL);
6246 : 4 : poll_threads();
6247 : 4 : CU_ASSERT(g_bserrno == 0);
6248 [ + - ]: 4 : SPDK_CU_ASSERT_FATAL(g_blob != NULL);
6249 : 4 : snapshot3 = g_blob;
6250 : :
6251 : 4 : spdk_bs_delete_blob(bs, snapshotid3, blob_op_complete, NULL);
6252 : 4 : poll_threads();
6253 : 4 : CU_ASSERT(g_bserrno != 0);
6254 : :
6255 : 4 : spdk_blob_close(snapshot3, blob_op_complete, NULL);
6256 : 4 : poll_threads();
6257 : 4 : CU_ASSERT(g_bserrno == 0);
6258 : :
6259 : 4 : spdk_bs_delete_blob(bs, cloneid3, blob_op_complete, NULL);
6260 : 4 : poll_threads();
6261 : 4 : CU_ASSERT(g_bserrno == 0);
6262 : :
6263 : : /* 10. Remove snapshot 1 */
6264 : :
6265 : : /* Check snapshot 1 and snapshot 2 allocated clusters */
6266 : 4 : CU_ASSERT(spdk_blob_get_num_allocated_clusters(snapshot1) == 10);
6267 : 4 : CU_ASSERT(spdk_blob_get_num_allocated_clusters(snapshot2) == 0);
6268 : :
6269 : 4 : ut_blob_close_and_delete(bs, snapshot1);
6270 : :
6271 : : /* Check if relations are back to state from before creating snapshot 4 (before step 6) */
6272 : 4 : CU_ASSERT(snapshot2->parent_id == SPDK_BLOBID_INVALID);
6273 : 4 : CU_ASSERT(spdk_blob_get_parent_snapshot(bs, snapshotid2) == SPDK_BLOBID_INVALID);
6274 : :
6275 : : /* Check that snapshot 2 has the clusters that were allocated to snapshot 1 */
6276 : 4 : CU_ASSERT(spdk_blob_get_num_allocated_clusters(snapshot2) == 10);
6277 : :
6278 : 4 : count = SPDK_COUNTOF(ids);
6279 : 4 : rc = spdk_blob_get_clones(bs, snapshotid2, ids, &count);
6280 : 4 : CU_ASSERT(rc == 0);
6281 : 4 : CU_ASSERT(count == 2);
6282 [ + - ]: 4 : CU_ASSERT(ids[0] == blobid || ids[1] == blobid);
6283 [ - + ]: 4 : CU_ASSERT(ids[0] == snapshotid3 || ids[1] == snapshotid3);
6284 : :
6285 : : /* 11. Try to create clone from read only blob */
6286 : :
6287 : : /* Mark blob as read only */
6288 : 4 : spdk_blob_set_read_only(blob);
6289 : 4 : spdk_blob_sync_md(blob, blob_op_complete, NULL);
6290 : 4 : poll_threads();
6291 : 4 : CU_ASSERT(g_bserrno == 0);
6292 : :
6293 : : /* Create clone from read only blob */
6294 : 4 : spdk_bs_create_clone(bs, blobid, NULL, blob_op_with_id_complete, NULL);
6295 : 4 : poll_threads();
6296 : 4 : CU_ASSERT(g_bserrno == 0);
6297 : 4 : CU_ASSERT(g_blobid != SPDK_BLOBID_INVALID);
6298 : 4 : cloneid2 = g_blobid;
6299 : :
6300 : 4 : spdk_bs_open_blob(bs, cloneid2, blob_op_with_handle_complete, NULL);
6301 : 4 : poll_threads();
6302 : 4 : CU_ASSERT(g_bserrno == 0);
6303 [ - + ]: 4 : SPDK_CU_ASSERT_FATAL(g_blob != NULL);
6304 : 4 : clone2 = g_blob;
6305 : :
6306 : 4 : CU_ASSERT(spdk_blob_get_parent_snapshot(bs, cloneid2) == blobid);
6307 : :
6308 : 4 : count = SPDK_COUNTOF(ids);
6309 : 4 : rc = spdk_blob_get_clones(bs, blobid, ids, &count);
6310 : 4 : CU_ASSERT(rc == 0);
6311 : 4 : CU_ASSERT(count == 1);
6312 : 4 : CU_ASSERT(ids[0] == cloneid2);
6313 : :
6314 : : /* Close blobs */
6315 : :
6316 : 4 : spdk_blob_close(clone2, blob_op_complete, NULL);
6317 : 4 : poll_threads();
6318 : 4 : CU_ASSERT(g_bserrno == 0);
6319 : :
6320 : 4 : spdk_blob_close(blob, blob_op_complete, NULL);
6321 : 4 : poll_threads();
6322 : 4 : CU_ASSERT(g_bserrno == 0);
6323 : :
6324 : 4 : spdk_blob_close(clone, blob_op_complete, NULL);
6325 : 4 : poll_threads();
6326 : 4 : CU_ASSERT(g_bserrno == 0);
6327 : :
6328 : 4 : spdk_blob_close(snapshot2, blob_op_complete, NULL);
6329 : 4 : poll_threads();
6330 : 4 : CU_ASSERT(g_bserrno == 0);
6331 : :
6332 : 4 : spdk_blob_close(snapshot3, blob_op_complete, NULL);
6333 : 4 : poll_threads();
6334 : 4 : CU_ASSERT(g_bserrno == 0);
6335 : :
6336 : 4 : ut_bs_reload(&bs, &bs_opts);
6337 : :
6338 : : /* Verify structure of loaded blob store */
6339 : :
6340 : : /* snapshot2 */
6341 : 4 : CU_ASSERT(spdk_blob_get_parent_snapshot(bs, snapshotid2) == SPDK_BLOBID_INVALID);
6342 : :
6343 : 4 : count = SPDK_COUNTOF(ids);
6344 : 4 : rc = spdk_blob_get_clones(bs, snapshotid2, ids, &count);
6345 : 4 : CU_ASSERT(rc == 0);
6346 : 4 : CU_ASSERT(count == 2);
6347 [ + - ]: 4 : CU_ASSERT(ids[0] == blobid || ids[1] == blobid);
6348 [ - + ]: 4 : CU_ASSERT(ids[0] == snapshotid3 || ids[1] == snapshotid3);
6349 : :
6350 : : /* blob */
6351 : 4 : CU_ASSERT(spdk_blob_get_parent_snapshot(bs, blobid) == snapshotid2);
6352 : 4 : count = SPDK_COUNTOF(ids);
6353 : 4 : rc = spdk_blob_get_clones(bs, blobid, ids, &count);
6354 : 4 : CU_ASSERT(rc == 0);
6355 : 4 : CU_ASSERT(count == 1);
6356 : 4 : CU_ASSERT(ids[0] == cloneid2);
6357 : :
6358 : : /* clone */
6359 : 4 : CU_ASSERT(spdk_blob_get_parent_snapshot(bs, cloneid) == snapshotid3);
6360 : 4 : count = SPDK_COUNTOF(ids);
6361 : 4 : rc = spdk_blob_get_clones(bs, cloneid, ids, &count);
6362 : 4 : CU_ASSERT(rc == 0);
6363 : 4 : CU_ASSERT(count == 0);
6364 : :
6365 : : /* snapshot3 */
6366 : 4 : CU_ASSERT(spdk_blob_get_parent_snapshot(bs, snapshotid3) == snapshotid2);
6367 : 4 : count = SPDK_COUNTOF(ids);
6368 : 4 : rc = spdk_blob_get_clones(bs, snapshotid3, ids, &count);
6369 : 4 : CU_ASSERT(rc == 0);
6370 : 4 : CU_ASSERT(count == 1);
6371 : 4 : CU_ASSERT(ids[0] == cloneid);
6372 : :
6373 : : /* clone2 */
6374 : 4 : CU_ASSERT(spdk_blob_get_parent_snapshot(bs, cloneid2) == blobid);
6375 : 4 : count = SPDK_COUNTOF(ids);
6376 : 4 : rc = spdk_blob_get_clones(bs, cloneid2, ids, &count);
6377 : 4 : CU_ASSERT(rc == 0);
6378 : 4 : CU_ASSERT(count == 0);
6379 : :
6380 : : /* Try to delete all blobs in the worse possible order */
6381 : :
6382 : 4 : spdk_bs_delete_blob(bs, snapshotid2, blob_op_complete, NULL);
6383 : 4 : poll_threads();
6384 : 4 : CU_ASSERT(g_bserrno != 0);
6385 : :
6386 : 4 : spdk_bs_delete_blob(bs, snapshotid3, blob_op_complete, NULL);
6387 : 4 : poll_threads();
6388 : 4 : CU_ASSERT(g_bserrno == 0);
6389 : :
6390 : 4 : spdk_bs_delete_blob(bs, snapshotid2, blob_op_complete, NULL);
6391 : 4 : poll_threads();
6392 : 4 : CU_ASSERT(g_bserrno != 0);
6393 : :
6394 : 4 : spdk_bs_delete_blob(bs, cloneid, blob_op_complete, NULL);
6395 : 4 : poll_threads();
6396 : 4 : CU_ASSERT(g_bserrno == 0);
6397 : :
6398 : 4 : spdk_bs_delete_blob(bs, snapshotid2, blob_op_complete, NULL);
6399 : 4 : poll_threads();
6400 : 4 : CU_ASSERT(g_bserrno == 0);
6401 : :
6402 : 4 : spdk_bs_delete_blob(bs, blobid, blob_op_complete, NULL);
6403 : 4 : poll_threads();
6404 : 4 : CU_ASSERT(g_bserrno == 0);
6405 : :
6406 : 4 : spdk_bs_delete_blob(bs, cloneid2, blob_op_complete, NULL);
6407 : 4 : poll_threads();
6408 : 4 : CU_ASSERT(g_bserrno == 0);
6409 : :
6410 : 4 : spdk_bs_unload(bs, bs_op_complete, NULL);
6411 : 4 : poll_threads();
6412 : 4 : CU_ASSERT(g_bserrno == 0);
6413 : :
6414 : 4 : g_bs = NULL;
6415 : 4 : }
6416 : :
6417 : : /**
6418 : : * Snapshot-clones relation test 3
6419 : : *
6420 : : * snapshot0
6421 : : * |
6422 : : * snapshot1
6423 : : * |
6424 : : * snapshot2
6425 : : * |
6426 : : * blob
6427 : : */
6428 : : static void
6429 : 4 : blob_relations3(void)
6430 : : {
6431 : : struct spdk_blob_store *bs;
6432 : : struct spdk_bs_dev *dev;
6433 : : struct spdk_io_channel *channel;
6434 : : struct spdk_bs_opts bs_opts;
6435 : : struct spdk_blob_opts opts;
6436 : : struct spdk_blob *blob;
6437 : : spdk_blob_id blobid, snapshotid0, snapshotid1, snapshotid2;
6438 : :
6439 : 4 : dev = init_dev();
6440 : 4 : spdk_bs_opts_init(&bs_opts, sizeof(bs_opts));
6441 : 4 : snprintf(bs_opts.bstype.bstype, sizeof(bs_opts.bstype.bstype), "TESTTYPE");
6442 : :
6443 : 4 : spdk_bs_init(dev, &bs_opts, bs_op_with_handle_complete, NULL);
6444 : 4 : poll_threads();
6445 : 4 : CU_ASSERT(g_bserrno == 0);
6446 [ + - ]: 4 : SPDK_CU_ASSERT_FATAL(g_bs != NULL);
6447 : 4 : bs = g_bs;
6448 : :
6449 : 4 : channel = spdk_bs_alloc_io_channel(bs);
6450 [ - + ]: 4 : SPDK_CU_ASSERT_FATAL(channel != NULL);
6451 : :
6452 : : /* 1. Create blob with 10 clusters */
6453 : 4 : ut_spdk_blob_opts_init(&opts);
6454 : 4 : opts.num_clusters = 10;
6455 : :
6456 : 4 : blob = ut_blob_create_and_open(bs, &opts);
6457 : 4 : blobid = spdk_blob_get_id(blob);
6458 : :
6459 : : /* 2. Create snapshot0 */
6460 : 4 : spdk_bs_create_snapshot(bs, blobid, NULL, blob_op_with_id_complete, NULL);
6461 : 4 : poll_threads();
6462 : 4 : CU_ASSERT(g_bserrno == 0);
6463 : 4 : CU_ASSERT(g_blobid != SPDK_BLOBID_INVALID);
6464 : 4 : snapshotid0 = g_blobid;
6465 : :
6466 : : /* 3. Create snapshot1 */
6467 : 4 : spdk_bs_create_snapshot(bs, blobid, NULL, blob_op_with_id_complete, NULL);
6468 : 4 : poll_threads();
6469 : 4 : CU_ASSERT(g_bserrno == 0);
6470 : 4 : CU_ASSERT(g_blobid != SPDK_BLOBID_INVALID);
6471 : 4 : snapshotid1 = g_blobid;
6472 : :
6473 : : /* 4. Create snapshot2 */
6474 : 4 : spdk_bs_create_snapshot(bs, blobid, NULL, blob_op_with_id_complete, NULL);
6475 : 4 : poll_threads();
6476 : 4 : CU_ASSERT(g_bserrno == 0);
6477 : 4 : CU_ASSERT(g_blobid != SPDK_BLOBID_INVALID);
6478 : 4 : snapshotid2 = g_blobid;
6479 : :
6480 : : /* 5. Decouple blob */
6481 : 4 : spdk_bs_blob_decouple_parent(bs, channel, blobid, blob_op_complete, NULL);
6482 : 4 : poll_threads();
6483 : 4 : CU_ASSERT(g_bserrno == 0);
6484 : :
6485 : : /* 6. Decouple snapshot2. Make sure updating md of snapshot2 is possible */
6486 : 4 : spdk_bs_blob_decouple_parent(bs, channel, snapshotid2, blob_op_complete, NULL);
6487 : 4 : poll_threads();
6488 : 4 : CU_ASSERT(g_bserrno == 0);
6489 : :
6490 : : /* 7. Delete blob */
6491 : 4 : spdk_blob_close(blob, blob_op_complete, NULL);
6492 : 4 : poll_threads();
6493 : 4 : CU_ASSERT(g_bserrno == 0);
6494 : :
6495 : 4 : spdk_bs_delete_blob(bs, blobid, blob_op_complete, NULL);
6496 : 4 : poll_threads();
6497 : 4 : CU_ASSERT(g_bserrno == 0);
6498 : :
6499 : : /* 8. Delete snapshot2.
6500 : : * If md of snapshot 2 was updated, it should be possible to delete it */
6501 : 4 : spdk_bs_delete_blob(bs, snapshotid2, blob_op_complete, NULL);
6502 : 4 : poll_threads();
6503 : 4 : CU_ASSERT(g_bserrno == 0);
6504 : :
6505 : : /* Remove remaining blobs and unload bs */
6506 : 4 : spdk_bs_delete_blob(bs, snapshotid1, blob_op_complete, NULL);
6507 : 4 : poll_threads();
6508 : 4 : CU_ASSERT(g_bserrno == 0);
6509 : :
6510 : 4 : spdk_bs_delete_blob(bs, snapshotid0, blob_op_complete, NULL);
6511 : 4 : poll_threads();
6512 : 4 : CU_ASSERT(g_bserrno == 0);
6513 : :
6514 : 4 : spdk_bs_free_io_channel(channel);
6515 : 4 : poll_threads();
6516 : :
6517 : 4 : spdk_bs_unload(bs, bs_op_complete, NULL);
6518 : 4 : poll_threads();
6519 : 4 : CU_ASSERT(g_bserrno == 0);
6520 : :
6521 : 4 : g_bs = NULL;
6522 : 4 : }
6523 : :
6524 : : static void
6525 : 4 : blobstore_clean_power_failure(void)
6526 : : {
6527 : : struct spdk_blob_store *bs;
6528 : : struct spdk_blob *blob;
6529 : 4 : struct spdk_power_failure_thresholds thresholds = {};
6530 : 4 : bool clean = false;
6531 : 4 : struct spdk_bs_super_block *super = (struct spdk_bs_super_block *)&g_dev_buffer[0];
6532 : 4 : struct spdk_bs_super_block super_copy = {};
6533 : :
6534 : 4 : thresholds.general_threshold = 1;
6535 [ + + ]: 20 : while (!clean) {
6536 : : /* Create bs and blob */
6537 : 16 : suite_blob_setup();
6538 [ + - ]: 16 : SPDK_CU_ASSERT_FATAL(g_bs != NULL);
6539 [ + - ]: 16 : SPDK_CU_ASSERT_FATAL(g_blob != NULL);
6540 : 16 : bs = g_bs;
6541 : 16 : blob = g_blob;
6542 : :
6543 : : /* Super block should not change for rest of the UT,
6544 : : * save it and compare later. */
6545 : 16 : memcpy(&super_copy, super, sizeof(struct spdk_bs_super_block));
6546 [ + - ]: 16 : SPDK_CU_ASSERT_FATAL(super->clean == 0);
6547 [ + - ]: 16 : SPDK_CU_ASSERT_FATAL(bs->clean == 0);
6548 : :
6549 : : /* Force bs/super block in a clean state.
6550 : : * Along with marking blob dirty, to cause blob persist. */
6551 : 16 : blob->state = SPDK_BLOB_STATE_DIRTY;
6552 : 16 : bs->clean = 1;
6553 : 16 : super->clean = 1;
6554 : 16 : super->crc = blob_md_page_calc_crc(super);
6555 : :
6556 : 16 : g_bserrno = -1;
6557 : 16 : dev_set_power_failure_thresholds(thresholds);
6558 : 16 : spdk_blob_sync_md(blob, blob_op_complete, NULL);
6559 : 16 : poll_threads();
6560 : 16 : dev_reset_power_failure_event();
6561 : :
6562 [ + + ]: 16 : if (g_bserrno == 0) {
6563 : : /* After successful md sync, both bs and super block
6564 : : * should be marked as not clean. */
6565 [ + - ]: 4 : SPDK_CU_ASSERT_FATAL(bs->clean == 0);
6566 [ - + ]: 4 : SPDK_CU_ASSERT_FATAL(super->clean == 0);
6567 : 4 : clean = true;
6568 : 4 : }
6569 : :
6570 : : /* Depending on the point of failure, super block was either updated or not. */
6571 : 16 : super_copy.clean = super->clean;
6572 : 16 : super_copy.crc = blob_md_page_calc_crc(&super_copy);
6573 : : /* Compare that the values in super block remained unchanged. */
6574 [ + - ]: 16 : SPDK_CU_ASSERT_FATAL(!memcmp(&super_copy, super, sizeof(struct spdk_bs_super_block)));
6575 : :
6576 : : /* Delete blob and unload bs */
6577 : 16 : suite_blob_cleanup();
6578 : :
6579 : 16 : thresholds.general_threshold++;
6580 : : }
6581 : 4 : }
6582 : :
6583 : : static void
6584 : 4 : blob_delete_snapshot_power_failure(void)
6585 : : {
6586 : : struct spdk_bs_dev *dev;
6587 : : struct spdk_blob_store *bs;
6588 : : struct spdk_blob_opts opts;
6589 : : struct spdk_blob *blob, *snapshot;
6590 : 4 : struct spdk_power_failure_thresholds thresholds = {};
6591 : : spdk_blob_id blobid, snapshotid;
6592 : : const void *value;
6593 : : size_t value_len;
6594 : : size_t count;
6595 : 4 : spdk_blob_id ids[3] = {};
6596 : : int rc;
6597 : 4 : bool deleted = false;
6598 : 4 : int delete_snapshot_bserrno = -1;
6599 : :
6600 : 4 : thresholds.general_threshold = 1;
6601 [ + + ]: 40 : while (!deleted) {
6602 : 36 : dev = init_dev();
6603 : :
6604 : 36 : spdk_bs_init(dev, NULL, bs_op_with_handle_complete, NULL);
6605 : 36 : poll_threads();
6606 : 36 : CU_ASSERT(g_bserrno == 0);
6607 [ + - ]: 36 : SPDK_CU_ASSERT_FATAL(g_bs != NULL);
6608 : 36 : bs = g_bs;
6609 : :
6610 : : /* Create blob */
6611 : 36 : ut_spdk_blob_opts_init(&opts);
6612 : 36 : opts.num_clusters = 10;
6613 : :
6614 : 36 : spdk_bs_create_blob_ext(bs, &opts, blob_op_with_id_complete, NULL);
6615 : 36 : poll_threads();
6616 : 36 : CU_ASSERT(g_bserrno == 0);
6617 : 36 : CU_ASSERT(g_blobid != SPDK_BLOBID_INVALID);
6618 : 36 : blobid = g_blobid;
6619 : :
6620 : : /* Create snapshot */
6621 : 36 : spdk_bs_create_snapshot(bs, blobid, NULL, blob_op_with_id_complete, NULL);
6622 : 36 : poll_threads();
6623 : 36 : CU_ASSERT(g_bserrno == 0);
6624 : 36 : CU_ASSERT(g_blobid != SPDK_BLOBID_INVALID);
6625 : 36 : snapshotid = g_blobid;
6626 [ + - ]: 36 : SPDK_CU_ASSERT_FATAL(spdk_bit_pool_is_allocated(bs->used_clusters, 1));
6627 [ + - ]: 36 : SPDK_CU_ASSERT_FATAL(!spdk_bit_pool_is_allocated(bs->used_clusters, 11));
6628 : :
6629 : 36 : dev_set_power_failure_thresholds(thresholds);
6630 : :
6631 : 36 : spdk_bs_delete_blob(bs, snapshotid, blob_op_complete, NULL);
6632 : 36 : poll_threads();
6633 : 36 : delete_snapshot_bserrno = g_bserrno;
6634 : :
6635 : : /* Do not shut down cleanly. Assumption is that after snapshot deletion
6636 : : * reports success, changes to both blobs should already persisted. */
6637 : 36 : dev_reset_power_failure_event();
6638 : 36 : ut_bs_dirty_load(&bs, NULL);
6639 : :
6640 [ + - ]: 36 : SPDK_CU_ASSERT_FATAL(spdk_bit_pool_is_allocated(bs->used_clusters, 1));
6641 [ + - ]: 36 : SPDK_CU_ASSERT_FATAL(!spdk_bit_pool_is_allocated(bs->used_clusters, 11));
6642 : :
6643 : 36 : spdk_bs_open_blob(bs, blobid, blob_op_with_handle_complete, NULL);
6644 : 36 : poll_threads();
6645 : 36 : CU_ASSERT(g_bserrno == 0);
6646 [ + - ]: 36 : SPDK_CU_ASSERT_FATAL(g_blob != NULL);
6647 : 36 : blob = g_blob;
6648 [ + - ]: 36 : SPDK_CU_ASSERT_FATAL(spdk_blob_is_thin_provisioned(blob) == true);
6649 : :
6650 : 36 : spdk_bs_open_blob(bs, snapshotid, blob_op_with_handle_complete, NULL);
6651 : 36 : poll_threads();
6652 : :
6653 [ + + ]: 36 : if (g_bserrno == 0) {
6654 [ - + ]: 24 : SPDK_CU_ASSERT_FATAL(g_blob != NULL);
6655 : 24 : snapshot = g_blob;
6656 : 24 : CU_ASSERT(spdk_blob_get_parent_snapshot(bs, blobid) == snapshotid);
6657 : 24 : count = SPDK_COUNTOF(ids);
6658 : 24 : rc = spdk_blob_get_clones(bs, snapshotid, ids, &count);
6659 : 24 : CU_ASSERT(rc == 0);
6660 : 24 : CU_ASSERT(count == 1);
6661 : 24 : CU_ASSERT(ids[0] == blobid);
6662 : 24 : rc = spdk_blob_get_xattr_value(snapshot, SNAPSHOT_PENDING_REMOVAL, &value, &value_len);
6663 : 24 : CU_ASSERT(rc != 0);
6664 [ - + ]: 24 : SPDK_CU_ASSERT_FATAL(spdk_blob_is_thin_provisioned(snapshot) == false);
6665 : 24 : CU_ASSERT(spdk_blob_get_num_allocated_clusters(blob) == 0);
6666 : 24 : CU_ASSERT(spdk_blob_get_num_allocated_clusters(snapshot) == 10);
6667 : :
6668 : 24 : spdk_blob_close(snapshot, blob_op_complete, NULL);
6669 : 24 : poll_threads();
6670 : 24 : CU_ASSERT(g_bserrno == 0);
6671 : 24 : } else {
6672 : 12 : CU_ASSERT(spdk_blob_get_parent_snapshot(bs, blobid) == SPDK_BLOBID_INVALID);
6673 : 12 : CU_ASSERT(spdk_blob_get_num_allocated_clusters(blob) == 10);
6674 : : /* Snapshot might have been left in unrecoverable state, so it does not open.
6675 : : * Yet delete might perform further changes to the clone after that.
6676 : : * This UT should test until snapshot is deleted and delete call succeeds. */
6677 [ + + ]: 12 : if (delete_snapshot_bserrno == 0) {
6678 : 4 : deleted = true;
6679 : 4 : }
6680 : : }
6681 : :
6682 : 36 : spdk_blob_close(blob, blob_op_complete, NULL);
6683 : 36 : poll_threads();
6684 : 36 : CU_ASSERT(g_bserrno == 0);
6685 : :
6686 : 36 : spdk_bs_unload(bs, bs_op_complete, NULL);
6687 : 36 : poll_threads();
6688 : 36 : CU_ASSERT(g_bserrno == 0);
6689 : :
6690 : 36 : thresholds.general_threshold++;
6691 : : }
6692 : 4 : }
6693 : :
6694 : : static void
6695 : 4 : blob_create_snapshot_power_failure(void)
6696 : : {
6697 : 4 : struct spdk_blob_store *bs = g_bs;
6698 : : struct spdk_bs_dev *dev;
6699 : : struct spdk_blob_opts opts;
6700 : : struct spdk_blob *blob, *snapshot;
6701 : 4 : struct spdk_power_failure_thresholds thresholds = {};
6702 : : spdk_blob_id blobid, snapshotid;
6703 : : const void *value;
6704 : : size_t value_len;
6705 : : size_t count;
6706 : 4 : spdk_blob_id ids[3] = {};
6707 : : int rc;
6708 : 4 : bool created = false;
6709 : 4 : int create_snapshot_bserrno = -1;
6710 : :
6711 : 4 : thresholds.general_threshold = 1;
6712 [ + + ]: 34 : while (!created) {
6713 : 30 : dev = init_dev();
6714 : :
6715 : 30 : spdk_bs_init(dev, NULL, bs_op_with_handle_complete, NULL);
6716 : 30 : poll_threads();
6717 : 30 : CU_ASSERT(g_bserrno == 0);
6718 [ + - ]: 30 : SPDK_CU_ASSERT_FATAL(g_bs != NULL);
6719 : 30 : bs = g_bs;
6720 : :
6721 : : /* Create blob */
6722 : 30 : ut_spdk_blob_opts_init(&opts);
6723 : 30 : opts.num_clusters = 10;
6724 : :
6725 : 30 : spdk_bs_create_blob_ext(bs, &opts, blob_op_with_id_complete, NULL);
6726 : 30 : poll_threads();
6727 : 30 : CU_ASSERT(g_bserrno == 0);
6728 : 30 : CU_ASSERT(g_blobid != SPDK_BLOBID_INVALID);
6729 : 30 : blobid = g_blobid;
6730 [ + - ]: 30 : SPDK_CU_ASSERT_FATAL(spdk_bit_pool_is_allocated(bs->used_clusters, 1));
6731 [ + - ]: 30 : SPDK_CU_ASSERT_FATAL(!spdk_bit_pool_is_allocated(bs->used_clusters, 11));
6732 : :
6733 : 30 : dev_set_power_failure_thresholds(thresholds);
6734 : :
6735 : : /* Create snapshot */
6736 : 30 : spdk_bs_create_snapshot(bs, blobid, NULL, blob_op_with_id_complete, NULL);
6737 : 30 : poll_threads();
6738 : 30 : create_snapshot_bserrno = g_bserrno;
6739 : 30 : snapshotid = g_blobid;
6740 [ + - ]: 30 : SPDK_CU_ASSERT_FATAL(spdk_bit_pool_is_allocated(bs->used_clusters, 1));
6741 [ + - ]: 30 : SPDK_CU_ASSERT_FATAL(!spdk_bit_pool_is_allocated(bs->used_clusters, 11));
6742 : :
6743 : : /* Do not shut down cleanly. Assumption is that after create snapshot
6744 : : * reports success, both blobs should be power-fail safe. */
6745 : 30 : dev_reset_power_failure_event();
6746 : 30 : ut_bs_dirty_load(&bs, NULL);
6747 : :
6748 [ + - ]: 30 : SPDK_CU_ASSERT_FATAL(spdk_bit_pool_is_allocated(bs->used_clusters, 1));
6749 [ + - ]: 30 : SPDK_CU_ASSERT_FATAL(!spdk_bit_pool_is_allocated(bs->used_clusters, 11));
6750 : :
6751 : 30 : spdk_bs_open_blob(bs, blobid, blob_op_with_handle_complete, NULL);
6752 : 30 : poll_threads();
6753 : 30 : CU_ASSERT(g_bserrno == 0);
6754 [ + - ]: 30 : SPDK_CU_ASSERT_FATAL(g_blob != NULL);
6755 : 30 : blob = g_blob;
6756 : :
6757 [ + + ]: 30 : if (snapshotid != SPDK_BLOBID_INVALID) {
6758 : 20 : spdk_bs_open_blob(bs, snapshotid, blob_op_with_handle_complete, NULL);
6759 : 20 : poll_threads();
6760 : 20 : }
6761 : :
6762 [ + + + + ]: 30 : if ((snapshotid != SPDK_BLOBID_INVALID) && (g_bserrno == 0)) {
6763 [ - + ]: 8 : SPDK_CU_ASSERT_FATAL(g_blob != NULL);
6764 : 8 : snapshot = g_blob;
6765 [ - + ]: 8 : SPDK_CU_ASSERT_FATAL(spdk_blob_is_thin_provisioned(blob) == true);
6766 [ - + ]: 8 : SPDK_CU_ASSERT_FATAL(spdk_blob_is_thin_provisioned(snapshot) == false);
6767 : 8 : CU_ASSERT(spdk_blob_get_num_allocated_clusters(blob) == 0);
6768 : 8 : CU_ASSERT(spdk_blob_get_num_allocated_clusters(snapshot) == 10);
6769 : 8 : CU_ASSERT(spdk_blob_get_parent_snapshot(bs, blobid) == snapshotid);
6770 : 8 : count = SPDK_COUNTOF(ids);
6771 : 8 : rc = spdk_blob_get_clones(bs, snapshotid, ids, &count);
6772 : 8 : CU_ASSERT(rc == 0);
6773 : 8 : CU_ASSERT(count == 1);
6774 : 8 : CU_ASSERT(ids[0] == blobid);
6775 : 8 : rc = spdk_blob_get_xattr_value(snapshot, SNAPSHOT_IN_PROGRESS, &value, &value_len);
6776 : 8 : CU_ASSERT(rc != 0);
6777 : :
6778 : 8 : spdk_blob_close(snapshot, blob_op_complete, NULL);
6779 : 8 : poll_threads();
6780 : 8 : CU_ASSERT(g_bserrno == 0);
6781 [ + + ]: 8 : if (create_snapshot_bserrno == 0) {
6782 : 4 : created = true;
6783 : 4 : }
6784 : 8 : } else {
6785 : 22 : CU_ASSERT(spdk_blob_get_parent_snapshot(bs, blobid) == SPDK_BLOBID_INVALID);
6786 [ + - ]: 22 : SPDK_CU_ASSERT_FATAL(spdk_blob_is_thin_provisioned(blob) == false);
6787 : 22 : CU_ASSERT(spdk_blob_get_num_allocated_clusters(blob) == 10);
6788 : : }
6789 : :
6790 : 30 : spdk_blob_close(blob, blob_op_complete, NULL);
6791 : 30 : poll_threads();
6792 : 30 : CU_ASSERT(g_bserrno == 0);
6793 : :
6794 : 30 : spdk_bs_unload(bs, bs_op_complete, NULL);
6795 : 30 : poll_threads();
6796 : 30 : CU_ASSERT(g_bserrno == 0);
6797 : :
6798 : 30 : thresholds.general_threshold++;
6799 : : }
6800 : 4 : }
6801 : :
6802 : : static void
6803 : 8 : test_io_write(struct spdk_bs_dev *dev, struct spdk_blob *blob, struct spdk_io_channel *channel)
6804 : : {
6805 : : uint8_t payload_ff[64 * 512];
6806 : : uint8_t payload_aa[64 * 512];
6807 : : uint8_t payload_00[64 * 512];
6808 : : uint8_t *cluster0, *cluster1;
6809 : :
6810 : 8 : memset(payload_ff, 0xFF, sizeof(payload_ff));
6811 : 8 : memset(payload_aa, 0xAA, sizeof(payload_aa));
6812 : 8 : memset(payload_00, 0x00, sizeof(payload_00));
6813 : :
6814 : : /* Try to perform I/O with io unit = 512 */
6815 : 8 : spdk_blob_io_write(blob, channel, payload_ff, 0, 1, blob_op_complete, NULL);
6816 : 8 : poll_threads();
6817 : 8 : CU_ASSERT(g_bserrno == 0);
6818 : :
6819 : : /* If thin provisioned is set cluster should be allocated now */
6820 [ + - ]: 8 : SPDK_CU_ASSERT_FATAL(blob->active.clusters[0] != 0);
6821 : 8 : cluster0 = &g_dev_buffer[blob->active.clusters[0] * dev->blocklen];
6822 : :
6823 : : /* Each character 0-F symbolizes single io_unit containing 512 bytes block filled with that character.
6824 : : * Each page is separated by |. Whole block [...] symbolizes one cluster (containing 4 pages). */
6825 : : /* cluster0: [ F000 0000 | 0000 0000 | 0000 0000 | 0000 0000 ] */
6826 : 8 : CU_ASSERT(memcmp(cluster0 + 0 * 512, payload_ff, 512) == 0);
6827 : 8 : CU_ASSERT(memcmp(cluster0 + 1 * 512, payload_00, 31 * 512) == 0);
6828 : :
6829 : : /* Verify write with offset on first page */
6830 : 8 : spdk_blob_io_write(blob, channel, payload_ff, 2, 1, blob_op_complete, NULL);
6831 : 8 : poll_threads();
6832 : 8 : CU_ASSERT(g_bserrno == 0);
6833 : :
6834 : : /* cluster0: [ F0F0 0000 | 0000 0000 | 0000 0000 | 0000 0000 ] */
6835 : 8 : CU_ASSERT(memcmp(cluster0 + 0 * 512, payload_ff, 512) == 0);
6836 : 8 : CU_ASSERT(memcmp(cluster0 + 1 * 512, payload_00, 512) == 0);
6837 : 8 : CU_ASSERT(memcmp(cluster0 + 2 * 512, payload_ff, 512) == 0);
6838 : 8 : CU_ASSERT(memcmp(cluster0 + 3 * 512, payload_00, 512) == 0);
6839 : 8 : CU_ASSERT(memcmp(cluster0 + 4 * 512, payload_00, 28 * 512) == 0);
6840 : :
6841 : : /* Verify write with offset on first page */
6842 : 8 : spdk_blob_io_write(blob, channel, payload_ff, 4, 4, blob_op_complete, NULL);
6843 : 8 : poll_threads();
6844 : :
6845 : : /* cluster0: [ F0F0 FFFF | 0000 0000 | 0000 0000 | 0000 0000 ] */
6846 : 8 : CU_ASSERT(memcmp(cluster0 + 0 * 512, payload_ff, 512) == 0);
6847 : 8 : CU_ASSERT(memcmp(cluster0 + 1 * 512, payload_00, 512) == 0);
6848 : 8 : CU_ASSERT(memcmp(cluster0 + 2 * 512, payload_ff, 512) == 0);
6849 : 8 : CU_ASSERT(memcmp(cluster0 + 3 * 512, payload_00, 512) == 0);
6850 : 8 : CU_ASSERT(memcmp(cluster0 + 4 * 512, payload_ff, 4 * 512) == 0);
6851 : 8 : CU_ASSERT(memcmp(cluster0 + 8 * 512, payload_00, 24 * 512) == 0);
6852 : :
6853 : : /* Verify write with offset on second page */
6854 : 8 : spdk_blob_io_write(blob, channel, payload_ff, 8, 4, blob_op_complete, NULL);
6855 : 8 : poll_threads();
6856 : :
6857 : : /* cluster0: [ F0F0 FFFF | FFFF 0000 | 0000 0000 | 0000 0000 ] */
6858 : 8 : CU_ASSERT(memcmp(cluster0 + 0 * 512, payload_ff, 512) == 0);
6859 : 8 : CU_ASSERT(memcmp(cluster0 + 1 * 512, payload_00, 512) == 0);
6860 : 8 : CU_ASSERT(memcmp(cluster0 + 2 * 512, payload_ff, 512) == 0);
6861 : 8 : CU_ASSERT(memcmp(cluster0 + 3 * 512, payload_00, 512) == 0);
6862 : 8 : CU_ASSERT(memcmp(cluster0 + 4 * 512, payload_ff, 8 * 512) == 0);
6863 : 8 : CU_ASSERT(memcmp(cluster0 + 12 * 512, payload_00, 20 * 512) == 0);
6864 : :
6865 : : /* Verify write across multiple pages */
6866 : 8 : spdk_blob_io_write(blob, channel, payload_aa, 4, 8, blob_op_complete, NULL);
6867 : 8 : poll_threads();
6868 : :
6869 : : /* cluster0: [ F0F0 AAAA | AAAA 0000 | 0000 0000 | 0000 0000 ] */
6870 : 8 : CU_ASSERT(memcmp(cluster0 + 0 * 512, payload_ff, 512) == 0);
6871 : 8 : CU_ASSERT(memcmp(cluster0 + 1 * 512, payload_00, 512) == 0);
6872 : 8 : CU_ASSERT(memcmp(cluster0 + 2 * 512, payload_ff, 512) == 0);
6873 : 8 : CU_ASSERT(memcmp(cluster0 + 3 * 512, payload_00, 512) == 0);
6874 : 8 : CU_ASSERT(memcmp(cluster0 + 4 * 512, payload_aa, 8 * 512) == 0);
6875 : 8 : CU_ASSERT(memcmp(cluster0 + 12 * 512, payload_00, 20 * 512) == 0);
6876 : :
6877 : : /* Verify write across multiple clusters */
6878 : 8 : spdk_blob_io_write(blob, channel, payload_ff, 28, 8, blob_op_complete, NULL);
6879 : 8 : poll_threads();
6880 : :
6881 [ + - ]: 8 : SPDK_CU_ASSERT_FATAL(blob->active.clusters[1] != 0);
6882 : 8 : cluster1 = &g_dev_buffer[blob->active.clusters[1] * dev->blocklen];
6883 : :
6884 : : /* cluster0: [ F0F0 AAAA | AAAA 0000 | 0000 0000 | 0000 FFFF ]
6885 : : * cluster1: [ FFFF 0000 | 0000 0000 | 0000 0000 | 0000 0000 ] */
6886 : 8 : CU_ASSERT(memcmp(cluster0 + 0 * 512, payload_ff, 512) == 0);
6887 : 8 : CU_ASSERT(memcmp(cluster0 + 1 * 512, payload_00, 512) == 0);
6888 : 8 : CU_ASSERT(memcmp(cluster0 + 2 * 512, payload_ff, 512) == 0);
6889 : 8 : CU_ASSERT(memcmp(cluster0 + 3 * 512, payload_00, 512) == 0);
6890 : 8 : CU_ASSERT(memcmp(cluster0 + 4 * 512, payload_aa, 8 * 512) == 0);
6891 : 8 : CU_ASSERT(memcmp(cluster0 + 28 * 512, payload_ff, 4 * 512) == 0);
6892 : :
6893 : 8 : CU_ASSERT(memcmp(cluster1 + 0 * 512, payload_ff, 4 * 512) == 0);
6894 : 8 : CU_ASSERT(memcmp(cluster1 + 4 * 512, payload_00, 28 * 512) == 0);
6895 : :
6896 : : /* Verify write to second cluster */
6897 : 8 : spdk_blob_io_write(blob, channel, payload_ff, 32 + 12, 2, blob_op_complete, NULL);
6898 : 8 : poll_threads();
6899 : :
6900 [ - + ]: 8 : SPDK_CU_ASSERT_FATAL(blob->active.clusters[1] != 0);
6901 : 8 : cluster1 = &g_dev_buffer[blob->active.clusters[1] * dev->blocklen];
6902 : :
6903 : : /* cluster0: [ F0F0 AAAA | AAAA 0000 | 0000 0000 | 0000 FFFF ]
6904 : : * cluster1: [ FFFF 0000 | 0000 FF00 | 0000 0000 | 0000 0000 ] */
6905 : 8 : CU_ASSERT(memcmp(cluster0 + 0 * 512, payload_ff, 512) == 0);
6906 : 8 : CU_ASSERT(memcmp(cluster0 + 1 * 512, payload_00, 512) == 0);
6907 : 8 : CU_ASSERT(memcmp(cluster0 + 2 * 512, payload_ff, 512) == 0);
6908 : 8 : CU_ASSERT(memcmp(cluster0 + 3 * 512, payload_00, 512) == 0);
6909 : 8 : CU_ASSERT(memcmp(cluster0 + 4 * 512, payload_aa, 8 * 512) == 0);
6910 : 8 : CU_ASSERT(memcmp(cluster0 + 28 * 512, payload_ff, 4 * 512) == 0);
6911 : :
6912 : 8 : CU_ASSERT(memcmp(cluster1 + 0 * 512, payload_ff, 4 * 512) == 0);
6913 : 8 : CU_ASSERT(memcmp(cluster1 + 4 * 512, payload_00, 8 * 512) == 0);
6914 : 8 : CU_ASSERT(memcmp(cluster1 + 12 * 512, payload_ff, 2 * 512) == 0);
6915 : 8 : CU_ASSERT(memcmp(cluster1 + 14 * 512, payload_00, 18 * 512) == 0);
6916 : 8 : }
6917 : :
6918 : : static void
6919 : 24 : test_io_read(struct spdk_bs_dev *dev, struct spdk_blob *blob, struct spdk_io_channel *channel)
6920 : : {
6921 : : uint8_t payload_read[64 * 512];
6922 : : uint8_t payload_ff[64 * 512];
6923 : : uint8_t payload_aa[64 * 512];
6924 : : uint8_t payload_00[64 * 512];
6925 : :
6926 : 24 : memset(payload_ff, 0xFF, sizeof(payload_ff));
6927 : 24 : memset(payload_aa, 0xAA, sizeof(payload_aa));
6928 : 24 : memset(payload_00, 0x00, sizeof(payload_00));
6929 : :
6930 : : /* Read only first io unit */
6931 : : /* cluster0: [ (F)0F0 AAAA | AAAA 0000 | 0000 0000 | 0000 FFFF ]
6932 : : * cluster1: [ FFFF 0000 | 0000 FF00 | 0000 0000 | 0000 0000 ]
6933 : : * payload_read: F000 0000 | 0000 0000 ... */
6934 : 24 : memset(payload_read, 0x00, sizeof(payload_read));
6935 : 24 : spdk_blob_io_read(blob, channel, payload_read, 0, 1, blob_op_complete, NULL);
6936 : 24 : poll_threads();
6937 : 24 : CU_ASSERT(g_bserrno == 0);
6938 : 24 : CU_ASSERT(memcmp(payload_read + 0 * 512, payload_ff, 512) == 0);
6939 : 24 : CU_ASSERT(memcmp(payload_read + 1 * 512, payload_00, 31 * 512) == 0);
6940 : :
6941 : : /* Read four io_units starting from offset = 2
6942 : : * cluster0: [ F0(F0 AA)AA | AAAA 0000 | 0000 0000 | 0000 FFFF ]
6943 : : * cluster1: [ FFFF 0000 | 0000 FF00 | 0000 0000 | 0000 0000 ]
6944 : : * payload_read: F0AA 0000 | 0000 0000 ... */
6945 : :
6946 : 24 : memset(payload_read, 0x00, sizeof(payload_read));
6947 : 24 : spdk_blob_io_read(blob, channel, payload_read, 2, 4, blob_op_complete, NULL);
6948 : 24 : poll_threads();
6949 : 24 : CU_ASSERT(g_bserrno == 0);
6950 : :
6951 : 24 : CU_ASSERT(memcmp(payload_read + 0 * 512, payload_ff, 512) == 0);
6952 : 24 : CU_ASSERT(memcmp(payload_read + 1 * 512, payload_00, 512) == 0);
6953 : 24 : CU_ASSERT(memcmp(payload_read + 2 * 512, payload_aa, 512) == 0);
6954 : 24 : CU_ASSERT(memcmp(payload_read + 3 * 512, payload_aa, 512) == 0);
6955 : 24 : CU_ASSERT(memcmp(payload_read + 4 * 512, payload_00, 28 * 512) == 0);
6956 : :
6957 : : /* Read eight io_units across multiple pages
6958 : : * cluster0: [ F0F0 (AAAA | AAAA) 0000 | 0000 0000 | 0000 FFFF ]
6959 : : * cluster1: [ FFFF 0000 | 0000 FF00 | 0000 0000 | 0000 0000 ]
6960 : : * payload_read: AAAA AAAA | 0000 0000 ... */
6961 : 24 : memset(payload_read, 0x00, sizeof(payload_read));
6962 : 24 : spdk_blob_io_read(blob, channel, payload_read, 4, 8, blob_op_complete, NULL);
6963 : 24 : poll_threads();
6964 : 24 : CU_ASSERT(g_bserrno == 0);
6965 : :
6966 : 24 : CU_ASSERT(memcmp(payload_read + 0 * 512, payload_aa, 8 * 512) == 0);
6967 : 24 : CU_ASSERT(memcmp(payload_read + 8 * 512, payload_00, 24 * 512) == 0);
6968 : :
6969 : : /* Read eight io_units across multiple clusters
6970 : : * cluster0: [ F0F0 AAAA | AAAA 0000 | 0000 0000 | 0000 (FFFF ]
6971 : : * cluster1: [ FFFF) 0000 | 0000 FF00 | 0000 0000 | 0000 0000 ]
6972 : : * payload_read: FFFF FFFF | 0000 0000 ... */
6973 : 24 : memset(payload_read, 0x00, sizeof(payload_read));
6974 : 24 : spdk_blob_io_read(blob, channel, payload_read, 28, 8, blob_op_complete, NULL);
6975 : 24 : poll_threads();
6976 : 24 : CU_ASSERT(g_bserrno == 0);
6977 : :
6978 : 24 : CU_ASSERT(memcmp(payload_read + 0 * 512, payload_ff, 8 * 512) == 0);
6979 : 24 : CU_ASSERT(memcmp(payload_read + 8 * 512, payload_00, 24 * 512) == 0);
6980 : :
6981 : : /* Read four io_units from second cluster
6982 : : * cluster0: [ F0F0 AAAA | AAAA 0000 | 0000 0000 | 0000 FFFF ]
6983 : : * cluster1: [ FFFF 0000 | 00(00 FF)00 | 0000 0000 | 0000 0000 ]
6984 : : * payload_read: 00FF 0000 | 0000 0000 ... */
6985 : 24 : memset(payload_read, 0x00, sizeof(payload_read));
6986 : 24 : spdk_blob_io_read(blob, channel, payload_read, 32 + 10, 4, blob_op_complete, NULL);
6987 : 24 : poll_threads();
6988 : 24 : CU_ASSERT(g_bserrno == 0);
6989 : :
6990 : 24 : CU_ASSERT(memcmp(payload_read + 0 * 512, payload_00, 2 * 512) == 0);
6991 : 24 : CU_ASSERT(memcmp(payload_read + 2 * 512, payload_ff, 2 * 512) == 0);
6992 : 24 : CU_ASSERT(memcmp(payload_read + 4 * 512, payload_00, 28 * 512) == 0);
6993 : :
6994 : : /* Read second cluster
6995 : : * cluster0: [ F0F0 AAAA | AAAA 0000 | 0000 0000 | 0000 FFFF ]
6996 : : * cluster1: [ (FFFF 0000 | 0000 FF00 | 0000 0000 | 0000 0000) ]
6997 : : * payload_read: FFFF 0000 | 0000 FF00 ... */
6998 : 24 : memset(payload_read, 0x00, sizeof(payload_read));
6999 : 24 : spdk_blob_io_read(blob, channel, payload_read, 32, 32, blob_op_complete, NULL);
7000 : 24 : poll_threads();
7001 : 24 : CU_ASSERT(g_bserrno == 0);
7002 : 24 : CU_ASSERT(memcmp(payload_read + 0 * 512, payload_ff, 4 * 512) == 0);
7003 : 24 : CU_ASSERT(memcmp(payload_read + 4 * 512, payload_00, 8 * 512) == 0);
7004 : 24 : CU_ASSERT(memcmp(payload_read + 12 * 512, payload_ff, 2 * 512) == 0);
7005 : 24 : CU_ASSERT(memcmp(payload_read + 14 * 512, payload_00, 18 * 512) == 0);
7006 : :
7007 : : /* Read whole two clusters
7008 : : * cluster0: [ (F0F0 AAAA | AAAA) 0000 | 0000 0000 | 0000 FFFF ]
7009 : : * cluster1: [ FFFF 0000 | 0000 FF00 | 0000 0000 | 0000 0000) ] */
7010 : 24 : memset(payload_read, 0x00, sizeof(payload_read));
7011 : 24 : spdk_blob_io_read(blob, channel, payload_read, 0, 64, blob_op_complete, NULL);
7012 : 24 : poll_threads();
7013 : 24 : CU_ASSERT(g_bserrno == 0);
7014 : :
7015 : 24 : CU_ASSERT(memcmp(payload_read + 0 * 512, payload_ff, 512) == 0);
7016 : 24 : CU_ASSERT(memcmp(payload_read + 1 * 512, payload_00, 512) == 0);
7017 : 24 : CU_ASSERT(memcmp(payload_read + 2 * 512, payload_ff, 512) == 0);
7018 : 24 : CU_ASSERT(memcmp(payload_read + 3 * 512, payload_00, 512) == 0);
7019 : 24 : CU_ASSERT(memcmp(payload_read + 4 * 512, payload_aa, 8 * 512) == 0);
7020 : 24 : CU_ASSERT(memcmp(payload_read + 28 * 512, payload_ff, 4 * 512) == 0);
7021 : :
7022 : 24 : CU_ASSERT(memcmp(payload_read + (32 + 0) * 512, payload_ff, 4 * 512) == 0);
7023 : 24 : CU_ASSERT(memcmp(payload_read + (32 + 4) * 512, payload_00, 8 * 512) == 0);
7024 : 24 : CU_ASSERT(memcmp(payload_read + (32 + 12) * 512, payload_ff, 2 * 512) == 0);
7025 : 24 : CU_ASSERT(memcmp(payload_read + (32 + 14) * 512, payload_00, 18 * 512) == 0);
7026 : 24 : }
7027 : :
7028 : :
7029 : : static void
7030 : 12 : test_io_unmap(struct spdk_bs_dev *dev, struct spdk_blob *blob, struct spdk_io_channel *channel)
7031 : : {
7032 : : uint8_t payload_ff[64 * 512];
7033 : : uint8_t payload_aa[64 * 512];
7034 : : uint8_t payload_00[64 * 512];
7035 : : uint8_t *cluster0, *cluster1;
7036 : :
7037 : 12 : memset(payload_ff, 0xFF, sizeof(payload_ff));
7038 : 12 : memset(payload_aa, 0xAA, sizeof(payload_aa));
7039 : 12 : memset(payload_00, 0x00, sizeof(payload_00));
7040 : :
7041 : 12 : cluster0 = &g_dev_buffer[blob->active.clusters[0] * dev->blocklen];
7042 : 12 : cluster1 = &g_dev_buffer[blob->active.clusters[1] * dev->blocklen];
7043 : :
7044 : : /* Unmap */
7045 : 12 : spdk_blob_io_unmap(blob, channel, 0, 64, blob_op_complete, NULL);
7046 : 12 : poll_threads();
7047 : :
7048 : 12 : CU_ASSERT(g_bserrno == 0);
7049 : :
7050 : 12 : CU_ASSERT(memcmp(cluster0 + 0 * 512, payload_00, 32 * 512) == 0);
7051 : 12 : CU_ASSERT(memcmp(cluster1 + 0 * 512, payload_00, 32 * 512) == 0);
7052 : 12 : }
7053 : :
7054 : : static void
7055 : 16 : test_io_zeroes(struct spdk_bs_dev *dev, struct spdk_blob *blob, struct spdk_io_channel *channel)
7056 : : {
7057 : : uint8_t payload_ff[64 * 512];
7058 : : uint8_t payload_aa[64 * 512];
7059 : : uint8_t payload_00[64 * 512];
7060 : : uint8_t *cluster0, *cluster1;
7061 : :
7062 : 16 : memset(payload_ff, 0xFF, sizeof(payload_ff));
7063 : 16 : memset(payload_aa, 0xAA, sizeof(payload_aa));
7064 : 16 : memset(payload_00, 0x00, sizeof(payload_00));
7065 : :
7066 : 16 : cluster0 = &g_dev_buffer[blob->active.clusters[0] * dev->blocklen];
7067 : 16 : cluster1 = &g_dev_buffer[blob->active.clusters[1] * dev->blocklen];
7068 : :
7069 : : /* Write zeroes */
7070 : 16 : spdk_blob_io_write_zeroes(blob, channel, 0, 64, blob_op_complete, NULL);
7071 : 16 : poll_threads();
7072 : :
7073 : 16 : CU_ASSERT(g_bserrno == 0);
7074 : :
7075 : 16 : CU_ASSERT(memcmp(cluster0 + 0 * 512, payload_00, 32 * 512) == 0);
7076 : 16 : CU_ASSERT(memcmp(cluster1 + 0 * 512, payload_00, 32 * 512) == 0);
7077 : 16 : }
7078 : :
7079 : : static inline void
7080 : 120 : test_blob_io_writev(struct spdk_blob *blob, struct spdk_io_channel *channel,
7081 : : struct iovec *iov, int iovcnt, uint64_t offset, uint64_t length,
7082 : : spdk_blob_op_complete cb_fn, void *cb_arg, struct spdk_blob_ext_io_opts *io_opts)
7083 : : {
7084 [ + + ]: 120 : if (io_opts) {
7085 : 60 : g_dev_writev_ext_called = false;
7086 : 60 : memset(&g_blob_ext_io_opts, 0, sizeof(g_blob_ext_io_opts));
7087 : 120 : spdk_blob_io_writev_ext(blob, channel, iov, iovcnt, offset, length, blob_op_complete, NULL,
7088 : 60 : io_opts);
7089 : 60 : } else {
7090 : 60 : spdk_blob_io_writev(blob, channel, iov, iovcnt, offset, length, blob_op_complete, NULL);
7091 : : }
7092 : 120 : poll_threads();
7093 : 120 : CU_ASSERT(g_bserrno == 0);
7094 [ + + ]: 120 : if (io_opts) {
7095 : 60 : CU_ASSERT(g_dev_writev_ext_called);
7096 : 60 : CU_ASSERT(memcmp(io_opts, &g_blob_ext_io_opts, sizeof(g_blob_ext_io_opts)) == 0);
7097 : 60 : }
7098 : 120 : }
7099 : :
7100 : : static void
7101 : 24 : test_iov_write(struct spdk_bs_dev *dev, struct spdk_blob *blob, struct spdk_io_channel *channel,
7102 : : bool ext_api)
7103 : : {
7104 : : uint8_t payload_ff[64 * 512];
7105 : : uint8_t payload_aa[64 * 512];
7106 : : uint8_t payload_00[64 * 512];
7107 : : uint8_t *cluster0, *cluster1;
7108 : : struct iovec iov[4];
7109 : 24 : struct spdk_blob_ext_io_opts ext_opts = {
7110 : : .memory_domain = (struct spdk_memory_domain *)0xfeedbeef,
7111 : : .memory_domain_ctx = (void *)0xf00df00d,
7112 : : .size = sizeof(struct spdk_blob_ext_io_opts),
7113 : : .user_ctx = (void *)123,
7114 : : };
7115 : :
7116 : 24 : memset(payload_ff, 0xFF, sizeof(payload_ff));
7117 : 24 : memset(payload_aa, 0xAA, sizeof(payload_aa));
7118 : 24 : memset(payload_00, 0x00, sizeof(payload_00));
7119 : :
7120 : : /* Try to perform I/O with io unit = 512 */
7121 : 24 : iov[0].iov_base = payload_ff;
7122 : 24 : iov[0].iov_len = 1 * 512;
7123 : :
7124 : 48 : test_blob_io_writev(blob, channel, iov, 1, 0, 1, blob_op_complete, NULL,
7125 [ + + ]: 24 : ext_api ? &ext_opts : NULL);
7126 : :
7127 : : /* If thin provisioned is set cluster should be allocated now */
7128 [ + - ]: 24 : SPDK_CU_ASSERT_FATAL(blob->active.clusters[0] != 0);
7129 : 24 : cluster0 = &g_dev_buffer[blob->active.clusters[0] * dev->blocklen];
7130 : :
7131 : : /* Each character 0-F symbolizes single io_unit containing 512 bytes block filled with that character.
7132 : : * Each page is separated by |. Whole block [...] symbolizes one cluster (containing 4 pages). */
7133 : : /* cluster0: [ F000 0000 | 0000 0000 | 0000 0000 | 0000 0000 ] */
7134 : 24 : CU_ASSERT(memcmp(cluster0 + 0 * 512, payload_ff, 512) == 0);
7135 : 24 : CU_ASSERT(memcmp(cluster0 + 1 * 512, payload_00, 31 * 512) == 0);
7136 : :
7137 : : /* Verify write with offset on first page */
7138 : 24 : iov[0].iov_base = payload_ff;
7139 : 24 : iov[0].iov_len = 1 * 512;
7140 : :
7141 : 48 : test_blob_io_writev(blob, channel, iov, 1, 2, 1, blob_op_complete, NULL,
7142 [ + + ]: 24 : ext_api ? &ext_opts : NULL);
7143 : :
7144 : : /* cluster0: [ F0F0 0000 | 0000 0000 | 0000 0000 | 0000 0000 ] */
7145 : 24 : CU_ASSERT(memcmp(cluster0 + 0 * 512, payload_ff, 512) == 0);
7146 : 24 : CU_ASSERT(memcmp(cluster0 + 1 * 512, payload_00, 512) == 0);
7147 : 24 : CU_ASSERT(memcmp(cluster0 + 2 * 512, payload_ff, 512) == 0);
7148 : 24 : CU_ASSERT(memcmp(cluster0 + 3 * 512, payload_00, 512) == 0);
7149 : 24 : CU_ASSERT(memcmp(cluster0 + 4 * 512, payload_00, 28 * 512) == 0);
7150 : :
7151 : : /* Verify write with offset on first page */
7152 : 24 : iov[0].iov_base = payload_ff;
7153 : 24 : iov[0].iov_len = 4 * 512;
7154 : 24 : spdk_blob_io_writev(blob, channel, iov, 1, 4, 4, blob_op_complete, NULL);
7155 : 24 : poll_threads();
7156 : :
7157 : : /* cluster0: [ F0F0 FFFF | 0000 0000 | 0000 0000 | 0000 0000 ] */
7158 : 24 : CU_ASSERT(memcmp(cluster0 + 0 * 512, payload_ff, 512) == 0);
7159 : 24 : CU_ASSERT(memcmp(cluster0 + 1 * 512, payload_00, 512) == 0);
7160 : 24 : CU_ASSERT(memcmp(cluster0 + 2 * 512, payload_ff, 512) == 0);
7161 : 24 : CU_ASSERT(memcmp(cluster0 + 3 * 512, payload_00, 512) == 0);
7162 : 24 : CU_ASSERT(memcmp(cluster0 + 4 * 512, payload_ff, 4 * 512) == 0);
7163 : 24 : CU_ASSERT(memcmp(cluster0 + 8 * 512, payload_00, 24 * 512) == 0);
7164 : :
7165 : : /* Verify write with offset on second page */
7166 : 24 : iov[0].iov_base = payload_ff;
7167 : 24 : iov[0].iov_len = 4 * 512;
7168 : 24 : spdk_blob_io_writev(blob, channel, iov, 1, 8, 4, blob_op_complete, NULL);
7169 : 24 : poll_threads();
7170 : :
7171 : : /* cluster0: [ F0F0 FFFF | FFFF 0000 | 0000 0000 | 0000 0000 ] */
7172 : 24 : CU_ASSERT(memcmp(cluster0 + 0 * 512, payload_ff, 512) == 0);
7173 : 24 : CU_ASSERT(memcmp(cluster0 + 1 * 512, payload_00, 512) == 0);
7174 : 24 : CU_ASSERT(memcmp(cluster0 + 2 * 512, payload_ff, 512) == 0);
7175 : 24 : CU_ASSERT(memcmp(cluster0 + 3 * 512, payload_00, 512) == 0);
7176 : 24 : CU_ASSERT(memcmp(cluster0 + 4 * 512, payload_ff, 8 * 512) == 0);
7177 : 24 : CU_ASSERT(memcmp(cluster0 + 12 * 512, payload_00, 20 * 512) == 0);
7178 : :
7179 : : /* Verify write across multiple pages */
7180 : 24 : iov[0].iov_base = payload_aa;
7181 : 24 : iov[0].iov_len = 8 * 512;
7182 : :
7183 : 48 : test_blob_io_writev(blob, channel, iov, 1, 4, 8, blob_op_complete, NULL,
7184 [ + + ]: 24 : ext_api ? &ext_opts : NULL);
7185 : :
7186 : : /* cluster0: [ F0F0 AAAA | AAAA 0000 | 0000 0000 | 0000 0000 ] */
7187 : 24 : CU_ASSERT(memcmp(cluster0 + 0 * 512, payload_ff, 512) == 0);
7188 : 24 : CU_ASSERT(memcmp(cluster0 + 1 * 512, payload_00, 512) == 0);
7189 : 24 : CU_ASSERT(memcmp(cluster0 + 2 * 512, payload_ff, 512) == 0);
7190 : 24 : CU_ASSERT(memcmp(cluster0 + 3 * 512, payload_00, 512) == 0);
7191 : 24 : CU_ASSERT(memcmp(cluster0 + 4 * 512, payload_aa, 8 * 512) == 0);
7192 : 24 : CU_ASSERT(memcmp(cluster0 + 12 * 512, payload_00, 20 * 512) == 0);
7193 : :
7194 : : /* Verify write across multiple clusters */
7195 : :
7196 : 24 : iov[0].iov_base = payload_ff;
7197 : 24 : iov[0].iov_len = 8 * 512;
7198 : :
7199 : 48 : test_blob_io_writev(blob, channel, iov, 1, 28, 8, blob_op_complete, NULL,
7200 [ + + ]: 24 : ext_api ? &ext_opts : NULL);
7201 : :
7202 [ + - ]: 24 : SPDK_CU_ASSERT_FATAL(blob->active.clusters[1] != 0);
7203 : 24 : cluster1 = &g_dev_buffer[blob->active.clusters[1] * dev->blocklen];
7204 : :
7205 : : /* cluster0: [ F0F0 AAAA | AAAA 0000 | 0000 0000 | 0000 FFFF ]
7206 : : * cluster1: [ FFFF 0000 | 0000 0000 | 0000 0000 | 0000 0000 ] */
7207 : 24 : CU_ASSERT(memcmp(cluster0 + 0 * 512, payload_ff, 512) == 0);
7208 : 24 : CU_ASSERT(memcmp(cluster0 + 1 * 512, payload_00, 512) == 0);
7209 : 24 : CU_ASSERT(memcmp(cluster0 + 2 * 512, payload_ff, 512) == 0);
7210 : 24 : CU_ASSERT(memcmp(cluster0 + 3 * 512, payload_00, 512) == 0);
7211 : 24 : CU_ASSERT(memcmp(cluster0 + 4 * 512, payload_aa, 8 * 512) == 0);
7212 : 24 : CU_ASSERT(memcmp(cluster0 + 12 * 512, payload_00, 16 * 512) == 0);
7213 : 24 : CU_ASSERT(memcmp(cluster0 + 28 * 512, payload_ff, 4 * 512) == 0);
7214 : :
7215 : 24 : CU_ASSERT(memcmp(cluster1 + 0 * 512, payload_ff, 4 * 512) == 0);
7216 : 24 : CU_ASSERT(memcmp(cluster1 + 4 * 512, payload_00, 28 * 512) == 0);
7217 : :
7218 : : /* Verify write to second cluster */
7219 : :
7220 : 24 : iov[0].iov_base = payload_ff;
7221 : 24 : iov[0].iov_len = 2 * 512;
7222 : :
7223 : 48 : test_blob_io_writev(blob, channel, iov, 1, 32 + 12, 2, blob_op_complete, NULL,
7224 [ + + ]: 24 : ext_api ? &ext_opts : NULL);
7225 : :
7226 [ - + ]: 24 : SPDK_CU_ASSERT_FATAL(blob->active.clusters[1] != 0);
7227 : 24 : cluster1 = &g_dev_buffer[blob->active.clusters[1] * dev->blocklen];
7228 : :
7229 : : /* cluster0: [ F0F0 AAAA | AAAA 0000 | 0000 0000 | 0000 FFFF ]
7230 : : * cluster1: [ FFFF 0000 | 0000 FF00 | 0000 0000 | 0000 0000 ] */
7231 : 24 : CU_ASSERT(memcmp(cluster0 + 0 * 512, payload_ff, 512) == 0);
7232 : 24 : CU_ASSERT(memcmp(cluster0 + 1 * 512, payload_00, 512) == 0);
7233 : 24 : CU_ASSERT(memcmp(cluster0 + 2 * 512, payload_ff, 512) == 0);
7234 : 24 : CU_ASSERT(memcmp(cluster0 + 3 * 512, payload_00, 512) == 0);
7235 : 24 : CU_ASSERT(memcmp(cluster0 + 4 * 512, payload_aa, 8 * 512) == 0);
7236 : 24 : CU_ASSERT(memcmp(cluster0 + 28 * 512, payload_ff, 4 * 512) == 0);
7237 : :
7238 : 24 : CU_ASSERT(memcmp(cluster1 + 0 * 512, payload_ff, 4 * 512) == 0);
7239 : 24 : CU_ASSERT(memcmp(cluster1 + 4 * 512, payload_00, 8 * 512) == 0);
7240 : 24 : CU_ASSERT(memcmp(cluster1 + 12 * 512, payload_ff, 2 * 512) == 0);
7241 : 24 : CU_ASSERT(memcmp(cluster1 + 14 * 512, payload_00, 18 * 512) == 0);
7242 : 24 : }
7243 : :
7244 : : static inline void
7245 : 336 : test_blob_io_readv(struct spdk_blob *blob, struct spdk_io_channel *channel,
7246 : : struct iovec *iov, int iovcnt, uint64_t offset, uint64_t length,
7247 : : spdk_blob_op_complete cb_fn, void *cb_arg, struct spdk_blob_ext_io_opts *io_opts)
7248 : : {
7249 [ + + ]: 336 : if (io_opts) {
7250 : 168 : g_dev_readv_ext_called = false;
7251 : 168 : memset(&g_blob_ext_io_opts, 0, sizeof(g_blob_ext_io_opts));
7252 : 168 : spdk_blob_io_readv_ext(blob, channel, iov, iovcnt, offset, length, blob_op_complete, NULL, io_opts);
7253 : 168 : } else {
7254 : 168 : spdk_blob_io_readv(blob, channel, iov, iovcnt, offset, length, blob_op_complete, NULL);
7255 : : }
7256 : 336 : poll_threads();
7257 : 336 : CU_ASSERT(g_bserrno == 0);
7258 [ + + ]: 336 : if (io_opts) {
7259 : 168 : CU_ASSERT(g_dev_readv_ext_called);
7260 : 168 : CU_ASSERT(memcmp(io_opts, &g_blob_ext_io_opts, sizeof(g_blob_ext_io_opts)) == 0);
7261 : 168 : }
7262 : 336 : }
7263 : :
7264 : : static void
7265 : 48 : test_iov_read(struct spdk_bs_dev *dev, struct spdk_blob *blob, struct spdk_io_channel *channel,
7266 : : bool ext_api)
7267 : : {
7268 : : uint8_t payload_read[64 * 512];
7269 : : uint8_t payload_ff[64 * 512];
7270 : : uint8_t payload_aa[64 * 512];
7271 : : uint8_t payload_00[64 * 512];
7272 : : struct iovec iov[4];
7273 : 48 : struct spdk_blob_ext_io_opts ext_opts = {
7274 : : .memory_domain = (struct spdk_memory_domain *)0xfeedbeef,
7275 : : .memory_domain_ctx = (void *)0xf00df00d,
7276 : : .size = sizeof(struct spdk_blob_ext_io_opts),
7277 : : .user_ctx = (void *)123,
7278 : : };
7279 : :
7280 : 48 : memset(payload_ff, 0xFF, sizeof(payload_ff));
7281 : 48 : memset(payload_aa, 0xAA, sizeof(payload_aa));
7282 : 48 : memset(payload_00, 0x00, sizeof(payload_00));
7283 : :
7284 : : /* Read only first io unit */
7285 : : /* cluster0: [ (F)0F0 AAAA | AAAA 0000 | 0000 0000 | 0000 FFFF ]
7286 : : * cluster1: [ FFFF 0000 | 0000 FF00 | 0000 0000 | 0000 0000 ]
7287 : : * payload_read: F000 0000 | 0000 0000 ... */
7288 : 48 : memset(payload_read, 0x00, sizeof(payload_read));
7289 : 48 : iov[0].iov_base = payload_read;
7290 : 48 : iov[0].iov_len = 1 * 512;
7291 : :
7292 [ + + ]: 48 : test_blob_io_readv(blob, channel, iov, 1, 0, 1, blob_op_complete, NULL, ext_api ? &ext_opts : NULL);
7293 : :
7294 : 48 : CU_ASSERT(memcmp(payload_read + 0 * 512, payload_ff, 512) == 0);
7295 : 48 : CU_ASSERT(memcmp(payload_read + 1 * 512, payload_00, 31 * 512) == 0);
7296 : :
7297 : : /* Read four io_units starting from offset = 2
7298 : : * cluster0: [ F0(F0 AA)AA | AAAA 0000 | 0000 0000 | 0000 FFFF ]
7299 : : * cluster1: [ FFFF 0000 | 0000 FF00 | 0000 0000 | 0000 0000 ]
7300 : : * payload_read: F0AA 0000 | 0000 0000 ... */
7301 : :
7302 : 48 : memset(payload_read, 0x00, sizeof(payload_read));
7303 : 48 : iov[0].iov_base = payload_read;
7304 : 48 : iov[0].iov_len = 4 * 512;
7305 : :
7306 [ + + ]: 48 : test_blob_io_readv(blob, channel, iov, 1, 2, 4, blob_op_complete, NULL, ext_api ? &ext_opts : NULL);
7307 : :
7308 : 48 : CU_ASSERT(memcmp(payload_read + 0 * 512, payload_ff, 512) == 0);
7309 : 48 : CU_ASSERT(memcmp(payload_read + 1 * 512, payload_00, 512) == 0);
7310 : 48 : CU_ASSERT(memcmp(payload_read + 2 * 512, payload_aa, 512) == 0);
7311 : 48 : CU_ASSERT(memcmp(payload_read + 3 * 512, payload_aa, 512) == 0);
7312 : 48 : CU_ASSERT(memcmp(payload_read + 4 * 512, payload_00, 28 * 512) == 0);
7313 : :
7314 : : /* Read eight io_units across multiple pages
7315 : : * cluster0: [ F0F0 (AAAA | AAAA) 0000 | 0000 0000 | 0000 FFFF ]
7316 : : * cluster1: [ FFFF 0000 | 0000 FF00 | 0000 0000 | 0000 0000 ]
7317 : : * payload_read: AAAA AAAA | 0000 0000 ... */
7318 : 48 : memset(payload_read, 0x00, sizeof(payload_read));
7319 : 48 : iov[0].iov_base = payload_read;
7320 : 48 : iov[0].iov_len = 4 * 512;
7321 : 48 : iov[1].iov_base = payload_read + 4 * 512;
7322 : 48 : iov[1].iov_len = 4 * 512;
7323 : :
7324 [ + + ]: 48 : test_blob_io_readv(blob, channel, iov, 2, 4, 8, blob_op_complete, NULL, ext_api ? &ext_opts : NULL);
7325 : :
7326 : 48 : CU_ASSERT(memcmp(payload_read + 0 * 512, payload_aa, 8 * 512) == 0);
7327 : 48 : CU_ASSERT(memcmp(payload_read + 8 * 512, payload_00, 24 * 512) == 0);
7328 : :
7329 : : /* Read eight io_units across multiple clusters
7330 : : * cluster0: [ F0F0 AAAA | AAAA 0000 | 0000 0000 | 0000 (FFFF ]
7331 : : * cluster1: [ FFFF) 0000 | 0000 FF00 | 0000 0000 | 0000 0000 ]
7332 : : * payload_read: FFFF FFFF | 0000 0000 ... */
7333 : 48 : memset(payload_read, 0x00, sizeof(payload_read));
7334 : 48 : iov[0].iov_base = payload_read;
7335 : 48 : iov[0].iov_len = 2 * 512;
7336 : 48 : iov[1].iov_base = payload_read + 2 * 512;
7337 : 48 : iov[1].iov_len = 2 * 512;
7338 : 48 : iov[2].iov_base = payload_read + 4 * 512;
7339 : 48 : iov[2].iov_len = 2 * 512;
7340 : 48 : iov[3].iov_base = payload_read + 6 * 512;
7341 : 48 : iov[3].iov_len = 2 * 512;
7342 : :
7343 : 96 : test_blob_io_readv(blob, channel, iov, 4, 28, 8, blob_op_complete, NULL,
7344 [ + + ]: 48 : ext_api ? &ext_opts : NULL);
7345 : :
7346 : 48 : CU_ASSERT(memcmp(payload_read + 0 * 512, payload_ff, 8 * 512) == 0);
7347 : 48 : CU_ASSERT(memcmp(payload_read + 8 * 512, payload_00, 24 * 512) == 0);
7348 : :
7349 : : /* Read four io_units from second cluster
7350 : : * cluster0: [ F0F0 AAAA | AAAA 0000 | 0000 0000 | 0000 FFFF ]
7351 : : * cluster1: [ FFFF 0000 | 00(00 FF)00 | 0000 0000 | 0000 0000 ]
7352 : : * payload_read: 00FF 0000 | 0000 0000 ... */
7353 : 48 : memset(payload_read, 0x00, sizeof(payload_read));
7354 : 48 : iov[0].iov_base = payload_read;
7355 : 48 : iov[0].iov_len = 1 * 512;
7356 : 48 : iov[1].iov_base = payload_read + 1 * 512;
7357 : 48 : iov[1].iov_len = 3 * 512;
7358 : :
7359 : 96 : test_blob_io_readv(blob, channel, iov, 2, 32 + 10, 4, blob_op_complete, NULL,
7360 [ + + ]: 48 : ext_api ? &ext_opts : NULL);
7361 : :
7362 : 48 : CU_ASSERT(memcmp(payload_read + 0 * 512, payload_00, 2 * 512) == 0);
7363 : 48 : CU_ASSERT(memcmp(payload_read + 2 * 512, payload_ff, 2 * 512) == 0);
7364 : 48 : CU_ASSERT(memcmp(payload_read + 4 * 512, payload_00, 28 * 512) == 0);
7365 : :
7366 : : /* Read second cluster
7367 : : * cluster0: [ F0F0 AAAA | AAAA 0000 | 0000 0000 | 0000 FFFF ]
7368 : : * cluster1: [ (FFFF 0000 | 0000 FF00 | 0000 0000 | 0000 0000) ]
7369 : : * payload_read: FFFF 0000 | 0000 FF00 ... */
7370 : 48 : memset(payload_read, 0x00, sizeof(payload_read));
7371 : 48 : iov[0].iov_base = payload_read;
7372 : 48 : iov[0].iov_len = 1 * 512;
7373 : 48 : iov[1].iov_base = payload_read + 1 * 512;
7374 : 48 : iov[1].iov_len = 2 * 512;
7375 : 48 : iov[2].iov_base = payload_read + 3 * 512;
7376 : 48 : iov[2].iov_len = 4 * 512;
7377 : 48 : iov[3].iov_base = payload_read + 7 * 512;
7378 : 48 : iov[3].iov_len = 25 * 512;
7379 : :
7380 : 96 : test_blob_io_readv(blob, channel, iov, 4, 32, 32, blob_op_complete, NULL,
7381 [ + + ]: 48 : ext_api ? &ext_opts : NULL);
7382 : :
7383 : 48 : CU_ASSERT(memcmp(payload_read + 0 * 512, payload_ff, 4 * 512) == 0);
7384 : 48 : CU_ASSERT(memcmp(payload_read + 4 * 512, payload_00, 8 * 512) == 0);
7385 : 48 : CU_ASSERT(memcmp(payload_read + 12 * 512, payload_ff, 2 * 512) == 0);
7386 : 48 : CU_ASSERT(memcmp(payload_read + 14 * 512, payload_00, 18 * 512) == 0);
7387 : :
7388 : : /* Read whole two clusters
7389 : : * cluster0: [ (F0F0 AAAA | AAAA) 0000 | 0000 0000 | 0000 FFFF ]
7390 : : * cluster1: [ FFFF 0000 | 0000 FF00 | 0000 0000 | 0000 0000) ] */
7391 : 48 : memset(payload_read, 0x00, sizeof(payload_read));
7392 : 48 : iov[0].iov_base = payload_read;
7393 : 48 : iov[0].iov_len = 1 * 512;
7394 : 48 : iov[1].iov_base = payload_read + 1 * 512;
7395 : 48 : iov[1].iov_len = 8 * 512;
7396 : 48 : iov[2].iov_base = payload_read + 9 * 512;
7397 : 48 : iov[2].iov_len = 16 * 512;
7398 : 48 : iov[3].iov_base = payload_read + 25 * 512;
7399 : 48 : iov[3].iov_len = 39 * 512;
7400 : :
7401 : 96 : test_blob_io_readv(blob, channel, iov, 4, 0, 64, blob_op_complete, NULL,
7402 [ + + ]: 48 : ext_api ? &ext_opts : NULL);
7403 : :
7404 : 48 : CU_ASSERT(memcmp(payload_read + 0 * 512, payload_ff, 512) == 0);
7405 : 48 : CU_ASSERT(memcmp(payload_read + 1 * 512, payload_00, 512) == 0);
7406 : 48 : CU_ASSERT(memcmp(payload_read + 2 * 512, payload_ff, 512) == 0);
7407 : 48 : CU_ASSERT(memcmp(payload_read + 3 * 512, payload_00, 512) == 0);
7408 : 48 : CU_ASSERT(memcmp(payload_read + 4 * 512, payload_aa, 8 * 512) == 0);
7409 : 48 : CU_ASSERT(memcmp(payload_read + 28 * 512, payload_ff, 4 * 512) == 0);
7410 : :
7411 : 48 : CU_ASSERT(memcmp(payload_read + (32 + 0) * 512, payload_ff, 4 * 512) == 0);
7412 : 48 : CU_ASSERT(memcmp(payload_read + (32 + 4) * 512, payload_00, 8 * 512) == 0);
7413 : 48 : CU_ASSERT(memcmp(payload_read + (32 + 12) * 512, payload_ff, 2 * 512) == 0);
7414 : 48 : CU_ASSERT(memcmp(payload_read + (32 + 14) * 512, payload_00, 18 * 512) == 0);
7415 : 48 : }
7416 : :
7417 : : static void
7418 : 4 : blob_io_unit(void)
7419 : : {
7420 : : struct spdk_bs_opts bsopts;
7421 : : struct spdk_blob_opts opts;
7422 : : struct spdk_blob_store *bs;
7423 : : struct spdk_bs_dev *dev;
7424 : : struct spdk_blob *blob, *snapshot, *clone;
7425 : : spdk_blob_id blobid;
7426 : : struct spdk_io_channel *channel;
7427 : :
7428 : : /* Create dev with 512 bytes io unit size */
7429 : :
7430 : 4 : spdk_bs_opts_init(&bsopts, sizeof(bsopts));
7431 : 4 : bsopts.cluster_sz = SPDK_BS_PAGE_SIZE * 4; /* 8 * 4 = 32 io_unit */
7432 : 4 : snprintf(bsopts.bstype.bstype, sizeof(bsopts.bstype.bstype), "TESTTYPE");
7433 : :
7434 : : /* Try to initialize a new blob store with unsupported io_unit */
7435 : 4 : dev = init_dev();
7436 : 4 : dev->blocklen = 512;
7437 : 4 : dev->blockcnt = DEV_BUFFER_SIZE / dev->blocklen;
7438 : :
7439 : : /* Initialize a new blob store */
7440 : 4 : spdk_bs_init(dev, &bsopts, bs_op_with_handle_complete, NULL);
7441 : 4 : poll_threads();
7442 : 4 : CU_ASSERT(g_bserrno == 0);
7443 [ + - ]: 4 : SPDK_CU_ASSERT_FATAL(g_bs != NULL);
7444 : 4 : bs = g_bs;
7445 : :
7446 : 4 : CU_ASSERT(spdk_bs_get_io_unit_size(bs) == 512);
7447 : 4 : channel = spdk_bs_alloc_io_channel(bs);
7448 : :
7449 : : /* Create thick provisioned blob */
7450 : 4 : ut_spdk_blob_opts_init(&opts);
7451 : 4 : opts.thin_provision = false;
7452 : 4 : opts.num_clusters = 32;
7453 : :
7454 : 4 : blob = ut_blob_create_and_open(bs, &opts);
7455 : 4 : blobid = spdk_blob_get_id(blob);
7456 : :
7457 : 4 : test_io_write(dev, blob, channel);
7458 : 4 : test_io_read(dev, blob, channel);
7459 : 4 : test_io_zeroes(dev, blob, channel);
7460 : :
7461 : 4 : test_iov_write(dev, blob, channel, false);
7462 : 4 : test_iov_read(dev, blob, channel, false);
7463 : 4 : test_io_zeroes(dev, blob, channel);
7464 : :
7465 : 4 : test_iov_write(dev, blob, channel, true);
7466 : 4 : test_iov_read(dev, blob, channel, true);
7467 : :
7468 : 4 : test_io_unmap(dev, blob, channel);
7469 : :
7470 : 4 : spdk_blob_close(blob, blob_op_complete, NULL);
7471 : 4 : poll_threads();
7472 : 4 : CU_ASSERT(g_bserrno == 0);
7473 : 4 : blob = NULL;
7474 : 4 : g_blob = NULL;
7475 : :
7476 : : /* Create thin provisioned blob */
7477 : :
7478 : 4 : ut_spdk_blob_opts_init(&opts);
7479 : 4 : opts.thin_provision = true;
7480 : 4 : opts.num_clusters = 32;
7481 : :
7482 : 4 : blob = ut_blob_create_and_open(bs, &opts);
7483 : 4 : blobid = spdk_blob_get_id(blob);
7484 : :
7485 : 4 : test_io_write(dev, blob, channel);
7486 : 4 : test_io_read(dev, blob, channel);
7487 : 4 : test_io_zeroes(dev, blob, channel);
7488 : :
7489 : 4 : test_iov_write(dev, blob, channel, false);
7490 : 4 : test_iov_read(dev, blob, channel, false);
7491 : 4 : test_io_zeroes(dev, blob, channel);
7492 : :
7493 : 4 : test_iov_write(dev, blob, channel, true);
7494 : 4 : test_iov_read(dev, blob, channel, true);
7495 : :
7496 : : /* Create snapshot */
7497 : :
7498 : 4 : spdk_bs_create_snapshot(bs, blobid, NULL, blob_op_with_id_complete, NULL);
7499 : 4 : poll_threads();
7500 : 4 : CU_ASSERT(g_bserrno == 0);
7501 : 4 : CU_ASSERT(g_blobid != SPDK_BLOBID_INVALID);
7502 : 4 : blobid = g_blobid;
7503 : :
7504 : 4 : spdk_bs_open_blob(bs, blobid, blob_op_with_handle_complete, NULL);
7505 : 4 : poll_threads();
7506 : 4 : CU_ASSERT(g_bserrno == 0);
7507 : 4 : CU_ASSERT(g_blob != NULL);
7508 : 4 : snapshot = g_blob;
7509 : :
7510 : 4 : spdk_bs_create_clone(bs, blobid, NULL, blob_op_with_id_complete, NULL);
7511 : 4 : poll_threads();
7512 : 4 : CU_ASSERT(g_bserrno == 0);
7513 : 4 : CU_ASSERT(g_blobid != SPDK_BLOBID_INVALID);
7514 : 4 : blobid = g_blobid;
7515 : :
7516 : 4 : spdk_bs_open_blob(bs, blobid, blob_op_with_handle_complete, NULL);
7517 : 4 : poll_threads();
7518 : 4 : CU_ASSERT(g_bserrno == 0);
7519 : 4 : CU_ASSERT(g_blob != NULL);
7520 : 4 : clone = g_blob;
7521 : :
7522 : 4 : test_io_read(dev, blob, channel);
7523 : 4 : test_io_read(dev, snapshot, channel);
7524 : 4 : test_io_read(dev, clone, channel);
7525 : :
7526 : 4 : test_iov_read(dev, blob, channel, false);
7527 : 4 : test_iov_read(dev, snapshot, channel, false);
7528 : 4 : test_iov_read(dev, clone, channel, false);
7529 : :
7530 : 4 : test_iov_read(dev, blob, channel, true);
7531 : 4 : test_iov_read(dev, snapshot, channel, true);
7532 : 4 : test_iov_read(dev, clone, channel, true);
7533 : :
7534 : : /* Inflate clone */
7535 : :
7536 : 4 : spdk_bs_inflate_blob(bs, channel, blobid, blob_op_complete, NULL);
7537 : 4 : poll_threads();
7538 : :
7539 : 4 : CU_ASSERT(g_bserrno == 0);
7540 : :
7541 : 4 : test_io_read(dev, clone, channel);
7542 : :
7543 : 4 : test_io_unmap(dev, clone, channel);
7544 : :
7545 : 4 : test_iov_write(dev, clone, channel, false);
7546 : 4 : test_iov_read(dev, clone, channel, false);
7547 : 4 : test_io_unmap(dev, clone, channel);
7548 : :
7549 : 4 : test_iov_write(dev, clone, channel, true);
7550 : 4 : test_iov_read(dev, clone, channel, true);
7551 : :
7552 : 4 : spdk_blob_close(blob, blob_op_complete, NULL);
7553 : 4 : spdk_blob_close(snapshot, blob_op_complete, NULL);
7554 : 4 : spdk_blob_close(clone, blob_op_complete, NULL);
7555 : 4 : poll_threads();
7556 : 4 : CU_ASSERT(g_bserrno == 0);
7557 : 4 : blob = NULL;
7558 : 4 : g_blob = NULL;
7559 : :
7560 : 4 : spdk_bs_free_io_channel(channel);
7561 : 4 : poll_threads();
7562 : :
7563 : : /* Unload the blob store */
7564 : 4 : spdk_bs_unload(bs, bs_op_complete, NULL);
7565 : 4 : poll_threads();
7566 : 4 : CU_ASSERT(g_bserrno == 0);
7567 : 4 : g_bs = NULL;
7568 : 4 : g_blob = NULL;
7569 : 4 : g_blobid = 0;
7570 : 4 : }
7571 : :
7572 : : static void
7573 : 4 : blob_io_unit_compatibility(void)
7574 : : {
7575 : : struct spdk_bs_opts bsopts;
7576 : : struct spdk_blob_store *bs;
7577 : : struct spdk_bs_dev *dev;
7578 : : struct spdk_bs_super_block *super;
7579 : :
7580 : : /* Create dev with 512 bytes io unit size */
7581 : :
7582 : 4 : spdk_bs_opts_init(&bsopts, sizeof(bsopts));
7583 : 4 : bsopts.cluster_sz = SPDK_BS_PAGE_SIZE * 4; /* 8 * 4 = 32 io_unit */
7584 : 4 : snprintf(bsopts.bstype.bstype, sizeof(bsopts.bstype.bstype), "TESTTYPE");
7585 : :
7586 : : /* Try to initialize a new blob store with unsupported io_unit */
7587 : 4 : dev = init_dev();
7588 : 4 : dev->blocklen = 512;
7589 : 4 : dev->blockcnt = DEV_BUFFER_SIZE / dev->blocklen;
7590 : :
7591 : : /* Initialize a new blob store */
7592 : 4 : spdk_bs_init(dev, &bsopts, bs_op_with_handle_complete, NULL);
7593 : 4 : poll_threads();
7594 : 4 : CU_ASSERT(g_bserrno == 0);
7595 [ + - ]: 4 : SPDK_CU_ASSERT_FATAL(g_bs != NULL);
7596 : 4 : bs = g_bs;
7597 : :
7598 : 4 : CU_ASSERT(spdk_bs_get_io_unit_size(bs) == 512);
7599 : :
7600 : : /* Unload the blob store */
7601 : 4 : spdk_bs_unload(bs, bs_op_complete, NULL);
7602 : 4 : poll_threads();
7603 : 4 : CU_ASSERT(g_bserrno == 0);
7604 : :
7605 : : /* Modify super block to behave like older version.
7606 : : * Check if loaded io unit size equals SPDK_BS_PAGE_SIZE */
7607 : 4 : super = (struct spdk_bs_super_block *)&g_dev_buffer[0];
7608 : 4 : super->io_unit_size = 0;
7609 : 4 : super->crc = blob_md_page_calc_crc(super);
7610 : :
7611 : 4 : dev = init_dev();
7612 : 4 : dev->blocklen = 512;
7613 : 4 : dev->blockcnt = DEV_BUFFER_SIZE / dev->blocklen;
7614 : :
7615 : 4 : spdk_bs_load(dev, &bsopts, bs_op_with_handle_complete, NULL);
7616 : 4 : poll_threads();
7617 : 4 : CU_ASSERT(g_bserrno == 0);
7618 [ - + ]: 4 : SPDK_CU_ASSERT_FATAL(g_bs != NULL);
7619 : 4 : bs = g_bs;
7620 : :
7621 : 4 : CU_ASSERT(spdk_bs_get_io_unit_size(bs) == SPDK_BS_PAGE_SIZE);
7622 : :
7623 : : /* Unload the blob store */
7624 : 4 : spdk_bs_unload(bs, bs_op_complete, NULL);
7625 : 4 : poll_threads();
7626 : 4 : CU_ASSERT(g_bserrno == 0);
7627 : :
7628 : 4 : g_bs = NULL;
7629 : 4 : g_blob = NULL;
7630 : 4 : g_blobid = 0;
7631 : 4 : }
7632 : :
7633 : : static void
7634 : 4 : first_sync_complete(void *cb_arg, int bserrno)
7635 : : {
7636 : 4 : struct spdk_blob *blob = cb_arg;
7637 : : int rc;
7638 : :
7639 : 4 : CU_ASSERT(bserrno == 0);
7640 : 4 : rc = spdk_blob_set_xattr(blob, "sync", "second", strlen("second") + 1);
7641 : 4 : CU_ASSERT(rc == 0);
7642 : 4 : CU_ASSERT(g_bserrno == -1);
7643 : :
7644 : : /* Keep g_bserrno at -1, only the
7645 : : * second sync completion should set it at 0. */
7646 : 4 : }
7647 : :
7648 : : static void
7649 : 4 : second_sync_complete(void *cb_arg, int bserrno)
7650 : : {
7651 : 4 : struct spdk_blob *blob = cb_arg;
7652 : : const void *value;
7653 : : size_t value_len;
7654 : : int rc;
7655 : :
7656 : 4 : CU_ASSERT(bserrno == 0);
7657 : :
7658 : : /* Verify that the first sync completion had a chance to execute */
7659 : 4 : rc = spdk_blob_get_xattr_value(blob, "sync", &value, &value_len);
7660 : 4 : CU_ASSERT(rc == 0);
7661 [ + - ]: 4 : SPDK_CU_ASSERT_FATAL(value != NULL);
7662 : 4 : CU_ASSERT(value_len == strlen("second") + 1);
7663 : 4 : CU_ASSERT_NSTRING_EQUAL_FATAL(value, "second", value_len);
7664 : :
7665 : 4 : CU_ASSERT(g_bserrno == -1);
7666 : 4 : g_bserrno = bserrno;
7667 : 4 : }
7668 : :
7669 : : static void
7670 : 4 : blob_simultaneous_operations(void)
7671 : : {
7672 : 4 : struct spdk_blob_store *bs = g_bs;
7673 : : struct spdk_blob_opts opts;
7674 : : struct spdk_blob *blob, *snapshot;
7675 : : spdk_blob_id blobid, snapshotid;
7676 : : struct spdk_io_channel *channel;
7677 : : int rc;
7678 : :
7679 : 4 : channel = spdk_bs_alloc_io_channel(bs);
7680 [ + - ]: 4 : SPDK_CU_ASSERT_FATAL(channel != NULL);
7681 : :
7682 : 4 : ut_spdk_blob_opts_init(&opts);
7683 : 4 : opts.num_clusters = 10;
7684 : :
7685 : 4 : blob = ut_blob_create_and_open(bs, &opts);
7686 : 4 : blobid = spdk_blob_get_id(blob);
7687 : :
7688 : : /* Create snapshot and try to remove blob in the same time:
7689 : : * - snapshot should be created successfully
7690 : : * - delete operation should fail w -EBUSY */
7691 : 4 : CU_ASSERT(blob->locked_operation_in_progress == false);
7692 : 4 : spdk_bs_create_snapshot(bs, blobid, NULL, blob_op_with_id_complete, NULL);
7693 : 4 : CU_ASSERT(blob->locked_operation_in_progress == true);
7694 : 4 : spdk_bs_delete_blob(bs, blobid, blob_op_complete, NULL);
7695 : 4 : CU_ASSERT(blob->locked_operation_in_progress == true);
7696 : : /* Deletion failure */
7697 : 4 : CU_ASSERT(g_bserrno == -EBUSY);
7698 : 4 : poll_threads();
7699 : 4 : CU_ASSERT(blob->locked_operation_in_progress == false);
7700 : : /* Snapshot creation success */
7701 : 4 : CU_ASSERT(g_bserrno == 0);
7702 : 4 : CU_ASSERT(g_blobid != SPDK_BLOBID_INVALID);
7703 : :
7704 : 4 : snapshotid = g_blobid;
7705 : :
7706 : 4 : spdk_bs_open_blob(bs, snapshotid, blob_op_with_handle_complete, NULL);
7707 : 4 : poll_threads();
7708 : 4 : CU_ASSERT(g_bserrno == 0);
7709 [ - + ]: 4 : SPDK_CU_ASSERT_FATAL(g_blob != NULL);
7710 : 4 : snapshot = g_blob;
7711 : :
7712 : : /* Inflate blob and try to remove blob in the same time:
7713 : : * - blob should be inflated successfully
7714 : : * - delete operation should fail w -EBUSY */
7715 : 4 : CU_ASSERT(blob->locked_operation_in_progress == false);
7716 : 4 : spdk_bs_inflate_blob(bs, channel, blobid, blob_op_complete, NULL);
7717 : 4 : CU_ASSERT(blob->locked_operation_in_progress == true);
7718 : 4 : spdk_bs_delete_blob(bs, blobid, blob_op_complete, NULL);
7719 : 4 : CU_ASSERT(blob->locked_operation_in_progress == true);
7720 : : /* Deletion failure */
7721 : 4 : CU_ASSERT(g_bserrno == -EBUSY);
7722 : 4 : poll_threads();
7723 : 4 : CU_ASSERT(blob->locked_operation_in_progress == false);
7724 : : /* Inflation success */
7725 : 4 : CU_ASSERT(g_bserrno == 0);
7726 : :
7727 : : /* Clone snapshot and try to remove snapshot in the same time:
7728 : : * - snapshot should be cloned successfully
7729 : : * - delete operation should fail w -EBUSY */
7730 : 4 : CU_ASSERT(blob->locked_operation_in_progress == false);
7731 : 4 : spdk_bs_create_clone(bs, snapshotid, NULL, blob_op_with_id_complete, NULL);
7732 : 4 : spdk_bs_delete_blob(bs, snapshotid, blob_op_complete, NULL);
7733 : : /* Deletion failure */
7734 : 4 : CU_ASSERT(g_bserrno == -EBUSY);
7735 : 4 : poll_threads();
7736 : 4 : CU_ASSERT(blob->locked_operation_in_progress == false);
7737 : : /* Clone created */
7738 : 4 : CU_ASSERT(g_bserrno == 0);
7739 : :
7740 : : /* Resize blob and try to remove blob in the same time:
7741 : : * - blob should be resized successfully
7742 : : * - delete operation should fail w -EBUSY */
7743 : 4 : CU_ASSERT(blob->locked_operation_in_progress == false);
7744 : 4 : spdk_blob_resize(blob, 50, blob_op_complete, NULL);
7745 : 4 : CU_ASSERT(blob->locked_operation_in_progress == true);
7746 : 4 : spdk_bs_delete_blob(bs, blobid, blob_op_complete, NULL);
7747 : 4 : CU_ASSERT(blob->locked_operation_in_progress == true);
7748 : : /* Deletion failure */
7749 : 4 : CU_ASSERT(g_bserrno == -EBUSY);
7750 : 4 : poll_threads();
7751 : 4 : CU_ASSERT(blob->locked_operation_in_progress == false);
7752 : : /* Blob resized successfully */
7753 : 4 : spdk_blob_sync_md(blob, blob_op_complete, NULL);
7754 : 4 : poll_threads();
7755 : 4 : CU_ASSERT(g_bserrno == 0);
7756 : :
7757 : : /* Issue two consecutive blob syncs, neither should fail.
7758 : : * Force sync to actually occur by marking blob dirty each time.
7759 : : * Execution of sync should not be enough to complete the operation,
7760 : : * since disk I/O is required to complete it. */
7761 : 4 : g_bserrno = -1;
7762 : :
7763 : 4 : rc = spdk_blob_set_xattr(blob, "sync", "first", strlen("first") + 1);
7764 : 4 : CU_ASSERT(rc == 0);
7765 : 4 : spdk_blob_sync_md(blob, first_sync_complete, blob);
7766 : 4 : CU_ASSERT(g_bserrno == -1);
7767 : :
7768 : 4 : spdk_blob_sync_md(blob, second_sync_complete, blob);
7769 : 4 : CU_ASSERT(g_bserrno == -1);
7770 : :
7771 : 4 : poll_threads();
7772 : 4 : CU_ASSERT(g_bserrno == 0);
7773 : :
7774 : 4 : spdk_bs_free_io_channel(channel);
7775 : 4 : poll_threads();
7776 : :
7777 : 4 : ut_blob_close_and_delete(bs, snapshot);
7778 : 4 : ut_blob_close_and_delete(bs, blob);
7779 : 4 : }
7780 : :
7781 : : static void
7782 : 4 : blob_persist_test(void)
7783 : : {
7784 : 4 : struct spdk_blob_store *bs = g_bs;
7785 : : struct spdk_blob_opts opts;
7786 : : struct spdk_blob *blob;
7787 : : spdk_blob_id blobid;
7788 : : struct spdk_io_channel *channel;
7789 : : char *xattr;
7790 : : size_t xattr_length;
7791 : : int rc;
7792 : : uint32_t page_count_clear, page_count_xattr;
7793 : : uint64_t poller_iterations;
7794 : : bool run_poller;
7795 : :
7796 : 4 : channel = spdk_bs_alloc_io_channel(bs);
7797 [ + - ]: 4 : SPDK_CU_ASSERT_FATAL(channel != NULL);
7798 : :
7799 : 4 : ut_spdk_blob_opts_init(&opts);
7800 : 4 : opts.num_clusters = 10;
7801 : :
7802 : 4 : blob = ut_blob_create_and_open(bs, &opts);
7803 : 4 : blobid = spdk_blob_get_id(blob);
7804 : :
7805 : : /* Save the amount of md pages used after creation of a blob.
7806 : : * This should be consistent after removing xattr. */
7807 : 4 : page_count_clear = spdk_bit_array_count_set(bs->used_md_pages);
7808 [ + - ]: 4 : SPDK_CU_ASSERT_FATAL(blob->active.num_pages + blob->active.num_extent_pages == page_count_clear);
7809 [ + - ]: 4 : SPDK_CU_ASSERT_FATAL(blob->clean.num_pages + blob->clean.num_extent_pages == page_count_clear);
7810 : :
7811 : : /* Add xattr with maximum length of descriptor to exceed single metadata page. */
7812 : 4 : xattr_length = SPDK_BS_MAX_DESC_SIZE - sizeof(struct spdk_blob_md_descriptor_xattr) -
7813 : : strlen("large_xattr");
7814 : 4 : xattr = calloc(xattr_length, sizeof(char));
7815 [ + - ]: 4 : SPDK_CU_ASSERT_FATAL(xattr != NULL);
7816 : :
7817 : 4 : rc = spdk_blob_set_xattr(blob, "large_xattr", xattr, xattr_length);
7818 [ + - ]: 4 : SPDK_CU_ASSERT_FATAL(rc == 0);
7819 : 4 : spdk_blob_sync_md(blob, blob_op_complete, NULL);
7820 : 4 : poll_threads();
7821 [ + - ]: 4 : SPDK_CU_ASSERT_FATAL(g_bserrno == 0);
7822 : :
7823 : : /* Save the amount of md pages used after adding the large xattr */
7824 : 4 : page_count_xattr = spdk_bit_array_count_set(bs->used_md_pages);
7825 [ + - ]: 4 : SPDK_CU_ASSERT_FATAL(blob->active.num_pages + blob->active.num_extent_pages == page_count_xattr);
7826 [ - + ]: 4 : SPDK_CU_ASSERT_FATAL(blob->clean.num_pages + blob->clean.num_extent_pages == page_count_xattr);
7827 : :
7828 : : /* Add xattr to a blob and sync it. While sync is occurring, remove the xattr and sync again.
7829 : : * Interrupt the first sync after increasing number of poller iterations, until it succeeds.
7830 : : * Expectation is that after second sync completes no xattr is saved in metadata. */
7831 : 4 : poller_iterations = 1;
7832 : 4 : run_poller = true;
7833 [ + + ]: 28 : while (run_poller) {
7834 : 24 : rc = spdk_blob_set_xattr(blob, "large_xattr", xattr, xattr_length);
7835 [ + - ]: 24 : SPDK_CU_ASSERT_FATAL(rc == 0);
7836 : 24 : g_bserrno = -1;
7837 : 24 : spdk_blob_sync_md(blob, blob_op_complete, NULL);
7838 : 24 : poll_thread_times(0, poller_iterations);
7839 [ + + ]: 24 : if (g_bserrno == 0) {
7840 : : /* Poller iteration count was high enough for first sync to complete.
7841 : : * Verify that blob takes up enough of md_pages to store the xattr. */
7842 [ + - ]: 4 : SPDK_CU_ASSERT_FATAL(blob->active.num_pages + blob->active.num_extent_pages == page_count_xattr);
7843 [ + - ]: 4 : SPDK_CU_ASSERT_FATAL(blob->clean.num_pages + blob->clean.num_extent_pages == page_count_xattr);
7844 [ + - ]: 4 : SPDK_CU_ASSERT_FATAL(spdk_bit_array_count_set(bs->used_md_pages) == page_count_xattr);
7845 : 4 : run_poller = false;
7846 : 4 : }
7847 : 24 : rc = spdk_blob_remove_xattr(blob, "large_xattr");
7848 [ + - ]: 24 : SPDK_CU_ASSERT_FATAL(rc == 0);
7849 : 24 : spdk_blob_sync_md(blob, blob_op_complete, NULL);
7850 : 24 : poll_threads();
7851 [ + - ]: 24 : SPDK_CU_ASSERT_FATAL(g_bserrno == 0);
7852 [ + - ]: 24 : SPDK_CU_ASSERT_FATAL(blob->active.num_pages + blob->active.num_extent_pages == page_count_clear);
7853 [ + - ]: 24 : SPDK_CU_ASSERT_FATAL(blob->clean.num_pages + blob->clean.num_extent_pages == page_count_clear);
7854 [ + - ]: 24 : SPDK_CU_ASSERT_FATAL(spdk_bit_array_count_set(bs->used_md_pages) == page_count_clear);
7855 : :
7856 : : /* Reload bs and re-open blob to verify that xattr was not persisted. */
7857 : 24 : spdk_blob_close(blob, blob_op_complete, NULL);
7858 : 24 : poll_threads();
7859 : 24 : CU_ASSERT(g_bserrno == 0);
7860 : :
7861 : 24 : ut_bs_reload(&bs, NULL);
7862 : :
7863 : 24 : spdk_bs_open_blob(bs, blobid, blob_op_with_handle_complete, NULL);
7864 : 24 : poll_threads();
7865 : 24 : CU_ASSERT(g_bserrno == 0);
7866 [ + - ]: 24 : SPDK_CU_ASSERT_FATAL(g_blob != NULL);
7867 : 24 : blob = g_blob;
7868 : :
7869 : 24 : rc = spdk_blob_get_xattr_value(blob, "large_xattr", (const void **)&xattr, &xattr_length);
7870 [ + - ]: 24 : SPDK_CU_ASSERT_FATAL(rc == -ENOENT);
7871 : :
7872 : 24 : poller_iterations++;
7873 : : /* Stop at high iteration count to prevent infinite loop.
7874 : : * This value should be enough for first md sync to complete in any case. */
7875 [ + - ]: 24 : SPDK_CU_ASSERT_FATAL(poller_iterations < 50);
7876 : : }
7877 : :
7878 : 4 : free(xattr);
7879 : :
7880 : 4 : ut_blob_close_and_delete(bs, blob);
7881 : :
7882 : 4 : spdk_bs_free_io_channel(channel);
7883 : 4 : poll_threads();
7884 : 4 : }
7885 : :
7886 : : static void
7887 : 4 : blob_decouple_snapshot(void)
7888 : : {
7889 : 4 : struct spdk_blob_store *bs = g_bs;
7890 : : struct spdk_blob_opts opts;
7891 : : struct spdk_blob *blob, *snapshot1, *snapshot2;
7892 : : struct spdk_io_channel *channel;
7893 : : spdk_blob_id blobid, snapshotid;
7894 : : uint64_t cluster;
7895 : :
7896 [ + + ]: 12 : for (int delete_snapshot_first = 0; delete_snapshot_first <= 1; delete_snapshot_first++) {
7897 : 8 : channel = spdk_bs_alloc_io_channel(bs);
7898 [ + - ]: 8 : SPDK_CU_ASSERT_FATAL(channel != NULL);
7899 : :
7900 : 8 : ut_spdk_blob_opts_init(&opts);
7901 : 8 : opts.num_clusters = 10;
7902 : 8 : opts.thin_provision = false;
7903 : :
7904 : 8 : blob = ut_blob_create_and_open(bs, &opts);
7905 : 8 : blobid = spdk_blob_get_id(blob);
7906 : :
7907 : : /* Create first snapshot */
7908 : 8 : CU_ASSERT_EQUAL(_get_snapshots_count(bs), 0);
7909 : 8 : spdk_bs_create_snapshot(bs, blobid, NULL, blob_op_with_id_complete, NULL);
7910 : 8 : poll_threads();
7911 : 8 : CU_ASSERT(g_bserrno == 0);
7912 : 8 : CU_ASSERT(g_blobid != SPDK_BLOBID_INVALID);
7913 : 8 : CU_ASSERT_EQUAL(_get_snapshots_count(bs), 1);
7914 : 8 : snapshotid = g_blobid;
7915 : :
7916 : 8 : spdk_bs_open_blob(bs, snapshotid, blob_op_with_handle_complete, NULL);
7917 : 8 : poll_threads();
7918 : 8 : CU_ASSERT(g_bserrno == 0);
7919 [ - + ]: 8 : SPDK_CU_ASSERT_FATAL(g_blob != NULL);
7920 : 8 : snapshot1 = g_blob;
7921 : :
7922 : : /* Create the second one */
7923 : 8 : CU_ASSERT_EQUAL(_get_snapshots_count(bs), 1);
7924 : 8 : spdk_bs_create_snapshot(bs, blobid, NULL, blob_op_with_id_complete, NULL);
7925 : 8 : poll_threads();
7926 : 8 : CU_ASSERT(g_bserrno == 0);
7927 : 8 : CU_ASSERT(g_blobid != SPDK_BLOBID_INVALID);
7928 : 8 : CU_ASSERT_EQUAL(_get_snapshots_count(bs), 2);
7929 : 8 : snapshotid = g_blobid;
7930 : :
7931 : 8 : spdk_bs_open_blob(bs, snapshotid, blob_op_with_handle_complete, NULL);
7932 : 8 : poll_threads();
7933 : 8 : CU_ASSERT(g_bserrno == 0);
7934 [ - + ]: 8 : SPDK_CU_ASSERT_FATAL(g_blob != NULL);
7935 : 8 : snapshot2 = g_blob;
7936 : 8 : CU_ASSERT_EQUAL(spdk_blob_get_parent_snapshot(bs, snapshot2->id), snapshot1->id);
7937 : :
7938 : : /* Now decouple the second snapshot forcing it to copy the written clusters */
7939 : 8 : spdk_bs_blob_decouple_parent(bs, channel, snapshot2->id, blob_op_complete, NULL);
7940 : 8 : poll_threads();
7941 : 8 : CU_ASSERT(g_bserrno == 0);
7942 : :
7943 : : /* Verify that the snapshot has been decoupled and that the clusters have been copied */
7944 : 8 : CU_ASSERT_EQUAL(spdk_blob_get_parent_snapshot(bs, snapshot2->id), SPDK_BLOBID_INVALID);
7945 [ + + ]: 88 : for (cluster = 0; cluster < snapshot2->active.num_clusters; ++cluster) {
7946 : 80 : CU_ASSERT_NOT_EQUAL(snapshot2->active.clusters[cluster], 0);
7947 : 80 : CU_ASSERT_NOT_EQUAL(snapshot2->active.clusters[cluster],
7948 : : snapshot1->active.clusters[cluster]);
7949 : 80 : }
7950 : :
7951 : 8 : spdk_bs_free_io_channel(channel);
7952 : :
7953 [ + + ]: 8 : if (delete_snapshot_first) {
7954 : 4 : ut_blob_close_and_delete(bs, snapshot2);
7955 : 4 : ut_blob_close_and_delete(bs, snapshot1);
7956 : 4 : ut_blob_close_and_delete(bs, blob);
7957 : 4 : } else {
7958 : 4 : ut_blob_close_and_delete(bs, blob);
7959 : 4 : ut_blob_close_and_delete(bs, snapshot2);
7960 : 4 : ut_blob_close_and_delete(bs, snapshot1);
7961 : : }
7962 : 8 : poll_threads();
7963 : 8 : }
7964 : 4 : }
7965 : :
7966 : : static void
7967 : 4 : blob_seek_io_unit(void)
7968 : : {
7969 : 4 : struct spdk_blob_store *bs = g_bs;
7970 : : struct spdk_blob *blob;
7971 : : struct spdk_io_channel *channel;
7972 : : struct spdk_blob_opts opts;
7973 : : uint64_t free_clusters;
7974 : : uint8_t payload[10 * BLOCKLEN];
7975 : : uint64_t offset;
7976 : : uint64_t io_unit, io_units_per_cluster;
7977 : :
7978 : 4 : free_clusters = spdk_bs_free_cluster_count(bs);
7979 : :
7980 : 4 : channel = spdk_bs_alloc_io_channel(bs);
7981 : 4 : CU_ASSERT(channel != NULL);
7982 : :
7983 : : /* Set blob as thin provisioned */
7984 : 4 : ut_spdk_blob_opts_init(&opts);
7985 : 4 : opts.thin_provision = true;
7986 : :
7987 : : /* Create a blob */
7988 : 4 : blob = ut_blob_create_and_open(bs, &opts);
7989 : 4 : CU_ASSERT(free_clusters == spdk_bs_free_cluster_count(bs));
7990 : :
7991 : 4 : io_units_per_cluster = bs_io_units_per_cluster(blob);
7992 : :
7993 : : /* The blob started at 0 clusters. Resize it to be 5, but still unallocated. */
7994 : 4 : spdk_blob_resize(blob, 5, blob_op_complete, NULL);
7995 : 4 : poll_threads();
7996 : 4 : CU_ASSERT(g_bserrno == 0);
7997 : 4 : CU_ASSERT(free_clusters == spdk_bs_free_cluster_count(bs));
7998 : 4 : CU_ASSERT(blob->active.num_clusters == 5);
7999 : :
8000 : : /* Write at the beginning of first cluster */
8001 : 4 : offset = 0;
8002 : 4 : spdk_blob_io_write(blob, channel, payload, offset, 1, blob_op_complete, NULL);
8003 : 4 : poll_threads();
8004 : 4 : CU_ASSERT(g_bserrno == 0);
8005 : :
8006 : 4 : io_unit = spdk_blob_get_next_allocated_io_unit(blob, 0);
8007 : 4 : CU_ASSERT(io_unit == offset);
8008 : :
8009 : 4 : io_unit = spdk_blob_get_next_unallocated_io_unit(blob, 0);
8010 : 4 : CU_ASSERT(io_unit == io_units_per_cluster);
8011 : :
8012 : : /* Write in the middle of third cluster */
8013 : 4 : offset = 2 * io_units_per_cluster + io_units_per_cluster / 2;
8014 : 4 : spdk_blob_io_write(blob, channel, payload, offset, 1, blob_op_complete, NULL);
8015 : 4 : poll_threads();
8016 : 4 : CU_ASSERT(g_bserrno == 0);
8017 : :
8018 : 4 : io_unit = spdk_blob_get_next_allocated_io_unit(blob, io_units_per_cluster);
8019 : 4 : CU_ASSERT(io_unit == 2 * io_units_per_cluster);
8020 : :
8021 : 4 : io_unit = spdk_blob_get_next_unallocated_io_unit(blob, 2 * io_units_per_cluster);
8022 : 4 : CU_ASSERT(io_unit == 3 * io_units_per_cluster);
8023 : :
8024 : : /* Write at the end of last cluster */
8025 : 4 : offset = 5 * io_units_per_cluster - 1;
8026 : 4 : spdk_blob_io_write(blob, channel, payload, offset, 1, blob_op_complete, NULL);
8027 : 4 : poll_threads();
8028 : 4 : CU_ASSERT(g_bserrno == 0);
8029 : :
8030 : 4 : io_unit = spdk_blob_get_next_allocated_io_unit(blob, 3 * io_units_per_cluster);
8031 : 4 : CU_ASSERT(io_unit == 4 * io_units_per_cluster);
8032 : :
8033 : 4 : io_unit = spdk_blob_get_next_unallocated_io_unit(blob, 4 * io_units_per_cluster);
8034 : 4 : CU_ASSERT(io_unit == UINT64_MAX);
8035 : :
8036 : 4 : spdk_bs_free_io_channel(channel);
8037 : 4 : poll_threads();
8038 : :
8039 : 4 : ut_blob_close_and_delete(bs, blob);
8040 : 4 : }
8041 : :
8042 : : static void
8043 : 4 : blob_esnap_create(void)
8044 : : {
8045 : 4 : struct spdk_blob_store *bs = g_bs;
8046 : : struct spdk_bs_opts bs_opts;
8047 : : struct ut_esnap_opts esnap_opts;
8048 : : struct spdk_blob_opts opts;
8049 : : struct spdk_blob_open_opts open_opts;
8050 : : struct spdk_blob *blob;
8051 : : uint32_t cluster_sz, block_sz;
8052 : 4 : const uint32_t esnap_num_clusters = 4;
8053 : : uint64_t esnap_num_blocks;
8054 : : uint32_t sz;
8055 : : spdk_blob_id blobid;
8056 : : uint32_t bs_ctx_count, blob_ctx_count;
8057 : :
8058 : 4 : cluster_sz = spdk_bs_get_cluster_size(bs);
8059 : 4 : block_sz = spdk_bs_get_io_unit_size(bs);
8060 : 4 : esnap_num_blocks = cluster_sz * esnap_num_clusters / block_sz;
8061 : :
8062 : : /* Create a normal blob and verify it is not an esnap clone. */
8063 : 4 : ut_spdk_blob_opts_init(&opts);
8064 : 4 : blob = ut_blob_create_and_open(bs, &opts);
8065 : 4 : CU_ASSERT(!spdk_blob_is_esnap_clone(blob));
8066 : 4 : ut_blob_close_and_delete(bs, blob);
8067 : :
8068 : : /* Create an esnap clone blob then verify it is an esnap clone and has the right size */
8069 : 4 : ut_spdk_blob_opts_init(&opts);
8070 : 4 : ut_esnap_opts_init(block_sz, esnap_num_blocks, __func__, NULL, &esnap_opts);
8071 : 4 : opts.esnap_id = &esnap_opts;
8072 : 4 : opts.esnap_id_len = sizeof(esnap_opts);
8073 : 4 : opts.num_clusters = esnap_num_clusters;
8074 : 4 : blob = ut_blob_create_and_open(bs, &opts);
8075 [ + - ]: 4 : SPDK_CU_ASSERT_FATAL(blob != NULL);
8076 [ + - ]: 4 : SPDK_CU_ASSERT_FATAL(spdk_blob_is_esnap_clone(blob));
8077 [ + - ]: 4 : SPDK_CU_ASSERT_FATAL(blob_is_esnap_clone(blob));
8078 [ + - ]: 4 : SPDK_CU_ASSERT_FATAL(!spdk_blob_is_clone(blob));
8079 : 4 : sz = spdk_blob_get_num_clusters(blob);
8080 : 4 : CU_ASSERT(sz == esnap_num_clusters);
8081 : 4 : ut_blob_close_and_delete(bs, blob);
8082 : :
8083 : : /* Create an esnap clone without the size and verify it can be grown */
8084 : 4 : ut_spdk_blob_opts_init(&opts);
8085 : 4 : ut_esnap_opts_init(block_sz, esnap_num_blocks, __func__, NULL, &esnap_opts);
8086 : 4 : opts.esnap_id = &esnap_opts;
8087 : 4 : opts.esnap_id_len = sizeof(esnap_opts);
8088 : 4 : blob = ut_blob_create_and_open(bs, &opts);
8089 [ + - ]: 4 : SPDK_CU_ASSERT_FATAL(spdk_blob_is_esnap_clone(blob));
8090 : 4 : sz = spdk_blob_get_num_clusters(blob);
8091 : 4 : CU_ASSERT(sz == 0);
8092 : 4 : spdk_blob_resize(blob, 1, blob_op_complete, NULL);
8093 : 4 : poll_threads();
8094 : 4 : CU_ASSERT(g_bserrno == 0);
8095 : 4 : sz = spdk_blob_get_num_clusters(blob);
8096 : 4 : CU_ASSERT(sz == 1);
8097 : 4 : spdk_blob_resize(blob, esnap_num_clusters, blob_op_complete, NULL);
8098 : 4 : poll_threads();
8099 : 4 : CU_ASSERT(g_bserrno == 0);
8100 : 4 : sz = spdk_blob_get_num_clusters(blob);
8101 : 4 : CU_ASSERT(sz == esnap_num_clusters);
8102 : 4 : spdk_blob_resize(blob, esnap_num_clusters + 1, blob_op_complete, NULL);
8103 : 4 : poll_threads();
8104 : 4 : CU_ASSERT(g_bserrno == 0);
8105 : 4 : sz = spdk_blob_get_num_clusters(blob);
8106 : 4 : CU_ASSERT(sz == esnap_num_clusters + 1);
8107 : :
8108 : : /* Reload the blobstore and be sure that the blob can be opened. */
8109 : 4 : blobid = spdk_blob_get_id(blob);
8110 : 4 : spdk_blob_close(blob, blob_op_complete, NULL);
8111 : 4 : poll_threads();
8112 : 4 : CU_ASSERT(g_bserrno == 0);
8113 : 4 : g_blob = NULL;
8114 : 4 : spdk_bs_opts_init(&bs_opts, sizeof(bs_opts));
8115 : 4 : bs_opts.esnap_bs_dev_create = ut_esnap_create;
8116 : 4 : ut_bs_reload(&bs, &bs_opts);
8117 : 4 : spdk_bs_open_blob(bs, blobid, blob_op_with_handle_complete, NULL);
8118 : 4 : poll_threads();
8119 : 4 : CU_ASSERT(g_bserrno == 0);
8120 : 4 : CU_ASSERT(g_blob != NULL);
8121 : 4 : blob = g_blob;
8122 [ + - ]: 4 : SPDK_CU_ASSERT_FATAL(spdk_blob_is_esnap_clone(blob));
8123 : 4 : sz = spdk_blob_get_num_clusters(blob);
8124 : 4 : CU_ASSERT(sz == esnap_num_clusters + 1);
8125 : :
8126 : : /* Reload the blobstore without esnap_bs_dev_create: should fail to open blob. */
8127 : 4 : spdk_blob_close(blob, blob_op_complete, NULL);
8128 : 4 : poll_threads();
8129 : 4 : CU_ASSERT(g_bserrno == 0);
8130 : 4 : g_blob = NULL;
8131 : 4 : spdk_bs_opts_init(&bs_opts, sizeof(bs_opts));
8132 : 4 : ut_bs_reload(&bs, &bs_opts);
8133 : 4 : spdk_bs_open_blob(bs, blobid, blob_op_with_handle_complete, NULL);
8134 : 4 : poll_threads();
8135 : 4 : CU_ASSERT(g_bserrno != 0);
8136 : 4 : CU_ASSERT(g_blob == NULL);
8137 : :
8138 : : /* Reload the blobstore with ctx set and verify it is passed to the esnap create callback */
8139 : 4 : bs_ctx_count = 0;
8140 : 4 : spdk_bs_opts_init(&bs_opts, sizeof(bs_opts));
8141 : 4 : bs_opts.esnap_bs_dev_create = ut_esnap_create_with_count;
8142 : 4 : bs_opts.esnap_ctx = &bs_ctx_count;
8143 : 4 : ut_bs_reload(&bs, &bs_opts);
8144 : : /* Loading the blobstore triggers the esnap to be loaded */
8145 : 4 : CU_ASSERT(bs_ctx_count == 1);
8146 : 4 : spdk_bs_open_blob(bs, blobid, blob_op_with_handle_complete, NULL);
8147 : 4 : poll_threads();
8148 : 4 : CU_ASSERT(g_bserrno == 0);
8149 : 4 : CU_ASSERT(g_blob != NULL);
8150 : : /* Opening the blob also triggers the esnap to be loaded */
8151 : 4 : CU_ASSERT(bs_ctx_count == 2);
8152 : 4 : blob = g_blob;
8153 [ - + ]: 4 : SPDK_CU_ASSERT_FATAL(spdk_blob_is_esnap_clone(blob));
8154 : 4 : sz = spdk_blob_get_num_clusters(blob);
8155 : 4 : CU_ASSERT(sz == esnap_num_clusters + 1);
8156 : 4 : spdk_blob_close(blob, blob_op_complete, NULL);
8157 : 4 : poll_threads();
8158 : 4 : CU_ASSERT(g_bserrno == 0);
8159 : 4 : g_blob = NULL;
8160 : : /* If open_opts.esnap_ctx is set it is passed to the esnap create callback */
8161 : 4 : blob_ctx_count = 0;
8162 : 4 : spdk_blob_open_opts_init(&open_opts, sizeof(open_opts));
8163 : 4 : open_opts.esnap_ctx = &blob_ctx_count;
8164 : 4 : spdk_bs_open_blob_ext(bs, blobid, &open_opts, blob_op_with_handle_complete, NULL);
8165 : 4 : poll_threads();
8166 : 4 : blob = g_blob;
8167 : 4 : CU_ASSERT(bs_ctx_count == 3);
8168 : 4 : CU_ASSERT(blob_ctx_count == 1);
8169 : 4 : spdk_blob_close(blob, blob_op_complete, NULL);
8170 : 4 : poll_threads();
8171 : 4 : CU_ASSERT(g_bserrno == 0);
8172 : 4 : g_blob = NULL;
8173 : 4 : }
8174 : :
8175 : : static void
8176 : 4 : blob_esnap_clone_reload(void)
8177 : : {
8178 : 4 : struct spdk_blob_store *bs = g_bs;
8179 : : struct spdk_bs_opts bs_opts;
8180 : : struct ut_esnap_opts esnap_opts;
8181 : : struct spdk_blob_opts opts;
8182 : : struct spdk_blob *eclone1, *snap1, *clone1;
8183 : 4 : uint32_t cluster_sz = spdk_bs_get_cluster_size(bs);
8184 : 4 : uint32_t block_sz = spdk_bs_get_io_unit_size(bs);
8185 : 4 : const uint32_t esnap_num_clusters = 4;
8186 : 4 : uint64_t esnap_num_blocks = cluster_sz * esnap_num_clusters / block_sz;
8187 : : spdk_blob_id eclone1_id, snap1_id, clone1_id;
8188 : : struct spdk_io_channel *bs_ch;
8189 : 4 : char buf[block_sz];
8190 : : int bserr1, bserr2, bserr3, bserr4;
8191 : : struct spdk_bs_dev *dev;
8192 : :
8193 : : /* Create and open an esnap clone blob */
8194 : 4 : ut_spdk_blob_opts_init(&opts);
8195 : 4 : ut_esnap_opts_init(block_sz, esnap_num_blocks, __func__, NULL, &esnap_opts);
8196 : 4 : opts.esnap_id = &esnap_opts;
8197 : 4 : opts.esnap_id_len = sizeof(esnap_opts);
8198 : 4 : opts.num_clusters = esnap_num_clusters;
8199 : 4 : eclone1 = ut_blob_create_and_open(bs, &opts);
8200 : 4 : CU_ASSERT(eclone1 != NULL);
8201 : 4 : CU_ASSERT(spdk_blob_is_esnap_clone(eclone1));
8202 : 4 : eclone1_id = eclone1->id;
8203 : :
8204 : : /* Create and open a snapshot of eclone1 */
8205 : 4 : spdk_bs_create_snapshot(bs, eclone1_id, NULL, blob_op_with_id_complete, NULL);
8206 : 4 : poll_threads();
8207 : 4 : CU_ASSERT(g_blobid != SPDK_BLOBID_INVALID);
8208 : 4 : CU_ASSERT(g_bserrno == 0);
8209 : 4 : snap1_id = g_blobid;
8210 : 4 : spdk_bs_open_blob(bs, snap1_id, blob_op_with_handle_complete, NULL);
8211 : 4 : poll_threads();
8212 : 4 : CU_ASSERT(g_bserrno == 0);
8213 : 4 : CU_ASSERT(g_blob != NULL);
8214 : 4 : snap1 = g_blob;
8215 : :
8216 : : /* Create and open regular clone of snap1 */
8217 : 4 : spdk_bs_create_clone(bs, snap1_id, NULL, blob_op_with_id_complete, NULL);
8218 : 4 : poll_threads();
8219 : 4 : CU_ASSERT(g_blobid != SPDK_BLOBID_INVALID);
8220 [ + - ]: 4 : SPDK_CU_ASSERT_FATAL(g_bserrno == 0);
8221 : 4 : clone1_id = g_blobid;
8222 : 4 : spdk_bs_open_blob(bs, clone1_id, blob_op_with_handle_complete, NULL);
8223 : 4 : poll_threads();
8224 : 4 : CU_ASSERT(g_bserrno == 0);
8225 : 4 : CU_ASSERT(g_blob != NULL);
8226 : 4 : clone1 = g_blob;
8227 : :
8228 : : /* Close the blobs in preparation for reloading the blobstore */
8229 : 4 : spdk_blob_close(clone1, blob_op_complete, NULL);
8230 : 4 : poll_threads();
8231 : 4 : CU_ASSERT(g_bserrno == 0);
8232 : 4 : spdk_blob_close(snap1, blob_op_complete, NULL);
8233 : 4 : poll_threads();
8234 : 4 : CU_ASSERT(g_bserrno == 0);
8235 : 4 : spdk_blob_close(eclone1, blob_op_complete, NULL);
8236 : 4 : poll_threads();
8237 : 4 : CU_ASSERT(g_bserrno == 0);
8238 : 4 : g_blob = NULL;
8239 : :
8240 : : /* Reload the blobstore */
8241 : 4 : spdk_bs_opts_init(&bs_opts, sizeof(bs_opts));
8242 : 4 : bs_opts.esnap_bs_dev_create = ut_esnap_create;
8243 : 4 : ut_bs_reload(&bs, &bs_opts);
8244 : :
8245 : : /* Be sure each of the blobs can be opened */
8246 : 4 : spdk_bs_open_blob(bs, eclone1_id, blob_op_with_handle_complete, NULL);
8247 : 4 : poll_threads();
8248 : 4 : CU_ASSERT(g_bserrno == 0);
8249 : 4 : CU_ASSERT(g_blob != NULL);
8250 : 4 : eclone1 = g_blob;
8251 : 4 : spdk_bs_open_blob(bs, snap1_id, blob_op_with_handle_complete, NULL);
8252 : 4 : poll_threads();
8253 : 4 : CU_ASSERT(g_bserrno == 0);
8254 : 4 : CU_ASSERT(g_blob != NULL);
8255 : 4 : snap1 = g_blob;
8256 : 4 : spdk_bs_open_blob(bs, clone1_id, blob_op_with_handle_complete, NULL);
8257 : 4 : poll_threads();
8258 : 4 : CU_ASSERT(g_bserrno == 0);
8259 : 4 : CU_ASSERT(g_blob != NULL);
8260 : 4 : clone1 = g_blob;
8261 : :
8262 : : /* Perform some reads on each of them to cause channels to be allocated */
8263 : 4 : bs_ch = spdk_bs_alloc_io_channel(bs);
8264 : 4 : CU_ASSERT(bs_ch != NULL);
8265 : 4 : spdk_blob_io_read(eclone1, bs_ch, buf, 0, 1, bs_op_complete, NULL);
8266 : 4 : poll_threads();
8267 : 4 : CU_ASSERT(g_bserrno == 0);
8268 : 4 : spdk_blob_io_read(snap1, bs_ch, buf, 0, 1, bs_op_complete, NULL);
8269 : 4 : poll_threads();
8270 : 4 : CU_ASSERT(g_bserrno == 0);
8271 : 4 : spdk_blob_io_read(clone1, bs_ch, buf, 0, 1, bs_op_complete, NULL);
8272 : 4 : poll_threads();
8273 : 4 : CU_ASSERT(g_bserrno == 0);
8274 : :
8275 : : /*
8276 : : * Unload the blobstore in a way similar to how lvstore unloads it. This should exercise
8277 : : * the deferred unload path in spdk_bs_unload().
8278 : : */
8279 : 4 : bserr1 = 0xbad;
8280 : 4 : bserr2 = 0xbad;
8281 : 4 : bserr3 = 0xbad;
8282 : 4 : bserr4 = 0xbad;
8283 : 4 : spdk_blob_close(eclone1, blob_op_complete, &bserr1);
8284 : 4 : spdk_blob_close(snap1, blob_op_complete, &bserr2);
8285 : 4 : spdk_blob_close(clone1, blob_op_complete, &bserr3);
8286 : 4 : spdk_bs_unload(bs, blob_op_complete, &bserr4);
8287 : 4 : spdk_bs_free_io_channel(bs_ch);
8288 : 4 : poll_threads();
8289 : 4 : CU_ASSERT(bserr1 == 0);
8290 : 4 : CU_ASSERT(bserr2 == 0);
8291 : 4 : CU_ASSERT(bserr3 == 0);
8292 : 4 : CU_ASSERT(bserr4 == 0);
8293 : 4 : g_blob = NULL;
8294 : :
8295 : : /* Reload the blobstore */
8296 : 4 : spdk_bs_opts_init(&bs_opts, sizeof(bs_opts));
8297 : 4 : bs_opts.esnap_bs_dev_create = ut_esnap_create;
8298 : 4 : dev = init_dev();
8299 : 4 : spdk_bs_load(dev, &bs_opts, bs_op_with_handle_complete, NULL);
8300 : 4 : poll_threads();
8301 : 4 : CU_ASSERT(g_bserrno == 0);
8302 [ - + ]: 4 : SPDK_CU_ASSERT_FATAL(g_bs != NULL);
8303 : 4 : }
8304 : :
8305 : : static bool
8306 : 80 : blob_esnap_verify_contents(struct spdk_blob *blob, struct spdk_io_channel *ch,
8307 : : uint64_t offset, uint64_t size, uint32_t readsize, const char *how)
8308 : : {
8309 : 80 : const uint32_t bs_blksz = blob->bs->io_unit_size;
8310 [ + + ]: 80 : const uint32_t esnap_blksz = blob->back_bs_dev ? blob->back_bs_dev->blocklen : bs_blksz;
8311 : 80 : const uint32_t start_blk = offset / bs_blksz;
8312 [ + + ]: 80 : const uint32_t num_blocks = spdk_max(size, readsize) / bs_blksz;
8313 [ - + ]: 80 : const uint32_t blocks_per_read = spdk_min(size, readsize) / bs_blksz;
8314 : : uint32_t blob_block;
8315 : : struct iovec iov;
8316 [ - + ]: 80 : uint8_t buf[spdk_min(size, readsize)];
8317 : : bool block_ok;
8318 : :
8319 [ + - ]: 80 : SPDK_CU_ASSERT_FATAL(offset % bs_blksz == 0);
8320 [ + - ]: 80 : SPDK_CU_ASSERT_FATAL(size % bs_blksz == 0);
8321 [ - + ]: 80 : SPDK_CU_ASSERT_FATAL(readsize % bs_blksz == 0);
8322 : :
8323 : 80 : memset(buf, 0, readsize);
8324 : 80 : iov.iov_base = buf;
8325 : 80 : iov.iov_len = readsize;
8326 [ + + ]: 2044 : for (blob_block = start_blk; blob_block < num_blocks; blob_block += blocks_per_read) {
8327 [ + + ]: 1964 : if (strcmp(how, "read") == 0) {
8328 : 660 : spdk_blob_io_read(blob, ch, buf, blob_block, blocks_per_read,
8329 : : bs_op_complete, NULL);
8330 [ + + ]: 1964 : } else if (strcmp(how, "readv") == 0) {
8331 : 652 : spdk_blob_io_readv(blob, ch, &iov, 1, blob_block, blocks_per_read,
8332 : : bs_op_complete, NULL);
8333 [ + - ]: 1304 : } else if (strcmp(how, "readv_ext") == 0) {
8334 : : /*
8335 : : * This is currently pointless. NULL ext_opts leads to dev->readv(), not
8336 : : * dev->readv_ext().
8337 : : */
8338 : 652 : spdk_blob_io_readv_ext(blob, ch, &iov, 1, blob_block, blocks_per_read,
8339 : : bs_op_complete, NULL, NULL);
8340 : 652 : } else {
8341 : 0 : abort();
8342 : : }
8343 : 1964 : poll_threads();
8344 : 1964 : CU_ASSERT(g_bserrno == 0);
8345 [ + - ]: 1964 : if (g_bserrno != 0) {
8346 : 0 : return false;
8347 : : }
8348 : 3928 : block_ok = ut_esnap_content_is_correct(buf, blocks_per_read * bs_blksz, blob->id,
8349 : 1964 : blob_block * bs_blksz, esnap_blksz);
8350 : 1964 : CU_ASSERT(block_ok);
8351 [ + - ]: 1964 : if (!block_ok) {
8352 : 0 : return false;
8353 : : }
8354 : 1964 : }
8355 : :
8356 : 80 : return true;
8357 : 80 : }
8358 : :
8359 : : static void
8360 : 12 : blob_esnap_io_size(uint32_t bs_blksz, uint32_t esnap_blksz)
8361 : : {
8362 : : struct spdk_bs_dev *dev;
8363 : : struct spdk_blob_store *bs;
8364 : : struct spdk_bs_opts bsopts;
8365 : : struct spdk_blob_opts opts;
8366 : : struct ut_esnap_opts esnap_opts;
8367 : : struct spdk_blob *blob;
8368 : 12 : const uint32_t cluster_sz = 16 * 1024;
8369 : 12 : const uint64_t esnap_num_clusters = 4;
8370 : 12 : const uint32_t esnap_sz = cluster_sz * esnap_num_clusters;
8371 : 12 : const uint64_t esnap_num_blocks = esnap_sz / esnap_blksz;
8372 : 12 : const uint64_t blob_num_blocks = esnap_sz / bs_blksz;
8373 : : uint32_t block;
8374 : : struct spdk_io_channel *bs_ch;
8375 : :
8376 : 12 : spdk_bs_opts_init(&bsopts, sizeof(bsopts));
8377 : 12 : bsopts.cluster_sz = cluster_sz;
8378 : 12 : bsopts.esnap_bs_dev_create = ut_esnap_create;
8379 : :
8380 : : /* Create device with desired block size */
8381 : 12 : dev = init_dev();
8382 : 12 : dev->blocklen = bs_blksz;
8383 : 12 : dev->blockcnt = DEV_BUFFER_SIZE / dev->blocklen;
8384 : :
8385 : : /* Initialize a new blob store */
8386 : 12 : spdk_bs_init(dev, &bsopts, bs_op_with_handle_complete, NULL);
8387 : 12 : poll_threads();
8388 : 12 : CU_ASSERT(g_bserrno == 0);
8389 [ + - ]: 12 : SPDK_CU_ASSERT_FATAL(g_bs != NULL);
8390 [ + - ]: 12 : SPDK_CU_ASSERT_FATAL(g_bs->io_unit_size == bs_blksz);
8391 : 12 : bs = g_bs;
8392 : :
8393 : 12 : bs_ch = spdk_bs_alloc_io_channel(bs);
8394 [ + - ]: 12 : SPDK_CU_ASSERT_FATAL(bs_ch != NULL);
8395 : :
8396 : : /* Create and open the esnap clone */
8397 : 12 : ut_spdk_blob_opts_init(&opts);
8398 : 12 : ut_esnap_opts_init(esnap_blksz, esnap_num_blocks, __func__, NULL, &esnap_opts);
8399 : 12 : opts.esnap_id = &esnap_opts;
8400 : 12 : opts.esnap_id_len = sizeof(esnap_opts);
8401 : 12 : opts.num_clusters = esnap_num_clusters;
8402 : 12 : blob = ut_blob_create_and_open(bs, &opts);
8403 [ + - ]: 12 : SPDK_CU_ASSERT_FATAL(blob != NULL);
8404 : :
8405 : : /* Verify that large reads return the content of the esnap device */
8406 : 12 : CU_ASSERT(blob_esnap_verify_contents(blob, bs_ch, 0, esnap_sz, esnap_sz, "read"));
8407 : 12 : CU_ASSERT(blob_esnap_verify_contents(blob, bs_ch, 0, esnap_sz, esnap_sz, "readv"));
8408 : 12 : CU_ASSERT(blob_esnap_verify_contents(blob, bs_ch, 0, esnap_sz, esnap_sz, "readv_ext"));
8409 : : /* Verify that small reads return the content of the esnap device */
8410 : 12 : CU_ASSERT(blob_esnap_verify_contents(blob, bs_ch, 0, esnap_sz, bs_blksz, "read"));
8411 : 12 : CU_ASSERT(blob_esnap_verify_contents(blob, bs_ch, 0, esnap_sz, bs_blksz, "readv"));
8412 : 12 : CU_ASSERT(blob_esnap_verify_contents(blob, bs_ch, 0, esnap_sz, bs_blksz, "readv_ext"));
8413 : :
8414 : : /* Write one blob block at a time; verify that the surrounding blocks are OK */
8415 [ + + ]: 652 : for (block = 0; block < blob_num_blocks; block++) {
8416 : 640 : char buf[bs_blksz];
8417 : : union ut_word word;
8418 : :
8419 : 640 : word.f.blob_id = 0xfedcba90;
8420 : 640 : word.f.lba = block;
8421 : 640 : ut_memset8(buf, word.num, bs_blksz);
8422 : :
8423 : 640 : spdk_blob_io_write(blob, bs_ch, buf, block, 1, bs_op_complete, NULL);
8424 : 640 : poll_threads();
8425 : 640 : CU_ASSERT(g_bserrno == 0);
8426 [ - + ]: 640 : if (g_bserrno != 0) {
8427 : 0 : break;
8428 : : }
8429 : :
8430 : : /* Read and verify the block before the current block */
8431 [ + + ]: 640 : if (block != 0) {
8432 : 628 : spdk_blob_io_read(blob, bs_ch, buf, block - 1, 1, bs_op_complete, NULL);
8433 : 628 : poll_threads();
8434 : 628 : CU_ASSERT(g_bserrno == 0);
8435 [ + - ]: 628 : if (g_bserrno != 0) {
8436 : 0 : break;
8437 : : }
8438 : 628 : CU_ASSERT(ut_esnap_content_is_correct(buf, bs_blksz, word.f.blob_id,
8439 : : (block - 1) * bs_blksz, bs_blksz));
8440 : 628 : }
8441 : :
8442 : : /* Read and verify the current block */
8443 : 640 : spdk_blob_io_read(blob, bs_ch, buf, block, 1, bs_op_complete, NULL);
8444 : 640 : poll_threads();
8445 : 640 : CU_ASSERT(g_bserrno == 0);
8446 [ - + ]: 640 : if (g_bserrno != 0) {
8447 : 0 : break;
8448 : : }
8449 : 640 : CU_ASSERT(ut_esnap_content_is_correct(buf, bs_blksz, word.f.blob_id,
8450 : : block * bs_blksz, bs_blksz));
8451 : :
8452 : : /* Check the block that follows */
8453 [ + + ]: 640 : if (block + 1 < blob_num_blocks) {
8454 : 628 : g_bserrno = 0xbad;
8455 : 628 : spdk_blob_io_read(blob, bs_ch, buf, block + 1, 1, bs_op_complete, NULL);
8456 : 628 : poll_threads();
8457 : 628 : CU_ASSERT(g_bserrno == 0);
8458 [ - + ]: 628 : if (g_bserrno != 0) {
8459 : 0 : break;
8460 : : }
8461 : 628 : CU_ASSERT(ut_esnap_content_is_correct(buf, bs_blksz, blob->id,
8462 : : (block + 1) * bs_blksz,
8463 : : esnap_blksz));
8464 : 628 : }
8465 [ - - + ]: 640 : }
8466 : :
8467 : : /* Clean up */
8468 : 12 : spdk_bs_free_io_channel(bs_ch);
8469 : 12 : g_bserrno = 0xbad;
8470 : 12 : spdk_blob_close(blob, blob_op_complete, NULL);
8471 : 12 : poll_threads();
8472 : 12 : CU_ASSERT(g_bserrno == 0);
8473 : 12 : spdk_bs_unload(g_bs, bs_op_complete, NULL);
8474 : 12 : poll_threads();
8475 : 12 : CU_ASSERT(g_bserrno == 0);
8476 : 12 : g_bs = NULL;
8477 : 12 : memset(g_dev_buffer, 0, DEV_BUFFER_SIZE);
8478 : 12 : }
8479 : :
8480 : : static void
8481 : 4 : blob_esnap_io_4096_4096(void)
8482 : : {
8483 : 4 : blob_esnap_io_size(4096, 4096);
8484 : 4 : }
8485 : :
8486 : : static void
8487 : 4 : blob_esnap_io_512_512(void)
8488 : : {
8489 : 4 : blob_esnap_io_size(512, 512);
8490 : 4 : }
8491 : :
8492 : : static void
8493 : 4 : blob_esnap_io_4096_512(void)
8494 : : {
8495 : 4 : blob_esnap_io_size(4096, 512);
8496 : 4 : }
8497 : :
8498 : : static void
8499 : 4 : blob_esnap_io_512_4096(void)
8500 : : {
8501 : : struct spdk_bs_dev *dev;
8502 : : struct spdk_blob_store *bs;
8503 : : struct spdk_bs_opts bs_opts;
8504 : : struct spdk_blob_opts blob_opts;
8505 : : struct ut_esnap_opts esnap_opts;
8506 : 4 : uint64_t cluster_sz = 16 * 1024;
8507 : 4 : uint32_t bs_blksz = 512;
8508 : 4 : uint32_t esnap_blksz = BLOCKLEN;
8509 : 4 : uint64_t esnap_num_blocks = 64;
8510 : : spdk_blob_id blobid;
8511 : :
8512 : : /* Create device with desired block size */
8513 : 4 : dev = init_dev();
8514 : 4 : dev->blocklen = bs_blksz;
8515 : 4 : dev->blockcnt = DEV_BUFFER_SIZE / dev->blocklen;
8516 : :
8517 : : /* Initialize a new blob store */
8518 : 4 : spdk_bs_opts_init(&bs_opts, sizeof(bs_opts));
8519 : 4 : bs_opts.cluster_sz = cluster_sz;
8520 : 4 : bs_opts.esnap_bs_dev_create = ut_esnap_create;
8521 : 4 : spdk_bs_init(dev, &bs_opts, bs_op_with_handle_complete, NULL);
8522 : 4 : poll_threads();
8523 : 4 : CU_ASSERT(g_bserrno == 0);
8524 [ + - ]: 4 : SPDK_CU_ASSERT_FATAL(g_bs != NULL);
8525 [ - + ]: 4 : SPDK_CU_ASSERT_FATAL(g_bs->io_unit_size == bs_blksz);
8526 : 4 : bs = g_bs;
8527 : :
8528 : : /* Try to create and open the esnap clone. Create should succeed, open should fail. */
8529 : 4 : ut_spdk_blob_opts_init(&blob_opts);
8530 : 4 : ut_esnap_opts_init(esnap_blksz, esnap_num_blocks, __func__, NULL, &esnap_opts);
8531 : 4 : blob_opts.esnap_id = &esnap_opts;
8532 : 4 : blob_opts.esnap_id_len = sizeof(esnap_opts);
8533 : 4 : blob_opts.num_clusters = esnap_num_blocks * esnap_blksz / bs_blksz;
8534 : 4 : spdk_bs_create_blob_ext(bs, &blob_opts, blob_op_with_id_complete, NULL);
8535 : 4 : poll_threads();
8536 : 4 : CU_ASSERT(g_bserrno == 0);
8537 : 4 : CU_ASSERT(g_blobid != SPDK_BLOBID_INVALID);
8538 : 4 : blobid = g_blobid;
8539 : 4 : spdk_bs_open_blob(bs, blobid, blob_op_with_handle_complete, NULL);
8540 : 4 : poll_threads();
8541 : 4 : CU_ASSERT(g_bserrno == -EINVAL);
8542 : 4 : CU_ASSERT(g_blob == NULL);
8543 : :
8544 : : /* Clean up */
8545 : 4 : spdk_bs_unload(bs, bs_op_complete, NULL);
8546 : 4 : poll_threads();
8547 : 4 : CU_ASSERT(g_bserrno == 0);
8548 : 4 : g_bs = NULL;
8549 : 4 : memset(g_dev_buffer, 0, DEV_BUFFER_SIZE);
8550 : 4 : }
8551 : :
8552 : : static void
8553 : 4 : blob_esnap_thread_add_remove(void)
8554 : : {
8555 : 4 : struct spdk_blob_store *bs = g_bs;
8556 : : struct spdk_blob_opts opts;
8557 : : struct ut_esnap_opts ut_esnap_opts;
8558 : : struct spdk_blob *blob;
8559 : : struct ut_esnap_dev *ut_dev;
8560 : : spdk_blob_id blobid;
8561 : 4 : uint64_t start_thread = g_ut_thread_id;
8562 : 4 : bool destroyed = false;
8563 : : struct spdk_io_channel *ch0, *ch1;
8564 : : struct ut_esnap_channel *ut_ch0, *ut_ch1;
8565 : 4 : const uint32_t blocklen = bs->io_unit_size;
8566 : 4 : char buf[blocklen * 4];
8567 : :
8568 [ + - ]: 4 : SPDK_CU_ASSERT_FATAL(g_ut_num_threads > 1);
8569 : 4 : set_thread(0);
8570 : :
8571 : : /* Create the esnap clone */
8572 : 4 : ut_esnap_opts_init(blocklen, 2048, "add_remove_1", &destroyed, &ut_esnap_opts);
8573 : 4 : ut_spdk_blob_opts_init(&opts);
8574 : 4 : opts.esnap_id = &ut_esnap_opts;
8575 : 4 : opts.esnap_id_len = sizeof(ut_esnap_opts);
8576 : 4 : opts.num_clusters = 10;
8577 : 4 : spdk_bs_create_blob_ext(bs, &opts, blob_op_with_id_complete, NULL);
8578 : 4 : poll_threads();
8579 : 4 : CU_ASSERT(g_bserrno == 0);
8580 : 4 : CU_ASSERT(g_blobid != SPDK_BLOBID_INVALID);
8581 : 4 : blobid = g_blobid;
8582 : :
8583 : : /* Open the blob. No channels should be allocated yet. */
8584 : 4 : spdk_bs_open_blob(bs, blobid, blob_op_with_handle_complete, NULL);
8585 : 4 : poll_threads();
8586 : 4 : CU_ASSERT(g_bserrno == 0);
8587 : 4 : CU_ASSERT(g_blob != NULL);
8588 : 4 : blob = g_blob;
8589 : 4 : ut_dev = (struct ut_esnap_dev *)blob->back_bs_dev;
8590 : 4 : CU_ASSERT(ut_dev != NULL);
8591 : 4 : CU_ASSERT(ut_dev->num_channels == 0);
8592 : :
8593 : : /* Create a channel on thread 0. It is lazily created on the first read. */
8594 : 4 : ch0 = spdk_bs_alloc_io_channel(bs);
8595 : 4 : CU_ASSERT(ch0 != NULL);
8596 : 4 : ut_ch0 = ut_esnap_get_io_channel(ch0, blobid);
8597 : 4 : CU_ASSERT(ut_ch0 == NULL);
8598 : 4 : CU_ASSERT(ut_dev->num_channels == 0);
8599 : 4 : spdk_blob_io_read(blob, ch0, buf, 0, 1, bs_op_complete, NULL);
8600 : 4 : poll_threads();
8601 : 4 : CU_ASSERT(g_bserrno == 0);
8602 : 4 : CU_ASSERT(ut_dev->num_channels == 1);
8603 : 4 : ut_ch0 = ut_esnap_get_io_channel(ch0, blobid);
8604 : 4 : CU_ASSERT(ut_ch0 != NULL);
8605 : 4 : CU_ASSERT(ut_ch0->blocks_read == 1);
8606 : :
8607 : : /* Create a channel on thread 1 and verify its lazy creation too. */
8608 : 4 : set_thread(1);
8609 : 4 : ch1 = spdk_bs_alloc_io_channel(bs);
8610 : 4 : CU_ASSERT(ch1 != NULL);
8611 : 4 : ut_ch1 = ut_esnap_get_io_channel(ch1, blobid);
8612 : 4 : CU_ASSERT(ut_ch1 == NULL);
8613 : 4 : CU_ASSERT(ut_dev->num_channels == 1);
8614 : 4 : spdk_blob_io_read(blob, ch1, buf, 0, 4, bs_op_complete, NULL);
8615 : 4 : poll_threads();
8616 : 4 : CU_ASSERT(g_bserrno == 0);
8617 : 4 : CU_ASSERT(ut_dev->num_channels == 2);
8618 : 4 : ut_ch1 = ut_esnap_get_io_channel(ch1, blobid);
8619 : 4 : CU_ASSERT(ut_ch1 != NULL);
8620 : 4 : CU_ASSERT(ut_ch1->blocks_read == 4);
8621 : :
8622 : : /* Close the channel on thread 0 and verify the bs_dev channel is also gone. */
8623 : 4 : set_thread(0);
8624 : 4 : spdk_bs_free_io_channel(ch0);
8625 : 4 : poll_threads();
8626 : 4 : CU_ASSERT(ut_dev->num_channels == 1);
8627 : :
8628 : : /* Close the blob. There is no outstanding IO so it should close right away. */
8629 : 4 : g_bserrno = 0xbad;
8630 : 4 : spdk_blob_close(blob, blob_op_complete, NULL);
8631 : 4 : poll_threads();
8632 : 4 : CU_ASSERT(g_bserrno == 0);
8633 : 4 : CU_ASSERT(destroyed);
8634 : :
8635 : : /* The esnap channel for the blob should be gone now too. */
8636 : 4 : ut_ch1 = ut_esnap_get_io_channel(ch1, blobid);
8637 : 4 : CU_ASSERT(ut_ch1 == NULL);
8638 : :
8639 : : /* Clean up */
8640 : 4 : set_thread(1);
8641 : 4 : spdk_bs_free_io_channel(ch1);
8642 : 4 : set_thread(start_thread);
8643 : 4 : }
8644 : :
8645 : : static void
8646 : 12 : freeze_done(void *cb_arg, int bserrno)
8647 : : {
8648 : 12 : uint32_t *freeze_cnt = cb_arg;
8649 : :
8650 : 12 : CU_ASSERT(bserrno == 0);
8651 : 12 : (*freeze_cnt)++;
8652 : 12 : }
8653 : :
8654 : : static void
8655 : 12 : unfreeze_done(void *cb_arg, int bserrno)
8656 : : {
8657 : 12 : uint32_t *unfreeze_cnt = cb_arg;
8658 : :
8659 : 12 : CU_ASSERT(bserrno == 0);
8660 : 12 : (*unfreeze_cnt)++;
8661 : 12 : }
8662 : :
8663 : : static void
8664 : 4 : blob_nested_freezes(void)
8665 : : {
8666 : 4 : struct spdk_blob_store *bs = g_bs;
8667 : : struct spdk_blob *blob;
8668 : : struct spdk_io_channel *channel[2];
8669 : : struct spdk_blob_opts opts;
8670 : : uint32_t freeze_cnt, unfreeze_cnt;
8671 : : int i;
8672 : :
8673 [ + + ]: 12 : for (i = 0; i < 2; i++) {
8674 : 8 : set_thread(i);
8675 : 8 : channel[i] = spdk_bs_alloc_io_channel(bs);
8676 [ + - ]: 8 : SPDK_CU_ASSERT_FATAL(channel[i] != NULL);
8677 : 8 : }
8678 : :
8679 : 4 : set_thread(0);
8680 : :
8681 : 4 : ut_spdk_blob_opts_init(&opts);
8682 : 4 : blob = ut_blob_create_and_open(bs, &opts);
8683 : :
8684 : : /* First just test a single freeze/unfreeze. */
8685 : 4 : freeze_cnt = 0;
8686 : 4 : unfreeze_cnt = 0;
8687 : 4 : CU_ASSERT(blob->frozen_refcnt == 0);
8688 : 4 : blob_freeze_io(blob, freeze_done, &freeze_cnt);
8689 : 4 : CU_ASSERT(blob->frozen_refcnt == 1);
8690 : 4 : CU_ASSERT(freeze_cnt == 0);
8691 : 4 : poll_threads();
8692 : 4 : CU_ASSERT(freeze_cnt == 1);
8693 : 4 : blob_unfreeze_io(blob, unfreeze_done, &unfreeze_cnt);
8694 : 4 : CU_ASSERT(blob->frozen_refcnt == 0);
8695 : 4 : CU_ASSERT(unfreeze_cnt == 0);
8696 : 4 : poll_threads();
8697 : 4 : CU_ASSERT(unfreeze_cnt == 1);
8698 : :
8699 : : /* Now nest multiple freeze/unfreeze operations. We should
8700 : : * expect a callback for each operation, but only after
8701 : : * the threads have been polled to ensure a for_each_channel()
8702 : : * was executed.
8703 : : */
8704 : 4 : freeze_cnt = 0;
8705 : 4 : unfreeze_cnt = 0;
8706 : 4 : CU_ASSERT(blob->frozen_refcnt == 0);
8707 : 4 : blob_freeze_io(blob, freeze_done, &freeze_cnt);
8708 : 4 : CU_ASSERT(blob->frozen_refcnt == 1);
8709 : 4 : CU_ASSERT(freeze_cnt == 0);
8710 : 4 : blob_freeze_io(blob, freeze_done, &freeze_cnt);
8711 : 4 : CU_ASSERT(blob->frozen_refcnt == 2);
8712 : 4 : CU_ASSERT(freeze_cnt == 0);
8713 : 4 : poll_threads();
8714 : 4 : CU_ASSERT(freeze_cnt == 2);
8715 : 4 : blob_unfreeze_io(blob, unfreeze_done, &unfreeze_cnt);
8716 : 4 : CU_ASSERT(blob->frozen_refcnt == 1);
8717 : 4 : CU_ASSERT(unfreeze_cnt == 0);
8718 : 4 : blob_unfreeze_io(blob, unfreeze_done, &unfreeze_cnt);
8719 : 4 : CU_ASSERT(blob->frozen_refcnt == 0);
8720 : 4 : CU_ASSERT(unfreeze_cnt == 0);
8721 : 4 : poll_threads();
8722 : 4 : CU_ASSERT(unfreeze_cnt == 2);
8723 : :
8724 [ + + ]: 12 : for (i = 0; i < 2; i++) {
8725 : 8 : set_thread(i);
8726 : 8 : spdk_bs_free_io_channel(channel[i]);
8727 : 8 : }
8728 : 4 : set_thread(0);
8729 : 4 : ut_blob_close_and_delete(bs, blob);
8730 : :
8731 : 4 : poll_threads();
8732 : 4 : g_blob = NULL;
8733 : 4 : g_blobid = 0;
8734 : 4 : }
8735 : :
8736 : : static void
8737 : 4 : blob_ext_md_pages(void)
8738 : : {
8739 : : struct spdk_blob_store *bs;
8740 : : struct spdk_bs_dev *dev;
8741 : : struct spdk_blob *blob;
8742 : : struct spdk_blob_opts opts;
8743 : : struct spdk_bs_opts bs_opts;
8744 : : uint64_t free_clusters;
8745 : :
8746 : 4 : dev = init_dev();
8747 : 4 : spdk_bs_opts_init(&bs_opts, sizeof(bs_opts));
8748 : 4 : snprintf(bs_opts.bstype.bstype, sizeof(bs_opts.bstype.bstype), "TESTTYPE");
8749 : : /* Issue #2932 was a bug in how we use bs_allocate_cluster() during resize.
8750 : : * It requires num_md_pages that is much smaller than the number of clusters.
8751 : : * Make sure we can create a blob that uses all of the free clusters.
8752 : : */
8753 : 4 : bs_opts.cluster_sz = 65536;
8754 : 4 : bs_opts.num_md_pages = 16;
8755 : :
8756 : : /* Initialize a new blob store */
8757 : 4 : spdk_bs_init(dev, &bs_opts, bs_op_with_handle_complete, NULL);
8758 : 4 : poll_threads();
8759 : 4 : CU_ASSERT(g_bserrno == 0);
8760 [ + - ]: 4 : SPDK_CU_ASSERT_FATAL(g_bs != NULL);
8761 : 4 : bs = g_bs;
8762 : :
8763 : 4 : free_clusters = spdk_bs_free_cluster_count(bs);
8764 : :
8765 : 4 : ut_spdk_blob_opts_init(&opts);
8766 : 4 : opts.num_clusters = free_clusters;
8767 : :
8768 : 4 : blob = ut_blob_create_and_open(bs, &opts);
8769 : 4 : spdk_blob_close(blob, blob_op_complete, NULL);
8770 : 4 : CU_ASSERT(g_bserrno == 0);
8771 : :
8772 : 4 : spdk_bs_unload(bs, bs_op_complete, NULL);
8773 : 4 : poll_threads();
8774 : 4 : CU_ASSERT(g_bserrno == 0);
8775 : 4 : g_bs = NULL;
8776 : 4 : }
8777 : :
8778 : : static void
8779 : 4 : blob_esnap_clone_snapshot(void)
8780 : : {
8781 : : /*
8782 : : * When a snapshot is created, the blob that is being snapped becomes
8783 : : * the leaf node (a clone of the snapshot) and the newly created
8784 : : * snapshot sits between the snapped blob and the external snapshot.
8785 : : *
8786 : : * Before creating snap1
8787 : : *
8788 : : * ,--------. ,----------.
8789 : : * | blob | | vbdev |
8790 : : * | blob1 |<----| nvme1n42 |
8791 : : * | (rw) | | (ro) |
8792 : : * `--------' `----------'
8793 : : * Figure 1
8794 : : *
8795 : : * After creating snap1
8796 : : *
8797 : : * ,--------. ,--------. ,----------.
8798 : : * | blob | | blob | | vbdev |
8799 : : * | blob1 |<----| snap1 |<----| nvme1n42 |
8800 : : * | (rw) | | (ro) | | (ro) |
8801 : : * `--------' `--------' `----------'
8802 : : * Figure 2
8803 : : *
8804 : : * Starting from Figure 2, if snap1 is removed, the chain reverts to
8805 : : * what it looks like in Figure 1.
8806 : : *
8807 : : * Starting from Figure 2, if blob1 is removed, the chain becomes:
8808 : : *
8809 : : * ,--------. ,----------.
8810 : : * | blob | | vbdev |
8811 : : * | snap1 |<----| nvme1n42 |
8812 : : * | (ro) | | (ro) |
8813 : : * `--------' `----------'
8814 : : * Figure 3
8815 : : *
8816 : : * In each case, the blob pointed to by the nvme vbdev is considered
8817 : : * the "esnap clone". The esnap clone must have:
8818 : : *
8819 : : * - XATTR_INTERNAL for BLOB_EXTERNAL_SNAPSHOT_ID (e.g. name or UUID)
8820 : : * - blob->invalid_flags must contain SPDK_BLOB_EXTERNAL_SNAPSHOT
8821 : : * - blob->parent_id must be SPDK_BLOBID_EXTERNAL_SNAPSHOT.
8822 : : *
8823 : : * No other blob that descends from the esnap clone may have any of
8824 : : * those set.
8825 : : */
8826 : 4 : struct spdk_blob_store *bs = g_bs;
8827 : 4 : const uint32_t blocklen = bs->io_unit_size;
8828 : : struct spdk_blob_opts opts;
8829 : : struct ut_esnap_opts esnap_opts;
8830 : : struct spdk_blob *blob, *snap_blob;
8831 : : spdk_blob_id blobid, snap_blobid;
8832 : 4 : bool destroyed = false;
8833 : :
8834 : : /* Create the esnap clone */
8835 : 4 : ut_esnap_opts_init(blocklen, 2048, __func__, &destroyed, &esnap_opts);
8836 : 4 : ut_spdk_blob_opts_init(&opts);
8837 : 4 : opts.esnap_id = &esnap_opts;
8838 : 4 : opts.esnap_id_len = sizeof(esnap_opts);
8839 : 4 : opts.num_clusters = 10;
8840 : 4 : spdk_bs_create_blob_ext(bs, &opts, blob_op_with_id_complete, NULL);
8841 : 4 : poll_threads();
8842 : 4 : CU_ASSERT(g_bserrno == 0);
8843 : 4 : CU_ASSERT(g_blobid != SPDK_BLOBID_INVALID);
8844 : 4 : blobid = g_blobid;
8845 : :
8846 : : /* Open the blob. */
8847 : 4 : spdk_bs_open_blob(bs, blobid, blob_op_with_handle_complete, NULL);
8848 : 4 : poll_threads();
8849 : 4 : CU_ASSERT(g_bserrno == 0);
8850 : 4 : CU_ASSERT(g_blob != NULL);
8851 : 4 : blob = g_blob;
8852 : 4 : UT_ASSERT_IS_ESNAP_CLONE(blob, &esnap_opts, sizeof(esnap_opts));
8853 : :
8854 : : /*
8855 : : * Create a snapshot of the blob. The snapshot becomes the esnap clone.
8856 : : */
8857 : 4 : spdk_bs_create_snapshot(bs, blobid, NULL, blob_op_with_id_complete, NULL);
8858 : 4 : poll_threads();
8859 : 4 : CU_ASSERT(g_bserrno == 0);
8860 : 4 : CU_ASSERT(g_blobid != SPDK_BLOBID_INVALID);
8861 : 4 : snap_blobid = g_blobid;
8862 : :
8863 : 4 : spdk_bs_open_blob(bs, snap_blobid, blob_op_with_handle_complete, NULL);
8864 : 4 : poll_threads();
8865 : 4 : CU_ASSERT(g_bserrno == 0);
8866 [ + - ]: 4 : SPDK_CU_ASSERT_FATAL(g_blob != NULL);
8867 : 4 : snap_blob = g_blob;
8868 : :
8869 : 4 : UT_ASSERT_IS_NOT_ESNAP_CLONE(blob);
8870 : 4 : UT_ASSERT_IS_ESNAP_CLONE(snap_blob, &esnap_opts, sizeof(esnap_opts));
8871 : :
8872 : : /*
8873 : : * Delete the snapshot. The original blob becomes the esnap clone.
8874 : : */
8875 : 4 : ut_blob_close_and_delete(bs, snap_blob);
8876 : 4 : snap_blob = NULL;
8877 : 4 : snap_blobid = SPDK_BLOBID_INVALID;
8878 : 4 : UT_ASSERT_IS_ESNAP_CLONE(blob, &esnap_opts, sizeof(esnap_opts));
8879 : :
8880 : : /*
8881 : : * Create the snapshot again, then delete the original blob. The
8882 : : * snapshot should survive as the esnap clone.
8883 : : */
8884 : 4 : spdk_bs_create_snapshot(bs, blobid, NULL, blob_op_with_id_complete, NULL);
8885 : 4 : poll_threads();
8886 : 4 : CU_ASSERT(g_bserrno == 0);
8887 : 4 : CU_ASSERT(g_blobid != SPDK_BLOBID_INVALID);
8888 : 4 : snap_blobid = g_blobid;
8889 : :
8890 : 4 : spdk_bs_open_blob(bs, snap_blobid, blob_op_with_handle_complete, NULL);
8891 : 4 : poll_threads();
8892 : 4 : CU_ASSERT(g_bserrno == 0);
8893 [ + - ]: 4 : SPDK_CU_ASSERT_FATAL(g_blob != NULL);
8894 : 4 : snap_blob = g_blob;
8895 : :
8896 : 4 : UT_ASSERT_IS_NOT_ESNAP_CLONE(blob);
8897 : 4 : UT_ASSERT_IS_ESNAP_CLONE(snap_blob, &esnap_opts, sizeof(esnap_opts));
8898 : :
8899 : 4 : ut_blob_close_and_delete(bs, blob);
8900 : 4 : blob = NULL;
8901 : 4 : blobid = SPDK_BLOBID_INVALID;
8902 : 4 : UT_ASSERT_IS_ESNAP_CLONE(snap_blob, &esnap_opts, sizeof(esnap_opts));
8903 : :
8904 : : /*
8905 : : * Clone the snapshot. The snapshot continues to be the esnap clone.
8906 : : */
8907 : 4 : spdk_bs_create_clone(bs, snap_blobid, NULL, blob_op_with_id_complete, NULL);
8908 : 4 : poll_threads();
8909 : 4 : CU_ASSERT(g_bserrno == 0);
8910 : 4 : CU_ASSERT(g_blobid != SPDK_BLOBID_INVALID);
8911 : 4 : blobid = g_blobid;
8912 : :
8913 : 4 : spdk_bs_open_blob(bs, blobid, blob_op_with_handle_complete, NULL);
8914 : 4 : poll_threads();
8915 : 4 : CU_ASSERT(g_bserrno == 0);
8916 [ - + ]: 4 : SPDK_CU_ASSERT_FATAL(g_blob != NULL);
8917 : 4 : blob = g_blob;
8918 : :
8919 : 4 : UT_ASSERT_IS_NOT_ESNAP_CLONE(blob);
8920 : 4 : UT_ASSERT_IS_ESNAP_CLONE(snap_blob, &esnap_opts, sizeof(esnap_opts));
8921 : :
8922 : : /*
8923 : : * Delete the snapshot. The clone becomes the esnap clone.
8924 : : */
8925 : 4 : ut_blob_close_and_delete(bs, snap_blob);
8926 : 4 : snap_blob = NULL;
8927 : 4 : snap_blobid = SPDK_BLOBID_INVALID;
8928 : 4 : UT_ASSERT_IS_ESNAP_CLONE(blob, &esnap_opts, sizeof(esnap_opts));
8929 : :
8930 : : /*
8931 : : * Clean up
8932 : : */
8933 : 4 : ut_blob_close_and_delete(bs, blob);
8934 : 4 : }
8935 : :
8936 : : static uint64_t
8937 : 8 : _blob_esnap_clone_hydrate(bool inflate)
8938 : : {
8939 : 8 : struct spdk_blob_store *bs = g_bs;
8940 : : struct spdk_blob_opts opts;
8941 : : struct ut_esnap_opts esnap_opts;
8942 : : struct spdk_blob *blob;
8943 : : spdk_blob_id blobid;
8944 : : struct spdk_io_channel *channel;
8945 : 8 : bool destroyed = false;
8946 : 8 : const uint32_t blocklen = spdk_bs_get_io_unit_size(bs);
8947 : 8 : const uint32_t cluster_sz = spdk_bs_get_cluster_size(bs);
8948 : 8 : const uint64_t esnap_num_clusters = 4;
8949 : 8 : const uint32_t esnap_sz = cluster_sz * esnap_num_clusters;
8950 : 8 : const uint64_t esnap_num_blocks = esnap_sz / blocklen;
8951 : 8 : uint64_t num_failures = CU_get_number_of_failures();
8952 : :
8953 : 8 : channel = spdk_bs_alloc_io_channel(bs);
8954 [ + - ]: 8 : SPDK_CU_ASSERT_FATAL(channel != NULL);
8955 : :
8956 : : /* Create the esnap clone */
8957 : 8 : ut_spdk_blob_opts_init(&opts);
8958 : 8 : ut_esnap_opts_init(blocklen, esnap_num_blocks, __func__, &destroyed, &esnap_opts);
8959 : 8 : opts.esnap_id = &esnap_opts;
8960 : 8 : opts.esnap_id_len = sizeof(esnap_opts);
8961 : 8 : opts.num_clusters = esnap_num_clusters;
8962 : 8 : spdk_bs_create_blob_ext(bs, &opts, blob_op_with_id_complete, NULL);
8963 : 8 : poll_threads();
8964 : 8 : CU_ASSERT(g_bserrno == 0);
8965 : 8 : CU_ASSERT(g_blobid != SPDK_BLOBID_INVALID);
8966 : 8 : blobid = g_blobid;
8967 : :
8968 : : /* Open the esnap clone */
8969 : 8 : spdk_bs_open_blob(bs, blobid, blob_op_with_handle_complete, NULL);
8970 : 8 : poll_threads();
8971 : 8 : CU_ASSERT(g_bserrno == 0);
8972 [ - + ]: 8 : SPDK_CU_ASSERT_FATAL(g_blob != NULL);
8973 : 8 : blob = g_blob;
8974 : 8 : UT_ASSERT_IS_ESNAP_CLONE(blob, &esnap_opts, sizeof(esnap_opts));
8975 : :
8976 : : /*
8977 : : * Inflate or decouple the blob then verify that it is no longer an esnap clone and has
8978 : : * right content
8979 : : */
8980 [ + + ]: 8 : if (inflate) {
8981 : 4 : spdk_bs_inflate_blob(bs, channel, blobid, blob_op_complete, NULL);
8982 : 4 : } else {
8983 : 4 : spdk_bs_blob_decouple_parent(bs, channel, blobid, blob_op_complete, NULL);
8984 : : }
8985 : 8 : poll_threads();
8986 : 8 : CU_ASSERT(g_bserrno == 0);
8987 : 8 : UT_ASSERT_IS_NOT_ESNAP_CLONE(blob);
8988 : 8 : CU_ASSERT(blob_esnap_verify_contents(blob, channel, 0, esnap_sz, esnap_sz, "read"));
8989 : 8 : ut_blob_close_and_delete(bs, blob);
8990 : :
8991 : : /*
8992 : : * Clean up
8993 : : */
8994 : 8 : spdk_bs_free_io_channel(channel);
8995 : 8 : poll_threads();
8996 : :
8997 : : /* Return number of new failures */
8998 : 8 : return CU_get_number_of_failures() - num_failures;
8999 : : }
9000 : :
9001 : : static void
9002 : 4 : blob_esnap_clone_inflate(void)
9003 : : {
9004 : 4 : _blob_esnap_clone_hydrate(true);
9005 : 4 : }
9006 : :
9007 : : static void
9008 : 4 : blob_esnap_clone_decouple(void)
9009 : : {
9010 : 4 : _blob_esnap_clone_hydrate(false);
9011 : 4 : }
9012 : :
9013 : : static void
9014 : 4 : blob_esnap_hotplug(void)
9015 : : {
9016 : 4 : struct spdk_blob_store *bs = g_bs;
9017 : : struct ut_esnap_opts esnap1_opts, esnap2_opts;
9018 : : struct spdk_blob_opts opts;
9019 : : struct spdk_blob *blob;
9020 : : struct spdk_bs_dev *bs_dev;
9021 : : struct ut_esnap_dev *esnap_dev;
9022 : 4 : uint32_t cluster_sz = spdk_bs_get_cluster_size(bs);
9023 : 4 : uint32_t block_sz = spdk_bs_get_io_unit_size(bs);
9024 : 4 : const uint32_t esnap_num_clusters = 4;
9025 : 4 : uint64_t esnap_num_blocks = cluster_sz * esnap_num_clusters / block_sz;
9026 : 4 : bool destroyed1 = false, destroyed2 = false;
9027 : 4 : uint64_t start_thread = g_ut_thread_id;
9028 : : struct spdk_io_channel *ch0, *ch1;
9029 : 4 : char buf[block_sz];
9030 : :
9031 : : /* Create and open an esnap clone blob */
9032 : 4 : ut_spdk_blob_opts_init(&opts);
9033 : 4 : ut_esnap_opts_init(block_sz, esnap_num_blocks, "esnap1", &destroyed1, &esnap1_opts);
9034 : 4 : opts.esnap_id = &esnap1_opts;
9035 : 4 : opts.esnap_id_len = sizeof(esnap1_opts);
9036 : 4 : opts.num_clusters = esnap_num_clusters;
9037 : 4 : blob = ut_blob_create_and_open(bs, &opts);
9038 : 4 : CU_ASSERT(blob != NULL);
9039 : 4 : CU_ASSERT(spdk_blob_is_esnap_clone(blob));
9040 [ + - ]: 4 : SPDK_CU_ASSERT_FATAL(blob->back_bs_dev != NULL);
9041 : 4 : esnap_dev = (struct ut_esnap_dev *)blob->back_bs_dev;
9042 : 4 : CU_ASSERT(strcmp(esnap_dev->ut_opts.name, "esnap1") == 0);
9043 : :
9044 : : /* Replace the external snapshot */
9045 : 4 : ut_esnap_opts_init(block_sz, esnap_num_blocks, "esnap2", &destroyed2, &esnap2_opts);
9046 : 4 : bs_dev = ut_esnap_dev_alloc(&esnap2_opts);
9047 : 4 : CU_ASSERT(!destroyed1);
9048 : 4 : CU_ASSERT(!destroyed2);
9049 : 4 : g_bserrno = 0xbad;
9050 : 4 : spdk_blob_set_esnap_bs_dev(blob, bs_dev, bs_op_complete, NULL);
9051 : 4 : poll_threads();
9052 : 4 : CU_ASSERT(g_bserrno == 0);
9053 : 4 : CU_ASSERT(destroyed1);
9054 : 4 : CU_ASSERT(!destroyed2);
9055 [ + - ]: 4 : SPDK_CU_ASSERT_FATAL(bs_dev == blob->back_bs_dev);
9056 [ + - ]: 4 : SPDK_CU_ASSERT_FATAL(bs_dev == spdk_blob_get_esnap_bs_dev(blob));
9057 : 4 : esnap_dev = (struct ut_esnap_dev *)blob->back_bs_dev;
9058 : 4 : CU_ASSERT(strcmp(esnap_dev->ut_opts.name, "esnap2") == 0);
9059 : :
9060 : : /* Create a couple channels */
9061 : 4 : set_thread(0);
9062 : 4 : ch0 = spdk_bs_alloc_io_channel(bs);
9063 : 4 : CU_ASSERT(ch0 != NULL);
9064 : 4 : spdk_blob_io_read(blob, ch0, buf, 0, 1, bs_op_complete, NULL);
9065 : 4 : set_thread(1);
9066 : 4 : ch1 = spdk_bs_alloc_io_channel(bs);
9067 : 4 : CU_ASSERT(ch1 != NULL);
9068 : 4 : spdk_blob_io_read(blob, ch1, buf, 0, 1, bs_op_complete, NULL);
9069 : 4 : set_thread(start_thread);
9070 : 4 : poll_threads();
9071 : 4 : CU_ASSERT(esnap_dev->num_channels == 2);
9072 : :
9073 : : /* Replace the external snapshot */
9074 : 4 : ut_esnap_opts_init(block_sz, esnap_num_blocks, "esnap1a", &destroyed1, &esnap1_opts);
9075 : 4 : bs_dev = ut_esnap_dev_alloc(&esnap1_opts);
9076 : 4 : destroyed1 = destroyed2 = false;
9077 : 4 : g_bserrno = 0xbad;
9078 : 4 : spdk_blob_set_esnap_bs_dev(blob, bs_dev, bs_op_complete, NULL);
9079 : 4 : poll_threads();
9080 : 4 : CU_ASSERT(g_bserrno == 0);
9081 : 4 : CU_ASSERT(!destroyed1);
9082 : 4 : CU_ASSERT(destroyed2);
9083 [ - + ]: 4 : SPDK_CU_ASSERT_FATAL(blob->back_bs_dev != NULL);
9084 : 4 : esnap_dev = (struct ut_esnap_dev *)blob->back_bs_dev;
9085 : 4 : CU_ASSERT(strcmp(esnap_dev->ut_opts.name, "esnap1a") == 0);
9086 : :
9087 : : /* Clean up */
9088 : 4 : set_thread(0);
9089 : 4 : spdk_bs_free_io_channel(ch0);
9090 : 4 : set_thread(1);
9091 : 4 : spdk_bs_free_io_channel(ch1);
9092 : 4 : set_thread(start_thread);
9093 : 4 : g_bserrno = 0xbad;
9094 : 4 : spdk_blob_close(blob, bs_op_complete, NULL);
9095 : 4 : poll_threads();
9096 : 4 : CU_ASSERT(g_bserrno == 0);
9097 : 4 : }
9098 : :
9099 : : static bool g_blob_is_degraded;
9100 : : static int g_blob_is_degraded_called;
9101 : :
9102 : : static bool
9103 : 24 : _blob_is_degraded(struct spdk_bs_dev *dev)
9104 : : {
9105 : 24 : g_blob_is_degraded_called++;
9106 : 24 : return g_blob_is_degraded;
9107 : : }
9108 : :
9109 : : static void
9110 : 4 : blob_is_degraded(void)
9111 : : {
9112 : 4 : struct spdk_bs_dev bs_is_degraded_null = { 0 };
9113 : 4 : struct spdk_bs_dev bs_is_degraded = { .is_degraded = _blob_is_degraded };
9114 : :
9115 : : /* No back_bs_dev, no bs->dev->is_degraded */
9116 : 4 : g_blob_is_degraded_called = 0;
9117 : 4 : CU_ASSERT(!spdk_blob_is_degraded(g_blob));
9118 : 4 : CU_ASSERT(g_blob_is_degraded_called == 0);
9119 : :
9120 : : /* No back_bs_dev, blobstore device degraded */
9121 : 4 : g_bs->dev->is_degraded = _blob_is_degraded;
9122 : 4 : g_blob_is_degraded_called = 0;
9123 : 4 : g_blob_is_degraded = true;
9124 : 4 : CU_ASSERT(spdk_blob_is_degraded(g_blob));
9125 : 4 : CU_ASSERT(g_blob_is_degraded_called == 1);
9126 : :
9127 : : /* No back_bs_dev, blobstore device not degraded */
9128 : 4 : g_bs->dev->is_degraded = _blob_is_degraded;
9129 : 4 : g_blob_is_degraded_called = 0;
9130 : 4 : g_blob_is_degraded = false;
9131 : 4 : CU_ASSERT(!spdk_blob_is_degraded(g_blob));
9132 : 4 : CU_ASSERT(g_blob_is_degraded_called == 1);
9133 : :
9134 : : /* back_bs_dev does not define is_degraded, no bs->dev->is_degraded */
9135 : 4 : g_bs->dev->is_degraded = NULL;
9136 : 4 : g_blob->back_bs_dev = &bs_is_degraded_null;
9137 : 4 : g_blob_is_degraded_called = 0;
9138 : 4 : g_blob_is_degraded = false;
9139 : 4 : CU_ASSERT(!spdk_blob_is_degraded(g_blob));
9140 : 4 : CU_ASSERT(g_blob_is_degraded_called == 0);
9141 : :
9142 : : /* back_bs_dev is not degraded, no bs->dev->is_degraded */
9143 : 4 : g_bs->dev->is_degraded = NULL;
9144 : 4 : g_blob->back_bs_dev = &bs_is_degraded;
9145 : 4 : g_blob_is_degraded_called = 0;
9146 : 4 : g_blob_is_degraded = false;
9147 : 4 : CU_ASSERT(!spdk_blob_is_degraded(g_blob));
9148 : 4 : CU_ASSERT(g_blob_is_degraded_called == 1);
9149 : :
9150 : : /* back_bs_dev is degraded, no bs->dev->is_degraded */
9151 : 4 : g_bs->dev->is_degraded = NULL;
9152 : 4 : g_blob->back_bs_dev = &bs_is_degraded;
9153 : 4 : g_blob_is_degraded_called = 0;
9154 : 4 : g_blob_is_degraded = true;
9155 : 4 : CU_ASSERT(spdk_blob_is_degraded(g_blob));
9156 : 4 : CU_ASSERT(g_blob_is_degraded_called == 1);
9157 : :
9158 : : /* back_bs_dev is not degraded, blobstore device is not degraded */
9159 : 4 : g_bs->dev->is_degraded = _blob_is_degraded;
9160 : 4 : g_blob->back_bs_dev = &bs_is_degraded;
9161 : 4 : g_blob_is_degraded_called = 0;
9162 : 4 : g_blob_is_degraded = false;
9163 : 4 : CU_ASSERT(!spdk_blob_is_degraded(g_blob));
9164 : 4 : CU_ASSERT(g_blob_is_degraded_called == 2);
9165 : :
9166 : 4 : g_blob->back_bs_dev = NULL;
9167 : 4 : }
9168 : :
9169 : : /* Resize a blob which is a clone created from snapshot. Verify read/writes to
9170 : : * expanded clone blob. Then inflate the clone blob. */
9171 : : static void
9172 : 4 : blob_clone_resize(void)
9173 : : {
9174 : 4 : struct spdk_blob_store *bs = g_bs;
9175 : : struct spdk_blob_opts opts;
9176 : : struct spdk_blob *blob, *clone, *snap_blob, *snap_blob_rsz;
9177 : : spdk_blob_id blobid, cloneid, snapid1, snapid2;
9178 : : uint64_t pages_per_cluster;
9179 : 4 : uint8_t payload_read[bs->dev->blocklen];
9180 : 4 : uint8_t payload_write[bs->dev->blocklen];
9181 : : struct spdk_io_channel *channel;
9182 : : uint64_t free_clusters;
9183 : :
9184 : 4 : channel = spdk_bs_alloc_io_channel(bs);
9185 [ + - ]: 4 : SPDK_CU_ASSERT_FATAL(channel != NULL);
9186 : :
9187 : 4 : pages_per_cluster = spdk_bs_get_cluster_size(bs) / spdk_bs_get_page_size(bs);
9188 : :
9189 : : /* Create blob with 10 clusters */
9190 : 4 : ut_spdk_blob_opts_init(&opts);
9191 : 4 : opts.num_clusters = 10;
9192 : :
9193 : 4 : blob = ut_blob_create_and_open(bs, &opts);
9194 : 4 : blobid = spdk_blob_get_id(blob);
9195 : 4 : CU_ASSERT(spdk_blob_get_num_clusters(blob) == 10);
9196 : :
9197 : : /* Create snapshot */
9198 : 4 : spdk_bs_create_snapshot(bs, blobid, NULL, blob_op_with_id_complete, NULL);
9199 : 4 : poll_threads();
9200 : 4 : CU_ASSERT(g_bserrno == 0);
9201 : 4 : CU_ASSERT(g_blobid != SPDK_BLOBID_INVALID);
9202 : 4 : snapid1 = g_blobid;
9203 : :
9204 : 4 : spdk_bs_create_clone(bs, snapid1, NULL, blob_op_with_id_complete, NULL);
9205 : 4 : poll_threads();
9206 : 4 : CU_ASSERT(g_bserrno == 0);
9207 : 4 : CU_ASSERT(g_blobid != SPDK_BLOBID_INVALID);
9208 : 4 : cloneid = g_blobid;
9209 : :
9210 : 4 : spdk_bs_open_blob(bs, cloneid, blob_op_with_handle_complete, NULL);
9211 : 4 : poll_threads();
9212 : 4 : CU_ASSERT(g_bserrno == 0);
9213 [ + - ]: 4 : SPDK_CU_ASSERT_FATAL(g_blob != NULL);
9214 : 4 : clone = g_blob;
9215 : 4 : CU_ASSERT(spdk_blob_get_num_clusters(clone) == 10);
9216 : :
9217 : 4 : g_bserrno = -1;
9218 : 4 : spdk_blob_resize(clone, 20, blob_op_complete, NULL);
9219 : 4 : poll_threads();
9220 : 4 : CU_ASSERT(g_bserrno == 0);
9221 : 4 : CU_ASSERT(spdk_blob_get_num_clusters(clone) == 20);
9222 : :
9223 : : /* Create another snapshot after resizing the clone */
9224 : 4 : spdk_bs_create_snapshot(bs, cloneid, NULL, blob_op_with_id_complete, NULL);
9225 : 4 : poll_threads();
9226 : 4 : CU_ASSERT(g_bserrno == 0);
9227 : 4 : CU_ASSERT(g_blobid != SPDK_BLOBID_INVALID);
9228 : 4 : snapid2 = g_blobid;
9229 : :
9230 : : /* Open the snapshot blobs */
9231 : 4 : spdk_bs_open_blob(bs, snapid1, blob_op_with_handle_complete, NULL);
9232 : 4 : CU_ASSERT(g_bserrno == 0);
9233 [ + - ]: 4 : SPDK_CU_ASSERT_FATAL(g_blob != NULL);
9234 : 4 : snap_blob = g_blob;
9235 : 4 : CU_ASSERT(snap_blob->data_ro == true);
9236 : 4 : CU_ASSERT(snap_blob->md_ro == true);
9237 : 4 : CU_ASSERT(spdk_blob_get_num_clusters(snap_blob) == 10);
9238 : :
9239 : 4 : spdk_bs_open_blob(bs, snapid2, blob_op_with_handle_complete, NULL);
9240 : 4 : CU_ASSERT(g_bserrno == 0);
9241 [ + - ]: 4 : SPDK_CU_ASSERT_FATAL(g_blob != NULL);
9242 : 4 : snap_blob_rsz = g_blob;
9243 : 4 : CU_ASSERT(snap_blob_rsz->data_ro == true);
9244 : 4 : CU_ASSERT(snap_blob_rsz->md_ro == true);
9245 : 4 : CU_ASSERT(spdk_blob_get_num_clusters(snap_blob_rsz) == 20);
9246 : :
9247 : : /* Confirm that clone is backed by snap_blob_rsz, and snap_blob_rsz is backed by snap_blob */
9248 [ + - ]: 4 : SPDK_CU_ASSERT_FATAL(snap_blob->back_bs_dev == NULL);
9249 [ + - ]: 4 : SPDK_CU_ASSERT_FATAL(blob->back_bs_dev != NULL);
9250 [ - + ]: 4 : SPDK_CU_ASSERT_FATAL(snap_blob_rsz->back_bs_dev != NULL);
9251 : :
9252 : : /* Write and read from pre-resize ranges */
9253 : 4 : g_bserrno = -1;
9254 : 4 : memset(payload_write, 0xE5, sizeof(payload_write));
9255 : 4 : spdk_blob_io_write(clone, channel, payload_write, 5 * pages_per_cluster, 1, blob_op_complete, NULL);
9256 : 4 : poll_threads();
9257 : 4 : CU_ASSERT(g_bserrno == 0);
9258 : :
9259 : 4 : g_bserrno = -1;
9260 : 4 : memset(payload_read, 0x00, sizeof(payload_read));
9261 : 4 : spdk_blob_io_read(clone, channel, payload_read, 5 * pages_per_cluster, 1, blob_op_complete, NULL);
9262 : 4 : poll_threads();
9263 : 4 : CU_ASSERT(g_bserrno == 0);
9264 : 4 : CU_ASSERT(memcmp(payload_write, payload_read, BLOCKLEN) == 0);
9265 : :
9266 : : /* Write and read from post-resize ranges */
9267 : 4 : g_bserrno = -1;
9268 : 4 : memset(payload_write, 0xE5, sizeof(payload_write));
9269 : 4 : spdk_blob_io_write(clone, channel, payload_write, 15 * pages_per_cluster, 1, blob_op_complete,
9270 : : NULL);
9271 : 4 : poll_threads();
9272 : 4 : CU_ASSERT(g_bserrno == 0);
9273 : :
9274 : 4 : g_bserrno = -1;
9275 : 4 : memset(payload_read, 0x00, sizeof(payload_read));
9276 : 4 : spdk_blob_io_read(clone, channel, payload_read, 15 * pages_per_cluster, 1, blob_op_complete, NULL);
9277 : 4 : poll_threads();
9278 : 4 : CU_ASSERT(g_bserrno == 0);
9279 : 4 : CU_ASSERT(memcmp(payload_write, payload_read, bs->dev->blocklen) == 0);
9280 : :
9281 : : /* Now do full blob inflation of the resized blob/clone. */
9282 : 4 : free_clusters = spdk_bs_free_cluster_count(bs);
9283 : 4 : spdk_bs_inflate_blob(bs, channel, cloneid, blob_op_complete, NULL);
9284 : 4 : poll_threads();
9285 : 4 : CU_ASSERT(g_bserrno == 0);
9286 : : /* We wrote to 2 clusters earlier, all remaining 18 clusters in
9287 : : * blob should get allocated after inflation */
9288 : 4 : CU_ASSERT(spdk_bs_free_cluster_count(bs) == free_clusters - 18);
9289 : :
9290 : 4 : spdk_blob_close(clone, blob_op_complete, NULL);
9291 : 4 : poll_threads();
9292 : 4 : CU_ASSERT(g_bserrno == 0);
9293 : :
9294 : 4 : spdk_blob_close(snap_blob, blob_op_complete, NULL);
9295 : 4 : poll_threads();
9296 : 4 : CU_ASSERT(g_bserrno == 0);
9297 : :
9298 : 4 : spdk_blob_close(snap_blob_rsz, blob_op_complete, NULL);
9299 : 4 : poll_threads();
9300 : 4 : CU_ASSERT(g_bserrno == 0);
9301 : :
9302 : 4 : ut_blob_close_and_delete(bs, blob);
9303 : :
9304 : 4 : spdk_bs_free_io_channel(channel);
9305 : 4 : }
9306 : :
9307 : :
9308 : : static void
9309 : 4 : blob_esnap_clone_resize(void)
9310 : : {
9311 : : struct spdk_bs_dev *dev;
9312 : : struct spdk_blob_store *bs;
9313 : : struct spdk_bs_opts bsopts;
9314 : : struct spdk_blob_opts opts;
9315 : : struct ut_esnap_opts esnap_opts;
9316 : : struct spdk_blob *blob;
9317 : 4 : uint32_t block, esnap_blksz = 512, bs_blksz = 512;
9318 : 4 : const uint32_t cluster_sz = 16 * 1024;
9319 : 4 : const uint64_t esnap_num_clusters = 4;
9320 : 4 : const uint32_t esnap_sz = cluster_sz * esnap_num_clusters;
9321 : 4 : const uint64_t esnap_num_blocks = esnap_sz / esnap_blksz;
9322 : 4 : uint64_t blob_num_blocks = esnap_sz / bs_blksz;
9323 : : struct spdk_io_channel *bs_ch;
9324 : :
9325 : 4 : spdk_bs_opts_init(&bsopts, sizeof(bsopts));
9326 : 4 : bsopts.cluster_sz = cluster_sz;
9327 : 4 : bsopts.esnap_bs_dev_create = ut_esnap_create;
9328 : : /* Create device with desired block size */
9329 : 4 : dev = init_dev();
9330 : 4 : dev->blocklen = bs_blksz;
9331 : 4 : dev->blockcnt = DEV_BUFFER_SIZE / dev->blocklen;
9332 : : /* Initialize a new blob store */
9333 : 4 : spdk_bs_init(dev, &bsopts, bs_op_with_handle_complete, NULL);
9334 : 4 : poll_threads();
9335 : 4 : CU_ASSERT(g_bserrno == 0);
9336 [ + - ]: 4 : SPDK_CU_ASSERT_FATAL(g_bs != NULL);
9337 [ + - ]: 4 : SPDK_CU_ASSERT_FATAL(g_bs->io_unit_size == bs_blksz);
9338 : 4 : bs = g_bs;
9339 : :
9340 : 4 : bs_ch = spdk_bs_alloc_io_channel(bs);
9341 [ + - ]: 4 : SPDK_CU_ASSERT_FATAL(bs_ch != NULL);
9342 : :
9343 : : /* Create and open the esnap clone */
9344 : 4 : ut_spdk_blob_opts_init(&opts);
9345 : 4 : ut_esnap_opts_init(esnap_blksz, esnap_num_blocks, __func__, NULL, &esnap_opts);
9346 : 4 : opts.esnap_id = &esnap_opts;
9347 : 4 : opts.esnap_id_len = sizeof(esnap_opts);
9348 : 4 : opts.num_clusters = esnap_num_clusters;
9349 : 4 : blob = ut_blob_create_and_open(bs, &opts);
9350 [ + - ]: 4 : SPDK_CU_ASSERT_FATAL(blob != NULL);
9351 : :
9352 : 4 : g_bserrno = -1;
9353 : 4 : spdk_blob_resize(blob, esnap_num_clusters * 2, blob_op_complete, NULL);
9354 : 4 : poll_threads();
9355 : 4 : CU_ASSERT(g_bserrno == 0);
9356 : 4 : CU_ASSERT(spdk_blob_get_num_clusters(blob) == esnap_num_clusters * 2);
9357 : :
9358 : : /* Write one blob block at a time; verify that the surrounding blocks are OK */
9359 : 4 : blob_num_blocks = (spdk_blob_get_num_clusters(blob) * cluster_sz) / bs_blksz;
9360 [ + + ]: 1028 : for (block = 0; block < blob_num_blocks; block++) {
9361 : 1024 : char buf[bs_blksz];
9362 : : union ut_word word;
9363 : 1024 : word.f.blob_id = 0xfedcba90;
9364 : 1024 : word.f.lba = block;
9365 : 1024 : ut_memset8(buf, word.num, bs_blksz);
9366 : 1024 : spdk_blob_io_write(blob, bs_ch, buf, block, 1, bs_op_complete, NULL);
9367 : 1024 : poll_threads();
9368 : 1024 : CU_ASSERT(g_bserrno == 0);
9369 [ - + ]: 1024 : if (g_bserrno != 0) {
9370 : 0 : break;
9371 : : }
9372 : : /* Read and verify the block before the current block */
9373 [ + + ]: 1024 : if (block != 0) {
9374 : 1020 : spdk_blob_io_read(blob, bs_ch, buf, block - 1, 1, bs_op_complete, NULL);
9375 : 1020 : poll_threads();
9376 : 1020 : CU_ASSERT(g_bserrno == 0);
9377 [ + - ]: 1020 : if (g_bserrno != 0) {
9378 : 0 : break;
9379 : : }
9380 : 1020 : CU_ASSERT(ut_esnap_content_is_correct(buf, bs_blksz, word.f.blob_id,
9381 : : (block - 1) * bs_blksz, bs_blksz));
9382 : 1020 : }
9383 : : /* Read and verify the current block */
9384 : 1024 : spdk_blob_io_read(blob, bs_ch, buf, block, 1, bs_op_complete, NULL);
9385 : 1024 : poll_threads();
9386 : 1024 : CU_ASSERT(g_bserrno == 0);
9387 [ - + ]: 1024 : if (g_bserrno != 0) {
9388 : 0 : break;
9389 : : }
9390 : 1024 : CU_ASSERT(ut_esnap_content_is_correct(buf, bs_blksz, word.f.blob_id,
9391 : : block * bs_blksz, bs_blksz));
9392 : : /* Check the block that follows */
9393 [ + + ]: 1024 : if (block + 1 < blob_num_blocks) {
9394 : 1020 : g_bserrno = 0xbad;
9395 : 1020 : spdk_blob_io_read(blob, bs_ch, buf, block + 1, 1, bs_op_complete, NULL);
9396 : 1020 : poll_threads();
9397 : 1020 : CU_ASSERT(g_bserrno == 0);
9398 [ - + ]: 1020 : if (g_bserrno != 0) {
9399 : 0 : break;
9400 : : }
9401 : 1020 : CU_ASSERT(ut_esnap_content_is_correct(buf, bs_blksz, blob->id,
9402 : : (block + 1) * bs_blksz,
9403 : : esnap_blksz));
9404 : 1020 : }
9405 [ - - + ]: 1024 : }
9406 : : /* Clean up */
9407 : 4 : spdk_bs_free_io_channel(bs_ch);
9408 : 4 : g_bserrno = 0xbad;
9409 : 4 : spdk_blob_close(blob, blob_op_complete, NULL);
9410 : 4 : poll_threads();
9411 : 4 : CU_ASSERT(g_bserrno == 0);
9412 : 4 : spdk_bs_unload(g_bs, bs_op_complete, NULL);
9413 : 4 : poll_threads();
9414 : 4 : CU_ASSERT(g_bserrno == 0);
9415 : 4 : g_bs = NULL;
9416 : 4 : memset(g_dev_buffer, 0, DEV_BUFFER_SIZE);
9417 : 4 : }
9418 : :
9419 : : static void
9420 : 8192 : bs_dev_io_complete_cb(struct spdk_io_channel *channel, void *cb_arg, int bserrno)
9421 : : {
9422 : 8192 : g_bserrno = bserrno;
9423 : 8192 : }
9424 : :
9425 : : static void
9426 : 4 : blob_shallow_copy(void)
9427 : : {
9428 : 4 : struct spdk_blob_store *bs = g_bs;
9429 : : struct spdk_blob_opts blob_opts;
9430 : : struct spdk_blob *blob;
9431 : : spdk_blob_id blobid;
9432 : 4 : uint64_t num_clusters = 4;
9433 : : struct spdk_bs_dev *ext_dev;
9434 : : struct spdk_bs_dev_cb_args ext_args;
9435 : : struct spdk_io_channel *bdev_ch, *blob_ch;
9436 : : uint8_t buf1[DEV_BUFFER_BLOCKLEN];
9437 : : uint8_t buf2[DEV_BUFFER_BLOCKLEN];
9438 : : uint64_t io_units_per_cluster;
9439 : : uint64_t offset;
9440 : : int rc;
9441 : :
9442 : 4 : blob_ch = spdk_bs_alloc_io_channel(bs);
9443 [ + - ]: 4 : SPDK_CU_ASSERT_FATAL(blob_ch != NULL);
9444 : :
9445 : : /* Set blob dimension and as thin provisioned */
9446 : 4 : ut_spdk_blob_opts_init(&blob_opts);
9447 : 4 : blob_opts.thin_provision = true;
9448 : 4 : blob_opts.num_clusters = num_clusters;
9449 : :
9450 : : /* Create a blob */
9451 : 4 : blob = ut_blob_create_and_open(bs, &blob_opts);
9452 [ + - ]: 4 : SPDK_CU_ASSERT_FATAL(blob != NULL);
9453 : 4 : blobid = spdk_blob_get_id(blob);
9454 : 4 : io_units_per_cluster = bs_io_units_per_cluster(blob);
9455 : :
9456 : : /* Write on cluster 2 and 4 of blob */
9457 [ + + ]: 1028 : for (offset = io_units_per_cluster; offset < 2 * io_units_per_cluster; offset++) {
9458 : 1024 : memset(buf1, offset, DEV_BUFFER_BLOCKLEN);
9459 : 1024 : spdk_blob_io_write(blob, blob_ch, buf1, offset, 1, blob_op_complete, NULL);
9460 : 1024 : poll_threads();
9461 : 1024 : CU_ASSERT(g_bserrno == 0);
9462 : 1024 : }
9463 [ + + ]: 1028 : for (offset = 3 * io_units_per_cluster; offset < 4 * io_units_per_cluster; offset++) {
9464 : 1024 : memset(buf1, offset, DEV_BUFFER_BLOCKLEN);
9465 : 1024 : spdk_blob_io_write(blob, blob_ch, buf1, offset, 1, blob_op_complete, NULL);
9466 : 1024 : poll_threads();
9467 : 1024 : CU_ASSERT(g_bserrno == 0);
9468 : 1024 : }
9469 : 4 : CU_ASSERT(spdk_blob_get_num_allocated_clusters(blob) == 2);
9470 : :
9471 : : /* Make a snapshot over blob */
9472 : 4 : spdk_bs_create_snapshot(bs, blobid, NULL, blob_op_with_id_complete, NULL);
9473 : 4 : poll_threads();
9474 : 4 : CU_ASSERT(g_bserrno == 0);
9475 : 4 : CU_ASSERT(spdk_blob_get_num_allocated_clusters(blob) == 0);
9476 : :
9477 : : /* Write on cluster 1 and 3 of blob */
9478 [ + + ]: 1028 : for (offset = 0; offset < io_units_per_cluster; offset++) {
9479 : 1024 : memset(buf1, offset, DEV_BUFFER_BLOCKLEN);
9480 : 1024 : spdk_blob_io_write(blob, blob_ch, buf1, offset, 1, blob_op_complete, NULL);
9481 : 1024 : poll_threads();
9482 : 1024 : CU_ASSERT(g_bserrno == 0);
9483 : 1024 : }
9484 [ + + ]: 1028 : for (offset = 2 * io_units_per_cluster; offset < 3 * io_units_per_cluster; offset++) {
9485 : 1024 : memset(buf1, offset, DEV_BUFFER_BLOCKLEN);
9486 : 1024 : spdk_blob_io_write(blob, blob_ch, buf1, offset, 1, blob_op_complete, NULL);
9487 : 1024 : poll_threads();
9488 : 1024 : CU_ASSERT(g_bserrno == 0);
9489 : 1024 : }
9490 : 4 : CU_ASSERT(spdk_blob_get_num_allocated_clusters(blob) == 2);
9491 : :
9492 : : /* Shallow copy with a not read only blob */
9493 : 4 : ext_dev = init_ext_dev(num_clusters * 1024 * 1024, DEV_BUFFER_BLOCKLEN);
9494 : 4 : rc = spdk_bs_blob_shallow_copy(bs, blob_ch, blobid, ext_dev,
9495 : : blob_shallow_copy_status_cb, NULL,
9496 : : blob_op_complete, NULL);
9497 : 4 : CU_ASSERT(rc == 0);
9498 : 4 : poll_threads();
9499 : 4 : CU_ASSERT(g_bserrno == -EPERM);
9500 : 4 : ext_dev->destroy(ext_dev);
9501 : :
9502 : : /* Set blob read only */
9503 : 4 : spdk_blob_set_read_only(blob);
9504 : 4 : spdk_blob_sync_md(blob, blob_op_complete, NULL);
9505 : 4 : poll_threads();
9506 : 4 : CU_ASSERT(g_bserrno == 0);
9507 : :
9508 : : /* Shallow copy over a spdk_bs_dev with incorrect size */
9509 : 4 : ext_dev = init_ext_dev(1, DEV_BUFFER_BLOCKLEN);
9510 : 4 : rc = spdk_bs_blob_shallow_copy(bs, blob_ch, blobid, ext_dev,
9511 : : blob_shallow_copy_status_cb, NULL,
9512 : : blob_op_complete, NULL);
9513 : 4 : CU_ASSERT(rc == 0);
9514 : 4 : poll_threads();
9515 : 4 : CU_ASSERT(g_bserrno == -EINVAL);
9516 : 4 : ext_dev->destroy(ext_dev);
9517 : :
9518 : : /* Shallow copy over a spdk_bs_dev with incorrect block len */
9519 : 4 : ext_dev = init_ext_dev(num_clusters * 1024 * 1024, DEV_BUFFER_BLOCKLEN * 2);
9520 : 4 : rc = spdk_bs_blob_shallow_copy(bs, blob_ch, blobid, ext_dev,
9521 : : blob_shallow_copy_status_cb, NULL,
9522 : : blob_op_complete, NULL);
9523 : 4 : CU_ASSERT(rc == 0);
9524 : 4 : poll_threads();
9525 : 4 : CU_ASSERT(g_bserrno == -EINVAL);
9526 : 4 : ext_dev->destroy(ext_dev);
9527 : :
9528 : : /* Initialize ext_dev for the successuful shallow copy */
9529 : 4 : ext_dev = init_ext_dev(num_clusters * 1024 * 1024, DEV_BUFFER_BLOCKLEN);
9530 : 4 : bdev_ch = ext_dev->create_channel(ext_dev);
9531 [ - + ]: 4 : SPDK_CU_ASSERT_FATAL(bdev_ch != NULL);
9532 : 4 : ext_args.cb_fn = bs_dev_io_complete_cb;
9533 [ + + ]: 4100 : for (offset = 0; offset < 4 * io_units_per_cluster; offset++) {
9534 : 4096 : memset(buf2, 0xff, DEV_BUFFER_BLOCKLEN);
9535 : 4096 : ext_dev->write(ext_dev, bdev_ch, buf2, offset, 1, &ext_args);
9536 : 4096 : poll_threads();
9537 : 4096 : CU_ASSERT(g_bserrno == 0);
9538 : 4096 : }
9539 : :
9540 : : /* Correct shallow copy of blob over bdev */
9541 : 4 : rc = spdk_bs_blob_shallow_copy(bs, blob_ch, blobid, ext_dev,
9542 : : blob_shallow_copy_status_cb, NULL,
9543 : : blob_op_complete, NULL);
9544 : 4 : CU_ASSERT(rc == 0);
9545 : 4 : poll_thread_times(0, 1);
9546 : 4 : CU_ASSERT(g_copied_clusters_count == 1);
9547 : 4 : poll_thread_times(0, 2);
9548 : 4 : CU_ASSERT(g_bserrno == 0);
9549 : 4 : CU_ASSERT(g_copied_clusters_count == 2);
9550 : :
9551 : : /* Read from bdev */
9552 : : /* Only cluster 1 and 3 must be filled */
9553 : : /* Clusters 2 and 4 should not have been touched */
9554 [ + + ]: 1028 : for (offset = 0; offset < io_units_per_cluster; offset++) {
9555 : 1024 : memset(buf1, offset, DEV_BUFFER_BLOCKLEN);
9556 : 1024 : ext_dev->read(ext_dev, bdev_ch, buf2, offset, 1, &ext_args);
9557 : 1024 : poll_threads();
9558 : 1024 : CU_ASSERT(g_bserrno == 0);
9559 : 1024 : CU_ASSERT(memcmp(buf1, buf2, DEV_BUFFER_BLOCKLEN) == 0);
9560 : 1024 : }
9561 [ + + ]: 1028 : for (offset = io_units_per_cluster; offset < 2 * io_units_per_cluster; offset++) {
9562 : 1024 : memset(buf1, 0xff, DEV_BUFFER_BLOCKLEN);
9563 : 1024 : ext_dev->read(ext_dev, bdev_ch, buf2, offset, 1, &ext_args);
9564 : 1024 : poll_threads();
9565 : 1024 : CU_ASSERT(g_bserrno == 0);
9566 : 1024 : CU_ASSERT(memcmp(buf1, buf2, DEV_BUFFER_BLOCKLEN) == 0);
9567 : 1024 : }
9568 [ + + ]: 1028 : for (offset = 2 * io_units_per_cluster; offset < 3 * io_units_per_cluster; offset++) {
9569 : 1024 : memset(buf1, offset, DEV_BUFFER_BLOCKLEN);
9570 : 1024 : ext_dev->read(ext_dev, bdev_ch, buf2, offset, 1, &ext_args);
9571 : 1024 : poll_threads();
9572 : 1024 : CU_ASSERT(g_bserrno == 0);
9573 : 1024 : CU_ASSERT(memcmp(buf1, buf2, DEV_BUFFER_BLOCKLEN) == 0);
9574 : 1024 : }
9575 [ + + ]: 1028 : for (offset = 3 * io_units_per_cluster; offset < 4 * io_units_per_cluster; offset++) {
9576 : 1024 : memset(buf1, 0xff, DEV_BUFFER_BLOCKLEN);
9577 : 1024 : ext_dev->read(ext_dev, bdev_ch, buf2, offset, 1, &ext_args);
9578 : 1024 : poll_threads();
9579 : 1024 : CU_ASSERT(g_bserrno == 0);
9580 : 1024 : CU_ASSERT(memcmp(buf1, buf2, DEV_BUFFER_BLOCKLEN) == 0);
9581 : 1024 : }
9582 : :
9583 : : /* Clean up */
9584 : 4 : ext_dev->destroy_channel(ext_dev, bdev_ch);
9585 : 4 : ext_dev->destroy(ext_dev);
9586 : 4 : spdk_bs_free_io_channel(blob_ch);
9587 : 4 : ut_blob_close_and_delete(bs, blob);
9588 : 4 : poll_threads();
9589 : 4 : }
9590 : :
9591 : : static void
9592 : 4 : blob_set_parent(void)
9593 : : {
9594 : 4 : struct spdk_blob_store *bs = g_bs;
9595 : : struct spdk_blob_opts opts;
9596 : : struct ut_esnap_opts esnap_opts;
9597 : : struct spdk_blob *blob1, *blob2, *blob3, *blob4, *blob5;
9598 : : spdk_blob_id blobid1, blobid2, blobid3, blobid4, blobid5,
9599 : : snapshotid1, snapshotid2, snapshotid3;
9600 : : uint32_t cluster_sz, block_sz;
9601 : 4 : const uint32_t esnap_num_clusters = 4;
9602 : : uint64_t esnap_num_blocks;
9603 : : spdk_blob_id ids[2];
9604 : 4 : size_t clone_count = 2;
9605 : :
9606 : 4 : cluster_sz = spdk_bs_get_cluster_size(bs);
9607 : 4 : block_sz = spdk_bs_get_io_unit_size(bs);
9608 : 4 : esnap_num_blocks = cluster_sz * esnap_num_clusters / block_sz;
9609 : :
9610 : : /* Create a normal blob and make a couple of snapshots */
9611 : 4 : ut_spdk_blob_opts_init(&opts);
9612 : 4 : blob1 = ut_blob_create_and_open(bs, &opts);
9613 [ + - ]: 4 : SPDK_CU_ASSERT_FATAL(blob1 != NULL);
9614 : 4 : blobid1 = spdk_blob_get_id(blob1);
9615 : 4 : spdk_bs_create_snapshot(bs, blobid1, NULL, blob_op_with_id_complete, NULL);
9616 : 4 : poll_threads();
9617 [ + - ]: 4 : SPDK_CU_ASSERT_FATAL(g_bserrno == 0);
9618 [ + - ]: 4 : SPDK_CU_ASSERT_FATAL(g_blobid != SPDK_BLOBID_INVALID);
9619 : 4 : snapshotid1 = g_blobid;
9620 : 4 : spdk_bs_create_snapshot(bs, blobid1, NULL, blob_op_with_id_complete, NULL);
9621 : 4 : poll_threads();
9622 [ + - ]: 4 : SPDK_CU_ASSERT_FATAL(g_bserrno == 0);
9623 [ + - ]: 4 : SPDK_CU_ASSERT_FATAL(g_blobid != SPDK_BLOBID_INVALID);
9624 : 4 : snapshotid2 = g_blobid;
9625 : :
9626 : : /* Call set_parent with an invalid snapshotid */
9627 : 4 : spdk_bs_blob_set_parent(bs, blobid1, SPDK_BLOBID_INVALID, blob_op_complete, NULL);
9628 : 4 : poll_threads();
9629 : 4 : CU_ASSERT(g_bserrno == -EINVAL);
9630 : :
9631 : : /* Call set_parent with blobid and snapshotid the same */
9632 : 4 : spdk_bs_blob_set_parent(bs, blobid1, blobid1, blob_op_complete, NULL);
9633 : 4 : poll_threads();
9634 : 4 : CU_ASSERT(g_bserrno == -EINVAL);
9635 : :
9636 : : /* Call set_parent with a blob and its parent snapshot */
9637 : 4 : spdk_bs_blob_set_parent(bs, blobid1, snapshotid2, blob_op_complete, NULL);
9638 : 4 : poll_threads();
9639 : 4 : CU_ASSERT(g_bserrno == -EEXIST);
9640 : :
9641 : : /* Create an esnap clone blob */
9642 : 4 : ut_spdk_blob_opts_init(&opts);
9643 : 4 : ut_esnap_opts_init(block_sz, esnap_num_blocks, __func__, NULL, &esnap_opts);
9644 : 4 : opts.esnap_id = &esnap_opts;
9645 : 4 : opts.esnap_id_len = sizeof(esnap_opts);
9646 : 4 : opts.num_clusters = esnap_num_clusters;
9647 : 4 : blob2 = ut_blob_create_and_open(bs, &opts);
9648 [ + - ]: 4 : SPDK_CU_ASSERT_FATAL(blob2 != NULL);
9649 : 4 : blobid2 = spdk_blob_get_id(blob2);
9650 : 4 : CU_ASSERT(spdk_blob_is_esnap_clone(blob2));
9651 : :
9652 : : /* Call set_parent with a non snapshot parent */
9653 : 4 : spdk_bs_blob_set_parent(bs, blobid2, blobid1, blob_op_complete, NULL);
9654 : 4 : poll_threads();
9655 : 4 : CU_ASSERT(g_bserrno == -EINVAL);
9656 : :
9657 : : /* Call set_parent with blob and snapshot of different size */
9658 : 4 : spdk_bs_blob_set_parent(bs, blobid2, snapshotid1, blob_op_complete, NULL);
9659 : 4 : poll_threads();
9660 : 4 : CU_ASSERT(g_bserrno == -EINVAL);
9661 : :
9662 : : /* Call set_parent correctly with a snapshot's clone blob */
9663 : 4 : spdk_bs_blob_set_parent(bs, blobid1, snapshotid1, blob_op_complete, NULL);
9664 : 4 : poll_threads();
9665 : 4 : CU_ASSERT(g_bserrno == 0);
9666 : :
9667 : : /* Check relations */
9668 : 4 : CU_ASSERT(spdk_blob_is_clone(blob1));
9669 : 4 : CU_ASSERT(spdk_blob_get_parent_snapshot(bs, blobid1) == snapshotid1);
9670 : 4 : CU_ASSERT(spdk_blob_get_clones(bs, snapshotid1, ids, &clone_count) == 0);
9671 : 4 : CU_ASSERT(clone_count == 2);
9672 : 4 : CU_ASSERT(ids[1] == blobid1);
9673 : :
9674 : : /* Create another normal blob with size equal to esnap size and make a snapshot */
9675 : 4 : ut_spdk_blob_opts_init(&opts);
9676 : 4 : opts.num_clusters = esnap_num_clusters;
9677 : 4 : opts.thin_provision = true;
9678 : 4 : blob3 = ut_blob_create_and_open(bs, &opts);
9679 [ + - ]: 4 : SPDK_CU_ASSERT_FATAL(blob3 != NULL);
9680 : 4 : blobid3 = spdk_blob_get_id(blob3);
9681 : 4 : spdk_bs_create_snapshot(bs, blobid3, NULL, blob_op_with_id_complete, NULL);
9682 : 4 : poll_threads();
9683 [ + - ]: 4 : SPDK_CU_ASSERT_FATAL(g_bserrno == 0);
9684 [ + - ]: 4 : SPDK_CU_ASSERT_FATAL(g_blobid != SPDK_BLOBID_INVALID);
9685 : 4 : snapshotid3 = g_blobid;
9686 : :
9687 : : /* Call set_parent correctly with an esnap's clone blob */
9688 : 4 : spdk_bs_blob_set_parent(bs, blobid2, snapshotid3, blob_op_complete, NULL);
9689 : 4 : poll_threads();
9690 : 4 : CU_ASSERT(g_bserrno == 0);
9691 : :
9692 : : /* Check relations */
9693 : 4 : CU_ASSERT(!spdk_blob_is_esnap_clone(blob2));
9694 : 4 : CU_ASSERT(spdk_blob_is_clone(blob2));
9695 : 4 : CU_ASSERT(spdk_blob_get_parent_snapshot(bs, blobid2) == snapshotid3);
9696 : 4 : CU_ASSERT(spdk_blob_get_clones(bs, snapshotid3, ids, &clone_count) == 0);
9697 : 4 : CU_ASSERT(clone_count == 2);
9698 : 4 : CU_ASSERT(ids[1] == blobid2);
9699 : :
9700 : : /* Create a not thin-provisioned blob that is not a clone */
9701 : 4 : ut_spdk_blob_opts_init(&opts);
9702 : 4 : opts.thin_provision = false;
9703 : 4 : blob4 = ut_blob_create_and_open(bs, &opts);
9704 [ + - ]: 4 : SPDK_CU_ASSERT_FATAL(blob4 != NULL);
9705 : 4 : blobid4 = spdk_blob_get_id(blob4);
9706 : :
9707 : : /* Call set_parent with a blob that isn't a clone and that isn't thin-provisioned */
9708 : 4 : spdk_bs_blob_set_parent(bs, blobid4, snapshotid2, blob_op_complete, NULL);
9709 : 4 : poll_threads();
9710 : 4 : CU_ASSERT(g_bserrno == -EINVAL);
9711 : :
9712 : : /* Create a thin-provisioned blob that is not a clone */
9713 : 4 : ut_spdk_blob_opts_init(&opts);
9714 : 4 : opts.thin_provision = true;
9715 : 4 : blob5 = ut_blob_create_and_open(bs, &opts);
9716 [ - + ]: 4 : SPDK_CU_ASSERT_FATAL(blob5 != NULL);
9717 : 4 : blobid5 = spdk_blob_get_id(blob5);
9718 : :
9719 : : /* Call set_parent correctly with a blob that isn't a clone */
9720 : 4 : spdk_bs_blob_set_parent(bs, blobid5, snapshotid2, blob_op_complete, NULL);
9721 : 4 : poll_threads();
9722 : 4 : CU_ASSERT(g_bserrno == 0);
9723 : :
9724 : : /* Check relations */
9725 : 4 : CU_ASSERT(spdk_blob_is_clone(blob5));
9726 : 4 : CU_ASSERT(spdk_blob_get_parent_snapshot(bs, blobid5) == snapshotid2);
9727 : 4 : CU_ASSERT(spdk_blob_get_clones(bs, snapshotid2, ids, &clone_count) == 0);
9728 : 4 : CU_ASSERT(clone_count == 1);
9729 : 4 : CU_ASSERT(ids[0] == blobid5);
9730 : :
9731 : : /* Clean up */
9732 : 4 : ut_blob_close_and_delete(bs, blob5);
9733 : 4 : ut_blob_close_and_delete(bs, blob4);
9734 : 4 : ut_blob_close_and_delete(bs, blob3);
9735 : 4 : ut_blob_close_and_delete(bs, blob2);
9736 : 4 : ut_blob_close_and_delete(bs, blob1);
9737 : 4 : spdk_bs_delete_blob(bs, snapshotid3, blob_op_complete, NULL);
9738 : 4 : poll_threads();
9739 : 4 : CU_ASSERT(g_bserrno == 0);
9740 : 4 : spdk_bs_delete_blob(bs, snapshotid2, blob_op_complete, NULL);
9741 : 4 : poll_threads();
9742 : 4 : CU_ASSERT(g_bserrno == 0);
9743 : 4 : spdk_bs_delete_blob(bs, snapshotid1, blob_op_complete, NULL);
9744 : 4 : poll_threads();
9745 : 4 : CU_ASSERT(g_bserrno == 0);
9746 : 4 : }
9747 : :
9748 : : static void
9749 : 4 : blob_set_external_parent(void)
9750 : : {
9751 : 4 : struct spdk_blob_store *bs = g_bs;
9752 : : struct spdk_blob_opts opts;
9753 : : struct ut_esnap_opts esnap_opts, esnap_opts2;
9754 : : struct spdk_blob *blob1, *blob2, *blob3, *blob4;
9755 : : spdk_blob_id blobid1, blobid2, blobid3, blobid4, snapshotid;
9756 : : uint32_t cluster_sz, block_sz;
9757 : 4 : const uint32_t esnap_num_clusters = 4;
9758 : : uint64_t esnap_num_blocks;
9759 : : struct spdk_bs_dev *esnap_dev1, *esnap_dev2, *esnap_dev3;
9760 : : const void *esnap_id;
9761 : : size_t esnap_id_len;
9762 : : int rc;
9763 : :
9764 : 4 : cluster_sz = spdk_bs_get_cluster_size(bs);
9765 : 4 : block_sz = spdk_bs_get_io_unit_size(bs);
9766 : 4 : esnap_num_blocks = cluster_sz * esnap_num_clusters / block_sz;
9767 : 4 : esnap_dev1 = init_dev();
9768 : 4 : esnap_dev2 = init_dev();
9769 : 4 : esnap_dev3 = init_dev();
9770 : :
9771 : : /* Create an esnap clone blob */
9772 : 4 : ut_spdk_blob_opts_init(&opts);
9773 : 4 : ut_esnap_opts_init(block_sz, esnap_num_blocks, __func__, NULL, &esnap_opts);
9774 : 4 : opts.esnap_id = &esnap_opts;
9775 : 4 : opts.esnap_id_len = sizeof(esnap_opts);
9776 : 4 : opts.num_clusters = esnap_num_clusters;
9777 : 4 : blob1 = ut_blob_create_and_open(bs, &opts);
9778 [ + - ]: 4 : SPDK_CU_ASSERT_FATAL(blob1 != NULL);
9779 : 4 : blobid1 = spdk_blob_get_id(blob1);
9780 : 4 : CU_ASSERT(spdk_blob_is_esnap_clone(blob1));
9781 : :
9782 : : /* Call set_esternal_parent with blobid and esnapid the same */
9783 : 4 : spdk_bs_blob_set_external_parent(bs, blobid1, esnap_dev1, &blobid1, sizeof(blobid1),
9784 : : blob_op_complete, NULL);
9785 : 4 : CU_ASSERT(g_bserrno == -EINVAL);
9786 : :
9787 : : /* Call set_external_parent with esnap of incompatible size */
9788 : 4 : esnap_dev1->blockcnt = esnap_num_blocks - 1;
9789 : 4 : spdk_bs_blob_set_external_parent(bs, blobid1, esnap_dev1, opts.esnap_id, opts.esnap_id_len,
9790 : : blob_op_complete, NULL);
9791 : 4 : CU_ASSERT(g_bserrno == -EINVAL);
9792 : :
9793 : : /* Call set_external_parent with a blob and its parent esnap */
9794 : 4 : esnap_dev1->blocklen = block_sz;
9795 : 4 : esnap_dev1->blockcnt = esnap_num_blocks;
9796 : 4 : spdk_bs_blob_set_external_parent(bs, blobid1, esnap_dev1, opts.esnap_id, opts.esnap_id_len,
9797 : : blob_op_complete, NULL);
9798 : 4 : poll_threads();
9799 : 4 : CU_ASSERT(g_bserrno == -EEXIST);
9800 : :
9801 : : /* Create a blob that is a clone of a snapshots */
9802 : 4 : ut_spdk_blob_opts_init(&opts);
9803 : 4 : blob2 = ut_blob_create_and_open(bs, &opts);
9804 [ + - ]: 4 : SPDK_CU_ASSERT_FATAL(blob2 != NULL);
9805 : 4 : blobid2 = spdk_blob_get_id(blob2);
9806 : 4 : spdk_bs_create_snapshot(bs, blobid2, NULL, blob_op_with_id_complete, NULL);
9807 : 4 : poll_threads();
9808 [ + - ]: 4 : SPDK_CU_ASSERT_FATAL(g_bserrno == 0);
9809 [ + - ]: 4 : SPDK_CU_ASSERT_FATAL(g_blobid != SPDK_BLOBID_INVALID);
9810 : 4 : snapshotid = g_blobid;
9811 : :
9812 : : /* Call set_parent correctly with a snapshot's clone blob */
9813 : 4 : esnap_dev2->blocklen = block_sz;
9814 : 4 : esnap_dev2->blockcnt = esnap_num_blocks;
9815 : 4 : ut_esnap_opts_init(block_sz, esnap_num_blocks, __func__, NULL, &esnap_opts2);
9816 : 4 : spdk_bs_blob_set_external_parent(bs, blobid2, esnap_dev2, &esnap_opts2, sizeof(esnap_opts2),
9817 : : blob_op_complete, NULL);
9818 : 4 : poll_threads();
9819 : 4 : CU_ASSERT(g_bserrno == 0);
9820 : :
9821 : : /* Check relations */
9822 : 4 : rc = spdk_blob_get_esnap_id(blob2, &esnap_id, &esnap_id_len);
9823 : 4 : CU_ASSERT(spdk_blob_is_esnap_clone(blob2));
9824 : 4 : CU_ASSERT(!spdk_blob_is_clone(blob2));
9825 [ + - - + ]: 4 : CU_ASSERT(rc == 0 && esnap_id_len == sizeof(esnap_opts2) &&
9826 : : memcmp(esnap_id, &esnap_opts2, esnap_id_len) == 0);
9827 : 4 : CU_ASSERT(blob2->parent_id == SPDK_BLOBID_EXTERNAL_SNAPSHOT);
9828 : :
9829 : : /* Create a not thin-provisioned blob that is not a clone */
9830 : 4 : ut_spdk_blob_opts_init(&opts);
9831 : 4 : opts.thin_provision = false;
9832 : 4 : blob3 = ut_blob_create_and_open(bs, &opts);
9833 [ + - ]: 4 : SPDK_CU_ASSERT_FATAL(blob3 != NULL);
9834 : 4 : blobid3 = spdk_blob_get_id(blob3);
9835 : :
9836 : : /* Call set_external_parent with a blob that isn't a clone and that isn't thin-provisioned */
9837 : 4 : spdk_bs_blob_set_external_parent(bs, blobid3, esnap_dev1, &esnap_opts, sizeof(esnap_opts),
9838 : : blob_op_complete, NULL);
9839 : 4 : poll_threads();
9840 : 4 : CU_ASSERT(g_bserrno == -EINVAL);
9841 : :
9842 : : /* Create a thin-provisioned blob that is not a clone */
9843 : 4 : ut_spdk_blob_opts_init(&opts);
9844 : 4 : opts.thin_provision = true;
9845 : 4 : blob4 = ut_blob_create_and_open(bs, &opts);
9846 [ - + ]: 4 : SPDK_CU_ASSERT_FATAL(blob4 != NULL);
9847 : 4 : blobid4 = spdk_blob_get_id(blob4);
9848 : :
9849 : : /* Call set_external_parent correctly with a blob that isn't a clone */
9850 : 4 : esnap_dev3->blocklen = block_sz;
9851 : 4 : esnap_dev3->blockcnt = esnap_num_blocks;
9852 : 4 : ut_esnap_opts_init(block_sz, esnap_num_blocks, __func__, NULL, &esnap_opts);
9853 : 4 : spdk_bs_blob_set_external_parent(bs, blobid4, esnap_dev3, &esnap_opts, sizeof(esnap_opts),
9854 : : blob_op_complete, NULL);
9855 : 4 : poll_threads();
9856 : 4 : CU_ASSERT(g_bserrno == 0);
9857 : :
9858 : : /* Check relations */
9859 : 4 : rc = spdk_blob_get_esnap_id(blob4, &esnap_id, &esnap_id_len);
9860 : 4 : CU_ASSERT(spdk_blob_is_esnap_clone(blob4));
9861 : 4 : CU_ASSERT(!spdk_blob_is_clone(blob4));
9862 [ + - - + ]: 4 : CU_ASSERT(rc == 0 && esnap_id_len == sizeof(esnap_opts) &&
9863 : : memcmp(esnap_id, &esnap_opts, esnap_id_len) == 0);
9864 : 4 : CU_ASSERT(blob4->parent_id == SPDK_BLOBID_EXTERNAL_SNAPSHOT);
9865 : :
9866 : 4 : ut_blob_close_and_delete(bs, blob4);
9867 : 4 : ut_blob_close_and_delete(bs, blob3);
9868 : 4 : ut_blob_close_and_delete(bs, blob2);
9869 : 4 : ut_blob_close_and_delete(bs, blob1);
9870 : 4 : spdk_bs_delete_blob(bs, snapshotid, blob_op_complete, NULL);
9871 : 4 : dev_destroy(esnap_dev1);
9872 : 4 : poll_threads();
9873 : 4 : CU_ASSERT(g_bserrno == 0);
9874 : 4 : }
9875 : :
9876 : : static void
9877 : 220 : suite_bs_setup(void)
9878 : : {
9879 : : struct spdk_bs_dev *dev;
9880 : :
9881 : 220 : dev = init_dev();
9882 : 220 : memset(g_dev_buffer, 0, DEV_BUFFER_SIZE);
9883 : 220 : spdk_bs_init(dev, NULL, bs_op_with_handle_complete, NULL);
9884 : 220 : poll_threads();
9885 : 220 : CU_ASSERT(g_bserrno == 0);
9886 : 220 : CU_ASSERT(g_bs != NULL);
9887 : 220 : }
9888 : :
9889 : : static void
9890 : 36 : suite_esnap_bs_setup(void)
9891 : : {
9892 : : struct spdk_bs_dev *dev;
9893 : : struct spdk_bs_opts bs_opts;
9894 : :
9895 : 36 : dev = init_dev();
9896 : 36 : memset(g_dev_buffer, 0, DEV_BUFFER_SIZE);
9897 : 36 : spdk_bs_opts_init(&bs_opts, sizeof(bs_opts));
9898 : 36 : bs_opts.cluster_sz = 16 * 1024;
9899 : 36 : bs_opts.esnap_bs_dev_create = ut_esnap_create;
9900 : 36 : spdk_bs_init(dev, &bs_opts, bs_op_with_handle_complete, NULL);
9901 : 36 : poll_threads();
9902 : 36 : CU_ASSERT(g_bserrno == 0);
9903 [ + - ]: 36 : SPDK_CU_ASSERT_FATAL(g_bs != NULL);
9904 : 36 : }
9905 : :
9906 : : static void
9907 : 256 : suite_bs_cleanup(void)
9908 : : {
9909 [ + - ]: 256 : if (g_bs != NULL) {
9910 : 256 : spdk_bs_unload(g_bs, bs_op_complete, NULL);
9911 : 256 : poll_threads();
9912 : 256 : CU_ASSERT(g_bserrno == 0);
9913 : 256 : g_bs = NULL;
9914 : 256 : }
9915 : 256 : memset(g_dev_buffer, 0, DEV_BUFFER_SIZE);
9916 : 256 : }
9917 : :
9918 : : static struct spdk_blob *
9919 : 360 : ut_blob_create_and_open(struct spdk_blob_store *bs, struct spdk_blob_opts *blob_opts)
9920 : : {
9921 : : struct spdk_blob *blob;
9922 : : struct spdk_blob_opts create_blob_opts;
9923 : : spdk_blob_id blobid;
9924 : :
9925 [ + + ]: 360 : if (blob_opts == NULL) {
9926 : 128 : ut_spdk_blob_opts_init(&create_blob_opts);
9927 : 128 : blob_opts = &create_blob_opts;
9928 : 128 : }
9929 : :
9930 : 360 : spdk_bs_create_blob_ext(bs, blob_opts, blob_op_with_id_complete, NULL);
9931 : 360 : poll_threads();
9932 : 360 : CU_ASSERT(g_bserrno == 0);
9933 : 360 : CU_ASSERT(g_blobid != SPDK_BLOBID_INVALID);
9934 : 360 : blobid = g_blobid;
9935 : 360 : g_blobid = -1;
9936 : :
9937 : 360 : spdk_bs_open_blob(bs, blobid, blob_op_with_handle_complete, NULL);
9938 : 360 : poll_threads();
9939 : 360 : CU_ASSERT(g_bserrno == 0);
9940 : 360 : CU_ASSERT(g_blob != NULL);
9941 : 360 : blob = g_blob;
9942 : :
9943 : 360 : g_blob = NULL;
9944 : 360 : g_bserrno = -1;
9945 : :
9946 : 360 : return blob;
9947 : : }
9948 : :
9949 : : static void
9950 : 320 : ut_blob_close_and_delete(struct spdk_blob_store *bs, struct spdk_blob *blob)
9951 : : {
9952 : 320 : spdk_blob_id blobid = spdk_blob_get_id(blob);
9953 : :
9954 : 320 : spdk_blob_close(blob, blob_op_complete, NULL);
9955 : 320 : poll_threads();
9956 : 320 : CU_ASSERT(g_bserrno == 0);
9957 : 320 : g_blob = NULL;
9958 : :
9959 : 320 : spdk_bs_delete_blob(bs, blobid, blob_op_complete, NULL);
9960 : 320 : poll_threads();
9961 : 320 : CU_ASSERT(g_bserrno == 0);
9962 : 320 : g_bserrno = -1;
9963 : 320 : }
9964 : :
9965 : : static void
9966 : 48 : suite_blob_setup(void)
9967 : : {
9968 : 48 : suite_bs_setup();
9969 : 48 : CU_ASSERT(g_bs != NULL);
9970 : :
9971 : 48 : g_blob = ut_blob_create_and_open(g_bs, NULL);
9972 : 48 : CU_ASSERT(g_blob != NULL);
9973 : 48 : }
9974 : :
9975 : : static void
9976 : 48 : suite_blob_cleanup(void)
9977 : : {
9978 : 48 : ut_blob_close_and_delete(g_bs, g_blob);
9979 : 48 : CU_ASSERT(g_blob == NULL);
9980 : :
9981 : 48 : suite_bs_cleanup();
9982 : 48 : CU_ASSERT(g_bs == NULL);
9983 : 48 : }
9984 : :
9985 : : static int
9986 : 4 : ut_setup_config_nocopy_noextent(void)
9987 : : {
9988 : 4 : g_dev_copy_enabled = false;
9989 : 4 : g_use_extent_table = false;
9990 : :
9991 : 4 : return 0;
9992 : : }
9993 : :
9994 : : static int
9995 : 4 : ut_setup_config_nocopy_extent(void)
9996 : : {
9997 : 4 : g_dev_copy_enabled = false;
9998 : 4 : g_use_extent_table = true;
9999 : :
10000 : 4 : return 0;
10001 : : }
10002 : :
10003 : : static int
10004 : 4 : ut_setup_config_copy_noextent(void)
10005 : : {
10006 : 4 : g_dev_copy_enabled = true;
10007 : 4 : g_use_extent_table = false;
10008 : :
10009 : 4 : return 0;
10010 : : }
10011 : :
10012 : : static int
10013 : 4 : ut_setup_config_copy_extent(void)
10014 : : {
10015 : 4 : g_dev_copy_enabled = true;
10016 : 4 : g_use_extent_table = true;
10017 : :
10018 : 4 : return 0;
10019 : : }
10020 : :
10021 : : struct ut_config {
10022 : : const char *suffix;
10023 : : CU_InitializeFunc setup_cb;
10024 : : };
10025 : :
10026 : : int
10027 : 1 : main(int argc, char **argv)
10028 : : {
10029 : : CU_pSuite suite, suite_bs, suite_blob, suite_esnap_bs;
10030 : : unsigned int i, num_failures;
10031 : : char suite_name[4096];
10032 : : struct ut_config *config;
10033 : 1 : struct ut_config configs[] = {
10034 : : {"nocopy_noextent", ut_setup_config_nocopy_noextent},
10035 : : {"nocopy_extent", ut_setup_config_nocopy_extent},
10036 : : {"copy_noextent", ut_setup_config_copy_noextent},
10037 : : {"copy_extent", ut_setup_config_copy_extent},
10038 : : };
10039 : :
10040 : 1 : CU_initialize_registry();
10041 : :
10042 [ + + ]: 5 : for (i = 0; i < SPDK_COUNTOF(configs); ++i) {
10043 : 4 : config = &configs[i];
10044 : :
10045 : 4 : snprintf(suite_name, sizeof(suite_name), "blob_%s", config->suffix);
10046 : 4 : suite = CU_add_suite(suite_name, config->setup_cb, NULL);
10047 : :
10048 : 4 : snprintf(suite_name, sizeof(suite_name), "blob_bs_%s", config->suffix);
10049 : 4 : suite_bs = CU_add_suite_with_setup_and_teardown(suite_name, config->setup_cb, NULL,
10050 : : suite_bs_setup, suite_bs_cleanup);
10051 : :
10052 : 4 : snprintf(suite_name, sizeof(suite_name), "blob_blob_%s", config->suffix);
10053 : 4 : suite_blob = CU_add_suite_with_setup_and_teardown(suite_name, config->setup_cb, NULL,
10054 : : suite_blob_setup, suite_blob_cleanup);
10055 : :
10056 : 4 : snprintf(suite_name, sizeof(suite_name), "blob_esnap_bs_%s", config->suffix);
10057 : 4 : suite_esnap_bs = CU_add_suite_with_setup_and_teardown(suite_name, config->setup_cb, NULL,
10058 : : suite_esnap_bs_setup,
10059 : : suite_bs_cleanup);
10060 : :
10061 : 4 : CU_ADD_TEST(suite, blob_init);
10062 : 4 : CU_ADD_TEST(suite_bs, blob_open);
10063 : 4 : CU_ADD_TEST(suite_bs, blob_create);
10064 : 4 : CU_ADD_TEST(suite_bs, blob_create_loop);
10065 : 4 : CU_ADD_TEST(suite_bs, blob_create_fail);
10066 : 4 : CU_ADD_TEST(suite_bs, blob_create_internal);
10067 : 4 : CU_ADD_TEST(suite_bs, blob_create_zero_extent);
10068 : 4 : CU_ADD_TEST(suite, blob_thin_provision);
10069 : 4 : CU_ADD_TEST(suite_bs, blob_snapshot);
10070 : 4 : CU_ADD_TEST(suite_bs, blob_clone);
10071 : 4 : CU_ADD_TEST(suite_bs, blob_inflate);
10072 : 4 : CU_ADD_TEST(suite_bs, blob_delete);
10073 : 4 : CU_ADD_TEST(suite_bs, blob_resize_test);
10074 : 4 : CU_ADD_TEST(suite_bs, blob_resize_thin_test);
10075 : 4 : CU_ADD_TEST(suite, blob_read_only);
10076 : 4 : CU_ADD_TEST(suite_bs, channel_ops);
10077 : 4 : CU_ADD_TEST(suite_bs, blob_super);
10078 : 4 : CU_ADD_TEST(suite_blob, blob_write);
10079 : 4 : CU_ADD_TEST(suite_blob, blob_read);
10080 : 4 : CU_ADD_TEST(suite_blob, blob_rw_verify);
10081 : 4 : CU_ADD_TEST(suite_bs, blob_rw_verify_iov);
10082 : 4 : CU_ADD_TEST(suite_blob, blob_rw_verify_iov_nomem);
10083 : 4 : CU_ADD_TEST(suite_blob, blob_rw_iov_read_only);
10084 : 4 : CU_ADD_TEST(suite_bs, blob_unmap);
10085 : 4 : CU_ADD_TEST(suite_bs, blob_iter);
10086 : 4 : CU_ADD_TEST(suite_blob, blob_xattr);
10087 : 4 : CU_ADD_TEST(suite_bs, blob_parse_md);
10088 : 4 : CU_ADD_TEST(suite, bs_load);
10089 : 4 : CU_ADD_TEST(suite_bs, bs_load_pending_removal);
10090 : 4 : CU_ADD_TEST(suite, bs_load_custom_cluster_size);
10091 : 4 : CU_ADD_TEST(suite, bs_load_after_failed_grow);
10092 : 4 : CU_ADD_TEST(suite_bs, bs_unload);
10093 : 4 : CU_ADD_TEST(suite, bs_cluster_sz);
10094 : 4 : CU_ADD_TEST(suite_bs, bs_usable_clusters);
10095 : 4 : CU_ADD_TEST(suite, bs_resize_md);
10096 : 4 : CU_ADD_TEST(suite, bs_destroy);
10097 : 4 : CU_ADD_TEST(suite, bs_type);
10098 : 4 : CU_ADD_TEST(suite, bs_super_block);
10099 : 4 : CU_ADD_TEST(suite, bs_test_recover_cluster_count);
10100 : 4 : CU_ADD_TEST(suite, bs_grow_live);
10101 : 4 : CU_ADD_TEST(suite, bs_grow_live_no_space);
10102 : 4 : CU_ADD_TEST(suite, bs_test_grow);
10103 : 4 : CU_ADD_TEST(suite, blob_serialize_test);
10104 : 4 : CU_ADD_TEST(suite_bs, blob_crc);
10105 : 4 : CU_ADD_TEST(suite, super_block_crc);
10106 : 4 : CU_ADD_TEST(suite_blob, blob_dirty_shutdown);
10107 : 4 : CU_ADD_TEST(suite_bs, blob_flags);
10108 : 4 : CU_ADD_TEST(suite_bs, bs_version);
10109 : 4 : CU_ADD_TEST(suite_bs, blob_set_xattrs_test);
10110 : 4 : CU_ADD_TEST(suite_bs, blob_thin_prov_alloc);
10111 : 4 : CU_ADD_TEST(suite_bs, blob_insert_cluster_msg_test);
10112 : 4 : CU_ADD_TEST(suite_bs, blob_thin_prov_rw);
10113 : 4 : CU_ADD_TEST(suite, blob_thin_prov_write_count_io);
10114 : 4 : CU_ADD_TEST(suite, blob_thin_prov_unmap_cluster);
10115 : 4 : CU_ADD_TEST(suite_bs, blob_thin_prov_rle);
10116 : 4 : CU_ADD_TEST(suite_bs, blob_thin_prov_rw_iov);
10117 : 4 : CU_ADD_TEST(suite, bs_load_iter_test);
10118 : 4 : CU_ADD_TEST(suite_bs, blob_snapshot_rw);
10119 : 4 : CU_ADD_TEST(suite_bs, blob_snapshot_rw_iov);
10120 : 4 : CU_ADD_TEST(suite, blob_relations);
10121 : 4 : CU_ADD_TEST(suite, blob_relations2);
10122 : 4 : CU_ADD_TEST(suite, blob_relations3);
10123 : 4 : CU_ADD_TEST(suite, blobstore_clean_power_failure);
10124 : 4 : CU_ADD_TEST(suite, blob_delete_snapshot_power_failure);
10125 : 4 : CU_ADD_TEST(suite, blob_create_snapshot_power_failure);
10126 : 4 : CU_ADD_TEST(suite_bs, blob_inflate_rw);
10127 : 4 : CU_ADD_TEST(suite_bs, blob_snapshot_freeze_io);
10128 : 4 : CU_ADD_TEST(suite_bs, blob_operation_split_rw);
10129 : 4 : CU_ADD_TEST(suite_bs, blob_operation_split_rw_iov);
10130 : 4 : CU_ADD_TEST(suite, blob_io_unit);
10131 : 4 : CU_ADD_TEST(suite, blob_io_unit_compatibility);
10132 : 4 : CU_ADD_TEST(suite_bs, blob_simultaneous_operations);
10133 : 4 : CU_ADD_TEST(suite_bs, blob_persist_test);
10134 : 4 : CU_ADD_TEST(suite_bs, blob_decouple_snapshot);
10135 : 4 : CU_ADD_TEST(suite_bs, blob_seek_io_unit);
10136 : 4 : CU_ADD_TEST(suite_esnap_bs, blob_esnap_create);
10137 : 4 : CU_ADD_TEST(suite_bs, blob_nested_freezes);
10138 : 4 : CU_ADD_TEST(suite, blob_ext_md_pages);
10139 : 4 : CU_ADD_TEST(suite, blob_esnap_io_4096_4096);
10140 : 4 : CU_ADD_TEST(suite, blob_esnap_io_512_512);
10141 : 4 : CU_ADD_TEST(suite, blob_esnap_io_4096_512);
10142 : 4 : CU_ADD_TEST(suite, blob_esnap_io_512_4096);
10143 : 4 : CU_ADD_TEST(suite_esnap_bs, blob_esnap_thread_add_remove);
10144 : 4 : CU_ADD_TEST(suite_esnap_bs, blob_esnap_clone_snapshot);
10145 : 4 : CU_ADD_TEST(suite_esnap_bs, blob_esnap_clone_inflate);
10146 : 4 : CU_ADD_TEST(suite_esnap_bs, blob_esnap_clone_decouple);
10147 : 4 : CU_ADD_TEST(suite_esnap_bs, blob_esnap_clone_reload);
10148 : 4 : CU_ADD_TEST(suite_esnap_bs, blob_esnap_hotplug);
10149 : 4 : CU_ADD_TEST(suite_blob, blob_is_degraded);
10150 : 4 : CU_ADD_TEST(suite_bs, blob_clone_resize);
10151 : 4 : CU_ADD_TEST(suite, blob_esnap_clone_resize);
10152 : 4 : CU_ADD_TEST(suite_bs, blob_shallow_copy);
10153 : 4 : CU_ADD_TEST(suite_esnap_bs, blob_set_parent);
10154 : 4 : CU_ADD_TEST(suite_esnap_bs, blob_set_external_parent);
10155 : 4 : }
10156 : :
10157 : 1 : allocate_threads(2);
10158 : 1 : set_thread(0);
10159 : :
10160 : 1 : g_dev_buffer = calloc(1, DEV_BUFFER_SIZE);
10161 : :
10162 : 1 : num_failures = spdk_ut_run_tests(argc, argv, NULL);
10163 : :
10164 : 1 : free(g_dev_buffer);
10165 : :
10166 : 1 : free_threads();
10167 : :
10168 : 1 : return num_failures;
10169 : : }
|