1 /*- 2 * BSD LICENSE 3 * 4 * Copyright (c) Intel Corporation. 5 * All rights reserved. 6 * 7 * Redistribution and use in source and binary forms, with or without 8 * modification, are permitted provided that the following conditions 9 * are met: 10 * 11 * * Redistributions of source code must retain the above copyright 12 * notice, this list of conditions and the following disclaimer. 13 * * Redistributions in binary form must reproduce the above copyright 14 * notice, this list of conditions and the following disclaimer in 15 * the documentation and/or other materials provided with the 16 * distribution. 17 * * Neither the name of Intel Corporation nor the names of its 18 * contributors may be used to endorse or promote products derived 19 * from this software without specific prior written permission. 20 * 21 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 22 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 23 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 24 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 25 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 26 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 27 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 28 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 29 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 30 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 31 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 32 */ 33 34 #include "spdk/stdinc.h" 35 36 #include "spdk_cunit.h" 37 38 #include "reduce/reduce.c" 39 #include "spdk_internal/mock.h" 40 #include "common/lib/test_env.c" 41 42 static struct spdk_reduce_vol *g_vol; 43 static int g_reduce_errno; 44 static char *g_volatile_pm_buf; 45 static size_t g_volatile_pm_buf_len; 46 static char *g_persistent_pm_buf; 47 static size_t g_persistent_pm_buf_len; 48 static bool g_backing_dev_closed; 49 static char *g_backing_dev_buf; 50 static const char *g_path; 51 52 #define TEST_MD_PATH "/tmp" 53 54 static void 55 sync_pm_buf(const void *addr, size_t length) 56 { 57 uint64_t offset = (char *)addr - g_volatile_pm_buf; 58 59 memcpy(&g_persistent_pm_buf[offset], addr, length); 60 } 61 62 int 63 pmem_msync(const void *addr, size_t length) 64 { 65 sync_pm_buf(addr, length); 66 return 0; 67 } 68 69 void 70 pmem_persist(const void *addr, size_t len) 71 { 72 sync_pm_buf(addr, len); 73 } 74 75 static void 76 get_pm_file_size(void) 77 { 78 struct spdk_reduce_vol_params params; 79 uint64_t pm_size, expected_pm_size; 80 81 params.backing_io_unit_size = 4096; 82 params.chunk_size = 4096 * 4; 83 params.vol_size = 4096 * 4 * 100; 84 85 pm_size = _get_pm_file_size(¶ms); 86 expected_pm_size = sizeof(struct spdk_reduce_vol_superblock); 87 /* 100 chunks in logical map * 8 bytes per chunk */ 88 expected_pm_size += 100 * sizeof(uint64_t); 89 /* 100 chunks * 4 backing io units per chunk * 8 bytes per backing io unit */ 90 expected_pm_size += 100 * 4 * sizeof(uint64_t); 91 /* reduce allocates some extra chunks too for in-flight writes when logical map 92 * is full. REDUCE_EXTRA_CHUNKS is a private #ifdef in reduce.c. 93 */ 94 expected_pm_size += REDUCE_NUM_EXTRA_CHUNKS * 4 * sizeof(uint64_t); 95 /* reduce will add some padding so numbers may not match exactly. Make sure 96 * they are close though. 97 */ 98 CU_ASSERT((pm_size - expected_pm_size) < REDUCE_PM_SIZE_ALIGNMENT); 99 } 100 101 static void 102 get_vol_size(void) 103 { 104 uint64_t chunk_size, backing_dev_size; 105 106 chunk_size = 16 * 1024; 107 backing_dev_size = 16 * 1024 * 1000; 108 CU_ASSERT(_get_vol_size(chunk_size, backing_dev_size) < backing_dev_size); 109 } 110 111 void * 112 pmem_map_file(const char *path, size_t len, int flags, mode_t mode, 113 size_t *mapped_lenp, int *is_pmemp) 114 { 115 CU_ASSERT(g_volatile_pm_buf == NULL); 116 g_path = path; 117 *is_pmemp = 1; 118 119 if (g_persistent_pm_buf == NULL) { 120 g_persistent_pm_buf = calloc(1, len); 121 g_persistent_pm_buf_len = len; 122 SPDK_CU_ASSERT_FATAL(g_persistent_pm_buf != NULL); 123 } 124 125 *mapped_lenp = g_persistent_pm_buf_len; 126 g_volatile_pm_buf = calloc(1, g_persistent_pm_buf_len); 127 SPDK_CU_ASSERT_FATAL(g_volatile_pm_buf != NULL); 128 g_volatile_pm_buf_len = g_persistent_pm_buf_len; 129 130 return g_volatile_pm_buf; 131 } 132 133 int 134 pmem_unmap(void *addr, size_t len) 135 { 136 CU_ASSERT(addr == g_volatile_pm_buf); 137 CU_ASSERT(len == g_volatile_pm_buf_len); 138 free(g_volatile_pm_buf); 139 g_volatile_pm_buf = NULL; 140 g_volatile_pm_buf_len = 0; 141 142 return 0; 143 } 144 145 static void 146 persistent_pm_buf_destroy(void) 147 { 148 CU_ASSERT(g_persistent_pm_buf != NULL); 149 free(g_persistent_pm_buf); 150 g_persistent_pm_buf = NULL; 151 g_persistent_pm_buf_len = 0; 152 } 153 154 static void 155 init_cb(void *cb_arg, struct spdk_reduce_vol *vol, int reduce_errno) 156 { 157 g_vol = vol; 158 g_reduce_errno = reduce_errno; 159 } 160 161 static void 162 load_cb(void *cb_arg, struct spdk_reduce_vol *vol, int reduce_errno) 163 { 164 g_vol = vol; 165 g_reduce_errno = reduce_errno; 166 } 167 168 static void 169 unload_cb(void *cb_arg, int reduce_errno) 170 { 171 g_reduce_errno = reduce_errno; 172 } 173 174 static void 175 init_failure(void) 176 { 177 struct spdk_reduce_vol_params params = {}; 178 struct spdk_reduce_backing_dev backing_dev = {}; 179 180 backing_dev.blocklen = 512; 181 /* This blockcnt is too small for a reduce vol - there needs to be 182 * enough space for at least REDUCE_NUM_EXTRA_CHUNKS + 1 chunks. 183 */ 184 backing_dev.blockcnt = 20; 185 186 params.vol_size = 0; 187 params.chunk_size = 16 * 1024; 188 params.backing_io_unit_size = backing_dev.blocklen; 189 params.logical_block_size = 512; 190 191 /* backing_dev has an invalid size. This should fail. */ 192 g_vol = NULL; 193 g_reduce_errno = 0; 194 spdk_reduce_vol_init(¶ms, &backing_dev, TEST_MD_PATH, init_cb, NULL); 195 CU_ASSERT(g_reduce_errno == -EINVAL); 196 SPDK_CU_ASSERT_FATAL(g_vol == NULL); 197 198 /* backing_dev now has valid size, but backing_dev still has null 199 * function pointers. This should fail. 200 */ 201 backing_dev.blockcnt = 20000; 202 203 g_vol = NULL; 204 g_reduce_errno = 0; 205 spdk_reduce_vol_init(¶ms, &backing_dev, TEST_MD_PATH, init_cb, NULL); 206 CU_ASSERT(g_reduce_errno == -EINVAL); 207 SPDK_CU_ASSERT_FATAL(g_vol == NULL); 208 } 209 210 static void 211 backing_dev_readv(struct spdk_reduce_backing_dev *backing_dev, struct iovec *iov, int iovcnt, 212 uint64_t lba, uint32_t lba_count, struct spdk_reduce_vol_cb_args *args) 213 { 214 char *offset; 215 int i; 216 217 offset = g_backing_dev_buf + lba * backing_dev->blocklen; 218 for (i = 0; i < iovcnt; i++) { 219 memcpy(iov[i].iov_base, offset, iov[i].iov_len); 220 offset += iov[i].iov_len; 221 } 222 args->cb_fn(args->cb_arg, 0); 223 } 224 225 static void 226 backing_dev_writev(struct spdk_reduce_backing_dev *backing_dev, struct iovec *iov, int iovcnt, 227 uint64_t lba, uint32_t lba_count, struct spdk_reduce_vol_cb_args *args) 228 { 229 char *offset; 230 int i; 231 232 offset = g_backing_dev_buf + lba * backing_dev->blocklen; 233 for (i = 0; i < iovcnt; i++) { 234 memcpy(offset, iov[i].iov_base, iov[i].iov_len); 235 offset += iov[i].iov_len; 236 } 237 args->cb_fn(args->cb_arg, 0); 238 } 239 240 static void 241 backing_dev_unmap(struct spdk_reduce_backing_dev *backing_dev, 242 uint64_t lba, uint32_t lba_count, struct spdk_reduce_vol_cb_args *args) 243 { 244 char *offset; 245 246 offset = g_backing_dev_buf + lba * backing_dev->blocklen; 247 memset(offset, 0, lba_count * backing_dev->blocklen); 248 args->cb_fn(args->cb_arg, 0); 249 } 250 251 static void 252 backing_dev_close(struct spdk_reduce_backing_dev *backing_dev) 253 { 254 g_backing_dev_closed = true; 255 } 256 257 static void 258 backing_dev_destroy(struct spdk_reduce_backing_dev *backing_dev) 259 { 260 /* We don't free this during backing_dev_close so that we can test init/unload/load 261 * scenarios. 262 */ 263 free(g_backing_dev_buf); 264 g_backing_dev_buf = NULL; 265 } 266 267 static void 268 backing_dev_init(struct spdk_reduce_backing_dev *backing_dev, struct spdk_reduce_vol_params *params, 269 uint32_t backing_blocklen) 270 { 271 int64_t size; 272 273 size = 4 * 1024 * 1024; 274 backing_dev->blocklen = backing_blocklen; 275 backing_dev->blockcnt = size / backing_dev->blocklen; 276 backing_dev->readv = backing_dev_readv; 277 backing_dev->writev = backing_dev_writev; 278 backing_dev->unmap = backing_dev_unmap; 279 backing_dev->close = backing_dev_close; 280 281 g_backing_dev_buf = calloc(1, size); 282 SPDK_CU_ASSERT_FATAL(g_backing_dev_buf != NULL); 283 } 284 285 static void 286 init_md(void) 287 { 288 struct spdk_reduce_vol_params params = {}; 289 struct spdk_reduce_vol_params *persistent_params; 290 struct spdk_reduce_backing_dev backing_dev = {}; 291 struct spdk_uuid uuid; 292 uint64_t *entry; 293 294 params.chunk_size = 16 * 1024; 295 params.backing_io_unit_size = 512; 296 params.logical_block_size = 512; 297 298 backing_dev_init(&backing_dev, ¶ms, 512); 299 300 g_vol = NULL; 301 g_reduce_errno = -1; 302 spdk_reduce_vol_init(¶ms, &backing_dev, TEST_MD_PATH, init_cb, NULL); 303 CU_ASSERT(g_reduce_errno == 0); 304 SPDK_CU_ASSERT_FATAL(g_vol != NULL); 305 /* Confirm that reduce persisted the params to metadata. */ 306 CU_ASSERT(memcmp(g_persistent_pm_buf, SPDK_REDUCE_SIGNATURE, 8) == 0); 307 persistent_params = (struct spdk_reduce_vol_params *)(g_persistent_pm_buf + 8); 308 CU_ASSERT(memcmp(persistent_params, ¶ms, sizeof(params)) == 0); 309 /* Now confirm that contents of pm_file after the superblock have been initialized 310 * to REDUCE_EMPTY_MAP_ENTRY. 311 */ 312 entry = (uint64_t *)(g_persistent_pm_buf + sizeof(struct spdk_reduce_vol_superblock)); 313 while (entry != (uint64_t *)(g_persistent_pm_buf + g_vol->pm_file.size)) { 314 CU_ASSERT(*entry == REDUCE_EMPTY_MAP_ENTRY); 315 entry++; 316 } 317 318 /* Check that the pm file path was constructed correctly. It should be in 319 * the form: 320 * TEST_MD_PATH + "/" + <uuid string> 321 */ 322 CU_ASSERT(strncmp(&g_path[0], TEST_MD_PATH, strlen(TEST_MD_PATH)) == 0); 323 CU_ASSERT(g_path[strlen(TEST_MD_PATH)] == '/'); 324 CU_ASSERT(spdk_uuid_parse(&uuid, &g_path[strlen(TEST_MD_PATH) + 1]) == 0); 325 CU_ASSERT(spdk_uuid_compare(&uuid, spdk_reduce_vol_get_uuid(g_vol)) == 0); 326 327 g_reduce_errno = -1; 328 g_backing_dev_closed = false; 329 spdk_reduce_vol_unload(g_vol, unload_cb, NULL); 330 CU_ASSERT(g_reduce_errno == 0); 331 CU_ASSERT(g_backing_dev_closed == true); 332 CU_ASSERT(g_volatile_pm_buf == NULL); 333 334 persistent_pm_buf_destroy(); 335 backing_dev_destroy(&backing_dev); 336 } 337 338 static void 339 _init_backing_dev(uint32_t backing_blocklen) 340 { 341 struct spdk_reduce_vol_params params = {}; 342 struct spdk_reduce_vol_params *persistent_params; 343 struct spdk_reduce_backing_dev backing_dev = {}; 344 345 params.chunk_size = 16 * 1024; 346 params.backing_io_unit_size = 512; 347 params.logical_block_size = 512; 348 spdk_uuid_generate(¶ms.uuid); 349 350 backing_dev_init(&backing_dev, ¶ms, backing_blocklen); 351 352 g_vol = NULL; 353 g_path = NULL; 354 g_reduce_errno = -1; 355 spdk_reduce_vol_init(¶ms, &backing_dev, TEST_MD_PATH, init_cb, NULL); 356 CU_ASSERT(g_reduce_errno == 0); 357 SPDK_CU_ASSERT_FATAL(g_vol != NULL); 358 SPDK_CU_ASSERT_FATAL(g_path != NULL); 359 /* Confirm that libreduce persisted the params to the backing device. */ 360 CU_ASSERT(memcmp(g_backing_dev_buf, SPDK_REDUCE_SIGNATURE, 8) == 0); 361 persistent_params = (struct spdk_reduce_vol_params *)(g_backing_dev_buf + 8); 362 CU_ASSERT(memcmp(persistent_params, ¶ms, sizeof(params)) == 0); 363 CU_ASSERT(backing_dev.close != NULL); 364 /* Confirm that the path to the persistent memory metadata file was persisted to 365 * the backing device. 366 */ 367 CU_ASSERT(strncmp(g_path, 368 g_backing_dev_buf + REDUCE_BACKING_DEV_PATH_OFFSET, 369 REDUCE_PATH_MAX) == 0); 370 371 g_reduce_errno = -1; 372 g_backing_dev_closed = false; 373 spdk_reduce_vol_unload(g_vol, unload_cb, NULL); 374 CU_ASSERT(g_reduce_errno == 0); 375 CU_ASSERT(g_backing_dev_closed == true); 376 377 persistent_pm_buf_destroy(); 378 backing_dev_destroy(&backing_dev); 379 } 380 381 static void 382 init_backing_dev(void) 383 { 384 _init_backing_dev(512); 385 _init_backing_dev(4096); 386 } 387 388 static void 389 _load(uint32_t backing_blocklen) 390 { 391 struct spdk_reduce_vol_params params = {}; 392 struct spdk_reduce_backing_dev backing_dev = {}; 393 char pmem_file_path[REDUCE_PATH_MAX]; 394 395 params.chunk_size = 16 * 1024; 396 params.backing_io_unit_size = 512; 397 params.logical_block_size = 512; 398 spdk_uuid_generate(¶ms.uuid); 399 400 backing_dev_init(&backing_dev, ¶ms, backing_blocklen); 401 402 g_vol = NULL; 403 g_reduce_errno = -1; 404 spdk_reduce_vol_init(¶ms, &backing_dev, TEST_MD_PATH, init_cb, NULL); 405 CU_ASSERT(g_reduce_errno == 0); 406 SPDK_CU_ASSERT_FATAL(g_vol != NULL); 407 SPDK_CU_ASSERT_FATAL(g_path != NULL); 408 memcpy(pmem_file_path, g_path, sizeof(pmem_file_path)); 409 410 g_reduce_errno = -1; 411 spdk_reduce_vol_unload(g_vol, unload_cb, NULL); 412 CU_ASSERT(g_reduce_errno == 0); 413 414 g_vol = NULL; 415 g_path = NULL; 416 g_reduce_errno = -1; 417 spdk_reduce_vol_load(&backing_dev, load_cb, NULL); 418 CU_ASSERT(g_reduce_errno == 0); 419 SPDK_CU_ASSERT_FATAL(g_vol != NULL); 420 SPDK_CU_ASSERT_FATAL(g_path != NULL); 421 CU_ASSERT(strncmp(g_path, pmem_file_path, sizeof(pmem_file_path)) == 0); 422 CU_ASSERT(g_vol->params.vol_size == params.vol_size); 423 CU_ASSERT(g_vol->params.chunk_size == params.chunk_size); 424 CU_ASSERT(g_vol->params.backing_io_unit_size == params.backing_io_unit_size); 425 426 g_reduce_errno = -1; 427 spdk_reduce_vol_unload(g_vol, unload_cb, NULL); 428 CU_ASSERT(g_reduce_errno == 0); 429 430 persistent_pm_buf_destroy(); 431 backing_dev_destroy(&backing_dev); 432 } 433 434 static void 435 load(void) 436 { 437 _load(512); 438 _load(4096); 439 } 440 441 static uint64_t 442 _vol_get_chunk_map_index(struct spdk_reduce_vol *vol, uint64_t offset) 443 { 444 uint64_t logical_map_index = offset / vol->logical_blocks_per_chunk; 445 446 return vol->pm_logical_map[logical_map_index]; 447 } 448 449 static uint64_t * 450 _vol_get_chunk_map(struct spdk_reduce_vol *vol, uint64_t chunk_map_index) 451 { 452 return &vol->pm_chunk_maps[chunk_map_index * vol->backing_io_units_per_chunk]; 453 } 454 455 static void 456 write_cb(void *arg, int reduce_errno) 457 { 458 g_reduce_errno = reduce_errno; 459 } 460 461 static void 462 read_cb(void *arg, int reduce_errno) 463 { 464 g_reduce_errno = reduce_errno; 465 } 466 467 static void 468 _write_maps(uint32_t backing_blocklen) 469 { 470 struct spdk_reduce_vol_params params = {}; 471 struct spdk_reduce_backing_dev backing_dev = {}; 472 struct iovec iov; 473 char buf[16 * 1024]; /* chunk size */ 474 uint32_t i; 475 uint64_t old_chunk0_map_index, new_chunk0_map_index; 476 uint64_t *old_chunk0_map, *new_chunk0_map; 477 478 params.chunk_size = 16 * 1024; 479 params.backing_io_unit_size = 4096; 480 params.logical_block_size = 512; 481 spdk_uuid_generate(¶ms.uuid); 482 483 backing_dev_init(&backing_dev, ¶ms, backing_blocklen); 484 485 g_vol = NULL; 486 g_reduce_errno = -1; 487 spdk_reduce_vol_init(¶ms, &backing_dev, TEST_MD_PATH, init_cb, NULL); 488 CU_ASSERT(g_reduce_errno == 0); 489 SPDK_CU_ASSERT_FATAL(g_vol != NULL); 490 491 for (i = 0; i < g_vol->params.vol_size / g_vol->params.chunk_size; i++) { 492 CU_ASSERT(_vol_get_chunk_map_index(g_vol, i) == REDUCE_EMPTY_MAP_ENTRY); 493 } 494 495 iov.iov_base = buf; 496 iov.iov_len = params.logical_block_size; 497 g_reduce_errno = -1; 498 spdk_reduce_vol_writev(g_vol, &iov, 1, 0, 1, write_cb, NULL); 499 CU_ASSERT(g_reduce_errno == 0); 500 501 old_chunk0_map_index = _vol_get_chunk_map_index(g_vol, 0); 502 CU_ASSERT(old_chunk0_map_index != REDUCE_EMPTY_MAP_ENTRY); 503 CU_ASSERT(spdk_bit_array_get(g_vol->allocated_chunk_maps, old_chunk0_map_index) == true); 504 505 old_chunk0_map = _vol_get_chunk_map(g_vol, old_chunk0_map_index); 506 for (i = 0; i < g_vol->backing_io_units_per_chunk; i++) { 507 CU_ASSERT(old_chunk0_map[i] != REDUCE_EMPTY_MAP_ENTRY); 508 CU_ASSERT(spdk_bit_array_get(g_vol->allocated_backing_io_units, old_chunk0_map[i]) == true); 509 } 510 511 g_reduce_errno = -1; 512 spdk_reduce_vol_writev(g_vol, &iov, 1, 0, 1, write_cb, NULL); 513 CU_ASSERT(g_reduce_errno == 0); 514 515 new_chunk0_map_index = _vol_get_chunk_map_index(g_vol, 0); 516 CU_ASSERT(new_chunk0_map_index != REDUCE_EMPTY_MAP_ENTRY); 517 CU_ASSERT(new_chunk0_map_index != old_chunk0_map_index); 518 CU_ASSERT(spdk_bit_array_get(g_vol->allocated_chunk_maps, new_chunk0_map_index) == true); 519 CU_ASSERT(spdk_bit_array_get(g_vol->allocated_chunk_maps, old_chunk0_map_index) == false); 520 521 for (i = 0; i < g_vol->backing_io_units_per_chunk; i++) { 522 CU_ASSERT(spdk_bit_array_get(g_vol->allocated_backing_io_units, old_chunk0_map[i]) == false); 523 } 524 525 new_chunk0_map = _vol_get_chunk_map(g_vol, new_chunk0_map_index); 526 for (i = 0; i < g_vol->backing_io_units_per_chunk; i++) { 527 CU_ASSERT(new_chunk0_map[i] != REDUCE_EMPTY_MAP_ENTRY); 528 CU_ASSERT(spdk_bit_array_get(g_vol->allocated_backing_io_units, new_chunk0_map[i]) == true); 529 } 530 531 g_reduce_errno = -1; 532 spdk_reduce_vol_unload(g_vol, unload_cb, NULL); 533 CU_ASSERT(g_reduce_errno == 0); 534 535 g_vol = NULL; 536 g_reduce_errno = -1; 537 spdk_reduce_vol_load(&backing_dev, load_cb, NULL); 538 CU_ASSERT(g_reduce_errno == 0); 539 SPDK_CU_ASSERT_FATAL(g_vol != NULL); 540 CU_ASSERT(g_vol->params.vol_size == params.vol_size); 541 CU_ASSERT(g_vol->params.chunk_size == params.chunk_size); 542 CU_ASSERT(g_vol->params.backing_io_unit_size == params.backing_io_unit_size); 543 544 g_reduce_errno = -1; 545 spdk_reduce_vol_unload(g_vol, unload_cb, NULL); 546 CU_ASSERT(g_reduce_errno == 0); 547 548 persistent_pm_buf_destroy(); 549 backing_dev_destroy(&backing_dev); 550 } 551 552 static void 553 write_maps(void) 554 { 555 _write_maps(512); 556 _write_maps(4096); 557 } 558 559 static void 560 _read_write(uint32_t backing_blocklen) 561 { 562 struct spdk_reduce_vol_params params = {}; 563 struct spdk_reduce_backing_dev backing_dev = {}; 564 struct iovec iov; 565 char buf[16 * 1024]; /* chunk size */ 566 char compare_buf[16 * 1024]; 567 uint32_t i; 568 569 params.chunk_size = 16 * 1024; 570 params.backing_io_unit_size = 4096; 571 params.logical_block_size = 512; 572 spdk_uuid_generate(¶ms.uuid); 573 574 backing_dev_init(&backing_dev, ¶ms, backing_blocklen); 575 576 g_vol = NULL; 577 g_reduce_errno = -1; 578 spdk_reduce_vol_init(¶ms, &backing_dev, TEST_MD_PATH, init_cb, NULL); 579 CU_ASSERT(g_reduce_errno == 0); 580 SPDK_CU_ASSERT_FATAL(g_vol != NULL); 581 582 /* Write 0xAA to 2 512-byte logical blocks, starting at LBA 2. */ 583 memset(buf, 0xAA, 2 * params.logical_block_size); 584 iov.iov_base = buf; 585 iov.iov_len = 2 * params.logical_block_size; 586 g_reduce_errno = -1; 587 spdk_reduce_vol_writev(g_vol, &iov, 1, 2, 2, write_cb, NULL); 588 CU_ASSERT(g_reduce_errno == 0); 589 590 memset(compare_buf, 0xAA, sizeof(compare_buf)); 591 for (i = 0; i < params.chunk_size / params.logical_block_size; i++) { 592 memset(buf, 0xFF, params.logical_block_size); 593 iov.iov_base = buf; 594 iov.iov_len = params.logical_block_size; 595 g_reduce_errno = -1; 596 spdk_reduce_vol_readv(g_vol, &iov, 1, i, 1, read_cb, NULL); 597 CU_ASSERT(g_reduce_errno == 0); 598 599 switch (i) { 600 case 2: 601 case 3: 602 CU_ASSERT(memcmp(buf, compare_buf, params.logical_block_size) == 0); 603 break; 604 default: 605 CU_ASSERT(spdk_mem_all_zero(buf, params.logical_block_size)); 606 break; 607 } 608 } 609 610 g_reduce_errno = -1; 611 spdk_reduce_vol_unload(g_vol, unload_cb, NULL); 612 CU_ASSERT(g_reduce_errno == 0); 613 614 g_vol = NULL; 615 g_reduce_errno = -1; 616 spdk_reduce_vol_load(&backing_dev, load_cb, NULL); 617 CU_ASSERT(g_reduce_errno == 0); 618 SPDK_CU_ASSERT_FATAL(g_vol != NULL); 619 CU_ASSERT(g_vol->params.vol_size == params.vol_size); 620 CU_ASSERT(g_vol->params.chunk_size == params.chunk_size); 621 CU_ASSERT(g_vol->params.backing_io_unit_size == params.backing_io_unit_size); 622 623 g_reduce_errno = -1; 624 spdk_reduce_vol_unload(g_vol, unload_cb, NULL); 625 CU_ASSERT(g_reduce_errno == 0); 626 627 persistent_pm_buf_destroy(); 628 backing_dev_destroy(&backing_dev); 629 } 630 631 static void 632 read_write(void) 633 { 634 _read_write(512); 635 _read_write(4096); 636 } 637 638 int 639 main(int argc, char **argv) 640 { 641 CU_pSuite suite = NULL; 642 unsigned int num_failures; 643 644 if (CU_initialize_registry() != CUE_SUCCESS) { 645 return CU_get_error(); 646 } 647 648 suite = CU_add_suite("reduce", NULL, NULL); 649 if (suite == NULL) { 650 CU_cleanup_registry(); 651 return CU_get_error(); 652 } 653 654 if ( 655 CU_add_test(suite, "get_pm_file_size", get_pm_file_size) == NULL || 656 CU_add_test(suite, "get_vol_size", get_vol_size) == NULL || 657 CU_add_test(suite, "init_failure", init_failure) == NULL || 658 CU_add_test(suite, "init_md", init_md) == NULL || 659 CU_add_test(suite, "init_backing_dev", init_backing_dev) == NULL || 660 CU_add_test(suite, "load", load) == NULL || 661 CU_add_test(suite, "write_maps", write_maps) == NULL || 662 CU_add_test(suite, "read_write", read_write) == NULL 663 ) { 664 CU_cleanup_registry(); 665 return CU_get_error(); 666 } 667 668 CU_basic_set_mode(CU_BRM_VERBOSE); 669 CU_basic_run_tests(); 670 num_failures = CU_get_number_of_failures(); 671 CU_cleanup_registry(); 672 return num_failures; 673 } 674