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 : 135 : is_esnap_clone(struct spdk_blob *_blob, const void *id, size_t id_len)
71 : : {
72 : 135 : const void *val = NULL;
73 : 135 : size_t len = 0;
74 : : bool c0, c1, c2, c3;
75 : :
76 : 135 : CU_ASSERT(blob_get_xattr_value(_blob, BLOB_EXTERNAL_SNAPSHOT_ID, &val, &len,
77 : : true) == 0);
78 : 135 : CU_ASSERT((c0 = (len == id_len)));
79 [ + - + + : 135 : CU_ASSERT((c1 = (val != NULL && memcmp(val, id, len) == 0)));
- + + - ]
80 : 135 : CU_ASSERT((c2 = !!(_blob->invalid_flags & SPDK_BLOB_EXTERNAL_SNAPSHOT)));
81 : 135 : CU_ASSERT((c3 = (_blob->parent_id == SPDK_BLOBID_EXTERNAL_SNAPSHOT)));
82 : :
83 [ + - + - : 135 : return c0 && c1 && c2 && c3;
+ - + - ]
84 : : }
85 : :
86 : : static bool
87 : 75 : is_not_esnap_clone(struct spdk_blob *_blob)
88 : : {
89 : 75 : const void *val = NULL;
90 : 75 : size_t len = 0;
91 : : bool c1, c2, c3, c4;
92 : :
93 : 75 : CU_ASSERT((c1 = (blob_get_xattr_value(_blob, BLOB_EXTERNAL_SNAPSHOT_ID, &val, &len,
94 : : true) == -ENOENT)));
95 : 75 : CU_ASSERT((c2 = (val == NULL)));
96 : 75 : CU_ASSERT((c3 = ((_blob->invalid_flags & SPDK_BLOB_EXTERNAL_SNAPSHOT) == 0)));
97 : 75 : CU_ASSERT((c4 = (_blob->parent_id != SPDK_BLOBID_EXTERNAL_SNAPSHOT)));
98 : :
99 [ + - + - : 75 : 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 : 180 : _get_xattr_value(void *arg, const char *name,
107 : : const void **value, size_t *value_len)
108 : : {
109 : : uint64_t i;
110 : :
111 [ - + ]: 180 : SPDK_CU_ASSERT_FATAL(value_len != NULL);
112 [ - + ]: 180 : SPDK_CU_ASSERT_FATAL(value != NULL);
113 : 180 : CU_ASSERT(arg == &g_ctx);
114 : :
115 [ + - ]: 360 : for (i = 0; i < sizeof(g_xattr_names); i++) {
116 [ + + - + : 360 : if (!strcmp(name, g_xattr_names[i])) {
+ + ]
117 [ - + ]: 180 : *value_len = strlen(g_xattr_values[i]);
118 : 180 : *value = g_xattr_values[i];
119 : 180 : break;
120 : : }
121 : : }
122 : 180 : }
123 : :
124 : : static void
125 : 15 : _get_xattr_value_null(void *arg, const char *name,
126 : : const void **value, size_t *value_len)
127 : : {
128 [ - + ]: 15 : SPDK_CU_ASSERT_FATAL(value_len != NULL);
129 [ - + ]: 15 : SPDK_CU_ASSERT_FATAL(value != NULL);
130 : 15 : CU_ASSERT(arg == NULL);
131 : :
132 : 15 : *value_len = 0;
133 : 15 : *value = NULL;
134 : 15 : }
135 : :
136 : : static int
137 : 240 : _get_snapshots_count(struct spdk_blob_store *bs)
138 : : {
139 : 240 : struct spdk_blob_list *snapshot = NULL;
140 : 240 : int count = 0;
141 : :
142 [ + + ]: 465 : TAILQ_FOREACH(snapshot, &bs->snapshots, link) {
143 : 225 : count += 1;
144 : : }
145 : :
146 : 240 : return count;
147 : : }
148 : :
149 : : static void
150 : 5727 : ut_spdk_blob_opts_init(struct spdk_blob_opts *opts)
151 : : {
152 : 5727 : spdk_blob_opts_init(opts, sizeof(*opts));
153 [ - + ]: 5727 : opts->use_extent_table = g_use_extent_table;
154 : 5727 : }
155 : :
156 : : static void
157 : 54183 : bs_op_complete(void *cb_arg, int bserrno)
158 : : {
159 : 54183 : g_bserrno = bserrno;
160 : 54183 : }
161 : :
162 : : static void
163 : 2949 : bs_op_with_handle_complete(void *cb_arg, struct spdk_blob_store *bs,
164 : : int bserrno)
165 : : {
166 : 2949 : g_bs = bs;
167 : 2949 : g_bserrno = bserrno;
168 : 2949 : }
169 : :
170 : : static void
171 : 123708 : blob_op_complete(void *cb_arg, int bserrno)
172 : : {
173 [ + + ]: 123708 : if (cb_arg != NULL) {
174 : 75 : int *errp = cb_arg;
175 : :
176 : 75 : *errp = bserrno;
177 : : }
178 : 123708 : g_bserrno = bserrno;
179 : 123708 : }
180 : :
181 : : static void
182 : 7149 : blob_op_with_id_complete(void *cb_arg, spdk_blob_id blobid, int bserrno)
183 : : {
184 : 7149 : g_blobid = blobid;
185 : 7149 : g_bserrno = bserrno;
186 : 7149 : }
187 : :
188 : : static void
189 : 3690 : blob_op_with_handle_complete(void *cb_arg, struct spdk_blob *blb, int bserrno)
190 : : {
191 : 3690 : g_blob = blb;
192 : 3690 : g_bserrno = bserrno;
193 : 3690 : }
194 : :
195 : : static void
196 : 30 : blob_op_with_handle_complete2(void *cb_arg, struct spdk_blob *blob, int bserrno)
197 : : {
198 [ + + ]: 30 : if (g_blob == NULL) {
199 : 15 : g_blob = blob;
200 : 15 : g_bserrno = bserrno;
201 : : } else {
202 : 15 : g_blob2 = blob;
203 : 15 : g_bserrno2 = bserrno;
204 : : }
205 : 30 : }
206 : :
207 : : static void
208 : 30 : blob_shallow_copy_status_cb(uint64_t copied_clusters, void *cb_arg)
209 : : {
210 : 30 : g_copied_clusters_count = copied_clusters;
211 : 30 : }
212 : :
213 : : static void
214 : 405 : 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 : 405 : spdk_bs_unload(*bs, bs_op_complete, NULL);
220 : 405 : poll_threads();
221 : 405 : CU_ASSERT(g_bserrno == 0);
222 : :
223 : 405 : dev = init_dev();
224 : : /* Load an existing blob store */
225 : 405 : spdk_bs_load(dev, opts, bs_op_with_handle_complete, NULL);
226 : 405 : poll_threads();
227 : 405 : CU_ASSERT(g_bserrno == 0);
228 [ - + ]: 405 : SPDK_CU_ASSERT_FATAL(g_bs != NULL);
229 : 405 : *bs = g_bs;
230 : :
231 : 405 : g_bserrno = -1;
232 : 405 : }
233 : :
234 : : static void
235 : 342 : 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 : 342 : bs_free(*bs);
241 : :
242 : 342 : dev = init_dev();
243 : : /* Load an existing blob store */
244 : 342 : spdk_bs_load(dev, opts, bs_op_with_handle_complete, NULL);
245 : 342 : poll_threads();
246 : 342 : CU_ASSERT(g_bserrno == 0);
247 [ - + ]: 342 : SPDK_CU_ASSERT_FATAL(g_bs != NULL);
248 : 342 : *bs = g_bs;
249 : :
250 : 342 : g_bserrno = -1;
251 : 342 : }
252 : :
253 : : static void
254 : 15 : blob_init(void)
255 : : {
256 : : struct spdk_blob_store *bs;
257 : : struct spdk_bs_dev *dev;
258 : :
259 : 15 : dev = init_dev();
260 : :
261 : : /* should fail for an unsupported blocklen */
262 : 15 : dev->blocklen = 500;
263 : 15 : spdk_bs_init(dev, NULL, bs_op_with_handle_complete, NULL);
264 : 15 : poll_threads();
265 : 15 : CU_ASSERT(g_bserrno == -EINVAL);
266 : :
267 : 15 : dev = init_dev();
268 : 15 : spdk_bs_init(dev, NULL, bs_op_with_handle_complete, NULL);
269 : 15 : poll_threads();
270 : 15 : CU_ASSERT(g_bserrno == 0);
271 [ - + ]: 15 : SPDK_CU_ASSERT_FATAL(g_bs != NULL);
272 : 15 : bs = g_bs;
273 : :
274 : 15 : spdk_bs_unload(bs, bs_op_complete, NULL);
275 : 15 : poll_threads();
276 : 15 : CU_ASSERT(g_bserrno == 0);
277 : 15 : g_bs = NULL;
278 : 15 : }
279 : :
280 : : static void
281 : 15 : blob_super(void)
282 : : {
283 : 15 : 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 : 15 : spdk_bs_get_super(bs, blob_op_with_id_complete, NULL);
289 : 15 : poll_threads();
290 : 15 : CU_ASSERT(g_bserrno == -ENOENT);
291 : 15 : CU_ASSERT(g_blobid == SPDK_BLOBID_INVALID);
292 : :
293 : : /* Create a blob */
294 : 15 : ut_spdk_blob_opts_init(&blob_opts);
295 : 15 : spdk_bs_create_blob_ext(bs, &blob_opts, blob_op_with_id_complete, NULL);
296 : 15 : poll_threads();
297 : 15 : CU_ASSERT(g_bserrno == 0);
298 : 15 : CU_ASSERT(g_blobid != SPDK_BLOBID_INVALID);
299 : 15 : blobid = g_blobid;
300 : :
301 : : /* Set the blob as the super blob */
302 : 15 : spdk_bs_set_super(bs, blobid, blob_op_complete, NULL);
303 : 15 : poll_threads();
304 : 15 : CU_ASSERT(g_bserrno == 0);
305 : :
306 : : /* Get the super blob */
307 : 15 : spdk_bs_get_super(bs, blob_op_with_id_complete, NULL);
308 : 15 : poll_threads();
309 : 15 : CU_ASSERT(g_bserrno == 0);
310 : 15 : CU_ASSERT(blobid == g_blobid);
311 : 15 : }
312 : :
313 : : static void
314 : 15 : blob_open(void)
315 : : {
316 : 15 : 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 : 15 : ut_spdk_blob_opts_init(&blob_opts);
322 : 15 : spdk_bs_create_blob_ext(bs, &blob_opts, blob_op_with_id_complete, NULL);
323 : 15 : poll_threads();
324 : 15 : CU_ASSERT(g_bserrno == 0);
325 : 15 : CU_ASSERT(g_blobid != SPDK_BLOBID_INVALID);
326 : 15 : blobid = g_blobid;
327 : :
328 : 15 : spdk_bs_open_blob(bs, blobid, blob_op_with_handle_complete, NULL);
329 : 15 : poll_threads();
330 : 15 : CU_ASSERT(g_bserrno == 0);
331 : 15 : CU_ASSERT(g_blob != NULL);
332 : 15 : blob = g_blob;
333 : :
334 : 15 : blobid2 = spdk_blob_get_id(blob);
335 : 15 : CU_ASSERT(blobid == blobid2);
336 : :
337 : : /* Try to open file again. It should return success. */
338 : 15 : spdk_bs_open_blob(bs, blobid, blob_op_with_handle_complete, NULL);
339 : 15 : poll_threads();
340 : 15 : CU_ASSERT(g_bserrno == 0);
341 : 15 : CU_ASSERT(blob == g_blob);
342 : :
343 : 15 : spdk_blob_close(blob, blob_op_complete, NULL);
344 : 15 : poll_threads();
345 : 15 : CU_ASSERT(g_bserrno == 0);
346 : :
347 : : /*
348 : : * Close the file a second time, releasing the second reference. This
349 : : * should succeed.
350 : : */
351 : 15 : blob = g_blob;
352 : 15 : spdk_blob_close(blob, blob_op_complete, NULL);
353 : 15 : poll_threads();
354 : 15 : 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 : 15 : spdk_bs_open_blob(bs, blobid, blob_op_with_handle_complete, NULL);
361 : 15 : poll_threads();
362 : 15 : CU_ASSERT(g_bserrno == 0);
363 : 15 : CU_ASSERT(g_blob != NULL);
364 : 15 : blob = g_blob;
365 : 15 : spdk_blob_close(blob, blob_op_complete, NULL);
366 : 15 : poll_threads();
367 : 15 : CU_ASSERT(g_bserrno == 0);
368 : :
369 : : /* Try to open file twice in succession. This should return the same
370 : : * blob object.
371 : : */
372 : 15 : g_blob = NULL;
373 : 15 : g_blob2 = NULL;
374 : 15 : g_bserrno = -1;
375 : 15 : g_bserrno2 = -1;
376 : 15 : spdk_bs_open_blob(bs, blobid, blob_op_with_handle_complete2, NULL);
377 : 15 : spdk_bs_open_blob(bs, blobid, blob_op_with_handle_complete2, NULL);
378 : 15 : poll_threads();
379 : 15 : CU_ASSERT(g_bserrno == 0);
380 : 15 : CU_ASSERT(g_bserrno2 == 0);
381 : 15 : CU_ASSERT(g_blob != NULL);
382 : 15 : CU_ASSERT(g_blob2 != NULL);
383 : 15 : CU_ASSERT(g_blob == g_blob2);
384 : :
385 : 15 : g_bserrno = -1;
386 : 15 : spdk_blob_close(g_blob, blob_op_complete, NULL);
387 : 15 : poll_threads();
388 : 15 : CU_ASSERT(g_bserrno == 0);
389 : :
390 : 15 : ut_blob_close_and_delete(bs, g_blob);
391 : 15 : }
392 : :
393 : : static void
394 : 15 : blob_create(void)
395 : : {
396 : 15 : 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 : 15 : ut_spdk_blob_opts_init(&opts);
404 : 15 : opts.num_clusters = 10;
405 : :
406 : 15 : spdk_bs_create_blob_ext(bs, &opts, blob_op_with_id_complete, NULL);
407 : 15 : poll_threads();
408 : 15 : CU_ASSERT(g_bserrno == 0);
409 : 15 : CU_ASSERT(g_blobid != SPDK_BLOBID_INVALID);
410 : 15 : blobid = g_blobid;
411 : :
412 : 15 : spdk_bs_open_blob(bs, blobid, blob_op_with_handle_complete, NULL);
413 : 15 : poll_threads();
414 : 15 : CU_ASSERT(g_bserrno == 0);
415 [ - + ]: 15 : SPDK_CU_ASSERT_FATAL(g_blob != NULL);
416 : 15 : blob = g_blob;
417 : 15 : CU_ASSERT(spdk_blob_get_num_clusters(blob) == 10);
418 : 15 : CU_ASSERT(spdk_blob_get_num_allocated_clusters(blob) == 10);
419 : :
420 : 15 : spdk_blob_close(blob, blob_op_complete, NULL);
421 : 15 : poll_threads();
422 : 15 : CU_ASSERT(g_bserrno == 0);
423 : :
424 : : /* Create blob with 0 clusters */
425 : :
426 : 15 : ut_spdk_blob_opts_init(&opts);
427 : 15 : opts.num_clusters = 0;
428 : :
429 : 15 : spdk_bs_create_blob_ext(bs, &opts, blob_op_with_id_complete, NULL);
430 : 15 : poll_threads();
431 : 15 : CU_ASSERT(g_bserrno == 0);
432 : 15 : CU_ASSERT(g_blobid != SPDK_BLOBID_INVALID);
433 : 15 : blobid = g_blobid;
434 : :
435 : 15 : spdk_bs_open_blob(bs, blobid, blob_op_with_handle_complete, NULL);
436 : 15 : poll_threads();
437 : 15 : CU_ASSERT(g_bserrno == 0);
438 [ - + ]: 15 : SPDK_CU_ASSERT_FATAL(g_blob != NULL);
439 : 15 : blob = g_blob;
440 : 15 : CU_ASSERT(spdk_blob_get_num_clusters(blob) == 0);
441 : 15 : CU_ASSERT(spdk_blob_get_num_allocated_clusters(blob) == 0);
442 : :
443 : 15 : spdk_blob_close(blob, blob_op_complete, NULL);
444 : 15 : poll_threads();
445 : 15 : CU_ASSERT(g_bserrno == 0);
446 : :
447 : : /* Create blob with default options (opts == NULL) */
448 : :
449 : 15 : spdk_bs_create_blob_ext(bs, NULL, blob_op_with_id_complete, NULL);
450 : 15 : poll_threads();
451 : 15 : CU_ASSERT(g_bserrno == 0);
452 : 15 : CU_ASSERT(g_blobid != SPDK_BLOBID_INVALID);
453 : 15 : blobid = g_blobid;
454 : :
455 : 15 : spdk_bs_open_blob(bs, blobid, blob_op_with_handle_complete, NULL);
456 : 15 : poll_threads();
457 : 15 : CU_ASSERT(g_bserrno == 0);
458 [ - + ]: 15 : SPDK_CU_ASSERT_FATAL(g_blob != NULL);
459 : 15 : blob = g_blob;
460 : 15 : CU_ASSERT(spdk_blob_get_num_clusters(blob) == 0);
461 : 15 : CU_ASSERT(spdk_blob_get_num_allocated_clusters(blob) == 0);
462 : :
463 : 15 : spdk_blob_close(blob, blob_op_complete, NULL);
464 : 15 : poll_threads();
465 : 15 : CU_ASSERT(g_bserrno == 0);
466 : :
467 : : /* Try to create blob with size larger than blobstore */
468 : :
469 : 15 : ut_spdk_blob_opts_init(&opts);
470 : 15 : opts.num_clusters = bs->total_clusters + 1;
471 : :
472 : 15 : spdk_bs_create_blob_ext(bs, &opts, blob_op_with_id_complete, NULL);
473 : 15 : poll_threads();
474 : 15 : CU_ASSERT(g_bserrno == -ENOSPC);
475 : 15 : }
476 : :
477 : : static void
478 : 15 : blob_create_zero_extent(void)
479 : : {
480 : 15 : 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 : 15 : spdk_bs_create_blob_ext(bs, NULL, blob_op_with_id_complete, NULL);
486 : 15 : poll_threads();
487 : 15 : CU_ASSERT(g_bserrno == 0);
488 : 15 : CU_ASSERT(g_blobid != SPDK_BLOBID_INVALID);
489 : 15 : blobid = g_blobid;
490 : :
491 : 15 : spdk_bs_open_blob(bs, blobid, blob_op_with_handle_complete, NULL);
492 : 15 : poll_threads();
493 : 15 : CU_ASSERT(g_bserrno == 0);
494 [ - + ]: 15 : SPDK_CU_ASSERT_FATAL(g_blob != NULL);
495 : 15 : blob = g_blob;
496 : 15 : CU_ASSERT(spdk_blob_get_num_clusters(blob) == 0);
497 [ - + ]: 15 : CU_ASSERT(blob->extent_table_found == true);
498 : 15 : CU_ASSERT(blob->active.extent_pages_array_size == 0);
499 : 15 : CU_ASSERT(blob->active.extent_pages == NULL);
500 : :
501 : 15 : spdk_blob_close(blob, blob_op_complete, NULL);
502 : 15 : poll_threads();
503 : 15 : CU_ASSERT(g_bserrno == 0);
504 : :
505 : : /* Create blob with NULL internal options */
506 : 15 : bs_create_blob(bs, NULL, NULL, blob_op_with_id_complete, NULL);
507 : 15 : poll_threads();
508 : 15 : CU_ASSERT(g_bserrno == 0);
509 : 15 : CU_ASSERT(g_blobid != SPDK_BLOBID_INVALID);
510 : 15 : blobid = g_blobid;
511 : :
512 : 15 : spdk_bs_open_blob(bs, blobid, blob_op_with_handle_complete, NULL);
513 : 15 : poll_threads();
514 : 15 : CU_ASSERT(g_bserrno == 0);
515 [ - + ]: 15 : SPDK_CU_ASSERT_FATAL(g_blob != NULL);
516 : 15 : blob = g_blob;
517 : 15 : CU_ASSERT(TAILQ_FIRST(&blob->xattrs_internal) == NULL);
518 : 15 : CU_ASSERT(spdk_blob_get_num_clusters(blob) == 0);
519 [ - + ]: 15 : CU_ASSERT(blob->extent_table_found == true);
520 : 15 : CU_ASSERT(blob->active.extent_pages_array_size == 0);
521 : 15 : CU_ASSERT(blob->active.extent_pages == NULL);
522 : :
523 : 15 : spdk_blob_close(blob, blob_op_complete, NULL);
524 : 15 : poll_threads();
525 : 15 : CU_ASSERT(g_bserrno == 0);
526 : 15 : }
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 : 15 : blob_create_loop(void)
535 : : {
536 : 15 : struct spdk_blob_store *bs = g_bs;
537 : 15 : struct spdk_blob_opts opts;
538 : : uint32_t i, loop_count;
539 : :
540 [ - + ]: 15 : loop_count = 4 * spdk_max(spdk_bit_array_capacity(bs->used_md_pages),
541 : : spdk_bit_pool_capacity(bs->used_clusters));
542 : :
543 [ + + ]: 3855 : for (i = 0; i < loop_count; i++) {
544 : 3840 : ut_spdk_blob_opts_init(&opts);
545 : 3840 : opts.num_clusters = 1;
546 : 3840 : g_bserrno = -1;
547 : 3840 : g_blobid = SPDK_BLOBID_INVALID;
548 : 3840 : spdk_bs_create_blob_ext(bs, &opts, blob_op_with_id_complete, NULL);
549 : 3840 : poll_threads();
550 : 3840 : CU_ASSERT(g_bserrno == 0);
551 : 3840 : CU_ASSERT(g_blobid != SPDK_BLOBID_INVALID);
552 : 3840 : spdk_bs_delete_blob(bs, g_blobid, blob_op_complete, NULL);
553 : 3840 : poll_threads();
554 : 3840 : CU_ASSERT(g_bserrno == 0);
555 : : }
556 : 15 : }
557 : :
558 : : static void
559 : 15 : blob_create_fail(void)
560 : : {
561 : 15 : struct spdk_blob_store *bs = g_bs;
562 : 15 : struct spdk_blob_opts opts;
563 : : spdk_blob_id blobid;
564 : 15 : uint32_t used_blobids_count = spdk_bit_array_count_set(bs->used_blobids);
565 : 15 : uint32_t used_md_pages_count = spdk_bit_array_count_set(bs->used_md_pages);
566 : :
567 : : /* NULL callback */
568 : 15 : ut_spdk_blob_opts_init(&opts);
569 : 15 : opts.xattrs.names = g_xattr_names;
570 : 15 : opts.xattrs.get_value = NULL;
571 : 15 : opts.xattrs.count = 1;
572 : 15 : opts.xattrs.ctx = &g_ctx;
573 : :
574 : 15 : blobid = spdk_bit_array_find_first_clear(bs->used_md_pages, 0);
575 : 15 : spdk_bs_create_blob_ext(bs, &opts, blob_op_with_id_complete, NULL);
576 : 15 : poll_threads();
577 : 15 : CU_ASSERT(g_bserrno == -EINVAL);
578 : 15 : CU_ASSERT(g_blobid != SPDK_BLOBID_INVALID);
579 : 15 : CU_ASSERT(spdk_bit_array_count_set(bs->used_blobids) == used_blobids_count);
580 : 15 : CU_ASSERT(spdk_bit_array_count_set(bs->used_md_pages) == used_md_pages_count);
581 : :
582 : 15 : spdk_bs_open_blob(bs, blobid, blob_op_with_handle_complete, NULL);
583 : 15 : poll_threads();
584 : 15 : CU_ASSERT(g_bserrno == -ENOENT);
585 [ - + ]: 15 : SPDK_CU_ASSERT_FATAL(g_blob == NULL);
586 : :
587 : 15 : ut_bs_reload(&bs, NULL);
588 : 15 : CU_ASSERT(spdk_bit_array_count_set(bs->used_blobids) == used_blobids_count);
589 : 15 : CU_ASSERT(spdk_bit_array_count_set(bs->used_md_pages) == used_md_pages_count);
590 : :
591 : 15 : spdk_bs_iter_first(bs, blob_op_with_handle_complete, NULL);
592 : 15 : poll_threads();
593 : 15 : CU_ASSERT(g_blob == NULL);
594 : 15 : CU_ASSERT(g_bserrno == -ENOENT);
595 : 15 : }
596 : :
597 : : static void
598 : 15 : blob_create_internal(void)
599 : : {
600 : 15 : 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 : 15 : ut_spdk_blob_opts_init(&opts);
612 : 15 : blob_xattrs_init(&internal_xattrs);
613 : 15 : internal_xattrs.count = 3;
614 : 15 : internal_xattrs.names = g_xattr_names;
615 : 15 : internal_xattrs.get_value = _get_xattr_value;
616 : 15 : internal_xattrs.ctx = &g_ctx;
617 : :
618 : 15 : bs_create_blob(bs, &opts, &internal_xattrs, blob_op_with_id_complete, NULL);
619 : 15 : poll_threads();
620 : 15 : CU_ASSERT(g_bserrno == 0);
621 : 15 : CU_ASSERT(g_blobid != SPDK_BLOBID_INVALID);
622 : 15 : blobid = g_blobid;
623 : :
624 : 15 : spdk_bs_open_blob(bs, blobid, blob_op_with_handle_complete, NULL);
625 : 15 : poll_threads();
626 : 15 : CU_ASSERT(g_bserrno == 0);
627 [ - + ]: 15 : SPDK_CU_ASSERT_FATAL(g_blob != NULL);
628 : 15 : blob = g_blob;
629 : :
630 : 15 : rc = blob_get_xattr_value(blob, g_xattr_names[0], &value, &value_len, true);
631 : 15 : CU_ASSERT(rc == 0);
632 [ - + ]: 15 : SPDK_CU_ASSERT_FATAL(value != NULL);
633 [ - + ]: 15 : CU_ASSERT(value_len == strlen(g_xattr_values[0]));
634 [ - + - + ]: 15 : CU_ASSERT_NSTRING_EQUAL_FATAL(value, g_xattr_values[0], value_len);
635 : :
636 : 15 : rc = blob_get_xattr_value(blob, g_xattr_names[1], &value, &value_len, true);
637 : 15 : CU_ASSERT(rc == 0);
638 [ - + ]: 15 : SPDK_CU_ASSERT_FATAL(value != NULL);
639 [ - + ]: 15 : CU_ASSERT(value_len == strlen(g_xattr_values[1]));
640 [ - + - + ]: 15 : CU_ASSERT_NSTRING_EQUAL((char *)value, g_xattr_values[1], value_len);
641 : :
642 : 15 : rc = blob_get_xattr_value(blob, g_xattr_names[2], &value, &value_len, true);
643 : 15 : CU_ASSERT(rc == 0);
644 [ - + ]: 15 : SPDK_CU_ASSERT_FATAL(value != NULL);
645 [ - + ]: 15 : CU_ASSERT(value_len == strlen(g_xattr_values[2]));
646 [ - + - + ]: 15 : CU_ASSERT_NSTRING_EQUAL((char *)value, g_xattr_values[2], value_len);
647 : :
648 : 15 : rc = spdk_blob_get_xattr_value(blob, g_xattr_names[0], &value, &value_len);
649 : 15 : CU_ASSERT(rc != 0);
650 : :
651 : 15 : rc = spdk_blob_get_xattr_value(blob, g_xattr_names[1], &value, &value_len);
652 : 15 : CU_ASSERT(rc != 0);
653 : :
654 : 15 : rc = spdk_blob_get_xattr_value(blob, g_xattr_names[2], &value, &value_len);
655 : 15 : CU_ASSERT(rc != 0);
656 : :
657 : 15 : spdk_blob_close(blob, blob_op_complete, NULL);
658 : 15 : poll_threads();
659 : 15 : CU_ASSERT(g_bserrno == 0);
660 : :
661 : : /* Create blob with NULL internal options */
662 : :
663 : 15 : bs_create_blob(bs, NULL, NULL, blob_op_with_id_complete, NULL);
664 : 15 : poll_threads();
665 : 15 : CU_ASSERT(g_bserrno == 0);
666 : 15 : CU_ASSERT(g_blobid != SPDK_BLOBID_INVALID);
667 : 15 : blobid = g_blobid;
668 : :
669 : 15 : spdk_bs_open_blob(bs, blobid, blob_op_with_handle_complete, NULL);
670 : 15 : poll_threads();
671 : 15 : CU_ASSERT(g_bserrno == 0);
672 [ - + ]: 15 : SPDK_CU_ASSERT_FATAL(g_blob != NULL);
673 : 15 : CU_ASSERT(TAILQ_FIRST(&g_blob->xattrs_internal) == NULL);
674 : 15 : CU_ASSERT(spdk_blob_get_num_clusters(g_blob) == 0);
675 : :
676 : 15 : blob = g_blob;
677 : :
678 : 15 : spdk_blob_close(blob, blob_op_complete, NULL);
679 : 15 : poll_threads();
680 : 15 : CU_ASSERT(g_bserrno == 0);
681 : 15 : }
682 : :
683 : : static void
684 : 15 : 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 : 15 : dev = init_dev();
694 : 15 : spdk_bs_opts_init(&bs_opts, sizeof(bs_opts));
695 [ - + ]: 15 : snprintf(bs_opts.bstype.bstype, sizeof(bs_opts.bstype.bstype), "TESTTYPE");
696 : :
697 : : /* Initialize a new blob store */
698 : 15 : spdk_bs_init(dev, &bs_opts, bs_op_with_handle_complete, NULL);
699 : 15 : poll_threads();
700 : 15 : CU_ASSERT(g_bserrno == 0);
701 [ - + ]: 15 : SPDK_CU_ASSERT_FATAL(g_bs != NULL);
702 : :
703 : 15 : bs = g_bs;
704 : :
705 : : /* Create blob with thin provisioning enabled */
706 : :
707 : 15 : ut_spdk_blob_opts_init(&opts);
708 : 15 : opts.thin_provision = true;
709 : 15 : opts.num_clusters = 10;
710 : :
711 : 15 : blob = ut_blob_create_and_open(bs, &opts);
712 : 15 : blobid = spdk_blob_get_id(blob);
713 : 15 : CU_ASSERT(blob->invalid_flags & SPDK_BLOB_THIN_PROV);
714 : 15 : 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 [ + + + + ]: 15 : if (blob->extent_table_found == true) {
719 : 9 : CU_ASSERT(blob->active.extent_pages_array_size > 0);
720 : 9 : CU_ASSERT(blob->active.extent_pages != NULL);
721 : : } else {
722 : 6 : CU_ASSERT(blob->active.extent_pages_array_size == 0);
723 : 6 : CU_ASSERT(blob->active.extent_pages == NULL);
724 : : }
725 : :
726 : 15 : spdk_blob_close(blob, blob_op_complete, NULL);
727 : 15 : 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 : 15 : ut_bs_dirty_load(&bs, &bs_opts);
734 : :
735 : 15 : spdk_bs_open_blob(bs, blobid, blob_op_with_handle_complete, NULL);
736 : 15 : poll_threads();
737 : 15 : CU_ASSERT(g_bserrno == 0);
738 [ - + ]: 15 : SPDK_CU_ASSERT_FATAL(g_blob != NULL);
739 : 15 : blob = g_blob;
740 : 15 : CU_ASSERT(blob->invalid_flags & SPDK_BLOB_THIN_PROV);
741 : 15 : CU_ASSERT(spdk_blob_get_num_allocated_clusters(blob) == 0);
742 : :
743 : 15 : ut_blob_close_and_delete(bs, blob);
744 : :
745 : 15 : spdk_bs_unload(bs, bs_op_complete, NULL);
746 : 15 : poll_threads();
747 : 15 : CU_ASSERT(g_bserrno == 0);
748 : 15 : g_bs = NULL;
749 : 15 : }
750 : :
751 : : static void
752 : 15 : blob_snapshot(void)
753 : : {
754 : 15 : 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 : 15 : ut_spdk_blob_opts_init(&opts);
771 : 15 : opts.num_clusters = 10;
772 : :
773 : 15 : blob = ut_blob_create_and_open(bs, &opts);
774 : 15 : blobid = spdk_blob_get_id(blob);
775 : 15 : CU_ASSERT(spdk_blob_get_num_clusters(blob) == 10);
776 : :
777 : : /* Create snapshot from blob */
778 : 15 : CU_ASSERT_EQUAL(_get_snapshots_count(bs), 0);
779 : 15 : spdk_bs_create_snapshot(bs, blobid, NULL, blob_op_with_id_complete, NULL);
780 : 15 : poll_threads();
781 : 15 : CU_ASSERT(g_bserrno == 0);
782 : 15 : CU_ASSERT(g_blobid != SPDK_BLOBID_INVALID);
783 : 15 : CU_ASSERT_EQUAL(_get_snapshots_count(bs), 1);
784 : 15 : snapshotid = g_blobid;
785 : :
786 : 15 : spdk_bs_open_blob(bs, snapshotid, blob_op_with_handle_complete, NULL);
787 : 15 : poll_threads();
788 : 15 : CU_ASSERT(g_bserrno == 0);
789 [ - + ]: 15 : SPDK_CU_ASSERT_FATAL(g_blob != NULL);
790 : 15 : snapshot = g_blob;
791 [ - + ]: 15 : CU_ASSERT(snapshot->data_ro == true);
792 [ - + ]: 15 : CU_ASSERT(snapshot->md_ro == true);
793 : 15 : CU_ASSERT(spdk_blob_get_num_clusters(snapshot) == 10);
794 : 15 : CU_ASSERT(spdk_blob_get_num_allocated_clusters(snapshot) == 10);
795 : :
796 : 15 : CU_ASSERT(spdk_blob_get_num_clusters(blob) == 10);
797 : 15 : CU_ASSERT(spdk_blob_get_num_allocated_clusters(blob) == 0);
798 : 15 : CU_ASSERT(blob->invalid_flags & SPDK_BLOB_THIN_PROV);
799 : 15 : 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 : 15 : xattrs.names = g_xattr_names;
804 : 15 : xattrs.get_value = _get_xattr_value;
805 : 15 : xattrs.count = 3;
806 : 15 : xattrs.ctx = &g_ctx;
807 : 15 : spdk_bs_create_snapshot(bs, blobid, &xattrs, blob_op_with_id_complete, NULL);
808 : 15 : poll_threads();
809 : 15 : CU_ASSERT(g_bserrno == 0);
810 : 15 : CU_ASSERT(g_blobid != SPDK_BLOBID_INVALID);
811 : 15 : CU_ASSERT_EQUAL(_get_snapshots_count(bs), 2);
812 : 15 : snapshotid2 = g_blobid;
813 : :
814 : 15 : spdk_bs_open_blob(bs, snapshotid2, blob_op_with_handle_complete, NULL);
815 : 15 : CU_ASSERT(g_bserrno == 0);
816 [ - + ]: 15 : SPDK_CU_ASSERT_FATAL(g_blob != NULL);
817 : 15 : snapshot2 = g_blob;
818 [ - + ]: 15 : CU_ASSERT(snapshot2->data_ro == true);
819 [ - + ]: 15 : CU_ASSERT(snapshot2->md_ro == true);
820 : 15 : CU_ASSERT(spdk_blob_get_num_clusters(snapshot2) == 10);
821 : 15 : 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 : 15 : CU_ASSERT(snapshot->back_bs_dev == NULL);
825 [ - + ]: 15 : SPDK_CU_ASSERT_FATAL(blob->back_bs_dev != NULL);
826 [ - + ]: 15 : SPDK_CU_ASSERT_FATAL(snapshot2->back_bs_dev != NULL);
827 : :
828 : 15 : blob_bs_dev = (struct spdk_blob_bs_dev *)blob->back_bs_dev;
829 : 15 : CU_ASSERT(blob_bs_dev->blob == snapshot2);
830 : :
831 : 15 : blob_bs_dev = (struct spdk_blob_bs_dev *)snapshot2->back_bs_dev;
832 : 15 : CU_ASSERT(blob_bs_dev->blob == snapshot);
833 : :
834 : 15 : rc = spdk_blob_get_xattr_value(snapshot2, g_xattr_names[0], &value, &value_len);
835 : 15 : CU_ASSERT(rc == 0);
836 [ - + ]: 15 : SPDK_CU_ASSERT_FATAL(value != NULL);
837 [ - + ]: 15 : CU_ASSERT(value_len == strlen(g_xattr_values[0]));
838 [ - + - + ]: 15 : CU_ASSERT_NSTRING_EQUAL_FATAL(value, g_xattr_values[0], value_len);
839 : :
840 : 15 : rc = spdk_blob_get_xattr_value(snapshot2, g_xattr_names[1], &value, &value_len);
841 : 15 : CU_ASSERT(rc == 0);
842 [ - + ]: 15 : SPDK_CU_ASSERT_FATAL(value != NULL);
843 [ - + ]: 15 : CU_ASSERT(value_len == strlen(g_xattr_values[1]));
844 [ - + - + ]: 15 : CU_ASSERT_NSTRING_EQUAL((char *)value, g_xattr_values[1], value_len);
845 : :
846 : 15 : rc = spdk_blob_get_xattr_value(snapshot2, g_xattr_names[2], &value, &value_len);
847 : 15 : CU_ASSERT(rc == 0);
848 [ - + ]: 15 : SPDK_CU_ASSERT_FATAL(value != NULL);
849 [ - + ]: 15 : CU_ASSERT(value_len == strlen(g_xattr_values[2]));
850 [ - + - + ]: 15 : 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 : 15 : count = 2;
854 : 15 : CU_ASSERT(spdk_blob_get_clones(bs, snapshotid2, ids, &count) == 0);
855 : 15 : CU_ASSERT(count == 1);
856 : 15 : CU_ASSERT(ids[0] == blobid);
857 : :
858 : 15 : count = 2;
859 : 15 : CU_ASSERT(spdk_blob_get_clones(bs, snapshotid, ids, &count) == 0);
860 : 15 : CU_ASSERT(count == 1);
861 : 15 : CU_ASSERT(ids[0] == snapshotid2);
862 : :
863 : : /* Try to create snapshot from snapshot */
864 : 15 : spdk_bs_create_snapshot(bs, snapshotid, NULL, blob_op_with_id_complete, NULL);
865 : 15 : poll_threads();
866 : 15 : CU_ASSERT(g_bserrno == -EINVAL);
867 : 15 : CU_ASSERT(g_blobid == SPDK_BLOBID_INVALID);
868 : 15 : CU_ASSERT_EQUAL(_get_snapshots_count(bs), 2);
869 : :
870 : : /* Delete blob and confirm that it is no longer on snapshot2 clone list */
871 : 15 : ut_blob_close_and_delete(bs, blob);
872 : 15 : count = 2;
873 : 15 : CU_ASSERT(spdk_blob_get_clones(bs, snapshotid2, ids, &count) == 0);
874 : 15 : CU_ASSERT(count == 0);
875 : :
876 : : /* Delete snapshot2 and confirm that it is no longer on snapshot clone list */
877 : 15 : ut_blob_close_and_delete(bs, snapshot2);
878 : 15 : CU_ASSERT_EQUAL(_get_snapshots_count(bs), 1);
879 : 15 : count = 2;
880 : 15 : CU_ASSERT(spdk_blob_get_clones(bs, snapshotid2, ids, &count) == 0);
881 : 15 : CU_ASSERT(count == 0);
882 : :
883 : 15 : ut_blob_close_and_delete(bs, snapshot);
884 : 15 : CU_ASSERT_EQUAL(_get_snapshots_count(bs), 0);
885 : 15 : }
886 : :
887 : : static void
888 : 15 : blob_snapshot_freeze_io(void)
889 : 15 : {
890 : : struct spdk_io_channel *channel;
891 : : struct spdk_bs_channel *bs_channel;
892 : 15 : 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 : 15 : uint32_t num_of_pages = 10;
897 [ - + ]: 15 : uint8_t payload_read[num_of_pages * BLOCKLEN];
898 [ - + ]: 15 : uint8_t payload_write[num_of_pages * BLOCKLEN];
899 [ - + ]: 15 : uint8_t payload_zero[num_of_pages * BLOCKLEN];
900 : :
901 [ - + ]: 15 : memset(payload_write, 0xE5, sizeof(payload_write));
902 [ - + ]: 15 : memset(payload_read, 0x00, sizeof(payload_read));
903 [ - + ]: 15 : memset(payload_zero, 0x00, sizeof(payload_zero));
904 : :
905 : : /* Test freeze I/O during snapshot */
906 : 15 : channel = spdk_bs_alloc_io_channel(bs);
907 : 15 : bs_channel = spdk_io_channel_get_ctx(channel);
908 : :
909 : : /* Create blob with 10 clusters */
910 : 15 : ut_spdk_blob_opts_init(&opts);
911 : 15 : opts.num_clusters = 10;
912 : 15 : opts.thin_provision = false;
913 : :
914 : 15 : blob = ut_blob_create_and_open(bs, &opts);
915 : 15 : blobid = spdk_blob_get_id(blob);
916 : 15 : CU_ASSERT(spdk_blob_get_num_clusters(blob) == 10);
917 : :
918 : 15 : 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 : 15 : poll_thread_times(0, 5);
924 : :
925 : 15 : CU_ASSERT(TAILQ_EMPTY(&bs_channel->queued_io));
926 : :
927 : : /* Blob I/O should be frozen here */
928 : 15 : CU_ASSERT(blob->frozen_refcnt == 1);
929 : :
930 : : /* Write to the blob */
931 : 15 : 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 : 15 : 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 : 15 : CU_ASSERT(blob->active.clusters[0] == 0);
937 : :
938 : : /* Finish all operations including spdk_bs_create_snapshot */
939 : 15 : poll_threads();
940 : :
941 : : /* Verify snapshot */
942 : 15 : CU_ASSERT(g_bserrno == 0);
943 : 15 : CU_ASSERT(g_blobid != SPDK_BLOBID_INVALID);
944 : :
945 : : /* Verify that blob has unset frozen_io */
946 : 15 : CU_ASSERT(blob->frozen_refcnt == 0);
947 : :
948 : : /* Verify that postponed I/O completed successfully by comparing payload */
949 : 15 : spdk_blob_io_read(blob, channel, payload_read, 0, num_of_pages, blob_op_complete, NULL);
950 : 15 : poll_threads();
951 : 15 : CU_ASSERT(g_bserrno == 0);
952 [ - + - + ]: 15 : CU_ASSERT(memcmp(payload_write, payload_read, num_of_pages * BLOCKLEN) == 0);
953 : :
954 : 15 : spdk_bs_free_io_channel(channel);
955 : 15 : poll_threads();
956 : :
957 : 15 : ut_blob_close_and_delete(bs, blob);
958 : 15 : }
959 : :
960 : : static void
961 : 15 : blob_clone(void)
962 : : {
963 : 15 : 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 : 15 : ut_spdk_blob_opts_init(&opts);
975 : 15 : opts.num_clusters = 10;
976 : :
977 : 15 : blob = ut_blob_create_and_open(bs, &opts);
978 : 15 : blobid = spdk_blob_get_id(blob);
979 : 15 : CU_ASSERT(spdk_blob_get_num_clusters(blob) == 10);
980 : :
981 : : /* Create snapshot */
982 : 15 : spdk_bs_create_snapshot(bs, blobid, NULL, blob_op_with_id_complete, NULL);
983 : 15 : poll_threads();
984 : 15 : CU_ASSERT(g_bserrno == 0);
985 : 15 : CU_ASSERT(g_blobid != SPDK_BLOBID_INVALID);
986 : 15 : snapshotid = g_blobid;
987 : :
988 : 15 : spdk_bs_open_blob(bs, snapshotid, blob_op_with_handle_complete, NULL);
989 : 15 : poll_threads();
990 : 15 : CU_ASSERT(g_bserrno == 0);
991 [ - + ]: 15 : SPDK_CU_ASSERT_FATAL(g_blob != NULL);
992 : 15 : snapshot = g_blob;
993 [ - + ]: 15 : CU_ASSERT(snapshot->data_ro == true);
994 [ - + ]: 15 : CU_ASSERT(snapshot->md_ro == true);
995 : 15 : CU_ASSERT(spdk_blob_get_num_clusters(snapshot) == 10);
996 : :
997 : 15 : spdk_blob_close(snapshot, blob_op_complete, NULL);
998 : 15 : poll_threads();
999 : 15 : CU_ASSERT(g_bserrno == 0);
1000 : :
1001 : : /* Create clone from snapshot with xattrs */
1002 : 15 : xattrs.names = g_xattr_names;
1003 : 15 : xattrs.get_value = _get_xattr_value;
1004 : 15 : xattrs.count = 3;
1005 : 15 : xattrs.ctx = &g_ctx;
1006 : :
1007 : 15 : spdk_bs_create_clone(bs, snapshotid, &xattrs, blob_op_with_id_complete, NULL);
1008 : 15 : poll_threads();
1009 : 15 : CU_ASSERT(g_bserrno == 0);
1010 : 15 : CU_ASSERT(g_blobid != SPDK_BLOBID_INVALID);
1011 : 15 : cloneid = g_blobid;
1012 : :
1013 : 15 : spdk_bs_open_blob(bs, cloneid, blob_op_with_handle_complete, NULL);
1014 : 15 : poll_threads();
1015 : 15 : CU_ASSERT(g_bserrno == 0);
1016 [ - + ]: 15 : SPDK_CU_ASSERT_FATAL(g_blob != NULL);
1017 : 15 : clone = g_blob;
1018 [ - + ]: 15 : CU_ASSERT(clone->data_ro == false);
1019 [ - + ]: 15 : CU_ASSERT(clone->md_ro == false);
1020 : 15 : CU_ASSERT(spdk_blob_get_num_clusters(clone) == 10);
1021 : 15 : CU_ASSERT(spdk_blob_get_num_allocated_clusters(clone) == 0);
1022 : :
1023 : 15 : rc = spdk_blob_get_xattr_value(clone, g_xattr_names[0], &value, &value_len);
1024 : 15 : CU_ASSERT(rc == 0);
1025 [ - + ]: 15 : SPDK_CU_ASSERT_FATAL(value != NULL);
1026 [ - + ]: 15 : CU_ASSERT(value_len == strlen(g_xattr_values[0]));
1027 [ - + - + ]: 15 : CU_ASSERT_NSTRING_EQUAL_FATAL(value, g_xattr_values[0], value_len);
1028 : :
1029 : 15 : rc = spdk_blob_get_xattr_value(clone, g_xattr_names[1], &value, &value_len);
1030 : 15 : CU_ASSERT(rc == 0);
1031 [ - + ]: 15 : SPDK_CU_ASSERT_FATAL(value != NULL);
1032 [ - + ]: 15 : CU_ASSERT(value_len == strlen(g_xattr_values[1]));
1033 [ - + - + ]: 15 : CU_ASSERT_NSTRING_EQUAL((char *)value, g_xattr_values[1], value_len);
1034 : :
1035 : 15 : rc = spdk_blob_get_xattr_value(clone, g_xattr_names[2], &value, &value_len);
1036 : 15 : CU_ASSERT(rc == 0);
1037 [ - + ]: 15 : SPDK_CU_ASSERT_FATAL(value != NULL);
1038 [ - + ]: 15 : CU_ASSERT(value_len == strlen(g_xattr_values[2]));
1039 [ - + - + ]: 15 : CU_ASSERT_NSTRING_EQUAL((char *)value, g_xattr_values[2], value_len);
1040 : :
1041 : :
1042 : 15 : spdk_blob_close(clone, blob_op_complete, NULL);
1043 : 15 : poll_threads();
1044 : 15 : CU_ASSERT(g_bserrno == 0);
1045 : :
1046 : : /* Try to create clone from not read only blob */
1047 : 15 : spdk_bs_create_clone(bs, blobid, NULL, blob_op_with_id_complete, NULL);
1048 : 15 : poll_threads();
1049 : 15 : CU_ASSERT(g_bserrno == -EINVAL);
1050 : 15 : CU_ASSERT(g_blobid == SPDK_BLOBID_INVALID);
1051 : :
1052 : : /* Mark blob as read only */
1053 : 15 : spdk_blob_set_read_only(blob);
1054 : 15 : spdk_blob_sync_md(blob, blob_op_complete, NULL);
1055 : 15 : poll_threads();
1056 : 15 : CU_ASSERT(g_bserrno == 0);
1057 : :
1058 : : /* Create clone from read only blob */
1059 : 15 : spdk_bs_create_clone(bs, blobid, NULL, blob_op_with_id_complete, NULL);
1060 : 15 : poll_threads();
1061 : 15 : CU_ASSERT(g_bserrno == 0);
1062 : 15 : CU_ASSERT(g_blobid != SPDK_BLOBID_INVALID);
1063 : 15 : cloneid = g_blobid;
1064 : :
1065 : 15 : spdk_bs_open_blob(bs, cloneid, blob_op_with_handle_complete, NULL);
1066 : 15 : poll_threads();
1067 : 15 : CU_ASSERT(g_bserrno == 0);
1068 [ - + ]: 15 : SPDK_CU_ASSERT_FATAL(g_blob != NULL);
1069 : 15 : clone = g_blob;
1070 [ - + ]: 15 : CU_ASSERT(clone->data_ro == false);
1071 [ - + ]: 15 : CU_ASSERT(clone->md_ro == false);
1072 : 15 : CU_ASSERT(spdk_blob_get_num_clusters(clone) == 10);
1073 : :
1074 : 15 : ut_blob_close_and_delete(bs, clone);
1075 : 15 : ut_blob_close_and_delete(bs, blob);
1076 : 15 : }
1077 : :
1078 : : static void
1079 : 30 : _blob_inflate(bool decouple_parent)
1080 : : {
1081 : 30 : 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 : 30 : channel = spdk_bs_alloc_io_channel(bs);
1089 [ - + ]: 30 : SPDK_CU_ASSERT_FATAL(channel != NULL);
1090 : :
1091 : : /* Create blob with 10 clusters */
1092 : :
1093 : 30 : ut_spdk_blob_opts_init(&opts);
1094 : 30 : opts.num_clusters = 10;
1095 : 30 : opts.thin_provision = true;
1096 : :
1097 : 30 : blob = ut_blob_create_and_open(bs, &opts);
1098 : 30 : blobid = spdk_blob_get_id(blob);
1099 : 30 : CU_ASSERT(spdk_blob_get_num_clusters(blob) == 10);
1100 : 30 : CU_ASSERT(spdk_blob_is_thin_provisioned(blob) == true);
1101 : 30 : CU_ASSERT(spdk_blob_get_num_allocated_clusters(blob) == 0);
1102 : :
1103 : : /* 1) Blob with no parent */
1104 [ + + ]: 30 : if (decouple_parent) {
1105 : : /* Decouple parent of blob with no parent (should fail) */
1106 : 15 : spdk_bs_blob_decouple_parent(bs, channel, blobid, blob_op_complete, NULL);
1107 : 15 : poll_threads();
1108 : 15 : CU_ASSERT(g_bserrno != 0);
1109 : : } else {
1110 : : /* Inflate of thin blob with no parent should made it thick */
1111 : 15 : spdk_bs_inflate_blob(bs, channel, blobid, blob_op_complete, NULL);
1112 : 15 : poll_threads();
1113 : 15 : CU_ASSERT(g_bserrno == 0);
1114 : 15 : CU_ASSERT(spdk_blob_is_thin_provisioned(blob) == false);
1115 : 15 : CU_ASSERT(spdk_blob_get_num_allocated_clusters(blob) == 10);
1116 : : }
1117 : :
1118 : 30 : spdk_bs_create_snapshot(bs, blobid, NULL, blob_op_with_id_complete, NULL);
1119 : 30 : poll_threads();
1120 : 30 : CU_ASSERT(g_bserrno == 0);
1121 : 30 : CU_ASSERT(g_blobid != SPDK_BLOBID_INVALID);
1122 : 30 : snapshotid = g_blobid;
1123 : :
1124 : 30 : CU_ASSERT(spdk_blob_is_thin_provisioned(blob) == true);
1125 : 30 : CU_ASSERT(spdk_blob_get_num_clusters(blob) == 10);
1126 : :
1127 : 30 : spdk_bs_open_blob(bs, snapshotid, blob_op_with_handle_complete, NULL);
1128 : 30 : poll_threads();
1129 : 30 : CU_ASSERT(g_bserrno == 0);
1130 [ - + ]: 30 : SPDK_CU_ASSERT_FATAL(g_blob != NULL);
1131 : 30 : snapshot = g_blob;
1132 [ - + ]: 30 : CU_ASSERT(snapshot->data_ro == true);
1133 [ - + ]: 30 : CU_ASSERT(snapshot->md_ro == true);
1134 : 30 : CU_ASSERT(spdk_blob_get_num_clusters(snapshot) == 10);
1135 : :
1136 : 30 : spdk_blob_close(snapshot, blob_op_complete, NULL);
1137 : 30 : poll_threads();
1138 : 30 : CU_ASSERT(g_bserrno == 0);
1139 : :
1140 : 30 : free_clusters = spdk_bs_free_cluster_count(bs);
1141 : :
1142 : : /* 2) Blob with parent */
1143 [ + + ]: 30 : if (!decouple_parent) {
1144 : : /* Do full blob inflation */
1145 : 15 : spdk_bs_inflate_blob(bs, channel, blobid, blob_op_complete, NULL);
1146 : 15 : poll_threads();
1147 : 15 : CU_ASSERT(g_bserrno == 0);
1148 : : /* all 10 clusters should be allocated */
1149 : 15 : CU_ASSERT(spdk_bs_free_cluster_count(bs) == free_clusters - 10);
1150 : 15 : CU_ASSERT(spdk_blob_get_num_allocated_clusters(blob) == 10);
1151 : : } else {
1152 : : /* Decouple parent of blob */
1153 : 15 : spdk_bs_blob_decouple_parent(bs, channel, blobid, blob_op_complete, NULL);
1154 : 15 : poll_threads();
1155 : 15 : CU_ASSERT(g_bserrno == 0);
1156 : : /* when only parent is removed, none of the clusters should be allocated */
1157 : 15 : CU_ASSERT(spdk_bs_free_cluster_count(bs) == free_clusters);
1158 : 15 : CU_ASSERT(spdk_blob_get_num_allocated_clusters(blob) == 0);
1159 : : }
1160 : :
1161 : : /* Now, it should be possible to delete snapshot */
1162 : 30 : spdk_bs_delete_blob(bs, snapshotid, blob_op_complete, NULL);
1163 : 30 : poll_threads();
1164 : 30 : CU_ASSERT(g_bserrno == 0);
1165 : :
1166 : 30 : CU_ASSERT(spdk_blob_get_num_clusters(blob) == 10);
1167 : 30 : CU_ASSERT(spdk_blob_is_thin_provisioned(blob) == decouple_parent);
1168 : :
1169 : 30 : spdk_bs_free_io_channel(channel);
1170 : 30 : poll_threads();
1171 : :
1172 : 30 : ut_blob_close_and_delete(bs, blob);
1173 : 30 : }
1174 : :
1175 : : static void
1176 : 15 : blob_inflate(void)
1177 : : {
1178 : 15 : _blob_inflate(false);
1179 : 15 : _blob_inflate(true);
1180 : 15 : }
1181 : :
1182 : : static void
1183 : 15 : blob_delete(void)
1184 : : {
1185 : 15 : 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 : 15 : ut_spdk_blob_opts_init(&blob_opts);
1191 : 15 : spdk_bs_create_blob_ext(bs, &blob_opts, blob_op_with_id_complete, NULL);
1192 : 15 : poll_threads();
1193 : 15 : CU_ASSERT(g_bserrno == 0);
1194 : 15 : CU_ASSERT(g_blobid > 0);
1195 : 15 : blobid = g_blobid;
1196 : :
1197 : 15 : spdk_bs_delete_blob(bs, blobid, blob_op_complete, NULL);
1198 : 15 : poll_threads();
1199 : 15 : CU_ASSERT(g_bserrno == 0);
1200 : :
1201 : : /* Try to open the blob */
1202 : 15 : spdk_bs_open_blob(bs, blobid, blob_op_with_handle_complete, NULL);
1203 : 15 : poll_threads();
1204 : 15 : CU_ASSERT(g_bserrno == -ENOENT);
1205 : 15 : }
1206 : :
1207 : : static void
1208 : 15 : blob_resize_test(void)
1209 : : {
1210 : 15 : struct spdk_blob_store *bs = g_bs;
1211 : : struct spdk_blob *blob;
1212 : : uint64_t free_clusters;
1213 : :
1214 : 15 : free_clusters = spdk_bs_free_cluster_count(bs);
1215 : :
1216 : 15 : blob = ut_blob_create_and_open(bs, NULL);
1217 : 15 : CU_ASSERT(free_clusters == spdk_bs_free_cluster_count(bs));
1218 : 15 : CU_ASSERT(spdk_blob_get_num_allocated_clusters(blob) == 0);
1219 : :
1220 : : /* Confirm that resize fails if blob is marked read-only. */
1221 : 15 : blob->md_ro = true;
1222 : 15 : spdk_blob_resize(blob, 5, blob_op_complete, NULL);
1223 : 15 : poll_threads();
1224 : 15 : CU_ASSERT(g_bserrno == -EPERM);
1225 : 15 : blob->md_ro = false;
1226 : :
1227 : : /* The blob started at 0 clusters. Resize it to be 5. */
1228 : 15 : spdk_blob_resize(blob, 5, blob_op_complete, NULL);
1229 : 15 : poll_threads();
1230 : 15 : CU_ASSERT(g_bserrno == 0);
1231 : 15 : CU_ASSERT((free_clusters - 5) == spdk_bs_free_cluster_count(bs));
1232 : 15 : 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 : 15 : spdk_blob_resize(blob, 3, blob_op_complete, NULL);
1238 : 15 : poll_threads();
1239 : 15 : CU_ASSERT(g_bserrno == 0);
1240 : : /* Verify there are still 5 clusters in use */
1241 : 15 : CU_ASSERT((free_clusters - 5) == spdk_bs_free_cluster_count(bs));
1242 : 15 : CU_ASSERT(spdk_blob_get_num_allocated_clusters(blob) == 3);
1243 : :
1244 : 15 : spdk_blob_sync_md(blob, blob_op_complete, NULL);
1245 : 15 : poll_threads();
1246 : 15 : CU_ASSERT(g_bserrno == 0);
1247 : : /* Now there are only 3 clusters in use */
1248 : 15 : 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 : 15 : spdk_blob_resize(blob, 10, blob_op_complete, NULL);
1252 : 15 : poll_threads();
1253 : 15 : CU_ASSERT(g_bserrno == 0);
1254 : 15 : CU_ASSERT((free_clusters - 10) == spdk_bs_free_cluster_count(bs));
1255 : 15 : CU_ASSERT(spdk_blob_get_num_allocated_clusters(blob) == 10);
1256 : :
1257 : : /* Try to resize the blob to size larger than blobstore. */
1258 : 15 : spdk_blob_resize(blob, bs->total_clusters + 1, blob_op_complete, NULL);
1259 : 15 : poll_threads();
1260 : 15 : CU_ASSERT(g_bserrno == -ENOSPC);
1261 : :
1262 : 15 : ut_blob_close_and_delete(bs, blob);
1263 : 15 : }
1264 : :
1265 : : static void
1266 : 15 : blob_resize_thin_test(void)
1267 : : {
1268 : 15 : 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 : 15 : free_clusters = spdk_bs_free_cluster_count(bs);
1278 : :
1279 : 15 : blob_ch = spdk_bs_alloc_io_channel(bs);
1280 [ - + ]: 15 : SPDK_CU_ASSERT_FATAL(blob_ch != NULL);
1281 : :
1282 : : /* Create blob with thin provisioning enabled */
1283 : 15 : ut_spdk_blob_opts_init(&opts);
1284 : 15 : opts.thin_provision = true;
1285 : 15 : opts.num_clusters = 0;
1286 : :
1287 : 15 : blob = ut_blob_create_and_open(bs, &opts);
1288 : 15 : CU_ASSERT((free_clusters) == spdk_bs_free_cluster_count(bs));
1289 : 15 : CU_ASSERT(spdk_blob_get_num_allocated_clusters(blob) == 0);
1290 : 15 : io_units_per_cluster = bs_io_units_per_cluster(blob);
1291 : :
1292 : : /* The blob started at 0 clusters. Resize it to be 6. */
1293 : 15 : spdk_blob_resize(blob, 6, blob_op_complete, NULL);
1294 : 15 : poll_threads();
1295 : 15 : CU_ASSERT(g_bserrno == 0);
1296 : 15 : CU_ASSERT((free_clusters) == spdk_bs_free_cluster_count(bs));
1297 : 15 : CU_ASSERT(spdk_blob_get_num_allocated_clusters(blob) == 0);
1298 : :
1299 : : /* Write on cluster 0,2,4 and 5 of blob */
1300 [ + + ]: 3855 : for (offset = 0; offset < io_units_per_cluster; offset++) {
1301 : 3840 : spdk_blob_io_write(blob, blob_ch, buf1, offset, 1, blob_op_complete, NULL);
1302 : 3840 : poll_threads();
1303 : 3840 : CU_ASSERT(g_bserrno == 0);
1304 : : }
1305 [ + + ]: 3855 : for (offset = 2 * io_units_per_cluster; offset < 3 * io_units_per_cluster; offset++) {
1306 : 3840 : spdk_blob_io_write(blob, blob_ch, buf1, offset, 1, blob_op_complete, NULL);
1307 : 3840 : poll_threads();
1308 : 3840 : CU_ASSERT(g_bserrno == 0);
1309 : : }
1310 [ + + ]: 3855 : for (offset = 4 * io_units_per_cluster; offset < 5 * io_units_per_cluster; offset++) {
1311 : 3840 : spdk_blob_io_write(blob, blob_ch, buf1, offset, 1, blob_op_complete, NULL);
1312 : 3840 : poll_threads();
1313 : 3840 : CU_ASSERT(g_bserrno == 0);
1314 : : }
1315 [ + + ]: 3855 : for (offset = 5 * io_units_per_cluster; offset < 6 * io_units_per_cluster; offset++) {
1316 : 3840 : spdk_blob_io_write(blob, blob_ch, buf1, offset, 1, blob_op_complete, NULL);
1317 : 3840 : poll_threads();
1318 : 3840 : CU_ASSERT(g_bserrno == 0);
1319 : : }
1320 : :
1321 : : /* Check allocated clusters after write */
1322 : 15 : CU_ASSERT((free_clusters - 4) == spdk_bs_free_cluster_count(bs));
1323 : 15 : 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 : 15 : spdk_blob_resize(blob, 2, blob_op_complete, NULL);
1329 : 15 : poll_threads();
1330 : 15 : CU_ASSERT(g_bserrno == 0);
1331 : 15 : CU_ASSERT(spdk_blob_get_num_clusters(blob) == 2);
1332 : 15 : CU_ASSERT((free_clusters - 4) == spdk_bs_free_cluster_count(bs));
1333 : 15 : 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 : 15 : spdk_blob_sync_md(blob, blob_op_complete, NULL);
1337 : 15 : poll_threads();
1338 : 15 : CU_ASSERT(g_bserrno == 0);
1339 : 15 : CU_ASSERT((free_clusters - 1) == spdk_bs_free_cluster_count(bs));
1340 : 15 : CU_ASSERT(spdk_blob_get_num_clusters(blob) == 2);
1341 : 15 : CU_ASSERT(spdk_blob_get_num_allocated_clusters(blob) == 1);
1342 : :
1343 : 15 : spdk_bs_free_io_channel(blob_ch);
1344 : 15 : ut_blob_close_and_delete(bs, blob);
1345 : 15 : }
1346 : :
1347 : : static void
1348 : 15 : 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 : 15 : dev = init_dev();
1358 : 15 : spdk_bs_opts_init(&opts, sizeof(opts));
1359 [ - + ]: 15 : snprintf(opts.bstype.bstype, sizeof(opts.bstype.bstype), "TESTTYPE");
1360 : :
1361 : 15 : spdk_bs_init(dev, &opts, bs_op_with_handle_complete, NULL);
1362 : 15 : poll_threads();
1363 : 15 : CU_ASSERT(g_bserrno == 0);
1364 [ - + ]: 15 : SPDK_CU_ASSERT_FATAL(g_bs != NULL);
1365 : 15 : bs = g_bs;
1366 : :
1367 : 15 : blob = ut_blob_create_and_open(bs, NULL);
1368 : 15 : blobid = spdk_blob_get_id(blob);
1369 : :
1370 : 15 : rc = spdk_blob_set_read_only(blob);
1371 : 15 : CU_ASSERT(rc == 0);
1372 : :
1373 [ - + ]: 15 : CU_ASSERT(blob->data_ro == false);
1374 [ - + ]: 15 : CU_ASSERT(blob->md_ro == false);
1375 : :
1376 : 15 : spdk_blob_sync_md(blob, bs_op_complete, NULL);
1377 : 15 : poll_threads();
1378 : :
1379 [ - + ]: 15 : CU_ASSERT(blob->data_ro == true);
1380 [ - + ]: 15 : CU_ASSERT(blob->md_ro == true);
1381 : 15 : CU_ASSERT(blob->data_ro_flags & SPDK_BLOB_READ_ONLY);
1382 : :
1383 : 15 : spdk_blob_close(blob, blob_op_complete, NULL);
1384 : 15 : poll_threads();
1385 : 15 : CU_ASSERT(g_bserrno == 0);
1386 : :
1387 : 15 : spdk_bs_open_blob(bs, blobid, blob_op_with_handle_complete, NULL);
1388 : 15 : poll_threads();
1389 : 15 : CU_ASSERT(g_bserrno == 0);
1390 [ - + ]: 15 : SPDK_CU_ASSERT_FATAL(g_blob != NULL);
1391 : 15 : blob = g_blob;
1392 : :
1393 [ - + ]: 15 : CU_ASSERT(blob->data_ro == true);
1394 [ - + ]: 15 : CU_ASSERT(blob->md_ro == true);
1395 : 15 : CU_ASSERT(blob->data_ro_flags & SPDK_BLOB_READ_ONLY);
1396 : :
1397 : 15 : spdk_blob_close(blob, blob_op_complete, NULL);
1398 : 15 : poll_threads();
1399 : 15 : CU_ASSERT(g_bserrno == 0);
1400 : :
1401 : 15 : ut_bs_reload(&bs, &opts);
1402 : :
1403 : 15 : spdk_bs_open_blob(bs, blobid, blob_op_with_handle_complete, NULL);
1404 : 15 : poll_threads();
1405 : 15 : CU_ASSERT(g_bserrno == 0);
1406 [ - + ]: 15 : SPDK_CU_ASSERT_FATAL(g_blob != NULL);
1407 : 15 : blob = g_blob;
1408 : :
1409 [ - + ]: 15 : CU_ASSERT(blob->data_ro == true);
1410 [ - + ]: 15 : CU_ASSERT(blob->md_ro == true);
1411 : 15 : CU_ASSERT(blob->data_ro_flags & SPDK_BLOB_READ_ONLY);
1412 : :
1413 : 15 : ut_blob_close_and_delete(bs, blob);
1414 : :
1415 : 15 : spdk_bs_unload(bs, bs_op_complete, NULL);
1416 : 15 : poll_threads();
1417 : 15 : CU_ASSERT(g_bserrno == 0);
1418 : 15 : }
1419 : :
1420 : : static void
1421 : 15 : channel_ops(void)
1422 : : {
1423 : 15 : struct spdk_blob_store *bs = g_bs;
1424 : : struct spdk_io_channel *channel;
1425 : :
1426 : 15 : channel = spdk_bs_alloc_io_channel(bs);
1427 : 15 : CU_ASSERT(channel != NULL);
1428 : :
1429 : 15 : spdk_bs_free_io_channel(channel);
1430 : 15 : poll_threads();
1431 : 15 : }
1432 : :
1433 : : static void
1434 : 15 : blob_write(void)
1435 : : {
1436 : 15 : struct spdk_blob_store *bs = g_bs;
1437 : 15 : 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 [ - + ]: 15 : io_units_per_cluster = spdk_bs_get_cluster_size(bs) / spdk_bs_get_io_unit_size(bs);
1443 : :
1444 : 15 : channel = spdk_bs_alloc_io_channel(bs);
1445 : 15 : CU_ASSERT(channel != NULL);
1446 : :
1447 : : /* Write to a blob with 0 size */
1448 : 15 : spdk_blob_io_write(blob, channel, payload, 0, 1, blob_op_complete, NULL);
1449 : 15 : poll_threads();
1450 : 15 : CU_ASSERT(g_bserrno == -EINVAL);
1451 : :
1452 : : /* Resize the blob */
1453 : 15 : spdk_blob_resize(blob, 5, blob_op_complete, NULL);
1454 : 15 : poll_threads();
1455 : 15 : CU_ASSERT(g_bserrno == 0);
1456 : :
1457 : : /* Confirm that write fails if blob is marked read-only. */
1458 : 15 : blob->data_ro = true;
1459 : 15 : spdk_blob_io_write(blob, channel, payload, 0, 1, blob_op_complete, NULL);
1460 : 15 : poll_threads();
1461 : 15 : CU_ASSERT(g_bserrno == -EPERM);
1462 : 15 : blob->data_ro = false;
1463 : :
1464 : : /* Write to the blob */
1465 : 15 : spdk_blob_io_write(blob, channel, payload, 0, 1, blob_op_complete, NULL);
1466 : 15 : poll_threads();
1467 : 15 : CU_ASSERT(g_bserrno == 0);
1468 : :
1469 : : /* Write starting beyond the end */
1470 : 15 : spdk_blob_io_write(blob, channel, payload, 5 * io_units_per_cluster, 1, blob_op_complete,
1471 : : NULL);
1472 : 15 : poll_threads();
1473 : 15 : CU_ASSERT(g_bserrno == -EINVAL);
1474 : :
1475 : : /* Write starting at a valid location but going off the end */
1476 : 15 : spdk_blob_io_write(blob, channel, payload, 4 * io_units_per_cluster, io_units_per_cluster + 1,
1477 : : blob_op_complete, NULL);
1478 : 15 : poll_threads();
1479 : 15 : CU_ASSERT(g_bserrno == -EINVAL);
1480 : :
1481 : 15 : spdk_bs_free_io_channel(channel);
1482 : 15 : poll_threads();
1483 : 15 : }
1484 : :
1485 : : static void
1486 : 15 : blob_read(void)
1487 : : {
1488 : 15 : struct spdk_blob_store *bs = g_bs;
1489 : 15 : 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 [ - + ]: 15 : io_units_per_cluster = spdk_bs_get_cluster_size(bs) / spdk_bs_get_io_unit_size(bs);
1495 : :
1496 : 15 : channel = spdk_bs_alloc_io_channel(bs);
1497 : 15 : CU_ASSERT(channel != NULL);
1498 : :
1499 : : /* Read from a blob with 0 size */
1500 : 15 : spdk_blob_io_read(blob, channel, payload, 0, 1, blob_op_complete, NULL);
1501 : 15 : poll_threads();
1502 : 15 : CU_ASSERT(g_bserrno == -EINVAL);
1503 : :
1504 : : /* Resize the blob */
1505 : 15 : spdk_blob_resize(blob, 5, blob_op_complete, NULL);
1506 : 15 : poll_threads();
1507 : 15 : CU_ASSERT(g_bserrno == 0);
1508 : :
1509 : : /* Confirm that read passes if blob is marked read-only. */
1510 : 15 : blob->data_ro = true;
1511 : 15 : spdk_blob_io_read(blob, channel, payload, 0, 1, blob_op_complete, NULL);
1512 : 15 : poll_threads();
1513 : 15 : CU_ASSERT(g_bserrno == 0);
1514 : 15 : blob->data_ro = false;
1515 : :
1516 : : /* Read from the blob */
1517 : 15 : spdk_blob_io_read(blob, channel, payload, 0, 1, blob_op_complete, NULL);
1518 : 15 : poll_threads();
1519 : 15 : CU_ASSERT(g_bserrno == 0);
1520 : :
1521 : : /* Read starting beyond the end */
1522 : 15 : spdk_blob_io_read(blob, channel, payload, 5 * io_units_per_cluster, 1, blob_op_complete,
1523 : : NULL);
1524 : 15 : poll_threads();
1525 : 15 : CU_ASSERT(g_bserrno == -EINVAL);
1526 : :
1527 : : /* Read starting at a valid location but going off the end */
1528 : 15 : spdk_blob_io_read(blob, channel, payload, 4 * io_units_per_cluster, io_units_per_cluster + 1,
1529 : : blob_op_complete, NULL);
1530 : 15 : poll_threads();
1531 : 15 : CU_ASSERT(g_bserrno == -EINVAL);
1532 : :
1533 : 15 : spdk_bs_free_io_channel(channel);
1534 : 15 : poll_threads();
1535 : 15 : }
1536 : :
1537 : : static void
1538 : 15 : blob_rw_verify(void)
1539 : : {
1540 : 15 : struct spdk_blob_store *bs = g_bs;
1541 : 15 : 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 : 15 : channel = spdk_bs_alloc_io_channel(bs);
1547 : 15 : CU_ASSERT(channel != NULL);
1548 : :
1549 : 15 : spdk_blob_resize(blob, 32, blob_op_complete, NULL);
1550 : 15 : poll_threads();
1551 : 15 : CU_ASSERT(g_bserrno == 0);
1552 : :
1553 : 15 : memset(payload_write, 0xE5, sizeof(payload_write));
1554 : 15 : spdk_blob_io_write(blob, channel, payload_write, 4, 10, blob_op_complete, NULL);
1555 : 15 : poll_threads();
1556 : 15 : CU_ASSERT(g_bserrno == 0);
1557 : :
1558 : 15 : memset(payload_read, 0x00, sizeof(payload_read));
1559 : 15 : spdk_blob_io_read(blob, channel, payload_read, 4, 10, blob_op_complete, NULL);
1560 : 15 : poll_threads();
1561 : 15 : CU_ASSERT(g_bserrno == 0);
1562 : 15 : CU_ASSERT(memcmp(payload_write, payload_read, 4 * BLOCKLEN) == 0);
1563 : :
1564 : 15 : spdk_bs_free_io_channel(channel);
1565 : 15 : poll_threads();
1566 : 15 : }
1567 : :
1568 : : static void
1569 : 15 : blob_rw_verify_iov(void)
1570 : : {
1571 : 15 : 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 [ - + ]: 15 : uint32_t first_data_cluster = FIRST_DATA_CLUSTER(bs);
1580 : :
1581 : 15 : channel = spdk_bs_alloc_io_channel(bs);
1582 : 15 : CU_ASSERT(channel != NULL);
1583 : :
1584 : 15 : blob = ut_blob_create_and_open(bs, NULL);
1585 : :
1586 : 15 : spdk_blob_resize(blob, 2, blob_op_complete, NULL);
1587 : 15 : poll_threads();
1588 : 15 : 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 : 15 : CU_ASSERT(blob->active.clusters[0] == first_data_cluster * 256);
1597 : 15 : CU_ASSERT(blob->active.clusters[1] == (first_data_cluster + 1) * 256);
1598 : 15 : blob->active.clusters[1] = (first_data_cluster + 2) * 256;
1599 : :
1600 : 15 : memset(payload_write, 0xE5, sizeof(payload_write));
1601 : 15 : iov_write[0].iov_base = payload_write;
1602 : 15 : iov_write[0].iov_len = 1 * BLOCKLEN;
1603 : 15 : iov_write[1].iov_base = payload_write + 1 * BLOCKLEN;
1604 : 15 : iov_write[1].iov_len = 5 * BLOCKLEN;
1605 : 15 : iov_write[2].iov_base = payload_write + 6 * BLOCKLEN;
1606 : 15 : 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 : 15 : spdk_blob_io_writev(blob, channel, iov_write, 3, 250, 10, blob_op_complete, NULL);
1612 : 15 : poll_threads();
1613 : 15 : CU_ASSERT(g_bserrno == 0);
1614 : :
1615 : 15 : memset(payload_read, 0xAA, sizeof(payload_read));
1616 : 15 : iov_read[0].iov_base = payload_read;
1617 : 15 : iov_read[0].iov_len = 3 * BLOCKLEN;
1618 : 15 : iov_read[1].iov_base = payload_read + 3 * BLOCKLEN;
1619 : 15 : iov_read[1].iov_len = 4 * BLOCKLEN;
1620 : 15 : iov_read[2].iov_base = payload_read + 7 * BLOCKLEN;
1621 : 15 : iov_read[2].iov_len = 3 * BLOCKLEN;
1622 : 15 : spdk_blob_io_readv(blob, channel, iov_read, 3, 250, 10, blob_op_complete, NULL);
1623 : 15 : poll_threads();
1624 : 15 : CU_ASSERT(g_bserrno == 0);
1625 : 15 : CU_ASSERT(memcmp(payload_write, payload_read, 10 * BLOCKLEN) == 0);
1626 : :
1627 : 15 : buf = calloc(1, 256 * BLOCKLEN);
1628 [ - + ]: 15 : SPDK_CU_ASSERT_FATAL(buf != NULL);
1629 : : /* Check that cluster 2 on "disk" was not modified. */
1630 [ - + - + ]: 15 : CU_ASSERT(memcmp(buf, &g_dev_buffer[(first_data_cluster + 1) * 256 * BLOCKLEN],
1631 : : 256 * BLOCKLEN) == 0);
1632 : 15 : free(buf);
1633 : :
1634 : 15 : spdk_blob_close(blob, blob_op_complete, NULL);
1635 : 15 : poll_threads();
1636 : 15 : CU_ASSERT(g_bserrno == 0);
1637 : :
1638 : 15 : spdk_bs_free_io_channel(channel);
1639 : 15 : poll_threads();
1640 : 15 : }
1641 : :
1642 : : static uint32_t
1643 : 30 : bs_channel_get_req_count(struct spdk_io_channel *_channel)
1644 : : {
1645 : 30 : struct spdk_bs_channel *channel = spdk_io_channel_get_ctx(_channel);
1646 : : struct spdk_bs_request_set *set;
1647 : 30 : uint32_t count = 0;
1648 : :
1649 [ + + ]: 15390 : TAILQ_FOREACH(set, &channel->reqs, link) {
1650 : 15360 : count++;
1651 : : }
1652 : :
1653 : 30 : return count;
1654 : : }
1655 : :
1656 : : static void
1657 : 15 : blob_rw_verify_iov_nomem(void)
1658 : : {
1659 : 15 : struct spdk_blob_store *bs = g_bs;
1660 : 15 : 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 : 15 : channel = spdk_bs_alloc_io_channel(bs);
1667 : 15 : CU_ASSERT(channel != NULL);
1668 : :
1669 : 15 : spdk_blob_resize(blob, 2, blob_op_complete, NULL);
1670 : 15 : poll_threads();
1671 : 15 : 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 : 15 : iov_write[0].iov_base = payload_write;
1678 : 15 : iov_write[0].iov_len = 1 * BLOCKLEN;
1679 : 15 : iov_write[1].iov_base = payload_write + 1 * BLOCKLEN;
1680 : 15 : iov_write[1].iov_len = 5 * BLOCKLEN;
1681 : 15 : iov_write[2].iov_base = payload_write + 6 * BLOCKLEN;
1682 : 15 : iov_write[2].iov_len = 4 * BLOCKLEN;
1683 : 15 : MOCK_SET(calloc, NULL);
1684 : 15 : req_count = bs_channel_get_req_count(channel);
1685 : 15 : spdk_blob_io_writev(blob, channel, iov_write, 3, 250, 10, blob_op_complete, NULL);
1686 : 15 : poll_threads();
1687 : 15 : CU_ASSERT(g_bserrno == -ENOMEM);
1688 : 15 : CU_ASSERT(req_count == bs_channel_get_req_count(channel));
1689 [ - - - + ]: 15 : MOCK_CLEAR(calloc);
1690 : :
1691 : 15 : spdk_bs_free_io_channel(channel);
1692 : 15 : poll_threads();
1693 : 15 : }
1694 : :
1695 : : static void
1696 : 15 : blob_rw_iov_read_only(void)
1697 : : {
1698 : 15 : struct spdk_blob_store *bs = g_bs;
1699 : 15 : 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 : 15 : channel = spdk_bs_alloc_io_channel(bs);
1707 : 15 : CU_ASSERT(channel != NULL);
1708 : :
1709 : 15 : spdk_blob_resize(blob, 2, blob_op_complete, NULL);
1710 : 15 : poll_threads();
1711 : 15 : CU_ASSERT(g_bserrno == 0);
1712 : :
1713 : : /* Verify that writev failed if read_only flag is set. */
1714 : 15 : blob->data_ro = true;
1715 : 15 : iov_write.iov_base = payload_write;
1716 : 15 : iov_write.iov_len = sizeof(payload_write);
1717 : 15 : spdk_blob_io_writev(blob, channel, &iov_write, 1, 0, 1, blob_op_complete, NULL);
1718 : 15 : poll_threads();
1719 : 15 : CU_ASSERT(g_bserrno == -EPERM);
1720 : :
1721 : : /* Verify that reads pass if data_ro flag is set. */
1722 : 15 : iov_read.iov_base = payload_read;
1723 : 15 : iov_read.iov_len = sizeof(payload_read);
1724 : 15 : spdk_blob_io_readv(blob, channel, &iov_read, 1, 0, 1, blob_op_complete, NULL);
1725 : 15 : poll_threads();
1726 : 15 : CU_ASSERT(g_bserrno == 0);
1727 : :
1728 : 15 : spdk_bs_free_io_channel(channel);
1729 : 15 : poll_threads();
1730 : 15 : }
1731 : :
1732 : : static void
1733 : 30 : _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 : 30 : 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 : 30 : buf = payload;
1743 [ + + ]: 38430 : for (i = 0; i < length; i++) {
1744 : 38400 : spdk_blob_io_read(blob, channel, buf, i + offset, 1, blob_op_complete, NULL);
1745 : 38400 : poll_threads();
1746 [ - + ]: 38400 : if (g_bserrno != 0) {
1747 : : /* Pass the error code up */
1748 : 0 : break;
1749 : : }
1750 : 38400 : buf += io_unit_size;
1751 : : }
1752 : :
1753 : 30 : cb_fn(cb_arg, g_bserrno);
1754 : 30 : }
1755 : :
1756 : : static void
1757 : 30 : _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 : 30 : 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 : 30 : buf = payload;
1767 [ + + ]: 38430 : for (i = 0; i < length; i++) {
1768 : 38400 : spdk_blob_io_write(blob, channel, buf, i + offset, 1, blob_op_complete, NULL);
1769 : 38400 : poll_threads();
1770 [ - + ]: 38400 : if (g_bserrno != 0) {
1771 : : /* Pass the error code up */
1772 : 0 : break;
1773 : : }
1774 : 38400 : buf += io_unit_size;
1775 : : }
1776 : :
1777 : 30 : cb_fn(cb_arg, g_bserrno);
1778 : 30 : }
1779 : :
1780 : : static void
1781 : 15 : blob_operation_split_rw(void)
1782 : : {
1783 : 15 : 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 : 15 : cluster_size = spdk_bs_get_cluster_size(bs);
1801 : 15 : io_unit_size = spdk_bs_get_io_unit_size(bs);
1802 [ - + ]: 15 : io_units_per_cluster = cluster_size / io_unit_size;
1803 : 15 : io_units_per_payload = io_units_per_cluster * 5;
1804 : 15 : payload_size = cluster_size * 5;
1805 : :
1806 : 15 : payload_read = malloc(payload_size);
1807 [ - + ]: 15 : SPDK_CU_ASSERT_FATAL(payload_read != NULL);
1808 : :
1809 : 15 : payload_write = malloc(payload_size);
1810 [ - + ]: 15 : SPDK_CU_ASSERT_FATAL(payload_write != NULL);
1811 : :
1812 : 15 : payload_pattern = malloc(payload_size);
1813 [ - + ]: 15 : SPDK_CU_ASSERT_FATAL(payload_pattern != NULL);
1814 : :
1815 : : /* Prepare random pattern to write */
1816 [ - + ]: 15 : memset(payload_pattern, 0xFF, payload_size);
1817 [ + + ]: 19215 : for (i = 0; i < io_units_per_payload; i++) {
1818 : 19200 : *((uint64_t *)(payload_pattern + io_unit_size * i)) = (i + 1);
1819 : : }
1820 : :
1821 : 15 : channel = spdk_bs_alloc_io_channel(bs);
1822 [ - + ]: 15 : SPDK_CU_ASSERT_FATAL(channel != NULL);
1823 : :
1824 : : /* Create blob */
1825 : 15 : ut_spdk_blob_opts_init(&opts);
1826 : 15 : opts.thin_provision = false;
1827 : 15 : opts.num_clusters = 5;
1828 : :
1829 : 15 : blob = ut_blob_create_and_open(bs, &opts);
1830 : 15 : CU_ASSERT(spdk_blob_get_num_clusters(blob) == 5);
1831 : :
1832 : : /* Initial read should return zeroed payload */
1833 [ - + ]: 15 : memset(payload_read, 0xFF, payload_size);
1834 : 15 : spdk_blob_io_read(blob, channel, payload_read, 0, io_units_per_payload, blob_op_complete, NULL);
1835 : 15 : poll_threads();
1836 : 15 : CU_ASSERT(g_bserrno == 0);
1837 : 15 : CU_ASSERT(spdk_mem_all_zero(payload_read, payload_size));
1838 : :
1839 : : /* Fill whole blob except last page */
1840 : 15 : spdk_blob_io_write(blob, channel, payload_pattern, 0, io_units_per_payload - 1,
1841 : : blob_op_complete, NULL);
1842 : 15 : poll_threads();
1843 : 15 : CU_ASSERT(g_bserrno == 0);
1844 : :
1845 : : /* Write last page with a pattern */
1846 : 15 : spdk_blob_io_write(blob, channel, payload_pattern, io_units_per_payload - 1, 1,
1847 : : blob_op_complete, NULL);
1848 : 15 : poll_threads();
1849 : 15 : CU_ASSERT(g_bserrno == 0);
1850 : :
1851 : : /* Read whole blob and check consistency */
1852 [ - + ]: 15 : memset(payload_read, 0xFF, payload_size);
1853 : 15 : spdk_blob_io_read(blob, channel, payload_read, 0, io_units_per_payload, blob_op_complete, NULL);
1854 : 15 : poll_threads();
1855 : 15 : CU_ASSERT(g_bserrno == 0);
1856 [ - + - + ]: 15 : CU_ASSERT(memcmp(payload_pattern, payload_read, payload_size - io_unit_size) == 0);
1857 [ - + - + ]: 15 : 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 : 15 : spdk_blob_io_write(blob, channel, payload_pattern, 1, io_units_per_payload - 1,
1861 : : blob_op_complete, NULL);
1862 : 15 : poll_threads();
1863 : 15 : CU_ASSERT(g_bserrno == 0);
1864 : :
1865 : : /* Write first page with a pattern */
1866 : 15 : spdk_blob_io_write(blob, channel, payload_pattern, 0, 1,
1867 : : blob_op_complete, NULL);
1868 : 15 : poll_threads();
1869 : 15 : CU_ASSERT(g_bserrno == 0);
1870 : :
1871 : : /* Read whole blob and check consistency */
1872 [ - + ]: 15 : memset(payload_read, 0xFF, payload_size);
1873 : 15 : spdk_blob_io_read(blob, channel, payload_read, 0, io_units_per_payload, blob_op_complete, NULL);
1874 : 15 : poll_threads();
1875 : 15 : CU_ASSERT(g_bserrno == 0);
1876 [ - + - + ]: 15 : CU_ASSERT(memcmp(payload_pattern, payload_read + io_unit_size, payload_size - io_unit_size) == 0);
1877 [ - + - + ]: 15 : 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 : 15 : _blob_io_write_no_split(blob, channel, payload_pattern, 0, io_units_per_payload,
1884 : : blob_op_complete, NULL);
1885 : 15 : poll_threads();
1886 : 15 : CU_ASSERT(g_bserrno == 0);
1887 : :
1888 [ - + ]: 15 : memset(payload_read, 0xFF, payload_size);
1889 : 15 : spdk_blob_io_read(blob, channel, payload_read, 0, io_units_per_payload, blob_op_complete, NULL);
1890 : 15 : poll_threads();
1891 : 15 : poll_threads();
1892 : 15 : CU_ASSERT(g_bserrno == 0);
1893 [ - + - + ]: 15 : CU_ASSERT(memcmp(payload_pattern, payload_read, payload_size) == 0);
1894 : :
1895 : : /* 2. Write test. */
1896 : 15 : spdk_blob_io_write(blob, channel, payload_pattern, 0, io_units_per_payload,
1897 : : blob_op_complete, NULL);
1898 : 15 : poll_threads();
1899 : 15 : CU_ASSERT(g_bserrno == 0);
1900 : :
1901 [ - + ]: 15 : memset(payload_read, 0xFF, payload_size);
1902 : 15 : _blob_io_read_no_split(blob, channel, payload_read, 0, io_units_per_payload, blob_op_complete,
1903 : : NULL);
1904 : 15 : poll_threads();
1905 : 15 : CU_ASSERT(g_bserrno == 0);
1906 [ - + - + ]: 15 : CU_ASSERT(memcmp(payload_pattern, payload_read, payload_size) == 0);
1907 : :
1908 : 15 : spdk_bs_free_io_channel(channel);
1909 : 15 : poll_threads();
1910 : :
1911 : 15 : g_blob = NULL;
1912 : 15 : g_blobid = 0;
1913 : :
1914 : 15 : free(payload_read);
1915 : 15 : free(payload_write);
1916 : 15 : free(payload_pattern);
1917 : :
1918 : 15 : ut_blob_close_and_delete(bs, blob);
1919 : 15 : }
1920 : :
1921 : : static void
1922 : 15 : blob_operation_split_rw_iov(void)
1923 : : {
1924 : 15 : 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 : 15 : cluster_size = spdk_bs_get_cluster_size(bs);
1945 : 15 : io_unit_size = spdk_bs_get_io_unit_size(bs);
1946 [ - + ]: 15 : io_units_per_cluster = cluster_size / io_unit_size;
1947 : 15 : io_units_per_payload = io_units_per_cluster * 5;
1948 : 15 : payload_size = cluster_size * 5;
1949 : :
1950 : 15 : payload_read = malloc(payload_size);
1951 [ - + ]: 15 : SPDK_CU_ASSERT_FATAL(payload_read != NULL);
1952 : :
1953 : 15 : payload_write = malloc(payload_size);
1954 [ - + ]: 15 : SPDK_CU_ASSERT_FATAL(payload_write != NULL);
1955 : :
1956 : 15 : payload_pattern = malloc(payload_size);
1957 [ - + ]: 15 : SPDK_CU_ASSERT_FATAL(payload_pattern != NULL);
1958 : :
1959 : : /* Prepare random pattern to write */
1960 [ + + ]: 19215 : for (i = 0; i < io_units_per_payload; i++) {
1961 [ + + ]: 9849600 : for (j = 0; j < io_unit_size / sizeof(uint64_t); j++) {
1962 : : uint64_t *tmp;
1963 : :
1964 : 9830400 : tmp = (uint64_t *)payload_pattern;
1965 : 9830400 : tmp += ((io_unit_size * i) / sizeof(uint64_t)) + j;
1966 : 9830400 : *tmp = i + 1;
1967 : : }
1968 : : }
1969 : :
1970 : 15 : channel = spdk_bs_alloc_io_channel(bs);
1971 [ - + ]: 15 : SPDK_CU_ASSERT_FATAL(channel != NULL);
1972 : :
1973 : : /* Create blob */
1974 : 15 : ut_spdk_blob_opts_init(&opts);
1975 : 15 : opts.thin_provision = false;
1976 : 15 : opts.num_clusters = 5;
1977 : :
1978 : 15 : blob = ut_blob_create_and_open(bs, &opts);
1979 : 15 : CU_ASSERT(spdk_blob_get_num_clusters(blob) == 5);
1980 : :
1981 : : /* Initial read should return zeroes payload */
1982 [ - + ]: 15 : memset(payload_read, 0xFF, payload_size);
1983 : 15 : iov_read[0].iov_base = payload_read;
1984 : 15 : iov_read[0].iov_len = cluster_size * 3;
1985 : 15 : iov_read[1].iov_base = payload_read + cluster_size * 3;
1986 : 15 : iov_read[1].iov_len = cluster_size * 2;
1987 : 15 : spdk_blob_io_readv(blob, channel, iov_read, 2, 0, io_units_per_payload, blob_op_complete, NULL);
1988 : 15 : poll_threads();
1989 : 15 : CU_ASSERT(g_bserrno == 0);
1990 : 15 : 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 : 15 : iov_write[0].iov_base = payload_pattern;
1995 : 15 : iov_write[0].iov_len = payload_size - io_unit_size;
1996 : 15 : iov_write[1].iov_base = payload_pattern;
1997 : 15 : iov_write[1].iov_len = io_unit_size;
1998 : 15 : spdk_blob_io_writev(blob, channel, iov_write, 2, 0, io_units_per_payload, blob_op_complete, NULL);
1999 : 15 : poll_threads();
2000 : 15 : CU_ASSERT(g_bserrno == 0);
2001 : :
2002 : : /* Read whole blob and check consistency */
2003 [ - + ]: 15 : memset(payload_read, 0xFF, payload_size);
2004 : 15 : iov_read[0].iov_base = payload_read;
2005 : 15 : iov_read[0].iov_len = cluster_size * 2;
2006 : 15 : iov_read[1].iov_base = payload_read + cluster_size * 2;
2007 : 15 : iov_read[1].iov_len = cluster_size * 3;
2008 : 15 : spdk_blob_io_readv(blob, channel, iov_read, 2, 0, io_units_per_payload, blob_op_complete, NULL);
2009 : 15 : poll_threads();
2010 : 15 : CU_ASSERT(g_bserrno == 0);
2011 [ - + - + ]: 15 : CU_ASSERT(memcmp(payload_pattern, payload_read, payload_size - io_unit_size) == 0);
2012 [ - + - + ]: 15 : 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 : 15 : iov_write[0].iov_base = payload_pattern;
2017 : 15 : iov_write[0].iov_len = io_unit_size;
2018 : 15 : iov_write[1].iov_base = payload_pattern;
2019 : 15 : iov_write[1].iov_len = payload_size - io_unit_size;
2020 : 15 : spdk_blob_io_writev(blob, channel, iov_write, 2, 0, io_units_per_payload, blob_op_complete, NULL);
2021 : 15 : poll_threads();
2022 : 15 : CU_ASSERT(g_bserrno == 0);
2023 : :
2024 : : /* Read whole blob and check consistency */
2025 [ - + ]: 15 : memset(payload_read, 0xFF, payload_size);
2026 : 15 : iov_read[0].iov_base = payload_read;
2027 : 15 : iov_read[0].iov_len = cluster_size * 4;
2028 : 15 : iov_read[1].iov_base = payload_read + cluster_size * 4;
2029 : 15 : iov_read[1].iov_len = cluster_size;
2030 : 15 : spdk_blob_io_readv(blob, channel, iov_read, 2, 0, io_units_per_payload, blob_op_complete, NULL);
2031 : 15 : poll_threads();
2032 : 15 : CU_ASSERT(g_bserrno == 0);
2033 [ - + - + ]: 15 : CU_ASSERT(memcmp(payload_pattern, payload_read + io_unit_size, payload_size - io_unit_size) == 0);
2034 [ - + - + ]: 15 : 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 : 15 : _blob_io_write_no_split(blob, channel, payload_pattern, 0, io_units_per_payload,
2041 : : blob_op_complete, NULL);
2042 : 15 : poll_threads();
2043 : 15 : CU_ASSERT(g_bserrno == 0);
2044 : :
2045 [ - + ]: 15 : memset(payload_read, 0xFF, payload_size);
2046 : 15 : iov_read[0].iov_base = payload_read;
2047 : 15 : iov_read[0].iov_len = cluster_size;
2048 : 15 : iov_read[1].iov_base = payload_read + cluster_size;
2049 : 15 : iov_read[1].iov_len = cluster_size * 4;
2050 : 15 : spdk_blob_io_readv(blob, channel, iov_read, 2, 0, io_units_per_payload, blob_op_complete, NULL);
2051 : 15 : poll_threads();
2052 : 15 : CU_ASSERT(g_bserrno == 0);
2053 [ - + - + ]: 15 : CU_ASSERT(memcmp(payload_pattern, payload_read, payload_size) == 0);
2054 : :
2055 : : /* 2. Write test. */
2056 : 15 : iov_write[0].iov_base = payload_read;
2057 : 15 : iov_write[0].iov_len = cluster_size * 2;
2058 : 15 : iov_write[1].iov_base = payload_read + cluster_size * 2;
2059 : 15 : iov_write[1].iov_len = cluster_size * 3;
2060 : 15 : spdk_blob_io_writev(blob, channel, iov_write, 2, 0, io_units_per_payload, blob_op_complete, NULL);
2061 : 15 : poll_threads();
2062 : 15 : CU_ASSERT(g_bserrno == 0);
2063 : :
2064 [ - + ]: 15 : memset(payload_read, 0xFF, payload_size);
2065 : 15 : _blob_io_read_no_split(blob, channel, payload_read, 0, io_units_per_payload, blob_op_complete,
2066 : : NULL);
2067 : 15 : poll_threads();
2068 : 15 : CU_ASSERT(g_bserrno == 0);
2069 [ - + - + ]: 15 : CU_ASSERT(memcmp(payload_pattern, payload_read, payload_size) == 0);
2070 : :
2071 : 15 : spdk_bs_free_io_channel(channel);
2072 : 15 : poll_threads();
2073 : :
2074 : 15 : g_blob = NULL;
2075 : 15 : g_blobid = 0;
2076 : :
2077 : 15 : free(payload_read);
2078 : 15 : free(payload_write);
2079 : 15 : free(payload_pattern);
2080 : :
2081 : 15 : ut_blob_close_and_delete(bs, blob);
2082 : 15 : }
2083 : :
2084 : : static void
2085 : 15 : blob_unmap(void)
2086 : : {
2087 : 15 : 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 [ - + ]: 15 : uint32_t first_data_cluster = FIRST_DATA_CLUSTER(bs);
2093 : : int i;
2094 : :
2095 : 15 : channel = spdk_bs_alloc_io_channel(bs);
2096 : 15 : CU_ASSERT(channel != NULL);
2097 : :
2098 : 15 : ut_spdk_blob_opts_init(&opts);
2099 : 15 : opts.num_clusters = 10;
2100 : :
2101 : 15 : blob = ut_blob_create_and_open(bs, &opts);
2102 : :
2103 : 15 : spdk_blob_resize(blob, 10, blob_op_complete, NULL);
2104 : 15 : poll_threads();
2105 : 15 : CU_ASSERT(g_bserrno == 0);
2106 : 15 : CU_ASSERT(spdk_blob_get_num_allocated_clusters(blob) == 10);
2107 : :
2108 [ - + ]: 15 : memset(payload, 0, sizeof(payload));
2109 : 15 : payload[0] = 0xFF;
2110 : :
2111 : : /*
2112 : : * Set first byte of every cluster to 0xFF.
2113 : : */
2114 [ + + ]: 165 : for (i = 0; i < 10; i++) {
2115 : 150 : g_dev_buffer[(first_data_cluster + i) * SPDK_BLOB_OPTS_CLUSTER_SZ] = 0xFF;
2116 : : }
2117 : :
2118 : : /* Confirm writes */
2119 [ + + ]: 165 : for (i = 0; i < 10; i++) {
2120 : 150 : payload[0] = 0;
2121 : 150 : spdk_blob_io_read(blob, channel, &payload, i * SPDK_BLOB_OPTS_CLUSTER_SZ / BLOCKLEN, 1,
2122 : : blob_op_complete, NULL);
2123 : 150 : poll_threads();
2124 : 150 : CU_ASSERT(g_bserrno == 0);
2125 : 150 : CU_ASSERT(payload[0] == 0xFF);
2126 : : }
2127 : :
2128 : : /* Mark some clusters as unallocated */
2129 : 15 : blob->active.clusters[1] = 0;
2130 : 15 : blob->active.clusters[2] = 0;
2131 : 15 : blob->active.clusters[3] = 0;
2132 : 15 : blob->active.clusters[6] = 0;
2133 : 15 : blob->active.clusters[8] = 0;
2134 : 15 : blob->active.num_allocated_clusters -= 5;
2135 : :
2136 : : /* Unmap clusters by resizing to 0 */
2137 : 15 : spdk_blob_resize(blob, 0, blob_op_complete, NULL);
2138 : 15 : poll_threads();
2139 : 15 : CU_ASSERT(g_bserrno == 0);
2140 : :
2141 : 15 : spdk_blob_sync_md(blob, blob_op_complete, NULL);
2142 : 15 : poll_threads();
2143 : 15 : CU_ASSERT(g_bserrno == 0);
2144 : 15 : CU_ASSERT(spdk_blob_get_num_allocated_clusters(blob) == 0);
2145 : :
2146 : : /* Confirm that only 'allocated' clusters were unmapped */
2147 [ + + ]: 165 : for (i = 0; i < 10; i++) {
2148 [ + + ]: 150 : switch (i) {
2149 : 75 : case 1:
2150 : : case 2:
2151 : : case 3:
2152 : : case 6:
2153 : : case 8:
2154 : 75 : CU_ASSERT(g_dev_buffer[(first_data_cluster + i) * SPDK_BLOB_OPTS_CLUSTER_SZ] == 0xFF);
2155 : 75 : break;
2156 : 75 : default:
2157 : 75 : CU_ASSERT(g_dev_buffer[(first_data_cluster + i) * SPDK_BLOB_OPTS_CLUSTER_SZ] == 0);
2158 : 75 : break;
2159 : : }
2160 : : }
2161 : :
2162 : 15 : spdk_bs_free_io_channel(channel);
2163 : 15 : poll_threads();
2164 : :
2165 : 15 : ut_blob_close_and_delete(bs, blob);
2166 : 15 : }
2167 : :
2168 : : static void
2169 : 15 : blob_iter(void)
2170 : : {
2171 : 15 : 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 : 15 : spdk_bs_iter_first(bs, blob_op_with_handle_complete, NULL);
2177 : 15 : poll_threads();
2178 : 15 : CU_ASSERT(g_blob == NULL);
2179 : 15 : CU_ASSERT(g_bserrno == -ENOENT);
2180 : :
2181 : 15 : ut_spdk_blob_opts_init(&blob_opts);
2182 : 15 : spdk_bs_create_blob_ext(bs, &blob_opts, blob_op_with_id_complete, NULL);
2183 : 15 : poll_threads();
2184 : 15 : CU_ASSERT(g_bserrno == 0);
2185 : 15 : CU_ASSERT(g_blobid != SPDK_BLOBID_INVALID);
2186 : 15 : blobid = g_blobid;
2187 : :
2188 : 15 : spdk_bs_iter_first(bs, blob_op_with_handle_complete, NULL);
2189 : 15 : poll_threads();
2190 : 15 : CU_ASSERT(g_blob != NULL);
2191 : 15 : CU_ASSERT(g_bserrno == 0);
2192 : 15 : blob = g_blob;
2193 : 15 : CU_ASSERT(spdk_blob_get_id(blob) == blobid);
2194 : :
2195 : 15 : spdk_bs_iter_next(bs, blob, blob_op_with_handle_complete, NULL);
2196 : 15 : poll_threads();
2197 : 15 : CU_ASSERT(g_blob == NULL);
2198 : 15 : CU_ASSERT(g_bserrno == -ENOENT);
2199 : 15 : }
2200 : :
2201 : : static void
2202 : 15 : blob_xattr(void)
2203 : : {
2204 : 15 : struct spdk_blob_store *bs = g_bs;
2205 : 15 : struct spdk_blob *blob = g_blob;
2206 : 15 : 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 : 15 : blob->md_ro = true;
2216 : 15 : rc = spdk_blob_set_xattr(blob, "name", "log.txt", strlen("log.txt") + 1);
2217 : 15 : CU_ASSERT(rc == -EPERM);
2218 : :
2219 : 15 : blob->md_ro = false;
2220 : 15 : rc = spdk_blob_set_xattr(blob, "name", "log.txt", strlen("log.txt") + 1);
2221 : 15 : CU_ASSERT(rc == 0);
2222 : :
2223 : 15 : length = 2345;
2224 : 15 : rc = spdk_blob_set_xattr(blob, "length", &length, sizeof(length));
2225 : 15 : CU_ASSERT(rc == 0);
2226 : :
2227 : : /* Overwrite "length" xattr. */
2228 : 15 : length = 3456;
2229 : 15 : rc = spdk_blob_set_xattr(blob, "length", &length, sizeof(length));
2230 : 15 : CU_ASSERT(rc == 0);
2231 : :
2232 : : /* get_xattr should still work even if md_ro flag is set. */
2233 : 15 : value = NULL;
2234 : 15 : blob->md_ro = true;
2235 : 15 : rc = spdk_blob_get_xattr_value(blob, "length", &value, &value_len);
2236 : 15 : CU_ASSERT(rc == 0);
2237 [ - + ]: 15 : SPDK_CU_ASSERT_FATAL(value != NULL);
2238 : 15 : CU_ASSERT(*(uint64_t *)value == length);
2239 : 15 : CU_ASSERT(value_len == 8);
2240 : 15 : blob->md_ro = false;
2241 : :
2242 : 15 : rc = spdk_blob_get_xattr_value(blob, "foobar", &value, &value_len);
2243 : 15 : CU_ASSERT(rc == -ENOENT);
2244 : :
2245 : 15 : names = NULL;
2246 : 15 : rc = spdk_blob_get_xattr_names(blob, &names);
2247 : 15 : CU_ASSERT(rc == 0);
2248 [ - + ]: 15 : SPDK_CU_ASSERT_FATAL(names != NULL);
2249 : 15 : CU_ASSERT(spdk_xattr_names_get_count(names) == 2);
2250 : 15 : name1 = spdk_xattr_names_get_name(names, 0);
2251 [ - + ]: 15 : SPDK_CU_ASSERT_FATAL(name1 != NULL);
2252 [ - + - + : 15 : CU_ASSERT(!strcmp(name1, "name") || !strcmp(name1, "length"));
- - - - ]
2253 : 15 : name2 = spdk_xattr_names_get_name(names, 1);
2254 [ - + ]: 15 : SPDK_CU_ASSERT_FATAL(name2 != NULL);
2255 [ + + + - : 15 : CU_ASSERT(!strcmp(name2, "name") || !strcmp(name2, "length"));
- + + - ]
2256 [ - + - + ]: 15 : CU_ASSERT(strcmp(name1, name2));
2257 : 15 : spdk_xattr_names_free(names);
2258 : :
2259 : : /* Confirm that remove_xattr fails if md_ro is set to true. */
2260 : 15 : blob->md_ro = true;
2261 : 15 : rc = spdk_blob_remove_xattr(blob, "name");
2262 : 15 : CU_ASSERT(rc == -EPERM);
2263 : :
2264 : 15 : blob->md_ro = false;
2265 : 15 : rc = spdk_blob_remove_xattr(blob, "name");
2266 : 15 : CU_ASSERT(rc == 0);
2267 : :
2268 : 15 : rc = spdk_blob_remove_xattr(blob, "foobar");
2269 : 15 : CU_ASSERT(rc == -ENOENT);
2270 : :
2271 : : /* Set internal xattr */
2272 : 15 : length = 7898;
2273 : 15 : rc = blob_set_xattr(blob, "internal", &length, sizeof(length), true);
2274 : 15 : CU_ASSERT(rc == 0);
2275 : 15 : rc = blob_get_xattr_value(blob, "internal", &value, &value_len, true);
2276 : 15 : CU_ASSERT(rc == 0);
2277 : 15 : CU_ASSERT(*(uint64_t *)value == length);
2278 : : /* try to get public xattr with same name */
2279 : 15 : rc = spdk_blob_get_xattr_value(blob, "internal", &value, &value_len);
2280 : 15 : CU_ASSERT(rc != 0);
2281 : 15 : rc = blob_get_xattr_value(blob, "internal", &value, &value_len, false);
2282 : 15 : CU_ASSERT(rc != 0);
2283 : : /* Check if SPDK_BLOB_INTERNAL_XATTR is set */
2284 : 15 : CU_ASSERT((blob->invalid_flags & SPDK_BLOB_INTERNAL_XATTR) ==
2285 : : SPDK_BLOB_INTERNAL_XATTR);
2286 : :
2287 : 15 : spdk_blob_close(blob, blob_op_complete, NULL);
2288 : 15 : poll_threads();
2289 : :
2290 : : /* Check if xattrs are persisted */
2291 : 15 : ut_bs_reload(&bs, NULL);
2292 : :
2293 : 15 : spdk_bs_open_blob(bs, blobid, blob_op_with_handle_complete, NULL);
2294 : 15 : poll_threads();
2295 : 15 : CU_ASSERT(g_bserrno == 0);
2296 [ - + ]: 15 : SPDK_CU_ASSERT_FATAL(g_blob != NULL);
2297 : 15 : blob = g_blob;
2298 : :
2299 : 15 : rc = blob_get_xattr_value(blob, "internal", &value, &value_len, true);
2300 : 15 : CU_ASSERT(rc == 0);
2301 : 15 : CU_ASSERT(*(uint64_t *)value == length);
2302 : :
2303 : : /* try to get internal xattr through public call */
2304 : 15 : rc = spdk_blob_get_xattr_value(blob, "internal", &value, &value_len);
2305 : 15 : CU_ASSERT(rc != 0);
2306 : :
2307 : 15 : rc = blob_remove_xattr(blob, "internal", true);
2308 : 15 : CU_ASSERT(rc == 0);
2309 : :
2310 : 15 : CU_ASSERT((blob->invalid_flags & SPDK_BLOB_INTERNAL_XATTR) == 0);
2311 : 15 : }
2312 : :
2313 : : static void
2314 : 15 : blob_parse_md(void)
2315 : : {
2316 : 15 : 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 : 15 : used_pages = spdk_bit_array_count_set(bs->used_md_pages);
2324 : 15 : blob = ut_blob_create_and_open(bs, NULL);
2325 : :
2326 : : /* Create large extent to force more than 1 page of metadata. */
2327 : 15 : xattr_length = SPDK_BS_MAX_DESC_SIZE - sizeof(struct spdk_blob_md_descriptor_xattr) -
2328 : : strlen("large_xattr");
2329 : 15 : xattr = calloc(xattr_length, sizeof(char));
2330 [ - + ]: 15 : SPDK_CU_ASSERT_FATAL(xattr != NULL);
2331 : 15 : rc = spdk_blob_set_xattr(blob, "large_xattr", xattr, xattr_length);
2332 : 15 : free(xattr);
2333 [ - + ]: 15 : SPDK_CU_ASSERT_FATAL(rc == 0);
2334 : :
2335 : 15 : spdk_blob_sync_md(blob, blob_op_complete, NULL);
2336 : 15 : poll_threads();
2337 : :
2338 : : /* Delete the blob and verify that number of pages returned to before its creation. */
2339 [ - + ]: 15 : SPDK_CU_ASSERT_FATAL(used_pages != spdk_bit_array_count_set(bs->used_md_pages));
2340 : 15 : ut_blob_close_and_delete(bs, blob);
2341 [ - + ]: 15 : SPDK_CU_ASSERT_FATAL(used_pages == spdk_bit_array_count_set(bs->used_md_pages));
2342 : 15 : }
2343 : :
2344 : : static void
2345 : 15 : 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 : 15 : dev = init_dev();
2360 : 15 : spdk_bs_opts_init(&opts, sizeof(opts));
2361 [ - + ]: 15 : snprintf(opts.bstype.bstype, sizeof(opts.bstype.bstype), "TESTTYPE");
2362 : :
2363 : : /* Initialize a new blob store */
2364 : 15 : spdk_bs_init(dev, &opts, bs_op_with_handle_complete, NULL);
2365 : 15 : poll_threads();
2366 : 15 : CU_ASSERT(g_bserrno == 0);
2367 [ - + ]: 15 : SPDK_CU_ASSERT_FATAL(g_bs != NULL);
2368 : 15 : bs = g_bs;
2369 : :
2370 : : /* Try to open a blobid that does not exist */
2371 : 15 : spdk_bs_open_blob(bs, 0, blob_op_with_handle_complete, NULL);
2372 : 15 : poll_threads();
2373 : 15 : CU_ASSERT(g_bserrno == -ENOENT);
2374 : 15 : CU_ASSERT(g_blob == NULL);
2375 : :
2376 : : /* Create a blob */
2377 : 15 : blob = ut_blob_create_and_open(bs, NULL);
2378 : 15 : blobid = spdk_blob_get_id(blob);
2379 : :
2380 : : /* Try again to open valid blob but without the upper bit set */
2381 : 15 : spdk_bs_open_blob(bs, blobid & 0xFFFFFFFF, blob_op_with_handle_complete, NULL);
2382 : 15 : poll_threads();
2383 : 15 : CU_ASSERT(g_bserrno == -ENOENT);
2384 : 15 : CU_ASSERT(g_blob == NULL);
2385 : :
2386 : : /* Set some xattrs */
2387 : 15 : rc = spdk_blob_set_xattr(blob, "name", "log.txt", strlen("log.txt") + 1);
2388 : 15 : CU_ASSERT(rc == 0);
2389 : :
2390 : 15 : length = 2345;
2391 : 15 : rc = spdk_blob_set_xattr(blob, "length", &length, sizeof(length));
2392 : 15 : CU_ASSERT(rc == 0);
2393 : :
2394 : : /* Resize the blob */
2395 : 15 : spdk_blob_resize(blob, 10, blob_op_complete, NULL);
2396 : 15 : poll_threads();
2397 : 15 : CU_ASSERT(g_bserrno == 0);
2398 : :
2399 : 15 : spdk_blob_close(blob, blob_op_complete, NULL);
2400 : 15 : poll_threads();
2401 : 15 : CU_ASSERT(g_bserrno == 0);
2402 : 15 : blob = NULL;
2403 : 15 : g_blob = NULL;
2404 : 15 : g_blobid = SPDK_BLOBID_INVALID;
2405 : :
2406 : : /* Unload the blob store */
2407 : 15 : spdk_bs_unload(bs, bs_op_complete, NULL);
2408 : 15 : poll_threads();
2409 : 15 : CU_ASSERT(g_bserrno == 0);
2410 : 15 : g_bs = NULL;
2411 : 15 : g_blob = NULL;
2412 : 15 : g_blobid = 0;
2413 : :
2414 : 15 : super_block = (struct spdk_bs_super_block *)g_dev_buffer;
2415 : 15 : CU_ASSERT(super_block->clean == 1);
2416 : :
2417 : : /* Load should fail for device with an unsupported blocklen */
2418 : 15 : dev = init_dev();
2419 : 15 : dev->blocklen = g_phys_blocklen * 2;
2420 : 15 : spdk_bs_load(dev, NULL, bs_op_with_handle_complete, NULL);
2421 : 15 : poll_threads();
2422 : 15 : CU_ASSERT(g_bserrno == -EINVAL);
2423 : :
2424 : : /* Load should when max_md_ops is set to zero */
2425 : 15 : dev = init_dev();
2426 : 15 : spdk_bs_opts_init(&opts, sizeof(opts));
2427 : 15 : opts.max_md_ops = 0;
2428 : 15 : spdk_bs_load(dev, &opts, bs_op_with_handle_complete, NULL);
2429 : 15 : poll_threads();
2430 : 15 : CU_ASSERT(g_bserrno == -EINVAL);
2431 : :
2432 : : /* Load should when max_channel_ops is set to zero */
2433 : 15 : dev = init_dev();
2434 : 15 : spdk_bs_opts_init(&opts, sizeof(opts));
2435 : 15 : opts.max_channel_ops = 0;
2436 : 15 : spdk_bs_load(dev, &opts, bs_op_with_handle_complete, NULL);
2437 : 15 : poll_threads();
2438 : 15 : CU_ASSERT(g_bserrno == -EINVAL);
2439 : :
2440 : : /* Load an existing blob store */
2441 : 15 : dev = init_dev();
2442 : 15 : spdk_bs_opts_init(&opts, sizeof(opts));
2443 [ - + ]: 15 : snprintf(opts.bstype.bstype, sizeof(opts.bstype.bstype), "TESTTYPE");
2444 : 15 : spdk_bs_load(dev, &opts, bs_op_with_handle_complete, NULL);
2445 : 15 : poll_threads();
2446 : 15 : CU_ASSERT(g_bserrno == 0);
2447 [ - + ]: 15 : SPDK_CU_ASSERT_FATAL(g_bs != NULL);
2448 : 15 : bs = g_bs;
2449 : :
2450 : 15 : super_block = (struct spdk_bs_super_block *)g_dev_buffer;
2451 : 15 : CU_ASSERT(super_block->clean == 1);
2452 : 15 : CU_ASSERT(super_block->size == dev->blockcnt * dev->blocklen);
2453 : :
2454 : 15 : spdk_bs_open_blob(bs, blobid, blob_op_with_handle_complete, NULL);
2455 : 15 : poll_threads();
2456 : 15 : CU_ASSERT(g_bserrno == 0);
2457 : 15 : CU_ASSERT(g_blob != NULL);
2458 : 15 : blob = g_blob;
2459 : :
2460 : : /* Verify that blobstore is marked dirty after first metadata sync */
2461 : 15 : spdk_blob_sync_md(blob, blob_op_complete, NULL);
2462 : 15 : CU_ASSERT(super_block->clean == 1);
2463 : :
2464 : : /* Get the xattrs */
2465 : 15 : value = NULL;
2466 : 15 : rc = spdk_blob_get_xattr_value(blob, "length", &value, &value_len);
2467 : 15 : CU_ASSERT(rc == 0);
2468 [ - + ]: 15 : SPDK_CU_ASSERT_FATAL(value != NULL);
2469 : 15 : CU_ASSERT(*(uint64_t *)value == length);
2470 : 15 : CU_ASSERT(value_len == 8);
2471 : :
2472 : 15 : rc = spdk_blob_get_xattr_value(blob, "foobar", &value, &value_len);
2473 : 15 : CU_ASSERT(rc == -ENOENT);
2474 : :
2475 : 15 : CU_ASSERT(spdk_blob_get_num_clusters(blob) == 10);
2476 : 15 : CU_ASSERT(spdk_blob_get_num_allocated_clusters(blob) == 10);
2477 : :
2478 : 15 : spdk_blob_close(blob, blob_op_complete, NULL);
2479 : 15 : poll_threads();
2480 : 15 : CU_ASSERT(g_bserrno == 0);
2481 : 15 : blob = NULL;
2482 : 15 : g_blob = NULL;
2483 : :
2484 : 15 : spdk_bs_unload(bs, bs_op_complete, NULL);
2485 : 15 : poll_threads();
2486 : 15 : CU_ASSERT(g_bserrno == 0);
2487 : 15 : g_bs = NULL;
2488 : :
2489 : : /* Load should fail: bdev size < saved size */
2490 : 15 : dev = init_dev();
2491 : 15 : dev->blockcnt /= 2;
2492 : :
2493 : 15 : spdk_bs_opts_init(&opts, sizeof(opts));
2494 [ - + ]: 15 : snprintf(opts.bstype.bstype, sizeof(opts.bstype.bstype), "TESTTYPE");
2495 : 15 : spdk_bs_load(dev, &opts, bs_op_with_handle_complete, NULL);
2496 : 15 : poll_threads();
2497 : :
2498 : 15 : CU_ASSERT(g_bserrno == -EILSEQ);
2499 : :
2500 : : /* Load should succeed: bdev size > saved size */
2501 : 15 : dev = init_dev();
2502 : 15 : dev->blockcnt *= 4;
2503 : :
2504 : 15 : spdk_bs_opts_init(&opts, sizeof(opts));
2505 [ - + ]: 15 : snprintf(opts.bstype.bstype, sizeof(opts.bstype.bstype), "TESTTYPE");
2506 : 15 : spdk_bs_load(dev, &opts, bs_op_with_handle_complete, NULL);
2507 : 15 : poll_threads();
2508 : 15 : CU_ASSERT(g_bserrno == 0);
2509 [ - + ]: 15 : SPDK_CU_ASSERT_FATAL(g_bs != NULL);
2510 : 15 : bs = g_bs;
2511 : :
2512 : 15 : CU_ASSERT(g_bserrno == 0);
2513 : 15 : spdk_bs_unload(bs, bs_op_complete, NULL);
2514 : 15 : poll_threads();
2515 : :
2516 : :
2517 : : /* Test compatibility mode */
2518 : :
2519 : 15 : dev = init_dev();
2520 : 15 : super_block->size = 0;
2521 : 15 : super_block->crc = blob_md_page_calc_crc(super_block);
2522 : :
2523 : 15 : spdk_bs_opts_init(&opts, sizeof(opts));
2524 [ - + ]: 15 : snprintf(opts.bstype.bstype, sizeof(opts.bstype.bstype), "TESTTYPE");
2525 : 15 : spdk_bs_load(dev, &opts, bs_op_with_handle_complete, NULL);
2526 : 15 : poll_threads();
2527 : 15 : CU_ASSERT(g_bserrno == 0);
2528 [ - + ]: 15 : SPDK_CU_ASSERT_FATAL(g_bs != NULL);
2529 : 15 : bs = g_bs;
2530 : :
2531 : : /* Create a blob */
2532 : 15 : ut_spdk_blob_opts_init(&blob_opts);
2533 : 15 : spdk_bs_create_blob_ext(bs, &blob_opts, blob_op_with_id_complete, NULL);
2534 : 15 : poll_threads();
2535 : 15 : CU_ASSERT(g_bserrno == 0);
2536 : 15 : CU_ASSERT(g_blobid != SPDK_BLOBID_INVALID);
2537 : :
2538 : : /* Blobstore should update number of blocks in super_block */
2539 : 15 : CU_ASSERT(super_block->size == dev->blockcnt * dev->blocklen);
2540 : 15 : CU_ASSERT(super_block->clean == 0);
2541 : :
2542 : 15 : spdk_bs_unload(bs, bs_op_complete, NULL);
2543 : 15 : poll_threads();
2544 : 15 : CU_ASSERT(g_bserrno == 0);
2545 : 15 : CU_ASSERT(super_block->clean == 1);
2546 : 15 : g_bs = NULL;
2547 : :
2548 : 15 : }
2549 : :
2550 : : static void
2551 : 15 : bs_load_pending_removal(void)
2552 : : {
2553 : 15 : 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 : 15 : ut_spdk_blob_opts_init(&opts);
2563 : 15 : opts.num_clusters = 10;
2564 : :
2565 : 15 : blob = ut_blob_create_and_open(bs, &opts);
2566 : 15 : blobid = spdk_blob_get_id(blob);
2567 : :
2568 : : /* Create snapshot */
2569 : 15 : spdk_bs_create_snapshot(bs, blobid, NULL, blob_op_with_id_complete, NULL);
2570 : 15 : poll_threads();
2571 : 15 : CU_ASSERT(g_bserrno == 0);
2572 : 15 : CU_ASSERT(g_blobid != SPDK_BLOBID_INVALID);
2573 : 15 : snapshotid = g_blobid;
2574 : :
2575 : 15 : spdk_bs_open_blob(bs, snapshotid, blob_op_with_handle_complete, NULL);
2576 : 15 : poll_threads();
2577 : 15 : CU_ASSERT(g_bserrno == 0);
2578 [ - + ]: 15 : SPDK_CU_ASSERT_FATAL(g_blob != NULL);
2579 : 15 : snapshot = g_blob;
2580 : :
2581 : : /* Set SNAPSHOT_PENDING_REMOVAL xattr */
2582 : 15 : snapshot->md_ro = false;
2583 : 15 : rc = blob_set_xattr(snapshot, SNAPSHOT_PENDING_REMOVAL, &blobid, sizeof(spdk_blob_id), true);
2584 : 15 : CU_ASSERT(rc == 0);
2585 : 15 : snapshot->md_ro = true;
2586 : :
2587 : 15 : spdk_blob_close(snapshot, blob_op_complete, NULL);
2588 : 15 : poll_threads();
2589 : 15 : CU_ASSERT(g_bserrno == 0);
2590 : :
2591 : 15 : spdk_blob_close(blob, blob_op_complete, NULL);
2592 : 15 : poll_threads();
2593 : 15 : CU_ASSERT(g_bserrno == 0);
2594 : :
2595 : : /* Reload blobstore */
2596 : 15 : ut_bs_reload(&bs, NULL);
2597 : :
2598 : : /* Snapshot should not be removed as blob is still pointing to it */
2599 : 15 : spdk_bs_open_blob(bs, snapshotid, blob_op_with_handle_complete, NULL);
2600 : 15 : poll_threads();
2601 : 15 : CU_ASSERT(g_bserrno == 0);
2602 [ - + ]: 15 : SPDK_CU_ASSERT_FATAL(g_blob != NULL);
2603 : 15 : snapshot = g_blob;
2604 : :
2605 : : /* SNAPSHOT_PENDING_REMOVAL xattr should be removed during load */
2606 : 15 : rc = spdk_blob_get_xattr_value(snapshot, SNAPSHOT_PENDING_REMOVAL, &value, &value_len);
2607 : 15 : CU_ASSERT(rc != 0);
2608 : :
2609 : : /* Set SNAPSHOT_PENDING_REMOVAL xattr again */
2610 : 15 : snapshot->md_ro = false;
2611 : 15 : rc = blob_set_xattr(snapshot, SNAPSHOT_PENDING_REMOVAL, &blobid, sizeof(spdk_blob_id), true);
2612 : 15 : CU_ASSERT(rc == 0);
2613 : 15 : snapshot->md_ro = true;
2614 : :
2615 : 15 : spdk_bs_open_blob(bs, blobid, blob_op_with_handle_complete, NULL);
2616 : 15 : poll_threads();
2617 : 15 : CU_ASSERT(g_bserrno == 0);
2618 [ - + ]: 15 : SPDK_CU_ASSERT_FATAL(g_blob != NULL);
2619 : 15 : blob = g_blob;
2620 : :
2621 : : /* Remove parent_id from blob by removing BLOB_SNAPSHOT xattr */
2622 : 15 : blob_remove_xattr(blob, BLOB_SNAPSHOT, true);
2623 : :
2624 : 15 : spdk_blob_sync_md(blob, blob_op_complete, NULL);
2625 : 15 : poll_threads();
2626 : 15 : CU_ASSERT(g_bserrno == 0);
2627 : :
2628 : 15 : spdk_blob_close(snapshot, blob_op_complete, NULL);
2629 : 15 : poll_threads();
2630 : 15 : CU_ASSERT(g_bserrno == 0);
2631 : :
2632 : 15 : spdk_blob_close(blob, blob_op_complete, NULL);
2633 : 15 : poll_threads();
2634 : 15 : CU_ASSERT(g_bserrno == 0);
2635 : :
2636 : : /* Reload blobstore */
2637 : 15 : ut_bs_reload(&bs, NULL);
2638 : :
2639 : : /* Snapshot should be removed as blob is not pointing to it anymore */
2640 : 15 : spdk_bs_open_blob(bs, snapshotid, blob_op_with_handle_complete, NULL);
2641 : 15 : poll_threads();
2642 : 15 : CU_ASSERT(g_bserrno != 0);
2643 : 15 : }
2644 : :
2645 : : static void
2646 : 15 : 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 : 15 : uint32_t custom_cluster_size = 4194304; /* 4MiB */
2653 : : uint32_t cluster_sz;
2654 : : uint64_t total_clusters;
2655 : :
2656 : 15 : dev = init_dev();
2657 : 15 : spdk_bs_opts_init(&opts, sizeof(opts));
2658 : 15 : opts.cluster_sz = custom_cluster_size;
2659 [ - + ]: 15 : snprintf(opts.bstype.bstype, sizeof(opts.bstype.bstype), "TESTTYPE");
2660 : :
2661 : : /* Initialize a new blob store */
2662 : 15 : spdk_bs_init(dev, &opts, bs_op_with_handle_complete, NULL);
2663 : 15 : poll_threads();
2664 : 15 : CU_ASSERT(g_bserrno == 0);
2665 [ - + ]: 15 : SPDK_CU_ASSERT_FATAL(g_bs != NULL);
2666 : 15 : bs = g_bs;
2667 : 15 : cluster_sz = bs->cluster_sz;
2668 : 15 : total_clusters = bs->total_clusters;
2669 : :
2670 : : /* Unload the blob store */
2671 : 15 : spdk_bs_unload(bs, bs_op_complete, NULL);
2672 : 15 : poll_threads();
2673 : 15 : CU_ASSERT(g_bserrno == 0);
2674 : 15 : g_bs = NULL;
2675 : 15 : g_blob = NULL;
2676 : 15 : g_blobid = 0;
2677 : :
2678 : 15 : super_block = (struct spdk_bs_super_block *)g_dev_buffer;
2679 : 15 : CU_ASSERT(super_block->clean == 1);
2680 : :
2681 : : /* Load an existing blob store */
2682 : 15 : dev = init_dev();
2683 : 15 : spdk_bs_opts_init(&opts, sizeof(opts));
2684 [ - + ]: 15 : snprintf(opts.bstype.bstype, sizeof(opts.bstype.bstype), "TESTTYPE");
2685 : 15 : spdk_bs_load(dev, &opts, bs_op_with_handle_complete, NULL);
2686 : 15 : poll_threads();
2687 : 15 : CU_ASSERT(g_bserrno == 0);
2688 [ - + ]: 15 : SPDK_CU_ASSERT_FATAL(g_bs != NULL);
2689 : 15 : bs = g_bs;
2690 : : /* Compare cluster size and number to one after initialization */
2691 : 15 : CU_ASSERT(cluster_sz == bs->cluster_sz);
2692 : 15 : CU_ASSERT(total_clusters == bs->total_clusters);
2693 : :
2694 : 15 : super_block = (struct spdk_bs_super_block *)g_dev_buffer;
2695 : 15 : CU_ASSERT(super_block->clean == 1);
2696 : 15 : CU_ASSERT(super_block->size == dev->blockcnt * dev->blocklen);
2697 : :
2698 : 15 : spdk_bs_unload(bs, bs_op_complete, NULL);
2699 : 15 : poll_threads();
2700 : 15 : CU_ASSERT(g_bserrno == 0);
2701 : 15 : CU_ASSERT(super_block->clean == 1);
2702 : 15 : g_bs = NULL;
2703 : 15 : }
2704 : :
2705 : : static void
2706 : 15 : 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 : 15 : dev = init_dev();
2719 : 15 : spdk_bs_opts_init(&opts, sizeof(opts));
2720 [ - + ]: 15 : 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 : 15 : opts.num_md_pages = 128;
2727 : :
2728 : : /* Initialize a new blob store */
2729 : 15 : spdk_bs_init(dev, &opts, bs_op_with_handle_complete, NULL);
2730 : 15 : poll_threads();
2731 : 15 : CU_ASSERT(g_bserrno == 0);
2732 [ - + ]: 15 : SPDK_CU_ASSERT_FATAL(g_bs != NULL);
2733 : 15 : bs = g_bs;
2734 : :
2735 : : /* Create blob */
2736 : 15 : ut_spdk_blob_opts_init(&blob_opts);
2737 : 15 : blob_opts.num_clusters = 10;
2738 : :
2739 : 15 : blob = ut_blob_create_and_open(bs, &blob_opts);
2740 : 15 : blobid = spdk_blob_get_id(blob);
2741 : :
2742 : : /* Create snapshot */
2743 : 15 : spdk_bs_create_snapshot(bs, blobid, NULL, blob_op_with_id_complete, NULL);
2744 : 15 : poll_threads();
2745 : 15 : CU_ASSERT(g_bserrno == 0);
2746 : 15 : CU_ASSERT(g_blobid != SPDK_BLOBID_INVALID);
2747 : 15 : snapshotid = g_blobid;
2748 : :
2749 : 15 : spdk_bs_open_blob(bs, snapshotid, blob_op_with_handle_complete, NULL);
2750 : 15 : poll_threads();
2751 : 15 : CU_ASSERT(g_bserrno == 0);
2752 [ - + ]: 15 : SPDK_CU_ASSERT_FATAL(g_blob != NULL);
2753 : 15 : snapshot = g_blob;
2754 : :
2755 : 15 : spdk_blob_close(snapshot, blob_op_complete, NULL);
2756 : 15 : poll_threads();
2757 : 15 : CU_ASSERT(g_bserrno == 0);
2758 : :
2759 : 15 : spdk_blob_close(blob, blob_op_complete, NULL);
2760 : 15 : poll_threads();
2761 : 15 : CU_ASSERT(g_bserrno == 0);
2762 : :
2763 : 15 : total_data_clusters = bs->total_data_clusters;
2764 : 15 : CU_ASSERT(bs->num_free_clusters + 10 == total_data_clusters);
2765 : :
2766 : : /* Unload the blob store */
2767 : 15 : spdk_bs_unload(bs, bs_op_complete, NULL);
2768 : 15 : poll_threads();
2769 : 15 : CU_ASSERT(g_bserrno == 0);
2770 : 15 : g_bs = NULL;
2771 : 15 : g_blob = NULL;
2772 : 15 : g_blobid = 0;
2773 : :
2774 : 15 : super_block = (struct spdk_bs_super_block *)g_dev_buffer;
2775 : 15 : CU_ASSERT(super_block->clean == 1);
2776 : :
2777 : 15 : mask = (struct spdk_bs_md_mask *)(g_dev_buffer + super_block->used_cluster_mask_start *
2778 : : g_phys_blocklen);
2779 : 15 : CU_ASSERT(mask->type == SPDK_MD_MASK_TYPE_USED_CLUSTERS);
2780 [ - + ]: 15 : 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 : 15 : mask->length *= 2;
2787 : :
2788 : : /* Load an existing blob store */
2789 : 15 : dev = init_dev();
2790 : 15 : dev->blockcnt *= 2;
2791 : 15 : spdk_bs_opts_init(&opts, sizeof(opts));
2792 : 15 : opts.clear_method = BS_CLEAR_WITH_NONE;
2793 [ - + ]: 15 : snprintf(opts.bstype.bstype, sizeof(opts.bstype.bstype), "TESTTYPE");
2794 : 15 : spdk_bs_load(dev, &opts, bs_op_with_handle_complete, NULL);
2795 : 15 : poll_threads();
2796 : 15 : CU_ASSERT(g_bserrno == 0);
2797 [ - + ]: 15 : SPDK_CU_ASSERT_FATAL(g_bs != NULL);
2798 : 15 : bs = g_bs;
2799 : :
2800 : : /* Check the capacity is the same as before */
2801 : 15 : CU_ASSERT(bs->total_data_clusters == total_data_clusters);
2802 : 15 : CU_ASSERT(bs->num_free_clusters + 10 == total_data_clusters);
2803 : :
2804 : : /* Check the blob and the snapshot are still available */
2805 : 15 : spdk_bs_open_blob(bs, blobid, blob_op_with_handle_complete, NULL);
2806 : 15 : poll_threads();
2807 : 15 : CU_ASSERT(g_bserrno == 0);
2808 [ - + ]: 15 : SPDK_CU_ASSERT_FATAL(g_blob != NULL);
2809 : 15 : blob = g_blob;
2810 : :
2811 : 15 : spdk_blob_close(blob, blob_op_complete, NULL);
2812 : 15 : poll_threads();
2813 : 15 : CU_ASSERT(g_bserrno == 0);
2814 : :
2815 : 15 : spdk_bs_open_blob(bs, snapshotid, blob_op_with_handle_complete, NULL);
2816 : 15 : poll_threads();
2817 : 15 : CU_ASSERT(g_bserrno == 0);
2818 [ - + ]: 15 : SPDK_CU_ASSERT_FATAL(g_blob != NULL);
2819 : 15 : snapshot = g_blob;
2820 : :
2821 : 15 : spdk_blob_close(snapshot, blob_op_complete, NULL);
2822 : 15 : poll_threads();
2823 : 15 : CU_ASSERT(g_bserrno == 0);
2824 : :
2825 : 15 : spdk_bs_unload(bs, bs_op_complete, NULL);
2826 : 15 : poll_threads();
2827 : 15 : CU_ASSERT(g_bserrno == 0);
2828 : 15 : CU_ASSERT(super_block->clean == 1);
2829 : 15 : g_bs = NULL;
2830 : 15 : }
2831 : :
2832 : : static void
2833 : 15 : bs_type(void)
2834 : : {
2835 : : struct spdk_blob_store *bs;
2836 : : struct spdk_bs_dev *dev;
2837 : 15 : struct spdk_bs_opts opts;
2838 : :
2839 : 15 : dev = init_dev();
2840 : 15 : spdk_bs_opts_init(&opts, sizeof(opts));
2841 [ - + ]: 15 : snprintf(opts.bstype.bstype, sizeof(opts.bstype.bstype), "TESTTYPE");
2842 : :
2843 : : /* Initialize a new blob store */
2844 : 15 : spdk_bs_init(dev, &opts, bs_op_with_handle_complete, NULL);
2845 : 15 : poll_threads();
2846 : 15 : CU_ASSERT(g_bserrno == 0);
2847 [ - + ]: 15 : SPDK_CU_ASSERT_FATAL(g_bs != NULL);
2848 : 15 : bs = g_bs;
2849 : :
2850 : : /* Unload the blob store */
2851 : 15 : spdk_bs_unload(bs, bs_op_complete, NULL);
2852 : 15 : poll_threads();
2853 : 15 : CU_ASSERT(g_bserrno == 0);
2854 : 15 : g_bs = NULL;
2855 : 15 : g_blob = NULL;
2856 : 15 : g_blobid = 0;
2857 : :
2858 : : /* Load non existing blobstore type */
2859 : 15 : dev = init_dev();
2860 [ - + ]: 15 : snprintf(opts.bstype.bstype, sizeof(opts.bstype.bstype), "NONEXISTING");
2861 : 15 : spdk_bs_load(dev, &opts, bs_op_with_handle_complete, NULL);
2862 : 15 : poll_threads();
2863 : 15 : CU_ASSERT(g_bserrno != 0);
2864 : :
2865 : : /* Load with empty blobstore type */
2866 : 15 : dev = init_dev();
2867 [ - + ]: 15 : memset(opts.bstype.bstype, 0, sizeof(opts.bstype.bstype));
2868 : 15 : spdk_bs_load(dev, &opts, bs_op_with_handle_complete, NULL);
2869 : 15 : poll_threads();
2870 : 15 : CU_ASSERT(g_bserrno == 0);
2871 [ - + ]: 15 : SPDK_CU_ASSERT_FATAL(g_bs != NULL);
2872 : 15 : bs = g_bs;
2873 : :
2874 : 15 : spdk_bs_unload(bs, bs_op_complete, NULL);
2875 : 15 : poll_threads();
2876 : 15 : CU_ASSERT(g_bserrno == 0);
2877 : 15 : g_bs = NULL;
2878 : :
2879 : : /* Initialize a new blob store with empty bstype */
2880 : 15 : dev = init_dev();
2881 [ - + ]: 15 : memset(opts.bstype.bstype, 0, sizeof(opts.bstype.bstype));
2882 : 15 : spdk_bs_init(dev, NULL, bs_op_with_handle_complete, NULL);
2883 : 15 : poll_threads();
2884 : 15 : CU_ASSERT(g_bserrno == 0);
2885 [ - + ]: 15 : SPDK_CU_ASSERT_FATAL(g_bs != NULL);
2886 : 15 : bs = g_bs;
2887 : :
2888 : 15 : spdk_bs_unload(bs, bs_op_complete, NULL);
2889 : 15 : poll_threads();
2890 : 15 : CU_ASSERT(g_bserrno == 0);
2891 : 15 : g_bs = NULL;
2892 : :
2893 : : /* Load non existing blobstore type */
2894 : 15 : dev = init_dev();
2895 [ - + ]: 15 : snprintf(opts.bstype.bstype, sizeof(opts.bstype.bstype), "NONEXISTING");
2896 : 15 : spdk_bs_load(dev, &opts, bs_op_with_handle_complete, NULL);
2897 : 15 : poll_threads();
2898 : 15 : CU_ASSERT(g_bserrno != 0);
2899 : :
2900 : : /* Load with empty blobstore type */
2901 : 15 : dev = init_dev();
2902 [ - + ]: 15 : memset(opts.bstype.bstype, 0, sizeof(opts.bstype.bstype));
2903 : 15 : spdk_bs_load(dev, &opts, bs_op_with_handle_complete, NULL);
2904 : 15 : poll_threads();
2905 : 15 : CU_ASSERT(g_bserrno == 0);
2906 [ - + ]: 15 : SPDK_CU_ASSERT_FATAL(g_bs != NULL);
2907 : 15 : bs = g_bs;
2908 : :
2909 : 15 : spdk_bs_unload(bs, bs_op_complete, NULL);
2910 : 15 : poll_threads();
2911 : 15 : CU_ASSERT(g_bserrno == 0);
2912 : 15 : g_bs = NULL;
2913 : 15 : }
2914 : :
2915 : : static void
2916 : 15 : bs_super_block(void)
2917 : : {
2918 : : struct spdk_blob_store *bs;
2919 : : struct spdk_bs_dev *dev;
2920 : : struct spdk_bs_super_block *super_block;
2921 : 15 : struct spdk_bs_opts opts;
2922 : 15 : struct spdk_bs_super_block_ver1 super_block_v1;
2923 : :
2924 : 15 : dev = init_dev();
2925 : 15 : spdk_bs_opts_init(&opts, sizeof(opts));
2926 [ - + ]: 15 : snprintf(opts.bstype.bstype, sizeof(opts.bstype.bstype), "TESTTYPE");
2927 : :
2928 : : /* Initialize a new blob store */
2929 : 15 : spdk_bs_init(dev, &opts, bs_op_with_handle_complete, NULL);
2930 : 15 : poll_threads();
2931 : 15 : CU_ASSERT(g_bserrno == 0);
2932 [ - + ]: 15 : SPDK_CU_ASSERT_FATAL(g_bs != NULL);
2933 : 15 : bs = g_bs;
2934 : :
2935 : : /* Unload the blob store */
2936 : 15 : spdk_bs_unload(bs, bs_op_complete, NULL);
2937 : 15 : poll_threads();
2938 : 15 : CU_ASSERT(g_bserrno == 0);
2939 : 15 : g_bs = NULL;
2940 : 15 : g_blob = NULL;
2941 : 15 : g_blobid = 0;
2942 : :
2943 : : /* Load an existing blob store with version newer than supported */
2944 : 15 : super_block = (struct spdk_bs_super_block *)g_dev_buffer;
2945 : 15 : super_block->version++;
2946 : :
2947 : 15 : dev = init_dev();
2948 [ - + ]: 15 : memset(opts.bstype.bstype, 0, sizeof(opts.bstype.bstype));
2949 : 15 : spdk_bs_load(dev, &opts, bs_op_with_handle_complete, NULL);
2950 : 15 : poll_threads();
2951 : 15 : CU_ASSERT(g_bserrno != 0);
2952 : :
2953 : : /* Create a new blob store with super block version 1 */
2954 : 15 : dev = init_dev();
2955 : 15 : super_block_v1.version = 1;
2956 : 15 : memcpy(super_block_v1.signature, "SPDKBLOB", sizeof(super_block_v1.signature));
2957 : 15 : super_block_v1.length = 0x1000;
2958 : 15 : super_block_v1.clean = 1;
2959 : 15 : super_block_v1.super_blob = 0xFFFFFFFFFFFFFFFF;
2960 : 15 : super_block_v1.cluster_size = 0x100000;
2961 : 15 : super_block_v1.used_page_mask_start = 0x01;
2962 : 15 : super_block_v1.used_page_mask_len = 0x01;
2963 : 15 : super_block_v1.used_cluster_mask_start = 0x02;
2964 : 15 : super_block_v1.used_cluster_mask_len = 0x01;
2965 : 15 : super_block_v1.md_start = 0x03;
2966 : 15 : super_block_v1.md_len = 0x40;
2967 [ - + ]: 15 : memset(super_block_v1.reserved, 0, 4036);
2968 : 15 : super_block_v1.crc = blob_md_page_calc_crc(&super_block_v1);
2969 : 15 : memcpy(g_dev_buffer, &super_block_v1, sizeof(struct spdk_bs_super_block_ver1));
2970 : :
2971 [ - + ]: 15 : memset(opts.bstype.bstype, 0, sizeof(opts.bstype.bstype));
2972 : 15 : spdk_bs_load(dev, &opts, bs_op_with_handle_complete, NULL);
2973 : 15 : poll_threads();
2974 : 15 : CU_ASSERT(g_bserrno == 0);
2975 [ - + ]: 15 : SPDK_CU_ASSERT_FATAL(g_bs != NULL);
2976 : 15 : bs = g_bs;
2977 : :
2978 : 15 : spdk_bs_unload(bs, bs_op_complete, NULL);
2979 : 15 : poll_threads();
2980 : 15 : CU_ASSERT(g_bserrno == 0);
2981 : 15 : g_bs = NULL;
2982 : 15 : }
2983 : :
2984 : : static void
2985 : 15 : bs_test_recover_cluster_count(void)
2986 : : {
2987 : : struct spdk_blob_store *bs;
2988 : : struct spdk_bs_dev *dev;
2989 : 15 : struct spdk_bs_super_block super_block;
2990 : 15 : struct spdk_bs_opts opts;
2991 : :
2992 : 15 : dev = init_dev();
2993 : 15 : spdk_bs_opts_init(&opts, sizeof(opts));
2994 [ - + ]: 15 : snprintf(opts.bstype.bstype, sizeof(opts.bstype.bstype), "TESTTYPE");
2995 : :
2996 : 15 : super_block.version = 3;
2997 : 15 : memcpy(super_block.signature, "SPDKBLOB", sizeof(super_block.signature));
2998 : 15 : super_block.length = 0x1000;
2999 : 15 : super_block.clean = 0;
3000 : 15 : super_block.super_blob = 0xFFFFFFFFFFFFFFFF;
3001 : 15 : super_block.cluster_size = g_phys_blocklen;
3002 : 15 : super_block.used_page_mask_start = 0x01;
3003 : 15 : super_block.used_page_mask_len = 0x01;
3004 : 15 : super_block.used_cluster_mask_start = 0x02;
3005 : 15 : super_block.used_cluster_mask_len = 0x01;
3006 : 15 : super_block.used_blobid_mask_start = 0x03;
3007 : 15 : super_block.used_blobid_mask_len = 0x01;
3008 : 15 : super_block.md_page_size = g_phys_blocklen;
3009 : 15 : super_block.md_start = 0x04;
3010 : 15 : super_block.md_len = 0x40;
3011 [ - + ]: 15 : memset(super_block.bstype.bstype, 0, sizeof(super_block.bstype.bstype));
3012 : 15 : super_block.size = dev->blockcnt * dev->blocklen;
3013 : 15 : super_block.io_unit_size = 0x1000;
3014 [ - + ]: 15 : memset(super_block.reserved, 0, SPDK_SIZEOF_MEMBER(struct spdk_bs_super_block, reserved));
3015 : 15 : super_block.crc = blob_md_page_calc_crc(&super_block);
3016 : 15 : memcpy(g_dev_buffer, &super_block, sizeof(struct spdk_bs_super_block));
3017 : :
3018 [ - + ]: 15 : memset(opts.bstype.bstype, 0, sizeof(opts.bstype.bstype));
3019 : 15 : spdk_bs_load(dev, &opts, bs_op_with_handle_complete, NULL);
3020 : 15 : poll_threads();
3021 : 15 : CU_ASSERT(g_bserrno == 0);
3022 [ - + ]: 15 : SPDK_CU_ASSERT_FATAL(g_bs != NULL);
3023 : 15 : bs = g_bs;
3024 : 15 : CU_ASSERT(bs->num_free_clusters == bs->total_clusters - (super_block.md_start +
3025 : : super_block.md_len));
3026 : :
3027 : 15 : spdk_bs_unload(bs, bs_op_complete, NULL);
3028 : 15 : poll_threads();
3029 : 15 : CU_ASSERT(g_bserrno == 0);
3030 : 15 : g_bs = NULL;
3031 : 15 : }
3032 : :
3033 : : static void
3034 : 45 : bs_grow_live_size(uint64_t new_blockcnt)
3035 : : {
3036 : : struct spdk_blob_store *bs;
3037 : : struct spdk_bs_dev *dev;
3038 : 45 : struct spdk_bs_super_block super_block;
3039 : 45 : struct spdk_bs_opts opts;
3040 : 45 : struct spdk_bs_md_mask mask;
3041 : : uint64_t bdev_size;
3042 : : uint64_t total_data_clusters;
3043 : :
3044 : : /*
3045 : : * Further down the test the dev size will be larger than the g_dev_buffer size,
3046 : : * so we set clear_method to NONE, or the blobstore will try to clear the dev and
3047 : : * will write beyond the end of g_dev_buffer.
3048 : : */
3049 : 45 : dev = init_dev();
3050 : 45 : spdk_bs_opts_init(&opts, sizeof(opts));
3051 : 45 : opts.clear_method = BS_CLEAR_WITH_NONE;
3052 : 45 : spdk_bs_init(dev, &opts, bs_op_with_handle_complete, NULL);
3053 : 45 : poll_threads();
3054 : 45 : CU_ASSERT(g_bserrno == 0);
3055 [ - + ]: 45 : SPDK_CU_ASSERT_FATAL(g_bs != NULL);
3056 : 45 : bs = g_bs;
3057 : :
3058 : : /*
3059 : : * Set the dev size according to the new_blockcnt,
3060 : : * then the blobstore will adjust the metadata according to the new size.
3061 : : */
3062 : 45 : dev->blockcnt = new_blockcnt;
3063 : 45 : bdev_size = dev->blockcnt * dev->blocklen;
3064 : 45 : spdk_bs_grow_live(bs, bs_op_complete, NULL);
3065 : 45 : poll_threads();
3066 : 45 : CU_ASSERT(g_bserrno == 0);
3067 : 45 : total_data_clusters = spdk_bs_total_data_cluster_count(bs);
3068 : :
3069 : : /* Make sure the super block is updated. */
3070 : 45 : memcpy(&super_block, g_dev_buffer, sizeof(struct spdk_bs_super_block));
3071 : 45 : CU_ASSERT(super_block.size == bdev_size);
3072 : 45 : CU_ASSERT(super_block.clean == 0);
3073 : : /* The used_cluster mask is not written out until first spdk_bs_unload. */
3074 : 45 : memcpy(&mask, g_dev_buffer + super_block.used_cluster_mask_start * g_phys_blocklen,
3075 : : sizeof(struct spdk_bs_md_mask));
3076 : 45 : CU_ASSERT(mask.type == 0);
3077 : 45 : CU_ASSERT(mask.length == 0);
3078 : :
3079 : 45 : spdk_bs_unload(bs, bs_op_complete, NULL);
3080 : 45 : poll_threads();
3081 : 45 : CU_ASSERT(g_bserrno == 0);
3082 : 45 : g_bs = NULL;
3083 : :
3084 : : /* Make sure all metadata is correct, super block and used_cluster mask. */
3085 : 45 : memcpy(&super_block, g_dev_buffer, sizeof(struct spdk_bs_super_block));
3086 : 45 : CU_ASSERT(super_block.size == bdev_size);
3087 : 45 : CU_ASSERT(super_block.clean == 1);
3088 : 45 : memcpy(&mask, g_dev_buffer + super_block.used_cluster_mask_start * g_phys_blocklen,
3089 : : sizeof(struct spdk_bs_md_mask));
3090 : 45 : CU_ASSERT(mask.type == SPDK_MD_MASK_TYPE_USED_CLUSTERS);
3091 : 45 : CU_ASSERT(mask.length == bdev_size / (1 * 1024 * 1024));
3092 : :
3093 : : /* Load blobstore and check the cluster counts again. */
3094 : 45 : dev = init_dev();
3095 : 45 : dev->blockcnt = new_blockcnt;
3096 : 45 : spdk_bs_load(dev, NULL, bs_op_with_handle_complete, NULL);
3097 : 45 : poll_threads();
3098 : 45 : CU_ASSERT(g_bserrno == 0);
3099 [ - + ]: 45 : SPDK_CU_ASSERT_FATAL(g_bs != NULL);
3100 : 45 : CU_ASSERT(super_block.clean == 1);
3101 : 45 : bs = g_bs;
3102 : 45 : CU_ASSERT(total_data_clusters == spdk_bs_total_data_cluster_count(bs));
3103 : :
3104 : : /* Perform grow without change in size, expected pass. */
3105 : 45 : spdk_bs_grow_live(bs, bs_op_complete, NULL);
3106 : 45 : poll_threads();
3107 : 45 : CU_ASSERT(g_bserrno == 0);
3108 : 45 : CU_ASSERT(total_data_clusters == spdk_bs_total_data_cluster_count(bs));
3109 : 45 : memcpy(&super_block, g_dev_buffer, sizeof(struct spdk_bs_super_block));
3110 : 45 : CU_ASSERT(super_block.size == bdev_size);
3111 : 45 : CU_ASSERT(super_block.clean == 1);
3112 : :
3113 : 45 : spdk_bs_unload(bs, bs_op_complete, NULL);
3114 : 45 : poll_threads();
3115 : 45 : CU_ASSERT(g_bserrno == 0);
3116 : 45 : g_bs = NULL;
3117 : 45 : }
3118 : :
3119 : : static void
3120 : 15 : bs_grow_live(void)
3121 : : {
3122 : : /* No change expected */
3123 : 15 : bs_grow_live_size(DEV_BUFFER_BLOCKCNT);
3124 : :
3125 : : /* Size slightly increased, but not enough to increase cluster count */
3126 : 15 : bs_grow_live_size(DEV_BUFFER_BLOCKCNT + 1);
3127 : :
3128 : : /* Size doubled, increasing the cluster count */
3129 : 15 : bs_grow_live_size(DEV_BUFFER_BLOCKCNT * 2);
3130 : 15 : }
3131 : :
3132 : : static void
3133 : 15 : bs_grow_live_no_space(void)
3134 : : {
3135 : : struct spdk_blob_store *bs;
3136 : : struct spdk_bs_dev *dev;
3137 : 15 : struct spdk_bs_super_block super_block;
3138 : 15 : struct spdk_bs_opts opts;
3139 : 15 : struct spdk_bs_md_mask mask;
3140 : : uint64_t bdev_size_init;
3141 : : uint64_t total_data_clusters, max_clusters;
3142 : :
3143 : : /*
3144 : : * Further down the test the dev size will be larger than the g_dev_buffer size,
3145 : : * so we set clear_method to NONE, or the blobstore will try to clear the dev and
3146 : : * will write beyond the end of g_dev_buffer.
3147 : : */
3148 : 15 : dev = init_dev();
3149 : 15 : bdev_size_init = dev->blockcnt * dev->blocklen;
3150 : 15 : spdk_bs_opts_init(&opts, sizeof(opts));
3151 : 15 : opts.clear_method = BS_CLEAR_WITH_NONE;
3152 : 15 : spdk_bs_init(dev, &opts, bs_op_with_handle_complete, NULL);
3153 : 15 : poll_threads();
3154 : 15 : CU_ASSERT(g_bserrno == 0);
3155 [ - + ]: 15 : SPDK_CU_ASSERT_FATAL(g_bs != NULL);
3156 : 15 : bs = g_bs;
3157 : 15 : total_data_clusters = spdk_bs_total_data_cluster_count(bs);
3158 : :
3159 : : /*
3160 : : * The default dev size is 64M, here we set the dev size to 32M,
3161 : : * expecting EILSEQ due to super_block validation and no change in blobstore.
3162 : : */
3163 [ - + ]: 15 : dev->blockcnt = (32L * 1024L * 1024L) / dev->blocklen;
3164 : 15 : spdk_bs_grow_live(bs, bs_op_complete, NULL);
3165 : 15 : poll_threads();
3166 : : /* This error code comes from bs_super_validate() */
3167 : 15 : CU_ASSERT(g_bserrno == -EILSEQ);
3168 : 15 : CU_ASSERT(total_data_clusters == spdk_bs_total_data_cluster_count(bs));
3169 : 15 : memcpy(&super_block, g_dev_buffer, sizeof(struct spdk_bs_super_block));
3170 : 15 : CU_ASSERT(super_block.size == bdev_size_init);
3171 : :
3172 : : /*
3173 : : * Blobstore in this test has only space for single md_page for used_clusters,
3174 : : * which fits 1 bit per cluster minus the md header.
3175 : : *
3176 : : * Dev size is increased to exceed the reserved space for the used_cluster_mask
3177 : : * in the metadata, expecting ENOSPC and no change in blobstore.
3178 : : */
3179 : 15 : max_clusters = (spdk_bs_get_page_size(bs) - sizeof(struct spdk_bs_md_mask)) * 8;
3180 : 15 : max_clusters += 1;
3181 [ - + ]: 15 : dev->blockcnt = (max_clusters * spdk_bs_get_cluster_size(bs)) / dev->blocklen;
3182 : 15 : spdk_bs_grow_live(bs, bs_op_complete, NULL);
3183 : 15 : poll_threads();
3184 : 15 : CU_ASSERT(g_bserrno == -ENOSPC);
3185 : 15 : CU_ASSERT(total_data_clusters == spdk_bs_total_data_cluster_count(bs));
3186 : 15 : memcpy(&super_block, g_dev_buffer, sizeof(struct spdk_bs_super_block));
3187 : 15 : CU_ASSERT(super_block.size == bdev_size_init);
3188 : :
3189 : : /*
3190 : : * No change should have occurred for the duration of the test,
3191 : : * unload blobstore and check metadata.
3192 : : */
3193 : 15 : spdk_bs_unload(bs, bs_op_complete, NULL);
3194 : 15 : poll_threads();
3195 : 15 : CU_ASSERT(g_bserrno == 0);
3196 : 15 : g_bs = NULL;
3197 : :
3198 : : /* Make sure all metadata is correct, super block and used_cluster mask. */
3199 : 15 : memcpy(&super_block, g_dev_buffer, sizeof(struct spdk_bs_super_block));
3200 : 15 : CU_ASSERT(super_block.size == bdev_size_init);
3201 : 15 : CU_ASSERT(super_block.clean == 1);
3202 : 15 : memcpy(&mask, g_dev_buffer + super_block.used_cluster_mask_start * g_phys_blocklen,
3203 : : sizeof(struct spdk_bs_md_mask));
3204 : 15 : CU_ASSERT(mask.type == SPDK_MD_MASK_TYPE_USED_CLUSTERS);
3205 : 15 : CU_ASSERT(mask.length == bdev_size_init / (1 * 1024 * 1024));
3206 : :
3207 : : /* Load blobstore and check the cluster counts again. */
3208 : 15 : dev = init_dev();
3209 : 15 : spdk_bs_load(dev, NULL, bs_op_with_handle_complete, NULL);
3210 : 15 : poll_threads();
3211 : 15 : CU_ASSERT(g_bserrno == 0);
3212 [ - + ]: 15 : SPDK_CU_ASSERT_FATAL(g_bs != NULL);
3213 : 15 : bs = g_bs;
3214 : 15 : CU_ASSERT(total_data_clusters == spdk_bs_total_data_cluster_count(bs));
3215 : :
3216 : 15 : spdk_bs_unload(bs, bs_op_complete, NULL);
3217 : 15 : poll_threads();
3218 : 15 : CU_ASSERT(g_bserrno == 0);
3219 : 15 : g_bs = NULL;
3220 : 15 : }
3221 : :
3222 : : static void
3223 : 15 : bs_test_grow(void)
3224 : : {
3225 : : struct spdk_blob_store *bs;
3226 : : struct spdk_bs_dev *dev;
3227 : 15 : struct spdk_bs_super_block super_block;
3228 : 15 : struct spdk_bs_opts opts;
3229 : 15 : struct spdk_bs_md_mask mask;
3230 : : uint64_t bdev_size;
3231 : :
3232 : 15 : dev = init_dev();
3233 : 15 : bdev_size = dev->blockcnt * dev->blocklen;
3234 : 15 : spdk_bs_opts_init(&opts, sizeof(opts));
3235 : 15 : spdk_bs_init(dev, &opts, bs_op_with_handle_complete, NULL);
3236 : 15 : poll_threads();
3237 : 15 : CU_ASSERT(g_bserrno == 0);
3238 [ - + ]: 15 : SPDK_CU_ASSERT_FATAL(g_bs != NULL);
3239 : 15 : bs = g_bs;
3240 : :
3241 : 15 : spdk_bs_unload(bs, bs_op_complete, NULL);
3242 : 15 : poll_threads();
3243 : 15 : CU_ASSERT(g_bserrno == 0);
3244 : 15 : g_bs = NULL;
3245 : :
3246 : : /*
3247 : : * To make sure all the metadata are updated to the disk,
3248 : : * we check the g_dev_buffer after spdk_bs_unload.
3249 : : */
3250 : 15 : memcpy(&super_block, g_dev_buffer, sizeof(struct spdk_bs_super_block));
3251 : 15 : CU_ASSERT(super_block.size == bdev_size);
3252 : :
3253 : : /*
3254 : : * Make sure the used_cluster mask is correct.
3255 : : */
3256 : 15 : memcpy(&mask, g_dev_buffer + super_block.used_cluster_mask_start * g_phys_blocklen,
3257 : : sizeof(struct spdk_bs_md_mask));
3258 : 15 : CU_ASSERT(mask.type == SPDK_MD_MASK_TYPE_USED_CLUSTERS);
3259 : 15 : CU_ASSERT(mask.length == bdev_size / (1 * 1024 * 1024));
3260 : :
3261 : : /*
3262 : : * The default dev size is 64M, here we set the dev size to 128M,
3263 : : * then the blobstore will adjust the metadata according to the new size.
3264 : : * The dev size is larger than the g_dev_buffer size, so we set clear_method
3265 : : * to NONE, or the blobstore will try to clear the dev and will write beyond
3266 : : * the end of g_dev_buffer.
3267 : : */
3268 : 15 : dev = init_dev();
3269 [ - + ]: 15 : dev->blockcnt = (128L * 1024L * 1024L) / dev->blocklen;
3270 : 15 : bdev_size = dev->blockcnt * dev->blocklen;
3271 : 15 : spdk_bs_opts_init(&opts, sizeof(opts));
3272 : 15 : opts.clear_method = BS_CLEAR_WITH_NONE;
3273 : 15 : spdk_bs_grow(dev, &opts, bs_op_with_handle_complete, NULL);
3274 : 15 : poll_threads();
3275 : 15 : CU_ASSERT(g_bserrno == 0);
3276 [ - + ]: 15 : SPDK_CU_ASSERT_FATAL(g_bs != NULL);
3277 : 15 : bs = g_bs;
3278 : :
3279 : : /*
3280 : : * After spdk_bs_grow, all metadata are updated to the disk.
3281 : : * So we can check g_dev_buffer now.
3282 : : */
3283 : 15 : memcpy(&super_block, g_dev_buffer, sizeof(struct spdk_bs_super_block));
3284 : 15 : CU_ASSERT(super_block.size == bdev_size);
3285 : :
3286 : : /*
3287 : : * Make sure the used_cluster mask has been updated according to the bdev size
3288 : : */
3289 : 15 : memcpy(&mask, g_dev_buffer + super_block.used_cluster_mask_start * g_phys_blocklen,
3290 : : sizeof(struct spdk_bs_md_mask));
3291 : 15 : CU_ASSERT(mask.type == SPDK_MD_MASK_TYPE_USED_CLUSTERS);
3292 : 15 : CU_ASSERT(mask.length == bdev_size / (1 * 1024 * 1024));
3293 : :
3294 : 15 : spdk_bs_unload(bs, bs_op_complete, NULL);
3295 : 15 : poll_threads();
3296 : 15 : CU_ASSERT(g_bserrno == 0);
3297 : 15 : g_bs = NULL;
3298 : 15 : }
3299 : :
3300 : : /*
3301 : : * Create a blobstore and then unload it.
3302 : : */
3303 : : static void
3304 : 15 : bs_unload(void)
3305 : : {
3306 : 15 : struct spdk_blob_store *bs = g_bs;
3307 : : struct spdk_blob *blob;
3308 : :
3309 : : /* Create a blob and open it. */
3310 : 15 : blob = ut_blob_create_and_open(bs, NULL);
3311 : :
3312 : : /* Try to unload blobstore, should fail with open blob */
3313 : 15 : g_bserrno = -1;
3314 : 15 : spdk_bs_unload(bs, bs_op_complete, NULL);
3315 : 15 : poll_threads();
3316 : 15 : CU_ASSERT(g_bserrno == -EBUSY);
3317 [ - + ]: 15 : SPDK_CU_ASSERT_FATAL(g_bs != NULL);
3318 : :
3319 : : /* Close the blob, then successfully unload blobstore */
3320 : 15 : g_bserrno = -1;
3321 : 15 : spdk_blob_close(blob, blob_op_complete, NULL);
3322 : 15 : poll_threads();
3323 : 15 : CU_ASSERT(g_bserrno == 0);
3324 : 15 : }
3325 : :
3326 : : /*
3327 : : * Create a blobstore with a cluster size different than the default, and ensure it is
3328 : : * persisted.
3329 : : */
3330 : : static void
3331 : 15 : bs_cluster_sz(void)
3332 : : {
3333 : 15 : struct spdk_blob_store *bs;
3334 : : struct spdk_bs_dev *dev;
3335 : 15 : struct spdk_bs_opts opts;
3336 : : uint32_t cluster_sz;
3337 : :
3338 : : /* Set cluster size to zero */
3339 : 15 : dev = init_dev();
3340 : 15 : spdk_bs_opts_init(&opts, sizeof(opts));
3341 : 15 : opts.cluster_sz = 0;
3342 : :
3343 : : /* Initialize a new blob store */
3344 : 15 : spdk_bs_init(dev, &opts, bs_op_with_handle_complete, NULL);
3345 : 15 : poll_threads();
3346 : 15 : CU_ASSERT(g_bserrno == -EINVAL);
3347 [ - + ]: 15 : SPDK_CU_ASSERT_FATAL(g_bs == NULL);
3348 : :
3349 : : /*
3350 : : * Set cluster size to blobstore page size,
3351 : : * to work it is required to be at least twice the blobstore page size.
3352 : : */
3353 : 15 : dev = init_dev();
3354 : 15 : spdk_bs_opts_init(&opts, sizeof(opts));
3355 : 15 : opts.cluster_sz = g_phys_blocklen;
3356 : :
3357 : : /* Initialize a new blob store */
3358 : 15 : spdk_bs_init(dev, &opts, bs_op_with_handle_complete, NULL);
3359 : 15 : poll_threads();
3360 : 15 : CU_ASSERT(g_bserrno == -ENOMEM);
3361 [ - + ]: 15 : SPDK_CU_ASSERT_FATAL(g_bs == NULL);
3362 : :
3363 : : /*
3364 : : * Set cluster size to lower than page size,
3365 : : * to work it is required to be at least twice the blobstore page size.
3366 : : */
3367 : 15 : dev = init_dev();
3368 : 15 : spdk_bs_opts_init(&opts, sizeof(opts));
3369 : 15 : opts.cluster_sz = g_phys_blocklen - 1;
3370 : :
3371 : : /* Initialize a new blob store */
3372 : 15 : spdk_bs_init(dev, &opts, bs_op_with_handle_complete, NULL);
3373 : 15 : poll_threads();
3374 : 15 : CU_ASSERT(g_bserrno == -EINVAL);
3375 [ - + ]: 15 : SPDK_CU_ASSERT_FATAL(g_bs == NULL);
3376 : :
3377 : : /* Set cluster size to twice the default */
3378 : 15 : dev = init_dev();
3379 : 15 : spdk_bs_opts_init(&opts, sizeof(opts));
3380 : 15 : opts.cluster_sz *= 2;
3381 : 15 : cluster_sz = opts.cluster_sz;
3382 : :
3383 : : /* Initialize a new blob store */
3384 : 15 : spdk_bs_init(dev, &opts, bs_op_with_handle_complete, NULL);
3385 : 15 : poll_threads();
3386 : 15 : CU_ASSERT(g_bserrno == 0);
3387 [ - + ]: 15 : SPDK_CU_ASSERT_FATAL(g_bs != NULL);
3388 : 15 : bs = g_bs;
3389 : :
3390 : 15 : CU_ASSERT(spdk_bs_get_cluster_size(bs) == cluster_sz);
3391 : :
3392 : 15 : ut_bs_reload(&bs, &opts);
3393 : :
3394 : 15 : CU_ASSERT(spdk_bs_get_cluster_size(bs) == cluster_sz);
3395 : :
3396 : 15 : spdk_bs_unload(bs, bs_op_complete, NULL);
3397 : 15 : poll_threads();
3398 : 15 : CU_ASSERT(g_bserrno == 0);
3399 : 15 : g_bs = NULL;
3400 : 15 : }
3401 : :
3402 : : /*
3403 : : * Create a blobstore, reload it and ensure total usable cluster count
3404 : : * stays the same.
3405 : : */
3406 : : static void
3407 : 15 : bs_usable_clusters(void)
3408 : : {
3409 : 15 : struct spdk_blob_store *bs = g_bs;
3410 : : struct spdk_blob *blob;
3411 : : uint32_t clusters;
3412 : : int i;
3413 : :
3414 : :
3415 : 15 : clusters = spdk_bs_total_data_cluster_count(bs);
3416 : :
3417 : 15 : ut_bs_reload(&bs, NULL);
3418 : :
3419 : 15 : CU_ASSERT(spdk_bs_total_data_cluster_count(bs) == clusters);
3420 : :
3421 : : /* Create and resize blobs to make sure that usable cluster count won't change */
3422 [ + + ]: 75 : for (i = 0; i < 4; i++) {
3423 : 60 : g_bserrno = -1;
3424 : 60 : g_blobid = SPDK_BLOBID_INVALID;
3425 : 60 : blob = ut_blob_create_and_open(bs, NULL);
3426 : :
3427 : 60 : spdk_blob_resize(blob, 10, blob_op_complete, NULL);
3428 : 60 : poll_threads();
3429 : 60 : CU_ASSERT(g_bserrno == 0);
3430 : :
3431 : 60 : g_bserrno = -1;
3432 : 60 : spdk_blob_close(blob, blob_op_complete, NULL);
3433 : 60 : poll_threads();
3434 : 60 : CU_ASSERT(g_bserrno == 0);
3435 : :
3436 : 60 : CU_ASSERT(spdk_bs_total_data_cluster_count(bs) == clusters);
3437 : : }
3438 : :
3439 : : /* Reload the blob store to make sure that nothing changed */
3440 : 15 : ut_bs_reload(&bs, NULL);
3441 : :
3442 : 15 : CU_ASSERT(spdk_bs_total_data_cluster_count(bs) == clusters);
3443 : 15 : }
3444 : :
3445 : : /*
3446 : : * Test resizing of the metadata blob. This requires creating enough blobs
3447 : : * so that one cluster is not enough to fit the metadata for those blobs.
3448 : : * To induce this condition to happen more quickly, we reduce the cluster
3449 : : * size to 16KB, which means only 4 4KB blob metadata pages can fit.
3450 : : */
3451 : : static void
3452 : 15 : bs_resize_md(void)
3453 : 15 : {
3454 : 15 : struct spdk_blob_store *bs;
3455 : 15 : const int CLUSTER_PAGE_COUNT = 4;
3456 : 15 : const int NUM_BLOBS = CLUSTER_PAGE_COUNT * 4;
3457 : : struct spdk_bs_dev *dev;
3458 : 15 : struct spdk_bs_opts opts;
3459 : : struct spdk_blob *blob;
3460 : 15 : struct spdk_blob_opts blob_opts;
3461 : : uint32_t cluster_sz;
3462 [ - + ]: 15 : spdk_blob_id blobids[NUM_BLOBS];
3463 : : int i;
3464 : :
3465 : :
3466 : 15 : dev = init_dev();
3467 : 15 : spdk_bs_opts_init(&opts, sizeof(opts));
3468 : 15 : opts.cluster_sz = CLUSTER_PAGE_COUNT * g_phys_blocklen;
3469 : 15 : cluster_sz = opts.cluster_sz;
3470 : :
3471 : : /* Initialize a new blob store */
3472 : 15 : spdk_bs_init(dev, &opts, bs_op_with_handle_complete, NULL);
3473 : 15 : poll_threads();
3474 : 15 : CU_ASSERT(g_bserrno == 0);
3475 [ - + ]: 15 : SPDK_CU_ASSERT_FATAL(g_bs != NULL);
3476 : 15 : bs = g_bs;
3477 : :
3478 : 15 : CU_ASSERT(spdk_bs_get_cluster_size(bs) == cluster_sz);
3479 : :
3480 : 15 : ut_spdk_blob_opts_init(&blob_opts);
3481 : :
3482 [ + + ]: 255 : for (i = 0; i < NUM_BLOBS; i++) {
3483 : 240 : g_bserrno = -1;
3484 : 240 : g_blobid = SPDK_BLOBID_INVALID;
3485 : 240 : spdk_bs_create_blob_ext(bs, &blob_opts, blob_op_with_id_complete, NULL);
3486 : 240 : poll_threads();
3487 : 240 : CU_ASSERT(g_bserrno == 0);
3488 : 240 : CU_ASSERT(g_blobid != SPDK_BLOBID_INVALID);
3489 : 240 : blobids[i] = g_blobid;
3490 : : }
3491 : :
3492 : 15 : ut_bs_reload(&bs, &opts);
3493 : :
3494 : 15 : CU_ASSERT(spdk_bs_get_cluster_size(bs) == cluster_sz);
3495 : :
3496 [ + + ]: 255 : for (i = 0; i < NUM_BLOBS; i++) {
3497 : 240 : g_bserrno = -1;
3498 : 240 : g_blob = NULL;
3499 : 240 : spdk_bs_open_blob(bs, blobids[i], blob_op_with_handle_complete, NULL);
3500 : 240 : poll_threads();
3501 : 240 : CU_ASSERT(g_bserrno == 0);
3502 : 240 : CU_ASSERT(g_blob != NULL);
3503 : 240 : blob = g_blob;
3504 : 240 : g_bserrno = -1;
3505 : 240 : spdk_blob_close(blob, blob_op_complete, NULL);
3506 : 240 : poll_threads();
3507 : 240 : CU_ASSERT(g_bserrno == 0);
3508 : : }
3509 : :
3510 : 15 : spdk_bs_unload(bs, bs_op_complete, NULL);
3511 : 15 : poll_threads();
3512 : 15 : CU_ASSERT(g_bserrno == 0);
3513 : 15 : g_bs = NULL;
3514 : 15 : }
3515 : :
3516 : : static void
3517 : 15 : bs_destroy(void)
3518 : : {
3519 : : struct spdk_blob_store *bs;
3520 : : struct spdk_bs_dev *dev;
3521 : :
3522 : : /* Initialize a new blob store */
3523 : 15 : dev = init_dev();
3524 : 15 : spdk_bs_init(dev, NULL, bs_op_with_handle_complete, NULL);
3525 : 15 : poll_threads();
3526 : 15 : CU_ASSERT(g_bserrno == 0);
3527 [ - + ]: 15 : SPDK_CU_ASSERT_FATAL(g_bs != NULL);
3528 : 15 : bs = g_bs;
3529 : :
3530 : : /* Destroy the blob store */
3531 : 15 : g_bserrno = -1;
3532 : 15 : spdk_bs_destroy(bs, bs_op_complete, NULL);
3533 : 15 : poll_threads();
3534 : 15 : CU_ASSERT(g_bserrno == 0);
3535 : :
3536 : : /* Loading an non-existent blob store should fail. */
3537 : 15 : g_bs = NULL;
3538 : 15 : dev = init_dev();
3539 : :
3540 : 15 : g_bserrno = 0;
3541 : 15 : spdk_bs_load(dev, NULL, bs_op_with_handle_complete, NULL);
3542 : 15 : poll_threads();
3543 : 15 : CU_ASSERT(g_bserrno != 0);
3544 : 15 : }
3545 : :
3546 : : /* Try to hit all of the corner cases associated with serializing
3547 : : * a blob to disk
3548 : : */
3549 : : static void
3550 : 15 : blob_serialize_test(void)
3551 : : {
3552 : : struct spdk_bs_dev *dev;
3553 : 15 : struct spdk_bs_opts opts;
3554 : 15 : struct spdk_blob_store *bs;
3555 : 15 : spdk_blob_id blobid[2];
3556 : 15 : struct spdk_blob *blob[2];
3557 : : uint64_t i;
3558 : : char *value;
3559 : : int rc;
3560 : :
3561 : 15 : dev = init_dev();
3562 : :
3563 : : /* Initialize a new blobstore with very small clusters */
3564 : 15 : spdk_bs_opts_init(&opts, sizeof(opts));
3565 : 15 : opts.cluster_sz = dev->blocklen * 8;
3566 : 15 : spdk_bs_init(dev, &opts, bs_op_with_handle_complete, NULL);
3567 : 15 : poll_threads();
3568 : 15 : CU_ASSERT(g_bserrno == 0);
3569 [ - + ]: 15 : SPDK_CU_ASSERT_FATAL(g_bs != NULL);
3570 : 15 : bs = g_bs;
3571 : :
3572 : : /* Create and open two blobs */
3573 [ + + ]: 45 : for (i = 0; i < 2; i++) {
3574 : 30 : blob[i] = ut_blob_create_and_open(bs, NULL);
3575 : 30 : blobid[i] = spdk_blob_get_id(blob[i]);
3576 : :
3577 : : /* Set a fairly large xattr on both blobs to eat up
3578 : : * metadata space
3579 : : */
3580 : 30 : value = calloc(dev->blocklen - 64, sizeof(char));
3581 [ - + ]: 30 : SPDK_CU_ASSERT_FATAL(value != NULL);
3582 [ - + ]: 30 : memset(value, i, dev->blocklen / 2);
3583 : 30 : rc = spdk_blob_set_xattr(blob[i], "name", value, dev->blocklen - 64);
3584 : 30 : CU_ASSERT(rc == 0);
3585 : 30 : free(value);
3586 : : }
3587 : :
3588 : : /* Resize the blobs, alternating 1 cluster at a time.
3589 : : * This thwarts run length encoding and will cause spill
3590 : : * over of the extents.
3591 : : */
3592 [ + + ]: 105 : for (i = 0; i < 6; i++) {
3593 : 90 : spdk_blob_resize(blob[i % 2], (i / 2) + 1, blob_op_complete, NULL);
3594 : 90 : poll_threads();
3595 : 90 : CU_ASSERT(g_bserrno == 0);
3596 : : }
3597 : :
3598 [ + + ]: 45 : for (i = 0; i < 2; i++) {
3599 : 30 : spdk_blob_sync_md(blob[i], blob_op_complete, NULL);
3600 : 30 : poll_threads();
3601 : 30 : CU_ASSERT(g_bserrno == 0);
3602 : : }
3603 : :
3604 : : /* Close the blobs */
3605 [ + + ]: 45 : for (i = 0; i < 2; i++) {
3606 : 30 : spdk_blob_close(blob[i], blob_op_complete, NULL);
3607 : 30 : poll_threads();
3608 : 30 : CU_ASSERT(g_bserrno == 0);
3609 : : }
3610 : :
3611 : 15 : ut_bs_reload(&bs, &opts);
3612 : :
3613 [ + + ]: 45 : for (i = 0; i < 2; i++) {
3614 : 30 : blob[i] = NULL;
3615 : :
3616 : 30 : spdk_bs_open_blob(bs, blobid[i], blob_op_with_handle_complete, NULL);
3617 : 30 : poll_threads();
3618 : 30 : CU_ASSERT(g_bserrno == 0);
3619 : 30 : CU_ASSERT(g_blob != NULL);
3620 : 30 : blob[i] = g_blob;
3621 : :
3622 : 30 : CU_ASSERT(spdk_blob_get_num_clusters(blob[i]) == 3);
3623 : :
3624 : 30 : spdk_blob_close(blob[i], blob_op_complete, NULL);
3625 : 30 : poll_threads();
3626 : 30 : CU_ASSERT(g_bserrno == 0);
3627 : : }
3628 : :
3629 : 15 : spdk_bs_unload(bs, bs_op_complete, NULL);
3630 : 15 : poll_threads();
3631 : 15 : CU_ASSERT(g_bserrno == 0);
3632 : 15 : g_bs = NULL;
3633 : 15 : }
3634 : :
3635 : : static void
3636 : 15 : blob_crc(void)
3637 : : {
3638 : 15 : struct spdk_blob_store *bs = g_bs;
3639 : : struct spdk_blob *blob;
3640 : : spdk_blob_id blobid;
3641 : : uint32_t page_num;
3642 : : int index;
3643 : : struct spdk_blob_md_page *page;
3644 : :
3645 : 15 : blob = ut_blob_create_and_open(bs, NULL);
3646 : 15 : blobid = spdk_blob_get_id(blob);
3647 : :
3648 : 15 : spdk_blob_close(blob, blob_op_complete, NULL);
3649 : 15 : poll_threads();
3650 : 15 : CU_ASSERT(g_bserrno == 0);
3651 : :
3652 : 15 : page_num = bs_blobid_to_page(blobid);
3653 : 15 : index = g_phys_blocklen * (bs->md_start + page_num);
3654 : 15 : page = (struct spdk_blob_md_page *)&g_dev_buffer[index];
3655 : 15 : page->crc = 0;
3656 : :
3657 : 15 : spdk_bs_open_blob(bs, blobid, blob_op_with_handle_complete, NULL);
3658 : 15 : poll_threads();
3659 : 15 : CU_ASSERT(g_bserrno == -EINVAL);
3660 : 15 : CU_ASSERT(g_blob == NULL);
3661 : 15 : g_bserrno = 0;
3662 : :
3663 : 15 : spdk_bs_delete_blob(bs, blobid, blob_op_complete, NULL);
3664 : 15 : poll_threads();
3665 : 15 : CU_ASSERT(g_bserrno == -EINVAL);
3666 : 15 : }
3667 : :
3668 : : static void
3669 : 15 : super_block_crc(void)
3670 : : {
3671 : : struct spdk_blob_store *bs;
3672 : : struct spdk_bs_dev *dev;
3673 : : struct spdk_bs_super_block *super_block;
3674 : :
3675 : 15 : dev = init_dev();
3676 : 15 : spdk_bs_init(dev, NULL, bs_op_with_handle_complete, NULL);
3677 : 15 : poll_threads();
3678 : 15 : CU_ASSERT(g_bserrno == 0);
3679 [ - + ]: 15 : SPDK_CU_ASSERT_FATAL(g_bs != NULL);
3680 : 15 : bs = g_bs;
3681 : :
3682 : 15 : spdk_bs_unload(bs, bs_op_complete, NULL);
3683 : 15 : poll_threads();
3684 : 15 : CU_ASSERT(g_bserrno == 0);
3685 : 15 : g_bs = NULL;
3686 : :
3687 : 15 : super_block = (struct spdk_bs_super_block *)g_dev_buffer;
3688 : 15 : super_block->crc = 0;
3689 : 15 : dev = init_dev();
3690 : :
3691 : : /* Load an existing blob store */
3692 : 15 : g_bserrno = 0;
3693 : 15 : spdk_bs_load(dev, NULL, bs_op_with_handle_complete, NULL);
3694 : 15 : poll_threads();
3695 : 15 : CU_ASSERT(g_bserrno == -EILSEQ);
3696 : 15 : }
3697 : :
3698 : : /* For blob dirty shutdown test case we do the following sub-test cases:
3699 : : * 1 Initialize new blob store and create 1 super blob with some xattrs, then we
3700 : : * dirty shutdown and reload the blob store and verify the xattrs.
3701 : : * 2 Resize the blob from 10 clusters to 20 clusters and then dirty shutdown,
3702 : : * reload the blob store and verify the clusters number.
3703 : : * 3 Create the second blob and then dirty shutdown, reload the blob store
3704 : : * and verify the second blob.
3705 : : * 4 Delete the second blob and then dirty shutdown, reload the blob store
3706 : : * and verify the second blob is invalid.
3707 : : * 5 Create the second blob again and also create the third blob, modify the
3708 : : * md of second blob which makes the md invalid, and then dirty shutdown,
3709 : : * reload the blob store verify the second blob, it should invalid and also
3710 : : * verify the third blob, it should correct.
3711 : : */
3712 : : static void
3713 : 15 : blob_dirty_shutdown(void)
3714 : : {
3715 : : int rc;
3716 : : int index;
3717 : 15 : struct spdk_blob_store *bs = g_bs;
3718 : : spdk_blob_id blobid1, blobid2, blobid3;
3719 : 15 : struct spdk_blob *blob = g_blob;
3720 : 15 : uint64_t length;
3721 : : uint64_t free_clusters;
3722 : 15 : const void *value;
3723 : 15 : size_t value_len;
3724 : : uint32_t page_num;
3725 : : struct spdk_blob_md_page *page;
3726 : 15 : struct spdk_blob_opts blob_opts;
3727 : :
3728 : : /* Create first blob */
3729 : 15 : blobid1 = spdk_blob_get_id(blob);
3730 : :
3731 : : /* Set some xattrs */
3732 : 15 : rc = spdk_blob_set_xattr(blob, "name", "log.txt", strlen("log.txt") + 1);
3733 : 15 : CU_ASSERT(rc == 0);
3734 : :
3735 : 15 : length = 2345;
3736 : 15 : rc = spdk_blob_set_xattr(blob, "length", &length, sizeof(length));
3737 : 15 : CU_ASSERT(rc == 0);
3738 : :
3739 : : /* Put xattr that fits exactly single page.
3740 : : * This results in adding additional pages to MD.
3741 : : * First is flags and smaller xattr, second the large xattr,
3742 : : * third are just the extents.
3743 : : */
3744 : 15 : size_t xattr_length = 4072 - sizeof(struct spdk_blob_md_descriptor_xattr) -
3745 : : strlen("large_xattr");
3746 : 15 : char *xattr = calloc(xattr_length, sizeof(char));
3747 [ - + ]: 15 : SPDK_CU_ASSERT_FATAL(xattr != NULL);
3748 : 15 : rc = spdk_blob_set_xattr(blob, "large_xattr", xattr, xattr_length);
3749 : 15 : free(xattr);
3750 [ - + ]: 15 : SPDK_CU_ASSERT_FATAL(rc == 0);
3751 : :
3752 : : /* Resize the blob */
3753 : 15 : spdk_blob_resize(blob, 10, blob_op_complete, NULL);
3754 : 15 : poll_threads();
3755 : 15 : CU_ASSERT(g_bserrno == 0);
3756 : :
3757 : : /* Set the blob as the super blob */
3758 : 15 : spdk_bs_set_super(bs, blobid1, blob_op_complete, NULL);
3759 : 15 : poll_threads();
3760 : 15 : CU_ASSERT(g_bserrno == 0);
3761 : :
3762 : 15 : free_clusters = spdk_bs_free_cluster_count(bs);
3763 : :
3764 : 15 : spdk_blob_close(blob, blob_op_complete, NULL);
3765 : 15 : poll_threads();
3766 : 15 : CU_ASSERT(g_bserrno == 0);
3767 : 15 : blob = NULL;
3768 : 15 : g_blob = NULL;
3769 : 15 : g_blobid = SPDK_BLOBID_INVALID;
3770 : :
3771 : 15 : ut_bs_dirty_load(&bs, NULL);
3772 : :
3773 : : /* Get the super blob */
3774 : 15 : spdk_bs_get_super(bs, blob_op_with_id_complete, NULL);
3775 : 15 : poll_threads();
3776 : 15 : CU_ASSERT(g_bserrno == 0);
3777 : 15 : CU_ASSERT(blobid1 == g_blobid);
3778 : :
3779 : 15 : spdk_bs_open_blob(bs, blobid1, blob_op_with_handle_complete, NULL);
3780 : 15 : poll_threads();
3781 : 15 : CU_ASSERT(g_bserrno == 0);
3782 : 15 : CU_ASSERT(g_blob != NULL);
3783 : 15 : blob = g_blob;
3784 : :
3785 : 15 : CU_ASSERT(free_clusters == spdk_bs_free_cluster_count(bs));
3786 : :
3787 : : /* Get the xattrs */
3788 : 15 : value = NULL;
3789 : 15 : rc = spdk_blob_get_xattr_value(blob, "length", &value, &value_len);
3790 : 15 : CU_ASSERT(rc == 0);
3791 [ - + ]: 15 : SPDK_CU_ASSERT_FATAL(value != NULL);
3792 : 15 : CU_ASSERT(*(uint64_t *)value == length);
3793 : 15 : CU_ASSERT(value_len == 8);
3794 : 15 : CU_ASSERT(spdk_blob_get_num_clusters(blob) == 10);
3795 : :
3796 : : /* Resize the blob */
3797 : 15 : spdk_blob_resize(blob, 20, blob_op_complete, NULL);
3798 : 15 : poll_threads();
3799 : 15 : CU_ASSERT(g_bserrno == 0);
3800 : :
3801 : 15 : free_clusters = spdk_bs_free_cluster_count(bs);
3802 : :
3803 : 15 : spdk_blob_close(blob, blob_op_complete, NULL);
3804 : 15 : poll_threads();
3805 : 15 : CU_ASSERT(g_bserrno == 0);
3806 : 15 : blob = NULL;
3807 : 15 : g_blob = NULL;
3808 : 15 : g_blobid = SPDK_BLOBID_INVALID;
3809 : :
3810 : 15 : ut_bs_dirty_load(&bs, NULL);
3811 : :
3812 : 15 : spdk_bs_open_blob(bs, blobid1, blob_op_with_handle_complete, NULL);
3813 : 15 : poll_threads();
3814 : 15 : CU_ASSERT(g_bserrno == 0);
3815 : 15 : CU_ASSERT(g_blob != NULL);
3816 : 15 : blob = g_blob;
3817 : 15 : CU_ASSERT(spdk_blob_get_num_clusters(blob) == 20);
3818 : 15 : CU_ASSERT(free_clusters == spdk_bs_free_cluster_count(bs));
3819 : :
3820 : 15 : spdk_blob_close(blob, blob_op_complete, NULL);
3821 : 15 : poll_threads();
3822 : 15 : CU_ASSERT(g_bserrno == 0);
3823 : 15 : blob = NULL;
3824 : 15 : g_blob = NULL;
3825 : 15 : g_blobid = SPDK_BLOBID_INVALID;
3826 : :
3827 : : /* Create second blob */
3828 : 15 : blob = ut_blob_create_and_open(bs, NULL);
3829 : 15 : blobid2 = spdk_blob_get_id(blob);
3830 : :
3831 : : /* Set some xattrs */
3832 : 15 : rc = spdk_blob_set_xattr(blob, "name", "log1.txt", strlen("log1.txt") + 1);
3833 : 15 : CU_ASSERT(rc == 0);
3834 : :
3835 : 15 : length = 5432;
3836 : 15 : rc = spdk_blob_set_xattr(blob, "length", &length, sizeof(length));
3837 : 15 : CU_ASSERT(rc == 0);
3838 : :
3839 : : /* Resize the blob */
3840 : 15 : spdk_blob_resize(blob, 10, blob_op_complete, NULL);
3841 : 15 : poll_threads();
3842 : 15 : CU_ASSERT(g_bserrno == 0);
3843 : :
3844 : 15 : free_clusters = spdk_bs_free_cluster_count(bs);
3845 : :
3846 : 15 : spdk_blob_close(blob, blob_op_complete, NULL);
3847 : 15 : poll_threads();
3848 : 15 : CU_ASSERT(g_bserrno == 0);
3849 : 15 : blob = NULL;
3850 : 15 : g_blob = NULL;
3851 : 15 : g_blobid = SPDK_BLOBID_INVALID;
3852 : :
3853 : 15 : ut_bs_dirty_load(&bs, NULL);
3854 : :
3855 : 15 : spdk_bs_open_blob(bs, blobid2, blob_op_with_handle_complete, NULL);
3856 : 15 : poll_threads();
3857 : 15 : CU_ASSERT(g_bserrno == 0);
3858 : 15 : CU_ASSERT(g_blob != NULL);
3859 : 15 : blob = g_blob;
3860 : :
3861 : : /* Get the xattrs */
3862 : 15 : value = NULL;
3863 : 15 : rc = spdk_blob_get_xattr_value(blob, "length", &value, &value_len);
3864 : 15 : CU_ASSERT(rc == 0);
3865 [ - + ]: 15 : SPDK_CU_ASSERT_FATAL(value != NULL);
3866 : 15 : CU_ASSERT(*(uint64_t *)value == length);
3867 : 15 : CU_ASSERT(value_len == 8);
3868 : 15 : CU_ASSERT(spdk_blob_get_num_clusters(blob) == 10);
3869 : 15 : CU_ASSERT(free_clusters == spdk_bs_free_cluster_count(bs));
3870 : :
3871 : 15 : ut_blob_close_and_delete(bs, blob);
3872 : :
3873 : 15 : free_clusters = spdk_bs_free_cluster_count(bs);
3874 : :
3875 : 15 : ut_bs_dirty_load(&bs, NULL);
3876 : :
3877 : 15 : spdk_bs_open_blob(bs, blobid2, blob_op_with_handle_complete, NULL);
3878 : 15 : poll_threads();
3879 : 15 : CU_ASSERT(g_bserrno != 0);
3880 : 15 : CU_ASSERT(g_blob == NULL);
3881 : :
3882 : 15 : spdk_bs_open_blob(bs, blobid1, blob_op_with_handle_complete, NULL);
3883 : 15 : poll_threads();
3884 : 15 : CU_ASSERT(g_bserrno == 0);
3885 : 15 : CU_ASSERT(g_blob != NULL);
3886 : 15 : blob = g_blob;
3887 : 15 : CU_ASSERT(free_clusters == spdk_bs_free_cluster_count(bs));
3888 : 15 : spdk_blob_close(blob, blob_op_complete, NULL);
3889 : 15 : poll_threads();
3890 : 15 : CU_ASSERT(g_bserrno == 0);
3891 : :
3892 : 15 : ut_bs_reload(&bs, NULL);
3893 : :
3894 : : /* Create second blob */
3895 : 15 : ut_spdk_blob_opts_init(&blob_opts);
3896 : 15 : spdk_bs_create_blob_ext(bs, &blob_opts, blob_op_with_id_complete, NULL);
3897 : 15 : poll_threads();
3898 : 15 : CU_ASSERT(g_bserrno == 0);
3899 : 15 : CU_ASSERT(g_blobid != SPDK_BLOBID_INVALID);
3900 : 15 : blobid2 = g_blobid;
3901 : :
3902 : : /* Create third blob */
3903 : 15 : spdk_bs_create_blob_ext(bs, &blob_opts, blob_op_with_id_complete, NULL);
3904 : 15 : poll_threads();
3905 : 15 : CU_ASSERT(g_bserrno == 0);
3906 : 15 : CU_ASSERT(g_blobid != SPDK_BLOBID_INVALID);
3907 : 15 : blobid3 = g_blobid;
3908 : :
3909 : 15 : spdk_bs_open_blob(bs, blobid2, blob_op_with_handle_complete, NULL);
3910 : 15 : poll_threads();
3911 : 15 : CU_ASSERT(g_bserrno == 0);
3912 : 15 : CU_ASSERT(g_blob != NULL);
3913 : 15 : blob = g_blob;
3914 : :
3915 : : /* Set some xattrs for second blob */
3916 : 15 : rc = spdk_blob_set_xattr(blob, "name", "log1.txt", strlen("log1.txt") + 1);
3917 : 15 : CU_ASSERT(rc == 0);
3918 : :
3919 : 15 : length = 5432;
3920 : 15 : rc = spdk_blob_set_xattr(blob, "length", &length, sizeof(length));
3921 : 15 : CU_ASSERT(rc == 0);
3922 : :
3923 : 15 : spdk_blob_close(blob, blob_op_complete, NULL);
3924 : 15 : poll_threads();
3925 : 15 : CU_ASSERT(g_bserrno == 0);
3926 : 15 : blob = NULL;
3927 : 15 : g_blob = NULL;
3928 : 15 : g_blobid = SPDK_BLOBID_INVALID;
3929 : :
3930 : 15 : spdk_bs_open_blob(bs, blobid3, blob_op_with_handle_complete, NULL);
3931 : 15 : poll_threads();
3932 : 15 : CU_ASSERT(g_bserrno == 0);
3933 : 15 : CU_ASSERT(g_blob != NULL);
3934 : 15 : blob = g_blob;
3935 : :
3936 : : /* Set some xattrs for third blob */
3937 : 15 : rc = spdk_blob_set_xattr(blob, "name", "log2.txt", strlen("log2.txt") + 1);
3938 : 15 : CU_ASSERT(rc == 0);
3939 : :
3940 : 15 : length = 5432;
3941 : 15 : rc = spdk_blob_set_xattr(blob, "length", &length, sizeof(length));
3942 : 15 : CU_ASSERT(rc == 0);
3943 : :
3944 : 15 : spdk_blob_close(blob, blob_op_complete, NULL);
3945 : 15 : poll_threads();
3946 : 15 : CU_ASSERT(g_bserrno == 0);
3947 : 15 : blob = NULL;
3948 : 15 : g_blob = NULL;
3949 : 15 : g_blobid = SPDK_BLOBID_INVALID;
3950 : :
3951 : : /* Mark second blob as invalid */
3952 : 15 : page_num = bs_blobid_to_page(blobid2);
3953 : :
3954 : 15 : index = g_phys_blocklen * (bs->md_start + page_num);
3955 : 15 : page = (struct spdk_blob_md_page *)&g_dev_buffer[index];
3956 : 15 : page->sequence_num = 1;
3957 : 15 : page->crc = blob_md_page_calc_crc(page);
3958 : :
3959 : 15 : free_clusters = spdk_bs_free_cluster_count(bs);
3960 : :
3961 : 15 : ut_bs_dirty_load(&bs, NULL);
3962 : :
3963 : 15 : spdk_bs_open_blob(bs, blobid2, blob_op_with_handle_complete, NULL);
3964 : 15 : poll_threads();
3965 : 15 : CU_ASSERT(g_bserrno != 0);
3966 : 15 : CU_ASSERT(g_blob == NULL);
3967 : :
3968 : 15 : spdk_bs_open_blob(bs, blobid3, blob_op_with_handle_complete, NULL);
3969 : 15 : poll_threads();
3970 : 15 : CU_ASSERT(g_bserrno == 0);
3971 : 15 : CU_ASSERT(g_blob != NULL);
3972 : 15 : blob = g_blob;
3973 : :
3974 : 15 : CU_ASSERT(free_clusters == spdk_bs_free_cluster_count(bs));
3975 : 15 : }
3976 : :
3977 : : static void
3978 : 15 : blob_flags(void)
3979 : : {
3980 : 15 : struct spdk_blob_store *bs = g_bs;
3981 : : spdk_blob_id blobid_invalid, blobid_data_ro, blobid_md_ro;
3982 : : struct spdk_blob *blob_invalid, *blob_data_ro, *blob_md_ro;
3983 : 15 : struct spdk_blob_opts blob_opts;
3984 : : int rc;
3985 : :
3986 : : /* Create three blobs - one each for testing invalid, data_ro and md_ro flags. */
3987 : 15 : blob_invalid = ut_blob_create_and_open(bs, NULL);
3988 : 15 : blobid_invalid = spdk_blob_get_id(blob_invalid);
3989 : :
3990 : 15 : blob_data_ro = ut_blob_create_and_open(bs, NULL);
3991 : 15 : blobid_data_ro = spdk_blob_get_id(blob_data_ro);
3992 : :
3993 : 15 : ut_spdk_blob_opts_init(&blob_opts);
3994 : 15 : blob_opts.clear_method = BLOB_CLEAR_WITH_WRITE_ZEROES;
3995 : 15 : blob_md_ro = ut_blob_create_and_open(bs, &blob_opts);
3996 : 15 : blobid_md_ro = spdk_blob_get_id(blob_md_ro);
3997 : 15 : CU_ASSERT((blob_md_ro->md_ro_flags & SPDK_BLOB_MD_RO_FLAGS_MASK) == BLOB_CLEAR_WITH_WRITE_ZEROES);
3998 : :
3999 : : /* Change the size of blob_data_ro to check if flags are serialized
4000 : : * when blob has non zero number of extents */
4001 : 15 : spdk_blob_resize(blob_data_ro, 10, blob_op_complete, NULL);
4002 : 15 : poll_threads();
4003 : 15 : CU_ASSERT(g_bserrno == 0);
4004 : :
4005 : : /* Set the xattr to check if flags are serialized
4006 : : * when blob has non zero number of xattrs */
4007 : 15 : rc = spdk_blob_set_xattr(blob_md_ro, "name", "log.txt", strlen("log.txt") + 1);
4008 : 15 : CU_ASSERT(rc == 0);
4009 : :
4010 : 15 : blob_invalid->invalid_flags = (1ULL << 63);
4011 : 15 : blob_invalid->state = SPDK_BLOB_STATE_DIRTY;
4012 : 15 : blob_data_ro->data_ro_flags = (1ULL << 62);
4013 : 15 : blob_data_ro->state = SPDK_BLOB_STATE_DIRTY;
4014 : 15 : blob_md_ro->md_ro_flags = (1ULL << 61);
4015 : 15 : blob_md_ro->state = SPDK_BLOB_STATE_DIRTY;
4016 : :
4017 : 15 : g_bserrno = -1;
4018 : 15 : spdk_blob_sync_md(blob_invalid, blob_op_complete, NULL);
4019 : 15 : poll_threads();
4020 : 15 : CU_ASSERT(g_bserrno == 0);
4021 : 15 : g_bserrno = -1;
4022 : 15 : spdk_blob_sync_md(blob_data_ro, blob_op_complete, NULL);
4023 : 15 : poll_threads();
4024 : 15 : CU_ASSERT(g_bserrno == 0);
4025 : 15 : g_bserrno = -1;
4026 : 15 : spdk_blob_sync_md(blob_md_ro, blob_op_complete, NULL);
4027 : 15 : poll_threads();
4028 : 15 : CU_ASSERT(g_bserrno == 0);
4029 : :
4030 : 15 : g_bserrno = -1;
4031 : 15 : spdk_blob_close(blob_invalid, blob_op_complete, NULL);
4032 : 15 : poll_threads();
4033 : 15 : CU_ASSERT(g_bserrno == 0);
4034 : 15 : blob_invalid = NULL;
4035 : 15 : g_bserrno = -1;
4036 : 15 : spdk_blob_close(blob_data_ro, blob_op_complete, NULL);
4037 : 15 : poll_threads();
4038 : 15 : CU_ASSERT(g_bserrno == 0);
4039 : 15 : blob_data_ro = NULL;
4040 : 15 : g_bserrno = -1;
4041 : 15 : spdk_blob_close(blob_md_ro, blob_op_complete, NULL);
4042 : 15 : poll_threads();
4043 : 15 : CU_ASSERT(g_bserrno == 0);
4044 : 15 : blob_md_ro = NULL;
4045 : :
4046 : 15 : g_blob = NULL;
4047 : 15 : g_blobid = SPDK_BLOBID_INVALID;
4048 : :
4049 : 15 : ut_bs_reload(&bs, NULL);
4050 : :
4051 : 15 : g_blob = NULL;
4052 : 15 : g_bserrno = 0;
4053 : 15 : spdk_bs_open_blob(bs, blobid_invalid, blob_op_with_handle_complete, NULL);
4054 : 15 : poll_threads();
4055 : 15 : CU_ASSERT(g_bserrno != 0);
4056 : 15 : CU_ASSERT(g_blob == NULL);
4057 : :
4058 : 15 : g_blob = NULL;
4059 : 15 : g_bserrno = -1;
4060 : 15 : spdk_bs_open_blob(bs, blobid_data_ro, blob_op_with_handle_complete, NULL);
4061 : 15 : poll_threads();
4062 : 15 : CU_ASSERT(g_bserrno == 0);
4063 [ - + ]: 15 : SPDK_CU_ASSERT_FATAL(g_blob != NULL);
4064 : 15 : blob_data_ro = g_blob;
4065 : : /* If an unknown data_ro flag was found, the blob should be marked both data and md read-only. */
4066 [ - + ]: 15 : CU_ASSERT(blob_data_ro->data_ro == true);
4067 [ - + ]: 15 : CU_ASSERT(blob_data_ro->md_ro == true);
4068 : 15 : CU_ASSERT(spdk_blob_get_num_clusters(blob_data_ro) == 10);
4069 : :
4070 : 15 : g_blob = NULL;
4071 : 15 : g_bserrno = -1;
4072 : 15 : spdk_bs_open_blob(bs, blobid_md_ro, blob_op_with_handle_complete, NULL);
4073 : 15 : poll_threads();
4074 : 15 : CU_ASSERT(g_bserrno == 0);
4075 [ - + ]: 15 : SPDK_CU_ASSERT_FATAL(g_blob != NULL);
4076 : 15 : blob_md_ro = g_blob;
4077 [ - + ]: 15 : CU_ASSERT(blob_md_ro->data_ro == false);
4078 [ - + ]: 15 : CU_ASSERT(blob_md_ro->md_ro == true);
4079 : :
4080 : 15 : g_bserrno = -1;
4081 : 15 : spdk_blob_sync_md(blob_md_ro, blob_op_complete, NULL);
4082 : 15 : poll_threads();
4083 : 15 : CU_ASSERT(g_bserrno == 0);
4084 : :
4085 : 15 : ut_blob_close_and_delete(bs, blob_data_ro);
4086 : 15 : ut_blob_close_and_delete(bs, blob_md_ro);
4087 : 15 : }
4088 : :
4089 : : static void
4090 : 15 : bs_version(void)
4091 : : {
4092 : : struct spdk_bs_super_block *super;
4093 : 15 : struct spdk_blob_store *bs = g_bs;
4094 : : struct spdk_bs_dev *dev;
4095 : : struct spdk_blob *blob;
4096 : 15 : struct spdk_blob_opts blob_opts;
4097 : : spdk_blob_id blobid;
4098 : :
4099 : : /* Unload the blob store */
4100 : 15 : spdk_bs_unload(bs, bs_op_complete, NULL);
4101 : 15 : poll_threads();
4102 : 15 : CU_ASSERT(g_bserrno == 0);
4103 : 15 : g_bs = NULL;
4104 : :
4105 : : /*
4106 : : * Change the bs version on disk. This will allow us to
4107 : : * test that the version does not get modified automatically
4108 : : * when loading and unloading the blobstore.
4109 : : */
4110 : 15 : super = (struct spdk_bs_super_block *)&g_dev_buffer[0];
4111 : 15 : CU_ASSERT(super->version == SPDK_BS_VERSION);
4112 : 15 : CU_ASSERT(super->clean == 1);
4113 : 15 : super->version = 2;
4114 : : /*
4115 : : * Version 2 metadata does not have a used blobid mask, so clear
4116 : : * those fields in the super block and zero the corresponding
4117 : : * region on "disk". We will use this to ensure blob IDs are
4118 : : * correctly reconstructed.
4119 : : */
4120 [ - + ]: 15 : memset(&g_dev_buffer[super->used_blobid_mask_start * SPDK_BS_PAGE_SIZE], 0,
4121 : 15 : super->used_blobid_mask_len * SPDK_BS_PAGE_SIZE);
4122 : 15 : super->used_blobid_mask_start = 0;
4123 : 15 : super->used_blobid_mask_len = 0;
4124 : 15 : super->crc = blob_md_page_calc_crc(super);
4125 : :
4126 : : /* Load an existing blob store */
4127 : 15 : dev = init_dev();
4128 : 15 : spdk_bs_load(dev, NULL, bs_op_with_handle_complete, NULL);
4129 : 15 : poll_threads();
4130 : 15 : CU_ASSERT(g_bserrno == 0);
4131 [ - + ]: 15 : SPDK_CU_ASSERT_FATAL(g_bs != NULL);
4132 : 15 : CU_ASSERT(super->clean == 1);
4133 : 15 : bs = g_bs;
4134 : :
4135 : : /*
4136 : : * Create a blob - just to make sure that when we unload it
4137 : : * results in writing the super block (since metadata pages
4138 : : * were allocated.
4139 : : */
4140 : 15 : ut_spdk_blob_opts_init(&blob_opts);
4141 : 15 : spdk_bs_create_blob_ext(bs, &blob_opts, blob_op_with_id_complete, NULL);
4142 : 15 : poll_threads();
4143 : 15 : CU_ASSERT(g_bserrno == 0);
4144 : 15 : CU_ASSERT(g_blobid != SPDK_BLOBID_INVALID);
4145 : 15 : blobid = g_blobid;
4146 : :
4147 : : /* Unload the blob store */
4148 : 15 : spdk_bs_unload(bs, bs_op_complete, NULL);
4149 : 15 : poll_threads();
4150 : 15 : CU_ASSERT(g_bserrno == 0);
4151 : 15 : g_bs = NULL;
4152 : 15 : CU_ASSERT(super->version == 2);
4153 : 15 : CU_ASSERT(super->used_blobid_mask_start == 0);
4154 : 15 : CU_ASSERT(super->used_blobid_mask_len == 0);
4155 : :
4156 : 15 : dev = init_dev();
4157 : 15 : spdk_bs_load(dev, NULL, bs_op_with_handle_complete, NULL);
4158 : 15 : poll_threads();
4159 : 15 : CU_ASSERT(g_bserrno == 0);
4160 [ - + ]: 15 : SPDK_CU_ASSERT_FATAL(g_bs != NULL);
4161 : 15 : bs = g_bs;
4162 : :
4163 : 15 : g_blob = NULL;
4164 : 15 : spdk_bs_open_blob(bs, blobid, blob_op_with_handle_complete, NULL);
4165 : 15 : poll_threads();
4166 : 15 : CU_ASSERT(g_bserrno == 0);
4167 : 15 : CU_ASSERT(g_blob != NULL);
4168 : 15 : blob = g_blob;
4169 : :
4170 : 15 : ut_blob_close_and_delete(bs, blob);
4171 : :
4172 : 15 : CU_ASSERT(super->version == 2);
4173 : 15 : CU_ASSERT(super->used_blobid_mask_start == 0);
4174 : 15 : CU_ASSERT(super->used_blobid_mask_len == 0);
4175 : 15 : }
4176 : :
4177 : : static void
4178 : 15 : blob_set_xattrs_test(void)
4179 : : {
4180 : 15 : struct spdk_blob_store *bs = g_bs;
4181 : : struct spdk_blob *blob;
4182 : 15 : struct spdk_blob_opts opts;
4183 : 15 : const void *value;
4184 : 15 : size_t value_len;
4185 : : char *xattr;
4186 : : size_t xattr_length;
4187 : : int rc;
4188 : :
4189 : : /* Create blob with extra attributes */
4190 : 15 : ut_spdk_blob_opts_init(&opts);
4191 : :
4192 : 15 : opts.xattrs.names = g_xattr_names;
4193 : 15 : opts.xattrs.get_value = _get_xattr_value;
4194 : 15 : opts.xattrs.count = 3;
4195 : 15 : opts.xattrs.ctx = &g_ctx;
4196 : :
4197 : 15 : blob = ut_blob_create_and_open(bs, &opts);
4198 : :
4199 : : /* Get the xattrs */
4200 : 15 : value = NULL;
4201 : :
4202 : 15 : rc = spdk_blob_get_xattr_value(blob, g_xattr_names[0], &value, &value_len);
4203 : 15 : CU_ASSERT(rc == 0);
4204 [ - + ]: 15 : SPDK_CU_ASSERT_FATAL(value != NULL);
4205 [ - + ]: 15 : CU_ASSERT(value_len == strlen(g_xattr_values[0]));
4206 [ - + - + ]: 15 : CU_ASSERT_NSTRING_EQUAL_FATAL(value, g_xattr_values[0], value_len);
4207 : :
4208 : 15 : rc = spdk_blob_get_xattr_value(blob, g_xattr_names[1], &value, &value_len);
4209 : 15 : CU_ASSERT(rc == 0);
4210 [ - + ]: 15 : SPDK_CU_ASSERT_FATAL(value != NULL);
4211 [ - + ]: 15 : CU_ASSERT(value_len == strlen(g_xattr_values[1]));
4212 [ - + - + ]: 15 : CU_ASSERT_NSTRING_EQUAL((char *)value, g_xattr_values[1], value_len);
4213 : :
4214 : 15 : rc = spdk_blob_get_xattr_value(blob, g_xattr_names[2], &value, &value_len);
4215 : 15 : CU_ASSERT(rc == 0);
4216 [ - + ]: 15 : SPDK_CU_ASSERT_FATAL(value != NULL);
4217 [ - + ]: 15 : CU_ASSERT(value_len == strlen(g_xattr_values[2]));
4218 [ - + - + ]: 15 : CU_ASSERT_NSTRING_EQUAL((char *)value, g_xattr_values[2], value_len);
4219 : :
4220 : : /* Try to get non existing attribute */
4221 : :
4222 : 15 : rc = spdk_blob_get_xattr_value(blob, "foobar", &value, &value_len);
4223 : 15 : CU_ASSERT(rc == -ENOENT);
4224 : :
4225 : : /* Try xattr exceeding maximum length of descriptor in single page */
4226 : 15 : xattr_length = SPDK_BS_MAX_DESC_SIZE - sizeof(struct spdk_blob_md_descriptor_xattr) -
4227 : : strlen("large_xattr") + 1;
4228 : 15 : xattr = calloc(xattr_length, sizeof(char));
4229 [ - + ]: 15 : SPDK_CU_ASSERT_FATAL(xattr != NULL);
4230 : 15 : rc = spdk_blob_set_xattr(blob, "large_xattr", xattr, xattr_length);
4231 : 15 : free(xattr);
4232 [ - + ]: 15 : SPDK_CU_ASSERT_FATAL(rc == -ENOMEM);
4233 : :
4234 : 15 : spdk_blob_close(blob, blob_op_complete, NULL);
4235 : 15 : poll_threads();
4236 : 15 : CU_ASSERT(g_bserrno == 0);
4237 : 15 : blob = NULL;
4238 : 15 : g_blob = NULL;
4239 : 15 : g_blobid = SPDK_BLOBID_INVALID;
4240 : :
4241 : : /* NULL callback */
4242 : 15 : ut_spdk_blob_opts_init(&opts);
4243 : 15 : opts.xattrs.names = g_xattr_names;
4244 : 15 : opts.xattrs.get_value = NULL;
4245 : 15 : opts.xattrs.count = 1;
4246 : 15 : opts.xattrs.ctx = &g_ctx;
4247 : :
4248 : 15 : spdk_bs_create_blob_ext(bs, &opts, blob_op_with_id_complete, NULL);
4249 : 15 : poll_threads();
4250 : 15 : CU_ASSERT(g_bserrno == -EINVAL);
4251 : 15 : CU_ASSERT(g_blobid != SPDK_BLOBID_INVALID);
4252 : :
4253 : : /* NULL values */
4254 : 15 : ut_spdk_blob_opts_init(&opts);
4255 : 15 : opts.xattrs.names = g_xattr_names;
4256 : 15 : opts.xattrs.get_value = _get_xattr_value_null;
4257 : 15 : opts.xattrs.count = 1;
4258 : 15 : opts.xattrs.ctx = NULL;
4259 : :
4260 : 15 : spdk_bs_create_blob_ext(bs, &opts, blob_op_with_id_complete, NULL);
4261 : 15 : poll_threads();
4262 : 15 : CU_ASSERT(g_bserrno == -EINVAL);
4263 : 15 : }
4264 : :
4265 : : static void
4266 : 15 : blob_thin_prov_alloc(void)
4267 : : {
4268 : 15 : struct spdk_blob_store *bs = g_bs;
4269 : : struct spdk_blob *blob;
4270 : 15 : struct spdk_blob_opts opts;
4271 : : spdk_blob_id blobid;
4272 : : uint64_t free_clusters;
4273 : :
4274 : 15 : free_clusters = spdk_bs_free_cluster_count(bs);
4275 : :
4276 : : /* Set blob as thin provisioned */
4277 : 15 : ut_spdk_blob_opts_init(&opts);
4278 : 15 : opts.thin_provision = true;
4279 : :
4280 : 15 : blob = ut_blob_create_and_open(bs, &opts);
4281 : 15 : blobid = spdk_blob_get_id(blob);
4282 : 15 : CU_ASSERT(free_clusters == spdk_bs_free_cluster_count(bs));
4283 : :
4284 : 15 : CU_ASSERT(blob->active.num_clusters == 0);
4285 : 15 : CU_ASSERT(spdk_blob_get_num_clusters(blob) == 0);
4286 : 15 : CU_ASSERT(spdk_blob_get_num_allocated_clusters(blob) == 0);
4287 : :
4288 : : /* The blob started at 0 clusters. Resize it to be 5, but still unallocated. */
4289 : 15 : spdk_blob_resize(blob, 5, blob_op_complete, NULL);
4290 : 15 : poll_threads();
4291 : 15 : CU_ASSERT(g_bserrno == 0);
4292 : 15 : CU_ASSERT(free_clusters == spdk_bs_free_cluster_count(bs));
4293 : 15 : CU_ASSERT(blob->active.num_clusters == 5);
4294 : 15 : CU_ASSERT(spdk_blob_get_num_clusters(blob) == 5);
4295 : 15 : CU_ASSERT(spdk_blob_get_num_allocated_clusters(blob) == 0);
4296 : :
4297 : : /* Grow it to 1TB - still unallocated */
4298 : 15 : spdk_blob_resize(blob, 262144, blob_op_complete, NULL);
4299 : 15 : poll_threads();
4300 : 15 : CU_ASSERT(g_bserrno == 0);
4301 : 15 : CU_ASSERT(free_clusters == spdk_bs_free_cluster_count(bs));
4302 : 15 : CU_ASSERT(blob->active.num_clusters == 262144);
4303 : 15 : CU_ASSERT(spdk_blob_get_num_clusters(blob) == 262144);
4304 : 15 : CU_ASSERT(spdk_blob_get_num_allocated_clusters(blob) == 0);
4305 : :
4306 : 15 : spdk_blob_sync_md(blob, blob_op_complete, NULL);
4307 : 15 : poll_threads();
4308 : 15 : CU_ASSERT(g_bserrno == 0);
4309 : : /* Sync must not change anything */
4310 : 15 : CU_ASSERT(free_clusters == spdk_bs_free_cluster_count(bs));
4311 : 15 : CU_ASSERT(blob->active.num_clusters == 262144);
4312 : 15 : CU_ASSERT(spdk_blob_get_num_clusters(blob) == 262144);
4313 : 15 : CU_ASSERT(spdk_blob_get_num_allocated_clusters(blob) == 0);
4314 : : /* Since clusters are not allocated,
4315 : : * number of metadata pages is expected to be minimal.
4316 : : */
4317 : 15 : CU_ASSERT(blob->active.num_pages == 1);
4318 : :
4319 : : /* Shrink the blob to 3 clusters - still unallocated */
4320 : 15 : spdk_blob_resize(blob, 3, blob_op_complete, NULL);
4321 : 15 : poll_threads();
4322 : 15 : CU_ASSERT(g_bserrno == 0);
4323 : 15 : CU_ASSERT(free_clusters == spdk_bs_free_cluster_count(bs));
4324 : 15 : CU_ASSERT(blob->active.num_clusters == 3);
4325 : 15 : CU_ASSERT(spdk_blob_get_num_clusters(blob) == 3);
4326 : 15 : CU_ASSERT(spdk_blob_get_num_allocated_clusters(blob) == 0);
4327 : :
4328 : 15 : spdk_blob_sync_md(blob, blob_op_complete, NULL);
4329 : 15 : poll_threads();
4330 : 15 : CU_ASSERT(g_bserrno == 0);
4331 : : /* Sync must not change anything */
4332 : 15 : CU_ASSERT(free_clusters == spdk_bs_free_cluster_count(bs));
4333 : 15 : CU_ASSERT(blob->active.num_clusters == 3);
4334 : 15 : CU_ASSERT(spdk_blob_get_num_clusters(blob) == 3);
4335 : 15 : CU_ASSERT(spdk_blob_get_num_allocated_clusters(blob) == 0);
4336 : :
4337 : 15 : spdk_blob_close(blob, blob_op_complete, NULL);
4338 : 15 : poll_threads();
4339 : 15 : CU_ASSERT(g_bserrno == 0);
4340 : :
4341 : 15 : ut_bs_reload(&bs, NULL);
4342 : :
4343 : 15 : spdk_bs_open_blob(bs, blobid, blob_op_with_handle_complete, NULL);
4344 : 15 : poll_threads();
4345 : 15 : CU_ASSERT(g_bserrno == 0);
4346 [ - + ]: 15 : SPDK_CU_ASSERT_FATAL(g_blob != NULL);
4347 : 15 : blob = g_blob;
4348 : :
4349 : : /* Check that clusters allocation and size is still the same */
4350 : 15 : CU_ASSERT(free_clusters == spdk_bs_free_cluster_count(bs));
4351 : 15 : CU_ASSERT(blob->active.num_clusters == 3);
4352 : :
4353 : 15 : ut_blob_close_and_delete(bs, blob);
4354 : 15 : }
4355 : :
4356 : : static void
4357 : 15 : blob_insert_cluster_msg_test(void)
4358 : : {
4359 : 15 : struct spdk_blob_store *bs = g_bs;
4360 : : struct spdk_blob *blob;
4361 : 15 : struct spdk_blob_opts opts;
4362 : : /* For now, even if md_page_size is > 4KB, we still only use the first
4363 : : * 4KB of it. The rest is left unused. Future changes may allow using the
4364 : : * rest of the md_page, but that will require more extensive changes since
4365 : : * then the struct spdk_blob_md_page cannot be used directly (since some
4366 : : * fields such as crc would have variable placement in the struct).
4367 : : */
4368 : : struct {
4369 : : struct spdk_blob_md_page page;
4370 : : uint8_t pad[DEV_MAX_PHYS_BLOCKLEN - sizeof(struct spdk_blob_md_page)];
4371 : 15 : } md = {};
4372 : : spdk_blob_id blobid;
4373 : : uint64_t free_clusters;
4374 : 15 : uint64_t new_cluster = 0;
4375 : 15 : uint32_t cluster_num = 3;
4376 : 15 : uint32_t extent_page = 0;
4377 : :
4378 : 15 : free_clusters = spdk_bs_free_cluster_count(bs);
4379 : :
4380 : : /* Set blob as thin provisioned */
4381 : 15 : ut_spdk_blob_opts_init(&opts);
4382 : 15 : opts.thin_provision = true;
4383 : 15 : opts.num_clusters = 4;
4384 : :
4385 : 15 : blob = ut_blob_create_and_open(bs, &opts);
4386 : 15 : blobid = spdk_blob_get_id(blob);
4387 : 15 : CU_ASSERT(free_clusters == spdk_bs_free_cluster_count(bs));
4388 : :
4389 : 15 : CU_ASSERT(blob->active.num_clusters == 4);
4390 : 15 : CU_ASSERT(spdk_blob_get_num_clusters(blob) == 4);
4391 : 15 : CU_ASSERT(blob->active.clusters[cluster_num] == 0);
4392 : :
4393 : : /* Specify cluster_num to allocate and new_cluster will be returned to insert on md_thread.
4394 : : * This is to simulate behaviour when cluster is allocated after blob creation.
4395 : : * Such as _spdk_bs_allocate_and_copy_cluster(). */
4396 : 15 : spdk_spin_lock(&bs->used_lock);
4397 : 15 : bs_allocate_cluster(blob, cluster_num, &new_cluster, &extent_page, false);
4398 : 15 : CU_ASSERT(blob->active.clusters[cluster_num] == 0);
4399 : 15 : spdk_spin_unlock(&bs->used_lock);
4400 : :
4401 : 15 : blob_insert_cluster_on_md_thread(blob, cluster_num, new_cluster, extent_page, &md.page,
4402 : : blob_op_complete, NULL);
4403 : 15 : poll_threads();
4404 : :
4405 : 15 : CU_ASSERT(blob->active.clusters[cluster_num] != 0);
4406 : :
4407 : 15 : spdk_blob_close(blob, blob_op_complete, NULL);
4408 : 15 : poll_threads();
4409 : 15 : CU_ASSERT(g_bserrno == 0);
4410 : :
4411 : 15 : ut_bs_reload(&bs, NULL);
4412 : :
4413 : 15 : spdk_bs_open_blob(bs, blobid, blob_op_with_handle_complete, NULL);
4414 : 15 : poll_threads();
4415 : 15 : CU_ASSERT(g_bserrno == 0);
4416 [ - + ]: 15 : SPDK_CU_ASSERT_FATAL(g_blob != NULL);
4417 : 15 : blob = g_blob;
4418 : :
4419 : 15 : CU_ASSERT(blob->active.clusters[cluster_num] != 0);
4420 : :
4421 : 15 : ut_blob_close_and_delete(bs, blob);
4422 : 15 : }
4423 : :
4424 : : static void
4425 : 15 : blob_thin_prov_rw(void)
4426 : : {
4427 : : static const uint8_t zero[10 * BLOCKLEN] = { 0 };
4428 : 15 : struct spdk_blob_store *bs = g_bs;
4429 : : struct spdk_blob *blob, *blob_id0;
4430 : : struct spdk_io_channel *channel, *channel_thread1;
4431 : 15 : struct spdk_blob_opts opts;
4432 : : uint64_t free_clusters;
4433 : : uint64_t io_unit_size;
4434 : 15 : uint8_t payload_read[10 * BLOCKLEN];
4435 : 15 : uint8_t payload_write[10 * BLOCKLEN];
4436 : : uint64_t write_bytes;
4437 : : uint64_t read_bytes;
4438 : : uint64_t expected_bytes;
4439 : :
4440 : 15 : free_clusters = spdk_bs_free_cluster_count(bs);
4441 : 15 : io_unit_size = spdk_bs_get_io_unit_size(bs);
4442 : :
4443 : 15 : channel = spdk_bs_alloc_io_channel(bs);
4444 : 15 : CU_ASSERT(channel != NULL);
4445 : :
4446 : 15 : ut_spdk_blob_opts_init(&opts);
4447 : 15 : opts.thin_provision = true;
4448 : :
4449 : : /* Create and delete blob at md page 0, so that next md page allocation
4450 : : * for extent will use that. */
4451 : 15 : blob_id0 = ut_blob_create_and_open(bs, &opts);
4452 : 15 : blob = ut_blob_create_and_open(bs, &opts);
4453 : 15 : ut_blob_close_and_delete(bs, blob_id0);
4454 : 15 : CU_ASSERT(free_clusters == spdk_bs_free_cluster_count(bs));
4455 : :
4456 : 15 : CU_ASSERT(blob->active.num_clusters == 0);
4457 : 15 : CU_ASSERT(spdk_blob_get_num_allocated_clusters(blob) == 0);
4458 : :
4459 : : /* The blob started at 0 clusters. Resize it to be 5, but still unallocated. */
4460 : 15 : spdk_blob_resize(blob, 5, blob_op_complete, NULL);
4461 : 15 : poll_threads();
4462 : 15 : CU_ASSERT(g_bserrno == 0);
4463 : 15 : CU_ASSERT(free_clusters == spdk_bs_free_cluster_count(bs));
4464 : 15 : CU_ASSERT(blob->active.num_clusters == 5);
4465 : 15 : CU_ASSERT(spdk_blob_get_num_allocated_clusters(blob) == 0);
4466 : :
4467 : 15 : spdk_blob_sync_md(blob, blob_op_complete, NULL);
4468 : 15 : poll_threads();
4469 : 15 : CU_ASSERT(g_bserrno == 0);
4470 : : /* Sync must not change anything */
4471 : 15 : CU_ASSERT(free_clusters == spdk_bs_free_cluster_count(bs));
4472 : 15 : CU_ASSERT(blob->active.num_clusters == 5);
4473 : 15 : CU_ASSERT(spdk_blob_get_num_allocated_clusters(blob) == 0);
4474 : :
4475 : : /* Payload should be all zeros from unallocated clusters */
4476 : 15 : memset(payload_read, 0xFF, sizeof(payload_read));
4477 : 15 : spdk_blob_io_read(blob, channel, payload_read, 4, 10, blob_op_complete, NULL);
4478 : 15 : poll_threads();
4479 : 15 : CU_ASSERT(g_bserrno == 0);
4480 : 15 : CU_ASSERT(memcmp(zero, payload_read, 10 * BLOCKLEN) == 0);
4481 : :
4482 : 15 : write_bytes = g_dev_write_bytes;
4483 : 15 : read_bytes = g_dev_read_bytes;
4484 : :
4485 : : /* Perform write on thread 1. That will allocate cluster on thread 0 via send_msg */
4486 : 15 : set_thread(1);
4487 : 15 : channel_thread1 = spdk_bs_alloc_io_channel(bs);
4488 : 15 : CU_ASSERT(channel_thread1 != NULL);
4489 : 15 : memset(payload_write, 0xE5, sizeof(payload_write));
4490 : 15 : spdk_blob_io_write(blob, channel_thread1, payload_write, 4, 10, blob_op_complete, NULL);
4491 : 15 : CU_ASSERT(free_clusters - 1 == spdk_bs_free_cluster_count(bs));
4492 : : /* Perform write on thread 0. That will try to allocate cluster,
4493 : : * but fail due to another thread issuing the cluster allocation first. */
4494 : 15 : set_thread(0);
4495 : 15 : memset(payload_write, 0xE5, sizeof(payload_write));
4496 : 15 : spdk_blob_io_write(blob, channel, payload_write, 4, 10, blob_op_complete, NULL);
4497 : 15 : CU_ASSERT(free_clusters - 2 == spdk_bs_free_cluster_count(bs));
4498 : 15 : poll_threads();
4499 : 15 : CU_ASSERT(g_bserrno == 0);
4500 : 15 : CU_ASSERT(free_clusters - 1 == spdk_bs_free_cluster_count(bs));
4501 : 15 : CU_ASSERT(spdk_blob_get_num_allocated_clusters(blob) == 1);
4502 : : /* For thin-provisioned blob we need to write 20 io_units plus one page metadata and
4503 : : * read 0 bytes */
4504 : 15 : expected_bytes = 20 * io_unit_size + spdk_bs_get_page_size(bs);
4505 [ + + + + ]: 15 : if (g_use_extent_table) {
4506 : : /* Add one more page for EXTENT_PAGE write */
4507 : 9 : expected_bytes += spdk_bs_get_page_size(bs);
4508 : : }
4509 : 15 : CU_ASSERT(g_dev_write_bytes - write_bytes == expected_bytes);
4510 : 15 : CU_ASSERT(g_dev_read_bytes - read_bytes == 0);
4511 : :
4512 : 15 : spdk_blob_io_read(blob, channel, payload_read, 4, 10, blob_op_complete, NULL);
4513 : 15 : poll_threads();
4514 : 15 : CU_ASSERT(g_bserrno == 0);
4515 : 15 : CU_ASSERT(memcmp(payload_write, payload_read, 10 * BLOCKLEN) == 0);
4516 : :
4517 : 15 : ut_blob_close_and_delete(bs, blob);
4518 : 15 : CU_ASSERT(free_clusters == spdk_bs_free_cluster_count(bs));
4519 : :
4520 : 15 : set_thread(1);
4521 : 15 : spdk_bs_free_io_channel(channel_thread1);
4522 : 15 : set_thread(0);
4523 : 15 : spdk_bs_free_io_channel(channel);
4524 : 15 : poll_threads();
4525 : 15 : g_blob = NULL;
4526 : 15 : g_blobid = 0;
4527 : 15 : }
4528 : :
4529 : : static void
4530 : 15 : blob_thin_prov_write_count_io(void)
4531 : : {
4532 : : struct spdk_blob_store *bs;
4533 : : struct spdk_blob *blob;
4534 : : struct spdk_io_channel *ch;
4535 : : struct spdk_bs_dev *dev;
4536 : 15 : struct spdk_bs_opts bs_opts;
4537 : 15 : struct spdk_blob_opts opts;
4538 : : uint64_t free_clusters;
4539 : : uint64_t io_unit_size;
4540 : 15 : uint8_t payload_write[BLOCKLEN];
4541 : : uint64_t write_bytes;
4542 : : uint64_t read_bytes;
4543 : : uint64_t expected_bytes;
4544 : 15 : const uint32_t CLUSTER_SZ = g_phys_blocklen * 4;
4545 : : uint32_t io_units_per_cluster;
4546 : : uint32_t io_units_per_extent_page;
4547 : : uint32_t i;
4548 : :
4549 : : /* Use a very small cluster size for this test. This ensures we need multiple
4550 : : * extent pages to hold all of the clusters even for relatively small blobs like
4551 : : * we are restricted to for the unit tests (i.e. we don't want to allocate multi-GB
4552 : : * buffers).
4553 : : */
4554 : 15 : dev = init_dev();
4555 : 15 : spdk_bs_opts_init(&bs_opts, sizeof(bs_opts));
4556 : 15 : bs_opts.cluster_sz = CLUSTER_SZ;
4557 : :
4558 : 15 : spdk_bs_init(dev, &bs_opts, bs_op_with_handle_complete, NULL);
4559 : 15 : poll_threads();
4560 : 15 : CU_ASSERT(g_bserrno == 0);
4561 [ - + ]: 15 : SPDK_CU_ASSERT_FATAL(g_bs != NULL);
4562 : 15 : bs = g_bs;
4563 : :
4564 : 15 : free_clusters = spdk_bs_free_cluster_count(bs);
4565 : 15 : io_unit_size = spdk_bs_get_io_unit_size(bs);
4566 [ - + ]: 15 : io_units_per_cluster = CLUSTER_SZ / io_unit_size;
4567 : 15 : io_units_per_extent_page = SPDK_EXTENTS_PER_EP * io_units_per_cluster;
4568 : :
4569 : 15 : ch = spdk_bs_alloc_io_channel(bs);
4570 [ - + ]: 15 : SPDK_CU_ASSERT_FATAL(ch != NULL);
4571 : :
4572 : 15 : ut_spdk_blob_opts_init(&opts);
4573 : 15 : opts.thin_provision = true;
4574 : :
4575 : 15 : blob = ut_blob_create_and_open(bs, &opts);
4576 : 15 : CU_ASSERT(free_clusters == spdk_bs_free_cluster_count(bs));
4577 : :
4578 : : /* Resize the blob so that it will require 8 extent pages to hold all of
4579 : : * the clusters.
4580 : : */
4581 : 15 : g_bserrno = -1;
4582 : 15 : spdk_blob_resize(blob, SPDK_EXTENTS_PER_EP * 8, blob_op_complete, NULL);
4583 : 15 : poll_threads();
4584 : 15 : CU_ASSERT(g_bserrno == 0);
4585 : :
4586 : 15 : g_bserrno = -1;
4587 : 15 : spdk_blob_sync_md(blob, blob_op_complete, NULL);
4588 : 15 : poll_threads();
4589 : 15 : CU_ASSERT(g_bserrno == 0);
4590 : 15 : CU_ASSERT(free_clusters == spdk_bs_free_cluster_count(bs));
4591 : 15 : CU_ASSERT(blob->active.num_clusters == SPDK_EXTENTS_PER_EP * 8);
4592 : :
4593 [ - + ]: 15 : memset(payload_write, 0, sizeof(payload_write));
4594 [ + + ]: 135 : for (i = 0; i < 8; i++) {
4595 : 120 : write_bytes = g_dev_write_bytes;
4596 : 120 : read_bytes = g_dev_read_bytes;
4597 : :
4598 : 120 : g_bserrno = -1;
4599 : 120 : spdk_blob_io_write(blob, ch, payload_write, io_units_per_extent_page * i, 1, blob_op_complete,
4600 : : NULL);
4601 : 120 : poll_threads();
4602 : 120 : CU_ASSERT(g_bserrno == 0);
4603 : 120 : CU_ASSERT(free_clusters - (2 * i + 1) == spdk_bs_free_cluster_count(bs));
4604 : :
4605 : 120 : CU_ASSERT(g_dev_read_bytes == read_bytes);
4606 [ + + + + ]: 120 : if (!g_use_extent_table) {
4607 : : /* For legacy metadata, we should have written the io_unit for
4608 : : * the write I/O, plus the blob's primary metadata page
4609 : : */
4610 : 48 : expected_bytes = io_unit_size + spdk_bs_get_page_size(bs);
4611 : : } else {
4612 : : /* For extent table metadata, we should have written the io_unit for
4613 : : * the write I/O, plus 2 metadata pages - the extent page and the
4614 : : * blob's primary metadata page
4615 : : */
4616 : 72 : expected_bytes = io_unit_size + 2 * spdk_bs_get_page_size(bs);
4617 : : }
4618 : 120 : CU_ASSERT((g_dev_write_bytes - write_bytes) == expected_bytes);
4619 : :
4620 : : /* The write should have synced the metadata already. Do another sync here
4621 : : * just to confirm.
4622 : : */
4623 : 120 : write_bytes = g_dev_write_bytes;
4624 : 120 : read_bytes = g_dev_read_bytes;
4625 : :
4626 : 120 : g_bserrno = -1;
4627 : 120 : spdk_blob_sync_md(blob, blob_op_complete, NULL);
4628 : 120 : poll_threads();
4629 : 120 : CU_ASSERT(g_bserrno == 0);
4630 : 120 : CU_ASSERT(free_clusters - (2 * i + 1) == spdk_bs_free_cluster_count(bs));
4631 : 120 : CU_ASSERT(spdk_blob_get_num_allocated_clusters(blob) == 2 * i + 1);
4632 : :
4633 : 120 : CU_ASSERT(g_dev_read_bytes == read_bytes);
4634 : 120 : CU_ASSERT(g_dev_write_bytes == write_bytes);
4635 : :
4636 : : /* Now write to another unallocated cluster that is part of the same extent page. */
4637 : 120 : g_bserrno = -1;
4638 : 120 : spdk_blob_io_write(blob, ch, payload_write, io_units_per_extent_page * i + io_units_per_cluster,
4639 : : 1, blob_op_complete, NULL);
4640 : 120 : poll_threads();
4641 : 120 : CU_ASSERT(g_bserrno == 0);
4642 : 120 : CU_ASSERT(free_clusters - (2 * i + 2) == spdk_bs_free_cluster_count(bs));
4643 : 120 : CU_ASSERT(spdk_blob_get_num_allocated_clusters(blob) == 2 * i + 2);
4644 : :
4645 : 120 : CU_ASSERT(g_dev_read_bytes == read_bytes);
4646 : : /*
4647 : : * For legacy metadata, we should have written the I/O and the primary metadata page.
4648 : : * For extent table metadata, we should have written the I/O and the extent metadata page.
4649 : : */
4650 : 120 : expected_bytes = io_unit_size + spdk_bs_get_page_size(bs);
4651 : 120 : CU_ASSERT((g_dev_write_bytes - write_bytes) == expected_bytes);
4652 : :
4653 : : /* Send unmap aligned to the whole cluster - should free it up */
4654 : 120 : g_bserrno = -1;
4655 : 120 : spdk_blob_io_unmap(blob, ch, io_units_per_extent_page * i, io_units_per_cluster, blob_op_complete,
4656 : : NULL);
4657 : 120 : poll_threads();
4658 : 120 : CU_ASSERT(g_bserrno == 0);
4659 : 120 : CU_ASSERT(free_clusters - (2 * i + 1) == spdk_bs_free_cluster_count(bs));
4660 : :
4661 : : /* Write back to the freed cluster */
4662 : 120 : g_bserrno = -1;
4663 : 120 : spdk_blob_io_write(blob, ch, payload_write, io_units_per_extent_page * i, 1, blob_op_complete,
4664 : : NULL);
4665 : 120 : poll_threads();
4666 : 120 : CU_ASSERT(g_bserrno == 0);
4667 : 120 : CU_ASSERT(free_clusters - (2 * i + 2) == spdk_bs_free_cluster_count(bs));
4668 : : }
4669 : :
4670 : 15 : ut_blob_close_and_delete(bs, blob);
4671 : 15 : CU_ASSERT(free_clusters == spdk_bs_free_cluster_count(bs));
4672 : :
4673 : 15 : spdk_bs_free_io_channel(ch);
4674 : 15 : poll_threads();
4675 : 15 : g_blob = NULL;
4676 : 15 : g_blobid = 0;
4677 : :
4678 : 15 : spdk_bs_unload(bs, bs_op_complete, NULL);
4679 : 15 : poll_threads();
4680 : 15 : CU_ASSERT(g_bserrno == 0);
4681 : 15 : g_bs = NULL;
4682 : 15 : }
4683 : :
4684 : : static void
4685 : 15 : blob_thin_prov_unmap_cluster(void)
4686 : : {
4687 : : struct spdk_blob_store *bs;
4688 : : struct spdk_blob *blob, *snapshot;
4689 : : struct spdk_io_channel *ch;
4690 : : struct spdk_bs_dev *dev;
4691 : 15 : struct spdk_bs_opts bs_opts;
4692 : 15 : struct spdk_blob_opts opts;
4693 : : uint64_t free_clusters;
4694 : : uint64_t io_unit_size;
4695 : 15 : uint8_t payload_write[BLOCKLEN];
4696 : 15 : uint8_t payload_read[BLOCKLEN];
4697 : 15 : const uint32_t CLUSTER_COUNT = 3;
4698 : : uint32_t io_units_per_cluster;
4699 : : spdk_blob_id blobid, snapshotid;
4700 : : uint32_t i;
4701 : 15 : int err;
4702 : :
4703 : : /* Use a very large cluster size for this test. Check how the unmap/release cluster code path behaves when
4704 : : * clusters are fully used.
4705 : : */
4706 : 15 : dev = init_dev();
4707 : 15 : spdk_bs_opts_init(&bs_opts, sizeof(bs_opts));
4708 [ - + ]: 15 : bs_opts.cluster_sz = dev->blocklen * dev->blockcnt / (CLUSTER_COUNT + 1);
4709 : :
4710 : 15 : spdk_bs_init(dev, &bs_opts, bs_op_with_handle_complete, NULL);
4711 : 15 : poll_threads();
4712 : 15 : CU_ASSERT(g_bserrno == 0);
4713 [ - + ]: 15 : SPDK_CU_ASSERT_FATAL(g_bs != NULL);
4714 : 15 : bs = g_bs;
4715 : :
4716 : 15 : free_clusters = spdk_bs_free_cluster_count(bs);
4717 : 15 : io_unit_size = spdk_bs_get_io_unit_size(bs);
4718 [ - + ]: 15 : io_units_per_cluster = bs_opts.cluster_sz / io_unit_size;
4719 : :
4720 : 15 : ch = spdk_bs_alloc_io_channel(bs);
4721 [ - + ]: 15 : SPDK_CU_ASSERT_FATAL(ch != NULL);
4722 : :
4723 : 15 : ut_spdk_blob_opts_init(&opts);
4724 : 15 : opts.thin_provision = true;
4725 : :
4726 : 15 : blob = ut_blob_create_and_open(bs, &opts);
4727 : 15 : CU_ASSERT(free_clusters == CLUSTER_COUNT);
4728 : 15 : CU_ASSERT(free_clusters == spdk_bs_free_cluster_count(bs));
4729 : 15 : blobid = spdk_blob_get_id(blob);
4730 : :
4731 : 15 : g_bserrno = -1;
4732 : 15 : spdk_blob_resize(blob, CLUSTER_COUNT, blob_op_complete, NULL);
4733 : 15 : poll_threads();
4734 : 15 : CU_ASSERT(g_bserrno == 0);
4735 : :
4736 : 15 : g_bserrno = -1;
4737 : 15 : spdk_blob_sync_md(blob, blob_op_complete, NULL);
4738 : 15 : poll_threads();
4739 : 15 : CU_ASSERT(g_bserrno == 0);
4740 : 15 : CU_ASSERT(free_clusters == spdk_bs_free_cluster_count(bs));
4741 : 15 : CU_ASSERT(blob->active.num_clusters == CLUSTER_COUNT);
4742 : :
4743 : : /* Fill all clusters */
4744 [ + + ]: 60 : for (i = 0; i < CLUSTER_COUNT; i++) {
4745 : 45 : memset(payload_write, i + 1, sizeof(payload_write));
4746 : 45 : g_bserrno = -1;
4747 : 45 : spdk_blob_io_write(blob, ch, payload_write, io_units_per_cluster * i, 1, blob_op_complete, NULL);
4748 : 45 : poll_threads();
4749 : 45 : CU_ASSERT(g_bserrno == 0);
4750 : 45 : CU_ASSERT(free_clusters - (i + 1) == spdk_bs_free_cluster_count(bs));
4751 : : }
4752 : 15 : CU_ASSERT(0 == spdk_bs_free_cluster_count(bs));
4753 : :
4754 : : /* Unmap one whole cluster */
4755 : 15 : g_bserrno = -1;
4756 : 15 : spdk_blob_io_unmap(blob, ch, io_units_per_cluster, io_units_per_cluster, blob_op_complete, NULL);
4757 : 15 : poll_threads();
4758 : 15 : CU_ASSERT(g_bserrno == 0);
4759 : 15 : CU_ASSERT(1 == spdk_bs_free_cluster_count(bs));
4760 : :
4761 : : /* Verify the data read from the cluster is zeroed out */
4762 : 15 : memset(payload_write, 0, sizeof(payload_write));
4763 : 15 : spdk_blob_io_read(blob, ch, payload_read, io_units_per_cluster, 1, blob_op_complete, NULL);
4764 : 15 : poll_threads();
4765 : 15 : CU_ASSERT(g_bserrno == 0);
4766 : 15 : CU_ASSERT(memcmp(payload_write, payload_read, BLOCKLEN) == 0);
4767 : :
4768 : : /* Fill the same cluster with data */
4769 : 15 : memset(payload_write, 3, sizeof(payload_write));
4770 : 15 : g_bserrno = -1;
4771 : 15 : spdk_blob_io_write(blob, ch, payload_write, io_units_per_cluster, 1, blob_op_complete, NULL);
4772 : 15 : poll_threads();
4773 : 15 : CU_ASSERT(g_bserrno == 0);
4774 : 15 : CU_ASSERT(0 == spdk_bs_free_cluster_count(bs));
4775 : :
4776 : : /* Verify the data read from the cluster has the expected data */
4777 : 15 : spdk_blob_io_read(blob, ch, payload_read, io_units_per_cluster, 1, blob_op_complete, NULL);
4778 : 15 : poll_threads();
4779 : 15 : CU_ASSERT(g_bserrno == 0);
4780 : 15 : CU_ASSERT(memcmp(payload_write, payload_read, BLOCKLEN) == 0);
4781 : :
4782 : : /* Send an unaligned unmap that ecompasses one whole cluster */
4783 : 15 : g_bserrno = -1;
4784 : 15 : spdk_blob_io_unmap(blob, ch, io_units_per_cluster - 1, io_units_per_cluster + 2, blob_op_complete,
4785 : : NULL);
4786 : 15 : poll_threads();
4787 : 15 : CU_ASSERT(g_bserrno == 0);
4788 : 15 : CU_ASSERT(1 == spdk_bs_free_cluster_count(bs));
4789 : :
4790 : : /* Verify the data read from the cluster is zeroed out */
4791 : 15 : g_bserrno = -1;
4792 : 15 : memset(payload_write, 0, sizeof(payload_write));
4793 : 15 : spdk_blob_io_read(blob, ch, payload_read, io_units_per_cluster, 1, blob_op_complete, NULL);
4794 : 15 : poll_threads();
4795 : 15 : CU_ASSERT(g_bserrno == 0);
4796 : 15 : CU_ASSERT(memcmp(payload_write, payload_read, BLOCKLEN) == 0);
4797 : :
4798 : : /* Send a simultaneous unmap with a write to an unallocated area -
4799 : : * check that writes don't claim the currently unmapped cluster */
4800 : 15 : g_bserrno = -1;
4801 : 15 : memset(payload_write, 7, sizeof(payload_write));
4802 : 15 : spdk_blob_io_unmap(blob, ch, 0, io_units_per_cluster, blob_op_complete, NULL);
4803 : 15 : spdk_blob_io_write(blob, ch, payload_write, io_units_per_cluster, 1, blob_op_complete, NULL);
4804 : 15 : poll_threads();
4805 : 15 : CU_ASSERT(g_bserrno == 0);
4806 : 15 : CU_ASSERT(1 == spdk_bs_free_cluster_count(bs));
4807 : :
4808 : : /* Verify the contents of written sector */
4809 : 15 : g_bserrno = -1;
4810 : 15 : spdk_blob_io_read(blob, ch, payload_read, io_units_per_cluster, 1, blob_op_complete, NULL);
4811 : 15 : poll_threads();
4812 : 15 : CU_ASSERT(g_bserrno == 0);
4813 : 15 : CU_ASSERT(memcmp(payload_write, payload_read, BLOCKLEN) == 0);
4814 : :
4815 : : /* Verify the contents of unmapped sector */
4816 : 15 : g_bserrno = -1;
4817 : 15 : memset(payload_write, 0, sizeof(payload_write));
4818 : 15 : spdk_blob_io_read(blob, ch, payload_read, 0, 1, blob_op_complete, NULL);
4819 : 15 : poll_threads();
4820 : 15 : CU_ASSERT(g_bserrno == 0);
4821 : 15 : CU_ASSERT(memcmp(payload_write, payload_read, BLOCKLEN) == 0);
4822 : :
4823 : : /* Make sure clusters are not freed until the unmap to the drive is done */
4824 : 15 : g_bserrno = -1;
4825 : 15 : memset(payload_write, 7, sizeof(payload_write));
4826 : 15 : spdk_blob_io_write(blob, ch, payload_write, 0, 1, blob_op_complete, NULL);
4827 : 15 : poll_threads();
4828 : 15 : CU_ASSERT(g_bserrno == 0);
4829 : 15 : CU_ASSERT(0 == spdk_bs_free_cluster_count(bs));
4830 : :
4831 : 15 : g_bserrno = -1;
4832 : 15 : spdk_blob_io_unmap(blob, ch, 0, io_units_per_cluster, blob_op_complete, NULL);
4833 [ - + - + ]: 15 : while (memcmp(payload_write, &g_dev_buffer[BLOCKLEN * io_units_per_cluster], BLOCKLEN) == 0) {
4834 : 0 : CU_ASSERT(0 == spdk_bs_free_cluster_count(bs));
4835 : 0 : poll_thread_times(0, 1);
4836 : : }
4837 : 15 : poll_threads();
4838 : 15 : CU_ASSERT(g_bserrno == 0);
4839 : 15 : CU_ASSERT(1 == spdk_bs_free_cluster_count(bs));
4840 : :
4841 : : /* Issue #3358 had a bug with concurrent trims to the same cluster causing an assert, check for regressions.
4842 : : * Send three concurrent unmaps to the same cluster.
4843 : : */
4844 : 15 : g_bserrno = -1;
4845 : 15 : memset(payload_write, 7, sizeof(payload_write));
4846 : 15 : spdk_blob_io_write(blob, ch, payload_write, 0, 1, blob_op_complete, NULL);
4847 : 15 : poll_threads();
4848 : 15 : CU_ASSERT(g_bserrno == 0);
4849 : 15 : CU_ASSERT(0 == spdk_bs_free_cluster_count(bs));
4850 : :
4851 : 15 : g_bserrno = -1;
4852 : 15 : err = -1;
4853 : 15 : spdk_blob_io_unmap(blob, ch, 0, io_units_per_cluster, blob_op_complete, NULL);
4854 : 15 : spdk_blob_io_unmap(blob, ch, 0, io_units_per_cluster, blob_op_complete, NULL);
4855 : 15 : spdk_blob_io_unmap(blob, ch, 0, io_units_per_cluster, blob_op_complete, &err);
4856 : 15 : poll_threads();
4857 : 15 : CU_ASSERT(g_bserrno == 0);
4858 : 15 : CU_ASSERT(err == 0);
4859 : 15 : CU_ASSERT(1 == spdk_bs_free_cluster_count(bs));
4860 : :
4861 : : /* Test thin-provisioned blob that is backed */
4862 : 15 : spdk_blob_resize(blob, 1, blob_op_complete, NULL);
4863 : 15 : poll_threads();
4864 : 15 : CU_ASSERT(g_bserrno == 0);
4865 : 15 : spdk_blob_sync_md(blob, blob_op_complete, NULL);
4866 : 15 : poll_threads();
4867 : 15 : CU_ASSERT(g_bserrno == 0);
4868 : 15 : CU_ASSERT(free_clusters == spdk_bs_free_cluster_count(bs));
4869 : :
4870 : 15 : g_bserrno = -1;
4871 : 15 : memset(payload_write, 1, sizeof(payload_write));
4872 : 15 : spdk_blob_io_write(blob, ch, payload_write, 0, 1, blob_op_complete, NULL);
4873 : 15 : poll_threads();
4874 : 15 : CU_ASSERT(g_bserrno == 0);
4875 : 15 : CU_ASSERT(free_clusters - 1 == spdk_bs_free_cluster_count(bs));
4876 : :
4877 : : /* Create a snapshot */
4878 : 15 : CU_ASSERT_EQUAL(_get_snapshots_count(bs), 0);
4879 : 15 : spdk_bs_create_snapshot(bs, blobid, NULL, blob_op_with_id_complete, NULL);
4880 : 15 : poll_threads();
4881 : 15 : CU_ASSERT(g_bserrno == 0);
4882 : 15 : CU_ASSERT(g_blobid != SPDK_BLOBID_INVALID);
4883 : 15 : CU_ASSERT_EQUAL(_get_snapshots_count(bs), 1);
4884 : 15 : snapshotid = g_blobid;
4885 : 15 : CU_ASSERT(free_clusters - 1 == spdk_bs_free_cluster_count(bs));
4886 : 15 : spdk_bs_open_blob(bs, snapshotid, blob_op_with_handle_complete, NULL);
4887 : 15 : poll_threads();
4888 : 15 : CU_ASSERT(g_bserrno == 0);
4889 [ - + ]: 15 : SPDK_CU_ASSERT_FATAL(g_blob != NULL);
4890 : 15 : snapshot = g_blob;
4891 : :
4892 : : /* Write data to blob, it will alloc new cluster */
4893 : 15 : g_bserrno = -1;
4894 : 15 : memset(payload_write, 2, sizeof(payload_write));
4895 : 15 : spdk_blob_io_write(blob, ch, payload_write, 0, 1, blob_op_complete, NULL);
4896 : 15 : poll_threads();
4897 : 15 : CU_ASSERT(g_bserrno == 0);
4898 : 15 : CU_ASSERT(free_clusters - 2 == spdk_bs_free_cluster_count(bs));
4899 : :
4900 : : /* Unmap one whole cluster, but do not release this cluster */
4901 : 15 : g_bserrno = -1;
4902 : 15 : spdk_blob_io_unmap(blob, ch, 0, io_units_per_cluster, blob_op_complete, NULL);
4903 : 15 : poll_threads();
4904 : 15 : CU_ASSERT(g_bserrno == 0);
4905 : 15 : CU_ASSERT(free_clusters - 2 == spdk_bs_free_cluster_count(bs));
4906 : :
4907 : : /* Verify the data read from the cluster is zeroed out */
4908 : 15 : g_bserrno = -1;
4909 : 15 : memset(payload_write, 0, sizeof(payload_write));
4910 : 15 : spdk_blob_io_read(blob, ch, payload_read, 0, 1, blob_op_complete, NULL);
4911 : 15 : poll_threads();
4912 : 15 : CU_ASSERT(g_bserrno == 0);
4913 : 15 : CU_ASSERT(memcmp(payload_write, payload_read, BLOCKLEN) == 0);
4914 : :
4915 : 15 : ut_blob_close_and_delete(bs, blob);
4916 : 15 : ut_blob_close_and_delete(bs, snapshot);
4917 : 15 : CU_ASSERT(free_clusters == spdk_bs_free_cluster_count(bs));
4918 : :
4919 : 15 : spdk_bs_free_io_channel(ch);
4920 : 15 : poll_threads();
4921 : 15 : g_blob = NULL;
4922 : 15 : g_blobid = 0;
4923 : :
4924 : 15 : spdk_bs_unload(bs, bs_op_complete, NULL);
4925 : 15 : poll_threads();
4926 : 15 : CU_ASSERT(g_bserrno == 0);
4927 : 15 : g_bs = NULL;
4928 : 15 : }
4929 : :
4930 : : static void
4931 : 15 : blob_thin_prov_rle(void)
4932 : : {
4933 : : static const uint8_t zero[10 * BLOCKLEN] = { 0 };
4934 : 15 : struct spdk_blob_store *bs = g_bs;
4935 : : struct spdk_blob *blob;
4936 : : struct spdk_io_channel *channel;
4937 : 15 : struct spdk_blob_opts opts;
4938 : : spdk_blob_id blobid;
4939 : : uint64_t free_clusters;
4940 : : uint64_t io_unit_size;
4941 : 15 : uint8_t payload_read[10 * BLOCKLEN];
4942 : 15 : uint8_t payload_write[10 * BLOCKLEN];
4943 : : uint64_t write_bytes;
4944 : : uint64_t read_bytes;
4945 : : uint64_t expected_bytes;
4946 : : uint64_t io_unit;
4947 : :
4948 : : /* assert that the stack variables above are of correct size */
4949 : 15 : CU_ASSERT(spdk_bs_get_io_unit_size(bs) == BLOCKLEN);
4950 : :
4951 : 15 : free_clusters = spdk_bs_free_cluster_count(bs);
4952 : 15 : io_unit_size = spdk_bs_get_io_unit_size(bs);
4953 : :
4954 : 15 : ut_spdk_blob_opts_init(&opts);
4955 : 15 : opts.thin_provision = true;
4956 : 15 : opts.num_clusters = 5;
4957 : :
4958 : 15 : blob = ut_blob_create_and_open(bs, &opts);
4959 : 15 : blobid = spdk_blob_get_id(blob);
4960 : 15 : CU_ASSERT(free_clusters == spdk_bs_free_cluster_count(bs));
4961 : :
4962 : 15 : channel = spdk_bs_alloc_io_channel(bs);
4963 : 15 : CU_ASSERT(channel != NULL);
4964 : :
4965 : : /* Target specifically second cluster in a blob as first allocation */
4966 : 15 : io_unit = bs_cluster_to_io_unit(bs, 1);
4967 : :
4968 : : /* Payload should be all zeros from unallocated clusters */
4969 : 15 : memset(payload_read, 0xFF, sizeof(payload_read));
4970 : 15 : spdk_blob_io_read(blob, channel, payload_read, io_unit, 10, blob_op_complete, NULL);
4971 : 15 : poll_threads();
4972 : 15 : CU_ASSERT(g_bserrno == 0);
4973 : 15 : CU_ASSERT(memcmp(zero, payload_read, 10 * BLOCKLEN) == 0);
4974 : :
4975 : 15 : write_bytes = g_dev_write_bytes;
4976 : 15 : read_bytes = g_dev_read_bytes;
4977 : :
4978 : : /* Issue write to second cluster in a blob */
4979 : 15 : memset(payload_write, 0xE5, sizeof(payload_write));
4980 : 15 : spdk_blob_io_write(blob, channel, payload_write, io_unit, 10, blob_op_complete, NULL);
4981 : 15 : poll_threads();
4982 : 15 : CU_ASSERT(g_bserrno == 0);
4983 : 15 : CU_ASSERT(free_clusters - 1 == spdk_bs_free_cluster_count(bs));
4984 : : /* For thin-provisioned blob we need to write 10 pages plus one page metadata and
4985 : : * read 0 bytes */
4986 : 15 : expected_bytes = 10 * io_unit_size + spdk_bs_get_page_size(bs);
4987 [ + + + + ]: 15 : if (g_use_extent_table) {
4988 : : /* Add one more page for EXTENT_PAGE write */
4989 : 9 : expected_bytes += spdk_bs_get_page_size(bs);
4990 : : }
4991 : 15 : CU_ASSERT(g_dev_write_bytes - write_bytes == expected_bytes);
4992 : 15 : CU_ASSERT(g_dev_read_bytes - read_bytes == 0);
4993 : :
4994 : 15 : spdk_blob_io_read(blob, channel, payload_read, io_unit, 10, blob_op_complete, NULL);
4995 : 15 : poll_threads();
4996 : 15 : CU_ASSERT(g_bserrno == 0);
4997 : 15 : CU_ASSERT(memcmp(payload_write, payload_read, 10 * BLOCKLEN) == 0);
4998 : :
4999 : 15 : spdk_bs_free_io_channel(channel);
5000 : 15 : poll_threads();
5001 : :
5002 : 15 : spdk_blob_close(blob, blob_op_complete, NULL);
5003 : 15 : poll_threads();
5004 : 15 : CU_ASSERT(g_bserrno == 0);
5005 : :
5006 : 15 : ut_bs_reload(&bs, NULL);
5007 : :
5008 : 15 : spdk_bs_open_blob(bs, blobid, blob_op_with_handle_complete, NULL);
5009 : 15 : poll_threads();
5010 : 15 : CU_ASSERT(g_bserrno == 0);
5011 [ - + ]: 15 : SPDK_CU_ASSERT_FATAL(g_blob != NULL);
5012 : 15 : blob = g_blob;
5013 : :
5014 : 15 : channel = spdk_bs_alloc_io_channel(bs);
5015 : 15 : CU_ASSERT(channel != NULL);
5016 : :
5017 : : /* Read second cluster after blob reload to confirm data written */
5018 : 15 : spdk_blob_io_read(blob, channel, payload_read, io_unit, 10, blob_op_complete, NULL);
5019 : 15 : poll_threads();
5020 : 15 : CU_ASSERT(g_bserrno == 0);
5021 : 15 : CU_ASSERT(memcmp(payload_write, payload_read, 10 * BLOCKLEN) == 0);
5022 : :
5023 : 15 : spdk_bs_free_io_channel(channel);
5024 : 15 : poll_threads();
5025 : :
5026 : 15 : ut_blob_close_and_delete(bs, blob);
5027 : 15 : }
5028 : :
5029 : : static void
5030 : 15 : blob_thin_prov_rw_iov(void)
5031 : : {
5032 : : static const uint8_t zero[10 * BLOCKLEN] = { 0 };
5033 : 15 : struct spdk_blob_store *bs = g_bs;
5034 : : struct spdk_blob *blob;
5035 : : struct spdk_io_channel *channel;
5036 : 15 : struct spdk_blob_opts opts;
5037 : : uint64_t free_clusters;
5038 : 15 : uint8_t payload_read[10 * BLOCKLEN];
5039 : 15 : uint8_t payload_write[10 * BLOCKLEN];
5040 : 15 : struct iovec iov_read[3];
5041 : 15 : struct iovec iov_write[3];
5042 : :
5043 : 15 : free_clusters = spdk_bs_free_cluster_count(bs);
5044 : :
5045 : 15 : channel = spdk_bs_alloc_io_channel(bs);
5046 : 15 : CU_ASSERT(channel != NULL);
5047 : :
5048 : 15 : ut_spdk_blob_opts_init(&opts);
5049 : 15 : opts.thin_provision = true;
5050 : :
5051 : 15 : blob = ut_blob_create_and_open(bs, &opts);
5052 : 15 : CU_ASSERT(free_clusters == spdk_bs_free_cluster_count(bs));
5053 : :
5054 : 15 : CU_ASSERT(blob->active.num_clusters == 0);
5055 : :
5056 : : /* The blob started at 0 clusters. Resize it to be 5, but still unallocated. */
5057 : 15 : spdk_blob_resize(blob, 5, blob_op_complete, NULL);
5058 : 15 : poll_threads();
5059 : 15 : CU_ASSERT(g_bserrno == 0);
5060 : 15 : CU_ASSERT(free_clusters == spdk_bs_free_cluster_count(bs));
5061 : 15 : CU_ASSERT(blob->active.num_clusters == 5);
5062 : :
5063 : 15 : spdk_blob_sync_md(blob, blob_op_complete, NULL);
5064 : 15 : poll_threads();
5065 : 15 : CU_ASSERT(g_bserrno == 0);
5066 : : /* Sync must not change anything */
5067 : 15 : CU_ASSERT(free_clusters == spdk_bs_free_cluster_count(bs));
5068 : 15 : CU_ASSERT(blob->active.num_clusters == 5);
5069 : :
5070 : : /* Payload should be all zeros from unallocated clusters */
5071 : 15 : memset(payload_read, 0xAA, sizeof(payload_read));
5072 : 15 : iov_read[0].iov_base = payload_read;
5073 : 15 : iov_read[0].iov_len = 3 * BLOCKLEN;
5074 : 15 : iov_read[1].iov_base = payload_read + 3 * BLOCKLEN;
5075 : 15 : iov_read[1].iov_len = 4 * BLOCKLEN;
5076 : 15 : iov_read[2].iov_base = payload_read + 7 * BLOCKLEN;
5077 : 15 : iov_read[2].iov_len = 3 * BLOCKLEN;
5078 : 15 : spdk_blob_io_readv(blob, channel, iov_read, 3, 250, 10, blob_op_complete, NULL);
5079 : 15 : poll_threads();
5080 : 15 : CU_ASSERT(g_bserrno == 0);
5081 : 15 : CU_ASSERT(memcmp(zero, payload_read, 10 * BLOCKLEN) == 0);
5082 : :
5083 : 15 : memset(payload_write, 0xE5, sizeof(payload_write));
5084 : 15 : iov_write[0].iov_base = payload_write;
5085 : 15 : iov_write[0].iov_len = 1 * BLOCKLEN;
5086 : 15 : iov_write[1].iov_base = payload_write + 1 * BLOCKLEN;
5087 : 15 : iov_write[1].iov_len = 5 * BLOCKLEN;
5088 : 15 : iov_write[2].iov_base = payload_write + 6 * BLOCKLEN;
5089 : 15 : iov_write[2].iov_len = 4 * BLOCKLEN;
5090 : :
5091 : 15 : spdk_blob_io_writev(blob, channel, iov_write, 3, 250, 10, blob_op_complete, NULL);
5092 : 15 : poll_threads();
5093 : 15 : CU_ASSERT(g_bserrno == 0);
5094 : :
5095 : 15 : memset(payload_read, 0xAA, sizeof(payload_read));
5096 : 15 : iov_read[0].iov_base = payload_read;
5097 : 15 : iov_read[0].iov_len = 3 * BLOCKLEN;
5098 : 15 : iov_read[1].iov_base = payload_read + 3 * BLOCKLEN;
5099 : 15 : iov_read[1].iov_len = 4 * BLOCKLEN;
5100 : 15 : iov_read[2].iov_base = payload_read + 7 * BLOCKLEN;
5101 : 15 : iov_read[2].iov_len = 3 * BLOCKLEN;
5102 : 15 : spdk_blob_io_readv(blob, channel, iov_read, 3, 250, 10, blob_op_complete, NULL);
5103 : 15 : poll_threads();
5104 : 15 : CU_ASSERT(g_bserrno == 0);
5105 : 15 : CU_ASSERT(memcmp(payload_write, payload_read, 10 * BLOCKLEN) == 0);
5106 : :
5107 : 15 : spdk_bs_free_io_channel(channel);
5108 : 15 : poll_threads();
5109 : :
5110 : 15 : ut_blob_close_and_delete(bs, blob);
5111 : 15 : }
5112 : :
5113 : : struct iter_ctx {
5114 : : int current_iter;
5115 : : spdk_blob_id blobid[4];
5116 : : };
5117 : :
5118 : : static void
5119 : 120 : test_iter(void *arg, struct spdk_blob *blob, int bserrno)
5120 : : {
5121 : 120 : struct iter_ctx *iter_ctx = arg;
5122 : : spdk_blob_id blobid;
5123 : :
5124 : 120 : CU_ASSERT(bserrno == 0);
5125 : 120 : blobid = spdk_blob_get_id(blob);
5126 : 120 : CU_ASSERT(blobid == iter_ctx->blobid[iter_ctx->current_iter++]);
5127 : 120 : }
5128 : :
5129 : : static void
5130 : 15 : bs_load_iter_test(void)
5131 : : {
5132 : : struct spdk_blob_store *bs;
5133 : : struct spdk_bs_dev *dev;
5134 : 15 : struct iter_ctx iter_ctx = { 0 };
5135 : : struct spdk_blob *blob;
5136 : : int i, rc;
5137 : 15 : struct spdk_bs_opts opts;
5138 : :
5139 : 15 : dev = init_dev();
5140 : 15 : spdk_bs_opts_init(&opts, sizeof(opts));
5141 [ - + ]: 15 : snprintf(opts.bstype.bstype, sizeof(opts.bstype.bstype), "TESTTYPE");
5142 : :
5143 : : /* Initialize a new blob store */
5144 : 15 : spdk_bs_init(dev, &opts, bs_op_with_handle_complete, NULL);
5145 : 15 : poll_threads();
5146 : 15 : CU_ASSERT(g_bserrno == 0);
5147 [ - + ]: 15 : SPDK_CU_ASSERT_FATAL(g_bs != NULL);
5148 : 15 : bs = g_bs;
5149 : :
5150 [ + + ]: 75 : for (i = 0; i < 4; i++) {
5151 : 60 : blob = ut_blob_create_and_open(bs, NULL);
5152 : 60 : iter_ctx.blobid[i] = spdk_blob_get_id(blob);
5153 : :
5154 : : /* Just save the blobid as an xattr for testing purposes. */
5155 : 60 : rc = spdk_blob_set_xattr(blob, "blobid", &iter_ctx.blobid[i], sizeof(spdk_blob_id));
5156 : 60 : CU_ASSERT(rc == 0);
5157 : :
5158 : : /* Resize the blob */
5159 : 60 : spdk_blob_resize(blob, i, blob_op_complete, NULL);
5160 : 60 : poll_threads();
5161 : 60 : CU_ASSERT(g_bserrno == 0);
5162 : :
5163 : 60 : spdk_blob_close(blob, blob_op_complete, NULL);
5164 : 60 : poll_threads();
5165 : 60 : CU_ASSERT(g_bserrno == 0);
5166 : : }
5167 : :
5168 : 15 : g_bserrno = -1;
5169 : 15 : spdk_bs_unload(bs, bs_op_complete, NULL);
5170 : 15 : poll_threads();
5171 : 15 : CU_ASSERT(g_bserrno == 0);
5172 : :
5173 : 15 : dev = init_dev();
5174 : 15 : spdk_bs_opts_init(&opts, sizeof(opts));
5175 [ - + ]: 15 : snprintf(opts.bstype.bstype, sizeof(opts.bstype.bstype), "TESTTYPE");
5176 : 15 : opts.iter_cb_fn = test_iter;
5177 : 15 : opts.iter_cb_arg = &iter_ctx;
5178 : :
5179 : : /* Test blob iteration during load after a clean shutdown. */
5180 : 15 : spdk_bs_load(dev, &opts, bs_op_with_handle_complete, NULL);
5181 : 15 : poll_threads();
5182 : 15 : CU_ASSERT(g_bserrno == 0);
5183 [ - + ]: 15 : SPDK_CU_ASSERT_FATAL(g_bs != NULL);
5184 : 15 : bs = g_bs;
5185 : :
5186 : : /* Dirty shutdown */
5187 : 15 : bs_free(bs);
5188 : :
5189 : 15 : dev = init_dev();
5190 : 15 : spdk_bs_opts_init(&opts, sizeof(opts));
5191 [ - + ]: 15 : snprintf(opts.bstype.bstype, sizeof(opts.bstype.bstype), "TESTTYPE");
5192 : 15 : opts.iter_cb_fn = test_iter;
5193 : 15 : iter_ctx.current_iter = 0;
5194 : 15 : opts.iter_cb_arg = &iter_ctx;
5195 : :
5196 : : /* Test blob iteration during load after a dirty shutdown. */
5197 : 15 : spdk_bs_load(dev, &opts, bs_op_with_handle_complete, NULL);
5198 : 15 : poll_threads();
5199 : 15 : CU_ASSERT(g_bserrno == 0);
5200 [ - + ]: 15 : SPDK_CU_ASSERT_FATAL(g_bs != NULL);
5201 : 15 : bs = g_bs;
5202 : :
5203 : 15 : spdk_bs_unload(bs, bs_op_complete, NULL);
5204 : 15 : poll_threads();
5205 : 15 : CU_ASSERT(g_bserrno == 0);
5206 : 15 : g_bs = NULL;
5207 : 15 : }
5208 : :
5209 : : static void
5210 : 15 : blob_snapshot_rw(void)
5211 : : {
5212 : : static const uint8_t zero[10 * BLOCKLEN] = { 0 };
5213 : 15 : struct spdk_blob_store *bs = g_bs;
5214 : : struct spdk_blob *blob, *snapshot;
5215 : : struct spdk_io_channel *channel;
5216 : 15 : struct spdk_blob_opts opts;
5217 : : spdk_blob_id blobid, snapshotid;
5218 : : uint64_t free_clusters;
5219 : : uint64_t cluster_size;
5220 : : uint64_t io_unit_size;
5221 : 15 : uint8_t payload_read[10 * BLOCKLEN];
5222 : 15 : uint8_t payload_write[10 * BLOCKLEN];
5223 : : uint64_t write_bytes_start;
5224 : : uint64_t read_bytes_start;
5225 : : uint64_t copy_bytes_start;
5226 : : uint64_t write_bytes;
5227 : : uint64_t read_bytes;
5228 : : uint64_t copy_bytes;
5229 : : uint64_t expected_bytes;
5230 : :
5231 : 15 : free_clusters = spdk_bs_free_cluster_count(bs);
5232 : 15 : cluster_size = spdk_bs_get_cluster_size(bs);
5233 : 15 : io_unit_size = spdk_bs_get_io_unit_size(bs);
5234 : :
5235 : 15 : channel = spdk_bs_alloc_io_channel(bs);
5236 : 15 : CU_ASSERT(channel != NULL);
5237 : :
5238 : 15 : ut_spdk_blob_opts_init(&opts);
5239 : 15 : opts.thin_provision = true;
5240 : 15 : opts.num_clusters = 5;
5241 : :
5242 : 15 : blob = ut_blob_create_and_open(bs, &opts);
5243 : 15 : blobid = spdk_blob_get_id(blob);
5244 : 15 : CU_ASSERT(free_clusters == spdk_bs_free_cluster_count(bs));
5245 : :
5246 : 15 : CU_ASSERT(spdk_blob_get_num_clusters(blob) == 5);
5247 : :
5248 : 15 : memset(payload_read, 0xFF, sizeof(payload_read));
5249 : 15 : spdk_blob_io_read(blob, channel, payload_read, 4, 10, blob_op_complete, NULL);
5250 : 15 : poll_threads();
5251 : 15 : CU_ASSERT(g_bserrno == 0);
5252 : 15 : CU_ASSERT(memcmp(zero, payload_read, 10 * BLOCKLEN) == 0);
5253 : :
5254 : 15 : memset(payload_write, 0xE5, sizeof(payload_write));
5255 : 15 : spdk_blob_io_write(blob, channel, payload_write, 4, 10, blob_op_complete, NULL);
5256 : 15 : poll_threads();
5257 : 15 : CU_ASSERT(g_bserrno == 0);
5258 : 15 : CU_ASSERT(free_clusters != spdk_bs_free_cluster_count(bs));
5259 : :
5260 : : /* Create snapshot from blob */
5261 : 15 : spdk_bs_create_snapshot(bs, blobid, NULL, blob_op_with_id_complete, NULL);
5262 : 15 : poll_threads();
5263 : 15 : CU_ASSERT(g_bserrno == 0);
5264 : 15 : CU_ASSERT(g_blobid != SPDK_BLOBID_INVALID);
5265 : 15 : snapshotid = g_blobid;
5266 : :
5267 : 15 : spdk_bs_open_blob(bs, snapshotid, blob_op_with_handle_complete, NULL);
5268 : 15 : poll_threads();
5269 : 15 : CU_ASSERT(g_bserrno == 0);
5270 [ - + ]: 15 : SPDK_CU_ASSERT_FATAL(g_blob != NULL);
5271 : 15 : snapshot = g_blob;
5272 [ - + ]: 15 : CU_ASSERT(snapshot->data_ro == true);
5273 [ - + ]: 15 : CU_ASSERT(snapshot->md_ro == true);
5274 : :
5275 : 15 : CU_ASSERT(spdk_blob_get_num_clusters(snapshot) == 5);
5276 : :
5277 : 15 : write_bytes_start = g_dev_write_bytes;
5278 : 15 : read_bytes_start = g_dev_read_bytes;
5279 : 15 : copy_bytes_start = g_dev_copy_bytes;
5280 : :
5281 : 15 : memset(payload_write, 0xAA, sizeof(payload_write));
5282 : 15 : spdk_blob_io_write(blob, channel, payload_write, 4, 10, blob_op_complete, NULL);
5283 : 15 : poll_threads();
5284 : 15 : CU_ASSERT(g_bserrno == 0);
5285 : 15 : CU_ASSERT(free_clusters != spdk_bs_free_cluster_count(bs));
5286 : :
5287 : : /* For a clone we need to allocate and copy one cluster, update one page of metadata
5288 : : * and then write 10 io units of payload.
5289 : : */
5290 : 15 : write_bytes = g_dev_write_bytes - write_bytes_start;
5291 : 15 : read_bytes = g_dev_read_bytes - read_bytes_start;
5292 : 15 : copy_bytes = g_dev_copy_bytes - copy_bytes_start;
5293 [ + + + + ]: 15 : if (g_dev_copy_enabled) {
5294 : 6 : CU_ASSERT(copy_bytes == cluster_size);
5295 : : } else {
5296 : 9 : CU_ASSERT(copy_bytes == 0);
5297 : : }
5298 : 15 : expected_bytes = 10 * io_unit_size + cluster_size + spdk_bs_get_page_size(bs);
5299 [ + + + + ]: 15 : if (g_use_extent_table) {
5300 : : /* Add one more page for EXTENT_PAGE write */
5301 : 9 : expected_bytes += spdk_bs_get_page_size(bs);
5302 : : }
5303 : 15 : CU_ASSERT(write_bytes + copy_bytes == expected_bytes);
5304 : 15 : CU_ASSERT(read_bytes + copy_bytes == cluster_size);
5305 : :
5306 : 15 : spdk_blob_io_read(blob, channel, payload_read, 4, 10, blob_op_complete, NULL);
5307 : 15 : poll_threads();
5308 : 15 : CU_ASSERT(g_bserrno == 0);
5309 : 15 : CU_ASSERT(memcmp(payload_write, payload_read, 10 * BLOCKLEN) == 0);
5310 : :
5311 : : /* Data on snapshot should not change after write to clone */
5312 : 15 : memset(payload_write, 0xE5, sizeof(payload_write));
5313 : 15 : spdk_blob_io_read(snapshot, channel, payload_read, 4, 10, blob_op_complete, NULL);
5314 : 15 : poll_threads();
5315 : 15 : CU_ASSERT(g_bserrno == 0);
5316 : 15 : CU_ASSERT(memcmp(payload_write, payload_read, 10 * BLOCKLEN) == 0);
5317 : :
5318 : 15 : ut_blob_close_and_delete(bs, blob);
5319 : 15 : ut_blob_close_and_delete(bs, snapshot);
5320 : :
5321 : 15 : spdk_bs_free_io_channel(channel);
5322 : 15 : poll_threads();
5323 : 15 : g_blob = NULL;
5324 : 15 : g_blobid = 0;
5325 : 15 : }
5326 : :
5327 : : static void
5328 : 15 : blob_snapshot_rw_iov(void)
5329 : : {
5330 : : static const uint8_t zero[10 * BLOCKLEN] = { 0 };
5331 : 15 : struct spdk_blob_store *bs = g_bs;
5332 : : struct spdk_blob *blob, *snapshot;
5333 : : struct spdk_io_channel *channel;
5334 : 15 : struct spdk_blob_opts opts;
5335 : : spdk_blob_id blobid, snapshotid;
5336 : : uint64_t free_clusters;
5337 : 15 : uint8_t payload_read[10 * BLOCKLEN];
5338 : 15 : uint8_t payload_write[10 * BLOCKLEN];
5339 : 15 : struct iovec iov_read[3];
5340 : 15 : struct iovec iov_write[3];
5341 : :
5342 : 15 : free_clusters = spdk_bs_free_cluster_count(bs);
5343 : :
5344 : 15 : channel = spdk_bs_alloc_io_channel(bs);
5345 : 15 : CU_ASSERT(channel != NULL);
5346 : :
5347 : 15 : ut_spdk_blob_opts_init(&opts);
5348 : 15 : opts.thin_provision = true;
5349 : 15 : opts.num_clusters = 5;
5350 : :
5351 : 15 : blob = ut_blob_create_and_open(bs, &opts);
5352 : 15 : blobid = spdk_blob_get_id(blob);
5353 : 15 : CU_ASSERT(free_clusters == spdk_bs_free_cluster_count(bs));
5354 : :
5355 : 15 : CU_ASSERT(spdk_blob_get_num_clusters(blob) == 5);
5356 : :
5357 : : /* Create snapshot from blob */
5358 : 15 : spdk_bs_create_snapshot(bs, blobid, NULL, blob_op_with_id_complete, NULL);
5359 : 15 : poll_threads();
5360 : 15 : CU_ASSERT(g_bserrno == 0);
5361 : 15 : CU_ASSERT(g_blobid != SPDK_BLOBID_INVALID);
5362 : 15 : snapshotid = g_blobid;
5363 : :
5364 : 15 : spdk_bs_open_blob(bs, snapshotid, blob_op_with_handle_complete, NULL);
5365 : 15 : poll_threads();
5366 : 15 : CU_ASSERT(g_bserrno == 0);
5367 [ - + ]: 15 : SPDK_CU_ASSERT_FATAL(g_blob != NULL);
5368 : 15 : snapshot = g_blob;
5369 [ - + ]: 15 : CU_ASSERT(snapshot->data_ro == true);
5370 [ - + ]: 15 : CU_ASSERT(snapshot->md_ro == true);
5371 : 15 : CU_ASSERT(spdk_blob_get_num_clusters(snapshot) == 5);
5372 : :
5373 : : /* Payload should be all zeros from unallocated clusters */
5374 : 15 : memset(payload_read, 0xAA, sizeof(payload_read));
5375 : 15 : iov_read[0].iov_base = payload_read;
5376 : 15 : iov_read[0].iov_len = 3 * BLOCKLEN;
5377 : 15 : iov_read[1].iov_base = payload_read + 3 * BLOCKLEN;
5378 : 15 : iov_read[1].iov_len = 4 * BLOCKLEN;
5379 : 15 : iov_read[2].iov_base = payload_read + 7 * BLOCKLEN;
5380 : 15 : iov_read[2].iov_len = 3 * BLOCKLEN;
5381 : 15 : spdk_blob_io_readv(blob, channel, iov_read, 3, 250, 10, blob_op_complete, NULL);
5382 : 15 : poll_threads();
5383 : 15 : CU_ASSERT(g_bserrno == 0);
5384 : 15 : CU_ASSERT(memcmp(zero, payload_read, 10 * BLOCKLEN) == 0);
5385 : :
5386 : 15 : memset(payload_write, 0xE5, sizeof(payload_write));
5387 : 15 : iov_write[0].iov_base = payload_write;
5388 : 15 : iov_write[0].iov_len = 1 * BLOCKLEN;
5389 : 15 : iov_write[1].iov_base = payload_write + 1 * BLOCKLEN;
5390 : 15 : iov_write[1].iov_len = 5 * BLOCKLEN;
5391 : 15 : iov_write[2].iov_base = payload_write + 6 * BLOCKLEN;
5392 : 15 : iov_write[2].iov_len = 4 * BLOCKLEN;
5393 : :
5394 : 15 : spdk_blob_io_writev(blob, channel, iov_write, 3, 250, 10, blob_op_complete, NULL);
5395 : 15 : poll_threads();
5396 : 15 : CU_ASSERT(g_bserrno == 0);
5397 : :
5398 : 15 : memset(payload_read, 0xAA, sizeof(payload_read));
5399 : 15 : iov_read[0].iov_base = payload_read;
5400 : 15 : iov_read[0].iov_len = 3 * BLOCKLEN;
5401 : 15 : iov_read[1].iov_base = payload_read + 3 * BLOCKLEN;
5402 : 15 : iov_read[1].iov_len = 4 * BLOCKLEN;
5403 : 15 : iov_read[2].iov_base = payload_read + 7 * BLOCKLEN;
5404 : 15 : iov_read[2].iov_len = 3 * BLOCKLEN;
5405 : 15 : spdk_blob_io_readv(blob, channel, iov_read, 3, 250, 10, blob_op_complete, NULL);
5406 : 15 : poll_threads();
5407 : 15 : CU_ASSERT(g_bserrno == 0);
5408 : 15 : CU_ASSERT(memcmp(payload_write, payload_read, 10 * BLOCKLEN) == 0);
5409 : :
5410 : 15 : spdk_bs_free_io_channel(channel);
5411 : 15 : poll_threads();
5412 : :
5413 : 15 : ut_blob_close_and_delete(bs, blob);
5414 : 15 : ut_blob_close_and_delete(bs, snapshot);
5415 : 15 : }
5416 : :
5417 : : /**
5418 : : * Inflate / decouple parent rw unit tests.
5419 : : *
5420 : : * --------------
5421 : : * original blob: 0 1 2 3 4
5422 : : * ,---------+---------+---------+---------+---------.
5423 : : * snapshot |xxxxxxxxx|xxxxxxxxx|xxxxxxxxx|xxxxxxxxx| - |
5424 : : * +---------+---------+---------+---------+---------+
5425 : : * snapshot2 | - |yyyyyyyyy| - |yyyyyyyyy| - |
5426 : : * +---------+---------+---------+---------+---------+
5427 : : * blob | - |zzzzzzzzz| - | - | - |
5428 : : * '---------+---------+---------+---------+---------'
5429 : : * . . . . . .
5430 : : * -------- . . . . . .
5431 : : * inflate: . . . . . .
5432 : : * ,---------+---------+---------+---------+---------.
5433 : : * blob |xxxxxxxxx|zzzzzzzzz|xxxxxxxxx|yyyyyyyyy|000000000|
5434 : : * '---------+---------+---------+---------+---------'
5435 : : *
5436 : : * NOTE: needs to allocate 4 clusters, thin provisioning removed, dependency
5437 : : * on snapshot2 and snapshot removed . . .
5438 : : * . . . . . .
5439 : : * ---------------- . . . . . .
5440 : : * decouple parent: . . . . . .
5441 : : * ,---------+---------+---------+---------+---------.
5442 : : * snapshot |xxxxxxxxx|xxxxxxxxx|xxxxxxxxx|xxxxxxxxx| - |
5443 : : * +---------+---------+---------+---------+---------+
5444 : : * blob | - |zzzzzzzzz| - |yyyyyyyyy| - |
5445 : : * '---------+---------+---------+---------+---------'
5446 : : *
5447 : : * NOTE: needs to allocate 1 cluster, 3 clusters unallocated, dependency
5448 : : * on snapshot2 removed and on snapshot still exists. Snapshot2
5449 : : * should remain a clone of snapshot.
5450 : : */
5451 : : static void
5452 : 30 : _blob_inflate_rw(bool decouple_parent)
5453 : : {
5454 : 30 : struct spdk_blob_store *bs = g_bs;
5455 : : struct spdk_blob *blob, *snapshot, *snapshot2;
5456 : : struct spdk_io_channel *channel;
5457 : 30 : struct spdk_blob_opts opts;
5458 : : spdk_blob_id blobid, snapshotid, snapshot2id;
5459 : : uint64_t free_clusters;
5460 : : uint64_t cluster_size;
5461 : :
5462 : : uint64_t payload_size;
5463 : : uint8_t *payload_read;
5464 : : uint8_t *payload_write;
5465 : : uint8_t *payload_clone;
5466 : :
5467 : : uint64_t io_units_per_cluster;
5468 : : uint64_t io_units_per_payload;
5469 : :
5470 : : int i;
5471 : 30 : spdk_blob_id ids[2];
5472 : 30 : size_t count;
5473 : :
5474 : 30 : free_clusters = spdk_bs_free_cluster_count(bs);
5475 : 30 : cluster_size = spdk_bs_get_cluster_size(bs);
5476 [ - + ]: 30 : io_units_per_cluster = cluster_size / spdk_bs_get_io_unit_size(bs);
5477 : 30 : io_units_per_payload = io_units_per_cluster * 5;
5478 : :
5479 : 30 : payload_size = cluster_size * 5;
5480 : :
5481 : 30 : payload_read = malloc(payload_size);
5482 [ - + ]: 30 : SPDK_CU_ASSERT_FATAL(payload_read != NULL);
5483 : :
5484 : 30 : payload_write = malloc(payload_size);
5485 [ - + ]: 30 : SPDK_CU_ASSERT_FATAL(payload_write != NULL);
5486 : :
5487 : 30 : payload_clone = malloc(payload_size);
5488 [ - + ]: 30 : SPDK_CU_ASSERT_FATAL(payload_clone != NULL);
5489 : :
5490 : 30 : channel = spdk_bs_alloc_io_channel(bs);
5491 [ - + ]: 30 : SPDK_CU_ASSERT_FATAL(channel != NULL);
5492 : :
5493 : : /* Create blob */
5494 : 30 : ut_spdk_blob_opts_init(&opts);
5495 : 30 : opts.thin_provision = true;
5496 : 30 : opts.num_clusters = 5;
5497 : :
5498 : 30 : blob = ut_blob_create_and_open(bs, &opts);
5499 : 30 : blobid = spdk_blob_get_id(blob);
5500 : 30 : CU_ASSERT(free_clusters == spdk_bs_free_cluster_count(bs));
5501 : :
5502 : 30 : CU_ASSERT(spdk_blob_get_num_clusters(blob) == 5);
5503 : :
5504 : : /* 1) Initial read should return zeroed payload */
5505 [ - + ]: 30 : memset(payload_read, 0xFF, payload_size);
5506 : 30 : spdk_blob_io_read(blob, channel, payload_read, 0, io_units_per_payload,
5507 : : blob_op_complete, NULL);
5508 : 30 : poll_threads();
5509 : 30 : CU_ASSERT(g_bserrno == 0);
5510 : 30 : CU_ASSERT(spdk_mem_all_zero(payload_read, payload_size));
5511 : :
5512 : : /* Fill whole blob with a pattern, except last cluster (to be sure it
5513 : : * isn't allocated) */
5514 [ - + ]: 30 : memset(payload_write, 0xE5, payload_size - cluster_size);
5515 : 30 : spdk_blob_io_write(blob, channel, payload_write, 0, io_units_per_payload -
5516 : : io_units_per_cluster, blob_op_complete, NULL);
5517 : 30 : poll_threads();
5518 : 30 : CU_ASSERT(g_bserrno == 0);
5519 : 30 : CU_ASSERT(free_clusters != spdk_bs_free_cluster_count(bs));
5520 : :
5521 : : /* 2) Create snapshot from blob (first level) */
5522 : 30 : spdk_bs_create_snapshot(bs, blobid, NULL, blob_op_with_id_complete, NULL);
5523 : 30 : poll_threads();
5524 : 30 : CU_ASSERT(g_bserrno == 0);
5525 : 30 : CU_ASSERT(g_blobid != SPDK_BLOBID_INVALID);
5526 : 30 : snapshotid = g_blobid;
5527 : :
5528 : 30 : spdk_bs_open_blob(bs, snapshotid, blob_op_with_handle_complete, NULL);
5529 : 30 : poll_threads();
5530 : 30 : CU_ASSERT(g_bserrno == 0);
5531 [ - + ]: 30 : SPDK_CU_ASSERT_FATAL(g_blob != NULL);
5532 : 30 : snapshot = g_blob;
5533 [ - + ]: 30 : CU_ASSERT(snapshot->data_ro == true);
5534 [ - + ]: 30 : CU_ASSERT(snapshot->md_ro == true);
5535 : :
5536 : 30 : CU_ASSERT(spdk_blob_get_num_clusters(snapshot) == 5);
5537 : :
5538 : : /* Write every second cluster with a pattern.
5539 : : *
5540 : : * Last cluster shouldn't be written, to be sure that snapshot nor clone
5541 : : * doesn't allocate it.
5542 : : *
5543 : : * payload_clone stores expected result on "blob" read at the time and
5544 : : * is used only to check data consistency on clone before and after
5545 : : * inflation. Initially we fill it with a backing snapshots pattern
5546 : : * used before.
5547 : : */
5548 [ - + ]: 30 : memset(payload_clone, 0xE5, payload_size - cluster_size);
5549 [ - + ]: 30 : memset(payload_clone + payload_size - cluster_size, 0x00, cluster_size);
5550 [ - + ]: 30 : memset(payload_write, 0xAA, payload_size);
5551 [ + + ]: 90 : for (i = 1; i < 5; i += 2) {
5552 : 60 : spdk_blob_io_write(blob, channel, payload_write, i * io_units_per_cluster,
5553 : : io_units_per_cluster, blob_op_complete, NULL);
5554 : 60 : poll_threads();
5555 : 60 : CU_ASSERT(g_bserrno == 0);
5556 : :
5557 : : /* Update expected result */
5558 [ - + - + ]: 60 : memcpy(payload_clone + (cluster_size * i), payload_write,
5559 : : cluster_size);
5560 : : }
5561 : 30 : CU_ASSERT(free_clusters != spdk_bs_free_cluster_count(bs));
5562 : :
5563 : : /* Check data consistency on clone */
5564 [ - + ]: 30 : memset(payload_read, 0xFF, payload_size);
5565 : 30 : spdk_blob_io_read(blob, channel, payload_read, 0, io_units_per_payload,
5566 : : blob_op_complete, NULL);
5567 : 30 : poll_threads();
5568 : 30 : CU_ASSERT(g_bserrno == 0);
5569 [ - + - + ]: 30 : CU_ASSERT(memcmp(payload_clone, payload_read, payload_size) == 0);
5570 : :
5571 : : /* 3) Create second levels snapshot from blob */
5572 : 30 : spdk_bs_create_snapshot(bs, blobid, NULL, blob_op_with_id_complete, NULL);
5573 : 30 : poll_threads();
5574 : 30 : CU_ASSERT(g_bserrno == 0);
5575 : 30 : CU_ASSERT(g_blobid != SPDK_BLOBID_INVALID);
5576 : 30 : snapshot2id = g_blobid;
5577 : :
5578 : 30 : spdk_bs_open_blob(bs, snapshot2id, blob_op_with_handle_complete, NULL);
5579 : 30 : poll_threads();
5580 : 30 : CU_ASSERT(g_bserrno == 0);
5581 [ - + ]: 30 : SPDK_CU_ASSERT_FATAL(g_blob != NULL);
5582 : 30 : snapshot2 = g_blob;
5583 [ - + ]: 30 : CU_ASSERT(snapshot2->data_ro == true);
5584 [ - + ]: 30 : CU_ASSERT(snapshot2->md_ro == true);
5585 : :
5586 : 30 : CU_ASSERT(spdk_blob_get_num_clusters(snapshot2) == 5);
5587 : :
5588 : 30 : CU_ASSERT(snapshot2->parent_id == snapshotid);
5589 : :
5590 : : /* Write one cluster on the top level blob. This cluster (1) covers
5591 : : * already allocated cluster in the snapshot2, so shouldn't be inflated
5592 : : * at all */
5593 : 30 : spdk_blob_io_write(blob, channel, payload_write, io_units_per_cluster,
5594 : : io_units_per_cluster, blob_op_complete, NULL);
5595 : 30 : poll_threads();
5596 : 30 : CU_ASSERT(g_bserrno == 0);
5597 : :
5598 : : /* Update expected result */
5599 [ - + - + ]: 30 : memcpy(payload_clone + cluster_size, payload_write, cluster_size);
5600 : :
5601 : : /* Check data consistency on clone */
5602 [ - + ]: 30 : memset(payload_read, 0xFF, payload_size);
5603 : 30 : spdk_blob_io_read(blob, channel, payload_read, 0, io_units_per_payload,
5604 : : blob_op_complete, NULL);
5605 : 30 : poll_threads();
5606 : 30 : CU_ASSERT(g_bserrno == 0);
5607 [ - + - + ]: 30 : CU_ASSERT(memcmp(payload_clone, payload_read, payload_size) == 0);
5608 : :
5609 : :
5610 : : /* Close all blobs */
5611 : 30 : spdk_blob_close(blob, blob_op_complete, NULL);
5612 : 30 : poll_threads();
5613 : 30 : CU_ASSERT(g_bserrno == 0);
5614 : :
5615 : 30 : spdk_blob_close(snapshot2, blob_op_complete, NULL);
5616 : 30 : poll_threads();
5617 : 30 : CU_ASSERT(g_bserrno == 0);
5618 : :
5619 : 30 : spdk_blob_close(snapshot, blob_op_complete, NULL);
5620 : 30 : poll_threads();
5621 : 30 : CU_ASSERT(g_bserrno == 0);
5622 : :
5623 : : /* Check snapshot-clone relations */
5624 : 30 : count = 2;
5625 : 30 : CU_ASSERT(spdk_blob_get_clones(bs, snapshotid, ids, &count) == 0);
5626 : 30 : CU_ASSERT(count == 1);
5627 : 30 : CU_ASSERT(ids[0] == snapshot2id);
5628 : :
5629 : 30 : count = 2;
5630 : 30 : CU_ASSERT(spdk_blob_get_clones(bs, snapshot2id, ids, &count) == 0);
5631 : 30 : CU_ASSERT(count == 1);
5632 : 30 : CU_ASSERT(ids[0] == blobid);
5633 : :
5634 : 30 : CU_ASSERT(spdk_blob_get_parent_snapshot(bs, blobid) == snapshot2id);
5635 : :
5636 : 30 : free_clusters = spdk_bs_free_cluster_count(bs);
5637 [ + + ]: 30 : if (!decouple_parent) {
5638 : : /* Do full blob inflation */
5639 : 15 : spdk_bs_inflate_blob(bs, channel, blobid, blob_op_complete, NULL);
5640 : 15 : poll_threads();
5641 : 15 : CU_ASSERT(g_bserrno == 0);
5642 : :
5643 : : /* All clusters should be inflated (except one already allocated
5644 : : * in a top level blob) */
5645 : 15 : CU_ASSERT(spdk_bs_free_cluster_count(bs) == free_clusters - 4);
5646 : :
5647 : : /* Check if relation tree updated correctly */
5648 : 15 : count = 2;
5649 : 15 : CU_ASSERT(spdk_blob_get_clones(bs, snapshotid, ids, &count) == 0);
5650 : :
5651 : : /* snapshotid have one clone */
5652 : 15 : CU_ASSERT(count == 1);
5653 : 15 : CU_ASSERT(ids[0] == snapshot2id);
5654 : :
5655 : : /* snapshot2id have no clones */
5656 : 15 : count = 2;
5657 : 15 : CU_ASSERT(spdk_blob_get_clones(bs, snapshot2id, ids, &count) == 0);
5658 : 15 : CU_ASSERT(count == 0);
5659 : :
5660 : 15 : CU_ASSERT(spdk_blob_get_parent_snapshot(bs, blobid) == SPDK_BLOBID_INVALID);
5661 : : } else {
5662 : : /* Decouple parent of blob */
5663 : 15 : spdk_bs_blob_decouple_parent(bs, channel, blobid, blob_op_complete, NULL);
5664 : 15 : poll_threads();
5665 : 15 : CU_ASSERT(g_bserrno == 0);
5666 : :
5667 : : /* Only one cluster from a parent should be inflated (second one
5668 : : * is covered by a cluster written on a top level blob, and
5669 : : * already allocated) */
5670 : 15 : CU_ASSERT(spdk_bs_free_cluster_count(bs) == free_clusters - 1);
5671 : :
5672 : : /* Check if relation tree updated correctly */
5673 : 15 : count = 2;
5674 : 15 : CU_ASSERT(spdk_blob_get_clones(bs, snapshotid, ids, &count) == 0);
5675 : :
5676 : : /* snapshotid have two clones now */
5677 : 15 : CU_ASSERT(count == 2);
5678 [ + - + - ]: 15 : CU_ASSERT(ids[0] == blobid || ids[1] == blobid);
5679 [ - + - - ]: 15 : CU_ASSERT(ids[0] == snapshot2id || ids[1] == snapshot2id);
5680 : :
5681 : : /* snapshot2id have no clones */
5682 : 15 : count = 2;
5683 : 15 : CU_ASSERT(spdk_blob_get_clones(bs, snapshot2id, ids, &count) == 0);
5684 : 15 : CU_ASSERT(count == 0);
5685 : :
5686 : 15 : CU_ASSERT(spdk_blob_get_parent_snapshot(bs, blobid) == snapshotid);
5687 : : }
5688 : :
5689 : : /* Try to delete snapshot2 (should pass) */
5690 : 30 : spdk_bs_delete_blob(bs, snapshot2id, blob_op_complete, NULL);
5691 : 30 : poll_threads();
5692 : 30 : CU_ASSERT(g_bserrno == 0);
5693 : :
5694 : : /* Try to delete base snapshot */
5695 : 30 : spdk_bs_delete_blob(bs, snapshotid, blob_op_complete, NULL);
5696 : 30 : poll_threads();
5697 : 30 : CU_ASSERT(g_bserrno == 0);
5698 : :
5699 : : /* Reopen blob after snapshot deletion */
5700 : 30 : spdk_bs_open_blob(bs, blobid, blob_op_with_handle_complete, NULL);
5701 : 30 : poll_threads();
5702 : 30 : CU_ASSERT(g_bserrno == 0);
5703 [ - + ]: 30 : SPDK_CU_ASSERT_FATAL(g_blob != NULL);
5704 : 30 : blob = g_blob;
5705 : :
5706 : 30 : CU_ASSERT(spdk_blob_get_num_clusters(blob) == 5);
5707 : :
5708 : : /* Check data consistency on inflated blob */
5709 [ - + ]: 30 : memset(payload_read, 0xFF, payload_size);
5710 : 30 : spdk_blob_io_read(blob, channel, payload_read, 0, io_units_per_payload,
5711 : : blob_op_complete, NULL);
5712 : 30 : poll_threads();
5713 : 30 : CU_ASSERT(g_bserrno == 0);
5714 [ - + - + ]: 30 : CU_ASSERT(memcmp(payload_clone, payload_read, payload_size) == 0);
5715 : :
5716 : 30 : spdk_bs_free_io_channel(channel);
5717 : 30 : poll_threads();
5718 : :
5719 : 30 : free(payload_read);
5720 : 30 : free(payload_write);
5721 : 30 : free(payload_clone);
5722 : :
5723 : 30 : ut_blob_close_and_delete(bs, blob);
5724 : 30 : }
5725 : :
5726 : : static void
5727 : 15 : blob_inflate_rw(void)
5728 : : {
5729 : 15 : _blob_inflate_rw(false);
5730 : 15 : _blob_inflate_rw(true);
5731 : 15 : }
5732 : :
5733 : : /**
5734 : : * Snapshot-clones relation test
5735 : : *
5736 : : * snapshot
5737 : : * |
5738 : : * +-----+-----+
5739 : : * | |
5740 : : * blob(ro) snapshot2
5741 : : * | |
5742 : : * clone2 clone
5743 : : */
5744 : : static void
5745 : 15 : blob_relations(void)
5746 : : {
5747 : 15 : struct spdk_blob_store *bs;
5748 : : struct spdk_bs_dev *dev;
5749 : 15 : struct spdk_bs_opts bs_opts;
5750 : 15 : struct spdk_blob_opts opts;
5751 : : struct spdk_blob *blob, *snapshot, *snapshot2, *clone, *clone2;
5752 : : spdk_blob_id blobid, cloneid, snapshotid, cloneid2, snapshotid2;
5753 : : int rc;
5754 : 15 : size_t count;
5755 : 15 : spdk_blob_id ids[10] = {};
5756 : :
5757 : 15 : dev = init_dev();
5758 : 15 : spdk_bs_opts_init(&bs_opts, sizeof(bs_opts));
5759 [ - + ]: 15 : snprintf(bs_opts.bstype.bstype, sizeof(bs_opts.bstype.bstype), "TESTTYPE");
5760 : :
5761 : 15 : spdk_bs_init(dev, &bs_opts, bs_op_with_handle_complete, NULL);
5762 : 15 : poll_threads();
5763 : 15 : CU_ASSERT(g_bserrno == 0);
5764 [ - + ]: 15 : SPDK_CU_ASSERT_FATAL(g_bs != NULL);
5765 : 15 : bs = g_bs;
5766 : :
5767 : : /* 1. Create blob with 10 clusters */
5768 : :
5769 : 15 : ut_spdk_blob_opts_init(&opts);
5770 : 15 : opts.num_clusters = 10;
5771 : :
5772 : 15 : blob = ut_blob_create_and_open(bs, &opts);
5773 : 15 : blobid = spdk_blob_get_id(blob);
5774 : :
5775 : 15 : CU_ASSERT(!spdk_blob_is_read_only(blob));
5776 : 15 : CU_ASSERT(!spdk_blob_is_snapshot(blob));
5777 : 15 : CU_ASSERT(!spdk_blob_is_clone(blob));
5778 : 15 : CU_ASSERT(!spdk_blob_is_thin_provisioned(blob));
5779 : :
5780 : : /* blob should not have underlying snapshot nor clones */
5781 : 15 : CU_ASSERT(blob->parent_id == SPDK_BLOBID_INVALID);
5782 : 15 : CU_ASSERT(spdk_blob_get_parent_snapshot(bs, blobid) == SPDK_BLOBID_INVALID);
5783 : 15 : count = SPDK_COUNTOF(ids);
5784 : 15 : rc = spdk_blob_get_clones(bs, blobid, ids, &count);
5785 : 15 : CU_ASSERT(rc == 0);
5786 : 15 : CU_ASSERT(count == 0);
5787 : :
5788 : :
5789 : : /* 2. Create snapshot */
5790 : :
5791 : 15 : spdk_bs_create_snapshot(bs, blobid, NULL, blob_op_with_id_complete, NULL);
5792 : 15 : poll_threads();
5793 : 15 : CU_ASSERT(g_bserrno == 0);
5794 : 15 : CU_ASSERT(g_blobid != SPDK_BLOBID_INVALID);
5795 : 15 : snapshotid = g_blobid;
5796 : :
5797 : 15 : spdk_bs_open_blob(bs, snapshotid, blob_op_with_handle_complete, NULL);
5798 : 15 : poll_threads();
5799 : 15 : CU_ASSERT(g_bserrno == 0);
5800 [ - + ]: 15 : SPDK_CU_ASSERT_FATAL(g_blob != NULL);
5801 : 15 : snapshot = g_blob;
5802 : :
5803 : 15 : CU_ASSERT(spdk_blob_is_read_only(snapshot));
5804 : 15 : CU_ASSERT(spdk_blob_is_snapshot(snapshot));
5805 : 15 : CU_ASSERT(!spdk_blob_is_clone(snapshot));
5806 : 15 : CU_ASSERT(snapshot->parent_id == SPDK_BLOBID_INVALID);
5807 : 15 : CU_ASSERT(spdk_blob_get_parent_snapshot(bs, snapshotid) == SPDK_BLOBID_INVALID);
5808 : :
5809 : : /* Check if original blob is converted to the clone of snapshot */
5810 : 15 : CU_ASSERT(!spdk_blob_is_read_only(blob));
5811 : 15 : CU_ASSERT(!spdk_blob_is_snapshot(blob));
5812 : 15 : CU_ASSERT(spdk_blob_is_clone(blob));
5813 : 15 : CU_ASSERT(spdk_blob_is_thin_provisioned(blob));
5814 : 15 : CU_ASSERT(blob->parent_id == snapshotid);
5815 : 15 : CU_ASSERT(spdk_blob_get_parent_snapshot(bs, blobid) == snapshotid);
5816 : :
5817 : 15 : count = SPDK_COUNTOF(ids);
5818 : 15 : rc = spdk_blob_get_clones(bs, snapshotid, ids, &count);
5819 : 15 : CU_ASSERT(rc == 0);
5820 : 15 : CU_ASSERT(count == 1);
5821 : 15 : CU_ASSERT(ids[0] == blobid);
5822 : :
5823 : :
5824 : : /* 3. Create clone from snapshot */
5825 : :
5826 : 15 : spdk_bs_create_clone(bs, snapshotid, NULL, blob_op_with_id_complete, NULL);
5827 : 15 : poll_threads();
5828 : 15 : CU_ASSERT(g_bserrno == 0);
5829 : 15 : CU_ASSERT(g_blobid != SPDK_BLOBID_INVALID);
5830 : 15 : cloneid = g_blobid;
5831 : :
5832 : 15 : spdk_bs_open_blob(bs, cloneid, blob_op_with_handle_complete, NULL);
5833 : 15 : poll_threads();
5834 : 15 : CU_ASSERT(g_bserrno == 0);
5835 [ - + ]: 15 : SPDK_CU_ASSERT_FATAL(g_blob != NULL);
5836 : 15 : clone = g_blob;
5837 : :
5838 : 15 : CU_ASSERT(!spdk_blob_is_read_only(clone));
5839 : 15 : CU_ASSERT(!spdk_blob_is_snapshot(clone));
5840 : 15 : CU_ASSERT(spdk_blob_is_clone(clone));
5841 : 15 : CU_ASSERT(spdk_blob_is_thin_provisioned(clone));
5842 : 15 : CU_ASSERT(clone->parent_id == snapshotid);
5843 : 15 : CU_ASSERT(spdk_blob_get_parent_snapshot(bs, cloneid) == snapshotid);
5844 : :
5845 : 15 : count = SPDK_COUNTOF(ids);
5846 : 15 : rc = spdk_blob_get_clones(bs, cloneid, ids, &count);
5847 : 15 : CU_ASSERT(rc == 0);
5848 : 15 : CU_ASSERT(count == 0);
5849 : :
5850 : : /* Check if clone is on the snapshot's list */
5851 : 15 : count = SPDK_COUNTOF(ids);
5852 : 15 : rc = spdk_blob_get_clones(bs, snapshotid, ids, &count);
5853 : 15 : CU_ASSERT(rc == 0);
5854 [ - + - - ]: 15 : CU_ASSERT(ids[0] == blobid || ids[1] == blobid);
5855 [ + - + - ]: 15 : CU_ASSERT(ids[0] == cloneid || ids[1] == cloneid);
5856 : :
5857 : :
5858 : : /* 4. Create snapshot of the clone */
5859 : :
5860 : 15 : spdk_bs_create_snapshot(bs, cloneid, NULL, blob_op_with_id_complete, NULL);
5861 : 15 : poll_threads();
5862 : 15 : CU_ASSERT(g_bserrno == 0);
5863 : 15 : CU_ASSERT(g_blobid != SPDK_BLOBID_INVALID);
5864 : 15 : snapshotid2 = g_blobid;
5865 : :
5866 : 15 : spdk_bs_open_blob(bs, snapshotid2, blob_op_with_handle_complete, NULL);
5867 : 15 : poll_threads();
5868 : 15 : CU_ASSERT(g_bserrno == 0);
5869 [ - + ]: 15 : SPDK_CU_ASSERT_FATAL(g_blob != NULL);
5870 : 15 : snapshot2 = g_blob;
5871 : :
5872 : 15 : CU_ASSERT(spdk_blob_is_read_only(snapshot2));
5873 : 15 : CU_ASSERT(spdk_blob_is_snapshot(snapshot2));
5874 : 15 : CU_ASSERT(spdk_blob_is_clone(snapshot2));
5875 : 15 : CU_ASSERT(snapshot2->parent_id == snapshotid);
5876 : 15 : CU_ASSERT(spdk_blob_get_parent_snapshot(bs, snapshotid2) == snapshotid);
5877 : :
5878 : : /* Check if clone is converted to the clone of snapshot2 and snapshot2
5879 : : * is a child of snapshot */
5880 : 15 : CU_ASSERT(!spdk_blob_is_read_only(clone));
5881 : 15 : CU_ASSERT(!spdk_blob_is_snapshot(clone));
5882 : 15 : CU_ASSERT(spdk_blob_is_clone(clone));
5883 : 15 : CU_ASSERT(spdk_blob_is_thin_provisioned(clone));
5884 : 15 : CU_ASSERT(clone->parent_id == snapshotid2);
5885 : 15 : CU_ASSERT(spdk_blob_get_parent_snapshot(bs, cloneid) == snapshotid2);
5886 : :
5887 : 15 : count = SPDK_COUNTOF(ids);
5888 : 15 : rc = spdk_blob_get_clones(bs, snapshotid2, ids, &count);
5889 : 15 : CU_ASSERT(rc == 0);
5890 : 15 : CU_ASSERT(count == 1);
5891 : 15 : CU_ASSERT(ids[0] == cloneid);
5892 : :
5893 : :
5894 : : /* 5. Try to create clone from read only blob */
5895 : :
5896 : : /* Mark blob as read only */
5897 : 15 : spdk_blob_set_read_only(blob);
5898 : 15 : spdk_blob_sync_md(blob, blob_op_complete, NULL);
5899 : 15 : poll_threads();
5900 : 15 : CU_ASSERT(g_bserrno == 0);
5901 : :
5902 : : /* Check if previously created blob is read only clone */
5903 : 15 : CU_ASSERT(spdk_blob_is_read_only(blob));
5904 : 15 : CU_ASSERT(!spdk_blob_is_snapshot(blob));
5905 : 15 : CU_ASSERT(spdk_blob_is_clone(blob));
5906 : 15 : CU_ASSERT(spdk_blob_is_thin_provisioned(blob));
5907 : :
5908 : : /* Create clone from read only blob */
5909 : 15 : spdk_bs_create_clone(bs, blobid, NULL, blob_op_with_id_complete, NULL);
5910 : 15 : poll_threads();
5911 : 15 : CU_ASSERT(g_bserrno == 0);
5912 : 15 : CU_ASSERT(g_blobid != SPDK_BLOBID_INVALID);
5913 : 15 : cloneid2 = g_blobid;
5914 : :
5915 : 15 : spdk_bs_open_blob(bs, cloneid2, blob_op_with_handle_complete, NULL);
5916 : 15 : poll_threads();
5917 : 15 : CU_ASSERT(g_bserrno == 0);
5918 [ - + ]: 15 : SPDK_CU_ASSERT_FATAL(g_blob != NULL);
5919 : 15 : clone2 = g_blob;
5920 : :
5921 : 15 : CU_ASSERT(!spdk_blob_is_read_only(clone2));
5922 : 15 : CU_ASSERT(!spdk_blob_is_snapshot(clone2));
5923 : 15 : CU_ASSERT(spdk_blob_is_clone(clone2));
5924 : 15 : CU_ASSERT(spdk_blob_is_thin_provisioned(clone2));
5925 : :
5926 : 15 : CU_ASSERT(spdk_blob_get_parent_snapshot(bs, cloneid2) == blobid);
5927 : :
5928 : 15 : count = SPDK_COUNTOF(ids);
5929 : 15 : rc = spdk_blob_get_clones(bs, blobid, ids, &count);
5930 : 15 : CU_ASSERT(rc == 0);
5931 : :
5932 : 15 : CU_ASSERT(count == 1);
5933 : 15 : CU_ASSERT(ids[0] == cloneid2);
5934 : :
5935 : : /* Close blobs */
5936 : :
5937 : 15 : spdk_blob_close(clone2, blob_op_complete, NULL);
5938 : 15 : poll_threads();
5939 : 15 : CU_ASSERT(g_bserrno == 0);
5940 : :
5941 : 15 : spdk_blob_close(blob, blob_op_complete, NULL);
5942 : 15 : poll_threads();
5943 : 15 : CU_ASSERT(g_bserrno == 0);
5944 : :
5945 : 15 : spdk_blob_close(clone, blob_op_complete, NULL);
5946 : 15 : poll_threads();
5947 : 15 : CU_ASSERT(g_bserrno == 0);
5948 : :
5949 : 15 : spdk_blob_close(snapshot, blob_op_complete, NULL);
5950 : 15 : poll_threads();
5951 : 15 : CU_ASSERT(g_bserrno == 0);
5952 : :
5953 : 15 : spdk_blob_close(snapshot2, blob_op_complete, NULL);
5954 : 15 : poll_threads();
5955 : 15 : CU_ASSERT(g_bserrno == 0);
5956 : :
5957 : : /* Try to delete snapshot with more than 1 clone */
5958 : 15 : spdk_bs_delete_blob(bs, snapshotid, blob_op_complete, NULL);
5959 : 15 : poll_threads();
5960 : 15 : CU_ASSERT(g_bserrno != 0);
5961 : :
5962 : 15 : ut_bs_reload(&bs, &bs_opts);
5963 : :
5964 : : /* NULL ids array should return number of clones in count */
5965 : 15 : count = SPDK_COUNTOF(ids);
5966 : 15 : rc = spdk_blob_get_clones(bs, snapshotid, NULL, &count);
5967 : 15 : CU_ASSERT(rc == -ENOMEM);
5968 : 15 : CU_ASSERT(count == 2);
5969 : :
5970 : : /* incorrect array size */
5971 : 15 : count = 1;
5972 : 15 : rc = spdk_blob_get_clones(bs, snapshotid, ids, &count);
5973 : 15 : CU_ASSERT(rc == -ENOMEM);
5974 : 15 : CU_ASSERT(count == 2);
5975 : :
5976 : :
5977 : : /* Verify structure of loaded blob store */
5978 : :
5979 : : /* snapshot */
5980 : 15 : CU_ASSERT(spdk_blob_get_parent_snapshot(bs, snapshotid) == SPDK_BLOBID_INVALID);
5981 : :
5982 : 15 : count = SPDK_COUNTOF(ids);
5983 : 15 : rc = spdk_blob_get_clones(bs, snapshotid, ids, &count);
5984 : 15 : CU_ASSERT(rc == 0);
5985 : 15 : CU_ASSERT(count == 2);
5986 [ - + - - ]: 15 : CU_ASSERT(ids[0] == blobid || ids[1] == blobid);
5987 [ + - + - ]: 15 : CU_ASSERT(ids[0] == snapshotid2 || ids[1] == snapshotid2);
5988 : :
5989 : : /* blob */
5990 : 15 : CU_ASSERT(spdk_blob_get_parent_snapshot(bs, blobid) == snapshotid);
5991 : 15 : count = SPDK_COUNTOF(ids);
5992 : 15 : rc = spdk_blob_get_clones(bs, blobid, ids, &count);
5993 : 15 : CU_ASSERT(rc == 0);
5994 : 15 : CU_ASSERT(count == 1);
5995 : 15 : CU_ASSERT(ids[0] == cloneid2);
5996 : :
5997 : : /* clone */
5998 : 15 : CU_ASSERT(spdk_blob_get_parent_snapshot(bs, cloneid) == snapshotid2);
5999 : 15 : count = SPDK_COUNTOF(ids);
6000 : 15 : rc = spdk_blob_get_clones(bs, cloneid, ids, &count);
6001 : 15 : CU_ASSERT(rc == 0);
6002 : 15 : CU_ASSERT(count == 0);
6003 : :
6004 : : /* snapshot2 */
6005 : 15 : CU_ASSERT(spdk_blob_get_parent_snapshot(bs, snapshotid2) == snapshotid);
6006 : 15 : count = SPDK_COUNTOF(ids);
6007 : 15 : rc = spdk_blob_get_clones(bs, snapshotid2, ids, &count);
6008 : 15 : CU_ASSERT(rc == 0);
6009 : 15 : CU_ASSERT(count == 1);
6010 : 15 : CU_ASSERT(ids[0] == cloneid);
6011 : :
6012 : : /* clone2 */
6013 : 15 : CU_ASSERT(spdk_blob_get_parent_snapshot(bs, cloneid2) == blobid);
6014 : 15 : count = SPDK_COUNTOF(ids);
6015 : 15 : rc = spdk_blob_get_clones(bs, cloneid2, ids, &count);
6016 : 15 : CU_ASSERT(rc == 0);
6017 : 15 : CU_ASSERT(count == 0);
6018 : :
6019 : : /* Try to delete blob that user should not be able to remove */
6020 : :
6021 : 15 : spdk_bs_delete_blob(bs, snapshotid, blob_op_complete, NULL);
6022 : 15 : poll_threads();
6023 : 15 : CU_ASSERT(g_bserrno != 0);
6024 : :
6025 : : /* Remove all blobs */
6026 : :
6027 : 15 : spdk_bs_delete_blob(bs, cloneid, blob_op_complete, NULL);
6028 : 15 : poll_threads();
6029 : 15 : CU_ASSERT(g_bserrno == 0);
6030 : :
6031 : 15 : spdk_bs_delete_blob(bs, snapshotid2, blob_op_complete, NULL);
6032 : 15 : poll_threads();
6033 : 15 : CU_ASSERT(g_bserrno == 0);
6034 : :
6035 : 15 : spdk_bs_delete_blob(bs, cloneid2, blob_op_complete, NULL);
6036 : 15 : poll_threads();
6037 : 15 : CU_ASSERT(g_bserrno == 0);
6038 : :
6039 : 15 : spdk_bs_delete_blob(bs, blobid, blob_op_complete, NULL);
6040 : 15 : poll_threads();
6041 : 15 : CU_ASSERT(g_bserrno == 0);
6042 : :
6043 : 15 : spdk_bs_delete_blob(bs, snapshotid, blob_op_complete, NULL);
6044 : 15 : poll_threads();
6045 : 15 : CU_ASSERT(g_bserrno == 0);
6046 : :
6047 : 15 : spdk_bs_unload(bs, bs_op_complete, NULL);
6048 : 15 : poll_threads();
6049 : 15 : CU_ASSERT(g_bserrno == 0);
6050 : :
6051 : 15 : g_bs = NULL;
6052 : 15 : }
6053 : :
6054 : : /**
6055 : : * Snapshot-clones relation test 2
6056 : : *
6057 : : * snapshot1
6058 : : * |
6059 : : * snapshot2
6060 : : * |
6061 : : * +-----+-----+
6062 : : * | |
6063 : : * blob(ro) snapshot3
6064 : : * | |
6065 : : * | snapshot4
6066 : : * | | |
6067 : : * clone2 clone clone3
6068 : : */
6069 : : static void
6070 : 15 : blob_relations2(void)
6071 : : {
6072 : 15 : struct spdk_blob_store *bs;
6073 : : struct spdk_bs_dev *dev;
6074 : 15 : struct spdk_bs_opts bs_opts;
6075 : 15 : struct spdk_blob_opts opts;
6076 : : struct spdk_blob *blob, *snapshot1, *snapshot2, *snapshot3, *snapshot4, *clone, *clone2;
6077 : : spdk_blob_id blobid, snapshotid1, snapshotid2, snapshotid3, snapshotid4, cloneid, cloneid2,
6078 : : cloneid3;
6079 : : int rc;
6080 : 15 : size_t count;
6081 : 15 : spdk_blob_id ids[10] = {};
6082 : :
6083 : 15 : dev = init_dev();
6084 : 15 : spdk_bs_opts_init(&bs_opts, sizeof(bs_opts));
6085 [ - + ]: 15 : snprintf(bs_opts.bstype.bstype, sizeof(bs_opts.bstype.bstype), "TESTTYPE");
6086 : :
6087 : 15 : spdk_bs_init(dev, &bs_opts, bs_op_with_handle_complete, NULL);
6088 : 15 : poll_threads();
6089 : 15 : CU_ASSERT(g_bserrno == 0);
6090 [ - + ]: 15 : SPDK_CU_ASSERT_FATAL(g_bs != NULL);
6091 : 15 : bs = g_bs;
6092 : :
6093 : : /* 1. Create blob with 10 clusters */
6094 : :
6095 : 15 : ut_spdk_blob_opts_init(&opts);
6096 : 15 : opts.num_clusters = 10;
6097 : :
6098 : 15 : blob = ut_blob_create_and_open(bs, &opts);
6099 : 15 : blobid = spdk_blob_get_id(blob);
6100 : :
6101 : : /* 2. Create snapshot1 */
6102 : :
6103 : 15 : spdk_bs_create_snapshot(bs, blobid, NULL, blob_op_with_id_complete, NULL);
6104 : 15 : poll_threads();
6105 : 15 : CU_ASSERT(g_bserrno == 0);
6106 : 15 : CU_ASSERT(g_blobid != SPDK_BLOBID_INVALID);
6107 : 15 : snapshotid1 = g_blobid;
6108 : :
6109 : 15 : spdk_bs_open_blob(bs, snapshotid1, blob_op_with_handle_complete, NULL);
6110 : 15 : poll_threads();
6111 : 15 : CU_ASSERT(g_bserrno == 0);
6112 [ - + ]: 15 : SPDK_CU_ASSERT_FATAL(g_blob != NULL);
6113 : 15 : snapshot1 = g_blob;
6114 : :
6115 : 15 : CU_ASSERT(snapshot1->parent_id == SPDK_BLOBID_INVALID);
6116 : 15 : CU_ASSERT(spdk_blob_get_parent_snapshot(bs, snapshotid1) == SPDK_BLOBID_INVALID);
6117 : :
6118 : 15 : CU_ASSERT(blob->parent_id == snapshotid1);
6119 : 15 : CU_ASSERT(spdk_blob_get_parent_snapshot(bs, blobid) == snapshotid1);
6120 : :
6121 : : /* Check if blob is the clone of snapshot1 */
6122 : 15 : CU_ASSERT(blob->parent_id == snapshotid1);
6123 : 15 : CU_ASSERT(spdk_blob_get_parent_snapshot(bs, blobid) == snapshotid1);
6124 : :
6125 : 15 : count = SPDK_COUNTOF(ids);
6126 : 15 : rc = spdk_blob_get_clones(bs, snapshotid1, ids, &count);
6127 : 15 : CU_ASSERT(rc == 0);
6128 : 15 : CU_ASSERT(count == 1);
6129 : 15 : CU_ASSERT(ids[0] == blobid);
6130 : :
6131 : : /* 3. Create another snapshot */
6132 : :
6133 : 15 : spdk_bs_create_snapshot(bs, blobid, NULL, blob_op_with_id_complete, NULL);
6134 : 15 : poll_threads();
6135 : 15 : CU_ASSERT(g_bserrno == 0);
6136 : 15 : CU_ASSERT(g_blobid != SPDK_BLOBID_INVALID);
6137 : 15 : snapshotid2 = g_blobid;
6138 : :
6139 : 15 : spdk_bs_open_blob(bs, snapshotid2, blob_op_with_handle_complete, NULL);
6140 : 15 : poll_threads();
6141 : 15 : CU_ASSERT(g_bserrno == 0);
6142 [ - + ]: 15 : SPDK_CU_ASSERT_FATAL(g_blob != NULL);
6143 : 15 : snapshot2 = g_blob;
6144 : :
6145 : 15 : CU_ASSERT(spdk_blob_is_clone(snapshot2));
6146 : 15 : CU_ASSERT(snapshot2->parent_id == snapshotid1);
6147 : 15 : CU_ASSERT(spdk_blob_get_parent_snapshot(bs, snapshotid2) == snapshotid1);
6148 : :
6149 : : /* Check if snapshot2 is the clone of snapshot1 and blob
6150 : : * is a child of snapshot2 */
6151 : 15 : CU_ASSERT(blob->parent_id == snapshotid2);
6152 : 15 : CU_ASSERT(spdk_blob_get_parent_snapshot(bs, blobid) == snapshotid2);
6153 : :
6154 : 15 : count = SPDK_COUNTOF(ids);
6155 : 15 : rc = spdk_blob_get_clones(bs, snapshotid2, ids, &count);
6156 : 15 : CU_ASSERT(rc == 0);
6157 : 15 : CU_ASSERT(count == 1);
6158 : 15 : CU_ASSERT(ids[0] == blobid);
6159 : :
6160 : : /* 4. Create clone from snapshot */
6161 : :
6162 : 15 : spdk_bs_create_clone(bs, snapshotid2, NULL, blob_op_with_id_complete, NULL);
6163 : 15 : poll_threads();
6164 : 15 : CU_ASSERT(g_bserrno == 0);
6165 : 15 : CU_ASSERT(g_blobid != SPDK_BLOBID_INVALID);
6166 : 15 : cloneid = g_blobid;
6167 : :
6168 : 15 : spdk_bs_open_blob(bs, cloneid, blob_op_with_handle_complete, NULL);
6169 : 15 : poll_threads();
6170 : 15 : CU_ASSERT(g_bserrno == 0);
6171 [ - + ]: 15 : SPDK_CU_ASSERT_FATAL(g_blob != NULL);
6172 : 15 : clone = g_blob;
6173 : :
6174 : 15 : CU_ASSERT(clone->parent_id == snapshotid2);
6175 : 15 : CU_ASSERT(spdk_blob_get_parent_snapshot(bs, cloneid) == snapshotid2);
6176 : :
6177 : : /* Check if clone is on the snapshot's list */
6178 : 15 : count = SPDK_COUNTOF(ids);
6179 : 15 : rc = spdk_blob_get_clones(bs, snapshotid2, ids, &count);
6180 : 15 : CU_ASSERT(rc == 0);
6181 : 15 : CU_ASSERT(count == 2);
6182 [ - + - - ]: 15 : CU_ASSERT(ids[0] == blobid || ids[1] == blobid);
6183 [ + - + - ]: 15 : CU_ASSERT(ids[0] == cloneid || ids[1] == cloneid);
6184 : :
6185 : : /* 5. Create snapshot of the clone */
6186 : :
6187 : 15 : spdk_bs_create_snapshot(bs, cloneid, NULL, blob_op_with_id_complete, NULL);
6188 : 15 : poll_threads();
6189 : 15 : CU_ASSERT(g_bserrno == 0);
6190 : 15 : CU_ASSERT(g_blobid != SPDK_BLOBID_INVALID);
6191 : 15 : snapshotid3 = g_blobid;
6192 : :
6193 : 15 : spdk_bs_open_blob(bs, snapshotid3, blob_op_with_handle_complete, NULL);
6194 : 15 : poll_threads();
6195 : 15 : CU_ASSERT(g_bserrno == 0);
6196 [ - + ]: 15 : SPDK_CU_ASSERT_FATAL(g_blob != NULL);
6197 : 15 : snapshot3 = g_blob;
6198 : :
6199 : 15 : CU_ASSERT(snapshot3->parent_id == snapshotid2);
6200 : 15 : CU_ASSERT(spdk_blob_get_parent_snapshot(bs, snapshotid3) == snapshotid2);
6201 : :
6202 : : /* Check if clone is converted to the clone of snapshot3 and snapshot3
6203 : : * is a child of snapshot2 */
6204 : 15 : CU_ASSERT(clone->parent_id == snapshotid3);
6205 : 15 : CU_ASSERT(spdk_blob_get_parent_snapshot(bs, cloneid) == snapshotid3);
6206 : :
6207 : 15 : count = SPDK_COUNTOF(ids);
6208 : 15 : rc = spdk_blob_get_clones(bs, snapshotid3, ids, &count);
6209 : 15 : CU_ASSERT(rc == 0);
6210 : 15 : CU_ASSERT(count == 1);
6211 : 15 : CU_ASSERT(ids[0] == cloneid);
6212 : :
6213 : : /* 6. Create another snapshot of the clone */
6214 : :
6215 : 15 : spdk_bs_create_snapshot(bs, cloneid, NULL, blob_op_with_id_complete, NULL);
6216 : 15 : poll_threads();
6217 : 15 : CU_ASSERT(g_bserrno == 0);
6218 : 15 : CU_ASSERT(g_blobid != SPDK_BLOBID_INVALID);
6219 : 15 : snapshotid4 = g_blobid;
6220 : :
6221 : 15 : spdk_bs_open_blob(bs, snapshotid4, blob_op_with_handle_complete, NULL);
6222 : 15 : poll_threads();
6223 : 15 : CU_ASSERT(g_bserrno == 0);
6224 [ - + ]: 15 : SPDK_CU_ASSERT_FATAL(g_blob != NULL);
6225 : 15 : snapshot4 = g_blob;
6226 : :
6227 : 15 : CU_ASSERT(snapshot4->parent_id == snapshotid3);
6228 : 15 : CU_ASSERT(spdk_blob_get_parent_snapshot(bs, snapshotid4) == snapshotid3);
6229 : :
6230 : : /* Check if clone is converted to the clone of snapshot4 and snapshot4
6231 : : * is a child of snapshot3 */
6232 : 15 : CU_ASSERT(clone->parent_id == snapshotid4);
6233 : 15 : CU_ASSERT(spdk_blob_get_parent_snapshot(bs, cloneid) == snapshotid4);
6234 : :
6235 : 15 : count = SPDK_COUNTOF(ids);
6236 : 15 : rc = spdk_blob_get_clones(bs, snapshotid4, ids, &count);
6237 : 15 : CU_ASSERT(rc == 0);
6238 : 15 : CU_ASSERT(count == 1);
6239 : 15 : CU_ASSERT(ids[0] == cloneid);
6240 : :
6241 : : /* 7. Remove snapshot 4 */
6242 : :
6243 : 15 : ut_blob_close_and_delete(bs, snapshot4);
6244 : :
6245 : : /* Check if relations are back to state from before creating snapshot 4 */
6246 : 15 : CU_ASSERT(clone->parent_id == snapshotid3);
6247 : 15 : CU_ASSERT(spdk_blob_get_parent_snapshot(bs, cloneid) == snapshotid3);
6248 : :
6249 : 15 : count = SPDK_COUNTOF(ids);
6250 : 15 : rc = spdk_blob_get_clones(bs, snapshotid3, ids, &count);
6251 : 15 : CU_ASSERT(rc == 0);
6252 : 15 : CU_ASSERT(count == 1);
6253 : 15 : CU_ASSERT(ids[0] == cloneid);
6254 : :
6255 : : /* 8. Create second clone of snapshot 3 and try to remove snapshot 3 */
6256 : :
6257 : 15 : spdk_bs_create_clone(bs, snapshotid3, NULL, blob_op_with_id_complete, NULL);
6258 : 15 : poll_threads();
6259 : 15 : CU_ASSERT(g_bserrno == 0);
6260 : 15 : CU_ASSERT(g_blobid != SPDK_BLOBID_INVALID);
6261 : 15 : cloneid3 = g_blobid;
6262 : :
6263 : 15 : spdk_bs_delete_blob(bs, snapshotid3, blob_op_complete, NULL);
6264 : 15 : poll_threads();
6265 : 15 : CU_ASSERT(g_bserrno != 0);
6266 : :
6267 : : /* 9. Open snapshot 3 again and try to remove it while clone 3 is closed */
6268 : :
6269 : 15 : spdk_bs_open_blob(bs, snapshotid3, blob_op_with_handle_complete, NULL);
6270 : 15 : poll_threads();
6271 : 15 : CU_ASSERT(g_bserrno == 0);
6272 [ - + ]: 15 : SPDK_CU_ASSERT_FATAL(g_blob != NULL);
6273 : 15 : snapshot3 = g_blob;
6274 : :
6275 : 15 : spdk_bs_delete_blob(bs, snapshotid3, blob_op_complete, NULL);
6276 : 15 : poll_threads();
6277 : 15 : CU_ASSERT(g_bserrno != 0);
6278 : :
6279 : 15 : spdk_blob_close(snapshot3, blob_op_complete, NULL);
6280 : 15 : poll_threads();
6281 : 15 : CU_ASSERT(g_bserrno == 0);
6282 : :
6283 : 15 : spdk_bs_delete_blob(bs, cloneid3, blob_op_complete, NULL);
6284 : 15 : poll_threads();
6285 : 15 : CU_ASSERT(g_bserrno == 0);
6286 : :
6287 : : /* 10. Remove snapshot 1 */
6288 : :
6289 : : /* Check snapshot 1 and snapshot 2 allocated clusters */
6290 : 15 : CU_ASSERT(spdk_blob_get_num_allocated_clusters(snapshot1) == 10);
6291 : 15 : CU_ASSERT(spdk_blob_get_num_allocated_clusters(snapshot2) == 0);
6292 : :
6293 : 15 : ut_blob_close_and_delete(bs, snapshot1);
6294 : :
6295 : : /* Check if relations are back to state from before creating snapshot 4 (before step 6) */
6296 : 15 : CU_ASSERT(snapshot2->parent_id == SPDK_BLOBID_INVALID);
6297 : 15 : CU_ASSERT(spdk_blob_get_parent_snapshot(bs, snapshotid2) == SPDK_BLOBID_INVALID);
6298 : :
6299 : : /* Check that snapshot 2 has the clusters that were allocated to snapshot 1 */
6300 : 15 : CU_ASSERT(spdk_blob_get_num_allocated_clusters(snapshot2) == 10);
6301 : :
6302 : 15 : count = SPDK_COUNTOF(ids);
6303 : 15 : rc = spdk_blob_get_clones(bs, snapshotid2, ids, &count);
6304 : 15 : CU_ASSERT(rc == 0);
6305 : 15 : CU_ASSERT(count == 2);
6306 [ - + - - ]: 15 : CU_ASSERT(ids[0] == blobid || ids[1] == blobid);
6307 [ + - + - ]: 15 : CU_ASSERT(ids[0] == snapshotid3 || ids[1] == snapshotid3);
6308 : :
6309 : : /* 11. Try to create clone from read only blob */
6310 : :
6311 : : /* Mark blob as read only */
6312 : 15 : spdk_blob_set_read_only(blob);
6313 : 15 : spdk_blob_sync_md(blob, blob_op_complete, NULL);
6314 : 15 : poll_threads();
6315 : 15 : CU_ASSERT(g_bserrno == 0);
6316 : :
6317 : : /* Create clone from read only blob */
6318 : 15 : spdk_bs_create_clone(bs, blobid, NULL, blob_op_with_id_complete, NULL);
6319 : 15 : poll_threads();
6320 : 15 : CU_ASSERT(g_bserrno == 0);
6321 : 15 : CU_ASSERT(g_blobid != SPDK_BLOBID_INVALID);
6322 : 15 : cloneid2 = g_blobid;
6323 : :
6324 : 15 : spdk_bs_open_blob(bs, cloneid2, blob_op_with_handle_complete, NULL);
6325 : 15 : poll_threads();
6326 : 15 : CU_ASSERT(g_bserrno == 0);
6327 [ - + ]: 15 : SPDK_CU_ASSERT_FATAL(g_blob != NULL);
6328 : 15 : clone2 = g_blob;
6329 : :
6330 : 15 : CU_ASSERT(spdk_blob_get_parent_snapshot(bs, cloneid2) == blobid);
6331 : :
6332 : 15 : count = SPDK_COUNTOF(ids);
6333 : 15 : rc = spdk_blob_get_clones(bs, blobid, ids, &count);
6334 : 15 : CU_ASSERT(rc == 0);
6335 : 15 : CU_ASSERT(count == 1);
6336 : 15 : CU_ASSERT(ids[0] == cloneid2);
6337 : :
6338 : : /* Close blobs */
6339 : :
6340 : 15 : spdk_blob_close(clone2, blob_op_complete, NULL);
6341 : 15 : poll_threads();
6342 : 15 : CU_ASSERT(g_bserrno == 0);
6343 : :
6344 : 15 : spdk_blob_close(blob, blob_op_complete, NULL);
6345 : 15 : poll_threads();
6346 : 15 : CU_ASSERT(g_bserrno == 0);
6347 : :
6348 : 15 : spdk_blob_close(clone, blob_op_complete, NULL);
6349 : 15 : poll_threads();
6350 : 15 : CU_ASSERT(g_bserrno == 0);
6351 : :
6352 : 15 : spdk_blob_close(snapshot2, blob_op_complete, NULL);
6353 : 15 : poll_threads();
6354 : 15 : CU_ASSERT(g_bserrno == 0);
6355 : :
6356 : 15 : spdk_blob_close(snapshot3, blob_op_complete, NULL);
6357 : 15 : poll_threads();
6358 : 15 : CU_ASSERT(g_bserrno == 0);
6359 : :
6360 : 15 : ut_bs_reload(&bs, &bs_opts);
6361 : :
6362 : : /* Verify structure of loaded blob store */
6363 : :
6364 : : /* snapshot2 */
6365 : 15 : CU_ASSERT(spdk_blob_get_parent_snapshot(bs, snapshotid2) == SPDK_BLOBID_INVALID);
6366 : :
6367 : 15 : count = SPDK_COUNTOF(ids);
6368 : 15 : rc = spdk_blob_get_clones(bs, snapshotid2, ids, &count);
6369 : 15 : CU_ASSERT(rc == 0);
6370 : 15 : CU_ASSERT(count == 2);
6371 [ - + - - ]: 15 : CU_ASSERT(ids[0] == blobid || ids[1] == blobid);
6372 [ + - + - ]: 15 : CU_ASSERT(ids[0] == snapshotid3 || ids[1] == snapshotid3);
6373 : :
6374 : : /* blob */
6375 : 15 : CU_ASSERT(spdk_blob_get_parent_snapshot(bs, blobid) == snapshotid2);
6376 : 15 : count = SPDK_COUNTOF(ids);
6377 : 15 : rc = spdk_blob_get_clones(bs, blobid, ids, &count);
6378 : 15 : CU_ASSERT(rc == 0);
6379 : 15 : CU_ASSERT(count == 1);
6380 : 15 : CU_ASSERT(ids[0] == cloneid2);
6381 : :
6382 : : /* clone */
6383 : 15 : CU_ASSERT(spdk_blob_get_parent_snapshot(bs, cloneid) == snapshotid3);
6384 : 15 : count = SPDK_COUNTOF(ids);
6385 : 15 : rc = spdk_blob_get_clones(bs, cloneid, ids, &count);
6386 : 15 : CU_ASSERT(rc == 0);
6387 : 15 : CU_ASSERT(count == 0);
6388 : :
6389 : : /* snapshot3 */
6390 : 15 : CU_ASSERT(spdk_blob_get_parent_snapshot(bs, snapshotid3) == snapshotid2);
6391 : 15 : count = SPDK_COUNTOF(ids);
6392 : 15 : rc = spdk_blob_get_clones(bs, snapshotid3, ids, &count);
6393 : 15 : CU_ASSERT(rc == 0);
6394 : 15 : CU_ASSERT(count == 1);
6395 : 15 : CU_ASSERT(ids[0] == cloneid);
6396 : :
6397 : : /* clone2 */
6398 : 15 : CU_ASSERT(spdk_blob_get_parent_snapshot(bs, cloneid2) == blobid);
6399 : 15 : count = SPDK_COUNTOF(ids);
6400 : 15 : rc = spdk_blob_get_clones(bs, cloneid2, ids, &count);
6401 : 15 : CU_ASSERT(rc == 0);
6402 : 15 : CU_ASSERT(count == 0);
6403 : :
6404 : : /* Try to delete all blobs in the worse possible order */
6405 : :
6406 : 15 : spdk_bs_delete_blob(bs, snapshotid2, blob_op_complete, NULL);
6407 : 15 : poll_threads();
6408 : 15 : CU_ASSERT(g_bserrno != 0);
6409 : :
6410 : 15 : spdk_bs_delete_blob(bs, snapshotid3, blob_op_complete, NULL);
6411 : 15 : poll_threads();
6412 : 15 : CU_ASSERT(g_bserrno == 0);
6413 : :
6414 : 15 : spdk_bs_delete_blob(bs, snapshotid2, blob_op_complete, NULL);
6415 : 15 : poll_threads();
6416 : 15 : CU_ASSERT(g_bserrno != 0);
6417 : :
6418 : 15 : spdk_bs_delete_blob(bs, cloneid, blob_op_complete, NULL);
6419 : 15 : poll_threads();
6420 : 15 : CU_ASSERT(g_bserrno == 0);
6421 : :
6422 : 15 : spdk_bs_delete_blob(bs, snapshotid2, blob_op_complete, NULL);
6423 : 15 : poll_threads();
6424 : 15 : CU_ASSERT(g_bserrno == 0);
6425 : :
6426 : 15 : spdk_bs_delete_blob(bs, blobid, blob_op_complete, NULL);
6427 : 15 : poll_threads();
6428 : 15 : CU_ASSERT(g_bserrno == 0);
6429 : :
6430 : 15 : spdk_bs_delete_blob(bs, cloneid2, blob_op_complete, NULL);
6431 : 15 : poll_threads();
6432 : 15 : CU_ASSERT(g_bserrno == 0);
6433 : :
6434 : 15 : spdk_bs_unload(bs, bs_op_complete, NULL);
6435 : 15 : poll_threads();
6436 : 15 : CU_ASSERT(g_bserrno == 0);
6437 : :
6438 : 15 : g_bs = NULL;
6439 : 15 : }
6440 : :
6441 : : /**
6442 : : * Snapshot-clones relation test 3
6443 : : *
6444 : : * snapshot0
6445 : : * |
6446 : : * snapshot1
6447 : : * |
6448 : : * snapshot2
6449 : : * |
6450 : : * blob
6451 : : */
6452 : : static void
6453 : 15 : blob_relations3(void)
6454 : : {
6455 : : struct spdk_blob_store *bs;
6456 : : struct spdk_bs_dev *dev;
6457 : : struct spdk_io_channel *channel;
6458 : 15 : struct spdk_bs_opts bs_opts;
6459 : 15 : struct spdk_blob_opts opts;
6460 : : struct spdk_blob *blob;
6461 : : spdk_blob_id blobid, snapshotid0, snapshotid1, snapshotid2;
6462 : :
6463 : 15 : dev = init_dev();
6464 : 15 : spdk_bs_opts_init(&bs_opts, sizeof(bs_opts));
6465 [ - + ]: 15 : snprintf(bs_opts.bstype.bstype, sizeof(bs_opts.bstype.bstype), "TESTTYPE");
6466 : :
6467 : 15 : spdk_bs_init(dev, &bs_opts, bs_op_with_handle_complete, NULL);
6468 : 15 : poll_threads();
6469 : 15 : CU_ASSERT(g_bserrno == 0);
6470 [ - + ]: 15 : SPDK_CU_ASSERT_FATAL(g_bs != NULL);
6471 : 15 : bs = g_bs;
6472 : :
6473 : 15 : channel = spdk_bs_alloc_io_channel(bs);
6474 [ - + ]: 15 : SPDK_CU_ASSERT_FATAL(channel != NULL);
6475 : :
6476 : : /* 1. Create blob with 10 clusters */
6477 : 15 : ut_spdk_blob_opts_init(&opts);
6478 : 15 : opts.num_clusters = 10;
6479 : :
6480 : 15 : blob = ut_blob_create_and_open(bs, &opts);
6481 : 15 : blobid = spdk_blob_get_id(blob);
6482 : :
6483 : : /* 2. Create snapshot0 */
6484 : 15 : spdk_bs_create_snapshot(bs, blobid, NULL, blob_op_with_id_complete, NULL);
6485 : 15 : poll_threads();
6486 : 15 : CU_ASSERT(g_bserrno == 0);
6487 : 15 : CU_ASSERT(g_blobid != SPDK_BLOBID_INVALID);
6488 : 15 : snapshotid0 = g_blobid;
6489 : :
6490 : : /* 3. Create snapshot1 */
6491 : 15 : spdk_bs_create_snapshot(bs, blobid, NULL, blob_op_with_id_complete, NULL);
6492 : 15 : poll_threads();
6493 : 15 : CU_ASSERT(g_bserrno == 0);
6494 : 15 : CU_ASSERT(g_blobid != SPDK_BLOBID_INVALID);
6495 : 15 : snapshotid1 = g_blobid;
6496 : :
6497 : : /* 4. Create snapshot2 */
6498 : 15 : spdk_bs_create_snapshot(bs, blobid, NULL, blob_op_with_id_complete, NULL);
6499 : 15 : poll_threads();
6500 : 15 : CU_ASSERT(g_bserrno == 0);
6501 : 15 : CU_ASSERT(g_blobid != SPDK_BLOBID_INVALID);
6502 : 15 : snapshotid2 = g_blobid;
6503 : :
6504 : : /* 5. Decouple blob */
6505 : 15 : spdk_bs_blob_decouple_parent(bs, channel, blobid, blob_op_complete, NULL);
6506 : 15 : poll_threads();
6507 : 15 : CU_ASSERT(g_bserrno == 0);
6508 : :
6509 : : /* 6. Decouple snapshot2. Make sure updating md of snapshot2 is possible */
6510 : 15 : spdk_bs_blob_decouple_parent(bs, channel, snapshotid2, blob_op_complete, NULL);
6511 : 15 : poll_threads();
6512 : 15 : CU_ASSERT(g_bserrno == 0);
6513 : :
6514 : : /* 7. Delete blob */
6515 : 15 : spdk_blob_close(blob, blob_op_complete, NULL);
6516 : 15 : poll_threads();
6517 : 15 : CU_ASSERT(g_bserrno == 0);
6518 : :
6519 : 15 : spdk_bs_delete_blob(bs, blobid, blob_op_complete, NULL);
6520 : 15 : poll_threads();
6521 : 15 : CU_ASSERT(g_bserrno == 0);
6522 : :
6523 : : /* 8. Delete snapshot2.
6524 : : * If md of snapshot 2 was updated, it should be possible to delete it */
6525 : 15 : spdk_bs_delete_blob(bs, snapshotid2, blob_op_complete, NULL);
6526 : 15 : poll_threads();
6527 : 15 : CU_ASSERT(g_bserrno == 0);
6528 : :
6529 : : /* Remove remaining blobs and unload bs */
6530 : 15 : spdk_bs_delete_blob(bs, snapshotid1, blob_op_complete, NULL);
6531 : 15 : poll_threads();
6532 : 15 : CU_ASSERT(g_bserrno == 0);
6533 : :
6534 : 15 : spdk_bs_delete_blob(bs, snapshotid0, blob_op_complete, NULL);
6535 : 15 : poll_threads();
6536 : 15 : CU_ASSERT(g_bserrno == 0);
6537 : :
6538 : 15 : spdk_bs_free_io_channel(channel);
6539 : 15 : poll_threads();
6540 : :
6541 : 15 : spdk_bs_unload(bs, bs_op_complete, NULL);
6542 : 15 : poll_threads();
6543 : 15 : CU_ASSERT(g_bserrno == 0);
6544 : :
6545 : 15 : g_bs = NULL;
6546 : 15 : }
6547 : :
6548 : : static void
6549 : 15 : blobstore_clean_power_failure(void)
6550 : : {
6551 : : struct spdk_blob_store *bs;
6552 : : struct spdk_blob *blob;
6553 : 15 : struct spdk_power_failure_thresholds thresholds = {};
6554 : 15 : bool clean = false;
6555 : 15 : struct spdk_bs_super_block *super = (struct spdk_bs_super_block *)&g_dev_buffer[0];
6556 : 15 : struct spdk_bs_super_block super_copy = {};
6557 : :
6558 : 15 : thresholds.general_threshold = 1;
6559 [ + + ]: 75 : while (!clean) {
6560 : : /* Create bs and blob */
6561 : 60 : suite_blob_setup();
6562 [ - + ]: 60 : SPDK_CU_ASSERT_FATAL(g_bs != NULL);
6563 [ - + ]: 60 : SPDK_CU_ASSERT_FATAL(g_blob != NULL);
6564 : 60 : bs = g_bs;
6565 : 60 : blob = g_blob;
6566 : :
6567 : : /* Super block should not change for rest of the UT,
6568 : : * save it and compare later. */
6569 : 60 : memcpy(&super_copy, super, sizeof(struct spdk_bs_super_block));
6570 [ - + ]: 60 : SPDK_CU_ASSERT_FATAL(super->clean == 0);
6571 [ - + - + ]: 60 : SPDK_CU_ASSERT_FATAL(bs->clean == 0);
6572 : :
6573 : : /* Force bs/super block in a clean state.
6574 : : * Along with marking blob dirty, to cause blob persist. */
6575 : 60 : blob->state = SPDK_BLOB_STATE_DIRTY;
6576 : 60 : bs->clean = 1;
6577 : 60 : super->clean = 1;
6578 : 60 : super->crc = blob_md_page_calc_crc(super);
6579 : :
6580 : 60 : g_bserrno = -1;
6581 : 60 : dev_set_power_failure_thresholds(thresholds);
6582 : 60 : spdk_blob_sync_md(blob, blob_op_complete, NULL);
6583 : 60 : poll_threads();
6584 : 60 : dev_reset_power_failure_event();
6585 : :
6586 [ + + ]: 60 : if (g_bserrno == 0) {
6587 : : /* After successful md sync, both bs and super block
6588 : : * should be marked as not clean. */
6589 [ - + - + ]: 15 : SPDK_CU_ASSERT_FATAL(bs->clean == 0);
6590 [ - + ]: 15 : SPDK_CU_ASSERT_FATAL(super->clean == 0);
6591 : 15 : clean = true;
6592 : : }
6593 : :
6594 : : /* Depending on the point of failure, super block was either updated or not. */
6595 : 60 : super_copy.clean = super->clean;
6596 : 60 : super_copy.crc = blob_md_page_calc_crc(&super_copy);
6597 : : /* Compare that the values in super block remained unchanged. */
6598 [ - + - + ]: 60 : SPDK_CU_ASSERT_FATAL(!memcmp(&super_copy, super, sizeof(struct spdk_bs_super_block)));
6599 : :
6600 : : /* Delete blob and unload bs */
6601 : 60 : suite_blob_cleanup();
6602 : :
6603 : 60 : thresholds.general_threshold++;
6604 : : }
6605 : 15 : }
6606 : :
6607 : : static void
6608 : 15 : blob_delete_snapshot_power_failure(void)
6609 : : {
6610 : : struct spdk_bs_dev *dev;
6611 : 15 : struct spdk_blob_store *bs;
6612 : 15 : struct spdk_blob_opts opts;
6613 : : struct spdk_blob *blob, *snapshot;
6614 : 15 : struct spdk_power_failure_thresholds thresholds = {};
6615 : : spdk_blob_id blobid, snapshotid;
6616 : 15 : const void *value;
6617 : 15 : size_t value_len;
6618 : 15 : size_t count;
6619 : 15 : spdk_blob_id ids[3] = {};
6620 : : int rc;
6621 : 15 : bool deleted = false;
6622 : 15 : int delete_snapshot_bserrno = -1;
6623 : : uint32_t first_data_cluster;
6624 : :
6625 : 15 : thresholds.general_threshold = 1;
6626 [ + + ]: 153 : while (!deleted) {
6627 : 138 : dev = init_dev();
6628 : :
6629 : 138 : spdk_bs_init(dev, NULL, bs_op_with_handle_complete, NULL);
6630 : 138 : poll_threads();
6631 : 138 : CU_ASSERT(g_bserrno == 0);
6632 [ - + ]: 138 : SPDK_CU_ASSERT_FATAL(g_bs != NULL);
6633 : 138 : bs = g_bs;
6634 : :
6635 [ - + ]: 138 : first_data_cluster = FIRST_DATA_CLUSTER(bs);
6636 : :
6637 : : /* Create blob */
6638 : 138 : ut_spdk_blob_opts_init(&opts);
6639 : 138 : opts.num_clusters = 10;
6640 : :
6641 : 138 : spdk_bs_create_blob_ext(bs, &opts, blob_op_with_id_complete, NULL);
6642 : 138 : poll_threads();
6643 : 138 : CU_ASSERT(g_bserrno == 0);
6644 : 138 : CU_ASSERT(g_blobid != SPDK_BLOBID_INVALID);
6645 : 138 : blobid = g_blobid;
6646 : :
6647 : : /* Create snapshot */
6648 : 138 : spdk_bs_create_snapshot(bs, blobid, NULL, blob_op_with_id_complete, NULL);
6649 : 138 : poll_threads();
6650 : 138 : CU_ASSERT(g_bserrno == 0);
6651 : 138 : CU_ASSERT(g_blobid != SPDK_BLOBID_INVALID);
6652 : 138 : snapshotid = g_blobid;
6653 [ - + ]: 138 : SPDK_CU_ASSERT_FATAL(spdk_bit_pool_is_allocated(bs->used_clusters, first_data_cluster));
6654 [ - + ]: 138 : SPDK_CU_ASSERT_FATAL(!spdk_bit_pool_is_allocated(bs->used_clusters, first_data_cluster + 10));
6655 : :
6656 : 138 : dev_set_power_failure_thresholds(thresholds);
6657 : :
6658 : 138 : spdk_bs_delete_blob(bs, snapshotid, blob_op_complete, NULL);
6659 : 138 : poll_threads();
6660 : 138 : delete_snapshot_bserrno = g_bserrno;
6661 : :
6662 : : /* Do not shut down cleanly. Assumption is that after snapshot deletion
6663 : : * reports success, changes to both blobs should already persisted. */
6664 : 138 : dev_reset_power_failure_event();
6665 : 138 : ut_bs_dirty_load(&bs, NULL);
6666 : :
6667 [ - + ]: 138 : SPDK_CU_ASSERT_FATAL(spdk_bit_pool_is_allocated(bs->used_clusters, first_data_cluster));
6668 [ - + ]: 138 : SPDK_CU_ASSERT_FATAL(!spdk_bit_pool_is_allocated(bs->used_clusters, first_data_cluster + 10));
6669 : :
6670 : 138 : spdk_bs_open_blob(bs, blobid, blob_op_with_handle_complete, NULL);
6671 : 138 : poll_threads();
6672 : 138 : CU_ASSERT(g_bserrno == 0);
6673 [ - + ]: 138 : SPDK_CU_ASSERT_FATAL(g_blob != NULL);
6674 : 138 : blob = g_blob;
6675 [ - + ]: 138 : SPDK_CU_ASSERT_FATAL(spdk_blob_is_thin_provisioned(blob) == true);
6676 : :
6677 : 138 : spdk_bs_open_blob(bs, snapshotid, blob_op_with_handle_complete, NULL);
6678 : 138 : poll_threads();
6679 : :
6680 [ + + ]: 138 : if (g_bserrno == 0) {
6681 [ - + ]: 93 : SPDK_CU_ASSERT_FATAL(g_blob != NULL);
6682 : 93 : snapshot = g_blob;
6683 : 93 : CU_ASSERT(spdk_blob_get_parent_snapshot(bs, blobid) == snapshotid);
6684 : 93 : count = SPDK_COUNTOF(ids);
6685 : 93 : rc = spdk_blob_get_clones(bs, snapshotid, ids, &count);
6686 : 93 : CU_ASSERT(rc == 0);
6687 : 93 : CU_ASSERT(count == 1);
6688 : 93 : CU_ASSERT(ids[0] == blobid);
6689 : 93 : rc = spdk_blob_get_xattr_value(snapshot, SNAPSHOT_PENDING_REMOVAL, &value, &value_len);
6690 : 93 : CU_ASSERT(rc != 0);
6691 [ - + ]: 93 : SPDK_CU_ASSERT_FATAL(spdk_blob_is_thin_provisioned(snapshot) == false);
6692 : 93 : CU_ASSERT(spdk_blob_get_num_allocated_clusters(blob) == 0);
6693 : 93 : CU_ASSERT(spdk_blob_get_num_allocated_clusters(snapshot) == 10);
6694 : :
6695 : 93 : spdk_blob_close(snapshot, blob_op_complete, NULL);
6696 : 93 : poll_threads();
6697 : 93 : CU_ASSERT(g_bserrno == 0);
6698 : : } else {
6699 : 45 : CU_ASSERT(spdk_blob_get_parent_snapshot(bs, blobid) == SPDK_BLOBID_INVALID);
6700 : 45 : CU_ASSERT(spdk_blob_get_num_allocated_clusters(blob) == 10);
6701 : : /* Snapshot might have been left in unrecoverable state, so it does not open.
6702 : : * Yet delete might perform further changes to the clone after that.
6703 : : * This UT should test until snapshot is deleted and delete call succeeds. */
6704 [ + + ]: 45 : if (delete_snapshot_bserrno == 0) {
6705 : 15 : deleted = true;
6706 : : }
6707 : : }
6708 : :
6709 : 138 : spdk_blob_close(blob, blob_op_complete, NULL);
6710 : 138 : poll_threads();
6711 : 138 : CU_ASSERT(g_bserrno == 0);
6712 : :
6713 : 138 : spdk_bs_unload(bs, bs_op_complete, NULL);
6714 : 138 : poll_threads();
6715 : 138 : CU_ASSERT(g_bserrno == 0);
6716 : :
6717 : 138 : thresholds.general_threshold++;
6718 : : }
6719 : 15 : }
6720 : :
6721 : : static void
6722 : 15 : blob_create_snapshot_power_failure(void)
6723 : : {
6724 : 15 : struct spdk_blob_store *bs = g_bs;
6725 : : struct spdk_bs_dev *dev;
6726 : 15 : struct spdk_blob_opts opts;
6727 : : struct spdk_blob *blob, *snapshot;
6728 : 15 : struct spdk_power_failure_thresholds thresholds = {};
6729 : : spdk_blob_id blobid, snapshotid;
6730 : 15 : const void *value;
6731 : 15 : size_t value_len;
6732 : 15 : size_t count;
6733 : 15 : spdk_blob_id ids[3] = {};
6734 : : int rc;
6735 : 15 : bool created = false;
6736 : 15 : int create_snapshot_bserrno = -1;
6737 : : uint32_t first_data_cluster;
6738 : :
6739 : 15 : thresholds.general_threshold = 1;
6740 [ + + ]: 129 : while (!created) {
6741 : 114 : dev = init_dev();
6742 : :
6743 : 114 : spdk_bs_init(dev, NULL, bs_op_with_handle_complete, NULL);
6744 : 114 : poll_threads();
6745 : 114 : CU_ASSERT(g_bserrno == 0);
6746 [ - + ]: 114 : SPDK_CU_ASSERT_FATAL(g_bs != NULL);
6747 : 114 : bs = g_bs;
6748 : :
6749 [ - + ]: 114 : first_data_cluster = FIRST_DATA_CLUSTER(bs);
6750 : :
6751 : : /* Create blob */
6752 : 114 : ut_spdk_blob_opts_init(&opts);
6753 : 114 : opts.num_clusters = 10;
6754 : :
6755 : 114 : spdk_bs_create_blob_ext(bs, &opts, blob_op_with_id_complete, NULL);
6756 : 114 : poll_threads();
6757 : 114 : CU_ASSERT(g_bserrno == 0);
6758 : 114 : CU_ASSERT(g_blobid != SPDK_BLOBID_INVALID);
6759 : 114 : blobid = g_blobid;
6760 [ - + ]: 114 : SPDK_CU_ASSERT_FATAL(spdk_bit_pool_is_allocated(bs->used_clusters, first_data_cluster));
6761 [ - + ]: 114 : SPDK_CU_ASSERT_FATAL(!spdk_bit_pool_is_allocated(bs->used_clusters, first_data_cluster + 10));
6762 : :
6763 : 114 : dev_set_power_failure_thresholds(thresholds);
6764 : :
6765 : : /* Create snapshot */
6766 : 114 : spdk_bs_create_snapshot(bs, blobid, NULL, blob_op_with_id_complete, NULL);
6767 : 114 : poll_threads();
6768 : 114 : create_snapshot_bserrno = g_bserrno;
6769 : 114 : snapshotid = g_blobid;
6770 [ - + ]: 114 : SPDK_CU_ASSERT_FATAL(spdk_bit_pool_is_allocated(bs->used_clusters, first_data_cluster));
6771 [ - + ]: 114 : SPDK_CU_ASSERT_FATAL(!spdk_bit_pool_is_allocated(bs->used_clusters, first_data_cluster + 10));
6772 : :
6773 : : /* Do not shut down cleanly. Assumption is that after create snapshot
6774 : : * reports success, both blobs should be power-fail safe. */
6775 : 114 : dev_reset_power_failure_event();
6776 : 114 : ut_bs_dirty_load(&bs, NULL);
6777 : :
6778 [ - + ]: 114 : SPDK_CU_ASSERT_FATAL(spdk_bit_pool_is_allocated(bs->used_clusters, first_data_cluster));
6779 [ - + ]: 114 : SPDK_CU_ASSERT_FATAL(!spdk_bit_pool_is_allocated(bs->used_clusters, first_data_cluster + 10));
6780 : :
6781 : 114 : spdk_bs_open_blob(bs, blobid, blob_op_with_handle_complete, NULL);
6782 : 114 : poll_threads();
6783 : 114 : CU_ASSERT(g_bserrno == 0);
6784 [ - + ]: 114 : SPDK_CU_ASSERT_FATAL(g_blob != NULL);
6785 : 114 : blob = g_blob;
6786 : :
6787 [ + + ]: 114 : if (snapshotid != SPDK_BLOBID_INVALID) {
6788 : 75 : spdk_bs_open_blob(bs, snapshotid, blob_op_with_handle_complete, NULL);
6789 : 75 : poll_threads();
6790 : : }
6791 : :
6792 [ + + + + ]: 114 : if ((snapshotid != SPDK_BLOBID_INVALID) && (g_bserrno == 0)) {
6793 [ - + ]: 30 : SPDK_CU_ASSERT_FATAL(g_blob != NULL);
6794 : 30 : snapshot = g_blob;
6795 [ - + ]: 30 : SPDK_CU_ASSERT_FATAL(spdk_blob_is_thin_provisioned(blob) == true);
6796 [ - + ]: 30 : SPDK_CU_ASSERT_FATAL(spdk_blob_is_thin_provisioned(snapshot) == false);
6797 : 30 : CU_ASSERT(spdk_blob_get_num_allocated_clusters(blob) == 0);
6798 : 30 : CU_ASSERT(spdk_blob_get_num_allocated_clusters(snapshot) == 10);
6799 : 30 : CU_ASSERT(spdk_blob_get_parent_snapshot(bs, blobid) == snapshotid);
6800 : 30 : count = SPDK_COUNTOF(ids);
6801 : 30 : rc = spdk_blob_get_clones(bs, snapshotid, ids, &count);
6802 : 30 : CU_ASSERT(rc == 0);
6803 : 30 : CU_ASSERT(count == 1);
6804 : 30 : CU_ASSERT(ids[0] == blobid);
6805 : 30 : rc = spdk_blob_get_xattr_value(snapshot, SNAPSHOT_IN_PROGRESS, &value, &value_len);
6806 : 30 : CU_ASSERT(rc != 0);
6807 : :
6808 : 30 : spdk_blob_close(snapshot, blob_op_complete, NULL);
6809 : 30 : poll_threads();
6810 : 30 : CU_ASSERT(g_bserrno == 0);
6811 [ + + ]: 30 : if (create_snapshot_bserrno == 0) {
6812 : 15 : created = true;
6813 : : }
6814 : : } else {
6815 : 84 : CU_ASSERT(spdk_blob_get_parent_snapshot(bs, blobid) == SPDK_BLOBID_INVALID);
6816 [ - + ]: 84 : SPDK_CU_ASSERT_FATAL(spdk_blob_is_thin_provisioned(blob) == false);
6817 : 84 : CU_ASSERT(spdk_blob_get_num_allocated_clusters(blob) == 10);
6818 : : }
6819 : :
6820 : 114 : spdk_blob_close(blob, blob_op_complete, NULL);
6821 : 114 : poll_threads();
6822 : 114 : CU_ASSERT(g_bserrno == 0);
6823 : :
6824 : 114 : spdk_bs_unload(bs, bs_op_complete, NULL);
6825 : 114 : poll_threads();
6826 : 114 : CU_ASSERT(g_bserrno == 0);
6827 : :
6828 : 114 : thresholds.general_threshold++;
6829 : : }
6830 : 15 : }
6831 : :
6832 : : #define IO_UT_BLOCKS_PER_CLUSTER 64
6833 : :
6834 : : static void
6835 : 30 : test_io_write(struct spdk_bs_dev *dev, struct spdk_blob *blob, struct spdk_io_channel *channel)
6836 : 30 : {
6837 : 30 : const uint32_t SZ = IO_UT_BLOCKS_PER_CLUSTER;
6838 [ - + ]: 30 : uint8_t payload_ff[SZ * 512];
6839 [ - + ]: 30 : uint8_t payload_aa[SZ * 512];
6840 [ - + ]: 30 : uint8_t payload_00[SZ * 512];
6841 : : uint8_t *cluster0, *cluster1;
6842 : :
6843 [ - + ]: 30 : memset(payload_ff, 0xFF, sizeof(payload_ff));
6844 [ - + ]: 30 : memset(payload_aa, 0xAA, sizeof(payload_aa));
6845 [ - + ]: 30 : memset(payload_00, 0x00, sizeof(payload_00));
6846 : :
6847 : : /* Try to perform I/O with io unit = 512 */
6848 : 30 : spdk_blob_io_write(blob, channel, payload_ff, 0, 1, blob_op_complete, NULL);
6849 : 30 : poll_threads();
6850 : 30 : CU_ASSERT(g_bserrno == 0);
6851 : :
6852 : : /* If thin provisioned is set cluster should be allocated now */
6853 [ - + ]: 30 : SPDK_CU_ASSERT_FATAL(blob->active.clusters[0] != 0);
6854 : 30 : cluster0 = &g_dev_buffer[blob->active.clusters[0] * dev->blocklen];
6855 : :
6856 : : /* Each character 0-F symbolizes single io_unit containing 512 bytes block filled with that character.
6857 : : * Each page is separated by |. Whole block [...] symbolizes one cluster (containing 4 pages). */
6858 : : /* cluster0: [ F000 0000 | 0000 0000 | 0000 0000 | 0000 0000 ] */
6859 [ - + - + ]: 30 : CU_ASSERT(memcmp(cluster0 + 0 * 512, payload_ff, 512) == 0);
6860 [ - + - + ]: 30 : CU_ASSERT(memcmp(cluster0 + 1 * 512, payload_00, (SZ - 1) * 512) == 0);
6861 : :
6862 : : /* Verify write with offset on first page */
6863 : 30 : spdk_blob_io_write(blob, channel, payload_ff, 2, 1, blob_op_complete, NULL);
6864 : 30 : poll_threads();
6865 : 30 : CU_ASSERT(g_bserrno == 0);
6866 : :
6867 : : /* cluster0: [ F0F0 0000 | 0000 0000 | 0000 0000 | 0000 0000 ] */
6868 [ - + - + ]: 30 : CU_ASSERT(memcmp(cluster0 + 0 * 512, payload_ff, 512) == 0);
6869 [ - + - + ]: 30 : CU_ASSERT(memcmp(cluster0 + 1 * 512, payload_00, 512) == 0);
6870 [ - + - + ]: 30 : CU_ASSERT(memcmp(cluster0 + 2 * 512, payload_ff, 512) == 0);
6871 [ - + - + ]: 30 : CU_ASSERT(memcmp(cluster0 + 3 * 512, payload_00, 512) == 0);
6872 [ - + - + ]: 30 : CU_ASSERT(memcmp(cluster0 + 4 * 512, payload_00, (SZ - 4) * 512) == 0);
6873 : :
6874 : : /* Verify write with offset on first page */
6875 : 30 : spdk_blob_io_write(blob, channel, payload_ff, 4, 4, blob_op_complete, NULL);
6876 : 30 : poll_threads();
6877 : :
6878 : : /* cluster0: [ F0F0 FFFF | 0000 0000 | 0000 0000 | 0000 0000 ] */
6879 [ - + - + ]: 30 : CU_ASSERT(memcmp(cluster0 + 0 * 512, payload_ff, 512) == 0);
6880 [ - + - + ]: 30 : CU_ASSERT(memcmp(cluster0 + 1 * 512, payload_00, 512) == 0);
6881 [ - + - + ]: 30 : CU_ASSERT(memcmp(cluster0 + 2 * 512, payload_ff, 512) == 0);
6882 [ - + - + ]: 30 : CU_ASSERT(memcmp(cluster0 + 3 * 512, payload_00, 512) == 0);
6883 [ - + - + ]: 30 : CU_ASSERT(memcmp(cluster0 + 4 * 512, payload_ff, 4 * 512) == 0);
6884 [ - + - + ]: 30 : CU_ASSERT(memcmp(cluster0 + 8 * 512, payload_00, (SZ - 8) * 512) == 0);
6885 : :
6886 : : /* Verify write with offset on second page */
6887 : 30 : spdk_blob_io_write(blob, channel, payload_ff, 8, 4, blob_op_complete, NULL);
6888 : 30 : poll_threads();
6889 : :
6890 : : /* cluster0: [ F0F0 FFFF | FFFF 0000 | 0000 0000 | 0000 0000 ] */
6891 [ - + - + ]: 30 : CU_ASSERT(memcmp(cluster0 + 0 * 512, payload_ff, 512) == 0);
6892 [ - + - + ]: 30 : CU_ASSERT(memcmp(cluster0 + 1 * 512, payload_00, 512) == 0);
6893 [ - + - + ]: 30 : CU_ASSERT(memcmp(cluster0 + 2 * 512, payload_ff, 512) == 0);
6894 [ - + - + ]: 30 : CU_ASSERT(memcmp(cluster0 + 3 * 512, payload_00, 512) == 0);
6895 [ - + - + ]: 30 : CU_ASSERT(memcmp(cluster0 + 4 * 512, payload_ff, 8 * 512) == 0);
6896 [ - + - + ]: 30 : CU_ASSERT(memcmp(cluster0 + 12 * 512, payload_00, (SZ - 12) * 512) == 0);
6897 : :
6898 : : /* Verify write across multiple pages */
6899 : 30 : spdk_blob_io_write(blob, channel, payload_aa, 4, 8, blob_op_complete, NULL);
6900 : 30 : poll_threads();
6901 : :
6902 : : /* cluster0: [ F0F0 AAAA | AAAA 0000 | 0000 0000 | 0000 0000 ] */
6903 [ - + - + ]: 30 : CU_ASSERT(memcmp(cluster0 + 0 * 512, payload_ff, 512) == 0);
6904 [ - + - + ]: 30 : CU_ASSERT(memcmp(cluster0 + 1 * 512, payload_00, 512) == 0);
6905 [ - + - + ]: 30 : CU_ASSERT(memcmp(cluster0 + 2 * 512, payload_ff, 512) == 0);
6906 [ - + - + ]: 30 : CU_ASSERT(memcmp(cluster0 + 3 * 512, payload_00, 512) == 0);
6907 [ - + - + ]: 30 : CU_ASSERT(memcmp(cluster0 + 4 * 512, payload_aa, 8 * 512) == 0);
6908 [ - + - + ]: 30 : CU_ASSERT(memcmp(cluster0 + 12 * 512, payload_00, (SZ - 12) * 512) == 0);
6909 : :
6910 : : /* Verify write across multiple clusters */
6911 : 30 : spdk_blob_io_write(blob, channel, payload_ff, SZ - 4, 8, blob_op_complete, NULL);
6912 : 30 : poll_threads();
6913 : :
6914 [ - + ]: 30 : SPDK_CU_ASSERT_FATAL(blob->active.clusters[1] != 0);
6915 : 30 : cluster1 = &g_dev_buffer[blob->active.clusters[1] * dev->blocklen];
6916 : :
6917 : : /* cluster0: [ F0F0 AAAA | AAAA 0000 | 0000 0000 | 0000 FFFF ]
6918 : : * cluster1: [ FFFF 0000 | 0000 0000 | 0000 0000 | 0000 0000 ] */
6919 [ - + - + ]: 30 : CU_ASSERT(memcmp(cluster0 + 0 * 512, payload_ff, 512) == 0);
6920 [ - + - + ]: 30 : CU_ASSERT(memcmp(cluster0 + 1 * 512, payload_00, 512) == 0);
6921 [ - + - + ]: 30 : CU_ASSERT(memcmp(cluster0 + 2 * 512, payload_ff, 512) == 0);
6922 [ - + - + ]: 30 : CU_ASSERT(memcmp(cluster0 + 3 * 512, payload_00, 512) == 0);
6923 [ - + - + ]: 30 : CU_ASSERT(memcmp(cluster0 + 4 * 512, payload_aa, 8 * 512) == 0);
6924 [ - + - + ]: 30 : CU_ASSERT(memcmp(cluster0 + (SZ - 4) * 512, payload_ff, 4 * 512) == 0);
6925 : :
6926 [ - + - + ]: 30 : CU_ASSERT(memcmp(cluster1 + 0 * 512, payload_ff, 4 * 512) == 0);
6927 [ - + - + ]: 30 : CU_ASSERT(memcmp(cluster1 + 4 * 512, payload_00, (SZ - 4) * 512) == 0);
6928 : :
6929 : : /* Verify write to second cluster */
6930 : 30 : spdk_blob_io_write(blob, channel, payload_ff, SZ + 12, 2, blob_op_complete, NULL);
6931 : 30 : poll_threads();
6932 : :
6933 [ - + ]: 30 : SPDK_CU_ASSERT_FATAL(blob->active.clusters[1] != 0);
6934 : 30 : cluster1 = &g_dev_buffer[blob->active.clusters[1] * dev->blocklen];
6935 : :
6936 : : /* cluster0: [ F0F0 AAAA | AAAA 0000 | 0000 0000 | 0000 FFFF ]
6937 : : * cluster1: [ FFFF 0000 | 0000 FF00 | 0000 0000 | 0000 0000 ] */
6938 [ - + - + ]: 30 : CU_ASSERT(memcmp(cluster0 + 0 * 512, payload_ff, 512) == 0);
6939 [ - + - + ]: 30 : CU_ASSERT(memcmp(cluster0 + 1 * 512, payload_00, 512) == 0);
6940 [ - + - + ]: 30 : CU_ASSERT(memcmp(cluster0 + 2 * 512, payload_ff, 512) == 0);
6941 [ - + - + ]: 30 : CU_ASSERT(memcmp(cluster0 + 3 * 512, payload_00, 512) == 0);
6942 [ - + - + ]: 30 : CU_ASSERT(memcmp(cluster0 + 4 * 512, payload_aa, 8 * 512) == 0);
6943 [ - + - + ]: 30 : CU_ASSERT(memcmp(cluster0 + (SZ - 4) * 512, payload_ff, 4 * 512) == 0);
6944 : :
6945 [ - + - + ]: 30 : CU_ASSERT(memcmp(cluster1 + 0 * 512, payload_ff, 4 * 512) == 0);
6946 [ - + - + ]: 30 : CU_ASSERT(memcmp(cluster1 + 4 * 512, payload_00, 8 * 512) == 0);
6947 [ - + - + ]: 30 : CU_ASSERT(memcmp(cluster1 + 12 * 512, payload_ff, 2 * 512) == 0);
6948 [ - + - + ]: 30 : CU_ASSERT(memcmp(cluster1 + 14 * 512, payload_00, (SZ - 14) * 512) == 0);
6949 : 30 : }
6950 : :
6951 : : static void
6952 : 90 : test_io_read(struct spdk_bs_dev *dev, struct spdk_blob *blob, struct spdk_io_channel *channel)
6953 : 90 : {
6954 : 90 : const uint32_t SZ = IO_UT_BLOCKS_PER_CLUSTER;
6955 [ - + ]: 270 : uint8_t payload_read[2 * SZ * 512];
6956 [ - + ]: 90 : uint8_t payload_ff[SZ * 512];
6957 [ - + ]: 90 : uint8_t payload_aa[SZ * 512];
6958 [ - + ]: 90 : uint8_t payload_00[SZ * 512];
6959 : :
6960 [ - + ]: 90 : memset(payload_ff, 0xFF, sizeof(payload_ff));
6961 [ - + ]: 90 : memset(payload_aa, 0xAA, sizeof(payload_aa));
6962 [ - + ]: 90 : memset(payload_00, 0x00, sizeof(payload_00));
6963 : :
6964 : : /* Read only first io unit */
6965 : : /* cluster0: [ (F)0F0 AAAA | AAAA 0000 | 0000 0000 | 0000 FFFF ]
6966 : : * cluster1: [ FFFF 0000 | 0000 FF00 | 0000 0000 | 0000 0000 ]
6967 : : * payload_read: F000 0000 | 0000 0000 ... */
6968 [ - + ]: 90 : memset(payload_read, 0x00, sizeof(payload_read));
6969 : 90 : spdk_blob_io_read(blob, channel, payload_read, 0, 1, blob_op_complete, NULL);
6970 : 90 : poll_threads();
6971 : 90 : CU_ASSERT(g_bserrno == 0);
6972 [ - + - + ]: 90 : CU_ASSERT(memcmp(payload_read + 0 * 512, payload_ff, 512) == 0);
6973 [ - + - + ]: 90 : CU_ASSERT(memcmp(payload_read + 1 * 512, payload_00, (SZ - 1) * 512) == 0);
6974 : :
6975 : : /* Read four io_units starting from offset = 2
6976 : : * cluster0: [ F0(F0 AA)AA | AAAA 0000 | 0000 0000 | 0000 FFFF ]
6977 : : * cluster1: [ FFFF 0000 | 0000 FF00 | 0000 0000 | 0000 0000 ]
6978 : : * payload_read: F0AA 0000 | 0000 0000 ... */
6979 : :
6980 [ - + ]: 90 : memset(payload_read, 0x00, sizeof(payload_read));
6981 : 90 : spdk_blob_io_read(blob, channel, payload_read, 2, 4, blob_op_complete, NULL);
6982 : 90 : poll_threads();
6983 : 90 : CU_ASSERT(g_bserrno == 0);
6984 : :
6985 [ - + - + ]: 90 : CU_ASSERT(memcmp(payload_read + 0 * 512, payload_ff, 512) == 0);
6986 [ - + - + ]: 90 : CU_ASSERT(memcmp(payload_read + 1 * 512, payload_00, 512) == 0);
6987 [ - + - + ]: 90 : CU_ASSERT(memcmp(payload_read + 2 * 512, payload_aa, 512) == 0);
6988 [ - + - + ]: 90 : CU_ASSERT(memcmp(payload_read + 3 * 512, payload_aa, 512) == 0);
6989 [ - + - + ]: 90 : CU_ASSERT(memcmp(payload_read + 4 * 512, payload_00, (SZ - 4) * 512) == 0);
6990 : :
6991 : : /* Read eight io_units across multiple pages
6992 : : * cluster0: [ F0F0 (AAAA | AAAA) 0000 | 0000 0000 | 0000 FFFF ]
6993 : : * cluster1: [ FFFF 0000 | 0000 FF00 | 0000 0000 | 0000 0000 ]
6994 : : * payload_read: AAAA AAAA | 0000 0000 ... */
6995 [ - + ]: 90 : memset(payload_read, 0x00, sizeof(payload_read));
6996 : 90 : spdk_blob_io_read(blob, channel, payload_read, 4, 8, blob_op_complete, NULL);
6997 : 90 : poll_threads();
6998 : 90 : CU_ASSERT(g_bserrno == 0);
6999 : :
7000 [ - + - + ]: 90 : CU_ASSERT(memcmp(payload_read + 0 * 512, payload_aa, 8 * 512) == 0);
7001 [ - + - + ]: 90 : CU_ASSERT(memcmp(payload_read + 8 * 512, payload_00, (SZ - 8) * 512) == 0);
7002 : :
7003 : : /* Read eight io_units across multiple clusters
7004 : : * cluster0: [ F0F0 AAAA | AAAA 0000 | 0000 0000 | 0000 (FFFF ]
7005 : : * cluster1: [ FFFF) 0000 | 0000 FF00 | 0000 0000 | 0000 0000 ]
7006 : : * payload_read: FFFF FFFF | 0000 0000 ... */
7007 [ - + ]: 90 : memset(payload_read, 0x00, sizeof(payload_read));
7008 : 90 : spdk_blob_io_read(blob, channel, payload_read, SZ - 4, 8, blob_op_complete, NULL);
7009 : 90 : poll_threads();
7010 : 90 : CU_ASSERT(g_bserrno == 0);
7011 : :
7012 [ - + - + ]: 90 : CU_ASSERT(memcmp(payload_read + 0 * 512, payload_ff, 8 * 512) == 0);
7013 [ - + - + ]: 90 : CU_ASSERT(memcmp(payload_read + 8 * 512, payload_00, (SZ - 8) * 512) == 0);
7014 : :
7015 : : /* Read four io_units from second cluster
7016 : : * cluster0: [ F0F0 AAAA | AAAA 0000 | 0000 0000 | 0000 FFFF ]
7017 : : * cluster1: [ FFFF 0000 | 00(00 FF)00 | 0000 0000 | 0000 0000 ]
7018 : : * payload_read: 00FF 0000 | 0000 0000 ... */
7019 [ - + ]: 90 : memset(payload_read, 0x00, sizeof(payload_read));
7020 : 90 : spdk_blob_io_read(blob, channel, payload_read, SZ + 10, 4, blob_op_complete, NULL);
7021 : 90 : poll_threads();
7022 : 90 : CU_ASSERT(g_bserrno == 0);
7023 : :
7024 [ - + - + ]: 90 : CU_ASSERT(memcmp(payload_read + 0 * 512, payload_00, 2 * 512) == 0);
7025 [ - + - + ]: 90 : CU_ASSERT(memcmp(payload_read + 2 * 512, payload_ff, 2 * 512) == 0);
7026 [ - + - + ]: 90 : CU_ASSERT(memcmp(payload_read + 4 * 512, payload_00, (SZ - 4) * 512) == 0);
7027 : :
7028 : : /* Read second cluster
7029 : : * cluster0: [ F0F0 AAAA | AAAA 0000 | 0000 0000 | 0000 FFFF ]
7030 : : * cluster1: [ (FFFF 0000 | 0000 FF00 | 0000 0000 | 0000 0000) ]
7031 : : * payload_read: FFFF 0000 | 0000 FF00 ... */
7032 [ - + ]: 90 : memset(payload_read, 0x00, sizeof(payload_read));
7033 : 90 : spdk_blob_io_read(blob, channel, payload_read, SZ, SZ, blob_op_complete, NULL);
7034 : 90 : poll_threads();
7035 : 90 : CU_ASSERT(g_bserrno == 0);
7036 [ - + - + ]: 90 : CU_ASSERT(memcmp(payload_read + 0 * 512, payload_ff, 4 * 512) == 0);
7037 [ - + - + ]: 90 : CU_ASSERT(memcmp(payload_read + 4 * 512, payload_00, 8 * 512) == 0);
7038 [ - + - + ]: 90 : CU_ASSERT(memcmp(payload_read + 12 * 512, payload_ff, 2 * 512) == 0);
7039 [ - + - + ]: 90 : CU_ASSERT(memcmp(payload_read + 14 * 512, payload_00, (SZ - 14) * 512) == 0);
7040 : :
7041 : : /* Read whole two clusters
7042 : : * cluster0: [ (F0F0 AAAA | AAAA) 0000 | 0000 0000 | 0000 FFFF ]
7043 : : * cluster1: [ FFFF 0000 | 0000 FF00 | 0000 0000 | 0000 0000) ] */
7044 [ - + ]: 90 : memset(payload_read, 0x00, sizeof(payload_read));
7045 : 90 : spdk_blob_io_read(blob, channel, payload_read, 0, SZ * 2, blob_op_complete, NULL);
7046 : 90 : poll_threads();
7047 : 90 : CU_ASSERT(g_bserrno == 0);
7048 : :
7049 [ - + - + ]: 90 : CU_ASSERT(memcmp(payload_read + 0 * 512, payload_ff, 512) == 0);
7050 [ - + - + ]: 90 : CU_ASSERT(memcmp(payload_read + 1 * 512, payload_00, 512) == 0);
7051 [ - + - + ]: 90 : CU_ASSERT(memcmp(payload_read + 2 * 512, payload_ff, 512) == 0);
7052 [ - + - + ]: 90 : CU_ASSERT(memcmp(payload_read + 3 * 512, payload_00, 512) == 0);
7053 [ - + - + ]: 90 : CU_ASSERT(memcmp(payload_read + 4 * 512, payload_aa, 8 * 512) == 0);
7054 [ - + - + ]: 90 : CU_ASSERT(memcmp(payload_read + (SZ - 4) * 512, payload_ff, 4 * 512) == 0);
7055 : :
7056 [ - + - + ]: 90 : CU_ASSERT(memcmp(payload_read + (SZ + 0) * 512, payload_ff, 4 * 512) == 0);
7057 [ - + - + ]: 90 : CU_ASSERT(memcmp(payload_read + (SZ + 4) * 512, payload_00, 8 * 512) == 0);
7058 [ - + - + ]: 90 : CU_ASSERT(memcmp(payload_read + (SZ + 12) * 512, payload_ff, 2 * 512) == 0);
7059 [ - + - + ]: 90 : CU_ASSERT(memcmp(payload_read + (SZ + 14) * 512, payload_00, (SZ - 14) * 512) == 0);
7060 : 90 : }
7061 : :
7062 : :
7063 : : static void
7064 : 45 : test_io_unmap(struct spdk_bs_dev *dev, struct spdk_blob *blob, struct spdk_io_channel *channel)
7065 : 45 : {
7066 : 45 : const uint32_t SZ = IO_UT_BLOCKS_PER_CLUSTER;
7067 [ - + ]: 45 : uint8_t payload_ff[SZ * 512];
7068 [ - + ]: 45 : uint8_t payload_aa[SZ * 512];
7069 [ - + ]: 45 : uint8_t payload_00[SZ * 512];
7070 : : uint8_t *cluster0, *cluster1;
7071 : :
7072 [ - + ]: 45 : memset(payload_ff, 0xFF, sizeof(payload_ff));
7073 [ - + ]: 45 : memset(payload_aa, 0xAA, sizeof(payload_aa));
7074 [ - + ]: 45 : memset(payload_00, 0x00, sizeof(payload_00));
7075 : :
7076 : 45 : cluster0 = &g_dev_buffer[blob->active.clusters[0] * dev->blocklen];
7077 : 45 : cluster1 = &g_dev_buffer[blob->active.clusters[1] * dev->blocklen];
7078 : :
7079 : : /* Unmap */
7080 : 45 : spdk_blob_io_unmap(blob, channel, 0, SZ * 2, blob_op_complete, NULL);
7081 : 45 : poll_threads();
7082 : :
7083 : 45 : CU_ASSERT(g_bserrno == 0);
7084 : :
7085 [ - + - + ]: 45 : CU_ASSERT(memcmp(cluster0 + 0 * 512, payload_00, SZ * 512) == 0);
7086 [ - + - + ]: 45 : CU_ASSERT(memcmp(cluster1 + 0 * 512, payload_00, SZ * 512) == 0);
7087 : 45 : }
7088 : :
7089 : : static void
7090 : 60 : test_io_zeroes(struct spdk_bs_dev *dev, struct spdk_blob *blob, struct spdk_io_channel *channel)
7091 : 60 : {
7092 : 60 : const uint32_t SZ = IO_UT_BLOCKS_PER_CLUSTER;
7093 [ - + ]: 60 : uint8_t payload_ff[SZ * 512];
7094 [ - + ]: 60 : uint8_t payload_aa[SZ * 512];
7095 [ - + ]: 60 : uint8_t payload_00[SZ * 512];
7096 : : uint8_t *cluster0, *cluster1;
7097 : :
7098 [ - + ]: 60 : memset(payload_ff, 0xFF, sizeof(payload_ff));
7099 [ - + ]: 60 : memset(payload_aa, 0xAA, sizeof(payload_aa));
7100 [ - + ]: 60 : memset(payload_00, 0x00, sizeof(payload_00));
7101 : :
7102 : 60 : cluster0 = &g_dev_buffer[blob->active.clusters[0] * dev->blocklen];
7103 : 60 : cluster1 = &g_dev_buffer[blob->active.clusters[1] * dev->blocklen];
7104 : :
7105 : : /* Write zeroes */
7106 : 60 : spdk_blob_io_write_zeroes(blob, channel, 0, SZ * 2, blob_op_complete, NULL);
7107 : 60 : poll_threads();
7108 : :
7109 : 60 : CU_ASSERT(g_bserrno == 0);
7110 : :
7111 [ - + - + ]: 60 : CU_ASSERT(memcmp(cluster0 + 0 * 512, payload_00, SZ * 512) == 0);
7112 [ - + - + ]: 60 : CU_ASSERT(memcmp(cluster1 + 0 * 512, payload_00, SZ * 512) == 0);
7113 : 60 : }
7114 : :
7115 : : static inline void
7116 : 450 : test_blob_io_writev(struct spdk_blob *blob, struct spdk_io_channel *channel,
7117 : : struct iovec *iov, int iovcnt, uint64_t offset, uint64_t length,
7118 : : spdk_blob_op_complete cb_fn, void *cb_arg, struct spdk_blob_ext_io_opts *io_opts)
7119 : : {
7120 [ + + ]: 450 : if (io_opts) {
7121 : 225 : g_dev_writev_ext_called = false;
7122 : 225 : memset(&g_blob_ext_io_opts, 0, sizeof(g_blob_ext_io_opts));
7123 : 225 : spdk_blob_io_writev_ext(blob, channel, iov, iovcnt, offset, length, blob_op_complete, NULL,
7124 : : io_opts);
7125 : : } else {
7126 : 225 : spdk_blob_io_writev(blob, channel, iov, iovcnt, offset, length, blob_op_complete, NULL);
7127 : : }
7128 : 450 : poll_threads();
7129 : 450 : CU_ASSERT(g_bserrno == 0);
7130 [ + + ]: 450 : if (io_opts) {
7131 [ - + ]: 225 : CU_ASSERT(g_dev_writev_ext_called);
7132 [ - + ]: 225 : CU_ASSERT(memcmp(io_opts, &g_blob_ext_io_opts, sizeof(g_blob_ext_io_opts)) == 0);
7133 : : }
7134 : 450 : }
7135 : :
7136 : : static void
7137 : 90 : test_iov_write(struct spdk_bs_dev *dev, struct spdk_blob *blob, struct spdk_io_channel *channel,
7138 : : bool ext_api)
7139 : 90 : {
7140 : 90 : const uint32_t SZ = IO_UT_BLOCKS_PER_CLUSTER;
7141 [ - + ]: 120 : uint8_t payload_ff[SZ * 512];
7142 [ - + ]: 120 : uint8_t payload_aa[SZ * 512];
7143 [ - + ]: 120 : uint8_t payload_00[SZ * 512];
7144 : : uint8_t *cluster0, *cluster1;
7145 : 90 : struct iovec iov[4];
7146 : 90 : struct spdk_blob_ext_io_opts ext_opts = {
7147 : : .memory_domain = (struct spdk_memory_domain *)0xfeedbeef,
7148 : : .memory_domain_ctx = (void *)0xf00df00d,
7149 : : .size = sizeof(struct spdk_blob_ext_io_opts),
7150 : : .user_ctx = (void *)123,
7151 : : };
7152 : :
7153 [ - + ]: 90 : memset(payload_ff, 0xFF, sizeof(payload_ff));
7154 [ - + ]: 90 : memset(payload_aa, 0xAA, sizeof(payload_aa));
7155 [ - + ]: 90 : memset(payload_00, 0x00, sizeof(payload_00));
7156 : :
7157 : : /* Try to perform I/O with io unit = 512 */
7158 : 90 : iov[0].iov_base = payload_ff;
7159 : 90 : iov[0].iov_len = 1 * 512;
7160 : :
7161 [ + + ]: 90 : test_blob_io_writev(blob, channel, iov, 1, 0, 1, blob_op_complete, NULL,
7162 : : ext_api ? &ext_opts : NULL);
7163 : :
7164 : : /* If thin provisioned is set cluster should be allocated now */
7165 [ - + ]: 90 : SPDK_CU_ASSERT_FATAL(blob->active.clusters[0] != 0);
7166 : 90 : cluster0 = &g_dev_buffer[blob->active.clusters[0] * dev->blocklen];
7167 : :
7168 : : /* Each character 0-F symbolizes single io_unit containing 512 bytes block filled with that character.
7169 : : * Each page is separated by |. Whole block [...] symbolizes one cluster (containing 4 pages). */
7170 : : /* cluster0: [ F000 0000 | 0000 0000 | 0000 0000 | 0000 0000 ] */
7171 [ - + - + ]: 90 : CU_ASSERT(memcmp(cluster0 + 0 * 512, payload_ff, 512) == 0);
7172 [ - + - + ]: 90 : CU_ASSERT(memcmp(cluster0 + 1 * 512, payload_00, (SZ - 1) * 512) == 0);
7173 : :
7174 : : /* Verify write with offset on first page */
7175 : 90 : iov[0].iov_base = payload_ff;
7176 : 90 : iov[0].iov_len = 1 * 512;
7177 : :
7178 [ + + ]: 90 : test_blob_io_writev(blob, channel, iov, 1, 2, 1, blob_op_complete, NULL,
7179 : : ext_api ? &ext_opts : NULL);
7180 : :
7181 : : /* cluster0: [ F0F0 0000 | 0000 0000 | 0000 0000 | 0000 0000 ] */
7182 [ - + - + ]: 90 : CU_ASSERT(memcmp(cluster0 + 0 * 512, payload_ff, 512) == 0);
7183 [ - + - + ]: 90 : CU_ASSERT(memcmp(cluster0 + 1 * 512, payload_00, 512) == 0);
7184 [ - + - + ]: 90 : CU_ASSERT(memcmp(cluster0 + 2 * 512, payload_ff, 512) == 0);
7185 [ - + - + ]: 90 : CU_ASSERT(memcmp(cluster0 + 3 * 512, payload_00, 512) == 0);
7186 [ - + - + ]: 90 : CU_ASSERT(memcmp(cluster0 + 4 * 512, payload_00, (SZ - 4) * 512) == 0);
7187 : :
7188 : : /* Verify write with offset on first page */
7189 : 90 : iov[0].iov_base = payload_ff;
7190 : 90 : iov[0].iov_len = 4 * 512;
7191 : 90 : spdk_blob_io_writev(blob, channel, iov, 1, 4, 4, blob_op_complete, NULL);
7192 : 90 : poll_threads();
7193 : :
7194 : : /* cluster0: [ F0F0 FFFF | 0000 0000 | 0000 0000 | 0000 0000 ] */
7195 [ - + - + ]: 90 : CU_ASSERT(memcmp(cluster0 + 0 * 512, payload_ff, 512) == 0);
7196 [ - + - + ]: 90 : CU_ASSERT(memcmp(cluster0 + 1 * 512, payload_00, 512) == 0);
7197 [ - + - + ]: 90 : CU_ASSERT(memcmp(cluster0 + 2 * 512, payload_ff, 512) == 0);
7198 [ - + - + ]: 90 : CU_ASSERT(memcmp(cluster0 + 3 * 512, payload_00, 512) == 0);
7199 [ - + - + ]: 90 : CU_ASSERT(memcmp(cluster0 + 4 * 512, payload_ff, 4 * 512) == 0);
7200 [ - + - + ]: 90 : CU_ASSERT(memcmp(cluster0 + 8 * 512, payload_00, (SZ - 8) * 512) == 0);
7201 : :
7202 : : /* Verify write with offset on second page */
7203 : 90 : iov[0].iov_base = payload_ff;
7204 : 90 : iov[0].iov_len = 4 * 512;
7205 : 90 : spdk_blob_io_writev(blob, channel, iov, 1, 8, 4, blob_op_complete, NULL);
7206 : 90 : poll_threads();
7207 : :
7208 : : /* cluster0: [ F0F0 FFFF | FFFF 0000 | 0000 0000 | 0000 0000 ] */
7209 [ - + - + ]: 90 : CU_ASSERT(memcmp(cluster0 + 0 * 512, payload_ff, 512) == 0);
7210 [ - + - + ]: 90 : CU_ASSERT(memcmp(cluster0 + 1 * 512, payload_00, 512) == 0);
7211 [ - + - + ]: 90 : CU_ASSERT(memcmp(cluster0 + 2 * 512, payload_ff, 512) == 0);
7212 [ - + - + ]: 90 : CU_ASSERT(memcmp(cluster0 + 3 * 512, payload_00, 512) == 0);
7213 [ - + - + ]: 90 : CU_ASSERT(memcmp(cluster0 + 4 * 512, payload_ff, 8 * 512) == 0);
7214 [ - + - + ]: 90 : CU_ASSERT(memcmp(cluster0 + 12 * 512, payload_00, (SZ - 12) * 512) == 0);
7215 : :
7216 : : /* Verify write across multiple pages */
7217 : 90 : iov[0].iov_base = payload_aa;
7218 : 90 : iov[0].iov_len = 8 * 512;
7219 : :
7220 [ + + ]: 90 : test_blob_io_writev(blob, channel, iov, 1, 4, 8, blob_op_complete, NULL,
7221 : : ext_api ? &ext_opts : NULL);
7222 : :
7223 : : /* cluster0: [ F0F0 AAAA | AAAA 0000 | 0000 0000 | 0000 0000 ] */
7224 [ - + - + ]: 90 : CU_ASSERT(memcmp(cluster0 + 0 * 512, payload_ff, 512) == 0);
7225 [ - + - + ]: 90 : CU_ASSERT(memcmp(cluster0 + 1 * 512, payload_00, 512) == 0);
7226 [ - + - + ]: 90 : CU_ASSERT(memcmp(cluster0 + 2 * 512, payload_ff, 512) == 0);
7227 [ - + - + ]: 90 : CU_ASSERT(memcmp(cluster0 + 3 * 512, payload_00, 512) == 0);
7228 [ - + - + ]: 90 : CU_ASSERT(memcmp(cluster0 + 4 * 512, payload_aa, 8 * 512) == 0);
7229 [ - + - + ]: 90 : CU_ASSERT(memcmp(cluster0 + 12 * 512, payload_00, (SZ - 12) * 512) == 0);
7230 : :
7231 : : /* Verify write across multiple clusters */
7232 : :
7233 : 90 : iov[0].iov_base = payload_ff;
7234 : 90 : iov[0].iov_len = 8 * 512;
7235 : :
7236 [ + + ]: 90 : test_blob_io_writev(blob, channel, iov, 1, (SZ - 4), 8, blob_op_complete, NULL,
7237 : : ext_api ? &ext_opts : NULL);
7238 : :
7239 [ - + ]: 90 : SPDK_CU_ASSERT_FATAL(blob->active.clusters[1] != 0);
7240 : 90 : cluster1 = &g_dev_buffer[blob->active.clusters[1] * dev->blocklen];
7241 : :
7242 : : /* cluster0: [ F0F0 AAAA | AAAA 0000 | 0000 0000 | 0000 FFFF ]
7243 : : * cluster1: [ FFFF 0000 | 0000 0000 | 0000 0000 | 0000 0000 ] */
7244 [ - + - + ]: 90 : CU_ASSERT(memcmp(cluster0 + 0 * 512, payload_ff, 512) == 0);
7245 [ - + - + ]: 90 : CU_ASSERT(memcmp(cluster0 + 1 * 512, payload_00, 512) == 0);
7246 [ - + - + ]: 90 : CU_ASSERT(memcmp(cluster0 + 2 * 512, payload_ff, 512) == 0);
7247 [ - + - + ]: 90 : CU_ASSERT(memcmp(cluster0 + 3 * 512, payload_00, 512) == 0);
7248 [ - + - + ]: 90 : CU_ASSERT(memcmp(cluster0 + 4 * 512, payload_aa, 8 * 512) == 0);
7249 [ - + - + ]: 90 : CU_ASSERT(memcmp(cluster0 + 12 * 512, payload_00, (SZ - 16) * 512) == 0);
7250 [ - + - + ]: 90 : CU_ASSERT(memcmp(cluster0 + (SZ - 4) * 512, payload_ff, 4 * 512) == 0);
7251 : :
7252 [ - + - + ]: 90 : CU_ASSERT(memcmp(cluster1 + 0 * 512, payload_ff, 4 * 512) == 0);
7253 [ - + - + ]: 90 : CU_ASSERT(memcmp(cluster1 + 4 * 512, payload_00, (SZ - 4) * 512) == 0);
7254 : :
7255 : : /* Verify write to second cluster */
7256 : :
7257 : 90 : iov[0].iov_base = payload_ff;
7258 : 90 : iov[0].iov_len = 2 * 512;
7259 : :
7260 [ + + ]: 90 : test_blob_io_writev(blob, channel, iov, 1, SZ + 12, 2, blob_op_complete, NULL,
7261 : : ext_api ? &ext_opts : NULL);
7262 : :
7263 [ - + ]: 90 : SPDK_CU_ASSERT_FATAL(blob->active.clusters[1] != 0);
7264 : 90 : cluster1 = &g_dev_buffer[blob->active.clusters[1] * dev->blocklen];
7265 : :
7266 : : /* cluster0: [ F0F0 AAAA | AAAA 0000 | 0000 0000 | 0000 FFFF ]
7267 : : * cluster1: [ FFFF 0000 | 0000 FF00 | 0000 0000 | 0000 0000 ] */
7268 [ - + - + ]: 90 : CU_ASSERT(memcmp(cluster0 + 0 * 512, payload_ff, 512) == 0);
7269 [ - + - + ]: 90 : CU_ASSERT(memcmp(cluster0 + 1 * 512, payload_00, 512) == 0);
7270 [ - + - + ]: 90 : CU_ASSERT(memcmp(cluster0 + 2 * 512, payload_ff, 512) == 0);
7271 [ - + - + ]: 90 : CU_ASSERT(memcmp(cluster0 + 3 * 512, payload_00, 512) == 0);
7272 [ - + - + ]: 90 : CU_ASSERT(memcmp(cluster0 + 4 * 512, payload_aa, 8 * 512) == 0);
7273 [ - + - + ]: 90 : CU_ASSERT(memcmp(cluster0 + (SZ - 4) * 512, payload_ff, 4 * 512) == 0);
7274 : :
7275 [ - + - + ]: 90 : CU_ASSERT(memcmp(cluster1 + 0 * 512, payload_ff, 4 * 512) == 0);
7276 [ - + - + ]: 90 : CU_ASSERT(memcmp(cluster1 + 4 * 512, payload_00, 8 * 512) == 0);
7277 [ - + - + ]: 90 : CU_ASSERT(memcmp(cluster1 + 12 * 512, payload_ff, 2 * 512) == 0);
7278 [ - + - + ]: 90 : CU_ASSERT(memcmp(cluster1 + 14 * 512, payload_00, (SZ - 14) * 512) == 0);
7279 : 90 : }
7280 : :
7281 : : static inline void
7282 : 1260 : test_blob_io_readv(struct spdk_blob *blob, struct spdk_io_channel *channel,
7283 : : struct iovec *iov, int iovcnt, uint64_t offset, uint64_t length,
7284 : : spdk_blob_op_complete cb_fn, void *cb_arg, struct spdk_blob_ext_io_opts *io_opts)
7285 : : {
7286 [ + + ]: 1260 : if (io_opts) {
7287 : 630 : g_dev_readv_ext_called = false;
7288 : 630 : memset(&g_blob_ext_io_opts, 0, sizeof(g_blob_ext_io_opts));
7289 : 630 : spdk_blob_io_readv_ext(blob, channel, iov, iovcnt, offset, length, blob_op_complete, NULL, io_opts);
7290 : : } else {
7291 : 630 : spdk_blob_io_readv(blob, channel, iov, iovcnt, offset, length, blob_op_complete, NULL);
7292 : : }
7293 : 1260 : poll_threads();
7294 : 1260 : CU_ASSERT(g_bserrno == 0);
7295 [ + + ]: 1260 : if (io_opts) {
7296 [ - + ]: 630 : CU_ASSERT(g_dev_readv_ext_called);
7297 [ - + ]: 630 : CU_ASSERT(memcmp(io_opts, &g_blob_ext_io_opts, sizeof(g_blob_ext_io_opts)) == 0);
7298 : : }
7299 : 1260 : }
7300 : :
7301 : : static void
7302 : 180 : test_iov_read(struct spdk_bs_dev *dev, struct spdk_blob *blob, struct spdk_io_channel *channel,
7303 : : bool ext_api)
7304 : 180 : {
7305 : 180 : const uint32_t SZ = IO_UT_BLOCKS_PER_CLUSTER;
7306 [ - + ]: 600 : uint8_t payload_read[2 * SZ * 512];
7307 [ - + ]: 240 : uint8_t payload_ff[SZ * 512];
7308 [ - + ]: 240 : uint8_t payload_aa[SZ * 512];
7309 [ - + ]: 240 : uint8_t payload_00[SZ * 512];
7310 : 180 : struct iovec iov[4];
7311 : 180 : struct spdk_blob_ext_io_opts ext_opts = {
7312 : : .memory_domain = (struct spdk_memory_domain *)0xfeedbeef,
7313 : : .memory_domain_ctx = (void *)0xf00df00d,
7314 : : .size = sizeof(struct spdk_blob_ext_io_opts),
7315 : : .user_ctx = (void *)123,
7316 : : };
7317 : :
7318 [ - + ]: 180 : memset(payload_ff, 0xFF, sizeof(payload_ff));
7319 [ - + ]: 180 : memset(payload_aa, 0xAA, sizeof(payload_aa));
7320 [ - + ]: 180 : memset(payload_00, 0x00, sizeof(payload_00));
7321 : :
7322 : : /* Read only first io unit */
7323 : : /* cluster0: [ (F)0F0 AAAA | AAAA 0000 | 0000 0000 | 0000 FFFF ]
7324 : : * cluster1: [ FFFF 0000 | 0000 FF00 | 0000 0000 | 0000 0000 ]
7325 : : * payload_read: F000 0000 | 0000 0000 ... */
7326 [ - + ]: 180 : memset(payload_read, 0x00, sizeof(payload_read));
7327 : 180 : iov[0].iov_base = payload_read;
7328 : 180 : iov[0].iov_len = 1 * 512;
7329 : :
7330 [ + + ]: 180 : test_blob_io_readv(blob, channel, iov, 1, 0, 1, blob_op_complete, NULL, ext_api ? &ext_opts : NULL);
7331 : :
7332 [ - + - + ]: 180 : CU_ASSERT(memcmp(payload_read + 0 * 512, payload_ff, 512) == 0);
7333 [ - + - + ]: 180 : CU_ASSERT(memcmp(payload_read + 1 * 512, payload_00, (SZ - 1) * 512) == 0);
7334 : :
7335 : : /* Read four io_units starting from offset = 2
7336 : : * cluster0: [ F0(F0 AA)AA | AAAA 0000 | 0000 0000 | 0000 FFFF ]
7337 : : * cluster1: [ FFFF 0000 | 0000 FF00 | 0000 0000 | 0000 0000 ]
7338 : : * payload_read: F0AA 0000 | 0000 0000 ... */
7339 : :
7340 [ - + ]: 180 : memset(payload_read, 0x00, sizeof(payload_read));
7341 : 180 : iov[0].iov_base = payload_read;
7342 : 180 : iov[0].iov_len = 4 * 512;
7343 : :
7344 [ + + ]: 180 : test_blob_io_readv(blob, channel, iov, 1, 2, 4, blob_op_complete, NULL, ext_api ? &ext_opts : NULL);
7345 : :
7346 [ - + - + ]: 180 : CU_ASSERT(memcmp(payload_read + 0 * 512, payload_ff, 512) == 0);
7347 [ - + - + ]: 180 : CU_ASSERT(memcmp(payload_read + 1 * 512, payload_00, 512) == 0);
7348 [ - + - + ]: 180 : CU_ASSERT(memcmp(payload_read + 2 * 512, payload_aa, 512) == 0);
7349 [ - + - + ]: 180 : CU_ASSERT(memcmp(payload_read + 3 * 512, payload_aa, 512) == 0);
7350 [ - + - + ]: 180 : CU_ASSERT(memcmp(payload_read + 4 * 512, payload_00, (SZ - 4) * 512) == 0);
7351 : :
7352 : : /* Read eight io_units across multiple pages
7353 : : * cluster0: [ F0F0 (AAAA | AAAA) 0000 | 0000 0000 | 0000 FFFF ]
7354 : : * cluster1: [ FFFF 0000 | 0000 FF00 | 0000 0000 | 0000 0000 ]
7355 : : * payload_read: AAAA AAAA | 0000 0000 ... */
7356 [ - + ]: 180 : memset(payload_read, 0x00, sizeof(payload_read));
7357 : 180 : iov[0].iov_base = payload_read;
7358 : 180 : iov[0].iov_len = 4 * 512;
7359 : 180 : iov[1].iov_base = payload_read + 4 * 512;
7360 : 180 : iov[1].iov_len = 4 * 512;
7361 : :
7362 [ + + ]: 180 : test_blob_io_readv(blob, channel, iov, 2, 4, 8, blob_op_complete, NULL, ext_api ? &ext_opts : NULL);
7363 : :
7364 [ - + - + ]: 180 : CU_ASSERT(memcmp(payload_read + 0 * 512, payload_aa, 8 * 512) == 0);
7365 [ - + - + ]: 180 : CU_ASSERT(memcmp(payload_read + 8 * 512, payload_00, (SZ - 8) * 512) == 0);
7366 : :
7367 : : /* Read eight io_units across multiple clusters
7368 : : * cluster0: [ F0F0 AAAA | AAAA 0000 | 0000 0000 | 0000 (FFFF ]
7369 : : * cluster1: [ FFFF) 0000 | 0000 FF00 | 0000 0000 | 0000 0000 ]
7370 : : * payload_read: FFFF FFFF | 0000 0000 ... */
7371 [ - + ]: 180 : memset(payload_read, 0x00, sizeof(payload_read));
7372 : 180 : iov[0].iov_base = payload_read;
7373 : 180 : iov[0].iov_len = 2 * 512;
7374 : 180 : iov[1].iov_base = payload_read + 2 * 512;
7375 : 180 : iov[1].iov_len = 2 * 512;
7376 : 180 : iov[2].iov_base = payload_read + 4 * 512;
7377 : 180 : iov[2].iov_len = 2 * 512;
7378 : 180 : iov[3].iov_base = payload_read + 6 * 512;
7379 : 180 : iov[3].iov_len = 2 * 512;
7380 : :
7381 [ + + ]: 180 : test_blob_io_readv(blob, channel, iov, 4, SZ - 4, 8, blob_op_complete, NULL,
7382 : : ext_api ? &ext_opts : NULL);
7383 : :
7384 [ - + - + ]: 180 : CU_ASSERT(memcmp(payload_read + 0 * 512, payload_ff, 8 * 512) == 0);
7385 [ - + - + ]: 180 : CU_ASSERT(memcmp(payload_read + 8 * 512, payload_00, (SZ - 8) * 512) == 0);
7386 : :
7387 : : /* Read four io_units from second cluster
7388 : : * cluster0: [ F0F0 AAAA | AAAA 0000 | 0000 0000 | 0000 FFFF ]
7389 : : * cluster1: [ FFFF 0000 | 00(00 FF)00 | 0000 0000 | 0000 0000 ]
7390 : : * payload_read: 00FF 0000 | 0000 0000 ... */
7391 [ - + ]: 180 : memset(payload_read, 0x00, sizeof(payload_read));
7392 : 180 : iov[0].iov_base = payload_read;
7393 : 180 : iov[0].iov_len = 1 * 512;
7394 : 180 : iov[1].iov_base = payload_read + 1 * 512;
7395 : 180 : iov[1].iov_len = 3 * 512;
7396 : :
7397 [ + + ]: 180 : test_blob_io_readv(blob, channel, iov, 2, SZ + 10, 4, blob_op_complete, NULL,
7398 : : ext_api ? &ext_opts : NULL);
7399 : :
7400 [ - + - + ]: 180 : CU_ASSERT(memcmp(payload_read + 0 * 512, payload_00, 2 * 512) == 0);
7401 [ - + - + ]: 180 : CU_ASSERT(memcmp(payload_read + 2 * 512, payload_ff, 2 * 512) == 0);
7402 [ - + - + ]: 180 : CU_ASSERT(memcmp(payload_read + 4 * 512, payload_00, (SZ - 4) * 512) == 0);
7403 : :
7404 : : /* Read second cluster
7405 : : * cluster0: [ F0F0 AAAA | AAAA 0000 | 0000 0000 | 0000 FFFF ]
7406 : : * cluster1: [ (FFFF 0000 | 0000 FF00 | 0000 0000 | 0000 0000) ]
7407 : : * payload_read: FFFF 0000 | 0000 FF00 ... */
7408 [ - + ]: 180 : memset(payload_read, 0x00, sizeof(payload_read));
7409 : 180 : iov[0].iov_base = payload_read;
7410 : 180 : iov[0].iov_len = 1 * 512;
7411 : 180 : iov[1].iov_base = payload_read + 1 * 512;
7412 : 180 : iov[1].iov_len = 2 * 512;
7413 : 180 : iov[2].iov_base = payload_read + 3 * 512;
7414 : 180 : iov[2].iov_len = 4 * 512;
7415 : 180 : iov[3].iov_base = payload_read + 7 * 512;
7416 : 180 : iov[3].iov_len = (SZ - 7) * 512;
7417 : :
7418 [ + + ]: 180 : test_blob_io_readv(blob, channel, iov, 4, SZ, SZ, blob_op_complete, NULL,
7419 : : ext_api ? &ext_opts : NULL);
7420 : :
7421 [ - + - + ]: 180 : CU_ASSERT(memcmp(payload_read + 0 * 512, payload_ff, 4 * 512) == 0);
7422 [ - + - + ]: 180 : CU_ASSERT(memcmp(payload_read + 4 * 512, payload_00, 8 * 512) == 0);
7423 [ - + - + ]: 180 : CU_ASSERT(memcmp(payload_read + 12 * 512, payload_ff, 2 * 512) == 0);
7424 [ - + - + ]: 180 : CU_ASSERT(memcmp(payload_read + 14 * 512, payload_00, (SZ - 14) * 512) == 0);
7425 : :
7426 : : /* Read whole two clusters
7427 : : * cluster0: [ (F0F0 AAAA | AAAA) 0000 | 0000 0000 | 0000 FFFF ]
7428 : : * cluster1: [ FFFF 0000 | 0000 FF00 | 0000 0000 | 0000 0000) ] */
7429 [ - + ]: 180 : memset(payload_read, 0x00, sizeof(payload_read));
7430 : 180 : iov[0].iov_base = payload_read;
7431 : 180 : iov[0].iov_len = 1 * 512;
7432 : 180 : iov[1].iov_base = payload_read + 1 * 512;
7433 : 180 : iov[1].iov_len = 8 * 512;
7434 : 180 : iov[2].iov_base = payload_read + 9 * 512;
7435 : 180 : iov[2].iov_len = 16 * 512;
7436 : 180 : iov[3].iov_base = payload_read + 25 * 512;
7437 : 180 : iov[3].iov_len = (2 * SZ - 25) * 512;
7438 : :
7439 [ + + ]: 180 : test_blob_io_readv(blob, channel, iov, 4, 0, SZ * 2, blob_op_complete, NULL,
7440 : : ext_api ? &ext_opts : NULL);
7441 : :
7442 [ - + - + ]: 180 : CU_ASSERT(memcmp(payload_read + 0 * 512, payload_ff, 512) == 0);
7443 [ - + - + ]: 180 : CU_ASSERT(memcmp(payload_read + 1 * 512, payload_00, 512) == 0);
7444 [ - + - + ]: 180 : CU_ASSERT(memcmp(payload_read + 2 * 512, payload_ff, 512) == 0);
7445 [ - + - + ]: 180 : CU_ASSERT(memcmp(payload_read + 3 * 512, payload_00, 512) == 0);
7446 [ - + - + ]: 180 : CU_ASSERT(memcmp(payload_read + 4 * 512, payload_aa, 8 * 512) == 0);
7447 [ - + - + ]: 180 : CU_ASSERT(memcmp(payload_read + (SZ - 4) * 512, payload_ff, 4 * 512) == 0);
7448 : :
7449 [ - + - + ]: 180 : CU_ASSERT(memcmp(payload_read + (SZ + 0) * 512, payload_ff, 4 * 512) == 0);
7450 [ - + - + ]: 180 : CU_ASSERT(memcmp(payload_read + (SZ + 4) * 512, payload_00, 8 * 512) == 0);
7451 [ - + - + ]: 180 : CU_ASSERT(memcmp(payload_read + (SZ + 12) * 512, payload_ff, 2 * 512) == 0);
7452 [ - + - + ]: 180 : CU_ASSERT(memcmp(payload_read + (SZ + 14) * 512, payload_00, (SZ - 14) * 512) == 0);
7453 : 180 : }
7454 : :
7455 : : static void
7456 : 15 : blob_io_unit(void)
7457 : : {
7458 : 15 : struct spdk_bs_opts bsopts;
7459 : 15 : struct spdk_blob_opts opts;
7460 : : struct spdk_blob_store *bs;
7461 : : struct spdk_bs_dev *dev;
7462 : : struct spdk_blob *blob, *snapshot, *clone;
7463 : : spdk_blob_id blobid;
7464 : : struct spdk_io_channel *channel;
7465 : :
7466 : : /* Create dev with 512 bytes io unit size */
7467 : :
7468 : 15 : spdk_bs_opts_init(&bsopts, sizeof(bsopts));
7469 : 15 : bsopts.cluster_sz = IO_UT_BLOCKS_PER_CLUSTER * 512;
7470 [ - + ]: 15 : snprintf(bsopts.bstype.bstype, sizeof(bsopts.bstype.bstype), "TESTTYPE");
7471 : :
7472 : : /* Try to initialize a new blob store with unsupported io_unit */
7473 : 15 : dev = init_dev();
7474 : 15 : dev->blocklen = 512;
7475 [ - + ]: 15 : dev->blockcnt = DEV_BUFFER_SIZE / dev->blocklen;
7476 : :
7477 : : /* Initialize a new blob store */
7478 : 15 : spdk_bs_init(dev, &bsopts, bs_op_with_handle_complete, NULL);
7479 : 15 : poll_threads();
7480 : 15 : CU_ASSERT(g_bserrno == 0);
7481 [ - + ]: 15 : SPDK_CU_ASSERT_FATAL(g_bs != NULL);
7482 : 15 : bs = g_bs;
7483 : :
7484 : 15 : CU_ASSERT(spdk_bs_get_io_unit_size(bs) == 512);
7485 : 15 : channel = spdk_bs_alloc_io_channel(bs);
7486 : :
7487 : : /* Create thick provisioned blob */
7488 : 15 : ut_spdk_blob_opts_init(&opts);
7489 : 15 : opts.thin_provision = false;
7490 : 15 : opts.num_clusters = 32;
7491 : :
7492 : 15 : blob = ut_blob_create_and_open(bs, &opts);
7493 : 15 : blobid = spdk_blob_get_id(blob);
7494 : :
7495 : 15 : test_io_write(dev, blob, channel);
7496 : 15 : test_io_read(dev, blob, channel);
7497 : 15 : test_io_zeroes(dev, blob, channel);
7498 : :
7499 : 15 : test_iov_write(dev, blob, channel, false);
7500 : 15 : test_iov_read(dev, blob, channel, false);
7501 : 15 : test_io_zeroes(dev, blob, channel);
7502 : :
7503 : 15 : test_iov_write(dev, blob, channel, true);
7504 : 15 : test_iov_read(dev, blob, channel, true);
7505 : :
7506 : 15 : test_io_unmap(dev, blob, channel);
7507 : :
7508 : 15 : spdk_blob_close(blob, blob_op_complete, NULL);
7509 : 15 : poll_threads();
7510 : 15 : CU_ASSERT(g_bserrno == 0);
7511 : 15 : blob = NULL;
7512 : 15 : g_blob = NULL;
7513 : :
7514 : : /* Create thin provisioned blob */
7515 : :
7516 : 15 : ut_spdk_blob_opts_init(&opts);
7517 : 15 : opts.thin_provision = true;
7518 : 15 : opts.num_clusters = 32;
7519 : :
7520 : 15 : blob = ut_blob_create_and_open(bs, &opts);
7521 : 15 : blobid = spdk_blob_get_id(blob);
7522 : :
7523 : 15 : test_io_write(dev, blob, channel);
7524 : 15 : test_io_read(dev, blob, channel);
7525 : 15 : test_io_zeroes(dev, blob, channel);
7526 : :
7527 : 15 : test_iov_write(dev, blob, channel, false);
7528 : 15 : test_iov_read(dev, blob, channel, false);
7529 : 15 : test_io_zeroes(dev, blob, channel);
7530 : :
7531 : 15 : test_iov_write(dev, blob, channel, true);
7532 : 15 : test_iov_read(dev, blob, channel, true);
7533 : :
7534 : : /* Create snapshot */
7535 : :
7536 : 15 : spdk_bs_create_snapshot(bs, blobid, NULL, blob_op_with_id_complete, NULL);
7537 : 15 : poll_threads();
7538 : 15 : CU_ASSERT(g_bserrno == 0);
7539 : 15 : CU_ASSERT(g_blobid != SPDK_BLOBID_INVALID);
7540 : 15 : blobid = g_blobid;
7541 : :
7542 : 15 : spdk_bs_open_blob(bs, blobid, blob_op_with_handle_complete, NULL);
7543 : 15 : poll_threads();
7544 : 15 : CU_ASSERT(g_bserrno == 0);
7545 : 15 : CU_ASSERT(g_blob != NULL);
7546 : 15 : snapshot = g_blob;
7547 : :
7548 : 15 : spdk_bs_create_clone(bs, blobid, NULL, blob_op_with_id_complete, NULL);
7549 : 15 : poll_threads();
7550 : 15 : CU_ASSERT(g_bserrno == 0);
7551 : 15 : CU_ASSERT(g_blobid != SPDK_BLOBID_INVALID);
7552 : 15 : blobid = g_blobid;
7553 : :
7554 : 15 : spdk_bs_open_blob(bs, blobid, blob_op_with_handle_complete, NULL);
7555 : 15 : poll_threads();
7556 : 15 : CU_ASSERT(g_bserrno == 0);
7557 : 15 : CU_ASSERT(g_blob != NULL);
7558 : 15 : clone = g_blob;
7559 : :
7560 : 15 : test_io_read(dev, blob, channel);
7561 : 15 : test_io_read(dev, snapshot, channel);
7562 : 15 : test_io_read(dev, clone, channel);
7563 : :
7564 : 15 : test_iov_read(dev, blob, channel, false);
7565 : 15 : test_iov_read(dev, snapshot, channel, false);
7566 : 15 : test_iov_read(dev, clone, channel, false);
7567 : :
7568 : 15 : test_iov_read(dev, blob, channel, true);
7569 : 15 : test_iov_read(dev, snapshot, channel, true);
7570 : 15 : test_iov_read(dev, clone, channel, true);
7571 : :
7572 : : /* Inflate clone */
7573 : :
7574 : 15 : spdk_bs_inflate_blob(bs, channel, blobid, blob_op_complete, NULL);
7575 : 15 : poll_threads();
7576 : :
7577 : 15 : CU_ASSERT(g_bserrno == 0);
7578 : :
7579 : 15 : test_io_read(dev, clone, channel);
7580 : :
7581 : 15 : test_io_unmap(dev, clone, channel);
7582 : :
7583 : 15 : test_iov_write(dev, clone, channel, false);
7584 : 15 : test_iov_read(dev, clone, channel, false);
7585 : 15 : test_io_unmap(dev, clone, channel);
7586 : :
7587 : 15 : test_iov_write(dev, clone, channel, true);
7588 : 15 : test_iov_read(dev, clone, channel, true);
7589 : :
7590 : 15 : spdk_blob_close(blob, blob_op_complete, NULL);
7591 : 15 : spdk_blob_close(snapshot, blob_op_complete, NULL);
7592 : 15 : spdk_blob_close(clone, blob_op_complete, NULL);
7593 : 15 : poll_threads();
7594 : 15 : CU_ASSERT(g_bserrno == 0);
7595 : 15 : blob = NULL;
7596 : 15 : g_blob = NULL;
7597 : :
7598 : 15 : spdk_bs_free_io_channel(channel);
7599 : 15 : poll_threads();
7600 : :
7601 : : /* Unload the blob store */
7602 : 15 : spdk_bs_unload(bs, bs_op_complete, NULL);
7603 : 15 : poll_threads();
7604 : 15 : CU_ASSERT(g_bserrno == 0);
7605 : 15 : g_bs = NULL;
7606 : 15 : g_blob = NULL;
7607 : 15 : g_blobid = 0;
7608 : 15 : }
7609 : :
7610 : : static void
7611 : 15 : blob_io_unit_compatibility(void)
7612 : : {
7613 : 15 : struct spdk_bs_opts bsopts;
7614 : : struct spdk_blob_store *bs;
7615 : : struct spdk_bs_dev *dev;
7616 : : struct spdk_bs_super_block *super;
7617 : :
7618 : : /* Create dev with 512 bytes io unit size */
7619 : :
7620 : 15 : spdk_bs_opts_init(&bsopts, sizeof(bsopts));
7621 : 15 : bsopts.cluster_sz = g_phys_blocklen * 4;
7622 [ - + ]: 15 : snprintf(bsopts.bstype.bstype, sizeof(bsopts.bstype.bstype), "TESTTYPE");
7623 : :
7624 : : /* Try to initialize a new blob store with unsupported io_unit */
7625 : 15 : dev = init_dev();
7626 : 15 : dev->blocklen = 512;
7627 [ - + ]: 15 : dev->blockcnt = DEV_BUFFER_SIZE / dev->blocklen;
7628 : :
7629 : : /* Initialize a new blob store */
7630 : 15 : spdk_bs_init(dev, &bsopts, bs_op_with_handle_complete, NULL);
7631 : 15 : poll_threads();
7632 : 15 : CU_ASSERT(g_bserrno == 0);
7633 [ - + ]: 15 : SPDK_CU_ASSERT_FATAL(g_bs != NULL);
7634 : 15 : bs = g_bs;
7635 : :
7636 : 15 : CU_ASSERT(spdk_bs_get_io_unit_size(bs) == 512);
7637 : :
7638 : : /* Unload the blob store */
7639 : 15 : spdk_bs_unload(bs, bs_op_complete, NULL);
7640 : 15 : poll_threads();
7641 : 15 : CU_ASSERT(g_bserrno == 0);
7642 : :
7643 : : /* Modify super block to behave like older version.
7644 : : * Check if loaded io unit size equals SPDK_BS_PAGE_SIZE */
7645 : 15 : super = (struct spdk_bs_super_block *)&g_dev_buffer[0];
7646 : 15 : super->io_unit_size = 0;
7647 : 15 : super->crc = blob_md_page_calc_crc(super);
7648 : :
7649 : 15 : dev = init_dev();
7650 : 15 : dev->blocklen = 512;
7651 [ - + ]: 15 : dev->blockcnt = DEV_BUFFER_SIZE / dev->blocklen;
7652 : :
7653 : 15 : spdk_bs_load(dev, &bsopts, bs_op_with_handle_complete, NULL);
7654 : 15 : poll_threads();
7655 : 15 : CU_ASSERT(g_bserrno == 0);
7656 [ - + ]: 15 : SPDK_CU_ASSERT_FATAL(g_bs != NULL);
7657 : 15 : bs = g_bs;
7658 : :
7659 : 15 : CU_ASSERT(spdk_bs_get_io_unit_size(bs) == SPDK_BS_PAGE_SIZE);
7660 : :
7661 : : /* Unload the blob store */
7662 : 15 : spdk_bs_unload(bs, bs_op_complete, NULL);
7663 : 15 : poll_threads();
7664 : 15 : CU_ASSERT(g_bserrno == 0);
7665 : :
7666 : 15 : g_bs = NULL;
7667 : 15 : g_blob = NULL;
7668 : 15 : g_blobid = 0;
7669 : 15 : }
7670 : :
7671 : : static void
7672 : 15 : first_sync_complete(void *cb_arg, int bserrno)
7673 : : {
7674 : 15 : struct spdk_blob *blob = cb_arg;
7675 : : int rc;
7676 : :
7677 : 15 : CU_ASSERT(bserrno == 0);
7678 : 15 : rc = spdk_blob_set_xattr(blob, "sync", "second", strlen("second") + 1);
7679 : 15 : CU_ASSERT(rc == 0);
7680 : 15 : CU_ASSERT(g_bserrno == -1);
7681 : :
7682 : : /* Keep g_bserrno at -1, only the
7683 : : * second sync completion should set it at 0. */
7684 : 15 : }
7685 : :
7686 : : static void
7687 : 15 : second_sync_complete(void *cb_arg, int bserrno)
7688 : : {
7689 : 15 : struct spdk_blob *blob = cb_arg;
7690 : 15 : const void *value;
7691 : 15 : size_t value_len;
7692 : : int rc;
7693 : :
7694 : 15 : CU_ASSERT(bserrno == 0);
7695 : :
7696 : : /* Verify that the first sync completion had a chance to execute */
7697 : 15 : rc = spdk_blob_get_xattr_value(blob, "sync", &value, &value_len);
7698 : 15 : CU_ASSERT(rc == 0);
7699 [ - + ]: 15 : SPDK_CU_ASSERT_FATAL(value != NULL);
7700 : 15 : CU_ASSERT(value_len == strlen("second") + 1);
7701 [ - + ]: 15 : CU_ASSERT_NSTRING_EQUAL_FATAL(value, "second", value_len);
7702 : :
7703 : 15 : CU_ASSERT(g_bserrno == -1);
7704 : 15 : g_bserrno = bserrno;
7705 : 15 : }
7706 : :
7707 : : static void
7708 : 15 : blob_simultaneous_operations(void)
7709 : : {
7710 : 15 : struct spdk_blob_store *bs = g_bs;
7711 : 15 : struct spdk_blob_opts opts;
7712 : : struct spdk_blob *blob, *snapshot;
7713 : : spdk_blob_id blobid, snapshotid;
7714 : : struct spdk_io_channel *channel;
7715 : : int rc;
7716 : :
7717 : 15 : channel = spdk_bs_alloc_io_channel(bs);
7718 [ - + ]: 15 : SPDK_CU_ASSERT_FATAL(channel != NULL);
7719 : :
7720 : 15 : ut_spdk_blob_opts_init(&opts);
7721 : 15 : opts.num_clusters = 10;
7722 : :
7723 : 15 : blob = ut_blob_create_and_open(bs, &opts);
7724 : 15 : blobid = spdk_blob_get_id(blob);
7725 : :
7726 : : /* Create snapshot and try to remove blob in the same time:
7727 : : * - snapshot should be created successfully
7728 : : * - delete operation should fail w -EBUSY */
7729 [ - + ]: 15 : CU_ASSERT(blob->locked_operation_in_progress == false);
7730 : 15 : spdk_bs_create_snapshot(bs, blobid, NULL, blob_op_with_id_complete, NULL);
7731 [ - + ]: 15 : CU_ASSERT(blob->locked_operation_in_progress == true);
7732 : 15 : spdk_bs_delete_blob(bs, blobid, blob_op_complete, NULL);
7733 [ - + ]: 15 : CU_ASSERT(blob->locked_operation_in_progress == true);
7734 : : /* Deletion failure */
7735 : 15 : CU_ASSERT(g_bserrno == -EBUSY);
7736 : 15 : poll_threads();
7737 [ - + ]: 15 : CU_ASSERT(blob->locked_operation_in_progress == false);
7738 : : /* Snapshot creation success */
7739 : 15 : CU_ASSERT(g_bserrno == 0);
7740 : 15 : CU_ASSERT(g_blobid != SPDK_BLOBID_INVALID);
7741 : :
7742 : 15 : snapshotid = g_blobid;
7743 : :
7744 : 15 : spdk_bs_open_blob(bs, snapshotid, blob_op_with_handle_complete, NULL);
7745 : 15 : poll_threads();
7746 : 15 : CU_ASSERT(g_bserrno == 0);
7747 [ - + ]: 15 : SPDK_CU_ASSERT_FATAL(g_blob != NULL);
7748 : 15 : snapshot = g_blob;
7749 : :
7750 : : /* Inflate blob and try to remove blob in the same time:
7751 : : * - blob should be inflated successfully
7752 : : * - delete operation should fail w -EBUSY */
7753 [ - + ]: 15 : CU_ASSERT(blob->locked_operation_in_progress == false);
7754 : 15 : spdk_bs_inflate_blob(bs, channel, blobid, blob_op_complete, NULL);
7755 [ - + ]: 15 : CU_ASSERT(blob->locked_operation_in_progress == true);
7756 : 15 : spdk_bs_delete_blob(bs, blobid, blob_op_complete, NULL);
7757 [ - + ]: 15 : CU_ASSERT(blob->locked_operation_in_progress == true);
7758 : : /* Deletion failure */
7759 : 15 : CU_ASSERT(g_bserrno == -EBUSY);
7760 : 15 : poll_threads();
7761 [ - + ]: 15 : CU_ASSERT(blob->locked_operation_in_progress == false);
7762 : : /* Inflation success */
7763 : 15 : CU_ASSERT(g_bserrno == 0);
7764 : :
7765 : : /* Clone snapshot and try to remove snapshot in the same time:
7766 : : * - snapshot should be cloned successfully
7767 : : * - delete operation should fail w -EBUSY */
7768 [ - + ]: 15 : CU_ASSERT(blob->locked_operation_in_progress == false);
7769 : 15 : spdk_bs_create_clone(bs, snapshotid, NULL, blob_op_with_id_complete, NULL);
7770 : 15 : spdk_bs_delete_blob(bs, snapshotid, blob_op_complete, NULL);
7771 : : /* Deletion failure */
7772 : 15 : CU_ASSERT(g_bserrno == -EBUSY);
7773 : 15 : poll_threads();
7774 [ - + ]: 15 : CU_ASSERT(blob->locked_operation_in_progress == false);
7775 : : /* Clone created */
7776 : 15 : CU_ASSERT(g_bserrno == 0);
7777 : :
7778 : : /* Resize blob and try to remove blob in the same time:
7779 : : * - blob should be resized successfully
7780 : : * - delete operation should fail w -EBUSY */
7781 [ - + ]: 15 : CU_ASSERT(blob->locked_operation_in_progress == false);
7782 : 15 : spdk_blob_resize(blob, 50, blob_op_complete, NULL);
7783 [ - + ]: 15 : CU_ASSERT(blob->locked_operation_in_progress == true);
7784 : 15 : spdk_bs_delete_blob(bs, blobid, blob_op_complete, NULL);
7785 [ - + ]: 15 : CU_ASSERT(blob->locked_operation_in_progress == true);
7786 : : /* Deletion failure */
7787 : 15 : CU_ASSERT(g_bserrno == -EBUSY);
7788 : 15 : poll_threads();
7789 [ - + ]: 15 : CU_ASSERT(blob->locked_operation_in_progress == false);
7790 : : /* Blob resized successfully */
7791 : 15 : spdk_blob_sync_md(blob, blob_op_complete, NULL);
7792 : 15 : poll_threads();
7793 : 15 : CU_ASSERT(g_bserrno == 0);
7794 : :
7795 : : /* Issue two consecutive blob syncs, neither should fail.
7796 : : * Force sync to actually occur by marking blob dirty each time.
7797 : : * Execution of sync should not be enough to complete the operation,
7798 : : * since disk I/O is required to complete it. */
7799 : 15 : g_bserrno = -1;
7800 : :
7801 : 15 : rc = spdk_blob_set_xattr(blob, "sync", "first", strlen("first") + 1);
7802 : 15 : CU_ASSERT(rc == 0);
7803 : 15 : spdk_blob_sync_md(blob, first_sync_complete, blob);
7804 : 15 : CU_ASSERT(g_bserrno == -1);
7805 : :
7806 : 15 : spdk_blob_sync_md(blob, second_sync_complete, blob);
7807 : 15 : CU_ASSERT(g_bserrno == -1);
7808 : :
7809 : 15 : poll_threads();
7810 : 15 : CU_ASSERT(g_bserrno == 0);
7811 : :
7812 : 15 : spdk_bs_free_io_channel(channel);
7813 : 15 : poll_threads();
7814 : :
7815 : 15 : ut_blob_close_and_delete(bs, snapshot);
7816 : 15 : ut_blob_close_and_delete(bs, blob);
7817 : 15 : }
7818 : :
7819 : : static void
7820 : 15 : blob_persist_test(void)
7821 : : {
7822 : 15 : struct spdk_blob_store *bs = g_bs;
7823 : 15 : struct spdk_blob_opts opts;
7824 : : struct spdk_blob *blob;
7825 : : spdk_blob_id blobid;
7826 : : struct spdk_io_channel *channel;
7827 : 15 : char *xattr;
7828 : 15 : size_t xattr_length;
7829 : : int rc;
7830 : : uint32_t page_count_clear, page_count_xattr;
7831 : : uint64_t poller_iterations;
7832 : : bool run_poller;
7833 : :
7834 : 15 : channel = spdk_bs_alloc_io_channel(bs);
7835 [ - + ]: 15 : SPDK_CU_ASSERT_FATAL(channel != NULL);
7836 : :
7837 : 15 : ut_spdk_blob_opts_init(&opts);
7838 : 15 : opts.num_clusters = 10;
7839 : :
7840 : 15 : blob = ut_blob_create_and_open(bs, &opts);
7841 : 15 : blobid = spdk_blob_get_id(blob);
7842 : :
7843 : : /* Save the amount of md pages used after creation of a blob.
7844 : : * This should be consistent after removing xattr. */
7845 : 15 : page_count_clear = spdk_bit_array_count_set(bs->used_md_pages);
7846 [ - + ]: 15 : SPDK_CU_ASSERT_FATAL(blob->active.num_pages + blob->active.num_extent_pages == page_count_clear);
7847 [ - + ]: 15 : SPDK_CU_ASSERT_FATAL(blob->clean.num_pages + blob->clean.num_extent_pages == page_count_clear);
7848 : :
7849 : : /* Add xattr with maximum length of descriptor to exceed single metadata page. */
7850 : 15 : xattr_length = SPDK_BS_MAX_DESC_SIZE - sizeof(struct spdk_blob_md_descriptor_xattr) -
7851 : : strlen("large_xattr");
7852 : 15 : xattr = calloc(xattr_length, sizeof(char));
7853 [ - + ]: 15 : SPDK_CU_ASSERT_FATAL(xattr != NULL);
7854 : :
7855 : 15 : rc = spdk_blob_set_xattr(blob, "large_xattr", xattr, xattr_length);
7856 [ - + ]: 15 : SPDK_CU_ASSERT_FATAL(rc == 0);
7857 : 15 : spdk_blob_sync_md(blob, blob_op_complete, NULL);
7858 : 15 : poll_threads();
7859 [ - + ]: 15 : SPDK_CU_ASSERT_FATAL(g_bserrno == 0);
7860 : :
7861 : : /* Save the amount of md pages used after adding the large xattr */
7862 : 15 : page_count_xattr = spdk_bit_array_count_set(bs->used_md_pages);
7863 [ - + ]: 15 : SPDK_CU_ASSERT_FATAL(blob->active.num_pages + blob->active.num_extent_pages == page_count_xattr);
7864 [ - + ]: 15 : SPDK_CU_ASSERT_FATAL(blob->clean.num_pages + blob->clean.num_extent_pages == page_count_xattr);
7865 : :
7866 : : /* Add xattr to a blob and sync it. While sync is occurring, remove the xattr and sync again.
7867 : : * Interrupt the first sync after increasing number of poller iterations, until it succeeds.
7868 : : * Expectation is that after second sync completes no xattr is saved in metadata. */
7869 : 15 : poller_iterations = 1;
7870 : 15 : run_poller = true;
7871 [ + + ]: 105 : while (run_poller) {
7872 : 90 : rc = spdk_blob_set_xattr(blob, "large_xattr", xattr, xattr_length);
7873 [ - + ]: 90 : SPDK_CU_ASSERT_FATAL(rc == 0);
7874 : 90 : g_bserrno = -1;
7875 : 90 : spdk_blob_sync_md(blob, blob_op_complete, NULL);
7876 : 90 : poll_thread_times(0, poller_iterations);
7877 [ + + ]: 90 : if (g_bserrno == 0) {
7878 : : /* Poller iteration count was high enough for first sync to complete.
7879 : : * Verify that blob takes up enough of md_pages to store the xattr. */
7880 [ - + ]: 15 : SPDK_CU_ASSERT_FATAL(blob->active.num_pages + blob->active.num_extent_pages == page_count_xattr);
7881 [ - + ]: 15 : SPDK_CU_ASSERT_FATAL(blob->clean.num_pages + blob->clean.num_extent_pages == page_count_xattr);
7882 [ - + ]: 15 : SPDK_CU_ASSERT_FATAL(spdk_bit_array_count_set(bs->used_md_pages) == page_count_xattr);
7883 : 15 : run_poller = false;
7884 : : }
7885 : 90 : rc = spdk_blob_remove_xattr(blob, "large_xattr");
7886 [ - + ]: 90 : SPDK_CU_ASSERT_FATAL(rc == 0);
7887 : 90 : spdk_blob_sync_md(blob, blob_op_complete, NULL);
7888 : 90 : poll_threads();
7889 [ - + ]: 90 : SPDK_CU_ASSERT_FATAL(g_bserrno == 0);
7890 [ - + ]: 90 : SPDK_CU_ASSERT_FATAL(blob->active.num_pages + blob->active.num_extent_pages == page_count_clear);
7891 [ - + ]: 90 : SPDK_CU_ASSERT_FATAL(blob->clean.num_pages + blob->clean.num_extent_pages == page_count_clear);
7892 [ - + ]: 90 : SPDK_CU_ASSERT_FATAL(spdk_bit_array_count_set(bs->used_md_pages) == page_count_clear);
7893 : :
7894 : : /* Reload bs and re-open blob to verify that xattr was not persisted. */
7895 : 90 : spdk_blob_close(blob, blob_op_complete, NULL);
7896 : 90 : poll_threads();
7897 : 90 : CU_ASSERT(g_bserrno == 0);
7898 : :
7899 : 90 : ut_bs_reload(&bs, NULL);
7900 : :
7901 : 90 : spdk_bs_open_blob(bs, blobid, blob_op_with_handle_complete, NULL);
7902 : 90 : poll_threads();
7903 : 90 : CU_ASSERT(g_bserrno == 0);
7904 [ - + ]: 90 : SPDK_CU_ASSERT_FATAL(g_blob != NULL);
7905 : 90 : blob = g_blob;
7906 : :
7907 : 90 : rc = spdk_blob_get_xattr_value(blob, "large_xattr", (const void **)&xattr, &xattr_length);
7908 [ - + ]: 90 : SPDK_CU_ASSERT_FATAL(rc == -ENOENT);
7909 : :
7910 : 90 : poller_iterations++;
7911 : : /* Stop at high iteration count to prevent infinite loop.
7912 : : * This value should be enough for first md sync to complete in any case. */
7913 [ - + ]: 90 : SPDK_CU_ASSERT_FATAL(poller_iterations < 50);
7914 : : }
7915 : :
7916 : 15 : free(xattr);
7917 : :
7918 : 15 : ut_blob_close_and_delete(bs, blob);
7919 : :
7920 : 15 : spdk_bs_free_io_channel(channel);
7921 : 15 : poll_threads();
7922 : 15 : }
7923 : :
7924 : : static void
7925 : 15 : blob_decouple_snapshot(void)
7926 : : {
7927 : 15 : struct spdk_blob_store *bs = g_bs;
7928 : 15 : struct spdk_blob_opts opts;
7929 : : struct spdk_blob *blob, *snapshot1, *snapshot2;
7930 : : struct spdk_io_channel *channel;
7931 : : spdk_blob_id blobid, snapshotid;
7932 : : uint64_t cluster;
7933 : :
7934 [ + + ]: 45 : for (int delete_snapshot_first = 0; delete_snapshot_first <= 1; delete_snapshot_first++) {
7935 : 30 : channel = spdk_bs_alloc_io_channel(bs);
7936 [ - + ]: 30 : SPDK_CU_ASSERT_FATAL(channel != NULL);
7937 : :
7938 : 30 : ut_spdk_blob_opts_init(&opts);
7939 : 30 : opts.num_clusters = 10;
7940 : 30 : opts.thin_provision = false;
7941 : :
7942 : 30 : blob = ut_blob_create_and_open(bs, &opts);
7943 : 30 : blobid = spdk_blob_get_id(blob);
7944 : :
7945 : : /* Create first snapshot */
7946 : 30 : CU_ASSERT_EQUAL(_get_snapshots_count(bs), 0);
7947 : 30 : spdk_bs_create_snapshot(bs, blobid, NULL, blob_op_with_id_complete, NULL);
7948 : 30 : poll_threads();
7949 : 30 : CU_ASSERT(g_bserrno == 0);
7950 : 30 : CU_ASSERT(g_blobid != SPDK_BLOBID_INVALID);
7951 : 30 : CU_ASSERT_EQUAL(_get_snapshots_count(bs), 1);
7952 : 30 : snapshotid = g_blobid;
7953 : :
7954 : 30 : spdk_bs_open_blob(bs, snapshotid, blob_op_with_handle_complete, NULL);
7955 : 30 : poll_threads();
7956 : 30 : CU_ASSERT(g_bserrno == 0);
7957 [ - + ]: 30 : SPDK_CU_ASSERT_FATAL(g_blob != NULL);
7958 : 30 : snapshot1 = g_blob;
7959 : :
7960 : : /* Create the second one */
7961 : 30 : CU_ASSERT_EQUAL(_get_snapshots_count(bs), 1);
7962 : 30 : spdk_bs_create_snapshot(bs, blobid, NULL, blob_op_with_id_complete, NULL);
7963 : 30 : poll_threads();
7964 : 30 : CU_ASSERT(g_bserrno == 0);
7965 : 30 : CU_ASSERT(g_blobid != SPDK_BLOBID_INVALID);
7966 : 30 : CU_ASSERT_EQUAL(_get_snapshots_count(bs), 2);
7967 : 30 : snapshotid = g_blobid;
7968 : :
7969 : 30 : spdk_bs_open_blob(bs, snapshotid, blob_op_with_handle_complete, NULL);
7970 : 30 : poll_threads();
7971 : 30 : CU_ASSERT(g_bserrno == 0);
7972 [ - + ]: 30 : SPDK_CU_ASSERT_FATAL(g_blob != NULL);
7973 : 30 : snapshot2 = g_blob;
7974 : 30 : CU_ASSERT_EQUAL(spdk_blob_get_parent_snapshot(bs, snapshot2->id), snapshot1->id);
7975 : :
7976 : : /* Now decouple the second snapshot forcing it to copy the written clusters */
7977 : 30 : spdk_bs_blob_decouple_parent(bs, channel, snapshot2->id, blob_op_complete, NULL);
7978 : 30 : poll_threads();
7979 : 30 : CU_ASSERT(g_bserrno == 0);
7980 : :
7981 : : /* Verify that the snapshot has been decoupled and that the clusters have been copied */
7982 : 30 : CU_ASSERT_EQUAL(spdk_blob_get_parent_snapshot(bs, snapshot2->id), SPDK_BLOBID_INVALID);
7983 [ + + ]: 330 : for (cluster = 0; cluster < snapshot2->active.num_clusters; ++cluster) {
7984 : 300 : CU_ASSERT_NOT_EQUAL(snapshot2->active.clusters[cluster], 0);
7985 : 300 : CU_ASSERT_NOT_EQUAL(snapshot2->active.clusters[cluster],
7986 : : snapshot1->active.clusters[cluster]);
7987 : : }
7988 : :
7989 : 30 : spdk_bs_free_io_channel(channel);
7990 : :
7991 [ + + ]: 30 : if (delete_snapshot_first) {
7992 : 15 : ut_blob_close_and_delete(bs, snapshot2);
7993 : 15 : ut_blob_close_and_delete(bs, snapshot1);
7994 : 15 : ut_blob_close_and_delete(bs, blob);
7995 : : } else {
7996 : 15 : ut_blob_close_and_delete(bs, blob);
7997 : 15 : ut_blob_close_and_delete(bs, snapshot2);
7998 : 15 : ut_blob_close_and_delete(bs, snapshot1);
7999 : : }
8000 : 30 : poll_threads();
8001 : : }
8002 : 15 : }
8003 : :
8004 : : static void
8005 : 15 : blob_seek_io_unit(void)
8006 : : {
8007 : 15 : struct spdk_blob_store *bs = g_bs;
8008 : : struct spdk_blob *blob;
8009 : : struct spdk_io_channel *channel;
8010 : 15 : struct spdk_blob_opts opts;
8011 : : uint64_t free_clusters;
8012 : 15 : uint8_t payload[10 * BLOCKLEN];
8013 : : uint64_t offset;
8014 : : uint64_t io_unit, io_units_per_cluster;
8015 : :
8016 : 15 : free_clusters = spdk_bs_free_cluster_count(bs);
8017 : :
8018 : 15 : channel = spdk_bs_alloc_io_channel(bs);
8019 : 15 : CU_ASSERT(channel != NULL);
8020 : :
8021 : : /* Set blob as thin provisioned */
8022 : 15 : ut_spdk_blob_opts_init(&opts);
8023 : 15 : opts.thin_provision = true;
8024 : :
8025 : : /* Create a blob */
8026 : 15 : blob = ut_blob_create_and_open(bs, &opts);
8027 : 15 : CU_ASSERT(free_clusters == spdk_bs_free_cluster_count(bs));
8028 : :
8029 : 15 : io_units_per_cluster = bs_io_units_per_cluster(blob);
8030 : :
8031 : : /* The blob started at 0 clusters. Resize it to be 5, but still unallocated. */
8032 : 15 : spdk_blob_resize(blob, 5, blob_op_complete, NULL);
8033 : 15 : poll_threads();
8034 : 15 : CU_ASSERT(g_bserrno == 0);
8035 : 15 : CU_ASSERT(free_clusters == spdk_bs_free_cluster_count(bs));
8036 : 15 : CU_ASSERT(blob->active.num_clusters == 5);
8037 : :
8038 : : /* Write at the beginning of first cluster */
8039 : 15 : offset = 0;
8040 : 15 : spdk_blob_io_write(blob, channel, payload, offset, 1, blob_op_complete, NULL);
8041 : 15 : poll_threads();
8042 : 15 : CU_ASSERT(g_bserrno == 0);
8043 : :
8044 : 15 : io_unit = spdk_blob_get_next_allocated_io_unit(blob, 0);
8045 : 15 : CU_ASSERT(io_unit == offset);
8046 : :
8047 : 15 : io_unit = spdk_blob_get_next_unallocated_io_unit(blob, 0);
8048 : 15 : CU_ASSERT(io_unit == io_units_per_cluster);
8049 : :
8050 : : /* Write in the middle of third cluster */
8051 : 15 : offset = 2 * io_units_per_cluster + io_units_per_cluster / 2;
8052 : 15 : spdk_blob_io_write(blob, channel, payload, offset, 1, blob_op_complete, NULL);
8053 : 15 : poll_threads();
8054 : 15 : CU_ASSERT(g_bserrno == 0);
8055 : :
8056 : 15 : io_unit = spdk_blob_get_next_allocated_io_unit(blob, io_units_per_cluster);
8057 : 15 : CU_ASSERT(io_unit == 2 * io_units_per_cluster);
8058 : :
8059 : 15 : io_unit = spdk_blob_get_next_unallocated_io_unit(blob, 2 * io_units_per_cluster);
8060 : 15 : CU_ASSERT(io_unit == 3 * io_units_per_cluster);
8061 : :
8062 : : /* Write at the end of last cluster */
8063 : 15 : offset = 5 * io_units_per_cluster - 1;
8064 : 15 : spdk_blob_io_write(blob, channel, payload, offset, 1, blob_op_complete, NULL);
8065 : 15 : poll_threads();
8066 : 15 : CU_ASSERT(g_bserrno == 0);
8067 : :
8068 : 15 : io_unit = spdk_blob_get_next_allocated_io_unit(blob, 3 * io_units_per_cluster);
8069 : 15 : CU_ASSERT(io_unit == 4 * io_units_per_cluster);
8070 : :
8071 : 15 : io_unit = spdk_blob_get_next_unallocated_io_unit(blob, 4 * io_units_per_cluster);
8072 : 15 : CU_ASSERT(io_unit == UINT64_MAX);
8073 : :
8074 : 15 : spdk_bs_free_io_channel(channel);
8075 : 15 : poll_threads();
8076 : :
8077 : 15 : ut_blob_close_and_delete(bs, blob);
8078 : 15 : }
8079 : :
8080 : : static void
8081 : 15 : blob_esnap_create(void)
8082 : : {
8083 : 15 : struct spdk_blob_store *bs = g_bs;
8084 : 15 : struct spdk_bs_opts bs_opts;
8085 : 15 : struct ut_esnap_opts esnap_opts;
8086 : 15 : struct spdk_blob_opts opts;
8087 : 15 : struct spdk_blob_open_opts open_opts;
8088 : : struct spdk_blob *blob;
8089 : : uint32_t cluster_sz, block_sz;
8090 : 15 : const uint32_t esnap_num_clusters = 4;
8091 : : uint64_t esnap_num_blocks;
8092 : : uint32_t sz;
8093 : : spdk_blob_id blobid;
8094 : 15 : uint32_t bs_ctx_count, blob_ctx_count;
8095 : :
8096 : 15 : cluster_sz = spdk_bs_get_cluster_size(bs);
8097 : 15 : block_sz = spdk_bs_get_io_unit_size(bs);
8098 [ - + ]: 15 : esnap_num_blocks = cluster_sz * esnap_num_clusters / block_sz;
8099 : :
8100 : : /* Create a normal blob and verify it is not an esnap clone. */
8101 : 15 : ut_spdk_blob_opts_init(&opts);
8102 : 15 : blob = ut_blob_create_and_open(bs, &opts);
8103 : 15 : CU_ASSERT(!spdk_blob_is_esnap_clone(blob));
8104 : 15 : ut_blob_close_and_delete(bs, blob);
8105 : :
8106 : : /* Create an esnap clone blob then verify it is an esnap clone and has the right size */
8107 : 15 : ut_spdk_blob_opts_init(&opts);
8108 : 15 : ut_esnap_opts_init(block_sz, esnap_num_blocks, __func__, NULL, &esnap_opts);
8109 : 15 : opts.esnap_id = &esnap_opts;
8110 : 15 : opts.esnap_id_len = sizeof(esnap_opts);
8111 : 15 : opts.num_clusters = esnap_num_clusters;
8112 : 15 : blob = ut_blob_create_and_open(bs, &opts);
8113 [ - + ]: 15 : SPDK_CU_ASSERT_FATAL(blob != NULL);
8114 [ - + ]: 15 : SPDK_CU_ASSERT_FATAL(spdk_blob_is_esnap_clone(blob));
8115 [ - + ]: 15 : SPDK_CU_ASSERT_FATAL(blob_is_esnap_clone(blob));
8116 [ - + ]: 15 : SPDK_CU_ASSERT_FATAL(!spdk_blob_is_clone(blob));
8117 : 15 : sz = spdk_blob_get_num_clusters(blob);
8118 : 15 : CU_ASSERT(sz == esnap_num_clusters);
8119 : 15 : ut_blob_close_and_delete(bs, blob);
8120 : :
8121 : : /* Create an esnap clone without the size and verify it can be grown */
8122 : 15 : ut_spdk_blob_opts_init(&opts);
8123 : 15 : ut_esnap_opts_init(block_sz, esnap_num_blocks, __func__, NULL, &esnap_opts);
8124 : 15 : opts.esnap_id = &esnap_opts;
8125 : 15 : opts.esnap_id_len = sizeof(esnap_opts);
8126 : 15 : blob = ut_blob_create_and_open(bs, &opts);
8127 [ - + ]: 15 : SPDK_CU_ASSERT_FATAL(spdk_blob_is_esnap_clone(blob));
8128 : 15 : sz = spdk_blob_get_num_clusters(blob);
8129 : 15 : CU_ASSERT(sz == 0);
8130 : 15 : spdk_blob_resize(blob, 1, blob_op_complete, NULL);
8131 : 15 : poll_threads();
8132 : 15 : CU_ASSERT(g_bserrno == 0);
8133 : 15 : sz = spdk_blob_get_num_clusters(blob);
8134 : 15 : CU_ASSERT(sz == 1);
8135 : 15 : spdk_blob_resize(blob, esnap_num_clusters, blob_op_complete, NULL);
8136 : 15 : poll_threads();
8137 : 15 : CU_ASSERT(g_bserrno == 0);
8138 : 15 : sz = spdk_blob_get_num_clusters(blob);
8139 : 15 : CU_ASSERT(sz == esnap_num_clusters);
8140 : 15 : spdk_blob_resize(blob, esnap_num_clusters + 1, blob_op_complete, NULL);
8141 : 15 : poll_threads();
8142 : 15 : CU_ASSERT(g_bserrno == 0);
8143 : 15 : sz = spdk_blob_get_num_clusters(blob);
8144 : 15 : CU_ASSERT(sz == esnap_num_clusters + 1);
8145 : :
8146 : : /* Reload the blobstore and be sure that the blob can be opened. */
8147 : 15 : blobid = spdk_blob_get_id(blob);
8148 : 15 : spdk_blob_close(blob, blob_op_complete, NULL);
8149 : 15 : poll_threads();
8150 : 15 : CU_ASSERT(g_bserrno == 0);
8151 : 15 : g_blob = NULL;
8152 : 15 : spdk_bs_opts_init(&bs_opts, sizeof(bs_opts));
8153 : 15 : bs_opts.esnap_bs_dev_create = ut_esnap_create;
8154 : 15 : ut_bs_reload(&bs, &bs_opts);
8155 : 15 : spdk_bs_open_blob(bs, blobid, blob_op_with_handle_complete, NULL);
8156 : 15 : poll_threads();
8157 : 15 : CU_ASSERT(g_bserrno == 0);
8158 : 15 : CU_ASSERT(g_blob != NULL);
8159 : 15 : blob = g_blob;
8160 [ - + ]: 15 : SPDK_CU_ASSERT_FATAL(spdk_blob_is_esnap_clone(blob));
8161 : 15 : sz = spdk_blob_get_num_clusters(blob);
8162 : 15 : CU_ASSERT(sz == esnap_num_clusters + 1);
8163 : :
8164 : : /* Reload the blobstore without esnap_bs_dev_create: should fail to open blob. */
8165 : 15 : spdk_blob_close(blob, blob_op_complete, NULL);
8166 : 15 : poll_threads();
8167 : 15 : CU_ASSERT(g_bserrno == 0);
8168 : 15 : g_blob = NULL;
8169 : 15 : spdk_bs_opts_init(&bs_opts, sizeof(bs_opts));
8170 : 15 : ut_bs_reload(&bs, &bs_opts);
8171 : 15 : spdk_bs_open_blob(bs, blobid, blob_op_with_handle_complete, NULL);
8172 : 15 : poll_threads();
8173 : 15 : CU_ASSERT(g_bserrno != 0);
8174 : 15 : CU_ASSERT(g_blob == NULL);
8175 : :
8176 : : /* Reload the blobstore with ctx set and verify it is passed to the esnap create callback */
8177 : 15 : bs_ctx_count = 0;
8178 : 15 : spdk_bs_opts_init(&bs_opts, sizeof(bs_opts));
8179 : 15 : bs_opts.esnap_bs_dev_create = ut_esnap_create_with_count;
8180 : 15 : bs_opts.esnap_ctx = &bs_ctx_count;
8181 : 15 : ut_bs_reload(&bs, &bs_opts);
8182 : : /* Loading the blobstore triggers the esnap to be loaded */
8183 : 15 : CU_ASSERT(bs_ctx_count == 1);
8184 : 15 : spdk_bs_open_blob(bs, blobid, blob_op_with_handle_complete, NULL);
8185 : 15 : poll_threads();
8186 : 15 : CU_ASSERT(g_bserrno == 0);
8187 : 15 : CU_ASSERT(g_blob != NULL);
8188 : : /* Opening the blob also triggers the esnap to be loaded */
8189 : 15 : CU_ASSERT(bs_ctx_count == 2);
8190 : 15 : blob = g_blob;
8191 [ - + ]: 15 : SPDK_CU_ASSERT_FATAL(spdk_blob_is_esnap_clone(blob));
8192 : 15 : sz = spdk_blob_get_num_clusters(blob);
8193 : 15 : CU_ASSERT(sz == esnap_num_clusters + 1);
8194 : 15 : spdk_blob_close(blob, blob_op_complete, NULL);
8195 : 15 : poll_threads();
8196 : 15 : CU_ASSERT(g_bserrno == 0);
8197 : 15 : g_blob = NULL;
8198 : : /* If open_opts.esnap_ctx is set it is passed to the esnap create callback */
8199 : 15 : blob_ctx_count = 0;
8200 : 15 : spdk_blob_open_opts_init(&open_opts, sizeof(open_opts));
8201 : 15 : open_opts.esnap_ctx = &blob_ctx_count;
8202 : 15 : spdk_bs_open_blob_ext(bs, blobid, &open_opts, blob_op_with_handle_complete, NULL);
8203 : 15 : poll_threads();
8204 : 15 : blob = g_blob;
8205 : 15 : CU_ASSERT(bs_ctx_count == 3);
8206 : 15 : CU_ASSERT(blob_ctx_count == 1);
8207 : 15 : spdk_blob_close(blob, blob_op_complete, NULL);
8208 : 15 : poll_threads();
8209 : 15 : CU_ASSERT(g_bserrno == 0);
8210 : 15 : g_blob = NULL;
8211 : 15 : }
8212 : :
8213 : : static void
8214 : 15 : blob_esnap_clone_reload(void)
8215 : 15 : {
8216 : 15 : struct spdk_blob_store *bs = g_bs;
8217 : 15 : struct spdk_bs_opts bs_opts;
8218 : 15 : struct ut_esnap_opts esnap_opts;
8219 : 15 : struct spdk_blob_opts opts;
8220 : : struct spdk_blob *eclone1, *snap1, *clone1;
8221 : 15 : uint32_t cluster_sz = spdk_bs_get_cluster_size(bs);
8222 : 15 : uint32_t block_sz = spdk_bs_get_io_unit_size(bs);
8223 : 15 : const uint32_t esnap_num_clusters = 4;
8224 [ - + ]: 15 : uint64_t esnap_num_blocks = cluster_sz * esnap_num_clusters / block_sz;
8225 : : spdk_blob_id eclone1_id, snap1_id, clone1_id;
8226 : : struct spdk_io_channel *bs_ch;
8227 [ - + ]: 15 : char buf[block_sz];
8228 : 15 : int bserr1, bserr2, bserr3, bserr4;
8229 : : struct spdk_bs_dev *dev;
8230 : :
8231 : : /* Create and open an esnap clone blob */
8232 : 15 : ut_spdk_blob_opts_init(&opts);
8233 : 15 : ut_esnap_opts_init(block_sz, esnap_num_blocks, __func__, NULL, &esnap_opts);
8234 : 15 : opts.esnap_id = &esnap_opts;
8235 : 15 : opts.esnap_id_len = sizeof(esnap_opts);
8236 : 15 : opts.num_clusters = esnap_num_clusters;
8237 : 15 : eclone1 = ut_blob_create_and_open(bs, &opts);
8238 : 15 : CU_ASSERT(eclone1 != NULL);
8239 : 15 : CU_ASSERT(spdk_blob_is_esnap_clone(eclone1));
8240 : 15 : eclone1_id = eclone1->id;
8241 : :
8242 : : /* Create and open a snapshot of eclone1 */
8243 : 15 : spdk_bs_create_snapshot(bs, eclone1_id, NULL, blob_op_with_id_complete, NULL);
8244 : 15 : poll_threads();
8245 : 15 : CU_ASSERT(g_blobid != SPDK_BLOBID_INVALID);
8246 : 15 : CU_ASSERT(g_bserrno == 0);
8247 : 15 : snap1_id = g_blobid;
8248 : 15 : spdk_bs_open_blob(bs, snap1_id, blob_op_with_handle_complete, NULL);
8249 : 15 : poll_threads();
8250 : 15 : CU_ASSERT(g_bserrno == 0);
8251 : 15 : CU_ASSERT(g_blob != NULL);
8252 : 15 : snap1 = g_blob;
8253 : :
8254 : : /* Create and open regular clone of snap1 */
8255 : 15 : spdk_bs_create_clone(bs, snap1_id, NULL, blob_op_with_id_complete, NULL);
8256 : 15 : poll_threads();
8257 : 15 : CU_ASSERT(g_blobid != SPDK_BLOBID_INVALID);
8258 [ - + ]: 15 : SPDK_CU_ASSERT_FATAL(g_bserrno == 0);
8259 : 15 : clone1_id = g_blobid;
8260 : 15 : spdk_bs_open_blob(bs, clone1_id, blob_op_with_handle_complete, NULL);
8261 : 15 : poll_threads();
8262 : 15 : CU_ASSERT(g_bserrno == 0);
8263 : 15 : CU_ASSERT(g_blob != NULL);
8264 : 15 : clone1 = g_blob;
8265 : :
8266 : : /* Close the blobs in preparation for reloading the blobstore */
8267 : 15 : spdk_blob_close(clone1, blob_op_complete, NULL);
8268 : 15 : poll_threads();
8269 : 15 : CU_ASSERT(g_bserrno == 0);
8270 : 15 : spdk_blob_close(snap1, blob_op_complete, NULL);
8271 : 15 : poll_threads();
8272 : 15 : CU_ASSERT(g_bserrno == 0);
8273 : 15 : spdk_blob_close(eclone1, blob_op_complete, NULL);
8274 : 15 : poll_threads();
8275 : 15 : CU_ASSERT(g_bserrno == 0);
8276 : 15 : g_blob = NULL;
8277 : :
8278 : : /* Reload the blobstore */
8279 : 15 : spdk_bs_opts_init(&bs_opts, sizeof(bs_opts));
8280 : 15 : bs_opts.esnap_bs_dev_create = ut_esnap_create;
8281 : 15 : ut_bs_reload(&bs, &bs_opts);
8282 : :
8283 : : /* Be sure each of the blobs can be opened */
8284 : 15 : spdk_bs_open_blob(bs, eclone1_id, blob_op_with_handle_complete, NULL);
8285 : 15 : poll_threads();
8286 : 15 : CU_ASSERT(g_bserrno == 0);
8287 : 15 : CU_ASSERT(g_blob != NULL);
8288 : 15 : eclone1 = g_blob;
8289 : 15 : spdk_bs_open_blob(bs, snap1_id, blob_op_with_handle_complete, NULL);
8290 : 15 : poll_threads();
8291 : 15 : CU_ASSERT(g_bserrno == 0);
8292 : 15 : CU_ASSERT(g_blob != NULL);
8293 : 15 : snap1 = g_blob;
8294 : 15 : spdk_bs_open_blob(bs, clone1_id, blob_op_with_handle_complete, NULL);
8295 : 15 : poll_threads();
8296 : 15 : CU_ASSERT(g_bserrno == 0);
8297 : 15 : CU_ASSERT(g_blob != NULL);
8298 : 15 : clone1 = g_blob;
8299 : :
8300 : : /* Perform some reads on each of them to cause channels to be allocated */
8301 : 15 : bs_ch = spdk_bs_alloc_io_channel(bs);
8302 : 15 : CU_ASSERT(bs_ch != NULL);
8303 : 15 : spdk_blob_io_read(eclone1, bs_ch, buf, 0, 1, bs_op_complete, NULL);
8304 : 15 : poll_threads();
8305 : 15 : CU_ASSERT(g_bserrno == 0);
8306 : 15 : spdk_blob_io_read(snap1, bs_ch, buf, 0, 1, bs_op_complete, NULL);
8307 : 15 : poll_threads();
8308 : 15 : CU_ASSERT(g_bserrno == 0);
8309 : 15 : spdk_blob_io_read(clone1, bs_ch, buf, 0, 1, bs_op_complete, NULL);
8310 : 15 : poll_threads();
8311 : 15 : CU_ASSERT(g_bserrno == 0);
8312 : :
8313 : : /*
8314 : : * Unload the blobstore in a way similar to how lvstore unloads it. This should exercise
8315 : : * the deferred unload path in spdk_bs_unload().
8316 : : */
8317 : 15 : bserr1 = 0xbad;
8318 : 15 : bserr2 = 0xbad;
8319 : 15 : bserr3 = 0xbad;
8320 : 15 : bserr4 = 0xbad;
8321 : 15 : spdk_blob_close(eclone1, blob_op_complete, &bserr1);
8322 : 15 : spdk_blob_close(snap1, blob_op_complete, &bserr2);
8323 : 15 : spdk_blob_close(clone1, blob_op_complete, &bserr3);
8324 : 15 : spdk_bs_unload(bs, blob_op_complete, &bserr4);
8325 : 15 : spdk_bs_free_io_channel(bs_ch);
8326 : 15 : poll_threads();
8327 : 15 : CU_ASSERT(bserr1 == 0);
8328 : 15 : CU_ASSERT(bserr2 == 0);
8329 : 15 : CU_ASSERT(bserr3 == 0);
8330 : 15 : CU_ASSERT(bserr4 == 0);
8331 : 15 : g_blob = NULL;
8332 : :
8333 : : /* Reload the blobstore */
8334 : 15 : spdk_bs_opts_init(&bs_opts, sizeof(bs_opts));
8335 : 15 : bs_opts.esnap_bs_dev_create = ut_esnap_create;
8336 : 15 : dev = init_dev();
8337 : 15 : spdk_bs_load(dev, &bs_opts, bs_op_with_handle_complete, NULL);
8338 : 15 : poll_threads();
8339 : 15 : CU_ASSERT(g_bserrno == 0);
8340 [ - + ]: 15 : SPDK_CU_ASSERT_FATAL(g_bs != NULL);
8341 : 15 : }
8342 : :
8343 : : static bool
8344 : 300 : blob_esnap_verify_contents(struct spdk_blob *blob, struct spdk_io_channel *ch,
8345 : : uint64_t offset, uint64_t size, uint32_t readsize, const char *how)
8346 : 300 : {
8347 : 300 : const uint32_t bs_blksz = blob->bs->io_unit_size;
8348 [ + + ]: 300 : const uint32_t esnap_blksz = blob->back_bs_dev ? blob->back_bs_dev->blocklen : bs_blksz;
8349 [ - + ]: 300 : const uint32_t start_blk = offset / bs_blksz;
8350 [ - + ]: 300 : const uint32_t num_blocks = spdk_max(size, readsize) / bs_blksz;
8351 [ - + ]: 300 : const uint32_t blocks_per_read = spdk_min(size, readsize) / bs_blksz;
8352 : : uint32_t blob_block;
8353 : 300 : struct iovec iov;
8354 [ - + ]: 300 : uint8_t buf[spdk_min(size, readsize)];
8355 : : bool block_ok;
8356 : :
8357 [ - + - + ]: 300 : SPDK_CU_ASSERT_FATAL(offset % bs_blksz == 0);
8358 [ - + - + ]: 300 : SPDK_CU_ASSERT_FATAL(size % bs_blksz == 0);
8359 [ - + - + ]: 300 : SPDK_CU_ASSERT_FATAL(readsize % bs_blksz == 0);
8360 : :
8361 [ - + ]: 300 : memset(buf, 0, readsize);
8362 : 300 : iov.iov_base = buf;
8363 : 300 : iov.iov_len = readsize;
8364 [ + + ]: 11985 : for (blob_block = start_blk; blob_block < num_blocks; blob_block += blocks_per_read) {
8365 [ + + + + ]: 11685 : if (strcmp(how, "read") == 0) {
8366 : 3915 : spdk_blob_io_read(blob, ch, buf, blob_block, blocks_per_read,
8367 : : bs_op_complete, NULL);
8368 [ + + + + ]: 7770 : } else if (strcmp(how, "readv") == 0) {
8369 : 3885 : spdk_blob_io_readv(blob, ch, &iov, 1, blob_block, blocks_per_read,
8370 : : bs_op_complete, NULL);
8371 [ + + + - ]: 3885 : } else if (strcmp(how, "readv_ext") == 0) {
8372 : : /*
8373 : : * This is currently pointless. NULL ext_opts leads to dev->readv(), not
8374 : : * dev->readv_ext().
8375 : : */
8376 : 3885 : spdk_blob_io_readv_ext(blob, ch, &iov, 1, blob_block, blocks_per_read,
8377 : : bs_op_complete, NULL, NULL);
8378 : : } else {
8379 : 0 : abort();
8380 : : }
8381 : 11685 : poll_threads();
8382 : 11685 : CU_ASSERT(g_bserrno == 0);
8383 [ - + ]: 11685 : if (g_bserrno != 0) {
8384 : 0 : return false;
8385 : : }
8386 : 11685 : block_ok = ut_esnap_content_is_correct(buf, blocks_per_read * bs_blksz, blob->id,
8387 : : blob_block * bs_blksz, esnap_blksz);
8388 : 11685 : CU_ASSERT(block_ok);
8389 [ - + ]: 11685 : if (!block_ok) {
8390 : 0 : return false;
8391 : : }
8392 : : }
8393 : :
8394 : 300 : return true;
8395 : : }
8396 : :
8397 : : static void
8398 : 45 : blob_esnap_io_size(uint32_t bs_blksz, uint32_t esnap_blksz)
8399 : : {
8400 : : struct spdk_bs_dev *dev;
8401 : : struct spdk_blob_store *bs;
8402 : 45 : struct spdk_bs_opts bsopts;
8403 : 45 : struct spdk_blob_opts opts;
8404 : 45 : struct ut_esnap_opts esnap_opts;
8405 : : struct spdk_blob *blob;
8406 : 45 : const uint32_t cluster_sz = 4 * g_phys_blocklen;
8407 : 45 : const uint64_t esnap_num_clusters = 4;
8408 : 45 : const uint32_t esnap_sz = cluster_sz * esnap_num_clusters;
8409 [ - + ]: 45 : const uint64_t esnap_num_blocks = esnap_sz / esnap_blksz;
8410 [ - + ]: 45 : const uint64_t blob_num_blocks = esnap_sz / bs_blksz;
8411 : : uint32_t block;
8412 : : struct spdk_io_channel *bs_ch;
8413 : :
8414 : 45 : spdk_bs_opts_init(&bsopts, sizeof(bsopts));
8415 : 45 : bsopts.cluster_sz = cluster_sz;
8416 : 45 : bsopts.esnap_bs_dev_create = ut_esnap_create;
8417 : :
8418 : : /* Create device with desired block size */
8419 : 45 : dev = init_dev();
8420 : 45 : dev->blocklen = bs_blksz;
8421 [ - + ]: 45 : dev->blockcnt = DEV_BUFFER_SIZE / dev->blocklen;
8422 : :
8423 : : /* Initialize a new blob store */
8424 : 45 : spdk_bs_init(dev, &bsopts, bs_op_with_handle_complete, NULL);
8425 : 45 : poll_threads();
8426 : 45 : CU_ASSERT(g_bserrno == 0);
8427 [ - + ]: 45 : SPDK_CU_ASSERT_FATAL(g_bs != NULL);
8428 [ - + ]: 45 : SPDK_CU_ASSERT_FATAL(g_bs->io_unit_size == bs_blksz);
8429 : 45 : bs = g_bs;
8430 : :
8431 : 45 : bs_ch = spdk_bs_alloc_io_channel(bs);
8432 [ - + ]: 45 : SPDK_CU_ASSERT_FATAL(bs_ch != NULL);
8433 : :
8434 : : /* Create and open the esnap clone */
8435 : 45 : ut_spdk_blob_opts_init(&opts);
8436 : 45 : ut_esnap_opts_init(esnap_blksz, esnap_num_blocks, __func__, NULL, &esnap_opts);
8437 : 45 : opts.esnap_id = &esnap_opts;
8438 : 45 : opts.esnap_id_len = sizeof(esnap_opts);
8439 : 45 : opts.num_clusters = esnap_num_clusters;
8440 : 45 : blob = ut_blob_create_and_open(bs, &opts);
8441 [ - + ]: 45 : SPDK_CU_ASSERT_FATAL(blob != NULL);
8442 : :
8443 : : /* Verify that large reads return the content of the esnap device */
8444 : 45 : CU_ASSERT(blob_esnap_verify_contents(blob, bs_ch, 0, esnap_sz, esnap_sz, "read"));
8445 : 45 : CU_ASSERT(blob_esnap_verify_contents(blob, bs_ch, 0, esnap_sz, esnap_sz, "readv"));
8446 : 45 : CU_ASSERT(blob_esnap_verify_contents(blob, bs_ch, 0, esnap_sz, esnap_sz, "readv_ext"));
8447 : : /* Verify that small reads return the content of the esnap device */
8448 : 45 : CU_ASSERT(blob_esnap_verify_contents(blob, bs_ch, 0, esnap_sz, bs_blksz, "read"));
8449 : 45 : CU_ASSERT(blob_esnap_verify_contents(blob, bs_ch, 0, esnap_sz, bs_blksz, "readv"));
8450 : 45 : CU_ASSERT(blob_esnap_verify_contents(blob, bs_ch, 0, esnap_sz, bs_blksz, "readv_ext"));
8451 : :
8452 : : /* Write one blob block at a time; verify that the surrounding blocks are OK */
8453 [ + + ]: 3885 : for (block = 0; block < blob_num_blocks; block++) {
8454 [ - + ]: 3840 : char buf[bs_blksz];
8455 : : union ut_word word;
8456 : :
8457 : 3840 : word.f.blob_id = 0xfedcba90;
8458 : 3840 : word.f.lba = block;
8459 : 3840 : ut_memset8(buf, word.num, bs_blksz);
8460 : :
8461 : 3840 : spdk_blob_io_write(blob, bs_ch, buf, block, 1, bs_op_complete, NULL);
8462 : 3840 : poll_threads();
8463 : 3840 : CU_ASSERT(g_bserrno == 0);
8464 [ - + ]: 3840 : if (g_bserrno != 0) {
8465 : 0 : break;
8466 : : }
8467 : :
8468 : : /* Read and verify the block before the current block */
8469 [ + + ]: 3840 : if (block != 0) {
8470 : 3795 : spdk_blob_io_read(blob, bs_ch, buf, block - 1, 1, bs_op_complete, NULL);
8471 : 3795 : poll_threads();
8472 : 3795 : CU_ASSERT(g_bserrno == 0);
8473 [ - + ]: 3795 : if (g_bserrno != 0) {
8474 : 0 : break;
8475 : : }
8476 : 3795 : CU_ASSERT(ut_esnap_content_is_correct(buf, bs_blksz, word.f.blob_id,
8477 : : (block - 1) * bs_blksz, bs_blksz));
8478 : : }
8479 : :
8480 : : /* Read and verify the current block */
8481 : 3840 : spdk_blob_io_read(blob, bs_ch, buf, block, 1, bs_op_complete, NULL);
8482 : 3840 : poll_threads();
8483 : 3840 : CU_ASSERT(g_bserrno == 0);
8484 [ - + ]: 3840 : if (g_bserrno != 0) {
8485 : 0 : break;
8486 : : }
8487 : 3840 : CU_ASSERT(ut_esnap_content_is_correct(buf, bs_blksz, word.f.blob_id,
8488 : : block * bs_blksz, bs_blksz));
8489 : :
8490 : : /* Check the block that follows */
8491 [ + + ]: 3840 : if (block + 1 < blob_num_blocks) {
8492 : 3795 : g_bserrno = 0xbad;
8493 : 3795 : spdk_blob_io_read(blob, bs_ch, buf, block + 1, 1, bs_op_complete, NULL);
8494 : 3795 : poll_threads();
8495 : 3795 : CU_ASSERT(g_bserrno == 0);
8496 [ - + ]: 3795 : if (g_bserrno != 0) {
8497 : 0 : break;
8498 : : }
8499 : 3795 : CU_ASSERT(ut_esnap_content_is_correct(buf, bs_blksz, blob->id,
8500 : : (block + 1) * bs_blksz,
8501 : : esnap_blksz));
8502 : : }
8503 : : }
8504 : :
8505 : : /* Clean up */
8506 : 45 : spdk_bs_free_io_channel(bs_ch);
8507 : 45 : g_bserrno = 0xbad;
8508 : 45 : spdk_blob_close(blob, blob_op_complete, NULL);
8509 : 45 : poll_threads();
8510 : 45 : CU_ASSERT(g_bserrno == 0);
8511 : 45 : spdk_bs_unload(g_bs, bs_op_complete, NULL);
8512 : 45 : poll_threads();
8513 : 45 : CU_ASSERT(g_bserrno == 0);
8514 : 45 : g_bs = NULL;
8515 [ - + ]: 45 : memset(g_dev_buffer, 0, DEV_BUFFER_SIZE);
8516 : 45 : }
8517 : :
8518 : : static void
8519 : 15 : blob_esnap_io_4096_4096(void)
8520 : : {
8521 : 15 : blob_esnap_io_size(4096, 4096);
8522 : 15 : }
8523 : :
8524 : : static void
8525 : 15 : blob_esnap_io_512_512(void)
8526 : : {
8527 : 15 : blob_esnap_io_size(512, 512);
8528 : 15 : }
8529 : :
8530 : : static void
8531 : 15 : blob_esnap_io_4096_512(void)
8532 : : {
8533 : 15 : blob_esnap_io_size(4096, 512);
8534 : 15 : }
8535 : :
8536 : : static void
8537 : 15 : blob_esnap_io_512_4096(void)
8538 : : {
8539 : : struct spdk_bs_dev *dev;
8540 : : struct spdk_blob_store *bs;
8541 : 15 : struct spdk_bs_opts bs_opts;
8542 : 15 : struct spdk_blob_opts blob_opts;
8543 : 15 : struct ut_esnap_opts esnap_opts;
8544 : 15 : uint64_t cluster_sz = 4 * g_phys_blocklen;
8545 : 15 : uint32_t bs_blksz = 512;
8546 : 15 : uint32_t esnap_blksz = BLOCKLEN;
8547 : 15 : uint64_t esnap_num_blocks = 64;
8548 : : spdk_blob_id blobid;
8549 : :
8550 : : /* Create device with desired block size */
8551 : 15 : dev = init_dev();
8552 : 15 : dev->blocklen = bs_blksz;
8553 [ - + ]: 15 : dev->blockcnt = DEV_BUFFER_SIZE / dev->blocklen;
8554 : :
8555 : : /* Initialize a new blob store */
8556 : 15 : spdk_bs_opts_init(&bs_opts, sizeof(bs_opts));
8557 : 15 : bs_opts.cluster_sz = cluster_sz;
8558 : 15 : bs_opts.esnap_bs_dev_create = ut_esnap_create;
8559 : 15 : spdk_bs_init(dev, &bs_opts, bs_op_with_handle_complete, NULL);
8560 : 15 : poll_threads();
8561 : 15 : CU_ASSERT(g_bserrno == 0);
8562 [ - + ]: 15 : SPDK_CU_ASSERT_FATAL(g_bs != NULL);
8563 [ - + ]: 15 : SPDK_CU_ASSERT_FATAL(g_bs->io_unit_size == bs_blksz);
8564 : 15 : bs = g_bs;
8565 : :
8566 : : /* Try to create and open the esnap clone. Create should succeed, open should fail. */
8567 : 15 : ut_spdk_blob_opts_init(&blob_opts);
8568 : 15 : ut_esnap_opts_init(esnap_blksz, esnap_num_blocks, __func__, NULL, &esnap_opts);
8569 : 15 : blob_opts.esnap_id = &esnap_opts;
8570 : 15 : blob_opts.esnap_id_len = sizeof(esnap_opts);
8571 [ - + ]: 15 : blob_opts.num_clusters = esnap_num_blocks * esnap_blksz / bs_blksz;
8572 : 15 : spdk_bs_create_blob_ext(bs, &blob_opts, blob_op_with_id_complete, NULL);
8573 : 15 : poll_threads();
8574 : 15 : CU_ASSERT(g_bserrno == 0);
8575 : 15 : CU_ASSERT(g_blobid != SPDK_BLOBID_INVALID);
8576 : 15 : blobid = g_blobid;
8577 : 15 : spdk_bs_open_blob(bs, blobid, blob_op_with_handle_complete, NULL);
8578 : 15 : poll_threads();
8579 : 15 : CU_ASSERT(g_bserrno == -EINVAL);
8580 : 15 : CU_ASSERT(g_blob == NULL);
8581 : :
8582 : : /* Clean up */
8583 : 15 : spdk_bs_unload(bs, bs_op_complete, NULL);
8584 : 15 : poll_threads();
8585 : 15 : CU_ASSERT(g_bserrno == 0);
8586 : 15 : g_bs = NULL;
8587 [ - + ]: 15 : memset(g_dev_buffer, 0, DEV_BUFFER_SIZE);
8588 : 15 : }
8589 : :
8590 : : static void
8591 : 15 : blob_esnap_thread_add_remove(void)
8592 : 15 : {
8593 : 15 : struct spdk_blob_store *bs = g_bs;
8594 : 15 : struct spdk_blob_opts opts;
8595 : 15 : struct ut_esnap_opts ut_esnap_opts;
8596 : : struct spdk_blob *blob;
8597 : : struct ut_esnap_dev *ut_dev;
8598 : : spdk_blob_id blobid;
8599 : 15 : uint64_t start_thread = g_ut_thread_id;
8600 : 15 : bool destroyed = false;
8601 : : struct spdk_io_channel *ch0, *ch1;
8602 : : struct ut_esnap_channel *ut_ch0, *ut_ch1;
8603 : 15 : const uint32_t blocklen = bs->io_unit_size;
8604 [ - + ]: 15 : char buf[blocklen * 4];
8605 : :
8606 [ - + ]: 15 : SPDK_CU_ASSERT_FATAL(g_ut_num_threads > 1);
8607 : 15 : set_thread(0);
8608 : :
8609 : : /* Create the esnap clone */
8610 : 15 : ut_esnap_opts_init(blocklen, 2048, "add_remove_1", &destroyed, &ut_esnap_opts);
8611 : 15 : ut_spdk_blob_opts_init(&opts);
8612 : 15 : opts.esnap_id = &ut_esnap_opts;
8613 : 15 : opts.esnap_id_len = sizeof(ut_esnap_opts);
8614 : 15 : opts.num_clusters = 10;
8615 : 15 : spdk_bs_create_blob_ext(bs, &opts, blob_op_with_id_complete, NULL);
8616 : 15 : poll_threads();
8617 : 15 : CU_ASSERT(g_bserrno == 0);
8618 : 15 : CU_ASSERT(g_blobid != SPDK_BLOBID_INVALID);
8619 : 15 : blobid = g_blobid;
8620 : :
8621 : : /* Open the blob. No channels should be allocated yet. */
8622 : 15 : spdk_bs_open_blob(bs, blobid, blob_op_with_handle_complete, NULL);
8623 : 15 : poll_threads();
8624 : 15 : CU_ASSERT(g_bserrno == 0);
8625 : 15 : CU_ASSERT(g_blob != NULL);
8626 : 15 : blob = g_blob;
8627 : 15 : ut_dev = (struct ut_esnap_dev *)blob->back_bs_dev;
8628 : 15 : CU_ASSERT(ut_dev != NULL);
8629 : 15 : CU_ASSERT(ut_dev->num_channels == 0);
8630 : :
8631 : : /* Create a channel on thread 0. It is lazily created on the first read. */
8632 : 15 : ch0 = spdk_bs_alloc_io_channel(bs);
8633 : 15 : CU_ASSERT(ch0 != NULL);
8634 : 15 : ut_ch0 = ut_esnap_get_io_channel(ch0, blobid);
8635 : 15 : CU_ASSERT(ut_ch0 == NULL);
8636 : 15 : CU_ASSERT(ut_dev->num_channels == 0);
8637 : 15 : spdk_blob_io_read(blob, ch0, buf, 0, 1, bs_op_complete, NULL);
8638 : 15 : poll_threads();
8639 : 15 : CU_ASSERT(g_bserrno == 0);
8640 : 15 : CU_ASSERT(ut_dev->num_channels == 1);
8641 : 15 : ut_ch0 = ut_esnap_get_io_channel(ch0, blobid);
8642 : 15 : CU_ASSERT(ut_ch0 != NULL);
8643 : 15 : CU_ASSERT(ut_ch0->blocks_read == 1);
8644 : :
8645 : : /* Create a channel on thread 1 and verify its lazy creation too. */
8646 : 15 : set_thread(1);
8647 : 15 : ch1 = spdk_bs_alloc_io_channel(bs);
8648 : 15 : CU_ASSERT(ch1 != NULL);
8649 : 15 : ut_ch1 = ut_esnap_get_io_channel(ch1, blobid);
8650 : 15 : CU_ASSERT(ut_ch1 == NULL);
8651 : 15 : CU_ASSERT(ut_dev->num_channels == 1);
8652 : 15 : spdk_blob_io_read(blob, ch1, buf, 0, 4, bs_op_complete, NULL);
8653 : 15 : poll_threads();
8654 : 15 : CU_ASSERT(g_bserrno == 0);
8655 : 15 : CU_ASSERT(ut_dev->num_channels == 2);
8656 : 15 : ut_ch1 = ut_esnap_get_io_channel(ch1, blobid);
8657 : 15 : CU_ASSERT(ut_ch1 != NULL);
8658 : 15 : CU_ASSERT(ut_ch1->blocks_read == 4);
8659 : :
8660 : : /* Close the channel on thread 0 and verify the bs_dev channel is also gone. */
8661 : 15 : set_thread(0);
8662 : 15 : spdk_bs_free_io_channel(ch0);
8663 : 15 : poll_threads();
8664 : 15 : CU_ASSERT(ut_dev->num_channels == 1);
8665 : :
8666 : : /* Close the blob. There is no outstanding IO so it should close right away. */
8667 : 15 : g_bserrno = 0xbad;
8668 : 15 : spdk_blob_close(blob, blob_op_complete, NULL);
8669 : 15 : poll_threads();
8670 : 15 : CU_ASSERT(g_bserrno == 0);
8671 [ - + ]: 15 : CU_ASSERT(destroyed);
8672 : :
8673 : : /* The esnap channel for the blob should be gone now too. */
8674 : 15 : ut_ch1 = ut_esnap_get_io_channel(ch1, blobid);
8675 : 15 : CU_ASSERT(ut_ch1 == NULL);
8676 : :
8677 : : /* Clean up */
8678 : 15 : set_thread(1);
8679 : 15 : spdk_bs_free_io_channel(ch1);
8680 : 15 : set_thread(start_thread);
8681 : 15 : }
8682 : :
8683 : : static void
8684 : 45 : freeze_done(void *cb_arg, int bserrno)
8685 : : {
8686 : 45 : uint32_t *freeze_cnt = cb_arg;
8687 : :
8688 : 45 : CU_ASSERT(bserrno == 0);
8689 : 45 : (*freeze_cnt)++;
8690 : 45 : }
8691 : :
8692 : : static void
8693 : 45 : unfreeze_done(void *cb_arg, int bserrno)
8694 : : {
8695 : 45 : uint32_t *unfreeze_cnt = cb_arg;
8696 : :
8697 : 45 : CU_ASSERT(bserrno == 0);
8698 : 45 : (*unfreeze_cnt)++;
8699 : 45 : }
8700 : :
8701 : : static void
8702 : 15 : blob_nested_freezes(void)
8703 : : {
8704 : 15 : struct spdk_blob_store *bs = g_bs;
8705 : : struct spdk_blob *blob;
8706 : 15 : struct spdk_io_channel *channel[2];
8707 : 15 : struct spdk_blob_opts opts;
8708 : 15 : uint32_t freeze_cnt, unfreeze_cnt;
8709 : : int i;
8710 : :
8711 [ + + ]: 45 : for (i = 0; i < 2; i++) {
8712 : 30 : set_thread(i);
8713 : 30 : channel[i] = spdk_bs_alloc_io_channel(bs);
8714 [ - + ]: 30 : SPDK_CU_ASSERT_FATAL(channel[i] != NULL);
8715 : : }
8716 : :
8717 : 15 : set_thread(0);
8718 : :
8719 : 15 : ut_spdk_blob_opts_init(&opts);
8720 : 15 : blob = ut_blob_create_and_open(bs, &opts);
8721 : :
8722 : : /* First just test a single freeze/unfreeze. */
8723 : 15 : freeze_cnt = 0;
8724 : 15 : unfreeze_cnt = 0;
8725 : 15 : CU_ASSERT(blob->frozen_refcnt == 0);
8726 : 15 : blob_freeze_io(blob, freeze_done, &freeze_cnt);
8727 : 15 : CU_ASSERT(blob->frozen_refcnt == 1);
8728 : 15 : CU_ASSERT(freeze_cnt == 0);
8729 : 15 : poll_threads();
8730 : 15 : CU_ASSERT(freeze_cnt == 1);
8731 : 15 : blob_unfreeze_io(blob, unfreeze_done, &unfreeze_cnt);
8732 : 15 : CU_ASSERT(blob->frozen_refcnt == 0);
8733 : 15 : CU_ASSERT(unfreeze_cnt == 0);
8734 : 15 : poll_threads();
8735 : 15 : CU_ASSERT(unfreeze_cnt == 1);
8736 : :
8737 : : /* Now nest multiple freeze/unfreeze operations. We should
8738 : : * expect a callback for each operation, but only after
8739 : : * the threads have been polled to ensure a for_each_channel()
8740 : : * was executed.
8741 : : */
8742 : 15 : freeze_cnt = 0;
8743 : 15 : unfreeze_cnt = 0;
8744 : 15 : CU_ASSERT(blob->frozen_refcnt == 0);
8745 : 15 : blob_freeze_io(blob, freeze_done, &freeze_cnt);
8746 : 15 : CU_ASSERT(blob->frozen_refcnt == 1);
8747 : 15 : CU_ASSERT(freeze_cnt == 0);
8748 : 15 : blob_freeze_io(blob, freeze_done, &freeze_cnt);
8749 : 15 : CU_ASSERT(blob->frozen_refcnt == 2);
8750 : 15 : CU_ASSERT(freeze_cnt == 0);
8751 : 15 : poll_threads();
8752 : 15 : CU_ASSERT(freeze_cnt == 2);
8753 : 15 : blob_unfreeze_io(blob, unfreeze_done, &unfreeze_cnt);
8754 : 15 : CU_ASSERT(blob->frozen_refcnt == 1);
8755 : 15 : CU_ASSERT(unfreeze_cnt == 0);
8756 : 15 : blob_unfreeze_io(blob, unfreeze_done, &unfreeze_cnt);
8757 : 15 : CU_ASSERT(blob->frozen_refcnt == 0);
8758 : 15 : CU_ASSERT(unfreeze_cnt == 0);
8759 : 15 : poll_threads();
8760 : 15 : CU_ASSERT(unfreeze_cnt == 2);
8761 : :
8762 [ + + ]: 45 : for (i = 0; i < 2; i++) {
8763 : 30 : set_thread(i);
8764 : 30 : spdk_bs_free_io_channel(channel[i]);
8765 : : }
8766 : 15 : set_thread(0);
8767 : 15 : ut_blob_close_and_delete(bs, blob);
8768 : :
8769 : 15 : poll_threads();
8770 : 15 : g_blob = NULL;
8771 : 15 : g_blobid = 0;
8772 : 15 : }
8773 : :
8774 : : static void
8775 : 15 : blob_ext_md_pages(void)
8776 : : {
8777 : : struct spdk_blob_store *bs;
8778 : : struct spdk_bs_dev *dev;
8779 : : struct spdk_blob *blob;
8780 : 15 : struct spdk_blob_opts opts;
8781 : 15 : struct spdk_bs_opts bs_opts;
8782 : : uint64_t free_clusters;
8783 : :
8784 : 15 : dev = init_dev();
8785 : 15 : spdk_bs_opts_init(&bs_opts, sizeof(bs_opts));
8786 [ - + ]: 15 : snprintf(bs_opts.bstype.bstype, sizeof(bs_opts.bstype.bstype), "TESTTYPE");
8787 : : /* Issue #2932 was a bug in how we use bs_allocate_cluster() during resize.
8788 : : * It requires num_md_pages that is much smaller than the number of clusters.
8789 : : * Make sure we can create a blob that uses all of the free clusters.
8790 : : */
8791 : 15 : bs_opts.cluster_sz = 65536;
8792 : 15 : bs_opts.num_md_pages = 16;
8793 : :
8794 : : /* Initialize a new blob store */
8795 : 15 : spdk_bs_init(dev, &bs_opts, bs_op_with_handle_complete, NULL);
8796 : 15 : poll_threads();
8797 : 15 : CU_ASSERT(g_bserrno == 0);
8798 [ - + ]: 15 : SPDK_CU_ASSERT_FATAL(g_bs != NULL);
8799 : 15 : bs = g_bs;
8800 : :
8801 : 15 : free_clusters = spdk_bs_free_cluster_count(bs);
8802 : :
8803 : 15 : ut_spdk_blob_opts_init(&opts);
8804 : 15 : opts.num_clusters = free_clusters;
8805 : :
8806 : 15 : blob = ut_blob_create_and_open(bs, &opts);
8807 : 15 : spdk_blob_close(blob, blob_op_complete, NULL);
8808 : 15 : CU_ASSERT(g_bserrno == 0);
8809 : :
8810 : 15 : spdk_bs_unload(bs, bs_op_complete, NULL);
8811 : 15 : poll_threads();
8812 : 15 : CU_ASSERT(g_bserrno == 0);
8813 : 15 : g_bs = NULL;
8814 : 15 : }
8815 : :
8816 : : static void
8817 : 15 : blob_esnap_clone_snapshot(void)
8818 : : {
8819 : : /*
8820 : : * When a snapshot is created, the blob that is being snapped becomes
8821 : : * the leaf node (a clone of the snapshot) and the newly created
8822 : : * snapshot sits between the snapped blob and the external snapshot.
8823 : : *
8824 : : * Before creating snap1
8825 : : *
8826 : : * ,--------. ,----------.
8827 : : * | blob | | vbdev |
8828 : : * | blob1 |<----| nvme1n42 |
8829 : : * | (rw) | | (ro) |
8830 : : * `--------' `----------'
8831 : : * Figure 1
8832 : : *
8833 : : * After creating snap1
8834 : : *
8835 : : * ,--------. ,--------. ,----------.
8836 : : * | blob | | blob | | vbdev |
8837 : : * | blob1 |<----| snap1 |<----| nvme1n42 |
8838 : : * | (rw) | | (ro) | | (ro) |
8839 : : * `--------' `--------' `----------'
8840 : : * Figure 2
8841 : : *
8842 : : * Starting from Figure 2, if snap1 is removed, the chain reverts to
8843 : : * what it looks like in Figure 1.
8844 : : *
8845 : : * Starting from Figure 2, if blob1 is removed, the chain becomes:
8846 : : *
8847 : : * ,--------. ,----------.
8848 : : * | blob | | vbdev |
8849 : : * | snap1 |<----| nvme1n42 |
8850 : : * | (ro) | | (ro) |
8851 : : * `--------' `----------'
8852 : : * Figure 3
8853 : : *
8854 : : * In each case, the blob pointed to by the nvme vbdev is considered
8855 : : * the "esnap clone". The esnap clone must have:
8856 : : *
8857 : : * - XATTR_INTERNAL for BLOB_EXTERNAL_SNAPSHOT_ID (e.g. name or UUID)
8858 : : * - blob->invalid_flags must contain SPDK_BLOB_EXTERNAL_SNAPSHOT
8859 : : * - blob->parent_id must be SPDK_BLOBID_EXTERNAL_SNAPSHOT.
8860 : : *
8861 : : * No other blob that descends from the esnap clone may have any of
8862 : : * those set.
8863 : : */
8864 : 15 : struct spdk_blob_store *bs = g_bs;
8865 : 15 : const uint32_t blocklen = bs->io_unit_size;
8866 : 15 : struct spdk_blob_opts opts;
8867 : 15 : struct ut_esnap_opts esnap_opts;
8868 : : struct spdk_blob *blob, *snap_blob;
8869 : : spdk_blob_id blobid, snap_blobid;
8870 : 15 : bool destroyed = false;
8871 : :
8872 : : /* Create the esnap clone */
8873 : 15 : ut_esnap_opts_init(blocklen, 2048, __func__, &destroyed, &esnap_opts);
8874 : 15 : ut_spdk_blob_opts_init(&opts);
8875 : 15 : opts.esnap_id = &esnap_opts;
8876 : 15 : opts.esnap_id_len = sizeof(esnap_opts);
8877 : 15 : opts.num_clusters = 10;
8878 : 15 : spdk_bs_create_blob_ext(bs, &opts, blob_op_with_id_complete, NULL);
8879 : 15 : poll_threads();
8880 : 15 : CU_ASSERT(g_bserrno == 0);
8881 : 15 : CU_ASSERT(g_blobid != SPDK_BLOBID_INVALID);
8882 : 15 : blobid = g_blobid;
8883 : :
8884 : : /* Open the blob. */
8885 : 15 : spdk_bs_open_blob(bs, blobid, blob_op_with_handle_complete, NULL);
8886 : 15 : poll_threads();
8887 : 15 : CU_ASSERT(g_bserrno == 0);
8888 : 15 : CU_ASSERT(g_blob != NULL);
8889 : 15 : blob = g_blob;
8890 : 15 : UT_ASSERT_IS_ESNAP_CLONE(blob, &esnap_opts, sizeof(esnap_opts));
8891 : :
8892 : : /*
8893 : : * Create a snapshot of the blob. The snapshot becomes the esnap clone.
8894 : : */
8895 : 15 : spdk_bs_create_snapshot(bs, blobid, NULL, blob_op_with_id_complete, NULL);
8896 : 15 : poll_threads();
8897 : 15 : CU_ASSERT(g_bserrno == 0);
8898 : 15 : CU_ASSERT(g_blobid != SPDK_BLOBID_INVALID);
8899 : 15 : snap_blobid = g_blobid;
8900 : :
8901 : 15 : spdk_bs_open_blob(bs, snap_blobid, blob_op_with_handle_complete, NULL);
8902 : 15 : poll_threads();
8903 : 15 : CU_ASSERT(g_bserrno == 0);
8904 [ - + ]: 15 : SPDK_CU_ASSERT_FATAL(g_blob != NULL);
8905 : 15 : snap_blob = g_blob;
8906 : :
8907 : 15 : UT_ASSERT_IS_NOT_ESNAP_CLONE(blob);
8908 : 15 : UT_ASSERT_IS_ESNAP_CLONE(snap_blob, &esnap_opts, sizeof(esnap_opts));
8909 : :
8910 : : /*
8911 : : * Delete the snapshot. The original blob becomes the esnap clone.
8912 : : */
8913 : 15 : ut_blob_close_and_delete(bs, snap_blob);
8914 : 15 : snap_blob = NULL;
8915 : 15 : snap_blobid = SPDK_BLOBID_INVALID;
8916 : 15 : UT_ASSERT_IS_ESNAP_CLONE(blob, &esnap_opts, sizeof(esnap_opts));
8917 : :
8918 : : /*
8919 : : * Create the snapshot again, then delete the original blob. The
8920 : : * snapshot should survive as the esnap clone.
8921 : : */
8922 : 15 : spdk_bs_create_snapshot(bs, blobid, NULL, blob_op_with_id_complete, NULL);
8923 : 15 : poll_threads();
8924 : 15 : CU_ASSERT(g_bserrno == 0);
8925 : 15 : CU_ASSERT(g_blobid != SPDK_BLOBID_INVALID);
8926 : 15 : snap_blobid = g_blobid;
8927 : :
8928 : 15 : spdk_bs_open_blob(bs, snap_blobid, blob_op_with_handle_complete, NULL);
8929 : 15 : poll_threads();
8930 : 15 : CU_ASSERT(g_bserrno == 0);
8931 [ - + ]: 15 : SPDK_CU_ASSERT_FATAL(g_blob != NULL);
8932 : 15 : snap_blob = g_blob;
8933 : :
8934 : 15 : UT_ASSERT_IS_NOT_ESNAP_CLONE(blob);
8935 : 15 : UT_ASSERT_IS_ESNAP_CLONE(snap_blob, &esnap_opts, sizeof(esnap_opts));
8936 : :
8937 : 15 : ut_blob_close_and_delete(bs, blob);
8938 : 15 : blob = NULL;
8939 : 15 : blobid = SPDK_BLOBID_INVALID;
8940 : 15 : UT_ASSERT_IS_ESNAP_CLONE(snap_blob, &esnap_opts, sizeof(esnap_opts));
8941 : :
8942 : : /*
8943 : : * Clone the snapshot. The snapshot continues to be the esnap clone.
8944 : : */
8945 : 15 : spdk_bs_create_clone(bs, snap_blobid, NULL, blob_op_with_id_complete, NULL);
8946 : 15 : poll_threads();
8947 : 15 : CU_ASSERT(g_bserrno == 0);
8948 : 15 : CU_ASSERT(g_blobid != SPDK_BLOBID_INVALID);
8949 : 15 : blobid = g_blobid;
8950 : :
8951 : 15 : spdk_bs_open_blob(bs, blobid, blob_op_with_handle_complete, NULL);
8952 : 15 : poll_threads();
8953 : 15 : CU_ASSERT(g_bserrno == 0);
8954 [ - + ]: 15 : SPDK_CU_ASSERT_FATAL(g_blob != NULL);
8955 : 15 : blob = g_blob;
8956 : :
8957 : 15 : UT_ASSERT_IS_NOT_ESNAP_CLONE(blob);
8958 : 15 : UT_ASSERT_IS_ESNAP_CLONE(snap_blob, &esnap_opts, sizeof(esnap_opts));
8959 : :
8960 : : /*
8961 : : * Delete the snapshot. The clone becomes the esnap clone.
8962 : : */
8963 : 15 : ut_blob_close_and_delete(bs, snap_blob);
8964 : 15 : snap_blob = NULL;
8965 : 15 : snap_blobid = SPDK_BLOBID_INVALID;
8966 : 15 : UT_ASSERT_IS_ESNAP_CLONE(blob, &esnap_opts, sizeof(esnap_opts));
8967 : :
8968 : : /*
8969 : : * Clean up
8970 : : */
8971 : 15 : ut_blob_close_and_delete(bs, blob);
8972 : 15 : }
8973 : :
8974 : : static uint64_t
8975 : 30 : _blob_esnap_clone_hydrate(bool inflate)
8976 : : {
8977 : 30 : struct spdk_blob_store *bs = g_bs;
8978 : 30 : struct spdk_blob_opts opts;
8979 : 30 : struct ut_esnap_opts esnap_opts;
8980 : : struct spdk_blob *blob;
8981 : : spdk_blob_id blobid;
8982 : : struct spdk_io_channel *channel;
8983 : 30 : bool destroyed = false;
8984 : 30 : const uint32_t blocklen = spdk_bs_get_io_unit_size(bs);
8985 : 30 : const uint32_t cluster_sz = spdk_bs_get_cluster_size(bs);
8986 : 30 : const uint64_t esnap_num_clusters = 4;
8987 : 30 : const uint32_t esnap_sz = cluster_sz * esnap_num_clusters;
8988 [ - + ]: 30 : const uint64_t esnap_num_blocks = esnap_sz / blocklen;
8989 : 30 : uint64_t num_failures = CU_get_number_of_failures();
8990 : :
8991 : 30 : channel = spdk_bs_alloc_io_channel(bs);
8992 [ - + ]: 30 : SPDK_CU_ASSERT_FATAL(channel != NULL);
8993 : :
8994 : : /* Create the esnap clone */
8995 : 30 : ut_spdk_blob_opts_init(&opts);
8996 : 30 : ut_esnap_opts_init(blocklen, esnap_num_blocks, __func__, &destroyed, &esnap_opts);
8997 : 30 : opts.esnap_id = &esnap_opts;
8998 : 30 : opts.esnap_id_len = sizeof(esnap_opts);
8999 : 30 : opts.num_clusters = esnap_num_clusters;
9000 : 30 : spdk_bs_create_blob_ext(bs, &opts, blob_op_with_id_complete, NULL);
9001 : 30 : poll_threads();
9002 : 30 : CU_ASSERT(g_bserrno == 0);
9003 : 30 : CU_ASSERT(g_blobid != SPDK_BLOBID_INVALID);
9004 : 30 : blobid = g_blobid;
9005 : :
9006 : : /* Open the esnap clone */
9007 : 30 : spdk_bs_open_blob(bs, blobid, blob_op_with_handle_complete, NULL);
9008 : 30 : poll_threads();
9009 : 30 : CU_ASSERT(g_bserrno == 0);
9010 [ - + ]: 30 : SPDK_CU_ASSERT_FATAL(g_blob != NULL);
9011 : 30 : blob = g_blob;
9012 : 30 : UT_ASSERT_IS_ESNAP_CLONE(blob, &esnap_opts, sizeof(esnap_opts));
9013 : :
9014 : : /*
9015 : : * Inflate or decouple the blob then verify that it is no longer an esnap clone and has
9016 : : * right content
9017 : : */
9018 [ + + ]: 30 : if (inflate) {
9019 : 15 : spdk_bs_inflate_blob(bs, channel, blobid, blob_op_complete, NULL);
9020 : : } else {
9021 : 15 : spdk_bs_blob_decouple_parent(bs, channel, blobid, blob_op_complete, NULL);
9022 : : }
9023 : 30 : poll_threads();
9024 : 30 : CU_ASSERT(g_bserrno == 0);
9025 : 30 : UT_ASSERT_IS_NOT_ESNAP_CLONE(blob);
9026 : 30 : CU_ASSERT(blob_esnap_verify_contents(blob, channel, 0, esnap_sz, esnap_sz, "read"));
9027 : 30 : ut_blob_close_and_delete(bs, blob);
9028 : :
9029 : : /*
9030 : : * Clean up
9031 : : */
9032 : 30 : spdk_bs_free_io_channel(channel);
9033 : 30 : poll_threads();
9034 : :
9035 : : /* Return number of new failures */
9036 : 30 : return CU_get_number_of_failures() - num_failures;
9037 : : }
9038 : :
9039 : : static void
9040 : 15 : blob_esnap_clone_inflate(void)
9041 : : {
9042 : 15 : _blob_esnap_clone_hydrate(true);
9043 : 15 : }
9044 : :
9045 : : static void
9046 : 15 : blob_esnap_clone_decouple(void)
9047 : : {
9048 : 15 : _blob_esnap_clone_hydrate(false);
9049 : 15 : }
9050 : :
9051 : : static void
9052 : 15 : blob_esnap_hotplug(void)
9053 : 15 : {
9054 : 15 : struct spdk_blob_store *bs = g_bs;
9055 : 15 : struct ut_esnap_opts esnap1_opts, esnap2_opts;
9056 : 15 : struct spdk_blob_opts opts;
9057 : : struct spdk_blob *blob;
9058 : : struct spdk_bs_dev *bs_dev;
9059 : : struct ut_esnap_dev *esnap_dev;
9060 : 15 : uint32_t cluster_sz = spdk_bs_get_cluster_size(bs);
9061 : 15 : uint32_t block_sz = spdk_bs_get_io_unit_size(bs);
9062 : 15 : const uint32_t esnap_num_clusters = 4;
9063 [ - + ]: 15 : uint64_t esnap_num_blocks = cluster_sz * esnap_num_clusters / block_sz;
9064 : 15 : bool destroyed1 = false, destroyed2 = false;
9065 : 15 : uint64_t start_thread = g_ut_thread_id;
9066 : : struct spdk_io_channel *ch0, *ch1;
9067 [ - + ]: 15 : char buf[block_sz];
9068 : :
9069 : : /* Create and open an esnap clone blob */
9070 : 15 : ut_spdk_blob_opts_init(&opts);
9071 : 15 : ut_esnap_opts_init(block_sz, esnap_num_blocks, "esnap1", &destroyed1, &esnap1_opts);
9072 : 15 : opts.esnap_id = &esnap1_opts;
9073 : 15 : opts.esnap_id_len = sizeof(esnap1_opts);
9074 : 15 : opts.num_clusters = esnap_num_clusters;
9075 : 15 : blob = ut_blob_create_and_open(bs, &opts);
9076 : 15 : CU_ASSERT(blob != NULL);
9077 : 15 : CU_ASSERT(spdk_blob_is_esnap_clone(blob));
9078 [ - + ]: 15 : SPDK_CU_ASSERT_FATAL(blob->back_bs_dev != NULL);
9079 : 15 : esnap_dev = (struct ut_esnap_dev *)blob->back_bs_dev;
9080 [ - + ]: 15 : CU_ASSERT(strcmp(esnap_dev->ut_opts.name, "esnap1") == 0);
9081 : :
9082 : : /* Replace the external snapshot */
9083 : 15 : ut_esnap_opts_init(block_sz, esnap_num_blocks, "esnap2", &destroyed2, &esnap2_opts);
9084 : 15 : bs_dev = ut_esnap_dev_alloc(&esnap2_opts);
9085 [ - + ]: 15 : CU_ASSERT(!destroyed1);
9086 [ - + ]: 15 : CU_ASSERT(!destroyed2);
9087 : 15 : g_bserrno = 0xbad;
9088 : 15 : spdk_blob_set_esnap_bs_dev(blob, bs_dev, bs_op_complete, NULL);
9089 : 15 : poll_threads();
9090 : 15 : CU_ASSERT(g_bserrno == 0);
9091 [ - + ]: 15 : CU_ASSERT(destroyed1);
9092 [ - + ]: 15 : CU_ASSERT(!destroyed2);
9093 [ - + ]: 15 : SPDK_CU_ASSERT_FATAL(bs_dev == blob->back_bs_dev);
9094 [ - + ]: 15 : SPDK_CU_ASSERT_FATAL(bs_dev == spdk_blob_get_esnap_bs_dev(blob));
9095 : 15 : esnap_dev = (struct ut_esnap_dev *)blob->back_bs_dev;
9096 [ - + ]: 15 : CU_ASSERT(strcmp(esnap_dev->ut_opts.name, "esnap2") == 0);
9097 : :
9098 : : /* Create a couple channels */
9099 : 15 : set_thread(0);
9100 : 15 : ch0 = spdk_bs_alloc_io_channel(bs);
9101 : 15 : CU_ASSERT(ch0 != NULL);
9102 : 15 : spdk_blob_io_read(blob, ch0, buf, 0, 1, bs_op_complete, NULL);
9103 : 15 : set_thread(1);
9104 : 15 : ch1 = spdk_bs_alloc_io_channel(bs);
9105 : 15 : CU_ASSERT(ch1 != NULL);
9106 : 15 : spdk_blob_io_read(blob, ch1, buf, 0, 1, bs_op_complete, NULL);
9107 : 15 : set_thread(start_thread);
9108 : 15 : poll_threads();
9109 : 15 : CU_ASSERT(esnap_dev->num_channels == 2);
9110 : :
9111 : : /* Replace the external snapshot */
9112 : 15 : ut_esnap_opts_init(block_sz, esnap_num_blocks, "esnap1a", &destroyed1, &esnap1_opts);
9113 : 15 : bs_dev = ut_esnap_dev_alloc(&esnap1_opts);
9114 [ - + ]: 15 : destroyed1 = destroyed2 = false;
9115 : 15 : g_bserrno = 0xbad;
9116 : 15 : spdk_blob_set_esnap_bs_dev(blob, bs_dev, bs_op_complete, NULL);
9117 : 15 : poll_threads();
9118 : 15 : CU_ASSERT(g_bserrno == 0);
9119 [ - + ]: 15 : CU_ASSERT(!destroyed1);
9120 [ - + ]: 15 : CU_ASSERT(destroyed2);
9121 [ - + ]: 15 : SPDK_CU_ASSERT_FATAL(blob->back_bs_dev != NULL);
9122 : 15 : esnap_dev = (struct ut_esnap_dev *)blob->back_bs_dev;
9123 [ - + ]: 15 : CU_ASSERT(strcmp(esnap_dev->ut_opts.name, "esnap1a") == 0);
9124 : :
9125 : : /* Clean up */
9126 : 15 : set_thread(0);
9127 : 15 : spdk_bs_free_io_channel(ch0);
9128 : 15 : set_thread(1);
9129 : 15 : spdk_bs_free_io_channel(ch1);
9130 : 15 : set_thread(start_thread);
9131 : 15 : g_bserrno = 0xbad;
9132 : 15 : spdk_blob_close(blob, bs_op_complete, NULL);
9133 : 15 : poll_threads();
9134 : 15 : CU_ASSERT(g_bserrno == 0);
9135 : 15 : }
9136 : :
9137 : : static bool g_blob_is_degraded;
9138 : : static int g_blob_is_degraded_called;
9139 : :
9140 : : static bool
9141 : 90 : _blob_is_degraded(struct spdk_bs_dev *dev)
9142 : : {
9143 : 90 : g_blob_is_degraded_called++;
9144 [ - + ]: 90 : return g_blob_is_degraded;
9145 : : }
9146 : :
9147 : : static void
9148 : 15 : blob_is_degraded(void)
9149 : : {
9150 : 15 : struct spdk_bs_dev bs_is_degraded_null = { 0 };
9151 : 15 : struct spdk_bs_dev bs_is_degraded = { .is_degraded = _blob_is_degraded };
9152 : :
9153 : : /* No back_bs_dev, no bs->dev->is_degraded */
9154 : 15 : g_blob_is_degraded_called = 0;
9155 : 15 : CU_ASSERT(!spdk_blob_is_degraded(g_blob));
9156 : 15 : CU_ASSERT(g_blob_is_degraded_called == 0);
9157 : :
9158 : : /* No back_bs_dev, blobstore device degraded */
9159 : 15 : g_bs->dev->is_degraded = _blob_is_degraded;
9160 : 15 : g_blob_is_degraded_called = 0;
9161 : 15 : g_blob_is_degraded = true;
9162 : 15 : CU_ASSERT(spdk_blob_is_degraded(g_blob));
9163 : 15 : CU_ASSERT(g_blob_is_degraded_called == 1);
9164 : :
9165 : : /* No back_bs_dev, blobstore device not degraded */
9166 : 15 : g_bs->dev->is_degraded = _blob_is_degraded;
9167 : 15 : g_blob_is_degraded_called = 0;
9168 : 15 : g_blob_is_degraded = false;
9169 : 15 : CU_ASSERT(!spdk_blob_is_degraded(g_blob));
9170 : 15 : CU_ASSERT(g_blob_is_degraded_called == 1);
9171 : :
9172 : : /* back_bs_dev does not define is_degraded, no bs->dev->is_degraded */
9173 : 15 : g_bs->dev->is_degraded = NULL;
9174 : 15 : g_blob->back_bs_dev = &bs_is_degraded_null;
9175 : 15 : g_blob_is_degraded_called = 0;
9176 : 15 : g_blob_is_degraded = false;
9177 : 15 : CU_ASSERT(!spdk_blob_is_degraded(g_blob));
9178 : 15 : CU_ASSERT(g_blob_is_degraded_called == 0);
9179 : :
9180 : : /* back_bs_dev is not degraded, no bs->dev->is_degraded */
9181 : 15 : g_bs->dev->is_degraded = NULL;
9182 : 15 : g_blob->back_bs_dev = &bs_is_degraded;
9183 : 15 : g_blob_is_degraded_called = 0;
9184 : 15 : g_blob_is_degraded = false;
9185 : 15 : CU_ASSERT(!spdk_blob_is_degraded(g_blob));
9186 : 15 : CU_ASSERT(g_blob_is_degraded_called == 1);
9187 : :
9188 : : /* back_bs_dev is degraded, no bs->dev->is_degraded */
9189 : 15 : g_bs->dev->is_degraded = NULL;
9190 : 15 : g_blob->back_bs_dev = &bs_is_degraded;
9191 : 15 : g_blob_is_degraded_called = 0;
9192 : 15 : g_blob_is_degraded = true;
9193 : 15 : CU_ASSERT(spdk_blob_is_degraded(g_blob));
9194 : 15 : CU_ASSERT(g_blob_is_degraded_called == 1);
9195 : :
9196 : : /* back_bs_dev is not degraded, blobstore device is not degraded */
9197 : 15 : g_bs->dev->is_degraded = _blob_is_degraded;
9198 : 15 : g_blob->back_bs_dev = &bs_is_degraded;
9199 : 15 : g_blob_is_degraded_called = 0;
9200 : 15 : g_blob_is_degraded = false;
9201 : 15 : CU_ASSERT(!spdk_blob_is_degraded(g_blob));
9202 : 15 : CU_ASSERT(g_blob_is_degraded_called == 2);
9203 : :
9204 : 15 : g_blob->back_bs_dev = NULL;
9205 : 15 : }
9206 : :
9207 : : /* Resize a blob which is a clone created from snapshot. Verify read/writes to
9208 : : * expanded clone blob. Then inflate the clone blob. */
9209 : : static void
9210 : 15 : blob_clone_resize(void)
9211 : 15 : {
9212 : 15 : struct spdk_blob_store *bs = g_bs;
9213 : 15 : struct spdk_blob_opts opts;
9214 : : struct spdk_blob *blob, *clone, *snap_blob, *snap_blob_rsz;
9215 : : spdk_blob_id blobid, cloneid, snapid1, snapid2;
9216 : : uint64_t pages_per_cluster;
9217 [ - + ]: 15 : uint8_t payload_read[bs->dev->blocklen];
9218 [ - + ]: 15 : uint8_t payload_write[bs->dev->blocklen];
9219 : : struct spdk_io_channel *channel;
9220 : : uint64_t free_clusters;
9221 : :
9222 : 15 : channel = spdk_bs_alloc_io_channel(bs);
9223 [ - + ]: 15 : SPDK_CU_ASSERT_FATAL(channel != NULL);
9224 : :
9225 [ - + ]: 15 : pages_per_cluster = spdk_bs_get_cluster_size(bs) / spdk_bs_get_page_size(bs);
9226 : :
9227 : : /* Create blob with 10 clusters */
9228 : 15 : ut_spdk_blob_opts_init(&opts);
9229 : 15 : opts.num_clusters = 10;
9230 : :
9231 : 15 : blob = ut_blob_create_and_open(bs, &opts);
9232 : 15 : blobid = spdk_blob_get_id(blob);
9233 : 15 : CU_ASSERT(spdk_blob_get_num_clusters(blob) == 10);
9234 : :
9235 : : /* Create snapshot */
9236 : 15 : spdk_bs_create_snapshot(bs, blobid, NULL, blob_op_with_id_complete, NULL);
9237 : 15 : poll_threads();
9238 : 15 : CU_ASSERT(g_bserrno == 0);
9239 : 15 : CU_ASSERT(g_blobid != SPDK_BLOBID_INVALID);
9240 : 15 : snapid1 = g_blobid;
9241 : :
9242 : 15 : spdk_bs_create_clone(bs, snapid1, NULL, blob_op_with_id_complete, NULL);
9243 : 15 : poll_threads();
9244 : 15 : CU_ASSERT(g_bserrno == 0);
9245 : 15 : CU_ASSERT(g_blobid != SPDK_BLOBID_INVALID);
9246 : 15 : cloneid = g_blobid;
9247 : :
9248 : 15 : spdk_bs_open_blob(bs, cloneid, blob_op_with_handle_complete, NULL);
9249 : 15 : poll_threads();
9250 : 15 : CU_ASSERT(g_bserrno == 0);
9251 [ - + ]: 15 : SPDK_CU_ASSERT_FATAL(g_blob != NULL);
9252 : 15 : clone = g_blob;
9253 : 15 : CU_ASSERT(spdk_blob_get_num_clusters(clone) == 10);
9254 : :
9255 : 15 : g_bserrno = -1;
9256 : 15 : spdk_blob_resize(clone, 20, blob_op_complete, NULL);
9257 : 15 : poll_threads();
9258 : 15 : CU_ASSERT(g_bserrno == 0);
9259 : 15 : CU_ASSERT(spdk_blob_get_num_clusters(clone) == 20);
9260 : :
9261 : : /* Create another snapshot after resizing the clone */
9262 : 15 : spdk_bs_create_snapshot(bs, cloneid, NULL, blob_op_with_id_complete, NULL);
9263 : 15 : poll_threads();
9264 : 15 : CU_ASSERT(g_bserrno == 0);
9265 : 15 : CU_ASSERT(g_blobid != SPDK_BLOBID_INVALID);
9266 : 15 : snapid2 = g_blobid;
9267 : :
9268 : : /* Open the snapshot blobs */
9269 : 15 : spdk_bs_open_blob(bs, snapid1, blob_op_with_handle_complete, NULL);
9270 : 15 : CU_ASSERT(g_bserrno == 0);
9271 [ - + ]: 15 : SPDK_CU_ASSERT_FATAL(g_blob != NULL);
9272 : 15 : snap_blob = g_blob;
9273 [ - + ]: 15 : CU_ASSERT(snap_blob->data_ro == true);
9274 [ - + ]: 15 : CU_ASSERT(snap_blob->md_ro == true);
9275 : 15 : CU_ASSERT(spdk_blob_get_num_clusters(snap_blob) == 10);
9276 : :
9277 : 15 : spdk_bs_open_blob(bs, snapid2, blob_op_with_handle_complete, NULL);
9278 : 15 : CU_ASSERT(g_bserrno == 0);
9279 [ - + ]: 15 : SPDK_CU_ASSERT_FATAL(g_blob != NULL);
9280 : 15 : snap_blob_rsz = g_blob;
9281 [ - + ]: 15 : CU_ASSERT(snap_blob_rsz->data_ro == true);
9282 [ - + ]: 15 : CU_ASSERT(snap_blob_rsz->md_ro == true);
9283 : 15 : CU_ASSERT(spdk_blob_get_num_clusters(snap_blob_rsz) == 20);
9284 : :
9285 : : /* Confirm that clone is backed by snap_blob_rsz, and snap_blob_rsz is backed by snap_blob */
9286 [ - + ]: 15 : SPDK_CU_ASSERT_FATAL(snap_blob->back_bs_dev == NULL);
9287 [ - + ]: 15 : SPDK_CU_ASSERT_FATAL(blob->back_bs_dev != NULL);
9288 [ - + ]: 15 : SPDK_CU_ASSERT_FATAL(snap_blob_rsz->back_bs_dev != NULL);
9289 : :
9290 : : /* Write and read from pre-resize ranges */
9291 : 15 : g_bserrno = -1;
9292 [ - + ]: 15 : memset(payload_write, 0xE5, sizeof(payload_write));
9293 : 15 : spdk_blob_io_write(clone, channel, payload_write, 5 * pages_per_cluster, 1, blob_op_complete, NULL);
9294 : 15 : poll_threads();
9295 : 15 : CU_ASSERT(g_bserrno == 0);
9296 : :
9297 : 15 : g_bserrno = -1;
9298 [ - + ]: 15 : memset(payload_read, 0x00, sizeof(payload_read));
9299 : 15 : spdk_blob_io_read(clone, channel, payload_read, 5 * pages_per_cluster, 1, blob_op_complete, NULL);
9300 : 15 : poll_threads();
9301 : 15 : CU_ASSERT(g_bserrno == 0);
9302 [ - + - + ]: 15 : CU_ASSERT(memcmp(payload_write, payload_read, BLOCKLEN) == 0);
9303 : :
9304 : : /* Write and read from post-resize ranges */
9305 : 15 : g_bserrno = -1;
9306 [ - + ]: 15 : memset(payload_write, 0xE5, sizeof(payload_write));
9307 : 15 : spdk_blob_io_write(clone, channel, payload_write, 15 * pages_per_cluster, 1, blob_op_complete,
9308 : : NULL);
9309 : 15 : poll_threads();
9310 : 15 : CU_ASSERT(g_bserrno == 0);
9311 : :
9312 : 15 : g_bserrno = -1;
9313 [ - + ]: 15 : memset(payload_read, 0x00, sizeof(payload_read));
9314 : 15 : spdk_blob_io_read(clone, channel, payload_read, 15 * pages_per_cluster, 1, blob_op_complete, NULL);
9315 : 15 : poll_threads();
9316 : 15 : CU_ASSERT(g_bserrno == 0);
9317 [ - + - + ]: 15 : CU_ASSERT(memcmp(payload_write, payload_read, bs->dev->blocklen) == 0);
9318 : :
9319 : : /* Now do full blob inflation of the resized blob/clone. */
9320 : 15 : free_clusters = spdk_bs_free_cluster_count(bs);
9321 : 15 : spdk_bs_inflate_blob(bs, channel, cloneid, blob_op_complete, NULL);
9322 : 15 : poll_threads();
9323 : 15 : CU_ASSERT(g_bserrno == 0);
9324 : : /* We wrote to 2 clusters earlier, all remaining 18 clusters in
9325 : : * blob should get allocated after inflation */
9326 : 15 : CU_ASSERT(spdk_bs_free_cluster_count(bs) == free_clusters - 18);
9327 : :
9328 : 15 : spdk_blob_close(clone, blob_op_complete, NULL);
9329 : 15 : poll_threads();
9330 : 15 : CU_ASSERT(g_bserrno == 0);
9331 : :
9332 : 15 : spdk_blob_close(snap_blob, blob_op_complete, NULL);
9333 : 15 : poll_threads();
9334 : 15 : CU_ASSERT(g_bserrno == 0);
9335 : :
9336 : 15 : spdk_blob_close(snap_blob_rsz, blob_op_complete, NULL);
9337 : 15 : poll_threads();
9338 : 15 : CU_ASSERT(g_bserrno == 0);
9339 : :
9340 : 15 : ut_blob_close_and_delete(bs, blob);
9341 : :
9342 : 15 : spdk_bs_free_io_channel(channel);
9343 : 15 : }
9344 : :
9345 : :
9346 : : static void
9347 : 15 : blob_esnap_clone_resize(void)
9348 : : {
9349 : : struct spdk_bs_dev *dev;
9350 : : struct spdk_blob_store *bs;
9351 : 15 : struct spdk_bs_opts bsopts;
9352 : 15 : struct spdk_blob_opts opts;
9353 : 15 : struct ut_esnap_opts esnap_opts;
9354 : : struct spdk_blob *blob;
9355 : 15 : uint32_t block, esnap_blksz = 512, bs_blksz = 512;
9356 : 15 : const uint32_t cluster_sz = 4 * g_phys_blocklen;
9357 : 15 : const uint64_t esnap_num_clusters = 4;
9358 : 15 : const uint32_t esnap_sz = cluster_sz * esnap_num_clusters;
9359 [ - + ]: 15 : const uint64_t esnap_num_blocks = esnap_sz / esnap_blksz;
9360 [ - + ]: 15 : uint64_t blob_num_blocks = esnap_sz / bs_blksz;
9361 : : struct spdk_io_channel *bs_ch;
9362 : :
9363 : 15 : spdk_bs_opts_init(&bsopts, sizeof(bsopts));
9364 : 15 : bsopts.cluster_sz = cluster_sz;
9365 : 15 : bsopts.esnap_bs_dev_create = ut_esnap_create;
9366 : : /* Create device with desired block size */
9367 : 15 : dev = init_dev();
9368 : 15 : dev->blocklen = bs_blksz;
9369 [ - + ]: 15 : dev->blockcnt = DEV_BUFFER_SIZE / dev->blocklen;
9370 : : /* Initialize a new blob store */
9371 : 15 : spdk_bs_init(dev, &bsopts, bs_op_with_handle_complete, NULL);
9372 : 15 : poll_threads();
9373 : 15 : CU_ASSERT(g_bserrno == 0);
9374 [ - + ]: 15 : SPDK_CU_ASSERT_FATAL(g_bs != NULL);
9375 [ - + ]: 15 : SPDK_CU_ASSERT_FATAL(g_bs->io_unit_size == bs_blksz);
9376 : 15 : bs = g_bs;
9377 : :
9378 : 15 : bs_ch = spdk_bs_alloc_io_channel(bs);
9379 [ - + ]: 15 : SPDK_CU_ASSERT_FATAL(bs_ch != NULL);
9380 : :
9381 : : /* Create and open the esnap clone */
9382 : 15 : ut_spdk_blob_opts_init(&opts);
9383 : 15 : ut_esnap_opts_init(esnap_blksz, esnap_num_blocks, __func__, NULL, &esnap_opts);
9384 : 15 : opts.esnap_id = &esnap_opts;
9385 : 15 : opts.esnap_id_len = sizeof(esnap_opts);
9386 : 15 : opts.num_clusters = esnap_num_clusters;
9387 : 15 : blob = ut_blob_create_and_open(bs, &opts);
9388 [ - + ]: 15 : SPDK_CU_ASSERT_FATAL(blob != NULL);
9389 : :
9390 : 15 : g_bserrno = -1;
9391 : 15 : spdk_blob_resize(blob, esnap_num_clusters * 2, blob_op_complete, NULL);
9392 : 15 : poll_threads();
9393 : 15 : CU_ASSERT(g_bserrno == 0);
9394 : 15 : CU_ASSERT(spdk_blob_get_num_clusters(blob) == esnap_num_clusters * 2);
9395 : :
9396 : : /* Write one blob block at a time; verify that the surrounding blocks are OK */
9397 [ - + ]: 15 : blob_num_blocks = (spdk_blob_get_num_clusters(blob) * cluster_sz) / bs_blksz;
9398 [ + + ]: 6159 : for (block = 0; block < blob_num_blocks; block++) {
9399 [ - + ]: 6144 : char buf[bs_blksz];
9400 : : union ut_word word;
9401 : 6144 : word.f.blob_id = 0xfedcba90;
9402 : 6144 : word.f.lba = block;
9403 : 6144 : ut_memset8(buf, word.num, bs_blksz);
9404 : 6144 : spdk_blob_io_write(blob, bs_ch, buf, block, 1, bs_op_complete, NULL);
9405 : 6144 : poll_threads();
9406 : 6144 : CU_ASSERT(g_bserrno == 0);
9407 [ - + ]: 6144 : if (g_bserrno != 0) {
9408 : 0 : break;
9409 : : }
9410 : : /* Read and verify the block before the current block */
9411 [ + + ]: 6144 : if (block != 0) {
9412 : 6129 : spdk_blob_io_read(blob, bs_ch, buf, block - 1, 1, bs_op_complete, NULL);
9413 : 6129 : poll_threads();
9414 : 6129 : CU_ASSERT(g_bserrno == 0);
9415 [ - + ]: 6129 : if (g_bserrno != 0) {
9416 : 0 : break;
9417 : : }
9418 : 6129 : CU_ASSERT(ut_esnap_content_is_correct(buf, bs_blksz, word.f.blob_id,
9419 : : (block - 1) * bs_blksz, bs_blksz));
9420 : : }
9421 : : /* Read and verify the current block */
9422 : 6144 : spdk_blob_io_read(blob, bs_ch, buf, block, 1, bs_op_complete, NULL);
9423 : 6144 : poll_threads();
9424 : 6144 : CU_ASSERT(g_bserrno == 0);
9425 [ - + ]: 6144 : if (g_bserrno != 0) {
9426 : 0 : break;
9427 : : }
9428 : 6144 : CU_ASSERT(ut_esnap_content_is_correct(buf, bs_blksz, word.f.blob_id,
9429 : : block * bs_blksz, bs_blksz));
9430 : : /* Check the block that follows */
9431 [ + + ]: 6144 : if (block + 1 < blob_num_blocks) {
9432 : 6129 : g_bserrno = 0xbad;
9433 : 6129 : spdk_blob_io_read(blob, bs_ch, buf, block + 1, 1, bs_op_complete, NULL);
9434 : 6129 : poll_threads();
9435 : 6129 : CU_ASSERT(g_bserrno == 0);
9436 [ - + ]: 6129 : if (g_bserrno != 0) {
9437 : 0 : break;
9438 : : }
9439 : 6129 : CU_ASSERT(ut_esnap_content_is_correct(buf, bs_blksz, blob->id,
9440 : : (block + 1) * bs_blksz,
9441 : : esnap_blksz));
9442 : : }
9443 : : }
9444 : : /* Clean up */
9445 : 15 : spdk_bs_free_io_channel(bs_ch);
9446 : 15 : g_bserrno = 0xbad;
9447 : 15 : spdk_blob_close(blob, blob_op_complete, NULL);
9448 : 15 : poll_threads();
9449 : 15 : CU_ASSERT(g_bserrno == 0);
9450 : 15 : spdk_bs_unload(g_bs, bs_op_complete, NULL);
9451 : 15 : poll_threads();
9452 : 15 : CU_ASSERT(g_bserrno == 0);
9453 : 15 : g_bs = NULL;
9454 [ - + ]: 15 : memset(g_dev_buffer, 0, DEV_BUFFER_SIZE);
9455 : 15 : }
9456 : :
9457 : : static void
9458 : 30720 : bs_dev_io_complete_cb(struct spdk_io_channel *channel, void *cb_arg, int bserrno)
9459 : : {
9460 : 30720 : g_bserrno = bserrno;
9461 : 30720 : }
9462 : :
9463 : : static void
9464 : 15 : blob_shallow_copy(void)
9465 : : {
9466 : 15 : struct spdk_blob_store *bs = g_bs;
9467 : 15 : struct spdk_blob_opts blob_opts;
9468 : : struct spdk_blob *blob;
9469 : : spdk_blob_id blobid;
9470 : 15 : uint64_t num_clusters = 4;
9471 : : struct spdk_bs_dev *ext_dev;
9472 : 15 : struct spdk_bs_dev_cb_args ext_args;
9473 : : struct spdk_io_channel *bdev_ch, *blob_ch;
9474 : 15 : uint8_t buf1[DEV_BUFFER_BLOCKLEN];
9475 : 15 : uint8_t buf2[DEV_BUFFER_BLOCKLEN];
9476 : : uint64_t io_units_per_cluster;
9477 : : uint64_t offset;
9478 : : int rc;
9479 : :
9480 : 15 : blob_ch = spdk_bs_alloc_io_channel(bs);
9481 [ - + ]: 15 : SPDK_CU_ASSERT_FATAL(blob_ch != NULL);
9482 : :
9483 : : /* Set blob dimension and as thin provisioned */
9484 : 15 : ut_spdk_blob_opts_init(&blob_opts);
9485 : 15 : blob_opts.thin_provision = true;
9486 : 15 : blob_opts.num_clusters = num_clusters;
9487 : :
9488 : : /* Create a blob */
9489 : 15 : blob = ut_blob_create_and_open(bs, &blob_opts);
9490 [ - + ]: 15 : SPDK_CU_ASSERT_FATAL(blob != NULL);
9491 : 15 : blobid = spdk_blob_get_id(blob);
9492 : 15 : io_units_per_cluster = bs_io_units_per_cluster(blob);
9493 : :
9494 : : /* Write on cluster 2 and 4 of blob */
9495 [ + + ]: 3855 : for (offset = io_units_per_cluster; offset < 2 * io_units_per_cluster; offset++) {
9496 : 3840 : memset(buf1, offset, DEV_BUFFER_BLOCKLEN);
9497 : 3840 : spdk_blob_io_write(blob, blob_ch, buf1, offset, 1, blob_op_complete, NULL);
9498 : 3840 : poll_threads();
9499 : 3840 : CU_ASSERT(g_bserrno == 0);
9500 : : }
9501 [ + + ]: 3855 : for (offset = 3 * io_units_per_cluster; offset < 4 * io_units_per_cluster; offset++) {
9502 : 3840 : memset(buf1, offset, DEV_BUFFER_BLOCKLEN);
9503 : 3840 : spdk_blob_io_write(blob, blob_ch, buf1, offset, 1, blob_op_complete, NULL);
9504 : 3840 : poll_threads();
9505 : 3840 : CU_ASSERT(g_bserrno == 0);
9506 : : }
9507 : 15 : CU_ASSERT(spdk_blob_get_num_allocated_clusters(blob) == 2);
9508 : :
9509 : : /* Make a snapshot over blob */
9510 : 15 : spdk_bs_create_snapshot(bs, blobid, NULL, blob_op_with_id_complete, NULL);
9511 : 15 : poll_threads();
9512 : 15 : CU_ASSERT(g_bserrno == 0);
9513 : 15 : CU_ASSERT(spdk_blob_get_num_allocated_clusters(blob) == 0);
9514 : :
9515 : : /* Write on cluster 1 and 3 of blob */
9516 [ + + ]: 3855 : for (offset = 0; offset < io_units_per_cluster; offset++) {
9517 : 3840 : memset(buf1, offset, DEV_BUFFER_BLOCKLEN);
9518 : 3840 : spdk_blob_io_write(blob, blob_ch, buf1, offset, 1, blob_op_complete, NULL);
9519 : 3840 : poll_threads();
9520 : 3840 : CU_ASSERT(g_bserrno == 0);
9521 : : }
9522 [ + + ]: 3855 : for (offset = 2 * io_units_per_cluster; offset < 3 * io_units_per_cluster; offset++) {
9523 : 3840 : memset(buf1, offset, DEV_BUFFER_BLOCKLEN);
9524 : 3840 : spdk_blob_io_write(blob, blob_ch, buf1, offset, 1, blob_op_complete, NULL);
9525 : 3840 : poll_threads();
9526 : 3840 : CU_ASSERT(g_bserrno == 0);
9527 : : }
9528 : 15 : CU_ASSERT(spdk_blob_get_num_allocated_clusters(blob) == 2);
9529 : :
9530 : : /* Shallow copy with a not read only blob */
9531 : 15 : ext_dev = init_ext_dev(num_clusters * 1024 * 1024, DEV_BUFFER_BLOCKLEN);
9532 : 15 : rc = spdk_bs_blob_shallow_copy(bs, blob_ch, blobid, ext_dev,
9533 : : blob_shallow_copy_status_cb, NULL,
9534 : : blob_op_complete, NULL);
9535 : 15 : CU_ASSERT(rc == 0);
9536 : 15 : poll_threads();
9537 : 15 : CU_ASSERT(g_bserrno == -EPERM);
9538 : 15 : ext_dev->destroy(ext_dev);
9539 : :
9540 : : /* Set blob read only */
9541 : 15 : spdk_blob_set_read_only(blob);
9542 : 15 : spdk_blob_sync_md(blob, blob_op_complete, NULL);
9543 : 15 : poll_threads();
9544 : 15 : CU_ASSERT(g_bserrno == 0);
9545 : :
9546 : : /* Shallow copy over a spdk_bs_dev with incorrect size */
9547 : 15 : ext_dev = init_ext_dev(1, DEV_BUFFER_BLOCKLEN);
9548 : 15 : rc = spdk_bs_blob_shallow_copy(bs, blob_ch, blobid, ext_dev,
9549 : : blob_shallow_copy_status_cb, NULL,
9550 : : blob_op_complete, NULL);
9551 : 15 : CU_ASSERT(rc == 0);
9552 : 15 : poll_threads();
9553 : 15 : CU_ASSERT(g_bserrno == -EINVAL);
9554 : 15 : ext_dev->destroy(ext_dev);
9555 : :
9556 : : /* Shallow copy over a spdk_bs_dev with incorrect block len */
9557 : 15 : ext_dev = init_ext_dev(num_clusters * 1024 * 1024, DEV_BUFFER_BLOCKLEN * 2);
9558 : 15 : rc = spdk_bs_blob_shallow_copy(bs, blob_ch, blobid, ext_dev,
9559 : : blob_shallow_copy_status_cb, NULL,
9560 : : blob_op_complete, NULL);
9561 : 15 : CU_ASSERT(rc == 0);
9562 : 15 : poll_threads();
9563 : 15 : CU_ASSERT(g_bserrno == -EINVAL);
9564 : 15 : ext_dev->destroy(ext_dev);
9565 : :
9566 : : /* Initialize ext_dev for the successuful shallow copy */
9567 : 15 : ext_dev = init_ext_dev(num_clusters * 1024 * 1024, DEV_BUFFER_BLOCKLEN);
9568 : 15 : bdev_ch = ext_dev->create_channel(ext_dev);
9569 [ - + ]: 15 : SPDK_CU_ASSERT_FATAL(bdev_ch != NULL);
9570 : 15 : ext_args.cb_fn = bs_dev_io_complete_cb;
9571 [ + + ]: 15375 : for (offset = 0; offset < 4 * io_units_per_cluster; offset++) {
9572 : 15360 : memset(buf2, 0xff, DEV_BUFFER_BLOCKLEN);
9573 : 15360 : ext_dev->write(ext_dev, bdev_ch, buf2, offset, 1, &ext_args);
9574 : 15360 : poll_threads();
9575 : 15360 : CU_ASSERT(g_bserrno == 0);
9576 : : }
9577 : :
9578 : : /* Correct shallow copy of blob over bdev */
9579 : 15 : rc = spdk_bs_blob_shallow_copy(bs, blob_ch, blobid, ext_dev,
9580 : : blob_shallow_copy_status_cb, NULL,
9581 : : blob_op_complete, NULL);
9582 : 15 : CU_ASSERT(rc == 0);
9583 : 15 : poll_thread_times(0, 1);
9584 : 15 : CU_ASSERT(g_copied_clusters_count == 1);
9585 : 15 : poll_thread_times(0, 2);
9586 : 15 : CU_ASSERT(g_bserrno == 0);
9587 : 15 : CU_ASSERT(g_copied_clusters_count == 2);
9588 : :
9589 : : /* Read from bdev */
9590 : : /* Only cluster 1 and 3 must be filled */
9591 : : /* Clusters 2 and 4 should not have been touched */
9592 [ + + ]: 3855 : for (offset = 0; offset < io_units_per_cluster; offset++) {
9593 : 3840 : memset(buf1, offset, DEV_BUFFER_BLOCKLEN);
9594 : 3840 : ext_dev->read(ext_dev, bdev_ch, buf2, offset, 1, &ext_args);
9595 : 3840 : poll_threads();
9596 : 3840 : CU_ASSERT(g_bserrno == 0);
9597 : 3840 : CU_ASSERT(memcmp(buf1, buf2, DEV_BUFFER_BLOCKLEN) == 0);
9598 : : }
9599 [ + + ]: 3855 : for (offset = io_units_per_cluster; offset < 2 * io_units_per_cluster; offset++) {
9600 : 3840 : memset(buf1, 0xff, DEV_BUFFER_BLOCKLEN);
9601 : 3840 : ext_dev->read(ext_dev, bdev_ch, buf2, offset, 1, &ext_args);
9602 : 3840 : poll_threads();
9603 : 3840 : CU_ASSERT(g_bserrno == 0);
9604 : 3840 : CU_ASSERT(memcmp(buf1, buf2, DEV_BUFFER_BLOCKLEN) == 0);
9605 : : }
9606 [ + + ]: 3855 : for (offset = 2 * io_units_per_cluster; offset < 3 * io_units_per_cluster; offset++) {
9607 : 3840 : memset(buf1, offset, DEV_BUFFER_BLOCKLEN);
9608 : 3840 : ext_dev->read(ext_dev, bdev_ch, buf2, offset, 1, &ext_args);
9609 : 3840 : poll_threads();
9610 : 3840 : CU_ASSERT(g_bserrno == 0);
9611 : 3840 : CU_ASSERT(memcmp(buf1, buf2, DEV_BUFFER_BLOCKLEN) == 0);
9612 : : }
9613 [ + + ]: 3855 : for (offset = 3 * io_units_per_cluster; offset < 4 * io_units_per_cluster; offset++) {
9614 : 3840 : memset(buf1, 0xff, DEV_BUFFER_BLOCKLEN);
9615 : 3840 : ext_dev->read(ext_dev, bdev_ch, buf2, offset, 1, &ext_args);
9616 : 3840 : poll_threads();
9617 : 3840 : CU_ASSERT(g_bserrno == 0);
9618 : 3840 : CU_ASSERT(memcmp(buf1, buf2, DEV_BUFFER_BLOCKLEN) == 0);
9619 : : }
9620 : :
9621 : : /* Clean up */
9622 : 15 : ext_dev->destroy_channel(ext_dev, bdev_ch);
9623 : 15 : ext_dev->destroy(ext_dev);
9624 : 15 : spdk_bs_free_io_channel(blob_ch);
9625 : 15 : ut_blob_close_and_delete(bs, blob);
9626 : 15 : poll_threads();
9627 : 15 : }
9628 : :
9629 : : static void
9630 : 15 : blob_set_parent(void)
9631 : : {
9632 : 15 : struct spdk_blob_store *bs = g_bs;
9633 : 15 : struct spdk_blob_opts opts;
9634 : 15 : struct ut_esnap_opts esnap_opts;
9635 : : struct spdk_blob *blob1, *blob2, *blob3, *blob4, *blob5;
9636 : : spdk_blob_id blobid1, blobid2, blobid3, blobid4, blobid5,
9637 : : snapshotid1, snapshotid2, snapshotid3;
9638 : : uint32_t cluster_sz, block_sz;
9639 : 15 : const uint32_t esnap_num_clusters = 4;
9640 : : uint64_t esnap_num_blocks;
9641 : 15 : spdk_blob_id ids[2];
9642 : 15 : size_t clone_count = 2;
9643 : :
9644 : 15 : cluster_sz = spdk_bs_get_cluster_size(bs);
9645 : 15 : block_sz = spdk_bs_get_io_unit_size(bs);
9646 [ - + ]: 15 : esnap_num_blocks = cluster_sz * esnap_num_clusters / block_sz;
9647 : :
9648 : : /* Create a normal blob and make a couple of snapshots */
9649 : 15 : ut_spdk_blob_opts_init(&opts);
9650 : 15 : blob1 = ut_blob_create_and_open(bs, &opts);
9651 [ - + ]: 15 : SPDK_CU_ASSERT_FATAL(blob1 != NULL);
9652 : 15 : blobid1 = spdk_blob_get_id(blob1);
9653 : 15 : spdk_bs_create_snapshot(bs, blobid1, NULL, blob_op_with_id_complete, NULL);
9654 : 15 : poll_threads();
9655 [ - + ]: 15 : SPDK_CU_ASSERT_FATAL(g_bserrno == 0);
9656 [ - + ]: 15 : SPDK_CU_ASSERT_FATAL(g_blobid != SPDK_BLOBID_INVALID);
9657 : 15 : snapshotid1 = g_blobid;
9658 : 15 : spdk_bs_create_snapshot(bs, blobid1, NULL, blob_op_with_id_complete, NULL);
9659 : 15 : poll_threads();
9660 [ - + ]: 15 : SPDK_CU_ASSERT_FATAL(g_bserrno == 0);
9661 [ - + ]: 15 : SPDK_CU_ASSERT_FATAL(g_blobid != SPDK_BLOBID_INVALID);
9662 : 15 : snapshotid2 = g_blobid;
9663 : :
9664 : : /* Call set_parent with an invalid snapshotid */
9665 : 15 : spdk_bs_blob_set_parent(bs, blobid1, SPDK_BLOBID_INVALID, blob_op_complete, NULL);
9666 : 15 : poll_threads();
9667 : 15 : CU_ASSERT(g_bserrno == -EINVAL);
9668 : :
9669 : : /* Call set_parent with blobid and snapshotid the same */
9670 : 15 : spdk_bs_blob_set_parent(bs, blobid1, blobid1, blob_op_complete, NULL);
9671 : 15 : poll_threads();
9672 : 15 : CU_ASSERT(g_bserrno == -EINVAL);
9673 : :
9674 : : /* Call set_parent with a blob and its parent snapshot */
9675 : 15 : spdk_bs_blob_set_parent(bs, blobid1, snapshotid2, blob_op_complete, NULL);
9676 : 15 : poll_threads();
9677 : 15 : CU_ASSERT(g_bserrno == -EEXIST);
9678 : :
9679 : : /* Create an esnap clone blob */
9680 : 15 : ut_spdk_blob_opts_init(&opts);
9681 : 15 : ut_esnap_opts_init(block_sz, esnap_num_blocks, __func__, NULL, &esnap_opts);
9682 : 15 : opts.esnap_id = &esnap_opts;
9683 : 15 : opts.esnap_id_len = sizeof(esnap_opts);
9684 : 15 : opts.num_clusters = esnap_num_clusters;
9685 : 15 : blob2 = ut_blob_create_and_open(bs, &opts);
9686 [ - + ]: 15 : SPDK_CU_ASSERT_FATAL(blob2 != NULL);
9687 : 15 : blobid2 = spdk_blob_get_id(blob2);
9688 : 15 : CU_ASSERT(spdk_blob_is_esnap_clone(blob2));
9689 : :
9690 : : /* Call set_parent with a non snapshot parent */
9691 : 15 : spdk_bs_blob_set_parent(bs, blobid2, blobid1, blob_op_complete, NULL);
9692 : 15 : poll_threads();
9693 : 15 : CU_ASSERT(g_bserrno == -EINVAL);
9694 : :
9695 : : /* Call set_parent with blob and snapshot of different size */
9696 : 15 : spdk_bs_blob_set_parent(bs, blobid2, snapshotid1, blob_op_complete, NULL);
9697 : 15 : poll_threads();
9698 : 15 : CU_ASSERT(g_bserrno == -EINVAL);
9699 : :
9700 : : /* Call set_parent correctly with a snapshot's clone blob */
9701 : 15 : spdk_bs_blob_set_parent(bs, blobid1, snapshotid1, blob_op_complete, NULL);
9702 : 15 : poll_threads();
9703 : 15 : CU_ASSERT(g_bserrno == 0);
9704 : :
9705 : : /* Check relations */
9706 : 15 : CU_ASSERT(spdk_blob_is_clone(blob1));
9707 : 15 : CU_ASSERT(spdk_blob_get_parent_snapshot(bs, blobid1) == snapshotid1);
9708 : 15 : CU_ASSERT(spdk_blob_get_clones(bs, snapshotid1, ids, &clone_count) == 0);
9709 : 15 : CU_ASSERT(clone_count == 2);
9710 : 15 : CU_ASSERT(ids[1] == blobid1);
9711 : :
9712 : : /* Create another normal blob with size equal to esnap size and make a snapshot */
9713 : 15 : ut_spdk_blob_opts_init(&opts);
9714 : 15 : opts.num_clusters = esnap_num_clusters;
9715 : 15 : opts.thin_provision = true;
9716 : 15 : blob3 = ut_blob_create_and_open(bs, &opts);
9717 [ - + ]: 15 : SPDK_CU_ASSERT_FATAL(blob3 != NULL);
9718 : 15 : blobid3 = spdk_blob_get_id(blob3);
9719 : 15 : spdk_bs_create_snapshot(bs, blobid3, NULL, blob_op_with_id_complete, NULL);
9720 : 15 : poll_threads();
9721 [ - + ]: 15 : SPDK_CU_ASSERT_FATAL(g_bserrno == 0);
9722 [ - + ]: 15 : SPDK_CU_ASSERT_FATAL(g_blobid != SPDK_BLOBID_INVALID);
9723 : 15 : snapshotid3 = g_blobid;
9724 : :
9725 : : /* Call set_parent correctly with an esnap's clone blob */
9726 : 15 : spdk_bs_blob_set_parent(bs, blobid2, snapshotid3, blob_op_complete, NULL);
9727 : 15 : poll_threads();
9728 : 15 : CU_ASSERT(g_bserrno == 0);
9729 : :
9730 : : /* Check relations */
9731 : 15 : CU_ASSERT(!spdk_blob_is_esnap_clone(blob2));
9732 : 15 : CU_ASSERT(spdk_blob_is_clone(blob2));
9733 : 15 : CU_ASSERT(spdk_blob_get_parent_snapshot(bs, blobid2) == snapshotid3);
9734 : 15 : CU_ASSERT(spdk_blob_get_clones(bs, snapshotid3, ids, &clone_count) == 0);
9735 : 15 : CU_ASSERT(clone_count == 2);
9736 : 15 : CU_ASSERT(ids[1] == blobid2);
9737 : :
9738 : : /* Create a not thin-provisioned blob that is not a clone */
9739 : 15 : ut_spdk_blob_opts_init(&opts);
9740 : 15 : opts.thin_provision = false;
9741 : 15 : blob4 = ut_blob_create_and_open(bs, &opts);
9742 [ - + ]: 15 : SPDK_CU_ASSERT_FATAL(blob4 != NULL);
9743 : 15 : blobid4 = spdk_blob_get_id(blob4);
9744 : :
9745 : : /* Call set_parent with a blob that isn't a clone and that isn't thin-provisioned */
9746 : 15 : spdk_bs_blob_set_parent(bs, blobid4, snapshotid2, blob_op_complete, NULL);
9747 : 15 : poll_threads();
9748 : 15 : CU_ASSERT(g_bserrno == -EINVAL);
9749 : :
9750 : : /* Create a thin-provisioned blob that is not a clone */
9751 : 15 : ut_spdk_blob_opts_init(&opts);
9752 : 15 : opts.thin_provision = true;
9753 : 15 : blob5 = ut_blob_create_and_open(bs, &opts);
9754 [ - + ]: 15 : SPDK_CU_ASSERT_FATAL(blob5 != NULL);
9755 : 15 : blobid5 = spdk_blob_get_id(blob5);
9756 : :
9757 : : /* Call set_parent correctly with a blob that isn't a clone */
9758 : 15 : spdk_bs_blob_set_parent(bs, blobid5, snapshotid2, blob_op_complete, NULL);
9759 : 15 : poll_threads();
9760 : 15 : CU_ASSERT(g_bserrno == 0);
9761 : :
9762 : : /* Check relations */
9763 : 15 : CU_ASSERT(spdk_blob_is_clone(blob5));
9764 : 15 : CU_ASSERT(spdk_blob_get_parent_snapshot(bs, blobid5) == snapshotid2);
9765 : 15 : CU_ASSERT(spdk_blob_get_clones(bs, snapshotid2, ids, &clone_count) == 0);
9766 : 15 : CU_ASSERT(clone_count == 1);
9767 : 15 : CU_ASSERT(ids[0] == blobid5);
9768 : :
9769 : : /* Clean up */
9770 : 15 : ut_blob_close_and_delete(bs, blob5);
9771 : 15 : ut_blob_close_and_delete(bs, blob4);
9772 : 15 : ut_blob_close_and_delete(bs, blob3);
9773 : 15 : ut_blob_close_and_delete(bs, blob2);
9774 : 15 : ut_blob_close_and_delete(bs, blob1);
9775 : 15 : spdk_bs_delete_blob(bs, snapshotid3, blob_op_complete, NULL);
9776 : 15 : poll_threads();
9777 : 15 : CU_ASSERT(g_bserrno == 0);
9778 : 15 : spdk_bs_delete_blob(bs, snapshotid2, blob_op_complete, NULL);
9779 : 15 : poll_threads();
9780 : 15 : CU_ASSERT(g_bserrno == 0);
9781 : 15 : spdk_bs_delete_blob(bs, snapshotid1, blob_op_complete, NULL);
9782 : 15 : poll_threads();
9783 : 15 : CU_ASSERT(g_bserrno == 0);
9784 : 15 : }
9785 : :
9786 : : static void
9787 : 15 : blob_set_external_parent(void)
9788 : : {
9789 : 15 : struct spdk_blob_store *bs = g_bs;
9790 : 15 : struct spdk_blob_opts opts;
9791 : 15 : struct ut_esnap_opts esnap_opts, esnap_opts2;
9792 : : struct spdk_blob *blob1, *blob2, *blob3, *blob4;
9793 : 15 : spdk_blob_id blobid1, blobid2, blobid3, blobid4, snapshotid;
9794 : : uint32_t cluster_sz, block_sz;
9795 : 15 : const uint32_t esnap_num_clusters = 4;
9796 : : uint64_t esnap_num_blocks;
9797 : : struct spdk_bs_dev *esnap_dev1, *esnap_dev2, *esnap_dev3;
9798 : 15 : const void *esnap_id;
9799 : 15 : size_t esnap_id_len;
9800 : : int rc;
9801 : :
9802 : 15 : cluster_sz = spdk_bs_get_cluster_size(bs);
9803 : 15 : block_sz = spdk_bs_get_io_unit_size(bs);
9804 [ - + ]: 15 : esnap_num_blocks = cluster_sz * esnap_num_clusters / block_sz;
9805 : 15 : esnap_dev1 = init_dev();
9806 : 15 : esnap_dev2 = init_dev();
9807 : 15 : esnap_dev3 = init_dev();
9808 : :
9809 : : /* Create an esnap clone blob */
9810 : 15 : ut_spdk_blob_opts_init(&opts);
9811 : 15 : ut_esnap_opts_init(block_sz, esnap_num_blocks, __func__, NULL, &esnap_opts);
9812 : 15 : opts.esnap_id = &esnap_opts;
9813 : 15 : opts.esnap_id_len = sizeof(esnap_opts);
9814 : 15 : opts.num_clusters = esnap_num_clusters;
9815 : 15 : blob1 = ut_blob_create_and_open(bs, &opts);
9816 [ - + ]: 15 : SPDK_CU_ASSERT_FATAL(blob1 != NULL);
9817 : 15 : blobid1 = spdk_blob_get_id(blob1);
9818 : 15 : CU_ASSERT(spdk_blob_is_esnap_clone(blob1));
9819 : :
9820 : : /* Call set_esternal_parent with blobid and esnapid the same */
9821 : 15 : spdk_bs_blob_set_external_parent(bs, blobid1, esnap_dev1, &blobid1, sizeof(blobid1),
9822 : : blob_op_complete, NULL);
9823 : 15 : CU_ASSERT(g_bserrno == -EINVAL);
9824 : :
9825 : : /* Call set_external_parent with esnap of incompatible size */
9826 : 15 : esnap_dev1->blockcnt = esnap_num_blocks - 1;
9827 : 15 : spdk_bs_blob_set_external_parent(bs, blobid1, esnap_dev1, opts.esnap_id, opts.esnap_id_len,
9828 : : blob_op_complete, NULL);
9829 : 15 : CU_ASSERT(g_bserrno == -EINVAL);
9830 : :
9831 : : /* Call set_external_parent with a blob and its parent esnap */
9832 : 15 : esnap_dev1->blocklen = block_sz;
9833 : 15 : esnap_dev1->blockcnt = esnap_num_blocks;
9834 : 15 : spdk_bs_blob_set_external_parent(bs, blobid1, esnap_dev1, opts.esnap_id, opts.esnap_id_len,
9835 : : blob_op_complete, NULL);
9836 : 15 : poll_threads();
9837 : 15 : CU_ASSERT(g_bserrno == -EEXIST);
9838 : :
9839 : : /* Create a blob that is a clone of a snapshots */
9840 : 15 : ut_spdk_blob_opts_init(&opts);
9841 : 15 : blob2 = ut_blob_create_and_open(bs, &opts);
9842 [ - + ]: 15 : SPDK_CU_ASSERT_FATAL(blob2 != NULL);
9843 : 15 : blobid2 = spdk_blob_get_id(blob2);
9844 : 15 : spdk_bs_create_snapshot(bs, blobid2, NULL, blob_op_with_id_complete, NULL);
9845 : 15 : poll_threads();
9846 [ - + ]: 15 : SPDK_CU_ASSERT_FATAL(g_bserrno == 0);
9847 [ - + ]: 15 : SPDK_CU_ASSERT_FATAL(g_blobid != SPDK_BLOBID_INVALID);
9848 : 15 : snapshotid = g_blobid;
9849 : :
9850 : : /* Call set_parent correctly with a snapshot's clone blob */
9851 : 15 : esnap_dev2->blocklen = block_sz;
9852 : 15 : esnap_dev2->blockcnt = esnap_num_blocks;
9853 : 15 : ut_esnap_opts_init(block_sz, esnap_num_blocks, __func__, NULL, &esnap_opts2);
9854 : 15 : spdk_bs_blob_set_external_parent(bs, blobid2, esnap_dev2, &esnap_opts2, sizeof(esnap_opts2),
9855 : : blob_op_complete, NULL);
9856 : 15 : poll_threads();
9857 : 15 : CU_ASSERT(g_bserrno == 0);
9858 : :
9859 : : /* Check relations */
9860 : 15 : rc = spdk_blob_get_esnap_id(blob2, &esnap_id, &esnap_id_len);
9861 : 15 : CU_ASSERT(spdk_blob_is_esnap_clone(blob2));
9862 : 15 : CU_ASSERT(!spdk_blob_is_clone(blob2));
9863 [ + - + - : 15 : CU_ASSERT(rc == 0 && esnap_id_len == sizeof(esnap_opts2) &&
+ + + - ]
9864 : : memcmp(esnap_id, &esnap_opts2, esnap_id_len) == 0);
9865 : 15 : CU_ASSERT(blob2->parent_id == SPDK_BLOBID_EXTERNAL_SNAPSHOT);
9866 : :
9867 : : /* Create a not thin-provisioned blob that is not a clone */
9868 : 15 : ut_spdk_blob_opts_init(&opts);
9869 : 15 : opts.thin_provision = false;
9870 : 15 : blob3 = ut_blob_create_and_open(bs, &opts);
9871 [ - + ]: 15 : SPDK_CU_ASSERT_FATAL(blob3 != NULL);
9872 : 15 : blobid3 = spdk_blob_get_id(blob3);
9873 : :
9874 : : /* Call set_external_parent with a blob that isn't a clone and that isn't thin-provisioned */
9875 : 15 : spdk_bs_blob_set_external_parent(bs, blobid3, esnap_dev1, &esnap_opts, sizeof(esnap_opts),
9876 : : blob_op_complete, NULL);
9877 : 15 : poll_threads();
9878 : 15 : CU_ASSERT(g_bserrno == -EINVAL);
9879 : :
9880 : : /* Create a thin-provisioned blob that is not a clone */
9881 : 15 : ut_spdk_blob_opts_init(&opts);
9882 : 15 : opts.thin_provision = true;
9883 : 15 : blob4 = ut_blob_create_and_open(bs, &opts);
9884 [ - + ]: 15 : SPDK_CU_ASSERT_FATAL(blob4 != NULL);
9885 : 15 : blobid4 = spdk_blob_get_id(blob4);
9886 : :
9887 : : /* Call set_external_parent correctly with a blob that isn't a clone */
9888 : 15 : esnap_dev3->blocklen = block_sz;
9889 : 15 : esnap_dev3->blockcnt = esnap_num_blocks;
9890 : 15 : ut_esnap_opts_init(block_sz, esnap_num_blocks, __func__, NULL, &esnap_opts);
9891 : 15 : spdk_bs_blob_set_external_parent(bs, blobid4, esnap_dev3, &esnap_opts, sizeof(esnap_opts),
9892 : : blob_op_complete, NULL);
9893 : 15 : poll_threads();
9894 : 15 : CU_ASSERT(g_bserrno == 0);
9895 : :
9896 : : /* Check relations */
9897 : 15 : rc = spdk_blob_get_esnap_id(blob4, &esnap_id, &esnap_id_len);
9898 : 15 : CU_ASSERT(spdk_blob_is_esnap_clone(blob4));
9899 : 15 : CU_ASSERT(!spdk_blob_is_clone(blob4));
9900 [ + - + - : 15 : CU_ASSERT(rc == 0 && esnap_id_len == sizeof(esnap_opts) &&
+ + + - ]
9901 : : memcmp(esnap_id, &esnap_opts, esnap_id_len) == 0);
9902 : 15 : CU_ASSERT(blob4->parent_id == SPDK_BLOBID_EXTERNAL_SNAPSHOT);
9903 : :
9904 : 15 : ut_blob_close_and_delete(bs, blob4);
9905 : 15 : ut_blob_close_and_delete(bs, blob3);
9906 : 15 : ut_blob_close_and_delete(bs, blob2);
9907 : 15 : ut_blob_close_and_delete(bs, blob1);
9908 : 15 : spdk_bs_delete_blob(bs, snapshotid, blob_op_complete, NULL);
9909 : 15 : dev_destroy(esnap_dev1);
9910 : 15 : poll_threads();
9911 : 15 : CU_ASSERT(g_bserrno == 0);
9912 : 15 : }
9913 : :
9914 : : static void
9915 : 825 : suite_bs_setup(void)
9916 : : {
9917 : : struct spdk_bs_dev *dev;
9918 : :
9919 : 825 : dev = init_dev();
9920 [ - + ]: 825 : memset(g_dev_buffer, 0, DEV_BUFFER_SIZE);
9921 : 825 : spdk_bs_init(dev, NULL, bs_op_with_handle_complete, NULL);
9922 : 825 : poll_threads();
9923 : 825 : CU_ASSERT(g_bserrno == 0);
9924 : 825 : CU_ASSERT(g_bs != NULL);
9925 : 825 : }
9926 : :
9927 : : static void
9928 : 135 : suite_esnap_bs_setup(void)
9929 : : {
9930 : : struct spdk_bs_dev *dev;
9931 : 135 : struct spdk_bs_opts bs_opts;
9932 : :
9933 : 135 : dev = init_dev();
9934 [ - + ]: 135 : memset(g_dev_buffer, 0, DEV_BUFFER_SIZE);
9935 : 135 : spdk_bs_opts_init(&bs_opts, sizeof(bs_opts));
9936 : 135 : bs_opts.cluster_sz = 4 * g_phys_blocklen;
9937 : 135 : bs_opts.esnap_bs_dev_create = ut_esnap_create;
9938 : 135 : spdk_bs_init(dev, &bs_opts, bs_op_with_handle_complete, NULL);
9939 : 135 : poll_threads();
9940 : 135 : CU_ASSERT(g_bserrno == 0);
9941 [ - + ]: 135 : SPDK_CU_ASSERT_FATAL(g_bs != NULL);
9942 : 135 : }
9943 : :
9944 : : static void
9945 : 960 : suite_bs_cleanup(void)
9946 : : {
9947 [ + - ]: 960 : if (g_bs != NULL) {
9948 : 960 : spdk_bs_unload(g_bs, bs_op_complete, NULL);
9949 : 960 : poll_threads();
9950 : 960 : CU_ASSERT(g_bserrno == 0);
9951 : 960 : g_bs = NULL;
9952 : : }
9953 [ - + ]: 960 : memset(g_dev_buffer, 0, DEV_BUFFER_SIZE);
9954 : 960 : }
9955 : :
9956 : : static struct spdk_blob *
9957 : 1350 : ut_blob_create_and_open(struct spdk_blob_store *bs, struct spdk_blob_opts *blob_opts)
9958 : : {
9959 : : struct spdk_blob *blob;
9960 : 1350 : struct spdk_blob_opts create_blob_opts;
9961 : : spdk_blob_id blobid;
9962 : :
9963 [ + + ]: 1350 : if (blob_opts == NULL) {
9964 : 480 : ut_spdk_blob_opts_init(&create_blob_opts);
9965 : 480 : blob_opts = &create_blob_opts;
9966 : : }
9967 : :
9968 : 1350 : spdk_bs_create_blob_ext(bs, blob_opts, blob_op_with_id_complete, NULL);
9969 : 1350 : poll_threads();
9970 : 1350 : CU_ASSERT(g_bserrno == 0);
9971 : 1350 : CU_ASSERT(g_blobid != SPDK_BLOBID_INVALID);
9972 : 1350 : blobid = g_blobid;
9973 : 1350 : g_blobid = -1;
9974 : :
9975 : 1350 : spdk_bs_open_blob(bs, blobid, blob_op_with_handle_complete, NULL);
9976 : 1350 : poll_threads();
9977 : 1350 : CU_ASSERT(g_bserrno == 0);
9978 : 1350 : CU_ASSERT(g_blob != NULL);
9979 : 1350 : blob = g_blob;
9980 : :
9981 : 1350 : g_blob = NULL;
9982 : 1350 : g_bserrno = -1;
9983 : :
9984 : 1350 : return blob;
9985 : : }
9986 : :
9987 : : static void
9988 : 1200 : ut_blob_close_and_delete(struct spdk_blob_store *bs, struct spdk_blob *blob)
9989 : : {
9990 : 1200 : spdk_blob_id blobid = spdk_blob_get_id(blob);
9991 : :
9992 : 1200 : spdk_blob_close(blob, blob_op_complete, NULL);
9993 : 1200 : poll_threads();
9994 : 1200 : CU_ASSERT(g_bserrno == 0);
9995 : 1200 : g_blob = NULL;
9996 : :
9997 : 1200 : spdk_bs_delete_blob(bs, blobid, blob_op_complete, NULL);
9998 : 1200 : poll_threads();
9999 : 1200 : CU_ASSERT(g_bserrno == 0);
10000 : 1200 : g_bserrno = -1;
10001 : 1200 : }
10002 : :
10003 : : static void
10004 : 180 : suite_blob_setup(void)
10005 : : {
10006 : 180 : suite_bs_setup();
10007 : 180 : CU_ASSERT(g_bs != NULL);
10008 : :
10009 : 180 : g_blob = ut_blob_create_and_open(g_bs, NULL);
10010 : 180 : CU_ASSERT(g_blob != NULL);
10011 : 180 : }
10012 : :
10013 : : static void
10014 : 180 : suite_blob_cleanup(void)
10015 : : {
10016 : 180 : ut_blob_close_and_delete(g_bs, g_blob);
10017 : 180 : CU_ASSERT(g_blob == NULL);
10018 : :
10019 : 180 : suite_bs_cleanup();
10020 : 180 : CU_ASSERT(g_bs == NULL);
10021 : 180 : }
10022 : :
10023 : : static int
10024 : 12 : ut_setup_config_nocopy_noextent(void)
10025 : : {
10026 : 12 : g_dev_copy_enabled = false;
10027 : 12 : g_use_extent_table = false;
10028 : 12 : g_phys_blocklen = 4096;
10029 : :
10030 : 12 : return 0;
10031 : : }
10032 : :
10033 : : static int
10034 : 12 : ut_setup_config_nocopy_extent(void)
10035 : : {
10036 : 12 : g_dev_copy_enabled = false;
10037 : 12 : g_use_extent_table = true;
10038 : 12 : g_phys_blocklen = 4096;
10039 : :
10040 : 12 : return 0;
10041 : : }
10042 : :
10043 : : static int
10044 : 12 : ut_setup_config_nocopy_extent_16k_phys(void)
10045 : : {
10046 : 12 : g_dev_copy_enabled = false;
10047 : 12 : g_use_extent_table = true;
10048 : 12 : g_phys_blocklen = 16384;
10049 : :
10050 : 12 : return 0;
10051 : : }
10052 : :
10053 : :
10054 : : static int
10055 : 12 : ut_setup_config_copy_noextent(void)
10056 : : {
10057 : 12 : g_dev_copy_enabled = true;
10058 : 12 : g_use_extent_table = false;
10059 : 12 : g_phys_blocklen = 4096;
10060 : :
10061 : 12 : return 0;
10062 : : }
10063 : :
10064 : : static int
10065 : 12 : ut_setup_config_copy_extent(void)
10066 : : {
10067 : 12 : g_dev_copy_enabled = true;
10068 : 12 : g_use_extent_table = true;
10069 : 12 : g_phys_blocklen = 4096;
10070 : :
10071 : 12 : return 0;
10072 : : }
10073 : :
10074 : : struct ut_config {
10075 : : const char *suffix;
10076 : : CU_InitializeFunc setup_cb;
10077 : : };
10078 : :
10079 : : int
10080 : 3 : main(int argc, char **argv)
10081 : : {
10082 : : CU_pSuite suite, suite_bs, suite_blob, suite_esnap_bs;
10083 : : unsigned int i, num_failures;
10084 : 3 : char suite_name[4096];
10085 : : struct ut_config *config;
10086 : 3 : struct ut_config configs[] = {
10087 : : {"nocopy_noextent", ut_setup_config_nocopy_noextent},
10088 : : {"nocopy_extent", ut_setup_config_nocopy_extent},
10089 : : {"nocopy_extent_16k_phys", ut_setup_config_nocopy_extent_16k_phys},
10090 : : {"copy_noextent", ut_setup_config_copy_noextent},
10091 : : {"copy_extent", ut_setup_config_copy_extent},
10092 : : };
10093 : :
10094 : 3 : CU_initialize_registry();
10095 : :
10096 [ + + ]: 18 : for (i = 0; i < SPDK_COUNTOF(configs); ++i) {
10097 : 15 : config = &configs[i];
10098 : :
10099 [ - + ]: 15 : snprintf(suite_name, sizeof(suite_name), "blob_%s", config->suffix);
10100 : 15 : suite = CU_add_suite(suite_name, config->setup_cb, NULL);
10101 : :
10102 [ - + ]: 15 : snprintf(suite_name, sizeof(suite_name), "blob_bs_%s", config->suffix);
10103 : 15 : suite_bs = CU_add_suite_with_setup_and_teardown(suite_name, config->setup_cb, NULL,
10104 : : suite_bs_setup, suite_bs_cleanup);
10105 : :
10106 [ - + ]: 15 : snprintf(suite_name, sizeof(suite_name), "blob_blob_%s", config->suffix);
10107 : 15 : suite_blob = CU_add_suite_with_setup_and_teardown(suite_name, config->setup_cb, NULL,
10108 : : suite_blob_setup, suite_blob_cleanup);
10109 : :
10110 [ - + ]: 15 : snprintf(suite_name, sizeof(suite_name), "blob_esnap_bs_%s", config->suffix);
10111 : 15 : suite_esnap_bs = CU_add_suite_with_setup_and_teardown(suite_name, config->setup_cb, NULL,
10112 : : suite_esnap_bs_setup,
10113 : : suite_bs_cleanup);
10114 : :
10115 : 15 : CU_ADD_TEST(suite, blob_init);
10116 : 15 : CU_ADD_TEST(suite_bs, blob_open);
10117 : 15 : CU_ADD_TEST(suite_bs, blob_create);
10118 : 15 : CU_ADD_TEST(suite_bs, blob_create_loop);
10119 : 15 : CU_ADD_TEST(suite_bs, blob_create_fail);
10120 : 15 : CU_ADD_TEST(suite_bs, blob_create_internal);
10121 : 15 : CU_ADD_TEST(suite_bs, blob_create_zero_extent);
10122 : 15 : CU_ADD_TEST(suite, blob_thin_provision);
10123 : 15 : CU_ADD_TEST(suite_bs, blob_snapshot);
10124 : 15 : CU_ADD_TEST(suite_bs, blob_clone);
10125 : 15 : CU_ADD_TEST(suite_bs, blob_inflate);
10126 : 15 : CU_ADD_TEST(suite_bs, blob_delete);
10127 : 15 : CU_ADD_TEST(suite_bs, blob_resize_test);
10128 : 15 : CU_ADD_TEST(suite_bs, blob_resize_thin_test);
10129 : 15 : CU_ADD_TEST(suite, blob_read_only);
10130 : 15 : CU_ADD_TEST(suite_bs, channel_ops);
10131 : 15 : CU_ADD_TEST(suite_bs, blob_super);
10132 : 15 : CU_ADD_TEST(suite_blob, blob_write);
10133 : 15 : CU_ADD_TEST(suite_blob, blob_read);
10134 : 15 : CU_ADD_TEST(suite_blob, blob_rw_verify);
10135 : 15 : CU_ADD_TEST(suite_bs, blob_rw_verify_iov);
10136 : 15 : CU_ADD_TEST(suite_blob, blob_rw_verify_iov_nomem);
10137 : 15 : CU_ADD_TEST(suite_blob, blob_rw_iov_read_only);
10138 : 15 : CU_ADD_TEST(suite_bs, blob_unmap);
10139 : 15 : CU_ADD_TEST(suite_bs, blob_iter);
10140 : 15 : CU_ADD_TEST(suite_blob, blob_xattr);
10141 : 15 : CU_ADD_TEST(suite_bs, blob_parse_md);
10142 : 15 : CU_ADD_TEST(suite, bs_load);
10143 : 15 : CU_ADD_TEST(suite_bs, bs_load_pending_removal);
10144 : 15 : CU_ADD_TEST(suite, bs_load_custom_cluster_size);
10145 : 15 : CU_ADD_TEST(suite, bs_load_after_failed_grow);
10146 : 15 : CU_ADD_TEST(suite_bs, bs_unload);
10147 : 15 : CU_ADD_TEST(suite, bs_cluster_sz);
10148 : 15 : CU_ADD_TEST(suite_bs, bs_usable_clusters);
10149 : 15 : CU_ADD_TEST(suite, bs_resize_md);
10150 : 15 : CU_ADD_TEST(suite, bs_destroy);
10151 : 15 : CU_ADD_TEST(suite, bs_type);
10152 : 15 : CU_ADD_TEST(suite, bs_super_block);
10153 : 15 : CU_ADD_TEST(suite, bs_test_recover_cluster_count);
10154 : 15 : CU_ADD_TEST(suite, bs_grow_live);
10155 : 15 : CU_ADD_TEST(suite, bs_grow_live_no_space);
10156 : 15 : CU_ADD_TEST(suite, bs_test_grow);
10157 : 15 : CU_ADD_TEST(suite, blob_serialize_test);
10158 : 15 : CU_ADD_TEST(suite_bs, blob_crc);
10159 : 15 : CU_ADD_TEST(suite, super_block_crc);
10160 : 15 : CU_ADD_TEST(suite_blob, blob_dirty_shutdown);
10161 : 15 : CU_ADD_TEST(suite_bs, blob_flags);
10162 : 15 : CU_ADD_TEST(suite_bs, bs_version);
10163 : 15 : CU_ADD_TEST(suite_bs, blob_set_xattrs_test);
10164 : 15 : CU_ADD_TEST(suite_bs, blob_thin_prov_alloc);
10165 : 15 : CU_ADD_TEST(suite_bs, blob_insert_cluster_msg_test);
10166 : 15 : CU_ADD_TEST(suite_bs, blob_thin_prov_rw);
10167 : 15 : CU_ADD_TEST(suite, blob_thin_prov_write_count_io);
10168 : 15 : CU_ADD_TEST(suite, blob_thin_prov_unmap_cluster);
10169 : 15 : CU_ADD_TEST(suite_bs, blob_thin_prov_rle);
10170 : 15 : CU_ADD_TEST(suite_bs, blob_thin_prov_rw_iov);
10171 : 15 : CU_ADD_TEST(suite, bs_load_iter_test);
10172 : 15 : CU_ADD_TEST(suite_bs, blob_snapshot_rw);
10173 : 15 : CU_ADD_TEST(suite_bs, blob_snapshot_rw_iov);
10174 : 15 : CU_ADD_TEST(suite, blob_relations);
10175 : 15 : CU_ADD_TEST(suite, blob_relations2);
10176 : 15 : CU_ADD_TEST(suite, blob_relations3);
10177 : 15 : CU_ADD_TEST(suite, blobstore_clean_power_failure);
10178 : 15 : CU_ADD_TEST(suite, blob_delete_snapshot_power_failure);
10179 : 15 : CU_ADD_TEST(suite, blob_create_snapshot_power_failure);
10180 : 15 : CU_ADD_TEST(suite_bs, blob_inflate_rw);
10181 : 15 : CU_ADD_TEST(suite_bs, blob_snapshot_freeze_io);
10182 : 15 : CU_ADD_TEST(suite_bs, blob_operation_split_rw);
10183 : 15 : CU_ADD_TEST(suite_bs, blob_operation_split_rw_iov);
10184 : 15 : CU_ADD_TEST(suite, blob_io_unit);
10185 : 15 : CU_ADD_TEST(suite, blob_io_unit_compatibility);
10186 : 15 : CU_ADD_TEST(suite_bs, blob_simultaneous_operations);
10187 : 15 : CU_ADD_TEST(suite_bs, blob_persist_test);
10188 : 15 : CU_ADD_TEST(suite_bs, blob_decouple_snapshot);
10189 : 15 : CU_ADD_TEST(suite_bs, blob_seek_io_unit);
10190 : 15 : CU_ADD_TEST(suite_esnap_bs, blob_esnap_create);
10191 : 15 : CU_ADD_TEST(suite_bs, blob_nested_freezes);
10192 : 15 : CU_ADD_TEST(suite, blob_ext_md_pages);
10193 : 15 : CU_ADD_TEST(suite, blob_esnap_io_4096_4096);
10194 : 15 : CU_ADD_TEST(suite, blob_esnap_io_512_512);
10195 : 15 : CU_ADD_TEST(suite, blob_esnap_io_4096_512);
10196 : 15 : CU_ADD_TEST(suite, blob_esnap_io_512_4096);
10197 : 15 : CU_ADD_TEST(suite_esnap_bs, blob_esnap_thread_add_remove);
10198 : 15 : CU_ADD_TEST(suite_esnap_bs, blob_esnap_clone_snapshot);
10199 : 15 : CU_ADD_TEST(suite_esnap_bs, blob_esnap_clone_inflate);
10200 : 15 : CU_ADD_TEST(suite_esnap_bs, blob_esnap_clone_decouple);
10201 : 15 : CU_ADD_TEST(suite_esnap_bs, blob_esnap_clone_reload);
10202 : 15 : CU_ADD_TEST(suite_esnap_bs, blob_esnap_hotplug);
10203 : 15 : CU_ADD_TEST(suite_blob, blob_is_degraded);
10204 : 15 : CU_ADD_TEST(suite_bs, blob_clone_resize);
10205 : 15 : CU_ADD_TEST(suite, blob_esnap_clone_resize);
10206 : 15 : CU_ADD_TEST(suite_bs, blob_shallow_copy);
10207 : 15 : CU_ADD_TEST(suite_esnap_bs, blob_set_parent);
10208 : 15 : CU_ADD_TEST(suite_esnap_bs, blob_set_external_parent);
10209 : : }
10210 : :
10211 : 3 : allocate_threads(2);
10212 : 3 : set_thread(0);
10213 : :
10214 : 3 : g_dev_buffer = calloc(1, DEV_BUFFER_SIZE);
10215 : :
10216 : 3 : num_failures = spdk_ut_run_tests(argc, argv, NULL);
10217 : :
10218 : 3 : free(g_dev_buffer);
10219 : :
10220 : 3 : free_threads();
10221 : :
10222 : 3 : return num_failures;
10223 : : }
|