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 "blob/blobstore.c"
17 : : #include "blob/request.c"
18 : : #include "blob/zeroes.c"
19 : : #include "blob/blob_bs_dev.c"
20 : : #include "esnap_dev.c"
21 : :
22 : : struct spdk_blob_store *g_bs;
23 : : spdk_blob_id g_blobid;
24 : : struct spdk_blob *g_blob, *g_blob2;
25 : : int g_bserrno, g_bserrno2;
26 : : struct spdk_xattr_names *g_names;
27 : : int g_done;
28 : : char *g_xattr_names[] = {"first", "second", "third"};
29 : : char *g_xattr_values[] = {"one", "two", "three"};
30 : : uint64_t g_ctx = 1729;
31 : : bool g_use_extent_table = false;
32 : :
33 : : struct spdk_bs_super_block_ver1 {
34 : : uint8_t signature[8];
35 : : uint32_t version;
36 : : uint32_t length;
37 : : uint32_t clean; /* If there was a clean shutdown, this is 1. */
38 : : spdk_blob_id super_blob;
39 : :
40 : : uint32_t cluster_size; /* In bytes */
41 : :
42 : : uint32_t used_page_mask_start; /* Offset from beginning of disk, in pages */
43 : : uint32_t used_page_mask_len; /* Count, in pages */
44 : :
45 : : uint32_t used_cluster_mask_start; /* Offset from beginning of disk, in pages */
46 : : uint32_t used_cluster_mask_len; /* Count, in pages */
47 : :
48 : : uint32_t md_start; /* Offset from beginning of disk, in pages */
49 : : uint32_t md_len; /* Count, in pages */
50 : :
51 : : uint8_t reserved[4036];
52 : : uint32_t crc;
53 : : } __attribute__((packed));
54 : : SPDK_STATIC_ASSERT(sizeof(struct spdk_bs_super_block_ver1) == 0x1000, "Invalid super block size");
55 : :
56 : : static struct spdk_blob *ut_blob_create_and_open(struct spdk_blob_store *bs,
57 : : struct spdk_blob_opts *blob_opts);
58 : : static void ut_blob_close_and_delete(struct spdk_blob_store *bs, struct spdk_blob *blob);
59 : : static void suite_blob_setup(void);
60 : : static void suite_blob_cleanup(void);
61 : :
62 : 0 : DEFINE_STUB(spdk_memory_domain_memzero, int, (struct spdk_memory_domain *src_domain,
63 : : void *src_domain_ctx, struct iovec *iov, uint32_t iovcnt, void (*cpl_cb)(void *, int),
64 : : void *cpl_cb_arg), 0);
65 : :
66 : : static bool
67 : 144 : is_esnap_clone(struct spdk_blob *_blob, const void *id, size_t id_len)
68 : : {
69 : 144 : const void *val = NULL;
70 : 144 : size_t len = 0;
71 : : bool c0, c1, c2, c3;
72 : :
73 : 144 : CU_ASSERT(blob_get_xattr_value(_blob, BLOB_EXTERNAL_SNAPSHOT_ID, &val, &len,
74 : : true) == 0);
75 : 144 : CU_ASSERT((c0 = (len == id_len)));
76 [ + - + + : 144 : CU_ASSERT((c1 = (val != NULL && memcmp(val, id, len) == 0)));
- + + - ]
77 : 144 : CU_ASSERT((c2 = !!(_blob->invalid_flags & SPDK_BLOB_EXTERNAL_SNAPSHOT)));
78 : 144 : CU_ASSERT((c3 = (_blob->parent_id == SPDK_BLOBID_EXTERNAL_SNAPSHOT)));
79 : :
80 [ + - + - : 144 : return c0 && c1 && c2 && c3;
+ - + - ]
81 : : }
82 : :
83 : : static bool
84 : 80 : is_not_esnap_clone(struct spdk_blob *_blob)
85 : : {
86 : 80 : const void *val = NULL;
87 : 80 : size_t len = 0;
88 : : bool c1, c2, c3, c4;
89 : :
90 : 80 : CU_ASSERT((c1 = (blob_get_xattr_value(_blob, BLOB_EXTERNAL_SNAPSHOT_ID, &val, &len,
91 : : true) == -ENOENT)));
92 : 80 : CU_ASSERT((c2 = (val == NULL)));
93 : 80 : CU_ASSERT((c3 = ((_blob->invalid_flags & SPDK_BLOB_EXTERNAL_SNAPSHOT) == 0)));
94 : 80 : CU_ASSERT((c4 = (_blob->parent_id != SPDK_BLOBID_EXTERNAL_SNAPSHOT)));
95 : :
96 [ + - + - : 80 : return c1 && c2 && c3 && c4;
+ - + - ]
97 : : }
98 : :
99 : : #define UT_ASSERT_IS_ESNAP_CLONE(_blob, _id, _len) CU_ASSERT(is_esnap_clone(_blob, _id, _len))
100 : : #define UT_ASSERT_IS_NOT_ESNAP_CLONE(_blob) CU_ASSERT(is_not_esnap_clone(_blob))
101 : :
102 : : static void
103 : 192 : _get_xattr_value(void *arg, const char *name,
104 : : const void **value, size_t *value_len)
105 : : {
106 : : uint64_t i;
107 : :
108 [ - + ]: 192 : SPDK_CU_ASSERT_FATAL(value_len != NULL);
109 [ - + ]: 192 : SPDK_CU_ASSERT_FATAL(value != NULL);
110 : 192 : CU_ASSERT(arg == &g_ctx);
111 : :
112 [ + - ]: 384 : for (i = 0; i < sizeof(g_xattr_names); i++) {
113 [ + + - + : 384 : if (!strcmp(name, g_xattr_names[i])) {
+ + ]
114 [ - + ]: 192 : *value_len = strlen(g_xattr_values[i]);
115 : 192 : *value = g_xattr_values[i];
116 : 192 : break;
117 : : }
118 : : }
119 : 192 : }
120 : :
121 : : static void
122 : 16 : _get_xattr_value_null(void *arg, const char *name,
123 : : const void **value, size_t *value_len)
124 : : {
125 [ - + ]: 16 : SPDK_CU_ASSERT_FATAL(value_len != NULL);
126 [ - + ]: 16 : SPDK_CU_ASSERT_FATAL(value != NULL);
127 : 16 : CU_ASSERT(arg == NULL);
128 : :
129 : 16 : *value_len = 0;
130 : 16 : *value = NULL;
131 : 16 : }
132 : :
133 : : static int
134 : 224 : _get_snapshots_count(struct spdk_blob_store *bs)
135 : : {
136 : 224 : struct spdk_blob_list *snapshot = NULL;
137 : 224 : int count = 0;
138 : :
139 [ + + ]: 448 : TAILQ_FOREACH(snapshot, &bs->snapshots, link) {
140 : 224 : count += 1;
141 : : }
142 : :
143 : 224 : return count;
144 : : }
145 : :
146 : : static void
147 : 5880 : ut_spdk_blob_opts_init(struct spdk_blob_opts *opts)
148 : : {
149 : 5880 : spdk_blob_opts_init(opts, sizeof(*opts));
150 [ - + ]: 5880 : opts->use_extent_table = g_use_extent_table;
151 : 5880 : }
152 : :
153 : : static void
154 : 20744 : bs_op_complete(void *cb_arg, int bserrno)
155 : : {
156 : 20744 : g_bserrno = bserrno;
157 : 20744 : }
158 : :
159 : : static void
160 : 3024 : bs_op_with_handle_complete(void *cb_arg, struct spdk_blob_store *bs,
161 : : int bserrno)
162 : : {
163 : 3024 : g_bs = bs;
164 : 3024 : g_bserrno = bserrno;
165 : 3024 : }
166 : :
167 : : static void
168 : 97432 : blob_op_complete(void *cb_arg, int bserrno)
169 : : {
170 [ + + ]: 97432 : if (cb_arg != NULL) {
171 : 64 : int *errp = cb_arg;
172 : :
173 : 64 : *errp = bserrno;
174 : : }
175 : 97432 : g_bserrno = bserrno;
176 : 97432 : }
177 : :
178 : : static void
179 : 7248 : blob_op_with_id_complete(void *cb_arg, spdk_blob_id blobid, int bserrno)
180 : : {
181 : 7248 : g_blobid = blobid;
182 : 7248 : g_bserrno = bserrno;
183 : 7248 : }
184 : :
185 : : static void
186 : 3640 : blob_op_with_handle_complete(void *cb_arg, struct spdk_blob *blb, int bserrno)
187 : : {
188 : 3640 : g_blob = blb;
189 : 3640 : g_bserrno = bserrno;
190 : 3640 : }
191 : :
192 : : static void
193 : 32 : blob_op_with_handle_complete2(void *cb_arg, struct spdk_blob *blob, int bserrno)
194 : : {
195 [ + + ]: 32 : if (g_blob == NULL) {
196 : 16 : g_blob = blob;
197 : 16 : g_bserrno = bserrno;
198 : : } else {
199 : 16 : g_blob2 = blob;
200 : 16 : g_bserrno2 = bserrno;
201 : : }
202 : 32 : }
203 : :
204 : : static void
205 : 432 : ut_bs_reload(struct spdk_blob_store **bs, struct spdk_bs_opts *opts)
206 : : {
207 : : struct spdk_bs_dev *dev;
208 : :
209 : : /* Unload the blob store */
210 : 432 : spdk_bs_unload(*bs, bs_op_complete, NULL);
211 : 432 : poll_threads();
212 : 432 : CU_ASSERT(g_bserrno == 0);
213 : :
214 : 432 : dev = init_dev();
215 : : /* Load an existing blob store */
216 : 432 : spdk_bs_load(dev, opts, bs_op_with_handle_complete, NULL);
217 : 432 : poll_threads();
218 : 432 : CU_ASSERT(g_bserrno == 0);
219 [ - + ]: 432 : SPDK_CU_ASSERT_FATAL(g_bs != NULL);
220 : 432 : *bs = g_bs;
221 : :
222 : 432 : g_bserrno = -1;
223 : 432 : }
224 : :
225 : : static void
226 : 360 : ut_bs_dirty_load(struct spdk_blob_store **bs, struct spdk_bs_opts *opts)
227 : : {
228 : : struct spdk_bs_dev *dev;
229 : :
230 : : /* Dirty shutdown */
231 : 360 : bs_free(*bs);
232 : :
233 : 360 : dev = init_dev();
234 : : /* Load an existing blob store */
235 : 360 : spdk_bs_load(dev, opts, bs_op_with_handle_complete, NULL);
236 : 360 : poll_threads();
237 : 360 : CU_ASSERT(g_bserrno == 0);
238 [ - + ]: 360 : SPDK_CU_ASSERT_FATAL(g_bs != NULL);
239 : 360 : *bs = g_bs;
240 : :
241 : 360 : g_bserrno = -1;
242 : 360 : }
243 : :
244 : : static void
245 : 16 : blob_init(void)
246 : : {
247 : : struct spdk_blob_store *bs;
248 : : struct spdk_bs_dev *dev;
249 : :
250 : 16 : dev = init_dev();
251 : :
252 : : /* should fail for an unsupported blocklen */
253 : 16 : dev->blocklen = 500;
254 : 16 : spdk_bs_init(dev, NULL, bs_op_with_handle_complete, NULL);
255 : 16 : poll_threads();
256 : 16 : CU_ASSERT(g_bserrno == -EINVAL);
257 : :
258 : 16 : dev = init_dev();
259 : 16 : spdk_bs_init(dev, NULL, bs_op_with_handle_complete, NULL);
260 : 16 : poll_threads();
261 : 16 : CU_ASSERT(g_bserrno == 0);
262 [ - + ]: 16 : SPDK_CU_ASSERT_FATAL(g_bs != NULL);
263 : 16 : bs = g_bs;
264 : :
265 : 16 : spdk_bs_unload(bs, bs_op_complete, NULL);
266 : 16 : poll_threads();
267 : 16 : CU_ASSERT(g_bserrno == 0);
268 : 16 : g_bs = NULL;
269 : 16 : }
270 : :
271 : : static void
272 : 16 : blob_super(void)
273 : : {
274 : 16 : struct spdk_blob_store *bs = g_bs;
275 : : spdk_blob_id blobid;
276 : 16 : struct spdk_blob_opts blob_opts;
277 : :
278 : : /* Get the super blob without having set one */
279 : 16 : spdk_bs_get_super(bs, blob_op_with_id_complete, NULL);
280 : 16 : poll_threads();
281 : 16 : CU_ASSERT(g_bserrno == -ENOENT);
282 : 16 : CU_ASSERT(g_blobid == SPDK_BLOBID_INVALID);
283 : :
284 : : /* Create a blob */
285 : 16 : ut_spdk_blob_opts_init(&blob_opts);
286 : 16 : spdk_bs_create_blob_ext(bs, &blob_opts, blob_op_with_id_complete, NULL);
287 : 16 : poll_threads();
288 : 16 : CU_ASSERT(g_bserrno == 0);
289 : 16 : CU_ASSERT(g_blobid != SPDK_BLOBID_INVALID);
290 : 16 : blobid = g_blobid;
291 : :
292 : : /* Set the blob as the super blob */
293 : 16 : spdk_bs_set_super(bs, blobid, blob_op_complete, NULL);
294 : 16 : poll_threads();
295 : 16 : CU_ASSERT(g_bserrno == 0);
296 : :
297 : : /* Get the super blob */
298 : 16 : spdk_bs_get_super(bs, blob_op_with_id_complete, NULL);
299 : 16 : poll_threads();
300 : 16 : CU_ASSERT(g_bserrno == 0);
301 : 16 : CU_ASSERT(blobid == g_blobid);
302 : 16 : }
303 : :
304 : : static void
305 : 16 : blob_open(void)
306 : : {
307 : 16 : struct spdk_blob_store *bs = g_bs;
308 : : struct spdk_blob *blob;
309 : 16 : struct spdk_blob_opts blob_opts;
310 : : spdk_blob_id blobid, blobid2;
311 : :
312 : 16 : ut_spdk_blob_opts_init(&blob_opts);
313 : 16 : spdk_bs_create_blob_ext(bs, &blob_opts, blob_op_with_id_complete, NULL);
314 : 16 : poll_threads();
315 : 16 : CU_ASSERT(g_bserrno == 0);
316 : 16 : CU_ASSERT(g_blobid != SPDK_BLOBID_INVALID);
317 : 16 : blobid = g_blobid;
318 : :
319 : 16 : spdk_bs_open_blob(bs, blobid, blob_op_with_handle_complete, NULL);
320 : 16 : poll_threads();
321 : 16 : CU_ASSERT(g_bserrno == 0);
322 : 16 : CU_ASSERT(g_blob != NULL);
323 : 16 : blob = g_blob;
324 : :
325 : 16 : blobid2 = spdk_blob_get_id(blob);
326 : 16 : CU_ASSERT(blobid == blobid2);
327 : :
328 : : /* Try to open file again. It should return success. */
329 : 16 : spdk_bs_open_blob(bs, blobid, blob_op_with_handle_complete, NULL);
330 : 16 : poll_threads();
331 : 16 : CU_ASSERT(g_bserrno == 0);
332 : 16 : CU_ASSERT(blob == g_blob);
333 : :
334 : 16 : spdk_blob_close(blob, blob_op_complete, NULL);
335 : 16 : poll_threads();
336 : 16 : CU_ASSERT(g_bserrno == 0);
337 : :
338 : : /*
339 : : * Close the file a second time, releasing the second reference. This
340 : : * should succeed.
341 : : */
342 : 16 : blob = g_blob;
343 : 16 : spdk_blob_close(blob, blob_op_complete, NULL);
344 : 16 : poll_threads();
345 : 16 : CU_ASSERT(g_bserrno == 0);
346 : :
347 : : /*
348 : : * Try to open file again. It should succeed. This tests the case
349 : : * where the file is opened, closed, then re-opened again.
350 : : */
351 : 16 : spdk_bs_open_blob(bs, blobid, blob_op_with_handle_complete, NULL);
352 : 16 : poll_threads();
353 : 16 : CU_ASSERT(g_bserrno == 0);
354 : 16 : CU_ASSERT(g_blob != NULL);
355 : 16 : blob = g_blob;
356 : 16 : spdk_blob_close(blob, blob_op_complete, NULL);
357 : 16 : poll_threads();
358 : 16 : CU_ASSERT(g_bserrno == 0);
359 : :
360 : : /* Try to open file twice in succession. This should return the same
361 : : * blob object.
362 : : */
363 : 16 : g_blob = NULL;
364 : 16 : g_blob2 = NULL;
365 : 16 : g_bserrno = -1;
366 : 16 : g_bserrno2 = -1;
367 : 16 : spdk_bs_open_blob(bs, blobid, blob_op_with_handle_complete2, NULL);
368 : 16 : spdk_bs_open_blob(bs, blobid, blob_op_with_handle_complete2, NULL);
369 : 16 : poll_threads();
370 : 16 : CU_ASSERT(g_bserrno == 0);
371 : 16 : CU_ASSERT(g_bserrno2 == 0);
372 : 16 : CU_ASSERT(g_blob != NULL);
373 : 16 : CU_ASSERT(g_blob2 != NULL);
374 : 16 : CU_ASSERT(g_blob == g_blob2);
375 : :
376 : 16 : g_bserrno = -1;
377 : 16 : spdk_blob_close(g_blob, blob_op_complete, NULL);
378 : 16 : poll_threads();
379 : 16 : CU_ASSERT(g_bserrno == 0);
380 : :
381 : 16 : ut_blob_close_and_delete(bs, g_blob);
382 : 16 : }
383 : :
384 : : static void
385 : 16 : blob_create(void)
386 : : {
387 : 16 : struct spdk_blob_store *bs = g_bs;
388 : : struct spdk_blob *blob;
389 : 16 : struct spdk_blob_opts opts;
390 : : spdk_blob_id blobid;
391 : :
392 : : /* Create blob with 10 clusters */
393 : :
394 : 16 : ut_spdk_blob_opts_init(&opts);
395 : 16 : opts.num_clusters = 10;
396 : :
397 : 16 : spdk_bs_create_blob_ext(bs, &opts, blob_op_with_id_complete, NULL);
398 : 16 : poll_threads();
399 : 16 : CU_ASSERT(g_bserrno == 0);
400 : 16 : CU_ASSERT(g_blobid != SPDK_BLOBID_INVALID);
401 : 16 : blobid = g_blobid;
402 : :
403 : 16 : spdk_bs_open_blob(bs, blobid, blob_op_with_handle_complete, NULL);
404 : 16 : poll_threads();
405 : 16 : CU_ASSERT(g_bserrno == 0);
406 [ - + ]: 16 : SPDK_CU_ASSERT_FATAL(g_blob != NULL);
407 : 16 : blob = g_blob;
408 : 16 : CU_ASSERT(spdk_blob_get_num_clusters(blob) == 10);
409 : :
410 : 16 : spdk_blob_close(blob, blob_op_complete, NULL);
411 : 16 : poll_threads();
412 : 16 : CU_ASSERT(g_bserrno == 0);
413 : :
414 : : /* Create blob with 0 clusters */
415 : :
416 : 16 : ut_spdk_blob_opts_init(&opts);
417 : 16 : opts.num_clusters = 0;
418 : :
419 : 16 : spdk_bs_create_blob_ext(bs, &opts, blob_op_with_id_complete, NULL);
420 : 16 : poll_threads();
421 : 16 : CU_ASSERT(g_bserrno == 0);
422 : 16 : CU_ASSERT(g_blobid != SPDK_BLOBID_INVALID);
423 : 16 : blobid = g_blobid;
424 : :
425 : 16 : spdk_bs_open_blob(bs, blobid, blob_op_with_handle_complete, NULL);
426 : 16 : poll_threads();
427 : 16 : CU_ASSERT(g_bserrno == 0);
428 [ - + ]: 16 : SPDK_CU_ASSERT_FATAL(g_blob != NULL);
429 : 16 : blob = g_blob;
430 : 16 : CU_ASSERT(spdk_blob_get_num_clusters(blob) == 0);
431 : :
432 : 16 : spdk_blob_close(blob, blob_op_complete, NULL);
433 : 16 : poll_threads();
434 : 16 : CU_ASSERT(g_bserrno == 0);
435 : :
436 : : /* Create blob with default options (opts == NULL) */
437 : :
438 : 16 : spdk_bs_create_blob_ext(bs, NULL, blob_op_with_id_complete, NULL);
439 : 16 : poll_threads();
440 : 16 : CU_ASSERT(g_bserrno == 0);
441 : 16 : CU_ASSERT(g_blobid != SPDK_BLOBID_INVALID);
442 : 16 : blobid = g_blobid;
443 : :
444 : 16 : spdk_bs_open_blob(bs, blobid, blob_op_with_handle_complete, NULL);
445 : 16 : poll_threads();
446 : 16 : CU_ASSERT(g_bserrno == 0);
447 [ - + ]: 16 : SPDK_CU_ASSERT_FATAL(g_blob != NULL);
448 : 16 : blob = g_blob;
449 : 16 : CU_ASSERT(spdk_blob_get_num_clusters(blob) == 0);
450 : :
451 : 16 : spdk_blob_close(blob, blob_op_complete, NULL);
452 : 16 : poll_threads();
453 : 16 : CU_ASSERT(g_bserrno == 0);
454 : :
455 : : /* Try to create blob with size larger than blobstore */
456 : :
457 : 16 : ut_spdk_blob_opts_init(&opts);
458 : 16 : opts.num_clusters = bs->total_clusters + 1;
459 : :
460 : 16 : spdk_bs_create_blob_ext(bs, &opts, blob_op_with_id_complete, NULL);
461 : 16 : poll_threads();
462 : 16 : CU_ASSERT(g_bserrno == -ENOSPC);
463 : 16 : }
464 : :
465 : : static void
466 : 16 : blob_create_zero_extent(void)
467 : : {
468 : 16 : struct spdk_blob_store *bs = g_bs;
469 : : struct spdk_blob *blob;
470 : : spdk_blob_id blobid;
471 : :
472 : : /* Create blob with default options (opts == NULL) */
473 : 16 : spdk_bs_create_blob_ext(bs, NULL, blob_op_with_id_complete, NULL);
474 : 16 : poll_threads();
475 : 16 : CU_ASSERT(g_bserrno == 0);
476 : 16 : CU_ASSERT(g_blobid != SPDK_BLOBID_INVALID);
477 : 16 : blobid = g_blobid;
478 : :
479 : 16 : spdk_bs_open_blob(bs, blobid, blob_op_with_handle_complete, NULL);
480 : 16 : poll_threads();
481 : 16 : CU_ASSERT(g_bserrno == 0);
482 [ - + ]: 16 : SPDK_CU_ASSERT_FATAL(g_blob != NULL);
483 : 16 : blob = g_blob;
484 : 16 : CU_ASSERT(spdk_blob_get_num_clusters(blob) == 0);
485 [ - + ]: 16 : CU_ASSERT(blob->extent_table_found == true);
486 : 16 : CU_ASSERT(blob->active.extent_pages_array_size == 0);
487 : 16 : CU_ASSERT(blob->active.extent_pages == NULL);
488 : :
489 : 16 : spdk_blob_close(blob, blob_op_complete, NULL);
490 : 16 : poll_threads();
491 : 16 : CU_ASSERT(g_bserrno == 0);
492 : :
493 : : /* Create blob with NULL internal options */
494 : 16 : bs_create_blob(bs, NULL, NULL, blob_op_with_id_complete, NULL);
495 : 16 : poll_threads();
496 : 16 : CU_ASSERT(g_bserrno == 0);
497 : 16 : CU_ASSERT(g_blobid != SPDK_BLOBID_INVALID);
498 : 16 : blobid = g_blobid;
499 : :
500 : 16 : spdk_bs_open_blob(bs, blobid, blob_op_with_handle_complete, NULL);
501 : 16 : poll_threads();
502 : 16 : CU_ASSERT(g_bserrno == 0);
503 [ - + ]: 16 : SPDK_CU_ASSERT_FATAL(g_blob != NULL);
504 : 16 : blob = g_blob;
505 : 16 : CU_ASSERT(TAILQ_FIRST(&blob->xattrs_internal) == NULL);
506 : 16 : CU_ASSERT(spdk_blob_get_num_clusters(blob) == 0);
507 [ - + ]: 16 : CU_ASSERT(blob->extent_table_found == true);
508 : 16 : CU_ASSERT(blob->active.extent_pages_array_size == 0);
509 : 16 : CU_ASSERT(blob->active.extent_pages == NULL);
510 : :
511 : 16 : spdk_blob_close(blob, blob_op_complete, NULL);
512 : 16 : poll_threads();
513 : 16 : CU_ASSERT(g_bserrno == 0);
514 : 16 : }
515 : :
516 : : /*
517 : : * Create and delete one blob in a loop over and over again. This helps ensure
518 : : * that the internal bit masks tracking used clusters and md_pages are being
519 : : * tracked correctly.
520 : : */
521 : : static void
522 : 16 : blob_create_loop(void)
523 : : {
524 : 16 : struct spdk_blob_store *bs = g_bs;
525 : 16 : struct spdk_blob_opts opts;
526 : : uint32_t i, loop_count;
527 : :
528 [ - + ]: 16 : loop_count = 4 * spdk_max(spdk_bit_array_capacity(bs->used_md_pages),
529 : : spdk_bit_pool_capacity(bs->used_clusters));
530 : :
531 [ + + ]: 4112 : for (i = 0; i < loop_count; i++) {
532 : 4096 : ut_spdk_blob_opts_init(&opts);
533 : 4096 : opts.num_clusters = 1;
534 : 4096 : g_bserrno = -1;
535 : 4096 : g_blobid = SPDK_BLOBID_INVALID;
536 : 4096 : spdk_bs_create_blob_ext(bs, &opts, blob_op_with_id_complete, NULL);
537 : 4096 : poll_threads();
538 : 4096 : CU_ASSERT(g_bserrno == 0);
539 : 4096 : CU_ASSERT(g_blobid != SPDK_BLOBID_INVALID);
540 : 4096 : spdk_bs_delete_blob(bs, g_blobid, blob_op_complete, NULL);
541 : 4096 : poll_threads();
542 : 4096 : CU_ASSERT(g_bserrno == 0);
543 : : }
544 : 16 : }
545 : :
546 : : static void
547 : 16 : blob_create_fail(void)
548 : : {
549 : 16 : struct spdk_blob_store *bs = g_bs;
550 : 16 : struct spdk_blob_opts opts;
551 : : spdk_blob_id blobid;
552 : 16 : uint32_t used_blobids_count = spdk_bit_array_count_set(bs->used_blobids);
553 : 16 : uint32_t used_md_pages_count = spdk_bit_array_count_set(bs->used_md_pages);
554 : :
555 : : /* NULL callback */
556 : 16 : ut_spdk_blob_opts_init(&opts);
557 : 16 : opts.xattrs.names = g_xattr_names;
558 : 16 : opts.xattrs.get_value = NULL;
559 : 16 : opts.xattrs.count = 1;
560 : 16 : opts.xattrs.ctx = &g_ctx;
561 : :
562 : 16 : blobid = spdk_bit_array_find_first_clear(bs->used_md_pages, 0);
563 : 16 : spdk_bs_create_blob_ext(bs, &opts, blob_op_with_id_complete, NULL);
564 : 16 : poll_threads();
565 : 16 : CU_ASSERT(g_bserrno == -EINVAL);
566 : 16 : CU_ASSERT(g_blobid != SPDK_BLOBID_INVALID);
567 : 16 : CU_ASSERT(spdk_bit_array_count_set(bs->used_blobids) == used_blobids_count);
568 : 16 : CU_ASSERT(spdk_bit_array_count_set(bs->used_md_pages) == used_md_pages_count);
569 : :
570 : 16 : spdk_bs_open_blob(bs, blobid, blob_op_with_handle_complete, NULL);
571 : 16 : poll_threads();
572 : 16 : CU_ASSERT(g_bserrno == -ENOENT);
573 [ - + ]: 16 : SPDK_CU_ASSERT_FATAL(g_blob == NULL);
574 : :
575 : 16 : ut_bs_reload(&bs, NULL);
576 : 16 : CU_ASSERT(spdk_bit_array_count_set(bs->used_blobids) == used_blobids_count);
577 : 16 : CU_ASSERT(spdk_bit_array_count_set(bs->used_md_pages) == used_md_pages_count);
578 : :
579 : 16 : spdk_bs_iter_first(bs, blob_op_with_handle_complete, NULL);
580 : 16 : poll_threads();
581 : 16 : CU_ASSERT(g_blob == NULL);
582 : 16 : CU_ASSERT(g_bserrno == -ENOENT);
583 : 16 : }
584 : :
585 : : static void
586 : 16 : blob_create_internal(void)
587 : : {
588 : 16 : struct spdk_blob_store *bs = g_bs;
589 : : struct spdk_blob *blob;
590 : 16 : struct spdk_blob_opts opts;
591 : 16 : struct spdk_blob_xattr_opts internal_xattrs;
592 : 16 : const void *value;
593 : 16 : size_t value_len;
594 : : spdk_blob_id blobid;
595 : : int rc;
596 : :
597 : : /* Create blob with custom xattrs */
598 : :
599 : 16 : ut_spdk_blob_opts_init(&opts);
600 : 16 : blob_xattrs_init(&internal_xattrs);
601 : 16 : internal_xattrs.count = 3;
602 : 16 : internal_xattrs.names = g_xattr_names;
603 : 16 : internal_xattrs.get_value = _get_xattr_value;
604 : 16 : internal_xattrs.ctx = &g_ctx;
605 : :
606 : 16 : bs_create_blob(bs, &opts, &internal_xattrs, blob_op_with_id_complete, NULL);
607 : 16 : poll_threads();
608 : 16 : CU_ASSERT(g_bserrno == 0);
609 : 16 : CU_ASSERT(g_blobid != SPDK_BLOBID_INVALID);
610 : 16 : blobid = g_blobid;
611 : :
612 : 16 : spdk_bs_open_blob(bs, blobid, blob_op_with_handle_complete, NULL);
613 : 16 : poll_threads();
614 : 16 : CU_ASSERT(g_bserrno == 0);
615 [ - + ]: 16 : SPDK_CU_ASSERT_FATAL(g_blob != NULL);
616 : 16 : blob = g_blob;
617 : :
618 : 16 : rc = blob_get_xattr_value(blob, g_xattr_names[0], &value, &value_len, true);
619 : 16 : CU_ASSERT(rc == 0);
620 [ - + ]: 16 : SPDK_CU_ASSERT_FATAL(value != NULL);
621 [ - + ]: 16 : CU_ASSERT(value_len == strlen(g_xattr_values[0]));
622 [ - + - + ]: 16 : CU_ASSERT_NSTRING_EQUAL_FATAL(value, g_xattr_values[0], value_len);
623 : :
624 : 16 : rc = blob_get_xattr_value(blob, g_xattr_names[1], &value, &value_len, true);
625 : 16 : CU_ASSERT(rc == 0);
626 [ - + ]: 16 : SPDK_CU_ASSERT_FATAL(value != NULL);
627 [ - + ]: 16 : CU_ASSERT(value_len == strlen(g_xattr_values[1]));
628 [ - + - + ]: 16 : CU_ASSERT_NSTRING_EQUAL((char *)value, g_xattr_values[1], value_len);
629 : :
630 : 16 : rc = blob_get_xattr_value(blob, g_xattr_names[2], &value, &value_len, true);
631 : 16 : CU_ASSERT(rc == 0);
632 [ - + ]: 16 : SPDK_CU_ASSERT_FATAL(value != NULL);
633 [ - + ]: 16 : CU_ASSERT(value_len == strlen(g_xattr_values[2]));
634 [ - + - + ]: 16 : CU_ASSERT_NSTRING_EQUAL((char *)value, g_xattr_values[2], value_len);
635 : :
636 : 16 : rc = spdk_blob_get_xattr_value(blob, g_xattr_names[0], &value, &value_len);
637 : 16 : CU_ASSERT(rc != 0);
638 : :
639 : 16 : rc = spdk_blob_get_xattr_value(blob, g_xattr_names[1], &value, &value_len);
640 : 16 : CU_ASSERT(rc != 0);
641 : :
642 : 16 : rc = spdk_blob_get_xattr_value(blob, g_xattr_names[2], &value, &value_len);
643 : 16 : CU_ASSERT(rc != 0);
644 : :
645 : 16 : spdk_blob_close(blob, blob_op_complete, NULL);
646 : 16 : poll_threads();
647 : 16 : CU_ASSERT(g_bserrno == 0);
648 : :
649 : : /* Create blob with NULL internal options */
650 : :
651 : 16 : bs_create_blob(bs, NULL, NULL, blob_op_with_id_complete, NULL);
652 : 16 : poll_threads();
653 : 16 : CU_ASSERT(g_bserrno == 0);
654 : 16 : CU_ASSERT(g_blobid != SPDK_BLOBID_INVALID);
655 : 16 : blobid = g_blobid;
656 : :
657 : 16 : spdk_bs_open_blob(bs, blobid, blob_op_with_handle_complete, NULL);
658 : 16 : poll_threads();
659 : 16 : CU_ASSERT(g_bserrno == 0);
660 [ - + ]: 16 : SPDK_CU_ASSERT_FATAL(g_blob != NULL);
661 : 16 : CU_ASSERT(TAILQ_FIRST(&g_blob->xattrs_internal) == NULL);
662 : 16 : CU_ASSERT(spdk_blob_get_num_clusters(g_blob) == 0);
663 : :
664 : 16 : blob = g_blob;
665 : :
666 : 16 : spdk_blob_close(blob, blob_op_complete, NULL);
667 : 16 : poll_threads();
668 : 16 : CU_ASSERT(g_bserrno == 0);
669 : 16 : }
670 : :
671 : : static void
672 : 16 : blob_thin_provision(void)
673 : : {
674 : 16 : struct spdk_blob_store *bs;
675 : : struct spdk_bs_dev *dev;
676 : : struct spdk_blob *blob;
677 : 16 : struct spdk_blob_opts opts;
678 : 16 : struct spdk_bs_opts bs_opts;
679 : : spdk_blob_id blobid;
680 : :
681 : 16 : dev = init_dev();
682 : 16 : spdk_bs_opts_init(&bs_opts, sizeof(bs_opts));
683 : 16 : snprintf(bs_opts.bstype.bstype, sizeof(bs_opts.bstype.bstype), "TESTTYPE");
684 : :
685 : : /* Initialize a new blob store */
686 : 16 : spdk_bs_init(dev, &bs_opts, bs_op_with_handle_complete, NULL);
687 : 16 : poll_threads();
688 : 16 : CU_ASSERT(g_bserrno == 0);
689 [ - + ]: 16 : SPDK_CU_ASSERT_FATAL(g_bs != NULL);
690 : :
691 : 16 : bs = g_bs;
692 : :
693 : : /* Create blob with thin provisioning enabled */
694 : :
695 : 16 : ut_spdk_blob_opts_init(&opts);
696 : 16 : opts.thin_provision = true;
697 : 16 : opts.num_clusters = 10;
698 : :
699 : 16 : blob = ut_blob_create_and_open(bs, &opts);
700 : 16 : blobid = spdk_blob_get_id(blob);
701 : 16 : CU_ASSERT(blob->invalid_flags & SPDK_BLOB_THIN_PROV);
702 : : /* In thin provisioning with num_clusters is set, if not using the
703 : : * extent table, there is no allocation. If extent table is used,
704 : : * there is related allocation happened. */
705 [ + + + + ]: 16 : if (blob->extent_table_found == true) {
706 : 8 : CU_ASSERT(blob->active.extent_pages_array_size > 0);
707 : 8 : CU_ASSERT(blob->active.extent_pages != NULL);
708 : : } else {
709 : 8 : CU_ASSERT(blob->active.extent_pages_array_size == 0);
710 : 8 : CU_ASSERT(blob->active.extent_pages == NULL);
711 : : }
712 : :
713 : 16 : spdk_blob_close(blob, blob_op_complete, NULL);
714 : 16 : CU_ASSERT(g_bserrno == 0);
715 : :
716 : : /* Do not shut down cleanly. This makes sure that when we load again
717 : : * and try to recover a valid used_cluster map, that blobstore will
718 : : * ignore clusters with index 0 since these are unallocated clusters.
719 : : */
720 : 16 : ut_bs_dirty_load(&bs, &bs_opts);
721 : :
722 : 16 : spdk_bs_open_blob(bs, blobid, blob_op_with_handle_complete, NULL);
723 : 16 : poll_threads();
724 : 16 : CU_ASSERT(g_bserrno == 0);
725 [ - + ]: 16 : SPDK_CU_ASSERT_FATAL(g_blob != NULL);
726 : 16 : blob = g_blob;
727 : 16 : CU_ASSERT(blob->invalid_flags & SPDK_BLOB_THIN_PROV);
728 : :
729 : 16 : ut_blob_close_and_delete(bs, blob);
730 : :
731 : 16 : spdk_bs_unload(bs, bs_op_complete, NULL);
732 : 16 : poll_threads();
733 : 16 : CU_ASSERT(g_bserrno == 0);
734 : 16 : g_bs = NULL;
735 : 16 : }
736 : :
737 : : static void
738 : 16 : blob_snapshot(void)
739 : : {
740 : 16 : struct spdk_blob_store *bs = g_bs;
741 : : struct spdk_blob *blob;
742 : : struct spdk_blob *snapshot, *snapshot2;
743 : : struct spdk_blob_bs_dev *blob_bs_dev;
744 : 16 : struct spdk_blob_opts opts;
745 : 16 : struct spdk_blob_xattr_opts xattrs;
746 : : spdk_blob_id blobid;
747 : : spdk_blob_id snapshotid;
748 : : spdk_blob_id snapshotid2;
749 : 16 : const void *value;
750 : 16 : size_t value_len;
751 : : int rc;
752 : 16 : spdk_blob_id ids[2];
753 : 16 : size_t count;
754 : :
755 : : /* Create blob with 10 clusters */
756 : 16 : ut_spdk_blob_opts_init(&opts);
757 : 16 : opts.num_clusters = 10;
758 : :
759 : 16 : blob = ut_blob_create_and_open(bs, &opts);
760 : 16 : blobid = spdk_blob_get_id(blob);
761 : 16 : CU_ASSERT(spdk_blob_get_num_clusters(blob) == 10);
762 : :
763 : : /* Create snapshot from blob */
764 : 16 : CU_ASSERT_EQUAL(_get_snapshots_count(bs), 0);
765 : 16 : spdk_bs_create_snapshot(bs, blobid, NULL, blob_op_with_id_complete, NULL);
766 : 16 : poll_threads();
767 : 16 : CU_ASSERT(g_bserrno == 0);
768 : 16 : CU_ASSERT(g_blobid != SPDK_BLOBID_INVALID);
769 : 16 : CU_ASSERT_EQUAL(_get_snapshots_count(bs), 1);
770 : 16 : snapshotid = g_blobid;
771 : :
772 : 16 : spdk_bs_open_blob(bs, snapshotid, blob_op_with_handle_complete, NULL);
773 : 16 : poll_threads();
774 : 16 : CU_ASSERT(g_bserrno == 0);
775 [ - + ]: 16 : SPDK_CU_ASSERT_FATAL(g_blob != NULL);
776 : 16 : snapshot = g_blob;
777 [ - + ]: 16 : CU_ASSERT(snapshot->data_ro == true);
778 [ - + ]: 16 : CU_ASSERT(snapshot->md_ro == true);
779 : 16 : CU_ASSERT(spdk_blob_get_num_clusters(snapshot) == 10);
780 : :
781 : 16 : CU_ASSERT(spdk_blob_get_num_clusters(blob) == 10);
782 : 16 : CU_ASSERT(blob->invalid_flags & SPDK_BLOB_THIN_PROV);
783 : 16 : CU_ASSERT(spdk_mem_all_zero(blob->active.clusters,
784 : : blob->active.num_clusters * sizeof(blob->active.clusters[0])));
785 : :
786 : : /* Try to create snapshot from clone with xattrs */
787 : 16 : xattrs.names = g_xattr_names;
788 : 16 : xattrs.get_value = _get_xattr_value;
789 : 16 : xattrs.count = 3;
790 : 16 : xattrs.ctx = &g_ctx;
791 : 16 : spdk_bs_create_snapshot(bs, blobid, &xattrs, blob_op_with_id_complete, NULL);
792 : 16 : poll_threads();
793 : 16 : CU_ASSERT(g_bserrno == 0);
794 : 16 : CU_ASSERT(g_blobid != SPDK_BLOBID_INVALID);
795 : 16 : CU_ASSERT_EQUAL(_get_snapshots_count(bs), 2);
796 : 16 : snapshotid2 = g_blobid;
797 : :
798 : 16 : spdk_bs_open_blob(bs, snapshotid2, blob_op_with_handle_complete, NULL);
799 : 16 : CU_ASSERT(g_bserrno == 0);
800 [ - + ]: 16 : SPDK_CU_ASSERT_FATAL(g_blob != NULL);
801 : 16 : snapshot2 = g_blob;
802 [ - + ]: 16 : CU_ASSERT(snapshot2->data_ro == true);
803 [ - + ]: 16 : CU_ASSERT(snapshot2->md_ro == true);
804 : 16 : CU_ASSERT(spdk_blob_get_num_clusters(snapshot2) == 10);
805 : :
806 : : /* Confirm that blob is backed by snapshot2 and snapshot2 is backed by snapshot */
807 : 16 : CU_ASSERT(snapshot->back_bs_dev == NULL);
808 [ - + ]: 16 : SPDK_CU_ASSERT_FATAL(blob->back_bs_dev != NULL);
809 [ - + ]: 16 : SPDK_CU_ASSERT_FATAL(snapshot2->back_bs_dev != NULL);
810 : :
811 : 16 : blob_bs_dev = (struct spdk_blob_bs_dev *)blob->back_bs_dev;
812 : 16 : CU_ASSERT(blob_bs_dev->blob == snapshot2);
813 : :
814 : 16 : blob_bs_dev = (struct spdk_blob_bs_dev *)snapshot2->back_bs_dev;
815 : 16 : CU_ASSERT(blob_bs_dev->blob == snapshot);
816 : :
817 : 16 : rc = spdk_blob_get_xattr_value(snapshot2, g_xattr_names[0], &value, &value_len);
818 : 16 : CU_ASSERT(rc == 0);
819 [ - + ]: 16 : SPDK_CU_ASSERT_FATAL(value != NULL);
820 [ - + ]: 16 : CU_ASSERT(value_len == strlen(g_xattr_values[0]));
821 [ - + - + ]: 16 : CU_ASSERT_NSTRING_EQUAL_FATAL(value, g_xattr_values[0], value_len);
822 : :
823 : 16 : rc = spdk_blob_get_xattr_value(snapshot2, g_xattr_names[1], &value, &value_len);
824 : 16 : CU_ASSERT(rc == 0);
825 [ - + ]: 16 : SPDK_CU_ASSERT_FATAL(value != NULL);
826 [ - + ]: 16 : CU_ASSERT(value_len == strlen(g_xattr_values[1]));
827 [ - + - + ]: 16 : CU_ASSERT_NSTRING_EQUAL((char *)value, g_xattr_values[1], value_len);
828 : :
829 : 16 : rc = spdk_blob_get_xattr_value(snapshot2, g_xattr_names[2], &value, &value_len);
830 : 16 : CU_ASSERT(rc == 0);
831 [ - + ]: 16 : SPDK_CU_ASSERT_FATAL(value != NULL);
832 [ - + ]: 16 : CU_ASSERT(value_len == strlen(g_xattr_values[2]));
833 [ - + - + ]: 16 : CU_ASSERT_NSTRING_EQUAL((char *)value, g_xattr_values[2], value_len);
834 : :
835 : : /* Confirm that blob is clone of snapshot2, and snapshot2 is clone of snapshot */
836 : 16 : count = 2;
837 : 16 : CU_ASSERT(spdk_blob_get_clones(bs, snapshotid2, ids, &count) == 0);
838 : 16 : CU_ASSERT(count == 1);
839 : 16 : CU_ASSERT(ids[0] == blobid);
840 : :
841 : 16 : count = 2;
842 : 16 : CU_ASSERT(spdk_blob_get_clones(bs, snapshotid, ids, &count) == 0);
843 : 16 : CU_ASSERT(count == 1);
844 : 16 : CU_ASSERT(ids[0] == snapshotid2);
845 : :
846 : : /* Try to create snapshot from snapshot */
847 : 16 : spdk_bs_create_snapshot(bs, snapshotid, NULL, blob_op_with_id_complete, NULL);
848 : 16 : poll_threads();
849 : 16 : CU_ASSERT(g_bserrno == -EINVAL);
850 : 16 : CU_ASSERT(g_blobid == SPDK_BLOBID_INVALID);
851 : 16 : CU_ASSERT_EQUAL(_get_snapshots_count(bs), 2);
852 : :
853 : : /* Delete blob and confirm that it is no longer on snapshot2 clone list */
854 : 16 : ut_blob_close_and_delete(bs, blob);
855 : 16 : count = 2;
856 : 16 : CU_ASSERT(spdk_blob_get_clones(bs, snapshotid2, ids, &count) == 0);
857 : 16 : CU_ASSERT(count == 0);
858 : :
859 : : /* Delete snapshot2 and confirm that it is no longer on snapshot clone list */
860 : 16 : ut_blob_close_and_delete(bs, snapshot2);
861 : 16 : CU_ASSERT_EQUAL(_get_snapshots_count(bs), 1);
862 : 16 : count = 2;
863 : 16 : CU_ASSERT(spdk_blob_get_clones(bs, snapshotid2, ids, &count) == 0);
864 : 16 : CU_ASSERT(count == 0);
865 : :
866 : 16 : ut_blob_close_and_delete(bs, snapshot);
867 : 16 : CU_ASSERT_EQUAL(_get_snapshots_count(bs), 0);
868 : 16 : }
869 : :
870 : : static void
871 : 16 : blob_snapshot_freeze_io(void)
872 : 16 : {
873 : : struct spdk_io_channel *channel;
874 : : struct spdk_bs_channel *bs_channel;
875 : 16 : struct spdk_blob_store *bs = g_bs;
876 : : struct spdk_blob *blob;
877 : 16 : struct spdk_blob_opts opts;
878 : : spdk_blob_id blobid;
879 : 16 : uint32_t num_of_pages = 10;
880 [ - + ]: 16 : uint8_t payload_read[num_of_pages * SPDK_BS_PAGE_SIZE];
881 [ - + ]: 16 : uint8_t payload_write[num_of_pages * SPDK_BS_PAGE_SIZE];
882 [ - + ]: 16 : uint8_t payload_zero[num_of_pages * SPDK_BS_PAGE_SIZE];
883 : :
884 [ - + ]: 16 : memset(payload_write, 0xE5, sizeof(payload_write));
885 [ - + ]: 16 : memset(payload_read, 0x00, sizeof(payload_read));
886 [ - + ]: 16 : memset(payload_zero, 0x00, sizeof(payload_zero));
887 : :
888 : : /* Test freeze I/O during snapshot */
889 : 16 : channel = spdk_bs_alloc_io_channel(bs);
890 : 16 : bs_channel = spdk_io_channel_get_ctx(channel);
891 : :
892 : : /* Create blob with 10 clusters */
893 : 16 : ut_spdk_blob_opts_init(&opts);
894 : 16 : opts.num_clusters = 10;
895 : 16 : opts.thin_provision = false;
896 : :
897 : 16 : blob = ut_blob_create_and_open(bs, &opts);
898 : 16 : blobid = spdk_blob_get_id(blob);
899 : 16 : CU_ASSERT(spdk_blob_get_num_clusters(blob) == 10);
900 : :
901 : 16 : spdk_bs_create_snapshot(bs, blobid, NULL, blob_op_with_id_complete, NULL);
902 : :
903 : : /* This is implementation specific.
904 : : * Flag 'frozen_io' is set in _spdk_bs_snapshot_freeze_cpl callback.
905 : : * Four async I/O operations happen before that. */
906 : 16 : poll_thread_times(0, 5);
907 : :
908 : 16 : CU_ASSERT(TAILQ_EMPTY(&bs_channel->queued_io));
909 : :
910 : : /* Blob I/O should be frozen here */
911 : 16 : CU_ASSERT(blob->frozen_refcnt == 1);
912 : :
913 : : /* Write to the blob */
914 : 16 : spdk_blob_io_write(blob, channel, payload_write, 0, num_of_pages, blob_op_complete, NULL);
915 : :
916 : : /* Verify that I/O is queued */
917 : 16 : CU_ASSERT(!TAILQ_EMPTY(&bs_channel->queued_io));
918 : : /* Verify that payload is not written to disk, at this point the blobs already switched */
919 : 16 : CU_ASSERT(blob->active.clusters[0] == 0);
920 : :
921 : : /* Finish all operations including spdk_bs_create_snapshot */
922 : 16 : poll_threads();
923 : :
924 : : /* Verify snapshot */
925 : 16 : CU_ASSERT(g_bserrno == 0);
926 : 16 : CU_ASSERT(g_blobid != SPDK_BLOBID_INVALID);
927 : :
928 : : /* Verify that blob has unset frozen_io */
929 : 16 : CU_ASSERT(blob->frozen_refcnt == 0);
930 : :
931 : : /* Verify that postponed I/O completed successfully by comparing payload */
932 : 16 : spdk_blob_io_read(blob, channel, payload_read, 0, num_of_pages, blob_op_complete, NULL);
933 : 16 : poll_threads();
934 : 16 : CU_ASSERT(g_bserrno == 0);
935 [ - + - + ]: 16 : CU_ASSERT(memcmp(payload_write, payload_read, num_of_pages * SPDK_BS_PAGE_SIZE) == 0);
936 : :
937 : 16 : spdk_bs_free_io_channel(channel);
938 : 16 : poll_threads();
939 : :
940 : 16 : ut_blob_close_and_delete(bs, blob);
941 : 16 : }
942 : :
943 : : static void
944 : 16 : blob_clone(void)
945 : : {
946 : 16 : struct spdk_blob_store *bs = g_bs;
947 : 16 : struct spdk_blob_opts opts;
948 : : struct spdk_blob *blob, *snapshot, *clone;
949 : : spdk_blob_id blobid, cloneid, snapshotid;
950 : 16 : struct spdk_blob_xattr_opts xattrs;
951 : 16 : const void *value;
952 : 16 : size_t value_len;
953 : : int rc;
954 : :
955 : : /* Create blob with 10 clusters */
956 : :
957 : 16 : ut_spdk_blob_opts_init(&opts);
958 : 16 : opts.num_clusters = 10;
959 : :
960 : 16 : blob = ut_blob_create_and_open(bs, &opts);
961 : 16 : blobid = spdk_blob_get_id(blob);
962 : 16 : CU_ASSERT(spdk_blob_get_num_clusters(blob) == 10);
963 : :
964 : : /* Create snapshot */
965 : 16 : spdk_bs_create_snapshot(bs, blobid, NULL, blob_op_with_id_complete, NULL);
966 : 16 : poll_threads();
967 : 16 : CU_ASSERT(g_bserrno == 0);
968 : 16 : CU_ASSERT(g_blobid != SPDK_BLOBID_INVALID);
969 : 16 : snapshotid = g_blobid;
970 : :
971 : 16 : spdk_bs_open_blob(bs, snapshotid, blob_op_with_handle_complete, NULL);
972 : 16 : poll_threads();
973 : 16 : CU_ASSERT(g_bserrno == 0);
974 [ - + ]: 16 : SPDK_CU_ASSERT_FATAL(g_blob != NULL);
975 : 16 : snapshot = g_blob;
976 [ - + ]: 16 : CU_ASSERT(snapshot->data_ro == true);
977 [ - + ]: 16 : CU_ASSERT(snapshot->md_ro == true);
978 : 16 : CU_ASSERT(spdk_blob_get_num_clusters(snapshot) == 10);
979 : :
980 : 16 : spdk_blob_close(snapshot, blob_op_complete, NULL);
981 : 16 : poll_threads();
982 : 16 : CU_ASSERT(g_bserrno == 0);
983 : :
984 : : /* Create clone from snapshot with xattrs */
985 : 16 : xattrs.names = g_xattr_names;
986 : 16 : xattrs.get_value = _get_xattr_value;
987 : 16 : xattrs.count = 3;
988 : 16 : xattrs.ctx = &g_ctx;
989 : :
990 : 16 : spdk_bs_create_clone(bs, snapshotid, &xattrs, blob_op_with_id_complete, NULL);
991 : 16 : poll_threads();
992 : 16 : CU_ASSERT(g_bserrno == 0);
993 : 16 : CU_ASSERT(g_blobid != SPDK_BLOBID_INVALID);
994 : 16 : cloneid = g_blobid;
995 : :
996 : 16 : spdk_bs_open_blob(bs, cloneid, blob_op_with_handle_complete, NULL);
997 : 16 : poll_threads();
998 : 16 : CU_ASSERT(g_bserrno == 0);
999 [ - + ]: 16 : SPDK_CU_ASSERT_FATAL(g_blob != NULL);
1000 : 16 : clone = g_blob;
1001 [ - + ]: 16 : CU_ASSERT(clone->data_ro == false);
1002 [ - + ]: 16 : CU_ASSERT(clone->md_ro == false);
1003 : 16 : CU_ASSERT(spdk_blob_get_num_clusters(clone) == 10);
1004 : :
1005 : 16 : rc = spdk_blob_get_xattr_value(clone, g_xattr_names[0], &value, &value_len);
1006 : 16 : CU_ASSERT(rc == 0);
1007 [ - + ]: 16 : SPDK_CU_ASSERT_FATAL(value != NULL);
1008 [ - + ]: 16 : CU_ASSERT(value_len == strlen(g_xattr_values[0]));
1009 [ - + - + ]: 16 : CU_ASSERT_NSTRING_EQUAL_FATAL(value, g_xattr_values[0], value_len);
1010 : :
1011 : 16 : rc = spdk_blob_get_xattr_value(clone, g_xattr_names[1], &value, &value_len);
1012 : 16 : CU_ASSERT(rc == 0);
1013 [ - + ]: 16 : SPDK_CU_ASSERT_FATAL(value != NULL);
1014 [ - + ]: 16 : CU_ASSERT(value_len == strlen(g_xattr_values[1]));
1015 [ - + - + ]: 16 : CU_ASSERT_NSTRING_EQUAL((char *)value, g_xattr_values[1], value_len);
1016 : :
1017 : 16 : rc = spdk_blob_get_xattr_value(clone, g_xattr_names[2], &value, &value_len);
1018 : 16 : CU_ASSERT(rc == 0);
1019 [ - + ]: 16 : SPDK_CU_ASSERT_FATAL(value != NULL);
1020 [ - + ]: 16 : CU_ASSERT(value_len == strlen(g_xattr_values[2]));
1021 [ - + - + ]: 16 : CU_ASSERT_NSTRING_EQUAL((char *)value, g_xattr_values[2], value_len);
1022 : :
1023 : :
1024 : 16 : spdk_blob_close(clone, blob_op_complete, NULL);
1025 : 16 : poll_threads();
1026 : 16 : CU_ASSERT(g_bserrno == 0);
1027 : :
1028 : : /* Try to create clone from not read only blob */
1029 : 16 : spdk_bs_create_clone(bs, blobid, NULL, blob_op_with_id_complete, NULL);
1030 : 16 : poll_threads();
1031 : 16 : CU_ASSERT(g_bserrno == -EINVAL);
1032 : 16 : CU_ASSERT(g_blobid == SPDK_BLOBID_INVALID);
1033 : :
1034 : : /* Mark blob as read only */
1035 : 16 : spdk_blob_set_read_only(blob);
1036 : 16 : spdk_blob_sync_md(blob, blob_op_complete, NULL);
1037 : 16 : poll_threads();
1038 : 16 : CU_ASSERT(g_bserrno == 0);
1039 : :
1040 : : /* Create clone from read only blob */
1041 : 16 : spdk_bs_create_clone(bs, blobid, NULL, blob_op_with_id_complete, NULL);
1042 : 16 : poll_threads();
1043 : 16 : CU_ASSERT(g_bserrno == 0);
1044 : 16 : CU_ASSERT(g_blobid != SPDK_BLOBID_INVALID);
1045 : 16 : cloneid = g_blobid;
1046 : :
1047 : 16 : spdk_bs_open_blob(bs, cloneid, blob_op_with_handle_complete, NULL);
1048 : 16 : poll_threads();
1049 : 16 : CU_ASSERT(g_bserrno == 0);
1050 [ - + ]: 16 : SPDK_CU_ASSERT_FATAL(g_blob != NULL);
1051 : 16 : clone = g_blob;
1052 [ - + ]: 16 : CU_ASSERT(clone->data_ro == false);
1053 [ - + ]: 16 : CU_ASSERT(clone->md_ro == false);
1054 : 16 : CU_ASSERT(spdk_blob_get_num_clusters(clone) == 10);
1055 : :
1056 : 16 : ut_blob_close_and_delete(bs, clone);
1057 : 16 : ut_blob_close_and_delete(bs, blob);
1058 : 16 : }
1059 : :
1060 : : static void
1061 : 32 : _blob_inflate(bool decouple_parent)
1062 : : {
1063 : 32 : struct spdk_blob_store *bs = g_bs;
1064 : 32 : struct spdk_blob_opts opts;
1065 : : struct spdk_blob *blob, *snapshot;
1066 : : spdk_blob_id blobid, snapshotid;
1067 : : struct spdk_io_channel *channel;
1068 : : uint64_t free_clusters;
1069 : :
1070 : 32 : channel = spdk_bs_alloc_io_channel(bs);
1071 [ - + ]: 32 : SPDK_CU_ASSERT_FATAL(channel != NULL);
1072 : :
1073 : : /* Create blob with 10 clusters */
1074 : :
1075 : 32 : ut_spdk_blob_opts_init(&opts);
1076 : 32 : opts.num_clusters = 10;
1077 : 32 : opts.thin_provision = true;
1078 : :
1079 : 32 : blob = ut_blob_create_and_open(bs, &opts);
1080 : 32 : blobid = spdk_blob_get_id(blob);
1081 : 32 : CU_ASSERT(spdk_blob_get_num_clusters(blob) == 10);
1082 : 32 : CU_ASSERT(spdk_blob_is_thin_provisioned(blob) == true);
1083 : :
1084 : : /* 1) Blob with no parent */
1085 [ + + ]: 32 : if (decouple_parent) {
1086 : : /* Decouple parent of blob with no parent (should fail) */
1087 : 16 : spdk_bs_blob_decouple_parent(bs, channel, blobid, blob_op_complete, NULL);
1088 : 16 : poll_threads();
1089 : 16 : CU_ASSERT(g_bserrno != 0);
1090 : : } else {
1091 : : /* Inflate of thin blob with no parent should made it thick */
1092 : 16 : spdk_bs_inflate_blob(bs, channel, blobid, blob_op_complete, NULL);
1093 : 16 : poll_threads();
1094 : 16 : CU_ASSERT(g_bserrno == 0);
1095 : 16 : CU_ASSERT(spdk_blob_is_thin_provisioned(blob) == false);
1096 : : }
1097 : :
1098 : 32 : spdk_bs_create_snapshot(bs, blobid, NULL, blob_op_with_id_complete, NULL);
1099 : 32 : poll_threads();
1100 : 32 : CU_ASSERT(g_bserrno == 0);
1101 : 32 : CU_ASSERT(g_blobid != SPDK_BLOBID_INVALID);
1102 : 32 : snapshotid = g_blobid;
1103 : :
1104 : 32 : CU_ASSERT(spdk_blob_is_thin_provisioned(blob) == true);
1105 : 32 : CU_ASSERT(spdk_blob_get_num_clusters(blob) == 10);
1106 : :
1107 : 32 : spdk_bs_open_blob(bs, snapshotid, blob_op_with_handle_complete, NULL);
1108 : 32 : poll_threads();
1109 : 32 : CU_ASSERT(g_bserrno == 0);
1110 [ - + ]: 32 : SPDK_CU_ASSERT_FATAL(g_blob != NULL);
1111 : 32 : snapshot = g_blob;
1112 [ - + ]: 32 : CU_ASSERT(snapshot->data_ro == true);
1113 [ - + ]: 32 : CU_ASSERT(snapshot->md_ro == true);
1114 : 32 : CU_ASSERT(spdk_blob_get_num_clusters(snapshot) == 10);
1115 : :
1116 : 32 : spdk_blob_close(snapshot, blob_op_complete, NULL);
1117 : 32 : poll_threads();
1118 : 32 : CU_ASSERT(g_bserrno == 0);
1119 : :
1120 : 32 : free_clusters = spdk_bs_free_cluster_count(bs);
1121 : :
1122 : : /* 2) Blob with parent */
1123 [ + + ]: 32 : if (!decouple_parent) {
1124 : : /* Do full blob inflation */
1125 : 16 : spdk_bs_inflate_blob(bs, channel, blobid, blob_op_complete, NULL);
1126 : 16 : poll_threads();
1127 : 16 : CU_ASSERT(g_bserrno == 0);
1128 : : /* all 10 clusters should be allocated */
1129 : 16 : CU_ASSERT(spdk_bs_free_cluster_count(bs) == free_clusters - 10);
1130 : : } else {
1131 : : /* Decouple parent of blob */
1132 : 16 : spdk_bs_blob_decouple_parent(bs, channel, blobid, blob_op_complete, NULL);
1133 : 16 : poll_threads();
1134 : 16 : CU_ASSERT(g_bserrno == 0);
1135 : : /* when only parent is removed, none of the clusters should be allocated */
1136 : 16 : CU_ASSERT(spdk_bs_free_cluster_count(bs) == free_clusters);
1137 : : }
1138 : :
1139 : : /* Now, it should be possible to delete snapshot */
1140 : 32 : spdk_bs_delete_blob(bs, snapshotid, blob_op_complete, NULL);
1141 : 32 : poll_threads();
1142 : 32 : CU_ASSERT(g_bserrno == 0);
1143 : :
1144 : 32 : CU_ASSERT(spdk_blob_get_num_clusters(blob) == 10);
1145 : 32 : CU_ASSERT(spdk_blob_is_thin_provisioned(blob) == decouple_parent);
1146 : :
1147 : 32 : spdk_bs_free_io_channel(channel);
1148 : 32 : poll_threads();
1149 : :
1150 : 32 : ut_blob_close_and_delete(bs, blob);
1151 : 32 : }
1152 : :
1153 : : static void
1154 : 16 : blob_inflate(void)
1155 : : {
1156 : 16 : _blob_inflate(false);
1157 : 16 : _blob_inflate(true);
1158 : 16 : }
1159 : :
1160 : : static void
1161 : 16 : blob_delete(void)
1162 : : {
1163 : 16 : struct spdk_blob_store *bs = g_bs;
1164 : 16 : struct spdk_blob_opts blob_opts;
1165 : : spdk_blob_id blobid;
1166 : :
1167 : : /* Create a blob and then delete it. */
1168 : 16 : ut_spdk_blob_opts_init(&blob_opts);
1169 : 16 : spdk_bs_create_blob_ext(bs, &blob_opts, blob_op_with_id_complete, NULL);
1170 : 16 : poll_threads();
1171 : 16 : CU_ASSERT(g_bserrno == 0);
1172 : 16 : CU_ASSERT(g_blobid > 0);
1173 : 16 : blobid = g_blobid;
1174 : :
1175 : 16 : spdk_bs_delete_blob(bs, blobid, blob_op_complete, NULL);
1176 : 16 : poll_threads();
1177 : 16 : CU_ASSERT(g_bserrno == 0);
1178 : :
1179 : : /* Try to open the blob */
1180 : 16 : spdk_bs_open_blob(bs, blobid, blob_op_with_handle_complete, NULL);
1181 : 16 : poll_threads();
1182 : 16 : CU_ASSERT(g_bserrno == -ENOENT);
1183 : 16 : }
1184 : :
1185 : : static void
1186 : 16 : blob_resize_test(void)
1187 : : {
1188 : 16 : struct spdk_blob_store *bs = g_bs;
1189 : : struct spdk_blob *blob;
1190 : : uint64_t free_clusters;
1191 : :
1192 : 16 : free_clusters = spdk_bs_free_cluster_count(bs);
1193 : :
1194 : 16 : blob = ut_blob_create_and_open(bs, NULL);
1195 : 16 : CU_ASSERT(free_clusters == spdk_bs_free_cluster_count(bs));
1196 : :
1197 : : /* Confirm that resize fails if blob is marked read-only. */
1198 : 16 : blob->md_ro = true;
1199 : 16 : spdk_blob_resize(blob, 5, blob_op_complete, NULL);
1200 : 16 : poll_threads();
1201 : 16 : CU_ASSERT(g_bserrno == -EPERM);
1202 : 16 : blob->md_ro = false;
1203 : :
1204 : : /* The blob started at 0 clusters. Resize it to be 5. */
1205 : 16 : spdk_blob_resize(blob, 5, blob_op_complete, NULL);
1206 : 16 : poll_threads();
1207 : 16 : CU_ASSERT(g_bserrno == 0);
1208 : 16 : CU_ASSERT((free_clusters - 5) == spdk_bs_free_cluster_count(bs));
1209 : :
1210 : : /* Shrink the blob to 3 clusters. This will not actually release
1211 : : * the old clusters until the blob is synced.
1212 : : */
1213 : 16 : spdk_blob_resize(blob, 3, blob_op_complete, NULL);
1214 : 16 : poll_threads();
1215 : 16 : CU_ASSERT(g_bserrno == 0);
1216 : : /* Verify there are still 5 clusters in use */
1217 : 16 : CU_ASSERT((free_clusters - 5) == spdk_bs_free_cluster_count(bs));
1218 : :
1219 : 16 : spdk_blob_sync_md(blob, blob_op_complete, NULL);
1220 : 16 : poll_threads();
1221 : 16 : CU_ASSERT(g_bserrno == 0);
1222 : : /* Now there are only 3 clusters in use */
1223 : 16 : CU_ASSERT((free_clusters - 3) == spdk_bs_free_cluster_count(bs));
1224 : :
1225 : : /* Resize the blob to be 10 clusters. Growth takes effect immediately. */
1226 : 16 : spdk_blob_resize(blob, 10, blob_op_complete, NULL);
1227 : 16 : poll_threads();
1228 : 16 : CU_ASSERT(g_bserrno == 0);
1229 : 16 : CU_ASSERT((free_clusters - 10) == spdk_bs_free_cluster_count(bs));
1230 : :
1231 : : /* Try to resize the blob to size larger than blobstore. */
1232 : 16 : spdk_blob_resize(blob, bs->total_clusters + 1, blob_op_complete, NULL);
1233 : 16 : poll_threads();
1234 : 16 : CU_ASSERT(g_bserrno == -ENOSPC);
1235 : :
1236 : 16 : ut_blob_close_and_delete(bs, blob);
1237 : 16 : }
1238 : :
1239 : : static void
1240 : 16 : blob_read_only(void)
1241 : : {
1242 : 16 : struct spdk_blob_store *bs;
1243 : : struct spdk_bs_dev *dev;
1244 : : struct spdk_blob *blob;
1245 : 16 : struct spdk_bs_opts opts;
1246 : : spdk_blob_id blobid;
1247 : : int rc;
1248 : :
1249 : 16 : dev = init_dev();
1250 : 16 : spdk_bs_opts_init(&opts, sizeof(opts));
1251 : 16 : snprintf(opts.bstype.bstype, sizeof(opts.bstype.bstype), "TESTTYPE");
1252 : :
1253 : 16 : spdk_bs_init(dev, &opts, bs_op_with_handle_complete, NULL);
1254 : 16 : poll_threads();
1255 : 16 : CU_ASSERT(g_bserrno == 0);
1256 [ - + ]: 16 : SPDK_CU_ASSERT_FATAL(g_bs != NULL);
1257 : 16 : bs = g_bs;
1258 : :
1259 : 16 : blob = ut_blob_create_and_open(bs, NULL);
1260 : 16 : blobid = spdk_blob_get_id(blob);
1261 : :
1262 : 16 : rc = spdk_blob_set_read_only(blob);
1263 : 16 : CU_ASSERT(rc == 0);
1264 : :
1265 [ - + ]: 16 : CU_ASSERT(blob->data_ro == false);
1266 [ - + ]: 16 : CU_ASSERT(blob->md_ro == false);
1267 : :
1268 : 16 : spdk_blob_sync_md(blob, bs_op_complete, NULL);
1269 : 16 : poll_threads();
1270 : :
1271 [ - + ]: 16 : CU_ASSERT(blob->data_ro == true);
1272 [ - + ]: 16 : CU_ASSERT(blob->md_ro == true);
1273 : 16 : CU_ASSERT(blob->data_ro_flags & SPDK_BLOB_READ_ONLY);
1274 : :
1275 : 16 : spdk_blob_close(blob, blob_op_complete, NULL);
1276 : 16 : poll_threads();
1277 : 16 : CU_ASSERT(g_bserrno == 0);
1278 : :
1279 : 16 : spdk_bs_open_blob(bs, blobid, blob_op_with_handle_complete, NULL);
1280 : 16 : poll_threads();
1281 : 16 : CU_ASSERT(g_bserrno == 0);
1282 [ - + ]: 16 : SPDK_CU_ASSERT_FATAL(g_blob != NULL);
1283 : 16 : blob = g_blob;
1284 : :
1285 [ - + ]: 16 : CU_ASSERT(blob->data_ro == true);
1286 [ - + ]: 16 : CU_ASSERT(blob->md_ro == true);
1287 : 16 : CU_ASSERT(blob->data_ro_flags & SPDK_BLOB_READ_ONLY);
1288 : :
1289 : 16 : spdk_blob_close(blob, blob_op_complete, NULL);
1290 : 16 : poll_threads();
1291 : 16 : CU_ASSERT(g_bserrno == 0);
1292 : :
1293 : 16 : ut_bs_reload(&bs, &opts);
1294 : :
1295 : 16 : spdk_bs_open_blob(bs, blobid, blob_op_with_handle_complete, NULL);
1296 : 16 : poll_threads();
1297 : 16 : CU_ASSERT(g_bserrno == 0);
1298 [ - + ]: 16 : SPDK_CU_ASSERT_FATAL(g_blob != NULL);
1299 : 16 : blob = g_blob;
1300 : :
1301 [ - + ]: 16 : CU_ASSERT(blob->data_ro == true);
1302 [ - + ]: 16 : CU_ASSERT(blob->md_ro == true);
1303 : 16 : CU_ASSERT(blob->data_ro_flags & SPDK_BLOB_READ_ONLY);
1304 : :
1305 : 16 : ut_blob_close_and_delete(bs, blob);
1306 : :
1307 : 16 : spdk_bs_unload(bs, bs_op_complete, NULL);
1308 : 16 : poll_threads();
1309 : 16 : CU_ASSERT(g_bserrno == 0);
1310 : 16 : }
1311 : :
1312 : : static void
1313 : 16 : channel_ops(void)
1314 : : {
1315 : 16 : struct spdk_blob_store *bs = g_bs;
1316 : : struct spdk_io_channel *channel;
1317 : :
1318 : 16 : channel = spdk_bs_alloc_io_channel(bs);
1319 : 16 : CU_ASSERT(channel != NULL);
1320 : :
1321 : 16 : spdk_bs_free_io_channel(channel);
1322 : 16 : poll_threads();
1323 : 16 : }
1324 : :
1325 : : static void
1326 : 16 : blob_write(void)
1327 : : {
1328 : 16 : struct spdk_blob_store *bs = g_bs;
1329 : 16 : struct spdk_blob *blob = g_blob;
1330 : : struct spdk_io_channel *channel;
1331 : : uint64_t pages_per_cluster;
1332 : 16 : uint8_t payload[10 * 4096];
1333 : :
1334 [ - + ]: 16 : pages_per_cluster = spdk_bs_get_cluster_size(bs) / spdk_bs_get_page_size(bs);
1335 : :
1336 : 16 : channel = spdk_bs_alloc_io_channel(bs);
1337 : 16 : CU_ASSERT(channel != NULL);
1338 : :
1339 : : /* Write to a blob with 0 size */
1340 : 16 : spdk_blob_io_write(blob, channel, payload, 0, 1, blob_op_complete, NULL);
1341 : 16 : poll_threads();
1342 : 16 : CU_ASSERT(g_bserrno == -EINVAL);
1343 : :
1344 : : /* Resize the blob */
1345 : 16 : spdk_blob_resize(blob, 5, blob_op_complete, NULL);
1346 : 16 : poll_threads();
1347 : 16 : CU_ASSERT(g_bserrno == 0);
1348 : :
1349 : : /* Confirm that write fails if blob is marked read-only. */
1350 : 16 : blob->data_ro = true;
1351 : 16 : spdk_blob_io_write(blob, channel, payload, 0, 1, blob_op_complete, NULL);
1352 : 16 : poll_threads();
1353 : 16 : CU_ASSERT(g_bserrno == -EPERM);
1354 : 16 : blob->data_ro = false;
1355 : :
1356 : : /* Write to the blob */
1357 : 16 : spdk_blob_io_write(blob, channel, payload, 0, 1, blob_op_complete, NULL);
1358 : 16 : poll_threads();
1359 : 16 : CU_ASSERT(g_bserrno == 0);
1360 : :
1361 : : /* Write starting beyond the end */
1362 : 16 : spdk_blob_io_write(blob, channel, payload, 5 * pages_per_cluster, 1, blob_op_complete,
1363 : : NULL);
1364 : 16 : poll_threads();
1365 : 16 : CU_ASSERT(g_bserrno == -EINVAL);
1366 : :
1367 : : /* Write starting at a valid location but going off the end */
1368 : 16 : spdk_blob_io_write(blob, channel, payload, 4 * pages_per_cluster, pages_per_cluster + 1,
1369 : : blob_op_complete, NULL);
1370 : 16 : poll_threads();
1371 : 16 : CU_ASSERT(g_bserrno == -EINVAL);
1372 : :
1373 : 16 : spdk_bs_free_io_channel(channel);
1374 : 16 : poll_threads();
1375 : 16 : }
1376 : :
1377 : : static void
1378 : 16 : blob_read(void)
1379 : : {
1380 : 16 : struct spdk_blob_store *bs = g_bs;
1381 : 16 : struct spdk_blob *blob = g_blob;
1382 : : struct spdk_io_channel *channel;
1383 : : uint64_t pages_per_cluster;
1384 : 16 : uint8_t payload[10 * 4096];
1385 : :
1386 [ - + ]: 16 : pages_per_cluster = spdk_bs_get_cluster_size(bs) / spdk_bs_get_page_size(bs);
1387 : :
1388 : 16 : channel = spdk_bs_alloc_io_channel(bs);
1389 : 16 : CU_ASSERT(channel != NULL);
1390 : :
1391 : : /* Read from a blob with 0 size */
1392 : 16 : spdk_blob_io_read(blob, channel, payload, 0, 1, blob_op_complete, NULL);
1393 : 16 : poll_threads();
1394 : 16 : CU_ASSERT(g_bserrno == -EINVAL);
1395 : :
1396 : : /* Resize the blob */
1397 : 16 : spdk_blob_resize(blob, 5, blob_op_complete, NULL);
1398 : 16 : poll_threads();
1399 : 16 : CU_ASSERT(g_bserrno == 0);
1400 : :
1401 : : /* Confirm that read passes if blob is marked read-only. */
1402 : 16 : blob->data_ro = true;
1403 : 16 : spdk_blob_io_read(blob, channel, payload, 0, 1, blob_op_complete, NULL);
1404 : 16 : poll_threads();
1405 : 16 : CU_ASSERT(g_bserrno == 0);
1406 : 16 : blob->data_ro = false;
1407 : :
1408 : : /* Read from the blob */
1409 : 16 : spdk_blob_io_read(blob, channel, payload, 0, 1, blob_op_complete, NULL);
1410 : 16 : poll_threads();
1411 : 16 : CU_ASSERT(g_bserrno == 0);
1412 : :
1413 : : /* Read starting beyond the end */
1414 : 16 : spdk_blob_io_read(blob, channel, payload, 5 * pages_per_cluster, 1, blob_op_complete,
1415 : : NULL);
1416 : 16 : poll_threads();
1417 : 16 : CU_ASSERT(g_bserrno == -EINVAL);
1418 : :
1419 : : /* Read starting at a valid location but going off the end */
1420 : 16 : spdk_blob_io_read(blob, channel, payload, 4 * pages_per_cluster, pages_per_cluster + 1,
1421 : : blob_op_complete, NULL);
1422 : 16 : poll_threads();
1423 : 16 : CU_ASSERT(g_bserrno == -EINVAL);
1424 : :
1425 : 16 : spdk_bs_free_io_channel(channel);
1426 : 16 : poll_threads();
1427 : 16 : }
1428 : :
1429 : : static void
1430 : 16 : blob_rw_verify(void)
1431 : : {
1432 : 16 : struct spdk_blob_store *bs = g_bs;
1433 : 16 : struct spdk_blob *blob = g_blob;
1434 : : struct spdk_io_channel *channel;
1435 : 16 : uint8_t payload_read[10 * 4096];
1436 : 16 : uint8_t payload_write[10 * 4096];
1437 : :
1438 : 16 : channel = spdk_bs_alloc_io_channel(bs);
1439 : 16 : CU_ASSERT(channel != NULL);
1440 : :
1441 : 16 : spdk_blob_resize(blob, 32, blob_op_complete, NULL);
1442 : 16 : poll_threads();
1443 : 16 : CU_ASSERT(g_bserrno == 0);
1444 : :
1445 : 16 : memset(payload_write, 0xE5, sizeof(payload_write));
1446 : 16 : spdk_blob_io_write(blob, channel, payload_write, 4, 10, blob_op_complete, NULL);
1447 : 16 : poll_threads();
1448 : 16 : CU_ASSERT(g_bserrno == 0);
1449 : :
1450 : 16 : memset(payload_read, 0x00, sizeof(payload_read));
1451 : 16 : spdk_blob_io_read(blob, channel, payload_read, 4, 10, blob_op_complete, NULL);
1452 : 16 : poll_threads();
1453 : 16 : CU_ASSERT(g_bserrno == 0);
1454 : 16 : CU_ASSERT(memcmp(payload_write, payload_read, 4 * 4096) == 0);
1455 : :
1456 : 16 : spdk_bs_free_io_channel(channel);
1457 : 16 : poll_threads();
1458 : 16 : }
1459 : :
1460 : : static void
1461 : 16 : blob_rw_verify_iov(void)
1462 : : {
1463 : 16 : struct spdk_blob_store *bs = g_bs;
1464 : : struct spdk_blob *blob;
1465 : : struct spdk_io_channel *channel;
1466 : 16 : uint8_t payload_read[10 * 4096];
1467 : 16 : uint8_t payload_write[10 * 4096];
1468 : 16 : struct iovec iov_read[3];
1469 : 16 : struct iovec iov_write[3];
1470 : : void *buf;
1471 : :
1472 : 16 : channel = spdk_bs_alloc_io_channel(bs);
1473 : 16 : CU_ASSERT(channel != NULL);
1474 : :
1475 : 16 : blob = ut_blob_create_and_open(bs, NULL);
1476 : :
1477 : 16 : spdk_blob_resize(blob, 2, blob_op_complete, NULL);
1478 : 16 : poll_threads();
1479 : 16 : CU_ASSERT(g_bserrno == 0);
1480 : :
1481 : : /*
1482 : : * Manually adjust the offset of the blob's second cluster. This allows
1483 : : * us to make sure that the readv/write code correctly accounts for I/O
1484 : : * that cross cluster boundaries. Start by asserting that the allocated
1485 : : * clusters are where we expect before modifying the second cluster.
1486 : : */
1487 : 16 : CU_ASSERT(blob->active.clusters[0] == 1 * 256);
1488 : 16 : CU_ASSERT(blob->active.clusters[1] == 2 * 256);
1489 : 16 : blob->active.clusters[1] = 3 * 256;
1490 : :
1491 : 16 : memset(payload_write, 0xE5, sizeof(payload_write));
1492 : 16 : iov_write[0].iov_base = payload_write;
1493 : 16 : iov_write[0].iov_len = 1 * 4096;
1494 : 16 : iov_write[1].iov_base = payload_write + 1 * 4096;
1495 : 16 : iov_write[1].iov_len = 5 * 4096;
1496 : 16 : iov_write[2].iov_base = payload_write + 6 * 4096;
1497 : 16 : iov_write[2].iov_len = 4 * 4096;
1498 : : /*
1499 : : * Choose a page offset just before the cluster boundary. The first 6 pages of payload
1500 : : * will get written to the first cluster, the last 4 to the second cluster.
1501 : : */
1502 : 16 : spdk_blob_io_writev(blob, channel, iov_write, 3, 250, 10, blob_op_complete, NULL);
1503 : 16 : poll_threads();
1504 : 16 : CU_ASSERT(g_bserrno == 0);
1505 : :
1506 : 16 : memset(payload_read, 0xAA, sizeof(payload_read));
1507 : 16 : iov_read[0].iov_base = payload_read;
1508 : 16 : iov_read[0].iov_len = 3 * 4096;
1509 : 16 : iov_read[1].iov_base = payload_read + 3 * 4096;
1510 : 16 : iov_read[1].iov_len = 4 * 4096;
1511 : 16 : iov_read[2].iov_base = payload_read + 7 * 4096;
1512 : 16 : iov_read[2].iov_len = 3 * 4096;
1513 : 16 : spdk_blob_io_readv(blob, channel, iov_read, 3, 250, 10, blob_op_complete, NULL);
1514 : 16 : poll_threads();
1515 : 16 : CU_ASSERT(g_bserrno == 0);
1516 : 16 : CU_ASSERT(memcmp(payload_write, payload_read, 10 * 4096) == 0);
1517 : :
1518 : 16 : buf = calloc(1, 256 * 4096);
1519 [ - + ]: 16 : SPDK_CU_ASSERT_FATAL(buf != NULL);
1520 : : /* Check that cluster 2 on "disk" was not modified. */
1521 [ - + - + ]: 16 : CU_ASSERT(memcmp(buf, &g_dev_buffer[512 * 4096], 256 * 4096) == 0);
1522 : 16 : free(buf);
1523 : :
1524 : 16 : spdk_blob_close(blob, blob_op_complete, NULL);
1525 : 16 : poll_threads();
1526 : 16 : CU_ASSERT(g_bserrno == 0);
1527 : :
1528 : 16 : spdk_bs_free_io_channel(channel);
1529 : 16 : poll_threads();
1530 : 16 : }
1531 : :
1532 : : static uint32_t
1533 : 32 : bs_channel_get_req_count(struct spdk_io_channel *_channel)
1534 : : {
1535 : 32 : struct spdk_bs_channel *channel = spdk_io_channel_get_ctx(_channel);
1536 : : struct spdk_bs_request_set *set;
1537 : 32 : uint32_t count = 0;
1538 : :
1539 [ + + ]: 16416 : TAILQ_FOREACH(set, &channel->reqs, link) {
1540 : 16384 : count++;
1541 : : }
1542 : :
1543 : 32 : return count;
1544 : : }
1545 : :
1546 : : static void
1547 : 16 : blob_rw_verify_iov_nomem(void)
1548 : : {
1549 : 16 : struct spdk_blob_store *bs = g_bs;
1550 : 16 : struct spdk_blob *blob = g_blob;
1551 : : struct spdk_io_channel *channel;
1552 : 16 : uint8_t payload_write[10 * 4096];
1553 : 16 : struct iovec iov_write[3];
1554 : : uint32_t req_count;
1555 : :
1556 : 16 : channel = spdk_bs_alloc_io_channel(bs);
1557 : 16 : CU_ASSERT(channel != NULL);
1558 : :
1559 : 16 : spdk_blob_resize(blob, 2, blob_op_complete, NULL);
1560 : 16 : poll_threads();
1561 : 16 : CU_ASSERT(g_bserrno == 0);
1562 : :
1563 : : /*
1564 : : * Choose a page offset just before the cluster boundary. The first 6 pages of payload
1565 : : * will get written to the first cluster, the last 4 to the second cluster.
1566 : : */
1567 : 16 : iov_write[0].iov_base = payload_write;
1568 : 16 : iov_write[0].iov_len = 1 * 4096;
1569 : 16 : iov_write[1].iov_base = payload_write + 1 * 4096;
1570 : 16 : iov_write[1].iov_len = 5 * 4096;
1571 : 16 : iov_write[2].iov_base = payload_write + 6 * 4096;
1572 : 16 : iov_write[2].iov_len = 4 * 4096;
1573 : 16 : MOCK_SET(calloc, NULL);
1574 : 16 : req_count = bs_channel_get_req_count(channel);
1575 : 16 : spdk_blob_io_writev(blob, channel, iov_write, 3, 250, 10, blob_op_complete, NULL);
1576 : 16 : poll_threads();
1577 : 16 : CU_ASSERT(g_bserrno = -ENOMEM);
1578 : 16 : CU_ASSERT(req_count == bs_channel_get_req_count(channel));
1579 : 16 : MOCK_CLEAR(calloc);
1580 : :
1581 : 16 : spdk_bs_free_io_channel(channel);
1582 : 16 : poll_threads();
1583 : 16 : }
1584 : :
1585 : : static void
1586 : 16 : blob_rw_iov_read_only(void)
1587 : : {
1588 : 16 : struct spdk_blob_store *bs = g_bs;
1589 : 16 : struct spdk_blob *blob = g_blob;
1590 : : struct spdk_io_channel *channel;
1591 : 16 : uint8_t payload_read[4096];
1592 : 16 : uint8_t payload_write[4096];
1593 : 16 : struct iovec iov_read;
1594 : 16 : struct iovec iov_write;
1595 : :
1596 : 16 : channel = spdk_bs_alloc_io_channel(bs);
1597 : 16 : CU_ASSERT(channel != NULL);
1598 : :
1599 : 16 : spdk_blob_resize(blob, 2, blob_op_complete, NULL);
1600 : 16 : poll_threads();
1601 : 16 : CU_ASSERT(g_bserrno == 0);
1602 : :
1603 : : /* Verify that writev failed if read_only flag is set. */
1604 : 16 : blob->data_ro = true;
1605 : 16 : iov_write.iov_base = payload_write;
1606 : 16 : iov_write.iov_len = sizeof(payload_write);
1607 : 16 : spdk_blob_io_writev(blob, channel, &iov_write, 1, 0, 1, blob_op_complete, NULL);
1608 : 16 : poll_threads();
1609 : 16 : CU_ASSERT(g_bserrno == -EPERM);
1610 : :
1611 : : /* Verify that reads pass if data_ro flag is set. */
1612 : 16 : iov_read.iov_base = payload_read;
1613 : 16 : iov_read.iov_len = sizeof(payload_read);
1614 : 16 : spdk_blob_io_readv(blob, channel, &iov_read, 1, 0, 1, blob_op_complete, NULL);
1615 : 16 : poll_threads();
1616 : 16 : CU_ASSERT(g_bserrno == 0);
1617 : :
1618 : 16 : spdk_bs_free_io_channel(channel);
1619 : 16 : poll_threads();
1620 : 16 : }
1621 : :
1622 : : static void
1623 : 32 : _blob_io_read_no_split(struct spdk_blob *blob, struct spdk_io_channel *channel,
1624 : : uint8_t *payload, uint64_t offset, uint64_t length,
1625 : : spdk_blob_op_complete cb_fn, void *cb_arg)
1626 : : {
1627 : : uint64_t i;
1628 : : uint8_t *buf;
1629 : 32 : uint64_t page_size = spdk_bs_get_page_size(blob->bs);
1630 : :
1631 : : /* To be sure that operation is NOT split, read one page at the time */
1632 : 32 : buf = payload;
1633 [ + + ]: 40992 : for (i = 0; i < length; i++) {
1634 : 40960 : spdk_blob_io_read(blob, channel, buf, i + offset, 1, blob_op_complete, NULL);
1635 : 40960 : poll_threads();
1636 [ - + ]: 40960 : if (g_bserrno != 0) {
1637 : : /* Pass the error code up */
1638 : 0 : break;
1639 : : }
1640 : 40960 : buf += page_size;
1641 : : }
1642 : :
1643 : 32 : cb_fn(cb_arg, g_bserrno);
1644 : 32 : }
1645 : :
1646 : : static void
1647 : 32 : _blob_io_write_no_split(struct spdk_blob *blob, struct spdk_io_channel *channel,
1648 : : uint8_t *payload, uint64_t offset, uint64_t length,
1649 : : spdk_blob_op_complete cb_fn, void *cb_arg)
1650 : : {
1651 : : uint64_t i;
1652 : : uint8_t *buf;
1653 : 32 : uint64_t page_size = spdk_bs_get_page_size(blob->bs);
1654 : :
1655 : : /* To be sure that operation is NOT split, write one page at the time */
1656 : 32 : buf = payload;
1657 [ + + ]: 40992 : for (i = 0; i < length; i++) {
1658 : 40960 : spdk_blob_io_write(blob, channel, buf, i + offset, 1, blob_op_complete, NULL);
1659 : 40960 : poll_threads();
1660 [ - + ]: 40960 : if (g_bserrno != 0) {
1661 : : /* Pass the error code up */
1662 : 0 : break;
1663 : : }
1664 : 40960 : buf += page_size;
1665 : : }
1666 : :
1667 : 32 : cb_fn(cb_arg, g_bserrno);
1668 : 32 : }
1669 : :
1670 : : static void
1671 : 16 : blob_operation_split_rw(void)
1672 : : {
1673 : 16 : struct spdk_blob_store *bs = g_bs;
1674 : : struct spdk_blob *blob;
1675 : : struct spdk_io_channel *channel;
1676 : 16 : struct spdk_blob_opts opts;
1677 : : uint64_t cluster_size;
1678 : :
1679 : : uint64_t payload_size;
1680 : : uint8_t *payload_read;
1681 : : uint8_t *payload_write;
1682 : : uint8_t *payload_pattern;
1683 : :
1684 : : uint64_t page_size;
1685 : : uint64_t pages_per_cluster;
1686 : : uint64_t pages_per_payload;
1687 : :
1688 : : uint64_t i;
1689 : :
1690 : 16 : cluster_size = spdk_bs_get_cluster_size(bs);
1691 : 16 : page_size = spdk_bs_get_page_size(bs);
1692 [ - + ]: 16 : pages_per_cluster = cluster_size / page_size;
1693 : 16 : pages_per_payload = pages_per_cluster * 5;
1694 : 16 : payload_size = cluster_size * 5;
1695 : :
1696 : 16 : payload_read = malloc(payload_size);
1697 [ - + ]: 16 : SPDK_CU_ASSERT_FATAL(payload_read != NULL);
1698 : :
1699 : 16 : payload_write = malloc(payload_size);
1700 [ - + ]: 16 : SPDK_CU_ASSERT_FATAL(payload_write != NULL);
1701 : :
1702 : 16 : payload_pattern = malloc(payload_size);
1703 [ - + ]: 16 : SPDK_CU_ASSERT_FATAL(payload_pattern != NULL);
1704 : :
1705 : : /* Prepare random pattern to write */
1706 [ - + ]: 16 : memset(payload_pattern, 0xFF, payload_size);
1707 [ + + ]: 20496 : for (i = 0; i < pages_per_payload; i++) {
1708 : 20480 : *((uint64_t *)(payload_pattern + page_size * i)) = (i + 1);
1709 : : }
1710 : :
1711 : 16 : channel = spdk_bs_alloc_io_channel(bs);
1712 [ - + ]: 16 : SPDK_CU_ASSERT_FATAL(channel != NULL);
1713 : :
1714 : : /* Create blob */
1715 : 16 : ut_spdk_blob_opts_init(&opts);
1716 : 16 : opts.thin_provision = false;
1717 : 16 : opts.num_clusters = 5;
1718 : :
1719 : 16 : blob = ut_blob_create_and_open(bs, &opts);
1720 : 16 : CU_ASSERT(spdk_blob_get_num_clusters(blob) == 5);
1721 : :
1722 : : /* Initial read should return zeroed payload */
1723 [ - + ]: 16 : memset(payload_read, 0xFF, payload_size);
1724 : 16 : spdk_blob_io_read(blob, channel, payload_read, 0, pages_per_payload, blob_op_complete, NULL);
1725 : 16 : poll_threads();
1726 : 16 : CU_ASSERT(g_bserrno == 0);
1727 : 16 : CU_ASSERT(spdk_mem_all_zero(payload_read, payload_size));
1728 : :
1729 : : /* Fill whole blob except last page */
1730 : 16 : spdk_blob_io_write(blob, channel, payload_pattern, 0, pages_per_payload - 1,
1731 : : blob_op_complete, NULL);
1732 : 16 : poll_threads();
1733 : 16 : CU_ASSERT(g_bserrno == 0);
1734 : :
1735 : : /* Write last page with a pattern */
1736 : 16 : spdk_blob_io_write(blob, channel, payload_pattern, pages_per_payload - 1, 1,
1737 : : blob_op_complete, NULL);
1738 : 16 : poll_threads();
1739 : 16 : CU_ASSERT(g_bserrno == 0);
1740 : :
1741 : : /* Read whole blob and check consistency */
1742 [ - + ]: 16 : memset(payload_read, 0xFF, payload_size);
1743 : 16 : spdk_blob_io_read(blob, channel, payload_read, 0, pages_per_payload, blob_op_complete, NULL);
1744 : 16 : poll_threads();
1745 : 16 : CU_ASSERT(g_bserrno == 0);
1746 [ - + - + ]: 16 : CU_ASSERT(memcmp(payload_pattern, payload_read, payload_size - page_size) == 0);
1747 [ - + - + ]: 16 : CU_ASSERT(memcmp(payload_pattern, payload_read + payload_size - page_size, page_size) == 0);
1748 : :
1749 : : /* Fill whole blob except first page */
1750 : 16 : spdk_blob_io_write(blob, channel, payload_pattern, 1, pages_per_payload - 1,
1751 : : blob_op_complete, NULL);
1752 : 16 : poll_threads();
1753 : 16 : CU_ASSERT(g_bserrno == 0);
1754 : :
1755 : : /* Write first page with a pattern */
1756 : 16 : spdk_blob_io_write(blob, channel, payload_pattern, 0, 1,
1757 : : blob_op_complete, NULL);
1758 : 16 : poll_threads();
1759 : 16 : CU_ASSERT(g_bserrno == 0);
1760 : :
1761 : : /* Read whole blob and check consistency */
1762 [ - + ]: 16 : memset(payload_read, 0xFF, payload_size);
1763 : 16 : spdk_blob_io_read(blob, channel, payload_read, 0, pages_per_payload, blob_op_complete, NULL);
1764 : 16 : poll_threads();
1765 : 16 : CU_ASSERT(g_bserrno == 0);
1766 [ - + - + ]: 16 : CU_ASSERT(memcmp(payload_pattern, payload_read + page_size, payload_size - page_size) == 0);
1767 [ - + - + ]: 16 : CU_ASSERT(memcmp(payload_pattern, payload_read, page_size) == 0);
1768 : :
1769 : :
1770 : : /* Fill whole blob with a pattern (5 clusters) */
1771 : :
1772 : : /* 1. Read test. */
1773 : 16 : _blob_io_write_no_split(blob, channel, payload_pattern, 0, pages_per_payload,
1774 : : blob_op_complete, NULL);
1775 : 16 : poll_threads();
1776 : 16 : CU_ASSERT(g_bserrno == 0);
1777 : :
1778 [ - + ]: 16 : memset(payload_read, 0xFF, payload_size);
1779 : 16 : spdk_blob_io_read(blob, channel, payload_read, 0, pages_per_payload, blob_op_complete, NULL);
1780 : 16 : poll_threads();
1781 : 16 : poll_threads();
1782 : 16 : CU_ASSERT(g_bserrno == 0);
1783 [ - + - + ]: 16 : CU_ASSERT(memcmp(payload_pattern, payload_read, payload_size) == 0);
1784 : :
1785 : : /* 2. Write test. */
1786 : 16 : spdk_blob_io_write(blob, channel, payload_pattern, 0, pages_per_payload,
1787 : : blob_op_complete, NULL);
1788 : 16 : poll_threads();
1789 : 16 : CU_ASSERT(g_bserrno == 0);
1790 : :
1791 [ - + ]: 16 : memset(payload_read, 0xFF, payload_size);
1792 : 16 : _blob_io_read_no_split(blob, channel, payload_read, 0, pages_per_payload, blob_op_complete, NULL);
1793 : 16 : poll_threads();
1794 : 16 : CU_ASSERT(g_bserrno == 0);
1795 [ - + - + ]: 16 : CU_ASSERT(memcmp(payload_pattern, payload_read, payload_size) == 0);
1796 : :
1797 : 16 : spdk_bs_free_io_channel(channel);
1798 : 16 : poll_threads();
1799 : :
1800 : 16 : g_blob = NULL;
1801 : 16 : g_blobid = 0;
1802 : :
1803 : 16 : free(payload_read);
1804 : 16 : free(payload_write);
1805 : 16 : free(payload_pattern);
1806 : :
1807 : 16 : ut_blob_close_and_delete(bs, blob);
1808 : 16 : }
1809 : :
1810 : : static void
1811 : 16 : blob_operation_split_rw_iov(void)
1812 : : {
1813 : 16 : struct spdk_blob_store *bs = g_bs;
1814 : : struct spdk_blob *blob;
1815 : : struct spdk_io_channel *channel;
1816 : 16 : struct spdk_blob_opts opts;
1817 : : uint64_t cluster_size;
1818 : :
1819 : : uint64_t payload_size;
1820 : : uint8_t *payload_read;
1821 : : uint8_t *payload_write;
1822 : : uint8_t *payload_pattern;
1823 : :
1824 : : uint64_t page_size;
1825 : : uint64_t pages_per_cluster;
1826 : : uint64_t pages_per_payload;
1827 : :
1828 : 16 : struct iovec iov_read[2];
1829 : 16 : struct iovec iov_write[2];
1830 : :
1831 : : uint64_t i, j;
1832 : :
1833 : 16 : cluster_size = spdk_bs_get_cluster_size(bs);
1834 : 16 : page_size = spdk_bs_get_page_size(bs);
1835 [ - + ]: 16 : pages_per_cluster = cluster_size / page_size;
1836 : 16 : pages_per_payload = pages_per_cluster * 5;
1837 : 16 : payload_size = cluster_size * 5;
1838 : :
1839 : 16 : payload_read = malloc(payload_size);
1840 [ - + ]: 16 : SPDK_CU_ASSERT_FATAL(payload_read != NULL);
1841 : :
1842 : 16 : payload_write = malloc(payload_size);
1843 [ - + ]: 16 : SPDK_CU_ASSERT_FATAL(payload_write != NULL);
1844 : :
1845 : 16 : payload_pattern = malloc(payload_size);
1846 [ - + ]: 16 : SPDK_CU_ASSERT_FATAL(payload_pattern != NULL);
1847 : :
1848 : : /* Prepare random pattern to write */
1849 [ + + ]: 20496 : for (i = 0; i < pages_per_payload; i++) {
1850 [ + + ]: 10506240 : for (j = 0; j < page_size / sizeof(uint64_t); j++) {
1851 : : uint64_t *tmp;
1852 : :
1853 : 10485760 : tmp = (uint64_t *)payload_pattern;
1854 : 10485760 : tmp += ((page_size * i) / sizeof(uint64_t)) + j;
1855 : 10485760 : *tmp = i + 1;
1856 : : }
1857 : : }
1858 : :
1859 : 16 : channel = spdk_bs_alloc_io_channel(bs);
1860 [ - + ]: 16 : SPDK_CU_ASSERT_FATAL(channel != NULL);
1861 : :
1862 : : /* Create blob */
1863 : 16 : ut_spdk_blob_opts_init(&opts);
1864 : 16 : opts.thin_provision = false;
1865 : 16 : opts.num_clusters = 5;
1866 : :
1867 : 16 : blob = ut_blob_create_and_open(bs, &opts);
1868 : 16 : CU_ASSERT(spdk_blob_get_num_clusters(blob) == 5);
1869 : :
1870 : : /* Initial read should return zeroes payload */
1871 [ - + ]: 16 : memset(payload_read, 0xFF, payload_size);
1872 : 16 : iov_read[0].iov_base = payload_read;
1873 : 16 : iov_read[0].iov_len = cluster_size * 3;
1874 : 16 : iov_read[1].iov_base = payload_read + cluster_size * 3;
1875 : 16 : iov_read[1].iov_len = cluster_size * 2;
1876 : 16 : spdk_blob_io_readv(blob, channel, iov_read, 2, 0, pages_per_payload, blob_op_complete, NULL);
1877 : 16 : poll_threads();
1878 : 16 : CU_ASSERT(g_bserrno == 0);
1879 : 16 : CU_ASSERT(spdk_mem_all_zero(payload_read, payload_size));
1880 : :
1881 : : /* First of iovs fills whole blob except last page and second of iovs writes last page
1882 : : * with a pattern. */
1883 : 16 : iov_write[0].iov_base = payload_pattern;
1884 : 16 : iov_write[0].iov_len = payload_size - page_size;
1885 : 16 : iov_write[1].iov_base = payload_pattern;
1886 : 16 : iov_write[1].iov_len = page_size;
1887 : 16 : spdk_blob_io_writev(blob, channel, iov_write, 2, 0, pages_per_payload, blob_op_complete, NULL);
1888 : 16 : poll_threads();
1889 : 16 : CU_ASSERT(g_bserrno == 0);
1890 : :
1891 : : /* Read whole blob and check consistency */
1892 [ - + ]: 16 : memset(payload_read, 0xFF, payload_size);
1893 : 16 : iov_read[0].iov_base = payload_read;
1894 : 16 : iov_read[0].iov_len = cluster_size * 2;
1895 : 16 : iov_read[1].iov_base = payload_read + cluster_size * 2;
1896 : 16 : iov_read[1].iov_len = cluster_size * 3;
1897 : 16 : spdk_blob_io_readv(blob, channel, iov_read, 2, 0, pages_per_payload, blob_op_complete, NULL);
1898 : 16 : poll_threads();
1899 : 16 : CU_ASSERT(g_bserrno == 0);
1900 [ - + - + ]: 16 : CU_ASSERT(memcmp(payload_pattern, payload_read, payload_size - page_size) == 0);
1901 [ - + - + ]: 16 : CU_ASSERT(memcmp(payload_pattern, payload_read + payload_size - page_size, page_size) == 0);
1902 : :
1903 : : /* First of iovs fills only first page and second of iovs writes whole blob except
1904 : : * first page with a pattern. */
1905 : 16 : iov_write[0].iov_base = payload_pattern;
1906 : 16 : iov_write[0].iov_len = page_size;
1907 : 16 : iov_write[1].iov_base = payload_pattern;
1908 : 16 : iov_write[1].iov_len = payload_size - page_size;
1909 : 16 : spdk_blob_io_writev(blob, channel, iov_write, 2, 0, pages_per_payload, blob_op_complete, NULL);
1910 : 16 : poll_threads();
1911 : 16 : CU_ASSERT(g_bserrno == 0);
1912 : :
1913 : : /* Read whole blob and check consistency */
1914 [ - + ]: 16 : memset(payload_read, 0xFF, payload_size);
1915 : 16 : iov_read[0].iov_base = payload_read;
1916 : 16 : iov_read[0].iov_len = cluster_size * 4;
1917 : 16 : iov_read[1].iov_base = payload_read + cluster_size * 4;
1918 : 16 : iov_read[1].iov_len = cluster_size;
1919 : 16 : spdk_blob_io_readv(blob, channel, iov_read, 2, 0, pages_per_payload, blob_op_complete, NULL);
1920 : 16 : poll_threads();
1921 : 16 : CU_ASSERT(g_bserrno == 0);
1922 [ - + - + ]: 16 : CU_ASSERT(memcmp(payload_pattern, payload_read + page_size, payload_size - page_size) == 0);
1923 [ - + - + ]: 16 : CU_ASSERT(memcmp(payload_pattern, payload_read, page_size) == 0);
1924 : :
1925 : :
1926 : : /* Fill whole blob with a pattern (5 clusters) */
1927 : :
1928 : : /* 1. Read test. */
1929 : 16 : _blob_io_write_no_split(blob, channel, payload_pattern, 0, pages_per_payload,
1930 : : blob_op_complete, NULL);
1931 : 16 : poll_threads();
1932 : 16 : CU_ASSERT(g_bserrno == 0);
1933 : :
1934 [ - + ]: 16 : memset(payload_read, 0xFF, payload_size);
1935 : 16 : iov_read[0].iov_base = payload_read;
1936 : 16 : iov_read[0].iov_len = cluster_size;
1937 : 16 : iov_read[1].iov_base = payload_read + cluster_size;
1938 : 16 : iov_read[1].iov_len = cluster_size * 4;
1939 : 16 : spdk_blob_io_readv(blob, channel, iov_read, 2, 0, pages_per_payload, blob_op_complete, NULL);
1940 : 16 : poll_threads();
1941 : 16 : CU_ASSERT(g_bserrno == 0);
1942 [ - + - + ]: 16 : CU_ASSERT(memcmp(payload_pattern, payload_read, payload_size) == 0);
1943 : :
1944 : : /* 2. Write test. */
1945 : 16 : iov_write[0].iov_base = payload_read;
1946 : 16 : iov_write[0].iov_len = cluster_size * 2;
1947 : 16 : iov_write[1].iov_base = payload_read + cluster_size * 2;
1948 : 16 : iov_write[1].iov_len = cluster_size * 3;
1949 : 16 : spdk_blob_io_writev(blob, channel, iov_write, 2, 0, pages_per_payload, blob_op_complete, NULL);
1950 : 16 : poll_threads();
1951 : 16 : CU_ASSERT(g_bserrno == 0);
1952 : :
1953 [ - + ]: 16 : memset(payload_read, 0xFF, payload_size);
1954 : 16 : _blob_io_read_no_split(blob, channel, payload_read, 0, pages_per_payload, blob_op_complete, NULL);
1955 : 16 : poll_threads();
1956 : 16 : CU_ASSERT(g_bserrno == 0);
1957 [ - + - + ]: 16 : CU_ASSERT(memcmp(payload_pattern, payload_read, payload_size) == 0);
1958 : :
1959 : 16 : spdk_bs_free_io_channel(channel);
1960 : 16 : poll_threads();
1961 : :
1962 : 16 : g_blob = NULL;
1963 : 16 : g_blobid = 0;
1964 : :
1965 : 16 : free(payload_read);
1966 : 16 : free(payload_write);
1967 : 16 : free(payload_pattern);
1968 : :
1969 : 16 : ut_blob_close_and_delete(bs, blob);
1970 : 16 : }
1971 : :
1972 : : static void
1973 : 16 : blob_unmap(void)
1974 : : {
1975 : 16 : struct spdk_blob_store *bs = g_bs;
1976 : : struct spdk_blob *blob;
1977 : : struct spdk_io_channel *channel;
1978 : 16 : struct spdk_blob_opts opts;
1979 : 16 : uint8_t payload[4096];
1980 : : int i;
1981 : :
1982 : 16 : channel = spdk_bs_alloc_io_channel(bs);
1983 : 16 : CU_ASSERT(channel != NULL);
1984 : :
1985 : 16 : ut_spdk_blob_opts_init(&opts);
1986 : 16 : opts.num_clusters = 10;
1987 : :
1988 : 16 : blob = ut_blob_create_and_open(bs, &opts);
1989 : :
1990 : 16 : spdk_blob_resize(blob, 10, blob_op_complete, NULL);
1991 : 16 : poll_threads();
1992 : 16 : CU_ASSERT(g_bserrno == 0);
1993 : :
1994 [ - + ]: 16 : memset(payload, 0, sizeof(payload));
1995 : 16 : payload[0] = 0xFF;
1996 : :
1997 : : /*
1998 : : * Set first byte of every cluster to 0xFF.
1999 : : * First cluster on device is reserved so let's start from cluster number 1
2000 : : */
2001 [ + + ]: 176 : for (i = 1; i < 11; i++) {
2002 : 160 : g_dev_buffer[i * SPDK_BLOB_OPTS_CLUSTER_SZ] = 0xFF;
2003 : : }
2004 : :
2005 : : /* Confirm writes */
2006 [ + + ]: 176 : for (i = 0; i < 10; i++) {
2007 : 160 : payload[0] = 0;
2008 : 160 : spdk_blob_io_read(blob, channel, &payload, i * SPDK_BLOB_OPTS_CLUSTER_SZ / 4096, 1,
2009 : : blob_op_complete, NULL);
2010 : 160 : poll_threads();
2011 : 160 : CU_ASSERT(g_bserrno == 0);
2012 : 160 : CU_ASSERT(payload[0] == 0xFF);
2013 : : }
2014 : :
2015 : : /* Mark some clusters as unallocated */
2016 : 16 : blob->active.clusters[1] = 0;
2017 : 16 : blob->active.clusters[2] = 0;
2018 : 16 : blob->active.clusters[3] = 0;
2019 : 16 : blob->active.clusters[6] = 0;
2020 : 16 : blob->active.clusters[8] = 0;
2021 : :
2022 : : /* Unmap clusters by resizing to 0 */
2023 : 16 : spdk_blob_resize(blob, 0, blob_op_complete, NULL);
2024 : 16 : poll_threads();
2025 : 16 : CU_ASSERT(g_bserrno == 0);
2026 : :
2027 : 16 : spdk_blob_sync_md(blob, blob_op_complete, NULL);
2028 : 16 : poll_threads();
2029 : 16 : CU_ASSERT(g_bserrno == 0);
2030 : :
2031 : : /* Confirm that only 'allocated' clusters were unmapped */
2032 [ + + ]: 176 : for (i = 1; i < 11; i++) {
2033 [ + + ]: 160 : switch (i) {
2034 : 80 : case 2:
2035 : : case 3:
2036 : : case 4:
2037 : : case 7:
2038 : : case 9:
2039 : 80 : CU_ASSERT(g_dev_buffer[i * SPDK_BLOB_OPTS_CLUSTER_SZ] == 0xFF);
2040 : 80 : break;
2041 : 80 : default:
2042 : 80 : CU_ASSERT(g_dev_buffer[i * SPDK_BLOB_OPTS_CLUSTER_SZ] == 0);
2043 : 80 : break;
2044 : : }
2045 : : }
2046 : :
2047 : 16 : spdk_bs_free_io_channel(channel);
2048 : 16 : poll_threads();
2049 : :
2050 : 16 : ut_blob_close_and_delete(bs, blob);
2051 : 16 : }
2052 : :
2053 : : static void
2054 : 16 : blob_iter(void)
2055 : : {
2056 : 16 : struct spdk_blob_store *bs = g_bs;
2057 : : struct spdk_blob *blob;
2058 : : spdk_blob_id blobid;
2059 : 16 : struct spdk_blob_opts blob_opts;
2060 : :
2061 : 16 : spdk_bs_iter_first(bs, blob_op_with_handle_complete, NULL);
2062 : 16 : poll_threads();
2063 : 16 : CU_ASSERT(g_blob == NULL);
2064 : 16 : CU_ASSERT(g_bserrno == -ENOENT);
2065 : :
2066 : 16 : ut_spdk_blob_opts_init(&blob_opts);
2067 : 16 : spdk_bs_create_blob_ext(bs, &blob_opts, blob_op_with_id_complete, NULL);
2068 : 16 : poll_threads();
2069 : 16 : CU_ASSERT(g_bserrno == 0);
2070 : 16 : CU_ASSERT(g_blobid != SPDK_BLOBID_INVALID);
2071 : 16 : blobid = g_blobid;
2072 : :
2073 : 16 : spdk_bs_iter_first(bs, blob_op_with_handle_complete, NULL);
2074 : 16 : poll_threads();
2075 : 16 : CU_ASSERT(g_blob != NULL);
2076 : 16 : CU_ASSERT(g_bserrno == 0);
2077 : 16 : blob = g_blob;
2078 : 16 : CU_ASSERT(spdk_blob_get_id(blob) == blobid);
2079 : :
2080 : 16 : spdk_bs_iter_next(bs, blob, blob_op_with_handle_complete, NULL);
2081 : 16 : poll_threads();
2082 : 16 : CU_ASSERT(g_blob == NULL);
2083 : 16 : CU_ASSERT(g_bserrno == -ENOENT);
2084 : 16 : }
2085 : :
2086 : : static void
2087 : 16 : blob_xattr(void)
2088 : : {
2089 : 16 : struct spdk_blob_store *bs = g_bs;
2090 : 16 : struct spdk_blob *blob = g_blob;
2091 : 16 : spdk_blob_id blobid = spdk_blob_get_id(blob);
2092 : 16 : uint64_t length;
2093 : : int rc;
2094 : : const char *name1, *name2;
2095 : 16 : const void *value;
2096 : 16 : size_t value_len;
2097 : 16 : struct spdk_xattr_names *names;
2098 : :
2099 : : /* Test that set_xattr fails if md_ro flag is set. */
2100 : 16 : blob->md_ro = true;
2101 : 16 : rc = spdk_blob_set_xattr(blob, "name", "log.txt", strlen("log.txt") + 1);
2102 : 16 : CU_ASSERT(rc == -EPERM);
2103 : :
2104 : 16 : blob->md_ro = false;
2105 : 16 : rc = spdk_blob_set_xattr(blob, "name", "log.txt", strlen("log.txt") + 1);
2106 : 16 : CU_ASSERT(rc == 0);
2107 : :
2108 : 16 : length = 2345;
2109 : 16 : rc = spdk_blob_set_xattr(blob, "length", &length, sizeof(length));
2110 : 16 : CU_ASSERT(rc == 0);
2111 : :
2112 : : /* Overwrite "length" xattr. */
2113 : 16 : length = 3456;
2114 : 16 : rc = spdk_blob_set_xattr(blob, "length", &length, sizeof(length));
2115 : 16 : CU_ASSERT(rc == 0);
2116 : :
2117 : : /* get_xattr should still work even if md_ro flag is set. */
2118 : 16 : value = NULL;
2119 : 16 : blob->md_ro = true;
2120 : 16 : rc = spdk_blob_get_xattr_value(blob, "length", &value, &value_len);
2121 : 16 : CU_ASSERT(rc == 0);
2122 [ - + ]: 16 : SPDK_CU_ASSERT_FATAL(value != NULL);
2123 : 16 : CU_ASSERT(*(uint64_t *)value == length);
2124 : 16 : CU_ASSERT(value_len == 8);
2125 : 16 : blob->md_ro = false;
2126 : :
2127 : 16 : rc = spdk_blob_get_xattr_value(blob, "foobar", &value, &value_len);
2128 : 16 : CU_ASSERT(rc == -ENOENT);
2129 : :
2130 : 16 : names = NULL;
2131 : 16 : rc = spdk_blob_get_xattr_names(blob, &names);
2132 : 16 : CU_ASSERT(rc == 0);
2133 [ - + ]: 16 : SPDK_CU_ASSERT_FATAL(names != NULL);
2134 : 16 : CU_ASSERT(spdk_xattr_names_get_count(names) == 2);
2135 : 16 : name1 = spdk_xattr_names_get_name(names, 0);
2136 [ - + ]: 16 : SPDK_CU_ASSERT_FATAL(name1 != NULL);
2137 [ - + - + : 16 : CU_ASSERT(!strcmp(name1, "name") || !strcmp(name1, "length"));
- - - - ]
2138 : 16 : name2 = spdk_xattr_names_get_name(names, 1);
2139 [ - + ]: 16 : SPDK_CU_ASSERT_FATAL(name2 != NULL);
2140 [ + + + - : 16 : CU_ASSERT(!strcmp(name2, "name") || !strcmp(name2, "length"));
- + + - ]
2141 [ - + - + ]: 16 : CU_ASSERT(strcmp(name1, name2));
2142 : 16 : spdk_xattr_names_free(names);
2143 : :
2144 : : /* Confirm that remove_xattr fails if md_ro is set to true. */
2145 : 16 : blob->md_ro = true;
2146 : 16 : rc = spdk_blob_remove_xattr(blob, "name");
2147 : 16 : CU_ASSERT(rc == -EPERM);
2148 : :
2149 : 16 : blob->md_ro = false;
2150 : 16 : rc = spdk_blob_remove_xattr(blob, "name");
2151 : 16 : CU_ASSERT(rc == 0);
2152 : :
2153 : 16 : rc = spdk_blob_remove_xattr(blob, "foobar");
2154 : 16 : CU_ASSERT(rc == -ENOENT);
2155 : :
2156 : : /* Set internal xattr */
2157 : 16 : length = 7898;
2158 : 16 : rc = blob_set_xattr(blob, "internal", &length, sizeof(length), true);
2159 : 16 : CU_ASSERT(rc == 0);
2160 : 16 : rc = blob_get_xattr_value(blob, "internal", &value, &value_len, true);
2161 : 16 : CU_ASSERT(rc == 0);
2162 : 16 : CU_ASSERT(*(uint64_t *)value == length);
2163 : : /* try to get public xattr with same name */
2164 : 16 : rc = spdk_blob_get_xattr_value(blob, "internal", &value, &value_len);
2165 : 16 : CU_ASSERT(rc != 0);
2166 : 16 : rc = blob_get_xattr_value(blob, "internal", &value, &value_len, false);
2167 : 16 : CU_ASSERT(rc != 0);
2168 : : /* Check if SPDK_BLOB_INTERNAL_XATTR is set */
2169 : 16 : CU_ASSERT((blob->invalid_flags & SPDK_BLOB_INTERNAL_XATTR) ==
2170 : : SPDK_BLOB_INTERNAL_XATTR);
2171 : :
2172 : 16 : spdk_blob_close(blob, blob_op_complete, NULL);
2173 : 16 : poll_threads();
2174 : :
2175 : : /* Check if xattrs are persisted */
2176 : 16 : ut_bs_reload(&bs, NULL);
2177 : :
2178 : 16 : spdk_bs_open_blob(bs, blobid, blob_op_with_handle_complete, NULL);
2179 : 16 : poll_threads();
2180 : 16 : CU_ASSERT(g_bserrno == 0);
2181 [ - + ]: 16 : SPDK_CU_ASSERT_FATAL(g_blob != NULL);
2182 : 16 : blob = g_blob;
2183 : :
2184 : 16 : rc = blob_get_xattr_value(blob, "internal", &value, &value_len, true);
2185 : 16 : CU_ASSERT(rc == 0);
2186 : 16 : CU_ASSERT(*(uint64_t *)value == length);
2187 : :
2188 : : /* try to get internal xattr trough public call */
2189 : 16 : rc = spdk_blob_get_xattr_value(blob, "internal", &value, &value_len);
2190 : 16 : CU_ASSERT(rc != 0);
2191 : :
2192 : 16 : rc = blob_remove_xattr(blob, "internal", true);
2193 : 16 : CU_ASSERT(rc == 0);
2194 : :
2195 : 16 : CU_ASSERT((blob->invalid_flags & SPDK_BLOB_INTERNAL_XATTR) == 0);
2196 : 16 : }
2197 : :
2198 : : static void
2199 : 16 : blob_parse_md(void)
2200 : : {
2201 : 16 : struct spdk_blob_store *bs = g_bs;
2202 : : struct spdk_blob *blob;
2203 : : int rc;
2204 : : uint32_t used_pages;
2205 : : size_t xattr_length;
2206 : : char *xattr;
2207 : :
2208 : 16 : used_pages = spdk_bit_array_count_set(bs->used_md_pages);
2209 : 16 : blob = ut_blob_create_and_open(bs, NULL);
2210 : :
2211 : : /* Create large extent to force more than 1 page of metadata. */
2212 : 16 : xattr_length = SPDK_BS_MAX_DESC_SIZE - sizeof(struct spdk_blob_md_descriptor_xattr) -
2213 : : strlen("large_xattr");
2214 : 16 : xattr = calloc(xattr_length, sizeof(char));
2215 [ - + ]: 16 : SPDK_CU_ASSERT_FATAL(xattr != NULL);
2216 : 16 : rc = spdk_blob_set_xattr(blob, "large_xattr", xattr, xattr_length);
2217 : 16 : free(xattr);
2218 [ - + ]: 16 : SPDK_CU_ASSERT_FATAL(rc == 0);
2219 : :
2220 : 16 : spdk_blob_sync_md(blob, blob_op_complete, NULL);
2221 : 16 : poll_threads();
2222 : :
2223 : : /* Delete the blob and verify that number of pages returned to before its creation. */
2224 [ - + ]: 16 : SPDK_CU_ASSERT_FATAL(used_pages != spdk_bit_array_count_set(bs->used_md_pages));
2225 : 16 : ut_blob_close_and_delete(bs, blob);
2226 [ - + ]: 16 : SPDK_CU_ASSERT_FATAL(used_pages == spdk_bit_array_count_set(bs->used_md_pages));
2227 : 16 : }
2228 : :
2229 : : static void
2230 : 16 : bs_load(void)
2231 : : {
2232 : : struct spdk_blob_store *bs;
2233 : : struct spdk_bs_dev *dev;
2234 : : spdk_blob_id blobid;
2235 : : struct spdk_blob *blob;
2236 : : struct spdk_bs_super_block *super_block;
2237 : 16 : uint64_t length;
2238 : : int rc;
2239 : 16 : const void *value;
2240 : 16 : size_t value_len;
2241 : 16 : struct spdk_bs_opts opts;
2242 : 16 : struct spdk_blob_opts blob_opts;
2243 : :
2244 : 16 : dev = init_dev();
2245 : 16 : spdk_bs_opts_init(&opts, sizeof(opts));
2246 : 16 : snprintf(opts.bstype.bstype, sizeof(opts.bstype.bstype), "TESTTYPE");
2247 : :
2248 : : /* Initialize a new blob store */
2249 : 16 : spdk_bs_init(dev, &opts, bs_op_with_handle_complete, NULL);
2250 : 16 : poll_threads();
2251 : 16 : CU_ASSERT(g_bserrno == 0);
2252 [ - + ]: 16 : SPDK_CU_ASSERT_FATAL(g_bs != NULL);
2253 : 16 : bs = g_bs;
2254 : :
2255 : : /* Try to open a blobid that does not exist */
2256 : 16 : spdk_bs_open_blob(bs, 0, blob_op_with_handle_complete, NULL);
2257 : 16 : poll_threads();
2258 : 16 : CU_ASSERT(g_bserrno == -ENOENT);
2259 : 16 : CU_ASSERT(g_blob == NULL);
2260 : :
2261 : : /* Create a blob */
2262 : 16 : blob = ut_blob_create_and_open(bs, NULL);
2263 : 16 : blobid = spdk_blob_get_id(blob);
2264 : :
2265 : : /* Try again to open valid blob but without the upper bit set */
2266 : 16 : spdk_bs_open_blob(bs, blobid & 0xFFFFFFFF, blob_op_with_handle_complete, NULL);
2267 : 16 : poll_threads();
2268 : 16 : CU_ASSERT(g_bserrno == -ENOENT);
2269 : 16 : CU_ASSERT(g_blob == NULL);
2270 : :
2271 : : /* Set some xattrs */
2272 : 16 : rc = spdk_blob_set_xattr(blob, "name", "log.txt", strlen("log.txt") + 1);
2273 : 16 : CU_ASSERT(rc == 0);
2274 : :
2275 : 16 : length = 2345;
2276 : 16 : rc = spdk_blob_set_xattr(blob, "length", &length, sizeof(length));
2277 : 16 : CU_ASSERT(rc == 0);
2278 : :
2279 : : /* Resize the blob */
2280 : 16 : spdk_blob_resize(blob, 10, blob_op_complete, NULL);
2281 : 16 : poll_threads();
2282 : 16 : CU_ASSERT(g_bserrno == 0);
2283 : :
2284 : 16 : spdk_blob_close(blob, blob_op_complete, NULL);
2285 : 16 : poll_threads();
2286 : 16 : CU_ASSERT(g_bserrno == 0);
2287 : 16 : blob = NULL;
2288 : 16 : g_blob = NULL;
2289 : 16 : g_blobid = SPDK_BLOBID_INVALID;
2290 : :
2291 : : /* Unload the blob store */
2292 : 16 : spdk_bs_unload(bs, bs_op_complete, NULL);
2293 : 16 : poll_threads();
2294 : 16 : CU_ASSERT(g_bserrno == 0);
2295 : 16 : g_bs = NULL;
2296 : 16 : g_blob = NULL;
2297 : 16 : g_blobid = 0;
2298 : :
2299 : 16 : super_block = (struct spdk_bs_super_block *)g_dev_buffer;
2300 : 16 : CU_ASSERT(super_block->clean == 1);
2301 : :
2302 : : /* Load should fail for device with an unsupported blocklen */
2303 : 16 : dev = init_dev();
2304 : 16 : dev->blocklen = SPDK_BS_PAGE_SIZE * 2;
2305 : 16 : spdk_bs_load(dev, NULL, bs_op_with_handle_complete, NULL);
2306 : 16 : poll_threads();
2307 : 16 : CU_ASSERT(g_bserrno == -EINVAL);
2308 : :
2309 : : /* Load should when max_md_ops is set to zero */
2310 : 16 : dev = init_dev();
2311 : 16 : spdk_bs_opts_init(&opts, sizeof(opts));
2312 : 16 : opts.max_md_ops = 0;
2313 : 16 : spdk_bs_load(dev, &opts, bs_op_with_handle_complete, NULL);
2314 : 16 : poll_threads();
2315 : 16 : CU_ASSERT(g_bserrno == -EINVAL);
2316 : :
2317 : : /* Load should when max_channel_ops is set to zero */
2318 : 16 : dev = init_dev();
2319 : 16 : spdk_bs_opts_init(&opts, sizeof(opts));
2320 : 16 : opts.max_channel_ops = 0;
2321 : 16 : spdk_bs_load(dev, &opts, bs_op_with_handle_complete, NULL);
2322 : 16 : poll_threads();
2323 : 16 : CU_ASSERT(g_bserrno == -EINVAL);
2324 : :
2325 : : /* Load an existing blob store */
2326 : 16 : dev = init_dev();
2327 : 16 : spdk_bs_opts_init(&opts, sizeof(opts));
2328 : 16 : snprintf(opts.bstype.bstype, sizeof(opts.bstype.bstype), "TESTTYPE");
2329 : 16 : spdk_bs_load(dev, &opts, bs_op_with_handle_complete, NULL);
2330 : 16 : poll_threads();
2331 : 16 : CU_ASSERT(g_bserrno == 0);
2332 [ - + ]: 16 : SPDK_CU_ASSERT_FATAL(g_bs != NULL);
2333 : 16 : bs = g_bs;
2334 : :
2335 : 16 : super_block = (struct spdk_bs_super_block *)g_dev_buffer;
2336 : 16 : CU_ASSERT(super_block->clean == 1);
2337 : 16 : CU_ASSERT(super_block->size == dev->blockcnt * dev->blocklen);
2338 : :
2339 : 16 : spdk_bs_open_blob(bs, blobid, blob_op_with_handle_complete, NULL);
2340 : 16 : poll_threads();
2341 : 16 : CU_ASSERT(g_bserrno == 0);
2342 : 16 : CU_ASSERT(g_blob != NULL);
2343 : 16 : blob = g_blob;
2344 : :
2345 : : /* Verify that blobstore is marked dirty after first metadata sync */
2346 : 16 : spdk_blob_sync_md(blob, blob_op_complete, NULL);
2347 : 16 : CU_ASSERT(super_block->clean == 1);
2348 : :
2349 : : /* Get the xattrs */
2350 : 16 : value = NULL;
2351 : 16 : rc = spdk_blob_get_xattr_value(blob, "length", &value, &value_len);
2352 : 16 : CU_ASSERT(rc == 0);
2353 [ - + ]: 16 : SPDK_CU_ASSERT_FATAL(value != NULL);
2354 : 16 : CU_ASSERT(*(uint64_t *)value == length);
2355 : 16 : CU_ASSERT(value_len == 8);
2356 : :
2357 : 16 : rc = spdk_blob_get_xattr_value(blob, "foobar", &value, &value_len);
2358 : 16 : CU_ASSERT(rc == -ENOENT);
2359 : :
2360 : 16 : CU_ASSERT(spdk_blob_get_num_clusters(blob) == 10);
2361 : :
2362 : 16 : spdk_blob_close(blob, blob_op_complete, NULL);
2363 : 16 : poll_threads();
2364 : 16 : CU_ASSERT(g_bserrno == 0);
2365 : 16 : blob = NULL;
2366 : 16 : g_blob = NULL;
2367 : :
2368 : 16 : spdk_bs_unload(bs, bs_op_complete, NULL);
2369 : 16 : poll_threads();
2370 : 16 : CU_ASSERT(g_bserrno == 0);
2371 : 16 : g_bs = NULL;
2372 : :
2373 : : /* Load should fail: bdev size < saved size */
2374 : 16 : dev = init_dev();
2375 : 16 : dev->blockcnt /= 2;
2376 : :
2377 : 16 : spdk_bs_opts_init(&opts, sizeof(opts));
2378 : 16 : snprintf(opts.bstype.bstype, sizeof(opts.bstype.bstype), "TESTTYPE");
2379 : 16 : spdk_bs_load(dev, &opts, bs_op_with_handle_complete, NULL);
2380 : 16 : poll_threads();
2381 : :
2382 : 16 : CU_ASSERT(g_bserrno == -EILSEQ);
2383 : :
2384 : : /* Load should succeed: bdev size > saved size */
2385 : 16 : dev = init_dev();
2386 : 16 : dev->blockcnt *= 4;
2387 : :
2388 : 16 : spdk_bs_opts_init(&opts, sizeof(opts));
2389 : 16 : snprintf(opts.bstype.bstype, sizeof(opts.bstype.bstype), "TESTTYPE");
2390 : 16 : spdk_bs_load(dev, &opts, bs_op_with_handle_complete, NULL);
2391 : 16 : poll_threads();
2392 : 16 : CU_ASSERT(g_bserrno == 0);
2393 [ - + ]: 16 : SPDK_CU_ASSERT_FATAL(g_bs != NULL);
2394 : 16 : bs = g_bs;
2395 : :
2396 : 16 : CU_ASSERT(g_bserrno == 0);
2397 : 16 : spdk_bs_unload(bs, bs_op_complete, NULL);
2398 : 16 : poll_threads();
2399 : :
2400 : :
2401 : : /* Test compatibility mode */
2402 : :
2403 : 16 : dev = init_dev();
2404 : 16 : super_block->size = 0;
2405 : 16 : super_block->crc = blob_md_page_calc_crc(super_block);
2406 : :
2407 : 16 : spdk_bs_opts_init(&opts, sizeof(opts));
2408 : 16 : snprintf(opts.bstype.bstype, sizeof(opts.bstype.bstype), "TESTTYPE");
2409 : 16 : spdk_bs_load(dev, &opts, bs_op_with_handle_complete, NULL);
2410 : 16 : poll_threads();
2411 : 16 : CU_ASSERT(g_bserrno == 0);
2412 [ - + ]: 16 : SPDK_CU_ASSERT_FATAL(g_bs != NULL);
2413 : 16 : bs = g_bs;
2414 : :
2415 : : /* Create a blob */
2416 : 16 : ut_spdk_blob_opts_init(&blob_opts);
2417 : 16 : spdk_bs_create_blob_ext(bs, &blob_opts, blob_op_with_id_complete, NULL);
2418 : 16 : poll_threads();
2419 : 16 : CU_ASSERT(g_bserrno == 0);
2420 : 16 : CU_ASSERT(g_blobid != SPDK_BLOBID_INVALID);
2421 : :
2422 : : /* Blobstore should update number of blocks in super_block */
2423 : 16 : CU_ASSERT(super_block->size == dev->blockcnt * dev->blocklen);
2424 : 16 : CU_ASSERT(super_block->clean == 0);
2425 : :
2426 : 16 : spdk_bs_unload(bs, bs_op_complete, NULL);
2427 : 16 : poll_threads();
2428 : 16 : CU_ASSERT(g_bserrno == 0);
2429 : 16 : CU_ASSERT(super_block->clean == 1);
2430 : 16 : g_bs = NULL;
2431 : :
2432 : 16 : }
2433 : :
2434 : : static void
2435 : 16 : bs_load_pending_removal(void)
2436 : : {
2437 : 16 : struct spdk_blob_store *bs = g_bs;
2438 : 16 : struct spdk_blob_opts opts;
2439 : : struct spdk_blob *blob, *snapshot;
2440 : 16 : spdk_blob_id blobid, snapshotid;
2441 : 16 : const void *value;
2442 : 16 : size_t value_len;
2443 : : int rc;
2444 : :
2445 : : /* Create blob */
2446 : 16 : ut_spdk_blob_opts_init(&opts);
2447 : 16 : opts.num_clusters = 10;
2448 : :
2449 : 16 : blob = ut_blob_create_and_open(bs, &opts);
2450 : 16 : blobid = spdk_blob_get_id(blob);
2451 : :
2452 : : /* Create snapshot */
2453 : 16 : spdk_bs_create_snapshot(bs, blobid, NULL, blob_op_with_id_complete, NULL);
2454 : 16 : poll_threads();
2455 : 16 : CU_ASSERT(g_bserrno == 0);
2456 : 16 : CU_ASSERT(g_blobid != SPDK_BLOBID_INVALID);
2457 : 16 : snapshotid = g_blobid;
2458 : :
2459 : 16 : spdk_bs_open_blob(bs, snapshotid, blob_op_with_handle_complete, NULL);
2460 : 16 : poll_threads();
2461 : 16 : CU_ASSERT(g_bserrno == 0);
2462 [ - + ]: 16 : SPDK_CU_ASSERT_FATAL(g_blob != NULL);
2463 : 16 : snapshot = g_blob;
2464 : :
2465 : : /* Set SNAPSHOT_PENDING_REMOVAL xattr */
2466 : 16 : snapshot->md_ro = false;
2467 : 16 : rc = blob_set_xattr(snapshot, SNAPSHOT_PENDING_REMOVAL, &blobid, sizeof(spdk_blob_id), true);
2468 : 16 : CU_ASSERT(rc == 0);
2469 : 16 : snapshot->md_ro = true;
2470 : :
2471 : 16 : spdk_blob_close(snapshot, blob_op_complete, NULL);
2472 : 16 : poll_threads();
2473 : 16 : CU_ASSERT(g_bserrno == 0);
2474 : :
2475 : 16 : spdk_blob_close(blob, blob_op_complete, NULL);
2476 : 16 : poll_threads();
2477 : 16 : CU_ASSERT(g_bserrno == 0);
2478 : :
2479 : : /* Reload blobstore */
2480 : 16 : ut_bs_reload(&bs, NULL);
2481 : :
2482 : : /* Snapshot should not be removed as blob is still pointing to it */
2483 : 16 : spdk_bs_open_blob(bs, snapshotid, blob_op_with_handle_complete, NULL);
2484 : 16 : poll_threads();
2485 : 16 : CU_ASSERT(g_bserrno == 0);
2486 [ - + ]: 16 : SPDK_CU_ASSERT_FATAL(g_blob != NULL);
2487 : 16 : snapshot = g_blob;
2488 : :
2489 : : /* SNAPSHOT_PENDING_REMOVAL xattr should be removed during load */
2490 : 16 : rc = spdk_blob_get_xattr_value(snapshot, SNAPSHOT_PENDING_REMOVAL, &value, &value_len);
2491 : 16 : CU_ASSERT(rc != 0);
2492 : :
2493 : : /* Set SNAPSHOT_PENDING_REMOVAL xattr again */
2494 : 16 : snapshot->md_ro = false;
2495 : 16 : rc = blob_set_xattr(snapshot, SNAPSHOT_PENDING_REMOVAL, &blobid, sizeof(spdk_blob_id), true);
2496 : 16 : CU_ASSERT(rc == 0);
2497 : 16 : snapshot->md_ro = true;
2498 : :
2499 : 16 : spdk_bs_open_blob(bs, blobid, blob_op_with_handle_complete, NULL);
2500 : 16 : poll_threads();
2501 : 16 : CU_ASSERT(g_bserrno == 0);
2502 [ - + ]: 16 : SPDK_CU_ASSERT_FATAL(g_blob != NULL);
2503 : 16 : blob = g_blob;
2504 : :
2505 : : /* Remove parent_id from blob by removing BLOB_SNAPSHOT xattr */
2506 : 16 : blob_remove_xattr(blob, BLOB_SNAPSHOT, true);
2507 : :
2508 : 16 : spdk_blob_sync_md(blob, blob_op_complete, NULL);
2509 : 16 : poll_threads();
2510 : 16 : CU_ASSERT(g_bserrno == 0);
2511 : :
2512 : 16 : spdk_blob_close(snapshot, blob_op_complete, NULL);
2513 : 16 : poll_threads();
2514 : 16 : CU_ASSERT(g_bserrno == 0);
2515 : :
2516 : 16 : spdk_blob_close(blob, blob_op_complete, NULL);
2517 : 16 : poll_threads();
2518 : 16 : CU_ASSERT(g_bserrno == 0);
2519 : :
2520 : : /* Reload blobstore */
2521 : 16 : ut_bs_reload(&bs, NULL);
2522 : :
2523 : : /* Snapshot should be removed as blob is not pointing to it anymore */
2524 : 16 : spdk_bs_open_blob(bs, snapshotid, blob_op_with_handle_complete, NULL);
2525 : 16 : poll_threads();
2526 : 16 : CU_ASSERT(g_bserrno != 0);
2527 : 16 : }
2528 : :
2529 : : static void
2530 : 16 : bs_load_custom_cluster_size(void)
2531 : : {
2532 : : struct spdk_blob_store *bs;
2533 : : struct spdk_bs_dev *dev;
2534 : : struct spdk_bs_super_block *super_block;
2535 : 16 : struct spdk_bs_opts opts;
2536 : 16 : uint32_t custom_cluster_size = 4194304; /* 4MiB */
2537 : : uint32_t cluster_sz;
2538 : : uint64_t total_clusters;
2539 : :
2540 : 16 : dev = init_dev();
2541 : 16 : spdk_bs_opts_init(&opts, sizeof(opts));
2542 : 16 : opts.cluster_sz = custom_cluster_size;
2543 : 16 : snprintf(opts.bstype.bstype, sizeof(opts.bstype.bstype), "TESTTYPE");
2544 : :
2545 : : /* Initialize a new blob store */
2546 : 16 : spdk_bs_init(dev, &opts, bs_op_with_handle_complete, NULL);
2547 : 16 : poll_threads();
2548 : 16 : CU_ASSERT(g_bserrno == 0);
2549 [ - + ]: 16 : SPDK_CU_ASSERT_FATAL(g_bs != NULL);
2550 : 16 : bs = g_bs;
2551 : 16 : cluster_sz = bs->cluster_sz;
2552 : 16 : total_clusters = bs->total_clusters;
2553 : :
2554 : : /* Unload the blob store */
2555 : 16 : spdk_bs_unload(bs, bs_op_complete, NULL);
2556 : 16 : poll_threads();
2557 : 16 : CU_ASSERT(g_bserrno == 0);
2558 : 16 : g_bs = NULL;
2559 : 16 : g_blob = NULL;
2560 : 16 : g_blobid = 0;
2561 : :
2562 : 16 : super_block = (struct spdk_bs_super_block *)g_dev_buffer;
2563 : 16 : CU_ASSERT(super_block->clean == 1);
2564 : :
2565 : : /* Load an existing blob store */
2566 : 16 : dev = init_dev();
2567 : 16 : spdk_bs_opts_init(&opts, sizeof(opts));
2568 : 16 : snprintf(opts.bstype.bstype, sizeof(opts.bstype.bstype), "TESTTYPE");
2569 : 16 : spdk_bs_load(dev, &opts, bs_op_with_handle_complete, NULL);
2570 : 16 : poll_threads();
2571 : 16 : CU_ASSERT(g_bserrno == 0);
2572 [ - + ]: 16 : SPDK_CU_ASSERT_FATAL(g_bs != NULL);
2573 : 16 : bs = g_bs;
2574 : : /* Compare cluster size and number to one after initialization */
2575 : 16 : CU_ASSERT(cluster_sz == bs->cluster_sz);
2576 : 16 : CU_ASSERT(total_clusters == bs->total_clusters);
2577 : :
2578 : 16 : super_block = (struct spdk_bs_super_block *)g_dev_buffer;
2579 : 16 : CU_ASSERT(super_block->clean == 1);
2580 : 16 : CU_ASSERT(super_block->size == dev->blockcnt * dev->blocklen);
2581 : :
2582 : 16 : spdk_bs_unload(bs, bs_op_complete, NULL);
2583 : 16 : poll_threads();
2584 : 16 : CU_ASSERT(g_bserrno == 0);
2585 : 16 : CU_ASSERT(super_block->clean == 1);
2586 : 16 : g_bs = NULL;
2587 : 16 : }
2588 : :
2589 : : static void
2590 : 16 : bs_load_after_failed_grow(void)
2591 : : {
2592 : : struct spdk_blob_store *bs;
2593 : : struct spdk_bs_dev *dev;
2594 : : struct spdk_bs_super_block *super_block;
2595 : 16 : struct spdk_bs_opts opts;
2596 : : struct spdk_bs_md_mask *mask;
2597 : 16 : struct spdk_blob_opts blob_opts;
2598 : : struct spdk_blob *blob, *snapshot;
2599 : : spdk_blob_id blobid, snapshotid;
2600 : : uint64_t total_data_clusters;
2601 : :
2602 : 16 : dev = init_dev();
2603 : 16 : spdk_bs_opts_init(&opts, sizeof(opts));
2604 : 16 : snprintf(opts.bstype.bstype, sizeof(opts.bstype.bstype), "TESTTYPE");
2605 : : /*
2606 : : * The bdev_size is 64M, cluster_sz is 1M, so there are 64 clusters. The
2607 : : * blobstore will create 64 md pages by default. We set num_md_pages to 128,
2608 : : * thus the blobstore could grow to the double size.
2609 : : */
2610 : 16 : opts.num_md_pages = 128;
2611 : :
2612 : : /* Initialize a new blob store */
2613 : 16 : spdk_bs_init(dev, &opts, bs_op_with_handle_complete, NULL);
2614 : 16 : poll_threads();
2615 : 16 : CU_ASSERT(g_bserrno == 0);
2616 [ - + ]: 16 : SPDK_CU_ASSERT_FATAL(g_bs != NULL);
2617 : 16 : bs = g_bs;
2618 : :
2619 : : /* Create blob */
2620 : 16 : ut_spdk_blob_opts_init(&blob_opts);
2621 : 16 : blob_opts.num_clusters = 10;
2622 : :
2623 : 16 : blob = ut_blob_create_and_open(bs, &blob_opts);
2624 : 16 : blobid = spdk_blob_get_id(blob);
2625 : :
2626 : : /* Create snapshot */
2627 : 16 : spdk_bs_create_snapshot(bs, blobid, NULL, blob_op_with_id_complete, NULL);
2628 : 16 : poll_threads();
2629 : 16 : CU_ASSERT(g_bserrno == 0);
2630 : 16 : CU_ASSERT(g_blobid != SPDK_BLOBID_INVALID);
2631 : 16 : snapshotid = g_blobid;
2632 : :
2633 : 16 : spdk_bs_open_blob(bs, snapshotid, blob_op_with_handle_complete, NULL);
2634 : 16 : poll_threads();
2635 : 16 : CU_ASSERT(g_bserrno == 0);
2636 [ - + ]: 16 : SPDK_CU_ASSERT_FATAL(g_blob != NULL);
2637 : 16 : snapshot = g_blob;
2638 : :
2639 : 16 : spdk_blob_close(snapshot, blob_op_complete, NULL);
2640 : 16 : poll_threads();
2641 : 16 : CU_ASSERT(g_bserrno == 0);
2642 : :
2643 : 16 : spdk_blob_close(blob, blob_op_complete, NULL);
2644 : 16 : poll_threads();
2645 : 16 : CU_ASSERT(g_bserrno == 0);
2646 : :
2647 : 16 : total_data_clusters = bs->total_data_clusters;
2648 : 16 : CU_ASSERT(bs->num_free_clusters + 10 == total_data_clusters);
2649 : :
2650 : : /* Unload the blob store */
2651 : 16 : spdk_bs_unload(bs, bs_op_complete, NULL);
2652 : 16 : poll_threads();
2653 : 16 : CU_ASSERT(g_bserrno == 0);
2654 : 16 : g_bs = NULL;
2655 : 16 : g_blob = NULL;
2656 : 16 : g_blobid = 0;
2657 : :
2658 : 16 : super_block = (struct spdk_bs_super_block *)g_dev_buffer;
2659 : 16 : CU_ASSERT(super_block->clean == 1);
2660 : :
2661 : 16 : mask = (struct spdk_bs_md_mask *)(g_dev_buffer + super_block->used_cluster_mask_start * 4096);
2662 : 16 : CU_ASSERT(mask->type == SPDK_MD_MASK_TYPE_USED_CLUSTERS);
2663 [ - + ]: 16 : CU_ASSERT(mask->length == super_block->size / super_block->cluster_size);
2664 : :
2665 : : /*
2666 : : * We change the mask->length to emulate this scenario: A spdk_bs_grow failed after it changed
2667 : : * the used_cluster bitmap length, but it didn't change the super block yet.
2668 : : */
2669 : 16 : mask->length *= 2;
2670 : :
2671 : : /* Load an existing blob store */
2672 : 16 : dev = init_dev();
2673 : 16 : dev->blockcnt *= 2;
2674 : 16 : spdk_bs_opts_init(&opts, sizeof(opts));
2675 : 16 : opts.clear_method = BS_CLEAR_WITH_NONE;
2676 : 16 : snprintf(opts.bstype.bstype, sizeof(opts.bstype.bstype), "TESTTYPE");
2677 : 16 : spdk_bs_load(dev, &opts, bs_op_with_handle_complete, NULL);
2678 : 16 : poll_threads();
2679 : 16 : CU_ASSERT(g_bserrno == 0);
2680 [ - + ]: 16 : SPDK_CU_ASSERT_FATAL(g_bs != NULL);
2681 : 16 : bs = g_bs;
2682 : :
2683 : : /* Check the capacity is the same as before */
2684 : 16 : CU_ASSERT(bs->total_data_clusters == total_data_clusters);
2685 : 16 : CU_ASSERT(bs->num_free_clusters + 10 == total_data_clusters);
2686 : :
2687 : : /* Check the blob and the snapshot are still available */
2688 : 16 : spdk_bs_open_blob(bs, blobid, blob_op_with_handle_complete, NULL);
2689 : 16 : poll_threads();
2690 : 16 : CU_ASSERT(g_bserrno == 0);
2691 [ - + ]: 16 : SPDK_CU_ASSERT_FATAL(g_blob != NULL);
2692 : 16 : blob = g_blob;
2693 : :
2694 : 16 : spdk_blob_close(blob, blob_op_complete, NULL);
2695 : 16 : poll_threads();
2696 : 16 : CU_ASSERT(g_bserrno == 0);
2697 : :
2698 : 16 : spdk_bs_open_blob(bs, snapshotid, blob_op_with_handle_complete, NULL);
2699 : 16 : poll_threads();
2700 : 16 : CU_ASSERT(g_bserrno == 0);
2701 [ - + ]: 16 : SPDK_CU_ASSERT_FATAL(g_blob != NULL);
2702 : 16 : snapshot = g_blob;
2703 : :
2704 : 16 : spdk_blob_close(snapshot, blob_op_complete, NULL);
2705 : 16 : poll_threads();
2706 : 16 : CU_ASSERT(g_bserrno == 0);
2707 : :
2708 : 16 : spdk_bs_unload(bs, bs_op_complete, NULL);
2709 : 16 : poll_threads();
2710 : 16 : CU_ASSERT(g_bserrno == 0);
2711 : 16 : CU_ASSERT(super_block->clean == 1);
2712 : 16 : g_bs = NULL;
2713 : 16 : }
2714 : :
2715 : : static void
2716 : 16 : bs_type(void)
2717 : : {
2718 : : struct spdk_blob_store *bs;
2719 : : struct spdk_bs_dev *dev;
2720 : 16 : struct spdk_bs_opts opts;
2721 : :
2722 : 16 : dev = init_dev();
2723 : 16 : spdk_bs_opts_init(&opts, sizeof(opts));
2724 : 16 : snprintf(opts.bstype.bstype, sizeof(opts.bstype.bstype), "TESTTYPE");
2725 : :
2726 : : /* Initialize a new blob store */
2727 : 16 : spdk_bs_init(dev, &opts, bs_op_with_handle_complete, NULL);
2728 : 16 : poll_threads();
2729 : 16 : CU_ASSERT(g_bserrno == 0);
2730 [ - + ]: 16 : SPDK_CU_ASSERT_FATAL(g_bs != NULL);
2731 : 16 : bs = g_bs;
2732 : :
2733 : : /* Unload the blob store */
2734 : 16 : spdk_bs_unload(bs, bs_op_complete, NULL);
2735 : 16 : poll_threads();
2736 : 16 : CU_ASSERT(g_bserrno == 0);
2737 : 16 : g_bs = NULL;
2738 : 16 : g_blob = NULL;
2739 : 16 : g_blobid = 0;
2740 : :
2741 : : /* Load non existing blobstore type */
2742 : 16 : dev = init_dev();
2743 : 16 : snprintf(opts.bstype.bstype, sizeof(opts.bstype.bstype), "NONEXISTING");
2744 : 16 : spdk_bs_load(dev, &opts, bs_op_with_handle_complete, NULL);
2745 : 16 : poll_threads();
2746 : 16 : CU_ASSERT(g_bserrno != 0);
2747 : :
2748 : : /* Load with empty blobstore type */
2749 : 16 : dev = init_dev();
2750 : 16 : memset(opts.bstype.bstype, 0, sizeof(opts.bstype.bstype));
2751 : 16 : spdk_bs_load(dev, &opts, bs_op_with_handle_complete, NULL);
2752 : 16 : poll_threads();
2753 : 16 : CU_ASSERT(g_bserrno == 0);
2754 [ - + ]: 16 : SPDK_CU_ASSERT_FATAL(g_bs != NULL);
2755 : 16 : bs = g_bs;
2756 : :
2757 : 16 : spdk_bs_unload(bs, bs_op_complete, NULL);
2758 : 16 : poll_threads();
2759 : 16 : CU_ASSERT(g_bserrno == 0);
2760 : 16 : g_bs = NULL;
2761 : :
2762 : : /* Initialize a new blob store with empty bstype */
2763 : 16 : dev = init_dev();
2764 : 16 : memset(opts.bstype.bstype, 0, sizeof(opts.bstype.bstype));
2765 : 16 : spdk_bs_init(dev, NULL, bs_op_with_handle_complete, NULL);
2766 : 16 : poll_threads();
2767 : 16 : CU_ASSERT(g_bserrno == 0);
2768 [ - + ]: 16 : SPDK_CU_ASSERT_FATAL(g_bs != NULL);
2769 : 16 : bs = g_bs;
2770 : :
2771 : 16 : spdk_bs_unload(bs, bs_op_complete, NULL);
2772 : 16 : poll_threads();
2773 : 16 : CU_ASSERT(g_bserrno == 0);
2774 : 16 : g_bs = NULL;
2775 : :
2776 : : /* Load non existing blobstore type */
2777 : 16 : dev = init_dev();
2778 : 16 : snprintf(opts.bstype.bstype, sizeof(opts.bstype.bstype), "NONEXISTING");
2779 : 16 : spdk_bs_load(dev, &opts, bs_op_with_handle_complete, NULL);
2780 : 16 : poll_threads();
2781 : 16 : CU_ASSERT(g_bserrno != 0);
2782 : :
2783 : : /* Load with empty blobstore type */
2784 : 16 : dev = init_dev();
2785 : 16 : memset(opts.bstype.bstype, 0, sizeof(opts.bstype.bstype));
2786 : 16 : spdk_bs_load(dev, &opts, bs_op_with_handle_complete, NULL);
2787 : 16 : poll_threads();
2788 : 16 : CU_ASSERT(g_bserrno == 0);
2789 [ - + ]: 16 : SPDK_CU_ASSERT_FATAL(g_bs != NULL);
2790 : 16 : bs = g_bs;
2791 : :
2792 : 16 : spdk_bs_unload(bs, bs_op_complete, NULL);
2793 : 16 : poll_threads();
2794 : 16 : CU_ASSERT(g_bserrno == 0);
2795 : 16 : g_bs = NULL;
2796 : 16 : }
2797 : :
2798 : : static void
2799 : 16 : bs_super_block(void)
2800 : : {
2801 : : struct spdk_blob_store *bs;
2802 : : struct spdk_bs_dev *dev;
2803 : : struct spdk_bs_super_block *super_block;
2804 : 16 : struct spdk_bs_opts opts;
2805 : 16 : struct spdk_bs_super_block_ver1 super_block_v1;
2806 : :
2807 : 16 : dev = init_dev();
2808 : 16 : spdk_bs_opts_init(&opts, sizeof(opts));
2809 : 16 : snprintf(opts.bstype.bstype, sizeof(opts.bstype.bstype), "TESTTYPE");
2810 : :
2811 : : /* Initialize a new blob store */
2812 : 16 : spdk_bs_init(dev, &opts, bs_op_with_handle_complete, NULL);
2813 : 16 : poll_threads();
2814 : 16 : CU_ASSERT(g_bserrno == 0);
2815 [ - + ]: 16 : SPDK_CU_ASSERT_FATAL(g_bs != NULL);
2816 : 16 : bs = g_bs;
2817 : :
2818 : : /* Unload the blob store */
2819 : 16 : spdk_bs_unload(bs, bs_op_complete, NULL);
2820 : 16 : poll_threads();
2821 : 16 : CU_ASSERT(g_bserrno == 0);
2822 : 16 : g_bs = NULL;
2823 : 16 : g_blob = NULL;
2824 : 16 : g_blobid = 0;
2825 : :
2826 : : /* Load an existing blob store with version newer than supported */
2827 : 16 : super_block = (struct spdk_bs_super_block *)g_dev_buffer;
2828 : 16 : super_block->version++;
2829 : :
2830 : 16 : dev = init_dev();
2831 : 16 : memset(opts.bstype.bstype, 0, sizeof(opts.bstype.bstype));
2832 : 16 : spdk_bs_load(dev, &opts, bs_op_with_handle_complete, NULL);
2833 : 16 : poll_threads();
2834 : 16 : CU_ASSERT(g_bserrno != 0);
2835 : :
2836 : : /* Create a new blob store with super block version 1 */
2837 : 16 : dev = init_dev();
2838 : 16 : super_block_v1.version = 1;
2839 : 16 : memcpy(super_block_v1.signature, "SPDKBLOB", sizeof(super_block_v1.signature));
2840 : 16 : super_block_v1.length = 0x1000;
2841 : 16 : super_block_v1.clean = 1;
2842 : 16 : super_block_v1.super_blob = 0xFFFFFFFFFFFFFFFF;
2843 : 16 : super_block_v1.cluster_size = 0x100000;
2844 : 16 : super_block_v1.used_page_mask_start = 0x01;
2845 : 16 : super_block_v1.used_page_mask_len = 0x01;
2846 : 16 : super_block_v1.used_cluster_mask_start = 0x02;
2847 : 16 : super_block_v1.used_cluster_mask_len = 0x01;
2848 : 16 : super_block_v1.md_start = 0x03;
2849 : 16 : super_block_v1.md_len = 0x40;
2850 : 16 : memset(super_block_v1.reserved, 0, 4036);
2851 : 16 : super_block_v1.crc = blob_md_page_calc_crc(&super_block_v1);
2852 : 16 : memcpy(g_dev_buffer, &super_block_v1, sizeof(struct spdk_bs_super_block_ver1));
2853 : :
2854 : 16 : memset(opts.bstype.bstype, 0, sizeof(opts.bstype.bstype));
2855 : 16 : spdk_bs_load(dev, &opts, bs_op_with_handle_complete, NULL);
2856 : 16 : poll_threads();
2857 : 16 : CU_ASSERT(g_bserrno == 0);
2858 [ - + ]: 16 : SPDK_CU_ASSERT_FATAL(g_bs != NULL);
2859 : 16 : bs = g_bs;
2860 : :
2861 : 16 : spdk_bs_unload(bs, bs_op_complete, NULL);
2862 : 16 : poll_threads();
2863 : 16 : CU_ASSERT(g_bserrno == 0);
2864 : 16 : g_bs = NULL;
2865 : 16 : }
2866 : :
2867 : : static void
2868 : 16 : bs_test_recover_cluster_count(void)
2869 : : {
2870 : : struct spdk_blob_store *bs;
2871 : : struct spdk_bs_dev *dev;
2872 : 16 : struct spdk_bs_super_block super_block;
2873 : 16 : struct spdk_bs_opts opts;
2874 : :
2875 : 16 : dev = init_dev();
2876 : 16 : spdk_bs_opts_init(&opts, sizeof(opts));
2877 : 16 : snprintf(opts.bstype.bstype, sizeof(opts.bstype.bstype), "TESTTYPE");
2878 : :
2879 : 16 : super_block.version = 3;
2880 : 16 : memcpy(super_block.signature, "SPDKBLOB", sizeof(super_block.signature));
2881 : 16 : super_block.length = 0x1000;
2882 : 16 : super_block.clean = 0;
2883 : 16 : super_block.super_blob = 0xFFFFFFFFFFFFFFFF;
2884 : 16 : super_block.cluster_size = 4096;
2885 : 16 : super_block.used_page_mask_start = 0x01;
2886 : 16 : super_block.used_page_mask_len = 0x01;
2887 : 16 : super_block.used_cluster_mask_start = 0x02;
2888 : 16 : super_block.used_cluster_mask_len = 0x01;
2889 : 16 : super_block.used_blobid_mask_start = 0x03;
2890 : 16 : super_block.used_blobid_mask_len = 0x01;
2891 : 16 : super_block.md_start = 0x04;
2892 : 16 : super_block.md_len = 0x40;
2893 : 16 : memset(super_block.bstype.bstype, 0, sizeof(super_block.bstype.bstype));
2894 : 16 : super_block.size = dev->blockcnt * dev->blocklen;
2895 : 16 : super_block.io_unit_size = 0x1000;
2896 : 16 : memset(super_block.reserved, 0, 4000);
2897 : 16 : super_block.crc = blob_md_page_calc_crc(&super_block);
2898 : 16 : memcpy(g_dev_buffer, &super_block, sizeof(struct spdk_bs_super_block));
2899 : :
2900 : 16 : memset(opts.bstype.bstype, 0, sizeof(opts.bstype.bstype));
2901 : 16 : spdk_bs_load(dev, &opts, bs_op_with_handle_complete, NULL);
2902 : 16 : poll_threads();
2903 : 16 : CU_ASSERT(g_bserrno == 0);
2904 [ - + ]: 16 : SPDK_CU_ASSERT_FATAL(g_bs != NULL);
2905 : 16 : bs = g_bs;
2906 : 16 : CU_ASSERT(bs->num_free_clusters == bs->total_clusters - (super_block.md_start +
2907 : : super_block.md_len));
2908 : :
2909 : 16 : spdk_bs_unload(bs, bs_op_complete, NULL);
2910 : 16 : poll_threads();
2911 : 16 : CU_ASSERT(g_bserrno == 0);
2912 : 16 : g_bs = NULL;
2913 : 16 : }
2914 : :
2915 : : static void
2916 : 48 : bs_grow_live_size(uint64_t new_blockcnt)
2917 : : {
2918 : : struct spdk_blob_store *bs;
2919 : : struct spdk_bs_dev *dev;
2920 : 48 : struct spdk_bs_super_block super_block;
2921 : 48 : struct spdk_bs_opts opts;
2922 : 48 : struct spdk_bs_md_mask mask;
2923 : : uint64_t bdev_size;
2924 : : uint64_t total_data_clusters;
2925 : :
2926 : : /*
2927 : : * Further down the test the dev size will be larger than the g_dev_buffer size,
2928 : : * so we set clear_method to NONE, or the blobstore will try to clear the dev and
2929 : : * will write beyond the end of g_dev_buffer.
2930 : : */
2931 : 48 : dev = init_dev();
2932 : 48 : spdk_bs_opts_init(&opts, sizeof(opts));
2933 : 48 : opts.clear_method = BS_CLEAR_WITH_NONE;
2934 : 48 : spdk_bs_init(dev, &opts, bs_op_with_handle_complete, NULL);
2935 : 48 : poll_threads();
2936 : 48 : CU_ASSERT(g_bserrno == 0);
2937 [ - + ]: 48 : SPDK_CU_ASSERT_FATAL(g_bs != NULL);
2938 : 48 : bs = g_bs;
2939 : 48 : CU_ASSERT(spdk_bs_total_data_cluster_count(bs) == 63);
2940 : :
2941 : : /*
2942 : : * Set the dev size according to the new_blockcnt,
2943 : : * then the blobstore will adjust the metadata according to the new size.
2944 : : */
2945 : 48 : dev->blockcnt = new_blockcnt;
2946 : 48 : bdev_size = dev->blockcnt * dev->blocklen;
2947 : 48 : spdk_bs_grow_live(bs, bs_op_complete, NULL);
2948 : 48 : poll_threads();
2949 : 48 : CU_ASSERT(g_bserrno == 0);
2950 : 48 : total_data_clusters = spdk_bs_total_data_cluster_count(bs);
2951 : : /* One cluster of 1MiB size is used for metadata */
2952 : 48 : CU_ASSERT(total_data_clusters == (bdev_size / (1 * 1024 * 1024)) - 1);
2953 : :
2954 : : /* Make sure the super block is updated. */
2955 : 48 : memcpy(&super_block, g_dev_buffer, sizeof(struct spdk_bs_super_block));
2956 : 48 : CU_ASSERT(super_block.size == bdev_size);
2957 : 48 : CU_ASSERT(super_block.clean == 0);
2958 : : /* The used_cluster mask is not written out until first spdk_bs_unload. */
2959 : 48 : memcpy(&mask, g_dev_buffer + super_block.used_cluster_mask_start * 4096,
2960 : : sizeof(struct spdk_bs_md_mask));
2961 : 48 : CU_ASSERT(mask.type == 0);
2962 : 48 : CU_ASSERT(mask.length == 0);
2963 : :
2964 : 48 : spdk_bs_unload(bs, bs_op_complete, NULL);
2965 : 48 : poll_threads();
2966 : 48 : CU_ASSERT(g_bserrno == 0);
2967 : 48 : g_bs = NULL;
2968 : :
2969 : : /* Make sure all metadata is correct, super block and used_cluster mask. */
2970 : 48 : memcpy(&super_block, g_dev_buffer, sizeof(struct spdk_bs_super_block));
2971 : 48 : CU_ASSERT(super_block.size == bdev_size);
2972 : 48 : CU_ASSERT(super_block.clean == 1);
2973 : 48 : memcpy(&mask, g_dev_buffer + super_block.used_cluster_mask_start * 4096,
2974 : : sizeof(struct spdk_bs_md_mask));
2975 : 48 : CU_ASSERT(mask.type == SPDK_MD_MASK_TYPE_USED_CLUSTERS);
2976 : 48 : CU_ASSERT(mask.length == bdev_size / (1 * 1024 * 1024));
2977 : :
2978 : : /* Load blobstore and check the cluster counts again. */
2979 : 48 : dev = init_dev();
2980 : 48 : dev->blockcnt = new_blockcnt;
2981 : 48 : spdk_bs_load(dev, NULL, bs_op_with_handle_complete, NULL);
2982 : 48 : poll_threads();
2983 : 48 : CU_ASSERT(g_bserrno == 0);
2984 [ - + ]: 48 : SPDK_CU_ASSERT_FATAL(g_bs != NULL);
2985 : 48 : CU_ASSERT(super_block.clean == 1);
2986 : 48 : bs = g_bs;
2987 : 48 : CU_ASSERT(total_data_clusters == spdk_bs_total_data_cluster_count(bs));
2988 : :
2989 : : /* Perform grow without change in size, expected pass. */
2990 : 48 : spdk_bs_grow_live(bs, bs_op_complete, NULL);
2991 : 48 : poll_threads();
2992 : 48 : CU_ASSERT(g_bserrno == 0);
2993 : 48 : CU_ASSERT(total_data_clusters == spdk_bs_total_data_cluster_count(bs));
2994 : 48 : memcpy(&super_block, g_dev_buffer, sizeof(struct spdk_bs_super_block));
2995 : 48 : CU_ASSERT(super_block.size == bdev_size);
2996 : 48 : CU_ASSERT(super_block.clean == 1);
2997 : :
2998 : 48 : spdk_bs_unload(bs, bs_op_complete, NULL);
2999 : 48 : poll_threads();
3000 : 48 : CU_ASSERT(g_bserrno == 0);
3001 : 48 : g_bs = NULL;
3002 : 48 : }
3003 : :
3004 : : static void
3005 : 16 : bs_grow_live(void)
3006 : : {
3007 : : /* No change expected */
3008 : 16 : bs_grow_live_size(DEV_BUFFER_BLOCKCNT);
3009 : :
3010 : : /* Size slightly increased, but not enough to increase cluster count */
3011 : 16 : bs_grow_live_size(DEV_BUFFER_BLOCKCNT + 1);
3012 : :
3013 : : /* Size doubled, increasing the cluster count */
3014 : 16 : bs_grow_live_size(DEV_BUFFER_BLOCKCNT * 2);
3015 : 16 : }
3016 : :
3017 : : static void
3018 : 16 : bs_grow_live_no_space(void)
3019 : : {
3020 : : struct spdk_blob_store *bs;
3021 : : struct spdk_bs_dev *dev;
3022 : 16 : struct spdk_bs_super_block super_block;
3023 : 16 : struct spdk_bs_opts opts;
3024 : 16 : struct spdk_bs_md_mask mask;
3025 : : uint64_t bdev_size_init;
3026 : : uint64_t total_data_clusters, max_clusters;
3027 : :
3028 : : /*
3029 : : * Further down the test the dev size will be larger than the g_dev_buffer size,
3030 : : * so we set clear_method to NONE, or the blobstore will try to clear the dev and
3031 : : * will write beyond the end of g_dev_buffer.
3032 : : */
3033 : 16 : dev = init_dev();
3034 : 16 : bdev_size_init = dev->blockcnt * dev->blocklen;
3035 : 16 : spdk_bs_opts_init(&opts, sizeof(opts));
3036 : 16 : opts.clear_method = BS_CLEAR_WITH_NONE;
3037 : 16 : spdk_bs_init(dev, &opts, bs_op_with_handle_complete, NULL);
3038 : 16 : poll_threads();
3039 : 16 : CU_ASSERT(g_bserrno == 0);
3040 [ - + ]: 16 : SPDK_CU_ASSERT_FATAL(g_bs != NULL);
3041 : 16 : bs = g_bs;
3042 : 16 : total_data_clusters = spdk_bs_total_data_cluster_count(bs);
3043 : 16 : CU_ASSERT(total_data_clusters == 63);
3044 : :
3045 : : /*
3046 : : * The default dev size is 64M, here we set the dev size to 32M,
3047 : : * expecting EILSEQ due to super_block validation and no change in blobstore.
3048 : : */
3049 [ - + ]: 16 : dev->blockcnt = (32L * 1024L * 1024L) / dev->blocklen;
3050 : 16 : spdk_bs_grow_live(bs, bs_op_complete, NULL);
3051 : 16 : poll_threads();
3052 : : /* This error code comes from bs_super_validate() */
3053 : 16 : CU_ASSERT(g_bserrno == -EILSEQ);
3054 : 16 : CU_ASSERT(total_data_clusters == spdk_bs_total_data_cluster_count(bs));
3055 : 16 : memcpy(&super_block, g_dev_buffer, sizeof(struct spdk_bs_super_block));
3056 : 16 : CU_ASSERT(super_block.size == bdev_size_init);
3057 : :
3058 : : /*
3059 : : * Blobstore in this test has only space for single md_page for used_clusters,
3060 : : * which fits 1 bit per cluster minus the md header.
3061 : : *
3062 : : * Dev size is increased to exceed the reserved space for the used_cluster_mask
3063 : : * in the metadata, expecting ENOSPC and no change in blobstore.
3064 : : */
3065 : 16 : max_clusters = (spdk_bs_get_page_size(bs) - sizeof(struct spdk_bs_md_mask)) * 8;
3066 : 16 : max_clusters += 1;
3067 [ - + ]: 16 : dev->blockcnt = (max_clusters * spdk_bs_get_cluster_size(bs)) / dev->blocklen;
3068 : 16 : spdk_bs_grow_live(bs, bs_op_complete, NULL);
3069 : 16 : poll_threads();
3070 : 16 : CU_ASSERT(g_bserrno == -ENOSPC);
3071 : 16 : CU_ASSERT(total_data_clusters == spdk_bs_total_data_cluster_count(bs));
3072 : 16 : memcpy(&super_block, g_dev_buffer, sizeof(struct spdk_bs_super_block));
3073 : 16 : CU_ASSERT(super_block.size == bdev_size_init);
3074 : :
3075 : : /*
3076 : : * No change should have occurred for the duration of the test,
3077 : : * unload blobstore and check metadata.
3078 : : */
3079 : 16 : spdk_bs_unload(bs, bs_op_complete, NULL);
3080 : 16 : poll_threads();
3081 : 16 : CU_ASSERT(g_bserrno == 0);
3082 : 16 : g_bs = NULL;
3083 : :
3084 : : /* Make sure all metadata is correct, super block and used_cluster mask. */
3085 : 16 : memcpy(&super_block, g_dev_buffer, sizeof(struct spdk_bs_super_block));
3086 : 16 : CU_ASSERT(super_block.size == bdev_size_init);
3087 : 16 : CU_ASSERT(super_block.clean == 1);
3088 : 16 : memcpy(&mask, g_dev_buffer + super_block.used_cluster_mask_start * 4096,
3089 : : sizeof(struct spdk_bs_md_mask));
3090 : 16 : CU_ASSERT(mask.type == SPDK_MD_MASK_TYPE_USED_CLUSTERS);
3091 : 16 : CU_ASSERT(mask.length == bdev_size_init / (1 * 1024 * 1024));
3092 : :
3093 : : /* Load blobstore and check the cluster counts again. */
3094 : 16 : dev = init_dev();
3095 : 16 : spdk_bs_load(dev, NULL, bs_op_with_handle_complete, NULL);
3096 : 16 : poll_threads();
3097 : 16 : CU_ASSERT(g_bserrno == 0);
3098 [ - + ]: 16 : SPDK_CU_ASSERT_FATAL(g_bs != NULL);
3099 : 16 : bs = g_bs;
3100 : 16 : CU_ASSERT(total_data_clusters == spdk_bs_total_data_cluster_count(bs));
3101 : :
3102 : 16 : spdk_bs_unload(bs, bs_op_complete, NULL);
3103 : 16 : poll_threads();
3104 : 16 : CU_ASSERT(g_bserrno == 0);
3105 : 16 : g_bs = NULL;
3106 : 16 : }
3107 : :
3108 : : static void
3109 : 16 : bs_test_grow(void)
3110 : : {
3111 : : struct spdk_blob_store *bs;
3112 : : struct spdk_bs_dev *dev;
3113 : 16 : struct spdk_bs_super_block super_block;
3114 : 16 : struct spdk_bs_opts opts;
3115 : 16 : struct spdk_bs_md_mask mask;
3116 : : uint64_t bdev_size;
3117 : :
3118 : 16 : dev = init_dev();
3119 : 16 : bdev_size = dev->blockcnt * dev->blocklen;
3120 : 16 : spdk_bs_opts_init(&opts, sizeof(opts));
3121 : 16 : spdk_bs_init(dev, &opts, bs_op_with_handle_complete, NULL);
3122 : 16 : poll_threads();
3123 : 16 : CU_ASSERT(g_bserrno == 0);
3124 [ - + ]: 16 : SPDK_CU_ASSERT_FATAL(g_bs != NULL);
3125 : 16 : bs = g_bs;
3126 : :
3127 : 16 : spdk_bs_unload(bs, bs_op_complete, NULL);
3128 : 16 : poll_threads();
3129 : 16 : CU_ASSERT(g_bserrno == 0);
3130 : 16 : g_bs = NULL;
3131 : :
3132 : : /*
3133 : : * To make sure all the metadata are updated to the disk,
3134 : : * we check the g_dev_buffer after spdk_bs_unload.
3135 : : */
3136 : 16 : memcpy(&super_block, g_dev_buffer, sizeof(struct spdk_bs_super_block));
3137 : 16 : CU_ASSERT(super_block.size == bdev_size);
3138 : :
3139 : : /*
3140 : : * Make sure the used_cluster mask is correct.
3141 : : */
3142 : 16 : memcpy(&mask, g_dev_buffer + super_block.used_cluster_mask_start * 4096,
3143 : : sizeof(struct spdk_bs_md_mask));
3144 : 16 : CU_ASSERT(mask.type == SPDK_MD_MASK_TYPE_USED_CLUSTERS);
3145 : 16 : CU_ASSERT(mask.length == bdev_size / (1 * 1024 * 1024));
3146 : :
3147 : : /*
3148 : : * The default dev size is 64M, here we set the dev size to 128M,
3149 : : * then the blobstore will adjust the metadata according to the new size.
3150 : : * The dev size is larger than the g_dev_buffer size, so we set clear_method
3151 : : * to NONE, or the blobstore will try to clear the dev and will write beyond
3152 : : * the end of g_dev_buffer.
3153 : : */
3154 : 16 : dev = init_dev();
3155 [ - + ]: 16 : dev->blockcnt = (128L * 1024L * 1024L) / dev->blocklen;
3156 : 16 : bdev_size = dev->blockcnt * dev->blocklen;
3157 : 16 : spdk_bs_opts_init(&opts, sizeof(opts));
3158 : 16 : opts.clear_method = BS_CLEAR_WITH_NONE;
3159 : 16 : spdk_bs_grow(dev, &opts, bs_op_with_handle_complete, NULL);
3160 : 16 : poll_threads();
3161 : 16 : CU_ASSERT(g_bserrno == 0);
3162 [ - + ]: 16 : SPDK_CU_ASSERT_FATAL(g_bs != NULL);
3163 : 16 : bs = g_bs;
3164 : :
3165 : : /*
3166 : : * After spdk_bs_grow, all metadata are updated to the disk.
3167 : : * So we can check g_dev_buffer now.
3168 : : */
3169 : 16 : memcpy(&super_block, g_dev_buffer, sizeof(struct spdk_bs_super_block));
3170 : 16 : CU_ASSERT(super_block.size == bdev_size);
3171 : :
3172 : : /*
3173 : : * Make sure the used_cluster mask has been updated according to the bdev size
3174 : : */
3175 : 16 : memcpy(&mask, g_dev_buffer + super_block.used_cluster_mask_start * 4096,
3176 : : sizeof(struct spdk_bs_md_mask));
3177 : 16 : CU_ASSERT(mask.type == SPDK_MD_MASK_TYPE_USED_CLUSTERS);
3178 : 16 : CU_ASSERT(mask.length == bdev_size / (1 * 1024 * 1024));
3179 : :
3180 : 16 : spdk_bs_unload(bs, bs_op_complete, NULL);
3181 : 16 : poll_threads();
3182 : 16 : CU_ASSERT(g_bserrno == 0);
3183 : 16 : g_bs = NULL;
3184 : 16 : }
3185 : :
3186 : : /*
3187 : : * Create a blobstore and then unload it.
3188 : : */
3189 : : static void
3190 : 16 : bs_unload(void)
3191 : : {
3192 : 16 : struct spdk_blob_store *bs = g_bs;
3193 : : struct spdk_blob *blob;
3194 : :
3195 : : /* Create a blob and open it. */
3196 : 16 : blob = ut_blob_create_and_open(bs, NULL);
3197 : :
3198 : : /* Try to unload blobstore, should fail with open blob */
3199 : 16 : g_bserrno = -1;
3200 : 16 : spdk_bs_unload(bs, bs_op_complete, NULL);
3201 : 16 : poll_threads();
3202 : 16 : CU_ASSERT(g_bserrno == -EBUSY);
3203 [ - + ]: 16 : SPDK_CU_ASSERT_FATAL(g_bs != NULL);
3204 : :
3205 : : /* Close the blob, then successfully unload blobstore */
3206 : 16 : g_bserrno = -1;
3207 : 16 : spdk_blob_close(blob, blob_op_complete, NULL);
3208 : 16 : poll_threads();
3209 : 16 : CU_ASSERT(g_bserrno == 0);
3210 : 16 : }
3211 : :
3212 : : /*
3213 : : * Create a blobstore with a cluster size different than the default, and ensure it is
3214 : : * persisted.
3215 : : */
3216 : : static void
3217 : 16 : bs_cluster_sz(void)
3218 : : {
3219 : 16 : struct spdk_blob_store *bs;
3220 : : struct spdk_bs_dev *dev;
3221 : 16 : struct spdk_bs_opts opts;
3222 : : uint32_t cluster_sz;
3223 : :
3224 : : /* Set cluster size to zero */
3225 : 16 : dev = init_dev();
3226 : 16 : spdk_bs_opts_init(&opts, sizeof(opts));
3227 : 16 : opts.cluster_sz = 0;
3228 : :
3229 : : /* Initialize a new blob store */
3230 : 16 : spdk_bs_init(dev, &opts, bs_op_with_handle_complete, NULL);
3231 : 16 : poll_threads();
3232 : 16 : CU_ASSERT(g_bserrno == -EINVAL);
3233 [ - + ]: 16 : SPDK_CU_ASSERT_FATAL(g_bs == NULL);
3234 : :
3235 : : /*
3236 : : * Set cluster size to blobstore page size,
3237 : : * to work it is required to be at least twice the blobstore page size.
3238 : : */
3239 : 16 : dev = init_dev();
3240 : 16 : spdk_bs_opts_init(&opts, sizeof(opts));
3241 : 16 : opts.cluster_sz = SPDK_BS_PAGE_SIZE;
3242 : :
3243 : : /* Initialize a new blob store */
3244 : 16 : spdk_bs_init(dev, &opts, bs_op_with_handle_complete, NULL);
3245 : 16 : poll_threads();
3246 : 16 : CU_ASSERT(g_bserrno == -ENOMEM);
3247 [ - + ]: 16 : SPDK_CU_ASSERT_FATAL(g_bs == NULL);
3248 : :
3249 : : /*
3250 : : * Set cluster size to lower than page size,
3251 : : * to work it is required to be at least twice the blobstore page size.
3252 : : */
3253 : 16 : dev = init_dev();
3254 : 16 : spdk_bs_opts_init(&opts, sizeof(opts));
3255 : 16 : opts.cluster_sz = SPDK_BS_PAGE_SIZE - 1;
3256 : :
3257 : : /* Initialize a new blob store */
3258 : 16 : spdk_bs_init(dev, &opts, bs_op_with_handle_complete, NULL);
3259 : 16 : poll_threads();
3260 : 16 : CU_ASSERT(g_bserrno == -EINVAL);
3261 [ - + ]: 16 : SPDK_CU_ASSERT_FATAL(g_bs == NULL);
3262 : :
3263 : : /* Set cluster size to twice the default */
3264 : 16 : dev = init_dev();
3265 : 16 : spdk_bs_opts_init(&opts, sizeof(opts));
3266 : 16 : opts.cluster_sz *= 2;
3267 : 16 : cluster_sz = opts.cluster_sz;
3268 : :
3269 : : /* Initialize a new blob store */
3270 : 16 : spdk_bs_init(dev, &opts, bs_op_with_handle_complete, NULL);
3271 : 16 : poll_threads();
3272 : 16 : CU_ASSERT(g_bserrno == 0);
3273 [ - + ]: 16 : SPDK_CU_ASSERT_FATAL(g_bs != NULL);
3274 : 16 : bs = g_bs;
3275 : :
3276 : 16 : CU_ASSERT(spdk_bs_get_cluster_size(bs) == cluster_sz);
3277 : :
3278 : 16 : ut_bs_reload(&bs, &opts);
3279 : :
3280 : 16 : CU_ASSERT(spdk_bs_get_cluster_size(bs) == cluster_sz);
3281 : :
3282 : 16 : spdk_bs_unload(bs, bs_op_complete, NULL);
3283 : 16 : poll_threads();
3284 : 16 : CU_ASSERT(g_bserrno == 0);
3285 : 16 : g_bs = NULL;
3286 : 16 : }
3287 : :
3288 : : /*
3289 : : * Create a blobstore, reload it and ensure total usable cluster count
3290 : : * stays the same.
3291 : : */
3292 : : static void
3293 : 16 : bs_usable_clusters(void)
3294 : : {
3295 : 16 : struct spdk_blob_store *bs = g_bs;
3296 : : struct spdk_blob *blob;
3297 : : uint32_t clusters;
3298 : : int i;
3299 : :
3300 : :
3301 : 16 : clusters = spdk_bs_total_data_cluster_count(bs);
3302 : :
3303 : 16 : ut_bs_reload(&bs, NULL);
3304 : :
3305 : 16 : CU_ASSERT(spdk_bs_total_data_cluster_count(bs) == clusters);
3306 : :
3307 : : /* Create and resize blobs to make sure that useable cluster count won't change */
3308 [ + + ]: 80 : for (i = 0; i < 4; i++) {
3309 : 64 : g_bserrno = -1;
3310 : 64 : g_blobid = SPDK_BLOBID_INVALID;
3311 : 64 : blob = ut_blob_create_and_open(bs, NULL);
3312 : :
3313 : 64 : spdk_blob_resize(blob, 10, blob_op_complete, NULL);
3314 : 64 : poll_threads();
3315 : 64 : CU_ASSERT(g_bserrno == 0);
3316 : :
3317 : 64 : g_bserrno = -1;
3318 : 64 : spdk_blob_close(blob, blob_op_complete, NULL);
3319 : 64 : poll_threads();
3320 : 64 : CU_ASSERT(g_bserrno == 0);
3321 : :
3322 : 64 : CU_ASSERT(spdk_bs_total_data_cluster_count(bs) == clusters);
3323 : : }
3324 : :
3325 : : /* Reload the blob store to make sure that nothing changed */
3326 : 16 : ut_bs_reload(&bs, NULL);
3327 : :
3328 : 16 : CU_ASSERT(spdk_bs_total_data_cluster_count(bs) == clusters);
3329 : 16 : }
3330 : :
3331 : : /*
3332 : : * Test resizing of the metadata blob. This requires creating enough blobs
3333 : : * so that one cluster is not enough to fit the metadata for those blobs.
3334 : : * To induce this condition to happen more quickly, we reduce the cluster
3335 : : * size to 16KB, which means only 4 4KB blob metadata pages can fit.
3336 : : */
3337 : : static void
3338 : 16 : bs_resize_md(void)
3339 : 16 : {
3340 : 16 : struct spdk_blob_store *bs;
3341 : 16 : const int CLUSTER_PAGE_COUNT = 4;
3342 : 16 : const int NUM_BLOBS = CLUSTER_PAGE_COUNT * 4;
3343 : : struct spdk_bs_dev *dev;
3344 : 16 : struct spdk_bs_opts opts;
3345 : : struct spdk_blob *blob;
3346 : 16 : struct spdk_blob_opts blob_opts;
3347 : : uint32_t cluster_sz;
3348 [ - + ]: 16 : spdk_blob_id blobids[NUM_BLOBS];
3349 : : int i;
3350 : :
3351 : :
3352 : 16 : dev = init_dev();
3353 : 16 : spdk_bs_opts_init(&opts, sizeof(opts));
3354 : 16 : opts.cluster_sz = CLUSTER_PAGE_COUNT * 4096;
3355 : 16 : cluster_sz = opts.cluster_sz;
3356 : :
3357 : : /* Initialize a new blob store */
3358 : 16 : spdk_bs_init(dev, &opts, bs_op_with_handle_complete, NULL);
3359 : 16 : poll_threads();
3360 : 16 : CU_ASSERT(g_bserrno == 0);
3361 [ - + ]: 16 : SPDK_CU_ASSERT_FATAL(g_bs != NULL);
3362 : 16 : bs = g_bs;
3363 : :
3364 : 16 : CU_ASSERT(spdk_bs_get_cluster_size(bs) == cluster_sz);
3365 : :
3366 : 16 : ut_spdk_blob_opts_init(&blob_opts);
3367 : :
3368 [ + + ]: 272 : for (i = 0; i < NUM_BLOBS; i++) {
3369 : 256 : g_bserrno = -1;
3370 : 256 : g_blobid = SPDK_BLOBID_INVALID;
3371 : 256 : spdk_bs_create_blob_ext(bs, &blob_opts, blob_op_with_id_complete, NULL);
3372 : 256 : poll_threads();
3373 : 256 : CU_ASSERT(g_bserrno == 0);
3374 : 256 : CU_ASSERT(g_blobid != SPDK_BLOBID_INVALID);
3375 : 256 : blobids[i] = g_blobid;
3376 : : }
3377 : :
3378 : 16 : ut_bs_reload(&bs, &opts);
3379 : :
3380 : 16 : CU_ASSERT(spdk_bs_get_cluster_size(bs) == cluster_sz);
3381 : :
3382 [ + + ]: 272 : for (i = 0; i < NUM_BLOBS; i++) {
3383 : 256 : g_bserrno = -1;
3384 : 256 : g_blob = NULL;
3385 : 256 : spdk_bs_open_blob(bs, blobids[i], blob_op_with_handle_complete, NULL);
3386 : 256 : poll_threads();
3387 : 256 : CU_ASSERT(g_bserrno == 0);
3388 : 256 : CU_ASSERT(g_blob != NULL);
3389 : 256 : blob = g_blob;
3390 : 256 : g_bserrno = -1;
3391 : 256 : spdk_blob_close(blob, blob_op_complete, NULL);
3392 : 256 : poll_threads();
3393 : 256 : CU_ASSERT(g_bserrno == 0);
3394 : : }
3395 : :
3396 : 16 : spdk_bs_unload(bs, bs_op_complete, NULL);
3397 : 16 : poll_threads();
3398 : 16 : CU_ASSERT(g_bserrno == 0);
3399 : 16 : g_bs = NULL;
3400 : 16 : }
3401 : :
3402 : : static void
3403 : 16 : bs_destroy(void)
3404 : : {
3405 : : struct spdk_blob_store *bs;
3406 : : struct spdk_bs_dev *dev;
3407 : :
3408 : : /* Initialize a new blob store */
3409 : 16 : dev = init_dev();
3410 : 16 : spdk_bs_init(dev, NULL, bs_op_with_handle_complete, NULL);
3411 : 16 : poll_threads();
3412 : 16 : CU_ASSERT(g_bserrno == 0);
3413 [ - + ]: 16 : SPDK_CU_ASSERT_FATAL(g_bs != NULL);
3414 : 16 : bs = g_bs;
3415 : :
3416 : : /* Destroy the blob store */
3417 : 16 : g_bserrno = -1;
3418 : 16 : spdk_bs_destroy(bs, bs_op_complete, NULL);
3419 : 16 : poll_threads();
3420 : 16 : CU_ASSERT(g_bserrno == 0);
3421 : :
3422 : : /* Loading an non-existent blob store should fail. */
3423 : 16 : g_bs = NULL;
3424 : 16 : dev = init_dev();
3425 : :
3426 : 16 : g_bserrno = 0;
3427 : 16 : spdk_bs_load(dev, NULL, bs_op_with_handle_complete, NULL);
3428 : 16 : poll_threads();
3429 : 16 : CU_ASSERT(g_bserrno != 0);
3430 : 16 : }
3431 : :
3432 : : /* Try to hit all of the corner cases associated with serializing
3433 : : * a blob to disk
3434 : : */
3435 : : static void
3436 : 16 : blob_serialize_test(void)
3437 : : {
3438 : : struct spdk_bs_dev *dev;
3439 : 16 : struct spdk_bs_opts opts;
3440 : 16 : struct spdk_blob_store *bs;
3441 : 16 : spdk_blob_id blobid[2];
3442 : 16 : struct spdk_blob *blob[2];
3443 : : uint64_t i;
3444 : : char *value;
3445 : : int rc;
3446 : :
3447 : 16 : dev = init_dev();
3448 : :
3449 : : /* Initialize a new blobstore with very small clusters */
3450 : 16 : spdk_bs_opts_init(&opts, sizeof(opts));
3451 : 16 : opts.cluster_sz = dev->blocklen * 8;
3452 : 16 : spdk_bs_init(dev, &opts, bs_op_with_handle_complete, NULL);
3453 : 16 : poll_threads();
3454 : 16 : CU_ASSERT(g_bserrno == 0);
3455 [ - + ]: 16 : SPDK_CU_ASSERT_FATAL(g_bs != NULL);
3456 : 16 : bs = g_bs;
3457 : :
3458 : : /* Create and open two blobs */
3459 [ + + ]: 48 : for (i = 0; i < 2; i++) {
3460 : 32 : blob[i] = ut_blob_create_and_open(bs, NULL);
3461 : 32 : blobid[i] = spdk_blob_get_id(blob[i]);
3462 : :
3463 : : /* Set a fairly large xattr on both blobs to eat up
3464 : : * metadata space
3465 : : */
3466 : 32 : value = calloc(dev->blocklen - 64, sizeof(char));
3467 [ - + ]: 32 : SPDK_CU_ASSERT_FATAL(value != NULL);
3468 [ - + ]: 32 : memset(value, i, dev->blocklen / 2);
3469 : 32 : rc = spdk_blob_set_xattr(blob[i], "name", value, dev->blocklen - 64);
3470 : 32 : CU_ASSERT(rc == 0);
3471 : 32 : free(value);
3472 : : }
3473 : :
3474 : : /* Resize the blobs, alternating 1 cluster at a time.
3475 : : * This thwarts run length encoding and will cause spill
3476 : : * over of the extents.
3477 : : */
3478 [ + + ]: 112 : for (i = 0; i < 6; i++) {
3479 : 96 : spdk_blob_resize(blob[i % 2], (i / 2) + 1, blob_op_complete, NULL);
3480 : 96 : poll_threads();
3481 : 96 : CU_ASSERT(g_bserrno == 0);
3482 : : }
3483 : :
3484 [ + + ]: 48 : for (i = 0; i < 2; i++) {
3485 : 32 : spdk_blob_sync_md(blob[i], blob_op_complete, NULL);
3486 : 32 : poll_threads();
3487 : 32 : CU_ASSERT(g_bserrno == 0);
3488 : : }
3489 : :
3490 : : /* Close the blobs */
3491 [ + + ]: 48 : for (i = 0; i < 2; i++) {
3492 : 32 : spdk_blob_close(blob[i], blob_op_complete, NULL);
3493 : 32 : poll_threads();
3494 : 32 : CU_ASSERT(g_bserrno == 0);
3495 : : }
3496 : :
3497 : 16 : ut_bs_reload(&bs, &opts);
3498 : :
3499 [ + + ]: 48 : for (i = 0; i < 2; i++) {
3500 : 32 : blob[i] = NULL;
3501 : :
3502 : 32 : spdk_bs_open_blob(bs, blobid[i], blob_op_with_handle_complete, NULL);
3503 : 32 : poll_threads();
3504 : 32 : CU_ASSERT(g_bserrno == 0);
3505 : 32 : CU_ASSERT(g_blob != NULL);
3506 : 32 : blob[i] = g_blob;
3507 : :
3508 : 32 : CU_ASSERT(spdk_blob_get_num_clusters(blob[i]) == 3);
3509 : :
3510 : 32 : spdk_blob_close(blob[i], blob_op_complete, NULL);
3511 : 32 : poll_threads();
3512 : 32 : CU_ASSERT(g_bserrno == 0);
3513 : : }
3514 : :
3515 : 16 : spdk_bs_unload(bs, bs_op_complete, NULL);
3516 : 16 : poll_threads();
3517 : 16 : CU_ASSERT(g_bserrno == 0);
3518 : 16 : g_bs = NULL;
3519 : 16 : }
3520 : :
3521 : : static void
3522 : 16 : blob_crc(void)
3523 : : {
3524 : 16 : struct spdk_blob_store *bs = g_bs;
3525 : : struct spdk_blob *blob;
3526 : : spdk_blob_id blobid;
3527 : : uint32_t page_num;
3528 : : int index;
3529 : : struct spdk_blob_md_page *page;
3530 : :
3531 : 16 : blob = ut_blob_create_and_open(bs, NULL);
3532 : 16 : blobid = spdk_blob_get_id(blob);
3533 : :
3534 : 16 : spdk_blob_close(blob, blob_op_complete, NULL);
3535 : 16 : poll_threads();
3536 : 16 : CU_ASSERT(g_bserrno == 0);
3537 : :
3538 : 16 : page_num = bs_blobid_to_page(blobid);
3539 : 16 : index = DEV_BUFFER_BLOCKLEN * (bs->md_start + page_num);
3540 : 16 : page = (struct spdk_blob_md_page *)&g_dev_buffer[index];
3541 : 16 : page->crc = 0;
3542 : :
3543 : 16 : spdk_bs_open_blob(bs, blobid, blob_op_with_handle_complete, NULL);
3544 : 16 : poll_threads();
3545 : 16 : CU_ASSERT(g_bserrno == -EINVAL);
3546 : 16 : CU_ASSERT(g_blob == NULL);
3547 : 16 : g_bserrno = 0;
3548 : :
3549 : 16 : spdk_bs_delete_blob(bs, blobid, blob_op_complete, NULL);
3550 : 16 : poll_threads();
3551 : 16 : CU_ASSERT(g_bserrno == -EINVAL);
3552 : 16 : }
3553 : :
3554 : : static void
3555 : 16 : super_block_crc(void)
3556 : : {
3557 : : struct spdk_blob_store *bs;
3558 : : struct spdk_bs_dev *dev;
3559 : : struct spdk_bs_super_block *super_block;
3560 : :
3561 : 16 : dev = init_dev();
3562 : 16 : spdk_bs_init(dev, NULL, bs_op_with_handle_complete, NULL);
3563 : 16 : poll_threads();
3564 : 16 : CU_ASSERT(g_bserrno == 0);
3565 [ - + ]: 16 : SPDK_CU_ASSERT_FATAL(g_bs != NULL);
3566 : 16 : bs = g_bs;
3567 : :
3568 : 16 : spdk_bs_unload(bs, bs_op_complete, NULL);
3569 : 16 : poll_threads();
3570 : 16 : CU_ASSERT(g_bserrno == 0);
3571 : 16 : g_bs = NULL;
3572 : :
3573 : 16 : super_block = (struct spdk_bs_super_block *)g_dev_buffer;
3574 : 16 : super_block->crc = 0;
3575 : 16 : dev = init_dev();
3576 : :
3577 : : /* Load an existing blob store */
3578 : 16 : g_bserrno = 0;
3579 : 16 : spdk_bs_load(dev, NULL, bs_op_with_handle_complete, NULL);
3580 : 16 : poll_threads();
3581 : 16 : CU_ASSERT(g_bserrno == -EILSEQ);
3582 : 16 : }
3583 : :
3584 : : /* For blob dirty shutdown test case we do the following sub-test cases:
3585 : : * 1 Initialize new blob store and create 1 super blob with some xattrs, then we
3586 : : * dirty shutdown and reload the blob store and verify the xattrs.
3587 : : * 2 Resize the blob from 10 clusters to 20 clusters and then dirty shutdown,
3588 : : * reload the blob store and verify the clusters number.
3589 : : * 3 Create the second blob and then dirty shutdown, reload the blob store
3590 : : * and verify the second blob.
3591 : : * 4 Delete the second blob and then dirty shutdown, reload the blob store
3592 : : * and verify the second blob is invalid.
3593 : : * 5 Create the second blob again and also create the third blob, modify the
3594 : : * md of second blob which makes the md invalid, and then dirty shutdown,
3595 : : * reload the blob store verify the second blob, it should invalid and also
3596 : : * verify the third blob, it should correct.
3597 : : */
3598 : : static void
3599 : 16 : blob_dirty_shutdown(void)
3600 : : {
3601 : : int rc;
3602 : : int index;
3603 : 16 : struct spdk_blob_store *bs = g_bs;
3604 : : spdk_blob_id blobid1, blobid2, blobid3;
3605 : 16 : struct spdk_blob *blob = g_blob;
3606 : 16 : uint64_t length;
3607 : : uint64_t free_clusters;
3608 : 16 : const void *value;
3609 : 16 : size_t value_len;
3610 : : uint32_t page_num;
3611 : : struct spdk_blob_md_page *page;
3612 : 16 : struct spdk_blob_opts blob_opts;
3613 : :
3614 : : /* Create first blob */
3615 : 16 : blobid1 = spdk_blob_get_id(blob);
3616 : :
3617 : : /* Set some xattrs */
3618 : 16 : rc = spdk_blob_set_xattr(blob, "name", "log.txt", strlen("log.txt") + 1);
3619 : 16 : CU_ASSERT(rc == 0);
3620 : :
3621 : 16 : length = 2345;
3622 : 16 : rc = spdk_blob_set_xattr(blob, "length", &length, sizeof(length));
3623 : 16 : CU_ASSERT(rc == 0);
3624 : :
3625 : : /* Put xattr that fits exactly single page.
3626 : : * This results in adding additional pages to MD.
3627 : : * First is flags and smaller xattr, second the large xattr,
3628 : : * third are just the extents.
3629 : : */
3630 : 16 : size_t xattr_length = 4072 - sizeof(struct spdk_blob_md_descriptor_xattr) -
3631 : : strlen("large_xattr");
3632 : 16 : char *xattr = calloc(xattr_length, sizeof(char));
3633 [ - + ]: 16 : SPDK_CU_ASSERT_FATAL(xattr != NULL);
3634 : 16 : rc = spdk_blob_set_xattr(blob, "large_xattr", xattr, xattr_length);
3635 : 16 : free(xattr);
3636 [ - + ]: 16 : SPDK_CU_ASSERT_FATAL(rc == 0);
3637 : :
3638 : : /* Resize the blob */
3639 : 16 : spdk_blob_resize(blob, 10, blob_op_complete, NULL);
3640 : 16 : poll_threads();
3641 : 16 : CU_ASSERT(g_bserrno == 0);
3642 : :
3643 : : /* Set the blob as the super blob */
3644 : 16 : spdk_bs_set_super(bs, blobid1, blob_op_complete, NULL);
3645 : 16 : poll_threads();
3646 : 16 : CU_ASSERT(g_bserrno == 0);
3647 : :
3648 : 16 : free_clusters = spdk_bs_free_cluster_count(bs);
3649 : :
3650 : 16 : spdk_blob_close(blob, blob_op_complete, NULL);
3651 : 16 : poll_threads();
3652 : 16 : CU_ASSERT(g_bserrno == 0);
3653 : 16 : blob = NULL;
3654 : 16 : g_blob = NULL;
3655 : 16 : g_blobid = SPDK_BLOBID_INVALID;
3656 : :
3657 : 16 : ut_bs_dirty_load(&bs, NULL);
3658 : :
3659 : : /* Get the super blob */
3660 : 16 : spdk_bs_get_super(bs, blob_op_with_id_complete, NULL);
3661 : 16 : poll_threads();
3662 : 16 : CU_ASSERT(g_bserrno == 0);
3663 : 16 : CU_ASSERT(blobid1 == g_blobid);
3664 : :
3665 : 16 : spdk_bs_open_blob(bs, blobid1, blob_op_with_handle_complete, NULL);
3666 : 16 : poll_threads();
3667 : 16 : CU_ASSERT(g_bserrno == 0);
3668 : 16 : CU_ASSERT(g_blob != NULL);
3669 : 16 : blob = g_blob;
3670 : :
3671 : 16 : CU_ASSERT(free_clusters == spdk_bs_free_cluster_count(bs));
3672 : :
3673 : : /* Get the xattrs */
3674 : 16 : value = NULL;
3675 : 16 : rc = spdk_blob_get_xattr_value(blob, "length", &value, &value_len);
3676 : 16 : CU_ASSERT(rc == 0);
3677 [ - + ]: 16 : SPDK_CU_ASSERT_FATAL(value != NULL);
3678 : 16 : CU_ASSERT(*(uint64_t *)value == length);
3679 : 16 : CU_ASSERT(value_len == 8);
3680 : 16 : CU_ASSERT(spdk_blob_get_num_clusters(blob) == 10);
3681 : :
3682 : : /* Resize the blob */
3683 : 16 : spdk_blob_resize(blob, 20, blob_op_complete, NULL);
3684 : 16 : poll_threads();
3685 : 16 : CU_ASSERT(g_bserrno == 0);
3686 : :
3687 : 16 : free_clusters = spdk_bs_free_cluster_count(bs);
3688 : :
3689 : 16 : spdk_blob_close(blob, blob_op_complete, NULL);
3690 : 16 : poll_threads();
3691 : 16 : CU_ASSERT(g_bserrno == 0);
3692 : 16 : blob = NULL;
3693 : 16 : g_blob = NULL;
3694 : 16 : g_blobid = SPDK_BLOBID_INVALID;
3695 : :
3696 : 16 : ut_bs_dirty_load(&bs, NULL);
3697 : :
3698 : 16 : spdk_bs_open_blob(bs, blobid1, blob_op_with_handle_complete, NULL);
3699 : 16 : poll_threads();
3700 : 16 : CU_ASSERT(g_bserrno == 0);
3701 : 16 : CU_ASSERT(g_blob != NULL);
3702 : 16 : blob = g_blob;
3703 : 16 : CU_ASSERT(spdk_blob_get_num_clusters(blob) == 20);
3704 : 16 : CU_ASSERT(free_clusters == spdk_bs_free_cluster_count(bs));
3705 : :
3706 : 16 : spdk_blob_close(blob, blob_op_complete, NULL);
3707 : 16 : poll_threads();
3708 : 16 : CU_ASSERT(g_bserrno == 0);
3709 : 16 : blob = NULL;
3710 : 16 : g_blob = NULL;
3711 : 16 : g_blobid = SPDK_BLOBID_INVALID;
3712 : :
3713 : : /* Create second blob */
3714 : 16 : blob = ut_blob_create_and_open(bs, NULL);
3715 : 16 : blobid2 = spdk_blob_get_id(blob);
3716 : :
3717 : : /* Set some xattrs */
3718 : 16 : rc = spdk_blob_set_xattr(blob, "name", "log1.txt", strlen("log1.txt") + 1);
3719 : 16 : CU_ASSERT(rc == 0);
3720 : :
3721 : 16 : length = 5432;
3722 : 16 : rc = spdk_blob_set_xattr(blob, "length", &length, sizeof(length));
3723 : 16 : CU_ASSERT(rc == 0);
3724 : :
3725 : : /* Resize the blob */
3726 : 16 : spdk_blob_resize(blob, 10, blob_op_complete, NULL);
3727 : 16 : poll_threads();
3728 : 16 : CU_ASSERT(g_bserrno == 0);
3729 : :
3730 : 16 : free_clusters = spdk_bs_free_cluster_count(bs);
3731 : :
3732 : 16 : spdk_blob_close(blob, blob_op_complete, NULL);
3733 : 16 : poll_threads();
3734 : 16 : CU_ASSERT(g_bserrno == 0);
3735 : 16 : blob = NULL;
3736 : 16 : g_blob = NULL;
3737 : 16 : g_blobid = SPDK_BLOBID_INVALID;
3738 : :
3739 : 16 : ut_bs_dirty_load(&bs, NULL);
3740 : :
3741 : 16 : spdk_bs_open_blob(bs, blobid2, blob_op_with_handle_complete, NULL);
3742 : 16 : poll_threads();
3743 : 16 : CU_ASSERT(g_bserrno == 0);
3744 : 16 : CU_ASSERT(g_blob != NULL);
3745 : 16 : blob = g_blob;
3746 : :
3747 : : /* Get the xattrs */
3748 : 16 : value = NULL;
3749 : 16 : rc = spdk_blob_get_xattr_value(blob, "length", &value, &value_len);
3750 : 16 : CU_ASSERT(rc == 0);
3751 [ - + ]: 16 : SPDK_CU_ASSERT_FATAL(value != NULL);
3752 : 16 : CU_ASSERT(*(uint64_t *)value == length);
3753 : 16 : CU_ASSERT(value_len == 8);
3754 : 16 : CU_ASSERT(spdk_blob_get_num_clusters(blob) == 10);
3755 : 16 : CU_ASSERT(free_clusters == spdk_bs_free_cluster_count(bs));
3756 : :
3757 : 16 : ut_blob_close_and_delete(bs, blob);
3758 : :
3759 : 16 : free_clusters = spdk_bs_free_cluster_count(bs);
3760 : :
3761 : 16 : ut_bs_dirty_load(&bs, NULL);
3762 : :
3763 : 16 : spdk_bs_open_blob(bs, blobid2, blob_op_with_handle_complete, NULL);
3764 : 16 : poll_threads();
3765 : 16 : CU_ASSERT(g_bserrno != 0);
3766 : 16 : CU_ASSERT(g_blob == NULL);
3767 : :
3768 : 16 : spdk_bs_open_blob(bs, blobid1, blob_op_with_handle_complete, NULL);
3769 : 16 : poll_threads();
3770 : 16 : CU_ASSERT(g_bserrno == 0);
3771 : 16 : CU_ASSERT(g_blob != NULL);
3772 : 16 : blob = g_blob;
3773 : 16 : CU_ASSERT(free_clusters == spdk_bs_free_cluster_count(bs));
3774 : 16 : spdk_blob_close(blob, blob_op_complete, NULL);
3775 : 16 : poll_threads();
3776 : 16 : CU_ASSERT(g_bserrno == 0);
3777 : :
3778 : 16 : ut_bs_reload(&bs, NULL);
3779 : :
3780 : : /* Create second blob */
3781 : 16 : ut_spdk_blob_opts_init(&blob_opts);
3782 : 16 : spdk_bs_create_blob_ext(bs, &blob_opts, blob_op_with_id_complete, NULL);
3783 : 16 : poll_threads();
3784 : 16 : CU_ASSERT(g_bserrno == 0);
3785 : 16 : CU_ASSERT(g_blobid != SPDK_BLOBID_INVALID);
3786 : 16 : blobid2 = g_blobid;
3787 : :
3788 : : /* Create third blob */
3789 : 16 : spdk_bs_create_blob_ext(bs, &blob_opts, blob_op_with_id_complete, NULL);
3790 : 16 : poll_threads();
3791 : 16 : CU_ASSERT(g_bserrno == 0);
3792 : 16 : CU_ASSERT(g_blobid != SPDK_BLOBID_INVALID);
3793 : 16 : blobid3 = g_blobid;
3794 : :
3795 : 16 : spdk_bs_open_blob(bs, blobid2, blob_op_with_handle_complete, NULL);
3796 : 16 : poll_threads();
3797 : 16 : CU_ASSERT(g_bserrno == 0);
3798 : 16 : CU_ASSERT(g_blob != NULL);
3799 : 16 : blob = g_blob;
3800 : :
3801 : : /* Set some xattrs for second blob */
3802 : 16 : rc = spdk_blob_set_xattr(blob, "name", "log1.txt", strlen("log1.txt") + 1);
3803 : 16 : CU_ASSERT(rc == 0);
3804 : :
3805 : 16 : length = 5432;
3806 : 16 : rc = spdk_blob_set_xattr(blob, "length", &length, sizeof(length));
3807 : 16 : CU_ASSERT(rc == 0);
3808 : :
3809 : 16 : spdk_blob_close(blob, blob_op_complete, NULL);
3810 : 16 : poll_threads();
3811 : 16 : CU_ASSERT(g_bserrno == 0);
3812 : 16 : blob = NULL;
3813 : 16 : g_blob = NULL;
3814 : 16 : g_blobid = SPDK_BLOBID_INVALID;
3815 : :
3816 : 16 : spdk_bs_open_blob(bs, blobid3, blob_op_with_handle_complete, NULL);
3817 : 16 : poll_threads();
3818 : 16 : CU_ASSERT(g_bserrno == 0);
3819 : 16 : CU_ASSERT(g_blob != NULL);
3820 : 16 : blob = g_blob;
3821 : :
3822 : : /* Set some xattrs for third blob */
3823 : 16 : rc = spdk_blob_set_xattr(blob, "name", "log2.txt", strlen("log2.txt") + 1);
3824 : 16 : CU_ASSERT(rc == 0);
3825 : :
3826 : 16 : length = 5432;
3827 : 16 : rc = spdk_blob_set_xattr(blob, "length", &length, sizeof(length));
3828 : 16 : CU_ASSERT(rc == 0);
3829 : :
3830 : 16 : spdk_blob_close(blob, blob_op_complete, NULL);
3831 : 16 : poll_threads();
3832 : 16 : CU_ASSERT(g_bserrno == 0);
3833 : 16 : blob = NULL;
3834 : 16 : g_blob = NULL;
3835 : 16 : g_blobid = SPDK_BLOBID_INVALID;
3836 : :
3837 : : /* Mark second blob as invalid */
3838 : 16 : page_num = bs_blobid_to_page(blobid2);
3839 : :
3840 : 16 : index = DEV_BUFFER_BLOCKLEN * (bs->md_start + page_num);
3841 : 16 : page = (struct spdk_blob_md_page *)&g_dev_buffer[index];
3842 : 16 : page->sequence_num = 1;
3843 : 16 : page->crc = blob_md_page_calc_crc(page);
3844 : :
3845 : 16 : free_clusters = spdk_bs_free_cluster_count(bs);
3846 : :
3847 : 16 : ut_bs_dirty_load(&bs, NULL);
3848 : :
3849 : 16 : spdk_bs_open_blob(bs, blobid2, blob_op_with_handle_complete, NULL);
3850 : 16 : poll_threads();
3851 : 16 : CU_ASSERT(g_bserrno != 0);
3852 : 16 : CU_ASSERT(g_blob == NULL);
3853 : :
3854 : 16 : spdk_bs_open_blob(bs, blobid3, blob_op_with_handle_complete, NULL);
3855 : 16 : poll_threads();
3856 : 16 : CU_ASSERT(g_bserrno == 0);
3857 : 16 : CU_ASSERT(g_blob != NULL);
3858 : 16 : blob = g_blob;
3859 : :
3860 : 16 : CU_ASSERT(free_clusters == spdk_bs_free_cluster_count(bs));
3861 : 16 : }
3862 : :
3863 : : static void
3864 : 16 : blob_flags(void)
3865 : : {
3866 : 16 : struct spdk_blob_store *bs = g_bs;
3867 : : spdk_blob_id blobid_invalid, blobid_data_ro, blobid_md_ro;
3868 : : struct spdk_blob *blob_invalid, *blob_data_ro, *blob_md_ro;
3869 : 16 : struct spdk_blob_opts blob_opts;
3870 : : int rc;
3871 : :
3872 : : /* Create three blobs - one each for testing invalid, data_ro and md_ro flags. */
3873 : 16 : blob_invalid = ut_blob_create_and_open(bs, NULL);
3874 : 16 : blobid_invalid = spdk_blob_get_id(blob_invalid);
3875 : :
3876 : 16 : blob_data_ro = ut_blob_create_and_open(bs, NULL);
3877 : 16 : blobid_data_ro = spdk_blob_get_id(blob_data_ro);
3878 : :
3879 : 16 : ut_spdk_blob_opts_init(&blob_opts);
3880 : 16 : blob_opts.clear_method = BLOB_CLEAR_WITH_WRITE_ZEROES;
3881 : 16 : blob_md_ro = ut_blob_create_and_open(bs, &blob_opts);
3882 : 16 : blobid_md_ro = spdk_blob_get_id(blob_md_ro);
3883 : 16 : CU_ASSERT((blob_md_ro->md_ro_flags & SPDK_BLOB_MD_RO_FLAGS_MASK) == BLOB_CLEAR_WITH_WRITE_ZEROES);
3884 : :
3885 : : /* Change the size of blob_data_ro to check if flags are serialized
3886 : : * when blob has non zero number of extents */
3887 : 16 : spdk_blob_resize(blob_data_ro, 10, blob_op_complete, NULL);
3888 : 16 : poll_threads();
3889 : 16 : CU_ASSERT(g_bserrno == 0);
3890 : :
3891 : : /* Set the xattr to check if flags are serialized
3892 : : * when blob has non zero number of xattrs */
3893 : 16 : rc = spdk_blob_set_xattr(blob_md_ro, "name", "log.txt", strlen("log.txt") + 1);
3894 : 16 : CU_ASSERT(rc == 0);
3895 : :
3896 : 16 : blob_invalid->invalid_flags = (1ULL << 63);
3897 : 16 : blob_invalid->state = SPDK_BLOB_STATE_DIRTY;
3898 : 16 : blob_data_ro->data_ro_flags = (1ULL << 62);
3899 : 16 : blob_data_ro->state = SPDK_BLOB_STATE_DIRTY;
3900 : 16 : blob_md_ro->md_ro_flags = (1ULL << 61);
3901 : 16 : blob_md_ro->state = SPDK_BLOB_STATE_DIRTY;
3902 : :
3903 : 16 : g_bserrno = -1;
3904 : 16 : spdk_blob_sync_md(blob_invalid, blob_op_complete, NULL);
3905 : 16 : poll_threads();
3906 : 16 : CU_ASSERT(g_bserrno == 0);
3907 : 16 : g_bserrno = -1;
3908 : 16 : spdk_blob_sync_md(blob_data_ro, blob_op_complete, NULL);
3909 : 16 : poll_threads();
3910 : 16 : CU_ASSERT(g_bserrno == 0);
3911 : 16 : g_bserrno = -1;
3912 : 16 : spdk_blob_sync_md(blob_md_ro, blob_op_complete, NULL);
3913 : 16 : poll_threads();
3914 : 16 : CU_ASSERT(g_bserrno == 0);
3915 : :
3916 : 16 : g_bserrno = -1;
3917 : 16 : spdk_blob_close(blob_invalid, blob_op_complete, NULL);
3918 : 16 : poll_threads();
3919 : 16 : CU_ASSERT(g_bserrno == 0);
3920 : 16 : blob_invalid = NULL;
3921 : 16 : g_bserrno = -1;
3922 : 16 : spdk_blob_close(blob_data_ro, blob_op_complete, NULL);
3923 : 16 : poll_threads();
3924 : 16 : CU_ASSERT(g_bserrno == 0);
3925 : 16 : blob_data_ro = NULL;
3926 : 16 : g_bserrno = -1;
3927 : 16 : spdk_blob_close(blob_md_ro, blob_op_complete, NULL);
3928 : 16 : poll_threads();
3929 : 16 : CU_ASSERT(g_bserrno == 0);
3930 : 16 : blob_md_ro = NULL;
3931 : :
3932 : 16 : g_blob = NULL;
3933 : 16 : g_blobid = SPDK_BLOBID_INVALID;
3934 : :
3935 : 16 : ut_bs_reload(&bs, NULL);
3936 : :
3937 : 16 : g_blob = NULL;
3938 : 16 : g_bserrno = 0;
3939 : 16 : spdk_bs_open_blob(bs, blobid_invalid, blob_op_with_handle_complete, NULL);
3940 : 16 : poll_threads();
3941 : 16 : CU_ASSERT(g_bserrno != 0);
3942 : 16 : CU_ASSERT(g_blob == NULL);
3943 : :
3944 : 16 : g_blob = NULL;
3945 : 16 : g_bserrno = -1;
3946 : 16 : spdk_bs_open_blob(bs, blobid_data_ro, blob_op_with_handle_complete, NULL);
3947 : 16 : poll_threads();
3948 : 16 : CU_ASSERT(g_bserrno == 0);
3949 [ - + ]: 16 : SPDK_CU_ASSERT_FATAL(g_blob != NULL);
3950 : 16 : blob_data_ro = g_blob;
3951 : : /* If an unknown data_ro flag was found, the blob should be marked both data and md read-only. */
3952 [ - + ]: 16 : CU_ASSERT(blob_data_ro->data_ro == true);
3953 [ - + ]: 16 : CU_ASSERT(blob_data_ro->md_ro == true);
3954 : 16 : CU_ASSERT(spdk_blob_get_num_clusters(blob_data_ro) == 10);
3955 : :
3956 : 16 : g_blob = NULL;
3957 : 16 : g_bserrno = -1;
3958 : 16 : spdk_bs_open_blob(bs, blobid_md_ro, blob_op_with_handle_complete, NULL);
3959 : 16 : poll_threads();
3960 : 16 : CU_ASSERT(g_bserrno == 0);
3961 [ - + ]: 16 : SPDK_CU_ASSERT_FATAL(g_blob != NULL);
3962 : 16 : blob_md_ro = g_blob;
3963 [ - + ]: 16 : CU_ASSERT(blob_md_ro->data_ro == false);
3964 [ - + ]: 16 : CU_ASSERT(blob_md_ro->md_ro == true);
3965 : :
3966 : 16 : g_bserrno = -1;
3967 : 16 : spdk_blob_sync_md(blob_md_ro, blob_op_complete, NULL);
3968 : 16 : poll_threads();
3969 : 16 : CU_ASSERT(g_bserrno == 0);
3970 : :
3971 : 16 : ut_blob_close_and_delete(bs, blob_data_ro);
3972 : 16 : ut_blob_close_and_delete(bs, blob_md_ro);
3973 : 16 : }
3974 : :
3975 : : static void
3976 : 16 : bs_version(void)
3977 : : {
3978 : : struct spdk_bs_super_block *super;
3979 : 16 : struct spdk_blob_store *bs = g_bs;
3980 : : struct spdk_bs_dev *dev;
3981 : : struct spdk_blob *blob;
3982 : 16 : struct spdk_blob_opts blob_opts;
3983 : : spdk_blob_id blobid;
3984 : :
3985 : : /* Unload the blob store */
3986 : 16 : spdk_bs_unload(bs, bs_op_complete, NULL);
3987 : 16 : poll_threads();
3988 : 16 : CU_ASSERT(g_bserrno == 0);
3989 : 16 : g_bs = NULL;
3990 : :
3991 : : /*
3992 : : * Change the bs version on disk. This will allow us to
3993 : : * test that the version does not get modified automatically
3994 : : * when loading and unloading the blobstore.
3995 : : */
3996 : 16 : super = (struct spdk_bs_super_block *)&g_dev_buffer[0];
3997 : 16 : CU_ASSERT(super->version == SPDK_BS_VERSION);
3998 : 16 : CU_ASSERT(super->clean == 1);
3999 : 16 : super->version = 2;
4000 : : /*
4001 : : * Version 2 metadata does not have a used blobid mask, so clear
4002 : : * those fields in the super block and zero the corresponding
4003 : : * region on "disk". We will use this to ensure blob IDs are
4004 : : * correctly reconstructed.
4005 : : */
4006 [ - + ]: 16 : memset(&g_dev_buffer[super->used_blobid_mask_start * SPDK_BS_PAGE_SIZE], 0,
4007 : 16 : super->used_blobid_mask_len * SPDK_BS_PAGE_SIZE);
4008 : 16 : super->used_blobid_mask_start = 0;
4009 : 16 : super->used_blobid_mask_len = 0;
4010 : 16 : super->crc = blob_md_page_calc_crc(super);
4011 : :
4012 : : /* Load an existing blob store */
4013 : 16 : dev = init_dev();
4014 : 16 : spdk_bs_load(dev, NULL, bs_op_with_handle_complete, NULL);
4015 : 16 : poll_threads();
4016 : 16 : CU_ASSERT(g_bserrno == 0);
4017 [ - + ]: 16 : SPDK_CU_ASSERT_FATAL(g_bs != NULL);
4018 : 16 : CU_ASSERT(super->clean == 1);
4019 : 16 : bs = g_bs;
4020 : :
4021 : : /*
4022 : : * Create a blob - just to make sure that when we unload it
4023 : : * results in writing the super block (since metadata pages
4024 : : * were allocated.
4025 : : */
4026 : 16 : ut_spdk_blob_opts_init(&blob_opts);
4027 : 16 : spdk_bs_create_blob_ext(bs, &blob_opts, blob_op_with_id_complete, NULL);
4028 : 16 : poll_threads();
4029 : 16 : CU_ASSERT(g_bserrno == 0);
4030 : 16 : CU_ASSERT(g_blobid != SPDK_BLOBID_INVALID);
4031 : 16 : blobid = g_blobid;
4032 : :
4033 : : /* Unload the blob store */
4034 : 16 : spdk_bs_unload(bs, bs_op_complete, NULL);
4035 : 16 : poll_threads();
4036 : 16 : CU_ASSERT(g_bserrno == 0);
4037 : 16 : g_bs = NULL;
4038 : 16 : CU_ASSERT(super->version == 2);
4039 : 16 : CU_ASSERT(super->used_blobid_mask_start == 0);
4040 : 16 : CU_ASSERT(super->used_blobid_mask_len == 0);
4041 : :
4042 : 16 : dev = init_dev();
4043 : 16 : spdk_bs_load(dev, NULL, bs_op_with_handle_complete, NULL);
4044 : 16 : poll_threads();
4045 : 16 : CU_ASSERT(g_bserrno == 0);
4046 [ - + ]: 16 : SPDK_CU_ASSERT_FATAL(g_bs != NULL);
4047 : 16 : bs = g_bs;
4048 : :
4049 : 16 : g_blob = NULL;
4050 : 16 : spdk_bs_open_blob(bs, blobid, blob_op_with_handle_complete, NULL);
4051 : 16 : poll_threads();
4052 : 16 : CU_ASSERT(g_bserrno == 0);
4053 : 16 : CU_ASSERT(g_blob != NULL);
4054 : 16 : blob = g_blob;
4055 : :
4056 : 16 : ut_blob_close_and_delete(bs, blob);
4057 : :
4058 : 16 : CU_ASSERT(super->version == 2);
4059 : 16 : CU_ASSERT(super->used_blobid_mask_start == 0);
4060 : 16 : CU_ASSERT(super->used_blobid_mask_len == 0);
4061 : 16 : }
4062 : :
4063 : : static void
4064 : 16 : blob_set_xattrs_test(void)
4065 : : {
4066 : 16 : struct spdk_blob_store *bs = g_bs;
4067 : : struct spdk_blob *blob;
4068 : 16 : struct spdk_blob_opts opts;
4069 : 16 : const void *value;
4070 : 16 : size_t value_len;
4071 : : char *xattr;
4072 : : size_t xattr_length;
4073 : : int rc;
4074 : :
4075 : : /* Create blob with extra attributes */
4076 : 16 : ut_spdk_blob_opts_init(&opts);
4077 : :
4078 : 16 : opts.xattrs.names = g_xattr_names;
4079 : 16 : opts.xattrs.get_value = _get_xattr_value;
4080 : 16 : opts.xattrs.count = 3;
4081 : 16 : opts.xattrs.ctx = &g_ctx;
4082 : :
4083 : 16 : blob = ut_blob_create_and_open(bs, &opts);
4084 : :
4085 : : /* Get the xattrs */
4086 : 16 : value = NULL;
4087 : :
4088 : 16 : rc = spdk_blob_get_xattr_value(blob, g_xattr_names[0], &value, &value_len);
4089 : 16 : CU_ASSERT(rc == 0);
4090 [ - + ]: 16 : SPDK_CU_ASSERT_FATAL(value != NULL);
4091 [ - + ]: 16 : CU_ASSERT(value_len == strlen(g_xattr_values[0]));
4092 [ - + - + ]: 16 : CU_ASSERT_NSTRING_EQUAL_FATAL(value, g_xattr_values[0], value_len);
4093 : :
4094 : 16 : rc = spdk_blob_get_xattr_value(blob, g_xattr_names[1], &value, &value_len);
4095 : 16 : CU_ASSERT(rc == 0);
4096 [ - + ]: 16 : SPDK_CU_ASSERT_FATAL(value != NULL);
4097 [ - + ]: 16 : CU_ASSERT(value_len == strlen(g_xattr_values[1]));
4098 [ - + - + ]: 16 : CU_ASSERT_NSTRING_EQUAL((char *)value, g_xattr_values[1], value_len);
4099 : :
4100 : 16 : rc = spdk_blob_get_xattr_value(blob, g_xattr_names[2], &value, &value_len);
4101 : 16 : CU_ASSERT(rc == 0);
4102 [ - + ]: 16 : SPDK_CU_ASSERT_FATAL(value != NULL);
4103 [ - + ]: 16 : CU_ASSERT(value_len == strlen(g_xattr_values[2]));
4104 [ - + - + ]: 16 : CU_ASSERT_NSTRING_EQUAL((char *)value, g_xattr_values[2], value_len);
4105 : :
4106 : : /* Try to get non existing attribute */
4107 : :
4108 : 16 : rc = spdk_blob_get_xattr_value(blob, "foobar", &value, &value_len);
4109 : 16 : CU_ASSERT(rc == -ENOENT);
4110 : :
4111 : : /* Try xattr exceeding maximum length of descriptor in single page */
4112 : 16 : xattr_length = SPDK_BS_MAX_DESC_SIZE - sizeof(struct spdk_blob_md_descriptor_xattr) -
4113 : : strlen("large_xattr") + 1;
4114 : 16 : xattr = calloc(xattr_length, sizeof(char));
4115 [ - + ]: 16 : SPDK_CU_ASSERT_FATAL(xattr != NULL);
4116 : 16 : rc = spdk_blob_set_xattr(blob, "large_xattr", xattr, xattr_length);
4117 : 16 : free(xattr);
4118 [ - + ]: 16 : SPDK_CU_ASSERT_FATAL(rc == -ENOMEM);
4119 : :
4120 : 16 : spdk_blob_close(blob, blob_op_complete, NULL);
4121 : 16 : poll_threads();
4122 : 16 : CU_ASSERT(g_bserrno == 0);
4123 : 16 : blob = NULL;
4124 : 16 : g_blob = NULL;
4125 : 16 : g_blobid = SPDK_BLOBID_INVALID;
4126 : :
4127 : : /* NULL callback */
4128 : 16 : ut_spdk_blob_opts_init(&opts);
4129 : 16 : opts.xattrs.names = g_xattr_names;
4130 : 16 : opts.xattrs.get_value = NULL;
4131 : 16 : opts.xattrs.count = 1;
4132 : 16 : opts.xattrs.ctx = &g_ctx;
4133 : :
4134 : 16 : spdk_bs_create_blob_ext(bs, &opts, blob_op_with_id_complete, NULL);
4135 : 16 : poll_threads();
4136 : 16 : CU_ASSERT(g_bserrno == -EINVAL);
4137 : 16 : CU_ASSERT(g_blobid != SPDK_BLOBID_INVALID);
4138 : :
4139 : : /* NULL values */
4140 : 16 : ut_spdk_blob_opts_init(&opts);
4141 : 16 : opts.xattrs.names = g_xattr_names;
4142 : 16 : opts.xattrs.get_value = _get_xattr_value_null;
4143 : 16 : opts.xattrs.count = 1;
4144 : 16 : opts.xattrs.ctx = NULL;
4145 : :
4146 : 16 : spdk_bs_create_blob_ext(bs, &opts, blob_op_with_id_complete, NULL);
4147 : 16 : poll_threads();
4148 : 16 : CU_ASSERT(g_bserrno == -EINVAL);
4149 : 16 : }
4150 : :
4151 : : static void
4152 : 16 : blob_thin_prov_alloc(void)
4153 : : {
4154 : 16 : struct spdk_blob_store *bs = g_bs;
4155 : : struct spdk_blob *blob;
4156 : 16 : struct spdk_blob_opts opts;
4157 : : spdk_blob_id blobid;
4158 : : uint64_t free_clusters;
4159 : :
4160 : 16 : free_clusters = spdk_bs_free_cluster_count(bs);
4161 : :
4162 : : /* Set blob as thin provisioned */
4163 : 16 : ut_spdk_blob_opts_init(&opts);
4164 : 16 : opts.thin_provision = true;
4165 : :
4166 : 16 : blob = ut_blob_create_and_open(bs, &opts);
4167 : 16 : blobid = spdk_blob_get_id(blob);
4168 : 16 : CU_ASSERT(free_clusters == spdk_bs_free_cluster_count(bs));
4169 : :
4170 : 16 : CU_ASSERT(blob->active.num_clusters == 0);
4171 : 16 : CU_ASSERT(spdk_blob_get_num_clusters(blob) == 0);
4172 : :
4173 : : /* The blob started at 0 clusters. Resize it to be 5, but still unallocated. */
4174 : 16 : spdk_blob_resize(blob, 5, blob_op_complete, NULL);
4175 : 16 : poll_threads();
4176 : 16 : CU_ASSERT(g_bserrno == 0);
4177 : 16 : CU_ASSERT(free_clusters == spdk_bs_free_cluster_count(bs));
4178 : 16 : CU_ASSERT(blob->active.num_clusters == 5);
4179 : 16 : CU_ASSERT(spdk_blob_get_num_clusters(blob) == 5);
4180 : :
4181 : : /* Grow it to 1TB - still unallocated */
4182 : 16 : spdk_blob_resize(blob, 262144, blob_op_complete, NULL);
4183 : 16 : poll_threads();
4184 : 16 : CU_ASSERT(g_bserrno == 0);
4185 : 16 : CU_ASSERT(free_clusters == spdk_bs_free_cluster_count(bs));
4186 : 16 : CU_ASSERT(blob->active.num_clusters == 262144);
4187 : 16 : CU_ASSERT(spdk_blob_get_num_clusters(blob) == 262144);
4188 : :
4189 : 16 : spdk_blob_sync_md(blob, blob_op_complete, NULL);
4190 : 16 : poll_threads();
4191 : 16 : CU_ASSERT(g_bserrno == 0);
4192 : : /* Sync must not change anything */
4193 : 16 : CU_ASSERT(free_clusters == spdk_bs_free_cluster_count(bs));
4194 : 16 : CU_ASSERT(blob->active.num_clusters == 262144);
4195 : 16 : CU_ASSERT(spdk_blob_get_num_clusters(blob) == 262144);
4196 : : /* Since clusters are not allocated,
4197 : : * number of metadata pages is expected to be minimal.
4198 : : */
4199 : 16 : CU_ASSERT(blob->active.num_pages == 1);
4200 : :
4201 : : /* Shrink the blob to 3 clusters - still unallocated */
4202 : 16 : spdk_blob_resize(blob, 3, blob_op_complete, NULL);
4203 : 16 : poll_threads();
4204 : 16 : CU_ASSERT(g_bserrno == 0);
4205 : 16 : CU_ASSERT(free_clusters == spdk_bs_free_cluster_count(bs));
4206 : 16 : CU_ASSERT(blob->active.num_clusters == 3);
4207 : 16 : CU_ASSERT(spdk_blob_get_num_clusters(blob) == 3);
4208 : :
4209 : 16 : spdk_blob_sync_md(blob, blob_op_complete, NULL);
4210 : 16 : poll_threads();
4211 : 16 : CU_ASSERT(g_bserrno == 0);
4212 : : /* Sync must not change anything */
4213 : 16 : CU_ASSERT(free_clusters == spdk_bs_free_cluster_count(bs));
4214 : 16 : CU_ASSERT(blob->active.num_clusters == 3);
4215 : 16 : CU_ASSERT(spdk_blob_get_num_clusters(blob) == 3);
4216 : :
4217 : 16 : spdk_blob_close(blob, blob_op_complete, NULL);
4218 : 16 : poll_threads();
4219 : 16 : CU_ASSERT(g_bserrno == 0);
4220 : :
4221 : 16 : ut_bs_reload(&bs, NULL);
4222 : :
4223 : 16 : spdk_bs_open_blob(bs, blobid, blob_op_with_handle_complete, NULL);
4224 : 16 : poll_threads();
4225 : 16 : CU_ASSERT(g_bserrno == 0);
4226 [ - + ]: 16 : SPDK_CU_ASSERT_FATAL(g_blob != NULL);
4227 : 16 : blob = g_blob;
4228 : :
4229 : : /* Check that clusters allocation and size is still the same */
4230 : 16 : CU_ASSERT(free_clusters == spdk_bs_free_cluster_count(bs));
4231 : 16 : CU_ASSERT(blob->active.num_clusters == 3);
4232 : :
4233 : 16 : ut_blob_close_and_delete(bs, blob);
4234 : 16 : }
4235 : :
4236 : : static void
4237 : 16 : blob_insert_cluster_msg_test(void)
4238 : : {
4239 : 16 : struct spdk_blob_store *bs = g_bs;
4240 : : struct spdk_blob *blob;
4241 : 16 : struct spdk_blob_opts opts;
4242 : 16 : struct spdk_blob_md_page page = {};
4243 : : spdk_blob_id blobid;
4244 : : uint64_t free_clusters;
4245 : 16 : uint64_t new_cluster = 0;
4246 : 16 : uint32_t cluster_num = 3;
4247 : 16 : uint32_t extent_page = 0;
4248 : :
4249 : 16 : free_clusters = spdk_bs_free_cluster_count(bs);
4250 : :
4251 : : /* Set blob as thin provisioned */
4252 : 16 : ut_spdk_blob_opts_init(&opts);
4253 : 16 : opts.thin_provision = true;
4254 : 16 : opts.num_clusters = 4;
4255 : :
4256 : 16 : blob = ut_blob_create_and_open(bs, &opts);
4257 : 16 : blobid = spdk_blob_get_id(blob);
4258 : 16 : CU_ASSERT(free_clusters == spdk_bs_free_cluster_count(bs));
4259 : :
4260 : 16 : CU_ASSERT(blob->active.num_clusters == 4);
4261 : 16 : CU_ASSERT(spdk_blob_get_num_clusters(blob) == 4);
4262 : 16 : CU_ASSERT(blob->active.clusters[cluster_num] == 0);
4263 : :
4264 : : /* Specify cluster_num to allocate and new_cluster will be returned to insert on md_thread.
4265 : : * This is to simulate behaviour when cluster is allocated after blob creation.
4266 : : * Such as _spdk_bs_allocate_and_copy_cluster(). */
4267 : 16 : spdk_spin_lock(&bs->used_lock);
4268 : 16 : bs_allocate_cluster(blob, cluster_num, &new_cluster, &extent_page, false);
4269 : 16 : CU_ASSERT(blob->active.clusters[cluster_num] == 0);
4270 : 16 : spdk_spin_unlock(&bs->used_lock);
4271 : :
4272 : 16 : blob_insert_cluster_on_md_thread(blob, cluster_num, new_cluster, extent_page, &page,
4273 : : blob_op_complete, NULL);
4274 : 16 : poll_threads();
4275 : :
4276 : 16 : CU_ASSERT(blob->active.clusters[cluster_num] != 0);
4277 : :
4278 : 16 : spdk_blob_close(blob, blob_op_complete, NULL);
4279 : 16 : poll_threads();
4280 : 16 : CU_ASSERT(g_bserrno == 0);
4281 : :
4282 : 16 : ut_bs_reload(&bs, NULL);
4283 : :
4284 : 16 : spdk_bs_open_blob(bs, blobid, blob_op_with_handle_complete, NULL);
4285 : 16 : poll_threads();
4286 : 16 : CU_ASSERT(g_bserrno == 0);
4287 [ - + ]: 16 : SPDK_CU_ASSERT_FATAL(g_blob != NULL);
4288 : 16 : blob = g_blob;
4289 : :
4290 : 16 : CU_ASSERT(blob->active.clusters[cluster_num] != 0);
4291 : :
4292 : 16 : ut_blob_close_and_delete(bs, blob);
4293 : 16 : }
4294 : :
4295 : : static void
4296 : 16 : blob_thin_prov_rw(void)
4297 : : {
4298 : : static const uint8_t zero[10 * 4096] = { 0 };
4299 : 16 : struct spdk_blob_store *bs = g_bs;
4300 : : struct spdk_blob *blob, *blob_id0;
4301 : : struct spdk_io_channel *channel, *channel_thread1;
4302 : 16 : struct spdk_blob_opts opts;
4303 : : uint64_t free_clusters;
4304 : : uint64_t page_size;
4305 : 16 : uint8_t payload_read[10 * 4096];
4306 : 16 : uint8_t payload_write[10 * 4096];
4307 : : uint64_t write_bytes;
4308 : : uint64_t read_bytes;
4309 : :
4310 : 16 : free_clusters = spdk_bs_free_cluster_count(bs);
4311 : 16 : page_size = spdk_bs_get_page_size(bs);
4312 : :
4313 : 16 : channel = spdk_bs_alloc_io_channel(bs);
4314 : 16 : CU_ASSERT(channel != NULL);
4315 : :
4316 : 16 : ut_spdk_blob_opts_init(&opts);
4317 : 16 : opts.thin_provision = true;
4318 : :
4319 : : /* Create and delete blob at md page 0, so that next md page allocation
4320 : : * for extent will use that. */
4321 : 16 : blob_id0 = ut_blob_create_and_open(bs, &opts);
4322 : 16 : blob = ut_blob_create_and_open(bs, &opts);
4323 : 16 : ut_blob_close_and_delete(bs, blob_id0);
4324 : 16 : CU_ASSERT(free_clusters == spdk_bs_free_cluster_count(bs));
4325 : :
4326 : 16 : CU_ASSERT(blob->active.num_clusters == 0);
4327 : :
4328 : : /* The blob started at 0 clusters. Resize it to be 5, but still unallocated. */
4329 : 16 : spdk_blob_resize(blob, 5, blob_op_complete, NULL);
4330 : 16 : poll_threads();
4331 : 16 : CU_ASSERT(g_bserrno == 0);
4332 : 16 : CU_ASSERT(free_clusters == spdk_bs_free_cluster_count(bs));
4333 : 16 : CU_ASSERT(blob->active.num_clusters == 5);
4334 : :
4335 : 16 : spdk_blob_sync_md(blob, blob_op_complete, NULL);
4336 : 16 : poll_threads();
4337 : 16 : CU_ASSERT(g_bserrno == 0);
4338 : : /* Sync must not change anything */
4339 : 16 : CU_ASSERT(free_clusters == spdk_bs_free_cluster_count(bs));
4340 : 16 : CU_ASSERT(blob->active.num_clusters == 5);
4341 : :
4342 : : /* Payload should be all zeros from unallocated clusters */
4343 : 16 : memset(payload_read, 0xFF, sizeof(payload_read));
4344 : 16 : spdk_blob_io_read(blob, channel, payload_read, 4, 10, blob_op_complete, NULL);
4345 : 16 : poll_threads();
4346 : 16 : CU_ASSERT(g_bserrno == 0);
4347 : 16 : CU_ASSERT(memcmp(zero, payload_read, 10 * 4096) == 0);
4348 : :
4349 : 16 : write_bytes = g_dev_write_bytes;
4350 : 16 : read_bytes = g_dev_read_bytes;
4351 : :
4352 : : /* Perform write on thread 1. That will allocate cluster on thread 0 via send_msg */
4353 : 16 : set_thread(1);
4354 : 16 : channel_thread1 = spdk_bs_alloc_io_channel(bs);
4355 : 16 : CU_ASSERT(channel_thread1 != NULL);
4356 : 16 : memset(payload_write, 0xE5, sizeof(payload_write));
4357 : 16 : spdk_blob_io_write(blob, channel_thread1, payload_write, 4, 10, blob_op_complete, NULL);
4358 : 16 : CU_ASSERT(free_clusters - 1 == spdk_bs_free_cluster_count(bs));
4359 : : /* Perform write on thread 0. That will try to allocate cluster,
4360 : : * but fail due to another thread issuing the cluster allocation first. */
4361 : 16 : set_thread(0);
4362 : 16 : memset(payload_write, 0xE5, sizeof(payload_write));
4363 : 16 : spdk_blob_io_write(blob, channel, payload_write, 4, 10, blob_op_complete, NULL);
4364 : 16 : CU_ASSERT(free_clusters - 2 == spdk_bs_free_cluster_count(bs));
4365 : 16 : poll_threads();
4366 : 16 : CU_ASSERT(g_bserrno == 0);
4367 : 16 : CU_ASSERT(free_clusters - 1 == spdk_bs_free_cluster_count(bs));
4368 : : /* For thin-provisioned blob we need to write 20 pages plus one page metadata and
4369 : : * read 0 bytes */
4370 [ + + + + ]: 16 : if (g_use_extent_table) {
4371 : : /* Add one more page for EXTENT_PAGE write */
4372 : 8 : CU_ASSERT(g_dev_write_bytes - write_bytes == page_size * 22);
4373 : : } else {
4374 : 8 : CU_ASSERT(g_dev_write_bytes - write_bytes == page_size * 21);
4375 : : }
4376 : 16 : CU_ASSERT(g_dev_read_bytes - read_bytes == 0);
4377 : :
4378 : 16 : spdk_blob_io_read(blob, channel, payload_read, 4, 10, blob_op_complete, NULL);
4379 : 16 : poll_threads();
4380 : 16 : CU_ASSERT(g_bserrno == 0);
4381 : 16 : CU_ASSERT(memcmp(payload_write, payload_read, 10 * 4096) == 0);
4382 : :
4383 : 16 : ut_blob_close_and_delete(bs, blob);
4384 : 16 : CU_ASSERT(free_clusters == spdk_bs_free_cluster_count(bs));
4385 : :
4386 : 16 : set_thread(1);
4387 : 16 : spdk_bs_free_io_channel(channel_thread1);
4388 : 16 : set_thread(0);
4389 : 16 : spdk_bs_free_io_channel(channel);
4390 : 16 : poll_threads();
4391 : 16 : g_blob = NULL;
4392 : 16 : g_blobid = 0;
4393 : 16 : }
4394 : :
4395 : : static void
4396 : 16 : blob_thin_prov_write_count_io(void)
4397 : : {
4398 : : struct spdk_blob_store *bs;
4399 : : struct spdk_blob *blob;
4400 : : struct spdk_io_channel *ch;
4401 : : struct spdk_bs_dev *dev;
4402 : 16 : struct spdk_bs_opts bs_opts;
4403 : 16 : struct spdk_blob_opts opts;
4404 : : uint64_t free_clusters;
4405 : : uint64_t page_size;
4406 : 16 : uint8_t payload_write[4096];
4407 : : uint64_t write_bytes;
4408 : : uint64_t read_bytes;
4409 : 16 : const uint32_t CLUSTER_SZ = 16384;
4410 : : uint32_t pages_per_cluster;
4411 : : uint32_t pages_per_extent_page;
4412 : : uint32_t i;
4413 : :
4414 : : /* Use a very small cluster size for this test. This ensures we need multiple
4415 : : * extent pages to hold all of the clusters even for relatively small blobs like
4416 : : * we are restricted to for the unit tests (i.e. we don't want to allocate multi-GB
4417 : : * buffers).
4418 : : */
4419 : 16 : dev = init_dev();
4420 : 16 : spdk_bs_opts_init(&bs_opts, sizeof(bs_opts));
4421 : 16 : bs_opts.cluster_sz = CLUSTER_SZ;
4422 : :
4423 : 16 : spdk_bs_init(dev, &bs_opts, bs_op_with_handle_complete, NULL);
4424 : 16 : poll_threads();
4425 : 16 : CU_ASSERT(g_bserrno == 0);
4426 [ - + ]: 16 : SPDK_CU_ASSERT_FATAL(g_bs != NULL);
4427 : 16 : bs = g_bs;
4428 : :
4429 : 16 : free_clusters = spdk_bs_free_cluster_count(bs);
4430 : 16 : page_size = spdk_bs_get_page_size(bs);
4431 [ - + ]: 16 : pages_per_cluster = CLUSTER_SZ / page_size;
4432 : 16 : pages_per_extent_page = SPDK_EXTENTS_PER_EP * pages_per_cluster;
4433 : :
4434 : 16 : ch = spdk_bs_alloc_io_channel(bs);
4435 [ - + ]: 16 : SPDK_CU_ASSERT_FATAL(ch != NULL);
4436 : :
4437 : 16 : ut_spdk_blob_opts_init(&opts);
4438 : 16 : opts.thin_provision = true;
4439 : :
4440 : 16 : blob = ut_blob_create_and_open(bs, &opts);
4441 : 16 : CU_ASSERT(free_clusters == spdk_bs_free_cluster_count(bs));
4442 : :
4443 : : /* Resize the blob so that it will require 8 extent pages to hold all of
4444 : : * the clusters.
4445 : : */
4446 : 16 : g_bserrno = -1;
4447 : 16 : spdk_blob_resize(blob, SPDK_EXTENTS_PER_EP * 8, blob_op_complete, NULL);
4448 : 16 : poll_threads();
4449 : 16 : CU_ASSERT(g_bserrno == 0);
4450 : :
4451 : 16 : g_bserrno = -1;
4452 : 16 : spdk_blob_sync_md(blob, blob_op_complete, NULL);
4453 : 16 : poll_threads();
4454 : 16 : CU_ASSERT(g_bserrno == 0);
4455 : 16 : CU_ASSERT(free_clusters == spdk_bs_free_cluster_count(bs));
4456 : 16 : CU_ASSERT(blob->active.num_clusters == SPDK_EXTENTS_PER_EP * 8);
4457 : :
4458 : 16 : memset(payload_write, 0, sizeof(payload_write));
4459 [ + + ]: 144 : for (i = 0; i < 8; i++) {
4460 : 128 : write_bytes = g_dev_write_bytes;
4461 : 128 : read_bytes = g_dev_read_bytes;
4462 : :
4463 : 128 : g_bserrno = -1;
4464 : 128 : spdk_blob_io_write(blob, ch, payload_write, pages_per_extent_page * i, 1, blob_op_complete, NULL);
4465 : 128 : poll_threads();
4466 : 128 : CU_ASSERT(g_bserrno == 0);
4467 : 128 : CU_ASSERT(free_clusters - (2 * i + 1) == spdk_bs_free_cluster_count(bs));
4468 : :
4469 : 128 : CU_ASSERT(g_dev_read_bytes == read_bytes);
4470 [ + + + + ]: 128 : if (!g_use_extent_table) {
4471 : : /* For legacy metadata, we should have written two pages - one for the
4472 : : * write I/O itself, another for the blob's primary metadata.
4473 : : */
4474 [ - + ]: 64 : CU_ASSERT((g_dev_write_bytes - write_bytes) / page_size == 2);
4475 : : } else {
4476 : : /* For extent table metadata, we should have written three pages - one
4477 : : * for the write I/O, one for the extent page, one for the blob's primary
4478 : : * metadata.
4479 : : */
4480 [ - + ]: 64 : CU_ASSERT((g_dev_write_bytes - write_bytes) / page_size == 3);
4481 : : }
4482 : :
4483 : : /* The write should have synced the metadata already. Do another sync here
4484 : : * just to confirm.
4485 : : */
4486 : 128 : write_bytes = g_dev_write_bytes;
4487 : 128 : read_bytes = g_dev_read_bytes;
4488 : :
4489 : 128 : g_bserrno = -1;
4490 : 128 : spdk_blob_sync_md(blob, blob_op_complete, NULL);
4491 : 128 : poll_threads();
4492 : 128 : CU_ASSERT(g_bserrno == 0);
4493 : 128 : CU_ASSERT(free_clusters - (2 * i + 1) == spdk_bs_free_cluster_count(bs));
4494 : :
4495 : 128 : CU_ASSERT(g_dev_read_bytes == read_bytes);
4496 : 128 : CU_ASSERT(g_dev_write_bytes == write_bytes);
4497 : :
4498 : : /* Now write to another unallocated cluster that is part of the same extent page. */
4499 : 128 : g_bserrno = -1;
4500 : 128 : spdk_blob_io_write(blob, ch, payload_write, pages_per_extent_page * i + pages_per_cluster,
4501 : : 1, blob_op_complete, NULL);
4502 : 128 : poll_threads();
4503 : 128 : CU_ASSERT(g_bserrno == 0);
4504 : 128 : CU_ASSERT(free_clusters - (2 * i + 2) == spdk_bs_free_cluster_count(bs));
4505 : :
4506 : 128 : CU_ASSERT(g_dev_read_bytes == read_bytes);
4507 : : /*
4508 : : * For legacy metadata, we should have written the I/O and the primary metadata page.
4509 : : * For extent table metadata, we should have written the I/O and the extent metadata page.
4510 : : */
4511 [ - + ]: 128 : CU_ASSERT((g_dev_write_bytes - write_bytes) / page_size == 2);
4512 : : }
4513 : :
4514 : 16 : ut_blob_close_and_delete(bs, blob);
4515 : 16 : CU_ASSERT(free_clusters == spdk_bs_free_cluster_count(bs));
4516 : :
4517 : 16 : spdk_bs_free_io_channel(ch);
4518 : 16 : poll_threads();
4519 : 16 : g_blob = NULL;
4520 : 16 : g_blobid = 0;
4521 : :
4522 : 16 : spdk_bs_unload(bs, bs_op_complete, NULL);
4523 : 16 : poll_threads();
4524 : 16 : CU_ASSERT(g_bserrno == 0);
4525 : 16 : g_bs = NULL;
4526 : 16 : }
4527 : :
4528 : : static void
4529 : 16 : blob_thin_prov_rle(void)
4530 : : {
4531 : : static const uint8_t zero[10 * 4096] = { 0 };
4532 : 16 : struct spdk_blob_store *bs = g_bs;
4533 : : struct spdk_blob *blob;
4534 : : struct spdk_io_channel *channel;
4535 : 16 : struct spdk_blob_opts opts;
4536 : : spdk_blob_id blobid;
4537 : : uint64_t free_clusters;
4538 : : uint64_t page_size;
4539 : 16 : uint8_t payload_read[10 * 4096];
4540 : 16 : uint8_t payload_write[10 * 4096];
4541 : : uint64_t write_bytes;
4542 : : uint64_t read_bytes;
4543 : : uint64_t io_unit;
4544 : :
4545 : 16 : free_clusters = spdk_bs_free_cluster_count(bs);
4546 : 16 : page_size = spdk_bs_get_page_size(bs);
4547 : :
4548 : 16 : ut_spdk_blob_opts_init(&opts);
4549 : 16 : opts.thin_provision = true;
4550 : 16 : opts.num_clusters = 5;
4551 : :
4552 : 16 : blob = ut_blob_create_and_open(bs, &opts);
4553 : 16 : blobid = spdk_blob_get_id(blob);
4554 : 16 : CU_ASSERT(free_clusters == spdk_bs_free_cluster_count(bs));
4555 : :
4556 : 16 : channel = spdk_bs_alloc_io_channel(bs);
4557 : 16 : CU_ASSERT(channel != NULL);
4558 : :
4559 : : /* Target specifically second cluster in a blob as first allocation */
4560 : 16 : io_unit = bs_cluster_to_page(bs, 1) * bs_io_unit_per_page(bs);
4561 : :
4562 : : /* Payload should be all zeros from unallocated clusters */
4563 : 16 : memset(payload_read, 0xFF, sizeof(payload_read));
4564 : 16 : spdk_blob_io_read(blob, channel, payload_read, io_unit, 10, blob_op_complete, NULL);
4565 : 16 : poll_threads();
4566 : 16 : CU_ASSERT(g_bserrno == 0);
4567 : 16 : CU_ASSERT(memcmp(zero, payload_read, 10 * 4096) == 0);
4568 : :
4569 : 16 : write_bytes = g_dev_write_bytes;
4570 : 16 : read_bytes = g_dev_read_bytes;
4571 : :
4572 : : /* Issue write to second cluster in a blob */
4573 : 16 : memset(payload_write, 0xE5, sizeof(payload_write));
4574 : 16 : spdk_blob_io_write(blob, channel, payload_write, io_unit, 10, blob_op_complete, NULL);
4575 : 16 : poll_threads();
4576 : 16 : CU_ASSERT(g_bserrno == 0);
4577 : 16 : CU_ASSERT(free_clusters - 1 == spdk_bs_free_cluster_count(bs));
4578 : : /* For thin-provisioned blob we need to write 10 pages plus one page metadata and
4579 : : * read 0 bytes */
4580 [ + + + + ]: 16 : if (g_use_extent_table) {
4581 : : /* Add one more page for EXTENT_PAGE write */
4582 : 8 : CU_ASSERT(g_dev_write_bytes - write_bytes == page_size * 12);
4583 : : } else {
4584 : 8 : CU_ASSERT(g_dev_write_bytes - write_bytes == page_size * 11);
4585 : : }
4586 : 16 : CU_ASSERT(g_dev_read_bytes - read_bytes == 0);
4587 : :
4588 : 16 : spdk_blob_io_read(blob, channel, payload_read, io_unit, 10, blob_op_complete, NULL);
4589 : 16 : poll_threads();
4590 : 16 : CU_ASSERT(g_bserrno == 0);
4591 : 16 : CU_ASSERT(memcmp(payload_write, payload_read, 10 * 4096) == 0);
4592 : :
4593 : 16 : spdk_bs_free_io_channel(channel);
4594 : 16 : poll_threads();
4595 : :
4596 : 16 : spdk_blob_close(blob, blob_op_complete, NULL);
4597 : 16 : poll_threads();
4598 : 16 : CU_ASSERT(g_bserrno == 0);
4599 : :
4600 : 16 : ut_bs_reload(&bs, NULL);
4601 : :
4602 : 16 : spdk_bs_open_blob(bs, blobid, blob_op_with_handle_complete, NULL);
4603 : 16 : poll_threads();
4604 : 16 : CU_ASSERT(g_bserrno == 0);
4605 [ - + ]: 16 : SPDK_CU_ASSERT_FATAL(g_blob != NULL);
4606 : 16 : blob = g_blob;
4607 : :
4608 : 16 : channel = spdk_bs_alloc_io_channel(bs);
4609 : 16 : CU_ASSERT(channel != NULL);
4610 : :
4611 : : /* Read second cluster after blob reload to confirm data written */
4612 : 16 : spdk_blob_io_read(blob, channel, payload_read, io_unit, 10, blob_op_complete, NULL);
4613 : 16 : poll_threads();
4614 : 16 : CU_ASSERT(g_bserrno == 0);
4615 : 16 : CU_ASSERT(memcmp(payload_write, payload_read, 10 * 4096) == 0);
4616 : :
4617 : 16 : spdk_bs_free_io_channel(channel);
4618 : 16 : poll_threads();
4619 : :
4620 : 16 : ut_blob_close_and_delete(bs, blob);
4621 : 16 : }
4622 : :
4623 : : static void
4624 : 16 : blob_thin_prov_rw_iov(void)
4625 : : {
4626 : : static const uint8_t zero[10 * 4096] = { 0 };
4627 : 16 : struct spdk_blob_store *bs = g_bs;
4628 : : struct spdk_blob *blob;
4629 : : struct spdk_io_channel *channel;
4630 : 16 : struct spdk_blob_opts opts;
4631 : : uint64_t free_clusters;
4632 : 16 : uint8_t payload_read[10 * 4096];
4633 : 16 : uint8_t payload_write[10 * 4096];
4634 : 16 : struct iovec iov_read[3];
4635 : 16 : struct iovec iov_write[3];
4636 : :
4637 : 16 : free_clusters = spdk_bs_free_cluster_count(bs);
4638 : :
4639 : 16 : channel = spdk_bs_alloc_io_channel(bs);
4640 : 16 : CU_ASSERT(channel != NULL);
4641 : :
4642 : 16 : ut_spdk_blob_opts_init(&opts);
4643 : 16 : opts.thin_provision = true;
4644 : :
4645 : 16 : blob = ut_blob_create_and_open(bs, &opts);
4646 : 16 : CU_ASSERT(free_clusters == spdk_bs_free_cluster_count(bs));
4647 : :
4648 : 16 : CU_ASSERT(blob->active.num_clusters == 0);
4649 : :
4650 : : /* The blob started at 0 clusters. Resize it to be 5, but still unallocated. */
4651 : 16 : spdk_blob_resize(blob, 5, blob_op_complete, NULL);
4652 : 16 : poll_threads();
4653 : 16 : CU_ASSERT(g_bserrno == 0);
4654 : 16 : CU_ASSERT(free_clusters == spdk_bs_free_cluster_count(bs));
4655 : 16 : CU_ASSERT(blob->active.num_clusters == 5);
4656 : :
4657 : 16 : spdk_blob_sync_md(blob, blob_op_complete, NULL);
4658 : 16 : poll_threads();
4659 : 16 : CU_ASSERT(g_bserrno == 0);
4660 : : /* Sync must not change anything */
4661 : 16 : CU_ASSERT(free_clusters == spdk_bs_free_cluster_count(bs));
4662 : 16 : CU_ASSERT(blob->active.num_clusters == 5);
4663 : :
4664 : : /* Payload should be all zeros from unallocated clusters */
4665 : 16 : memset(payload_read, 0xAA, sizeof(payload_read));
4666 : 16 : iov_read[0].iov_base = payload_read;
4667 : 16 : iov_read[0].iov_len = 3 * 4096;
4668 : 16 : iov_read[1].iov_base = payload_read + 3 * 4096;
4669 : 16 : iov_read[1].iov_len = 4 * 4096;
4670 : 16 : iov_read[2].iov_base = payload_read + 7 * 4096;
4671 : 16 : iov_read[2].iov_len = 3 * 4096;
4672 : 16 : spdk_blob_io_readv(blob, channel, iov_read, 3, 250, 10, blob_op_complete, NULL);
4673 : 16 : poll_threads();
4674 : 16 : CU_ASSERT(g_bserrno == 0);
4675 : 16 : CU_ASSERT(memcmp(zero, payload_read, 10 * 4096) == 0);
4676 : :
4677 : 16 : memset(payload_write, 0xE5, sizeof(payload_write));
4678 : 16 : iov_write[0].iov_base = payload_write;
4679 : 16 : iov_write[0].iov_len = 1 * 4096;
4680 : 16 : iov_write[1].iov_base = payload_write + 1 * 4096;
4681 : 16 : iov_write[1].iov_len = 5 * 4096;
4682 : 16 : iov_write[2].iov_base = payload_write + 6 * 4096;
4683 : 16 : iov_write[2].iov_len = 4 * 4096;
4684 : :
4685 : 16 : spdk_blob_io_writev(blob, channel, iov_write, 3, 250, 10, blob_op_complete, NULL);
4686 : 16 : poll_threads();
4687 : 16 : CU_ASSERT(g_bserrno == 0);
4688 : :
4689 : 16 : memset(payload_read, 0xAA, sizeof(payload_read));
4690 : 16 : iov_read[0].iov_base = payload_read;
4691 : 16 : iov_read[0].iov_len = 3 * 4096;
4692 : 16 : iov_read[1].iov_base = payload_read + 3 * 4096;
4693 : 16 : iov_read[1].iov_len = 4 * 4096;
4694 : 16 : iov_read[2].iov_base = payload_read + 7 * 4096;
4695 : 16 : iov_read[2].iov_len = 3 * 4096;
4696 : 16 : spdk_blob_io_readv(blob, channel, iov_read, 3, 250, 10, blob_op_complete, NULL);
4697 : 16 : poll_threads();
4698 : 16 : CU_ASSERT(g_bserrno == 0);
4699 : 16 : CU_ASSERT(memcmp(payload_write, payload_read, 10 * 4096) == 0);
4700 : :
4701 : 16 : spdk_bs_free_io_channel(channel);
4702 : 16 : poll_threads();
4703 : :
4704 : 16 : ut_blob_close_and_delete(bs, blob);
4705 : 16 : }
4706 : :
4707 : : struct iter_ctx {
4708 : : int current_iter;
4709 : : spdk_blob_id blobid[4];
4710 : : };
4711 : :
4712 : : static void
4713 : 128 : test_iter(void *arg, struct spdk_blob *blob, int bserrno)
4714 : : {
4715 : 128 : struct iter_ctx *iter_ctx = arg;
4716 : : spdk_blob_id blobid;
4717 : :
4718 : 128 : CU_ASSERT(bserrno == 0);
4719 : 128 : blobid = spdk_blob_get_id(blob);
4720 : 128 : CU_ASSERT(blobid == iter_ctx->blobid[iter_ctx->current_iter++]);
4721 : 128 : }
4722 : :
4723 : : static void
4724 : 16 : bs_load_iter_test(void)
4725 : : {
4726 : : struct spdk_blob_store *bs;
4727 : : struct spdk_bs_dev *dev;
4728 : 16 : struct iter_ctx iter_ctx = { 0 };
4729 : : struct spdk_blob *blob;
4730 : : int i, rc;
4731 : 16 : struct spdk_bs_opts opts;
4732 : :
4733 : 16 : dev = init_dev();
4734 : 16 : spdk_bs_opts_init(&opts, sizeof(opts));
4735 : 16 : snprintf(opts.bstype.bstype, sizeof(opts.bstype.bstype), "TESTTYPE");
4736 : :
4737 : : /* Initialize a new blob store */
4738 : 16 : spdk_bs_init(dev, &opts, bs_op_with_handle_complete, NULL);
4739 : 16 : poll_threads();
4740 : 16 : CU_ASSERT(g_bserrno == 0);
4741 [ - + ]: 16 : SPDK_CU_ASSERT_FATAL(g_bs != NULL);
4742 : 16 : bs = g_bs;
4743 : :
4744 [ + + ]: 80 : for (i = 0; i < 4; i++) {
4745 : 64 : blob = ut_blob_create_and_open(bs, NULL);
4746 : 64 : iter_ctx.blobid[i] = spdk_blob_get_id(blob);
4747 : :
4748 : : /* Just save the blobid as an xattr for testing purposes. */
4749 : 64 : rc = spdk_blob_set_xattr(blob, "blobid", &iter_ctx.blobid[i], sizeof(spdk_blob_id));
4750 : 64 : CU_ASSERT(rc == 0);
4751 : :
4752 : : /* Resize the blob */
4753 : 64 : spdk_blob_resize(blob, i, blob_op_complete, NULL);
4754 : 64 : poll_threads();
4755 : 64 : CU_ASSERT(g_bserrno == 0);
4756 : :
4757 : 64 : spdk_blob_close(blob, blob_op_complete, NULL);
4758 : 64 : poll_threads();
4759 : 64 : CU_ASSERT(g_bserrno == 0);
4760 : : }
4761 : :
4762 : 16 : g_bserrno = -1;
4763 : 16 : spdk_bs_unload(bs, bs_op_complete, NULL);
4764 : 16 : poll_threads();
4765 : 16 : CU_ASSERT(g_bserrno == 0);
4766 : :
4767 : 16 : dev = init_dev();
4768 : 16 : spdk_bs_opts_init(&opts, sizeof(opts));
4769 : 16 : snprintf(opts.bstype.bstype, sizeof(opts.bstype.bstype), "TESTTYPE");
4770 : 16 : opts.iter_cb_fn = test_iter;
4771 : 16 : opts.iter_cb_arg = &iter_ctx;
4772 : :
4773 : : /* Test blob iteration during load after a clean shutdown. */
4774 : 16 : spdk_bs_load(dev, &opts, bs_op_with_handle_complete, NULL);
4775 : 16 : poll_threads();
4776 : 16 : CU_ASSERT(g_bserrno == 0);
4777 [ - + ]: 16 : SPDK_CU_ASSERT_FATAL(g_bs != NULL);
4778 : 16 : bs = g_bs;
4779 : :
4780 : : /* Dirty shutdown */
4781 : 16 : bs_free(bs);
4782 : :
4783 : 16 : dev = init_dev();
4784 : 16 : spdk_bs_opts_init(&opts, sizeof(opts));
4785 : 16 : snprintf(opts.bstype.bstype, sizeof(opts.bstype.bstype), "TESTTYPE");
4786 : 16 : opts.iter_cb_fn = test_iter;
4787 : 16 : iter_ctx.current_iter = 0;
4788 : 16 : opts.iter_cb_arg = &iter_ctx;
4789 : :
4790 : : /* Test blob iteration during load after a dirty shutdown. */
4791 : 16 : spdk_bs_load(dev, &opts, bs_op_with_handle_complete, NULL);
4792 : 16 : poll_threads();
4793 : 16 : CU_ASSERT(g_bserrno == 0);
4794 [ - + ]: 16 : SPDK_CU_ASSERT_FATAL(g_bs != NULL);
4795 : 16 : bs = g_bs;
4796 : :
4797 : 16 : spdk_bs_unload(bs, bs_op_complete, NULL);
4798 : 16 : poll_threads();
4799 : 16 : CU_ASSERT(g_bserrno == 0);
4800 : 16 : g_bs = NULL;
4801 : 16 : }
4802 : :
4803 : : static void
4804 : 16 : blob_snapshot_rw(void)
4805 : : {
4806 : : static const uint8_t zero[10 * 4096] = { 0 };
4807 : 16 : struct spdk_blob_store *bs = g_bs;
4808 : : struct spdk_blob *blob, *snapshot;
4809 : : struct spdk_io_channel *channel;
4810 : 16 : struct spdk_blob_opts opts;
4811 : : spdk_blob_id blobid, snapshotid;
4812 : : uint64_t free_clusters;
4813 : : uint64_t cluster_size;
4814 : : uint64_t page_size;
4815 : 16 : uint8_t payload_read[10 * 4096];
4816 : 16 : uint8_t payload_write[10 * 4096];
4817 : : uint64_t write_bytes_start;
4818 : : uint64_t read_bytes_start;
4819 : : uint64_t copy_bytes_start;
4820 : : uint64_t write_bytes;
4821 : : uint64_t read_bytes;
4822 : : uint64_t copy_bytes;
4823 : :
4824 : 16 : free_clusters = spdk_bs_free_cluster_count(bs);
4825 : 16 : cluster_size = spdk_bs_get_cluster_size(bs);
4826 : 16 : page_size = spdk_bs_get_page_size(bs);
4827 : :
4828 : 16 : channel = spdk_bs_alloc_io_channel(bs);
4829 : 16 : CU_ASSERT(channel != NULL);
4830 : :
4831 : 16 : ut_spdk_blob_opts_init(&opts);
4832 : 16 : opts.thin_provision = true;
4833 : 16 : opts.num_clusters = 5;
4834 : :
4835 : 16 : blob = ut_blob_create_and_open(bs, &opts);
4836 : 16 : blobid = spdk_blob_get_id(blob);
4837 : 16 : CU_ASSERT(free_clusters == spdk_bs_free_cluster_count(bs));
4838 : :
4839 : 16 : CU_ASSERT(spdk_blob_get_num_clusters(blob) == 5);
4840 : :
4841 : 16 : memset(payload_read, 0xFF, sizeof(payload_read));
4842 : 16 : spdk_blob_io_read(blob, channel, payload_read, 4, 10, blob_op_complete, NULL);
4843 : 16 : poll_threads();
4844 : 16 : CU_ASSERT(g_bserrno == 0);
4845 : 16 : CU_ASSERT(memcmp(zero, payload_read, 10 * 4096) == 0);
4846 : :
4847 : 16 : memset(payload_write, 0xE5, sizeof(payload_write));
4848 : 16 : spdk_blob_io_write(blob, channel, payload_write, 4, 10, blob_op_complete, NULL);
4849 : 16 : poll_threads();
4850 : 16 : CU_ASSERT(g_bserrno == 0);
4851 : 16 : CU_ASSERT(free_clusters != spdk_bs_free_cluster_count(bs));
4852 : :
4853 : : /* Create snapshot from blob */
4854 : 16 : spdk_bs_create_snapshot(bs, blobid, NULL, blob_op_with_id_complete, NULL);
4855 : 16 : poll_threads();
4856 : 16 : CU_ASSERT(g_bserrno == 0);
4857 : 16 : CU_ASSERT(g_blobid != SPDK_BLOBID_INVALID);
4858 : 16 : snapshotid = g_blobid;
4859 : :
4860 : 16 : spdk_bs_open_blob(bs, snapshotid, blob_op_with_handle_complete, NULL);
4861 : 16 : poll_threads();
4862 : 16 : CU_ASSERT(g_bserrno == 0);
4863 [ - + ]: 16 : SPDK_CU_ASSERT_FATAL(g_blob != NULL);
4864 : 16 : snapshot = g_blob;
4865 [ - + ]: 16 : CU_ASSERT(snapshot->data_ro == true);
4866 [ - + ]: 16 : CU_ASSERT(snapshot->md_ro == true);
4867 : :
4868 : 16 : CU_ASSERT(spdk_blob_get_num_clusters(snapshot) == 5);
4869 : :
4870 : 16 : write_bytes_start = g_dev_write_bytes;
4871 : 16 : read_bytes_start = g_dev_read_bytes;
4872 : 16 : copy_bytes_start = g_dev_copy_bytes;
4873 : :
4874 : 16 : memset(payload_write, 0xAA, sizeof(payload_write));
4875 : 16 : spdk_blob_io_write(blob, channel, payload_write, 4, 10, blob_op_complete, NULL);
4876 : 16 : poll_threads();
4877 : 16 : CU_ASSERT(g_bserrno == 0);
4878 : 16 : CU_ASSERT(free_clusters != spdk_bs_free_cluster_count(bs));
4879 : :
4880 : : /* For a clone we need to allocate and copy one cluster, update one page of metadata
4881 : : * and then write 10 pages of payload.
4882 : : */
4883 : 16 : write_bytes = g_dev_write_bytes - write_bytes_start;
4884 : 16 : read_bytes = g_dev_read_bytes - read_bytes_start;
4885 : 16 : copy_bytes = g_dev_copy_bytes - copy_bytes_start;
4886 [ + + + + ]: 16 : if (g_dev_copy_enabled) {
4887 : 8 : CU_ASSERT(copy_bytes == cluster_size);
4888 : : } else {
4889 : 8 : CU_ASSERT(copy_bytes == 0);
4890 : : }
4891 [ + + + + ]: 16 : if (g_use_extent_table) {
4892 : : /* Add one more page for EXTENT_PAGE write */
4893 : 8 : CU_ASSERT(write_bytes + copy_bytes == page_size * 12 + cluster_size);
4894 : : } else {
4895 : 8 : CU_ASSERT(write_bytes + copy_bytes == page_size * 11 + cluster_size);
4896 : : }
4897 : 16 : CU_ASSERT(read_bytes + copy_bytes == cluster_size);
4898 : :
4899 : 16 : spdk_blob_io_read(blob, channel, payload_read, 4, 10, blob_op_complete, NULL);
4900 : 16 : poll_threads();
4901 : 16 : CU_ASSERT(g_bserrno == 0);
4902 : 16 : CU_ASSERT(memcmp(payload_write, payload_read, 10 * 4096) == 0);
4903 : :
4904 : : /* Data on snapshot should not change after write to clone */
4905 : 16 : memset(payload_write, 0xE5, sizeof(payload_write));
4906 : 16 : spdk_blob_io_read(snapshot, channel, payload_read, 4, 10, blob_op_complete, NULL);
4907 : 16 : poll_threads();
4908 : 16 : CU_ASSERT(g_bserrno == 0);
4909 : 16 : CU_ASSERT(memcmp(payload_write, payload_read, 10 * 4096) == 0);
4910 : :
4911 : 16 : ut_blob_close_and_delete(bs, blob);
4912 : 16 : ut_blob_close_and_delete(bs, snapshot);
4913 : :
4914 : 16 : spdk_bs_free_io_channel(channel);
4915 : 16 : poll_threads();
4916 : 16 : g_blob = NULL;
4917 : 16 : g_blobid = 0;
4918 : 16 : }
4919 : :
4920 : : static void
4921 : 16 : blob_snapshot_rw_iov(void)
4922 : : {
4923 : : static const uint8_t zero[10 * 4096] = { 0 };
4924 : 16 : struct spdk_blob_store *bs = g_bs;
4925 : : struct spdk_blob *blob, *snapshot;
4926 : : struct spdk_io_channel *channel;
4927 : 16 : struct spdk_blob_opts opts;
4928 : : spdk_blob_id blobid, snapshotid;
4929 : : uint64_t free_clusters;
4930 : 16 : uint8_t payload_read[10 * 4096];
4931 : 16 : uint8_t payload_write[10 * 4096];
4932 : 16 : struct iovec iov_read[3];
4933 : 16 : struct iovec iov_write[3];
4934 : :
4935 : 16 : free_clusters = spdk_bs_free_cluster_count(bs);
4936 : :
4937 : 16 : channel = spdk_bs_alloc_io_channel(bs);
4938 : 16 : CU_ASSERT(channel != NULL);
4939 : :
4940 : 16 : ut_spdk_blob_opts_init(&opts);
4941 : 16 : opts.thin_provision = true;
4942 : 16 : opts.num_clusters = 5;
4943 : :
4944 : 16 : blob = ut_blob_create_and_open(bs, &opts);
4945 : 16 : blobid = spdk_blob_get_id(blob);
4946 : 16 : CU_ASSERT(free_clusters == spdk_bs_free_cluster_count(bs));
4947 : :
4948 : 16 : CU_ASSERT(spdk_blob_get_num_clusters(blob) == 5);
4949 : :
4950 : : /* Create snapshot from blob */
4951 : 16 : spdk_bs_create_snapshot(bs, blobid, NULL, blob_op_with_id_complete, NULL);
4952 : 16 : poll_threads();
4953 : 16 : CU_ASSERT(g_bserrno == 0);
4954 : 16 : CU_ASSERT(g_blobid != SPDK_BLOBID_INVALID);
4955 : 16 : snapshotid = g_blobid;
4956 : :
4957 : 16 : spdk_bs_open_blob(bs, snapshotid, blob_op_with_handle_complete, NULL);
4958 : 16 : poll_threads();
4959 : 16 : CU_ASSERT(g_bserrno == 0);
4960 [ - + ]: 16 : SPDK_CU_ASSERT_FATAL(g_blob != NULL);
4961 : 16 : snapshot = g_blob;
4962 [ - + ]: 16 : CU_ASSERT(snapshot->data_ro == true);
4963 [ - + ]: 16 : CU_ASSERT(snapshot->md_ro == true);
4964 : 16 : CU_ASSERT(spdk_blob_get_num_clusters(snapshot) == 5);
4965 : :
4966 : : /* Payload should be all zeros from unallocated clusters */
4967 : 16 : memset(payload_read, 0xAA, sizeof(payload_read));
4968 : 16 : iov_read[0].iov_base = payload_read;
4969 : 16 : iov_read[0].iov_len = 3 * 4096;
4970 : 16 : iov_read[1].iov_base = payload_read + 3 * 4096;
4971 : 16 : iov_read[1].iov_len = 4 * 4096;
4972 : 16 : iov_read[2].iov_base = payload_read + 7 * 4096;
4973 : 16 : iov_read[2].iov_len = 3 * 4096;
4974 : 16 : spdk_blob_io_readv(blob, channel, iov_read, 3, 250, 10, blob_op_complete, NULL);
4975 : 16 : poll_threads();
4976 : 16 : CU_ASSERT(g_bserrno == 0);
4977 : 16 : CU_ASSERT(memcmp(zero, payload_read, 10 * 4096) == 0);
4978 : :
4979 : 16 : memset(payload_write, 0xE5, sizeof(payload_write));
4980 : 16 : iov_write[0].iov_base = payload_write;
4981 : 16 : iov_write[0].iov_len = 1 * 4096;
4982 : 16 : iov_write[1].iov_base = payload_write + 1 * 4096;
4983 : 16 : iov_write[1].iov_len = 5 * 4096;
4984 : 16 : iov_write[2].iov_base = payload_write + 6 * 4096;
4985 : 16 : iov_write[2].iov_len = 4 * 4096;
4986 : :
4987 : 16 : spdk_blob_io_writev(blob, channel, iov_write, 3, 250, 10, blob_op_complete, NULL);
4988 : 16 : poll_threads();
4989 : 16 : CU_ASSERT(g_bserrno == 0);
4990 : :
4991 : 16 : memset(payload_read, 0xAA, sizeof(payload_read));
4992 : 16 : iov_read[0].iov_base = payload_read;
4993 : 16 : iov_read[0].iov_len = 3 * 4096;
4994 : 16 : iov_read[1].iov_base = payload_read + 3 * 4096;
4995 : 16 : iov_read[1].iov_len = 4 * 4096;
4996 : 16 : iov_read[2].iov_base = payload_read + 7 * 4096;
4997 : 16 : iov_read[2].iov_len = 3 * 4096;
4998 : 16 : spdk_blob_io_readv(blob, channel, iov_read, 3, 250, 10, blob_op_complete, NULL);
4999 : 16 : poll_threads();
5000 : 16 : CU_ASSERT(g_bserrno == 0);
5001 : 16 : CU_ASSERT(memcmp(payload_write, payload_read, 10 * 4096) == 0);
5002 : :
5003 : 16 : spdk_bs_free_io_channel(channel);
5004 : 16 : poll_threads();
5005 : :
5006 : 16 : ut_blob_close_and_delete(bs, blob);
5007 : 16 : ut_blob_close_and_delete(bs, snapshot);
5008 : 16 : }
5009 : :
5010 : : /**
5011 : : * Inflate / decouple parent rw unit tests.
5012 : : *
5013 : : * --------------
5014 : : * original blob: 0 1 2 3 4
5015 : : * ,---------+---------+---------+---------+---------.
5016 : : * snapshot |xxxxxxxxx|xxxxxxxxx|xxxxxxxxx|xxxxxxxxx| - |
5017 : : * +---------+---------+---------+---------+---------+
5018 : : * snapshot2 | - |yyyyyyyyy| - |yyyyyyyyy| - |
5019 : : * +---------+---------+---------+---------+---------+
5020 : : * blob | - |zzzzzzzzz| - | - | - |
5021 : : * '---------+---------+---------+---------+---------'
5022 : : * . . . . . .
5023 : : * -------- . . . . . .
5024 : : * inflate: . . . . . .
5025 : : * ,---------+---------+---------+---------+---------.
5026 : : * blob |xxxxxxxxx|zzzzzzzzz|xxxxxxxxx|yyyyyyyyy|000000000|
5027 : : * '---------+---------+---------+---------+---------'
5028 : : *
5029 : : * NOTE: needs to allocate 4 clusters, thin provisioning removed, dependency
5030 : : * on snapshot2 and snapshot removed . . .
5031 : : * . . . . . .
5032 : : * ---------------- . . . . . .
5033 : : * decouple parent: . . . . . .
5034 : : * ,---------+---------+---------+---------+---------.
5035 : : * snapshot |xxxxxxxxx|xxxxxxxxx|xxxxxxxxx|xxxxxxxxx| - |
5036 : : * +---------+---------+---------+---------+---------+
5037 : : * blob | - |zzzzzzzzz| - |yyyyyyyyy| - |
5038 : : * '---------+---------+---------+---------+---------'
5039 : : *
5040 : : * NOTE: needs to allocate 1 cluster, 3 clusters unallocated, dependency
5041 : : * on snapshot2 removed and on snapshot still exists. Snapshot2
5042 : : * should remain a clone of snapshot.
5043 : : */
5044 : : static void
5045 : 32 : _blob_inflate_rw(bool decouple_parent)
5046 : : {
5047 : 32 : struct spdk_blob_store *bs = g_bs;
5048 : : struct spdk_blob *blob, *snapshot, *snapshot2;
5049 : : struct spdk_io_channel *channel;
5050 : 32 : struct spdk_blob_opts opts;
5051 : : spdk_blob_id blobid, snapshotid, snapshot2id;
5052 : : uint64_t free_clusters;
5053 : : uint64_t cluster_size;
5054 : :
5055 : : uint64_t payload_size;
5056 : : uint8_t *payload_read;
5057 : : uint8_t *payload_write;
5058 : : uint8_t *payload_clone;
5059 : :
5060 : : uint64_t pages_per_cluster;
5061 : : uint64_t pages_per_payload;
5062 : :
5063 : : int i;
5064 : 32 : spdk_blob_id ids[2];
5065 : 32 : size_t count;
5066 : :
5067 : 32 : free_clusters = spdk_bs_free_cluster_count(bs);
5068 : 32 : cluster_size = spdk_bs_get_cluster_size(bs);
5069 [ - + ]: 32 : pages_per_cluster = cluster_size / spdk_bs_get_page_size(bs);
5070 : 32 : pages_per_payload = pages_per_cluster * 5;
5071 : :
5072 : 32 : payload_size = cluster_size * 5;
5073 : :
5074 : 32 : payload_read = malloc(payload_size);
5075 [ - + ]: 32 : SPDK_CU_ASSERT_FATAL(payload_read != NULL);
5076 : :
5077 : 32 : payload_write = malloc(payload_size);
5078 [ - + ]: 32 : SPDK_CU_ASSERT_FATAL(payload_write != NULL);
5079 : :
5080 : 32 : payload_clone = malloc(payload_size);
5081 [ - + ]: 32 : SPDK_CU_ASSERT_FATAL(payload_clone != NULL);
5082 : :
5083 : 32 : channel = spdk_bs_alloc_io_channel(bs);
5084 [ - + ]: 32 : SPDK_CU_ASSERT_FATAL(channel != NULL);
5085 : :
5086 : : /* Create blob */
5087 : 32 : ut_spdk_blob_opts_init(&opts);
5088 : 32 : opts.thin_provision = true;
5089 : 32 : opts.num_clusters = 5;
5090 : :
5091 : 32 : blob = ut_blob_create_and_open(bs, &opts);
5092 : 32 : blobid = spdk_blob_get_id(blob);
5093 : 32 : CU_ASSERT(free_clusters == spdk_bs_free_cluster_count(bs));
5094 : :
5095 : 32 : CU_ASSERT(spdk_blob_get_num_clusters(blob) == 5);
5096 : :
5097 : : /* 1) Initial read should return zeroed payload */
5098 [ - + ]: 32 : memset(payload_read, 0xFF, payload_size);
5099 : 32 : spdk_blob_io_read(blob, channel, payload_read, 0, pages_per_payload,
5100 : : blob_op_complete, NULL);
5101 : 32 : poll_threads();
5102 : 32 : CU_ASSERT(g_bserrno == 0);
5103 : 32 : CU_ASSERT(spdk_mem_all_zero(payload_read, payload_size));
5104 : :
5105 : : /* Fill whole blob with a pattern, except last cluster (to be sure it
5106 : : * isn't allocated) */
5107 [ - + ]: 32 : memset(payload_write, 0xE5, payload_size - cluster_size);
5108 : 32 : spdk_blob_io_write(blob, channel, payload_write, 0, pages_per_payload -
5109 : : pages_per_cluster, blob_op_complete, NULL);
5110 : 32 : poll_threads();
5111 : 32 : CU_ASSERT(g_bserrno == 0);
5112 : 32 : CU_ASSERT(free_clusters != spdk_bs_free_cluster_count(bs));
5113 : :
5114 : : /* 2) Create snapshot from blob (first level) */
5115 : 32 : spdk_bs_create_snapshot(bs, blobid, NULL, blob_op_with_id_complete, NULL);
5116 : 32 : poll_threads();
5117 : 32 : CU_ASSERT(g_bserrno == 0);
5118 : 32 : CU_ASSERT(g_blobid != SPDK_BLOBID_INVALID);
5119 : 32 : snapshotid = g_blobid;
5120 : :
5121 : 32 : spdk_bs_open_blob(bs, snapshotid, blob_op_with_handle_complete, NULL);
5122 : 32 : poll_threads();
5123 : 32 : CU_ASSERT(g_bserrno == 0);
5124 [ - + ]: 32 : SPDK_CU_ASSERT_FATAL(g_blob != NULL);
5125 : 32 : snapshot = g_blob;
5126 [ - + ]: 32 : CU_ASSERT(snapshot->data_ro == true);
5127 [ - + ]: 32 : CU_ASSERT(snapshot->md_ro == true);
5128 : :
5129 : 32 : CU_ASSERT(spdk_blob_get_num_clusters(snapshot) == 5);
5130 : :
5131 : : /* Write every second cluster with a pattern.
5132 : : *
5133 : : * Last cluster shouldn't be written, to be sure that snapshot nor clone
5134 : : * doesn't allocate it.
5135 : : *
5136 : : * payload_clone stores expected result on "blob" read at the time and
5137 : : * is used only to check data consistency on clone before and after
5138 : : * inflation. Initially we fill it with a backing snapshots pattern
5139 : : * used before.
5140 : : */
5141 [ - + ]: 32 : memset(payload_clone, 0xE5, payload_size - cluster_size);
5142 [ - + ]: 32 : memset(payload_clone + payload_size - cluster_size, 0x00, cluster_size);
5143 [ - + ]: 32 : memset(payload_write, 0xAA, payload_size);
5144 [ + + ]: 96 : for (i = 1; i < 5; i += 2) {
5145 : 64 : spdk_blob_io_write(blob, channel, payload_write, i * pages_per_cluster,
5146 : : pages_per_cluster, blob_op_complete, NULL);
5147 : 64 : poll_threads();
5148 : 64 : CU_ASSERT(g_bserrno == 0);
5149 : :
5150 : : /* Update expected result */
5151 [ - + - + ]: 64 : memcpy(payload_clone + (cluster_size * i), payload_write,
5152 : : cluster_size);
5153 : : }
5154 : 32 : CU_ASSERT(free_clusters != spdk_bs_free_cluster_count(bs));
5155 : :
5156 : : /* Check data consistency on clone */
5157 [ - + ]: 32 : memset(payload_read, 0xFF, payload_size);
5158 : 32 : spdk_blob_io_read(blob, channel, payload_read, 0, pages_per_payload,
5159 : : blob_op_complete, NULL);
5160 : 32 : poll_threads();
5161 : 32 : CU_ASSERT(g_bserrno == 0);
5162 [ - + - + ]: 32 : CU_ASSERT(memcmp(payload_clone, payload_read, payload_size) == 0);
5163 : :
5164 : : /* 3) Create second levels snapshot from blob */
5165 : 32 : spdk_bs_create_snapshot(bs, blobid, NULL, blob_op_with_id_complete, NULL);
5166 : 32 : poll_threads();
5167 : 32 : CU_ASSERT(g_bserrno == 0);
5168 : 32 : CU_ASSERT(g_blobid != SPDK_BLOBID_INVALID);
5169 : 32 : snapshot2id = g_blobid;
5170 : :
5171 : 32 : spdk_bs_open_blob(bs, snapshot2id, blob_op_with_handle_complete, NULL);
5172 : 32 : poll_threads();
5173 : 32 : CU_ASSERT(g_bserrno == 0);
5174 [ - + ]: 32 : SPDK_CU_ASSERT_FATAL(g_blob != NULL);
5175 : 32 : snapshot2 = g_blob;
5176 [ - + ]: 32 : CU_ASSERT(snapshot2->data_ro == true);
5177 [ - + ]: 32 : CU_ASSERT(snapshot2->md_ro == true);
5178 : :
5179 : 32 : CU_ASSERT(spdk_blob_get_num_clusters(snapshot2) == 5);
5180 : :
5181 : 32 : CU_ASSERT(snapshot2->parent_id == snapshotid);
5182 : :
5183 : : /* Write one cluster on the top level blob. This cluster (1) covers
5184 : : * already allocated cluster in the snapshot2, so shouldn't be inflated
5185 : : * at all */
5186 : 32 : spdk_blob_io_write(blob, channel, payload_write, pages_per_cluster,
5187 : : pages_per_cluster, blob_op_complete, NULL);
5188 : 32 : poll_threads();
5189 : 32 : CU_ASSERT(g_bserrno == 0);
5190 : :
5191 : : /* Update expected result */
5192 [ - + - + ]: 32 : memcpy(payload_clone + cluster_size, payload_write, cluster_size);
5193 : :
5194 : : /* Check data consistency on clone */
5195 [ - + ]: 32 : memset(payload_read, 0xFF, payload_size);
5196 : 32 : spdk_blob_io_read(blob, channel, payload_read, 0, pages_per_payload,
5197 : : blob_op_complete, NULL);
5198 : 32 : poll_threads();
5199 : 32 : CU_ASSERT(g_bserrno == 0);
5200 [ - + - + ]: 32 : CU_ASSERT(memcmp(payload_clone, payload_read, payload_size) == 0);
5201 : :
5202 : :
5203 : : /* Close all blobs */
5204 : 32 : spdk_blob_close(blob, blob_op_complete, NULL);
5205 : 32 : poll_threads();
5206 : 32 : CU_ASSERT(g_bserrno == 0);
5207 : :
5208 : 32 : spdk_blob_close(snapshot2, blob_op_complete, NULL);
5209 : 32 : poll_threads();
5210 : 32 : CU_ASSERT(g_bserrno == 0);
5211 : :
5212 : 32 : spdk_blob_close(snapshot, blob_op_complete, NULL);
5213 : 32 : poll_threads();
5214 : 32 : CU_ASSERT(g_bserrno == 0);
5215 : :
5216 : : /* Check snapshot-clone relations */
5217 : 32 : count = 2;
5218 : 32 : CU_ASSERT(spdk_blob_get_clones(bs, snapshotid, ids, &count) == 0);
5219 : 32 : CU_ASSERT(count == 1);
5220 : 32 : CU_ASSERT(ids[0] == snapshot2id);
5221 : :
5222 : 32 : count = 2;
5223 : 32 : CU_ASSERT(spdk_blob_get_clones(bs, snapshot2id, ids, &count) == 0);
5224 : 32 : CU_ASSERT(count == 1);
5225 : 32 : CU_ASSERT(ids[0] == blobid);
5226 : :
5227 : 32 : CU_ASSERT(spdk_blob_get_parent_snapshot(bs, blobid) == snapshot2id);
5228 : :
5229 : 32 : free_clusters = spdk_bs_free_cluster_count(bs);
5230 [ + + ]: 32 : if (!decouple_parent) {
5231 : : /* Do full blob inflation */
5232 : 16 : spdk_bs_inflate_blob(bs, channel, blobid, blob_op_complete, NULL);
5233 : 16 : poll_threads();
5234 : 16 : CU_ASSERT(g_bserrno == 0);
5235 : :
5236 : : /* All clusters should be inflated (except one already allocated
5237 : : * in a top level blob) */
5238 : 16 : CU_ASSERT(spdk_bs_free_cluster_count(bs) == free_clusters - 4);
5239 : :
5240 : : /* Check if relation tree updated correctly */
5241 : 16 : count = 2;
5242 : 16 : CU_ASSERT(spdk_blob_get_clones(bs, snapshotid, ids, &count) == 0);
5243 : :
5244 : : /* snapshotid have one clone */
5245 : 16 : CU_ASSERT(count == 1);
5246 : 16 : CU_ASSERT(ids[0] == snapshot2id);
5247 : :
5248 : : /* snapshot2id have no clones */
5249 : 16 : count = 2;
5250 : 16 : CU_ASSERT(spdk_blob_get_clones(bs, snapshot2id, ids, &count) == 0);
5251 : 16 : CU_ASSERT(count == 0);
5252 : :
5253 : 16 : CU_ASSERT(spdk_blob_get_parent_snapshot(bs, blobid) == SPDK_BLOBID_INVALID);
5254 : : } else {
5255 : : /* Decouple parent of blob */
5256 : 16 : spdk_bs_blob_decouple_parent(bs, channel, blobid, blob_op_complete, NULL);
5257 : 16 : poll_threads();
5258 : 16 : CU_ASSERT(g_bserrno == 0);
5259 : :
5260 : : /* Only one cluster from a parent should be inflated (second one
5261 : : * is covered by a cluster written on a top level blob, and
5262 : : * already allocated) */
5263 : 16 : CU_ASSERT(spdk_bs_free_cluster_count(bs) == free_clusters - 1);
5264 : :
5265 : : /* Check if relation tree updated correctly */
5266 : 16 : count = 2;
5267 : 16 : CU_ASSERT(spdk_blob_get_clones(bs, snapshotid, ids, &count) == 0);
5268 : :
5269 : : /* snapshotid have two clones now */
5270 : 16 : CU_ASSERT(count == 2);
5271 [ + - + - ]: 16 : CU_ASSERT(ids[0] == blobid || ids[1] == blobid);
5272 [ - + - - ]: 16 : CU_ASSERT(ids[0] == snapshot2id || ids[1] == snapshot2id);
5273 : :
5274 : : /* snapshot2id have no clones */
5275 : 16 : count = 2;
5276 : 16 : CU_ASSERT(spdk_blob_get_clones(bs, snapshot2id, ids, &count) == 0);
5277 : 16 : CU_ASSERT(count == 0);
5278 : :
5279 : 16 : CU_ASSERT(spdk_blob_get_parent_snapshot(bs, blobid) == snapshotid);
5280 : : }
5281 : :
5282 : : /* Try to delete snapshot2 (should pass) */
5283 : 32 : spdk_bs_delete_blob(bs, snapshot2id, blob_op_complete, NULL);
5284 : 32 : poll_threads();
5285 : 32 : CU_ASSERT(g_bserrno == 0);
5286 : :
5287 : : /* Try to delete base snapshot */
5288 : 32 : spdk_bs_delete_blob(bs, snapshotid, blob_op_complete, NULL);
5289 : 32 : poll_threads();
5290 : 32 : CU_ASSERT(g_bserrno == 0);
5291 : :
5292 : : /* Reopen blob after snapshot deletion */
5293 : 32 : spdk_bs_open_blob(bs, blobid, blob_op_with_handle_complete, NULL);
5294 : 32 : poll_threads();
5295 : 32 : CU_ASSERT(g_bserrno == 0);
5296 [ - + ]: 32 : SPDK_CU_ASSERT_FATAL(g_blob != NULL);
5297 : 32 : blob = g_blob;
5298 : :
5299 : 32 : CU_ASSERT(spdk_blob_get_num_clusters(blob) == 5);
5300 : :
5301 : : /* Check data consistency on inflated blob */
5302 [ - + ]: 32 : memset(payload_read, 0xFF, payload_size);
5303 : 32 : spdk_blob_io_read(blob, channel, payload_read, 0, pages_per_payload,
5304 : : blob_op_complete, NULL);
5305 : 32 : poll_threads();
5306 : 32 : CU_ASSERT(g_bserrno == 0);
5307 [ - + - + ]: 32 : CU_ASSERT(memcmp(payload_clone, payload_read, payload_size) == 0);
5308 : :
5309 : 32 : spdk_bs_free_io_channel(channel);
5310 : 32 : poll_threads();
5311 : :
5312 : 32 : free(payload_read);
5313 : 32 : free(payload_write);
5314 : 32 : free(payload_clone);
5315 : :
5316 : 32 : ut_blob_close_and_delete(bs, blob);
5317 : 32 : }
5318 : :
5319 : : static void
5320 : 16 : blob_inflate_rw(void)
5321 : : {
5322 : 16 : _blob_inflate_rw(false);
5323 : 16 : _blob_inflate_rw(true);
5324 : 16 : }
5325 : :
5326 : : /**
5327 : : * Snapshot-clones relation test
5328 : : *
5329 : : * snapshot
5330 : : * |
5331 : : * +-----+-----+
5332 : : * | |
5333 : : * blob(ro) snapshot2
5334 : : * | |
5335 : : * clone2 clone
5336 : : */
5337 : : static void
5338 : 16 : blob_relations(void)
5339 : : {
5340 : 16 : struct spdk_blob_store *bs;
5341 : : struct spdk_bs_dev *dev;
5342 : 16 : struct spdk_bs_opts bs_opts;
5343 : 16 : struct spdk_blob_opts opts;
5344 : : struct spdk_blob *blob, *snapshot, *snapshot2, *clone, *clone2;
5345 : : spdk_blob_id blobid, cloneid, snapshotid, cloneid2, snapshotid2;
5346 : : int rc;
5347 : 16 : size_t count;
5348 : 16 : spdk_blob_id ids[10] = {};
5349 : :
5350 : 16 : dev = init_dev();
5351 : 16 : spdk_bs_opts_init(&bs_opts, sizeof(bs_opts));
5352 : 16 : snprintf(bs_opts.bstype.bstype, sizeof(bs_opts.bstype.bstype), "TESTTYPE");
5353 : :
5354 : 16 : spdk_bs_init(dev, &bs_opts, bs_op_with_handle_complete, NULL);
5355 : 16 : poll_threads();
5356 : 16 : CU_ASSERT(g_bserrno == 0);
5357 [ - + ]: 16 : SPDK_CU_ASSERT_FATAL(g_bs != NULL);
5358 : 16 : bs = g_bs;
5359 : :
5360 : : /* 1. Create blob with 10 clusters */
5361 : :
5362 : 16 : ut_spdk_blob_opts_init(&opts);
5363 : 16 : opts.num_clusters = 10;
5364 : :
5365 : 16 : blob = ut_blob_create_and_open(bs, &opts);
5366 : 16 : blobid = spdk_blob_get_id(blob);
5367 : :
5368 : 16 : CU_ASSERT(!spdk_blob_is_read_only(blob));
5369 : 16 : CU_ASSERT(!spdk_blob_is_snapshot(blob));
5370 : 16 : CU_ASSERT(!spdk_blob_is_clone(blob));
5371 : 16 : CU_ASSERT(!spdk_blob_is_thin_provisioned(blob));
5372 : :
5373 : : /* blob should not have underlying snapshot nor clones */
5374 : 16 : CU_ASSERT(blob->parent_id == SPDK_BLOBID_INVALID);
5375 : 16 : CU_ASSERT(spdk_blob_get_parent_snapshot(bs, blobid) == SPDK_BLOBID_INVALID);
5376 : 16 : count = SPDK_COUNTOF(ids);
5377 : 16 : rc = spdk_blob_get_clones(bs, blobid, ids, &count);
5378 : 16 : CU_ASSERT(rc == 0);
5379 : 16 : CU_ASSERT(count == 0);
5380 : :
5381 : :
5382 : : /* 2. Create snapshot */
5383 : :
5384 : 16 : spdk_bs_create_snapshot(bs, blobid, NULL, blob_op_with_id_complete, NULL);
5385 : 16 : poll_threads();
5386 : 16 : CU_ASSERT(g_bserrno == 0);
5387 : 16 : CU_ASSERT(g_blobid != SPDK_BLOBID_INVALID);
5388 : 16 : snapshotid = g_blobid;
5389 : :
5390 : 16 : spdk_bs_open_blob(bs, snapshotid, blob_op_with_handle_complete, NULL);
5391 : 16 : poll_threads();
5392 : 16 : CU_ASSERT(g_bserrno == 0);
5393 [ - + ]: 16 : SPDK_CU_ASSERT_FATAL(g_blob != NULL);
5394 : 16 : snapshot = g_blob;
5395 : :
5396 : 16 : CU_ASSERT(spdk_blob_is_read_only(snapshot));
5397 : 16 : CU_ASSERT(spdk_blob_is_snapshot(snapshot));
5398 : 16 : CU_ASSERT(!spdk_blob_is_clone(snapshot));
5399 : 16 : CU_ASSERT(snapshot->parent_id == SPDK_BLOBID_INVALID);
5400 : 16 : CU_ASSERT(spdk_blob_get_parent_snapshot(bs, snapshotid) == SPDK_BLOBID_INVALID);
5401 : :
5402 : : /* Check if original blob is converted to the clone of snapshot */
5403 : 16 : CU_ASSERT(!spdk_blob_is_read_only(blob));
5404 : 16 : CU_ASSERT(!spdk_blob_is_snapshot(blob));
5405 : 16 : CU_ASSERT(spdk_blob_is_clone(blob));
5406 : 16 : CU_ASSERT(spdk_blob_is_thin_provisioned(blob));
5407 : 16 : CU_ASSERT(blob->parent_id == snapshotid);
5408 : 16 : CU_ASSERT(spdk_blob_get_parent_snapshot(bs, blobid) == snapshotid);
5409 : :
5410 : 16 : count = SPDK_COUNTOF(ids);
5411 : 16 : rc = spdk_blob_get_clones(bs, snapshotid, ids, &count);
5412 : 16 : CU_ASSERT(rc == 0);
5413 : 16 : CU_ASSERT(count == 1);
5414 : 16 : CU_ASSERT(ids[0] == blobid);
5415 : :
5416 : :
5417 : : /* 3. Create clone from snapshot */
5418 : :
5419 : 16 : spdk_bs_create_clone(bs, snapshotid, NULL, blob_op_with_id_complete, NULL);
5420 : 16 : poll_threads();
5421 : 16 : CU_ASSERT(g_bserrno == 0);
5422 : 16 : CU_ASSERT(g_blobid != SPDK_BLOBID_INVALID);
5423 : 16 : cloneid = g_blobid;
5424 : :
5425 : 16 : spdk_bs_open_blob(bs, cloneid, blob_op_with_handle_complete, NULL);
5426 : 16 : poll_threads();
5427 : 16 : CU_ASSERT(g_bserrno == 0);
5428 [ - + ]: 16 : SPDK_CU_ASSERT_FATAL(g_blob != NULL);
5429 : 16 : clone = g_blob;
5430 : :
5431 : 16 : CU_ASSERT(!spdk_blob_is_read_only(clone));
5432 : 16 : CU_ASSERT(!spdk_blob_is_snapshot(clone));
5433 : 16 : CU_ASSERT(spdk_blob_is_clone(clone));
5434 : 16 : CU_ASSERT(spdk_blob_is_thin_provisioned(clone));
5435 : 16 : CU_ASSERT(clone->parent_id == snapshotid);
5436 : 16 : CU_ASSERT(spdk_blob_get_parent_snapshot(bs, cloneid) == snapshotid);
5437 : :
5438 : 16 : count = SPDK_COUNTOF(ids);
5439 : 16 : rc = spdk_blob_get_clones(bs, cloneid, ids, &count);
5440 : 16 : CU_ASSERT(rc == 0);
5441 : 16 : CU_ASSERT(count == 0);
5442 : :
5443 : : /* Check if clone is on the snapshot's list */
5444 : 16 : count = SPDK_COUNTOF(ids);
5445 : 16 : rc = spdk_blob_get_clones(bs, snapshotid, ids, &count);
5446 : 16 : CU_ASSERT(rc == 0);
5447 [ - + - - ]: 16 : CU_ASSERT(ids[0] == blobid || ids[1] == blobid);
5448 [ + - + - ]: 16 : CU_ASSERT(ids[0] == cloneid || ids[1] == cloneid);
5449 : :
5450 : :
5451 : : /* 4. Create snapshot of the clone */
5452 : :
5453 : 16 : spdk_bs_create_snapshot(bs, cloneid, NULL, blob_op_with_id_complete, NULL);
5454 : 16 : poll_threads();
5455 : 16 : CU_ASSERT(g_bserrno == 0);
5456 : 16 : CU_ASSERT(g_blobid != SPDK_BLOBID_INVALID);
5457 : 16 : snapshotid2 = g_blobid;
5458 : :
5459 : 16 : spdk_bs_open_blob(bs, snapshotid2, blob_op_with_handle_complete, NULL);
5460 : 16 : poll_threads();
5461 : 16 : CU_ASSERT(g_bserrno == 0);
5462 [ - + ]: 16 : SPDK_CU_ASSERT_FATAL(g_blob != NULL);
5463 : 16 : snapshot2 = g_blob;
5464 : :
5465 : 16 : CU_ASSERT(spdk_blob_is_read_only(snapshot2));
5466 : 16 : CU_ASSERT(spdk_blob_is_snapshot(snapshot2));
5467 : 16 : CU_ASSERT(spdk_blob_is_clone(snapshot2));
5468 : 16 : CU_ASSERT(snapshot2->parent_id == snapshotid);
5469 : 16 : CU_ASSERT(spdk_blob_get_parent_snapshot(bs, snapshotid2) == snapshotid);
5470 : :
5471 : : /* Check if clone is converted to the clone of snapshot2 and snapshot2
5472 : : * is a child of snapshot */
5473 : 16 : CU_ASSERT(!spdk_blob_is_read_only(clone));
5474 : 16 : CU_ASSERT(!spdk_blob_is_snapshot(clone));
5475 : 16 : CU_ASSERT(spdk_blob_is_clone(clone));
5476 : 16 : CU_ASSERT(spdk_blob_is_thin_provisioned(clone));
5477 : 16 : CU_ASSERT(clone->parent_id == snapshotid2);
5478 : 16 : CU_ASSERT(spdk_blob_get_parent_snapshot(bs, cloneid) == snapshotid2);
5479 : :
5480 : 16 : count = SPDK_COUNTOF(ids);
5481 : 16 : rc = spdk_blob_get_clones(bs, snapshotid2, ids, &count);
5482 : 16 : CU_ASSERT(rc == 0);
5483 : 16 : CU_ASSERT(count == 1);
5484 : 16 : CU_ASSERT(ids[0] == cloneid);
5485 : :
5486 : :
5487 : : /* 5. Try to create clone from read only blob */
5488 : :
5489 : : /* Mark blob as read only */
5490 : 16 : spdk_blob_set_read_only(blob);
5491 : 16 : spdk_blob_sync_md(blob, blob_op_complete, NULL);
5492 : 16 : poll_threads();
5493 : 16 : CU_ASSERT(g_bserrno == 0);
5494 : :
5495 : : /* Check if previously created blob is read only clone */
5496 : 16 : CU_ASSERT(spdk_blob_is_read_only(blob));
5497 : 16 : CU_ASSERT(!spdk_blob_is_snapshot(blob));
5498 : 16 : CU_ASSERT(spdk_blob_is_clone(blob));
5499 : 16 : CU_ASSERT(spdk_blob_is_thin_provisioned(blob));
5500 : :
5501 : : /* Create clone from read only blob */
5502 : 16 : spdk_bs_create_clone(bs, blobid, NULL, blob_op_with_id_complete, NULL);
5503 : 16 : poll_threads();
5504 : 16 : CU_ASSERT(g_bserrno == 0);
5505 : 16 : CU_ASSERT(g_blobid != SPDK_BLOBID_INVALID);
5506 : 16 : cloneid2 = g_blobid;
5507 : :
5508 : 16 : spdk_bs_open_blob(bs, cloneid2, blob_op_with_handle_complete, NULL);
5509 : 16 : poll_threads();
5510 : 16 : CU_ASSERT(g_bserrno == 0);
5511 [ - + ]: 16 : SPDK_CU_ASSERT_FATAL(g_blob != NULL);
5512 : 16 : clone2 = g_blob;
5513 : :
5514 : 16 : CU_ASSERT(!spdk_blob_is_read_only(clone2));
5515 : 16 : CU_ASSERT(!spdk_blob_is_snapshot(clone2));
5516 : 16 : CU_ASSERT(spdk_blob_is_clone(clone2));
5517 : 16 : CU_ASSERT(spdk_blob_is_thin_provisioned(clone2));
5518 : :
5519 : 16 : CU_ASSERT(spdk_blob_get_parent_snapshot(bs, cloneid2) == blobid);
5520 : :
5521 : 16 : count = SPDK_COUNTOF(ids);
5522 : 16 : rc = spdk_blob_get_clones(bs, blobid, ids, &count);
5523 : 16 : CU_ASSERT(rc == 0);
5524 : :
5525 : 16 : CU_ASSERT(count == 1);
5526 : 16 : CU_ASSERT(ids[0] == cloneid2);
5527 : :
5528 : : /* Close blobs */
5529 : :
5530 : 16 : spdk_blob_close(clone2, blob_op_complete, NULL);
5531 : 16 : poll_threads();
5532 : 16 : CU_ASSERT(g_bserrno == 0);
5533 : :
5534 : 16 : spdk_blob_close(blob, blob_op_complete, NULL);
5535 : 16 : poll_threads();
5536 : 16 : CU_ASSERT(g_bserrno == 0);
5537 : :
5538 : 16 : spdk_blob_close(clone, blob_op_complete, NULL);
5539 : 16 : poll_threads();
5540 : 16 : CU_ASSERT(g_bserrno == 0);
5541 : :
5542 : 16 : spdk_blob_close(snapshot, blob_op_complete, NULL);
5543 : 16 : poll_threads();
5544 : 16 : CU_ASSERT(g_bserrno == 0);
5545 : :
5546 : 16 : spdk_blob_close(snapshot2, blob_op_complete, NULL);
5547 : 16 : poll_threads();
5548 : 16 : CU_ASSERT(g_bserrno == 0);
5549 : :
5550 : : /* Try to delete snapshot with more than 1 clone */
5551 : 16 : spdk_bs_delete_blob(bs, snapshotid, blob_op_complete, NULL);
5552 : 16 : poll_threads();
5553 : 16 : CU_ASSERT(g_bserrno != 0);
5554 : :
5555 : 16 : ut_bs_reload(&bs, &bs_opts);
5556 : :
5557 : : /* NULL ids array should return number of clones in count */
5558 : 16 : count = SPDK_COUNTOF(ids);
5559 : 16 : rc = spdk_blob_get_clones(bs, snapshotid, NULL, &count);
5560 : 16 : CU_ASSERT(rc == -ENOMEM);
5561 : 16 : CU_ASSERT(count == 2);
5562 : :
5563 : : /* incorrect array size */
5564 : 16 : count = 1;
5565 : 16 : rc = spdk_blob_get_clones(bs, snapshotid, ids, &count);
5566 : 16 : CU_ASSERT(rc == -ENOMEM);
5567 : 16 : CU_ASSERT(count == 2);
5568 : :
5569 : :
5570 : : /* Verify structure of loaded blob store */
5571 : :
5572 : : /* snapshot */
5573 : 16 : CU_ASSERT(spdk_blob_get_parent_snapshot(bs, snapshotid) == SPDK_BLOBID_INVALID);
5574 : :
5575 : 16 : count = SPDK_COUNTOF(ids);
5576 : 16 : rc = spdk_blob_get_clones(bs, snapshotid, ids, &count);
5577 : 16 : CU_ASSERT(rc == 0);
5578 : 16 : CU_ASSERT(count == 2);
5579 [ - + - - ]: 16 : CU_ASSERT(ids[0] == blobid || ids[1] == blobid);
5580 [ + - + - ]: 16 : CU_ASSERT(ids[0] == snapshotid2 || ids[1] == snapshotid2);
5581 : :
5582 : : /* blob */
5583 : 16 : CU_ASSERT(spdk_blob_get_parent_snapshot(bs, blobid) == snapshotid);
5584 : 16 : count = SPDK_COUNTOF(ids);
5585 : 16 : rc = spdk_blob_get_clones(bs, blobid, ids, &count);
5586 : 16 : CU_ASSERT(rc == 0);
5587 : 16 : CU_ASSERT(count == 1);
5588 : 16 : CU_ASSERT(ids[0] == cloneid2);
5589 : :
5590 : : /* clone */
5591 : 16 : CU_ASSERT(spdk_blob_get_parent_snapshot(bs, cloneid) == snapshotid2);
5592 : 16 : count = SPDK_COUNTOF(ids);
5593 : 16 : rc = spdk_blob_get_clones(bs, cloneid, ids, &count);
5594 : 16 : CU_ASSERT(rc == 0);
5595 : 16 : CU_ASSERT(count == 0);
5596 : :
5597 : : /* snapshot2 */
5598 : 16 : CU_ASSERT(spdk_blob_get_parent_snapshot(bs, snapshotid2) == snapshotid);
5599 : 16 : count = SPDK_COUNTOF(ids);
5600 : 16 : rc = spdk_blob_get_clones(bs, snapshotid2, ids, &count);
5601 : 16 : CU_ASSERT(rc == 0);
5602 : 16 : CU_ASSERT(count == 1);
5603 : 16 : CU_ASSERT(ids[0] == cloneid);
5604 : :
5605 : : /* clone2 */
5606 : 16 : CU_ASSERT(spdk_blob_get_parent_snapshot(bs, cloneid2) == blobid);
5607 : 16 : count = SPDK_COUNTOF(ids);
5608 : 16 : rc = spdk_blob_get_clones(bs, cloneid2, ids, &count);
5609 : 16 : CU_ASSERT(rc == 0);
5610 : 16 : CU_ASSERT(count == 0);
5611 : :
5612 : : /* Try to delete blob that user should not be able to remove */
5613 : :
5614 : 16 : spdk_bs_delete_blob(bs, snapshotid, blob_op_complete, NULL);
5615 : 16 : poll_threads();
5616 : 16 : CU_ASSERT(g_bserrno != 0);
5617 : :
5618 : : /* Remove all blobs */
5619 : :
5620 : 16 : spdk_bs_delete_blob(bs, cloneid, blob_op_complete, NULL);
5621 : 16 : poll_threads();
5622 : 16 : CU_ASSERT(g_bserrno == 0);
5623 : :
5624 : 16 : spdk_bs_delete_blob(bs, snapshotid2, blob_op_complete, NULL);
5625 : 16 : poll_threads();
5626 : 16 : CU_ASSERT(g_bserrno == 0);
5627 : :
5628 : 16 : spdk_bs_delete_blob(bs, cloneid2, blob_op_complete, NULL);
5629 : 16 : poll_threads();
5630 : 16 : CU_ASSERT(g_bserrno == 0);
5631 : :
5632 : 16 : spdk_bs_delete_blob(bs, blobid, blob_op_complete, NULL);
5633 : 16 : poll_threads();
5634 : 16 : CU_ASSERT(g_bserrno == 0);
5635 : :
5636 : 16 : spdk_bs_delete_blob(bs, snapshotid, blob_op_complete, NULL);
5637 : 16 : poll_threads();
5638 : 16 : CU_ASSERT(g_bserrno == 0);
5639 : :
5640 : 16 : spdk_bs_unload(bs, bs_op_complete, NULL);
5641 : 16 : poll_threads();
5642 : 16 : CU_ASSERT(g_bserrno == 0);
5643 : :
5644 : 16 : g_bs = NULL;
5645 : 16 : }
5646 : :
5647 : : /**
5648 : : * Snapshot-clones relation test 2
5649 : : *
5650 : : * snapshot1
5651 : : * |
5652 : : * snapshot2
5653 : : * |
5654 : : * +-----+-----+
5655 : : * | |
5656 : : * blob(ro) snapshot3
5657 : : * | |
5658 : : * | snapshot4
5659 : : * | | |
5660 : : * clone2 clone clone3
5661 : : */
5662 : : static void
5663 : 16 : blob_relations2(void)
5664 : : {
5665 : 16 : struct spdk_blob_store *bs;
5666 : : struct spdk_bs_dev *dev;
5667 : 16 : struct spdk_bs_opts bs_opts;
5668 : 16 : struct spdk_blob_opts opts;
5669 : : struct spdk_blob *blob, *snapshot1, *snapshot2, *snapshot3, *snapshot4, *clone, *clone2;
5670 : : spdk_blob_id blobid, snapshotid1, snapshotid2, snapshotid3, snapshotid4, cloneid, cloneid2,
5671 : : cloneid3;
5672 : : int rc;
5673 : 16 : size_t count;
5674 : 16 : spdk_blob_id ids[10] = {};
5675 : :
5676 : 16 : dev = init_dev();
5677 : 16 : spdk_bs_opts_init(&bs_opts, sizeof(bs_opts));
5678 : 16 : snprintf(bs_opts.bstype.bstype, sizeof(bs_opts.bstype.bstype), "TESTTYPE");
5679 : :
5680 : 16 : spdk_bs_init(dev, &bs_opts, bs_op_with_handle_complete, NULL);
5681 : 16 : poll_threads();
5682 : 16 : CU_ASSERT(g_bserrno == 0);
5683 [ - + ]: 16 : SPDK_CU_ASSERT_FATAL(g_bs != NULL);
5684 : 16 : bs = g_bs;
5685 : :
5686 : : /* 1. Create blob with 10 clusters */
5687 : :
5688 : 16 : ut_spdk_blob_opts_init(&opts);
5689 : 16 : opts.num_clusters = 10;
5690 : :
5691 : 16 : blob = ut_blob_create_and_open(bs, &opts);
5692 : 16 : blobid = spdk_blob_get_id(blob);
5693 : :
5694 : : /* 2. Create snapshot1 */
5695 : :
5696 : 16 : spdk_bs_create_snapshot(bs, blobid, NULL, blob_op_with_id_complete, NULL);
5697 : 16 : poll_threads();
5698 : 16 : CU_ASSERT(g_bserrno == 0);
5699 : 16 : CU_ASSERT(g_blobid != SPDK_BLOBID_INVALID);
5700 : 16 : snapshotid1 = g_blobid;
5701 : :
5702 : 16 : spdk_bs_open_blob(bs, snapshotid1, blob_op_with_handle_complete, NULL);
5703 : 16 : poll_threads();
5704 : 16 : CU_ASSERT(g_bserrno == 0);
5705 [ - + ]: 16 : SPDK_CU_ASSERT_FATAL(g_blob != NULL);
5706 : 16 : snapshot1 = g_blob;
5707 : :
5708 : 16 : CU_ASSERT(snapshot1->parent_id == SPDK_BLOBID_INVALID);
5709 : 16 : CU_ASSERT(spdk_blob_get_parent_snapshot(bs, snapshotid1) == SPDK_BLOBID_INVALID);
5710 : :
5711 : 16 : CU_ASSERT(blob->parent_id == snapshotid1);
5712 : 16 : CU_ASSERT(spdk_blob_get_parent_snapshot(bs, blobid) == snapshotid1);
5713 : :
5714 : : /* Check if blob is the clone of snapshot1 */
5715 : 16 : CU_ASSERT(blob->parent_id == snapshotid1);
5716 : 16 : CU_ASSERT(spdk_blob_get_parent_snapshot(bs, blobid) == snapshotid1);
5717 : :
5718 : 16 : count = SPDK_COUNTOF(ids);
5719 : 16 : rc = spdk_blob_get_clones(bs, snapshotid1, ids, &count);
5720 : 16 : CU_ASSERT(rc == 0);
5721 : 16 : CU_ASSERT(count == 1);
5722 : 16 : CU_ASSERT(ids[0] == blobid);
5723 : :
5724 : : /* 3. Create another snapshot */
5725 : :
5726 : 16 : spdk_bs_create_snapshot(bs, blobid, NULL, blob_op_with_id_complete, NULL);
5727 : 16 : poll_threads();
5728 : 16 : CU_ASSERT(g_bserrno == 0);
5729 : 16 : CU_ASSERT(g_blobid != SPDK_BLOBID_INVALID);
5730 : 16 : snapshotid2 = g_blobid;
5731 : :
5732 : 16 : spdk_bs_open_blob(bs, snapshotid2, blob_op_with_handle_complete, NULL);
5733 : 16 : poll_threads();
5734 : 16 : CU_ASSERT(g_bserrno == 0);
5735 [ - + ]: 16 : SPDK_CU_ASSERT_FATAL(g_blob != NULL);
5736 : 16 : snapshot2 = g_blob;
5737 : :
5738 : 16 : CU_ASSERT(spdk_blob_is_clone(snapshot2));
5739 : 16 : CU_ASSERT(snapshot2->parent_id == snapshotid1);
5740 : 16 : CU_ASSERT(spdk_blob_get_parent_snapshot(bs, snapshotid2) == snapshotid1);
5741 : :
5742 : : /* Check if snapshot2 is the clone of snapshot1 and blob
5743 : : * is a child of snapshot2 */
5744 : 16 : CU_ASSERT(blob->parent_id == snapshotid2);
5745 : 16 : CU_ASSERT(spdk_blob_get_parent_snapshot(bs, blobid) == snapshotid2);
5746 : :
5747 : 16 : count = SPDK_COUNTOF(ids);
5748 : 16 : rc = spdk_blob_get_clones(bs, snapshotid2, ids, &count);
5749 : 16 : CU_ASSERT(rc == 0);
5750 : 16 : CU_ASSERT(count == 1);
5751 : 16 : CU_ASSERT(ids[0] == blobid);
5752 : :
5753 : : /* 4. Create clone from snapshot */
5754 : :
5755 : 16 : spdk_bs_create_clone(bs, snapshotid2, NULL, blob_op_with_id_complete, NULL);
5756 : 16 : poll_threads();
5757 : 16 : CU_ASSERT(g_bserrno == 0);
5758 : 16 : CU_ASSERT(g_blobid != SPDK_BLOBID_INVALID);
5759 : 16 : cloneid = g_blobid;
5760 : :
5761 : 16 : spdk_bs_open_blob(bs, cloneid, blob_op_with_handle_complete, NULL);
5762 : 16 : poll_threads();
5763 : 16 : CU_ASSERT(g_bserrno == 0);
5764 [ - + ]: 16 : SPDK_CU_ASSERT_FATAL(g_blob != NULL);
5765 : 16 : clone = g_blob;
5766 : :
5767 : 16 : CU_ASSERT(clone->parent_id == snapshotid2);
5768 : 16 : CU_ASSERT(spdk_blob_get_parent_snapshot(bs, cloneid) == snapshotid2);
5769 : :
5770 : : /* Check if clone is on the snapshot's list */
5771 : 16 : count = SPDK_COUNTOF(ids);
5772 : 16 : rc = spdk_blob_get_clones(bs, snapshotid2, ids, &count);
5773 : 16 : CU_ASSERT(rc == 0);
5774 : 16 : CU_ASSERT(count == 2);
5775 [ - + - - ]: 16 : CU_ASSERT(ids[0] == blobid || ids[1] == blobid);
5776 [ + - + - ]: 16 : CU_ASSERT(ids[0] == cloneid || ids[1] == cloneid);
5777 : :
5778 : : /* 5. Create snapshot of the clone */
5779 : :
5780 : 16 : spdk_bs_create_snapshot(bs, cloneid, NULL, blob_op_with_id_complete, NULL);
5781 : 16 : poll_threads();
5782 : 16 : CU_ASSERT(g_bserrno == 0);
5783 : 16 : CU_ASSERT(g_blobid != SPDK_BLOBID_INVALID);
5784 : 16 : snapshotid3 = g_blobid;
5785 : :
5786 : 16 : spdk_bs_open_blob(bs, snapshotid3, blob_op_with_handle_complete, NULL);
5787 : 16 : poll_threads();
5788 : 16 : CU_ASSERT(g_bserrno == 0);
5789 [ - + ]: 16 : SPDK_CU_ASSERT_FATAL(g_blob != NULL);
5790 : 16 : snapshot3 = g_blob;
5791 : :
5792 : 16 : CU_ASSERT(snapshot3->parent_id == snapshotid2);
5793 : 16 : CU_ASSERT(spdk_blob_get_parent_snapshot(bs, snapshotid3) == snapshotid2);
5794 : :
5795 : : /* Check if clone is converted to the clone of snapshot3 and snapshot3
5796 : : * is a child of snapshot2 */
5797 : 16 : CU_ASSERT(clone->parent_id == snapshotid3);
5798 : 16 : CU_ASSERT(spdk_blob_get_parent_snapshot(bs, cloneid) == snapshotid3);
5799 : :
5800 : 16 : count = SPDK_COUNTOF(ids);
5801 : 16 : rc = spdk_blob_get_clones(bs, snapshotid3, ids, &count);
5802 : 16 : CU_ASSERT(rc == 0);
5803 : 16 : CU_ASSERT(count == 1);
5804 : 16 : CU_ASSERT(ids[0] == cloneid);
5805 : :
5806 : : /* 6. Create another snapshot of the clone */
5807 : :
5808 : 16 : spdk_bs_create_snapshot(bs, cloneid, NULL, blob_op_with_id_complete, NULL);
5809 : 16 : poll_threads();
5810 : 16 : CU_ASSERT(g_bserrno == 0);
5811 : 16 : CU_ASSERT(g_blobid != SPDK_BLOBID_INVALID);
5812 : 16 : snapshotid4 = g_blobid;
5813 : :
5814 : 16 : spdk_bs_open_blob(bs, snapshotid4, blob_op_with_handle_complete, NULL);
5815 : 16 : poll_threads();
5816 : 16 : CU_ASSERT(g_bserrno == 0);
5817 [ - + ]: 16 : SPDK_CU_ASSERT_FATAL(g_blob != NULL);
5818 : 16 : snapshot4 = g_blob;
5819 : :
5820 : 16 : CU_ASSERT(snapshot4->parent_id == snapshotid3);
5821 : 16 : CU_ASSERT(spdk_blob_get_parent_snapshot(bs, snapshotid4) == snapshotid3);
5822 : :
5823 : : /* Check if clone is converted to the clone of snapshot4 and snapshot4
5824 : : * is a child of snapshot3 */
5825 : 16 : CU_ASSERT(clone->parent_id == snapshotid4);
5826 : 16 : CU_ASSERT(spdk_blob_get_parent_snapshot(bs, cloneid) == snapshotid4);
5827 : :
5828 : 16 : count = SPDK_COUNTOF(ids);
5829 : 16 : rc = spdk_blob_get_clones(bs, snapshotid4, ids, &count);
5830 : 16 : CU_ASSERT(rc == 0);
5831 : 16 : CU_ASSERT(count == 1);
5832 : 16 : CU_ASSERT(ids[0] == cloneid);
5833 : :
5834 : : /* 7. Remove snapshot 4 */
5835 : :
5836 : 16 : ut_blob_close_and_delete(bs, snapshot4);
5837 : :
5838 : : /* Check if relations are back to state from before creating snapshot 4 */
5839 : 16 : CU_ASSERT(clone->parent_id == snapshotid3);
5840 : 16 : CU_ASSERT(spdk_blob_get_parent_snapshot(bs, cloneid) == snapshotid3);
5841 : :
5842 : 16 : count = SPDK_COUNTOF(ids);
5843 : 16 : rc = spdk_blob_get_clones(bs, snapshotid3, ids, &count);
5844 : 16 : CU_ASSERT(rc == 0);
5845 : 16 : CU_ASSERT(count == 1);
5846 : 16 : CU_ASSERT(ids[0] == cloneid);
5847 : :
5848 : : /* 8. Create second clone of snapshot 3 and try to remove snapshot 3 */
5849 : :
5850 : 16 : spdk_bs_create_clone(bs, snapshotid3, NULL, blob_op_with_id_complete, NULL);
5851 : 16 : poll_threads();
5852 : 16 : CU_ASSERT(g_bserrno == 0);
5853 : 16 : CU_ASSERT(g_blobid != SPDK_BLOBID_INVALID);
5854 : 16 : cloneid3 = g_blobid;
5855 : :
5856 : 16 : spdk_bs_delete_blob(bs, snapshotid3, blob_op_complete, NULL);
5857 : 16 : poll_threads();
5858 : 16 : CU_ASSERT(g_bserrno != 0);
5859 : :
5860 : : /* 9. Open snapshot 3 again and try to remove it while clone 3 is closed */
5861 : :
5862 : 16 : spdk_bs_open_blob(bs, snapshotid3, blob_op_with_handle_complete, NULL);
5863 : 16 : poll_threads();
5864 : 16 : CU_ASSERT(g_bserrno == 0);
5865 [ - + ]: 16 : SPDK_CU_ASSERT_FATAL(g_blob != NULL);
5866 : 16 : snapshot3 = g_blob;
5867 : :
5868 : 16 : spdk_bs_delete_blob(bs, snapshotid3, blob_op_complete, NULL);
5869 : 16 : poll_threads();
5870 : 16 : CU_ASSERT(g_bserrno != 0);
5871 : :
5872 : 16 : spdk_blob_close(snapshot3, blob_op_complete, NULL);
5873 : 16 : poll_threads();
5874 : 16 : CU_ASSERT(g_bserrno == 0);
5875 : :
5876 : 16 : spdk_bs_delete_blob(bs, cloneid3, blob_op_complete, NULL);
5877 : 16 : poll_threads();
5878 : 16 : CU_ASSERT(g_bserrno == 0);
5879 : :
5880 : : /* 10. Remove snapshot 1 */
5881 : :
5882 : 16 : ut_blob_close_and_delete(bs, snapshot1);
5883 : :
5884 : : /* Check if relations are back to state from before creating snapshot 4 (before step 6) */
5885 : 16 : CU_ASSERT(snapshot2->parent_id == SPDK_BLOBID_INVALID);
5886 : 16 : CU_ASSERT(spdk_blob_get_parent_snapshot(bs, snapshotid2) == SPDK_BLOBID_INVALID);
5887 : :
5888 : 16 : count = SPDK_COUNTOF(ids);
5889 : 16 : rc = spdk_blob_get_clones(bs, snapshotid2, ids, &count);
5890 : 16 : CU_ASSERT(rc == 0);
5891 : 16 : CU_ASSERT(count == 2);
5892 [ - + - - ]: 16 : CU_ASSERT(ids[0] == blobid || ids[1] == blobid);
5893 [ + - + - ]: 16 : CU_ASSERT(ids[0] == snapshotid3 || ids[1] == snapshotid3);
5894 : :
5895 : : /* 11. Try to create clone from read only blob */
5896 : :
5897 : : /* Mark blob as read only */
5898 : 16 : spdk_blob_set_read_only(blob);
5899 : 16 : spdk_blob_sync_md(blob, blob_op_complete, NULL);
5900 : 16 : poll_threads();
5901 : 16 : CU_ASSERT(g_bserrno == 0);
5902 : :
5903 : : /* Create clone from read only blob */
5904 : 16 : spdk_bs_create_clone(bs, blobid, NULL, blob_op_with_id_complete, NULL);
5905 : 16 : poll_threads();
5906 : 16 : CU_ASSERT(g_bserrno == 0);
5907 : 16 : CU_ASSERT(g_blobid != SPDK_BLOBID_INVALID);
5908 : 16 : cloneid2 = g_blobid;
5909 : :
5910 : 16 : spdk_bs_open_blob(bs, cloneid2, blob_op_with_handle_complete, NULL);
5911 : 16 : poll_threads();
5912 : 16 : CU_ASSERT(g_bserrno == 0);
5913 [ - + ]: 16 : SPDK_CU_ASSERT_FATAL(g_blob != NULL);
5914 : 16 : clone2 = g_blob;
5915 : :
5916 : 16 : CU_ASSERT(spdk_blob_get_parent_snapshot(bs, cloneid2) == blobid);
5917 : :
5918 : 16 : count = SPDK_COUNTOF(ids);
5919 : 16 : rc = spdk_blob_get_clones(bs, blobid, ids, &count);
5920 : 16 : CU_ASSERT(rc == 0);
5921 : 16 : CU_ASSERT(count == 1);
5922 : 16 : CU_ASSERT(ids[0] == cloneid2);
5923 : :
5924 : : /* Close blobs */
5925 : :
5926 : 16 : spdk_blob_close(clone2, blob_op_complete, NULL);
5927 : 16 : poll_threads();
5928 : 16 : CU_ASSERT(g_bserrno == 0);
5929 : :
5930 : 16 : spdk_blob_close(blob, blob_op_complete, NULL);
5931 : 16 : poll_threads();
5932 : 16 : CU_ASSERT(g_bserrno == 0);
5933 : :
5934 : 16 : spdk_blob_close(clone, blob_op_complete, NULL);
5935 : 16 : poll_threads();
5936 : 16 : CU_ASSERT(g_bserrno == 0);
5937 : :
5938 : 16 : spdk_blob_close(snapshot2, blob_op_complete, NULL);
5939 : 16 : poll_threads();
5940 : 16 : CU_ASSERT(g_bserrno == 0);
5941 : :
5942 : 16 : spdk_blob_close(snapshot3, blob_op_complete, NULL);
5943 : 16 : poll_threads();
5944 : 16 : CU_ASSERT(g_bserrno == 0);
5945 : :
5946 : 16 : ut_bs_reload(&bs, &bs_opts);
5947 : :
5948 : : /* Verify structure of loaded blob store */
5949 : :
5950 : : /* snapshot2 */
5951 : 16 : CU_ASSERT(spdk_blob_get_parent_snapshot(bs, snapshotid2) == SPDK_BLOBID_INVALID);
5952 : :
5953 : 16 : count = SPDK_COUNTOF(ids);
5954 : 16 : rc = spdk_blob_get_clones(bs, snapshotid2, ids, &count);
5955 : 16 : CU_ASSERT(rc == 0);
5956 : 16 : CU_ASSERT(count == 2);
5957 [ - + - - ]: 16 : CU_ASSERT(ids[0] == blobid || ids[1] == blobid);
5958 [ + - + - ]: 16 : CU_ASSERT(ids[0] == snapshotid3 || ids[1] == snapshotid3);
5959 : :
5960 : : /* blob */
5961 : 16 : CU_ASSERT(spdk_blob_get_parent_snapshot(bs, blobid) == snapshotid2);
5962 : 16 : count = SPDK_COUNTOF(ids);
5963 : 16 : rc = spdk_blob_get_clones(bs, blobid, ids, &count);
5964 : 16 : CU_ASSERT(rc == 0);
5965 : 16 : CU_ASSERT(count == 1);
5966 : 16 : CU_ASSERT(ids[0] == cloneid2);
5967 : :
5968 : : /* clone */
5969 : 16 : CU_ASSERT(spdk_blob_get_parent_snapshot(bs, cloneid) == snapshotid3);
5970 : 16 : count = SPDK_COUNTOF(ids);
5971 : 16 : rc = spdk_blob_get_clones(bs, cloneid, ids, &count);
5972 : 16 : CU_ASSERT(rc == 0);
5973 : 16 : CU_ASSERT(count == 0);
5974 : :
5975 : : /* snapshot3 */
5976 : 16 : CU_ASSERT(spdk_blob_get_parent_snapshot(bs, snapshotid3) == snapshotid2);
5977 : 16 : count = SPDK_COUNTOF(ids);
5978 : 16 : rc = spdk_blob_get_clones(bs, snapshotid3, ids, &count);
5979 : 16 : CU_ASSERT(rc == 0);
5980 : 16 : CU_ASSERT(count == 1);
5981 : 16 : CU_ASSERT(ids[0] == cloneid);
5982 : :
5983 : : /* clone2 */
5984 : 16 : CU_ASSERT(spdk_blob_get_parent_snapshot(bs, cloneid2) == blobid);
5985 : 16 : count = SPDK_COUNTOF(ids);
5986 : 16 : rc = spdk_blob_get_clones(bs, cloneid2, ids, &count);
5987 : 16 : CU_ASSERT(rc == 0);
5988 : 16 : CU_ASSERT(count == 0);
5989 : :
5990 : : /* Try to delete all blobs in the worse possible order */
5991 : :
5992 : 16 : spdk_bs_delete_blob(bs, snapshotid2, blob_op_complete, NULL);
5993 : 16 : poll_threads();
5994 : 16 : CU_ASSERT(g_bserrno != 0);
5995 : :
5996 : 16 : spdk_bs_delete_blob(bs, snapshotid3, blob_op_complete, NULL);
5997 : 16 : poll_threads();
5998 : 16 : CU_ASSERT(g_bserrno == 0);
5999 : :
6000 : 16 : spdk_bs_delete_blob(bs, snapshotid2, blob_op_complete, NULL);
6001 : 16 : poll_threads();
6002 : 16 : CU_ASSERT(g_bserrno != 0);
6003 : :
6004 : 16 : spdk_bs_delete_blob(bs, cloneid, blob_op_complete, NULL);
6005 : 16 : poll_threads();
6006 : 16 : CU_ASSERT(g_bserrno == 0);
6007 : :
6008 : 16 : spdk_bs_delete_blob(bs, snapshotid2, blob_op_complete, NULL);
6009 : 16 : poll_threads();
6010 : 16 : CU_ASSERT(g_bserrno == 0);
6011 : :
6012 : 16 : spdk_bs_delete_blob(bs, blobid, blob_op_complete, NULL);
6013 : 16 : poll_threads();
6014 : 16 : CU_ASSERT(g_bserrno == 0);
6015 : :
6016 : 16 : spdk_bs_delete_blob(bs, cloneid2, blob_op_complete, NULL);
6017 : 16 : poll_threads();
6018 : 16 : CU_ASSERT(g_bserrno == 0);
6019 : :
6020 : 16 : spdk_bs_unload(bs, bs_op_complete, NULL);
6021 : 16 : poll_threads();
6022 : 16 : CU_ASSERT(g_bserrno == 0);
6023 : :
6024 : 16 : g_bs = NULL;
6025 : 16 : }
6026 : :
6027 : : /**
6028 : : * Snapshot-clones relation test 3
6029 : : *
6030 : : * snapshot0
6031 : : * |
6032 : : * snapshot1
6033 : : * |
6034 : : * snapshot2
6035 : : * |
6036 : : * blob
6037 : : */
6038 : : static void
6039 : 16 : blob_relations3(void)
6040 : : {
6041 : : struct spdk_blob_store *bs;
6042 : : struct spdk_bs_dev *dev;
6043 : : struct spdk_io_channel *channel;
6044 : 16 : struct spdk_bs_opts bs_opts;
6045 : 16 : struct spdk_blob_opts opts;
6046 : : struct spdk_blob *blob;
6047 : : spdk_blob_id blobid, snapshotid0, snapshotid1, snapshotid2;
6048 : :
6049 : 16 : dev = init_dev();
6050 : 16 : spdk_bs_opts_init(&bs_opts, sizeof(bs_opts));
6051 : 16 : snprintf(bs_opts.bstype.bstype, sizeof(bs_opts.bstype.bstype), "TESTTYPE");
6052 : :
6053 : 16 : spdk_bs_init(dev, &bs_opts, bs_op_with_handle_complete, NULL);
6054 : 16 : poll_threads();
6055 : 16 : CU_ASSERT(g_bserrno == 0);
6056 [ - + ]: 16 : SPDK_CU_ASSERT_FATAL(g_bs != NULL);
6057 : 16 : bs = g_bs;
6058 : :
6059 : 16 : channel = spdk_bs_alloc_io_channel(bs);
6060 [ - + ]: 16 : SPDK_CU_ASSERT_FATAL(channel != NULL);
6061 : :
6062 : : /* 1. Create blob with 10 clusters */
6063 : 16 : ut_spdk_blob_opts_init(&opts);
6064 : 16 : opts.num_clusters = 10;
6065 : :
6066 : 16 : blob = ut_blob_create_and_open(bs, &opts);
6067 : 16 : blobid = spdk_blob_get_id(blob);
6068 : :
6069 : : /* 2. Create snapshot0 */
6070 : 16 : spdk_bs_create_snapshot(bs, blobid, NULL, blob_op_with_id_complete, NULL);
6071 : 16 : poll_threads();
6072 : 16 : CU_ASSERT(g_bserrno == 0);
6073 : 16 : CU_ASSERT(g_blobid != SPDK_BLOBID_INVALID);
6074 : 16 : snapshotid0 = g_blobid;
6075 : :
6076 : : /* 3. Create snapshot1 */
6077 : 16 : spdk_bs_create_snapshot(bs, blobid, NULL, blob_op_with_id_complete, NULL);
6078 : 16 : poll_threads();
6079 : 16 : CU_ASSERT(g_bserrno == 0);
6080 : 16 : CU_ASSERT(g_blobid != SPDK_BLOBID_INVALID);
6081 : 16 : snapshotid1 = g_blobid;
6082 : :
6083 : : /* 4. Create snapshot2 */
6084 : 16 : spdk_bs_create_snapshot(bs, blobid, NULL, blob_op_with_id_complete, NULL);
6085 : 16 : poll_threads();
6086 : 16 : CU_ASSERT(g_bserrno == 0);
6087 : 16 : CU_ASSERT(g_blobid != SPDK_BLOBID_INVALID);
6088 : 16 : snapshotid2 = g_blobid;
6089 : :
6090 : : /* 5. Decouple blob */
6091 : 16 : spdk_bs_blob_decouple_parent(bs, channel, blobid, blob_op_complete, NULL);
6092 : 16 : poll_threads();
6093 : 16 : CU_ASSERT(g_bserrno == 0);
6094 : :
6095 : : /* 6. Decouple snapshot2. Make sure updating md of snapshot2 is possible */
6096 : 16 : spdk_bs_blob_decouple_parent(bs, channel, snapshotid2, blob_op_complete, NULL);
6097 : 16 : poll_threads();
6098 : 16 : CU_ASSERT(g_bserrno == 0);
6099 : :
6100 : : /* 7. Delete blob */
6101 : 16 : spdk_blob_close(blob, blob_op_complete, NULL);
6102 : 16 : poll_threads();
6103 : 16 : CU_ASSERT(g_bserrno == 0);
6104 : :
6105 : 16 : spdk_bs_delete_blob(bs, blobid, blob_op_complete, NULL);
6106 : 16 : poll_threads();
6107 : 16 : CU_ASSERT(g_bserrno == 0);
6108 : :
6109 : : /* 8. Delete snapshot2.
6110 : : * If md of snapshot 2 was updated, it should be possible to delete it */
6111 : 16 : spdk_bs_delete_blob(bs, snapshotid2, blob_op_complete, NULL);
6112 : 16 : poll_threads();
6113 : 16 : CU_ASSERT(g_bserrno == 0);
6114 : :
6115 : : /* Remove remaining blobs and unload bs */
6116 : 16 : spdk_bs_delete_blob(bs, snapshotid1, blob_op_complete, NULL);
6117 : 16 : poll_threads();
6118 : 16 : CU_ASSERT(g_bserrno == 0);
6119 : :
6120 : 16 : spdk_bs_delete_blob(bs, snapshotid0, blob_op_complete, NULL);
6121 : 16 : poll_threads();
6122 : 16 : CU_ASSERT(g_bserrno == 0);
6123 : :
6124 : 16 : spdk_bs_free_io_channel(channel);
6125 : 16 : poll_threads();
6126 : :
6127 : 16 : spdk_bs_unload(bs, bs_op_complete, NULL);
6128 : 16 : poll_threads();
6129 : 16 : CU_ASSERT(g_bserrno == 0);
6130 : :
6131 : 16 : g_bs = NULL;
6132 : 16 : }
6133 : :
6134 : : static void
6135 : 16 : blobstore_clean_power_failure(void)
6136 : : {
6137 : : struct spdk_blob_store *bs;
6138 : : struct spdk_blob *blob;
6139 : 16 : struct spdk_power_failure_thresholds thresholds = {};
6140 : 16 : bool clean = false;
6141 : 16 : struct spdk_bs_super_block *super = (struct spdk_bs_super_block *)&g_dev_buffer[0];
6142 : 16 : struct spdk_bs_super_block super_copy = {};
6143 : :
6144 : 16 : thresholds.general_threshold = 1;
6145 [ + + ]: 80 : while (!clean) {
6146 : : /* Create bs and blob */
6147 : 64 : suite_blob_setup();
6148 [ - + ]: 64 : SPDK_CU_ASSERT_FATAL(g_bs != NULL);
6149 [ - + ]: 64 : SPDK_CU_ASSERT_FATAL(g_blob != NULL);
6150 : 64 : bs = g_bs;
6151 : 64 : blob = g_blob;
6152 : :
6153 : : /* Super block should not change for rest of the UT,
6154 : : * save it and compare later. */
6155 : 64 : memcpy(&super_copy, super, sizeof(struct spdk_bs_super_block));
6156 [ - + ]: 64 : SPDK_CU_ASSERT_FATAL(super->clean == 0);
6157 [ - + - + ]: 64 : SPDK_CU_ASSERT_FATAL(bs->clean == 0);
6158 : :
6159 : : /* Force bs/super block in a clean state.
6160 : : * Along with marking blob dirty, to cause blob persist. */
6161 : 64 : blob->state = SPDK_BLOB_STATE_DIRTY;
6162 : 64 : bs->clean = 1;
6163 : 64 : super->clean = 1;
6164 : 64 : super->crc = blob_md_page_calc_crc(super);
6165 : :
6166 : 64 : g_bserrno = -1;
6167 : 64 : dev_set_power_failure_thresholds(thresholds);
6168 : 64 : spdk_blob_sync_md(blob, blob_op_complete, NULL);
6169 : 64 : poll_threads();
6170 : 64 : dev_reset_power_failure_event();
6171 : :
6172 [ + + ]: 64 : if (g_bserrno == 0) {
6173 : : /* After successful md sync, both bs and super block
6174 : : * should be marked as not clean. */
6175 [ - + - + ]: 16 : SPDK_CU_ASSERT_FATAL(bs->clean == 0);
6176 [ - + ]: 16 : SPDK_CU_ASSERT_FATAL(super->clean == 0);
6177 : 16 : clean = true;
6178 : : }
6179 : :
6180 : : /* Depending on the point of failure, super block was either updated or not. */
6181 : 64 : super_copy.clean = super->clean;
6182 : 64 : super_copy.crc = blob_md_page_calc_crc(&super_copy);
6183 : : /* Compare that the values in super block remained unchanged. */
6184 [ - + - + ]: 64 : SPDK_CU_ASSERT_FATAL(!memcmp(&super_copy, super, sizeof(struct spdk_bs_super_block)));
6185 : :
6186 : : /* Delete blob and unload bs */
6187 : 64 : suite_blob_cleanup();
6188 : :
6189 : 64 : thresholds.general_threshold++;
6190 : : }
6191 : 16 : }
6192 : :
6193 : : static void
6194 : 16 : blob_delete_snapshot_power_failure(void)
6195 : : {
6196 : : struct spdk_bs_dev *dev;
6197 : 16 : struct spdk_blob_store *bs;
6198 : 16 : struct spdk_blob_opts opts;
6199 : : struct spdk_blob *blob, *snapshot;
6200 : 16 : struct spdk_power_failure_thresholds thresholds = {};
6201 : : spdk_blob_id blobid, snapshotid;
6202 : 16 : const void *value;
6203 : 16 : size_t value_len;
6204 : 16 : size_t count;
6205 : 16 : spdk_blob_id ids[3] = {};
6206 : : int rc;
6207 : 16 : bool deleted = false;
6208 : 16 : int delete_snapshot_bserrno = -1;
6209 : :
6210 : 16 : thresholds.general_threshold = 1;
6211 [ + + ]: 160 : while (!deleted) {
6212 : 144 : dev = init_dev();
6213 : :
6214 : 144 : spdk_bs_init(dev, NULL, bs_op_with_handle_complete, NULL);
6215 : 144 : poll_threads();
6216 : 144 : CU_ASSERT(g_bserrno == 0);
6217 [ - + ]: 144 : SPDK_CU_ASSERT_FATAL(g_bs != NULL);
6218 : 144 : bs = g_bs;
6219 : :
6220 : : /* Create blob */
6221 : 144 : ut_spdk_blob_opts_init(&opts);
6222 : 144 : opts.num_clusters = 10;
6223 : :
6224 : 144 : spdk_bs_create_blob_ext(bs, &opts, blob_op_with_id_complete, NULL);
6225 : 144 : poll_threads();
6226 : 144 : CU_ASSERT(g_bserrno == 0);
6227 : 144 : CU_ASSERT(g_blobid != SPDK_BLOBID_INVALID);
6228 : 144 : blobid = g_blobid;
6229 : :
6230 : : /* Create snapshot */
6231 : 144 : spdk_bs_create_snapshot(bs, blobid, NULL, blob_op_with_id_complete, NULL);
6232 : 144 : poll_threads();
6233 : 144 : CU_ASSERT(g_bserrno == 0);
6234 : 144 : CU_ASSERT(g_blobid != SPDK_BLOBID_INVALID);
6235 : 144 : snapshotid = g_blobid;
6236 [ - + ]: 144 : SPDK_CU_ASSERT_FATAL(spdk_bit_pool_is_allocated(bs->used_clusters, 1));
6237 [ - + ]: 144 : SPDK_CU_ASSERT_FATAL(!spdk_bit_pool_is_allocated(bs->used_clusters, 11));
6238 : :
6239 : 144 : dev_set_power_failure_thresholds(thresholds);
6240 : :
6241 : 144 : spdk_bs_delete_blob(bs, snapshotid, blob_op_complete, NULL);
6242 : 144 : poll_threads();
6243 : 144 : delete_snapshot_bserrno = g_bserrno;
6244 : :
6245 : : /* Do not shut down cleanly. Assumption is that after snapshot deletion
6246 : : * reports success, changes to both blobs should already persisted. */
6247 : 144 : dev_reset_power_failure_event();
6248 : 144 : ut_bs_dirty_load(&bs, NULL);
6249 : :
6250 [ - + ]: 144 : SPDK_CU_ASSERT_FATAL(spdk_bit_pool_is_allocated(bs->used_clusters, 1));
6251 [ - + ]: 144 : SPDK_CU_ASSERT_FATAL(!spdk_bit_pool_is_allocated(bs->used_clusters, 11));
6252 : :
6253 : 144 : spdk_bs_open_blob(bs, blobid, blob_op_with_handle_complete, NULL);
6254 : 144 : poll_threads();
6255 : 144 : CU_ASSERT(g_bserrno == 0);
6256 [ - + ]: 144 : SPDK_CU_ASSERT_FATAL(g_blob != NULL);
6257 : 144 : blob = g_blob;
6258 [ - + ]: 144 : SPDK_CU_ASSERT_FATAL(spdk_blob_is_thin_provisioned(blob) == true);
6259 : :
6260 : 144 : spdk_bs_open_blob(bs, snapshotid, blob_op_with_handle_complete, NULL);
6261 : 144 : poll_threads();
6262 : :
6263 [ + + ]: 144 : if (g_bserrno == 0) {
6264 [ - + ]: 96 : SPDK_CU_ASSERT_FATAL(g_blob != NULL);
6265 : 96 : snapshot = g_blob;
6266 : 96 : CU_ASSERT(spdk_blob_get_parent_snapshot(bs, blobid) == snapshotid);
6267 : 96 : count = SPDK_COUNTOF(ids);
6268 : 96 : rc = spdk_blob_get_clones(bs, snapshotid, ids, &count);
6269 : 96 : CU_ASSERT(rc == 0);
6270 : 96 : CU_ASSERT(count == 1);
6271 : 96 : CU_ASSERT(ids[0] == blobid);
6272 : 96 : rc = spdk_blob_get_xattr_value(snapshot, SNAPSHOT_PENDING_REMOVAL, &value, &value_len);
6273 : 96 : CU_ASSERT(rc != 0);
6274 [ - + ]: 96 : SPDK_CU_ASSERT_FATAL(spdk_blob_is_thin_provisioned(snapshot) == false);
6275 : :
6276 : 96 : spdk_blob_close(snapshot, blob_op_complete, NULL);
6277 : 96 : poll_threads();
6278 : 96 : CU_ASSERT(g_bserrno == 0);
6279 : : } else {
6280 : 48 : CU_ASSERT(spdk_blob_get_parent_snapshot(bs, blobid) == SPDK_BLOBID_INVALID);
6281 : : /* Snapshot might have been left in unrecoverable state, so it does not open.
6282 : : * Yet delete might perform further changes to the clone after that.
6283 : : * This UT should test until snapshot is deleted and delete call succeeds. */
6284 [ + + ]: 48 : if (delete_snapshot_bserrno == 0) {
6285 : 16 : deleted = true;
6286 : : }
6287 : : }
6288 : :
6289 : 144 : spdk_blob_close(blob, blob_op_complete, NULL);
6290 : 144 : poll_threads();
6291 : 144 : CU_ASSERT(g_bserrno == 0);
6292 : :
6293 : 144 : spdk_bs_unload(bs, bs_op_complete, NULL);
6294 : 144 : poll_threads();
6295 : 144 : CU_ASSERT(g_bserrno == 0);
6296 : :
6297 : 144 : thresholds.general_threshold++;
6298 : : }
6299 : 16 : }
6300 : :
6301 : : static void
6302 : 16 : blob_create_snapshot_power_failure(void)
6303 : : {
6304 : 16 : struct spdk_blob_store *bs = g_bs;
6305 : : struct spdk_bs_dev *dev;
6306 : 16 : struct spdk_blob_opts opts;
6307 : : struct spdk_blob *blob, *snapshot;
6308 : 16 : struct spdk_power_failure_thresholds thresholds = {};
6309 : : spdk_blob_id blobid, snapshotid;
6310 : 16 : const void *value;
6311 : 16 : size_t value_len;
6312 : 16 : size_t count;
6313 : 16 : spdk_blob_id ids[3] = {};
6314 : : int rc;
6315 : 16 : bool created = false;
6316 : 16 : int create_snapshot_bserrno = -1;
6317 : :
6318 : 16 : thresholds.general_threshold = 1;
6319 [ + + ]: 136 : while (!created) {
6320 : 120 : dev = init_dev();
6321 : :
6322 : 120 : spdk_bs_init(dev, NULL, bs_op_with_handle_complete, NULL);
6323 : 120 : poll_threads();
6324 : 120 : CU_ASSERT(g_bserrno == 0);
6325 [ - + ]: 120 : SPDK_CU_ASSERT_FATAL(g_bs != NULL);
6326 : 120 : bs = g_bs;
6327 : :
6328 : : /* Create blob */
6329 : 120 : ut_spdk_blob_opts_init(&opts);
6330 : 120 : opts.num_clusters = 10;
6331 : :
6332 : 120 : spdk_bs_create_blob_ext(bs, &opts, blob_op_with_id_complete, NULL);
6333 : 120 : poll_threads();
6334 : 120 : CU_ASSERT(g_bserrno == 0);
6335 : 120 : CU_ASSERT(g_blobid != SPDK_BLOBID_INVALID);
6336 : 120 : blobid = g_blobid;
6337 [ - + ]: 120 : SPDK_CU_ASSERT_FATAL(spdk_bit_pool_is_allocated(bs->used_clusters, 1));
6338 [ - + ]: 120 : SPDK_CU_ASSERT_FATAL(!spdk_bit_pool_is_allocated(bs->used_clusters, 11));
6339 : :
6340 : 120 : dev_set_power_failure_thresholds(thresholds);
6341 : :
6342 : : /* Create snapshot */
6343 : 120 : spdk_bs_create_snapshot(bs, blobid, NULL, blob_op_with_id_complete, NULL);
6344 : 120 : poll_threads();
6345 : 120 : create_snapshot_bserrno = g_bserrno;
6346 : 120 : snapshotid = g_blobid;
6347 [ - + ]: 120 : SPDK_CU_ASSERT_FATAL(spdk_bit_pool_is_allocated(bs->used_clusters, 1));
6348 [ - + ]: 120 : SPDK_CU_ASSERT_FATAL(!spdk_bit_pool_is_allocated(bs->used_clusters, 11));
6349 : :
6350 : : /* Do not shut down cleanly. Assumption is that after create snapshot
6351 : : * reports success, both blobs should be power-fail safe. */
6352 : 120 : dev_reset_power_failure_event();
6353 : 120 : ut_bs_dirty_load(&bs, NULL);
6354 : :
6355 [ - + ]: 120 : SPDK_CU_ASSERT_FATAL(spdk_bit_pool_is_allocated(bs->used_clusters, 1));
6356 [ - + ]: 120 : SPDK_CU_ASSERT_FATAL(!spdk_bit_pool_is_allocated(bs->used_clusters, 11));
6357 : :
6358 : 120 : spdk_bs_open_blob(bs, blobid, blob_op_with_handle_complete, NULL);
6359 : 120 : poll_threads();
6360 : 120 : CU_ASSERT(g_bserrno == 0);
6361 [ - + ]: 120 : SPDK_CU_ASSERT_FATAL(g_blob != NULL);
6362 : 120 : blob = g_blob;
6363 : :
6364 [ + + ]: 120 : if (snapshotid != SPDK_BLOBID_INVALID) {
6365 : 80 : spdk_bs_open_blob(bs, snapshotid, blob_op_with_handle_complete, NULL);
6366 : 80 : poll_threads();
6367 : : }
6368 : :
6369 [ + + + + ]: 120 : if ((snapshotid != SPDK_BLOBID_INVALID) && (g_bserrno == 0)) {
6370 [ - + ]: 32 : SPDK_CU_ASSERT_FATAL(g_blob != NULL);
6371 : 32 : snapshot = g_blob;
6372 [ - + ]: 32 : SPDK_CU_ASSERT_FATAL(spdk_blob_is_thin_provisioned(blob) == true);
6373 [ - + ]: 32 : SPDK_CU_ASSERT_FATAL(spdk_blob_is_thin_provisioned(snapshot) == false);
6374 : 32 : CU_ASSERT(spdk_blob_get_parent_snapshot(bs, blobid) == snapshotid);
6375 : 32 : count = SPDK_COUNTOF(ids);
6376 : 32 : rc = spdk_blob_get_clones(bs, snapshotid, ids, &count);
6377 : 32 : CU_ASSERT(rc == 0);
6378 : 32 : CU_ASSERT(count == 1);
6379 : 32 : CU_ASSERT(ids[0] == blobid);
6380 : 32 : rc = spdk_blob_get_xattr_value(snapshot, SNAPSHOT_IN_PROGRESS, &value, &value_len);
6381 : 32 : CU_ASSERT(rc != 0);
6382 : :
6383 : 32 : spdk_blob_close(snapshot, blob_op_complete, NULL);
6384 : 32 : poll_threads();
6385 : 32 : CU_ASSERT(g_bserrno == 0);
6386 [ + + ]: 32 : if (create_snapshot_bserrno == 0) {
6387 : 16 : created = true;
6388 : : }
6389 : : } else {
6390 : 88 : CU_ASSERT(spdk_blob_get_parent_snapshot(bs, blobid) == SPDK_BLOBID_INVALID);
6391 [ - + ]: 88 : SPDK_CU_ASSERT_FATAL(spdk_blob_is_thin_provisioned(blob) == false);
6392 : : }
6393 : :
6394 : 120 : spdk_blob_close(blob, blob_op_complete, NULL);
6395 : 120 : poll_threads();
6396 : 120 : CU_ASSERT(g_bserrno == 0);
6397 : :
6398 : 120 : spdk_bs_unload(bs, bs_op_complete, NULL);
6399 : 120 : poll_threads();
6400 : 120 : CU_ASSERT(g_bserrno == 0);
6401 : :
6402 : 120 : thresholds.general_threshold++;
6403 : : }
6404 : 16 : }
6405 : :
6406 : : static void
6407 : 32 : test_io_write(struct spdk_bs_dev *dev, struct spdk_blob *blob, struct spdk_io_channel *channel)
6408 : : {
6409 : 32 : uint8_t payload_ff[64 * 512];
6410 : 32 : uint8_t payload_aa[64 * 512];
6411 : 32 : uint8_t payload_00[64 * 512];
6412 : : uint8_t *cluster0, *cluster1;
6413 : :
6414 : 32 : memset(payload_ff, 0xFF, sizeof(payload_ff));
6415 : 32 : memset(payload_aa, 0xAA, sizeof(payload_aa));
6416 : 32 : memset(payload_00, 0x00, sizeof(payload_00));
6417 : :
6418 : : /* Try to perform I/O with io unit = 512 */
6419 : 32 : spdk_blob_io_write(blob, channel, payload_ff, 0, 1, blob_op_complete, NULL);
6420 : 32 : poll_threads();
6421 : 32 : CU_ASSERT(g_bserrno == 0);
6422 : :
6423 : : /* If thin provisioned is set cluster should be allocated now */
6424 [ - + ]: 32 : SPDK_CU_ASSERT_FATAL(blob->active.clusters[0] != 0);
6425 : 32 : cluster0 = &g_dev_buffer[blob->active.clusters[0] * dev->blocklen];
6426 : :
6427 : : /* Each character 0-F symbolizes single io_unit containing 512 bytes block filled with that character.
6428 : : * Each page is separated by |. Whole block [...] symbolizes one cluster (containing 4 pages). */
6429 : : /* cluster0: [ F000 0000 | 0000 0000 | 0000 0000 | 0000 0000 ] */
6430 [ - + ]: 32 : CU_ASSERT(memcmp(cluster0 + 0 * 512, payload_ff, 512) == 0);
6431 [ - + ]: 32 : CU_ASSERT(memcmp(cluster0 + 1 * 512, payload_00, 31 * 512) == 0);
6432 : :
6433 : : /* Verify write with offset on first page */
6434 : 32 : spdk_blob_io_write(blob, channel, payload_ff, 2, 1, blob_op_complete, NULL);
6435 : 32 : poll_threads();
6436 : 32 : CU_ASSERT(g_bserrno == 0);
6437 : :
6438 : : /* cluster0: [ F0F0 0000 | 0000 0000 | 0000 0000 | 0000 0000 ] */
6439 [ - + ]: 32 : CU_ASSERT(memcmp(cluster0 + 0 * 512, payload_ff, 512) == 0);
6440 [ - + ]: 32 : CU_ASSERT(memcmp(cluster0 + 1 * 512, payload_00, 512) == 0);
6441 [ - + ]: 32 : CU_ASSERT(memcmp(cluster0 + 2 * 512, payload_ff, 512) == 0);
6442 [ - + ]: 32 : CU_ASSERT(memcmp(cluster0 + 3 * 512, payload_00, 512) == 0);
6443 [ - + ]: 32 : CU_ASSERT(memcmp(cluster0 + 4 * 512, payload_00, 28 * 512) == 0);
6444 : :
6445 : : /* Verify write with offset on first page */
6446 : 32 : spdk_blob_io_write(blob, channel, payload_ff, 4, 4, blob_op_complete, NULL);
6447 : 32 : poll_threads();
6448 : :
6449 : : /* cluster0: [ F0F0 FFFF | 0000 0000 | 0000 0000 | 0000 0000 ] */
6450 [ - + ]: 32 : CU_ASSERT(memcmp(cluster0 + 0 * 512, payload_ff, 512) == 0);
6451 [ - + ]: 32 : CU_ASSERT(memcmp(cluster0 + 1 * 512, payload_00, 512) == 0);
6452 [ - + ]: 32 : CU_ASSERT(memcmp(cluster0 + 2 * 512, payload_ff, 512) == 0);
6453 [ - + ]: 32 : CU_ASSERT(memcmp(cluster0 + 3 * 512, payload_00, 512) == 0);
6454 [ - + ]: 32 : CU_ASSERT(memcmp(cluster0 + 4 * 512, payload_ff, 4 * 512) == 0);
6455 [ - + ]: 32 : CU_ASSERT(memcmp(cluster0 + 8 * 512, payload_00, 24 * 512) == 0);
6456 : :
6457 : : /* Verify write with offset on second page */
6458 : 32 : spdk_blob_io_write(blob, channel, payload_ff, 8, 4, blob_op_complete, NULL);
6459 : 32 : poll_threads();
6460 : :
6461 : : /* cluster0: [ F0F0 FFFF | FFFF 0000 | 0000 0000 | 0000 0000 ] */
6462 [ - + ]: 32 : CU_ASSERT(memcmp(cluster0 + 0 * 512, payload_ff, 512) == 0);
6463 [ - + ]: 32 : CU_ASSERT(memcmp(cluster0 + 1 * 512, payload_00, 512) == 0);
6464 [ - + ]: 32 : CU_ASSERT(memcmp(cluster0 + 2 * 512, payload_ff, 512) == 0);
6465 [ - + ]: 32 : CU_ASSERT(memcmp(cluster0 + 3 * 512, payload_00, 512) == 0);
6466 [ - + ]: 32 : CU_ASSERT(memcmp(cluster0 + 4 * 512, payload_ff, 8 * 512) == 0);
6467 [ - + ]: 32 : CU_ASSERT(memcmp(cluster0 + 12 * 512, payload_00, 20 * 512) == 0);
6468 : :
6469 : : /* Verify write across multiple pages */
6470 : 32 : spdk_blob_io_write(blob, channel, payload_aa, 4, 8, blob_op_complete, NULL);
6471 : 32 : poll_threads();
6472 : :
6473 : : /* cluster0: [ F0F0 AAAA | AAAA 0000 | 0000 0000 | 0000 0000 ] */
6474 [ - + ]: 32 : CU_ASSERT(memcmp(cluster0 + 0 * 512, payload_ff, 512) == 0);
6475 [ - + ]: 32 : CU_ASSERT(memcmp(cluster0 + 1 * 512, payload_00, 512) == 0);
6476 [ - + ]: 32 : CU_ASSERT(memcmp(cluster0 + 2 * 512, payload_ff, 512) == 0);
6477 [ - + ]: 32 : CU_ASSERT(memcmp(cluster0 + 3 * 512, payload_00, 512) == 0);
6478 [ - + ]: 32 : CU_ASSERT(memcmp(cluster0 + 4 * 512, payload_aa, 8 * 512) == 0);
6479 [ - + ]: 32 : CU_ASSERT(memcmp(cluster0 + 12 * 512, payload_00, 20 * 512) == 0);
6480 : :
6481 : : /* Verify write across multiple clusters */
6482 : 32 : spdk_blob_io_write(blob, channel, payload_ff, 28, 8, blob_op_complete, NULL);
6483 : 32 : poll_threads();
6484 : :
6485 [ - + ]: 32 : SPDK_CU_ASSERT_FATAL(blob->active.clusters[1] != 0);
6486 : 32 : cluster1 = &g_dev_buffer[blob->active.clusters[1] * dev->blocklen];
6487 : :
6488 : : /* cluster0: [ F0F0 AAAA | AAAA 0000 | 0000 0000 | 0000 FFFF ]
6489 : : * cluster1: [ FFFF 0000 | 0000 0000 | 0000 0000 | 0000 0000 ] */
6490 [ - + ]: 32 : CU_ASSERT(memcmp(cluster0 + 0 * 512, payload_ff, 512) == 0);
6491 [ - + ]: 32 : CU_ASSERT(memcmp(cluster0 + 1 * 512, payload_00, 512) == 0);
6492 [ - + ]: 32 : CU_ASSERT(memcmp(cluster0 + 2 * 512, payload_ff, 512) == 0);
6493 [ - + ]: 32 : CU_ASSERT(memcmp(cluster0 + 3 * 512, payload_00, 512) == 0);
6494 [ - + ]: 32 : CU_ASSERT(memcmp(cluster0 + 4 * 512, payload_aa, 8 * 512) == 0);
6495 [ - + ]: 32 : CU_ASSERT(memcmp(cluster0 + 28 * 512, payload_ff, 4 * 512) == 0);
6496 : :
6497 [ - + ]: 32 : CU_ASSERT(memcmp(cluster1 + 0 * 512, payload_ff, 4 * 512) == 0);
6498 [ - + ]: 32 : CU_ASSERT(memcmp(cluster1 + 4 * 512, payload_00, 28 * 512) == 0);
6499 : :
6500 : : /* Verify write to second cluster */
6501 : 32 : spdk_blob_io_write(blob, channel, payload_ff, 32 + 12, 2, blob_op_complete, NULL);
6502 : 32 : poll_threads();
6503 : :
6504 [ - + ]: 32 : SPDK_CU_ASSERT_FATAL(blob->active.clusters[1] != 0);
6505 : 32 : cluster1 = &g_dev_buffer[blob->active.clusters[1] * dev->blocklen];
6506 : :
6507 : : /* cluster0: [ F0F0 AAAA | AAAA 0000 | 0000 0000 | 0000 FFFF ]
6508 : : * cluster1: [ FFFF 0000 | 0000 FF00 | 0000 0000 | 0000 0000 ] */
6509 [ - + ]: 32 : CU_ASSERT(memcmp(cluster0 + 0 * 512, payload_ff, 512) == 0);
6510 [ - + ]: 32 : CU_ASSERT(memcmp(cluster0 + 1 * 512, payload_00, 512) == 0);
6511 [ - + ]: 32 : CU_ASSERT(memcmp(cluster0 + 2 * 512, payload_ff, 512) == 0);
6512 [ - + ]: 32 : CU_ASSERT(memcmp(cluster0 + 3 * 512, payload_00, 512) == 0);
6513 [ - + ]: 32 : CU_ASSERT(memcmp(cluster0 + 4 * 512, payload_aa, 8 * 512) == 0);
6514 [ - + ]: 32 : CU_ASSERT(memcmp(cluster0 + 28 * 512, payload_ff, 4 * 512) == 0);
6515 : :
6516 [ - + ]: 32 : CU_ASSERT(memcmp(cluster1 + 0 * 512, payload_ff, 4 * 512) == 0);
6517 [ - + ]: 32 : CU_ASSERT(memcmp(cluster1 + 4 * 512, payload_00, 8 * 512) == 0);
6518 [ - + ]: 32 : CU_ASSERT(memcmp(cluster1 + 12 * 512, payload_ff, 2 * 512) == 0);
6519 [ - + ]: 32 : CU_ASSERT(memcmp(cluster1 + 14 * 512, payload_00, 18 * 512) == 0);
6520 : 32 : }
6521 : :
6522 : : static void
6523 : 96 : test_io_read(struct spdk_bs_dev *dev, struct spdk_blob *blob, struct spdk_io_channel *channel)
6524 : : {
6525 : 96 : uint8_t payload_read[64 * 512];
6526 : 96 : uint8_t payload_ff[64 * 512];
6527 : 96 : uint8_t payload_aa[64 * 512];
6528 : 96 : uint8_t payload_00[64 * 512];
6529 : :
6530 : 96 : memset(payload_ff, 0xFF, sizeof(payload_ff));
6531 : 96 : memset(payload_aa, 0xAA, sizeof(payload_aa));
6532 : 96 : memset(payload_00, 0x00, sizeof(payload_00));
6533 : :
6534 : : /* Read only first io unit */
6535 : : /* cluster0: [ (F)0F0 AAAA | AAAA 0000 | 0000 0000 | 0000 FFFF ]
6536 : : * cluster1: [ FFFF 0000 | 0000 FF00 | 0000 0000 | 0000 0000 ]
6537 : : * payload_read: F000 0000 | 0000 0000 ... */
6538 : 96 : memset(payload_read, 0x00, sizeof(payload_read));
6539 : 96 : spdk_blob_io_read(blob, channel, payload_read, 0, 1, blob_op_complete, NULL);
6540 : 96 : poll_threads();
6541 : 96 : CU_ASSERT(g_bserrno == 0);
6542 : 96 : CU_ASSERT(memcmp(payload_read + 0 * 512, payload_ff, 512) == 0);
6543 [ - + ]: 96 : CU_ASSERT(memcmp(payload_read + 1 * 512, payload_00, 31 * 512) == 0);
6544 : :
6545 : : /* Read four io_units starting from offset = 2
6546 : : * cluster0: [ F0(F0 AA)AA | AAAA 0000 | 0000 0000 | 0000 FFFF ]
6547 : : * cluster1: [ FFFF 0000 | 0000 FF00 | 0000 0000 | 0000 0000 ]
6548 : : * payload_read: F0AA 0000 | 0000 0000 ... */
6549 : :
6550 : 96 : memset(payload_read, 0x00, sizeof(payload_read));
6551 : 96 : spdk_blob_io_read(blob, channel, payload_read, 2, 4, blob_op_complete, NULL);
6552 : 96 : poll_threads();
6553 : 96 : CU_ASSERT(g_bserrno == 0);
6554 : :
6555 : 96 : CU_ASSERT(memcmp(payload_read + 0 * 512, payload_ff, 512) == 0);
6556 [ - + ]: 96 : CU_ASSERT(memcmp(payload_read + 1 * 512, payload_00, 512) == 0);
6557 [ - + ]: 96 : CU_ASSERT(memcmp(payload_read + 2 * 512, payload_aa, 512) == 0);
6558 [ - + ]: 96 : CU_ASSERT(memcmp(payload_read + 3 * 512, payload_aa, 512) == 0);
6559 [ - + ]: 96 : CU_ASSERT(memcmp(payload_read + 4 * 512, payload_00, 28 * 512) == 0);
6560 : :
6561 : : /* Read eight io_units across multiple pages
6562 : : * cluster0: [ F0F0 (AAAA | AAAA) 0000 | 0000 0000 | 0000 FFFF ]
6563 : : * cluster1: [ FFFF 0000 | 0000 FF00 | 0000 0000 | 0000 0000 ]
6564 : : * payload_read: AAAA AAAA | 0000 0000 ... */
6565 : 96 : memset(payload_read, 0x00, sizeof(payload_read));
6566 : 96 : spdk_blob_io_read(blob, channel, payload_read, 4, 8, blob_op_complete, NULL);
6567 : 96 : poll_threads();
6568 : 96 : CU_ASSERT(g_bserrno == 0);
6569 : :
6570 : 96 : CU_ASSERT(memcmp(payload_read + 0 * 512, payload_aa, 8 * 512) == 0);
6571 [ - + ]: 96 : CU_ASSERT(memcmp(payload_read + 8 * 512, payload_00, 24 * 512) == 0);
6572 : :
6573 : : /* Read eight io_units across multiple clusters
6574 : : * cluster0: [ F0F0 AAAA | AAAA 0000 | 0000 0000 | 0000 (FFFF ]
6575 : : * cluster1: [ FFFF) 0000 | 0000 FF00 | 0000 0000 | 0000 0000 ]
6576 : : * payload_read: FFFF FFFF | 0000 0000 ... */
6577 : 96 : memset(payload_read, 0x00, sizeof(payload_read));
6578 : 96 : spdk_blob_io_read(blob, channel, payload_read, 28, 8, blob_op_complete, NULL);
6579 : 96 : poll_threads();
6580 : 96 : CU_ASSERT(g_bserrno == 0);
6581 : :
6582 : 96 : CU_ASSERT(memcmp(payload_read + 0 * 512, payload_ff, 8 * 512) == 0);
6583 [ - + ]: 96 : CU_ASSERT(memcmp(payload_read + 8 * 512, payload_00, 24 * 512) == 0);
6584 : :
6585 : : /* Read four io_units from second cluster
6586 : : * cluster0: [ F0F0 AAAA | AAAA 0000 | 0000 0000 | 0000 FFFF ]
6587 : : * cluster1: [ FFFF 0000 | 00(00 FF)00 | 0000 0000 | 0000 0000 ]
6588 : : * payload_read: 00FF 0000 | 0000 0000 ... */
6589 : 96 : memset(payload_read, 0x00, sizeof(payload_read));
6590 : 96 : spdk_blob_io_read(blob, channel, payload_read, 32 + 10, 4, blob_op_complete, NULL);
6591 : 96 : poll_threads();
6592 : 96 : CU_ASSERT(g_bserrno == 0);
6593 : :
6594 : 96 : CU_ASSERT(memcmp(payload_read + 0 * 512, payload_00, 2 * 512) == 0);
6595 [ - + ]: 96 : CU_ASSERT(memcmp(payload_read + 2 * 512, payload_ff, 2 * 512) == 0);
6596 [ - + ]: 96 : CU_ASSERT(memcmp(payload_read + 4 * 512, payload_00, 28 * 512) == 0);
6597 : :
6598 : : /* Read second cluster
6599 : : * cluster0: [ F0F0 AAAA | AAAA 0000 | 0000 0000 | 0000 FFFF ]
6600 : : * cluster1: [ (FFFF 0000 | 0000 FF00 | 0000 0000 | 0000 0000) ]
6601 : : * payload_read: FFFF 0000 | 0000 FF00 ... */
6602 : 96 : memset(payload_read, 0x00, sizeof(payload_read));
6603 : 96 : spdk_blob_io_read(blob, channel, payload_read, 32, 32, blob_op_complete, NULL);
6604 : 96 : poll_threads();
6605 : 96 : CU_ASSERT(g_bserrno == 0);
6606 : 96 : CU_ASSERT(memcmp(payload_read + 0 * 512, payload_ff, 4 * 512) == 0);
6607 [ - + ]: 96 : CU_ASSERT(memcmp(payload_read + 4 * 512, payload_00, 8 * 512) == 0);
6608 [ - + ]: 96 : CU_ASSERT(memcmp(payload_read + 12 * 512, payload_ff, 2 * 512) == 0);
6609 [ - + ]: 96 : CU_ASSERT(memcmp(payload_read + 14 * 512, payload_00, 18 * 512) == 0);
6610 : :
6611 : : /* Read whole two clusters
6612 : : * cluster0: [ (F0F0 AAAA | AAAA) 0000 | 0000 0000 | 0000 FFFF ]
6613 : : * cluster1: [ FFFF 0000 | 0000 FF00 | 0000 0000 | 0000 0000) ] */
6614 : 96 : memset(payload_read, 0x00, sizeof(payload_read));
6615 : 96 : spdk_blob_io_read(blob, channel, payload_read, 0, 64, blob_op_complete, NULL);
6616 : 96 : poll_threads();
6617 : 96 : CU_ASSERT(g_bserrno == 0);
6618 : :
6619 : 96 : CU_ASSERT(memcmp(payload_read + 0 * 512, payload_ff, 512) == 0);
6620 [ - + ]: 96 : CU_ASSERT(memcmp(payload_read + 1 * 512, payload_00, 512) == 0);
6621 [ - + ]: 96 : CU_ASSERT(memcmp(payload_read + 2 * 512, payload_ff, 512) == 0);
6622 [ - + ]: 96 : CU_ASSERT(memcmp(payload_read + 3 * 512, payload_00, 512) == 0);
6623 [ - + ]: 96 : CU_ASSERT(memcmp(payload_read + 4 * 512, payload_aa, 8 * 512) == 0);
6624 [ - + ]: 96 : CU_ASSERT(memcmp(payload_read + 28 * 512, payload_ff, 4 * 512) == 0);
6625 : :
6626 [ - + ]: 96 : CU_ASSERT(memcmp(payload_read + (32 + 0) * 512, payload_ff, 4 * 512) == 0);
6627 [ - + ]: 96 : CU_ASSERT(memcmp(payload_read + (32 + 4) * 512, payload_00, 8 * 512) == 0);
6628 [ - + ]: 96 : CU_ASSERT(memcmp(payload_read + (32 + 12) * 512, payload_ff, 2 * 512) == 0);
6629 [ - + ]: 96 : CU_ASSERT(memcmp(payload_read + (32 + 14) * 512, payload_00, 18 * 512) == 0);
6630 : 96 : }
6631 : :
6632 : :
6633 : : static void
6634 : 48 : test_io_unmap(struct spdk_bs_dev *dev, struct spdk_blob *blob, struct spdk_io_channel *channel)
6635 : : {
6636 : 48 : uint8_t payload_ff[64 * 512];
6637 : 48 : uint8_t payload_aa[64 * 512];
6638 : 48 : uint8_t payload_00[64 * 512];
6639 : : uint8_t *cluster0, *cluster1;
6640 : :
6641 : 48 : memset(payload_ff, 0xFF, sizeof(payload_ff));
6642 : 48 : memset(payload_aa, 0xAA, sizeof(payload_aa));
6643 : 48 : memset(payload_00, 0x00, sizeof(payload_00));
6644 : :
6645 : 48 : cluster0 = &g_dev_buffer[blob->active.clusters[0] * dev->blocklen];
6646 : 48 : cluster1 = &g_dev_buffer[blob->active.clusters[1] * dev->blocklen];
6647 : :
6648 : : /* Unmap */
6649 : 48 : spdk_blob_io_unmap(blob, channel, 0, 64, blob_op_complete, NULL);
6650 : 48 : poll_threads();
6651 : :
6652 : 48 : CU_ASSERT(g_bserrno == 0);
6653 : :
6654 [ - + ]: 48 : CU_ASSERT(memcmp(cluster0 + 0 * 512, payload_00, 32 * 512) == 0);
6655 [ - + ]: 48 : CU_ASSERT(memcmp(cluster1 + 0 * 512, payload_00, 32 * 512) == 0);
6656 : 48 : }
6657 : :
6658 : : static void
6659 : 64 : test_io_zeroes(struct spdk_bs_dev *dev, struct spdk_blob *blob, struct spdk_io_channel *channel)
6660 : : {
6661 : 64 : uint8_t payload_ff[64 * 512];
6662 : 64 : uint8_t payload_aa[64 * 512];
6663 : 64 : uint8_t payload_00[64 * 512];
6664 : : uint8_t *cluster0, *cluster1;
6665 : :
6666 : 64 : memset(payload_ff, 0xFF, sizeof(payload_ff));
6667 : 64 : memset(payload_aa, 0xAA, sizeof(payload_aa));
6668 : 64 : memset(payload_00, 0x00, sizeof(payload_00));
6669 : :
6670 : 64 : cluster0 = &g_dev_buffer[blob->active.clusters[0] * dev->blocklen];
6671 : 64 : cluster1 = &g_dev_buffer[blob->active.clusters[1] * dev->blocklen];
6672 : :
6673 : : /* Write zeroes */
6674 : 64 : spdk_blob_io_write_zeroes(blob, channel, 0, 64, blob_op_complete, NULL);
6675 : 64 : poll_threads();
6676 : :
6677 : 64 : CU_ASSERT(g_bserrno == 0);
6678 : :
6679 [ - + ]: 64 : CU_ASSERT(memcmp(cluster0 + 0 * 512, payload_00, 32 * 512) == 0);
6680 [ - + ]: 64 : CU_ASSERT(memcmp(cluster1 + 0 * 512, payload_00, 32 * 512) == 0);
6681 : 64 : }
6682 : :
6683 : : static inline void
6684 : 480 : test_blob_io_writev(struct spdk_blob *blob, struct spdk_io_channel *channel,
6685 : : struct iovec *iov, int iovcnt, uint64_t offset, uint64_t length,
6686 : : spdk_blob_op_complete cb_fn, void *cb_arg, struct spdk_blob_ext_io_opts *io_opts)
6687 : : {
6688 [ + + ]: 480 : if (io_opts) {
6689 : 240 : g_dev_writev_ext_called = false;
6690 : 240 : memset(&g_blob_ext_io_opts, 0, sizeof(g_blob_ext_io_opts));
6691 : 240 : spdk_blob_io_writev_ext(blob, channel, iov, iovcnt, offset, length, blob_op_complete, NULL,
6692 : : io_opts);
6693 : : } else {
6694 : 240 : spdk_blob_io_writev(blob, channel, iov, iovcnt, offset, length, blob_op_complete, NULL);
6695 : : }
6696 : 480 : poll_threads();
6697 : 480 : CU_ASSERT(g_bserrno == 0);
6698 [ + + ]: 480 : if (io_opts) {
6699 [ - + ]: 240 : CU_ASSERT(g_dev_writev_ext_called);
6700 [ - + ]: 240 : CU_ASSERT(memcmp(io_opts, &g_blob_ext_io_opts, sizeof(g_blob_ext_io_opts)) == 0);
6701 : : }
6702 : 480 : }
6703 : :
6704 : : static void
6705 : 96 : test_iov_write(struct spdk_bs_dev *dev, struct spdk_blob *blob, struct spdk_io_channel *channel,
6706 : : bool ext_api)
6707 : : {
6708 : 96 : uint8_t payload_ff[64 * 512];
6709 : 96 : uint8_t payload_aa[64 * 512];
6710 : 96 : uint8_t payload_00[64 * 512];
6711 : : uint8_t *cluster0, *cluster1;
6712 : 96 : struct iovec iov[4];
6713 : 96 : struct spdk_blob_ext_io_opts ext_opts = {
6714 : : .memory_domain = (struct spdk_memory_domain *)0xfeedbeef,
6715 : : .memory_domain_ctx = (void *)0xf00df00d,
6716 : : .size = sizeof(struct spdk_blob_ext_io_opts),
6717 : : .user_ctx = (void *)123,
6718 : : };
6719 : :
6720 : 96 : memset(payload_ff, 0xFF, sizeof(payload_ff));
6721 : 96 : memset(payload_aa, 0xAA, sizeof(payload_aa));
6722 : 96 : memset(payload_00, 0x00, sizeof(payload_00));
6723 : :
6724 : : /* Try to perform I/O with io unit = 512 */
6725 : 96 : iov[0].iov_base = payload_ff;
6726 : 96 : iov[0].iov_len = 1 * 512;
6727 : :
6728 [ + + ]: 96 : test_blob_io_writev(blob, channel, iov, 1, 0, 1, blob_op_complete, NULL,
6729 : : ext_api ? &ext_opts : NULL);
6730 : :
6731 : : /* If thin provisioned is set cluster should be allocated now */
6732 [ - + ]: 96 : SPDK_CU_ASSERT_FATAL(blob->active.clusters[0] != 0);
6733 : 96 : cluster0 = &g_dev_buffer[blob->active.clusters[0] * dev->blocklen];
6734 : :
6735 : : /* Each character 0-F symbolizes single io_unit containing 512 bytes block filled with that character.
6736 : : * Each page is separated by |. Whole block [...] symbolizes one cluster (containing 4 pages). */
6737 : : /* cluster0: [ F000 0000 | 0000 0000 | 0000 0000 | 0000 0000 ] */
6738 [ - + ]: 96 : CU_ASSERT(memcmp(cluster0 + 0 * 512, payload_ff, 512) == 0);
6739 [ - + ]: 96 : CU_ASSERT(memcmp(cluster0 + 1 * 512, payload_00, 31 * 512) == 0);
6740 : :
6741 : : /* Verify write with offset on first page */
6742 : 96 : iov[0].iov_base = payload_ff;
6743 : 96 : iov[0].iov_len = 1 * 512;
6744 : :
6745 [ + + ]: 96 : test_blob_io_writev(blob, channel, iov, 1, 2, 1, blob_op_complete, NULL,
6746 : : ext_api ? &ext_opts : NULL);
6747 : :
6748 : : /* cluster0: [ F0F0 0000 | 0000 0000 | 0000 0000 | 0000 0000 ] */
6749 [ - + ]: 96 : CU_ASSERT(memcmp(cluster0 + 0 * 512, payload_ff, 512) == 0);
6750 [ - + ]: 96 : CU_ASSERT(memcmp(cluster0 + 1 * 512, payload_00, 512) == 0);
6751 [ - + ]: 96 : CU_ASSERT(memcmp(cluster0 + 2 * 512, payload_ff, 512) == 0);
6752 [ - + ]: 96 : CU_ASSERT(memcmp(cluster0 + 3 * 512, payload_00, 512) == 0);
6753 [ - + ]: 96 : CU_ASSERT(memcmp(cluster0 + 4 * 512, payload_00, 28 * 512) == 0);
6754 : :
6755 : : /* Verify write with offset on first page */
6756 : 96 : iov[0].iov_base = payload_ff;
6757 : 96 : iov[0].iov_len = 4 * 512;
6758 : 96 : spdk_blob_io_writev(blob, channel, iov, 1, 4, 4, blob_op_complete, NULL);
6759 : 96 : poll_threads();
6760 : :
6761 : : /* cluster0: [ F0F0 FFFF | 0000 0000 | 0000 0000 | 0000 0000 ] */
6762 [ - + ]: 96 : CU_ASSERT(memcmp(cluster0 + 0 * 512, payload_ff, 512) == 0);
6763 [ - + ]: 96 : CU_ASSERT(memcmp(cluster0 + 1 * 512, payload_00, 512) == 0);
6764 [ - + ]: 96 : CU_ASSERT(memcmp(cluster0 + 2 * 512, payload_ff, 512) == 0);
6765 [ - + ]: 96 : CU_ASSERT(memcmp(cluster0 + 3 * 512, payload_00, 512) == 0);
6766 [ - + ]: 96 : CU_ASSERT(memcmp(cluster0 + 4 * 512, payload_ff, 4 * 512) == 0);
6767 [ - + ]: 96 : CU_ASSERT(memcmp(cluster0 + 8 * 512, payload_00, 24 * 512) == 0);
6768 : :
6769 : : /* Verify write with offset on second page */
6770 : 96 : iov[0].iov_base = payload_ff;
6771 : 96 : iov[0].iov_len = 4 * 512;
6772 : 96 : spdk_blob_io_writev(blob, channel, iov, 1, 8, 4, blob_op_complete, NULL);
6773 : 96 : poll_threads();
6774 : :
6775 : : /* cluster0: [ F0F0 FFFF | FFFF 0000 | 0000 0000 | 0000 0000 ] */
6776 [ - + ]: 96 : CU_ASSERT(memcmp(cluster0 + 0 * 512, payload_ff, 512) == 0);
6777 [ - + ]: 96 : CU_ASSERT(memcmp(cluster0 + 1 * 512, payload_00, 512) == 0);
6778 [ - + ]: 96 : CU_ASSERT(memcmp(cluster0 + 2 * 512, payload_ff, 512) == 0);
6779 [ - + ]: 96 : CU_ASSERT(memcmp(cluster0 + 3 * 512, payload_00, 512) == 0);
6780 [ - + ]: 96 : CU_ASSERT(memcmp(cluster0 + 4 * 512, payload_ff, 8 * 512) == 0);
6781 [ - + ]: 96 : CU_ASSERT(memcmp(cluster0 + 12 * 512, payload_00, 20 * 512) == 0);
6782 : :
6783 : : /* Verify write across multiple pages */
6784 : 96 : iov[0].iov_base = payload_aa;
6785 : 96 : iov[0].iov_len = 8 * 512;
6786 : :
6787 [ + + ]: 96 : test_blob_io_writev(blob, channel, iov, 1, 4, 8, blob_op_complete, NULL,
6788 : : ext_api ? &ext_opts : NULL);
6789 : :
6790 : : /* cluster0: [ F0F0 AAAA | AAAA 0000 | 0000 0000 | 0000 0000 ] */
6791 [ - + ]: 96 : CU_ASSERT(memcmp(cluster0 + 0 * 512, payload_ff, 512) == 0);
6792 [ - + ]: 96 : CU_ASSERT(memcmp(cluster0 + 1 * 512, payload_00, 512) == 0);
6793 [ - + ]: 96 : CU_ASSERT(memcmp(cluster0 + 2 * 512, payload_ff, 512) == 0);
6794 [ - + ]: 96 : CU_ASSERT(memcmp(cluster0 + 3 * 512, payload_00, 512) == 0);
6795 [ - + ]: 96 : CU_ASSERT(memcmp(cluster0 + 4 * 512, payload_aa, 8 * 512) == 0);
6796 [ - + ]: 96 : CU_ASSERT(memcmp(cluster0 + 12 * 512, payload_00, 20 * 512) == 0);
6797 : :
6798 : : /* Verify write across multiple clusters */
6799 : :
6800 : 96 : iov[0].iov_base = payload_ff;
6801 : 96 : iov[0].iov_len = 8 * 512;
6802 : :
6803 [ + + ]: 96 : test_blob_io_writev(blob, channel, iov, 1, 28, 8, blob_op_complete, NULL,
6804 : : ext_api ? &ext_opts : NULL);
6805 : :
6806 [ - + ]: 96 : SPDK_CU_ASSERT_FATAL(blob->active.clusters[1] != 0);
6807 : 96 : cluster1 = &g_dev_buffer[blob->active.clusters[1] * dev->blocklen];
6808 : :
6809 : : /* cluster0: [ F0F0 AAAA | AAAA 0000 | 0000 0000 | 0000 FFFF ]
6810 : : * cluster1: [ FFFF 0000 | 0000 0000 | 0000 0000 | 0000 0000 ] */
6811 [ - + ]: 96 : CU_ASSERT(memcmp(cluster0 + 0 * 512, payload_ff, 512) == 0);
6812 [ - + ]: 96 : CU_ASSERT(memcmp(cluster0 + 1 * 512, payload_00, 512) == 0);
6813 [ - + ]: 96 : CU_ASSERT(memcmp(cluster0 + 2 * 512, payload_ff, 512) == 0);
6814 [ - + ]: 96 : CU_ASSERT(memcmp(cluster0 + 3 * 512, payload_00, 512) == 0);
6815 [ - + ]: 96 : CU_ASSERT(memcmp(cluster0 + 4 * 512, payload_aa, 8 * 512) == 0);
6816 [ - + ]: 96 : CU_ASSERT(memcmp(cluster0 + 12 * 512, payload_00, 16 * 512) == 0);
6817 [ - + ]: 96 : CU_ASSERT(memcmp(cluster0 + 28 * 512, payload_ff, 4 * 512) == 0);
6818 : :
6819 [ - + ]: 96 : CU_ASSERT(memcmp(cluster1 + 0 * 512, payload_ff, 4 * 512) == 0);
6820 [ - + ]: 96 : CU_ASSERT(memcmp(cluster1 + 4 * 512, payload_00, 28 * 512) == 0);
6821 : :
6822 : : /* Verify write to second cluster */
6823 : :
6824 : 96 : iov[0].iov_base = payload_ff;
6825 : 96 : iov[0].iov_len = 2 * 512;
6826 : :
6827 [ + + ]: 96 : test_blob_io_writev(blob, channel, iov, 1, 32 + 12, 2, blob_op_complete, NULL,
6828 : : ext_api ? &ext_opts : NULL);
6829 : :
6830 [ - + ]: 96 : SPDK_CU_ASSERT_FATAL(blob->active.clusters[1] != 0);
6831 : 96 : cluster1 = &g_dev_buffer[blob->active.clusters[1] * dev->blocklen];
6832 : :
6833 : : /* cluster0: [ F0F0 AAAA | AAAA 0000 | 0000 0000 | 0000 FFFF ]
6834 : : * cluster1: [ FFFF 0000 | 0000 FF00 | 0000 0000 | 0000 0000 ] */
6835 [ - + ]: 96 : CU_ASSERT(memcmp(cluster0 + 0 * 512, payload_ff, 512) == 0);
6836 [ - + ]: 96 : CU_ASSERT(memcmp(cluster0 + 1 * 512, payload_00, 512) == 0);
6837 [ - + ]: 96 : CU_ASSERT(memcmp(cluster0 + 2 * 512, payload_ff, 512) == 0);
6838 [ - + ]: 96 : CU_ASSERT(memcmp(cluster0 + 3 * 512, payload_00, 512) == 0);
6839 [ - + ]: 96 : CU_ASSERT(memcmp(cluster0 + 4 * 512, payload_aa, 8 * 512) == 0);
6840 [ - + ]: 96 : CU_ASSERT(memcmp(cluster0 + 28 * 512, payload_ff, 4 * 512) == 0);
6841 : :
6842 [ - + ]: 96 : CU_ASSERT(memcmp(cluster1 + 0 * 512, payload_ff, 4 * 512) == 0);
6843 [ - + ]: 96 : CU_ASSERT(memcmp(cluster1 + 4 * 512, payload_00, 8 * 512) == 0);
6844 [ - + ]: 96 : CU_ASSERT(memcmp(cluster1 + 12 * 512, payload_ff, 2 * 512) == 0);
6845 [ - + ]: 96 : CU_ASSERT(memcmp(cluster1 + 14 * 512, payload_00, 18 * 512) == 0);
6846 : 96 : }
6847 : :
6848 : : static inline void
6849 : 1344 : test_blob_io_readv(struct spdk_blob *blob, struct spdk_io_channel *channel,
6850 : : struct iovec *iov, int iovcnt, uint64_t offset, uint64_t length,
6851 : : spdk_blob_op_complete cb_fn, void *cb_arg, struct spdk_blob_ext_io_opts *io_opts)
6852 : : {
6853 [ + + ]: 1344 : if (io_opts) {
6854 : 672 : g_dev_readv_ext_called = false;
6855 : 672 : memset(&g_blob_ext_io_opts, 0, sizeof(g_blob_ext_io_opts));
6856 : 672 : spdk_blob_io_readv_ext(blob, channel, iov, iovcnt, offset, length, blob_op_complete, NULL, io_opts);
6857 : : } else {
6858 : 672 : spdk_blob_io_readv(blob, channel, iov, iovcnt, offset, length, blob_op_complete, NULL);
6859 : : }
6860 : 1344 : poll_threads();
6861 : 1344 : CU_ASSERT(g_bserrno == 0);
6862 [ + + ]: 1344 : if (io_opts) {
6863 [ - + ]: 672 : CU_ASSERT(g_dev_readv_ext_called);
6864 [ - + ]: 672 : CU_ASSERT(memcmp(io_opts, &g_blob_ext_io_opts, sizeof(g_blob_ext_io_opts)) == 0);
6865 : : }
6866 : 1344 : }
6867 : :
6868 : : static void
6869 : 192 : test_iov_read(struct spdk_bs_dev *dev, struct spdk_blob *blob, struct spdk_io_channel *channel,
6870 : : bool ext_api)
6871 : : {
6872 : 192 : uint8_t payload_read[64 * 512];
6873 : 192 : uint8_t payload_ff[64 * 512];
6874 : 192 : uint8_t payload_aa[64 * 512];
6875 : 192 : uint8_t payload_00[64 * 512];
6876 : 192 : struct iovec iov[4];
6877 : 192 : struct spdk_blob_ext_io_opts ext_opts = {
6878 : : .memory_domain = (struct spdk_memory_domain *)0xfeedbeef,
6879 : : .memory_domain_ctx = (void *)0xf00df00d,
6880 : : .size = sizeof(struct spdk_blob_ext_io_opts),
6881 : : .user_ctx = (void *)123,
6882 : : };
6883 : :
6884 : 192 : memset(payload_ff, 0xFF, sizeof(payload_ff));
6885 : 192 : memset(payload_aa, 0xAA, sizeof(payload_aa));
6886 : 192 : memset(payload_00, 0x00, sizeof(payload_00));
6887 : :
6888 : : /* Read only first io unit */
6889 : : /* cluster0: [ (F)0F0 AAAA | AAAA 0000 | 0000 0000 | 0000 FFFF ]
6890 : : * cluster1: [ FFFF 0000 | 0000 FF00 | 0000 0000 | 0000 0000 ]
6891 : : * payload_read: F000 0000 | 0000 0000 ... */
6892 : 192 : memset(payload_read, 0x00, sizeof(payload_read));
6893 : 192 : iov[0].iov_base = payload_read;
6894 : 192 : iov[0].iov_len = 1 * 512;
6895 : :
6896 [ + + ]: 192 : test_blob_io_readv(blob, channel, iov, 1, 0, 1, blob_op_complete, NULL, ext_api ? &ext_opts : NULL);
6897 : :
6898 : 192 : CU_ASSERT(memcmp(payload_read + 0 * 512, payload_ff, 512) == 0);
6899 [ - + ]: 192 : CU_ASSERT(memcmp(payload_read + 1 * 512, payload_00, 31 * 512) == 0);
6900 : :
6901 : : /* Read four io_units starting from offset = 2
6902 : : * cluster0: [ F0(F0 AA)AA | AAAA 0000 | 0000 0000 | 0000 FFFF ]
6903 : : * cluster1: [ FFFF 0000 | 0000 FF00 | 0000 0000 | 0000 0000 ]
6904 : : * payload_read: F0AA 0000 | 0000 0000 ... */
6905 : :
6906 : 192 : memset(payload_read, 0x00, sizeof(payload_read));
6907 : 192 : iov[0].iov_base = payload_read;
6908 : 192 : iov[0].iov_len = 4 * 512;
6909 : :
6910 [ + + ]: 192 : test_blob_io_readv(blob, channel, iov, 1, 2, 4, blob_op_complete, NULL, ext_api ? &ext_opts : NULL);
6911 : :
6912 : 192 : CU_ASSERT(memcmp(payload_read + 0 * 512, payload_ff, 512) == 0);
6913 [ - + ]: 192 : CU_ASSERT(memcmp(payload_read + 1 * 512, payload_00, 512) == 0);
6914 [ - + ]: 192 : CU_ASSERT(memcmp(payload_read + 2 * 512, payload_aa, 512) == 0);
6915 [ - + ]: 192 : CU_ASSERT(memcmp(payload_read + 3 * 512, payload_aa, 512) == 0);
6916 [ - + ]: 192 : CU_ASSERT(memcmp(payload_read + 4 * 512, payload_00, 28 * 512) == 0);
6917 : :
6918 : : /* Read eight io_units across multiple pages
6919 : : * cluster0: [ F0F0 (AAAA | AAAA) 0000 | 0000 0000 | 0000 FFFF ]
6920 : : * cluster1: [ FFFF 0000 | 0000 FF00 | 0000 0000 | 0000 0000 ]
6921 : : * payload_read: AAAA AAAA | 0000 0000 ... */
6922 : 192 : memset(payload_read, 0x00, sizeof(payload_read));
6923 : 192 : iov[0].iov_base = payload_read;
6924 : 192 : iov[0].iov_len = 4 * 512;
6925 : 192 : iov[1].iov_base = payload_read + 4 * 512;
6926 : 192 : iov[1].iov_len = 4 * 512;
6927 : :
6928 [ + + ]: 192 : test_blob_io_readv(blob, channel, iov, 2, 4, 8, blob_op_complete, NULL, ext_api ? &ext_opts : NULL);
6929 : :
6930 : 192 : CU_ASSERT(memcmp(payload_read + 0 * 512, payload_aa, 8 * 512) == 0);
6931 [ - + ]: 192 : CU_ASSERT(memcmp(payload_read + 8 * 512, payload_00, 24 * 512) == 0);
6932 : :
6933 : : /* Read eight io_units across multiple clusters
6934 : : * cluster0: [ F0F0 AAAA | AAAA 0000 | 0000 0000 | 0000 (FFFF ]
6935 : : * cluster1: [ FFFF) 0000 | 0000 FF00 | 0000 0000 | 0000 0000 ]
6936 : : * payload_read: FFFF FFFF | 0000 0000 ... */
6937 : 192 : memset(payload_read, 0x00, sizeof(payload_read));
6938 : 192 : iov[0].iov_base = payload_read;
6939 : 192 : iov[0].iov_len = 2 * 512;
6940 : 192 : iov[1].iov_base = payload_read + 2 * 512;
6941 : 192 : iov[1].iov_len = 2 * 512;
6942 : 192 : iov[2].iov_base = payload_read + 4 * 512;
6943 : 192 : iov[2].iov_len = 2 * 512;
6944 : 192 : iov[3].iov_base = payload_read + 6 * 512;
6945 : 192 : iov[3].iov_len = 2 * 512;
6946 : :
6947 [ + + ]: 192 : test_blob_io_readv(blob, channel, iov, 4, 28, 8, blob_op_complete, NULL,
6948 : : ext_api ? &ext_opts : NULL);
6949 : :
6950 : 192 : CU_ASSERT(memcmp(payload_read + 0 * 512, payload_ff, 8 * 512) == 0);
6951 [ - + ]: 192 : CU_ASSERT(memcmp(payload_read + 8 * 512, payload_00, 24 * 512) == 0);
6952 : :
6953 : : /* Read four io_units from second cluster
6954 : : * cluster0: [ F0F0 AAAA | AAAA 0000 | 0000 0000 | 0000 FFFF ]
6955 : : * cluster1: [ FFFF 0000 | 00(00 FF)00 | 0000 0000 | 0000 0000 ]
6956 : : * payload_read: 00FF 0000 | 0000 0000 ... */
6957 : 192 : memset(payload_read, 0x00, sizeof(payload_read));
6958 : 192 : iov[0].iov_base = payload_read;
6959 : 192 : iov[0].iov_len = 1 * 512;
6960 : 192 : iov[1].iov_base = payload_read + 1 * 512;
6961 : 192 : iov[1].iov_len = 3 * 512;
6962 : :
6963 [ + + ]: 192 : test_blob_io_readv(blob, channel, iov, 2, 32 + 10, 4, blob_op_complete, NULL,
6964 : : ext_api ? &ext_opts : NULL);
6965 : :
6966 : 192 : CU_ASSERT(memcmp(payload_read + 0 * 512, payload_00, 2 * 512) == 0);
6967 [ - + ]: 192 : CU_ASSERT(memcmp(payload_read + 2 * 512, payload_ff, 2 * 512) == 0);
6968 [ - + ]: 192 : CU_ASSERT(memcmp(payload_read + 4 * 512, payload_00, 28 * 512) == 0);
6969 : :
6970 : : /* Read second cluster
6971 : : * cluster0: [ F0F0 AAAA | AAAA 0000 | 0000 0000 | 0000 FFFF ]
6972 : : * cluster1: [ (FFFF 0000 | 0000 FF00 | 0000 0000 | 0000 0000) ]
6973 : : * payload_read: FFFF 0000 | 0000 FF00 ... */
6974 : 192 : memset(payload_read, 0x00, sizeof(payload_read));
6975 : 192 : iov[0].iov_base = payload_read;
6976 : 192 : iov[0].iov_len = 1 * 512;
6977 : 192 : iov[1].iov_base = payload_read + 1 * 512;
6978 : 192 : iov[1].iov_len = 2 * 512;
6979 : 192 : iov[2].iov_base = payload_read + 3 * 512;
6980 : 192 : iov[2].iov_len = 4 * 512;
6981 : 192 : iov[3].iov_base = payload_read + 7 * 512;
6982 : 192 : iov[3].iov_len = 25 * 512;
6983 : :
6984 [ + + ]: 192 : test_blob_io_readv(blob, channel, iov, 4, 32, 32, blob_op_complete, NULL,
6985 : : ext_api ? &ext_opts : NULL);
6986 : :
6987 : 192 : CU_ASSERT(memcmp(payload_read + 0 * 512, payload_ff, 4 * 512) == 0);
6988 [ - + ]: 192 : CU_ASSERT(memcmp(payload_read + 4 * 512, payload_00, 8 * 512) == 0);
6989 [ - + ]: 192 : CU_ASSERT(memcmp(payload_read + 12 * 512, payload_ff, 2 * 512) == 0);
6990 [ - + ]: 192 : CU_ASSERT(memcmp(payload_read + 14 * 512, payload_00, 18 * 512) == 0);
6991 : :
6992 : : /* Read whole two clusters
6993 : : * cluster0: [ (F0F0 AAAA | AAAA) 0000 | 0000 0000 | 0000 FFFF ]
6994 : : * cluster1: [ FFFF 0000 | 0000 FF00 | 0000 0000 | 0000 0000) ] */
6995 : 192 : memset(payload_read, 0x00, sizeof(payload_read));
6996 : 192 : iov[0].iov_base = payload_read;
6997 : 192 : iov[0].iov_len = 1 * 512;
6998 : 192 : iov[1].iov_base = payload_read + 1 * 512;
6999 : 192 : iov[1].iov_len = 8 * 512;
7000 : 192 : iov[2].iov_base = payload_read + 9 * 512;
7001 : 192 : iov[2].iov_len = 16 * 512;
7002 : 192 : iov[3].iov_base = payload_read + 25 * 512;
7003 : 192 : iov[3].iov_len = 39 * 512;
7004 : :
7005 [ + + ]: 192 : test_blob_io_readv(blob, channel, iov, 4, 0, 64, blob_op_complete, NULL,
7006 : : ext_api ? &ext_opts : NULL);
7007 : :
7008 : 192 : CU_ASSERT(memcmp(payload_read + 0 * 512, payload_ff, 512) == 0);
7009 [ - + ]: 192 : CU_ASSERT(memcmp(payload_read + 1 * 512, payload_00, 512) == 0);
7010 [ - + ]: 192 : CU_ASSERT(memcmp(payload_read + 2 * 512, payload_ff, 512) == 0);
7011 [ - + ]: 192 : CU_ASSERT(memcmp(payload_read + 3 * 512, payload_00, 512) == 0);
7012 [ - + ]: 192 : CU_ASSERT(memcmp(payload_read + 4 * 512, payload_aa, 8 * 512) == 0);
7013 [ - + ]: 192 : CU_ASSERT(memcmp(payload_read + 28 * 512, payload_ff, 4 * 512) == 0);
7014 : :
7015 [ - + ]: 192 : CU_ASSERT(memcmp(payload_read + (32 + 0) * 512, payload_ff, 4 * 512) == 0);
7016 [ - + ]: 192 : CU_ASSERT(memcmp(payload_read + (32 + 4) * 512, payload_00, 8 * 512) == 0);
7017 [ - + ]: 192 : CU_ASSERT(memcmp(payload_read + (32 + 12) * 512, payload_ff, 2 * 512) == 0);
7018 [ - + ]: 192 : CU_ASSERT(memcmp(payload_read + (32 + 14) * 512, payload_00, 18 * 512) == 0);
7019 : 192 : }
7020 : :
7021 : : static void
7022 : 16 : blob_io_unit(void)
7023 : : {
7024 : 16 : struct spdk_bs_opts bsopts;
7025 : 16 : struct spdk_blob_opts opts;
7026 : : struct spdk_blob_store *bs;
7027 : : struct spdk_bs_dev *dev;
7028 : : struct spdk_blob *blob, *snapshot, *clone;
7029 : : spdk_blob_id blobid;
7030 : : struct spdk_io_channel *channel;
7031 : :
7032 : : /* Create dev with 512 bytes io unit size */
7033 : :
7034 : 16 : spdk_bs_opts_init(&bsopts, sizeof(bsopts));
7035 : 16 : bsopts.cluster_sz = SPDK_BS_PAGE_SIZE * 4; /* 8 * 4 = 32 io_unit */
7036 : 16 : snprintf(bsopts.bstype.bstype, sizeof(bsopts.bstype.bstype), "TESTTYPE");
7037 : :
7038 : : /* Try to initialize a new blob store with unsupported io_unit */
7039 : 16 : dev = init_dev();
7040 : 16 : dev->blocklen = 512;
7041 [ - + ]: 16 : dev->blockcnt = DEV_BUFFER_SIZE / dev->blocklen;
7042 : :
7043 : : /* Initialize a new blob store */
7044 : 16 : spdk_bs_init(dev, &bsopts, bs_op_with_handle_complete, NULL);
7045 : 16 : poll_threads();
7046 : 16 : CU_ASSERT(g_bserrno == 0);
7047 [ - + ]: 16 : SPDK_CU_ASSERT_FATAL(g_bs != NULL);
7048 : 16 : bs = g_bs;
7049 : :
7050 : 16 : CU_ASSERT(spdk_bs_get_io_unit_size(bs) == 512);
7051 : 16 : channel = spdk_bs_alloc_io_channel(bs);
7052 : :
7053 : : /* Create thick provisioned blob */
7054 : 16 : ut_spdk_blob_opts_init(&opts);
7055 : 16 : opts.thin_provision = false;
7056 : 16 : opts.num_clusters = 32;
7057 : :
7058 : 16 : blob = ut_blob_create_and_open(bs, &opts);
7059 : 16 : blobid = spdk_blob_get_id(blob);
7060 : :
7061 : 16 : test_io_write(dev, blob, channel);
7062 : 16 : test_io_read(dev, blob, channel);
7063 : 16 : test_io_zeroes(dev, blob, channel);
7064 : :
7065 : 16 : test_iov_write(dev, blob, channel, false);
7066 : 16 : test_iov_read(dev, blob, channel, false);
7067 : 16 : test_io_zeroes(dev, blob, channel);
7068 : :
7069 : 16 : test_iov_write(dev, blob, channel, true);
7070 : 16 : test_iov_read(dev, blob, channel, true);
7071 : :
7072 : 16 : test_io_unmap(dev, blob, channel);
7073 : :
7074 : 16 : spdk_blob_close(blob, blob_op_complete, NULL);
7075 : 16 : poll_threads();
7076 : 16 : CU_ASSERT(g_bserrno == 0);
7077 : 16 : blob = NULL;
7078 : 16 : g_blob = NULL;
7079 : :
7080 : : /* Create thin provisioned blob */
7081 : :
7082 : 16 : ut_spdk_blob_opts_init(&opts);
7083 : 16 : opts.thin_provision = true;
7084 : 16 : opts.num_clusters = 32;
7085 : :
7086 : 16 : blob = ut_blob_create_and_open(bs, &opts);
7087 : 16 : blobid = spdk_blob_get_id(blob);
7088 : :
7089 : 16 : test_io_write(dev, blob, channel);
7090 : 16 : test_io_read(dev, blob, channel);
7091 : 16 : test_io_zeroes(dev, blob, channel);
7092 : :
7093 : 16 : test_iov_write(dev, blob, channel, false);
7094 : 16 : test_iov_read(dev, blob, channel, false);
7095 : 16 : test_io_zeroes(dev, blob, channel);
7096 : :
7097 : 16 : test_iov_write(dev, blob, channel, true);
7098 : 16 : test_iov_read(dev, blob, channel, true);
7099 : :
7100 : : /* Create snapshot */
7101 : :
7102 : 16 : spdk_bs_create_snapshot(bs, blobid, NULL, blob_op_with_id_complete, NULL);
7103 : 16 : poll_threads();
7104 : 16 : CU_ASSERT(g_bserrno == 0);
7105 : 16 : CU_ASSERT(g_blobid != SPDK_BLOBID_INVALID);
7106 : 16 : blobid = g_blobid;
7107 : :
7108 : 16 : spdk_bs_open_blob(bs, blobid, blob_op_with_handle_complete, NULL);
7109 : 16 : poll_threads();
7110 : 16 : CU_ASSERT(g_bserrno == 0);
7111 : 16 : CU_ASSERT(g_blob != NULL);
7112 : 16 : snapshot = g_blob;
7113 : :
7114 : 16 : spdk_bs_create_clone(bs, blobid, NULL, blob_op_with_id_complete, NULL);
7115 : 16 : poll_threads();
7116 : 16 : CU_ASSERT(g_bserrno == 0);
7117 : 16 : CU_ASSERT(g_blobid != SPDK_BLOBID_INVALID);
7118 : 16 : blobid = g_blobid;
7119 : :
7120 : 16 : spdk_bs_open_blob(bs, blobid, blob_op_with_handle_complete, NULL);
7121 : 16 : poll_threads();
7122 : 16 : CU_ASSERT(g_bserrno == 0);
7123 : 16 : CU_ASSERT(g_blob != NULL);
7124 : 16 : clone = g_blob;
7125 : :
7126 : 16 : test_io_read(dev, blob, channel);
7127 : 16 : test_io_read(dev, snapshot, channel);
7128 : 16 : test_io_read(dev, clone, channel);
7129 : :
7130 : 16 : test_iov_read(dev, blob, channel, false);
7131 : 16 : test_iov_read(dev, snapshot, channel, false);
7132 : 16 : test_iov_read(dev, clone, channel, false);
7133 : :
7134 : 16 : test_iov_read(dev, blob, channel, true);
7135 : 16 : test_iov_read(dev, snapshot, channel, true);
7136 : 16 : test_iov_read(dev, clone, channel, true);
7137 : :
7138 : : /* Inflate clone */
7139 : :
7140 : 16 : spdk_bs_inflate_blob(bs, channel, blobid, blob_op_complete, NULL);
7141 : 16 : poll_threads();
7142 : :
7143 : 16 : CU_ASSERT(g_bserrno == 0);
7144 : :
7145 : 16 : test_io_read(dev, clone, channel);
7146 : :
7147 : 16 : test_io_unmap(dev, clone, channel);
7148 : :
7149 : 16 : test_iov_write(dev, clone, channel, false);
7150 : 16 : test_iov_read(dev, clone, channel, false);
7151 : 16 : test_io_unmap(dev, clone, channel);
7152 : :
7153 : 16 : test_iov_write(dev, clone, channel, true);
7154 : 16 : test_iov_read(dev, clone, channel, true);
7155 : :
7156 : 16 : spdk_blob_close(blob, blob_op_complete, NULL);
7157 : 16 : spdk_blob_close(snapshot, blob_op_complete, NULL);
7158 : 16 : spdk_blob_close(clone, blob_op_complete, NULL);
7159 : 16 : poll_threads();
7160 : 16 : CU_ASSERT(g_bserrno == 0);
7161 : 16 : blob = NULL;
7162 : 16 : g_blob = NULL;
7163 : :
7164 : 16 : spdk_bs_free_io_channel(channel);
7165 : 16 : poll_threads();
7166 : :
7167 : : /* Unload the blob store */
7168 : 16 : spdk_bs_unload(bs, bs_op_complete, NULL);
7169 : 16 : poll_threads();
7170 : 16 : CU_ASSERT(g_bserrno == 0);
7171 : 16 : g_bs = NULL;
7172 : 16 : g_blob = NULL;
7173 : 16 : g_blobid = 0;
7174 : 16 : }
7175 : :
7176 : : static void
7177 : 16 : blob_io_unit_compatibility(void)
7178 : : {
7179 : 16 : struct spdk_bs_opts bsopts;
7180 : : struct spdk_blob_store *bs;
7181 : : struct spdk_bs_dev *dev;
7182 : : struct spdk_bs_super_block *super;
7183 : :
7184 : : /* Create dev with 512 bytes io unit size */
7185 : :
7186 : 16 : spdk_bs_opts_init(&bsopts, sizeof(bsopts));
7187 : 16 : bsopts.cluster_sz = SPDK_BS_PAGE_SIZE * 4; /* 8 * 4 = 32 io_unit */
7188 : 16 : snprintf(bsopts.bstype.bstype, sizeof(bsopts.bstype.bstype), "TESTTYPE");
7189 : :
7190 : : /* Try to initialize a new blob store with unsupported io_unit */
7191 : 16 : dev = init_dev();
7192 : 16 : dev->blocklen = 512;
7193 [ - + ]: 16 : dev->blockcnt = DEV_BUFFER_SIZE / dev->blocklen;
7194 : :
7195 : : /* Initialize a new blob store */
7196 : 16 : spdk_bs_init(dev, &bsopts, bs_op_with_handle_complete, NULL);
7197 : 16 : poll_threads();
7198 : 16 : CU_ASSERT(g_bserrno == 0);
7199 [ - + ]: 16 : SPDK_CU_ASSERT_FATAL(g_bs != NULL);
7200 : 16 : bs = g_bs;
7201 : :
7202 : 16 : CU_ASSERT(spdk_bs_get_io_unit_size(bs) == 512);
7203 : :
7204 : : /* Unload the blob store */
7205 : 16 : spdk_bs_unload(bs, bs_op_complete, NULL);
7206 : 16 : poll_threads();
7207 : 16 : CU_ASSERT(g_bserrno == 0);
7208 : :
7209 : : /* Modify super block to behave like older version.
7210 : : * Check if loaded io unit size equals SPDK_BS_PAGE_SIZE */
7211 : 16 : super = (struct spdk_bs_super_block *)&g_dev_buffer[0];
7212 : 16 : super->io_unit_size = 0;
7213 : 16 : super->crc = blob_md_page_calc_crc(super);
7214 : :
7215 : 16 : dev = init_dev();
7216 : 16 : dev->blocklen = 512;
7217 [ - + ]: 16 : dev->blockcnt = DEV_BUFFER_SIZE / dev->blocklen;
7218 : :
7219 : 16 : spdk_bs_load(dev, &bsopts, bs_op_with_handle_complete, NULL);
7220 : 16 : poll_threads();
7221 : 16 : CU_ASSERT(g_bserrno == 0);
7222 [ - + ]: 16 : SPDK_CU_ASSERT_FATAL(g_bs != NULL);
7223 : 16 : bs = g_bs;
7224 : :
7225 : 16 : CU_ASSERT(spdk_bs_get_io_unit_size(bs) == SPDK_BS_PAGE_SIZE);
7226 : :
7227 : : /* Unload the blob store */
7228 : 16 : spdk_bs_unload(bs, bs_op_complete, NULL);
7229 : 16 : poll_threads();
7230 : 16 : CU_ASSERT(g_bserrno == 0);
7231 : :
7232 : 16 : g_bs = NULL;
7233 : 16 : g_blob = NULL;
7234 : 16 : g_blobid = 0;
7235 : 16 : }
7236 : :
7237 : : static void
7238 : 16 : first_sync_complete(void *cb_arg, int bserrno)
7239 : : {
7240 : 16 : struct spdk_blob *blob = cb_arg;
7241 : : int rc;
7242 : :
7243 : 16 : CU_ASSERT(bserrno == 0);
7244 : 16 : rc = spdk_blob_set_xattr(blob, "sync", "second", strlen("second") + 1);
7245 : 16 : CU_ASSERT(rc == 0);
7246 : 16 : CU_ASSERT(g_bserrno == -1);
7247 : :
7248 : : /* Keep g_bserrno at -1, only the
7249 : : * second sync completion should set it at 0. */
7250 : 16 : }
7251 : :
7252 : : static void
7253 : 16 : second_sync_complete(void *cb_arg, int bserrno)
7254 : : {
7255 : 16 : struct spdk_blob *blob = cb_arg;
7256 : 16 : const void *value;
7257 : 16 : size_t value_len;
7258 : : int rc;
7259 : :
7260 : 16 : CU_ASSERT(bserrno == 0);
7261 : :
7262 : : /* Verify that the first sync completion had a chance to execute */
7263 : 16 : rc = spdk_blob_get_xattr_value(blob, "sync", &value, &value_len);
7264 : 16 : CU_ASSERT(rc == 0);
7265 [ - + ]: 16 : SPDK_CU_ASSERT_FATAL(value != NULL);
7266 : 16 : CU_ASSERT(value_len == strlen("second") + 1);
7267 [ - + ]: 16 : CU_ASSERT_NSTRING_EQUAL_FATAL(value, "second", value_len);
7268 : :
7269 : 16 : CU_ASSERT(g_bserrno == -1);
7270 : 16 : g_bserrno = bserrno;
7271 : 16 : }
7272 : :
7273 : : static void
7274 : 16 : blob_simultaneous_operations(void)
7275 : : {
7276 : 16 : struct spdk_blob_store *bs = g_bs;
7277 : 16 : struct spdk_blob_opts opts;
7278 : : struct spdk_blob *blob, *snapshot;
7279 : : spdk_blob_id blobid, snapshotid;
7280 : : struct spdk_io_channel *channel;
7281 : : int rc;
7282 : :
7283 : 16 : channel = spdk_bs_alloc_io_channel(bs);
7284 [ - + ]: 16 : SPDK_CU_ASSERT_FATAL(channel != NULL);
7285 : :
7286 : 16 : ut_spdk_blob_opts_init(&opts);
7287 : 16 : opts.num_clusters = 10;
7288 : :
7289 : 16 : blob = ut_blob_create_and_open(bs, &opts);
7290 : 16 : blobid = spdk_blob_get_id(blob);
7291 : :
7292 : : /* Create snapshot and try to remove blob in the same time:
7293 : : * - snapshot should be created successfully
7294 : : * - delete operation should fail w -EBUSY */
7295 [ - + ]: 16 : CU_ASSERT(blob->locked_operation_in_progress == false);
7296 : 16 : spdk_bs_create_snapshot(bs, blobid, NULL, blob_op_with_id_complete, NULL);
7297 [ - + ]: 16 : CU_ASSERT(blob->locked_operation_in_progress == true);
7298 : 16 : spdk_bs_delete_blob(bs, blobid, blob_op_complete, NULL);
7299 [ - + ]: 16 : CU_ASSERT(blob->locked_operation_in_progress == true);
7300 : : /* Deletion failure */
7301 : 16 : CU_ASSERT(g_bserrno == -EBUSY);
7302 : 16 : poll_threads();
7303 [ - + ]: 16 : CU_ASSERT(blob->locked_operation_in_progress == false);
7304 : : /* Snapshot creation success */
7305 : 16 : CU_ASSERT(g_bserrno == 0);
7306 : 16 : CU_ASSERT(g_blobid != SPDK_BLOBID_INVALID);
7307 : :
7308 : 16 : snapshotid = g_blobid;
7309 : :
7310 : 16 : spdk_bs_open_blob(bs, snapshotid, blob_op_with_handle_complete, NULL);
7311 : 16 : poll_threads();
7312 : 16 : CU_ASSERT(g_bserrno == 0);
7313 [ - + ]: 16 : SPDK_CU_ASSERT_FATAL(g_blob != NULL);
7314 : 16 : snapshot = g_blob;
7315 : :
7316 : : /* Inflate blob and try to remove blob in the same time:
7317 : : * - blob should be inflated successfully
7318 : : * - delete operation should fail w -EBUSY */
7319 [ - + ]: 16 : CU_ASSERT(blob->locked_operation_in_progress == false);
7320 : 16 : spdk_bs_inflate_blob(bs, channel, blobid, blob_op_complete, NULL);
7321 [ - + ]: 16 : CU_ASSERT(blob->locked_operation_in_progress == true);
7322 : 16 : spdk_bs_delete_blob(bs, blobid, blob_op_complete, NULL);
7323 [ - + ]: 16 : CU_ASSERT(blob->locked_operation_in_progress == true);
7324 : : /* Deletion failure */
7325 : 16 : CU_ASSERT(g_bserrno == -EBUSY);
7326 : 16 : poll_threads();
7327 [ - + ]: 16 : CU_ASSERT(blob->locked_operation_in_progress == false);
7328 : : /* Inflation success */
7329 : 16 : CU_ASSERT(g_bserrno == 0);
7330 : :
7331 : : /* Clone snapshot and try to remove snapshot in the same time:
7332 : : * - snapshot should be cloned successfully
7333 : : * - delete operation should fail w -EBUSY */
7334 [ - + ]: 16 : CU_ASSERT(blob->locked_operation_in_progress == false);
7335 : 16 : spdk_bs_create_clone(bs, snapshotid, NULL, blob_op_with_id_complete, NULL);
7336 : 16 : spdk_bs_delete_blob(bs, snapshotid, blob_op_complete, NULL);
7337 : : /* Deletion failure */
7338 : 16 : CU_ASSERT(g_bserrno == -EBUSY);
7339 : 16 : poll_threads();
7340 [ - + ]: 16 : CU_ASSERT(blob->locked_operation_in_progress == false);
7341 : : /* Clone created */
7342 : 16 : CU_ASSERT(g_bserrno == 0);
7343 : :
7344 : : /* Resize blob and try to remove blob in the same time:
7345 : : * - blob should be resized successfully
7346 : : * - delete operation should fail w -EBUSY */
7347 [ - + ]: 16 : CU_ASSERT(blob->locked_operation_in_progress == false);
7348 : 16 : spdk_blob_resize(blob, 50, blob_op_complete, NULL);
7349 [ - + ]: 16 : CU_ASSERT(blob->locked_operation_in_progress == true);
7350 : 16 : spdk_bs_delete_blob(bs, blobid, blob_op_complete, NULL);
7351 [ - + ]: 16 : CU_ASSERT(blob->locked_operation_in_progress == true);
7352 : : /* Deletion failure */
7353 : 16 : CU_ASSERT(g_bserrno == -EBUSY);
7354 : 16 : poll_threads();
7355 [ - + ]: 16 : CU_ASSERT(blob->locked_operation_in_progress == false);
7356 : : /* Blob resized successfully */
7357 : 16 : spdk_blob_sync_md(blob, blob_op_complete, NULL);
7358 : 16 : poll_threads();
7359 : 16 : CU_ASSERT(g_bserrno == 0);
7360 : :
7361 : : /* Issue two consecutive blob syncs, neither should fail.
7362 : : * Force sync to actually occur by marking blob dirty each time.
7363 : : * Execution of sync should not be enough to complete the operation,
7364 : : * since disk I/O is required to complete it. */
7365 : 16 : g_bserrno = -1;
7366 : :
7367 : 16 : rc = spdk_blob_set_xattr(blob, "sync", "first", strlen("first") + 1);
7368 : 16 : CU_ASSERT(rc == 0);
7369 : 16 : spdk_blob_sync_md(blob, first_sync_complete, blob);
7370 : 16 : CU_ASSERT(g_bserrno == -1);
7371 : :
7372 : 16 : spdk_blob_sync_md(blob, second_sync_complete, blob);
7373 : 16 : CU_ASSERT(g_bserrno == -1);
7374 : :
7375 : 16 : poll_threads();
7376 : 16 : CU_ASSERT(g_bserrno == 0);
7377 : :
7378 : 16 : spdk_bs_free_io_channel(channel);
7379 : 16 : poll_threads();
7380 : :
7381 : 16 : ut_blob_close_and_delete(bs, snapshot);
7382 : 16 : ut_blob_close_and_delete(bs, blob);
7383 : 16 : }
7384 : :
7385 : : static void
7386 : 16 : blob_persist_test(void)
7387 : : {
7388 : 16 : struct spdk_blob_store *bs = g_bs;
7389 : 16 : struct spdk_blob_opts opts;
7390 : : struct spdk_blob *blob;
7391 : : spdk_blob_id blobid;
7392 : : struct spdk_io_channel *channel;
7393 : 16 : char *xattr;
7394 : 16 : size_t xattr_length;
7395 : : int rc;
7396 : : uint32_t page_count_clear, page_count_xattr;
7397 : : uint64_t poller_iterations;
7398 : : bool run_poller;
7399 : :
7400 : 16 : channel = spdk_bs_alloc_io_channel(bs);
7401 [ - + ]: 16 : SPDK_CU_ASSERT_FATAL(channel != NULL);
7402 : :
7403 : 16 : ut_spdk_blob_opts_init(&opts);
7404 : 16 : opts.num_clusters = 10;
7405 : :
7406 : 16 : blob = ut_blob_create_and_open(bs, &opts);
7407 : 16 : blobid = spdk_blob_get_id(blob);
7408 : :
7409 : : /* Save the amount of md pages used after creation of a blob.
7410 : : * This should be consistent after removing xattr. */
7411 : 16 : page_count_clear = spdk_bit_array_count_set(bs->used_md_pages);
7412 [ - + ]: 16 : SPDK_CU_ASSERT_FATAL(blob->active.num_pages + blob->active.num_extent_pages == page_count_clear);
7413 [ - + ]: 16 : SPDK_CU_ASSERT_FATAL(blob->clean.num_pages + blob->clean.num_extent_pages == page_count_clear);
7414 : :
7415 : : /* Add xattr with maximum length of descriptor to exceed single metadata page. */
7416 : 16 : xattr_length = SPDK_BS_MAX_DESC_SIZE - sizeof(struct spdk_blob_md_descriptor_xattr) -
7417 : : strlen("large_xattr");
7418 : 16 : xattr = calloc(xattr_length, sizeof(char));
7419 [ - + ]: 16 : SPDK_CU_ASSERT_FATAL(xattr != NULL);
7420 : :
7421 : 16 : rc = spdk_blob_set_xattr(blob, "large_xattr", xattr, xattr_length);
7422 [ - + ]: 16 : SPDK_CU_ASSERT_FATAL(rc == 0);
7423 : 16 : spdk_blob_sync_md(blob, blob_op_complete, NULL);
7424 : 16 : poll_threads();
7425 [ - + ]: 16 : SPDK_CU_ASSERT_FATAL(g_bserrno == 0);
7426 : :
7427 : : /* Save the amount of md pages used after adding the large xattr */
7428 : 16 : page_count_xattr = spdk_bit_array_count_set(bs->used_md_pages);
7429 [ - + ]: 16 : SPDK_CU_ASSERT_FATAL(blob->active.num_pages + blob->active.num_extent_pages == page_count_xattr);
7430 [ - + ]: 16 : SPDK_CU_ASSERT_FATAL(blob->clean.num_pages + blob->clean.num_extent_pages == page_count_xattr);
7431 : :
7432 : : /* Add xattr to a blob and sync it. While sync is occurring, remove the xattr and sync again.
7433 : : * Interrupt the first sync after increasing number of poller iterations, until it succeeds.
7434 : : * Expectation is that after second sync completes no xattr is saved in metadata. */
7435 : 16 : poller_iterations = 1;
7436 : 16 : run_poller = true;
7437 [ + + ]: 112 : while (run_poller) {
7438 : 96 : rc = spdk_blob_set_xattr(blob, "large_xattr", xattr, xattr_length);
7439 [ - + ]: 96 : SPDK_CU_ASSERT_FATAL(rc == 0);
7440 : 96 : g_bserrno = -1;
7441 : 96 : spdk_blob_sync_md(blob, blob_op_complete, NULL);
7442 : 96 : poll_thread_times(0, poller_iterations);
7443 [ + + ]: 96 : if (g_bserrno == 0) {
7444 : : /* Poller iteration count was high enough for first sync to complete.
7445 : : * Verify that blob takes up enough of md_pages to store the xattr. */
7446 [ - + ]: 16 : SPDK_CU_ASSERT_FATAL(blob->active.num_pages + blob->active.num_extent_pages == page_count_xattr);
7447 [ - + ]: 16 : SPDK_CU_ASSERT_FATAL(blob->clean.num_pages + blob->clean.num_extent_pages == page_count_xattr);
7448 [ - + ]: 16 : SPDK_CU_ASSERT_FATAL(spdk_bit_array_count_set(bs->used_md_pages) == page_count_xattr);
7449 : 16 : run_poller = false;
7450 : : }
7451 : 96 : rc = spdk_blob_remove_xattr(blob, "large_xattr");
7452 [ - + ]: 96 : SPDK_CU_ASSERT_FATAL(rc == 0);
7453 : 96 : spdk_blob_sync_md(blob, blob_op_complete, NULL);
7454 : 96 : poll_threads();
7455 [ - + ]: 96 : SPDK_CU_ASSERT_FATAL(g_bserrno == 0);
7456 [ - + ]: 96 : SPDK_CU_ASSERT_FATAL(blob->active.num_pages + blob->active.num_extent_pages == page_count_clear);
7457 [ - + ]: 96 : SPDK_CU_ASSERT_FATAL(blob->clean.num_pages + blob->clean.num_extent_pages == page_count_clear);
7458 [ - + ]: 96 : SPDK_CU_ASSERT_FATAL(spdk_bit_array_count_set(bs->used_md_pages) == page_count_clear);
7459 : :
7460 : : /* Reload bs and re-open blob to verify that xattr was not persisted. */
7461 : 96 : spdk_blob_close(blob, blob_op_complete, NULL);
7462 : 96 : poll_threads();
7463 : 96 : CU_ASSERT(g_bserrno == 0);
7464 : :
7465 : 96 : ut_bs_reload(&bs, NULL);
7466 : :
7467 : 96 : spdk_bs_open_blob(bs, blobid, blob_op_with_handle_complete, NULL);
7468 : 96 : poll_threads();
7469 : 96 : CU_ASSERT(g_bserrno == 0);
7470 [ - + ]: 96 : SPDK_CU_ASSERT_FATAL(g_blob != NULL);
7471 : 96 : blob = g_blob;
7472 : :
7473 : 96 : rc = spdk_blob_get_xattr_value(blob, "large_xattr", (const void **)&xattr, &xattr_length);
7474 [ - + ]: 96 : SPDK_CU_ASSERT_FATAL(rc == -ENOENT);
7475 : :
7476 : 96 : poller_iterations++;
7477 : : /* Stop at high iteration count to prevent infinite loop.
7478 : : * This value should be enough for first md sync to complete in any case. */
7479 [ - + ]: 96 : SPDK_CU_ASSERT_FATAL(poller_iterations < 50);
7480 : : }
7481 : :
7482 : 16 : free(xattr);
7483 : :
7484 : 16 : ut_blob_close_and_delete(bs, blob);
7485 : :
7486 : 16 : spdk_bs_free_io_channel(channel);
7487 : 16 : poll_threads();
7488 : 16 : }
7489 : :
7490 : : static void
7491 : 16 : blob_decouple_snapshot(void)
7492 : : {
7493 : 16 : struct spdk_blob_store *bs = g_bs;
7494 : 16 : struct spdk_blob_opts opts;
7495 : : struct spdk_blob *blob, *snapshot1, *snapshot2;
7496 : : struct spdk_io_channel *channel;
7497 : : spdk_blob_id blobid, snapshotid;
7498 : : uint64_t cluster;
7499 : :
7500 [ + + ]: 48 : for (int delete_snapshot_first = 0; delete_snapshot_first <= 1; delete_snapshot_first++) {
7501 : 32 : channel = spdk_bs_alloc_io_channel(bs);
7502 [ - + ]: 32 : SPDK_CU_ASSERT_FATAL(channel != NULL);
7503 : :
7504 : 32 : ut_spdk_blob_opts_init(&opts);
7505 : 32 : opts.num_clusters = 10;
7506 : 32 : opts.thin_provision = false;
7507 : :
7508 : 32 : blob = ut_blob_create_and_open(bs, &opts);
7509 : 32 : blobid = spdk_blob_get_id(blob);
7510 : :
7511 : : /* Create first snapshot */
7512 : 32 : CU_ASSERT_EQUAL(_get_snapshots_count(bs), 0);
7513 : 32 : spdk_bs_create_snapshot(bs, blobid, NULL, blob_op_with_id_complete, NULL);
7514 : 32 : poll_threads();
7515 : 32 : CU_ASSERT(g_bserrno == 0);
7516 : 32 : CU_ASSERT(g_blobid != SPDK_BLOBID_INVALID);
7517 : 32 : CU_ASSERT_EQUAL(_get_snapshots_count(bs), 1);
7518 : 32 : snapshotid = g_blobid;
7519 : :
7520 : 32 : spdk_bs_open_blob(bs, snapshotid, blob_op_with_handle_complete, NULL);
7521 : 32 : poll_threads();
7522 : 32 : CU_ASSERT(g_bserrno == 0);
7523 [ - + ]: 32 : SPDK_CU_ASSERT_FATAL(g_blob != NULL);
7524 : 32 : snapshot1 = g_blob;
7525 : :
7526 : : /* Create the second one */
7527 : 32 : CU_ASSERT_EQUAL(_get_snapshots_count(bs), 1);
7528 : 32 : spdk_bs_create_snapshot(bs, blobid, NULL, blob_op_with_id_complete, NULL);
7529 : 32 : poll_threads();
7530 : 32 : CU_ASSERT(g_bserrno == 0);
7531 : 32 : CU_ASSERT(g_blobid != SPDK_BLOBID_INVALID);
7532 : 32 : CU_ASSERT_EQUAL(_get_snapshots_count(bs), 2);
7533 : 32 : snapshotid = g_blobid;
7534 : :
7535 : 32 : spdk_bs_open_blob(bs, snapshotid, blob_op_with_handle_complete, NULL);
7536 : 32 : poll_threads();
7537 : 32 : CU_ASSERT(g_bserrno == 0);
7538 [ - + ]: 32 : SPDK_CU_ASSERT_FATAL(g_blob != NULL);
7539 : 32 : snapshot2 = g_blob;
7540 : 32 : CU_ASSERT_EQUAL(spdk_blob_get_parent_snapshot(bs, snapshot2->id), snapshot1->id);
7541 : :
7542 : : /* Now decouple the second snapshot forcing it to copy the written clusters */
7543 : 32 : spdk_bs_blob_decouple_parent(bs, channel, snapshot2->id, blob_op_complete, NULL);
7544 : 32 : poll_threads();
7545 : 32 : CU_ASSERT(g_bserrno == 0);
7546 : :
7547 : : /* Verify that the snapshot has been decoupled and that the clusters have been copied */
7548 : 32 : CU_ASSERT_EQUAL(spdk_blob_get_parent_snapshot(bs, snapshot2->id), SPDK_BLOBID_INVALID);
7549 [ + + ]: 352 : for (cluster = 0; cluster < snapshot2->active.num_clusters; ++cluster) {
7550 : 320 : CU_ASSERT_NOT_EQUAL(snapshot2->active.clusters[cluster], 0);
7551 : 320 : CU_ASSERT_NOT_EQUAL(snapshot2->active.clusters[cluster],
7552 : : snapshot1->active.clusters[cluster]);
7553 : : }
7554 : :
7555 : 32 : spdk_bs_free_io_channel(channel);
7556 : :
7557 [ + + ]: 32 : if (delete_snapshot_first) {
7558 : 16 : ut_blob_close_and_delete(bs, snapshot2);
7559 : 16 : ut_blob_close_and_delete(bs, snapshot1);
7560 : 16 : ut_blob_close_and_delete(bs, blob);
7561 : : } else {
7562 : 16 : ut_blob_close_and_delete(bs, blob);
7563 : 16 : ut_blob_close_and_delete(bs, snapshot2);
7564 : 16 : ut_blob_close_and_delete(bs, snapshot1);
7565 : : }
7566 : 32 : poll_threads();
7567 : : }
7568 : 16 : }
7569 : :
7570 : : static void
7571 : 16 : blob_seek_io_unit(void)
7572 : : {
7573 : 16 : struct spdk_blob_store *bs = g_bs;
7574 : : struct spdk_blob *blob;
7575 : : struct spdk_io_channel *channel;
7576 : 16 : struct spdk_blob_opts opts;
7577 : : uint64_t free_clusters;
7578 : 16 : uint8_t payload[10 * 4096];
7579 : : uint64_t offset;
7580 : : uint64_t io_unit, io_units_per_cluster;
7581 : :
7582 : 16 : free_clusters = spdk_bs_free_cluster_count(bs);
7583 : :
7584 : 16 : channel = spdk_bs_alloc_io_channel(bs);
7585 : 16 : CU_ASSERT(channel != NULL);
7586 : :
7587 : : /* Set blob as thin provisioned */
7588 : 16 : ut_spdk_blob_opts_init(&opts);
7589 : 16 : opts.thin_provision = true;
7590 : :
7591 : : /* Create a blob */
7592 : 16 : blob = ut_blob_create_and_open(bs, &opts);
7593 : 16 : CU_ASSERT(free_clusters == spdk_bs_free_cluster_count(bs));
7594 : :
7595 : 16 : io_units_per_cluster = bs_io_units_per_cluster(blob);
7596 : :
7597 : : /* The blob started at 0 clusters. Resize it to be 5, but still unallocated. */
7598 : 16 : spdk_blob_resize(blob, 5, blob_op_complete, NULL);
7599 : 16 : poll_threads();
7600 : 16 : CU_ASSERT(g_bserrno == 0);
7601 : 16 : CU_ASSERT(free_clusters == spdk_bs_free_cluster_count(bs));
7602 : 16 : CU_ASSERT(blob->active.num_clusters == 5);
7603 : :
7604 : : /* Write at the beginning of first cluster */
7605 : 16 : offset = 0;
7606 : 16 : spdk_blob_io_write(blob, channel, payload, offset, 1, blob_op_complete, NULL);
7607 : 16 : poll_threads();
7608 : 16 : CU_ASSERT(g_bserrno == 0);
7609 : :
7610 : 16 : io_unit = spdk_blob_get_next_allocated_io_unit(blob, 0);
7611 : 16 : CU_ASSERT(io_unit == offset);
7612 : :
7613 : 16 : io_unit = spdk_blob_get_next_unallocated_io_unit(blob, 0);
7614 : 16 : CU_ASSERT(io_unit == io_units_per_cluster);
7615 : :
7616 : : /* Write in the middle of third cluster */
7617 : 16 : offset = 2 * io_units_per_cluster + io_units_per_cluster / 2;
7618 : 16 : spdk_blob_io_write(blob, channel, payload, offset, 1, blob_op_complete, NULL);
7619 : 16 : poll_threads();
7620 : 16 : CU_ASSERT(g_bserrno == 0);
7621 : :
7622 : 16 : io_unit = spdk_blob_get_next_allocated_io_unit(blob, io_units_per_cluster);
7623 : 16 : CU_ASSERT(io_unit == 2 * io_units_per_cluster);
7624 : :
7625 : 16 : io_unit = spdk_blob_get_next_unallocated_io_unit(blob, 2 * io_units_per_cluster);
7626 : 16 : CU_ASSERT(io_unit == 3 * io_units_per_cluster);
7627 : :
7628 : : /* Write at the end of last cluster */
7629 : 16 : offset = 5 * io_units_per_cluster - 1;
7630 : 16 : spdk_blob_io_write(blob, channel, payload, offset, 1, blob_op_complete, NULL);
7631 : 16 : poll_threads();
7632 : 16 : CU_ASSERT(g_bserrno == 0);
7633 : :
7634 : 16 : io_unit = spdk_blob_get_next_allocated_io_unit(blob, 3 * io_units_per_cluster);
7635 : 16 : CU_ASSERT(io_unit == 4 * io_units_per_cluster);
7636 : :
7637 : 16 : io_unit = spdk_blob_get_next_unallocated_io_unit(blob, 4 * io_units_per_cluster);
7638 : 16 : CU_ASSERT(io_unit == UINT64_MAX);
7639 : :
7640 : 16 : spdk_bs_free_io_channel(channel);
7641 : 16 : poll_threads();
7642 : :
7643 : 16 : ut_blob_close_and_delete(bs, blob);
7644 : 16 : }
7645 : :
7646 : : static void
7647 : 16 : blob_esnap_create(void)
7648 : : {
7649 : 16 : struct spdk_blob_store *bs = g_bs;
7650 : 16 : struct spdk_bs_opts bs_opts;
7651 : 16 : struct ut_esnap_opts esnap_opts;
7652 : 16 : struct spdk_blob_opts opts;
7653 : 16 : struct spdk_blob_open_opts open_opts;
7654 : : struct spdk_blob *blob;
7655 : : uint32_t cluster_sz, block_sz;
7656 : 16 : const uint32_t esnap_num_clusters = 4;
7657 : : uint64_t esnap_num_blocks;
7658 : : uint32_t sz;
7659 : : spdk_blob_id blobid;
7660 : 16 : uint32_t bs_ctx_count, blob_ctx_count;
7661 : :
7662 : 16 : cluster_sz = spdk_bs_get_cluster_size(bs);
7663 : 16 : block_sz = spdk_bs_get_io_unit_size(bs);
7664 [ - + ]: 16 : esnap_num_blocks = cluster_sz * esnap_num_clusters / block_sz;
7665 : :
7666 : : /* Create a normal blob and verify it is not an esnap clone. */
7667 : 16 : ut_spdk_blob_opts_init(&opts);
7668 : 16 : blob = ut_blob_create_and_open(bs, &opts);
7669 : 16 : CU_ASSERT(!spdk_blob_is_esnap_clone(blob));
7670 : 16 : ut_blob_close_and_delete(bs, blob);
7671 : :
7672 : : /* Create an esnap clone blob then verify it is an esnap clone and has the right size */
7673 : 16 : ut_spdk_blob_opts_init(&opts);
7674 : 16 : ut_esnap_opts_init(block_sz, esnap_num_blocks, __func__, NULL, &esnap_opts);
7675 : 16 : opts.esnap_id = &esnap_opts;
7676 : 16 : opts.esnap_id_len = sizeof(esnap_opts);
7677 : 16 : opts.num_clusters = esnap_num_clusters;
7678 : 16 : blob = ut_blob_create_and_open(bs, &opts);
7679 [ - + ]: 16 : SPDK_CU_ASSERT_FATAL(blob != NULL);
7680 [ - + ]: 16 : SPDK_CU_ASSERT_FATAL(spdk_blob_is_esnap_clone(blob));
7681 [ - + ]: 16 : SPDK_CU_ASSERT_FATAL(blob_is_esnap_clone(blob));
7682 [ - + ]: 16 : SPDK_CU_ASSERT_FATAL(!spdk_blob_is_clone(blob));
7683 : 16 : sz = spdk_blob_get_num_clusters(blob);
7684 : 16 : CU_ASSERT(sz == esnap_num_clusters);
7685 : 16 : ut_blob_close_and_delete(bs, blob);
7686 : :
7687 : : /* Create an esnap clone without the size and verify it can be grown */
7688 : 16 : ut_spdk_blob_opts_init(&opts);
7689 : 16 : ut_esnap_opts_init(block_sz, esnap_num_blocks, __func__, NULL, &esnap_opts);
7690 : 16 : opts.esnap_id = &esnap_opts;
7691 : 16 : opts.esnap_id_len = sizeof(esnap_opts);
7692 : 16 : blob = ut_blob_create_and_open(bs, &opts);
7693 [ - + ]: 16 : SPDK_CU_ASSERT_FATAL(spdk_blob_is_esnap_clone(blob));
7694 : 16 : sz = spdk_blob_get_num_clusters(blob);
7695 : 16 : CU_ASSERT(sz == 0);
7696 : 16 : spdk_blob_resize(blob, 1, blob_op_complete, NULL);
7697 : 16 : poll_threads();
7698 : 16 : CU_ASSERT(g_bserrno == 0);
7699 : 16 : sz = spdk_blob_get_num_clusters(blob);
7700 : 16 : CU_ASSERT(sz == 1);
7701 : 16 : spdk_blob_resize(blob, esnap_num_clusters, blob_op_complete, NULL);
7702 : 16 : poll_threads();
7703 : 16 : CU_ASSERT(g_bserrno == 0);
7704 : 16 : sz = spdk_blob_get_num_clusters(blob);
7705 : 16 : CU_ASSERT(sz == esnap_num_clusters);
7706 : 16 : spdk_blob_resize(blob, esnap_num_clusters + 1, blob_op_complete, NULL);
7707 : 16 : poll_threads();
7708 : 16 : CU_ASSERT(g_bserrno == 0);
7709 : 16 : sz = spdk_blob_get_num_clusters(blob);
7710 : 16 : CU_ASSERT(sz == esnap_num_clusters + 1);
7711 : :
7712 : : /* Reload the blobstore and be sure that the blob can be opened. */
7713 : 16 : blobid = spdk_blob_get_id(blob);
7714 : 16 : spdk_blob_close(blob, blob_op_complete, NULL);
7715 : 16 : poll_threads();
7716 : 16 : CU_ASSERT(g_bserrno == 0);
7717 : 16 : g_blob = NULL;
7718 : 16 : spdk_bs_opts_init(&bs_opts, sizeof(bs_opts));
7719 : 16 : bs_opts.esnap_bs_dev_create = ut_esnap_create;
7720 : 16 : ut_bs_reload(&bs, &bs_opts);
7721 : 16 : spdk_bs_open_blob(bs, blobid, blob_op_with_handle_complete, NULL);
7722 : 16 : poll_threads();
7723 : 16 : CU_ASSERT(g_bserrno == 0);
7724 : 16 : CU_ASSERT(g_blob != NULL);
7725 : 16 : blob = g_blob;
7726 [ - + ]: 16 : SPDK_CU_ASSERT_FATAL(spdk_blob_is_esnap_clone(blob));
7727 : 16 : sz = spdk_blob_get_num_clusters(blob);
7728 : 16 : CU_ASSERT(sz == esnap_num_clusters + 1);
7729 : :
7730 : : /* Reload the blobstore without esnap_bs_dev_create: should fail to open blob. */
7731 : 16 : spdk_blob_close(blob, blob_op_complete, NULL);
7732 : 16 : poll_threads();
7733 : 16 : CU_ASSERT(g_bserrno == 0);
7734 : 16 : g_blob = NULL;
7735 : 16 : spdk_bs_opts_init(&bs_opts, sizeof(bs_opts));
7736 : 16 : ut_bs_reload(&bs, &bs_opts);
7737 : 16 : spdk_bs_open_blob(bs, blobid, blob_op_with_handle_complete, NULL);
7738 : 16 : poll_threads();
7739 : 16 : CU_ASSERT(g_bserrno != 0);
7740 : 16 : CU_ASSERT(g_blob == NULL);
7741 : :
7742 : : /* Reload the blobstore with ctx set and verify it is passed to the esnap create callback */
7743 : 16 : bs_ctx_count = 0;
7744 : 16 : spdk_bs_opts_init(&bs_opts, sizeof(bs_opts));
7745 : 16 : bs_opts.esnap_bs_dev_create = ut_esnap_create_with_count;
7746 : 16 : bs_opts.esnap_ctx = &bs_ctx_count;
7747 : 16 : ut_bs_reload(&bs, &bs_opts);
7748 : : /* Loading the blobstore triggers the esnap to be loaded */
7749 : 16 : CU_ASSERT(bs_ctx_count == 1);
7750 : 16 : spdk_bs_open_blob(bs, blobid, blob_op_with_handle_complete, NULL);
7751 : 16 : poll_threads();
7752 : 16 : CU_ASSERT(g_bserrno == 0);
7753 : 16 : CU_ASSERT(g_blob != NULL);
7754 : : /* Opening the blob also triggers the esnap to be loaded */
7755 : 16 : CU_ASSERT(bs_ctx_count == 2);
7756 : 16 : blob = g_blob;
7757 [ - + ]: 16 : SPDK_CU_ASSERT_FATAL(spdk_blob_is_esnap_clone(blob));
7758 : 16 : sz = spdk_blob_get_num_clusters(blob);
7759 : 16 : CU_ASSERT(sz == esnap_num_clusters + 1);
7760 : 16 : spdk_blob_close(blob, blob_op_complete, NULL);
7761 : 16 : poll_threads();
7762 : 16 : CU_ASSERT(g_bserrno == 0);
7763 : 16 : g_blob = NULL;
7764 : : /* If open_opts.esnap_ctx is set it is passed to the esnap create callback */
7765 : 16 : blob_ctx_count = 0;
7766 : 16 : spdk_blob_open_opts_init(&open_opts, sizeof(open_opts));
7767 : 16 : open_opts.esnap_ctx = &blob_ctx_count;
7768 : 16 : spdk_bs_open_blob_ext(bs, blobid, &open_opts, blob_op_with_handle_complete, NULL);
7769 : 16 : poll_threads();
7770 : 16 : blob = g_blob;
7771 : 16 : CU_ASSERT(bs_ctx_count == 3);
7772 : 16 : CU_ASSERT(blob_ctx_count == 1);
7773 : 16 : spdk_blob_close(blob, blob_op_complete, NULL);
7774 : 16 : poll_threads();
7775 : 16 : CU_ASSERT(g_bserrno == 0);
7776 : 16 : g_blob = NULL;
7777 : 16 : }
7778 : :
7779 : : static void
7780 : 16 : blob_esnap_clone_reload(void)
7781 : 16 : {
7782 : 16 : struct spdk_blob_store *bs = g_bs;
7783 : 16 : struct spdk_bs_opts bs_opts;
7784 : 16 : struct ut_esnap_opts esnap_opts;
7785 : 16 : struct spdk_blob_opts opts;
7786 : : struct spdk_blob *eclone1, *snap1, *clone1;
7787 : 16 : uint32_t cluster_sz = spdk_bs_get_cluster_size(bs);
7788 : 16 : uint32_t block_sz = spdk_bs_get_io_unit_size(bs);
7789 : 16 : const uint32_t esnap_num_clusters = 4;
7790 [ - + ]: 16 : uint64_t esnap_num_blocks = cluster_sz * esnap_num_clusters / block_sz;
7791 : : spdk_blob_id eclone1_id, snap1_id, clone1_id;
7792 : : struct spdk_io_channel *bs_ch;
7793 [ - + ]: 16 : char buf[block_sz];
7794 : 16 : int bserr1, bserr2, bserr3, bserr4;
7795 : : struct spdk_bs_dev *dev;
7796 : :
7797 : : /* Create and open an esnap clone blob */
7798 : 16 : ut_spdk_blob_opts_init(&opts);
7799 : 16 : ut_esnap_opts_init(block_sz, esnap_num_blocks, __func__, NULL, &esnap_opts);
7800 : 16 : opts.esnap_id = &esnap_opts;
7801 : 16 : opts.esnap_id_len = sizeof(esnap_opts);
7802 : 16 : opts.num_clusters = esnap_num_clusters;
7803 : 16 : eclone1 = ut_blob_create_and_open(bs, &opts);
7804 : 16 : CU_ASSERT(eclone1 != NULL);
7805 : 16 : CU_ASSERT(spdk_blob_is_esnap_clone(eclone1));
7806 : 16 : eclone1_id = eclone1->id;
7807 : :
7808 : : /* Create and open a snapshot of eclone1 */
7809 : 16 : spdk_bs_create_snapshot(bs, eclone1_id, NULL, blob_op_with_id_complete, NULL);
7810 : 16 : poll_threads();
7811 : 16 : CU_ASSERT(g_blobid != SPDK_BLOBID_INVALID);
7812 : 16 : CU_ASSERT(g_bserrno == 0);
7813 : 16 : snap1_id = g_blobid;
7814 : 16 : spdk_bs_open_blob(bs, snap1_id, blob_op_with_handle_complete, NULL);
7815 : 16 : poll_threads();
7816 : 16 : CU_ASSERT(g_bserrno == 0);
7817 : 16 : CU_ASSERT(g_blob != NULL);
7818 : 16 : snap1 = g_blob;
7819 : :
7820 : : /* Create and open regular clone of snap1 */
7821 : 16 : spdk_bs_create_clone(bs, snap1_id, NULL, blob_op_with_id_complete, NULL);
7822 : 16 : poll_threads();
7823 : 16 : CU_ASSERT(g_blobid != SPDK_BLOBID_INVALID);
7824 [ - + ]: 16 : SPDK_CU_ASSERT_FATAL(g_bserrno == 0);
7825 : 16 : clone1_id = g_blobid;
7826 : 16 : spdk_bs_open_blob(bs, clone1_id, blob_op_with_handle_complete, NULL);
7827 : 16 : poll_threads();
7828 : 16 : CU_ASSERT(g_bserrno == 0);
7829 : 16 : CU_ASSERT(g_blob != NULL);
7830 : 16 : clone1 = g_blob;
7831 : :
7832 : : /* Close the blobs in preparation for reloading the blobstore */
7833 : 16 : spdk_blob_close(clone1, blob_op_complete, NULL);
7834 : 16 : poll_threads();
7835 : 16 : CU_ASSERT(g_bserrno == 0);
7836 : 16 : spdk_blob_close(snap1, blob_op_complete, NULL);
7837 : 16 : poll_threads();
7838 : 16 : CU_ASSERT(g_bserrno == 0);
7839 : 16 : spdk_blob_close(eclone1, blob_op_complete, NULL);
7840 : 16 : poll_threads();
7841 : 16 : CU_ASSERT(g_bserrno == 0);
7842 : 16 : g_blob = NULL;
7843 : :
7844 : : /* Reload the blobstore */
7845 : 16 : spdk_bs_opts_init(&bs_opts, sizeof(bs_opts));
7846 : 16 : bs_opts.esnap_bs_dev_create = ut_esnap_create;
7847 : 16 : ut_bs_reload(&bs, &bs_opts);
7848 : :
7849 : : /* Be sure each of the blobs can be opened */
7850 : 16 : spdk_bs_open_blob(bs, eclone1_id, blob_op_with_handle_complete, NULL);
7851 : 16 : poll_threads();
7852 : 16 : CU_ASSERT(g_bserrno == 0);
7853 : 16 : CU_ASSERT(g_blob != NULL);
7854 : 16 : eclone1 = g_blob;
7855 : 16 : spdk_bs_open_blob(bs, snap1_id, blob_op_with_handle_complete, NULL);
7856 : 16 : poll_threads();
7857 : 16 : CU_ASSERT(g_bserrno == 0);
7858 : 16 : CU_ASSERT(g_blob != NULL);
7859 : 16 : snap1 = g_blob;
7860 : 16 : spdk_bs_open_blob(bs, clone1_id, blob_op_with_handle_complete, NULL);
7861 : 16 : poll_threads();
7862 : 16 : CU_ASSERT(g_bserrno == 0);
7863 : 16 : CU_ASSERT(g_blob != NULL);
7864 : 16 : clone1 = g_blob;
7865 : :
7866 : : /* Perform some reads on each of them to cause channels to be allocated */
7867 : 16 : bs_ch = spdk_bs_alloc_io_channel(bs);
7868 : 16 : CU_ASSERT(bs_ch != NULL);
7869 : 16 : spdk_blob_io_read(eclone1, bs_ch, buf, 0, 1, bs_op_complete, NULL);
7870 : 16 : poll_threads();
7871 : 16 : CU_ASSERT(g_bserrno == 0);
7872 : 16 : spdk_blob_io_read(snap1, bs_ch, buf, 0, 1, bs_op_complete, NULL);
7873 : 16 : poll_threads();
7874 : 16 : CU_ASSERT(g_bserrno == 0);
7875 : 16 : spdk_blob_io_read(clone1, bs_ch, buf, 0, 1, bs_op_complete, NULL);
7876 : 16 : poll_threads();
7877 : 16 : CU_ASSERT(g_bserrno == 0);
7878 : :
7879 : : /*
7880 : : * Unload the blobstore in a way similar to how lvstore unloads it. This should exercise
7881 : : * the deferred unload path in spdk_bs_unload().
7882 : : */
7883 : 16 : bserr1 = 0xbad;
7884 : 16 : bserr2 = 0xbad;
7885 : 16 : bserr3 = 0xbad;
7886 : 16 : bserr4 = 0xbad;
7887 : 16 : spdk_blob_close(eclone1, blob_op_complete, &bserr1);
7888 : 16 : spdk_blob_close(snap1, blob_op_complete, &bserr2);
7889 : 16 : spdk_blob_close(clone1, blob_op_complete, &bserr3);
7890 : 16 : spdk_bs_unload(bs, blob_op_complete, &bserr4);
7891 : 16 : spdk_bs_free_io_channel(bs_ch);
7892 : 16 : poll_threads();
7893 : 16 : CU_ASSERT(bserr1 == 0);
7894 : 16 : CU_ASSERT(bserr2 == 0);
7895 : 16 : CU_ASSERT(bserr3 == 0);
7896 : 16 : CU_ASSERT(bserr4 == 0);
7897 : 16 : g_blob = NULL;
7898 : :
7899 : : /* Reload the blobstore */
7900 : 16 : spdk_bs_opts_init(&bs_opts, sizeof(bs_opts));
7901 : 16 : bs_opts.esnap_bs_dev_create = ut_esnap_create;
7902 : 16 : dev = init_dev();
7903 : 16 : spdk_bs_load(dev, &bs_opts, bs_op_with_handle_complete, NULL);
7904 : 16 : poll_threads();
7905 : 16 : CU_ASSERT(g_bserrno == 0);
7906 [ - + ]: 16 : SPDK_CU_ASSERT_FATAL(g_bs != NULL);
7907 : 16 : }
7908 : :
7909 : : static bool
7910 : 320 : blob_esnap_verify_contents(struct spdk_blob *blob, struct spdk_io_channel *ch,
7911 : : uint64_t offset, uint64_t size, uint32_t readsize, const char *how)
7912 : 320 : {
7913 : 320 : const uint32_t bs_blksz = blob->bs->io_unit_size;
7914 [ + + ]: 320 : const uint32_t esnap_blksz = blob->back_bs_dev ? blob->back_bs_dev->blocklen : bs_blksz;
7915 [ - + ]: 320 : const uint32_t start_blk = offset / bs_blksz;
7916 [ - + ]: 320 : const uint32_t num_blocks = spdk_max(size, readsize) / bs_blksz;
7917 [ - + ]: 320 : const uint32_t blocks_per_read = spdk_min(size, readsize) / bs_blksz;
7918 : : uint32_t blob_block;
7919 : 320 : struct iovec iov;
7920 [ - + ]: 320 : uint8_t buf[spdk_min(size, readsize)];
7921 : : bool block_ok;
7922 : :
7923 [ - + - + ]: 320 : SPDK_CU_ASSERT_FATAL(offset % bs_blksz == 0);
7924 [ - + - + ]: 320 : SPDK_CU_ASSERT_FATAL(size % bs_blksz == 0);
7925 [ - + - + ]: 320 : SPDK_CU_ASSERT_FATAL(readsize % bs_blksz == 0);
7926 : :
7927 [ - + ]: 320 : memset(buf, 0, readsize);
7928 : 320 : iov.iov_base = buf;
7929 : 320 : iov.iov_len = readsize;
7930 [ + + ]: 8176 : for (blob_block = start_blk; blob_block < num_blocks; blob_block += blocks_per_read) {
7931 [ + + + + ]: 7856 : if (strcmp(how, "read") == 0) {
7932 : 2640 : spdk_blob_io_read(blob, ch, buf, blob_block, blocks_per_read,
7933 : : bs_op_complete, NULL);
7934 [ + + + + ]: 5216 : } else if (strcmp(how, "readv") == 0) {
7935 : 2608 : spdk_blob_io_readv(blob, ch, &iov, 1, blob_block, blocks_per_read,
7936 : : bs_op_complete, NULL);
7937 [ + + + - ]: 2608 : } else if (strcmp(how, "readv_ext") == 0) {
7938 : : /*
7939 : : * This is currently pointless. NULL ext_opts leads to dev->readv(), not
7940 : : * dev->readv_ext().
7941 : : */
7942 : 2608 : spdk_blob_io_readv_ext(blob, ch, &iov, 1, blob_block, blocks_per_read,
7943 : : bs_op_complete, NULL, NULL);
7944 : : } else {
7945 : 0 : abort();
7946 : : }
7947 : 7856 : poll_threads();
7948 : 7856 : CU_ASSERT(g_bserrno == 0);
7949 [ - + ]: 7856 : if (g_bserrno != 0) {
7950 : 0 : return false;
7951 : : }
7952 : 7856 : block_ok = ut_esnap_content_is_correct(buf, blocks_per_read * bs_blksz, blob->id,
7953 : : blob_block * bs_blksz, esnap_blksz);
7954 : 7856 : CU_ASSERT(block_ok);
7955 [ - + ]: 7856 : if (!block_ok) {
7956 : 0 : return false;
7957 : : }
7958 : : }
7959 : :
7960 : 320 : return true;
7961 : : }
7962 : :
7963 : : static void
7964 : 48 : blob_esnap_io_size(uint32_t bs_blksz, uint32_t esnap_blksz)
7965 : : {
7966 : : struct spdk_bs_dev *dev;
7967 : : struct spdk_blob_store *bs;
7968 : 48 : struct spdk_bs_opts bsopts;
7969 : 48 : struct spdk_blob_opts opts;
7970 : 48 : struct ut_esnap_opts esnap_opts;
7971 : : struct spdk_blob *blob;
7972 : 48 : const uint32_t cluster_sz = 16 * 1024;
7973 : 48 : const uint64_t esnap_num_clusters = 4;
7974 : 48 : const uint32_t esnap_sz = cluster_sz * esnap_num_clusters;
7975 [ - + ]: 48 : const uint64_t esnap_num_blocks = esnap_sz / esnap_blksz;
7976 [ - + ]: 48 : const uint64_t blob_num_blocks = esnap_sz / bs_blksz;
7977 : : uint32_t block;
7978 : : struct spdk_io_channel *bs_ch;
7979 : :
7980 : 48 : spdk_bs_opts_init(&bsopts, sizeof(bsopts));
7981 : 48 : bsopts.cluster_sz = cluster_sz;
7982 : 48 : bsopts.esnap_bs_dev_create = ut_esnap_create;
7983 : :
7984 : : /* Create device with desired block size */
7985 : 48 : dev = init_dev();
7986 : 48 : dev->blocklen = bs_blksz;
7987 [ - + ]: 48 : dev->blockcnt = DEV_BUFFER_SIZE / dev->blocklen;
7988 : :
7989 : : /* Initialize a new blob store */
7990 : 48 : spdk_bs_init(dev, &bsopts, bs_op_with_handle_complete, NULL);
7991 : 48 : poll_threads();
7992 : 48 : CU_ASSERT(g_bserrno == 0);
7993 [ - + ]: 48 : SPDK_CU_ASSERT_FATAL(g_bs != NULL);
7994 [ - + ]: 48 : SPDK_CU_ASSERT_FATAL(g_bs->io_unit_size == bs_blksz);
7995 : 48 : bs = g_bs;
7996 : :
7997 : 48 : bs_ch = spdk_bs_alloc_io_channel(bs);
7998 [ - + ]: 48 : SPDK_CU_ASSERT_FATAL(bs_ch != NULL);
7999 : :
8000 : : /* Create and open the esnap clone */
8001 : 48 : ut_spdk_blob_opts_init(&opts);
8002 : 48 : ut_esnap_opts_init(esnap_blksz, esnap_num_blocks, __func__, NULL, &esnap_opts);
8003 : 48 : opts.esnap_id = &esnap_opts;
8004 : 48 : opts.esnap_id_len = sizeof(esnap_opts);
8005 : 48 : opts.num_clusters = esnap_num_clusters;
8006 : 48 : blob = ut_blob_create_and_open(bs, &opts);
8007 [ - + ]: 48 : SPDK_CU_ASSERT_FATAL(blob != NULL);
8008 : :
8009 : : /* Verify that large reads return the content of the esnap device */
8010 : 48 : CU_ASSERT(blob_esnap_verify_contents(blob, bs_ch, 0, esnap_sz, esnap_sz, "read"));
8011 : 48 : CU_ASSERT(blob_esnap_verify_contents(blob, bs_ch, 0, esnap_sz, esnap_sz, "readv"));
8012 : 48 : CU_ASSERT(blob_esnap_verify_contents(blob, bs_ch, 0, esnap_sz, esnap_sz, "readv_ext"));
8013 : : /* Verify that small reads return the content of the esnap device */
8014 : 48 : CU_ASSERT(blob_esnap_verify_contents(blob, bs_ch, 0, esnap_sz, bs_blksz, "read"));
8015 : 48 : CU_ASSERT(blob_esnap_verify_contents(blob, bs_ch, 0, esnap_sz, bs_blksz, "readv"));
8016 : 48 : CU_ASSERT(blob_esnap_verify_contents(blob, bs_ch, 0, esnap_sz, bs_blksz, "readv_ext"));
8017 : :
8018 : : /* Write one blob block at a time; verify that the surrounding blocks are OK */
8019 [ + + ]: 2608 : for (block = 0; block < blob_num_blocks; block++) {
8020 [ - + ]: 2560 : char buf[bs_blksz];
8021 : : union ut_word word;
8022 : :
8023 : 2560 : word.f.blob_id = 0xfedcba90;
8024 : 2560 : word.f.lba = block;
8025 : 2560 : ut_memset8(buf, word.num, bs_blksz);
8026 : :
8027 : 2560 : spdk_blob_io_write(blob, bs_ch, buf, block, 1, bs_op_complete, NULL);
8028 : 2560 : poll_threads();
8029 : 2560 : CU_ASSERT(g_bserrno == 0);
8030 [ - + ]: 2560 : if (g_bserrno != 0) {
8031 : 0 : break;
8032 : : }
8033 : :
8034 : : /* Read and verify the block before the current block */
8035 [ + + ]: 2560 : if (block != 0) {
8036 : 2512 : spdk_blob_io_read(blob, bs_ch, buf, block - 1, 1, bs_op_complete, NULL);
8037 : 2512 : poll_threads();
8038 : 2512 : CU_ASSERT(g_bserrno == 0);
8039 [ - + ]: 2512 : if (g_bserrno != 0) {
8040 : 0 : break;
8041 : : }
8042 : 2512 : CU_ASSERT(ut_esnap_content_is_correct(buf, bs_blksz, word.f.blob_id,
8043 : : (block - 1) * bs_blksz, bs_blksz));
8044 : : }
8045 : :
8046 : : /* Read and verify the current block */
8047 : 2560 : spdk_blob_io_read(blob, bs_ch, buf, block, 1, bs_op_complete, NULL);
8048 : 2560 : poll_threads();
8049 : 2560 : CU_ASSERT(g_bserrno == 0);
8050 [ - + ]: 2560 : if (g_bserrno != 0) {
8051 : 0 : break;
8052 : : }
8053 : 2560 : CU_ASSERT(ut_esnap_content_is_correct(buf, bs_blksz, word.f.blob_id,
8054 : : block * bs_blksz, bs_blksz));
8055 : :
8056 : : /* Check the block that follows */
8057 [ + + ]: 2560 : if (block + 1 < blob_num_blocks) {
8058 : 2512 : g_bserrno = 0xbad;
8059 : 2512 : spdk_blob_io_read(blob, bs_ch, buf, block + 1, 1, bs_op_complete, NULL);
8060 : 2512 : poll_threads();
8061 : 2512 : CU_ASSERT(g_bserrno == 0);
8062 [ - + ]: 2512 : if (g_bserrno != 0) {
8063 : 0 : break;
8064 : : }
8065 : 2512 : CU_ASSERT(ut_esnap_content_is_correct(buf, bs_blksz, blob->id,
8066 : : (block + 1) * bs_blksz,
8067 : : esnap_blksz));
8068 : : }
8069 : : }
8070 : :
8071 : : /* Clean up */
8072 : 48 : spdk_bs_free_io_channel(bs_ch);
8073 : 48 : g_bserrno = 0xbad;
8074 : 48 : spdk_blob_close(blob, blob_op_complete, NULL);
8075 : 48 : poll_threads();
8076 : 48 : CU_ASSERT(g_bserrno == 0);
8077 : 48 : spdk_bs_unload(g_bs, bs_op_complete, NULL);
8078 : 48 : poll_threads();
8079 : 48 : CU_ASSERT(g_bserrno == 0);
8080 : 48 : g_bs = NULL;
8081 [ - + ]: 48 : memset(g_dev_buffer, 0, DEV_BUFFER_SIZE);
8082 : 48 : }
8083 : :
8084 : : static void
8085 : 16 : blob_esnap_io_4096_4096(void)
8086 : : {
8087 : 16 : blob_esnap_io_size(4096, 4096);
8088 : 16 : }
8089 : :
8090 : : static void
8091 : 16 : blob_esnap_io_512_512(void)
8092 : : {
8093 : 16 : blob_esnap_io_size(512, 512);
8094 : 16 : }
8095 : :
8096 : : static void
8097 : 16 : blob_esnap_io_4096_512(void)
8098 : : {
8099 : 16 : blob_esnap_io_size(4096, 512);
8100 : 16 : }
8101 : :
8102 : : static void
8103 : 16 : blob_esnap_io_512_4096(void)
8104 : : {
8105 : : struct spdk_bs_dev *dev;
8106 : : struct spdk_blob_store *bs;
8107 : 16 : struct spdk_bs_opts bs_opts;
8108 : 16 : struct spdk_blob_opts blob_opts;
8109 : 16 : struct ut_esnap_opts esnap_opts;
8110 : 16 : uint64_t cluster_sz = 16 * 1024;
8111 : 16 : uint32_t bs_blksz = 512;
8112 : 16 : uint32_t esnap_blksz = 4096;
8113 : 16 : uint64_t esnap_num_blocks = 64;
8114 : : spdk_blob_id blobid;
8115 : :
8116 : : /* Create device with desired block size */
8117 : 16 : dev = init_dev();
8118 : 16 : dev->blocklen = bs_blksz;
8119 [ - + ]: 16 : dev->blockcnt = DEV_BUFFER_SIZE / dev->blocklen;
8120 : :
8121 : : /* Initialize a new blob store */
8122 : 16 : spdk_bs_opts_init(&bs_opts, sizeof(bs_opts));
8123 : 16 : bs_opts.cluster_sz = cluster_sz;
8124 : 16 : bs_opts.esnap_bs_dev_create = ut_esnap_create;
8125 : 16 : spdk_bs_init(dev, &bs_opts, bs_op_with_handle_complete, NULL);
8126 : 16 : poll_threads();
8127 : 16 : CU_ASSERT(g_bserrno == 0);
8128 [ - + ]: 16 : SPDK_CU_ASSERT_FATAL(g_bs != NULL);
8129 [ - + ]: 16 : SPDK_CU_ASSERT_FATAL(g_bs->io_unit_size == bs_blksz);
8130 : 16 : bs = g_bs;
8131 : :
8132 : : /* Try to create and open the esnap clone. Create should succeed, open should fail. */
8133 : 16 : ut_spdk_blob_opts_init(&blob_opts);
8134 : 16 : ut_esnap_opts_init(esnap_blksz, esnap_num_blocks, __func__, NULL, &esnap_opts);
8135 : 16 : blob_opts.esnap_id = &esnap_opts;
8136 : 16 : blob_opts.esnap_id_len = sizeof(esnap_opts);
8137 [ - + ]: 16 : blob_opts.num_clusters = esnap_num_blocks * esnap_blksz / bs_blksz;
8138 : 16 : spdk_bs_create_blob_ext(bs, &blob_opts, blob_op_with_id_complete, NULL);
8139 : 16 : poll_threads();
8140 : 16 : CU_ASSERT(g_bserrno == 0);
8141 : 16 : CU_ASSERT(g_blobid != SPDK_BLOBID_INVALID);
8142 : 16 : blobid = g_blobid;
8143 : 16 : spdk_bs_open_blob(bs, blobid, blob_op_with_handle_complete, NULL);
8144 : 16 : poll_threads();
8145 : 16 : CU_ASSERT(g_bserrno == -EINVAL);
8146 : 16 : CU_ASSERT(g_blob == NULL);
8147 : :
8148 : : /* Clean up */
8149 : 16 : spdk_bs_unload(bs, bs_op_complete, NULL);
8150 : 16 : poll_threads();
8151 : 16 : CU_ASSERT(g_bserrno == 0);
8152 : 16 : g_bs = NULL;
8153 [ - + ]: 16 : memset(g_dev_buffer, 0, DEV_BUFFER_SIZE);
8154 : 16 : }
8155 : :
8156 : : static void
8157 : 16 : blob_esnap_thread_add_remove(void)
8158 : 16 : {
8159 : 16 : struct spdk_blob_store *bs = g_bs;
8160 : 16 : struct spdk_blob_opts opts;
8161 : 16 : struct ut_esnap_opts ut_esnap_opts;
8162 : : struct spdk_blob *blob;
8163 : : struct ut_esnap_dev *ut_dev;
8164 : : spdk_blob_id blobid;
8165 : 16 : uint64_t start_thread = g_ut_thread_id;
8166 : 16 : bool destroyed = false;
8167 : : struct spdk_io_channel *ch0, *ch1;
8168 : : struct ut_esnap_channel *ut_ch0, *ut_ch1;
8169 : 16 : const uint32_t blocklen = bs->io_unit_size;
8170 [ - + ]: 16 : char buf[blocklen * 4];
8171 : :
8172 [ - + ]: 16 : SPDK_CU_ASSERT_FATAL(g_ut_num_threads > 1);
8173 : 16 : set_thread(0);
8174 : :
8175 : : /* Create the esnap clone */
8176 : 16 : ut_esnap_opts_init(blocklen, 2048, "add_remove_1", &destroyed, &ut_esnap_opts);
8177 : 16 : ut_spdk_blob_opts_init(&opts);
8178 : 16 : opts.esnap_id = &ut_esnap_opts;
8179 : 16 : opts.esnap_id_len = sizeof(ut_esnap_opts);
8180 : 16 : opts.num_clusters = 10;
8181 : 16 : spdk_bs_create_blob_ext(bs, &opts, blob_op_with_id_complete, NULL);
8182 : 16 : poll_threads();
8183 : 16 : CU_ASSERT(g_bserrno == 0);
8184 : 16 : CU_ASSERT(g_blobid != SPDK_BLOBID_INVALID);
8185 : 16 : blobid = g_blobid;
8186 : :
8187 : : /* Open the blob. No channels should be allocated yet. */
8188 : 16 : spdk_bs_open_blob(bs, blobid, blob_op_with_handle_complete, NULL);
8189 : 16 : poll_threads();
8190 : 16 : CU_ASSERT(g_bserrno == 0);
8191 : 16 : CU_ASSERT(g_blob != NULL);
8192 : 16 : blob = g_blob;
8193 : 16 : ut_dev = (struct ut_esnap_dev *)blob->back_bs_dev;
8194 : 16 : CU_ASSERT(ut_dev != NULL);
8195 : 16 : CU_ASSERT(ut_dev->num_channels == 0);
8196 : :
8197 : : /* Create a channel on thread 0. It is lazily created on the first read. */
8198 : 16 : ch0 = spdk_bs_alloc_io_channel(bs);
8199 : 16 : CU_ASSERT(ch0 != NULL);
8200 : 16 : ut_ch0 = ut_esnap_get_io_channel(ch0, blobid);
8201 : 16 : CU_ASSERT(ut_ch0 == NULL);
8202 : 16 : CU_ASSERT(ut_dev->num_channels == 0);
8203 : 16 : spdk_blob_io_read(blob, ch0, buf, 0, 1, bs_op_complete, NULL);
8204 : 16 : poll_threads();
8205 : 16 : CU_ASSERT(g_bserrno == 0);
8206 : 16 : CU_ASSERT(ut_dev->num_channels == 1);
8207 : 16 : ut_ch0 = ut_esnap_get_io_channel(ch0, blobid);
8208 : 16 : CU_ASSERT(ut_ch0 != NULL);
8209 : 16 : CU_ASSERT(ut_ch0->blocks_read == 1);
8210 : :
8211 : : /* Create a channel on thread 1 and verify its lazy creation too. */
8212 : 16 : set_thread(1);
8213 : 16 : ch1 = spdk_bs_alloc_io_channel(bs);
8214 : 16 : CU_ASSERT(ch1 != NULL);
8215 : 16 : ut_ch1 = ut_esnap_get_io_channel(ch1, blobid);
8216 : 16 : CU_ASSERT(ut_ch1 == NULL);
8217 : 16 : CU_ASSERT(ut_dev->num_channels == 1);
8218 : 16 : spdk_blob_io_read(blob, ch1, buf, 0, 4, bs_op_complete, NULL);
8219 : 16 : poll_threads();
8220 : 16 : CU_ASSERT(g_bserrno == 0);
8221 : 16 : CU_ASSERT(ut_dev->num_channels == 2);
8222 : 16 : ut_ch1 = ut_esnap_get_io_channel(ch1, blobid);
8223 : 16 : CU_ASSERT(ut_ch1 != NULL);
8224 : 16 : CU_ASSERT(ut_ch1->blocks_read == 4);
8225 : :
8226 : : /* Close the channel on thread 0 and verify the bs_dev channel is also gone. */
8227 : 16 : set_thread(0);
8228 : 16 : spdk_bs_free_io_channel(ch0);
8229 : 16 : poll_threads();
8230 : 16 : CU_ASSERT(ut_dev->num_channels == 1);
8231 : :
8232 : : /* Close the blob. There is no outstanding IO so it should close right away. */
8233 : 16 : g_bserrno = 0xbad;
8234 : 16 : spdk_blob_close(blob, blob_op_complete, NULL);
8235 : 16 : poll_threads();
8236 : 16 : CU_ASSERT(g_bserrno == 0);
8237 [ - + ]: 16 : CU_ASSERT(destroyed);
8238 : :
8239 : : /* The esnap channel for the blob should be gone now too. */
8240 : 16 : ut_ch1 = ut_esnap_get_io_channel(ch1, blobid);
8241 : 16 : CU_ASSERT(ut_ch1 == NULL);
8242 : :
8243 : : /* Clean up */
8244 : 16 : set_thread(1);
8245 : 16 : spdk_bs_free_io_channel(ch1);
8246 : 16 : set_thread(start_thread);
8247 : 16 : }
8248 : :
8249 : : static void
8250 : 48 : freeze_done(void *cb_arg, int bserrno)
8251 : : {
8252 : 48 : uint32_t *freeze_cnt = cb_arg;
8253 : :
8254 : 48 : CU_ASSERT(bserrno == 0);
8255 : 48 : (*freeze_cnt)++;
8256 : 48 : }
8257 : :
8258 : : static void
8259 : 48 : unfreeze_done(void *cb_arg, int bserrno)
8260 : : {
8261 : 48 : uint32_t *unfreeze_cnt = cb_arg;
8262 : :
8263 : 48 : CU_ASSERT(bserrno == 0);
8264 : 48 : (*unfreeze_cnt)++;
8265 : 48 : }
8266 : :
8267 : : static void
8268 : 16 : blob_nested_freezes(void)
8269 : : {
8270 : 16 : struct spdk_blob_store *bs = g_bs;
8271 : : struct spdk_blob *blob;
8272 : 16 : struct spdk_io_channel *channel[2];
8273 : 16 : struct spdk_blob_opts opts;
8274 : 16 : uint32_t freeze_cnt, unfreeze_cnt;
8275 : : int i;
8276 : :
8277 [ + + ]: 48 : for (i = 0; i < 2; i++) {
8278 : 32 : set_thread(i);
8279 : 32 : channel[i] = spdk_bs_alloc_io_channel(bs);
8280 [ - + ]: 32 : SPDK_CU_ASSERT_FATAL(channel[i] != NULL);
8281 : : }
8282 : :
8283 : 16 : set_thread(0);
8284 : :
8285 : 16 : ut_spdk_blob_opts_init(&opts);
8286 : 16 : blob = ut_blob_create_and_open(bs, &opts);
8287 : :
8288 : : /* First just test a single freeze/unfreeze. */
8289 : 16 : freeze_cnt = 0;
8290 : 16 : unfreeze_cnt = 0;
8291 : 16 : CU_ASSERT(blob->frozen_refcnt == 0);
8292 : 16 : blob_freeze_io(blob, freeze_done, &freeze_cnt);
8293 : 16 : CU_ASSERT(blob->frozen_refcnt == 1);
8294 : 16 : CU_ASSERT(freeze_cnt == 0);
8295 : 16 : poll_threads();
8296 : 16 : CU_ASSERT(freeze_cnt == 1);
8297 : 16 : blob_unfreeze_io(blob, unfreeze_done, &unfreeze_cnt);
8298 : 16 : CU_ASSERT(blob->frozen_refcnt == 0);
8299 : 16 : CU_ASSERT(unfreeze_cnt == 0);
8300 : 16 : poll_threads();
8301 : 16 : CU_ASSERT(unfreeze_cnt == 1);
8302 : :
8303 : : /* Now nest multiple freeze/unfreeze operations. We should
8304 : : * expect a callback for each operation, but only after
8305 : : * the threads have been polled to ensure a for_each_channel()
8306 : : * was executed.
8307 : : */
8308 : 16 : freeze_cnt = 0;
8309 : 16 : unfreeze_cnt = 0;
8310 : 16 : CU_ASSERT(blob->frozen_refcnt == 0);
8311 : 16 : blob_freeze_io(blob, freeze_done, &freeze_cnt);
8312 : 16 : CU_ASSERT(blob->frozen_refcnt == 1);
8313 : 16 : CU_ASSERT(freeze_cnt == 0);
8314 : 16 : blob_freeze_io(blob, freeze_done, &freeze_cnt);
8315 : 16 : CU_ASSERT(blob->frozen_refcnt == 2);
8316 : 16 : CU_ASSERT(freeze_cnt == 0);
8317 : 16 : poll_threads();
8318 : 16 : CU_ASSERT(freeze_cnt == 2);
8319 : 16 : blob_unfreeze_io(blob, unfreeze_done, &unfreeze_cnt);
8320 : 16 : CU_ASSERT(blob->frozen_refcnt == 1);
8321 : 16 : CU_ASSERT(unfreeze_cnt == 0);
8322 : 16 : blob_unfreeze_io(blob, unfreeze_done, &unfreeze_cnt);
8323 : 16 : CU_ASSERT(blob->frozen_refcnt == 0);
8324 : 16 : CU_ASSERT(unfreeze_cnt == 0);
8325 : 16 : poll_threads();
8326 : 16 : CU_ASSERT(unfreeze_cnt == 2);
8327 : :
8328 [ + + ]: 48 : for (i = 0; i < 2; i++) {
8329 : 32 : set_thread(i);
8330 : 32 : spdk_bs_free_io_channel(channel[i]);
8331 : : }
8332 : 16 : set_thread(0);
8333 : 16 : ut_blob_close_and_delete(bs, blob);
8334 : :
8335 : 16 : poll_threads();
8336 : 16 : g_blob = NULL;
8337 : 16 : g_blobid = 0;
8338 : 16 : }
8339 : :
8340 : : static void
8341 : 16 : blob_ext_md_pages(void)
8342 : : {
8343 : : struct spdk_blob_store *bs;
8344 : : struct spdk_bs_dev *dev;
8345 : : struct spdk_blob *blob;
8346 : 16 : struct spdk_blob_opts opts;
8347 : 16 : struct spdk_bs_opts bs_opts;
8348 : : uint64_t free_clusters;
8349 : :
8350 : 16 : dev = init_dev();
8351 : 16 : spdk_bs_opts_init(&bs_opts, sizeof(bs_opts));
8352 : 16 : snprintf(bs_opts.bstype.bstype, sizeof(bs_opts.bstype.bstype), "TESTTYPE");
8353 : : /* Issue #2932 was a bug in how we use bs_allocate_cluster() during resize.
8354 : : * It requires num_md_pages that is much smaller than the number of clusters.
8355 : : * Make sure we can create a blob that uses all of the free clusters.
8356 : : */
8357 : 16 : bs_opts.cluster_sz = 65536;
8358 : 16 : bs_opts.num_md_pages = 16;
8359 : :
8360 : : /* Initialize a new blob store */
8361 : 16 : spdk_bs_init(dev, &bs_opts, bs_op_with_handle_complete, NULL);
8362 : 16 : poll_threads();
8363 : 16 : CU_ASSERT(g_bserrno == 0);
8364 [ - + ]: 16 : SPDK_CU_ASSERT_FATAL(g_bs != NULL);
8365 : 16 : bs = g_bs;
8366 : :
8367 : 16 : free_clusters = spdk_bs_free_cluster_count(bs);
8368 : :
8369 : 16 : ut_spdk_blob_opts_init(&opts);
8370 : 16 : opts.num_clusters = free_clusters;
8371 : :
8372 : 16 : blob = ut_blob_create_and_open(bs, &opts);
8373 : 16 : spdk_blob_close(blob, blob_op_complete, NULL);
8374 : 16 : CU_ASSERT(g_bserrno == 0);
8375 : :
8376 : 16 : spdk_bs_unload(bs, bs_op_complete, NULL);
8377 : 16 : poll_threads();
8378 : 16 : CU_ASSERT(g_bserrno == 0);
8379 : 16 : g_bs = NULL;
8380 : 16 : }
8381 : :
8382 : : static void
8383 : 16 : blob_esnap_clone_snapshot(void)
8384 : : {
8385 : : /*
8386 : : * When a snapshot is created, the blob that is being snapped becomes
8387 : : * the leaf node (a clone of the snapshot) and the newly created
8388 : : * snapshot sits between the snapped blob and the external snapshot.
8389 : : *
8390 : : * Before creating snap1
8391 : : *
8392 : : * ,--------. ,----------.
8393 : : * | blob | | vbdev |
8394 : : * | blob1 |<----| nvme1n42 |
8395 : : * | (rw) | | (ro) |
8396 : : * `--------' `----------'
8397 : : * Figure 1
8398 : : *
8399 : : * After creating snap1
8400 : : *
8401 : : * ,--------. ,--------. ,----------.
8402 : : * | blob | | blob | | vbdev |
8403 : : * | blob1 |<----| snap1 |<----| nvme1n42 |
8404 : : * | (rw) | | (ro) | | (ro) |
8405 : : * `--------' `--------' `----------'
8406 : : * Figure 2
8407 : : *
8408 : : * Starting from Figure 2, if snap1 is removed, the chain reverts to
8409 : : * what it looks like in Figure 1.
8410 : : *
8411 : : * Starting from Figure 2, if blob1 is removed, the chain becomes:
8412 : : *
8413 : : * ,--------. ,----------.
8414 : : * | blob | | vbdev |
8415 : : * | snap1 |<----| nvme1n42 |
8416 : : * | (ro) | | (ro) |
8417 : : * `--------' `----------'
8418 : : * Figure 3
8419 : : *
8420 : : * In each case, the blob pointed to by the nvme vbdev is considered
8421 : : * the "esnap clone". The esnap clone must have:
8422 : : *
8423 : : * - XATTR_INTERNAL for BLOB_EXTERNAL_SNAPSHOT_ID (e.g. name or UUID)
8424 : : * - blob->invalid_flags must contain SPDK_BLOB_EXTERNAL_SNAPSHOT
8425 : : * - blob->parent_id must be SPDK_BLOBID_EXTERNAL_SNAPSHOT.
8426 : : *
8427 : : * No other blob that descends from the esnap clone may have any of
8428 : : * those set.
8429 : : */
8430 : 16 : struct spdk_blob_store *bs = g_bs;
8431 : 16 : const uint32_t blocklen = bs->io_unit_size;
8432 : 16 : struct spdk_blob_opts opts;
8433 : 16 : struct ut_esnap_opts esnap_opts;
8434 : : struct spdk_blob *blob, *snap_blob;
8435 : : spdk_blob_id blobid, snap_blobid;
8436 : 16 : bool destroyed = false;
8437 : :
8438 : : /* Create the esnap clone */
8439 : 16 : ut_esnap_opts_init(blocklen, 2048, __func__, &destroyed, &esnap_opts);
8440 : 16 : ut_spdk_blob_opts_init(&opts);
8441 : 16 : opts.esnap_id = &esnap_opts;
8442 : 16 : opts.esnap_id_len = sizeof(esnap_opts);
8443 : 16 : opts.num_clusters = 10;
8444 : 16 : spdk_bs_create_blob_ext(bs, &opts, blob_op_with_id_complete, NULL);
8445 : 16 : poll_threads();
8446 : 16 : CU_ASSERT(g_bserrno == 0);
8447 : 16 : CU_ASSERT(g_blobid != SPDK_BLOBID_INVALID);
8448 : 16 : blobid = g_blobid;
8449 : :
8450 : : /* Open the blob. */
8451 : 16 : spdk_bs_open_blob(bs, blobid, blob_op_with_handle_complete, NULL);
8452 : 16 : poll_threads();
8453 : 16 : CU_ASSERT(g_bserrno == 0);
8454 : 16 : CU_ASSERT(g_blob != NULL);
8455 : 16 : blob = g_blob;
8456 : 16 : UT_ASSERT_IS_ESNAP_CLONE(blob, &esnap_opts, sizeof(esnap_opts));
8457 : :
8458 : : /*
8459 : : * Create a snapshot of the blob. The snapshot becomes the esnap clone.
8460 : : */
8461 : 16 : spdk_bs_create_snapshot(bs, blobid, NULL, blob_op_with_id_complete, NULL);
8462 : 16 : poll_threads();
8463 : 16 : CU_ASSERT(g_bserrno == 0);
8464 : 16 : CU_ASSERT(g_blobid != SPDK_BLOBID_INVALID);
8465 : 16 : snap_blobid = g_blobid;
8466 : :
8467 : 16 : spdk_bs_open_blob(bs, snap_blobid, blob_op_with_handle_complete, NULL);
8468 : 16 : poll_threads();
8469 : 16 : CU_ASSERT(g_bserrno == 0);
8470 [ - + ]: 16 : SPDK_CU_ASSERT_FATAL(g_blob != NULL);
8471 : 16 : snap_blob = g_blob;
8472 : :
8473 : 16 : UT_ASSERT_IS_NOT_ESNAP_CLONE(blob);
8474 : 16 : UT_ASSERT_IS_ESNAP_CLONE(snap_blob, &esnap_opts, sizeof(esnap_opts));
8475 : :
8476 : : /*
8477 : : * Delete the snapshot. The original blob becomes the esnap clone.
8478 : : */
8479 : 16 : ut_blob_close_and_delete(bs, snap_blob);
8480 : 16 : snap_blob = NULL;
8481 : 16 : snap_blobid = SPDK_BLOBID_INVALID;
8482 : 16 : UT_ASSERT_IS_ESNAP_CLONE(blob, &esnap_opts, sizeof(esnap_opts));
8483 : :
8484 : : /*
8485 : : * Create the snapshot again, then delete the original blob. The
8486 : : * snapshot should survive as the esnap clone.
8487 : : */
8488 : 16 : spdk_bs_create_snapshot(bs, blobid, NULL, blob_op_with_id_complete, NULL);
8489 : 16 : poll_threads();
8490 : 16 : CU_ASSERT(g_bserrno == 0);
8491 : 16 : CU_ASSERT(g_blobid != SPDK_BLOBID_INVALID);
8492 : 16 : snap_blobid = g_blobid;
8493 : :
8494 : 16 : spdk_bs_open_blob(bs, snap_blobid, blob_op_with_handle_complete, NULL);
8495 : 16 : poll_threads();
8496 : 16 : CU_ASSERT(g_bserrno == 0);
8497 [ - + ]: 16 : SPDK_CU_ASSERT_FATAL(g_blob != NULL);
8498 : 16 : snap_blob = g_blob;
8499 : :
8500 : 16 : UT_ASSERT_IS_NOT_ESNAP_CLONE(blob);
8501 : 16 : UT_ASSERT_IS_ESNAP_CLONE(snap_blob, &esnap_opts, sizeof(esnap_opts));
8502 : :
8503 : 16 : ut_blob_close_and_delete(bs, blob);
8504 : 16 : blob = NULL;
8505 : 16 : blobid = SPDK_BLOBID_INVALID;
8506 : 16 : UT_ASSERT_IS_ESNAP_CLONE(snap_blob, &esnap_opts, sizeof(esnap_opts));
8507 : :
8508 : : /*
8509 : : * Clone the snapshot. The snapshot continues to be the esnap clone.
8510 : : */
8511 : 16 : spdk_bs_create_clone(bs, snap_blobid, NULL, blob_op_with_id_complete, NULL);
8512 : 16 : poll_threads();
8513 : 16 : CU_ASSERT(g_bserrno == 0);
8514 : 16 : CU_ASSERT(g_blobid != SPDK_BLOBID_INVALID);
8515 : 16 : blobid = g_blobid;
8516 : :
8517 : 16 : spdk_bs_open_blob(bs, blobid, blob_op_with_handle_complete, NULL);
8518 : 16 : poll_threads();
8519 : 16 : CU_ASSERT(g_bserrno == 0);
8520 [ - + ]: 16 : SPDK_CU_ASSERT_FATAL(g_blob != NULL);
8521 : 16 : blob = g_blob;
8522 : :
8523 : 16 : UT_ASSERT_IS_NOT_ESNAP_CLONE(blob);
8524 : 16 : UT_ASSERT_IS_ESNAP_CLONE(snap_blob, &esnap_opts, sizeof(esnap_opts));
8525 : :
8526 : : /*
8527 : : * Delete the snapshot. The clone becomes the esnap clone.
8528 : : */
8529 : 16 : ut_blob_close_and_delete(bs, snap_blob);
8530 : 16 : snap_blob = NULL;
8531 : 16 : snap_blobid = SPDK_BLOBID_INVALID;
8532 : 16 : UT_ASSERT_IS_ESNAP_CLONE(blob, &esnap_opts, sizeof(esnap_opts));
8533 : :
8534 : : /*
8535 : : * Clean up
8536 : : */
8537 : 16 : ut_blob_close_and_delete(bs, blob);
8538 : 16 : }
8539 : :
8540 : : static uint64_t
8541 : 32 : _blob_esnap_clone_hydrate(bool inflate)
8542 : : {
8543 : 32 : struct spdk_blob_store *bs = g_bs;
8544 : 32 : struct spdk_blob_opts opts;
8545 : 32 : struct ut_esnap_opts esnap_opts;
8546 : : struct spdk_blob *blob;
8547 : : spdk_blob_id blobid;
8548 : : struct spdk_io_channel *channel;
8549 : 32 : bool destroyed = false;
8550 : 32 : const uint32_t blocklen = spdk_bs_get_io_unit_size(bs);
8551 : 32 : const uint32_t cluster_sz = spdk_bs_get_cluster_size(bs);
8552 : 32 : const uint64_t esnap_num_clusters = 4;
8553 : 32 : const uint32_t esnap_sz = cluster_sz * esnap_num_clusters;
8554 [ - + ]: 32 : const uint64_t esnap_num_blocks = esnap_sz / blocklen;
8555 : 32 : uint64_t num_failures = CU_get_number_of_failures();
8556 : :
8557 : 32 : channel = spdk_bs_alloc_io_channel(bs);
8558 [ - + ]: 32 : SPDK_CU_ASSERT_FATAL(channel != NULL);
8559 : :
8560 : : /* Create the esnap clone */
8561 : 32 : ut_spdk_blob_opts_init(&opts);
8562 : 32 : ut_esnap_opts_init(blocklen, esnap_num_blocks, __func__, &destroyed, &esnap_opts);
8563 : 32 : opts.esnap_id = &esnap_opts;
8564 : 32 : opts.esnap_id_len = sizeof(esnap_opts);
8565 : 32 : opts.num_clusters = esnap_num_clusters;
8566 : 32 : spdk_bs_create_blob_ext(bs, &opts, blob_op_with_id_complete, NULL);
8567 : 32 : poll_threads();
8568 : 32 : CU_ASSERT(g_bserrno == 0);
8569 : 32 : CU_ASSERT(g_blobid != SPDK_BLOBID_INVALID);
8570 : 32 : blobid = g_blobid;
8571 : :
8572 : : /* Open the esnap clone */
8573 : 32 : spdk_bs_open_blob(bs, blobid, blob_op_with_handle_complete, NULL);
8574 : 32 : poll_threads();
8575 : 32 : CU_ASSERT(g_bserrno == 0);
8576 [ - + ]: 32 : SPDK_CU_ASSERT_FATAL(g_blob != NULL);
8577 : 32 : blob = g_blob;
8578 : 32 : UT_ASSERT_IS_ESNAP_CLONE(blob, &esnap_opts, sizeof(esnap_opts));
8579 : :
8580 : : /*
8581 : : * Inflate or decouple the blob then verify that it is no longer an esnap clone and has
8582 : : * right content
8583 : : */
8584 [ + + ]: 32 : if (inflate) {
8585 : 16 : spdk_bs_inflate_blob(bs, channel, blobid, blob_op_complete, NULL);
8586 : : } else {
8587 : 16 : spdk_bs_blob_decouple_parent(bs, channel, blobid, blob_op_complete, NULL);
8588 : : }
8589 : 32 : poll_threads();
8590 : 32 : CU_ASSERT(g_bserrno == 0);
8591 : 32 : UT_ASSERT_IS_NOT_ESNAP_CLONE(blob);
8592 : 32 : CU_ASSERT(blob_esnap_verify_contents(blob, channel, 0, esnap_sz, esnap_sz, "read"));
8593 : 32 : ut_blob_close_and_delete(bs, blob);
8594 : :
8595 : : /*
8596 : : * Clean up
8597 : : */
8598 : 32 : spdk_bs_free_io_channel(channel);
8599 : 32 : poll_threads();
8600 : :
8601 : : /* Return number of new failures */
8602 : 32 : return CU_get_number_of_failures() - num_failures;
8603 : : }
8604 : :
8605 : : static void
8606 : 16 : blob_esnap_clone_inflate(void)
8607 : : {
8608 : 16 : _blob_esnap_clone_hydrate(true);
8609 : 16 : }
8610 : :
8611 : : static void
8612 : 16 : blob_esnap_clone_decouple(void)
8613 : : {
8614 : 16 : _blob_esnap_clone_hydrate(false);
8615 : 16 : }
8616 : :
8617 : : static void
8618 : 16 : blob_esnap_hotplug(void)
8619 : 16 : {
8620 : 16 : struct spdk_blob_store *bs = g_bs;
8621 : 16 : struct ut_esnap_opts esnap1_opts, esnap2_opts;
8622 : 16 : struct spdk_blob_opts opts;
8623 : : struct spdk_blob *blob;
8624 : : struct spdk_bs_dev *bs_dev;
8625 : : struct ut_esnap_dev *esnap_dev;
8626 : 16 : uint32_t cluster_sz = spdk_bs_get_cluster_size(bs);
8627 : 16 : uint32_t block_sz = spdk_bs_get_io_unit_size(bs);
8628 : 16 : const uint32_t esnap_num_clusters = 4;
8629 [ - + ]: 16 : uint64_t esnap_num_blocks = cluster_sz * esnap_num_clusters / block_sz;
8630 : 16 : bool destroyed1 = false, destroyed2 = false;
8631 : 16 : uint64_t start_thread = g_ut_thread_id;
8632 : : struct spdk_io_channel *ch0, *ch1;
8633 [ - + ]: 16 : char buf[block_sz];
8634 : :
8635 : : /* Create and open an esnap clone blob */
8636 : 16 : ut_spdk_blob_opts_init(&opts);
8637 : 16 : ut_esnap_opts_init(block_sz, esnap_num_blocks, "esnap1", &destroyed1, &esnap1_opts);
8638 : 16 : opts.esnap_id = &esnap1_opts;
8639 : 16 : opts.esnap_id_len = sizeof(esnap1_opts);
8640 : 16 : opts.num_clusters = esnap_num_clusters;
8641 : 16 : blob = ut_blob_create_and_open(bs, &opts);
8642 : 16 : CU_ASSERT(blob != NULL);
8643 : 16 : CU_ASSERT(spdk_blob_is_esnap_clone(blob));
8644 [ - + ]: 16 : SPDK_CU_ASSERT_FATAL(blob->back_bs_dev != NULL);
8645 : 16 : esnap_dev = (struct ut_esnap_dev *)blob->back_bs_dev;
8646 [ - + ]: 16 : CU_ASSERT(strcmp(esnap_dev->ut_opts.name, "esnap1") == 0);
8647 : :
8648 : : /* Replace the external snapshot */
8649 : 16 : ut_esnap_opts_init(block_sz, esnap_num_blocks, "esnap2", &destroyed2, &esnap2_opts);
8650 : 16 : bs_dev = ut_esnap_dev_alloc(&esnap2_opts);
8651 [ - + ]: 16 : CU_ASSERT(!destroyed1);
8652 [ - + ]: 16 : CU_ASSERT(!destroyed2);
8653 : 16 : g_bserrno = 0xbad;
8654 : 16 : spdk_blob_set_esnap_bs_dev(blob, bs_dev, bs_op_complete, NULL);
8655 : 16 : poll_threads();
8656 : 16 : CU_ASSERT(g_bserrno == 0);
8657 [ - + ]: 16 : CU_ASSERT(destroyed1);
8658 [ - + ]: 16 : CU_ASSERT(!destroyed2);
8659 [ - + ]: 16 : SPDK_CU_ASSERT_FATAL(bs_dev == blob->back_bs_dev);
8660 [ - + ]: 16 : SPDK_CU_ASSERT_FATAL(bs_dev == spdk_blob_get_esnap_bs_dev(blob));
8661 : 16 : esnap_dev = (struct ut_esnap_dev *)blob->back_bs_dev;
8662 [ - + ]: 16 : CU_ASSERT(strcmp(esnap_dev->ut_opts.name, "esnap2") == 0);
8663 : :
8664 : : /* Create a couple channels */
8665 : 16 : set_thread(0);
8666 : 16 : ch0 = spdk_bs_alloc_io_channel(bs);
8667 : 16 : CU_ASSERT(ch0 != NULL);
8668 : 16 : spdk_blob_io_read(blob, ch0, buf, 0, 1, bs_op_complete, NULL);
8669 : 16 : set_thread(1);
8670 : 16 : ch1 = spdk_bs_alloc_io_channel(bs);
8671 : 16 : CU_ASSERT(ch1 != NULL);
8672 : 16 : spdk_blob_io_read(blob, ch1, buf, 0, 1, bs_op_complete, NULL);
8673 : 16 : set_thread(start_thread);
8674 : 16 : poll_threads();
8675 : 16 : CU_ASSERT(esnap_dev->num_channels == 2);
8676 : :
8677 : : /* Replace the external snapshot */
8678 : 16 : ut_esnap_opts_init(block_sz, esnap_num_blocks, "esnap1a", &destroyed1, &esnap1_opts);
8679 : 16 : bs_dev = ut_esnap_dev_alloc(&esnap1_opts);
8680 [ - + ]: 16 : destroyed1 = destroyed2 = false;
8681 : 16 : g_bserrno = 0xbad;
8682 : 16 : spdk_blob_set_esnap_bs_dev(blob, bs_dev, bs_op_complete, NULL);
8683 : 16 : poll_threads();
8684 : 16 : CU_ASSERT(g_bserrno == 0);
8685 [ - + ]: 16 : CU_ASSERT(!destroyed1);
8686 [ - + ]: 16 : CU_ASSERT(destroyed2);
8687 [ - + ]: 16 : SPDK_CU_ASSERT_FATAL(blob->back_bs_dev != NULL);
8688 : 16 : esnap_dev = (struct ut_esnap_dev *)blob->back_bs_dev;
8689 [ - + ]: 16 : CU_ASSERT(strcmp(esnap_dev->ut_opts.name, "esnap1a") == 0);
8690 : :
8691 : : /* Clean up */
8692 : 16 : set_thread(0);
8693 : 16 : spdk_bs_free_io_channel(ch0);
8694 : 16 : set_thread(1);
8695 : 16 : spdk_bs_free_io_channel(ch1);
8696 : 16 : set_thread(start_thread);
8697 : 16 : g_bserrno = 0xbad;
8698 : 16 : spdk_blob_close(blob, bs_op_complete, NULL);
8699 : 16 : poll_threads();
8700 : 16 : CU_ASSERT(g_bserrno == 0);
8701 : 16 : }
8702 : :
8703 : : static bool g_blob_is_degraded;
8704 : : static int g_blob_is_degraded_called;
8705 : :
8706 : : static bool
8707 : 96 : _blob_is_degraded(struct spdk_bs_dev *dev)
8708 : : {
8709 : 96 : g_blob_is_degraded_called++;
8710 [ - + ]: 96 : return g_blob_is_degraded;
8711 : : }
8712 : :
8713 : : static void
8714 : 16 : blob_is_degraded(void)
8715 : : {
8716 : 16 : struct spdk_bs_dev bs_is_degraded_null = { 0 };
8717 : 16 : struct spdk_bs_dev bs_is_degraded = { .is_degraded = _blob_is_degraded };
8718 : :
8719 : : /* No back_bs_dev, no bs->dev->is_degraded */
8720 : 16 : g_blob_is_degraded_called = 0;
8721 : 16 : CU_ASSERT(!spdk_blob_is_degraded(g_blob));
8722 : 16 : CU_ASSERT(g_blob_is_degraded_called == 0);
8723 : :
8724 : : /* No back_bs_dev, blobstore device degraded */
8725 : 16 : g_bs->dev->is_degraded = _blob_is_degraded;
8726 : 16 : g_blob_is_degraded_called = 0;
8727 : 16 : g_blob_is_degraded = true;
8728 : 16 : CU_ASSERT(spdk_blob_is_degraded(g_blob));
8729 : 16 : CU_ASSERT(g_blob_is_degraded_called == 1);
8730 : :
8731 : : /* No back_bs_dev, blobstore device not degraded */
8732 : 16 : g_bs->dev->is_degraded = _blob_is_degraded;
8733 : 16 : g_blob_is_degraded_called = 0;
8734 : 16 : g_blob_is_degraded = false;
8735 : 16 : CU_ASSERT(!spdk_blob_is_degraded(g_blob));
8736 : 16 : CU_ASSERT(g_blob_is_degraded_called == 1);
8737 : :
8738 : : /* back_bs_dev does not define is_degraded, no bs->dev->is_degraded */
8739 : 16 : g_bs->dev->is_degraded = NULL;
8740 : 16 : g_blob->back_bs_dev = &bs_is_degraded_null;
8741 : 16 : g_blob_is_degraded_called = 0;
8742 : 16 : g_blob_is_degraded = false;
8743 : 16 : CU_ASSERT(!spdk_blob_is_degraded(g_blob));
8744 : 16 : CU_ASSERT(g_blob_is_degraded_called == 0);
8745 : :
8746 : : /* back_bs_dev is not degraded, no bs->dev->is_degraded */
8747 : 16 : g_bs->dev->is_degraded = NULL;
8748 : 16 : g_blob->back_bs_dev = &bs_is_degraded;
8749 : 16 : g_blob_is_degraded_called = 0;
8750 : 16 : g_blob_is_degraded = false;
8751 : 16 : CU_ASSERT(!spdk_blob_is_degraded(g_blob));
8752 : 16 : CU_ASSERT(g_blob_is_degraded_called == 1);
8753 : :
8754 : : /* back_bs_dev is degraded, no bs->dev->is_degraded */
8755 : 16 : g_bs->dev->is_degraded = NULL;
8756 : 16 : g_blob->back_bs_dev = &bs_is_degraded;
8757 : 16 : g_blob_is_degraded_called = 0;
8758 : 16 : g_blob_is_degraded = true;
8759 : 16 : CU_ASSERT(spdk_blob_is_degraded(g_blob));
8760 : 16 : CU_ASSERT(g_blob_is_degraded_called == 1);
8761 : :
8762 : : /* back_bs_dev is not degraded, blobstore device is not degraded */
8763 : 16 : g_bs->dev->is_degraded = _blob_is_degraded;
8764 : 16 : g_blob->back_bs_dev = &bs_is_degraded;
8765 : 16 : g_blob_is_degraded_called = 0;
8766 : 16 : g_blob_is_degraded = false;
8767 : 16 : CU_ASSERT(!spdk_blob_is_degraded(g_blob));
8768 : 16 : CU_ASSERT(g_blob_is_degraded_called == 2);
8769 : :
8770 : 16 : g_blob->back_bs_dev = NULL;
8771 : 16 : }
8772 : :
8773 : : static void
8774 : 832 : suite_bs_setup(void)
8775 : : {
8776 : : struct spdk_bs_dev *dev;
8777 : :
8778 : 832 : dev = init_dev();
8779 [ - + ]: 832 : memset(g_dev_buffer, 0, DEV_BUFFER_SIZE);
8780 : 832 : spdk_bs_init(dev, NULL, bs_op_with_handle_complete, NULL);
8781 : 832 : poll_threads();
8782 : 832 : CU_ASSERT(g_bserrno == 0);
8783 : 832 : CU_ASSERT(g_bs != NULL);
8784 : 832 : }
8785 : :
8786 : : static void
8787 : 112 : suite_esnap_bs_setup(void)
8788 : : {
8789 : : struct spdk_bs_dev *dev;
8790 : 112 : struct spdk_bs_opts bs_opts;
8791 : :
8792 : 112 : dev = init_dev();
8793 [ - + ]: 112 : memset(g_dev_buffer, 0, DEV_BUFFER_SIZE);
8794 : 112 : spdk_bs_opts_init(&bs_opts, sizeof(bs_opts));
8795 : 112 : bs_opts.cluster_sz = 16 * 1024;
8796 : 112 : bs_opts.esnap_bs_dev_create = ut_esnap_create;
8797 : 112 : spdk_bs_init(dev, &bs_opts, bs_op_with_handle_complete, NULL);
8798 : 112 : poll_threads();
8799 : 112 : CU_ASSERT(g_bserrno == 0);
8800 [ - + ]: 112 : SPDK_CU_ASSERT_FATAL(g_bs != NULL);
8801 : 112 : }
8802 : :
8803 : : static void
8804 : 944 : suite_bs_cleanup(void)
8805 : : {
8806 [ + - ]: 944 : if (g_bs != NULL) {
8807 : 944 : spdk_bs_unload(g_bs, bs_op_complete, NULL);
8808 : 944 : poll_threads();
8809 : 944 : CU_ASSERT(g_bserrno == 0);
8810 : 944 : g_bs = NULL;
8811 : : }
8812 [ - + ]: 944 : memset(g_dev_buffer, 0, DEV_BUFFER_SIZE);
8813 : 944 : }
8814 : :
8815 : : static struct spdk_blob *
8816 : 1216 : ut_blob_create_and_open(struct spdk_blob_store *bs, struct spdk_blob_opts *blob_opts)
8817 : : {
8818 : : struct spdk_blob *blob;
8819 : 1216 : struct spdk_blob_opts create_blob_opts;
8820 : : spdk_blob_id blobid;
8821 : :
8822 [ + + ]: 1216 : if (blob_opts == NULL) {
8823 : 512 : ut_spdk_blob_opts_init(&create_blob_opts);
8824 : 512 : blob_opts = &create_blob_opts;
8825 : : }
8826 : :
8827 : 1216 : spdk_bs_create_blob_ext(bs, blob_opts, blob_op_with_id_complete, NULL);
8828 : 1216 : poll_threads();
8829 : 1216 : CU_ASSERT(g_bserrno == 0);
8830 : 1216 : CU_ASSERT(g_blobid != SPDK_BLOBID_INVALID);
8831 : 1216 : blobid = g_blobid;
8832 : 1216 : g_blobid = -1;
8833 : :
8834 : 1216 : spdk_bs_open_blob(bs, blobid, blob_op_with_handle_complete, NULL);
8835 : 1216 : poll_threads();
8836 : 1216 : CU_ASSERT(g_bserrno == 0);
8837 : 1216 : CU_ASSERT(g_blob != NULL);
8838 : 1216 : blob = g_blob;
8839 : :
8840 : 1216 : g_blob = NULL;
8841 : 1216 : g_bserrno = -1;
8842 : :
8843 : 1216 : return blob;
8844 : : }
8845 : :
8846 : : static void
8847 : 1056 : ut_blob_close_and_delete(struct spdk_blob_store *bs, struct spdk_blob *blob)
8848 : : {
8849 : 1056 : spdk_blob_id blobid = spdk_blob_get_id(blob);
8850 : :
8851 : 1056 : spdk_blob_close(blob, blob_op_complete, NULL);
8852 : 1056 : poll_threads();
8853 : 1056 : CU_ASSERT(g_bserrno == 0);
8854 : 1056 : g_blob = NULL;
8855 : :
8856 : 1056 : spdk_bs_delete_blob(bs, blobid, blob_op_complete, NULL);
8857 : 1056 : poll_threads();
8858 : 1056 : CU_ASSERT(g_bserrno == 0);
8859 : 1056 : g_bserrno = -1;
8860 : 1056 : }
8861 : :
8862 : : static void
8863 : 192 : suite_blob_setup(void)
8864 : : {
8865 : 192 : suite_bs_setup();
8866 : 192 : CU_ASSERT(g_bs != NULL);
8867 : :
8868 : 192 : g_blob = ut_blob_create_and_open(g_bs, NULL);
8869 : 192 : CU_ASSERT(g_blob != NULL);
8870 : 192 : }
8871 : :
8872 : : static void
8873 : 192 : suite_blob_cleanup(void)
8874 : : {
8875 : 192 : ut_blob_close_and_delete(g_bs, g_blob);
8876 : 192 : CU_ASSERT(g_blob == NULL);
8877 : :
8878 : 192 : suite_bs_cleanup();
8879 : 192 : CU_ASSERT(g_bs == NULL);
8880 : 192 : }
8881 : :
8882 : : static int
8883 : 16 : ut_setup_config_nocopy_noextent(void)
8884 : : {
8885 : 16 : g_dev_copy_enabled = false;
8886 : 16 : g_use_extent_table = false;
8887 : :
8888 : 16 : return 0;
8889 : : }
8890 : :
8891 : : static int
8892 : 16 : ut_setup_config_nocopy_extent(void)
8893 : : {
8894 : 16 : g_dev_copy_enabled = false;
8895 : 16 : g_use_extent_table = true;
8896 : :
8897 : 16 : return 0;
8898 : : }
8899 : :
8900 : : static int
8901 : 16 : ut_setup_config_copy_noextent(void)
8902 : : {
8903 : 16 : g_dev_copy_enabled = true;
8904 : 16 : g_use_extent_table = false;
8905 : :
8906 : 16 : return 0;
8907 : : }
8908 : :
8909 : : static int
8910 : 16 : ut_setup_config_copy_extent(void)
8911 : : {
8912 : 16 : g_dev_copy_enabled = true;
8913 : 16 : g_use_extent_table = true;
8914 : :
8915 : 16 : return 0;
8916 : : }
8917 : :
8918 : : struct ut_config {
8919 : : const char *suffix;
8920 : : CU_InitializeFunc setup_cb;
8921 : : };
8922 : :
8923 : : int
8924 : 4 : main(int argc, char **argv)
8925 : : {
8926 : : CU_pSuite suite, suite_bs, suite_blob, suite_esnap_bs;
8927 : : unsigned int i, num_failures;
8928 : 4 : char suite_name[4096];
8929 : : struct ut_config *config;
8930 : 4 : struct ut_config configs[] = {
8931 : : {"nocopy_noextent", ut_setup_config_nocopy_noextent},
8932 : : {"nocopy_extent", ut_setup_config_nocopy_extent},
8933 : : {"copy_noextent", ut_setup_config_copy_noextent},
8934 : : {"copy_extent", ut_setup_config_copy_extent},
8935 : : };
8936 : :
8937 : 4 : CU_initialize_registry();
8938 : :
8939 [ + + ]: 20 : for (i = 0; i < SPDK_COUNTOF(configs); ++i) {
8940 : 16 : config = &configs[i];
8941 : :
8942 [ - + ]: 16 : snprintf(suite_name, sizeof(suite_name), "blob_%s", config->suffix);
8943 : 16 : suite = CU_add_suite(suite_name, config->setup_cb, NULL);
8944 : :
8945 [ - + ]: 16 : snprintf(suite_name, sizeof(suite_name), "blob_bs_%s", config->suffix);
8946 : 16 : suite_bs = CU_add_suite_with_setup_and_teardown(suite_name, config->setup_cb, NULL,
8947 : : suite_bs_setup, suite_bs_cleanup);
8948 : :
8949 [ - + ]: 16 : snprintf(suite_name, sizeof(suite_name), "blob_blob_%s", config->suffix);
8950 : 16 : suite_blob = CU_add_suite_with_setup_and_teardown(suite_name, config->setup_cb, NULL,
8951 : : suite_blob_setup, suite_blob_cleanup);
8952 : :
8953 [ - + ]: 16 : snprintf(suite_name, sizeof(suite_name), "blob_esnap_bs_%s", config->suffix);
8954 : 16 : suite_esnap_bs = CU_add_suite_with_setup_and_teardown(suite_name, config->setup_cb, NULL,
8955 : : suite_esnap_bs_setup,
8956 : : suite_bs_cleanup);
8957 : :
8958 : 16 : CU_ADD_TEST(suite, blob_init);
8959 : 16 : CU_ADD_TEST(suite_bs, blob_open);
8960 : 16 : CU_ADD_TEST(suite_bs, blob_create);
8961 : 16 : CU_ADD_TEST(suite_bs, blob_create_loop);
8962 : 16 : CU_ADD_TEST(suite_bs, blob_create_fail);
8963 : 16 : CU_ADD_TEST(suite_bs, blob_create_internal);
8964 : 16 : CU_ADD_TEST(suite_bs, blob_create_zero_extent);
8965 : 16 : CU_ADD_TEST(suite, blob_thin_provision);
8966 : 16 : CU_ADD_TEST(suite_bs, blob_snapshot);
8967 : 16 : CU_ADD_TEST(suite_bs, blob_clone);
8968 : 16 : CU_ADD_TEST(suite_bs, blob_inflate);
8969 : 16 : CU_ADD_TEST(suite_bs, blob_delete);
8970 : 16 : CU_ADD_TEST(suite_bs, blob_resize_test);
8971 : 16 : CU_ADD_TEST(suite, blob_read_only);
8972 : 16 : CU_ADD_TEST(suite_bs, channel_ops);
8973 : 16 : CU_ADD_TEST(suite_bs, blob_super);
8974 : 16 : CU_ADD_TEST(suite_blob, blob_write);
8975 : 16 : CU_ADD_TEST(suite_blob, blob_read);
8976 : 16 : CU_ADD_TEST(suite_blob, blob_rw_verify);
8977 : 16 : CU_ADD_TEST(suite_bs, blob_rw_verify_iov);
8978 : 16 : CU_ADD_TEST(suite_blob, blob_rw_verify_iov_nomem);
8979 : 16 : CU_ADD_TEST(suite_blob, blob_rw_iov_read_only);
8980 : 16 : CU_ADD_TEST(suite_bs, blob_unmap);
8981 : 16 : CU_ADD_TEST(suite_bs, blob_iter);
8982 : 16 : CU_ADD_TEST(suite_blob, blob_xattr);
8983 : 16 : CU_ADD_TEST(suite_bs, blob_parse_md);
8984 : 16 : CU_ADD_TEST(suite, bs_load);
8985 : 16 : CU_ADD_TEST(suite_bs, bs_load_pending_removal);
8986 : 16 : CU_ADD_TEST(suite, bs_load_custom_cluster_size);
8987 : 16 : CU_ADD_TEST(suite, bs_load_after_failed_grow);
8988 : 16 : CU_ADD_TEST(suite_bs, bs_unload);
8989 : 16 : CU_ADD_TEST(suite, bs_cluster_sz);
8990 : 16 : CU_ADD_TEST(suite_bs, bs_usable_clusters);
8991 : 16 : CU_ADD_TEST(suite, bs_resize_md);
8992 : 16 : CU_ADD_TEST(suite, bs_destroy);
8993 : 16 : CU_ADD_TEST(suite, bs_type);
8994 : 16 : CU_ADD_TEST(suite, bs_super_block);
8995 : 16 : CU_ADD_TEST(suite, bs_test_recover_cluster_count);
8996 : 16 : CU_ADD_TEST(suite, bs_grow_live);
8997 : 16 : CU_ADD_TEST(suite, bs_grow_live_no_space);
8998 : 16 : CU_ADD_TEST(suite, bs_test_grow);
8999 : 16 : CU_ADD_TEST(suite, blob_serialize_test);
9000 : 16 : CU_ADD_TEST(suite_bs, blob_crc);
9001 : 16 : CU_ADD_TEST(suite, super_block_crc);
9002 : 16 : CU_ADD_TEST(suite_blob, blob_dirty_shutdown);
9003 : 16 : CU_ADD_TEST(suite_bs, blob_flags);
9004 : 16 : CU_ADD_TEST(suite_bs, bs_version);
9005 : 16 : CU_ADD_TEST(suite_bs, blob_set_xattrs_test);
9006 : 16 : CU_ADD_TEST(suite_bs, blob_thin_prov_alloc);
9007 : 16 : CU_ADD_TEST(suite_bs, blob_insert_cluster_msg_test);
9008 : 16 : CU_ADD_TEST(suite_bs, blob_thin_prov_rw);
9009 : 16 : CU_ADD_TEST(suite, blob_thin_prov_write_count_io);
9010 : 16 : CU_ADD_TEST(suite_bs, blob_thin_prov_rle);
9011 : 16 : CU_ADD_TEST(suite_bs, blob_thin_prov_rw_iov);
9012 : 16 : CU_ADD_TEST(suite, bs_load_iter_test);
9013 : 16 : CU_ADD_TEST(suite_bs, blob_snapshot_rw);
9014 : 16 : CU_ADD_TEST(suite_bs, blob_snapshot_rw_iov);
9015 : 16 : CU_ADD_TEST(suite, blob_relations);
9016 : 16 : CU_ADD_TEST(suite, blob_relations2);
9017 : 16 : CU_ADD_TEST(suite, blob_relations3);
9018 : 16 : CU_ADD_TEST(suite, blobstore_clean_power_failure);
9019 : 16 : CU_ADD_TEST(suite, blob_delete_snapshot_power_failure);
9020 : 16 : CU_ADD_TEST(suite, blob_create_snapshot_power_failure);
9021 : 16 : CU_ADD_TEST(suite_bs, blob_inflate_rw);
9022 : 16 : CU_ADD_TEST(suite_bs, blob_snapshot_freeze_io);
9023 : 16 : CU_ADD_TEST(suite_bs, blob_operation_split_rw);
9024 : 16 : CU_ADD_TEST(suite_bs, blob_operation_split_rw_iov);
9025 : 16 : CU_ADD_TEST(suite, blob_io_unit);
9026 : 16 : CU_ADD_TEST(suite, blob_io_unit_compatibility);
9027 : 16 : CU_ADD_TEST(suite_bs, blob_simultaneous_operations);
9028 : 16 : CU_ADD_TEST(suite_bs, blob_persist_test);
9029 : 16 : CU_ADD_TEST(suite_bs, blob_decouple_snapshot);
9030 : 16 : CU_ADD_TEST(suite_bs, blob_seek_io_unit);
9031 : 16 : CU_ADD_TEST(suite_esnap_bs, blob_esnap_create);
9032 : 16 : CU_ADD_TEST(suite_bs, blob_nested_freezes);
9033 : 16 : CU_ADD_TEST(suite, blob_ext_md_pages);
9034 : 16 : CU_ADD_TEST(suite, blob_esnap_io_4096_4096);
9035 : 16 : CU_ADD_TEST(suite, blob_esnap_io_512_512);
9036 : 16 : CU_ADD_TEST(suite, blob_esnap_io_4096_512);
9037 : 16 : CU_ADD_TEST(suite, blob_esnap_io_512_4096);
9038 : 16 : CU_ADD_TEST(suite_esnap_bs, blob_esnap_thread_add_remove);
9039 : 16 : CU_ADD_TEST(suite_esnap_bs, blob_esnap_clone_snapshot);
9040 : 16 : CU_ADD_TEST(suite_esnap_bs, blob_esnap_clone_inflate);
9041 : 16 : CU_ADD_TEST(suite_esnap_bs, blob_esnap_clone_decouple);
9042 : 16 : CU_ADD_TEST(suite_esnap_bs, blob_esnap_clone_reload);
9043 : 16 : CU_ADD_TEST(suite_esnap_bs, blob_esnap_hotplug);
9044 : 16 : CU_ADD_TEST(suite_blob, blob_is_degraded);
9045 : : }
9046 : :
9047 : 4 : allocate_threads(2);
9048 : 4 : set_thread(0);
9049 : :
9050 : 4 : g_dev_buffer = calloc(1, DEV_BUFFER_SIZE);
9051 : :
9052 : 4 : num_failures = spdk_ut_run_tests(argc, argv, NULL);
9053 : :
9054 : 4 : free(g_dev_buffer);
9055 : :
9056 : 4 : free_threads();
9057 : :
9058 : 4 : return num_failures;
9059 : : }
|