xref: /spdk/test/bdev/bdevio/bdevio.c (revision 95e4ddce51963d7ff832a644e36e1c932d7b50b5)
1 /*   SPDX-License-Identifier: BSD-3-Clause
2  *   Copyright (c) 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/bdev.h"
10 #include "spdk/accel.h"
11 #include "spdk/env.h"
12 #include "spdk/log.h"
13 #include "spdk/thread.h"
14 #include "spdk/event.h"
15 #include "spdk/rpc.h"
16 #include "spdk/util.h"
17 #include "spdk/string.h"
18 
19 #include "bdev_internal.h"
20 #include "CUnit/Basic.h"
21 
22 #define BUFFER_IOVS		1024
23 #define BUFFER_SIZE		260 * 1024
24 #define BDEV_TASK_ARRAY_SIZE	2048
25 
26 pthread_mutex_t g_test_mutex;
27 pthread_cond_t g_test_cond;
28 
29 static struct spdk_thread *g_thread_init;
30 static struct spdk_thread *g_thread_ut;
31 static struct spdk_thread *g_thread_io;
32 static bool g_wait_for_tests = false;
33 static int g_num_failures = 0;
34 static bool g_shutdown = false;
35 
36 struct io_target {
37 	struct spdk_bdev	*bdev;
38 	struct spdk_bdev_desc	*bdev_desc;
39 	struct spdk_io_channel	*ch;
40 	struct io_target	*next;
41 };
42 
43 struct bdevio_request {
44 	char *buf;
45 	char *fused_buf;
46 	int data_len;
47 	uint64_t offset;
48 	struct iovec iov[BUFFER_IOVS];
49 	int iovcnt;
50 	struct iovec fused_iov[BUFFER_IOVS];
51 	int fused_iovcnt;
52 	struct io_target *target;
53 	uint64_t src_offset;
54 };
55 
56 struct io_target *g_io_targets = NULL;
57 struct io_target *g_current_io_target = NULL;
58 static void rpc_perform_tests_cb(unsigned num_failures, struct spdk_jsonrpc_request *request);
59 
60 static void
61 execute_spdk_function(spdk_msg_fn fn, void *arg)
62 {
63 	pthread_mutex_lock(&g_test_mutex);
64 	spdk_thread_send_msg(g_thread_io, fn, arg);
65 	pthread_cond_wait(&g_test_cond, &g_test_mutex);
66 	pthread_mutex_unlock(&g_test_mutex);
67 }
68 
69 static void
70 wake_ut_thread(void)
71 {
72 	pthread_mutex_lock(&g_test_mutex);
73 	pthread_cond_signal(&g_test_cond);
74 	pthread_mutex_unlock(&g_test_mutex);
75 }
76 
77 static void
78 __get_io_channel(void *arg)
79 {
80 	struct io_target *target = arg;
81 
82 	target->ch = spdk_bdev_get_io_channel(target->bdev_desc);
83 	assert(target->ch);
84 	wake_ut_thread();
85 }
86 
87 static void
88 bdevio_construct_target_open_cb(enum spdk_bdev_event_type type, struct spdk_bdev *bdev,
89 				void *event_ctx)
90 {
91 }
92 
93 static int
94 bdevio_construct_target(struct spdk_bdev *bdev)
95 {
96 	struct io_target *target;
97 	int rc;
98 	uint64_t num_blocks = spdk_bdev_get_num_blocks(bdev);
99 	uint32_t block_size = spdk_bdev_get_block_size(bdev);
100 
101 	target = malloc(sizeof(struct io_target));
102 	if (target == NULL) {
103 		return -ENOMEM;
104 	}
105 
106 	rc = spdk_bdev_open_ext(spdk_bdev_get_name(bdev), true, bdevio_construct_target_open_cb, NULL,
107 				&target->bdev_desc);
108 	if (rc != 0) {
109 		free(target);
110 		SPDK_ERRLOG("Could not open leaf bdev %s, error=%d\n", spdk_bdev_get_name(bdev), rc);
111 		return rc;
112 	}
113 
114 	printf("  %s: %" PRIu64 " blocks of %" PRIu32 " bytes (%" PRIu64 " MiB)\n",
115 	       spdk_bdev_get_name(bdev),
116 	       num_blocks, block_size,
117 	       (num_blocks * block_size + 1024 * 1024 - 1) / (1024 * 1024));
118 
119 	target->bdev = bdev;
120 	target->next = g_io_targets;
121 	execute_spdk_function(__get_io_channel, target);
122 	g_io_targets = target;
123 
124 	return 0;
125 }
126 
127 static int
128 bdevio_construct_targets(void)
129 {
130 	struct spdk_bdev *bdev;
131 	int rc;
132 
133 	printf("I/O targets:\n");
134 
135 	bdev = spdk_bdev_first_leaf();
136 	while (bdev != NULL) {
137 		rc = bdevio_construct_target(bdev);
138 		if (rc < 0) {
139 			SPDK_ERRLOG("Could not construct bdev %s, error=%d\n", spdk_bdev_get_name(bdev), rc);
140 			return rc;
141 		}
142 		bdev = spdk_bdev_next_leaf(bdev);
143 	}
144 
145 	if (g_io_targets == NULL) {
146 		SPDK_ERRLOG("No bdevs to perform tests on\n");
147 		return -1;
148 	}
149 
150 	return 0;
151 }
152 
153 static void
154 __put_io_channel(void *arg)
155 {
156 	struct io_target *target = arg;
157 
158 	spdk_put_io_channel(target->ch);
159 	wake_ut_thread();
160 }
161 
162 static void
163 bdevio_cleanup_targets(void)
164 {
165 	struct io_target *target;
166 
167 	target = g_io_targets;
168 	while (target != NULL) {
169 		execute_spdk_function(__put_io_channel, target);
170 		spdk_bdev_close(target->bdev_desc);
171 		g_io_targets = target->next;
172 		free(target);
173 		target = g_io_targets;
174 	}
175 }
176 
177 static bool g_completion_success;
178 
179 static void
180 initialize_buffer(char **buf, int pattern, int size)
181 {
182 	*buf = spdk_zmalloc(size, 0x1000, NULL, SPDK_ENV_LCORE_ID_ANY, SPDK_MALLOC_DMA);
183 	memset(*buf, pattern, size);
184 }
185 
186 static void
187 quick_test_complete(struct spdk_bdev_io *bdev_io, bool success, void *arg)
188 {
189 	g_completion_success = success;
190 	spdk_bdev_free_io(bdev_io);
191 	wake_ut_thread();
192 }
193 
194 static uint64_t
195 bdev_bytes_to_blocks(struct spdk_bdev *bdev, uint64_t bytes)
196 {
197 	uint32_t block_size = spdk_bdev_get_block_size(bdev);
198 
199 	CU_ASSERT(bytes % block_size == 0);
200 	return bytes / block_size;
201 }
202 
203 static void
204 __blockdev_write(void *arg)
205 {
206 	struct bdevio_request *req = arg;
207 	struct io_target *target = req->target;
208 	int rc;
209 
210 	if (req->iovcnt) {
211 		rc = spdk_bdev_writev(target->bdev_desc, target->ch, req->iov, req->iovcnt, req->offset,
212 				      req->data_len, quick_test_complete, NULL);
213 	} else {
214 		rc = spdk_bdev_write(target->bdev_desc, target->ch, req->buf, req->offset,
215 				     req->data_len, quick_test_complete, NULL);
216 	}
217 
218 	if (rc) {
219 		g_completion_success = false;
220 		wake_ut_thread();
221 	}
222 }
223 
224 static void
225 __blockdev_write_zeroes(void *arg)
226 {
227 	struct bdevio_request *req = arg;
228 	struct io_target *target = req->target;
229 	int rc;
230 
231 	rc = spdk_bdev_write_zeroes(target->bdev_desc, target->ch, req->offset,
232 				    req->data_len, quick_test_complete, NULL);
233 	if (rc) {
234 		g_completion_success = false;
235 		wake_ut_thread();
236 	}
237 }
238 
239 static void
240 __blockdev_compare_and_write(void *arg)
241 {
242 	struct bdevio_request *req = arg;
243 	struct io_target *target = req->target;
244 	struct spdk_bdev *bdev = target->bdev;
245 	int rc;
246 
247 	rc = spdk_bdev_comparev_and_writev_blocks(target->bdev_desc, target->ch, req->iov, req->iovcnt,
248 			req->fused_iov, req->fused_iovcnt, bdev_bytes_to_blocks(bdev, req->offset),
249 			bdev_bytes_to_blocks(bdev, req->data_len), quick_test_complete, NULL);
250 
251 	if (rc) {
252 		g_completion_success = false;
253 		wake_ut_thread();
254 	}
255 }
256 
257 static void
258 sgl_chop_buffer(struct bdevio_request *req, int iov_len)
259 {
260 	int data_len = req->data_len;
261 	char *buf = req->buf;
262 
263 	req->iovcnt = 0;
264 	if (!iov_len) {
265 		return;
266 	}
267 
268 	for (; data_len > 0 && req->iovcnt < BUFFER_IOVS; req->iovcnt++) {
269 		if (data_len < iov_len) {
270 			iov_len = data_len;
271 		}
272 
273 		req->iov[req->iovcnt].iov_base = buf;
274 		req->iov[req->iovcnt].iov_len = iov_len;
275 
276 		buf += iov_len;
277 		data_len -= iov_len;
278 	}
279 
280 	CU_ASSERT_EQUAL_FATAL(data_len, 0);
281 }
282 
283 static void
284 sgl_chop_fused_buffer(struct bdevio_request *req, int iov_len)
285 {
286 	int data_len = req->data_len;
287 	char *buf = req->fused_buf;
288 
289 	req->fused_iovcnt = 0;
290 	if (!iov_len) {
291 		return;
292 	}
293 
294 	for (; data_len > 0 && req->fused_iovcnt < BUFFER_IOVS; req->fused_iovcnt++) {
295 		if (data_len < iov_len) {
296 			iov_len = data_len;
297 		}
298 
299 		req->fused_iov[req->fused_iovcnt].iov_base = buf;
300 		req->fused_iov[req->fused_iovcnt].iov_len = iov_len;
301 
302 		buf += iov_len;
303 		data_len -= iov_len;
304 	}
305 
306 	CU_ASSERT_EQUAL_FATAL(data_len, 0);
307 }
308 
309 static void
310 blockdev_write(struct io_target *target, char *tx_buf,
311 	       uint64_t offset, int data_len, int iov_len)
312 {
313 	struct bdevio_request req;
314 
315 	req.target = target;
316 	req.buf = tx_buf;
317 	req.data_len = data_len;
318 	req.offset = offset;
319 	sgl_chop_buffer(&req, iov_len);
320 
321 	g_completion_success = false;
322 
323 	execute_spdk_function(__blockdev_write, &req);
324 }
325 
326 static void
327 _blockdev_compare_and_write(struct io_target *target, char *cmp_buf, char *write_buf,
328 			    uint64_t offset, int data_len, int iov_len)
329 {
330 	struct bdevio_request req;
331 
332 	req.target = target;
333 	req.buf = cmp_buf;
334 	req.fused_buf = write_buf;
335 	req.data_len = data_len;
336 	req.offset = offset;
337 	sgl_chop_buffer(&req, iov_len);
338 	sgl_chop_fused_buffer(&req, iov_len);
339 
340 	g_completion_success = false;
341 
342 	execute_spdk_function(__blockdev_compare_and_write, &req);
343 }
344 
345 static void
346 blockdev_write_zeroes(struct io_target *target, char *tx_buf,
347 		      uint64_t offset, int data_len)
348 {
349 	struct bdevio_request req;
350 
351 	req.target = target;
352 	req.buf = tx_buf;
353 	req.data_len = data_len;
354 	req.offset = offset;
355 
356 	g_completion_success = false;
357 
358 	execute_spdk_function(__blockdev_write_zeroes, &req);
359 }
360 
361 static void
362 __blockdev_read(void *arg)
363 {
364 	struct bdevio_request *req = arg;
365 	struct io_target *target = req->target;
366 	int rc;
367 
368 	if (req->iovcnt) {
369 		rc = spdk_bdev_readv(target->bdev_desc, target->ch, req->iov, req->iovcnt, req->offset,
370 				     req->data_len, quick_test_complete, NULL);
371 	} else {
372 		rc = spdk_bdev_read(target->bdev_desc, target->ch, req->buf, req->offset,
373 				    req->data_len, quick_test_complete, NULL);
374 	}
375 
376 	if (rc) {
377 		g_completion_success = false;
378 		wake_ut_thread();
379 	}
380 }
381 
382 static void
383 blockdev_read(struct io_target *target, char *rx_buf,
384 	      uint64_t offset, int data_len, int iov_len)
385 {
386 	struct bdevio_request req;
387 
388 	req.target = target;
389 	req.buf = rx_buf;
390 	req.data_len = data_len;
391 	req.offset = offset;
392 	req.iovcnt = 0;
393 	sgl_chop_buffer(&req, iov_len);
394 
395 	g_completion_success = false;
396 
397 	execute_spdk_function(__blockdev_read, &req);
398 }
399 
400 static void
401 _blockdev_copy(void *arg)
402 {
403 	struct bdevio_request *req = arg;
404 	struct io_target *target = req->target;
405 	struct spdk_bdev *bdev = target->bdev;
406 	int rc;
407 
408 	rc = spdk_bdev_copy_blocks(target->bdev_desc, target->ch,
409 				   bdev_bytes_to_blocks(bdev, req->offset),
410 				   bdev_bytes_to_blocks(bdev, req->src_offset),
411 				   bdev_bytes_to_blocks(bdev, req->data_len),
412 				   quick_test_complete, NULL);
413 
414 	if (rc) {
415 		g_completion_success = false;
416 		wake_ut_thread();
417 	}
418 }
419 
420 static void
421 blockdev_copy(struct io_target *target, uint64_t dst_offset, uint64_t src_offset, int data_len)
422 {
423 	struct bdevio_request req;
424 
425 	req.target = target;
426 	req.data_len = data_len;
427 	req.offset = dst_offset;
428 	req.src_offset = src_offset;
429 
430 	g_completion_success = false;
431 
432 	execute_spdk_function(_blockdev_copy, &req);
433 }
434 
435 static int
436 blockdev_write_read_data_match(char *rx_buf, char *tx_buf, int data_length)
437 {
438 	return memcmp(rx_buf, tx_buf, data_length);
439 }
440 
441 static void
442 blockdev_write_read(uint32_t data_length, uint32_t iov_len, int pattern, uint64_t offset,
443 		    int expected_rc, bool write_zeroes)
444 {
445 	struct io_target *target;
446 	char	*tx_buf = NULL;
447 	char	*rx_buf = NULL;
448 	int	rc;
449 	uint64_t write_offset = offset;
450 	uint32_t write_data_len = data_length;
451 
452 	target = g_current_io_target;
453 
454 	if (spdk_bdev_get_write_unit_size(target->bdev) > 1 && expected_rc == 0) {
455 		uint32_t write_unit_bytes;
456 
457 		write_unit_bytes = spdk_bdev_get_write_unit_size(target->bdev) *
458 				   spdk_bdev_get_block_size(target->bdev);
459 		write_offset -= offset % write_unit_bytes;
460 		write_data_len += (offset - write_offset);
461 
462 		if (write_data_len % write_unit_bytes) {
463 			write_data_len += write_unit_bytes - write_data_len % write_unit_bytes;
464 		}
465 	}
466 
467 	if (!write_zeroes) {
468 		initialize_buffer(&tx_buf, pattern, write_data_len);
469 		initialize_buffer(&rx_buf, 0, data_length);
470 
471 		blockdev_write(target, tx_buf, write_offset, write_data_len, iov_len);
472 	} else {
473 		initialize_buffer(&tx_buf, 0, write_data_len);
474 		initialize_buffer(&rx_buf, pattern, data_length);
475 
476 		blockdev_write_zeroes(target, tx_buf, write_offset, write_data_len);
477 	}
478 
479 
480 	if (expected_rc == 0) {
481 		CU_ASSERT_EQUAL(g_completion_success, true);
482 	} else {
483 		CU_ASSERT_EQUAL(g_completion_success, false);
484 	}
485 	blockdev_read(target, rx_buf, offset, data_length, iov_len);
486 
487 	if (expected_rc == 0) {
488 		CU_ASSERT_EQUAL(g_completion_success, true);
489 	} else {
490 		CU_ASSERT_EQUAL(g_completion_success, false);
491 	}
492 
493 	if (g_completion_success) {
494 		rc = blockdev_write_read_data_match(rx_buf, tx_buf + (offset - write_offset), data_length);
495 		/* Assert the write by comparing it with values read
496 		 * from each blockdev */
497 		CU_ASSERT_EQUAL(rc, 0);
498 	}
499 
500 	spdk_free(rx_buf);
501 	spdk_free(tx_buf);
502 }
503 
504 static void
505 blockdev_compare_and_write(uint32_t data_length, uint32_t iov_len, uint64_t offset)
506 {
507 	struct io_target *target;
508 	char	*tx_buf = NULL;
509 	char	*write_buf = NULL;
510 	char	*rx_buf = NULL;
511 	int	rc;
512 
513 	target = g_current_io_target;
514 
515 	initialize_buffer(&tx_buf, 0xAA, data_length);
516 	initialize_buffer(&rx_buf, 0, data_length);
517 	initialize_buffer(&write_buf, 0xBB, data_length);
518 
519 	blockdev_write(target, tx_buf, offset, data_length, iov_len);
520 	CU_ASSERT_EQUAL(g_completion_success, true);
521 
522 	_blockdev_compare_and_write(target, tx_buf, write_buf, offset, data_length, iov_len);
523 	CU_ASSERT_EQUAL(g_completion_success, true);
524 
525 	_blockdev_compare_and_write(target, tx_buf, write_buf, offset, data_length, iov_len);
526 	CU_ASSERT_EQUAL(g_completion_success, false);
527 
528 	blockdev_read(target, rx_buf, offset, data_length, iov_len);
529 	CU_ASSERT_EQUAL(g_completion_success, true);
530 	rc = blockdev_write_read_data_match(rx_buf, write_buf, data_length);
531 	/* Assert the write by comparing it with values read
532 	 * from each blockdev */
533 	CU_ASSERT_EQUAL(rc, 0);
534 
535 	spdk_free(rx_buf);
536 	spdk_free(tx_buf);
537 	spdk_free(write_buf);
538 }
539 
540 static void
541 blockdev_write_read_block(void)
542 {
543 	uint32_t data_length;
544 	uint64_t offset;
545 	int pattern;
546 	int expected_rc;
547 	struct io_target *target = g_current_io_target;
548 	struct spdk_bdev *bdev = target->bdev;
549 
550 	/* Data size = 1 block */
551 	data_length = spdk_bdev_get_block_size(bdev);
552 	CU_ASSERT_TRUE(data_length < BUFFER_SIZE);
553 	offset = 0;
554 	pattern = 0xA3;
555 	/* Params are valid, hence the expected return value
556 	 * of write and read for all blockdevs is 0. */
557 	expected_rc = 0;
558 
559 	blockdev_write_read(data_length, 0, pattern, offset, expected_rc, 0);
560 }
561 
562 static void
563 blockdev_write_zeroes_read_block(void)
564 {
565 	uint32_t data_length;
566 	uint64_t offset;
567 	int pattern;
568 	int expected_rc;
569 	struct io_target *target = g_current_io_target;
570 	struct spdk_bdev *bdev = target->bdev;
571 
572 	/* Data size = 1 block */
573 	data_length = spdk_bdev_get_block_size(bdev);
574 	offset = 0;
575 	pattern = 0xA3;
576 	/* Params are valid, hence the expected return value
577 	 * of write_zeroes and read for all blockdevs is 0. */
578 	expected_rc = 0;
579 
580 	blockdev_write_read(data_length, 0, pattern, offset, expected_rc, 1);
581 }
582 
583 /*
584  * This i/o will not have to split at the bdev layer.
585  */
586 static void
587 blockdev_write_zeroes_read_no_split(void)
588 {
589 	uint32_t data_length;
590 	uint64_t offset;
591 	int pattern;
592 	int expected_rc;
593 	struct io_target *target = g_current_io_target;
594 	struct spdk_bdev *bdev = target->bdev;
595 
596 	/* Data size = block size aligned ZERO_BUFFER_SIZE */
597 	data_length = ZERO_BUFFER_SIZE; /* from bdev_internal.h */
598 	data_length -= ZERO_BUFFER_SIZE % spdk_bdev_get_block_size(bdev);
599 	offset = 0;
600 	pattern = 0xA3;
601 	/* Params are valid, hence the expected return value
602 	 * of write_zeroes and read for all blockdevs is 0. */
603 	expected_rc = 0;
604 
605 	blockdev_write_read(data_length, 0, pattern, offset, expected_rc, 1);
606 }
607 
608 /*
609  * This i/o will have to split at the bdev layer if
610  * write-zeroes is not supported by the bdev.
611  */
612 static void
613 blockdev_write_zeroes_read_split(void)
614 {
615 	uint32_t data_length;
616 	uint64_t offset;
617 	int pattern;
618 	int expected_rc;
619 	struct io_target *target = g_current_io_target;
620 	struct spdk_bdev *bdev = target->bdev;
621 
622 	/* Data size = block size aligned 3 * ZERO_BUFFER_SIZE */
623 	data_length = 3 * ZERO_BUFFER_SIZE; /* from bdev_internal.h */
624 	data_length -= data_length % spdk_bdev_get_block_size(bdev);
625 	offset = 0;
626 	pattern = 0xA3;
627 	/* Params are valid, hence the expected return value
628 	 * of write_zeroes and read for all blockdevs is 0. */
629 	expected_rc = 0;
630 
631 	blockdev_write_read(data_length, 0, pattern, offset, expected_rc, 1);
632 }
633 
634 /*
635  * This i/o will have to split at the bdev layer if
636  * write-zeroes is not supported by the bdev. It also
637  * tests a write size that is not an even multiple of
638  * the bdev layer zero buffer size.
639  */
640 static void
641 blockdev_write_zeroes_read_split_partial(void)
642 {
643 	uint32_t data_length;
644 	uint64_t offset;
645 	int pattern;
646 	int expected_rc;
647 	struct io_target *target = g_current_io_target;
648 	struct spdk_bdev *bdev = target->bdev;
649 	uint32_t block_size = spdk_bdev_get_block_size(bdev);
650 
651 	/* Data size = block size aligned 7 * ZERO_BUFFER_SIZE / 2 */
652 	data_length = ZERO_BUFFER_SIZE * 7 / 2;
653 	data_length -= data_length % block_size;
654 	offset = 0;
655 	pattern = 0xA3;
656 	/* Params are valid, hence the expected return value
657 	 * of write_zeroes and read for all blockdevs is 0. */
658 	expected_rc = 0;
659 
660 	blockdev_write_read(data_length, 0, pattern, offset, expected_rc, 1);
661 }
662 
663 static void
664 blockdev_writev_readv_block(void)
665 {
666 	uint32_t data_length, iov_len;
667 	uint64_t offset;
668 	int pattern;
669 	int expected_rc;
670 	struct io_target *target = g_current_io_target;
671 	struct spdk_bdev *bdev = target->bdev;
672 
673 	/* Data size = 1 block */
674 	data_length = spdk_bdev_get_block_size(bdev);
675 	iov_len = data_length;
676 	CU_ASSERT_TRUE(data_length < BUFFER_SIZE);
677 	offset = 0;
678 	pattern = 0xA3;
679 	/* Params are valid, hence the expected return value
680 	 * of write and read for all blockdevs is 0. */
681 	expected_rc = 0;
682 
683 	blockdev_write_read(data_length, iov_len, pattern, offset, expected_rc, 0);
684 }
685 
686 static void
687 blockdev_comparev_and_writev(void)
688 {
689 	uint32_t data_length, iov_len;
690 	uint64_t offset;
691 	struct io_target *target = g_current_io_target;
692 	struct spdk_bdev *bdev = target->bdev;
693 
694 	if (spdk_bdev_is_md_separate(bdev)) {
695 		/* TODO: remove this check once bdev layer properly supports
696 		 * compare and write for bdevs with separate md.
697 		 */
698 		SPDK_ERRLOG("skipping comparev_and_writev on bdev %s since it has\n"
699 			    "separate metadata which is not supported yet.\n",
700 			    spdk_bdev_get_name(bdev));
701 		return;
702 	}
703 
704 	/* Data size = acwu size */
705 	data_length = spdk_bdev_get_block_size(bdev) * spdk_bdev_get_acwu(bdev);
706 	iov_len = data_length;
707 	CU_ASSERT_TRUE(data_length < BUFFER_SIZE);
708 	offset = 0;
709 
710 	blockdev_compare_and_write(data_length, iov_len, offset);
711 }
712 
713 static void
714 blockdev_writev_readv_30x1block(void)
715 {
716 	uint32_t data_length, iov_len;
717 	uint64_t offset;
718 	int pattern;
719 	int expected_rc;
720 	struct io_target *target = g_current_io_target;
721 	struct spdk_bdev *bdev = target->bdev;
722 	uint32_t block_size = spdk_bdev_get_block_size(bdev);
723 
724 	/* Data size = 30 * block size */
725 	data_length = block_size * 30;
726 	iov_len = block_size;
727 	CU_ASSERT_TRUE(data_length < BUFFER_SIZE);
728 	offset = 0;
729 	pattern = 0xA3;
730 	/* Params are valid, hence the expected return value
731 	 * of write and read for all blockdevs is 0. */
732 	expected_rc = 0;
733 
734 	blockdev_write_read(data_length, iov_len, pattern, offset, expected_rc, 0);
735 }
736 
737 static void
738 blockdev_write_read_8blocks(void)
739 {
740 	uint32_t data_length;
741 	uint64_t offset;
742 	int pattern;
743 	int expected_rc;
744 	struct io_target *target = g_current_io_target;
745 	struct spdk_bdev *bdev = target->bdev;
746 
747 	/* Data size = 8 * block size */
748 	data_length = spdk_bdev_get_block_size(bdev) * 8;
749 	CU_ASSERT_TRUE(data_length < BUFFER_SIZE);
750 	offset = data_length;
751 	pattern = 0xA3;
752 	/* Params are valid, hence the expected return value
753 	 * of write and read for all blockdevs is 0. */
754 	expected_rc = 0;
755 
756 	blockdev_write_read(data_length, 0, pattern, offset, expected_rc, 0);
757 }
758 
759 static void
760 blockdev_writev_readv_8blocks(void)
761 {
762 	uint32_t data_length, iov_len;
763 	uint64_t offset;
764 	int pattern;
765 	int expected_rc;
766 	struct io_target *target = g_current_io_target;
767 	struct spdk_bdev *bdev = target->bdev;
768 
769 	/* Data size = 8 * block size */
770 	data_length = spdk_bdev_get_block_size(bdev) * 8;
771 	iov_len = data_length;
772 	CU_ASSERT_TRUE(data_length < BUFFER_SIZE);
773 	offset = data_length;
774 	pattern = 0xA3;
775 	/* Params are valid, hence the expected return value
776 	 * of write and read for all blockdevs is 0. */
777 	expected_rc = 0;
778 
779 	blockdev_write_read(data_length, iov_len, pattern, offset, expected_rc, 0);
780 }
781 
782 static void
783 blockdev_write_read_size_gt_128k(void)
784 {
785 	uint32_t data_length;
786 	uint64_t offset;
787 	int pattern;
788 	int expected_rc;
789 	struct io_target *target = g_current_io_target;
790 	struct spdk_bdev *bdev = target->bdev;
791 	uint32_t block_size = spdk_bdev_get_block_size(bdev);
792 
793 	/* Data size = block size aligned 128K + 1 block */
794 	data_length = 128 * 1024;
795 	data_length -= data_length % block_size;
796 	data_length += block_size;
797 	CU_ASSERT_TRUE(data_length < BUFFER_SIZE);
798 	offset = block_size * 2;
799 	pattern = 0xA3;
800 	/* Params are valid, hence the expected return value
801 	 * of write and read for all blockdevs is 0. */
802 	expected_rc = 0;
803 
804 	blockdev_write_read(data_length, 0, pattern, offset, expected_rc, 0);
805 }
806 
807 static void
808 blockdev_writev_readv_size_gt_128k(void)
809 {
810 	uint32_t data_length, iov_len;
811 	uint64_t offset;
812 	int pattern;
813 	int expected_rc;
814 	struct io_target *target = g_current_io_target;
815 	struct spdk_bdev *bdev = target->bdev;
816 	uint32_t block_size = spdk_bdev_get_block_size(bdev);
817 
818 	/* Data size = block size aligned 128K + 1 block */
819 	data_length = 128 * 1024;
820 	data_length -= data_length % block_size;
821 	data_length += block_size;
822 	iov_len = data_length;
823 	CU_ASSERT_TRUE(data_length < BUFFER_SIZE);
824 	offset = block_size * 2;
825 	pattern = 0xA3;
826 	/* Params are valid, hence the expected return value
827 	 * of write and read for all blockdevs is 0. */
828 	expected_rc = 0;
829 
830 	blockdev_write_read(data_length, iov_len, pattern, offset, expected_rc, 0);
831 }
832 
833 static void
834 blockdev_writev_readv_size_gt_128k_two_iov(void)
835 {
836 	uint32_t data_length, iov_len;
837 	uint64_t offset;
838 	int pattern;
839 	int expected_rc;
840 	struct io_target *target = g_current_io_target;
841 	struct spdk_bdev *bdev = target->bdev;
842 	uint32_t block_size = spdk_bdev_get_block_size(bdev);
843 
844 	/* Data size = block size aligned 128K + 1 block */
845 	data_length = 128 * 1024;
846 	data_length -= data_length % block_size;
847 	iov_len = data_length;
848 	data_length += block_size;
849 	CU_ASSERT_TRUE(data_length < BUFFER_SIZE);
850 	offset = block_size * 2;
851 	pattern = 0xA3;
852 	/* Params are valid, hence the expected return value
853 	 * of write and read for all blockdevs is 0. */
854 	expected_rc = 0;
855 
856 	blockdev_write_read(data_length, iov_len, pattern, offset, expected_rc, 0);
857 }
858 
859 static void
860 blockdev_write_read_invalid_size(void)
861 {
862 	uint32_t data_length;
863 	uint64_t offset;
864 	int pattern;
865 	int expected_rc;
866 	struct io_target *target = g_current_io_target;
867 	struct spdk_bdev *bdev = target->bdev;
868 	uint32_t block_size = spdk_bdev_get_block_size(bdev);
869 
870 	/* Data size is not a multiple of the block size */
871 	data_length = block_size - 1;
872 	CU_ASSERT_TRUE(data_length < BUFFER_SIZE);
873 	offset = block_size * 2;
874 	pattern = 0xA3;
875 	/* Params are invalid, hence the expected return value
876 	 * of write and read for all blockdevs is < 0 */
877 	expected_rc = -1;
878 
879 	blockdev_write_read(data_length, 0, pattern, offset, expected_rc, 0);
880 }
881 
882 static void
883 blockdev_write_read_offset_plus_nbytes_equals_bdev_size(void)
884 {
885 	uint32_t data_length;
886 	uint64_t offset;
887 	int pattern;
888 	int expected_rc;
889 	struct io_target *target = g_current_io_target;
890 	struct spdk_bdev *bdev = target->bdev;
891 	uint32_t block_size = spdk_bdev_get_block_size(bdev);
892 
893 	data_length = block_size;
894 	CU_ASSERT_TRUE(data_length < BUFFER_SIZE);
895 	/* The start offset has been set to a marginal value
896 	 * such that offset + nbytes == Total size of
897 	 * blockdev. */
898 	offset = ((spdk_bdev_get_num_blocks(bdev) - 1) * block_size);
899 	pattern = 0xA3;
900 	/* Params are valid, hence the expected return value
901 	 * of write and read for all blockdevs is 0. */
902 	expected_rc = 0;
903 
904 	blockdev_write_read(data_length, 0, pattern, offset, expected_rc, 0);
905 }
906 
907 static void
908 blockdev_write_read_offset_plus_nbytes_gt_bdev_size(void)
909 {
910 	uint32_t data_length;
911 	uint64_t offset;
912 	int pattern;
913 	int expected_rc;
914 	struct io_target *target = g_current_io_target;
915 	struct spdk_bdev *bdev = target->bdev;
916 	uint32_t block_size = spdk_bdev_get_block_size(bdev);
917 
918 	/* Tests the overflow condition of the blockdevs. */
919 	data_length = block_size * 2;
920 	CU_ASSERT_TRUE(data_length < BUFFER_SIZE);
921 	pattern = 0xA3;
922 
923 	/* The start offset has been set to a valid value
924 	 * but offset + nbytes is greater than the Total size
925 	 * of the blockdev. The test should fail. */
926 	offset = (spdk_bdev_get_num_blocks(bdev) - 1) * block_size;
927 	/* Params are invalid, hence the expected return value
928 	 * of write and read for all blockdevs is < 0 */
929 	expected_rc = -1;
930 
931 	blockdev_write_read(data_length, 0, pattern, offset, expected_rc, 0);
932 }
933 
934 static void
935 blockdev_write_read_max_offset(void)
936 {
937 	int	data_length;
938 	uint64_t offset;
939 	int pattern;
940 	int expected_rc;
941 	struct io_target *target = g_current_io_target;
942 	struct spdk_bdev *bdev = target->bdev;
943 
944 	data_length = spdk_bdev_get_block_size(bdev);
945 	CU_ASSERT_TRUE(data_length < BUFFER_SIZE);
946 	/* The start offset has been set to UINT64_MAX such that
947 	 * adding nbytes wraps around and points to an invalid address. */
948 	offset = UINT64_MAX;
949 	pattern = 0xA3;
950 	/* Params are invalid, hence the expected return value
951 	 * of write and read for all blockdevs is < 0 */
952 	expected_rc = -1;
953 
954 	blockdev_write_read(data_length, 0, pattern, offset, expected_rc, 0);
955 }
956 
957 static void
958 blockdev_overlapped_write_read_2blocks(void)
959 {
960 	int	data_length;
961 	uint64_t offset;
962 	int pattern;
963 	int expected_rc;
964 	struct io_target *target = g_current_io_target;
965 	struct spdk_bdev *bdev = target->bdev;
966 
967 	/* Data size = 2 blocks */
968 	data_length = spdk_bdev_get_block_size(bdev) * 2;
969 	CU_ASSERT_TRUE(data_length < BUFFER_SIZE);
970 	offset = 0;
971 	pattern = 0xA3;
972 	/* Params are valid, hence the expected return value
973 	 * of write and read for all blockdevs is 0. */
974 	expected_rc = 0;
975 	/* Assert the write by comparing it with values read
976 	 * from the same offset for each blockdev */
977 	blockdev_write_read(data_length, 0, pattern, offset, expected_rc, 0);
978 
979 	/* Overwrite the pattern 0xbb of size 2*block size on an address offset
980 	 * overlapping with the address written above and assert the new value in
981 	 * the overlapped address range */
982 	/* Populate 2*block size with value 0xBB */
983 	pattern = 0xBB;
984 	/* Offset = 1 block; Overlap offset addresses and write value 0xbb */
985 	offset = spdk_bdev_get_block_size(bdev);
986 	/* Assert the write by comparing it with values read
987 	 * from the overlapped offset for each blockdev */
988 	blockdev_write_read(data_length, 0, pattern, offset, expected_rc, 0);
989 }
990 
991 static void
992 __blockdev_reset(void *arg)
993 {
994 	struct bdevio_request *req = arg;
995 	struct io_target *target = req->target;
996 	int rc;
997 
998 	rc = spdk_bdev_reset(target->bdev_desc, target->ch, quick_test_complete, NULL);
999 	if (rc < 0) {
1000 		g_completion_success = false;
1001 		wake_ut_thread();
1002 	}
1003 }
1004 
1005 static void
1006 blockdev_test_reset(void)
1007 {
1008 	struct bdevio_request req;
1009 	struct io_target *target;
1010 	bool reset_supported;
1011 
1012 	target = g_current_io_target;
1013 	req.target = target;
1014 
1015 	reset_supported = spdk_bdev_io_type_supported(target->bdev, SPDK_BDEV_IO_TYPE_RESET);
1016 	g_completion_success = false;
1017 
1018 	execute_spdk_function(__blockdev_reset, &req);
1019 
1020 	CU_ASSERT_EQUAL(g_completion_success, reset_supported);
1021 }
1022 
1023 struct bdevio_passthrough_request {
1024 	struct spdk_nvme_cmd cmd;
1025 	void *buf;
1026 	uint32_t len;
1027 	struct io_target *target;
1028 	int sct;
1029 	int sc;
1030 	uint32_t cdw0;
1031 };
1032 
1033 static void
1034 nvme_pt_test_complete(struct spdk_bdev_io *bdev_io, bool success, void *arg)
1035 {
1036 	struct bdevio_passthrough_request *pt_req = arg;
1037 
1038 	spdk_bdev_io_get_nvme_status(bdev_io, &pt_req->cdw0, &pt_req->sct, &pt_req->sc);
1039 	spdk_bdev_free_io(bdev_io);
1040 	wake_ut_thread();
1041 }
1042 
1043 static void
1044 __blockdev_nvme_passthru(void *arg)
1045 {
1046 	struct bdevio_passthrough_request *pt_req = arg;
1047 	struct io_target *target = pt_req->target;
1048 	int rc;
1049 
1050 	rc = spdk_bdev_nvme_io_passthru(target->bdev_desc, target->ch,
1051 					&pt_req->cmd, pt_req->buf, pt_req->len,
1052 					nvme_pt_test_complete, pt_req);
1053 	if (rc) {
1054 		wake_ut_thread();
1055 	}
1056 }
1057 
1058 static void
1059 blockdev_test_nvme_passthru_rw(void)
1060 {
1061 	struct bdevio_passthrough_request pt_req;
1062 	void *write_buf, *read_buf;
1063 	struct io_target *target;
1064 
1065 	target = g_current_io_target;
1066 
1067 	if (!spdk_bdev_io_type_supported(target->bdev, SPDK_BDEV_IO_TYPE_NVME_IO)) {
1068 		return;
1069 	}
1070 
1071 	memset(&pt_req, 0, sizeof(pt_req));
1072 	pt_req.target = target;
1073 	pt_req.cmd.opc = SPDK_NVME_OPC_WRITE;
1074 	pt_req.cmd.nsid = 1;
1075 	*(uint64_t *)&pt_req.cmd.cdw10 = 4;
1076 	pt_req.cmd.cdw12 = 0;
1077 
1078 	pt_req.len = spdk_bdev_get_block_size(target->bdev);
1079 	write_buf = spdk_malloc(pt_req.len, 0, NULL, SPDK_ENV_LCORE_ID_ANY, SPDK_MALLOC_DMA);
1080 	memset(write_buf, 0xA5, pt_req.len);
1081 	pt_req.buf = write_buf;
1082 
1083 	pt_req.sct = SPDK_NVME_SCT_VENDOR_SPECIFIC;
1084 	pt_req.sc = SPDK_NVME_SC_INVALID_FIELD;
1085 	execute_spdk_function(__blockdev_nvme_passthru, &pt_req);
1086 	CU_ASSERT(pt_req.sct == SPDK_NVME_SCT_GENERIC);
1087 	CU_ASSERT(pt_req.sc == SPDK_NVME_SC_SUCCESS);
1088 
1089 	pt_req.cmd.opc = SPDK_NVME_OPC_READ;
1090 	read_buf = spdk_zmalloc(pt_req.len, 0, NULL, SPDK_ENV_LCORE_ID_ANY, SPDK_MALLOC_DMA);
1091 	pt_req.buf = read_buf;
1092 
1093 	pt_req.sct = SPDK_NVME_SCT_VENDOR_SPECIFIC;
1094 	pt_req.sc = SPDK_NVME_SC_INVALID_FIELD;
1095 	execute_spdk_function(__blockdev_nvme_passthru, &pt_req);
1096 	CU_ASSERT(pt_req.sct == SPDK_NVME_SCT_GENERIC);
1097 	CU_ASSERT(pt_req.sc == SPDK_NVME_SC_SUCCESS);
1098 
1099 	CU_ASSERT(!memcmp(read_buf, write_buf, pt_req.len));
1100 	spdk_free(read_buf);
1101 	spdk_free(write_buf);
1102 }
1103 
1104 static void
1105 blockdev_test_nvme_passthru_vendor_specific(void)
1106 {
1107 	struct bdevio_passthrough_request pt_req;
1108 	struct io_target *target;
1109 
1110 	target = g_current_io_target;
1111 
1112 	if (!spdk_bdev_io_type_supported(target->bdev, SPDK_BDEV_IO_TYPE_NVME_IO)) {
1113 		return;
1114 	}
1115 
1116 	memset(&pt_req, 0, sizeof(pt_req));
1117 	pt_req.target = target;
1118 	pt_req.cmd.opc = 0x7F; /* choose known invalid opcode */
1119 	pt_req.cmd.nsid = 1;
1120 
1121 	pt_req.sct = SPDK_NVME_SCT_VENDOR_SPECIFIC;
1122 	pt_req.sc = SPDK_NVME_SC_SUCCESS;
1123 	pt_req.cdw0 = 0xbeef;
1124 	execute_spdk_function(__blockdev_nvme_passthru, &pt_req);
1125 	CU_ASSERT(pt_req.sct == SPDK_NVME_SCT_GENERIC);
1126 	CU_ASSERT(pt_req.sc == SPDK_NVME_SC_INVALID_OPCODE);
1127 	CU_ASSERT(pt_req.cdw0 == 0x0);
1128 }
1129 
1130 static void
1131 __blockdev_nvme_admin_passthru(void *arg)
1132 {
1133 	struct bdevio_passthrough_request *pt_req = arg;
1134 	struct io_target *target = pt_req->target;
1135 	int rc;
1136 
1137 	rc = spdk_bdev_nvme_admin_passthru(target->bdev_desc, target->ch,
1138 					   &pt_req->cmd, pt_req->buf, pt_req->len,
1139 					   nvme_pt_test_complete, pt_req);
1140 	if (rc) {
1141 		wake_ut_thread();
1142 	}
1143 }
1144 
1145 static void
1146 blockdev_test_nvme_admin_passthru(void)
1147 {
1148 	struct io_target *target;
1149 	struct bdevio_passthrough_request pt_req;
1150 
1151 	target = g_current_io_target;
1152 
1153 	if (!spdk_bdev_io_type_supported(target->bdev, SPDK_BDEV_IO_TYPE_NVME_ADMIN)) {
1154 		return;
1155 	}
1156 
1157 	memset(&pt_req, 0, sizeof(pt_req));
1158 	pt_req.target = target;
1159 	pt_req.cmd.opc = SPDK_NVME_OPC_IDENTIFY;
1160 	pt_req.cmd.nsid = 0;
1161 	*(uint64_t *)&pt_req.cmd.cdw10 = SPDK_NVME_IDENTIFY_CTRLR;
1162 
1163 	pt_req.len = sizeof(struct spdk_nvme_ctrlr_data);
1164 	pt_req.buf = spdk_malloc(pt_req.len, 0, NULL, SPDK_ENV_LCORE_ID_ANY, SPDK_MALLOC_DMA);
1165 
1166 	pt_req.sct = SPDK_NVME_SCT_GENERIC;
1167 	pt_req.sc = SPDK_NVME_SC_SUCCESS;
1168 	execute_spdk_function(__blockdev_nvme_admin_passthru, &pt_req);
1169 	CU_ASSERT(pt_req.sct == SPDK_NVME_SCT_GENERIC);
1170 	CU_ASSERT(pt_req.sc == SPDK_NVME_SC_SUCCESS);
1171 }
1172 
1173 static void
1174 blockdev_test_copy(void)
1175 {
1176 	uint32_t data_length;
1177 	uint64_t src_offset, dst_offset;
1178 	struct io_target *target = g_current_io_target;
1179 	struct spdk_bdev *bdev = target->bdev;
1180 	char *tx_buf = NULL;
1181 	char *rx_buf = NULL;
1182 	int rc;
1183 
1184 	if (!spdk_bdev_io_type_supported(target->bdev, SPDK_BDEV_IO_TYPE_COPY)) {
1185 		return;
1186 	}
1187 
1188 	data_length = spdk_bdev_get_block_size(bdev);
1189 	CU_ASSERT_TRUE(data_length < BUFFER_SIZE);
1190 	src_offset = 0;
1191 	dst_offset = spdk_bdev_get_block_size(bdev);
1192 
1193 	initialize_buffer(&tx_buf, 0xAA, data_length);
1194 	initialize_buffer(&rx_buf, 0, data_length);
1195 
1196 	blockdev_write(target, tx_buf, src_offset, data_length, data_length);
1197 	CU_ASSERT_EQUAL(g_completion_success, true);
1198 
1199 	blockdev_copy(target, dst_offset, src_offset, data_length);
1200 	CU_ASSERT_EQUAL(g_completion_success, true);
1201 
1202 	blockdev_read(target, rx_buf, dst_offset, data_length, data_length);
1203 	CU_ASSERT_EQUAL(g_completion_success, true);
1204 
1205 	rc = blockdev_write_read_data_match(rx_buf, tx_buf, data_length);
1206 	CU_ASSERT_EQUAL(rc, 0);
1207 }
1208 
1209 static void
1210 __stop_init_thread(void *arg)
1211 {
1212 	unsigned num_failures = g_num_failures;
1213 	struct spdk_jsonrpc_request *request = arg;
1214 
1215 	g_num_failures = 0;
1216 
1217 	bdevio_cleanup_targets();
1218 	if (g_wait_for_tests && !g_shutdown) {
1219 		/* Do not stop the app yet, wait for another RPC */
1220 		rpc_perform_tests_cb(num_failures, request);
1221 		return;
1222 	}
1223 	spdk_app_stop(num_failures);
1224 }
1225 
1226 static void
1227 stop_init_thread(unsigned num_failures, struct spdk_jsonrpc_request *request)
1228 {
1229 	g_num_failures = num_failures;
1230 
1231 	spdk_thread_send_msg(g_thread_init, __stop_init_thread, request);
1232 }
1233 
1234 static int
1235 suite_init(void)
1236 {
1237 	if (g_current_io_target == NULL) {
1238 		g_current_io_target = g_io_targets;
1239 	}
1240 	return 0;
1241 }
1242 
1243 static int
1244 suite_fini(void)
1245 {
1246 	g_current_io_target = g_current_io_target->next;
1247 	return 0;
1248 }
1249 
1250 #define SUITE_NAME_MAX 64
1251 
1252 static int
1253 __setup_ut_on_single_target(struct io_target *target)
1254 {
1255 	unsigned rc = 0;
1256 	CU_pSuite suite = NULL;
1257 	char name[SUITE_NAME_MAX];
1258 
1259 	snprintf(name, sizeof(name), "bdevio tests on: %s", spdk_bdev_get_name(target->bdev));
1260 	suite = CU_add_suite(name, suite_init, suite_fini);
1261 	if (suite == NULL) {
1262 		CU_cleanup_registry();
1263 		rc = CU_get_error();
1264 		return -rc;
1265 	}
1266 
1267 	if (
1268 		CU_add_test(suite, "blockdev write read block",
1269 			    blockdev_write_read_block) == NULL
1270 		|| CU_add_test(suite, "blockdev write zeroes read block",
1271 			       blockdev_write_zeroes_read_block) == NULL
1272 		|| CU_add_test(suite, "blockdev write zeroes read no split",
1273 			       blockdev_write_zeroes_read_no_split) == NULL
1274 		|| CU_add_test(suite, "blockdev write zeroes read split",
1275 			       blockdev_write_zeroes_read_split) == NULL
1276 		|| CU_add_test(suite, "blockdev write zeroes read split partial",
1277 			       blockdev_write_zeroes_read_split_partial) == NULL
1278 		|| CU_add_test(suite, "blockdev reset",
1279 			       blockdev_test_reset) == NULL
1280 		|| CU_add_test(suite, "blockdev write read 8 blocks",
1281 			       blockdev_write_read_8blocks) == NULL
1282 		|| CU_add_test(suite, "blockdev write read size > 128k",
1283 			       blockdev_write_read_size_gt_128k) == NULL
1284 		|| CU_add_test(suite, "blockdev write read invalid size",
1285 			       blockdev_write_read_invalid_size) == NULL
1286 		|| CU_add_test(suite, "blockdev write read offset + nbytes == size of blockdev",
1287 			       blockdev_write_read_offset_plus_nbytes_equals_bdev_size) == NULL
1288 		|| CU_add_test(suite, "blockdev write read offset + nbytes > size of blockdev",
1289 			       blockdev_write_read_offset_plus_nbytes_gt_bdev_size) == NULL
1290 		|| CU_add_test(suite, "blockdev write read max offset",
1291 			       blockdev_write_read_max_offset) == NULL
1292 		|| CU_add_test(suite, "blockdev write read 2 blocks on overlapped address offset",
1293 			       blockdev_overlapped_write_read_2blocks) == NULL
1294 		|| CU_add_test(suite, "blockdev writev readv 8 blocks",
1295 			       blockdev_writev_readv_8blocks) == NULL
1296 		|| CU_add_test(suite, "blockdev writev readv 30 x 1block",
1297 			       blockdev_writev_readv_30x1block) == NULL
1298 		|| CU_add_test(suite, "blockdev writev readv block",
1299 			       blockdev_writev_readv_block) == NULL
1300 		|| CU_add_test(suite, "blockdev writev readv size > 128k",
1301 			       blockdev_writev_readv_size_gt_128k) == NULL
1302 		|| CU_add_test(suite, "blockdev writev readv size > 128k in two iovs",
1303 			       blockdev_writev_readv_size_gt_128k_two_iov) == NULL
1304 		|| CU_add_test(suite, "blockdev comparev and writev",
1305 			       blockdev_comparev_and_writev) == NULL
1306 		|| CU_add_test(suite, "blockdev nvme passthru rw",
1307 			       blockdev_test_nvme_passthru_rw) == NULL
1308 		|| CU_add_test(suite, "blockdev nvme passthru vendor specific",
1309 			       blockdev_test_nvme_passthru_vendor_specific) == NULL
1310 		|| CU_add_test(suite, "blockdev nvme admin passthru",
1311 			       blockdev_test_nvme_admin_passthru) == NULL
1312 		|| CU_add_test(suite, "blockdev copy",
1313 			       blockdev_test_copy) == NULL
1314 	) {
1315 		CU_cleanup_registry();
1316 		rc = CU_get_error();
1317 		return -rc;
1318 	}
1319 	return 0;
1320 }
1321 
1322 static void
1323 __run_ut_thread(void *arg)
1324 {
1325 	struct spdk_jsonrpc_request *request = arg;
1326 	int rc = 0;
1327 	struct io_target *target;
1328 	unsigned num_failures;
1329 
1330 	if (CU_initialize_registry() != CUE_SUCCESS) {
1331 		/* CUnit error, probably won't recover */
1332 		rc = CU_get_error();
1333 		stop_init_thread(-rc, request);
1334 	}
1335 
1336 	target = g_io_targets;
1337 	while (target != NULL) {
1338 		rc = __setup_ut_on_single_target(target);
1339 		if (rc < 0) {
1340 			/* CUnit error, probably won't recover */
1341 			stop_init_thread(-rc, request);
1342 		}
1343 		target = target->next;
1344 	}
1345 	CU_basic_set_mode(CU_BRM_VERBOSE);
1346 	CU_basic_run_tests();
1347 	num_failures = CU_get_number_of_failures();
1348 	CU_cleanup_registry();
1349 
1350 	stop_init_thread(num_failures, request);
1351 }
1352 
1353 static void
1354 __construct_targets(void *arg)
1355 {
1356 	if (bdevio_construct_targets() < 0) {
1357 		spdk_app_stop(-1);
1358 		return;
1359 	}
1360 
1361 	spdk_thread_send_msg(g_thread_ut, __run_ut_thread, NULL);
1362 }
1363 
1364 static void
1365 test_main(void *arg1)
1366 {
1367 	struct spdk_cpuset tmpmask = {};
1368 	uint32_t i;
1369 
1370 	pthread_mutex_init(&g_test_mutex, NULL);
1371 	pthread_cond_init(&g_test_cond, NULL);
1372 
1373 	/* This test runs specifically on at least three cores.
1374 	 * g_thread_init is the app_thread on main core from event framework.
1375 	 * Next two are only for the tests and should always be on separate CPU cores. */
1376 	if (spdk_env_get_core_count() < 3) {
1377 		spdk_app_stop(-1);
1378 		return;
1379 	}
1380 
1381 	SPDK_ENV_FOREACH_CORE(i) {
1382 		if (i == spdk_env_get_current_core()) {
1383 			g_thread_init = spdk_get_thread();
1384 			continue;
1385 		}
1386 		spdk_cpuset_zero(&tmpmask);
1387 		spdk_cpuset_set_cpu(&tmpmask, i, true);
1388 		if (g_thread_ut == NULL) {
1389 			g_thread_ut = spdk_thread_create("ut_thread", &tmpmask);
1390 		} else if (g_thread_io == NULL) {
1391 			g_thread_io = spdk_thread_create("io_thread", &tmpmask);
1392 		}
1393 
1394 	}
1395 
1396 	if (g_wait_for_tests) {
1397 		/* Do not perform any tests until RPC is received */
1398 		return;
1399 	}
1400 
1401 	spdk_thread_send_msg(g_thread_init, __construct_targets, NULL);
1402 }
1403 
1404 static void
1405 bdevio_usage(void)
1406 {
1407 	printf(" -w                        start bdevio app and wait for RPC to start the tests\n");
1408 }
1409 
1410 static int
1411 bdevio_parse_arg(int ch, char *arg)
1412 {
1413 	switch (ch) {
1414 	case 'w':
1415 		g_wait_for_tests =  true;
1416 		break;
1417 	default:
1418 		return -EINVAL;
1419 	}
1420 	return 0;
1421 }
1422 
1423 struct rpc_perform_tests {
1424 	char *name;
1425 };
1426 
1427 static void
1428 free_rpc_perform_tests(struct rpc_perform_tests *r)
1429 {
1430 	free(r->name);
1431 }
1432 
1433 static const struct spdk_json_object_decoder rpc_perform_tests_decoders[] = {
1434 	{"name", offsetof(struct rpc_perform_tests, name), spdk_json_decode_string, true},
1435 };
1436 
1437 static void
1438 rpc_perform_tests_cb(unsigned num_failures, struct spdk_jsonrpc_request *request)
1439 {
1440 	struct spdk_json_write_ctx *w;
1441 
1442 	if (num_failures == 0) {
1443 		w = spdk_jsonrpc_begin_result(request);
1444 		spdk_json_write_uint32(w, num_failures);
1445 		spdk_jsonrpc_end_result(request, w);
1446 	} else {
1447 		spdk_jsonrpc_send_error_response_fmt(request, SPDK_JSONRPC_ERROR_INTERNAL_ERROR,
1448 						     "%d test cases failed", num_failures);
1449 	}
1450 }
1451 
1452 static void
1453 rpc_perform_tests(struct spdk_jsonrpc_request *request, const struct spdk_json_val *params)
1454 {
1455 	struct rpc_perform_tests req = {NULL};
1456 	struct spdk_bdev *bdev;
1457 	int rc;
1458 
1459 	if (params && spdk_json_decode_object(params, rpc_perform_tests_decoders,
1460 					      SPDK_COUNTOF(rpc_perform_tests_decoders),
1461 					      &req)) {
1462 		SPDK_ERRLOG("spdk_json_decode_object failed\n");
1463 		spdk_jsonrpc_send_error_response(request, SPDK_JSONRPC_ERROR_INVALID_PARAMS, "Invalid parameters");
1464 		goto invalid;
1465 	}
1466 
1467 	if (req.name) {
1468 		bdev = spdk_bdev_get_by_name(req.name);
1469 		if (bdev == NULL) {
1470 			SPDK_ERRLOG("Bdev '%s' does not exist\n", req.name);
1471 			spdk_jsonrpc_send_error_response_fmt(request, SPDK_JSONRPC_ERROR_INTERNAL_ERROR,
1472 							     "Bdev '%s' does not exist: %s",
1473 							     req.name, spdk_strerror(ENODEV));
1474 			goto invalid;
1475 		}
1476 		rc = bdevio_construct_target(bdev);
1477 		if (rc < 0) {
1478 			SPDK_ERRLOG("Could not construct target for bdev '%s'\n", spdk_bdev_get_name(bdev));
1479 			spdk_jsonrpc_send_error_response_fmt(request, SPDK_JSONRPC_ERROR_INTERNAL_ERROR,
1480 							     "Could not construct target for bdev '%s': %s",
1481 							     spdk_bdev_get_name(bdev), spdk_strerror(-rc));
1482 			goto invalid;
1483 		}
1484 	} else {
1485 		rc = bdevio_construct_targets();
1486 		if (rc < 0) {
1487 			SPDK_ERRLOG("Could not construct targets for all bdevs\n");
1488 			spdk_jsonrpc_send_error_response_fmt(request, SPDK_JSONRPC_ERROR_INTERNAL_ERROR,
1489 							     "Could not construct targets for all bdevs: %s",
1490 							     spdk_strerror(-rc));
1491 			goto invalid;
1492 		}
1493 	}
1494 	free_rpc_perform_tests(&req);
1495 
1496 	spdk_thread_send_msg(g_thread_ut, __run_ut_thread, request);
1497 
1498 	return;
1499 
1500 invalid:
1501 	free_rpc_perform_tests(&req);
1502 }
1503 SPDK_RPC_REGISTER("perform_tests", rpc_perform_tests, SPDK_RPC_RUNTIME)
1504 
1505 static void
1506 spdk_bdevio_shutdown_cb(void)
1507 {
1508 	g_shutdown = true;
1509 	spdk_thread_send_msg(g_thread_init, __stop_init_thread, NULL);
1510 }
1511 
1512 int
1513 main(int argc, char **argv)
1514 {
1515 	int			rc;
1516 	struct spdk_app_opts	opts = {};
1517 
1518 	spdk_app_opts_init(&opts, sizeof(opts));
1519 	opts.name = "bdevio";
1520 	opts.reactor_mask = "0x7";
1521 	opts.shutdown_cb = spdk_bdevio_shutdown_cb;
1522 
1523 	if ((rc = spdk_app_parse_args(argc, argv, &opts, "w", NULL,
1524 				      bdevio_parse_arg, bdevio_usage)) !=
1525 	    SPDK_APP_PARSE_ARGS_SUCCESS) {
1526 		return rc;
1527 	}
1528 
1529 	rc = spdk_app_start(&opts, test_main, NULL);
1530 	spdk_app_fini();
1531 
1532 	return rc;
1533 }
1534