]> git.proxmox.com Git - ceph.git/blob - ceph/src/spdk/test/unit/lib/bdev/pmem/bdev_pmem_ut.c
update source to Ceph Pacific 16.2.2
[ceph.git] / ceph / src / spdk / test / unit / lib / bdev / pmem / bdev_pmem_ut.c
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_cunit.h"
35
36 #include "common/lib/ut_multithread.c"
37 #include "unit/lib/json_mock.c"
38
39 #include "spdk_internal/thread.h"
40
41 #include "bdev/pmem/bdev_pmem.c"
42
43 DEFINE_STUB(spdk_conf_find_section, struct spdk_conf_section *,
44 (struct spdk_conf *cp, const char *name), NULL);
45 DEFINE_STUB(spdk_conf_section_get_nval, char *,
46 (struct spdk_conf_section *sp, const char *key, int idx), NULL);
47 DEFINE_STUB(spdk_conf_section_get_nmval, char *,
48 (struct spdk_conf_section *sp, const char *key, int idx1, int idx2), NULL);
49
50 static struct spdk_bdev_module *g_bdev_pmem_module;
51 static int g_bdev_module_cnt;
52
53 struct pmemblk {
54 const char *name;
55 bool is_open;
56 bool is_consistent;
57 size_t bsize;
58 long long nblock;
59
60 uint8_t *buffer;
61 };
62
63 static const char *g_bdev_name = "pmem0";
64
65 /* PMEMblkpool is a typedef of struct pmemblk */
66 static PMEMblkpool g_pool_ok = {
67 .name = "/pools/ok_pool",
68 .is_open = false,
69 .is_consistent = true,
70 .bsize = 4096,
71 .nblock = 150
72 };
73
74 static PMEMblkpool g_pool_nblock_0 = {
75 .name = "/pools/nblock_0",
76 .is_open = false,
77 .is_consistent = true,
78 .bsize = 4096,
79 .nblock = 0
80 };
81
82 static PMEMblkpool g_pool_bsize_0 = {
83 .name = "/pools/nblock_0",
84 .is_open = false,
85 .is_consistent = true,
86 .bsize = 0,
87 .nblock = 100
88 };
89
90 static PMEMblkpool g_pool_inconsistent = {
91 .name = "/pools/inconsistent",
92 .is_open = false,
93 .is_consistent = false,
94 .bsize = 512,
95 .nblock = 1
96 };
97
98 static int g_opened_pools;
99 static struct spdk_bdev *g_bdev;
100 static const char *g_check_version_msg;
101 static bool g_pmemblk_open_allow_open = true;
102
103 static PMEMblkpool *
104 find_pmemblk_pool(const char *path)
105 {
106 if (path == NULL) {
107 errno = EINVAL;
108 return NULL;
109 } else if (strcmp(g_pool_ok.name, path) == 0) {
110 return &g_pool_ok;
111 } else if (strcmp(g_pool_nblock_0.name, path) == 0) {
112 return &g_pool_nblock_0;
113 } else if (strcmp(g_pool_bsize_0.name, path) == 0) {
114 return &g_pool_bsize_0;
115 } else if (strcmp(g_pool_inconsistent.name, path) == 0) {
116 return &g_pool_inconsistent;
117 }
118
119 errno = ENOENT;
120 return NULL;
121 }
122
123 PMEMblkpool *
124 pmemblk_open(const char *path, size_t bsize)
125 {
126 PMEMblkpool *pool;
127
128 if (!g_pmemblk_open_allow_open) {
129 errno = EIO;
130 return NULL;
131 }
132
133 pool = find_pmemblk_pool(path);
134 if (!pool) {
135 errno = ENOENT;
136 return NULL;
137 }
138
139 CU_ASSERT_TRUE_FATAL(pool->is_consistent);
140 CU_ASSERT_FALSE(pool->is_open);
141 if (pool->is_open == false) {
142 pool->is_open = true;
143 g_opened_pools++;
144 } else {
145 errno = EBUSY;
146 pool = NULL;
147 }
148
149 return pool;
150 }
151 void
152 spdk_bdev_io_get_buf(struct spdk_bdev_io *bdev_io, spdk_bdev_io_get_buf_cb cb, uint64_t len)
153 {
154 cb(NULL, bdev_io, true);
155 }
156
157 static void
158 check_open_pool_fatal(PMEMblkpool *pool)
159 {
160 SPDK_CU_ASSERT_FATAL(pool != NULL);
161 SPDK_CU_ASSERT_FATAL(find_pmemblk_pool(pool->name) == pool);
162 SPDK_CU_ASSERT_FATAL(pool->is_open == true);
163 }
164
165 void
166 pmemblk_close(PMEMblkpool *pool)
167 {
168 check_open_pool_fatal(pool);
169 pool->is_open = false;
170 CU_ASSERT(g_opened_pools > 0);
171 g_opened_pools--;
172 }
173
174 size_t
175 pmemblk_bsize(PMEMblkpool *pool)
176 {
177 check_open_pool_fatal(pool);
178 return pool->bsize;
179 }
180
181 size_t
182 pmemblk_nblock(PMEMblkpool *pool)
183 {
184 check_open_pool_fatal(pool);
185 return pool->nblock;
186 }
187
188 int
189 pmemblk_read(PMEMblkpool *pool, void *buf, long long blockno)
190 {
191 check_open_pool_fatal(pool);
192 if (blockno >= pool->nblock) {
193 errno = EINVAL;
194 return -1;
195 }
196
197 memcpy(buf, &pool->buffer[blockno * pool->bsize], pool->bsize);
198 return 0;
199 }
200
201 int
202 pmemblk_write(PMEMblkpool *pool, const void *buf, long long blockno)
203 {
204 check_open_pool_fatal(pool);
205 if (blockno >= pool->nblock) {
206 errno = EINVAL;
207 return -1;
208 }
209
210 memcpy(&pool->buffer[blockno * pool->bsize], buf, pool->bsize);
211 return 0;
212 }
213
214 int
215 pmemblk_set_zero(PMEMblkpool *pool, long long blockno)
216 {
217 check_open_pool_fatal(pool);
218 if (blockno >= pool->nblock) {
219
220 errno = EINVAL;
221 return -1;
222 }
223
224 memset(&pool->buffer[blockno * pool->bsize], 0, pool->bsize);
225 return 0;
226 }
227
228 const char *
229 pmemblk_errormsg(void)
230 {
231 return strerror(errno);
232 }
233
234 const char *
235 pmemblk_check_version(unsigned major_required, unsigned minor_required)
236 {
237 return g_check_version_msg;
238 }
239
240 int
241 pmemblk_check(const char *path, size_t bsize)
242 {
243 PMEMblkpool *pool = find_pmemblk_pool(path);
244
245 if (!pool) {
246 errno = ENOENT;
247 return -1;
248 }
249
250 if (!pool->is_consistent) {
251 /* errno ? */
252 return 0;
253 }
254
255 if (bsize != 0 && pool->bsize != bsize) {
256 /* errno ? */
257 return 0;
258 }
259
260 return 1;
261 }
262
263 void
264 spdk_bdev_io_complete(struct spdk_bdev_io *bdev_io, enum spdk_bdev_io_status status)
265 {
266 bdev_io->internal.status = status;
267 }
268
269 int
270 spdk_bdev_register(struct spdk_bdev *bdev)
271 {
272 CU_ASSERT_PTR_NULL(g_bdev);
273 g_bdev = bdev;
274
275 return 0;
276 }
277
278 void
279 spdk_bdev_unregister(struct spdk_bdev *bdev, spdk_bdev_unregister_cb cb_fn, void *cb_arg)
280 {
281 }
282
283 void
284 spdk_bdev_module_finish_done(void)
285 {
286 }
287
288 int
289 spdk_bdev_notify_blockcnt_change(struct spdk_bdev *bdev, uint64_t size)
290 {
291 bdev->blockcnt = size;
292 return 0;
293 }
294
295 static void
296 ut_bdev_pmem_destruct(struct spdk_bdev *bdev)
297 {
298 SPDK_CU_ASSERT_FATAL(g_bdev != NULL);
299 CU_ASSERT_EQUAL(bdev_pmem_destruct(bdev->ctxt), 0);
300 g_bdev = NULL;
301 }
302
303 void
304 spdk_bdev_module_list_add(struct spdk_bdev_module *bdev_module)
305 {
306 g_bdev_pmem_module = bdev_module;
307 g_bdev_module_cnt++;
308 }
309
310 static int
311 bdev_submit_request(struct spdk_bdev *bdev, int16_t io_type, uint64_t offset_blocks,
312 uint64_t num_blocks, struct iovec *iovs, size_t iov_cnt)
313 {
314 struct spdk_bdev_io bio = { 0 };
315
316 switch (io_type) {
317 case SPDK_BDEV_IO_TYPE_READ:
318 bio.u.bdev.iovs = iovs;
319 bio.u.bdev.iovcnt = iov_cnt;
320 bio.u.bdev.offset_blocks = offset_blocks;
321 bio.u.bdev.num_blocks = num_blocks;
322 break;
323 case SPDK_BDEV_IO_TYPE_WRITE:
324 bio.u.bdev.iovs = iovs;
325 bio.u.bdev.iovcnt = iov_cnt;
326 bio.u.bdev.offset_blocks = offset_blocks;
327 bio.u.bdev.num_blocks = num_blocks;
328 break;
329 case SPDK_BDEV_IO_TYPE_FLUSH:
330 bio.u.bdev.offset_blocks = offset_blocks;
331 bio.u.bdev.num_blocks = num_blocks;
332 break;
333 case SPDK_BDEV_IO_TYPE_RESET:
334 break;
335 case SPDK_BDEV_IO_TYPE_UNMAP:
336 bio.u.bdev.offset_blocks = offset_blocks;
337 bio.u.bdev.num_blocks = num_blocks;
338 break;
339 case SPDK_BDEV_IO_TYPE_WRITE_ZEROES:
340 bio.u.bdev.offset_blocks = offset_blocks;
341 bio.u.bdev.num_blocks = num_blocks;
342 break;
343 default:
344 CU_FAIL_FATAL("BUG:Unexpected IO type");
345 break;
346 }
347
348 /*
349 * Set status to value that shouldn't be returned
350 */
351 bio.type = io_type;
352 bio.internal.status = SPDK_BDEV_IO_STATUS_PENDING;
353 bio.bdev = bdev;
354 bdev_pmem_submit_request(NULL, &bio);
355 return bio.internal.status;
356 }
357
358
359 static int
360 ut_pmem_blk_clean(void)
361 {
362 free(g_pool_ok.buffer);
363 g_pool_ok.buffer = NULL;
364
365 /* Unload module to free IO channel */
366 g_bdev_pmem_module->module_fini();
367 poll_threads();
368
369 free_threads();
370
371 return 0;
372 }
373
374 static int
375 ut_pmem_blk_init(void)
376 {
377 errno = 0;
378
379 allocate_threads(1);
380 set_thread(0);
381
382 g_pool_ok.buffer = calloc(g_pool_ok.nblock, g_pool_ok.bsize);
383 if (g_pool_ok.buffer == NULL) {
384 ut_pmem_blk_clean();
385 return -1;
386 }
387
388 return 0;
389 }
390
391 static void
392 ut_pmem_init(void)
393 {
394 SPDK_CU_ASSERT_FATAL(g_bdev_pmem_module != NULL);
395 CU_ASSERT_EQUAL(g_bdev_module_cnt, 1);
396
397 /* Make pmemblk_check_version fail with provided error message */
398 g_check_version_msg = "TEST FAIL MESSAGE";
399 CU_ASSERT_NOT_EQUAL(g_bdev_pmem_module->module_init(), 0);
400
401 /* This init must success */
402 g_check_version_msg = NULL;
403 CU_ASSERT_EQUAL(g_bdev_pmem_module->module_init(), 0);
404 }
405
406 static void
407 ut_pmem_open_close(void)
408 {
409 struct spdk_bdev *bdev = NULL;
410 int pools_cnt;
411 int rc;
412
413 pools_cnt = g_opened_pools;
414
415 /* Try opening with NULL name */
416 rc = create_pmem_disk(NULL, NULL, &bdev);
417 CU_ASSERT_PTR_NULL(bdev);
418 CU_ASSERT_EQUAL(pools_cnt, g_opened_pools);
419 CU_ASSERT_NOT_EQUAL(rc, 0);
420
421 /* Open non-existent pool */
422 rc = create_pmem_disk("non existent pool", NULL, &bdev);
423 CU_ASSERT_PTR_NULL(bdev);
424 CU_ASSERT_EQUAL(pools_cnt, g_opened_pools);
425 CU_ASSERT_NOT_EQUAL(rc, 0);
426
427 /* Open inconsistent pool */
428 rc = create_pmem_disk(g_pool_inconsistent.name, NULL, &bdev);
429 CU_ASSERT_PTR_NULL(bdev);
430 CU_ASSERT_EQUAL(pools_cnt, g_opened_pools);
431 CU_ASSERT_NOT_EQUAL(rc, 0);
432
433 /* Open consistent pool fail the open from unknown reason. */
434 g_pmemblk_open_allow_open = false;
435 rc = create_pmem_disk(g_pool_inconsistent.name, NULL, &bdev);
436 g_pmemblk_open_allow_open = true;
437 CU_ASSERT_PTR_NULL(bdev);
438 CU_ASSERT_EQUAL(pools_cnt, g_opened_pools);
439 CU_ASSERT_NOT_EQUAL(rc, 0);
440
441 /* Open pool with nblocks = 0 */
442 rc = create_pmem_disk(g_pool_nblock_0.name, NULL, &bdev);
443 CU_ASSERT_PTR_NULL(bdev);
444 CU_ASSERT_EQUAL(pools_cnt, g_opened_pools);
445 CU_ASSERT_NOT_EQUAL(rc, 0);
446
447 /* Open pool with bsize = 0 */
448 rc = create_pmem_disk(g_pool_bsize_0.name, NULL, &bdev);
449 CU_ASSERT_PTR_NULL(bdev);
450 CU_ASSERT_EQUAL(pools_cnt, g_opened_pools);
451 CU_ASSERT_NOT_EQUAL(rc, 0);
452
453 /* Open pool with NULL name */
454 rc = create_pmem_disk(g_pool_ok.name, NULL, &bdev);
455 CU_ASSERT_PTR_NULL(bdev);
456 CU_ASSERT_EQUAL(pools_cnt, g_opened_pools);
457 CU_ASSERT_NOT_EQUAL(rc, 0);
458
459 /* Open good pool */
460 rc = create_pmem_disk(g_pool_ok.name, g_bdev_name, &bdev);
461 SPDK_CU_ASSERT_FATAL(bdev != NULL);
462 CU_ASSERT_TRUE(g_pool_ok.is_open);
463 CU_ASSERT_EQUAL(pools_cnt + 1, g_opened_pools);
464 CU_ASSERT_EQUAL(rc, 0);
465
466 /* Now remove this bdev */
467 ut_bdev_pmem_destruct(bdev);
468 CU_ASSERT_FALSE(g_pool_ok.is_open);
469 CU_ASSERT_EQUAL(pools_cnt, g_opened_pools);
470 }
471
472 static void
473 ut_pmem_write_read(void)
474 {
475 uint8_t *write_buf, *read_buf;
476 struct spdk_bdev *bdev;
477 int rc;
478 size_t unaligned_aligned_size = 100;
479 size_t buf_size = g_pool_ok.bsize * g_pool_ok.nblock;
480 size_t i;
481 const uint64_t nblock_offset = 10;
482 uint64_t offset;
483 size_t io_size, nblock, total_io_size, bsize;
484
485 bsize = 4096;
486 struct iovec iov[] = {
487 { 0, 2 * bsize },
488 { 0, 3 * bsize },
489 { 0, 4 * bsize },
490 };
491
492 rc = create_pmem_disk(g_pool_ok.name, g_bdev_name, &bdev);
493 CU_ASSERT_EQUAL(rc, 0);
494
495 SPDK_CU_ASSERT_FATAL(g_pool_ok.nblock > 40);
496
497 write_buf = calloc(1, buf_size);
498 read_buf = calloc(1, buf_size);
499
500 SPDK_CU_ASSERT_FATAL(bdev != NULL);
501 SPDK_CU_ASSERT_FATAL(write_buf != NULL);
502 SPDK_CU_ASSERT_FATAL(read_buf != NULL);
503
504 total_io_size = 0;
505 offset = nblock_offset * g_pool_ok.bsize;
506 for (i = 0; i < 3; i++) {
507 iov[i].iov_base = &write_buf[offset + total_io_size];
508 total_io_size += iov[i].iov_len;
509 }
510
511 for (i = 0; i < total_io_size + unaligned_aligned_size; i++) {
512 write_buf[offset + i] = 0x42 + i;
513 }
514
515 SPDK_CU_ASSERT_FATAL(total_io_size < buf_size);
516
517 /*
518 * Write outside pool.
519 */
520 rc = bdev_submit_request(bdev, SPDK_BDEV_IO_TYPE_WRITE, g_pool_ok.nblock, 1, &iov[0], 2);
521 CU_ASSERT_EQUAL(rc, SPDK_BDEV_IO_STATUS_FAILED);
522
523 /*
524 * Write with insufficient IOV buffers length.
525 */
526 rc = bdev_submit_request(bdev, SPDK_BDEV_IO_TYPE_WRITE, 0, g_pool_ok.nblock, &iov[0], 2);
527 CU_ASSERT_EQUAL(rc, SPDK_BDEV_IO_STATUS_FAILED);
528
529 /*
530 * Try to write two IOV with first one iov_len % bsize != 0.
531 */
532 io_size = iov[0].iov_len + iov[1].iov_len;
533 nblock = io_size / g_pool_ok.bsize;
534 iov[0].iov_len += unaligned_aligned_size;
535 rc = bdev_submit_request(bdev, SPDK_BDEV_IO_TYPE_WRITE, 0, nblock, &iov[0], 2);
536 CU_ASSERT_EQUAL(rc, SPDK_BDEV_IO_STATUS_FAILED);
537 iov[0].iov_len -= unaligned_aligned_size;
538
539 /*
540 * Try to write one IOV.
541 */
542 nblock = iov[0].iov_len / g_pool_ok.bsize;
543 rc = bdev_submit_request(bdev, SPDK_BDEV_IO_TYPE_WRITE, nblock_offset, nblock, &iov[0], 1);
544 CU_ASSERT_EQUAL(rc, SPDK_BDEV_IO_STATUS_SUCCESS);
545
546 /*
547 * Try to write 2 IOV.
548 * Sum of IOV length is larger than IO size and last IOV is larger and iov_len % bsize != 0
549 */
550 offset = iov[0].iov_len / g_pool_ok.bsize;
551 io_size = iov[1].iov_len + iov[2].iov_len;
552 nblock = io_size / g_pool_ok.bsize;
553 iov[2].iov_len += unaligned_aligned_size;
554 rc = bdev_submit_request(bdev, SPDK_BDEV_IO_TYPE_WRITE, nblock_offset + offset, nblock,
555 &iov[1], 2);
556 CU_ASSERT_EQUAL(rc, SPDK_BDEV_IO_STATUS_SUCCESS);
557 iov[2].iov_len -= unaligned_aligned_size;
558
559 /*
560 * Examine pool state:
561 * 1. Written area should have expected values.
562 * 2. Anything else should contain zeros.
563 */
564 offset = nblock_offset * g_pool_ok.bsize + total_io_size;
565 rc = memcmp(&g_pool_ok.buffer[0], write_buf, offset);
566 CU_ASSERT_EQUAL(rc, 0);
567
568 for (i = offset; i < buf_size; i++) {
569 if (g_pool_ok.buffer[i] != 0) {
570 CU_ASSERT_EQUAL(g_pool_ok.buffer[i], 0);
571 break;
572 }
573 }
574
575 /* Setup IOV for reads */
576 memset(read_buf, 0xAB, buf_size);
577 offset = nblock_offset * g_pool_ok.bsize;
578 for (i = 0; i < 3; i++) {
579 iov[i].iov_base = &read_buf[offset];
580 offset += iov[i].iov_len;
581 }
582
583 /*
584 * Write outside pool.
585 */
586 rc = bdev_submit_request(bdev, SPDK_BDEV_IO_TYPE_READ, g_pool_ok.nblock, 1, &iov[0], 2);
587 CU_ASSERT_EQUAL(rc, SPDK_BDEV_IO_STATUS_FAILED);
588
589 /*
590 * Read with insufficient IOV buffers length.
591 */
592 rc = bdev_submit_request(bdev, SPDK_BDEV_IO_TYPE_READ, 0, g_pool_ok.nblock, &iov[0], 2);
593 CU_ASSERT_EQUAL(rc, SPDK_BDEV_IO_STATUS_FAILED);
594
595 /*
596 * Try to read two IOV with first one iov_len % bsize != 0.
597 */
598 io_size = iov[0].iov_len + iov[1].iov_len;
599 nblock = io_size / g_pool_ok.bsize;
600 iov[0].iov_len += unaligned_aligned_size;
601 rc = bdev_submit_request(bdev, SPDK_BDEV_IO_TYPE_READ, 0, nblock, &iov[0], 2);
602 CU_ASSERT_EQUAL(rc, SPDK_BDEV_IO_STATUS_FAILED);
603 iov[0].iov_len -= unaligned_aligned_size;
604
605 /*
606 * Try to write one IOV.
607 */
608 nblock = iov[0].iov_len / g_pool_ok.bsize;
609 rc = bdev_submit_request(bdev, SPDK_BDEV_IO_TYPE_READ, nblock_offset, nblock, &iov[0], 1);
610 CU_ASSERT_EQUAL(rc, SPDK_BDEV_IO_STATUS_SUCCESS);
611
612 /*
613 * Try to read 2 IOV.
614 * Sum of IOV length is larger than IO size and last IOV is larger and iov_len % bsize != 0
615 */
616 offset = iov[0].iov_len / g_pool_ok.bsize;
617 io_size = iov[1].iov_len + iov[2].iov_len;
618 nblock = io_size / g_pool_ok.bsize;
619 iov[2].iov_len += unaligned_aligned_size;
620 rc = bdev_submit_request(bdev, SPDK_BDEV_IO_TYPE_READ, nblock_offset + offset, nblock,
621 &iov[1], 2);
622 CU_ASSERT_EQUAL(rc, SPDK_BDEV_IO_STATUS_SUCCESS);
623 iov[2].iov_len -= unaligned_aligned_size;
624
625
626 /*
627 * Examine what we read state:
628 * 1. Written area should have expected values.
629 * 2. Anything else should contain zeros.
630 */
631 offset = nblock_offset * g_pool_ok.bsize;
632 for (i = 0; i < offset; i++) {
633 if (read_buf[i] != 0xAB) {
634 CU_ASSERT_EQUAL(read_buf[i], 0xAB);
635 break;
636 }
637 }
638
639 rc = memcmp(&read_buf[offset], &write_buf[offset], total_io_size);
640 CU_ASSERT_EQUAL(rc, 0);
641
642 offset += total_io_size;
643 for (i = offset; i < buf_size; i++) {
644 if (read_buf[i] != 0xAB) {
645 CU_ASSERT_EQUAL(read_buf[i], 0xAB);
646 break;
647 }
648 }
649
650 memset(g_pool_ok.buffer, 0, g_pool_ok.bsize * g_pool_ok.nblock);
651 free(write_buf);
652 free(read_buf);
653
654 /* Now remove this bdev */
655 ut_bdev_pmem_destruct(bdev);
656 CU_ASSERT_FALSE(g_pool_ok.is_open);
657 CU_ASSERT_EQUAL(g_opened_pools, 0);
658 }
659
660 static void
661 ut_pmem_reset(void)
662 {
663 struct spdk_bdev *bdev;
664 int rc;
665
666 rc = create_pmem_disk(g_pool_ok.name, g_bdev_name, &bdev);
667 CU_ASSERT_EQUAL(rc, 0);
668 SPDK_CU_ASSERT_FATAL(bdev != NULL);
669
670 rc = bdev_submit_request(bdev, SPDK_BDEV_IO_TYPE_RESET, 0, 0, NULL, 0);
671 CU_ASSERT_EQUAL(rc, SPDK_BDEV_IO_STATUS_SUCCESS);
672
673 ut_bdev_pmem_destruct(bdev);
674 }
675
676 static void
677 ut_pmem_unmap_write_zero(int16_t io_type)
678 {
679 struct spdk_bdev *bdev;
680 size_t buff_size = g_pool_ok.nblock * g_pool_ok.bsize;
681 size_t i;
682 uint8_t *buffer;
683 int rc;
684
685 CU_ASSERT(io_type == SPDK_BDEV_IO_TYPE_UNMAP || io_type == SPDK_BDEV_IO_TYPE_WRITE_ZEROES);
686 rc = create_pmem_disk(g_pool_ok.name, g_bdev_name, &bdev);
687 CU_ASSERT_EQUAL(rc, 0);
688 SPDK_CU_ASSERT_FATAL(bdev != NULL);
689 SPDK_CU_ASSERT_FATAL(g_pool_ok.nblock > 40);
690
691 buffer = calloc(1, buff_size);
692 SPDK_CU_ASSERT_FATAL(buffer != NULL);
693
694 for (i = 10 * g_pool_ok.bsize; i < 30 * g_pool_ok.bsize; i++) {
695 buffer[i] = 0x30 + io_type + i;
696 }
697 memcpy(g_pool_ok.buffer, buffer, buff_size);
698
699 /*
700 * Block outside of pool.
701 */
702 rc = bdev_submit_request(bdev, io_type, g_pool_ok.nblock, 1, NULL, 0);
703 CU_ASSERT_EQUAL(rc, SPDK_BDEV_IO_STATUS_FAILED);
704
705 rc = memcmp(buffer, g_pool_ok.buffer, buff_size);
706 CU_ASSERT_EQUAL(rc, 0);
707
708 /*
709 * Blocks 15 to 25
710 */
711 memset(&buffer[15 * g_pool_ok.bsize], 0, 10 * g_pool_ok.bsize);
712 rc = bdev_submit_request(bdev, io_type, 15, 10, NULL, 0);
713 CU_ASSERT_EQUAL(rc, SPDK_BDEV_IO_STATUS_SUCCESS);
714
715 rc = memcmp(buffer, g_pool_ok.buffer, buff_size);
716 CU_ASSERT_EQUAL(rc, 0);
717
718 /*
719 * All blocks.
720 */
721 memset(buffer, 0, buff_size);
722 rc = bdev_submit_request(bdev, io_type, 0, g_pool_ok.nblock, NULL, 0);
723 CU_ASSERT_EQUAL(rc, SPDK_BDEV_IO_STATUS_SUCCESS);
724
725 rc = memcmp(buffer, g_pool_ok.buffer, buff_size);
726 CU_ASSERT_EQUAL(rc, 0);
727
728 /* Now remove this bdev */
729 ut_bdev_pmem_destruct(bdev);
730 CU_ASSERT_FALSE(g_pool_ok.is_open);
731 CU_ASSERT_EQUAL(g_opened_pools, 0);
732
733 free(buffer);
734 }
735
736 static void
737 ut_pmem_write_zero(void)
738 {
739 ut_pmem_unmap_write_zero(SPDK_BDEV_IO_TYPE_WRITE_ZEROES);
740 }
741
742 static void
743 ut_pmem_unmap(void)
744 {
745 ut_pmem_unmap_write_zero(SPDK_BDEV_IO_TYPE_UNMAP);
746 }
747
748 int
749 main(int argc, char **argv)
750 {
751 CU_pSuite suite = NULL;
752 unsigned int num_failures;
753
754 CU_set_error_action(CUEA_ABORT);
755 CU_initialize_registry();
756
757 suite = CU_add_suite("bdev_pmem", ut_pmem_blk_init, ut_pmem_blk_clean);
758
759 CU_ADD_TEST(suite, ut_pmem_init);
760 CU_ADD_TEST(suite, ut_pmem_open_close);
761 CU_ADD_TEST(suite, ut_pmem_write_read);
762 CU_ADD_TEST(suite, ut_pmem_reset);
763 CU_ADD_TEST(suite, ut_pmem_write_zero);
764 CU_ADD_TEST(suite, ut_pmem_unmap);
765
766 CU_basic_set_mode(CU_BRM_VERBOSE);
767 CU_basic_run_tests();
768 num_failures = CU_get_number_of_failures();
769 CU_cleanup_registry();
770
771 return num_failures;
772 }