Branch data Line data Source code
1 : : /* SPDX-License-Identifier: BSD-3-Clause
2 : : * Copyright (C) 2016 Intel Corporation.
3 : : * All rights reserved.
4 : : * Copyright (c) 2022 NVIDIA CORPORATION & AFFILIATES. All rights reserved.
5 : : */
6 : :
7 : : #include "spdk/stdinc.h"
8 : :
9 : : #include "spdk_internal/cunit.h"
10 : :
11 : : #include "reduce/reduce.c"
12 : : #include "spdk_internal/mock.h"
13 : : #define UNIT_TEST_NO_VTOPHYS
14 : : #include "common/lib/test_env.c"
15 : : #undef UNIT_TEST_NO_VTOPHYS
16 : :
17 : : static struct spdk_reduce_vol *g_vol;
18 : : static int g_reduce_errno;
19 : : static char *g_volatile_pm_buf;
20 : : static size_t g_volatile_pm_buf_len;
21 : : static char *g_persistent_pm_buf;
22 : : static size_t g_persistent_pm_buf_len;
23 : : static char *g_backing_dev_buf;
24 : : static char g_path[REDUCE_PATH_MAX];
25 : : static char *g_decomp_buf;
26 : : static int g_decompressed_len;
27 : :
28 : : #define TEST_MD_PATH "/tmp"
29 : :
30 : : uint64_t
31 : 13830 : spdk_vtophys(const void *buf, uint64_t *size)
32 : : {
33 : : /* add + 1 to buf addr for cases where buf is the start of the page, that will give us correct end of the page */
34 : 13830 : const uint8_t *page_2mb_end = (const uint8_t *)SPDK_ALIGN_CEIL((uintptr_t)buf + 1, VALUE_2MB);
35 : 13830 : uint64_t bytes_to_page_end = page_2mb_end - (const uint8_t *)buf;
36 : : uint64_t _size;
37 : :
38 [ + - ]: 13830 : if (*size) {
39 : 13830 : _size = *size;
40 : 13830 : _size = spdk_min(_size, bytes_to_page_end);
41 : 13830 : *size = _size;
42 : : }
43 : :
44 : 13830 : return (uintptr_t)buf;
45 : : }
46 : :
47 : : enum ut_reduce_bdev_io_type {
48 : : UT_REDUCE_IO_READV = 1,
49 : : UT_REDUCE_IO_WRITEV = 2,
50 : : UT_REDUCE_IO_UNMAP = 3,
51 : : };
52 : :
53 : : struct ut_reduce_bdev_io {
54 : : enum ut_reduce_bdev_io_type type;
55 : : struct spdk_reduce_backing_dev *backing_dev;
56 : : struct iovec *iov;
57 : : int iovcnt;
58 : : uint64_t lba;
59 : : uint32_t lba_count;
60 : : struct spdk_reduce_vol_cb_args *args;
61 : : TAILQ_ENTRY(ut_reduce_bdev_io) link;
62 : : };
63 : :
64 : : static bool g_defer_bdev_io = false;
65 : : static TAILQ_HEAD(, ut_reduce_bdev_io) g_pending_bdev_io =
66 : : TAILQ_HEAD_INITIALIZER(g_pending_bdev_io);
67 : : static uint32_t g_pending_bdev_io_count = 0;
68 : :
69 : : static void
70 : 40 : sync_pm_buf(const void *addr, size_t length)
71 : : {
72 : 40 : uint64_t offset = (char *)addr - g_volatile_pm_buf;
73 : :
74 [ - + - + ]: 40 : memcpy(&g_persistent_pm_buf[offset], addr, length);
75 : 40 : }
76 : :
77 : : int
78 : : pmem_msync(const void *addr, size_t length)
79 : : {
80 : 0 : sync_pm_buf(addr, length);
81 : 0 : return 0;
82 : : }
83 : :
84 : : void
85 : : pmem_persist(const void *addr, size_t len)
86 : : {
87 : 40 : sync_pm_buf(addr, len);
88 : 40 : }
89 : :
90 : : static void
91 : 1 : get_pm_file_size(void)
92 : : {
93 : 1 : struct spdk_reduce_vol_params params;
94 : : uint64_t pm_size, expected_pm_size;
95 : :
96 : 1 : params.backing_io_unit_size = 4096;
97 : 1 : params.chunk_size = 4096 * 4;
98 : 1 : params.vol_size = 4096 * 4 * 100;
99 : :
100 : 1 : pm_size = _get_pm_file_size(¶ms);
101 : 1 : expected_pm_size = sizeof(struct spdk_reduce_vol_superblock);
102 : : /* 100 chunks in logical map * 8 bytes per chunk */
103 : 1 : expected_pm_size += 100 * sizeof(uint64_t);
104 : : /* 100 chunks * (chunk struct size + 4 backing io units per chunk * 8 bytes per backing io unit) */
105 : 1 : expected_pm_size += 100 * (sizeof(struct spdk_reduce_chunk_map) + 4 * sizeof(uint64_t));
106 : : /* reduce allocates some extra chunks too for in-flight writes when logical map
107 : : * is full. REDUCE_EXTRA_CHUNKS is a private #ifdef in reduce.c Here we need the num chunks
108 : : * times (chunk struct size + 4 backing io units per chunk * 8 bytes per backing io unit).
109 : : */
110 : 1 : expected_pm_size += REDUCE_NUM_EXTRA_CHUNKS *
111 : : (sizeof(struct spdk_reduce_chunk_map) + 4 * sizeof(uint64_t));
112 : : /* reduce will add some padding so numbers may not match exactly. Make sure
113 : : * they are close though.
114 : : */
115 : 1 : CU_ASSERT((pm_size - expected_pm_size) <= REDUCE_PM_SIZE_ALIGNMENT);
116 : 1 : }
117 : :
118 : : static void
119 : 1 : get_vol_size(void)
120 : : {
121 : : uint64_t chunk_size, backing_dev_size;
122 : :
123 : 1 : chunk_size = 16 * 1024;
124 : 1 : backing_dev_size = 16 * 1024 * 1000;
125 : 1 : CU_ASSERT(_get_vol_size(chunk_size, backing_dev_size) < backing_dev_size);
126 : 1 : }
127 : :
128 : : void *
129 : : pmem_map_file(const char *path, size_t len, int flags, mode_t mode,
130 : : size_t *mapped_lenp, int *is_pmemp)
131 : : {
132 : 23 : CU_ASSERT(g_volatile_pm_buf == NULL);
133 [ - + ]: 23 : snprintf(g_path, sizeof(g_path), "%s", path);
134 : 23 : *is_pmemp = 1;
135 : :
136 [ + + ]: 23 : if (g_persistent_pm_buf == NULL) {
137 : 14 : g_persistent_pm_buf = calloc(1, len);
138 : 14 : g_persistent_pm_buf_len = len;
139 [ - + ]: 14 : SPDK_CU_ASSERT_FATAL(g_persistent_pm_buf != NULL);
140 : : }
141 : :
142 : 23 : *mapped_lenp = g_persistent_pm_buf_len;
143 : 23 : g_volatile_pm_buf = calloc(1, g_persistent_pm_buf_len);
144 [ - + ]: 23 : SPDK_CU_ASSERT_FATAL(g_volatile_pm_buf != NULL);
145 [ - + - + ]: 23 : memcpy(g_volatile_pm_buf, g_persistent_pm_buf, g_persistent_pm_buf_len);
146 : 23 : g_volatile_pm_buf_len = g_persistent_pm_buf_len;
147 : :
148 : 23 : return g_volatile_pm_buf;
149 : : }
150 : :
151 : : int
152 : : pmem_unmap(void *addr, size_t len)
153 : : {
154 : 23 : CU_ASSERT(addr == g_volatile_pm_buf);
155 : 23 : CU_ASSERT(len == g_volatile_pm_buf_len);
156 : 23 : free(g_volatile_pm_buf);
157 : 23 : g_volatile_pm_buf = NULL;
158 : 23 : g_volatile_pm_buf_len = 0;
159 : :
160 : 23 : return 0;
161 : : }
162 : :
163 : : static void
164 : 14 : persistent_pm_buf_destroy(void)
165 : : {
166 : 14 : CU_ASSERT(g_persistent_pm_buf != NULL);
167 : 14 : free(g_persistent_pm_buf);
168 : 14 : g_persistent_pm_buf = NULL;
169 : 14 : g_persistent_pm_buf_len = 0;
170 : 14 : }
171 : :
172 : : static void
173 : 1 : unlink_cb(void)
174 : : {
175 : 1 : persistent_pm_buf_destroy();
176 : 1 : }
177 : :
178 : : static void
179 : 16 : init_cb(void *cb_arg, struct spdk_reduce_vol *vol, int reduce_errno)
180 : : {
181 : 16 : g_vol = vol;
182 : 16 : g_reduce_errno = reduce_errno;
183 : 16 : }
184 : :
185 : : static void
186 : 10 : load_cb(void *cb_arg, struct spdk_reduce_vol *vol, int reduce_errno)
187 : : {
188 : 10 : g_vol = vol;
189 : 10 : g_reduce_errno = reduce_errno;
190 : 10 : }
191 : :
192 : : static void
193 : 23 : unload_cb(void *cb_arg, int reduce_errno)
194 : : {
195 : 23 : g_reduce_errno = reduce_errno;
196 : 23 : }
197 : :
198 : : static void
199 : 1 : init_failure(void)
200 : : {
201 : 1 : struct spdk_reduce_vol_params params = {};
202 : 1 : struct spdk_reduce_backing_dev backing_dev = {};
203 : :
204 : 1 : backing_dev.blocklen = 512;
205 : : /* This blockcnt is too small for a reduce vol - there needs to be
206 : : * enough space for at least REDUCE_NUM_EXTRA_CHUNKS + 1 chunks.
207 : : */
208 : 1 : backing_dev.blockcnt = 20;
209 : :
210 : 1 : params.vol_size = 0;
211 : 1 : params.chunk_size = 16 * 1024;
212 : 1 : params.backing_io_unit_size = backing_dev.blocklen;
213 : 1 : params.logical_block_size = 512;
214 : :
215 : : /* backing_dev has an invalid size. This should fail. */
216 : 1 : g_vol = NULL;
217 : 1 : g_reduce_errno = 0;
218 : 1 : spdk_reduce_vol_init(¶ms, &backing_dev, TEST_MD_PATH, init_cb, NULL);
219 : 1 : CU_ASSERT(g_reduce_errno == -EINVAL);
220 [ - + ]: 1 : SPDK_CU_ASSERT_FATAL(g_vol == NULL);
221 : :
222 : : /* backing_dev now has valid size, but backing_dev still has null
223 : : * function pointers. This should fail.
224 : : */
225 : 1 : backing_dev.blockcnt = 20000;
226 : :
227 : 1 : g_vol = NULL;
228 : 1 : g_reduce_errno = 0;
229 : 1 : spdk_reduce_vol_init(¶ms, &backing_dev, TEST_MD_PATH, init_cb, NULL);
230 : 1 : CU_ASSERT(g_reduce_errno == -EINVAL);
231 [ - + ]: 1 : SPDK_CU_ASSERT_FATAL(g_vol == NULL);
232 : 1 : }
233 : :
234 : : static void
235 : 272 : backing_dev_readv_execute(struct spdk_reduce_backing_dev *backing_dev,
236 : : struct iovec *iov, int iovcnt,
237 : : uint64_t lba, uint32_t lba_count,
238 : : struct spdk_reduce_vol_cb_args *args)
239 : : {
240 : : char *offset;
241 : : int i;
242 : :
243 : 272 : offset = g_backing_dev_buf + lba * backing_dev->blocklen;
244 [ + + ]: 555 : for (i = 0; i < iovcnt; i++) {
245 [ - + - + ]: 283 : memcpy(iov[i].iov_base, offset, iov[i].iov_len);
246 : 283 : offset += iov[i].iov_len;
247 : : }
248 : 272 : args->cb_fn(args->cb_arg, 0);
249 : 272 : }
250 : :
251 : : static void
252 : 4 : backing_dev_insert_io(enum ut_reduce_bdev_io_type type, struct spdk_reduce_backing_dev *backing_dev,
253 : : struct iovec *iov, int iovcnt, uint64_t lba, uint32_t lba_count,
254 : : struct spdk_reduce_vol_cb_args *args)
255 : : {
256 : : struct ut_reduce_bdev_io *ut_bdev_io;
257 : :
258 : 4 : ut_bdev_io = calloc(1, sizeof(*ut_bdev_io));
259 [ - + ]: 4 : SPDK_CU_ASSERT_FATAL(ut_bdev_io != NULL);
260 : :
261 : 4 : ut_bdev_io->type = type;
262 : 4 : ut_bdev_io->backing_dev = backing_dev;
263 : 4 : ut_bdev_io->iov = iov;
264 : 4 : ut_bdev_io->iovcnt = iovcnt;
265 : 4 : ut_bdev_io->lba = lba;
266 : 4 : ut_bdev_io->lba_count = lba_count;
267 : 4 : ut_bdev_io->args = args;
268 : 4 : TAILQ_INSERT_TAIL(&g_pending_bdev_io, ut_bdev_io, link);
269 : 4 : g_pending_bdev_io_count++;
270 : 4 : }
271 : :
272 : : static void
273 : 272 : backing_dev_readv(struct spdk_reduce_backing_dev *backing_dev, struct iovec *iov, int iovcnt,
274 : : uint64_t lba, uint32_t lba_count, struct spdk_reduce_vol_cb_args *args)
275 : : {
276 [ - + + + ]: 272 : if (g_defer_bdev_io == false) {
277 : 271 : CU_ASSERT(g_pending_bdev_io_count == 0);
278 : 271 : CU_ASSERT(TAILQ_EMPTY(&g_pending_bdev_io));
279 : 271 : backing_dev_readv_execute(backing_dev, iov, iovcnt, lba, lba_count, args);
280 : 271 : return;
281 : : }
282 : :
283 : 1 : backing_dev_insert_io(UT_REDUCE_IO_READV, backing_dev, iov, iovcnt, lba, lba_count, args);
284 : : }
285 : :
286 : : static void
287 : 54 : backing_dev_writev_execute(struct spdk_reduce_backing_dev *backing_dev,
288 : : struct iovec *iov, int iovcnt,
289 : : uint64_t lba, uint32_t lba_count,
290 : : struct spdk_reduce_vol_cb_args *args)
291 : : {
292 : : char *offset;
293 : : int i;
294 : :
295 : 54 : offset = g_backing_dev_buf + lba * backing_dev->blocklen;
296 [ + + ]: 108 : for (i = 0; i < iovcnt; i++) {
297 [ - + - + ]: 54 : memcpy(offset, iov[i].iov_base, iov[i].iov_len);
298 : 54 : offset += iov[i].iov_len;
299 : : }
300 : 54 : args->cb_fn(args->cb_arg, 0);
301 : 54 : }
302 : :
303 : : static void
304 : 54 : backing_dev_writev(struct spdk_reduce_backing_dev *backing_dev, struct iovec *iov, int iovcnt,
305 : : uint64_t lba, uint32_t lba_count, struct spdk_reduce_vol_cb_args *args)
306 : : {
307 [ - + + + ]: 54 : if (g_defer_bdev_io == false) {
308 : 51 : CU_ASSERT(g_pending_bdev_io_count == 0);
309 : 51 : CU_ASSERT(TAILQ_EMPTY(&g_pending_bdev_io));
310 : 51 : backing_dev_writev_execute(backing_dev, iov, iovcnt, lba, lba_count, args);
311 : 51 : return;
312 : : }
313 : :
314 : 3 : backing_dev_insert_io(UT_REDUCE_IO_WRITEV, backing_dev, iov, iovcnt, lba, lba_count, args);
315 : : }
316 : :
317 : : static void
318 : 0 : backing_dev_unmap_execute(struct spdk_reduce_backing_dev *backing_dev,
319 : : uint64_t lba, uint32_t lba_count,
320 : : struct spdk_reduce_vol_cb_args *args)
321 : : {
322 : : char *offset;
323 : :
324 : 0 : offset = g_backing_dev_buf + lba * backing_dev->blocklen;
325 [ # # ]: 0 : memset(offset, 0, lba_count * backing_dev->blocklen);
326 : 0 : args->cb_fn(args->cb_arg, 0);
327 : 0 : }
328 : :
329 : : static void
330 : 0 : backing_dev_unmap(struct spdk_reduce_backing_dev *backing_dev,
331 : : uint64_t lba, uint32_t lba_count, struct spdk_reduce_vol_cb_args *args)
332 : : {
333 [ # # # # ]: 0 : if (g_defer_bdev_io == false) {
334 : 0 : CU_ASSERT(g_pending_bdev_io_count == 0);
335 : 0 : CU_ASSERT(TAILQ_EMPTY(&g_pending_bdev_io));
336 : 0 : backing_dev_unmap_execute(backing_dev, lba, lba_count, args);
337 : 0 : return;
338 : : }
339 : :
340 : 0 : backing_dev_insert_io(UT_REDUCE_IO_UNMAP, backing_dev, NULL, 0, lba, lba_count, args);
341 : : }
342 : :
343 : : static void
344 : 2 : backing_dev_io_execute(uint32_t count)
345 : : {
346 : : struct ut_reduce_bdev_io *ut_bdev_io;
347 : 2 : uint32_t done = 0;
348 : :
349 [ - + ]: 2 : CU_ASSERT(g_defer_bdev_io == true);
350 [ + + + - : 6 : while (!TAILQ_EMPTY(&g_pending_bdev_io) && (count == 0 || done < count)) {
- - ]
351 : 4 : ut_bdev_io = TAILQ_FIRST(&g_pending_bdev_io);
352 [ - + ]: 4 : TAILQ_REMOVE(&g_pending_bdev_io, ut_bdev_io, link);
353 : 4 : g_pending_bdev_io_count--;
354 [ + + - - ]: 4 : switch (ut_bdev_io->type) {
355 : 1 : case UT_REDUCE_IO_READV:
356 : 1 : backing_dev_readv_execute(ut_bdev_io->backing_dev,
357 : : ut_bdev_io->iov, ut_bdev_io->iovcnt,
358 : : ut_bdev_io->lba, ut_bdev_io->lba_count,
359 : : ut_bdev_io->args);
360 : 1 : break;
361 : 3 : case UT_REDUCE_IO_WRITEV:
362 : 3 : backing_dev_writev_execute(ut_bdev_io->backing_dev,
363 : : ut_bdev_io->iov, ut_bdev_io->iovcnt,
364 : : ut_bdev_io->lba, ut_bdev_io->lba_count,
365 : : ut_bdev_io->args);
366 : 3 : break;
367 : 0 : case UT_REDUCE_IO_UNMAP:
368 : 0 : backing_dev_unmap_execute(ut_bdev_io->backing_dev,
369 : : ut_bdev_io->lba, ut_bdev_io->lba_count,
370 : : ut_bdev_io->args);
371 : 0 : break;
372 : 0 : default:
373 : 0 : CU_ASSERT(false);
374 : 0 : break;
375 : : }
376 : 4 : free(ut_bdev_io);
377 : 4 : done++;
378 : : }
379 : 2 : }
380 : :
381 : : static int
382 : 17 : ut_compress(char *outbuf, uint32_t *compressed_len, char *inbuf, uint32_t inbuflen)
383 : : {
384 : 17 : uint32_t len = 0;
385 : : uint8_t count;
386 : : char last;
387 : :
388 : : while (true) {
389 [ + + ]: 37484 : if (inbuflen == 0) {
390 : 12 : *compressed_len = len;
391 : 12 : return 0;
392 : : }
393 : :
394 [ + + ]: 37472 : if (*compressed_len < (len + 2)) {
395 : 5 : return -ENOSPC;
396 : : }
397 : :
398 : 37467 : last = *inbuf;
399 : 37467 : count = 1;
400 : 37467 : inbuflen--;
401 : 37467 : inbuf++;
402 : :
403 [ + + + + : 184831 : while (inbuflen > 0 && *inbuf == last && count < UINT8_MAX) {
+ + ]
404 : 147364 : count++;
405 : 147364 : inbuflen--;
406 : 147364 : inbuf++;
407 : : }
408 : :
409 : 37467 : outbuf[len] = count;
410 : 37467 : outbuf[len + 1] = last;
411 : 37467 : len += 2;
412 : : }
413 : : }
414 : :
415 : : static int
416 : 264 : ut_decompress(uint8_t *outbuf, uint32_t *compressed_len, uint8_t *inbuf, uint32_t inbuflen)
417 : : {
418 : 264 : uint32_t len = 0;
419 : :
420 [ + - ]: 264 : SPDK_CU_ASSERT_FATAL(inbuflen % 2 == 0);
421 : :
422 : : while (true) {
423 [ + + ]: 19799 : if (inbuflen == 0) {
424 : 264 : *compressed_len = len;
425 : 264 : return 0;
426 : : }
427 : :
428 [ - + ]: 19535 : if ((len + inbuf[0]) > *compressed_len) {
429 : 0 : return -ENOSPC;
430 : : }
431 : :
432 [ - + ]: 19535 : memset(outbuf, inbuf[1], inbuf[0]);
433 : 19535 : outbuf += inbuf[0];
434 : 19535 : len += inbuf[0];
435 : 19535 : inbuflen -= 2;
436 : 19535 : inbuf += 2;
437 : : }
438 : : }
439 : :
440 : : static void
441 : 4 : ut_build_data_buffer(uint8_t *data, uint32_t data_len, uint8_t init_val, uint32_t repeat)
442 : : {
443 : 4 : uint32_t _repeat = repeat;
444 : :
445 [ - + ]: 4 : SPDK_CU_ASSERT_FATAL(repeat > 0);
446 : :
447 [ + + ]: 40964 : while (data_len > 0) {
448 : 40960 : *data = init_val;
449 : 40960 : data++;
450 : 40960 : data_len--;
451 : 40960 : _repeat--;
452 [ + + ]: 40960 : if (_repeat == 0) {
453 : 36865 : init_val++;
454 : 36865 : _repeat = repeat;
455 : : }
456 : : }
457 : 4 : }
458 : :
459 : : static void
460 : 13 : backing_dev_compress(struct spdk_reduce_backing_dev *backing_dev,
461 : : struct iovec *src_iov, int src_iovcnt,
462 : : struct iovec *dst_iov, int dst_iovcnt,
463 : : struct spdk_reduce_vol_cb_args *args)
464 : : {
465 : 13 : uint32_t compressed_len;
466 : 13 : uint64_t total_length = 0;
467 : 13 : char *buf = g_decomp_buf;
468 : : int rc, i;
469 : :
470 : 13 : CU_ASSERT(dst_iovcnt == 1);
471 : :
472 [ + + ]: 42 : for (i = 0; i < src_iovcnt; i++) {
473 [ - + - + ]: 29 : memcpy(buf, src_iov[i].iov_base, src_iov[i].iov_len);
474 : 29 : buf += src_iov[i].iov_len;
475 : 29 : total_length += src_iov[i].iov_len;
476 : : }
477 : :
478 : 13 : compressed_len = dst_iov[0].iov_len;
479 : 13 : rc = ut_compress(dst_iov[0].iov_base, &compressed_len,
480 : : g_decomp_buf, total_length);
481 : :
482 : 13 : args->output_size = compressed_len;
483 : :
484 : 13 : args->cb_fn(args->cb_arg, rc);
485 : 13 : }
486 : :
487 : : static void
488 : 261 : backing_dev_decompress(struct spdk_reduce_backing_dev *backing_dev,
489 : : struct iovec *src_iov, int src_iovcnt,
490 : : struct iovec *dst_iov, int dst_iovcnt,
491 : : struct spdk_reduce_vol_cb_args *args)
492 : : {
493 : 261 : uint32_t decompressed_len = 0;
494 : 261 : char *buf = g_decomp_buf;
495 : : int rc, i;
496 : :
497 : 261 : CU_ASSERT(src_iovcnt == 1);
498 : :
499 [ + + ]: 1020 : for (i = 0; i < dst_iovcnt; i++) {
500 : 759 : decompressed_len += dst_iov[i].iov_len;
501 : : }
502 : :
503 : 522 : rc = ut_decompress(g_decomp_buf, &decompressed_len,
504 : 261 : src_iov[0].iov_base, src_iov[0].iov_len);
505 : :
506 [ + + ]: 1020 : for (i = 0; i < dst_iovcnt; i++) {
507 [ - + - + ]: 759 : memcpy(dst_iov[i].iov_base, buf, dst_iov[i].iov_len);
508 : 759 : buf += dst_iov[i].iov_len;
509 : : }
510 : :
511 : 261 : args->output_size = decompressed_len;
512 : :
513 : 261 : args->cb_fn(args->cb_arg, rc);
514 : 261 : }
515 : :
516 : : static void
517 : 15 : backing_dev_destroy(struct spdk_reduce_backing_dev *backing_dev)
518 : : {
519 : : /* We don't free this during backing_dev_close so that we can test init/unload/load
520 : : * scenarios.
521 : : */
522 : 15 : free(g_backing_dev_buf);
523 : 15 : free(g_decomp_buf);
524 : 15 : g_backing_dev_buf = NULL;
525 : 15 : }
526 : :
527 : : static void
528 : 16 : backing_dev_init(struct spdk_reduce_backing_dev *backing_dev, struct spdk_reduce_vol_params *params,
529 : : uint32_t backing_blocklen)
530 : : {
531 : : int64_t size;
532 : :
533 : 16 : size = 4 * 1024 * 1024;
534 : 16 : backing_dev->blocklen = backing_blocklen;
535 [ - + ]: 16 : backing_dev->blockcnt = size / backing_dev->blocklen;
536 : 16 : backing_dev->readv = backing_dev_readv;
537 : 16 : backing_dev->writev = backing_dev_writev;
538 : 16 : backing_dev->unmap = backing_dev_unmap;
539 : 16 : backing_dev->compress = backing_dev_compress;
540 : 16 : backing_dev->decompress = backing_dev_decompress;
541 : 16 : backing_dev->sgl_in = true;
542 : 16 : backing_dev->sgl_out = true;
543 : :
544 : 16 : g_decomp_buf = calloc(1, params->chunk_size);
545 [ - + ]: 16 : SPDK_CU_ASSERT_FATAL(g_decomp_buf != NULL);
546 : :
547 : 16 : g_backing_dev_buf = calloc(1, size);
548 [ - + ]: 16 : SPDK_CU_ASSERT_FATAL(g_backing_dev_buf != NULL);
549 : 16 : }
550 : :
551 : : static void
552 : 1 : init_md(void)
553 : : {
554 : 1 : struct spdk_reduce_vol_params params = {};
555 : : struct spdk_reduce_vol_params *persistent_params;
556 : 1 : struct spdk_reduce_backing_dev backing_dev = {};
557 : 1 : struct spdk_uuid uuid;
558 : : uint64_t *entry;
559 : :
560 : 1 : params.chunk_size = 16 * 1024;
561 : 1 : params.backing_io_unit_size = 512;
562 : 1 : params.logical_block_size = 512;
563 : :
564 : 1 : backing_dev_init(&backing_dev, ¶ms, 512);
565 : :
566 : 1 : g_vol = NULL;
567 : 1 : g_reduce_errno = -1;
568 : 1 : spdk_reduce_vol_init(¶ms, &backing_dev, TEST_MD_PATH, init_cb, NULL);
569 : 1 : CU_ASSERT(g_reduce_errno == 0);
570 [ - + ]: 1 : SPDK_CU_ASSERT_FATAL(g_vol != NULL);
571 : : /* Confirm that reduce persisted the params to metadata. */
572 [ - + ]: 1 : CU_ASSERT(memcmp(g_persistent_pm_buf, SPDK_REDUCE_SIGNATURE, 8) == 0);
573 : 1 : persistent_params = (struct spdk_reduce_vol_params *)(g_persistent_pm_buf + 8);
574 [ - + ]: 1 : CU_ASSERT(memcmp(persistent_params, ¶ms, sizeof(params)) == 0);
575 : : /* Now confirm that contents of pm_file after the superblock have been initialized
576 : : * to REDUCE_EMPTY_MAP_ENTRY.
577 : : */
578 : 1 : entry = (uint64_t *)(g_persistent_pm_buf + sizeof(struct spdk_reduce_vol_superblock));
579 [ + + ]: 8577 : while (entry != (uint64_t *)(g_persistent_pm_buf + g_vol->pm_file.size)) {
580 : 8576 : CU_ASSERT(*entry == REDUCE_EMPTY_MAP_ENTRY);
581 : 8576 : entry++;
582 : : }
583 : :
584 : : /* Check that the pm file path was constructed correctly. It should be in
585 : : * the form:
586 : : * TEST_MD_PATH + "/" + <uuid string>
587 : : */
588 : 1 : CU_ASSERT(strncmp(&g_path[0], TEST_MD_PATH, strlen(TEST_MD_PATH)) == 0);
589 : 1 : CU_ASSERT(g_path[strlen(TEST_MD_PATH)] == '/');
590 : 1 : CU_ASSERT(spdk_uuid_parse(&uuid, &g_path[strlen(TEST_MD_PATH) + 1]) == 0);
591 : 1 : CU_ASSERT(spdk_uuid_compare(&uuid, spdk_reduce_vol_get_uuid(g_vol)) == 0);
592 : :
593 : 1 : g_reduce_errno = -1;
594 : 1 : spdk_reduce_vol_unload(g_vol, unload_cb, NULL);
595 : 1 : CU_ASSERT(g_reduce_errno == 0);
596 : 1 : CU_ASSERT(g_volatile_pm_buf == NULL);
597 : :
598 : 1 : persistent_pm_buf_destroy();
599 : 1 : backing_dev_destroy(&backing_dev);
600 : 1 : }
601 : :
602 : : static void
603 : 2 : _init_backing_dev(uint32_t backing_blocklen)
604 : : {
605 : 2 : struct spdk_reduce_vol_params params = {};
606 : : struct spdk_reduce_vol_params *persistent_params;
607 : 2 : struct spdk_reduce_backing_dev backing_dev = {};
608 : :
609 : 2 : params.chunk_size = 16 * 1024;
610 : 2 : params.backing_io_unit_size = 512;
611 : 2 : params.logical_block_size = 512;
612 : 2 : spdk_uuid_generate(¶ms.uuid);
613 : :
614 : 2 : backing_dev_init(&backing_dev, ¶ms, backing_blocklen);
615 : :
616 : 2 : g_vol = NULL;
617 : 2 : memset(g_path, 0, sizeof(g_path));
618 : 2 : g_reduce_errno = -1;
619 : 2 : spdk_reduce_vol_init(¶ms, &backing_dev, TEST_MD_PATH, init_cb, NULL);
620 : 2 : CU_ASSERT(g_reduce_errno == 0);
621 [ - + ]: 2 : SPDK_CU_ASSERT_FATAL(g_vol != NULL);
622 : 2 : CU_ASSERT(strncmp(TEST_MD_PATH, g_path, strlen(TEST_MD_PATH)) == 0);
623 : : /* Confirm that libreduce persisted the params to the backing device. */
624 [ - + ]: 2 : CU_ASSERT(memcmp(g_backing_dev_buf, SPDK_REDUCE_SIGNATURE, 8) == 0);
625 : 2 : persistent_params = (struct spdk_reduce_vol_params *)(g_backing_dev_buf + 8);
626 [ - + ]: 2 : CU_ASSERT(memcmp(persistent_params, ¶ms, sizeof(params)) == 0);
627 : : /* Confirm that the path to the persistent memory metadata file was persisted to
628 : : * the backing device.
629 : : */
630 [ - + ]: 2 : CU_ASSERT(strncmp(g_path,
631 : : g_backing_dev_buf + REDUCE_BACKING_DEV_PATH_OFFSET,
632 : : REDUCE_PATH_MAX) == 0);
633 : :
634 : 2 : g_reduce_errno = -1;
635 : 2 : spdk_reduce_vol_unload(g_vol, unload_cb, NULL);
636 : 2 : CU_ASSERT(g_reduce_errno == 0);
637 : :
638 : 2 : persistent_pm_buf_destroy();
639 : 2 : backing_dev_destroy(&backing_dev);
640 : 2 : }
641 : :
642 : : static void
643 : 1 : init_backing_dev(void)
644 : : {
645 : 1 : _init_backing_dev(512);
646 : 1 : _init_backing_dev(4096);
647 : 1 : }
648 : :
649 : : static void
650 : 2 : _load(uint32_t backing_blocklen)
651 : : {
652 : 2 : struct spdk_reduce_vol_params params = {};
653 : 2 : struct spdk_reduce_backing_dev backing_dev = {};
654 : 2 : char pmem_file_path[REDUCE_PATH_MAX];
655 : :
656 : 2 : params.chunk_size = 16 * 1024;
657 : 2 : params.backing_io_unit_size = 512;
658 : 2 : params.logical_block_size = 512;
659 : 2 : spdk_uuid_generate(¶ms.uuid);
660 : :
661 : 2 : backing_dev_init(&backing_dev, ¶ms, backing_blocklen);
662 : :
663 : 2 : g_vol = NULL;
664 : 2 : g_reduce_errno = -1;
665 : 2 : spdk_reduce_vol_init(¶ms, &backing_dev, TEST_MD_PATH, init_cb, NULL);
666 : 2 : CU_ASSERT(g_reduce_errno == 0);
667 [ - + ]: 2 : SPDK_CU_ASSERT_FATAL(g_vol != NULL);
668 : 2 : CU_ASSERT(strncmp(TEST_MD_PATH, g_path, strlen(TEST_MD_PATH)) == 0);
669 : 2 : memcpy(pmem_file_path, g_path, sizeof(pmem_file_path));
670 : :
671 : 2 : g_reduce_errno = -1;
672 : 2 : spdk_reduce_vol_unload(g_vol, unload_cb, NULL);
673 : 2 : CU_ASSERT(g_reduce_errno == 0);
674 : :
675 : 2 : g_vol = NULL;
676 : 2 : memset(g_path, 0, sizeof(g_path));
677 : 2 : g_reduce_errno = -1;
678 : 2 : spdk_reduce_vol_load(&backing_dev, load_cb, NULL);
679 : 2 : CU_ASSERT(g_reduce_errno == 0);
680 [ - + ]: 2 : SPDK_CU_ASSERT_FATAL(g_vol != NULL);
681 : 2 : CU_ASSERT(strncmp(g_path, pmem_file_path, sizeof(pmem_file_path)) == 0);
682 : 2 : CU_ASSERT(g_vol->params.vol_size == params.vol_size);
683 : 2 : CU_ASSERT(g_vol->params.chunk_size == params.chunk_size);
684 : 2 : CU_ASSERT(g_vol->params.backing_io_unit_size == params.backing_io_unit_size);
685 : :
686 : 2 : g_reduce_errno = -1;
687 : 2 : spdk_reduce_vol_unload(g_vol, unload_cb, NULL);
688 : 2 : CU_ASSERT(g_reduce_errno == 0);
689 : :
690 : 2 : persistent_pm_buf_destroy();
691 : 2 : backing_dev_destroy(&backing_dev);
692 : 2 : }
693 : :
694 : : static void
695 : 1 : load(void)
696 : : {
697 : 1 : _load(512);
698 : 1 : _load(4096);
699 : 1 : }
700 : :
701 : : static uint64_t
702 : 260 : _vol_get_chunk_map_index(struct spdk_reduce_vol *vol, uint64_t offset)
703 : : {
704 [ - + ]: 260 : uint64_t logical_map_index = offset / vol->logical_blocks_per_chunk;
705 : :
706 : 260 : return vol->pm_logical_map[logical_map_index];
707 : : }
708 : :
709 : : static void
710 : 15 : write_cb(void *arg, int reduce_errno)
711 : : {
712 : 15 : g_reduce_errno = reduce_errno;
713 : 15 : }
714 : :
715 : : static void
716 : 258 : read_cb(void *arg, int reduce_errno)
717 : : {
718 : 258 : g_reduce_errno = reduce_errno;
719 : 258 : }
720 : :
721 : : static void
722 : 2 : _write_maps(uint32_t backing_blocklen)
723 : 2 : {
724 : 2 : struct spdk_reduce_vol_params params = {};
725 : 2 : struct spdk_reduce_backing_dev backing_dev = {};
726 : 2 : struct iovec iov;
727 : 2 : const int bufsize = 16 * 1024; /* chunk size */
728 [ - + ]: 2 : char buf[bufsize];
729 : : uint32_t num_lbas, i;
730 : : uint64_t old_chunk0_map_index, new_chunk0_map_index;
731 : : struct spdk_reduce_chunk_map *old_chunk0_map, *new_chunk0_map;
732 : :
733 : 2 : params.chunk_size = bufsize;
734 : 2 : params.backing_io_unit_size = 4096;
735 : 2 : params.logical_block_size = 512;
736 [ - + ]: 2 : num_lbas = bufsize / params.logical_block_size;
737 : 2 : spdk_uuid_generate(¶ms.uuid);
738 : :
739 : 2 : backing_dev_init(&backing_dev, ¶ms, backing_blocklen);
740 : :
741 : 2 : g_vol = NULL;
742 : 2 : g_reduce_errno = -1;
743 : 2 : spdk_reduce_vol_init(¶ms, &backing_dev, TEST_MD_PATH, init_cb, NULL);
744 : 2 : CU_ASSERT(g_reduce_errno == 0);
745 [ - + ]: 2 : SPDK_CU_ASSERT_FATAL(g_vol != NULL);
746 : :
747 [ - + + + ]: 258 : for (i = 0; i < g_vol->params.vol_size / g_vol->params.chunk_size; i++) {
748 : 256 : CU_ASSERT(_vol_get_chunk_map_index(g_vol, i) == REDUCE_EMPTY_MAP_ENTRY);
749 : : }
750 : :
751 : 2 : ut_build_data_buffer(buf, bufsize, 0x00, 1);
752 : 2 : iov.iov_base = buf;
753 : 2 : iov.iov_len = bufsize;
754 : 2 : g_reduce_errno = -1;
755 : 2 : spdk_reduce_vol_writev(g_vol, &iov, 1, 0, num_lbas, write_cb, NULL);
756 : 2 : CU_ASSERT(g_reduce_errno == 0);
757 : :
758 : 2 : old_chunk0_map_index = _vol_get_chunk_map_index(g_vol, 0);
759 : 2 : CU_ASSERT(old_chunk0_map_index != REDUCE_EMPTY_MAP_ENTRY);
760 : 2 : CU_ASSERT(spdk_bit_array_get(g_vol->allocated_chunk_maps, old_chunk0_map_index) == true);
761 : :
762 : 2 : old_chunk0_map = _reduce_vol_get_chunk_map(g_vol, old_chunk0_map_index);
763 [ + + ]: 10 : for (i = 0; i < g_vol->backing_io_units_per_chunk; i++) {
764 : 8 : CU_ASSERT(old_chunk0_map->io_unit_index[i] != REDUCE_EMPTY_MAP_ENTRY);
765 : 8 : CU_ASSERT(spdk_bit_array_get(g_vol->allocated_backing_io_units,
766 : : old_chunk0_map->io_unit_index[i]) == true);
767 : : }
768 : :
769 : 2 : g_reduce_errno = -1;
770 : 2 : spdk_reduce_vol_writev(g_vol, &iov, 1, 0, num_lbas, write_cb, NULL);
771 : 2 : CU_ASSERT(g_reduce_errno == 0);
772 : :
773 : 2 : new_chunk0_map_index = _vol_get_chunk_map_index(g_vol, 0);
774 : 2 : CU_ASSERT(new_chunk0_map_index != REDUCE_EMPTY_MAP_ENTRY);
775 : 2 : CU_ASSERT(new_chunk0_map_index != old_chunk0_map_index);
776 : 2 : CU_ASSERT(spdk_bit_array_get(g_vol->allocated_chunk_maps, new_chunk0_map_index) == true);
777 : 2 : CU_ASSERT(spdk_bit_array_get(g_vol->allocated_chunk_maps, old_chunk0_map_index) == false);
778 : :
779 [ + + ]: 10 : for (i = 0; i < g_vol->backing_io_units_per_chunk; i++) {
780 : 8 : CU_ASSERT(spdk_bit_array_get(g_vol->allocated_backing_io_units,
781 : : old_chunk0_map->io_unit_index[i]) == false);
782 : : }
783 : :
784 : 2 : new_chunk0_map = _reduce_vol_get_chunk_map(g_vol, new_chunk0_map_index);
785 [ + + ]: 10 : for (i = 0; i < g_vol->backing_io_units_per_chunk; i++) {
786 : 8 : CU_ASSERT(new_chunk0_map->io_unit_index[i] != REDUCE_EMPTY_MAP_ENTRY);
787 : 8 : CU_ASSERT(spdk_bit_array_get(g_vol->allocated_backing_io_units,
788 : : new_chunk0_map->io_unit_index[i]) == true);
789 : : }
790 : :
791 : 2 : g_reduce_errno = -1;
792 : 2 : spdk_reduce_vol_unload(g_vol, unload_cb, NULL);
793 : 2 : CU_ASSERT(g_reduce_errno == 0);
794 : :
795 : 2 : g_vol = NULL;
796 : 2 : g_reduce_errno = -1;
797 : 2 : spdk_reduce_vol_load(&backing_dev, load_cb, NULL);
798 : 2 : CU_ASSERT(g_reduce_errno == 0);
799 [ - + ]: 2 : SPDK_CU_ASSERT_FATAL(g_vol != NULL);
800 : 2 : CU_ASSERT(g_vol->params.vol_size == params.vol_size);
801 : 2 : CU_ASSERT(g_vol->params.chunk_size == params.chunk_size);
802 : 2 : CU_ASSERT(g_vol->params.backing_io_unit_size == params.backing_io_unit_size);
803 : :
804 : 2 : g_reduce_errno = -1;
805 : 2 : spdk_reduce_vol_unload(g_vol, unload_cb, NULL);
806 : 2 : CU_ASSERT(g_reduce_errno == 0);
807 : :
808 : 2 : persistent_pm_buf_destroy();
809 : 2 : backing_dev_destroy(&backing_dev);
810 : 2 : }
811 : :
812 : : static void
813 : 1 : write_maps(void)
814 : : {
815 : 1 : _write_maps(512);
816 : 1 : _write_maps(4096);
817 : 1 : }
818 : :
819 : : static void
820 : 2 : _read_write(uint32_t backing_blocklen)
821 : : {
822 : 2 : struct spdk_reduce_vol_params params = {};
823 : 2 : struct spdk_reduce_backing_dev backing_dev = {};
824 : 2 : struct iovec iov;
825 : 2 : char buf[16 * 1024]; /* chunk size */
826 : 2 : char compare_buf[16 * 1024];
827 : : uint32_t i;
828 : :
829 : 2 : params.chunk_size = 16 * 1024;
830 : 2 : params.backing_io_unit_size = 4096;
831 : 2 : params.logical_block_size = 512;
832 : 2 : spdk_uuid_generate(¶ms.uuid);
833 : :
834 : 2 : backing_dev_init(&backing_dev, ¶ms, backing_blocklen);
835 : :
836 : 2 : g_vol = NULL;
837 : 2 : g_reduce_errno = -1;
838 : 2 : spdk_reduce_vol_init(¶ms, &backing_dev, TEST_MD_PATH, init_cb, NULL);
839 : 2 : CU_ASSERT(g_reduce_errno == 0);
840 [ - + ]: 2 : SPDK_CU_ASSERT_FATAL(g_vol != NULL);
841 : :
842 : : /* Write 0xAA to 2 512-byte logical blocks, starting at LBA 2. */
843 : 2 : memset(buf, 0xAA, 2 * params.logical_block_size);
844 : 2 : iov.iov_base = buf;
845 : 2 : iov.iov_len = 2 * params.logical_block_size;
846 : 2 : g_reduce_errno = -1;
847 : 2 : spdk_reduce_vol_writev(g_vol, &iov, 1, 2, 2, write_cb, NULL);
848 : 2 : CU_ASSERT(g_reduce_errno == 0);
849 : :
850 : 2 : memset(compare_buf, 0xAA, sizeof(compare_buf));
851 [ - + + + ]: 66 : for (i = 0; i < params.chunk_size / params.logical_block_size; i++) {
852 : 64 : memset(buf, 0xFF, params.logical_block_size);
853 : 64 : iov.iov_base = buf;
854 : 64 : iov.iov_len = params.logical_block_size;
855 : 64 : g_reduce_errno = -1;
856 : 64 : spdk_reduce_vol_readv(g_vol, &iov, 1, i, 1, read_cb, NULL);
857 : 64 : CU_ASSERT(g_reduce_errno == 0);
858 : :
859 [ + + ]: 64 : switch (i) {
860 : 4 : case 2:
861 : : case 3:
862 : 4 : CU_ASSERT(memcmp(buf, compare_buf, params.logical_block_size) == 0);
863 : 4 : break;
864 : 60 : default:
865 : 60 : CU_ASSERT(spdk_mem_all_zero(buf, params.logical_block_size));
866 : 60 : break;
867 : : }
868 : : }
869 : :
870 : 2 : g_reduce_errno = -1;
871 : 2 : spdk_reduce_vol_unload(g_vol, unload_cb, NULL);
872 : 2 : CU_ASSERT(g_reduce_errno == 0);
873 : :
874 : : /* Overwrite what we just wrote with 0xCC */
875 : 2 : g_vol = NULL;
876 : 2 : g_reduce_errno = -1;
877 : 2 : spdk_reduce_vol_load(&backing_dev, load_cb, NULL);
878 : 2 : CU_ASSERT(g_reduce_errno == 0);
879 [ - + ]: 2 : SPDK_CU_ASSERT_FATAL(g_vol != NULL);
880 : 2 : CU_ASSERT(g_vol->params.vol_size == params.vol_size);
881 : 2 : CU_ASSERT(g_vol->params.chunk_size == params.chunk_size);
882 : 2 : CU_ASSERT(g_vol->params.backing_io_unit_size == params.backing_io_unit_size);
883 : :
884 : 2 : memset(buf, 0xCC, 2 * params.logical_block_size);
885 : 2 : iov.iov_base = buf;
886 : 2 : iov.iov_len = 2 * params.logical_block_size;
887 : 2 : g_reduce_errno = -1;
888 : 2 : spdk_reduce_vol_writev(g_vol, &iov, 1, 2, 2, write_cb, NULL);
889 : 2 : CU_ASSERT(g_reduce_errno == 0);
890 : :
891 : 2 : memset(compare_buf, 0xCC, sizeof(compare_buf));
892 [ - + + + ]: 66 : for (i = 0; i < params.chunk_size / params.logical_block_size; i++) {
893 : 64 : memset(buf, 0xFF, params.logical_block_size);
894 : 64 : iov.iov_base = buf;
895 : 64 : iov.iov_len = params.logical_block_size;
896 : 64 : g_reduce_errno = -1;
897 : 64 : spdk_reduce_vol_readv(g_vol, &iov, 1, i, 1, read_cb, NULL);
898 : 64 : CU_ASSERT(g_reduce_errno == 0);
899 : :
900 [ + + ]: 64 : switch (i) {
901 : 4 : case 2:
902 : : case 3:
903 : 4 : CU_ASSERT(memcmp(buf, compare_buf, params.logical_block_size) == 0);
904 : 4 : break;
905 : 60 : default:
906 : 60 : CU_ASSERT(spdk_mem_all_zero(buf, params.logical_block_size));
907 : 60 : break;
908 : : }
909 : : }
910 : :
911 : 2 : g_reduce_errno = -1;
912 : 2 : spdk_reduce_vol_unload(g_vol, unload_cb, NULL);
913 : 2 : CU_ASSERT(g_reduce_errno == 0);
914 : :
915 : 2 : g_vol = NULL;
916 : 2 : g_reduce_errno = -1;
917 : 2 : spdk_reduce_vol_load(&backing_dev, load_cb, NULL);
918 : 2 : CU_ASSERT(g_reduce_errno == 0);
919 [ - + ]: 2 : SPDK_CU_ASSERT_FATAL(g_vol != NULL);
920 : 2 : CU_ASSERT(g_vol->params.vol_size == params.vol_size);
921 : 2 : CU_ASSERT(g_vol->params.chunk_size == params.chunk_size);
922 : 2 : CU_ASSERT(g_vol->params.backing_io_unit_size == params.backing_io_unit_size);
923 : :
924 : 2 : g_reduce_errno = -1;
925 : :
926 : : /* Write 0xBB to 2 512-byte logical blocks, starting at LBA 37.
927 : : * This is writing into the second chunk of the volume. This also
928 : : * enables implicitly checking that we reloaded the bit arrays
929 : : * correctly - making sure we don't use the first chunk map again
930 : : * for this new write - the first chunk map was already used by the
931 : : * write from before we unloaded and reloaded.
932 : : */
933 : 2 : memset(buf, 0xBB, 2 * params.logical_block_size);
934 : 2 : iov.iov_base = buf;
935 : 2 : iov.iov_len = 2 * params.logical_block_size;
936 : 2 : g_reduce_errno = -1;
937 : 2 : spdk_reduce_vol_writev(g_vol, &iov, 1, 37, 2, write_cb, NULL);
938 : 2 : CU_ASSERT(g_reduce_errno == 0);
939 : :
940 [ - + + + ]: 130 : for (i = 0; i < 2 * params.chunk_size / params.logical_block_size; i++) {
941 : 128 : memset(buf, 0xFF, params.logical_block_size);
942 : 128 : iov.iov_base = buf;
943 : 128 : iov.iov_len = params.logical_block_size;
944 : 128 : g_reduce_errno = -1;
945 : 128 : spdk_reduce_vol_readv(g_vol, &iov, 1, i, 1, read_cb, NULL);
946 : 128 : CU_ASSERT(g_reduce_errno == 0);
947 : :
948 [ + + + ]: 128 : switch (i) {
949 : 4 : case 2:
950 : : case 3:
951 : 4 : memset(compare_buf, 0xCC, sizeof(compare_buf));
952 : 4 : CU_ASSERT(memcmp(buf, compare_buf, params.logical_block_size) == 0);
953 : 4 : break;
954 : 4 : case 37:
955 : : case 38:
956 : 4 : memset(compare_buf, 0xBB, sizeof(compare_buf));
957 : 4 : CU_ASSERT(memcmp(buf, compare_buf, params.logical_block_size) == 0);
958 : 4 : break;
959 : 120 : default:
960 : 120 : CU_ASSERT(spdk_mem_all_zero(buf, params.logical_block_size));
961 : 120 : break;
962 : : }
963 : : }
964 : :
965 : 2 : g_reduce_errno = -1;
966 : 2 : spdk_reduce_vol_unload(g_vol, unload_cb, NULL);
967 : 2 : CU_ASSERT(g_reduce_errno == 0);
968 : :
969 : 2 : persistent_pm_buf_destroy();
970 : 2 : backing_dev_destroy(&backing_dev);
971 : 2 : }
972 : :
973 : : static void
974 : 1 : read_write(void)
975 : : {
976 : 1 : _read_write(512);
977 : 1 : _read_write(4096);
978 : 1 : }
979 : :
980 : : static void
981 : 2 : _readv_writev(uint32_t backing_blocklen)
982 : : {
983 : 2 : struct spdk_reduce_vol_params params = {};
984 : 2 : struct spdk_reduce_backing_dev backing_dev = {};
985 : 2 : struct iovec iov[REDUCE_MAX_IOVECS + 1];
986 : :
987 : 2 : params.chunk_size = 16 * 1024;
988 : 2 : params.backing_io_unit_size = 4096;
989 : 2 : params.logical_block_size = 512;
990 : 2 : spdk_uuid_generate(¶ms.uuid);
991 : :
992 : 2 : backing_dev_init(&backing_dev, ¶ms, backing_blocklen);
993 : :
994 : 2 : g_vol = NULL;
995 : 2 : g_reduce_errno = -1;
996 : 2 : spdk_reduce_vol_init(¶ms, &backing_dev, TEST_MD_PATH, init_cb, NULL);
997 : 2 : CU_ASSERT(g_reduce_errno == 0);
998 [ - + ]: 2 : SPDK_CU_ASSERT_FATAL(g_vol != NULL);
999 : :
1000 : 2 : g_reduce_errno = -1;
1001 : 2 : spdk_reduce_vol_writev(g_vol, iov, REDUCE_MAX_IOVECS + 1, 2, REDUCE_MAX_IOVECS + 1, write_cb, NULL);
1002 : 2 : CU_ASSERT(g_reduce_errno == -EINVAL);
1003 : :
1004 : 2 : g_reduce_errno = -1;
1005 : 2 : spdk_reduce_vol_unload(g_vol, unload_cb, NULL);
1006 : 2 : CU_ASSERT(g_reduce_errno == 0);
1007 : :
1008 : 2 : persistent_pm_buf_destroy();
1009 : 2 : backing_dev_destroy(&backing_dev);
1010 : 2 : }
1011 : :
1012 : : static void
1013 : 1 : readv_writev(void)
1014 : : {
1015 : 1 : _readv_writev(512);
1016 : 1 : _readv_writev(4096);
1017 : 1 : }
1018 : :
1019 : : static void
1020 : 1 : destroy_cb(void *ctx, int reduce_errno)
1021 : : {
1022 : 1 : g_reduce_errno = reduce_errno;
1023 : 1 : }
1024 : :
1025 : : static void
1026 : 1 : destroy(void)
1027 : : {
1028 : 1 : struct spdk_reduce_vol_params params = {};
1029 : 1 : struct spdk_reduce_backing_dev backing_dev = {};
1030 : :
1031 : 1 : params.chunk_size = 16 * 1024;
1032 : 1 : params.backing_io_unit_size = 512;
1033 : 1 : params.logical_block_size = 512;
1034 : 1 : spdk_uuid_generate(¶ms.uuid);
1035 : :
1036 : 1 : backing_dev_init(&backing_dev, ¶ms, 512);
1037 : :
1038 : 1 : g_vol = NULL;
1039 : 1 : g_reduce_errno = -1;
1040 : 1 : spdk_reduce_vol_init(¶ms, &backing_dev, TEST_MD_PATH, init_cb, NULL);
1041 : 1 : CU_ASSERT(g_reduce_errno == 0);
1042 [ - + ]: 1 : SPDK_CU_ASSERT_FATAL(g_vol != NULL);
1043 : :
1044 : 1 : g_reduce_errno = -1;
1045 : 1 : spdk_reduce_vol_unload(g_vol, unload_cb, NULL);
1046 : 1 : CU_ASSERT(g_reduce_errno == 0);
1047 : :
1048 : 1 : g_vol = NULL;
1049 : 1 : g_reduce_errno = -1;
1050 : 1 : spdk_reduce_vol_load(&backing_dev, load_cb, NULL);
1051 : 1 : CU_ASSERT(g_reduce_errno == 0);
1052 [ - + ]: 1 : SPDK_CU_ASSERT_FATAL(g_vol != NULL);
1053 : :
1054 : 1 : g_reduce_errno = -1;
1055 : 1 : spdk_reduce_vol_unload(g_vol, unload_cb, NULL);
1056 : 1 : CU_ASSERT(g_reduce_errno == 0);
1057 : :
1058 : 1 : g_reduce_errno = -1;
1059 : 1 : MOCK_CLEAR(spdk_malloc);
1060 : 1 : MOCK_CLEAR(spdk_zmalloc);
1061 : 1 : spdk_reduce_vol_destroy(&backing_dev, destroy_cb, NULL);
1062 : 1 : CU_ASSERT(g_reduce_errno == 0);
1063 : :
1064 : 1 : g_reduce_errno = 0;
1065 : 1 : spdk_reduce_vol_load(&backing_dev, load_cb, NULL);
1066 : 1 : CU_ASSERT(g_reduce_errno == -EILSEQ);
1067 : :
1068 : 1 : backing_dev_destroy(&backing_dev);
1069 : 1 : }
1070 : :
1071 : : /* This test primarily checks that the reduce unit test infrastructure for asynchronous
1072 : : * backing device I/O operations is working correctly.
1073 : : */
1074 : : static void
1075 : 1 : defer_bdev_io(void)
1076 : 1 : {
1077 : 1 : struct spdk_reduce_vol_params params = {};
1078 : 1 : struct spdk_reduce_backing_dev backing_dev = {};
1079 : 1 : const uint32_t logical_block_size = 512;
1080 : 1 : struct iovec iov;
1081 [ - + ]: 1 : char buf[logical_block_size];
1082 [ - + ]: 1 : char compare_buf[logical_block_size];
1083 : :
1084 : 1 : params.chunk_size = 16 * 1024;
1085 : 1 : params.backing_io_unit_size = 4096;
1086 : 1 : params.logical_block_size = logical_block_size;
1087 : 1 : spdk_uuid_generate(¶ms.uuid);
1088 : :
1089 : 1 : backing_dev_init(&backing_dev, ¶ms, 512);
1090 : :
1091 : 1 : g_vol = NULL;
1092 : 1 : g_reduce_errno = -1;
1093 : 1 : spdk_reduce_vol_init(¶ms, &backing_dev, TEST_MD_PATH, init_cb, NULL);
1094 : 1 : CU_ASSERT(g_reduce_errno == 0);
1095 [ - + ]: 1 : SPDK_CU_ASSERT_FATAL(g_vol != NULL);
1096 : :
1097 : : /* Write 0xAA to 1 512-byte logical block. */
1098 [ - + ]: 1 : memset(buf, 0xAA, params.logical_block_size);
1099 : 1 : iov.iov_base = buf;
1100 : 1 : iov.iov_len = params.logical_block_size;
1101 : 1 : g_reduce_errno = -100;
1102 : 1 : g_defer_bdev_io = true;
1103 : 1 : spdk_reduce_vol_writev(g_vol, &iov, 1, 0, 1, write_cb, NULL);
1104 : : /* Callback should not have executed, so this should still equal -100. */
1105 : 1 : CU_ASSERT(g_reduce_errno == -100);
1106 : 1 : CU_ASSERT(!TAILQ_EMPTY(&g_pending_bdev_io));
1107 : : /* We wrote to just 512 bytes of one chunk which was previously unallocated. This
1108 : : * should result in 1 pending I/O since the rest of this chunk will be zeroes and
1109 : : * very compressible.
1110 : : */
1111 : 1 : CU_ASSERT(g_pending_bdev_io_count == 1);
1112 : :
1113 : 1 : backing_dev_io_execute(0);
1114 : 1 : CU_ASSERT(TAILQ_EMPTY(&g_pending_bdev_io));
1115 : 1 : CU_ASSERT(g_reduce_errno == 0);
1116 : :
1117 : 1 : g_defer_bdev_io = false;
1118 [ - + ]: 1 : memset(compare_buf, 0xAA, sizeof(compare_buf));
1119 [ - + ]: 1 : memset(buf, 0xFF, sizeof(buf));
1120 : 1 : iov.iov_base = buf;
1121 : 1 : iov.iov_len = params.logical_block_size;
1122 : 1 : g_reduce_errno = -100;
1123 : 1 : spdk_reduce_vol_readv(g_vol, &iov, 1, 0, 1, read_cb, NULL);
1124 : 1 : CU_ASSERT(g_reduce_errno == 0);
1125 [ - + - + ]: 1 : CU_ASSERT(memcmp(buf, compare_buf, sizeof(buf)) == 0);
1126 : :
1127 : 1 : g_reduce_errno = -1;
1128 : 1 : spdk_reduce_vol_unload(g_vol, unload_cb, NULL);
1129 : 1 : CU_ASSERT(g_reduce_errno == 0);
1130 : :
1131 : 1 : persistent_pm_buf_destroy();
1132 : 1 : backing_dev_destroy(&backing_dev);
1133 : 1 : }
1134 : :
1135 : : static void
1136 : 1 : overlapped(void)
1137 : 1 : {
1138 : 1 : struct spdk_reduce_vol_params params = {};
1139 : 1 : struct spdk_reduce_backing_dev backing_dev = {};
1140 : 1 : const uint32_t logical_block_size = 512;
1141 : 1 : struct iovec iov;
1142 [ - + ]: 1 : char buf[2 * logical_block_size];
1143 [ - + ]: 1 : char compare_buf[2 * logical_block_size];
1144 : :
1145 : 1 : params.chunk_size = 16 * 1024;
1146 : 1 : params.backing_io_unit_size = 4096;
1147 : 1 : params.logical_block_size = logical_block_size;
1148 : 1 : spdk_uuid_generate(¶ms.uuid);
1149 : :
1150 : 1 : backing_dev_init(&backing_dev, ¶ms, 512);
1151 : :
1152 : 1 : g_vol = NULL;
1153 : 1 : g_reduce_errno = -1;
1154 : 1 : spdk_reduce_vol_init(¶ms, &backing_dev, TEST_MD_PATH, init_cb, NULL);
1155 : 1 : CU_ASSERT(g_reduce_errno == 0);
1156 [ - + ]: 1 : SPDK_CU_ASSERT_FATAL(g_vol != NULL);
1157 : :
1158 : : /* Write 0xAA to 1 512-byte logical block. */
1159 [ - + ]: 1 : memset(buf, 0xAA, logical_block_size);
1160 : 1 : iov.iov_base = buf;
1161 : 1 : iov.iov_len = logical_block_size;
1162 : 1 : g_reduce_errno = -100;
1163 : 1 : g_defer_bdev_io = true;
1164 : 1 : spdk_reduce_vol_writev(g_vol, &iov, 1, 0, 1, write_cb, NULL);
1165 : : /* Callback should not have executed, so this should still equal -100. */
1166 : 1 : CU_ASSERT(g_reduce_errno == -100);
1167 : 1 : CU_ASSERT(!TAILQ_EMPTY(&g_pending_bdev_io));
1168 : : /* We wrote to just 512 bytes of one chunk which was previously unallocated. This
1169 : : * should result in 1 pending I/O since the rest of this chunk will be zeroes and
1170 : : * very compressible.
1171 : : */
1172 : 1 : CU_ASSERT(g_pending_bdev_io_count == 1);
1173 : :
1174 : : /* Now do an overlapped I/O to the same chunk. */
1175 : 1 : spdk_reduce_vol_writev(g_vol, &iov, 1, 1, 1, write_cb, NULL);
1176 : : /* Callback should not have executed, so this should still equal -100. */
1177 : 1 : CU_ASSERT(g_reduce_errno == -100);
1178 : 1 : CU_ASSERT(!TAILQ_EMPTY(&g_pending_bdev_io));
1179 : : /* The second I/O overlaps with the first one. So we should only see pending bdev_io
1180 : : * related to the first I/O here - the second one won't start until the first one is completed.
1181 : : */
1182 : 1 : CU_ASSERT(g_pending_bdev_io_count == 1);
1183 : :
1184 : 1 : backing_dev_io_execute(0);
1185 : 1 : CU_ASSERT(g_reduce_errno == 0);
1186 : :
1187 : 1 : g_defer_bdev_io = false;
1188 [ - + ]: 1 : memset(compare_buf, 0xAA, sizeof(compare_buf));
1189 [ - + ]: 1 : memset(buf, 0xFF, sizeof(buf));
1190 : 1 : iov.iov_base = buf;
1191 : 1 : iov.iov_len = 2 * logical_block_size;
1192 : 1 : g_reduce_errno = -100;
1193 : 1 : spdk_reduce_vol_readv(g_vol, &iov, 1, 0, 2, read_cb, NULL);
1194 : 1 : CU_ASSERT(g_reduce_errno == 0);
1195 [ - + - + ]: 1 : CU_ASSERT(memcmp(buf, compare_buf, 2 * logical_block_size) == 0);
1196 : :
1197 : 1 : g_reduce_errno = -1;
1198 : 1 : spdk_reduce_vol_unload(g_vol, unload_cb, NULL);
1199 : 1 : CU_ASSERT(g_reduce_errno == 0);
1200 : :
1201 : 1 : persistent_pm_buf_destroy();
1202 : 1 : backing_dev_destroy(&backing_dev);
1203 : 1 : }
1204 : :
1205 : : #define BUFSIZE 4096
1206 : :
1207 : : static void
1208 : 1 : compress_algorithm(void)
1209 : : {
1210 : 1 : uint8_t original_data[BUFSIZE];
1211 : 1 : uint8_t compressed_data[BUFSIZE];
1212 : 1 : uint8_t decompressed_data[BUFSIZE];
1213 : 1 : uint32_t compressed_len, decompressed_len;
1214 : : int rc;
1215 : :
1216 : 1 : ut_build_data_buffer(original_data, BUFSIZE, 0xAA, BUFSIZE);
1217 : 1 : compressed_len = sizeof(compressed_data);
1218 : 1 : rc = ut_compress(compressed_data, &compressed_len, original_data, UINT8_MAX);
1219 : 1 : CU_ASSERT(rc == 0);
1220 : 1 : CU_ASSERT(compressed_len == 2);
1221 : 1 : CU_ASSERT(compressed_data[0] == UINT8_MAX);
1222 : 1 : CU_ASSERT(compressed_data[1] == 0xAA);
1223 : :
1224 : 1 : decompressed_len = sizeof(decompressed_data);
1225 : 1 : rc = ut_decompress(decompressed_data, &decompressed_len, compressed_data, compressed_len);
1226 : 1 : CU_ASSERT(rc == 0);
1227 : 1 : CU_ASSERT(decompressed_len == UINT8_MAX);
1228 : 1 : CU_ASSERT(memcmp(original_data, decompressed_data, decompressed_len) == 0);
1229 : :
1230 : 1 : compressed_len = sizeof(compressed_data);
1231 : 1 : rc = ut_compress(compressed_data, &compressed_len, original_data, UINT8_MAX + 1);
1232 : 1 : CU_ASSERT(rc == 0);
1233 : 1 : CU_ASSERT(compressed_len == 4);
1234 : 1 : CU_ASSERT(compressed_data[0] == UINT8_MAX);
1235 : 1 : CU_ASSERT(compressed_data[1] == 0xAA);
1236 : 1 : CU_ASSERT(compressed_data[2] == 1);
1237 : 1 : CU_ASSERT(compressed_data[3] == 0xAA);
1238 : :
1239 : 1 : decompressed_len = sizeof(decompressed_data);
1240 : 1 : rc = ut_decompress(decompressed_data, &decompressed_len, compressed_data, compressed_len);
1241 : 1 : CU_ASSERT(rc == 0);
1242 : 1 : CU_ASSERT(decompressed_len == UINT8_MAX + 1);
1243 : 1 : CU_ASSERT(memcmp(original_data, decompressed_data, decompressed_len) == 0);
1244 : :
1245 : 1 : ut_build_data_buffer(original_data, BUFSIZE, 0x00, 1);
1246 : 1 : compressed_len = sizeof(compressed_data);
1247 : 1 : rc = ut_compress(compressed_data, &compressed_len, original_data, 2048);
1248 : 1 : CU_ASSERT(rc == 0);
1249 : 1 : CU_ASSERT(compressed_len == 4096);
1250 : 1 : CU_ASSERT(compressed_data[0] == 1);
1251 : 1 : CU_ASSERT(compressed_data[1] == 0);
1252 : 1 : CU_ASSERT(compressed_data[4094] == 1);
1253 : 1 : CU_ASSERT(compressed_data[4095] == 0xFF);
1254 : :
1255 : 1 : decompressed_len = sizeof(decompressed_data);
1256 : 1 : rc = ut_decompress(decompressed_data, &decompressed_len, compressed_data, compressed_len);
1257 : 1 : CU_ASSERT(rc == 0);
1258 : 1 : CU_ASSERT(decompressed_len == 2048);
1259 : 1 : CU_ASSERT(memcmp(original_data, decompressed_data, decompressed_len) == 0);
1260 : :
1261 : 1 : compressed_len = sizeof(compressed_data);
1262 : 1 : rc = ut_compress(compressed_data, &compressed_len, original_data, 2049);
1263 : 1 : CU_ASSERT(rc == -ENOSPC);
1264 : 1 : }
1265 : :
1266 : : static void
1267 : 1 : test_prepare_compress_chunk(void)
1268 : : {
1269 : 1 : struct spdk_reduce_vol vol = {};
1270 : 1 : struct spdk_reduce_backing_dev backing_dev = {};
1271 : 1 : struct spdk_reduce_vol_request req = {};
1272 : 1 : void *buf;
1273 : : char *buffer_end, *aligned_user_buffer, *unaligned_user_buffer;
1274 : 1 : char decomp_buffer[16 * 1024] = {};
1275 : 1 : char comp_buffer[16 * 1024] = {};
1276 : 1 : struct iovec user_iov[2] = {};
1277 : 1 : size_t user_buffer_iov_len = 8192;
1278 : : size_t remainder_bytes;
1279 : : size_t offset_bytes;
1280 : : size_t memcmp_offset;
1281 : : uint32_t i;
1282 : :
1283 : 1 : vol.params.chunk_size = 16 * 1024;
1284 : 1 : vol.params.backing_io_unit_size = 4096;
1285 : 1 : vol.params.logical_block_size = 512;
1286 : 1 : backing_dev_init(&backing_dev, &vol.params, 512);
1287 : 1 : vol.backing_dev = &backing_dev;
1288 [ - + ]: 1 : vol.logical_blocks_per_chunk = vol.params.chunk_size / vol.params.logical_block_size;
1289 : :
1290 : : /* Allocate 1 extra byte to test a case when buffer crosses huge page boundary */
1291 [ - + ]: 1 : SPDK_CU_ASSERT_FATAL(posix_memalign(&buf, VALUE_2MB, VALUE_2MB + 1) == 0);
1292 : 1 : buffer_end = (char *)buf + VALUE_2MB + 1;
1293 : 1 : aligned_user_buffer = (char *)buf;
1294 [ - + ]: 1 : memset(aligned_user_buffer, 0xc, vol.params.chunk_size);
1295 : 1 : unaligned_user_buffer = buffer_end - vol.params.chunk_size;
1296 [ - + ]: 1 : memset(unaligned_user_buffer, 0xc, vol.params.chunk_size);
1297 : :
1298 : 1 : req.vol = &vol;
1299 : 1 : req.decomp_buf = decomp_buffer;
1300 : 1 : req.comp_buf = comp_buffer;
1301 : 1 : req.iov = user_iov;
1302 : 1 : req.iovcnt = 2;
1303 : 1 : req.offset = 0;
1304 : :
1305 : : /* Part 1 - backing dev supports sgl_in */
1306 : : /* Test 1 - user's buffers length equals to chunk_size */
1307 [ + + ]: 3 : for (i = 0; i < 2; i++) {
1308 : 2 : req.iov[i].iov_base = aligned_user_buffer + i * user_buffer_iov_len;
1309 : 2 : req.iov[i].iov_len = user_buffer_iov_len;
1310 : : }
1311 : :
1312 : 1 : _prepare_compress_chunk(&req, false);
1313 : 1 : CU_ASSERT(req.decomp_iovcnt == 2);
1314 [ + + ]: 3 : for (i = 0; i < 2; i++) {
1315 : 2 : CU_ASSERT(req.decomp_iov[i].iov_base == req.iov[i].iov_base);
1316 : 2 : CU_ASSERT(req.decomp_iov[i].iov_len == req.iov[i].iov_len);
1317 : : }
1318 : :
1319 : 1 : _prepare_compress_chunk(&req, true);
1320 : 1 : CU_ASSERT(req.decomp_iovcnt == 2);
1321 [ + + ]: 3 : for (i = 0; i < 2; i++) {
1322 : 2 : CU_ASSERT(req.decomp_iov[i].iov_base == req.iov[i].iov_base);
1323 : 2 : CU_ASSERT(req.decomp_iov[i].iov_len == req.iov[i].iov_len);
1324 : : }
1325 : :
1326 : : /* Test 2 - user's buffer less than chunk_size, without offset */
1327 : 1 : user_buffer_iov_len = 4096;
1328 : 1 : remainder_bytes = vol.params.chunk_size - user_buffer_iov_len * 2;
1329 [ + + ]: 3 : for (i = 0; i < 2; i++) {
1330 : 2 : req.iov[i].iov_base = aligned_user_buffer + i * user_buffer_iov_len;
1331 : 2 : req.iov[i].iov_len = user_buffer_iov_len;
1332 : : }
1333 : :
1334 : 1 : _prepare_compress_chunk(&req, false);
1335 : 1 : CU_ASSERT(req.decomp_iovcnt == 3);
1336 [ + + ]: 3 : for (i = 0; i < 2; i++) {
1337 : 2 : CU_ASSERT(req.decomp_iov[i].iov_base == req.iov[i].iov_base);
1338 : 2 : CU_ASSERT(req.decomp_iov[i].iov_len == req.iov[i].iov_len);
1339 : : }
1340 : 1 : CU_ASSERT(req.decomp_iov[i].iov_base == req.decomp_buf + user_buffer_iov_len * 2);
1341 : 1 : CU_ASSERT(req.decomp_iov[i].iov_len == remainder_bytes);
1342 : :
1343 : 1 : _prepare_compress_chunk(&req, true);
1344 : 1 : CU_ASSERT(req.decomp_iovcnt == 3);
1345 [ + + ]: 3 : for (i = 0; i < 2; i++) {
1346 : 2 : CU_ASSERT(req.decomp_iov[i].iov_base == req.iov[i].iov_base);
1347 : 2 : CU_ASSERT(req.decomp_iov[i].iov_len == req.iov[i].iov_len);
1348 : : }
1349 : 1 : CU_ASSERT(req.decomp_iov[i].iov_base == g_zero_buf + user_buffer_iov_len * 2);
1350 : 1 : CU_ASSERT(req.decomp_iov[i].iov_len == remainder_bytes);
1351 : :
1352 : : /* Test 3 - user's buffer less than chunk_size, non zero offset */
1353 : 1 : user_buffer_iov_len = 4096;
1354 : 1 : req.offset = 3;
1355 : 1 : offset_bytes = req.offset * vol.params.logical_block_size;
1356 : 1 : remainder_bytes = vol.params.chunk_size - offset_bytes - user_buffer_iov_len * 2;
1357 : :
1358 : 1 : _prepare_compress_chunk(&req, false);
1359 : 1 : CU_ASSERT(req.decomp_iovcnt == 4);
1360 : 1 : CU_ASSERT(req.decomp_iov[0].iov_base == req.decomp_buf);
1361 : 1 : CU_ASSERT(req.decomp_iov[0].iov_len == offset_bytes);
1362 [ + + ]: 3 : for (i = 0; i < 2; i++) {
1363 : 2 : CU_ASSERT(req.decomp_iov[i + 1].iov_base == req.iov[i].iov_base);
1364 : 2 : CU_ASSERT(req.decomp_iov[i + 1].iov_len == req.iov[i].iov_len);
1365 : : }
1366 : 1 : CU_ASSERT(req.decomp_iov[3].iov_base == req.decomp_buf + offset_bytes + user_buffer_iov_len * 2);
1367 : 1 : CU_ASSERT(req.decomp_iov[3].iov_len == remainder_bytes);
1368 : :
1369 : 1 : _prepare_compress_chunk(&req, true);
1370 : 1 : CU_ASSERT(req.decomp_iovcnt == 4);
1371 : 1 : CU_ASSERT(req.decomp_iov[0].iov_base == g_zero_buf);
1372 : 1 : CU_ASSERT(req.decomp_iov[0].iov_len == offset_bytes);
1373 [ + + ]: 3 : for (i = 0; i < 2; i++) {
1374 : 2 : CU_ASSERT(req.decomp_iov[i + 1].iov_base == req.iov[i].iov_base);
1375 : 2 : CU_ASSERT(req.decomp_iov[i + 1].iov_len == req.iov[i].iov_len);
1376 : : }
1377 : 1 : CU_ASSERT(req.decomp_iov[3].iov_base == g_zero_buf + offset_bytes + user_buffer_iov_len * 2);
1378 : 1 : CU_ASSERT(req.decomp_iov[3].iov_len == remainder_bytes);
1379 : :
1380 : : /* Part 2 - backing dev doesn't support sgl_in */
1381 : : /* Test 1 - user's buffers length equals to chunk_size
1382 : : * user's buffers are copied */
1383 : 1 : vol.backing_dev->sgl_in = false;
1384 : 1 : req.offset = 0;
1385 : 1 : user_buffer_iov_len = 8192;
1386 [ + + ]: 3 : for (i = 0; i < 2; i++) {
1387 : 2 : req.iov[i].iov_base = aligned_user_buffer + i * user_buffer_iov_len;
1388 : 2 : req.iov[i].iov_len = user_buffer_iov_len;
1389 [ - + ]: 2 : memset(req.iov[i].iov_base, 0xb + i, req.iov[i].iov_len);
1390 : : }
1391 : :
1392 [ - + ]: 1 : memset(req.decomp_buf, 0xa, vol.params.chunk_size);
1393 : :
1394 : 1 : _prepare_compress_chunk(&req, false);
1395 : 1 : CU_ASSERT(req.decomp_iovcnt == 1);
1396 : 1 : CU_ASSERT(req.decomp_iov[0].iov_base == req.decomp_buf);
1397 : 1 : CU_ASSERT(req.decomp_iov[0].iov_len == vol.params.chunk_size);
1398 [ - + - + ]: 1 : CU_ASSERT(memcmp(req.decomp_iov[0].iov_base, req.iov[0].iov_base, req.iov[0].iov_len) == 0);
1399 [ - + - + ]: 1 : CU_ASSERT(memcmp(req.decomp_iov[0].iov_base + req.iov[0].iov_len, req.iov[1].iov_base,
1400 : : req.iov[1].iov_len) == 0);
1401 : :
1402 [ - + ]: 1 : memset(req.decomp_buf, 0xa, vol.params.chunk_size);
1403 : :
1404 : 1 : _prepare_compress_chunk(&req, true);
1405 : 1 : CU_ASSERT(req.decomp_iovcnt == 1);
1406 : 1 : CU_ASSERT(req.decomp_iov[0].iov_base == req.decomp_buf);
1407 : 1 : CU_ASSERT(req.decomp_iov[0].iov_len == vol.params.chunk_size);
1408 [ - + - + ]: 1 : CU_ASSERT(memcmp(req.decomp_iov[0].iov_base, req.iov[0].iov_base, req.iov[0].iov_len) == 0);
1409 [ - + - + ]: 1 : CU_ASSERT(memcmp(req.decomp_iov[0].iov_base + req.iov[0].iov_len, req.iov[1].iov_base,
1410 : : req.iov[1].iov_len) == 0);
1411 : :
1412 : : /* Test 2 - single user's buffer length equals to chunk_size, buffer is not aligned
1413 : : * User's buffer is copied */
1414 : 1 : req.iov[0].iov_base = unaligned_user_buffer;
1415 : 1 : req.iov[0].iov_len = vol.params.chunk_size;
1416 : 1 : req.iovcnt = 1;
1417 [ - + ]: 1 : memset(req.decomp_buf, 0xa, vol.params.chunk_size);
1418 : :
1419 : 1 : _prepare_compress_chunk(&req, false);
1420 : 1 : CU_ASSERT(req.decomp_iovcnt == 1);
1421 : 1 : CU_ASSERT(req.decomp_iov[0].iov_base == req.decomp_buf);
1422 : 1 : CU_ASSERT(req.decomp_iov[0].iov_len == vol.params.chunk_size);
1423 [ - + - + ]: 1 : CU_ASSERT(memcmp(req.decomp_iov[0].iov_base, req.iov[0].iov_base,
1424 : : req.iov[0].iov_len) == 0);
1425 : :
1426 [ - + ]: 1 : memset(req.decomp_buf, 0xa, vol.params.chunk_size);
1427 : :
1428 : 1 : _prepare_compress_chunk(&req, true);
1429 : 1 : CU_ASSERT(req.decomp_iovcnt == 1);
1430 : 1 : CU_ASSERT(req.decomp_iov[0].iov_base == req.decomp_buf);
1431 : 1 : CU_ASSERT(req.decomp_iov[0].iov_len == vol.params.chunk_size);
1432 [ - + - + ]: 1 : CU_ASSERT(memcmp(req.decomp_iov[0].iov_base, req.iov[0].iov_base,
1433 : : req.iov[0].iov_len) == 0);
1434 : :
1435 : : /* Test 3 - single user's buffer length equals to chunk_size
1436 : : * User's buffer is not copied */
1437 : 1 : req.iov[0].iov_base = aligned_user_buffer;
1438 : 1 : req.iov[0].iov_len = vol.params.chunk_size;
1439 : 1 : req.iovcnt = 1;
1440 [ - + ]: 1 : memset(req.decomp_buf, 0xa, vol.params.chunk_size);
1441 : :
1442 : 1 : _prepare_compress_chunk(&req, false);
1443 : 1 : CU_ASSERT(req.decomp_iovcnt == 1);
1444 : 1 : CU_ASSERT(req.decomp_iov[0].iov_base == req.iov[0].iov_base);
1445 : 1 : CU_ASSERT(req.decomp_iov[0].iov_len == vol.params.chunk_size);
1446 : :
1447 [ - + ]: 1 : memset(req.decomp_buf, 0xa, vol.params.chunk_size);
1448 : :
1449 : 1 : _prepare_compress_chunk(&req, true);
1450 : 1 : CU_ASSERT(req.decomp_iovcnt == 1);
1451 : 1 : CU_ASSERT(req.decomp_iov[0].iov_base == req.iov[0].iov_base);
1452 : 1 : CU_ASSERT(req.decomp_iov[0].iov_len == vol.params.chunk_size);
1453 : :
1454 : : /* Test 4 - user's buffer less than chunk_size, without offset
1455 : : * User's buffers are copied */
1456 [ - + ]: 1 : memset(req.decomp_buf, 0xa, vol.params.chunk_size);
1457 : 1 : user_buffer_iov_len = 4096;
1458 : 1 : req.iovcnt = 2;
1459 : 1 : remainder_bytes = vol.params.chunk_size - user_buffer_iov_len * 2;
1460 [ + + ]: 3 : for (i = 0; i < 2; i++) {
1461 : 2 : req.iov[i].iov_base = aligned_user_buffer + i * user_buffer_iov_len;
1462 : 2 : req.iov[i].iov_len = user_buffer_iov_len;
1463 : : }
1464 : :
1465 [ - + ]: 1 : memset(req.decomp_buf, 0xa, vol.params.chunk_size);
1466 : :
1467 : 1 : _prepare_compress_chunk(&req, false);
1468 : 1 : CU_ASSERT(req.decomp_iovcnt == 1);
1469 : 1 : CU_ASSERT(req.decomp_iov[0].iov_base == req.decomp_buf);
1470 : 1 : CU_ASSERT(req.decomp_iov[0].iov_len == vol.params.chunk_size);
1471 : 1 : memcmp_offset = 0;
1472 [ - + - + ]: 1 : CU_ASSERT(memcmp(req.decomp_iov[0].iov_base + memcmp_offset, req.iov[0].iov_base,
1473 : : req.iov[0].iov_len) == 0);
1474 : 1 : memcmp_offset += req.iov[0].iov_len;
1475 [ - + - + ]: 1 : CU_ASSERT(memcmp(req.decomp_iov[0].iov_base + memcmp_offset, req.iov[1].iov_base,
1476 : : req.iov[1].iov_len) == 0);
1477 : 1 : memcmp_offset += req.iov[0].iov_len;
1478 [ - + - + ]: 1 : CU_ASSERT(memcmp(req.decomp_iov[0].iov_base + memcmp_offset, req.decomp_buf + memcmp_offset,
1479 : : remainder_bytes) == 0);
1480 : :
1481 [ - + ]: 1 : memset(req.decomp_buf, 0xa, vol.params.chunk_size);
1482 : :
1483 : 1 : _prepare_compress_chunk(&req, true);
1484 : 1 : CU_ASSERT(req.decomp_iovcnt == 1);
1485 : 1 : CU_ASSERT(req.decomp_iov[0].iov_base == req.decomp_buf);
1486 : 1 : CU_ASSERT(req.decomp_iov[0].iov_len == vol.params.chunk_size);
1487 : 1 : memcmp_offset = 0;
1488 [ - + - + ]: 1 : CU_ASSERT(memcmp(req.decomp_iov[0].iov_base + memcmp_offset, req.iov[0].iov_base,
1489 : : req.iov[0].iov_len) == 0);
1490 : 1 : memcmp_offset += req.iov[0].iov_len;
1491 [ - + - + ]: 1 : CU_ASSERT(memcmp(req.decomp_iov[0].iov_base + memcmp_offset, req.iov[1].iov_base,
1492 : : req.iov[1].iov_len) == 0);
1493 : 1 : memcmp_offset += req.iov[0].iov_len;
1494 [ - + - + ]: 1 : CU_ASSERT(memcmp(req.decomp_iov[0].iov_base + memcmp_offset, g_zero_buf + memcmp_offset,
1495 : : remainder_bytes) == 0);
1496 : :
1497 : : /* Test 5 - user's buffer less than chunk_size, non zero offset
1498 : : * user's buffers are copied */
1499 : 1 : req.offset = 3;
1500 : 1 : offset_bytes = req.offset * vol.params.logical_block_size;
1501 : 1 : remainder_bytes = vol.params.chunk_size - offset_bytes - user_buffer_iov_len * 2;
1502 : :
1503 [ - + ]: 1 : memset(req.decomp_buf, 0xa, vol.params.chunk_size);
1504 : :
1505 : 1 : _prepare_compress_chunk(&req, false);
1506 : 1 : CU_ASSERT(req.decomp_iovcnt == 1);
1507 : 1 : CU_ASSERT(req.decomp_iov[0].iov_base == req.decomp_buf);
1508 : 1 : CU_ASSERT(req.decomp_iov[0].iov_len == vol.params.chunk_size);
1509 : 1 : memcmp_offset = 0;
1510 [ - + - + ]: 1 : CU_ASSERT(memcmp(req.decomp_iov[0].iov_base + memcmp_offset, req.decomp_buf, offset_bytes) == 0);
1511 : 1 : memcmp_offset += offset_bytes;
1512 [ - + - + ]: 1 : CU_ASSERT(memcmp(req.decomp_iov[0].iov_base + memcmp_offset, req.iov[0].iov_base,
1513 : : req.iov[0].iov_len) == 0);
1514 : 1 : memcmp_offset += req.iov[0].iov_len;
1515 [ - + - + ]: 1 : CU_ASSERT(memcmp(req.decomp_iov[0].iov_base + memcmp_offset, req.iov[1].iov_base,
1516 : : req.iov[1].iov_len) == 0);
1517 : 1 : memcmp_offset += req.iov[1].iov_len;
1518 [ - + - + ]: 1 : CU_ASSERT(memcmp(req.decomp_iov[0].iov_base + memcmp_offset, req.decomp_buf + memcmp_offset,
1519 : : remainder_bytes) == 0);
1520 : :
1521 [ - + ]: 1 : memset(req.decomp_buf, 0xa, vol.params.chunk_size);
1522 : :
1523 : 1 : _prepare_compress_chunk(&req, true);
1524 : 1 : CU_ASSERT(req.decomp_iovcnt == 1);
1525 : 1 : CU_ASSERT(req.decomp_iov[0].iov_base == req.decomp_buf);
1526 : 1 : CU_ASSERT(req.decomp_iov[0].iov_len == vol.params.chunk_size);
1527 : 1 : memcmp_offset = 0;
1528 [ - + - + ]: 1 : CU_ASSERT(memcmp(req.decomp_iov[0].iov_base + memcmp_offset, g_zero_buf, offset_bytes) == 0);
1529 : 1 : memcmp_offset += offset_bytes;
1530 [ - + - + ]: 1 : CU_ASSERT(memcmp(req.decomp_iov[0].iov_base + memcmp_offset, req.iov[0].iov_base,
1531 : : req.iov[0].iov_len) == 0);
1532 : 1 : memcmp_offset += req.iov[0].iov_len;
1533 [ - + - + ]: 1 : CU_ASSERT(memcmp(req.decomp_iov[0].iov_base + memcmp_offset, req.iov[1].iov_base,
1534 : : req.iov[1].iov_len) == 0);
1535 : 1 : memcmp_offset += req.iov[1].iov_len;
1536 [ - + - + ]: 1 : CU_ASSERT(memcmp(req.decomp_iov[0].iov_base + memcmp_offset, g_zero_buf + memcmp_offset,
1537 : : remainder_bytes) == 0);
1538 : 1 : backing_dev_destroy(&backing_dev);
1539 : 1 : free(buf);
1540 : 1 : }
1541 : :
1542 : : static void
1543 : 8 : _reduce_vol_op_complete(void *ctx, int reduce_errno)
1544 : : {
1545 : 8 : g_reduce_errno = reduce_errno;
1546 : 8 : }
1547 : :
1548 : : static void
1549 : 8 : dummy_backing_dev_decompress(struct spdk_reduce_backing_dev *backing_dev,
1550 : : struct iovec *src_iov, int src_iovcnt,
1551 : : struct iovec *dst_iov, int dst_iovcnt,
1552 : : struct spdk_reduce_vol_cb_args *args)
1553 : : {
1554 : 8 : args->output_size = g_decompressed_len;
1555 : 8 : args->cb_fn(args->cb_arg, 0);
1556 : 8 : }
1557 : : static void
1558 : 1 : test_reduce_decompress_chunk(void)
1559 : : {
1560 : 1 : struct spdk_reduce_vol vol = {};
1561 : 1 : struct spdk_reduce_backing_dev backing_dev = {};
1562 : 1 : struct spdk_reduce_vol_request req = {};
1563 : 1 : void *buf;
1564 : : char *buffer_end, *aligned_user_buffer, *unaligned_user_buffer;
1565 : 1 : char decomp_buffer[16 * 1024] = {};
1566 : 1 : char comp_buffer[16 * 1024] = {};
1567 : 1 : struct iovec user_iov[2] = {};
1568 : 1 : struct iovec comp_buf_iov = {};
1569 : 1 : struct spdk_reduce_chunk_map chunk = {};
1570 : 1 : size_t user_buffer_iov_len = 8192;
1571 : : size_t remainder_bytes;
1572 : : size_t offset_bytes;
1573 : : uint32_t i;
1574 : :
1575 : 1 : vol.params.chunk_size = 16 * 1024;
1576 : 1 : vol.params.backing_io_unit_size = 4096;
1577 : 1 : vol.params.logical_block_size = 512;
1578 : 1 : backing_dev_init(&backing_dev, &vol.params, 512);
1579 : 1 : backing_dev.decompress = dummy_backing_dev_decompress;
1580 : 1 : vol.backing_dev = &backing_dev;
1581 [ - + ]: 1 : vol.logical_blocks_per_chunk = vol.params.chunk_size / vol.params.logical_block_size;
1582 : 1 : TAILQ_INIT(&vol.executing_requests);
1583 : 1 : TAILQ_INIT(&vol.queued_requests);
1584 : 1 : TAILQ_INIT(&vol.free_requests);
1585 : :
1586 : : /* Allocate 1 extra byte to test a case when buffer crosses huge page boundary */
1587 [ - + ]: 1 : SPDK_CU_ASSERT_FATAL(posix_memalign(&buf, VALUE_2MB, VALUE_2MB + 1) == 0);
1588 : 1 : buffer_end = (char *)buf + VALUE_2MB + 1;
1589 : 1 : aligned_user_buffer = (char *)buf;
1590 : 1 : unaligned_user_buffer = buffer_end - vol.params.chunk_size;
1591 : :
1592 : 1 : chunk.compressed_size = user_buffer_iov_len / 2;
1593 : 1 : req.chunk = &chunk;
1594 : 1 : req.vol = &vol;
1595 : 1 : req.decomp_buf = decomp_buffer;
1596 : 1 : req.comp_buf = comp_buffer;
1597 : 1 : req.comp_buf_iov = &comp_buf_iov;
1598 : 1 : req.iov = user_iov;
1599 : 1 : req.iovcnt = 2;
1600 : 1 : req.offset = 0;
1601 : 1 : req.cb_fn = _reduce_vol_op_complete;
1602 : :
1603 : : /* Part 1 - backing dev supports sgl_out */
1604 : : /* Test 1 - user's buffers length equals to chunk_size */
1605 [ + + ]: 3 : for (i = 0; i < 2; i++) {
1606 : 2 : req.iov[i].iov_base = aligned_user_buffer + i * user_buffer_iov_len;
1607 : 2 : req.iov[i].iov_len = user_buffer_iov_len;
1608 [ - + ]: 2 : memset(req.iov[i].iov_base, 0, req.iov[i].iov_len);
1609 : : }
1610 [ - + ]: 1 : TAILQ_INSERT_HEAD(&vol.executing_requests, &req, tailq);
1611 : 1 : g_reduce_errno = -1;
1612 : 1 : g_decompressed_len = vol.params.chunk_size;
1613 : :
1614 : 1 : _reduce_vol_decompress_chunk(&req, _read_decompress_done);
1615 : 1 : CU_ASSERT(g_reduce_errno == 0);
1616 [ - + ]: 1 : CU_ASSERT(req.copy_after_decompress == false);
1617 : 1 : CU_ASSERT(req.decomp_iovcnt == 2);
1618 [ + + ]: 3 : for (i = 0; i < 2; i++) {
1619 : 2 : CU_ASSERT(req.decomp_iov[i].iov_base == req.iov[i].iov_base);
1620 : 2 : CU_ASSERT(req.decomp_iov[i].iov_len == req.iov[i].iov_len);
1621 : : }
1622 : 1 : CU_ASSERT(TAILQ_EMPTY(&vol.executing_requests));
1623 : 1 : CU_ASSERT(TAILQ_FIRST(&vol.free_requests) == &req);
1624 : :
1625 : : /* Test 2 - user's buffer less than chunk_size, without offset */
1626 [ - + ]: 1 : TAILQ_INSERT_HEAD(&vol.executing_requests, &req, tailq);
1627 : 1 : g_reduce_errno = -1;
1628 : 1 : user_buffer_iov_len = 4096;
1629 [ + + ]: 3 : for (i = 0; i < 2; i++) {
1630 : 2 : req.iov[i].iov_base = aligned_user_buffer + i * user_buffer_iov_len;
1631 : 2 : req.iov[i].iov_len = user_buffer_iov_len;
1632 [ - + ]: 2 : memset(req.iov[i].iov_base, 0, req.iov[i].iov_len);
1633 : : }
1634 : 1 : remainder_bytes = vol.params.chunk_size - user_buffer_iov_len * 2;
1635 : :
1636 : 1 : _reduce_vol_decompress_chunk(&req, _read_decompress_done);
1637 : 1 : CU_ASSERT(g_reduce_errno == 0);
1638 [ - + ]: 1 : CU_ASSERT(req.copy_after_decompress == false);
1639 : 1 : CU_ASSERT(req.decomp_iovcnt == 3);
1640 [ + + ]: 3 : for (i = 0; i < 2; i++) {
1641 : 2 : CU_ASSERT(req.decomp_iov[i].iov_base == req.iov[i].iov_base);
1642 : 2 : CU_ASSERT(req.decomp_iov[i].iov_len == req.iov[i].iov_len);
1643 : : }
1644 : 1 : CU_ASSERT(req.decomp_iov[i].iov_base == req.decomp_buf + user_buffer_iov_len * 2);
1645 : 1 : CU_ASSERT(req.decomp_iov[i].iov_len == remainder_bytes);
1646 : 1 : CU_ASSERT(TAILQ_EMPTY(&vol.executing_requests));
1647 : 1 : CU_ASSERT(TAILQ_FIRST(&vol.free_requests) == &req);
1648 : :
1649 : : /* Test 3 - user's buffer less than chunk_size, non zero offset */
1650 : 1 : req.offset = 3;
1651 : 1 : offset_bytes = req.offset * vol.params.logical_block_size;
1652 : 1 : remainder_bytes = vol.params.chunk_size - offset_bytes - user_buffer_iov_len * 2;
1653 [ - + ]: 1 : TAILQ_INSERT_HEAD(&vol.executing_requests, &req, tailq);
1654 : 1 : g_reduce_errno = -1;
1655 : :
1656 : 1 : _reduce_vol_decompress_chunk(&req, _read_decompress_done);
1657 : 1 : CU_ASSERT(g_reduce_errno == 0);
1658 [ - + ]: 1 : CU_ASSERT(req.copy_after_decompress == false);
1659 : 1 : CU_ASSERT(req.decomp_iovcnt == 4);
1660 : 1 : CU_ASSERT(req.decomp_iov[0].iov_base == req.decomp_buf);
1661 : 1 : CU_ASSERT(req.decomp_iov[0].iov_len == offset_bytes);
1662 [ + + ]: 3 : for (i = 0; i < 2; i++) {
1663 : 2 : CU_ASSERT(req.decomp_iov[i + 1].iov_base == req.iov[i].iov_base);
1664 : 2 : CU_ASSERT(req.decomp_iov[i + 1].iov_len == req.iov[i].iov_len);
1665 : : }
1666 : 1 : CU_ASSERT(req.decomp_iov[3].iov_base == req.decomp_buf + offset_bytes + user_buffer_iov_len * 2);
1667 : 1 : CU_ASSERT(req.decomp_iov[3].iov_len == remainder_bytes);
1668 : 1 : CU_ASSERT(TAILQ_EMPTY(&vol.executing_requests));
1669 : 1 : CU_ASSERT(TAILQ_FIRST(&vol.free_requests) == &req);
1670 : :
1671 : : /* Part 2 - backing dev doesn't support sgl_out */
1672 : : /* Test 1 - user's buffers length equals to chunk_size
1673 : : * user's buffers are copied */
1674 : 1 : vol.backing_dev->sgl_out = false;
1675 : 1 : req.offset = 0;
1676 : 1 : user_buffer_iov_len = 8192;
1677 : :
1678 [ - + ]: 1 : memset(req.decomp_buf, 0xa, vol.params.chunk_size);
1679 [ + + ]: 3 : for (i = 0; i < 2; i++) {
1680 : 2 : req.iov[i].iov_base = aligned_user_buffer + i * user_buffer_iov_len;
1681 : 2 : req.iov[i].iov_len = user_buffer_iov_len;
1682 [ - + ]: 2 : memset(req.iov[i].iov_base, 0xb + i, req.iov[i].iov_len);
1683 : : }
1684 [ - + ]: 1 : TAILQ_INSERT_HEAD(&vol.executing_requests, &req, tailq);
1685 : 1 : g_reduce_errno = -1;
1686 : :
1687 : 1 : _reduce_vol_decompress_chunk(&req, _read_decompress_done);
1688 : 1 : CU_ASSERT(g_reduce_errno == 0);
1689 [ - + ]: 1 : CU_ASSERT(req.copy_after_decompress == true);
1690 : 1 : CU_ASSERT(req.decomp_iovcnt == 1);
1691 : 1 : CU_ASSERT(req.decomp_iov[0].iov_base == req.decomp_buf);
1692 : 1 : CU_ASSERT(req.decomp_iov[0].iov_len == vol.params.chunk_size);
1693 [ - + - + ]: 1 : CU_ASSERT(memcmp(req.iov[0].iov_base, req.decomp_iov[0].iov_base, req.iov[0].iov_len) == 0);
1694 [ - + - + ]: 1 : CU_ASSERT(memcmp(req.iov[1].iov_base, req.decomp_iov[0].iov_base + req.iov[0].iov_len,
1695 : : req.iov[1].iov_len) == 0);
1696 : 1 : CU_ASSERT(TAILQ_EMPTY(&vol.executing_requests));
1697 : 1 : CU_ASSERT(TAILQ_FIRST(&vol.free_requests) == &req);
1698 : :
1699 : : /* Test 2 - single user's buffer length equals to chunk_size, buffer is not aligned
1700 : : * User's buffer is copied */
1701 [ - + ]: 1 : memset(unaligned_user_buffer, 0xc, vol.params.chunk_size);
1702 : 1 : req.iov[0].iov_base = unaligned_user_buffer;
1703 : 1 : req.iov[0].iov_len = vol.params.chunk_size;
1704 : 1 : req.iovcnt = 1;
1705 [ - + ]: 1 : memset(req.decomp_buf, 0xa, vol.params.chunk_size);
1706 [ - + ]: 1 : TAILQ_INSERT_HEAD(&vol.executing_requests, &req, tailq);
1707 : 1 : g_reduce_errno = -1;
1708 : :
1709 : 1 : _reduce_vol_decompress_chunk(&req, _read_decompress_done);
1710 : 1 : CU_ASSERT(g_reduce_errno == 0);
1711 [ - + ]: 1 : CU_ASSERT(req.copy_after_decompress == true);
1712 : 1 : CU_ASSERT(req.decomp_iovcnt == 1);
1713 : 1 : CU_ASSERT(req.decomp_iov[0].iov_base == req.decomp_buf);
1714 : 1 : CU_ASSERT(req.decomp_iov[0].iov_len == vol.params.chunk_size);
1715 [ - + - + ]: 1 : CU_ASSERT(memcmp(req.iov[0].iov_base, req.decomp_iov[0].iov_base,
1716 : : req.iov[0].iov_len) == 0);
1717 : :
1718 : : /* Test 3 - single user's buffer length equals to chunk_size
1719 : : * User's buffer is not copied */
1720 : 1 : req.iov[0].iov_base = aligned_user_buffer;
1721 : 1 : req.iov[0].iov_len = vol.params.chunk_size;
1722 : 1 : req.iovcnt = 1;
1723 [ - + ]: 1 : memset(req.decomp_buf, 0xa, vol.params.chunk_size);
1724 [ - + ]: 1 : TAILQ_INSERT_HEAD(&vol.executing_requests, &req, tailq);
1725 : 1 : g_reduce_errno = -1;
1726 : :
1727 : 1 : _reduce_vol_decompress_chunk(&req, _read_decompress_done);
1728 : 1 : CU_ASSERT(g_reduce_errno == 0);
1729 [ - + ]: 1 : CU_ASSERT(req.copy_after_decompress == false);
1730 : 1 : CU_ASSERT(req.decomp_iovcnt == 1);
1731 : 1 : CU_ASSERT(req.decomp_iov[0].iov_base == req.iov[0].iov_base);
1732 : 1 : CU_ASSERT(req.decomp_iov[0].iov_len == vol.params.chunk_size);
1733 : :
1734 : : /* Test 4 - user's buffer less than chunk_size, without offset
1735 : : * User's buffers are copied */
1736 : 1 : user_buffer_iov_len = 4096;
1737 : 1 : req.iovcnt = 2;
1738 : 1 : remainder_bytes = vol.params.chunk_size - user_buffer_iov_len * 2;
1739 [ + + ]: 3 : for (i = 0; i < 2; i++) {
1740 : 2 : req.iov[i].iov_base = aligned_user_buffer + i * user_buffer_iov_len;
1741 : 2 : req.iov[i].iov_len = user_buffer_iov_len;
1742 [ - + ]: 2 : memset(req.iov[i].iov_base, 0xb + i, req.iov[i].iov_len);
1743 : : }
1744 : :
1745 [ - + ]: 1 : memset(req.decomp_buf, 0xa, vol.params.chunk_size);
1746 [ - + ]: 1 : TAILQ_INSERT_HEAD(&vol.executing_requests, &req, tailq);
1747 : 1 : g_reduce_errno = -1;
1748 : :
1749 : 1 : _reduce_vol_decompress_chunk(&req, _read_decompress_done);
1750 : 1 : CU_ASSERT(g_reduce_errno == 0);
1751 [ - + ]: 1 : CU_ASSERT(req.copy_after_decompress == true);
1752 : 1 : CU_ASSERT(req.decomp_iovcnt == 1);
1753 : 1 : CU_ASSERT(req.decomp_iov[0].iov_base == req.decomp_buf);
1754 : 1 : CU_ASSERT(req.decomp_iov[0].iov_len == vol.params.chunk_size);
1755 [ - + - + ]: 1 : CU_ASSERT(memcmp(req.iov[0].iov_base, req.decomp_iov[0].iov_base,
1756 : : req.iov[0].iov_len) == 0);
1757 [ - + - + ]: 1 : CU_ASSERT(memcmp(req.iov[1].iov_base, req.decomp_iov[0].iov_base + req.iov[0].iov_len,
1758 : : req.iov[1].iov_len) == 0);
1759 : 1 : CU_ASSERT(TAILQ_EMPTY(&vol.executing_requests));
1760 : 1 : CU_ASSERT(TAILQ_FIRST(&vol.free_requests) == &req);
1761 : :
1762 : : /* Test 5 - user's buffer less than chunk_size, non zero offset
1763 : : * user's buffers are copied */
1764 : 1 : req.offset = 3;
1765 : 1 : offset_bytes = req.offset * vol.params.logical_block_size;
1766 : 1 : remainder_bytes = vol.params.chunk_size - offset_bytes - user_buffer_iov_len * 2;
1767 : :
1768 [ + + ]: 3 : for (i = 0; i < 2; i++) {
1769 : 2 : req.iov[i].iov_base = aligned_user_buffer + i * user_buffer_iov_len;
1770 : 2 : req.iov[i].iov_len = user_buffer_iov_len;
1771 [ - + ]: 2 : memset(req.iov[i].iov_base, 0xb + i, req.iov[i].iov_len);
1772 : : }
1773 : :
1774 [ - + ]: 1 : memset(req.decomp_buf, 0xa, vol.params.chunk_size);
1775 [ - + ]: 1 : TAILQ_INSERT_HEAD(&vol.executing_requests, &req, tailq);
1776 : 1 : g_reduce_errno = -1;
1777 : :
1778 : 1 : _prepare_compress_chunk(&req, false);
1779 : 1 : _reduce_vol_decompress_chunk(&req, _read_decompress_done);
1780 : 1 : CU_ASSERT(g_reduce_errno == 0);
1781 [ - + ]: 1 : CU_ASSERT(req.copy_after_decompress == true);
1782 : 1 : CU_ASSERT(req.decomp_iovcnt == 1);
1783 : 1 : CU_ASSERT(req.decomp_iov[0].iov_base == req.decomp_buf);
1784 : 1 : CU_ASSERT(req.decomp_iov[0].iov_len == vol.params.chunk_size);
1785 [ - + - + ]: 1 : CU_ASSERT(memcmp(req.decomp_iov[0].iov_base + offset_bytes, req.iov[0].iov_base,
1786 : : req.iov[0].iov_len) == 0);
1787 [ - + - + ]: 1 : CU_ASSERT(memcmp(req.decomp_iov[0].iov_base + offset_bytes + req.iov[0].iov_len,
1788 : : req.iov[1].iov_base,
1789 : : req.iov[1].iov_len) == 0);
1790 : 1 : CU_ASSERT(TAILQ_EMPTY(&vol.executing_requests));
1791 : 1 : CU_ASSERT(TAILQ_FIRST(&vol.free_requests) == &req);
1792 : :
1793 : 1 : free(buf);
1794 : 1 : }
1795 : :
1796 : : static void
1797 : 1 : test_allocate_vol_requests(void)
1798 : : {
1799 : : struct spdk_reduce_vol *vol;
1800 : : /* include chunk_sizes which are not power of 2 */
1801 : 1 : uint32_t chunk_sizes[] = {8192, 8320, 16384, 16416, 32768};
1802 : 1 : uint32_t io_unit_sizes[] = {512, 520, 4096, 4104, 4096};
1803 : : uint32_t i;
1804 : :
1805 [ + + ]: 5 : for (i = 0; i < 4; i++) {
1806 : 4 : vol = calloc(1, sizeof(*vol));
1807 [ - + ]: 4 : SPDK_CU_ASSERT_FATAL(vol);
1808 : :
1809 : 4 : vol->params.chunk_size = chunk_sizes[i];
1810 : 4 : vol->params.logical_block_size = io_unit_sizes[i];
1811 : 4 : vol->params.backing_io_unit_size = io_unit_sizes[i];
1812 [ - + ]: 4 : vol->backing_io_units_per_chunk = vol->params.chunk_size / vol->params.backing_io_unit_size;
1813 [ - + ]: 4 : vol->logical_blocks_per_chunk = vol->params.chunk_size / vol->params.logical_block_size;
1814 : :
1815 : 4 : CU_ASSERT(_validate_vol_params(&vol->params) == 0);
1816 : 4 : CU_ASSERT(_allocate_vol_requests(vol) == 0);
1817 : 4 : _init_load_cleanup(vol, NULL);
1818 : : }
1819 : 1 : }
1820 : :
1821 : : int
1822 : 1 : main(int argc, char **argv)
1823 : : {
1824 : 1 : CU_pSuite suite = NULL;
1825 : : unsigned int num_failures;
1826 : :
1827 : 1 : CU_initialize_registry();
1828 : :
1829 : 1 : suite = CU_add_suite("reduce", NULL, NULL);
1830 : :
1831 : 1 : CU_ADD_TEST(suite, get_pm_file_size);
1832 : 1 : CU_ADD_TEST(suite, get_vol_size);
1833 : 1 : CU_ADD_TEST(suite, init_failure);
1834 : 1 : CU_ADD_TEST(suite, init_md);
1835 : 1 : CU_ADD_TEST(suite, init_backing_dev);
1836 : 1 : CU_ADD_TEST(suite, load);
1837 : 1 : CU_ADD_TEST(suite, write_maps);
1838 : 1 : CU_ADD_TEST(suite, read_write);
1839 : 1 : CU_ADD_TEST(suite, readv_writev);
1840 : 1 : CU_ADD_TEST(suite, destroy);
1841 : 1 : CU_ADD_TEST(suite, defer_bdev_io);
1842 : 1 : CU_ADD_TEST(suite, overlapped);
1843 : 1 : CU_ADD_TEST(suite, compress_algorithm);
1844 : 1 : CU_ADD_TEST(suite, test_prepare_compress_chunk);
1845 : 1 : CU_ADD_TEST(suite, test_reduce_decompress_chunk);
1846 : 1 : CU_ADD_TEST(suite, test_allocate_vol_requests);
1847 : :
1848 : 1 : g_unlink_path = g_path;
1849 : 1 : g_unlink_callback = unlink_cb;
1850 : :
1851 : 1 : num_failures = spdk_ut_run_tests(argc, argv, NULL);
1852 : 1 : CU_cleanup_registry();
1853 : 1 : return num_failures;
1854 : : }
|