Branch data Line data Source code
1 : : /* SPDX-License-Identifier: BSD-3-Clause
2 : : * Copyright (C) 2017 Intel Corporation.
3 : : * All rights reserved.
4 : : * Copyright (c) 2021-2023 NVIDIA CORPORATION & AFFILIATES. All rights reserved.
5 : : */
6 : :
7 : : #include "spdk/stdinc.h"
8 : :
9 : : #include "spdk_internal/cunit.h"
10 : : #include "spdk/blob.h"
11 : : #include "spdk/string.h"
12 : :
13 : : #include "common/lib/ut_multithread.c"
14 : : #include "../bs_dev_common.c"
15 : : #include "thread/thread.c"
16 : : #include "ext_dev.c"
17 : : #include "blob/blobstore.c"
18 : : #include "blob/request.c"
19 : : #include "blob/zeroes.c"
20 : : #include "blob/blob_bs_dev.c"
21 : : #include "esnap_dev.c"
22 : : #define BLOCKLEN DEV_BUFFER_BLOCKLEN
23 : :
24 : : struct spdk_blob_store *g_bs;
25 : : spdk_blob_id g_blobid;
26 : : struct spdk_blob *g_blob, *g_blob2;
27 : : int g_bserrno, g_bserrno2;
28 : : struct spdk_xattr_names *g_names;
29 : : int g_done;
30 : : char *g_xattr_names[] = {"first", "second", "third"};
31 : : char *g_xattr_values[] = {"one", "two", "three"};
32 : : uint64_t g_ctx = 1729;
33 : : bool g_use_extent_table = false;
34 : : uint64_t g_copied_clusters_count = 0;
35 : :
36 : : struct spdk_bs_super_block_ver1 {
37 : : uint8_t signature[8];
38 : : uint32_t version;
39 : : uint32_t length;
40 : : uint32_t clean; /* If there was a clean shutdown, this is 1. */
41 : : spdk_blob_id super_blob;
42 : :
43 : : uint32_t cluster_size; /* In bytes */
44 : :
45 : : uint32_t used_page_mask_start; /* Offset from beginning of disk, in pages */
46 : : uint32_t used_page_mask_len; /* Count, in pages */
47 : :
48 : : uint32_t used_cluster_mask_start; /* Offset from beginning of disk, in pages */
49 : : uint32_t used_cluster_mask_len; /* Count, in pages */
50 : :
51 : : uint32_t md_start; /* Offset from beginning of disk, in pages */
52 : : uint32_t md_len; /* Count, in pages */
53 : :
54 : : uint8_t reserved[4036];
55 : : uint32_t crc;
56 : : } __attribute__((packed));
57 : : SPDK_STATIC_ASSERT(sizeof(struct spdk_bs_super_block_ver1) == 0x1000, "Invalid super block size");
58 : :
59 : : static struct spdk_blob *ut_blob_create_and_open(struct spdk_blob_store *bs,
60 : : struct spdk_blob_opts *blob_opts);
61 : : static void ut_blob_close_and_delete(struct spdk_blob_store *bs, struct spdk_blob *blob);
62 : : static void suite_blob_setup(void);
63 : : static void suite_blob_cleanup(void);
64 : :
65 [ # # # # ]: 0 : DEFINE_STUB(spdk_memory_domain_memzero, int, (struct spdk_memory_domain *src_domain,
66 : : void *src_domain_ctx, struct iovec *iov, uint32_t iovcnt, void (*cpl_cb)(void *, int),
67 : : void *cpl_cb_arg), 0);
68 : :
69 : : static bool
70 : 180 : is_esnap_clone(struct spdk_blob *_blob, const void *id, size_t id_len)
71 : : {
72 : 180 : const void *val = NULL;
73 : 180 : size_t len = 0;
74 : : bool c0, c1, c2, c3;
75 : :
76 : 180 : CU_ASSERT(blob_get_xattr_value(_blob, BLOB_EXTERNAL_SNAPSHOT_ID, &val, &len,
77 : : true) == 0);
78 : 180 : CU_ASSERT((c0 = (len == id_len)));
79 [ + + + + : 180 : CU_ASSERT((c1 = (val != NULL && memcmp(val, id, len) == 0)));
- + + - ]
80 : 180 : CU_ASSERT((c2 = !!(_blob->invalid_flags & SPDK_BLOB_EXTERNAL_SNAPSHOT)));
81 : 180 : CU_ASSERT((c3 = (_blob->parent_id == SPDK_BLOBID_EXTERNAL_SNAPSHOT)));
82 : :
83 [ + - + - : 180 : return c0 && c1 && c2 && c3;
+ + + - ]
84 : : }
85 : :
86 : : static bool
87 : 100 : is_not_esnap_clone(struct spdk_blob *_blob)
88 : : {
89 : 100 : const void *val = NULL;
90 : 100 : size_t len = 0;
91 : : bool c1, c2, c3, c4;
92 : :
93 : 100 : CU_ASSERT((c1 = (blob_get_xattr_value(_blob, BLOB_EXTERNAL_SNAPSHOT_ID, &val, &len,
94 : : true) == -ENOENT)));
95 : 100 : CU_ASSERT((c2 = (val == NULL)));
96 : 100 : CU_ASSERT((c3 = ((_blob->invalid_flags & SPDK_BLOB_EXTERNAL_SNAPSHOT) == 0)));
97 : 100 : CU_ASSERT((c4 = (_blob->parent_id != SPDK_BLOBID_EXTERNAL_SNAPSHOT)));
98 : :
99 [ + - + - : 100 : return c1 && c2 && c3 && c4;
+ + + - ]
100 : : }
101 : :
102 : : #define UT_ASSERT_IS_ESNAP_CLONE(_blob, _id, _len) CU_ASSERT(is_esnap_clone(_blob, _id, _len))
103 : : #define UT_ASSERT_IS_NOT_ESNAP_CLONE(_blob) CU_ASSERT(is_not_esnap_clone(_blob))
104 : :
105 : : static void
106 : 240 : _get_xattr_value(void *arg, const char *name,
107 : : const void **value, size_t *value_len)
108 : : {
109 : : uint64_t i;
110 : :
111 [ + + ]: 240 : SPDK_CU_ASSERT_FATAL(value_len != NULL);
112 [ - + ]: 240 : SPDK_CU_ASSERT_FATAL(value != NULL);
113 : 240 : CU_ASSERT(arg == &g_ctx);
114 : :
115 [ + + ]: 480 : for (i = 0; i < sizeof(g_xattr_names); i++) {
116 [ + + - + : 480 : if (!strcmp(name, g_xattr_names[i])) {
+ + ]
117 [ - + ]: 240 : *value_len = strlen(g_xattr_values[i]);
118 : 240 : *value = g_xattr_values[i];
119 : 240 : break;
120 : : }
121 : 60 : }
122 : 240 : }
123 : :
124 : : static void
125 : 20 : _get_xattr_value_null(void *arg, const char *name,
126 : : const void **value, size_t *value_len)
127 : : {
128 [ + + ]: 20 : SPDK_CU_ASSERT_FATAL(value_len != NULL);
129 [ - + ]: 20 : SPDK_CU_ASSERT_FATAL(value != NULL);
130 : 20 : CU_ASSERT(arg == NULL);
131 : :
132 : 20 : *value_len = 0;
133 : 20 : *value = NULL;
134 : 20 : }
135 : :
136 : : static int
137 : 320 : _get_snapshots_count(struct spdk_blob_store *bs)
138 : : {
139 : 320 : struct spdk_blob_list *snapshot = NULL;
140 : 320 : int count = 0;
141 : :
142 [ + + ]: 620 : TAILQ_FOREACH(snapshot, &bs->snapshots, link) {
143 : 300 : count += 1;
144 : 75 : }
145 : :
146 : 320 : return count;
147 : : }
148 : :
149 : : static void
150 : 7636 : ut_spdk_blob_opts_init(struct spdk_blob_opts *opts)
151 : : {
152 : 7636 : spdk_blob_opts_init(opts, sizeof(*opts));
153 [ - + ]: 7636 : opts->use_extent_table = g_use_extent_table;
154 : 7636 : }
155 : :
156 : : static void
157 : 72264 : bs_op_complete(void *cb_arg, int bserrno)
158 : : {
159 : 72264 : g_bserrno = bserrno;
160 : 72264 : }
161 : :
162 : : static void
163 : 3992 : bs_op_with_handle_complete(void *cb_arg, struct spdk_blob_store *bs,
164 : : int bserrno)
165 : : {
166 : 3992 : g_bs = bs;
167 : 3992 : g_bserrno = bserrno;
168 : 3992 : }
169 : :
170 : : static void
171 : 164944 : blob_op_complete(void *cb_arg, int bserrno)
172 : : {
173 [ + + ]: 164944 : if (cb_arg != NULL) {
174 : 100 : int *errp = cb_arg;
175 : :
176 : 100 : *errp = bserrno;
177 : 25 : }
178 : 164944 : g_bserrno = bserrno;
179 : 164944 : }
180 : :
181 : : static void
182 : 9532 : blob_op_with_id_complete(void *cb_arg, spdk_blob_id blobid, int bserrno)
183 : : {
184 : 9532 : g_blobid = blobid;
185 : 9532 : g_bserrno = bserrno;
186 : 9532 : }
187 : :
188 : : static void
189 : 4920 : blob_op_with_handle_complete(void *cb_arg, struct spdk_blob *blb, int bserrno)
190 : : {
191 : 4920 : g_blob = blb;
192 : 4920 : g_bserrno = bserrno;
193 : 4920 : }
194 : :
195 : : static void
196 : 40 : blob_op_with_handle_complete2(void *cb_arg, struct spdk_blob *blob, int bserrno)
197 : : {
198 [ + + ]: 40 : if (g_blob == NULL) {
199 : 20 : g_blob = blob;
200 : 20 : g_bserrno = bserrno;
201 : 5 : } else {
202 : 20 : g_blob2 = blob;
203 : 20 : g_bserrno2 = bserrno;
204 : : }
205 : 40 : }
206 : :
207 : : static void
208 : 40 : blob_shallow_copy_status_cb(uint64_t copied_clusters, void *cb_arg)
209 : : {
210 : 40 : g_copied_clusters_count = copied_clusters;
211 : 40 : }
212 : :
213 : : static void
214 : 540 : ut_bs_reload(struct spdk_blob_store **bs, struct spdk_bs_opts *opts)
215 : : {
216 : : struct spdk_bs_dev *dev;
217 : :
218 : : /* Unload the blob store */
219 : 540 : spdk_bs_unload(*bs, bs_op_complete, NULL);
220 : 540 : poll_threads();
221 : 540 : CU_ASSERT(g_bserrno == 0);
222 : :
223 : 540 : dev = init_dev();
224 : : /* Load an existing blob store */
225 : 540 : spdk_bs_load(dev, opts, bs_op_with_handle_complete, NULL);
226 : 540 : poll_threads();
227 : 540 : CU_ASSERT(g_bserrno == 0);
228 [ + + ]: 540 : SPDK_CU_ASSERT_FATAL(g_bs != NULL);
229 : 540 : *bs = g_bs;
230 : :
231 : 540 : g_bserrno = -1;
232 : 540 : }
233 : :
234 : : static void
235 : 456 : ut_bs_dirty_load(struct spdk_blob_store **bs, struct spdk_bs_opts *opts)
236 : : {
237 : : struct spdk_bs_dev *dev;
238 : :
239 : : /* Dirty shutdown */
240 : 456 : bs_free(*bs);
241 : :
242 : 456 : dev = init_dev();
243 : : /* Load an existing blob store */
244 : 456 : spdk_bs_load(dev, opts, bs_op_with_handle_complete, NULL);
245 : 456 : poll_threads();
246 : 456 : CU_ASSERT(g_bserrno == 0);
247 [ + + ]: 456 : SPDK_CU_ASSERT_FATAL(g_bs != NULL);
248 : 456 : *bs = g_bs;
249 : :
250 : 456 : g_bserrno = -1;
251 : 456 : }
252 : :
253 : : static void
254 : 20 : blob_init(void)
255 : : {
256 : : struct spdk_blob_store *bs;
257 : : struct spdk_bs_dev *dev;
258 : :
259 : 20 : dev = init_dev();
260 : :
261 : : /* should fail for an unsupported blocklen */
262 : 20 : dev->blocklen = 500;
263 : 20 : spdk_bs_init(dev, NULL, bs_op_with_handle_complete, NULL);
264 : 20 : poll_threads();
265 : 20 : CU_ASSERT(g_bserrno == -EINVAL);
266 : :
267 : 20 : dev = init_dev();
268 : 20 : spdk_bs_init(dev, NULL, bs_op_with_handle_complete, NULL);
269 : 20 : poll_threads();
270 : 20 : CU_ASSERT(g_bserrno == 0);
271 [ + + ]: 20 : SPDK_CU_ASSERT_FATAL(g_bs != NULL);
272 : 20 : bs = g_bs;
273 : :
274 : 20 : spdk_bs_unload(bs, bs_op_complete, NULL);
275 : 20 : poll_threads();
276 : 20 : CU_ASSERT(g_bserrno == 0);
277 : 20 : g_bs = NULL;
278 : 20 : }
279 : :
280 : : static void
281 : 20 : blob_super(void)
282 : : {
283 : 20 : struct spdk_blob_store *bs = g_bs;
284 : : spdk_blob_id blobid;
285 : 15 : struct spdk_blob_opts blob_opts;
286 : :
287 : : /* Get the super blob without having set one */
288 : 20 : spdk_bs_get_super(bs, blob_op_with_id_complete, NULL);
289 : 20 : poll_threads();
290 : 20 : CU_ASSERT(g_bserrno == -ENOENT);
291 : 20 : CU_ASSERT(g_blobid == SPDK_BLOBID_INVALID);
292 : :
293 : : /* Create a blob */
294 : 20 : ut_spdk_blob_opts_init(&blob_opts);
295 : 20 : spdk_bs_create_blob_ext(bs, &blob_opts, blob_op_with_id_complete, NULL);
296 : 20 : poll_threads();
297 : 20 : CU_ASSERT(g_bserrno == 0);
298 : 20 : CU_ASSERT(g_blobid != SPDK_BLOBID_INVALID);
299 : 20 : blobid = g_blobid;
300 : :
301 : : /* Set the blob as the super blob */
302 : 20 : spdk_bs_set_super(bs, blobid, blob_op_complete, NULL);
303 : 20 : poll_threads();
304 : 20 : CU_ASSERT(g_bserrno == 0);
305 : :
306 : : /* Get the super blob */
307 : 20 : spdk_bs_get_super(bs, blob_op_with_id_complete, NULL);
308 : 20 : poll_threads();
309 : 20 : CU_ASSERT(g_bserrno == 0);
310 : 20 : CU_ASSERT(blobid == g_blobid);
311 : 20 : }
312 : :
313 : : static void
314 : 20 : blob_open(void)
315 : : {
316 : 20 : struct spdk_blob_store *bs = g_bs;
317 : : struct spdk_blob *blob;
318 : 15 : struct spdk_blob_opts blob_opts;
319 : : spdk_blob_id blobid, blobid2;
320 : :
321 : 20 : ut_spdk_blob_opts_init(&blob_opts);
322 : 20 : spdk_bs_create_blob_ext(bs, &blob_opts, blob_op_with_id_complete, NULL);
323 : 20 : poll_threads();
324 : 20 : CU_ASSERT(g_bserrno == 0);
325 : 20 : CU_ASSERT(g_blobid != SPDK_BLOBID_INVALID);
326 : 20 : blobid = g_blobid;
327 : :
328 : 20 : spdk_bs_open_blob(bs, blobid, blob_op_with_handle_complete, NULL);
329 : 20 : poll_threads();
330 : 20 : CU_ASSERT(g_bserrno == 0);
331 : 20 : CU_ASSERT(g_blob != NULL);
332 : 20 : blob = g_blob;
333 : :
334 : 20 : blobid2 = spdk_blob_get_id(blob);
335 : 20 : CU_ASSERT(blobid == blobid2);
336 : :
337 : : /* Try to open file again. It should return success. */
338 : 20 : spdk_bs_open_blob(bs, blobid, blob_op_with_handle_complete, NULL);
339 : 20 : poll_threads();
340 : 20 : CU_ASSERT(g_bserrno == 0);
341 : 20 : CU_ASSERT(blob == g_blob);
342 : :
343 : 20 : spdk_blob_close(blob, blob_op_complete, NULL);
344 : 20 : poll_threads();
345 : 20 : CU_ASSERT(g_bserrno == 0);
346 : :
347 : : /*
348 : : * Close the file a second time, releasing the second reference. This
349 : : * should succeed.
350 : : */
351 : 20 : blob = g_blob;
352 : 20 : spdk_blob_close(blob, blob_op_complete, NULL);
353 : 20 : poll_threads();
354 : 20 : CU_ASSERT(g_bserrno == 0);
355 : :
356 : : /*
357 : : * Try to open file again. It should succeed. This tests the case
358 : : * where the file is opened, closed, then re-opened again.
359 : : */
360 : 20 : spdk_bs_open_blob(bs, blobid, blob_op_with_handle_complete, NULL);
361 : 20 : poll_threads();
362 : 20 : CU_ASSERT(g_bserrno == 0);
363 : 20 : CU_ASSERT(g_blob != NULL);
364 : 20 : blob = g_blob;
365 : 20 : spdk_blob_close(blob, blob_op_complete, NULL);
366 : 20 : poll_threads();
367 : 20 : CU_ASSERT(g_bserrno == 0);
368 : :
369 : : /* Try to open file twice in succession. This should return the same
370 : : * blob object.
371 : : */
372 : 20 : g_blob = NULL;
373 : 20 : g_blob2 = NULL;
374 : 20 : g_bserrno = -1;
375 : 20 : g_bserrno2 = -1;
376 : 20 : spdk_bs_open_blob(bs, blobid, blob_op_with_handle_complete2, NULL);
377 : 20 : spdk_bs_open_blob(bs, blobid, blob_op_with_handle_complete2, NULL);
378 : 20 : poll_threads();
379 : 20 : CU_ASSERT(g_bserrno == 0);
380 : 20 : CU_ASSERT(g_bserrno2 == 0);
381 : 20 : CU_ASSERT(g_blob != NULL);
382 : 20 : CU_ASSERT(g_blob2 != NULL);
383 : 20 : CU_ASSERT(g_blob == g_blob2);
384 : :
385 : 20 : g_bserrno = -1;
386 : 20 : spdk_blob_close(g_blob, blob_op_complete, NULL);
387 : 20 : poll_threads();
388 : 20 : CU_ASSERT(g_bserrno == 0);
389 : :
390 : 20 : ut_blob_close_and_delete(bs, g_blob);
391 : 20 : }
392 : :
393 : : static void
394 : 20 : blob_create(void)
395 : : {
396 : 20 : struct spdk_blob_store *bs = g_bs;
397 : : struct spdk_blob *blob;
398 : 15 : struct spdk_blob_opts opts;
399 : : spdk_blob_id blobid;
400 : :
401 : : /* Create blob with 10 clusters */
402 : :
403 : 20 : ut_spdk_blob_opts_init(&opts);
404 : 20 : opts.num_clusters = 10;
405 : :
406 : 20 : spdk_bs_create_blob_ext(bs, &opts, blob_op_with_id_complete, NULL);
407 : 20 : poll_threads();
408 : 20 : CU_ASSERT(g_bserrno == 0);
409 : 20 : CU_ASSERT(g_blobid != SPDK_BLOBID_INVALID);
410 : 20 : blobid = g_blobid;
411 : :
412 : 20 : spdk_bs_open_blob(bs, blobid, blob_op_with_handle_complete, NULL);
413 : 20 : poll_threads();
414 : 20 : CU_ASSERT(g_bserrno == 0);
415 [ + + ]: 20 : SPDK_CU_ASSERT_FATAL(g_blob != NULL);
416 : 20 : blob = g_blob;
417 : 20 : CU_ASSERT(spdk_blob_get_num_clusters(blob) == 10);
418 : 20 : CU_ASSERT(spdk_blob_get_num_allocated_clusters(blob) == 10);
419 : :
420 : 20 : spdk_blob_close(blob, blob_op_complete, NULL);
421 : 20 : poll_threads();
422 : 20 : CU_ASSERT(g_bserrno == 0);
423 : :
424 : : /* Create blob with 0 clusters */
425 : :
426 : 20 : ut_spdk_blob_opts_init(&opts);
427 : 20 : opts.num_clusters = 0;
428 : :
429 : 20 : spdk_bs_create_blob_ext(bs, &opts, blob_op_with_id_complete, NULL);
430 : 20 : poll_threads();
431 : 20 : CU_ASSERT(g_bserrno == 0);
432 : 20 : CU_ASSERT(g_blobid != SPDK_BLOBID_INVALID);
433 : 20 : blobid = g_blobid;
434 : :
435 : 20 : spdk_bs_open_blob(bs, blobid, blob_op_with_handle_complete, NULL);
436 : 20 : poll_threads();
437 : 20 : CU_ASSERT(g_bserrno == 0);
438 [ + + ]: 20 : SPDK_CU_ASSERT_FATAL(g_blob != NULL);
439 : 20 : blob = g_blob;
440 : 20 : CU_ASSERT(spdk_blob_get_num_clusters(blob) == 0);
441 : 20 : CU_ASSERT(spdk_blob_get_num_allocated_clusters(blob) == 0);
442 : :
443 : 20 : spdk_blob_close(blob, blob_op_complete, NULL);
444 : 20 : poll_threads();
445 : 20 : CU_ASSERT(g_bserrno == 0);
446 : :
447 : : /* Create blob with default options (opts == NULL) */
448 : :
449 : 20 : spdk_bs_create_blob_ext(bs, NULL, blob_op_with_id_complete, NULL);
450 : 20 : poll_threads();
451 : 20 : CU_ASSERT(g_bserrno == 0);
452 : 20 : CU_ASSERT(g_blobid != SPDK_BLOBID_INVALID);
453 : 20 : blobid = g_blobid;
454 : :
455 : 20 : spdk_bs_open_blob(bs, blobid, blob_op_with_handle_complete, NULL);
456 : 20 : poll_threads();
457 : 20 : CU_ASSERT(g_bserrno == 0);
458 [ - + ]: 20 : SPDK_CU_ASSERT_FATAL(g_blob != NULL);
459 : 20 : blob = g_blob;
460 : 20 : CU_ASSERT(spdk_blob_get_num_clusters(blob) == 0);
461 : 20 : CU_ASSERT(spdk_blob_get_num_allocated_clusters(blob) == 0);
462 : :
463 : 20 : spdk_blob_close(blob, blob_op_complete, NULL);
464 : 20 : poll_threads();
465 : 20 : CU_ASSERT(g_bserrno == 0);
466 : :
467 : : /* Try to create blob with size larger than blobstore */
468 : :
469 : 20 : ut_spdk_blob_opts_init(&opts);
470 : 20 : opts.num_clusters = bs->total_clusters + 1;
471 : :
472 : 20 : spdk_bs_create_blob_ext(bs, &opts, blob_op_with_id_complete, NULL);
473 : 20 : poll_threads();
474 : 20 : CU_ASSERT(g_bserrno == -ENOSPC);
475 : 20 : }
476 : :
477 : : static void
478 : 20 : blob_create_zero_extent(void)
479 : : {
480 : 20 : struct spdk_blob_store *bs = g_bs;
481 : : struct spdk_blob *blob;
482 : : spdk_blob_id blobid;
483 : :
484 : : /* Create blob with default options (opts == NULL) */
485 : 20 : spdk_bs_create_blob_ext(bs, NULL, blob_op_with_id_complete, NULL);
486 : 20 : poll_threads();
487 : 20 : CU_ASSERT(g_bserrno == 0);
488 : 20 : CU_ASSERT(g_blobid != SPDK_BLOBID_INVALID);
489 : 20 : blobid = g_blobid;
490 : :
491 : 20 : spdk_bs_open_blob(bs, blobid, blob_op_with_handle_complete, NULL);
492 : 20 : poll_threads();
493 : 20 : CU_ASSERT(g_bserrno == 0);
494 [ + + ]: 20 : SPDK_CU_ASSERT_FATAL(g_blob != NULL);
495 : 20 : blob = g_blob;
496 : 20 : CU_ASSERT(spdk_blob_get_num_clusters(blob) == 0);
497 [ - + ]: 20 : CU_ASSERT(blob->extent_table_found == true);
498 : 20 : CU_ASSERT(blob->active.extent_pages_array_size == 0);
499 : 20 : CU_ASSERT(blob->active.extent_pages == NULL);
500 : :
501 : 20 : spdk_blob_close(blob, blob_op_complete, NULL);
502 : 20 : poll_threads();
503 : 20 : CU_ASSERT(g_bserrno == 0);
504 : :
505 : : /* Create blob with NULL internal options */
506 : 20 : bs_create_blob(bs, NULL, NULL, blob_op_with_id_complete, NULL);
507 : 20 : poll_threads();
508 : 20 : CU_ASSERT(g_bserrno == 0);
509 : 20 : CU_ASSERT(g_blobid != SPDK_BLOBID_INVALID);
510 : 20 : blobid = g_blobid;
511 : :
512 : 20 : spdk_bs_open_blob(bs, blobid, blob_op_with_handle_complete, NULL);
513 : 20 : poll_threads();
514 : 20 : CU_ASSERT(g_bserrno == 0);
515 [ - + ]: 20 : SPDK_CU_ASSERT_FATAL(g_blob != NULL);
516 : 20 : blob = g_blob;
517 : 20 : CU_ASSERT(TAILQ_FIRST(&blob->xattrs_internal) == NULL);
518 : 20 : CU_ASSERT(spdk_blob_get_num_clusters(blob) == 0);
519 [ - + ]: 20 : CU_ASSERT(blob->extent_table_found == true);
520 : 20 : CU_ASSERT(blob->active.extent_pages_array_size == 0);
521 : 20 : CU_ASSERT(blob->active.extent_pages == NULL);
522 : :
523 : 20 : spdk_blob_close(blob, blob_op_complete, NULL);
524 : 20 : poll_threads();
525 : 20 : CU_ASSERT(g_bserrno == 0);
526 : 20 : }
527 : :
528 : : /*
529 : : * Create and delete one blob in a loop over and over again. This helps ensure
530 : : * that the internal bit masks tracking used clusters and md_pages are being
531 : : * tracked correctly.
532 : : */
533 : : static void
534 : 20 : blob_create_loop(void)
535 : : {
536 : 20 : struct spdk_blob_store *bs = g_bs;
537 : 15 : struct spdk_blob_opts opts;
538 : : uint32_t i, loop_count;
539 : :
540 [ - + ]: 20 : loop_count = 4 * spdk_max(spdk_bit_array_capacity(bs->used_md_pages),
541 : : spdk_bit_pool_capacity(bs->used_clusters));
542 : :
543 [ + + ]: 5140 : for (i = 0; i < loop_count; i++) {
544 : 5120 : ut_spdk_blob_opts_init(&opts);
545 : 5120 : opts.num_clusters = 1;
546 : 5120 : g_bserrno = -1;
547 : 5120 : g_blobid = SPDK_BLOBID_INVALID;
548 : 5120 : spdk_bs_create_blob_ext(bs, &opts, blob_op_with_id_complete, NULL);
549 : 5120 : poll_threads();
550 : 5120 : CU_ASSERT(g_bserrno == 0);
551 : 5120 : CU_ASSERT(g_blobid != SPDK_BLOBID_INVALID);
552 : 5120 : spdk_bs_delete_blob(bs, g_blobid, blob_op_complete, NULL);
553 : 5120 : poll_threads();
554 : 5120 : CU_ASSERT(g_bserrno == 0);
555 : 1280 : }
556 : 20 : }
557 : :
558 : : static void
559 : 20 : blob_create_fail(void)
560 : : {
561 : 20 : struct spdk_blob_store *bs = g_bs;
562 : 15 : struct spdk_blob_opts opts;
563 : : spdk_blob_id blobid;
564 : 20 : uint32_t used_blobids_count = spdk_bit_array_count_set(bs->used_blobids);
565 : 20 : uint32_t used_md_pages_count = spdk_bit_array_count_set(bs->used_md_pages);
566 : :
567 : : /* NULL callback */
568 : 20 : ut_spdk_blob_opts_init(&opts);
569 : 20 : opts.xattrs.names = g_xattr_names;
570 : 20 : opts.xattrs.get_value = NULL;
571 : 20 : opts.xattrs.count = 1;
572 : 20 : opts.xattrs.ctx = &g_ctx;
573 : :
574 : 20 : blobid = spdk_bit_array_find_first_clear(bs->used_md_pages, 0);
575 : 20 : spdk_bs_create_blob_ext(bs, &opts, blob_op_with_id_complete, NULL);
576 : 20 : poll_threads();
577 : 20 : CU_ASSERT(g_bserrno == -EINVAL);
578 : 20 : CU_ASSERT(g_blobid != SPDK_BLOBID_INVALID);
579 : 20 : CU_ASSERT(spdk_bit_array_count_set(bs->used_blobids) == used_blobids_count);
580 : 20 : CU_ASSERT(spdk_bit_array_count_set(bs->used_md_pages) == used_md_pages_count);
581 : :
582 : 20 : spdk_bs_open_blob(bs, blobid, blob_op_with_handle_complete, NULL);
583 : 20 : poll_threads();
584 : 20 : CU_ASSERT(g_bserrno == -ENOENT);
585 [ + + ]: 20 : SPDK_CU_ASSERT_FATAL(g_blob == NULL);
586 : :
587 : 20 : ut_bs_reload(&bs, NULL);
588 : 20 : CU_ASSERT(spdk_bit_array_count_set(bs->used_blobids) == used_blobids_count);
589 : 20 : CU_ASSERT(spdk_bit_array_count_set(bs->used_md_pages) == used_md_pages_count);
590 : :
591 : 20 : spdk_bs_iter_first(bs, blob_op_with_handle_complete, NULL);
592 : 20 : poll_threads();
593 : 20 : CU_ASSERT(g_blob == NULL);
594 : 20 : CU_ASSERT(g_bserrno == -ENOENT);
595 : 20 : }
596 : :
597 : : static void
598 : 20 : blob_create_internal(void)
599 : : {
600 : 20 : struct spdk_blob_store *bs = g_bs;
601 : : struct spdk_blob *blob;
602 : 15 : struct spdk_blob_opts opts;
603 : 15 : struct spdk_blob_xattr_opts internal_xattrs;
604 : 15 : const void *value;
605 : 15 : size_t value_len;
606 : : spdk_blob_id blobid;
607 : : int rc;
608 : :
609 : : /* Create blob with custom xattrs */
610 : :
611 : 20 : ut_spdk_blob_opts_init(&opts);
612 : 20 : blob_xattrs_init(&internal_xattrs);
613 : 20 : internal_xattrs.count = 3;
614 : 20 : internal_xattrs.names = g_xattr_names;
615 : 20 : internal_xattrs.get_value = _get_xattr_value;
616 : 20 : internal_xattrs.ctx = &g_ctx;
617 : :
618 : 20 : bs_create_blob(bs, &opts, &internal_xattrs, blob_op_with_id_complete, NULL);
619 : 20 : poll_threads();
620 : 20 : CU_ASSERT(g_bserrno == 0);
621 : 20 : CU_ASSERT(g_blobid != SPDK_BLOBID_INVALID);
622 : 20 : blobid = g_blobid;
623 : :
624 : 20 : spdk_bs_open_blob(bs, blobid, blob_op_with_handle_complete, NULL);
625 : 20 : poll_threads();
626 : 20 : CU_ASSERT(g_bserrno == 0);
627 [ + + ]: 20 : SPDK_CU_ASSERT_FATAL(g_blob != NULL);
628 : 20 : blob = g_blob;
629 : :
630 : 20 : rc = blob_get_xattr_value(blob, g_xattr_names[0], &value, &value_len, true);
631 : 20 : CU_ASSERT(rc == 0);
632 [ + + ]: 20 : SPDK_CU_ASSERT_FATAL(value != NULL);
633 [ - + ]: 20 : CU_ASSERT(value_len == strlen(g_xattr_values[0]));
634 [ - + - + ]: 20 : CU_ASSERT_NSTRING_EQUAL_FATAL(value, g_xattr_values[0], value_len);
635 : :
636 : 20 : rc = blob_get_xattr_value(blob, g_xattr_names[1], &value, &value_len, true);
637 : 20 : CU_ASSERT(rc == 0);
638 [ + + ]: 20 : SPDK_CU_ASSERT_FATAL(value != NULL);
639 [ - + ]: 20 : CU_ASSERT(value_len == strlen(g_xattr_values[1]));
640 [ - + - + ]: 20 : CU_ASSERT_NSTRING_EQUAL((char *)value, g_xattr_values[1], value_len);
641 : :
642 : 20 : rc = blob_get_xattr_value(blob, g_xattr_names[2], &value, &value_len, true);
643 : 20 : CU_ASSERT(rc == 0);
644 [ + + ]: 20 : SPDK_CU_ASSERT_FATAL(value != NULL);
645 [ - + ]: 20 : CU_ASSERT(value_len == strlen(g_xattr_values[2]));
646 [ - + - + ]: 20 : CU_ASSERT_NSTRING_EQUAL((char *)value, g_xattr_values[2], value_len);
647 : :
648 : 20 : rc = spdk_blob_get_xattr_value(blob, g_xattr_names[0], &value, &value_len);
649 : 20 : CU_ASSERT(rc != 0);
650 : :
651 : 20 : rc = spdk_blob_get_xattr_value(blob, g_xattr_names[1], &value, &value_len);
652 : 20 : CU_ASSERT(rc != 0);
653 : :
654 : 20 : rc = spdk_blob_get_xattr_value(blob, g_xattr_names[2], &value, &value_len);
655 : 20 : CU_ASSERT(rc != 0);
656 : :
657 : 20 : spdk_blob_close(blob, blob_op_complete, NULL);
658 : 20 : poll_threads();
659 : 20 : CU_ASSERT(g_bserrno == 0);
660 : :
661 : : /* Create blob with NULL internal options */
662 : :
663 : 20 : bs_create_blob(bs, NULL, NULL, blob_op_with_id_complete, NULL);
664 : 20 : poll_threads();
665 : 20 : CU_ASSERT(g_bserrno == 0);
666 : 20 : CU_ASSERT(g_blobid != SPDK_BLOBID_INVALID);
667 : 20 : blobid = g_blobid;
668 : :
669 : 20 : spdk_bs_open_blob(bs, blobid, blob_op_with_handle_complete, NULL);
670 : 20 : poll_threads();
671 : 20 : CU_ASSERT(g_bserrno == 0);
672 [ - + ]: 20 : SPDK_CU_ASSERT_FATAL(g_blob != NULL);
673 : 20 : CU_ASSERT(TAILQ_FIRST(&g_blob->xattrs_internal) == NULL);
674 : 20 : CU_ASSERT(spdk_blob_get_num_clusters(g_blob) == 0);
675 : :
676 : 20 : blob = g_blob;
677 : :
678 : 20 : spdk_blob_close(blob, blob_op_complete, NULL);
679 : 20 : poll_threads();
680 : 20 : CU_ASSERT(g_bserrno == 0);
681 : 20 : }
682 : :
683 : : static void
684 : 20 : blob_thin_provision(void)
685 : : {
686 : 15 : struct spdk_blob_store *bs;
687 : : struct spdk_bs_dev *dev;
688 : : struct spdk_blob *blob;
689 : 15 : struct spdk_blob_opts opts;
690 : 15 : struct spdk_bs_opts bs_opts;
691 : : spdk_blob_id blobid;
692 : :
693 : 20 : dev = init_dev();
694 : 20 : spdk_bs_opts_init(&bs_opts, sizeof(bs_opts));
695 [ - + ]: 20 : snprintf(bs_opts.bstype.bstype, sizeof(bs_opts.bstype.bstype), "TESTTYPE");
696 : :
697 : : /* Initialize a new blob store */
698 : 20 : spdk_bs_init(dev, &bs_opts, bs_op_with_handle_complete, NULL);
699 : 20 : poll_threads();
700 : 20 : CU_ASSERT(g_bserrno == 0);
701 [ + + ]: 20 : SPDK_CU_ASSERT_FATAL(g_bs != NULL);
702 : :
703 : 20 : bs = g_bs;
704 : :
705 : : /* Create blob with thin provisioning enabled */
706 : :
707 : 20 : ut_spdk_blob_opts_init(&opts);
708 : 20 : opts.thin_provision = true;
709 : 20 : opts.num_clusters = 10;
710 : :
711 : 20 : blob = ut_blob_create_and_open(bs, &opts);
712 : 20 : blobid = spdk_blob_get_id(blob);
713 : 20 : CU_ASSERT(blob->invalid_flags & SPDK_BLOB_THIN_PROV);
714 : 20 : CU_ASSERT(spdk_blob_get_num_allocated_clusters(blob) == 0);
715 : : /* In thin provisioning with num_clusters is set, if not using the
716 : : * extent table, there is no allocation. If extent table is used,
717 : : * there is related allocation happened. */
718 [ + + + + ]: 20 : if (blob->extent_table_found == true) {
719 : 12 : CU_ASSERT(blob->active.extent_pages_array_size > 0);
720 : 12 : CU_ASSERT(blob->active.extent_pages != NULL);
721 : 3 : } else {
722 : 8 : CU_ASSERT(blob->active.extent_pages_array_size == 0);
723 : 8 : CU_ASSERT(blob->active.extent_pages == NULL);
724 : : }
725 : :
726 : 20 : spdk_blob_close(blob, blob_op_complete, NULL);
727 : 20 : CU_ASSERT(g_bserrno == 0);
728 : :
729 : : /* Do not shut down cleanly. This makes sure that when we load again
730 : : * and try to recover a valid used_cluster map, that blobstore will
731 : : * ignore clusters with index 0 since these are unallocated clusters.
732 : : */
733 : 20 : ut_bs_dirty_load(&bs, &bs_opts);
734 : :
735 : 20 : spdk_bs_open_blob(bs, blobid, blob_op_with_handle_complete, NULL);
736 : 20 : poll_threads();
737 : 20 : CU_ASSERT(g_bserrno == 0);
738 [ - + ]: 20 : SPDK_CU_ASSERT_FATAL(g_blob != NULL);
739 : 20 : blob = g_blob;
740 : 20 : CU_ASSERT(blob->invalid_flags & SPDK_BLOB_THIN_PROV);
741 : 20 : CU_ASSERT(spdk_blob_get_num_allocated_clusters(blob) == 0);
742 : :
743 : 20 : ut_blob_close_and_delete(bs, blob);
744 : :
745 : 20 : spdk_bs_unload(bs, bs_op_complete, NULL);
746 : 20 : poll_threads();
747 : 20 : CU_ASSERT(g_bserrno == 0);
748 : 20 : g_bs = NULL;
749 : 20 : }
750 : :
751 : : static void
752 : 20 : blob_snapshot(void)
753 : : {
754 : 20 : struct spdk_blob_store *bs = g_bs;
755 : : struct spdk_blob *blob;
756 : : struct spdk_blob *snapshot, *snapshot2;
757 : : struct spdk_blob_bs_dev *blob_bs_dev;
758 : 15 : struct spdk_blob_opts opts;
759 : 15 : struct spdk_blob_xattr_opts xattrs;
760 : : spdk_blob_id blobid;
761 : : spdk_blob_id snapshotid;
762 : : spdk_blob_id snapshotid2;
763 : 15 : const void *value;
764 : 15 : size_t value_len;
765 : : int rc;
766 : 15 : spdk_blob_id ids[2];
767 : 15 : size_t count;
768 : :
769 : : /* Create blob with 10 clusters */
770 : 20 : ut_spdk_blob_opts_init(&opts);
771 : 20 : opts.num_clusters = 10;
772 : :
773 : 20 : blob = ut_blob_create_and_open(bs, &opts);
774 : 20 : blobid = spdk_blob_get_id(blob);
775 : 20 : CU_ASSERT(spdk_blob_get_num_clusters(blob) == 10);
776 : :
777 : : /* Create snapshot from blob */
778 : 20 : CU_ASSERT_EQUAL(_get_snapshots_count(bs), 0);
779 : 20 : spdk_bs_create_snapshot(bs, blobid, NULL, blob_op_with_id_complete, NULL);
780 : 20 : poll_threads();
781 : 20 : CU_ASSERT(g_bserrno == 0);
782 : 20 : CU_ASSERT(g_blobid != SPDK_BLOBID_INVALID);
783 : 20 : CU_ASSERT_EQUAL(_get_snapshots_count(bs), 1);
784 : 20 : snapshotid = g_blobid;
785 : :
786 : 20 : spdk_bs_open_blob(bs, snapshotid, blob_op_with_handle_complete, NULL);
787 : 20 : poll_threads();
788 : 20 : CU_ASSERT(g_bserrno == 0);
789 [ + + ]: 20 : SPDK_CU_ASSERT_FATAL(g_blob != NULL);
790 : 20 : snapshot = g_blob;
791 [ - + ]: 20 : CU_ASSERT(snapshot->data_ro == true);
792 [ - + ]: 20 : CU_ASSERT(snapshot->md_ro == true);
793 : 20 : CU_ASSERT(spdk_blob_get_num_clusters(snapshot) == 10);
794 : 20 : CU_ASSERT(spdk_blob_get_num_allocated_clusters(snapshot) == 10);
795 : :
796 : 20 : CU_ASSERT(spdk_blob_get_num_clusters(blob) == 10);
797 : 20 : CU_ASSERT(spdk_blob_get_num_allocated_clusters(blob) == 0);
798 : 20 : CU_ASSERT(blob->invalid_flags & SPDK_BLOB_THIN_PROV);
799 : 20 : CU_ASSERT(spdk_mem_all_zero(blob->active.clusters,
800 : : blob->active.num_clusters * sizeof(blob->active.clusters[0])));
801 : :
802 : : /* Try to create snapshot from clone with xattrs */
803 : 20 : xattrs.names = g_xattr_names;
804 : 20 : xattrs.get_value = _get_xattr_value;
805 : 20 : xattrs.count = 3;
806 : 20 : xattrs.ctx = &g_ctx;
807 : 20 : spdk_bs_create_snapshot(bs, blobid, &xattrs, blob_op_with_id_complete, NULL);
808 : 20 : poll_threads();
809 : 20 : CU_ASSERT(g_bserrno == 0);
810 : 20 : CU_ASSERT(g_blobid != SPDK_BLOBID_INVALID);
811 : 20 : CU_ASSERT_EQUAL(_get_snapshots_count(bs), 2);
812 : 20 : snapshotid2 = g_blobid;
813 : :
814 : 20 : spdk_bs_open_blob(bs, snapshotid2, blob_op_with_handle_complete, NULL);
815 : 20 : CU_ASSERT(g_bserrno == 0);
816 [ + + ]: 20 : SPDK_CU_ASSERT_FATAL(g_blob != NULL);
817 : 20 : snapshot2 = g_blob;
818 [ - + ]: 20 : CU_ASSERT(snapshot2->data_ro == true);
819 [ - + ]: 20 : CU_ASSERT(snapshot2->md_ro == true);
820 : 20 : CU_ASSERT(spdk_blob_get_num_clusters(snapshot2) == 10);
821 : 20 : CU_ASSERT(spdk_blob_get_num_allocated_clusters(snapshot2) == 0);
822 : :
823 : : /* Confirm that blob is backed by snapshot2 and snapshot2 is backed by snapshot */
824 : 20 : CU_ASSERT(snapshot->back_bs_dev == NULL);
825 [ + + ]: 20 : SPDK_CU_ASSERT_FATAL(blob->back_bs_dev != NULL);
826 [ + + ]: 20 : SPDK_CU_ASSERT_FATAL(snapshot2->back_bs_dev != NULL);
827 : :
828 : 20 : blob_bs_dev = (struct spdk_blob_bs_dev *)blob->back_bs_dev;
829 : 20 : CU_ASSERT(blob_bs_dev->blob == snapshot2);
830 : :
831 : 20 : blob_bs_dev = (struct spdk_blob_bs_dev *)snapshot2->back_bs_dev;
832 : 20 : CU_ASSERT(blob_bs_dev->blob == snapshot);
833 : :
834 : 20 : rc = spdk_blob_get_xattr_value(snapshot2, g_xattr_names[0], &value, &value_len);
835 : 20 : CU_ASSERT(rc == 0);
836 [ + + ]: 20 : SPDK_CU_ASSERT_FATAL(value != NULL);
837 [ - + ]: 20 : CU_ASSERT(value_len == strlen(g_xattr_values[0]));
838 [ - + - + ]: 20 : CU_ASSERT_NSTRING_EQUAL_FATAL(value, g_xattr_values[0], value_len);
839 : :
840 : 20 : rc = spdk_blob_get_xattr_value(snapshot2, g_xattr_names[1], &value, &value_len);
841 : 20 : CU_ASSERT(rc == 0);
842 [ + + ]: 20 : SPDK_CU_ASSERT_FATAL(value != NULL);
843 [ - + ]: 20 : CU_ASSERT(value_len == strlen(g_xattr_values[1]));
844 [ - + - + ]: 20 : CU_ASSERT_NSTRING_EQUAL((char *)value, g_xattr_values[1], value_len);
845 : :
846 : 20 : rc = spdk_blob_get_xattr_value(snapshot2, g_xattr_names[2], &value, &value_len);
847 : 20 : CU_ASSERT(rc == 0);
848 [ - + ]: 20 : SPDK_CU_ASSERT_FATAL(value != NULL);
849 [ - + ]: 20 : CU_ASSERT(value_len == strlen(g_xattr_values[2]));
850 [ - + - + ]: 20 : CU_ASSERT_NSTRING_EQUAL((char *)value, g_xattr_values[2], value_len);
851 : :
852 : : /* Confirm that blob is clone of snapshot2, and snapshot2 is clone of snapshot */
853 : 20 : count = 2;
854 : 20 : CU_ASSERT(spdk_blob_get_clones(bs, snapshotid2, ids, &count) == 0);
855 : 20 : CU_ASSERT(count == 1);
856 : 20 : CU_ASSERT(ids[0] == blobid);
857 : :
858 : 20 : count = 2;
859 : 20 : CU_ASSERT(spdk_blob_get_clones(bs, snapshotid, ids, &count) == 0);
860 : 20 : CU_ASSERT(count == 1);
861 : 20 : CU_ASSERT(ids[0] == snapshotid2);
862 : :
863 : : /* Try to create snapshot from snapshot */
864 : 20 : spdk_bs_create_snapshot(bs, snapshotid, NULL, blob_op_with_id_complete, NULL);
865 : 20 : poll_threads();
866 : 20 : CU_ASSERT(g_bserrno == -EINVAL);
867 : 20 : CU_ASSERT(g_blobid == SPDK_BLOBID_INVALID);
868 : 20 : CU_ASSERT_EQUAL(_get_snapshots_count(bs), 2);
869 : :
870 : : /* Delete blob and confirm that it is no longer on snapshot2 clone list */
871 : 20 : ut_blob_close_and_delete(bs, blob);
872 : 20 : count = 2;
873 : 20 : CU_ASSERT(spdk_blob_get_clones(bs, snapshotid2, ids, &count) == 0);
874 : 20 : CU_ASSERT(count == 0);
875 : :
876 : : /* Delete snapshot2 and confirm that it is no longer on snapshot clone list */
877 : 20 : ut_blob_close_and_delete(bs, snapshot2);
878 : 20 : CU_ASSERT_EQUAL(_get_snapshots_count(bs), 1);
879 : 20 : count = 2;
880 : 20 : CU_ASSERT(spdk_blob_get_clones(bs, snapshotid2, ids, &count) == 0);
881 : 20 : CU_ASSERT(count == 0);
882 : :
883 : 20 : ut_blob_close_and_delete(bs, snapshot);
884 : 20 : CU_ASSERT_EQUAL(_get_snapshots_count(bs), 0);
885 : 20 : }
886 : :
887 : : static void
888 : 20 : blob_snapshot_freeze_io(void)
889 : 15 : {
890 : : struct spdk_io_channel *channel;
891 : : struct spdk_bs_channel *bs_channel;
892 : 20 : struct spdk_blob_store *bs = g_bs;
893 : : struct spdk_blob *blob;
894 : 15 : struct spdk_blob_opts opts;
895 : : spdk_blob_id blobid;
896 : 20 : uint32_t num_of_pages = 10;
897 [ - + ]: 20 : uint8_t payload_read[num_of_pages * BLOCKLEN];
898 [ - + ]: 20 : uint8_t payload_write[num_of_pages * BLOCKLEN];
899 [ - + ]: 20 : uint8_t payload_zero[num_of_pages * BLOCKLEN];
900 : :
901 [ - + ]: 20 : memset(payload_write, 0xE5, sizeof(payload_write));
902 [ - + ]: 20 : memset(payload_read, 0x00, sizeof(payload_read));
903 [ - + ]: 20 : memset(payload_zero, 0x00, sizeof(payload_zero));
904 : :
905 : : /* Test freeze I/O during snapshot */
906 : 20 : channel = spdk_bs_alloc_io_channel(bs);
907 : 20 : bs_channel = spdk_io_channel_get_ctx(channel);
908 : :
909 : : /* Create blob with 10 clusters */
910 : 20 : ut_spdk_blob_opts_init(&opts);
911 : 20 : opts.num_clusters = 10;
912 : 20 : opts.thin_provision = false;
913 : :
914 : 20 : blob = ut_blob_create_and_open(bs, &opts);
915 : 20 : blobid = spdk_blob_get_id(blob);
916 : 20 : CU_ASSERT(spdk_blob_get_num_clusters(blob) == 10);
917 : :
918 : 20 : spdk_bs_create_snapshot(bs, blobid, NULL, blob_op_with_id_complete, NULL);
919 : :
920 : : /* This is implementation specific.
921 : : * Flag 'frozen_io' is set in _spdk_bs_snapshot_freeze_cpl callback.
922 : : * Four async I/O operations happen before that. */
923 : 20 : poll_thread_times(0, 5);
924 : :
925 : 20 : CU_ASSERT(TAILQ_EMPTY(&bs_channel->queued_io));
926 : :
927 : : /* Blob I/O should be frozen here */
928 : 20 : CU_ASSERT(blob->frozen_refcnt == 1);
929 : :
930 : : /* Write to the blob */
931 : 20 : spdk_blob_io_write(blob, channel, payload_write, 0, num_of_pages, blob_op_complete, NULL);
932 : :
933 : : /* Verify that I/O is queued */
934 : 20 : CU_ASSERT(!TAILQ_EMPTY(&bs_channel->queued_io));
935 : : /* Verify that payload is not written to disk, at this point the blobs already switched */
936 : 20 : CU_ASSERT(blob->active.clusters[0] == 0);
937 : :
938 : : /* Finish all operations including spdk_bs_create_snapshot */
939 : 20 : poll_threads();
940 : :
941 : : /* Verify snapshot */
942 : 20 : CU_ASSERT(g_bserrno == 0);
943 : 20 : CU_ASSERT(g_blobid != SPDK_BLOBID_INVALID);
944 : :
945 : : /* Verify that blob has unset frozen_io */
946 : 20 : CU_ASSERT(blob->frozen_refcnt == 0);
947 : :
948 : : /* Verify that postponed I/O completed successfully by comparing payload */
949 : 20 : spdk_blob_io_read(blob, channel, payload_read, 0, num_of_pages, blob_op_complete, NULL);
950 : 20 : poll_threads();
951 : 20 : CU_ASSERT(g_bserrno == 0);
952 [ - + - + ]: 20 : CU_ASSERT(memcmp(payload_write, payload_read, num_of_pages * BLOCKLEN) == 0);
953 : :
954 : 20 : spdk_bs_free_io_channel(channel);
955 : 20 : poll_threads();
956 : :
957 : 20 : ut_blob_close_and_delete(bs, blob);
958 : 20 : }
959 : :
960 : : static void
961 : 20 : blob_clone(void)
962 : : {
963 : 20 : struct spdk_blob_store *bs = g_bs;
964 : 15 : struct spdk_blob_opts opts;
965 : : struct spdk_blob *blob, *snapshot, *clone;
966 : : spdk_blob_id blobid, cloneid, snapshotid;
967 : 15 : struct spdk_blob_xattr_opts xattrs;
968 : 15 : const void *value;
969 : 15 : size_t value_len;
970 : : int rc;
971 : :
972 : : /* Create blob with 10 clusters */
973 : :
974 : 20 : ut_spdk_blob_opts_init(&opts);
975 : 20 : opts.num_clusters = 10;
976 : :
977 : 20 : blob = ut_blob_create_and_open(bs, &opts);
978 : 20 : blobid = spdk_blob_get_id(blob);
979 : 20 : CU_ASSERT(spdk_blob_get_num_clusters(blob) == 10);
980 : :
981 : : /* Create snapshot */
982 : 20 : spdk_bs_create_snapshot(bs, blobid, NULL, blob_op_with_id_complete, NULL);
983 : 20 : poll_threads();
984 : 20 : CU_ASSERT(g_bserrno == 0);
985 : 20 : CU_ASSERT(g_blobid != SPDK_BLOBID_INVALID);
986 : 20 : snapshotid = g_blobid;
987 : :
988 : 20 : spdk_bs_open_blob(bs, snapshotid, blob_op_with_handle_complete, NULL);
989 : 20 : poll_threads();
990 : 20 : CU_ASSERT(g_bserrno == 0);
991 [ + + ]: 20 : SPDK_CU_ASSERT_FATAL(g_blob != NULL);
992 : 20 : snapshot = g_blob;
993 [ - + ]: 20 : CU_ASSERT(snapshot->data_ro == true);
994 [ - + ]: 20 : CU_ASSERT(snapshot->md_ro == true);
995 : 20 : CU_ASSERT(spdk_blob_get_num_clusters(snapshot) == 10);
996 : :
997 : 20 : spdk_blob_close(snapshot, blob_op_complete, NULL);
998 : 20 : poll_threads();
999 : 20 : CU_ASSERT(g_bserrno == 0);
1000 : :
1001 : : /* Create clone from snapshot with xattrs */
1002 : 20 : xattrs.names = g_xattr_names;
1003 : 20 : xattrs.get_value = _get_xattr_value;
1004 : 20 : xattrs.count = 3;
1005 : 20 : xattrs.ctx = &g_ctx;
1006 : :
1007 : 20 : spdk_bs_create_clone(bs, snapshotid, &xattrs, blob_op_with_id_complete, NULL);
1008 : 20 : poll_threads();
1009 : 20 : CU_ASSERT(g_bserrno == 0);
1010 : 20 : CU_ASSERT(g_blobid != SPDK_BLOBID_INVALID);
1011 : 20 : cloneid = g_blobid;
1012 : :
1013 : 20 : spdk_bs_open_blob(bs, cloneid, blob_op_with_handle_complete, NULL);
1014 : 20 : poll_threads();
1015 : 20 : CU_ASSERT(g_bserrno == 0);
1016 [ + + ]: 20 : SPDK_CU_ASSERT_FATAL(g_blob != NULL);
1017 : 20 : clone = g_blob;
1018 [ - + ]: 20 : CU_ASSERT(clone->data_ro == false);
1019 [ - + ]: 20 : CU_ASSERT(clone->md_ro == false);
1020 : 20 : CU_ASSERT(spdk_blob_get_num_clusters(clone) == 10);
1021 : 20 : CU_ASSERT(spdk_blob_get_num_allocated_clusters(clone) == 0);
1022 : :
1023 : 20 : rc = spdk_blob_get_xattr_value(clone, g_xattr_names[0], &value, &value_len);
1024 : 20 : CU_ASSERT(rc == 0);
1025 [ + + ]: 20 : SPDK_CU_ASSERT_FATAL(value != NULL);
1026 [ - + ]: 20 : CU_ASSERT(value_len == strlen(g_xattr_values[0]));
1027 [ - + - + ]: 20 : CU_ASSERT_NSTRING_EQUAL_FATAL(value, g_xattr_values[0], value_len);
1028 : :
1029 : 20 : rc = spdk_blob_get_xattr_value(clone, g_xattr_names[1], &value, &value_len);
1030 : 20 : CU_ASSERT(rc == 0);
1031 [ + + ]: 20 : SPDK_CU_ASSERT_FATAL(value != NULL);
1032 [ - + ]: 20 : CU_ASSERT(value_len == strlen(g_xattr_values[1]));
1033 [ - + - + ]: 20 : CU_ASSERT_NSTRING_EQUAL((char *)value, g_xattr_values[1], value_len);
1034 : :
1035 : 20 : rc = spdk_blob_get_xattr_value(clone, g_xattr_names[2], &value, &value_len);
1036 : 20 : CU_ASSERT(rc == 0);
1037 [ + + ]: 20 : SPDK_CU_ASSERT_FATAL(value != NULL);
1038 [ - + ]: 20 : CU_ASSERT(value_len == strlen(g_xattr_values[2]));
1039 [ - + - + ]: 20 : CU_ASSERT_NSTRING_EQUAL((char *)value, g_xattr_values[2], value_len);
1040 : :
1041 : :
1042 : 20 : spdk_blob_close(clone, blob_op_complete, NULL);
1043 : 20 : poll_threads();
1044 : 20 : CU_ASSERT(g_bserrno == 0);
1045 : :
1046 : : /* Try to create clone from not read only blob */
1047 : 20 : spdk_bs_create_clone(bs, blobid, NULL, blob_op_with_id_complete, NULL);
1048 : 20 : poll_threads();
1049 : 20 : CU_ASSERT(g_bserrno == -EINVAL);
1050 : 20 : CU_ASSERT(g_blobid == SPDK_BLOBID_INVALID);
1051 : :
1052 : : /* Mark blob as read only */
1053 : 20 : spdk_blob_set_read_only(blob);
1054 : 20 : spdk_blob_sync_md(blob, blob_op_complete, NULL);
1055 : 20 : poll_threads();
1056 : 20 : CU_ASSERT(g_bserrno == 0);
1057 : :
1058 : : /* Create clone from read only blob */
1059 : 20 : spdk_bs_create_clone(bs, blobid, NULL, blob_op_with_id_complete, NULL);
1060 : 20 : poll_threads();
1061 : 20 : CU_ASSERT(g_bserrno == 0);
1062 : 20 : CU_ASSERT(g_blobid != SPDK_BLOBID_INVALID);
1063 : 20 : cloneid = g_blobid;
1064 : :
1065 : 20 : spdk_bs_open_blob(bs, cloneid, blob_op_with_handle_complete, NULL);
1066 : 20 : poll_threads();
1067 : 20 : CU_ASSERT(g_bserrno == 0);
1068 [ - + ]: 20 : SPDK_CU_ASSERT_FATAL(g_blob != NULL);
1069 : 20 : clone = g_blob;
1070 [ - + ]: 20 : CU_ASSERT(clone->data_ro == false);
1071 [ - + ]: 20 : CU_ASSERT(clone->md_ro == false);
1072 : 20 : CU_ASSERT(spdk_blob_get_num_clusters(clone) == 10);
1073 : :
1074 : 20 : ut_blob_close_and_delete(bs, clone);
1075 : 20 : ut_blob_close_and_delete(bs, blob);
1076 : 20 : }
1077 : :
1078 : : static void
1079 : 40 : _blob_inflate(bool decouple_parent)
1080 : : {
1081 : 40 : struct spdk_blob_store *bs = g_bs;
1082 : 30 : struct spdk_blob_opts opts;
1083 : : struct spdk_blob *blob, *snapshot;
1084 : : spdk_blob_id blobid, snapshotid;
1085 : : struct spdk_io_channel *channel;
1086 : : uint64_t free_clusters;
1087 : :
1088 : 40 : channel = spdk_bs_alloc_io_channel(bs);
1089 [ + + ]: 40 : SPDK_CU_ASSERT_FATAL(channel != NULL);
1090 : :
1091 : : /* Create blob with 10 clusters */
1092 : :
1093 : 40 : ut_spdk_blob_opts_init(&opts);
1094 : 40 : opts.num_clusters = 10;
1095 : 40 : opts.thin_provision = true;
1096 : :
1097 : 40 : blob = ut_blob_create_and_open(bs, &opts);
1098 : 40 : blobid = spdk_blob_get_id(blob);
1099 : 40 : CU_ASSERT(spdk_blob_get_num_clusters(blob) == 10);
1100 : 40 : CU_ASSERT(spdk_blob_is_thin_provisioned(blob) == true);
1101 : 40 : CU_ASSERT(spdk_blob_get_num_allocated_clusters(blob) == 0);
1102 : :
1103 : : /* 1) Blob with no parent */
1104 [ + + ]: 40 : if (decouple_parent) {
1105 : : /* Decouple parent of blob with no parent (should fail) */
1106 : 20 : spdk_bs_blob_decouple_parent(bs, channel, blobid, blob_op_complete, NULL);
1107 : 20 : poll_threads();
1108 : 20 : CU_ASSERT(g_bserrno != 0);
1109 : 5 : } else {
1110 : : /* Inflate of thin blob with no parent should made it thick */
1111 : 20 : spdk_bs_inflate_blob(bs, channel, blobid, blob_op_complete, NULL);
1112 : 20 : poll_threads();
1113 : 20 : CU_ASSERT(g_bserrno == 0);
1114 : 20 : CU_ASSERT(spdk_blob_is_thin_provisioned(blob) == false);
1115 : 20 : CU_ASSERT(spdk_blob_get_num_allocated_clusters(blob) == 10);
1116 : : }
1117 : :
1118 : 40 : spdk_bs_create_snapshot(bs, blobid, NULL, blob_op_with_id_complete, NULL);
1119 : 40 : poll_threads();
1120 : 40 : CU_ASSERT(g_bserrno == 0);
1121 : 40 : CU_ASSERT(g_blobid != SPDK_BLOBID_INVALID);
1122 : 40 : snapshotid = g_blobid;
1123 : :
1124 : 40 : CU_ASSERT(spdk_blob_is_thin_provisioned(blob) == true);
1125 : 40 : CU_ASSERT(spdk_blob_get_num_clusters(blob) == 10);
1126 : :
1127 : 40 : spdk_bs_open_blob(bs, snapshotid, blob_op_with_handle_complete, NULL);
1128 : 40 : poll_threads();
1129 : 40 : CU_ASSERT(g_bserrno == 0);
1130 [ - + ]: 40 : SPDK_CU_ASSERT_FATAL(g_blob != NULL);
1131 : 40 : snapshot = g_blob;
1132 [ - + ]: 40 : CU_ASSERT(snapshot->data_ro == true);
1133 [ - + ]: 40 : CU_ASSERT(snapshot->md_ro == true);
1134 : 40 : CU_ASSERT(spdk_blob_get_num_clusters(snapshot) == 10);
1135 : :
1136 : 40 : spdk_blob_close(snapshot, blob_op_complete, NULL);
1137 : 40 : poll_threads();
1138 : 40 : CU_ASSERT(g_bserrno == 0);
1139 : :
1140 : 40 : free_clusters = spdk_bs_free_cluster_count(bs);
1141 : :
1142 : : /* 2) Blob with parent */
1143 [ + + ]: 40 : if (!decouple_parent) {
1144 : : /* Do full blob inflation */
1145 : 20 : spdk_bs_inflate_blob(bs, channel, blobid, blob_op_complete, NULL);
1146 : 20 : poll_threads();
1147 : 20 : CU_ASSERT(g_bserrno == 0);
1148 : : /* all 10 clusters should be allocated */
1149 : 20 : CU_ASSERT(spdk_bs_free_cluster_count(bs) == free_clusters - 10);
1150 : 20 : CU_ASSERT(spdk_blob_get_num_allocated_clusters(blob) == 10);
1151 : 5 : } else {
1152 : : /* Decouple parent of blob */
1153 : 20 : spdk_bs_blob_decouple_parent(bs, channel, blobid, blob_op_complete, NULL);
1154 : 20 : poll_threads();
1155 : 20 : CU_ASSERT(g_bserrno == 0);
1156 : : /* when only parent is removed, none of the clusters should be allocated */
1157 : 20 : CU_ASSERT(spdk_bs_free_cluster_count(bs) == free_clusters);
1158 : 20 : CU_ASSERT(spdk_blob_get_num_allocated_clusters(blob) == 0);
1159 : : }
1160 : :
1161 : : /* Now, it should be possible to delete snapshot */
1162 : 40 : spdk_bs_delete_blob(bs, snapshotid, blob_op_complete, NULL);
1163 : 40 : poll_threads();
1164 : 40 : CU_ASSERT(g_bserrno == 0);
1165 : :
1166 : 40 : CU_ASSERT(spdk_blob_get_num_clusters(blob) == 10);
1167 : 40 : CU_ASSERT(spdk_blob_is_thin_provisioned(blob) == decouple_parent);
1168 : :
1169 : 40 : spdk_bs_free_io_channel(channel);
1170 : 40 : poll_threads();
1171 : :
1172 : 40 : ut_blob_close_and_delete(bs, blob);
1173 : 40 : }
1174 : :
1175 : : static void
1176 : 20 : blob_inflate(void)
1177 : : {
1178 : 20 : _blob_inflate(false);
1179 : 20 : _blob_inflate(true);
1180 : 20 : }
1181 : :
1182 : : static void
1183 : 20 : blob_delete(void)
1184 : : {
1185 : 20 : struct spdk_blob_store *bs = g_bs;
1186 : 15 : struct spdk_blob_opts blob_opts;
1187 : : spdk_blob_id blobid;
1188 : :
1189 : : /* Create a blob and then delete it. */
1190 : 20 : ut_spdk_blob_opts_init(&blob_opts);
1191 : 20 : spdk_bs_create_blob_ext(bs, &blob_opts, blob_op_with_id_complete, NULL);
1192 : 20 : poll_threads();
1193 : 20 : CU_ASSERT(g_bserrno == 0);
1194 : 20 : CU_ASSERT(g_blobid > 0);
1195 : 20 : blobid = g_blobid;
1196 : :
1197 : 20 : spdk_bs_delete_blob(bs, blobid, blob_op_complete, NULL);
1198 : 20 : poll_threads();
1199 : 20 : CU_ASSERT(g_bserrno == 0);
1200 : :
1201 : : /* Try to open the blob */
1202 : 20 : spdk_bs_open_blob(bs, blobid, blob_op_with_handle_complete, NULL);
1203 : 20 : poll_threads();
1204 : 20 : CU_ASSERT(g_bserrno == -ENOENT);
1205 : 20 : }
1206 : :
1207 : : static void
1208 : 20 : blob_resize_test(void)
1209 : : {
1210 : 20 : struct spdk_blob_store *bs = g_bs;
1211 : : struct spdk_blob *blob;
1212 : : uint64_t free_clusters;
1213 : :
1214 : 20 : free_clusters = spdk_bs_free_cluster_count(bs);
1215 : :
1216 : 20 : blob = ut_blob_create_and_open(bs, NULL);
1217 : 20 : CU_ASSERT(free_clusters == spdk_bs_free_cluster_count(bs));
1218 : 20 : CU_ASSERT(spdk_blob_get_num_allocated_clusters(blob) == 0);
1219 : :
1220 : : /* Confirm that resize fails if blob is marked read-only. */
1221 : 20 : blob->md_ro = true;
1222 : 20 : spdk_blob_resize(blob, 5, blob_op_complete, NULL);
1223 : 20 : poll_threads();
1224 : 20 : CU_ASSERT(g_bserrno == -EPERM);
1225 : 20 : blob->md_ro = false;
1226 : :
1227 : : /* The blob started at 0 clusters. Resize it to be 5. */
1228 : 20 : spdk_blob_resize(blob, 5, blob_op_complete, NULL);
1229 : 20 : poll_threads();
1230 : 20 : CU_ASSERT(g_bserrno == 0);
1231 : 20 : CU_ASSERT((free_clusters - 5) == spdk_bs_free_cluster_count(bs));
1232 : 20 : CU_ASSERT(spdk_blob_get_num_allocated_clusters(blob) == 5);
1233 : :
1234 : : /* Shrink the blob to 3 clusters. This will not actually release
1235 : : * the old clusters until the blob is synced.
1236 : : */
1237 : 20 : spdk_blob_resize(blob, 3, blob_op_complete, NULL);
1238 : 20 : poll_threads();
1239 : 20 : CU_ASSERT(g_bserrno == 0);
1240 : : /* Verify there are still 5 clusters in use */
1241 : 20 : CU_ASSERT((free_clusters - 5) == spdk_bs_free_cluster_count(bs));
1242 : 20 : CU_ASSERT(spdk_blob_get_num_allocated_clusters(blob) == 3);
1243 : :
1244 : 20 : spdk_blob_sync_md(blob, blob_op_complete, NULL);
1245 : 20 : poll_threads();
1246 : 20 : CU_ASSERT(g_bserrno == 0);
1247 : : /* Now there are only 3 clusters in use */
1248 : 20 : CU_ASSERT((free_clusters - 3) == spdk_bs_free_cluster_count(bs));
1249 : :
1250 : : /* Resize the blob to be 10 clusters. Growth takes effect immediately. */
1251 : 20 : spdk_blob_resize(blob, 10, blob_op_complete, NULL);
1252 : 20 : poll_threads();
1253 : 20 : CU_ASSERT(g_bserrno == 0);
1254 : 20 : CU_ASSERT((free_clusters - 10) == spdk_bs_free_cluster_count(bs));
1255 : 20 : CU_ASSERT(spdk_blob_get_num_allocated_clusters(blob) == 10);
1256 : :
1257 : : /* Try to resize the blob to size larger than blobstore. */
1258 : 20 : spdk_blob_resize(blob, bs->total_clusters + 1, blob_op_complete, NULL);
1259 : 20 : poll_threads();
1260 : 20 : CU_ASSERT(g_bserrno == -ENOSPC);
1261 : :
1262 : 20 : ut_blob_close_and_delete(bs, blob);
1263 : 20 : }
1264 : :
1265 : : static void
1266 : 20 : blob_resize_thin_test(void)
1267 : : {
1268 : 20 : struct spdk_blob_store *bs = g_bs;
1269 : : struct spdk_blob *blob;
1270 : 15 : struct spdk_blob_opts opts;
1271 : : struct spdk_io_channel *blob_ch;
1272 : : uint64_t free_clusters;
1273 : : uint64_t io_units_per_cluster;
1274 : : uint64_t offset;
1275 : 15 : uint8_t buf1[DEV_BUFFER_BLOCKLEN];
1276 : :
1277 : 20 : free_clusters = spdk_bs_free_cluster_count(bs);
1278 : :
1279 : 20 : blob_ch = spdk_bs_alloc_io_channel(bs);
1280 [ + + ]: 20 : SPDK_CU_ASSERT_FATAL(blob_ch != NULL);
1281 : :
1282 : : /* Create blob with thin provisioning enabled */
1283 : 20 : ut_spdk_blob_opts_init(&opts);
1284 : 20 : opts.thin_provision = true;
1285 : 20 : opts.num_clusters = 0;
1286 : :
1287 : 20 : blob = ut_blob_create_and_open(bs, &opts);
1288 : 20 : CU_ASSERT((free_clusters) == spdk_bs_free_cluster_count(bs));
1289 : 20 : CU_ASSERT(spdk_blob_get_num_allocated_clusters(blob) == 0);
1290 : 20 : io_units_per_cluster = bs_io_units_per_cluster(blob);
1291 : :
1292 : : /* The blob started at 0 clusters. Resize it to be 6. */
1293 : 20 : spdk_blob_resize(blob, 6, blob_op_complete, NULL);
1294 : 20 : poll_threads();
1295 : 20 : CU_ASSERT(g_bserrno == 0);
1296 : 20 : CU_ASSERT((free_clusters) == spdk_bs_free_cluster_count(bs));
1297 : 20 : CU_ASSERT(spdk_blob_get_num_allocated_clusters(blob) == 0);
1298 : :
1299 : : /* Write on cluster 0,2,4 and 5 of blob */
1300 [ + + ]: 5140 : for (offset = 0; offset < io_units_per_cluster; offset++) {
1301 : 5120 : spdk_blob_io_write(blob, blob_ch, buf1, offset, 1, blob_op_complete, NULL);
1302 : 5120 : poll_threads();
1303 : 5120 : CU_ASSERT(g_bserrno == 0);
1304 : 1280 : }
1305 [ + + ]: 5140 : for (offset = 2 * io_units_per_cluster; offset < 3 * io_units_per_cluster; offset++) {
1306 : 5120 : spdk_blob_io_write(blob, blob_ch, buf1, offset, 1, blob_op_complete, NULL);
1307 : 5120 : poll_threads();
1308 : 5120 : CU_ASSERT(g_bserrno == 0);
1309 : 1280 : }
1310 [ + + ]: 5140 : for (offset = 4 * io_units_per_cluster; offset < 5 * io_units_per_cluster; offset++) {
1311 : 5120 : spdk_blob_io_write(blob, blob_ch, buf1, offset, 1, blob_op_complete, NULL);
1312 : 5120 : poll_threads();
1313 : 5120 : CU_ASSERT(g_bserrno == 0);
1314 : 1280 : }
1315 [ + + ]: 5140 : for (offset = 5 * io_units_per_cluster; offset < 6 * io_units_per_cluster; offset++) {
1316 : 5120 : spdk_blob_io_write(blob, blob_ch, buf1, offset, 1, blob_op_complete, NULL);
1317 : 5120 : poll_threads();
1318 : 5120 : CU_ASSERT(g_bserrno == 0);
1319 : 1280 : }
1320 : :
1321 : : /* Check allocated clusters after write */
1322 : 20 : CU_ASSERT((free_clusters - 4) == spdk_bs_free_cluster_count(bs));
1323 : 20 : CU_ASSERT(spdk_blob_get_num_allocated_clusters(blob) == 4);
1324 : :
1325 : : /* Shrink the blob to 2 clusters. This will not actually release
1326 : : * the old clusters until the blob is synced.
1327 : : */
1328 : 20 : spdk_blob_resize(blob, 2, blob_op_complete, NULL);
1329 : 20 : poll_threads();
1330 : 20 : CU_ASSERT(g_bserrno == 0);
1331 : 20 : CU_ASSERT(spdk_blob_get_num_clusters(blob) == 2);
1332 : 20 : CU_ASSERT((free_clusters - 4) == spdk_bs_free_cluster_count(bs));
1333 : 20 : CU_ASSERT(spdk_blob_get_num_allocated_clusters(blob) == 1);
1334 : :
1335 : : /* Sync blob: 4 clusters were truncated but only 3 of them was allocated */
1336 : 20 : spdk_blob_sync_md(blob, blob_op_complete, NULL);
1337 : 20 : poll_threads();
1338 : 20 : CU_ASSERT(g_bserrno == 0);
1339 : 20 : CU_ASSERT((free_clusters - 1) == spdk_bs_free_cluster_count(bs));
1340 : 20 : CU_ASSERT(spdk_blob_get_num_clusters(blob) == 2);
1341 : 20 : CU_ASSERT(spdk_blob_get_num_allocated_clusters(blob) == 1);
1342 : :
1343 : 20 : spdk_bs_free_io_channel(blob_ch);
1344 : 20 : ut_blob_close_and_delete(bs, blob);
1345 : 20 : }
1346 : :
1347 : : static void
1348 : 20 : blob_read_only(void)
1349 : : {
1350 : 15 : struct spdk_blob_store *bs;
1351 : : struct spdk_bs_dev *dev;
1352 : : struct spdk_blob *blob;
1353 : 15 : struct spdk_bs_opts opts;
1354 : : spdk_blob_id blobid;
1355 : : int rc;
1356 : :
1357 : 20 : dev = init_dev();
1358 : 20 : spdk_bs_opts_init(&opts, sizeof(opts));
1359 [ - + ]: 20 : snprintf(opts.bstype.bstype, sizeof(opts.bstype.bstype), "TESTTYPE");
1360 : :
1361 : 20 : spdk_bs_init(dev, &opts, bs_op_with_handle_complete, NULL);
1362 : 20 : poll_threads();
1363 : 20 : CU_ASSERT(g_bserrno == 0);
1364 [ + + ]: 20 : SPDK_CU_ASSERT_FATAL(g_bs != NULL);
1365 : 20 : bs = g_bs;
1366 : :
1367 : 20 : blob = ut_blob_create_and_open(bs, NULL);
1368 : 20 : blobid = spdk_blob_get_id(blob);
1369 : :
1370 : 20 : rc = spdk_blob_set_read_only(blob);
1371 : 20 : CU_ASSERT(rc == 0);
1372 : :
1373 [ - + ]: 20 : CU_ASSERT(blob->data_ro == false);
1374 [ - + ]: 20 : CU_ASSERT(blob->md_ro == false);
1375 : :
1376 : 20 : spdk_blob_sync_md(blob, bs_op_complete, NULL);
1377 : 20 : poll_threads();
1378 : :
1379 [ - + ]: 20 : CU_ASSERT(blob->data_ro == true);
1380 [ - + ]: 20 : CU_ASSERT(blob->md_ro == true);
1381 : 20 : CU_ASSERT(blob->data_ro_flags & SPDK_BLOB_READ_ONLY);
1382 : :
1383 : 20 : spdk_blob_close(blob, blob_op_complete, NULL);
1384 : 20 : poll_threads();
1385 : 20 : CU_ASSERT(g_bserrno == 0);
1386 : :
1387 : 20 : spdk_bs_open_blob(bs, blobid, blob_op_with_handle_complete, NULL);
1388 : 20 : poll_threads();
1389 : 20 : CU_ASSERT(g_bserrno == 0);
1390 [ + + ]: 20 : SPDK_CU_ASSERT_FATAL(g_blob != NULL);
1391 : 20 : blob = g_blob;
1392 : :
1393 [ - + ]: 20 : CU_ASSERT(blob->data_ro == true);
1394 [ - + ]: 20 : CU_ASSERT(blob->md_ro == true);
1395 : 20 : CU_ASSERT(blob->data_ro_flags & SPDK_BLOB_READ_ONLY);
1396 : :
1397 : 20 : spdk_blob_close(blob, blob_op_complete, NULL);
1398 : 20 : poll_threads();
1399 : 20 : CU_ASSERT(g_bserrno == 0);
1400 : :
1401 : 20 : ut_bs_reload(&bs, &opts);
1402 : :
1403 : 20 : spdk_bs_open_blob(bs, blobid, blob_op_with_handle_complete, NULL);
1404 : 20 : poll_threads();
1405 : 20 : CU_ASSERT(g_bserrno == 0);
1406 [ - + ]: 20 : SPDK_CU_ASSERT_FATAL(g_blob != NULL);
1407 : 20 : blob = g_blob;
1408 : :
1409 [ - + ]: 20 : CU_ASSERT(blob->data_ro == true);
1410 [ - + ]: 20 : CU_ASSERT(blob->md_ro == true);
1411 : 20 : CU_ASSERT(blob->data_ro_flags & SPDK_BLOB_READ_ONLY);
1412 : :
1413 : 20 : ut_blob_close_and_delete(bs, blob);
1414 : :
1415 : 20 : spdk_bs_unload(bs, bs_op_complete, NULL);
1416 : 20 : poll_threads();
1417 : 20 : CU_ASSERT(g_bserrno == 0);
1418 : 20 : }
1419 : :
1420 : : static void
1421 : 20 : channel_ops(void)
1422 : : {
1423 : 20 : struct spdk_blob_store *bs = g_bs;
1424 : : struct spdk_io_channel *channel;
1425 : :
1426 : 20 : channel = spdk_bs_alloc_io_channel(bs);
1427 : 20 : CU_ASSERT(channel != NULL);
1428 : :
1429 : 20 : spdk_bs_free_io_channel(channel);
1430 : 20 : poll_threads();
1431 : 20 : }
1432 : :
1433 : : static void
1434 : 20 : blob_write(void)
1435 : : {
1436 : 20 : struct spdk_blob_store *bs = g_bs;
1437 : 20 : struct spdk_blob *blob = g_blob;
1438 : : struct spdk_io_channel *channel;
1439 : : uint64_t io_units_per_cluster;
1440 : 15 : uint8_t payload[10 * BLOCKLEN];
1441 : :
1442 [ - + ]: 20 : io_units_per_cluster = spdk_bs_get_cluster_size(bs) / spdk_bs_get_io_unit_size(bs);
1443 : :
1444 : 20 : channel = spdk_bs_alloc_io_channel(bs);
1445 : 20 : CU_ASSERT(channel != NULL);
1446 : :
1447 : : /* Write to a blob with 0 size */
1448 : 20 : spdk_blob_io_write(blob, channel, payload, 0, 1, blob_op_complete, NULL);
1449 : 20 : poll_threads();
1450 : 20 : CU_ASSERT(g_bserrno == -EINVAL);
1451 : :
1452 : : /* Resize the blob */
1453 : 20 : spdk_blob_resize(blob, 5, blob_op_complete, NULL);
1454 : 20 : poll_threads();
1455 : 20 : CU_ASSERT(g_bserrno == 0);
1456 : :
1457 : : /* Confirm that write fails if blob is marked read-only. */
1458 : 20 : blob->data_ro = true;
1459 : 20 : spdk_blob_io_write(blob, channel, payload, 0, 1, blob_op_complete, NULL);
1460 : 20 : poll_threads();
1461 : 20 : CU_ASSERT(g_bserrno == -EPERM);
1462 : 20 : blob->data_ro = false;
1463 : :
1464 : : /* Write to the blob */
1465 : 20 : spdk_blob_io_write(blob, channel, payload, 0, 1, blob_op_complete, NULL);
1466 : 20 : poll_threads();
1467 : 20 : CU_ASSERT(g_bserrno == 0);
1468 : :
1469 : : /* Write starting beyond the end */
1470 : 20 : spdk_blob_io_write(blob, channel, payload, 5 * io_units_per_cluster, 1, blob_op_complete,
1471 : : NULL);
1472 : 20 : poll_threads();
1473 : 20 : CU_ASSERT(g_bserrno == -EINVAL);
1474 : :
1475 : : /* Write starting at a valid location but going off the end */
1476 : 20 : spdk_blob_io_write(blob, channel, payload, 4 * io_units_per_cluster, io_units_per_cluster + 1,
1477 : : blob_op_complete, NULL);
1478 : 20 : poll_threads();
1479 : 20 : CU_ASSERT(g_bserrno == -EINVAL);
1480 : :
1481 : 20 : spdk_bs_free_io_channel(channel);
1482 : 20 : poll_threads();
1483 : 20 : }
1484 : :
1485 : : static void
1486 : 20 : blob_read(void)
1487 : : {
1488 : 20 : struct spdk_blob_store *bs = g_bs;
1489 : 20 : struct spdk_blob *blob = g_blob;
1490 : : struct spdk_io_channel *channel;
1491 : : uint64_t io_units_per_cluster;
1492 : 15 : uint8_t payload[10 * BLOCKLEN];
1493 : :
1494 [ - + ]: 20 : io_units_per_cluster = spdk_bs_get_cluster_size(bs) / spdk_bs_get_io_unit_size(bs);
1495 : :
1496 : 20 : channel = spdk_bs_alloc_io_channel(bs);
1497 : 20 : CU_ASSERT(channel != NULL);
1498 : :
1499 : : /* Read from a blob with 0 size */
1500 : 20 : spdk_blob_io_read(blob, channel, payload, 0, 1, blob_op_complete, NULL);
1501 : 20 : poll_threads();
1502 : 20 : CU_ASSERT(g_bserrno == -EINVAL);
1503 : :
1504 : : /* Resize the blob */
1505 : 20 : spdk_blob_resize(blob, 5, blob_op_complete, NULL);
1506 : 20 : poll_threads();
1507 : 20 : CU_ASSERT(g_bserrno == 0);
1508 : :
1509 : : /* Confirm that read passes if blob is marked read-only. */
1510 : 20 : blob->data_ro = true;
1511 : 20 : spdk_blob_io_read(blob, channel, payload, 0, 1, blob_op_complete, NULL);
1512 : 20 : poll_threads();
1513 : 20 : CU_ASSERT(g_bserrno == 0);
1514 : 20 : blob->data_ro = false;
1515 : :
1516 : : /* Read from the blob */
1517 : 20 : spdk_blob_io_read(blob, channel, payload, 0, 1, blob_op_complete, NULL);
1518 : 20 : poll_threads();
1519 : 20 : CU_ASSERT(g_bserrno == 0);
1520 : :
1521 : : /* Read starting beyond the end */
1522 : 20 : spdk_blob_io_read(blob, channel, payload, 5 * io_units_per_cluster, 1, blob_op_complete,
1523 : : NULL);
1524 : 20 : poll_threads();
1525 : 20 : CU_ASSERT(g_bserrno == -EINVAL);
1526 : :
1527 : : /* Read starting at a valid location but going off the end */
1528 : 20 : spdk_blob_io_read(blob, channel, payload, 4 * io_units_per_cluster, io_units_per_cluster + 1,
1529 : : blob_op_complete, NULL);
1530 : 20 : poll_threads();
1531 : 20 : CU_ASSERT(g_bserrno == -EINVAL);
1532 : :
1533 : 20 : spdk_bs_free_io_channel(channel);
1534 : 20 : poll_threads();
1535 : 20 : }
1536 : :
1537 : : static void
1538 : 20 : blob_rw_verify(void)
1539 : : {
1540 : 20 : struct spdk_blob_store *bs = g_bs;
1541 : 20 : struct spdk_blob *blob = g_blob;
1542 : : struct spdk_io_channel *channel;
1543 : 15 : uint8_t payload_read[10 * BLOCKLEN];
1544 : 15 : uint8_t payload_write[10 * BLOCKLEN];
1545 : :
1546 : 20 : channel = spdk_bs_alloc_io_channel(bs);
1547 : 20 : CU_ASSERT(channel != NULL);
1548 : :
1549 : 20 : spdk_blob_resize(blob, 32, blob_op_complete, NULL);
1550 : 20 : poll_threads();
1551 : 20 : CU_ASSERT(g_bserrno == 0);
1552 : :
1553 : 20 : memset(payload_write, 0xE5, sizeof(payload_write));
1554 : 20 : spdk_blob_io_write(blob, channel, payload_write, 4, 10, blob_op_complete, NULL);
1555 : 20 : poll_threads();
1556 : 20 : CU_ASSERT(g_bserrno == 0);
1557 : :
1558 : 20 : memset(payload_read, 0x00, sizeof(payload_read));
1559 : 20 : spdk_blob_io_read(blob, channel, payload_read, 4, 10, blob_op_complete, NULL);
1560 : 20 : poll_threads();
1561 : 20 : CU_ASSERT(g_bserrno == 0);
1562 : 20 : CU_ASSERT(memcmp(payload_write, payload_read, 4 * BLOCKLEN) == 0);
1563 : :
1564 : 20 : spdk_bs_free_io_channel(channel);
1565 : 20 : poll_threads();
1566 : 20 : }
1567 : :
1568 : : static void
1569 : 20 : blob_rw_verify_iov(void)
1570 : : {
1571 : 20 : struct spdk_blob_store *bs = g_bs;
1572 : : struct spdk_blob *blob;
1573 : : struct spdk_io_channel *channel;
1574 : 15 : uint8_t payload_read[10 * BLOCKLEN];
1575 : 15 : uint8_t payload_write[10 * BLOCKLEN];
1576 : 15 : struct iovec iov_read[3];
1577 : 15 : struct iovec iov_write[3];
1578 : : void *buf;
1579 [ - + ]: 20 : uint32_t first_data_cluster = FIRST_DATA_CLUSTER(bs);
1580 : :
1581 : 20 : channel = spdk_bs_alloc_io_channel(bs);
1582 : 20 : CU_ASSERT(channel != NULL);
1583 : :
1584 : 20 : blob = ut_blob_create_and_open(bs, NULL);
1585 : :
1586 : 20 : spdk_blob_resize(blob, 2, blob_op_complete, NULL);
1587 : 20 : poll_threads();
1588 : 20 : CU_ASSERT(g_bserrno == 0);
1589 : :
1590 : : /*
1591 : : * Manually adjust the offset of the blob's second cluster. This allows
1592 : : * us to make sure that the readv/write code correctly accounts for I/O
1593 : : * that cross cluster boundaries. Start by asserting that the allocated
1594 : : * clusters are where we expect before modifying the second cluster.
1595 : : */
1596 : 20 : CU_ASSERT(blob->active.clusters[0] == first_data_cluster * 256);
1597 : 20 : CU_ASSERT(blob->active.clusters[1] == (first_data_cluster + 1) * 256);
1598 : 20 : blob->active.clusters[1] = (first_data_cluster + 2) * 256;
1599 : :
1600 : 20 : memset(payload_write, 0xE5, sizeof(payload_write));
1601 : 20 : iov_write[0].iov_base = payload_write;
1602 : 20 : iov_write[0].iov_len = 1 * BLOCKLEN;
1603 : 20 : iov_write[1].iov_base = payload_write + 1 * BLOCKLEN;
1604 : 20 : iov_write[1].iov_len = 5 * BLOCKLEN;
1605 : 20 : iov_write[2].iov_base = payload_write + 6 * BLOCKLEN;
1606 : 20 : iov_write[2].iov_len = 4 * BLOCKLEN;
1607 : : /*
1608 : : * Choose a page offset just before the cluster boundary. The first 6 pages of payload
1609 : : * will get written to the first cluster, the last 4 to the second cluster.
1610 : : */
1611 : 20 : spdk_blob_io_writev(blob, channel, iov_write, 3, 250, 10, blob_op_complete, NULL);
1612 : 20 : poll_threads();
1613 : 20 : CU_ASSERT(g_bserrno == 0);
1614 : :
1615 : 20 : memset(payload_read, 0xAA, sizeof(payload_read));
1616 : 20 : iov_read[0].iov_base = payload_read;
1617 : 20 : iov_read[0].iov_len = 3 * BLOCKLEN;
1618 : 20 : iov_read[1].iov_base = payload_read + 3 * BLOCKLEN;
1619 : 20 : iov_read[1].iov_len = 4 * BLOCKLEN;
1620 : 20 : iov_read[2].iov_base = payload_read + 7 * BLOCKLEN;
1621 : 20 : iov_read[2].iov_len = 3 * BLOCKLEN;
1622 : 20 : spdk_blob_io_readv(blob, channel, iov_read, 3, 250, 10, blob_op_complete, NULL);
1623 : 20 : poll_threads();
1624 : 20 : CU_ASSERT(g_bserrno == 0);
1625 : 20 : CU_ASSERT(memcmp(payload_write, payload_read, 10 * BLOCKLEN) == 0);
1626 : :
1627 : 20 : buf = calloc(1, 256 * BLOCKLEN);
1628 [ + + ]: 20 : SPDK_CU_ASSERT_FATAL(buf != NULL);
1629 : : /* Check that cluster 2 on "disk" was not modified. */
1630 [ - + - + ]: 20 : CU_ASSERT(memcmp(buf, &g_dev_buffer[(first_data_cluster + 1) * 256 * BLOCKLEN],
1631 : : 256 * BLOCKLEN) == 0);
1632 : 20 : free(buf);
1633 : :
1634 : 20 : spdk_blob_close(blob, blob_op_complete, NULL);
1635 : 20 : poll_threads();
1636 : 20 : CU_ASSERT(g_bserrno == 0);
1637 : :
1638 : 20 : spdk_bs_free_io_channel(channel);
1639 : 20 : poll_threads();
1640 : 20 : }
1641 : :
1642 : : static uint32_t
1643 : 40 : bs_channel_get_req_count(struct spdk_io_channel *_channel)
1644 : : {
1645 : 40 : struct spdk_bs_channel *channel = spdk_io_channel_get_ctx(_channel);
1646 : : struct spdk_bs_request_set *set;
1647 : 40 : uint32_t count = 0;
1648 : :
1649 [ + + ]: 20520 : TAILQ_FOREACH(set, &channel->reqs, link) {
1650 : 20480 : count++;
1651 : 5120 : }
1652 : :
1653 : 40 : return count;
1654 : : }
1655 : :
1656 : : static void
1657 : 20 : blob_rw_verify_iov_nomem(void)
1658 : : {
1659 : 20 : struct spdk_blob_store *bs = g_bs;
1660 : 20 : struct spdk_blob *blob = g_blob;
1661 : : struct spdk_io_channel *channel;
1662 : 15 : uint8_t payload_write[10 * BLOCKLEN];
1663 : 15 : struct iovec iov_write[3];
1664 : : uint32_t req_count;
1665 : :
1666 : 20 : channel = spdk_bs_alloc_io_channel(bs);
1667 : 20 : CU_ASSERT(channel != NULL);
1668 : :
1669 : 20 : spdk_blob_resize(blob, 2, blob_op_complete, NULL);
1670 : 20 : poll_threads();
1671 : 20 : CU_ASSERT(g_bserrno == 0);
1672 : :
1673 : : /*
1674 : : * Choose a page offset just before the cluster boundary. The first 6 pages of payload
1675 : : * will get written to the first cluster, the last 4 to the second cluster.
1676 : : */
1677 : 20 : iov_write[0].iov_base = payload_write;
1678 : 20 : iov_write[0].iov_len = 1 * BLOCKLEN;
1679 : 20 : iov_write[1].iov_base = payload_write + 1 * BLOCKLEN;
1680 : 20 : iov_write[1].iov_len = 5 * BLOCKLEN;
1681 : 20 : iov_write[2].iov_base = payload_write + 6 * BLOCKLEN;
1682 : 20 : iov_write[2].iov_len = 4 * BLOCKLEN;
1683 : 20 : MOCK_SET(calloc, NULL);
1684 : 20 : req_count = bs_channel_get_req_count(channel);
1685 : 20 : spdk_blob_io_writev(blob, channel, iov_write, 3, 250, 10, blob_op_complete, NULL);
1686 : 20 : poll_threads();
1687 : 20 : CU_ASSERT(g_bserrno == -ENOMEM);
1688 : 20 : CU_ASSERT(req_count == bs_channel_get_req_count(channel));
1689 [ - + - + ]: 20 : MOCK_CLEAR(calloc);
1690 : :
1691 : 20 : spdk_bs_free_io_channel(channel);
1692 : 20 : poll_threads();
1693 : 20 : }
1694 : :
1695 : : static void
1696 : 20 : blob_rw_iov_read_only(void)
1697 : : {
1698 : 20 : struct spdk_blob_store *bs = g_bs;
1699 : 20 : struct spdk_blob *blob = g_blob;
1700 : : struct spdk_io_channel *channel;
1701 : 15 : uint8_t payload_read[BLOCKLEN];
1702 : 15 : uint8_t payload_write[BLOCKLEN];
1703 : 15 : struct iovec iov_read;
1704 : 15 : struct iovec iov_write;
1705 : :
1706 : 20 : channel = spdk_bs_alloc_io_channel(bs);
1707 : 20 : CU_ASSERT(channel != NULL);
1708 : :
1709 : 20 : spdk_blob_resize(blob, 2, blob_op_complete, NULL);
1710 : 20 : poll_threads();
1711 : 20 : CU_ASSERT(g_bserrno == 0);
1712 : :
1713 : : /* Verify that writev failed if read_only flag is set. */
1714 : 20 : blob->data_ro = true;
1715 : 20 : iov_write.iov_base = payload_write;
1716 : 20 : iov_write.iov_len = sizeof(payload_write);
1717 : 20 : spdk_blob_io_writev(blob, channel, &iov_write, 1, 0, 1, blob_op_complete, NULL);
1718 : 20 : poll_threads();
1719 : 20 : CU_ASSERT(g_bserrno == -EPERM);
1720 : :
1721 : : /* Verify that reads pass if data_ro flag is set. */
1722 : 20 : iov_read.iov_base = payload_read;
1723 : 20 : iov_read.iov_len = sizeof(payload_read);
1724 : 20 : spdk_blob_io_readv(blob, channel, &iov_read, 1, 0, 1, blob_op_complete, NULL);
1725 : 20 : poll_threads();
1726 : 20 : CU_ASSERT(g_bserrno == 0);
1727 : :
1728 : 20 : spdk_bs_free_io_channel(channel);
1729 : 20 : poll_threads();
1730 : 20 : }
1731 : :
1732 : : static void
1733 : 40 : _blob_io_read_no_split(struct spdk_blob *blob, struct spdk_io_channel *channel,
1734 : : uint8_t *payload, uint64_t offset, uint64_t length,
1735 : : spdk_blob_op_complete cb_fn, void *cb_arg)
1736 : : {
1737 : : uint64_t i;
1738 : : uint8_t *buf;
1739 : 40 : uint64_t io_unit_size = spdk_bs_get_io_unit_size(blob->bs);
1740 : :
1741 : : /* To be sure that operation is NOT split, read one io_unit at the time */
1742 : 40 : buf = payload;
1743 [ + + ]: 51240 : for (i = 0; i < length; i++) {
1744 : 51200 : spdk_blob_io_read(blob, channel, buf, i + offset, 1, blob_op_complete, NULL);
1745 : 51200 : poll_threads();
1746 [ - + ]: 51200 : if (g_bserrno != 0) {
1747 : : /* Pass the error code up */
1748 : 0 : break;
1749 : : }
1750 : 51200 : buf += io_unit_size;
1751 : 12800 : }
1752 : :
1753 : 40 : cb_fn(cb_arg, g_bserrno);
1754 : 40 : }
1755 : :
1756 : : static void
1757 : 40 : _blob_io_write_no_split(struct spdk_blob *blob, struct spdk_io_channel *channel,
1758 : : uint8_t *payload, uint64_t offset, uint64_t length,
1759 : : spdk_blob_op_complete cb_fn, void *cb_arg)
1760 : : {
1761 : : uint64_t i;
1762 : : uint8_t *buf;
1763 : 40 : uint64_t io_unit_size = spdk_bs_get_io_unit_size(blob->bs);
1764 : :
1765 : : /* To be sure that operation is NOT split, write one io_unit at the time */
1766 : 40 : buf = payload;
1767 [ + + ]: 51240 : for (i = 0; i < length; i++) {
1768 : 51200 : spdk_blob_io_write(blob, channel, buf, i + offset, 1, blob_op_complete, NULL);
1769 : 51200 : poll_threads();
1770 [ - + ]: 51200 : if (g_bserrno != 0) {
1771 : : /* Pass the error code up */
1772 : 0 : break;
1773 : : }
1774 : 51200 : buf += io_unit_size;
1775 : 12800 : }
1776 : :
1777 : 40 : cb_fn(cb_arg, g_bserrno);
1778 : 40 : }
1779 : :
1780 : : static void
1781 : 20 : blob_operation_split_rw(void)
1782 : : {
1783 : 20 : struct spdk_blob_store *bs = g_bs;
1784 : : struct spdk_blob *blob;
1785 : : struct spdk_io_channel *channel;
1786 : 15 : struct spdk_blob_opts opts;
1787 : : uint64_t cluster_size;
1788 : :
1789 : : uint64_t payload_size;
1790 : : uint8_t *payload_read;
1791 : : uint8_t *payload_write;
1792 : : uint8_t *payload_pattern;
1793 : :
1794 : : uint64_t io_unit_size;
1795 : : uint64_t io_units_per_cluster;
1796 : : uint64_t io_units_per_payload;
1797 : :
1798 : : uint64_t i;
1799 : :
1800 : 20 : cluster_size = spdk_bs_get_cluster_size(bs);
1801 : 20 : io_unit_size = spdk_bs_get_io_unit_size(bs);
1802 [ - + ]: 20 : io_units_per_cluster = cluster_size / io_unit_size;
1803 : 20 : io_units_per_payload = io_units_per_cluster * 5;
1804 : 20 : payload_size = cluster_size * 5;
1805 : :
1806 : 20 : payload_read = malloc(payload_size);
1807 [ + + ]: 20 : SPDK_CU_ASSERT_FATAL(payload_read != NULL);
1808 : :
1809 : 20 : payload_write = malloc(payload_size);
1810 [ + + ]: 20 : SPDK_CU_ASSERT_FATAL(payload_write != NULL);
1811 : :
1812 : 20 : payload_pattern = malloc(payload_size);
1813 [ + + ]: 20 : SPDK_CU_ASSERT_FATAL(payload_pattern != NULL);
1814 : :
1815 : : /* Prepare random pattern to write */
1816 [ - + ]: 20 : memset(payload_pattern, 0xFF, payload_size);
1817 [ + + ]: 25620 : for (i = 0; i < io_units_per_payload; i++) {
1818 : 25600 : *((uint64_t *)(payload_pattern + io_unit_size * i)) = (i + 1);
1819 : 6400 : }
1820 : :
1821 : 20 : channel = spdk_bs_alloc_io_channel(bs);
1822 [ - + ]: 20 : SPDK_CU_ASSERT_FATAL(channel != NULL);
1823 : :
1824 : : /* Create blob */
1825 : 20 : ut_spdk_blob_opts_init(&opts);
1826 : 20 : opts.thin_provision = false;
1827 : 20 : opts.num_clusters = 5;
1828 : :
1829 : 20 : blob = ut_blob_create_and_open(bs, &opts);
1830 : 20 : CU_ASSERT(spdk_blob_get_num_clusters(blob) == 5);
1831 : :
1832 : : /* Initial read should return zeroed payload */
1833 [ - + ]: 20 : memset(payload_read, 0xFF, payload_size);
1834 : 20 : spdk_blob_io_read(blob, channel, payload_read, 0, io_units_per_payload, blob_op_complete, NULL);
1835 : 20 : poll_threads();
1836 : 20 : CU_ASSERT(g_bserrno == 0);
1837 : 20 : CU_ASSERT(spdk_mem_all_zero(payload_read, payload_size));
1838 : :
1839 : : /* Fill whole blob except last page */
1840 : 20 : spdk_blob_io_write(blob, channel, payload_pattern, 0, io_units_per_payload - 1,
1841 : : blob_op_complete, NULL);
1842 : 20 : poll_threads();
1843 : 20 : CU_ASSERT(g_bserrno == 0);
1844 : :
1845 : : /* Write last page with a pattern */
1846 : 20 : spdk_blob_io_write(blob, channel, payload_pattern, io_units_per_payload - 1, 1,
1847 : : blob_op_complete, NULL);
1848 : 20 : poll_threads();
1849 : 20 : CU_ASSERT(g_bserrno == 0);
1850 : :
1851 : : /* Read whole blob and check consistency */
1852 [ - + ]: 20 : memset(payload_read, 0xFF, payload_size);
1853 : 20 : spdk_blob_io_read(blob, channel, payload_read, 0, io_units_per_payload, blob_op_complete, NULL);
1854 : 20 : poll_threads();
1855 : 20 : CU_ASSERT(g_bserrno == 0);
1856 [ - + - + ]: 20 : CU_ASSERT(memcmp(payload_pattern, payload_read, payload_size - io_unit_size) == 0);
1857 [ - + - + ]: 20 : CU_ASSERT(memcmp(payload_pattern, payload_read + payload_size - io_unit_size, io_unit_size) == 0);
1858 : :
1859 : : /* Fill whole blob except first page */
1860 : 20 : spdk_blob_io_write(blob, channel, payload_pattern, 1, io_units_per_payload - 1,
1861 : : blob_op_complete, NULL);
1862 : 20 : poll_threads();
1863 : 20 : CU_ASSERT(g_bserrno == 0);
1864 : :
1865 : : /* Write first page with a pattern */
1866 : 20 : spdk_blob_io_write(blob, channel, payload_pattern, 0, 1,
1867 : : blob_op_complete, NULL);
1868 : 20 : poll_threads();
1869 : 20 : CU_ASSERT(g_bserrno == 0);
1870 : :
1871 : : /* Read whole blob and check consistency */
1872 [ - + ]: 20 : memset(payload_read, 0xFF, payload_size);
1873 : 20 : spdk_blob_io_read(blob, channel, payload_read, 0, io_units_per_payload, blob_op_complete, NULL);
1874 : 20 : poll_threads();
1875 : 20 : CU_ASSERT(g_bserrno == 0);
1876 [ - + - + ]: 20 : CU_ASSERT(memcmp(payload_pattern, payload_read + io_unit_size, payload_size - io_unit_size) == 0);
1877 [ - + - + ]: 20 : CU_ASSERT(memcmp(payload_pattern, payload_read, io_unit_size) == 0);
1878 : :
1879 : :
1880 : : /* Fill whole blob with a pattern (5 clusters) */
1881 : :
1882 : : /* 1. Read test. */
1883 : 20 : _blob_io_write_no_split(blob, channel, payload_pattern, 0, io_units_per_payload,
1884 : : blob_op_complete, NULL);
1885 : 20 : poll_threads();
1886 : 20 : CU_ASSERT(g_bserrno == 0);
1887 : :
1888 [ - + ]: 20 : memset(payload_read, 0xFF, payload_size);
1889 : 20 : spdk_blob_io_read(blob, channel, payload_read, 0, io_units_per_payload, blob_op_complete, NULL);
1890 : 20 : poll_threads();
1891 : 20 : poll_threads();
1892 : 20 : CU_ASSERT(g_bserrno == 0);
1893 [ - + - + ]: 20 : CU_ASSERT(memcmp(payload_pattern, payload_read, payload_size) == 0);
1894 : :
1895 : : /* 2. Write test. */
1896 : 20 : spdk_blob_io_write(blob, channel, payload_pattern, 0, io_units_per_payload,
1897 : : blob_op_complete, NULL);
1898 : 20 : poll_threads();
1899 : 20 : CU_ASSERT(g_bserrno == 0);
1900 : :
1901 [ - + ]: 20 : memset(payload_read, 0xFF, payload_size);
1902 : 20 : _blob_io_read_no_split(blob, channel, payload_read, 0, io_units_per_payload, blob_op_complete,
1903 : : NULL);
1904 : 20 : poll_threads();
1905 : 20 : CU_ASSERT(g_bserrno == 0);
1906 [ - + - + ]: 20 : CU_ASSERT(memcmp(payload_pattern, payload_read, payload_size) == 0);
1907 : :
1908 : 20 : spdk_bs_free_io_channel(channel);
1909 : 20 : poll_threads();
1910 : :
1911 : 20 : g_blob = NULL;
1912 : 20 : g_blobid = 0;
1913 : :
1914 : 20 : free(payload_read);
1915 : 20 : free(payload_write);
1916 : 20 : free(payload_pattern);
1917 : :
1918 : 20 : ut_blob_close_and_delete(bs, blob);
1919 : 20 : }
1920 : :
1921 : : static void
1922 : 20 : blob_operation_split_rw_iov(void)
1923 : : {
1924 : 20 : struct spdk_blob_store *bs = g_bs;
1925 : : struct spdk_blob *blob;
1926 : : struct spdk_io_channel *channel;
1927 : 15 : struct spdk_blob_opts opts;
1928 : : uint64_t cluster_size;
1929 : :
1930 : : uint64_t payload_size;
1931 : : uint8_t *payload_read;
1932 : : uint8_t *payload_write;
1933 : : uint8_t *payload_pattern;
1934 : :
1935 : : uint64_t io_unit_size;
1936 : : uint64_t io_units_per_cluster;
1937 : : uint64_t io_units_per_payload;
1938 : :
1939 : 15 : struct iovec iov_read[2];
1940 : 15 : struct iovec iov_write[2];
1941 : :
1942 : : uint64_t i, j;
1943 : :
1944 : 20 : cluster_size = spdk_bs_get_cluster_size(bs);
1945 : 20 : io_unit_size = spdk_bs_get_io_unit_size(bs);
1946 [ - + ]: 20 : io_units_per_cluster = cluster_size / io_unit_size;
1947 : 20 : io_units_per_payload = io_units_per_cluster * 5;
1948 : 20 : payload_size = cluster_size * 5;
1949 : :
1950 : 20 : payload_read = malloc(payload_size);
1951 [ + + ]: 20 : SPDK_CU_ASSERT_FATAL(payload_read != NULL);
1952 : :
1953 : 20 : payload_write = malloc(payload_size);
1954 [ + + ]: 20 : SPDK_CU_ASSERT_FATAL(payload_write != NULL);
1955 : :
1956 : 20 : payload_pattern = malloc(payload_size);
1957 [ + + ]: 20 : SPDK_CU_ASSERT_FATAL(payload_pattern != NULL);
1958 : :
1959 : : /* Prepare random pattern to write */
1960 [ + + ]: 25620 : for (i = 0; i < io_units_per_payload; i++) {
1961 [ + + ]: 13132800 : for (j = 0; j < io_unit_size / sizeof(uint64_t); j++) {
1962 : : uint64_t *tmp;
1963 : :
1964 : 13107200 : tmp = (uint64_t *)payload_pattern;
1965 : 13107200 : tmp += ((io_unit_size * i) / sizeof(uint64_t)) + j;
1966 : 13107200 : *tmp = i + 1;
1967 : 3276800 : }
1968 : 6400 : }
1969 : :
1970 : 20 : channel = spdk_bs_alloc_io_channel(bs);
1971 [ - + ]: 20 : SPDK_CU_ASSERT_FATAL(channel != NULL);
1972 : :
1973 : : /* Create blob */
1974 : 20 : ut_spdk_blob_opts_init(&opts);
1975 : 20 : opts.thin_provision = false;
1976 : 20 : opts.num_clusters = 5;
1977 : :
1978 : 20 : blob = ut_blob_create_and_open(bs, &opts);
1979 : 20 : CU_ASSERT(spdk_blob_get_num_clusters(blob) == 5);
1980 : :
1981 : : /* Initial read should return zeroes payload */
1982 [ - + ]: 20 : memset(payload_read, 0xFF, payload_size);
1983 : 20 : iov_read[0].iov_base = payload_read;
1984 : 20 : iov_read[0].iov_len = cluster_size * 3;
1985 : 20 : iov_read[1].iov_base = payload_read + cluster_size * 3;
1986 : 20 : iov_read[1].iov_len = cluster_size * 2;
1987 : 20 : spdk_blob_io_readv(blob, channel, iov_read, 2, 0, io_units_per_payload, blob_op_complete, NULL);
1988 : 20 : poll_threads();
1989 : 20 : CU_ASSERT(g_bserrno == 0);
1990 : 20 : CU_ASSERT(spdk_mem_all_zero(payload_read, payload_size));
1991 : :
1992 : : /* First of iovs fills whole blob except last io_unit and second of iovs writes last io_unit
1993 : : * with a pattern. */
1994 : 20 : iov_write[0].iov_base = payload_pattern;
1995 : 20 : iov_write[0].iov_len = payload_size - io_unit_size;
1996 : 20 : iov_write[1].iov_base = payload_pattern;
1997 : 20 : iov_write[1].iov_len = io_unit_size;
1998 : 20 : spdk_blob_io_writev(blob, channel, iov_write, 2, 0, io_units_per_payload, blob_op_complete, NULL);
1999 : 20 : poll_threads();
2000 : 20 : CU_ASSERT(g_bserrno == 0);
2001 : :
2002 : : /* Read whole blob and check consistency */
2003 [ - + ]: 20 : memset(payload_read, 0xFF, payload_size);
2004 : 20 : iov_read[0].iov_base = payload_read;
2005 : 20 : iov_read[0].iov_len = cluster_size * 2;
2006 : 20 : iov_read[1].iov_base = payload_read + cluster_size * 2;
2007 : 20 : iov_read[1].iov_len = cluster_size * 3;
2008 : 20 : spdk_blob_io_readv(blob, channel, iov_read, 2, 0, io_units_per_payload, blob_op_complete, NULL);
2009 : 20 : poll_threads();
2010 : 20 : CU_ASSERT(g_bserrno == 0);
2011 [ - + - + ]: 20 : CU_ASSERT(memcmp(payload_pattern, payload_read, payload_size - io_unit_size) == 0);
2012 [ - + - + ]: 20 : CU_ASSERT(memcmp(payload_pattern, payload_read + payload_size - io_unit_size, io_unit_size) == 0);
2013 : :
2014 : : /* First of iovs fills only first io_unit and second of iovs writes whole blob except
2015 : : * first io_unit with a pattern. */
2016 : 20 : iov_write[0].iov_base = payload_pattern;
2017 : 20 : iov_write[0].iov_len = io_unit_size;
2018 : 20 : iov_write[1].iov_base = payload_pattern;
2019 : 20 : iov_write[1].iov_len = payload_size - io_unit_size;
2020 : 20 : spdk_blob_io_writev(blob, channel, iov_write, 2, 0, io_units_per_payload, blob_op_complete, NULL);
2021 : 20 : poll_threads();
2022 : 20 : CU_ASSERT(g_bserrno == 0);
2023 : :
2024 : : /* Read whole blob and check consistency */
2025 [ - + ]: 20 : memset(payload_read, 0xFF, payload_size);
2026 : 20 : iov_read[0].iov_base = payload_read;
2027 : 20 : iov_read[0].iov_len = cluster_size * 4;
2028 : 20 : iov_read[1].iov_base = payload_read + cluster_size * 4;
2029 : 20 : iov_read[1].iov_len = cluster_size;
2030 : 20 : spdk_blob_io_readv(blob, channel, iov_read, 2, 0, io_units_per_payload, blob_op_complete, NULL);
2031 : 20 : poll_threads();
2032 : 20 : CU_ASSERT(g_bserrno == 0);
2033 [ - + - + ]: 20 : CU_ASSERT(memcmp(payload_pattern, payload_read + io_unit_size, payload_size - io_unit_size) == 0);
2034 [ - + - + ]: 20 : CU_ASSERT(memcmp(payload_pattern, payload_read, io_unit_size) == 0);
2035 : :
2036 : :
2037 : : /* Fill whole blob with a pattern (5 clusters) */
2038 : :
2039 : : /* 1. Read test. */
2040 : 20 : _blob_io_write_no_split(blob, channel, payload_pattern, 0, io_units_per_payload,
2041 : : blob_op_complete, NULL);
2042 : 20 : poll_threads();
2043 : 20 : CU_ASSERT(g_bserrno == 0);
2044 : :
2045 [ - + ]: 20 : memset(payload_read, 0xFF, payload_size);
2046 : 20 : iov_read[0].iov_base = payload_read;
2047 : 20 : iov_read[0].iov_len = cluster_size;
2048 : 20 : iov_read[1].iov_base = payload_read + cluster_size;
2049 : 20 : iov_read[1].iov_len = cluster_size * 4;
2050 : 20 : spdk_blob_io_readv(blob, channel, iov_read, 2, 0, io_units_per_payload, blob_op_complete, NULL);
2051 : 20 : poll_threads();
2052 : 20 : CU_ASSERT(g_bserrno == 0);
2053 [ - + - + ]: 20 : CU_ASSERT(memcmp(payload_pattern, payload_read, payload_size) == 0);
2054 : :
2055 : : /* 2. Write test. */
2056 : 20 : iov_write[0].iov_base = payload_read;
2057 : 20 : iov_write[0].iov_len = cluster_size * 2;
2058 : 20 : iov_write[1].iov_base = payload_read + cluster_size * 2;
2059 : 20 : iov_write[1].iov_len = cluster_size * 3;
2060 : 20 : spdk_blob_io_writev(blob, channel, iov_write, 2, 0, io_units_per_payload, blob_op_complete, NULL);
2061 : 20 : poll_threads();
2062 : 20 : CU_ASSERT(g_bserrno == 0);
2063 : :
2064 [ - + ]: 20 : memset(payload_read, 0xFF, payload_size);
2065 : 20 : _blob_io_read_no_split(blob, channel, payload_read, 0, io_units_per_payload, blob_op_complete,
2066 : : NULL);
2067 : 20 : poll_threads();
2068 : 20 : CU_ASSERT(g_bserrno == 0);
2069 [ - + - + ]: 20 : CU_ASSERT(memcmp(payload_pattern, payload_read, payload_size) == 0);
2070 : :
2071 : 20 : spdk_bs_free_io_channel(channel);
2072 : 20 : poll_threads();
2073 : :
2074 : 20 : g_blob = NULL;
2075 : 20 : g_blobid = 0;
2076 : :
2077 : 20 : free(payload_read);
2078 : 20 : free(payload_write);
2079 : 20 : free(payload_pattern);
2080 : :
2081 : 20 : ut_blob_close_and_delete(bs, blob);
2082 : 20 : }
2083 : :
2084 : : static void
2085 : 20 : blob_unmap(void)
2086 : : {
2087 : 20 : struct spdk_blob_store *bs = g_bs;
2088 : : struct spdk_blob *blob;
2089 : : struct spdk_io_channel *channel;
2090 : 15 : struct spdk_blob_opts opts;
2091 : 15 : uint8_t payload[BLOCKLEN];
2092 [ - + ]: 20 : uint32_t first_data_cluster = FIRST_DATA_CLUSTER(bs);
2093 : : int i;
2094 : :
2095 : 20 : channel = spdk_bs_alloc_io_channel(bs);
2096 : 20 : CU_ASSERT(channel != NULL);
2097 : :
2098 : 20 : ut_spdk_blob_opts_init(&opts);
2099 : 20 : opts.num_clusters = 10;
2100 : :
2101 : 20 : blob = ut_blob_create_and_open(bs, &opts);
2102 : :
2103 : 20 : spdk_blob_resize(blob, 10, blob_op_complete, NULL);
2104 : 20 : poll_threads();
2105 : 20 : CU_ASSERT(g_bserrno == 0);
2106 : 20 : CU_ASSERT(spdk_blob_get_num_allocated_clusters(blob) == 10);
2107 : :
2108 [ - + ]: 20 : memset(payload, 0, sizeof(payload));
2109 : 20 : payload[0] = 0xFF;
2110 : :
2111 : : /*
2112 : : * Set first byte of every cluster to 0xFF.
2113 : : */
2114 [ + + ]: 220 : for (i = 0; i < 10; i++) {
2115 : 200 : g_dev_buffer[(first_data_cluster + i) * SPDK_BLOB_OPTS_CLUSTER_SZ] = 0xFF;
2116 : 50 : }
2117 : :
2118 : : /* Confirm writes */
2119 [ + + ]: 220 : for (i = 0; i < 10; i++) {
2120 : 200 : payload[0] = 0;
2121 : 200 : spdk_blob_io_read(blob, channel, &payload, i * SPDK_BLOB_OPTS_CLUSTER_SZ / BLOCKLEN, 1,
2122 : : blob_op_complete, NULL);
2123 : 200 : poll_threads();
2124 : 200 : CU_ASSERT(g_bserrno == 0);
2125 : 200 : CU_ASSERT(payload[0] == 0xFF);
2126 : 50 : }
2127 : :
2128 : : /* Mark some clusters as unallocated */
2129 : 20 : blob->active.clusters[1] = 0;
2130 : 20 : blob->active.clusters[2] = 0;
2131 : 20 : blob->active.clusters[3] = 0;
2132 : 20 : blob->active.clusters[6] = 0;
2133 : 20 : blob->active.clusters[8] = 0;
2134 : 20 : blob->active.num_allocated_clusters -= 5;
2135 : :
2136 : : /* Unmap clusters by resizing to 0 */
2137 : 20 : spdk_blob_resize(blob, 0, blob_op_complete, NULL);
2138 : 20 : poll_threads();
2139 : 20 : CU_ASSERT(g_bserrno == 0);
2140 : :
2141 : 20 : spdk_blob_sync_md(blob, blob_op_complete, NULL);
2142 : 20 : poll_threads();
2143 : 20 : CU_ASSERT(g_bserrno == 0);
2144 : 20 : CU_ASSERT(spdk_blob_get_num_allocated_clusters(blob) == 0);
2145 : :
2146 : : /* Confirm that only 'allocated' clusters were unmapped */
2147 [ + + ]: 220 : for (i = 0; i < 10; i++) {
2148 [ + + ]: 200 : switch (i) {
2149 : 75 : case 1:
2150 : : case 2:
2151 : : case 3:
2152 : : case 6:
2153 : : case 8:
2154 : 100 : CU_ASSERT(g_dev_buffer[(first_data_cluster + i) * SPDK_BLOB_OPTS_CLUSTER_SZ] == 0xFF);
2155 : 100 : break;
2156 : 75 : default:
2157 : 100 : CU_ASSERT(g_dev_buffer[(first_data_cluster + i) * SPDK_BLOB_OPTS_CLUSTER_SZ] == 0);
2158 : 100 : break;
2159 : : }
2160 : 50 : }
2161 : :
2162 : 20 : spdk_bs_free_io_channel(channel);
2163 : 20 : poll_threads();
2164 : :
2165 : 20 : ut_blob_close_and_delete(bs, blob);
2166 : 20 : }
2167 : :
2168 : : static void
2169 : 20 : blob_iter(void)
2170 : : {
2171 : 20 : struct spdk_blob_store *bs = g_bs;
2172 : : struct spdk_blob *blob;
2173 : : spdk_blob_id blobid;
2174 : 15 : struct spdk_blob_opts blob_opts;
2175 : :
2176 : 20 : spdk_bs_iter_first(bs, blob_op_with_handle_complete, NULL);
2177 : 20 : poll_threads();
2178 : 20 : CU_ASSERT(g_blob == NULL);
2179 : 20 : CU_ASSERT(g_bserrno == -ENOENT);
2180 : :
2181 : 20 : ut_spdk_blob_opts_init(&blob_opts);
2182 : 20 : spdk_bs_create_blob_ext(bs, &blob_opts, blob_op_with_id_complete, NULL);
2183 : 20 : poll_threads();
2184 : 20 : CU_ASSERT(g_bserrno == 0);
2185 : 20 : CU_ASSERT(g_blobid != SPDK_BLOBID_INVALID);
2186 : 20 : blobid = g_blobid;
2187 : :
2188 : 20 : spdk_bs_iter_first(bs, blob_op_with_handle_complete, NULL);
2189 : 20 : poll_threads();
2190 : 20 : CU_ASSERT(g_blob != NULL);
2191 : 20 : CU_ASSERT(g_bserrno == 0);
2192 : 20 : blob = g_blob;
2193 : 20 : CU_ASSERT(spdk_blob_get_id(blob) == blobid);
2194 : :
2195 : 20 : spdk_bs_iter_next(bs, blob, blob_op_with_handle_complete, NULL);
2196 : 20 : poll_threads();
2197 : 20 : CU_ASSERT(g_blob == NULL);
2198 : 20 : CU_ASSERT(g_bserrno == -ENOENT);
2199 : 20 : }
2200 : :
2201 : : static void
2202 : 20 : blob_xattr(void)
2203 : : {
2204 : 20 : struct spdk_blob_store *bs = g_bs;
2205 : 20 : struct spdk_blob *blob = g_blob;
2206 : 20 : spdk_blob_id blobid = spdk_blob_get_id(blob);
2207 : 15 : uint64_t length;
2208 : : int rc;
2209 : : const char *name1, *name2;
2210 : 15 : const void *value;
2211 : 15 : size_t value_len;
2212 : 15 : struct spdk_xattr_names *names;
2213 : :
2214 : : /* Test that set_xattr fails if md_ro flag is set. */
2215 : 20 : blob->md_ro = true;
2216 : 20 : rc = spdk_blob_set_xattr(blob, "name", "log.txt", strlen("log.txt") + 1);
2217 : 20 : CU_ASSERT(rc == -EPERM);
2218 : :
2219 : 20 : blob->md_ro = false;
2220 : 20 : rc = spdk_blob_set_xattr(blob, "name", "log.txt", strlen("log.txt") + 1);
2221 : 20 : CU_ASSERT(rc == 0);
2222 : :
2223 : 20 : length = 2345;
2224 : 20 : rc = spdk_blob_set_xattr(blob, "length", &length, sizeof(length));
2225 : 20 : CU_ASSERT(rc == 0);
2226 : :
2227 : : /* Overwrite "length" xattr. */
2228 : 20 : length = 3456;
2229 : 20 : rc = spdk_blob_set_xattr(blob, "length", &length, sizeof(length));
2230 : 20 : CU_ASSERT(rc == 0);
2231 : :
2232 : : /* get_xattr should still work even if md_ro flag is set. */
2233 : 20 : value = NULL;
2234 : 20 : blob->md_ro = true;
2235 : 20 : rc = spdk_blob_get_xattr_value(blob, "length", &value, &value_len);
2236 : 20 : CU_ASSERT(rc == 0);
2237 [ + + ]: 20 : SPDK_CU_ASSERT_FATAL(value != NULL);
2238 : 20 : CU_ASSERT(*(uint64_t *)value == length);
2239 : 20 : CU_ASSERT(value_len == 8);
2240 : 20 : blob->md_ro = false;
2241 : :
2242 : 20 : rc = spdk_blob_get_xattr_value(blob, "foobar", &value, &value_len);
2243 : 20 : CU_ASSERT(rc == -ENOENT);
2244 : :
2245 : 20 : names = NULL;
2246 : 20 : rc = spdk_blob_get_xattr_names(blob, &names);
2247 : 20 : CU_ASSERT(rc == 0);
2248 [ + + ]: 20 : SPDK_CU_ASSERT_FATAL(names != NULL);
2249 : 20 : CU_ASSERT(spdk_xattr_names_get_count(names) == 2);
2250 : 20 : name1 = spdk_xattr_names_get_name(names, 0);
2251 [ + + ]: 20 : SPDK_CU_ASSERT_FATAL(name1 != NULL);
2252 [ + + - + : 20 : CU_ASSERT(!strcmp(name1, "name") || !strcmp(name1, "length"));
- - - - ]
2253 : 20 : name2 = spdk_xattr_names_get_name(names, 1);
2254 [ + + ]: 20 : SPDK_CU_ASSERT_FATAL(name2 != NULL);
2255 [ + + + - : 20 : CU_ASSERT(!strcmp(name2, "name") || !strcmp(name2, "length"));
- + + - ]
2256 [ - + - + ]: 20 : CU_ASSERT(strcmp(name1, name2));
2257 : 20 : spdk_xattr_names_free(names);
2258 : :
2259 : : /* Confirm that remove_xattr fails if md_ro is set to true. */
2260 : 20 : blob->md_ro = true;
2261 : 20 : rc = spdk_blob_remove_xattr(blob, "name");
2262 : 20 : CU_ASSERT(rc == -EPERM);
2263 : :
2264 : 20 : blob->md_ro = false;
2265 : 20 : rc = spdk_blob_remove_xattr(blob, "name");
2266 : 20 : CU_ASSERT(rc == 0);
2267 : :
2268 : 20 : rc = spdk_blob_remove_xattr(blob, "foobar");
2269 : 20 : CU_ASSERT(rc == -ENOENT);
2270 : :
2271 : : /* Set internal xattr */
2272 : 20 : length = 7898;
2273 : 20 : rc = blob_set_xattr(blob, "internal", &length, sizeof(length), true);
2274 : 20 : CU_ASSERT(rc == 0);
2275 : 20 : rc = blob_get_xattr_value(blob, "internal", &value, &value_len, true);
2276 : 20 : CU_ASSERT(rc == 0);
2277 : 20 : CU_ASSERT(*(uint64_t *)value == length);
2278 : : /* try to get public xattr with same name */
2279 : 20 : rc = spdk_blob_get_xattr_value(blob, "internal", &value, &value_len);
2280 : 20 : CU_ASSERT(rc != 0);
2281 : 20 : rc = blob_get_xattr_value(blob, "internal", &value, &value_len, false);
2282 : 20 : CU_ASSERT(rc != 0);
2283 : : /* Check if SPDK_BLOB_INTERNAL_XATTR is set */
2284 : 20 : CU_ASSERT((blob->invalid_flags & SPDK_BLOB_INTERNAL_XATTR) ==
2285 : : SPDK_BLOB_INTERNAL_XATTR);
2286 : :
2287 : 20 : spdk_blob_close(blob, blob_op_complete, NULL);
2288 : 20 : poll_threads();
2289 : :
2290 : : /* Check if xattrs are persisted */
2291 : 20 : ut_bs_reload(&bs, NULL);
2292 : :
2293 : 20 : spdk_bs_open_blob(bs, blobid, blob_op_with_handle_complete, NULL);
2294 : 20 : poll_threads();
2295 : 20 : CU_ASSERT(g_bserrno == 0);
2296 [ - + ]: 20 : SPDK_CU_ASSERT_FATAL(g_blob != NULL);
2297 : 20 : blob = g_blob;
2298 : :
2299 : 20 : rc = blob_get_xattr_value(blob, "internal", &value, &value_len, true);
2300 : 20 : CU_ASSERT(rc == 0);
2301 : 20 : CU_ASSERT(*(uint64_t *)value == length);
2302 : :
2303 : : /* try to get internal xattr through public call */
2304 : 20 : rc = spdk_blob_get_xattr_value(blob, "internal", &value, &value_len);
2305 : 20 : CU_ASSERT(rc != 0);
2306 : :
2307 : 20 : rc = blob_remove_xattr(blob, "internal", true);
2308 : 20 : CU_ASSERT(rc == 0);
2309 : :
2310 : 20 : CU_ASSERT((blob->invalid_flags & SPDK_BLOB_INTERNAL_XATTR) == 0);
2311 : 20 : }
2312 : :
2313 : : static void
2314 : 20 : blob_parse_md(void)
2315 : : {
2316 : 20 : struct spdk_blob_store *bs = g_bs;
2317 : : struct spdk_blob *blob;
2318 : : int rc;
2319 : : uint32_t used_pages;
2320 : : size_t xattr_length;
2321 : : char *xattr;
2322 : :
2323 : 20 : used_pages = spdk_bit_array_count_set(bs->used_md_pages);
2324 : 20 : blob = ut_blob_create_and_open(bs, NULL);
2325 : :
2326 : : /* Create large extent to force more than 1 page of metadata. */
2327 : 20 : xattr_length = SPDK_BS_MAX_DESC_SIZE - sizeof(struct spdk_blob_md_descriptor_xattr) -
2328 : : strlen("large_xattr");
2329 : 20 : xattr = calloc(xattr_length, sizeof(char));
2330 [ + + ]: 20 : SPDK_CU_ASSERT_FATAL(xattr != NULL);
2331 : 20 : rc = spdk_blob_set_xattr(blob, "large_xattr", xattr, xattr_length);
2332 : 20 : free(xattr);
2333 [ + + ]: 20 : SPDK_CU_ASSERT_FATAL(rc == 0);
2334 : :
2335 : 20 : spdk_blob_sync_md(blob, blob_op_complete, NULL);
2336 : 20 : poll_threads();
2337 : :
2338 : : /* Delete the blob and verify that number of pages returned to before its creation. */
2339 [ + + ]: 20 : SPDK_CU_ASSERT_FATAL(used_pages != spdk_bit_array_count_set(bs->used_md_pages));
2340 : 20 : ut_blob_close_and_delete(bs, blob);
2341 [ - + ]: 20 : SPDK_CU_ASSERT_FATAL(used_pages == spdk_bit_array_count_set(bs->used_md_pages));
2342 : 20 : }
2343 : :
2344 : : static void
2345 : 20 : bs_load(void)
2346 : : {
2347 : : struct spdk_blob_store *bs;
2348 : : struct spdk_bs_dev *dev;
2349 : : spdk_blob_id blobid;
2350 : : struct spdk_blob *blob;
2351 : : struct spdk_bs_super_block *super_block;
2352 : 15 : uint64_t length;
2353 : : int rc;
2354 : 15 : const void *value;
2355 : 15 : size_t value_len;
2356 : 15 : struct spdk_bs_opts opts;
2357 : 15 : struct spdk_blob_opts blob_opts;
2358 : :
2359 : 20 : dev = init_dev();
2360 : 20 : spdk_bs_opts_init(&opts, sizeof(opts));
2361 [ - + ]: 20 : snprintf(opts.bstype.bstype, sizeof(opts.bstype.bstype), "TESTTYPE");
2362 : :
2363 : : /* Initialize a new blob store */
2364 : 20 : spdk_bs_init(dev, &opts, bs_op_with_handle_complete, NULL);
2365 : 20 : poll_threads();
2366 : 20 : CU_ASSERT(g_bserrno == 0);
2367 [ + + ]: 20 : SPDK_CU_ASSERT_FATAL(g_bs != NULL);
2368 : 20 : bs = g_bs;
2369 : :
2370 : : /* Try to open a blobid that does not exist */
2371 : 20 : spdk_bs_open_blob(bs, 0, blob_op_with_handle_complete, NULL);
2372 : 20 : poll_threads();
2373 : 20 : CU_ASSERT(g_bserrno == -ENOENT);
2374 : 20 : CU_ASSERT(g_blob == NULL);
2375 : :
2376 : : /* Create a blob */
2377 : 20 : blob = ut_blob_create_and_open(bs, NULL);
2378 : 20 : blobid = spdk_blob_get_id(blob);
2379 : :
2380 : : /* Try again to open valid blob but without the upper bit set */
2381 : 20 : spdk_bs_open_blob(bs, blobid & 0xFFFFFFFF, blob_op_with_handle_complete, NULL);
2382 : 20 : poll_threads();
2383 : 20 : CU_ASSERT(g_bserrno == -ENOENT);
2384 : 20 : CU_ASSERT(g_blob == NULL);
2385 : :
2386 : : /* Set some xattrs */
2387 : 20 : rc = spdk_blob_set_xattr(blob, "name", "log.txt", strlen("log.txt") + 1);
2388 : 20 : CU_ASSERT(rc == 0);
2389 : :
2390 : 20 : length = 2345;
2391 : 20 : rc = spdk_blob_set_xattr(blob, "length", &length, sizeof(length));
2392 : 20 : CU_ASSERT(rc == 0);
2393 : :
2394 : : /* Resize the blob */
2395 : 20 : spdk_blob_resize(blob, 10, blob_op_complete, NULL);
2396 : 20 : poll_threads();
2397 : 20 : CU_ASSERT(g_bserrno == 0);
2398 : :
2399 : 20 : spdk_blob_close(blob, blob_op_complete, NULL);
2400 : 20 : poll_threads();
2401 : 20 : CU_ASSERT(g_bserrno == 0);
2402 : 20 : blob = NULL;
2403 : 20 : g_blob = NULL;
2404 : 20 : g_blobid = SPDK_BLOBID_INVALID;
2405 : :
2406 : : /* Unload the blob store */
2407 : 20 : spdk_bs_unload(bs, bs_op_complete, NULL);
2408 : 20 : poll_threads();
2409 : 20 : CU_ASSERT(g_bserrno == 0);
2410 : 20 : g_bs = NULL;
2411 : 20 : g_blob = NULL;
2412 : 20 : g_blobid = 0;
2413 : :
2414 : 20 : super_block = (struct spdk_bs_super_block *)g_dev_buffer;
2415 : 20 : CU_ASSERT(super_block->clean == 1);
2416 : :
2417 : : /* Load should fail for device with an unsupported blocklen */
2418 : 20 : dev = init_dev();
2419 : 20 : dev->blocklen = g_phys_blocklen * 2;
2420 : 20 : spdk_bs_load(dev, NULL, bs_op_with_handle_complete, NULL);
2421 : 20 : poll_threads();
2422 : 20 : CU_ASSERT(g_bserrno == -EINVAL);
2423 : :
2424 : : /* Load should when max_md_ops is set to zero */
2425 : 20 : dev = init_dev();
2426 : 20 : spdk_bs_opts_init(&opts, sizeof(opts));
2427 : 20 : opts.max_md_ops = 0;
2428 : 20 : spdk_bs_load(dev, &opts, bs_op_with_handle_complete, NULL);
2429 : 20 : poll_threads();
2430 : 20 : CU_ASSERT(g_bserrno == -EINVAL);
2431 : :
2432 : : /* Load should when max_channel_ops is set to zero */
2433 : 20 : dev = init_dev();
2434 : 20 : spdk_bs_opts_init(&opts, sizeof(opts));
2435 : 20 : opts.max_channel_ops = 0;
2436 : 20 : spdk_bs_load(dev, &opts, bs_op_with_handle_complete, NULL);
2437 : 20 : poll_threads();
2438 : 20 : CU_ASSERT(g_bserrno == -EINVAL);
2439 : :
2440 : : /* Load an existing blob store */
2441 : 20 : dev = init_dev();
2442 : 20 : spdk_bs_opts_init(&opts, sizeof(opts));
2443 [ - + ]: 20 : snprintf(opts.bstype.bstype, sizeof(opts.bstype.bstype), "TESTTYPE");
2444 : 20 : spdk_bs_load(dev, &opts, bs_op_with_handle_complete, NULL);
2445 : 20 : poll_threads();
2446 : 20 : CU_ASSERT(g_bserrno == 0);
2447 [ + + ]: 20 : SPDK_CU_ASSERT_FATAL(g_bs != NULL);
2448 : 20 : bs = g_bs;
2449 : :
2450 : 20 : super_block = (struct spdk_bs_super_block *)g_dev_buffer;
2451 : 20 : CU_ASSERT(super_block->clean == 1);
2452 : 20 : CU_ASSERT(super_block->size == dev->blockcnt * dev->blocklen);
2453 : :
2454 : 20 : spdk_bs_open_blob(bs, blobid, blob_op_with_handle_complete, NULL);
2455 : 20 : poll_threads();
2456 : 20 : CU_ASSERT(g_bserrno == 0);
2457 : 20 : CU_ASSERT(g_blob != NULL);
2458 : 20 : blob = g_blob;
2459 : :
2460 : : /* Verify that blobstore is marked dirty after first metadata sync */
2461 : 20 : spdk_blob_sync_md(blob, blob_op_complete, NULL);
2462 : 20 : CU_ASSERT(super_block->clean == 1);
2463 : :
2464 : : /* Get the xattrs */
2465 : 20 : value = NULL;
2466 : 20 : rc = spdk_blob_get_xattr_value(blob, "length", &value, &value_len);
2467 : 20 : CU_ASSERT(rc == 0);
2468 [ + + ]: 20 : SPDK_CU_ASSERT_FATAL(value != NULL);
2469 : 20 : CU_ASSERT(*(uint64_t *)value == length);
2470 : 20 : CU_ASSERT(value_len == 8);
2471 : :
2472 : 20 : rc = spdk_blob_get_xattr_value(blob, "foobar", &value, &value_len);
2473 : 20 : CU_ASSERT(rc == -ENOENT);
2474 : :
2475 : 20 : CU_ASSERT(spdk_blob_get_num_clusters(blob) == 10);
2476 : 20 : CU_ASSERT(spdk_blob_get_num_allocated_clusters(blob) == 10);
2477 : :
2478 : 20 : spdk_blob_close(blob, blob_op_complete, NULL);
2479 : 20 : poll_threads();
2480 : 20 : CU_ASSERT(g_bserrno == 0);
2481 : 20 : blob = NULL;
2482 : 20 : g_blob = NULL;
2483 : :
2484 : 20 : spdk_bs_unload(bs, bs_op_complete, NULL);
2485 : 20 : poll_threads();
2486 : 20 : CU_ASSERT(g_bserrno == 0);
2487 : 20 : g_bs = NULL;
2488 : :
2489 : : /* Load should fail: bdev size < saved size */
2490 : 20 : dev = init_dev();
2491 : 20 : dev->blockcnt /= 2;
2492 : :
2493 : 20 : spdk_bs_opts_init(&opts, sizeof(opts));
2494 [ - + ]: 20 : snprintf(opts.bstype.bstype, sizeof(opts.bstype.bstype), "TESTTYPE");
2495 : 20 : spdk_bs_load(dev, &opts, bs_op_with_handle_complete, NULL);
2496 : 20 : poll_threads();
2497 : :
2498 : 20 : CU_ASSERT(g_bserrno == -EILSEQ);
2499 : :
2500 : : /* Load should succeed: bdev size > saved size */
2501 : 20 : dev = init_dev();
2502 : 20 : dev->blockcnt *= 4;
2503 : :
2504 : 20 : spdk_bs_opts_init(&opts, sizeof(opts));
2505 [ - + ]: 20 : snprintf(opts.bstype.bstype, sizeof(opts.bstype.bstype), "TESTTYPE");
2506 : 20 : spdk_bs_load(dev, &opts, bs_op_with_handle_complete, NULL);
2507 : 20 : poll_threads();
2508 : 20 : CU_ASSERT(g_bserrno == 0);
2509 [ + + ]: 20 : SPDK_CU_ASSERT_FATAL(g_bs != NULL);
2510 : 20 : bs = g_bs;
2511 : :
2512 : 20 : CU_ASSERT(g_bserrno == 0);
2513 : 20 : spdk_bs_unload(bs, bs_op_complete, NULL);
2514 : 20 : poll_threads();
2515 : :
2516 : :
2517 : : /* Test compatibility mode */
2518 : :
2519 : 20 : dev = init_dev();
2520 : 20 : super_block->size = 0;
2521 : 20 : super_block->crc = blob_md_page_calc_crc(super_block);
2522 : :
2523 : 20 : spdk_bs_opts_init(&opts, sizeof(opts));
2524 [ - + ]: 20 : snprintf(opts.bstype.bstype, sizeof(opts.bstype.bstype), "TESTTYPE");
2525 : 20 : spdk_bs_load(dev, &opts, bs_op_with_handle_complete, NULL);
2526 : 20 : poll_threads();
2527 : 20 : CU_ASSERT(g_bserrno == 0);
2528 [ - + ]: 20 : SPDK_CU_ASSERT_FATAL(g_bs != NULL);
2529 : 20 : bs = g_bs;
2530 : :
2531 : : /* Create a blob */
2532 : 20 : ut_spdk_blob_opts_init(&blob_opts);
2533 : 20 : spdk_bs_create_blob_ext(bs, &blob_opts, blob_op_with_id_complete, NULL);
2534 : 20 : poll_threads();
2535 : 20 : CU_ASSERT(g_bserrno == 0);
2536 : 20 : CU_ASSERT(g_blobid != SPDK_BLOBID_INVALID);
2537 : :
2538 : : /* Blobstore should update number of blocks in super_block */
2539 : 20 : CU_ASSERT(super_block->size == dev->blockcnt * dev->blocklen);
2540 : 20 : CU_ASSERT(super_block->clean == 0);
2541 : :
2542 : 20 : spdk_bs_unload(bs, bs_op_complete, NULL);
2543 : 20 : poll_threads();
2544 : 20 : CU_ASSERT(g_bserrno == 0);
2545 : 20 : CU_ASSERT(super_block->clean == 1);
2546 : 20 : g_bs = NULL;
2547 : :
2548 : 20 : }
2549 : :
2550 : : static void
2551 : 20 : bs_load_pending_removal(void)
2552 : : {
2553 : 20 : struct spdk_blob_store *bs = g_bs;
2554 : 15 : struct spdk_blob_opts opts;
2555 : : struct spdk_blob *blob, *snapshot;
2556 : 15 : spdk_blob_id blobid, snapshotid;
2557 : 15 : const void *value;
2558 : 15 : size_t value_len;
2559 : : int rc;
2560 : :
2561 : : /* Create blob */
2562 : 20 : ut_spdk_blob_opts_init(&opts);
2563 : 20 : opts.num_clusters = 10;
2564 : :
2565 : 20 : blob = ut_blob_create_and_open(bs, &opts);
2566 : 20 : blobid = spdk_blob_get_id(blob);
2567 : :
2568 : : /* Create snapshot */
2569 : 20 : spdk_bs_create_snapshot(bs, blobid, NULL, blob_op_with_id_complete, NULL);
2570 : 20 : poll_threads();
2571 : 20 : CU_ASSERT(g_bserrno == 0);
2572 : 20 : CU_ASSERT(g_blobid != SPDK_BLOBID_INVALID);
2573 : 20 : snapshotid = g_blobid;
2574 : :
2575 : 20 : spdk_bs_open_blob(bs, snapshotid, blob_op_with_handle_complete, NULL);
2576 : 20 : poll_threads();
2577 : 20 : CU_ASSERT(g_bserrno == 0);
2578 [ + + ]: 20 : SPDK_CU_ASSERT_FATAL(g_blob != NULL);
2579 : 20 : snapshot = g_blob;
2580 : :
2581 : : /* Set SNAPSHOT_PENDING_REMOVAL xattr */
2582 : 20 : snapshot->md_ro = false;
2583 : 20 : rc = blob_set_xattr(snapshot, SNAPSHOT_PENDING_REMOVAL, &blobid, sizeof(spdk_blob_id), true);
2584 : 20 : CU_ASSERT(rc == 0);
2585 : 20 : snapshot->md_ro = true;
2586 : :
2587 : 20 : spdk_blob_close(snapshot, blob_op_complete, NULL);
2588 : 20 : poll_threads();
2589 : 20 : CU_ASSERT(g_bserrno == 0);
2590 : :
2591 : 20 : spdk_blob_close(blob, blob_op_complete, NULL);
2592 : 20 : poll_threads();
2593 : 20 : CU_ASSERT(g_bserrno == 0);
2594 : :
2595 : : /* Reload blobstore */
2596 : 20 : ut_bs_reload(&bs, NULL);
2597 : :
2598 : : /* Snapshot should not be removed as blob is still pointing to it */
2599 : 20 : spdk_bs_open_blob(bs, snapshotid, blob_op_with_handle_complete, NULL);
2600 : 20 : poll_threads();
2601 : 20 : CU_ASSERT(g_bserrno == 0);
2602 [ + + ]: 20 : SPDK_CU_ASSERT_FATAL(g_blob != NULL);
2603 : 20 : snapshot = g_blob;
2604 : :
2605 : : /* SNAPSHOT_PENDING_REMOVAL xattr should be removed during load */
2606 : 20 : rc = spdk_blob_get_xattr_value(snapshot, SNAPSHOT_PENDING_REMOVAL, &value, &value_len);
2607 : 20 : CU_ASSERT(rc != 0);
2608 : :
2609 : : /* Set SNAPSHOT_PENDING_REMOVAL xattr again */
2610 : 20 : snapshot->md_ro = false;
2611 : 20 : rc = blob_set_xattr(snapshot, SNAPSHOT_PENDING_REMOVAL, &blobid, sizeof(spdk_blob_id), true);
2612 : 20 : CU_ASSERT(rc == 0);
2613 : 20 : snapshot->md_ro = true;
2614 : :
2615 : 20 : spdk_bs_open_blob(bs, blobid, blob_op_with_handle_complete, NULL);
2616 : 20 : poll_threads();
2617 : 20 : CU_ASSERT(g_bserrno == 0);
2618 [ - + ]: 20 : SPDK_CU_ASSERT_FATAL(g_blob != NULL);
2619 : 20 : blob = g_blob;
2620 : :
2621 : : /* Remove parent_id from blob by removing BLOB_SNAPSHOT xattr */
2622 : 20 : blob_remove_xattr(blob, BLOB_SNAPSHOT, true);
2623 : :
2624 : 20 : spdk_blob_sync_md(blob, blob_op_complete, NULL);
2625 : 20 : poll_threads();
2626 : 20 : CU_ASSERT(g_bserrno == 0);
2627 : :
2628 : 20 : spdk_blob_close(snapshot, blob_op_complete, NULL);
2629 : 20 : poll_threads();
2630 : 20 : CU_ASSERT(g_bserrno == 0);
2631 : :
2632 : 20 : spdk_blob_close(blob, blob_op_complete, NULL);
2633 : 20 : poll_threads();
2634 : 20 : CU_ASSERT(g_bserrno == 0);
2635 : :
2636 : : /* Reload blobstore */
2637 : 20 : ut_bs_reload(&bs, NULL);
2638 : :
2639 : : /* Snapshot should be removed as blob is not pointing to it anymore */
2640 : 20 : spdk_bs_open_blob(bs, snapshotid, blob_op_with_handle_complete, NULL);
2641 : 20 : poll_threads();
2642 : 20 : CU_ASSERT(g_bserrno != 0);
2643 : 20 : }
2644 : :
2645 : : static void
2646 : 20 : bs_load_custom_cluster_size(void)
2647 : : {
2648 : : struct spdk_blob_store *bs;
2649 : : struct spdk_bs_dev *dev;
2650 : : struct spdk_bs_super_block *super_block;
2651 : 15 : struct spdk_bs_opts opts;
2652 : 20 : uint32_t custom_cluster_size = 4194304; /* 4MiB */
2653 : : uint32_t cluster_sz;
2654 : : uint64_t total_clusters;
2655 : :
2656 : 20 : dev = init_dev();
2657 : 20 : spdk_bs_opts_init(&opts, sizeof(opts));
2658 : 20 : opts.cluster_sz = custom_cluster_size;
2659 [ - + ]: 20 : snprintf(opts.bstype.bstype, sizeof(opts.bstype.bstype), "TESTTYPE");
2660 : :
2661 : : /* Initialize a new blob store */
2662 : 20 : spdk_bs_init(dev, &opts, bs_op_with_handle_complete, NULL);
2663 : 20 : poll_threads();
2664 : 20 : CU_ASSERT(g_bserrno == 0);
2665 [ + + ]: 20 : SPDK_CU_ASSERT_FATAL(g_bs != NULL);
2666 : 20 : bs = g_bs;
2667 : 20 : cluster_sz = bs->cluster_sz;
2668 : 20 : total_clusters = bs->total_clusters;
2669 : :
2670 : : /* Unload the blob store */
2671 : 20 : spdk_bs_unload(bs, bs_op_complete, NULL);
2672 : 20 : poll_threads();
2673 : 20 : CU_ASSERT(g_bserrno == 0);
2674 : 20 : g_bs = NULL;
2675 : 20 : g_blob = NULL;
2676 : 20 : g_blobid = 0;
2677 : :
2678 : 20 : super_block = (struct spdk_bs_super_block *)g_dev_buffer;
2679 : 20 : CU_ASSERT(super_block->clean == 1);
2680 : :
2681 : : /* Load an existing blob store */
2682 : 20 : dev = init_dev();
2683 : 20 : spdk_bs_opts_init(&opts, sizeof(opts));
2684 [ - + ]: 20 : snprintf(opts.bstype.bstype, sizeof(opts.bstype.bstype), "TESTTYPE");
2685 : 20 : spdk_bs_load(dev, &opts, bs_op_with_handle_complete, NULL);
2686 : 20 : poll_threads();
2687 : 20 : CU_ASSERT(g_bserrno == 0);
2688 [ - + ]: 20 : SPDK_CU_ASSERT_FATAL(g_bs != NULL);
2689 : 20 : bs = g_bs;
2690 : : /* Compare cluster size and number to one after initialization */
2691 : 20 : CU_ASSERT(cluster_sz == bs->cluster_sz);
2692 : 20 : CU_ASSERT(total_clusters == bs->total_clusters);
2693 : :
2694 : 20 : super_block = (struct spdk_bs_super_block *)g_dev_buffer;
2695 : 20 : CU_ASSERT(super_block->clean == 1);
2696 : 20 : CU_ASSERT(super_block->size == dev->blockcnt * dev->blocklen);
2697 : :
2698 : 20 : spdk_bs_unload(bs, bs_op_complete, NULL);
2699 : 20 : poll_threads();
2700 : 20 : CU_ASSERT(g_bserrno == 0);
2701 : 20 : CU_ASSERT(super_block->clean == 1);
2702 : 20 : g_bs = NULL;
2703 : 20 : }
2704 : :
2705 : : static void
2706 : 20 : bs_load_after_failed_grow(void)
2707 : : {
2708 : : struct spdk_blob_store *bs;
2709 : : struct spdk_bs_dev *dev;
2710 : : struct spdk_bs_super_block *super_block;
2711 : 15 : struct spdk_bs_opts opts;
2712 : : struct spdk_bs_md_mask *mask;
2713 : 15 : struct spdk_blob_opts blob_opts;
2714 : : struct spdk_blob *blob, *snapshot;
2715 : : spdk_blob_id blobid, snapshotid;
2716 : : uint64_t total_data_clusters;
2717 : :
2718 : 20 : dev = init_dev();
2719 : 20 : spdk_bs_opts_init(&opts, sizeof(opts));
2720 [ - + ]: 20 : snprintf(opts.bstype.bstype, sizeof(opts.bstype.bstype), "TESTTYPE");
2721 : : /*
2722 : : * The bdev_size is 64M, cluster_sz is 1M, so there are 64 clusters. The
2723 : : * blobstore will create 64 md pages by default. We set num_md_pages to 128,
2724 : : * thus the blobstore could grow to the double size.
2725 : : */
2726 : 20 : opts.num_md_pages = 128;
2727 : :
2728 : : /* Initialize a new blob store */
2729 : 20 : spdk_bs_init(dev, &opts, bs_op_with_handle_complete, NULL);
2730 : 20 : poll_threads();
2731 : 20 : CU_ASSERT(g_bserrno == 0);
2732 [ + + ]: 20 : SPDK_CU_ASSERT_FATAL(g_bs != NULL);
2733 : 20 : bs = g_bs;
2734 : :
2735 : : /* Create blob */
2736 : 20 : ut_spdk_blob_opts_init(&blob_opts);
2737 : 20 : blob_opts.num_clusters = 10;
2738 : :
2739 : 20 : blob = ut_blob_create_and_open(bs, &blob_opts);
2740 : 20 : blobid = spdk_blob_get_id(blob);
2741 : :
2742 : : /* Create snapshot */
2743 : 20 : spdk_bs_create_snapshot(bs, blobid, NULL, blob_op_with_id_complete, NULL);
2744 : 20 : poll_threads();
2745 : 20 : CU_ASSERT(g_bserrno == 0);
2746 : 20 : CU_ASSERT(g_blobid != SPDK_BLOBID_INVALID);
2747 : 20 : snapshotid = g_blobid;
2748 : :
2749 : 20 : spdk_bs_open_blob(bs, snapshotid, blob_op_with_handle_complete, NULL);
2750 : 20 : poll_threads();
2751 : 20 : CU_ASSERT(g_bserrno == 0);
2752 [ + + ]: 20 : SPDK_CU_ASSERT_FATAL(g_blob != NULL);
2753 : 20 : snapshot = g_blob;
2754 : :
2755 : 20 : spdk_blob_close(snapshot, blob_op_complete, NULL);
2756 : 20 : poll_threads();
2757 : 20 : CU_ASSERT(g_bserrno == 0);
2758 : :
2759 : 20 : spdk_blob_close(blob, blob_op_complete, NULL);
2760 : 20 : poll_threads();
2761 : 20 : CU_ASSERT(g_bserrno == 0);
2762 : :
2763 : 20 : total_data_clusters = bs->total_data_clusters;
2764 : 20 : CU_ASSERT(bs->num_free_clusters + 10 == total_data_clusters);
2765 : :
2766 : : /* Unload the blob store */
2767 : 20 : spdk_bs_unload(bs, bs_op_complete, NULL);
2768 : 20 : poll_threads();
2769 : 20 : CU_ASSERT(g_bserrno == 0);
2770 : 20 : g_bs = NULL;
2771 : 20 : g_blob = NULL;
2772 : 20 : g_blobid = 0;
2773 : :
2774 : 20 : super_block = (struct spdk_bs_super_block *)g_dev_buffer;
2775 : 20 : CU_ASSERT(super_block->clean == 1);
2776 : :
2777 : 25 : mask = (struct spdk_bs_md_mask *)(g_dev_buffer + super_block->used_cluster_mask_start *
2778 : 5 : g_phys_blocklen);
2779 : 20 : CU_ASSERT(mask->type == SPDK_MD_MASK_TYPE_USED_CLUSTERS);
2780 [ - + ]: 20 : CU_ASSERT(mask->length == super_block->size / super_block->cluster_size);
2781 : :
2782 : : /*
2783 : : * We change the mask->length to emulate this scenario: A spdk_bs_grow failed after it changed
2784 : : * the used_cluster bitmap length, but it didn't change the super block yet.
2785 : : */
2786 : 20 : mask->length *= 2;
2787 : :
2788 : : /* Load an existing blob store */
2789 : 20 : dev = init_dev();
2790 : 20 : dev->blockcnt *= 2;
2791 : 20 : spdk_bs_opts_init(&opts, sizeof(opts));
2792 : 20 : opts.clear_method = BS_CLEAR_WITH_NONE;
2793 [ - + ]: 20 : snprintf(opts.bstype.bstype, sizeof(opts.bstype.bstype), "TESTTYPE");
2794 : 20 : spdk_bs_load(dev, &opts, bs_op_with_handle_complete, NULL);
2795 : 20 : poll_threads();
2796 : 20 : CU_ASSERT(g_bserrno == 0);
2797 [ + + ]: 20 : SPDK_CU_ASSERT_FATAL(g_bs != NULL);
2798 : 20 : bs = g_bs;
2799 : :
2800 : : /* Check the capacity is the same as before */
2801 : 20 : CU_ASSERT(bs->total_data_clusters == total_data_clusters);
2802 : 20 : CU_ASSERT(bs->num_free_clusters + 10 == total_data_clusters);
2803 : :
2804 : : /* Check the blob and the snapshot are still available */
2805 : 20 : spdk_bs_open_blob(bs, blobid, blob_op_with_handle_complete, NULL);
2806 : 20 : poll_threads();
2807 : 20 : CU_ASSERT(g_bserrno == 0);
2808 [ + + ]: 20 : SPDK_CU_ASSERT_FATAL(g_blob != NULL);
2809 : 20 : blob = g_blob;
2810 : :
2811 : 20 : spdk_blob_close(blob, blob_op_complete, NULL);
2812 : 20 : poll_threads();
2813 : 20 : CU_ASSERT(g_bserrno == 0);
2814 : :
2815 : 20 : spdk_bs_open_blob(bs, snapshotid, blob_op_with_handle_complete, NULL);
2816 : 20 : poll_threads();
2817 : 20 : CU_ASSERT(g_bserrno == 0);
2818 [ - + ]: 20 : SPDK_CU_ASSERT_FATAL(g_blob != NULL);
2819 : 20 : snapshot = g_blob;
2820 : :
2821 : 20 : spdk_blob_close(snapshot, blob_op_complete, NULL);
2822 : 20 : poll_threads();
2823 : 20 : CU_ASSERT(g_bserrno == 0);
2824 : :
2825 : 20 : spdk_bs_unload(bs, bs_op_complete, NULL);
2826 : 20 : poll_threads();
2827 : 20 : CU_ASSERT(g_bserrno == 0);
2828 : 20 : CU_ASSERT(super_block->clean == 1);
2829 : 20 : g_bs = NULL;
2830 : 20 : }
2831 : :
2832 : : static void
2833 : 20 : bs_load_error(void)
2834 : : {
2835 : : struct spdk_blob_store *bs;
2836 : : struct spdk_bs_dev *dev;
2837 : 15 : struct spdk_bs_opts opts;
2838 : 20 : struct spdk_power_failure_thresholds thresholds = {};
2839 : :
2840 : 20 : dev = init_dev();
2841 : 20 : spdk_bs_opts_init(&opts, sizeof(opts));
2842 [ - + ]: 20 : snprintf(opts.bstype.bstype, sizeof(opts.bstype.bstype), "TESTTYPE");
2843 : :
2844 : : /* Initialize a new blob store */
2845 : 20 : spdk_bs_init(dev, &opts, bs_op_with_handle_complete, NULL);
2846 : 20 : poll_threads();
2847 : 20 : CU_ASSERT(g_bserrno == 0);
2848 [ + + ]: 20 : SPDK_CU_ASSERT_FATAL(g_bs != NULL);
2849 : 20 : bs = g_bs;
2850 : :
2851 : : /* Unload the blob store */
2852 : 20 : spdk_bs_unload(bs, bs_op_complete, NULL);
2853 : 20 : poll_threads();
2854 : 20 : CU_ASSERT(g_bserrno == 0);
2855 : :
2856 : : /* Load fails with I/O error */
2857 : 20 : thresholds.general_threshold = 2;
2858 : 20 : dev_set_power_failure_thresholds(thresholds);
2859 : 20 : g_bserrno = -1;
2860 : 20 : dev = init_dev();
2861 : 20 : spdk_bs_load(dev, &opts, bs_op_with_handle_complete, NULL);
2862 : 20 : poll_threads();
2863 : 20 : CU_ASSERT(g_bserrno == -EIO);
2864 : 20 : CU_ASSERT(g_bs == NULL);
2865 : 20 : dev_reset_power_failure_event();
2866 : :
2867 : : /* Load fails with NOMEM error */
2868 : 20 : g_bserrno = -1;
2869 : 20 : dev = init_dev();
2870 : 20 : spdk_bs_load(dev, &opts, bs_op_with_handle_complete, NULL);
2871 : 20 : MOCK_SET(spdk_zmalloc, NULL);
2872 : 20 : poll_threads();
2873 : 20 : CU_ASSERT(g_bserrno == -ENOMEM);
2874 : 20 : CU_ASSERT(g_bs == NULL);
2875 [ - + - + ]: 20 : MOCK_CLEAR(spdk_zmalloc);
2876 : 20 : }
2877 : :
2878 : : static void
2879 : 20 : bs_type(void)
2880 : : {
2881 : : struct spdk_blob_store *bs;
2882 : : struct spdk_bs_dev *dev;
2883 : 15 : struct spdk_bs_opts opts;
2884 : :
2885 : 20 : dev = init_dev();
2886 : 20 : spdk_bs_opts_init(&opts, sizeof(opts));
2887 [ - + ]: 20 : snprintf(opts.bstype.bstype, sizeof(opts.bstype.bstype), "TESTTYPE");
2888 : :
2889 : : /* Initialize a new blob store */
2890 : 20 : spdk_bs_init(dev, &opts, bs_op_with_handle_complete, NULL);
2891 : 20 : poll_threads();
2892 : 20 : CU_ASSERT(g_bserrno == 0);
2893 [ + + ]: 20 : SPDK_CU_ASSERT_FATAL(g_bs != NULL);
2894 : 20 : bs = g_bs;
2895 : :
2896 : : /* Unload the blob store */
2897 : 20 : spdk_bs_unload(bs, bs_op_complete, NULL);
2898 : 20 : poll_threads();
2899 : 20 : CU_ASSERT(g_bserrno == 0);
2900 : 20 : g_bs = NULL;
2901 : 20 : g_blob = NULL;
2902 : 20 : g_blobid = 0;
2903 : :
2904 : : /* Load non existing blobstore type */
2905 : 20 : dev = init_dev();
2906 [ - + ]: 20 : snprintf(opts.bstype.bstype, sizeof(opts.bstype.bstype), "NONEXISTING");
2907 : 20 : spdk_bs_load(dev, &opts, bs_op_with_handle_complete, NULL);
2908 : 20 : poll_threads();
2909 : 20 : CU_ASSERT(g_bserrno != 0);
2910 : :
2911 : : /* Load with empty blobstore type */
2912 : 20 : dev = init_dev();
2913 [ - + ]: 20 : memset(opts.bstype.bstype, 0, sizeof(opts.bstype.bstype));
2914 : 20 : spdk_bs_load(dev, &opts, bs_op_with_handle_complete, NULL);
2915 : 20 : poll_threads();
2916 : 20 : CU_ASSERT(g_bserrno == 0);
2917 [ + + ]: 20 : SPDK_CU_ASSERT_FATAL(g_bs != NULL);
2918 : 20 : bs = g_bs;
2919 : :
2920 : 20 : spdk_bs_unload(bs, bs_op_complete, NULL);
2921 : 20 : poll_threads();
2922 : 20 : CU_ASSERT(g_bserrno == 0);
2923 : 20 : g_bs = NULL;
2924 : :
2925 : : /* Initialize a new blob store with empty bstype */
2926 : 20 : dev = init_dev();
2927 [ - + ]: 20 : memset(opts.bstype.bstype, 0, sizeof(opts.bstype.bstype));
2928 : 20 : spdk_bs_init(dev, NULL, bs_op_with_handle_complete, NULL);
2929 : 20 : poll_threads();
2930 : 20 : CU_ASSERT(g_bserrno == 0);
2931 [ + + ]: 20 : SPDK_CU_ASSERT_FATAL(g_bs != NULL);
2932 : 20 : bs = g_bs;
2933 : :
2934 : 20 : spdk_bs_unload(bs, bs_op_complete, NULL);
2935 : 20 : poll_threads();
2936 : 20 : CU_ASSERT(g_bserrno == 0);
2937 : 20 : g_bs = NULL;
2938 : :
2939 : : /* Load non existing blobstore type */
2940 : 20 : dev = init_dev();
2941 [ - + ]: 20 : snprintf(opts.bstype.bstype, sizeof(opts.bstype.bstype), "NONEXISTING");
2942 : 20 : spdk_bs_load(dev, &opts, bs_op_with_handle_complete, NULL);
2943 : 20 : poll_threads();
2944 : 20 : CU_ASSERT(g_bserrno != 0);
2945 : :
2946 : : /* Load with empty blobstore type */
2947 : 20 : dev = init_dev();
2948 [ - + ]: 20 : memset(opts.bstype.bstype, 0, sizeof(opts.bstype.bstype));
2949 : 20 : spdk_bs_load(dev, &opts, bs_op_with_handle_complete, NULL);
2950 : 20 : poll_threads();
2951 : 20 : CU_ASSERT(g_bserrno == 0);
2952 [ - + ]: 20 : SPDK_CU_ASSERT_FATAL(g_bs != NULL);
2953 : 20 : bs = g_bs;
2954 : :
2955 : 20 : spdk_bs_unload(bs, bs_op_complete, NULL);
2956 : 20 : poll_threads();
2957 : 20 : CU_ASSERT(g_bserrno == 0);
2958 : 20 : g_bs = NULL;
2959 : 20 : }
2960 : :
2961 : : static void
2962 : 20 : bs_super_block(void)
2963 : : {
2964 : : struct spdk_blob_store *bs;
2965 : : struct spdk_bs_dev *dev;
2966 : : struct spdk_bs_super_block *super_block;
2967 : 15 : struct spdk_bs_opts opts;
2968 : 15 : struct spdk_bs_super_block_ver1 super_block_v1;
2969 : :
2970 : 20 : dev = init_dev();
2971 : 20 : spdk_bs_opts_init(&opts, sizeof(opts));
2972 [ - + ]: 20 : snprintf(opts.bstype.bstype, sizeof(opts.bstype.bstype), "TESTTYPE");
2973 : :
2974 : : /* Initialize a new blob store */
2975 : 20 : spdk_bs_init(dev, &opts, bs_op_with_handle_complete, NULL);
2976 : 20 : poll_threads();
2977 : 20 : CU_ASSERT(g_bserrno == 0);
2978 [ + + ]: 20 : SPDK_CU_ASSERT_FATAL(g_bs != NULL);
2979 : 20 : bs = g_bs;
2980 : :
2981 : : /* Unload the blob store */
2982 : 20 : spdk_bs_unload(bs, bs_op_complete, NULL);
2983 : 20 : poll_threads();
2984 : 20 : CU_ASSERT(g_bserrno == 0);
2985 : 20 : g_bs = NULL;
2986 : 20 : g_blob = NULL;
2987 : 20 : g_blobid = 0;
2988 : :
2989 : : /* Load an existing blob store with version newer than supported */
2990 : 20 : super_block = (struct spdk_bs_super_block *)g_dev_buffer;
2991 : 20 : super_block->version++;
2992 : :
2993 : 20 : dev = init_dev();
2994 [ - + ]: 20 : memset(opts.bstype.bstype, 0, sizeof(opts.bstype.bstype));
2995 : 20 : spdk_bs_load(dev, &opts, bs_op_with_handle_complete, NULL);
2996 : 20 : poll_threads();
2997 : 20 : CU_ASSERT(g_bserrno != 0);
2998 : :
2999 : : /* Create a new blob store with super block version 1 */
3000 : 20 : dev = init_dev();
3001 : 20 : super_block_v1.version = 1;
3002 : 20 : memcpy(super_block_v1.signature, "SPDKBLOB", sizeof(super_block_v1.signature));
3003 : 20 : super_block_v1.length = 0x1000;
3004 : 20 : super_block_v1.clean = 1;
3005 : 20 : super_block_v1.super_blob = 0xFFFFFFFFFFFFFFFF;
3006 : 20 : super_block_v1.cluster_size = 0x100000;
3007 : 20 : super_block_v1.used_page_mask_start = 0x01;
3008 : 20 : super_block_v1.used_page_mask_len = 0x01;
3009 : 20 : super_block_v1.used_cluster_mask_start = 0x02;
3010 : 20 : super_block_v1.used_cluster_mask_len = 0x01;
3011 : 20 : super_block_v1.md_start = 0x03;
3012 : 20 : super_block_v1.md_len = 0x40;
3013 [ - + ]: 20 : memset(super_block_v1.reserved, 0, 4036);
3014 : 20 : super_block_v1.crc = blob_md_page_calc_crc(&super_block_v1);
3015 : 20 : memcpy(g_dev_buffer, &super_block_v1, sizeof(struct spdk_bs_super_block_ver1));
3016 : :
3017 [ - + ]: 20 : memset(opts.bstype.bstype, 0, sizeof(opts.bstype.bstype));
3018 : 20 : spdk_bs_load(dev, &opts, bs_op_with_handle_complete, NULL);
3019 : 20 : poll_threads();
3020 : 20 : CU_ASSERT(g_bserrno == 0);
3021 [ - + ]: 20 : SPDK_CU_ASSERT_FATAL(g_bs != NULL);
3022 : 20 : bs = g_bs;
3023 : :
3024 : 20 : spdk_bs_unload(bs, bs_op_complete, NULL);
3025 : 20 : poll_threads();
3026 : 20 : CU_ASSERT(g_bserrno == 0);
3027 : 20 : g_bs = NULL;
3028 : 20 : }
3029 : :
3030 : : static void
3031 : 20 : bs_test_recover_cluster_count(void)
3032 : : {
3033 : : struct spdk_blob_store *bs;
3034 : : struct spdk_bs_dev *dev;
3035 : 15 : struct spdk_bs_super_block super_block;
3036 : 15 : struct spdk_bs_opts opts;
3037 : :
3038 : 20 : dev = init_dev();
3039 : 20 : spdk_bs_opts_init(&opts, sizeof(opts));
3040 [ - + ]: 20 : snprintf(opts.bstype.bstype, sizeof(opts.bstype.bstype), "TESTTYPE");
3041 : :
3042 : 20 : super_block.version = 3;
3043 : 20 : memcpy(super_block.signature, "SPDKBLOB", sizeof(super_block.signature));
3044 : 20 : super_block.length = 0x1000;
3045 : 20 : super_block.clean = 0;
3046 : 20 : super_block.super_blob = 0xFFFFFFFFFFFFFFFF;
3047 : 20 : super_block.cluster_size = g_phys_blocklen;
3048 : 20 : super_block.used_page_mask_start = 0x01;
3049 : 20 : super_block.used_page_mask_len = 0x01;
3050 : 20 : super_block.used_cluster_mask_start = 0x02;
3051 : 20 : super_block.used_cluster_mask_len = 0x01;
3052 : 20 : super_block.used_blobid_mask_start = 0x03;
3053 : 20 : super_block.used_blobid_mask_len = 0x01;
3054 : 20 : super_block.md_page_size = g_phys_blocklen;
3055 : 20 : super_block.md_start = 0x04;
3056 : 20 : super_block.md_len = 0x40;
3057 [ - + ]: 20 : memset(super_block.bstype.bstype, 0, sizeof(super_block.bstype.bstype));
3058 : 20 : super_block.size = dev->blockcnt * dev->blocklen;
3059 : 20 : super_block.io_unit_size = 0x1000;
3060 [ - + ]: 20 : memset(super_block.reserved, 0, SPDK_SIZEOF_MEMBER(struct spdk_bs_super_block, reserved));
3061 : 20 : super_block.crc = blob_md_page_calc_crc(&super_block);
3062 : 20 : memcpy(g_dev_buffer, &super_block, sizeof(struct spdk_bs_super_block));
3063 : :
3064 [ - + ]: 20 : memset(opts.bstype.bstype, 0, sizeof(opts.bstype.bstype));
3065 : 20 : spdk_bs_load(dev, &opts, bs_op_with_handle_complete, NULL);
3066 : 20 : poll_threads();
3067 : 20 : CU_ASSERT(g_bserrno == 0);
3068 [ + + ]: 20 : SPDK_CU_ASSERT_FATAL(g_bs != NULL);
3069 : 20 : bs = g_bs;
3070 : 20 : CU_ASSERT(bs->num_free_clusters == bs->total_clusters - (super_block.md_start +
3071 : : super_block.md_len));
3072 : :
3073 : 20 : spdk_bs_unload(bs, bs_op_complete, NULL);
3074 : 20 : poll_threads();
3075 : 20 : CU_ASSERT(g_bserrno == 0);
3076 : 20 : g_bs = NULL;
3077 : 20 : }
3078 : :
3079 : : static void
3080 : 60 : bs_grow_live_size(uint64_t new_blockcnt)
3081 : : {
3082 : : struct spdk_blob_store *bs;
3083 : : struct spdk_bs_dev *dev;
3084 : 45 : struct spdk_bs_super_block super_block;
3085 : 45 : struct spdk_bs_opts opts;
3086 : 45 : struct spdk_bs_md_mask mask;
3087 : : uint64_t bdev_size;
3088 : : uint64_t total_data_clusters;
3089 : :
3090 : : /*
3091 : : * Further down the test the dev size will be larger than the g_dev_buffer size,
3092 : : * so we set clear_method to NONE, or the blobstore will try to clear the dev and
3093 : : * will write beyond the end of g_dev_buffer.
3094 : : */
3095 : 60 : dev = init_dev();
3096 : 60 : spdk_bs_opts_init(&opts, sizeof(opts));
3097 : 60 : opts.clear_method = BS_CLEAR_WITH_NONE;
3098 : 60 : spdk_bs_init(dev, &opts, bs_op_with_handle_complete, NULL);
3099 : 60 : poll_threads();
3100 : 60 : CU_ASSERT(g_bserrno == 0);
3101 [ + + ]: 60 : SPDK_CU_ASSERT_FATAL(g_bs != NULL);
3102 : 60 : bs = g_bs;
3103 : :
3104 : : /*
3105 : : * Set the dev size according to the new_blockcnt,
3106 : : * then the blobstore will adjust the metadata according to the new size.
3107 : : */
3108 : 60 : dev->blockcnt = new_blockcnt;
3109 : 60 : bdev_size = dev->blockcnt * dev->blocklen;
3110 : 60 : spdk_bs_grow_live(bs, bs_op_complete, NULL);
3111 : 60 : poll_threads();
3112 : 60 : CU_ASSERT(g_bserrno == 0);
3113 : 60 : total_data_clusters = spdk_bs_total_data_cluster_count(bs);
3114 : :
3115 : : /* Make sure the super block is updated. */
3116 : 60 : memcpy(&super_block, g_dev_buffer, sizeof(struct spdk_bs_super_block));
3117 : 60 : CU_ASSERT(super_block.size == bdev_size);
3118 : 60 : CU_ASSERT(super_block.clean == 0);
3119 : : /* The used_cluster mask is not written out until first spdk_bs_unload. */
3120 : 60 : memcpy(&mask, g_dev_buffer + super_block.used_cluster_mask_start * g_phys_blocklen,
3121 : : sizeof(struct spdk_bs_md_mask));
3122 : 60 : CU_ASSERT(mask.type == 0);
3123 : 60 : CU_ASSERT(mask.length == 0);
3124 : :
3125 : 60 : spdk_bs_unload(bs, bs_op_complete, NULL);
3126 : 60 : poll_threads();
3127 : 60 : CU_ASSERT(g_bserrno == 0);
3128 : 60 : g_bs = NULL;
3129 : :
3130 : : /* Make sure all metadata is correct, super block and used_cluster mask. */
3131 : 60 : memcpy(&super_block, g_dev_buffer, sizeof(struct spdk_bs_super_block));
3132 : 60 : CU_ASSERT(super_block.size == bdev_size);
3133 : 60 : CU_ASSERT(super_block.clean == 1);
3134 : 60 : memcpy(&mask, g_dev_buffer + super_block.used_cluster_mask_start * g_phys_blocklen,
3135 : : sizeof(struct spdk_bs_md_mask));
3136 : 60 : CU_ASSERT(mask.type == SPDK_MD_MASK_TYPE_USED_CLUSTERS);
3137 : 60 : CU_ASSERT(mask.length == bdev_size / (1 * 1024 * 1024));
3138 : :
3139 : : /* Load blobstore and check the cluster counts again. */
3140 : 60 : dev = init_dev();
3141 : 60 : dev->blockcnt = new_blockcnt;
3142 : 60 : spdk_bs_load(dev, NULL, bs_op_with_handle_complete, NULL);
3143 : 60 : poll_threads();
3144 : 60 : CU_ASSERT(g_bserrno == 0);
3145 [ - + ]: 60 : SPDK_CU_ASSERT_FATAL(g_bs != NULL);
3146 : 60 : CU_ASSERT(super_block.clean == 1);
3147 : 60 : bs = g_bs;
3148 : 60 : CU_ASSERT(total_data_clusters == spdk_bs_total_data_cluster_count(bs));
3149 : :
3150 : : /* Perform grow without change in size, expected pass. */
3151 : 60 : spdk_bs_grow_live(bs, bs_op_complete, NULL);
3152 : 60 : poll_threads();
3153 : 60 : CU_ASSERT(g_bserrno == 0);
3154 : 60 : CU_ASSERT(total_data_clusters == spdk_bs_total_data_cluster_count(bs));
3155 : 60 : memcpy(&super_block, g_dev_buffer, sizeof(struct spdk_bs_super_block));
3156 : 60 : CU_ASSERT(super_block.size == bdev_size);
3157 : 60 : CU_ASSERT(super_block.clean == 1);
3158 : :
3159 : 60 : spdk_bs_unload(bs, bs_op_complete, NULL);
3160 : 60 : poll_threads();
3161 : 60 : CU_ASSERT(g_bserrno == 0);
3162 : 60 : g_bs = NULL;
3163 : 60 : }
3164 : :
3165 : : static void
3166 : 20 : bs_grow_live(void)
3167 : : {
3168 : : /* No change expected */
3169 : 20 : bs_grow_live_size(DEV_BUFFER_BLOCKCNT);
3170 : :
3171 : : /* Size slightly increased, but not enough to increase cluster count */
3172 : 20 : bs_grow_live_size(DEV_BUFFER_BLOCKCNT + 1);
3173 : :
3174 : : /* Size doubled, increasing the cluster count */
3175 : 20 : bs_grow_live_size(DEV_BUFFER_BLOCKCNT * 2);
3176 : 20 : }
3177 : :
3178 : : static void
3179 : 20 : bs_grow_live_no_space(void)
3180 : : {
3181 : : struct spdk_blob_store *bs;
3182 : : struct spdk_bs_dev *dev;
3183 : 15 : struct spdk_bs_super_block super_block;
3184 : 15 : struct spdk_bs_opts opts;
3185 : 15 : struct spdk_bs_md_mask mask;
3186 : : uint64_t bdev_size_init;
3187 : : uint64_t total_data_clusters, max_clusters;
3188 : :
3189 : : /*
3190 : : * Further down the test the dev size will be larger than the g_dev_buffer size,
3191 : : * so we set clear_method to NONE, or the blobstore will try to clear the dev and
3192 : : * will write beyond the end of g_dev_buffer.
3193 : : */
3194 : 20 : dev = init_dev();
3195 : 20 : bdev_size_init = dev->blockcnt * dev->blocklen;
3196 : 20 : spdk_bs_opts_init(&opts, sizeof(opts));
3197 : 20 : opts.clear_method = BS_CLEAR_WITH_NONE;
3198 : 20 : spdk_bs_init(dev, &opts, bs_op_with_handle_complete, NULL);
3199 : 20 : poll_threads();
3200 : 20 : CU_ASSERT(g_bserrno == 0);
3201 [ + + ]: 20 : SPDK_CU_ASSERT_FATAL(g_bs != NULL);
3202 : 20 : bs = g_bs;
3203 : 20 : total_data_clusters = spdk_bs_total_data_cluster_count(bs);
3204 : :
3205 : : /*
3206 : : * The default dev size is 64M, here we set the dev size to 32M,
3207 : : * expecting EILSEQ due to super_block validation and no change in blobstore.
3208 : : */
3209 [ - + ]: 20 : dev->blockcnt = (32L * 1024L * 1024L) / dev->blocklen;
3210 : 20 : spdk_bs_grow_live(bs, bs_op_complete, NULL);
3211 : 20 : poll_threads();
3212 : : /* This error code comes from bs_super_validate() */
3213 : 20 : CU_ASSERT(g_bserrno == -EILSEQ);
3214 : 20 : CU_ASSERT(total_data_clusters == spdk_bs_total_data_cluster_count(bs));
3215 : 20 : memcpy(&super_block, g_dev_buffer, sizeof(struct spdk_bs_super_block));
3216 : 20 : CU_ASSERT(super_block.size == bdev_size_init);
3217 : :
3218 : : /*
3219 : : * Blobstore in this test has only space for single md_page for used_clusters,
3220 : : * which fits 1 bit per cluster minus the md header.
3221 : : *
3222 : : * Dev size is increased to exceed the reserved space for the used_cluster_mask
3223 : : * in the metadata, expecting ENOSPC and no change in blobstore.
3224 : : */
3225 : 20 : max_clusters = (spdk_bs_get_page_size(bs) - sizeof(struct spdk_bs_md_mask)) * 8;
3226 : 20 : max_clusters += 1;
3227 [ - + ]: 20 : dev->blockcnt = (max_clusters * spdk_bs_get_cluster_size(bs)) / dev->blocklen;
3228 : 20 : spdk_bs_grow_live(bs, bs_op_complete, NULL);
3229 : 20 : poll_threads();
3230 : 20 : CU_ASSERT(g_bserrno == -ENOSPC);
3231 : 20 : CU_ASSERT(total_data_clusters == spdk_bs_total_data_cluster_count(bs));
3232 : 20 : memcpy(&super_block, g_dev_buffer, sizeof(struct spdk_bs_super_block));
3233 : 20 : CU_ASSERT(super_block.size == bdev_size_init);
3234 : :
3235 : : /*
3236 : : * No change should have occurred for the duration of the test,
3237 : : * unload blobstore and check metadata.
3238 : : */
3239 : 20 : spdk_bs_unload(bs, bs_op_complete, NULL);
3240 : 20 : poll_threads();
3241 : 20 : CU_ASSERT(g_bserrno == 0);
3242 : 20 : g_bs = NULL;
3243 : :
3244 : : /* Make sure all metadata is correct, super block and used_cluster mask. */
3245 : 20 : memcpy(&super_block, g_dev_buffer, sizeof(struct spdk_bs_super_block));
3246 : 20 : CU_ASSERT(super_block.size == bdev_size_init);
3247 : 20 : CU_ASSERT(super_block.clean == 1);
3248 : 20 : memcpy(&mask, g_dev_buffer + super_block.used_cluster_mask_start * g_phys_blocklen,
3249 : : sizeof(struct spdk_bs_md_mask));
3250 : 20 : CU_ASSERT(mask.type == SPDK_MD_MASK_TYPE_USED_CLUSTERS);
3251 : 20 : CU_ASSERT(mask.length == bdev_size_init / (1 * 1024 * 1024));
3252 : :
3253 : : /* Load blobstore and check the cluster counts again. */
3254 : 20 : dev = init_dev();
3255 : 20 : spdk_bs_load(dev, NULL, bs_op_with_handle_complete, NULL);
3256 : 20 : poll_threads();
3257 : 20 : CU_ASSERT(g_bserrno == 0);
3258 [ - + ]: 20 : SPDK_CU_ASSERT_FATAL(g_bs != NULL);
3259 : 20 : bs = g_bs;
3260 : 20 : CU_ASSERT(total_data_clusters == spdk_bs_total_data_cluster_count(bs));
3261 : :
3262 : 20 : spdk_bs_unload(bs, bs_op_complete, NULL);
3263 : 20 : poll_threads();
3264 : 20 : CU_ASSERT(g_bserrno == 0);
3265 : 20 : g_bs = NULL;
3266 : 20 : }
3267 : :
3268 : : static void
3269 : 20 : bs_test_grow(void)
3270 : : {
3271 : : struct spdk_blob_store *bs;
3272 : : struct spdk_bs_dev *dev;
3273 : 15 : struct spdk_bs_super_block super_block;
3274 : 15 : struct spdk_bs_opts opts;
3275 : 15 : struct spdk_bs_md_mask mask;
3276 : : uint64_t bdev_size;
3277 : :
3278 : 20 : dev = init_dev();
3279 : 20 : bdev_size = dev->blockcnt * dev->blocklen;
3280 : 20 : spdk_bs_opts_init(&opts, sizeof(opts));
3281 : 20 : spdk_bs_init(dev, &opts, bs_op_with_handle_complete, NULL);
3282 : 20 : poll_threads();
3283 : 20 : CU_ASSERT(g_bserrno == 0);
3284 [ + + ]: 20 : SPDK_CU_ASSERT_FATAL(g_bs != NULL);
3285 : 20 : bs = g_bs;
3286 : :
3287 : 20 : spdk_bs_unload(bs, bs_op_complete, NULL);
3288 : 20 : poll_threads();
3289 : 20 : CU_ASSERT(g_bserrno == 0);
3290 : 20 : g_bs = NULL;
3291 : :
3292 : : /*
3293 : : * To make sure all the metadata are updated to the disk,
3294 : : * we check the g_dev_buffer after spdk_bs_unload.
3295 : : */
3296 : 20 : memcpy(&super_block, g_dev_buffer, sizeof(struct spdk_bs_super_block));
3297 : 20 : CU_ASSERT(super_block.size == bdev_size);
3298 : :
3299 : : /*
3300 : : * Make sure the used_cluster mask is correct.
3301 : : */
3302 : 20 : memcpy(&mask, g_dev_buffer + super_block.used_cluster_mask_start * g_phys_blocklen,
3303 : : sizeof(struct spdk_bs_md_mask));
3304 : 20 : CU_ASSERT(mask.type == SPDK_MD_MASK_TYPE_USED_CLUSTERS);
3305 : 20 : CU_ASSERT(mask.length == bdev_size / (1 * 1024 * 1024));
3306 : :
3307 : : /*
3308 : : * The default dev size is 64M, here we set the dev size to 128M,
3309 : : * then the blobstore will adjust the metadata according to the new size.
3310 : : * The dev size is larger than the g_dev_buffer size, so we set clear_method
3311 : : * to NONE, or the blobstore will try to clear the dev and will write beyond
3312 : : * the end of g_dev_buffer.
3313 : : */
3314 : 20 : dev = init_dev();
3315 [ - + ]: 20 : dev->blockcnt = (128L * 1024L * 1024L) / dev->blocklen;
3316 : 20 : bdev_size = dev->blockcnt * dev->blocklen;
3317 : 20 : spdk_bs_opts_init(&opts, sizeof(opts));
3318 : 20 : opts.clear_method = BS_CLEAR_WITH_NONE;
3319 : 20 : spdk_bs_grow(dev, &opts, bs_op_with_handle_complete, NULL);
3320 : 20 : poll_threads();
3321 : 20 : CU_ASSERT(g_bserrno == 0);
3322 [ - + ]: 20 : SPDK_CU_ASSERT_FATAL(g_bs != NULL);
3323 : 20 : bs = g_bs;
3324 : :
3325 : : /*
3326 : : * After spdk_bs_grow, all metadata are updated to the disk.
3327 : : * So we can check g_dev_buffer now.
3328 : : */
3329 : 20 : memcpy(&super_block, g_dev_buffer, sizeof(struct spdk_bs_super_block));
3330 : 20 : CU_ASSERT(super_block.size == bdev_size);
3331 : :
3332 : : /*
3333 : : * Make sure the used_cluster mask has been updated according to the bdev size
3334 : : */
3335 : 20 : memcpy(&mask, g_dev_buffer + super_block.used_cluster_mask_start * g_phys_blocklen,
3336 : : sizeof(struct spdk_bs_md_mask));
3337 : 20 : CU_ASSERT(mask.type == SPDK_MD_MASK_TYPE_USED_CLUSTERS);
3338 : 20 : CU_ASSERT(mask.length == bdev_size / (1 * 1024 * 1024));
3339 : :
3340 : 20 : spdk_bs_unload(bs, bs_op_complete, NULL);
3341 : 20 : poll_threads();
3342 : 20 : CU_ASSERT(g_bserrno == 0);
3343 : 20 : g_bs = NULL;
3344 : 20 : }
3345 : :
3346 : : /*
3347 : : * Create a blobstore and then unload it.
3348 : : */
3349 : : static void
3350 : 20 : bs_unload(void)
3351 : : {
3352 : 20 : struct spdk_blob_store *bs = g_bs;
3353 : : struct spdk_blob *blob;
3354 : :
3355 : : /* Create a blob and open it. */
3356 : 20 : blob = ut_blob_create_and_open(bs, NULL);
3357 : :
3358 : : /* Try to unload blobstore, should fail with open blob */
3359 : 20 : g_bserrno = -1;
3360 : 20 : spdk_bs_unload(bs, bs_op_complete, NULL);
3361 : 20 : poll_threads();
3362 : 20 : CU_ASSERT(g_bserrno == -EBUSY);
3363 [ + + ]: 20 : SPDK_CU_ASSERT_FATAL(g_bs != NULL);
3364 : :
3365 : : /* Close the blob, then successfully unload blobstore */
3366 : 20 : g_bserrno = -1;
3367 : 20 : spdk_blob_close(blob, blob_op_complete, NULL);
3368 : 20 : poll_threads();
3369 : 20 : CU_ASSERT(g_bserrno == 0);
3370 : 20 : }
3371 : :
3372 : : /*
3373 : : * Create a blobstore with a cluster size different than the default, and ensure it is
3374 : : * persisted.
3375 : : */
3376 : : static void
3377 : 20 : bs_cluster_sz(void)
3378 : : {
3379 : 15 : struct spdk_blob_store *bs;
3380 : : struct spdk_bs_dev *dev;
3381 : 15 : struct spdk_bs_opts opts;
3382 : : uint32_t cluster_sz;
3383 : :
3384 : : /* Set cluster size to zero */
3385 : 20 : dev = init_dev();
3386 : 20 : spdk_bs_opts_init(&opts, sizeof(opts));
3387 : 20 : opts.cluster_sz = 0;
3388 : :
3389 : : /* Initialize a new blob store */
3390 : 20 : spdk_bs_init(dev, &opts, bs_op_with_handle_complete, NULL);
3391 : 20 : poll_threads();
3392 : 20 : CU_ASSERT(g_bserrno == -EINVAL);
3393 [ + + ]: 20 : SPDK_CU_ASSERT_FATAL(g_bs == NULL);
3394 : :
3395 : : /*
3396 : : * Set cluster size to blobstore page size,
3397 : : * to work it is required to be at least twice the blobstore page size.
3398 : : */
3399 : 20 : dev = init_dev();
3400 : 20 : spdk_bs_opts_init(&opts, sizeof(opts));
3401 : 20 : opts.cluster_sz = g_phys_blocklen;
3402 : :
3403 : : /* Initialize a new blob store */
3404 : 20 : spdk_bs_init(dev, &opts, bs_op_with_handle_complete, NULL);
3405 : 20 : poll_threads();
3406 : 20 : CU_ASSERT(g_bserrno == -ENOMEM);
3407 [ + + ]: 20 : SPDK_CU_ASSERT_FATAL(g_bs == NULL);
3408 : :
3409 : : /*
3410 : : * Set cluster size to lower than page size,
3411 : : * to work it is required to be at least twice the blobstore page size.
3412 : : */
3413 : 20 : dev = init_dev();
3414 : 20 : spdk_bs_opts_init(&opts, sizeof(opts));
3415 : 20 : opts.cluster_sz = g_phys_blocklen - 1;
3416 : :
3417 : : /* Initialize a new blob store */
3418 : 20 : spdk_bs_init(dev, &opts, bs_op_with_handle_complete, NULL);
3419 : 20 : poll_threads();
3420 : 20 : CU_ASSERT(g_bserrno == -EINVAL);
3421 [ + + ]: 20 : SPDK_CU_ASSERT_FATAL(g_bs == NULL);
3422 : :
3423 : : /* Set cluster size to twice the default */
3424 : 20 : dev = init_dev();
3425 : 20 : spdk_bs_opts_init(&opts, sizeof(opts));
3426 : 20 : opts.cluster_sz *= 2;
3427 : 20 : cluster_sz = opts.cluster_sz;
3428 : :
3429 : : /* Initialize a new blob store */
3430 : 20 : spdk_bs_init(dev, &opts, bs_op_with_handle_complete, NULL);
3431 : 20 : poll_threads();
3432 : 20 : CU_ASSERT(g_bserrno == 0);
3433 [ - + ]: 20 : SPDK_CU_ASSERT_FATAL(g_bs != NULL);
3434 : 20 : bs = g_bs;
3435 : :
3436 : 20 : CU_ASSERT(spdk_bs_get_cluster_size(bs) == cluster_sz);
3437 : :
3438 : 20 : ut_bs_reload(&bs, &opts);
3439 : :
3440 : 20 : CU_ASSERT(spdk_bs_get_cluster_size(bs) == cluster_sz);
3441 : :
3442 : 20 : spdk_bs_unload(bs, bs_op_complete, NULL);
3443 : 20 : poll_threads();
3444 : 20 : CU_ASSERT(g_bserrno == 0);
3445 : 20 : g_bs = NULL;
3446 : 20 : }
3447 : :
3448 : : /*
3449 : : * Create a blobstore, reload it and ensure total usable cluster count
3450 : : * stays the same.
3451 : : */
3452 : : static void
3453 : 20 : bs_usable_clusters(void)
3454 : : {
3455 : 20 : struct spdk_blob_store *bs = g_bs;
3456 : : struct spdk_blob *blob;
3457 : : uint32_t clusters;
3458 : : int i;
3459 : :
3460 : :
3461 : 20 : clusters = spdk_bs_total_data_cluster_count(bs);
3462 : :
3463 : 20 : ut_bs_reload(&bs, NULL);
3464 : :
3465 : 20 : CU_ASSERT(spdk_bs_total_data_cluster_count(bs) == clusters);
3466 : :
3467 : : /* Create and resize blobs to make sure that usable cluster count won't change */
3468 [ + + ]: 100 : for (i = 0; i < 4; i++) {
3469 : 80 : g_bserrno = -1;
3470 : 80 : g_blobid = SPDK_BLOBID_INVALID;
3471 : 80 : blob = ut_blob_create_and_open(bs, NULL);
3472 : :
3473 : 80 : spdk_blob_resize(blob, 10, blob_op_complete, NULL);
3474 : 80 : poll_threads();
3475 : 80 : CU_ASSERT(g_bserrno == 0);
3476 : :
3477 : 80 : g_bserrno = -1;
3478 : 80 : spdk_blob_close(blob, blob_op_complete, NULL);
3479 : 80 : poll_threads();
3480 : 80 : CU_ASSERT(g_bserrno == 0);
3481 : :
3482 : 80 : CU_ASSERT(spdk_bs_total_data_cluster_count(bs) == clusters);
3483 : 20 : }
3484 : :
3485 : : /* Reload the blob store to make sure that nothing changed */
3486 : 20 : ut_bs_reload(&bs, NULL);
3487 : :
3488 : 20 : CU_ASSERT(spdk_bs_total_data_cluster_count(bs) == clusters);
3489 : 20 : }
3490 : :
3491 : : /*
3492 : : * Test resizing of the metadata blob. This requires creating enough blobs
3493 : : * so that one cluster is not enough to fit the metadata for those blobs.
3494 : : * To induce this condition to happen more quickly, we reduce the cluster
3495 : : * size to 16KB, which means only 4 4KB blob metadata pages can fit.
3496 : : */
3497 : : static void
3498 : 20 : bs_resize_md(void)
3499 : 15 : {
3500 : 15 : struct spdk_blob_store *bs;
3501 : 20 : const int CLUSTER_PAGE_COUNT = 4;
3502 : 20 : const int NUM_BLOBS = CLUSTER_PAGE_COUNT * 4;
3503 : : struct spdk_bs_dev *dev;
3504 : 15 : struct spdk_bs_opts opts;
3505 : : struct spdk_blob *blob;
3506 : 15 : struct spdk_blob_opts blob_opts;
3507 : : uint32_t cluster_sz;
3508 [ - + ]: 20 : spdk_blob_id blobids[NUM_BLOBS];
3509 : : int i;
3510 : :
3511 : :
3512 : 20 : dev = init_dev();
3513 : 20 : spdk_bs_opts_init(&opts, sizeof(opts));
3514 : 20 : opts.cluster_sz = CLUSTER_PAGE_COUNT * g_phys_blocklen;
3515 : 20 : cluster_sz = opts.cluster_sz;
3516 : :
3517 : : /* Initialize a new blob store */
3518 : 20 : spdk_bs_init(dev, &opts, bs_op_with_handle_complete, NULL);
3519 : 20 : poll_threads();
3520 : 20 : CU_ASSERT(g_bserrno == 0);
3521 [ + + ]: 20 : SPDK_CU_ASSERT_FATAL(g_bs != NULL);
3522 : 20 : bs = g_bs;
3523 : :
3524 : 20 : CU_ASSERT(spdk_bs_get_cluster_size(bs) == cluster_sz);
3525 : :
3526 : 20 : ut_spdk_blob_opts_init(&blob_opts);
3527 : :
3528 [ + + ]: 340 : for (i = 0; i < NUM_BLOBS; i++) {
3529 : 320 : g_bserrno = -1;
3530 : 320 : g_blobid = SPDK_BLOBID_INVALID;
3531 : 320 : spdk_bs_create_blob_ext(bs, &blob_opts, blob_op_with_id_complete, NULL);
3532 : 320 : poll_threads();
3533 : 320 : CU_ASSERT(g_bserrno == 0);
3534 : 320 : CU_ASSERT(g_blobid != SPDK_BLOBID_INVALID);
3535 : 320 : blobids[i] = g_blobid;
3536 : 80 : }
3537 : :
3538 : 20 : ut_bs_reload(&bs, &opts);
3539 : :
3540 : 20 : CU_ASSERT(spdk_bs_get_cluster_size(bs) == cluster_sz);
3541 : :
3542 [ + + ]: 340 : for (i = 0; i < NUM_BLOBS; i++) {
3543 : 320 : g_bserrno = -1;
3544 : 320 : g_blob = NULL;
3545 : 320 : spdk_bs_open_blob(bs, blobids[i], blob_op_with_handle_complete, NULL);
3546 : 320 : poll_threads();
3547 : 320 : CU_ASSERT(g_bserrno == 0);
3548 : 320 : CU_ASSERT(g_blob != NULL);
3549 : 320 : blob = g_blob;
3550 : 320 : g_bserrno = -1;
3551 : 320 : spdk_blob_close(blob, blob_op_complete, NULL);
3552 : 320 : poll_threads();
3553 : 320 : CU_ASSERT(g_bserrno == 0);
3554 : 80 : }
3555 : :
3556 : 20 : spdk_bs_unload(bs, bs_op_complete, NULL);
3557 : 20 : poll_threads();
3558 : 20 : CU_ASSERT(g_bserrno == 0);
3559 : 20 : g_bs = NULL;
3560 : 20 : }
3561 : :
3562 : : static void
3563 : 20 : bs_destroy(void)
3564 : : {
3565 : : struct spdk_blob_store *bs;
3566 : : struct spdk_bs_dev *dev;
3567 : :
3568 : : /* Initialize a new blob store */
3569 : 20 : dev = init_dev();
3570 : 20 : spdk_bs_init(dev, NULL, bs_op_with_handle_complete, NULL);
3571 : 20 : poll_threads();
3572 : 20 : CU_ASSERT(g_bserrno == 0);
3573 [ + + ]: 20 : SPDK_CU_ASSERT_FATAL(g_bs != NULL);
3574 : 20 : bs = g_bs;
3575 : :
3576 : : /* Destroy the blob store */
3577 : 20 : g_bserrno = -1;
3578 : 20 : spdk_bs_destroy(bs, bs_op_complete, NULL);
3579 : 20 : poll_threads();
3580 : 20 : CU_ASSERT(g_bserrno == 0);
3581 : :
3582 : : /* Loading an non-existent blob store should fail. */
3583 : 20 : g_bs = NULL;
3584 : 20 : dev = init_dev();
3585 : :
3586 : 20 : g_bserrno = 0;
3587 : 20 : spdk_bs_load(dev, NULL, bs_op_with_handle_complete, NULL);
3588 : 20 : poll_threads();
3589 : 20 : CU_ASSERT(g_bserrno != 0);
3590 : 20 : }
3591 : :
3592 : : /* Try to hit all of the corner cases associated with serializing
3593 : : * a blob to disk
3594 : : */
3595 : : static void
3596 : 20 : blob_serialize_test(void)
3597 : : {
3598 : : struct spdk_bs_dev *dev;
3599 : 15 : struct spdk_bs_opts opts;
3600 : 15 : struct spdk_blob_store *bs;
3601 : 15 : spdk_blob_id blobid[2];
3602 : 15 : struct spdk_blob *blob[2];
3603 : : uint64_t i;
3604 : : char *value;
3605 : : int rc;
3606 : :
3607 : 20 : dev = init_dev();
3608 : :
3609 : : /* Initialize a new blobstore with very small clusters */
3610 : 20 : spdk_bs_opts_init(&opts, sizeof(opts));
3611 : 20 : opts.cluster_sz = dev->blocklen * 8;
3612 : 20 : spdk_bs_init(dev, &opts, bs_op_with_handle_complete, NULL);
3613 : 20 : poll_threads();
3614 : 20 : CU_ASSERT(g_bserrno == 0);
3615 [ + + ]: 20 : SPDK_CU_ASSERT_FATAL(g_bs != NULL);
3616 : 20 : bs = g_bs;
3617 : :
3618 : : /* Create and open two blobs */
3619 [ + + ]: 60 : for (i = 0; i < 2; i++) {
3620 : 40 : blob[i] = ut_blob_create_and_open(bs, NULL);
3621 : 40 : blobid[i] = spdk_blob_get_id(blob[i]);
3622 : :
3623 : : /* Set a fairly large xattr on both blobs to eat up
3624 : : * metadata space
3625 : : */
3626 : 40 : value = calloc(dev->blocklen - 64, sizeof(char));
3627 [ + + ]: 40 : SPDK_CU_ASSERT_FATAL(value != NULL);
3628 [ - + ]: 40 : memset(value, i, dev->blocklen / 2);
3629 : 40 : rc = spdk_blob_set_xattr(blob[i], "name", value, dev->blocklen - 64);
3630 : 40 : CU_ASSERT(rc == 0);
3631 : 40 : free(value);
3632 : 10 : }
3633 : :
3634 : : /* Resize the blobs, alternating 1 cluster at a time.
3635 : : * This thwarts run length encoding and will cause spill
3636 : : * over of the extents.
3637 : : */
3638 [ + + ]: 140 : for (i = 0; i < 6; i++) {
3639 : 120 : spdk_blob_resize(blob[i % 2], (i / 2) + 1, blob_op_complete, NULL);
3640 : 120 : poll_threads();
3641 : 120 : CU_ASSERT(g_bserrno == 0);
3642 : 30 : }
3643 : :
3644 [ + + ]: 60 : for (i = 0; i < 2; i++) {
3645 : 40 : spdk_blob_sync_md(blob[i], blob_op_complete, NULL);
3646 : 40 : poll_threads();
3647 : 40 : CU_ASSERT(g_bserrno == 0);
3648 : 10 : }
3649 : :
3650 : : /* Close the blobs */
3651 [ + + ]: 60 : for (i = 0; i < 2; i++) {
3652 : 40 : spdk_blob_close(blob[i], blob_op_complete, NULL);
3653 : 40 : poll_threads();
3654 : 40 : CU_ASSERT(g_bserrno == 0);
3655 : 10 : }
3656 : :
3657 : 20 : ut_bs_reload(&bs, &opts);
3658 : :
3659 [ + + ]: 60 : for (i = 0; i < 2; i++) {
3660 : 40 : blob[i] = NULL;
3661 : :
3662 : 40 : spdk_bs_open_blob(bs, blobid[i], blob_op_with_handle_complete, NULL);
3663 : 40 : poll_threads();
3664 : 40 : CU_ASSERT(g_bserrno == 0);
3665 : 40 : CU_ASSERT(g_blob != NULL);
3666 : 40 : blob[i] = g_blob;
3667 : :
3668 : 40 : CU_ASSERT(spdk_blob_get_num_clusters(blob[i]) == 3);
3669 : :
3670 : 40 : spdk_blob_close(blob[i], blob_op_complete, NULL);
3671 : 40 : poll_threads();
3672 : 40 : CU_ASSERT(g_bserrno == 0);
3673 : 10 : }
3674 : :
3675 : 20 : spdk_bs_unload(bs, bs_op_complete, NULL);
3676 : 20 : poll_threads();
3677 : 20 : CU_ASSERT(g_bserrno == 0);
3678 : 20 : g_bs = NULL;
3679 : 20 : }
3680 : :
3681 : : static void
3682 : 20 : blob_crc(void)
3683 : : {
3684 : 20 : struct spdk_blob_store *bs = g_bs;
3685 : : struct spdk_blob *blob;
3686 : : spdk_blob_id blobid;
3687 : : uint32_t page_num;
3688 : : int index;
3689 : : struct spdk_blob_md_page *page;
3690 : :
3691 : 20 : blob = ut_blob_create_and_open(bs, NULL);
3692 : 20 : blobid = spdk_blob_get_id(blob);
3693 : :
3694 : 20 : spdk_blob_close(blob, blob_op_complete, NULL);
3695 : 20 : poll_threads();
3696 : 20 : CU_ASSERT(g_bserrno == 0);
3697 : :
3698 : 20 : page_num = bs_blobid_to_page(blobid);
3699 : 20 : index = g_phys_blocklen * (bs->md_start + page_num);
3700 : 20 : page = (struct spdk_blob_md_page *)&g_dev_buffer[index];
3701 : 20 : page->crc = 0;
3702 : :
3703 : 20 : spdk_bs_open_blob(bs, blobid, blob_op_with_handle_complete, NULL);
3704 : 20 : poll_threads();
3705 : 20 : CU_ASSERT(g_bserrno == -EINVAL);
3706 : 20 : CU_ASSERT(g_blob == NULL);
3707 : 20 : g_bserrno = 0;
3708 : :
3709 : 20 : spdk_bs_delete_blob(bs, blobid, blob_op_complete, NULL);
3710 : 20 : poll_threads();
3711 : 20 : CU_ASSERT(g_bserrno == -EINVAL);
3712 : 20 : }
3713 : :
3714 : : static void
3715 : 20 : super_block_crc(void)
3716 : : {
3717 : : struct spdk_blob_store *bs;
3718 : : struct spdk_bs_dev *dev;
3719 : : struct spdk_bs_super_block *super_block;
3720 : :
3721 : 20 : dev = init_dev();
3722 : 20 : spdk_bs_init(dev, NULL, bs_op_with_handle_complete, NULL);
3723 : 20 : poll_threads();
3724 : 20 : CU_ASSERT(g_bserrno == 0);
3725 [ + + ]: 20 : SPDK_CU_ASSERT_FATAL(g_bs != NULL);
3726 : 20 : bs = g_bs;
3727 : :
3728 : 20 : spdk_bs_unload(bs, bs_op_complete, NULL);
3729 : 20 : poll_threads();
3730 : 20 : CU_ASSERT(g_bserrno == 0);
3731 : 20 : g_bs = NULL;
3732 : :
3733 : 20 : super_block = (struct spdk_bs_super_block *)g_dev_buffer;
3734 : 20 : super_block->crc = 0;
3735 : 20 : dev = init_dev();
3736 : :
3737 : : /* Load an existing blob store */
3738 : 20 : g_bserrno = 0;
3739 : 20 : spdk_bs_load(dev, NULL, bs_op_with_handle_complete, NULL);
3740 : 20 : poll_threads();
3741 : 20 : CU_ASSERT(g_bserrno == -EILSEQ);
3742 : 20 : }
3743 : :
3744 : : /* For blob dirty shutdown test case we do the following sub-test cases:
3745 : : * 1 Initialize new blob store and create 1 super blob with some xattrs, then we
3746 : : * dirty shutdown and reload the blob store and verify the xattrs.
3747 : : * 2 Resize the blob from 10 clusters to 20 clusters and then dirty shutdown,
3748 : : * reload the blob store and verify the clusters number.
3749 : : * 3 Create the second blob and then dirty shutdown, reload the blob store
3750 : : * and verify the second blob.
3751 : : * 4 Delete the second blob and then dirty shutdown, reload the blob store
3752 : : * and verify the second blob is invalid.
3753 : : * 5 Create the second blob again and also create the third blob, modify the
3754 : : * md of second blob which makes the md invalid, and then dirty shutdown,
3755 : : * reload the blob store verify the second blob, it should invalid and also
3756 : : * verify the third blob, it should correct.
3757 : : */
3758 : : static void
3759 : 20 : blob_dirty_shutdown(void)
3760 : : {
3761 : : int rc;
3762 : : int index;
3763 : 20 : struct spdk_blob_store *bs = g_bs;
3764 : : spdk_blob_id blobid1, blobid2, blobid3;
3765 : 20 : struct spdk_blob *blob = g_blob;
3766 : 15 : uint64_t length;
3767 : : uint64_t free_clusters;
3768 : 15 : const void *value;
3769 : 15 : size_t value_len;
3770 : : uint32_t page_num;
3771 : : struct spdk_blob_md_page *page;
3772 : 15 : struct spdk_blob_opts blob_opts;
3773 : :
3774 : : /* Create first blob */
3775 : 20 : blobid1 = spdk_blob_get_id(blob);
3776 : :
3777 : : /* Set some xattrs */
3778 : 20 : rc = spdk_blob_set_xattr(blob, "name", "log.txt", strlen("log.txt") + 1);
3779 : 20 : CU_ASSERT(rc == 0);
3780 : :
3781 : 20 : length = 2345;
3782 : 20 : rc = spdk_blob_set_xattr(blob, "length", &length, sizeof(length));
3783 : 20 : CU_ASSERT(rc == 0);
3784 : :
3785 : : /* Put xattr that fits exactly single page.
3786 : : * This results in adding additional pages to MD.
3787 : : * First is flags and smaller xattr, second the large xattr,
3788 : : * third are just the extents.
3789 : : */
3790 : 20 : size_t xattr_length = 4072 - sizeof(struct spdk_blob_md_descriptor_xattr) -
3791 : : strlen("large_xattr");
3792 : 20 : char *xattr = calloc(xattr_length, sizeof(char));
3793 [ + + ]: 20 : SPDK_CU_ASSERT_FATAL(xattr != NULL);
3794 : 20 : rc = spdk_blob_set_xattr(blob, "large_xattr", xattr, xattr_length);
3795 : 20 : free(xattr);
3796 [ + + ]: 20 : SPDK_CU_ASSERT_FATAL(rc == 0);
3797 : :
3798 : : /* Resize the blob */
3799 : 20 : spdk_blob_resize(blob, 10, blob_op_complete, NULL);
3800 : 20 : poll_threads();
3801 : 20 : CU_ASSERT(g_bserrno == 0);
3802 : :
3803 : : /* Set the blob as the super blob */
3804 : 20 : spdk_bs_set_super(bs, blobid1, blob_op_complete, NULL);
3805 : 20 : poll_threads();
3806 : 20 : CU_ASSERT(g_bserrno == 0);
3807 : :
3808 : 20 : free_clusters = spdk_bs_free_cluster_count(bs);
3809 : :
3810 : 20 : spdk_blob_close(blob, blob_op_complete, NULL);
3811 : 20 : poll_threads();
3812 : 20 : CU_ASSERT(g_bserrno == 0);
3813 : 20 : blob = NULL;
3814 : 20 : g_blob = NULL;
3815 : 20 : g_blobid = SPDK_BLOBID_INVALID;
3816 : :
3817 : 20 : ut_bs_dirty_load(&bs, NULL);
3818 : :
3819 : : /* Get the super blob */
3820 : 20 : spdk_bs_get_super(bs, blob_op_with_id_complete, NULL);
3821 : 20 : poll_threads();
3822 : 20 : CU_ASSERT(g_bserrno == 0);
3823 : 20 : CU_ASSERT(blobid1 == g_blobid);
3824 : :
3825 : 20 : spdk_bs_open_blob(bs, blobid1, blob_op_with_handle_complete, NULL);
3826 : 20 : poll_threads();
3827 : 20 : CU_ASSERT(g_bserrno == 0);
3828 : 20 : CU_ASSERT(g_blob != NULL);
3829 : 20 : blob = g_blob;
3830 : :
3831 : 20 : CU_ASSERT(free_clusters == spdk_bs_free_cluster_count(bs));
3832 : :
3833 : : /* Get the xattrs */
3834 : 20 : value = NULL;
3835 : 20 : rc = spdk_blob_get_xattr_value(blob, "length", &value, &value_len);
3836 : 20 : CU_ASSERT(rc == 0);
3837 [ + + ]: 20 : SPDK_CU_ASSERT_FATAL(value != NULL);
3838 : 20 : CU_ASSERT(*(uint64_t *)value == length);
3839 : 20 : CU_ASSERT(value_len == 8);
3840 : 20 : CU_ASSERT(spdk_blob_get_num_clusters(blob) == 10);
3841 : :
3842 : : /* Resize the blob */
3843 : 20 : spdk_blob_resize(blob, 20, blob_op_complete, NULL);
3844 : 20 : poll_threads();
3845 : 20 : CU_ASSERT(g_bserrno == 0);
3846 : :
3847 : 20 : free_clusters = spdk_bs_free_cluster_count(bs);
3848 : :
3849 : 20 : spdk_blob_close(blob, blob_op_complete, NULL);
3850 : 20 : poll_threads();
3851 : 20 : CU_ASSERT(g_bserrno == 0);
3852 : 20 : blob = NULL;
3853 : 20 : g_blob = NULL;
3854 : 20 : g_blobid = SPDK_BLOBID_INVALID;
3855 : :
3856 : 20 : ut_bs_dirty_load(&bs, NULL);
3857 : :
3858 : 20 : spdk_bs_open_blob(bs, blobid1, blob_op_with_handle_complete, NULL);
3859 : 20 : poll_threads();
3860 : 20 : CU_ASSERT(g_bserrno == 0);
3861 : 20 : CU_ASSERT(g_blob != NULL);
3862 : 20 : blob = g_blob;
3863 : 20 : CU_ASSERT(spdk_blob_get_num_clusters(blob) == 20);
3864 : 20 : CU_ASSERT(free_clusters == spdk_bs_free_cluster_count(bs));
3865 : :
3866 : 20 : spdk_blob_close(blob, blob_op_complete, NULL);
3867 : 20 : poll_threads();
3868 : 20 : CU_ASSERT(g_bserrno == 0);
3869 : 20 : blob = NULL;
3870 : 20 : g_blob = NULL;
3871 : 20 : g_blobid = SPDK_BLOBID_INVALID;
3872 : :
3873 : : /* Create second blob */
3874 : 20 : blob = ut_blob_create_and_open(bs, NULL);
3875 : 20 : blobid2 = spdk_blob_get_id(blob);
3876 : :
3877 : : /* Set some xattrs */
3878 : 20 : rc = spdk_blob_set_xattr(blob, "name", "log1.txt", strlen("log1.txt") + 1);
3879 : 20 : CU_ASSERT(rc == 0);
3880 : :
3881 : 20 : length = 5432;
3882 : 20 : rc = spdk_blob_set_xattr(blob, "length", &length, sizeof(length));
3883 : 20 : CU_ASSERT(rc == 0);
3884 : :
3885 : : /* Resize the blob */
3886 : 20 : spdk_blob_resize(blob, 10, blob_op_complete, NULL);
3887 : 20 : poll_threads();
3888 : 20 : CU_ASSERT(g_bserrno == 0);
3889 : :
3890 : 20 : free_clusters = spdk_bs_free_cluster_count(bs);
3891 : :
3892 : 20 : spdk_blob_close(blob, blob_op_complete, NULL);
3893 : 20 : poll_threads();
3894 : 20 : CU_ASSERT(g_bserrno == 0);
3895 : 20 : blob = NULL;
3896 : 20 : g_blob = NULL;
3897 : 20 : g_blobid = SPDK_BLOBID_INVALID;
3898 : :
3899 : 20 : ut_bs_dirty_load(&bs, NULL);
3900 : :
3901 : 20 : spdk_bs_open_blob(bs, blobid2, blob_op_with_handle_complete, NULL);
3902 : 20 : poll_threads();
3903 : 20 : CU_ASSERT(g_bserrno == 0);
3904 : 20 : CU_ASSERT(g_blob != NULL);
3905 : 20 : blob = g_blob;
3906 : :
3907 : : /* Get the xattrs */
3908 : 20 : value = NULL;
3909 : 20 : rc = spdk_blob_get_xattr_value(blob, "length", &value, &value_len);
3910 : 20 : CU_ASSERT(rc == 0);
3911 [ - + ]: 20 : SPDK_CU_ASSERT_FATAL(value != NULL);
3912 : 20 : CU_ASSERT(*(uint64_t *)value == length);
3913 : 20 : CU_ASSERT(value_len == 8);
3914 : 20 : CU_ASSERT(spdk_blob_get_num_clusters(blob) == 10);
3915 : 20 : CU_ASSERT(free_clusters == spdk_bs_free_cluster_count(bs));
3916 : :
3917 : 20 : ut_blob_close_and_delete(bs, blob);
3918 : :
3919 : 20 : free_clusters = spdk_bs_free_cluster_count(bs);
3920 : :
3921 : 20 : ut_bs_dirty_load(&bs, NULL);
3922 : :
3923 : 20 : spdk_bs_open_blob(bs, blobid2, blob_op_with_handle_complete, NULL);
3924 : 20 : poll_threads();
3925 : 20 : CU_ASSERT(g_bserrno != 0);
3926 : 20 : CU_ASSERT(g_blob == NULL);
3927 : :
3928 : 20 : spdk_bs_open_blob(bs, blobid1, blob_op_with_handle_complete, NULL);
3929 : 20 : poll_threads();
3930 : 20 : CU_ASSERT(g_bserrno == 0);
3931 : 20 : CU_ASSERT(g_blob != NULL);
3932 : 20 : blob = g_blob;
3933 : 20 : CU_ASSERT(free_clusters == spdk_bs_free_cluster_count(bs));
3934 : 20 : spdk_blob_close(blob, blob_op_complete, NULL);
3935 : 20 : poll_threads();
3936 : 20 : CU_ASSERT(g_bserrno == 0);
3937 : :
3938 : 20 : ut_bs_reload(&bs, NULL);
3939 : :
3940 : : /* Create second blob */
3941 : 20 : ut_spdk_blob_opts_init(&blob_opts);
3942 : 20 : spdk_bs_create_blob_ext(bs, &blob_opts, blob_op_with_id_complete, NULL);
3943 : 20 : poll_threads();
3944 : 20 : CU_ASSERT(g_bserrno == 0);
3945 : 20 : CU_ASSERT(g_blobid != SPDK_BLOBID_INVALID);
3946 : 20 : blobid2 = g_blobid;
3947 : :
3948 : : /* Create third blob */
3949 : 20 : spdk_bs_create_blob_ext(bs, &blob_opts, blob_op_with_id_complete, NULL);
3950 : 20 : poll_threads();
3951 : 20 : CU_ASSERT(g_bserrno == 0);
3952 : 20 : CU_ASSERT(g_blobid != SPDK_BLOBID_INVALID);
3953 : 20 : blobid3 = g_blobid;
3954 : :
3955 : 20 : spdk_bs_open_blob(bs, blobid2, blob_op_with_handle_complete, NULL);
3956 : 20 : poll_threads();
3957 : 20 : CU_ASSERT(g_bserrno == 0);
3958 : 20 : CU_ASSERT(g_blob != NULL);
3959 : 20 : blob = g_blob;
3960 : :
3961 : : /* Set some xattrs for second blob */
3962 : 20 : rc = spdk_blob_set_xattr(blob, "name", "log1.txt", strlen("log1.txt") + 1);
3963 : 20 : CU_ASSERT(rc == 0);
3964 : :
3965 : 20 : length = 5432;
3966 : 20 : rc = spdk_blob_set_xattr(blob, "length", &length, sizeof(length));
3967 : 20 : CU_ASSERT(rc == 0);
3968 : :
3969 : 20 : spdk_blob_close(blob, blob_op_complete, NULL);
3970 : 20 : poll_threads();
3971 : 20 : CU_ASSERT(g_bserrno == 0);
3972 : 20 : blob = NULL;
3973 : 20 : g_blob = NULL;
3974 : 20 : g_blobid = SPDK_BLOBID_INVALID;
3975 : :
3976 : 20 : spdk_bs_open_blob(bs, blobid3, blob_op_with_handle_complete, NULL);
3977 : 20 : poll_threads();
3978 : 20 : CU_ASSERT(g_bserrno == 0);
3979 : 20 : CU_ASSERT(g_blob != NULL);
3980 : 20 : blob = g_blob;
3981 : :
3982 : : /* Set some xattrs for third blob */
3983 : 20 : rc = spdk_blob_set_xattr(blob, "name", "log2.txt", strlen("log2.txt") + 1);
3984 : 20 : CU_ASSERT(rc == 0);
3985 : :
3986 : 20 : length = 5432;
3987 : 20 : rc = spdk_blob_set_xattr(blob, "length", &length, sizeof(length));
3988 : 20 : CU_ASSERT(rc == 0);
3989 : :
3990 : 20 : spdk_blob_close(blob, blob_op_complete, NULL);
3991 : 20 : poll_threads();
3992 : 20 : CU_ASSERT(g_bserrno == 0);
3993 : 20 : blob = NULL;
3994 : 20 : g_blob = NULL;
3995 : 20 : g_blobid = SPDK_BLOBID_INVALID;
3996 : :
3997 : : /* Mark second blob as invalid */
3998 : 20 : page_num = bs_blobid_to_page(blobid2);
3999 : :
4000 : 20 : index = g_phys_blocklen * (bs->md_start + page_num);
4001 : 20 : page = (struct spdk_blob_md_page *)&g_dev_buffer[index];
4002 : 20 : page->sequence_num = 1;
4003 : 20 : page->crc = blob_md_page_calc_crc(page);
4004 : :
4005 : 20 : free_clusters = spdk_bs_free_cluster_count(bs);
4006 : :
4007 : 20 : ut_bs_dirty_load(&bs, NULL);
4008 : :
4009 : 20 : spdk_bs_open_blob(bs, blobid2, blob_op_with_handle_complete, NULL);
4010 : 20 : poll_threads();
4011 : 20 : CU_ASSERT(g_bserrno != 0);
4012 : 20 : CU_ASSERT(g_blob == NULL);
4013 : :
4014 : 20 : spdk_bs_open_blob(bs, blobid3, blob_op_with_handle_complete, NULL);
4015 : 20 : poll_threads();
4016 : 20 : CU_ASSERT(g_bserrno == 0);
4017 : 20 : CU_ASSERT(g_blob != NULL);
4018 : 20 : blob = g_blob;
4019 : :
4020 : 20 : CU_ASSERT(free_clusters == spdk_bs_free_cluster_count(bs));
4021 : 20 : }
4022 : :
4023 : : static void
4024 : 20 : blob_flags(void)
4025 : : {
4026 : 20 : struct spdk_blob_store *bs = g_bs;
4027 : : spdk_blob_id blobid_invalid, blobid_data_ro, blobid_md_ro;
4028 : : struct spdk_blob *blob_invalid, *blob_data_ro, *blob_md_ro;
4029 : 15 : struct spdk_blob_opts blob_opts;
4030 : : int rc;
4031 : :
4032 : : /* Create three blobs - one each for testing invalid, data_ro and md_ro flags. */
4033 : 20 : blob_invalid = ut_blob_create_and_open(bs, NULL);
4034 : 20 : blobid_invalid = spdk_blob_get_id(blob_invalid);
4035 : :
4036 : 20 : blob_data_ro = ut_blob_create_and_open(bs, NULL);
4037 : 20 : blobid_data_ro = spdk_blob_get_id(blob_data_ro);
4038 : :
4039 : 20 : ut_spdk_blob_opts_init(&blob_opts);
4040 : 20 : blob_opts.clear_method = BLOB_CLEAR_WITH_WRITE_ZEROES;
4041 : 20 : blob_md_ro = ut_blob_create_and_open(bs, &blob_opts);
4042 : 20 : blobid_md_ro = spdk_blob_get_id(blob_md_ro);
4043 : 20 : CU_ASSERT((blob_md_ro->md_ro_flags & SPDK_BLOB_MD_RO_FLAGS_MASK) == BLOB_CLEAR_WITH_WRITE_ZEROES);
4044 : :
4045 : : /* Change the size of blob_data_ro to check if flags are serialized
4046 : : * when blob has non zero number of extents */
4047 : 20 : spdk_blob_resize(blob_data_ro, 10, blob_op_complete, NULL);
4048 : 20 : poll_threads();
4049 : 20 : CU_ASSERT(g_bserrno == 0);
4050 : :
4051 : : /* Set the xattr to check if flags are serialized
4052 : : * when blob has non zero number of xattrs */
4053 : 20 : rc = spdk_blob_set_xattr(blob_md_ro, "name", "log.txt", strlen("log.txt") + 1);
4054 : 20 : CU_ASSERT(rc == 0);
4055 : :
4056 : 20 : blob_invalid->invalid_flags = (1ULL << 63);
4057 : 20 : blob_invalid->state = SPDK_BLOB_STATE_DIRTY;
4058 : 20 : blob_data_ro->data_ro_flags = (1ULL << 62);
4059 : 20 : blob_data_ro->state = SPDK_BLOB_STATE_DIRTY;
4060 : 20 : blob_md_ro->md_ro_flags = (1ULL << 61);
4061 : 20 : blob_md_ro->state = SPDK_BLOB_STATE_DIRTY;
4062 : :
4063 : 20 : g_bserrno = -1;
4064 : 20 : spdk_blob_sync_md(blob_invalid, blob_op_complete, NULL);
4065 : 20 : poll_threads();
4066 : 20 : CU_ASSERT(g_bserrno == 0);
4067 : 20 : g_bserrno = -1;
4068 : 20 : spdk_blob_sync_md(blob_data_ro, blob_op_complete, NULL);
4069 : 20 : poll_threads();
4070 : 20 : CU_ASSERT(g_bserrno == 0);
4071 : 20 : g_bserrno = -1;
4072 : 20 : spdk_blob_sync_md(blob_md_ro, blob_op_complete, NULL);
4073 : 20 : poll_threads();
4074 : 20 : CU_ASSERT(g_bserrno == 0);
4075 : :
4076 : 20 : g_bserrno = -1;
4077 : 20 : spdk_blob_close(blob_invalid, blob_op_complete, NULL);
4078 : 20 : poll_threads();
4079 : 20 : CU_ASSERT(g_bserrno == 0);
4080 : 20 : blob_invalid = NULL;
4081 : 20 : g_bserrno = -1;
4082 : 20 : spdk_blob_close(blob_data_ro, blob_op_complete, NULL);
4083 : 20 : poll_threads();
4084 : 20 : CU_ASSERT(g_bserrno == 0);
4085 : 20 : blob_data_ro = NULL;
4086 : 20 : g_bserrno = -1;
4087 : 20 : spdk_blob_close(blob_md_ro, blob_op_complete, NULL);
4088 : 20 : poll_threads();
4089 : 20 : CU_ASSERT(g_bserrno == 0);
4090 : 20 : blob_md_ro = NULL;
4091 : :
4092 : 20 : g_blob = NULL;
4093 : 20 : g_blobid = SPDK_BLOBID_INVALID;
4094 : :
4095 : 20 : ut_bs_reload(&bs, NULL);
4096 : :
4097 : 20 : g_blob = NULL;
4098 : 20 : g_bserrno = 0;
4099 : 20 : spdk_bs_open_blob(bs, blobid_invalid, blob_op_with_handle_complete, NULL);
4100 : 20 : poll_threads();
4101 : 20 : CU_ASSERT(g_bserrno != 0);
4102 : 20 : CU_ASSERT(g_blob == NULL);
4103 : :
4104 : 20 : g_blob = NULL;
4105 : 20 : g_bserrno = -1;
4106 : 20 : spdk_bs_open_blob(bs, blobid_data_ro, blob_op_with_handle_complete, NULL);
4107 : 20 : poll_threads();
4108 : 20 : CU_ASSERT(g_bserrno == 0);
4109 [ + + ]: 20 : SPDK_CU_ASSERT_FATAL(g_blob != NULL);
4110 : 20 : blob_data_ro = g_blob;
4111 : : /* If an unknown data_ro flag was found, the blob should be marked both data and md read-only. */
4112 [ - + ]: 20 : CU_ASSERT(blob_data_ro->data_ro == true);
4113 [ - + ]: 20 : CU_ASSERT(blob_data_ro->md_ro == true);
4114 : 20 : CU_ASSERT(spdk_blob_get_num_clusters(blob_data_ro) == 10);
4115 : :
4116 : 20 : g_blob = NULL;
4117 : 20 : g_bserrno = -1;
4118 : 20 : spdk_bs_open_blob(bs, blobid_md_ro, blob_op_with_handle_complete, NULL);
4119 : 20 : poll_threads();
4120 : 20 : CU_ASSERT(g_bserrno == 0);
4121 [ - + ]: 20 : SPDK_CU_ASSERT_FATAL(g_blob != NULL);
4122 : 20 : blob_md_ro = g_blob;
4123 [ - + ]: 20 : CU_ASSERT(blob_md_ro->data_ro == false);
4124 [ - + ]: 20 : CU_ASSERT(blob_md_ro->md_ro == true);
4125 : :
4126 : 20 : g_bserrno = -1;
4127 : 20 : spdk_blob_sync_md(blob_md_ro, blob_op_complete, NULL);
4128 : 20 : poll_threads();
4129 : 20 : CU_ASSERT(g_bserrno == 0);
4130 : :
4131 : 20 : ut_blob_close_and_delete(bs, blob_data_ro);
4132 : 20 : ut_blob_close_and_delete(bs, blob_md_ro);
4133 : 20 : }
4134 : :
4135 : : static void
4136 : 20 : bs_version(void)
4137 : : {
4138 : : struct spdk_bs_super_block *super;
4139 : 20 : struct spdk_blob_store *bs = g_bs;
4140 : : struct spdk_bs_dev *dev;
4141 : : struct spdk_blob *blob;
4142 : 15 : struct spdk_blob_opts blob_opts;
4143 : : spdk_blob_id blobid;
4144 : :
4145 : : /* Unload the blob store */
4146 : 20 : spdk_bs_unload(bs, bs_op_complete, NULL);
4147 : 20 : poll_threads();
4148 : 20 : CU_ASSERT(g_bserrno == 0);
4149 : 20 : g_bs = NULL;
4150 : :
4151 : : /*
4152 : : * Change the bs version on disk. This will allow us to
4153 : : * test that the version does not get modified automatically
4154 : : * when loading and unloading the blobstore.
4155 : : */
4156 : 20 : super = (struct spdk_bs_super_block *)&g_dev_buffer[0];
4157 : 20 : CU_ASSERT(super->version == SPDK_BS_VERSION);
4158 : 20 : CU_ASSERT(super->clean == 1);
4159 : 20 : super->version = 2;
4160 : : /*
4161 : : * Version 2 metadata does not have a used blobid mask, so clear
4162 : : * those fields in the super block and zero the corresponding
4163 : : * region on "disk". We will use this to ensure blob IDs are
4164 : : * correctly reconstructed.
4165 : : */
4166 [ - + ]: 25 : memset(&g_dev_buffer[super->used_blobid_mask_start * SPDK_BS_PAGE_SIZE], 0,
4167 : 20 : super->used_blobid_mask_len * SPDK_BS_PAGE_SIZE);
4168 : 20 : super->used_blobid_mask_start = 0;
4169 : 20 : super->used_blobid_mask_len = 0;
4170 : 20 : super->crc = blob_md_page_calc_crc(super);
4171 : :
4172 : : /* Load an existing blob store */
4173 : 20 : dev = init_dev();
4174 : 20 : spdk_bs_load(dev, NULL, bs_op_with_handle_complete, NULL);
4175 : 20 : poll_threads();
4176 : 20 : CU_ASSERT(g_bserrno == 0);
4177 [ + + ]: 20 : SPDK_CU_ASSERT_FATAL(g_bs != NULL);
4178 : 20 : CU_ASSERT(super->clean == 1);
4179 : 20 : bs = g_bs;
4180 : :
4181 : : /*
4182 : : * Create a blob - just to make sure that when we unload it
4183 : : * results in writing the super block (since metadata pages
4184 : : * were allocated.
4185 : : */
4186 : 20 : ut_spdk_blob_opts_init(&blob_opts);
4187 : 20 : spdk_bs_create_blob_ext(bs, &blob_opts, blob_op_with_id_complete, NULL);
4188 : 20 : poll_threads();
4189 : 20 : CU_ASSERT(g_bserrno == 0);
4190 : 20 : CU_ASSERT(g_blobid != SPDK_BLOBID_INVALID);
4191 : 20 : blobid = g_blobid;
4192 : :
4193 : : /* Unload the blob store */
4194 : 20 : spdk_bs_unload(bs, bs_op_complete, NULL);
4195 : 20 : poll_threads();
4196 : 20 : CU_ASSERT(g_bserrno == 0);
4197 : 20 : g_bs = NULL;
4198 : 20 : CU_ASSERT(super->version == 2);
4199 : 20 : CU_ASSERT(super->used_blobid_mask_start == 0);
4200 : 20 : CU_ASSERT(super->used_blobid_mask_len == 0);
4201 : :
4202 : 20 : dev = init_dev();
4203 : 20 : spdk_bs_load(dev, NULL, bs_op_with_handle_complete, NULL);
4204 : 20 : poll_threads();
4205 : 20 : CU_ASSERT(g_bserrno == 0);
4206 [ - + ]: 20 : SPDK_CU_ASSERT_FATAL(g_bs != NULL);
4207 : 20 : bs = g_bs;
4208 : :
4209 : 20 : g_blob = NULL;
4210 : 20 : spdk_bs_open_blob(bs, blobid, blob_op_with_handle_complete, NULL);
4211 : 20 : poll_threads();
4212 : 20 : CU_ASSERT(g_bserrno == 0);
4213 : 20 : CU_ASSERT(g_blob != NULL);
4214 : 20 : blob = g_blob;
4215 : :
4216 : 20 : ut_blob_close_and_delete(bs, blob);
4217 : :
4218 : 20 : CU_ASSERT(super->version == 2);
4219 : 20 : CU_ASSERT(super->used_blobid_mask_start == 0);
4220 : 20 : CU_ASSERT(super->used_blobid_mask_len == 0);
4221 : 20 : }
4222 : :
4223 : : static void
4224 : 20 : blob_set_xattrs_test(void)
4225 : : {
4226 : 20 : struct spdk_blob_store *bs = g_bs;
4227 : : struct spdk_blob *blob;
4228 : 15 : struct spdk_blob_opts opts;
4229 : 15 : const void *value;
4230 : 15 : size_t value_len;
4231 : : char *xattr;
4232 : : size_t xattr_length;
4233 : : int rc;
4234 : :
4235 : : /* Create blob with extra attributes */
4236 : 20 : ut_spdk_blob_opts_init(&opts);
4237 : :
4238 : 20 : opts.xattrs.names = g_xattr_names;
4239 : 20 : opts.xattrs.get_value = _get_xattr_value;
4240 : 20 : opts.xattrs.count = 3;
4241 : 20 : opts.xattrs.ctx = &g_ctx;
4242 : :
4243 : 20 : blob = ut_blob_create_and_open(bs, &opts);
4244 : :
4245 : : /* Get the xattrs */
4246 : 20 : value = NULL;
4247 : :
4248 : 20 : rc = spdk_blob_get_xattr_value(blob, g_xattr_names[0], &value, &value_len);
4249 : 20 : CU_ASSERT(rc == 0);
4250 [ + + ]: 20 : SPDK_CU_ASSERT_FATAL(value != NULL);
4251 [ - + ]: 20 : CU_ASSERT(value_len == strlen(g_xattr_values[0]));
4252 [ - + - + ]: 20 : CU_ASSERT_NSTRING_EQUAL_FATAL(value, g_xattr_values[0], value_len);
4253 : :
4254 : 20 : rc = spdk_blob_get_xattr_value(blob, g_xattr_names[1], &value, &value_len);
4255 : 20 : CU_ASSERT(rc == 0);
4256 [ + + ]: 20 : SPDK_CU_ASSERT_FATAL(value != NULL);
4257 [ - + ]: 20 : CU_ASSERT(value_len == strlen(g_xattr_values[1]));
4258 [ - + - + ]: 20 : CU_ASSERT_NSTRING_EQUAL((char *)value, g_xattr_values[1], value_len);
4259 : :
4260 : 20 : rc = spdk_blob_get_xattr_value(blob, g_xattr_names[2], &value, &value_len);
4261 : 20 : CU_ASSERT(rc == 0);
4262 [ + + ]: 20 : SPDK_CU_ASSERT_FATAL(value != NULL);
4263 [ - + ]: 20 : CU_ASSERT(value_len == strlen(g_xattr_values[2]));
4264 [ - + - + ]: 20 : CU_ASSERT_NSTRING_EQUAL((char *)value, g_xattr_values[2], value_len);
4265 : :
4266 : : /* Try to get non existing attribute */
4267 : :
4268 : 20 : rc = spdk_blob_get_xattr_value(blob, "foobar", &value, &value_len);
4269 : 20 : CU_ASSERT(rc == -ENOENT);
4270 : :
4271 : : /* Try xattr exceeding maximum length of descriptor in single page */
4272 : 20 : xattr_length = SPDK_BS_MAX_DESC_SIZE - sizeof(struct spdk_blob_md_descriptor_xattr) -
4273 : : strlen("large_xattr") + 1;
4274 : 20 : xattr = calloc(xattr_length, sizeof(char));
4275 [ + + ]: 20 : SPDK_CU_ASSERT_FATAL(xattr != NULL);
4276 : 20 : rc = spdk_blob_set_xattr(blob, "large_xattr", xattr, xattr_length);
4277 : 20 : free(xattr);
4278 [ - + ]: 20 : SPDK_CU_ASSERT_FATAL(rc == -ENOMEM);
4279 : :
4280 : 20 : spdk_blob_close(blob, blob_op_complete, NULL);
4281 : 20 : poll_threads();
4282 : 20 : CU_ASSERT(g_bserrno == 0);
4283 : 20 : blob = NULL;
4284 : 20 : g_blob = NULL;
4285 : 20 : g_blobid = SPDK_BLOBID_INVALID;
4286 : :
4287 : : /* NULL callback */
4288 : 20 : ut_spdk_blob_opts_init(&opts);
4289 : 20 : opts.xattrs.names = g_xattr_names;
4290 : 20 : opts.xattrs.get_value = NULL;
4291 : 20 : opts.xattrs.count = 1;
4292 : 20 : opts.xattrs.ctx = &g_ctx;
4293 : :
4294 : 20 : spdk_bs_create_blob_ext(bs, &opts, blob_op_with_id_complete, NULL);
4295 : 20 : poll_threads();
4296 : 20 : CU_ASSERT(g_bserrno == -EINVAL);
4297 : 20 : CU_ASSERT(g_blobid != SPDK_BLOBID_INVALID);
4298 : :
4299 : : /* NULL values */
4300 : 20 : ut_spdk_blob_opts_init(&opts);
4301 : 20 : opts.xattrs.names = g_xattr_names;
4302 : 20 : opts.xattrs.get_value = _get_xattr_value_null;
4303 : 20 : opts.xattrs.count = 1;
4304 : 20 : opts.xattrs.ctx = NULL;
4305 : :
4306 : 20 : spdk_bs_create_blob_ext(bs, &opts, blob_op_with_id_complete, NULL);
4307 : 20 : poll_threads();
4308 : 20 : CU_ASSERT(g_bserrno == -EINVAL);
4309 : 20 : }
4310 : :
4311 : : static void
4312 : 20 : blob_thin_prov_alloc(void)
4313 : : {
4314 : 20 : struct spdk_blob_store *bs = g_bs;
4315 : : struct spdk_blob *blob;
4316 : 15 : struct spdk_blob_opts opts;
4317 : : spdk_blob_id blobid;
4318 : : uint64_t free_clusters;
4319 : :
4320 : 20 : free_clusters = spdk_bs_free_cluster_count(bs);
4321 : :
4322 : : /* Set blob as thin provisioned */
4323 : 20 : ut_spdk_blob_opts_init(&opts);
4324 : 20 : opts.thin_provision = true;
4325 : :
4326 : 20 : blob = ut_blob_create_and_open(bs, &opts);
4327 : 20 : blobid = spdk_blob_get_id(blob);
4328 : 20 : CU_ASSERT(free_clusters == spdk_bs_free_cluster_count(bs));
4329 : :
4330 : 20 : CU_ASSERT(blob->active.num_clusters == 0);
4331 : 20 : CU_ASSERT(spdk_blob_get_num_clusters(blob) == 0);
4332 : 20 : CU_ASSERT(spdk_blob_get_num_allocated_clusters(blob) == 0);
4333 : :
4334 : : /* The blob started at 0 clusters. Resize it to be 5, but still unallocated. */
4335 : 20 : spdk_blob_resize(blob, 5, blob_op_complete, NULL);
4336 : 20 : poll_threads();
4337 : 20 : CU_ASSERT(g_bserrno == 0);
4338 : 20 : CU_ASSERT(free_clusters == spdk_bs_free_cluster_count(bs));
4339 : 20 : CU_ASSERT(blob->active.num_clusters == 5);
4340 : 20 : CU_ASSERT(spdk_blob_get_num_clusters(blob) == 5);
4341 : 20 : CU_ASSERT(spdk_blob_get_num_allocated_clusters(blob) == 0);
4342 : :
4343 : : /* Grow it to 1TB - still unallocated */
4344 : 20 : spdk_blob_resize(blob, 262144, blob_op_complete, NULL);
4345 : 20 : poll_threads();
4346 : 20 : CU_ASSERT(g_bserrno == 0);
4347 : 20 : CU_ASSERT(free_clusters == spdk_bs_free_cluster_count(bs));
4348 : 20 : CU_ASSERT(blob->active.num_clusters == 262144);
4349 : 20 : CU_ASSERT(spdk_blob_get_num_clusters(blob) == 262144);
4350 : 20 : CU_ASSERT(spdk_blob_get_num_allocated_clusters(blob) == 0);
4351 : :
4352 : 20 : spdk_blob_sync_md(blob, blob_op_complete, NULL);
4353 : 20 : poll_threads();
4354 : 20 : CU_ASSERT(g_bserrno == 0);
4355 : : /* Sync must not change anything */
4356 : 20 : CU_ASSERT(free_clusters == spdk_bs_free_cluster_count(bs));
4357 : 20 : CU_ASSERT(blob->active.num_clusters == 262144);
4358 : 20 : CU_ASSERT(spdk_blob_get_num_clusters(blob) == 262144);
4359 : 20 : CU_ASSERT(spdk_blob_get_num_allocated_clusters(blob) == 0);
4360 : : /* Since clusters are not allocated,
4361 : : * number of metadata pages is expected to be minimal.
4362 : : */
4363 : 20 : CU_ASSERT(blob->active.num_pages == 1);
4364 : :
4365 : : /* Shrink the blob to 3 clusters - still unallocated */
4366 : 20 : spdk_blob_resize(blob, 3, blob_op_complete, NULL);
4367 : 20 : poll_threads();
4368 : 20 : CU_ASSERT(g_bserrno == 0);
4369 : 20 : CU_ASSERT(free_clusters == spdk_bs_free_cluster_count(bs));
4370 : 20 : CU_ASSERT(blob->active.num_clusters == 3);
4371 : 20 : CU_ASSERT(spdk_blob_get_num_clusters(blob) == 3);
4372 : 20 : CU_ASSERT(spdk_blob_get_num_allocated_clusters(blob) == 0);
4373 : :
4374 : 20 : spdk_blob_sync_md(blob, blob_op_complete, NULL);
4375 : 20 : poll_threads();
4376 : 20 : CU_ASSERT(g_bserrno == 0);
4377 : : /* Sync must not change anything */
4378 : 20 : CU_ASSERT(free_clusters == spdk_bs_free_cluster_count(bs));
4379 : 20 : CU_ASSERT(blob->active.num_clusters == 3);
4380 : 20 : CU_ASSERT(spdk_blob_get_num_clusters(blob) == 3);
4381 : 20 : CU_ASSERT(spdk_blob_get_num_allocated_clusters(blob) == 0);
4382 : :
4383 : 20 : spdk_blob_close(blob, blob_op_complete, NULL);
4384 : 20 : poll_threads();
4385 : 20 : CU_ASSERT(g_bserrno == 0);
4386 : :
4387 : 20 : ut_bs_reload(&bs, NULL);
4388 : :
4389 : 20 : spdk_bs_open_blob(bs, blobid, blob_op_with_handle_complete, NULL);
4390 : 20 : poll_threads();
4391 : 20 : CU_ASSERT(g_bserrno == 0);
4392 [ + + ]: 20 : SPDK_CU_ASSERT_FATAL(g_blob != NULL);
4393 : 20 : blob = g_blob;
4394 : :
4395 : : /* Check that clusters allocation and size is still the same */
4396 : 20 : CU_ASSERT(free_clusters == spdk_bs_free_cluster_count(bs));
4397 : 20 : CU_ASSERT(blob->active.num_clusters == 3);
4398 : :
4399 : 20 : ut_blob_close_and_delete(bs, blob);
4400 : 20 : }
4401 : :
4402 : : static void
4403 : 20 : blob_insert_cluster_msg_test(void)
4404 : : {
4405 : 20 : struct spdk_blob_store *bs = g_bs;
4406 : : struct spdk_blob *blob;
4407 : 15 : struct spdk_blob_opts opts;
4408 : : /* For now, even if md_page_size is > 4KB, we still only use the first
4409 : : * 4KB of it. The rest is left unused. Future changes may allow using the
4410 : : * rest of the md_page, but that will require more extensive changes since
4411 : : * then the struct spdk_blob_md_page cannot be used directly (since some
4412 : : * fields such as crc would have variable placement in the struct).
4413 : : */
4414 : : struct {
4415 : : struct spdk_blob_md_page page;
4416 : : uint8_t pad[DEV_MAX_PHYS_BLOCKLEN - sizeof(struct spdk_blob_md_page)];
4417 : 20 : } md = {};
4418 : : spdk_blob_id blobid;
4419 : : uint64_t free_clusters;
4420 : 20 : uint64_t new_cluster = 0;
4421 : 20 : uint32_t cluster_num = 3;
4422 : 20 : uint32_t extent_page = 0;
4423 : :
4424 : 20 : free_clusters = spdk_bs_free_cluster_count(bs);
4425 : :
4426 : : /* Set blob as thin provisioned */
4427 : 20 : ut_spdk_blob_opts_init(&opts);
4428 : 20 : opts.thin_provision = true;
4429 : 20 : opts.num_clusters = 4;
4430 : :
4431 : 20 : blob = ut_blob_create_and_open(bs, &opts);
4432 : 20 : blobid = spdk_blob_get_id(blob);
4433 : 20 : CU_ASSERT(free_clusters == spdk_bs_free_cluster_count(bs));
4434 : :
4435 : 20 : CU_ASSERT(blob->active.num_clusters == 4);
4436 : 20 : CU_ASSERT(spdk_blob_get_num_clusters(blob) == 4);
4437 : 20 : CU_ASSERT(blob->active.clusters[cluster_num] == 0);
4438 : :
4439 : : /* Specify cluster_num to allocate and new_cluster will be returned to insert on md_thread.
4440 : : * This is to simulate behaviour when cluster is allocated after blob creation.
4441 : : * Such as _spdk_bs_allocate_and_copy_cluster(). */
4442 : 20 : spdk_spin_lock(&bs->used_lock);
4443 : 20 : bs_allocate_cluster(blob, cluster_num, &new_cluster, &extent_page, false);
4444 : 20 : CU_ASSERT(blob->active.clusters[cluster_num] == 0);
4445 : 20 : spdk_spin_unlock(&bs->used_lock);
4446 : :
4447 : 20 : blob_insert_cluster_on_md_thread(blob, cluster_num, new_cluster, extent_page, &md.page,
4448 : : blob_op_complete, NULL);
4449 : 20 : poll_threads();
4450 : :
4451 : 20 : CU_ASSERT(blob->active.clusters[cluster_num] != 0);
4452 : :
4453 : 20 : spdk_blob_close(blob, blob_op_complete, NULL);
4454 : 20 : poll_threads();
4455 : 20 : CU_ASSERT(g_bserrno == 0);
4456 : :
4457 : 20 : ut_bs_reload(&bs, NULL);
4458 : :
4459 : 20 : spdk_bs_open_blob(bs, blobid, blob_op_with_handle_complete, NULL);
4460 : 20 : poll_threads();
4461 : 20 : CU_ASSERT(g_bserrno == 0);
4462 [ + + ]: 20 : SPDK_CU_ASSERT_FATAL(g_blob != NULL);
4463 : 20 : blob = g_blob;
4464 : :
4465 : 20 : CU_ASSERT(blob->active.clusters[cluster_num] != 0);
4466 : :
4467 : 20 : ut_blob_close_and_delete(bs, blob);
4468 : 20 : }
4469 : :
4470 : : static void
4471 : 20 : blob_thin_prov_rw(void)
4472 : : {
4473 : : static const uint8_t zero[10 * BLOCKLEN] = { 0 };
4474 : 20 : struct spdk_blob_store *bs = g_bs;
4475 : : struct spdk_blob *blob, *blob_id0;
4476 : : struct spdk_io_channel *channel, *channel_thread1;
4477 : 15 : struct spdk_blob_opts opts;
4478 : : uint64_t free_clusters;
4479 : : uint64_t io_unit_size;
4480 : 15 : uint8_t payload_read[10 * BLOCKLEN];
4481 : 15 : uint8_t payload_write[10 * BLOCKLEN];
4482 : : uint64_t write_bytes;
4483 : : uint64_t read_bytes;
4484 : : uint64_t expected_bytes;
4485 : :
4486 : 20 : free_clusters = spdk_bs_free_cluster_count(bs);
4487 : 20 : io_unit_size = spdk_bs_get_io_unit_size(bs);
4488 : :
4489 : 20 : channel = spdk_bs_alloc_io_channel(bs);
4490 : 20 : CU_ASSERT(channel != NULL);
4491 : :
4492 : 20 : ut_spdk_blob_opts_init(&opts);
4493 : 20 : opts.thin_provision = true;
4494 : :
4495 : : /* Create and delete blob at md page 0, so that next md page allocation
4496 : : * for extent will use that. */
4497 : 20 : blob_id0 = ut_blob_create_and_open(bs, &opts);
4498 : 20 : blob = ut_blob_create_and_open(bs, &opts);
4499 : 20 : ut_blob_close_and_delete(bs, blob_id0);
4500 : 20 : CU_ASSERT(free_clusters == spdk_bs_free_cluster_count(bs));
4501 : :
4502 : 20 : CU_ASSERT(blob->active.num_clusters == 0);
4503 : 20 : CU_ASSERT(spdk_blob_get_num_allocated_clusters(blob) == 0);
4504 : :
4505 : : /* The blob started at 0 clusters. Resize it to be 5, but still unallocated. */
4506 : 20 : spdk_blob_resize(blob, 5, blob_op_complete, NULL);
4507 : 20 : poll_threads();
4508 : 20 : CU_ASSERT(g_bserrno == 0);
4509 : 20 : CU_ASSERT(free_clusters == spdk_bs_free_cluster_count(bs));
4510 : 20 : CU_ASSERT(blob->active.num_clusters == 5);
4511 : 20 : CU_ASSERT(spdk_blob_get_num_allocated_clusters(blob) == 0);
4512 : :
4513 : 20 : spdk_blob_sync_md(blob, blob_op_complete, NULL);
4514 : 20 : poll_threads();
4515 : 20 : CU_ASSERT(g_bserrno == 0);
4516 : : /* Sync must not change anything */
4517 : 20 : CU_ASSERT(free_clusters == spdk_bs_free_cluster_count(bs));
4518 : 20 : CU_ASSERT(blob->active.num_clusters == 5);
4519 : 20 : CU_ASSERT(spdk_blob_get_num_allocated_clusters(blob) == 0);
4520 : :
4521 : : /* Payload should be all zeros from unallocated clusters */
4522 : 20 : memset(payload_read, 0xFF, sizeof(payload_read));
4523 : 20 : spdk_blob_io_read(blob, channel, payload_read, 4, 10, blob_op_complete, NULL);
4524 : 20 : poll_threads();
4525 : 20 : CU_ASSERT(g_bserrno == 0);
4526 : 20 : CU_ASSERT(memcmp(zero, payload_read, 10 * BLOCKLEN) == 0);
4527 : :
4528 : 20 : write_bytes = g_dev_write_bytes;
4529 : 20 : read_bytes = g_dev_read_bytes;
4530 : :
4531 : : /* Perform write on thread 1. That will allocate cluster on thread 0 via send_msg */
4532 : 20 : set_thread(1);
4533 : 20 : channel_thread1 = spdk_bs_alloc_io_channel(bs);
4534 : 20 : CU_ASSERT(channel_thread1 != NULL);
4535 : 20 : memset(payload_write, 0xE5, sizeof(payload_write));
4536 : 20 : spdk_blob_io_write(blob, channel_thread1, payload_write, 4, 10, blob_op_complete, NULL);
4537 : 20 : CU_ASSERT(free_clusters - 1 == spdk_bs_free_cluster_count(bs));
4538 : : /* Perform write on thread 0. That will try to allocate cluster,
4539 : : * but fail due to another thread issuing the cluster allocation first. */
4540 : 20 : set_thread(0);
4541 : 20 : memset(payload_write, 0xE5, sizeof(payload_write));
4542 : 20 : spdk_blob_io_write(blob, channel, payload_write, 4, 10, blob_op_complete, NULL);
4543 : 20 : CU_ASSERT(free_clusters - 2 == spdk_bs_free_cluster_count(bs));
4544 : 20 : poll_threads();
4545 : 20 : CU_ASSERT(g_bserrno == 0);
4546 : 20 : CU_ASSERT(free_clusters - 1 == spdk_bs_free_cluster_count(bs));
4547 : 20 : CU_ASSERT(spdk_blob_get_num_allocated_clusters(blob) == 1);
4548 : : /* For thin-provisioned blob we need to write 20 io_units plus one page metadata and
4549 : : * read 0 bytes */
4550 : 20 : expected_bytes = 20 * io_unit_size + spdk_bs_get_page_size(bs);
4551 [ + + + + ]: 20 : if (g_use_extent_table) {
4552 : : /* Add one more page for EXTENT_PAGE write */
4553 : 12 : expected_bytes += spdk_bs_get_page_size(bs);
4554 : 3 : }
4555 : 20 : CU_ASSERT(g_dev_write_bytes - write_bytes == expected_bytes);
4556 : 20 : CU_ASSERT(g_dev_read_bytes - read_bytes == 0);
4557 : :
4558 : 20 : spdk_blob_io_read(blob, channel, payload_read, 4, 10, blob_op_complete, NULL);
4559 : 20 : poll_threads();
4560 : 20 : CU_ASSERT(g_bserrno == 0);
4561 : 20 : CU_ASSERT(memcmp(payload_write, payload_read, 10 * BLOCKLEN) == 0);
4562 : :
4563 : 20 : ut_blob_close_and_delete(bs, blob);
4564 : 20 : CU_ASSERT(free_clusters == spdk_bs_free_cluster_count(bs));
4565 : :
4566 : 20 : set_thread(1);
4567 : 20 : spdk_bs_free_io_channel(channel_thread1);
4568 : 20 : set_thread(0);
4569 : 20 : spdk_bs_free_io_channel(channel);
4570 : 20 : poll_threads();
4571 : 20 : g_blob = NULL;
4572 : 20 : g_blobid = 0;
4573 : 20 : }
4574 : :
4575 : : static void
4576 : 20 : blob_thin_prov_write_count_io(void)
4577 : : {
4578 : : struct spdk_blob_store *bs;
4579 : : struct spdk_blob *blob;
4580 : : struct spdk_io_channel *ch;
4581 : : struct spdk_bs_dev *dev;
4582 : 15 : struct spdk_bs_opts bs_opts;
4583 : 15 : struct spdk_blob_opts opts;
4584 : : uint64_t free_clusters;
4585 : : uint64_t io_unit_size;
4586 : 15 : uint8_t payload_write[BLOCKLEN];
4587 : : uint64_t write_bytes;
4588 : : uint64_t read_bytes;
4589 : : uint64_t expected_bytes;
4590 : 20 : const uint32_t CLUSTER_SZ = g_phys_blocklen * 4;
4591 : : uint32_t io_units_per_cluster;
4592 : : uint32_t io_units_per_extent_page;
4593 : : uint32_t i;
4594 : :
4595 : : /* Use a very small cluster size for this test. This ensures we need multiple
4596 : : * extent pages to hold all of the clusters even for relatively small blobs like
4597 : : * we are restricted to for the unit tests (i.e. we don't want to allocate multi-GB
4598 : : * buffers).
4599 : : */
4600 : 20 : dev = init_dev();
4601 : 20 : spdk_bs_opts_init(&bs_opts, sizeof(bs_opts));
4602 : 20 : bs_opts.cluster_sz = CLUSTER_SZ;
4603 : :
4604 : 20 : spdk_bs_init(dev, &bs_opts, bs_op_with_handle_complete, NULL);
4605 : 20 : poll_threads();
4606 : 20 : CU_ASSERT(g_bserrno == 0);
4607 [ + + ]: 20 : SPDK_CU_ASSERT_FATAL(g_bs != NULL);
4608 : 20 : bs = g_bs;
4609 : :
4610 : 20 : free_clusters = spdk_bs_free_cluster_count(bs);
4611 : 20 : io_unit_size = spdk_bs_get_io_unit_size(bs);
4612 [ - + ]: 20 : io_units_per_cluster = CLUSTER_SZ / io_unit_size;
4613 : 20 : io_units_per_extent_page = SPDK_EXTENTS_PER_EP * io_units_per_cluster;
4614 : :
4615 : 20 : ch = spdk_bs_alloc_io_channel(bs);
4616 [ - + ]: 20 : SPDK_CU_ASSERT_FATAL(ch != NULL);
4617 : :
4618 : 20 : ut_spdk_blob_opts_init(&opts);
4619 : 20 : opts.thin_provision = true;
4620 : :
4621 : 20 : blob = ut_blob_create_and_open(bs, &opts);
4622 : 20 : CU_ASSERT(free_clusters == spdk_bs_free_cluster_count(bs));
4623 : :
4624 : : /* Resize the blob so that it will require 8 extent pages to hold all of
4625 : : * the clusters.
4626 : : */
4627 : 20 : g_bserrno = -1;
4628 : 20 : spdk_blob_resize(blob, SPDK_EXTENTS_PER_EP * 8, blob_op_complete, NULL);
4629 : 20 : poll_threads();
4630 : 20 : CU_ASSERT(g_bserrno == 0);
4631 : :
4632 : 20 : g_bserrno = -1;
4633 : 20 : spdk_blob_sync_md(blob, blob_op_complete, NULL);
4634 : 20 : poll_threads();
4635 : 20 : CU_ASSERT(g_bserrno == 0);
4636 : 20 : CU_ASSERT(free_clusters == spdk_bs_free_cluster_count(bs));
4637 : 20 : CU_ASSERT(blob->active.num_clusters == SPDK_EXTENTS_PER_EP * 8);
4638 : :
4639 [ - + ]: 20 : memset(payload_write, 0, sizeof(payload_write));
4640 [ + + ]: 180 : for (i = 0; i < 8; i++) {
4641 : 160 : write_bytes = g_dev_write_bytes;
4642 : 160 : read_bytes = g_dev_read_bytes;
4643 : :
4644 : 160 : g_bserrno = -1;
4645 : 160 : spdk_blob_io_write(blob, ch, payload_write, io_units_per_extent_page * i, 1, blob_op_complete,
4646 : : NULL);
4647 : 160 : poll_threads();
4648 : 160 : CU_ASSERT(g_bserrno == 0);
4649 : 160 : CU_ASSERT(free_clusters - (2 * i + 1) == spdk_bs_free_cluster_count(bs));
4650 : :
4651 : 160 : CU_ASSERT(g_dev_read_bytes == read_bytes);
4652 [ + + + + ]: 160 : if (!g_use_extent_table) {
4653 : : /* For legacy metadata, we should have written the io_unit for
4654 : : * the write I/O, plus the blob's primary metadata page
4655 : : */
4656 : 64 : expected_bytes = io_unit_size + spdk_bs_get_page_size(bs);
4657 : 16 : } else {
4658 : : /* For extent table metadata, we should have written the io_unit for
4659 : : * the write I/O, plus 2 metadata pages - the extent page and the
4660 : : * blob's primary metadata page
4661 : : */
4662 : 96 : expected_bytes = io_unit_size + 2 * spdk_bs_get_page_size(bs);
4663 : : }
4664 : 160 : CU_ASSERT((g_dev_write_bytes - write_bytes) == expected_bytes);
4665 : :
4666 : : /* The write should have synced the metadata already. Do another sync here
4667 : : * just to confirm.
4668 : : */
4669 : 160 : write_bytes = g_dev_write_bytes;
4670 : 160 : read_bytes = g_dev_read_bytes;
4671 : :
4672 : 160 : g_bserrno = -1;
4673 : 160 : spdk_blob_sync_md(blob, blob_op_complete, NULL);
4674 : 160 : poll_threads();
4675 : 160 : CU_ASSERT(g_bserrno == 0);
4676 : 160 : CU_ASSERT(free_clusters - (2 * i + 1) == spdk_bs_free_cluster_count(bs));
4677 : 160 : CU_ASSERT(spdk_blob_get_num_allocated_clusters(blob) == 2 * i + 1);
4678 : :
4679 : 160 : CU_ASSERT(g_dev_read_bytes == read_bytes);
4680 : 160 : CU_ASSERT(g_dev_write_bytes == write_bytes);
4681 : :
4682 : : /* Now write to another unallocated cluster that is part of the same extent page. */
4683 : 160 : g_bserrno = -1;
4684 : 160 : spdk_blob_io_write(blob, ch, payload_write, io_units_per_extent_page * i + io_units_per_cluster,
4685 : : 1, blob_op_complete, NULL);
4686 : 160 : poll_threads();
4687 : 160 : CU_ASSERT(g_bserrno == 0);
4688 : 160 : CU_ASSERT(free_clusters - (2 * i + 2) == spdk_bs_free_cluster_count(bs));
4689 : 160 : CU_ASSERT(spdk_blob_get_num_allocated_clusters(blob) == 2 * i + 2);
4690 : :
4691 : 160 : CU_ASSERT(g_dev_read_bytes == read_bytes);
4692 : : /*
4693 : : * For legacy metadata, we should have written the I/O and the primary metadata page.
4694 : : * For extent table metadata, we should have written the I/O and the extent metadata page.
4695 : : */
4696 : 160 : expected_bytes = io_unit_size + spdk_bs_get_page_size(bs);
4697 : 160 : CU_ASSERT((g_dev_write_bytes - write_bytes) == expected_bytes);
4698 : :
4699 : : /* Send unmap aligned to the whole cluster - should free it up */
4700 : 160 : g_bserrno = -1;
4701 : 160 : spdk_blob_io_unmap(blob, ch, io_units_per_extent_page * i, io_units_per_cluster, blob_op_complete,
4702 : : NULL);
4703 : 160 : poll_threads();
4704 : 160 : CU_ASSERT(g_bserrno == 0);
4705 : 160 : CU_ASSERT(free_clusters - (2 * i + 1) == spdk_bs_free_cluster_count(bs));
4706 : :
4707 : : /* Write back to the freed cluster */
4708 : 160 : g_bserrno = -1;
4709 : 160 : spdk_blob_io_write(blob, ch, payload_write, io_units_per_extent_page * i, 1, blob_op_complete,
4710 : : NULL);
4711 : 160 : poll_threads();
4712 : 160 : CU_ASSERT(g_bserrno == 0);
4713 : 160 : CU_ASSERT(free_clusters - (2 * i + 2) == spdk_bs_free_cluster_count(bs));
4714 : 40 : }
4715 : :
4716 : 20 : ut_blob_close_and_delete(bs, blob);
4717 : 20 : CU_ASSERT(free_clusters == spdk_bs_free_cluster_count(bs));
4718 : :
4719 : 20 : spdk_bs_free_io_channel(ch);
4720 : 20 : poll_threads();
4721 : 20 : g_blob = NULL;
4722 : 20 : g_blobid = 0;
4723 : :
4724 : 20 : spdk_bs_unload(bs, bs_op_complete, NULL);
4725 : 20 : poll_threads();
4726 : 20 : CU_ASSERT(g_bserrno == 0);
4727 : 20 : g_bs = NULL;
4728 : 20 : }
4729 : :
4730 : : static void
4731 : 20 : blob_thin_prov_unmap_cluster(void)
4732 : : {
4733 : : struct spdk_blob_store *bs;
4734 : : struct spdk_blob *blob, *snapshot;
4735 : : struct spdk_io_channel *ch;
4736 : : struct spdk_bs_dev *dev;
4737 : 15 : struct spdk_bs_opts bs_opts;
4738 : 15 : struct spdk_blob_opts opts;
4739 : : uint64_t free_clusters;
4740 : : uint64_t io_unit_size;
4741 : 15 : uint8_t payload_write[BLOCKLEN];
4742 : 15 : uint8_t payload_read[BLOCKLEN];
4743 : 20 : const uint32_t CLUSTER_COUNT = 3;
4744 : : uint32_t io_units_per_cluster;
4745 : : spdk_blob_id blobid, snapshotid;
4746 : : uint32_t i;
4747 : 15 : int err;
4748 : :
4749 : : /* Use a very large cluster size for this test. Check how the unmap/release cluster code path behaves when
4750 : : * clusters are fully used.
4751 : : */
4752 : 20 : dev = init_dev();
4753 : 20 : spdk_bs_opts_init(&bs_opts, sizeof(bs_opts));
4754 [ - + ]: 20 : bs_opts.cluster_sz = dev->blocklen * dev->blockcnt / (CLUSTER_COUNT + 1);
4755 : :
4756 : 20 : spdk_bs_init(dev, &bs_opts, bs_op_with_handle_complete, NULL);
4757 : 20 : poll_threads();
4758 : 20 : CU_ASSERT(g_bserrno == 0);
4759 [ + + ]: 20 : SPDK_CU_ASSERT_FATAL(g_bs != NULL);
4760 : 20 : bs = g_bs;
4761 : :
4762 : 20 : free_clusters = spdk_bs_free_cluster_count(bs);
4763 : 20 : io_unit_size = spdk_bs_get_io_unit_size(bs);
4764 [ - + ]: 20 : io_units_per_cluster = bs_opts.cluster_sz / io_unit_size;
4765 : :
4766 : 20 : ch = spdk_bs_alloc_io_channel(bs);
4767 [ + + ]: 20 : SPDK_CU_ASSERT_FATAL(ch != NULL);
4768 : :
4769 : 20 : ut_spdk_blob_opts_init(&opts);
4770 : 20 : opts.thin_provision = true;
4771 : :
4772 : 20 : blob = ut_blob_create_and_open(bs, &opts);
4773 : 20 : CU_ASSERT(free_clusters == CLUSTER_COUNT);
4774 : 20 : CU_ASSERT(free_clusters == spdk_bs_free_cluster_count(bs));
4775 : 20 : blobid = spdk_blob_get_id(blob);
4776 : :
4777 : 20 : g_bserrno = -1;
4778 : 20 : spdk_blob_resize(blob, CLUSTER_COUNT, blob_op_complete, NULL);
4779 : 20 : poll_threads();
4780 : 20 : CU_ASSERT(g_bserrno == 0);
4781 : :
4782 : 20 : g_bserrno = -1;
4783 : 20 : spdk_blob_sync_md(blob, blob_op_complete, NULL);
4784 : 20 : poll_threads();
4785 : 20 : CU_ASSERT(g_bserrno == 0);
4786 : 20 : CU_ASSERT(free_clusters == spdk_bs_free_cluster_count(bs));
4787 : 20 : CU_ASSERT(blob->active.num_clusters == CLUSTER_COUNT);
4788 : :
4789 : : /* Fill all clusters */
4790 [ + + ]: 80 : for (i = 0; i < CLUSTER_COUNT; i++) {
4791 : 60 : memset(payload_write, i + 1, sizeof(payload_write));
4792 : 60 : g_bserrno = -1;
4793 : 60 : spdk_blob_io_write(blob, ch, payload_write, io_units_per_cluster * i, 1, blob_op_complete, NULL);
4794 : 60 : poll_threads();
4795 : 60 : CU_ASSERT(g_bserrno == 0);
4796 : 60 : CU_ASSERT(free_clusters - (i + 1) == spdk_bs_free_cluster_count(bs));
4797 : 15 : }
4798 : 20 : CU_ASSERT(0 == spdk_bs_free_cluster_count(bs));
4799 : :
4800 : : /* Unmap one whole cluster */
4801 : 20 : g_bserrno = -1;
4802 : 20 : spdk_blob_io_unmap(blob, ch, io_units_per_cluster, io_units_per_cluster, blob_op_complete, NULL);
4803 : 20 : poll_threads();
4804 : 20 : CU_ASSERT(g_bserrno == 0);
4805 : 20 : CU_ASSERT(1 == spdk_bs_free_cluster_count(bs));
4806 : :
4807 : : /* Verify the data read from the cluster is zeroed out */
4808 : 20 : memset(payload_write, 0, sizeof(payload_write));
4809 : 20 : spdk_blob_io_read(blob, ch, payload_read, io_units_per_cluster, 1, blob_op_complete, NULL);
4810 : 20 : poll_threads();
4811 : 20 : CU_ASSERT(g_bserrno == 0);
4812 : 20 : CU_ASSERT(memcmp(payload_write, payload_read, BLOCKLEN) == 0);
4813 : :
4814 : : /* Fill the same cluster with data */
4815 : 20 : memset(payload_write, 3, sizeof(payload_write));
4816 : 20 : g_bserrno = -1;
4817 : 20 : spdk_blob_io_write(blob, ch, payload_write, io_units_per_cluster, 1, blob_op_complete, NULL);
4818 : 20 : poll_threads();
4819 : 20 : CU_ASSERT(g_bserrno == 0);
4820 : 20 : CU_ASSERT(0 == spdk_bs_free_cluster_count(bs));
4821 : :
4822 : : /* Verify the data read from the cluster has the expected data */
4823 : 20 : spdk_blob_io_read(blob, ch, payload_read, io_units_per_cluster, 1, blob_op_complete, NULL);
4824 : 20 : poll_threads();
4825 : 20 : CU_ASSERT(g_bserrno == 0);
4826 : 20 : CU_ASSERT(memcmp(payload_write, payload_read, BLOCKLEN) == 0);
4827 : :
4828 : : /* Send an unaligned unmap that ecompasses one whole cluster */
4829 : 20 : g_bserrno = -1;
4830 : 20 : spdk_blob_io_unmap(blob, ch, io_units_per_cluster - 1, io_units_per_cluster + 2, blob_op_complete,
4831 : : NULL);
4832 : 20 : poll_threads();
4833 : 20 : CU_ASSERT(g_bserrno == 0);
4834 : 20 : CU_ASSERT(1 == spdk_bs_free_cluster_count(bs));
4835 : :
4836 : : /* Verify the data read from the cluster is zeroed out */
4837 : 20 : g_bserrno = -1;
4838 : 20 : memset(payload_write, 0, sizeof(payload_write));
4839 : 20 : spdk_blob_io_read(blob, ch, payload_read, io_units_per_cluster, 1, blob_op_complete, NULL);
4840 : 20 : poll_threads();
4841 : 20 : CU_ASSERT(g_bserrno == 0);
4842 : 20 : CU_ASSERT(memcmp(payload_write, payload_read, BLOCKLEN) == 0);
4843 : :
4844 : : /* Send a simultaneous unmap with a write to an unallocated area -
4845 : : * check that writes don't claim the currently unmapped cluster */
4846 : 20 : g_bserrno = -1;
4847 : 20 : memset(payload_write, 7, sizeof(payload_write));
4848 : 20 : spdk_blob_io_unmap(blob, ch, 0, io_units_per_cluster, blob_op_complete, NULL);
4849 : 20 : spdk_blob_io_write(blob, ch, payload_write, io_units_per_cluster, 1, blob_op_complete, NULL);
4850 : 20 : poll_threads();
4851 : 20 : CU_ASSERT(g_bserrno == 0);
4852 : 20 : CU_ASSERT(1 == spdk_bs_free_cluster_count(bs));
4853 : :
4854 : : /* Verify the contents of written sector */
4855 : 20 : g_bserrno = -1;
4856 : 20 : spdk_blob_io_read(blob, ch, payload_read, io_units_per_cluster, 1, blob_op_complete, NULL);
4857 : 20 : poll_threads();
4858 : 20 : CU_ASSERT(g_bserrno == 0);
4859 : 20 : CU_ASSERT(memcmp(payload_write, payload_read, BLOCKLEN) == 0);
4860 : :
4861 : : /* Verify the contents of unmapped sector */
4862 : 20 : g_bserrno = -1;
4863 : 20 : memset(payload_write, 0, sizeof(payload_write));
4864 : 20 : spdk_blob_io_read(blob, ch, payload_read, 0, 1, blob_op_complete, NULL);
4865 : 20 : poll_threads();
4866 : 20 : CU_ASSERT(g_bserrno == 0);
4867 : 20 : CU_ASSERT(memcmp(payload_write, payload_read, BLOCKLEN) == 0);
4868 : :
4869 : : /* Make sure clusters are not freed until the unmap to the drive is done */
4870 : 20 : g_bserrno = -1;
4871 : 20 : memset(payload_write, 7, sizeof(payload_write));
4872 : 20 : spdk_blob_io_write(blob, ch, payload_write, 0, 1, blob_op_complete, NULL);
4873 : 20 : poll_threads();
4874 : 20 : CU_ASSERT(g_bserrno == 0);
4875 : 20 : CU_ASSERT(0 == spdk_bs_free_cluster_count(bs));
4876 : :
4877 : 20 : g_bserrno = -1;
4878 : 20 : spdk_blob_io_unmap(blob, ch, 0, io_units_per_cluster, blob_op_complete, NULL);
4879 [ - + - + ]: 20 : while (memcmp(payload_write, &g_dev_buffer[BLOCKLEN * io_units_per_cluster], BLOCKLEN) == 0) {
4880 : 0 : CU_ASSERT(0 == spdk_bs_free_cluster_count(bs));
4881 : 0 : poll_thread_times(0, 1);
4882 : : }
4883 : 20 : poll_threads();
4884 : 20 : CU_ASSERT(g_bserrno == 0);
4885 : 20 : CU_ASSERT(1 == spdk_bs_free_cluster_count(bs));
4886 : :
4887 : : /* Issue #3358 had a bug with concurrent trims to the same cluster causing an assert, check for regressions.
4888 : : * Send three concurrent unmaps to the same cluster.
4889 : : */
4890 : 20 : g_bserrno = -1;
4891 : 20 : memset(payload_write, 7, sizeof(payload_write));
4892 : 20 : spdk_blob_io_write(blob, ch, payload_write, 0, 1, blob_op_complete, NULL);
4893 : 20 : poll_threads();
4894 : 20 : CU_ASSERT(g_bserrno == 0);
4895 : 20 : CU_ASSERT(0 == spdk_bs_free_cluster_count(bs));
4896 : :
4897 : 20 : g_bserrno = -1;
4898 : 20 : err = -1;
4899 : 20 : spdk_blob_io_unmap(blob, ch, 0, io_units_per_cluster, blob_op_complete, NULL);
4900 : 20 : spdk_blob_io_unmap(blob, ch, 0, io_units_per_cluster, blob_op_complete, NULL);
4901 : 20 : spdk_blob_io_unmap(blob, ch, 0, io_units_per_cluster, blob_op_complete, &err);
4902 : 20 : poll_threads();
4903 : 20 : CU_ASSERT(g_bserrno == 0);
4904 : 20 : CU_ASSERT(err == 0);
4905 : 20 : CU_ASSERT(1 == spdk_bs_free_cluster_count(bs));
4906 : :
4907 : : /* Test thin-provisioned blob that is backed */
4908 : 20 : spdk_blob_resize(blob, 1, blob_op_complete, NULL);
4909 : 20 : poll_threads();
4910 : 20 : CU_ASSERT(g_bserrno == 0);
4911 : 20 : spdk_blob_sync_md(blob, blob_op_complete, NULL);
4912 : 20 : poll_threads();
4913 : 20 : CU_ASSERT(g_bserrno == 0);
4914 : 20 : CU_ASSERT(free_clusters == spdk_bs_free_cluster_count(bs));
4915 : :
4916 : 20 : g_bserrno = -1;
4917 : 20 : memset(payload_write, 1, sizeof(payload_write));
4918 : 20 : spdk_blob_io_write(blob, ch, payload_write, 0, 1, blob_op_complete, NULL);
4919 : 20 : poll_threads();
4920 : 20 : CU_ASSERT(g_bserrno == 0);
4921 : 20 : CU_ASSERT(free_clusters - 1 == spdk_bs_free_cluster_count(bs));
4922 : :
4923 : : /* Create a snapshot */
4924 : 20 : CU_ASSERT_EQUAL(_get_snapshots_count(bs), 0);
4925 : 20 : spdk_bs_create_snapshot(bs, blobid, NULL, blob_op_with_id_complete, NULL);
4926 : 20 : poll_threads();
4927 : 20 : CU_ASSERT(g_bserrno == 0);
4928 : 20 : CU_ASSERT(g_blobid != SPDK_BLOBID_INVALID);
4929 : 20 : CU_ASSERT_EQUAL(_get_snapshots_count(bs), 1);
4930 : 20 : snapshotid = g_blobid;
4931 : 20 : CU_ASSERT(free_clusters - 1 == spdk_bs_free_cluster_count(bs));
4932 : 20 : spdk_bs_open_blob(bs, snapshotid, blob_op_with_handle_complete, NULL);
4933 : 20 : poll_threads();
4934 : 20 : CU_ASSERT(g_bserrno == 0);
4935 [ - + ]: 20 : SPDK_CU_ASSERT_FATAL(g_blob != NULL);
4936 : 20 : snapshot = g_blob;
4937 : :
4938 : : /* Write data to blob, it will alloc new cluster */
4939 : 20 : g_bserrno = -1;
4940 : 20 : memset(payload_write, 2, sizeof(payload_write));
4941 : 20 : spdk_blob_io_write(blob, ch, payload_write, 0, 1, blob_op_complete, NULL);
4942 : 20 : poll_threads();
4943 : 20 : CU_ASSERT(g_bserrno == 0);
4944 : 20 : CU_ASSERT(free_clusters - 2 == spdk_bs_free_cluster_count(bs));
4945 : :
4946 : : /* Unmap one whole cluster, but do not release this cluster */
4947 : 20 : g_bserrno = -1;
4948 : 20 : spdk_blob_io_unmap(blob, ch, 0, io_units_per_cluster, blob_op_complete, NULL);
4949 : 20 : poll_threads();
4950 : 20 : CU_ASSERT(g_bserrno == 0);
4951 : 20 : CU_ASSERT(free_clusters - 2 == spdk_bs_free_cluster_count(bs));
4952 : :
4953 : : /* Verify the data read from the cluster is zeroed out */
4954 : 20 : g_bserrno = -1;
4955 : 20 : memset(payload_write, 0, sizeof(payload_write));
4956 : 20 : spdk_blob_io_read(blob, ch, payload_read, 0, 1, blob_op_complete, NULL);
4957 : 20 : poll_threads();
4958 : 20 : CU_ASSERT(g_bserrno == 0);
4959 : 20 : CU_ASSERT(memcmp(payload_write, payload_read, BLOCKLEN) == 0);
4960 : :
4961 : 20 : ut_blob_close_and_delete(bs, blob);
4962 : 20 : ut_blob_close_and_delete(bs, snapshot);
4963 : 20 : CU_ASSERT(free_clusters == spdk_bs_free_cluster_count(bs));
4964 : :
4965 : 20 : spdk_bs_free_io_channel(ch);
4966 : 20 : poll_threads();
4967 : 20 : g_blob = NULL;
4968 : 20 : g_blobid = 0;
4969 : :
4970 : 20 : spdk_bs_unload(bs, bs_op_complete, NULL);
4971 : 20 : poll_threads();
4972 : 20 : CU_ASSERT(g_bserrno == 0);
4973 : 20 : g_bs = NULL;
4974 : 20 : }
4975 : :
4976 : : static void
4977 : 20 : blob_thin_prov_rle(void)
4978 : : {
4979 : : static const uint8_t zero[10 * BLOCKLEN] = { 0 };
4980 : 20 : struct spdk_blob_store *bs = g_bs;
4981 : : struct spdk_blob *blob;
4982 : : struct spdk_io_channel *channel;
4983 : 15 : struct spdk_blob_opts opts;
4984 : : spdk_blob_id blobid;
4985 : : uint64_t free_clusters;
4986 : : uint64_t io_unit_size;
4987 : 15 : uint8_t payload_read[10 * BLOCKLEN];
4988 : 15 : uint8_t payload_write[10 * BLOCKLEN];
4989 : : uint64_t write_bytes;
4990 : : uint64_t read_bytes;
4991 : : uint64_t expected_bytes;
4992 : : uint64_t io_unit;
4993 : :
4994 : : /* assert that the stack variables above are of correct size */
4995 : 20 : CU_ASSERT(spdk_bs_get_io_unit_size(bs) == BLOCKLEN);
4996 : :
4997 : 20 : free_clusters = spdk_bs_free_cluster_count(bs);
4998 : 20 : io_unit_size = spdk_bs_get_io_unit_size(bs);
4999 : :
5000 : 20 : ut_spdk_blob_opts_init(&opts);
5001 : 20 : opts.thin_provision = true;
5002 : 20 : opts.num_clusters = 5;
5003 : :
5004 : 20 : blob = ut_blob_create_and_open(bs, &opts);
5005 : 20 : blobid = spdk_blob_get_id(blob);
5006 : 20 : CU_ASSERT(free_clusters == spdk_bs_free_cluster_count(bs));
5007 : :
5008 : 20 : channel = spdk_bs_alloc_io_channel(bs);
5009 : 20 : CU_ASSERT(channel != NULL);
5010 : :
5011 : : /* Target specifically second cluster in a blob as first allocation */
5012 : 20 : io_unit = bs_cluster_to_io_unit(bs, 1);
5013 : :
5014 : : /* Payload should be all zeros from unallocated clusters */
5015 : 20 : memset(payload_read, 0xFF, sizeof(payload_read));
5016 : 20 : spdk_blob_io_read(blob, channel, payload_read, io_unit, 10, blob_op_complete, NULL);
5017 : 20 : poll_threads();
5018 : 20 : CU_ASSERT(g_bserrno == 0);
5019 : 20 : CU_ASSERT(memcmp(zero, payload_read, 10 * BLOCKLEN) == 0);
5020 : :
5021 : 20 : write_bytes = g_dev_write_bytes;
5022 : 20 : read_bytes = g_dev_read_bytes;
5023 : :
5024 : : /* Issue write to second cluster in a blob */
5025 : 20 : memset(payload_write, 0xE5, sizeof(payload_write));
5026 : 20 : spdk_blob_io_write(blob, channel, payload_write, io_unit, 10, blob_op_complete, NULL);
5027 : 20 : poll_threads();
5028 : 20 : CU_ASSERT(g_bserrno == 0);
5029 : 20 : CU_ASSERT(free_clusters - 1 == spdk_bs_free_cluster_count(bs));
5030 : : /* For thin-provisioned blob we need to write 10 pages plus one page metadata and
5031 : : * read 0 bytes */
5032 : 20 : expected_bytes = 10 * io_unit_size + spdk_bs_get_page_size(bs);
5033 [ + + + + ]: 20 : if (g_use_extent_table) {
5034 : : /* Add one more page for EXTENT_PAGE write */
5035 : 12 : expected_bytes += spdk_bs_get_page_size(bs);
5036 : 3 : }
5037 : 20 : CU_ASSERT(g_dev_write_bytes - write_bytes == expected_bytes);
5038 : 20 : CU_ASSERT(g_dev_read_bytes - read_bytes == 0);
5039 : :
5040 : 20 : spdk_blob_io_read(blob, channel, payload_read, io_unit, 10, blob_op_complete, NULL);
5041 : 20 : poll_threads();
5042 : 20 : CU_ASSERT(g_bserrno == 0);
5043 : 20 : CU_ASSERT(memcmp(payload_write, payload_read, 10 * BLOCKLEN) == 0);
5044 : :
5045 : 20 : spdk_bs_free_io_channel(channel);
5046 : 20 : poll_threads();
5047 : :
5048 : 20 : spdk_blob_close(blob, blob_op_complete, NULL);
5049 : 20 : poll_threads();
5050 : 20 : CU_ASSERT(g_bserrno == 0);
5051 : :
5052 : 20 : ut_bs_reload(&bs, NULL);
5053 : :
5054 : 20 : spdk_bs_open_blob(bs, blobid, blob_op_with_handle_complete, NULL);
5055 : 20 : poll_threads();
5056 : 20 : CU_ASSERT(g_bserrno == 0);
5057 [ + + ]: 20 : SPDK_CU_ASSERT_FATAL(g_blob != NULL);
5058 : 20 : blob = g_blob;
5059 : :
5060 : 20 : channel = spdk_bs_alloc_io_channel(bs);
5061 : 20 : CU_ASSERT(channel != NULL);
5062 : :
5063 : : /* Read second cluster after blob reload to confirm data written */
5064 : 20 : spdk_blob_io_read(blob, channel, payload_read, io_unit, 10, blob_op_complete, NULL);
5065 : 20 : poll_threads();
5066 : 20 : CU_ASSERT(g_bserrno == 0);
5067 : 20 : CU_ASSERT(memcmp(payload_write, payload_read, 10 * BLOCKLEN) == 0);
5068 : :
5069 : 20 : spdk_bs_free_io_channel(channel);
5070 : 20 : poll_threads();
5071 : :
5072 : 20 : ut_blob_close_and_delete(bs, blob);
5073 : 20 : }
5074 : :
5075 : : static void
5076 : 20 : blob_thin_prov_rw_iov(void)
5077 : : {
5078 : : static const uint8_t zero[10 * BLOCKLEN] = { 0 };
5079 : 20 : struct spdk_blob_store *bs = g_bs;
5080 : : struct spdk_blob *blob;
5081 : : struct spdk_io_channel *channel;
5082 : 15 : struct spdk_blob_opts opts;
5083 : : uint64_t free_clusters;
5084 : 15 : uint8_t payload_read[10 * BLOCKLEN];
5085 : 15 : uint8_t payload_write[10 * BLOCKLEN];
5086 : 15 : struct iovec iov_read[3];
5087 : 15 : struct iovec iov_write[3];
5088 : :
5089 : 20 : free_clusters = spdk_bs_free_cluster_count(bs);
5090 : :
5091 : 20 : channel = spdk_bs_alloc_io_channel(bs);
5092 : 20 : CU_ASSERT(channel != NULL);
5093 : :
5094 : 20 : ut_spdk_blob_opts_init(&opts);
5095 : 20 : opts.thin_provision = true;
5096 : :
5097 : 20 : blob = ut_blob_create_and_open(bs, &opts);
5098 : 20 : CU_ASSERT(free_clusters == spdk_bs_free_cluster_count(bs));
5099 : :
5100 : 20 : CU_ASSERT(blob->active.num_clusters == 0);
5101 : :
5102 : : /* The blob started at 0 clusters. Resize it to be 5, but still unallocated. */
5103 : 20 : spdk_blob_resize(blob, 5, blob_op_complete, NULL);
5104 : 20 : poll_threads();
5105 : 20 : CU_ASSERT(g_bserrno == 0);
5106 : 20 : CU_ASSERT(free_clusters == spdk_bs_free_cluster_count(bs));
5107 : 20 : CU_ASSERT(blob->active.num_clusters == 5);
5108 : :
5109 : 20 : spdk_blob_sync_md(blob, blob_op_complete, NULL);
5110 : 20 : poll_threads();
5111 : 20 : CU_ASSERT(g_bserrno == 0);
5112 : : /* Sync must not change anything */
5113 : 20 : CU_ASSERT(free_clusters == spdk_bs_free_cluster_count(bs));
5114 : 20 : CU_ASSERT(blob->active.num_clusters == 5);
5115 : :
5116 : : /* Payload should be all zeros from unallocated clusters */
5117 : 20 : memset(payload_read, 0xAA, sizeof(payload_read));
5118 : 20 : iov_read[0].iov_base = payload_read;
5119 : 20 : iov_read[0].iov_len = 3 * BLOCKLEN;
5120 : 20 : iov_read[1].iov_base = payload_read + 3 * BLOCKLEN;
5121 : 20 : iov_read[1].iov_len = 4 * BLOCKLEN;
5122 : 20 : iov_read[2].iov_base = payload_read + 7 * BLOCKLEN;
5123 : 20 : iov_read[2].iov_len = 3 * BLOCKLEN;
5124 : 20 : spdk_blob_io_readv(blob, channel, iov_read, 3, 250, 10, blob_op_complete, NULL);
5125 : 20 : poll_threads();
5126 : 20 : CU_ASSERT(g_bserrno == 0);
5127 : 20 : CU_ASSERT(memcmp(zero, payload_read, 10 * BLOCKLEN) == 0);
5128 : :
5129 : 20 : memset(payload_write, 0xE5, sizeof(payload_write));
5130 : 20 : iov_write[0].iov_base = payload_write;
5131 : 20 : iov_write[0].iov_len = 1 * BLOCKLEN;
5132 : 20 : iov_write[1].iov_base = payload_write + 1 * BLOCKLEN;
5133 : 20 : iov_write[1].iov_len = 5 * BLOCKLEN;
5134 : 20 : iov_write[2].iov_base = payload_write + 6 * BLOCKLEN;
5135 : 20 : iov_write[2].iov_len = 4 * BLOCKLEN;
5136 : :
5137 : 20 : spdk_blob_io_writev(blob, channel, iov_write, 3, 250, 10, blob_op_complete, NULL);
5138 : 20 : poll_threads();
5139 : 20 : CU_ASSERT(g_bserrno == 0);
5140 : :
5141 : 20 : memset(payload_read, 0xAA, sizeof(payload_read));
5142 : 20 : iov_read[0].iov_base = payload_read;
5143 : 20 : iov_read[0].iov_len = 3 * BLOCKLEN;
5144 : 20 : iov_read[1].iov_base = payload_read + 3 * BLOCKLEN;
5145 : 20 : iov_read[1].iov_len = 4 * BLOCKLEN;
5146 : 20 : iov_read[2].iov_base = payload_read + 7 * BLOCKLEN;
5147 : 20 : iov_read[2].iov_len = 3 * BLOCKLEN;
5148 : 20 : spdk_blob_io_readv(blob, channel, iov_read, 3, 250, 10, blob_op_complete, NULL);
5149 : 20 : poll_threads();
5150 : 20 : CU_ASSERT(g_bserrno == 0);
5151 : 20 : CU_ASSERT(memcmp(payload_write, payload_read, 10 * BLOCKLEN) == 0);
5152 : :
5153 : 20 : spdk_bs_free_io_channel(channel);
5154 : 20 : poll_threads();
5155 : :
5156 : 20 : ut_blob_close_and_delete(bs, blob);
5157 : 20 : }
5158 : :
5159 : : struct iter_ctx {
5160 : : int current_iter;
5161 : : spdk_blob_id blobid[4];
5162 : : };
5163 : :
5164 : : static void
5165 : 160 : test_iter(void *arg, struct spdk_blob *blob, int bserrno)
5166 : : {
5167 : 160 : struct iter_ctx *iter_ctx = arg;
5168 : : spdk_blob_id blobid;
5169 : :
5170 : 160 : CU_ASSERT(bserrno == 0);
5171 : 160 : blobid = spdk_blob_get_id(blob);
5172 : 160 : CU_ASSERT(blobid == iter_ctx->blobid[iter_ctx->current_iter++]);
5173 : 160 : }
5174 : :
5175 : : static void
5176 : 20 : bs_load_iter_test(void)
5177 : : {
5178 : : struct spdk_blob_store *bs;
5179 : : struct spdk_bs_dev *dev;
5180 : 20 : struct iter_ctx iter_ctx = { 0 };
5181 : : struct spdk_blob *blob;
5182 : : int i, rc;
5183 : 15 : struct spdk_bs_opts opts;
5184 : :
5185 : 20 : dev = init_dev();
5186 : 20 : spdk_bs_opts_init(&opts, sizeof(opts));
5187 [ - + ]: 20 : snprintf(opts.bstype.bstype, sizeof(opts.bstype.bstype), "TESTTYPE");
5188 : :
5189 : : /* Initialize a new blob store */
5190 : 20 : spdk_bs_init(dev, &opts, bs_op_with_handle_complete, NULL);
5191 : 20 : poll_threads();
5192 : 20 : CU_ASSERT(g_bserrno == 0);
5193 [ + + ]: 20 : SPDK_CU_ASSERT_FATAL(g_bs != NULL);
5194 : 20 : bs = g_bs;
5195 : :
5196 [ + + ]: 100 : for (i = 0; i < 4; i++) {
5197 : 80 : blob = ut_blob_create_and_open(bs, NULL);
5198 : 80 : iter_ctx.blobid[i] = spdk_blob_get_id(blob);
5199 : :
5200 : : /* Just save the blobid as an xattr for testing purposes. */
5201 : 80 : rc = spdk_blob_set_xattr(blob, "blobid", &iter_ctx.blobid[i], sizeof(spdk_blob_id));
5202 : 80 : CU_ASSERT(rc == 0);
5203 : :
5204 : : /* Resize the blob */
5205 : 80 : spdk_blob_resize(blob, i, blob_op_complete, NULL);
5206 : 80 : poll_threads();
5207 : 80 : CU_ASSERT(g_bserrno == 0);
5208 : :
5209 : 80 : spdk_blob_close(blob, blob_op_complete, NULL);
5210 : 80 : poll_threads();
5211 : 80 : CU_ASSERT(g_bserrno == 0);
5212 : 20 : }
5213 : :
5214 : 20 : g_bserrno = -1;
5215 : 20 : spdk_bs_unload(bs, bs_op_complete, NULL);
5216 : 20 : poll_threads();
5217 : 20 : CU_ASSERT(g_bserrno == 0);
5218 : :
5219 : 20 : dev = init_dev();
5220 : 20 : spdk_bs_opts_init(&opts, sizeof(opts));
5221 [ - + ]: 20 : snprintf(opts.bstype.bstype, sizeof(opts.bstype.bstype), "TESTTYPE");
5222 : 20 : opts.iter_cb_fn = test_iter;
5223 : 20 : opts.iter_cb_arg = &iter_ctx;
5224 : :
5225 : : /* Test blob iteration during load after a clean shutdown. */
5226 : 20 : spdk_bs_load(dev, &opts, bs_op_with_handle_complete, NULL);
5227 : 20 : poll_threads();
5228 : 20 : CU_ASSERT(g_bserrno == 0);
5229 [ + + ]: 20 : SPDK_CU_ASSERT_FATAL(g_bs != NULL);
5230 : 20 : bs = g_bs;
5231 : :
5232 : : /* Dirty shutdown */
5233 : 20 : bs_free(bs);
5234 : :
5235 : 20 : dev = init_dev();
5236 : 20 : spdk_bs_opts_init(&opts, sizeof(opts));
5237 [ - + ]: 20 : snprintf(opts.bstype.bstype, sizeof(opts.bstype.bstype), "TESTTYPE");
5238 : 20 : opts.iter_cb_fn = test_iter;
5239 : 20 : iter_ctx.current_iter = 0;
5240 : 20 : opts.iter_cb_arg = &iter_ctx;
5241 : :
5242 : : /* Test blob iteration during load after a dirty shutdown. */
5243 : 20 : spdk_bs_load(dev, &opts, bs_op_with_handle_complete, NULL);
5244 : 20 : poll_threads();
5245 : 20 : CU_ASSERT(g_bserrno == 0);
5246 [ - + ]: 20 : SPDK_CU_ASSERT_FATAL(g_bs != NULL);
5247 : 20 : bs = g_bs;
5248 : :
5249 : 20 : spdk_bs_unload(bs, bs_op_complete, NULL);
5250 : 20 : poll_threads();
5251 : 20 : CU_ASSERT(g_bserrno == 0);
5252 : 20 : g_bs = NULL;
5253 : 20 : }
5254 : :
5255 : : static void
5256 : 20 : blob_snapshot_rw(void)
5257 : : {
5258 : : static const uint8_t zero[10 * BLOCKLEN] = { 0 };
5259 : 20 : struct spdk_blob_store *bs = g_bs;
5260 : : struct spdk_blob *blob, *snapshot;
5261 : : struct spdk_io_channel *channel;
5262 : 15 : struct spdk_blob_opts opts;
5263 : : spdk_blob_id blobid, snapshotid;
5264 : : uint64_t free_clusters;
5265 : : uint64_t cluster_size;
5266 : : uint64_t io_unit_size;
5267 : 15 : uint8_t payload_read[10 * BLOCKLEN];
5268 : 15 : uint8_t payload_write[10 * BLOCKLEN];
5269 : : uint64_t write_bytes_start;
5270 : : uint64_t read_bytes_start;
5271 : : uint64_t copy_bytes_start;
5272 : : uint64_t write_bytes;
5273 : : uint64_t read_bytes;
5274 : : uint64_t copy_bytes;
5275 : : uint64_t expected_bytes;
5276 : :
5277 : 20 : free_clusters = spdk_bs_free_cluster_count(bs);
5278 : 20 : cluster_size = spdk_bs_get_cluster_size(bs);
5279 : 20 : io_unit_size = spdk_bs_get_io_unit_size(bs);
5280 : :
5281 : 20 : channel = spdk_bs_alloc_io_channel(bs);
5282 : 20 : CU_ASSERT(channel != NULL);
5283 : :
5284 : 20 : ut_spdk_blob_opts_init(&opts);
5285 : 20 : opts.thin_provision = true;
5286 : 20 : opts.num_clusters = 5;
5287 : :
5288 : 20 : blob = ut_blob_create_and_open(bs, &opts);
5289 : 20 : blobid = spdk_blob_get_id(blob);
5290 : 20 : CU_ASSERT(free_clusters == spdk_bs_free_cluster_count(bs));
5291 : :
5292 : 20 : CU_ASSERT(spdk_blob_get_num_clusters(blob) == 5);
5293 : :
5294 : 20 : memset(payload_read, 0xFF, sizeof(payload_read));
5295 : 20 : spdk_blob_io_read(blob, channel, payload_read, 4, 10, blob_op_complete, NULL);
5296 : 20 : poll_threads();
5297 : 20 : CU_ASSERT(g_bserrno == 0);
5298 : 20 : CU_ASSERT(memcmp(zero, payload_read, 10 * BLOCKLEN) == 0);
5299 : :
5300 : 20 : memset(payload_write, 0xE5, sizeof(payload_write));
5301 : 20 : spdk_blob_io_write(blob, channel, payload_write, 4, 10, blob_op_complete, NULL);
5302 : 20 : poll_threads();
5303 : 20 : CU_ASSERT(g_bserrno == 0);
5304 : 20 : CU_ASSERT(free_clusters != spdk_bs_free_cluster_count(bs));
5305 : :
5306 : : /* Create snapshot from blob */
5307 : 20 : spdk_bs_create_snapshot(bs, blobid, NULL, blob_op_with_id_complete, NULL);
5308 : 20 : poll_threads();
5309 : 20 : CU_ASSERT(g_bserrno == 0);
5310 : 20 : CU_ASSERT(g_blobid != SPDK_BLOBID_INVALID);
5311 : 20 : snapshotid = g_blobid;
5312 : :
5313 : 20 : spdk_bs_open_blob(bs, snapshotid, blob_op_with_handle_complete, NULL);
5314 : 20 : poll_threads();
5315 : 20 : CU_ASSERT(g_bserrno == 0);
5316 [ + + ]: 20 : SPDK_CU_ASSERT_FATAL(g_blob != NULL);
5317 : 20 : snapshot = g_blob;
5318 [ - + ]: 20 : CU_ASSERT(snapshot->data_ro == true);
5319 [ - + ]: 20 : CU_ASSERT(snapshot->md_ro == true);
5320 : :
5321 : 20 : CU_ASSERT(spdk_blob_get_num_clusters(snapshot) == 5);
5322 : :
5323 : 20 : write_bytes_start = g_dev_write_bytes;
5324 : 20 : read_bytes_start = g_dev_read_bytes;
5325 : 20 : copy_bytes_start = g_dev_copy_bytes;
5326 : :
5327 : 20 : memset(payload_write, 0xAA, sizeof(payload_write));
5328 : 20 : spdk_blob_io_write(blob, channel, payload_write, 4, 10, blob_op_complete, NULL);
5329 : 20 : poll_threads();
5330 : 20 : CU_ASSERT(g_bserrno == 0);
5331 : 20 : CU_ASSERT(free_clusters != spdk_bs_free_cluster_count(bs));
5332 : :
5333 : : /* For a clone we need to allocate and copy one cluster, update one page of metadata
5334 : : * and then write 10 io units of payload.
5335 : : */
5336 : 20 : write_bytes = g_dev_write_bytes - write_bytes_start;
5337 : 20 : read_bytes = g_dev_read_bytes - read_bytes_start;
5338 : 20 : copy_bytes = g_dev_copy_bytes - copy_bytes_start;
5339 [ + + + + ]: 20 : if (g_dev_copy_enabled) {
5340 : 8 : CU_ASSERT(copy_bytes == cluster_size);
5341 : 2 : } else {
5342 : 12 : CU_ASSERT(copy_bytes == 0);
5343 : : }
5344 : 20 : expected_bytes = 10 * io_unit_size + cluster_size + spdk_bs_get_page_size(bs);
5345 [ + + + + ]: 20 : if (g_use_extent_table) {
5346 : : /* Add one more page for EXTENT_PAGE write */
5347 : 12 : expected_bytes += spdk_bs_get_page_size(bs);
5348 : 3 : }
5349 : 20 : CU_ASSERT(write_bytes + copy_bytes == expected_bytes);
5350 : 20 : CU_ASSERT(read_bytes + copy_bytes == cluster_size);
5351 : :
5352 : 20 : spdk_blob_io_read(blob, channel, payload_read, 4, 10, blob_op_complete, NULL);
5353 : 20 : poll_threads();
5354 : 20 : CU_ASSERT(g_bserrno == 0);
5355 : 20 : CU_ASSERT(memcmp(payload_write, payload_read, 10 * BLOCKLEN) == 0);
5356 : :
5357 : : /* Data on snapshot should not change after write to clone */
5358 : 20 : memset(payload_write, 0xE5, sizeof(payload_write));
5359 : 20 : spdk_blob_io_read(snapshot, channel, payload_read, 4, 10, blob_op_complete, NULL);
5360 : 20 : poll_threads();
5361 : 20 : CU_ASSERT(g_bserrno == 0);
5362 : 20 : CU_ASSERT(memcmp(payload_write, payload_read, 10 * BLOCKLEN) == 0);
5363 : :
5364 : 20 : ut_blob_close_and_delete(bs, blob);
5365 : 20 : ut_blob_close_and_delete(bs, snapshot);
5366 : :
5367 : 20 : spdk_bs_free_io_channel(channel);
5368 : 20 : poll_threads();
5369 : 20 : g_blob = NULL;
5370 : 20 : g_blobid = 0;
5371 : 20 : }
5372 : :
5373 : : static void
5374 : 20 : blob_snapshot_rw_iov(void)
5375 : : {
5376 : : static const uint8_t zero[10 * BLOCKLEN] = { 0 };
5377 : 20 : struct spdk_blob_store *bs = g_bs;
5378 : : struct spdk_blob *blob, *snapshot;
5379 : : struct spdk_io_channel *channel;
5380 : 15 : struct spdk_blob_opts opts;
5381 : : spdk_blob_id blobid, snapshotid;
5382 : : uint64_t free_clusters;
5383 : 15 : uint8_t payload_read[10 * BLOCKLEN];
5384 : 15 : uint8_t payload_write[10 * BLOCKLEN];
5385 : 15 : struct iovec iov_read[3];
5386 : 15 : struct iovec iov_write[3];
5387 : :
5388 : 20 : free_clusters = spdk_bs_free_cluster_count(bs);
5389 : :
5390 : 20 : channel = spdk_bs_alloc_io_channel(bs);
5391 : 20 : CU_ASSERT(channel != NULL);
5392 : :
5393 : 20 : ut_spdk_blob_opts_init(&opts);
5394 : 20 : opts.thin_provision = true;
5395 : 20 : opts.num_clusters = 5;
5396 : :
5397 : 20 : blob = ut_blob_create_and_open(bs, &opts);
5398 : 20 : blobid = spdk_blob_get_id(blob);
5399 : 20 : CU_ASSERT(free_clusters == spdk_bs_free_cluster_count(bs));
5400 : :
5401 : 20 : CU_ASSERT(spdk_blob_get_num_clusters(blob) == 5);
5402 : :
5403 : : /* Create snapshot from blob */
5404 : 20 : spdk_bs_create_snapshot(bs, blobid, NULL, blob_op_with_id_complete, NULL);
5405 : 20 : poll_threads();
5406 : 20 : CU_ASSERT(g_bserrno == 0);
5407 : 20 : CU_ASSERT(g_blobid != SPDK_BLOBID_INVALID);
5408 : 20 : snapshotid = g_blobid;
5409 : :
5410 : 20 : spdk_bs_open_blob(bs, snapshotid, blob_op_with_handle_complete, NULL);
5411 : 20 : poll_threads();
5412 : 20 : CU_ASSERT(g_bserrno == 0);
5413 [ + + ]: 20 : SPDK_CU_ASSERT_FATAL(g_blob != NULL);
5414 : 20 : snapshot = g_blob;
5415 [ - + ]: 20 : CU_ASSERT(snapshot->data_ro == true);
5416 [ - + ]: 20 : CU_ASSERT(snapshot->md_ro == true);
5417 : 20 : CU_ASSERT(spdk_blob_get_num_clusters(snapshot) == 5);
5418 : :
5419 : : /* Payload should be all zeros from unallocated clusters */
5420 : 20 : memset(payload_read, 0xAA, sizeof(payload_read));
5421 : 20 : iov_read[0].iov_base = payload_read;
5422 : 20 : iov_read[0].iov_len = 3 * BLOCKLEN;
5423 : 20 : iov_read[1].iov_base = payload_read + 3 * BLOCKLEN;
5424 : 20 : iov_read[1].iov_len = 4 * BLOCKLEN;
5425 : 20 : iov_read[2].iov_base = payload_read + 7 * BLOCKLEN;
5426 : 20 : iov_read[2].iov_len = 3 * BLOCKLEN;
5427 : 20 : spdk_blob_io_readv(blob, channel, iov_read, 3, 250, 10, blob_op_complete, NULL);
5428 : 20 : poll_threads();
5429 : 20 : CU_ASSERT(g_bserrno == 0);
5430 : 20 : CU_ASSERT(memcmp(zero, payload_read, 10 * BLOCKLEN) == 0);
5431 : :
5432 : 20 : memset(payload_write, 0xE5, sizeof(payload_write));
5433 : 20 : iov_write[0].iov_base = payload_write;
5434 : 20 : iov_write[0].iov_len = 1 * BLOCKLEN;
5435 : 20 : iov_write[1].iov_base = payload_write + 1 * BLOCKLEN;
5436 : 20 : iov_write[1].iov_len = 5 * BLOCKLEN;
5437 : 20 : iov_write[2].iov_base = payload_write + 6 * BLOCKLEN;
5438 : 20 : iov_write[2].iov_len = 4 * BLOCKLEN;
5439 : :
5440 : 20 : spdk_blob_io_writev(blob, channel, iov_write, 3, 250, 10, blob_op_complete, NULL);
5441 : 20 : poll_threads();
5442 : 20 : CU_ASSERT(g_bserrno == 0);
5443 : :
5444 : 20 : memset(payload_read, 0xAA, sizeof(payload_read));
5445 : 20 : iov_read[0].iov_base = payload_read;
5446 : 20 : iov_read[0].iov_len = 3 * BLOCKLEN;
5447 : 20 : iov_read[1].iov_base = payload_read + 3 * BLOCKLEN;
5448 : 20 : iov_read[1].iov_len = 4 * BLOCKLEN;
5449 : 20 : iov_read[2].iov_base = payload_read + 7 * BLOCKLEN;
5450 : 20 : iov_read[2].iov_len = 3 * BLOCKLEN;
5451 : 20 : spdk_blob_io_readv(blob, channel, iov_read, 3, 250, 10, blob_op_complete, NULL);
5452 : 20 : poll_threads();
5453 : 20 : CU_ASSERT(g_bserrno == 0);
5454 : 20 : CU_ASSERT(memcmp(payload_write, payload_read, 10 * BLOCKLEN) == 0);
5455 : :
5456 : 20 : spdk_bs_free_io_channel(channel);
5457 : 20 : poll_threads();
5458 : :
5459 : 20 : ut_blob_close_and_delete(bs, blob);
5460 : 20 : ut_blob_close_and_delete(bs, snapshot);
5461 : 20 : }
5462 : :
5463 : : /**
5464 : : * Inflate / decouple parent rw unit tests.
5465 : : *
5466 : : * --------------
5467 : : * original blob: 0 1 2 3 4
5468 : : * ,---------+---------+---------+---------+---------.
5469 : : * snapshot |xxxxxxxxx|xxxxxxxxx|xxxxxxxxx|xxxxxxxxx| - |
5470 : : * +---------+---------+---------+---------+---------+
5471 : : * snapshot2 | - |yyyyyyyyy| - |yyyyyyyyy| - |
5472 : : * +---------+---------+---------+---------+---------+
5473 : : * blob | - |zzzzzzzzz| - | - | - |
5474 : : * '---------+---------+---------+---------+---------'
5475 : : * . . . . . .
5476 : : * -------- . . . . . .
5477 : : * inflate: . . . . . .
5478 : : * ,---------+---------+---------+---------+---------.
5479 : : * blob |xxxxxxxxx|zzzzzzzzz|xxxxxxxxx|yyyyyyyyy|000000000|
5480 : : * '---------+---------+---------+---------+---------'
5481 : : *
5482 : : * NOTE: needs to allocate 4 clusters, thin provisioning removed, dependency
5483 : : * on snapshot2 and snapshot removed . . .
5484 : : * . . . . . .
5485 : : * ---------------- . . . . . .
5486 : : * decouple parent: . . . . . .
5487 : : * ,---------+---------+---------+---------+---------.
5488 : : * snapshot |xxxxxxxxx|xxxxxxxxx|xxxxxxxxx|xxxxxxxxx| - |
5489 : : * +---------+---------+---------+---------+---------+
5490 : : * blob | - |zzzzzzzzz| - |yyyyyyyyy| - |
5491 : : * '---------+---------+---------+---------+---------'
5492 : : *
5493 : : * NOTE: needs to allocate 1 cluster, 3 clusters unallocated, dependency
5494 : : * on snapshot2 removed and on snapshot still exists. Snapshot2
5495 : : * should remain a clone of snapshot.
5496 : : */
5497 : : static void
5498 : 40 : _blob_inflate_rw(bool decouple_parent)
5499 : : {
5500 : 40 : struct spdk_blob_store *bs = g_bs;
5501 : : struct spdk_blob *blob, *snapshot, *snapshot2;
5502 : : struct spdk_io_channel *channel;
5503 : 30 : struct spdk_blob_opts opts;
5504 : : spdk_blob_id blobid, snapshotid, snapshot2id;
5505 : : uint64_t free_clusters;
5506 : : uint64_t cluster_size;
5507 : :
5508 : : uint64_t payload_size;
5509 : : uint8_t *payload_read;
5510 : : uint8_t *payload_write;
5511 : : uint8_t *payload_clone;
5512 : :
5513 : : uint64_t io_units_per_cluster;
5514 : : uint64_t io_units_per_payload;
5515 : :
5516 : : int i;
5517 : 30 : spdk_blob_id ids[2];
5518 : 30 : size_t count;
5519 : :
5520 : 40 : free_clusters = spdk_bs_free_cluster_count(bs);
5521 : 40 : cluster_size = spdk_bs_get_cluster_size(bs);
5522 [ - + ]: 40 : io_units_per_cluster = cluster_size / spdk_bs_get_io_unit_size(bs);
5523 : 40 : io_units_per_payload = io_units_per_cluster * 5;
5524 : :
5525 : 40 : payload_size = cluster_size * 5;
5526 : :
5527 : 40 : payload_read = malloc(payload_size);
5528 [ + + ]: 40 : SPDK_CU_ASSERT_FATAL(payload_read != NULL);
5529 : :
5530 : 40 : payload_write = malloc(payload_size);
5531 [ + + ]: 40 : SPDK_CU_ASSERT_FATAL(payload_write != NULL);
5532 : :
5533 : 40 : payload_clone = malloc(payload_size);
5534 [ + + ]: 40 : SPDK_CU_ASSERT_FATAL(payload_clone != NULL);
5535 : :
5536 : 40 : channel = spdk_bs_alloc_io_channel(bs);
5537 [ + + ]: 40 : SPDK_CU_ASSERT_FATAL(channel != NULL);
5538 : :
5539 : : /* Create blob */
5540 : 40 : ut_spdk_blob_opts_init(&opts);
5541 : 40 : opts.thin_provision = true;
5542 : 40 : opts.num_clusters = 5;
5543 : :
5544 : 40 : blob = ut_blob_create_and_open(bs, &opts);
5545 : 40 : blobid = spdk_blob_get_id(blob);
5546 : 40 : CU_ASSERT(free_clusters == spdk_bs_free_cluster_count(bs));
5547 : :
5548 : 40 : CU_ASSERT(spdk_blob_get_num_clusters(blob) == 5);
5549 : :
5550 : : /* 1) Initial read should return zeroed payload */
5551 [ - + ]: 40 : memset(payload_read, 0xFF, payload_size);
5552 : 40 : spdk_blob_io_read(blob, channel, payload_read, 0, io_units_per_payload,
5553 : : blob_op_complete, NULL);
5554 : 40 : poll_threads();
5555 : 40 : CU_ASSERT(g_bserrno == 0);
5556 : 40 : CU_ASSERT(spdk_mem_all_zero(payload_read, payload_size));
5557 : :
5558 : : /* Fill whole blob with a pattern, except last cluster (to be sure it
5559 : : * isn't allocated) */
5560 [ - + ]: 40 : memset(payload_write, 0xE5, payload_size - cluster_size);
5561 : 50 : spdk_blob_io_write(blob, channel, payload_write, 0, io_units_per_payload -
5562 : 10 : io_units_per_cluster, blob_op_complete, NULL);
5563 : 40 : poll_threads();
5564 : 40 : CU_ASSERT(g_bserrno == 0);
5565 : 40 : CU_ASSERT(free_clusters != spdk_bs_free_cluster_count(bs));
5566 : :
5567 : : /* 2) Create snapshot from blob (first level) */
5568 : 40 : spdk_bs_create_snapshot(bs, blobid, NULL, blob_op_with_id_complete, NULL);
5569 : 40 : poll_threads();
5570 : 40 : CU_ASSERT(g_bserrno == 0);
5571 : 40 : CU_ASSERT(g_blobid != SPDK_BLOBID_INVALID);
5572 : 40 : snapshotid = g_blobid;
5573 : :
5574 : 40 : spdk_bs_open_blob(bs, snapshotid, blob_op_with_handle_complete, NULL);
5575 : 40 : poll_threads();
5576 : 40 : CU_ASSERT(g_bserrno == 0);
5577 [ + + ]: 40 : SPDK_CU_ASSERT_FATAL(g_blob != NULL);
5578 : 40 : snapshot = g_blob;
5579 [ - + ]: 40 : CU_ASSERT(snapshot->data_ro == true);
5580 [ - + ]: 40 : CU_ASSERT(snapshot->md_ro == true);
5581 : :
5582 : 40 : CU_ASSERT(spdk_blob_get_num_clusters(snapshot) == 5);
5583 : :
5584 : : /* Write every second cluster with a pattern.
5585 : : *
5586 : : * Last cluster shouldn't be written, to be sure that snapshot nor clone
5587 : : * doesn't allocate it.
5588 : : *
5589 : : * payload_clone stores expected result on "blob" read at the time and
5590 : : * is used only to check data consistency on clone before and after
5591 : : * inflation. Initially we fill it with a backing snapshots pattern
5592 : : * used before.
5593 : : */
5594 [ - + ]: 40 : memset(payload_clone, 0xE5, payload_size - cluster_size);
5595 [ - + ]: 40 : memset(payload_clone + payload_size - cluster_size, 0x00, cluster_size);
5596 [ - + ]: 40 : memset(payload_write, 0xAA, payload_size);
5597 [ + + ]: 120 : for (i = 1; i < 5; i += 2) {
5598 : 100 : spdk_blob_io_write(blob, channel, payload_write, i * io_units_per_cluster,
5599 : 20 : io_units_per_cluster, blob_op_complete, NULL);
5600 : 80 : poll_threads();
5601 : 80 : CU_ASSERT(g_bserrno == 0);
5602 : :
5603 : : /* Update expected result */
5604 [ - + - + ]: 100 : memcpy(payload_clone + (cluster_size * i), payload_write,
5605 : 20 : cluster_size);
5606 : 20 : }
5607 : 40 : CU_ASSERT(free_clusters != spdk_bs_free_cluster_count(bs));
5608 : :
5609 : : /* Check data consistency on clone */
5610 [ - + ]: 40 : memset(payload_read, 0xFF, payload_size);
5611 : 40 : spdk_blob_io_read(blob, channel, payload_read, 0, io_units_per_payload,
5612 : : blob_op_complete, NULL);
5613 : 40 : poll_threads();
5614 : 40 : CU_ASSERT(g_bserrno == 0);
5615 [ - + - + ]: 40 : CU_ASSERT(memcmp(payload_clone, payload_read, payload_size) == 0);
5616 : :
5617 : : /* 3) Create second levels snapshot from blob */
5618 : 40 : spdk_bs_create_snapshot(bs, blobid, NULL, blob_op_with_id_complete, NULL);
5619 : 40 : poll_threads();
5620 : 40 : CU_ASSERT(g_bserrno == 0);
5621 : 40 : CU_ASSERT(g_blobid != SPDK_BLOBID_INVALID);
5622 : 40 : snapshot2id = g_blobid;
5623 : :
5624 : 40 : spdk_bs_open_blob(bs, snapshot2id, blob_op_with_handle_complete, NULL);
5625 : 40 : poll_threads();
5626 : 40 : CU_ASSERT(g_bserrno == 0);
5627 [ + + ]: 40 : SPDK_CU_ASSERT_FATAL(g_blob != NULL);
5628 : 40 : snapshot2 = g_blob;
5629 [ - + ]: 40 : CU_ASSERT(snapshot2->data_ro == true);
5630 [ - + ]: 40 : CU_ASSERT(snapshot2->md_ro == true);
5631 : :
5632 : 40 : CU_ASSERT(spdk_blob_get_num_clusters(snapshot2) == 5);
5633 : :
5634 : 40 : CU_ASSERT(snapshot2->parent_id == snapshotid);
5635 : :
5636 : : /* Write one cluster on the top level blob. This cluster (1) covers
5637 : : * already allocated cluster in the snapshot2, so shouldn't be inflated
5638 : : * at all */
5639 : 50 : spdk_blob_io_write(blob, channel, payload_write, io_units_per_cluster,
5640 : 10 : io_units_per_cluster, blob_op_complete, NULL);
5641 : 40 : poll_threads();
5642 : 40 : CU_ASSERT(g_bserrno == 0);
5643 : :
5644 : : /* Update expected result */
5645 [ - + - + ]: 40 : memcpy(payload_clone + cluster_size, payload_write, cluster_size);
5646 : :
5647 : : /* Check data consistency on clone */
5648 [ - + ]: 40 : memset(payload_read, 0xFF, payload_size);
5649 : 40 : spdk_blob_io_read(blob, channel, payload_read, 0, io_units_per_payload,
5650 : : blob_op_complete, NULL);
5651 : 40 : poll_threads();
5652 : 40 : CU_ASSERT(g_bserrno == 0);
5653 [ - + - + ]: 40 : CU_ASSERT(memcmp(payload_clone, payload_read, payload_size) == 0);
5654 : :
5655 : :
5656 : : /* Close all blobs */
5657 : 40 : spdk_blob_close(blob, blob_op_complete, NULL);
5658 : 40 : poll_threads();
5659 : 40 : CU_ASSERT(g_bserrno == 0);
5660 : :
5661 : 40 : spdk_blob_close(snapshot2, blob_op_complete, NULL);
5662 : 40 : poll_threads();
5663 : 40 : CU_ASSERT(g_bserrno == 0);
5664 : :
5665 : 40 : spdk_blob_close(snapshot, blob_op_complete, NULL);
5666 : 40 : poll_threads();
5667 : 40 : CU_ASSERT(g_bserrno == 0);
5668 : :
5669 : : /* Check snapshot-clone relations */
5670 : 40 : count = 2;
5671 : 40 : CU_ASSERT(spdk_blob_get_clones(bs, snapshotid, ids, &count) == 0);
5672 : 40 : CU_ASSERT(count == 1);
5673 : 40 : CU_ASSERT(ids[0] == snapshot2id);
5674 : :
5675 : 40 : count = 2;
5676 : 40 : CU_ASSERT(spdk_blob_get_clones(bs, snapshot2id, ids, &count) == 0);
5677 : 40 : CU_ASSERT(count == 1);
5678 : 40 : CU_ASSERT(ids[0] == blobid);
5679 : :
5680 : 40 : CU_ASSERT(spdk_blob_get_parent_snapshot(bs, blobid) == snapshot2id);
5681 : :
5682 : 40 : free_clusters = spdk_bs_free_cluster_count(bs);
5683 [ + + ]: 40 : if (!decouple_parent) {
5684 : : /* Do full blob inflation */
5685 : 20 : spdk_bs_inflate_blob(bs, channel, blobid, blob_op_complete, NULL);
5686 : 20 : poll_threads();
5687 : 20 : CU_ASSERT(g_bserrno == 0);
5688 : :
5689 : : /* All clusters should be inflated (except one already allocated
5690 : : * in a top level blob) */
5691 : 20 : CU_ASSERT(spdk_bs_free_cluster_count(bs) == free_clusters - 4);
5692 : :
5693 : : /* Check if relation tree updated correctly */
5694 : 20 : count = 2;
5695 : 20 : CU_ASSERT(spdk_blob_get_clones(bs, snapshotid, ids, &count) == 0);
5696 : :
5697 : : /* snapshotid have one clone */
5698 : 20 : CU_ASSERT(count == 1);
5699 : 20 : CU_ASSERT(ids[0] == snapshot2id);
5700 : :
5701 : : /* snapshot2id have no clones */
5702 : 20 : count = 2;
5703 : 20 : CU_ASSERT(spdk_blob_get_clones(bs, snapshot2id, ids, &count) == 0);
5704 : 20 : CU_ASSERT(count == 0);
5705 : :
5706 : 20 : CU_ASSERT(spdk_blob_get_parent_snapshot(bs, blobid) == SPDK_BLOBID_INVALID);
5707 : 5 : } else {
5708 : : /* Decouple parent of blob */
5709 : 20 : spdk_bs_blob_decouple_parent(bs, channel, blobid, blob_op_complete, NULL);
5710 : 20 : poll_threads();
5711 : 20 : CU_ASSERT(g_bserrno == 0);
5712 : :
5713 : : /* Only one cluster from a parent should be inflated (second one
5714 : : * is covered by a cluster written on a top level blob, and
5715 : : * already allocated) */
5716 : 20 : CU_ASSERT(spdk_bs_free_cluster_count(bs) == free_clusters - 1);
5717 : :
5718 : : /* Check if relation tree updated correctly */
5719 : 20 : count = 2;
5720 : 20 : CU_ASSERT(spdk_blob_get_clones(bs, snapshotid, ids, &count) == 0);
5721 : :
5722 : : /* snapshotid have two clones now */
5723 : 20 : CU_ASSERT(count == 2);
5724 [ + + + - ]: 20 : CU_ASSERT(ids[0] == blobid || ids[1] == blobid);
5725 [ + + - - ]: 20 : CU_ASSERT(ids[0] == snapshot2id || ids[1] == snapshot2id);
5726 : :
5727 : : /* snapshot2id have no clones */
5728 : 20 : count = 2;
5729 : 20 : CU_ASSERT(spdk_blob_get_clones(bs, snapshot2id, ids, &count) == 0);
5730 : 20 : CU_ASSERT(count == 0);
5731 : :
5732 : 20 : CU_ASSERT(spdk_blob_get_parent_snapshot(bs, blobid) == snapshotid);
5733 : : }
5734 : :
5735 : : /* Try to delete snapshot2 (should pass) */
5736 : 40 : spdk_bs_delete_blob(bs, snapshot2id, blob_op_complete, NULL);
5737 : 40 : poll_threads();
5738 : 40 : CU_ASSERT(g_bserrno == 0);
5739 : :
5740 : : /* Try to delete base snapshot */
5741 : 40 : spdk_bs_delete_blob(bs, snapshotid, blob_op_complete, NULL);
5742 : 40 : poll_threads();
5743 : 40 : CU_ASSERT(g_bserrno == 0);
5744 : :
5745 : : /* Reopen blob after snapshot deletion */
5746 : 40 : spdk_bs_open_blob(bs, blobid, blob_op_with_handle_complete, NULL);
5747 : 40 : poll_threads();
5748 : 40 : CU_ASSERT(g_bserrno == 0);
5749 [ - + ]: 40 : SPDK_CU_ASSERT_FATAL(g_blob != NULL);
5750 : 40 : blob = g_blob;
5751 : :
5752 : 40 : CU_ASSERT(spdk_blob_get_num_clusters(blob) == 5);
5753 : :
5754 : : /* Check data consistency on inflated blob */
5755 [ - + ]: 40 : memset(payload_read, 0xFF, payload_size);
5756 : 40 : spdk_blob_io_read(blob, channel, payload_read, 0, io_units_per_payload,
5757 : : blob_op_complete, NULL);
5758 : 40 : poll_threads();
5759 : 40 : CU_ASSERT(g_bserrno == 0);
5760 [ - + - + ]: 40 : CU_ASSERT(memcmp(payload_clone, payload_read, payload_size) == 0);
5761 : :
5762 : 40 : spdk_bs_free_io_channel(channel);
5763 : 40 : poll_threads();
5764 : :
5765 : 40 : free(payload_read);
5766 : 40 : free(payload_write);
5767 : 40 : free(payload_clone);
5768 : :
5769 : 40 : ut_blob_close_and_delete(bs, blob);
5770 : 40 : }
5771 : :
5772 : : static void
5773 : 20 : blob_inflate_rw(void)
5774 : : {
5775 : 20 : _blob_inflate_rw(false);
5776 : 20 : _blob_inflate_rw(true);
5777 : 20 : }
5778 : :
5779 : : /**
5780 : : * Snapshot-clones relation test
5781 : : *
5782 : : * snapshot
5783 : : * |
5784 : : * +-----+-----+
5785 : : * | |
5786 : : * blob(ro) snapshot2
5787 : : * | |
5788 : : * clone2 clone
5789 : : */
5790 : : static void
5791 : 20 : blob_relations(void)
5792 : : {
5793 : 15 : struct spdk_blob_store *bs;
5794 : : struct spdk_bs_dev *dev;
5795 : 15 : struct spdk_bs_opts bs_opts;
5796 : 15 : struct spdk_blob_opts opts;
5797 : : struct spdk_blob *blob, *snapshot, *snapshot2, *clone, *clone2;
5798 : : spdk_blob_id blobid, cloneid, snapshotid, cloneid2, snapshotid2;
5799 : : int rc;
5800 : 15 : size_t count;
5801 : 20 : spdk_blob_id ids[10] = {};
5802 : :
5803 : 20 : dev = init_dev();
5804 : 20 : spdk_bs_opts_init(&bs_opts, sizeof(bs_opts));
5805 [ - + ]: 20 : snprintf(bs_opts.bstype.bstype, sizeof(bs_opts.bstype.bstype), "TESTTYPE");
5806 : :
5807 : 20 : spdk_bs_init(dev, &bs_opts, bs_op_with_handle_complete, NULL);
5808 : 20 : poll_threads();
5809 : 20 : CU_ASSERT(g_bserrno == 0);
5810 [ + + ]: 20 : SPDK_CU_ASSERT_FATAL(g_bs != NULL);
5811 : 20 : bs = g_bs;
5812 : :
5813 : : /* 1. Create blob with 10 clusters */
5814 : :
5815 : 20 : ut_spdk_blob_opts_init(&opts);
5816 : 20 : opts.num_clusters = 10;
5817 : :
5818 : 20 : blob = ut_blob_create_and_open(bs, &opts);
5819 : 20 : blobid = spdk_blob_get_id(blob);
5820 : :
5821 : 20 : CU_ASSERT(!spdk_blob_is_read_only(blob));
5822 : 20 : CU_ASSERT(!spdk_blob_is_snapshot(blob));
5823 : 20 : CU_ASSERT(!spdk_blob_is_clone(blob));
5824 : 20 : CU_ASSERT(!spdk_blob_is_thin_provisioned(blob));
5825 : :
5826 : : /* blob should not have underlying snapshot nor clones */
5827 : 20 : CU_ASSERT(blob->parent_id == SPDK_BLOBID_INVALID);
5828 : 20 : CU_ASSERT(spdk_blob_get_parent_snapshot(bs, blobid) == SPDK_BLOBID_INVALID);
5829 : 20 : count = SPDK_COUNTOF(ids);
5830 : 20 : rc = spdk_blob_get_clones(bs, blobid, ids, &count);
5831 : 20 : CU_ASSERT(rc == 0);
5832 : 20 : CU_ASSERT(count == 0);
5833 : :
5834 : :
5835 : : /* 2. Create snapshot */
5836 : :
5837 : 20 : spdk_bs_create_snapshot(bs, blobid, NULL, blob_op_with_id_complete, NULL);
5838 : 20 : poll_threads();
5839 : 20 : CU_ASSERT(g_bserrno == 0);
5840 : 20 : CU_ASSERT(g_blobid != SPDK_BLOBID_INVALID);
5841 : 20 : snapshotid = g_blobid;
5842 : :
5843 : 20 : spdk_bs_open_blob(bs, snapshotid, blob_op_with_handle_complete, NULL);
5844 : 20 : poll_threads();
5845 : 20 : CU_ASSERT(g_bserrno == 0);
5846 [ + + ]: 20 : SPDK_CU_ASSERT_FATAL(g_blob != NULL);
5847 : 20 : snapshot = g_blob;
5848 : :
5849 : 20 : CU_ASSERT(spdk_blob_is_read_only(snapshot));
5850 : 20 : CU_ASSERT(spdk_blob_is_snapshot(snapshot));
5851 : 20 : CU_ASSERT(!spdk_blob_is_clone(snapshot));
5852 : 20 : CU_ASSERT(snapshot->parent_id == SPDK_BLOBID_INVALID);
5853 : 20 : CU_ASSERT(spdk_blob_get_parent_snapshot(bs, snapshotid) == SPDK_BLOBID_INVALID);
5854 : :
5855 : : /* Check if original blob is converted to the clone of snapshot */
5856 : 20 : CU_ASSERT(!spdk_blob_is_read_only(blob));
5857 : 20 : CU_ASSERT(!spdk_blob_is_snapshot(blob));
5858 : 20 : CU_ASSERT(spdk_blob_is_clone(blob));
5859 : 20 : CU_ASSERT(spdk_blob_is_thin_provisioned(blob));
5860 : 20 : CU_ASSERT(blob->parent_id == snapshotid);
5861 : 20 : CU_ASSERT(spdk_blob_get_parent_snapshot(bs, blobid) == snapshotid);
5862 : :
5863 : 20 : count = SPDK_COUNTOF(ids);
5864 : 20 : rc = spdk_blob_get_clones(bs, snapshotid, ids, &count);
5865 : 20 : CU_ASSERT(rc == 0);
5866 : 20 : CU_ASSERT(count == 1);
5867 : 20 : CU_ASSERT(ids[0] == blobid);
5868 : :
5869 : :
5870 : : /* 3. Create clone from snapshot */
5871 : :
5872 : 20 : spdk_bs_create_clone(bs, snapshotid, NULL, blob_op_with_id_complete, NULL);
5873 : 20 : poll_threads();
5874 : 20 : CU_ASSERT(g_bserrno == 0);
5875 : 20 : CU_ASSERT(g_blobid != SPDK_BLOBID_INVALID);
5876 : 20 : cloneid = g_blobid;
5877 : :
5878 : 20 : spdk_bs_open_blob(bs, cloneid, blob_op_with_handle_complete, NULL);
5879 : 20 : poll_threads();
5880 : 20 : CU_ASSERT(g_bserrno == 0);
5881 [ + + ]: 20 : SPDK_CU_ASSERT_FATAL(g_blob != NULL);
5882 : 20 : clone = g_blob;
5883 : :
5884 : 20 : CU_ASSERT(!spdk_blob_is_read_only(clone));
5885 : 20 : CU_ASSERT(!spdk_blob_is_snapshot(clone));
5886 : 20 : CU_ASSERT(spdk_blob_is_clone(clone));
5887 : 20 : CU_ASSERT(spdk_blob_is_thin_provisioned(clone));
5888 : 20 : CU_ASSERT(clone->parent_id == snapshotid);
5889 : 20 : CU_ASSERT(spdk_blob_get_parent_snapshot(bs, cloneid) == snapshotid);
5890 : :
5891 : 20 : count = SPDK_COUNTOF(ids);
5892 : 20 : rc = spdk_blob_get_clones(bs, cloneid, ids, &count);
5893 : 20 : CU_ASSERT(rc == 0);
5894 : 20 : CU_ASSERT(count == 0);
5895 : :
5896 : : /* Check if clone is on the snapshot's list */
5897 : 20 : count = SPDK_COUNTOF(ids);
5898 : 20 : rc = spdk_blob_get_clones(bs, snapshotid, ids, &count);
5899 : 20 : CU_ASSERT(rc == 0);
5900 [ + + - - ]: 20 : CU_ASSERT(ids[0] == blobid || ids[1] == blobid);
5901 [ + + + - ]: 20 : CU_ASSERT(ids[0] == cloneid || ids[1] == cloneid);
5902 : :
5903 : :
5904 : : /* 4. Create snapshot of the clone */
5905 : :
5906 : 20 : spdk_bs_create_snapshot(bs, cloneid, NULL, blob_op_with_id_complete, NULL);
5907 : 20 : poll_threads();
5908 : 20 : CU_ASSERT(g_bserrno == 0);
5909 : 20 : CU_ASSERT(g_blobid != SPDK_BLOBID_INVALID);
5910 : 20 : snapshotid2 = g_blobid;
5911 : :
5912 : 20 : spdk_bs_open_blob(bs, snapshotid2, blob_op_with_handle_complete, NULL);
5913 : 20 : poll_threads();
5914 : 20 : CU_ASSERT(g_bserrno == 0);
5915 [ + + ]: 20 : SPDK_CU_ASSERT_FATAL(g_blob != NULL);
5916 : 20 : snapshot2 = g_blob;
5917 : :
5918 : 20 : CU_ASSERT(spdk_blob_is_read_only(snapshot2));
5919 : 20 : CU_ASSERT(spdk_blob_is_snapshot(snapshot2));
5920 : 20 : CU_ASSERT(spdk_blob_is_clone(snapshot2));
5921 : 20 : CU_ASSERT(snapshot2->parent_id == snapshotid);
5922 : 20 : CU_ASSERT(spdk_blob_get_parent_snapshot(bs, snapshotid2) == snapshotid);
5923 : :
5924 : : /* Check if clone is converted to the clone of snapshot2 and snapshot2
5925 : : * is a child of snapshot */
5926 : 20 : CU_ASSERT(!spdk_blob_is_read_only(clone));
5927 : 20 : CU_ASSERT(!spdk_blob_is_snapshot(clone));
5928 : 20 : CU_ASSERT(spdk_blob_is_clone(clone));
5929 : 20 : CU_ASSERT(spdk_blob_is_thin_provisioned(clone));
5930 : 20 : CU_ASSERT(clone->parent_id == snapshotid2);
5931 : 20 : CU_ASSERT(spdk_blob_get_parent_snapshot(bs, cloneid) == snapshotid2);
5932 : :
5933 : 20 : count = SPDK_COUNTOF(ids);
5934 : 20 : rc = spdk_blob_get_clones(bs, snapshotid2, ids, &count);
5935 : 20 : CU_ASSERT(rc == 0);
5936 : 20 : CU_ASSERT(count == 1);
5937 : 20 : CU_ASSERT(ids[0] == cloneid);
5938 : :
5939 : :
5940 : : /* 5. Try to create clone from read only blob */
5941 : :
5942 : : /* Mark blob as read only */
5943 : 20 : spdk_blob_set_read_only(blob);
5944 : 20 : spdk_blob_sync_md(blob, blob_op_complete, NULL);
5945 : 20 : poll_threads();
5946 : 20 : CU_ASSERT(g_bserrno == 0);
5947 : :
5948 : : /* Check if previously created blob is read only clone */
5949 : 20 : CU_ASSERT(spdk_blob_is_read_only(blob));
5950 : 20 : CU_ASSERT(!spdk_blob_is_snapshot(blob));
5951 : 20 : CU_ASSERT(spdk_blob_is_clone(blob));
5952 : 20 : CU_ASSERT(spdk_blob_is_thin_provisioned(blob));
5953 : :
5954 : : /* Create clone from read only blob */
5955 : 20 : spdk_bs_create_clone(bs, blobid, NULL, blob_op_with_id_complete, NULL);
5956 : 20 : poll_threads();
5957 : 20 : CU_ASSERT(g_bserrno == 0);
5958 : 20 : CU_ASSERT(g_blobid != SPDK_BLOBID_INVALID);
5959 : 20 : cloneid2 = g_blobid;
5960 : :
5961 : 20 : spdk_bs_open_blob(bs, cloneid2, blob_op_with_handle_complete, NULL);
5962 : 20 : poll_threads();
5963 : 20 : CU_ASSERT(g_bserrno == 0);
5964 [ - + ]: 20 : SPDK_CU_ASSERT_FATAL(g_blob != NULL);
5965 : 20 : clone2 = g_blob;
5966 : :
5967 : 20 : CU_ASSERT(!spdk_blob_is_read_only(clone2));
5968 : 20 : CU_ASSERT(!spdk_blob_is_snapshot(clone2));
5969 : 20 : CU_ASSERT(spdk_blob_is_clone(clone2));
5970 : 20 : CU_ASSERT(spdk_blob_is_thin_provisioned(clone2));
5971 : :
5972 : 20 : CU_ASSERT(spdk_blob_get_parent_snapshot(bs, cloneid2) == blobid);
5973 : :
5974 : 20 : count = SPDK_COUNTOF(ids);
5975 : 20 : rc = spdk_blob_get_clones(bs, blobid, ids, &count);
5976 : 20 : CU_ASSERT(rc == 0);
5977 : :
5978 : 20 : CU_ASSERT(count == 1);
5979 : 20 : CU_ASSERT(ids[0] == cloneid2);
5980 : :
5981 : : /* Close blobs */
5982 : :
5983 : 20 : spdk_blob_close(clone2, blob_op_complete, NULL);
5984 : 20 : poll_threads();
5985 : 20 : CU_ASSERT(g_bserrno == 0);
5986 : :
5987 : 20 : spdk_blob_close(blob, blob_op_complete, NULL);
5988 : 20 : poll_threads();
5989 : 20 : CU_ASSERT(g_bserrno == 0);
5990 : :
5991 : 20 : spdk_blob_close(clone, blob_op_complete, NULL);
5992 : 20 : poll_threads();
5993 : 20 : CU_ASSERT(g_bserrno == 0);
5994 : :
5995 : 20 : spdk_blob_close(snapshot, blob_op_complete, NULL);
5996 : 20 : poll_threads();
5997 : 20 : CU_ASSERT(g_bserrno == 0);
5998 : :
5999 : 20 : spdk_blob_close(snapshot2, blob_op_complete, NULL);
6000 : 20 : poll_threads();
6001 : 20 : CU_ASSERT(g_bserrno == 0);
6002 : :
6003 : : /* Try to delete snapshot with more than 1 clone */
6004 : 20 : spdk_bs_delete_blob(bs, snapshotid, blob_op_complete, NULL);
6005 : 20 : poll_threads();
6006 : 20 : CU_ASSERT(g_bserrno != 0);
6007 : :
6008 : 20 : ut_bs_reload(&bs, &bs_opts);
6009 : :
6010 : : /* NULL ids array should return number of clones in count */
6011 : 20 : count = SPDK_COUNTOF(ids);
6012 : 20 : rc = spdk_blob_get_clones(bs, snapshotid, NULL, &count);
6013 : 20 : CU_ASSERT(rc == -ENOMEM);
6014 : 20 : CU_ASSERT(count == 2);
6015 : :
6016 : : /* incorrect array size */
6017 : 20 : count = 1;
6018 : 20 : rc = spdk_blob_get_clones(bs, snapshotid, ids, &count);
6019 : 20 : CU_ASSERT(rc == -ENOMEM);
6020 : 20 : CU_ASSERT(count == 2);
6021 : :
6022 : :
6023 : : /* Verify structure of loaded blob store */
6024 : :
6025 : : /* snapshot */
6026 : 20 : CU_ASSERT(spdk_blob_get_parent_snapshot(bs, snapshotid) == SPDK_BLOBID_INVALID);
6027 : :
6028 : 20 : count = SPDK_COUNTOF(ids);
6029 : 20 : rc = spdk_blob_get_clones(bs, snapshotid, ids, &count);
6030 : 20 : CU_ASSERT(rc == 0);
6031 : 20 : CU_ASSERT(count == 2);
6032 [ + + - - ]: 20 : CU_ASSERT(ids[0] == blobid || ids[1] == blobid);
6033 [ + + + - ]: 20 : CU_ASSERT(ids[0] == snapshotid2 || ids[1] == snapshotid2);
6034 : :
6035 : : /* blob */
6036 : 20 : CU_ASSERT(spdk_blob_get_parent_snapshot(bs, blobid) == snapshotid);
6037 : 20 : count = SPDK_COUNTOF(ids);
6038 : 20 : rc = spdk_blob_get_clones(bs, blobid, ids, &count);
6039 : 20 : CU_ASSERT(rc == 0);
6040 : 20 : CU_ASSERT(count == 1);
6041 : 20 : CU_ASSERT(ids[0] == cloneid2);
6042 : :
6043 : : /* clone */
6044 : 20 : CU_ASSERT(spdk_blob_get_parent_snapshot(bs, cloneid) == snapshotid2);
6045 : 20 : count = SPDK_COUNTOF(ids);
6046 : 20 : rc = spdk_blob_get_clones(bs, cloneid, ids, &count);
6047 : 20 : CU_ASSERT(rc == 0);
6048 : 20 : CU_ASSERT(count == 0);
6049 : :
6050 : : /* snapshot2 */
6051 : 20 : CU_ASSERT(spdk_blob_get_parent_snapshot(bs, snapshotid2) == snapshotid);
6052 : 20 : count = SPDK_COUNTOF(ids);
6053 : 20 : rc = spdk_blob_get_clones(bs, snapshotid2, ids, &count);
6054 : 20 : CU_ASSERT(rc == 0);
6055 : 20 : CU_ASSERT(count == 1);
6056 : 20 : CU_ASSERT(ids[0] == cloneid);
6057 : :
6058 : : /* clone2 */
6059 : 20 : CU_ASSERT(spdk_blob_get_parent_snapshot(bs, cloneid2) == blobid);
6060 : 20 : count = SPDK_COUNTOF(ids);
6061 : 20 : rc = spdk_blob_get_clones(bs, cloneid2, ids, &count);
6062 : 20 : CU_ASSERT(rc == 0);
6063 : 20 : CU_ASSERT(count == 0);
6064 : :
6065 : : /* Try to delete blob that user should not be able to remove */
6066 : :
6067 : 20 : spdk_bs_delete_blob(bs, snapshotid, blob_op_complete, NULL);
6068 : 20 : poll_threads();
6069 : 20 : CU_ASSERT(g_bserrno != 0);
6070 : :
6071 : : /* Remove all blobs */
6072 : :
6073 : 20 : spdk_bs_delete_blob(bs, cloneid, blob_op_complete, NULL);
6074 : 20 : poll_threads();
6075 : 20 : CU_ASSERT(g_bserrno == 0);
6076 : :
6077 : 20 : spdk_bs_delete_blob(bs, snapshotid2, blob_op_complete, NULL);
6078 : 20 : poll_threads();
6079 : 20 : CU_ASSERT(g_bserrno == 0);
6080 : :
6081 : 20 : spdk_bs_delete_blob(bs, cloneid2, blob_op_complete, NULL);
6082 : 20 : poll_threads();
6083 : 20 : CU_ASSERT(g_bserrno == 0);
6084 : :
6085 : 20 : spdk_bs_delete_blob(bs, blobid, blob_op_complete, NULL);
6086 : 20 : poll_threads();
6087 : 20 : CU_ASSERT(g_bserrno == 0);
6088 : :
6089 : 20 : spdk_bs_delete_blob(bs, snapshotid, blob_op_complete, NULL);
6090 : 20 : poll_threads();
6091 : 20 : CU_ASSERT(g_bserrno == 0);
6092 : :
6093 : 20 : spdk_bs_unload(bs, bs_op_complete, NULL);
6094 : 20 : poll_threads();
6095 : 20 : CU_ASSERT(g_bserrno == 0);
6096 : :
6097 : 20 : g_bs = NULL;
6098 : 20 : }
6099 : :
6100 : : /**
6101 : : * Snapshot-clones relation test 2
6102 : : *
6103 : : * snapshot1
6104 : : * |
6105 : : * snapshot2
6106 : : * |
6107 : : * +-----+-----+
6108 : : * | |
6109 : : * blob(ro) snapshot3
6110 : : * | |
6111 : : * | snapshot4
6112 : : * | | |
6113 : : * clone2 clone clone3
6114 : : */
6115 : : static void
6116 : 20 : blob_relations2(void)
6117 : : {
6118 : 15 : struct spdk_blob_store *bs;
6119 : : struct spdk_bs_dev *dev;
6120 : 15 : struct spdk_bs_opts bs_opts;
6121 : 15 : struct spdk_blob_opts opts;
6122 : : struct spdk_blob *blob, *snapshot1, *snapshot2, *snapshot3, *snapshot4, *clone, *clone2;
6123 : : spdk_blob_id blobid, snapshotid1, snapshotid2, snapshotid3, snapshotid4, cloneid, cloneid2,
6124 : : cloneid3;
6125 : : int rc;
6126 : 15 : size_t count;
6127 : 20 : spdk_blob_id ids[10] = {};
6128 : :
6129 : 20 : dev = init_dev();
6130 : 20 : spdk_bs_opts_init(&bs_opts, sizeof(bs_opts));
6131 [ - + ]: 20 : snprintf(bs_opts.bstype.bstype, sizeof(bs_opts.bstype.bstype), "TESTTYPE");
6132 : :
6133 : 20 : spdk_bs_init(dev, &bs_opts, bs_op_with_handle_complete, NULL);
6134 : 20 : poll_threads();
6135 : 20 : CU_ASSERT(g_bserrno == 0);
6136 [ + + ]: 20 : SPDK_CU_ASSERT_FATAL(g_bs != NULL);
6137 : 20 : bs = g_bs;
6138 : :
6139 : : /* 1. Create blob with 10 clusters */
6140 : :
6141 : 20 : ut_spdk_blob_opts_init(&opts);
6142 : 20 : opts.num_clusters = 10;
6143 : :
6144 : 20 : blob = ut_blob_create_and_open(bs, &opts);
6145 : 20 : blobid = spdk_blob_get_id(blob);
6146 : :
6147 : : /* 2. Create snapshot1 */
6148 : :
6149 : 20 : spdk_bs_create_snapshot(bs, blobid, NULL, blob_op_with_id_complete, NULL);
6150 : 20 : poll_threads();
6151 : 20 : CU_ASSERT(g_bserrno == 0);
6152 : 20 : CU_ASSERT(g_blobid != SPDK_BLOBID_INVALID);
6153 : 20 : snapshotid1 = g_blobid;
6154 : :
6155 : 20 : spdk_bs_open_blob(bs, snapshotid1, blob_op_with_handle_complete, NULL);
6156 : 20 : poll_threads();
6157 : 20 : CU_ASSERT(g_bserrno == 0);
6158 [ + + ]: 20 : SPDK_CU_ASSERT_FATAL(g_blob != NULL);
6159 : 20 : snapshot1 = g_blob;
6160 : :
6161 : 20 : CU_ASSERT(snapshot1->parent_id == SPDK_BLOBID_INVALID);
6162 : 20 : CU_ASSERT(spdk_blob_get_parent_snapshot(bs, snapshotid1) == SPDK_BLOBID_INVALID);
6163 : :
6164 : 20 : CU_ASSERT(blob->parent_id == snapshotid1);
6165 : 20 : CU_ASSERT(spdk_blob_get_parent_snapshot(bs, blobid) == snapshotid1);
6166 : :
6167 : : /* Check if blob is the clone of snapshot1 */
6168 : 20 : CU_ASSERT(blob->parent_id == snapshotid1);
6169 : 20 : CU_ASSERT(spdk_blob_get_parent_snapshot(bs, blobid) == snapshotid1);
6170 : :
6171 : 20 : count = SPDK_COUNTOF(ids);
6172 : 20 : rc = spdk_blob_get_clones(bs, snapshotid1, ids, &count);
6173 : 20 : CU_ASSERT(rc == 0);
6174 : 20 : CU_ASSERT(count == 1);
6175 : 20 : CU_ASSERT(ids[0] == blobid);
6176 : :
6177 : : /* 3. Create another snapshot */
6178 : :
6179 : 20 : spdk_bs_create_snapshot(bs, blobid, NULL, blob_op_with_id_complete, NULL);
6180 : 20 : poll_threads();
6181 : 20 : CU_ASSERT(g_bserrno == 0);
6182 : 20 : CU_ASSERT(g_blobid != SPDK_BLOBID_INVALID);
6183 : 20 : snapshotid2 = g_blobid;
6184 : :
6185 : 20 : spdk_bs_open_blob(bs, snapshotid2, blob_op_with_handle_complete, NULL);
6186 : 20 : poll_threads();
6187 : 20 : CU_ASSERT(g_bserrno == 0);
6188 [ + + ]: 20 : SPDK_CU_ASSERT_FATAL(g_blob != NULL);
6189 : 20 : snapshot2 = g_blob;
6190 : :
6191 : 20 : CU_ASSERT(spdk_blob_is_clone(snapshot2));
6192 : 20 : CU_ASSERT(snapshot2->parent_id == snapshotid1);
6193 : 20 : CU_ASSERT(spdk_blob_get_parent_snapshot(bs, snapshotid2) == snapshotid1);
6194 : :
6195 : : /* Check if snapshot2 is the clone of snapshot1 and blob
6196 : : * is a child of snapshot2 */
6197 : 20 : CU_ASSERT(blob->parent_id == snapshotid2);
6198 : 20 : CU_ASSERT(spdk_blob_get_parent_snapshot(bs, blobid) == snapshotid2);
6199 : :
6200 : 20 : count = SPDK_COUNTOF(ids);
6201 : 20 : rc = spdk_blob_get_clones(bs, snapshotid2, ids, &count);
6202 : 20 : CU_ASSERT(rc == 0);
6203 : 20 : CU_ASSERT(count == 1);
6204 : 20 : CU_ASSERT(ids[0] == blobid);
6205 : :
6206 : : /* 4. Create clone from snapshot */
6207 : :
6208 : 20 : spdk_bs_create_clone(bs, snapshotid2, NULL, blob_op_with_id_complete, NULL);
6209 : 20 : poll_threads();
6210 : 20 : CU_ASSERT(g_bserrno == 0);
6211 : 20 : CU_ASSERT(g_blobid != SPDK_BLOBID_INVALID);
6212 : 20 : cloneid = g_blobid;
6213 : :
6214 : 20 : spdk_bs_open_blob(bs, cloneid, blob_op_with_handle_complete, NULL);
6215 : 20 : poll_threads();
6216 : 20 : CU_ASSERT(g_bserrno == 0);
6217 [ + + ]: 20 : SPDK_CU_ASSERT_FATAL(g_blob != NULL);
6218 : 20 : clone = g_blob;
6219 : :
6220 : 20 : CU_ASSERT(clone->parent_id == snapshotid2);
6221 : 20 : CU_ASSERT(spdk_blob_get_parent_snapshot(bs, cloneid) == snapshotid2);
6222 : :
6223 : : /* Check if clone is on the snapshot's list */
6224 : 20 : count = SPDK_COUNTOF(ids);
6225 : 20 : rc = spdk_blob_get_clones(bs, snapshotid2, ids, &count);
6226 : 20 : CU_ASSERT(rc == 0);
6227 : 20 : CU_ASSERT(count == 2);
6228 [ + + - - ]: 20 : CU_ASSERT(ids[0] == blobid || ids[1] == blobid);
6229 [ + + + - ]: 20 : CU_ASSERT(ids[0] == cloneid || ids[1] == cloneid);
6230 : :
6231 : : /* 5. Create snapshot of the clone */
6232 : :
6233 : 20 : spdk_bs_create_snapshot(bs, cloneid, NULL, blob_op_with_id_complete, NULL);
6234 : 20 : poll_threads();
6235 : 20 : CU_ASSERT(g_bserrno == 0);
6236 : 20 : CU_ASSERT(g_blobid != SPDK_BLOBID_INVALID);
6237 : 20 : snapshotid3 = g_blobid;
6238 : :
6239 : 20 : spdk_bs_open_blob(bs, snapshotid3, blob_op_with_handle_complete, NULL);
6240 : 20 : poll_threads();
6241 : 20 : CU_ASSERT(g_bserrno == 0);
6242 [ + + ]: 20 : SPDK_CU_ASSERT_FATAL(g_blob != NULL);
6243 : 20 : snapshot3 = g_blob;
6244 : :
6245 : 20 : CU_ASSERT(snapshot3->parent_id == snapshotid2);
6246 : 20 : CU_ASSERT(spdk_blob_get_parent_snapshot(bs, snapshotid3) == snapshotid2);
6247 : :
6248 : : /* Check if clone is converted to the clone of snapshot3 and snapshot3
6249 : : * is a child of snapshot2 */
6250 : 20 : CU_ASSERT(clone->parent_id == snapshotid3);
6251 : 20 : CU_ASSERT(spdk_blob_get_parent_snapshot(bs, cloneid) == snapshotid3);
6252 : :
6253 : 20 : count = SPDK_COUNTOF(ids);
6254 : 20 : rc = spdk_blob_get_clones(bs, snapshotid3, ids, &count);
6255 : 20 : CU_ASSERT(rc == 0);
6256 : 20 : CU_ASSERT(count == 1);
6257 : 20 : CU_ASSERT(ids[0] == cloneid);
6258 : :
6259 : : /* 6. Create another snapshot of the clone */
6260 : :
6261 : 20 : spdk_bs_create_snapshot(bs, cloneid, NULL, blob_op_with_id_complete, NULL);
6262 : 20 : poll_threads();
6263 : 20 : CU_ASSERT(g_bserrno == 0);
6264 : 20 : CU_ASSERT(g_blobid != SPDK_BLOBID_INVALID);
6265 : 20 : snapshotid4 = g_blobid;
6266 : :
6267 : 20 : spdk_bs_open_blob(bs, snapshotid4, blob_op_with_handle_complete, NULL);
6268 : 20 : poll_threads();
6269 : 20 : CU_ASSERT(g_bserrno == 0);
6270 [ + + ]: 20 : SPDK_CU_ASSERT_FATAL(g_blob != NULL);
6271 : 20 : snapshot4 = g_blob;
6272 : :
6273 : 20 : CU_ASSERT(snapshot4->parent_id == snapshotid3);
6274 : 20 : CU_ASSERT(spdk_blob_get_parent_snapshot(bs, snapshotid4) == snapshotid3);
6275 : :
6276 : : /* Check if clone is converted to the clone of snapshot4 and snapshot4
6277 : : * is a child of snapshot3 */
6278 : 20 : CU_ASSERT(clone->parent_id == snapshotid4);
6279 : 20 : CU_ASSERT(spdk_blob_get_parent_snapshot(bs, cloneid) == snapshotid4);
6280 : :
6281 : 20 : count = SPDK_COUNTOF(ids);
6282 : 20 : rc = spdk_blob_get_clones(bs, snapshotid4, ids, &count);
6283 : 20 : CU_ASSERT(rc == 0);
6284 : 20 : CU_ASSERT(count == 1);
6285 : 20 : CU_ASSERT(ids[0] == cloneid);
6286 : :
6287 : : /* 7. Remove snapshot 4 */
6288 : :
6289 : 20 : ut_blob_close_and_delete(bs, snapshot4);
6290 : :
6291 : : /* Check if relations are back to state from before creating snapshot 4 */
6292 : 20 : CU_ASSERT(clone->parent_id == snapshotid3);
6293 : 20 : CU_ASSERT(spdk_blob_get_parent_snapshot(bs, cloneid) == snapshotid3);
6294 : :
6295 : 20 : count = SPDK_COUNTOF(ids);
6296 : 20 : rc = spdk_blob_get_clones(bs, snapshotid3, ids, &count);
6297 : 20 : CU_ASSERT(rc == 0);
6298 : 20 : CU_ASSERT(count == 1);
6299 : 20 : CU_ASSERT(ids[0] == cloneid);
6300 : :
6301 : : /* 8. Create second clone of snapshot 3 and try to remove snapshot 3 */
6302 : :
6303 : 20 : spdk_bs_create_clone(bs, snapshotid3, NULL, blob_op_with_id_complete, NULL);
6304 : 20 : poll_threads();
6305 : 20 : CU_ASSERT(g_bserrno == 0);
6306 : 20 : CU_ASSERT(g_blobid != SPDK_BLOBID_INVALID);
6307 : 20 : cloneid3 = g_blobid;
6308 : :
6309 : 20 : spdk_bs_delete_blob(bs, snapshotid3, blob_op_complete, NULL);
6310 : 20 : poll_threads();
6311 : 20 : CU_ASSERT(g_bserrno != 0);
6312 : :
6313 : : /* 9. Open snapshot 3 again and try to remove it while clone 3 is closed */
6314 : :
6315 : 20 : spdk_bs_open_blob(bs, snapshotid3, blob_op_with_handle_complete, NULL);
6316 : 20 : poll_threads();
6317 : 20 : CU_ASSERT(g_bserrno == 0);
6318 [ + + ]: 20 : SPDK_CU_ASSERT_FATAL(g_blob != NULL);
6319 : 20 : snapshot3 = g_blob;
6320 : :
6321 : 20 : spdk_bs_delete_blob(bs, snapshotid3, blob_op_complete, NULL);
6322 : 20 : poll_threads();
6323 : 20 : CU_ASSERT(g_bserrno != 0);
6324 : :
6325 : 20 : spdk_blob_close(snapshot3, blob_op_complete, NULL);
6326 : 20 : poll_threads();
6327 : 20 : CU_ASSERT(g_bserrno == 0);
6328 : :
6329 : 20 : spdk_bs_delete_blob(bs, cloneid3, blob_op_complete, NULL);
6330 : 20 : poll_threads();
6331 : 20 : CU_ASSERT(g_bserrno == 0);
6332 : :
6333 : : /* 10. Remove snapshot 1 */
6334 : :
6335 : : /* Check snapshot 1 and snapshot 2 allocated clusters */
6336 : 20 : CU_ASSERT(spdk_blob_get_num_allocated_clusters(snapshot1) == 10);
6337 : 20 : CU_ASSERT(spdk_blob_get_num_allocated_clusters(snapshot2) == 0);
6338 : :
6339 : 20 : ut_blob_close_and_delete(bs, snapshot1);
6340 : :
6341 : : /* Check if relations are back to state from before creating snapshot 4 (before step 6) */
6342 : 20 : CU_ASSERT(snapshot2->parent_id == SPDK_BLOBID_INVALID);
6343 : 20 : CU_ASSERT(spdk_blob_get_parent_snapshot(bs, snapshotid2) == SPDK_BLOBID_INVALID);
6344 : :
6345 : : /* Check that snapshot 2 has the clusters that were allocated to snapshot 1 */
6346 : 20 : CU_ASSERT(spdk_blob_get_num_allocated_clusters(snapshot2) == 10);
6347 : :
6348 : 20 : count = SPDK_COUNTOF(ids);
6349 : 20 : rc = spdk_blob_get_clones(bs, snapshotid2, ids, &count);
6350 : 20 : CU_ASSERT(rc == 0);
6351 : 20 : CU_ASSERT(count == 2);
6352 [ + + - - ]: 20 : CU_ASSERT(ids[0] == blobid || ids[1] == blobid);
6353 [ + + + - ]: 20 : CU_ASSERT(ids[0] == snapshotid3 || ids[1] == snapshotid3);
6354 : :
6355 : : /* 11. Try to create clone from read only blob */
6356 : :
6357 : : /* Mark blob as read only */
6358 : 20 : spdk_blob_set_read_only(blob);
6359 : 20 : spdk_blob_sync_md(blob, blob_op_complete, NULL);
6360 : 20 : poll_threads();
6361 : 20 : CU_ASSERT(g_bserrno == 0);
6362 : :
6363 : : /* Create clone from read only blob */
6364 : 20 : spdk_bs_create_clone(bs, blobid, NULL, blob_op_with_id_complete, NULL);
6365 : 20 : poll_threads();
6366 : 20 : CU_ASSERT(g_bserrno == 0);
6367 : 20 : CU_ASSERT(g_blobid != SPDK_BLOBID_INVALID);
6368 : 20 : cloneid2 = g_blobid;
6369 : :
6370 : 20 : spdk_bs_open_blob(bs, cloneid2, blob_op_with_handle_complete, NULL);
6371 : 20 : poll_threads();
6372 : 20 : CU_ASSERT(g_bserrno == 0);
6373 [ - + ]: 20 : SPDK_CU_ASSERT_FATAL(g_blob != NULL);
6374 : 20 : clone2 = g_blob;
6375 : :
6376 : 20 : CU_ASSERT(spdk_blob_get_parent_snapshot(bs, cloneid2) == blobid);
6377 : :
6378 : 20 : count = SPDK_COUNTOF(ids);
6379 : 20 : rc = spdk_blob_get_clones(bs, blobid, ids, &count);
6380 : 20 : CU_ASSERT(rc == 0);
6381 : 20 : CU_ASSERT(count == 1);
6382 : 20 : CU_ASSERT(ids[0] == cloneid2);
6383 : :
6384 : : /* Close blobs */
6385 : :
6386 : 20 : spdk_blob_close(clone2, blob_op_complete, NULL);
6387 : 20 : poll_threads();
6388 : 20 : CU_ASSERT(g_bserrno == 0);
6389 : :
6390 : 20 : spdk_blob_close(blob, blob_op_complete, NULL);
6391 : 20 : poll_threads();
6392 : 20 : CU_ASSERT(g_bserrno == 0);
6393 : :
6394 : 20 : spdk_blob_close(clone, blob_op_complete, NULL);
6395 : 20 : poll_threads();
6396 : 20 : CU_ASSERT(g_bserrno == 0);
6397 : :
6398 : 20 : spdk_blob_close(snapshot2, blob_op_complete, NULL);
6399 : 20 : poll_threads();
6400 : 20 : CU_ASSERT(g_bserrno == 0);
6401 : :
6402 : 20 : spdk_blob_close(snapshot3, blob_op_complete, NULL);
6403 : 20 : poll_threads();
6404 : 20 : CU_ASSERT(g_bserrno == 0);
6405 : :
6406 : 20 : ut_bs_reload(&bs, &bs_opts);
6407 : :
6408 : : /* Verify structure of loaded blob store */
6409 : :
6410 : : /* snapshot2 */
6411 : 20 : CU_ASSERT(spdk_blob_get_parent_snapshot(bs, snapshotid2) == SPDK_BLOBID_INVALID);
6412 : :
6413 : 20 : count = SPDK_COUNTOF(ids);
6414 : 20 : rc = spdk_blob_get_clones(bs, snapshotid2, ids, &count);
6415 : 20 : CU_ASSERT(rc == 0);
6416 : 20 : CU_ASSERT(count == 2);
6417 [ + + - - ]: 20 : CU_ASSERT(ids[0] == blobid || ids[1] == blobid);
6418 [ + + + - ]: 20 : CU_ASSERT(ids[0] == snapshotid3 || ids[1] == snapshotid3);
6419 : :
6420 : : /* blob */
6421 : 20 : CU_ASSERT(spdk_blob_get_parent_snapshot(bs, blobid) == snapshotid2);
6422 : 20 : count = SPDK_COUNTOF(ids);
6423 : 20 : rc = spdk_blob_get_clones(bs, blobid, ids, &count);
6424 : 20 : CU_ASSERT(rc == 0);
6425 : 20 : CU_ASSERT(count == 1);
6426 : 20 : CU_ASSERT(ids[0] == cloneid2);
6427 : :
6428 : : /* clone */
6429 : 20 : CU_ASSERT(spdk_blob_get_parent_snapshot(bs, cloneid) == snapshotid3);
6430 : 20 : count = SPDK_COUNTOF(ids);
6431 : 20 : rc = spdk_blob_get_clones(bs, cloneid, ids, &count);
6432 : 20 : CU_ASSERT(rc == 0);
6433 : 20 : CU_ASSERT(count == 0);
6434 : :
6435 : : /* snapshot3 */
6436 : 20 : CU_ASSERT(spdk_blob_get_parent_snapshot(bs, snapshotid3) == snapshotid2);
6437 : 20 : count = SPDK_COUNTOF(ids);
6438 : 20 : rc = spdk_blob_get_clones(bs, snapshotid3, ids, &count);
6439 : 20 : CU_ASSERT(rc == 0);
6440 : 20 : CU_ASSERT(count == 1);
6441 : 20 : CU_ASSERT(ids[0] == cloneid);
6442 : :
6443 : : /* clone2 */
6444 : 20 : CU_ASSERT(spdk_blob_get_parent_snapshot(bs, cloneid2) == blobid);
6445 : 20 : count = SPDK_COUNTOF(ids);
6446 : 20 : rc = spdk_blob_get_clones(bs, cloneid2, ids, &count);
6447 : 20 : CU_ASSERT(rc == 0);
6448 : 20 : CU_ASSERT(count == 0);
6449 : :
6450 : : /* Try to delete all blobs in the worse possible order */
6451 : :
6452 : 20 : spdk_bs_delete_blob(bs, snapshotid2, blob_op_complete, NULL);
6453 : 20 : poll_threads();
6454 : 20 : CU_ASSERT(g_bserrno != 0);
6455 : :
6456 : 20 : spdk_bs_delete_blob(bs, snapshotid3, blob_op_complete, NULL);
6457 : 20 : poll_threads();
6458 : 20 : CU_ASSERT(g_bserrno == 0);
6459 : :
6460 : 20 : spdk_bs_delete_blob(bs, snapshotid2, blob_op_complete, NULL);
6461 : 20 : poll_threads();
6462 : 20 : CU_ASSERT(g_bserrno != 0);
6463 : :
6464 : 20 : spdk_bs_delete_blob(bs, cloneid, blob_op_complete, NULL);
6465 : 20 : poll_threads();
6466 : 20 : CU_ASSERT(g_bserrno == 0);
6467 : :
6468 : 20 : spdk_bs_delete_blob(bs, snapshotid2, blob_op_complete, NULL);
6469 : 20 : poll_threads();
6470 : 20 : CU_ASSERT(g_bserrno == 0);
6471 : :
6472 : 20 : spdk_bs_delete_blob(bs, blobid, blob_op_complete, NULL);
6473 : 20 : poll_threads();
6474 : 20 : CU_ASSERT(g_bserrno == 0);
6475 : :
6476 : 20 : spdk_bs_delete_blob(bs, cloneid2, blob_op_complete, NULL);
6477 : 20 : poll_threads();
6478 : 20 : CU_ASSERT(g_bserrno == 0);
6479 : :
6480 : 20 : spdk_bs_unload(bs, bs_op_complete, NULL);
6481 : 20 : poll_threads();
6482 : 20 : CU_ASSERT(g_bserrno == 0);
6483 : :
6484 : 20 : g_bs = NULL;
6485 : 20 : }
6486 : :
6487 : : /**
6488 : : * Snapshot-clones relation test 3
6489 : : *
6490 : : * snapshot0
6491 : : * |
6492 : : * snapshot1
6493 : : * |
6494 : : * snapshot2
6495 : : * |
6496 : : * blob
6497 : : */
6498 : : static void
6499 : 20 : blob_relations3(void)
6500 : : {
6501 : : struct spdk_blob_store *bs;
6502 : : struct spdk_bs_dev *dev;
6503 : : struct spdk_io_channel *channel;
6504 : 15 : struct spdk_bs_opts bs_opts;
6505 : 15 : struct spdk_blob_opts opts;
6506 : : struct spdk_blob *blob;
6507 : : spdk_blob_id blobid, snapshotid0, snapshotid1, snapshotid2;
6508 : :
6509 : 20 : dev = init_dev();
6510 : 20 : spdk_bs_opts_init(&bs_opts, sizeof(bs_opts));
6511 [ - + ]: 20 : snprintf(bs_opts.bstype.bstype, sizeof(bs_opts.bstype.bstype), "TESTTYPE");
6512 : :
6513 : 20 : spdk_bs_init(dev, &bs_opts, bs_op_with_handle_complete, NULL);
6514 : 20 : poll_threads();
6515 : 20 : CU_ASSERT(g_bserrno == 0);
6516 [ + + ]: 20 : SPDK_CU_ASSERT_FATAL(g_bs != NULL);
6517 : 20 : bs = g_bs;
6518 : :
6519 : 20 : channel = spdk_bs_alloc_io_channel(bs);
6520 [ - + ]: 20 : SPDK_CU_ASSERT_FATAL(channel != NULL);
6521 : :
6522 : : /* 1. Create blob with 10 clusters */
6523 : 20 : ut_spdk_blob_opts_init(&opts);
6524 : 20 : opts.num_clusters = 10;
6525 : :
6526 : 20 : blob = ut_blob_create_and_open(bs, &opts);
6527 : 20 : blobid = spdk_blob_get_id(blob);
6528 : :
6529 : : /* 2. Create snapshot0 */
6530 : 20 : spdk_bs_create_snapshot(bs, blobid, NULL, blob_op_with_id_complete, NULL);
6531 : 20 : poll_threads();
6532 : 20 : CU_ASSERT(g_bserrno == 0);
6533 : 20 : CU_ASSERT(g_blobid != SPDK_BLOBID_INVALID);
6534 : 20 : snapshotid0 = g_blobid;
6535 : :
6536 : : /* 3. Create snapshot1 */
6537 : 20 : spdk_bs_create_snapshot(bs, blobid, NULL, blob_op_with_id_complete, NULL);
6538 : 20 : poll_threads();
6539 : 20 : CU_ASSERT(g_bserrno == 0);
6540 : 20 : CU_ASSERT(g_blobid != SPDK_BLOBID_INVALID);
6541 : 20 : snapshotid1 = g_blobid;
6542 : :
6543 : : /* 4. Create snapshot2 */
6544 : 20 : spdk_bs_create_snapshot(bs, blobid, NULL, blob_op_with_id_complete, NULL);
6545 : 20 : poll_threads();
6546 : 20 : CU_ASSERT(g_bserrno == 0);
6547 : 20 : CU_ASSERT(g_blobid != SPDK_BLOBID_INVALID);
6548 : 20 : snapshotid2 = g_blobid;
6549 : :
6550 : : /* 5. Decouple blob */
6551 : 20 : spdk_bs_blob_decouple_parent(bs, channel, blobid, blob_op_complete, NULL);
6552 : 20 : poll_threads();
6553 : 20 : CU_ASSERT(g_bserrno == 0);
6554 : :
6555 : : /* 6. Decouple snapshot2. Make sure updating md of snapshot2 is possible */
6556 : 20 : spdk_bs_blob_decouple_parent(bs, channel, snapshotid2, blob_op_complete, NULL);
6557 : 20 : poll_threads();
6558 : 20 : CU_ASSERT(g_bserrno == 0);
6559 : :
6560 : : /* 7. Delete blob */
6561 : 20 : spdk_blob_close(blob, blob_op_complete, NULL);
6562 : 20 : poll_threads();
6563 : 20 : CU_ASSERT(g_bserrno == 0);
6564 : :
6565 : 20 : spdk_bs_delete_blob(bs, blobid, blob_op_complete, NULL);
6566 : 20 : poll_threads();
6567 : 20 : CU_ASSERT(g_bserrno == 0);
6568 : :
6569 : : /* 8. Delete snapshot2.
6570 : : * If md of snapshot 2 was updated, it should be possible to delete it */
6571 : 20 : spdk_bs_delete_blob(bs, snapshotid2, blob_op_complete, NULL);
6572 : 20 : poll_threads();
6573 : 20 : CU_ASSERT(g_bserrno == 0);
6574 : :
6575 : : /* Remove remaining blobs and unload bs */
6576 : 20 : spdk_bs_delete_blob(bs, snapshotid1, blob_op_complete, NULL);
6577 : 20 : poll_threads();
6578 : 20 : CU_ASSERT(g_bserrno == 0);
6579 : :
6580 : 20 : spdk_bs_delete_blob(bs, snapshotid0, blob_op_complete, NULL);
6581 : 20 : poll_threads();
6582 : 20 : CU_ASSERT(g_bserrno == 0);
6583 : :
6584 : 20 : spdk_bs_free_io_channel(channel);
6585 : 20 : poll_threads();
6586 : :
6587 : 20 : spdk_bs_unload(bs, bs_op_complete, NULL);
6588 : 20 : poll_threads();
6589 : 20 : CU_ASSERT(g_bserrno == 0);
6590 : :
6591 : 20 : g_bs = NULL;
6592 : 20 : }
6593 : :
6594 : : static void
6595 : 20 : blobstore_clean_power_failure(void)
6596 : : {
6597 : : struct spdk_blob_store *bs;
6598 : : struct spdk_blob *blob;
6599 : 20 : struct spdk_power_failure_thresholds thresholds = {};
6600 : 20 : bool clean = false;
6601 : 20 : struct spdk_bs_super_block *super = (struct spdk_bs_super_block *)&g_dev_buffer[0];
6602 : 20 : struct spdk_bs_super_block super_copy = {};
6603 : :
6604 : 20 : thresholds.general_threshold = 1;
6605 [ + + ]: 100 : while (!clean) {
6606 : : /* Create bs and blob */
6607 : 80 : suite_blob_setup();
6608 [ + + ]: 80 : SPDK_CU_ASSERT_FATAL(g_bs != NULL);
6609 [ + + ]: 80 : SPDK_CU_ASSERT_FATAL(g_blob != NULL);
6610 : 80 : bs = g_bs;
6611 : 80 : blob = g_blob;
6612 : :
6613 : : /* Super block should not change for rest of the UT,
6614 : : * save it and compare later. */
6615 : 80 : memcpy(&super_copy, super, sizeof(struct spdk_bs_super_block));
6616 [ + + ]: 80 : SPDK_CU_ASSERT_FATAL(super->clean == 0);
6617 [ + + - + ]: 80 : SPDK_CU_ASSERT_FATAL(bs->clean == 0);
6618 : :
6619 : : /* Force bs/super block in a clean state.
6620 : : * Along with marking blob dirty, to cause blob persist. */
6621 : 80 : blob->state = SPDK_BLOB_STATE_DIRTY;
6622 : 80 : bs->clean = 1;
6623 : 80 : super->clean = 1;
6624 : 80 : super->crc = blob_md_page_calc_crc(super);
6625 : :
6626 : 80 : g_bserrno = -1;
6627 : 80 : dev_set_power_failure_thresholds(thresholds);
6628 : 80 : spdk_blob_sync_md(blob, blob_op_complete, NULL);
6629 : 80 : poll_threads();
6630 : 80 : dev_reset_power_failure_event();
6631 : :
6632 [ + + ]: 80 : if (g_bserrno == 0) {
6633 : : /* After successful md sync, both bs and super block
6634 : : * should be marked as not clean. */
6635 [ + + - + ]: 20 : SPDK_CU_ASSERT_FATAL(bs->clean == 0);
6636 [ - + ]: 20 : SPDK_CU_ASSERT_FATAL(super->clean == 0);
6637 : 20 : clean = true;
6638 : 5 : }
6639 : :
6640 : : /* Depending on the point of failure, super block was either updated or not. */
6641 : 80 : super_copy.clean = super->clean;
6642 : 80 : super_copy.crc = blob_md_page_calc_crc(&super_copy);
6643 : : /* Compare that the values in super block remained unchanged. */
6644 [ + + - + ]: 80 : SPDK_CU_ASSERT_FATAL(!memcmp(&super_copy, super, sizeof(struct spdk_bs_super_block)));
6645 : :
6646 : : /* Delete blob and unload bs */
6647 : 80 : suite_blob_cleanup();
6648 : :
6649 : 80 : thresholds.general_threshold++;
6650 : : }
6651 : 20 : }
6652 : :
6653 : : static void
6654 : 20 : blob_delete_snapshot_power_failure(void)
6655 : : {
6656 : : struct spdk_bs_dev *dev;
6657 : 15 : struct spdk_blob_store *bs;
6658 : 15 : struct spdk_blob_opts opts;
6659 : : struct spdk_blob *blob, *snapshot;
6660 : 20 : struct spdk_power_failure_thresholds thresholds = {};
6661 : : spdk_blob_id blobid, snapshotid;
6662 : 15 : const void *value;
6663 : 15 : size_t value_len;
6664 : 15 : size_t count;
6665 : 20 : spdk_blob_id ids[3] = {};
6666 : : int rc;
6667 : 20 : bool deleted = false;
6668 : 20 : int delete_snapshot_bserrno = -1;
6669 : : uint32_t first_data_cluster;
6670 : :
6671 : 20 : thresholds.general_threshold = 1;
6672 [ + + ]: 204 : while (!deleted) {
6673 : 184 : dev = init_dev();
6674 : :
6675 : 184 : spdk_bs_init(dev, NULL, bs_op_with_handle_complete, NULL);
6676 : 184 : poll_threads();
6677 : 184 : CU_ASSERT(g_bserrno == 0);
6678 [ + + ]: 184 : SPDK_CU_ASSERT_FATAL(g_bs != NULL);
6679 : 184 : bs = g_bs;
6680 : :
6681 [ - + ]: 184 : first_data_cluster = FIRST_DATA_CLUSTER(bs);
6682 : :
6683 : : /* Create blob */
6684 : 184 : ut_spdk_blob_opts_init(&opts);
6685 : 184 : opts.num_clusters = 10;
6686 : :
6687 : 184 : spdk_bs_create_blob_ext(bs, &opts, blob_op_with_id_complete, NULL);
6688 : 184 : poll_threads();
6689 : 184 : CU_ASSERT(g_bserrno == 0);
6690 : 184 : CU_ASSERT(g_blobid != SPDK_BLOBID_INVALID);
6691 : 184 : blobid = g_blobid;
6692 : :
6693 : : /* Create snapshot */
6694 : 184 : spdk_bs_create_snapshot(bs, blobid, NULL, blob_op_with_id_complete, NULL);
6695 : 184 : poll_threads();
6696 : 184 : CU_ASSERT(g_bserrno == 0);
6697 : 184 : CU_ASSERT(g_blobid != SPDK_BLOBID_INVALID);
6698 : 184 : snapshotid = g_blobid;
6699 [ + + ]: 184 : SPDK_CU_ASSERT_FATAL(spdk_bit_pool_is_allocated(bs->used_clusters, first_data_cluster));
6700 [ + + ]: 184 : SPDK_CU_ASSERT_FATAL(!spdk_bit_pool_is_allocated(bs->used_clusters, first_data_cluster + 10));
6701 : :
6702 : 184 : dev_set_power_failure_thresholds(thresholds);
6703 : :
6704 : 184 : spdk_bs_delete_blob(bs, snapshotid, blob_op_complete, NULL);
6705 : 184 : poll_threads();
6706 : 184 : delete_snapshot_bserrno = g_bserrno;
6707 : :
6708 : : /* Do not shut down cleanly. Assumption is that after snapshot deletion
6709 : : * reports success, changes to both blobs should already persisted. */
6710 : 184 : dev_reset_power_failure_event();
6711 : 184 : ut_bs_dirty_load(&bs, NULL);
6712 : :
6713 [ + + ]: 184 : SPDK_CU_ASSERT_FATAL(spdk_bit_pool_is_allocated(bs->used_clusters, first_data_cluster));
6714 [ + + ]: 184 : SPDK_CU_ASSERT_FATAL(!spdk_bit_pool_is_allocated(bs->used_clusters, first_data_cluster + 10));
6715 : :
6716 : 184 : spdk_bs_open_blob(bs, blobid, blob_op_with_handle_complete, NULL);
6717 : 184 : poll_threads();
6718 : 184 : CU_ASSERT(g_bserrno == 0);
6719 [ + + ]: 184 : SPDK_CU_ASSERT_FATAL(g_blob != NULL);
6720 : 184 : blob = g_blob;
6721 [ + + ]: 184 : SPDK_CU_ASSERT_FATAL(spdk_blob_is_thin_provisioned(blob) == true);
6722 : :
6723 : 184 : spdk_bs_open_blob(bs, snapshotid, blob_op_with_handle_complete, NULL);
6724 : 184 : poll_threads();
6725 : :
6726 [ + + ]: 184 : if (g_bserrno == 0) {
6727 [ - + ]: 124 : SPDK_CU_ASSERT_FATAL(g_blob != NULL);
6728 : 124 : snapshot = g_blob;
6729 : 124 : CU_ASSERT(spdk_blob_get_parent_snapshot(bs, blobid) == snapshotid);
6730 : 124 : count = SPDK_COUNTOF(ids);
6731 : 124 : rc = spdk_blob_get_clones(bs, snapshotid, ids, &count);
6732 : 124 : CU_ASSERT(rc == 0);
6733 : 124 : CU_ASSERT(count == 1);
6734 : 124 : CU_ASSERT(ids[0] == blobid);
6735 : 124 : rc = spdk_blob_get_xattr_value(snapshot, SNAPSHOT_PENDING_REMOVAL, &value, &value_len);
6736 : 124 : CU_ASSERT(rc != 0);
6737 [ - + ]: 124 : SPDK_CU_ASSERT_FATAL(spdk_blob_is_thin_provisioned(snapshot) == false);
6738 : 124 : CU_ASSERT(spdk_blob_get_num_allocated_clusters(blob) == 0);
6739 : 124 : CU_ASSERT(spdk_blob_get_num_allocated_clusters(snapshot) == 10);
6740 : :
6741 : 124 : spdk_blob_close(snapshot, blob_op_complete, NULL);
6742 : 124 : poll_threads();
6743 : 124 : CU_ASSERT(g_bserrno == 0);
6744 : 31 : } else {
6745 : 60 : CU_ASSERT(spdk_blob_get_parent_snapshot(bs, blobid) == SPDK_BLOBID_INVALID);
6746 : 60 : CU_ASSERT(spdk_blob_get_num_allocated_clusters(blob) == 10);
6747 : : /* Snapshot might have been left in unrecoverable state, so it does not open.
6748 : : * Yet delete might perform further changes to the clone after that.
6749 : : * This UT should test until snapshot is deleted and delete call succeeds. */
6750 [ + + ]: 60 : if (delete_snapshot_bserrno == 0) {
6751 : 20 : deleted = true;
6752 : 5 : }
6753 : : }
6754 : :
6755 : 184 : spdk_blob_close(blob, blob_op_complete, NULL);
6756 : 184 : poll_threads();
6757 : 184 : CU_ASSERT(g_bserrno == 0);
6758 : :
6759 : 184 : spdk_bs_unload(bs, bs_op_complete, NULL);
6760 : 184 : poll_threads();
6761 : 184 : CU_ASSERT(g_bserrno == 0);
6762 : :
6763 : 184 : thresholds.general_threshold++;
6764 : : }
6765 : 20 : }
6766 : :
6767 : : static void
6768 : 20 : blob_create_snapshot_power_failure(void)
6769 : : {
6770 : 20 : struct spdk_blob_store *bs = g_bs;
6771 : : struct spdk_bs_dev *dev;
6772 : 15 : struct spdk_blob_opts opts;
6773 : : struct spdk_blob *blob, *snapshot;
6774 : 20 : struct spdk_power_failure_thresholds thresholds = {};
6775 : : spdk_blob_id blobid, snapshotid;
6776 : 15 : const void *value;
6777 : 15 : size_t value_len;
6778 : 15 : size_t count;
6779 : 20 : spdk_blob_id ids[3] = {};
6780 : : int rc;
6781 : 20 : bool created = false;
6782 : 20 : int create_snapshot_bserrno = -1;
6783 : : uint32_t first_data_cluster;
6784 : :
6785 : 20 : thresholds.general_threshold = 1;
6786 [ + + ]: 172 : while (!created) {
6787 : 152 : dev = init_dev();
6788 : :
6789 : 152 : spdk_bs_init(dev, NULL, bs_op_with_handle_complete, NULL);
6790 : 152 : poll_threads();
6791 : 152 : CU_ASSERT(g_bserrno == 0);
6792 [ + + ]: 152 : SPDK_CU_ASSERT_FATAL(g_bs != NULL);
6793 : 152 : bs = g_bs;
6794 : :
6795 [ - + ]: 152 : first_data_cluster = FIRST_DATA_CLUSTER(bs);
6796 : :
6797 : : /* Create blob */
6798 : 152 : ut_spdk_blob_opts_init(&opts);
6799 : 152 : opts.num_clusters = 10;
6800 : :
6801 : 152 : spdk_bs_create_blob_ext(bs, &opts, blob_op_with_id_complete, NULL);
6802 : 152 : poll_threads();
6803 : 152 : CU_ASSERT(g_bserrno == 0);
6804 : 152 : CU_ASSERT(g_blobid != SPDK_BLOBID_INVALID);
6805 : 152 : blobid = g_blobid;
6806 [ + + ]: 152 : SPDK_CU_ASSERT_FATAL(spdk_bit_pool_is_allocated(bs->used_clusters, first_data_cluster));
6807 [ + + ]: 152 : SPDK_CU_ASSERT_FATAL(!spdk_bit_pool_is_allocated(bs->used_clusters, first_data_cluster + 10));
6808 : :
6809 : 152 : dev_set_power_failure_thresholds(thresholds);
6810 : :
6811 : : /* Create snapshot */
6812 : 152 : spdk_bs_create_snapshot(bs, blobid, NULL, blob_op_with_id_complete, NULL);
6813 : 152 : poll_threads();
6814 : 152 : create_snapshot_bserrno = g_bserrno;
6815 : 152 : snapshotid = g_blobid;
6816 [ + + ]: 152 : SPDK_CU_ASSERT_FATAL(spdk_bit_pool_is_allocated(bs->used_clusters, first_data_cluster));
6817 [ + + ]: 152 : SPDK_CU_ASSERT_FATAL(!spdk_bit_pool_is_allocated(bs->used_clusters, first_data_cluster + 10));
6818 : :
6819 : : /* Do not shut down cleanly. Assumption is that after create snapshot
6820 : : * reports success, both blobs should be power-fail safe. */
6821 : 152 : dev_reset_power_failure_event();
6822 : 152 : ut_bs_dirty_load(&bs, NULL);
6823 : :
6824 [ + + ]: 152 : SPDK_CU_ASSERT_FATAL(spdk_bit_pool_is_allocated(bs->used_clusters, first_data_cluster));
6825 [ + + ]: 152 : SPDK_CU_ASSERT_FATAL(!spdk_bit_pool_is_allocated(bs->used_clusters, first_data_cluster + 10));
6826 : :
6827 : 152 : spdk_bs_open_blob(bs, blobid, blob_op_with_handle_complete, NULL);
6828 : 152 : poll_threads();
6829 : 152 : CU_ASSERT(g_bserrno == 0);
6830 [ + + ]: 152 : SPDK_CU_ASSERT_FATAL(g_blob != NULL);
6831 : 152 : blob = g_blob;
6832 : :
6833 [ + + ]: 152 : if (snapshotid != SPDK_BLOBID_INVALID) {
6834 : 100 : spdk_bs_open_blob(bs, snapshotid, blob_op_with_handle_complete, NULL);
6835 : 100 : poll_threads();
6836 : 25 : }
6837 : :
6838 [ + + + + ]: 152 : if ((snapshotid != SPDK_BLOBID_INVALID) && (g_bserrno == 0)) {
6839 [ - + ]: 40 : SPDK_CU_ASSERT_FATAL(g_blob != NULL);
6840 : 40 : snapshot = g_blob;
6841 [ - + ]: 40 : SPDK_CU_ASSERT_FATAL(spdk_blob_is_thin_provisioned(blob) == true);
6842 [ - + ]: 40 : SPDK_CU_ASSERT_FATAL(spdk_blob_is_thin_provisioned(snapshot) == false);
6843 : 40 : CU_ASSERT(spdk_blob_get_num_allocated_clusters(blob) == 0);
6844 : 40 : CU_ASSERT(spdk_blob_get_num_allocated_clusters(snapshot) == 10);
6845 : 40 : CU_ASSERT(spdk_blob_get_parent_snapshot(bs, blobid) == snapshotid);
6846 : 40 : count = SPDK_COUNTOF(ids);
6847 : 40 : rc = spdk_blob_get_clones(bs, snapshotid, ids, &count);
6848 : 40 : CU_ASSERT(rc == 0);
6849 : 40 : CU_ASSERT(count == 1);
6850 : 40 : CU_ASSERT(ids[0] == blobid);
6851 : 40 : rc = spdk_blob_get_xattr_value(snapshot, SNAPSHOT_IN_PROGRESS, &value, &value_len);
6852 : 40 : CU_ASSERT(rc != 0);
6853 : :
6854 : 40 : spdk_blob_close(snapshot, blob_op_complete, NULL);
6855 : 40 : poll_threads();
6856 : 40 : CU_ASSERT(g_bserrno == 0);
6857 [ + + ]: 40 : if (create_snapshot_bserrno == 0) {
6858 : 20 : created = true;
6859 : 5 : }
6860 : 10 : } else {
6861 : 112 : CU_ASSERT(spdk_blob_get_parent_snapshot(bs, blobid) == SPDK_BLOBID_INVALID);
6862 [ + + ]: 112 : SPDK_CU_ASSERT_FATAL(spdk_blob_is_thin_provisioned(blob) == false);
6863 : 112 : CU_ASSERT(spdk_blob_get_num_allocated_clusters(blob) == 10);
6864 : : }
6865 : :
6866 : 152 : spdk_blob_close(blob, blob_op_complete, NULL);
6867 : 152 : poll_threads();
6868 : 152 : CU_ASSERT(g_bserrno == 0);
6869 : :
6870 : 152 : spdk_bs_unload(bs, bs_op_complete, NULL);
6871 : 152 : poll_threads();
6872 : 152 : CU_ASSERT(g_bserrno == 0);
6873 : :
6874 : 152 : thresholds.general_threshold++;
6875 : : }
6876 : 20 : }
6877 : :
6878 : : #define IO_UT_BLOCKS_PER_CLUSTER 64
6879 : :
6880 : : static void
6881 : 40 : test_io_write(struct spdk_bs_dev *dev, struct spdk_blob *blob, struct spdk_io_channel *channel)
6882 : 30 : {
6883 : 40 : const uint32_t SZ = IO_UT_BLOCKS_PER_CLUSTER;
6884 [ - + ]: 40 : uint8_t payload_ff[SZ * 512];
6885 [ - + ]: 40 : uint8_t payload_aa[SZ * 512];
6886 [ - + ]: 40 : uint8_t payload_00[SZ * 512];
6887 : : uint8_t *cluster0, *cluster1;
6888 : :
6889 [ - + ]: 40 : memset(payload_ff, 0xFF, sizeof(payload_ff));
6890 [ - + ]: 40 : memset(payload_aa, 0xAA, sizeof(payload_aa));
6891 [ - + ]: 40 : memset(payload_00, 0x00, sizeof(payload_00));
6892 : :
6893 : : /* Try to perform I/O with io unit = 512 */
6894 : 40 : spdk_blob_io_write(blob, channel, payload_ff, 0, 1, blob_op_complete, NULL);
6895 : 40 : poll_threads();
6896 : 40 : CU_ASSERT(g_bserrno == 0);
6897 : :
6898 : : /* If thin provisioned is set cluster should be allocated now */
6899 [ + + ]: 40 : SPDK_CU_ASSERT_FATAL(blob->active.clusters[0] != 0);
6900 : 40 : cluster0 = &g_dev_buffer[blob->active.clusters[0] * dev->blocklen];
6901 : :
6902 : : /* Each character 0-F symbolizes single io_unit containing 512 bytes block filled with that character.
6903 : : * Each page is separated by |. Whole block [...] symbolizes one cluster (containing 4 pages). */
6904 : : /* cluster0: [ F000 0000 | 0000 0000 | 0000 0000 | 0000 0000 ] */
6905 [ - + - + ]: 40 : CU_ASSERT(memcmp(cluster0 + 0 * 512, payload_ff, 512) == 0);
6906 [ - + - + ]: 40 : CU_ASSERT(memcmp(cluster0 + 1 * 512, payload_00, (SZ - 1) * 512) == 0);
6907 : :
6908 : : /* Verify write with offset on first page */
6909 : 40 : spdk_blob_io_write(blob, channel, payload_ff, 2, 1, blob_op_complete, NULL);
6910 : 40 : poll_threads();
6911 : 40 : CU_ASSERT(g_bserrno == 0);
6912 : :
6913 : : /* cluster0: [ F0F0 0000 | 0000 0000 | 0000 0000 | 0000 0000 ] */
6914 [ - + - + ]: 40 : CU_ASSERT(memcmp(cluster0 + 0 * 512, payload_ff, 512) == 0);
6915 [ - + - + ]: 40 : CU_ASSERT(memcmp(cluster0 + 1 * 512, payload_00, 512) == 0);
6916 [ - + - + ]: 40 : CU_ASSERT(memcmp(cluster0 + 2 * 512, payload_ff, 512) == 0);
6917 [ - + - + ]: 40 : CU_ASSERT(memcmp(cluster0 + 3 * 512, payload_00, 512) == 0);
6918 [ - + - + ]: 40 : CU_ASSERT(memcmp(cluster0 + 4 * 512, payload_00, (SZ - 4) * 512) == 0);
6919 : :
6920 : : /* Verify write with offset on first page */
6921 : 40 : spdk_blob_io_write(blob, channel, payload_ff, 4, 4, blob_op_complete, NULL);
6922 : 40 : poll_threads();
6923 : :
6924 : : /* cluster0: [ F0F0 FFFF | 0000 0000 | 0000 0000 | 0000 0000 ] */
6925 [ - + - + ]: 40 : CU_ASSERT(memcmp(cluster0 + 0 * 512, payload_ff, 512) == 0);
6926 [ - + - + ]: 40 : CU_ASSERT(memcmp(cluster0 + 1 * 512, payload_00, 512) == 0);
6927 [ - + - + ]: 40 : CU_ASSERT(memcmp(cluster0 + 2 * 512, payload_ff, 512) == 0);
6928 [ - + - + ]: 40 : CU_ASSERT(memcmp(cluster0 + 3 * 512, payload_00, 512) == 0);
6929 [ - + - + ]: 40 : CU_ASSERT(memcmp(cluster0 + 4 * 512, payload_ff, 4 * 512) == 0);
6930 [ - + - + ]: 40 : CU_ASSERT(memcmp(cluster0 + 8 * 512, payload_00, (SZ - 8) * 512) == 0);
6931 : :
6932 : : /* Verify write with offset on second page */
6933 : 40 : spdk_blob_io_write(blob, channel, payload_ff, 8, 4, blob_op_complete, NULL);
6934 : 40 : poll_threads();
6935 : :
6936 : : /* cluster0: [ F0F0 FFFF | FFFF 0000 | 0000 0000 | 0000 0000 ] */
6937 [ - + - + ]: 40 : CU_ASSERT(memcmp(cluster0 + 0 * 512, payload_ff, 512) == 0);
6938 [ - + - + ]: 40 : CU_ASSERT(memcmp(cluster0 + 1 * 512, payload_00, 512) == 0);
6939 [ - + - + ]: 40 : CU_ASSERT(memcmp(cluster0 + 2 * 512, payload_ff, 512) == 0);
6940 [ - + - + ]: 40 : CU_ASSERT(memcmp(cluster0 + 3 * 512, payload_00, 512) == 0);
6941 [ - + - + ]: 40 : CU_ASSERT(memcmp(cluster0 + 4 * 512, payload_ff, 8 * 512) == 0);
6942 [ - + - + ]: 40 : CU_ASSERT(memcmp(cluster0 + 12 * 512, payload_00, (SZ - 12) * 512) == 0);
6943 : :
6944 : : /* Verify write across multiple pages */
6945 : 40 : spdk_blob_io_write(blob, channel, payload_aa, 4, 8, blob_op_complete, NULL);
6946 : 40 : poll_threads();
6947 : :
6948 : : /* cluster0: [ F0F0 AAAA | AAAA 0000 | 0000 0000 | 0000 0000 ] */
6949 [ - + - + ]: 40 : CU_ASSERT(memcmp(cluster0 + 0 * 512, payload_ff, 512) == 0);
6950 [ - + - + ]: 40 : CU_ASSERT(memcmp(cluster0 + 1 * 512, payload_00, 512) == 0);
6951 [ - + - + ]: 40 : CU_ASSERT(memcmp(cluster0 + 2 * 512, payload_ff, 512) == 0);
6952 [ - + - + ]: 40 : CU_ASSERT(memcmp(cluster0 + 3 * 512, payload_00, 512) == 0);
6953 [ - + - + ]: 40 : CU_ASSERT(memcmp(cluster0 + 4 * 512, payload_aa, 8 * 512) == 0);
6954 [ - + - + ]: 40 : CU_ASSERT(memcmp(cluster0 + 12 * 512, payload_00, (SZ - 12) * 512) == 0);
6955 : :
6956 : : /* Verify write across multiple clusters */
6957 : 40 : spdk_blob_io_write(blob, channel, payload_ff, SZ - 4, 8, blob_op_complete, NULL);
6958 : 40 : poll_threads();
6959 : :
6960 [ + + ]: 40 : SPDK_CU_ASSERT_FATAL(blob->active.clusters[1] != 0);
6961 : 40 : cluster1 = &g_dev_buffer[blob->active.clusters[1] * dev->blocklen];
6962 : :
6963 : : /* cluster0: [ F0F0 AAAA | AAAA 0000 | 0000 0000 | 0000 FFFF ]
6964 : : * cluster1: [ FFFF 0000 | 0000 0000 | 0000 0000 | 0000 0000 ] */
6965 [ - + - + ]: 40 : CU_ASSERT(memcmp(cluster0 + 0 * 512, payload_ff, 512) == 0);
6966 [ - + - + ]: 40 : CU_ASSERT(memcmp(cluster0 + 1 * 512, payload_00, 512) == 0);
6967 [ - + - + ]: 40 : CU_ASSERT(memcmp(cluster0 + 2 * 512, payload_ff, 512) == 0);
6968 [ - + - + ]: 40 : CU_ASSERT(memcmp(cluster0 + 3 * 512, payload_00, 512) == 0);
6969 [ - + - + ]: 40 : CU_ASSERT(memcmp(cluster0 + 4 * 512, payload_aa, 8 * 512) == 0);
6970 [ - + - + ]: 40 : CU_ASSERT(memcmp(cluster0 + (SZ - 4) * 512, payload_ff, 4 * 512) == 0);
6971 : :
6972 [ - + - + ]: 40 : CU_ASSERT(memcmp(cluster1 + 0 * 512, payload_ff, 4 * 512) == 0);
6973 [ - + - + ]: 40 : CU_ASSERT(memcmp(cluster1 + 4 * 512, payload_00, (SZ - 4) * 512) == 0);
6974 : :
6975 : : /* Verify write to second cluster */
6976 : 40 : spdk_blob_io_write(blob, channel, payload_ff, SZ + 12, 2, blob_op_complete, NULL);
6977 : 40 : poll_threads();
6978 : :
6979 [ - + ]: 40 : SPDK_CU_ASSERT_FATAL(blob->active.clusters[1] != 0);
6980 : 40 : cluster1 = &g_dev_buffer[blob->active.clusters[1] * dev->blocklen];
6981 : :
6982 : : /* cluster0: [ F0F0 AAAA | AAAA 0000 | 0000 0000 | 0000 FFFF ]
6983 : : * cluster1: [ FFFF 0000 | 0000 FF00 | 0000 0000 | 0000 0000 ] */
6984 [ - + - + ]: 40 : CU_ASSERT(memcmp(cluster0 + 0 * 512, payload_ff, 512) == 0);
6985 [ - + - + ]: 40 : CU_ASSERT(memcmp(cluster0 + 1 * 512, payload_00, 512) == 0);
6986 [ - + - + ]: 40 : CU_ASSERT(memcmp(cluster0 + 2 * 512, payload_ff, 512) == 0);
6987 [ - + - + ]: 40 : CU_ASSERT(memcmp(cluster0 + 3 * 512, payload_00, 512) == 0);
6988 [ - + - + ]: 40 : CU_ASSERT(memcmp(cluster0 + 4 * 512, payload_aa, 8 * 512) == 0);
6989 [ - + - + ]: 40 : CU_ASSERT(memcmp(cluster0 + (SZ - 4) * 512, payload_ff, 4 * 512) == 0);
6990 : :
6991 [ - + - + ]: 40 : CU_ASSERT(memcmp(cluster1 + 0 * 512, payload_ff, 4 * 512) == 0);
6992 [ - + - + ]: 40 : CU_ASSERT(memcmp(cluster1 + 4 * 512, payload_00, 8 * 512) == 0);
6993 [ - + - + ]: 40 : CU_ASSERT(memcmp(cluster1 + 12 * 512, payload_ff, 2 * 512) == 0);
6994 [ - + - + ]: 40 : CU_ASSERT(memcmp(cluster1 + 14 * 512, payload_00, (SZ - 14) * 512) == 0);
6995 : 40 : }
6996 : :
6997 : : static void
6998 : 120 : test_io_read(struct spdk_bs_dev *dev, struct spdk_blob *blob, struct spdk_io_channel *channel)
6999 : 90 : {
7000 : 120 : const uint32_t SZ = IO_UT_BLOCKS_PER_CLUSTER;
7001 [ - + ]: 300 : uint8_t payload_read[2 * SZ * 512];
7002 [ - + ]: 120 : uint8_t payload_ff[SZ * 512];
7003 [ - + ]: 120 : uint8_t payload_aa[SZ * 512];
7004 [ - + ]: 120 : uint8_t payload_00[SZ * 512];
7005 : :
7006 [ - + ]: 120 : memset(payload_ff, 0xFF, sizeof(payload_ff));
7007 [ - + ]: 120 : memset(payload_aa, 0xAA, sizeof(payload_aa));
7008 [ - + ]: 120 : memset(payload_00, 0x00, sizeof(payload_00));
7009 : :
7010 : : /* Read only first io unit */
7011 : : /* cluster0: [ (F)0F0 AAAA | AAAA 0000 | 0000 0000 | 0000 FFFF ]
7012 : : * cluster1: [ FFFF 0000 | 0000 FF00 | 0000 0000 | 0000 0000 ]
7013 : : * payload_read: F000 0000 | 0000 0000 ... */
7014 [ - + ]: 120 : memset(payload_read, 0x00, sizeof(payload_read));
7015 : 120 : spdk_blob_io_read(blob, channel, payload_read, 0, 1, blob_op_complete, NULL);
7016 : 120 : poll_threads();
7017 : 120 : CU_ASSERT(g_bserrno == 0);
7018 [ - + - + ]: 120 : CU_ASSERT(memcmp(payload_read + 0 * 512, payload_ff, 512) == 0);
7019 [ - + - + ]: 120 : CU_ASSERT(memcmp(payload_read + 1 * 512, payload_00, (SZ - 1) * 512) == 0);
7020 : :
7021 : : /* Read four io_units starting from offset = 2
7022 : : * cluster0: [ F0(F0 AA)AA | AAAA 0000 | 0000 0000 | 0000 FFFF ]
7023 : : * cluster1: [ FFFF 0000 | 0000 FF00 | 0000 0000 | 0000 0000 ]
7024 : : * payload_read: F0AA 0000 | 0000 0000 ... */
7025 : :
7026 [ - + ]: 120 : memset(payload_read, 0x00, sizeof(payload_read));
7027 : 120 : spdk_blob_io_read(blob, channel, payload_read, 2, 4, blob_op_complete, NULL);
7028 : 120 : poll_threads();
7029 : 120 : CU_ASSERT(g_bserrno == 0);
7030 : :
7031 [ - + - + ]: 120 : CU_ASSERT(memcmp(payload_read + 0 * 512, payload_ff, 512) == 0);
7032 [ - + - + ]: 120 : CU_ASSERT(memcmp(payload_read + 1 * 512, payload_00, 512) == 0);
7033 [ - + - + ]: 120 : CU_ASSERT(memcmp(payload_read + 2 * 512, payload_aa, 512) == 0);
7034 [ - + - + ]: 120 : CU_ASSERT(memcmp(payload_read + 3 * 512, payload_aa, 512) == 0);
7035 [ - + - + ]: 120 : CU_ASSERT(memcmp(payload_read + 4 * 512, payload_00, (SZ - 4) * 512) == 0);
7036 : :
7037 : : /* Read eight io_units across multiple pages
7038 : : * cluster0: [ F0F0 (AAAA | AAAA) 0000 | 0000 0000 | 0000 FFFF ]
7039 : : * cluster1: [ FFFF 0000 | 0000 FF00 | 0000 0000 | 0000 0000 ]
7040 : : * payload_read: AAAA AAAA | 0000 0000 ... */
7041 [ - + ]: 120 : memset(payload_read, 0x00, sizeof(payload_read));
7042 : 120 : spdk_blob_io_read(blob, channel, payload_read, 4, 8, blob_op_complete, NULL);
7043 : 120 : poll_threads();
7044 : 120 : CU_ASSERT(g_bserrno == 0);
7045 : :
7046 [ - + - + ]: 120 : CU_ASSERT(memcmp(payload_read + 0 * 512, payload_aa, 8 * 512) == 0);
7047 [ - + - + ]: 120 : CU_ASSERT(memcmp(payload_read + 8 * 512, payload_00, (SZ - 8) * 512) == 0);
7048 : :
7049 : : /* Read eight io_units across multiple clusters
7050 : : * cluster0: [ F0F0 AAAA | AAAA 0000 | 0000 0000 | 0000 (FFFF ]
7051 : : * cluster1: [ FFFF) 0000 | 0000 FF00 | 0000 0000 | 0000 0000 ]
7052 : : * payload_read: FFFF FFFF | 0000 0000 ... */
7053 [ - + ]: 120 : memset(payload_read, 0x00, sizeof(payload_read));
7054 : 120 : spdk_blob_io_read(blob, channel, payload_read, SZ - 4, 8, blob_op_complete, NULL);
7055 : 120 : poll_threads();
7056 : 120 : CU_ASSERT(g_bserrno == 0);
7057 : :
7058 [ - + - + ]: 120 : CU_ASSERT(memcmp(payload_read + 0 * 512, payload_ff, 8 * 512) == 0);
7059 [ - + - + ]: 120 : CU_ASSERT(memcmp(payload_read + 8 * 512, payload_00, (SZ - 8) * 512) == 0);
7060 : :
7061 : : /* Read four io_units from second cluster
7062 : : * cluster0: [ F0F0 AAAA | AAAA 0000 | 0000 0000 | 0000 FFFF ]
7063 : : * cluster1: [ FFFF 0000 | 00(00 FF)00 | 0000 0000 | 0000 0000 ]
7064 : : * payload_read: 00FF 0000 | 0000 0000 ... */
7065 [ - + ]: 120 : memset(payload_read, 0x00, sizeof(payload_read));
7066 : 120 : spdk_blob_io_read(blob, channel, payload_read, SZ + 10, 4, blob_op_complete, NULL);
7067 : 120 : poll_threads();
7068 : 120 : CU_ASSERT(g_bserrno == 0);
7069 : :
7070 [ - + - + ]: 120 : CU_ASSERT(memcmp(payload_read + 0 * 512, payload_00, 2 * 512) == 0);
7071 [ - + - + ]: 120 : CU_ASSERT(memcmp(payload_read + 2 * 512, payload_ff, 2 * 512) == 0);
7072 [ - + - + ]: 120 : CU_ASSERT(memcmp(payload_read + 4 * 512, payload_00, (SZ - 4) * 512) == 0);
7073 : :
7074 : : /* Read second cluster
7075 : : * cluster0: [ F0F0 AAAA | AAAA 0000 | 0000 0000 | 0000 FFFF ]
7076 : : * cluster1: [ (FFFF 0000 | 0000 FF00 | 0000 0000 | 0000 0000) ]
7077 : : * payload_read: FFFF 0000 | 0000 FF00 ... */
7078 [ - + ]: 120 : memset(payload_read, 0x00, sizeof(payload_read));
7079 : 120 : spdk_blob_io_read(blob, channel, payload_read, SZ, SZ, blob_op_complete, NULL);
7080 : 120 : poll_threads();
7081 : 120 : CU_ASSERT(g_bserrno == 0);
7082 [ - + - + ]: 120 : CU_ASSERT(memcmp(payload_read + 0 * 512, payload_ff, 4 * 512) == 0);
7083 [ - + - + ]: 120 : CU_ASSERT(memcmp(payload_read + 4 * 512, payload_00, 8 * 512) == 0);
7084 [ - + - + ]: 120 : CU_ASSERT(memcmp(payload_read + 12 * 512, payload_ff, 2 * 512) == 0);
7085 [ - + - + ]: 120 : CU_ASSERT(memcmp(payload_read + 14 * 512, payload_00, (SZ - 14) * 512) == 0);
7086 : :
7087 : : /* Read whole two clusters
7088 : : * cluster0: [ (F0F0 AAAA | AAAA) 0000 | 0000 0000 | 0000 FFFF ]
7089 : : * cluster1: [ FFFF 0000 | 0000 FF00 | 0000 0000 | 0000 0000) ] */
7090 [ - + ]: 120 : memset(payload_read, 0x00, sizeof(payload_read));
7091 : 120 : spdk_blob_io_read(blob, channel, payload_read, 0, SZ * 2, blob_op_complete, NULL);
7092 : 120 : poll_threads();
7093 : 120 : CU_ASSERT(g_bserrno == 0);
7094 : :
7095 [ - + - + ]: 120 : CU_ASSERT(memcmp(payload_read + 0 * 512, payload_ff, 512) == 0);
7096 [ - + - + ]: 120 : CU_ASSERT(memcmp(payload_read + 1 * 512, payload_00, 512) == 0);
7097 [ - + - + ]: 120 : CU_ASSERT(memcmp(payload_read + 2 * 512, payload_ff, 512) == 0);
7098 [ - + - + ]: 120 : CU_ASSERT(memcmp(payload_read + 3 * 512, payload_00, 512) == 0);
7099 [ - + - + ]: 120 : CU_ASSERT(memcmp(payload_read + 4 * 512, payload_aa, 8 * 512) == 0);
7100 [ - + - + ]: 120 : CU_ASSERT(memcmp(payload_read + (SZ - 4) * 512, payload_ff, 4 * 512) == 0);
7101 : :
7102 [ - + - + ]: 120 : CU_ASSERT(memcmp(payload_read + (SZ + 0) * 512, payload_ff, 4 * 512) == 0);
7103 [ - + - + ]: 120 : CU_ASSERT(memcmp(payload_read + (SZ + 4) * 512, payload_00, 8 * 512) == 0);
7104 [ - + - + ]: 120 : CU_ASSERT(memcmp(payload_read + (SZ + 12) * 512, payload_ff, 2 * 512) == 0);
7105 [ - + - + ]: 120 : CU_ASSERT(memcmp(payload_read + (SZ + 14) * 512, payload_00, (SZ - 14) * 512) == 0);
7106 : 120 : }
7107 : :
7108 : :
7109 : : static void
7110 : 60 : test_io_unmap(struct spdk_bs_dev *dev, struct spdk_blob *blob, struct spdk_io_channel *channel)
7111 : 45 : {
7112 : 60 : const uint32_t SZ = IO_UT_BLOCKS_PER_CLUSTER;
7113 [ - + ]: 60 : uint8_t payload_ff[SZ * 512];
7114 [ - + ]: 60 : uint8_t payload_aa[SZ * 512];
7115 [ - + ]: 60 : uint8_t payload_00[SZ * 512];
7116 : : uint8_t *cluster0, *cluster1;
7117 : :
7118 [ - + ]: 60 : memset(payload_ff, 0xFF, sizeof(payload_ff));
7119 [ - + ]: 60 : memset(payload_aa, 0xAA, sizeof(payload_aa));
7120 [ - + ]: 60 : memset(payload_00, 0x00, sizeof(payload_00));
7121 : :
7122 : 60 : cluster0 = &g_dev_buffer[blob->active.clusters[0] * dev->blocklen];
7123 : 60 : cluster1 = &g_dev_buffer[blob->active.clusters[1] * dev->blocklen];
7124 : :
7125 : : /* Unmap */
7126 : 60 : spdk_blob_io_unmap(blob, channel, 0, SZ * 2, blob_op_complete, NULL);
7127 : 60 : poll_threads();
7128 : :
7129 : 60 : CU_ASSERT(g_bserrno == 0);
7130 : :
7131 [ - + - + ]: 60 : CU_ASSERT(memcmp(cluster0 + 0 * 512, payload_00, SZ * 512) == 0);
7132 [ - + - + ]: 60 : CU_ASSERT(memcmp(cluster1 + 0 * 512, payload_00, SZ * 512) == 0);
7133 : 60 : }
7134 : :
7135 : : static void
7136 : 80 : test_io_zeroes(struct spdk_bs_dev *dev, struct spdk_blob *blob, struct spdk_io_channel *channel)
7137 : 60 : {
7138 : 80 : const uint32_t SZ = IO_UT_BLOCKS_PER_CLUSTER;
7139 [ - + ]: 80 : uint8_t payload_ff[SZ * 512];
7140 [ - + ]: 80 : uint8_t payload_aa[SZ * 512];
7141 [ - + ]: 80 : uint8_t payload_00[SZ * 512];
7142 : : uint8_t *cluster0, *cluster1;
7143 : :
7144 [ - + ]: 80 : memset(payload_ff, 0xFF, sizeof(payload_ff));
7145 [ - + ]: 80 : memset(payload_aa, 0xAA, sizeof(payload_aa));
7146 [ - + ]: 80 : memset(payload_00, 0x00, sizeof(payload_00));
7147 : :
7148 : 80 : cluster0 = &g_dev_buffer[blob->active.clusters[0] * dev->blocklen];
7149 : 80 : cluster1 = &g_dev_buffer[blob->active.clusters[1] * dev->blocklen];
7150 : :
7151 : : /* Write zeroes */
7152 : 80 : spdk_blob_io_write_zeroes(blob, channel, 0, SZ * 2, blob_op_complete, NULL);
7153 : 80 : poll_threads();
7154 : :
7155 : 80 : CU_ASSERT(g_bserrno == 0);
7156 : :
7157 [ - + - + ]: 80 : CU_ASSERT(memcmp(cluster0 + 0 * 512, payload_00, SZ * 512) == 0);
7158 [ - + - + ]: 80 : CU_ASSERT(memcmp(cluster1 + 0 * 512, payload_00, SZ * 512) == 0);
7159 : 80 : }
7160 : :
7161 : : static inline void
7162 : 600 : test_blob_io_writev(struct spdk_blob *blob, struct spdk_io_channel *channel,
7163 : : struct iovec *iov, int iovcnt, uint64_t offset, uint64_t length,
7164 : : spdk_blob_op_complete cb_fn, void *cb_arg, struct spdk_blob_ext_io_opts *io_opts)
7165 : : {
7166 [ + + ]: 600 : if (io_opts) {
7167 : 300 : g_dev_writev_ext_called = false;
7168 : 300 : memset(&g_blob_ext_io_opts, 0, sizeof(g_blob_ext_io_opts));
7169 : 375 : spdk_blob_io_writev_ext(blob, channel, iov, iovcnt, offset, length, blob_op_complete, NULL,
7170 : 75 : io_opts);
7171 : 75 : } else {
7172 : 300 : spdk_blob_io_writev(blob, channel, iov, iovcnt, offset, length, blob_op_complete, NULL);
7173 : : }
7174 : 600 : poll_threads();
7175 : 600 : CU_ASSERT(g_bserrno == 0);
7176 [ + + ]: 600 : if (io_opts) {
7177 [ - + ]: 300 : CU_ASSERT(g_dev_writev_ext_called);
7178 [ - + ]: 300 : CU_ASSERT(memcmp(io_opts, &g_blob_ext_io_opts, sizeof(g_blob_ext_io_opts)) == 0);
7179 : 75 : }
7180 : 600 : }
7181 : :
7182 : : static void
7183 : 120 : test_iov_write(struct spdk_bs_dev *dev, struct spdk_blob *blob, struct spdk_io_channel *channel,
7184 : : bool ext_api)
7185 : 90 : {
7186 : 120 : const uint32_t SZ = IO_UT_BLOCKS_PER_CLUSTER;
7187 [ - + ]: 150 : uint8_t payload_ff[SZ * 512];
7188 [ - + ]: 150 : uint8_t payload_aa[SZ * 512];
7189 [ - + ]: 150 : uint8_t payload_00[SZ * 512];
7190 : : uint8_t *cluster0, *cluster1;
7191 : 90 : struct iovec iov[4];
7192 : 120 : struct spdk_blob_ext_io_opts ext_opts = {
7193 : : .memory_domain = (struct spdk_memory_domain *)0xfeedbeef,
7194 : : .memory_domain_ctx = (void *)0xf00df00d,
7195 : : .size = sizeof(struct spdk_blob_ext_io_opts),
7196 : : .user_ctx = (void *)123,
7197 : : };
7198 : :
7199 [ - + ]: 120 : memset(payload_ff, 0xFF, sizeof(payload_ff));
7200 [ - + ]: 120 : memset(payload_aa, 0xAA, sizeof(payload_aa));
7201 [ - + ]: 120 : memset(payload_00, 0x00, sizeof(payload_00));
7202 : :
7203 : : /* Try to perform I/O with io unit = 512 */
7204 : 120 : iov[0].iov_base = payload_ff;
7205 : 120 : iov[0].iov_len = 1 * 512;
7206 : :
7207 [ + + ]: 150 : test_blob_io_writev(blob, channel, iov, 1, 0, 1, blob_op_complete, NULL,
7208 [ + + ]: 30 : ext_api ? &ext_opts : NULL);
7209 : :
7210 : : /* If thin provisioned is set cluster should be allocated now */
7211 [ + + ]: 120 : SPDK_CU_ASSERT_FATAL(blob->active.clusters[0] != 0);
7212 : 120 : cluster0 = &g_dev_buffer[blob->active.clusters[0] * dev->blocklen];
7213 : :
7214 : : /* Each character 0-F symbolizes single io_unit containing 512 bytes block filled with that character.
7215 : : * Each page is separated by |. Whole block [...] symbolizes one cluster (containing 4 pages). */
7216 : : /* cluster0: [ F000 0000 | 0000 0000 | 0000 0000 | 0000 0000 ] */
7217 [ - + - + ]: 120 : CU_ASSERT(memcmp(cluster0 + 0 * 512, payload_ff, 512) == 0);
7218 [ - + - + ]: 120 : CU_ASSERT(memcmp(cluster0 + 1 * 512, payload_00, (SZ - 1) * 512) == 0);
7219 : :
7220 : : /* Verify write with offset on first page */
7221 : 120 : iov[0].iov_base = payload_ff;
7222 : 120 : iov[0].iov_len = 1 * 512;
7223 : :
7224 [ + + ]: 150 : test_blob_io_writev(blob, channel, iov, 1, 2, 1, blob_op_complete, NULL,
7225 [ + + ]: 30 : ext_api ? &ext_opts : NULL);
7226 : :
7227 : : /* cluster0: [ F0F0 0000 | 0000 0000 | 0000 0000 | 0000 0000 ] */
7228 [ - + - + ]: 120 : CU_ASSERT(memcmp(cluster0 + 0 * 512, payload_ff, 512) == 0);
7229 [ - + - + ]: 120 : CU_ASSERT(memcmp(cluster0 + 1 * 512, payload_00, 512) == 0);
7230 [ - + - + ]: 120 : CU_ASSERT(memcmp(cluster0 + 2 * 512, payload_ff, 512) == 0);
7231 [ - + - + ]: 120 : CU_ASSERT(memcmp(cluster0 + 3 * 512, payload_00, 512) == 0);
7232 [ - + - + ]: 120 : CU_ASSERT(memcmp(cluster0 + 4 * 512, payload_00, (SZ - 4) * 512) == 0);
7233 : :
7234 : : /* Verify write with offset on first page */
7235 : 120 : iov[0].iov_base = payload_ff;
7236 : 120 : iov[0].iov_len = 4 * 512;
7237 : 120 : spdk_blob_io_writev(blob, channel, iov, 1, 4, 4, blob_op_complete, NULL);
7238 : 120 : poll_threads();
7239 : :
7240 : : /* cluster0: [ F0F0 FFFF | 0000 0000 | 0000 0000 | 0000 0000 ] */
7241 [ - + - + ]: 120 : CU_ASSERT(memcmp(cluster0 + 0 * 512, payload_ff, 512) == 0);
7242 [ - + - + ]: 120 : CU_ASSERT(memcmp(cluster0 + 1 * 512, payload_00, 512) == 0);
7243 [ - + - + ]: 120 : CU_ASSERT(memcmp(cluster0 + 2 * 512, payload_ff, 512) == 0);
7244 [ - + - + ]: 120 : CU_ASSERT(memcmp(cluster0 + 3 * 512, payload_00, 512) == 0);
7245 [ - + - + ]: 120 : CU_ASSERT(memcmp(cluster0 + 4 * 512, payload_ff, 4 * 512) == 0);
7246 [ - + - + ]: 120 : CU_ASSERT(memcmp(cluster0 + 8 * 512, payload_00, (SZ - 8) * 512) == 0);
7247 : :
7248 : : /* Verify write with offset on second page */
7249 : 120 : iov[0].iov_base = payload_ff;
7250 : 120 : iov[0].iov_len = 4 * 512;
7251 : 120 : spdk_blob_io_writev(blob, channel, iov, 1, 8, 4, blob_op_complete, NULL);
7252 : 120 : poll_threads();
7253 : :
7254 : : /* cluster0: [ F0F0 FFFF | FFFF 0000 | 0000 0000 | 0000 0000 ] */
7255 [ - + - + ]: 120 : CU_ASSERT(memcmp(cluster0 + 0 * 512, payload_ff, 512) == 0);
7256 [ - + - + ]: 120 : CU_ASSERT(memcmp(cluster0 + 1 * 512, payload_00, 512) == 0);
7257 [ - + - + ]: 120 : CU_ASSERT(memcmp(cluster0 + 2 * 512, payload_ff, 512) == 0);
7258 [ - + - + ]: 120 : CU_ASSERT(memcmp(cluster0 + 3 * 512, payload_00, 512) == 0);
7259 [ - + - + ]: 120 : CU_ASSERT(memcmp(cluster0 + 4 * 512, payload_ff, 8 * 512) == 0);
7260 [ - + - + ]: 120 : CU_ASSERT(memcmp(cluster0 + 12 * 512, payload_00, (SZ - 12) * 512) == 0);
7261 : :
7262 : : /* Verify write across multiple pages */
7263 : 120 : iov[0].iov_base = payload_aa;
7264 : 120 : iov[0].iov_len = 8 * 512;
7265 : :
7266 [ + + ]: 150 : test_blob_io_writev(blob, channel, iov, 1, 4, 8, blob_op_complete, NULL,
7267 [ + + ]: 30 : ext_api ? &ext_opts : NULL);
7268 : :
7269 : : /* cluster0: [ F0F0 AAAA | AAAA 0000 | 0000 0000 | 0000 0000 ] */
7270 [ - + - + ]: 120 : CU_ASSERT(memcmp(cluster0 + 0 * 512, payload_ff, 512) == 0);
7271 [ - + - + ]: 120 : CU_ASSERT(memcmp(cluster0 + 1 * 512, payload_00, 512) == 0);
7272 [ - + - + ]: 120 : CU_ASSERT(memcmp(cluster0 + 2 * 512, payload_ff, 512) == 0);
7273 [ - + - + ]: 120 : CU_ASSERT(memcmp(cluster0 + 3 * 512, payload_00, 512) == 0);
7274 [ - + - + ]: 120 : CU_ASSERT(memcmp(cluster0 + 4 * 512, payload_aa, 8 * 512) == 0);
7275 [ - + - + ]: 120 : CU_ASSERT(memcmp(cluster0 + 12 * 512, payload_00, (SZ - 12) * 512) == 0);
7276 : :
7277 : : /* Verify write across multiple clusters */
7278 : :
7279 : 120 : iov[0].iov_base = payload_ff;
7280 : 120 : iov[0].iov_len = 8 * 512;
7281 : :
7282 [ + + ]: 150 : test_blob_io_writev(blob, channel, iov, 1, (SZ - 4), 8, blob_op_complete, NULL,
7283 [ + + ]: 30 : ext_api ? &ext_opts : NULL);
7284 : :
7285 [ + + ]: 120 : SPDK_CU_ASSERT_FATAL(blob->active.clusters[1] != 0);
7286 : 120 : cluster1 = &g_dev_buffer[blob->active.clusters[1] * dev->blocklen];
7287 : :
7288 : : /* cluster0: [ F0F0 AAAA | AAAA 0000 | 0000 0000 | 0000 FFFF ]
7289 : : * cluster1: [ FFFF 0000 | 0000 0000 | 0000 0000 | 0000 0000 ] */
7290 [ - + - + ]: 120 : CU_ASSERT(memcmp(cluster0 + 0 * 512, payload_ff, 512) == 0);
7291 [ - + - + ]: 120 : CU_ASSERT(memcmp(cluster0 + 1 * 512, payload_00, 512) == 0);
7292 [ - + - + ]: 120 : CU_ASSERT(memcmp(cluster0 + 2 * 512, payload_ff, 512) == 0);
7293 [ - + - + ]: 120 : CU_ASSERT(memcmp(cluster0 + 3 * 512, payload_00, 512) == 0);
7294 [ - + - + ]: 120 : CU_ASSERT(memcmp(cluster0 + 4 * 512, payload_aa, 8 * 512) == 0);
7295 [ - + - + ]: 120 : CU_ASSERT(memcmp(cluster0 + 12 * 512, payload_00, (SZ - 16) * 512) == 0);
7296 [ - + - + ]: 120 : CU_ASSERT(memcmp(cluster0 + (SZ - 4) * 512, payload_ff, 4 * 512) == 0);
7297 : :
7298 [ - + - + ]: 120 : CU_ASSERT(memcmp(cluster1 + 0 * 512, payload_ff, 4 * 512) == 0);
7299 [ - + - + ]: 120 : CU_ASSERT(memcmp(cluster1 + 4 * 512, payload_00, (SZ - 4) * 512) == 0);
7300 : :
7301 : : /* Verify write to second cluster */
7302 : :
7303 : 120 : iov[0].iov_base = payload_ff;
7304 : 120 : iov[0].iov_len = 2 * 512;
7305 : :
7306 [ + + ]: 150 : test_blob_io_writev(blob, channel, iov, 1, SZ + 12, 2, blob_op_complete, NULL,
7307 [ + + ]: 30 : ext_api ? &ext_opts : NULL);
7308 : :
7309 [ - + ]: 120 : SPDK_CU_ASSERT_FATAL(blob->active.clusters[1] != 0);
7310 : 120 : cluster1 = &g_dev_buffer[blob->active.clusters[1] * dev->blocklen];
7311 : :
7312 : : /* cluster0: [ F0F0 AAAA | AAAA 0000 | 0000 0000 | 0000 FFFF ]
7313 : : * cluster1: [ FFFF 0000 | 0000 FF00 | 0000 0000 | 0000 0000 ] */
7314 [ - + - + ]: 120 : CU_ASSERT(memcmp(cluster0 + 0 * 512, payload_ff, 512) == 0);
7315 [ - + - + ]: 120 : CU_ASSERT(memcmp(cluster0 + 1 * 512, payload_00, 512) == 0);
7316 [ - + - + ]: 120 : CU_ASSERT(memcmp(cluster0 + 2 * 512, payload_ff, 512) == 0);
7317 [ - + - + ]: 120 : CU_ASSERT(memcmp(cluster0 + 3 * 512, payload_00, 512) == 0);
7318 [ - + - + ]: 120 : CU_ASSERT(memcmp(cluster0 + 4 * 512, payload_aa, 8 * 512) == 0);
7319 [ - + - + ]: 120 : CU_ASSERT(memcmp(cluster0 + (SZ - 4) * 512, payload_ff, 4 * 512) == 0);
7320 : :
7321 [ - + - + ]: 120 : CU_ASSERT(memcmp(cluster1 + 0 * 512, payload_ff, 4 * 512) == 0);
7322 [ - + - + ]: 120 : CU_ASSERT(memcmp(cluster1 + 4 * 512, payload_00, 8 * 512) == 0);
7323 [ - + - + ]: 120 : CU_ASSERT(memcmp(cluster1 + 12 * 512, payload_ff, 2 * 512) == 0);
7324 [ - + - + ]: 120 : CU_ASSERT(memcmp(cluster1 + 14 * 512, payload_00, (SZ - 14) * 512) == 0);
7325 : 120 : }
7326 : :
7327 : : static inline void
7328 : 1680 : test_blob_io_readv(struct spdk_blob *blob, struct spdk_io_channel *channel,
7329 : : struct iovec *iov, int iovcnt, uint64_t offset, uint64_t length,
7330 : : spdk_blob_op_complete cb_fn, void *cb_arg, struct spdk_blob_ext_io_opts *io_opts)
7331 : : {
7332 [ + + ]: 1680 : if (io_opts) {
7333 : 840 : g_dev_readv_ext_called = false;
7334 : 840 : memset(&g_blob_ext_io_opts, 0, sizeof(g_blob_ext_io_opts));
7335 : 840 : spdk_blob_io_readv_ext(blob, channel, iov, iovcnt, offset, length, blob_op_complete, NULL, io_opts);
7336 : 210 : } else {
7337 : 840 : spdk_blob_io_readv(blob, channel, iov, iovcnt, offset, length, blob_op_complete, NULL);
7338 : : }
7339 : 1680 : poll_threads();
7340 : 1680 : CU_ASSERT(g_bserrno == 0);
7341 [ + + ]: 1680 : if (io_opts) {
7342 [ - + ]: 840 : CU_ASSERT(g_dev_readv_ext_called);
7343 [ - + ]: 840 : CU_ASSERT(memcmp(io_opts, &g_blob_ext_io_opts, sizeof(g_blob_ext_io_opts)) == 0);
7344 : 210 : }
7345 : 1680 : }
7346 : :
7347 : : static void
7348 : 240 : test_iov_read(struct spdk_bs_dev *dev, struct spdk_blob *blob, struct spdk_io_channel *channel,
7349 : : bool ext_api)
7350 : 180 : {
7351 : 240 : const uint32_t SZ = IO_UT_BLOCKS_PER_CLUSTER;
7352 [ - + ]: 660 : uint8_t payload_read[2 * SZ * 512];
7353 [ - + ]: 300 : uint8_t payload_ff[SZ * 512];
7354 [ - + ]: 300 : uint8_t payload_aa[SZ * 512];
7355 [ - + ]: 300 : uint8_t payload_00[SZ * 512];
7356 : 180 : struct iovec iov[4];
7357 : 240 : struct spdk_blob_ext_io_opts ext_opts = {
7358 : : .memory_domain = (struct spdk_memory_domain *)0xfeedbeef,
7359 : : .memory_domain_ctx = (void *)0xf00df00d,
7360 : : .size = sizeof(struct spdk_blob_ext_io_opts),
7361 : : .user_ctx = (void *)123,
7362 : : };
7363 : :
7364 [ - + ]: 240 : memset(payload_ff, 0xFF, sizeof(payload_ff));
7365 [ - + ]: 240 : memset(payload_aa, 0xAA, sizeof(payload_aa));
7366 [ - + ]: 240 : memset(payload_00, 0x00, sizeof(payload_00));
7367 : :
7368 : : /* Read only first io unit */
7369 : : /* cluster0: [ (F)0F0 AAAA | AAAA 0000 | 0000 0000 | 0000 FFFF ]
7370 : : * cluster1: [ FFFF 0000 | 0000 FF00 | 0000 0000 | 0000 0000 ]
7371 : : * payload_read: F000 0000 | 0000 0000 ... */
7372 [ - + ]: 240 : memset(payload_read, 0x00, sizeof(payload_read));
7373 : 240 : iov[0].iov_base = payload_read;
7374 : 240 : iov[0].iov_len = 1 * 512;
7375 : :
7376 [ + + ]: 240 : test_blob_io_readv(blob, channel, iov, 1, 0, 1, blob_op_complete, NULL, ext_api ? &ext_opts : NULL);
7377 : :
7378 [ - + - + ]: 240 : CU_ASSERT(memcmp(payload_read + 0 * 512, payload_ff, 512) == 0);
7379 [ - + - + ]: 240 : CU_ASSERT(memcmp(payload_read + 1 * 512, payload_00, (SZ - 1) * 512) == 0);
7380 : :
7381 : : /* Read four io_units starting from offset = 2
7382 : : * cluster0: [ F0(F0 AA)AA | AAAA 0000 | 0000 0000 | 0000 FFFF ]
7383 : : * cluster1: [ FFFF 0000 | 0000 FF00 | 0000 0000 | 0000 0000 ]
7384 : : * payload_read: F0AA 0000 | 0000 0000 ... */
7385 : :
7386 [ - + ]: 240 : memset(payload_read, 0x00, sizeof(payload_read));
7387 : 240 : iov[0].iov_base = payload_read;
7388 : 240 : iov[0].iov_len = 4 * 512;
7389 : :
7390 [ + + ]: 240 : test_blob_io_readv(blob, channel, iov, 1, 2, 4, blob_op_complete, NULL, ext_api ? &ext_opts : NULL);
7391 : :
7392 [ - + - + ]: 240 : CU_ASSERT(memcmp(payload_read + 0 * 512, payload_ff, 512) == 0);
7393 [ - + - + ]: 240 : CU_ASSERT(memcmp(payload_read + 1 * 512, payload_00, 512) == 0);
7394 [ - + - + ]: 240 : CU_ASSERT(memcmp(payload_read + 2 * 512, payload_aa, 512) == 0);
7395 [ - + - + ]: 240 : CU_ASSERT(memcmp(payload_read + 3 * 512, payload_aa, 512) == 0);
7396 [ - + - + ]: 240 : CU_ASSERT(memcmp(payload_read + 4 * 512, payload_00, (SZ - 4) * 512) == 0);
7397 : :
7398 : : /* Read eight io_units across multiple pages
7399 : : * cluster0: [ F0F0 (AAAA | AAAA) 0000 | 0000 0000 | 0000 FFFF ]
7400 : : * cluster1: [ FFFF 0000 | 0000 FF00 | 0000 0000 | 0000 0000 ]
7401 : : * payload_read: AAAA AAAA | 0000 0000 ... */
7402 [ - + ]: 240 : memset(payload_read, 0x00, sizeof(payload_read));
7403 : 240 : iov[0].iov_base = payload_read;
7404 : 240 : iov[0].iov_len = 4 * 512;
7405 : 240 : iov[1].iov_base = payload_read + 4 * 512;
7406 : 240 : iov[1].iov_len = 4 * 512;
7407 : :
7408 [ + + ]: 240 : test_blob_io_readv(blob, channel, iov, 2, 4, 8, blob_op_complete, NULL, ext_api ? &ext_opts : NULL);
7409 : :
7410 [ - + - + ]: 240 : CU_ASSERT(memcmp(payload_read + 0 * 512, payload_aa, 8 * 512) == 0);
7411 [ - + - + ]: 240 : CU_ASSERT(memcmp(payload_read + 8 * 512, payload_00, (SZ - 8) * 512) == 0);
7412 : :
7413 : : /* Read eight io_units across multiple clusters
7414 : : * cluster0: [ F0F0 AAAA | AAAA 0000 | 0000 0000 | 0000 (FFFF ]
7415 : : * cluster1: [ FFFF) 0000 | 0000 FF00 | 0000 0000 | 0000 0000 ]
7416 : : * payload_read: FFFF FFFF | 0000 0000 ... */
7417 [ - + ]: 240 : memset(payload_read, 0x00, sizeof(payload_read));
7418 : 240 : iov[0].iov_base = payload_read;
7419 : 240 : iov[0].iov_len = 2 * 512;
7420 : 240 : iov[1].iov_base = payload_read + 2 * 512;
7421 : 240 : iov[1].iov_len = 2 * 512;
7422 : 240 : iov[2].iov_base = payload_read + 4 * 512;
7423 : 240 : iov[2].iov_len = 2 * 512;
7424 : 240 : iov[3].iov_base = payload_read + 6 * 512;
7425 : 240 : iov[3].iov_len = 2 * 512;
7426 : :
7427 [ + + ]: 300 : test_blob_io_readv(blob, channel, iov, 4, SZ - 4, 8, blob_op_complete, NULL,
7428 [ + + ]: 60 : ext_api ? &ext_opts : NULL);
7429 : :
7430 [ - + - + ]: 240 : CU_ASSERT(memcmp(payload_read + 0 * 512, payload_ff, 8 * 512) == 0);
7431 [ - + - + ]: 240 : CU_ASSERT(memcmp(payload_read + 8 * 512, payload_00, (SZ - 8) * 512) == 0);
7432 : :
7433 : : /* Read four io_units from second cluster
7434 : : * cluster0: [ F0F0 AAAA | AAAA 0000 | 0000 0000 | 0000 FFFF ]
7435 : : * cluster1: [ FFFF 0000 | 00(00 FF)00 | 0000 0000 | 0000 0000 ]
7436 : : * payload_read: 00FF 0000 | 0000 0000 ... */
7437 [ - + ]: 240 : memset(payload_read, 0x00, sizeof(payload_read));
7438 : 240 : iov[0].iov_base = payload_read;
7439 : 240 : iov[0].iov_len = 1 * 512;
7440 : 240 : iov[1].iov_base = payload_read + 1 * 512;
7441 : 240 : iov[1].iov_len = 3 * 512;
7442 : :
7443 [ + + ]: 300 : test_blob_io_readv(blob, channel, iov, 2, SZ + 10, 4, blob_op_complete, NULL,
7444 [ + + ]: 60 : ext_api ? &ext_opts : NULL);
7445 : :
7446 [ - + - + ]: 240 : CU_ASSERT(memcmp(payload_read + 0 * 512, payload_00, 2 * 512) == 0);
7447 [ - + - + ]: 240 : CU_ASSERT(memcmp(payload_read + 2 * 512, payload_ff, 2 * 512) == 0);
7448 [ - + - + ]: 240 : CU_ASSERT(memcmp(payload_read + 4 * 512, payload_00, (SZ - 4) * 512) == 0);
7449 : :
7450 : : /* Read second cluster
7451 : : * cluster0: [ F0F0 AAAA | AAAA 0000 | 0000 0000 | 0000 FFFF ]
7452 : : * cluster1: [ (FFFF 0000 | 0000 FF00 | 0000 0000 | 0000 0000) ]
7453 : : * payload_read: FFFF 0000 | 0000 FF00 ... */
7454 [ - + ]: 240 : memset(payload_read, 0x00, sizeof(payload_read));
7455 : 240 : iov[0].iov_base = payload_read;
7456 : 240 : iov[0].iov_len = 1 * 512;
7457 : 240 : iov[1].iov_base = payload_read + 1 * 512;
7458 : 240 : iov[1].iov_len = 2 * 512;
7459 : 240 : iov[2].iov_base = payload_read + 3 * 512;
7460 : 240 : iov[2].iov_len = 4 * 512;
7461 : 240 : iov[3].iov_base = payload_read + 7 * 512;
7462 : 240 : iov[3].iov_len = (SZ - 7) * 512;
7463 : :
7464 [ + + ]: 300 : test_blob_io_readv(blob, channel, iov, 4, SZ, SZ, blob_op_complete, NULL,
7465 [ + + ]: 60 : ext_api ? &ext_opts : NULL);
7466 : :
7467 [ - + - + ]: 240 : CU_ASSERT(memcmp(payload_read + 0 * 512, payload_ff, 4 * 512) == 0);
7468 [ - + - + ]: 240 : CU_ASSERT(memcmp(payload_read + 4 * 512, payload_00, 8 * 512) == 0);
7469 [ - + - + ]: 240 : CU_ASSERT(memcmp(payload_read + 12 * 512, payload_ff, 2 * 512) == 0);
7470 [ - + - + ]: 240 : CU_ASSERT(memcmp(payload_read + 14 * 512, payload_00, (SZ - 14) * 512) == 0);
7471 : :
7472 : : /* Read whole two clusters
7473 : : * cluster0: [ (F0F0 AAAA | AAAA) 0000 | 0000 0000 | 0000 FFFF ]
7474 : : * cluster1: [ FFFF 0000 | 0000 FF00 | 0000 0000 | 0000 0000) ] */
7475 [ - + ]: 240 : memset(payload_read, 0x00, sizeof(payload_read));
7476 : 240 : iov[0].iov_base = payload_read;
7477 : 240 : iov[0].iov_len = 1 * 512;
7478 : 240 : iov[1].iov_base = payload_read + 1 * 512;
7479 : 240 : iov[1].iov_len = 8 * 512;
7480 : 240 : iov[2].iov_base = payload_read + 9 * 512;
7481 : 240 : iov[2].iov_len = 16 * 512;
7482 : 240 : iov[3].iov_base = payload_read + 25 * 512;
7483 : 240 : iov[3].iov_len = (2 * SZ - 25) * 512;
7484 : :
7485 [ + + ]: 300 : test_blob_io_readv(blob, channel, iov, 4, 0, SZ * 2, blob_op_complete, NULL,
7486 [ + + ]: 60 : ext_api ? &ext_opts : NULL);
7487 : :
7488 [ - + - + ]: 240 : CU_ASSERT(memcmp(payload_read + 0 * 512, payload_ff, 512) == 0);
7489 [ - + - + ]: 240 : CU_ASSERT(memcmp(payload_read + 1 * 512, payload_00, 512) == 0);
7490 [ - + - + ]: 240 : CU_ASSERT(memcmp(payload_read + 2 * 512, payload_ff, 512) == 0);
7491 [ - + - + ]: 240 : CU_ASSERT(memcmp(payload_read + 3 * 512, payload_00, 512) == 0);
7492 [ - + - + ]: 240 : CU_ASSERT(memcmp(payload_read + 4 * 512, payload_aa, 8 * 512) == 0);
7493 [ - + - + ]: 240 : CU_ASSERT(memcmp(payload_read + (SZ - 4) * 512, payload_ff, 4 * 512) == 0);
7494 : :
7495 [ - + - + ]: 240 : CU_ASSERT(memcmp(payload_read + (SZ + 0) * 512, payload_ff, 4 * 512) == 0);
7496 [ - + - + ]: 240 : CU_ASSERT(memcmp(payload_read + (SZ + 4) * 512, payload_00, 8 * 512) == 0);
7497 [ - + - + ]: 240 : CU_ASSERT(memcmp(payload_read + (SZ + 12) * 512, payload_ff, 2 * 512) == 0);
7498 [ - + - + ]: 240 : CU_ASSERT(memcmp(payload_read + (SZ + 14) * 512, payload_00, (SZ - 14) * 512) == 0);
7499 : 240 : }
7500 : :
7501 : : static void
7502 : 20 : blob_io_unit(void)
7503 : : {
7504 : 15 : struct spdk_bs_opts bsopts;
7505 : 15 : struct spdk_blob_opts opts;
7506 : : struct spdk_blob_store *bs;
7507 : : struct spdk_bs_dev *dev;
7508 : : struct spdk_blob *blob, *snapshot, *clone;
7509 : : spdk_blob_id blobid;
7510 : : struct spdk_io_channel *channel;
7511 : :
7512 : : /* Create dev with 512 bytes io unit size */
7513 : :
7514 : 20 : spdk_bs_opts_init(&bsopts, sizeof(bsopts));
7515 : 20 : bsopts.cluster_sz = IO_UT_BLOCKS_PER_CLUSTER * 512;
7516 [ - + ]: 20 : snprintf(bsopts.bstype.bstype, sizeof(bsopts.bstype.bstype), "TESTTYPE");
7517 : :
7518 : : /* Try to initialize a new blob store with unsupported io_unit */
7519 : 20 : dev = init_dev();
7520 : 20 : dev->blocklen = 512;
7521 [ - + ]: 20 : dev->blockcnt = DEV_BUFFER_SIZE / dev->blocklen;
7522 : :
7523 : : /* Initialize a new blob store */
7524 : 20 : spdk_bs_init(dev, &bsopts, bs_op_with_handle_complete, NULL);
7525 : 20 : poll_threads();
7526 : 20 : CU_ASSERT(g_bserrno == 0);
7527 [ + + ]: 20 : SPDK_CU_ASSERT_FATAL(g_bs != NULL);
7528 : 20 : bs = g_bs;
7529 : :
7530 : 20 : CU_ASSERT(spdk_bs_get_io_unit_size(bs) == 512);
7531 : 20 : channel = spdk_bs_alloc_io_channel(bs);
7532 : :
7533 : : /* Create thick provisioned blob */
7534 : 20 : ut_spdk_blob_opts_init(&opts);
7535 : 20 : opts.thin_provision = false;
7536 : 20 : opts.num_clusters = 32;
7537 : :
7538 : 20 : blob = ut_blob_create_and_open(bs, &opts);
7539 : 20 : blobid = spdk_blob_get_id(blob);
7540 : :
7541 : 20 : test_io_write(dev, blob, channel);
7542 : 20 : test_io_read(dev, blob, channel);
7543 : 20 : test_io_zeroes(dev, blob, channel);
7544 : :
7545 : 20 : test_iov_write(dev, blob, channel, false);
7546 : 20 : test_iov_read(dev, blob, channel, false);
7547 : 20 : test_io_zeroes(dev, blob, channel);
7548 : :
7549 : 20 : test_iov_write(dev, blob, channel, true);
7550 : 20 : test_iov_read(dev, blob, channel, true);
7551 : :
7552 : 20 : test_io_unmap(dev, blob, channel);
7553 : :
7554 : 20 : spdk_blob_close(blob, blob_op_complete, NULL);
7555 : 20 : poll_threads();
7556 : 20 : CU_ASSERT(g_bserrno == 0);
7557 : 20 : blob = NULL;
7558 : 20 : g_blob = NULL;
7559 : :
7560 : : /* Create thin provisioned blob */
7561 : :
7562 : 20 : ut_spdk_blob_opts_init(&opts);
7563 : 20 : opts.thin_provision = true;
7564 : 20 : opts.num_clusters = 32;
7565 : :
7566 : 20 : blob = ut_blob_create_and_open(bs, &opts);
7567 : 20 : blobid = spdk_blob_get_id(blob);
7568 : :
7569 : 20 : test_io_write(dev, blob, channel);
7570 : 20 : test_io_read(dev, blob, channel);
7571 : 20 : test_io_zeroes(dev, blob, channel);
7572 : :
7573 : 20 : test_iov_write(dev, blob, channel, false);
7574 : 20 : test_iov_read(dev, blob, channel, false);
7575 : 20 : test_io_zeroes(dev, blob, channel);
7576 : :
7577 : 20 : test_iov_write(dev, blob, channel, true);
7578 : 20 : test_iov_read(dev, blob, channel, true);
7579 : :
7580 : : /* Create snapshot */
7581 : :
7582 : 20 : spdk_bs_create_snapshot(bs, blobid, NULL, blob_op_with_id_complete, NULL);
7583 : 20 : poll_threads();
7584 : 20 : CU_ASSERT(g_bserrno == 0);
7585 : 20 : CU_ASSERT(g_blobid != SPDK_BLOBID_INVALID);
7586 : 20 : blobid = g_blobid;
7587 : :
7588 : 20 : spdk_bs_open_blob(bs, blobid, blob_op_with_handle_complete, NULL);
7589 : 20 : poll_threads();
7590 : 20 : CU_ASSERT(g_bserrno == 0);
7591 : 20 : CU_ASSERT(g_blob != NULL);
7592 : 20 : snapshot = g_blob;
7593 : :
7594 : 20 : spdk_bs_create_clone(bs, blobid, NULL, blob_op_with_id_complete, NULL);
7595 : 20 : poll_threads();
7596 : 20 : CU_ASSERT(g_bserrno == 0);
7597 : 20 : CU_ASSERT(g_blobid != SPDK_BLOBID_INVALID);
7598 : 20 : blobid = g_blobid;
7599 : :
7600 : 20 : spdk_bs_open_blob(bs, blobid, blob_op_with_handle_complete, NULL);
7601 : 20 : poll_threads();
7602 : 20 : CU_ASSERT(g_bserrno == 0);
7603 : 20 : CU_ASSERT(g_blob != NULL);
7604 : 20 : clone = g_blob;
7605 : :
7606 : 20 : test_io_read(dev, blob, channel);
7607 : 20 : test_io_read(dev, snapshot, channel);
7608 : 20 : test_io_read(dev, clone, channel);
7609 : :
7610 : 20 : test_iov_read(dev, blob, channel, false);
7611 : 20 : test_iov_read(dev, snapshot, channel, false);
7612 : 20 : test_iov_read(dev, clone, channel, false);
7613 : :
7614 : 20 : test_iov_read(dev, blob, channel, true);
7615 : 20 : test_iov_read(dev, snapshot, channel, true);
7616 : 20 : test_iov_read(dev, clone, channel, true);
7617 : :
7618 : : /* Inflate clone */
7619 : :
7620 : 20 : spdk_bs_inflate_blob(bs, channel, blobid, blob_op_complete, NULL);
7621 : 20 : poll_threads();
7622 : :
7623 : 20 : CU_ASSERT(g_bserrno == 0);
7624 : :
7625 : 20 : test_io_read(dev, clone, channel);
7626 : :
7627 : 20 : test_io_unmap(dev, clone, channel);
7628 : :
7629 : 20 : test_iov_write(dev, clone, channel, false);
7630 : 20 : test_iov_read(dev, clone, channel, false);
7631 : 20 : test_io_unmap(dev, clone, channel);
7632 : :
7633 : 20 : test_iov_write(dev, clone, channel, true);
7634 : 20 : test_iov_read(dev, clone, channel, true);
7635 : :
7636 : 20 : spdk_blob_close(blob, blob_op_complete, NULL);
7637 : 20 : spdk_blob_close(snapshot, blob_op_complete, NULL);
7638 : 20 : spdk_blob_close(clone, blob_op_complete, NULL);
7639 : 20 : poll_threads();
7640 : 20 : CU_ASSERT(g_bserrno == 0);
7641 : 20 : blob = NULL;
7642 : 20 : g_blob = NULL;
7643 : :
7644 : 20 : spdk_bs_free_io_channel(channel);
7645 : 20 : poll_threads();
7646 : :
7647 : : /* Unload the blob store */
7648 : 20 : spdk_bs_unload(bs, bs_op_complete, NULL);
7649 : 20 : poll_threads();
7650 : 20 : CU_ASSERT(g_bserrno == 0);
7651 : 20 : g_bs = NULL;
7652 : 20 : g_blob = NULL;
7653 : 20 : g_blobid = 0;
7654 : 20 : }
7655 : :
7656 : : static void
7657 : 20 : blob_io_unit_compatibility(void)
7658 : : {
7659 : 15 : struct spdk_bs_opts bsopts;
7660 : : struct spdk_blob_store *bs;
7661 : : struct spdk_bs_dev *dev;
7662 : : struct spdk_bs_super_block *super;
7663 : :
7664 : : /* Create dev with 512 bytes io unit size */
7665 : :
7666 : 20 : spdk_bs_opts_init(&bsopts, sizeof(bsopts));
7667 : 20 : bsopts.cluster_sz = g_phys_blocklen * 4;
7668 [ - + ]: 20 : snprintf(bsopts.bstype.bstype, sizeof(bsopts.bstype.bstype), "TESTTYPE");
7669 : :
7670 : : /* Try to initialize a new blob store with unsupported io_unit */
7671 : 20 : dev = init_dev();
7672 : 20 : dev->blocklen = 512;
7673 [ - + ]: 20 : dev->blockcnt = DEV_BUFFER_SIZE / dev->blocklen;
7674 : :
7675 : : /* Initialize a new blob store */
7676 : 20 : spdk_bs_init(dev, &bsopts, bs_op_with_handle_complete, NULL);
7677 : 20 : poll_threads();
7678 : 20 : CU_ASSERT(g_bserrno == 0);
7679 [ + + ]: 20 : SPDK_CU_ASSERT_FATAL(g_bs != NULL);
7680 : 20 : bs = g_bs;
7681 : :
7682 : 20 : CU_ASSERT(spdk_bs_get_io_unit_size(bs) == 512);
7683 : :
7684 : : /* Unload the blob store */
7685 : 20 : spdk_bs_unload(bs, bs_op_complete, NULL);
7686 : 20 : poll_threads();
7687 : 20 : CU_ASSERT(g_bserrno == 0);
7688 : :
7689 : : /* Modify super block to behave like older version.
7690 : : * Check if loaded io unit size equals SPDK_BS_PAGE_SIZE */
7691 : 20 : super = (struct spdk_bs_super_block *)&g_dev_buffer[0];
7692 : 20 : super->io_unit_size = 0;
7693 : 20 : super->crc = blob_md_page_calc_crc(super);
7694 : :
7695 : 20 : dev = init_dev();
7696 : 20 : dev->blocklen = 512;
7697 [ - + ]: 20 : dev->blockcnt = DEV_BUFFER_SIZE / dev->blocklen;
7698 : :
7699 : 20 : spdk_bs_load(dev, &bsopts, bs_op_with_handle_complete, NULL);
7700 : 20 : poll_threads();
7701 : 20 : CU_ASSERT(g_bserrno == 0);
7702 [ - + ]: 20 : SPDK_CU_ASSERT_FATAL(g_bs != NULL);
7703 : 20 : bs = g_bs;
7704 : :
7705 : 20 : CU_ASSERT(spdk_bs_get_io_unit_size(bs) == SPDK_BS_PAGE_SIZE);
7706 : :
7707 : : /* Unload the blob store */
7708 : 20 : spdk_bs_unload(bs, bs_op_complete, NULL);
7709 : 20 : poll_threads();
7710 : 20 : CU_ASSERT(g_bserrno == 0);
7711 : :
7712 : 20 : g_bs = NULL;
7713 : 20 : g_blob = NULL;
7714 : 20 : g_blobid = 0;
7715 : 20 : }
7716 : :
7717 : : static void
7718 : 20 : first_sync_complete(void *cb_arg, int bserrno)
7719 : : {
7720 : 20 : struct spdk_blob *blob = cb_arg;
7721 : : int rc;
7722 : :
7723 : 20 : CU_ASSERT(bserrno == 0);
7724 : 20 : rc = spdk_blob_set_xattr(blob, "sync", "second", strlen("second") + 1);
7725 : 20 : CU_ASSERT(rc == 0);
7726 : 20 : CU_ASSERT(g_bserrno == -1);
7727 : :
7728 : : /* Keep g_bserrno at -1, only the
7729 : : * second sync completion should set it at 0. */
7730 : 20 : }
7731 : :
7732 : : static void
7733 : 20 : second_sync_complete(void *cb_arg, int bserrno)
7734 : : {
7735 : 20 : struct spdk_blob *blob = cb_arg;
7736 : 15 : const void *value;
7737 : 15 : size_t value_len;
7738 : : int rc;
7739 : :
7740 : 20 : CU_ASSERT(bserrno == 0);
7741 : :
7742 : : /* Verify that the first sync completion had a chance to execute */
7743 : 20 : rc = spdk_blob_get_xattr_value(blob, "sync", &value, &value_len);
7744 : 20 : CU_ASSERT(rc == 0);
7745 [ + + ]: 20 : SPDK_CU_ASSERT_FATAL(value != NULL);
7746 : 20 : CU_ASSERT(value_len == strlen("second") + 1);
7747 [ - + ]: 20 : CU_ASSERT_NSTRING_EQUAL_FATAL(value, "second", value_len);
7748 : :
7749 : 20 : CU_ASSERT(g_bserrno == -1);
7750 : 20 : g_bserrno = bserrno;
7751 : 20 : }
7752 : :
7753 : : static void
7754 : 20 : blob_simultaneous_operations(void)
7755 : : {
7756 : 20 : struct spdk_blob_store *bs = g_bs;
7757 : 15 : struct spdk_blob_opts opts;
7758 : : struct spdk_blob *blob, *snapshot;
7759 : : spdk_blob_id blobid, snapshotid;
7760 : : struct spdk_io_channel *channel;
7761 : : int rc;
7762 : :
7763 : 20 : channel = spdk_bs_alloc_io_channel(bs);
7764 [ + + ]: 20 : SPDK_CU_ASSERT_FATAL(channel != NULL);
7765 : :
7766 : 20 : ut_spdk_blob_opts_init(&opts);
7767 : 20 : opts.num_clusters = 10;
7768 : :
7769 : 20 : blob = ut_blob_create_and_open(bs, &opts);
7770 : 20 : blobid = spdk_blob_get_id(blob);
7771 : :
7772 : : /* Create snapshot and try to remove blob in the same time:
7773 : : * - snapshot should be created successfully
7774 : : * - delete operation should fail w -EBUSY */
7775 [ - + ]: 20 : CU_ASSERT(blob->locked_operation_in_progress == false);
7776 : 20 : spdk_bs_create_snapshot(bs, blobid, NULL, blob_op_with_id_complete, NULL);
7777 [ - + ]: 20 : CU_ASSERT(blob->locked_operation_in_progress == true);
7778 : 20 : spdk_bs_delete_blob(bs, blobid, blob_op_complete, NULL);
7779 [ - + ]: 20 : CU_ASSERT(blob->locked_operation_in_progress == true);
7780 : : /* Deletion failure */
7781 : 20 : CU_ASSERT(g_bserrno == -EBUSY);
7782 : 20 : poll_threads();
7783 [ - + ]: 20 : CU_ASSERT(blob->locked_operation_in_progress == false);
7784 : : /* Snapshot creation success */
7785 : 20 : CU_ASSERT(g_bserrno == 0);
7786 : 20 : CU_ASSERT(g_blobid != SPDK_BLOBID_INVALID);
7787 : :
7788 : 20 : snapshotid = g_blobid;
7789 : :
7790 : 20 : spdk_bs_open_blob(bs, snapshotid, blob_op_with_handle_complete, NULL);
7791 : 20 : poll_threads();
7792 : 20 : CU_ASSERT(g_bserrno == 0);
7793 [ - + ]: 20 : SPDK_CU_ASSERT_FATAL(g_blob != NULL);
7794 : 20 : snapshot = g_blob;
7795 : :
7796 : : /* Inflate blob and try to remove blob in the same time:
7797 : : * - blob should be inflated successfully
7798 : : * - delete operation should fail w -EBUSY */
7799 [ - + ]: 20 : CU_ASSERT(blob->locked_operation_in_progress == false);
7800 : 20 : spdk_bs_inflate_blob(bs, channel, blobid, blob_op_complete, NULL);
7801 [ - + ]: 20 : CU_ASSERT(blob->locked_operation_in_progress == true);
7802 : 20 : spdk_bs_delete_blob(bs, blobid, blob_op_complete, NULL);
7803 [ - + ]: 20 : CU_ASSERT(blob->locked_operation_in_progress == true);
7804 : : /* Deletion failure */
7805 : 20 : CU_ASSERT(g_bserrno == -EBUSY);
7806 : 20 : poll_threads();
7807 [ - + ]: 20 : CU_ASSERT(blob->locked_operation_in_progress == false);
7808 : : /* Inflation success */
7809 : 20 : CU_ASSERT(g_bserrno == 0);
7810 : :
7811 : : /* Clone snapshot and try to remove snapshot in the same time:
7812 : : * - snapshot should be cloned successfully
7813 : : * - delete operation should fail w -EBUSY */
7814 [ - + ]: 20 : CU_ASSERT(blob->locked_operation_in_progress == false);
7815 : 20 : spdk_bs_create_clone(bs, snapshotid, NULL, blob_op_with_id_complete, NULL);
7816 : 20 : spdk_bs_delete_blob(bs, snapshotid, blob_op_complete, NULL);
7817 : : /* Deletion failure */
7818 : 20 : CU_ASSERT(g_bserrno == -EBUSY);
7819 : 20 : poll_threads();
7820 [ - + ]: 20 : CU_ASSERT(blob->locked_operation_in_progress == false);
7821 : : /* Clone created */
7822 : 20 : CU_ASSERT(g_bserrno == 0);
7823 : :
7824 : : /* Resize blob and try to remove blob in the same time:
7825 : : * - blob should be resized successfully
7826 : : * - delete operation should fail w -EBUSY */
7827 [ - + ]: 20 : CU_ASSERT(blob->locked_operation_in_progress == false);
7828 : 20 : spdk_blob_resize(blob, 50, blob_op_complete, NULL);
7829 [ - + ]: 20 : CU_ASSERT(blob->locked_operation_in_progress == true);
7830 : 20 : spdk_bs_delete_blob(bs, blobid, blob_op_complete, NULL);
7831 [ - + ]: 20 : CU_ASSERT(blob->locked_operation_in_progress == true);
7832 : : /* Deletion failure */
7833 : 20 : CU_ASSERT(g_bserrno == -EBUSY);
7834 : 20 : poll_threads();
7835 [ - + ]: 20 : CU_ASSERT(blob->locked_operation_in_progress == false);
7836 : : /* Blob resized successfully */
7837 : 20 : spdk_blob_sync_md(blob, blob_op_complete, NULL);
7838 : 20 : poll_threads();
7839 : 20 : CU_ASSERT(g_bserrno == 0);
7840 : :
7841 : : /* Issue two consecutive blob syncs, neither should fail.
7842 : : * Force sync to actually occur by marking blob dirty each time.
7843 : : * Execution of sync should not be enough to complete the operation,
7844 : : * since disk I/O is required to complete it. */
7845 : 20 : g_bserrno = -1;
7846 : :
7847 : 20 : rc = spdk_blob_set_xattr(blob, "sync", "first", strlen("first") + 1);
7848 : 20 : CU_ASSERT(rc == 0);
7849 : 20 : spdk_blob_sync_md(blob, first_sync_complete, blob);
7850 : 20 : CU_ASSERT(g_bserrno == -1);
7851 : :
7852 : 20 : spdk_blob_sync_md(blob, second_sync_complete, blob);
7853 : 20 : CU_ASSERT(g_bserrno == -1);
7854 : :
7855 : 20 : poll_threads();
7856 : 20 : CU_ASSERT(g_bserrno == 0);
7857 : :
7858 : 20 : spdk_bs_free_io_channel(channel);
7859 : 20 : poll_threads();
7860 : :
7861 : 20 : ut_blob_close_and_delete(bs, snapshot);
7862 : 20 : ut_blob_close_and_delete(bs, blob);
7863 : 20 : }
7864 : :
7865 : : static void
7866 : 20 : blob_persist_test(void)
7867 : : {
7868 : 20 : struct spdk_blob_store *bs = g_bs;
7869 : 15 : struct spdk_blob_opts opts;
7870 : : struct spdk_blob *blob;
7871 : : spdk_blob_id blobid;
7872 : : struct spdk_io_channel *channel;
7873 : 15 : char *xattr;
7874 : 15 : size_t xattr_length;
7875 : : int rc;
7876 : : uint32_t page_count_clear, page_count_xattr;
7877 : : uint64_t poller_iterations;
7878 : : bool run_poller;
7879 : :
7880 : 20 : channel = spdk_bs_alloc_io_channel(bs);
7881 [ + + ]: 20 : SPDK_CU_ASSERT_FATAL(channel != NULL);
7882 : :
7883 : 20 : ut_spdk_blob_opts_init(&opts);
7884 : 20 : opts.num_clusters = 10;
7885 : :
7886 : 20 : blob = ut_blob_create_and_open(bs, &opts);
7887 : 20 : blobid = spdk_blob_get_id(blob);
7888 : :
7889 : : /* Save the amount of md pages used after creation of a blob.
7890 : : * This should be consistent after removing xattr. */
7891 : 20 : page_count_clear = spdk_bit_array_count_set(bs->used_md_pages);
7892 [ + + ]: 20 : SPDK_CU_ASSERT_FATAL(blob->active.num_pages + blob->active.num_extent_pages == page_count_clear);
7893 [ + + ]: 20 : SPDK_CU_ASSERT_FATAL(blob->clean.num_pages + blob->clean.num_extent_pages == page_count_clear);
7894 : :
7895 : : /* Add xattr with maximum length of descriptor to exceed single metadata page. */
7896 : 20 : xattr_length = SPDK_BS_MAX_DESC_SIZE - sizeof(struct spdk_blob_md_descriptor_xattr) -
7897 : : strlen("large_xattr");
7898 : 20 : xattr = calloc(xattr_length, sizeof(char));
7899 [ + + ]: 20 : SPDK_CU_ASSERT_FATAL(xattr != NULL);
7900 : :
7901 : 20 : rc = spdk_blob_set_xattr(blob, "large_xattr", xattr, xattr_length);
7902 [ + + ]: 20 : SPDK_CU_ASSERT_FATAL(rc == 0);
7903 : 20 : spdk_blob_sync_md(blob, blob_op_complete, NULL);
7904 : 20 : poll_threads();
7905 [ + + ]: 20 : SPDK_CU_ASSERT_FATAL(g_bserrno == 0);
7906 : :
7907 : : /* Save the amount of md pages used after adding the large xattr */
7908 : 20 : page_count_xattr = spdk_bit_array_count_set(bs->used_md_pages);
7909 [ + + ]: 20 : SPDK_CU_ASSERT_FATAL(blob->active.num_pages + blob->active.num_extent_pages == page_count_xattr);
7910 [ - + ]: 20 : SPDK_CU_ASSERT_FATAL(blob->clean.num_pages + blob->clean.num_extent_pages == page_count_xattr);
7911 : :
7912 : : /* Add xattr to a blob and sync it. While sync is occurring, remove the xattr and sync again.
7913 : : * Interrupt the first sync after increasing number of poller iterations, until it succeeds.
7914 : : * Expectation is that after second sync completes no xattr is saved in metadata. */
7915 : 20 : poller_iterations = 1;
7916 : 20 : run_poller = true;
7917 [ + + ]: 140 : while (run_poller) {
7918 : 120 : rc = spdk_blob_set_xattr(blob, "large_xattr", xattr, xattr_length);
7919 [ + + ]: 120 : SPDK_CU_ASSERT_FATAL(rc == 0);
7920 : 120 : g_bserrno = -1;
7921 : 120 : spdk_blob_sync_md(blob, blob_op_complete, NULL);
7922 : 120 : poll_thread_times(0, poller_iterations);
7923 [ + + ]: 120 : if (g_bserrno == 0) {
7924 : : /* Poller iteration count was high enough for first sync to complete.
7925 : : * Verify that blob takes up enough of md_pages to store the xattr. */
7926 [ + + ]: 20 : SPDK_CU_ASSERT_FATAL(blob->active.num_pages + blob->active.num_extent_pages == page_count_xattr);
7927 [ + + ]: 20 : SPDK_CU_ASSERT_FATAL(blob->clean.num_pages + blob->clean.num_extent_pages == page_count_xattr);
7928 [ + + ]: 20 : SPDK_CU_ASSERT_FATAL(spdk_bit_array_count_set(bs->used_md_pages) == page_count_xattr);
7929 : 20 : run_poller = false;
7930 : 5 : }
7931 : 120 : rc = spdk_blob_remove_xattr(blob, "large_xattr");
7932 [ + + ]: 120 : SPDK_CU_ASSERT_FATAL(rc == 0);
7933 : 120 : spdk_blob_sync_md(blob, blob_op_complete, NULL);
7934 : 120 : poll_threads();
7935 [ + + ]: 120 : SPDK_CU_ASSERT_FATAL(g_bserrno == 0);
7936 [ + + ]: 120 : SPDK_CU_ASSERT_FATAL(blob->active.num_pages + blob->active.num_extent_pages == page_count_clear);
7937 [ + + ]: 120 : SPDK_CU_ASSERT_FATAL(blob->clean.num_pages + blob->clean.num_extent_pages == page_count_clear);
7938 [ + + ]: 120 : SPDK_CU_ASSERT_FATAL(spdk_bit_array_count_set(bs->used_md_pages) == page_count_clear);
7939 : :
7940 : : /* Reload bs and re-open blob to verify that xattr was not persisted. */
7941 : 120 : spdk_blob_close(blob, blob_op_complete, NULL);
7942 : 120 : poll_threads();
7943 : 120 : CU_ASSERT(g_bserrno == 0);
7944 : :
7945 : 120 : ut_bs_reload(&bs, NULL);
7946 : :
7947 : 120 : spdk_bs_open_blob(bs, blobid, blob_op_with_handle_complete, NULL);
7948 : 120 : poll_threads();
7949 : 120 : CU_ASSERT(g_bserrno == 0);
7950 [ + + ]: 120 : SPDK_CU_ASSERT_FATAL(g_blob != NULL);
7951 : 120 : blob = g_blob;
7952 : :
7953 : 120 : rc = spdk_blob_get_xattr_value(blob, "large_xattr", (const void **)&xattr, &xattr_length);
7954 [ + + ]: 120 : SPDK_CU_ASSERT_FATAL(rc == -ENOENT);
7955 : :
7956 : 120 : poller_iterations++;
7957 : : /* Stop at high iteration count to prevent infinite loop.
7958 : : * This value should be enough for first md sync to complete in any case. */
7959 [ + + ]: 120 : SPDK_CU_ASSERT_FATAL(poller_iterations < 50);
7960 : : }
7961 : :
7962 : 20 : free(xattr);
7963 : :
7964 : 20 : ut_blob_close_and_delete(bs, blob);
7965 : :
7966 : 20 : spdk_bs_free_io_channel(channel);
7967 : 20 : poll_threads();
7968 : 20 : }
7969 : :
7970 : : static void
7971 : 20 : blob_decouple_snapshot(void)
7972 : : {
7973 : 20 : struct spdk_blob_store *bs = g_bs;
7974 : 15 : struct spdk_blob_opts opts;
7975 : : struct spdk_blob *blob, *snapshot1, *snapshot2;
7976 : : struct spdk_io_channel *channel;
7977 : : spdk_blob_id blobid, snapshotid;
7978 : : uint64_t cluster;
7979 : :
7980 [ + + ]: 60 : for (int delete_snapshot_first = 0; delete_snapshot_first <= 1; delete_snapshot_first++) {
7981 : 40 : channel = spdk_bs_alloc_io_channel(bs);
7982 [ + + ]: 40 : SPDK_CU_ASSERT_FATAL(channel != NULL);
7983 : :
7984 : 40 : ut_spdk_blob_opts_init(&opts);
7985 : 40 : opts.num_clusters = 10;
7986 : 40 : opts.thin_provision = false;
7987 : :
7988 : 40 : blob = ut_blob_create_and_open(bs, &opts);
7989 : 40 : blobid = spdk_blob_get_id(blob);
7990 : :
7991 : : /* Create first snapshot */
7992 : 40 : CU_ASSERT_EQUAL(_get_snapshots_count(bs), 0);
7993 : 40 : spdk_bs_create_snapshot(bs, blobid, NULL, blob_op_with_id_complete, NULL);
7994 : 40 : poll_threads();
7995 : 40 : CU_ASSERT(g_bserrno == 0);
7996 : 40 : CU_ASSERT(g_blobid != SPDK_BLOBID_INVALID);
7997 : 40 : CU_ASSERT_EQUAL(_get_snapshots_count(bs), 1);
7998 : 40 : snapshotid = g_blobid;
7999 : :
8000 : 40 : spdk_bs_open_blob(bs, snapshotid, blob_op_with_handle_complete, NULL);
8001 : 40 : poll_threads();
8002 : 40 : CU_ASSERT(g_bserrno == 0);
8003 [ - + ]: 40 : SPDK_CU_ASSERT_FATAL(g_blob != NULL);
8004 : 40 : snapshot1 = g_blob;
8005 : :
8006 : : /* Create the second one */
8007 : 40 : CU_ASSERT_EQUAL(_get_snapshots_count(bs), 1);
8008 : 40 : spdk_bs_create_snapshot(bs, blobid, NULL, blob_op_with_id_complete, NULL);
8009 : 40 : poll_threads();
8010 : 40 : CU_ASSERT(g_bserrno == 0);
8011 : 40 : CU_ASSERT(g_blobid != SPDK_BLOBID_INVALID);
8012 : 40 : CU_ASSERT_EQUAL(_get_snapshots_count(bs), 2);
8013 : 40 : snapshotid = g_blobid;
8014 : :
8015 : 40 : spdk_bs_open_blob(bs, snapshotid, blob_op_with_handle_complete, NULL);
8016 : 40 : poll_threads();
8017 : 40 : CU_ASSERT(g_bserrno == 0);
8018 [ - + ]: 40 : SPDK_CU_ASSERT_FATAL(g_blob != NULL);
8019 : 40 : snapshot2 = g_blob;
8020 : 40 : CU_ASSERT_EQUAL(spdk_blob_get_parent_snapshot(bs, snapshot2->id), snapshot1->id);
8021 : :
8022 : : /* Now decouple the second snapshot forcing it to copy the written clusters */
8023 : 40 : spdk_bs_blob_decouple_parent(bs, channel, snapshot2->id, blob_op_complete, NULL);
8024 : 40 : poll_threads();
8025 : 40 : CU_ASSERT(g_bserrno == 0);
8026 : :
8027 : : /* Verify that the snapshot has been decoupled and that the clusters have been copied */
8028 : 40 : CU_ASSERT_EQUAL(spdk_blob_get_parent_snapshot(bs, snapshot2->id), SPDK_BLOBID_INVALID);
8029 [ + + ]: 440 : for (cluster = 0; cluster < snapshot2->active.num_clusters; ++cluster) {
8030 : 400 : CU_ASSERT_NOT_EQUAL(snapshot2->active.clusters[cluster], 0);
8031 : 400 : CU_ASSERT_NOT_EQUAL(snapshot2->active.clusters[cluster],
8032 : : snapshot1->active.clusters[cluster]);
8033 : 100 : }
8034 : :
8035 : 40 : spdk_bs_free_io_channel(channel);
8036 : :
8037 [ + + ]: 40 : if (delete_snapshot_first) {
8038 : 20 : ut_blob_close_and_delete(bs, snapshot2);
8039 : 20 : ut_blob_close_and_delete(bs, snapshot1);
8040 : 20 : ut_blob_close_and_delete(bs, blob);
8041 : 5 : } else {
8042 : 20 : ut_blob_close_and_delete(bs, blob);
8043 : 20 : ut_blob_close_and_delete(bs, snapshot2);
8044 : 20 : ut_blob_close_and_delete(bs, snapshot1);
8045 : : }
8046 : 40 : poll_threads();
8047 : 10 : }
8048 : 20 : }
8049 : :
8050 : : static void
8051 : 20 : blob_seek_io_unit(void)
8052 : : {
8053 : 20 : struct spdk_blob_store *bs = g_bs;
8054 : : struct spdk_blob *blob;
8055 : : struct spdk_io_channel *channel;
8056 : 15 : struct spdk_blob_opts opts;
8057 : : uint64_t free_clusters;
8058 : 15 : uint8_t payload[10 * BLOCKLEN];
8059 : : uint64_t offset;
8060 : : uint64_t io_unit, io_units_per_cluster;
8061 : :
8062 : 20 : free_clusters = spdk_bs_free_cluster_count(bs);
8063 : :
8064 : 20 : channel = spdk_bs_alloc_io_channel(bs);
8065 : 20 : CU_ASSERT(channel != NULL);
8066 : :
8067 : : /* Set blob as thin provisioned */
8068 : 20 : ut_spdk_blob_opts_init(&opts);
8069 : 20 : opts.thin_provision = true;
8070 : :
8071 : : /* Create a blob */
8072 : 20 : blob = ut_blob_create_and_open(bs, &opts);
8073 : 20 : CU_ASSERT(free_clusters == spdk_bs_free_cluster_count(bs));
8074 : :
8075 : 20 : io_units_per_cluster = bs_io_units_per_cluster(blob);
8076 : :
8077 : : /* The blob started at 0 clusters. Resize it to be 5, but still unallocated. */
8078 : 20 : spdk_blob_resize(blob, 5, blob_op_complete, NULL);
8079 : 20 : poll_threads();
8080 : 20 : CU_ASSERT(g_bserrno == 0);
8081 : 20 : CU_ASSERT(free_clusters == spdk_bs_free_cluster_count(bs));
8082 : 20 : CU_ASSERT(blob->active.num_clusters == 5);
8083 : :
8084 : : /* Write at the beginning of first cluster */
8085 : 20 : offset = 0;
8086 : 20 : spdk_blob_io_write(blob, channel, payload, offset, 1, blob_op_complete, NULL);
8087 : 20 : poll_threads();
8088 : 20 : CU_ASSERT(g_bserrno == 0);
8089 : :
8090 : 20 : io_unit = spdk_blob_get_next_allocated_io_unit(blob, 0);
8091 : 20 : CU_ASSERT(io_unit == offset);
8092 : :
8093 : 20 : io_unit = spdk_blob_get_next_unallocated_io_unit(blob, 0);
8094 : 20 : CU_ASSERT(io_unit == io_units_per_cluster);
8095 : :
8096 : : /* Write in the middle of third cluster */
8097 : 20 : offset = 2 * io_units_per_cluster + io_units_per_cluster / 2;
8098 : 20 : spdk_blob_io_write(blob, channel, payload, offset, 1, blob_op_complete, NULL);
8099 : 20 : poll_threads();
8100 : 20 : CU_ASSERT(g_bserrno == 0);
8101 : :
8102 : 20 : io_unit = spdk_blob_get_next_allocated_io_unit(blob, io_units_per_cluster);
8103 : 20 : CU_ASSERT(io_unit == 2 * io_units_per_cluster);
8104 : :
8105 : 20 : io_unit = spdk_blob_get_next_unallocated_io_unit(blob, 2 * io_units_per_cluster);
8106 : 20 : CU_ASSERT(io_unit == 3 * io_units_per_cluster);
8107 : :
8108 : : /* Write at the end of last cluster */
8109 : 20 : offset = 5 * io_units_per_cluster - 1;
8110 : 20 : spdk_blob_io_write(blob, channel, payload, offset, 1, blob_op_complete, NULL);
8111 : 20 : poll_threads();
8112 : 20 : CU_ASSERT(g_bserrno == 0);
8113 : :
8114 : 20 : io_unit = spdk_blob_get_next_allocated_io_unit(blob, 3 * io_units_per_cluster);
8115 : 20 : CU_ASSERT(io_unit == 4 * io_units_per_cluster);
8116 : :
8117 : 20 : io_unit = spdk_blob_get_next_unallocated_io_unit(blob, 4 * io_units_per_cluster);
8118 : 20 : CU_ASSERT(io_unit == UINT64_MAX);
8119 : :
8120 : 20 : spdk_bs_free_io_channel(channel);
8121 : 20 : poll_threads();
8122 : :
8123 : 20 : ut_blob_close_and_delete(bs, blob);
8124 : 20 : }
8125 : :
8126 : : static void
8127 : 20 : blob_esnap_create(void)
8128 : : {
8129 : 20 : struct spdk_blob_store *bs = g_bs;
8130 : 15 : struct spdk_bs_opts bs_opts;
8131 : 15 : struct ut_esnap_opts esnap_opts;
8132 : 15 : struct spdk_blob_opts opts;
8133 : 15 : struct spdk_blob_open_opts open_opts;
8134 : : struct spdk_blob *blob;
8135 : : uint32_t cluster_sz, block_sz;
8136 : 20 : const uint32_t esnap_num_clusters = 4;
8137 : : uint64_t esnap_num_blocks;
8138 : : uint32_t sz;
8139 : : spdk_blob_id blobid;
8140 : 15 : uint32_t bs_ctx_count, blob_ctx_count;
8141 : :
8142 : 20 : cluster_sz = spdk_bs_get_cluster_size(bs);
8143 : 20 : block_sz = spdk_bs_get_io_unit_size(bs);
8144 [ - + ]: 20 : esnap_num_blocks = cluster_sz * esnap_num_clusters / block_sz;
8145 : :
8146 : : /* Create a normal blob and verify it is not an esnap clone. */
8147 : 20 : ut_spdk_blob_opts_init(&opts);
8148 : 20 : blob = ut_blob_create_and_open(bs, &opts);
8149 : 20 : CU_ASSERT(!spdk_blob_is_esnap_clone(blob));
8150 : 20 : ut_blob_close_and_delete(bs, blob);
8151 : :
8152 : : /* Create an esnap clone blob then verify it is an esnap clone and has the right size */
8153 : 20 : ut_spdk_blob_opts_init(&opts);
8154 : 20 : ut_esnap_opts_init(block_sz, esnap_num_blocks, __func__, NULL, &esnap_opts);
8155 : 20 : opts.esnap_id = &esnap_opts;
8156 : 20 : opts.esnap_id_len = sizeof(esnap_opts);
8157 : 20 : opts.num_clusters = esnap_num_clusters;
8158 : 20 : blob = ut_blob_create_and_open(bs, &opts);
8159 [ + + ]: 20 : SPDK_CU_ASSERT_FATAL(blob != NULL);
8160 [ + + ]: 20 : SPDK_CU_ASSERT_FATAL(spdk_blob_is_esnap_clone(blob));
8161 [ + + ]: 20 : SPDK_CU_ASSERT_FATAL(blob_is_esnap_clone(blob));
8162 [ + + ]: 20 : SPDK_CU_ASSERT_FATAL(!spdk_blob_is_clone(blob));
8163 : 20 : sz = spdk_blob_get_num_clusters(blob);
8164 : 20 : CU_ASSERT(sz == esnap_num_clusters);
8165 : 20 : ut_blob_close_and_delete(bs, blob);
8166 : :
8167 : : /* Create an esnap clone without the size and verify it can be grown */
8168 : 20 : ut_spdk_blob_opts_init(&opts);
8169 : 20 : ut_esnap_opts_init(block_sz, esnap_num_blocks, __func__, NULL, &esnap_opts);
8170 : 20 : opts.esnap_id = &esnap_opts;
8171 : 20 : opts.esnap_id_len = sizeof(esnap_opts);
8172 : 20 : blob = ut_blob_create_and_open(bs, &opts);
8173 [ + + ]: 20 : SPDK_CU_ASSERT_FATAL(spdk_blob_is_esnap_clone(blob));
8174 : 20 : sz = spdk_blob_get_num_clusters(blob);
8175 : 20 : CU_ASSERT(sz == 0);
8176 : 20 : spdk_blob_resize(blob, 1, blob_op_complete, NULL);
8177 : 20 : poll_threads();
8178 : 20 : CU_ASSERT(g_bserrno == 0);
8179 : 20 : sz = spdk_blob_get_num_clusters(blob);
8180 : 20 : CU_ASSERT(sz == 1);
8181 : 20 : spdk_blob_resize(blob, esnap_num_clusters, blob_op_complete, NULL);
8182 : 20 : poll_threads();
8183 : 20 : CU_ASSERT(g_bserrno == 0);
8184 : 20 : sz = spdk_blob_get_num_clusters(blob);
8185 : 20 : CU_ASSERT(sz == esnap_num_clusters);
8186 : 20 : spdk_blob_resize(blob, esnap_num_clusters + 1, blob_op_complete, NULL);
8187 : 20 : poll_threads();
8188 : 20 : CU_ASSERT(g_bserrno == 0);
8189 : 20 : sz = spdk_blob_get_num_clusters(blob);
8190 : 20 : CU_ASSERT(sz == esnap_num_clusters + 1);
8191 : :
8192 : : /* Reload the blobstore and be sure that the blob can be opened. */
8193 : 20 : blobid = spdk_blob_get_id(blob);
8194 : 20 : spdk_blob_close(blob, blob_op_complete, NULL);
8195 : 20 : poll_threads();
8196 : 20 : CU_ASSERT(g_bserrno == 0);
8197 : 20 : g_blob = NULL;
8198 : 20 : spdk_bs_opts_init(&bs_opts, sizeof(bs_opts));
8199 : 20 : bs_opts.esnap_bs_dev_create = ut_esnap_create;
8200 : 20 : ut_bs_reload(&bs, &bs_opts);
8201 : 20 : spdk_bs_open_blob(bs, blobid, blob_op_with_handle_complete, NULL);
8202 : 20 : poll_threads();
8203 : 20 : CU_ASSERT(g_bserrno == 0);
8204 : 20 : CU_ASSERT(g_blob != NULL);
8205 : 20 : blob = g_blob;
8206 [ + + ]: 20 : SPDK_CU_ASSERT_FATAL(spdk_blob_is_esnap_clone(blob));
8207 : 20 : sz = spdk_blob_get_num_clusters(blob);
8208 : 20 : CU_ASSERT(sz == esnap_num_clusters + 1);
8209 : :
8210 : : /* Reload the blobstore without esnap_bs_dev_create: should fail to open blob. */
8211 : 20 : spdk_blob_close(blob, blob_op_complete, NULL);
8212 : 20 : poll_threads();
8213 : 20 : CU_ASSERT(g_bserrno == 0);
8214 : 20 : g_blob = NULL;
8215 : 20 : spdk_bs_opts_init(&bs_opts, sizeof(bs_opts));
8216 : 20 : ut_bs_reload(&bs, &bs_opts);
8217 : 20 : spdk_bs_open_blob(bs, blobid, blob_op_with_handle_complete, NULL);
8218 : 20 : poll_threads();
8219 : 20 : CU_ASSERT(g_bserrno != 0);
8220 : 20 : CU_ASSERT(g_blob == NULL);
8221 : :
8222 : : /* Reload the blobstore with ctx set and verify it is passed to the esnap create callback */
8223 : 20 : bs_ctx_count = 0;
8224 : 20 : spdk_bs_opts_init(&bs_opts, sizeof(bs_opts));
8225 : 20 : bs_opts.esnap_bs_dev_create = ut_esnap_create_with_count;
8226 : 20 : bs_opts.esnap_ctx = &bs_ctx_count;
8227 : 20 : ut_bs_reload(&bs, &bs_opts);
8228 : : /* Loading the blobstore triggers the esnap to be loaded */
8229 : 20 : CU_ASSERT(bs_ctx_count == 1);
8230 : 20 : spdk_bs_open_blob(bs, blobid, blob_op_with_handle_complete, NULL);
8231 : 20 : poll_threads();
8232 : 20 : CU_ASSERT(g_bserrno == 0);
8233 : 20 : CU_ASSERT(g_blob != NULL);
8234 : : /* Opening the blob also triggers the esnap to be loaded */
8235 : 20 : CU_ASSERT(bs_ctx_count == 2);
8236 : 20 : blob = g_blob;
8237 [ - + ]: 20 : SPDK_CU_ASSERT_FATAL(spdk_blob_is_esnap_clone(blob));
8238 : 20 : sz = spdk_blob_get_num_clusters(blob);
8239 : 20 : CU_ASSERT(sz == esnap_num_clusters + 1);
8240 : 20 : spdk_blob_close(blob, blob_op_complete, NULL);
8241 : 20 : poll_threads();
8242 : 20 : CU_ASSERT(g_bserrno == 0);
8243 : 20 : g_blob = NULL;
8244 : : /* If open_opts.esnap_ctx is set it is passed to the esnap create callback */
8245 : 20 : blob_ctx_count = 0;
8246 : 20 : spdk_blob_open_opts_init(&open_opts, sizeof(open_opts));
8247 : 20 : open_opts.esnap_ctx = &blob_ctx_count;
8248 : 20 : spdk_bs_open_blob_ext(bs, blobid, &open_opts, blob_op_with_handle_complete, NULL);
8249 : 20 : poll_threads();
8250 : 20 : blob = g_blob;
8251 : 20 : CU_ASSERT(bs_ctx_count == 3);
8252 : 20 : CU_ASSERT(blob_ctx_count == 1);
8253 : 20 : spdk_blob_close(blob, blob_op_complete, NULL);
8254 : 20 : poll_threads();
8255 : 20 : CU_ASSERT(g_bserrno == 0);
8256 : 20 : g_blob = NULL;
8257 : 20 : }
8258 : :
8259 : : static void
8260 : 20 : blob_esnap_clone_reload(void)
8261 : 15 : {
8262 : 20 : struct spdk_blob_store *bs = g_bs;
8263 : 15 : struct spdk_bs_opts bs_opts;
8264 : 15 : struct ut_esnap_opts esnap_opts;
8265 : 15 : struct spdk_blob_opts opts;
8266 : : struct spdk_blob *eclone1, *snap1, *clone1;
8267 : 20 : uint32_t cluster_sz = spdk_bs_get_cluster_size(bs);
8268 : 20 : uint32_t block_sz = spdk_bs_get_io_unit_size(bs);
8269 : 20 : const uint32_t esnap_num_clusters = 4;
8270 [ - + ]: 20 : uint64_t esnap_num_blocks = cluster_sz * esnap_num_clusters / block_sz;
8271 : : spdk_blob_id eclone1_id, snap1_id, clone1_id;
8272 : : struct spdk_io_channel *bs_ch;
8273 [ - + ]: 20 : char buf[block_sz];
8274 : 15 : int bserr1, bserr2, bserr3, bserr4;
8275 : : struct spdk_bs_dev *dev;
8276 : :
8277 : : /* Create and open an esnap clone blob */
8278 : 20 : ut_spdk_blob_opts_init(&opts);
8279 : 20 : ut_esnap_opts_init(block_sz, esnap_num_blocks, __func__, NULL, &esnap_opts);
8280 : 20 : opts.esnap_id = &esnap_opts;
8281 : 20 : opts.esnap_id_len = sizeof(esnap_opts);
8282 : 20 : opts.num_clusters = esnap_num_clusters;
8283 : 20 : eclone1 = ut_blob_create_and_open(bs, &opts);
8284 : 20 : CU_ASSERT(eclone1 != NULL);
8285 : 20 : CU_ASSERT(spdk_blob_is_esnap_clone(eclone1));
8286 : 20 : eclone1_id = eclone1->id;
8287 : :
8288 : : /* Create and open a snapshot of eclone1 */
8289 : 20 : spdk_bs_create_snapshot(bs, eclone1_id, NULL, blob_op_with_id_complete, NULL);
8290 : 20 : poll_threads();
8291 : 20 : CU_ASSERT(g_blobid != SPDK_BLOBID_INVALID);
8292 : 20 : CU_ASSERT(g_bserrno == 0);
8293 : 20 : snap1_id = g_blobid;
8294 : 20 : spdk_bs_open_blob(bs, snap1_id, blob_op_with_handle_complete, NULL);
8295 : 20 : poll_threads();
8296 : 20 : CU_ASSERT(g_bserrno == 0);
8297 : 20 : CU_ASSERT(g_blob != NULL);
8298 : 20 : snap1 = g_blob;
8299 : :
8300 : : /* Create and open regular clone of snap1 */
8301 : 20 : spdk_bs_create_clone(bs, snap1_id, NULL, blob_op_with_id_complete, NULL);
8302 : 20 : poll_threads();
8303 : 20 : CU_ASSERT(g_blobid != SPDK_BLOBID_INVALID);
8304 [ + + ]: 20 : SPDK_CU_ASSERT_FATAL(g_bserrno == 0);
8305 : 20 : clone1_id = g_blobid;
8306 : 20 : spdk_bs_open_blob(bs, clone1_id, blob_op_with_handle_complete, NULL);
8307 : 20 : poll_threads();
8308 : 20 : CU_ASSERT(g_bserrno == 0);
8309 : 20 : CU_ASSERT(g_blob != NULL);
8310 : 20 : clone1 = g_blob;
8311 : :
8312 : : /* Close the blobs in preparation for reloading the blobstore */
8313 : 20 : spdk_blob_close(clone1, blob_op_complete, NULL);
8314 : 20 : poll_threads();
8315 : 20 : CU_ASSERT(g_bserrno == 0);
8316 : 20 : spdk_blob_close(snap1, blob_op_complete, NULL);
8317 : 20 : poll_threads();
8318 : 20 : CU_ASSERT(g_bserrno == 0);
8319 : 20 : spdk_blob_close(eclone1, blob_op_complete, NULL);
8320 : 20 : poll_threads();
8321 : 20 : CU_ASSERT(g_bserrno == 0);
8322 : 20 : g_blob = NULL;
8323 : :
8324 : : /* Reload the blobstore */
8325 : 20 : spdk_bs_opts_init(&bs_opts, sizeof(bs_opts));
8326 : 20 : bs_opts.esnap_bs_dev_create = ut_esnap_create;
8327 : 20 : ut_bs_reload(&bs, &bs_opts);
8328 : :
8329 : : /* Be sure each of the blobs can be opened */
8330 : 20 : spdk_bs_open_blob(bs, eclone1_id, blob_op_with_handle_complete, NULL);
8331 : 20 : poll_threads();
8332 : 20 : CU_ASSERT(g_bserrno == 0);
8333 : 20 : CU_ASSERT(g_blob != NULL);
8334 : 20 : eclone1 = g_blob;
8335 : 20 : spdk_bs_open_blob(bs, snap1_id, blob_op_with_handle_complete, NULL);
8336 : 20 : poll_threads();
8337 : 20 : CU_ASSERT(g_bserrno == 0);
8338 : 20 : CU_ASSERT(g_blob != NULL);
8339 : 20 : snap1 = g_blob;
8340 : 20 : spdk_bs_open_blob(bs, clone1_id, blob_op_with_handle_complete, NULL);
8341 : 20 : poll_threads();
8342 : 20 : CU_ASSERT(g_bserrno == 0);
8343 : 20 : CU_ASSERT(g_blob != NULL);
8344 : 20 : clone1 = g_blob;
8345 : :
8346 : : /* Perform some reads on each of them to cause channels to be allocated */
8347 : 20 : bs_ch = spdk_bs_alloc_io_channel(bs);
8348 : 20 : CU_ASSERT(bs_ch != NULL);
8349 : 20 : spdk_blob_io_read(eclone1, bs_ch, buf, 0, 1, bs_op_complete, NULL);
8350 : 20 : poll_threads();
8351 : 20 : CU_ASSERT(g_bserrno == 0);
8352 : 20 : spdk_blob_io_read(snap1, bs_ch, buf, 0, 1, bs_op_complete, NULL);
8353 : 20 : poll_threads();
8354 : 20 : CU_ASSERT(g_bserrno == 0);
8355 : 20 : spdk_blob_io_read(clone1, bs_ch, buf, 0, 1, bs_op_complete, NULL);
8356 : 20 : poll_threads();
8357 : 20 : CU_ASSERT(g_bserrno == 0);
8358 : :
8359 : : /*
8360 : : * Unload the blobstore in a way similar to how lvstore unloads it. This should exercise
8361 : : * the deferred unload path in spdk_bs_unload().
8362 : : */
8363 : 20 : bserr1 = 0xbad;
8364 : 20 : bserr2 = 0xbad;
8365 : 20 : bserr3 = 0xbad;
8366 : 20 : bserr4 = 0xbad;
8367 : 20 : spdk_blob_close(eclone1, blob_op_complete, &bserr1);
8368 : 20 : spdk_blob_close(snap1, blob_op_complete, &bserr2);
8369 : 20 : spdk_blob_close(clone1, blob_op_complete, &bserr3);
8370 : 20 : spdk_bs_unload(bs, blob_op_complete, &bserr4);
8371 : 20 : spdk_bs_free_io_channel(bs_ch);
8372 : 20 : poll_threads();
8373 : 20 : CU_ASSERT(bserr1 == 0);
8374 : 20 : CU_ASSERT(bserr2 == 0);
8375 : 20 : CU_ASSERT(bserr3 == 0);
8376 : 20 : CU_ASSERT(bserr4 == 0);
8377 : 20 : g_blob = NULL;
8378 : :
8379 : : /* Reload the blobstore */
8380 : 20 : spdk_bs_opts_init(&bs_opts, sizeof(bs_opts));
8381 : 20 : bs_opts.esnap_bs_dev_create = ut_esnap_create;
8382 : 20 : dev = init_dev();
8383 : 20 : spdk_bs_load(dev, &bs_opts, bs_op_with_handle_complete, NULL);
8384 : 20 : poll_threads();
8385 : 20 : CU_ASSERT(g_bserrno == 0);
8386 [ - + ]: 20 : SPDK_CU_ASSERT_FATAL(g_bs != NULL);
8387 : 20 : }
8388 : :
8389 : : static bool
8390 : 400 : blob_esnap_verify_contents(struct spdk_blob *blob, struct spdk_io_channel *ch,
8391 : : uint64_t offset, uint64_t size, uint32_t readsize, const char *how)
8392 : 300 : {
8393 : 400 : const uint32_t bs_blksz = blob->bs->io_unit_size;
8394 [ + + ]: 400 : const uint32_t esnap_blksz = blob->back_bs_dev ? blob->back_bs_dev->blocklen : bs_blksz;
8395 [ - + ]: 400 : const uint32_t start_blk = offset / bs_blksz;
8396 [ + + ]: 400 : const uint32_t num_blocks = spdk_max(size, readsize) / bs_blksz;
8397 [ - + ]: 400 : const uint32_t blocks_per_read = spdk_min(size, readsize) / bs_blksz;
8398 : : uint32_t blob_block;
8399 : 300 : struct iovec iov;
8400 [ - + ]: 400 : uint8_t buf[spdk_min(size, readsize)];
8401 : : bool block_ok;
8402 : :
8403 [ + + - + ]: 400 : SPDK_CU_ASSERT_FATAL(offset % bs_blksz == 0);
8404 [ + + - + ]: 400 : SPDK_CU_ASSERT_FATAL(size % bs_blksz == 0);
8405 [ - + - + ]: 400 : SPDK_CU_ASSERT_FATAL(readsize % bs_blksz == 0);
8406 : :
8407 [ - + ]: 400 : memset(buf, 0, readsize);
8408 : 400 : iov.iov_base = buf;
8409 : 400 : iov.iov_len = readsize;
8410 [ + + ]: 15980 : for (blob_block = start_blk; blob_block < num_blocks; blob_block += blocks_per_read) {
8411 [ + + + + ]: 15580 : if (strcmp(how, "read") == 0) {
8412 : 5220 : spdk_blob_io_read(blob, ch, buf, blob_block, blocks_per_read,
8413 : : bs_op_complete, NULL);
8414 [ + + + + ]: 11665 : } else if (strcmp(how, "readv") == 0) {
8415 : 5180 : spdk_blob_io_readv(blob, ch, &iov, 1, blob_block, blocks_per_read,
8416 : : bs_op_complete, NULL);
8417 [ + + + - ]: 6475 : } else if (strcmp(how, "readv_ext") == 0) {
8418 : : /*
8419 : : * This is currently pointless. NULL ext_opts leads to dev->readv(), not
8420 : : * dev->readv_ext().
8421 : : */
8422 : 5180 : spdk_blob_io_readv_ext(blob, ch, &iov, 1, blob_block, blocks_per_read,
8423 : : bs_op_complete, NULL, NULL);
8424 : 1295 : } else {
8425 : 0 : abort();
8426 : : }
8427 : 15580 : poll_threads();
8428 : 15580 : CU_ASSERT(g_bserrno == 0);
8429 [ + + ]: 15580 : if (g_bserrno != 0) {
8430 : 0 : return false;
8431 : : }
8432 : 19475 : block_ok = ut_esnap_content_is_correct(buf, blocks_per_read * bs_blksz, blob->id,
8433 : 3895 : blob_block * bs_blksz, esnap_blksz);
8434 : 15580 : CU_ASSERT(block_ok);
8435 [ + + ]: 15580 : if (!block_ok) {
8436 : 0 : return false;
8437 : : }
8438 : 3895 : }
8439 : :
8440 : 400 : return true;
8441 : 100 : }
8442 : :
8443 : : static void
8444 : 60 : blob_esnap_io_size(uint32_t bs_blksz, uint32_t esnap_blksz)
8445 : : {
8446 : : struct spdk_bs_dev *dev;
8447 : : struct spdk_blob_store *bs;
8448 : 45 : struct spdk_bs_opts bsopts;
8449 : 45 : struct spdk_blob_opts opts;
8450 : 45 : struct ut_esnap_opts esnap_opts;
8451 : : struct spdk_blob *blob;
8452 : 60 : const uint32_t cluster_sz = 4 * g_phys_blocklen;
8453 : 60 : const uint64_t esnap_num_clusters = 4;
8454 : 60 : const uint32_t esnap_sz = cluster_sz * esnap_num_clusters;
8455 [ - + ]: 60 : const uint64_t esnap_num_blocks = esnap_sz / esnap_blksz;
8456 [ - + ]: 60 : const uint64_t blob_num_blocks = esnap_sz / bs_blksz;
8457 : : uint32_t block;
8458 : : struct spdk_io_channel *bs_ch;
8459 : :
8460 : 60 : spdk_bs_opts_init(&bsopts, sizeof(bsopts));
8461 : 60 : bsopts.cluster_sz = cluster_sz;
8462 : 60 : bsopts.esnap_bs_dev_create = ut_esnap_create;
8463 : :
8464 : : /* Create device with desired block size */
8465 : 60 : dev = init_dev();
8466 : 60 : dev->blocklen = bs_blksz;
8467 [ - + ]: 60 : dev->blockcnt = DEV_BUFFER_SIZE / dev->blocklen;
8468 : :
8469 : : /* Initialize a new blob store */
8470 : 60 : spdk_bs_init(dev, &bsopts, bs_op_with_handle_complete, NULL);
8471 : 60 : poll_threads();
8472 : 60 : CU_ASSERT(g_bserrno == 0);
8473 [ + + ]: 60 : SPDK_CU_ASSERT_FATAL(g_bs != NULL);
8474 [ + + ]: 60 : SPDK_CU_ASSERT_FATAL(g_bs->io_unit_size == bs_blksz);
8475 : 60 : bs = g_bs;
8476 : :
8477 : 60 : bs_ch = spdk_bs_alloc_io_channel(bs);
8478 [ + + ]: 60 : SPDK_CU_ASSERT_FATAL(bs_ch != NULL);
8479 : :
8480 : : /* Create and open the esnap clone */
8481 : 60 : ut_spdk_blob_opts_init(&opts);
8482 : 60 : ut_esnap_opts_init(esnap_blksz, esnap_num_blocks, __func__, NULL, &esnap_opts);
8483 : 60 : opts.esnap_id = &esnap_opts;
8484 : 60 : opts.esnap_id_len = sizeof(esnap_opts);
8485 : 60 : opts.num_clusters = esnap_num_clusters;
8486 : 60 : blob = ut_blob_create_and_open(bs, &opts);
8487 [ + + ]: 60 : SPDK_CU_ASSERT_FATAL(blob != NULL);
8488 : :
8489 : : /* Verify that large reads return the content of the esnap device */
8490 : 60 : CU_ASSERT(blob_esnap_verify_contents(blob, bs_ch, 0, esnap_sz, esnap_sz, "read"));
8491 : 60 : CU_ASSERT(blob_esnap_verify_contents(blob, bs_ch, 0, esnap_sz, esnap_sz, "readv"));
8492 : 60 : CU_ASSERT(blob_esnap_verify_contents(blob, bs_ch, 0, esnap_sz, esnap_sz, "readv_ext"));
8493 : : /* Verify that small reads return the content of the esnap device */
8494 : 60 : CU_ASSERT(blob_esnap_verify_contents(blob, bs_ch, 0, esnap_sz, bs_blksz, "read"));
8495 : 60 : CU_ASSERT(blob_esnap_verify_contents(blob, bs_ch, 0, esnap_sz, bs_blksz, "readv"));
8496 : 60 : CU_ASSERT(blob_esnap_verify_contents(blob, bs_ch, 0, esnap_sz, bs_blksz, "readv_ext"));
8497 : :
8498 : : /* Write one blob block at a time; verify that the surrounding blocks are OK */
8499 [ + + ]: 5180 : for (block = 0; block < blob_num_blocks; block++) {
8500 [ - + ]: 5120 : char buf[bs_blksz];
8501 : : union ut_word word;
8502 : :
8503 : 5120 : word.f.blob_id = 0xfedcba90;
8504 : 5120 : word.f.lba = block;
8505 : 5120 : ut_memset8(buf, word.num, bs_blksz);
8506 : :
8507 : 5120 : spdk_blob_io_write(blob, bs_ch, buf, block, 1, bs_op_complete, NULL);
8508 : 5120 : poll_threads();
8509 : 5120 : CU_ASSERT(g_bserrno == 0);
8510 [ - + ]: 5120 : if (g_bserrno != 0) {
8511 : 0 : break;
8512 : : }
8513 : :
8514 : : /* Read and verify the block before the current block */
8515 [ + + ]: 5120 : if (block != 0) {
8516 : 5060 : spdk_blob_io_read(blob, bs_ch, buf, block - 1, 1, bs_op_complete, NULL);
8517 : 5060 : poll_threads();
8518 : 5060 : CU_ASSERT(g_bserrno == 0);
8519 [ + + ]: 5060 : if (g_bserrno != 0) {
8520 : 0 : break;
8521 : : }
8522 : 5060 : CU_ASSERT(ut_esnap_content_is_correct(buf, bs_blksz, word.f.blob_id,
8523 : : (block - 1) * bs_blksz, bs_blksz));
8524 : 1265 : }
8525 : :
8526 : : /* Read and verify the current block */
8527 : 5120 : spdk_blob_io_read(blob, bs_ch, buf, block, 1, bs_op_complete, NULL);
8528 : 5120 : poll_threads();
8529 : 5120 : CU_ASSERT(g_bserrno == 0);
8530 [ - + ]: 5120 : if (g_bserrno != 0) {
8531 : 0 : break;
8532 : : }
8533 : 5120 : CU_ASSERT(ut_esnap_content_is_correct(buf, bs_blksz, word.f.blob_id,
8534 : : block * bs_blksz, bs_blksz));
8535 : :
8536 : : /* Check the block that follows */
8537 [ + + ]: 5120 : if (block + 1 < blob_num_blocks) {
8538 : 5060 : g_bserrno = 0xbad;
8539 : 5060 : spdk_blob_io_read(blob, bs_ch, buf, block + 1, 1, bs_op_complete, NULL);
8540 : 5060 : poll_threads();
8541 : 5060 : CU_ASSERT(g_bserrno == 0);
8542 [ - + ]: 5060 : if (g_bserrno != 0) {
8543 : 0 : break;
8544 : : }
8545 : 5060 : CU_ASSERT(ut_esnap_content_is_correct(buf, bs_blksz, blob->id,
8546 : : (block + 1) * bs_blksz,
8547 : : esnap_blksz));
8548 : 1265 : }
8549 [ - - + ]: 1280 : }
8550 : :
8551 : : /* Clean up */
8552 : 60 : spdk_bs_free_io_channel(bs_ch);
8553 : 60 : g_bserrno = 0xbad;
8554 : 60 : spdk_blob_close(blob, blob_op_complete, NULL);
8555 : 60 : poll_threads();
8556 : 60 : CU_ASSERT(g_bserrno == 0);
8557 : 60 : spdk_bs_unload(g_bs, bs_op_complete, NULL);
8558 : 60 : poll_threads();
8559 : 60 : CU_ASSERT(g_bserrno == 0);
8560 : 60 : g_bs = NULL;
8561 [ - + ]: 60 : memset(g_dev_buffer, 0, DEV_BUFFER_SIZE);
8562 : 60 : }
8563 : :
8564 : : static void
8565 : 20 : blob_esnap_io_4096_4096(void)
8566 : : {
8567 : 20 : blob_esnap_io_size(4096, 4096);
8568 : 20 : }
8569 : :
8570 : : static void
8571 : 20 : blob_esnap_io_512_512(void)
8572 : : {
8573 : 20 : blob_esnap_io_size(512, 512);
8574 : 20 : }
8575 : :
8576 : : static void
8577 : 20 : blob_esnap_io_4096_512(void)
8578 : : {
8579 : 20 : blob_esnap_io_size(4096, 512);
8580 : 20 : }
8581 : :
8582 : : static void
8583 : 20 : blob_esnap_io_512_4096(void)
8584 : : {
8585 : : struct spdk_bs_dev *dev;
8586 : : struct spdk_blob_store *bs;
8587 : 15 : struct spdk_bs_opts bs_opts;
8588 : 15 : struct spdk_blob_opts blob_opts;
8589 : 15 : struct ut_esnap_opts esnap_opts;
8590 : 20 : uint64_t cluster_sz = 4 * g_phys_blocklen;
8591 : 20 : uint32_t bs_blksz = 512;
8592 : 20 : uint32_t esnap_blksz = BLOCKLEN;
8593 : 20 : uint64_t esnap_num_blocks = 64;
8594 : : spdk_blob_id blobid;
8595 : :
8596 : : /* Create device with desired block size */
8597 : 20 : dev = init_dev();
8598 : 20 : dev->blocklen = bs_blksz;
8599 [ - + ]: 20 : dev->blockcnt = DEV_BUFFER_SIZE / dev->blocklen;
8600 : :
8601 : : /* Initialize a new blob store */
8602 : 20 : spdk_bs_opts_init(&bs_opts, sizeof(bs_opts));
8603 : 20 : bs_opts.cluster_sz = cluster_sz;
8604 : 20 : bs_opts.esnap_bs_dev_create = ut_esnap_create;
8605 : 20 : spdk_bs_init(dev, &bs_opts, bs_op_with_handle_complete, NULL);
8606 : 20 : poll_threads();
8607 : 20 : CU_ASSERT(g_bserrno == 0);
8608 [ + + ]: 20 : SPDK_CU_ASSERT_FATAL(g_bs != NULL);
8609 [ - + ]: 20 : SPDK_CU_ASSERT_FATAL(g_bs->io_unit_size == bs_blksz);
8610 : 20 : bs = g_bs;
8611 : :
8612 : : /* Try to create and open the esnap clone. Create should succeed, open should fail. */
8613 : 20 : ut_spdk_blob_opts_init(&blob_opts);
8614 : 20 : ut_esnap_opts_init(esnap_blksz, esnap_num_blocks, __func__, NULL, &esnap_opts);
8615 : 20 : blob_opts.esnap_id = &esnap_opts;
8616 : 20 : blob_opts.esnap_id_len = sizeof(esnap_opts);
8617 [ - + ]: 20 : blob_opts.num_clusters = esnap_num_blocks * esnap_blksz / bs_blksz;
8618 : 20 : spdk_bs_create_blob_ext(bs, &blob_opts, blob_op_with_id_complete, NULL);
8619 : 20 : poll_threads();
8620 : 20 : CU_ASSERT(g_bserrno == 0);
8621 : 20 : CU_ASSERT(g_blobid != SPDK_BLOBID_INVALID);
8622 : 20 : blobid = g_blobid;
8623 : 20 : spdk_bs_open_blob(bs, blobid, blob_op_with_handle_complete, NULL);
8624 : 20 : poll_threads();
8625 : 20 : CU_ASSERT(g_bserrno == -EINVAL);
8626 : 20 : CU_ASSERT(g_blob == NULL);
8627 : :
8628 : : /* Clean up */
8629 : 20 : spdk_bs_unload(bs, bs_op_complete, NULL);
8630 : 20 : poll_threads();
8631 : 20 : CU_ASSERT(g_bserrno == 0);
8632 : 20 : g_bs = NULL;
8633 [ - + ]: 20 : memset(g_dev_buffer, 0, DEV_BUFFER_SIZE);
8634 : 20 : }
8635 : :
8636 : : static void
8637 : 20 : blob_esnap_thread_add_remove(void)
8638 : 15 : {
8639 : 20 : struct spdk_blob_store *bs = g_bs;
8640 : 15 : struct spdk_blob_opts opts;
8641 : 15 : struct ut_esnap_opts ut_esnap_opts;
8642 : : struct spdk_blob *blob;
8643 : : struct ut_esnap_dev *ut_dev;
8644 : : spdk_blob_id blobid;
8645 : 20 : uint64_t start_thread = g_ut_thread_id;
8646 : 20 : bool destroyed = false;
8647 : : struct spdk_io_channel *ch0, *ch1;
8648 : : struct ut_esnap_channel *ut_ch0, *ut_ch1;
8649 : 20 : const uint32_t blocklen = bs->io_unit_size;
8650 [ - + ]: 20 : char buf[blocklen * 4];
8651 : :
8652 [ + + ]: 20 : SPDK_CU_ASSERT_FATAL(g_ut_num_threads > 1);
8653 : 20 : set_thread(0);
8654 : :
8655 : : /* Create the esnap clone */
8656 : 20 : ut_esnap_opts_init(blocklen, 2048, "add_remove_1", &destroyed, &ut_esnap_opts);
8657 : 20 : ut_spdk_blob_opts_init(&opts);
8658 : 20 : opts.esnap_id = &ut_esnap_opts;
8659 : 20 : opts.esnap_id_len = sizeof(ut_esnap_opts);
8660 : 20 : opts.num_clusters = 10;
8661 : 20 : spdk_bs_create_blob_ext(bs, &opts, blob_op_with_id_complete, NULL);
8662 : 20 : poll_threads();
8663 : 20 : CU_ASSERT(g_bserrno == 0);
8664 : 20 : CU_ASSERT(g_blobid != SPDK_BLOBID_INVALID);
8665 : 20 : blobid = g_blobid;
8666 : :
8667 : : /* Open the blob. No channels should be allocated yet. */
8668 : 20 : spdk_bs_open_blob(bs, blobid, blob_op_with_handle_complete, NULL);
8669 : 20 : poll_threads();
8670 : 20 : CU_ASSERT(g_bserrno == 0);
8671 : 20 : CU_ASSERT(g_blob != NULL);
8672 : 20 : blob = g_blob;
8673 : 20 : ut_dev = (struct ut_esnap_dev *)blob->back_bs_dev;
8674 : 20 : CU_ASSERT(ut_dev != NULL);
8675 : 20 : CU_ASSERT(ut_dev->num_channels == 0);
8676 : :
8677 : : /* Create a channel on thread 0. It is lazily created on the first read. */
8678 : 20 : ch0 = spdk_bs_alloc_io_channel(bs);
8679 : 20 : CU_ASSERT(ch0 != NULL);
8680 : 20 : ut_ch0 = ut_esnap_get_io_channel(ch0, blobid);
8681 : 20 : CU_ASSERT(ut_ch0 == NULL);
8682 : 20 : CU_ASSERT(ut_dev->num_channels == 0);
8683 : 20 : spdk_blob_io_read(blob, ch0, buf, 0, 1, bs_op_complete, NULL);
8684 : 20 : poll_threads();
8685 : 20 : CU_ASSERT(g_bserrno == 0);
8686 : 20 : CU_ASSERT(ut_dev->num_channels == 1);
8687 : 20 : ut_ch0 = ut_esnap_get_io_channel(ch0, blobid);
8688 : 20 : CU_ASSERT(ut_ch0 != NULL);
8689 : 20 : CU_ASSERT(ut_ch0->blocks_read == 1);
8690 : :
8691 : : /* Create a channel on thread 1 and verify its lazy creation too. */
8692 : 20 : set_thread(1);
8693 : 20 : ch1 = spdk_bs_alloc_io_channel(bs);
8694 : 20 : CU_ASSERT(ch1 != NULL);
8695 : 20 : ut_ch1 = ut_esnap_get_io_channel(ch1, blobid);
8696 : 20 : CU_ASSERT(ut_ch1 == NULL);
8697 : 20 : CU_ASSERT(ut_dev->num_channels == 1);
8698 : 20 : spdk_blob_io_read(blob, ch1, buf, 0, 4, bs_op_complete, NULL);
8699 : 20 : poll_threads();
8700 : 20 : CU_ASSERT(g_bserrno == 0);
8701 : 20 : CU_ASSERT(ut_dev->num_channels == 2);
8702 : 20 : ut_ch1 = ut_esnap_get_io_channel(ch1, blobid);
8703 : 20 : CU_ASSERT(ut_ch1 != NULL);
8704 : 20 : CU_ASSERT(ut_ch1->blocks_read == 4);
8705 : :
8706 : : /* Close the channel on thread 0 and verify the bs_dev channel is also gone. */
8707 : 20 : set_thread(0);
8708 : 20 : spdk_bs_free_io_channel(ch0);
8709 : 20 : poll_threads();
8710 : 20 : CU_ASSERT(ut_dev->num_channels == 1);
8711 : :
8712 : : /* Close the blob. There is no outstanding IO so it should close right away. */
8713 : 20 : g_bserrno = 0xbad;
8714 : 20 : spdk_blob_close(blob, blob_op_complete, NULL);
8715 : 20 : poll_threads();
8716 : 20 : CU_ASSERT(g_bserrno == 0);
8717 [ - + ]: 20 : CU_ASSERT(destroyed);
8718 : :
8719 : : /* The esnap channel for the blob should be gone now too. */
8720 : 20 : ut_ch1 = ut_esnap_get_io_channel(ch1, blobid);
8721 : 20 : CU_ASSERT(ut_ch1 == NULL);
8722 : :
8723 : : /* Clean up */
8724 : 20 : set_thread(1);
8725 : 20 : spdk_bs_free_io_channel(ch1);
8726 : 20 : set_thread(start_thread);
8727 : 20 : }
8728 : :
8729 : : static void
8730 : 60 : freeze_done(void *cb_arg, int bserrno)
8731 : : {
8732 : 60 : uint32_t *freeze_cnt = cb_arg;
8733 : :
8734 : 60 : CU_ASSERT(bserrno == 0);
8735 : 60 : (*freeze_cnt)++;
8736 : 60 : }
8737 : :
8738 : : static void
8739 : 60 : unfreeze_done(void *cb_arg, int bserrno)
8740 : : {
8741 : 60 : uint32_t *unfreeze_cnt = cb_arg;
8742 : :
8743 : 60 : CU_ASSERT(bserrno == 0);
8744 : 60 : (*unfreeze_cnt)++;
8745 : 60 : }
8746 : :
8747 : : static void
8748 : 20 : blob_nested_freezes(void)
8749 : : {
8750 : 20 : struct spdk_blob_store *bs = g_bs;
8751 : : struct spdk_blob *blob;
8752 : 15 : struct spdk_io_channel *channel[2];
8753 : 15 : struct spdk_blob_opts opts;
8754 : 15 : uint32_t freeze_cnt, unfreeze_cnt;
8755 : : int i;
8756 : :
8757 [ + + ]: 60 : for (i = 0; i < 2; i++) {
8758 : 40 : set_thread(i);
8759 : 40 : channel[i] = spdk_bs_alloc_io_channel(bs);
8760 [ + + ]: 40 : SPDK_CU_ASSERT_FATAL(channel[i] != NULL);
8761 : 10 : }
8762 : :
8763 : 20 : set_thread(0);
8764 : :
8765 : 20 : ut_spdk_blob_opts_init(&opts);
8766 : 20 : blob = ut_blob_create_and_open(bs, &opts);
8767 : :
8768 : : /* First just test a single freeze/unfreeze. */
8769 : 20 : freeze_cnt = 0;
8770 : 20 : unfreeze_cnt = 0;
8771 : 20 : CU_ASSERT(blob->frozen_refcnt == 0);
8772 : 20 : blob_freeze_io(blob, freeze_done, &freeze_cnt);
8773 : 20 : CU_ASSERT(blob->frozen_refcnt == 1);
8774 : 20 : CU_ASSERT(freeze_cnt == 0);
8775 : 20 : poll_threads();
8776 : 20 : CU_ASSERT(freeze_cnt == 1);
8777 : 20 : blob_unfreeze_io(blob, unfreeze_done, &unfreeze_cnt);
8778 : 20 : CU_ASSERT(blob->frozen_refcnt == 0);
8779 : 20 : CU_ASSERT(unfreeze_cnt == 0);
8780 : 20 : poll_threads();
8781 : 20 : CU_ASSERT(unfreeze_cnt == 1);
8782 : :
8783 : : /* Now nest multiple freeze/unfreeze operations. We should
8784 : : * expect a callback for each operation, but only after
8785 : : * the threads have been polled to ensure a for_each_channel()
8786 : : * was executed.
8787 : : */
8788 : 20 : freeze_cnt = 0;
8789 : 20 : unfreeze_cnt = 0;
8790 : 20 : CU_ASSERT(blob->frozen_refcnt == 0);
8791 : 20 : blob_freeze_io(blob, freeze_done, &freeze_cnt);
8792 : 20 : CU_ASSERT(blob->frozen_refcnt == 1);
8793 : 20 : CU_ASSERT(freeze_cnt == 0);
8794 : 20 : blob_freeze_io(blob, freeze_done, &freeze_cnt);
8795 : 20 : CU_ASSERT(blob->frozen_refcnt == 2);
8796 : 20 : CU_ASSERT(freeze_cnt == 0);
8797 : 20 : poll_threads();
8798 : 20 : CU_ASSERT(freeze_cnt == 2);
8799 : 20 : blob_unfreeze_io(blob, unfreeze_done, &unfreeze_cnt);
8800 : 20 : CU_ASSERT(blob->frozen_refcnt == 1);
8801 : 20 : CU_ASSERT(unfreeze_cnt == 0);
8802 : 20 : blob_unfreeze_io(blob, unfreeze_done, &unfreeze_cnt);
8803 : 20 : CU_ASSERT(blob->frozen_refcnt == 0);
8804 : 20 : CU_ASSERT(unfreeze_cnt == 0);
8805 : 20 : poll_threads();
8806 : 20 : CU_ASSERT(unfreeze_cnt == 2);
8807 : :
8808 [ + + ]: 60 : for (i = 0; i < 2; i++) {
8809 : 40 : set_thread(i);
8810 : 40 : spdk_bs_free_io_channel(channel[i]);
8811 : 10 : }
8812 : 20 : set_thread(0);
8813 : 20 : ut_blob_close_and_delete(bs, blob);
8814 : :
8815 : 20 : poll_threads();
8816 : 20 : g_blob = NULL;
8817 : 20 : g_blobid = 0;
8818 : 20 : }
8819 : :
8820 : : static void
8821 : 20 : blob_ext_md_pages(void)
8822 : : {
8823 : : struct spdk_blob_store *bs;
8824 : : struct spdk_bs_dev *dev;
8825 : : struct spdk_blob *blob;
8826 : 15 : struct spdk_blob_opts opts;
8827 : 15 : struct spdk_bs_opts bs_opts;
8828 : : uint64_t free_clusters;
8829 : :
8830 : 20 : dev = init_dev();
8831 : 20 : spdk_bs_opts_init(&bs_opts, sizeof(bs_opts));
8832 [ - + ]: 20 : snprintf(bs_opts.bstype.bstype, sizeof(bs_opts.bstype.bstype), "TESTTYPE");
8833 : : /* Issue #2932 was a bug in how we use bs_allocate_cluster() during resize.
8834 : : * It requires num_md_pages that is much smaller than the number of clusters.
8835 : : * Make sure we can create a blob that uses all of the free clusters.
8836 : : */
8837 : 20 : bs_opts.cluster_sz = 65536;
8838 : 20 : bs_opts.num_md_pages = 16;
8839 : :
8840 : : /* Initialize a new blob store */
8841 : 20 : spdk_bs_init(dev, &bs_opts, bs_op_with_handle_complete, NULL);
8842 : 20 : poll_threads();
8843 : 20 : CU_ASSERT(g_bserrno == 0);
8844 [ + + ]: 20 : SPDK_CU_ASSERT_FATAL(g_bs != NULL);
8845 : 20 : bs = g_bs;
8846 : :
8847 : 20 : free_clusters = spdk_bs_free_cluster_count(bs);
8848 : :
8849 : 20 : ut_spdk_blob_opts_init(&opts);
8850 : 20 : opts.num_clusters = free_clusters;
8851 : :
8852 : 20 : blob = ut_blob_create_and_open(bs, &opts);
8853 : 20 : spdk_blob_close(blob, blob_op_complete, NULL);
8854 : 20 : CU_ASSERT(g_bserrno == 0);
8855 : :
8856 : 20 : spdk_bs_unload(bs, bs_op_complete, NULL);
8857 : 20 : poll_threads();
8858 : 20 : CU_ASSERT(g_bserrno == 0);
8859 : 20 : g_bs = NULL;
8860 : 20 : }
8861 : :
8862 : : static void
8863 : 20 : blob_esnap_clone_snapshot(void)
8864 : : {
8865 : : /*
8866 : : * When a snapshot is created, the blob that is being snapped becomes
8867 : : * the leaf node (a clone of the snapshot) and the newly created
8868 : : * snapshot sits between the snapped blob and the external snapshot.
8869 : : *
8870 : : * Before creating snap1
8871 : : *
8872 : : * ,--------. ,----------.
8873 : : * | blob | | vbdev |
8874 : : * | blob1 |<----| nvme1n42 |
8875 : : * | (rw) | | (ro) |
8876 : : * `--------' `----------'
8877 : : * Figure 1
8878 : : *
8879 : : * After creating snap1
8880 : : *
8881 : : * ,--------. ,--------. ,----------.
8882 : : * | blob | | blob | | vbdev |
8883 : : * | blob1 |<----| snap1 |<----| nvme1n42 |
8884 : : * | (rw) | | (ro) | | (ro) |
8885 : : * `--------' `--------' `----------'
8886 : : * Figure 2
8887 : : *
8888 : : * Starting from Figure 2, if snap1 is removed, the chain reverts to
8889 : : * what it looks like in Figure 1.
8890 : : *
8891 : : * Starting from Figure 2, if blob1 is removed, the chain becomes:
8892 : : *
8893 : : * ,--------. ,----------.
8894 : : * | blob | | vbdev |
8895 : : * | snap1 |<----| nvme1n42 |
8896 : : * | (ro) | | (ro) |
8897 : : * `--------' `----------'
8898 : : * Figure 3
8899 : : *
8900 : : * In each case, the blob pointed to by the nvme vbdev is considered
8901 : : * the "esnap clone". The esnap clone must have:
8902 : : *
8903 : : * - XATTR_INTERNAL for BLOB_EXTERNAL_SNAPSHOT_ID (e.g. name or UUID)
8904 : : * - blob->invalid_flags must contain SPDK_BLOB_EXTERNAL_SNAPSHOT
8905 : : * - blob->parent_id must be SPDK_BLOBID_EXTERNAL_SNAPSHOT.
8906 : : *
8907 : : * No other blob that descends from the esnap clone may have any of
8908 : : * those set.
8909 : : */
8910 : 20 : struct spdk_blob_store *bs = g_bs;
8911 : 20 : const uint32_t blocklen = bs->io_unit_size;
8912 : 15 : struct spdk_blob_opts opts;
8913 : 15 : struct ut_esnap_opts esnap_opts;
8914 : : struct spdk_blob *blob, *snap_blob;
8915 : : spdk_blob_id blobid, snap_blobid;
8916 : 20 : bool destroyed = false;
8917 : :
8918 : : /* Create the esnap clone */
8919 : 20 : ut_esnap_opts_init(blocklen, 2048, __func__, &destroyed, &esnap_opts);
8920 : 20 : ut_spdk_blob_opts_init(&opts);
8921 : 20 : opts.esnap_id = &esnap_opts;
8922 : 20 : opts.esnap_id_len = sizeof(esnap_opts);
8923 : 20 : opts.num_clusters = 10;
8924 : 20 : spdk_bs_create_blob_ext(bs, &opts, blob_op_with_id_complete, NULL);
8925 : 20 : poll_threads();
8926 : 20 : CU_ASSERT(g_bserrno == 0);
8927 : 20 : CU_ASSERT(g_blobid != SPDK_BLOBID_INVALID);
8928 : 20 : blobid = g_blobid;
8929 : :
8930 : : /* Open the blob. */
8931 : 20 : spdk_bs_open_blob(bs, blobid, blob_op_with_handle_complete, NULL);
8932 : 20 : poll_threads();
8933 : 20 : CU_ASSERT(g_bserrno == 0);
8934 : 20 : CU_ASSERT(g_blob != NULL);
8935 : 20 : blob = g_blob;
8936 : 20 : UT_ASSERT_IS_ESNAP_CLONE(blob, &esnap_opts, sizeof(esnap_opts));
8937 : :
8938 : : /*
8939 : : * Create a snapshot of the blob. The snapshot becomes the esnap clone.
8940 : : */
8941 : 20 : spdk_bs_create_snapshot(bs, blobid, NULL, blob_op_with_id_complete, NULL);
8942 : 20 : poll_threads();
8943 : 20 : CU_ASSERT(g_bserrno == 0);
8944 : 20 : CU_ASSERT(g_blobid != SPDK_BLOBID_INVALID);
8945 : 20 : snap_blobid = g_blobid;
8946 : :
8947 : 20 : spdk_bs_open_blob(bs, snap_blobid, blob_op_with_handle_complete, NULL);
8948 : 20 : poll_threads();
8949 : 20 : CU_ASSERT(g_bserrno == 0);
8950 [ + + ]: 20 : SPDK_CU_ASSERT_FATAL(g_blob != NULL);
8951 : 20 : snap_blob = g_blob;
8952 : :
8953 : 20 : UT_ASSERT_IS_NOT_ESNAP_CLONE(blob);
8954 : 20 : UT_ASSERT_IS_ESNAP_CLONE(snap_blob, &esnap_opts, sizeof(esnap_opts));
8955 : :
8956 : : /*
8957 : : * Delete the snapshot. The original blob becomes the esnap clone.
8958 : : */
8959 : 20 : ut_blob_close_and_delete(bs, snap_blob);
8960 : 20 : snap_blob = NULL;
8961 : 20 : snap_blobid = SPDK_BLOBID_INVALID;
8962 : 20 : UT_ASSERT_IS_ESNAP_CLONE(blob, &esnap_opts, sizeof(esnap_opts));
8963 : :
8964 : : /*
8965 : : * Create the snapshot again, then delete the original blob. The
8966 : : * snapshot should survive as the esnap clone.
8967 : : */
8968 : 20 : spdk_bs_create_snapshot(bs, blobid, NULL, blob_op_with_id_complete, NULL);
8969 : 20 : poll_threads();
8970 : 20 : CU_ASSERT(g_bserrno == 0);
8971 : 20 : CU_ASSERT(g_blobid != SPDK_BLOBID_INVALID);
8972 : 20 : snap_blobid = g_blobid;
8973 : :
8974 : 20 : spdk_bs_open_blob(bs, snap_blobid, blob_op_with_handle_complete, NULL);
8975 : 20 : poll_threads();
8976 : 20 : CU_ASSERT(g_bserrno == 0);
8977 [ + + ]: 20 : SPDK_CU_ASSERT_FATAL(g_blob != NULL);
8978 : 20 : snap_blob = g_blob;
8979 : :
8980 : 20 : UT_ASSERT_IS_NOT_ESNAP_CLONE(blob);
8981 : 20 : UT_ASSERT_IS_ESNAP_CLONE(snap_blob, &esnap_opts, sizeof(esnap_opts));
8982 : :
8983 : 20 : ut_blob_close_and_delete(bs, blob);
8984 : 20 : blob = NULL;
8985 : 20 : blobid = SPDK_BLOBID_INVALID;
8986 : 20 : UT_ASSERT_IS_ESNAP_CLONE(snap_blob, &esnap_opts, sizeof(esnap_opts));
8987 : :
8988 : : /*
8989 : : * Clone the snapshot. The snapshot continues to be the esnap clone.
8990 : : */
8991 : 20 : spdk_bs_create_clone(bs, snap_blobid, NULL, blob_op_with_id_complete, NULL);
8992 : 20 : poll_threads();
8993 : 20 : CU_ASSERT(g_bserrno == 0);
8994 : 20 : CU_ASSERT(g_blobid != SPDK_BLOBID_INVALID);
8995 : 20 : blobid = g_blobid;
8996 : :
8997 : 20 : spdk_bs_open_blob(bs, blobid, blob_op_with_handle_complete, NULL);
8998 : 20 : poll_threads();
8999 : 20 : CU_ASSERT(g_bserrno == 0);
9000 [ - + ]: 20 : SPDK_CU_ASSERT_FATAL(g_blob != NULL);
9001 : 20 : blob = g_blob;
9002 : :
9003 : 20 : UT_ASSERT_IS_NOT_ESNAP_CLONE(blob);
9004 : 20 : UT_ASSERT_IS_ESNAP_CLONE(snap_blob, &esnap_opts, sizeof(esnap_opts));
9005 : :
9006 : : /*
9007 : : * Delete the snapshot. The clone becomes the esnap clone.
9008 : : */
9009 : 20 : ut_blob_close_and_delete(bs, snap_blob);
9010 : 20 : snap_blob = NULL;
9011 : 20 : snap_blobid = SPDK_BLOBID_INVALID;
9012 : 20 : UT_ASSERT_IS_ESNAP_CLONE(blob, &esnap_opts, sizeof(esnap_opts));
9013 : :
9014 : : /*
9015 : : * Clean up
9016 : : */
9017 : 20 : ut_blob_close_and_delete(bs, blob);
9018 : 20 : }
9019 : :
9020 : : static uint64_t
9021 : 40 : _blob_esnap_clone_hydrate(bool inflate)
9022 : : {
9023 : 40 : struct spdk_blob_store *bs = g_bs;
9024 : 30 : struct spdk_blob_opts opts;
9025 : 30 : struct ut_esnap_opts esnap_opts;
9026 : : struct spdk_blob *blob;
9027 : : spdk_blob_id blobid;
9028 : : struct spdk_io_channel *channel;
9029 : 40 : bool destroyed = false;
9030 : 40 : const uint32_t blocklen = spdk_bs_get_io_unit_size(bs);
9031 : 40 : const uint32_t cluster_sz = spdk_bs_get_cluster_size(bs);
9032 : 40 : const uint64_t esnap_num_clusters = 4;
9033 : 40 : const uint32_t esnap_sz = cluster_sz * esnap_num_clusters;
9034 [ - + ]: 40 : const uint64_t esnap_num_blocks = esnap_sz / blocklen;
9035 : 40 : uint64_t num_failures = CU_get_number_of_failures();
9036 : :
9037 : 40 : channel = spdk_bs_alloc_io_channel(bs);
9038 [ + + ]: 40 : SPDK_CU_ASSERT_FATAL(channel != NULL);
9039 : :
9040 : : /* Create the esnap clone */
9041 : 40 : ut_spdk_blob_opts_init(&opts);
9042 : 40 : ut_esnap_opts_init(blocklen, esnap_num_blocks, __func__, &destroyed, &esnap_opts);
9043 : 40 : opts.esnap_id = &esnap_opts;
9044 : 40 : opts.esnap_id_len = sizeof(esnap_opts);
9045 : 40 : opts.num_clusters = esnap_num_clusters;
9046 : 40 : spdk_bs_create_blob_ext(bs, &opts, blob_op_with_id_complete, NULL);
9047 : 40 : poll_threads();
9048 : 40 : CU_ASSERT(g_bserrno == 0);
9049 : 40 : CU_ASSERT(g_blobid != SPDK_BLOBID_INVALID);
9050 : 40 : blobid = g_blobid;
9051 : :
9052 : : /* Open the esnap clone */
9053 : 40 : spdk_bs_open_blob(bs, blobid, blob_op_with_handle_complete, NULL);
9054 : 40 : poll_threads();
9055 : 40 : CU_ASSERT(g_bserrno == 0);
9056 [ - + ]: 40 : SPDK_CU_ASSERT_FATAL(g_blob != NULL);
9057 : 40 : blob = g_blob;
9058 : 40 : UT_ASSERT_IS_ESNAP_CLONE(blob, &esnap_opts, sizeof(esnap_opts));
9059 : :
9060 : : /*
9061 : : * Inflate or decouple the blob then verify that it is no longer an esnap clone and has
9062 : : * right content
9063 : : */
9064 [ + + ]: 40 : if (inflate) {
9065 : 20 : spdk_bs_inflate_blob(bs, channel, blobid, blob_op_complete, NULL);
9066 : 5 : } else {
9067 : 20 : spdk_bs_blob_decouple_parent(bs, channel, blobid, blob_op_complete, NULL);
9068 : : }
9069 : 40 : poll_threads();
9070 : 40 : CU_ASSERT(g_bserrno == 0);
9071 : 40 : UT_ASSERT_IS_NOT_ESNAP_CLONE(blob);
9072 : 40 : CU_ASSERT(blob_esnap_verify_contents(blob, channel, 0, esnap_sz, esnap_sz, "read"));
9073 : 40 : ut_blob_close_and_delete(bs, blob);
9074 : :
9075 : : /*
9076 : : * Clean up
9077 : : */
9078 : 40 : spdk_bs_free_io_channel(channel);
9079 : 40 : poll_threads();
9080 : :
9081 : : /* Return number of new failures */
9082 : 40 : return CU_get_number_of_failures() - num_failures;
9083 : : }
9084 : :
9085 : : static void
9086 : 20 : blob_esnap_clone_inflate(void)
9087 : : {
9088 : 20 : _blob_esnap_clone_hydrate(true);
9089 : 20 : }
9090 : :
9091 : : static void
9092 : 20 : blob_esnap_clone_decouple(void)
9093 : : {
9094 : 20 : _blob_esnap_clone_hydrate(false);
9095 : 20 : }
9096 : :
9097 : : static void
9098 : 20 : blob_esnap_hotplug(void)
9099 : 15 : {
9100 : 20 : struct spdk_blob_store *bs = g_bs;
9101 : 15 : struct ut_esnap_opts esnap1_opts, esnap2_opts;
9102 : 15 : struct spdk_blob_opts opts;
9103 : : struct spdk_blob *blob;
9104 : : struct spdk_bs_dev *bs_dev;
9105 : : struct ut_esnap_dev *esnap_dev;
9106 : 20 : uint32_t cluster_sz = spdk_bs_get_cluster_size(bs);
9107 : 20 : uint32_t block_sz = spdk_bs_get_io_unit_size(bs);
9108 : 20 : const uint32_t esnap_num_clusters = 4;
9109 [ - + ]: 20 : uint64_t esnap_num_blocks = cluster_sz * esnap_num_clusters / block_sz;
9110 : 20 : bool destroyed1 = false, destroyed2 = false;
9111 : 20 : uint64_t start_thread = g_ut_thread_id;
9112 : : struct spdk_io_channel *ch0, *ch1;
9113 [ - + ]: 20 : char buf[block_sz];
9114 : :
9115 : : /* Create and open an esnap clone blob */
9116 : 20 : ut_spdk_blob_opts_init(&opts);
9117 : 20 : ut_esnap_opts_init(block_sz, esnap_num_blocks, "esnap1", &destroyed1, &esnap1_opts);
9118 : 20 : opts.esnap_id = &esnap1_opts;
9119 : 20 : opts.esnap_id_len = sizeof(esnap1_opts);
9120 : 20 : opts.num_clusters = esnap_num_clusters;
9121 : 20 : blob = ut_blob_create_and_open(bs, &opts);
9122 : 20 : CU_ASSERT(blob != NULL);
9123 : 20 : CU_ASSERT(spdk_blob_is_esnap_clone(blob));
9124 [ + + ]: 20 : SPDK_CU_ASSERT_FATAL(blob->back_bs_dev != NULL);
9125 : 20 : esnap_dev = (struct ut_esnap_dev *)blob->back_bs_dev;
9126 [ - + ]: 20 : CU_ASSERT(strcmp(esnap_dev->ut_opts.name, "esnap1") == 0);
9127 : :
9128 : : /* Replace the external snapshot */
9129 : 20 : ut_esnap_opts_init(block_sz, esnap_num_blocks, "esnap2", &destroyed2, &esnap2_opts);
9130 : 20 : bs_dev = ut_esnap_dev_alloc(&esnap2_opts);
9131 [ - + ]: 20 : CU_ASSERT(!destroyed1);
9132 [ - + ]: 20 : CU_ASSERT(!destroyed2);
9133 : 20 : g_bserrno = 0xbad;
9134 : 20 : spdk_blob_set_esnap_bs_dev(blob, bs_dev, bs_op_complete, NULL);
9135 : 20 : poll_threads();
9136 : 20 : CU_ASSERT(g_bserrno == 0);
9137 [ - + ]: 20 : CU_ASSERT(destroyed1);
9138 [ - + ]: 20 : CU_ASSERT(!destroyed2);
9139 [ + + ]: 20 : SPDK_CU_ASSERT_FATAL(bs_dev == blob->back_bs_dev);
9140 [ + + ]: 20 : SPDK_CU_ASSERT_FATAL(bs_dev == spdk_blob_get_esnap_bs_dev(blob));
9141 : 20 : esnap_dev = (struct ut_esnap_dev *)blob->back_bs_dev;
9142 [ - + ]: 20 : CU_ASSERT(strcmp(esnap_dev->ut_opts.name, "esnap2") == 0);
9143 : :
9144 : : /* Create a couple channels */
9145 : 20 : set_thread(0);
9146 : 20 : ch0 = spdk_bs_alloc_io_channel(bs);
9147 : 20 : CU_ASSERT(ch0 != NULL);
9148 : 20 : spdk_blob_io_read(blob, ch0, buf, 0, 1, bs_op_complete, NULL);
9149 : 20 : set_thread(1);
9150 : 20 : ch1 = spdk_bs_alloc_io_channel(bs);
9151 : 20 : CU_ASSERT(ch1 != NULL);
9152 : 20 : spdk_blob_io_read(blob, ch1, buf, 0, 1, bs_op_complete, NULL);
9153 : 20 : set_thread(start_thread);
9154 : 20 : poll_threads();
9155 : 20 : CU_ASSERT(esnap_dev->num_channels == 2);
9156 : :
9157 : : /* Replace the external snapshot */
9158 : 20 : ut_esnap_opts_init(block_sz, esnap_num_blocks, "esnap1a", &destroyed1, &esnap1_opts);
9159 : 20 : bs_dev = ut_esnap_dev_alloc(&esnap1_opts);
9160 [ - + ]: 20 : destroyed1 = destroyed2 = false;
9161 : 20 : g_bserrno = 0xbad;
9162 : 20 : spdk_blob_set_esnap_bs_dev(blob, bs_dev, bs_op_complete, NULL);
9163 : 20 : poll_threads();
9164 : 20 : CU_ASSERT(g_bserrno == 0);
9165 [ - + ]: 20 : CU_ASSERT(!destroyed1);
9166 [ - + ]: 20 : CU_ASSERT(destroyed2);
9167 [ - + ]: 20 : SPDK_CU_ASSERT_FATAL(blob->back_bs_dev != NULL);
9168 : 20 : esnap_dev = (struct ut_esnap_dev *)blob->back_bs_dev;
9169 [ - + ]: 20 : CU_ASSERT(strcmp(esnap_dev->ut_opts.name, "esnap1a") == 0);
9170 : :
9171 : : /* Clean up */
9172 : 20 : set_thread(0);
9173 : 20 : spdk_bs_free_io_channel(ch0);
9174 : 20 : set_thread(1);
9175 : 20 : spdk_bs_free_io_channel(ch1);
9176 : 20 : set_thread(start_thread);
9177 : 20 : g_bserrno = 0xbad;
9178 : 20 : spdk_blob_close(blob, bs_op_complete, NULL);
9179 : 20 : poll_threads();
9180 : 20 : CU_ASSERT(g_bserrno == 0);
9181 : 20 : }
9182 : :
9183 : : static bool g_blob_is_degraded;
9184 : : static int g_blob_is_degraded_called;
9185 : :
9186 : : static bool
9187 : 120 : _blob_is_degraded(struct spdk_bs_dev *dev)
9188 : : {
9189 : 120 : g_blob_is_degraded_called++;
9190 [ - + ]: 120 : return g_blob_is_degraded;
9191 : : }
9192 : :
9193 : : static void
9194 : 20 : blob_is_degraded(void)
9195 : : {
9196 : 20 : struct spdk_bs_dev bs_is_degraded_null = { 0 };
9197 : 20 : struct spdk_bs_dev bs_is_degraded = { .is_degraded = _blob_is_degraded };
9198 : :
9199 : : /* No back_bs_dev, no bs->dev->is_degraded */
9200 : 20 : g_blob_is_degraded_called = 0;
9201 : 20 : CU_ASSERT(!spdk_blob_is_degraded(g_blob));
9202 : 20 : CU_ASSERT(g_blob_is_degraded_called == 0);
9203 : :
9204 : : /* No back_bs_dev, blobstore device degraded */
9205 : 20 : g_bs->dev->is_degraded = _blob_is_degraded;
9206 : 20 : g_blob_is_degraded_called = 0;
9207 : 20 : g_blob_is_degraded = true;
9208 : 20 : CU_ASSERT(spdk_blob_is_degraded(g_blob));
9209 : 20 : CU_ASSERT(g_blob_is_degraded_called == 1);
9210 : :
9211 : : /* No back_bs_dev, blobstore device not degraded */
9212 : 20 : g_bs->dev->is_degraded = _blob_is_degraded;
9213 : 20 : g_blob_is_degraded_called = 0;
9214 : 20 : g_blob_is_degraded = false;
9215 : 20 : CU_ASSERT(!spdk_blob_is_degraded(g_blob));
9216 : 20 : CU_ASSERT(g_blob_is_degraded_called == 1);
9217 : :
9218 : : /* back_bs_dev does not define is_degraded, no bs->dev->is_degraded */
9219 : 20 : g_bs->dev->is_degraded = NULL;
9220 : 20 : g_blob->back_bs_dev = &bs_is_degraded_null;
9221 : 20 : g_blob_is_degraded_called = 0;
9222 : 20 : g_blob_is_degraded = false;
9223 : 20 : CU_ASSERT(!spdk_blob_is_degraded(g_blob));
9224 : 20 : CU_ASSERT(g_blob_is_degraded_called == 0);
9225 : :
9226 : : /* back_bs_dev is not degraded, no bs->dev->is_degraded */
9227 : 20 : g_bs->dev->is_degraded = NULL;
9228 : 20 : g_blob->back_bs_dev = &bs_is_degraded;
9229 : 20 : g_blob_is_degraded_called = 0;
9230 : 20 : g_blob_is_degraded = false;
9231 : 20 : CU_ASSERT(!spdk_blob_is_degraded(g_blob));
9232 : 20 : CU_ASSERT(g_blob_is_degraded_called == 1);
9233 : :
9234 : : /* back_bs_dev is degraded, no bs->dev->is_degraded */
9235 : 20 : g_bs->dev->is_degraded = NULL;
9236 : 20 : g_blob->back_bs_dev = &bs_is_degraded;
9237 : 20 : g_blob_is_degraded_called = 0;
9238 : 20 : g_blob_is_degraded = true;
9239 : 20 : CU_ASSERT(spdk_blob_is_degraded(g_blob));
9240 : 20 : CU_ASSERT(g_blob_is_degraded_called == 1);
9241 : :
9242 : : /* back_bs_dev is not degraded, blobstore device is not degraded */
9243 : 20 : g_bs->dev->is_degraded = _blob_is_degraded;
9244 : 20 : g_blob->back_bs_dev = &bs_is_degraded;
9245 : 20 : g_blob_is_degraded_called = 0;
9246 : 20 : g_blob_is_degraded = false;
9247 : 20 : CU_ASSERT(!spdk_blob_is_degraded(g_blob));
9248 : 20 : CU_ASSERT(g_blob_is_degraded_called == 2);
9249 : :
9250 : 20 : g_blob->back_bs_dev = NULL;
9251 : 20 : }
9252 : :
9253 : : /* Resize a blob which is a clone created from snapshot. Verify read/writes to
9254 : : * expanded clone blob. Then inflate the clone blob. */
9255 : : static void
9256 : 20 : blob_clone_resize(void)
9257 : 15 : {
9258 : 20 : struct spdk_blob_store *bs = g_bs;
9259 : 15 : struct spdk_blob_opts opts;
9260 : : struct spdk_blob *blob, *clone, *snap_blob, *snap_blob_rsz;
9261 : : spdk_blob_id blobid, cloneid, snapid1, snapid2;
9262 : : uint64_t pages_per_cluster;
9263 [ - + ]: 20 : uint8_t payload_read[bs->dev->blocklen];
9264 [ - + ]: 20 : uint8_t payload_write[bs->dev->blocklen];
9265 : : struct spdk_io_channel *channel;
9266 : : uint64_t free_clusters;
9267 : :
9268 : 20 : channel = spdk_bs_alloc_io_channel(bs);
9269 [ + + ]: 20 : SPDK_CU_ASSERT_FATAL(channel != NULL);
9270 : :
9271 [ - + ]: 20 : pages_per_cluster = spdk_bs_get_cluster_size(bs) / spdk_bs_get_page_size(bs);
9272 : :
9273 : : /* Create blob with 10 clusters */
9274 : 20 : ut_spdk_blob_opts_init(&opts);
9275 : 20 : opts.num_clusters = 10;
9276 : :
9277 : 20 : blob = ut_blob_create_and_open(bs, &opts);
9278 : 20 : blobid = spdk_blob_get_id(blob);
9279 : 20 : CU_ASSERT(spdk_blob_get_num_clusters(blob) == 10);
9280 : :
9281 : : /* Create snapshot */
9282 : 20 : spdk_bs_create_snapshot(bs, blobid, NULL, blob_op_with_id_complete, NULL);
9283 : 20 : poll_threads();
9284 : 20 : CU_ASSERT(g_bserrno == 0);
9285 : 20 : CU_ASSERT(g_blobid != SPDK_BLOBID_INVALID);
9286 : 20 : snapid1 = g_blobid;
9287 : :
9288 : 20 : spdk_bs_create_clone(bs, snapid1, NULL, blob_op_with_id_complete, NULL);
9289 : 20 : poll_threads();
9290 : 20 : CU_ASSERT(g_bserrno == 0);
9291 : 20 : CU_ASSERT(g_blobid != SPDK_BLOBID_INVALID);
9292 : 20 : cloneid = g_blobid;
9293 : :
9294 : 20 : spdk_bs_open_blob(bs, cloneid, blob_op_with_handle_complete, NULL);
9295 : 20 : poll_threads();
9296 : 20 : CU_ASSERT(g_bserrno == 0);
9297 [ + + ]: 20 : SPDK_CU_ASSERT_FATAL(g_blob != NULL);
9298 : 20 : clone = g_blob;
9299 : 20 : CU_ASSERT(spdk_blob_get_num_clusters(clone) == 10);
9300 : :
9301 : 20 : g_bserrno = -1;
9302 : 20 : spdk_blob_resize(clone, 20, blob_op_complete, NULL);
9303 : 20 : poll_threads();
9304 : 20 : CU_ASSERT(g_bserrno == 0);
9305 : 20 : CU_ASSERT(spdk_blob_get_num_clusters(clone) == 20);
9306 : :
9307 : : /* Create another snapshot after resizing the clone */
9308 : 20 : spdk_bs_create_snapshot(bs, cloneid, NULL, blob_op_with_id_complete, NULL);
9309 : 20 : poll_threads();
9310 : 20 : CU_ASSERT(g_bserrno == 0);
9311 : 20 : CU_ASSERT(g_blobid != SPDK_BLOBID_INVALID);
9312 : 20 : snapid2 = g_blobid;
9313 : :
9314 : : /* Open the snapshot blobs */
9315 : 20 : spdk_bs_open_blob(bs, snapid1, blob_op_with_handle_complete, NULL);
9316 : 20 : CU_ASSERT(g_bserrno == 0);
9317 [ + + ]: 20 : SPDK_CU_ASSERT_FATAL(g_blob != NULL);
9318 : 20 : snap_blob = g_blob;
9319 [ - + ]: 20 : CU_ASSERT(snap_blob->data_ro == true);
9320 [ - + ]: 20 : CU_ASSERT(snap_blob->md_ro == true);
9321 : 20 : CU_ASSERT(spdk_blob_get_num_clusters(snap_blob) == 10);
9322 : :
9323 : 20 : spdk_bs_open_blob(bs, snapid2, blob_op_with_handle_complete, NULL);
9324 : 20 : CU_ASSERT(g_bserrno == 0);
9325 [ + + ]: 20 : SPDK_CU_ASSERT_FATAL(g_blob != NULL);
9326 : 20 : snap_blob_rsz = g_blob;
9327 [ - + ]: 20 : CU_ASSERT(snap_blob_rsz->data_ro == true);
9328 [ - + ]: 20 : CU_ASSERT(snap_blob_rsz->md_ro == true);
9329 : 20 : CU_ASSERT(spdk_blob_get_num_clusters(snap_blob_rsz) == 20);
9330 : :
9331 : : /* Confirm that clone is backed by snap_blob_rsz, and snap_blob_rsz is backed by snap_blob */
9332 [ + + ]: 20 : SPDK_CU_ASSERT_FATAL(snap_blob->back_bs_dev == NULL);
9333 [ + + ]: 20 : SPDK_CU_ASSERT_FATAL(blob->back_bs_dev != NULL);
9334 [ - + ]: 20 : SPDK_CU_ASSERT_FATAL(snap_blob_rsz->back_bs_dev != NULL);
9335 : :
9336 : : /* Write and read from pre-resize ranges */
9337 : 20 : g_bserrno = -1;
9338 [ - + ]: 20 : memset(payload_write, 0xE5, sizeof(payload_write));
9339 : 20 : spdk_blob_io_write(clone, channel, payload_write, 5 * pages_per_cluster, 1, blob_op_complete, NULL);
9340 : 20 : poll_threads();
9341 : 20 : CU_ASSERT(g_bserrno == 0);
9342 : :
9343 : 20 : g_bserrno = -1;
9344 [ - + ]: 20 : memset(payload_read, 0x00, sizeof(payload_read));
9345 : 20 : spdk_blob_io_read(clone, channel, payload_read, 5 * pages_per_cluster, 1, blob_op_complete, NULL);
9346 : 20 : poll_threads();
9347 : 20 : CU_ASSERT(g_bserrno == 0);
9348 [ - + - + ]: 20 : CU_ASSERT(memcmp(payload_write, payload_read, BLOCKLEN) == 0);
9349 : :
9350 : : /* Write and read from post-resize ranges */
9351 : 20 : g_bserrno = -1;
9352 [ - + ]: 20 : memset(payload_write, 0xE5, sizeof(payload_write));
9353 : 20 : spdk_blob_io_write(clone, channel, payload_write, 15 * pages_per_cluster, 1, blob_op_complete,
9354 : : NULL);
9355 : 20 : poll_threads();
9356 : 20 : CU_ASSERT(g_bserrno == 0);
9357 : :
9358 : 20 : g_bserrno = -1;
9359 [ - + ]: 20 : memset(payload_read, 0x00, sizeof(payload_read));
9360 : 20 : spdk_blob_io_read(clone, channel, payload_read, 15 * pages_per_cluster, 1, blob_op_complete, NULL);
9361 : 20 : poll_threads();
9362 : 20 : CU_ASSERT(g_bserrno == 0);
9363 [ - + - + ]: 20 : CU_ASSERT(memcmp(payload_write, payload_read, bs->dev->blocklen) == 0);
9364 : :
9365 : : /* Now do full blob inflation of the resized blob/clone. */
9366 : 20 : free_clusters = spdk_bs_free_cluster_count(bs);
9367 : 20 : spdk_bs_inflate_blob(bs, channel, cloneid, blob_op_complete, NULL);
9368 : 20 : poll_threads();
9369 : 20 : CU_ASSERT(g_bserrno == 0);
9370 : : /* We wrote to 2 clusters earlier, all remaining 18 clusters in
9371 : : * blob should get allocated after inflation */
9372 : 20 : CU_ASSERT(spdk_bs_free_cluster_count(bs) == free_clusters - 18);
9373 : :
9374 : 20 : spdk_blob_close(clone, blob_op_complete, NULL);
9375 : 20 : poll_threads();
9376 : 20 : CU_ASSERT(g_bserrno == 0);
9377 : :
9378 : 20 : spdk_blob_close(snap_blob, blob_op_complete, NULL);
9379 : 20 : poll_threads();
9380 : 20 : CU_ASSERT(g_bserrno == 0);
9381 : :
9382 : 20 : spdk_blob_close(snap_blob_rsz, blob_op_complete, NULL);
9383 : 20 : poll_threads();
9384 : 20 : CU_ASSERT(g_bserrno == 0);
9385 : :
9386 : 20 : ut_blob_close_and_delete(bs, blob);
9387 : :
9388 : 20 : spdk_bs_free_io_channel(channel);
9389 : 20 : }
9390 : :
9391 : :
9392 : : static void
9393 : 20 : blob_esnap_clone_resize(void)
9394 : : {
9395 : : struct spdk_bs_dev *dev;
9396 : : struct spdk_blob_store *bs;
9397 : 15 : struct spdk_bs_opts bsopts;
9398 : 15 : struct spdk_blob_opts opts;
9399 : 15 : struct ut_esnap_opts esnap_opts;
9400 : : struct spdk_blob *blob;
9401 : 20 : uint32_t block, esnap_blksz = 512, bs_blksz = 512;
9402 : 20 : const uint32_t cluster_sz = 4 * g_phys_blocklen;
9403 : 20 : const uint64_t esnap_num_clusters = 4;
9404 : 20 : const uint32_t esnap_sz = cluster_sz * esnap_num_clusters;
9405 [ - + ]: 20 : const uint64_t esnap_num_blocks = esnap_sz / esnap_blksz;
9406 [ - + ]: 20 : uint64_t blob_num_blocks = esnap_sz / bs_blksz;
9407 : : struct spdk_io_channel *bs_ch;
9408 : :
9409 : 20 : spdk_bs_opts_init(&bsopts, sizeof(bsopts));
9410 : 20 : bsopts.cluster_sz = cluster_sz;
9411 : 20 : bsopts.esnap_bs_dev_create = ut_esnap_create;
9412 : : /* Create device with desired block size */
9413 : 20 : dev = init_dev();
9414 : 20 : dev->blocklen = bs_blksz;
9415 [ - + ]: 20 : dev->blockcnt = DEV_BUFFER_SIZE / dev->blocklen;
9416 : : /* Initialize a new blob store */
9417 : 20 : spdk_bs_init(dev, &bsopts, bs_op_with_handle_complete, NULL);
9418 : 20 : poll_threads();
9419 : 20 : CU_ASSERT(g_bserrno == 0);
9420 [ + + ]: 20 : SPDK_CU_ASSERT_FATAL(g_bs != NULL);
9421 [ + + ]: 20 : SPDK_CU_ASSERT_FATAL(g_bs->io_unit_size == bs_blksz);
9422 : 20 : bs = g_bs;
9423 : :
9424 : 20 : bs_ch = spdk_bs_alloc_io_channel(bs);
9425 [ + + ]: 20 : SPDK_CU_ASSERT_FATAL(bs_ch != NULL);
9426 : :
9427 : : /* Create and open the esnap clone */
9428 : 20 : ut_spdk_blob_opts_init(&opts);
9429 : 20 : ut_esnap_opts_init(esnap_blksz, esnap_num_blocks, __func__, NULL, &esnap_opts);
9430 : 20 : opts.esnap_id = &esnap_opts;
9431 : 20 : opts.esnap_id_len = sizeof(esnap_opts);
9432 : 20 : opts.num_clusters = esnap_num_clusters;
9433 : 20 : blob = ut_blob_create_and_open(bs, &opts);
9434 [ + + ]: 20 : SPDK_CU_ASSERT_FATAL(blob != NULL);
9435 : :
9436 : 20 : g_bserrno = -1;
9437 : 20 : spdk_blob_resize(blob, esnap_num_clusters * 2, blob_op_complete, NULL);
9438 : 20 : poll_threads();
9439 : 20 : CU_ASSERT(g_bserrno == 0);
9440 : 20 : CU_ASSERT(spdk_blob_get_num_clusters(blob) == esnap_num_clusters * 2);
9441 : :
9442 : : /* Write one blob block at a time; verify that the surrounding blocks are OK */
9443 [ - + ]: 20 : blob_num_blocks = (spdk_blob_get_num_clusters(blob) * cluster_sz) / bs_blksz;
9444 [ + + ]: 8212 : for (block = 0; block < blob_num_blocks; block++) {
9445 [ - + ]: 8192 : char buf[bs_blksz];
9446 : : union ut_word word;
9447 : 8192 : word.f.blob_id = 0xfedcba90;
9448 : 8192 : word.f.lba = block;
9449 : 8192 : ut_memset8(buf, word.num, bs_blksz);
9450 : 8192 : spdk_blob_io_write(blob, bs_ch, buf, block, 1, bs_op_complete, NULL);
9451 : 8192 : poll_threads();
9452 : 8192 : CU_ASSERT(g_bserrno == 0);
9453 [ - + ]: 8192 : if (g_bserrno != 0) {
9454 : 0 : break;
9455 : : }
9456 : : /* Read and verify the block before the current block */
9457 [ + + ]: 8192 : if (block != 0) {
9458 : 8172 : spdk_blob_io_read(blob, bs_ch, buf, block - 1, 1, bs_op_complete, NULL);
9459 : 8172 : poll_threads();
9460 : 8172 : CU_ASSERT(g_bserrno == 0);
9461 [ + + ]: 8172 : if (g_bserrno != 0) {
9462 : 0 : break;
9463 : : }
9464 : 8172 : CU_ASSERT(ut_esnap_content_is_correct(buf, bs_blksz, word.f.blob_id,
9465 : : (block - 1) * bs_blksz, bs_blksz));
9466 : 2043 : }
9467 : : /* Read and verify the current block */
9468 : 8192 : spdk_blob_io_read(blob, bs_ch, buf, block, 1, bs_op_complete, NULL);
9469 : 8192 : poll_threads();
9470 : 8192 : CU_ASSERT(g_bserrno == 0);
9471 [ - + ]: 8192 : if (g_bserrno != 0) {
9472 : 0 : break;
9473 : : }
9474 : 8192 : CU_ASSERT(ut_esnap_content_is_correct(buf, bs_blksz, word.f.blob_id,
9475 : : block * bs_blksz, bs_blksz));
9476 : : /* Check the block that follows */
9477 [ + + ]: 8192 : if (block + 1 < blob_num_blocks) {
9478 : 8172 : g_bserrno = 0xbad;
9479 : 8172 : spdk_blob_io_read(blob, bs_ch, buf, block + 1, 1, bs_op_complete, NULL);
9480 : 8172 : poll_threads();
9481 : 8172 : CU_ASSERT(g_bserrno == 0);
9482 [ - + ]: 8172 : if (g_bserrno != 0) {
9483 : 0 : break;
9484 : : }
9485 : 8172 : CU_ASSERT(ut_esnap_content_is_correct(buf, bs_blksz, blob->id,
9486 : : (block + 1) * bs_blksz,
9487 : : esnap_blksz));
9488 : 2043 : }
9489 [ - - + ]: 2048 : }
9490 : : /* Clean up */
9491 : 20 : spdk_bs_free_io_channel(bs_ch);
9492 : 20 : g_bserrno = 0xbad;
9493 : 20 : spdk_blob_close(blob, blob_op_complete, NULL);
9494 : 20 : poll_threads();
9495 : 20 : CU_ASSERT(g_bserrno == 0);
9496 : 20 : spdk_bs_unload(g_bs, bs_op_complete, NULL);
9497 : 20 : poll_threads();
9498 : 20 : CU_ASSERT(g_bserrno == 0);
9499 : 20 : g_bs = NULL;
9500 [ - + ]: 20 : memset(g_dev_buffer, 0, DEV_BUFFER_SIZE);
9501 : 20 : }
9502 : :
9503 : : static void
9504 : 40960 : bs_dev_io_complete_cb(struct spdk_io_channel *channel, void *cb_arg, int bserrno)
9505 : : {
9506 : 40960 : g_bserrno = bserrno;
9507 : 40960 : }
9508 : :
9509 : : static void
9510 : 20 : blob_shallow_copy(void)
9511 : : {
9512 : 20 : struct spdk_blob_store *bs = g_bs;
9513 : 15 : struct spdk_blob_opts blob_opts;
9514 : : struct spdk_blob *blob;
9515 : : spdk_blob_id blobid;
9516 : 20 : uint64_t num_clusters = 4;
9517 : : struct spdk_bs_dev *ext_dev;
9518 : 15 : struct spdk_bs_dev_cb_args ext_args;
9519 : : struct spdk_io_channel *bdev_ch, *blob_ch;
9520 : 15 : uint8_t buf1[DEV_BUFFER_BLOCKLEN];
9521 : 15 : uint8_t buf2[DEV_BUFFER_BLOCKLEN];
9522 : : uint64_t io_units_per_cluster;
9523 : : uint64_t offset;
9524 : : int rc;
9525 : :
9526 : 20 : blob_ch = spdk_bs_alloc_io_channel(bs);
9527 [ + + ]: 20 : SPDK_CU_ASSERT_FATAL(blob_ch != NULL);
9528 : :
9529 : : /* Set blob dimension and as thin provisioned */
9530 : 20 : ut_spdk_blob_opts_init(&blob_opts);
9531 : 20 : blob_opts.thin_provision = true;
9532 : 20 : blob_opts.num_clusters = num_clusters;
9533 : :
9534 : : /* Create a blob */
9535 : 20 : blob = ut_blob_create_and_open(bs, &blob_opts);
9536 [ + + ]: 20 : SPDK_CU_ASSERT_FATAL(blob != NULL);
9537 : 20 : blobid = spdk_blob_get_id(blob);
9538 : 20 : io_units_per_cluster = bs_io_units_per_cluster(blob);
9539 : :
9540 : : /* Write on cluster 2 and 4 of blob */
9541 [ + + ]: 5140 : for (offset = io_units_per_cluster; offset < 2 * io_units_per_cluster; offset++) {
9542 : 5120 : memset(buf1, offset, DEV_BUFFER_BLOCKLEN);
9543 : 5120 : spdk_blob_io_write(blob, blob_ch, buf1, offset, 1, blob_op_complete, NULL);
9544 : 5120 : poll_threads();
9545 : 5120 : CU_ASSERT(g_bserrno == 0);
9546 : 1280 : }
9547 [ + + ]: 5140 : for (offset = 3 * io_units_per_cluster; offset < 4 * io_units_per_cluster; offset++) {
9548 : 5120 : memset(buf1, offset, DEV_BUFFER_BLOCKLEN);
9549 : 5120 : spdk_blob_io_write(blob, blob_ch, buf1, offset, 1, blob_op_complete, NULL);
9550 : 5120 : poll_threads();
9551 : 5120 : CU_ASSERT(g_bserrno == 0);
9552 : 1280 : }
9553 : 20 : CU_ASSERT(spdk_blob_get_num_allocated_clusters(blob) == 2);
9554 : :
9555 : : /* Make a snapshot over blob */
9556 : 20 : spdk_bs_create_snapshot(bs, blobid, NULL, blob_op_with_id_complete, NULL);
9557 : 20 : poll_threads();
9558 : 20 : CU_ASSERT(g_bserrno == 0);
9559 : 20 : CU_ASSERT(spdk_blob_get_num_allocated_clusters(blob) == 0);
9560 : :
9561 : : /* Write on cluster 1 and 3 of blob */
9562 [ + + ]: 5140 : for (offset = 0; offset < io_units_per_cluster; offset++) {
9563 : 5120 : memset(buf1, offset, DEV_BUFFER_BLOCKLEN);
9564 : 5120 : spdk_blob_io_write(blob, blob_ch, buf1, offset, 1, blob_op_complete, NULL);
9565 : 5120 : poll_threads();
9566 : 5120 : CU_ASSERT(g_bserrno == 0);
9567 : 1280 : }
9568 [ + + ]: 5140 : for (offset = 2 * io_units_per_cluster; offset < 3 * io_units_per_cluster; offset++) {
9569 : 5120 : memset(buf1, offset, DEV_BUFFER_BLOCKLEN);
9570 : 5120 : spdk_blob_io_write(blob, blob_ch, buf1, offset, 1, blob_op_complete, NULL);
9571 : 5120 : poll_threads();
9572 : 5120 : CU_ASSERT(g_bserrno == 0);
9573 : 1280 : }
9574 : 20 : CU_ASSERT(spdk_blob_get_num_allocated_clusters(blob) == 2);
9575 : :
9576 : : /* Shallow copy with a not read only blob */
9577 : 20 : ext_dev = init_ext_dev(num_clusters * 1024 * 1024, DEV_BUFFER_BLOCKLEN);
9578 : 20 : rc = spdk_bs_blob_shallow_copy(bs, blob_ch, blobid, ext_dev,
9579 : : blob_shallow_copy_status_cb, NULL,
9580 : : blob_op_complete, NULL);
9581 : 20 : CU_ASSERT(rc == 0);
9582 : 20 : poll_threads();
9583 : 20 : CU_ASSERT(g_bserrno == -EPERM);
9584 : 20 : ext_dev->destroy(ext_dev);
9585 : :
9586 : : /* Set blob read only */
9587 : 20 : spdk_blob_set_read_only(blob);
9588 : 20 : spdk_blob_sync_md(blob, blob_op_complete, NULL);
9589 : 20 : poll_threads();
9590 : 20 : CU_ASSERT(g_bserrno == 0);
9591 : :
9592 : : /* Shallow copy over a spdk_bs_dev with incorrect size */
9593 : 20 : ext_dev = init_ext_dev(1, DEV_BUFFER_BLOCKLEN);
9594 : 20 : rc = spdk_bs_blob_shallow_copy(bs, blob_ch, blobid, ext_dev,
9595 : : blob_shallow_copy_status_cb, NULL,
9596 : : blob_op_complete, NULL);
9597 : 20 : CU_ASSERT(rc == 0);
9598 : 20 : poll_threads();
9599 : 20 : CU_ASSERT(g_bserrno == -EINVAL);
9600 : 20 : ext_dev->destroy(ext_dev);
9601 : :
9602 : : /* Shallow copy over a spdk_bs_dev with incorrect block len */
9603 : 20 : ext_dev = init_ext_dev(num_clusters * 1024 * 1024, DEV_BUFFER_BLOCKLEN * 2);
9604 : 20 : rc = spdk_bs_blob_shallow_copy(bs, blob_ch, blobid, ext_dev,
9605 : : blob_shallow_copy_status_cb, NULL,
9606 : : blob_op_complete, NULL);
9607 : 20 : CU_ASSERT(rc == 0);
9608 : 20 : poll_threads();
9609 : 20 : CU_ASSERT(g_bserrno == -EINVAL);
9610 : 20 : ext_dev->destroy(ext_dev);
9611 : :
9612 : : /* Initialize ext_dev for the successuful shallow copy */
9613 : 20 : ext_dev = init_ext_dev(num_clusters * 1024 * 1024, DEV_BUFFER_BLOCKLEN);
9614 : 20 : bdev_ch = ext_dev->create_channel(ext_dev);
9615 [ - + ]: 20 : SPDK_CU_ASSERT_FATAL(bdev_ch != NULL);
9616 : 20 : ext_args.cb_fn = bs_dev_io_complete_cb;
9617 [ + + ]: 20500 : for (offset = 0; offset < 4 * io_units_per_cluster; offset++) {
9618 : 20480 : memset(buf2, 0xff, DEV_BUFFER_BLOCKLEN);
9619 : 20480 : ext_dev->write(ext_dev, bdev_ch, buf2, offset, 1, &ext_args);
9620 : 20480 : poll_threads();
9621 : 20480 : CU_ASSERT(g_bserrno == 0);
9622 : 5120 : }
9623 : :
9624 : : /* Correct shallow copy of blob over bdev */
9625 : 20 : rc = spdk_bs_blob_shallow_copy(bs, blob_ch, blobid, ext_dev,
9626 : : blob_shallow_copy_status_cb, NULL,
9627 : : blob_op_complete, NULL);
9628 : 20 : CU_ASSERT(rc == 0);
9629 : 20 : poll_thread_times(0, 1);
9630 : 20 : CU_ASSERT(g_copied_clusters_count == 1);
9631 : 20 : poll_thread_times(0, 2);
9632 : 20 : CU_ASSERT(g_bserrno == 0);
9633 : 20 : CU_ASSERT(g_copied_clusters_count == 2);
9634 : :
9635 : : /* Read from bdev */
9636 : : /* Only cluster 1 and 3 must be filled */
9637 : : /* Clusters 2 and 4 should not have been touched */
9638 [ + + ]: 5140 : for (offset = 0; offset < io_units_per_cluster; offset++) {
9639 : 5120 : memset(buf1, offset, DEV_BUFFER_BLOCKLEN);
9640 : 5120 : ext_dev->read(ext_dev, bdev_ch, buf2, offset, 1, &ext_args);
9641 : 5120 : poll_threads();
9642 : 5120 : CU_ASSERT(g_bserrno == 0);
9643 : 5120 : CU_ASSERT(memcmp(buf1, buf2, DEV_BUFFER_BLOCKLEN) == 0);
9644 : 1280 : }
9645 [ + + ]: 5140 : for (offset = io_units_per_cluster; offset < 2 * io_units_per_cluster; offset++) {
9646 : 5120 : memset(buf1, 0xff, DEV_BUFFER_BLOCKLEN);
9647 : 5120 : ext_dev->read(ext_dev, bdev_ch, buf2, offset, 1, &ext_args);
9648 : 5120 : poll_threads();
9649 : 5120 : CU_ASSERT(g_bserrno == 0);
9650 : 5120 : CU_ASSERT(memcmp(buf1, buf2, DEV_BUFFER_BLOCKLEN) == 0);
9651 : 1280 : }
9652 [ + + ]: 5140 : for (offset = 2 * io_units_per_cluster; offset < 3 * io_units_per_cluster; offset++) {
9653 : 5120 : memset(buf1, offset, DEV_BUFFER_BLOCKLEN);
9654 : 5120 : ext_dev->read(ext_dev, bdev_ch, buf2, offset, 1, &ext_args);
9655 : 5120 : poll_threads();
9656 : 5120 : CU_ASSERT(g_bserrno == 0);
9657 : 5120 : CU_ASSERT(memcmp(buf1, buf2, DEV_BUFFER_BLOCKLEN) == 0);
9658 : 1280 : }
9659 [ + + ]: 5140 : for (offset = 3 * io_units_per_cluster; offset < 4 * io_units_per_cluster; offset++) {
9660 : 5120 : memset(buf1, 0xff, DEV_BUFFER_BLOCKLEN);
9661 : 5120 : ext_dev->read(ext_dev, bdev_ch, buf2, offset, 1, &ext_args);
9662 : 5120 : poll_threads();
9663 : 5120 : CU_ASSERT(g_bserrno == 0);
9664 : 5120 : CU_ASSERT(memcmp(buf1, buf2, DEV_BUFFER_BLOCKLEN) == 0);
9665 : 1280 : }
9666 : :
9667 : : /* Clean up */
9668 : 20 : ext_dev->destroy_channel(ext_dev, bdev_ch);
9669 : 20 : ext_dev->destroy(ext_dev);
9670 : 20 : spdk_bs_free_io_channel(blob_ch);
9671 : 20 : ut_blob_close_and_delete(bs, blob);
9672 : 20 : poll_threads();
9673 : 20 : }
9674 : :
9675 : : static void
9676 : 20 : blob_set_parent(void)
9677 : : {
9678 : 20 : struct spdk_blob_store *bs = g_bs;
9679 : 15 : struct spdk_blob_opts opts;
9680 : 15 : struct ut_esnap_opts esnap_opts;
9681 : : struct spdk_blob *blob1, *blob2, *blob3, *blob4, *blob5;
9682 : : spdk_blob_id blobid1, blobid2, blobid3, blobid4, blobid5,
9683 : : snapshotid1, snapshotid2, snapshotid3;
9684 : : uint32_t cluster_sz, block_sz;
9685 : 20 : const uint32_t esnap_num_clusters = 4;
9686 : : uint64_t esnap_num_blocks;
9687 : 15 : spdk_blob_id ids[2];
9688 : 20 : size_t clone_count = 2;
9689 : :
9690 : 20 : cluster_sz = spdk_bs_get_cluster_size(bs);
9691 : 20 : block_sz = spdk_bs_get_io_unit_size(bs);
9692 [ - + ]: 20 : esnap_num_blocks = cluster_sz * esnap_num_clusters / block_sz;
9693 : :
9694 : : /* Create a normal blob and make a couple of snapshots */
9695 : 20 : ut_spdk_blob_opts_init(&opts);
9696 : 20 : blob1 = ut_blob_create_and_open(bs, &opts);
9697 [ + + ]: 20 : SPDK_CU_ASSERT_FATAL(blob1 != NULL);
9698 : 20 : blobid1 = spdk_blob_get_id(blob1);
9699 : 20 : spdk_bs_create_snapshot(bs, blobid1, NULL, blob_op_with_id_complete, NULL);
9700 : 20 : poll_threads();
9701 [ + + ]: 20 : SPDK_CU_ASSERT_FATAL(g_bserrno == 0);
9702 [ + + ]: 20 : SPDK_CU_ASSERT_FATAL(g_blobid != SPDK_BLOBID_INVALID);
9703 : 20 : snapshotid1 = g_blobid;
9704 : 20 : spdk_bs_create_snapshot(bs, blobid1, NULL, blob_op_with_id_complete, NULL);
9705 : 20 : poll_threads();
9706 [ + + ]: 20 : SPDK_CU_ASSERT_FATAL(g_bserrno == 0);
9707 [ + + ]: 20 : SPDK_CU_ASSERT_FATAL(g_blobid != SPDK_BLOBID_INVALID);
9708 : 20 : snapshotid2 = g_blobid;
9709 : :
9710 : : /* Call set_parent with an invalid snapshotid */
9711 : 20 : spdk_bs_blob_set_parent(bs, blobid1, SPDK_BLOBID_INVALID, blob_op_complete, NULL);
9712 : 20 : poll_threads();
9713 : 20 : CU_ASSERT(g_bserrno == -EINVAL);
9714 : :
9715 : : /* Call set_parent with blobid and snapshotid the same */
9716 : 20 : spdk_bs_blob_set_parent(bs, blobid1, blobid1, blob_op_complete, NULL);
9717 : 20 : poll_threads();
9718 : 20 : CU_ASSERT(g_bserrno == -EINVAL);
9719 : :
9720 : : /* Call set_parent with a blob and its parent snapshot */
9721 : 20 : spdk_bs_blob_set_parent(bs, blobid1, snapshotid2, blob_op_complete, NULL);
9722 : 20 : poll_threads();
9723 : 20 : CU_ASSERT(g_bserrno == -EEXIST);
9724 : :
9725 : : /* Create an esnap clone blob */
9726 : 20 : ut_spdk_blob_opts_init(&opts);
9727 : 20 : ut_esnap_opts_init(block_sz, esnap_num_blocks, __func__, NULL, &esnap_opts);
9728 : 20 : opts.esnap_id = &esnap_opts;
9729 : 20 : opts.esnap_id_len = sizeof(esnap_opts);
9730 : 20 : opts.num_clusters = esnap_num_clusters;
9731 : 20 : blob2 = ut_blob_create_and_open(bs, &opts);
9732 [ + + ]: 20 : SPDK_CU_ASSERT_FATAL(blob2 != NULL);
9733 : 20 : blobid2 = spdk_blob_get_id(blob2);
9734 : 20 : CU_ASSERT(spdk_blob_is_esnap_clone(blob2));
9735 : :
9736 : : /* Call set_parent with a non snapshot parent */
9737 : 20 : spdk_bs_blob_set_parent(bs, blobid2, blobid1, blob_op_complete, NULL);
9738 : 20 : poll_threads();
9739 : 20 : CU_ASSERT(g_bserrno == -EINVAL);
9740 : :
9741 : : /* Call set_parent with blob and snapshot of different size */
9742 : 20 : spdk_bs_blob_set_parent(bs, blobid2, snapshotid1, blob_op_complete, NULL);
9743 : 20 : poll_threads();
9744 : 20 : CU_ASSERT(g_bserrno == -EINVAL);
9745 : :
9746 : : /* Call set_parent correctly with a snapshot's clone blob */
9747 : 20 : spdk_bs_blob_set_parent(bs, blobid1, snapshotid1, blob_op_complete, NULL);
9748 : 20 : poll_threads();
9749 : 20 : CU_ASSERT(g_bserrno == 0);
9750 : :
9751 : : /* Check relations */
9752 : 20 : CU_ASSERT(spdk_blob_is_clone(blob1));
9753 : 20 : CU_ASSERT(spdk_blob_get_parent_snapshot(bs, blobid1) == snapshotid1);
9754 : 20 : CU_ASSERT(spdk_blob_get_clones(bs, snapshotid1, ids, &clone_count) == 0);
9755 : 20 : CU_ASSERT(clone_count == 2);
9756 : 20 : CU_ASSERT(ids[1] == blobid1);
9757 : :
9758 : : /* Create another normal blob with size equal to esnap size and make a snapshot */
9759 : 20 : ut_spdk_blob_opts_init(&opts);
9760 : 20 : opts.num_clusters = esnap_num_clusters;
9761 : 20 : opts.thin_provision = true;
9762 : 20 : blob3 = ut_blob_create_and_open(bs, &opts);
9763 [ + + ]: 20 : SPDK_CU_ASSERT_FATAL(blob3 != NULL);
9764 : 20 : blobid3 = spdk_blob_get_id(blob3);
9765 : 20 : spdk_bs_create_snapshot(bs, blobid3, NULL, blob_op_with_id_complete, NULL);
9766 : 20 : poll_threads();
9767 [ + + ]: 20 : SPDK_CU_ASSERT_FATAL(g_bserrno == 0);
9768 [ + + ]: 20 : SPDK_CU_ASSERT_FATAL(g_blobid != SPDK_BLOBID_INVALID);
9769 : 20 : snapshotid3 = g_blobid;
9770 : :
9771 : : /* Call set_parent correctly with an esnap's clone blob */
9772 : 20 : spdk_bs_blob_set_parent(bs, blobid2, snapshotid3, blob_op_complete, NULL);
9773 : 20 : poll_threads();
9774 : 20 : CU_ASSERT(g_bserrno == 0);
9775 : :
9776 : : /* Check relations */
9777 : 20 : CU_ASSERT(!spdk_blob_is_esnap_clone(blob2));
9778 : 20 : CU_ASSERT(spdk_blob_is_clone(blob2));
9779 : 20 : CU_ASSERT(spdk_blob_get_parent_snapshot(bs, blobid2) == snapshotid3);
9780 : 20 : CU_ASSERT(spdk_blob_get_clones(bs, snapshotid3, ids, &clone_count) == 0);
9781 : 20 : CU_ASSERT(clone_count == 2);
9782 : 20 : CU_ASSERT(ids[1] == blobid2);
9783 : :
9784 : : /* Create a not thin-provisioned blob that is not a clone */
9785 : 20 : ut_spdk_blob_opts_init(&opts);
9786 : 20 : opts.thin_provision = false;
9787 : 20 : blob4 = ut_blob_create_and_open(bs, &opts);
9788 [ + + ]: 20 : SPDK_CU_ASSERT_FATAL(blob4 != NULL);
9789 : 20 : blobid4 = spdk_blob_get_id(blob4);
9790 : :
9791 : : /* Call set_parent with a blob that isn't a clone and that isn't thin-provisioned */
9792 : 20 : spdk_bs_blob_set_parent(bs, blobid4, snapshotid2, blob_op_complete, NULL);
9793 : 20 : poll_threads();
9794 : 20 : CU_ASSERT(g_bserrno == -EINVAL);
9795 : :
9796 : : /* Create a thin-provisioned blob that is not a clone */
9797 : 20 : ut_spdk_blob_opts_init(&opts);
9798 : 20 : opts.thin_provision = true;
9799 : 20 : blob5 = ut_blob_create_and_open(bs, &opts);
9800 [ - + ]: 20 : SPDK_CU_ASSERT_FATAL(blob5 != NULL);
9801 : 20 : blobid5 = spdk_blob_get_id(blob5);
9802 : :
9803 : : /* Call set_parent correctly with a blob that isn't a clone */
9804 : 20 : spdk_bs_blob_set_parent(bs, blobid5, snapshotid2, blob_op_complete, NULL);
9805 : 20 : poll_threads();
9806 : 20 : CU_ASSERT(g_bserrno == 0);
9807 : :
9808 : : /* Check relations */
9809 : 20 : CU_ASSERT(spdk_blob_is_clone(blob5));
9810 : 20 : CU_ASSERT(spdk_blob_get_parent_snapshot(bs, blobid5) == snapshotid2);
9811 : 20 : CU_ASSERT(spdk_blob_get_clones(bs, snapshotid2, ids, &clone_count) == 0);
9812 : 20 : CU_ASSERT(clone_count == 1);
9813 : 20 : CU_ASSERT(ids[0] == blobid5);
9814 : :
9815 : : /* Clean up */
9816 : 20 : ut_blob_close_and_delete(bs, blob5);
9817 : 20 : ut_blob_close_and_delete(bs, blob4);
9818 : 20 : ut_blob_close_and_delete(bs, blob3);
9819 : 20 : ut_blob_close_and_delete(bs, blob2);
9820 : 20 : ut_blob_close_and_delete(bs, blob1);
9821 : 20 : spdk_bs_delete_blob(bs, snapshotid3, blob_op_complete, NULL);
9822 : 20 : poll_threads();
9823 : 20 : CU_ASSERT(g_bserrno == 0);
9824 : 20 : spdk_bs_delete_blob(bs, snapshotid2, blob_op_complete, NULL);
9825 : 20 : poll_threads();
9826 : 20 : CU_ASSERT(g_bserrno == 0);
9827 : 20 : spdk_bs_delete_blob(bs, snapshotid1, blob_op_complete, NULL);
9828 : 20 : poll_threads();
9829 : 20 : CU_ASSERT(g_bserrno == 0);
9830 : 20 : }
9831 : :
9832 : : static void
9833 : 20 : blob_set_external_parent(void)
9834 : : {
9835 : 20 : struct spdk_blob_store *bs = g_bs;
9836 : 15 : struct spdk_blob_opts opts;
9837 : 15 : struct ut_esnap_opts esnap_opts, esnap_opts2;
9838 : : struct spdk_blob *blob1, *blob2, *blob3, *blob4;
9839 : 15 : spdk_blob_id blobid1, blobid2, blobid3, blobid4, snapshotid;
9840 : : uint32_t cluster_sz, block_sz;
9841 : 20 : const uint32_t esnap_num_clusters = 4;
9842 : : uint64_t esnap_num_blocks;
9843 : : struct spdk_bs_dev *esnap_dev1, *esnap_dev2, *esnap_dev3;
9844 : 15 : const void *esnap_id;
9845 : 15 : size_t esnap_id_len;
9846 : : int rc;
9847 : :
9848 : 20 : cluster_sz = spdk_bs_get_cluster_size(bs);
9849 : 20 : block_sz = spdk_bs_get_io_unit_size(bs);
9850 [ - + ]: 20 : esnap_num_blocks = cluster_sz * esnap_num_clusters / block_sz;
9851 : 20 : esnap_dev1 = init_dev();
9852 : 20 : esnap_dev2 = init_dev();
9853 : 20 : esnap_dev3 = init_dev();
9854 : :
9855 : : /* Create an esnap clone blob */
9856 : 20 : ut_spdk_blob_opts_init(&opts);
9857 : 20 : ut_esnap_opts_init(block_sz, esnap_num_blocks, __func__, NULL, &esnap_opts);
9858 : 20 : opts.esnap_id = &esnap_opts;
9859 : 20 : opts.esnap_id_len = sizeof(esnap_opts);
9860 : 20 : opts.num_clusters = esnap_num_clusters;
9861 : 20 : blob1 = ut_blob_create_and_open(bs, &opts);
9862 [ + + ]: 20 : SPDK_CU_ASSERT_FATAL(blob1 != NULL);
9863 : 20 : blobid1 = spdk_blob_get_id(blob1);
9864 : 20 : CU_ASSERT(spdk_blob_is_esnap_clone(blob1));
9865 : :
9866 : : /* Call set_esternal_parent with blobid and esnapid the same */
9867 : 20 : spdk_bs_blob_set_external_parent(bs, blobid1, esnap_dev1, &blobid1, sizeof(blobid1),
9868 : : blob_op_complete, NULL);
9869 : 20 : CU_ASSERT(g_bserrno == -EINVAL);
9870 : :
9871 : : /* Call set_external_parent with esnap of incompatible size */
9872 : 20 : esnap_dev1->blockcnt = esnap_num_blocks - 1;
9873 : 20 : spdk_bs_blob_set_external_parent(bs, blobid1, esnap_dev1, opts.esnap_id, opts.esnap_id_len,
9874 : : blob_op_complete, NULL);
9875 : 20 : CU_ASSERT(g_bserrno == -EINVAL);
9876 : :
9877 : : /* Call set_external_parent with a blob and its parent esnap */
9878 : 20 : esnap_dev1->blocklen = block_sz;
9879 : 20 : esnap_dev1->blockcnt = esnap_num_blocks;
9880 : 20 : spdk_bs_blob_set_external_parent(bs, blobid1, esnap_dev1, opts.esnap_id, opts.esnap_id_len,
9881 : : blob_op_complete, NULL);
9882 : 20 : poll_threads();
9883 : 20 : CU_ASSERT(g_bserrno == -EEXIST);
9884 : :
9885 : : /* Create a blob that is a clone of a snapshots */
9886 : 20 : ut_spdk_blob_opts_init(&opts);
9887 : 20 : blob2 = ut_blob_create_and_open(bs, &opts);
9888 [ + + ]: 20 : SPDK_CU_ASSERT_FATAL(blob2 != NULL);
9889 : 20 : blobid2 = spdk_blob_get_id(blob2);
9890 : 20 : spdk_bs_create_snapshot(bs, blobid2, NULL, blob_op_with_id_complete, NULL);
9891 : 20 : poll_threads();
9892 [ + + ]: 20 : SPDK_CU_ASSERT_FATAL(g_bserrno == 0);
9893 [ + + ]: 20 : SPDK_CU_ASSERT_FATAL(g_blobid != SPDK_BLOBID_INVALID);
9894 : 20 : snapshotid = g_blobid;
9895 : :
9896 : : /* Call set_parent correctly with a snapshot's clone blob */
9897 : 20 : esnap_dev2->blocklen = block_sz;
9898 : 20 : esnap_dev2->blockcnt = esnap_num_blocks;
9899 : 20 : ut_esnap_opts_init(block_sz, esnap_num_blocks, __func__, NULL, &esnap_opts2);
9900 : 20 : spdk_bs_blob_set_external_parent(bs, blobid2, esnap_dev2, &esnap_opts2, sizeof(esnap_opts2),
9901 : : blob_op_complete, NULL);
9902 : 20 : poll_threads();
9903 : 20 : CU_ASSERT(g_bserrno == 0);
9904 : :
9905 : : /* Check relations */
9906 : 20 : rc = spdk_blob_get_esnap_id(blob2, &esnap_id, &esnap_id_len);
9907 : 20 : CU_ASSERT(spdk_blob_is_esnap_clone(blob2));
9908 : 20 : CU_ASSERT(!spdk_blob_is_clone(blob2));
9909 [ + - + + : 20 : CU_ASSERT(rc == 0 && esnap_id_len == sizeof(esnap_opts2) &&
+ + + - ]
9910 : : memcmp(esnap_id, &esnap_opts2, esnap_id_len) == 0);
9911 : 20 : CU_ASSERT(blob2->parent_id == SPDK_BLOBID_EXTERNAL_SNAPSHOT);
9912 : :
9913 : : /* Create a not thin-provisioned blob that is not a clone */
9914 : 20 : ut_spdk_blob_opts_init(&opts);
9915 : 20 : opts.thin_provision = false;
9916 : 20 : blob3 = ut_blob_create_and_open(bs, &opts);
9917 [ + + ]: 20 : SPDK_CU_ASSERT_FATAL(blob3 != NULL);
9918 : 20 : blobid3 = spdk_blob_get_id(blob3);
9919 : :
9920 : : /* Call set_external_parent with a blob that isn't a clone and that isn't thin-provisioned */
9921 : 20 : spdk_bs_blob_set_external_parent(bs, blobid3, esnap_dev1, &esnap_opts, sizeof(esnap_opts),
9922 : : blob_op_complete, NULL);
9923 : 20 : poll_threads();
9924 : 20 : CU_ASSERT(g_bserrno == -EINVAL);
9925 : :
9926 : : /* Create a thin-provisioned blob that is not a clone */
9927 : 20 : ut_spdk_blob_opts_init(&opts);
9928 : 20 : opts.thin_provision = true;
9929 : 20 : blob4 = ut_blob_create_and_open(bs, &opts);
9930 [ - + ]: 20 : SPDK_CU_ASSERT_FATAL(blob4 != NULL);
9931 : 20 : blobid4 = spdk_blob_get_id(blob4);
9932 : :
9933 : : /* Call set_external_parent correctly with a blob that isn't a clone */
9934 : 20 : esnap_dev3->blocklen = block_sz;
9935 : 20 : esnap_dev3->blockcnt = esnap_num_blocks;
9936 : 20 : ut_esnap_opts_init(block_sz, esnap_num_blocks, __func__, NULL, &esnap_opts);
9937 : 20 : spdk_bs_blob_set_external_parent(bs, blobid4, esnap_dev3, &esnap_opts, sizeof(esnap_opts),
9938 : : blob_op_complete, NULL);
9939 : 20 : poll_threads();
9940 : 20 : CU_ASSERT(g_bserrno == 0);
9941 : :
9942 : : /* Check relations */
9943 : 20 : rc = spdk_blob_get_esnap_id(blob4, &esnap_id, &esnap_id_len);
9944 : 20 : CU_ASSERT(spdk_blob_is_esnap_clone(blob4));
9945 : 20 : CU_ASSERT(!spdk_blob_is_clone(blob4));
9946 [ + - + + : 20 : CU_ASSERT(rc == 0 && esnap_id_len == sizeof(esnap_opts) &&
+ + + - ]
9947 : : memcmp(esnap_id, &esnap_opts, esnap_id_len) == 0);
9948 : 20 : CU_ASSERT(blob4->parent_id == SPDK_BLOBID_EXTERNAL_SNAPSHOT);
9949 : :
9950 : 20 : ut_blob_close_and_delete(bs, blob4);
9951 : 20 : ut_blob_close_and_delete(bs, blob3);
9952 : 20 : ut_blob_close_and_delete(bs, blob2);
9953 : 20 : ut_blob_close_and_delete(bs, blob1);
9954 : 20 : spdk_bs_delete_blob(bs, snapshotid, blob_op_complete, NULL);
9955 : 20 : dev_destroy(esnap_dev1);
9956 : 20 : poll_threads();
9957 : 20 : CU_ASSERT(g_bserrno == 0);
9958 : 20 : }
9959 : :
9960 : : static void
9961 : 1100 : suite_bs_setup(void)
9962 : : {
9963 : : struct spdk_bs_dev *dev;
9964 : :
9965 : 1100 : dev = init_dev();
9966 [ - + ]: 1100 : memset(g_dev_buffer, 0, DEV_BUFFER_SIZE);
9967 : 1100 : spdk_bs_init(dev, NULL, bs_op_with_handle_complete, NULL);
9968 : 1100 : poll_threads();
9969 : 1100 : CU_ASSERT(g_bserrno == 0);
9970 : 1100 : CU_ASSERT(g_bs != NULL);
9971 : 1100 : }
9972 : :
9973 : : static void
9974 : 180 : suite_esnap_bs_setup(void)
9975 : : {
9976 : : struct spdk_bs_dev *dev;
9977 : 135 : struct spdk_bs_opts bs_opts;
9978 : :
9979 : 180 : dev = init_dev();
9980 [ - + ]: 180 : memset(g_dev_buffer, 0, DEV_BUFFER_SIZE);
9981 : 180 : spdk_bs_opts_init(&bs_opts, sizeof(bs_opts));
9982 : 180 : bs_opts.cluster_sz = 4 * g_phys_blocklen;
9983 : 180 : bs_opts.esnap_bs_dev_create = ut_esnap_create;
9984 : 180 : spdk_bs_init(dev, &bs_opts, bs_op_with_handle_complete, NULL);
9985 : 180 : poll_threads();
9986 : 180 : CU_ASSERT(g_bserrno == 0);
9987 [ + + ]: 180 : SPDK_CU_ASSERT_FATAL(g_bs != NULL);
9988 : 180 : }
9989 : :
9990 : : static void
9991 : 1280 : suite_bs_cleanup(void)
9992 : : {
9993 [ + - ]: 1280 : if (g_bs != NULL) {
9994 : 1280 : spdk_bs_unload(g_bs, bs_op_complete, NULL);
9995 : 1280 : poll_threads();
9996 : 1280 : CU_ASSERT(g_bserrno == 0);
9997 : 1280 : g_bs = NULL;
9998 : 320 : }
9999 [ - + ]: 1280 : memset(g_dev_buffer, 0, DEV_BUFFER_SIZE);
10000 : 1280 : }
10001 : :
10002 : : static struct spdk_blob *
10003 : 1800 : ut_blob_create_and_open(struct spdk_blob_store *bs, struct spdk_blob_opts *blob_opts)
10004 : : {
10005 : : struct spdk_blob *blob;
10006 : 1350 : struct spdk_blob_opts create_blob_opts;
10007 : : spdk_blob_id blobid;
10008 : :
10009 [ + + ]: 1800 : if (blob_opts == NULL) {
10010 : 640 : ut_spdk_blob_opts_init(&create_blob_opts);
10011 : 640 : blob_opts = &create_blob_opts;
10012 : 160 : }
10013 : :
10014 : 1800 : spdk_bs_create_blob_ext(bs, blob_opts, blob_op_with_id_complete, NULL);
10015 : 1800 : poll_threads();
10016 : 1800 : CU_ASSERT(g_bserrno == 0);
10017 : 1800 : CU_ASSERT(g_blobid != SPDK_BLOBID_INVALID);
10018 : 1800 : blobid = g_blobid;
10019 : 1800 : g_blobid = -1;
10020 : :
10021 : 1800 : spdk_bs_open_blob(bs, blobid, blob_op_with_handle_complete, NULL);
10022 : 1800 : poll_threads();
10023 : 1800 : CU_ASSERT(g_bserrno == 0);
10024 : 1800 : CU_ASSERT(g_blob != NULL);
10025 : 1800 : blob = g_blob;
10026 : :
10027 : 1800 : g_blob = NULL;
10028 : 1800 : g_bserrno = -1;
10029 : :
10030 : 1800 : return blob;
10031 : : }
10032 : :
10033 : : static void
10034 : 1600 : ut_blob_close_and_delete(struct spdk_blob_store *bs, struct spdk_blob *blob)
10035 : : {
10036 : 1600 : spdk_blob_id blobid = spdk_blob_get_id(blob);
10037 : :
10038 : 1600 : spdk_blob_close(blob, blob_op_complete, NULL);
10039 : 1600 : poll_threads();
10040 : 1600 : CU_ASSERT(g_bserrno == 0);
10041 : 1600 : g_blob = NULL;
10042 : :
10043 : 1600 : spdk_bs_delete_blob(bs, blobid, blob_op_complete, NULL);
10044 : 1600 : poll_threads();
10045 : 1600 : CU_ASSERT(g_bserrno == 0);
10046 : 1600 : g_bserrno = -1;
10047 : 1600 : }
10048 : :
10049 : : static void
10050 : 240 : suite_blob_setup(void)
10051 : : {
10052 : 240 : suite_bs_setup();
10053 : 240 : CU_ASSERT(g_bs != NULL);
10054 : :
10055 : 240 : g_blob = ut_blob_create_and_open(g_bs, NULL);
10056 : 240 : CU_ASSERT(g_blob != NULL);
10057 : 240 : }
10058 : :
10059 : : static void
10060 : 240 : suite_blob_cleanup(void)
10061 : : {
10062 : 240 : ut_blob_close_and_delete(g_bs, g_blob);
10063 : 240 : CU_ASSERT(g_blob == NULL);
10064 : :
10065 : 240 : suite_bs_cleanup();
10066 : 240 : CU_ASSERT(g_bs == NULL);
10067 : 240 : }
10068 : :
10069 : : static int
10070 : 16 : ut_setup_config_nocopy_noextent(void)
10071 : : {
10072 : 16 : g_dev_copy_enabled = false;
10073 : 16 : g_use_extent_table = false;
10074 : 16 : g_phys_blocklen = 4096;
10075 : :
10076 : 16 : return 0;
10077 : : }
10078 : :
10079 : : static int
10080 : 16 : ut_setup_config_nocopy_extent(void)
10081 : : {
10082 : 16 : g_dev_copy_enabled = false;
10083 : 16 : g_use_extent_table = true;
10084 : 16 : g_phys_blocklen = 4096;
10085 : :
10086 : 16 : return 0;
10087 : : }
10088 : :
10089 : : static int
10090 : 16 : ut_setup_config_nocopy_extent_16k_phys(void)
10091 : : {
10092 : 16 : g_dev_copy_enabled = false;
10093 : 16 : g_use_extent_table = true;
10094 : 16 : g_phys_blocklen = 16384;
10095 : :
10096 : 16 : return 0;
10097 : : }
10098 : :
10099 : :
10100 : : static int
10101 : 16 : ut_setup_config_copy_noextent(void)
10102 : : {
10103 : 16 : g_dev_copy_enabled = true;
10104 : 16 : g_use_extent_table = false;
10105 : 16 : g_phys_blocklen = 4096;
10106 : :
10107 : 16 : return 0;
10108 : : }
10109 : :
10110 : : static int
10111 : 16 : ut_setup_config_copy_extent(void)
10112 : : {
10113 : 16 : g_dev_copy_enabled = true;
10114 : 16 : g_use_extent_table = true;
10115 : 16 : g_phys_blocklen = 4096;
10116 : :
10117 : 16 : return 0;
10118 : : }
10119 : :
10120 : : struct ut_config {
10121 : : const char *suffix;
10122 : : CU_InitializeFunc setup_cb;
10123 : : };
10124 : :
10125 : : int
10126 : 4 : main(int argc, char **argv)
10127 : : {
10128 : : CU_pSuite suite, suite_bs, suite_blob, suite_esnap_bs;
10129 : : unsigned int i, num_failures;
10130 : 3 : char suite_name[4096];
10131 : : struct ut_config *config;
10132 : 4 : struct ut_config configs[] = {
10133 : : {"nocopy_noextent", ut_setup_config_nocopy_noextent},
10134 : : {"nocopy_extent", ut_setup_config_nocopy_extent},
10135 : : {"nocopy_extent_16k_phys", ut_setup_config_nocopy_extent_16k_phys},
10136 : : {"copy_noextent", ut_setup_config_copy_noextent},
10137 : : {"copy_extent", ut_setup_config_copy_extent},
10138 : : };
10139 : :
10140 : 4 : CU_initialize_registry();
10141 : :
10142 [ + + ]: 24 : for (i = 0; i < SPDK_COUNTOF(configs); ++i) {
10143 : 20 : config = &configs[i];
10144 : :
10145 [ - + ]: 20 : snprintf(suite_name, sizeof(suite_name), "blob_%s", config->suffix);
10146 : 20 : suite = CU_add_suite(suite_name, config->setup_cb, NULL);
10147 : :
10148 [ - + ]: 20 : snprintf(suite_name, sizeof(suite_name), "blob_bs_%s", config->suffix);
10149 : 20 : suite_bs = CU_add_suite_with_setup_and_teardown(suite_name, config->setup_cb, NULL,
10150 : : suite_bs_setup, suite_bs_cleanup);
10151 : :
10152 [ - + ]: 20 : snprintf(suite_name, sizeof(suite_name), "blob_blob_%s", config->suffix);
10153 : 20 : suite_blob = CU_add_suite_with_setup_and_teardown(suite_name, config->setup_cb, NULL,
10154 : : suite_blob_setup, suite_blob_cleanup);
10155 : :
10156 [ - + ]: 20 : snprintf(suite_name, sizeof(suite_name), "blob_esnap_bs_%s", config->suffix);
10157 : 20 : suite_esnap_bs = CU_add_suite_with_setup_and_teardown(suite_name, config->setup_cb, NULL,
10158 : : suite_esnap_bs_setup,
10159 : : suite_bs_cleanup);
10160 : :
10161 : 20 : CU_ADD_TEST(suite, blob_init);
10162 : 20 : CU_ADD_TEST(suite_bs, blob_open);
10163 : 20 : CU_ADD_TEST(suite_bs, blob_create);
10164 : 20 : CU_ADD_TEST(suite_bs, blob_create_loop);
10165 : 20 : CU_ADD_TEST(suite_bs, blob_create_fail);
10166 : 20 : CU_ADD_TEST(suite_bs, blob_create_internal);
10167 : 20 : CU_ADD_TEST(suite_bs, blob_create_zero_extent);
10168 : 20 : CU_ADD_TEST(suite, blob_thin_provision);
10169 : 20 : CU_ADD_TEST(suite_bs, blob_snapshot);
10170 : 20 : CU_ADD_TEST(suite_bs, blob_clone);
10171 : 20 : CU_ADD_TEST(suite_bs, blob_inflate);
10172 : 20 : CU_ADD_TEST(suite_bs, blob_delete);
10173 : 20 : CU_ADD_TEST(suite_bs, blob_resize_test);
10174 : 20 : CU_ADD_TEST(suite_bs, blob_resize_thin_test);
10175 : 20 : CU_ADD_TEST(suite, blob_read_only);
10176 : 20 : CU_ADD_TEST(suite_bs, channel_ops);
10177 : 20 : CU_ADD_TEST(suite_bs, blob_super);
10178 : 20 : CU_ADD_TEST(suite_blob, blob_write);
10179 : 20 : CU_ADD_TEST(suite_blob, blob_read);
10180 : 20 : CU_ADD_TEST(suite_blob, blob_rw_verify);
10181 : 20 : CU_ADD_TEST(suite_bs, blob_rw_verify_iov);
10182 : 20 : CU_ADD_TEST(suite_blob, blob_rw_verify_iov_nomem);
10183 : 20 : CU_ADD_TEST(suite_blob, blob_rw_iov_read_only);
10184 : 20 : CU_ADD_TEST(suite_bs, blob_unmap);
10185 : 20 : CU_ADD_TEST(suite_bs, blob_iter);
10186 : 20 : CU_ADD_TEST(suite_blob, blob_xattr);
10187 : 20 : CU_ADD_TEST(suite_bs, blob_parse_md);
10188 : 20 : CU_ADD_TEST(suite, bs_load);
10189 : 20 : CU_ADD_TEST(suite_bs, bs_load_pending_removal);
10190 : 20 : CU_ADD_TEST(suite, bs_load_custom_cluster_size);
10191 : 20 : CU_ADD_TEST(suite, bs_load_after_failed_grow);
10192 : 20 : CU_ADD_TEST(suite, bs_load_error);
10193 : 20 : CU_ADD_TEST(suite_bs, bs_unload);
10194 : 20 : CU_ADD_TEST(suite, bs_cluster_sz);
10195 : 20 : CU_ADD_TEST(suite_bs, bs_usable_clusters);
10196 : 20 : CU_ADD_TEST(suite, bs_resize_md);
10197 : 20 : CU_ADD_TEST(suite, bs_destroy);
10198 : 20 : CU_ADD_TEST(suite, bs_type);
10199 : 20 : CU_ADD_TEST(suite, bs_super_block);
10200 : 20 : CU_ADD_TEST(suite, bs_test_recover_cluster_count);
10201 : 20 : CU_ADD_TEST(suite, bs_grow_live);
10202 : 20 : CU_ADD_TEST(suite, bs_grow_live_no_space);
10203 : 20 : CU_ADD_TEST(suite, bs_test_grow);
10204 : 20 : CU_ADD_TEST(suite, blob_serialize_test);
10205 : 20 : CU_ADD_TEST(suite_bs, blob_crc);
10206 : 20 : CU_ADD_TEST(suite, super_block_crc);
10207 : 20 : CU_ADD_TEST(suite_blob, blob_dirty_shutdown);
10208 : 20 : CU_ADD_TEST(suite_bs, blob_flags);
10209 : 20 : CU_ADD_TEST(suite_bs, bs_version);
10210 : 20 : CU_ADD_TEST(suite_bs, blob_set_xattrs_test);
10211 : 20 : CU_ADD_TEST(suite_bs, blob_thin_prov_alloc);
10212 : 20 : CU_ADD_TEST(suite_bs, blob_insert_cluster_msg_test);
10213 : 20 : CU_ADD_TEST(suite_bs, blob_thin_prov_rw);
10214 : 20 : CU_ADD_TEST(suite, blob_thin_prov_write_count_io);
10215 : 20 : CU_ADD_TEST(suite, blob_thin_prov_unmap_cluster);
10216 : 20 : CU_ADD_TEST(suite_bs, blob_thin_prov_rle);
10217 : 20 : CU_ADD_TEST(suite_bs, blob_thin_prov_rw_iov);
10218 : 20 : CU_ADD_TEST(suite, bs_load_iter_test);
10219 : 20 : CU_ADD_TEST(suite_bs, blob_snapshot_rw);
10220 : 20 : CU_ADD_TEST(suite_bs, blob_snapshot_rw_iov);
10221 : 20 : CU_ADD_TEST(suite, blob_relations);
10222 : 20 : CU_ADD_TEST(suite, blob_relations2);
10223 : 20 : CU_ADD_TEST(suite, blob_relations3);
10224 : 20 : CU_ADD_TEST(suite, blobstore_clean_power_failure);
10225 : 20 : CU_ADD_TEST(suite, blob_delete_snapshot_power_failure);
10226 : 20 : CU_ADD_TEST(suite, blob_create_snapshot_power_failure);
10227 : 20 : CU_ADD_TEST(suite_bs, blob_inflate_rw);
10228 : 20 : CU_ADD_TEST(suite_bs, blob_snapshot_freeze_io);
10229 : 20 : CU_ADD_TEST(suite_bs, blob_operation_split_rw);
10230 : 20 : CU_ADD_TEST(suite_bs, blob_operation_split_rw_iov);
10231 : 20 : CU_ADD_TEST(suite, blob_io_unit);
10232 : 20 : CU_ADD_TEST(suite, blob_io_unit_compatibility);
10233 : 20 : CU_ADD_TEST(suite_bs, blob_simultaneous_operations);
10234 : 20 : CU_ADD_TEST(suite_bs, blob_persist_test);
10235 : 20 : CU_ADD_TEST(suite_bs, blob_decouple_snapshot);
10236 : 20 : CU_ADD_TEST(suite_bs, blob_seek_io_unit);
10237 : 20 : CU_ADD_TEST(suite_esnap_bs, blob_esnap_create);
10238 : 20 : CU_ADD_TEST(suite_bs, blob_nested_freezes);
10239 : 20 : CU_ADD_TEST(suite, blob_ext_md_pages);
10240 : 20 : CU_ADD_TEST(suite, blob_esnap_io_4096_4096);
10241 : 20 : CU_ADD_TEST(suite, blob_esnap_io_512_512);
10242 : 20 : CU_ADD_TEST(suite, blob_esnap_io_4096_512);
10243 : 20 : CU_ADD_TEST(suite, blob_esnap_io_512_4096);
10244 : 20 : CU_ADD_TEST(suite_esnap_bs, blob_esnap_thread_add_remove);
10245 : 20 : CU_ADD_TEST(suite_esnap_bs, blob_esnap_clone_snapshot);
10246 : 20 : CU_ADD_TEST(suite_esnap_bs, blob_esnap_clone_inflate);
10247 : 20 : CU_ADD_TEST(suite_esnap_bs, blob_esnap_clone_decouple);
10248 : 20 : CU_ADD_TEST(suite_esnap_bs, blob_esnap_clone_reload);
10249 : 20 : CU_ADD_TEST(suite_esnap_bs, blob_esnap_hotplug);
10250 : 20 : CU_ADD_TEST(suite_blob, blob_is_degraded);
10251 : 20 : CU_ADD_TEST(suite_bs, blob_clone_resize);
10252 : 20 : CU_ADD_TEST(suite, blob_esnap_clone_resize);
10253 : 20 : CU_ADD_TEST(suite_bs, blob_shallow_copy);
10254 : 20 : CU_ADD_TEST(suite_esnap_bs, blob_set_parent);
10255 : 20 : CU_ADD_TEST(suite_esnap_bs, blob_set_external_parent);
10256 : 5 : }
10257 : :
10258 : 4 : allocate_threads(2);
10259 : 4 : set_thread(0);
10260 : :
10261 : 4 : g_dev_buffer = calloc(1, DEV_BUFFER_SIZE);
10262 : :
10263 : 4 : num_failures = spdk_ut_run_tests(argc, argv, NULL);
10264 : :
10265 : 4 : free(g_dev_buffer);
10266 : :
10267 : 4 : free_threads();
10268 : :
10269 : 4 : return num_failures;
10270 : : }
|