xref: /spdk/test/unit/lib/bdev/bdev.c/bdev_ut.c (revision ff173863b114ffb0d2b86e2825badcc504fc5fa1)
1488570ebSJim Harris /*   SPDX-License-Identifier: BSD-3-Clause
2a6dbe372Spaul luse  *   Copyright (C) 2017 Intel Corporation. All rights reserved.
3437e54f7SEvgeniy Kochetov  *   Copyright (c) 2019 Mellanox Technologies LTD. All rights reserved.
44bb902a6SMike Gerdts  *   Copyright (c) 2021-2023 NVIDIA CORPORATION & AFFILIATES. All rights reserved.
54ee51dcbSJim Harris  */
64ee51dcbSJim Harris 
7ae431e31SKonrad Sztyber #include "spdk_internal/cunit.h"
84ee51dcbSJim Harris 
9270a25dfSBen Walker #include "common/lib/ut_multithread.c"
105ffa5c00SPawel Wodkowski #include "unit/lib/json_mock.c"
11229f6494SDaniel Verkamp 
12c4fee1e9SPawel Wodkowski #include "spdk/config.h"
13229f6494SDaniel Verkamp /* HACK: disable VTune integration so the unit test doesn't need VTune headers and libs to build */
14229f6494SDaniel Verkamp #undef SPDK_CONFIG_VTUNE
15229f6494SDaniel Verkamp 
16d8c3ff5fSJim Harris #include "bdev/bdev.c"
174ee51dcbSJim Harris 
18*ff173863SShuhei Matsumoto #include "common/lib/bdev/common_stubs.h"
191299439fSAlexey Marchuk 
201299439fSAlexey Marchuk static bool g_memory_domain_pull_data_called;
211299439fSAlexey Marchuk static bool g_memory_domain_push_data_called;
2280b22cf3SKonrad Sztyber static int g_accel_io_device;
231299439fSAlexey Marchuk 
241299439fSAlexey Marchuk DEFINE_RETURN_MOCK(spdk_memory_domain_pull_data, int);
251299439fSAlexey Marchuk int
261299439fSAlexey Marchuk spdk_memory_domain_pull_data(struct spdk_memory_domain *src_domain, void *src_domain_ctx,
271299439fSAlexey Marchuk 			     struct iovec *src_iov, uint32_t src_iov_cnt, struct iovec *dst_iov, uint32_t dst_iov_cnt,
281299439fSAlexey Marchuk 			     spdk_memory_domain_data_cpl_cb cpl_cb, void *cpl_cb_arg)
291299439fSAlexey Marchuk {
301299439fSAlexey Marchuk 	g_memory_domain_pull_data_called = true;
311299439fSAlexey Marchuk 	HANDLE_RETURN_MOCK(spdk_memory_domain_pull_data);
321299439fSAlexey Marchuk 	cpl_cb(cpl_cb_arg, 0);
331299439fSAlexey Marchuk 	return 0;
341299439fSAlexey Marchuk }
351299439fSAlexey Marchuk 
361299439fSAlexey Marchuk DEFINE_RETURN_MOCK(spdk_memory_domain_push_data, int);
371299439fSAlexey Marchuk int
381299439fSAlexey Marchuk spdk_memory_domain_push_data(struct spdk_memory_domain *dst_domain, void *dst_domain_ctx,
391299439fSAlexey Marchuk 			     struct iovec *dst_iov, uint32_t dst_iovcnt, struct iovec *src_iov, uint32_t src_iovcnt,
401299439fSAlexey Marchuk 			     spdk_memory_domain_data_cpl_cb cpl_cb, void *cpl_cb_arg)
411299439fSAlexey Marchuk {
421299439fSAlexey Marchuk 	g_memory_domain_push_data_called = true;
431299439fSAlexey Marchuk 	HANDLE_RETURN_MOCK(spdk_memory_domain_push_data);
441299439fSAlexey Marchuk 	cpl_cb(cpl_cb_arg, 0);
451299439fSAlexey Marchuk 	return 0;
461299439fSAlexey Marchuk }
471d83a09dSPiotr Pelplinski 
4880b22cf3SKonrad Sztyber struct spdk_io_channel *
4980b22cf3SKonrad Sztyber spdk_accel_get_io_channel(void)
5080b22cf3SKonrad Sztyber {
5180b22cf3SKonrad Sztyber 	return spdk_get_io_channel(&g_accel_io_device);
5280b22cf3SKonrad Sztyber }
5380b22cf3SKonrad Sztyber 
5442dba604SPiotr Pelplinski int g_status;
5542dba604SPiotr Pelplinski int g_count;
5679ed1ba1SMaciej Szwed enum spdk_bdev_event_type g_event_type1;
5779ed1ba1SMaciej Szwed enum spdk_bdev_event_type g_event_type2;
587bcd316dSGangCao enum spdk_bdev_event_type g_event_type3;
597bcd316dSGangCao enum spdk_bdev_event_type g_event_type4;
6042dba604SPiotr Pelplinski struct spdk_histogram_data *g_histogram;
6123975858SEvgeniy Kochetov void *g_unregister_arg;
6223975858SEvgeniy Kochetov int g_unregister_rc;
6342dba604SPiotr Pelplinski 
644ee51dcbSJim Harris void
654ee51dcbSJim Harris spdk_scsi_nvme_translate(const struct spdk_bdev_io *bdev_io,
664ee51dcbSJim Harris 			 int *sc, int *sk, int *asc, int *ascq)
674ee51dcbSJim Harris {
684ee51dcbSJim Harris }
694ee51dcbSJim Harris 
704ee51dcbSJim Harris static int
7180b22cf3SKonrad Sztyber ut_accel_ch_create_cb(void *io_device, void *ctx)
724ee51dcbSJim Harris {
734ee51dcbSJim Harris 	return 0;
744ee51dcbSJim Harris }
754ee51dcbSJim Harris 
7680b22cf3SKonrad Sztyber static void
7780b22cf3SKonrad Sztyber ut_accel_ch_destroy_cb(void *io_device, void *ctx)
784ee51dcbSJim Harris {
7980b22cf3SKonrad Sztyber }
8080b22cf3SKonrad Sztyber 
8180b22cf3SKonrad Sztyber static int
8280b22cf3SKonrad Sztyber ut_bdev_setup(void)
8380b22cf3SKonrad Sztyber {
8480b22cf3SKonrad Sztyber 	spdk_io_device_register(&g_accel_io_device, ut_accel_ch_create_cb,
8580b22cf3SKonrad Sztyber 				ut_accel_ch_destroy_cb, 0, NULL);
8680b22cf3SKonrad Sztyber 	return 0;
8780b22cf3SKonrad Sztyber }
8880b22cf3SKonrad Sztyber 
8980b22cf3SKonrad Sztyber static int
9080b22cf3SKonrad Sztyber ut_bdev_teardown(void)
9180b22cf3SKonrad Sztyber {
9280b22cf3SKonrad Sztyber 	spdk_io_device_unregister(&g_accel_io_device, NULL);
9380b22cf3SKonrad Sztyber 
944ee51dcbSJim Harris 	return 0;
954ee51dcbSJim Harris }
964ee51dcbSJim Harris 
9757d174ffSJim Harris static int
9857d174ffSJim Harris stub_destruct(void *ctx)
994ee51dcbSJim Harris {
10057d174ffSJim Harris 	return 0;
10157d174ffSJim Harris }
10257d174ffSJim Harris 
1033c7894ffSShuhei Matsumoto struct ut_expected_io {
1043c7894ffSShuhei Matsumoto 	uint8_t				type;
1053c7894ffSShuhei Matsumoto 	uint64_t			offset;
1066c8702acSEvgeniy Kochetov 	uint64_t			src_offset;
1073c7894ffSShuhei Matsumoto 	uint64_t			length;
1083c7894ffSShuhei Matsumoto 	int				iovcnt;
109b45556e2SChangpeng Liu 	struct iovec			iov[SPDK_BDEV_IO_NUM_CHILD_IOV];
110e2918289SKonrad Sztyber 	void				*md_buf;
1113c7894ffSShuhei Matsumoto 	TAILQ_ENTRY(ut_expected_io)	link;
1123c7894ffSShuhei Matsumoto };
1133c7894ffSShuhei Matsumoto 
114dc996557SBen Walker struct bdev_ut_io {
115dc996557SBen Walker 	TAILQ_ENTRY(bdev_ut_io)		link;
116dc996557SBen Walker };
117dc996557SBen Walker 
11832d7c91cSJim Harris struct bdev_ut_channel {
119dc996557SBen Walker 	TAILQ_HEAD(, bdev_ut_io)	outstanding_io;
12032d7c91cSJim Harris 	uint32_t			outstanding_io_count;
1213c7894ffSShuhei Matsumoto 	TAILQ_HEAD(, ut_expected_io)	expected_io;
12232d7c91cSJim Harris };
12332d7c91cSJim Harris 
1244bd97621SJim Harris static bool g_io_done;
125dadd2a6dSPiotr Pelplinski static struct spdk_bdev_io *g_bdev_io;
1260df515a8SShuhei Matsumoto static enum spdk_bdev_io_status g_io_status;
127c55c85f8SChangpeng Liu static enum spdk_bdev_io_status g_io_exp_status = SPDK_BDEV_IO_STATUS_SUCCESS;
12832d7c91cSJim Harris static uint32_t g_bdev_ut_io_device;
12932d7c91cSJim Harris static struct bdev_ut_channel *g_bdev_ut_channel;
130ae43c81aSJim Harris static void *g_compare_read_buf;
131ae43c81aSJim Harris static uint32_t g_compare_read_buf_len;
132ae43c81aSJim Harris static void *g_compare_write_buf;
133ae43c81aSJim Harris static uint32_t g_compare_write_buf_len;
1340bd6b7f2SJonas Pfefferle static void *g_compare_md_buf;
1357cd20dd3SShuhei Matsumoto static bool g_abort_done;
1367cd20dd3SShuhei Matsumoto static enum spdk_bdev_io_status g_abort_status;
1376127461cSmatthewb static void *g_zcopy_read_buf;
1386127461cSmatthewb static uint32_t g_zcopy_read_buf_len;
1396127461cSmatthewb static void *g_zcopy_write_buf;
1406127461cSmatthewb static uint32_t g_zcopy_write_buf_len;
1416127461cSmatthewb static struct spdk_bdev_io *g_zcopy_bdev_io;
1426defafc9SDamiano static uint64_t g_seek_data_offset;
1436defafc9SDamiano static uint64_t g_seek_hole_offset;
1446defafc9SDamiano static uint64_t g_seek_offset;
14532d7c91cSJim Harris 
1463c7894ffSShuhei Matsumoto static struct ut_expected_io *
1473c7894ffSShuhei Matsumoto ut_alloc_expected_io(uint8_t type, uint64_t offset, uint64_t length, int iovcnt)
1483c7894ffSShuhei Matsumoto {
1493c7894ffSShuhei Matsumoto 	struct ut_expected_io *expected_io;
1503c7894ffSShuhei Matsumoto 
1513c7894ffSShuhei Matsumoto 	expected_io = calloc(1, sizeof(*expected_io));
1523c7894ffSShuhei Matsumoto 	SPDK_CU_ASSERT_FATAL(expected_io != NULL);
1533c7894ffSShuhei Matsumoto 
1543c7894ffSShuhei Matsumoto 	expected_io->type = type;
1553c7894ffSShuhei Matsumoto 	expected_io->offset = offset;
1563c7894ffSShuhei Matsumoto 	expected_io->length = length;
1573c7894ffSShuhei Matsumoto 	expected_io->iovcnt = iovcnt;
1583c7894ffSShuhei Matsumoto 
1593c7894ffSShuhei Matsumoto 	return expected_io;
1603c7894ffSShuhei Matsumoto }
1613c7894ffSShuhei Matsumoto 
1626c8702acSEvgeniy Kochetov static struct ut_expected_io *
1636c8702acSEvgeniy Kochetov ut_alloc_expected_copy_io(uint8_t type, uint64_t offset, uint64_t src_offset, uint64_t length)
1646c8702acSEvgeniy Kochetov {
1656c8702acSEvgeniy Kochetov 	struct ut_expected_io *expected_io;
1666c8702acSEvgeniy Kochetov 
1676c8702acSEvgeniy Kochetov 	expected_io = calloc(1, sizeof(*expected_io));
1686c8702acSEvgeniy Kochetov 	SPDK_CU_ASSERT_FATAL(expected_io != NULL);
1696c8702acSEvgeniy Kochetov 
1706c8702acSEvgeniy Kochetov 	expected_io->type = type;
1716c8702acSEvgeniy Kochetov 	expected_io->offset = offset;
1726c8702acSEvgeniy Kochetov 	expected_io->src_offset = src_offset;
1736c8702acSEvgeniy Kochetov 	expected_io->length = length;
1746c8702acSEvgeniy Kochetov 
1756c8702acSEvgeniy Kochetov 	return expected_io;
1766c8702acSEvgeniy Kochetov }
1776c8702acSEvgeniy Kochetov 
1783c7894ffSShuhei Matsumoto static void
1793c7894ffSShuhei Matsumoto ut_expected_io_set_iov(struct ut_expected_io *expected_io, int pos, void *base, size_t len)
1803c7894ffSShuhei Matsumoto {
1813c7894ffSShuhei Matsumoto 	expected_io->iov[pos].iov_base = base;
1823c7894ffSShuhei Matsumoto 	expected_io->iov[pos].iov_len = len;
1833c7894ffSShuhei Matsumoto }
1843c7894ffSShuhei Matsumoto 
18532d7c91cSJim Harris static void
18632d7c91cSJim Harris stub_submit_request(struct spdk_io_channel *_ch, struct spdk_bdev_io *bdev_io)
18732d7c91cSJim Harris {
18832d7c91cSJim Harris 	struct bdev_ut_channel *ch = spdk_io_channel_get_ctx(_ch);
1893c7894ffSShuhei Matsumoto 	struct ut_expected_io *expected_io;
1904bd97621SJim Harris 	struct iovec *iov, *expected_iov;
1917cd20dd3SShuhei Matsumoto 	struct spdk_bdev_io *bio_to_abort;
192dc996557SBen Walker 	struct bdev_ut_io *bio;
1934bd97621SJim Harris 	int i;
19432d7c91cSJim Harris 
195dadd2a6dSPiotr Pelplinski 	g_bdev_io = bdev_io;
196dadd2a6dSPiotr Pelplinski 
197ae43c81aSJim Harris 	if (g_compare_read_buf && bdev_io->type == SPDK_BDEV_IO_TYPE_READ) {
198ae43c81aSJim Harris 		uint32_t len = bdev_io->u.bdev.iovs[0].iov_len;
199ae43c81aSJim Harris 
200ae43c81aSJim Harris 		CU_ASSERT(bdev_io->u.bdev.iovcnt == 1);
201ae43c81aSJim Harris 		CU_ASSERT(g_compare_read_buf_len == len);
202ae43c81aSJim Harris 		memcpy(bdev_io->u.bdev.iovs[0].iov_base, g_compare_read_buf, len);
2030bd6b7f2SJonas Pfefferle 		if (bdev_io->bdev->md_len && bdev_io->u.bdev.md_buf && g_compare_md_buf) {
2040bd6b7f2SJonas Pfefferle 			memcpy(bdev_io->u.bdev.md_buf, g_compare_md_buf,
2050bd6b7f2SJonas Pfefferle 			       bdev_io->bdev->md_len * bdev_io->u.bdev.num_blocks);
2060bd6b7f2SJonas Pfefferle 		}
207ae43c81aSJim Harris 	}
208ae43c81aSJim Harris 
209ae43c81aSJim Harris 	if (g_compare_write_buf && bdev_io->type == SPDK_BDEV_IO_TYPE_WRITE) {
210ae43c81aSJim Harris 		uint32_t len = bdev_io->u.bdev.iovs[0].iov_len;
211ae43c81aSJim Harris 
212ae43c81aSJim Harris 		CU_ASSERT(bdev_io->u.bdev.iovcnt == 1);
213ae43c81aSJim Harris 		CU_ASSERT(g_compare_write_buf_len == len);
214ae43c81aSJim Harris 		memcpy(g_compare_write_buf, bdev_io->u.bdev.iovs[0].iov_base, len);
215ae43c81aSJim Harris 	}
216ae43c81aSJim Harris 
217ca0eeaabSMaciej Szwed 	if (g_compare_read_buf && bdev_io->type == SPDK_BDEV_IO_TYPE_COMPARE) {
218ca0eeaabSMaciej Szwed 		uint32_t len = bdev_io->u.bdev.iovs[0].iov_len;
219ca0eeaabSMaciej Szwed 
220ca0eeaabSMaciej Szwed 		CU_ASSERT(bdev_io->u.bdev.iovcnt == 1);
221ca0eeaabSMaciej Szwed 		CU_ASSERT(g_compare_read_buf_len == len);
222ca0eeaabSMaciej Szwed 		if (memcmp(bdev_io->u.bdev.iovs[0].iov_base, g_compare_read_buf, len)) {
223ca0eeaabSMaciej Szwed 			g_io_exp_status = SPDK_BDEV_IO_STATUS_MISCOMPARE;
224ca0eeaabSMaciej Szwed 		}
2250bd6b7f2SJonas Pfefferle 		if (bdev_io->u.bdev.md_buf &&
2260bd6b7f2SJonas Pfefferle 		    memcmp(bdev_io->u.bdev.md_buf, g_compare_md_buf,
2270bd6b7f2SJonas Pfefferle 			   bdev_io->bdev->md_len * bdev_io->u.bdev.num_blocks)) {
2280bd6b7f2SJonas Pfefferle 			g_io_exp_status = SPDK_BDEV_IO_STATUS_MISCOMPARE;
2290bd6b7f2SJonas Pfefferle 		}
230ca0eeaabSMaciej Szwed 	}
231ca0eeaabSMaciej Szwed 
2327cd20dd3SShuhei Matsumoto 	if (bdev_io->type == SPDK_BDEV_IO_TYPE_ABORT) {
2337cd20dd3SShuhei Matsumoto 		if (g_io_exp_status == SPDK_BDEV_IO_STATUS_SUCCESS) {
234dc996557SBen Walker 			TAILQ_FOREACH(bio, &ch->outstanding_io, link) {
235dc996557SBen Walker 				bio_to_abort = spdk_bdev_io_from_ctx(bio);
2367cd20dd3SShuhei Matsumoto 				if (bio_to_abort == bdev_io->u.abort.bio_to_abort) {
237dc996557SBen Walker 					TAILQ_REMOVE(&ch->outstanding_io, bio, link);
2387cd20dd3SShuhei Matsumoto 					ch->outstanding_io_count--;
2397cd20dd3SShuhei Matsumoto 					spdk_bdev_io_complete(bio_to_abort, SPDK_BDEV_IO_STATUS_FAILED);
2407cd20dd3SShuhei Matsumoto 					break;
2417cd20dd3SShuhei Matsumoto 				}
2427cd20dd3SShuhei Matsumoto 			}
2437cd20dd3SShuhei Matsumoto 		}
2447cd20dd3SShuhei Matsumoto 	}
2457cd20dd3SShuhei Matsumoto 
2466127461cSmatthewb 	if (bdev_io->type == SPDK_BDEV_IO_TYPE_ZCOPY) {
2476127461cSmatthewb 		if (bdev_io->u.bdev.zcopy.start) {
2486127461cSmatthewb 			g_zcopy_bdev_io = bdev_io;
2496127461cSmatthewb 			if (bdev_io->u.bdev.zcopy.populate) {
2506127461cSmatthewb 				/* Start of a read */
2516127461cSmatthewb 				CU_ASSERT(g_zcopy_read_buf != NULL);
2526127461cSmatthewb 				CU_ASSERT(g_zcopy_read_buf_len > 0);
2536127461cSmatthewb 				bdev_io->u.bdev.iovs[0].iov_base = g_zcopy_read_buf;
2546127461cSmatthewb 				bdev_io->u.bdev.iovs[0].iov_len = g_zcopy_read_buf_len;
2556127461cSmatthewb 				bdev_io->u.bdev.iovcnt = 1;
2566127461cSmatthewb 			} else {
2576127461cSmatthewb 				/* Start of a write */
2586127461cSmatthewb 				CU_ASSERT(g_zcopy_write_buf != NULL);
2596127461cSmatthewb 				CU_ASSERT(g_zcopy_write_buf_len > 0);
2606127461cSmatthewb 				bdev_io->u.bdev.iovs[0].iov_base = g_zcopy_write_buf;
2616127461cSmatthewb 				bdev_io->u.bdev.iovs[0].iov_len = g_zcopy_write_buf_len;
2626127461cSmatthewb 				bdev_io->u.bdev.iovcnt = 1;
2636127461cSmatthewb 			}
2646127461cSmatthewb 		} else {
2656127461cSmatthewb 			if (bdev_io->u.bdev.zcopy.commit) {
2666127461cSmatthewb 				/* End of write */
2676127461cSmatthewb 				CU_ASSERT(bdev_io->u.bdev.iovs[0].iov_base == g_zcopy_write_buf);
2686127461cSmatthewb 				CU_ASSERT(bdev_io->u.bdev.iovs[0].iov_len == g_zcopy_write_buf_len);
2696127461cSmatthewb 				CU_ASSERT(bdev_io->u.bdev.iovcnt == 1);
2706127461cSmatthewb 				g_zcopy_write_buf = NULL;
2716127461cSmatthewb 				g_zcopy_write_buf_len = 0;
2726127461cSmatthewb 			} else {
2736127461cSmatthewb 				/* End of read */
2746127461cSmatthewb 				CU_ASSERT(bdev_io->u.bdev.iovs[0].iov_base == g_zcopy_read_buf);
2756127461cSmatthewb 				CU_ASSERT(bdev_io->u.bdev.iovs[0].iov_len == g_zcopy_read_buf_len);
2766127461cSmatthewb 				CU_ASSERT(bdev_io->u.bdev.iovcnt == 1);
2776127461cSmatthewb 				g_zcopy_read_buf = NULL;
2786127461cSmatthewb 				g_zcopy_read_buf_len = 0;
2796127461cSmatthewb 			}
2806127461cSmatthewb 		}
2816127461cSmatthewb 	}
2826127461cSmatthewb 
2836defafc9SDamiano 	if (bdev_io->type == SPDK_BDEV_IO_TYPE_SEEK_DATA) {
2846defafc9SDamiano 		bdev_io->u.bdev.seek.offset = g_seek_data_offset;
2856defafc9SDamiano 	}
2866defafc9SDamiano 
2876defafc9SDamiano 	if (bdev_io->type == SPDK_BDEV_IO_TYPE_SEEK_HOLE) {
2886defafc9SDamiano 		bdev_io->u.bdev.seek.offset = g_seek_hole_offset;
2896defafc9SDamiano 	}
2906defafc9SDamiano 
291dc996557SBen Walker 	TAILQ_INSERT_TAIL(&ch->outstanding_io, (struct bdev_ut_io *)bdev_io->driver_ctx, link);
29232d7c91cSJim Harris 	ch->outstanding_io_count++;
2934bd97621SJim Harris 
2943c7894ffSShuhei Matsumoto 	expected_io = TAILQ_FIRST(&ch->expected_io);
2953c7894ffSShuhei Matsumoto 	if (expected_io == NULL) {
2963c7894ffSShuhei Matsumoto 		return;
2973c7894ffSShuhei Matsumoto 	}
2983c7894ffSShuhei Matsumoto 	TAILQ_REMOVE(&ch->expected_io, expected_io, link);
2993c7894ffSShuhei Matsumoto 
3003c7894ffSShuhei Matsumoto 	if (expected_io->type != SPDK_BDEV_IO_TYPE_INVALID) {
3013c7894ffSShuhei Matsumoto 		CU_ASSERT(bdev_io->type == expected_io->type);
3024bd97621SJim Harris 	}
3034bd97621SJim Harris 
304e2918289SKonrad Sztyber 	if (expected_io->md_buf != NULL) {
305e2918289SKonrad Sztyber 		CU_ASSERT(expected_io->md_buf == bdev_io->u.bdev.md_buf);
306442e13c0SJonas Pfefferle 	}
307442e13c0SJonas Pfefferle 
3083c7894ffSShuhei Matsumoto 	if (expected_io->length == 0) {
3093c7894ffSShuhei Matsumoto 		free(expected_io);
3104bd97621SJim Harris 		return;
3114bd97621SJim Harris 	}
3124bd97621SJim Harris 
3133c7894ffSShuhei Matsumoto 	CU_ASSERT(expected_io->offset == bdev_io->u.bdev.offset_blocks);
314c26697bfSSlawomir Ptak 	CU_ASSERT(expected_io->length == bdev_io->u.bdev.num_blocks);
3156c8702acSEvgeniy Kochetov 	if (expected_io->type == SPDK_BDEV_IO_TYPE_COPY) {
3166c8702acSEvgeniy Kochetov 		CU_ASSERT(expected_io->src_offset == bdev_io->u.bdev.copy.src_offset_blocks);
3176c8702acSEvgeniy Kochetov 	}
3184bd97621SJim Harris 
3193c7894ffSShuhei Matsumoto 	if (expected_io->iovcnt == 0) {
3203c7894ffSShuhei Matsumoto 		free(expected_io);
3216c8702acSEvgeniy Kochetov 		/* UNMAP, WRITE_ZEROES, FLUSH and COPY don't have iovs, so we can just return now. */
3224bd97621SJim Harris 		return;
3234bd97621SJim Harris 	}
3244bd97621SJim Harris 
3253c7894ffSShuhei Matsumoto 	CU_ASSERT(expected_io->iovcnt == bdev_io->u.bdev.iovcnt);
3263c7894ffSShuhei Matsumoto 	for (i = 0; i < expected_io->iovcnt; i++) {
3273c7894ffSShuhei Matsumoto 		expected_iov = &expected_io->iov[i];
3287fee8002SBen Walker 		if (bdev_io->internal.f.has_bounce_buf == false) {
329c03985a0SAlexey Marchuk 			iov = &bdev_io->u.bdev.iovs[i];
330c03985a0SAlexey Marchuk 		} else {
3317fee8002SBen Walker 			iov = bdev_io->internal.bounce_buf.orig_iovs;
332c03985a0SAlexey Marchuk 		}
3334bd97621SJim Harris 		CU_ASSERT(iov->iov_len == expected_iov->iov_len);
3344bd97621SJim Harris 		CU_ASSERT(iov->iov_base == expected_iov->iov_base);
3354bd97621SJim Harris 	}
3363c7894ffSShuhei Matsumoto 
3373c7894ffSShuhei Matsumoto 	free(expected_io);
33832d7c91cSJim Harris }
33932d7c91cSJim Harris 
340dadd2a6dSPiotr Pelplinski static void
34180da9548SMaciej Szwed stub_submit_request_get_buf_cb(struct spdk_io_channel *_ch,
3424b92ffb3SShuhei Matsumoto 			       struct spdk_bdev_io *bdev_io, bool success)
3434b92ffb3SShuhei Matsumoto {
3444b92ffb3SShuhei Matsumoto 	CU_ASSERT(success == true);
3454b92ffb3SShuhei Matsumoto 
3464b92ffb3SShuhei Matsumoto 	stub_submit_request(_ch, bdev_io);
3474b92ffb3SShuhei Matsumoto }
3484b92ffb3SShuhei Matsumoto 
3494b92ffb3SShuhei Matsumoto static void
35080da9548SMaciej Szwed stub_submit_request_get_buf(struct spdk_io_channel *_ch, struct spdk_bdev_io *bdev_io)
351dadd2a6dSPiotr Pelplinski {
35280da9548SMaciej Szwed 	spdk_bdev_io_get_buf(bdev_io, stub_submit_request_get_buf_cb,
353dadd2a6dSPiotr Pelplinski 			     bdev_io->u.bdev.num_blocks * bdev_io->bdev->blocklen);
354dadd2a6dSPiotr Pelplinski }
355dadd2a6dSPiotr Pelplinski 
35632d7c91cSJim Harris static uint32_t
35732d7c91cSJim Harris stub_complete_io(uint32_t num_to_complete)
35832d7c91cSJim Harris {
35932d7c91cSJim Harris 	struct bdev_ut_channel *ch = g_bdev_ut_channel;
360dc996557SBen Walker 	struct bdev_ut_io *bio;
36132d7c91cSJim Harris 	struct spdk_bdev_io *bdev_io;
362c55c85f8SChangpeng Liu 	static enum spdk_bdev_io_status io_status;
36332d7c91cSJim Harris 	uint32_t num_completed = 0;
36432d7c91cSJim Harris 
36532d7c91cSJim Harris 	while (num_completed < num_to_complete) {
36632d7c91cSJim Harris 		if (TAILQ_EMPTY(&ch->outstanding_io)) {
36732d7c91cSJim Harris 			break;
36832d7c91cSJim Harris 		}
369dc996557SBen Walker 		bio = TAILQ_FIRST(&ch->outstanding_io);
370dc996557SBen Walker 		TAILQ_REMOVE(&ch->outstanding_io, bio, link);
371dc996557SBen Walker 		bdev_io = spdk_bdev_io_from_ctx(bio);
37232d7c91cSJim Harris 		ch->outstanding_io_count--;
373c55c85f8SChangpeng Liu 		io_status = g_io_exp_status == SPDK_BDEV_IO_STATUS_SUCCESS ? SPDK_BDEV_IO_STATUS_SUCCESS :
374c55c85f8SChangpeng Liu 			    g_io_exp_status;
375c55c85f8SChangpeng Liu 		spdk_bdev_io_complete(bdev_io, io_status);
37632d7c91cSJim Harris 		num_completed++;
37732d7c91cSJim Harris 	}
37832d7c91cSJim Harris 
37932d7c91cSJim Harris 	return num_completed;
38032d7c91cSJim Harris }
38132d7c91cSJim Harris 
38232d7c91cSJim Harris static struct spdk_io_channel *
38332d7c91cSJim Harris bdev_ut_get_io_channel(void *ctx)
38432d7c91cSJim Harris {
38532d7c91cSJim Harris 	return spdk_get_io_channel(&g_bdev_ut_io_device);
38632d7c91cSJim Harris }
38732d7c91cSJim Harris 
388e2918289SKonrad Sztyber static bool g_io_types_supported[SPDK_BDEV_NUM_IO_TYPES] = {
389e2918289SKonrad Sztyber 	[SPDK_BDEV_IO_TYPE_READ]		= true,
390e2918289SKonrad Sztyber 	[SPDK_BDEV_IO_TYPE_WRITE]		= true,
391bee042e4SMaciej Szwed 	[SPDK_BDEV_IO_TYPE_COMPARE]		= true,
392e2918289SKonrad Sztyber 	[SPDK_BDEV_IO_TYPE_UNMAP]		= true,
393e2918289SKonrad Sztyber 	[SPDK_BDEV_IO_TYPE_FLUSH]		= true,
394e2918289SKonrad Sztyber 	[SPDK_BDEV_IO_TYPE_RESET]		= true,
395e2918289SKonrad Sztyber 	[SPDK_BDEV_IO_TYPE_NVME_ADMIN]		= true,
396e2918289SKonrad Sztyber 	[SPDK_BDEV_IO_TYPE_NVME_IO]		= true,
397e2918289SKonrad Sztyber 	[SPDK_BDEV_IO_TYPE_NVME_IO_MD]		= true,
398e2918289SKonrad Sztyber 	[SPDK_BDEV_IO_TYPE_WRITE_ZEROES]	= true,
399e2918289SKonrad Sztyber 	[SPDK_BDEV_IO_TYPE_ZCOPY]		= true,
4007cd20dd3SShuhei Matsumoto 	[SPDK_BDEV_IO_TYPE_ABORT]		= true,
4016defafc9SDamiano 	[SPDK_BDEV_IO_TYPE_SEEK_HOLE]		= true,
4026defafc9SDamiano 	[SPDK_BDEV_IO_TYPE_SEEK_DATA]		= true,
4036c8702acSEvgeniy Kochetov 	[SPDK_BDEV_IO_TYPE_COPY]		= true,
404e2918289SKonrad Sztyber };
405e2918289SKonrad Sztyber 
406e2918289SKonrad Sztyber static void
407e2918289SKonrad Sztyber ut_enable_io_type(enum spdk_bdev_io_type io_type, bool enable)
408e2918289SKonrad Sztyber {
409e2918289SKonrad Sztyber 	g_io_types_supported[io_type] = enable;
410e2918289SKonrad Sztyber }
411e2918289SKonrad Sztyber 
412e2918289SKonrad Sztyber static bool
413e2918289SKonrad Sztyber stub_io_type_supported(void *_bdev, enum spdk_bdev_io_type io_type)
414e2918289SKonrad Sztyber {
415e2918289SKonrad Sztyber 	return g_io_types_supported[io_type];
416e2918289SKonrad Sztyber }
4174bd97621SJim Harris 
41857d174ffSJim Harris static struct spdk_bdev_fn_table fn_table = {
41957d174ffSJim Harris 	.destruct = stub_destruct,
42032d7c91cSJim Harris 	.submit_request = stub_submit_request,
42132d7c91cSJim Harris 	.get_io_channel = bdev_ut_get_io_channel,
4224bd97621SJim Harris 	.io_type_supported = stub_io_type_supported,
42357d174ffSJim Harris };
42457d174ffSJim Harris 
42532d7c91cSJim Harris static int
42632d7c91cSJim Harris bdev_ut_create_ch(void *io_device, void *ctx_buf)
42732d7c91cSJim Harris {
42832d7c91cSJim Harris 	struct bdev_ut_channel *ch = ctx_buf;
42932d7c91cSJim Harris 
43032d7c91cSJim Harris 	CU_ASSERT(g_bdev_ut_channel == NULL);
43132d7c91cSJim Harris 	g_bdev_ut_channel = ch;
43232d7c91cSJim Harris 
43332d7c91cSJim Harris 	TAILQ_INIT(&ch->outstanding_io);
43432d7c91cSJim Harris 	ch->outstanding_io_count = 0;
4353c7894ffSShuhei Matsumoto 	TAILQ_INIT(&ch->expected_io);
43632d7c91cSJim Harris 	return 0;
43732d7c91cSJim Harris }
43832d7c91cSJim Harris 
43932d7c91cSJim Harris static void
44032d7c91cSJim Harris bdev_ut_destroy_ch(void *io_device, void *ctx_buf)
44132d7c91cSJim Harris {
44232d7c91cSJim Harris 	CU_ASSERT(g_bdev_ut_channel != NULL);
44332d7c91cSJim Harris 	g_bdev_ut_channel = NULL;
44432d7c91cSJim Harris }
44532d7c91cSJim Harris 
446d83a3489STomasz Zawadzki struct spdk_bdev_module bdev_ut_if;
447d83a3489STomasz Zawadzki 
44832d7c91cSJim Harris static int
44932d7c91cSJim Harris bdev_ut_module_init(void)
45032d7c91cSJim Harris {
45132d7c91cSJim Harris 	spdk_io_device_register(&g_bdev_ut_io_device, bdev_ut_create_ch, bdev_ut_destroy_ch,
452c9402000SBen Walker 				sizeof(struct bdev_ut_channel), NULL);
453d83a3489STomasz Zawadzki 	spdk_bdev_module_init_done(&bdev_ut_if);
45432d7c91cSJim Harris 	return 0;
45532d7c91cSJim Harris }
45632d7c91cSJim Harris 
45732d7c91cSJim Harris static void
45832d7c91cSJim Harris bdev_ut_module_fini(void)
45932d7c91cSJim Harris {
4608ef7818aSJim Harris 	spdk_io_device_unregister(&g_bdev_ut_io_device, NULL);
46132d7c91cSJim Harris }
46232d7c91cSJim Harris 
46319100ed5SDaniel Verkamp struct spdk_bdev_module bdev_ut_if = {
4644d367354SPawel Wodkowski 	.name = "bdev_ut",
46532d7c91cSJim Harris 	.module_init = bdev_ut_module_init,
46632d7c91cSJim Harris 	.module_fini = bdev_ut_module_fini,
467d83a3489STomasz Zawadzki 	.async_init = true,
4684d367354SPawel Wodkowski };
4694d367354SPawel Wodkowski 
470ae215731SMike Gerdts static void vbdev_ut_examine_config(struct spdk_bdev *bdev);
471ae215731SMike Gerdts static void vbdev_ut_examine_disk(struct spdk_bdev *bdev);
4724d367354SPawel Wodkowski 
47332d7c91cSJim Harris static int
47432d7c91cSJim Harris vbdev_ut_module_init(void)
47532d7c91cSJim Harris {
47632d7c91cSJim Harris 	return 0;
47732d7c91cSJim Harris }
47832d7c91cSJim Harris 
47932d7c91cSJim Harris static void
48032d7c91cSJim Harris vbdev_ut_module_fini(void)
48132d7c91cSJim Harris {
48232d7c91cSJim Harris }
48332d7c91cSJim Harris 
484dc996557SBen Walker static int
485dc996557SBen Walker vbdev_ut_get_ctx_size(void)
486dc996557SBen Walker {
487dc996557SBen Walker 	return sizeof(struct bdev_ut_io);
488dc996557SBen Walker }
489dc996557SBen Walker 
49019100ed5SDaniel Verkamp struct spdk_bdev_module vbdev_ut_if = {
4914d367354SPawel Wodkowski 	.name = "vbdev_ut",
49232d7c91cSJim Harris 	.module_init = vbdev_ut_module_init,
49332d7c91cSJim Harris 	.module_fini = vbdev_ut_module_fini,
494ae215731SMike Gerdts 	.examine_config = vbdev_ut_examine_config,
495ae215731SMike Gerdts 	.examine_disk = vbdev_ut_examine_disk,
496dc996557SBen Walker 	.get_ctx_size = vbdev_ut_get_ctx_size,
4974d367354SPawel Wodkowski };
4984d367354SPawel Wodkowski 
499df6b55fdSgila SPDK_BDEV_MODULE_REGISTER(bdev_ut, &bdev_ut_if)
500df6b55fdSgila SPDK_BDEV_MODULE_REGISTER(vbdev_ut, &vbdev_ut_if)
5014d367354SPawel Wodkowski 
502ae215731SMike Gerdts struct ut_examine_ctx {
503ae215731SMike Gerdts 	void (*examine_config)(struct spdk_bdev *bdev);
504ae215731SMike Gerdts 	void (*examine_disk)(struct spdk_bdev *bdev);
505ae215731SMike Gerdts 	uint32_t examine_config_count;
506ae215731SMike Gerdts 	uint32_t examine_disk_count;
507ae215731SMike Gerdts };
508ae215731SMike Gerdts 
509e075a3dcSJim Harris static void
510ae215731SMike Gerdts vbdev_ut_examine_config(struct spdk_bdev *bdev)
511e075a3dcSJim Harris {
512ae215731SMike Gerdts 	struct ut_examine_ctx *ctx = bdev->ctxt;
513ae215731SMike Gerdts 
514ae215731SMike Gerdts 	if (ctx != NULL) {
515ae215731SMike Gerdts 		ctx->examine_config_count++;
516ae215731SMike Gerdts 		if (ctx->examine_config != NULL) {
517ae215731SMike Gerdts 			ctx->examine_config(bdev);
518ae215731SMike Gerdts 		}
519ae215731SMike Gerdts 	}
520ae215731SMike Gerdts 
521ae215731SMike Gerdts 	spdk_bdev_module_examine_done(&vbdev_ut_if);
522ae215731SMike Gerdts }
523ae215731SMike Gerdts 
524ae215731SMike Gerdts static void
525ae215731SMike Gerdts vbdev_ut_examine_disk(struct spdk_bdev *bdev)
526ae215731SMike Gerdts {
527ae215731SMike Gerdts 	struct ut_examine_ctx *ctx = bdev->ctxt;
528ae215731SMike Gerdts 
529ae215731SMike Gerdts 	if (ctx != NULL) {
530ae215731SMike Gerdts 		ctx->examine_disk_count++;
531ae215731SMike Gerdts 		if (ctx->examine_disk != NULL) {
532ae215731SMike Gerdts 			ctx->examine_disk(bdev);
533ae215731SMike Gerdts 		}
534ae215731SMike Gerdts 	}
535ae215731SMike Gerdts 
5364d367354SPawel Wodkowski 	spdk_bdev_module_examine_done(&vbdev_ut_if);
537e075a3dcSJim Harris }
538e075a3dcSJim Harris 
539cec70a60SShuhei Matsumoto static void
540cec70a60SShuhei Matsumoto bdev_init_cb(void *arg, int rc)
541cec70a60SShuhei Matsumoto {
542cec70a60SShuhei Matsumoto 	CU_ASSERT(rc == 0);
543cec70a60SShuhei Matsumoto }
544cec70a60SShuhei Matsumoto 
545cec70a60SShuhei Matsumoto static void
546cec70a60SShuhei Matsumoto bdev_fini_cb(void *arg)
547cec70a60SShuhei Matsumoto {
548cec70a60SShuhei Matsumoto }
549cec70a60SShuhei Matsumoto 
550cec70a60SShuhei Matsumoto static void
551cec70a60SShuhei Matsumoto ut_init_bdev(struct spdk_bdev_opts *opts)
552cec70a60SShuhei Matsumoto {
553cec70a60SShuhei Matsumoto 	int rc;
554cec70a60SShuhei Matsumoto 
555cec70a60SShuhei Matsumoto 	if (opts != NULL) {
556cec70a60SShuhei Matsumoto 		rc = spdk_bdev_set_opts(opts);
557cec70a60SShuhei Matsumoto 		CU_ASSERT(rc == 0);
558cec70a60SShuhei Matsumoto 	}
559cec70a60SShuhei Matsumoto 	rc = spdk_iobuf_initialize();
560cec70a60SShuhei Matsumoto 	CU_ASSERT(rc == 0);
561cec70a60SShuhei Matsumoto 	spdk_bdev_initialize(bdev_init_cb, NULL);
562cec70a60SShuhei Matsumoto 	poll_threads();
563cec70a60SShuhei Matsumoto }
564cec70a60SShuhei Matsumoto 
565cec70a60SShuhei Matsumoto static void
566cec70a60SShuhei Matsumoto ut_fini_bdev(void)
567cec70a60SShuhei Matsumoto {
568cec70a60SShuhei Matsumoto 	spdk_bdev_finish(bdev_fini_cb, NULL);
569cec70a60SShuhei Matsumoto 	spdk_iobuf_finish(bdev_fini_cb, NULL);
570cec70a60SShuhei Matsumoto 	poll_threads();
571cec70a60SShuhei Matsumoto }
572cec70a60SShuhei Matsumoto 
57357d174ffSJim Harris static struct spdk_bdev *
574ae215731SMike Gerdts allocate_bdev_ctx(char *name, void *ctx)
57557d174ffSJim Harris {
57657d174ffSJim Harris 	struct spdk_bdev *bdev;
577b9afa3c7SSebastian Basierski 	int rc;
57857d174ffSJim Harris 
57957d174ffSJim Harris 	bdev = calloc(1, sizeof(*bdev));
58057d174ffSJim Harris 	SPDK_CU_ASSERT_FATAL(bdev != NULL);
58157d174ffSJim Harris 
582ae215731SMike Gerdts 	bdev->ctxt = ctx;
58357d174ffSJim Harris 	bdev->name = name;
58457d174ffSJim Harris 	bdev->fn_table = &fn_table;
5854d367354SPawel Wodkowski 	bdev->module = &bdev_ut_if;
5865616c1edSShuhei Matsumoto 	bdev->blockcnt = 1024;
5874bd97621SJim Harris 	bdev->blocklen = 512;
58857d174ffSJim Harris 
589a1c7ae2dSKrzysztof Karas 	spdk_uuid_generate(&bdev->uuid);
590a1c7ae2dSKrzysztof Karas 
591b9afa3c7SSebastian Basierski 	rc = spdk_bdev_register(bdev);
592d0038b70SNathan Claudel 	poll_threads();
593b9afa3c7SSebastian Basierski 	CU_ASSERT(rc == 0);
59457d174ffSJim Harris 
59557d174ffSJim Harris 	return bdev;
59657d174ffSJim Harris }
59757d174ffSJim Harris 
59857d174ffSJim Harris static struct spdk_bdev *
599ae215731SMike Gerdts allocate_bdev(char *name)
600ae215731SMike Gerdts {
601ae215731SMike Gerdts 	return allocate_bdev_ctx(name, NULL);
602ae215731SMike Gerdts }
603ae215731SMike Gerdts 
604ae215731SMike Gerdts static struct spdk_bdev *
605bfd1e46eSJim Harris allocate_vbdev(char *name)
60657d174ffSJim Harris {
60757d174ffSJim Harris 	struct spdk_bdev *bdev;
608b9afa3c7SSebastian Basierski 	int rc;
60957d174ffSJim Harris 
61057d174ffSJim Harris 	bdev = calloc(1, sizeof(*bdev));
61157d174ffSJim Harris 	SPDK_CU_ASSERT_FATAL(bdev != NULL);
61257d174ffSJim Harris 
61357d174ffSJim Harris 	bdev->name = name;
61457d174ffSJim Harris 	bdev->fn_table = &fn_table;
6154d367354SPawel Wodkowski 	bdev->module = &vbdev_ut_if;
616cec70a60SShuhei Matsumoto 	bdev->blockcnt = 1024;
617cec70a60SShuhei Matsumoto 	bdev->blocklen = 512;
61857d174ffSJim Harris 
619bfd1e46eSJim Harris 	rc = spdk_bdev_register(bdev);
620d0038b70SNathan Claudel 	poll_threads();
621b9afa3c7SSebastian Basierski 	CU_ASSERT(rc == 0);
62257d174ffSJim Harris 
62357d174ffSJim Harris 	return bdev;
62457d174ffSJim Harris }
62557d174ffSJim Harris 
62657d174ffSJim Harris static void
62757d174ffSJim Harris free_bdev(struct spdk_bdev *bdev)
62857d174ffSJim Harris {
6292baeea7dSMaciej Szwed 	spdk_bdev_unregister(bdev, NULL, NULL);
630270a25dfSBen Walker 	poll_threads();
6314473942fSPawel Wodkowski 	memset(bdev, 0xFF, sizeof(*bdev));
63257d174ffSJim Harris 	free(bdev);
63357d174ffSJim Harris }
63457d174ffSJim Harris 
63557d174ffSJim Harris static void
63657d174ffSJim Harris free_vbdev(struct spdk_bdev *bdev)
63757d174ffSJim Harris {
638b6aaba08STomasz Zawadzki 	spdk_bdev_unregister(bdev, NULL, NULL);
639270a25dfSBen Walker 	poll_threads();
6404473942fSPawel Wodkowski 	memset(bdev, 0xFF, sizeof(*bdev));
64157d174ffSJim Harris 	free(bdev);
64257d174ffSJim Harris }
64357d174ffSJim Harris 
64457d174ffSJim Harris static void
64564ccd4b9SYanbo Zhou get_device_stat_cb(struct spdk_bdev *bdev, struct spdk_bdev_io_stat *stat, void *cb_arg, int rc)
64664ccd4b9SYanbo Zhou {
64764ccd4b9SYanbo Zhou 	const char *bdev_name;
64864ccd4b9SYanbo Zhou 
64964ccd4b9SYanbo Zhou 	CU_ASSERT(bdev != NULL);
65064ccd4b9SYanbo Zhou 	CU_ASSERT(rc == 0);
65164ccd4b9SYanbo Zhou 	bdev_name = spdk_bdev_get_name(bdev);
65264ccd4b9SYanbo Zhou 	CU_ASSERT_STRING_EQUAL(bdev_name, "bdev0");
65364ccd4b9SYanbo Zhou 
65464ccd4b9SYanbo Zhou 	free(stat);
655270a25dfSBen Walker 
656270a25dfSBen Walker 	*(bool *)cb_arg = true;
65764ccd4b9SYanbo Zhou }
65864ccd4b9SYanbo Zhou 
65964ccd4b9SYanbo Zhou static void
66023975858SEvgeniy Kochetov bdev_unregister_cb(void *cb_arg, int rc)
66123975858SEvgeniy Kochetov {
66223975858SEvgeniy Kochetov 	g_unregister_arg = cb_arg;
66323975858SEvgeniy Kochetov 	g_unregister_rc = rc;
66423975858SEvgeniy Kochetov }
66523975858SEvgeniy Kochetov 
66623975858SEvgeniy Kochetov static void
66775dfecbbSShuhei Matsumoto bdev_ut_event_cb(enum spdk_bdev_event_type type, struct spdk_bdev *bdev, void *event_ctx)
66875dfecbbSShuhei Matsumoto {
66975dfecbbSShuhei Matsumoto }
67075dfecbbSShuhei Matsumoto 
67175dfecbbSShuhei Matsumoto static void
672437e54f7SEvgeniy Kochetov bdev_open_cb1(enum spdk_bdev_event_type type, struct spdk_bdev *bdev, void *event_ctx)
673437e54f7SEvgeniy Kochetov {
674437e54f7SEvgeniy Kochetov 	struct spdk_bdev_desc *desc = *(struct spdk_bdev_desc **)event_ctx;
675437e54f7SEvgeniy Kochetov 
676437e54f7SEvgeniy Kochetov 	g_event_type1 = type;
6779522ed36SEvgeniy Kochetov 	if (SPDK_BDEV_EVENT_REMOVE == type) {
678437e54f7SEvgeniy Kochetov 		spdk_bdev_close(desc);
679437e54f7SEvgeniy Kochetov 	}
6809522ed36SEvgeniy Kochetov }
681437e54f7SEvgeniy Kochetov 
682437e54f7SEvgeniy Kochetov static void
683437e54f7SEvgeniy Kochetov bdev_open_cb2(enum spdk_bdev_event_type type, struct spdk_bdev *bdev, void *event_ctx)
684437e54f7SEvgeniy Kochetov {
685437e54f7SEvgeniy Kochetov 	struct spdk_bdev_desc *desc = *(struct spdk_bdev_desc **)event_ctx;
686437e54f7SEvgeniy Kochetov 
687437e54f7SEvgeniy Kochetov 	g_event_type2 = type;
6889522ed36SEvgeniy Kochetov 	if (SPDK_BDEV_EVENT_REMOVE == type) {
689437e54f7SEvgeniy Kochetov 		spdk_bdev_close(desc);
690437e54f7SEvgeniy Kochetov 	}
6919522ed36SEvgeniy Kochetov }
692437e54f7SEvgeniy Kochetov 
693437e54f7SEvgeniy Kochetov static void
6947bcd316dSGangCao bdev_open_cb3(enum spdk_bdev_event_type type, struct spdk_bdev *bdev, void *event_ctx)
6957bcd316dSGangCao {
6967bcd316dSGangCao 	g_event_type3 = type;
6977bcd316dSGangCao }
6987bcd316dSGangCao 
6997bcd316dSGangCao static void
7007bcd316dSGangCao bdev_open_cb4(enum spdk_bdev_event_type type, struct spdk_bdev *bdev, void *event_ctx)
7017bcd316dSGangCao {
7027bcd316dSGangCao 	g_event_type4 = type;
7037bcd316dSGangCao }
7047bcd316dSGangCao 
7057bcd316dSGangCao static void
7066defafc9SDamiano bdev_seek_cb(struct spdk_bdev_io *bdev_io, bool success, void *cb_arg)
7076defafc9SDamiano {
7086defafc9SDamiano 	g_seek_offset = spdk_bdev_io_get_seek_offset(bdev_io);
7096defafc9SDamiano 	spdk_bdev_free_io(bdev_io);
7106defafc9SDamiano }
7116defafc9SDamiano 
7126defafc9SDamiano static void
71364ccd4b9SYanbo Zhou get_device_stat_test(void)
71464ccd4b9SYanbo Zhou {
71564ccd4b9SYanbo Zhou 	struct spdk_bdev *bdev;
71664ccd4b9SYanbo Zhou 	struct spdk_bdev_io_stat *stat;
717270a25dfSBen Walker 	bool done;
71864ccd4b9SYanbo Zhou 
71964ccd4b9SYanbo Zhou 	bdev = allocate_bdev("bdev0");
72064ccd4b9SYanbo Zhou 	stat = calloc(1, sizeof(struct spdk_bdev_io_stat));
72164ccd4b9SYanbo Zhou 	if (stat == NULL) {
72264ccd4b9SYanbo Zhou 		free_bdev(bdev);
72364ccd4b9SYanbo Zhou 		return;
72464ccd4b9SYanbo Zhou 	}
725270a25dfSBen Walker 
726270a25dfSBen Walker 	done = false;
72763e0c25dSVasilii Ivanov 	spdk_bdev_get_device_stat(bdev, stat, SPDK_BDEV_RESET_STAT_NONE, get_device_stat_cb, &done);
728270a25dfSBen Walker 	while (!done) { poll_threads(); }
729270a25dfSBen Walker 
730c83ffe32STomasz Zawadzki 	free_bdev(bdev);
73164ccd4b9SYanbo Zhou }
73264ccd4b9SYanbo Zhou 
73364ccd4b9SYanbo Zhou static void
73457d174ffSJim Harris open_write_test(void)
73557d174ffSJim Harris {
7364473942fSPawel Wodkowski 	struct spdk_bdev *bdev[9];
7374473942fSPawel Wodkowski 	struct spdk_bdev_desc *desc[9] = {};
73857d174ffSJim Harris 	int rc;
73957d174ffSJim Harris 
740cec70a60SShuhei Matsumoto 	ut_init_bdev(NULL);
741cec70a60SShuhei Matsumoto 
74257d174ffSJim Harris 	/*
74357d174ffSJim Harris 	 * Create a tree of bdevs to test various open w/ write cases.
74457d174ffSJim Harris 	 *
7454473942fSPawel Wodkowski 	 * bdev0 through bdev3 are physical block devices, such as NVMe
74657d174ffSJim Harris 	 * namespaces or Ceph block devices.
74757d174ffSJim Harris 	 *
7484473942fSPawel Wodkowski 	 * bdev4 is a virtual bdev with multiple base bdevs.  This models
74957d174ffSJim Harris 	 * caching or RAID use cases.
75057d174ffSJim Harris 	 *
7514473942fSPawel Wodkowski 	 * bdev5 through bdev7 are all virtual bdevs with the same base
7524473942fSPawel Wodkowski 	 * bdev (except bdev7). This models partitioning or logical volume
7534473942fSPawel Wodkowski 	 * use cases.
75457d174ffSJim Harris 	 *
7554473942fSPawel Wodkowski 	 * bdev7 is a virtual bdev with multiple base bdevs. One of base bdevs
7564473942fSPawel Wodkowski 	 * (bdev2) is shared with other virtual bdevs: bdev5 and bdev6. This
7574473942fSPawel Wodkowski 	 * models caching, RAID, partitioning or logical volumes use cases.
7584473942fSPawel Wodkowski 	 *
7594473942fSPawel Wodkowski 	 * bdev8 is a virtual bdev with multiple base bdevs, but these
76057d174ffSJim Harris 	 * base bdevs are themselves virtual bdevs.
76157d174ffSJim Harris 	 *
7624473942fSPawel Wodkowski 	 *                bdev8
76357d174ffSJim Harris 	 *                  |
76457d174ffSJim Harris 	 *            +----------+
76557d174ffSJim Harris 	 *            |          |
7664473942fSPawel Wodkowski 	 *          bdev4      bdev5   bdev6   bdev7
76757d174ffSJim Harris 	 *            |          |       |       |
7684473942fSPawel Wodkowski 	 *        +---+---+      +---+   +   +---+---+
7694473942fSPawel Wodkowski 	 *        |       |           \  |  /         \
7704473942fSPawel Wodkowski 	 *      bdev0   bdev1          bdev2         bdev3
77157d174ffSJim Harris 	 */
77257d174ffSJim Harris 
77357d174ffSJim Harris 	bdev[0] = allocate_bdev("bdev0");
7744d367354SPawel Wodkowski 	rc = spdk_bdev_module_claim_bdev(bdev[0], NULL, &bdev_ut_if);
7754fc7e666SJim Harris 	CU_ASSERT(rc == 0);
7764fc7e666SJim Harris 
77757d174ffSJim Harris 	bdev[1] = allocate_bdev("bdev1");
7784d367354SPawel Wodkowski 	rc = spdk_bdev_module_claim_bdev(bdev[1], NULL, &bdev_ut_if);
7794fc7e666SJim Harris 	CU_ASSERT(rc == 0);
7804fc7e666SJim Harris 
78157d174ffSJim Harris 	bdev[2] = allocate_bdev("bdev2");
7824d367354SPawel Wodkowski 	rc = spdk_bdev_module_claim_bdev(bdev[2], NULL, &bdev_ut_if);
7834fc7e666SJim Harris 	CU_ASSERT(rc == 0);
78457d174ffSJim Harris 
7854473942fSPawel Wodkowski 	bdev[3] = allocate_bdev("bdev3");
7864d367354SPawel Wodkowski 	rc = spdk_bdev_module_claim_bdev(bdev[3], NULL, &bdev_ut_if);
7874fc7e666SJim Harris 	CU_ASSERT(rc == 0);
78857d174ffSJim Harris 
789bfd1e46eSJim Harris 	bdev[4] = allocate_vbdev("bdev4");
7904d367354SPawel Wodkowski 	rc = spdk_bdev_module_claim_bdev(bdev[4], NULL, &bdev_ut_if);
7914fc7e666SJim Harris 	CU_ASSERT(rc == 0);
7924fc7e666SJim Harris 
793bfd1e46eSJim Harris 	bdev[5] = allocate_vbdev("bdev5");
7944473942fSPawel Wodkowski 	rc = spdk_bdev_module_claim_bdev(bdev[5], NULL, &bdev_ut_if);
7954473942fSPawel Wodkowski 	CU_ASSERT(rc == 0);
7964473942fSPawel Wodkowski 
797bfd1e46eSJim Harris 	bdev[6] = allocate_vbdev("bdev6");
79857d174ffSJim Harris 
799bfd1e46eSJim Harris 	bdev[7] = allocate_vbdev("bdev7");
8004473942fSPawel Wodkowski 
801bfd1e46eSJim Harris 	bdev[8] = allocate_vbdev("bdev8");
8024473942fSPawel Wodkowski 
80357d174ffSJim Harris 	/* Open bdev0 read-only.  This should succeed. */
80475dfecbbSShuhei Matsumoto 	rc = spdk_bdev_open_ext("bdev0", false, bdev_ut_event_cb, NULL, &desc[0]);
80557d174ffSJim Harris 	CU_ASSERT(rc == 0);
8061196deb5SSeth Howell 	SPDK_CU_ASSERT_FATAL(desc[0] != NULL);
80775dfecbbSShuhei Matsumoto 	CU_ASSERT(bdev[0] == spdk_bdev_desc_get_bdev(desc[0]));
80857d174ffSJim Harris 	spdk_bdev_close(desc[0]);
80957d174ffSJim Harris 
8104fc7e666SJim Harris 	/*
8114fc7e666SJim Harris 	 * Open bdev1 read/write.  This should fail since bdev1 has been claimed
8124fc7e666SJim Harris 	 * by a vbdev module.
8134fc7e666SJim Harris 	 */
81475dfecbbSShuhei Matsumoto 	rc = spdk_bdev_open_ext("bdev1", true, bdev_ut_event_cb, NULL, &desc[1]);
8154fc7e666SJim Harris 	CU_ASSERT(rc == -EPERM);
81657d174ffSJim Harris 
81757d174ffSJim Harris 	/*
8184473942fSPawel Wodkowski 	 * Open bdev4 read/write.  This should fail since bdev3 has been claimed
8194fc7e666SJim Harris 	 * by a vbdev module.
82057d174ffSJim Harris 	 */
82175dfecbbSShuhei Matsumoto 	rc = spdk_bdev_open_ext("bdev4", true, bdev_ut_event_cb, NULL, &desc[4]);
82257d174ffSJim Harris 	CU_ASSERT(rc == -EPERM);
82357d174ffSJim Harris 
82457d174ffSJim Harris 	/* Open bdev4 read-only.  This should succeed. */
82575dfecbbSShuhei Matsumoto 	rc = spdk_bdev_open_ext("bdev4", false, bdev_ut_event_cb, NULL, &desc[4]);
82657d174ffSJim Harris 	CU_ASSERT(rc == 0);
8271196deb5SSeth Howell 	SPDK_CU_ASSERT_FATAL(desc[4] != NULL);
82875dfecbbSShuhei Matsumoto 	CU_ASSERT(bdev[4] == spdk_bdev_desc_get_bdev(desc[4]));
82957d174ffSJim Harris 	spdk_bdev_close(desc[4]);
83057d174ffSJim Harris 
8314473942fSPawel Wodkowski 	/*
8324473942fSPawel Wodkowski 	 * Open bdev8 read/write.  This should succeed since it is a leaf
8334473942fSPawel Wodkowski 	 * bdev.
8344473942fSPawel Wodkowski 	 */
83575dfecbbSShuhei Matsumoto 	rc = spdk_bdev_open_ext("bdev8", true, bdev_ut_event_cb, NULL, &desc[8]);
8364473942fSPawel Wodkowski 	CU_ASSERT(rc == 0);
8371196deb5SSeth Howell 	SPDK_CU_ASSERT_FATAL(desc[8] != NULL);
83875dfecbbSShuhei Matsumoto 	CU_ASSERT(bdev[8] == spdk_bdev_desc_get_bdev(desc[8]));
8394473942fSPawel Wodkowski 	spdk_bdev_close(desc[8]);
84057d174ffSJim Harris 
8414473942fSPawel Wodkowski 	/*
8424473942fSPawel Wodkowski 	 * Open bdev5 read/write.  This should fail since bdev4 has been claimed
8434473942fSPawel Wodkowski 	 * by a vbdev module.
8444473942fSPawel Wodkowski 	 */
84575dfecbbSShuhei Matsumoto 	rc = spdk_bdev_open_ext("bdev5", true, bdev_ut_event_cb, NULL, &desc[5]);
8464473942fSPawel Wodkowski 	CU_ASSERT(rc == -EPERM);
8474473942fSPawel Wodkowski 
8484473942fSPawel Wodkowski 	/* Open bdev4 read-only.  This should succeed. */
84975dfecbbSShuhei Matsumoto 	rc = spdk_bdev_open_ext("bdev5", false, bdev_ut_event_cb, NULL, &desc[5]);
8504473942fSPawel Wodkowski 	CU_ASSERT(rc == 0);
8511196deb5SSeth Howell 	SPDK_CU_ASSERT_FATAL(desc[5] != NULL);
85275dfecbbSShuhei Matsumoto 	CU_ASSERT(bdev[5] == spdk_bdev_desc_get_bdev(desc[5]));
8534473942fSPawel Wodkowski 	spdk_bdev_close(desc[5]);
8544473942fSPawel Wodkowski 
8554473942fSPawel Wodkowski 	free_vbdev(bdev[8]);
8564473942fSPawel Wodkowski 
85757d174ffSJim Harris 	free_vbdev(bdev[5]);
85857d174ffSJim Harris 	free_vbdev(bdev[6]);
8594473942fSPawel Wodkowski 	free_vbdev(bdev[7]);
8604473942fSPawel Wodkowski 
8614473942fSPawel Wodkowski 	free_vbdev(bdev[4]);
86257d174ffSJim Harris 
86357d174ffSJim Harris 	free_bdev(bdev[0]);
86457d174ffSJim Harris 	free_bdev(bdev[1]);
86557d174ffSJim Harris 	free_bdev(bdev[2]);
8664473942fSPawel Wodkowski 	free_bdev(bdev[3]);
867cec70a60SShuhei Matsumoto 
868cec70a60SShuhei Matsumoto 	ut_fini_bdev();
8694ee51dcbSJim Harris }
8704ee51dcbSJim Harris 
871906ce694SDaniel Verkamp static void
8729f9c7161SMike Gerdts claim_test(void)
8739f9c7161SMike Gerdts {
8749f9c7161SMike Gerdts 	struct spdk_bdev *bdev;
8759f9c7161SMike Gerdts 	struct spdk_bdev_desc *desc, *open_desc;
8769f9c7161SMike Gerdts 	int rc;
8779f9c7161SMike Gerdts 	uint32_t count;
8789f9c7161SMike Gerdts 
879cec70a60SShuhei Matsumoto 	ut_init_bdev(NULL);
880cec70a60SShuhei Matsumoto 
8819f9c7161SMike Gerdts 	/*
8829f9c7161SMike Gerdts 	 * A vbdev that uses a read-only bdev may need it to remain read-only.
8839f9c7161SMike Gerdts 	 * To do so, it opens the bdev read-only, then claims it without
8849f9c7161SMike Gerdts 	 * passing a spdk_bdev_desc.
8859f9c7161SMike Gerdts 	 */
8869f9c7161SMike Gerdts 	bdev = allocate_bdev("bdev0");
8879f9c7161SMike Gerdts 	rc = spdk_bdev_open_ext("bdev0", false, bdev_ut_event_cb, NULL, &desc);
8889f9c7161SMike Gerdts 	CU_ASSERT(rc == 0);
8899f9c7161SMike Gerdts 	CU_ASSERT(desc->write == false);
8909f9c7161SMike Gerdts 
8919f9c7161SMike Gerdts 	rc = spdk_bdev_module_claim_bdev(bdev, NULL, &bdev_ut_if);
8929f9c7161SMike Gerdts 	CU_ASSERT(rc == 0);
8934bb902a6SMike Gerdts 	CU_ASSERT(bdev->internal.claim_type == SPDK_BDEV_CLAIM_EXCL_WRITE);
8949fd2f931SMike Gerdts 	CU_ASSERT(bdev->internal.claim.v1.module == &bdev_ut_if);
8959f9c7161SMike Gerdts 
8969f9c7161SMike Gerdts 	/* There should be only one open descriptor and it should still be ro */
8979f9c7161SMike Gerdts 	count = 0;
8989f9c7161SMike Gerdts 	TAILQ_FOREACH(open_desc, &bdev->internal.open_descs, link) {
8999f9c7161SMike Gerdts 		CU_ASSERT(open_desc == desc);
9009f9c7161SMike Gerdts 		CU_ASSERT(!open_desc->write);
9019f9c7161SMike Gerdts 		count++;
9029f9c7161SMike Gerdts 	}
9039f9c7161SMike Gerdts 	CU_ASSERT(count == 1);
9049f9c7161SMike Gerdts 
9059f9c7161SMike Gerdts 	/* A read-only bdev is upgraded to read-write if desc is passed. */
9069f9c7161SMike Gerdts 	spdk_bdev_module_release_bdev(bdev);
9079f9c7161SMike Gerdts 	rc = spdk_bdev_module_claim_bdev(bdev, desc, &bdev_ut_if);
9089f9c7161SMike Gerdts 	CU_ASSERT(rc == 0);
9094bb902a6SMike Gerdts 	CU_ASSERT(bdev->internal.claim_type == SPDK_BDEV_CLAIM_EXCL_WRITE);
9109fd2f931SMike Gerdts 	CU_ASSERT(bdev->internal.claim.v1.module == &bdev_ut_if);
9119f9c7161SMike Gerdts 
9129f9c7161SMike Gerdts 	/* There should be only one open descriptor and it should be rw */
9139f9c7161SMike Gerdts 	count = 0;
9149f9c7161SMike Gerdts 	TAILQ_FOREACH(open_desc, &bdev->internal.open_descs, link) {
9159f9c7161SMike Gerdts 		CU_ASSERT(open_desc == desc);
9169f9c7161SMike Gerdts 		CU_ASSERT(open_desc->write);
9179f9c7161SMike Gerdts 		count++;
9189f9c7161SMike Gerdts 	}
9199f9c7161SMike Gerdts 	CU_ASSERT(count == 1);
9209f9c7161SMike Gerdts 
9219f9c7161SMike Gerdts 	spdk_bdev_close(desc);
9229f9c7161SMike Gerdts 	free_bdev(bdev);
923cec70a60SShuhei Matsumoto 	ut_fini_bdev();
9249f9c7161SMike Gerdts }
9259f9c7161SMike Gerdts 
9269f9c7161SMike Gerdts static void
927e83f9767SDaniel Verkamp bytes_to_blocks_test(void)
928e83f9767SDaniel Verkamp {
929fb1630bfSShuhei Matsumoto 	struct spdk_bdev_desc desc = {0};
930fb1630bfSShuhei Matsumoto 	struct spdk_bdev bdev = {0};
931e83f9767SDaniel Verkamp 	uint64_t offset_blocks, num_blocks;
932e83f9767SDaniel Verkamp 
933557f022fSShuhei Matsumoto 
934557f022fSShuhei Matsumoto 	desc.bdev = &bdev;
935e83f9767SDaniel Verkamp 	memset(&bdev, 0, sizeof(bdev));
936e83f9767SDaniel Verkamp 
937e83f9767SDaniel Verkamp 	bdev.blocklen = 512;
938e83f9767SDaniel Verkamp 
939e83f9767SDaniel Verkamp 	/* All parameters valid */
940e83f9767SDaniel Verkamp 	offset_blocks = 0;
941e83f9767SDaniel Verkamp 	num_blocks = 0;
942557f022fSShuhei Matsumoto 	CU_ASSERT(bdev_bytes_to_blocks(&desc, 512, &offset_blocks, 1024, &num_blocks) == 0);
943e83f9767SDaniel Verkamp 	CU_ASSERT(offset_blocks == 1);
944e83f9767SDaniel Verkamp 	CU_ASSERT(num_blocks == 2);
945e83f9767SDaniel Verkamp 
946e83f9767SDaniel Verkamp 	/* Offset not a block multiple */
947557f022fSShuhei Matsumoto 	CU_ASSERT(bdev_bytes_to_blocks(&desc, 3, &offset_blocks, 512, &num_blocks) != 0);
948e83f9767SDaniel Verkamp 
949e83f9767SDaniel Verkamp 	/* Length not a block multiple */
950557f022fSShuhei Matsumoto 	CU_ASSERT(bdev_bytes_to_blocks(&desc, 512, &offset_blocks, 3, &num_blocks) != 0);
95102be32d4Slorneli 
95202be32d4Slorneli 	/* In case blocklen not the power of two */
95302be32d4Slorneli 	bdev.blocklen = 100;
954557f022fSShuhei Matsumoto 	CU_ASSERT(bdev_bytes_to_blocks(&desc, 100, &offset_blocks, 200, &num_blocks) == 0);
95502be32d4Slorneli 	CU_ASSERT(offset_blocks == 1);
95602be32d4Slorneli 	CU_ASSERT(num_blocks == 2);
95702be32d4Slorneli 
95802be32d4Slorneli 	/* Offset not a block multiple */
959557f022fSShuhei Matsumoto 	CU_ASSERT(bdev_bytes_to_blocks(&desc, 3, &offset_blocks, 100, &num_blocks) != 0);
96002be32d4Slorneli 
96102be32d4Slorneli 	/* Length not a block multiple */
962557f022fSShuhei Matsumoto 	CU_ASSERT(bdev_bytes_to_blocks(&desc, 100, &offset_blocks, 3, &num_blocks) != 0);
963e83f9767SDaniel Verkamp }
964e83f9767SDaniel Verkamp 
965e83f9767SDaniel Verkamp static void
966d4822a7dSSlawomir Mrozowicz num_blocks_test(void)
967d4822a7dSSlawomir Mrozowicz {
968cec70a60SShuhei Matsumoto 	struct spdk_bdev *bdev;
9691196deb5SSeth Howell 	struct spdk_bdev_desc *desc = NULL;
9701196deb5SSeth Howell 	int rc;
971d4822a7dSSlawomir Mrozowicz 
972cec70a60SShuhei Matsumoto 	ut_init_bdev(NULL);
973cec70a60SShuhei Matsumoto 	bdev = allocate_bdev("num_blocks");
974cec70a60SShuhei Matsumoto 
975cec70a60SShuhei Matsumoto 	spdk_bdev_notify_blockcnt_change(bdev, 50);
976d4822a7dSSlawomir Mrozowicz 
977d4822a7dSSlawomir Mrozowicz 	/* Growing block number */
978cec70a60SShuhei Matsumoto 	CU_ASSERT(spdk_bdev_notify_blockcnt_change(bdev, 70) == 0);
979d4822a7dSSlawomir Mrozowicz 	/* Shrinking block number */
980cec70a60SShuhei Matsumoto 	CU_ASSERT(spdk_bdev_notify_blockcnt_change(bdev, 30) == 0);
981d4822a7dSSlawomir Mrozowicz 
982739d5413STomasz Zawadzki 	rc = spdk_bdev_open_ext("num_blocks", false, bdev_open_cb1, &desc, &desc);
9831196deb5SSeth Howell 	CU_ASSERT(rc == 0);
9841196deb5SSeth Howell 	SPDK_CU_ASSERT_FATAL(desc != NULL);
985cec70a60SShuhei Matsumoto 	CU_ASSERT(bdev == spdk_bdev_desc_get_bdev(desc));
986d4822a7dSSlawomir Mrozowicz 
987d4822a7dSSlawomir Mrozowicz 	/* Growing block number */
988cec70a60SShuhei Matsumoto 	CU_ASSERT(spdk_bdev_notify_blockcnt_change(bdev, 80) == 0);
989d4822a7dSSlawomir Mrozowicz 	/* Shrinking block number */
990cec70a60SShuhei Matsumoto 	CU_ASSERT(spdk_bdev_notify_blockcnt_change(bdev, 20) != 0);
991d4822a7dSSlawomir Mrozowicz 
9929522ed36SEvgeniy Kochetov 	g_event_type1 = 0xFF;
9939522ed36SEvgeniy Kochetov 	/* Growing block number */
994cec70a60SShuhei Matsumoto 	CU_ASSERT(spdk_bdev_notify_blockcnt_change(bdev, 90) == 0);
9959522ed36SEvgeniy Kochetov 
9969522ed36SEvgeniy Kochetov 	poll_threads();
9979522ed36SEvgeniy Kochetov 	CU_ASSERT_EQUAL(g_event_type1, SPDK_BDEV_EVENT_RESIZE);
9989522ed36SEvgeniy Kochetov 
9999522ed36SEvgeniy Kochetov 	g_event_type1 = 0xFF;
10009522ed36SEvgeniy Kochetov 	/* Growing block number and closing */
1001cec70a60SShuhei Matsumoto 	CU_ASSERT(spdk_bdev_notify_blockcnt_change(bdev, 100) == 0);
10029522ed36SEvgeniy Kochetov 
1003d4822a7dSSlawomir Mrozowicz 	spdk_bdev_close(desc);
1004cec70a60SShuhei Matsumoto 	free_bdev(bdev);
1005cec70a60SShuhei Matsumoto 	ut_fini_bdev();
1006270a25dfSBen Walker 
1007270a25dfSBen Walker 	poll_threads();
10089522ed36SEvgeniy Kochetov 
10099522ed36SEvgeniy Kochetov 	/* Callback is not called for closed device */
10109522ed36SEvgeniy Kochetov 	CU_ASSERT_EQUAL(g_event_type1, 0xFF);
1011d4822a7dSSlawomir Mrozowicz }
1012d4822a7dSSlawomir Mrozowicz 
1013d4822a7dSSlawomir Mrozowicz static void
1014906ce694SDaniel Verkamp io_valid_test(void)
1015906ce694SDaniel Verkamp {
1016906ce694SDaniel Verkamp 	struct spdk_bdev bdev;
1017906ce694SDaniel Verkamp 
1018906ce694SDaniel Verkamp 	memset(&bdev, 0, sizeof(bdev));
1019906ce694SDaniel Verkamp 
1020906ce694SDaniel Verkamp 	bdev.blocklen = 512;
10210dc6aac1SMike Gerdts 	spdk_spin_init(&bdev.internal.spinlock);
10227d3b2c13SNick Connolly 
1023d4822a7dSSlawomir Mrozowicz 	spdk_bdev_notify_blockcnt_change(&bdev, 100);
1024906ce694SDaniel Verkamp 
1025906ce694SDaniel Verkamp 	/* All parameters valid */
10260e58d154SJim Harris 	CU_ASSERT(bdev_io_valid_blocks(&bdev, 1, 2) == true);
1027906ce694SDaniel Verkamp 
1028906ce694SDaniel Verkamp 	/* Last valid block */
10290e58d154SJim Harris 	CU_ASSERT(bdev_io_valid_blocks(&bdev, 99, 1) == true);
1030906ce694SDaniel Verkamp 
1031906ce694SDaniel Verkamp 	/* Offset past end of bdev */
10320e58d154SJim Harris 	CU_ASSERT(bdev_io_valid_blocks(&bdev, 100, 1) == false);
1033906ce694SDaniel Verkamp 
1034906ce694SDaniel Verkamp 	/* Offset + length past end of bdev */
10350e58d154SJim Harris 	CU_ASSERT(bdev_io_valid_blocks(&bdev, 99, 2) == false);
1036906ce694SDaniel Verkamp 
1037e83f9767SDaniel Verkamp 	/* Offset near end of uint64_t range (2^64 - 1) */
10380e58d154SJim Harris 	CU_ASSERT(bdev_io_valid_blocks(&bdev, 18446744073709551615ULL, 1) == false);
10397d3b2c13SNick Connolly 
10400dc6aac1SMike Gerdts 	spdk_spin_destroy(&bdev.internal.spinlock);
1041906ce694SDaniel Verkamp }
1042906ce694SDaniel Verkamp 
1043b9afa3c7SSebastian Basierski static void
1044b9afa3c7SSebastian Basierski alias_add_del_test(void)
1045b9afa3c7SSebastian Basierski {
10466deac3e6Swuzhouhui 	struct spdk_bdev *bdev[3];
1047b9afa3c7SSebastian Basierski 	int rc;
1048b9afa3c7SSebastian Basierski 
1049cec70a60SShuhei Matsumoto 	ut_init_bdev(NULL);
1050cec70a60SShuhei Matsumoto 
1051b9afa3c7SSebastian Basierski 	/* Creating and registering bdevs */
1052b9afa3c7SSebastian Basierski 	bdev[0] = allocate_bdev("bdev0");
1053b9afa3c7SSebastian Basierski 	SPDK_CU_ASSERT_FATAL(bdev[0] != 0);
1054b9afa3c7SSebastian Basierski 
1055b9afa3c7SSebastian Basierski 	bdev[1] = allocate_bdev("bdev1");
1056b9afa3c7SSebastian Basierski 	SPDK_CU_ASSERT_FATAL(bdev[1] != 0);
1057b9afa3c7SSebastian Basierski 
10586deac3e6Swuzhouhui 	bdev[2] = allocate_bdev("bdev2");
10596deac3e6Swuzhouhui 	SPDK_CU_ASSERT_FATAL(bdev[2] != 0);
10606deac3e6Swuzhouhui 
1061270a25dfSBen Walker 	poll_threads();
1062270a25dfSBen Walker 
1063b9afa3c7SSebastian Basierski 	/*
1064b9afa3c7SSebastian Basierski 	 * Trying adding an alias identical to name.
1065b9afa3c7SSebastian Basierski 	 * Alias is identical to name, so it can not be added to aliases list
1066b9afa3c7SSebastian Basierski 	 */
1067b9afa3c7SSebastian Basierski 	rc = spdk_bdev_alias_add(bdev[0], bdev[0]->name);
1068b9afa3c7SSebastian Basierski 	CU_ASSERT(rc == -EEXIST);
1069b9afa3c7SSebastian Basierski 
1070b9afa3c7SSebastian Basierski 	/*
1071b9afa3c7SSebastian Basierski 	 * Trying to add empty alias,
1072b9afa3c7SSebastian Basierski 	 * this one should fail
1073b9afa3c7SSebastian Basierski 	 */
1074b9afa3c7SSebastian Basierski 	rc = spdk_bdev_alias_add(bdev[0], NULL);
1075b9afa3c7SSebastian Basierski 	CU_ASSERT(rc == -EINVAL);
1076b9afa3c7SSebastian Basierski 
1077b9afa3c7SSebastian Basierski 	/* Trying adding same alias to two different registered bdevs */
1078b9afa3c7SSebastian Basierski 
1079b9afa3c7SSebastian Basierski 	/* Alias is used first time, so this one should pass */
1080b9afa3c7SSebastian Basierski 	rc = spdk_bdev_alias_add(bdev[0], "proper alias 0");
1081b9afa3c7SSebastian Basierski 	CU_ASSERT(rc == 0);
1082b9afa3c7SSebastian Basierski 
1083b9afa3c7SSebastian Basierski 	/* Alias was added to another bdev, so this one should fail */
1084b9afa3c7SSebastian Basierski 	rc = spdk_bdev_alias_add(bdev[1], "proper alias 0");
1085b9afa3c7SSebastian Basierski 	CU_ASSERT(rc == -EEXIST);
1086b9afa3c7SSebastian Basierski 
1087b9afa3c7SSebastian Basierski 	/* Alias is used first time, so this one should pass */
1088b9afa3c7SSebastian Basierski 	rc = spdk_bdev_alias_add(bdev[1], "proper alias 1");
1089b9afa3c7SSebastian Basierski 	CU_ASSERT(rc == 0);
1090b9afa3c7SSebastian Basierski 
1091b9afa3c7SSebastian Basierski 	/* Trying removing an alias from registered bdevs */
1092b9afa3c7SSebastian Basierski 
1093b9afa3c7SSebastian Basierski 	/* Alias is not on a bdev aliases list, so this one should fail */
1094b9afa3c7SSebastian Basierski 	rc = spdk_bdev_alias_del(bdev[0], "not existing");
1095b9afa3c7SSebastian Basierski 	CU_ASSERT(rc == -ENOENT);
1096b9afa3c7SSebastian Basierski 
1097b9afa3c7SSebastian Basierski 	/* Alias is present on a bdev aliases list, so this one should pass */
1098b9afa3c7SSebastian Basierski 	rc = spdk_bdev_alias_del(bdev[0], "proper alias 0");
1099b9afa3c7SSebastian Basierski 	CU_ASSERT(rc == 0);
1100b9afa3c7SSebastian Basierski 
1101b9afa3c7SSebastian Basierski 	/* Alias is present on a bdev aliases list, so this one should pass */
1102b9afa3c7SSebastian Basierski 	rc = spdk_bdev_alias_del(bdev[1], "proper alias 1");
1103b9afa3c7SSebastian Basierski 	CU_ASSERT(rc == 0);
1104b9afa3c7SSebastian Basierski 
1105b9afa3c7SSebastian Basierski 	/* Trying to remove name instead of alias, so this one should fail, name cannot be changed or removed */
1106b9afa3c7SSebastian Basierski 	rc = spdk_bdev_alias_del(bdev[0], bdev[0]->name);
1107b9afa3c7SSebastian Basierski 	CU_ASSERT(rc != 0);
1108b9afa3c7SSebastian Basierski 
11096deac3e6Swuzhouhui 	/* Trying to del all alias from empty alias list */
11106deac3e6Swuzhouhui 	spdk_bdev_alias_del_all(bdev[2]);
111111ccf3beSSeth Howell 	SPDK_CU_ASSERT_FATAL(TAILQ_EMPTY(&bdev[2]->aliases));
11126deac3e6Swuzhouhui 
11136deac3e6Swuzhouhui 	/* Trying to del all alias from non-empty alias list */
11146deac3e6Swuzhouhui 	rc = spdk_bdev_alias_add(bdev[2], "alias0");
11156deac3e6Swuzhouhui 	CU_ASSERT(rc == 0);
11166deac3e6Swuzhouhui 	rc = spdk_bdev_alias_add(bdev[2], "alias1");
11176deac3e6Swuzhouhui 	CU_ASSERT(rc == 0);
11186deac3e6Swuzhouhui 	spdk_bdev_alias_del_all(bdev[2]);
11196deac3e6Swuzhouhui 	CU_ASSERT(TAILQ_EMPTY(&bdev[2]->aliases));
11206deac3e6Swuzhouhui 
1121b9afa3c7SSebastian Basierski 	/* Unregister and free bdevs */
1122b9afa3c7SSebastian Basierski 	spdk_bdev_unregister(bdev[0], NULL, NULL);
1123b9afa3c7SSebastian Basierski 	spdk_bdev_unregister(bdev[1], NULL, NULL);
11246deac3e6Swuzhouhui 	spdk_bdev_unregister(bdev[2], NULL, NULL);
1125b9afa3c7SSebastian Basierski 
1126270a25dfSBen Walker 	poll_threads();
1127270a25dfSBen Walker 
1128b9afa3c7SSebastian Basierski 	free(bdev[0]);
1129b9afa3c7SSebastian Basierski 	free(bdev[1]);
11306deac3e6Swuzhouhui 	free(bdev[2]);
1131cec70a60SShuhei Matsumoto 
1132cec70a60SShuhei Matsumoto 	ut_fini_bdev();
1133b9afa3c7SSebastian Basierski }
1134b9afa3c7SSebastian Basierski 
113532d7c91cSJim Harris static void
113632d7c91cSJim Harris io_done(struct spdk_bdev_io *bdev_io, bool success, void *cb_arg)
113732d7c91cSJim Harris {
11384bd97621SJim Harris 	g_io_done = true;
11390df515a8SShuhei Matsumoto 	g_io_status = bdev_io->internal.status;
11406127461cSmatthewb 	if ((bdev_io->type == SPDK_BDEV_IO_TYPE_ZCOPY) &&
11416127461cSmatthewb 	    (bdev_io->u.bdev.zcopy.start)) {
11426127461cSmatthewb 		g_zcopy_bdev_io = bdev_io;
11436127461cSmatthewb 	} else {
114432d7c91cSJim Harris 		spdk_bdev_free_io(bdev_io);
11456127461cSmatthewb 		g_zcopy_bdev_io = NULL;
11466127461cSmatthewb 	}
114732d7c91cSJim Harris }
114832d7c91cSJim Harris 
114932d7c91cSJim Harris struct bdev_ut_io_wait_entry {
115032d7c91cSJim Harris 	struct spdk_bdev_io_wait_entry	entry;
115132d7c91cSJim Harris 	struct spdk_io_channel		*io_ch;
115232d7c91cSJim Harris 	struct spdk_bdev_desc		*desc;
115332d7c91cSJim Harris 	bool				submitted;
115432d7c91cSJim Harris };
115532d7c91cSJim Harris 
115632d7c91cSJim Harris static void
115732d7c91cSJim Harris io_wait_cb(void *arg)
115832d7c91cSJim Harris {
115932d7c91cSJim Harris 	struct bdev_ut_io_wait_entry *entry = arg;
116032d7c91cSJim Harris 	int rc;
116132d7c91cSJim Harris 
116232d7c91cSJim Harris 	rc = spdk_bdev_read_blocks(entry->desc, entry->io_ch, NULL, 0, 1, io_done, NULL);
116332d7c91cSJim Harris 	CU_ASSERT(rc == 0);
116432d7c91cSJim Harris 	entry->submitted = true;
116532d7c91cSJim Harris }
116632d7c91cSJim Harris 
116732d7c91cSJim Harris static void
11689da1c738SChangpeng Liu bdev_io_types_test(void)
11699da1c738SChangpeng Liu {
11709da1c738SChangpeng Liu 	struct spdk_bdev *bdev;
11719da1c738SChangpeng Liu 	struct spdk_bdev_desc *desc = NULL;
11729da1c738SChangpeng Liu 	struct spdk_io_channel *io_ch;
1173f420b9efSZiye Yang 	struct spdk_bdev_opts bdev_opts = {};
11749da1c738SChangpeng Liu 	int rc;
11759da1c738SChangpeng Liu 
1176f420b9efSZiye Yang 	spdk_bdev_get_opts(&bdev_opts, sizeof(bdev_opts));
1177f420b9efSZiye Yang 	bdev_opts.bdev_io_pool_size = 4;
1178f420b9efSZiye Yang 	bdev_opts.bdev_io_cache_size = 2;
1179107741fcSKonrad Sztyber 	ut_init_bdev(&bdev_opts);
11809da1c738SChangpeng Liu 
11819da1c738SChangpeng Liu 	bdev = allocate_bdev("bdev0");
11829da1c738SChangpeng Liu 
118375dfecbbSShuhei Matsumoto 	rc = spdk_bdev_open_ext("bdev0", true, bdev_ut_event_cb, NULL, &desc);
11849da1c738SChangpeng Liu 	CU_ASSERT(rc == 0);
11859da1c738SChangpeng Liu 	poll_threads();
11869da1c738SChangpeng Liu 	SPDK_CU_ASSERT_FATAL(desc != NULL);
118775dfecbbSShuhei Matsumoto 	CU_ASSERT(bdev == spdk_bdev_desc_get_bdev(desc));
11889da1c738SChangpeng Liu 	io_ch = spdk_bdev_get_io_channel(desc);
11899da1c738SChangpeng Liu 	CU_ASSERT(io_ch != NULL);
11909da1c738SChangpeng Liu 
11919da1c738SChangpeng Liu 	/* WRITE and WRITE ZEROES are not supported */
1192e2918289SKonrad Sztyber 	ut_enable_io_type(SPDK_BDEV_IO_TYPE_WRITE_ZEROES, false);
1193e2918289SKonrad Sztyber 	ut_enable_io_type(SPDK_BDEV_IO_TYPE_WRITE, false);
11949da1c738SChangpeng Liu 	rc = spdk_bdev_write_zeroes_blocks(desc, io_ch, 0, 128, io_done, NULL);
11959da1c738SChangpeng Liu 	CU_ASSERT(rc == -ENOTSUP);
1196e2918289SKonrad Sztyber 	ut_enable_io_type(SPDK_BDEV_IO_TYPE_WRITE_ZEROES, true);
1197e2918289SKonrad Sztyber 	ut_enable_io_type(SPDK_BDEV_IO_TYPE_WRITE, true);
11989da1c738SChangpeng Liu 
1199a9593c79SEvgeniy Kochetov 	/* NVME_IO, NVME_IO_MD and NVME_ADMIN are not supported */
1200a9593c79SEvgeniy Kochetov 	ut_enable_io_type(SPDK_BDEV_IO_TYPE_NVME_IO, false);
1201a9593c79SEvgeniy Kochetov 	ut_enable_io_type(SPDK_BDEV_IO_TYPE_NVME_IO_MD, false);
1202a9593c79SEvgeniy Kochetov 	ut_enable_io_type(SPDK_BDEV_IO_TYPE_NVME_ADMIN, false);
1203a9593c79SEvgeniy Kochetov 	rc = spdk_bdev_nvme_io_passthru(desc, io_ch, NULL, NULL, 0, NULL, NULL);
1204a9593c79SEvgeniy Kochetov 	CU_ASSERT(rc == -ENOTSUP);
1205a9593c79SEvgeniy Kochetov 	rc = spdk_bdev_nvme_io_passthru_md(desc, io_ch, NULL, NULL, 0, NULL, 0, NULL, NULL);
1206a9593c79SEvgeniy Kochetov 	CU_ASSERT(rc == -ENOTSUP);
1207a9593c79SEvgeniy Kochetov 	rc = spdk_bdev_nvme_admin_passthru(desc, io_ch, NULL, NULL, 0, NULL, NULL);
1208a9593c79SEvgeniy Kochetov 	CU_ASSERT(rc == -ENOTSUP);
1209a9593c79SEvgeniy Kochetov 	ut_enable_io_type(SPDK_BDEV_IO_TYPE_NVME_IO, true);
1210a9593c79SEvgeniy Kochetov 	ut_enable_io_type(SPDK_BDEV_IO_TYPE_NVME_IO_MD, true);
1211a9593c79SEvgeniy Kochetov 	ut_enable_io_type(SPDK_BDEV_IO_TYPE_NVME_ADMIN, true);
1212a9593c79SEvgeniy Kochetov 
12139da1c738SChangpeng Liu 	spdk_put_io_channel(io_ch);
12149da1c738SChangpeng Liu 	spdk_bdev_close(desc);
12159da1c738SChangpeng Liu 	free_bdev(bdev);
1216107741fcSKonrad Sztyber 	ut_fini_bdev();
12179da1c738SChangpeng Liu }
12189da1c738SChangpeng Liu 
12199da1c738SChangpeng Liu static void
122032d7c91cSJim Harris bdev_io_wait_test(void)
122132d7c91cSJim Harris {
122232d7c91cSJim Harris 	struct spdk_bdev *bdev;
1223fb0fe6b1SShuhei Matsumoto 	struct spdk_bdev_desc *desc = NULL;
122432d7c91cSJim Harris 	struct spdk_io_channel *io_ch;
1225f420b9efSZiye Yang 	struct spdk_bdev_opts bdev_opts = {};
122632d7c91cSJim Harris 	struct bdev_ut_io_wait_entry io_wait_entry;
122732d7c91cSJim Harris 	struct bdev_ut_io_wait_entry io_wait_entry2;
122832d7c91cSJim Harris 	int rc;
122932d7c91cSJim Harris 
1230f420b9efSZiye Yang 	spdk_bdev_get_opts(&bdev_opts, sizeof(bdev_opts));
1231f420b9efSZiye Yang 	bdev_opts.bdev_io_pool_size = 4;
1232f420b9efSZiye Yang 	bdev_opts.bdev_io_cache_size = 2;
1233107741fcSKonrad Sztyber 	ut_init_bdev(&bdev_opts);
123432d7c91cSJim Harris 
123532d7c91cSJim Harris 	bdev = allocate_bdev("bdev0");
123632d7c91cSJim Harris 
123775dfecbbSShuhei Matsumoto 	rc = spdk_bdev_open_ext("bdev0", true, bdev_ut_event_cb, NULL, &desc);
123832d7c91cSJim Harris 	CU_ASSERT(rc == 0);
1239270a25dfSBen Walker 	poll_threads();
1240fb0fe6b1SShuhei Matsumoto 	SPDK_CU_ASSERT_FATAL(desc != NULL);
124175dfecbbSShuhei Matsumoto 	CU_ASSERT(bdev == spdk_bdev_desc_get_bdev(desc));
124232d7c91cSJim Harris 	io_ch = spdk_bdev_get_io_channel(desc);
124332d7c91cSJim Harris 	CU_ASSERT(io_ch != NULL);
124432d7c91cSJim Harris 
124532d7c91cSJim Harris 	rc = spdk_bdev_read_blocks(desc, io_ch, NULL, 0, 1, io_done, NULL);
124632d7c91cSJim Harris 	CU_ASSERT(rc == 0);
124732d7c91cSJim Harris 	rc = spdk_bdev_read_blocks(desc, io_ch, NULL, 0, 1, io_done, NULL);
124832d7c91cSJim Harris 	CU_ASSERT(rc == 0);
124932d7c91cSJim Harris 	rc = spdk_bdev_read_blocks(desc, io_ch, NULL, 0, 1, io_done, NULL);
125032d7c91cSJim Harris 	CU_ASSERT(rc == 0);
125132d7c91cSJim Harris 	rc = spdk_bdev_read_blocks(desc, io_ch, NULL, 0, 1, io_done, NULL);
125232d7c91cSJim Harris 	CU_ASSERT(rc == 0);
125332d7c91cSJim Harris 	CU_ASSERT(g_bdev_ut_channel->outstanding_io_count == 4);
125432d7c91cSJim Harris 
125532d7c91cSJim Harris 	rc = spdk_bdev_read_blocks(desc, io_ch, NULL, 0, 1, io_done, NULL);
125632d7c91cSJim Harris 	CU_ASSERT(rc == -ENOMEM);
125732d7c91cSJim Harris 
125832d7c91cSJim Harris 	io_wait_entry.entry.bdev = bdev;
125932d7c91cSJim Harris 	io_wait_entry.entry.cb_fn = io_wait_cb;
126032d7c91cSJim Harris 	io_wait_entry.entry.cb_arg = &io_wait_entry;
126132d7c91cSJim Harris 	io_wait_entry.io_ch = io_ch;
126232d7c91cSJim Harris 	io_wait_entry.desc = desc;
126332d7c91cSJim Harris 	io_wait_entry.submitted = false;
126432d7c91cSJim Harris 	/* Cannot use the same io_wait_entry for two different calls. */
126532d7c91cSJim Harris 	memcpy(&io_wait_entry2, &io_wait_entry, sizeof(io_wait_entry));
126632d7c91cSJim Harris 	io_wait_entry2.entry.cb_arg = &io_wait_entry2;
126732d7c91cSJim Harris 
126832d7c91cSJim Harris 	/* Queue two I/O waits. */
126932d7c91cSJim Harris 	rc = spdk_bdev_queue_io_wait(bdev, io_ch, &io_wait_entry.entry);
127032d7c91cSJim Harris 	CU_ASSERT(rc == 0);
127132d7c91cSJim Harris 	CU_ASSERT(io_wait_entry.submitted == false);
127232d7c91cSJim Harris 	rc = spdk_bdev_queue_io_wait(bdev, io_ch, &io_wait_entry2.entry);
127332d7c91cSJim Harris 	CU_ASSERT(rc == 0);
127432d7c91cSJim Harris 	CU_ASSERT(io_wait_entry2.submitted == false);
127532d7c91cSJim Harris 
127632d7c91cSJim Harris 	stub_complete_io(1);
127732d7c91cSJim Harris 	CU_ASSERT(g_bdev_ut_channel->outstanding_io_count == 4);
127832d7c91cSJim Harris 	CU_ASSERT(io_wait_entry.submitted == true);
127932d7c91cSJim Harris 	CU_ASSERT(io_wait_entry2.submitted == false);
128032d7c91cSJim Harris 
128132d7c91cSJim Harris 	stub_complete_io(1);
128232d7c91cSJim Harris 	CU_ASSERT(g_bdev_ut_channel->outstanding_io_count == 4);
128332d7c91cSJim Harris 	CU_ASSERT(io_wait_entry2.submitted == true);
128432d7c91cSJim Harris 
128532d7c91cSJim Harris 	stub_complete_io(4);
128632d7c91cSJim Harris 	CU_ASSERT(g_bdev_ut_channel->outstanding_io_count == 0);
128732d7c91cSJim Harris 
128832d7c91cSJim Harris 	spdk_put_io_channel(io_ch);
128932d7c91cSJim Harris 	spdk_bdev_close(desc);
129032d7c91cSJim Harris 	free_bdev(bdev);
1291107741fcSKonrad Sztyber 	ut_fini_bdev();
129232d7c91cSJim Harris }
129332d7c91cSJim Harris 
12944bd97621SJim Harris static void
12953b616c0fSJin Yu bdev_io_spans_split_test(void)
12964bd97621SJim Harris {
12974bd97621SJim Harris 	struct spdk_bdev bdev;
12984bd97621SJim Harris 	struct spdk_bdev_io bdev_io;
1299b45556e2SChangpeng Liu 	struct iovec iov[SPDK_BDEV_IO_NUM_CHILD_IOV];
13004bd97621SJim Harris 
13014bd97621SJim Harris 	memset(&bdev, 0, sizeof(bdev));
13023b616c0fSJin Yu 	bdev_io.u.bdev.iovs = iov;
13034bd97621SJim Harris 
1304d4d5e20dSChangpeng Liu 	bdev_io.type = SPDK_BDEV_IO_TYPE_READ;
13054bd97621SJim Harris 	bdev.optimal_io_boundary = 0;
13063b616c0fSJin Yu 	bdev.max_segment_size = 0;
13073b616c0fSJin Yu 	bdev.max_num_segments = 0;
13084bd97621SJim Harris 	bdev_io.bdev = &bdev;
13094bd97621SJim Harris 
13103b616c0fSJin Yu 	/* bdev has no optimal_io_boundary and max_size set - so this should return false. */
1311aa485663SJim Harris 	CU_ASSERT(bdev_io_should_split(&bdev_io) == false);
13124bd97621SJim Harris 
13133b616c0fSJin Yu 	bdev.split_on_optimal_io_boundary = true;
13144bd97621SJim Harris 	bdev.optimal_io_boundary = 32;
13154bd97621SJim Harris 	bdev_io.type = SPDK_BDEV_IO_TYPE_RESET;
13164bd97621SJim Harris 
13174bd97621SJim Harris 	/* RESETs are not based on LBAs - so this should return false. */
1318aa485663SJim Harris 	CU_ASSERT(bdev_io_should_split(&bdev_io) == false);
13194bd97621SJim Harris 
13204bd97621SJim Harris 	bdev_io.type = SPDK_BDEV_IO_TYPE_READ;
13214bd97621SJim Harris 	bdev_io.u.bdev.offset_blocks = 0;
13224bd97621SJim Harris 	bdev_io.u.bdev.num_blocks = 32;
13234bd97621SJim Harris 
13244bd97621SJim Harris 	/* This I/O run right up to, but does not cross, the boundary - so this should return false. */
1325aa485663SJim Harris 	CU_ASSERT(bdev_io_should_split(&bdev_io) == false);
13264bd97621SJim Harris 
13274bd97621SJim Harris 	bdev_io.u.bdev.num_blocks = 33;
13284bd97621SJim Harris 
13294bd97621SJim Harris 	/* This I/O spans a boundary. */
1330aa485663SJim Harris 	CU_ASSERT(bdev_io_should_split(&bdev_io) == true);
13313b616c0fSJin Yu 
13323b616c0fSJin Yu 	bdev_io.u.bdev.num_blocks = 32;
13333b616c0fSJin Yu 	bdev.max_segment_size = 512 * 32;
13343b616c0fSJin Yu 	bdev.max_num_segments = 1;
13353b616c0fSJin Yu 	bdev_io.u.bdev.iovcnt = 1;
13363b616c0fSJin Yu 	iov[0].iov_len = 512;
13373b616c0fSJin Yu 
13383b616c0fSJin Yu 	/* Does not cross and exceed max_size or max_segs */
13393b616c0fSJin Yu 	CU_ASSERT(bdev_io_should_split(&bdev_io) == false);
13403b616c0fSJin Yu 
13413b616c0fSJin Yu 	bdev.split_on_optimal_io_boundary = false;
13423b616c0fSJin Yu 	bdev.max_segment_size = 512;
13433b616c0fSJin Yu 	bdev.max_num_segments = 1;
13443b616c0fSJin Yu 	bdev_io.u.bdev.iovcnt = 2;
13453b616c0fSJin Yu 
13463b616c0fSJin Yu 	/* Exceed max_segs */
13473b616c0fSJin Yu 	CU_ASSERT(bdev_io_should_split(&bdev_io) == true);
13483b616c0fSJin Yu 
13493b616c0fSJin Yu 	bdev.max_num_segments = 2;
13503b616c0fSJin Yu 	iov[0].iov_len = 513;
13513b616c0fSJin Yu 	iov[1].iov_len = 512;
13523b616c0fSJin Yu 
13533b616c0fSJin Yu 	/* Exceed max_sizes */
13543b616c0fSJin Yu 	CU_ASSERT(bdev_io_should_split(&bdev_io) == true);
1355d6e9827eSArtur Paszkiewicz 
1356d6e9827eSArtur Paszkiewicz 	bdev.max_segment_size = 0;
1357d6e9827eSArtur Paszkiewicz 	bdev.write_unit_size = 32;
1358d6e9827eSArtur Paszkiewicz 	bdev.split_on_write_unit = true;
1359d6e9827eSArtur Paszkiewicz 	bdev_io.type = SPDK_BDEV_IO_TYPE_WRITE;
1360d6e9827eSArtur Paszkiewicz 
1361d6e9827eSArtur Paszkiewicz 	/* This I/O is one write unit */
1362d6e9827eSArtur Paszkiewicz 	CU_ASSERT(bdev_io_should_split(&bdev_io) == false);
1363d6e9827eSArtur Paszkiewicz 
1364d6e9827eSArtur Paszkiewicz 	bdev_io.u.bdev.num_blocks = 32 * 2;
1365d6e9827eSArtur Paszkiewicz 
1366d6e9827eSArtur Paszkiewicz 	/* This I/O is more than one write unit */
1367d6e9827eSArtur Paszkiewicz 	CU_ASSERT(bdev_io_should_split(&bdev_io) == true);
1368d6e9827eSArtur Paszkiewicz 
1369d6e9827eSArtur Paszkiewicz 	bdev_io.u.bdev.offset_blocks = 1;
1370d6e9827eSArtur Paszkiewicz 	bdev_io.u.bdev.num_blocks = 32;
1371d6e9827eSArtur Paszkiewicz 
1372d6e9827eSArtur Paszkiewicz 	/* This I/O is not aligned to write unit size */
1373d6e9827eSArtur Paszkiewicz 	CU_ASSERT(bdev_io_should_split(&bdev_io) == true);
13744bd97621SJim Harris }
13754bd97621SJim Harris 
13764bd97621SJim Harris static void
13779697d84fSJin Yu bdev_io_boundary_split_test(void)
13784bd97621SJim Harris {
13794bd97621SJim Harris 	struct spdk_bdev *bdev;
1380fb0fe6b1SShuhei Matsumoto 	struct spdk_bdev_desc *desc = NULL;
13814bd97621SJim Harris 	struct spdk_io_channel *io_ch;
1382f420b9efSZiye Yang 	struct spdk_bdev_opts bdev_opts = {};
1383b45556e2SChangpeng Liu 	struct iovec iov[SPDK_BDEV_IO_NUM_CHILD_IOV * 2];
13843c7894ffSShuhei Matsumoto 	struct ut_expected_io *expected_io;
138530f9fecaSJin Yu 	void *md_buf = (void *)0xFF000000;
13860df515a8SShuhei Matsumoto 	uint64_t i;
13874bd97621SJim Harris 	int rc;
13884bd97621SJim Harris 
1389f420b9efSZiye Yang 	spdk_bdev_get_opts(&bdev_opts, sizeof(bdev_opts));
1390f420b9efSZiye Yang 	bdev_opts.bdev_io_pool_size = 512;
1391f420b9efSZiye Yang 	bdev_opts.bdev_io_cache_size = 64;
1392107741fcSKonrad Sztyber 	ut_init_bdev(&bdev_opts);
13934bd97621SJim Harris 
13944bd97621SJim Harris 	bdev = allocate_bdev("bdev0");
13954bd97621SJim Harris 
139675dfecbbSShuhei Matsumoto 	rc = spdk_bdev_open_ext("bdev0", true, bdev_ut_event_cb, NULL, &desc);
13974bd97621SJim Harris 	CU_ASSERT(rc == 0);
1398fb0fe6b1SShuhei Matsumoto 	SPDK_CU_ASSERT_FATAL(desc != NULL);
139975dfecbbSShuhei Matsumoto 	CU_ASSERT(bdev == spdk_bdev_desc_get_bdev(desc));
14004bd97621SJim Harris 	io_ch = spdk_bdev_get_io_channel(desc);
14014bd97621SJim Harris 	CU_ASSERT(io_ch != NULL);
14024bd97621SJim Harris 
14034bd97621SJim Harris 	bdev->optimal_io_boundary = 16;
14044bd97621SJim Harris 	bdev->split_on_optimal_io_boundary = false;
14054bd97621SJim Harris 
14064bd97621SJim Harris 	g_io_done = false;
14074bd97621SJim Harris 
14084bd97621SJim Harris 	/* First test that the I/O does not get split if split_on_optimal_io_boundary == false. */
14093c7894ffSShuhei Matsumoto 	expected_io = ut_alloc_expected_io(SPDK_BDEV_IO_TYPE_READ, 14, 8, 1);
14103c7894ffSShuhei Matsumoto 	ut_expected_io_set_iov(expected_io, 0, (void *)0xF000, 8 * 512);
14113c7894ffSShuhei Matsumoto 	TAILQ_INSERT_TAIL(&g_bdev_ut_channel->expected_io, expected_io, link);
14124bd97621SJim Harris 
14134bd97621SJim Harris 	rc = spdk_bdev_read_blocks(desc, io_ch, (void *)0xF000, 14, 8, io_done, NULL);
14144bd97621SJim Harris 	CU_ASSERT(rc == 0);
14154bd97621SJim Harris 	CU_ASSERT(g_io_done == false);
14164bd97621SJim Harris 
14174bd97621SJim Harris 	CU_ASSERT(g_bdev_ut_channel->outstanding_io_count == 1);
14184bd97621SJim Harris 	stub_complete_io(1);
14194bd97621SJim Harris 	CU_ASSERT(g_io_done == true);
14204bd97621SJim Harris 	CU_ASSERT(g_bdev_ut_channel->outstanding_io_count == 0);
14214bd97621SJim Harris 
14224bd97621SJim Harris 	bdev->split_on_optimal_io_boundary = true;
142330f9fecaSJin Yu 	bdev->md_interleave = false;
142430f9fecaSJin Yu 	bdev->md_len = 8;
14254bd97621SJim Harris 
14264bd97621SJim Harris 	/* Now test that a single-vector command is split correctly.
14274bd97621SJim Harris 	 * Offset 14, length 8, payload 0xF000
14284bd97621SJim Harris 	 *  Child - Offset 14, length 2, payload 0xF000
14294bd97621SJim Harris 	 *  Child - Offset 16, length 6, payload 0xF000 + 2 * 512
14304bd97621SJim Harris 	 *
14318f33ef24SShuhei Matsumoto 	 * Set up the expected values before calling spdk_bdev_read_blocks
14324bd97621SJim Harris 	 */
14334bd97621SJim Harris 	g_io_done = false;
14343c7894ffSShuhei Matsumoto 	expected_io = ut_alloc_expected_io(SPDK_BDEV_IO_TYPE_READ, 14, 2, 1);
143530f9fecaSJin Yu 	expected_io->md_buf = md_buf;
14363c7894ffSShuhei Matsumoto 	ut_expected_io_set_iov(expected_io, 0, (void *)0xF000, 2 * 512);
14373c7894ffSShuhei Matsumoto 	TAILQ_INSERT_TAIL(&g_bdev_ut_channel->expected_io, expected_io, link);
14384bd97621SJim Harris 
14393c7894ffSShuhei Matsumoto 	expected_io = ut_alloc_expected_io(SPDK_BDEV_IO_TYPE_READ, 16, 6, 1);
144030f9fecaSJin Yu 	expected_io->md_buf = md_buf + 2 * 8;
14413c7894ffSShuhei Matsumoto 	ut_expected_io_set_iov(expected_io, 0, (void *)(0xF000 + 2 * 512), 6 * 512);
14423c7894ffSShuhei Matsumoto 	TAILQ_INSERT_TAIL(&g_bdev_ut_channel->expected_io, expected_io, link);
14434bd97621SJim Harris 
14448f33ef24SShuhei Matsumoto 	/* spdk_bdev_read_blocks will submit the first child immediately. */
144530f9fecaSJin Yu 	rc = spdk_bdev_read_blocks_with_md(desc, io_ch, (void *)0xF000, md_buf,
144630f9fecaSJin Yu 					   14, 8, io_done, NULL);
14478f33ef24SShuhei Matsumoto 	CU_ASSERT(rc == 0);
14488f33ef24SShuhei Matsumoto 	CU_ASSERT(g_io_done == false);
14498f33ef24SShuhei Matsumoto 
14505616c1edSShuhei Matsumoto 	CU_ASSERT(g_bdev_ut_channel->outstanding_io_count == 2);
14515616c1edSShuhei Matsumoto 	stub_complete_io(2);
14524bd97621SJim Harris 	CU_ASSERT(g_io_done == true);
14535616c1edSShuhei Matsumoto 	CU_ASSERT(g_bdev_ut_channel->outstanding_io_count == 0);
14544bd97621SJim Harris 
14554bd97621SJim Harris 	/* Now set up a more complex, multi-vector command that needs to be split,
14564bd97621SJim Harris 	 *  including splitting iovecs.
14574bd97621SJim Harris 	 */
14584bd97621SJim Harris 	iov[0].iov_base = (void *)0x10000;
14594bd97621SJim Harris 	iov[0].iov_len = 512;
14604bd97621SJim Harris 	iov[1].iov_base = (void *)0x20000;
14614bd97621SJim Harris 	iov[1].iov_len = 20 * 512;
14624bd97621SJim Harris 	iov[2].iov_base = (void *)0x30000;
14634bd97621SJim Harris 	iov[2].iov_len = 11 * 512;
14644bd97621SJim Harris 
14654bd97621SJim Harris 	g_io_done = false;
14663c7894ffSShuhei Matsumoto 	expected_io = ut_alloc_expected_io(SPDK_BDEV_IO_TYPE_WRITE, 14, 2, 2);
146730f9fecaSJin Yu 	expected_io->md_buf = md_buf;
14683c7894ffSShuhei Matsumoto 	ut_expected_io_set_iov(expected_io, 0, (void *)0x10000, 512);
14693c7894ffSShuhei Matsumoto 	ut_expected_io_set_iov(expected_io, 1, (void *)0x20000, 512);
14703c7894ffSShuhei Matsumoto 	TAILQ_INSERT_TAIL(&g_bdev_ut_channel->expected_io, expected_io, link);
14714bd97621SJim Harris 
14723c7894ffSShuhei Matsumoto 	expected_io = ut_alloc_expected_io(SPDK_BDEV_IO_TYPE_WRITE, 16, 16, 1);
147330f9fecaSJin Yu 	expected_io->md_buf = md_buf + 2 * 8;
14743c7894ffSShuhei Matsumoto 	ut_expected_io_set_iov(expected_io, 0, (void *)(0x20000 + 512), 16 * 512);
14753c7894ffSShuhei Matsumoto 	TAILQ_INSERT_TAIL(&g_bdev_ut_channel->expected_io, expected_io, link);
14764bd97621SJim Harris 
14773c7894ffSShuhei Matsumoto 	expected_io = ut_alloc_expected_io(SPDK_BDEV_IO_TYPE_WRITE, 32, 14, 2);
147830f9fecaSJin Yu 	expected_io->md_buf = md_buf + 18 * 8;
14793c7894ffSShuhei Matsumoto 	ut_expected_io_set_iov(expected_io, 0, (void *)(0x20000 + 17 * 512), 3 * 512);
14803c7894ffSShuhei Matsumoto 	ut_expected_io_set_iov(expected_io, 1, (void *)0x30000, 11 * 512);
14813c7894ffSShuhei Matsumoto 	TAILQ_INSERT_TAIL(&g_bdev_ut_channel->expected_io, expected_io, link);
14824bd97621SJim Harris 
148330f9fecaSJin Yu 	rc = spdk_bdev_writev_blocks_with_md(desc, io_ch, iov, 3, md_buf,
148430f9fecaSJin Yu 					     14, 32, io_done, NULL);
14858f33ef24SShuhei Matsumoto 	CU_ASSERT(rc == 0);
14868f33ef24SShuhei Matsumoto 	CU_ASSERT(g_io_done == false);
14878f33ef24SShuhei Matsumoto 
14885616c1edSShuhei Matsumoto 	CU_ASSERT(g_bdev_ut_channel->outstanding_io_count == 3);
14895616c1edSShuhei Matsumoto 	stub_complete_io(3);
14904bd97621SJim Harris 	CU_ASSERT(g_io_done == true);
14914bd97621SJim Harris 
14920df515a8SShuhei Matsumoto 	/* Test multi vector command that needs to be split by strip and then needs to be
14930df515a8SShuhei Matsumoto 	 * split further due to the capacity of child iovs.
14940df515a8SShuhei Matsumoto 	 */
1495b45556e2SChangpeng Liu 	for (i = 0; i < SPDK_BDEV_IO_NUM_CHILD_IOV * 2; i++) {
14960df515a8SShuhei Matsumoto 		iov[i].iov_base = (void *)((i + 1) * 0x10000);
14970df515a8SShuhei Matsumoto 		iov[i].iov_len = 512;
14980df515a8SShuhei Matsumoto 	}
14990df515a8SShuhei Matsumoto 
1500b45556e2SChangpeng Liu 	bdev->optimal_io_boundary = SPDK_BDEV_IO_NUM_CHILD_IOV;
15010df515a8SShuhei Matsumoto 	g_io_done = false;
1502b45556e2SChangpeng Liu 	expected_io = ut_alloc_expected_io(SPDK_BDEV_IO_TYPE_READ, 0, SPDK_BDEV_IO_NUM_CHILD_IOV,
1503b45556e2SChangpeng Liu 					   SPDK_BDEV_IO_NUM_CHILD_IOV);
150430f9fecaSJin Yu 	expected_io->md_buf = md_buf;
1505b45556e2SChangpeng Liu 	for (i = 0; i < SPDK_BDEV_IO_NUM_CHILD_IOV; i++) {
15063c7894ffSShuhei Matsumoto 		ut_expected_io_set_iov(expected_io, i, (void *)((i + 1) * 0x10000), 512);
15070df515a8SShuhei Matsumoto 	}
15083c7894ffSShuhei Matsumoto 	TAILQ_INSERT_TAIL(&g_bdev_ut_channel->expected_io, expected_io, link);
15090df515a8SShuhei Matsumoto 
1510b45556e2SChangpeng Liu 	expected_io = ut_alloc_expected_io(SPDK_BDEV_IO_TYPE_READ, SPDK_BDEV_IO_NUM_CHILD_IOV,
1511b45556e2SChangpeng Liu 					   SPDK_BDEV_IO_NUM_CHILD_IOV, SPDK_BDEV_IO_NUM_CHILD_IOV);
1512b45556e2SChangpeng Liu 	expected_io->md_buf = md_buf + SPDK_BDEV_IO_NUM_CHILD_IOV * 8;
1513b45556e2SChangpeng Liu 	for (i = 0; i < SPDK_BDEV_IO_NUM_CHILD_IOV; i++) {
15143c7894ffSShuhei Matsumoto 		ut_expected_io_set_iov(expected_io, i,
1515b45556e2SChangpeng Liu 				       (void *)((i + 1 + SPDK_BDEV_IO_NUM_CHILD_IOV) * 0x10000), 512);
15160df515a8SShuhei Matsumoto 	}
15173c7894ffSShuhei Matsumoto 	TAILQ_INSERT_TAIL(&g_bdev_ut_channel->expected_io, expected_io, link);
15180df515a8SShuhei Matsumoto 
1519b45556e2SChangpeng Liu 	rc = spdk_bdev_readv_blocks_with_md(desc, io_ch, iov, SPDK_BDEV_IO_NUM_CHILD_IOV * 2, md_buf,
1520b45556e2SChangpeng Liu 					    0, SPDK_BDEV_IO_NUM_CHILD_IOV * 2, io_done, NULL);
15218f33ef24SShuhei Matsumoto 	CU_ASSERT(rc == 0);
15228f33ef24SShuhei Matsumoto 	CU_ASSERT(g_io_done == false);
15238f33ef24SShuhei Matsumoto 
15240df515a8SShuhei Matsumoto 	CU_ASSERT(g_bdev_ut_channel->outstanding_io_count == 1);
15250df515a8SShuhei Matsumoto 	stub_complete_io(1);
15260df515a8SShuhei Matsumoto 	CU_ASSERT(g_io_done == false);
15270df515a8SShuhei Matsumoto 
15280df515a8SShuhei Matsumoto 	CU_ASSERT(g_bdev_ut_channel->outstanding_io_count == 1);
15290df515a8SShuhei Matsumoto 	stub_complete_io(1);
15300df515a8SShuhei Matsumoto 	CU_ASSERT(g_io_done == true);
15315616c1edSShuhei Matsumoto 	CU_ASSERT(g_bdev_ut_channel->outstanding_io_count == 0);
15320df515a8SShuhei Matsumoto 
15330df515a8SShuhei Matsumoto 	/* Test multi vector command that needs to be split by strip and then needs to be
1534598ba408Slorneli 	 * split further due to the capacity of child iovs. In this case, the length of
1535598ba408Slorneli 	 * the rest of iovec array with an I/O boundary is the multiple of block size.
1536598ba408Slorneli 	 */
1537598ba408Slorneli 
1538598ba408Slorneli 	/* Fill iovec array for exactly one boundary. The iovec cnt for this boundary
1539b45556e2SChangpeng Liu 	 * is SPDK_BDEV_IO_NUM_CHILD_IOV + 1, which exceeds the capacity of child iovs.
1540598ba408Slorneli 	 */
1541b45556e2SChangpeng Liu 	for (i = 0; i < SPDK_BDEV_IO_NUM_CHILD_IOV - 2; i++) {
1542598ba408Slorneli 		iov[i].iov_base = (void *)((i + 1) * 0x10000);
1543598ba408Slorneli 		iov[i].iov_len = 512;
1544598ba408Slorneli 	}
1545b45556e2SChangpeng Liu 	for (i = SPDK_BDEV_IO_NUM_CHILD_IOV - 2; i < SPDK_BDEV_IO_NUM_CHILD_IOV; i++) {
1546598ba408Slorneli 		iov[i].iov_base = (void *)((i + 1) * 0x10000);
1547598ba408Slorneli 		iov[i].iov_len = 256;
1548598ba408Slorneli 	}
1549b45556e2SChangpeng Liu 	iov[SPDK_BDEV_IO_NUM_CHILD_IOV].iov_base = (void *)((SPDK_BDEV_IO_NUM_CHILD_IOV + 1) * 0x10000);
1550b45556e2SChangpeng Liu 	iov[SPDK_BDEV_IO_NUM_CHILD_IOV].iov_len = 512;
1551598ba408Slorneli 
1552598ba408Slorneli 	/* Add an extra iovec to trigger split */
1553b45556e2SChangpeng Liu 	iov[SPDK_BDEV_IO_NUM_CHILD_IOV + 1].iov_base = (void *)((SPDK_BDEV_IO_NUM_CHILD_IOV + 2) * 0x10000);
1554b45556e2SChangpeng Liu 	iov[SPDK_BDEV_IO_NUM_CHILD_IOV + 1].iov_len = 512;
1555598ba408Slorneli 
1556b45556e2SChangpeng Liu 	bdev->optimal_io_boundary = SPDK_BDEV_IO_NUM_CHILD_IOV;
1557598ba408Slorneli 	g_io_done = false;
1558598ba408Slorneli 	expected_io = ut_alloc_expected_io(SPDK_BDEV_IO_TYPE_READ, 0,
1559b45556e2SChangpeng Liu 					   SPDK_BDEV_IO_NUM_CHILD_IOV - 1, SPDK_BDEV_IO_NUM_CHILD_IOV);
156030f9fecaSJin Yu 	expected_io->md_buf = md_buf;
1561b45556e2SChangpeng Liu 	for (i = 0; i < SPDK_BDEV_IO_NUM_CHILD_IOV - 2; i++) {
1562598ba408Slorneli 		ut_expected_io_set_iov(expected_io, i,
1563598ba408Slorneli 				       (void *)((i + 1) * 0x10000), 512);
1564598ba408Slorneli 	}
1565b45556e2SChangpeng Liu 	for (i = SPDK_BDEV_IO_NUM_CHILD_IOV - 2; i < SPDK_BDEV_IO_NUM_CHILD_IOV; i++) {
1566598ba408Slorneli 		ut_expected_io_set_iov(expected_io, i,
1567598ba408Slorneli 				       (void *)((i + 1) * 0x10000), 256);
1568598ba408Slorneli 	}
1569598ba408Slorneli 	TAILQ_INSERT_TAIL(&g_bdev_ut_channel->expected_io, expected_io, link);
1570598ba408Slorneli 
1571b45556e2SChangpeng Liu 	expected_io = ut_alloc_expected_io(SPDK_BDEV_IO_TYPE_READ, SPDK_BDEV_IO_NUM_CHILD_IOV - 1,
1572598ba408Slorneli 					   1, 1);
1573b45556e2SChangpeng Liu 	expected_io->md_buf = md_buf + (SPDK_BDEV_IO_NUM_CHILD_IOV - 1) * 8;
1574598ba408Slorneli 	ut_expected_io_set_iov(expected_io, 0,
1575b45556e2SChangpeng Liu 			       (void *)((SPDK_BDEV_IO_NUM_CHILD_IOV + 1) * 0x10000), 512);
1576598ba408Slorneli 	TAILQ_INSERT_TAIL(&g_bdev_ut_channel->expected_io, expected_io, link);
1577598ba408Slorneli 
1578b45556e2SChangpeng Liu 	expected_io = ut_alloc_expected_io(SPDK_BDEV_IO_TYPE_READ, SPDK_BDEV_IO_NUM_CHILD_IOV,
1579598ba408Slorneli 					   1, 1);
1580b45556e2SChangpeng Liu 	expected_io->md_buf = md_buf + SPDK_BDEV_IO_NUM_CHILD_IOV * 8;
1581598ba408Slorneli 	ut_expected_io_set_iov(expected_io, 0,
1582b45556e2SChangpeng Liu 			       (void *)((SPDK_BDEV_IO_NUM_CHILD_IOV + 2) * 0x10000), 512);
1583598ba408Slorneli 	TAILQ_INSERT_TAIL(&g_bdev_ut_channel->expected_io, expected_io, link);
1584598ba408Slorneli 
1585b45556e2SChangpeng Liu 	rc = spdk_bdev_readv_blocks_with_md(desc, io_ch, iov, SPDK_BDEV_IO_NUM_CHILD_IOV + 2, md_buf,
1586b45556e2SChangpeng Liu 					    0, SPDK_BDEV_IO_NUM_CHILD_IOV + 1, io_done, NULL);
1587598ba408Slorneli 	CU_ASSERT(rc == 0);
1588598ba408Slorneli 	CU_ASSERT(g_io_done == false);
1589598ba408Slorneli 
1590598ba408Slorneli 	CU_ASSERT(g_bdev_ut_channel->outstanding_io_count == 1);
1591598ba408Slorneli 	stub_complete_io(1);
1592598ba408Slorneli 	CU_ASSERT(g_io_done == false);
1593598ba408Slorneli 
1594598ba408Slorneli 	CU_ASSERT(g_bdev_ut_channel->outstanding_io_count == 2);
1595598ba408Slorneli 	stub_complete_io(2);
1596598ba408Slorneli 	CU_ASSERT(g_io_done == true);
1597598ba408Slorneli 	CU_ASSERT(g_bdev_ut_channel->outstanding_io_count == 0);
1598598ba408Slorneli 
1599598ba408Slorneli 	/* Test multi vector command that needs to be split by strip and then needs to be
1600efd7b514SChangpeng Liu 	 * split further due to the capacity of child iovs, the child request offset should
1601efd7b514SChangpeng Liu 	 * be rewind to last aligned offset and go success without error.
16020df515a8SShuhei Matsumoto 	 */
1603b45556e2SChangpeng Liu 	for (i = 0; i < SPDK_BDEV_IO_NUM_CHILD_IOV - 1; i++) {
16040df515a8SShuhei Matsumoto 		iov[i].iov_base = (void *)((i + 1) * 0x10000);
16050df515a8SShuhei Matsumoto 		iov[i].iov_len = 512;
16060df515a8SShuhei Matsumoto 	}
1607b45556e2SChangpeng Liu 	iov[SPDK_BDEV_IO_NUM_CHILD_IOV - 1].iov_base = (void *)(SPDK_BDEV_IO_NUM_CHILD_IOV * 0x10000);
1608b45556e2SChangpeng Liu 	iov[SPDK_BDEV_IO_NUM_CHILD_IOV - 1].iov_len = 256;
16090df515a8SShuhei Matsumoto 
1610b45556e2SChangpeng Liu 	iov[SPDK_BDEV_IO_NUM_CHILD_IOV].iov_base = (void *)((SPDK_BDEV_IO_NUM_CHILD_IOV + 1) * 0x10000);
1611b45556e2SChangpeng Liu 	iov[SPDK_BDEV_IO_NUM_CHILD_IOV].iov_len = 256;
1612efd7b514SChangpeng Liu 
1613b45556e2SChangpeng Liu 	iov[SPDK_BDEV_IO_NUM_CHILD_IOV + 1].iov_base = (void *)((SPDK_BDEV_IO_NUM_CHILD_IOV + 2) * 0x10000);
1614b45556e2SChangpeng Liu 	iov[SPDK_BDEV_IO_NUM_CHILD_IOV + 1].iov_len = 512;
1615efd7b514SChangpeng Liu 
1616b45556e2SChangpeng Liu 	bdev->optimal_io_boundary = SPDK_BDEV_IO_NUM_CHILD_IOV;
16170df515a8SShuhei Matsumoto 	g_io_done = false;
16180df515a8SShuhei Matsumoto 	g_io_status = 0;
1619b45556e2SChangpeng Liu 	/* The first expected io should be start from offset 0 to SPDK_BDEV_IO_NUM_CHILD_IOV - 1 */
1620efd7b514SChangpeng Liu 	expected_io = ut_alloc_expected_io(SPDK_BDEV_IO_TYPE_READ, 0,
1621b45556e2SChangpeng Liu 					   SPDK_BDEV_IO_NUM_CHILD_IOV - 1, SPDK_BDEV_IO_NUM_CHILD_IOV - 1);
162230f9fecaSJin Yu 	expected_io->md_buf = md_buf;
1623b45556e2SChangpeng Liu 	for (i = 0; i < SPDK_BDEV_IO_NUM_CHILD_IOV - 1; i++) {
1624efd7b514SChangpeng Liu 		ut_expected_io_set_iov(expected_io, i,
1625efd7b514SChangpeng Liu 				       (void *)((i + 1) * 0x10000), 512);
1626efd7b514SChangpeng Liu 	}
1627efd7b514SChangpeng Liu 	TAILQ_INSERT_TAIL(&g_bdev_ut_channel->expected_io, expected_io, link);
1628b45556e2SChangpeng Liu 	/* The second expected io should be start from offset SPDK_BDEV_IO_NUM_CHILD_IOV - 1 to SPDK_BDEV_IO_NUM_CHILD_IOV */
1629b45556e2SChangpeng Liu 	expected_io = ut_alloc_expected_io(SPDK_BDEV_IO_TYPE_READ, SPDK_BDEV_IO_NUM_CHILD_IOV - 1,
1630efd7b514SChangpeng Liu 					   1, 2);
1631b45556e2SChangpeng Liu 	expected_io->md_buf = md_buf + (SPDK_BDEV_IO_NUM_CHILD_IOV - 1) * 8;
1632efd7b514SChangpeng Liu 	ut_expected_io_set_iov(expected_io, 0,
1633b45556e2SChangpeng Liu 			       (void *)(SPDK_BDEV_IO_NUM_CHILD_IOV * 0x10000), 256);
1634efd7b514SChangpeng Liu 	ut_expected_io_set_iov(expected_io, 1,
1635b45556e2SChangpeng Liu 			       (void *)((SPDK_BDEV_IO_NUM_CHILD_IOV + 1) * 0x10000), 256);
1636efd7b514SChangpeng Liu 	TAILQ_INSERT_TAIL(&g_bdev_ut_channel->expected_io, expected_io, link);
1637b45556e2SChangpeng Liu 	/* The third expected io should be start from offset SPDK_BDEV_IO_NUM_CHILD_IOV to SPDK_BDEV_IO_NUM_CHILD_IOV + 1 */
1638b45556e2SChangpeng Liu 	expected_io = ut_alloc_expected_io(SPDK_BDEV_IO_TYPE_READ, SPDK_BDEV_IO_NUM_CHILD_IOV,
1639efd7b514SChangpeng Liu 					   1, 1);
1640b45556e2SChangpeng Liu 	expected_io->md_buf = md_buf + SPDK_BDEV_IO_NUM_CHILD_IOV * 8;
1641efd7b514SChangpeng Liu 	ut_expected_io_set_iov(expected_io, 0,
1642b45556e2SChangpeng Liu 			       (void *)((SPDK_BDEV_IO_NUM_CHILD_IOV + 2) * 0x10000), 512);
1643efd7b514SChangpeng Liu 	TAILQ_INSERT_TAIL(&g_bdev_ut_channel->expected_io, expected_io, link);
16440df515a8SShuhei Matsumoto 
1645b45556e2SChangpeng Liu 	rc = spdk_bdev_readv_blocks_with_md(desc, io_ch, iov, SPDK_BDEV_IO_NUM_CHILD_IOV * 2, md_buf,
1646b45556e2SChangpeng Liu 					    0, SPDK_BDEV_IO_NUM_CHILD_IOV + 1, io_done, NULL);
16470df515a8SShuhei Matsumoto 	CU_ASSERT(rc == 0);
1648efd7b514SChangpeng Liu 	CU_ASSERT(g_io_done == false);
1649efd7b514SChangpeng Liu 
1650efd7b514SChangpeng Liu 	CU_ASSERT(g_bdev_ut_channel->outstanding_io_count == 1);
1651efd7b514SChangpeng Liu 	stub_complete_io(1);
1652efd7b514SChangpeng Liu 	CU_ASSERT(g_io_done == false);
1653efd7b514SChangpeng Liu 
1654efd7b514SChangpeng Liu 	CU_ASSERT(g_bdev_ut_channel->outstanding_io_count == 2);
1655efd7b514SChangpeng Liu 	stub_complete_io(2);
16560df515a8SShuhei Matsumoto 	CU_ASSERT(g_io_done == true);
1657efd7b514SChangpeng Liu 	CU_ASSERT(g_bdev_ut_channel->outstanding_io_count == 0);
16580df515a8SShuhei Matsumoto 
16593deaf005SShuhei Matsumoto 	/* Test multi vector command that needs to be split due to the IO boundary and
16603deaf005SShuhei Matsumoto 	 * the capacity of child iovs. Especially test the case when the command is
16613deaf005SShuhei Matsumoto 	 * split due to the capacity of child iovs, the tail address is not aligned with
16623deaf005SShuhei Matsumoto 	 * block size and is rewinded to the aligned address.
16633deaf005SShuhei Matsumoto 	 *
16643deaf005SShuhei Matsumoto 	 * The iovecs used in read request is complex but is based on the data
16653deaf005SShuhei Matsumoto 	 * collected in the real issue. We change the base addresses but keep the lengths
16663deaf005SShuhei Matsumoto 	 * not to loose the credibility of the test.
16673deaf005SShuhei Matsumoto 	 */
16683deaf005SShuhei Matsumoto 	bdev->optimal_io_boundary = 128;
16693deaf005SShuhei Matsumoto 	g_io_done = false;
16703deaf005SShuhei Matsumoto 	g_io_status = 0;
16713deaf005SShuhei Matsumoto 
16723deaf005SShuhei Matsumoto 	for (i = 0; i < 31; i++) {
16733deaf005SShuhei Matsumoto 		iov[i].iov_base = (void *)(0xFEED0000000 + (i << 20));
16743deaf005SShuhei Matsumoto 		iov[i].iov_len = 1024;
16753deaf005SShuhei Matsumoto 	}
16763deaf005SShuhei Matsumoto 	iov[31].iov_base = (void *)0xFEED1F00000;
16773deaf005SShuhei Matsumoto 	iov[31].iov_len = 32768;
16783deaf005SShuhei Matsumoto 	iov[32].iov_base = (void *)0xFEED2000000;
16793deaf005SShuhei Matsumoto 	iov[32].iov_len = 160;
16803deaf005SShuhei Matsumoto 	iov[33].iov_base = (void *)0xFEED2100000;
16813deaf005SShuhei Matsumoto 	iov[33].iov_len = 4096;
16823deaf005SShuhei Matsumoto 	iov[34].iov_base = (void *)0xFEED2200000;
16833deaf005SShuhei Matsumoto 	iov[34].iov_len = 4096;
16843deaf005SShuhei Matsumoto 	iov[35].iov_base = (void *)0xFEED2300000;
16853deaf005SShuhei Matsumoto 	iov[35].iov_len = 4096;
16863deaf005SShuhei Matsumoto 	iov[36].iov_base = (void *)0xFEED2400000;
16873deaf005SShuhei Matsumoto 	iov[36].iov_len = 4096;
16883deaf005SShuhei Matsumoto 	iov[37].iov_base = (void *)0xFEED2500000;
16893deaf005SShuhei Matsumoto 	iov[37].iov_len = 4096;
16903deaf005SShuhei Matsumoto 	iov[38].iov_base = (void *)0xFEED2600000;
16913deaf005SShuhei Matsumoto 	iov[38].iov_len = 4096;
16923deaf005SShuhei Matsumoto 	iov[39].iov_base = (void *)0xFEED2700000;
16933deaf005SShuhei Matsumoto 	iov[39].iov_len = 4096;
16943deaf005SShuhei Matsumoto 	iov[40].iov_base = (void *)0xFEED2800000;
16953deaf005SShuhei Matsumoto 	iov[40].iov_len = 4096;
16963deaf005SShuhei Matsumoto 	iov[41].iov_base = (void *)0xFEED2900000;
16973deaf005SShuhei Matsumoto 	iov[41].iov_len = 4096;
16983deaf005SShuhei Matsumoto 	iov[42].iov_base = (void *)0xFEED2A00000;
16993deaf005SShuhei Matsumoto 	iov[42].iov_len = 4096;
17003deaf005SShuhei Matsumoto 	iov[43].iov_base = (void *)0xFEED2B00000;
17013deaf005SShuhei Matsumoto 	iov[43].iov_len = 12288;
17023deaf005SShuhei Matsumoto 	iov[44].iov_base = (void *)0xFEED2C00000;
17033deaf005SShuhei Matsumoto 	iov[44].iov_len = 8192;
17043deaf005SShuhei Matsumoto 	iov[45].iov_base = (void *)0xFEED2F00000;
17053deaf005SShuhei Matsumoto 	iov[45].iov_len = 4096;
17063deaf005SShuhei Matsumoto 	iov[46].iov_base = (void *)0xFEED3000000;
17073deaf005SShuhei Matsumoto 	iov[46].iov_len = 4096;
17083deaf005SShuhei Matsumoto 	iov[47].iov_base = (void *)0xFEED3100000;
17093deaf005SShuhei Matsumoto 	iov[47].iov_len = 4096;
17103deaf005SShuhei Matsumoto 	iov[48].iov_base = (void *)0xFEED3200000;
17113deaf005SShuhei Matsumoto 	iov[48].iov_len = 24576;
17123deaf005SShuhei Matsumoto 	iov[49].iov_base = (void *)0xFEED3300000;
17133deaf005SShuhei Matsumoto 	iov[49].iov_len = 16384;
17143deaf005SShuhei Matsumoto 	iov[50].iov_base = (void *)0xFEED3400000;
17153deaf005SShuhei Matsumoto 	iov[50].iov_len = 12288;
17163deaf005SShuhei Matsumoto 	iov[51].iov_base = (void *)0xFEED3500000;
17173deaf005SShuhei Matsumoto 	iov[51].iov_len = 4096;
17183deaf005SShuhei Matsumoto 	iov[52].iov_base = (void *)0xFEED3600000;
17193deaf005SShuhei Matsumoto 	iov[52].iov_len = 4096;
17203deaf005SShuhei Matsumoto 	iov[53].iov_base = (void *)0xFEED3700000;
17213deaf005SShuhei Matsumoto 	iov[53].iov_len = 4096;
17223deaf005SShuhei Matsumoto 	iov[54].iov_base = (void *)0xFEED3800000;
17233deaf005SShuhei Matsumoto 	iov[54].iov_len = 28672;
17243deaf005SShuhei Matsumoto 	iov[55].iov_base = (void *)0xFEED3900000;
17253deaf005SShuhei Matsumoto 	iov[55].iov_len = 20480;
17263deaf005SShuhei Matsumoto 	iov[56].iov_base = (void *)0xFEED3A00000;
17273deaf005SShuhei Matsumoto 	iov[56].iov_len = 4096;
17283deaf005SShuhei Matsumoto 	iov[57].iov_base = (void *)0xFEED3B00000;
17293deaf005SShuhei Matsumoto 	iov[57].iov_len = 12288;
17303deaf005SShuhei Matsumoto 	iov[58].iov_base = (void *)0xFEED3C00000;
17313deaf005SShuhei Matsumoto 	iov[58].iov_len = 4096;
17323deaf005SShuhei Matsumoto 	iov[59].iov_base = (void *)0xFEED3D00000;
17333deaf005SShuhei Matsumoto 	iov[59].iov_len = 4096;
17343deaf005SShuhei Matsumoto 	iov[60].iov_base = (void *)0xFEED3E00000;
17353deaf005SShuhei Matsumoto 	iov[60].iov_len = 352;
17363deaf005SShuhei Matsumoto 
17373deaf005SShuhei Matsumoto 	/* The 1st child IO must be from iov[0] to iov[31] split by the capacity
17383deaf005SShuhei Matsumoto 	 * of child iovs,
17393deaf005SShuhei Matsumoto 	 */
17403deaf005SShuhei Matsumoto 	expected_io = ut_alloc_expected_io(SPDK_BDEV_IO_TYPE_READ, 0, 126, 32);
174130f9fecaSJin Yu 	expected_io->md_buf = md_buf;
17423deaf005SShuhei Matsumoto 	for (i = 0; i < 32; i++) {
17433deaf005SShuhei Matsumoto 		ut_expected_io_set_iov(expected_io, i, iov[i].iov_base, iov[i].iov_len);
17443deaf005SShuhei Matsumoto 	}
17453deaf005SShuhei Matsumoto 	TAILQ_INSERT_TAIL(&g_bdev_ut_channel->expected_io, expected_io, link);
17463deaf005SShuhei Matsumoto 
17473deaf005SShuhei Matsumoto 	/* The 2nd child IO must be from iov[32] to the first 864 bytes of iov[33]
17483deaf005SShuhei Matsumoto 	 * split by the IO boundary requirement.
17493deaf005SShuhei Matsumoto 	 */
17503deaf005SShuhei Matsumoto 	expected_io = ut_alloc_expected_io(SPDK_BDEV_IO_TYPE_READ, 126, 2, 2);
175130f9fecaSJin Yu 	expected_io->md_buf = md_buf + 126 * 8;
17523deaf005SShuhei Matsumoto 	ut_expected_io_set_iov(expected_io, 0, iov[32].iov_base, iov[32].iov_len);
17533deaf005SShuhei Matsumoto 	ut_expected_io_set_iov(expected_io, 1, iov[33].iov_base, 864);
17543deaf005SShuhei Matsumoto 	TAILQ_INSERT_TAIL(&g_bdev_ut_channel->expected_io, expected_io, link);
17553deaf005SShuhei Matsumoto 
17563deaf005SShuhei Matsumoto 	/* The 3rd child IO must be from the remaining 3232 bytes of iov[33] to
17573deaf005SShuhei Matsumoto 	 * the first 864 bytes of iov[46] split by the IO boundary requirement.
17583deaf005SShuhei Matsumoto 	 */
17593deaf005SShuhei Matsumoto 	expected_io = ut_alloc_expected_io(SPDK_BDEV_IO_TYPE_READ, 128, 128, 14);
176030f9fecaSJin Yu 	expected_io->md_buf = md_buf + 128 * 8;
17613deaf005SShuhei Matsumoto 	ut_expected_io_set_iov(expected_io, 0, (void *)((uintptr_t)iov[33].iov_base + 864),
17623deaf005SShuhei Matsumoto 			       iov[33].iov_len - 864);
17633deaf005SShuhei Matsumoto 	ut_expected_io_set_iov(expected_io, 1, iov[34].iov_base, iov[34].iov_len);
17643deaf005SShuhei Matsumoto 	ut_expected_io_set_iov(expected_io, 2, iov[35].iov_base, iov[35].iov_len);
17653deaf005SShuhei Matsumoto 	ut_expected_io_set_iov(expected_io, 3, iov[36].iov_base, iov[36].iov_len);
17663deaf005SShuhei Matsumoto 	ut_expected_io_set_iov(expected_io, 4, iov[37].iov_base, iov[37].iov_len);
17673deaf005SShuhei Matsumoto 	ut_expected_io_set_iov(expected_io, 5, iov[38].iov_base, iov[38].iov_len);
17683deaf005SShuhei Matsumoto 	ut_expected_io_set_iov(expected_io, 6, iov[39].iov_base, iov[39].iov_len);
17693deaf005SShuhei Matsumoto 	ut_expected_io_set_iov(expected_io, 7, iov[40].iov_base, iov[40].iov_len);
17703deaf005SShuhei Matsumoto 	ut_expected_io_set_iov(expected_io, 8, iov[41].iov_base, iov[41].iov_len);
17713deaf005SShuhei Matsumoto 	ut_expected_io_set_iov(expected_io, 9, iov[42].iov_base, iov[42].iov_len);
17723deaf005SShuhei Matsumoto 	ut_expected_io_set_iov(expected_io, 10, iov[43].iov_base, iov[43].iov_len);
17733deaf005SShuhei Matsumoto 	ut_expected_io_set_iov(expected_io, 11, iov[44].iov_base, iov[44].iov_len);
17743deaf005SShuhei Matsumoto 	ut_expected_io_set_iov(expected_io, 12, iov[45].iov_base, iov[45].iov_len);
17753deaf005SShuhei Matsumoto 	ut_expected_io_set_iov(expected_io, 13, iov[46].iov_base, 864);
17763deaf005SShuhei Matsumoto 	TAILQ_INSERT_TAIL(&g_bdev_ut_channel->expected_io, expected_io, link);
17773deaf005SShuhei Matsumoto 
17783deaf005SShuhei Matsumoto 	/* The 4th child IO must be from the remaining 3232 bytes of iov[46] to the
17793deaf005SShuhei Matsumoto 	 * first 864 bytes of iov[52] split by the IO boundary requirement.
17803deaf005SShuhei Matsumoto 	 */
17813deaf005SShuhei Matsumoto 	expected_io = ut_alloc_expected_io(SPDK_BDEV_IO_TYPE_READ, 256, 128, 7);
178230f9fecaSJin Yu 	expected_io->md_buf = md_buf + 256 * 8;
17833deaf005SShuhei Matsumoto 	ut_expected_io_set_iov(expected_io, 0, (void *)((uintptr_t)iov[46].iov_base + 864),
17843deaf005SShuhei Matsumoto 			       iov[46].iov_len - 864);
17853deaf005SShuhei Matsumoto 	ut_expected_io_set_iov(expected_io, 1, iov[47].iov_base, iov[47].iov_len);
17863deaf005SShuhei Matsumoto 	ut_expected_io_set_iov(expected_io, 2, iov[48].iov_base, iov[48].iov_len);
17873deaf005SShuhei Matsumoto 	ut_expected_io_set_iov(expected_io, 3, iov[49].iov_base, iov[49].iov_len);
17883deaf005SShuhei Matsumoto 	ut_expected_io_set_iov(expected_io, 4, iov[50].iov_base, iov[50].iov_len);
17893deaf005SShuhei Matsumoto 	ut_expected_io_set_iov(expected_io, 5, iov[51].iov_base, iov[51].iov_len);
17903deaf005SShuhei Matsumoto 	ut_expected_io_set_iov(expected_io, 6, iov[52].iov_base, 864);
17913deaf005SShuhei Matsumoto 	TAILQ_INSERT_TAIL(&g_bdev_ut_channel->expected_io, expected_io, link);
17923deaf005SShuhei Matsumoto 
17933deaf005SShuhei Matsumoto 	/* The 5th child IO must be from the remaining 3232 bytes of iov[52] to
17943deaf005SShuhei Matsumoto 	 * the first 4096 bytes of iov[57] split by the IO boundary requirement.
17953deaf005SShuhei Matsumoto 	 */
17963deaf005SShuhei Matsumoto 	expected_io = ut_alloc_expected_io(SPDK_BDEV_IO_TYPE_READ, 384, 128, 6);
179730f9fecaSJin Yu 	expected_io->md_buf = md_buf + 384 * 8;
17983deaf005SShuhei Matsumoto 	ut_expected_io_set_iov(expected_io, 0, (void *)((uintptr_t)iov[52].iov_base + 864),
17993deaf005SShuhei Matsumoto 			       iov[52].iov_len - 864);
18003deaf005SShuhei Matsumoto 	ut_expected_io_set_iov(expected_io, 1, iov[53].iov_base, iov[53].iov_len);
18013deaf005SShuhei Matsumoto 	ut_expected_io_set_iov(expected_io, 2, iov[54].iov_base, iov[54].iov_len);
18023deaf005SShuhei Matsumoto 	ut_expected_io_set_iov(expected_io, 3, iov[55].iov_base, iov[55].iov_len);
18033deaf005SShuhei Matsumoto 	ut_expected_io_set_iov(expected_io, 4, iov[56].iov_base, iov[56].iov_len);
18043deaf005SShuhei Matsumoto 	ut_expected_io_set_iov(expected_io, 5, iov[57].iov_base, 4960);
18053deaf005SShuhei Matsumoto 	TAILQ_INSERT_TAIL(&g_bdev_ut_channel->expected_io, expected_io, link);
18063deaf005SShuhei Matsumoto 
18073deaf005SShuhei Matsumoto 	/* The 6th child IO must be from the remaining 7328 bytes of iov[57]
18083deaf005SShuhei Matsumoto 	 * to the first 3936 bytes of iov[58] split by the capacity of child iovs.
18093deaf005SShuhei Matsumoto 	 */
18103deaf005SShuhei Matsumoto 	expected_io = ut_alloc_expected_io(SPDK_BDEV_IO_TYPE_READ, 512, 30, 3);
181130f9fecaSJin Yu 	expected_io->md_buf = md_buf + 512 * 8;
18123deaf005SShuhei Matsumoto 	ut_expected_io_set_iov(expected_io, 0, (void *)((uintptr_t)iov[57].iov_base + 4960),
18133deaf005SShuhei Matsumoto 			       iov[57].iov_len - 4960);
18143deaf005SShuhei Matsumoto 	ut_expected_io_set_iov(expected_io, 1, iov[58].iov_base, iov[58].iov_len);
18153deaf005SShuhei Matsumoto 	ut_expected_io_set_iov(expected_io, 2, iov[59].iov_base, 3936);
18163deaf005SShuhei Matsumoto 	TAILQ_INSERT_TAIL(&g_bdev_ut_channel->expected_io, expected_io, link);
18173deaf005SShuhei Matsumoto 
18183deaf005SShuhei Matsumoto 	/* The 7th child IO is from the remaining 160 bytes of iov[59] and iov[60]. */
18193deaf005SShuhei Matsumoto 	expected_io = ut_alloc_expected_io(SPDK_BDEV_IO_TYPE_READ, 542, 1, 2);
182030f9fecaSJin Yu 	expected_io->md_buf = md_buf + 542 * 8;
18213deaf005SShuhei Matsumoto 	ut_expected_io_set_iov(expected_io, 0, (void *)((uintptr_t)iov[59].iov_base + 3936),
18223deaf005SShuhei Matsumoto 			       iov[59].iov_len - 3936);
18233deaf005SShuhei Matsumoto 	ut_expected_io_set_iov(expected_io, 1, iov[60].iov_base, iov[60].iov_len);
18243deaf005SShuhei Matsumoto 	TAILQ_INSERT_TAIL(&g_bdev_ut_channel->expected_io, expected_io, link);
18253deaf005SShuhei Matsumoto 
182630f9fecaSJin Yu 	rc = spdk_bdev_readv_blocks_with_md(desc, io_ch, iov, 61, md_buf,
182730f9fecaSJin Yu 					    0, 543, io_done, NULL);
18283deaf005SShuhei Matsumoto 	CU_ASSERT(rc == 0);
18293deaf005SShuhei Matsumoto 	CU_ASSERT(g_io_done == false);
18303deaf005SShuhei Matsumoto 
18313deaf005SShuhei Matsumoto 	CU_ASSERT(g_bdev_ut_channel->outstanding_io_count == 1);
18323deaf005SShuhei Matsumoto 	stub_complete_io(1);
18333deaf005SShuhei Matsumoto 	CU_ASSERT(g_io_done == false);
18343deaf005SShuhei Matsumoto 
18353deaf005SShuhei Matsumoto 	CU_ASSERT(g_bdev_ut_channel->outstanding_io_count == 5);
18363deaf005SShuhei Matsumoto 	stub_complete_io(5);
18373deaf005SShuhei Matsumoto 	CU_ASSERT(g_io_done == false);
18383deaf005SShuhei Matsumoto 
18393deaf005SShuhei Matsumoto 	CU_ASSERT(g_bdev_ut_channel->outstanding_io_count == 1);
18403deaf005SShuhei Matsumoto 	stub_complete_io(1);
18413deaf005SShuhei Matsumoto 	CU_ASSERT(g_io_done == true);
18423deaf005SShuhei Matsumoto 	CU_ASSERT(g_bdev_ut_channel->outstanding_io_count == 0);
18433deaf005SShuhei Matsumoto 	CU_ASSERT(g_io_status == SPDK_BDEV_IO_STATUS_SUCCESS);
18443deaf005SShuhei Matsumoto 
18454f860d7eSJim Harris 	/* Test a WRITE_ZEROES that would span an I/O boundary.  WRITE_ZEROES should not be
18464f860d7eSJim Harris 	 * split, so test that.
18474bd97621SJim Harris 	 */
18484bd97621SJim Harris 	bdev->optimal_io_boundary = 15;
18494bd97621SJim Harris 	g_io_done = false;
18503c7894ffSShuhei Matsumoto 	expected_io = ut_alloc_expected_io(SPDK_BDEV_IO_TYPE_WRITE_ZEROES, 9, 36, 0);
18513c7894ffSShuhei Matsumoto 	TAILQ_INSERT_TAIL(&g_bdev_ut_channel->expected_io, expected_io, link);
18524bd97621SJim Harris 
18534bd97621SJim Harris 	rc = spdk_bdev_write_zeroes_blocks(desc, io_ch, 9, 36, io_done, NULL);
18544bd97621SJim Harris 	CU_ASSERT(rc == 0);
18554bd97621SJim Harris 	CU_ASSERT(g_io_done == false);
18564bd97621SJim Harris 	CU_ASSERT(g_bdev_ut_channel->outstanding_io_count == 1);
18574bd97621SJim Harris 	stub_complete_io(1);
18584bd97621SJim Harris 	CU_ASSERT(g_io_done == true);
18594bd97621SJim Harris 
18604f860d7eSJim Harris 	/* Test an UNMAP.  This should also not be split. */
18614bd97621SJim Harris 	bdev->optimal_io_boundary = 16;
18624bd97621SJim Harris 	g_io_done = false;
18633c7894ffSShuhei Matsumoto 	expected_io = ut_alloc_expected_io(SPDK_BDEV_IO_TYPE_UNMAP, 15, 2, 0);
18643c7894ffSShuhei Matsumoto 	TAILQ_INSERT_TAIL(&g_bdev_ut_channel->expected_io, expected_io, link);
18654bd97621SJim Harris 
18664bd97621SJim Harris 	rc = spdk_bdev_unmap_blocks(desc, io_ch, 15, 2, io_done, NULL);
18674bd97621SJim Harris 	CU_ASSERT(rc == 0);
18684bd97621SJim Harris 	CU_ASSERT(g_io_done == false);
18694bd97621SJim Harris 	CU_ASSERT(g_bdev_ut_channel->outstanding_io_count == 1);
18704bd97621SJim Harris 	stub_complete_io(1);
18714bd97621SJim Harris 	CU_ASSERT(g_io_done == true);
18724bd97621SJim Harris 
18734f860d7eSJim Harris 	/* Test a FLUSH.  This should also not be split. */
18744bd97621SJim Harris 	bdev->optimal_io_boundary = 16;
18754bd97621SJim Harris 	g_io_done = false;
18763c7894ffSShuhei Matsumoto 	expected_io = ut_alloc_expected_io(SPDK_BDEV_IO_TYPE_FLUSH, 15, 2, 0);
18773c7894ffSShuhei Matsumoto 	TAILQ_INSERT_TAIL(&g_bdev_ut_channel->expected_io, expected_io, link);
18784bd97621SJim Harris 
18794bd97621SJim Harris 	rc = spdk_bdev_flush_blocks(desc, io_ch, 15, 2, io_done, NULL);
18804bd97621SJim Harris 	CU_ASSERT(rc == 0);
18814bd97621SJim Harris 	CU_ASSERT(g_io_done == false);
18824bd97621SJim Harris 	CU_ASSERT(g_bdev_ut_channel->outstanding_io_count == 1);
18834bd97621SJim Harris 	stub_complete_io(1);
18844bd97621SJim Harris 	CU_ASSERT(g_io_done == true);
18854bd97621SJim Harris 
18866c8702acSEvgeniy Kochetov 	/* Test a COPY.  This should also not be split. */
18876c8702acSEvgeniy Kochetov 	bdev->optimal_io_boundary = 15;
18886c8702acSEvgeniy Kochetov 	g_io_done = false;
18896c8702acSEvgeniy Kochetov 	expected_io = ut_alloc_expected_copy_io(SPDK_BDEV_IO_TYPE_COPY, 9, 45, 36);
18906c8702acSEvgeniy Kochetov 	TAILQ_INSERT_TAIL(&g_bdev_ut_channel->expected_io, expected_io, link);
18916c8702acSEvgeniy Kochetov 
18926c8702acSEvgeniy Kochetov 	rc = spdk_bdev_copy_blocks(desc, io_ch, 9, 45, 36, io_done, NULL);
18936c8702acSEvgeniy Kochetov 	CU_ASSERT(rc == 0);
18946c8702acSEvgeniy Kochetov 	CU_ASSERT(g_io_done == false);
18956c8702acSEvgeniy Kochetov 	CU_ASSERT(g_bdev_ut_channel->outstanding_io_count == 1);
18966c8702acSEvgeniy Kochetov 	stub_complete_io(1);
18976c8702acSEvgeniy Kochetov 	CU_ASSERT(g_io_done == true);
18986c8702acSEvgeniy Kochetov 
18993c7894ffSShuhei Matsumoto 	CU_ASSERT(TAILQ_EMPTY(&g_bdev_ut_channel->expected_io));
19004bd97621SJim Harris 
1901c55c85f8SChangpeng Liu 	/* Children requests return an error status */
1902c55c85f8SChangpeng Liu 	bdev->optimal_io_boundary = 16;
1903c55c85f8SChangpeng Liu 	iov[0].iov_base = (void *)0x10000;
1904c55c85f8SChangpeng Liu 	iov[0].iov_len = 512 * 64;
1905c55c85f8SChangpeng Liu 	g_io_exp_status = SPDK_BDEV_IO_STATUS_FAILED;
1906c55c85f8SChangpeng Liu 	g_io_done = false;
1907c55c85f8SChangpeng Liu 	g_io_status = SPDK_BDEV_IO_STATUS_SUCCESS;
1908c55c85f8SChangpeng Liu 
1909c55c85f8SChangpeng Liu 	rc = spdk_bdev_readv_blocks(desc, io_ch, iov, 1, 1, 64, io_done, NULL);
1910c55c85f8SChangpeng Liu 	CU_ASSERT(rc == 0);
1911c55c85f8SChangpeng Liu 	CU_ASSERT(g_bdev_ut_channel->outstanding_io_count == 5);
1912c55c85f8SChangpeng Liu 	stub_complete_io(4);
1913c55c85f8SChangpeng Liu 	CU_ASSERT(g_io_done == false);
1914c55c85f8SChangpeng Liu 	CU_ASSERT(g_io_status == SPDK_BDEV_IO_STATUS_SUCCESS);
1915c55c85f8SChangpeng Liu 	stub_complete_io(1);
1916c55c85f8SChangpeng Liu 	CU_ASSERT(g_io_done == true);
1917c55c85f8SChangpeng Liu 	CU_ASSERT(g_io_status == SPDK_BDEV_IO_STATUS_FAILED);
1918c55c85f8SChangpeng Liu 
1919c9c7c281SJosh Soref 	/* Test if a multi vector command terminated with failure before continuing
1920089d178aSShuhei Matsumoto 	 * splitting process when one of child I/O failed.
1921089d178aSShuhei Matsumoto 	 * The multi vector command is as same as the above that needs to be split by strip
1922089d178aSShuhei Matsumoto 	 * and then needs to be split further due to the capacity of child iovs.
1923089d178aSShuhei Matsumoto 	 */
1924b45556e2SChangpeng Liu 	for (i = 0; i < SPDK_BDEV_IO_NUM_CHILD_IOV - 1; i++) {
1925089d178aSShuhei Matsumoto 		iov[i].iov_base = (void *)((i + 1) * 0x10000);
1926089d178aSShuhei Matsumoto 		iov[i].iov_len = 512;
1927089d178aSShuhei Matsumoto 	}
1928b45556e2SChangpeng Liu 	iov[SPDK_BDEV_IO_NUM_CHILD_IOV - 1].iov_base = (void *)(SPDK_BDEV_IO_NUM_CHILD_IOV * 0x10000);
1929b45556e2SChangpeng Liu 	iov[SPDK_BDEV_IO_NUM_CHILD_IOV - 1].iov_len = 256;
1930089d178aSShuhei Matsumoto 
1931b45556e2SChangpeng Liu 	iov[SPDK_BDEV_IO_NUM_CHILD_IOV].iov_base = (void *)((SPDK_BDEV_IO_NUM_CHILD_IOV + 1) * 0x10000);
1932b45556e2SChangpeng Liu 	iov[SPDK_BDEV_IO_NUM_CHILD_IOV].iov_len = 256;
1933089d178aSShuhei Matsumoto 
1934b45556e2SChangpeng Liu 	iov[SPDK_BDEV_IO_NUM_CHILD_IOV + 1].iov_base = (void *)((SPDK_BDEV_IO_NUM_CHILD_IOV + 2) * 0x10000);
1935b45556e2SChangpeng Liu 	iov[SPDK_BDEV_IO_NUM_CHILD_IOV + 1].iov_len = 512;
1936089d178aSShuhei Matsumoto 
1937b45556e2SChangpeng Liu 	bdev->optimal_io_boundary = SPDK_BDEV_IO_NUM_CHILD_IOV;
1938089d178aSShuhei Matsumoto 
1939089d178aSShuhei Matsumoto 	g_io_exp_status = SPDK_BDEV_IO_STATUS_FAILED;
1940089d178aSShuhei Matsumoto 	g_io_done = false;
1941089d178aSShuhei Matsumoto 	g_io_status = SPDK_BDEV_IO_STATUS_SUCCESS;
1942089d178aSShuhei Matsumoto 
1943b45556e2SChangpeng Liu 	rc = spdk_bdev_readv_blocks(desc, io_ch, iov, SPDK_BDEV_IO_NUM_CHILD_IOV * 2, 0,
1944b45556e2SChangpeng Liu 				    SPDK_BDEV_IO_NUM_CHILD_IOV + 1, io_done, NULL);
1945089d178aSShuhei Matsumoto 	CU_ASSERT(rc == 0);
1946089d178aSShuhei Matsumoto 	CU_ASSERT(g_io_done == false);
1947089d178aSShuhei Matsumoto 
1948089d178aSShuhei Matsumoto 	CU_ASSERT(g_bdev_ut_channel->outstanding_io_count == 1);
1949089d178aSShuhei Matsumoto 	stub_complete_io(1);
1950089d178aSShuhei Matsumoto 	CU_ASSERT(g_io_done == true);
1951089d178aSShuhei Matsumoto 	CU_ASSERT(g_io_status == SPDK_BDEV_IO_STATUS_FAILED);
1952089d178aSShuhei Matsumoto 
1953089d178aSShuhei Matsumoto 	g_io_exp_status = SPDK_BDEV_IO_STATUS_SUCCESS;
1954089d178aSShuhei Matsumoto 
1955ebacdcd9Spaul luse 	/* for this test we will create the following conditions to hit the code path where
1956ebacdcd9Spaul luse 	 * we are trying to send and IO following a split that has no iovs because we had to
1957ebacdcd9Spaul luse 	 * trim them for alignment reasons.
1958ebacdcd9Spaul luse 	 *
1959ebacdcd9Spaul luse 	 * - 16K boundary, our IO will start at offset 0 with a length of 0x4200
1960ebacdcd9Spaul luse 	 * - Our IOVs are 0x212 in size so that we run into the 16K boundary at child IOV
1961ebacdcd9Spaul luse 	 *   position 30 and overshoot by 0x2e.
1962ebacdcd9Spaul luse 	 * - That means we'll send the IO and loop back to pick up the remaining bytes at
1963ebacdcd9Spaul luse 	 *   child IOV index 31. When we do, we find that we have to shorten index 31 by 0x2e
1964ebacdcd9Spaul luse 	 *   which eliniates that vector so we just send the first split IO with 30 vectors
1965ebacdcd9Spaul luse 	 *   and let the completion pick up the last 2 vectors.
1966ebacdcd9Spaul luse 	 */
1967ebacdcd9Spaul luse 	bdev->optimal_io_boundary = 32;
1968ebacdcd9Spaul luse 	bdev->split_on_optimal_io_boundary = true;
1969ebacdcd9Spaul luse 	g_io_done = false;
1970ebacdcd9Spaul luse 
1971ebacdcd9Spaul luse 	/* Init all parent IOVs to 0x212 */
1972b45556e2SChangpeng Liu 	for (i = 0; i < SPDK_BDEV_IO_NUM_CHILD_IOV + 2; i++) {
1973ebacdcd9Spaul luse 		iov[i].iov_base = (void *)((i + 1) * 0x10000);
1974ebacdcd9Spaul luse 		iov[i].iov_len = 0x212;
1975ebacdcd9Spaul luse 	}
1976ebacdcd9Spaul luse 
1977b45556e2SChangpeng Liu 	expected_io = ut_alloc_expected_io(SPDK_BDEV_IO_TYPE_READ, 0, SPDK_BDEV_IO_NUM_CHILD_IOV,
1978b45556e2SChangpeng Liu 					   SPDK_BDEV_IO_NUM_CHILD_IOV - 1);
1979ebacdcd9Spaul luse 	/* expect 0-29 to be 1:1 with the parent iov */
1980b45556e2SChangpeng Liu 	for (i = 0; i < SPDK_BDEV_IO_NUM_CHILD_IOV - 2; i++) {
1981ebacdcd9Spaul luse 		ut_expected_io_set_iov(expected_io, i, iov[i].iov_base, iov[i].iov_len);
1982ebacdcd9Spaul luse 	}
1983ebacdcd9Spaul luse 
1984ebacdcd9Spaul luse 	/* expect index 30 to be shortened to 0x1e4 (0x212 - 0x1e) because of the alignment
1985ebacdcd9Spaul luse 	 * where 0x1e is the amount we overshot the 16K boundary
1986ebacdcd9Spaul luse 	 */
1987b45556e2SChangpeng Liu 	ut_expected_io_set_iov(expected_io, SPDK_BDEV_IO_NUM_CHILD_IOV - 2,
1988b45556e2SChangpeng Liu 			       (void *)(iov[SPDK_BDEV_IO_NUM_CHILD_IOV - 2].iov_base), 0x1e4);
1989ebacdcd9Spaul luse 	TAILQ_INSERT_TAIL(&g_bdev_ut_channel->expected_io, expected_io, link);
1990ebacdcd9Spaul luse 
1991ebacdcd9Spaul luse 	/* 2nd child IO will have 2 remaining vectors, one to pick up from the one that was
1992ebacdcd9Spaul luse 	 * shortened that take it to the next boundary and then a final one to get us to
1993ebacdcd9Spaul luse 	 * 0x4200 bytes for the IO.
1994ebacdcd9Spaul luse 	 */
1995b45556e2SChangpeng Liu 	expected_io = ut_alloc_expected_io(SPDK_BDEV_IO_TYPE_READ, SPDK_BDEV_IO_NUM_CHILD_IOV,
1996c26697bfSSlawomir Ptak 					   1, 2);
1997ebacdcd9Spaul luse 	/* position 30 picked up the remaining bytes to the next boundary */
1998ebacdcd9Spaul luse 	ut_expected_io_set_iov(expected_io, 0,
1999b45556e2SChangpeng Liu 			       (void *)(iov[SPDK_BDEV_IO_NUM_CHILD_IOV - 2].iov_base + 0x1e4), 0x2e);
2000ebacdcd9Spaul luse 
2001c9c7c281SJosh Soref 	/* position 31 picked the the rest of the transfer to get us to 0x4200 */
2002ebacdcd9Spaul luse 	ut_expected_io_set_iov(expected_io, 1,
2003b45556e2SChangpeng Liu 			       (void *)(iov[SPDK_BDEV_IO_NUM_CHILD_IOV - 1].iov_base), 0x1d2);
2004ebacdcd9Spaul luse 	TAILQ_INSERT_TAIL(&g_bdev_ut_channel->expected_io, expected_io, link);
2005ebacdcd9Spaul luse 
2006b45556e2SChangpeng Liu 	rc = spdk_bdev_readv_blocks(desc, io_ch, iov, SPDK_BDEV_IO_NUM_CHILD_IOV + 1, 0,
2007b45556e2SChangpeng Liu 				    SPDK_BDEV_IO_NUM_CHILD_IOV + 1, io_done, NULL);
2008ebacdcd9Spaul luse 	CU_ASSERT(rc == 0);
2009ebacdcd9Spaul luse 	CU_ASSERT(g_io_done == false);
2010ebacdcd9Spaul luse 
2011ebacdcd9Spaul luse 	CU_ASSERT(g_bdev_ut_channel->outstanding_io_count == 1);
2012ebacdcd9Spaul luse 	stub_complete_io(1);
2013ebacdcd9Spaul luse 	CU_ASSERT(g_io_done == false);
2014ebacdcd9Spaul luse 
2015ebacdcd9Spaul luse 	CU_ASSERT(g_bdev_ut_channel->outstanding_io_count == 1);
2016ebacdcd9Spaul luse 	stub_complete_io(1);
2017ebacdcd9Spaul luse 	CU_ASSERT(g_io_done == true);
2018ebacdcd9Spaul luse 	CU_ASSERT(g_bdev_ut_channel->outstanding_io_count == 0);
2019ebacdcd9Spaul luse 
20204bd97621SJim Harris 	spdk_put_io_channel(io_ch);
20214bd97621SJim Harris 	spdk_bdev_close(desc);
20224bd97621SJim Harris 	free_bdev(bdev);
2023107741fcSKonrad Sztyber 	ut_fini_bdev();
20244bd97621SJim Harris }
20254bd97621SJim Harris 
2026a8780177SShuhei Matsumoto static void
20279697d84fSJin Yu bdev_io_max_size_and_segment_split_test(void)
20289697d84fSJin Yu {
20299697d84fSJin Yu 	struct spdk_bdev *bdev;
20309697d84fSJin Yu 	struct spdk_bdev_desc *desc = NULL;
20319697d84fSJin Yu 	struct spdk_io_channel *io_ch;
2032f420b9efSZiye Yang 	struct spdk_bdev_opts bdev_opts = {};
2033b45556e2SChangpeng Liu 	struct iovec iov[SPDK_BDEV_IO_NUM_CHILD_IOV * 2];
20349697d84fSJin Yu 	struct ut_expected_io *expected_io;
20359697d84fSJin Yu 	uint64_t i;
20369697d84fSJin Yu 	int rc;
20379697d84fSJin Yu 
2038f420b9efSZiye Yang 	spdk_bdev_get_opts(&bdev_opts, sizeof(bdev_opts));
2039f420b9efSZiye Yang 	bdev_opts.bdev_io_pool_size = 512;
2040f420b9efSZiye Yang 	bdev_opts.bdev_io_cache_size = 64;
20412d36698dSTomasz Zawadzki 	bdev_opts.opts_size = sizeof(bdev_opts);
2042107741fcSKonrad Sztyber 	ut_init_bdev(&bdev_opts);
20439697d84fSJin Yu 
20449697d84fSJin Yu 	bdev = allocate_bdev("bdev0");
20459697d84fSJin Yu 
20469697d84fSJin Yu 	rc = spdk_bdev_open_ext(bdev->name, true, bdev_ut_event_cb, NULL, &desc);
20479697d84fSJin Yu 	CU_ASSERT(rc == 0);
20489697d84fSJin Yu 	SPDK_CU_ASSERT_FATAL(desc != NULL);
20499697d84fSJin Yu 	io_ch = spdk_bdev_get_io_channel(desc);
20509697d84fSJin Yu 	CU_ASSERT(io_ch != NULL);
20519697d84fSJin Yu 
20529697d84fSJin Yu 	bdev->split_on_optimal_io_boundary = false;
20539697d84fSJin Yu 	bdev->optimal_io_boundary = 0;
20549697d84fSJin Yu 
20559697d84fSJin Yu 	/* Case 0 max_num_segments == 0.
20569697d84fSJin Yu 	 * but segment size 2 * 512 > 512
20579697d84fSJin Yu 	 */
20589697d84fSJin Yu 	bdev->max_segment_size = 512;
20599697d84fSJin Yu 	bdev->max_num_segments = 0;
20609697d84fSJin Yu 	g_io_done = false;
20619697d84fSJin Yu 
20629697d84fSJin Yu 	expected_io = ut_alloc_expected_io(SPDK_BDEV_IO_TYPE_READ, 14, 2, 2);
20639697d84fSJin Yu 	ut_expected_io_set_iov(expected_io, 0, (void *)0xF000, 512);
20649697d84fSJin Yu 	ut_expected_io_set_iov(expected_io, 1, (void *)(0xF000 + 512), 512);
20659697d84fSJin Yu 	TAILQ_INSERT_TAIL(&g_bdev_ut_channel->expected_io, expected_io, link);
20669697d84fSJin Yu 
20679697d84fSJin Yu 	rc = spdk_bdev_read_blocks(desc, io_ch, (void *)0xF000, 14, 2, io_done, NULL);
20689697d84fSJin Yu 	CU_ASSERT(rc == 0);
20699697d84fSJin Yu 	CU_ASSERT(g_io_done == false);
20709697d84fSJin Yu 
20719697d84fSJin Yu 	CU_ASSERT(g_bdev_ut_channel->outstanding_io_count == 1);
20729697d84fSJin Yu 	stub_complete_io(1);
20739697d84fSJin Yu 	CU_ASSERT(g_io_done == true);
20749697d84fSJin Yu 	CU_ASSERT(g_bdev_ut_channel->outstanding_io_count == 0);
20759697d84fSJin Yu 
20769697d84fSJin Yu 	/* Case 1 max_segment_size == 0
20779697d84fSJin Yu 	 * but iov num 2 > 1.
20789697d84fSJin Yu 	 */
20799697d84fSJin Yu 	bdev->max_segment_size = 0;
20809697d84fSJin Yu 	bdev->max_num_segments = 1;
20819697d84fSJin Yu 	g_io_done = false;
20829697d84fSJin Yu 
20839697d84fSJin Yu 	iov[0].iov_base = (void *)0x10000;
20849697d84fSJin Yu 	iov[0].iov_len = 512;
20859697d84fSJin Yu 	iov[1].iov_base = (void *)0x20000;
20869697d84fSJin Yu 	iov[1].iov_len = 8 * 512;
20879697d84fSJin Yu 
20889697d84fSJin Yu 	expected_io = ut_alloc_expected_io(SPDK_BDEV_IO_TYPE_READ, 14, 1, 1);
20899697d84fSJin Yu 	ut_expected_io_set_iov(expected_io, 0, iov[0].iov_base, iov[0].iov_len);
20909697d84fSJin Yu 	TAILQ_INSERT_TAIL(&g_bdev_ut_channel->expected_io, expected_io, link);
20919697d84fSJin Yu 
20929697d84fSJin Yu 	expected_io = ut_alloc_expected_io(SPDK_BDEV_IO_TYPE_READ, 15, 8, 1);
20939697d84fSJin Yu 	ut_expected_io_set_iov(expected_io, 0, iov[1].iov_base, iov[1].iov_len);
20949697d84fSJin Yu 	TAILQ_INSERT_TAIL(&g_bdev_ut_channel->expected_io, expected_io, link);
20959697d84fSJin Yu 
20969697d84fSJin Yu 	rc = spdk_bdev_readv_blocks(desc, io_ch, iov, 2, 14, 9, io_done, NULL);
20979697d84fSJin Yu 	CU_ASSERT(rc == 0);
20989697d84fSJin Yu 	CU_ASSERT(g_io_done == false);
20999697d84fSJin Yu 
21009697d84fSJin Yu 	CU_ASSERT(g_bdev_ut_channel->outstanding_io_count == 2);
21019697d84fSJin Yu 	stub_complete_io(2);
21029697d84fSJin Yu 	CU_ASSERT(g_io_done == true);
21039697d84fSJin Yu 	CU_ASSERT(g_bdev_ut_channel->outstanding_io_count == 0);
21049697d84fSJin Yu 
21059697d84fSJin Yu 	/* Test that a non-vector command is split correctly.
21069697d84fSJin Yu 	 * Set up the expected values before calling spdk_bdev_read_blocks
21079697d84fSJin Yu 	 */
21089697d84fSJin Yu 	bdev->max_segment_size = 512;
21099697d84fSJin Yu 	bdev->max_num_segments = 1;
21109697d84fSJin Yu 	g_io_done = false;
21119697d84fSJin Yu 
21129697d84fSJin Yu 	/* Child IO 0 */
21139697d84fSJin Yu 	expected_io = ut_alloc_expected_io(SPDK_BDEV_IO_TYPE_READ, 14, 1, 1);
21149697d84fSJin Yu 	ut_expected_io_set_iov(expected_io, 0, (void *)0xF000, 512);
21159697d84fSJin Yu 	TAILQ_INSERT_TAIL(&g_bdev_ut_channel->expected_io, expected_io, link);
21169697d84fSJin Yu 
21179697d84fSJin Yu 	/* Child IO 1 */
21189697d84fSJin Yu 	expected_io = ut_alloc_expected_io(SPDK_BDEV_IO_TYPE_READ, 15, 1, 1);
21199697d84fSJin Yu 	ut_expected_io_set_iov(expected_io, 0, (void *)(0xF000 + 1 * 512), 512);
21209697d84fSJin Yu 	TAILQ_INSERT_TAIL(&g_bdev_ut_channel->expected_io, expected_io, link);
21219697d84fSJin Yu 
21229697d84fSJin Yu 	/* spdk_bdev_read_blocks will submit the first child immediately. */
21239697d84fSJin Yu 	rc = spdk_bdev_read_blocks(desc, io_ch, (void *)0xF000, 14, 2, io_done, NULL);
21249697d84fSJin Yu 	CU_ASSERT(rc == 0);
21259697d84fSJin Yu 	CU_ASSERT(g_io_done == false);
21269697d84fSJin Yu 
21279697d84fSJin Yu 	CU_ASSERT(g_bdev_ut_channel->outstanding_io_count == 2);
21289697d84fSJin Yu 	stub_complete_io(2);
21299697d84fSJin Yu 	CU_ASSERT(g_io_done == true);
21309697d84fSJin Yu 	CU_ASSERT(g_bdev_ut_channel->outstanding_io_count == 0);
21319697d84fSJin Yu 
21329697d84fSJin Yu 	/* Now set up a more complex, multi-vector command that needs to be split,
21339697d84fSJin Yu 	 * including splitting iovecs.
21349697d84fSJin Yu 	 */
21359697d84fSJin Yu 	bdev->max_segment_size = 2 * 512;
21369697d84fSJin Yu 	bdev->max_num_segments = 1;
21379697d84fSJin Yu 	g_io_done = false;
21389697d84fSJin Yu 
21399697d84fSJin Yu 	iov[0].iov_base = (void *)0x10000;
21409697d84fSJin Yu 	iov[0].iov_len = 2 * 512;
21419697d84fSJin Yu 	iov[1].iov_base = (void *)0x20000;
21429697d84fSJin Yu 	iov[1].iov_len = 4 * 512;
21439697d84fSJin Yu 	iov[2].iov_base = (void *)0x30000;
21449697d84fSJin Yu 	iov[2].iov_len = 6 * 512;
21459697d84fSJin Yu 
21469697d84fSJin Yu 	expected_io = ut_alloc_expected_io(SPDK_BDEV_IO_TYPE_WRITE, 14, 2, 1);
21479697d84fSJin Yu 	ut_expected_io_set_iov(expected_io, 0, iov[0].iov_base, 512 * 2);
21489697d84fSJin Yu 	TAILQ_INSERT_TAIL(&g_bdev_ut_channel->expected_io, expected_io, link);
21499697d84fSJin Yu 
21509697d84fSJin Yu 	/* Split iov[1].size to 2 iov entries then split the segments */
21519697d84fSJin Yu 	expected_io = ut_alloc_expected_io(SPDK_BDEV_IO_TYPE_WRITE, 16, 2, 1);
21529697d84fSJin Yu 	ut_expected_io_set_iov(expected_io, 0, iov[1].iov_base, 512 * 2);
21539697d84fSJin Yu 	TAILQ_INSERT_TAIL(&g_bdev_ut_channel->expected_io, expected_io, link);
21549697d84fSJin Yu 
21559697d84fSJin Yu 	expected_io = ut_alloc_expected_io(SPDK_BDEV_IO_TYPE_WRITE, 18, 2, 1);
21569697d84fSJin Yu 	ut_expected_io_set_iov(expected_io, 0, iov[1].iov_base + 512 * 2, 512 * 2);
21579697d84fSJin Yu 	TAILQ_INSERT_TAIL(&g_bdev_ut_channel->expected_io, expected_io, link);
21589697d84fSJin Yu 
21599697d84fSJin Yu 	/* Split iov[2].size to 3 iov entries then split the segments */
21609697d84fSJin Yu 	expected_io = ut_alloc_expected_io(SPDK_BDEV_IO_TYPE_WRITE, 20, 2, 1);
21619697d84fSJin Yu 	ut_expected_io_set_iov(expected_io, 0, iov[2].iov_base, 512 * 2);
21629697d84fSJin Yu 	TAILQ_INSERT_TAIL(&g_bdev_ut_channel->expected_io, expected_io, link);
21639697d84fSJin Yu 
21649697d84fSJin Yu 	expected_io = ut_alloc_expected_io(SPDK_BDEV_IO_TYPE_WRITE, 22, 2, 1);
21659697d84fSJin Yu 	ut_expected_io_set_iov(expected_io, 0, iov[2].iov_base + 512 * 2, 512 * 2);
21669697d84fSJin Yu 	TAILQ_INSERT_TAIL(&g_bdev_ut_channel->expected_io, expected_io, link);
21679697d84fSJin Yu 
21689697d84fSJin Yu 	expected_io = ut_alloc_expected_io(SPDK_BDEV_IO_TYPE_WRITE, 24, 2, 1);
21699697d84fSJin Yu 	ut_expected_io_set_iov(expected_io, 0, iov[2].iov_base + 512 * 4, 512 * 2);
21709697d84fSJin Yu 	TAILQ_INSERT_TAIL(&g_bdev_ut_channel->expected_io, expected_io, link);
21719697d84fSJin Yu 
21729697d84fSJin Yu 	rc = spdk_bdev_writev_blocks(desc, io_ch, iov, 3, 14, 12, io_done, NULL);
21739697d84fSJin Yu 	CU_ASSERT(rc == 0);
21749697d84fSJin Yu 	CU_ASSERT(g_io_done == false);
21759697d84fSJin Yu 
21769697d84fSJin Yu 	CU_ASSERT(g_bdev_ut_channel->outstanding_io_count == 6);
21779697d84fSJin Yu 	stub_complete_io(6);
21789697d84fSJin Yu 	CU_ASSERT(g_io_done == true);
21799697d84fSJin Yu 	CU_ASSERT(g_bdev_ut_channel->outstanding_io_count == 0);
21809697d84fSJin Yu 
21819697d84fSJin Yu 	/* Test multi vector command that needs to be split by strip and then needs to be
21829697d84fSJin Yu 	 * split further due to the capacity of parent IO child iovs.
21839697d84fSJin Yu 	 */
21849697d84fSJin Yu 	bdev->max_segment_size = 512;
21859697d84fSJin Yu 	bdev->max_num_segments = 1;
21869697d84fSJin Yu 	g_io_done = false;
21879697d84fSJin Yu 
2188b45556e2SChangpeng Liu 	for (i = 0; i < SPDK_BDEV_IO_NUM_CHILD_IOV; i++) {
21899697d84fSJin Yu 		iov[i].iov_base = (void *)((i + 1) * 0x10000);
21909697d84fSJin Yu 		iov[i].iov_len = 512 * 2;
21919697d84fSJin Yu 	}
21929697d84fSJin Yu 
21939697d84fSJin Yu 	/* Each input iov.size is split into 2 iovs,
21949697d84fSJin Yu 	 * half of the input iov can fill all child iov entries of a single IO.
21959697d84fSJin Yu 	 */
2196b45556e2SChangpeng Liu 	for (i = 0; i < SPDK_BDEV_IO_NUM_CHILD_IOV / 2; i++) {
21979697d84fSJin Yu 		expected_io = ut_alloc_expected_io(SPDK_BDEV_IO_TYPE_READ, 2 * i, 1, 1);
21989697d84fSJin Yu 		ut_expected_io_set_iov(expected_io, 0, iov[i].iov_base, 512);
21999697d84fSJin Yu 		TAILQ_INSERT_TAIL(&g_bdev_ut_channel->expected_io, expected_io, link);
22009697d84fSJin Yu 
22019697d84fSJin Yu 		expected_io = ut_alloc_expected_io(SPDK_BDEV_IO_TYPE_READ, 2 * i + 1, 1, 1);
22029697d84fSJin Yu 		ut_expected_io_set_iov(expected_io, 0, iov[i].iov_base + 512, 512);
22039697d84fSJin Yu 		TAILQ_INSERT_TAIL(&g_bdev_ut_channel->expected_io, expected_io, link);
22049697d84fSJin Yu 	}
22059697d84fSJin Yu 
22069697d84fSJin Yu 	/* The remaining iov is split in the second round */
2207b45556e2SChangpeng Liu 	for (i = SPDK_BDEV_IO_NUM_CHILD_IOV / 2; i < SPDK_BDEV_IO_NUM_CHILD_IOV; i++) {
22089697d84fSJin Yu 		expected_io = ut_alloc_expected_io(SPDK_BDEV_IO_TYPE_READ, i * 2, 1, 1);
22099697d84fSJin Yu 		ut_expected_io_set_iov(expected_io, 0, iov[i].iov_base, 512);
22109697d84fSJin Yu 		TAILQ_INSERT_TAIL(&g_bdev_ut_channel->expected_io, expected_io, link);
22119697d84fSJin Yu 
22129697d84fSJin Yu 		expected_io = ut_alloc_expected_io(SPDK_BDEV_IO_TYPE_READ, i * 2 + 1, 1, 1);
22139697d84fSJin Yu 		ut_expected_io_set_iov(expected_io, 0, iov[i].iov_base + 512, 512);
22149697d84fSJin Yu 		TAILQ_INSERT_TAIL(&g_bdev_ut_channel->expected_io, expected_io, link);
22159697d84fSJin Yu 	}
22169697d84fSJin Yu 
2217b45556e2SChangpeng Liu 	rc = spdk_bdev_readv_blocks(desc, io_ch, iov, SPDK_BDEV_IO_NUM_CHILD_IOV, 0,
2218b45556e2SChangpeng Liu 				    SPDK_BDEV_IO_NUM_CHILD_IOV * 2, io_done, NULL);
22199697d84fSJin Yu 	CU_ASSERT(rc == 0);
22209697d84fSJin Yu 	CU_ASSERT(g_io_done == false);
22219697d84fSJin Yu 
2222b45556e2SChangpeng Liu 	CU_ASSERT(g_bdev_ut_channel->outstanding_io_count == SPDK_BDEV_IO_NUM_CHILD_IOV);
2223b45556e2SChangpeng Liu 	stub_complete_io(SPDK_BDEV_IO_NUM_CHILD_IOV);
22249697d84fSJin Yu 	CU_ASSERT(g_io_done == false);
22259697d84fSJin Yu 
2226b45556e2SChangpeng Liu 	CU_ASSERT(g_bdev_ut_channel->outstanding_io_count == SPDK_BDEV_IO_NUM_CHILD_IOV);
2227b45556e2SChangpeng Liu 	stub_complete_io(SPDK_BDEV_IO_NUM_CHILD_IOV);
22289697d84fSJin Yu 	CU_ASSERT(g_io_done == true);
22299697d84fSJin Yu 	CU_ASSERT(g_bdev_ut_channel->outstanding_io_count == 0);
22309697d84fSJin Yu 
22319697d84fSJin Yu 	/* A wrong case, a child IO that is divided does
22329697d84fSJin Yu 	 * not meet the principle of multiples of block size,
22339697d84fSJin Yu 	 * and exits with error
22349697d84fSJin Yu 	 */
22359697d84fSJin Yu 	bdev->max_segment_size = 512;
22369697d84fSJin Yu 	bdev->max_num_segments = 1;
22379697d84fSJin Yu 	g_io_done = false;
22389697d84fSJin Yu 
22399697d84fSJin Yu 	iov[0].iov_base = (void *)0x10000;
22409697d84fSJin Yu 	iov[0].iov_len = 512 + 256;
22419697d84fSJin Yu 	iov[1].iov_base = (void *)0x20000;
22429697d84fSJin Yu 	iov[1].iov_len = 256;
22439697d84fSJin Yu 
22449697d84fSJin Yu 	/* iov[0] is split to 512 and 256.
22459697d84fSJin Yu 	 * 256 is less than a block size, and it is found
22469697d84fSJin Yu 	 * in the next round of split that it is the first child IO smaller than
22479697d84fSJin Yu 	 * the block size, so the error exit
22489697d84fSJin Yu 	 */
22499697d84fSJin Yu 	expected_io = ut_alloc_expected_io(SPDK_BDEV_IO_TYPE_READ, 0, 1, 1);
22509697d84fSJin Yu 	ut_expected_io_set_iov(expected_io, 0, iov[0].iov_base, 512);
22519697d84fSJin Yu 	TAILQ_INSERT_TAIL(&g_bdev_ut_channel->expected_io, expected_io, link);
22529697d84fSJin Yu 
22539697d84fSJin Yu 	rc = spdk_bdev_readv_blocks(desc, io_ch, iov, 2, 0, 2, io_done, NULL);
22549697d84fSJin Yu 	CU_ASSERT(rc == 0);
22559697d84fSJin Yu 	CU_ASSERT(g_io_done == false);
22569697d84fSJin Yu 
22579697d84fSJin Yu 	/* First child IO is OK */
22589697d84fSJin Yu 	CU_ASSERT(g_bdev_ut_channel->outstanding_io_count == 1);
22599697d84fSJin Yu 	stub_complete_io(1);
22609697d84fSJin Yu 	CU_ASSERT(g_io_done == true);
22619697d84fSJin Yu 	CU_ASSERT(g_bdev_ut_channel->outstanding_io_count == 0);
22629697d84fSJin Yu 
22639697d84fSJin Yu 	/* error exit */
22649697d84fSJin Yu 	stub_complete_io(1);
22659697d84fSJin Yu 	CU_ASSERT(g_io_done == true);
22669697d84fSJin Yu 	CU_ASSERT(g_io_status == SPDK_BDEV_IO_STATUS_FAILED);
22679697d84fSJin Yu 	CU_ASSERT(g_bdev_ut_channel->outstanding_io_count == 0);
22689697d84fSJin Yu 
22699697d84fSJin Yu 	/* Test multi vector command that needs to be split by strip and then needs to be
22709697d84fSJin Yu 	 * split further due to the capacity of child iovs.
22719697d84fSJin Yu 	 *
22729697d84fSJin Yu 	 * In this case, the last two iovs need to be split, but it will exceed the capacity
22739697d84fSJin Yu 	 * of child iovs, so it needs to wait until the first batch completed.
22749697d84fSJin Yu 	 */
22759697d84fSJin Yu 	bdev->max_segment_size = 512;
2276b45556e2SChangpeng Liu 	bdev->max_num_segments = SPDK_BDEV_IO_NUM_CHILD_IOV;
22779697d84fSJin Yu 	g_io_done = false;
22789697d84fSJin Yu 
2279b45556e2SChangpeng Liu 	for (i = 0; i < SPDK_BDEV_IO_NUM_CHILD_IOV - 2; i++) {
22809697d84fSJin Yu 		iov[i].iov_base = (void *)((i + 1) * 0x10000);
22819697d84fSJin Yu 		iov[i].iov_len = 512;
22829697d84fSJin Yu 	}
2283b45556e2SChangpeng Liu 	for (i = SPDK_BDEV_IO_NUM_CHILD_IOV - 2; i < SPDK_BDEV_IO_NUM_CHILD_IOV; i++) {
22849697d84fSJin Yu 		iov[i].iov_base = (void *)((i + 1) * 0x10000);
22859697d84fSJin Yu 		iov[i].iov_len = 512 * 2;
22869697d84fSJin Yu 	}
22879697d84fSJin Yu 
22889697d84fSJin Yu 	expected_io = ut_alloc_expected_io(SPDK_BDEV_IO_TYPE_READ, 0,
2289b45556e2SChangpeng Liu 					   SPDK_BDEV_IO_NUM_CHILD_IOV, SPDK_BDEV_IO_NUM_CHILD_IOV);
2290b45556e2SChangpeng Liu 	/* 0 ~ (SPDK_BDEV_IO_NUM_CHILD_IOV - 2) Will not be split */
2291b45556e2SChangpeng Liu 	for (i = 0; i < SPDK_BDEV_IO_NUM_CHILD_IOV - 2; i++) {
22929697d84fSJin Yu 		ut_expected_io_set_iov(expected_io, i, iov[i].iov_base, iov[i].iov_len);
22939697d84fSJin Yu 	}
2294b45556e2SChangpeng Liu 	/* (SPDK_BDEV_IO_NUM_CHILD_IOV - 2) is split */
22959697d84fSJin Yu 	ut_expected_io_set_iov(expected_io, i, iov[i].iov_base, 512);
22969697d84fSJin Yu 	ut_expected_io_set_iov(expected_io, i + 1, iov[i].iov_base + 512, 512);
22979697d84fSJin Yu 	TAILQ_INSERT_TAIL(&g_bdev_ut_channel->expected_io, expected_io, link);
22989697d84fSJin Yu 
22999697d84fSJin Yu 	/* Child iov entries exceed the max num of parent IO so split it in next round */
2300b45556e2SChangpeng Liu 	expected_io = ut_alloc_expected_io(SPDK_BDEV_IO_TYPE_READ, SPDK_BDEV_IO_NUM_CHILD_IOV, 2, 2);
23019697d84fSJin Yu 	ut_expected_io_set_iov(expected_io, 0, iov[i + 1].iov_base, 512);
23029697d84fSJin Yu 	ut_expected_io_set_iov(expected_io, 1, iov[i + 1].iov_base + 512, 512);
23039697d84fSJin Yu 	TAILQ_INSERT_TAIL(&g_bdev_ut_channel->expected_io, expected_io, link);
23049697d84fSJin Yu 
2305b45556e2SChangpeng Liu 	rc = spdk_bdev_readv_blocks(desc, io_ch, iov, SPDK_BDEV_IO_NUM_CHILD_IOV, 0,
2306b45556e2SChangpeng Liu 				    SPDK_BDEV_IO_NUM_CHILD_IOV + 2, io_done, NULL);
23079697d84fSJin Yu 	CU_ASSERT(rc == 0);
23089697d84fSJin Yu 	CU_ASSERT(g_io_done == false);
23099697d84fSJin Yu 
23109697d84fSJin Yu 	CU_ASSERT(g_bdev_ut_channel->outstanding_io_count == 1);
23119697d84fSJin Yu 	stub_complete_io(1);
23129697d84fSJin Yu 	CU_ASSERT(g_io_done == false);
23139697d84fSJin Yu 
23149697d84fSJin Yu 	/* Next round */
23159697d84fSJin Yu 	CU_ASSERT(g_bdev_ut_channel->outstanding_io_count == 1);
23169697d84fSJin Yu 	stub_complete_io(1);
23179697d84fSJin Yu 	CU_ASSERT(g_io_done == true);
23189697d84fSJin Yu 	CU_ASSERT(g_bdev_ut_channel->outstanding_io_count == 0);
23199697d84fSJin Yu 
23209697d84fSJin Yu 	/* This case is similar to the previous one, but the io composed of
23219697d84fSJin Yu 	 * the last few entries of child iov is not enough for a blocklen, so they
23229697d84fSJin Yu 	 * cannot be put into this IO, but wait until the next time.
23239697d84fSJin Yu 	 */
23249697d84fSJin Yu 	bdev->max_segment_size = 512;
2325b45556e2SChangpeng Liu 	bdev->max_num_segments = SPDK_BDEV_IO_NUM_CHILD_IOV;
23269697d84fSJin Yu 	g_io_done = false;
23279697d84fSJin Yu 
2328b45556e2SChangpeng Liu 	for (i = 0; i < SPDK_BDEV_IO_NUM_CHILD_IOV - 2; i++) {
23299697d84fSJin Yu 		iov[i].iov_base = (void *)((i + 1) * 0x10000);
23309697d84fSJin Yu 		iov[i].iov_len = 512;
23319697d84fSJin Yu 	}
23329697d84fSJin Yu 
2333b45556e2SChangpeng Liu 	for (i = SPDK_BDEV_IO_NUM_CHILD_IOV - 2; i < SPDK_BDEV_IO_NUM_CHILD_IOV + 2; i++) {
23349697d84fSJin Yu 		iov[i].iov_base = (void *)((i + 1) * 0x10000);
23359697d84fSJin Yu 		iov[i].iov_len = 128;
23369697d84fSJin Yu 	}
23379697d84fSJin Yu 
2338b45556e2SChangpeng Liu 	/* First child iovcnt is't SPDK_BDEV_IO_NUM_CHILD_IOV but SPDK_BDEV_IO_NUM_CHILD_IOV - 2.
23399697d84fSJin Yu 	 * Because the left 2 iov is not enough for a blocklen.
23409697d84fSJin Yu 	 */
23419697d84fSJin Yu 	expected_io = ut_alloc_expected_io(SPDK_BDEV_IO_TYPE_READ, 0,
2342b45556e2SChangpeng Liu 					   SPDK_BDEV_IO_NUM_CHILD_IOV - 2, SPDK_BDEV_IO_NUM_CHILD_IOV - 2);
2343b45556e2SChangpeng Liu 	for (i = 0; i < SPDK_BDEV_IO_NUM_CHILD_IOV - 2; i++) {
23449697d84fSJin Yu 		ut_expected_io_set_iov(expected_io, i, iov[i].iov_base, iov[i].iov_len);
23459697d84fSJin Yu 	}
23469697d84fSJin Yu 	TAILQ_INSERT_TAIL(&g_bdev_ut_channel->expected_io, expected_io, link);
23479697d84fSJin Yu 
23489697d84fSJin Yu 	/* The second child io waits until the end of the first child io before executing.
23499697d84fSJin Yu 	 * Because the iovcnt of the two IOs exceeds the child iovcnt of the parent IO.
2350b45556e2SChangpeng Liu 	 * SPDK_BDEV_IO_NUM_CHILD_IOV - 2 to SPDK_BDEV_IO_NUM_CHILD_IOV + 2
23519697d84fSJin Yu 	 */
2352b45556e2SChangpeng Liu 	expected_io = ut_alloc_expected_io(SPDK_BDEV_IO_TYPE_READ, SPDK_BDEV_IO_NUM_CHILD_IOV - 2,
23539697d84fSJin Yu 					   1, 4);
23549697d84fSJin Yu 	ut_expected_io_set_iov(expected_io, 0, iov[i].iov_base, iov[i].iov_len);
23559697d84fSJin Yu 	ut_expected_io_set_iov(expected_io, 1, iov[i + 1].iov_base, iov[i + 1].iov_len);
23569697d84fSJin Yu 	ut_expected_io_set_iov(expected_io, 2, iov[i + 2].iov_base, iov[i + 2].iov_len);
23579697d84fSJin Yu 	ut_expected_io_set_iov(expected_io, 3, iov[i + 3].iov_base, iov[i + 3].iov_len);
23589697d84fSJin Yu 	TAILQ_INSERT_TAIL(&g_bdev_ut_channel->expected_io, expected_io, link);
23599697d84fSJin Yu 
2360b45556e2SChangpeng Liu 	rc = spdk_bdev_readv_blocks(desc, io_ch, iov, SPDK_BDEV_IO_NUM_CHILD_IOV + 2, 0,
2361b45556e2SChangpeng Liu 				    SPDK_BDEV_IO_NUM_CHILD_IOV - 1, io_done, NULL);
23629697d84fSJin Yu 	CU_ASSERT(rc == 0);
23639697d84fSJin Yu 	CU_ASSERT(g_io_done == false);
23649697d84fSJin Yu 
23659697d84fSJin Yu 	CU_ASSERT(g_bdev_ut_channel->outstanding_io_count == 1);
23669697d84fSJin Yu 	stub_complete_io(1);
23679697d84fSJin Yu 	CU_ASSERT(g_io_done == false);
23689697d84fSJin Yu 
23699697d84fSJin Yu 	CU_ASSERT(g_bdev_ut_channel->outstanding_io_count == 1);
23709697d84fSJin Yu 	stub_complete_io(1);
23719697d84fSJin Yu 	CU_ASSERT(g_io_done == true);
23729697d84fSJin Yu 	CU_ASSERT(g_bdev_ut_channel->outstanding_io_count == 0);
23739697d84fSJin Yu 
23749697d84fSJin Yu 	/* A very complicated case. Each sg entry exceeds max_segment_size and
23759697d84fSJin Yu 	 * needs to be split. At the same time, child io must be a multiple of blocklen.
23769697d84fSJin Yu 	 * At the same time, child iovcnt exceeds parent iovcnt.
23779697d84fSJin Yu 	 */
23789697d84fSJin Yu 	bdev->max_segment_size = 512 + 128;
23799697d84fSJin Yu 	bdev->max_num_segments = 3;
23809697d84fSJin Yu 	g_io_done = false;
23819697d84fSJin Yu 
2382b45556e2SChangpeng Liu 	for (i = 0; i < SPDK_BDEV_IO_NUM_CHILD_IOV - 2; i++) {
23839697d84fSJin Yu 		iov[i].iov_base = (void *)((i + 1) * 0x10000);
23849697d84fSJin Yu 		iov[i].iov_len = 512 + 256;
23859697d84fSJin Yu 	}
23869697d84fSJin Yu 
2387b45556e2SChangpeng Liu 	for (i = SPDK_BDEV_IO_NUM_CHILD_IOV - 2; i < SPDK_BDEV_IO_NUM_CHILD_IOV + 2; i++) {
23889697d84fSJin Yu 		iov[i].iov_base = (void *)((i + 1) * 0x10000);
23899697d84fSJin Yu 		iov[i].iov_len = 512 + 128;
23909697d84fSJin Yu 	}
23919697d84fSJin Yu 
23929697d84fSJin Yu 	/* Child IOs use 9 entries per for() round and 3 * 9 = 27 child iov entries.
23939697d84fSJin Yu 	 * Consume 4 parent IO iov entries per for() round and 6 block size.
23949697d84fSJin Yu 	 * Generate 9 child IOs.
23959697d84fSJin Yu 	 */
23969697d84fSJin Yu 	for (i = 0; i < 3; i++) {
23979697d84fSJin Yu 		uint32_t j = i * 4;
23989697d84fSJin Yu 		expected_io = ut_alloc_expected_io(SPDK_BDEV_IO_TYPE_READ, i * 6, 2, 3);
23999697d84fSJin Yu 		ut_expected_io_set_iov(expected_io, 0, iov[j].iov_base, 640);
24009697d84fSJin Yu 		ut_expected_io_set_iov(expected_io, 1, iov[j].iov_base + 640, 128);
24019697d84fSJin Yu 		ut_expected_io_set_iov(expected_io, 2, iov[j + 1].iov_base, 256);
24029697d84fSJin Yu 		TAILQ_INSERT_TAIL(&g_bdev_ut_channel->expected_io, expected_io, link);
24039697d84fSJin Yu 
24049697d84fSJin Yu 		/* Child io must be a multiple of blocklen
24059697d84fSJin Yu 		 * iov[j + 2] must be split. If the third entry is also added,
24069697d84fSJin Yu 		 * the multiple of blocklen cannot be guaranteed. But it still
24079697d84fSJin Yu 		 * occupies one iov entry of the parent child iov.
24089697d84fSJin Yu 		 */
24099697d84fSJin Yu 		expected_io = ut_alloc_expected_io(SPDK_BDEV_IO_TYPE_READ, i * 6 + 2, 2, 2);
24109697d84fSJin Yu 		ut_expected_io_set_iov(expected_io, 0, iov[j + 1].iov_base + 256, 512);
24119697d84fSJin Yu 		ut_expected_io_set_iov(expected_io, 1, iov[j + 2].iov_base, 512);
24129697d84fSJin Yu 		TAILQ_INSERT_TAIL(&g_bdev_ut_channel->expected_io, expected_io, link);
24139697d84fSJin Yu 
24149697d84fSJin Yu 		expected_io = ut_alloc_expected_io(SPDK_BDEV_IO_TYPE_READ, i * 6 + 4, 2, 3);
24159697d84fSJin Yu 		ut_expected_io_set_iov(expected_io, 0, iov[j + 2].iov_base + 512, 256);
24169697d84fSJin Yu 		ut_expected_io_set_iov(expected_io, 1, iov[j + 3].iov_base, 640);
24179697d84fSJin Yu 		ut_expected_io_set_iov(expected_io, 2, iov[j + 3].iov_base + 640, 128);
24189697d84fSJin Yu 		TAILQ_INSERT_TAIL(&g_bdev_ut_channel->expected_io, expected_io, link);
24199697d84fSJin Yu 	}
24209697d84fSJin Yu 
24219697d84fSJin Yu 	/* Child iov position at 27, the 10th child IO
24229697d84fSJin Yu 	 * iov entry index is 3 * 4 and offset is 3 * 6
24239697d84fSJin Yu 	 */
24249697d84fSJin Yu 	expected_io = ut_alloc_expected_io(SPDK_BDEV_IO_TYPE_READ, 18, 2, 3);
24259697d84fSJin Yu 	ut_expected_io_set_iov(expected_io, 0, iov[12].iov_base, 640);
24269697d84fSJin Yu 	ut_expected_io_set_iov(expected_io, 1, iov[12].iov_base + 640, 128);
24279697d84fSJin Yu 	ut_expected_io_set_iov(expected_io, 2, iov[13].iov_base, 256);
24289697d84fSJin Yu 	TAILQ_INSERT_TAIL(&g_bdev_ut_channel->expected_io, expected_io, link);
24299697d84fSJin Yu 
24309697d84fSJin Yu 	/* Child iov position at 30, the 11th child IO */
24319697d84fSJin Yu 	expected_io = ut_alloc_expected_io(SPDK_BDEV_IO_TYPE_READ, 20, 2, 2);
24329697d84fSJin Yu 	ut_expected_io_set_iov(expected_io, 0, iov[13].iov_base + 256, 512);
24339697d84fSJin Yu 	ut_expected_io_set_iov(expected_io, 1, iov[14].iov_base, 512);
24349697d84fSJin Yu 	TAILQ_INSERT_TAIL(&g_bdev_ut_channel->expected_io, expected_io, link);
24359697d84fSJin Yu 
24369697d84fSJin Yu 	/* The 2nd split round and iovpos is 0, the 12th child IO */
24379697d84fSJin Yu 	expected_io = ut_alloc_expected_io(SPDK_BDEV_IO_TYPE_READ, 22, 2, 3);
24389697d84fSJin Yu 	ut_expected_io_set_iov(expected_io, 0, iov[14].iov_base + 512, 256);
24399697d84fSJin Yu 	ut_expected_io_set_iov(expected_io, 1, iov[15].iov_base, 640);
24409697d84fSJin Yu 	ut_expected_io_set_iov(expected_io, 2, iov[15].iov_base + 640, 128);
24419697d84fSJin Yu 	TAILQ_INSERT_TAIL(&g_bdev_ut_channel->expected_io, expected_io, link);
24429697d84fSJin Yu 
24439697d84fSJin Yu 	/* Consume 9 child IOs and 27 child iov entries.
24449697d84fSJin Yu 	 * Consume 4 parent IO iov entries per for() round and 6 block size.
24459697d84fSJin Yu 	 * Parent IO iov index start from 16 and block offset start from 24
24469697d84fSJin Yu 	 */
24479697d84fSJin Yu 	for (i = 0; i < 3; i++) {
24489697d84fSJin Yu 		uint32_t j = i * 4 + 16;
24499697d84fSJin Yu 		uint32_t offset = i * 6 + 24;
24509697d84fSJin Yu 		expected_io = ut_alloc_expected_io(SPDK_BDEV_IO_TYPE_READ, offset, 2, 3);
24519697d84fSJin Yu 		ut_expected_io_set_iov(expected_io, 0, iov[j].iov_base, 640);
24529697d84fSJin Yu 		ut_expected_io_set_iov(expected_io, 1, iov[j].iov_base + 640, 128);
24539697d84fSJin Yu 		ut_expected_io_set_iov(expected_io, 2, iov[j + 1].iov_base, 256);
24549697d84fSJin Yu 		TAILQ_INSERT_TAIL(&g_bdev_ut_channel->expected_io, expected_io, link);
24559697d84fSJin Yu 
24569697d84fSJin Yu 		/* Child io must be a multiple of blocklen
24579697d84fSJin Yu 		 * iov[j + 2] must be split. If the third entry is also added,
24589697d84fSJin Yu 		 * the multiple of blocklen cannot be guaranteed. But it still
24599697d84fSJin Yu 		 * occupies one iov entry of the parent child iov.
24609697d84fSJin Yu 		 */
24619697d84fSJin Yu 		expected_io = ut_alloc_expected_io(SPDK_BDEV_IO_TYPE_READ, offset + 2, 2, 2);
24629697d84fSJin Yu 		ut_expected_io_set_iov(expected_io, 0, iov[j + 1].iov_base + 256, 512);
24639697d84fSJin Yu 		ut_expected_io_set_iov(expected_io, 1, iov[j + 2].iov_base, 512);
24649697d84fSJin Yu 		TAILQ_INSERT_TAIL(&g_bdev_ut_channel->expected_io, expected_io, link);
24659697d84fSJin Yu 
24669697d84fSJin Yu 		expected_io = ut_alloc_expected_io(SPDK_BDEV_IO_TYPE_READ, offset + 4, 2, 3);
24679697d84fSJin Yu 		ut_expected_io_set_iov(expected_io, 0, iov[j + 2].iov_base + 512, 256);
24689697d84fSJin Yu 		ut_expected_io_set_iov(expected_io, 1, iov[j + 3].iov_base, 640);
24699697d84fSJin Yu 		ut_expected_io_set_iov(expected_io, 2, iov[j + 3].iov_base + 640, 128);
24709697d84fSJin Yu 		TAILQ_INSERT_TAIL(&g_bdev_ut_channel->expected_io, expected_io, link);
24719697d84fSJin Yu 	}
24729697d84fSJin Yu 
24739697d84fSJin Yu 	/* The 22th child IO, child iov position at 30 */
24749697d84fSJin Yu 	expected_io = ut_alloc_expected_io(SPDK_BDEV_IO_TYPE_READ, 42, 1, 1);
24759697d84fSJin Yu 	ut_expected_io_set_iov(expected_io, 0, iov[28].iov_base, 512);
24769697d84fSJin Yu 	TAILQ_INSERT_TAIL(&g_bdev_ut_channel->expected_io, expected_io, link);
24779697d84fSJin Yu 
24789697d84fSJin Yu 	/* The third round */
24799697d84fSJin Yu 	/* Here is the 23nd child IO and child iovpos is 0 */
24809697d84fSJin Yu 	expected_io = ut_alloc_expected_io(SPDK_BDEV_IO_TYPE_READ, 43, 2, 3);
24819697d84fSJin Yu 	ut_expected_io_set_iov(expected_io, 0, iov[28].iov_base + 512, 256);
24829697d84fSJin Yu 	ut_expected_io_set_iov(expected_io, 1, iov[29].iov_base, 640);
24839697d84fSJin Yu 	ut_expected_io_set_iov(expected_io, 2, iov[29].iov_base + 640, 128);
24849697d84fSJin Yu 	TAILQ_INSERT_TAIL(&g_bdev_ut_channel->expected_io, expected_io, link);
24859697d84fSJin Yu 
24869697d84fSJin Yu 	/* The 24th child IO */
24879697d84fSJin Yu 	expected_io = ut_alloc_expected_io(SPDK_BDEV_IO_TYPE_READ, 45, 3, 3);
24889697d84fSJin Yu 	ut_expected_io_set_iov(expected_io, 0, iov[30].iov_base, 640);
24899697d84fSJin Yu 	ut_expected_io_set_iov(expected_io, 1, iov[31].iov_base, 640);
24909697d84fSJin Yu 	ut_expected_io_set_iov(expected_io, 2, iov[32].iov_base, 256);
24919697d84fSJin Yu 	TAILQ_INSERT_TAIL(&g_bdev_ut_channel->expected_io, expected_io, link);
24929697d84fSJin Yu 
24939697d84fSJin Yu 	/* The 25th child IO */
24949697d84fSJin Yu 	expected_io = ut_alloc_expected_io(SPDK_BDEV_IO_TYPE_READ, 48, 2, 2);
24959697d84fSJin Yu 	ut_expected_io_set_iov(expected_io, 0, iov[32].iov_base + 256, 384);
24969697d84fSJin Yu 	ut_expected_io_set_iov(expected_io, 1, iov[33].iov_base, 640);
24979697d84fSJin Yu 	TAILQ_INSERT_TAIL(&g_bdev_ut_channel->expected_io, expected_io, link);
24989697d84fSJin Yu 
2499b45556e2SChangpeng Liu 	rc = spdk_bdev_readv_blocks(desc, io_ch, iov, SPDK_BDEV_IO_NUM_CHILD_IOV + 2, 0,
25009697d84fSJin Yu 				    50, io_done, NULL);
25019697d84fSJin Yu 	CU_ASSERT(rc == 0);
25029697d84fSJin Yu 	CU_ASSERT(g_io_done == false);
25039697d84fSJin Yu 
25049697d84fSJin Yu 	/* Parent IO supports up to 32 child iovs, so it is calculated that
25059697d84fSJin Yu 	 * a maximum of 11 IOs can be split at a time, and the
25069697d84fSJin Yu 	 * splitting will continue after the first batch is over.
25079697d84fSJin Yu 	 */
25089697d84fSJin Yu 	CU_ASSERT(g_bdev_ut_channel->outstanding_io_count == 11);
25099697d84fSJin Yu 	stub_complete_io(11);
25109697d84fSJin Yu 	CU_ASSERT(g_io_done == false);
25119697d84fSJin Yu 
25129697d84fSJin Yu 	/* The 2nd round */
25139697d84fSJin Yu 	CU_ASSERT(g_bdev_ut_channel->outstanding_io_count == 11);
25149697d84fSJin Yu 	stub_complete_io(11);
25159697d84fSJin Yu 	CU_ASSERT(g_io_done == false);
25169697d84fSJin Yu 
25179697d84fSJin Yu 	/* The last round */
25189697d84fSJin Yu 	CU_ASSERT(g_bdev_ut_channel->outstanding_io_count == 3);
25199697d84fSJin Yu 	stub_complete_io(3);
25209697d84fSJin Yu 	CU_ASSERT(g_io_done == true);
25219697d84fSJin Yu 	CU_ASSERT(g_bdev_ut_channel->outstanding_io_count == 0);
25229697d84fSJin Yu 
25239697d84fSJin Yu 	/* Test an WRITE_ZEROES.  This should also not be split. */
25249697d84fSJin Yu 	bdev->max_segment_size = 512;
25259697d84fSJin Yu 	bdev->max_num_segments = 1;
25269697d84fSJin Yu 	g_io_done = false;
25279697d84fSJin Yu 
25289697d84fSJin Yu 	expected_io = ut_alloc_expected_io(SPDK_BDEV_IO_TYPE_WRITE_ZEROES, 9, 36, 0);
25299697d84fSJin Yu 	TAILQ_INSERT_TAIL(&g_bdev_ut_channel->expected_io, expected_io, link);
25309697d84fSJin Yu 
25319697d84fSJin Yu 	rc = spdk_bdev_write_zeroes_blocks(desc, io_ch, 9, 36, io_done, NULL);
25329697d84fSJin Yu 	CU_ASSERT(rc == 0);
25339697d84fSJin Yu 	CU_ASSERT(g_io_done == false);
25349697d84fSJin Yu 	CU_ASSERT(g_bdev_ut_channel->outstanding_io_count == 1);
25359697d84fSJin Yu 	stub_complete_io(1);
25369697d84fSJin Yu 	CU_ASSERT(g_io_done == true);
25379697d84fSJin Yu 
25389697d84fSJin Yu 	/* Test an UNMAP.  This should also not be split. */
25399697d84fSJin Yu 	g_io_done = false;
25409697d84fSJin Yu 
25419697d84fSJin Yu 	expected_io = ut_alloc_expected_io(SPDK_BDEV_IO_TYPE_UNMAP, 15, 4, 0);
25429697d84fSJin Yu 	TAILQ_INSERT_TAIL(&g_bdev_ut_channel->expected_io, expected_io, link);
25439697d84fSJin Yu 
25449697d84fSJin Yu 	rc = spdk_bdev_unmap_blocks(desc, io_ch, 15, 4, io_done, NULL);
25459697d84fSJin Yu 	CU_ASSERT(rc == 0);
25469697d84fSJin Yu 	CU_ASSERT(g_io_done == false);
25479697d84fSJin Yu 	CU_ASSERT(g_bdev_ut_channel->outstanding_io_count == 1);
25489697d84fSJin Yu 	stub_complete_io(1);
25499697d84fSJin Yu 	CU_ASSERT(g_io_done == true);
25509697d84fSJin Yu 
25519697d84fSJin Yu 	/* Test a FLUSH.  This should also not be split. */
25529697d84fSJin Yu 	g_io_done = false;
25539697d84fSJin Yu 
25549697d84fSJin Yu 	expected_io = ut_alloc_expected_io(SPDK_BDEV_IO_TYPE_FLUSH, 15, 4, 0);
25559697d84fSJin Yu 	TAILQ_INSERT_TAIL(&g_bdev_ut_channel->expected_io, expected_io, link);
25569697d84fSJin Yu 
2557c26697bfSSlawomir Ptak 	rc = spdk_bdev_flush_blocks(desc, io_ch, 15, 4, io_done, NULL);
25589697d84fSJin Yu 	CU_ASSERT(rc == 0);
25599697d84fSJin Yu 	CU_ASSERT(g_io_done == false);
25609697d84fSJin Yu 	CU_ASSERT(g_bdev_ut_channel->outstanding_io_count == 1);
25619697d84fSJin Yu 	stub_complete_io(1);
25629697d84fSJin Yu 	CU_ASSERT(g_io_done == true);
25639697d84fSJin Yu 
25646c8702acSEvgeniy Kochetov 	/* Test a COPY.  This should also not be split. */
25656c8702acSEvgeniy Kochetov 	g_io_done = false;
25666c8702acSEvgeniy Kochetov 
25676c8702acSEvgeniy Kochetov 	expected_io = ut_alloc_expected_copy_io(SPDK_BDEV_IO_TYPE_COPY, 9, 45, 36);
25686c8702acSEvgeniy Kochetov 	TAILQ_INSERT_TAIL(&g_bdev_ut_channel->expected_io, expected_io, link);
25696c8702acSEvgeniy Kochetov 
25706c8702acSEvgeniy Kochetov 	rc = spdk_bdev_copy_blocks(desc, io_ch, 9, 45, 36, io_done, NULL);
25716c8702acSEvgeniy Kochetov 	CU_ASSERT(rc == 0);
25726c8702acSEvgeniy Kochetov 	CU_ASSERT(g_io_done == false);
25736c8702acSEvgeniy Kochetov 	CU_ASSERT(g_bdev_ut_channel->outstanding_io_count == 1);
25746c8702acSEvgeniy Kochetov 	stub_complete_io(1);
25756c8702acSEvgeniy Kochetov 	CU_ASSERT(g_io_done == true);
25766c8702acSEvgeniy Kochetov 
257701ccef6eSKonrad Sztyber 	/* Test that IOs are split on max_rw_size */
257801ccef6eSKonrad Sztyber 	bdev->max_rw_size = 2;
257901ccef6eSKonrad Sztyber 	bdev->max_segment_size = 0;
258001ccef6eSKonrad Sztyber 	bdev->max_num_segments = 0;
258101ccef6eSKonrad Sztyber 	g_io_done = false;
258201ccef6eSKonrad Sztyber 
258301ccef6eSKonrad Sztyber 	/* 5 blocks in a contiguous buffer */
258401ccef6eSKonrad Sztyber 	iov[0].iov_base = (void *)0x10000;
258501ccef6eSKonrad Sztyber 	iov[0].iov_len = 5 * 512;
258601ccef6eSKonrad Sztyber 
258701ccef6eSKonrad Sztyber 	/* First: offset=0, num_blocks=2 */
258801ccef6eSKonrad Sztyber 	expected_io = ut_alloc_expected_io(SPDK_BDEV_IO_TYPE_READ, 0, 2, 1);
258901ccef6eSKonrad Sztyber 	ut_expected_io_set_iov(expected_io, 0, (void *)0x10000, 2 * 512);
259001ccef6eSKonrad Sztyber 	TAILQ_INSERT_TAIL(&g_bdev_ut_channel->expected_io, expected_io, link);
259101ccef6eSKonrad Sztyber 	/* Second: offset=2, num_blocks=2 */
259201ccef6eSKonrad Sztyber 	expected_io = ut_alloc_expected_io(SPDK_BDEV_IO_TYPE_READ, 2, 2, 1);
259301ccef6eSKonrad Sztyber 	ut_expected_io_set_iov(expected_io, 0, (void *)0x10000 + 2 * 512, 2 * 512);
259401ccef6eSKonrad Sztyber 	TAILQ_INSERT_TAIL(&g_bdev_ut_channel->expected_io, expected_io, link);
259501ccef6eSKonrad Sztyber 	/* Third: offset=4, num_blocks=1 */
259601ccef6eSKonrad Sztyber 	expected_io = ut_alloc_expected_io(SPDK_BDEV_IO_TYPE_READ, 4, 1, 1);
259701ccef6eSKonrad Sztyber 	ut_expected_io_set_iov(expected_io, 0, (void *)0x10000 + 4 * 512, 512);
259801ccef6eSKonrad Sztyber 	TAILQ_INSERT_TAIL(&g_bdev_ut_channel->expected_io, expected_io, link);
259901ccef6eSKonrad Sztyber 
260001ccef6eSKonrad Sztyber 	rc = spdk_bdev_readv_blocks(desc, io_ch, iov, 1, 0, 5, io_done, NULL);
260101ccef6eSKonrad Sztyber 	CU_ASSERT(rc == 0);
260201ccef6eSKonrad Sztyber 	CU_ASSERT(g_io_done == false);
260301ccef6eSKonrad Sztyber 
260401ccef6eSKonrad Sztyber 	CU_ASSERT(g_bdev_ut_channel->outstanding_io_count == 3);
260501ccef6eSKonrad Sztyber 	stub_complete_io(3);
260601ccef6eSKonrad Sztyber 	CU_ASSERT(g_io_done == true);
260701ccef6eSKonrad Sztyber 	CU_ASSERT(g_bdev_ut_channel->outstanding_io_count == 0);
260801ccef6eSKonrad Sztyber 
260901ccef6eSKonrad Sztyber 	/* Check splitting on both max_rw_size + max_num_segments */
261001ccef6eSKonrad Sztyber 	bdev->max_rw_size = 2;
261101ccef6eSKonrad Sztyber 	bdev->max_num_segments = 2;
261201ccef6eSKonrad Sztyber 	bdev->max_segment_size = 0;
261301ccef6eSKonrad Sztyber 	g_io_done = false;
261401ccef6eSKonrad Sztyber 
261501ccef6eSKonrad Sztyber 	/* 5 blocks split across 4 iovs */
261601ccef6eSKonrad Sztyber 	iov[0].iov_base = (void *)0x10000;
261701ccef6eSKonrad Sztyber 	iov[0].iov_len = 3 * 512;
261801ccef6eSKonrad Sztyber 	iov[1].iov_base = (void *)0x20000;
261901ccef6eSKonrad Sztyber 	iov[1].iov_len = 256;
262001ccef6eSKonrad Sztyber 	iov[2].iov_base = (void *)0x30000;
262101ccef6eSKonrad Sztyber 	iov[2].iov_len = 256;
262201ccef6eSKonrad Sztyber 	iov[3].iov_base = (void *)0x40000;
262301ccef6eSKonrad Sztyber 	iov[3].iov_len = 512;
262401ccef6eSKonrad Sztyber 
262501ccef6eSKonrad Sztyber 	/* First: offset=0, num_blocks=2, iovcnt=1 */
262601ccef6eSKonrad Sztyber 	expected_io = ut_alloc_expected_io(SPDK_BDEV_IO_TYPE_READ, 0, 2, 1);
262701ccef6eSKonrad Sztyber 	ut_expected_io_set_iov(expected_io, 0, (void *)0x10000, 2 * 512);
262801ccef6eSKonrad Sztyber 	TAILQ_INSERT_TAIL(&g_bdev_ut_channel->expected_io, expected_io, link);
262901ccef6eSKonrad Sztyber 	/* Second: offset=2, num_blocks=1, iovcnt=1 (max_segment_size prevents from submitting
263001ccef6eSKonrad Sztyber 	 * the rest of iov[0], and iov[1]+iov[2])
263101ccef6eSKonrad Sztyber 	 */
263201ccef6eSKonrad Sztyber 	expected_io = ut_alloc_expected_io(SPDK_BDEV_IO_TYPE_READ, 2, 1, 1);
263301ccef6eSKonrad Sztyber 	ut_expected_io_set_iov(expected_io, 0, (void *)0x10000 + 2 * 512, 512);
263401ccef6eSKonrad Sztyber 	TAILQ_INSERT_TAIL(&g_bdev_ut_channel->expected_io, expected_io, link);
263501ccef6eSKonrad Sztyber 	/* Third: offset=3, num_blocks=1, iovcnt=2 (iov[1]+iov[2]) */
263601ccef6eSKonrad Sztyber 	expected_io = ut_alloc_expected_io(SPDK_BDEV_IO_TYPE_READ, 3, 1, 2);
263701ccef6eSKonrad Sztyber 	ut_expected_io_set_iov(expected_io, 0, (void *)0x20000, 256);
263801ccef6eSKonrad Sztyber 	ut_expected_io_set_iov(expected_io, 1, (void *)0x30000, 256);
263901ccef6eSKonrad Sztyber 	TAILQ_INSERT_TAIL(&g_bdev_ut_channel->expected_io, expected_io, link);
264001ccef6eSKonrad Sztyber 	/* Fourth: offset=4, num_blocks=1, iovcnt=1 (iov[3]) */
264101ccef6eSKonrad Sztyber 	expected_io = ut_alloc_expected_io(SPDK_BDEV_IO_TYPE_READ, 4, 1, 1);
264201ccef6eSKonrad Sztyber 	ut_expected_io_set_iov(expected_io, 0, (void *)0x40000, 512);
264301ccef6eSKonrad Sztyber 	TAILQ_INSERT_TAIL(&g_bdev_ut_channel->expected_io, expected_io, link);
264401ccef6eSKonrad Sztyber 
264501ccef6eSKonrad Sztyber 	rc = spdk_bdev_readv_blocks(desc, io_ch, iov, 4, 0, 5, io_done, NULL);
264601ccef6eSKonrad Sztyber 	CU_ASSERT(rc == 0);
264701ccef6eSKonrad Sztyber 	CU_ASSERT(g_io_done == false);
264801ccef6eSKonrad Sztyber 
264901ccef6eSKonrad Sztyber 	CU_ASSERT(g_bdev_ut_channel->outstanding_io_count == 4);
265001ccef6eSKonrad Sztyber 	stub_complete_io(4);
265101ccef6eSKonrad Sztyber 	CU_ASSERT(g_io_done == true);
265201ccef6eSKonrad Sztyber 	CU_ASSERT(g_bdev_ut_channel->outstanding_io_count == 0);
265301ccef6eSKonrad Sztyber 
265401ccef6eSKonrad Sztyber 	/* Check splitting on both max_rw_size + max_segment_size */
265501ccef6eSKonrad Sztyber 	bdev->max_rw_size = 2;
265601ccef6eSKonrad Sztyber 	bdev->max_segment_size = 512;
265701ccef6eSKonrad Sztyber 	bdev->max_num_segments = 0;
265801ccef6eSKonrad Sztyber 	g_io_done = false;
265901ccef6eSKonrad Sztyber 
266001ccef6eSKonrad Sztyber 	/* 6 blocks in a contiguous buffer */
266101ccef6eSKonrad Sztyber 	iov[0].iov_base = (void *)0x10000;
266201ccef6eSKonrad Sztyber 	iov[0].iov_len = 6 * 512;
266301ccef6eSKonrad Sztyber 
266401ccef6eSKonrad Sztyber 	/* We expect 3 IOs each with 2 blocks and 2 iovs */
266501ccef6eSKonrad Sztyber 	for (i = 0; i < 3; ++i) {
266601ccef6eSKonrad Sztyber 		expected_io = ut_alloc_expected_io(SPDK_BDEV_IO_TYPE_READ, i * 2, 2, 2);
266701ccef6eSKonrad Sztyber 		ut_expected_io_set_iov(expected_io, 0, (void *)0x10000 + i * 2 * 512, 512);
266801ccef6eSKonrad Sztyber 		ut_expected_io_set_iov(expected_io, 1, (void *)0x10000 + i * 2 * 512 + 512, 512);
266901ccef6eSKonrad Sztyber 		TAILQ_INSERT_TAIL(&g_bdev_ut_channel->expected_io, expected_io, link);
267001ccef6eSKonrad Sztyber 	}
267101ccef6eSKonrad Sztyber 
267201ccef6eSKonrad Sztyber 	rc = spdk_bdev_readv_blocks(desc, io_ch, iov, 1, 0, 6, io_done, NULL);
267301ccef6eSKonrad Sztyber 	CU_ASSERT(rc == 0);
267401ccef6eSKonrad Sztyber 	CU_ASSERT(g_io_done == false);
267501ccef6eSKonrad Sztyber 
267601ccef6eSKonrad Sztyber 	CU_ASSERT(g_bdev_ut_channel->outstanding_io_count == 3);
267701ccef6eSKonrad Sztyber 	stub_complete_io(3);
267801ccef6eSKonrad Sztyber 	CU_ASSERT(g_io_done == true);
267901ccef6eSKonrad Sztyber 	CU_ASSERT(g_bdev_ut_channel->outstanding_io_count == 0);
268001ccef6eSKonrad Sztyber 
268101ccef6eSKonrad Sztyber 	/* Check splitting on max_rw_size limited by SPDK_BDEV_IO_NUM_CHILD_IOV */
268201ccef6eSKonrad Sztyber 	bdev->max_rw_size = 1;
268301ccef6eSKonrad Sztyber 	bdev->max_segment_size = 0;
268401ccef6eSKonrad Sztyber 	bdev->max_num_segments = 0;
268501ccef6eSKonrad Sztyber 	g_io_done = false;
268601ccef6eSKonrad Sztyber 
268701ccef6eSKonrad Sztyber 	/* SPDK_BDEV_IO_NUM_CHILD_IOV + 1 blocks */
268801ccef6eSKonrad Sztyber 	iov[0].iov_base = (void *)0x10000;
268901ccef6eSKonrad Sztyber 	iov[0].iov_len = (SPDK_BDEV_IO_NUM_CHILD_IOV + 1) * 512;
269001ccef6eSKonrad Sztyber 
269101ccef6eSKonrad Sztyber 	/* We expect SPDK_BDEV_IO_NUM_CHILD_IOV + 1 IOs each with a single iov */
269201ccef6eSKonrad Sztyber 	for (i = 0; i < 3; ++i) {
269301ccef6eSKonrad Sztyber 		expected_io = ut_alloc_expected_io(SPDK_BDEV_IO_TYPE_READ, i, 1, 1);
269401ccef6eSKonrad Sztyber 		ut_expected_io_set_iov(expected_io, 0, (void *)0x10000 + i * 512, 512);
269501ccef6eSKonrad Sztyber 		TAILQ_INSERT_TAIL(&g_bdev_ut_channel->expected_io, expected_io, link);
269601ccef6eSKonrad Sztyber 	}
269701ccef6eSKonrad Sztyber 
269801ccef6eSKonrad Sztyber 	rc = spdk_bdev_readv_blocks(desc, io_ch, iov, 1, 0, SPDK_BDEV_IO_NUM_CHILD_IOV + 1, io_done, NULL);
269901ccef6eSKonrad Sztyber 	CU_ASSERT(rc == 0);
270001ccef6eSKonrad Sztyber 	CU_ASSERT(g_io_done == false);
270101ccef6eSKonrad Sztyber 
270201ccef6eSKonrad Sztyber 	CU_ASSERT(g_bdev_ut_channel->outstanding_io_count == SPDK_BDEV_IO_NUM_CHILD_IOV);
270301ccef6eSKonrad Sztyber 	stub_complete_io(SPDK_BDEV_IO_NUM_CHILD_IOV);
270401ccef6eSKonrad Sztyber 	CU_ASSERT(g_io_done == false);
270501ccef6eSKonrad Sztyber 	CU_ASSERT(g_bdev_ut_channel->outstanding_io_count == 1);
270601ccef6eSKonrad Sztyber 	stub_complete_io(1);
270701ccef6eSKonrad Sztyber 	CU_ASSERT(g_io_done == true);
270801ccef6eSKonrad Sztyber 	CU_ASSERT(g_bdev_ut_channel->outstanding_io_count == 0);
270901ccef6eSKonrad Sztyber 
27109697d84fSJin Yu 	spdk_put_io_channel(io_ch);
27119697d84fSJin Yu 	spdk_bdev_close(desc);
27129697d84fSJin Yu 	free_bdev(bdev);
2713107741fcSKonrad Sztyber 	ut_fini_bdev();
27149697d84fSJin Yu }
27159697d84fSJin Yu 
27169697d84fSJin Yu static void
27171fae3687SJin Yu bdev_io_mix_split_test(void)
27181fae3687SJin Yu {
27191fae3687SJin Yu 	struct spdk_bdev *bdev;
27201fae3687SJin Yu 	struct spdk_bdev_desc *desc = NULL;
27211fae3687SJin Yu 	struct spdk_io_channel *io_ch;
2722f420b9efSZiye Yang 	struct spdk_bdev_opts bdev_opts = {};
2723b45556e2SChangpeng Liu 	struct iovec iov[SPDK_BDEV_IO_NUM_CHILD_IOV * 2];
27241fae3687SJin Yu 	struct ut_expected_io *expected_io;
27251fae3687SJin Yu 	uint64_t i;
27261fae3687SJin Yu 	int rc;
27271fae3687SJin Yu 
2728f420b9efSZiye Yang 	spdk_bdev_get_opts(&bdev_opts, sizeof(bdev_opts));
2729f420b9efSZiye Yang 	bdev_opts.bdev_io_pool_size = 512;
2730f420b9efSZiye Yang 	bdev_opts.bdev_io_cache_size = 64;
2731107741fcSKonrad Sztyber 	ut_init_bdev(&bdev_opts);
27321fae3687SJin Yu 
27331fae3687SJin Yu 	bdev = allocate_bdev("bdev0");
27341fae3687SJin Yu 
27351fae3687SJin Yu 	rc = spdk_bdev_open_ext(bdev->name, true, bdev_ut_event_cb, NULL, &desc);
27361fae3687SJin Yu 	CU_ASSERT(rc == 0);
27371fae3687SJin Yu 	SPDK_CU_ASSERT_FATAL(desc != NULL);
27381fae3687SJin Yu 	io_ch = spdk_bdev_get_io_channel(desc);
27391fae3687SJin Yu 	CU_ASSERT(io_ch != NULL);
27401fae3687SJin Yu 
27411fae3687SJin Yu 	/* First case optimal_io_boundary == max_segment_size * max_num_segments */
27421fae3687SJin Yu 	bdev->split_on_optimal_io_boundary = true;
27431fae3687SJin Yu 	bdev->optimal_io_boundary = 16;
27441fae3687SJin Yu 
27451fae3687SJin Yu 	bdev->max_segment_size = 512;
27461fae3687SJin Yu 	bdev->max_num_segments = 16;
27471fae3687SJin Yu 	g_io_done = false;
27481fae3687SJin Yu 
27491fae3687SJin Yu 	/* IO crossing the IO boundary requires split
27501fae3687SJin Yu 	 * Total 2 child IOs.
27511fae3687SJin Yu 	 */
27521fae3687SJin Yu 
27531fae3687SJin Yu 	/* The 1st child IO split the segment_size to multiple segment entry */
27541fae3687SJin Yu 	expected_io = ut_alloc_expected_io(SPDK_BDEV_IO_TYPE_READ, 14, 2, 2);
27551fae3687SJin Yu 	ut_expected_io_set_iov(expected_io, 0, (void *)0xF000, 512);
27561fae3687SJin Yu 	ut_expected_io_set_iov(expected_io, 1, (void *)(0xF000 + 512), 512);
27571fae3687SJin Yu 	TAILQ_INSERT_TAIL(&g_bdev_ut_channel->expected_io, expected_io, link);
27581fae3687SJin Yu 
27591fae3687SJin Yu 	/* The 2nd child IO split the segment_size to multiple segment entry */
27601fae3687SJin Yu 	expected_io = ut_alloc_expected_io(SPDK_BDEV_IO_TYPE_READ, 16, 2, 2);
27611fae3687SJin Yu 	ut_expected_io_set_iov(expected_io, 0, (void *)(0xF000 + 2 * 512), 512);
27621fae3687SJin Yu 	ut_expected_io_set_iov(expected_io, 1, (void *)(0xF000 + 3 * 512), 512);
27631fae3687SJin Yu 	TAILQ_INSERT_TAIL(&g_bdev_ut_channel->expected_io, expected_io, link);
27641fae3687SJin Yu 
27651fae3687SJin Yu 	rc = spdk_bdev_read_blocks(desc, io_ch, (void *)0xF000, 14, 4, io_done, NULL);
27661fae3687SJin Yu 	CU_ASSERT(rc == 0);
27671fae3687SJin Yu 	CU_ASSERT(g_io_done == false);
27681fae3687SJin Yu 
27691fae3687SJin Yu 	CU_ASSERT(g_bdev_ut_channel->outstanding_io_count == 2);
27701fae3687SJin Yu 	stub_complete_io(2);
27711fae3687SJin Yu 	CU_ASSERT(g_io_done == true);
27721fae3687SJin Yu 	CU_ASSERT(g_bdev_ut_channel->outstanding_io_count == 0);
27731fae3687SJin Yu 
27741fae3687SJin Yu 	/* Second case optimal_io_boundary > max_segment_size * max_num_segments */
27751fae3687SJin Yu 	bdev->max_segment_size = 15 * 512;
27761fae3687SJin Yu 	bdev->max_num_segments = 1;
27771fae3687SJin Yu 	g_io_done = false;
27781fae3687SJin Yu 
27791fae3687SJin Yu 	/* IO crossing the IO boundary requires split.
27801fae3687SJin Yu 	 * The 1st child IO segment size exceeds the max_segment_size,
27813f912cf0SMichal Berger 	 * So 1st child IO will be split to multiple segment entry.
27821fae3687SJin Yu 	 * Then it split to 2 child IOs because of the max_num_segments.
27831fae3687SJin Yu 	 * Total 3 child IOs.
27841fae3687SJin Yu 	 */
27851fae3687SJin Yu 
27861fae3687SJin Yu 	/* The first 2 IOs are in an IO boundary.
27871fae3687SJin Yu 	 * Because the optimal_io_boundary > max_segment_size * max_num_segments
27881fae3687SJin Yu 	 * So it split to the first 2 IOs.
27891fae3687SJin Yu 	 */
27901fae3687SJin Yu 	expected_io = ut_alloc_expected_io(SPDK_BDEV_IO_TYPE_READ, 0, 15, 1);
27911fae3687SJin Yu 	ut_expected_io_set_iov(expected_io, 0, (void *)0xF000, 512 * 15);
27921fae3687SJin Yu 	TAILQ_INSERT_TAIL(&g_bdev_ut_channel->expected_io, expected_io, link);
27931fae3687SJin Yu 
27941fae3687SJin Yu 	expected_io = ut_alloc_expected_io(SPDK_BDEV_IO_TYPE_READ, 15, 1, 1);
27951fae3687SJin Yu 	ut_expected_io_set_iov(expected_io, 0, (void *)(0xF000 + 512 * 15), 512);
27961fae3687SJin Yu 	TAILQ_INSERT_TAIL(&g_bdev_ut_channel->expected_io, expected_io, link);
27971fae3687SJin Yu 
27981fae3687SJin Yu 	/* The 3rd Child IO is because of the io boundary */
27991fae3687SJin Yu 	expected_io = ut_alloc_expected_io(SPDK_BDEV_IO_TYPE_READ, 16, 2, 1);
28001fae3687SJin Yu 	ut_expected_io_set_iov(expected_io, 0, (void *)(0xF000 + 512 * 16), 512 * 2);
28011fae3687SJin Yu 	TAILQ_INSERT_TAIL(&g_bdev_ut_channel->expected_io, expected_io, link);
28021fae3687SJin Yu 
28031fae3687SJin Yu 	rc = spdk_bdev_read_blocks(desc, io_ch, (void *)0xF000, 0, 18, io_done, NULL);
28041fae3687SJin Yu 	CU_ASSERT(rc == 0);
28051fae3687SJin Yu 	CU_ASSERT(g_io_done == false);
28061fae3687SJin Yu 
28071fae3687SJin Yu 	CU_ASSERT(g_bdev_ut_channel->outstanding_io_count == 3);
28081fae3687SJin Yu 	stub_complete_io(3);
28091fae3687SJin Yu 	CU_ASSERT(g_io_done == true);
28101fae3687SJin Yu 	CU_ASSERT(g_bdev_ut_channel->outstanding_io_count == 0);
28111fae3687SJin Yu 
28121fae3687SJin Yu 	/* Third case optimal_io_boundary < max_segment_size * max_num_segments */
28131fae3687SJin Yu 	bdev->max_segment_size = 17 * 512;
28141fae3687SJin Yu 	bdev->max_num_segments = 1;
28151fae3687SJin Yu 	g_io_done = false;
28161fae3687SJin Yu 
28171fae3687SJin Yu 	/* IO crossing the IO boundary requires split.
28181fae3687SJin Yu 	 * Child IO does not split.
28191fae3687SJin Yu 	 * Total 2 child IOs.
28201fae3687SJin Yu 	 */
28211fae3687SJin Yu 
28221fae3687SJin Yu 	expected_io = ut_alloc_expected_io(SPDK_BDEV_IO_TYPE_READ, 0, 16, 1);
28231fae3687SJin Yu 	ut_expected_io_set_iov(expected_io, 0, (void *)0xF000, 512 * 16);
28241fae3687SJin Yu 	TAILQ_INSERT_TAIL(&g_bdev_ut_channel->expected_io, expected_io, link);
28251fae3687SJin Yu 
28261fae3687SJin Yu 	expected_io = ut_alloc_expected_io(SPDK_BDEV_IO_TYPE_READ, 16, 2, 1);
28271fae3687SJin Yu 	ut_expected_io_set_iov(expected_io, 0, (void *)(0xF000 + 512 * 16), 512 * 2);
28281fae3687SJin Yu 	TAILQ_INSERT_TAIL(&g_bdev_ut_channel->expected_io, expected_io, link);
28291fae3687SJin Yu 
28301fae3687SJin Yu 	rc = spdk_bdev_read_blocks(desc, io_ch, (void *)0xF000, 0, 18, io_done, NULL);
28311fae3687SJin Yu 	CU_ASSERT(rc == 0);
28321fae3687SJin Yu 	CU_ASSERT(g_io_done == false);
28331fae3687SJin Yu 
28341fae3687SJin Yu 	CU_ASSERT(g_bdev_ut_channel->outstanding_io_count == 2);
28351fae3687SJin Yu 	stub_complete_io(2);
28361fae3687SJin Yu 	CU_ASSERT(g_io_done == true);
28371fae3687SJin Yu 	CU_ASSERT(g_bdev_ut_channel->outstanding_io_count == 0);
28381fae3687SJin Yu 
28391fae3687SJin Yu 	/* Now set up a more complex, multi-vector command that needs to be split,
28401fae3687SJin Yu 	 * including splitting iovecs.
28411fae3687SJin Yu 	 * optimal_io_boundary < max_segment_size * max_num_segments
28421fae3687SJin Yu 	 */
28431fae3687SJin Yu 	bdev->max_segment_size = 3 * 512;
28441fae3687SJin Yu 	bdev->max_num_segments = 6;
28451fae3687SJin Yu 	g_io_done = false;
28461fae3687SJin Yu 
28471fae3687SJin Yu 	iov[0].iov_base = (void *)0x10000;
28481fae3687SJin Yu 	iov[0].iov_len = 4 * 512;
28491fae3687SJin Yu 	iov[1].iov_base = (void *)0x20000;
28501fae3687SJin Yu 	iov[1].iov_len = 4 * 512;
28511fae3687SJin Yu 	iov[2].iov_base = (void *)0x30000;
28521fae3687SJin Yu 	iov[2].iov_len = 10 * 512;
28531fae3687SJin Yu 
28541fae3687SJin Yu 	/* IO crossing the IO boundary requires split.
28551fae3687SJin Yu 	 * The 1st child IO segment size exceeds the max_segment_size and after
28561fae3687SJin Yu 	 * splitting segment_size, the num_segments exceeds max_num_segments.
28573f912cf0SMichal Berger 	 * So 1st child IO will be split to 2 child IOs.
28581fae3687SJin Yu 	 * Total 3 child IOs.
28591fae3687SJin Yu 	 */
28601fae3687SJin Yu 
28611fae3687SJin Yu 	/* The first 2 IOs are in an IO boundary.
2862c9c7c281SJosh Soref 	 * After splitting segment size the segment num exceeds.
28631fae3687SJin Yu 	 * So it splits to 2 child IOs.
28641fae3687SJin Yu 	 */
28651fae3687SJin Yu 	expected_io = ut_alloc_expected_io(SPDK_BDEV_IO_TYPE_WRITE, 0, 14, 6);
28661fae3687SJin Yu 	ut_expected_io_set_iov(expected_io, 0, iov[0].iov_base, 512 * 3);
28671fae3687SJin Yu 	ut_expected_io_set_iov(expected_io, 1, iov[0].iov_base + 512 * 3, 512);
28681fae3687SJin Yu 	ut_expected_io_set_iov(expected_io, 2, iov[1].iov_base, 512 * 3);
28691fae3687SJin Yu 	ut_expected_io_set_iov(expected_io, 3, iov[1].iov_base + 512 * 3, 512);
28701fae3687SJin Yu 	ut_expected_io_set_iov(expected_io, 4, iov[2].iov_base, 512 * 3);
28711fae3687SJin Yu 	ut_expected_io_set_iov(expected_io, 5, iov[2].iov_base + 512 * 3, 512 * 3);
28721fae3687SJin Yu 	TAILQ_INSERT_TAIL(&g_bdev_ut_channel->expected_io, expected_io, link);
28731fae3687SJin Yu 
28741fae3687SJin Yu 	/* The 2nd child IO has the left segment entry */
28751fae3687SJin Yu 	expected_io = ut_alloc_expected_io(SPDK_BDEV_IO_TYPE_WRITE, 14, 2, 1);
28761fae3687SJin Yu 	ut_expected_io_set_iov(expected_io, 0, iov[2].iov_base + 512 * 6, 512 * 2);
28771fae3687SJin Yu 	TAILQ_INSERT_TAIL(&g_bdev_ut_channel->expected_io, expected_io, link);
28781fae3687SJin Yu 
28791fae3687SJin Yu 	expected_io = ut_alloc_expected_io(SPDK_BDEV_IO_TYPE_WRITE, 16, 2, 1);
28801fae3687SJin Yu 	ut_expected_io_set_iov(expected_io, 0, iov[2].iov_base + 512 * 8, 512 * 2);
28811fae3687SJin Yu 	TAILQ_INSERT_TAIL(&g_bdev_ut_channel->expected_io, expected_io, link);
28821fae3687SJin Yu 
28831fae3687SJin Yu 	rc = spdk_bdev_writev_blocks(desc, io_ch, iov, 3, 0, 18, io_done, NULL);
28841fae3687SJin Yu 	CU_ASSERT(rc == 0);
28851fae3687SJin Yu 	CU_ASSERT(g_io_done == false);
28861fae3687SJin Yu 
28871fae3687SJin Yu 	CU_ASSERT(g_bdev_ut_channel->outstanding_io_count == 3);
28881fae3687SJin Yu 	stub_complete_io(3);
28891fae3687SJin Yu 	CU_ASSERT(g_io_done == true);
28901fae3687SJin Yu 	CU_ASSERT(g_bdev_ut_channel->outstanding_io_count == 0);
28911fae3687SJin Yu 
28921fae3687SJin Yu 	/* A very complicated case. Each sg entry exceeds max_segment_size
28931fae3687SJin Yu 	 * and split on io boundary.
28941fae3687SJin Yu 	 * optimal_io_boundary < max_segment_size * max_num_segments
28951fae3687SJin Yu 	 */
28961fae3687SJin Yu 	bdev->max_segment_size = 3 * 512;
2897b45556e2SChangpeng Liu 	bdev->max_num_segments = SPDK_BDEV_IO_NUM_CHILD_IOV;
28981fae3687SJin Yu 	g_io_done = false;
28991fae3687SJin Yu 
29001fae3687SJin Yu 	for (i = 0; i < 20; i++) {
29011fae3687SJin Yu 		iov[i].iov_base = (void *)((i + 1) * 0x10000);
29021fae3687SJin Yu 		iov[i].iov_len = 512 * 4;
29031fae3687SJin Yu 	}
29041fae3687SJin Yu 
29051fae3687SJin Yu 	/* IO crossing the IO boundary requires split.
29061fae3687SJin Yu 	 * 80 block length can split 5 child IOs base on offset and IO boundary.
29073f912cf0SMichal Berger 	 * Each iov entry needs to be split to 2 entries because of max_segment_size
29081fae3687SJin Yu 	 * Total 5 child IOs.
29091fae3687SJin Yu 	 */
29101fae3687SJin Yu 
29111fae3687SJin Yu 	/* 4 iov entries are in an IO boundary and each iov entry splits to 2.
29121fae3687SJin Yu 	 * So each child IO occupies 8 child iov entries.
29131fae3687SJin Yu 	 */
29141fae3687SJin Yu 	expected_io = ut_alloc_expected_io(SPDK_BDEV_IO_TYPE_WRITE, 0, 16, 8);
29151fae3687SJin Yu 	for (i = 0; i < 4; i++) {
29161fae3687SJin Yu 		int iovcnt = i * 2;
29171fae3687SJin Yu 		ut_expected_io_set_iov(expected_io, iovcnt, iov[i].iov_base, 512 * 3);
29181fae3687SJin Yu 		ut_expected_io_set_iov(expected_io, iovcnt + 1, iov[i].iov_base + 512 * 3, 512);
29191fae3687SJin Yu 	}
29201fae3687SJin Yu 	TAILQ_INSERT_TAIL(&g_bdev_ut_channel->expected_io, expected_io, link);
29211fae3687SJin Yu 
29221fae3687SJin Yu 	/* 2nd child IO and total 16 child iov entries of parent IO */
29231fae3687SJin Yu 	expected_io = ut_alloc_expected_io(SPDK_BDEV_IO_TYPE_WRITE, 16, 16, 8);
29241fae3687SJin Yu 	for (i = 4; i < 8; i++) {
29251fae3687SJin Yu 		int iovcnt = (i - 4) * 2;
29261fae3687SJin Yu 		ut_expected_io_set_iov(expected_io, iovcnt, iov[i].iov_base, 512 * 3);
29271fae3687SJin Yu 		ut_expected_io_set_iov(expected_io, iovcnt + 1, iov[i].iov_base + 512 * 3, 512);
29281fae3687SJin Yu 	}
29291fae3687SJin Yu 	TAILQ_INSERT_TAIL(&g_bdev_ut_channel->expected_io, expected_io, link);
29301fae3687SJin Yu 
29311fae3687SJin Yu 	/* 3rd child IO and total 24 child iov entries of parent IO */
29321fae3687SJin Yu 	expected_io = ut_alloc_expected_io(SPDK_BDEV_IO_TYPE_WRITE, 32, 16, 8);
29331fae3687SJin Yu 	for (i = 8; i < 12; i++) {
29341fae3687SJin Yu 		int iovcnt = (i - 8) * 2;
29351fae3687SJin Yu 		ut_expected_io_set_iov(expected_io, iovcnt, iov[i].iov_base, 512 * 3);
29361fae3687SJin Yu 		ut_expected_io_set_iov(expected_io, iovcnt + 1, iov[i].iov_base + 512 * 3, 512);
29371fae3687SJin Yu 	}
29381fae3687SJin Yu 	TAILQ_INSERT_TAIL(&g_bdev_ut_channel->expected_io, expected_io, link);
29391fae3687SJin Yu 
29401fae3687SJin Yu 	/* 4th child IO and total 32 child iov entries of parent IO */
29411fae3687SJin Yu 	expected_io = ut_alloc_expected_io(SPDK_BDEV_IO_TYPE_WRITE, 48, 16, 8);
29421fae3687SJin Yu 	for (i = 12; i < 16; i++) {
29431fae3687SJin Yu 		int iovcnt = (i - 12) * 2;
29441fae3687SJin Yu 		ut_expected_io_set_iov(expected_io, iovcnt, iov[i].iov_base, 512 * 3);
29451fae3687SJin Yu 		ut_expected_io_set_iov(expected_io, iovcnt + 1, iov[i].iov_base + 512 * 3, 512);
29461fae3687SJin Yu 	}
29471fae3687SJin Yu 	TAILQ_INSERT_TAIL(&g_bdev_ut_channel->expected_io, expected_io, link);
29481fae3687SJin Yu 
29493f912cf0SMichal Berger 	/* 5th child IO and because of the child iov entry it should be split
29501fae3687SJin Yu 	 * in next round.
29511fae3687SJin Yu 	 */
29521fae3687SJin Yu 	expected_io = ut_alloc_expected_io(SPDK_BDEV_IO_TYPE_WRITE, 64, 16, 8);
29531fae3687SJin Yu 	for (i = 16; i < 20; i++) {
29541fae3687SJin Yu 		int iovcnt = (i - 16) * 2;
29551fae3687SJin Yu 		ut_expected_io_set_iov(expected_io, iovcnt, iov[i].iov_base, 512 * 3);
29561fae3687SJin Yu 		ut_expected_io_set_iov(expected_io, iovcnt + 1, iov[i].iov_base + 512 * 3, 512);
29571fae3687SJin Yu 	}
29581fae3687SJin Yu 	TAILQ_INSERT_TAIL(&g_bdev_ut_channel->expected_io, expected_io, link);
29591fae3687SJin Yu 
29601fae3687SJin Yu 	rc = spdk_bdev_writev_blocks(desc, io_ch, iov, 20, 0, 80, io_done, NULL);
29611fae3687SJin Yu 	CU_ASSERT(rc == 0);
29621fae3687SJin Yu 	CU_ASSERT(g_io_done == false);
29631fae3687SJin Yu 
29641fae3687SJin Yu 	/* First split round */
29651fae3687SJin Yu 	CU_ASSERT(g_bdev_ut_channel->outstanding_io_count == 4);
29661fae3687SJin Yu 	stub_complete_io(4);
29671fae3687SJin Yu 	CU_ASSERT(g_io_done == false);
29681fae3687SJin Yu 
29691fae3687SJin Yu 	/* Second split round */
29701fae3687SJin Yu 	CU_ASSERT(g_bdev_ut_channel->outstanding_io_count == 1);
29711fae3687SJin Yu 	stub_complete_io(1);
29721fae3687SJin Yu 	CU_ASSERT(g_io_done == true);
29731fae3687SJin Yu 	CU_ASSERT(g_bdev_ut_channel->outstanding_io_count == 0);
29741fae3687SJin Yu 
29751fae3687SJin Yu 	spdk_put_io_channel(io_ch);
29761fae3687SJin Yu 	spdk_bdev_close(desc);
29771fae3687SJin Yu 	free_bdev(bdev);
2978107741fcSKonrad Sztyber 	ut_fini_bdev();
29791fae3687SJin Yu }
29801fae3687SJin Yu 
29811fae3687SJin Yu static void
2982a8780177SShuhei Matsumoto bdev_io_split_with_io_wait(void)
2983a8780177SShuhei Matsumoto {
2984a8780177SShuhei Matsumoto 	struct spdk_bdev *bdev;
2985b701087fSDarek Stojaczyk 	struct spdk_bdev_desc *desc = NULL;
2986a8780177SShuhei Matsumoto 	struct spdk_io_channel *io_ch;
2987a8780177SShuhei Matsumoto 	struct spdk_bdev_channel *channel;
2988a8780177SShuhei Matsumoto 	struct spdk_bdev_mgmt_channel *mgmt_ch;
2989f420b9efSZiye Yang 	struct spdk_bdev_opts bdev_opts = {};
29905616c1edSShuhei Matsumoto 	struct iovec iov[3];
2991a8780177SShuhei Matsumoto 	struct ut_expected_io *expected_io;
2992a8780177SShuhei Matsumoto 	int rc;
2993a8780177SShuhei Matsumoto 
2994f420b9efSZiye Yang 	spdk_bdev_get_opts(&bdev_opts, sizeof(bdev_opts));
2995f420b9efSZiye Yang 	bdev_opts.bdev_io_pool_size = 2;
2996f420b9efSZiye Yang 	bdev_opts.bdev_io_cache_size = 1;
2997107741fcSKonrad Sztyber 	ut_init_bdev(&bdev_opts);
2998a8780177SShuhei Matsumoto 
2999a8780177SShuhei Matsumoto 	bdev = allocate_bdev("bdev0");
3000a8780177SShuhei Matsumoto 
300175dfecbbSShuhei Matsumoto 	rc = spdk_bdev_open_ext("bdev0", true, bdev_ut_event_cb, NULL, &desc);
3002a8780177SShuhei Matsumoto 	CU_ASSERT(rc == 0);
3003a8780177SShuhei Matsumoto 	CU_ASSERT(desc != NULL);
300475dfecbbSShuhei Matsumoto 	CU_ASSERT(bdev == spdk_bdev_desc_get_bdev(desc));
3005a8780177SShuhei Matsumoto 	io_ch = spdk_bdev_get_io_channel(desc);
3006a8780177SShuhei Matsumoto 	CU_ASSERT(io_ch != NULL);
3007a8780177SShuhei Matsumoto 	channel = spdk_io_channel_get_ctx(io_ch);
3008a8780177SShuhei Matsumoto 	mgmt_ch = channel->shared_resource->mgmt_ch;
3009a8780177SShuhei Matsumoto 
3010a8780177SShuhei Matsumoto 	bdev->optimal_io_boundary = 16;
3011a8780177SShuhei Matsumoto 	bdev->split_on_optimal_io_boundary = true;
3012a8780177SShuhei Matsumoto 
3013a8780177SShuhei Matsumoto 	rc = spdk_bdev_read_blocks(desc, io_ch, NULL, 0, 1, io_done, NULL);
3014a8780177SShuhei Matsumoto 	CU_ASSERT(rc == 0);
3015a8780177SShuhei Matsumoto 
3016a8780177SShuhei Matsumoto 	/* Now test that a single-vector command is split correctly.
3017a8780177SShuhei Matsumoto 	 * Offset 14, length 8, payload 0xF000
3018a8780177SShuhei Matsumoto 	 *  Child - Offset 14, length 2, payload 0xF000
3019a8780177SShuhei Matsumoto 	 *  Child - Offset 16, length 6, payload 0xF000 + 2 * 512
3020a8780177SShuhei Matsumoto 	 *
3021a8780177SShuhei Matsumoto 	 * Set up the expected values before calling spdk_bdev_read_blocks
3022a8780177SShuhei Matsumoto 	 */
3023a8780177SShuhei Matsumoto 	expected_io = ut_alloc_expected_io(SPDK_BDEV_IO_TYPE_READ, 14, 2, 1);
3024a8780177SShuhei Matsumoto 	ut_expected_io_set_iov(expected_io, 0, (void *)0xF000, 2 * 512);
3025a8780177SShuhei Matsumoto 	TAILQ_INSERT_TAIL(&g_bdev_ut_channel->expected_io, expected_io, link);
3026a8780177SShuhei Matsumoto 
3027a8780177SShuhei Matsumoto 	expected_io = ut_alloc_expected_io(SPDK_BDEV_IO_TYPE_READ, 16, 6, 1);
3028a8780177SShuhei Matsumoto 	ut_expected_io_set_iov(expected_io, 0, (void *)(0xF000 + 2 * 512), 6 * 512);
3029a8780177SShuhei Matsumoto 	TAILQ_INSERT_TAIL(&g_bdev_ut_channel->expected_io, expected_io, link);
3030a8780177SShuhei Matsumoto 
30315616c1edSShuhei Matsumoto 	/* The following children will be submitted sequentially due to the capacity of
30325616c1edSShuhei Matsumoto 	 * spdk_bdev_io.
30335616c1edSShuhei Matsumoto 	 */
30345616c1edSShuhei Matsumoto 
3035a8780177SShuhei Matsumoto 	/* The first child I/O will be queued to wait until an spdk_bdev_io becomes available */
3036a8780177SShuhei Matsumoto 	rc = spdk_bdev_read_blocks(desc, io_ch, (void *)0xF000, 14, 8, io_done, NULL);
3037a8780177SShuhei Matsumoto 	CU_ASSERT(rc == 0);
3038a8780177SShuhei Matsumoto 	CU_ASSERT(!TAILQ_EMPTY(&mgmt_ch->io_wait_queue));
3039a8780177SShuhei Matsumoto 	CU_ASSERT(g_bdev_ut_channel->outstanding_io_count == 1);
3040a8780177SShuhei Matsumoto 
3041a8780177SShuhei Matsumoto 	/* Completing the first read I/O will submit the first child */
3042a8780177SShuhei Matsumoto 	stub_complete_io(1);
3043a8780177SShuhei Matsumoto 	CU_ASSERT(TAILQ_EMPTY(&mgmt_ch->io_wait_queue));
3044a8780177SShuhei Matsumoto 	CU_ASSERT(g_bdev_ut_channel->outstanding_io_count == 1);
3045a8780177SShuhei Matsumoto 
3046a8780177SShuhei Matsumoto 	/* Completing the first child will submit the second child */
3047a8780177SShuhei Matsumoto 	stub_complete_io(1);
3048a8780177SShuhei Matsumoto 	CU_ASSERT(g_bdev_ut_channel->outstanding_io_count == 1);
3049a8780177SShuhei Matsumoto 
3050a8780177SShuhei Matsumoto 	/* Complete the second child I/O.  This should result in our callback getting
3051a8780177SShuhei Matsumoto 	 * invoked since the parent I/O is now complete.
3052a8780177SShuhei Matsumoto 	 */
3053a8780177SShuhei Matsumoto 	stub_complete_io(1);
3054a8780177SShuhei Matsumoto 	CU_ASSERT(g_bdev_ut_channel->outstanding_io_count == 0);
3055a8780177SShuhei Matsumoto 
30565616c1edSShuhei Matsumoto 	/* Now set up a more complex, multi-vector command that needs to be split,
30575616c1edSShuhei Matsumoto 	 *  including splitting iovecs.
30585616c1edSShuhei Matsumoto 	 */
30595616c1edSShuhei Matsumoto 	iov[0].iov_base = (void *)0x10000;
30605616c1edSShuhei Matsumoto 	iov[0].iov_len = 512;
30615616c1edSShuhei Matsumoto 	iov[1].iov_base = (void *)0x20000;
30625616c1edSShuhei Matsumoto 	iov[1].iov_len = 20 * 512;
30635616c1edSShuhei Matsumoto 	iov[2].iov_base = (void *)0x30000;
30645616c1edSShuhei Matsumoto 	iov[2].iov_len = 11 * 512;
30655616c1edSShuhei Matsumoto 
30665616c1edSShuhei Matsumoto 	g_io_done = false;
30675616c1edSShuhei Matsumoto 	expected_io = ut_alloc_expected_io(SPDK_BDEV_IO_TYPE_WRITE, 14, 2, 2);
30685616c1edSShuhei Matsumoto 	ut_expected_io_set_iov(expected_io, 0, (void *)0x10000, 512);
30695616c1edSShuhei Matsumoto 	ut_expected_io_set_iov(expected_io, 1, (void *)0x20000, 512);
30705616c1edSShuhei Matsumoto 	TAILQ_INSERT_TAIL(&g_bdev_ut_channel->expected_io, expected_io, link);
30715616c1edSShuhei Matsumoto 
30725616c1edSShuhei Matsumoto 	expected_io = ut_alloc_expected_io(SPDK_BDEV_IO_TYPE_WRITE, 16, 16, 1);
30735616c1edSShuhei Matsumoto 	ut_expected_io_set_iov(expected_io, 0, (void *)(0x20000 + 512), 16 * 512);
30745616c1edSShuhei Matsumoto 	TAILQ_INSERT_TAIL(&g_bdev_ut_channel->expected_io, expected_io, link);
30755616c1edSShuhei Matsumoto 
30765616c1edSShuhei Matsumoto 	expected_io = ut_alloc_expected_io(SPDK_BDEV_IO_TYPE_WRITE, 32, 14, 2);
30775616c1edSShuhei Matsumoto 	ut_expected_io_set_iov(expected_io, 0, (void *)(0x20000 + 17 * 512), 3 * 512);
30785616c1edSShuhei Matsumoto 	ut_expected_io_set_iov(expected_io, 1, (void *)0x30000, 11 * 512);
30795616c1edSShuhei Matsumoto 	TAILQ_INSERT_TAIL(&g_bdev_ut_channel->expected_io, expected_io, link);
30805616c1edSShuhei Matsumoto 
30815616c1edSShuhei Matsumoto 	rc = spdk_bdev_writev_blocks(desc, io_ch, iov, 3, 14, 32, io_done, NULL);
30825616c1edSShuhei Matsumoto 	CU_ASSERT(rc == 0);
30835616c1edSShuhei Matsumoto 	CU_ASSERT(g_io_done == false);
30845616c1edSShuhei Matsumoto 
30855616c1edSShuhei Matsumoto 	/* The following children will be submitted sequentially due to the capacity of
30865616c1edSShuhei Matsumoto 	 * spdk_bdev_io.
30875616c1edSShuhei Matsumoto 	 */
30885616c1edSShuhei Matsumoto 
30895616c1edSShuhei Matsumoto 	/* Completing the first child will submit the second child */
30905616c1edSShuhei Matsumoto 	CU_ASSERT(g_bdev_ut_channel->outstanding_io_count == 1);
30915616c1edSShuhei Matsumoto 	stub_complete_io(1);
30925616c1edSShuhei Matsumoto 	CU_ASSERT(g_io_done == false);
30935616c1edSShuhei Matsumoto 
30945616c1edSShuhei Matsumoto 	/* Completing the second child will submit the third child */
30955616c1edSShuhei Matsumoto 	CU_ASSERT(g_bdev_ut_channel->outstanding_io_count == 1);
30965616c1edSShuhei Matsumoto 	stub_complete_io(1);
30975616c1edSShuhei Matsumoto 	CU_ASSERT(g_io_done == false);
30985616c1edSShuhei Matsumoto 
30995616c1edSShuhei Matsumoto 	/* Completing the third child will result in our callback getting invoked
31005616c1edSShuhei Matsumoto 	 * since the parent I/O is now complete.
31015616c1edSShuhei Matsumoto 	 */
31025616c1edSShuhei Matsumoto 	CU_ASSERT(g_bdev_ut_channel->outstanding_io_count == 1);
31035616c1edSShuhei Matsumoto 	stub_complete_io(1);
31045616c1edSShuhei Matsumoto 	CU_ASSERT(g_io_done == true);
31055616c1edSShuhei Matsumoto 
3106a8780177SShuhei Matsumoto 	CU_ASSERT(TAILQ_EMPTY(&g_bdev_ut_channel->expected_io));
3107a8780177SShuhei Matsumoto 
3108a8780177SShuhei Matsumoto 	spdk_put_io_channel(io_ch);
3109a8780177SShuhei Matsumoto 	spdk_bdev_close(desc);
3110a8780177SShuhei Matsumoto 	free_bdev(bdev);
3111107741fcSKonrad Sztyber 	ut_fini_bdev();
3112a8780177SShuhei Matsumoto }
3113a8780177SShuhei Matsumoto 
3114dadd2a6dSPiotr Pelplinski static void
3115d6e9827eSArtur Paszkiewicz bdev_io_write_unit_split_test(void)
3116d6e9827eSArtur Paszkiewicz {
3117d6e9827eSArtur Paszkiewicz 	struct spdk_bdev *bdev;
3118d6e9827eSArtur Paszkiewicz 	struct spdk_bdev_desc *desc = NULL;
3119d6e9827eSArtur Paszkiewicz 	struct spdk_io_channel *io_ch;
3120d6e9827eSArtur Paszkiewicz 	struct spdk_bdev_opts bdev_opts = {};
3121b45556e2SChangpeng Liu 	struct iovec iov[SPDK_BDEV_IO_NUM_CHILD_IOV * 4];
3122d6e9827eSArtur Paszkiewicz 	struct ut_expected_io *expected_io;
3123d6e9827eSArtur Paszkiewicz 	uint64_t i;
3124d6e9827eSArtur Paszkiewicz 	int rc;
3125d6e9827eSArtur Paszkiewicz 
3126d6e9827eSArtur Paszkiewicz 	spdk_bdev_get_opts(&bdev_opts, sizeof(bdev_opts));
3127d6e9827eSArtur Paszkiewicz 	bdev_opts.bdev_io_pool_size = 512;
3128d6e9827eSArtur Paszkiewicz 	bdev_opts.bdev_io_cache_size = 64;
3129107741fcSKonrad Sztyber 	ut_init_bdev(&bdev_opts);
3130d6e9827eSArtur Paszkiewicz 
3131d6e9827eSArtur Paszkiewicz 	bdev = allocate_bdev("bdev0");
3132d6e9827eSArtur Paszkiewicz 
3133d6e9827eSArtur Paszkiewicz 	rc = spdk_bdev_open_ext(bdev->name, true, bdev_ut_event_cb, NULL, &desc);
3134d6e9827eSArtur Paszkiewicz 	CU_ASSERT(rc == 0);
3135d6e9827eSArtur Paszkiewicz 	SPDK_CU_ASSERT_FATAL(desc != NULL);
3136d6e9827eSArtur Paszkiewicz 	io_ch = spdk_bdev_get_io_channel(desc);
3137d6e9827eSArtur Paszkiewicz 	CU_ASSERT(io_ch != NULL);
3138d6e9827eSArtur Paszkiewicz 
3139d6e9827eSArtur Paszkiewicz 	/* Write I/O 2x larger than write_unit_size should get split into 2 I/Os */
3140d6e9827eSArtur Paszkiewicz 	bdev->write_unit_size = 32;
3141d6e9827eSArtur Paszkiewicz 	bdev->split_on_write_unit = true;
3142d6e9827eSArtur Paszkiewicz 	g_io_done = false;
3143d6e9827eSArtur Paszkiewicz 
3144d6e9827eSArtur Paszkiewicz 	expected_io = ut_alloc_expected_io(SPDK_BDEV_IO_TYPE_WRITE, 0, 32, 1);
3145d6e9827eSArtur Paszkiewicz 	ut_expected_io_set_iov(expected_io, 0, (void *)0xF000, 32 * 512);
3146d6e9827eSArtur Paszkiewicz 	TAILQ_INSERT_TAIL(&g_bdev_ut_channel->expected_io, expected_io, link);
3147d6e9827eSArtur Paszkiewicz 
3148d6e9827eSArtur Paszkiewicz 	expected_io = ut_alloc_expected_io(SPDK_BDEV_IO_TYPE_WRITE, 32, 32, 1);
3149d6e9827eSArtur Paszkiewicz 	ut_expected_io_set_iov(expected_io, 0, (void *)(0xF000 + 32 * 512), 32 * 512);
3150d6e9827eSArtur Paszkiewicz 	TAILQ_INSERT_TAIL(&g_bdev_ut_channel->expected_io, expected_io, link);
3151d6e9827eSArtur Paszkiewicz 
3152d6e9827eSArtur Paszkiewicz 	rc = spdk_bdev_write_blocks(desc, io_ch, (void *)0xF000, 0, 64, io_done, NULL);
3153d6e9827eSArtur Paszkiewicz 	CU_ASSERT(rc == 0);
3154d6e9827eSArtur Paszkiewicz 	CU_ASSERT(g_io_done == false);
3155d6e9827eSArtur Paszkiewicz 
3156d6e9827eSArtur Paszkiewicz 	CU_ASSERT(g_bdev_ut_channel->outstanding_io_count == 2);
3157d6e9827eSArtur Paszkiewicz 	stub_complete_io(2);
3158d6e9827eSArtur Paszkiewicz 	CU_ASSERT(g_io_done == true);
3159d6e9827eSArtur Paszkiewicz 	CU_ASSERT(g_bdev_ut_channel->outstanding_io_count == 0);
3160d6e9827eSArtur Paszkiewicz 	CU_ASSERT(g_io_status == SPDK_BDEV_IO_STATUS_SUCCESS);
3161d6e9827eSArtur Paszkiewicz 
3162d6e9827eSArtur Paszkiewicz 	/* Same as above but with optimal_io_boundary < write_unit_size - the I/O should be split
3163d6e9827eSArtur Paszkiewicz 	 * based on write_unit_size, not optimal_io_boundary */
3164d6e9827eSArtur Paszkiewicz 	bdev->split_on_optimal_io_boundary = true;
3165d6e9827eSArtur Paszkiewicz 	bdev->optimal_io_boundary = 16;
3166d6e9827eSArtur Paszkiewicz 	g_io_done = false;
3167d6e9827eSArtur Paszkiewicz 
3168d6e9827eSArtur Paszkiewicz 	rc = spdk_bdev_write_blocks(desc, io_ch, (void *)0xF000, 0, 64, io_done, NULL);
3169d6e9827eSArtur Paszkiewicz 	CU_ASSERT(rc == 0);
3170d6e9827eSArtur Paszkiewicz 	CU_ASSERT(g_io_done == false);
3171d6e9827eSArtur Paszkiewicz 
3172d6e9827eSArtur Paszkiewicz 	CU_ASSERT(g_bdev_ut_channel->outstanding_io_count == 2);
3173d6e9827eSArtur Paszkiewicz 	stub_complete_io(2);
3174d6e9827eSArtur Paszkiewicz 	CU_ASSERT(g_io_done == true);
3175d6e9827eSArtur Paszkiewicz 	CU_ASSERT(g_bdev_ut_channel->outstanding_io_count == 0);
3176d6e9827eSArtur Paszkiewicz 	CU_ASSERT(g_io_status == SPDK_BDEV_IO_STATUS_SUCCESS);
3177d6e9827eSArtur Paszkiewicz 
3178d6e9827eSArtur Paszkiewicz 	/* Write I/O should fail if it is smaller than write_unit_size */
3179d6e9827eSArtur Paszkiewicz 	g_io_done = false;
3180d6e9827eSArtur Paszkiewicz 
3181d6e9827eSArtur Paszkiewicz 	rc = spdk_bdev_write_blocks(desc, io_ch, (void *)0xF000, 0, 31, io_done, NULL);
3182d6e9827eSArtur Paszkiewicz 	CU_ASSERT(rc == 0);
3183d6e9827eSArtur Paszkiewicz 	CU_ASSERT(g_io_done == false);
3184d6e9827eSArtur Paszkiewicz 
3185d6e9827eSArtur Paszkiewicz 	CU_ASSERT(g_bdev_ut_channel->outstanding_io_count == 0);
3186d6e9827eSArtur Paszkiewicz 	poll_threads();
3187d6e9827eSArtur Paszkiewicz 	CU_ASSERT(g_io_done == true);
3188d6e9827eSArtur Paszkiewicz 	CU_ASSERT(g_bdev_ut_channel->outstanding_io_count == 0);
3189d6e9827eSArtur Paszkiewicz 	CU_ASSERT(g_io_status == SPDK_BDEV_IO_STATUS_FAILED);
3190d6e9827eSArtur Paszkiewicz 
3191d6e9827eSArtur Paszkiewicz 	/* Same for I/O not aligned to write_unit_size */
3192d6e9827eSArtur Paszkiewicz 	g_io_done = false;
3193d6e9827eSArtur Paszkiewicz 
3194d6e9827eSArtur Paszkiewicz 	rc = spdk_bdev_write_blocks(desc, io_ch, (void *)0xF000, 1, 32, io_done, NULL);
3195d6e9827eSArtur Paszkiewicz 	CU_ASSERT(rc == 0);
3196d6e9827eSArtur Paszkiewicz 	CU_ASSERT(g_io_done == false);
3197d6e9827eSArtur Paszkiewicz 
3198d6e9827eSArtur Paszkiewicz 	CU_ASSERT(g_bdev_ut_channel->outstanding_io_count == 0);
3199d6e9827eSArtur Paszkiewicz 	poll_threads();
3200d6e9827eSArtur Paszkiewicz 	CU_ASSERT(g_io_done == true);
3201d6e9827eSArtur Paszkiewicz 	CU_ASSERT(g_bdev_ut_channel->outstanding_io_count == 0);
3202d6e9827eSArtur Paszkiewicz 	CU_ASSERT(g_io_status == SPDK_BDEV_IO_STATUS_FAILED);
3203d6e9827eSArtur Paszkiewicz 
3204d6e9827eSArtur Paszkiewicz 	/* Write should fail if it needs to be split but there are not enough iovs to submit
3205d6e9827eSArtur Paszkiewicz 	 * an entire write unit */
3206d6e9827eSArtur Paszkiewicz 	bdev->write_unit_size = SPDK_COUNTOF(iov) / 2;
3207d6e9827eSArtur Paszkiewicz 	g_io_done = false;
3208d6e9827eSArtur Paszkiewicz 
3209d6e9827eSArtur Paszkiewicz 	for (i = 0; i < SPDK_COUNTOF(iov); i++) {
3210d6e9827eSArtur Paszkiewicz 		iov[i].iov_base = (void *)(0x1000 + 512 * i);
3211d6e9827eSArtur Paszkiewicz 		iov[i].iov_len = 512;
3212d6e9827eSArtur Paszkiewicz 	}
3213d6e9827eSArtur Paszkiewicz 
3214d6e9827eSArtur Paszkiewicz 	rc = spdk_bdev_writev_blocks(desc, io_ch, iov, SPDK_COUNTOF(iov), 0, SPDK_COUNTOF(iov),
3215d6e9827eSArtur Paszkiewicz 				     io_done, NULL);
3216d6e9827eSArtur Paszkiewicz 	CU_ASSERT(rc == 0);
3217d6e9827eSArtur Paszkiewicz 	CU_ASSERT(g_io_done == false);
3218d6e9827eSArtur Paszkiewicz 
3219d6e9827eSArtur Paszkiewicz 	CU_ASSERT(g_bdev_ut_channel->outstanding_io_count == 0);
3220d6e9827eSArtur Paszkiewicz 	poll_threads();
3221d6e9827eSArtur Paszkiewicz 	CU_ASSERT(g_io_done == true);
3222d6e9827eSArtur Paszkiewicz 	CU_ASSERT(g_bdev_ut_channel->outstanding_io_count == 0);
3223d6e9827eSArtur Paszkiewicz 	CU_ASSERT(g_io_status == SPDK_BDEV_IO_STATUS_FAILED);
3224d6e9827eSArtur Paszkiewicz 
3225d6e9827eSArtur Paszkiewicz 	spdk_put_io_channel(io_ch);
3226d6e9827eSArtur Paszkiewicz 	spdk_bdev_close(desc);
3227d6e9827eSArtur Paszkiewicz 	free_bdev(bdev);
3228107741fcSKonrad Sztyber 	ut_fini_bdev();
3229d6e9827eSArtur Paszkiewicz }
3230d6e9827eSArtur Paszkiewicz 
3231d6e9827eSArtur Paszkiewicz static void
3232dadd2a6dSPiotr Pelplinski bdev_io_alignment(void)
3233dadd2a6dSPiotr Pelplinski {
3234dadd2a6dSPiotr Pelplinski 	struct spdk_bdev *bdev;
3235e2ce08cfSTomasz Zawadzki 	struct spdk_bdev_desc *desc = NULL;
3236dadd2a6dSPiotr Pelplinski 	struct spdk_io_channel *io_ch;
3237f420b9efSZiye Yang 	struct spdk_bdev_opts bdev_opts = {};
3238dadd2a6dSPiotr Pelplinski 	int rc;
32399714818dSyidong0635 	void *buf = NULL;
3240dadd2a6dSPiotr Pelplinski 	struct iovec iovs[2];
3241dadd2a6dSPiotr Pelplinski 	int iovcnt;
3242dadd2a6dSPiotr Pelplinski 	uint64_t alignment;
3243dadd2a6dSPiotr Pelplinski 
3244f420b9efSZiye Yang 	spdk_bdev_get_opts(&bdev_opts, sizeof(bdev_opts));
3245f420b9efSZiye Yang 	bdev_opts.bdev_io_pool_size = 20;
3246f420b9efSZiye Yang 	bdev_opts.bdev_io_cache_size = 2;
3247107741fcSKonrad Sztyber 	ut_init_bdev(&bdev_opts);
3248dadd2a6dSPiotr Pelplinski 
324980da9548SMaciej Szwed 	fn_table.submit_request = stub_submit_request_get_buf;
3250dadd2a6dSPiotr Pelplinski 	bdev = allocate_bdev("bdev0");
3251dadd2a6dSPiotr Pelplinski 
325275dfecbbSShuhei Matsumoto 	rc = spdk_bdev_open_ext("bdev0", true, bdev_ut_event_cb, NULL, &desc);
3253dadd2a6dSPiotr Pelplinski 	CU_ASSERT(rc == 0);
3254dadd2a6dSPiotr Pelplinski 	CU_ASSERT(desc != NULL);
325575dfecbbSShuhei Matsumoto 	CU_ASSERT(bdev == spdk_bdev_desc_get_bdev(desc));
3256dadd2a6dSPiotr Pelplinski 	io_ch = spdk_bdev_get_io_channel(desc);
3257dadd2a6dSPiotr Pelplinski 	CU_ASSERT(io_ch != NULL);
3258dadd2a6dSPiotr Pelplinski 
3259dadd2a6dSPiotr Pelplinski 	/* Create aligned buffer */
3260dadd2a6dSPiotr Pelplinski 	rc = posix_memalign(&buf, 4096, 8192);
3261dadd2a6dSPiotr Pelplinski 	SPDK_CU_ASSERT_FATAL(rc == 0);
3262dadd2a6dSPiotr Pelplinski 
3263dadd2a6dSPiotr Pelplinski 	/* Pass aligned single buffer with no alignment required */
3264dadd2a6dSPiotr Pelplinski 	alignment = 1;
3265dadd2a6dSPiotr Pelplinski 	bdev->required_alignment = spdk_u32log2(alignment);
3266dadd2a6dSPiotr Pelplinski 
3267dadd2a6dSPiotr Pelplinski 	rc = spdk_bdev_write_blocks(desc, io_ch, buf, 0, 1, io_done, NULL);
3268dadd2a6dSPiotr Pelplinski 	CU_ASSERT(rc == 0);
3269dadd2a6dSPiotr Pelplinski 	stub_complete_io(1);
3270dadd2a6dSPiotr Pelplinski 	CU_ASSERT(_are_iovs_aligned(g_bdev_io->u.bdev.iovs, g_bdev_io->u.bdev.iovcnt,
3271dadd2a6dSPiotr Pelplinski 				    alignment));
3272dadd2a6dSPiotr Pelplinski 
3273dadd2a6dSPiotr Pelplinski 	rc = spdk_bdev_read_blocks(desc, io_ch, buf, 0, 1, io_done, NULL);
3274dadd2a6dSPiotr Pelplinski 	CU_ASSERT(rc == 0);
3275dadd2a6dSPiotr Pelplinski 	stub_complete_io(1);
3276dadd2a6dSPiotr Pelplinski 	CU_ASSERT(_are_iovs_aligned(g_bdev_io->u.bdev.iovs, g_bdev_io->u.bdev.iovcnt,
3277dadd2a6dSPiotr Pelplinski 				    alignment));
3278dadd2a6dSPiotr Pelplinski 
3279dadd2a6dSPiotr Pelplinski 	/* Pass unaligned single buffer with no alignment required */
3280dadd2a6dSPiotr Pelplinski 	alignment = 1;
3281dadd2a6dSPiotr Pelplinski 	bdev->required_alignment = spdk_u32log2(alignment);
3282dadd2a6dSPiotr Pelplinski 
3283dadd2a6dSPiotr Pelplinski 	rc = spdk_bdev_write_blocks(desc, io_ch, buf + 4, 0, 1, io_done, NULL);
3284dadd2a6dSPiotr Pelplinski 	CU_ASSERT(rc == 0);
32857fee8002SBen Walker 	CU_ASSERT(g_bdev_io->internal.f.has_bounce_buf == false);
3286dadd2a6dSPiotr Pelplinski 	CU_ASSERT(g_bdev_io->u.bdev.iovs[0].iov_base == buf + 4);
3287dadd2a6dSPiotr Pelplinski 	stub_complete_io(1);
3288dadd2a6dSPiotr Pelplinski 
3289dadd2a6dSPiotr Pelplinski 	rc = spdk_bdev_read_blocks(desc, io_ch, buf + 4, 0, 1, io_done, NULL);
3290dadd2a6dSPiotr Pelplinski 	CU_ASSERT(rc == 0);
32917fee8002SBen Walker 	CU_ASSERT(g_bdev_io->internal.f.has_bounce_buf == false);
3292dadd2a6dSPiotr Pelplinski 	CU_ASSERT(g_bdev_io->u.bdev.iovs[0].iov_base == buf + 4);
3293dadd2a6dSPiotr Pelplinski 	stub_complete_io(1);
3294dadd2a6dSPiotr Pelplinski 
3295dadd2a6dSPiotr Pelplinski 	/* Pass unaligned single buffer with 512 alignment required */
3296dadd2a6dSPiotr Pelplinski 	alignment = 512;
3297dadd2a6dSPiotr Pelplinski 	bdev->required_alignment = spdk_u32log2(alignment);
3298dadd2a6dSPiotr Pelplinski 
3299dadd2a6dSPiotr Pelplinski 	rc = spdk_bdev_write_blocks(desc, io_ch, buf + 4, 0, 1, io_done, NULL);
3300dadd2a6dSPiotr Pelplinski 	CU_ASSERT(rc == 0);
33017fee8002SBen Walker 	CU_ASSERT(g_bdev_io->internal.bounce_buf.orig_iovcnt == 1);
33027fee8002SBen Walker 	CU_ASSERT(g_bdev_io->u.bdev.iovs == &g_bdev_io->internal.bounce_buf.iov);
3303dadd2a6dSPiotr Pelplinski 	CU_ASSERT(_are_iovs_aligned(g_bdev_io->u.bdev.iovs, g_bdev_io->u.bdev.iovcnt,
3304dadd2a6dSPiotr Pelplinski 				    alignment));
3305dadd2a6dSPiotr Pelplinski 	stub_complete_io(1);
33067fee8002SBen Walker 	CU_ASSERT(g_bdev_io->internal.f.has_bounce_buf == false);
3307dadd2a6dSPiotr Pelplinski 
3308dadd2a6dSPiotr Pelplinski 	rc = spdk_bdev_read_blocks(desc, io_ch, buf + 4, 0, 1, io_done, NULL);
3309dadd2a6dSPiotr Pelplinski 	CU_ASSERT(rc == 0);
33107fee8002SBen Walker 	CU_ASSERT(g_bdev_io->internal.bounce_buf.orig_iovcnt == 1);
33117fee8002SBen Walker 	CU_ASSERT(g_bdev_io->u.bdev.iovs == &g_bdev_io->internal.bounce_buf.iov);
3312dadd2a6dSPiotr Pelplinski 	CU_ASSERT(_are_iovs_aligned(g_bdev_io->u.bdev.iovs, g_bdev_io->u.bdev.iovcnt,
3313dadd2a6dSPiotr Pelplinski 				    alignment));
3314dadd2a6dSPiotr Pelplinski 	stub_complete_io(1);
33157fee8002SBen Walker 	CU_ASSERT(g_bdev_io->internal.f.has_bounce_buf == false);
3316dadd2a6dSPiotr Pelplinski 
3317dadd2a6dSPiotr Pelplinski 	/* Pass unaligned single buffer with 4096 alignment required */
3318dadd2a6dSPiotr Pelplinski 	alignment = 4096;
3319dadd2a6dSPiotr Pelplinski 	bdev->required_alignment = spdk_u32log2(alignment);
3320dadd2a6dSPiotr Pelplinski 
3321dadd2a6dSPiotr Pelplinski 	rc = spdk_bdev_write_blocks(desc, io_ch, buf + 8, 0, 1, io_done, NULL);
3322dadd2a6dSPiotr Pelplinski 	CU_ASSERT(rc == 0);
33237fee8002SBen Walker 	CU_ASSERT(g_bdev_io->internal.bounce_buf.orig_iovcnt == 1);
33247fee8002SBen Walker 	CU_ASSERT(g_bdev_io->u.bdev.iovs == &g_bdev_io->internal.bounce_buf.iov);
3325dadd2a6dSPiotr Pelplinski 	CU_ASSERT(_are_iovs_aligned(g_bdev_io->u.bdev.iovs, g_bdev_io->u.bdev.iovcnt,
3326dadd2a6dSPiotr Pelplinski 				    alignment));
3327dadd2a6dSPiotr Pelplinski 	stub_complete_io(1);
33287fee8002SBen Walker 	CU_ASSERT(g_bdev_io->internal.f.has_bounce_buf == false);
3329dadd2a6dSPiotr Pelplinski 
3330dadd2a6dSPiotr Pelplinski 	rc = spdk_bdev_read_blocks(desc, io_ch, buf + 8, 0, 1, io_done, NULL);
3331dadd2a6dSPiotr Pelplinski 	CU_ASSERT(rc == 0);
33327fee8002SBen Walker 	CU_ASSERT(g_bdev_io->internal.bounce_buf.orig_iovcnt == 1);
33337fee8002SBen Walker 	CU_ASSERT(g_bdev_io->u.bdev.iovs == &g_bdev_io->internal.bounce_buf.iov);
3334dadd2a6dSPiotr Pelplinski 	CU_ASSERT(_are_iovs_aligned(g_bdev_io->u.bdev.iovs, g_bdev_io->u.bdev.iovcnt,
3335dadd2a6dSPiotr Pelplinski 				    alignment));
3336dadd2a6dSPiotr Pelplinski 	stub_complete_io(1);
33377fee8002SBen Walker 	CU_ASSERT(g_bdev_io->internal.f.has_bounce_buf == false);
3338dadd2a6dSPiotr Pelplinski 
3339dadd2a6dSPiotr Pelplinski 	/* Pass aligned iovs with no alignment required */
3340dadd2a6dSPiotr Pelplinski 	alignment = 1;
3341dadd2a6dSPiotr Pelplinski 	bdev->required_alignment = spdk_u32log2(alignment);
3342dadd2a6dSPiotr Pelplinski 
3343dadd2a6dSPiotr Pelplinski 	iovcnt = 1;
3344dadd2a6dSPiotr Pelplinski 	iovs[0].iov_base = buf;
3345dadd2a6dSPiotr Pelplinski 	iovs[0].iov_len = 512;
3346dadd2a6dSPiotr Pelplinski 
3347dadd2a6dSPiotr Pelplinski 	rc = spdk_bdev_writev(desc, io_ch, iovs, iovcnt, 0, 512, io_done, NULL);
3348dadd2a6dSPiotr Pelplinski 	CU_ASSERT(rc == 0);
33497fee8002SBen Walker 	CU_ASSERT(g_bdev_io->internal.f.has_bounce_buf == false);
3350dadd2a6dSPiotr Pelplinski 	stub_complete_io(1);
3351dadd2a6dSPiotr Pelplinski 	CU_ASSERT(g_bdev_io->u.bdev.iovs[0].iov_base == iovs[0].iov_base);
3352dadd2a6dSPiotr Pelplinski 
3353dadd2a6dSPiotr Pelplinski 	rc = spdk_bdev_readv(desc, io_ch, iovs, iovcnt, 0, 512, io_done, NULL);
3354dadd2a6dSPiotr Pelplinski 	CU_ASSERT(rc == 0);
33557fee8002SBen Walker 	CU_ASSERT(g_bdev_io->internal.f.has_bounce_buf == false);
3356dadd2a6dSPiotr Pelplinski 	stub_complete_io(1);
3357dadd2a6dSPiotr Pelplinski 	CU_ASSERT(g_bdev_io->u.bdev.iovs[0].iov_base == iovs[0].iov_base);
3358dadd2a6dSPiotr Pelplinski 
3359dadd2a6dSPiotr Pelplinski 	/* Pass unaligned iovs with no alignment required */
3360dadd2a6dSPiotr Pelplinski 	alignment = 1;
3361dadd2a6dSPiotr Pelplinski 	bdev->required_alignment = spdk_u32log2(alignment);
3362dadd2a6dSPiotr Pelplinski 
3363dadd2a6dSPiotr Pelplinski 	iovcnt = 2;
3364dadd2a6dSPiotr Pelplinski 	iovs[0].iov_base = buf + 16;
3365dadd2a6dSPiotr Pelplinski 	iovs[0].iov_len = 256;
3366dadd2a6dSPiotr Pelplinski 	iovs[1].iov_base = buf + 16 + 256 + 32;
3367dadd2a6dSPiotr Pelplinski 	iovs[1].iov_len = 256;
3368dadd2a6dSPiotr Pelplinski 
3369dadd2a6dSPiotr Pelplinski 	rc = spdk_bdev_writev(desc, io_ch, iovs, iovcnt, 0, 512, io_done, NULL);
3370dadd2a6dSPiotr Pelplinski 	CU_ASSERT(rc == 0);
33717fee8002SBen Walker 	CU_ASSERT(g_bdev_io->internal.f.has_bounce_buf == false);
3372dadd2a6dSPiotr Pelplinski 	stub_complete_io(1);
3373dadd2a6dSPiotr Pelplinski 	CU_ASSERT(g_bdev_io->u.bdev.iovs[0].iov_base == iovs[0].iov_base);
3374dadd2a6dSPiotr Pelplinski 
3375dadd2a6dSPiotr Pelplinski 	rc = spdk_bdev_readv(desc, io_ch, iovs, iovcnt, 0, 512, io_done, NULL);
3376dadd2a6dSPiotr Pelplinski 	CU_ASSERT(rc == 0);
33777fee8002SBen Walker 	CU_ASSERT(g_bdev_io->internal.f.has_bounce_buf == false);
3378dadd2a6dSPiotr Pelplinski 	stub_complete_io(1);
3379dadd2a6dSPiotr Pelplinski 	CU_ASSERT(g_bdev_io->u.bdev.iovs[0].iov_base == iovs[0].iov_base);
3380dadd2a6dSPiotr Pelplinski 
3381dadd2a6dSPiotr Pelplinski 	/* Pass unaligned iov with 2048 alignment required */
3382dadd2a6dSPiotr Pelplinski 	alignment = 2048;
3383dadd2a6dSPiotr Pelplinski 	bdev->required_alignment = spdk_u32log2(alignment);
3384dadd2a6dSPiotr Pelplinski 
3385dadd2a6dSPiotr Pelplinski 	iovcnt = 2;
3386dadd2a6dSPiotr Pelplinski 	iovs[0].iov_base = buf + 16;
3387dadd2a6dSPiotr Pelplinski 	iovs[0].iov_len = 256;
3388dadd2a6dSPiotr Pelplinski 	iovs[1].iov_base = buf + 16 + 256 + 32;
3389dadd2a6dSPiotr Pelplinski 	iovs[1].iov_len = 256;
3390dadd2a6dSPiotr Pelplinski 
3391dadd2a6dSPiotr Pelplinski 	rc = spdk_bdev_writev(desc, io_ch, iovs, iovcnt, 0, 512, io_done, NULL);
3392dadd2a6dSPiotr Pelplinski 	CU_ASSERT(rc == 0);
33937fee8002SBen Walker 	CU_ASSERT(g_bdev_io->internal.bounce_buf.orig_iovcnt == iovcnt);
33947fee8002SBen Walker 	CU_ASSERT(g_bdev_io->u.bdev.iovs == &g_bdev_io->internal.bounce_buf.iov);
3395dadd2a6dSPiotr Pelplinski 	CU_ASSERT(_are_iovs_aligned(g_bdev_io->u.bdev.iovs, g_bdev_io->u.bdev.iovcnt,
3396dadd2a6dSPiotr Pelplinski 				    alignment));
3397dadd2a6dSPiotr Pelplinski 	stub_complete_io(1);
33987fee8002SBen Walker 	CU_ASSERT(g_bdev_io->internal.f.has_bounce_buf == false);
3399dadd2a6dSPiotr Pelplinski 
3400dadd2a6dSPiotr Pelplinski 	rc = spdk_bdev_readv(desc, io_ch, iovs, iovcnt, 0, 512, io_done, NULL);
3401dadd2a6dSPiotr Pelplinski 	CU_ASSERT(rc == 0);
34027fee8002SBen Walker 	CU_ASSERT(g_bdev_io->internal.bounce_buf.orig_iovcnt == iovcnt);
34037fee8002SBen Walker 	CU_ASSERT(g_bdev_io->u.bdev.iovs == &g_bdev_io->internal.bounce_buf.iov);
3404dadd2a6dSPiotr Pelplinski 	CU_ASSERT(_are_iovs_aligned(g_bdev_io->u.bdev.iovs, g_bdev_io->u.bdev.iovcnt,
3405dadd2a6dSPiotr Pelplinski 				    alignment));
3406dadd2a6dSPiotr Pelplinski 	stub_complete_io(1);
34077fee8002SBen Walker 	CU_ASSERT(g_bdev_io->internal.f.has_bounce_buf == false);
3408dadd2a6dSPiotr Pelplinski 
3409dadd2a6dSPiotr Pelplinski 	/* Pass iov without allocated buffer without alignment required */
3410dadd2a6dSPiotr Pelplinski 	alignment = 1;
3411dadd2a6dSPiotr Pelplinski 	bdev->required_alignment = spdk_u32log2(alignment);
3412dadd2a6dSPiotr Pelplinski 
3413dadd2a6dSPiotr Pelplinski 	iovcnt = 1;
3414dadd2a6dSPiotr Pelplinski 	iovs[0].iov_base = NULL;
3415dadd2a6dSPiotr Pelplinski 	iovs[0].iov_len = 0;
3416dadd2a6dSPiotr Pelplinski 
3417dadd2a6dSPiotr Pelplinski 	rc = spdk_bdev_readv(desc, io_ch, iovs, iovcnt, 0, 512, io_done, NULL);
3418dadd2a6dSPiotr Pelplinski 	CU_ASSERT(rc == 0);
34197fee8002SBen Walker 	CU_ASSERT(g_bdev_io->internal.f.has_bounce_buf == false);
3420dadd2a6dSPiotr Pelplinski 	CU_ASSERT(_are_iovs_aligned(g_bdev_io->u.bdev.iovs, g_bdev_io->u.bdev.iovcnt,
3421dadd2a6dSPiotr Pelplinski 				    alignment));
3422dadd2a6dSPiotr Pelplinski 	stub_complete_io(1);
3423dadd2a6dSPiotr Pelplinski 
3424dadd2a6dSPiotr Pelplinski 	/* Pass iov without allocated buffer with 1024 alignment required */
3425dadd2a6dSPiotr Pelplinski 	alignment = 1024;
3426dadd2a6dSPiotr Pelplinski 	bdev->required_alignment = spdk_u32log2(alignment);
3427dadd2a6dSPiotr Pelplinski 
3428dadd2a6dSPiotr Pelplinski 	iovcnt = 1;
3429dadd2a6dSPiotr Pelplinski 	iovs[0].iov_base = NULL;
3430dadd2a6dSPiotr Pelplinski 	iovs[0].iov_len = 0;
3431dadd2a6dSPiotr Pelplinski 
3432dadd2a6dSPiotr Pelplinski 	rc = spdk_bdev_readv(desc, io_ch, iovs, iovcnt, 0, 512, io_done, NULL);
3433dadd2a6dSPiotr Pelplinski 	CU_ASSERT(rc == 0);
34347fee8002SBen Walker 	CU_ASSERT(g_bdev_io->internal.f.has_bounce_buf == false);
3435dadd2a6dSPiotr Pelplinski 	CU_ASSERT(_are_iovs_aligned(g_bdev_io->u.bdev.iovs, g_bdev_io->u.bdev.iovcnt,
3436dadd2a6dSPiotr Pelplinski 				    alignment));
3437dadd2a6dSPiotr Pelplinski 	stub_complete_io(1);
3438dadd2a6dSPiotr Pelplinski 
3439dadd2a6dSPiotr Pelplinski 	spdk_put_io_channel(io_ch);
3440dadd2a6dSPiotr Pelplinski 	spdk_bdev_close(desc);
3441dadd2a6dSPiotr Pelplinski 	free_bdev(bdev);
3442ae43c81aSJim Harris 	fn_table.submit_request = stub_submit_request;
3443107741fcSKonrad Sztyber 	ut_fini_bdev();
3444dadd2a6dSPiotr Pelplinski 
3445dadd2a6dSPiotr Pelplinski 	free(buf);
3446dadd2a6dSPiotr Pelplinski }
3447dadd2a6dSPiotr Pelplinski 
344842dba604SPiotr Pelplinski static void
344945f48053SChangpeng Liu bdev_io_alignment_with_boundary(void)
345045f48053SChangpeng Liu {
345145f48053SChangpeng Liu 	struct spdk_bdev *bdev;
3452e2ce08cfSTomasz Zawadzki 	struct spdk_bdev_desc *desc = NULL;
345345f48053SChangpeng Liu 	struct spdk_io_channel *io_ch;
3454f420b9efSZiye Yang 	struct spdk_bdev_opts bdev_opts = {};
345545f48053SChangpeng Liu 	int rc;
34569714818dSyidong0635 	void *buf = NULL;
345745f48053SChangpeng Liu 	struct iovec iovs[2];
345845f48053SChangpeng Liu 	int iovcnt;
345945f48053SChangpeng Liu 	uint64_t alignment;
346045f48053SChangpeng Liu 
3461f420b9efSZiye Yang 	spdk_bdev_get_opts(&bdev_opts, sizeof(bdev_opts));
3462f420b9efSZiye Yang 	bdev_opts.bdev_io_pool_size = 20;
3463f420b9efSZiye Yang 	bdev_opts.bdev_io_cache_size = 2;
3464d3d077ccSZiye Yang 	bdev_opts.opts_size = sizeof(bdev_opts);
3465107741fcSKonrad Sztyber 	ut_init_bdev(&bdev_opts);
346645f48053SChangpeng Liu 
346780da9548SMaciej Szwed 	fn_table.submit_request = stub_submit_request_get_buf;
346845f48053SChangpeng Liu 	bdev = allocate_bdev("bdev0");
346945f48053SChangpeng Liu 
347075dfecbbSShuhei Matsumoto 	rc = spdk_bdev_open_ext("bdev0", true, bdev_ut_event_cb, NULL, &desc);
347145f48053SChangpeng Liu 	CU_ASSERT(rc == 0);
347245f48053SChangpeng Liu 	CU_ASSERT(desc != NULL);
347375dfecbbSShuhei Matsumoto 	CU_ASSERT(bdev == spdk_bdev_desc_get_bdev(desc));
347445f48053SChangpeng Liu 	io_ch = spdk_bdev_get_io_channel(desc);
347545f48053SChangpeng Liu 	CU_ASSERT(io_ch != NULL);
347645f48053SChangpeng Liu 
347745f48053SChangpeng Liu 	/* Create aligned buffer */
347845f48053SChangpeng Liu 	rc = posix_memalign(&buf, 4096, 131072);
347945f48053SChangpeng Liu 	SPDK_CU_ASSERT_FATAL(rc == 0);
348045f48053SChangpeng Liu 	g_io_exp_status = SPDK_BDEV_IO_STATUS_SUCCESS;
348145f48053SChangpeng Liu 
34827fee8002SBen Walker #ifdef NOTDEF
348345f48053SChangpeng Liu 	/* 512 * 3 with 2 IO boundary, allocate small data buffer from bdev layer */
348445f48053SChangpeng Liu 	alignment = 512;
348545f48053SChangpeng Liu 	bdev->required_alignment = spdk_u32log2(alignment);
348645f48053SChangpeng Liu 	bdev->optimal_io_boundary = 2;
348745f48053SChangpeng Liu 	bdev->split_on_optimal_io_boundary = true;
348845f48053SChangpeng Liu 
348945f48053SChangpeng Liu 	iovcnt = 1;
349045f48053SChangpeng Liu 	iovs[0].iov_base = NULL;
349145f48053SChangpeng Liu 	iovs[0].iov_len = 512 * 3;
349245f48053SChangpeng Liu 
349345f48053SChangpeng Liu 	rc = spdk_bdev_readv_blocks(desc, io_ch, iovs, iovcnt, 1, 3, io_done, NULL);
349445f48053SChangpeng Liu 	CU_ASSERT(rc == 0);
349545f48053SChangpeng Liu 	CU_ASSERT(g_bdev_ut_channel->outstanding_io_count == 2);
349645f48053SChangpeng Liu 	stub_complete_io(2);
349745f48053SChangpeng Liu 
349845f48053SChangpeng Liu 	/* 8KiB with 16 IO boundary, allocate large data buffer from bdev layer */
349945f48053SChangpeng Liu 	alignment = 512;
350045f48053SChangpeng Liu 	bdev->required_alignment = spdk_u32log2(alignment);
350145f48053SChangpeng Liu 	bdev->optimal_io_boundary = 16;
350245f48053SChangpeng Liu 	bdev->split_on_optimal_io_boundary = true;
350345f48053SChangpeng Liu 
350445f48053SChangpeng Liu 	iovcnt = 1;
350545f48053SChangpeng Liu 	iovs[0].iov_base = NULL;
350645f48053SChangpeng Liu 	iovs[0].iov_len = 512 * 16;
350745f48053SChangpeng Liu 
350845f48053SChangpeng Liu 	rc = spdk_bdev_readv_blocks(desc, io_ch, iovs, iovcnt, 1, 16, io_done, NULL);
350945f48053SChangpeng Liu 	CU_ASSERT(rc == 0);
351045f48053SChangpeng Liu 	CU_ASSERT(g_bdev_ut_channel->outstanding_io_count == 2);
351145f48053SChangpeng Liu 	stub_complete_io(2);
351245f48053SChangpeng Liu 
351345f48053SChangpeng Liu 	/* 512 * 160 with 128 IO boundary, 63.5KiB + 16.5KiB for the two children requests */
351445f48053SChangpeng Liu 	alignment = 512;
351545f48053SChangpeng Liu 	bdev->required_alignment = spdk_u32log2(alignment);
351645f48053SChangpeng Liu 	bdev->optimal_io_boundary = 128;
351745f48053SChangpeng Liu 	bdev->split_on_optimal_io_boundary = true;
351845f48053SChangpeng Liu 
351945f48053SChangpeng Liu 	iovcnt = 1;
352045f48053SChangpeng Liu 	iovs[0].iov_base = buf + 16;
352145f48053SChangpeng Liu 	iovs[0].iov_len = 512 * 160;
352245f48053SChangpeng Liu 	rc = spdk_bdev_readv_blocks(desc, io_ch, iovs, iovcnt, 1, 160, io_done, NULL);
352345f48053SChangpeng Liu 	CU_ASSERT(rc == 0);
352445f48053SChangpeng Liu 	CU_ASSERT(g_bdev_ut_channel->outstanding_io_count == 2);
352545f48053SChangpeng Liu 	stub_complete_io(2);
352645f48053SChangpeng Liu 
35277fee8002SBen Walker #endif
35287fee8002SBen Walker 
352945f48053SChangpeng Liu 	/* 512 * 3 with 2 IO boundary */
353045f48053SChangpeng Liu 	alignment = 512;
353145f48053SChangpeng Liu 	bdev->required_alignment = spdk_u32log2(alignment);
353245f48053SChangpeng Liu 	bdev->optimal_io_boundary = 2;
353345f48053SChangpeng Liu 	bdev->split_on_optimal_io_boundary = true;
353445f48053SChangpeng Liu 
353545f48053SChangpeng Liu 	iovcnt = 2;
353645f48053SChangpeng Liu 	iovs[0].iov_base = buf + 16;
353745f48053SChangpeng Liu 	iovs[0].iov_len = 512;
353845f48053SChangpeng Liu 	iovs[1].iov_base = buf + 16 + 512 + 32;
353945f48053SChangpeng Liu 	iovs[1].iov_len = 1024;
354045f48053SChangpeng Liu 
354145f48053SChangpeng Liu 	rc = spdk_bdev_writev_blocks(desc, io_ch, iovs, iovcnt, 1, 3, io_done, NULL);
354245f48053SChangpeng Liu 	CU_ASSERT(rc == 0);
354345f48053SChangpeng Liu 	CU_ASSERT(g_bdev_ut_channel->outstanding_io_count == 2);
354445f48053SChangpeng Liu 	stub_complete_io(2);
354545f48053SChangpeng Liu 
354645f48053SChangpeng Liu 	rc = spdk_bdev_readv_blocks(desc, io_ch, iovs, iovcnt, 1, 3, io_done, NULL);
354745f48053SChangpeng Liu 	CU_ASSERT(rc == 0);
354845f48053SChangpeng Liu 	CU_ASSERT(g_bdev_ut_channel->outstanding_io_count == 2);
354945f48053SChangpeng Liu 	stub_complete_io(2);
355045f48053SChangpeng Liu 
355145f48053SChangpeng Liu 	/* 512 * 64 with 32 IO boundary */
355245f48053SChangpeng Liu 	bdev->optimal_io_boundary = 32;
355345f48053SChangpeng Liu 	iovcnt = 2;
355445f48053SChangpeng Liu 	iovs[0].iov_base = buf + 16;
355545f48053SChangpeng Liu 	iovs[0].iov_len = 16384;
355645f48053SChangpeng Liu 	iovs[1].iov_base = buf + 16 + 16384 + 32;
355745f48053SChangpeng Liu 	iovs[1].iov_len = 16384;
355845f48053SChangpeng Liu 
355945f48053SChangpeng Liu 	rc = spdk_bdev_writev_blocks(desc, io_ch, iovs, iovcnt, 1, 64, io_done, NULL);
356045f48053SChangpeng Liu 	CU_ASSERT(rc == 0);
356145f48053SChangpeng Liu 	CU_ASSERT(g_bdev_ut_channel->outstanding_io_count == 3);
356245f48053SChangpeng Liu 	stub_complete_io(3);
356345f48053SChangpeng Liu 
356445f48053SChangpeng Liu 	rc = spdk_bdev_readv_blocks(desc, io_ch, iovs, iovcnt, 1, 64, io_done, NULL);
356545f48053SChangpeng Liu 	CU_ASSERT(rc == 0);
356645f48053SChangpeng Liu 	CU_ASSERT(g_bdev_ut_channel->outstanding_io_count == 3);
356745f48053SChangpeng Liu 	stub_complete_io(3);
356845f48053SChangpeng Liu 
356945f48053SChangpeng Liu 	/* 512 * 160 with 32 IO boundary */
357045f48053SChangpeng Liu 	iovcnt = 1;
357145f48053SChangpeng Liu 	iovs[0].iov_base = buf + 16;
357245f48053SChangpeng Liu 	iovs[0].iov_len = 16384 + 65536;
357345f48053SChangpeng Liu 
357445f48053SChangpeng Liu 	rc = spdk_bdev_writev_blocks(desc, io_ch, iovs, iovcnt, 1, 160, io_done, NULL);
357545f48053SChangpeng Liu 	CU_ASSERT(rc == 0);
357645f48053SChangpeng Liu 	CU_ASSERT(g_bdev_ut_channel->outstanding_io_count == 6);
357745f48053SChangpeng Liu 	stub_complete_io(6);
357845f48053SChangpeng Liu 
357945f48053SChangpeng Liu 	spdk_put_io_channel(io_ch);
358045f48053SChangpeng Liu 	spdk_bdev_close(desc);
358145f48053SChangpeng Liu 	free_bdev(bdev);
3582ae43c81aSJim Harris 	fn_table.submit_request = stub_submit_request;
3583107741fcSKonrad Sztyber 	ut_fini_bdev();
358445f48053SChangpeng Liu 
358545f48053SChangpeng Liu 	free(buf);
358645f48053SChangpeng Liu }
358745f48053SChangpeng Liu 
358845f48053SChangpeng Liu static void
358942dba604SPiotr Pelplinski histogram_status_cb(void *cb_arg, int status)
359042dba604SPiotr Pelplinski {
359142dba604SPiotr Pelplinski 	g_status = status;
359242dba604SPiotr Pelplinski }
359342dba604SPiotr Pelplinski 
359442dba604SPiotr Pelplinski static void
359542dba604SPiotr Pelplinski histogram_data_cb(void *cb_arg, int status, struct spdk_histogram_data *histogram)
359642dba604SPiotr Pelplinski {
359742dba604SPiotr Pelplinski 	g_status = status;
359842dba604SPiotr Pelplinski 	g_histogram = histogram;
359942dba604SPiotr Pelplinski }
360042dba604SPiotr Pelplinski 
360142dba604SPiotr Pelplinski static void
360242dba604SPiotr Pelplinski histogram_io_count(void *ctx, uint64_t start, uint64_t end, uint64_t count,
360342dba604SPiotr Pelplinski 		   uint64_t total, uint64_t so_far)
360442dba604SPiotr Pelplinski {
360542dba604SPiotr Pelplinski 	g_count += count;
360642dba604SPiotr Pelplinski }
360742dba604SPiotr Pelplinski 
360842dba604SPiotr Pelplinski static void
3609f192c11bSRichael Zhuang histogram_channel_data_cb(void *cb_arg, int status, struct spdk_histogram_data *histogram)
3610f192c11bSRichael Zhuang {
3611f192c11bSRichael Zhuang 	spdk_histogram_data_fn cb_fn = cb_arg;
3612f192c11bSRichael Zhuang 
3613f192c11bSRichael Zhuang 	g_status = status;
3614f192c11bSRichael Zhuang 
3615f192c11bSRichael Zhuang 	if (status == 0) {
3616f192c11bSRichael Zhuang 		spdk_histogram_data_iterate(histogram, cb_fn, NULL);
3617f192c11bSRichael Zhuang 	}
3618f192c11bSRichael Zhuang }
3619f192c11bSRichael Zhuang 
3620f192c11bSRichael Zhuang static void
362142dba604SPiotr Pelplinski bdev_histograms(void)
362242dba604SPiotr Pelplinski {
362342dba604SPiotr Pelplinski 	struct spdk_bdev *bdev;
3624dae8e892STomasz Zawadzki 	struct spdk_bdev_desc *desc = NULL;
362542dba604SPiotr Pelplinski 	struct spdk_io_channel *ch;
362642dba604SPiotr Pelplinski 	struct spdk_histogram_data *histogram;
362742dba604SPiotr Pelplinski 	uint8_t buf[4096];
362842dba604SPiotr Pelplinski 	int rc;
362942dba604SPiotr Pelplinski 
3630107741fcSKonrad Sztyber 	ut_init_bdev(NULL);
363142dba604SPiotr Pelplinski 
363242dba604SPiotr Pelplinski 	bdev = allocate_bdev("bdev");
363342dba604SPiotr Pelplinski 
363475dfecbbSShuhei Matsumoto 	rc = spdk_bdev_open_ext("bdev", true, bdev_ut_event_cb, NULL, &desc);
363542dba604SPiotr Pelplinski 	CU_ASSERT(rc == 0);
363642dba604SPiotr Pelplinski 	CU_ASSERT(desc != NULL);
363775dfecbbSShuhei Matsumoto 	CU_ASSERT(bdev == spdk_bdev_desc_get_bdev(desc));
363842dba604SPiotr Pelplinski 
363942dba604SPiotr Pelplinski 	ch = spdk_bdev_get_io_channel(desc);
364042dba604SPiotr Pelplinski 	CU_ASSERT(ch != NULL);
364142dba604SPiotr Pelplinski 
364242dba604SPiotr Pelplinski 	/* Enable histogram */
364342dba604SPiotr Pelplinski 	g_status = -1;
364442dba604SPiotr Pelplinski 	spdk_bdev_histogram_enable(bdev, histogram_status_cb, NULL, true);
364542dba604SPiotr Pelplinski 	poll_threads();
364642dba604SPiotr Pelplinski 	CU_ASSERT(g_status == 0);
364742dba604SPiotr Pelplinski 	CU_ASSERT(bdev->internal.histogram_enabled == true);
364842dba604SPiotr Pelplinski 
364942dba604SPiotr Pelplinski 	/* Allocate histogram */
365042dba604SPiotr Pelplinski 	histogram = spdk_histogram_data_alloc();
365142dba604SPiotr Pelplinski 	SPDK_CU_ASSERT_FATAL(histogram != NULL);
365242dba604SPiotr Pelplinski 
365342dba604SPiotr Pelplinski 	/* Check if histogram is zeroed */
365442dba604SPiotr Pelplinski 	spdk_bdev_histogram_get(bdev, histogram, histogram_data_cb, NULL);
365542dba604SPiotr Pelplinski 	poll_threads();
365642dba604SPiotr Pelplinski 	CU_ASSERT(g_status == 0);
365742dba604SPiotr Pelplinski 	SPDK_CU_ASSERT_FATAL(g_histogram != NULL);
365842dba604SPiotr Pelplinski 
365942dba604SPiotr Pelplinski 	g_count = 0;
366042dba604SPiotr Pelplinski 	spdk_histogram_data_iterate(g_histogram, histogram_io_count, NULL);
366142dba604SPiotr Pelplinski 
366242dba604SPiotr Pelplinski 	CU_ASSERT(g_count == 0);
366342dba604SPiotr Pelplinski 
36641d94a0b0SJim Harris 	rc = spdk_bdev_write_blocks(desc, ch, buf, 0, 1, io_done, NULL);
366542dba604SPiotr Pelplinski 	CU_ASSERT(rc == 0);
366642dba604SPiotr Pelplinski 
366742dba604SPiotr Pelplinski 	spdk_delay_us(10);
366842dba604SPiotr Pelplinski 	stub_complete_io(1);
366942dba604SPiotr Pelplinski 	poll_threads();
367042dba604SPiotr Pelplinski 
36711d94a0b0SJim Harris 	rc = spdk_bdev_read_blocks(desc, ch, buf, 0, 1, io_done, NULL);
367242dba604SPiotr Pelplinski 	CU_ASSERT(rc == 0);
367342dba604SPiotr Pelplinski 
367442dba604SPiotr Pelplinski 	spdk_delay_us(10);
367542dba604SPiotr Pelplinski 	stub_complete_io(1);
367642dba604SPiotr Pelplinski 	poll_threads();
367742dba604SPiotr Pelplinski 
367842dba604SPiotr Pelplinski 	/* Check if histogram gathered data from all I/O channels */
367942dba604SPiotr Pelplinski 	g_histogram = NULL;
368042dba604SPiotr Pelplinski 	spdk_bdev_histogram_get(bdev, histogram, histogram_data_cb, NULL);
368142dba604SPiotr Pelplinski 	poll_threads();
368242dba604SPiotr Pelplinski 	CU_ASSERT(g_status == 0);
368342dba604SPiotr Pelplinski 	CU_ASSERT(bdev->internal.histogram_enabled == true);
368442dba604SPiotr Pelplinski 	SPDK_CU_ASSERT_FATAL(g_histogram != NULL);
368542dba604SPiotr Pelplinski 
368642dba604SPiotr Pelplinski 	g_count = 0;
368742dba604SPiotr Pelplinski 	spdk_histogram_data_iterate(g_histogram, histogram_io_count, NULL);
368842dba604SPiotr Pelplinski 	CU_ASSERT(g_count == 2);
368942dba604SPiotr Pelplinski 
3690f192c11bSRichael Zhuang 	g_count = 0;
369136f8f8daSRichael Zhuang 	spdk_bdev_channel_get_histogram(ch, histogram_channel_data_cb, histogram_io_count);
3692f192c11bSRichael Zhuang 	CU_ASSERT(g_status == 0);
3693f192c11bSRichael Zhuang 	CU_ASSERT(g_count == 2);
3694f192c11bSRichael Zhuang 
369542dba604SPiotr Pelplinski 	/* Disable histogram */
369642dba604SPiotr Pelplinski 	spdk_bdev_histogram_enable(bdev, histogram_status_cb, NULL, false);
369742dba604SPiotr Pelplinski 	poll_threads();
369842dba604SPiotr Pelplinski 	CU_ASSERT(g_status == 0);
369942dba604SPiotr Pelplinski 	CU_ASSERT(bdev->internal.histogram_enabled == false);
370042dba604SPiotr Pelplinski 
370142dba604SPiotr Pelplinski 	/* Try to run histogram commands on disabled bdev */
370242dba604SPiotr Pelplinski 	spdk_bdev_histogram_get(bdev, histogram, histogram_data_cb, NULL);
370342dba604SPiotr Pelplinski 	poll_threads();
370442dba604SPiotr Pelplinski 	CU_ASSERT(g_status == -EFAULT);
370542dba604SPiotr Pelplinski 
370636f8f8daSRichael Zhuang 	spdk_bdev_channel_get_histogram(ch, histogram_channel_data_cb, NULL);
3707f192c11bSRichael Zhuang 	CU_ASSERT(g_status == -EFAULT);
3708f192c11bSRichael Zhuang 
370926f6c2a0SDarek Stojaczyk 	spdk_histogram_data_free(histogram);
371042dba604SPiotr Pelplinski 	spdk_put_io_channel(ch);
371142dba604SPiotr Pelplinski 	spdk_bdev_close(desc);
371242dba604SPiotr Pelplinski 	free_bdev(bdev);
3713107741fcSKonrad Sztyber 	ut_fini_bdev();
371442dba604SPiotr Pelplinski }
371542dba604SPiotr Pelplinski 
3716e2918289SKonrad Sztyber static void
37173eda8bf6SMaciej Szwed _bdev_compare(bool emulated)
371877183c9cSMaciej Szwed {
371977183c9cSMaciej Szwed 	struct spdk_bdev *bdev;
372077183c9cSMaciej Szwed 	struct spdk_bdev_desc *desc = NULL;
372177183c9cSMaciej Szwed 	struct spdk_io_channel *ioch;
372277183c9cSMaciej Szwed 	struct ut_expected_io *expected_io;
372377183c9cSMaciej Szwed 	uint64_t offset, num_blocks;
372477183c9cSMaciej Szwed 	uint32_t num_completed;
372577183c9cSMaciej Szwed 	char aa_buf[512];
372677183c9cSMaciej Szwed 	char bb_buf[512];
372777183c9cSMaciej Szwed 	struct iovec compare_iov;
37280bd6b7f2SJonas Pfefferle 	uint8_t expected_io_type;
372977183c9cSMaciej Szwed 	int rc;
373077183c9cSMaciej Szwed 
37313eda8bf6SMaciej Szwed 	if (emulated) {
37320bd6b7f2SJonas Pfefferle 		expected_io_type = SPDK_BDEV_IO_TYPE_READ;
37333eda8bf6SMaciej Szwed 	} else {
37340bd6b7f2SJonas Pfefferle 		expected_io_type = SPDK_BDEV_IO_TYPE_COMPARE;
37353eda8bf6SMaciej Szwed 	}
37363eda8bf6SMaciej Szwed 
373777183c9cSMaciej Szwed 	memset(aa_buf, 0xaa, sizeof(aa_buf));
373877183c9cSMaciej Szwed 	memset(bb_buf, 0xbb, sizeof(bb_buf));
373977183c9cSMaciej Szwed 
37403eda8bf6SMaciej Szwed 	g_io_types_supported[SPDK_BDEV_IO_TYPE_COMPARE] = !emulated;
3741bee042e4SMaciej Szwed 
3742107741fcSKonrad Sztyber 	ut_init_bdev(NULL);
374377183c9cSMaciej Szwed 	fn_table.submit_request = stub_submit_request_get_buf;
374477183c9cSMaciej Szwed 	bdev = allocate_bdev("bdev");
374577183c9cSMaciej Szwed 
374675dfecbbSShuhei Matsumoto 	rc = spdk_bdev_open_ext("bdev", true, bdev_ut_event_cb, NULL, &desc);
374777183c9cSMaciej Szwed 	CU_ASSERT_EQUAL(rc, 0);
374877183c9cSMaciej Szwed 	SPDK_CU_ASSERT_FATAL(desc != NULL);
374975dfecbbSShuhei Matsumoto 	CU_ASSERT(bdev == spdk_bdev_desc_get_bdev(desc));
375077183c9cSMaciej Szwed 	ioch = spdk_bdev_get_io_channel(desc);
375177183c9cSMaciej Szwed 	SPDK_CU_ASSERT_FATAL(ioch != NULL);
375277183c9cSMaciej Szwed 
375377183c9cSMaciej Szwed 	fn_table.submit_request = stub_submit_request_get_buf;
375477183c9cSMaciej Szwed 	g_io_exp_status = SPDK_BDEV_IO_STATUS_SUCCESS;
375577183c9cSMaciej Szwed 
375677183c9cSMaciej Szwed 	offset = 50;
375777183c9cSMaciej Szwed 	num_blocks = 1;
375877183c9cSMaciej Szwed 	compare_iov.iov_base = aa_buf;
375977183c9cSMaciej Szwed 	compare_iov.iov_len = sizeof(aa_buf);
376077183c9cSMaciej Szwed 
3761f46d3a24SKanKuo 	/* 1. successful comparev */
37620bd6b7f2SJonas Pfefferle 	expected_io = ut_alloc_expected_io(expected_io_type, offset, num_blocks, 0);
376377183c9cSMaciej Szwed 	TAILQ_INSERT_TAIL(&g_bdev_ut_channel->expected_io, expected_io, link);
376477183c9cSMaciej Szwed 
376577183c9cSMaciej Szwed 	g_io_done = false;
376677183c9cSMaciej Szwed 	g_compare_read_buf = aa_buf;
376777183c9cSMaciej Szwed 	g_compare_read_buf_len = sizeof(aa_buf);
376877183c9cSMaciej Szwed 	rc = spdk_bdev_comparev_blocks(desc, ioch, &compare_iov, 1, offset, num_blocks, io_done, NULL);
376977183c9cSMaciej Szwed 	CU_ASSERT_EQUAL(rc, 0);
377077183c9cSMaciej Szwed 	num_completed = stub_complete_io(1);
377177183c9cSMaciej Szwed 	CU_ASSERT_EQUAL(num_completed, 1);
377277183c9cSMaciej Szwed 	CU_ASSERT(g_io_done == true);
377377183c9cSMaciej Szwed 	CU_ASSERT(g_io_status == SPDK_BDEV_IO_STATUS_SUCCESS);
377477183c9cSMaciej Szwed 
3775f46d3a24SKanKuo 	/* 2. miscompare comparev */
37760bd6b7f2SJonas Pfefferle 	expected_io = ut_alloc_expected_io(expected_io_type, offset, num_blocks, 0);
377777183c9cSMaciej Szwed 	TAILQ_INSERT_TAIL(&g_bdev_ut_channel->expected_io, expected_io, link);
377877183c9cSMaciej Szwed 
377977183c9cSMaciej Szwed 	g_io_done = false;
378077183c9cSMaciej Szwed 	g_compare_read_buf = bb_buf;
378177183c9cSMaciej Szwed 	g_compare_read_buf_len = sizeof(bb_buf);
378277183c9cSMaciej Szwed 	rc = spdk_bdev_comparev_blocks(desc, ioch, &compare_iov, 1, offset, num_blocks, io_done, NULL);
378377183c9cSMaciej Szwed 	CU_ASSERT_EQUAL(rc, 0);
378477183c9cSMaciej Szwed 	num_completed = stub_complete_io(1);
378577183c9cSMaciej Szwed 	CU_ASSERT_EQUAL(num_completed, 1);
378677183c9cSMaciej Szwed 	CU_ASSERT(g_io_done == true);
378777183c9cSMaciej Szwed 	CU_ASSERT(g_io_status == SPDK_BDEV_IO_STATUS_MISCOMPARE);
378877183c9cSMaciej Szwed 
3789f46d3a24SKanKuo 	/* 3. successful compare */
3790f46d3a24SKanKuo 	g_io_exp_status = SPDK_BDEV_IO_STATUS_SUCCESS;
3791f46d3a24SKanKuo 	expected_io = ut_alloc_expected_io(expected_io_type, offset, num_blocks, 0);
3792f46d3a24SKanKuo 	TAILQ_INSERT_TAIL(&g_bdev_ut_channel->expected_io, expected_io, link);
3793f46d3a24SKanKuo 
3794f46d3a24SKanKuo 	g_io_done = false;
3795f46d3a24SKanKuo 	g_compare_read_buf = aa_buf;
3796f46d3a24SKanKuo 	g_compare_read_buf_len = sizeof(aa_buf);
3797f46d3a24SKanKuo 	rc = spdk_bdev_compare_blocks(desc, ioch, aa_buf, offset, num_blocks, io_done, NULL);
3798f46d3a24SKanKuo 	CU_ASSERT_EQUAL(rc, 0);
3799f46d3a24SKanKuo 	num_completed = stub_complete_io(1);
3800f46d3a24SKanKuo 	CU_ASSERT_EQUAL(num_completed, 1);
3801f46d3a24SKanKuo 	CU_ASSERT(g_io_done == true);
3802f46d3a24SKanKuo 	CU_ASSERT(g_io_status == SPDK_BDEV_IO_STATUS_SUCCESS);
3803f46d3a24SKanKuo 
3804f46d3a24SKanKuo 	/* 4. miscompare compare */
3805f46d3a24SKanKuo 	expected_io = ut_alloc_expected_io(expected_io_type, offset, num_blocks, 0);
3806f46d3a24SKanKuo 	TAILQ_INSERT_TAIL(&g_bdev_ut_channel->expected_io, expected_io, link);
3807f46d3a24SKanKuo 
3808f46d3a24SKanKuo 	g_io_done = false;
3809f46d3a24SKanKuo 	g_compare_read_buf = bb_buf;
3810f46d3a24SKanKuo 	g_compare_read_buf_len = sizeof(bb_buf);
3811f46d3a24SKanKuo 	rc = spdk_bdev_compare_blocks(desc, ioch, aa_buf, offset, num_blocks, io_done, NULL);
3812f46d3a24SKanKuo 	CU_ASSERT_EQUAL(rc, 0);
3813f46d3a24SKanKuo 	num_completed = stub_complete_io(1);
3814f46d3a24SKanKuo 	CU_ASSERT_EQUAL(num_completed, 1);
3815f46d3a24SKanKuo 	CU_ASSERT(g_io_done == true);
3816f46d3a24SKanKuo 	CU_ASSERT(g_io_status == SPDK_BDEV_IO_STATUS_MISCOMPARE);
3817f46d3a24SKanKuo 
381877183c9cSMaciej Szwed 	spdk_put_io_channel(ioch);
381977183c9cSMaciej Szwed 	spdk_bdev_close(desc);
382077183c9cSMaciej Szwed 	free_bdev(bdev);
382177183c9cSMaciej Szwed 	fn_table.submit_request = stub_submit_request;
3822107741fcSKonrad Sztyber 	ut_fini_bdev();
382377183c9cSMaciej Szwed 
3824bee042e4SMaciej Szwed 	g_io_types_supported[SPDK_BDEV_IO_TYPE_COMPARE] = true;
3825bee042e4SMaciej Szwed 
382677183c9cSMaciej Szwed 	g_compare_read_buf = NULL;
382777183c9cSMaciej Szwed }
382877183c9cSMaciej Szwed 
382977183c9cSMaciej Szwed static void
38300bd6b7f2SJonas Pfefferle _bdev_compare_with_md(bool emulated)
38310bd6b7f2SJonas Pfefferle {
38320bd6b7f2SJonas Pfefferle 	struct spdk_bdev *bdev;
38330bd6b7f2SJonas Pfefferle 	struct spdk_bdev_desc *desc = NULL;
38340bd6b7f2SJonas Pfefferle 	struct spdk_io_channel *ioch;
38350bd6b7f2SJonas Pfefferle 	struct ut_expected_io *expected_io;
38360bd6b7f2SJonas Pfefferle 	uint64_t offset, num_blocks;
38370bd6b7f2SJonas Pfefferle 	uint32_t num_completed;
38380bd6b7f2SJonas Pfefferle 	char buf[1024 + 16 /* 2 * blocklen + 2 * mdlen */];
38390bd6b7f2SJonas Pfefferle 	char buf_interleaved_miscompare[1024 + 16 /* 2 * blocklen + 2 * mdlen */];
38400bd6b7f2SJonas Pfefferle 	char buf_miscompare[1024 /* 2 * blocklen */];
38410bd6b7f2SJonas Pfefferle 	char md_buf[16];
38420bd6b7f2SJonas Pfefferle 	char md_buf_miscompare[16];
38430bd6b7f2SJonas Pfefferle 	struct iovec compare_iov;
38440bd6b7f2SJonas Pfefferle 	uint8_t expected_io_type;
38450bd6b7f2SJonas Pfefferle 	int rc;
38460bd6b7f2SJonas Pfefferle 
38470bd6b7f2SJonas Pfefferle 	if (emulated) {
38480bd6b7f2SJonas Pfefferle 		expected_io_type = SPDK_BDEV_IO_TYPE_READ;
38490bd6b7f2SJonas Pfefferle 	} else {
38500bd6b7f2SJonas Pfefferle 		expected_io_type = SPDK_BDEV_IO_TYPE_COMPARE;
38510bd6b7f2SJonas Pfefferle 	}
38520bd6b7f2SJonas Pfefferle 
38530bd6b7f2SJonas Pfefferle 	memset(buf, 0xaa, sizeof(buf));
38540bd6b7f2SJonas Pfefferle 	memset(buf_interleaved_miscompare, 0xaa, sizeof(buf_interleaved_miscompare));
38550bd6b7f2SJonas Pfefferle 	/* make last md different */
38560bd6b7f2SJonas Pfefferle 	memset(buf_interleaved_miscompare + 1024 + 8, 0xbb, 8);
38570bd6b7f2SJonas Pfefferle 	memset(buf_miscompare, 0xbb, sizeof(buf_miscompare));
38580bd6b7f2SJonas Pfefferle 	memset(md_buf, 0xaa, 16);
38590bd6b7f2SJonas Pfefferle 	memset(md_buf_miscompare, 0xbb, 16);
38600bd6b7f2SJonas Pfefferle 
38610bd6b7f2SJonas Pfefferle 	g_io_types_supported[SPDK_BDEV_IO_TYPE_COMPARE] = !emulated;
38620bd6b7f2SJonas Pfefferle 
3863107741fcSKonrad Sztyber 	ut_init_bdev(NULL);
38640bd6b7f2SJonas Pfefferle 	fn_table.submit_request = stub_submit_request_get_buf;
38650bd6b7f2SJonas Pfefferle 	bdev = allocate_bdev("bdev");
38660bd6b7f2SJonas Pfefferle 
38670bd6b7f2SJonas Pfefferle 	rc = spdk_bdev_open_ext("bdev", true, bdev_ut_event_cb, NULL, &desc);
38680bd6b7f2SJonas Pfefferle 	CU_ASSERT_EQUAL(rc, 0);
38690bd6b7f2SJonas Pfefferle 	SPDK_CU_ASSERT_FATAL(desc != NULL);
38700bd6b7f2SJonas Pfefferle 	CU_ASSERT(bdev == spdk_bdev_desc_get_bdev(desc));
38710bd6b7f2SJonas Pfefferle 	ioch = spdk_bdev_get_io_channel(desc);
38720bd6b7f2SJonas Pfefferle 	SPDK_CU_ASSERT_FATAL(ioch != NULL);
38730bd6b7f2SJonas Pfefferle 
38740bd6b7f2SJonas Pfefferle 	fn_table.submit_request = stub_submit_request_get_buf;
38750bd6b7f2SJonas Pfefferle 	g_io_exp_status = SPDK_BDEV_IO_STATUS_SUCCESS;
38760bd6b7f2SJonas Pfefferle 
38770bd6b7f2SJonas Pfefferle 	offset = 50;
38780bd6b7f2SJonas Pfefferle 	num_blocks = 2;
38790bd6b7f2SJonas Pfefferle 
38800bd6b7f2SJonas Pfefferle 	/* interleaved md & data */
38810bd6b7f2SJonas Pfefferle 	bdev->md_interleave = true;
38820bd6b7f2SJonas Pfefferle 	bdev->md_len = 8;
38830bd6b7f2SJonas Pfefferle 	bdev->blocklen = 512 + 8;
38840bd6b7f2SJonas Pfefferle 	compare_iov.iov_base = buf;
38850bd6b7f2SJonas Pfefferle 	compare_iov.iov_len = sizeof(buf);
38860bd6b7f2SJonas Pfefferle 
38870bd6b7f2SJonas Pfefferle 	/* 1. successful compare with md interleaved */
38880bd6b7f2SJonas Pfefferle 	expected_io = ut_alloc_expected_io(expected_io_type, offset, num_blocks, 0);
38890bd6b7f2SJonas Pfefferle 	TAILQ_INSERT_TAIL(&g_bdev_ut_channel->expected_io, expected_io, link);
38900bd6b7f2SJonas Pfefferle 
38910bd6b7f2SJonas Pfefferle 	g_io_done = false;
38920bd6b7f2SJonas Pfefferle 	g_compare_read_buf = buf;
38930bd6b7f2SJonas Pfefferle 	g_compare_read_buf_len = sizeof(buf);
38940bd6b7f2SJonas Pfefferle 	rc = spdk_bdev_comparev_blocks(desc, ioch, &compare_iov, 1, offset, num_blocks, io_done, NULL);
38950bd6b7f2SJonas Pfefferle 	CU_ASSERT_EQUAL(rc, 0);
38960bd6b7f2SJonas Pfefferle 	num_completed = stub_complete_io(1);
38970bd6b7f2SJonas Pfefferle 	CU_ASSERT_EQUAL(num_completed, 1);
38980bd6b7f2SJonas Pfefferle 	CU_ASSERT(g_io_done == true);
38990bd6b7f2SJonas Pfefferle 	CU_ASSERT(g_io_status == SPDK_BDEV_IO_STATUS_SUCCESS);
39000bd6b7f2SJonas Pfefferle 
39010bd6b7f2SJonas Pfefferle 	/* 2. miscompare with md interleaved */
39020bd6b7f2SJonas Pfefferle 	expected_io = ut_alloc_expected_io(expected_io_type, offset, num_blocks, 0);
39030bd6b7f2SJonas Pfefferle 	TAILQ_INSERT_TAIL(&g_bdev_ut_channel->expected_io, expected_io, link);
39040bd6b7f2SJonas Pfefferle 
39050bd6b7f2SJonas Pfefferle 	g_io_done = false;
39060bd6b7f2SJonas Pfefferle 	g_compare_read_buf = buf_interleaved_miscompare;
39070bd6b7f2SJonas Pfefferle 	g_compare_read_buf_len = sizeof(buf_interleaved_miscompare);
39080bd6b7f2SJonas Pfefferle 	rc = spdk_bdev_comparev_blocks(desc, ioch, &compare_iov, 1, offset, num_blocks, io_done, NULL);
39090bd6b7f2SJonas Pfefferle 	CU_ASSERT_EQUAL(rc, 0);
39100bd6b7f2SJonas Pfefferle 	num_completed = stub_complete_io(1);
39110bd6b7f2SJonas Pfefferle 	CU_ASSERT_EQUAL(num_completed, 1);
39120bd6b7f2SJonas Pfefferle 	CU_ASSERT(g_io_done == true);
39130bd6b7f2SJonas Pfefferle 	CU_ASSERT(g_io_status == SPDK_BDEV_IO_STATUS_MISCOMPARE);
39140bd6b7f2SJonas Pfefferle 
39150bd6b7f2SJonas Pfefferle 	/* Separate data & md buffers */
39160bd6b7f2SJonas Pfefferle 	bdev->md_interleave = false;
39170bd6b7f2SJonas Pfefferle 	bdev->blocklen = 512;
39180bd6b7f2SJonas Pfefferle 	compare_iov.iov_base = buf;
39190bd6b7f2SJonas Pfefferle 	compare_iov.iov_len = 1024;
39200bd6b7f2SJonas Pfefferle 
39210bd6b7f2SJonas Pfefferle 	/* 3. successful compare with md separated */
39220bd6b7f2SJonas Pfefferle 	expected_io = ut_alloc_expected_io(expected_io_type, offset, num_blocks, 0);
39230bd6b7f2SJonas Pfefferle 	TAILQ_INSERT_TAIL(&g_bdev_ut_channel->expected_io, expected_io, link);
39240bd6b7f2SJonas Pfefferle 
39250bd6b7f2SJonas Pfefferle 	g_io_done = false;
39260bd6b7f2SJonas Pfefferle 	g_compare_read_buf = buf;
39270bd6b7f2SJonas Pfefferle 	g_compare_read_buf_len = 1024;
39280bd6b7f2SJonas Pfefferle 	g_io_exp_status = SPDK_BDEV_IO_STATUS_SUCCESS;
39290bd6b7f2SJonas Pfefferle 	g_compare_md_buf = md_buf;
39300bd6b7f2SJonas Pfefferle 	rc = spdk_bdev_comparev_blocks_with_md(desc, ioch, &compare_iov, 1, md_buf,
39310bd6b7f2SJonas Pfefferle 					       offset, num_blocks, io_done, NULL);
39320bd6b7f2SJonas Pfefferle 	CU_ASSERT_EQUAL(rc, 0);
39330bd6b7f2SJonas Pfefferle 	num_completed = stub_complete_io(1);
39340bd6b7f2SJonas Pfefferle 	CU_ASSERT_EQUAL(num_completed, 1);
39350bd6b7f2SJonas Pfefferle 	CU_ASSERT(g_io_done == true);
39360bd6b7f2SJonas Pfefferle 	CU_ASSERT(g_io_status == SPDK_BDEV_IO_STATUS_SUCCESS);
39370bd6b7f2SJonas Pfefferle 
39380bd6b7f2SJonas Pfefferle 	/* 4. miscompare with md separated where md buf is different */
39390bd6b7f2SJonas Pfefferle 	expected_io = ut_alloc_expected_io(expected_io_type, offset, num_blocks, 0);
39400bd6b7f2SJonas Pfefferle 	TAILQ_INSERT_TAIL(&g_bdev_ut_channel->expected_io, expected_io, link);
39410bd6b7f2SJonas Pfefferle 
39420bd6b7f2SJonas Pfefferle 	g_io_done = false;
39430bd6b7f2SJonas Pfefferle 	g_compare_read_buf = buf;
39440bd6b7f2SJonas Pfefferle 	g_compare_read_buf_len = 1024;
39450bd6b7f2SJonas Pfefferle 	g_compare_md_buf = md_buf_miscompare;
39460bd6b7f2SJonas Pfefferle 	rc = spdk_bdev_comparev_blocks_with_md(desc, ioch, &compare_iov, 1, md_buf,
39470bd6b7f2SJonas Pfefferle 					       offset, num_blocks, io_done, NULL);
39480bd6b7f2SJonas Pfefferle 	CU_ASSERT_EQUAL(rc, 0);
39490bd6b7f2SJonas Pfefferle 	num_completed = stub_complete_io(1);
39500bd6b7f2SJonas Pfefferle 	CU_ASSERT_EQUAL(num_completed, 1);
39510bd6b7f2SJonas Pfefferle 	CU_ASSERT(g_io_done == true);
39520bd6b7f2SJonas Pfefferle 	CU_ASSERT(g_io_status == SPDK_BDEV_IO_STATUS_MISCOMPARE);
39530bd6b7f2SJonas Pfefferle 
39540bd6b7f2SJonas Pfefferle 	/* 5. miscompare with md separated where buf is different */
39550bd6b7f2SJonas Pfefferle 	expected_io = ut_alloc_expected_io(expected_io_type, offset, num_blocks, 0);
39560bd6b7f2SJonas Pfefferle 	TAILQ_INSERT_TAIL(&g_bdev_ut_channel->expected_io, expected_io, link);
39570bd6b7f2SJonas Pfefferle 
39580bd6b7f2SJonas Pfefferle 	g_io_done = false;
39590bd6b7f2SJonas Pfefferle 	g_compare_read_buf = buf_miscompare;
39600bd6b7f2SJonas Pfefferle 	g_compare_read_buf_len = sizeof(buf_miscompare);
39610bd6b7f2SJonas Pfefferle 	g_compare_md_buf = md_buf;
39620bd6b7f2SJonas Pfefferle 	rc = spdk_bdev_comparev_blocks_with_md(desc, ioch, &compare_iov, 1, md_buf,
39630bd6b7f2SJonas Pfefferle 					       offset, num_blocks, io_done, NULL);
39640bd6b7f2SJonas Pfefferle 	CU_ASSERT_EQUAL(rc, 0);
39650bd6b7f2SJonas Pfefferle 	num_completed = stub_complete_io(1);
39660bd6b7f2SJonas Pfefferle 	CU_ASSERT_EQUAL(num_completed, 1);
39670bd6b7f2SJonas Pfefferle 	CU_ASSERT(g_io_done == true);
39680bd6b7f2SJonas Pfefferle 	CU_ASSERT(g_io_status == SPDK_BDEV_IO_STATUS_MISCOMPARE);
39690bd6b7f2SJonas Pfefferle 
39700bd6b7f2SJonas Pfefferle 	bdev->md_len = 0;
39710bd6b7f2SJonas Pfefferle 	g_compare_md_buf = NULL;
39720bd6b7f2SJonas Pfefferle 
39730bd6b7f2SJonas Pfefferle 	spdk_put_io_channel(ioch);
39740bd6b7f2SJonas Pfefferle 	spdk_bdev_close(desc);
39750bd6b7f2SJonas Pfefferle 	free_bdev(bdev);
39760bd6b7f2SJonas Pfefferle 	fn_table.submit_request = stub_submit_request;
3977107741fcSKonrad Sztyber 	ut_fini_bdev();
39780bd6b7f2SJonas Pfefferle 
39790bd6b7f2SJonas Pfefferle 	g_io_types_supported[SPDK_BDEV_IO_TYPE_COMPARE] = true;
39800bd6b7f2SJonas Pfefferle 
39810bd6b7f2SJonas Pfefferle 	g_compare_read_buf = NULL;
39820bd6b7f2SJonas Pfefferle }
39830bd6b7f2SJonas Pfefferle 
39840bd6b7f2SJonas Pfefferle static void
39853eda8bf6SMaciej Szwed bdev_compare(void)
39863eda8bf6SMaciej Szwed {
3987ca0eeaabSMaciej Szwed 	_bdev_compare(false);
39880bd6b7f2SJonas Pfefferle 	_bdev_compare_with_md(false);
39890bd6b7f2SJonas Pfefferle }
39900bd6b7f2SJonas Pfefferle 
39910bd6b7f2SJonas Pfefferle static void
39920bd6b7f2SJonas Pfefferle bdev_compare_emulated(void)
39930bd6b7f2SJonas Pfefferle {
39940bd6b7f2SJonas Pfefferle 	_bdev_compare(true);
39950bd6b7f2SJonas Pfefferle 	_bdev_compare_with_md(true);
39963eda8bf6SMaciej Szwed }
39973eda8bf6SMaciej Szwed 
39983eda8bf6SMaciej Szwed static void
3999ae43c81aSJim Harris bdev_compare_and_write(void)
4000ae43c81aSJim Harris {
4001ae43c81aSJim Harris 	struct spdk_bdev *bdev;
4002ae43c81aSJim Harris 	struct spdk_bdev_desc *desc = NULL;
4003ae43c81aSJim Harris 	struct spdk_io_channel *ioch;
4004ae43c81aSJim Harris 	struct ut_expected_io *expected_io;
4005ae43c81aSJim Harris 	uint64_t offset, num_blocks;
4006ae43c81aSJim Harris 	uint32_t num_completed;
4007ae43c81aSJim Harris 	char aa_buf[512];
4008ae43c81aSJim Harris 	char bb_buf[512];
4009ae43c81aSJim Harris 	char cc_buf[512];
4010ae43c81aSJim Harris 	char write_buf[512];
4011ae43c81aSJim Harris 	struct iovec compare_iov;
4012ae43c81aSJim Harris 	struct iovec write_iov;
4013ae43c81aSJim Harris 	int rc;
4014ae43c81aSJim Harris 
4015ae43c81aSJim Harris 	memset(aa_buf, 0xaa, sizeof(aa_buf));
4016ae43c81aSJim Harris 	memset(bb_buf, 0xbb, sizeof(bb_buf));
4017ae43c81aSJim Harris 	memset(cc_buf, 0xcc, sizeof(cc_buf));
4018ae43c81aSJim Harris 
4019bee042e4SMaciej Szwed 	g_io_types_supported[SPDK_BDEV_IO_TYPE_COMPARE] = false;
4020bee042e4SMaciej Szwed 
4021107741fcSKonrad Sztyber 	ut_init_bdev(NULL);
4022ae43c81aSJim Harris 	fn_table.submit_request = stub_submit_request_get_buf;
4023ae43c81aSJim Harris 	bdev = allocate_bdev("bdev");
4024ae43c81aSJim Harris 
402575dfecbbSShuhei Matsumoto 	rc = spdk_bdev_open_ext("bdev", true, bdev_ut_event_cb, NULL, &desc);
4026ae43c81aSJim Harris 	CU_ASSERT_EQUAL(rc, 0);
4027ae43c81aSJim Harris 	SPDK_CU_ASSERT_FATAL(desc != NULL);
402875dfecbbSShuhei Matsumoto 	CU_ASSERT(bdev == spdk_bdev_desc_get_bdev(desc));
4029ae43c81aSJim Harris 	ioch = spdk_bdev_get_io_channel(desc);
4030ae43c81aSJim Harris 	SPDK_CU_ASSERT_FATAL(ioch != NULL);
4031ae43c81aSJim Harris 
4032ae43c81aSJim Harris 	fn_table.submit_request = stub_submit_request_get_buf;
4033ae43c81aSJim Harris 	g_io_exp_status = SPDK_BDEV_IO_STATUS_SUCCESS;
4034ae43c81aSJim Harris 
4035ae43c81aSJim Harris 	offset = 50;
4036ae43c81aSJim Harris 	num_blocks = 1;
4037ae43c81aSJim Harris 	compare_iov.iov_base = aa_buf;
4038ae43c81aSJim Harris 	compare_iov.iov_len = sizeof(aa_buf);
4039ae43c81aSJim Harris 	write_iov.iov_base = bb_buf;
4040ae43c81aSJim Harris 	write_iov.iov_len = sizeof(bb_buf);
4041ae43c81aSJim Harris 
4042ae43c81aSJim Harris 	expected_io = ut_alloc_expected_io(SPDK_BDEV_IO_TYPE_READ, offset, num_blocks, 0);
4043ae43c81aSJim Harris 	TAILQ_INSERT_TAIL(&g_bdev_ut_channel->expected_io, expected_io, link);
4044ae43c81aSJim Harris 	expected_io = ut_alloc_expected_io(SPDK_BDEV_IO_TYPE_WRITE, offset, num_blocks, 0);
4045ae43c81aSJim Harris 	TAILQ_INSERT_TAIL(&g_bdev_ut_channel->expected_io, expected_io, link);
4046ae43c81aSJim Harris 
4047ae43c81aSJim Harris 	g_io_done = false;
4048ae43c81aSJim Harris 	g_compare_read_buf = aa_buf;
4049ae43c81aSJim Harris 	g_compare_read_buf_len = sizeof(aa_buf);
4050ae43c81aSJim Harris 	memset(write_buf, 0, sizeof(write_buf));
4051ae43c81aSJim Harris 	g_compare_write_buf = write_buf;
4052ae43c81aSJim Harris 	g_compare_write_buf_len = sizeof(write_buf);
4053ae43c81aSJim Harris 	rc = spdk_bdev_comparev_and_writev_blocks(desc, ioch, &compare_iov, 1, &write_iov, 1,
4054ae43c81aSJim Harris 			offset, num_blocks, io_done, NULL);
4055a83644feSMaciej Szwed 	/* Trigger range locking */
4056a83644feSMaciej Szwed 	poll_threads();
4057ae43c81aSJim Harris 	CU_ASSERT_EQUAL(rc, 0);
4058ae43c81aSJim Harris 	num_completed = stub_complete_io(1);
4059ae43c81aSJim Harris 	CU_ASSERT_EQUAL(num_completed, 1);
4060ae43c81aSJim Harris 	CU_ASSERT(g_io_done == false);
4061ae43c81aSJim Harris 	num_completed = stub_complete_io(1);
4062a83644feSMaciej Szwed 	/* Trigger range unlocking */
4063a83644feSMaciej Szwed 	poll_threads();
4064ae43c81aSJim Harris 	CU_ASSERT_EQUAL(num_completed, 1);
4065ae43c81aSJim Harris 	CU_ASSERT(g_io_done == true);
4066ae43c81aSJim Harris 	CU_ASSERT(g_io_status == SPDK_BDEV_IO_STATUS_SUCCESS);
4067ae43c81aSJim Harris 	CU_ASSERT(memcmp(write_buf, bb_buf, sizeof(write_buf)) == 0);
4068ae43c81aSJim Harris 
4069442e13c0SJonas Pfefferle 	/* Test miscompare */
4070ae43c81aSJim Harris 	expected_io = ut_alloc_expected_io(SPDK_BDEV_IO_TYPE_READ, offset, num_blocks, 0);
4071ae43c81aSJim Harris 	TAILQ_INSERT_TAIL(&g_bdev_ut_channel->expected_io, expected_io, link);
4072ae43c81aSJim Harris 
4073ae43c81aSJim Harris 	g_io_done = false;
4074ae43c81aSJim Harris 	g_compare_read_buf = cc_buf;
4075ae43c81aSJim Harris 	g_compare_read_buf_len = sizeof(cc_buf);
4076ae43c81aSJim Harris 	memset(write_buf, 0, sizeof(write_buf));
4077ae43c81aSJim Harris 	g_compare_write_buf = write_buf;
4078ae43c81aSJim Harris 	g_compare_write_buf_len = sizeof(write_buf);
4079ae43c81aSJim Harris 	rc = spdk_bdev_comparev_and_writev_blocks(desc, ioch, &compare_iov, 1, &write_iov, 1,
4080ae43c81aSJim Harris 			offset, num_blocks, io_done, NULL);
4081a83644feSMaciej Szwed 	/* Trigger range locking */
4082a83644feSMaciej Szwed 	poll_threads();
4083ae43c81aSJim Harris 	CU_ASSERT_EQUAL(rc, 0);
4084ae43c81aSJim Harris 	num_completed = stub_complete_io(1);
4085a83644feSMaciej Szwed 	/* Trigger range unlocking earlier because we expect error here */
4086a83644feSMaciej Szwed 	poll_threads();
4087ae43c81aSJim Harris 	CU_ASSERT_EQUAL(num_completed, 1);
4088ae43c81aSJim Harris 	CU_ASSERT(g_io_done == true);
4089ae43c81aSJim Harris 	CU_ASSERT(g_io_status == SPDK_BDEV_IO_STATUS_MISCOMPARE);
4090ae43c81aSJim Harris 	num_completed = stub_complete_io(1);
4091ae43c81aSJim Harris 	CU_ASSERT_EQUAL(num_completed, 0);
4092ae43c81aSJim Harris 
4093ae43c81aSJim Harris 	spdk_put_io_channel(ioch);
4094ae43c81aSJim Harris 	spdk_bdev_close(desc);
4095ae43c81aSJim Harris 	free_bdev(bdev);
4096ae43c81aSJim Harris 	fn_table.submit_request = stub_submit_request;
4097107741fcSKonrad Sztyber 	ut_fini_bdev();
4098ae43c81aSJim Harris 
4099bee042e4SMaciej Szwed 	g_io_types_supported[SPDK_BDEV_IO_TYPE_COMPARE] = true;
4100bee042e4SMaciej Szwed 
4101ae43c81aSJim Harris 	g_compare_read_buf = NULL;
4102ae43c81aSJim Harris 	g_compare_write_buf = NULL;
4103ae43c81aSJim Harris }
4104ae43c81aSJim Harris 
4105ae43c81aSJim Harris static void
4106e2918289SKonrad Sztyber bdev_write_zeroes(void)
4107e2918289SKonrad Sztyber {
4108e2918289SKonrad Sztyber 	struct spdk_bdev *bdev;
4109e2918289SKonrad Sztyber 	struct spdk_bdev_desc *desc = NULL;
4110e2918289SKonrad Sztyber 	struct spdk_io_channel *ioch;
4111e2918289SKonrad Sztyber 	struct ut_expected_io *expected_io;
4112e2918289SKonrad Sztyber 	uint64_t offset, num_io_blocks, num_blocks;
4113e2918289SKonrad Sztyber 	uint32_t num_completed, num_requests;
4114e2918289SKonrad Sztyber 	int rc;
4115e2918289SKonrad Sztyber 
4116107741fcSKonrad Sztyber 	ut_init_bdev(NULL);
4117e2918289SKonrad Sztyber 	bdev = allocate_bdev("bdev");
4118e2918289SKonrad Sztyber 
411975dfecbbSShuhei Matsumoto 	rc = spdk_bdev_open_ext("bdev", true, bdev_ut_event_cb, NULL, &desc);
4120e2918289SKonrad Sztyber 	CU_ASSERT_EQUAL(rc, 0);
4121e2918289SKonrad Sztyber 	SPDK_CU_ASSERT_FATAL(desc != NULL);
412275dfecbbSShuhei Matsumoto 	CU_ASSERT(bdev == spdk_bdev_desc_get_bdev(desc));
4123e2918289SKonrad Sztyber 	ioch = spdk_bdev_get_io_channel(desc);
4124e2918289SKonrad Sztyber 	SPDK_CU_ASSERT_FATAL(ioch != NULL);
4125e2918289SKonrad Sztyber 
4126e2918289SKonrad Sztyber 	fn_table.submit_request = stub_submit_request;
4127e2918289SKonrad Sztyber 	g_io_exp_status = SPDK_BDEV_IO_STATUS_SUCCESS;
4128e2918289SKonrad Sztyber 
4129e2918289SKonrad Sztyber 	/* First test that if the bdev supports write_zeroes, the request won't be split */
4130e2918289SKonrad Sztyber 	bdev->md_len = 0;
4131e2918289SKonrad Sztyber 	bdev->blocklen = 4096;
4132e2918289SKonrad Sztyber 	num_blocks = (ZERO_BUFFER_SIZE / bdev->blocklen) * 2;
4133e2918289SKonrad Sztyber 
4134e2918289SKonrad Sztyber 	expected_io = ut_alloc_expected_io(SPDK_BDEV_IO_TYPE_WRITE_ZEROES, 0, num_blocks, 0);
4135e2918289SKonrad Sztyber 	TAILQ_INSERT_TAIL(&g_bdev_ut_channel->expected_io, expected_io, link);
4136e2918289SKonrad Sztyber 	rc = spdk_bdev_write_zeroes_blocks(desc, ioch, 0, num_blocks, io_done, NULL);
4137e2918289SKonrad Sztyber 	CU_ASSERT_EQUAL(rc, 0);
4138e2918289SKonrad Sztyber 	num_completed = stub_complete_io(1);
4139e2918289SKonrad Sztyber 	CU_ASSERT_EQUAL(num_completed, 1);
4140e2918289SKonrad Sztyber 
4141e2918289SKonrad Sztyber 	/* Check that if write zeroes is not supported it'll be replaced by regular writes */
4142e2918289SKonrad Sztyber 	ut_enable_io_type(SPDK_BDEV_IO_TYPE_WRITE_ZEROES, false);
4143af92c28bSShuhei Matsumoto 	bdev->max_write_zeroes = bdev_get_max_write(bdev, ZERO_BUFFER_SIZE);
4144e2918289SKonrad Sztyber 	num_io_blocks = ZERO_BUFFER_SIZE / bdev->blocklen;
4145e2918289SKonrad Sztyber 	num_requests = 2;
4146e2918289SKonrad Sztyber 	num_blocks = (ZERO_BUFFER_SIZE / bdev->blocklen) * num_requests;
4147e2918289SKonrad Sztyber 
4148e2918289SKonrad Sztyber 	for (offset = 0; offset < num_requests; ++offset) {
4149e2918289SKonrad Sztyber 		expected_io = ut_alloc_expected_io(SPDK_BDEV_IO_TYPE_WRITE,
4150e2918289SKonrad Sztyber 						   offset * num_io_blocks, num_io_blocks, 0);
4151e2918289SKonrad Sztyber 		TAILQ_INSERT_TAIL(&g_bdev_ut_channel->expected_io, expected_io, link);
4152e2918289SKonrad Sztyber 	}
4153e2918289SKonrad Sztyber 
4154e2918289SKonrad Sztyber 	rc = spdk_bdev_write_zeroes_blocks(desc, ioch, 0, num_blocks, io_done, NULL);
4155e2918289SKonrad Sztyber 	CU_ASSERT_EQUAL(rc, 0);
4156e2918289SKonrad Sztyber 	num_completed = stub_complete_io(num_requests);
4157e2918289SKonrad Sztyber 	CU_ASSERT_EQUAL(num_completed, num_requests);
4158e2918289SKonrad Sztyber 
4159e2918289SKonrad Sztyber 	/* Check that the splitting is correct if bdev has interleaved metadata */
4160e2918289SKonrad Sztyber 	bdev->md_interleave = true;
4161e2918289SKonrad Sztyber 	bdev->md_len = 64;
4162e2918289SKonrad Sztyber 	bdev->blocklen = 4096 + 64;
4163af92c28bSShuhei Matsumoto 	bdev->max_write_zeroes = bdev_get_max_write(bdev, ZERO_BUFFER_SIZE);
4164e2918289SKonrad Sztyber 	num_blocks = (ZERO_BUFFER_SIZE / bdev->blocklen) * 2;
4165e2918289SKonrad Sztyber 
4166e2918289SKonrad Sztyber 	num_requests = offset = 0;
4167e2918289SKonrad Sztyber 	while (offset < num_blocks) {
4168e2918289SKonrad Sztyber 		num_io_blocks = spdk_min(ZERO_BUFFER_SIZE / bdev->blocklen, num_blocks - offset);
4169e2918289SKonrad Sztyber 		expected_io = ut_alloc_expected_io(SPDK_BDEV_IO_TYPE_WRITE,
4170e2918289SKonrad Sztyber 						   offset, num_io_blocks, 0);
4171e2918289SKonrad Sztyber 		TAILQ_INSERT_TAIL(&g_bdev_ut_channel->expected_io, expected_io, link);
4172e2918289SKonrad Sztyber 		offset += num_io_blocks;
4173e2918289SKonrad Sztyber 		num_requests++;
4174e2918289SKonrad Sztyber 	}
4175e2918289SKonrad Sztyber 
4176e2918289SKonrad Sztyber 	rc = spdk_bdev_write_zeroes_blocks(desc, ioch, 0, num_blocks, io_done, NULL);
4177e2918289SKonrad Sztyber 	CU_ASSERT_EQUAL(rc, 0);
4178e2918289SKonrad Sztyber 	num_completed = stub_complete_io(num_requests);
4179e2918289SKonrad Sztyber 	CU_ASSERT_EQUAL(num_completed, num_requests);
4180e2918289SKonrad Sztyber 	num_completed = stub_complete_io(num_requests);
4181e2918289SKonrad Sztyber 	assert(num_completed == 0);
4182e2918289SKonrad Sztyber 
4183e2918289SKonrad Sztyber 	/* Check the the same for separate metadata buffer */
4184e2918289SKonrad Sztyber 	bdev->md_interleave = false;
4185e2918289SKonrad Sztyber 	bdev->md_len = 64;
4186e2918289SKonrad Sztyber 	bdev->blocklen = 4096;
4187af92c28bSShuhei Matsumoto 	bdev->max_write_zeroes = bdev_get_max_write(bdev, ZERO_BUFFER_SIZE);
4188e2918289SKonrad Sztyber 
4189e2918289SKonrad Sztyber 	num_requests = offset = 0;
4190e2918289SKonrad Sztyber 	while (offset < num_blocks) {
4191e2918289SKonrad Sztyber 		num_io_blocks = spdk_min(ZERO_BUFFER_SIZE / (bdev->blocklen + bdev->md_len), num_blocks);
4192e2918289SKonrad Sztyber 		expected_io = ut_alloc_expected_io(SPDK_BDEV_IO_TYPE_WRITE,
4193e2918289SKonrad Sztyber 						   offset, num_io_blocks, 0);
4194e2918289SKonrad Sztyber 		expected_io->md_buf = (char *)g_bdev_mgr.zero_buffer + num_io_blocks * bdev->blocklen;
4195e2918289SKonrad Sztyber 		TAILQ_INSERT_TAIL(&g_bdev_ut_channel->expected_io, expected_io, link);
4196e2918289SKonrad Sztyber 		offset += num_io_blocks;
4197e2918289SKonrad Sztyber 		num_requests++;
4198e2918289SKonrad Sztyber 	}
4199e2918289SKonrad Sztyber 
4200e2918289SKonrad Sztyber 	rc = spdk_bdev_write_zeroes_blocks(desc, ioch, 0, num_blocks, io_done, NULL);
4201e2918289SKonrad Sztyber 	CU_ASSERT_EQUAL(rc, 0);
4202e2918289SKonrad Sztyber 	num_completed = stub_complete_io(num_requests);
4203e2918289SKonrad Sztyber 	CU_ASSERT_EQUAL(num_completed, num_requests);
4204e2918289SKonrad Sztyber 
4205e2918289SKonrad Sztyber 	ut_enable_io_type(SPDK_BDEV_IO_TYPE_WRITE_ZEROES, true);
4206e2918289SKonrad Sztyber 	spdk_put_io_channel(ioch);
4207e2918289SKonrad Sztyber 	spdk_bdev_close(desc);
4208e2918289SKonrad Sztyber 	free_bdev(bdev);
4209107741fcSKonrad Sztyber 	ut_fini_bdev();
4210e2918289SKonrad Sztyber }
4211e2918289SKonrad Sztyber 
4212c141bd94SMaciej Szwed static void
42136127461cSmatthewb bdev_zcopy_write(void)
42146127461cSmatthewb {
42156127461cSmatthewb 	struct spdk_bdev *bdev;
42166127461cSmatthewb 	struct spdk_bdev_desc *desc = NULL;
42176127461cSmatthewb 	struct spdk_io_channel *ioch;
42186127461cSmatthewb 	struct ut_expected_io *expected_io;
42196127461cSmatthewb 	uint64_t offset, num_blocks;
42206127461cSmatthewb 	uint32_t num_completed;
42216127461cSmatthewb 	char aa_buf[512];
42226127461cSmatthewb 	struct iovec iov;
42236127461cSmatthewb 	int rc;
42246127461cSmatthewb 	const bool populate = false;
42256127461cSmatthewb 	const bool commit = true;
42266127461cSmatthewb 
42276127461cSmatthewb 	memset(aa_buf, 0xaa, sizeof(aa_buf));
42286127461cSmatthewb 
4229107741fcSKonrad Sztyber 	ut_init_bdev(NULL);
42306127461cSmatthewb 	bdev = allocate_bdev("bdev");
42316127461cSmatthewb 
42326127461cSmatthewb 	rc = spdk_bdev_open_ext("bdev", true, bdev_ut_event_cb, NULL, &desc);
42336127461cSmatthewb 	CU_ASSERT_EQUAL(rc, 0);
42346127461cSmatthewb 	SPDK_CU_ASSERT_FATAL(desc != NULL);
42356127461cSmatthewb 	CU_ASSERT(bdev == spdk_bdev_desc_get_bdev(desc));
42366127461cSmatthewb 	ioch = spdk_bdev_get_io_channel(desc);
42376127461cSmatthewb 	SPDK_CU_ASSERT_FATAL(ioch != NULL);
42386127461cSmatthewb 
42396127461cSmatthewb 	g_io_exp_status = SPDK_BDEV_IO_STATUS_SUCCESS;
42406127461cSmatthewb 
42416127461cSmatthewb 	offset = 50;
42426127461cSmatthewb 	num_blocks = 1;
42436127461cSmatthewb 	iov.iov_base = NULL;
42446127461cSmatthewb 	iov.iov_len = 0;
42456127461cSmatthewb 
42466127461cSmatthewb 	g_zcopy_read_buf = (void *) 0x1122334455667788UL;
42476127461cSmatthewb 	g_zcopy_read_buf_len = (uint32_t) -1;
42486127461cSmatthewb 	/* Do a zcopy start for a write (populate=false) */
42496127461cSmatthewb 	expected_io = ut_alloc_expected_io(SPDK_BDEV_IO_TYPE_ZCOPY, offset, num_blocks, 0);
42506127461cSmatthewb 	TAILQ_INSERT_TAIL(&g_bdev_ut_channel->expected_io, expected_io, link);
42516127461cSmatthewb 	g_io_done = false;
42526127461cSmatthewb 	g_zcopy_write_buf = aa_buf;
42536127461cSmatthewb 	g_zcopy_write_buf_len = sizeof(aa_buf);
42546127461cSmatthewb 	g_zcopy_bdev_io = NULL;
42556127461cSmatthewb 	rc = spdk_bdev_zcopy_start(desc, ioch, &iov, 1, offset, num_blocks, populate, io_done, NULL);
42566127461cSmatthewb 	CU_ASSERT_EQUAL(rc, 0);
42576127461cSmatthewb 	num_completed = stub_complete_io(1);
42586127461cSmatthewb 	CU_ASSERT_EQUAL(num_completed, 1);
42596127461cSmatthewb 	CU_ASSERT(g_io_done == true);
42606127461cSmatthewb 	CU_ASSERT(g_io_status == SPDK_BDEV_IO_STATUS_SUCCESS);
42616127461cSmatthewb 	/* Check that the iov has been set up */
42626127461cSmatthewb 	CU_ASSERT(iov.iov_base == g_zcopy_write_buf);
42636127461cSmatthewb 	CU_ASSERT(iov.iov_len == g_zcopy_write_buf_len);
42646127461cSmatthewb 	/* Check that the bdev_io has been saved */
42656127461cSmatthewb 	CU_ASSERT(g_zcopy_bdev_io != NULL);
42666127461cSmatthewb 	/* Now do the zcopy end for a write (commit=true) */
42676127461cSmatthewb 	g_io_done = false;
42686127461cSmatthewb 	expected_io = ut_alloc_expected_io(SPDK_BDEV_IO_TYPE_ZCOPY, offset, num_blocks, 0);
42696127461cSmatthewb 	TAILQ_INSERT_TAIL(&g_bdev_ut_channel->expected_io, expected_io, link);
42706127461cSmatthewb 	rc = spdk_bdev_zcopy_end(g_zcopy_bdev_io, commit, io_done, NULL);
42716127461cSmatthewb 	CU_ASSERT_EQUAL(rc, 0);
42726127461cSmatthewb 	num_completed = stub_complete_io(1);
42736127461cSmatthewb 	CU_ASSERT_EQUAL(num_completed, 1);
42746127461cSmatthewb 	CU_ASSERT(g_io_done == true);
42756127461cSmatthewb 	CU_ASSERT(g_io_status == SPDK_BDEV_IO_STATUS_SUCCESS);
42766127461cSmatthewb 	/* Check the g_zcopy are reset by io_done */
42776127461cSmatthewb 	CU_ASSERT(g_zcopy_write_buf == NULL);
42786127461cSmatthewb 	CU_ASSERT(g_zcopy_write_buf_len == 0);
42796127461cSmatthewb 	/* Check that io_done has freed the g_zcopy_bdev_io */
42806127461cSmatthewb 	CU_ASSERT(g_zcopy_bdev_io == NULL);
42816127461cSmatthewb 
42826127461cSmatthewb 	/* Check the zcopy read buffer has not been touched which
42836127461cSmatthewb 	 * ensures that the correct buffers were used.
42846127461cSmatthewb 	 */
42856127461cSmatthewb 	CU_ASSERT(g_zcopy_read_buf == (void *) 0x1122334455667788UL);
42866127461cSmatthewb 	CU_ASSERT(g_zcopy_read_buf_len == (uint32_t) -1);
42876127461cSmatthewb 
42886127461cSmatthewb 	spdk_put_io_channel(ioch);
42896127461cSmatthewb 	spdk_bdev_close(desc);
42906127461cSmatthewb 	free_bdev(bdev);
4291107741fcSKonrad Sztyber 	ut_fini_bdev();
42926127461cSmatthewb }
42936127461cSmatthewb 
42946127461cSmatthewb static void
42956127461cSmatthewb bdev_zcopy_read(void)
42966127461cSmatthewb {
42976127461cSmatthewb 	struct spdk_bdev *bdev;
42986127461cSmatthewb 	struct spdk_bdev_desc *desc = NULL;
42996127461cSmatthewb 	struct spdk_io_channel *ioch;
43006127461cSmatthewb 	struct ut_expected_io *expected_io;
43016127461cSmatthewb 	uint64_t offset, num_blocks;
43026127461cSmatthewb 	uint32_t num_completed;
43036127461cSmatthewb 	char aa_buf[512];
43046127461cSmatthewb 	struct iovec iov;
43056127461cSmatthewb 	int rc;
43066127461cSmatthewb 	const bool populate = true;
43076127461cSmatthewb 	const bool commit = false;
43086127461cSmatthewb 
43096127461cSmatthewb 	memset(aa_buf, 0xaa, sizeof(aa_buf));
43106127461cSmatthewb 
4311107741fcSKonrad Sztyber 	ut_init_bdev(NULL);
43126127461cSmatthewb 	bdev = allocate_bdev("bdev");
43136127461cSmatthewb 
43146127461cSmatthewb 	rc = spdk_bdev_open_ext("bdev", true, bdev_ut_event_cb, NULL, &desc);
43156127461cSmatthewb 	CU_ASSERT_EQUAL(rc, 0);
43166127461cSmatthewb 	SPDK_CU_ASSERT_FATAL(desc != NULL);
43176127461cSmatthewb 	CU_ASSERT(bdev == spdk_bdev_desc_get_bdev(desc));
43186127461cSmatthewb 	ioch = spdk_bdev_get_io_channel(desc);
43196127461cSmatthewb 	SPDK_CU_ASSERT_FATAL(ioch != NULL);
43206127461cSmatthewb 
43216127461cSmatthewb 	g_io_exp_status = SPDK_BDEV_IO_STATUS_SUCCESS;
43226127461cSmatthewb 
43236127461cSmatthewb 	offset = 50;
43246127461cSmatthewb 	num_blocks = 1;
43256127461cSmatthewb 	iov.iov_base = NULL;
43266127461cSmatthewb 	iov.iov_len = 0;
43276127461cSmatthewb 
43286127461cSmatthewb 	g_zcopy_write_buf = (void *) 0x1122334455667788UL;
43296127461cSmatthewb 	g_zcopy_write_buf_len = (uint32_t) -1;
43306127461cSmatthewb 
43316127461cSmatthewb 	/* Do a zcopy start for a read (populate=true) */
43326127461cSmatthewb 	expected_io = ut_alloc_expected_io(SPDK_BDEV_IO_TYPE_ZCOPY, offset, num_blocks, 0);
43336127461cSmatthewb 	TAILQ_INSERT_TAIL(&g_bdev_ut_channel->expected_io, expected_io, link);
43346127461cSmatthewb 	g_io_done = false;
43356127461cSmatthewb 	g_zcopy_read_buf = aa_buf;
43366127461cSmatthewb 	g_zcopy_read_buf_len = sizeof(aa_buf);
43376127461cSmatthewb 	g_zcopy_bdev_io = NULL;
43386127461cSmatthewb 	rc = spdk_bdev_zcopy_start(desc, ioch, &iov, 1, offset, num_blocks, populate, io_done, NULL);
43396127461cSmatthewb 	CU_ASSERT_EQUAL(rc, 0);
43406127461cSmatthewb 	num_completed = stub_complete_io(1);
43416127461cSmatthewb 	CU_ASSERT_EQUAL(num_completed, 1);
43426127461cSmatthewb 	CU_ASSERT(g_io_done == true);
43436127461cSmatthewb 	CU_ASSERT(g_io_status == SPDK_BDEV_IO_STATUS_SUCCESS);
43446127461cSmatthewb 	/* Check that the iov has been set up */
43456127461cSmatthewb 	CU_ASSERT(iov.iov_base == g_zcopy_read_buf);
43466127461cSmatthewb 	CU_ASSERT(iov.iov_len == g_zcopy_read_buf_len);
43476127461cSmatthewb 	/* Check that the bdev_io has been saved */
43486127461cSmatthewb 	CU_ASSERT(g_zcopy_bdev_io != NULL);
43496127461cSmatthewb 
43506127461cSmatthewb 	/* Now do the zcopy end for a read (commit=false) */
43516127461cSmatthewb 	g_io_done = false;
43526127461cSmatthewb 	expected_io = ut_alloc_expected_io(SPDK_BDEV_IO_TYPE_ZCOPY, offset, num_blocks, 0);
43536127461cSmatthewb 	TAILQ_INSERT_TAIL(&g_bdev_ut_channel->expected_io, expected_io, link);
43546127461cSmatthewb 	rc = spdk_bdev_zcopy_end(g_zcopy_bdev_io, commit, io_done, NULL);
43556127461cSmatthewb 	CU_ASSERT_EQUAL(rc, 0);
43566127461cSmatthewb 	num_completed = stub_complete_io(1);
43576127461cSmatthewb 	CU_ASSERT_EQUAL(num_completed, 1);
43586127461cSmatthewb 	CU_ASSERT(g_io_done == true);
43596127461cSmatthewb 	CU_ASSERT(g_io_status == SPDK_BDEV_IO_STATUS_SUCCESS);
43606127461cSmatthewb 	/* Check the g_zcopy are reset by io_done */
43616127461cSmatthewb 	CU_ASSERT(g_zcopy_read_buf == NULL);
43626127461cSmatthewb 	CU_ASSERT(g_zcopy_read_buf_len == 0);
43636127461cSmatthewb 	/* Check that io_done has freed the g_zcopy_bdev_io */
43646127461cSmatthewb 	CU_ASSERT(g_zcopy_bdev_io == NULL);
43656127461cSmatthewb 
43666127461cSmatthewb 	/* Check the zcopy write buffer has not been touched which
43676127461cSmatthewb 	 * ensures that the correct buffers were used.
43686127461cSmatthewb 	 */
43696127461cSmatthewb 	CU_ASSERT(g_zcopy_write_buf == (void *) 0x1122334455667788UL);
43706127461cSmatthewb 	CU_ASSERT(g_zcopy_write_buf_len == (uint32_t) -1);
43716127461cSmatthewb 
43726127461cSmatthewb 	spdk_put_io_channel(ioch);
43736127461cSmatthewb 	spdk_bdev_close(desc);
43746127461cSmatthewb 	free_bdev(bdev);
4375107741fcSKonrad Sztyber 	ut_fini_bdev();
43766127461cSmatthewb }
43776127461cSmatthewb 
43786127461cSmatthewb static void
4379c141bd94SMaciej Szwed bdev_open_while_hotremove(void)
4380c141bd94SMaciej Szwed {
4381c141bd94SMaciej Szwed 	struct spdk_bdev *bdev;
4382c141bd94SMaciej Szwed 	struct spdk_bdev_desc *desc[2] = {};
4383c141bd94SMaciej Szwed 	int rc;
4384c141bd94SMaciej Szwed 
4385c141bd94SMaciej Szwed 	bdev = allocate_bdev("bdev");
4386c141bd94SMaciej Szwed 
438775dfecbbSShuhei Matsumoto 	rc = spdk_bdev_open_ext("bdev", false, bdev_ut_event_cb, NULL, &desc[0]);
4388c141bd94SMaciej Szwed 	CU_ASSERT(rc == 0);
4389c141bd94SMaciej Szwed 	SPDK_CU_ASSERT_FATAL(desc[0] != NULL);
439075dfecbbSShuhei Matsumoto 	CU_ASSERT(bdev == spdk_bdev_desc_get_bdev(desc[0]));
4391c141bd94SMaciej Szwed 
4392c141bd94SMaciej Szwed 	spdk_bdev_unregister(bdev, NULL, NULL);
43937bcd316dSGangCao 	/* Bdev unregister is handled asynchronously. Poll thread to complete. */
43947bcd316dSGangCao 	poll_threads();
4395c141bd94SMaciej Szwed 
439675dfecbbSShuhei Matsumoto 	rc = spdk_bdev_open_ext("bdev", false, bdev_ut_event_cb, NULL, &desc[1]);
4397c141bd94SMaciej Szwed 	CU_ASSERT(rc == -ENODEV);
4398c141bd94SMaciej Szwed 	SPDK_CU_ASSERT_FATAL(desc[1] == NULL);
4399c141bd94SMaciej Szwed 
4400c141bd94SMaciej Szwed 	spdk_bdev_close(desc[0]);
4401c141bd94SMaciej Szwed 	free_bdev(bdev);
4402c141bd94SMaciej Szwed }
4403c141bd94SMaciej Szwed 
440479ed1ba1SMaciej Szwed static void
440523975858SEvgeniy Kochetov bdev_close_while_hotremove(void)
440623975858SEvgeniy Kochetov {
440723975858SEvgeniy Kochetov 	struct spdk_bdev *bdev;
440823975858SEvgeniy Kochetov 	struct spdk_bdev_desc *desc = NULL;
440923975858SEvgeniy Kochetov 	int rc = 0;
441023975858SEvgeniy Kochetov 
441123975858SEvgeniy Kochetov 	bdev = allocate_bdev("bdev");
441223975858SEvgeniy Kochetov 
441323975858SEvgeniy Kochetov 	rc = spdk_bdev_open_ext("bdev", true, bdev_open_cb1, &desc, &desc);
441423975858SEvgeniy Kochetov 	CU_ASSERT_EQUAL(rc, 0);
441575dfecbbSShuhei Matsumoto 	SPDK_CU_ASSERT_FATAL(desc != NULL);
441675dfecbbSShuhei Matsumoto 	CU_ASSERT(bdev == spdk_bdev_desc_get_bdev(desc));
441723975858SEvgeniy Kochetov 
441823975858SEvgeniy Kochetov 	/* Simulate hot-unplug by unregistering bdev */
441923975858SEvgeniy Kochetov 	g_event_type1 = 0xFF;
442023975858SEvgeniy Kochetov 	g_unregister_arg = NULL;
442123975858SEvgeniy Kochetov 	g_unregister_rc = -1;
442223975858SEvgeniy Kochetov 	spdk_bdev_unregister(bdev, bdev_unregister_cb, (void *)0x12345678);
442323975858SEvgeniy Kochetov 	/* Close device while remove event is in flight */
442423975858SEvgeniy Kochetov 	spdk_bdev_close(desc);
442523975858SEvgeniy Kochetov 
442623975858SEvgeniy Kochetov 	/* Ensure that unregister callback is delayed */
442723975858SEvgeniy Kochetov 	CU_ASSERT_EQUAL(g_unregister_arg, NULL);
442823975858SEvgeniy Kochetov 	CU_ASSERT_EQUAL(g_unregister_rc, -1);
442923975858SEvgeniy Kochetov 
443023975858SEvgeniy Kochetov 	poll_threads();
443123975858SEvgeniy Kochetov 
443223975858SEvgeniy Kochetov 	/* Event callback shall not be issued because device was closed */
443323975858SEvgeniy Kochetov 	CU_ASSERT_EQUAL(g_event_type1, 0xFF);
443423975858SEvgeniy Kochetov 	/* Unregister callback is issued */
443523975858SEvgeniy Kochetov 	CU_ASSERT_EQUAL(g_unregister_arg, (void *)0x12345678);
443623975858SEvgeniy Kochetov 	CU_ASSERT_EQUAL(g_unregister_rc, 0);
443723975858SEvgeniy Kochetov 
443823975858SEvgeniy Kochetov 	free_bdev(bdev);
443923975858SEvgeniy Kochetov }
444023975858SEvgeniy Kochetov 
444123975858SEvgeniy Kochetov static void
44426e17adcbSShuhei Matsumoto bdev_open_ext_test(void)
444379ed1ba1SMaciej Szwed {
444479ed1ba1SMaciej Szwed 	struct spdk_bdev *bdev;
444579ed1ba1SMaciej Szwed 	struct spdk_bdev_desc *desc1 = NULL;
444679ed1ba1SMaciej Szwed 	struct spdk_bdev_desc *desc2 = NULL;
444779ed1ba1SMaciej Szwed 	int rc = 0;
444879ed1ba1SMaciej Szwed 
444979ed1ba1SMaciej Szwed 	bdev = allocate_bdev("bdev");
445079ed1ba1SMaciej Szwed 
445179ed1ba1SMaciej Szwed 	rc = spdk_bdev_open_ext("bdev", true, NULL, NULL, &desc1);
445279ed1ba1SMaciej Szwed 	CU_ASSERT_EQUAL(rc, -EINVAL);
445379ed1ba1SMaciej Szwed 
445479ed1ba1SMaciej Szwed 	rc = spdk_bdev_open_ext("bdev", true, bdev_open_cb1, &desc1, &desc1);
445579ed1ba1SMaciej Szwed 	CU_ASSERT_EQUAL(rc, 0);
445679ed1ba1SMaciej Szwed 
445779ed1ba1SMaciej Szwed 	rc = spdk_bdev_open_ext("bdev", true, bdev_open_cb2, &desc2, &desc2);
445879ed1ba1SMaciej Szwed 	CU_ASSERT_EQUAL(rc, 0);
445979ed1ba1SMaciej Szwed 
446079ed1ba1SMaciej Szwed 	g_event_type1 = 0xFF;
446179ed1ba1SMaciej Szwed 	g_event_type2 = 0xFF;
446279ed1ba1SMaciej Szwed 
446379ed1ba1SMaciej Szwed 	/* Simulate hot-unplug by unregistering bdev */
446479ed1ba1SMaciej Szwed 	spdk_bdev_unregister(bdev, NULL, NULL);
446579ed1ba1SMaciej Szwed 	poll_threads();
446679ed1ba1SMaciej Szwed 
446779ed1ba1SMaciej Szwed 	/* Check if correct events have been triggered in event callback fn */
446879ed1ba1SMaciej Szwed 	CU_ASSERT_EQUAL(g_event_type1, SPDK_BDEV_EVENT_REMOVE);
446979ed1ba1SMaciej Szwed 	CU_ASSERT_EQUAL(g_event_type2, SPDK_BDEV_EVENT_REMOVE);
447079ed1ba1SMaciej Szwed 
447179ed1ba1SMaciej Szwed 	free_bdev(bdev);
447279ed1ba1SMaciej Szwed 	poll_threads();
447379ed1ba1SMaciej Szwed }
447479ed1ba1SMaciej Szwed 
44757bcd316dSGangCao static void
44767bcd316dSGangCao bdev_open_ext_unregister(void)
44777bcd316dSGangCao {
44787bcd316dSGangCao 	struct spdk_bdev *bdev;
44797bcd316dSGangCao 	struct spdk_bdev_desc *desc1 = NULL;
44807bcd316dSGangCao 	struct spdk_bdev_desc *desc2 = NULL;
44817bcd316dSGangCao 	struct spdk_bdev_desc *desc3 = NULL;
44827bcd316dSGangCao 	struct spdk_bdev_desc *desc4 = NULL;
44837bcd316dSGangCao 	int rc = 0;
44847bcd316dSGangCao 
44857bcd316dSGangCao 	bdev = allocate_bdev("bdev");
44867bcd316dSGangCao 
44877bcd316dSGangCao 	rc = spdk_bdev_open_ext("bdev", true, NULL, NULL, &desc1);
44887bcd316dSGangCao 	CU_ASSERT_EQUAL(rc, -EINVAL);
44897bcd316dSGangCao 
44907bcd316dSGangCao 	rc = spdk_bdev_open_ext("bdev", true, bdev_open_cb1, &desc1, &desc1);
44917bcd316dSGangCao 	CU_ASSERT_EQUAL(rc, 0);
44927bcd316dSGangCao 
44937bcd316dSGangCao 	rc = spdk_bdev_open_ext("bdev", true, bdev_open_cb2, &desc2, &desc2);
44947bcd316dSGangCao 	CU_ASSERT_EQUAL(rc, 0);
44957bcd316dSGangCao 
44967bcd316dSGangCao 	rc = spdk_bdev_open_ext("bdev", true, bdev_open_cb3, &desc3, &desc3);
44977bcd316dSGangCao 	CU_ASSERT_EQUAL(rc, 0);
44987bcd316dSGangCao 
44997bcd316dSGangCao 	rc = spdk_bdev_open_ext("bdev", true, bdev_open_cb4, &desc4, &desc4);
45007bcd316dSGangCao 	CU_ASSERT_EQUAL(rc, 0);
45017bcd316dSGangCao 
45027bcd316dSGangCao 	g_event_type1 = 0xFF;
45037bcd316dSGangCao 	g_event_type2 = 0xFF;
45047bcd316dSGangCao 	g_event_type3 = 0xFF;
45057bcd316dSGangCao 	g_event_type4 = 0xFF;
45067bcd316dSGangCao 
45077bcd316dSGangCao 	g_unregister_arg = NULL;
45087bcd316dSGangCao 	g_unregister_rc = -1;
45097bcd316dSGangCao 
45107bcd316dSGangCao 	/* Simulate hot-unplug by unregistering bdev */
45117bcd316dSGangCao 	spdk_bdev_unregister(bdev, bdev_unregister_cb, (void *)0x12345678);
45127bcd316dSGangCao 
45137bcd316dSGangCao 	/*
45147bcd316dSGangCao 	 * Unregister is handled asynchronously and event callback
45157bcd316dSGangCao 	 * (i.e., above bdev_open_cbN) will be called.
45167bcd316dSGangCao 	 * For bdev_open_cb3 and bdev_open_cb4, it is intended to not
45177bcd316dSGangCao 	 * close the desc3 and desc4 so that the bdev is not closed.
45187bcd316dSGangCao 	 */
45197bcd316dSGangCao 	poll_threads();
45207bcd316dSGangCao 
45217bcd316dSGangCao 	/* Check if correct events have been triggered in event callback fn */
45227bcd316dSGangCao 	CU_ASSERT_EQUAL(g_event_type1, SPDK_BDEV_EVENT_REMOVE);
45237bcd316dSGangCao 	CU_ASSERT_EQUAL(g_event_type2, SPDK_BDEV_EVENT_REMOVE);
45247bcd316dSGangCao 	CU_ASSERT_EQUAL(g_event_type3, SPDK_BDEV_EVENT_REMOVE);
45257bcd316dSGangCao 	CU_ASSERT_EQUAL(g_event_type4, SPDK_BDEV_EVENT_REMOVE);
45267bcd316dSGangCao 
45277bcd316dSGangCao 	/* Check that unregister callback is delayed */
45287bcd316dSGangCao 	CU_ASSERT(g_unregister_arg == NULL);
45297bcd316dSGangCao 	CU_ASSERT(g_unregister_rc == -1);
45307bcd316dSGangCao 
45317bcd316dSGangCao 	/*
45327bcd316dSGangCao 	 * Explicitly close desc3. As desc4 is still opened there, the
45337bcd316dSGangCao 	 * unergister callback is still delayed to execute.
45347bcd316dSGangCao 	 */
45357bcd316dSGangCao 	spdk_bdev_close(desc3);
45367bcd316dSGangCao 	CU_ASSERT(g_unregister_arg == NULL);
45377bcd316dSGangCao 	CU_ASSERT(g_unregister_rc == -1);
45387bcd316dSGangCao 
45397bcd316dSGangCao 	/*
45407bcd316dSGangCao 	 * Explicitly close desc4 to trigger the ongoing bdev unregister
45417bcd316dSGangCao 	 * operation after last desc is closed.
45427bcd316dSGangCao 	 */
45437bcd316dSGangCao 	spdk_bdev_close(desc4);
45447bcd316dSGangCao 
45457bcd316dSGangCao 	/* Poll the thread for the async unregister operation */
45467bcd316dSGangCao 	poll_threads();
45477bcd316dSGangCao 
45487bcd316dSGangCao 	/* Check that unregister callback is executed */
45497bcd316dSGangCao 	CU_ASSERT(g_unregister_arg == (void *)0x12345678);
45507bcd316dSGangCao 	CU_ASSERT(g_unregister_rc == 0);
45517bcd316dSGangCao 
45527bcd316dSGangCao 	free_bdev(bdev);
45537bcd316dSGangCao 	poll_threads();
45547bcd316dSGangCao }
45557bcd316dSGangCao 
4556f1d47d69SJin Yu struct timeout_io_cb_arg {
4557f1d47d69SJin Yu 	struct iovec iov;
4558f1d47d69SJin Yu 	uint8_t type;
4559f1d47d69SJin Yu };
4560f1d47d69SJin Yu 
4561f1d47d69SJin Yu static int
4562f1d47d69SJin Yu bdev_channel_count_submitted_io(struct spdk_bdev_channel *ch)
4563f1d47d69SJin Yu {
4564f1d47d69SJin Yu 	struct spdk_bdev_io *bdev_io;
4565f1d47d69SJin Yu 	int n = 0;
4566f1d47d69SJin Yu 
4567f1d47d69SJin Yu 	if (!ch) {
4568f1d47d69SJin Yu 		return -1;
4569f1d47d69SJin Yu 	}
4570f1d47d69SJin Yu 
4571f1d47d69SJin Yu 	TAILQ_FOREACH(bdev_io, &ch->io_submitted, internal.ch_link) {
4572f1d47d69SJin Yu 		n++;
4573f1d47d69SJin Yu 	}
4574f1d47d69SJin Yu 
4575f1d47d69SJin Yu 	return n;
4576f1d47d69SJin Yu }
4577f1d47d69SJin Yu 
4578f1d47d69SJin Yu static void
4579f1d47d69SJin Yu bdev_channel_io_timeout_cb(void *cb_arg, struct spdk_bdev_io *bdev_io)
4580f1d47d69SJin Yu {
4581f1d47d69SJin Yu 	struct timeout_io_cb_arg *ctx = cb_arg;
4582f1d47d69SJin Yu 
4583f1d47d69SJin Yu 	ctx->type = bdev_io->type;
4584f1d47d69SJin Yu 	ctx->iov.iov_base = bdev_io->iov.iov_base;
4585f1d47d69SJin Yu 	ctx->iov.iov_len = bdev_io->iov.iov_len;
4586f1d47d69SJin Yu }
4587f1d47d69SJin Yu 
4588f1d47d69SJin Yu static void
4589f1d47d69SJin Yu bdev_set_io_timeout(void)
4590f1d47d69SJin Yu {
4591f1d47d69SJin Yu 	struct spdk_bdev *bdev;
4592f1d47d69SJin Yu 	struct spdk_bdev_desc *desc = NULL;
4593f1d47d69SJin Yu 	struct spdk_io_channel *io_ch = NULL;
4594f1d47d69SJin Yu 	struct spdk_bdev_channel *bdev_ch = NULL;
4595f1d47d69SJin Yu 	struct timeout_io_cb_arg cb_arg;
4596f1d47d69SJin Yu 
4597107741fcSKonrad Sztyber 	ut_init_bdev(NULL);
4598f1d47d69SJin Yu 	bdev = allocate_bdev("bdev");
4599f1d47d69SJin Yu 
460075dfecbbSShuhei Matsumoto 	CU_ASSERT(spdk_bdev_open_ext("bdev", true, bdev_ut_event_cb, NULL, &desc) == 0);
4601f1d47d69SJin Yu 	SPDK_CU_ASSERT_FATAL(desc != NULL);
460275dfecbbSShuhei Matsumoto 	CU_ASSERT(bdev == spdk_bdev_desc_get_bdev(desc));
460375dfecbbSShuhei Matsumoto 
4604f1d47d69SJin Yu 	io_ch = spdk_bdev_get_io_channel(desc);
4605f1d47d69SJin Yu 	CU_ASSERT(io_ch != NULL);
4606f1d47d69SJin Yu 
4607f1d47d69SJin Yu 	bdev_ch = spdk_io_channel_get_ctx(io_ch);
4608f1d47d69SJin Yu 	CU_ASSERT(TAILQ_EMPTY(&bdev_ch->io_submitted));
4609f1d47d69SJin Yu 
4610f1d47d69SJin Yu 	/* This is the part1.
4611f1d47d69SJin Yu 	 * We will check the bdev_ch->io_submitted list
4612f1d47d69SJin Yu 	 * TO make sure that it can link IOs and only the user submitted IOs
4613f1d47d69SJin Yu 	 */
4614f1d47d69SJin Yu 	CU_ASSERT(spdk_bdev_read(desc, io_ch, (void *)0x1000, 0, 4096, io_done, NULL) == 0);
4615f1d47d69SJin Yu 	CU_ASSERT(bdev_channel_count_submitted_io(bdev_ch) == 1);
4616f1d47d69SJin Yu 	CU_ASSERT(spdk_bdev_write(desc, io_ch, (void *)0x2000, 0, 4096, io_done, NULL) == 0);
4617f1d47d69SJin Yu 	CU_ASSERT(bdev_channel_count_submitted_io(bdev_ch) == 2);
4618f1d47d69SJin Yu 	stub_complete_io(1);
4619f1d47d69SJin Yu 	CU_ASSERT(bdev_channel_count_submitted_io(bdev_ch) == 1);
4620f1d47d69SJin Yu 	stub_complete_io(1);
4621f1d47d69SJin Yu 	CU_ASSERT(bdev_channel_count_submitted_io(bdev_ch) == 0);
4622f1d47d69SJin Yu 
4623f1d47d69SJin Yu 	/* Split IO */
4624f1d47d69SJin Yu 	bdev->optimal_io_boundary = 16;
4625f1d47d69SJin Yu 	bdev->split_on_optimal_io_boundary = true;
4626f1d47d69SJin Yu 
4627f1d47d69SJin Yu 	/* Now test that a single-vector command is split correctly.
4628f1d47d69SJin Yu 	 * Offset 14, length 8, payload 0xF000
4629f1d47d69SJin Yu 	 *  Child - Offset 14, length 2, payload 0xF000
4630f1d47d69SJin Yu 	 *  Child - Offset 16, length 6, payload 0xF000 + 2 * 512
4631f1d47d69SJin Yu 	 *
4632f1d47d69SJin Yu 	 * Set up the expected values before calling spdk_bdev_read_blocks
4633f1d47d69SJin Yu 	 */
4634f1d47d69SJin Yu 	CU_ASSERT(spdk_bdev_read_blocks(desc, io_ch, (void *)0xF000, 14, 8, io_done, NULL) == 0);
4635fc3e4061SShuhei Matsumoto 	/* We count all submitted IOs including IO that are generated by splitting. */
4636fc3e4061SShuhei Matsumoto 	CU_ASSERT(bdev_channel_count_submitted_io(bdev_ch) == 3);
4637f1d47d69SJin Yu 	stub_complete_io(1);
4638fc3e4061SShuhei Matsumoto 	CU_ASSERT(bdev_channel_count_submitted_io(bdev_ch) == 2);
4639f1d47d69SJin Yu 	stub_complete_io(1);
4640f1d47d69SJin Yu 	CU_ASSERT(bdev_channel_count_submitted_io(bdev_ch) == 0);
4641f1d47d69SJin Yu 
4642f1d47d69SJin Yu 	/* Also include the reset IO */
4643f1d47d69SJin Yu 	CU_ASSERT(spdk_bdev_reset(desc, io_ch, io_done, NULL) == 0);
4644f1d47d69SJin Yu 	CU_ASSERT(bdev_channel_count_submitted_io(bdev_ch) == 1);
4645f1d47d69SJin Yu 	poll_threads();
4646f1d47d69SJin Yu 	stub_complete_io(1);
4647f1d47d69SJin Yu 	poll_threads();
4648f1d47d69SJin Yu 	CU_ASSERT(bdev_channel_count_submitted_io(bdev_ch) == 0);
4649f1d47d69SJin Yu 
4650f1d47d69SJin Yu 	/* This is part2
4651f1d47d69SJin Yu 	 * Test the desc timeout poller register
4652f1d47d69SJin Yu 	 */
4653f1d47d69SJin Yu 
4654f1d47d69SJin Yu 	/* Successfully set the timeout */
4655f1d47d69SJin Yu 	CU_ASSERT(spdk_bdev_set_timeout(desc, 30, bdev_channel_io_timeout_cb, &cb_arg) == 0);
4656f1d47d69SJin Yu 	CU_ASSERT(desc->io_timeout_poller != NULL);
4657f1d47d69SJin Yu 	CU_ASSERT(desc->timeout_in_sec == 30);
4658f1d47d69SJin Yu 	CU_ASSERT(desc->cb_fn == bdev_channel_io_timeout_cb);
4659f1d47d69SJin Yu 	CU_ASSERT(desc->cb_arg == &cb_arg);
4660f1d47d69SJin Yu 
4661f1d47d69SJin Yu 	/* Change the timeout limit */
4662f1d47d69SJin Yu 	CU_ASSERT(spdk_bdev_set_timeout(desc, 20, bdev_channel_io_timeout_cb, &cb_arg) == 0);
4663f1d47d69SJin Yu 	CU_ASSERT(desc->io_timeout_poller != NULL);
4664f1d47d69SJin Yu 	CU_ASSERT(desc->timeout_in_sec == 20);
4665f1d47d69SJin Yu 	CU_ASSERT(desc->cb_fn == bdev_channel_io_timeout_cb);
4666f1d47d69SJin Yu 	CU_ASSERT(desc->cb_arg == &cb_arg);
4667f1d47d69SJin Yu 
4668f1d47d69SJin Yu 	/* Disable the timeout */
4669f1d47d69SJin Yu 	CU_ASSERT(spdk_bdev_set_timeout(desc, 0, NULL, NULL) == 0);
4670f1d47d69SJin Yu 	CU_ASSERT(desc->io_timeout_poller == NULL);
4671f1d47d69SJin Yu 
4672f1d47d69SJin Yu 	/* This the part3
4673f1d47d69SJin Yu 	 * We will test to catch timeout IO and check whether the IO is
4674f1d47d69SJin Yu 	 * the submitted one.
4675f1d47d69SJin Yu 	 */
4676f1d47d69SJin Yu 	memset(&cb_arg, 0, sizeof(cb_arg));
4677f1d47d69SJin Yu 	CU_ASSERT(spdk_bdev_set_timeout(desc, 30, bdev_channel_io_timeout_cb, &cb_arg) == 0);
4678f1d47d69SJin Yu 	CU_ASSERT(spdk_bdev_write_blocks(desc, io_ch, (void *)0x1000, 0, 1, io_done, NULL) == 0);
4679f1d47d69SJin Yu 
4680f1d47d69SJin Yu 	/* Don't reach the limit */
4681f1d47d69SJin Yu 	spdk_delay_us(15 * spdk_get_ticks_hz());
4682f1d47d69SJin Yu 	poll_threads();
4683f1d47d69SJin Yu 	CU_ASSERT(cb_arg.type == 0);
4684f1d47d69SJin Yu 	CU_ASSERT(cb_arg.iov.iov_base == (void *)0x0);
4685f1d47d69SJin Yu 	CU_ASSERT(cb_arg.iov.iov_len == 0);
4686f1d47d69SJin Yu 
4687f1d47d69SJin Yu 	/* 15 + 15 = 30 reach the limit */
4688f1d47d69SJin Yu 	spdk_delay_us(15 * spdk_get_ticks_hz());
4689f1d47d69SJin Yu 	poll_threads();
4690f1d47d69SJin Yu 	CU_ASSERT(cb_arg.type == SPDK_BDEV_IO_TYPE_WRITE);
4691f1d47d69SJin Yu 	CU_ASSERT(cb_arg.iov.iov_base == (void *)0x1000);
4692f1d47d69SJin Yu 	CU_ASSERT(cb_arg.iov.iov_len == 1 * bdev->blocklen);
4693f1d47d69SJin Yu 	stub_complete_io(1);
4694f1d47d69SJin Yu 
4695f1d47d69SJin Yu 	/* Use the same split IO above and check the IO */
4696f1d47d69SJin Yu 	memset(&cb_arg, 0, sizeof(cb_arg));
4697f1d47d69SJin Yu 	CU_ASSERT(spdk_bdev_write_blocks(desc, io_ch, (void *)0xF000, 14, 8, io_done, NULL) == 0);
4698f1d47d69SJin Yu 
4699f1d47d69SJin Yu 	/* The first child complete in time */
4700f1d47d69SJin Yu 	spdk_delay_us(15 * spdk_get_ticks_hz());
4701f1d47d69SJin Yu 	poll_threads();
4702f1d47d69SJin Yu 	stub_complete_io(1);
4703f1d47d69SJin Yu 	CU_ASSERT(cb_arg.type == 0);
4704f1d47d69SJin Yu 	CU_ASSERT(cb_arg.iov.iov_base == (void *)0x0);
4705f1d47d69SJin Yu 	CU_ASSERT(cb_arg.iov.iov_len == 0);
4706f1d47d69SJin Yu 
4707f1d47d69SJin Yu 	/* The second child reach the limit */
4708f1d47d69SJin Yu 	spdk_delay_us(15 * spdk_get_ticks_hz());
4709f1d47d69SJin Yu 	poll_threads();
4710f1d47d69SJin Yu 	CU_ASSERT(cb_arg.type == SPDK_BDEV_IO_TYPE_WRITE);
4711f1d47d69SJin Yu 	CU_ASSERT(cb_arg.iov.iov_base == (void *)0xF000);
4712f1d47d69SJin Yu 	CU_ASSERT(cb_arg.iov.iov_len == 8 * bdev->blocklen);
4713f1d47d69SJin Yu 	stub_complete_io(1);
4714f1d47d69SJin Yu 
4715f1d47d69SJin Yu 	/* Also include the reset IO */
4716f1d47d69SJin Yu 	memset(&cb_arg, 0, sizeof(cb_arg));
4717f1d47d69SJin Yu 	CU_ASSERT(spdk_bdev_reset(desc, io_ch, io_done, NULL) == 0);
4718f1d47d69SJin Yu 	spdk_delay_us(30 * spdk_get_ticks_hz());
4719f1d47d69SJin Yu 	poll_threads();
4720f1d47d69SJin Yu 	CU_ASSERT(cb_arg.type == SPDK_BDEV_IO_TYPE_RESET);
4721f1d47d69SJin Yu 	stub_complete_io(1);
4722f1d47d69SJin Yu 	poll_threads();
4723f1d47d69SJin Yu 
4724f1d47d69SJin Yu 	spdk_put_io_channel(io_ch);
4725f1d47d69SJin Yu 	spdk_bdev_close(desc);
4726f1d47d69SJin Yu 	free_bdev(bdev);
4727107741fcSKonrad Sztyber 	ut_fini_bdev();
4728f1d47d69SJin Yu }
4729f1d47d69SJin Yu 
4730b87080efSJim Harris static void
473148ce2c97SGangCao bdev_set_qd_sampling(void)
473248ce2c97SGangCao {
473348ce2c97SGangCao 	struct spdk_bdev *bdev;
473448ce2c97SGangCao 	struct spdk_bdev_desc *desc = NULL;
473548ce2c97SGangCao 	struct spdk_io_channel *io_ch = NULL;
473648ce2c97SGangCao 	struct spdk_bdev_channel *bdev_ch = NULL;
473748ce2c97SGangCao 	struct timeout_io_cb_arg cb_arg;
473848ce2c97SGangCao 
4739107741fcSKonrad Sztyber 	ut_init_bdev(NULL);
474048ce2c97SGangCao 	bdev = allocate_bdev("bdev");
474148ce2c97SGangCao 
474248ce2c97SGangCao 	CU_ASSERT(spdk_bdev_open_ext("bdev", true, bdev_ut_event_cb, NULL, &desc) == 0);
474348ce2c97SGangCao 	SPDK_CU_ASSERT_FATAL(desc != NULL);
474448ce2c97SGangCao 	CU_ASSERT(bdev == spdk_bdev_desc_get_bdev(desc));
474548ce2c97SGangCao 
474648ce2c97SGangCao 	io_ch = spdk_bdev_get_io_channel(desc);
474748ce2c97SGangCao 	CU_ASSERT(io_ch != NULL);
474848ce2c97SGangCao 
474948ce2c97SGangCao 	bdev_ch = spdk_io_channel_get_ctx(io_ch);
475048ce2c97SGangCao 	CU_ASSERT(TAILQ_EMPTY(&bdev_ch->io_submitted));
475148ce2c97SGangCao 
475248ce2c97SGangCao 	/* This is the part1.
475348ce2c97SGangCao 	 * We will check the bdev_ch->io_submitted list
475448ce2c97SGangCao 	 * TO make sure that it can link IOs and only the user submitted IOs
475548ce2c97SGangCao 	 */
475648ce2c97SGangCao 	CU_ASSERT(spdk_bdev_read(desc, io_ch, (void *)0x1000, 0, 4096, io_done, NULL) == 0);
475748ce2c97SGangCao 	CU_ASSERT(bdev_channel_count_submitted_io(bdev_ch) == 1);
475848ce2c97SGangCao 	CU_ASSERT(spdk_bdev_write(desc, io_ch, (void *)0x2000, 0, 4096, io_done, NULL) == 0);
475948ce2c97SGangCao 	CU_ASSERT(bdev_channel_count_submitted_io(bdev_ch) == 2);
476048ce2c97SGangCao 	stub_complete_io(1);
476148ce2c97SGangCao 	CU_ASSERT(bdev_channel_count_submitted_io(bdev_ch) == 1);
476248ce2c97SGangCao 	stub_complete_io(1);
476348ce2c97SGangCao 	CU_ASSERT(bdev_channel_count_submitted_io(bdev_ch) == 0);
476448ce2c97SGangCao 
476548ce2c97SGangCao 	/* This is the part2.
476648ce2c97SGangCao 	 * Test the bdev's qd poller register
476748ce2c97SGangCao 	 */
476848ce2c97SGangCao 	/* 1st Successfully set the qd sampling period */
476948ce2c97SGangCao 	spdk_bdev_set_qd_sampling_period(bdev, 10);
477048ce2c97SGangCao 	CU_ASSERT(bdev->internal.new_period == 10);
477148ce2c97SGangCao 	CU_ASSERT(bdev->internal.period == 10);
477248ce2c97SGangCao 	CU_ASSERT(bdev->internal.qd_desc != NULL);
477348ce2c97SGangCao 	poll_threads();
477448ce2c97SGangCao 	CU_ASSERT(bdev->internal.qd_poller != NULL);
477548ce2c97SGangCao 
477648ce2c97SGangCao 	/* 2nd Change the qd sampling period */
477748ce2c97SGangCao 	spdk_bdev_set_qd_sampling_period(bdev, 20);
477848ce2c97SGangCao 	CU_ASSERT(bdev->internal.new_period == 20);
477948ce2c97SGangCao 	CU_ASSERT(bdev->internal.period == 10);
478048ce2c97SGangCao 	CU_ASSERT(bdev->internal.qd_desc != NULL);
478148ce2c97SGangCao 	poll_threads();
478248ce2c97SGangCao 	CU_ASSERT(bdev->internal.qd_poller != NULL);
478348ce2c97SGangCao 	CU_ASSERT(bdev->internal.period == bdev->internal.new_period);
478448ce2c97SGangCao 
478548ce2c97SGangCao 	/* 3rd Change the qd sampling period and verify qd_poll_in_progress */
478648ce2c97SGangCao 	spdk_delay_us(20);
478748ce2c97SGangCao 	poll_thread_times(0, 1);
478848ce2c97SGangCao 	CU_ASSERT(bdev->internal.qd_poll_in_progress == true);
478948ce2c97SGangCao 	spdk_bdev_set_qd_sampling_period(bdev, 30);
479048ce2c97SGangCao 	CU_ASSERT(bdev->internal.new_period == 30);
479148ce2c97SGangCao 	CU_ASSERT(bdev->internal.period == 20);
479248ce2c97SGangCao 	poll_threads();
479348ce2c97SGangCao 	CU_ASSERT(bdev->internal.qd_poll_in_progress == false);
479448ce2c97SGangCao 	CU_ASSERT(bdev->internal.period == bdev->internal.new_period);
479548ce2c97SGangCao 
479648ce2c97SGangCao 	/* 4th Disable the qd sampling period */
479748ce2c97SGangCao 	spdk_bdev_set_qd_sampling_period(bdev, 0);
479848ce2c97SGangCao 	CU_ASSERT(bdev->internal.new_period == 0);
479948ce2c97SGangCao 	CU_ASSERT(bdev->internal.period == 30);
480048ce2c97SGangCao 	poll_threads();
480148ce2c97SGangCao 	CU_ASSERT(bdev->internal.qd_poller == NULL);
480248ce2c97SGangCao 	CU_ASSERT(bdev->internal.period == bdev->internal.new_period);
480348ce2c97SGangCao 	CU_ASSERT(bdev->internal.qd_desc == NULL);
480448ce2c97SGangCao 
480548ce2c97SGangCao 	/* This is the part3.
480648ce2c97SGangCao 	 * We will test the submitted IO and reset works
480748ce2c97SGangCao 	 * properly with the qd sampling.
480848ce2c97SGangCao 	 */
480948ce2c97SGangCao 	memset(&cb_arg, 0, sizeof(cb_arg));
481048ce2c97SGangCao 	spdk_bdev_set_qd_sampling_period(bdev, 1);
481148ce2c97SGangCao 	poll_threads();
481248ce2c97SGangCao 
481348ce2c97SGangCao 	CU_ASSERT(spdk_bdev_write(desc, io_ch, (void *)0x2000, 0, 4096, io_done, NULL) == 0);
481448ce2c97SGangCao 	CU_ASSERT(bdev_channel_count_submitted_io(bdev_ch) == 1);
481548ce2c97SGangCao 
481648ce2c97SGangCao 	/* Also include the reset IO */
481748ce2c97SGangCao 	memset(&cb_arg, 0, sizeof(cb_arg));
481848ce2c97SGangCao 	CU_ASSERT(spdk_bdev_reset(desc, io_ch, io_done, NULL) == 0);
481948ce2c97SGangCao 	poll_threads();
482048ce2c97SGangCao 
482148ce2c97SGangCao 	/* Close the desc */
482248ce2c97SGangCao 	spdk_put_io_channel(io_ch);
482348ce2c97SGangCao 	spdk_bdev_close(desc);
482448ce2c97SGangCao 
482548ce2c97SGangCao 	/* Complete the submitted IO and reset */
482648ce2c97SGangCao 	stub_complete_io(2);
482748ce2c97SGangCao 	poll_threads();
482848ce2c97SGangCao 
482948ce2c97SGangCao 	free_bdev(bdev);
4830107741fcSKonrad Sztyber 	ut_fini_bdev();
483148ce2c97SGangCao }
483248ce2c97SGangCao 
483348ce2c97SGangCao static void
4834b87080efSJim Harris lba_range_overlap(void)
4835b87080efSJim Harris {
4836b87080efSJim Harris 	struct lba_range r1, r2;
4837b87080efSJim Harris 
4838b87080efSJim Harris 	r1.offset = 100;
4839b87080efSJim Harris 	r1.length = 50;
4840b87080efSJim Harris 
4841b87080efSJim Harris 	r2.offset = 0;
4842b87080efSJim Harris 	r2.length = 1;
4843b87080efSJim Harris 	CU_ASSERT(!bdev_lba_range_overlapped(&r1, &r2));
4844b87080efSJim Harris 
4845b87080efSJim Harris 	r2.offset = 0;
4846b87080efSJim Harris 	r2.length = 100;
4847b87080efSJim Harris 	CU_ASSERT(!bdev_lba_range_overlapped(&r1, &r2));
4848b87080efSJim Harris 
4849b87080efSJim Harris 	r2.offset = 0;
4850b87080efSJim Harris 	r2.length = 110;
4851b87080efSJim Harris 	CU_ASSERT(bdev_lba_range_overlapped(&r1, &r2));
4852b87080efSJim Harris 
4853b87080efSJim Harris 	r2.offset = 100;
4854b87080efSJim Harris 	r2.length = 10;
4855b87080efSJim Harris 	CU_ASSERT(bdev_lba_range_overlapped(&r1, &r2));
4856b87080efSJim Harris 
4857b87080efSJim Harris 	r2.offset = 110;
4858b87080efSJim Harris 	r2.length = 20;
4859b87080efSJim Harris 	CU_ASSERT(bdev_lba_range_overlapped(&r1, &r2));
4860b87080efSJim Harris 
4861b87080efSJim Harris 	r2.offset = 140;
4862b87080efSJim Harris 	r2.length = 150;
4863b87080efSJim Harris 	CU_ASSERT(bdev_lba_range_overlapped(&r1, &r2));
4864b87080efSJim Harris 
4865b87080efSJim Harris 	r2.offset = 130;
4866b87080efSJim Harris 	r2.length = 200;
4867b87080efSJim Harris 	CU_ASSERT(bdev_lba_range_overlapped(&r1, &r2));
4868b87080efSJim Harris 
4869b87080efSJim Harris 	r2.offset = 150;
4870b87080efSJim Harris 	r2.length = 100;
4871b87080efSJim Harris 	CU_ASSERT(!bdev_lba_range_overlapped(&r1, &r2));
4872b87080efSJim Harris 
4873b87080efSJim Harris 	r2.offset = 110;
4874b87080efSJim Harris 	r2.length = 0;
4875b87080efSJim Harris 	CU_ASSERT(!bdev_lba_range_overlapped(&r1, &r2));
4876b87080efSJim Harris }
4877b87080efSJim Harris 
4878d84a88c1SJim Harris static bool g_lock_lba_range_done;
4879d84a88c1SJim Harris static bool g_unlock_lba_range_done;
4880d84a88c1SJim Harris 
4881d84a88c1SJim Harris static void
4882687cfd4bSArtur Paszkiewicz lock_lba_range_done(struct lba_range *range, void *ctx, int status)
4883d84a88c1SJim Harris {
4884d84a88c1SJim Harris 	g_lock_lba_range_done = true;
4885d84a88c1SJim Harris }
4886d84a88c1SJim Harris 
4887d84a88c1SJim Harris static void
4888687cfd4bSArtur Paszkiewicz unlock_lba_range_done(struct lba_range *range, void *ctx, int status)
4889d84a88c1SJim Harris {
4890d84a88c1SJim Harris 	g_unlock_lba_range_done = true;
4891d84a88c1SJim Harris }
4892d84a88c1SJim Harris 
4893d84a88c1SJim Harris static void
4894d84a88c1SJim Harris lock_lba_range_check_ranges(void)
4895d84a88c1SJim Harris {
4896d84a88c1SJim Harris 	struct spdk_bdev *bdev;
4897d84a88c1SJim Harris 	struct spdk_bdev_desc *desc = NULL;
4898d84a88c1SJim Harris 	struct spdk_io_channel *io_ch;
4899d84a88c1SJim Harris 	struct spdk_bdev_channel *channel;
4900d84a88c1SJim Harris 	struct lba_range *range;
4901d84a88c1SJim Harris 	int ctx1;
4902d84a88c1SJim Harris 	int rc;
4903d84a88c1SJim Harris 
4904107741fcSKonrad Sztyber 	ut_init_bdev(NULL);
4905d84a88c1SJim Harris 	bdev = allocate_bdev("bdev0");
4906d84a88c1SJim Harris 
490775dfecbbSShuhei Matsumoto 	rc = spdk_bdev_open_ext("bdev0", true, bdev_ut_event_cb, NULL, &desc);
4908d84a88c1SJim Harris 	CU_ASSERT(rc == 0);
4909d84a88c1SJim Harris 	CU_ASSERT(desc != NULL);
491075dfecbbSShuhei Matsumoto 	CU_ASSERT(bdev == spdk_bdev_desc_get_bdev(desc));
4911d84a88c1SJim Harris 	io_ch = spdk_bdev_get_io_channel(desc);
4912d84a88c1SJim Harris 	CU_ASSERT(io_ch != NULL);
4913d84a88c1SJim Harris 	channel = spdk_io_channel_get_ctx(io_ch);
4914d84a88c1SJim Harris 
4915d84a88c1SJim Harris 	g_lock_lba_range_done = false;
4916d84a88c1SJim Harris 	rc = bdev_lock_lba_range(desc, io_ch, 20, 10, lock_lba_range_done, &ctx1);
4917d84a88c1SJim Harris 	CU_ASSERT(rc == 0);
4918d84a88c1SJim Harris 	poll_threads();
4919d84a88c1SJim Harris 
4920d84a88c1SJim Harris 	CU_ASSERT(g_lock_lba_range_done == true);
4921d84a88c1SJim Harris 	range = TAILQ_FIRST(&channel->locked_ranges);
4922d84a88c1SJim Harris 	SPDK_CU_ASSERT_FATAL(range != NULL);
4923d84a88c1SJim Harris 	CU_ASSERT(range->offset == 20);
4924d84a88c1SJim Harris 	CU_ASSERT(range->length == 10);
4925d84a88c1SJim Harris 	CU_ASSERT(range->owner_ch == channel);
4926d84a88c1SJim Harris 
4927d84a88c1SJim Harris 	/* Unlocks must exactly match a lock. */
4928d84a88c1SJim Harris 	g_unlock_lba_range_done = false;
4929d84a88c1SJim Harris 	rc = bdev_unlock_lba_range(desc, io_ch, 20, 1, unlock_lba_range_done, &ctx1);
4930d84a88c1SJim Harris 	CU_ASSERT(rc == -EINVAL);
4931d84a88c1SJim Harris 	CU_ASSERT(g_unlock_lba_range_done == false);
4932d84a88c1SJim Harris 
4933d84a88c1SJim Harris 	rc = bdev_unlock_lba_range(desc, io_ch, 20, 10, unlock_lba_range_done, &ctx1);
4934d84a88c1SJim Harris 	CU_ASSERT(rc == 0);
4935d84a88c1SJim Harris 	spdk_delay_us(100);
4936d84a88c1SJim Harris 	poll_threads();
4937d84a88c1SJim Harris 
4938d84a88c1SJim Harris 	CU_ASSERT(g_unlock_lba_range_done == true);
4939d84a88c1SJim Harris 	CU_ASSERT(TAILQ_EMPTY(&channel->locked_ranges));
4940d84a88c1SJim Harris 
4941d84a88c1SJim Harris 	spdk_put_io_channel(io_ch);
4942d84a88c1SJim Harris 	spdk_bdev_close(desc);
4943d84a88c1SJim Harris 	free_bdev(bdev);
4944107741fcSKonrad Sztyber 	ut_fini_bdev();
4945d84a88c1SJim Harris }
4946d84a88c1SJim Harris 
4947b90b7ce4SJim Harris static void
4948b90b7ce4SJim Harris lock_lba_range_with_io_outstanding(void)
4949b90b7ce4SJim Harris {
4950b90b7ce4SJim Harris 	struct spdk_bdev *bdev;
4951b90b7ce4SJim Harris 	struct spdk_bdev_desc *desc = NULL;
4952b90b7ce4SJim Harris 	struct spdk_io_channel *io_ch;
4953b90b7ce4SJim Harris 	struct spdk_bdev_channel *channel;
4954b90b7ce4SJim Harris 	struct lba_range *range;
4955b90b7ce4SJim Harris 	char buf[4096];
4956b90b7ce4SJim Harris 	int ctx1;
4957b90b7ce4SJim Harris 	int rc;
4958b90b7ce4SJim Harris 
4959107741fcSKonrad Sztyber 	ut_init_bdev(NULL);
4960b90b7ce4SJim Harris 	bdev = allocate_bdev("bdev0");
4961b90b7ce4SJim Harris 
496275dfecbbSShuhei Matsumoto 	rc = spdk_bdev_open_ext("bdev0", true, bdev_ut_event_cb, NULL, &desc);
4963b90b7ce4SJim Harris 	CU_ASSERT(rc == 0);
4964b90b7ce4SJim Harris 	CU_ASSERT(desc != NULL);
496575dfecbbSShuhei Matsumoto 	CU_ASSERT(bdev == spdk_bdev_desc_get_bdev(desc));
4966b90b7ce4SJim Harris 	io_ch = spdk_bdev_get_io_channel(desc);
4967b90b7ce4SJim Harris 	CU_ASSERT(io_ch != NULL);
4968b90b7ce4SJim Harris 	channel = spdk_io_channel_get_ctx(io_ch);
4969b90b7ce4SJim Harris 
4970b90b7ce4SJim Harris 	g_io_done = false;
4971b90b7ce4SJim Harris 	rc = spdk_bdev_read_blocks(desc, io_ch, buf, 20, 1, io_done, &ctx1);
4972b90b7ce4SJim Harris 	CU_ASSERT(rc == 0);
4973b90b7ce4SJim Harris 
4974b90b7ce4SJim Harris 	g_lock_lba_range_done = false;
4975b90b7ce4SJim Harris 	rc = bdev_lock_lba_range(desc, io_ch, 20, 10, lock_lba_range_done, &ctx1);
4976b90b7ce4SJim Harris 	CU_ASSERT(rc == 0);
4977b90b7ce4SJim Harris 	poll_threads();
4978b90b7ce4SJim Harris 
4979b90b7ce4SJim Harris 	/* The lock should immediately become valid, since there are no outstanding
4980b90b7ce4SJim Harris 	 * write I/O.
4981b90b7ce4SJim Harris 	 */
4982b90b7ce4SJim Harris 	CU_ASSERT(g_io_done == false);
4983b90b7ce4SJim Harris 	CU_ASSERT(g_lock_lba_range_done == true);
4984b90b7ce4SJim Harris 	range = TAILQ_FIRST(&channel->locked_ranges);
4985b90b7ce4SJim Harris 	SPDK_CU_ASSERT_FATAL(range != NULL);
4986b90b7ce4SJim Harris 	CU_ASSERT(range->offset == 20);
4987b90b7ce4SJim Harris 	CU_ASSERT(range->length == 10);
4988b90b7ce4SJim Harris 	CU_ASSERT(range->owner_ch == channel);
4989b90b7ce4SJim Harris 	CU_ASSERT(range->locked_ctx == &ctx1);
4990b90b7ce4SJim Harris 
4991b90b7ce4SJim Harris 	rc = bdev_unlock_lba_range(desc, io_ch, 20, 10, lock_lba_range_done, &ctx1);
4992b90b7ce4SJim Harris 	CU_ASSERT(rc == 0);
4993b90b7ce4SJim Harris 	stub_complete_io(1);
4994b90b7ce4SJim Harris 	spdk_delay_us(100);
4995b90b7ce4SJim Harris 	poll_threads();
4996b90b7ce4SJim Harris 
4997b90b7ce4SJim Harris 	CU_ASSERT(TAILQ_EMPTY(&channel->locked_ranges));
4998b90b7ce4SJim Harris 
4999b90b7ce4SJim Harris 	/* Now try again, but with a write I/O. */
5000b90b7ce4SJim Harris 	g_io_done = false;
5001b90b7ce4SJim Harris 	rc = spdk_bdev_write_blocks(desc, io_ch, buf, 20, 1, io_done, &ctx1);
5002b90b7ce4SJim Harris 	CU_ASSERT(rc == 0);
5003b90b7ce4SJim Harris 
5004b90b7ce4SJim Harris 	g_lock_lba_range_done = false;
5005b90b7ce4SJim Harris 	rc = bdev_lock_lba_range(desc, io_ch, 20, 10, lock_lba_range_done, &ctx1);
5006b90b7ce4SJim Harris 	CU_ASSERT(rc == 0);
5007b90b7ce4SJim Harris 	poll_threads();
5008b90b7ce4SJim Harris 
5009b90b7ce4SJim Harris 	/* The lock should not be fully valid yet, since a write I/O is outstanding.
5010b90b7ce4SJim Harris 	 * But note that the range should be on the channel's locked_list, to make sure no
5011b90b7ce4SJim Harris 	 * new write I/O are started.
5012b90b7ce4SJim Harris 	 */
5013b90b7ce4SJim Harris 	CU_ASSERT(g_io_done == false);
5014b90b7ce4SJim Harris 	CU_ASSERT(g_lock_lba_range_done == false);
5015b90b7ce4SJim Harris 	range = TAILQ_FIRST(&channel->locked_ranges);
5016b90b7ce4SJim Harris 	SPDK_CU_ASSERT_FATAL(range != NULL);
5017b90b7ce4SJim Harris 	CU_ASSERT(range->offset == 20);
5018b90b7ce4SJim Harris 	CU_ASSERT(range->length == 10);
5019b90b7ce4SJim Harris 
5020b90b7ce4SJim Harris 	/* Complete the write I/O.  This should make the lock valid (checked by confirming
5021b90b7ce4SJim Harris 	 * our callback was invoked).
5022b90b7ce4SJim Harris 	 */
5023b90b7ce4SJim Harris 	stub_complete_io(1);
5024b90b7ce4SJim Harris 	spdk_delay_us(100);
5025b90b7ce4SJim Harris 	poll_threads();
5026b90b7ce4SJim Harris 	CU_ASSERT(g_io_done == true);
5027b90b7ce4SJim Harris 	CU_ASSERT(g_lock_lba_range_done == true);
5028b90b7ce4SJim Harris 
5029b90b7ce4SJim Harris 	rc = bdev_unlock_lba_range(desc, io_ch, 20, 10, unlock_lba_range_done, &ctx1);
5030b90b7ce4SJim Harris 	CU_ASSERT(rc == 0);
5031b90b7ce4SJim Harris 	poll_threads();
5032b90b7ce4SJim Harris 
5033b90b7ce4SJim Harris 	CU_ASSERT(TAILQ_EMPTY(&channel->locked_ranges));
5034b90b7ce4SJim Harris 
5035b90b7ce4SJim Harris 	spdk_put_io_channel(io_ch);
5036b90b7ce4SJim Harris 	spdk_bdev_close(desc);
5037b90b7ce4SJim Harris 	free_bdev(bdev);
5038107741fcSKonrad Sztyber 	ut_fini_bdev();
5039b90b7ce4SJim Harris }
5040b90b7ce4SJim Harris 
50412a2b7296SJim Harris static void
50422a2b7296SJim Harris lock_lba_range_overlapped(void)
50432a2b7296SJim Harris {
50442a2b7296SJim Harris 	struct spdk_bdev *bdev;
50452a2b7296SJim Harris 	struct spdk_bdev_desc *desc = NULL;
50462a2b7296SJim Harris 	struct spdk_io_channel *io_ch;
50472a2b7296SJim Harris 	struct spdk_bdev_channel *channel;
50482a2b7296SJim Harris 	struct lba_range *range;
50492a2b7296SJim Harris 	int ctx1;
50502a2b7296SJim Harris 	int rc;
50512a2b7296SJim Harris 
5052107741fcSKonrad Sztyber 	ut_init_bdev(NULL);
50532a2b7296SJim Harris 	bdev = allocate_bdev("bdev0");
50542a2b7296SJim Harris 
505575dfecbbSShuhei Matsumoto 	rc = spdk_bdev_open_ext("bdev0", true, bdev_ut_event_cb, NULL, &desc);
50562a2b7296SJim Harris 	CU_ASSERT(rc == 0);
50572a2b7296SJim Harris 	CU_ASSERT(desc != NULL);
505875dfecbbSShuhei Matsumoto 	CU_ASSERT(bdev == spdk_bdev_desc_get_bdev(desc));
50592a2b7296SJim Harris 	io_ch = spdk_bdev_get_io_channel(desc);
50602a2b7296SJim Harris 	CU_ASSERT(io_ch != NULL);
50612a2b7296SJim Harris 	channel = spdk_io_channel_get_ctx(io_ch);
50622a2b7296SJim Harris 
50632a2b7296SJim Harris 	/* Lock range 20-29. */
50642a2b7296SJim Harris 	g_lock_lba_range_done = false;
50652a2b7296SJim Harris 	rc = bdev_lock_lba_range(desc, io_ch, 20, 10, lock_lba_range_done, &ctx1);
50662a2b7296SJim Harris 	CU_ASSERT(rc == 0);
50672a2b7296SJim Harris 	poll_threads();
50682a2b7296SJim Harris 
50692a2b7296SJim Harris 	CU_ASSERT(g_lock_lba_range_done == true);
50702a2b7296SJim Harris 	range = TAILQ_FIRST(&channel->locked_ranges);
50712a2b7296SJim Harris 	SPDK_CU_ASSERT_FATAL(range != NULL);
50722a2b7296SJim Harris 	CU_ASSERT(range->offset == 20);
50732a2b7296SJim Harris 	CU_ASSERT(range->length == 10);
50742a2b7296SJim Harris 
50752a2b7296SJim Harris 	/* Try to lock range 25-39.  It should not lock immediately, since it overlaps with
50762a2b7296SJim Harris 	 * 20-29.
50772a2b7296SJim Harris 	 */
50782a2b7296SJim Harris 	g_lock_lba_range_done = false;
50792a2b7296SJim Harris 	rc = bdev_lock_lba_range(desc, io_ch, 25, 15, lock_lba_range_done, &ctx1);
50802a2b7296SJim Harris 	CU_ASSERT(rc == 0);
50812a2b7296SJim Harris 	poll_threads();
50822a2b7296SJim Harris 
50832a2b7296SJim Harris 	CU_ASSERT(g_lock_lba_range_done == false);
50842a2b7296SJim Harris 	range = TAILQ_FIRST(&bdev->internal.pending_locked_ranges);
50852a2b7296SJim Harris 	SPDK_CU_ASSERT_FATAL(range != NULL);
50862a2b7296SJim Harris 	CU_ASSERT(range->offset == 25);
50872a2b7296SJim Harris 	CU_ASSERT(range->length == 15);
50882a2b7296SJim Harris 
50892a2b7296SJim Harris 	/* Unlock 20-29.  This should result in range 25-39 now getting locked since it
50902a2b7296SJim Harris 	 * no longer overlaps with an active lock.
50912a2b7296SJim Harris 	 */
50922a2b7296SJim Harris 	g_unlock_lba_range_done = false;
50932a2b7296SJim Harris 	rc = bdev_unlock_lba_range(desc, io_ch, 20, 10, unlock_lba_range_done, &ctx1);
50942a2b7296SJim Harris 	CU_ASSERT(rc == 0);
50952a2b7296SJim Harris 	poll_threads();
50962a2b7296SJim Harris 
50972a2b7296SJim Harris 	CU_ASSERT(g_unlock_lba_range_done == true);
50982a2b7296SJim Harris 	CU_ASSERT(TAILQ_EMPTY(&bdev->internal.pending_locked_ranges));
50992a2b7296SJim Harris 	range = TAILQ_FIRST(&channel->locked_ranges);
51002a2b7296SJim Harris 	SPDK_CU_ASSERT_FATAL(range != NULL);
51012a2b7296SJim Harris 	CU_ASSERT(range->offset == 25);
51022a2b7296SJim Harris 	CU_ASSERT(range->length == 15);
51032a2b7296SJim Harris 
51042a2b7296SJim Harris 	/* Lock 40-59.  This should immediately lock since it does not overlap with the
51052a2b7296SJim Harris 	 * currently active 25-39 lock.
51062a2b7296SJim Harris 	 */
51072a2b7296SJim Harris 	g_lock_lba_range_done = false;
51082a2b7296SJim Harris 	rc = bdev_lock_lba_range(desc, io_ch, 40, 20, lock_lba_range_done, &ctx1);
51092a2b7296SJim Harris 	CU_ASSERT(rc == 0);
51102a2b7296SJim Harris 	poll_threads();
51112a2b7296SJim Harris 
51122a2b7296SJim Harris 	CU_ASSERT(g_lock_lba_range_done == true);
51132a2b7296SJim Harris 	range = TAILQ_FIRST(&bdev->internal.locked_ranges);
51142a2b7296SJim Harris 	SPDK_CU_ASSERT_FATAL(range != NULL);
51152a2b7296SJim Harris 	range = TAILQ_NEXT(range, tailq);
51162a2b7296SJim Harris 	SPDK_CU_ASSERT_FATAL(range != NULL);
51172a2b7296SJim Harris 	CU_ASSERT(range->offset == 40);
51182a2b7296SJim Harris 	CU_ASSERT(range->length == 20);
51192a2b7296SJim Harris 
51202a2b7296SJim Harris 	/* Try to lock 35-44.  Note that this overlaps with both 25-39 and 40-59. */
51212a2b7296SJim Harris 	g_lock_lba_range_done = false;
51222a2b7296SJim Harris 	rc = bdev_lock_lba_range(desc, io_ch, 35, 10, lock_lba_range_done, &ctx1);
51232a2b7296SJim Harris 	CU_ASSERT(rc == 0);
51242a2b7296SJim Harris 	poll_threads();
51252a2b7296SJim Harris 
51262a2b7296SJim Harris 	CU_ASSERT(g_lock_lba_range_done == false);
51272a2b7296SJim Harris 	range = TAILQ_FIRST(&bdev->internal.pending_locked_ranges);
51282a2b7296SJim Harris 	SPDK_CU_ASSERT_FATAL(range != NULL);
51292a2b7296SJim Harris 	CU_ASSERT(range->offset == 35);
51302a2b7296SJim Harris 	CU_ASSERT(range->length == 10);
51312a2b7296SJim Harris 
51322a2b7296SJim Harris 	/* Unlock 25-39.  Make sure that 35-44 is still in the pending list, since
51332a2b7296SJim Harris 	 * the 40-59 lock is still active.
51342a2b7296SJim Harris 	 */
51352a2b7296SJim Harris 	g_unlock_lba_range_done = false;
51362a2b7296SJim Harris 	rc = bdev_unlock_lba_range(desc, io_ch, 25, 15, unlock_lba_range_done, &ctx1);
51372a2b7296SJim Harris 	CU_ASSERT(rc == 0);
51382a2b7296SJim Harris 	poll_threads();
51392a2b7296SJim Harris 
51402a2b7296SJim Harris 	CU_ASSERT(g_unlock_lba_range_done == true);
51412a2b7296SJim Harris 	CU_ASSERT(g_lock_lba_range_done == false);
51422a2b7296SJim Harris 	range = TAILQ_FIRST(&bdev->internal.pending_locked_ranges);
51432a2b7296SJim Harris 	SPDK_CU_ASSERT_FATAL(range != NULL);
51442a2b7296SJim Harris 	CU_ASSERT(range->offset == 35);
51452a2b7296SJim Harris 	CU_ASSERT(range->length == 10);
51462a2b7296SJim Harris 
51472a2b7296SJim Harris 	/* Unlock 40-59.  This should result in 35-44 now getting locked, since there are
51482a2b7296SJim Harris 	 * no longer any active overlapping locks.
51492a2b7296SJim Harris 	 */
51502a2b7296SJim Harris 	g_unlock_lba_range_done = false;
51512a2b7296SJim Harris 	rc = bdev_unlock_lba_range(desc, io_ch, 40, 20, unlock_lba_range_done, &ctx1);
51522a2b7296SJim Harris 	CU_ASSERT(rc == 0);
51532a2b7296SJim Harris 	poll_threads();
51542a2b7296SJim Harris 
51552a2b7296SJim Harris 	CU_ASSERT(g_unlock_lba_range_done == true);
51562a2b7296SJim Harris 	CU_ASSERT(g_lock_lba_range_done == true);
51572a2b7296SJim Harris 	CU_ASSERT(TAILQ_EMPTY(&bdev->internal.pending_locked_ranges));
51582a2b7296SJim Harris 	range = TAILQ_FIRST(&bdev->internal.locked_ranges);
51592a2b7296SJim Harris 	SPDK_CU_ASSERT_FATAL(range != NULL);
51602a2b7296SJim Harris 	CU_ASSERT(range->offset == 35);
51612a2b7296SJim Harris 	CU_ASSERT(range->length == 10);
51622a2b7296SJim Harris 
51632a2b7296SJim Harris 	/* Finally, unlock 35-44. */
51642a2b7296SJim Harris 	g_unlock_lba_range_done = false;
51652a2b7296SJim Harris 	rc = bdev_unlock_lba_range(desc, io_ch, 35, 10, unlock_lba_range_done, &ctx1);
51662a2b7296SJim Harris 	CU_ASSERT(rc == 0);
51672a2b7296SJim Harris 	poll_threads();
51682a2b7296SJim Harris 
51692a2b7296SJim Harris 	CU_ASSERT(g_unlock_lba_range_done == true);
51702a2b7296SJim Harris 	CU_ASSERT(TAILQ_EMPTY(&bdev->internal.locked_ranges));
51712a2b7296SJim Harris 
51722a2b7296SJim Harris 	spdk_put_io_channel(io_ch);
51732a2b7296SJim Harris 	spdk_bdev_close(desc);
51742a2b7296SJim Harris 	free_bdev(bdev);
5175107741fcSKonrad Sztyber 	ut_fini_bdev();
51762a2b7296SJim Harris }
51772a2b7296SJim Harris 
51787cd20dd3SShuhei Matsumoto static void
51799e386832SArtur Paszkiewicz bdev_quiesce_done(void *ctx, int status)
51809e386832SArtur Paszkiewicz {
51819e386832SArtur Paszkiewicz 	g_lock_lba_range_done = true;
51829e386832SArtur Paszkiewicz }
51839e386832SArtur Paszkiewicz 
51849e386832SArtur Paszkiewicz static void
51859e386832SArtur Paszkiewicz bdev_unquiesce_done(void *ctx, int status)
51869e386832SArtur Paszkiewicz {
51879e386832SArtur Paszkiewicz 	g_unlock_lba_range_done = true;
51889e386832SArtur Paszkiewicz }
51899e386832SArtur Paszkiewicz 
51909e386832SArtur Paszkiewicz static void
5191e7912a28SArtur Paszkiewicz bdev_quiesce_done_unquiesce(void *ctx, int status)
5192e7912a28SArtur Paszkiewicz {
5193e7912a28SArtur Paszkiewicz 	struct spdk_bdev *bdev = ctx;
5194e7912a28SArtur Paszkiewicz 	int rc;
5195e7912a28SArtur Paszkiewicz 
5196e7912a28SArtur Paszkiewicz 	g_lock_lba_range_done = true;
5197e7912a28SArtur Paszkiewicz 
5198e7912a28SArtur Paszkiewicz 	rc = spdk_bdev_unquiesce(bdev, &bdev_ut_if, bdev_unquiesce_done, NULL);
5199e7912a28SArtur Paszkiewicz 	CU_ASSERT(rc == 0);
5200e7912a28SArtur Paszkiewicz }
5201e7912a28SArtur Paszkiewicz 
5202e7912a28SArtur Paszkiewicz static void
52039e386832SArtur Paszkiewicz bdev_quiesce(void)
52049e386832SArtur Paszkiewicz {
52059e386832SArtur Paszkiewicz 	struct spdk_bdev *bdev;
52069e386832SArtur Paszkiewicz 	struct spdk_bdev_desc *desc = NULL;
52079e386832SArtur Paszkiewicz 	struct spdk_io_channel *io_ch;
52089e386832SArtur Paszkiewicz 	struct spdk_bdev_channel *channel;
52099e386832SArtur Paszkiewicz 	struct lba_range *range;
5210effe7a01SArtur Paszkiewicz 	struct spdk_bdev_io *bdev_io;
52119e386832SArtur Paszkiewicz 	int ctx1;
52129e386832SArtur Paszkiewicz 	int rc;
52139e386832SArtur Paszkiewicz 
52149e386832SArtur Paszkiewicz 	ut_init_bdev(NULL);
52159e386832SArtur Paszkiewicz 	bdev = allocate_bdev("bdev0");
52169e386832SArtur Paszkiewicz 
52179e386832SArtur Paszkiewicz 	rc = spdk_bdev_open_ext("bdev0", true, bdev_ut_event_cb, NULL, &desc);
52189e386832SArtur Paszkiewicz 	CU_ASSERT(rc == 0);
52199e386832SArtur Paszkiewicz 	CU_ASSERT(desc != NULL);
52209e386832SArtur Paszkiewicz 	CU_ASSERT(bdev == spdk_bdev_desc_get_bdev(desc));
52219e386832SArtur Paszkiewicz 	io_ch = spdk_bdev_get_io_channel(desc);
52229e386832SArtur Paszkiewicz 	CU_ASSERT(io_ch != NULL);
52239e386832SArtur Paszkiewicz 	channel = spdk_io_channel_get_ctx(io_ch);
52249e386832SArtur Paszkiewicz 
52259e386832SArtur Paszkiewicz 	g_lock_lba_range_done = false;
52269e386832SArtur Paszkiewicz 	rc = spdk_bdev_quiesce(bdev, &bdev_ut_if, bdev_quiesce_done, &ctx1);
52279e386832SArtur Paszkiewicz 	CU_ASSERT(rc == 0);
52289e386832SArtur Paszkiewicz 	poll_threads();
52299e386832SArtur Paszkiewicz 
52309e386832SArtur Paszkiewicz 	CU_ASSERT(g_lock_lba_range_done == true);
52319e386832SArtur Paszkiewicz 	range = TAILQ_FIRST(&channel->locked_ranges);
52329e386832SArtur Paszkiewicz 	SPDK_CU_ASSERT_FATAL(range != NULL);
52339e386832SArtur Paszkiewicz 	CU_ASSERT(range->offset == 0);
52349e386832SArtur Paszkiewicz 	CU_ASSERT(range->length == bdev->blockcnt);
52359e386832SArtur Paszkiewicz 	CU_ASSERT(range->owner_ch == NULL);
52369d5dd7ccSArtur Paszkiewicz 	range = TAILQ_FIRST(&bdev_ut_if.internal.quiesced_ranges);
52379d5dd7ccSArtur Paszkiewicz 	SPDK_CU_ASSERT_FATAL(range != NULL);
52389d5dd7ccSArtur Paszkiewicz 	CU_ASSERT(range->offset == 0);
52399d5dd7ccSArtur Paszkiewicz 	CU_ASSERT(range->length == bdev->blockcnt);
52409d5dd7ccSArtur Paszkiewicz 	CU_ASSERT(range->owner_ch == NULL);
52419e386832SArtur Paszkiewicz 
52429e386832SArtur Paszkiewicz 	g_unlock_lba_range_done = false;
52439e386832SArtur Paszkiewicz 	rc = spdk_bdev_unquiesce(bdev, &bdev_ut_if, bdev_unquiesce_done, &ctx1);
52449e386832SArtur Paszkiewicz 	CU_ASSERT(rc == 0);
52459e386832SArtur Paszkiewicz 	spdk_delay_us(100);
52469e386832SArtur Paszkiewicz 	poll_threads();
52479e386832SArtur Paszkiewicz 
52489e386832SArtur Paszkiewicz 	CU_ASSERT(g_unlock_lba_range_done == true);
52499e386832SArtur Paszkiewicz 	CU_ASSERT(TAILQ_EMPTY(&channel->locked_ranges));
52509d5dd7ccSArtur Paszkiewicz 	CU_ASSERT(TAILQ_EMPTY(&bdev_ut_if.internal.quiesced_ranges));
52519e386832SArtur Paszkiewicz 
52529e386832SArtur Paszkiewicz 	g_lock_lba_range_done = false;
52539e386832SArtur Paszkiewicz 	rc = spdk_bdev_quiesce_range(bdev, &bdev_ut_if, 20, 10, bdev_quiesce_done, &ctx1);
52549e386832SArtur Paszkiewicz 	CU_ASSERT(rc == 0);
52559e386832SArtur Paszkiewicz 	poll_threads();
52569e386832SArtur Paszkiewicz 
52579e386832SArtur Paszkiewicz 	CU_ASSERT(g_lock_lba_range_done == true);
52589e386832SArtur Paszkiewicz 	range = TAILQ_FIRST(&channel->locked_ranges);
52599e386832SArtur Paszkiewicz 	SPDK_CU_ASSERT_FATAL(range != NULL);
52609e386832SArtur Paszkiewicz 	CU_ASSERT(range->offset == 20);
52619e386832SArtur Paszkiewicz 	CU_ASSERT(range->length == 10);
52629e386832SArtur Paszkiewicz 	CU_ASSERT(range->owner_ch == NULL);
52639d5dd7ccSArtur Paszkiewicz 	range = TAILQ_FIRST(&bdev_ut_if.internal.quiesced_ranges);
52649d5dd7ccSArtur Paszkiewicz 	SPDK_CU_ASSERT_FATAL(range != NULL);
52659d5dd7ccSArtur Paszkiewicz 	CU_ASSERT(range->offset == 20);
52669d5dd7ccSArtur Paszkiewicz 	CU_ASSERT(range->length == 10);
52679d5dd7ccSArtur Paszkiewicz 	CU_ASSERT(range->owner_ch == NULL);
52689e386832SArtur Paszkiewicz 
52699e386832SArtur Paszkiewicz 	/* Unlocks must exactly match a lock. */
52709e386832SArtur Paszkiewicz 	g_unlock_lba_range_done = false;
52719d5dd7ccSArtur Paszkiewicz 	rc = spdk_bdev_unquiesce_range(bdev, &bdev_ut_if, 20, 1, bdev_unquiesce_done, &ctx1);
52729d5dd7ccSArtur Paszkiewicz 	CU_ASSERT(rc == -EINVAL);
52739d5dd7ccSArtur Paszkiewicz 	CU_ASSERT(g_unlock_lba_range_done == false);
52749d5dd7ccSArtur Paszkiewicz 
52759e386832SArtur Paszkiewicz 	rc = spdk_bdev_unquiesce_range(bdev, &bdev_ut_if, 20, 10, bdev_unquiesce_done, &ctx1);
52769e386832SArtur Paszkiewicz 	CU_ASSERT(rc == 0);
52779e386832SArtur Paszkiewicz 	spdk_delay_us(100);
52789e386832SArtur Paszkiewicz 	poll_threads();
52799e386832SArtur Paszkiewicz 
52809e386832SArtur Paszkiewicz 	CU_ASSERT(g_unlock_lba_range_done == true);
52819e386832SArtur Paszkiewicz 	CU_ASSERT(TAILQ_EMPTY(&channel->locked_ranges));
52829d5dd7ccSArtur Paszkiewicz 	CU_ASSERT(TAILQ_EMPTY(&bdev_ut_if.internal.quiesced_ranges));
52839e386832SArtur Paszkiewicz 
5284e7912a28SArtur Paszkiewicz 	/* Test unquiesce from quiesce cb */
5285e7912a28SArtur Paszkiewicz 	g_lock_lba_range_done = false;
5286e7912a28SArtur Paszkiewicz 	g_unlock_lba_range_done = false;
5287e7912a28SArtur Paszkiewicz 	rc = spdk_bdev_quiesce(bdev, &bdev_ut_if, bdev_quiesce_done_unquiesce, bdev);
5288e7912a28SArtur Paszkiewicz 	CU_ASSERT(rc == 0);
5289e7912a28SArtur Paszkiewicz 	poll_threads();
5290e7912a28SArtur Paszkiewicz 
5291e7912a28SArtur Paszkiewicz 	CU_ASSERT(g_lock_lba_range_done == true);
5292e7912a28SArtur Paszkiewicz 	CU_ASSERT(g_unlock_lba_range_done == true);
5293e7912a28SArtur Paszkiewicz 
5294effe7a01SArtur Paszkiewicz 	/* Test quiesce with read I/O */
5295effe7a01SArtur Paszkiewicz 	g_lock_lba_range_done = false;
5296effe7a01SArtur Paszkiewicz 	g_unlock_lba_range_done = false;
5297effe7a01SArtur Paszkiewicz 	g_io_done = false;
5298effe7a01SArtur Paszkiewicz 	rc = spdk_bdev_read_blocks(desc, io_ch, (void *)0xF000, 20, 1, io_done, &ctx1);
5299effe7a01SArtur Paszkiewicz 	CU_ASSERT(rc == 0);
5300effe7a01SArtur Paszkiewicz 
5301effe7a01SArtur Paszkiewicz 	rc = spdk_bdev_quiesce(bdev, &bdev_ut_if, bdev_quiesce_done, &ctx1);
5302effe7a01SArtur Paszkiewicz 	CU_ASSERT(rc == 0);
5303effe7a01SArtur Paszkiewicz 	poll_threads();
5304effe7a01SArtur Paszkiewicz 
5305effe7a01SArtur Paszkiewicz 	CU_ASSERT(g_io_done == false);
5306effe7a01SArtur Paszkiewicz 	CU_ASSERT(g_lock_lba_range_done == false);
5307effe7a01SArtur Paszkiewicz 	range = TAILQ_FIRST(&channel->locked_ranges);
5308effe7a01SArtur Paszkiewicz 	SPDK_CU_ASSERT_FATAL(range != NULL);
5309effe7a01SArtur Paszkiewicz 
5310effe7a01SArtur Paszkiewicz 	stub_complete_io(1);
5311effe7a01SArtur Paszkiewicz 	spdk_delay_us(100);
5312effe7a01SArtur Paszkiewicz 	poll_threads();
5313effe7a01SArtur Paszkiewicz 	CU_ASSERT(g_io_done == true);
5314effe7a01SArtur Paszkiewicz 	CU_ASSERT(g_lock_lba_range_done == true);
5315effe7a01SArtur Paszkiewicz 	CU_ASSERT(TAILQ_EMPTY(&channel->io_locked));
5316effe7a01SArtur Paszkiewicz 
5317effe7a01SArtur Paszkiewicz 	g_io_done = false;
5318effe7a01SArtur Paszkiewicz 	rc = spdk_bdev_read_blocks(desc, io_ch, (void *)0xF000, 20, 1, io_done, &ctx1);
5319effe7a01SArtur Paszkiewicz 	CU_ASSERT(rc == 0);
5320effe7a01SArtur Paszkiewicz 
5321effe7a01SArtur Paszkiewicz 	bdev_io = TAILQ_FIRST(&channel->io_locked);
5322effe7a01SArtur Paszkiewicz 	SPDK_CU_ASSERT_FATAL(bdev_io != NULL);
5323effe7a01SArtur Paszkiewicz 	CU_ASSERT(bdev_io->u.bdev.offset_blocks == 20);
5324effe7a01SArtur Paszkiewicz 	CU_ASSERT(bdev_io->u.bdev.num_blocks == 1);
5325effe7a01SArtur Paszkiewicz 
5326effe7a01SArtur Paszkiewicz 	rc = spdk_bdev_unquiesce(bdev, &bdev_ut_if, bdev_unquiesce_done, &ctx1);
5327effe7a01SArtur Paszkiewicz 	CU_ASSERT(rc == 0);
5328effe7a01SArtur Paszkiewicz 	spdk_delay_us(100);
5329effe7a01SArtur Paszkiewicz 	poll_threads();
5330effe7a01SArtur Paszkiewicz 
5331effe7a01SArtur Paszkiewicz 	CU_ASSERT(g_unlock_lba_range_done == true);
5332effe7a01SArtur Paszkiewicz 	CU_ASSERT(TAILQ_EMPTY(&channel->locked_ranges));
5333effe7a01SArtur Paszkiewicz 	CU_ASSERT(TAILQ_EMPTY(&bdev_ut_if.internal.quiesced_ranges));
5334effe7a01SArtur Paszkiewicz 
5335effe7a01SArtur Paszkiewicz 	CU_ASSERT(TAILQ_EMPTY(&channel->io_locked));
5336effe7a01SArtur Paszkiewicz 	spdk_bdev_io_complete(bdev_io, SPDK_BDEV_IO_STATUS_SUCCESS);
5337effe7a01SArtur Paszkiewicz 	poll_threads();
5338effe7a01SArtur Paszkiewicz 	CU_ASSERT(g_io_done == true);
5339effe7a01SArtur Paszkiewicz 
53409e386832SArtur Paszkiewicz 	spdk_put_io_channel(io_ch);
53419e386832SArtur Paszkiewicz 	spdk_bdev_close(desc);
53429e386832SArtur Paszkiewicz 	free_bdev(bdev);
53439e386832SArtur Paszkiewicz 	ut_fini_bdev();
53449e386832SArtur Paszkiewicz }
53459e386832SArtur Paszkiewicz 
53469e386832SArtur Paszkiewicz static void
53477cd20dd3SShuhei Matsumoto abort_done(struct spdk_bdev_io *bdev_io, bool success, void *cb_arg)
53487cd20dd3SShuhei Matsumoto {
53497cd20dd3SShuhei Matsumoto 	g_abort_done = true;
53507cd20dd3SShuhei Matsumoto 	g_abort_status = bdev_io->internal.status;
53517cd20dd3SShuhei Matsumoto 	spdk_bdev_free_io(bdev_io);
53527cd20dd3SShuhei Matsumoto }
53537cd20dd3SShuhei Matsumoto 
53547cd20dd3SShuhei Matsumoto static void
53557cd20dd3SShuhei Matsumoto bdev_io_abort(void)
53567cd20dd3SShuhei Matsumoto {
53577cd20dd3SShuhei Matsumoto 	struct spdk_bdev *bdev;
53587cd20dd3SShuhei Matsumoto 	struct spdk_bdev_desc *desc = NULL;
53597cd20dd3SShuhei Matsumoto 	struct spdk_io_channel *io_ch;
536097a5ea57SShuhei Matsumoto 	struct spdk_bdev_channel *channel;
536197a5ea57SShuhei Matsumoto 	struct spdk_bdev_mgmt_channel *mgmt_ch;
5362f420b9efSZiye Yang 	struct spdk_bdev_opts bdev_opts = {};
5363b45556e2SChangpeng Liu 	struct iovec iov[SPDK_BDEV_IO_NUM_CHILD_IOV * 2];
536497a5ea57SShuhei Matsumoto 	uint64_t io_ctx1 = 0, io_ctx2 = 0, i;
53657cd20dd3SShuhei Matsumoto 	int rc;
53667cd20dd3SShuhei Matsumoto 
5367f420b9efSZiye Yang 	spdk_bdev_get_opts(&bdev_opts, sizeof(bdev_opts));
5368f420b9efSZiye Yang 	bdev_opts.bdev_io_pool_size = 7;
5369f420b9efSZiye Yang 	bdev_opts.bdev_io_cache_size = 2;
5370107741fcSKonrad Sztyber 	ut_init_bdev(&bdev_opts);
53717cd20dd3SShuhei Matsumoto 
53727cd20dd3SShuhei Matsumoto 	bdev = allocate_bdev("bdev0");
53737cd20dd3SShuhei Matsumoto 
537475dfecbbSShuhei Matsumoto 	rc = spdk_bdev_open_ext("bdev0", true, bdev_ut_event_cb, NULL, &desc);
53757cd20dd3SShuhei Matsumoto 	CU_ASSERT(rc == 0);
53767cd20dd3SShuhei Matsumoto 	CU_ASSERT(desc != NULL);
537775dfecbbSShuhei Matsumoto 	CU_ASSERT(bdev == spdk_bdev_desc_get_bdev(desc));
53787cd20dd3SShuhei Matsumoto 	io_ch = spdk_bdev_get_io_channel(desc);
53797cd20dd3SShuhei Matsumoto 	CU_ASSERT(io_ch != NULL);
538097a5ea57SShuhei Matsumoto 	channel = spdk_io_channel_get_ctx(io_ch);
538197a5ea57SShuhei Matsumoto 	mgmt_ch = channel->shared_resource->mgmt_ch;
53827cd20dd3SShuhei Matsumoto 
53837cd20dd3SShuhei Matsumoto 	g_abort_done = false;
53847cd20dd3SShuhei Matsumoto 
53857cd20dd3SShuhei Matsumoto 	ut_enable_io_type(SPDK_BDEV_IO_TYPE_ABORT, false);
53867cd20dd3SShuhei Matsumoto 
53877cd20dd3SShuhei Matsumoto 	rc = spdk_bdev_abort(desc, io_ch, &io_ctx1, abort_done, NULL);
53887cd20dd3SShuhei Matsumoto 	CU_ASSERT(rc == -ENOTSUP);
53897cd20dd3SShuhei Matsumoto 
53907cd20dd3SShuhei Matsumoto 	ut_enable_io_type(SPDK_BDEV_IO_TYPE_ABORT, true);
53917cd20dd3SShuhei Matsumoto 
53927cd20dd3SShuhei Matsumoto 	rc = spdk_bdev_abort(desc, io_ch, &io_ctx2, abort_done, NULL);
53937cd20dd3SShuhei Matsumoto 	CU_ASSERT(rc == 0);
53947cd20dd3SShuhei Matsumoto 	CU_ASSERT(g_abort_done == true);
53957cd20dd3SShuhei Matsumoto 	CU_ASSERT(g_abort_status == SPDK_BDEV_IO_STATUS_FAILED);
53967cd20dd3SShuhei Matsumoto 
53977cd20dd3SShuhei Matsumoto 	/* Test the case that the target I/O was successfully aborted. */
53987cd20dd3SShuhei Matsumoto 	g_io_done = false;
53997cd20dd3SShuhei Matsumoto 
54007cd20dd3SShuhei Matsumoto 	rc = spdk_bdev_read_blocks(desc, io_ch, NULL, 0, 1, io_done, &io_ctx1);
54017cd20dd3SShuhei Matsumoto 	CU_ASSERT(rc == 0);
54027cd20dd3SShuhei Matsumoto 	CU_ASSERT(g_io_done == false);
54037cd20dd3SShuhei Matsumoto 
54047cd20dd3SShuhei Matsumoto 	g_abort_done = false;
54057cd20dd3SShuhei Matsumoto 	g_io_exp_status = SPDK_BDEV_IO_STATUS_SUCCESS;
54067cd20dd3SShuhei Matsumoto 
54077cd20dd3SShuhei Matsumoto 	rc = spdk_bdev_abort(desc, io_ch, &io_ctx1, abort_done, NULL);
54087cd20dd3SShuhei Matsumoto 	CU_ASSERT(rc == 0);
54097cd20dd3SShuhei Matsumoto 	CU_ASSERT(g_io_done == true);
54107cd20dd3SShuhei Matsumoto 	CU_ASSERT(g_io_status == SPDK_BDEV_IO_STATUS_FAILED);
54117cd20dd3SShuhei Matsumoto 	stub_complete_io(1);
54127cd20dd3SShuhei Matsumoto 	CU_ASSERT(g_abort_done == true);
54137cd20dd3SShuhei Matsumoto 	CU_ASSERT(g_abort_status == SPDK_BDEV_IO_STATUS_SUCCESS);
54147cd20dd3SShuhei Matsumoto 
54157cd20dd3SShuhei Matsumoto 	/* Test the case that the target I/O was not aborted because it completed
54167cd20dd3SShuhei Matsumoto 	 * in the middle of execution of the abort.
54177cd20dd3SShuhei Matsumoto 	 */
54187cd20dd3SShuhei Matsumoto 	g_io_done = false;
54197cd20dd3SShuhei Matsumoto 
54207cd20dd3SShuhei Matsumoto 	rc = spdk_bdev_read_blocks(desc, io_ch, NULL, 0, 1, io_done, &io_ctx1);
54217cd20dd3SShuhei Matsumoto 	CU_ASSERT(rc == 0);
54227cd20dd3SShuhei Matsumoto 	CU_ASSERT(g_io_done == false);
54237cd20dd3SShuhei Matsumoto 
54247cd20dd3SShuhei Matsumoto 	g_abort_done = false;
54257cd20dd3SShuhei Matsumoto 	g_io_exp_status = SPDK_BDEV_IO_STATUS_FAILED;
54267cd20dd3SShuhei Matsumoto 
54277cd20dd3SShuhei Matsumoto 	rc = spdk_bdev_abort(desc, io_ch, &io_ctx1, abort_done, NULL);
54287cd20dd3SShuhei Matsumoto 	CU_ASSERT(rc == 0);
54297cd20dd3SShuhei Matsumoto 	CU_ASSERT(g_io_done == false);
54307cd20dd3SShuhei Matsumoto 
54317cd20dd3SShuhei Matsumoto 	g_io_exp_status = SPDK_BDEV_IO_STATUS_SUCCESS;
54327cd20dd3SShuhei Matsumoto 	stub_complete_io(1);
54337cd20dd3SShuhei Matsumoto 	CU_ASSERT(g_io_done == true);
54347cd20dd3SShuhei Matsumoto 	CU_ASSERT(g_io_status == SPDK_BDEV_IO_STATUS_SUCCESS);
54357cd20dd3SShuhei Matsumoto 
54367cd20dd3SShuhei Matsumoto 	g_io_exp_status = SPDK_BDEV_IO_STATUS_FAILED;
54377cd20dd3SShuhei Matsumoto 	stub_complete_io(1);
54387cd20dd3SShuhei Matsumoto 	CU_ASSERT(g_abort_done == true);
54397cd20dd3SShuhei Matsumoto 	CU_ASSERT(g_abort_status == SPDK_BDEV_IO_STATUS_SUCCESS);
54407cd20dd3SShuhei Matsumoto 
54417cd20dd3SShuhei Matsumoto 	g_io_exp_status = SPDK_BDEV_IO_STATUS_SUCCESS;
54427cd20dd3SShuhei Matsumoto 
544397a5ea57SShuhei Matsumoto 	bdev->optimal_io_boundary = 16;
544497a5ea57SShuhei Matsumoto 	bdev->split_on_optimal_io_boundary = true;
544597a5ea57SShuhei Matsumoto 
544697a5ea57SShuhei Matsumoto 	/* Test that a single-vector command which is split is aborted correctly.
544797a5ea57SShuhei Matsumoto 	 * Offset 14, length 8, payload 0xF000
544897a5ea57SShuhei Matsumoto 	 *  Child - Offset 14, length 2, payload 0xF000
544997a5ea57SShuhei Matsumoto 	 *  Child - Offset 16, length 6, payload 0xF000 + 2 * 512
545097a5ea57SShuhei Matsumoto 	 */
545197a5ea57SShuhei Matsumoto 	g_io_done = false;
545297a5ea57SShuhei Matsumoto 
545397a5ea57SShuhei Matsumoto 	rc = spdk_bdev_read_blocks(desc, io_ch, (void *)0xF000, 14, 8, io_done, &io_ctx1);
545497a5ea57SShuhei Matsumoto 	CU_ASSERT(rc == 0);
545597a5ea57SShuhei Matsumoto 	CU_ASSERT(g_io_done == false);
545697a5ea57SShuhei Matsumoto 
545797a5ea57SShuhei Matsumoto 	CU_ASSERT(g_bdev_ut_channel->outstanding_io_count == 2);
545897a5ea57SShuhei Matsumoto 
545997a5ea57SShuhei Matsumoto 	g_io_exp_status = SPDK_BDEV_IO_STATUS_SUCCESS;
546097a5ea57SShuhei Matsumoto 
546197a5ea57SShuhei Matsumoto 	rc = spdk_bdev_abort(desc, io_ch, &io_ctx1, abort_done, NULL);
546297a5ea57SShuhei Matsumoto 	CU_ASSERT(rc == 0);
546397a5ea57SShuhei Matsumoto 	CU_ASSERT(g_io_done == true);
546497a5ea57SShuhei Matsumoto 	CU_ASSERT(g_io_status == SPDK_BDEV_IO_STATUS_FAILED);
546597a5ea57SShuhei Matsumoto 	stub_complete_io(2);
546697a5ea57SShuhei Matsumoto 	CU_ASSERT(g_abort_done == true);
546797a5ea57SShuhei Matsumoto 	CU_ASSERT(g_abort_status == SPDK_BDEV_IO_STATUS_SUCCESS);
546897a5ea57SShuhei Matsumoto 
546997a5ea57SShuhei Matsumoto 	/* Test that a multi-vector command that needs to be split by strip and then
547097a5ea57SShuhei Matsumoto 	 * needs to be split is aborted correctly. Abort is requested before the second
547197a5ea57SShuhei Matsumoto 	 * child I/O was submitted. The parent I/O should complete with failure without
547297a5ea57SShuhei Matsumoto 	 * submitting the second child I/O.
547397a5ea57SShuhei Matsumoto 	 */
5474b45556e2SChangpeng Liu 	for (i = 0; i < SPDK_BDEV_IO_NUM_CHILD_IOV * 2; i++) {
547597a5ea57SShuhei Matsumoto 		iov[i].iov_base = (void *)((i + 1) * 0x10000);
547697a5ea57SShuhei Matsumoto 		iov[i].iov_len = 512;
547797a5ea57SShuhei Matsumoto 	}
547897a5ea57SShuhei Matsumoto 
5479b45556e2SChangpeng Liu 	bdev->optimal_io_boundary = SPDK_BDEV_IO_NUM_CHILD_IOV;
548097a5ea57SShuhei Matsumoto 	g_io_done = false;
5481b45556e2SChangpeng Liu 	rc = spdk_bdev_readv_blocks(desc, io_ch, iov, SPDK_BDEV_IO_NUM_CHILD_IOV * 2, 0,
5482b45556e2SChangpeng Liu 				    SPDK_BDEV_IO_NUM_CHILD_IOV * 2, io_done, &io_ctx1);
548397a5ea57SShuhei Matsumoto 	CU_ASSERT(rc == 0);
548497a5ea57SShuhei Matsumoto 	CU_ASSERT(g_io_done == false);
548597a5ea57SShuhei Matsumoto 
548697a5ea57SShuhei Matsumoto 	CU_ASSERT(g_bdev_ut_channel->outstanding_io_count == 1);
548797a5ea57SShuhei Matsumoto 
548897a5ea57SShuhei Matsumoto 	g_io_exp_status = SPDK_BDEV_IO_STATUS_SUCCESS;
548997a5ea57SShuhei Matsumoto 
549097a5ea57SShuhei Matsumoto 	rc = spdk_bdev_abort(desc, io_ch, &io_ctx1, abort_done, NULL);
549197a5ea57SShuhei Matsumoto 	CU_ASSERT(rc == 0);
549297a5ea57SShuhei Matsumoto 	CU_ASSERT(g_io_done == true);
549397a5ea57SShuhei Matsumoto 	CU_ASSERT(g_io_status == SPDK_BDEV_IO_STATUS_FAILED);
549497a5ea57SShuhei Matsumoto 	stub_complete_io(1);
549597a5ea57SShuhei Matsumoto 	CU_ASSERT(g_abort_done == true);
549697a5ea57SShuhei Matsumoto 	CU_ASSERT(g_abort_status == SPDK_BDEV_IO_STATUS_SUCCESS);
549797a5ea57SShuhei Matsumoto 
549897a5ea57SShuhei Matsumoto 	g_io_exp_status = SPDK_BDEV_IO_STATUS_SUCCESS;
549997a5ea57SShuhei Matsumoto 
550097a5ea57SShuhei Matsumoto 	CU_ASSERT(g_bdev_ut_channel->outstanding_io_count == 0);
550197a5ea57SShuhei Matsumoto 
550297a5ea57SShuhei Matsumoto 	bdev->optimal_io_boundary = 16;
550397a5ea57SShuhei Matsumoto 	g_io_done = false;
550497a5ea57SShuhei Matsumoto 
5505153e3344SShuhei Matsumoto 	/* Test that a single-vector command which is split is aborted correctly.
550697a5ea57SShuhei Matsumoto 	 * Differently from the above, the child abort request will be submitted
550797a5ea57SShuhei Matsumoto 	 * sequentially due to the capacity of spdk_bdev_io.
550897a5ea57SShuhei Matsumoto 	 */
550997a5ea57SShuhei Matsumoto 	rc = spdk_bdev_read_blocks(desc, io_ch, (void *)0xF000, 14, 50, io_done, &io_ctx1);
551097a5ea57SShuhei Matsumoto 	CU_ASSERT(rc == 0);
551197a5ea57SShuhei Matsumoto 	CU_ASSERT(g_io_done == false);
551297a5ea57SShuhei Matsumoto 
551397a5ea57SShuhei Matsumoto 	CU_ASSERT(g_bdev_ut_channel->outstanding_io_count == 4);
551497a5ea57SShuhei Matsumoto 
551597a5ea57SShuhei Matsumoto 	g_abort_done = false;
551697a5ea57SShuhei Matsumoto 	g_io_exp_status = SPDK_BDEV_IO_STATUS_SUCCESS;
551797a5ea57SShuhei Matsumoto 
551897a5ea57SShuhei Matsumoto 	rc = spdk_bdev_abort(desc, io_ch, &io_ctx1, abort_done, NULL);
551997a5ea57SShuhei Matsumoto 	CU_ASSERT(rc == 0);
552097a5ea57SShuhei Matsumoto 	CU_ASSERT(!TAILQ_EMPTY(&mgmt_ch->io_wait_queue));
552197a5ea57SShuhei Matsumoto 	CU_ASSERT(g_bdev_ut_channel->outstanding_io_count == 4);
552297a5ea57SShuhei Matsumoto 
552397a5ea57SShuhei Matsumoto 	stub_complete_io(1);
552497a5ea57SShuhei Matsumoto 	CU_ASSERT(g_io_done == true);
552597a5ea57SShuhei Matsumoto 	CU_ASSERT(g_io_status == SPDK_BDEV_IO_STATUS_FAILED);
552697a5ea57SShuhei Matsumoto 	stub_complete_io(3);
552797a5ea57SShuhei Matsumoto 	CU_ASSERT(g_abort_done == true);
552897a5ea57SShuhei Matsumoto 	CU_ASSERT(g_abort_status == SPDK_BDEV_IO_STATUS_SUCCESS);
552997a5ea57SShuhei Matsumoto 
553097a5ea57SShuhei Matsumoto 	g_io_exp_status = SPDK_BDEV_IO_STATUS_SUCCESS;
553197a5ea57SShuhei Matsumoto 
553297a5ea57SShuhei Matsumoto 	CU_ASSERT(g_bdev_ut_channel->outstanding_io_count == 0);
553397a5ea57SShuhei Matsumoto 
5534153e3344SShuhei Matsumoto 	bdev->split_on_optimal_io_boundary = false;
5535153e3344SShuhei Matsumoto 	bdev->split_on_write_unit = true;
5536153e3344SShuhei Matsumoto 	bdev->write_unit_size = 16;
5537153e3344SShuhei Matsumoto 
5538153e3344SShuhei Matsumoto 	/* Test that a single-vector command which is split is aborted correctly.
5539153e3344SShuhei Matsumoto 	 * Offset 16, length 32, payload 0xF000
5540153e3344SShuhei Matsumoto 	 *  Child - Offset 16, length 16, payload 0xF000
5541153e3344SShuhei Matsumoto 	 *  Child - Offset 32, length 16, payload 0xF000 + 16 * 512
5542153e3344SShuhei Matsumoto 	 *
5543153e3344SShuhei Matsumoto 	 * Use bdev->split_on_write_unit as a split condition.
5544153e3344SShuhei Matsumoto 	 */
5545153e3344SShuhei Matsumoto 	g_io_done = false;
5546153e3344SShuhei Matsumoto 
5547153e3344SShuhei Matsumoto 	rc = spdk_bdev_write_blocks(desc, io_ch, (void *)0xF000, 16, 32, io_done, &io_ctx1);
5548153e3344SShuhei Matsumoto 	CU_ASSERT(rc == 0);
5549153e3344SShuhei Matsumoto 	CU_ASSERT(g_io_done == false);
5550153e3344SShuhei Matsumoto 
5551153e3344SShuhei Matsumoto 	CU_ASSERT(g_bdev_ut_channel->outstanding_io_count == 2);
5552153e3344SShuhei Matsumoto 
5553153e3344SShuhei Matsumoto 	g_io_exp_status = SPDK_BDEV_IO_STATUS_SUCCESS;
5554153e3344SShuhei Matsumoto 
5555153e3344SShuhei Matsumoto 	rc = spdk_bdev_abort(desc, io_ch, &io_ctx1, abort_done, NULL);
5556153e3344SShuhei Matsumoto 	CU_ASSERT(rc == 0);
5557153e3344SShuhei Matsumoto 	CU_ASSERT(g_io_done == true);
5558153e3344SShuhei Matsumoto 	CU_ASSERT(g_io_status == SPDK_BDEV_IO_STATUS_FAILED);
5559153e3344SShuhei Matsumoto 	stub_complete_io(2);
5560153e3344SShuhei Matsumoto 	CU_ASSERT(g_abort_done == true);
5561153e3344SShuhei Matsumoto 	CU_ASSERT(g_abort_status == SPDK_BDEV_IO_STATUS_SUCCESS);
5562153e3344SShuhei Matsumoto 
5563153e3344SShuhei Matsumoto 	g_io_exp_status = SPDK_BDEV_IO_STATUS_SUCCESS;
5564153e3344SShuhei Matsumoto 
5565153e3344SShuhei Matsumoto 	CU_ASSERT(g_bdev_ut_channel->outstanding_io_count == 0);
5566153e3344SShuhei Matsumoto 
5567153e3344SShuhei Matsumoto 	bdev->split_on_write_unit = false;
5568153e3344SShuhei Matsumoto 	bdev->max_rw_size = 16;
5569153e3344SShuhei Matsumoto 
5570153e3344SShuhei Matsumoto 	/* Test that a single-vector command which is split is aborted correctly.
5571153e3344SShuhei Matsumoto 	 * Use bdev->max_rw_size as a split condition.
5572153e3344SShuhei Matsumoto 	 */
5573153e3344SShuhei Matsumoto 	g_io_done = false;
5574153e3344SShuhei Matsumoto 
5575153e3344SShuhei Matsumoto 	rc = spdk_bdev_write_blocks(desc, io_ch, (void *)0xF000, 0, 32, io_done, &io_ctx1);
5576153e3344SShuhei Matsumoto 	CU_ASSERT(rc == 0);
5577153e3344SShuhei Matsumoto 	CU_ASSERT(g_io_done == false);
5578153e3344SShuhei Matsumoto 
5579153e3344SShuhei Matsumoto 	CU_ASSERT(g_bdev_ut_channel->outstanding_io_count == 2);
5580153e3344SShuhei Matsumoto 
5581153e3344SShuhei Matsumoto 	g_io_exp_status = SPDK_BDEV_IO_STATUS_SUCCESS;
5582153e3344SShuhei Matsumoto 
5583153e3344SShuhei Matsumoto 	rc = spdk_bdev_abort(desc, io_ch, &io_ctx1, abort_done, NULL);
5584153e3344SShuhei Matsumoto 	CU_ASSERT(rc == 0);
5585153e3344SShuhei Matsumoto 	CU_ASSERT(g_io_done == true);
5586153e3344SShuhei Matsumoto 	CU_ASSERT(g_io_status == SPDK_BDEV_IO_STATUS_FAILED);
5587153e3344SShuhei Matsumoto 	stub_complete_io(2);
5588153e3344SShuhei Matsumoto 	CU_ASSERT(g_abort_done == true);
5589153e3344SShuhei Matsumoto 	CU_ASSERT(g_abort_status == SPDK_BDEV_IO_STATUS_SUCCESS);
5590153e3344SShuhei Matsumoto 
5591153e3344SShuhei Matsumoto 	g_io_exp_status = SPDK_BDEV_IO_STATUS_SUCCESS;
5592153e3344SShuhei Matsumoto 
5593153e3344SShuhei Matsumoto 	CU_ASSERT(g_bdev_ut_channel->outstanding_io_count == 0);
5594153e3344SShuhei Matsumoto 
5595153e3344SShuhei Matsumoto 	bdev->max_rw_size = 0;
5596153e3344SShuhei Matsumoto 	bdev->max_segment_size = 512 * 16;
5597153e3344SShuhei Matsumoto 	bdev->max_num_segments = 1;
5598153e3344SShuhei Matsumoto 
5599153e3344SShuhei Matsumoto 	/* Test that a single-vector command which is split is aborted correctly.
5600153e3344SShuhei Matsumoto 	 * Use bdev->max_segment_size and bdev->max_num_segments together as split conditions.
5601153e3344SShuhei Matsumoto 	 *
5602153e3344SShuhei Matsumoto 	 * One single-vector command is changed to one two-vectors command, but
5603153e3344SShuhei Matsumoto 	 * bdev->max_num_segments is 1 and it is split into two single-vector commands.
5604153e3344SShuhei Matsumoto 	 */
5605153e3344SShuhei Matsumoto 	g_io_done = false;
5606153e3344SShuhei Matsumoto 
5607153e3344SShuhei Matsumoto 	rc = spdk_bdev_write_blocks(desc, io_ch, (void *)0xF000, 0, 32, io_done, &io_ctx1);
5608153e3344SShuhei Matsumoto 	CU_ASSERT(rc == 0);
5609153e3344SShuhei Matsumoto 	CU_ASSERT(g_io_done == false);
5610153e3344SShuhei Matsumoto 
5611153e3344SShuhei Matsumoto 	CU_ASSERT(g_bdev_ut_channel->outstanding_io_count == 2);
5612153e3344SShuhei Matsumoto 
5613153e3344SShuhei Matsumoto 	g_io_exp_status = SPDK_BDEV_IO_STATUS_SUCCESS;
5614153e3344SShuhei Matsumoto 
5615153e3344SShuhei Matsumoto 	rc = spdk_bdev_abort(desc, io_ch, &io_ctx1, abort_done, NULL);
5616153e3344SShuhei Matsumoto 	CU_ASSERT(rc == 0);
5617153e3344SShuhei Matsumoto 	CU_ASSERT(g_io_done == true);
5618153e3344SShuhei Matsumoto 	CU_ASSERT(g_io_status == SPDK_BDEV_IO_STATUS_FAILED);
5619153e3344SShuhei Matsumoto 	stub_complete_io(2);
5620153e3344SShuhei Matsumoto 	CU_ASSERT(g_abort_done == true);
5621153e3344SShuhei Matsumoto 	CU_ASSERT(g_abort_status == SPDK_BDEV_IO_STATUS_SUCCESS);
5622153e3344SShuhei Matsumoto 
5623153e3344SShuhei Matsumoto 	g_io_exp_status = SPDK_BDEV_IO_STATUS_SUCCESS;
5624153e3344SShuhei Matsumoto 
5625153e3344SShuhei Matsumoto 	CU_ASSERT(g_bdev_ut_channel->outstanding_io_count == 0);
5626153e3344SShuhei Matsumoto 
56277cd20dd3SShuhei Matsumoto 	spdk_put_io_channel(io_ch);
56287cd20dd3SShuhei Matsumoto 	spdk_bdev_close(desc);
56297cd20dd3SShuhei Matsumoto 	free_bdev(bdev);
5630107741fcSKonrad Sztyber 	ut_fini_bdev();
56317cd20dd3SShuhei Matsumoto }
56327cd20dd3SShuhei Matsumoto 
5633f420b9efSZiye Yang static void
5634d0b4deabSChangpeng Liu bdev_unmap(void)
5635d0b4deabSChangpeng Liu {
5636d0b4deabSChangpeng Liu 	struct spdk_bdev *bdev;
5637d0b4deabSChangpeng Liu 	struct spdk_bdev_desc *desc = NULL;
5638d0b4deabSChangpeng Liu 	struct spdk_io_channel *ioch;
5639d0b4deabSChangpeng Liu 	struct spdk_bdev_channel *bdev_ch;
5640d0b4deabSChangpeng Liu 	struct ut_expected_io *expected_io;
5641d0b4deabSChangpeng Liu 	struct spdk_bdev_opts bdev_opts = {};
5642d0b4deabSChangpeng Liu 	uint32_t i, num_outstanding;
5643d0b4deabSChangpeng Liu 	uint64_t offset, num_blocks, max_unmap_blocks, num_children;
5644d0b4deabSChangpeng Liu 	int rc;
5645d0b4deabSChangpeng Liu 
5646d0b4deabSChangpeng Liu 	spdk_bdev_get_opts(&bdev_opts, sizeof(bdev_opts));
5647d0b4deabSChangpeng Liu 	bdev_opts.bdev_io_pool_size = 512;
5648d0b4deabSChangpeng Liu 	bdev_opts.bdev_io_cache_size = 64;
5649107741fcSKonrad Sztyber 	ut_init_bdev(&bdev_opts);
5650d0b4deabSChangpeng Liu 
5651d0b4deabSChangpeng Liu 	bdev = allocate_bdev("bdev");
5652d0b4deabSChangpeng Liu 
5653d0b4deabSChangpeng Liu 	rc = spdk_bdev_open_ext("bdev", true, bdev_ut_event_cb, NULL, &desc);
5654d0b4deabSChangpeng Liu 	CU_ASSERT_EQUAL(rc, 0);
5655d0b4deabSChangpeng Liu 	SPDK_CU_ASSERT_FATAL(desc != NULL);
5656d0b4deabSChangpeng Liu 	CU_ASSERT(bdev == spdk_bdev_desc_get_bdev(desc));
5657d0b4deabSChangpeng Liu 	ioch = spdk_bdev_get_io_channel(desc);
5658d0b4deabSChangpeng Liu 	SPDK_CU_ASSERT_FATAL(ioch != NULL);
5659d0b4deabSChangpeng Liu 	bdev_ch = spdk_io_channel_get_ctx(ioch);
5660d0b4deabSChangpeng Liu 	CU_ASSERT(TAILQ_EMPTY(&bdev_ch->io_submitted));
5661d0b4deabSChangpeng Liu 
5662d0b4deabSChangpeng Liu 	fn_table.submit_request = stub_submit_request;
5663d0b4deabSChangpeng Liu 	g_io_exp_status = SPDK_BDEV_IO_STATUS_SUCCESS;
5664d0b4deabSChangpeng Liu 
5665d0b4deabSChangpeng Liu 	/* Case 1: First test the request won't be split */
5666d0b4deabSChangpeng Liu 	num_blocks = 32;
5667d0b4deabSChangpeng Liu 
5668d0b4deabSChangpeng Liu 	g_io_done = false;
5669d0b4deabSChangpeng Liu 	expected_io = ut_alloc_expected_io(SPDK_BDEV_IO_TYPE_UNMAP, 0, num_blocks, 0);
5670d0b4deabSChangpeng Liu 	TAILQ_INSERT_TAIL(&g_bdev_ut_channel->expected_io, expected_io, link);
5671d0b4deabSChangpeng Liu 	rc = spdk_bdev_unmap_blocks(desc, ioch, 0, num_blocks, io_done, NULL);
5672d0b4deabSChangpeng Liu 	CU_ASSERT_EQUAL(rc, 0);
5673d0b4deabSChangpeng Liu 	CU_ASSERT(g_io_done == false);
5674d0b4deabSChangpeng Liu 	CU_ASSERT(g_bdev_ut_channel->outstanding_io_count == 1);
5675d0b4deabSChangpeng Liu 	stub_complete_io(1);
5676d0b4deabSChangpeng Liu 	CU_ASSERT(g_io_done == true);
5677d0b4deabSChangpeng Liu 	CU_ASSERT(g_bdev_ut_channel->outstanding_io_count == 0);
5678d0b4deabSChangpeng Liu 
5679d0b4deabSChangpeng Liu 	/* Case 2: Test the split with 2 children requests */
5680d0b4deabSChangpeng Liu 	bdev->max_unmap = 8;
5681d0b4deabSChangpeng Liu 	bdev->max_unmap_segments = 2;
5682d0b4deabSChangpeng Liu 	max_unmap_blocks = bdev->max_unmap * bdev->max_unmap_segments;
5683d0b4deabSChangpeng Liu 	num_blocks = max_unmap_blocks * 2;
5684d0b4deabSChangpeng Liu 	offset = 0;
5685d0b4deabSChangpeng Liu 
5686d0b4deabSChangpeng Liu 	g_io_done = false;
5687d0b4deabSChangpeng Liu 	for (i = 0; i < 2; i++) {
5688d0b4deabSChangpeng Liu 		expected_io = ut_alloc_expected_io(SPDK_BDEV_IO_TYPE_UNMAP, offset, max_unmap_blocks, 0);
5689d0b4deabSChangpeng Liu 		TAILQ_INSERT_TAIL(&g_bdev_ut_channel->expected_io, expected_io, link);
5690d0b4deabSChangpeng Liu 		offset += max_unmap_blocks;
5691d0b4deabSChangpeng Liu 	}
5692d0b4deabSChangpeng Liu 
5693d0b4deabSChangpeng Liu 	rc = spdk_bdev_unmap_blocks(desc, ioch, 0, num_blocks, io_done, NULL);
5694d0b4deabSChangpeng Liu 	CU_ASSERT_EQUAL(rc, 0);
5695d0b4deabSChangpeng Liu 	CU_ASSERT(g_io_done == false);
5696d0b4deabSChangpeng Liu 	CU_ASSERT(g_bdev_ut_channel->outstanding_io_count == 2);
5697d0b4deabSChangpeng Liu 	stub_complete_io(2);
5698d0b4deabSChangpeng Liu 	CU_ASSERT(g_io_done == true);
5699d0b4deabSChangpeng Liu 	CU_ASSERT(g_bdev_ut_channel->outstanding_io_count == 0);
5700d0b4deabSChangpeng Liu 
5701d0b4deabSChangpeng Liu 	/* Case 3: Test the split with 15 children requests, will finish 8 requests first */
5702d0b4deabSChangpeng Liu 	num_children = 15;
5703d0b4deabSChangpeng Liu 	num_blocks = max_unmap_blocks * num_children;
5704d0b4deabSChangpeng Liu 	g_io_done = false;
5705d0b4deabSChangpeng Liu 	offset = 0;
5706d0b4deabSChangpeng Liu 	for (i = 0; i < num_children; i++) {
5707d0b4deabSChangpeng Liu 		expected_io = ut_alloc_expected_io(SPDK_BDEV_IO_TYPE_UNMAP, offset, max_unmap_blocks, 0);
5708d0b4deabSChangpeng Liu 		TAILQ_INSERT_TAIL(&g_bdev_ut_channel->expected_io, expected_io, link);
5709d0b4deabSChangpeng Liu 		offset += max_unmap_blocks;
5710d0b4deabSChangpeng Liu 	}
5711d0b4deabSChangpeng Liu 
5712d0b4deabSChangpeng Liu 	rc = spdk_bdev_unmap_blocks(desc, ioch, 0, num_blocks, io_done, NULL);
5713d0b4deabSChangpeng Liu 	CU_ASSERT_EQUAL(rc, 0);
5714d0b4deabSChangpeng Liu 	CU_ASSERT(g_io_done == false);
5715d0b4deabSChangpeng Liu 
5716d0b4deabSChangpeng Liu 	while (num_children > 0) {
5717734de260SChangpeng Liu 		num_outstanding = spdk_min(num_children, SPDK_BDEV_MAX_CHILDREN_UNMAP_WRITE_ZEROES_REQS);
5718d0b4deabSChangpeng Liu 		CU_ASSERT(g_bdev_ut_channel->outstanding_io_count == num_outstanding);
5719d0b4deabSChangpeng Liu 		stub_complete_io(num_outstanding);
5720d0b4deabSChangpeng Liu 		num_children -= num_outstanding;
5721d0b4deabSChangpeng Liu 	}
5722d0b4deabSChangpeng Liu 	CU_ASSERT(g_io_done == true);
5723d0b4deabSChangpeng Liu 
5724d0b4deabSChangpeng Liu 	spdk_put_io_channel(ioch);
5725d0b4deabSChangpeng Liu 	spdk_bdev_close(desc);
5726d0b4deabSChangpeng Liu 	free_bdev(bdev);
5727107741fcSKonrad Sztyber 	ut_fini_bdev();
5728d0b4deabSChangpeng Liu }
5729d0b4deabSChangpeng Liu 
5730d0b4deabSChangpeng Liu static void
5731e7fbdf15SChangpeng Liu bdev_write_zeroes_split_test(void)
5732e7fbdf15SChangpeng Liu {
5733e7fbdf15SChangpeng Liu 	struct spdk_bdev *bdev;
5734e7fbdf15SChangpeng Liu 	struct spdk_bdev_desc *desc = NULL;
5735e7fbdf15SChangpeng Liu 	struct spdk_io_channel *ioch;
5736e7fbdf15SChangpeng Liu 	struct spdk_bdev_channel *bdev_ch;
5737e7fbdf15SChangpeng Liu 	struct ut_expected_io *expected_io;
5738e7fbdf15SChangpeng Liu 	struct spdk_bdev_opts bdev_opts = {};
5739e7fbdf15SChangpeng Liu 	uint32_t i, num_outstanding;
5740e7fbdf15SChangpeng Liu 	uint64_t offset, num_blocks, max_write_zeroes_blocks, num_children;
5741e7fbdf15SChangpeng Liu 	int rc;
5742e7fbdf15SChangpeng Liu 
5743e7fbdf15SChangpeng Liu 	spdk_bdev_get_opts(&bdev_opts, sizeof(bdev_opts));
5744e7fbdf15SChangpeng Liu 	bdev_opts.bdev_io_pool_size = 512;
5745e7fbdf15SChangpeng Liu 	bdev_opts.bdev_io_cache_size = 64;
5746107741fcSKonrad Sztyber 	ut_init_bdev(&bdev_opts);
5747e7fbdf15SChangpeng Liu 
5748e7fbdf15SChangpeng Liu 	bdev = allocate_bdev("bdev");
5749e7fbdf15SChangpeng Liu 
5750e7fbdf15SChangpeng Liu 	rc = spdk_bdev_open_ext("bdev", true, bdev_ut_event_cb, NULL, &desc);
5751e7fbdf15SChangpeng Liu 	CU_ASSERT_EQUAL(rc, 0);
5752e7fbdf15SChangpeng Liu 	SPDK_CU_ASSERT_FATAL(desc != NULL);
5753e7fbdf15SChangpeng Liu 	CU_ASSERT(bdev == spdk_bdev_desc_get_bdev(desc));
5754e7fbdf15SChangpeng Liu 	ioch = spdk_bdev_get_io_channel(desc);
5755e7fbdf15SChangpeng Liu 	SPDK_CU_ASSERT_FATAL(ioch != NULL);
5756e7fbdf15SChangpeng Liu 	bdev_ch = spdk_io_channel_get_ctx(ioch);
5757e7fbdf15SChangpeng Liu 	CU_ASSERT(TAILQ_EMPTY(&bdev_ch->io_submitted));
5758e7fbdf15SChangpeng Liu 
5759e7fbdf15SChangpeng Liu 	fn_table.submit_request = stub_submit_request;
5760e7fbdf15SChangpeng Liu 	g_io_exp_status = SPDK_BDEV_IO_STATUS_SUCCESS;
5761e7fbdf15SChangpeng Liu 
5762e7fbdf15SChangpeng Liu 	/* Case 1: First test the request won't be split */
5763e7fbdf15SChangpeng Liu 	num_blocks = 32;
5764e7fbdf15SChangpeng Liu 
5765e7fbdf15SChangpeng Liu 	g_io_done = false;
5766e7fbdf15SChangpeng Liu 	expected_io = ut_alloc_expected_io(SPDK_BDEV_IO_TYPE_WRITE_ZEROES, 0, num_blocks, 0);
5767e7fbdf15SChangpeng Liu 	TAILQ_INSERT_TAIL(&g_bdev_ut_channel->expected_io, expected_io, link);
5768e7fbdf15SChangpeng Liu 	rc = spdk_bdev_write_zeroes_blocks(desc, ioch, 0, num_blocks, io_done, NULL);
5769e7fbdf15SChangpeng Liu 	CU_ASSERT_EQUAL(rc, 0);
5770e7fbdf15SChangpeng Liu 	CU_ASSERT(g_io_done == false);
5771e7fbdf15SChangpeng Liu 	CU_ASSERT(g_bdev_ut_channel->outstanding_io_count == 1);
5772e7fbdf15SChangpeng Liu 	stub_complete_io(1);
5773e7fbdf15SChangpeng Liu 	CU_ASSERT(g_io_done == true);
5774e7fbdf15SChangpeng Liu 	CU_ASSERT(g_bdev_ut_channel->outstanding_io_count == 0);
5775e7fbdf15SChangpeng Liu 
5776e7fbdf15SChangpeng Liu 	/* Case 2: Test the split with 2 children requests */
5777e7fbdf15SChangpeng Liu 	max_write_zeroes_blocks = 8;
5778e7fbdf15SChangpeng Liu 	bdev->max_write_zeroes = max_write_zeroes_blocks;
5779e7fbdf15SChangpeng Liu 	num_blocks = max_write_zeroes_blocks * 2;
5780e7fbdf15SChangpeng Liu 	offset = 0;
5781e7fbdf15SChangpeng Liu 
5782e7fbdf15SChangpeng Liu 	g_io_done = false;
5783e7fbdf15SChangpeng Liu 	for (i = 0; i < 2; i++) {
5784e7fbdf15SChangpeng Liu 		expected_io = ut_alloc_expected_io(SPDK_BDEV_IO_TYPE_WRITE_ZEROES, offset, max_write_zeroes_blocks,
5785e7fbdf15SChangpeng Liu 						   0);
5786e7fbdf15SChangpeng Liu 		TAILQ_INSERT_TAIL(&g_bdev_ut_channel->expected_io, expected_io, link);
5787e7fbdf15SChangpeng Liu 		offset += max_write_zeroes_blocks;
5788e7fbdf15SChangpeng Liu 	}
5789e7fbdf15SChangpeng Liu 
5790e7fbdf15SChangpeng Liu 	rc = spdk_bdev_write_zeroes_blocks(desc, ioch, 0, num_blocks, io_done, NULL);
5791e7fbdf15SChangpeng Liu 	CU_ASSERT_EQUAL(rc, 0);
5792e7fbdf15SChangpeng Liu 	CU_ASSERT(g_io_done == false);
5793e7fbdf15SChangpeng Liu 	CU_ASSERT(g_bdev_ut_channel->outstanding_io_count == 2);
5794e7fbdf15SChangpeng Liu 	stub_complete_io(2);
5795e7fbdf15SChangpeng Liu 	CU_ASSERT(g_io_done == true);
5796e7fbdf15SChangpeng Liu 	CU_ASSERT(g_bdev_ut_channel->outstanding_io_count == 0);
5797e7fbdf15SChangpeng Liu 
5798e7fbdf15SChangpeng Liu 	/* Case 3: Test the split with 15 children requests, will finish 8 requests first */
5799e7fbdf15SChangpeng Liu 	num_children = 15;
5800e7fbdf15SChangpeng Liu 	num_blocks = max_write_zeroes_blocks * num_children;
5801e7fbdf15SChangpeng Liu 	g_io_done = false;
5802e7fbdf15SChangpeng Liu 	offset = 0;
5803e7fbdf15SChangpeng Liu 	for (i = 0; i < num_children; i++) {
5804e7fbdf15SChangpeng Liu 		expected_io = ut_alloc_expected_io(SPDK_BDEV_IO_TYPE_WRITE_ZEROES, offset, max_write_zeroes_blocks,
5805e7fbdf15SChangpeng Liu 						   0);
5806e7fbdf15SChangpeng Liu 		TAILQ_INSERT_TAIL(&g_bdev_ut_channel->expected_io, expected_io, link);
5807e7fbdf15SChangpeng Liu 		offset += max_write_zeroes_blocks;
5808e7fbdf15SChangpeng Liu 	}
5809e7fbdf15SChangpeng Liu 
5810e7fbdf15SChangpeng Liu 	rc = spdk_bdev_write_zeroes_blocks(desc, ioch, 0, num_blocks, io_done, NULL);
5811e7fbdf15SChangpeng Liu 	CU_ASSERT_EQUAL(rc, 0);
5812e7fbdf15SChangpeng Liu 	CU_ASSERT(g_io_done == false);
5813e7fbdf15SChangpeng Liu 
5814e7fbdf15SChangpeng Liu 	while (num_children > 0) {
5815e7fbdf15SChangpeng Liu 		num_outstanding = spdk_min(num_children, SPDK_BDEV_MAX_CHILDREN_UNMAP_WRITE_ZEROES_REQS);
5816e7fbdf15SChangpeng Liu 		CU_ASSERT(g_bdev_ut_channel->outstanding_io_count == num_outstanding);
5817e7fbdf15SChangpeng Liu 		stub_complete_io(num_outstanding);
5818e7fbdf15SChangpeng Liu 		num_children -= num_outstanding;
5819e7fbdf15SChangpeng Liu 	}
5820e7fbdf15SChangpeng Liu 	CU_ASSERT(g_io_done == true);
5821e7fbdf15SChangpeng Liu 
5822e7fbdf15SChangpeng Liu 	spdk_put_io_channel(ioch);
5823e7fbdf15SChangpeng Liu 	spdk_bdev_close(desc);
5824e7fbdf15SChangpeng Liu 	free_bdev(bdev);
5825107741fcSKonrad Sztyber 	ut_fini_bdev();
5826e7fbdf15SChangpeng Liu }
5827e7fbdf15SChangpeng Liu 
5828e7fbdf15SChangpeng Liu static void
5829f420b9efSZiye Yang bdev_set_options_test(void)
5830f420b9efSZiye Yang {
5831f420b9efSZiye Yang 	struct spdk_bdev_opts bdev_opts = {};
5832f420b9efSZiye Yang 	int rc;
5833f420b9efSZiye Yang 
5834f420b9efSZiye Yang 	/* Case1: Do not set opts_size */
5835f420b9efSZiye Yang 	rc = spdk_bdev_set_opts(&bdev_opts);
5836f420b9efSZiye Yang 	CU_ASSERT(rc == -1);
5837f420b9efSZiye Yang }
5838f420b9efSZiye Yang 
5839c3a58489SAlexey Marchuk static struct spdk_memory_domain *g_bdev_memory_domain = (struct spdk_memory_domain *) 0xf00df00d;
5840c3a58489SAlexey Marchuk 
5841c3a58489SAlexey Marchuk static int
5842c3a58489SAlexey Marchuk test_bdev_get_supported_dma_device_types_op(void *ctx, struct spdk_memory_domain **domains,
5843c3a58489SAlexey Marchuk 		int array_size)
5844c3a58489SAlexey Marchuk {
5845c3a58489SAlexey Marchuk 	if (array_size > 0 && domains) {
5846c3a58489SAlexey Marchuk 		domains[0] = g_bdev_memory_domain;
5847c3a58489SAlexey Marchuk 	}
5848c3a58489SAlexey Marchuk 
5849c3a58489SAlexey Marchuk 	return 1;
5850c3a58489SAlexey Marchuk }
5851c3a58489SAlexey Marchuk 
5852c3a58489SAlexey Marchuk static void
5853c3a58489SAlexey Marchuk bdev_get_memory_domains(void)
5854c3a58489SAlexey Marchuk {
5855c3a58489SAlexey Marchuk 	struct spdk_bdev_fn_table fn_table = {
5856c3a58489SAlexey Marchuk 		.get_memory_domains = test_bdev_get_supported_dma_device_types_op
5857c3a58489SAlexey Marchuk 	};
5858c3a58489SAlexey Marchuk 	struct spdk_bdev bdev = { .fn_table = &fn_table };
5859c3a58489SAlexey Marchuk 	struct spdk_memory_domain *domains[2] = {};
5860c3a58489SAlexey Marchuk 	int rc;
5861c3a58489SAlexey Marchuk 
5862c3a58489SAlexey Marchuk 	/* bdev is NULL */
5863c3a58489SAlexey Marchuk 	rc = spdk_bdev_get_memory_domains(NULL, domains, 2);
5864c3a58489SAlexey Marchuk 	CU_ASSERT(rc == -EINVAL);
5865c3a58489SAlexey Marchuk 
5866c3a58489SAlexey Marchuk 	/* domains is NULL */
5867c3a58489SAlexey Marchuk 	rc = spdk_bdev_get_memory_domains(&bdev, NULL, 2);
5868c3a58489SAlexey Marchuk 	CU_ASSERT(rc == 1);
5869c3a58489SAlexey Marchuk 
5870c3a58489SAlexey Marchuk 	/* array size is 0 */
5871c3a58489SAlexey Marchuk 	rc = spdk_bdev_get_memory_domains(&bdev, domains, 0);
5872c3a58489SAlexey Marchuk 	CU_ASSERT(rc == 1);
5873c3a58489SAlexey Marchuk 
5874c3a58489SAlexey Marchuk 	/* get_supported_dma_device_types op is set */
5875c3a58489SAlexey Marchuk 	rc = spdk_bdev_get_memory_domains(&bdev, domains, 2);
5876c3a58489SAlexey Marchuk 	CU_ASSERT(rc == 1);
5877c3a58489SAlexey Marchuk 	CU_ASSERT(domains[0] == g_bdev_memory_domain);
5878c3a58489SAlexey Marchuk 
5879c3a58489SAlexey Marchuk 	/* get_supported_dma_device_types op is not set */
5880c3a58489SAlexey Marchuk 	fn_table.get_memory_domains = NULL;
5881c3a58489SAlexey Marchuk 	rc = spdk_bdev_get_memory_domains(&bdev, domains, 2);
5882c3a58489SAlexey Marchuk 	CU_ASSERT(rc == 0);
5883c3a58489SAlexey Marchuk }
5884c3a58489SAlexey Marchuk 
5885ac6f2bddSAlexey Marchuk static void
5886442e13c0SJonas Pfefferle _bdev_io_ext(struct spdk_bdev_ext_io_opts *ext_io_opts)
5887442e13c0SJonas Pfefferle {
5888442e13c0SJonas Pfefferle 	struct spdk_bdev *bdev;
5889442e13c0SJonas Pfefferle 	struct spdk_bdev_desc *desc = NULL;
5890442e13c0SJonas Pfefferle 	struct spdk_io_channel *io_ch;
5891442e13c0SJonas Pfefferle 	char io_buf[512];
5892442e13c0SJonas Pfefferle 	struct iovec iov = { .iov_base = io_buf, .iov_len = 512 };
5893442e13c0SJonas Pfefferle 	struct ut_expected_io *expected_io;
5894442e13c0SJonas Pfefferle 	int rc;
5895442e13c0SJonas Pfefferle 
5896107741fcSKonrad Sztyber 	ut_init_bdev(NULL);
5897442e13c0SJonas Pfefferle 
5898442e13c0SJonas Pfefferle 	bdev = allocate_bdev("bdev0");
5899442e13c0SJonas Pfefferle 	bdev->md_interleave = false;
5900442e13c0SJonas Pfefferle 	bdev->md_len = 8;
5901442e13c0SJonas Pfefferle 
5902442e13c0SJonas Pfefferle 	rc = spdk_bdev_open_ext("bdev0", true, bdev_ut_event_cb, NULL, &desc);
5903442e13c0SJonas Pfefferle 	CU_ASSERT(rc == 0);
5904442e13c0SJonas Pfefferle 	SPDK_CU_ASSERT_FATAL(desc != NULL);
5905442e13c0SJonas Pfefferle 	CU_ASSERT(bdev == spdk_bdev_desc_get_bdev(desc));
5906442e13c0SJonas Pfefferle 	io_ch = spdk_bdev_get_io_channel(desc);
5907442e13c0SJonas Pfefferle 	CU_ASSERT(io_ch != NULL);
5908442e13c0SJonas Pfefferle 
5909442e13c0SJonas Pfefferle 	/* read */
5910442e13c0SJonas Pfefferle 	g_io_done = false;
5911442e13c0SJonas Pfefferle 	expected_io = ut_alloc_expected_io(SPDK_BDEV_IO_TYPE_READ, 32, 14, 1);
5912442e13c0SJonas Pfefferle 	if (ext_io_opts) {
5913442e13c0SJonas Pfefferle 		expected_io->md_buf = ext_io_opts->metadata;
5914442e13c0SJonas Pfefferle 	}
5915442e13c0SJonas Pfefferle 	ut_expected_io_set_iov(expected_io, 0, iov.iov_base, iov.iov_len);
5916442e13c0SJonas Pfefferle 	TAILQ_INSERT_TAIL(&g_bdev_ut_channel->expected_io, expected_io, link);
5917442e13c0SJonas Pfefferle 
5918442e13c0SJonas Pfefferle 	rc = spdk_bdev_readv_blocks_ext(desc, io_ch, &iov, 1, 32, 14, io_done, NULL, ext_io_opts);
5919442e13c0SJonas Pfefferle 
5920442e13c0SJonas Pfefferle 	CU_ASSERT(rc == 0);
5921442e13c0SJonas Pfefferle 	CU_ASSERT(g_io_done == false);
5922442e13c0SJonas Pfefferle 	CU_ASSERT(g_bdev_ut_channel->outstanding_io_count == 1);
5923442e13c0SJonas Pfefferle 	stub_complete_io(1);
5924442e13c0SJonas Pfefferle 	CU_ASSERT(g_io_done == true);
5925442e13c0SJonas Pfefferle 
5926442e13c0SJonas Pfefferle 	/* write */
5927442e13c0SJonas Pfefferle 	g_io_done = false;
5928442e13c0SJonas Pfefferle 	expected_io = ut_alloc_expected_io(SPDK_BDEV_IO_TYPE_WRITE, 32, 14, 1);
5929442e13c0SJonas Pfefferle 	if (ext_io_opts) {
5930442e13c0SJonas Pfefferle 		expected_io->md_buf = ext_io_opts->metadata;
5931442e13c0SJonas Pfefferle 	}
5932442e13c0SJonas Pfefferle 	ut_expected_io_set_iov(expected_io, 0, iov.iov_base, iov.iov_len);
5933442e13c0SJonas Pfefferle 	TAILQ_INSERT_TAIL(&g_bdev_ut_channel->expected_io, expected_io, link);
5934442e13c0SJonas Pfefferle 
5935442e13c0SJonas Pfefferle 	rc = spdk_bdev_writev_blocks_ext(desc, io_ch, &iov, 1, 32, 14, io_done, NULL, ext_io_opts);
5936442e13c0SJonas Pfefferle 
5937442e13c0SJonas Pfefferle 	CU_ASSERT(rc == 0);
5938442e13c0SJonas Pfefferle 	CU_ASSERT(g_io_done == false);
5939442e13c0SJonas Pfefferle 	CU_ASSERT(g_bdev_ut_channel->outstanding_io_count == 1);
5940442e13c0SJonas Pfefferle 	stub_complete_io(1);
5941442e13c0SJonas Pfefferle 	CU_ASSERT(g_io_done == true);
5942442e13c0SJonas Pfefferle 
5943442e13c0SJonas Pfefferle 	spdk_put_io_channel(io_ch);
5944442e13c0SJonas Pfefferle 	spdk_bdev_close(desc);
5945442e13c0SJonas Pfefferle 	free_bdev(bdev);
5946107741fcSKonrad Sztyber 	ut_fini_bdev();
5947442e13c0SJonas Pfefferle 
5948442e13c0SJonas Pfefferle }
5949442e13c0SJonas Pfefferle 
5950442e13c0SJonas Pfefferle static void
5951442e13c0SJonas Pfefferle bdev_io_ext(void)
5952442e13c0SJonas Pfefferle {
5953442e13c0SJonas Pfefferle 	struct spdk_bdev_ext_io_opts ext_io_opts = {
5954442e13c0SJonas Pfefferle 		.metadata = (void *)0xFF000000,
5955bbd27a75SSlawomir Ptak 		.size = sizeof(ext_io_opts),
5956bbd27a75SSlawomir Ptak 		.dif_check_flags_exclude_mask = 0
5957442e13c0SJonas Pfefferle 	};
5958442e13c0SJonas Pfefferle 
5959442e13c0SJonas Pfefferle 	_bdev_io_ext(&ext_io_opts);
5960442e13c0SJonas Pfefferle }
5961442e13c0SJonas Pfefferle 
5962442e13c0SJonas Pfefferle static void
5963442e13c0SJonas Pfefferle bdev_io_ext_no_opts(void)
5964442e13c0SJonas Pfefferle {
5965442e13c0SJonas Pfefferle 	_bdev_io_ext(NULL);
5966442e13c0SJonas Pfefferle }
5967442e13c0SJonas Pfefferle 
5968442e13c0SJonas Pfefferle static void
5969442e13c0SJonas Pfefferle bdev_io_ext_invalid_opts(void)
5970442e13c0SJonas Pfefferle {
5971442e13c0SJonas Pfefferle 	struct spdk_bdev *bdev;
5972442e13c0SJonas Pfefferle 	struct spdk_bdev_desc *desc = NULL;
5973442e13c0SJonas Pfefferle 	struct spdk_io_channel *io_ch;
5974442e13c0SJonas Pfefferle 	char io_buf[512];
5975442e13c0SJonas Pfefferle 	struct iovec iov = { .iov_base = io_buf, .iov_len = 512 };
5976442e13c0SJonas Pfefferle 	struct spdk_bdev_ext_io_opts ext_io_opts = {
5977442e13c0SJonas Pfefferle 		.metadata = (void *)0xFF000000,
5978bbd27a75SSlawomir Ptak 		.size = sizeof(ext_io_opts),
5979bbd27a75SSlawomir Ptak 		.dif_check_flags_exclude_mask = 0
5980442e13c0SJonas Pfefferle 	};
5981442e13c0SJonas Pfefferle 	int rc;
5982442e13c0SJonas Pfefferle 
5983107741fcSKonrad Sztyber 	ut_init_bdev(NULL);
5984442e13c0SJonas Pfefferle 
5985442e13c0SJonas Pfefferle 	bdev = allocate_bdev("bdev0");
5986442e13c0SJonas Pfefferle 	bdev->md_interleave = false;
5987442e13c0SJonas Pfefferle 	bdev->md_len = 8;
5988442e13c0SJonas Pfefferle 
5989442e13c0SJonas Pfefferle 	rc = spdk_bdev_open_ext("bdev0", true, bdev_ut_event_cb, NULL, &desc);
5990442e13c0SJonas Pfefferle 	CU_ASSERT(rc == 0);
5991442e13c0SJonas Pfefferle 	SPDK_CU_ASSERT_FATAL(desc != NULL);
5992442e13c0SJonas Pfefferle 	CU_ASSERT(bdev == spdk_bdev_desc_get_bdev(desc));
5993442e13c0SJonas Pfefferle 	io_ch = spdk_bdev_get_io_channel(desc);
5994442e13c0SJonas Pfefferle 	CU_ASSERT(io_ch != NULL);
5995442e13c0SJonas Pfefferle 
5996442e13c0SJonas Pfefferle 	/* Test invalid ext_opts size */
5997442e13c0SJonas Pfefferle 	ext_io_opts.size = 0;
5998442e13c0SJonas Pfefferle 	rc = spdk_bdev_readv_blocks_ext(desc, io_ch, &iov, 1, 32, 14, io_done, NULL, &ext_io_opts);
5999442e13c0SJonas Pfefferle 	CU_ASSERT(rc == -EINVAL);
6000442e13c0SJonas Pfefferle 	rc = spdk_bdev_writev_blocks_ext(desc, io_ch, &iov, 1, 32, 14, io_done, NULL, &ext_io_opts);
6001442e13c0SJonas Pfefferle 	CU_ASSERT(rc == -EINVAL);
6002442e13c0SJonas Pfefferle 
6003442e13c0SJonas Pfefferle 	ext_io_opts.size = sizeof(ext_io_opts) * 2;
6004442e13c0SJonas Pfefferle 	rc = spdk_bdev_readv_blocks_ext(desc, io_ch, &iov, 1, 32, 14, io_done, NULL, &ext_io_opts);
6005442e13c0SJonas Pfefferle 	CU_ASSERT(rc == -EINVAL);
6006442e13c0SJonas Pfefferle 	rc = spdk_bdev_writev_blocks_ext(desc, io_ch, &iov, 1, 32, 14, io_done, NULL, &ext_io_opts);
6007442e13c0SJonas Pfefferle 	CU_ASSERT(rc == -EINVAL);
6008442e13c0SJonas Pfefferle 
6009442e13c0SJonas Pfefferle 	ext_io_opts.size = offsetof(struct spdk_bdev_ext_io_opts, metadata) +
6010442e13c0SJonas Pfefferle 			   sizeof(ext_io_opts.metadata) - 1;
6011442e13c0SJonas Pfefferle 	rc = spdk_bdev_readv_blocks_ext(desc, io_ch, &iov, 1, 32, 14, io_done, NULL, &ext_io_opts);
6012442e13c0SJonas Pfefferle 	CU_ASSERT(rc == -EINVAL);
6013442e13c0SJonas Pfefferle 	rc = spdk_bdev_writev_blocks_ext(desc, io_ch, &iov, 1, 32, 14, io_done, NULL, &ext_io_opts);
6014442e13c0SJonas Pfefferle 	CU_ASSERT(rc == -EINVAL);
6015442e13c0SJonas Pfefferle 
6016442e13c0SJonas Pfefferle 	spdk_put_io_channel(io_ch);
6017442e13c0SJonas Pfefferle 	spdk_bdev_close(desc);
6018442e13c0SJonas Pfefferle 	free_bdev(bdev);
6019107741fcSKonrad Sztyber 	ut_fini_bdev();
6020442e13c0SJonas Pfefferle }
6021442e13c0SJonas Pfefferle 
6022442e13c0SJonas Pfefferle static void
6023442e13c0SJonas Pfefferle bdev_io_ext_split(void)
6024ac6f2bddSAlexey Marchuk {
6025ac6f2bddSAlexey Marchuk 	struct spdk_bdev *bdev;
6026ac6f2bddSAlexey Marchuk 	struct spdk_bdev_desc *desc = NULL;
6027ac6f2bddSAlexey Marchuk 	struct spdk_io_channel *io_ch;
60281299439fSAlexey Marchuk 	char io_buf[512];
60291299439fSAlexey Marchuk 	struct iovec iov = { .iov_base = io_buf, .iov_len = 512 };
6030ac6f2bddSAlexey Marchuk 	struct ut_expected_io *expected_io;
6031ac6f2bddSAlexey Marchuk 	struct spdk_bdev_ext_io_opts ext_io_opts = {
60328e7688c5SAlexey Marchuk 		.metadata = (void *)0xFF000000,
6033bbd27a75SSlawomir Ptak 		.size = sizeof(ext_io_opts),
6034bbd27a75SSlawomir Ptak 		.dif_check_flags_exclude_mask = 0
6035ac6f2bddSAlexey Marchuk 	};
6036ac6f2bddSAlexey Marchuk 	int rc;
6037ac6f2bddSAlexey Marchuk 
6038107741fcSKonrad Sztyber 	ut_init_bdev(NULL);
6039ac6f2bddSAlexey Marchuk 
6040ac6f2bddSAlexey Marchuk 	bdev = allocate_bdev("bdev0");
6041ac6f2bddSAlexey Marchuk 	bdev->md_interleave = false;
6042ac6f2bddSAlexey Marchuk 	bdev->md_len = 8;
6043ac6f2bddSAlexey Marchuk 
6044ac6f2bddSAlexey Marchuk 	rc = spdk_bdev_open_ext("bdev0", true, bdev_ut_event_cb, NULL, &desc);
6045ac6f2bddSAlexey Marchuk 	CU_ASSERT(rc == 0);
6046ac6f2bddSAlexey Marchuk 	SPDK_CU_ASSERT_FATAL(desc != NULL);
6047ac6f2bddSAlexey Marchuk 	CU_ASSERT(bdev == spdk_bdev_desc_get_bdev(desc));
6048ac6f2bddSAlexey Marchuk 	io_ch = spdk_bdev_get_io_channel(desc);
6049ac6f2bddSAlexey Marchuk 	CU_ASSERT(io_ch != NULL);
6050ac6f2bddSAlexey Marchuk 
6051442e13c0SJonas Pfefferle 	/* Check that IO request with ext_opts and metadata is split correctly
60528e7688c5SAlexey Marchuk 	 * Offset 14, length 8, payload 0xF000
60538e7688c5SAlexey Marchuk 	 *  Child - Offset 14, length 2, payload 0xF000
60548e7688c5SAlexey Marchuk 	 *  Child - Offset 16, length 6, payload 0xF000 + 2 * 512
60558e7688c5SAlexey Marchuk 	 */
60568e7688c5SAlexey Marchuk 	bdev->optimal_io_boundary = 16;
60578e7688c5SAlexey Marchuk 	bdev->split_on_optimal_io_boundary = true;
60588e7688c5SAlexey Marchuk 	bdev->md_interleave = false;
60598e7688c5SAlexey Marchuk 	bdev->md_len = 8;
60608e7688c5SAlexey Marchuk 
60618e7688c5SAlexey Marchuk 	iov.iov_base = (void *)0xF000;
60628e7688c5SAlexey Marchuk 	iov.iov_len = 4096;
60638e7688c5SAlexey Marchuk 	memset(&ext_io_opts, 0, sizeof(ext_io_opts));
60648e7688c5SAlexey Marchuk 	ext_io_opts.metadata = (void *)0xFF000000;
60658e7688c5SAlexey Marchuk 	ext_io_opts.size = sizeof(ext_io_opts);
60668e7688c5SAlexey Marchuk 	g_io_done = false;
60678e7688c5SAlexey Marchuk 
60688e7688c5SAlexey Marchuk 	/* read */
60698e7688c5SAlexey Marchuk 	expected_io = ut_alloc_expected_io(SPDK_BDEV_IO_TYPE_READ, 14, 2, 1);
60708e7688c5SAlexey Marchuk 	expected_io->md_buf = ext_io_opts.metadata;
60718e7688c5SAlexey Marchuk 	ut_expected_io_set_iov(expected_io, 0, (void *)0xF000, 2 * 512);
60728e7688c5SAlexey Marchuk 	TAILQ_INSERT_TAIL(&g_bdev_ut_channel->expected_io, expected_io, link);
60738e7688c5SAlexey Marchuk 
60748e7688c5SAlexey Marchuk 	expected_io = ut_alloc_expected_io(SPDK_BDEV_IO_TYPE_READ, 16, 6, 1);
60758e7688c5SAlexey Marchuk 	expected_io->md_buf = ext_io_opts.metadata + 2 * 8;
60768e7688c5SAlexey Marchuk 	ut_expected_io_set_iov(expected_io, 0, (void *)(0xF000 + 2 * 512), 6 * 512);
60778e7688c5SAlexey Marchuk 	TAILQ_INSERT_TAIL(&g_bdev_ut_channel->expected_io, expected_io, link);
60788e7688c5SAlexey Marchuk 
60798e7688c5SAlexey Marchuk 	rc = spdk_bdev_readv_blocks_ext(desc, io_ch, &iov, 1, 14, 8, io_done, NULL, &ext_io_opts);
60808e7688c5SAlexey Marchuk 	CU_ASSERT(rc == 0);
60818e7688c5SAlexey Marchuk 	CU_ASSERT(g_io_done == false);
60828e7688c5SAlexey Marchuk 
60838e7688c5SAlexey Marchuk 	CU_ASSERT(g_bdev_ut_channel->outstanding_io_count == 2);
60848e7688c5SAlexey Marchuk 	stub_complete_io(2);
60858e7688c5SAlexey Marchuk 	CU_ASSERT(g_io_done == true);
60868e7688c5SAlexey Marchuk 	CU_ASSERT(g_bdev_ut_channel->outstanding_io_count == 0);
60878e7688c5SAlexey Marchuk 
60888e7688c5SAlexey Marchuk 	/* write */
60898e7688c5SAlexey Marchuk 	g_io_done = false;
60908e7688c5SAlexey Marchuk 	expected_io = ut_alloc_expected_io(SPDK_BDEV_IO_TYPE_WRITE, 14, 2, 1);
60918e7688c5SAlexey Marchuk 	expected_io->md_buf = ext_io_opts.metadata;
60928e7688c5SAlexey Marchuk 	ut_expected_io_set_iov(expected_io, 0, (void *)0xF000, 2 * 512);
60938e7688c5SAlexey Marchuk 	TAILQ_INSERT_TAIL(&g_bdev_ut_channel->expected_io, expected_io, link);
60948e7688c5SAlexey Marchuk 
60958e7688c5SAlexey Marchuk 	expected_io = ut_alloc_expected_io(SPDK_BDEV_IO_TYPE_WRITE, 16, 6, 1);
60968e7688c5SAlexey Marchuk 	expected_io->md_buf = ext_io_opts.metadata + 2 * 8;
60978e7688c5SAlexey Marchuk 	ut_expected_io_set_iov(expected_io, 0, (void *)(0xF000 + 2 * 512), 6 * 512);
60988e7688c5SAlexey Marchuk 	TAILQ_INSERT_TAIL(&g_bdev_ut_channel->expected_io, expected_io, link);
60998e7688c5SAlexey Marchuk 
61008e7688c5SAlexey Marchuk 	rc = spdk_bdev_writev_blocks_ext(desc, io_ch, &iov, 1, 14, 8, io_done, NULL, &ext_io_opts);
61018e7688c5SAlexey Marchuk 	CU_ASSERT(rc == 0);
61028e7688c5SAlexey Marchuk 	CU_ASSERT(g_io_done == false);
61038e7688c5SAlexey Marchuk 
61048e7688c5SAlexey Marchuk 	CU_ASSERT(g_bdev_ut_channel->outstanding_io_count == 2);
61058e7688c5SAlexey Marchuk 	stub_complete_io(2);
61068e7688c5SAlexey Marchuk 	CU_ASSERT(g_io_done == true);
61078e7688c5SAlexey Marchuk 	CU_ASSERT(g_bdev_ut_channel->outstanding_io_count == 0);
61088e7688c5SAlexey Marchuk 
6109442e13c0SJonas Pfefferle 	spdk_put_io_channel(io_ch);
6110442e13c0SJonas Pfefferle 	spdk_bdev_close(desc);
6111442e13c0SJonas Pfefferle 	free_bdev(bdev);
6112107741fcSKonrad Sztyber 	ut_fini_bdev();
6113442e13c0SJonas Pfefferle }
6114442e13c0SJonas Pfefferle 
6115442e13c0SJonas Pfefferle static void
6116442e13c0SJonas Pfefferle bdev_io_ext_bounce_buffer(void)
6117442e13c0SJonas Pfefferle {
6118442e13c0SJonas Pfefferle 	struct spdk_bdev *bdev;
6119442e13c0SJonas Pfefferle 	struct spdk_bdev_desc *desc = NULL;
6120442e13c0SJonas Pfefferle 	struct spdk_io_channel *io_ch;
6121442e13c0SJonas Pfefferle 	char io_buf[512];
6122442e13c0SJonas Pfefferle 	struct iovec iov = { .iov_base = io_buf, .iov_len = 512 };
612328bcf6a7SKonrad Sztyber 	struct ut_expected_io *expected_io, *aux_io;
6124442e13c0SJonas Pfefferle 	struct spdk_bdev_ext_io_opts ext_io_opts = {
6125442e13c0SJonas Pfefferle 		.metadata = (void *)0xFF000000,
6126bbd27a75SSlawomir Ptak 		.size = sizeof(ext_io_opts),
6127bbd27a75SSlawomir Ptak 		.dif_check_flags_exclude_mask = 0
6128442e13c0SJonas Pfefferle 	};
6129442e13c0SJonas Pfefferle 	int rc;
6130442e13c0SJonas Pfefferle 
6131107741fcSKonrad Sztyber 	ut_init_bdev(NULL);
6132442e13c0SJonas Pfefferle 
6133442e13c0SJonas Pfefferle 	bdev = allocate_bdev("bdev0");
6134442e13c0SJonas Pfefferle 	bdev->md_interleave = false;
6135442e13c0SJonas Pfefferle 	bdev->md_len = 8;
6136442e13c0SJonas Pfefferle 
6137442e13c0SJonas Pfefferle 	rc = spdk_bdev_open_ext("bdev0", true, bdev_ut_event_cb, NULL, &desc);
6138442e13c0SJonas Pfefferle 	CU_ASSERT(rc == 0);
6139442e13c0SJonas Pfefferle 	SPDK_CU_ASSERT_FATAL(desc != NULL);
6140442e13c0SJonas Pfefferle 	CU_ASSERT(bdev == spdk_bdev_desc_get_bdev(desc));
6141442e13c0SJonas Pfefferle 	io_ch = spdk_bdev_get_io_channel(desc);
6142442e13c0SJonas Pfefferle 	CU_ASSERT(io_ch != NULL);
6143442e13c0SJonas Pfefferle 
6144442e13c0SJonas Pfefferle 	/* Verify data pull/push
6145442e13c0SJonas Pfefferle 	 * bdev doesn't support memory domains, so buffers from bdev memory pool will be used */
61461299439fSAlexey Marchuk 	ext_io_opts.memory_domain = (struct spdk_memory_domain *)0xdeadbeef;
61471299439fSAlexey Marchuk 
6148442e13c0SJonas Pfefferle 	/* read */
61491299439fSAlexey Marchuk 	g_io_done = false;
61501299439fSAlexey Marchuk 	expected_io = ut_alloc_expected_io(SPDK_BDEV_IO_TYPE_READ, 32, 14, 1);
61511299439fSAlexey Marchuk 	ut_expected_io_set_iov(expected_io, 0, iov.iov_base, iov.iov_len);
61521299439fSAlexey Marchuk 	TAILQ_INSERT_TAIL(&g_bdev_ut_channel->expected_io, expected_io, link);
61531299439fSAlexey Marchuk 
61541299439fSAlexey Marchuk 	rc = spdk_bdev_readv_blocks_ext(desc, io_ch, &iov, 1, 32, 14, io_done, NULL, &ext_io_opts);
61551299439fSAlexey Marchuk 
61561299439fSAlexey Marchuk 	CU_ASSERT(rc == 0);
61571299439fSAlexey Marchuk 	CU_ASSERT(g_io_done == false);
61581299439fSAlexey Marchuk 	CU_ASSERT(g_bdev_ut_channel->outstanding_io_count == 1);
61591299439fSAlexey Marchuk 	stub_complete_io(1);
61601299439fSAlexey Marchuk 	CU_ASSERT(g_memory_domain_push_data_called == true);
61611299439fSAlexey Marchuk 	CU_ASSERT(g_io_done == true);
61621299439fSAlexey Marchuk 
6163442e13c0SJonas Pfefferle 	/* write */
61641299439fSAlexey Marchuk 	g_io_done = false;
61651299439fSAlexey Marchuk 	expected_io = ut_alloc_expected_io(SPDK_BDEV_IO_TYPE_WRITE, 32, 14, 1);
61661299439fSAlexey Marchuk 	ut_expected_io_set_iov(expected_io, 0, iov.iov_base, iov.iov_len);
61671299439fSAlexey Marchuk 	TAILQ_INSERT_TAIL(&g_bdev_ut_channel->expected_io, expected_io, link);
61681299439fSAlexey Marchuk 
61691299439fSAlexey Marchuk 	rc = spdk_bdev_writev_blocks_ext(desc, io_ch, &iov, 1, 32, 14, io_done, NULL, &ext_io_opts);
61701299439fSAlexey Marchuk 
61711299439fSAlexey Marchuk 	CU_ASSERT(rc == 0);
61721299439fSAlexey Marchuk 	CU_ASSERT(g_memory_domain_pull_data_called == true);
61731299439fSAlexey Marchuk 	CU_ASSERT(g_io_done == false);
61741299439fSAlexey Marchuk 	CU_ASSERT(g_bdev_ut_channel->outstanding_io_count == 1);
61751299439fSAlexey Marchuk 	stub_complete_io(1);
61761299439fSAlexey Marchuk 	CU_ASSERT(g_io_done == true);
61771299439fSAlexey Marchuk 
617828bcf6a7SKonrad Sztyber 	/* Verify the request is queued after receiving ENOMEM from pull */
617928bcf6a7SKonrad Sztyber 	g_io_done = false;
618028bcf6a7SKonrad Sztyber 	aux_io = ut_alloc_expected_io(SPDK_BDEV_IO_TYPE_WRITE, 32, 14, 1);
618128bcf6a7SKonrad Sztyber 	ut_expected_io_set_iov(aux_io, 0, iov.iov_base, iov.iov_len);
618228bcf6a7SKonrad Sztyber 	TAILQ_INSERT_TAIL(&g_bdev_ut_channel->expected_io, aux_io, link);
618328bcf6a7SKonrad Sztyber 	rc = spdk_bdev_writev_blocks(desc, io_ch, &iov, 1, 32, 14, io_done, NULL);
618428bcf6a7SKonrad Sztyber 	CU_ASSERT(rc == 0);
618528bcf6a7SKonrad Sztyber 	CU_ASSERT(g_io_done == false);
618628bcf6a7SKonrad Sztyber 	CU_ASSERT(g_bdev_ut_channel->outstanding_io_count == 1);
618728bcf6a7SKonrad Sztyber 
618828bcf6a7SKonrad Sztyber 	expected_io = ut_alloc_expected_io(SPDK_BDEV_IO_TYPE_WRITE, 32, 14, 1);
618928bcf6a7SKonrad Sztyber 	ut_expected_io_set_iov(expected_io, 0, iov.iov_base, iov.iov_len);
619028bcf6a7SKonrad Sztyber 	TAILQ_INSERT_TAIL(&g_bdev_ut_channel->expected_io, expected_io, link);
619128bcf6a7SKonrad Sztyber 
619228bcf6a7SKonrad Sztyber 	MOCK_SET(spdk_memory_domain_pull_data, -ENOMEM);
619328bcf6a7SKonrad Sztyber 	rc = spdk_bdev_writev_blocks_ext(desc, io_ch, &iov, 1, 32, 14, io_done, NULL, &ext_io_opts);
619428bcf6a7SKonrad Sztyber 	CU_ASSERT(rc == 0);
619528bcf6a7SKonrad Sztyber 	CU_ASSERT(g_io_done == false);
619628bcf6a7SKonrad Sztyber 	/* The second IO has been queued */
619728bcf6a7SKonrad Sztyber 	CU_ASSERT(g_bdev_ut_channel->outstanding_io_count == 1);
619828bcf6a7SKonrad Sztyber 
619928bcf6a7SKonrad Sztyber 	MOCK_CLEAR(spdk_memory_domain_pull_data);
620028bcf6a7SKonrad Sztyber 	g_memory_domain_pull_data_called = false;
620128bcf6a7SKonrad Sztyber 	stub_complete_io(1);
620228bcf6a7SKonrad Sztyber 	CU_ASSERT(g_io_done == true);
620328bcf6a7SKonrad Sztyber 	CU_ASSERT(g_memory_domain_pull_data_called == true);
620428bcf6a7SKonrad Sztyber 	/* The second IO should be submitted now */
620528bcf6a7SKonrad Sztyber 	CU_ASSERT(g_bdev_ut_channel->outstanding_io_count == 1);
620628bcf6a7SKonrad Sztyber 	g_io_done = false;
620728bcf6a7SKonrad Sztyber 	stub_complete_io(1);
620828bcf6a7SKonrad Sztyber 	CU_ASSERT(g_io_done == true);
620928bcf6a7SKonrad Sztyber 
6210f8a33650SKonrad Sztyber 	/* Verify the request is queued after receiving ENOMEM from push */
6211f8a33650SKonrad Sztyber 	g_io_done = false;
6212f8a33650SKonrad Sztyber 	expected_io = ut_alloc_expected_io(SPDK_BDEV_IO_TYPE_READ, 32, 14, 1);
6213f8a33650SKonrad Sztyber 	ut_expected_io_set_iov(expected_io, 0, iov.iov_base, iov.iov_len);
6214f8a33650SKonrad Sztyber 	TAILQ_INSERT_TAIL(&g_bdev_ut_channel->expected_io, expected_io, link);
6215f8a33650SKonrad Sztyber 
6216f8a33650SKonrad Sztyber 	MOCK_SET(spdk_memory_domain_push_data, -ENOMEM);
6217f8a33650SKonrad Sztyber 	rc = spdk_bdev_readv_blocks_ext(desc, io_ch, &iov, 1, 32, 14, io_done, NULL, &ext_io_opts);
6218f8a33650SKonrad Sztyber 	CU_ASSERT(rc == 0);
6219f8a33650SKonrad Sztyber 	CU_ASSERT(g_io_done == false);
6220f8a33650SKonrad Sztyber 	CU_ASSERT(g_bdev_ut_channel->outstanding_io_count == 1);
6221f8a33650SKonrad Sztyber 
6222f8a33650SKonrad Sztyber 	aux_io = ut_alloc_expected_io(SPDK_BDEV_IO_TYPE_WRITE, 32, 14, 1);
6223f8a33650SKonrad Sztyber 	ut_expected_io_set_iov(aux_io, 0, iov.iov_base, iov.iov_len);
6224f8a33650SKonrad Sztyber 	TAILQ_INSERT_TAIL(&g_bdev_ut_channel->expected_io, aux_io, link);
6225f8a33650SKonrad Sztyber 	rc = spdk_bdev_writev_blocks(desc, io_ch, &iov, 1, 32, 14, io_done, NULL);
6226f8a33650SKonrad Sztyber 	CU_ASSERT(rc == 0);
6227f8a33650SKonrad Sztyber 	CU_ASSERT(g_bdev_ut_channel->outstanding_io_count == 2);
6228f8a33650SKonrad Sztyber 
6229f8a33650SKonrad Sztyber 	stub_complete_io(1);
6230f8a33650SKonrad Sztyber 	/* The IO isn't done yet, it's still waiting on push */
6231f8a33650SKonrad Sztyber 	CU_ASSERT(g_io_done == false);
6232f8a33650SKonrad Sztyber 	CU_ASSERT(g_bdev_ut_channel->outstanding_io_count == 1);
6233f8a33650SKonrad Sztyber 	MOCK_CLEAR(spdk_memory_domain_push_data);
6234f8a33650SKonrad Sztyber 	g_memory_domain_push_data_called = false;
6235f8a33650SKonrad Sztyber 	/* Completing the second IO should also trigger push on the first one */
6236f8a33650SKonrad Sztyber 	stub_complete_io(1);
6237f8a33650SKonrad Sztyber 	CU_ASSERT(g_io_done == true);
6238f8a33650SKonrad Sztyber 	CU_ASSERT(g_memory_domain_push_data_called == true);
6239f8a33650SKonrad Sztyber 	CU_ASSERT(g_bdev_ut_channel->outstanding_io_count == 0);
6240f8a33650SKonrad Sztyber 
6241ac6f2bddSAlexey Marchuk 	spdk_put_io_channel(io_ch);
6242ac6f2bddSAlexey Marchuk 	spdk_bdev_close(desc);
6243ac6f2bddSAlexey Marchuk 	free_bdev(bdev);
6244107741fcSKonrad Sztyber 	ut_fini_bdev();
6245ac6f2bddSAlexey Marchuk }
6246ac6f2bddSAlexey Marchuk 
624779415753SKonrad Sztyber static void
624879415753SKonrad Sztyber bdev_register_uuid_alias(void)
624979415753SKonrad Sztyber {
625079415753SKonrad Sztyber 	struct spdk_bdev *bdev, *second;
625179415753SKonrad Sztyber 	char uuid[SPDK_UUID_STRING_LEN];
625279415753SKonrad Sztyber 	int rc;
625379415753SKonrad Sztyber 
6254107741fcSKonrad Sztyber 	ut_init_bdev(NULL);
625579415753SKonrad Sztyber 	bdev = allocate_bdev("bdev0");
625679415753SKonrad Sztyber 
625779415753SKonrad Sztyber 	/* Make sure an UUID was generated  */
625895a367d6SArtur Paszkiewicz 	CU_ASSERT_FALSE(spdk_uuid_is_null(&bdev->uuid));
625979415753SKonrad Sztyber 
626079415753SKonrad Sztyber 	/* Check that an UUID alias was registered */
626179415753SKonrad Sztyber 	spdk_uuid_fmt_lower(uuid, sizeof(uuid), &bdev->uuid);
626279415753SKonrad Sztyber 	CU_ASSERT_EQUAL(spdk_bdev_get_by_name(uuid), bdev);
626379415753SKonrad Sztyber 
626479415753SKonrad Sztyber 	/* Unregister the bdev */
626579415753SKonrad Sztyber 	spdk_bdev_unregister(bdev, NULL, NULL);
626679415753SKonrad Sztyber 	poll_threads();
626779415753SKonrad Sztyber 	CU_ASSERT_PTR_NULL(spdk_bdev_get_by_name(uuid));
626879415753SKonrad Sztyber 
626979415753SKonrad Sztyber 	/* Check the same, but this time register the bdev with non-zero UUID */
627079415753SKonrad Sztyber 	rc = spdk_bdev_register(bdev);
627179415753SKonrad Sztyber 	CU_ASSERT_EQUAL(rc, 0);
627279415753SKonrad Sztyber 	CU_ASSERT_EQUAL(spdk_bdev_get_by_name(uuid), bdev);
627379415753SKonrad Sztyber 
627479415753SKonrad Sztyber 	/* Unregister the bdev */
627579415753SKonrad Sztyber 	spdk_bdev_unregister(bdev, NULL, NULL);
627679415753SKonrad Sztyber 	poll_threads();
627779415753SKonrad Sztyber 	CU_ASSERT_PTR_NULL(spdk_bdev_get_by_name(uuid));
627879415753SKonrad Sztyber 
627934edd9f1SKamil Godzwon 	/* Register the bdev using UUID as the name */
628079415753SKonrad Sztyber 	bdev->name = uuid;
628179415753SKonrad Sztyber 	rc = spdk_bdev_register(bdev);
628279415753SKonrad Sztyber 	CU_ASSERT_EQUAL(rc, 0);
628379415753SKonrad Sztyber 	CU_ASSERT_EQUAL(spdk_bdev_get_by_name(uuid), bdev);
628479415753SKonrad Sztyber 
628579415753SKonrad Sztyber 	/* Unregister the bdev */
628679415753SKonrad Sztyber 	spdk_bdev_unregister(bdev, NULL, NULL);
628779415753SKonrad Sztyber 	poll_threads();
628879415753SKonrad Sztyber 	CU_ASSERT_PTR_NULL(spdk_bdev_get_by_name(uuid));
628979415753SKonrad Sztyber 
629079415753SKonrad Sztyber 	/* Check that it's not possible to register two bdevs with the same UUIDs */
629179415753SKonrad Sztyber 	bdev->name = "bdev0";
629279415753SKonrad Sztyber 	second = allocate_bdev("bdev1");
629379415753SKonrad Sztyber 	spdk_uuid_copy(&bdev->uuid, &second->uuid);
629479415753SKonrad Sztyber 	rc = spdk_bdev_register(bdev);
629579415753SKonrad Sztyber 	CU_ASSERT_EQUAL(rc, -EEXIST);
629679415753SKonrad Sztyber 
629779415753SKonrad Sztyber 	/* Regenerate the UUID and re-check */
629879415753SKonrad Sztyber 	spdk_uuid_generate(&bdev->uuid);
629979415753SKonrad Sztyber 	rc = spdk_bdev_register(bdev);
630079415753SKonrad Sztyber 	CU_ASSERT_EQUAL(rc, 0);
630179415753SKonrad Sztyber 
630279415753SKonrad Sztyber 	/* And check that both bdevs can be retrieved through their UUIDs */
630379415753SKonrad Sztyber 	spdk_uuid_fmt_lower(uuid, sizeof(uuid), &bdev->uuid);
630479415753SKonrad Sztyber 	CU_ASSERT_EQUAL(spdk_bdev_get_by_name(uuid), bdev);
630579415753SKonrad Sztyber 	spdk_uuid_fmt_lower(uuid, sizeof(uuid), &second->uuid);
630679415753SKonrad Sztyber 	CU_ASSERT_EQUAL(spdk_bdev_get_by_name(uuid), second);
630779415753SKonrad Sztyber 
630879415753SKonrad Sztyber 	free_bdev(second);
630979415753SKonrad Sztyber 	free_bdev(bdev);
6310107741fcSKonrad Sztyber 	ut_fini_bdev();
631179415753SKonrad Sztyber }
631279415753SKonrad Sztyber 
631396c007d3SShuhei Matsumoto static void
631496c007d3SShuhei Matsumoto bdev_unregister_by_name(void)
631596c007d3SShuhei Matsumoto {
631696c007d3SShuhei Matsumoto 	struct spdk_bdev *bdev;
631796c007d3SShuhei Matsumoto 	int rc;
631896c007d3SShuhei Matsumoto 
631996c007d3SShuhei Matsumoto 	bdev = allocate_bdev("bdev");
632096c007d3SShuhei Matsumoto 
632196c007d3SShuhei Matsumoto 	g_event_type1 = 0xFF;
632296c007d3SShuhei Matsumoto 	g_unregister_arg = NULL;
632396c007d3SShuhei Matsumoto 	g_unregister_rc = -1;
632496c007d3SShuhei Matsumoto 
632596c007d3SShuhei Matsumoto 	rc = spdk_bdev_unregister_by_name("bdev1", &bdev_ut_if, bdev_unregister_cb, (void *)0x12345678);
632696c007d3SShuhei Matsumoto 	CU_ASSERT(rc == -ENODEV);
632796c007d3SShuhei Matsumoto 
632896c007d3SShuhei Matsumoto 	rc = spdk_bdev_unregister_by_name("bdev", &vbdev_ut_if, bdev_unregister_cb, (void *)0x12345678);
632996c007d3SShuhei Matsumoto 	CU_ASSERT(rc == -ENODEV);
633096c007d3SShuhei Matsumoto 
633196c007d3SShuhei Matsumoto 	rc = spdk_bdev_unregister_by_name("bdev", &bdev_ut_if, bdev_unregister_cb, (void *)0x12345678);
633296c007d3SShuhei Matsumoto 	CU_ASSERT(rc == 0);
633396c007d3SShuhei Matsumoto 
633496c007d3SShuhei Matsumoto 	/* Check that unregister callback is delayed */
633596c007d3SShuhei Matsumoto 	CU_ASSERT(g_unregister_arg == NULL);
633696c007d3SShuhei Matsumoto 	CU_ASSERT(g_unregister_rc == -1);
633796c007d3SShuhei Matsumoto 
633896c007d3SShuhei Matsumoto 	poll_threads();
633996c007d3SShuhei Matsumoto 
634096c007d3SShuhei Matsumoto 	/* Event callback shall not be issued because device was closed */
634196c007d3SShuhei Matsumoto 	CU_ASSERT(g_event_type1 == 0xFF);
634296c007d3SShuhei Matsumoto 	/* Unregister callback is issued */
634396c007d3SShuhei Matsumoto 	CU_ASSERT(g_unregister_arg == (void *)0x12345678);
634496c007d3SShuhei Matsumoto 	CU_ASSERT(g_unregister_rc == 0);
634596c007d3SShuhei Matsumoto 
634696c007d3SShuhei Matsumoto 	free_bdev(bdev);
634796c007d3SShuhei Matsumoto }
634896c007d3SShuhei Matsumoto 
6349428b17a0SShuhei Matsumoto static int
6350428b17a0SShuhei Matsumoto count_bdevs(void *ctx, struct spdk_bdev *bdev)
6351428b17a0SShuhei Matsumoto {
6352428b17a0SShuhei Matsumoto 	int *count = ctx;
6353428b17a0SShuhei Matsumoto 
6354428b17a0SShuhei Matsumoto 	(*count)++;
6355428b17a0SShuhei Matsumoto 
6356428b17a0SShuhei Matsumoto 	return 0;
6357428b17a0SShuhei Matsumoto }
6358428b17a0SShuhei Matsumoto 
6359428b17a0SShuhei Matsumoto static void
6360428b17a0SShuhei Matsumoto for_each_bdev_test(void)
6361428b17a0SShuhei Matsumoto {
6362428b17a0SShuhei Matsumoto 	struct spdk_bdev *bdev[8];
6363428b17a0SShuhei Matsumoto 	int rc, count;
6364428b17a0SShuhei Matsumoto 
6365428b17a0SShuhei Matsumoto 	bdev[0] = allocate_bdev("bdev0");
6366c0c333e2Syupeng 	bdev[0]->internal.status = SPDK_BDEV_STATUS_REMOVING;
6367428b17a0SShuhei Matsumoto 
6368428b17a0SShuhei Matsumoto 	bdev[1] = allocate_bdev("bdev1");
6369428b17a0SShuhei Matsumoto 	rc = spdk_bdev_module_claim_bdev(bdev[1], NULL, &bdev_ut_if);
6370428b17a0SShuhei Matsumoto 	CU_ASSERT(rc == 0);
6371428b17a0SShuhei Matsumoto 
6372428b17a0SShuhei Matsumoto 	bdev[2] = allocate_bdev("bdev2");
6373428b17a0SShuhei Matsumoto 
6374428b17a0SShuhei Matsumoto 	bdev[3] = allocate_bdev("bdev3");
6375428b17a0SShuhei Matsumoto 	rc = spdk_bdev_module_claim_bdev(bdev[3], NULL, &bdev_ut_if);
6376428b17a0SShuhei Matsumoto 	CU_ASSERT(rc == 0);
6377428b17a0SShuhei Matsumoto 
6378428b17a0SShuhei Matsumoto 	bdev[4] = allocate_bdev("bdev4");
6379428b17a0SShuhei Matsumoto 
6380428b17a0SShuhei Matsumoto 	bdev[5] = allocate_bdev("bdev5");
6381428b17a0SShuhei Matsumoto 	rc = spdk_bdev_module_claim_bdev(bdev[5], NULL, &bdev_ut_if);
6382428b17a0SShuhei Matsumoto 	CU_ASSERT(rc == 0);
6383428b17a0SShuhei Matsumoto 
6384428b17a0SShuhei Matsumoto 	bdev[6] = allocate_bdev("bdev6");
6385428b17a0SShuhei Matsumoto 
6386428b17a0SShuhei Matsumoto 	bdev[7] = allocate_bdev("bdev7");
6387428b17a0SShuhei Matsumoto 
6388428b17a0SShuhei Matsumoto 	count = 0;
6389428b17a0SShuhei Matsumoto 	rc = spdk_for_each_bdev(&count, count_bdevs);
6390428b17a0SShuhei Matsumoto 	CU_ASSERT(rc == 0);
6391c0c333e2Syupeng 	CU_ASSERT(count == 7);
6392428b17a0SShuhei Matsumoto 
6393428b17a0SShuhei Matsumoto 	count = 0;
6394428b17a0SShuhei Matsumoto 	rc = spdk_for_each_bdev_leaf(&count, count_bdevs);
6395428b17a0SShuhei Matsumoto 	CU_ASSERT(rc == 0);
6396c0c333e2Syupeng 	CU_ASSERT(count == 4);
6397428b17a0SShuhei Matsumoto 
6398c0c333e2Syupeng 	bdev[0]->internal.status = SPDK_BDEV_STATUS_READY;
6399428b17a0SShuhei Matsumoto 	free_bdev(bdev[0]);
6400428b17a0SShuhei Matsumoto 	free_bdev(bdev[1]);
6401428b17a0SShuhei Matsumoto 	free_bdev(bdev[2]);
6402428b17a0SShuhei Matsumoto 	free_bdev(bdev[3]);
6403428b17a0SShuhei Matsumoto 	free_bdev(bdev[4]);
6404428b17a0SShuhei Matsumoto 	free_bdev(bdev[5]);
6405428b17a0SShuhei Matsumoto 	free_bdev(bdev[6]);
6406428b17a0SShuhei Matsumoto 	free_bdev(bdev[7]);
6407428b17a0SShuhei Matsumoto }
6408428b17a0SShuhei Matsumoto 
64096defafc9SDamiano static void
64106defafc9SDamiano bdev_seek_test(void)
64116defafc9SDamiano {
64126defafc9SDamiano 	struct spdk_bdev *bdev;
64136defafc9SDamiano 	struct spdk_bdev_desc *desc = NULL;
64146defafc9SDamiano 	struct spdk_io_channel *io_ch;
64156defafc9SDamiano 	int rc;
64166defafc9SDamiano 
6417107741fcSKonrad Sztyber 	ut_init_bdev(NULL);
64186defafc9SDamiano 	poll_threads();
64196defafc9SDamiano 
64206defafc9SDamiano 	bdev = allocate_bdev("bdev0");
64216defafc9SDamiano 
64226defafc9SDamiano 	rc = spdk_bdev_open_ext("bdev0", true, bdev_ut_event_cb, NULL, &desc);
64236defafc9SDamiano 	CU_ASSERT(rc == 0);
64246defafc9SDamiano 	poll_threads();
64256defafc9SDamiano 	SPDK_CU_ASSERT_FATAL(desc != NULL);
64266defafc9SDamiano 	CU_ASSERT(bdev == spdk_bdev_desc_get_bdev(desc));
64276defafc9SDamiano 	io_ch = spdk_bdev_get_io_channel(desc);
64286defafc9SDamiano 	CU_ASSERT(io_ch != NULL);
64296defafc9SDamiano 
64306defafc9SDamiano 	/* Seek data not supported */
64316defafc9SDamiano 	ut_enable_io_type(SPDK_BDEV_IO_TYPE_SEEK_DATA, false);
64326defafc9SDamiano 	rc = spdk_bdev_seek_data(desc, io_ch, 0, bdev_seek_cb, NULL);
64336defafc9SDamiano 	CU_ASSERT(rc == 0);
64346defafc9SDamiano 	CU_ASSERT(g_bdev_ut_channel->outstanding_io_count == 0);
64356defafc9SDamiano 	poll_threads();
64366defafc9SDamiano 	CU_ASSERT(g_seek_offset == 0);
64376defafc9SDamiano 
64386defafc9SDamiano 	/* Seek hole not supported */
64396defafc9SDamiano 	ut_enable_io_type(SPDK_BDEV_IO_TYPE_SEEK_HOLE, false);
64406defafc9SDamiano 	rc = spdk_bdev_seek_hole(desc, io_ch, 0, bdev_seek_cb, NULL);
64416defafc9SDamiano 	CU_ASSERT(rc == 0);
64426defafc9SDamiano 	CU_ASSERT(g_bdev_ut_channel->outstanding_io_count == 0);
64436defafc9SDamiano 	poll_threads();
64446defafc9SDamiano 	CU_ASSERT(g_seek_offset == UINT64_MAX);
64456defafc9SDamiano 
64466defafc9SDamiano 	/* Seek data supported */
64476defafc9SDamiano 	g_seek_data_offset = 12345;
64486defafc9SDamiano 	ut_enable_io_type(SPDK_BDEV_IO_TYPE_SEEK_DATA, true);
64496defafc9SDamiano 	rc = spdk_bdev_seek_data(desc, io_ch, 0, bdev_seek_cb, NULL);
64506defafc9SDamiano 	CU_ASSERT(rc == 0);
64516defafc9SDamiano 	CU_ASSERT(g_bdev_ut_channel->outstanding_io_count == 1);
64526defafc9SDamiano 	stub_complete_io(1);
64536defafc9SDamiano 	CU_ASSERT(g_bdev_ut_channel->outstanding_io_count == 0);
64546defafc9SDamiano 	CU_ASSERT(g_seek_offset == 12345);
64556defafc9SDamiano 
64566defafc9SDamiano 	/* Seek hole supported */
64576defafc9SDamiano 	g_seek_hole_offset = 67890;
64586defafc9SDamiano 	ut_enable_io_type(SPDK_BDEV_IO_TYPE_SEEK_HOLE, true);
64596defafc9SDamiano 	rc = spdk_bdev_seek_hole(desc, io_ch, 0, bdev_seek_cb, NULL);
64606defafc9SDamiano 	CU_ASSERT(rc == 0);
64616defafc9SDamiano 	CU_ASSERT(g_bdev_ut_channel->outstanding_io_count == 1);
64626defafc9SDamiano 	stub_complete_io(1);
64636defafc9SDamiano 	CU_ASSERT(g_bdev_ut_channel->outstanding_io_count == 0);
64646defafc9SDamiano 	CU_ASSERT(g_seek_offset == 67890);
64656defafc9SDamiano 
64666defafc9SDamiano 	spdk_put_io_channel(io_ch);
64676defafc9SDamiano 	spdk_bdev_close(desc);
64686defafc9SDamiano 	free_bdev(bdev);
6469107741fcSKonrad Sztyber 	ut_fini_bdev();
64706defafc9SDamiano }
64716defafc9SDamiano 
64726c8702acSEvgeniy Kochetov static void
64736c8702acSEvgeniy Kochetov bdev_copy(void)
64746c8702acSEvgeniy Kochetov {
64756c8702acSEvgeniy Kochetov 	struct spdk_bdev *bdev;
64766c8702acSEvgeniy Kochetov 	struct spdk_bdev_desc *desc = NULL;
64776c8702acSEvgeniy Kochetov 	struct spdk_io_channel *ioch;
64786c8702acSEvgeniy Kochetov 	struct ut_expected_io *expected_io;
64796c8702acSEvgeniy Kochetov 	uint64_t src_offset, num_blocks;
64806c8702acSEvgeniy Kochetov 	uint32_t num_completed;
64816c8702acSEvgeniy Kochetov 	int rc;
64826c8702acSEvgeniy Kochetov 
6483107741fcSKonrad Sztyber 	ut_init_bdev(NULL);
64846c8702acSEvgeniy Kochetov 	bdev = allocate_bdev("bdev");
64856c8702acSEvgeniy Kochetov 
64866c8702acSEvgeniy Kochetov 	rc = spdk_bdev_open_ext("bdev", true, bdev_ut_event_cb, NULL, &desc);
64876c8702acSEvgeniy Kochetov 	CU_ASSERT_EQUAL(rc, 0);
64886c8702acSEvgeniy Kochetov 	SPDK_CU_ASSERT_FATAL(desc != NULL);
64896c8702acSEvgeniy Kochetov 	CU_ASSERT(bdev == spdk_bdev_desc_get_bdev(desc));
64906c8702acSEvgeniy Kochetov 	ioch = spdk_bdev_get_io_channel(desc);
64916c8702acSEvgeniy Kochetov 	SPDK_CU_ASSERT_FATAL(ioch != NULL);
64926c8702acSEvgeniy Kochetov 
64936c8702acSEvgeniy Kochetov 	fn_table.submit_request = stub_submit_request;
64946c8702acSEvgeniy Kochetov 	g_io_exp_status = SPDK_BDEV_IO_STATUS_SUCCESS;
64956c8702acSEvgeniy Kochetov 
64966c8702acSEvgeniy Kochetov 	/* First test that if the bdev supports copy, the request won't be split */
64976c8702acSEvgeniy Kochetov 	bdev->md_len = 0;
649886136540SRui Chang 	bdev->blocklen = 512;
649986136540SRui Chang 	num_blocks = 128;
65006c8702acSEvgeniy Kochetov 	src_offset = bdev->blockcnt - num_blocks;
65016c8702acSEvgeniy Kochetov 
65026c8702acSEvgeniy Kochetov 	expected_io = ut_alloc_expected_copy_io(SPDK_BDEV_IO_TYPE_COPY, 0, src_offset, num_blocks);
65036c8702acSEvgeniy Kochetov 	TAILQ_INSERT_TAIL(&g_bdev_ut_channel->expected_io, expected_io, link);
650486136540SRui Chang 
65056c8702acSEvgeniy Kochetov 	rc = spdk_bdev_copy_blocks(desc, ioch, 0, src_offset, num_blocks, io_done, NULL);
65066c8702acSEvgeniy Kochetov 	CU_ASSERT_EQUAL(rc, 0);
65076c8702acSEvgeniy Kochetov 	num_completed = stub_complete_io(1);
65086c8702acSEvgeniy Kochetov 	CU_ASSERT_EQUAL(num_completed, 1);
65096c8702acSEvgeniy Kochetov 
651086136540SRui Chang 	/* Check that if copy is not supported it'll still work */
651186136540SRui Chang 	expected_io = ut_alloc_expected_io(SPDK_BDEV_IO_TYPE_READ, src_offset, num_blocks, 0);
651286136540SRui Chang 	TAILQ_INSERT_TAIL(&g_bdev_ut_channel->expected_io, expected_io, link);
651386136540SRui Chang 	expected_io = ut_alloc_expected_io(SPDK_BDEV_IO_TYPE_WRITE, 0, num_blocks, 0);
651486136540SRui Chang 	TAILQ_INSERT_TAIL(&g_bdev_ut_channel->expected_io, expected_io, link);
651586136540SRui Chang 
65166c8702acSEvgeniy Kochetov 	ut_enable_io_type(SPDK_BDEV_IO_TYPE_COPY, false);
65176c8702acSEvgeniy Kochetov 
65186c8702acSEvgeniy Kochetov 	rc = spdk_bdev_copy_blocks(desc, ioch, 0, src_offset, num_blocks, io_done, NULL);
651986136540SRui Chang 	CU_ASSERT_EQUAL(rc, 0);
652086136540SRui Chang 	num_completed = stub_complete_io(1);
652186136540SRui Chang 	CU_ASSERT_EQUAL(num_completed, 1);
652286136540SRui Chang 	num_completed = stub_complete_io(1);
652386136540SRui Chang 	CU_ASSERT_EQUAL(num_completed, 1);
65246c8702acSEvgeniy Kochetov 
65256c8702acSEvgeniy Kochetov 	ut_enable_io_type(SPDK_BDEV_IO_TYPE_COPY, true);
65266c8702acSEvgeniy Kochetov 	spdk_put_io_channel(ioch);
65276c8702acSEvgeniy Kochetov 	spdk_bdev_close(desc);
65286c8702acSEvgeniy Kochetov 	free_bdev(bdev);
6529107741fcSKonrad Sztyber 	ut_fini_bdev();
65306c8702acSEvgeniy Kochetov }
65316c8702acSEvgeniy Kochetov 
65326c8702acSEvgeniy Kochetov static void
65336c8702acSEvgeniy Kochetov bdev_copy_split_test(void)
65346c8702acSEvgeniy Kochetov {
65356c8702acSEvgeniy Kochetov 	struct spdk_bdev *bdev;
65366c8702acSEvgeniy Kochetov 	struct spdk_bdev_desc *desc = NULL;
65376c8702acSEvgeniy Kochetov 	struct spdk_io_channel *ioch;
65386c8702acSEvgeniy Kochetov 	struct spdk_bdev_channel *bdev_ch;
65396c8702acSEvgeniy Kochetov 	struct ut_expected_io *expected_io;
65406c8702acSEvgeniy Kochetov 	struct spdk_bdev_opts bdev_opts = {};
65416c8702acSEvgeniy Kochetov 	uint32_t i, num_outstanding;
65426c8702acSEvgeniy Kochetov 	uint64_t offset, src_offset, num_blocks, max_copy_blocks, num_children;
65436c8702acSEvgeniy Kochetov 	int rc;
65446c8702acSEvgeniy Kochetov 
65456c8702acSEvgeniy Kochetov 	spdk_bdev_get_opts(&bdev_opts, sizeof(bdev_opts));
65466c8702acSEvgeniy Kochetov 	bdev_opts.bdev_io_pool_size = 512;
65476c8702acSEvgeniy Kochetov 	bdev_opts.bdev_io_cache_size = 64;
65486c8702acSEvgeniy Kochetov 	rc = spdk_bdev_set_opts(&bdev_opts);
65496c8702acSEvgeniy Kochetov 	CU_ASSERT(rc == 0);
65506c8702acSEvgeniy Kochetov 
6551107741fcSKonrad Sztyber 	ut_init_bdev(NULL);
65526c8702acSEvgeniy Kochetov 	bdev = allocate_bdev("bdev");
65536c8702acSEvgeniy Kochetov 
65546c8702acSEvgeniy Kochetov 	rc = spdk_bdev_open_ext("bdev", true, bdev_ut_event_cb, NULL, &desc);
65556c8702acSEvgeniy Kochetov 	CU_ASSERT_EQUAL(rc, 0);
65566c8702acSEvgeniy Kochetov 	SPDK_CU_ASSERT_FATAL(desc != NULL);
65576c8702acSEvgeniy Kochetov 	CU_ASSERT(bdev == spdk_bdev_desc_get_bdev(desc));
65586c8702acSEvgeniy Kochetov 	ioch = spdk_bdev_get_io_channel(desc);
65596c8702acSEvgeniy Kochetov 	SPDK_CU_ASSERT_FATAL(ioch != NULL);
65606c8702acSEvgeniy Kochetov 	bdev_ch = spdk_io_channel_get_ctx(ioch);
65616c8702acSEvgeniy Kochetov 	CU_ASSERT(TAILQ_EMPTY(&bdev_ch->io_submitted));
65626c8702acSEvgeniy Kochetov 
65636c8702acSEvgeniy Kochetov 	fn_table.submit_request = stub_submit_request;
65646c8702acSEvgeniy Kochetov 	g_io_exp_status = SPDK_BDEV_IO_STATUS_SUCCESS;
65656c8702acSEvgeniy Kochetov 
65666c8702acSEvgeniy Kochetov 	/* Case 1: First test the request won't be split */
65676c8702acSEvgeniy Kochetov 	num_blocks = 32;
65686c8702acSEvgeniy Kochetov 	src_offset = bdev->blockcnt - num_blocks;
65696c8702acSEvgeniy Kochetov 
65706c8702acSEvgeniy Kochetov 	g_io_done = false;
65716c8702acSEvgeniy Kochetov 	expected_io = ut_alloc_expected_copy_io(SPDK_BDEV_IO_TYPE_COPY, 0, src_offset, num_blocks);
65726c8702acSEvgeniy Kochetov 	TAILQ_INSERT_TAIL(&g_bdev_ut_channel->expected_io, expected_io, link);
65736c8702acSEvgeniy Kochetov 	rc = spdk_bdev_copy_blocks(desc, ioch, 0, src_offset, num_blocks, io_done, NULL);
65746c8702acSEvgeniy Kochetov 	CU_ASSERT_EQUAL(rc, 0);
65756c8702acSEvgeniy Kochetov 	CU_ASSERT(g_io_done == false);
65766c8702acSEvgeniy Kochetov 	CU_ASSERT(g_bdev_ut_channel->outstanding_io_count == 1);
65776c8702acSEvgeniy Kochetov 	stub_complete_io(1);
65786c8702acSEvgeniy Kochetov 	CU_ASSERT(g_io_done == true);
65796c8702acSEvgeniy Kochetov 	CU_ASSERT(g_bdev_ut_channel->outstanding_io_count == 0);
65806c8702acSEvgeniy Kochetov 
65816c8702acSEvgeniy Kochetov 	/* Case 2: Test the split with 2 children requests */
65826c8702acSEvgeniy Kochetov 	max_copy_blocks = 8;
65836c8702acSEvgeniy Kochetov 	bdev->max_copy = max_copy_blocks;
65846c8702acSEvgeniy Kochetov 	num_children = 2;
65856c8702acSEvgeniy Kochetov 	num_blocks = max_copy_blocks * num_children;
65866c8702acSEvgeniy Kochetov 	offset = 0;
65876c8702acSEvgeniy Kochetov 	src_offset = bdev->blockcnt - num_blocks;
65886c8702acSEvgeniy Kochetov 
65896c8702acSEvgeniy Kochetov 	g_io_done = false;
65906c8702acSEvgeniy Kochetov 	for (i = 0; i < num_children; i++) {
65916c8702acSEvgeniy Kochetov 		expected_io = ut_alloc_expected_copy_io(SPDK_BDEV_IO_TYPE_COPY, offset,
65926c8702acSEvgeniy Kochetov 							src_offset + offset, max_copy_blocks);
65936c8702acSEvgeniy Kochetov 		TAILQ_INSERT_TAIL(&g_bdev_ut_channel->expected_io, expected_io, link);
65946c8702acSEvgeniy Kochetov 		offset += max_copy_blocks;
65956c8702acSEvgeniy Kochetov 	}
65966c8702acSEvgeniy Kochetov 
65976c8702acSEvgeniy Kochetov 	rc = spdk_bdev_copy_blocks(desc, ioch, 0, src_offset, num_blocks, io_done, NULL);
65986c8702acSEvgeniy Kochetov 	CU_ASSERT_EQUAL(rc, 0);
65996c8702acSEvgeniy Kochetov 	CU_ASSERT(g_io_done == false);
66006c8702acSEvgeniy Kochetov 	CU_ASSERT(g_bdev_ut_channel->outstanding_io_count == num_children);
66016c8702acSEvgeniy Kochetov 	stub_complete_io(num_children);
66026c8702acSEvgeniy Kochetov 	CU_ASSERT(g_io_done == true);
66036c8702acSEvgeniy Kochetov 	CU_ASSERT(g_bdev_ut_channel->outstanding_io_count == 0);
66046c8702acSEvgeniy Kochetov 
66056c8702acSEvgeniy Kochetov 	/* Case 3: Test the split with 15 children requests, will finish 8 requests first */
66066c8702acSEvgeniy Kochetov 	num_children = 15;
66076c8702acSEvgeniy Kochetov 	num_blocks = max_copy_blocks * num_children;
66086c8702acSEvgeniy Kochetov 	offset = 0;
66096c8702acSEvgeniy Kochetov 	src_offset = bdev->blockcnt - num_blocks;
66106c8702acSEvgeniy Kochetov 
66116c8702acSEvgeniy Kochetov 	g_io_done = false;
66126c8702acSEvgeniy Kochetov 	for (i = 0; i < num_children; i++) {
66136c8702acSEvgeniy Kochetov 		expected_io = ut_alloc_expected_copy_io(SPDK_BDEV_IO_TYPE_COPY, offset,
66146c8702acSEvgeniy Kochetov 							src_offset + offset, max_copy_blocks);
66156c8702acSEvgeniy Kochetov 		TAILQ_INSERT_TAIL(&g_bdev_ut_channel->expected_io, expected_io, link);
66166c8702acSEvgeniy Kochetov 		offset += max_copy_blocks;
66176c8702acSEvgeniy Kochetov 	}
66186c8702acSEvgeniy Kochetov 
66196c8702acSEvgeniy Kochetov 	rc = spdk_bdev_copy_blocks(desc, ioch, 0, src_offset, num_blocks, io_done, NULL);
66206c8702acSEvgeniy Kochetov 	CU_ASSERT_EQUAL(rc, 0);
66216c8702acSEvgeniy Kochetov 	CU_ASSERT(g_io_done == false);
66226c8702acSEvgeniy Kochetov 
66236c8702acSEvgeniy Kochetov 	while (num_children > 0) {
66246c8702acSEvgeniy Kochetov 		num_outstanding = spdk_min(num_children, SPDK_BDEV_MAX_CHILDREN_COPY_REQS);
66256c8702acSEvgeniy Kochetov 		CU_ASSERT(g_bdev_ut_channel->outstanding_io_count == num_outstanding);
66266c8702acSEvgeniy Kochetov 		stub_complete_io(num_outstanding);
66276c8702acSEvgeniy Kochetov 		num_children -= num_outstanding;
66286c8702acSEvgeniy Kochetov 	}
66296c8702acSEvgeniy Kochetov 	CU_ASSERT(g_io_done == true);
66306c8702acSEvgeniy Kochetov 
66310c1df53eSShuhei Matsumoto 	/* Case 4: Same test scenario as the case 2 but the configuration is different.
66320c1df53eSShuhei Matsumoto 	 * Copy is not supported.
66330c1df53eSShuhei Matsumoto 	 */
66340c1df53eSShuhei Matsumoto 	ut_enable_io_type(SPDK_BDEV_IO_TYPE_COPY, false);
66350c1df53eSShuhei Matsumoto 
66360c1df53eSShuhei Matsumoto 	num_children = 2;
66370c1df53eSShuhei Matsumoto 	max_copy_blocks = spdk_bdev_get_max_copy(bdev);
66380c1df53eSShuhei Matsumoto 	num_blocks = max_copy_blocks * num_children;
66390c1df53eSShuhei Matsumoto 	src_offset = bdev->blockcnt - num_blocks;
66400c1df53eSShuhei Matsumoto 	offset = 0;
66410c1df53eSShuhei Matsumoto 
66420c1df53eSShuhei Matsumoto 	g_io_done = false;
66430c1df53eSShuhei Matsumoto 	for (i = 0; i < num_children; i++) {
66440c1df53eSShuhei Matsumoto 		expected_io = ut_alloc_expected_io(SPDK_BDEV_IO_TYPE_READ, src_offset,
66450c1df53eSShuhei Matsumoto 						   max_copy_blocks, 0);
66460c1df53eSShuhei Matsumoto 		TAILQ_INSERT_TAIL(&g_bdev_ut_channel->expected_io, expected_io, link);
66470c1df53eSShuhei Matsumoto 		src_offset += max_copy_blocks;
66480c1df53eSShuhei Matsumoto 	}
66490c1df53eSShuhei Matsumoto 	for (i = 0; i < num_children; i++) {
66500c1df53eSShuhei Matsumoto 		expected_io = ut_alloc_expected_io(SPDK_BDEV_IO_TYPE_WRITE, offset,
66510c1df53eSShuhei Matsumoto 						   max_copy_blocks, 0);
66520c1df53eSShuhei Matsumoto 		TAILQ_INSERT_TAIL(&g_bdev_ut_channel->expected_io, expected_io, link);
66530c1df53eSShuhei Matsumoto 		offset += max_copy_blocks;
66540c1df53eSShuhei Matsumoto 	}
66550c1df53eSShuhei Matsumoto 
66560c1df53eSShuhei Matsumoto 	src_offset = bdev->blockcnt - num_blocks;
66570c1df53eSShuhei Matsumoto 	offset = 0;
66580c1df53eSShuhei Matsumoto 
66590c1df53eSShuhei Matsumoto 	rc = spdk_bdev_copy_blocks(desc, ioch, offset, src_offset, num_blocks, io_done, NULL);
66600c1df53eSShuhei Matsumoto 	CU_ASSERT_EQUAL(rc, 0);
66610c1df53eSShuhei Matsumoto 	CU_ASSERT(g_io_done == false);
66620c1df53eSShuhei Matsumoto 
66630c1df53eSShuhei Matsumoto 	while (num_children > 0) {
66640c1df53eSShuhei Matsumoto 		num_outstanding = spdk_min(num_children, SPDK_BDEV_MAX_CHILDREN_COPY_REQS);
66650c1df53eSShuhei Matsumoto 
66660c1df53eSShuhei Matsumoto 		/* One copy request is split into one read and one write requests. */
66670c1df53eSShuhei Matsumoto 		CU_ASSERT(g_bdev_ut_channel->outstanding_io_count == num_outstanding);
66680c1df53eSShuhei Matsumoto 		stub_complete_io(num_outstanding);
66690c1df53eSShuhei Matsumoto 		CU_ASSERT(g_bdev_ut_channel->outstanding_io_count == num_outstanding);
66700c1df53eSShuhei Matsumoto 		stub_complete_io(num_outstanding);
66710c1df53eSShuhei Matsumoto 
66720c1df53eSShuhei Matsumoto 		num_children -= num_outstanding;
66730c1df53eSShuhei Matsumoto 	}
66740c1df53eSShuhei Matsumoto 	CU_ASSERT(g_io_done == true);
66750c1df53eSShuhei Matsumoto 
66760c1df53eSShuhei Matsumoto 	ut_enable_io_type(SPDK_BDEV_IO_TYPE_COPY, true);
66770c1df53eSShuhei Matsumoto 
66786c8702acSEvgeniy Kochetov 	spdk_put_io_channel(ioch);
66796c8702acSEvgeniy Kochetov 	spdk_bdev_close(desc);
66806c8702acSEvgeniy Kochetov 	free_bdev(bdev);
6681107741fcSKonrad Sztyber 	ut_fini_bdev();
66826c8702acSEvgeniy Kochetov }
66836c8702acSEvgeniy Kochetov 
6684ae215731SMike Gerdts static void
6685a7eb6187SMike Gerdts examine_claim_v1(struct spdk_bdev *bdev)
6686ae215731SMike Gerdts {
6687ae215731SMike Gerdts 	int rc;
6688ae215731SMike Gerdts 
6689ae215731SMike Gerdts 	rc = spdk_bdev_module_claim_bdev(bdev, NULL, &vbdev_ut_if);
6690ae215731SMike Gerdts 	CU_ASSERT(rc == 0);
6691ae215731SMike Gerdts }
6692ae215731SMike Gerdts 
6693ae215731SMike Gerdts static void
6694ae215731SMike Gerdts examine_no_lock_held(struct spdk_bdev *bdev)
6695ae215731SMike Gerdts {
6696ae215731SMike Gerdts 	CU_ASSERT(!spdk_spin_held(&g_bdev_mgr.spinlock));
6697ae215731SMike Gerdts 	CU_ASSERT(!spdk_spin_held(&bdev->internal.spinlock));
6698ae215731SMike Gerdts }
6699ae215731SMike Gerdts 
670086bbcdb8SMike Gerdts struct examine_claim_v2_ctx {
670186bbcdb8SMike Gerdts 	struct ut_examine_ctx examine_ctx;
670286bbcdb8SMike Gerdts 	enum spdk_bdev_claim_type claim_type;
670386bbcdb8SMike Gerdts 	struct spdk_bdev_desc *desc;
670486bbcdb8SMike Gerdts };
670586bbcdb8SMike Gerdts 
670686bbcdb8SMike Gerdts static void
670786bbcdb8SMike Gerdts examine_claim_v2(struct spdk_bdev *bdev)
670886bbcdb8SMike Gerdts {
670986bbcdb8SMike Gerdts 	struct examine_claim_v2_ctx *ctx = bdev->ctxt;
671086bbcdb8SMike Gerdts 	int rc;
671186bbcdb8SMike Gerdts 
671286bbcdb8SMike Gerdts 	rc = spdk_bdev_open_ext(bdev->name, false, bdev_ut_event_cb, NULL, &ctx->desc);
671386bbcdb8SMike Gerdts 	CU_ASSERT(rc == 0);
671486bbcdb8SMike Gerdts 
671586bbcdb8SMike Gerdts 	rc = spdk_bdev_module_claim_bdev_desc(ctx->desc, ctx->claim_type, NULL, &vbdev_ut_if);
671686bbcdb8SMike Gerdts 	CU_ASSERT(rc == 0);
671786bbcdb8SMike Gerdts }
671886bbcdb8SMike Gerdts 
6719ae215731SMike Gerdts static void
6720ae215731SMike Gerdts examine_locks(void)
6721ae215731SMike Gerdts {
6722ae215731SMike Gerdts 	struct spdk_bdev *bdev;
6723ae215731SMike Gerdts 	struct ut_examine_ctx ctx = { 0 };
672486bbcdb8SMike Gerdts 	struct examine_claim_v2_ctx v2_ctx;
6725ae215731SMike Gerdts 
6726ae215731SMike Gerdts 	/* Without any claims, one code path is taken */
6727ae215731SMike Gerdts 	ctx.examine_config = examine_no_lock_held;
6728ae215731SMike Gerdts 	ctx.examine_disk = examine_no_lock_held;
6729ae215731SMike Gerdts 	bdev = allocate_bdev_ctx("bdev0", &ctx);
6730ae215731SMike Gerdts 	CU_ASSERT(ctx.examine_config_count == 1);
6731ae215731SMike Gerdts 	CU_ASSERT(ctx.examine_disk_count == 1);
67324bb902a6SMike Gerdts 	CU_ASSERT(bdev->internal.claim_type == SPDK_BDEV_CLAIM_NONE);
67339fd2f931SMike Gerdts 	CU_ASSERT(bdev->internal.claim.v1.module == NULL);
6734ae215731SMike Gerdts 	free_bdev(bdev);
6735ae215731SMike Gerdts 
673686bbcdb8SMike Gerdts 	/* Exercise another path that is taken when examine_config() takes a v1 claim. */
6737ae215731SMike Gerdts 	memset(&ctx, 0, sizeof(ctx));
6738a7eb6187SMike Gerdts 	ctx.examine_config = examine_claim_v1;
6739ae215731SMike Gerdts 	ctx.examine_disk = examine_no_lock_held;
6740ae215731SMike Gerdts 	bdev = allocate_bdev_ctx("bdev0", &ctx);
6741ae215731SMike Gerdts 	CU_ASSERT(ctx.examine_config_count == 1);
6742ae215731SMike Gerdts 	CU_ASSERT(ctx.examine_disk_count == 1);
67434bb902a6SMike Gerdts 	CU_ASSERT(bdev->internal.claim_type == SPDK_BDEV_CLAIM_EXCL_WRITE);
67449fd2f931SMike Gerdts 	CU_ASSERT(bdev->internal.claim.v1.module == &vbdev_ut_if);
6745ae215731SMike Gerdts 	spdk_bdev_module_release_bdev(bdev);
67464bb902a6SMike Gerdts 	CU_ASSERT(bdev->internal.claim_type == SPDK_BDEV_CLAIM_NONE);
67479fd2f931SMike Gerdts 	CU_ASSERT(bdev->internal.claim.v1.module == NULL);
6748ae215731SMike Gerdts 	free_bdev(bdev);
674986bbcdb8SMike Gerdts 
675086bbcdb8SMike Gerdts 	/* Exercise the final path that comes with v2 claims. */
675186bbcdb8SMike Gerdts 	memset(&v2_ctx, 0, sizeof(v2_ctx));
675286bbcdb8SMike Gerdts 	v2_ctx.examine_ctx.examine_config = examine_claim_v2;
675386bbcdb8SMike Gerdts 	v2_ctx.examine_ctx.examine_disk = examine_no_lock_held;
675486bbcdb8SMike Gerdts 	v2_ctx.claim_type = SPDK_BDEV_CLAIM_READ_MANY_WRITE_NONE;
675586bbcdb8SMike Gerdts 	bdev = allocate_bdev_ctx("bdev0", &v2_ctx);
675686bbcdb8SMike Gerdts 	CU_ASSERT(v2_ctx.examine_ctx.examine_config_count == 1);
675786bbcdb8SMike Gerdts 	CU_ASSERT(v2_ctx.examine_ctx.examine_disk_count == 1);
675886bbcdb8SMike Gerdts 	CU_ASSERT(bdev->internal.claim_type == SPDK_BDEV_CLAIM_READ_MANY_WRITE_NONE);
675986bbcdb8SMike Gerdts 	spdk_bdev_close(v2_ctx.desc);
676086bbcdb8SMike Gerdts 	CU_ASSERT(bdev->internal.claim_type == SPDK_BDEV_CLAIM_NONE);
676186bbcdb8SMike Gerdts 	free_bdev(bdev);
6762ae215731SMike Gerdts }
6763ae215731SMike Gerdts 
6764a7eb6187SMike Gerdts #define UT_ASSERT_CLAIM_V2_COUNT(bdev, expect) \
6765a7eb6187SMike Gerdts 	do { \
6766a7eb6187SMike Gerdts 		uint32_t len = 0; \
6767a7eb6187SMike Gerdts 		struct spdk_bdev_module_claim *claim; \
6768a7eb6187SMike Gerdts 		TAILQ_FOREACH(claim, &bdev->internal.claim.v2.claims, link) { \
6769a7eb6187SMike Gerdts 			len++; \
6770a7eb6187SMike Gerdts 		} \
6771a7eb6187SMike Gerdts 		CU_ASSERT(len == expect); \
6772a7eb6187SMike Gerdts 	} while (0)
6773a7eb6187SMike Gerdts 
6774a7eb6187SMike Gerdts static void
6775a7eb6187SMike Gerdts claim_v2_rwo(void)
6776a7eb6187SMike Gerdts {
6777a7eb6187SMike Gerdts 	struct spdk_bdev *bdev;
6778a7eb6187SMike Gerdts 	struct spdk_bdev_desc *desc;
6779a7eb6187SMike Gerdts 	struct spdk_bdev_desc *desc2;
6780a7eb6187SMike Gerdts 	struct spdk_bdev_claim_opts opts;
6781a7eb6187SMike Gerdts 	int rc;
6782a7eb6187SMike Gerdts 
6783a7eb6187SMike Gerdts 	bdev = allocate_bdev("bdev0");
6784a7eb6187SMike Gerdts 
6785a7eb6187SMike Gerdts 	/* Claim without options */
6786a7eb6187SMike Gerdts 	desc = NULL;
6787a7eb6187SMike Gerdts 	rc = spdk_bdev_open_ext("bdev0", true, bdev_ut_event_cb, NULL, &desc);
6788a7eb6187SMike Gerdts 	CU_ASSERT(rc == 0);
6789a7eb6187SMike Gerdts 	SPDK_CU_ASSERT_FATAL(desc != NULL);
6790a7eb6187SMike Gerdts 	rc = spdk_bdev_module_claim_bdev_desc(desc, SPDK_BDEV_CLAIM_READ_MANY_WRITE_ONE, NULL,
6791a7eb6187SMike Gerdts 					      &bdev_ut_if);
6792a7eb6187SMike Gerdts 	CU_ASSERT(rc == 0);
6793a7eb6187SMike Gerdts 	CU_ASSERT(bdev->internal.claim_type == SPDK_BDEV_CLAIM_READ_MANY_WRITE_ONE);
6794a7eb6187SMike Gerdts 	CU_ASSERT(desc->claim != NULL);
6795a7eb6187SMike Gerdts 	CU_ASSERT(desc->claim->module == &bdev_ut_if);
6796a7eb6187SMike Gerdts 	CU_ASSERT(strcmp(desc->claim->name, "") == 0);
6797a7eb6187SMike Gerdts 	CU_ASSERT(TAILQ_FIRST(&bdev->internal.claim.v2.claims) == desc->claim);
6798a7eb6187SMike Gerdts 	UT_ASSERT_CLAIM_V2_COUNT(bdev, 1);
6799a7eb6187SMike Gerdts 
6800a7eb6187SMike Gerdts 	/* Release the claim by closing the descriptor */
6801a7eb6187SMike Gerdts 	spdk_bdev_close(desc);
6802a7eb6187SMike Gerdts 	CU_ASSERT(bdev->internal.claim_type == SPDK_BDEV_CLAIM_NONE);
6803a7eb6187SMike Gerdts 	CU_ASSERT(TAILQ_EMPTY(&bdev->internal.open_descs));
6804a7eb6187SMike Gerdts 	UT_ASSERT_CLAIM_V2_COUNT(bdev, 0);
6805a7eb6187SMike Gerdts 
6806a7eb6187SMike Gerdts 	/* Claim with options */
6807a7eb6187SMike Gerdts 	spdk_bdev_claim_opts_init(&opts, sizeof(opts));
6808a7eb6187SMike Gerdts 	snprintf(opts.name, sizeof(opts.name), "%s", "claim with options");
6809a7eb6187SMike Gerdts 	desc = NULL;
6810a7eb6187SMike Gerdts 	rc = spdk_bdev_open_ext("bdev0", true, bdev_ut_event_cb, NULL, &desc);
6811a7eb6187SMike Gerdts 	CU_ASSERT(rc == 0);
6812a7eb6187SMike Gerdts 	SPDK_CU_ASSERT_FATAL(desc != NULL);
6813a7eb6187SMike Gerdts 	rc = spdk_bdev_module_claim_bdev_desc(desc, SPDK_BDEV_CLAIM_READ_MANY_WRITE_ONE, &opts,
6814a7eb6187SMike Gerdts 					      &bdev_ut_if);
6815a7eb6187SMike Gerdts 	CU_ASSERT(rc == 0);
6816a7eb6187SMike Gerdts 	CU_ASSERT(bdev->internal.claim_type == SPDK_BDEV_CLAIM_READ_MANY_WRITE_ONE);
6817a7eb6187SMike Gerdts 	CU_ASSERT(desc->claim != NULL);
6818a7eb6187SMike Gerdts 	CU_ASSERT(desc->claim->module == &bdev_ut_if);
6819a7eb6187SMike Gerdts 	CU_ASSERT(strcmp(desc->claim->name, "claim with options") == 0);
6820a7eb6187SMike Gerdts 	memset(&opts, 0, sizeof(opts));
6821a7eb6187SMike Gerdts 	CU_ASSERT(strcmp(desc->claim->name, "claim with options") == 0);
6822a7eb6187SMike Gerdts 	CU_ASSERT(TAILQ_FIRST(&bdev->internal.claim.v2.claims) == desc->claim);
6823a7eb6187SMike Gerdts 	UT_ASSERT_CLAIM_V2_COUNT(bdev, 1);
6824a7eb6187SMike Gerdts 
6825a7eb6187SMike Gerdts 	/* The claim blocks new writers. */
6826a7eb6187SMike Gerdts 	desc2 = NULL;
6827a7eb6187SMike Gerdts 	rc = spdk_bdev_open_ext("bdev0", true, bdev_ut_event_cb, NULL, &desc2);
6828a7eb6187SMike Gerdts 	CU_ASSERT(rc == -EPERM);
6829a7eb6187SMike Gerdts 	CU_ASSERT(desc2 == NULL);
6830a7eb6187SMike Gerdts 
6831a7eb6187SMike Gerdts 	/* New readers are allowed */
6832a7eb6187SMike Gerdts 	desc2 = NULL;
6833a7eb6187SMike Gerdts 	rc = spdk_bdev_open_ext("bdev0", false, bdev_ut_event_cb, NULL, &desc2);
6834a7eb6187SMike Gerdts 	CU_ASSERT(rc == 0);
6835a7eb6187SMike Gerdts 	CU_ASSERT(desc2 != NULL);
6836a7eb6187SMike Gerdts 	CU_ASSERT(!desc2->write);
6837a7eb6187SMike Gerdts 
6838a7eb6187SMike Gerdts 	/* No new v2 RWO claims are allowed */
6839a7eb6187SMike Gerdts 	rc = spdk_bdev_module_claim_bdev_desc(desc2, SPDK_BDEV_CLAIM_READ_MANY_WRITE_ONE, NULL,
6840a7eb6187SMike Gerdts 					      &bdev_ut_if);
6841a7eb6187SMike Gerdts 	CU_ASSERT(rc == -EPERM);
6842a7eb6187SMike Gerdts 
6843a7eb6187SMike Gerdts 	/* No new v2 ROM claims are allowed */
6844a7eb6187SMike Gerdts 	CU_ASSERT(!desc2->write);
6845a7eb6187SMike Gerdts 	rc = spdk_bdev_module_claim_bdev_desc(desc2, SPDK_BDEV_CLAIM_READ_MANY_WRITE_NONE, NULL,
6846a7eb6187SMike Gerdts 					      &bdev_ut_if);
6847a7eb6187SMike Gerdts 	CU_ASSERT(rc == -EPERM);
6848a7eb6187SMike Gerdts 	CU_ASSERT(!desc2->write);
6849a7eb6187SMike Gerdts 
6850a7eb6187SMike Gerdts 	/* No new v2 RWM claims are allowed */
6851a7eb6187SMike Gerdts 	spdk_bdev_claim_opts_init(&opts, sizeof(opts));
6852a7eb6187SMike Gerdts 	opts.shared_claim_key = (uint64_t)&opts;
6853a7eb6187SMike Gerdts 	rc = spdk_bdev_module_claim_bdev_desc(desc2, SPDK_BDEV_CLAIM_READ_MANY_WRITE_SHARED, &opts,
6854a7eb6187SMike Gerdts 					      &bdev_ut_if);
6855a7eb6187SMike Gerdts 	CU_ASSERT(rc == -EPERM);
6856a7eb6187SMike Gerdts 	CU_ASSERT(!desc2->write);
6857a7eb6187SMike Gerdts 
6858a7eb6187SMike Gerdts 	/* No new v1 claims are allowed */
6859a7eb6187SMike Gerdts 	rc = spdk_bdev_module_claim_bdev(bdev, NULL, &bdev_ut_if);
6860a7eb6187SMike Gerdts 	CU_ASSERT(rc == -EPERM);
6861a7eb6187SMike Gerdts 
6862a7eb6187SMike Gerdts 	/* None of the above changed the existing claim */
6863a7eb6187SMike Gerdts 	CU_ASSERT(TAILQ_FIRST(&bdev->internal.claim.v2.claims) == desc->claim);
6864a7eb6187SMike Gerdts 	UT_ASSERT_CLAIM_V2_COUNT(bdev, 1);
6865a7eb6187SMike Gerdts 
6866a7eb6187SMike Gerdts 	/* Closing the first descriptor now allows a new claim and it is promoted to rw. */
6867a7eb6187SMike Gerdts 	spdk_bdev_close(desc);
6868a7eb6187SMike Gerdts 	CU_ASSERT(bdev->internal.claim_type == SPDK_BDEV_CLAIM_NONE);
6869a7eb6187SMike Gerdts 	UT_ASSERT_CLAIM_V2_COUNT(bdev, 0);
6870a7eb6187SMike Gerdts 	CU_ASSERT(!desc2->write);
6871a7eb6187SMike Gerdts 	rc = spdk_bdev_module_claim_bdev_desc(desc2, SPDK_BDEV_CLAIM_READ_MANY_WRITE_ONE, NULL,
6872a7eb6187SMike Gerdts 					      &bdev_ut_if);
6873a7eb6187SMike Gerdts 	CU_ASSERT(rc == 0);
6874a7eb6187SMike Gerdts 	CU_ASSERT(desc2->claim != NULL);
6875a7eb6187SMike Gerdts 	CU_ASSERT(desc2->write);
6876a7eb6187SMike Gerdts 	CU_ASSERT(bdev->internal.claim_type == SPDK_BDEV_CLAIM_READ_MANY_WRITE_ONE);
6877a7eb6187SMike Gerdts 	CU_ASSERT(TAILQ_FIRST(&bdev->internal.claim.v2.claims) == desc2->claim);
6878a7eb6187SMike Gerdts 	UT_ASSERT_CLAIM_V2_COUNT(bdev, 1);
6879a7eb6187SMike Gerdts 	spdk_bdev_close(desc2);
6880a7eb6187SMike Gerdts 	CU_ASSERT(bdev->internal.claim_type == SPDK_BDEV_CLAIM_NONE);
6881a7eb6187SMike Gerdts 	UT_ASSERT_CLAIM_V2_COUNT(bdev, 0);
6882a7eb6187SMike Gerdts 
6883a7eb6187SMike Gerdts 	/* Cannot claim with a key */
6884a7eb6187SMike Gerdts 	desc = NULL;
6885a7eb6187SMike Gerdts 	rc = spdk_bdev_open_ext("bdev0", false, bdev_ut_event_cb, NULL, &desc);
6886a7eb6187SMike Gerdts 	CU_ASSERT(rc == 0);
6887a7eb6187SMike Gerdts 	SPDK_CU_ASSERT_FATAL(desc != NULL);
6888a7eb6187SMike Gerdts 	spdk_bdev_claim_opts_init(&opts, sizeof(opts));
6889a7eb6187SMike Gerdts 	opts.shared_claim_key = (uint64_t)&opts;
6890a7eb6187SMike Gerdts 	rc = spdk_bdev_module_claim_bdev_desc(desc, SPDK_BDEV_CLAIM_READ_MANY_WRITE_ONE, &opts,
6891a7eb6187SMike Gerdts 					      &bdev_ut_if);
6892a7eb6187SMike Gerdts 	CU_ASSERT(rc == -EINVAL);
6893a7eb6187SMike Gerdts 	CU_ASSERT(bdev->internal.claim_type == SPDK_BDEV_CLAIM_NONE);
6894a7eb6187SMike Gerdts 	UT_ASSERT_CLAIM_V2_COUNT(bdev, 0);
6895a7eb6187SMike Gerdts 	spdk_bdev_close(desc);
6896a7eb6187SMike Gerdts 
6897a7eb6187SMike Gerdts 	/* Clean up */
6898a7eb6187SMike Gerdts 	free_bdev(bdev);
6899a7eb6187SMike Gerdts }
6900a7eb6187SMike Gerdts 
6901a7eb6187SMike Gerdts static void
6902a7eb6187SMike Gerdts claim_v2_rom(void)
6903a7eb6187SMike Gerdts {
6904a7eb6187SMike Gerdts 	struct spdk_bdev *bdev;
6905a7eb6187SMike Gerdts 	struct spdk_bdev_desc *desc;
6906a7eb6187SMike Gerdts 	struct spdk_bdev_desc *desc2;
6907a7eb6187SMike Gerdts 	struct spdk_bdev_claim_opts opts;
6908a7eb6187SMike Gerdts 	int rc;
6909a7eb6187SMike Gerdts 
6910a7eb6187SMike Gerdts 	bdev = allocate_bdev("bdev0");
6911a7eb6187SMike Gerdts 
6912a7eb6187SMike Gerdts 	/* Claim without options */
6913a7eb6187SMike Gerdts 	desc = NULL;
6914a7eb6187SMike Gerdts 	rc = spdk_bdev_open_ext("bdev0", false, bdev_ut_event_cb, NULL, &desc);
6915a7eb6187SMike Gerdts 	CU_ASSERT(rc == 0);
6916a7eb6187SMike Gerdts 	SPDK_CU_ASSERT_FATAL(desc != NULL);
6917a7eb6187SMike Gerdts 	rc = spdk_bdev_module_claim_bdev_desc(desc, SPDK_BDEV_CLAIM_READ_MANY_WRITE_NONE, NULL,
6918a7eb6187SMike Gerdts 					      &bdev_ut_if);
6919a7eb6187SMike Gerdts 	CU_ASSERT(rc == 0);
6920a7eb6187SMike Gerdts 	CU_ASSERT(bdev->internal.claim_type == SPDK_BDEV_CLAIM_READ_MANY_WRITE_NONE);
6921a7eb6187SMike Gerdts 	CU_ASSERT(desc->claim != NULL);
6922a7eb6187SMike Gerdts 	CU_ASSERT(desc->claim->module == &bdev_ut_if);
6923a7eb6187SMike Gerdts 	CU_ASSERT(strcmp(desc->claim->name, "") == 0);
6924a7eb6187SMike Gerdts 	CU_ASSERT(TAILQ_FIRST(&bdev->internal.claim.v2.claims) == desc->claim);
6925a7eb6187SMike Gerdts 	UT_ASSERT_CLAIM_V2_COUNT(bdev, 1);
6926a7eb6187SMike Gerdts 
6927a7eb6187SMike Gerdts 	/* Release the claim by closing the descriptor */
6928a7eb6187SMike Gerdts 	spdk_bdev_close(desc);
6929a7eb6187SMike Gerdts 	CU_ASSERT(bdev->internal.claim_type == SPDK_BDEV_CLAIM_NONE);
6930a7eb6187SMike Gerdts 	CU_ASSERT(TAILQ_EMPTY(&bdev->internal.open_descs));
6931a7eb6187SMike Gerdts 	CU_ASSERT(bdev->internal.claim_type == SPDK_BDEV_CLAIM_NONE);
6932a7eb6187SMike Gerdts 	UT_ASSERT_CLAIM_V2_COUNT(bdev, 0);
6933a7eb6187SMike Gerdts 
6934a7eb6187SMike Gerdts 	/* Claim with options */
6935a7eb6187SMike Gerdts 	spdk_bdev_claim_opts_init(&opts, sizeof(opts));
6936a7eb6187SMike Gerdts 	snprintf(opts.name, sizeof(opts.name), "%s", "claim with options");
6937a7eb6187SMike Gerdts 	desc = NULL;
6938a7eb6187SMike Gerdts 	rc = spdk_bdev_open_ext("bdev0", false, bdev_ut_event_cb, NULL, &desc);
6939a7eb6187SMike Gerdts 	CU_ASSERT(rc == 0);
6940a7eb6187SMike Gerdts 	SPDK_CU_ASSERT_FATAL(desc != NULL);
6941a7eb6187SMike Gerdts 	rc = spdk_bdev_module_claim_bdev_desc(desc, SPDK_BDEV_CLAIM_READ_MANY_WRITE_NONE, &opts,
6942a7eb6187SMike Gerdts 					      &bdev_ut_if);
6943a7eb6187SMike Gerdts 	CU_ASSERT(rc == 0);
6944a7eb6187SMike Gerdts 	CU_ASSERT(bdev->internal.claim_type == SPDK_BDEV_CLAIM_READ_MANY_WRITE_NONE);
6945a7eb6187SMike Gerdts 	SPDK_CU_ASSERT_FATAL(desc->claim != NULL);
6946a7eb6187SMike Gerdts 	CU_ASSERT(desc->claim->module == &bdev_ut_if);
6947a7eb6187SMike Gerdts 	CU_ASSERT(strcmp(desc->claim->name, "claim with options") == 0);
6948a7eb6187SMike Gerdts 	memset(&opts, 0, sizeof(opts));
6949a7eb6187SMike Gerdts 	CU_ASSERT(strcmp(desc->claim->name, "claim with options") == 0);
6950a7eb6187SMike Gerdts 	CU_ASSERT(TAILQ_FIRST(&bdev->internal.claim.v2.claims) == desc->claim);
6951a7eb6187SMike Gerdts 	UT_ASSERT_CLAIM_V2_COUNT(bdev, 1);
6952a7eb6187SMike Gerdts 
6953a7eb6187SMike Gerdts 	/* The claim blocks new writers. */
6954a7eb6187SMike Gerdts 	desc2 = NULL;
6955a7eb6187SMike Gerdts 	rc = spdk_bdev_open_ext("bdev0", true, bdev_ut_event_cb, NULL, &desc2);
6956a7eb6187SMike Gerdts 	CU_ASSERT(rc == -EPERM);
6957a7eb6187SMike Gerdts 	CU_ASSERT(desc2 == NULL);
6958a7eb6187SMike Gerdts 
6959a7eb6187SMike Gerdts 	/* New readers are allowed */
6960a7eb6187SMike Gerdts 	desc2 = NULL;
6961a7eb6187SMike Gerdts 	rc = spdk_bdev_open_ext("bdev0", false, bdev_ut_event_cb, NULL, &desc2);
6962a7eb6187SMike Gerdts 	CU_ASSERT(rc == 0);
6963a7eb6187SMike Gerdts 	CU_ASSERT(desc2 != NULL);
6964a7eb6187SMike Gerdts 	CU_ASSERT(!desc2->write);
6965a7eb6187SMike Gerdts 
6966a7eb6187SMike Gerdts 	/* No new v2 RWO claims are allowed */
6967a7eb6187SMike Gerdts 	rc = spdk_bdev_module_claim_bdev_desc(desc2, SPDK_BDEV_CLAIM_READ_MANY_WRITE_ONE, NULL,
6968a7eb6187SMike Gerdts 					      &bdev_ut_if);
6969a7eb6187SMike Gerdts 	CU_ASSERT(rc == -EPERM);
6970a7eb6187SMike Gerdts 
6971a7eb6187SMike Gerdts 	/* No new v2 RWM claims are allowed */
6972a7eb6187SMike Gerdts 	spdk_bdev_claim_opts_init(&opts, sizeof(opts));
6973a7eb6187SMike Gerdts 	opts.shared_claim_key = (uint64_t)&opts;
6974a7eb6187SMike Gerdts 	rc = spdk_bdev_module_claim_bdev_desc(desc2, SPDK_BDEV_CLAIM_READ_MANY_WRITE_SHARED, &opts,
6975a7eb6187SMike Gerdts 					      &bdev_ut_if);
6976a7eb6187SMike Gerdts 	CU_ASSERT(rc == -EPERM);
6977a7eb6187SMike Gerdts 	CU_ASSERT(!desc2->write);
6978a7eb6187SMike Gerdts 
6979a7eb6187SMike Gerdts 	/* No new v1 claims are allowed */
6980a7eb6187SMike Gerdts 	rc = spdk_bdev_module_claim_bdev(bdev, NULL, &bdev_ut_if);
6981a7eb6187SMike Gerdts 	CU_ASSERT(rc == -EPERM);
6982a7eb6187SMike Gerdts 
6983a7eb6187SMike Gerdts 	/* None of the above messed up the existing claim */
6984a7eb6187SMike Gerdts 	CU_ASSERT(TAILQ_FIRST(&bdev->internal.claim.v2.claims) == desc->claim);
6985a7eb6187SMike Gerdts 	UT_ASSERT_CLAIM_V2_COUNT(bdev, 1);
6986a7eb6187SMike Gerdts 
6987a7eb6187SMike Gerdts 	/* New v2 ROM claims are allowed and the descriptor stays read-only. */
6988a7eb6187SMike Gerdts 	CU_ASSERT(!desc2->write);
6989a7eb6187SMike Gerdts 	rc = spdk_bdev_module_claim_bdev_desc(desc2, SPDK_BDEV_CLAIM_READ_MANY_WRITE_NONE, NULL,
6990a7eb6187SMike Gerdts 					      &bdev_ut_if);
6991a7eb6187SMike Gerdts 	CU_ASSERT(rc == 0);
6992a7eb6187SMike Gerdts 	CU_ASSERT(!desc2->write);
6993a7eb6187SMike Gerdts 	CU_ASSERT(TAILQ_FIRST(&bdev->internal.claim.v2.claims) == desc->claim);
6994a7eb6187SMike Gerdts 	CU_ASSERT(TAILQ_NEXT(desc->claim, link) == desc2->claim);
6995a7eb6187SMike Gerdts 	UT_ASSERT_CLAIM_V2_COUNT(bdev, 2);
6996a7eb6187SMike Gerdts 
6997a7eb6187SMike Gerdts 	/* Claim remains when closing the first descriptor */
6998a7eb6187SMike Gerdts 	spdk_bdev_close(desc);
6999a7eb6187SMike Gerdts 	CU_ASSERT(bdev->internal.claim_type == SPDK_BDEV_CLAIM_READ_MANY_WRITE_NONE);
7000a7eb6187SMike Gerdts 	CU_ASSERT(!TAILQ_EMPTY(&bdev->internal.open_descs));
7001a7eb6187SMike Gerdts 	CU_ASSERT(TAILQ_FIRST(&bdev->internal.claim.v2.claims) == desc2->claim);
7002a7eb6187SMike Gerdts 	UT_ASSERT_CLAIM_V2_COUNT(bdev, 1);
7003a7eb6187SMike Gerdts 
7004a7eb6187SMike Gerdts 	/* Claim removed when closing the other descriptor */
7005a7eb6187SMike Gerdts 	spdk_bdev_close(desc2);
7006a7eb6187SMike Gerdts 	CU_ASSERT(bdev->internal.claim_type == SPDK_BDEV_CLAIM_NONE);
7007a7eb6187SMike Gerdts 	UT_ASSERT_CLAIM_V2_COUNT(bdev, 0);
7008a7eb6187SMike Gerdts 	CU_ASSERT(TAILQ_EMPTY(&bdev->internal.open_descs));
7009a7eb6187SMike Gerdts 
7010a7eb6187SMike Gerdts 	/* Cannot claim with a key */
7011a7eb6187SMike Gerdts 	desc = NULL;
7012a7eb6187SMike Gerdts 	rc = spdk_bdev_open_ext("bdev0", false, bdev_ut_event_cb, NULL, &desc);
7013a7eb6187SMike Gerdts 	CU_ASSERT(rc == 0);
7014a7eb6187SMike Gerdts 	SPDK_CU_ASSERT_FATAL(desc != NULL);
7015a7eb6187SMike Gerdts 	spdk_bdev_claim_opts_init(&opts, sizeof(opts));
7016a7eb6187SMike Gerdts 	opts.shared_claim_key = (uint64_t)&opts;
7017a7eb6187SMike Gerdts 	rc = spdk_bdev_module_claim_bdev_desc(desc, SPDK_BDEV_CLAIM_READ_MANY_WRITE_NONE, &opts,
7018a7eb6187SMike Gerdts 					      &bdev_ut_if);
7019a7eb6187SMike Gerdts 	CU_ASSERT(rc == -EINVAL);
7020a7eb6187SMike Gerdts 	CU_ASSERT(bdev->internal.claim_type == SPDK_BDEV_CLAIM_NONE);
7021a7eb6187SMike Gerdts 	UT_ASSERT_CLAIM_V2_COUNT(bdev, 0);
7022a7eb6187SMike Gerdts 	spdk_bdev_close(desc);
7023a7eb6187SMike Gerdts 
7024a7eb6187SMike Gerdts 	/* Cannot claim with a read-write descriptor */
7025a7eb6187SMike Gerdts 	desc = NULL;
7026a7eb6187SMike Gerdts 	rc = spdk_bdev_open_ext("bdev0", true, bdev_ut_event_cb, NULL, &desc);
7027a7eb6187SMike Gerdts 	CU_ASSERT(rc == 0);
7028a7eb6187SMike Gerdts 	SPDK_CU_ASSERT_FATAL(desc != NULL);
7029a7eb6187SMike Gerdts 	rc = spdk_bdev_module_claim_bdev_desc(desc, SPDK_BDEV_CLAIM_READ_MANY_WRITE_NONE, NULL,
7030a7eb6187SMike Gerdts 					      &bdev_ut_if);
7031a7eb6187SMike Gerdts 	CU_ASSERT(rc == -EINVAL);
7032a7eb6187SMike Gerdts 	CU_ASSERT(bdev->internal.claim_type == SPDK_BDEV_CLAIM_NONE);
7033a7eb6187SMike Gerdts 	UT_ASSERT_CLAIM_V2_COUNT(bdev, 0);
7034a7eb6187SMike Gerdts 	spdk_bdev_close(desc);
7035a7eb6187SMike Gerdts 	CU_ASSERT(TAILQ_EMPTY(&bdev->internal.open_descs));
7036a7eb6187SMike Gerdts 
7037a7eb6187SMike Gerdts 	/* Clean up */
7038a7eb6187SMike Gerdts 	free_bdev(bdev);
7039a7eb6187SMike Gerdts }
7040a7eb6187SMike Gerdts 
7041a7eb6187SMike Gerdts static void
7042a7eb6187SMike Gerdts claim_v2_rwm(void)
7043a7eb6187SMike Gerdts {
7044a7eb6187SMike Gerdts 	struct spdk_bdev *bdev;
7045a7eb6187SMike Gerdts 	struct spdk_bdev_desc *desc;
7046a7eb6187SMike Gerdts 	struct spdk_bdev_desc *desc2;
7047a7eb6187SMike Gerdts 	struct spdk_bdev_claim_opts opts;
7048a7eb6187SMike Gerdts 	char good_key, bad_key;
7049a7eb6187SMike Gerdts 	int rc;
7050a7eb6187SMike Gerdts 
7051a7eb6187SMike Gerdts 	bdev = allocate_bdev("bdev0");
7052a7eb6187SMike Gerdts 
7053a7eb6187SMike Gerdts 	/* Claim without options should fail */
7054a7eb6187SMike Gerdts 	desc = NULL;
7055a7eb6187SMike Gerdts 	rc = spdk_bdev_open_ext("bdev0", true, bdev_ut_event_cb, NULL, &desc);
7056a7eb6187SMike Gerdts 	CU_ASSERT(rc == 0);
7057a7eb6187SMike Gerdts 	SPDK_CU_ASSERT_FATAL(desc != NULL);
7058a7eb6187SMike Gerdts 	rc = spdk_bdev_module_claim_bdev_desc(desc, SPDK_BDEV_CLAIM_READ_MANY_WRITE_SHARED, NULL,
7059a7eb6187SMike Gerdts 					      &bdev_ut_if);
7060a7eb6187SMike Gerdts 	CU_ASSERT(rc == -EINVAL);
7061a7eb6187SMike Gerdts 	CU_ASSERT(bdev->internal.claim_type == SPDK_BDEV_CLAIM_NONE);
7062a7eb6187SMike Gerdts 	UT_ASSERT_CLAIM_V2_COUNT(bdev, 0);
7063a7eb6187SMike Gerdts 	CU_ASSERT(desc->claim == NULL);
7064a7eb6187SMike Gerdts 
7065a7eb6187SMike Gerdts 	/* Claim with options */
7066a7eb6187SMike Gerdts 	spdk_bdev_claim_opts_init(&opts, sizeof(opts));
7067a7eb6187SMike Gerdts 	snprintf(opts.name, sizeof(opts.name), "%s", "claim with options");
7068a7eb6187SMike Gerdts 	opts.shared_claim_key = (uint64_t)&good_key;
7069a7eb6187SMike Gerdts 	rc = spdk_bdev_module_claim_bdev_desc(desc, SPDK_BDEV_CLAIM_READ_MANY_WRITE_SHARED, &opts,
7070a7eb6187SMike Gerdts 					      &bdev_ut_if);
7071a7eb6187SMike Gerdts 	CU_ASSERT(rc == 0);
7072a7eb6187SMike Gerdts 	CU_ASSERT(bdev->internal.claim_type == SPDK_BDEV_CLAIM_READ_MANY_WRITE_SHARED);
7073a7eb6187SMike Gerdts 	SPDK_CU_ASSERT_FATAL(desc->claim != NULL);
7074a7eb6187SMike Gerdts 	CU_ASSERT(desc->claim->module == &bdev_ut_if);
7075a7eb6187SMike Gerdts 	CU_ASSERT(strcmp(desc->claim->name, "claim with options") == 0);
7076a7eb6187SMike Gerdts 	memset(&opts, 0, sizeof(opts));
7077a7eb6187SMike Gerdts 	CU_ASSERT(strcmp(desc->claim->name, "claim with options") == 0);
7078a7eb6187SMike Gerdts 	CU_ASSERT(TAILQ_FIRST(&bdev->internal.claim.v2.claims) == desc->claim);
7079a7eb6187SMike Gerdts 	UT_ASSERT_CLAIM_V2_COUNT(bdev, 1);
7080a7eb6187SMike Gerdts 
7081a7eb6187SMike Gerdts 	/* The claim blocks new writers. */
7082a7eb6187SMike Gerdts 	desc2 = NULL;
7083a7eb6187SMike Gerdts 	rc = spdk_bdev_open_ext("bdev0", true, bdev_ut_event_cb, NULL, &desc2);
7084a7eb6187SMike Gerdts 	CU_ASSERT(rc == -EPERM);
7085a7eb6187SMike Gerdts 	CU_ASSERT(desc2 == NULL);
7086a7eb6187SMike Gerdts 
7087a7eb6187SMike Gerdts 	/* New readers are allowed */
7088a7eb6187SMike Gerdts 	desc2 = NULL;
7089a7eb6187SMike Gerdts 	rc = spdk_bdev_open_ext("bdev0", false, bdev_ut_event_cb, NULL, &desc2);
7090a7eb6187SMike Gerdts 	CU_ASSERT(rc == 0);
7091a7eb6187SMike Gerdts 	CU_ASSERT(desc2 != NULL);
7092a7eb6187SMike Gerdts 	CU_ASSERT(!desc2->write);
7093a7eb6187SMike Gerdts 
7094a7eb6187SMike Gerdts 	/* No new v2 RWO claims are allowed */
7095a7eb6187SMike Gerdts 	rc = spdk_bdev_module_claim_bdev_desc(desc2, SPDK_BDEV_CLAIM_READ_MANY_WRITE_ONE, NULL,
7096a7eb6187SMike Gerdts 					      &bdev_ut_if);
7097a7eb6187SMike Gerdts 	CU_ASSERT(rc == -EPERM);
7098a7eb6187SMike Gerdts 
7099a7eb6187SMike Gerdts 	/* No new v2 ROM claims are allowed and the descriptor stays read-only. */
7100a7eb6187SMike Gerdts 	CU_ASSERT(!desc2->write);
7101a7eb6187SMike Gerdts 	rc = spdk_bdev_module_claim_bdev_desc(desc2, SPDK_BDEV_CLAIM_READ_MANY_WRITE_NONE, NULL,
7102a7eb6187SMike Gerdts 					      &bdev_ut_if);
7103a7eb6187SMike Gerdts 	CU_ASSERT(rc == -EPERM);
7104a7eb6187SMike Gerdts 	CU_ASSERT(!desc2->write);
7105a7eb6187SMike Gerdts 
7106a7eb6187SMike Gerdts 	/* No new v1 claims are allowed */
7107a7eb6187SMike Gerdts 	rc = spdk_bdev_module_claim_bdev(bdev, NULL, &bdev_ut_if);
7108a7eb6187SMike Gerdts 	CU_ASSERT(rc == -EPERM);
7109a7eb6187SMike Gerdts 
7110a7eb6187SMike Gerdts 	/* No new v2 RWM claims are allowed if the key does not match */
7111a7eb6187SMike Gerdts 	spdk_bdev_claim_opts_init(&opts, sizeof(opts));
7112a7eb6187SMike Gerdts 	opts.shared_claim_key = (uint64_t)&bad_key;
7113a7eb6187SMike Gerdts 	rc = spdk_bdev_module_claim_bdev_desc(desc2, SPDK_BDEV_CLAIM_READ_MANY_WRITE_SHARED, &opts,
7114a7eb6187SMike Gerdts 					      &bdev_ut_if);
7115a7eb6187SMike Gerdts 	CU_ASSERT(rc == -EPERM);
7116a7eb6187SMike Gerdts 	CU_ASSERT(!desc2->write);
7117a7eb6187SMike Gerdts 
7118a7eb6187SMike Gerdts 	/* None of the above messed up the existing claim */
7119a7eb6187SMike Gerdts 	CU_ASSERT(TAILQ_FIRST(&bdev->internal.claim.v2.claims) == desc->claim);
7120a7eb6187SMike Gerdts 	UT_ASSERT_CLAIM_V2_COUNT(bdev, 1);
7121a7eb6187SMike Gerdts 
7122a7eb6187SMike Gerdts 	/* New v2 RWM claims are allowed and the descriptor is promoted if the key matches. */
7123a7eb6187SMike Gerdts 	spdk_bdev_claim_opts_init(&opts, sizeof(opts));
7124a7eb6187SMike Gerdts 	opts.shared_claim_key = (uint64_t)&good_key;
7125a7eb6187SMike Gerdts 	CU_ASSERT(!desc2->write);
7126a7eb6187SMike Gerdts 	rc = spdk_bdev_module_claim_bdev_desc(desc2, SPDK_BDEV_CLAIM_READ_MANY_WRITE_SHARED, &opts,
7127a7eb6187SMike Gerdts 					      &bdev_ut_if);
7128a7eb6187SMike Gerdts 	CU_ASSERT(rc == 0);
7129a7eb6187SMike Gerdts 	CU_ASSERT(desc2->write);
7130a7eb6187SMike Gerdts 	CU_ASSERT(TAILQ_NEXT(desc->claim, link) == desc2->claim);
7131a7eb6187SMike Gerdts 	UT_ASSERT_CLAIM_V2_COUNT(bdev, 2);
7132a7eb6187SMike Gerdts 
7133a7eb6187SMike Gerdts 	/* Claim remains when closing the first descriptor */
7134a7eb6187SMike Gerdts 	spdk_bdev_close(desc);
7135a7eb6187SMike Gerdts 	CU_ASSERT(bdev->internal.claim_type == SPDK_BDEV_CLAIM_READ_MANY_WRITE_SHARED);
7136a7eb6187SMike Gerdts 	CU_ASSERT(!TAILQ_EMPTY(&bdev->internal.open_descs));
7137a7eb6187SMike Gerdts 	CU_ASSERT(TAILQ_FIRST(&bdev->internal.claim.v2.claims) == desc2->claim);
7138a7eb6187SMike Gerdts 	UT_ASSERT_CLAIM_V2_COUNT(bdev, 1);
7139a7eb6187SMike Gerdts 
7140a7eb6187SMike Gerdts 	/* Claim removed when closing the other descriptor */
7141a7eb6187SMike Gerdts 	spdk_bdev_close(desc2);
7142a7eb6187SMike Gerdts 	CU_ASSERT(bdev->internal.claim_type == SPDK_BDEV_CLAIM_NONE);
7143a7eb6187SMike Gerdts 	CU_ASSERT(TAILQ_EMPTY(&bdev->internal.open_descs));
7144a7eb6187SMike Gerdts 
7145a7eb6187SMike Gerdts 	/* Cannot claim without a key */
7146a7eb6187SMike Gerdts 	desc = NULL;
7147a7eb6187SMike Gerdts 	rc = spdk_bdev_open_ext("bdev0", true, bdev_ut_event_cb, NULL, &desc);
7148a7eb6187SMike Gerdts 	CU_ASSERT(rc == 0);
7149a7eb6187SMike Gerdts 	SPDK_CU_ASSERT_FATAL(desc != NULL);
7150a7eb6187SMike Gerdts 	spdk_bdev_claim_opts_init(&opts, sizeof(opts));
7151a7eb6187SMike Gerdts 	rc = spdk_bdev_module_claim_bdev_desc(desc, SPDK_BDEV_CLAIM_READ_MANY_WRITE_SHARED, &opts,
7152a7eb6187SMike Gerdts 					      &bdev_ut_if);
7153a7eb6187SMike Gerdts 	CU_ASSERT(rc == -EINVAL);
7154a7eb6187SMike Gerdts 	spdk_bdev_close(desc);
7155a7eb6187SMike Gerdts 	CU_ASSERT(bdev->internal.claim_type == SPDK_BDEV_CLAIM_NONE);
7156a7eb6187SMike Gerdts 	CU_ASSERT(TAILQ_EMPTY(&bdev->internal.open_descs));
7157a7eb6187SMike Gerdts 
7158a7eb6187SMike Gerdts 	/* Clean up */
7159a7eb6187SMike Gerdts 	free_bdev(bdev);
7160a7eb6187SMike Gerdts }
7161a7eb6187SMike Gerdts 
7162a7eb6187SMike Gerdts static void
7163a7eb6187SMike Gerdts claim_v2_existing_writer(void)
7164a7eb6187SMike Gerdts {
7165a7eb6187SMike Gerdts 	struct spdk_bdev *bdev;
7166a7eb6187SMike Gerdts 	struct spdk_bdev_desc *desc;
7167a7eb6187SMike Gerdts 	struct spdk_bdev_desc *desc2;
7168a7eb6187SMike Gerdts 	struct spdk_bdev_claim_opts opts;
7169a7eb6187SMike Gerdts 	enum spdk_bdev_claim_type type;
7170a7eb6187SMike Gerdts 	enum spdk_bdev_claim_type types[] = {
7171a7eb6187SMike Gerdts 		SPDK_BDEV_CLAIM_READ_MANY_WRITE_ONE,
7172a7eb6187SMike Gerdts 		SPDK_BDEV_CLAIM_READ_MANY_WRITE_SHARED,
7173a7eb6187SMike Gerdts 		SPDK_BDEV_CLAIM_READ_MANY_WRITE_NONE
7174a7eb6187SMike Gerdts 	};
7175a7eb6187SMike Gerdts 	size_t i;
7176a7eb6187SMike Gerdts 	int rc;
7177a7eb6187SMike Gerdts 
7178a7eb6187SMike Gerdts 	bdev = allocate_bdev("bdev0");
7179a7eb6187SMike Gerdts 
7180a7eb6187SMike Gerdts 	desc = NULL;
7181a7eb6187SMike Gerdts 	rc = spdk_bdev_open_ext("bdev0", true, bdev_ut_event_cb, NULL, &desc);
7182a7eb6187SMike Gerdts 	CU_ASSERT(rc == 0);
7183a7eb6187SMike Gerdts 	SPDK_CU_ASSERT_FATAL(desc != NULL);
7184a7eb6187SMike Gerdts 	desc2 = NULL;
7185a7eb6187SMike Gerdts 	rc = spdk_bdev_open_ext("bdev0", true, bdev_ut_event_cb, NULL, &desc2);
7186a7eb6187SMike Gerdts 	CU_ASSERT(rc == 0);
7187a7eb6187SMike Gerdts 	SPDK_CU_ASSERT_FATAL(desc2 != NULL);
7188a7eb6187SMike Gerdts 
7189a7eb6187SMike Gerdts 	for (i = 0; i < SPDK_COUNTOF(types); i++) {
7190a7eb6187SMike Gerdts 		type = types[i];
7191a7eb6187SMike Gerdts 		spdk_bdev_claim_opts_init(&opts, sizeof(opts));
7192a7eb6187SMike Gerdts 		if (type == SPDK_BDEV_CLAIM_READ_MANY_WRITE_SHARED) {
7193a7eb6187SMike Gerdts 			opts.shared_claim_key = (uint64_t)&opts;
7194a7eb6187SMike Gerdts 		}
7195a7eb6187SMike Gerdts 		rc = spdk_bdev_module_claim_bdev_desc(desc, type, &opts, &bdev_ut_if);
7196a7eb6187SMike Gerdts 		if (type == SPDK_BDEV_CLAIM_READ_MANY_WRITE_NONE) {
7197a7eb6187SMike Gerdts 			CU_ASSERT(rc == -EINVAL);
7198a7eb6187SMike Gerdts 		} else {
7199a7eb6187SMike Gerdts 			CU_ASSERT(rc == -EPERM);
7200a7eb6187SMike Gerdts 		}
7201a7eb6187SMike Gerdts 		CU_ASSERT(bdev->internal.claim_type == SPDK_BDEV_CLAIM_NONE);
7202a7eb6187SMike Gerdts 		rc = spdk_bdev_module_claim_bdev_desc(desc2, type, &opts, &bdev_ut_if);
7203a7eb6187SMike Gerdts 		if (type == SPDK_BDEV_CLAIM_READ_MANY_WRITE_NONE) {
7204a7eb6187SMike Gerdts 			CU_ASSERT(rc == -EINVAL);
7205a7eb6187SMike Gerdts 		} else {
7206a7eb6187SMike Gerdts 			CU_ASSERT(rc == -EPERM);
7207a7eb6187SMike Gerdts 		}
7208a7eb6187SMike Gerdts 		CU_ASSERT(bdev->internal.claim_type == SPDK_BDEV_CLAIM_NONE);
7209a7eb6187SMike Gerdts 	}
7210a7eb6187SMike Gerdts 
7211a7eb6187SMike Gerdts 	spdk_bdev_close(desc);
7212a7eb6187SMike Gerdts 	spdk_bdev_close(desc2);
7213a7eb6187SMike Gerdts 
7214a7eb6187SMike Gerdts 	/* Clean up */
7215a7eb6187SMike Gerdts 	free_bdev(bdev);
7216a7eb6187SMike Gerdts }
7217a7eb6187SMike Gerdts 
7218a7eb6187SMike Gerdts static void
7219a7eb6187SMike Gerdts claim_v2_existing_v1(void)
7220a7eb6187SMike Gerdts {
7221a7eb6187SMike Gerdts 	struct spdk_bdev *bdev;
7222a7eb6187SMike Gerdts 	struct spdk_bdev_desc *desc;
7223a7eb6187SMike Gerdts 	struct spdk_bdev_claim_opts opts;
7224a7eb6187SMike Gerdts 	enum spdk_bdev_claim_type type;
7225a7eb6187SMike Gerdts 	enum spdk_bdev_claim_type types[] = {
7226a7eb6187SMike Gerdts 		SPDK_BDEV_CLAIM_READ_MANY_WRITE_ONE,
7227a7eb6187SMike Gerdts 		SPDK_BDEV_CLAIM_READ_MANY_WRITE_SHARED,
7228a7eb6187SMike Gerdts 		SPDK_BDEV_CLAIM_READ_MANY_WRITE_NONE
7229a7eb6187SMike Gerdts 	};
7230a7eb6187SMike Gerdts 	size_t i;
7231a7eb6187SMike Gerdts 	int rc;
7232a7eb6187SMike Gerdts 
7233a7eb6187SMike Gerdts 	bdev = allocate_bdev("bdev0");
7234a7eb6187SMike Gerdts 
7235a7eb6187SMike Gerdts 	rc = spdk_bdev_module_claim_bdev(bdev, NULL, &bdev_ut_if);
7236a7eb6187SMike Gerdts 	CU_ASSERT(rc == 0);
7237a7eb6187SMike Gerdts 	CU_ASSERT(bdev->internal.claim_type == SPDK_BDEV_CLAIM_EXCL_WRITE);
7238a7eb6187SMike Gerdts 
7239a7eb6187SMike Gerdts 	desc = NULL;
7240a7eb6187SMike Gerdts 	rc = spdk_bdev_open_ext("bdev0", false, bdev_ut_event_cb, NULL, &desc);
7241a7eb6187SMike Gerdts 	CU_ASSERT(rc == 0);
7242a7eb6187SMike Gerdts 	SPDK_CU_ASSERT_FATAL(desc != NULL);
7243a7eb6187SMike Gerdts 
7244a7eb6187SMike Gerdts 	for (i = 0; i < SPDK_COUNTOF(types); i++) {
7245a7eb6187SMike Gerdts 		type = types[i];
7246a7eb6187SMike Gerdts 		spdk_bdev_claim_opts_init(&opts, sizeof(opts));
7247a7eb6187SMike Gerdts 		if (type == SPDK_BDEV_CLAIM_READ_MANY_WRITE_SHARED) {
7248a7eb6187SMike Gerdts 			opts.shared_claim_key = (uint64_t)&opts;
7249a7eb6187SMike Gerdts 		}
7250a7eb6187SMike Gerdts 		rc = spdk_bdev_module_claim_bdev_desc(desc, type, &opts, &bdev_ut_if);
7251a7eb6187SMike Gerdts 		CU_ASSERT(rc == -EPERM);
7252a7eb6187SMike Gerdts 		CU_ASSERT(bdev->internal.claim_type == SPDK_BDEV_CLAIM_EXCL_WRITE);
7253a7eb6187SMike Gerdts 	}
7254a7eb6187SMike Gerdts 
7255a7eb6187SMike Gerdts 	spdk_bdev_module_release_bdev(bdev);
7256a7eb6187SMike Gerdts 	spdk_bdev_close(desc);
7257a7eb6187SMike Gerdts 
7258a7eb6187SMike Gerdts 	/* Clean up */
7259a7eb6187SMike Gerdts 	free_bdev(bdev);
7260a7eb6187SMike Gerdts }
7261a7eb6187SMike Gerdts 
7262a7eb6187SMike Gerdts static void
7263a7eb6187SMike Gerdts claim_v1_existing_v2(void)
7264a7eb6187SMike Gerdts {
7265a7eb6187SMike Gerdts 	struct spdk_bdev *bdev;
7266a7eb6187SMike Gerdts 	struct spdk_bdev_desc *desc;
7267a7eb6187SMike Gerdts 	struct spdk_bdev_claim_opts opts;
7268a7eb6187SMike Gerdts 	enum spdk_bdev_claim_type type;
7269a7eb6187SMike Gerdts 	enum spdk_bdev_claim_type types[] = {
7270a7eb6187SMike Gerdts 		SPDK_BDEV_CLAIM_READ_MANY_WRITE_ONE,
7271a7eb6187SMike Gerdts 		SPDK_BDEV_CLAIM_READ_MANY_WRITE_SHARED,
7272a7eb6187SMike Gerdts 		SPDK_BDEV_CLAIM_READ_MANY_WRITE_NONE
7273a7eb6187SMike Gerdts 	};
7274a7eb6187SMike Gerdts 	size_t i;
7275a7eb6187SMike Gerdts 	int rc;
7276a7eb6187SMike Gerdts 
7277a7eb6187SMike Gerdts 	bdev = allocate_bdev("bdev0");
7278a7eb6187SMike Gerdts 
7279a7eb6187SMike Gerdts 	for (i = 0; i < SPDK_COUNTOF(types); i++) {
7280a7eb6187SMike Gerdts 		type = types[i];
7281a7eb6187SMike Gerdts 
7282a7eb6187SMike Gerdts 		desc = NULL;
7283a7eb6187SMike Gerdts 		rc = spdk_bdev_open_ext("bdev0", false, bdev_ut_event_cb, NULL, &desc);
7284a7eb6187SMike Gerdts 		CU_ASSERT(rc == 0);
7285a7eb6187SMike Gerdts 		SPDK_CU_ASSERT_FATAL(desc != NULL);
7286a7eb6187SMike Gerdts 
7287a7eb6187SMike Gerdts 		/* Get a v2 claim */
7288a7eb6187SMike Gerdts 		spdk_bdev_claim_opts_init(&opts, sizeof(opts));
7289a7eb6187SMike Gerdts 		if (type == SPDK_BDEV_CLAIM_READ_MANY_WRITE_SHARED) {
7290a7eb6187SMike Gerdts 			opts.shared_claim_key = (uint64_t)&opts;
7291a7eb6187SMike Gerdts 		}
7292a7eb6187SMike Gerdts 		rc = spdk_bdev_module_claim_bdev_desc(desc, type, &opts, &bdev_ut_if);
7293a7eb6187SMike Gerdts 		CU_ASSERT(rc == 0);
7294a7eb6187SMike Gerdts 
7295a7eb6187SMike Gerdts 		/* Fail to get a v1 claim */
7296a7eb6187SMike Gerdts 		rc = spdk_bdev_module_claim_bdev(bdev, NULL, &bdev_ut_if);
7297a7eb6187SMike Gerdts 		CU_ASSERT(rc == -EPERM);
7298a7eb6187SMike Gerdts 
7299a7eb6187SMike Gerdts 		spdk_bdev_close(desc);
7300a7eb6187SMike Gerdts 
7301a7eb6187SMike Gerdts 		/* Now v1 succeeds */
7302a7eb6187SMike Gerdts 		rc = spdk_bdev_module_claim_bdev(bdev, NULL, &bdev_ut_if);
7303a7eb6187SMike Gerdts 		CU_ASSERT(rc == 0)
7304a7eb6187SMike Gerdts 		spdk_bdev_module_release_bdev(bdev);
7305a7eb6187SMike Gerdts 	}
7306a7eb6187SMike Gerdts 
7307a7eb6187SMike Gerdts 	/* Clean up */
7308a7eb6187SMike Gerdts 	free_bdev(bdev);
7309a7eb6187SMike Gerdts }
7310a7eb6187SMike Gerdts 
7311cd7064c7SNathan Claudel static int ut_examine_claimed_init0(void);
7312cd7064c7SNathan Claudel static int ut_examine_claimed_init1(void);
731386bbcdb8SMike Gerdts static void ut_examine_claimed_config0(struct spdk_bdev *bdev);
731486bbcdb8SMike Gerdts static void ut_examine_claimed_disk0(struct spdk_bdev *bdev);
731586bbcdb8SMike Gerdts static void ut_examine_claimed_config1(struct spdk_bdev *bdev);
731686bbcdb8SMike Gerdts static void ut_examine_claimed_disk1(struct spdk_bdev *bdev);
731786bbcdb8SMike Gerdts 
731886bbcdb8SMike Gerdts #define UT_MAX_EXAMINE_MODS 2
731986bbcdb8SMike Gerdts struct spdk_bdev_module examine_claimed_mods[UT_MAX_EXAMINE_MODS] = {
732086bbcdb8SMike Gerdts 	{
732186bbcdb8SMike Gerdts 		.name = "vbdev_ut_examine0",
7322cd7064c7SNathan Claudel 		.module_init = ut_examine_claimed_init0,
732386bbcdb8SMike Gerdts 		.module_fini = vbdev_ut_module_fini,
732486bbcdb8SMike Gerdts 		.examine_config = ut_examine_claimed_config0,
732586bbcdb8SMike Gerdts 		.examine_disk = ut_examine_claimed_disk0,
732686bbcdb8SMike Gerdts 	},
732786bbcdb8SMike Gerdts 	{
732886bbcdb8SMike Gerdts 		.name = "vbdev_ut_examine1",
7329cd7064c7SNathan Claudel 		.module_init = ut_examine_claimed_init1,
733086bbcdb8SMike Gerdts 		.module_fini = vbdev_ut_module_fini,
733186bbcdb8SMike Gerdts 		.examine_config = ut_examine_claimed_config1,
733286bbcdb8SMike Gerdts 		.examine_disk = ut_examine_claimed_disk1,
733386bbcdb8SMike Gerdts 	}
733486bbcdb8SMike Gerdts };
733586bbcdb8SMike Gerdts 
733686bbcdb8SMike Gerdts SPDK_BDEV_MODULE_REGISTER(bdev_ut_claimed0, &examine_claimed_mods[0])
733786bbcdb8SMike Gerdts SPDK_BDEV_MODULE_REGISTER(bdev_ut_claimed1, &examine_claimed_mods[1])
733886bbcdb8SMike Gerdts 
733986bbcdb8SMike Gerdts struct ut_examine_claimed_ctx {
734086bbcdb8SMike Gerdts 	uint32_t examine_config_count;
734186bbcdb8SMike Gerdts 	uint32_t examine_disk_count;
734286bbcdb8SMike Gerdts 
734386bbcdb8SMike Gerdts 	/* Claim type to take, with these options */
734486bbcdb8SMike Gerdts 	enum spdk_bdev_claim_type claim_type;
734586bbcdb8SMike Gerdts 	struct spdk_bdev_claim_opts claim_opts;
734686bbcdb8SMike Gerdts 
734786bbcdb8SMike Gerdts 	/* Expected return value from spdk_bdev_module_claim_bdev_desc() */
734886bbcdb8SMike Gerdts 	int expect_claim_err;
734986bbcdb8SMike Gerdts 
735086bbcdb8SMike Gerdts 	/* Descriptor used for a claim */
735186bbcdb8SMike Gerdts 	struct spdk_bdev_desc *desc;
735286bbcdb8SMike Gerdts } examine_claimed_ctx[UT_MAX_EXAMINE_MODS];
735386bbcdb8SMike Gerdts 
735486bbcdb8SMike Gerdts bool ut_testing_examine_claimed;
735586bbcdb8SMike Gerdts 
7356cd7064c7SNathan Claudel /*
7357cd7064c7SNathan Claudel  * Store the order in which the modules were initialized,
7358cd7064c7SNathan Claudel  * since we have no guarantee on the order of execution of the constructors.
7359cd7064c7SNathan Claudel  * Modules are examined in reverse order of their initialization.
7360cd7064c7SNathan Claudel  */
7361cd7064c7SNathan Claudel static int g_ut_examine_claimed_order[UT_MAX_EXAMINE_MODS];
7362cd7064c7SNathan Claudel static int
7363cd7064c7SNathan Claudel ut_examine_claimed_init(uint32_t modnum)
7364cd7064c7SNathan Claudel {
7365cd7064c7SNathan Claudel 	static int current = UT_MAX_EXAMINE_MODS;
7366cd7064c7SNathan Claudel 
736734edd9f1SKamil Godzwon 	/* Only do this for the first initialization of the bdev framework */
7368cd7064c7SNathan Claudel 	if (current == 0) {
7369cd7064c7SNathan Claudel 		return 0;
7370cd7064c7SNathan Claudel 	}
7371cd7064c7SNathan Claudel 	g_ut_examine_claimed_order[modnum] = --current;
7372cd7064c7SNathan Claudel 
7373cd7064c7SNathan Claudel 	return 0;
7374cd7064c7SNathan Claudel }
7375cd7064c7SNathan Claudel 
7376cd7064c7SNathan Claudel static int
7377cd7064c7SNathan Claudel ut_examine_claimed_init0(void)
7378cd7064c7SNathan Claudel {
7379cd7064c7SNathan Claudel 	return ut_examine_claimed_init(0);
7380cd7064c7SNathan Claudel }
7381cd7064c7SNathan Claudel 
7382cd7064c7SNathan Claudel static int
7383cd7064c7SNathan Claudel ut_examine_claimed_init1(void)
7384cd7064c7SNathan Claudel {
7385cd7064c7SNathan Claudel 	return ut_examine_claimed_init(1);
7386cd7064c7SNathan Claudel }
7387cd7064c7SNathan Claudel 
738886bbcdb8SMike Gerdts static void
738986bbcdb8SMike Gerdts reset_examine_claimed_ctx(void)
739086bbcdb8SMike Gerdts {
739186bbcdb8SMike Gerdts 	struct ut_examine_claimed_ctx *ctx;
739286bbcdb8SMike Gerdts 	uint32_t i;
739386bbcdb8SMike Gerdts 
739486bbcdb8SMike Gerdts 	for (i = 0; i < SPDK_COUNTOF(examine_claimed_ctx); i++) {
739586bbcdb8SMike Gerdts 		ctx = &examine_claimed_ctx[i];
739686bbcdb8SMike Gerdts 		if (ctx->desc != NULL) {
739786bbcdb8SMike Gerdts 			spdk_bdev_close(ctx->desc);
739886bbcdb8SMike Gerdts 		}
739986bbcdb8SMike Gerdts 		memset(ctx, 0, sizeof(*ctx));
740086bbcdb8SMike Gerdts 		spdk_bdev_claim_opts_init(&ctx->claim_opts, sizeof(ctx->claim_opts));
740186bbcdb8SMike Gerdts 	}
740286bbcdb8SMike Gerdts }
740386bbcdb8SMike Gerdts 
740486bbcdb8SMike Gerdts static void
740586bbcdb8SMike Gerdts examine_claimed_config(struct spdk_bdev *bdev, uint32_t modnum)
740686bbcdb8SMike Gerdts {
740786bbcdb8SMike Gerdts 	SPDK_CU_ASSERT_FATAL(modnum < UT_MAX_EXAMINE_MODS);
740886bbcdb8SMike Gerdts 	struct spdk_bdev_module *module = &examine_claimed_mods[modnum];
740986bbcdb8SMike Gerdts 	struct ut_examine_claimed_ctx *ctx = &examine_claimed_ctx[modnum];
741086bbcdb8SMike Gerdts 	int rc;
741186bbcdb8SMike Gerdts 
741286bbcdb8SMike Gerdts 	if (!ut_testing_examine_claimed) {
741386bbcdb8SMike Gerdts 		spdk_bdev_module_examine_done(module);
741486bbcdb8SMike Gerdts 		return;
741586bbcdb8SMike Gerdts 	}
741686bbcdb8SMike Gerdts 
741786bbcdb8SMike Gerdts 	ctx->examine_config_count++;
741886bbcdb8SMike Gerdts 
741986bbcdb8SMike Gerdts 	if (ctx->claim_type != SPDK_BDEV_CLAIM_NONE) {
742086bbcdb8SMike Gerdts 		rc = spdk_bdev_open_ext(bdev->name, false, bdev_ut_event_cb, &ctx->claim_opts,
742186bbcdb8SMike Gerdts 					&ctx->desc);
742286bbcdb8SMike Gerdts 		CU_ASSERT(rc == 0);
742386bbcdb8SMike Gerdts 
742486bbcdb8SMike Gerdts 		rc = spdk_bdev_module_claim_bdev_desc(ctx->desc, ctx->claim_type, NULL, module);
742586bbcdb8SMike Gerdts 		CU_ASSERT(rc == ctx->expect_claim_err);
742686bbcdb8SMike Gerdts 	}
742786bbcdb8SMike Gerdts 	spdk_bdev_module_examine_done(module);
742886bbcdb8SMike Gerdts }
742986bbcdb8SMike Gerdts 
743086bbcdb8SMike Gerdts static void
743186bbcdb8SMike Gerdts ut_examine_claimed_config0(struct spdk_bdev *bdev)
743286bbcdb8SMike Gerdts {
7433cd7064c7SNathan Claudel 	examine_claimed_config(bdev, g_ut_examine_claimed_order[0]);
743486bbcdb8SMike Gerdts }
743586bbcdb8SMike Gerdts 
743686bbcdb8SMike Gerdts static void
743786bbcdb8SMike Gerdts ut_examine_claimed_config1(struct spdk_bdev *bdev)
743886bbcdb8SMike Gerdts {
7439cd7064c7SNathan Claudel 	examine_claimed_config(bdev, g_ut_examine_claimed_order[1]);
744086bbcdb8SMike Gerdts }
744186bbcdb8SMike Gerdts 
744286bbcdb8SMike Gerdts static void
744386bbcdb8SMike Gerdts examine_claimed_disk(struct spdk_bdev *bdev, uint32_t modnum)
744486bbcdb8SMike Gerdts {
744586bbcdb8SMike Gerdts 	SPDK_CU_ASSERT_FATAL(modnum < UT_MAX_EXAMINE_MODS);
744686bbcdb8SMike Gerdts 	struct spdk_bdev_module *module = &examine_claimed_mods[modnum];
744786bbcdb8SMike Gerdts 	struct ut_examine_claimed_ctx *ctx = &examine_claimed_ctx[modnum];
744886bbcdb8SMike Gerdts 
744986bbcdb8SMike Gerdts 	if (!ut_testing_examine_claimed) {
745086bbcdb8SMike Gerdts 		spdk_bdev_module_examine_done(module);
745186bbcdb8SMike Gerdts 		return;
745286bbcdb8SMike Gerdts 	}
745386bbcdb8SMike Gerdts 
745486bbcdb8SMike Gerdts 	ctx->examine_disk_count++;
745586bbcdb8SMike Gerdts 
745686bbcdb8SMike Gerdts 	spdk_bdev_module_examine_done(module);
745786bbcdb8SMike Gerdts }
745886bbcdb8SMike Gerdts 
745986bbcdb8SMike Gerdts static void
746086bbcdb8SMike Gerdts ut_examine_claimed_disk0(struct spdk_bdev *bdev)
746186bbcdb8SMike Gerdts {
746286bbcdb8SMike Gerdts 	examine_claimed_disk(bdev, 0);
746386bbcdb8SMike Gerdts }
746486bbcdb8SMike Gerdts 
746586bbcdb8SMike Gerdts static void
746686bbcdb8SMike Gerdts ut_examine_claimed_disk1(struct spdk_bdev *bdev)
746786bbcdb8SMike Gerdts {
746886bbcdb8SMike Gerdts 	examine_claimed_disk(bdev, 1);
746986bbcdb8SMike Gerdts }
747086bbcdb8SMike Gerdts 
747102935561SEd Reed static bool g_examine_done = false;
747202935561SEd Reed 
747386bbcdb8SMike Gerdts static void
747402935561SEd Reed ut_examine_done_cb(void *ctx)
747502935561SEd Reed {
747602935561SEd Reed 	g_examine_done = true;
747702935561SEd Reed }
747802935561SEd Reed 
747902935561SEd Reed static void
748002935561SEd Reed examine_claimed_common(bool autoexamine)
748186bbcdb8SMike Gerdts {
748286bbcdb8SMike Gerdts 	struct spdk_bdev *bdev;
748386bbcdb8SMike Gerdts 	struct spdk_bdev_module *mod = examine_claimed_mods;
748486bbcdb8SMike Gerdts 	struct ut_examine_claimed_ctx *ctx = examine_claimed_ctx;
748502935561SEd Reed 	struct spdk_bdev_opts bdev_opts = {};
748602935561SEd Reed 	int rc;
748702935561SEd Reed 
748802935561SEd Reed 	spdk_bdev_get_opts(&bdev_opts, sizeof(bdev_opts));
748902935561SEd Reed 	bdev_opts.bdev_auto_examine = autoexamine;
749002935561SEd Reed 	ut_init_bdev(&bdev_opts);
749186bbcdb8SMike Gerdts 
749286bbcdb8SMike Gerdts 	ut_testing_examine_claimed = true;
749386bbcdb8SMike Gerdts 	reset_examine_claimed_ctx();
749486bbcdb8SMike Gerdts 
749586bbcdb8SMike Gerdts 	/*
749686bbcdb8SMike Gerdts 	 * With one module claiming, both modules' examine_config should be called, but only the
749786bbcdb8SMike Gerdts 	 * claiming module's examine_disk should be called.
749886bbcdb8SMike Gerdts 	 */
749986bbcdb8SMike Gerdts 	ctx[0].claim_type = SPDK_BDEV_CLAIM_READ_MANY_WRITE_NONE;
750002935561SEd Reed 	g_examine_done = false;
750186bbcdb8SMike Gerdts 	bdev = allocate_bdev("bdev0");
750202935561SEd Reed 
750302935561SEd Reed 	if (!autoexamine) {
750402935561SEd Reed 		rc = spdk_bdev_examine("bdev0");
750502935561SEd Reed 		CU_ASSERT(rc == 0);
750602935561SEd Reed 		rc = spdk_bdev_wait_for_examine(ut_examine_done_cb, NULL);
750702935561SEd Reed 		CU_ASSERT(rc == 0);
750802935561SEd Reed 		CU_ASSERT(!g_examine_done);
750902935561SEd Reed 		poll_threads();
751002935561SEd Reed 		CU_ASSERT(g_examine_done);
751102935561SEd Reed 	}
751202935561SEd Reed 
751386bbcdb8SMike Gerdts 	CU_ASSERT(ctx[0].examine_config_count == 1);
751486bbcdb8SMike Gerdts 	CU_ASSERT(ctx[0].examine_disk_count == 1);
751586bbcdb8SMike Gerdts 	SPDK_CU_ASSERT_FATAL(ctx[0].desc != NULL);
751686bbcdb8SMike Gerdts 	CU_ASSERT(ctx[0].desc->claim->module == &mod[0]);
751786bbcdb8SMike Gerdts 	CU_ASSERT(ctx[1].examine_config_count == 1);
751886bbcdb8SMike Gerdts 	CU_ASSERT(ctx[1].examine_disk_count == 0);
751986bbcdb8SMike Gerdts 	CU_ASSERT(ctx[1].desc == NULL);
752086bbcdb8SMike Gerdts 	reset_examine_claimed_ctx();
752186bbcdb8SMike Gerdts 	free_bdev(bdev);
752286bbcdb8SMike Gerdts 
752386bbcdb8SMike Gerdts 	/*
752486bbcdb8SMike Gerdts 	 * With two modules claiming, both modules' examine_config and examine_disk should be
752586bbcdb8SMike Gerdts 	 * called.
752686bbcdb8SMike Gerdts 	 */
752786bbcdb8SMike Gerdts 	ctx[0].claim_type = SPDK_BDEV_CLAIM_READ_MANY_WRITE_NONE;
752886bbcdb8SMike Gerdts 	ctx[1].claim_type = SPDK_BDEV_CLAIM_READ_MANY_WRITE_NONE;
752902935561SEd Reed 	g_examine_done = false;
753086bbcdb8SMike Gerdts 	bdev = allocate_bdev("bdev0");
753102935561SEd Reed 
753202935561SEd Reed 	if (!autoexamine) {
753302935561SEd Reed 		rc = spdk_bdev_examine("bdev0");
753402935561SEd Reed 		CU_ASSERT(rc == 0);
753502935561SEd Reed 		rc = spdk_bdev_wait_for_examine(ut_examine_done_cb, NULL);
753602935561SEd Reed 		CU_ASSERT(rc == 0);
753702935561SEd Reed 		CU_ASSERT(!g_examine_done);
753802935561SEd Reed 		poll_threads();
753902935561SEd Reed 		CU_ASSERT(g_examine_done);
754002935561SEd Reed 	}
754102935561SEd Reed 
754286bbcdb8SMike Gerdts 	CU_ASSERT(ctx[0].examine_config_count == 1);
754386bbcdb8SMike Gerdts 	CU_ASSERT(ctx[0].examine_disk_count == 1);
754486bbcdb8SMike Gerdts 	SPDK_CU_ASSERT_FATAL(ctx[0].desc != NULL);
754586bbcdb8SMike Gerdts 	CU_ASSERT(ctx[0].desc->claim->module == &mod[0]);
754686bbcdb8SMike Gerdts 	CU_ASSERT(ctx[1].examine_config_count == 1);
754786bbcdb8SMike Gerdts 	CU_ASSERT(ctx[1].examine_disk_count == 1);
754886bbcdb8SMike Gerdts 	SPDK_CU_ASSERT_FATAL(ctx[1].desc != NULL);
754986bbcdb8SMike Gerdts 	CU_ASSERT(ctx[1].desc->claim->module == &mod[1]);
755086bbcdb8SMike Gerdts 	reset_examine_claimed_ctx();
755186bbcdb8SMike Gerdts 	free_bdev(bdev);
755286bbcdb8SMike Gerdts 
755386bbcdb8SMike Gerdts 	/*
755486bbcdb8SMike Gerdts 	 * If two vbdev modules try to claim with conflicting claim types, the module that was added
755586bbcdb8SMike Gerdts 	 * last wins. The winner gets the claim and is the only one that has its examine_disk
755686bbcdb8SMike Gerdts 	 * callback invoked.
755786bbcdb8SMike Gerdts 	 */
755886bbcdb8SMike Gerdts 	ctx[0].claim_type = SPDK_BDEV_CLAIM_READ_MANY_WRITE_NONE;
755986bbcdb8SMike Gerdts 	ctx[0].expect_claim_err = -EPERM;
756086bbcdb8SMike Gerdts 	ctx[1].claim_type = SPDK_BDEV_CLAIM_READ_MANY_WRITE_ONE;
756102935561SEd Reed 	g_examine_done = false;
756286bbcdb8SMike Gerdts 	bdev = allocate_bdev("bdev0");
756302935561SEd Reed 
756402935561SEd Reed 	if (!autoexamine) {
756502935561SEd Reed 		rc = spdk_bdev_examine("bdev0");
756602935561SEd Reed 		CU_ASSERT(rc == 0);
756702935561SEd Reed 		rc = spdk_bdev_wait_for_examine(ut_examine_done_cb, NULL);
756802935561SEd Reed 		CU_ASSERT(rc == 0);
756902935561SEd Reed 		CU_ASSERT(!g_examine_done);
757002935561SEd Reed 		poll_threads();
757102935561SEd Reed 		CU_ASSERT(g_examine_done);
757202935561SEd Reed 	}
757302935561SEd Reed 
757486bbcdb8SMike Gerdts 	CU_ASSERT(ctx[0].examine_config_count == 1);
757586bbcdb8SMike Gerdts 	CU_ASSERT(ctx[0].examine_disk_count == 0);
757686bbcdb8SMike Gerdts 	CU_ASSERT(ctx[1].examine_config_count == 1);
757786bbcdb8SMike Gerdts 	CU_ASSERT(ctx[1].examine_disk_count == 1);
757886bbcdb8SMike Gerdts 	SPDK_CU_ASSERT_FATAL(ctx[1].desc != NULL);
757986bbcdb8SMike Gerdts 	CU_ASSERT(ctx[1].desc->claim->module == &mod[1]);
758086bbcdb8SMike Gerdts 	CU_ASSERT(bdev->internal.claim_type == SPDK_BDEV_CLAIM_READ_MANY_WRITE_ONE);
758186bbcdb8SMike Gerdts 	reset_examine_claimed_ctx();
758286bbcdb8SMike Gerdts 	free_bdev(bdev);
758386bbcdb8SMike Gerdts 
758486bbcdb8SMike Gerdts 	ut_testing_examine_claimed = false;
758502935561SEd Reed 
758602935561SEd Reed 	ut_fini_bdev();
758702935561SEd Reed }
758802935561SEd Reed 
758902935561SEd Reed static void
759002935561SEd Reed examine_claimed(void)
759102935561SEd Reed {
759202935561SEd Reed 	examine_claimed_common(true);
759302935561SEd Reed }
759402935561SEd Reed 
759502935561SEd Reed static void
759602935561SEd Reed examine_claimed_manual(void)
759702935561SEd Reed {
759802935561SEd Reed 	examine_claimed_common(false);
759986bbcdb8SMike Gerdts }
760086bbcdb8SMike Gerdts 
7601fee788f6SJim Harris static void
7602fee788f6SJim Harris get_numa_id(void)
7603fee788f6SJim Harris {
7604fee788f6SJim Harris 	struct spdk_bdev bdev = {};
7605fee788f6SJim Harris 
7606fee788f6SJim Harris 	bdev.numa.id = 0;
7607fee788f6SJim Harris 	bdev.numa.id_valid = 0;
7608fee788f6SJim Harris 	CU_ASSERT(spdk_bdev_get_numa_id(&bdev) == SPDK_ENV_NUMA_ID_ANY);
7609fee788f6SJim Harris 
7610fee788f6SJim Harris 	bdev.numa.id_valid = 1;
7611fee788f6SJim Harris 	CU_ASSERT(spdk_bdev_get_numa_id(&bdev) == 0);
7612fee788f6SJim Harris 
7613fee788f6SJim Harris 	bdev.numa.id = SPDK_ENV_NUMA_ID_ANY;
7614fee788f6SJim Harris 	CU_ASSERT(spdk_bdev_get_numa_id(&bdev) == SPDK_ENV_NUMA_ID_ANY);
7615fee788f6SJim Harris }
7616fee788f6SJim Harris 
761763e0c25dSVasilii Ivanov static void
761863e0c25dSVasilii Ivanov get_device_stat_with_reset_cb(struct spdk_bdev *bdev, struct spdk_bdev_io_stat *stat, void *cb_arg,
761963e0c25dSVasilii Ivanov 			      int rc)
762063e0c25dSVasilii Ivanov {
762163e0c25dSVasilii Ivanov 	*(bool *)cb_arg = true;
762263e0c25dSVasilii Ivanov }
762363e0c25dSVasilii Ivanov 
762463e0c25dSVasilii Ivanov static void
762563e0c25dSVasilii Ivanov get_device_stat_with_given_reset(struct spdk_bdev *bdev, struct spdk_bdev_io_stat *stat,
762663e0c25dSVasilii Ivanov 				 enum spdk_bdev_reset_stat_mode mode)
762763e0c25dSVasilii Ivanov {
762863e0c25dSVasilii Ivanov 	bool done = false;
762963e0c25dSVasilii Ivanov 
763063e0c25dSVasilii Ivanov 	spdk_bdev_get_device_stat(bdev, stat, mode, get_device_stat_with_reset_cb, &done);
763163e0c25dSVasilii Ivanov 	while (!done) { poll_threads(); }
763263e0c25dSVasilii Ivanov }
763363e0c25dSVasilii Ivanov 
763463e0c25dSVasilii Ivanov static void
763563e0c25dSVasilii Ivanov get_device_stat_with_reset(void)
763663e0c25dSVasilii Ivanov {
763763e0c25dSVasilii Ivanov 	struct spdk_bdev *bdev;
763863e0c25dSVasilii Ivanov 	struct spdk_bdev_desc *desc = NULL;
763963e0c25dSVasilii Ivanov 	struct spdk_io_channel *io_ch;
764063e0c25dSVasilii Ivanov 	struct spdk_bdev_opts bdev_opts = {};
764163e0c25dSVasilii Ivanov 	struct spdk_bdev_io_stat *stat;
764263e0c25dSVasilii Ivanov 
764363e0c25dSVasilii Ivanov 	spdk_bdev_get_opts(&bdev_opts, sizeof(bdev_opts));
764463e0c25dSVasilii Ivanov 	bdev_opts.bdev_io_pool_size = 2;
764563e0c25dSVasilii Ivanov 	bdev_opts.bdev_io_cache_size = 1;
764663e0c25dSVasilii Ivanov 	ut_init_bdev(&bdev_opts);
764763e0c25dSVasilii Ivanov 	bdev = allocate_bdev("bdev0");
764863e0c25dSVasilii Ivanov 
764963e0c25dSVasilii Ivanov 	CU_ASSERT(spdk_bdev_open_ext("bdev0", true, bdev_ut_event_cb, NULL, &desc) == 0);
765063e0c25dSVasilii Ivanov 	SPDK_CU_ASSERT_FATAL(desc != NULL);
765163e0c25dSVasilii Ivanov 	CU_ASSERT(bdev == spdk_bdev_desc_get_bdev(desc));
765263e0c25dSVasilii Ivanov 	io_ch = spdk_bdev_get_io_channel(desc);
765363e0c25dSVasilii Ivanov 	CU_ASSERT(io_ch != NULL);
765463e0c25dSVasilii Ivanov 
765563e0c25dSVasilii Ivanov 	g_io_done = false;
765663e0c25dSVasilii Ivanov 	CU_ASSERT(spdk_bdev_read(desc, io_ch, (void *)0x1000, 0, 4096, io_done, NULL) == 0);
765763e0c25dSVasilii Ivanov 	spdk_delay_us(10);
765863e0c25dSVasilii Ivanov 	stub_complete_io(1);
765963e0c25dSVasilii Ivanov 	CU_ASSERT(g_io_done == true);
766063e0c25dSVasilii Ivanov 
766163e0c25dSVasilii Ivanov 	stat = calloc(1, sizeof(struct spdk_bdev_io_stat));
766263e0c25dSVasilii Ivanov 	SPDK_CU_ASSERT_FATAL(stat != NULL);
766363e0c25dSVasilii Ivanov 
766463e0c25dSVasilii Ivanov 	/* Get stat without resetting and check that it is correct  */
766563e0c25dSVasilii Ivanov 	get_device_stat_with_given_reset(bdev, stat, SPDK_BDEV_RESET_STAT_NONE);
766663e0c25dSVasilii Ivanov 	CU_ASSERT(stat->bytes_read == 4096);
766763e0c25dSVasilii Ivanov 	CU_ASSERT(stat->max_read_latency_ticks == 10);
766863e0c25dSVasilii Ivanov 
766963e0c25dSVasilii Ivanov 	/**
767063e0c25dSVasilii Ivanov 	 * Check that stat was not reseted after previous step,
767163e0c25dSVasilii Ivanov 	 * send get request with resetting maxmin stats
767263e0c25dSVasilii Ivanov 	 */
767363e0c25dSVasilii Ivanov 	get_device_stat_with_given_reset(bdev, stat, SPDK_BDEV_RESET_STAT_MAXMIN);
767463e0c25dSVasilii Ivanov 	CU_ASSERT(stat->bytes_read == 4096);
767563e0c25dSVasilii Ivanov 	CU_ASSERT(stat->max_read_latency_ticks == 10);
767663e0c25dSVasilii Ivanov 
767763e0c25dSVasilii Ivanov 	/**
767863e0c25dSVasilii Ivanov 	 * Check that maxmins stats are reseted after previous step,
767963e0c25dSVasilii Ivanov 	 * send get request with resetting all stats
768063e0c25dSVasilii Ivanov 	 */
768163e0c25dSVasilii Ivanov 	get_device_stat_with_given_reset(bdev, stat, SPDK_BDEV_RESET_STAT_ALL);
768263e0c25dSVasilii Ivanov 	CU_ASSERT(stat->bytes_read == 4096);
768363e0c25dSVasilii Ivanov 	CU_ASSERT(stat->max_read_latency_ticks == 0);
768463e0c25dSVasilii Ivanov 
768563e0c25dSVasilii Ivanov 	/* Check that all stats are reseted after previous step */
768663e0c25dSVasilii Ivanov 	get_device_stat_with_given_reset(bdev, stat, SPDK_BDEV_RESET_STAT_NONE);
768763e0c25dSVasilii Ivanov 	CU_ASSERT(stat->bytes_read == 0);
768863e0c25dSVasilii Ivanov 	CU_ASSERT(stat->max_read_latency_ticks == 0);
768963e0c25dSVasilii Ivanov 
769063e0c25dSVasilii Ivanov 	free(stat);
769163e0c25dSVasilii Ivanov 	spdk_put_io_channel(io_ch);
769263e0c25dSVasilii Ivanov 	spdk_bdev_close(desc);
769363e0c25dSVasilii Ivanov 	free_bdev(bdev);
769463e0c25dSVasilii Ivanov 	ut_fini_bdev();
769563e0c25dSVasilii Ivanov }
769663e0c25dSVasilii Ivanov 
769716e5e505SShuhei Matsumoto static void
769816e5e505SShuhei Matsumoto open_ext_v2_test(void)
769916e5e505SShuhei Matsumoto {
770016e5e505SShuhei Matsumoto 	struct spdk_bdev_open_opts opts;
770116e5e505SShuhei Matsumoto 	struct spdk_bdev *bdev;
770216e5e505SShuhei Matsumoto 	struct spdk_bdev_desc *desc;
770316e5e505SShuhei Matsumoto 	int rc;
770416e5e505SShuhei Matsumoto 
770516e5e505SShuhei Matsumoto 	bdev = allocate_bdev("bdev0");
770616e5e505SShuhei Matsumoto 
770716e5e505SShuhei Matsumoto 	rc = spdk_bdev_open_ext_v2("bdev0", true, bdev_ut_event_cb, NULL, NULL, &desc);
770816e5e505SShuhei Matsumoto 	CU_ASSERT(rc == 0);
770916e5e505SShuhei Matsumoto 	SPDK_CU_ASSERT_FATAL(desc != NULL);
771016e5e505SShuhei Matsumoto 	CU_ASSERT(desc->write == true);
771116e5e505SShuhei Matsumoto 	CU_ASSERT(desc->opts.hide_metadata == false);
771216e5e505SShuhei Matsumoto 
771316e5e505SShuhei Matsumoto 	spdk_bdev_close(desc);
771416e5e505SShuhei Matsumoto 
771516e5e505SShuhei Matsumoto 	spdk_bdev_open_opts_init(&opts, sizeof(opts));
771616e5e505SShuhei Matsumoto 	opts.hide_metadata = true;
771716e5e505SShuhei Matsumoto 
771816e5e505SShuhei Matsumoto 	rc = spdk_bdev_open_ext_v2("bdev0", true, bdev_ut_event_cb, NULL, &opts, &desc);
771916e5e505SShuhei Matsumoto 	CU_ASSERT(rc == 0);
772016e5e505SShuhei Matsumoto 	CU_ASSERT(desc->write == true);
772116e5e505SShuhei Matsumoto 	CU_ASSERT(desc->opts.hide_metadata == true);
772216e5e505SShuhei Matsumoto 
772316e5e505SShuhei Matsumoto 	spdk_bdev_close(desc);
772416e5e505SShuhei Matsumoto 
772516e5e505SShuhei Matsumoto 	free_bdev(bdev);
772616e5e505SShuhei Matsumoto }
772716e5e505SShuhei Matsumoto 
77280836dccdSShuhei Matsumoto static void
77290836dccdSShuhei Matsumoto bdev_io_init_dif_ctx_test(void)
77300836dccdSShuhei Matsumoto {
77310836dccdSShuhei Matsumoto 	struct spdk_bdev *bdev;
77320836dccdSShuhei Matsumoto 	struct spdk_bdev_io bdev_io;
77330836dccdSShuhei Matsumoto 	int rc;
77340836dccdSShuhei Matsumoto 
77350836dccdSShuhei Matsumoto 	bdev = allocate_bdev("bdev0");
77360836dccdSShuhei Matsumoto 
77370836dccdSShuhei Matsumoto 	/* This is invalid because md_len should be larger than PI size. */
77380836dccdSShuhei Matsumoto 	bdev->dif_pi_format = SPDK_DIF_PI_FORMAT_32;
77390836dccdSShuhei Matsumoto 	bdev->blocklen = 4096 + 8;
77400836dccdSShuhei Matsumoto 	bdev->md_len = 8;
77410836dccdSShuhei Matsumoto 	bdev->md_interleave = true;
77420836dccdSShuhei Matsumoto 
77430836dccdSShuhei Matsumoto 	bdev_io.bdev = bdev;
77440836dccdSShuhei Matsumoto 
77450836dccdSShuhei Matsumoto 	/* Check if initialization detects error. */
77460836dccdSShuhei Matsumoto 	rc = bdev_io_init_dif_ctx(&bdev_io);
77470836dccdSShuhei Matsumoto 	CU_ASSERT(rc != 0);
77480836dccdSShuhei Matsumoto 
77490836dccdSShuhei Matsumoto 	/* Increase md_len to pass initialization check. */
77500836dccdSShuhei Matsumoto 	bdev->blocklen = 4096 + 16;
77510836dccdSShuhei Matsumoto 	bdev->md_len = 16;
77520836dccdSShuhei Matsumoto 
77530836dccdSShuhei Matsumoto 	rc = bdev_io_init_dif_ctx(&bdev_io);
77540836dccdSShuhei Matsumoto 	CU_ASSERT(rc == 0);
77550836dccdSShuhei Matsumoto 
77560836dccdSShuhei Matsumoto 	free_bdev(bdev);
77570836dccdSShuhei Matsumoto }
77580836dccdSShuhei Matsumoto 
77594ee51dcbSJim Harris int
77604ee51dcbSJim Harris main(int argc, char **argv)
77614ee51dcbSJim Harris {
77624ee51dcbSJim Harris 	CU_pSuite		suite = NULL;
77634ee51dcbSJim Harris 	unsigned int		num_failures;
77644ee51dcbSJim Harris 
776578b696bcSVitaliy Mysak 	CU_initialize_registry();
77664ee51dcbSJim Harris 
776780b22cf3SKonrad Sztyber 	suite = CU_add_suite("bdev", ut_bdev_setup, ut_bdev_teardown);
77684ee51dcbSJim Harris 
7769dcf0ca15SVitaliy Mysak 	CU_ADD_TEST(suite, bytes_to_blocks_test);
7770dcf0ca15SVitaliy Mysak 	CU_ADD_TEST(suite, num_blocks_test);
7771dcf0ca15SVitaliy Mysak 	CU_ADD_TEST(suite, io_valid_test);
7772dcf0ca15SVitaliy Mysak 	CU_ADD_TEST(suite, open_write_test);
77739f9c7161SMike Gerdts 	CU_ADD_TEST(suite, claim_test);
7774dcf0ca15SVitaliy Mysak 	CU_ADD_TEST(suite, alias_add_del_test);
7775dcf0ca15SVitaliy Mysak 	CU_ADD_TEST(suite, get_device_stat_test);
7776dcf0ca15SVitaliy Mysak 	CU_ADD_TEST(suite, bdev_io_types_test);
7777dcf0ca15SVitaliy Mysak 	CU_ADD_TEST(suite, bdev_io_wait_test);
77783b616c0fSJin Yu 	CU_ADD_TEST(suite, bdev_io_spans_split_test);
77799697d84fSJin Yu 	CU_ADD_TEST(suite, bdev_io_boundary_split_test);
77809697d84fSJin Yu 	CU_ADD_TEST(suite, bdev_io_max_size_and_segment_split_test);
77811fae3687SJin Yu 	CU_ADD_TEST(suite, bdev_io_mix_split_test);
7782dcf0ca15SVitaliy Mysak 	CU_ADD_TEST(suite, bdev_io_split_with_io_wait);
7783d6e9827eSArtur Paszkiewicz 	CU_ADD_TEST(suite, bdev_io_write_unit_split_test);
7784dcf0ca15SVitaliy Mysak 	CU_ADD_TEST(suite, bdev_io_alignment_with_boundary);
7785dcf0ca15SVitaliy Mysak 	CU_ADD_TEST(suite, bdev_io_alignment);
7786dcf0ca15SVitaliy Mysak 	CU_ADD_TEST(suite, bdev_histograms);
7787dcf0ca15SVitaliy Mysak 	CU_ADD_TEST(suite, bdev_write_zeroes);
7788dcf0ca15SVitaliy Mysak 	CU_ADD_TEST(suite, bdev_compare_and_write);
7789dcf0ca15SVitaliy Mysak 	CU_ADD_TEST(suite, bdev_compare);
77900bd6b7f2SJonas Pfefferle 	CU_ADD_TEST(suite, bdev_compare_emulated);
77916127461cSmatthewb 	CU_ADD_TEST(suite, bdev_zcopy_write);
77926127461cSmatthewb 	CU_ADD_TEST(suite, bdev_zcopy_read);
7793dcf0ca15SVitaliy Mysak 	CU_ADD_TEST(suite, bdev_open_while_hotremove);
7794dcf0ca15SVitaliy Mysak 	CU_ADD_TEST(suite, bdev_close_while_hotremove);
77956e17adcbSShuhei Matsumoto 	CU_ADD_TEST(suite, bdev_open_ext_test);
77967bcd316dSGangCao 	CU_ADD_TEST(suite, bdev_open_ext_unregister);
7797dcf0ca15SVitaliy Mysak 	CU_ADD_TEST(suite, bdev_set_io_timeout);
779848ce2c97SGangCao 	CU_ADD_TEST(suite, bdev_set_qd_sampling);
7799dcf0ca15SVitaliy Mysak 	CU_ADD_TEST(suite, lba_range_overlap);
7800dcf0ca15SVitaliy Mysak 	CU_ADD_TEST(suite, lock_lba_range_check_ranges);
7801dcf0ca15SVitaliy Mysak 	CU_ADD_TEST(suite, lock_lba_range_with_io_outstanding);
7802dcf0ca15SVitaliy Mysak 	CU_ADD_TEST(suite, lock_lba_range_overlapped);
78039e386832SArtur Paszkiewicz 	CU_ADD_TEST(suite, bdev_quiesce);
78047cd20dd3SShuhei Matsumoto 	CU_ADD_TEST(suite, bdev_io_abort);
7805d0b4deabSChangpeng Liu 	CU_ADD_TEST(suite, bdev_unmap);
7806e7fbdf15SChangpeng Liu 	CU_ADD_TEST(suite, bdev_write_zeroes_split_test);
7807f420b9efSZiye Yang 	CU_ADD_TEST(suite, bdev_set_options_test);
7808c3a58489SAlexey Marchuk 	CU_ADD_TEST(suite, bdev_get_memory_domains);
7809442e13c0SJonas Pfefferle 	CU_ADD_TEST(suite, bdev_io_ext);
7810442e13c0SJonas Pfefferle 	CU_ADD_TEST(suite, bdev_io_ext_no_opts);
7811442e13c0SJonas Pfefferle 	CU_ADD_TEST(suite, bdev_io_ext_invalid_opts);
7812442e13c0SJonas Pfefferle 	CU_ADD_TEST(suite, bdev_io_ext_split);
7813442e13c0SJonas Pfefferle 	CU_ADD_TEST(suite, bdev_io_ext_bounce_buffer);
781479415753SKonrad Sztyber 	CU_ADD_TEST(suite, bdev_register_uuid_alias);
781596c007d3SShuhei Matsumoto 	CU_ADD_TEST(suite, bdev_unregister_by_name);
7816428b17a0SShuhei Matsumoto 	CU_ADD_TEST(suite, for_each_bdev_test);
78176defafc9SDamiano 	CU_ADD_TEST(suite, bdev_seek_test);
78186c8702acSEvgeniy Kochetov 	CU_ADD_TEST(suite, bdev_copy);
78196c8702acSEvgeniy Kochetov 	CU_ADD_TEST(suite, bdev_copy_split_test);
7820ae215731SMike Gerdts 	CU_ADD_TEST(suite, examine_locks);
7821a7eb6187SMike Gerdts 	CU_ADD_TEST(suite, claim_v2_rwo);
7822a7eb6187SMike Gerdts 	CU_ADD_TEST(suite, claim_v2_rom);
7823a7eb6187SMike Gerdts 	CU_ADD_TEST(suite, claim_v2_rwm);
7824a7eb6187SMike Gerdts 	CU_ADD_TEST(suite, claim_v2_existing_writer);
7825a7eb6187SMike Gerdts 	CU_ADD_TEST(suite, claim_v2_existing_v1);
7826a7eb6187SMike Gerdts 	CU_ADD_TEST(suite, claim_v1_existing_v2);
782786bbcdb8SMike Gerdts 	CU_ADD_TEST(suite, examine_claimed);
782802935561SEd Reed 	CU_ADD_TEST(suite, examine_claimed_manual);
7829fee788f6SJim Harris 	CU_ADD_TEST(suite, get_numa_id);
783063e0c25dSVasilii Ivanov 	CU_ADD_TEST(suite, get_device_stat_with_reset);
783116e5e505SShuhei Matsumoto 	CU_ADD_TEST(suite, open_ext_v2_test);
78320836dccdSShuhei Matsumoto 	CU_ADD_TEST(suite, bdev_io_init_dif_ctx_test);
78334ee51dcbSJim Harris 
7834972b3ae3SShuhei Matsumoto 	allocate_cores(1);
7835270a25dfSBen Walker 	allocate_threads(1);
7836270a25dfSBen Walker 	set_thread(0);
7837270a25dfSBen Walker 
7838ea941caeSKonrad Sztyber 	num_failures = spdk_ut_run_tests(argc, argv, NULL);
78394ee51dcbSJim Harris 	CU_cleanup_registry();
7840270a25dfSBen Walker 
7841270a25dfSBen Walker 	free_threads();
7842972b3ae3SShuhei Matsumoto 	free_cores();
7843270a25dfSBen Walker 
78444ee51dcbSJim Harris 	return num_failures;
78454ee51dcbSJim Harris }
7846