4 * Copyright (C) 2008-2012 Daisuke Aoyama <aoyama@peach.ne.jp>.
5 * Copyright (c) Intel Corporation.
8 * Redistribution and use in source and binary forms, with or without
9 * modification, are permitted provided that the following conditions
12 * * Redistributions of source code must retain the above copyright
13 * notice, this list of conditions and the following disclaimer.
14 * * Redistributions in binary form must reproduce the above copyright
15 * notice, this list of conditions and the following disclaimer in
16 * the documentation and/or other materials provided with the
18 * * Neither the name of Intel Corporation nor the names of its
19 * contributors may be used to endorse or promote products derived
20 * from this software without specific prior written permission.
22 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
23 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
24 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
25 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
26 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
27 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
28 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
29 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
30 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
31 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
32 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
40 #include "spdk/bdev.h"
41 #include "spdk/copy_engine.h"
44 #include "spdk/io_channel.h"
46 #include "CUnit/Basic.h"
48 #define BUFFER_IOVS 1024
49 #define BUFFER_SIZE 260 * 1024
50 #define BDEV_TASK_ARRAY_SIZE 2048
53 #include "../common.c"
55 pthread_mutex_t g_test_mutex
;
56 pthread_cond_t g_test_cond
;
59 struct spdk_bdev
*bdev
;
60 struct spdk_io_channel
*ch
;
61 struct io_target
*next
;
64 struct bdevio_request
{
68 struct iovec iov
[BUFFER_IOVS
];
70 struct io_target
*target
;
73 struct io_target
*g_io_targets
= NULL
;
76 execute_spdk_function(spdk_event_fn fn
, void *arg1
, void *arg2
)
78 struct spdk_event
*event
;
80 event
= spdk_event_allocate(1, fn
, arg1
, arg2
);
81 pthread_mutex_lock(&g_test_mutex
);
82 spdk_event_call(event
);
83 pthread_cond_wait(&g_test_cond
, &g_test_mutex
);
84 pthread_mutex_unlock(&g_test_mutex
);
90 pthread_mutex_lock(&g_test_mutex
);
91 pthread_cond_signal(&g_test_cond
);
92 pthread_mutex_unlock(&g_test_mutex
);
96 __get_io_channel(void *arg1
, void *arg2
)
98 struct io_target
*target
= arg1
;
100 target
->ch
= spdk_bdev_get_io_channel(target
->bdev
, SPDK_IO_PRIORITY_DEFAULT
);
105 bdevio_construct_targets(void)
107 struct spdk_bdev
*bdev
;
108 struct io_target
*target
;
110 printf("I/O targets:\n");
112 bdev
= spdk_bdev_first();
113 while (bdev
!= NULL
) {
115 if (!spdk_bdev_claim(bdev
, NULL
, NULL
)) {
116 bdev
= spdk_bdev_next(bdev
);
120 printf(" %s: %" PRIu64
" blocks of %" PRIu32
" bytes (%" PRIu64
" MiB)\n",
122 bdev
->blockcnt
, bdev
->blocklen
,
123 (bdev
->blockcnt
* bdev
->blocklen
+ 1024 * 1024 - 1) / (1024 * 1024));
125 target
= malloc(sizeof(struct io_target
));
126 if (target
== NULL
) {
130 target
->next
= g_io_targets
;
131 execute_spdk_function(__get_io_channel
, target
, NULL
);
132 g_io_targets
= target
;
134 bdev
= spdk_bdev_next(bdev
);
141 __put_io_channel(void *arg1
, void *arg2
)
143 struct io_target
*target
= arg1
;
145 spdk_put_io_channel(target
->ch
);
150 bdevio_cleanup_targets(void)
152 struct io_target
*target
;
154 target
= g_io_targets
;
155 while (target
!= NULL
) {
156 execute_spdk_function(__put_io_channel
, target
, NULL
);
157 spdk_bdev_unclaim(target
->bdev
);
158 g_io_targets
= target
->next
;
160 target
= g_io_targets
;
164 static enum spdk_bdev_io_status g_completion_status
;
167 initialize_buffer(char **buf
, int pattern
, int size
)
169 *buf
= spdk_zmalloc(size
, 0x1000, NULL
);
170 memset(*buf
, pattern
, size
);
174 quick_test_complete(struct spdk_bdev_io
*bdev_io
, enum spdk_bdev_io_status status
, void *arg
)
176 g_completion_status
= status
;
177 spdk_bdev_free_io(bdev_io
);
182 __blockdev_write(void *arg1
, void *arg2
)
184 struct bdevio_request
*req
= arg1
;
185 struct io_target
*target
= req
->target
;
186 struct spdk_bdev_io
*bdev_io
;
189 bdev_io
= spdk_bdev_writev(target
->bdev
, target
->ch
, req
->iov
, req
->iovcnt
, req
->offset
,
190 req
->data_len
, quick_test_complete
, NULL
);
192 bdev_io
= spdk_bdev_write(target
->bdev
, target
->ch
, req
->buf
, req
->offset
,
193 req
->data_len
, quick_test_complete
, NULL
);
197 g_completion_status
= SPDK_BDEV_IO_STATUS_FAILED
;
203 sgl_chop_buffer(struct bdevio_request
*req
, int iov_len
)
205 int data_len
= req
->data_len
;
206 char *buf
= req
->buf
;
212 for (; data_len
> 0 && req
->iovcnt
< BUFFER_IOVS
; req
->iovcnt
++) {
213 if (data_len
< iov_len
)
216 req
->iov
[req
->iovcnt
].iov_base
= buf
;
217 req
->iov
[req
->iovcnt
].iov_len
= iov_len
;
223 CU_ASSERT_EQUAL_FATAL(data_len
, 0);
227 blockdev_write(struct io_target
*target
, char *tx_buf
,
228 uint64_t offset
, int data_len
, int iov_len
)
230 struct bdevio_request req
;
234 req
.data_len
= data_len
;
236 sgl_chop_buffer(&req
, iov_len
);
238 g_completion_status
= SPDK_BDEV_IO_STATUS_FAILED
;
240 execute_spdk_function(__blockdev_write
, &req
, NULL
);
244 __blockdev_read(void *arg1
, void *arg2
)
246 struct bdevio_request
*req
= arg1
;
247 struct io_target
*target
= req
->target
;
248 struct spdk_bdev_io
*bdev_io
;
251 bdev_io
= spdk_bdev_readv(target
->bdev
, target
->ch
, req
->iov
, req
->iovcnt
, req
->offset
,
252 req
->data_len
, quick_test_complete
, NULL
);
254 bdev_io
= spdk_bdev_read(target
->bdev
, target
->ch
, req
->buf
, req
->offset
,
255 req
->data_len
, quick_test_complete
, NULL
);
259 g_completion_status
= SPDK_BDEV_IO_STATUS_FAILED
;
265 blockdev_read(struct io_target
*target
, char *rx_buf
,
266 uint64_t offset
, int data_len
, int iov_len
)
268 struct bdevio_request req
;
272 req
.data_len
= data_len
;
275 sgl_chop_buffer(&req
, iov_len
);
277 g_completion_status
= SPDK_BDEV_IO_STATUS_FAILED
;
279 execute_spdk_function(__blockdev_read
, &req
, NULL
);
283 blockdev_write_read_data_match(char *rx_buf
, char *tx_buf
, int data_length
)
286 rc
= memcmp(rx_buf
, tx_buf
, data_length
);
295 blockdev_write_read(uint32_t data_length
, uint32_t iov_len
, int pattern
, uint64_t offset
,
298 struct io_target
*target
;
303 target
= g_io_targets
;
304 while (target
!= NULL
) {
305 if (data_length
< target
->bdev
->blocklen
) {
306 target
= target
->next
;
310 initialize_buffer(&tx_buf
, pattern
, data_length
);
311 initialize_buffer(&rx_buf
, 0, data_length
);
313 blockdev_write(target
, tx_buf
, offset
, data_length
, iov_len
);
315 if (expected_rc
== 0) {
316 CU_ASSERT_EQUAL(g_completion_status
, SPDK_BDEV_IO_STATUS_SUCCESS
);
318 CU_ASSERT_EQUAL(g_completion_status
, SPDK_BDEV_IO_STATUS_FAILED
);
321 blockdev_read(target
, rx_buf
, offset
, data_length
, iov_len
);
323 if (expected_rc
== 0) {
324 CU_ASSERT_EQUAL(g_completion_status
, SPDK_BDEV_IO_STATUS_SUCCESS
);
326 CU_ASSERT_EQUAL(g_completion_status
, SPDK_BDEV_IO_STATUS_FAILED
);
329 if (g_completion_status
== SPDK_BDEV_IO_STATUS_SUCCESS
) {
330 rc
= blockdev_write_read_data_match(rx_buf
, tx_buf
, data_length
);
331 /* Assert the write by comparing it with values read
332 * from each blockdev */
333 CU_ASSERT_EQUAL(rc
, 0);
336 target
= target
->next
;
341 blockdev_write_read_4k(void)
343 uint32_t data_length
;
350 CU_ASSERT_TRUE(data_length
< BUFFER_SIZE
);
353 /* Params are valid, hence the expected return value
354 * of write and read for all blockdevs is 0. */
357 blockdev_write_read(data_length
, 0, pattern
, offset
, expected_rc
);
361 blockdev_writev_readv_4k(void)
363 uint32_t data_length
, iov_len
;
371 CU_ASSERT_TRUE(data_length
< BUFFER_SIZE
);
374 /* Params are valid, hence the expected return value
375 * of write and read for all blockdevs is 0. */
378 blockdev_write_read(data_length
, iov_len
, pattern
, offset
, expected_rc
);
382 blockdev_writev_readv_30x4k(void)
384 uint32_t data_length
, iov_len
;
390 data_length
= 4096 * 30;
392 CU_ASSERT_TRUE(data_length
< BUFFER_SIZE
);
395 /* Params are valid, hence the expected return value
396 * of write and read for all blockdevs is 0. */
399 blockdev_write_read(data_length
, iov_len
, pattern
, offset
, expected_rc
);
403 blockdev_write_read_512Bytes(void)
405 uint32_t data_length
;
410 /* Data size = 512 */
412 CU_ASSERT_TRUE(data_length
< BUFFER_SIZE
);
415 /* Params are valid, hence the expected return value
416 * of write and read for all blockdevs is 0. */
419 blockdev_write_read(data_length
, 0, pattern
, offset
, expected_rc
);
423 blockdev_writev_readv_512Bytes(void)
425 uint32_t data_length
, iov_len
;
430 /* Data size = 512 */
433 CU_ASSERT_TRUE(data_length
< BUFFER_SIZE
);
436 /* Params are valid, hence the expected return value
437 * of write and read for all blockdevs is 0. */
440 blockdev_write_read(data_length
, iov_len
, pattern
, offset
, expected_rc
);
444 blockdev_write_read_size_gt_128k(void)
446 uint32_t data_length
;
451 /* Data size = 132K */
452 data_length
= 135168;
453 CU_ASSERT_TRUE(data_length
< BUFFER_SIZE
);
456 /* Params are valid, hence the expected return value
457 * of write and read for all blockdevs is 0. */
460 blockdev_write_read(data_length
, 0, pattern
, offset
, expected_rc
);
464 blockdev_writev_readv_size_gt_128k(void)
466 uint32_t data_length
, iov_len
;
471 /* Data size = 132K */
472 data_length
= 135168;
474 CU_ASSERT_TRUE(data_length
< BUFFER_SIZE
);
477 /* Params are valid, hence the expected return value
478 * of write and read for all blockdevs is 0. */
481 blockdev_write_read(data_length
, iov_len
, pattern
, offset
, expected_rc
);
485 blockdev_writev_readv_size_gt_128k_two_iov(void)
487 uint32_t data_length
, iov_len
;
492 /* Data size = 132K */
493 data_length
= 135168;
494 iov_len
= 128 * 1024;
495 CU_ASSERT_TRUE(data_length
< BUFFER_SIZE
);
498 /* Params are valid, hence the expected return value
499 * of write and read for all blockdevs is 0. */
502 blockdev_write_read(data_length
, iov_len
, pattern
, offset
, expected_rc
);
506 blockdev_write_read_invalid_size(void)
508 uint32_t data_length
;
513 /* Data size is not a multiple of the block size */
514 data_length
= 0x1015;
515 CU_ASSERT_TRUE(data_length
< BUFFER_SIZE
);
518 /* Params are invalid, hence the expected return value
519 * of write and read for all blockdevs is < 0 */
522 blockdev_write_read(data_length
, 0, pattern
, offset
, expected_rc
);
526 blockdev_write_read_offset_plus_nbytes_equals_bdev_size(void)
528 struct io_target
*target
;
529 struct spdk_bdev
*bdev
;
535 target
= g_io_targets
;
536 while (target
!= NULL
) {
539 /* The start offset has been set to a marginal value
540 * such that offset + nbytes == Total size of
542 offset
= ((bdev
->blockcnt
- 1) * bdev
->blocklen
);
544 initialize_buffer(&tx_buf
, 0xA3, bdev
->blocklen
);
545 initialize_buffer(&rx_buf
, 0, bdev
->blocklen
);
547 blockdev_write(target
, tx_buf
, offset
, bdev
->blocklen
, 0);
548 CU_ASSERT_EQUAL(g_completion_status
, SPDK_BDEV_IO_STATUS_SUCCESS
);
550 blockdev_read(target
, rx_buf
, offset
, bdev
->blocklen
, 0);
551 CU_ASSERT_EQUAL(g_completion_status
, SPDK_BDEV_IO_STATUS_SUCCESS
);
553 rc
= blockdev_write_read_data_match(rx_buf
, tx_buf
, bdev
->blocklen
);
554 /* Assert the write by comparing it with values read
555 * from each blockdev */
556 CU_ASSERT_EQUAL(rc
, 0);
558 target
= target
->next
;
563 blockdev_write_read_offset_plus_nbytes_gt_bdev_size(void)
565 struct io_target
*target
;
566 struct spdk_bdev
*bdev
;
573 /* Tests the overflow condition of the blockdevs. */
575 CU_ASSERT_TRUE(data_length
< BUFFER_SIZE
);
578 target
= g_io_targets
;
579 while (target
!= NULL
) {
582 /* The start offset has been set to a valid value
583 * but offset + nbytes is greater than the Total size
584 * of the blockdev. The test should fail. */
585 offset
= ((bdev
->blockcnt
* bdev
->blocklen
) - 1024);
587 initialize_buffer(&tx_buf
, pattern
, data_length
);
588 initialize_buffer(&rx_buf
, 0, data_length
);
590 blockdev_write(target
, tx_buf
, offset
, data_length
, 0);
591 CU_ASSERT_EQUAL(g_completion_status
, SPDK_BDEV_IO_STATUS_FAILED
);
593 blockdev_read(target
, rx_buf
, offset
, data_length
, 0);
594 CU_ASSERT_EQUAL(g_completion_status
, SPDK_BDEV_IO_STATUS_FAILED
);
596 target
= target
->next
;
601 blockdev_write_read_max_offset(void)
609 CU_ASSERT_TRUE(data_length
< BUFFER_SIZE
);
610 /* The start offset has been set to UINT64_MAX such that
611 * adding nbytes wraps around and points to an invalid address. */
614 /* Params are invalid, hence the expected return value
615 * of write and read for all blockdevs is < 0 */
618 blockdev_write_read(data_length
, 0, pattern
, offset
, expected_rc
);
622 blockdev_overlapped_write_read_8k(void)
631 CU_ASSERT_TRUE(data_length
< BUFFER_SIZE
);
634 /* Params are valid, hence the expected return value
635 * of write and read for all blockdevs is 0. */
637 /* Assert the write by comparing it with values read
638 * from the same offset for each blockdev */
639 blockdev_write_read(data_length
, 0, pattern
, offset
, expected_rc
);
641 /* Overwrite the pattern 0xbb of size 8K on an address offset overlapping
642 * with the address written above and assert the new value in
643 * the overlapped address range */
644 /* Populate 8k with value 0xBB */
646 /* Offset = 6144; Overlap offset addresses and write value 0xbb */
648 /* Assert the write by comparing it with values read
649 * from the overlapped offset for each blockdev */
650 blockdev_write_read(data_length
, 0, pattern
, offset
, expected_rc
);
654 __blockdev_reset(void *arg1
, void *arg2
)
656 struct bdevio_request
*req
= arg1
;
657 enum spdk_bdev_reset_type
*reset_type
= arg2
;
658 struct io_target
*target
= req
->target
;
661 rc
= spdk_bdev_reset(target
->bdev
, *reset_type
, quick_test_complete
, NULL
);
663 g_completion_status
= SPDK_BDEV_IO_STATUS_FAILED
;
669 blockdev_reset(struct io_target
*target
, enum spdk_bdev_reset_type reset_type
)
671 struct bdevio_request req
;
675 g_completion_status
= SPDK_BDEV_IO_STATUS_FAILED
;
677 execute_spdk_function(__blockdev_reset
, &req
, &reset_type
);
681 blockdev_test_reset(void)
683 struct io_target
*target
;
685 target
= g_io_targets
;
686 while (target
!= NULL
) {
687 target
->bdev
->gencnt
= 0;
688 blockdev_reset(target
, SPDK_BDEV_RESET_HARD
);
689 CU_ASSERT_EQUAL(g_completion_status
, SPDK_BDEV_IO_STATUS_SUCCESS
);
690 CU_ASSERT_EQUAL(target
->bdev
->gencnt
, 1);
692 target
->bdev
->gencnt
= 0;
693 blockdev_reset(target
, SPDK_BDEV_RESET_SOFT
);
694 CU_ASSERT_EQUAL(g_completion_status
, SPDK_BDEV_IO_STATUS_SUCCESS
);
695 CU_ASSERT_EQUAL(target
->bdev
->gencnt
, 0);
697 target
= target
->next
;
702 test_main(void *arg1
, void *arg2
)
704 CU_pSuite suite
= NULL
;
705 unsigned int num_failures
;
707 pthread_mutex_init(&g_test_mutex
, NULL
);
708 pthread_cond_init(&g_test_cond
, NULL
);
710 if (bdevio_construct_targets() < 0) {
715 if (CU_initialize_registry() != CUE_SUCCESS
) {
716 spdk_app_stop(CU_get_error());
720 suite
= CU_add_suite("components_suite", NULL
, NULL
);
722 CU_cleanup_registry();
723 spdk_app_stop(CU_get_error());
728 CU_add_test(suite
, "blockdev write read 4k", blockdev_write_read_4k
) == NULL
729 || CU_add_test(suite
, "blockdev write read 512 bytes",
730 blockdev_write_read_512Bytes
) == NULL
731 || CU_add_test(suite
, "blockdev write read size > 128k",
732 blockdev_write_read_size_gt_128k
) == NULL
733 || CU_add_test(suite
, "blockdev write read invalid size",
734 blockdev_write_read_invalid_size
) == NULL
735 || CU_add_test(suite
, "blockdev write read offset + nbytes == size of blockdev",
736 blockdev_write_read_offset_plus_nbytes_equals_bdev_size
) == NULL
737 || CU_add_test(suite
, "blockdev write read offset + nbytes > size of blockdev",
738 blockdev_write_read_offset_plus_nbytes_gt_bdev_size
) == NULL
739 || CU_add_test(suite
, "blockdev write read max offset",
740 blockdev_write_read_max_offset
) == NULL
741 || CU_add_test(suite
, "blockdev write read 8k on overlapped address offset",
742 blockdev_overlapped_write_read_8k
) == NULL
743 || CU_add_test(suite
, "blockdev writev readv 4k", blockdev_writev_readv_4k
) == NULL
744 || CU_add_test(suite
, "blockdev writev readv 30 x 4k",
745 blockdev_writev_readv_30x4k
) == NULL
746 || CU_add_test(suite
, "blockdev writev readv 512 bytes",
747 blockdev_writev_readv_512Bytes
) == NULL
748 || CU_add_test(suite
, "blockdev writev readv size > 128k",
749 blockdev_writev_readv_size_gt_128k
) == NULL
750 || CU_add_test(suite
, "blockdev writev readv size > 128k in two iovs",
751 blockdev_writev_readv_size_gt_128k_two_iov
) == NULL
752 || CU_add_test(suite
, "blockdev reset",
753 blockdev_test_reset
) == NULL
755 CU_cleanup_registry();
756 spdk_app_stop(CU_get_error());
760 CU_basic_set_mode(CU_BRM_VERBOSE
);
761 CU_basic_run_tests();
762 num_failures
= CU_get_number_of_failures();
763 CU_cleanup_registry();
764 bdevio_cleanup_targets();
765 spdk_app_stop(num_failures
);
769 main(int argc
, char **argv
)
771 const char *config_file
;
775 config_file
= "/usr/local/etc/spdk/iscsi.conf";
777 config_file
= argv
[1];
779 bdevtest_init(config_file
, "0x3");
781 num_failures
= spdk_app_start(test_main
, NULL
, NULL
);