xref: /spdk/test/unit/lib/bdev/bdev.c/bdev_ut.c (revision 75dfecbb16072de02ae86a70df34d50e3149ba4c)
14ee51dcbSJim Harris /*-
24ee51dcbSJim Harris  *   BSD LICENSE
34ee51dcbSJim Harris  *
4437e54f7SEvgeniy Kochetov  *   Copyright (c) Intel Corporation. All rights reserved.
5437e54f7SEvgeniy Kochetov  *   Copyright (c) 2019 Mellanox Technologies LTD. All rights reserved.
64ee51dcbSJim Harris  *
74ee51dcbSJim Harris  *   Redistribution and use in source and binary forms, with or without
84ee51dcbSJim Harris  *   modification, are permitted provided that the following conditions
94ee51dcbSJim Harris  *   are met:
104ee51dcbSJim Harris  *
114ee51dcbSJim Harris  *     * Redistributions of source code must retain the above copyright
124ee51dcbSJim Harris  *       notice, this list of conditions and the following disclaimer.
134ee51dcbSJim Harris  *     * Redistributions in binary form must reproduce the above copyright
144ee51dcbSJim Harris  *       notice, this list of conditions and the following disclaimer in
154ee51dcbSJim Harris  *       the documentation and/or other materials provided with the
164ee51dcbSJim Harris  *       distribution.
174ee51dcbSJim Harris  *     * Neither the name of Intel Corporation nor the names of its
184ee51dcbSJim Harris  *       contributors may be used to endorse or promote products derived
194ee51dcbSJim Harris  *       from this software without specific prior written permission.
204ee51dcbSJim Harris  *
214ee51dcbSJim Harris  *   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
224ee51dcbSJim Harris  *   "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
234ee51dcbSJim Harris  *   LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
244ee51dcbSJim Harris  *   A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
254ee51dcbSJim Harris  *   OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
264ee51dcbSJim Harris  *   SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
274ee51dcbSJim Harris  *   LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
284ee51dcbSJim Harris  *   DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
294ee51dcbSJim Harris  *   THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
304ee51dcbSJim Harris  *   (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
314ee51dcbSJim Harris  *   OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
324ee51dcbSJim Harris  */
334ee51dcbSJim Harris 
344ee51dcbSJim Harris #include "spdk_cunit.h"
354ee51dcbSJim Harris 
36270a25dfSBen Walker #include "common/lib/ut_multithread.c"
375ffa5c00SPawel Wodkowski #include "unit/lib/json_mock.c"
38229f6494SDaniel Verkamp 
39c4fee1e9SPawel Wodkowski #include "spdk/config.h"
40229f6494SDaniel Verkamp /* HACK: disable VTune integration so the unit test doesn't need VTune headers and libs to build */
41229f6494SDaniel Verkamp #undef SPDK_CONFIG_VTUNE
42229f6494SDaniel Verkamp 
43d8c3ff5fSJim Harris #include "bdev/bdev.c"
444ee51dcbSJim Harris 
45afaabcceSJim Harris struct spdk_trace_histories *g_trace_histories;
46afaabcceSJim Harris DEFINE_STUB_V(spdk_trace_add_register_fn, (struct spdk_trace_register_fn *reg_fn));
47afaabcceSJim Harris DEFINE_STUB_V(spdk_trace_register_owner, (uint8_t type, char id_prefix));
48afaabcceSJim Harris DEFINE_STUB_V(spdk_trace_register_object, (uint8_t type, char id_prefix));
49617184beSJim Harris DEFINE_STUB_V(spdk_trace_register_description, (const char *name,
50afaabcceSJim Harris 		uint16_t tpoint_id, uint8_t owner_type,
51afaabcceSJim Harris 		uint8_t object_type, uint8_t new_object,
52dd1c38ccSJim Harris 		uint8_t arg1_type, const char *arg1_name));
53afaabcceSJim Harris DEFINE_STUB_V(_spdk_trace_record, (uint64_t tsc, uint16_t tpoint_id, uint16_t poller_id,
54afaabcceSJim Harris 				   uint32_t size, uint64_t object_id, uint64_t arg1));
551d83a09dSPiotr Pelplinski DEFINE_STUB(spdk_notify_send, uint64_t, (const char *type, const char *ctx), 0);
561d83a09dSPiotr Pelplinski DEFINE_STUB(spdk_notify_type_register, struct spdk_notify_type *, (const char *type), NULL);
571d83a09dSPiotr Pelplinski 
58afaabcceSJim Harris 
5942dba604SPiotr Pelplinski int g_status;
6042dba604SPiotr Pelplinski int g_count;
6179ed1ba1SMaciej Szwed enum spdk_bdev_event_type g_event_type1;
6279ed1ba1SMaciej Szwed enum spdk_bdev_event_type g_event_type2;
6342dba604SPiotr Pelplinski struct spdk_histogram_data *g_histogram;
6423975858SEvgeniy Kochetov void *g_unregister_arg;
6523975858SEvgeniy Kochetov int g_unregister_rc;
6642dba604SPiotr Pelplinski 
674ee51dcbSJim Harris void
684ee51dcbSJim Harris spdk_scsi_nvme_translate(const struct spdk_bdev_io *bdev_io,
694ee51dcbSJim Harris 			 int *sc, int *sk, int *asc, int *ascq)
704ee51dcbSJim Harris {
714ee51dcbSJim Harris }
724ee51dcbSJim Harris 
734ee51dcbSJim Harris static int
744ee51dcbSJim Harris null_init(void)
754ee51dcbSJim Harris {
764ee51dcbSJim Harris 	return 0;
774ee51dcbSJim Harris }
784ee51dcbSJim Harris 
794ee51dcbSJim Harris static int
804ee51dcbSJim Harris null_clean(void)
814ee51dcbSJim Harris {
824ee51dcbSJim Harris 	return 0;
834ee51dcbSJim Harris }
844ee51dcbSJim Harris 
8557d174ffSJim Harris static int
8657d174ffSJim Harris stub_destruct(void *ctx)
874ee51dcbSJim Harris {
8857d174ffSJim Harris 	return 0;
8957d174ffSJim Harris }
9057d174ffSJim Harris 
913c7894ffSShuhei Matsumoto struct ut_expected_io {
923c7894ffSShuhei Matsumoto 	uint8_t				type;
933c7894ffSShuhei Matsumoto 	uint64_t			offset;
943c7894ffSShuhei Matsumoto 	uint64_t			length;
953c7894ffSShuhei Matsumoto 	int				iovcnt;
963c7894ffSShuhei Matsumoto 	struct iovec			iov[BDEV_IO_NUM_CHILD_IOV];
97e2918289SKonrad Sztyber 	void				*md_buf;
983c7894ffSShuhei Matsumoto 	TAILQ_ENTRY(ut_expected_io)	link;
993c7894ffSShuhei Matsumoto };
1003c7894ffSShuhei Matsumoto 
10132d7c91cSJim Harris struct bdev_ut_channel {
10232d7c91cSJim Harris 	TAILQ_HEAD(, spdk_bdev_io)	outstanding_io;
10332d7c91cSJim Harris 	uint32_t			outstanding_io_count;
1043c7894ffSShuhei Matsumoto 	TAILQ_HEAD(, ut_expected_io)	expected_io;
10532d7c91cSJim Harris };
10632d7c91cSJim Harris 
1074bd97621SJim Harris static bool g_io_done;
108dadd2a6dSPiotr Pelplinski static struct spdk_bdev_io *g_bdev_io;
1090df515a8SShuhei Matsumoto static enum spdk_bdev_io_status g_io_status;
110c55c85f8SChangpeng Liu static enum spdk_bdev_io_status g_io_exp_status = SPDK_BDEV_IO_STATUS_SUCCESS;
11132d7c91cSJim Harris static uint32_t g_bdev_ut_io_device;
11232d7c91cSJim Harris static struct bdev_ut_channel *g_bdev_ut_channel;
113ae43c81aSJim Harris static void *g_compare_read_buf;
114ae43c81aSJim Harris static uint32_t g_compare_read_buf_len;
115ae43c81aSJim Harris static void *g_compare_write_buf;
116ae43c81aSJim Harris static uint32_t g_compare_write_buf_len;
1177cd20dd3SShuhei Matsumoto static bool g_abort_done;
1187cd20dd3SShuhei Matsumoto static enum spdk_bdev_io_status g_abort_status;
11932d7c91cSJim Harris 
1203c7894ffSShuhei Matsumoto static struct ut_expected_io *
1213c7894ffSShuhei Matsumoto ut_alloc_expected_io(uint8_t type, uint64_t offset, uint64_t length, int iovcnt)
1223c7894ffSShuhei Matsumoto {
1233c7894ffSShuhei Matsumoto 	struct ut_expected_io *expected_io;
1243c7894ffSShuhei Matsumoto 
1253c7894ffSShuhei Matsumoto 	expected_io = calloc(1, sizeof(*expected_io));
1263c7894ffSShuhei Matsumoto 	SPDK_CU_ASSERT_FATAL(expected_io != NULL);
1273c7894ffSShuhei Matsumoto 
1283c7894ffSShuhei Matsumoto 	expected_io->type = type;
1293c7894ffSShuhei Matsumoto 	expected_io->offset = offset;
1303c7894ffSShuhei Matsumoto 	expected_io->length = length;
1313c7894ffSShuhei Matsumoto 	expected_io->iovcnt = iovcnt;
1323c7894ffSShuhei Matsumoto 
1333c7894ffSShuhei Matsumoto 	return expected_io;
1343c7894ffSShuhei Matsumoto }
1353c7894ffSShuhei Matsumoto 
1363c7894ffSShuhei Matsumoto static void
1373c7894ffSShuhei Matsumoto ut_expected_io_set_iov(struct ut_expected_io *expected_io, int pos, void *base, size_t len)
1383c7894ffSShuhei Matsumoto {
1393c7894ffSShuhei Matsumoto 	expected_io->iov[pos].iov_base = base;
1403c7894ffSShuhei Matsumoto 	expected_io->iov[pos].iov_len = len;
1413c7894ffSShuhei Matsumoto }
1423c7894ffSShuhei Matsumoto 
14332d7c91cSJim Harris static void
14432d7c91cSJim Harris stub_submit_request(struct spdk_io_channel *_ch, struct spdk_bdev_io *bdev_io)
14532d7c91cSJim Harris {
14632d7c91cSJim Harris 	struct bdev_ut_channel *ch = spdk_io_channel_get_ctx(_ch);
1473c7894ffSShuhei Matsumoto 	struct ut_expected_io *expected_io;
1484bd97621SJim Harris 	struct iovec *iov, *expected_iov;
1497cd20dd3SShuhei Matsumoto 	struct spdk_bdev_io *bio_to_abort;
1504bd97621SJim Harris 	int i;
15132d7c91cSJim Harris 
152dadd2a6dSPiotr Pelplinski 	g_bdev_io = bdev_io;
153dadd2a6dSPiotr Pelplinski 
154ae43c81aSJim Harris 	if (g_compare_read_buf && bdev_io->type == SPDK_BDEV_IO_TYPE_READ) {
155ae43c81aSJim Harris 		uint32_t len = bdev_io->u.bdev.iovs[0].iov_len;
156ae43c81aSJim Harris 
157ae43c81aSJim Harris 		CU_ASSERT(bdev_io->u.bdev.iovcnt == 1);
158ae43c81aSJim Harris 		CU_ASSERT(g_compare_read_buf_len == len);
159ae43c81aSJim Harris 		memcpy(bdev_io->u.bdev.iovs[0].iov_base, g_compare_read_buf, len);
160ae43c81aSJim Harris 	}
161ae43c81aSJim Harris 
162ae43c81aSJim Harris 	if (g_compare_write_buf && bdev_io->type == SPDK_BDEV_IO_TYPE_WRITE) {
163ae43c81aSJim Harris 		uint32_t len = bdev_io->u.bdev.iovs[0].iov_len;
164ae43c81aSJim Harris 
165ae43c81aSJim Harris 		CU_ASSERT(bdev_io->u.bdev.iovcnt == 1);
166ae43c81aSJim Harris 		CU_ASSERT(g_compare_write_buf_len == len);
167ae43c81aSJim Harris 		memcpy(g_compare_write_buf, bdev_io->u.bdev.iovs[0].iov_base, len);
168ae43c81aSJim Harris 	}
169ae43c81aSJim Harris 
170ca0eeaabSMaciej Szwed 	if (g_compare_read_buf && bdev_io->type == SPDK_BDEV_IO_TYPE_COMPARE) {
171ca0eeaabSMaciej Szwed 		uint32_t len = bdev_io->u.bdev.iovs[0].iov_len;
172ca0eeaabSMaciej Szwed 
173ca0eeaabSMaciej Szwed 		CU_ASSERT(bdev_io->u.bdev.iovcnt == 1);
174ca0eeaabSMaciej Szwed 		CU_ASSERT(g_compare_read_buf_len == len);
175ca0eeaabSMaciej Szwed 		if (memcmp(bdev_io->u.bdev.iovs[0].iov_base, g_compare_read_buf, len)) {
176ca0eeaabSMaciej Szwed 			g_io_exp_status = SPDK_BDEV_IO_STATUS_MISCOMPARE;
177ca0eeaabSMaciej Szwed 		}
178ca0eeaabSMaciej Szwed 	}
179ca0eeaabSMaciej Szwed 
1807cd20dd3SShuhei Matsumoto 	if (bdev_io->type == SPDK_BDEV_IO_TYPE_ABORT) {
1817cd20dd3SShuhei Matsumoto 		if (g_io_exp_status == SPDK_BDEV_IO_STATUS_SUCCESS) {
1827cd20dd3SShuhei Matsumoto 			TAILQ_FOREACH(bio_to_abort, &ch->outstanding_io, module_link) {
1837cd20dd3SShuhei Matsumoto 				if (bio_to_abort == bdev_io->u.abort.bio_to_abort) {
1847cd20dd3SShuhei Matsumoto 					TAILQ_REMOVE(&ch->outstanding_io, bio_to_abort, module_link);
1857cd20dd3SShuhei Matsumoto 					ch->outstanding_io_count--;
1867cd20dd3SShuhei Matsumoto 					spdk_bdev_io_complete(bio_to_abort, SPDK_BDEV_IO_STATUS_FAILED);
1877cd20dd3SShuhei Matsumoto 					break;
1887cd20dd3SShuhei Matsumoto 				}
1897cd20dd3SShuhei Matsumoto 			}
1907cd20dd3SShuhei Matsumoto 		}
1917cd20dd3SShuhei Matsumoto 	}
1927cd20dd3SShuhei Matsumoto 
19332d7c91cSJim Harris 	TAILQ_INSERT_TAIL(&ch->outstanding_io, bdev_io, module_link);
19432d7c91cSJim Harris 	ch->outstanding_io_count++;
1954bd97621SJim Harris 
1963c7894ffSShuhei Matsumoto 	expected_io = TAILQ_FIRST(&ch->expected_io);
1973c7894ffSShuhei Matsumoto 	if (expected_io == NULL) {
1983c7894ffSShuhei Matsumoto 		return;
1993c7894ffSShuhei Matsumoto 	}
2003c7894ffSShuhei Matsumoto 	TAILQ_REMOVE(&ch->expected_io, expected_io, link);
2013c7894ffSShuhei Matsumoto 
2023c7894ffSShuhei Matsumoto 	if (expected_io->type != SPDK_BDEV_IO_TYPE_INVALID) {
2033c7894ffSShuhei Matsumoto 		CU_ASSERT(bdev_io->type == expected_io->type);
2044bd97621SJim Harris 	}
2054bd97621SJim Harris 
206e2918289SKonrad Sztyber 	if (expected_io->md_buf != NULL) {
207e2918289SKonrad Sztyber 		CU_ASSERT(expected_io->md_buf == bdev_io->u.bdev.md_buf);
208e2918289SKonrad Sztyber 	}
209e2918289SKonrad Sztyber 
2103c7894ffSShuhei Matsumoto 	if (expected_io->length == 0) {
2113c7894ffSShuhei Matsumoto 		free(expected_io);
2124bd97621SJim Harris 		return;
2134bd97621SJim Harris 	}
2144bd97621SJim Harris 
2153c7894ffSShuhei Matsumoto 	CU_ASSERT(expected_io->offset == bdev_io->u.bdev.offset_blocks);
2163c7894ffSShuhei Matsumoto 	CU_ASSERT(expected_io->length = bdev_io->u.bdev.num_blocks);
2174bd97621SJim Harris 
2183c7894ffSShuhei Matsumoto 	if (expected_io->iovcnt == 0) {
2193c7894ffSShuhei Matsumoto 		free(expected_io);
2204bd97621SJim Harris 		/* UNMAP, WRITE_ZEROES and FLUSH don't have iovs, so we can just return now. */
2214bd97621SJim Harris 		return;
2224bd97621SJim Harris 	}
2234bd97621SJim Harris 
2243c7894ffSShuhei Matsumoto 	CU_ASSERT(expected_io->iovcnt == bdev_io->u.bdev.iovcnt);
2253c7894ffSShuhei Matsumoto 	for (i = 0; i < expected_io->iovcnt; i++) {
2264bd97621SJim Harris 		iov = &bdev_io->u.bdev.iovs[i];
2273c7894ffSShuhei Matsumoto 		expected_iov = &expected_io->iov[i];
2284bd97621SJim Harris 		CU_ASSERT(iov->iov_len == expected_iov->iov_len);
2294bd97621SJim Harris 		CU_ASSERT(iov->iov_base == expected_iov->iov_base);
2304bd97621SJim Harris 	}
2313c7894ffSShuhei Matsumoto 
2323c7894ffSShuhei Matsumoto 	free(expected_io);
23332d7c91cSJim Harris }
23432d7c91cSJim Harris 
235dadd2a6dSPiotr Pelplinski static void
23680da9548SMaciej Szwed stub_submit_request_get_buf_cb(struct spdk_io_channel *_ch,
2374b92ffb3SShuhei Matsumoto 			       struct spdk_bdev_io *bdev_io, bool success)
2384b92ffb3SShuhei Matsumoto {
2394b92ffb3SShuhei Matsumoto 	CU_ASSERT(success == true);
2404b92ffb3SShuhei Matsumoto 
2414b92ffb3SShuhei Matsumoto 	stub_submit_request(_ch, bdev_io);
2424b92ffb3SShuhei Matsumoto }
2434b92ffb3SShuhei Matsumoto 
2444b92ffb3SShuhei Matsumoto static void
24580da9548SMaciej Szwed stub_submit_request_get_buf(struct spdk_io_channel *_ch, struct spdk_bdev_io *bdev_io)
246dadd2a6dSPiotr Pelplinski {
24780da9548SMaciej Szwed 	spdk_bdev_io_get_buf(bdev_io, stub_submit_request_get_buf_cb,
248dadd2a6dSPiotr Pelplinski 			     bdev_io->u.bdev.num_blocks * bdev_io->bdev->blocklen);
249dadd2a6dSPiotr Pelplinski }
250dadd2a6dSPiotr Pelplinski 
25132d7c91cSJim Harris static uint32_t
25232d7c91cSJim Harris stub_complete_io(uint32_t num_to_complete)
25332d7c91cSJim Harris {
25432d7c91cSJim Harris 	struct bdev_ut_channel *ch = g_bdev_ut_channel;
25532d7c91cSJim Harris 	struct spdk_bdev_io *bdev_io;
256c55c85f8SChangpeng Liu 	static enum spdk_bdev_io_status io_status;
25732d7c91cSJim Harris 	uint32_t num_completed = 0;
25832d7c91cSJim Harris 
25932d7c91cSJim Harris 	while (num_completed < num_to_complete) {
26032d7c91cSJim Harris 		if (TAILQ_EMPTY(&ch->outstanding_io)) {
26132d7c91cSJim Harris 			break;
26232d7c91cSJim Harris 		}
26332d7c91cSJim Harris 		bdev_io = TAILQ_FIRST(&ch->outstanding_io);
26432d7c91cSJim Harris 		TAILQ_REMOVE(&ch->outstanding_io, bdev_io, module_link);
26532d7c91cSJim Harris 		ch->outstanding_io_count--;
266c55c85f8SChangpeng Liu 		io_status = g_io_exp_status == SPDK_BDEV_IO_STATUS_SUCCESS ? SPDK_BDEV_IO_STATUS_SUCCESS :
267c55c85f8SChangpeng Liu 			    g_io_exp_status;
268c55c85f8SChangpeng Liu 		spdk_bdev_io_complete(bdev_io, io_status);
26932d7c91cSJim Harris 		num_completed++;
27032d7c91cSJim Harris 	}
27132d7c91cSJim Harris 
27232d7c91cSJim Harris 	return num_completed;
27332d7c91cSJim Harris }
27432d7c91cSJim Harris 
27532d7c91cSJim Harris static struct spdk_io_channel *
27632d7c91cSJim Harris bdev_ut_get_io_channel(void *ctx)
27732d7c91cSJim Harris {
27832d7c91cSJim Harris 	return spdk_get_io_channel(&g_bdev_ut_io_device);
27932d7c91cSJim Harris }
28032d7c91cSJim Harris 
281e2918289SKonrad Sztyber static bool g_io_types_supported[SPDK_BDEV_NUM_IO_TYPES] = {
282e2918289SKonrad Sztyber 	[SPDK_BDEV_IO_TYPE_READ]		= true,
283e2918289SKonrad Sztyber 	[SPDK_BDEV_IO_TYPE_WRITE]		= true,
284bee042e4SMaciej Szwed 	[SPDK_BDEV_IO_TYPE_COMPARE]		= true,
285e2918289SKonrad Sztyber 	[SPDK_BDEV_IO_TYPE_UNMAP]		= true,
286e2918289SKonrad Sztyber 	[SPDK_BDEV_IO_TYPE_FLUSH]		= true,
287e2918289SKonrad Sztyber 	[SPDK_BDEV_IO_TYPE_RESET]		= true,
288e2918289SKonrad Sztyber 	[SPDK_BDEV_IO_TYPE_NVME_ADMIN]		= true,
289e2918289SKonrad Sztyber 	[SPDK_BDEV_IO_TYPE_NVME_IO]		= true,
290e2918289SKonrad Sztyber 	[SPDK_BDEV_IO_TYPE_NVME_IO_MD]		= true,
291e2918289SKonrad Sztyber 	[SPDK_BDEV_IO_TYPE_WRITE_ZEROES]	= true,
292e2918289SKonrad Sztyber 	[SPDK_BDEV_IO_TYPE_ZCOPY]		= true,
2937cd20dd3SShuhei Matsumoto 	[SPDK_BDEV_IO_TYPE_ABORT]		= true,
294e2918289SKonrad Sztyber };
295e2918289SKonrad Sztyber 
296e2918289SKonrad Sztyber static void
297e2918289SKonrad Sztyber ut_enable_io_type(enum spdk_bdev_io_type io_type, bool enable)
298e2918289SKonrad Sztyber {
299e2918289SKonrad Sztyber 	g_io_types_supported[io_type] = enable;
300e2918289SKonrad Sztyber }
301e2918289SKonrad Sztyber 
302e2918289SKonrad Sztyber static bool
303e2918289SKonrad Sztyber stub_io_type_supported(void *_bdev, enum spdk_bdev_io_type io_type)
304e2918289SKonrad Sztyber {
305e2918289SKonrad Sztyber 	return g_io_types_supported[io_type];
306e2918289SKonrad Sztyber }
3074bd97621SJim Harris 
30857d174ffSJim Harris static struct spdk_bdev_fn_table fn_table = {
30957d174ffSJim Harris 	.destruct = stub_destruct,
31032d7c91cSJim Harris 	.submit_request = stub_submit_request,
31132d7c91cSJim Harris 	.get_io_channel = bdev_ut_get_io_channel,
3124bd97621SJim Harris 	.io_type_supported = stub_io_type_supported,
31357d174ffSJim Harris };
31457d174ffSJim Harris 
31532d7c91cSJim Harris static int
31632d7c91cSJim Harris bdev_ut_create_ch(void *io_device, void *ctx_buf)
31732d7c91cSJim Harris {
31832d7c91cSJim Harris 	struct bdev_ut_channel *ch = ctx_buf;
31932d7c91cSJim Harris 
32032d7c91cSJim Harris 	CU_ASSERT(g_bdev_ut_channel == NULL);
32132d7c91cSJim Harris 	g_bdev_ut_channel = ch;
32232d7c91cSJim Harris 
32332d7c91cSJim Harris 	TAILQ_INIT(&ch->outstanding_io);
32432d7c91cSJim Harris 	ch->outstanding_io_count = 0;
3253c7894ffSShuhei Matsumoto 	TAILQ_INIT(&ch->expected_io);
32632d7c91cSJim Harris 	return 0;
32732d7c91cSJim Harris }
32832d7c91cSJim Harris 
32932d7c91cSJim Harris static void
33032d7c91cSJim Harris bdev_ut_destroy_ch(void *io_device, void *ctx_buf)
33132d7c91cSJim Harris {
33232d7c91cSJim Harris 	CU_ASSERT(g_bdev_ut_channel != NULL);
33332d7c91cSJim Harris 	g_bdev_ut_channel = NULL;
33432d7c91cSJim Harris }
33532d7c91cSJim Harris 
336d83a3489STomasz Zawadzki struct spdk_bdev_module bdev_ut_if;
337d83a3489STomasz Zawadzki 
33832d7c91cSJim Harris static int
33932d7c91cSJim Harris bdev_ut_module_init(void)
34032d7c91cSJim Harris {
34132d7c91cSJim Harris 	spdk_io_device_register(&g_bdev_ut_io_device, bdev_ut_create_ch, bdev_ut_destroy_ch,
342c9402000SBen Walker 				sizeof(struct bdev_ut_channel), NULL);
343d83a3489STomasz Zawadzki 	spdk_bdev_module_init_done(&bdev_ut_if);
34432d7c91cSJim Harris 	return 0;
34532d7c91cSJim Harris }
34632d7c91cSJim Harris 
34732d7c91cSJim Harris static void
34832d7c91cSJim Harris bdev_ut_module_fini(void)
34932d7c91cSJim Harris {
3508ef7818aSJim Harris 	spdk_io_device_unregister(&g_bdev_ut_io_device, NULL);
35132d7c91cSJim Harris }
35232d7c91cSJim Harris 
35319100ed5SDaniel Verkamp struct spdk_bdev_module bdev_ut_if = {
3544d367354SPawel Wodkowski 	.name = "bdev_ut",
35532d7c91cSJim Harris 	.module_init = bdev_ut_module_init,
35632d7c91cSJim Harris 	.module_fini = bdev_ut_module_fini,
357d83a3489STomasz Zawadzki 	.async_init = true,
3584d367354SPawel Wodkowski };
3594d367354SPawel Wodkowski 
3604d367354SPawel Wodkowski static void vbdev_ut_examine(struct spdk_bdev *bdev);
3614d367354SPawel Wodkowski 
36232d7c91cSJim Harris static int
36332d7c91cSJim Harris vbdev_ut_module_init(void)
36432d7c91cSJim Harris {
36532d7c91cSJim Harris 	return 0;
36632d7c91cSJim Harris }
36732d7c91cSJim Harris 
36832d7c91cSJim Harris static void
36932d7c91cSJim Harris vbdev_ut_module_fini(void)
37032d7c91cSJim Harris {
37132d7c91cSJim Harris }
37232d7c91cSJim Harris 
37319100ed5SDaniel Verkamp struct spdk_bdev_module vbdev_ut_if = {
3744d367354SPawel Wodkowski 	.name = "vbdev_ut",
37532d7c91cSJim Harris 	.module_init = vbdev_ut_module_init,
37632d7c91cSJim Harris 	.module_fini = vbdev_ut_module_fini,
3779d258c75SPiotr Pelplinski 	.examine_config = vbdev_ut_examine,
3784d367354SPawel Wodkowski };
3794d367354SPawel Wodkowski 
380df6b55fdSgila SPDK_BDEV_MODULE_REGISTER(bdev_ut, &bdev_ut_if)
381df6b55fdSgila SPDK_BDEV_MODULE_REGISTER(vbdev_ut, &vbdev_ut_if)
3824d367354SPawel Wodkowski 
383e075a3dcSJim Harris static void
384e075a3dcSJim Harris vbdev_ut_examine(struct spdk_bdev *bdev)
385e075a3dcSJim Harris {
3864d367354SPawel Wodkowski 	spdk_bdev_module_examine_done(&vbdev_ut_if);
387e075a3dcSJim Harris }
388e075a3dcSJim Harris 
38957d174ffSJim Harris static struct spdk_bdev *
39057d174ffSJim Harris allocate_bdev(char *name)
39157d174ffSJim Harris {
39257d174ffSJim Harris 	struct spdk_bdev *bdev;
393b9afa3c7SSebastian Basierski 	int rc;
39457d174ffSJim Harris 
39557d174ffSJim Harris 	bdev = calloc(1, sizeof(*bdev));
39657d174ffSJim Harris 	SPDK_CU_ASSERT_FATAL(bdev != NULL);
39757d174ffSJim Harris 
39857d174ffSJim Harris 	bdev->name = name;
39957d174ffSJim Harris 	bdev->fn_table = &fn_table;
4004d367354SPawel Wodkowski 	bdev->module = &bdev_ut_if;
4015616c1edSShuhei Matsumoto 	bdev->blockcnt = 1024;
4024bd97621SJim Harris 	bdev->blocklen = 512;
40357d174ffSJim Harris 
404b9afa3c7SSebastian Basierski 	rc = spdk_bdev_register(bdev);
405b9afa3c7SSebastian Basierski 	CU_ASSERT(rc == 0);
40657d174ffSJim Harris 
40757d174ffSJim Harris 	return bdev;
40857d174ffSJim Harris }
40957d174ffSJim Harris 
41057d174ffSJim Harris static struct spdk_bdev *
411bfd1e46eSJim Harris allocate_vbdev(char *name)
41257d174ffSJim Harris {
41357d174ffSJim Harris 	struct spdk_bdev *bdev;
414b9afa3c7SSebastian Basierski 	int rc;
41557d174ffSJim Harris 
41657d174ffSJim Harris 	bdev = calloc(1, sizeof(*bdev));
41757d174ffSJim Harris 	SPDK_CU_ASSERT_FATAL(bdev != NULL);
41857d174ffSJim Harris 
41957d174ffSJim Harris 	bdev->name = name;
42057d174ffSJim Harris 	bdev->fn_table = &fn_table;
4214d367354SPawel Wodkowski 	bdev->module = &vbdev_ut_if;
42257d174ffSJim Harris 
423bfd1e46eSJim Harris 	rc = spdk_bdev_register(bdev);
424b9afa3c7SSebastian Basierski 	CU_ASSERT(rc == 0);
42557d174ffSJim Harris 
42657d174ffSJim Harris 	return bdev;
42757d174ffSJim Harris }
42857d174ffSJim Harris 
42957d174ffSJim Harris static void
43057d174ffSJim Harris free_bdev(struct spdk_bdev *bdev)
43157d174ffSJim Harris {
4322baeea7dSMaciej Szwed 	spdk_bdev_unregister(bdev, NULL, NULL);
433270a25dfSBen Walker 	poll_threads();
4344473942fSPawel Wodkowski 	memset(bdev, 0xFF, sizeof(*bdev));
43557d174ffSJim Harris 	free(bdev);
43657d174ffSJim Harris }
43757d174ffSJim Harris 
43857d174ffSJim Harris static void
43957d174ffSJim Harris free_vbdev(struct spdk_bdev *bdev)
44057d174ffSJim Harris {
441b6aaba08STomasz Zawadzki 	spdk_bdev_unregister(bdev, NULL, NULL);
442270a25dfSBen Walker 	poll_threads();
4434473942fSPawel Wodkowski 	memset(bdev, 0xFF, sizeof(*bdev));
44457d174ffSJim Harris 	free(bdev);
44557d174ffSJim Harris }
44657d174ffSJim Harris 
44757d174ffSJim Harris static void
44864ccd4b9SYanbo Zhou get_device_stat_cb(struct spdk_bdev *bdev, struct spdk_bdev_io_stat *stat, void *cb_arg, int rc)
44964ccd4b9SYanbo Zhou {
45064ccd4b9SYanbo Zhou 	const char *bdev_name;
45164ccd4b9SYanbo Zhou 
45264ccd4b9SYanbo Zhou 	CU_ASSERT(bdev != NULL);
45364ccd4b9SYanbo Zhou 	CU_ASSERT(rc == 0);
45464ccd4b9SYanbo Zhou 	bdev_name = spdk_bdev_get_name(bdev);
45564ccd4b9SYanbo Zhou 	CU_ASSERT_STRING_EQUAL(bdev_name, "bdev0");
45664ccd4b9SYanbo Zhou 
45764ccd4b9SYanbo Zhou 	free(stat);
45864ccd4b9SYanbo Zhou 	free_bdev(bdev);
459270a25dfSBen Walker 
460270a25dfSBen Walker 	*(bool *)cb_arg = true;
46164ccd4b9SYanbo Zhou }
46264ccd4b9SYanbo Zhou 
46364ccd4b9SYanbo Zhou static void
46423975858SEvgeniy Kochetov bdev_unregister_cb(void *cb_arg, int rc)
46523975858SEvgeniy Kochetov {
46623975858SEvgeniy Kochetov 	g_unregister_arg = cb_arg;
46723975858SEvgeniy Kochetov 	g_unregister_rc = rc;
46823975858SEvgeniy Kochetov }
46923975858SEvgeniy Kochetov 
47023975858SEvgeniy Kochetov static void
471*75dfecbbSShuhei Matsumoto bdev_ut_event_cb(enum spdk_bdev_event_type type, struct spdk_bdev *bdev, void *event_ctx)
472*75dfecbbSShuhei Matsumoto {
473*75dfecbbSShuhei Matsumoto }
474*75dfecbbSShuhei Matsumoto 
475*75dfecbbSShuhei Matsumoto static void
476437e54f7SEvgeniy Kochetov bdev_open_cb1(enum spdk_bdev_event_type type, struct spdk_bdev *bdev, void *event_ctx)
477437e54f7SEvgeniy Kochetov {
478437e54f7SEvgeniy Kochetov 	struct spdk_bdev_desc *desc = *(struct spdk_bdev_desc **)event_ctx;
479437e54f7SEvgeniy Kochetov 
480437e54f7SEvgeniy Kochetov 	g_event_type1 = type;
4819522ed36SEvgeniy Kochetov 	if (SPDK_BDEV_EVENT_REMOVE == type) {
482437e54f7SEvgeniy Kochetov 		spdk_bdev_close(desc);
483437e54f7SEvgeniy Kochetov 	}
4849522ed36SEvgeniy Kochetov }
485437e54f7SEvgeniy Kochetov 
486437e54f7SEvgeniy Kochetov static void
487437e54f7SEvgeniy Kochetov bdev_open_cb2(enum spdk_bdev_event_type type, struct spdk_bdev *bdev, void *event_ctx)
488437e54f7SEvgeniy Kochetov {
489437e54f7SEvgeniy Kochetov 	struct spdk_bdev_desc *desc = *(struct spdk_bdev_desc **)event_ctx;
490437e54f7SEvgeniy Kochetov 
491437e54f7SEvgeniy Kochetov 	g_event_type2 = type;
4929522ed36SEvgeniy Kochetov 	if (SPDK_BDEV_EVENT_REMOVE == type) {
493437e54f7SEvgeniy Kochetov 		spdk_bdev_close(desc);
494437e54f7SEvgeniy Kochetov 	}
4959522ed36SEvgeniy Kochetov }
496437e54f7SEvgeniy Kochetov 
497437e54f7SEvgeniy Kochetov static void
49864ccd4b9SYanbo Zhou get_device_stat_test(void)
49964ccd4b9SYanbo Zhou {
50064ccd4b9SYanbo Zhou 	struct spdk_bdev *bdev;
50164ccd4b9SYanbo Zhou 	struct spdk_bdev_io_stat *stat;
502270a25dfSBen Walker 	bool done;
50364ccd4b9SYanbo Zhou 
50464ccd4b9SYanbo Zhou 	bdev = allocate_bdev("bdev0");
50564ccd4b9SYanbo Zhou 	stat = calloc(1, sizeof(struct spdk_bdev_io_stat));
50664ccd4b9SYanbo Zhou 	if (stat == NULL) {
50764ccd4b9SYanbo Zhou 		free_bdev(bdev);
50864ccd4b9SYanbo Zhou 		return;
50964ccd4b9SYanbo Zhou 	}
510270a25dfSBen Walker 
511270a25dfSBen Walker 	done = false;
512270a25dfSBen Walker 	spdk_bdev_get_device_stat(bdev, stat, get_device_stat_cb, &done);
513270a25dfSBen Walker 	while (!done) { poll_threads(); }
514270a25dfSBen Walker 
515270a25dfSBen Walker 
51664ccd4b9SYanbo Zhou }
51764ccd4b9SYanbo Zhou 
51864ccd4b9SYanbo Zhou static void
51957d174ffSJim Harris open_write_test(void)
52057d174ffSJim Harris {
5214473942fSPawel Wodkowski 	struct spdk_bdev *bdev[9];
5224473942fSPawel Wodkowski 	struct spdk_bdev_desc *desc[9] = {};
52357d174ffSJim Harris 	int rc;
52457d174ffSJim Harris 
52557d174ffSJim Harris 	/*
52657d174ffSJim Harris 	 * Create a tree of bdevs to test various open w/ write cases.
52757d174ffSJim Harris 	 *
5284473942fSPawel Wodkowski 	 * bdev0 through bdev3 are physical block devices, such as NVMe
52957d174ffSJim Harris 	 * namespaces or Ceph block devices.
53057d174ffSJim Harris 	 *
5314473942fSPawel Wodkowski 	 * bdev4 is a virtual bdev with multiple base bdevs.  This models
53257d174ffSJim Harris 	 * caching or RAID use cases.
53357d174ffSJim Harris 	 *
5344473942fSPawel Wodkowski 	 * bdev5 through bdev7 are all virtual bdevs with the same base
5354473942fSPawel Wodkowski 	 * bdev (except bdev7). This models partitioning or logical volume
5364473942fSPawel Wodkowski 	 * use cases.
53757d174ffSJim Harris 	 *
5384473942fSPawel Wodkowski 	 * bdev7 is a virtual bdev with multiple base bdevs. One of base bdevs
5394473942fSPawel Wodkowski 	 * (bdev2) is shared with other virtual bdevs: bdev5 and bdev6. This
5404473942fSPawel Wodkowski 	 * models caching, RAID, partitioning or logical volumes use cases.
5414473942fSPawel Wodkowski 	 *
5424473942fSPawel Wodkowski 	 * bdev8 is a virtual bdev with multiple base bdevs, but these
54357d174ffSJim Harris 	 * base bdevs are themselves virtual bdevs.
54457d174ffSJim Harris 	 *
5454473942fSPawel Wodkowski 	 *                bdev8
54657d174ffSJim Harris 	 *                  |
54757d174ffSJim Harris 	 *            +----------+
54857d174ffSJim Harris 	 *            |          |
5494473942fSPawel Wodkowski 	 *          bdev4      bdev5   bdev6   bdev7
55057d174ffSJim Harris 	 *            |          |       |       |
5514473942fSPawel Wodkowski 	 *        +---+---+      +---+   +   +---+---+
5524473942fSPawel Wodkowski 	 *        |       |           \  |  /         \
5534473942fSPawel Wodkowski 	 *      bdev0   bdev1          bdev2         bdev3
55457d174ffSJim Harris 	 */
55557d174ffSJim Harris 
55657d174ffSJim Harris 	bdev[0] = allocate_bdev("bdev0");
5574d367354SPawel Wodkowski 	rc = spdk_bdev_module_claim_bdev(bdev[0], NULL, &bdev_ut_if);
5584fc7e666SJim Harris 	CU_ASSERT(rc == 0);
5594fc7e666SJim Harris 
56057d174ffSJim Harris 	bdev[1] = allocate_bdev("bdev1");
5614d367354SPawel Wodkowski 	rc = spdk_bdev_module_claim_bdev(bdev[1], NULL, &bdev_ut_if);
5624fc7e666SJim Harris 	CU_ASSERT(rc == 0);
5634fc7e666SJim Harris 
56457d174ffSJim Harris 	bdev[2] = allocate_bdev("bdev2");
5654d367354SPawel Wodkowski 	rc = spdk_bdev_module_claim_bdev(bdev[2], NULL, &bdev_ut_if);
5664fc7e666SJim Harris 	CU_ASSERT(rc == 0);
56757d174ffSJim Harris 
5684473942fSPawel Wodkowski 	bdev[3] = allocate_bdev("bdev3");
5694d367354SPawel Wodkowski 	rc = spdk_bdev_module_claim_bdev(bdev[3], NULL, &bdev_ut_if);
5704fc7e666SJim Harris 	CU_ASSERT(rc == 0);
57157d174ffSJim Harris 
572bfd1e46eSJim Harris 	bdev[4] = allocate_vbdev("bdev4");
5734d367354SPawel Wodkowski 	rc = spdk_bdev_module_claim_bdev(bdev[4], NULL, &bdev_ut_if);
5744fc7e666SJim Harris 	CU_ASSERT(rc == 0);
5754fc7e666SJim Harris 
576bfd1e46eSJim Harris 	bdev[5] = allocate_vbdev("bdev5");
5774473942fSPawel Wodkowski 	rc = spdk_bdev_module_claim_bdev(bdev[5], NULL, &bdev_ut_if);
5784473942fSPawel Wodkowski 	CU_ASSERT(rc == 0);
5794473942fSPawel Wodkowski 
580bfd1e46eSJim Harris 	bdev[6] = allocate_vbdev("bdev6");
58157d174ffSJim Harris 
582bfd1e46eSJim Harris 	bdev[7] = allocate_vbdev("bdev7");
5834473942fSPawel Wodkowski 
584bfd1e46eSJim Harris 	bdev[8] = allocate_vbdev("bdev8");
5854473942fSPawel Wodkowski 
58657d174ffSJim Harris 	/* Open bdev0 read-only.  This should succeed. */
587*75dfecbbSShuhei Matsumoto 	rc = spdk_bdev_open_ext("bdev0", false, bdev_ut_event_cb, NULL, &desc[0]);
58857d174ffSJim Harris 	CU_ASSERT(rc == 0);
5891196deb5SSeth Howell 	SPDK_CU_ASSERT_FATAL(desc[0] != NULL);
590*75dfecbbSShuhei Matsumoto 	CU_ASSERT(bdev[0] == spdk_bdev_desc_get_bdev(desc[0]));
59157d174ffSJim Harris 	spdk_bdev_close(desc[0]);
59257d174ffSJim Harris 
5934fc7e666SJim Harris 	/*
5944fc7e666SJim Harris 	 * Open bdev1 read/write.  This should fail since bdev1 has been claimed
5954fc7e666SJim Harris 	 * by a vbdev module.
5964fc7e666SJim Harris 	 */
597*75dfecbbSShuhei Matsumoto 	rc = spdk_bdev_open_ext("bdev1", true, bdev_ut_event_cb, NULL, &desc[1]);
5984fc7e666SJim Harris 	CU_ASSERT(rc == -EPERM);
59957d174ffSJim Harris 
60057d174ffSJim Harris 	/*
6014473942fSPawel Wodkowski 	 * Open bdev4 read/write.  This should fail since bdev3 has been claimed
6024fc7e666SJim Harris 	 * by a vbdev module.
60357d174ffSJim Harris 	 */
604*75dfecbbSShuhei Matsumoto 	rc = spdk_bdev_open_ext("bdev4", true, bdev_ut_event_cb, NULL, &desc[4]);
60557d174ffSJim Harris 	CU_ASSERT(rc == -EPERM);
60657d174ffSJim Harris 
60757d174ffSJim Harris 	/* Open bdev4 read-only.  This should succeed. */
608*75dfecbbSShuhei Matsumoto 	rc = spdk_bdev_open_ext("bdev4", false, bdev_ut_event_cb, NULL, &desc[4]);
60957d174ffSJim Harris 	CU_ASSERT(rc == 0);
6101196deb5SSeth Howell 	SPDK_CU_ASSERT_FATAL(desc[4] != NULL);
611*75dfecbbSShuhei Matsumoto 	CU_ASSERT(bdev[4] == spdk_bdev_desc_get_bdev(desc[4]));
61257d174ffSJim Harris 	spdk_bdev_close(desc[4]);
61357d174ffSJim Harris 
6144473942fSPawel Wodkowski 	/*
6154473942fSPawel Wodkowski 	 * Open bdev8 read/write.  This should succeed since it is a leaf
6164473942fSPawel Wodkowski 	 * bdev.
6174473942fSPawel Wodkowski 	 */
618*75dfecbbSShuhei Matsumoto 	rc = spdk_bdev_open_ext("bdev8", true, bdev_ut_event_cb, NULL, &desc[8]);
6194473942fSPawel Wodkowski 	CU_ASSERT(rc == 0);
6201196deb5SSeth Howell 	SPDK_CU_ASSERT_FATAL(desc[8] != NULL);
621*75dfecbbSShuhei Matsumoto 	CU_ASSERT(bdev[8] == spdk_bdev_desc_get_bdev(desc[8]));
6224473942fSPawel Wodkowski 	spdk_bdev_close(desc[8]);
62357d174ffSJim Harris 
6244473942fSPawel Wodkowski 	/*
6254473942fSPawel Wodkowski 	 * Open bdev5 read/write.  This should fail since bdev4 has been claimed
6264473942fSPawel Wodkowski 	 * by a vbdev module.
6274473942fSPawel Wodkowski 	 */
628*75dfecbbSShuhei Matsumoto 	rc = spdk_bdev_open_ext("bdev5", true, bdev_ut_event_cb, NULL, &desc[5]);
6294473942fSPawel Wodkowski 	CU_ASSERT(rc == -EPERM);
6304473942fSPawel Wodkowski 
6314473942fSPawel Wodkowski 	/* Open bdev4 read-only.  This should succeed. */
632*75dfecbbSShuhei Matsumoto 	rc = spdk_bdev_open_ext("bdev5", false, bdev_ut_event_cb, NULL, &desc[5]);
6334473942fSPawel Wodkowski 	CU_ASSERT(rc == 0);
6341196deb5SSeth Howell 	SPDK_CU_ASSERT_FATAL(desc[5] != NULL);
635*75dfecbbSShuhei Matsumoto 	CU_ASSERT(bdev[5] == spdk_bdev_desc_get_bdev(desc[5]));
6364473942fSPawel Wodkowski 	spdk_bdev_close(desc[5]);
6374473942fSPawel Wodkowski 
6384473942fSPawel Wodkowski 	free_vbdev(bdev[8]);
6394473942fSPawel Wodkowski 
64057d174ffSJim Harris 	free_vbdev(bdev[5]);
64157d174ffSJim Harris 	free_vbdev(bdev[6]);
6424473942fSPawel Wodkowski 	free_vbdev(bdev[7]);
6434473942fSPawel Wodkowski 
6444473942fSPawel Wodkowski 	free_vbdev(bdev[4]);
64557d174ffSJim Harris 
64657d174ffSJim Harris 	free_bdev(bdev[0]);
64757d174ffSJim Harris 	free_bdev(bdev[1]);
64857d174ffSJim Harris 	free_bdev(bdev[2]);
6494473942fSPawel Wodkowski 	free_bdev(bdev[3]);
6504ee51dcbSJim Harris }
6514ee51dcbSJim Harris 
652906ce694SDaniel Verkamp static void
653e83f9767SDaniel Verkamp bytes_to_blocks_test(void)
654e83f9767SDaniel Verkamp {
655e83f9767SDaniel Verkamp 	struct spdk_bdev bdev;
656e83f9767SDaniel Verkamp 	uint64_t offset_blocks, num_blocks;
657e83f9767SDaniel Verkamp 
658e83f9767SDaniel Verkamp 	memset(&bdev, 0, sizeof(bdev));
659e83f9767SDaniel Verkamp 
660e83f9767SDaniel Verkamp 	bdev.blocklen = 512;
661e83f9767SDaniel Verkamp 
662e83f9767SDaniel Verkamp 	/* All parameters valid */
663e83f9767SDaniel Verkamp 	offset_blocks = 0;
664e83f9767SDaniel Verkamp 	num_blocks = 0;
6650e58d154SJim Harris 	CU_ASSERT(bdev_bytes_to_blocks(&bdev, 512, &offset_blocks, 1024, &num_blocks) == 0);
666e83f9767SDaniel Verkamp 	CU_ASSERT(offset_blocks == 1);
667e83f9767SDaniel Verkamp 	CU_ASSERT(num_blocks == 2);
668e83f9767SDaniel Verkamp 
669e83f9767SDaniel Verkamp 	/* Offset not a block multiple */
6700e58d154SJim Harris 	CU_ASSERT(bdev_bytes_to_blocks(&bdev, 3, &offset_blocks, 512, &num_blocks) != 0);
671e83f9767SDaniel Verkamp 
672e83f9767SDaniel Verkamp 	/* Length not a block multiple */
6730e58d154SJim Harris 	CU_ASSERT(bdev_bytes_to_blocks(&bdev, 512, &offset_blocks, 3, &num_blocks) != 0);
67402be32d4Slorneli 
67502be32d4Slorneli 	/* In case blocklen not the power of two */
67602be32d4Slorneli 	bdev.blocklen = 100;
6770e58d154SJim Harris 	CU_ASSERT(bdev_bytes_to_blocks(&bdev, 100, &offset_blocks, 200, &num_blocks) == 0);
67802be32d4Slorneli 	CU_ASSERT(offset_blocks == 1);
67902be32d4Slorneli 	CU_ASSERT(num_blocks == 2);
68002be32d4Slorneli 
68102be32d4Slorneli 	/* Offset not a block multiple */
6820e58d154SJim Harris 	CU_ASSERT(bdev_bytes_to_blocks(&bdev, 3, &offset_blocks, 100, &num_blocks) != 0);
68302be32d4Slorneli 
68402be32d4Slorneli 	/* Length not a block multiple */
6850e58d154SJim Harris 	CU_ASSERT(bdev_bytes_to_blocks(&bdev, 100, &offset_blocks, 3, &num_blocks) != 0);
686e83f9767SDaniel Verkamp }
687e83f9767SDaniel Verkamp 
688e83f9767SDaniel Verkamp static void
689d4822a7dSSlawomir Mrozowicz num_blocks_test(void)
690d4822a7dSSlawomir Mrozowicz {
691d4822a7dSSlawomir Mrozowicz 	struct spdk_bdev bdev;
6921196deb5SSeth Howell 	struct spdk_bdev_desc *desc = NULL;
6939522ed36SEvgeniy Kochetov 	struct spdk_bdev_desc *desc_ext = NULL;
6941196deb5SSeth Howell 	int rc;
695d4822a7dSSlawomir Mrozowicz 
696d4822a7dSSlawomir Mrozowicz 	memset(&bdev, 0, sizeof(bdev));
697d4822a7dSSlawomir Mrozowicz 	bdev.name = "num_blocks";
698d4822a7dSSlawomir Mrozowicz 	bdev.fn_table = &fn_table;
6994d367354SPawel Wodkowski 	bdev.module = &bdev_ut_if;
700d4822a7dSSlawomir Mrozowicz 	spdk_bdev_register(&bdev);
701d4822a7dSSlawomir Mrozowicz 	spdk_bdev_notify_blockcnt_change(&bdev, 50);
702d4822a7dSSlawomir Mrozowicz 
703d4822a7dSSlawomir Mrozowicz 	/* Growing block number */
704d4822a7dSSlawomir Mrozowicz 	CU_ASSERT(spdk_bdev_notify_blockcnt_change(&bdev, 70) == 0);
705d4822a7dSSlawomir Mrozowicz 	/* Shrinking block number */
706d4822a7dSSlawomir Mrozowicz 	CU_ASSERT(spdk_bdev_notify_blockcnt_change(&bdev, 30) == 0);
707d4822a7dSSlawomir Mrozowicz 
708d4822a7dSSlawomir Mrozowicz 	/* In case bdev opened */
7091196deb5SSeth Howell 	rc = spdk_bdev_open(&bdev, false, NULL, NULL, &desc);
7101196deb5SSeth Howell 	CU_ASSERT(rc == 0);
7111196deb5SSeth Howell 	SPDK_CU_ASSERT_FATAL(desc != NULL);
712d4822a7dSSlawomir Mrozowicz 
713d4822a7dSSlawomir Mrozowicz 	/* Growing block number */
714d4822a7dSSlawomir Mrozowicz 	CU_ASSERT(spdk_bdev_notify_blockcnt_change(&bdev, 80) == 0);
715d4822a7dSSlawomir Mrozowicz 	/* Shrinking block number */
716d4822a7dSSlawomir Mrozowicz 	CU_ASSERT(spdk_bdev_notify_blockcnt_change(&bdev, 20) != 0);
717d4822a7dSSlawomir Mrozowicz 
7189522ed36SEvgeniy Kochetov 	/* In case bdev opened with ext API */
7199522ed36SEvgeniy Kochetov 	rc = spdk_bdev_open_ext("num_blocks", false, bdev_open_cb1, &desc_ext, &desc_ext);
7209522ed36SEvgeniy Kochetov 	CU_ASSERT(rc == 0);
7219522ed36SEvgeniy Kochetov 	SPDK_CU_ASSERT_FATAL(desc_ext != NULL);
722*75dfecbbSShuhei Matsumoto 	CU_ASSERT(&bdev == spdk_bdev_desc_get_bdev(desc_ext));
7239522ed36SEvgeniy Kochetov 
7249522ed36SEvgeniy Kochetov 	g_event_type1 = 0xFF;
7259522ed36SEvgeniy Kochetov 	/* Growing block number */
7269522ed36SEvgeniy Kochetov 	CU_ASSERT(spdk_bdev_notify_blockcnt_change(&bdev, 90) == 0);
7279522ed36SEvgeniy Kochetov 
7289522ed36SEvgeniy Kochetov 	poll_threads();
7299522ed36SEvgeniy Kochetov 	CU_ASSERT_EQUAL(g_event_type1, SPDK_BDEV_EVENT_RESIZE);
7309522ed36SEvgeniy Kochetov 
7319522ed36SEvgeniy Kochetov 	g_event_type1 = 0xFF;
7329522ed36SEvgeniy Kochetov 	/* Growing block number and closing */
7339522ed36SEvgeniy Kochetov 	CU_ASSERT(spdk_bdev_notify_blockcnt_change(&bdev, 100) == 0);
7349522ed36SEvgeniy Kochetov 
735d4822a7dSSlawomir Mrozowicz 	spdk_bdev_close(desc);
7369522ed36SEvgeniy Kochetov 	spdk_bdev_close(desc_ext);
737d4822a7dSSlawomir Mrozowicz 	spdk_bdev_unregister(&bdev, NULL, NULL);
738270a25dfSBen Walker 
739270a25dfSBen Walker 	poll_threads();
7409522ed36SEvgeniy Kochetov 
7419522ed36SEvgeniy Kochetov 	/* Callback is not called for closed device */
7429522ed36SEvgeniy Kochetov 	CU_ASSERT_EQUAL(g_event_type1, 0xFF);
743d4822a7dSSlawomir Mrozowicz }
744d4822a7dSSlawomir Mrozowicz 
745d4822a7dSSlawomir Mrozowicz static void
746906ce694SDaniel Verkamp io_valid_test(void)
747906ce694SDaniel Verkamp {
748906ce694SDaniel Verkamp 	struct spdk_bdev bdev;
749906ce694SDaniel Verkamp 
750906ce694SDaniel Verkamp 	memset(&bdev, 0, sizeof(bdev));
751906ce694SDaniel Verkamp 
752906ce694SDaniel Verkamp 	bdev.blocklen = 512;
753d4822a7dSSlawomir Mrozowicz 	spdk_bdev_notify_blockcnt_change(&bdev, 100);
754906ce694SDaniel Verkamp 
755906ce694SDaniel Verkamp 	/* All parameters valid */
7560e58d154SJim Harris 	CU_ASSERT(bdev_io_valid_blocks(&bdev, 1, 2) == true);
757906ce694SDaniel Verkamp 
758906ce694SDaniel Verkamp 	/* Last valid block */
7590e58d154SJim Harris 	CU_ASSERT(bdev_io_valid_blocks(&bdev, 99, 1) == true);
760906ce694SDaniel Verkamp 
761906ce694SDaniel Verkamp 	/* Offset past end of bdev */
7620e58d154SJim Harris 	CU_ASSERT(bdev_io_valid_blocks(&bdev, 100, 1) == false);
763906ce694SDaniel Verkamp 
764906ce694SDaniel Verkamp 	/* Offset + length past end of bdev */
7650e58d154SJim Harris 	CU_ASSERT(bdev_io_valid_blocks(&bdev, 99, 2) == false);
766906ce694SDaniel Verkamp 
767e83f9767SDaniel Verkamp 	/* Offset near end of uint64_t range (2^64 - 1) */
7680e58d154SJim Harris 	CU_ASSERT(bdev_io_valid_blocks(&bdev, 18446744073709551615ULL, 1) == false);
769906ce694SDaniel Verkamp }
770906ce694SDaniel Verkamp 
771b9afa3c7SSebastian Basierski static void
772b9afa3c7SSebastian Basierski alias_add_del_test(void)
773b9afa3c7SSebastian Basierski {
7746deac3e6Swuzhouhui 	struct spdk_bdev *bdev[3];
775b9afa3c7SSebastian Basierski 	int rc;
776b9afa3c7SSebastian Basierski 
777b9afa3c7SSebastian Basierski 	/* Creating and registering bdevs */
778b9afa3c7SSebastian Basierski 	bdev[0] = allocate_bdev("bdev0");
779b9afa3c7SSebastian Basierski 	SPDK_CU_ASSERT_FATAL(bdev[0] != 0);
780b9afa3c7SSebastian Basierski 
781b9afa3c7SSebastian Basierski 	bdev[1] = allocate_bdev("bdev1");
782b9afa3c7SSebastian Basierski 	SPDK_CU_ASSERT_FATAL(bdev[1] != 0);
783b9afa3c7SSebastian Basierski 
7846deac3e6Swuzhouhui 	bdev[2] = allocate_bdev("bdev2");
7856deac3e6Swuzhouhui 	SPDK_CU_ASSERT_FATAL(bdev[2] != 0);
7866deac3e6Swuzhouhui 
787270a25dfSBen Walker 	poll_threads();
788270a25dfSBen Walker 
789b9afa3c7SSebastian Basierski 	/*
790b9afa3c7SSebastian Basierski 	 * Trying adding an alias identical to name.
791b9afa3c7SSebastian Basierski 	 * Alias is identical to name, so it can not be added to aliases list
792b9afa3c7SSebastian Basierski 	 */
793b9afa3c7SSebastian Basierski 	rc = spdk_bdev_alias_add(bdev[0], bdev[0]->name);
794b9afa3c7SSebastian Basierski 	CU_ASSERT(rc == -EEXIST);
795b9afa3c7SSebastian Basierski 
796b9afa3c7SSebastian Basierski 	/*
797b9afa3c7SSebastian Basierski 	 * Trying to add empty alias,
798b9afa3c7SSebastian Basierski 	 * this one should fail
799b9afa3c7SSebastian Basierski 	 */
800b9afa3c7SSebastian Basierski 	rc = spdk_bdev_alias_add(bdev[0], NULL);
801b9afa3c7SSebastian Basierski 	CU_ASSERT(rc == -EINVAL);
802b9afa3c7SSebastian Basierski 
803b9afa3c7SSebastian Basierski 	/* Trying adding same alias to two different registered bdevs */
804b9afa3c7SSebastian Basierski 
805b9afa3c7SSebastian Basierski 	/* Alias is used first time, so this one should pass */
806b9afa3c7SSebastian Basierski 	rc = spdk_bdev_alias_add(bdev[0], "proper alias 0");
807b9afa3c7SSebastian Basierski 	CU_ASSERT(rc == 0);
808b9afa3c7SSebastian Basierski 
809b9afa3c7SSebastian Basierski 	/* Alias was added to another bdev, so this one should fail */
810b9afa3c7SSebastian Basierski 	rc = spdk_bdev_alias_add(bdev[1], "proper alias 0");
811b9afa3c7SSebastian Basierski 	CU_ASSERT(rc == -EEXIST);
812b9afa3c7SSebastian Basierski 
813b9afa3c7SSebastian Basierski 	/* Alias is used first time, so this one should pass */
814b9afa3c7SSebastian Basierski 	rc = spdk_bdev_alias_add(bdev[1], "proper alias 1");
815b9afa3c7SSebastian Basierski 	CU_ASSERT(rc == 0);
816b9afa3c7SSebastian Basierski 
817b9afa3c7SSebastian Basierski 	/* Trying removing an alias from registered bdevs */
818b9afa3c7SSebastian Basierski 
819b9afa3c7SSebastian Basierski 	/* Alias is not on a bdev aliases list, so this one should fail */
820b9afa3c7SSebastian Basierski 	rc = spdk_bdev_alias_del(bdev[0], "not existing");
821b9afa3c7SSebastian Basierski 	CU_ASSERT(rc == -ENOENT);
822b9afa3c7SSebastian Basierski 
823b9afa3c7SSebastian Basierski 	/* Alias is present on a bdev aliases list, so this one should pass */
824b9afa3c7SSebastian Basierski 	rc = spdk_bdev_alias_del(bdev[0], "proper alias 0");
825b9afa3c7SSebastian Basierski 	CU_ASSERT(rc == 0);
826b9afa3c7SSebastian Basierski 
827b9afa3c7SSebastian Basierski 	/* Alias is present on a bdev aliases list, so this one should pass */
828b9afa3c7SSebastian Basierski 	rc = spdk_bdev_alias_del(bdev[1], "proper alias 1");
829b9afa3c7SSebastian Basierski 	CU_ASSERT(rc == 0);
830b9afa3c7SSebastian Basierski 
831b9afa3c7SSebastian Basierski 	/* Trying to remove name instead of alias, so this one should fail, name cannot be changed or removed */
832b9afa3c7SSebastian Basierski 	rc = spdk_bdev_alias_del(bdev[0], bdev[0]->name);
833b9afa3c7SSebastian Basierski 	CU_ASSERT(rc != 0);
834b9afa3c7SSebastian Basierski 
8356deac3e6Swuzhouhui 	/* Trying to del all alias from empty alias list */
8366deac3e6Swuzhouhui 	spdk_bdev_alias_del_all(bdev[2]);
83711ccf3beSSeth Howell 	SPDK_CU_ASSERT_FATAL(TAILQ_EMPTY(&bdev[2]->aliases));
8386deac3e6Swuzhouhui 
8396deac3e6Swuzhouhui 	/* Trying to del all alias from non-empty alias list */
8406deac3e6Swuzhouhui 	rc = spdk_bdev_alias_add(bdev[2], "alias0");
8416deac3e6Swuzhouhui 	CU_ASSERT(rc == 0);
8426deac3e6Swuzhouhui 	rc = spdk_bdev_alias_add(bdev[2], "alias1");
8436deac3e6Swuzhouhui 	CU_ASSERT(rc == 0);
8446deac3e6Swuzhouhui 	spdk_bdev_alias_del_all(bdev[2]);
8456deac3e6Swuzhouhui 	CU_ASSERT(TAILQ_EMPTY(&bdev[2]->aliases));
8466deac3e6Swuzhouhui 
847b9afa3c7SSebastian Basierski 	/* Unregister and free bdevs */
848b9afa3c7SSebastian Basierski 	spdk_bdev_unregister(bdev[0], NULL, NULL);
849b9afa3c7SSebastian Basierski 	spdk_bdev_unregister(bdev[1], NULL, NULL);
8506deac3e6Swuzhouhui 	spdk_bdev_unregister(bdev[2], NULL, NULL);
851b9afa3c7SSebastian Basierski 
852270a25dfSBen Walker 	poll_threads();
853270a25dfSBen Walker 
854b9afa3c7SSebastian Basierski 	free(bdev[0]);
855b9afa3c7SSebastian Basierski 	free(bdev[1]);
8566deac3e6Swuzhouhui 	free(bdev[2]);
857b9afa3c7SSebastian Basierski }
858b9afa3c7SSebastian Basierski 
85932d7c91cSJim Harris static void
86032d7c91cSJim Harris io_done(struct spdk_bdev_io *bdev_io, bool success, void *cb_arg)
86132d7c91cSJim Harris {
8624bd97621SJim Harris 	g_io_done = true;
8630df515a8SShuhei Matsumoto 	g_io_status = bdev_io->internal.status;
86432d7c91cSJim Harris 	spdk_bdev_free_io(bdev_io);
86532d7c91cSJim Harris }
86632d7c91cSJim Harris 
86732d7c91cSJim Harris static void
86832d7c91cSJim Harris bdev_init_cb(void *arg, int rc)
86932d7c91cSJim Harris {
87032d7c91cSJim Harris 	CU_ASSERT(rc == 0);
87132d7c91cSJim Harris }
87232d7c91cSJim Harris 
8738ef7818aSJim Harris static void
8748ef7818aSJim Harris bdev_fini_cb(void *arg)
8758ef7818aSJim Harris {
8768ef7818aSJim Harris }
8778ef7818aSJim Harris 
87832d7c91cSJim Harris struct bdev_ut_io_wait_entry {
87932d7c91cSJim Harris 	struct spdk_bdev_io_wait_entry	entry;
88032d7c91cSJim Harris 	struct spdk_io_channel		*io_ch;
88132d7c91cSJim Harris 	struct spdk_bdev_desc		*desc;
88232d7c91cSJim Harris 	bool				submitted;
88332d7c91cSJim Harris };
88432d7c91cSJim Harris 
88532d7c91cSJim Harris static void
88632d7c91cSJim Harris io_wait_cb(void *arg)
88732d7c91cSJim Harris {
88832d7c91cSJim Harris 	struct bdev_ut_io_wait_entry *entry = arg;
88932d7c91cSJim Harris 	int rc;
89032d7c91cSJim Harris 
89132d7c91cSJim Harris 	rc = spdk_bdev_read_blocks(entry->desc, entry->io_ch, NULL, 0, 1, io_done, NULL);
89232d7c91cSJim Harris 	CU_ASSERT(rc == 0);
89332d7c91cSJim Harris 	entry->submitted = true;
89432d7c91cSJim Harris }
89532d7c91cSJim Harris 
89632d7c91cSJim Harris static void
8979da1c738SChangpeng Liu bdev_io_types_test(void)
8989da1c738SChangpeng Liu {
8999da1c738SChangpeng Liu 	struct spdk_bdev *bdev;
9009da1c738SChangpeng Liu 	struct spdk_bdev_desc *desc = NULL;
9019da1c738SChangpeng Liu 	struct spdk_io_channel *io_ch;
9029da1c738SChangpeng Liu 	struct spdk_bdev_opts bdev_opts = {
9039da1c738SChangpeng Liu 		.bdev_io_pool_size = 4,
9049da1c738SChangpeng Liu 		.bdev_io_cache_size = 2,
9059da1c738SChangpeng Liu 	};
9069da1c738SChangpeng Liu 	int rc;
9079da1c738SChangpeng Liu 
9089da1c738SChangpeng Liu 	rc = spdk_bdev_set_opts(&bdev_opts);
9099da1c738SChangpeng Liu 	CU_ASSERT(rc == 0);
9109da1c738SChangpeng Liu 	spdk_bdev_initialize(bdev_init_cb, NULL);
9119da1c738SChangpeng Liu 	poll_threads();
9129da1c738SChangpeng Liu 
9139da1c738SChangpeng Liu 	bdev = allocate_bdev("bdev0");
9149da1c738SChangpeng Liu 
915*75dfecbbSShuhei Matsumoto 	rc = spdk_bdev_open_ext("bdev0", true, bdev_ut_event_cb, NULL, &desc);
9169da1c738SChangpeng Liu 	CU_ASSERT(rc == 0);
9179da1c738SChangpeng Liu 	poll_threads();
9189da1c738SChangpeng Liu 	SPDK_CU_ASSERT_FATAL(desc != NULL);
919*75dfecbbSShuhei Matsumoto 	CU_ASSERT(bdev == spdk_bdev_desc_get_bdev(desc));
9209da1c738SChangpeng Liu 	io_ch = spdk_bdev_get_io_channel(desc);
9219da1c738SChangpeng Liu 	CU_ASSERT(io_ch != NULL);
9229da1c738SChangpeng Liu 
9239da1c738SChangpeng Liu 	/* WRITE and WRITE ZEROES are not supported */
924e2918289SKonrad Sztyber 	ut_enable_io_type(SPDK_BDEV_IO_TYPE_WRITE_ZEROES, false);
925e2918289SKonrad Sztyber 	ut_enable_io_type(SPDK_BDEV_IO_TYPE_WRITE, false);
9269da1c738SChangpeng Liu 	rc = spdk_bdev_write_zeroes_blocks(desc, io_ch, 0, 128, io_done, NULL);
9279da1c738SChangpeng Liu 	CU_ASSERT(rc == -ENOTSUP);
928e2918289SKonrad Sztyber 	ut_enable_io_type(SPDK_BDEV_IO_TYPE_WRITE_ZEROES, true);
929e2918289SKonrad Sztyber 	ut_enable_io_type(SPDK_BDEV_IO_TYPE_WRITE, true);
9309da1c738SChangpeng Liu 
9319da1c738SChangpeng Liu 	spdk_put_io_channel(io_ch);
9329da1c738SChangpeng Liu 	spdk_bdev_close(desc);
9339da1c738SChangpeng Liu 	free_bdev(bdev);
9349da1c738SChangpeng Liu 	spdk_bdev_finish(bdev_fini_cb, NULL);
9359da1c738SChangpeng Liu 	poll_threads();
9369da1c738SChangpeng Liu }
9379da1c738SChangpeng Liu 
9389da1c738SChangpeng Liu static void
93932d7c91cSJim Harris bdev_io_wait_test(void)
94032d7c91cSJim Harris {
94132d7c91cSJim Harris 	struct spdk_bdev *bdev;
942fb0fe6b1SShuhei Matsumoto 	struct spdk_bdev_desc *desc = NULL;
94332d7c91cSJim Harris 	struct spdk_io_channel *io_ch;
94432d7c91cSJim Harris 	struct spdk_bdev_opts bdev_opts = {
94532d7c91cSJim Harris 		.bdev_io_pool_size = 4,
94632d7c91cSJim Harris 		.bdev_io_cache_size = 2,
94732d7c91cSJim Harris 	};
94832d7c91cSJim Harris 	struct bdev_ut_io_wait_entry io_wait_entry;
94932d7c91cSJim Harris 	struct bdev_ut_io_wait_entry io_wait_entry2;
95032d7c91cSJim Harris 	int rc;
95132d7c91cSJim Harris 
95232d7c91cSJim Harris 	rc = spdk_bdev_set_opts(&bdev_opts);
95332d7c91cSJim Harris 	CU_ASSERT(rc == 0);
95432d7c91cSJim Harris 	spdk_bdev_initialize(bdev_init_cb, NULL);
955270a25dfSBen Walker 	poll_threads();
95632d7c91cSJim Harris 
95732d7c91cSJim Harris 	bdev = allocate_bdev("bdev0");
95832d7c91cSJim Harris 
959*75dfecbbSShuhei Matsumoto 	rc = spdk_bdev_open_ext("bdev0", true, bdev_ut_event_cb, NULL, &desc);
96032d7c91cSJim Harris 	CU_ASSERT(rc == 0);
961270a25dfSBen Walker 	poll_threads();
962fb0fe6b1SShuhei Matsumoto 	SPDK_CU_ASSERT_FATAL(desc != NULL);
963*75dfecbbSShuhei Matsumoto 	CU_ASSERT(bdev == spdk_bdev_desc_get_bdev(desc));
96432d7c91cSJim Harris 	io_ch = spdk_bdev_get_io_channel(desc);
96532d7c91cSJim Harris 	CU_ASSERT(io_ch != NULL);
96632d7c91cSJim Harris 
96732d7c91cSJim Harris 	rc = spdk_bdev_read_blocks(desc, io_ch, NULL, 0, 1, io_done, NULL);
96832d7c91cSJim Harris 	CU_ASSERT(rc == 0);
96932d7c91cSJim Harris 	rc = spdk_bdev_read_blocks(desc, io_ch, NULL, 0, 1, io_done, NULL);
97032d7c91cSJim Harris 	CU_ASSERT(rc == 0);
97132d7c91cSJim Harris 	rc = spdk_bdev_read_blocks(desc, io_ch, NULL, 0, 1, io_done, NULL);
97232d7c91cSJim Harris 	CU_ASSERT(rc == 0);
97332d7c91cSJim Harris 	rc = spdk_bdev_read_blocks(desc, io_ch, NULL, 0, 1, io_done, NULL);
97432d7c91cSJim Harris 	CU_ASSERT(rc == 0);
97532d7c91cSJim Harris 	CU_ASSERT(g_bdev_ut_channel->outstanding_io_count == 4);
97632d7c91cSJim Harris 
97732d7c91cSJim Harris 	rc = spdk_bdev_read_blocks(desc, io_ch, NULL, 0, 1, io_done, NULL);
97832d7c91cSJim Harris 	CU_ASSERT(rc == -ENOMEM);
97932d7c91cSJim Harris 
98032d7c91cSJim Harris 	io_wait_entry.entry.bdev = bdev;
98132d7c91cSJim Harris 	io_wait_entry.entry.cb_fn = io_wait_cb;
98232d7c91cSJim Harris 	io_wait_entry.entry.cb_arg = &io_wait_entry;
98332d7c91cSJim Harris 	io_wait_entry.io_ch = io_ch;
98432d7c91cSJim Harris 	io_wait_entry.desc = desc;
98532d7c91cSJim Harris 	io_wait_entry.submitted = false;
98632d7c91cSJim Harris 	/* Cannot use the same io_wait_entry for two different calls. */
98732d7c91cSJim Harris 	memcpy(&io_wait_entry2, &io_wait_entry, sizeof(io_wait_entry));
98832d7c91cSJim Harris 	io_wait_entry2.entry.cb_arg = &io_wait_entry2;
98932d7c91cSJim Harris 
99032d7c91cSJim Harris 	/* Queue two I/O waits. */
99132d7c91cSJim Harris 	rc = spdk_bdev_queue_io_wait(bdev, io_ch, &io_wait_entry.entry);
99232d7c91cSJim Harris 	CU_ASSERT(rc == 0);
99332d7c91cSJim Harris 	CU_ASSERT(io_wait_entry.submitted == false);
99432d7c91cSJim Harris 	rc = spdk_bdev_queue_io_wait(bdev, io_ch, &io_wait_entry2.entry);
99532d7c91cSJim Harris 	CU_ASSERT(rc == 0);
99632d7c91cSJim Harris 	CU_ASSERT(io_wait_entry2.submitted == false);
99732d7c91cSJim Harris 
99832d7c91cSJim Harris 	stub_complete_io(1);
99932d7c91cSJim Harris 	CU_ASSERT(g_bdev_ut_channel->outstanding_io_count == 4);
100032d7c91cSJim Harris 	CU_ASSERT(io_wait_entry.submitted == true);
100132d7c91cSJim Harris 	CU_ASSERT(io_wait_entry2.submitted == false);
100232d7c91cSJim Harris 
100332d7c91cSJim Harris 	stub_complete_io(1);
100432d7c91cSJim Harris 	CU_ASSERT(g_bdev_ut_channel->outstanding_io_count == 4);
100532d7c91cSJim Harris 	CU_ASSERT(io_wait_entry2.submitted == true);
100632d7c91cSJim Harris 
100732d7c91cSJim Harris 	stub_complete_io(4);
100832d7c91cSJim Harris 	CU_ASSERT(g_bdev_ut_channel->outstanding_io_count == 0);
100932d7c91cSJim Harris 
101032d7c91cSJim Harris 	spdk_put_io_channel(io_ch);
101132d7c91cSJim Harris 	spdk_bdev_close(desc);
101232d7c91cSJim Harris 	free_bdev(bdev);
10138ef7818aSJim Harris 	spdk_bdev_finish(bdev_fini_cb, NULL);
1014270a25dfSBen Walker 	poll_threads();
101532d7c91cSJim Harris }
101632d7c91cSJim Harris 
10174bd97621SJim Harris static void
10184bd97621SJim Harris bdev_io_spans_boundary_test(void)
10194bd97621SJim Harris {
10204bd97621SJim Harris 	struct spdk_bdev bdev;
10214bd97621SJim Harris 	struct spdk_bdev_io bdev_io;
10224bd97621SJim Harris 
10234bd97621SJim Harris 	memset(&bdev, 0, sizeof(bdev));
10244bd97621SJim Harris 
10254bd97621SJim Harris 	bdev.optimal_io_boundary = 0;
10264bd97621SJim Harris 	bdev_io.bdev = &bdev;
10274bd97621SJim Harris 
10284bd97621SJim Harris 	/* bdev has no optimal_io_boundary set - so this should return false. */
1029aa485663SJim Harris 	CU_ASSERT(bdev_io_should_split(&bdev_io) == false);
10304bd97621SJim Harris 
10314bd97621SJim Harris 	bdev.optimal_io_boundary = 32;
10324bd97621SJim Harris 	bdev_io.type = SPDK_BDEV_IO_TYPE_RESET;
10334bd97621SJim Harris 
10344bd97621SJim Harris 	/* RESETs are not based on LBAs - so this should return false. */
1035aa485663SJim Harris 	CU_ASSERT(bdev_io_should_split(&bdev_io) == false);
10364bd97621SJim Harris 
10374bd97621SJim Harris 	bdev_io.type = SPDK_BDEV_IO_TYPE_READ;
10384bd97621SJim Harris 	bdev_io.u.bdev.offset_blocks = 0;
10394bd97621SJim Harris 	bdev_io.u.bdev.num_blocks = 32;
10404bd97621SJim Harris 
10414bd97621SJim Harris 	/* This I/O run right up to, but does not cross, the boundary - so this should return false. */
1042aa485663SJim Harris 	CU_ASSERT(bdev_io_should_split(&bdev_io) == false);
10434bd97621SJim Harris 
10444bd97621SJim Harris 	bdev_io.u.bdev.num_blocks = 33;
10454bd97621SJim Harris 
10464bd97621SJim Harris 	/* This I/O spans a boundary. */
1047aa485663SJim Harris 	CU_ASSERT(bdev_io_should_split(&bdev_io) == true);
10484bd97621SJim Harris }
10494bd97621SJim Harris 
10504bd97621SJim Harris static void
10510e58d154SJim Harris bdev_io_split_test(void)
10524bd97621SJim Harris {
10534bd97621SJim Harris 	struct spdk_bdev *bdev;
1054fb0fe6b1SShuhei Matsumoto 	struct spdk_bdev_desc *desc = NULL;
10554bd97621SJim Harris 	struct spdk_io_channel *io_ch;
10564bd97621SJim Harris 	struct spdk_bdev_opts bdev_opts = {
10574bd97621SJim Harris 		.bdev_io_pool_size = 512,
10584bd97621SJim Harris 		.bdev_io_cache_size = 64,
10594bd97621SJim Harris 	};
10600df515a8SShuhei Matsumoto 	struct iovec iov[BDEV_IO_NUM_CHILD_IOV * 2];
10613c7894ffSShuhei Matsumoto 	struct ut_expected_io *expected_io;
10620df515a8SShuhei Matsumoto 	uint64_t i;
10634bd97621SJim Harris 	int rc;
10644bd97621SJim Harris 
10654bd97621SJim Harris 	rc = spdk_bdev_set_opts(&bdev_opts);
10664bd97621SJim Harris 	CU_ASSERT(rc == 0);
10674bd97621SJim Harris 	spdk_bdev_initialize(bdev_init_cb, NULL);
10684bd97621SJim Harris 
10694bd97621SJim Harris 	bdev = allocate_bdev("bdev0");
10704bd97621SJim Harris 
1071*75dfecbbSShuhei Matsumoto 	rc = spdk_bdev_open_ext("bdev0", true, bdev_ut_event_cb, NULL, &desc);
10724bd97621SJim Harris 	CU_ASSERT(rc == 0);
1073fb0fe6b1SShuhei Matsumoto 	SPDK_CU_ASSERT_FATAL(desc != NULL);
1074*75dfecbbSShuhei Matsumoto 	CU_ASSERT(bdev == spdk_bdev_desc_get_bdev(desc));
10754bd97621SJim Harris 	io_ch = spdk_bdev_get_io_channel(desc);
10764bd97621SJim Harris 	CU_ASSERT(io_ch != NULL);
10774bd97621SJim Harris 
10784bd97621SJim Harris 	bdev->optimal_io_boundary = 16;
10794bd97621SJim Harris 	bdev->split_on_optimal_io_boundary = false;
10804bd97621SJim Harris 
10814bd97621SJim Harris 	g_io_done = false;
10824bd97621SJim Harris 
10834bd97621SJim Harris 	/* First test that the I/O does not get split if split_on_optimal_io_boundary == false. */
10843c7894ffSShuhei Matsumoto 	expected_io = ut_alloc_expected_io(SPDK_BDEV_IO_TYPE_READ, 14, 8, 1);
10853c7894ffSShuhei Matsumoto 	ut_expected_io_set_iov(expected_io, 0, (void *)0xF000, 8 * 512);
10863c7894ffSShuhei Matsumoto 	TAILQ_INSERT_TAIL(&g_bdev_ut_channel->expected_io, expected_io, link);
10874bd97621SJim Harris 
10884bd97621SJim Harris 	rc = spdk_bdev_read_blocks(desc, io_ch, (void *)0xF000, 14, 8, io_done, NULL);
10894bd97621SJim Harris 	CU_ASSERT(rc == 0);
10904bd97621SJim Harris 	CU_ASSERT(g_io_done == false);
10914bd97621SJim Harris 
10924bd97621SJim Harris 	CU_ASSERT(g_bdev_ut_channel->outstanding_io_count == 1);
10934bd97621SJim Harris 	stub_complete_io(1);
10944bd97621SJim Harris 	CU_ASSERT(g_io_done == true);
10954bd97621SJim Harris 	CU_ASSERT(g_bdev_ut_channel->outstanding_io_count == 0);
10964bd97621SJim Harris 
10974bd97621SJim Harris 	bdev->split_on_optimal_io_boundary = true;
10984bd97621SJim Harris 
10994bd97621SJim Harris 	/* Now test that a single-vector command is split correctly.
11004bd97621SJim Harris 	 * Offset 14, length 8, payload 0xF000
11014bd97621SJim Harris 	 *  Child - Offset 14, length 2, payload 0xF000
11024bd97621SJim Harris 	 *  Child - Offset 16, length 6, payload 0xF000 + 2 * 512
11034bd97621SJim Harris 	 *
11048f33ef24SShuhei Matsumoto 	 * Set up the expected values before calling spdk_bdev_read_blocks
11054bd97621SJim Harris 	 */
11064bd97621SJim Harris 	g_io_done = false;
11073c7894ffSShuhei Matsumoto 	expected_io = ut_alloc_expected_io(SPDK_BDEV_IO_TYPE_READ, 14, 2, 1);
11083c7894ffSShuhei Matsumoto 	ut_expected_io_set_iov(expected_io, 0, (void *)0xF000, 2 * 512);
11093c7894ffSShuhei Matsumoto 	TAILQ_INSERT_TAIL(&g_bdev_ut_channel->expected_io, expected_io, link);
11104bd97621SJim Harris 
11113c7894ffSShuhei Matsumoto 	expected_io = ut_alloc_expected_io(SPDK_BDEV_IO_TYPE_READ, 16, 6, 1);
11123c7894ffSShuhei Matsumoto 	ut_expected_io_set_iov(expected_io, 0, (void *)(0xF000 + 2 * 512), 6 * 512);
11133c7894ffSShuhei Matsumoto 	TAILQ_INSERT_TAIL(&g_bdev_ut_channel->expected_io, expected_io, link);
11144bd97621SJim Harris 
11158f33ef24SShuhei Matsumoto 	/* spdk_bdev_read_blocks will submit the first child immediately. */
11168f33ef24SShuhei Matsumoto 	rc = spdk_bdev_read_blocks(desc, io_ch, (void *)0xF000, 14, 8, io_done, NULL);
11178f33ef24SShuhei Matsumoto 	CU_ASSERT(rc == 0);
11188f33ef24SShuhei Matsumoto 	CU_ASSERT(g_io_done == false);
11198f33ef24SShuhei Matsumoto 
11205616c1edSShuhei Matsumoto 	CU_ASSERT(g_bdev_ut_channel->outstanding_io_count == 2);
11215616c1edSShuhei Matsumoto 	stub_complete_io(2);
11224bd97621SJim Harris 	CU_ASSERT(g_io_done == true);
11235616c1edSShuhei Matsumoto 	CU_ASSERT(g_bdev_ut_channel->outstanding_io_count == 0);
11244bd97621SJim Harris 
11254bd97621SJim Harris 	/* Now set up a more complex, multi-vector command that needs to be split,
11264bd97621SJim Harris 	 *  including splitting iovecs.
11274bd97621SJim Harris 	 */
11284bd97621SJim Harris 	iov[0].iov_base = (void *)0x10000;
11294bd97621SJim Harris 	iov[0].iov_len = 512;
11304bd97621SJim Harris 	iov[1].iov_base = (void *)0x20000;
11314bd97621SJim Harris 	iov[1].iov_len = 20 * 512;
11324bd97621SJim Harris 	iov[2].iov_base = (void *)0x30000;
11334bd97621SJim Harris 	iov[2].iov_len = 11 * 512;
11344bd97621SJim Harris 
11354bd97621SJim Harris 	g_io_done = false;
11363c7894ffSShuhei Matsumoto 	expected_io = ut_alloc_expected_io(SPDK_BDEV_IO_TYPE_WRITE, 14, 2, 2);
11373c7894ffSShuhei Matsumoto 	ut_expected_io_set_iov(expected_io, 0, (void *)0x10000, 512);
11383c7894ffSShuhei Matsumoto 	ut_expected_io_set_iov(expected_io, 1, (void *)0x20000, 512);
11393c7894ffSShuhei Matsumoto 	TAILQ_INSERT_TAIL(&g_bdev_ut_channel->expected_io, expected_io, link);
11404bd97621SJim Harris 
11413c7894ffSShuhei Matsumoto 	expected_io = ut_alloc_expected_io(SPDK_BDEV_IO_TYPE_WRITE, 16, 16, 1);
11423c7894ffSShuhei Matsumoto 	ut_expected_io_set_iov(expected_io, 0, (void *)(0x20000 + 512), 16 * 512);
11433c7894ffSShuhei Matsumoto 	TAILQ_INSERT_TAIL(&g_bdev_ut_channel->expected_io, expected_io, link);
11444bd97621SJim Harris 
11453c7894ffSShuhei Matsumoto 	expected_io = ut_alloc_expected_io(SPDK_BDEV_IO_TYPE_WRITE, 32, 14, 2);
11463c7894ffSShuhei Matsumoto 	ut_expected_io_set_iov(expected_io, 0, (void *)(0x20000 + 17 * 512), 3 * 512);
11473c7894ffSShuhei Matsumoto 	ut_expected_io_set_iov(expected_io, 1, (void *)0x30000, 11 * 512);
11483c7894ffSShuhei Matsumoto 	TAILQ_INSERT_TAIL(&g_bdev_ut_channel->expected_io, expected_io, link);
11494bd97621SJim Harris 
11508f33ef24SShuhei Matsumoto 	rc = spdk_bdev_writev_blocks(desc, io_ch, iov, 3, 14, 32, io_done, NULL);
11518f33ef24SShuhei Matsumoto 	CU_ASSERT(rc == 0);
11528f33ef24SShuhei Matsumoto 	CU_ASSERT(g_io_done == false);
11538f33ef24SShuhei Matsumoto 
11545616c1edSShuhei Matsumoto 	CU_ASSERT(g_bdev_ut_channel->outstanding_io_count == 3);
11555616c1edSShuhei Matsumoto 	stub_complete_io(3);
11564bd97621SJim Harris 	CU_ASSERT(g_io_done == true);
11574bd97621SJim Harris 
11580df515a8SShuhei Matsumoto 	/* Test multi vector command that needs to be split by strip and then needs to be
11590df515a8SShuhei Matsumoto 	 * split further due to the capacity of child iovs.
11600df515a8SShuhei Matsumoto 	 */
11610df515a8SShuhei Matsumoto 	for (i = 0; i < BDEV_IO_NUM_CHILD_IOV * 2; i++) {
11620df515a8SShuhei Matsumoto 		iov[i].iov_base = (void *)((i + 1) * 0x10000);
11630df515a8SShuhei Matsumoto 		iov[i].iov_len = 512;
11640df515a8SShuhei Matsumoto 	}
11650df515a8SShuhei Matsumoto 
11660df515a8SShuhei Matsumoto 	bdev->optimal_io_boundary = BDEV_IO_NUM_CHILD_IOV;
11670df515a8SShuhei Matsumoto 	g_io_done = false;
11683c7894ffSShuhei Matsumoto 	expected_io = ut_alloc_expected_io(SPDK_BDEV_IO_TYPE_READ, 0, BDEV_IO_NUM_CHILD_IOV,
11693c7894ffSShuhei Matsumoto 					   BDEV_IO_NUM_CHILD_IOV);
11700df515a8SShuhei Matsumoto 	for (i = 0; i < BDEV_IO_NUM_CHILD_IOV; i++) {
11713c7894ffSShuhei Matsumoto 		ut_expected_io_set_iov(expected_io, i, (void *)((i + 1) * 0x10000), 512);
11720df515a8SShuhei Matsumoto 	}
11733c7894ffSShuhei Matsumoto 	TAILQ_INSERT_TAIL(&g_bdev_ut_channel->expected_io, expected_io, link);
11740df515a8SShuhei Matsumoto 
11753c7894ffSShuhei Matsumoto 	expected_io = ut_alloc_expected_io(SPDK_BDEV_IO_TYPE_READ, BDEV_IO_NUM_CHILD_IOV,
11763c7894ffSShuhei Matsumoto 					   BDEV_IO_NUM_CHILD_IOV, BDEV_IO_NUM_CHILD_IOV);
11770df515a8SShuhei Matsumoto 	for (i = 0; i < BDEV_IO_NUM_CHILD_IOV; i++) {
11783c7894ffSShuhei Matsumoto 		ut_expected_io_set_iov(expected_io, i,
11793c7894ffSShuhei Matsumoto 				       (void *)((i + 1 + BDEV_IO_NUM_CHILD_IOV) * 0x10000), 512);
11800df515a8SShuhei Matsumoto 	}
11813c7894ffSShuhei Matsumoto 	TAILQ_INSERT_TAIL(&g_bdev_ut_channel->expected_io, expected_io, link);
11820df515a8SShuhei Matsumoto 
11838f33ef24SShuhei Matsumoto 	rc = spdk_bdev_readv_blocks(desc, io_ch, iov, BDEV_IO_NUM_CHILD_IOV * 2, 0,
11848f33ef24SShuhei Matsumoto 				    BDEV_IO_NUM_CHILD_IOV * 2, io_done, NULL);
11858f33ef24SShuhei Matsumoto 	CU_ASSERT(rc == 0);
11868f33ef24SShuhei Matsumoto 	CU_ASSERT(g_io_done == false);
11878f33ef24SShuhei Matsumoto 
11880df515a8SShuhei Matsumoto 	CU_ASSERT(g_bdev_ut_channel->outstanding_io_count == 1);
11890df515a8SShuhei Matsumoto 	stub_complete_io(1);
11900df515a8SShuhei Matsumoto 	CU_ASSERT(g_io_done == false);
11910df515a8SShuhei Matsumoto 
11920df515a8SShuhei Matsumoto 	CU_ASSERT(g_bdev_ut_channel->outstanding_io_count == 1);
11930df515a8SShuhei Matsumoto 	stub_complete_io(1);
11940df515a8SShuhei Matsumoto 	CU_ASSERT(g_io_done == true);
11955616c1edSShuhei Matsumoto 	CU_ASSERT(g_bdev_ut_channel->outstanding_io_count == 0);
11960df515a8SShuhei Matsumoto 
11970df515a8SShuhei Matsumoto 	/* Test multi vector command that needs to be split by strip and then needs to be
1198598ba408Slorneli 	 * split further due to the capacity of child iovs. In this case, the length of
1199598ba408Slorneli 	 * the rest of iovec array with an I/O boundary is the multiple of block size.
1200598ba408Slorneli 	 */
1201598ba408Slorneli 
1202598ba408Slorneli 	/* Fill iovec array for exactly one boundary. The iovec cnt for this boundary
1203598ba408Slorneli 	 * is BDEV_IO_NUM_CHILD_IOV + 1, which exceeds the capacity of child iovs.
1204598ba408Slorneli 	 */
1205598ba408Slorneli 	for (i = 0; i < BDEV_IO_NUM_CHILD_IOV - 2; i++) {
1206598ba408Slorneli 		iov[i].iov_base = (void *)((i + 1) * 0x10000);
1207598ba408Slorneli 		iov[i].iov_len = 512;
1208598ba408Slorneli 	}
1209598ba408Slorneli 	for (i = BDEV_IO_NUM_CHILD_IOV - 2; i < BDEV_IO_NUM_CHILD_IOV; i++) {
1210598ba408Slorneli 		iov[i].iov_base = (void *)((i + 1) * 0x10000);
1211598ba408Slorneli 		iov[i].iov_len = 256;
1212598ba408Slorneli 	}
1213598ba408Slorneli 	iov[BDEV_IO_NUM_CHILD_IOV].iov_base = (void *)((BDEV_IO_NUM_CHILD_IOV + 1) * 0x10000);
1214598ba408Slorneli 	iov[BDEV_IO_NUM_CHILD_IOV].iov_len = 512;
1215598ba408Slorneli 
1216598ba408Slorneli 	/* Add an extra iovec to trigger split */
1217598ba408Slorneli 	iov[BDEV_IO_NUM_CHILD_IOV + 1].iov_base = (void *)((BDEV_IO_NUM_CHILD_IOV + 2) * 0x10000);
1218598ba408Slorneli 	iov[BDEV_IO_NUM_CHILD_IOV + 1].iov_len = 512;
1219598ba408Slorneli 
1220598ba408Slorneli 	bdev->optimal_io_boundary = BDEV_IO_NUM_CHILD_IOV;
1221598ba408Slorneli 	g_io_done = false;
1222598ba408Slorneli 	expected_io = ut_alloc_expected_io(SPDK_BDEV_IO_TYPE_READ, 0,
1223598ba408Slorneli 					   BDEV_IO_NUM_CHILD_IOV - 1, BDEV_IO_NUM_CHILD_IOV);
1224598ba408Slorneli 	for (i = 0; i < BDEV_IO_NUM_CHILD_IOV - 2; i++) {
1225598ba408Slorneli 		ut_expected_io_set_iov(expected_io, i,
1226598ba408Slorneli 				       (void *)((i + 1) * 0x10000), 512);
1227598ba408Slorneli 	}
1228598ba408Slorneli 	for (i = BDEV_IO_NUM_CHILD_IOV - 2; i < BDEV_IO_NUM_CHILD_IOV; i++) {
1229598ba408Slorneli 		ut_expected_io_set_iov(expected_io, i,
1230598ba408Slorneli 				       (void *)((i + 1) * 0x10000), 256);
1231598ba408Slorneli 	}
1232598ba408Slorneli 	TAILQ_INSERT_TAIL(&g_bdev_ut_channel->expected_io, expected_io, link);
1233598ba408Slorneli 
1234598ba408Slorneli 	expected_io = ut_alloc_expected_io(SPDK_BDEV_IO_TYPE_READ, BDEV_IO_NUM_CHILD_IOV - 1,
1235598ba408Slorneli 					   1, 1);
1236598ba408Slorneli 	ut_expected_io_set_iov(expected_io, 0,
1237598ba408Slorneli 			       (void *)((BDEV_IO_NUM_CHILD_IOV + 1) * 0x10000), 512);
1238598ba408Slorneli 	TAILQ_INSERT_TAIL(&g_bdev_ut_channel->expected_io, expected_io, link);
1239598ba408Slorneli 
1240598ba408Slorneli 	expected_io = ut_alloc_expected_io(SPDK_BDEV_IO_TYPE_READ, BDEV_IO_NUM_CHILD_IOV,
1241598ba408Slorneli 					   1, 1);
1242598ba408Slorneli 	ut_expected_io_set_iov(expected_io, 0,
1243598ba408Slorneli 			       (void *)((BDEV_IO_NUM_CHILD_IOV + 2) * 0x10000), 512);
1244598ba408Slorneli 	TAILQ_INSERT_TAIL(&g_bdev_ut_channel->expected_io, expected_io, link);
1245598ba408Slorneli 
1246598ba408Slorneli 	rc = spdk_bdev_readv_blocks(desc, io_ch, iov, BDEV_IO_NUM_CHILD_IOV + 2, 0,
1247598ba408Slorneli 				    BDEV_IO_NUM_CHILD_IOV + 1, io_done, NULL);
1248598ba408Slorneli 	CU_ASSERT(rc == 0);
1249598ba408Slorneli 	CU_ASSERT(g_io_done == false);
1250598ba408Slorneli 
1251598ba408Slorneli 	CU_ASSERT(g_bdev_ut_channel->outstanding_io_count == 1);
1252598ba408Slorneli 	stub_complete_io(1);
1253598ba408Slorneli 	CU_ASSERT(g_io_done == false);
1254598ba408Slorneli 
1255598ba408Slorneli 	CU_ASSERT(g_bdev_ut_channel->outstanding_io_count == 2);
1256598ba408Slorneli 	stub_complete_io(2);
1257598ba408Slorneli 	CU_ASSERT(g_io_done == true);
1258598ba408Slorneli 	CU_ASSERT(g_bdev_ut_channel->outstanding_io_count == 0);
1259598ba408Slorneli 
1260598ba408Slorneli 	/* Test multi vector command that needs to be split by strip and then needs to be
1261efd7b514SChangpeng Liu 	 * split further due to the capacity of child iovs, the child request offset should
1262efd7b514SChangpeng Liu 	 * be rewind to last aligned offset and go success without error.
12630df515a8SShuhei Matsumoto 	 */
12640df515a8SShuhei Matsumoto 	for (i = 0; i < BDEV_IO_NUM_CHILD_IOV - 1; i++) {
12650df515a8SShuhei Matsumoto 		iov[i].iov_base = (void *)((i + 1) * 0x10000);
12660df515a8SShuhei Matsumoto 		iov[i].iov_len = 512;
12670df515a8SShuhei Matsumoto 	}
12680df515a8SShuhei Matsumoto 	iov[BDEV_IO_NUM_CHILD_IOV - 1].iov_base = (void *)(BDEV_IO_NUM_CHILD_IOV * 0x10000);
12690df515a8SShuhei Matsumoto 	iov[BDEV_IO_NUM_CHILD_IOV - 1].iov_len = 256;
12700df515a8SShuhei Matsumoto 
1271efd7b514SChangpeng Liu 	iov[BDEV_IO_NUM_CHILD_IOV].iov_base = (void *)((BDEV_IO_NUM_CHILD_IOV + 1) * 0x10000);
1272efd7b514SChangpeng Liu 	iov[BDEV_IO_NUM_CHILD_IOV].iov_len = 256;
1273efd7b514SChangpeng Liu 
1274efd7b514SChangpeng Liu 	iov[BDEV_IO_NUM_CHILD_IOV + 1].iov_base = (void *)((BDEV_IO_NUM_CHILD_IOV + 2) * 0x10000);
1275efd7b514SChangpeng Liu 	iov[BDEV_IO_NUM_CHILD_IOV + 1].iov_len = 512;
1276efd7b514SChangpeng Liu 
12770df515a8SShuhei Matsumoto 	bdev->optimal_io_boundary = BDEV_IO_NUM_CHILD_IOV;
12780df515a8SShuhei Matsumoto 	g_io_done = false;
12790df515a8SShuhei Matsumoto 	g_io_status = 0;
1280efd7b514SChangpeng Liu 	/* The first expected io should be start from offset 0 to BDEV_IO_NUM_CHILD_IOV - 1 */
1281efd7b514SChangpeng Liu 	expected_io = ut_alloc_expected_io(SPDK_BDEV_IO_TYPE_READ, 0,
1282efd7b514SChangpeng Liu 					   BDEV_IO_NUM_CHILD_IOV - 1, BDEV_IO_NUM_CHILD_IOV - 1);
1283efd7b514SChangpeng Liu 	for (i = 0; i < BDEV_IO_NUM_CHILD_IOV - 1; i++) {
1284efd7b514SChangpeng Liu 		ut_expected_io_set_iov(expected_io, i,
1285efd7b514SChangpeng Liu 				       (void *)((i + 1) * 0x10000), 512);
1286efd7b514SChangpeng Liu 	}
1287efd7b514SChangpeng Liu 	TAILQ_INSERT_TAIL(&g_bdev_ut_channel->expected_io, expected_io, link);
1288efd7b514SChangpeng Liu 	/* The second expected io should be start from offset BDEV_IO_NUM_CHILD_IOV - 1 to BDEV_IO_NUM_CHILD_IOV */
1289efd7b514SChangpeng Liu 	expected_io = ut_alloc_expected_io(SPDK_BDEV_IO_TYPE_READ, BDEV_IO_NUM_CHILD_IOV - 1,
1290efd7b514SChangpeng Liu 					   1, 2);
1291efd7b514SChangpeng Liu 	ut_expected_io_set_iov(expected_io, 0,
1292efd7b514SChangpeng Liu 			       (void *)(BDEV_IO_NUM_CHILD_IOV * 0x10000), 256);
1293efd7b514SChangpeng Liu 	ut_expected_io_set_iov(expected_io, 1,
1294efd7b514SChangpeng Liu 			       (void *)((BDEV_IO_NUM_CHILD_IOV + 1) * 0x10000), 256);
1295efd7b514SChangpeng Liu 	TAILQ_INSERT_TAIL(&g_bdev_ut_channel->expected_io, expected_io, link);
1296efd7b514SChangpeng Liu 	/* The third expected io should be start from offset BDEV_IO_NUM_CHILD_IOV to BDEV_IO_NUM_CHILD_IOV + 1 */
1297efd7b514SChangpeng Liu 	expected_io = ut_alloc_expected_io(SPDK_BDEV_IO_TYPE_READ, BDEV_IO_NUM_CHILD_IOV,
1298efd7b514SChangpeng Liu 					   1, 1);
1299efd7b514SChangpeng Liu 	ut_expected_io_set_iov(expected_io, 0,
1300efd7b514SChangpeng Liu 			       (void *)((BDEV_IO_NUM_CHILD_IOV + 2) * 0x10000), 512);
1301efd7b514SChangpeng Liu 	TAILQ_INSERT_TAIL(&g_bdev_ut_channel->expected_io, expected_io, link);
13020df515a8SShuhei Matsumoto 
13030df515a8SShuhei Matsumoto 	rc = spdk_bdev_readv_blocks(desc, io_ch, iov, BDEV_IO_NUM_CHILD_IOV * 2, 0,
1304efd7b514SChangpeng Liu 				    BDEV_IO_NUM_CHILD_IOV + 1, io_done, NULL);
13050df515a8SShuhei Matsumoto 	CU_ASSERT(rc == 0);
1306efd7b514SChangpeng Liu 	CU_ASSERT(g_io_done == false);
1307efd7b514SChangpeng Liu 
1308efd7b514SChangpeng Liu 	CU_ASSERT(g_bdev_ut_channel->outstanding_io_count == 1);
1309efd7b514SChangpeng Liu 	stub_complete_io(1);
1310efd7b514SChangpeng Liu 	CU_ASSERT(g_io_done == false);
1311efd7b514SChangpeng Liu 
1312efd7b514SChangpeng Liu 	CU_ASSERT(g_bdev_ut_channel->outstanding_io_count == 2);
1313efd7b514SChangpeng Liu 	stub_complete_io(2);
13140df515a8SShuhei Matsumoto 	CU_ASSERT(g_io_done == true);
1315efd7b514SChangpeng Liu 	CU_ASSERT(g_bdev_ut_channel->outstanding_io_count == 0);
13160df515a8SShuhei Matsumoto 
13173deaf005SShuhei Matsumoto 	/* Test multi vector command that needs to be split due to the IO boundary and
13183deaf005SShuhei Matsumoto 	 * the capacity of child iovs. Especially test the case when the command is
13193deaf005SShuhei Matsumoto 	 * split due to the capacity of child iovs, the tail address is not aligned with
13203deaf005SShuhei Matsumoto 	 * block size and is rewinded to the aligned address.
13213deaf005SShuhei Matsumoto 	 *
13223deaf005SShuhei Matsumoto 	 * The iovecs used in read request is complex but is based on the data
13233deaf005SShuhei Matsumoto 	 * collected in the real issue. We change the base addresses but keep the lengths
13243deaf005SShuhei Matsumoto 	 * not to loose the credibility of the test.
13253deaf005SShuhei Matsumoto 	 */
13263deaf005SShuhei Matsumoto 	bdev->optimal_io_boundary = 128;
13273deaf005SShuhei Matsumoto 	g_io_done = false;
13283deaf005SShuhei Matsumoto 	g_io_status = 0;
13293deaf005SShuhei Matsumoto 
13303deaf005SShuhei Matsumoto 	for (i = 0; i < 31; i++) {
13313deaf005SShuhei Matsumoto 		iov[i].iov_base = (void *)(0xFEED0000000 + (i << 20));
13323deaf005SShuhei Matsumoto 		iov[i].iov_len = 1024;
13333deaf005SShuhei Matsumoto 	}
13343deaf005SShuhei Matsumoto 	iov[31].iov_base = (void *)0xFEED1F00000;
13353deaf005SShuhei Matsumoto 	iov[31].iov_len = 32768;
13363deaf005SShuhei Matsumoto 	iov[32].iov_base = (void *)0xFEED2000000;
13373deaf005SShuhei Matsumoto 	iov[32].iov_len = 160;
13383deaf005SShuhei Matsumoto 	iov[33].iov_base = (void *)0xFEED2100000;
13393deaf005SShuhei Matsumoto 	iov[33].iov_len = 4096;
13403deaf005SShuhei Matsumoto 	iov[34].iov_base = (void *)0xFEED2200000;
13413deaf005SShuhei Matsumoto 	iov[34].iov_len = 4096;
13423deaf005SShuhei Matsumoto 	iov[35].iov_base = (void *)0xFEED2300000;
13433deaf005SShuhei Matsumoto 	iov[35].iov_len = 4096;
13443deaf005SShuhei Matsumoto 	iov[36].iov_base = (void *)0xFEED2400000;
13453deaf005SShuhei Matsumoto 	iov[36].iov_len = 4096;
13463deaf005SShuhei Matsumoto 	iov[37].iov_base = (void *)0xFEED2500000;
13473deaf005SShuhei Matsumoto 	iov[37].iov_len = 4096;
13483deaf005SShuhei Matsumoto 	iov[38].iov_base = (void *)0xFEED2600000;
13493deaf005SShuhei Matsumoto 	iov[38].iov_len = 4096;
13503deaf005SShuhei Matsumoto 	iov[39].iov_base = (void *)0xFEED2700000;
13513deaf005SShuhei Matsumoto 	iov[39].iov_len = 4096;
13523deaf005SShuhei Matsumoto 	iov[40].iov_base = (void *)0xFEED2800000;
13533deaf005SShuhei Matsumoto 	iov[40].iov_len = 4096;
13543deaf005SShuhei Matsumoto 	iov[41].iov_base = (void *)0xFEED2900000;
13553deaf005SShuhei Matsumoto 	iov[41].iov_len = 4096;
13563deaf005SShuhei Matsumoto 	iov[42].iov_base = (void *)0xFEED2A00000;
13573deaf005SShuhei Matsumoto 	iov[42].iov_len = 4096;
13583deaf005SShuhei Matsumoto 	iov[43].iov_base = (void *)0xFEED2B00000;
13593deaf005SShuhei Matsumoto 	iov[43].iov_len = 12288;
13603deaf005SShuhei Matsumoto 	iov[44].iov_base = (void *)0xFEED2C00000;
13613deaf005SShuhei Matsumoto 	iov[44].iov_len = 8192;
13623deaf005SShuhei Matsumoto 	iov[45].iov_base = (void *)0xFEED2F00000;
13633deaf005SShuhei Matsumoto 	iov[45].iov_len = 4096;
13643deaf005SShuhei Matsumoto 	iov[46].iov_base = (void *)0xFEED3000000;
13653deaf005SShuhei Matsumoto 	iov[46].iov_len = 4096;
13663deaf005SShuhei Matsumoto 	iov[47].iov_base = (void *)0xFEED3100000;
13673deaf005SShuhei Matsumoto 	iov[47].iov_len = 4096;
13683deaf005SShuhei Matsumoto 	iov[48].iov_base = (void *)0xFEED3200000;
13693deaf005SShuhei Matsumoto 	iov[48].iov_len = 24576;
13703deaf005SShuhei Matsumoto 	iov[49].iov_base = (void *)0xFEED3300000;
13713deaf005SShuhei Matsumoto 	iov[49].iov_len = 16384;
13723deaf005SShuhei Matsumoto 	iov[50].iov_base = (void *)0xFEED3400000;
13733deaf005SShuhei Matsumoto 	iov[50].iov_len = 12288;
13743deaf005SShuhei Matsumoto 	iov[51].iov_base = (void *)0xFEED3500000;
13753deaf005SShuhei Matsumoto 	iov[51].iov_len = 4096;
13763deaf005SShuhei Matsumoto 	iov[52].iov_base = (void *)0xFEED3600000;
13773deaf005SShuhei Matsumoto 	iov[52].iov_len = 4096;
13783deaf005SShuhei Matsumoto 	iov[53].iov_base = (void *)0xFEED3700000;
13793deaf005SShuhei Matsumoto 	iov[53].iov_len = 4096;
13803deaf005SShuhei Matsumoto 	iov[54].iov_base = (void *)0xFEED3800000;
13813deaf005SShuhei Matsumoto 	iov[54].iov_len = 28672;
13823deaf005SShuhei Matsumoto 	iov[55].iov_base = (void *)0xFEED3900000;
13833deaf005SShuhei Matsumoto 	iov[55].iov_len = 20480;
13843deaf005SShuhei Matsumoto 	iov[56].iov_base = (void *)0xFEED3A00000;
13853deaf005SShuhei Matsumoto 	iov[56].iov_len = 4096;
13863deaf005SShuhei Matsumoto 	iov[57].iov_base = (void *)0xFEED3B00000;
13873deaf005SShuhei Matsumoto 	iov[57].iov_len = 12288;
13883deaf005SShuhei Matsumoto 	iov[58].iov_base = (void *)0xFEED3C00000;
13893deaf005SShuhei Matsumoto 	iov[58].iov_len = 4096;
13903deaf005SShuhei Matsumoto 	iov[59].iov_base = (void *)0xFEED3D00000;
13913deaf005SShuhei Matsumoto 	iov[59].iov_len = 4096;
13923deaf005SShuhei Matsumoto 	iov[60].iov_base = (void *)0xFEED3E00000;
13933deaf005SShuhei Matsumoto 	iov[60].iov_len = 352;
13943deaf005SShuhei Matsumoto 
13953deaf005SShuhei Matsumoto 	/* The 1st child IO must be from iov[0] to iov[31] split by the capacity
13963deaf005SShuhei Matsumoto 	 * of child iovs,
13973deaf005SShuhei Matsumoto 	 */
13983deaf005SShuhei Matsumoto 	expected_io = ut_alloc_expected_io(SPDK_BDEV_IO_TYPE_READ, 0, 126, 32);
13993deaf005SShuhei Matsumoto 	for (i = 0; i < 32; i++) {
14003deaf005SShuhei Matsumoto 		ut_expected_io_set_iov(expected_io, i, iov[i].iov_base, iov[i].iov_len);
14013deaf005SShuhei Matsumoto 	}
14023deaf005SShuhei Matsumoto 	TAILQ_INSERT_TAIL(&g_bdev_ut_channel->expected_io, expected_io, link);
14033deaf005SShuhei Matsumoto 
14043deaf005SShuhei Matsumoto 	/* The 2nd child IO must be from iov[32] to the first 864 bytes of iov[33]
14053deaf005SShuhei Matsumoto 	 * split by the IO boundary requirement.
14063deaf005SShuhei Matsumoto 	 */
14073deaf005SShuhei Matsumoto 	expected_io = ut_alloc_expected_io(SPDK_BDEV_IO_TYPE_READ, 126, 2, 2);
14083deaf005SShuhei Matsumoto 	ut_expected_io_set_iov(expected_io, 0, iov[32].iov_base, iov[32].iov_len);
14093deaf005SShuhei Matsumoto 	ut_expected_io_set_iov(expected_io, 1, iov[33].iov_base, 864);
14103deaf005SShuhei Matsumoto 	TAILQ_INSERT_TAIL(&g_bdev_ut_channel->expected_io, expected_io, link);
14113deaf005SShuhei Matsumoto 
14123deaf005SShuhei Matsumoto 	/* The 3rd child IO must be from the remaining 3232 bytes of iov[33] to
14133deaf005SShuhei Matsumoto 	 * the first 864 bytes of iov[46] split by the IO boundary requirement.
14143deaf005SShuhei Matsumoto 	 */
14153deaf005SShuhei Matsumoto 	expected_io = ut_alloc_expected_io(SPDK_BDEV_IO_TYPE_READ, 128, 128, 14);
14163deaf005SShuhei Matsumoto 	ut_expected_io_set_iov(expected_io, 0, (void *)((uintptr_t)iov[33].iov_base + 864),
14173deaf005SShuhei Matsumoto 			       iov[33].iov_len - 864);
14183deaf005SShuhei Matsumoto 	ut_expected_io_set_iov(expected_io, 1, iov[34].iov_base, iov[34].iov_len);
14193deaf005SShuhei Matsumoto 	ut_expected_io_set_iov(expected_io, 2, iov[35].iov_base, iov[35].iov_len);
14203deaf005SShuhei Matsumoto 	ut_expected_io_set_iov(expected_io, 3, iov[36].iov_base, iov[36].iov_len);
14213deaf005SShuhei Matsumoto 	ut_expected_io_set_iov(expected_io, 4, iov[37].iov_base, iov[37].iov_len);
14223deaf005SShuhei Matsumoto 	ut_expected_io_set_iov(expected_io, 5, iov[38].iov_base, iov[38].iov_len);
14233deaf005SShuhei Matsumoto 	ut_expected_io_set_iov(expected_io, 6, iov[39].iov_base, iov[39].iov_len);
14243deaf005SShuhei Matsumoto 	ut_expected_io_set_iov(expected_io, 7, iov[40].iov_base, iov[40].iov_len);
14253deaf005SShuhei Matsumoto 	ut_expected_io_set_iov(expected_io, 8, iov[41].iov_base, iov[41].iov_len);
14263deaf005SShuhei Matsumoto 	ut_expected_io_set_iov(expected_io, 9, iov[42].iov_base, iov[42].iov_len);
14273deaf005SShuhei Matsumoto 	ut_expected_io_set_iov(expected_io, 10, iov[43].iov_base, iov[43].iov_len);
14283deaf005SShuhei Matsumoto 	ut_expected_io_set_iov(expected_io, 11, iov[44].iov_base, iov[44].iov_len);
14293deaf005SShuhei Matsumoto 	ut_expected_io_set_iov(expected_io, 12, iov[45].iov_base, iov[45].iov_len);
14303deaf005SShuhei Matsumoto 	ut_expected_io_set_iov(expected_io, 13, iov[46].iov_base, 864);
14313deaf005SShuhei Matsumoto 	TAILQ_INSERT_TAIL(&g_bdev_ut_channel->expected_io, expected_io, link);
14323deaf005SShuhei Matsumoto 
14333deaf005SShuhei Matsumoto 	/* The 4th child IO must be from the remaining 3232 bytes of iov[46] to the
14343deaf005SShuhei Matsumoto 	 * first 864 bytes of iov[52] split by the IO boundary requirement.
14353deaf005SShuhei Matsumoto 	 */
14363deaf005SShuhei Matsumoto 	expected_io = ut_alloc_expected_io(SPDK_BDEV_IO_TYPE_READ, 256, 128, 7);
14373deaf005SShuhei Matsumoto 	ut_expected_io_set_iov(expected_io, 0, (void *)((uintptr_t)iov[46].iov_base + 864),
14383deaf005SShuhei Matsumoto 			       iov[46].iov_len - 864);
14393deaf005SShuhei Matsumoto 	ut_expected_io_set_iov(expected_io, 1, iov[47].iov_base, iov[47].iov_len);
14403deaf005SShuhei Matsumoto 	ut_expected_io_set_iov(expected_io, 2, iov[48].iov_base, iov[48].iov_len);
14413deaf005SShuhei Matsumoto 	ut_expected_io_set_iov(expected_io, 3, iov[49].iov_base, iov[49].iov_len);
14423deaf005SShuhei Matsumoto 	ut_expected_io_set_iov(expected_io, 4, iov[50].iov_base, iov[50].iov_len);
14433deaf005SShuhei Matsumoto 	ut_expected_io_set_iov(expected_io, 5, iov[51].iov_base, iov[51].iov_len);
14443deaf005SShuhei Matsumoto 	ut_expected_io_set_iov(expected_io, 6, iov[52].iov_base, 864);
14453deaf005SShuhei Matsumoto 	TAILQ_INSERT_TAIL(&g_bdev_ut_channel->expected_io, expected_io, link);
14463deaf005SShuhei Matsumoto 
14473deaf005SShuhei Matsumoto 	/* The 5th child IO must be from the remaining 3232 bytes of iov[52] to
14483deaf005SShuhei Matsumoto 	 * the first 4096 bytes of iov[57] split by the IO boundary requirement.
14493deaf005SShuhei Matsumoto 	 */
14503deaf005SShuhei Matsumoto 	expected_io = ut_alloc_expected_io(SPDK_BDEV_IO_TYPE_READ, 384, 128, 6);
14513deaf005SShuhei Matsumoto 	ut_expected_io_set_iov(expected_io, 0, (void *)((uintptr_t)iov[52].iov_base + 864),
14523deaf005SShuhei Matsumoto 			       iov[52].iov_len - 864);
14533deaf005SShuhei Matsumoto 	ut_expected_io_set_iov(expected_io, 1, iov[53].iov_base, iov[53].iov_len);
14543deaf005SShuhei Matsumoto 	ut_expected_io_set_iov(expected_io, 2, iov[54].iov_base, iov[54].iov_len);
14553deaf005SShuhei Matsumoto 	ut_expected_io_set_iov(expected_io, 3, iov[55].iov_base, iov[55].iov_len);
14563deaf005SShuhei Matsumoto 	ut_expected_io_set_iov(expected_io, 4, iov[56].iov_base, iov[56].iov_len);
14573deaf005SShuhei Matsumoto 	ut_expected_io_set_iov(expected_io, 5, iov[57].iov_base, 4960);
14583deaf005SShuhei Matsumoto 	TAILQ_INSERT_TAIL(&g_bdev_ut_channel->expected_io, expected_io, link);
14593deaf005SShuhei Matsumoto 
14603deaf005SShuhei Matsumoto 	/* The 6th child IO must be from the remaining 7328 bytes of iov[57]
14613deaf005SShuhei Matsumoto 	 * to the first 3936 bytes of iov[58] split by the capacity of child iovs.
14623deaf005SShuhei Matsumoto 	 */
14633deaf005SShuhei Matsumoto 	expected_io = ut_alloc_expected_io(SPDK_BDEV_IO_TYPE_READ, 512, 30, 3);
14643deaf005SShuhei Matsumoto 	ut_expected_io_set_iov(expected_io, 0, (void *)((uintptr_t)iov[57].iov_base + 4960),
14653deaf005SShuhei Matsumoto 			       iov[57].iov_len - 4960);
14663deaf005SShuhei Matsumoto 	ut_expected_io_set_iov(expected_io, 1, iov[58].iov_base, iov[58].iov_len);
14673deaf005SShuhei Matsumoto 	ut_expected_io_set_iov(expected_io, 2, iov[59].iov_base, 3936);
14683deaf005SShuhei Matsumoto 	TAILQ_INSERT_TAIL(&g_bdev_ut_channel->expected_io, expected_io, link);
14693deaf005SShuhei Matsumoto 
14703deaf005SShuhei Matsumoto 	/* The 7th child IO is from the remaining 160 bytes of iov[59] and iov[60]. */
14713deaf005SShuhei Matsumoto 	expected_io = ut_alloc_expected_io(SPDK_BDEV_IO_TYPE_READ, 542, 1, 2);
14723deaf005SShuhei Matsumoto 	ut_expected_io_set_iov(expected_io, 0, (void *)((uintptr_t)iov[59].iov_base + 3936),
14733deaf005SShuhei Matsumoto 			       iov[59].iov_len - 3936);
14743deaf005SShuhei Matsumoto 	ut_expected_io_set_iov(expected_io, 1, iov[60].iov_base, iov[60].iov_len);
14753deaf005SShuhei Matsumoto 	TAILQ_INSERT_TAIL(&g_bdev_ut_channel->expected_io, expected_io, link);
14763deaf005SShuhei Matsumoto 
14773deaf005SShuhei Matsumoto 	rc = spdk_bdev_readv_blocks(desc, io_ch, iov, 61, 0, 543, io_done, NULL);
14783deaf005SShuhei Matsumoto 	CU_ASSERT(rc == 0);
14793deaf005SShuhei Matsumoto 	CU_ASSERT(g_io_done == false);
14803deaf005SShuhei Matsumoto 
14813deaf005SShuhei Matsumoto 	CU_ASSERT(g_bdev_ut_channel->outstanding_io_count == 1);
14823deaf005SShuhei Matsumoto 	stub_complete_io(1);
14833deaf005SShuhei Matsumoto 	CU_ASSERT(g_io_done == false);
14843deaf005SShuhei Matsumoto 
14853deaf005SShuhei Matsumoto 	CU_ASSERT(g_bdev_ut_channel->outstanding_io_count == 5);
14863deaf005SShuhei Matsumoto 	stub_complete_io(5);
14873deaf005SShuhei Matsumoto 	CU_ASSERT(g_io_done == false);
14883deaf005SShuhei Matsumoto 
14893deaf005SShuhei Matsumoto 	CU_ASSERT(g_bdev_ut_channel->outstanding_io_count == 1);
14903deaf005SShuhei Matsumoto 	stub_complete_io(1);
14913deaf005SShuhei Matsumoto 	CU_ASSERT(g_io_done == true);
14923deaf005SShuhei Matsumoto 	CU_ASSERT(g_bdev_ut_channel->outstanding_io_count == 0);
14933deaf005SShuhei Matsumoto 	CU_ASSERT(g_io_status == SPDK_BDEV_IO_STATUS_SUCCESS);
14943deaf005SShuhei Matsumoto 
14954f860d7eSJim Harris 	/* Test a WRITE_ZEROES that would span an I/O boundary.  WRITE_ZEROES should not be
14964f860d7eSJim Harris 	 * split, so test that.
14974bd97621SJim Harris 	 */
14984bd97621SJim Harris 	bdev->optimal_io_boundary = 15;
14994bd97621SJim Harris 	g_io_done = false;
15003c7894ffSShuhei Matsumoto 	expected_io = ut_alloc_expected_io(SPDK_BDEV_IO_TYPE_WRITE_ZEROES, 9, 36, 0);
15013c7894ffSShuhei Matsumoto 	TAILQ_INSERT_TAIL(&g_bdev_ut_channel->expected_io, expected_io, link);
15024bd97621SJim Harris 
15034bd97621SJim Harris 	rc = spdk_bdev_write_zeroes_blocks(desc, io_ch, 9, 36, io_done, NULL);
15044bd97621SJim Harris 	CU_ASSERT(rc == 0);
15054bd97621SJim Harris 	CU_ASSERT(g_io_done == false);
15064bd97621SJim Harris 	CU_ASSERT(g_bdev_ut_channel->outstanding_io_count == 1);
15074bd97621SJim Harris 	stub_complete_io(1);
15084bd97621SJim Harris 	CU_ASSERT(g_io_done == true);
15094bd97621SJim Harris 
15104f860d7eSJim Harris 	/* Test an UNMAP.  This should also not be split. */
15114bd97621SJim Harris 	bdev->optimal_io_boundary = 16;
15124bd97621SJim Harris 	g_io_done = false;
15133c7894ffSShuhei Matsumoto 	expected_io = ut_alloc_expected_io(SPDK_BDEV_IO_TYPE_UNMAP, 15, 2, 0);
15143c7894ffSShuhei Matsumoto 	TAILQ_INSERT_TAIL(&g_bdev_ut_channel->expected_io, expected_io, link);
15154bd97621SJim Harris 
15164bd97621SJim Harris 	rc = spdk_bdev_unmap_blocks(desc, io_ch, 15, 2, io_done, NULL);
15174bd97621SJim Harris 	CU_ASSERT(rc == 0);
15184bd97621SJim Harris 	CU_ASSERT(g_io_done == false);
15194bd97621SJim Harris 	CU_ASSERT(g_bdev_ut_channel->outstanding_io_count == 1);
15204bd97621SJim Harris 	stub_complete_io(1);
15214bd97621SJim Harris 	CU_ASSERT(g_io_done == true);
15224bd97621SJim Harris 
15234f860d7eSJim Harris 	/* Test a FLUSH.  This should also not be split. */
15244bd97621SJim Harris 	bdev->optimal_io_boundary = 16;
15254bd97621SJim Harris 	g_io_done = false;
15263c7894ffSShuhei Matsumoto 	expected_io = ut_alloc_expected_io(SPDK_BDEV_IO_TYPE_FLUSH, 15, 2, 0);
15273c7894ffSShuhei Matsumoto 	TAILQ_INSERT_TAIL(&g_bdev_ut_channel->expected_io, expected_io, link);
15284bd97621SJim Harris 
15294bd97621SJim Harris 	rc = spdk_bdev_flush_blocks(desc, io_ch, 15, 2, io_done, NULL);
15304bd97621SJim Harris 	CU_ASSERT(rc == 0);
15314bd97621SJim Harris 	CU_ASSERT(g_io_done == false);
15324bd97621SJim Harris 	CU_ASSERT(g_bdev_ut_channel->outstanding_io_count == 1);
15334bd97621SJim Harris 	stub_complete_io(1);
15344bd97621SJim Harris 	CU_ASSERT(g_io_done == true);
15354bd97621SJim Harris 
15363c7894ffSShuhei Matsumoto 	CU_ASSERT(TAILQ_EMPTY(&g_bdev_ut_channel->expected_io));
15374bd97621SJim Harris 
1538c55c85f8SChangpeng Liu 	/* Children requests return an error status */
1539c55c85f8SChangpeng Liu 	bdev->optimal_io_boundary = 16;
1540c55c85f8SChangpeng Liu 	iov[0].iov_base = (void *)0x10000;
1541c55c85f8SChangpeng Liu 	iov[0].iov_len = 512 * 64;
1542c55c85f8SChangpeng Liu 	g_io_exp_status = SPDK_BDEV_IO_STATUS_FAILED;
1543c55c85f8SChangpeng Liu 	g_io_done = false;
1544c55c85f8SChangpeng Liu 	g_io_status = SPDK_BDEV_IO_STATUS_SUCCESS;
1545c55c85f8SChangpeng Liu 
1546c55c85f8SChangpeng Liu 	rc = spdk_bdev_readv_blocks(desc, io_ch, iov, 1, 1, 64, io_done, NULL);
1547c55c85f8SChangpeng Liu 	CU_ASSERT(rc == 0);
1548c55c85f8SChangpeng Liu 	CU_ASSERT(g_bdev_ut_channel->outstanding_io_count == 5);
1549c55c85f8SChangpeng Liu 	stub_complete_io(4);
1550c55c85f8SChangpeng Liu 	CU_ASSERT(g_io_done == false);
1551c55c85f8SChangpeng Liu 	CU_ASSERT(g_io_status == SPDK_BDEV_IO_STATUS_SUCCESS);
1552c55c85f8SChangpeng Liu 	stub_complete_io(1);
1553c55c85f8SChangpeng Liu 	CU_ASSERT(g_io_done == true);
1554c55c85f8SChangpeng Liu 	CU_ASSERT(g_io_status == SPDK_BDEV_IO_STATUS_FAILED);
1555c55c85f8SChangpeng Liu 
1556089d178aSShuhei Matsumoto 	/* Test if a multi vector command terminated with failure before continueing
1557089d178aSShuhei Matsumoto 	 * splitting process when one of child I/O failed.
1558089d178aSShuhei Matsumoto 	 * The multi vector command is as same as the above that needs to be split by strip
1559089d178aSShuhei Matsumoto 	 * and then needs to be split further due to the capacity of child iovs.
1560089d178aSShuhei Matsumoto 	 */
1561089d178aSShuhei Matsumoto 	for (i = 0; i < BDEV_IO_NUM_CHILD_IOV - 1; i++) {
1562089d178aSShuhei Matsumoto 		iov[i].iov_base = (void *)((i + 1) * 0x10000);
1563089d178aSShuhei Matsumoto 		iov[i].iov_len = 512;
1564089d178aSShuhei Matsumoto 	}
1565089d178aSShuhei Matsumoto 	iov[BDEV_IO_NUM_CHILD_IOV - 1].iov_base = (void *)(BDEV_IO_NUM_CHILD_IOV * 0x10000);
1566089d178aSShuhei Matsumoto 	iov[BDEV_IO_NUM_CHILD_IOV - 1].iov_len = 256;
1567089d178aSShuhei Matsumoto 
1568089d178aSShuhei Matsumoto 	iov[BDEV_IO_NUM_CHILD_IOV].iov_base = (void *)((BDEV_IO_NUM_CHILD_IOV + 1) * 0x10000);
1569089d178aSShuhei Matsumoto 	iov[BDEV_IO_NUM_CHILD_IOV].iov_len = 256;
1570089d178aSShuhei Matsumoto 
1571089d178aSShuhei Matsumoto 	iov[BDEV_IO_NUM_CHILD_IOV + 1].iov_base = (void *)((BDEV_IO_NUM_CHILD_IOV + 2) * 0x10000);
1572089d178aSShuhei Matsumoto 	iov[BDEV_IO_NUM_CHILD_IOV + 1].iov_len = 512;
1573089d178aSShuhei Matsumoto 
1574089d178aSShuhei Matsumoto 	bdev->optimal_io_boundary = BDEV_IO_NUM_CHILD_IOV;
1575089d178aSShuhei Matsumoto 
1576089d178aSShuhei Matsumoto 	g_io_exp_status = SPDK_BDEV_IO_STATUS_FAILED;
1577089d178aSShuhei Matsumoto 	g_io_done = false;
1578089d178aSShuhei Matsumoto 	g_io_status = SPDK_BDEV_IO_STATUS_SUCCESS;
1579089d178aSShuhei Matsumoto 
1580089d178aSShuhei Matsumoto 	rc = spdk_bdev_readv_blocks(desc, io_ch, iov, BDEV_IO_NUM_CHILD_IOV * 2, 0,
1581089d178aSShuhei Matsumoto 				    BDEV_IO_NUM_CHILD_IOV + 1, io_done, NULL);
1582089d178aSShuhei Matsumoto 	CU_ASSERT(rc == 0);
1583089d178aSShuhei Matsumoto 	CU_ASSERT(g_io_done == false);
1584089d178aSShuhei Matsumoto 
1585089d178aSShuhei Matsumoto 	CU_ASSERT(g_bdev_ut_channel->outstanding_io_count == 1);
1586089d178aSShuhei Matsumoto 	stub_complete_io(1);
1587089d178aSShuhei Matsumoto 	CU_ASSERT(g_io_done == true);
1588089d178aSShuhei Matsumoto 	CU_ASSERT(g_io_status == SPDK_BDEV_IO_STATUS_FAILED);
1589089d178aSShuhei Matsumoto 
1590089d178aSShuhei Matsumoto 	g_io_exp_status = SPDK_BDEV_IO_STATUS_SUCCESS;
1591089d178aSShuhei Matsumoto 
1592ebacdcd9Spaul luse 	/* for this test we will create the following conditions to hit the code path where
1593ebacdcd9Spaul luse 	 * we are trying to send and IO following a split that has no iovs because we had to
1594ebacdcd9Spaul luse 	 * trim them for alignment reasons.
1595ebacdcd9Spaul luse 	 *
1596ebacdcd9Spaul luse 	 * - 16K boundary, our IO will start at offset 0 with a length of 0x4200
1597ebacdcd9Spaul luse 	 * - Our IOVs are 0x212 in size so that we run into the 16K boundary at child IOV
1598ebacdcd9Spaul luse 	 *   position 30 and overshoot by 0x2e.
1599ebacdcd9Spaul luse 	 * - That means we'll send the IO and loop back to pick up the remaining bytes at
1600ebacdcd9Spaul luse 	 *   child IOV index 31. When we do, we find that we have to shorten index 31 by 0x2e
1601ebacdcd9Spaul luse 	 *   which eliniates that vector so we just send the first split IO with 30 vectors
1602ebacdcd9Spaul luse 	 *   and let the completion pick up the last 2 vectors.
1603ebacdcd9Spaul luse 	 */
1604ebacdcd9Spaul luse 	bdev->optimal_io_boundary = 32;
1605ebacdcd9Spaul luse 	bdev->split_on_optimal_io_boundary = true;
1606ebacdcd9Spaul luse 	g_io_done = false;
1607ebacdcd9Spaul luse 
1608ebacdcd9Spaul luse 	/* Init all parent IOVs to 0x212 */
1609ebacdcd9Spaul luse 	for (i = 0; i < BDEV_IO_NUM_CHILD_IOV + 2; i++) {
1610ebacdcd9Spaul luse 		iov[i].iov_base = (void *)((i + 1) * 0x10000);
1611ebacdcd9Spaul luse 		iov[i].iov_len = 0x212;
1612ebacdcd9Spaul luse 	}
1613ebacdcd9Spaul luse 
1614ebacdcd9Spaul luse 	expected_io = ut_alloc_expected_io(SPDK_BDEV_IO_TYPE_READ, 0, BDEV_IO_NUM_CHILD_IOV,
1615ebacdcd9Spaul luse 					   BDEV_IO_NUM_CHILD_IOV - 1);
1616ebacdcd9Spaul luse 	/* expect 0-29 to be 1:1 with the parent iov */
1617ebacdcd9Spaul luse 	for (i = 0; i < BDEV_IO_NUM_CHILD_IOV - 2; i++) {
1618ebacdcd9Spaul luse 		ut_expected_io_set_iov(expected_io, i, iov[i].iov_base, iov[i].iov_len);
1619ebacdcd9Spaul luse 	}
1620ebacdcd9Spaul luse 
1621ebacdcd9Spaul luse 	/* expect index 30 to be shortened to 0x1e4 (0x212 - 0x1e) because of the alignment
1622ebacdcd9Spaul luse 	 * where 0x1e is the amount we overshot the 16K boundary
1623ebacdcd9Spaul luse 	 */
1624ebacdcd9Spaul luse 	ut_expected_io_set_iov(expected_io, BDEV_IO_NUM_CHILD_IOV - 2,
1625ebacdcd9Spaul luse 			       (void *)(iov[BDEV_IO_NUM_CHILD_IOV - 2].iov_base), 0x1e4);
1626ebacdcd9Spaul luse 	TAILQ_INSERT_TAIL(&g_bdev_ut_channel->expected_io, expected_io, link);
1627ebacdcd9Spaul luse 
1628ebacdcd9Spaul luse 	/* 2nd child IO will have 2 remaining vectors, one to pick up from the one that was
1629ebacdcd9Spaul luse 	 * shortened that take it to the next boundary and then a final one to get us to
1630ebacdcd9Spaul luse 	 * 0x4200 bytes for the IO.
1631ebacdcd9Spaul luse 	 */
1632ebacdcd9Spaul luse 	expected_io = ut_alloc_expected_io(SPDK_BDEV_IO_TYPE_READ, BDEV_IO_NUM_CHILD_IOV,
1633ebacdcd9Spaul luse 					   BDEV_IO_NUM_CHILD_IOV, 2);
1634ebacdcd9Spaul luse 	/* position 30 picked up the remaining bytes to the next boundary */
1635ebacdcd9Spaul luse 	ut_expected_io_set_iov(expected_io, 0,
1636ebacdcd9Spaul luse 			       (void *)(iov[BDEV_IO_NUM_CHILD_IOV - 2].iov_base + 0x1e4), 0x2e);
1637ebacdcd9Spaul luse 
1638ebacdcd9Spaul luse 	/* position 31 picked the the rest of the trasnfer to get us to 0x4200 */
1639ebacdcd9Spaul luse 	ut_expected_io_set_iov(expected_io, 1,
1640ebacdcd9Spaul luse 			       (void *)(iov[BDEV_IO_NUM_CHILD_IOV - 1].iov_base), 0x1d2);
1641ebacdcd9Spaul luse 	TAILQ_INSERT_TAIL(&g_bdev_ut_channel->expected_io, expected_io, link);
1642ebacdcd9Spaul luse 
1643ebacdcd9Spaul luse 	rc = spdk_bdev_readv_blocks(desc, io_ch, iov, BDEV_IO_NUM_CHILD_IOV + 1, 0,
1644ebacdcd9Spaul luse 				    BDEV_IO_NUM_CHILD_IOV + 1, io_done, NULL);
1645ebacdcd9Spaul luse 	CU_ASSERT(rc == 0);
1646ebacdcd9Spaul luse 	CU_ASSERT(g_io_done == false);
1647ebacdcd9Spaul luse 
1648ebacdcd9Spaul luse 	CU_ASSERT(g_bdev_ut_channel->outstanding_io_count == 1);
1649ebacdcd9Spaul luse 	stub_complete_io(1);
1650ebacdcd9Spaul luse 	CU_ASSERT(g_io_done == false);
1651ebacdcd9Spaul luse 
1652ebacdcd9Spaul luse 	CU_ASSERT(g_bdev_ut_channel->outstanding_io_count == 1);
1653ebacdcd9Spaul luse 	stub_complete_io(1);
1654ebacdcd9Spaul luse 	CU_ASSERT(g_io_done == true);
1655ebacdcd9Spaul luse 	CU_ASSERT(g_bdev_ut_channel->outstanding_io_count == 0);
1656ebacdcd9Spaul luse 
16574bd97621SJim Harris 	spdk_put_io_channel(io_ch);
16584bd97621SJim Harris 	spdk_bdev_close(desc);
16594bd97621SJim Harris 	free_bdev(bdev);
16604bd97621SJim Harris 	spdk_bdev_finish(bdev_fini_cb, NULL);
1661270a25dfSBen Walker 	poll_threads();
16624bd97621SJim Harris }
16634bd97621SJim Harris 
1664a8780177SShuhei Matsumoto static void
1665a8780177SShuhei Matsumoto bdev_io_split_with_io_wait(void)
1666a8780177SShuhei Matsumoto {
1667a8780177SShuhei Matsumoto 	struct spdk_bdev *bdev;
1668b701087fSDarek Stojaczyk 	struct spdk_bdev_desc *desc = NULL;
1669a8780177SShuhei Matsumoto 	struct spdk_io_channel *io_ch;
1670a8780177SShuhei Matsumoto 	struct spdk_bdev_channel *channel;
1671a8780177SShuhei Matsumoto 	struct spdk_bdev_mgmt_channel *mgmt_ch;
1672a8780177SShuhei Matsumoto 	struct spdk_bdev_opts bdev_opts = {
1673a8780177SShuhei Matsumoto 		.bdev_io_pool_size = 2,
1674a8780177SShuhei Matsumoto 		.bdev_io_cache_size = 1,
1675a8780177SShuhei Matsumoto 	};
16765616c1edSShuhei Matsumoto 	struct iovec iov[3];
1677a8780177SShuhei Matsumoto 	struct ut_expected_io *expected_io;
1678a8780177SShuhei Matsumoto 	int rc;
1679a8780177SShuhei Matsumoto 
1680a8780177SShuhei Matsumoto 	rc = spdk_bdev_set_opts(&bdev_opts);
1681a8780177SShuhei Matsumoto 	CU_ASSERT(rc == 0);
1682a8780177SShuhei Matsumoto 	spdk_bdev_initialize(bdev_init_cb, NULL);
1683a8780177SShuhei Matsumoto 
1684a8780177SShuhei Matsumoto 	bdev = allocate_bdev("bdev0");
1685a8780177SShuhei Matsumoto 
1686*75dfecbbSShuhei Matsumoto 	rc = spdk_bdev_open_ext("bdev0", true, bdev_ut_event_cb, NULL, &desc);
1687a8780177SShuhei Matsumoto 	CU_ASSERT(rc == 0);
1688a8780177SShuhei Matsumoto 	CU_ASSERT(desc != NULL);
1689*75dfecbbSShuhei Matsumoto 	CU_ASSERT(bdev == spdk_bdev_desc_get_bdev(desc));
1690a8780177SShuhei Matsumoto 	io_ch = spdk_bdev_get_io_channel(desc);
1691a8780177SShuhei Matsumoto 	CU_ASSERT(io_ch != NULL);
1692a8780177SShuhei Matsumoto 	channel = spdk_io_channel_get_ctx(io_ch);
1693a8780177SShuhei Matsumoto 	mgmt_ch = channel->shared_resource->mgmt_ch;
1694a8780177SShuhei Matsumoto 
1695a8780177SShuhei Matsumoto 	bdev->optimal_io_boundary = 16;
1696a8780177SShuhei Matsumoto 	bdev->split_on_optimal_io_boundary = true;
1697a8780177SShuhei Matsumoto 
1698a8780177SShuhei Matsumoto 	rc = spdk_bdev_read_blocks(desc, io_ch, NULL, 0, 1, io_done, NULL);
1699a8780177SShuhei Matsumoto 	CU_ASSERT(rc == 0);
1700a8780177SShuhei Matsumoto 
1701a8780177SShuhei Matsumoto 	/* Now test that a single-vector command is split correctly.
1702a8780177SShuhei Matsumoto 	 * Offset 14, length 8, payload 0xF000
1703a8780177SShuhei Matsumoto 	 *  Child - Offset 14, length 2, payload 0xF000
1704a8780177SShuhei Matsumoto 	 *  Child - Offset 16, length 6, payload 0xF000 + 2 * 512
1705a8780177SShuhei Matsumoto 	 *
1706a8780177SShuhei Matsumoto 	 * Set up the expected values before calling spdk_bdev_read_blocks
1707a8780177SShuhei Matsumoto 	 */
1708a8780177SShuhei Matsumoto 	expected_io = ut_alloc_expected_io(SPDK_BDEV_IO_TYPE_READ, 14, 2, 1);
1709a8780177SShuhei Matsumoto 	ut_expected_io_set_iov(expected_io, 0, (void *)0xF000, 2 * 512);
1710a8780177SShuhei Matsumoto 	TAILQ_INSERT_TAIL(&g_bdev_ut_channel->expected_io, expected_io, link);
1711a8780177SShuhei Matsumoto 
1712a8780177SShuhei Matsumoto 	expected_io = ut_alloc_expected_io(SPDK_BDEV_IO_TYPE_READ, 16, 6, 1);
1713a8780177SShuhei Matsumoto 	ut_expected_io_set_iov(expected_io, 0, (void *)(0xF000 + 2 * 512), 6 * 512);
1714a8780177SShuhei Matsumoto 	TAILQ_INSERT_TAIL(&g_bdev_ut_channel->expected_io, expected_io, link);
1715a8780177SShuhei Matsumoto 
17165616c1edSShuhei Matsumoto 	/* The following children will be submitted sequentially due to the capacity of
17175616c1edSShuhei Matsumoto 	 * spdk_bdev_io.
17185616c1edSShuhei Matsumoto 	 */
17195616c1edSShuhei Matsumoto 
1720a8780177SShuhei Matsumoto 	/* The first child I/O will be queued to wait until an spdk_bdev_io becomes available */
1721a8780177SShuhei Matsumoto 	rc = spdk_bdev_read_blocks(desc, io_ch, (void *)0xF000, 14, 8, io_done, NULL);
1722a8780177SShuhei Matsumoto 	CU_ASSERT(rc == 0);
1723a8780177SShuhei Matsumoto 	CU_ASSERT(!TAILQ_EMPTY(&mgmt_ch->io_wait_queue));
1724a8780177SShuhei Matsumoto 	CU_ASSERT(g_bdev_ut_channel->outstanding_io_count == 1);
1725a8780177SShuhei Matsumoto 
1726a8780177SShuhei Matsumoto 	/* Completing the first read I/O will submit the first child */
1727a8780177SShuhei Matsumoto 	stub_complete_io(1);
1728a8780177SShuhei Matsumoto 	CU_ASSERT(TAILQ_EMPTY(&mgmt_ch->io_wait_queue));
1729a8780177SShuhei Matsumoto 	CU_ASSERT(g_bdev_ut_channel->outstanding_io_count == 1);
1730a8780177SShuhei Matsumoto 
1731a8780177SShuhei Matsumoto 	/* Completing the first child will submit the second child */
1732a8780177SShuhei Matsumoto 	stub_complete_io(1);
1733a8780177SShuhei Matsumoto 	CU_ASSERT(g_bdev_ut_channel->outstanding_io_count == 1);
1734a8780177SShuhei Matsumoto 
1735a8780177SShuhei Matsumoto 	/* Complete the second child I/O.  This should result in our callback getting
1736a8780177SShuhei Matsumoto 	 * invoked since the parent I/O is now complete.
1737a8780177SShuhei Matsumoto 	 */
1738a8780177SShuhei Matsumoto 	stub_complete_io(1);
1739a8780177SShuhei Matsumoto 	CU_ASSERT(g_bdev_ut_channel->outstanding_io_count == 0);
1740a8780177SShuhei Matsumoto 
17415616c1edSShuhei Matsumoto 	/* Now set up a more complex, multi-vector command that needs to be split,
17425616c1edSShuhei Matsumoto 	 *  including splitting iovecs.
17435616c1edSShuhei Matsumoto 	 */
17445616c1edSShuhei Matsumoto 	iov[0].iov_base = (void *)0x10000;
17455616c1edSShuhei Matsumoto 	iov[0].iov_len = 512;
17465616c1edSShuhei Matsumoto 	iov[1].iov_base = (void *)0x20000;
17475616c1edSShuhei Matsumoto 	iov[1].iov_len = 20 * 512;
17485616c1edSShuhei Matsumoto 	iov[2].iov_base = (void *)0x30000;
17495616c1edSShuhei Matsumoto 	iov[2].iov_len = 11 * 512;
17505616c1edSShuhei Matsumoto 
17515616c1edSShuhei Matsumoto 	g_io_done = false;
17525616c1edSShuhei Matsumoto 	expected_io = ut_alloc_expected_io(SPDK_BDEV_IO_TYPE_WRITE, 14, 2, 2);
17535616c1edSShuhei Matsumoto 	ut_expected_io_set_iov(expected_io, 0, (void *)0x10000, 512);
17545616c1edSShuhei Matsumoto 	ut_expected_io_set_iov(expected_io, 1, (void *)0x20000, 512);
17555616c1edSShuhei Matsumoto 	TAILQ_INSERT_TAIL(&g_bdev_ut_channel->expected_io, expected_io, link);
17565616c1edSShuhei Matsumoto 
17575616c1edSShuhei Matsumoto 	expected_io = ut_alloc_expected_io(SPDK_BDEV_IO_TYPE_WRITE, 16, 16, 1);
17585616c1edSShuhei Matsumoto 	ut_expected_io_set_iov(expected_io, 0, (void *)(0x20000 + 512), 16 * 512);
17595616c1edSShuhei Matsumoto 	TAILQ_INSERT_TAIL(&g_bdev_ut_channel->expected_io, expected_io, link);
17605616c1edSShuhei Matsumoto 
17615616c1edSShuhei Matsumoto 	expected_io = ut_alloc_expected_io(SPDK_BDEV_IO_TYPE_WRITE, 32, 14, 2);
17625616c1edSShuhei Matsumoto 	ut_expected_io_set_iov(expected_io, 0, (void *)(0x20000 + 17 * 512), 3 * 512);
17635616c1edSShuhei Matsumoto 	ut_expected_io_set_iov(expected_io, 1, (void *)0x30000, 11 * 512);
17645616c1edSShuhei Matsumoto 	TAILQ_INSERT_TAIL(&g_bdev_ut_channel->expected_io, expected_io, link);
17655616c1edSShuhei Matsumoto 
17665616c1edSShuhei Matsumoto 	rc = spdk_bdev_writev_blocks(desc, io_ch, iov, 3, 14, 32, io_done, NULL);
17675616c1edSShuhei Matsumoto 	CU_ASSERT(rc == 0);
17685616c1edSShuhei Matsumoto 	CU_ASSERT(g_io_done == false);
17695616c1edSShuhei Matsumoto 
17705616c1edSShuhei Matsumoto 	/* The following children will be submitted sequentially due to the capacity of
17715616c1edSShuhei Matsumoto 	 * spdk_bdev_io.
17725616c1edSShuhei Matsumoto 	 */
17735616c1edSShuhei Matsumoto 
17745616c1edSShuhei Matsumoto 	/* Completing the first child will submit the second child */
17755616c1edSShuhei Matsumoto 	CU_ASSERT(g_bdev_ut_channel->outstanding_io_count == 1);
17765616c1edSShuhei Matsumoto 	stub_complete_io(1);
17775616c1edSShuhei Matsumoto 	CU_ASSERT(g_io_done == false);
17785616c1edSShuhei Matsumoto 
17795616c1edSShuhei Matsumoto 	/* Completing the second child will submit the third child */
17805616c1edSShuhei Matsumoto 	CU_ASSERT(g_bdev_ut_channel->outstanding_io_count == 1);
17815616c1edSShuhei Matsumoto 	stub_complete_io(1);
17825616c1edSShuhei Matsumoto 	CU_ASSERT(g_io_done == false);
17835616c1edSShuhei Matsumoto 
17845616c1edSShuhei Matsumoto 	/* Completing the third child will result in our callback getting invoked
17855616c1edSShuhei Matsumoto 	 * since the parent I/O is now complete.
17865616c1edSShuhei Matsumoto 	 */
17875616c1edSShuhei Matsumoto 	CU_ASSERT(g_bdev_ut_channel->outstanding_io_count == 1);
17885616c1edSShuhei Matsumoto 	stub_complete_io(1);
17895616c1edSShuhei Matsumoto 	CU_ASSERT(g_io_done == true);
17905616c1edSShuhei Matsumoto 
1791a8780177SShuhei Matsumoto 	CU_ASSERT(TAILQ_EMPTY(&g_bdev_ut_channel->expected_io));
1792a8780177SShuhei Matsumoto 
1793a8780177SShuhei Matsumoto 	spdk_put_io_channel(io_ch);
1794a8780177SShuhei Matsumoto 	spdk_bdev_close(desc);
1795a8780177SShuhei Matsumoto 	free_bdev(bdev);
1796a8780177SShuhei Matsumoto 	spdk_bdev_finish(bdev_fini_cb, NULL);
1797270a25dfSBen Walker 	poll_threads();
1798a8780177SShuhei Matsumoto }
1799a8780177SShuhei Matsumoto 
1800dadd2a6dSPiotr Pelplinski static void
1801dadd2a6dSPiotr Pelplinski bdev_io_alignment(void)
1802dadd2a6dSPiotr Pelplinski {
1803dadd2a6dSPiotr Pelplinski 	struct spdk_bdev *bdev;
1804e2ce08cfSTomasz Zawadzki 	struct spdk_bdev_desc *desc = NULL;
1805dadd2a6dSPiotr Pelplinski 	struct spdk_io_channel *io_ch;
1806dadd2a6dSPiotr Pelplinski 	struct spdk_bdev_opts bdev_opts = {
1807dadd2a6dSPiotr Pelplinski 		.bdev_io_pool_size = 20,
1808dadd2a6dSPiotr Pelplinski 		.bdev_io_cache_size = 2,
1809dadd2a6dSPiotr Pelplinski 	};
1810dadd2a6dSPiotr Pelplinski 	int rc;
18119714818dSyidong0635 	void *buf = NULL;
1812dadd2a6dSPiotr Pelplinski 	struct iovec iovs[2];
1813dadd2a6dSPiotr Pelplinski 	int iovcnt;
1814dadd2a6dSPiotr Pelplinski 	uint64_t alignment;
1815dadd2a6dSPiotr Pelplinski 
1816dadd2a6dSPiotr Pelplinski 	rc = spdk_bdev_set_opts(&bdev_opts);
1817dadd2a6dSPiotr Pelplinski 	CU_ASSERT(rc == 0);
1818dadd2a6dSPiotr Pelplinski 	spdk_bdev_initialize(bdev_init_cb, NULL);
1819dadd2a6dSPiotr Pelplinski 
182080da9548SMaciej Szwed 	fn_table.submit_request = stub_submit_request_get_buf;
1821dadd2a6dSPiotr Pelplinski 	bdev = allocate_bdev("bdev0");
1822dadd2a6dSPiotr Pelplinski 
1823*75dfecbbSShuhei Matsumoto 	rc = spdk_bdev_open_ext("bdev0", true, bdev_ut_event_cb, NULL, &desc);
1824dadd2a6dSPiotr Pelplinski 	CU_ASSERT(rc == 0);
1825dadd2a6dSPiotr Pelplinski 	CU_ASSERT(desc != NULL);
1826*75dfecbbSShuhei Matsumoto 	CU_ASSERT(bdev == spdk_bdev_desc_get_bdev(desc));
1827dadd2a6dSPiotr Pelplinski 	io_ch = spdk_bdev_get_io_channel(desc);
1828dadd2a6dSPiotr Pelplinski 	CU_ASSERT(io_ch != NULL);
1829dadd2a6dSPiotr Pelplinski 
1830dadd2a6dSPiotr Pelplinski 	/* Create aligned buffer */
1831dadd2a6dSPiotr Pelplinski 	rc = posix_memalign(&buf, 4096, 8192);
1832dadd2a6dSPiotr Pelplinski 	SPDK_CU_ASSERT_FATAL(rc == 0);
1833dadd2a6dSPiotr Pelplinski 
1834dadd2a6dSPiotr Pelplinski 	/* Pass aligned single buffer with no alignment required */
1835dadd2a6dSPiotr Pelplinski 	alignment = 1;
1836dadd2a6dSPiotr Pelplinski 	bdev->required_alignment = spdk_u32log2(alignment);
1837dadd2a6dSPiotr Pelplinski 
1838dadd2a6dSPiotr Pelplinski 	rc = spdk_bdev_write_blocks(desc, io_ch, buf, 0, 1, io_done, NULL);
1839dadd2a6dSPiotr Pelplinski 	CU_ASSERT(rc == 0);
1840dadd2a6dSPiotr Pelplinski 	stub_complete_io(1);
1841dadd2a6dSPiotr Pelplinski 	CU_ASSERT(_are_iovs_aligned(g_bdev_io->u.bdev.iovs, g_bdev_io->u.bdev.iovcnt,
1842dadd2a6dSPiotr Pelplinski 				    alignment));
1843dadd2a6dSPiotr Pelplinski 
1844dadd2a6dSPiotr Pelplinski 	rc = spdk_bdev_read_blocks(desc, io_ch, buf, 0, 1, io_done, NULL);
1845dadd2a6dSPiotr Pelplinski 	CU_ASSERT(rc == 0);
1846dadd2a6dSPiotr Pelplinski 	stub_complete_io(1);
1847dadd2a6dSPiotr Pelplinski 	CU_ASSERT(_are_iovs_aligned(g_bdev_io->u.bdev.iovs, g_bdev_io->u.bdev.iovcnt,
1848dadd2a6dSPiotr Pelplinski 				    alignment));
1849dadd2a6dSPiotr Pelplinski 
1850dadd2a6dSPiotr Pelplinski 	/* Pass unaligned single buffer with no alignment required */
1851dadd2a6dSPiotr Pelplinski 	alignment = 1;
1852dadd2a6dSPiotr Pelplinski 	bdev->required_alignment = spdk_u32log2(alignment);
1853dadd2a6dSPiotr Pelplinski 
1854dadd2a6dSPiotr Pelplinski 	rc = spdk_bdev_write_blocks(desc, io_ch, buf + 4, 0, 1, io_done, NULL);
1855dadd2a6dSPiotr Pelplinski 	CU_ASSERT(rc == 0);
1856dadd2a6dSPiotr Pelplinski 	CU_ASSERT(g_bdev_io->internal.orig_iovcnt == 0);
1857dadd2a6dSPiotr Pelplinski 	CU_ASSERT(g_bdev_io->u.bdev.iovs[0].iov_base == buf + 4);
1858dadd2a6dSPiotr Pelplinski 	stub_complete_io(1);
1859dadd2a6dSPiotr Pelplinski 
1860dadd2a6dSPiotr Pelplinski 	rc = spdk_bdev_read_blocks(desc, io_ch, buf + 4, 0, 1, io_done, NULL);
1861dadd2a6dSPiotr Pelplinski 	CU_ASSERT(rc == 0);
1862dadd2a6dSPiotr Pelplinski 	CU_ASSERT(g_bdev_io->internal.orig_iovcnt == 0);
1863dadd2a6dSPiotr Pelplinski 	CU_ASSERT(g_bdev_io->u.bdev.iovs[0].iov_base == buf + 4);
1864dadd2a6dSPiotr Pelplinski 	stub_complete_io(1);
1865dadd2a6dSPiotr Pelplinski 
1866dadd2a6dSPiotr Pelplinski 	/* Pass unaligned single buffer with 512 alignment required */
1867dadd2a6dSPiotr Pelplinski 	alignment = 512;
1868dadd2a6dSPiotr Pelplinski 	bdev->required_alignment = spdk_u32log2(alignment);
1869dadd2a6dSPiotr Pelplinski 
1870dadd2a6dSPiotr Pelplinski 	rc = spdk_bdev_write_blocks(desc, io_ch, buf + 4, 0, 1, io_done, NULL);
1871dadd2a6dSPiotr Pelplinski 	CU_ASSERT(rc == 0);
1872dadd2a6dSPiotr Pelplinski 	CU_ASSERT(g_bdev_io->internal.orig_iovcnt == 1);
1873dadd2a6dSPiotr Pelplinski 	CU_ASSERT(g_bdev_io->u.bdev.iovs == &g_bdev_io->internal.bounce_iov);
1874dadd2a6dSPiotr Pelplinski 	CU_ASSERT(_are_iovs_aligned(g_bdev_io->u.bdev.iovs, g_bdev_io->u.bdev.iovcnt,
1875dadd2a6dSPiotr Pelplinski 				    alignment));
1876dadd2a6dSPiotr Pelplinski 	stub_complete_io(1);
1877dadd2a6dSPiotr Pelplinski 	CU_ASSERT(g_bdev_io->internal.orig_iovcnt == 0);
1878dadd2a6dSPiotr Pelplinski 
1879dadd2a6dSPiotr Pelplinski 	rc = spdk_bdev_read_blocks(desc, io_ch, buf + 4, 0, 1, io_done, NULL);
1880dadd2a6dSPiotr Pelplinski 	CU_ASSERT(rc == 0);
1881dadd2a6dSPiotr Pelplinski 	CU_ASSERT(g_bdev_io->internal.orig_iovcnt == 1);
1882dadd2a6dSPiotr Pelplinski 	CU_ASSERT(g_bdev_io->u.bdev.iovs == &g_bdev_io->internal.bounce_iov);
1883dadd2a6dSPiotr Pelplinski 	CU_ASSERT(_are_iovs_aligned(g_bdev_io->u.bdev.iovs, g_bdev_io->u.bdev.iovcnt,
1884dadd2a6dSPiotr Pelplinski 				    alignment));
1885dadd2a6dSPiotr Pelplinski 	stub_complete_io(1);
1886dadd2a6dSPiotr Pelplinski 	CU_ASSERT(g_bdev_io->internal.orig_iovcnt == 0);
1887dadd2a6dSPiotr Pelplinski 
1888dadd2a6dSPiotr Pelplinski 	/* Pass unaligned single buffer with 4096 alignment required */
1889dadd2a6dSPiotr Pelplinski 	alignment = 4096;
1890dadd2a6dSPiotr Pelplinski 	bdev->required_alignment = spdk_u32log2(alignment);
1891dadd2a6dSPiotr Pelplinski 
1892dadd2a6dSPiotr Pelplinski 	rc = spdk_bdev_write_blocks(desc, io_ch, buf + 8, 0, 1, io_done, NULL);
1893dadd2a6dSPiotr Pelplinski 	CU_ASSERT(rc == 0);
1894dadd2a6dSPiotr Pelplinski 	CU_ASSERT(g_bdev_io->internal.orig_iovcnt == 1);
1895dadd2a6dSPiotr Pelplinski 	CU_ASSERT(g_bdev_io->u.bdev.iovs == &g_bdev_io->internal.bounce_iov);
1896dadd2a6dSPiotr Pelplinski 	CU_ASSERT(_are_iovs_aligned(g_bdev_io->u.bdev.iovs, g_bdev_io->u.bdev.iovcnt,
1897dadd2a6dSPiotr Pelplinski 				    alignment));
1898dadd2a6dSPiotr Pelplinski 	stub_complete_io(1);
1899dadd2a6dSPiotr Pelplinski 	CU_ASSERT(g_bdev_io->internal.orig_iovcnt == 0);
1900dadd2a6dSPiotr Pelplinski 
1901dadd2a6dSPiotr Pelplinski 	rc = spdk_bdev_read_blocks(desc, io_ch, buf + 8, 0, 1, io_done, NULL);
1902dadd2a6dSPiotr Pelplinski 	CU_ASSERT(rc == 0);
1903dadd2a6dSPiotr Pelplinski 	CU_ASSERT(g_bdev_io->internal.orig_iovcnt == 1);
1904dadd2a6dSPiotr Pelplinski 	CU_ASSERT(g_bdev_io->u.bdev.iovs == &g_bdev_io->internal.bounce_iov);
1905dadd2a6dSPiotr Pelplinski 	CU_ASSERT(_are_iovs_aligned(g_bdev_io->u.bdev.iovs, g_bdev_io->u.bdev.iovcnt,
1906dadd2a6dSPiotr Pelplinski 				    alignment));
1907dadd2a6dSPiotr Pelplinski 	stub_complete_io(1);
1908dadd2a6dSPiotr Pelplinski 	CU_ASSERT(g_bdev_io->internal.orig_iovcnt == 0);
1909dadd2a6dSPiotr Pelplinski 
1910dadd2a6dSPiotr Pelplinski 	/* Pass aligned iovs with no alignment required */
1911dadd2a6dSPiotr Pelplinski 	alignment = 1;
1912dadd2a6dSPiotr Pelplinski 	bdev->required_alignment = spdk_u32log2(alignment);
1913dadd2a6dSPiotr Pelplinski 
1914dadd2a6dSPiotr Pelplinski 	iovcnt = 1;
1915dadd2a6dSPiotr Pelplinski 	iovs[0].iov_base = buf;
1916dadd2a6dSPiotr Pelplinski 	iovs[0].iov_len = 512;
1917dadd2a6dSPiotr Pelplinski 
1918dadd2a6dSPiotr Pelplinski 	rc = spdk_bdev_writev(desc, io_ch, iovs, iovcnt, 0, 512, io_done, NULL);
1919dadd2a6dSPiotr Pelplinski 	CU_ASSERT(rc == 0);
1920dadd2a6dSPiotr Pelplinski 	CU_ASSERT(g_bdev_io->internal.orig_iovcnt == 0);
1921dadd2a6dSPiotr Pelplinski 	stub_complete_io(1);
1922dadd2a6dSPiotr Pelplinski 	CU_ASSERT(g_bdev_io->u.bdev.iovs[0].iov_base == iovs[0].iov_base);
1923dadd2a6dSPiotr Pelplinski 
1924dadd2a6dSPiotr Pelplinski 	rc = spdk_bdev_readv(desc, io_ch, iovs, iovcnt, 0, 512, io_done, NULL);
1925dadd2a6dSPiotr Pelplinski 	CU_ASSERT(rc == 0);
1926dadd2a6dSPiotr Pelplinski 	CU_ASSERT(g_bdev_io->internal.orig_iovcnt == 0);
1927dadd2a6dSPiotr Pelplinski 	stub_complete_io(1);
1928dadd2a6dSPiotr Pelplinski 	CU_ASSERT(g_bdev_io->u.bdev.iovs[0].iov_base == iovs[0].iov_base);
1929dadd2a6dSPiotr Pelplinski 
1930dadd2a6dSPiotr Pelplinski 	/* Pass unaligned iovs with no alignment required */
1931dadd2a6dSPiotr Pelplinski 	alignment = 1;
1932dadd2a6dSPiotr Pelplinski 	bdev->required_alignment = spdk_u32log2(alignment);
1933dadd2a6dSPiotr Pelplinski 
1934dadd2a6dSPiotr Pelplinski 	iovcnt = 2;
1935dadd2a6dSPiotr Pelplinski 	iovs[0].iov_base = buf + 16;
1936dadd2a6dSPiotr Pelplinski 	iovs[0].iov_len = 256;
1937dadd2a6dSPiotr Pelplinski 	iovs[1].iov_base = buf + 16 + 256 + 32;
1938dadd2a6dSPiotr Pelplinski 	iovs[1].iov_len = 256;
1939dadd2a6dSPiotr Pelplinski 
1940dadd2a6dSPiotr Pelplinski 	rc = spdk_bdev_writev(desc, io_ch, iovs, iovcnt, 0, 512, io_done, NULL);
1941dadd2a6dSPiotr Pelplinski 	CU_ASSERT(rc == 0);
1942dadd2a6dSPiotr Pelplinski 	CU_ASSERT(g_bdev_io->internal.orig_iovcnt == 0);
1943dadd2a6dSPiotr Pelplinski 	stub_complete_io(1);
1944dadd2a6dSPiotr Pelplinski 	CU_ASSERT(g_bdev_io->u.bdev.iovs[0].iov_base == iovs[0].iov_base);
1945dadd2a6dSPiotr Pelplinski 
1946dadd2a6dSPiotr Pelplinski 	rc = spdk_bdev_readv(desc, io_ch, iovs, iovcnt, 0, 512, io_done, NULL);
1947dadd2a6dSPiotr Pelplinski 	CU_ASSERT(rc == 0);
1948dadd2a6dSPiotr Pelplinski 	CU_ASSERT(g_bdev_io->internal.orig_iovcnt == 0);
1949dadd2a6dSPiotr Pelplinski 	stub_complete_io(1);
1950dadd2a6dSPiotr Pelplinski 	CU_ASSERT(g_bdev_io->u.bdev.iovs[0].iov_base == iovs[0].iov_base);
1951dadd2a6dSPiotr Pelplinski 
1952dadd2a6dSPiotr Pelplinski 	/* Pass unaligned iov with 2048 alignment required */
1953dadd2a6dSPiotr Pelplinski 	alignment = 2048;
1954dadd2a6dSPiotr Pelplinski 	bdev->required_alignment = spdk_u32log2(alignment);
1955dadd2a6dSPiotr Pelplinski 
1956dadd2a6dSPiotr Pelplinski 	iovcnt = 2;
1957dadd2a6dSPiotr Pelplinski 	iovs[0].iov_base = buf + 16;
1958dadd2a6dSPiotr Pelplinski 	iovs[0].iov_len = 256;
1959dadd2a6dSPiotr Pelplinski 	iovs[1].iov_base = buf + 16 + 256 + 32;
1960dadd2a6dSPiotr Pelplinski 	iovs[1].iov_len = 256;
1961dadd2a6dSPiotr Pelplinski 
1962dadd2a6dSPiotr Pelplinski 	rc = spdk_bdev_writev(desc, io_ch, iovs, iovcnt, 0, 512, io_done, NULL);
1963dadd2a6dSPiotr Pelplinski 	CU_ASSERT(rc == 0);
1964dadd2a6dSPiotr Pelplinski 	CU_ASSERT(g_bdev_io->internal.orig_iovcnt == iovcnt);
1965dadd2a6dSPiotr Pelplinski 	CU_ASSERT(g_bdev_io->u.bdev.iovs == &g_bdev_io->internal.bounce_iov);
1966dadd2a6dSPiotr Pelplinski 	CU_ASSERT(_are_iovs_aligned(g_bdev_io->u.bdev.iovs, g_bdev_io->u.bdev.iovcnt,
1967dadd2a6dSPiotr Pelplinski 				    alignment));
1968dadd2a6dSPiotr Pelplinski 	stub_complete_io(1);
1969dadd2a6dSPiotr Pelplinski 	CU_ASSERT(g_bdev_io->internal.orig_iovcnt == 0);
1970dadd2a6dSPiotr Pelplinski 
1971dadd2a6dSPiotr Pelplinski 	rc = spdk_bdev_readv(desc, io_ch, iovs, iovcnt, 0, 512, io_done, NULL);
1972dadd2a6dSPiotr Pelplinski 	CU_ASSERT(rc == 0);
1973dadd2a6dSPiotr Pelplinski 	CU_ASSERT(g_bdev_io->internal.orig_iovcnt == iovcnt);
1974dadd2a6dSPiotr Pelplinski 	CU_ASSERT(g_bdev_io->u.bdev.iovs == &g_bdev_io->internal.bounce_iov);
1975dadd2a6dSPiotr Pelplinski 	CU_ASSERT(_are_iovs_aligned(g_bdev_io->u.bdev.iovs, g_bdev_io->u.bdev.iovcnt,
1976dadd2a6dSPiotr Pelplinski 				    alignment));
1977dadd2a6dSPiotr Pelplinski 	stub_complete_io(1);
1978dadd2a6dSPiotr Pelplinski 	CU_ASSERT(g_bdev_io->internal.orig_iovcnt == 0);
1979dadd2a6dSPiotr Pelplinski 
1980dadd2a6dSPiotr Pelplinski 	/* Pass iov without allocated buffer without alignment required */
1981dadd2a6dSPiotr Pelplinski 	alignment = 1;
1982dadd2a6dSPiotr Pelplinski 	bdev->required_alignment = spdk_u32log2(alignment);
1983dadd2a6dSPiotr Pelplinski 
1984dadd2a6dSPiotr Pelplinski 	iovcnt = 1;
1985dadd2a6dSPiotr Pelplinski 	iovs[0].iov_base = NULL;
1986dadd2a6dSPiotr Pelplinski 	iovs[0].iov_len = 0;
1987dadd2a6dSPiotr Pelplinski 
1988dadd2a6dSPiotr Pelplinski 	rc = spdk_bdev_readv(desc, io_ch, iovs, iovcnt, 0, 512, io_done, NULL);
1989dadd2a6dSPiotr Pelplinski 	CU_ASSERT(rc == 0);
1990dadd2a6dSPiotr Pelplinski 	CU_ASSERT(g_bdev_io->internal.orig_iovcnt == 0);
1991dadd2a6dSPiotr Pelplinski 	CU_ASSERT(_are_iovs_aligned(g_bdev_io->u.bdev.iovs, g_bdev_io->u.bdev.iovcnt,
1992dadd2a6dSPiotr Pelplinski 				    alignment));
1993dadd2a6dSPiotr Pelplinski 	stub_complete_io(1);
1994dadd2a6dSPiotr Pelplinski 
1995dadd2a6dSPiotr Pelplinski 	/* Pass iov without allocated buffer with 1024 alignment required */
1996dadd2a6dSPiotr Pelplinski 	alignment = 1024;
1997dadd2a6dSPiotr Pelplinski 	bdev->required_alignment = spdk_u32log2(alignment);
1998dadd2a6dSPiotr Pelplinski 
1999dadd2a6dSPiotr Pelplinski 	iovcnt = 1;
2000dadd2a6dSPiotr Pelplinski 	iovs[0].iov_base = NULL;
2001dadd2a6dSPiotr Pelplinski 	iovs[0].iov_len = 0;
2002dadd2a6dSPiotr Pelplinski 
2003dadd2a6dSPiotr Pelplinski 	rc = spdk_bdev_readv(desc, io_ch, iovs, iovcnt, 0, 512, io_done, NULL);
2004dadd2a6dSPiotr Pelplinski 	CU_ASSERT(rc == 0);
2005dadd2a6dSPiotr Pelplinski 	CU_ASSERT(g_bdev_io->internal.orig_iovcnt == 0);
2006dadd2a6dSPiotr Pelplinski 	CU_ASSERT(_are_iovs_aligned(g_bdev_io->u.bdev.iovs, g_bdev_io->u.bdev.iovcnt,
2007dadd2a6dSPiotr Pelplinski 				    alignment));
2008dadd2a6dSPiotr Pelplinski 	stub_complete_io(1);
2009dadd2a6dSPiotr Pelplinski 
2010dadd2a6dSPiotr Pelplinski 	spdk_put_io_channel(io_ch);
2011dadd2a6dSPiotr Pelplinski 	spdk_bdev_close(desc);
2012dadd2a6dSPiotr Pelplinski 	free_bdev(bdev);
2013ae43c81aSJim Harris 	fn_table.submit_request = stub_submit_request;
2014dadd2a6dSPiotr Pelplinski 	spdk_bdev_finish(bdev_fini_cb, NULL);
2015270a25dfSBen Walker 	poll_threads();
2016dadd2a6dSPiotr Pelplinski 
2017dadd2a6dSPiotr Pelplinski 	free(buf);
2018dadd2a6dSPiotr Pelplinski }
2019dadd2a6dSPiotr Pelplinski 
202042dba604SPiotr Pelplinski static void
202145f48053SChangpeng Liu bdev_io_alignment_with_boundary(void)
202245f48053SChangpeng Liu {
202345f48053SChangpeng Liu 	struct spdk_bdev *bdev;
2024e2ce08cfSTomasz Zawadzki 	struct spdk_bdev_desc *desc = NULL;
202545f48053SChangpeng Liu 	struct spdk_io_channel *io_ch;
202645f48053SChangpeng Liu 	struct spdk_bdev_opts bdev_opts = {
202745f48053SChangpeng Liu 		.bdev_io_pool_size = 20,
202845f48053SChangpeng Liu 		.bdev_io_cache_size = 2,
202945f48053SChangpeng Liu 	};
203045f48053SChangpeng Liu 	int rc;
20319714818dSyidong0635 	void *buf = NULL;
203245f48053SChangpeng Liu 	struct iovec iovs[2];
203345f48053SChangpeng Liu 	int iovcnt;
203445f48053SChangpeng Liu 	uint64_t alignment;
203545f48053SChangpeng Liu 
203645f48053SChangpeng Liu 	rc = spdk_bdev_set_opts(&bdev_opts);
203745f48053SChangpeng Liu 	CU_ASSERT(rc == 0);
203845f48053SChangpeng Liu 	spdk_bdev_initialize(bdev_init_cb, NULL);
203945f48053SChangpeng Liu 
204080da9548SMaciej Szwed 	fn_table.submit_request = stub_submit_request_get_buf;
204145f48053SChangpeng Liu 	bdev = allocate_bdev("bdev0");
204245f48053SChangpeng Liu 
2043*75dfecbbSShuhei Matsumoto 	rc = spdk_bdev_open_ext("bdev0", true, bdev_ut_event_cb, NULL, &desc);
204445f48053SChangpeng Liu 	CU_ASSERT(rc == 0);
204545f48053SChangpeng Liu 	CU_ASSERT(desc != NULL);
2046*75dfecbbSShuhei Matsumoto 	CU_ASSERT(bdev == spdk_bdev_desc_get_bdev(desc));
204745f48053SChangpeng Liu 	io_ch = spdk_bdev_get_io_channel(desc);
204845f48053SChangpeng Liu 	CU_ASSERT(io_ch != NULL);
204945f48053SChangpeng Liu 
205045f48053SChangpeng Liu 	/* Create aligned buffer */
205145f48053SChangpeng Liu 	rc = posix_memalign(&buf, 4096, 131072);
205245f48053SChangpeng Liu 	SPDK_CU_ASSERT_FATAL(rc == 0);
205345f48053SChangpeng Liu 	g_io_exp_status = SPDK_BDEV_IO_STATUS_SUCCESS;
205445f48053SChangpeng Liu 
205545f48053SChangpeng Liu 	/* 512 * 3 with 2 IO boundary, allocate small data buffer from bdev layer */
205645f48053SChangpeng Liu 	alignment = 512;
205745f48053SChangpeng Liu 	bdev->required_alignment = spdk_u32log2(alignment);
205845f48053SChangpeng Liu 	bdev->optimal_io_boundary = 2;
205945f48053SChangpeng Liu 	bdev->split_on_optimal_io_boundary = true;
206045f48053SChangpeng Liu 
206145f48053SChangpeng Liu 	iovcnt = 1;
206245f48053SChangpeng Liu 	iovs[0].iov_base = NULL;
206345f48053SChangpeng Liu 	iovs[0].iov_len = 512 * 3;
206445f48053SChangpeng Liu 
206545f48053SChangpeng Liu 	rc = spdk_bdev_readv_blocks(desc, io_ch, iovs, iovcnt, 1, 3, io_done, NULL);
206645f48053SChangpeng Liu 	CU_ASSERT(rc == 0);
206745f48053SChangpeng Liu 	CU_ASSERT(g_bdev_ut_channel->outstanding_io_count == 2);
206845f48053SChangpeng Liu 	stub_complete_io(2);
206945f48053SChangpeng Liu 
207045f48053SChangpeng Liu 	/* 8KiB with 16 IO boundary, allocate large data buffer from bdev layer */
207145f48053SChangpeng Liu 	alignment = 512;
207245f48053SChangpeng Liu 	bdev->required_alignment = spdk_u32log2(alignment);
207345f48053SChangpeng Liu 	bdev->optimal_io_boundary = 16;
207445f48053SChangpeng Liu 	bdev->split_on_optimal_io_boundary = true;
207545f48053SChangpeng Liu 
207645f48053SChangpeng Liu 	iovcnt = 1;
207745f48053SChangpeng Liu 	iovs[0].iov_base = NULL;
207845f48053SChangpeng Liu 	iovs[0].iov_len = 512 * 16;
207945f48053SChangpeng Liu 
208045f48053SChangpeng Liu 	rc = spdk_bdev_readv_blocks(desc, io_ch, iovs, iovcnt, 1, 16, io_done, NULL);
208145f48053SChangpeng Liu 	CU_ASSERT(rc == 0);
208245f48053SChangpeng Liu 	CU_ASSERT(g_bdev_ut_channel->outstanding_io_count == 2);
208345f48053SChangpeng Liu 	stub_complete_io(2);
208445f48053SChangpeng Liu 
208545f48053SChangpeng Liu 	/* 512 * 160 with 128 IO boundary, 63.5KiB + 16.5KiB for the two children requests */
208645f48053SChangpeng Liu 	alignment = 512;
208745f48053SChangpeng Liu 	bdev->required_alignment = spdk_u32log2(alignment);
208845f48053SChangpeng Liu 	bdev->optimal_io_boundary = 128;
208945f48053SChangpeng Liu 	bdev->split_on_optimal_io_boundary = true;
209045f48053SChangpeng Liu 
209145f48053SChangpeng Liu 	iovcnt = 1;
209245f48053SChangpeng Liu 	iovs[0].iov_base = buf + 16;
209345f48053SChangpeng Liu 	iovs[0].iov_len = 512 * 160;
209445f48053SChangpeng Liu 	rc = spdk_bdev_readv_blocks(desc, io_ch, iovs, iovcnt, 1, 160, io_done, NULL);
209545f48053SChangpeng Liu 	CU_ASSERT(rc == 0);
209645f48053SChangpeng Liu 	CU_ASSERT(g_bdev_ut_channel->outstanding_io_count == 2);
209745f48053SChangpeng Liu 	stub_complete_io(2);
209845f48053SChangpeng Liu 
209945f48053SChangpeng Liu 	/* 512 * 3 with 2 IO boundary */
210045f48053SChangpeng Liu 	alignment = 512;
210145f48053SChangpeng Liu 	bdev->required_alignment = spdk_u32log2(alignment);
210245f48053SChangpeng Liu 	bdev->optimal_io_boundary = 2;
210345f48053SChangpeng Liu 	bdev->split_on_optimal_io_boundary = true;
210445f48053SChangpeng Liu 
210545f48053SChangpeng Liu 	iovcnt = 2;
210645f48053SChangpeng Liu 	iovs[0].iov_base = buf + 16;
210745f48053SChangpeng Liu 	iovs[0].iov_len = 512;
210845f48053SChangpeng Liu 	iovs[1].iov_base = buf + 16 + 512 + 32;
210945f48053SChangpeng Liu 	iovs[1].iov_len = 1024;
211045f48053SChangpeng Liu 
211145f48053SChangpeng Liu 	rc = spdk_bdev_writev_blocks(desc, io_ch, iovs, iovcnt, 1, 3, io_done, NULL);
211245f48053SChangpeng Liu 	CU_ASSERT(rc == 0);
211345f48053SChangpeng Liu 	CU_ASSERT(g_bdev_ut_channel->outstanding_io_count == 2);
211445f48053SChangpeng Liu 	stub_complete_io(2);
211545f48053SChangpeng Liu 
211645f48053SChangpeng Liu 	rc = spdk_bdev_readv_blocks(desc, io_ch, iovs, iovcnt, 1, 3, io_done, NULL);
211745f48053SChangpeng Liu 	CU_ASSERT(rc == 0);
211845f48053SChangpeng Liu 	CU_ASSERT(g_bdev_ut_channel->outstanding_io_count == 2);
211945f48053SChangpeng Liu 	stub_complete_io(2);
212045f48053SChangpeng Liu 
212145f48053SChangpeng Liu 	/* 512 * 64 with 32 IO boundary */
212245f48053SChangpeng Liu 	bdev->optimal_io_boundary = 32;
212345f48053SChangpeng Liu 	iovcnt = 2;
212445f48053SChangpeng Liu 	iovs[0].iov_base = buf + 16;
212545f48053SChangpeng Liu 	iovs[0].iov_len = 16384;
212645f48053SChangpeng Liu 	iovs[1].iov_base = buf + 16 + 16384 + 32;
212745f48053SChangpeng Liu 	iovs[1].iov_len = 16384;
212845f48053SChangpeng Liu 
212945f48053SChangpeng Liu 	rc = spdk_bdev_writev_blocks(desc, io_ch, iovs, iovcnt, 1, 64, io_done, NULL);
213045f48053SChangpeng Liu 	CU_ASSERT(rc == 0);
213145f48053SChangpeng Liu 	CU_ASSERT(g_bdev_ut_channel->outstanding_io_count == 3);
213245f48053SChangpeng Liu 	stub_complete_io(3);
213345f48053SChangpeng Liu 
213445f48053SChangpeng Liu 	rc = spdk_bdev_readv_blocks(desc, io_ch, iovs, iovcnt, 1, 64, io_done, NULL);
213545f48053SChangpeng Liu 	CU_ASSERT(rc == 0);
213645f48053SChangpeng Liu 	CU_ASSERT(g_bdev_ut_channel->outstanding_io_count == 3);
213745f48053SChangpeng Liu 	stub_complete_io(3);
213845f48053SChangpeng Liu 
213945f48053SChangpeng Liu 	/* 512 * 160 with 32 IO boundary */
214045f48053SChangpeng Liu 	iovcnt = 1;
214145f48053SChangpeng Liu 	iovs[0].iov_base = buf + 16;
214245f48053SChangpeng Liu 	iovs[0].iov_len = 16384 + 65536;
214345f48053SChangpeng Liu 
214445f48053SChangpeng Liu 	rc = spdk_bdev_writev_blocks(desc, io_ch, iovs, iovcnt, 1, 160, io_done, NULL);
214545f48053SChangpeng Liu 	CU_ASSERT(rc == 0);
214645f48053SChangpeng Liu 	CU_ASSERT(g_bdev_ut_channel->outstanding_io_count == 6);
214745f48053SChangpeng Liu 	stub_complete_io(6);
214845f48053SChangpeng Liu 
214945f48053SChangpeng Liu 	spdk_put_io_channel(io_ch);
215045f48053SChangpeng Liu 	spdk_bdev_close(desc);
215145f48053SChangpeng Liu 	free_bdev(bdev);
2152ae43c81aSJim Harris 	fn_table.submit_request = stub_submit_request;
215345f48053SChangpeng Liu 	spdk_bdev_finish(bdev_fini_cb, NULL);
215445f48053SChangpeng Liu 	poll_threads();
215545f48053SChangpeng Liu 
215645f48053SChangpeng Liu 	free(buf);
215745f48053SChangpeng Liu }
215845f48053SChangpeng Liu 
215945f48053SChangpeng Liu static void
216042dba604SPiotr Pelplinski histogram_status_cb(void *cb_arg, int status)
216142dba604SPiotr Pelplinski {
216242dba604SPiotr Pelplinski 	g_status = status;
216342dba604SPiotr Pelplinski }
216442dba604SPiotr Pelplinski 
216542dba604SPiotr Pelplinski static void
216642dba604SPiotr Pelplinski histogram_data_cb(void *cb_arg, int status, struct spdk_histogram_data *histogram)
216742dba604SPiotr Pelplinski {
216842dba604SPiotr Pelplinski 	g_status = status;
216942dba604SPiotr Pelplinski 	g_histogram = histogram;
217042dba604SPiotr Pelplinski }
217142dba604SPiotr Pelplinski 
217242dba604SPiotr Pelplinski static void
217342dba604SPiotr Pelplinski histogram_io_count(void *ctx, uint64_t start, uint64_t end, uint64_t count,
217442dba604SPiotr Pelplinski 		   uint64_t total, uint64_t so_far)
217542dba604SPiotr Pelplinski {
217642dba604SPiotr Pelplinski 	g_count += count;
217742dba604SPiotr Pelplinski }
217842dba604SPiotr Pelplinski 
217942dba604SPiotr Pelplinski static void
218042dba604SPiotr Pelplinski bdev_histograms(void)
218142dba604SPiotr Pelplinski {
218242dba604SPiotr Pelplinski 	struct spdk_bdev *bdev;
2183dae8e892STomasz Zawadzki 	struct spdk_bdev_desc *desc = NULL;
218442dba604SPiotr Pelplinski 	struct spdk_io_channel *ch;
218542dba604SPiotr Pelplinski 	struct spdk_histogram_data *histogram;
218642dba604SPiotr Pelplinski 	uint8_t buf[4096];
218742dba604SPiotr Pelplinski 	int rc;
218842dba604SPiotr Pelplinski 
218942dba604SPiotr Pelplinski 	spdk_bdev_initialize(bdev_init_cb, NULL);
219042dba604SPiotr Pelplinski 
219142dba604SPiotr Pelplinski 	bdev = allocate_bdev("bdev");
219242dba604SPiotr Pelplinski 
2193*75dfecbbSShuhei Matsumoto 	rc = spdk_bdev_open_ext("bdev", true, bdev_ut_event_cb, NULL, &desc);
219442dba604SPiotr Pelplinski 	CU_ASSERT(rc == 0);
219542dba604SPiotr Pelplinski 	CU_ASSERT(desc != NULL);
2196*75dfecbbSShuhei Matsumoto 	CU_ASSERT(bdev == spdk_bdev_desc_get_bdev(desc));
219742dba604SPiotr Pelplinski 
219842dba604SPiotr Pelplinski 	ch = spdk_bdev_get_io_channel(desc);
219942dba604SPiotr Pelplinski 	CU_ASSERT(ch != NULL);
220042dba604SPiotr Pelplinski 
220142dba604SPiotr Pelplinski 	/* Enable histogram */
220242dba604SPiotr Pelplinski 	g_status = -1;
220342dba604SPiotr Pelplinski 	spdk_bdev_histogram_enable(bdev, histogram_status_cb, NULL, true);
220442dba604SPiotr Pelplinski 	poll_threads();
220542dba604SPiotr Pelplinski 	CU_ASSERT(g_status == 0);
220642dba604SPiotr Pelplinski 	CU_ASSERT(bdev->internal.histogram_enabled == true);
220742dba604SPiotr Pelplinski 
220842dba604SPiotr Pelplinski 	/* Allocate histogram */
220942dba604SPiotr Pelplinski 	histogram = spdk_histogram_data_alloc();
221042dba604SPiotr Pelplinski 	SPDK_CU_ASSERT_FATAL(histogram != NULL);
221142dba604SPiotr Pelplinski 
221242dba604SPiotr Pelplinski 	/* Check if histogram is zeroed */
221342dba604SPiotr Pelplinski 	spdk_bdev_histogram_get(bdev, histogram, histogram_data_cb, NULL);
221442dba604SPiotr Pelplinski 	poll_threads();
221542dba604SPiotr Pelplinski 	CU_ASSERT(g_status == 0);
221642dba604SPiotr Pelplinski 	SPDK_CU_ASSERT_FATAL(g_histogram != NULL);
221742dba604SPiotr Pelplinski 
221842dba604SPiotr Pelplinski 	g_count = 0;
221942dba604SPiotr Pelplinski 	spdk_histogram_data_iterate(g_histogram, histogram_io_count, NULL);
222042dba604SPiotr Pelplinski 
222142dba604SPiotr Pelplinski 	CU_ASSERT(g_count == 0);
222242dba604SPiotr Pelplinski 
22231d94a0b0SJim Harris 	rc = spdk_bdev_write_blocks(desc, ch, buf, 0, 1, io_done, NULL);
222442dba604SPiotr Pelplinski 	CU_ASSERT(rc == 0);
222542dba604SPiotr Pelplinski 
222642dba604SPiotr Pelplinski 	spdk_delay_us(10);
222742dba604SPiotr Pelplinski 	stub_complete_io(1);
222842dba604SPiotr Pelplinski 	poll_threads();
222942dba604SPiotr Pelplinski 
22301d94a0b0SJim Harris 	rc = spdk_bdev_read_blocks(desc, ch, buf, 0, 1, io_done, NULL);
223142dba604SPiotr Pelplinski 	CU_ASSERT(rc == 0);
223242dba604SPiotr Pelplinski 
223342dba604SPiotr Pelplinski 	spdk_delay_us(10);
223442dba604SPiotr Pelplinski 	stub_complete_io(1);
223542dba604SPiotr Pelplinski 	poll_threads();
223642dba604SPiotr Pelplinski 
223742dba604SPiotr Pelplinski 	/* Check if histogram gathered data from all I/O channels */
223842dba604SPiotr Pelplinski 	g_histogram = NULL;
223942dba604SPiotr Pelplinski 	spdk_bdev_histogram_get(bdev, histogram, histogram_data_cb, NULL);
224042dba604SPiotr Pelplinski 	poll_threads();
224142dba604SPiotr Pelplinski 	CU_ASSERT(g_status == 0);
224242dba604SPiotr Pelplinski 	CU_ASSERT(bdev->internal.histogram_enabled == true);
224342dba604SPiotr Pelplinski 	SPDK_CU_ASSERT_FATAL(g_histogram != NULL);
224442dba604SPiotr Pelplinski 
224542dba604SPiotr Pelplinski 	g_count = 0;
224642dba604SPiotr Pelplinski 	spdk_histogram_data_iterate(g_histogram, histogram_io_count, NULL);
224742dba604SPiotr Pelplinski 	CU_ASSERT(g_count == 2);
224842dba604SPiotr Pelplinski 
224942dba604SPiotr Pelplinski 	/* Disable histogram */
225042dba604SPiotr Pelplinski 	spdk_bdev_histogram_enable(bdev, histogram_status_cb, NULL, false);
225142dba604SPiotr Pelplinski 	poll_threads();
225242dba604SPiotr Pelplinski 	CU_ASSERT(g_status == 0);
225342dba604SPiotr Pelplinski 	CU_ASSERT(bdev->internal.histogram_enabled == false);
225442dba604SPiotr Pelplinski 
225542dba604SPiotr Pelplinski 	/* Try to run histogram commands on disabled bdev */
225642dba604SPiotr Pelplinski 	spdk_bdev_histogram_get(bdev, histogram, histogram_data_cb, NULL);
225742dba604SPiotr Pelplinski 	poll_threads();
225842dba604SPiotr Pelplinski 	CU_ASSERT(g_status == -EFAULT);
225942dba604SPiotr Pelplinski 
226026f6c2a0SDarek Stojaczyk 	spdk_histogram_data_free(histogram);
226142dba604SPiotr Pelplinski 	spdk_put_io_channel(ch);
226242dba604SPiotr Pelplinski 	spdk_bdev_close(desc);
226342dba604SPiotr Pelplinski 	free_bdev(bdev);
226442dba604SPiotr Pelplinski 	spdk_bdev_finish(bdev_fini_cb, NULL);
226542dba604SPiotr Pelplinski 	poll_threads();
226642dba604SPiotr Pelplinski }
226742dba604SPiotr Pelplinski 
2268e2918289SKonrad Sztyber static void
22693eda8bf6SMaciej Szwed _bdev_compare(bool emulated)
227077183c9cSMaciej Szwed {
227177183c9cSMaciej Szwed 	struct spdk_bdev *bdev;
227277183c9cSMaciej Szwed 	struct spdk_bdev_desc *desc = NULL;
227377183c9cSMaciej Szwed 	struct spdk_io_channel *ioch;
227477183c9cSMaciej Szwed 	struct ut_expected_io *expected_io;
227577183c9cSMaciej Szwed 	uint64_t offset, num_blocks;
227677183c9cSMaciej Szwed 	uint32_t num_completed;
227777183c9cSMaciej Szwed 	char aa_buf[512];
227877183c9cSMaciej Szwed 	char bb_buf[512];
227977183c9cSMaciej Szwed 	struct iovec compare_iov;
22803eda8bf6SMaciej Szwed 	uint8_t io_type;
228177183c9cSMaciej Szwed 	int rc;
228277183c9cSMaciej Szwed 
22833eda8bf6SMaciej Szwed 	if (emulated) {
22843eda8bf6SMaciej Szwed 		io_type = SPDK_BDEV_IO_TYPE_READ;
22853eda8bf6SMaciej Szwed 	} else {
22863eda8bf6SMaciej Szwed 		io_type = SPDK_BDEV_IO_TYPE_COMPARE;
22873eda8bf6SMaciej Szwed 	}
22883eda8bf6SMaciej Szwed 
228977183c9cSMaciej Szwed 	memset(aa_buf, 0xaa, sizeof(aa_buf));
229077183c9cSMaciej Szwed 	memset(bb_buf, 0xbb, sizeof(bb_buf));
229177183c9cSMaciej Szwed 
22923eda8bf6SMaciej Szwed 	g_io_types_supported[SPDK_BDEV_IO_TYPE_COMPARE] = !emulated;
2293bee042e4SMaciej Szwed 
229477183c9cSMaciej Szwed 	spdk_bdev_initialize(bdev_init_cb, NULL);
229577183c9cSMaciej Szwed 	fn_table.submit_request = stub_submit_request_get_buf;
229677183c9cSMaciej Szwed 	bdev = allocate_bdev("bdev");
229777183c9cSMaciej Szwed 
2298*75dfecbbSShuhei Matsumoto 	rc = spdk_bdev_open_ext("bdev", true, bdev_ut_event_cb, NULL, &desc);
229977183c9cSMaciej Szwed 	CU_ASSERT_EQUAL(rc, 0);
230077183c9cSMaciej Szwed 	SPDK_CU_ASSERT_FATAL(desc != NULL);
2301*75dfecbbSShuhei Matsumoto 	CU_ASSERT(bdev == spdk_bdev_desc_get_bdev(desc));
230277183c9cSMaciej Szwed 	ioch = spdk_bdev_get_io_channel(desc);
230377183c9cSMaciej Szwed 	SPDK_CU_ASSERT_FATAL(ioch != NULL);
230477183c9cSMaciej Szwed 
230577183c9cSMaciej Szwed 	fn_table.submit_request = stub_submit_request_get_buf;
230677183c9cSMaciej Szwed 	g_io_exp_status = SPDK_BDEV_IO_STATUS_SUCCESS;
230777183c9cSMaciej Szwed 
230877183c9cSMaciej Szwed 	offset = 50;
230977183c9cSMaciej Szwed 	num_blocks = 1;
231077183c9cSMaciej Szwed 	compare_iov.iov_base = aa_buf;
231177183c9cSMaciej Szwed 	compare_iov.iov_len = sizeof(aa_buf);
231277183c9cSMaciej Szwed 
23133eda8bf6SMaciej Szwed 	expected_io = ut_alloc_expected_io(io_type, offset, num_blocks, 0);
231477183c9cSMaciej Szwed 	TAILQ_INSERT_TAIL(&g_bdev_ut_channel->expected_io, expected_io, link);
231577183c9cSMaciej Szwed 
231677183c9cSMaciej Szwed 	g_io_done = false;
231777183c9cSMaciej Szwed 	g_compare_read_buf = aa_buf;
231877183c9cSMaciej Szwed 	g_compare_read_buf_len = sizeof(aa_buf);
231977183c9cSMaciej Szwed 	rc = spdk_bdev_comparev_blocks(desc, ioch, &compare_iov, 1, offset, num_blocks, io_done, NULL);
232077183c9cSMaciej Szwed 	CU_ASSERT_EQUAL(rc, 0);
232177183c9cSMaciej Szwed 	num_completed = stub_complete_io(1);
232277183c9cSMaciej Szwed 	CU_ASSERT_EQUAL(num_completed, 1);
232377183c9cSMaciej Szwed 	CU_ASSERT(g_io_done == true);
232477183c9cSMaciej Szwed 	CU_ASSERT(g_io_status == SPDK_BDEV_IO_STATUS_SUCCESS);
232577183c9cSMaciej Szwed 
23263eda8bf6SMaciej Szwed 	expected_io = ut_alloc_expected_io(io_type, offset, num_blocks, 0);
232777183c9cSMaciej Szwed 	TAILQ_INSERT_TAIL(&g_bdev_ut_channel->expected_io, expected_io, link);
232877183c9cSMaciej Szwed 
232977183c9cSMaciej Szwed 	g_io_done = false;
233077183c9cSMaciej Szwed 	g_compare_read_buf = bb_buf;
233177183c9cSMaciej Szwed 	g_compare_read_buf_len = sizeof(bb_buf);
233277183c9cSMaciej Szwed 	rc = spdk_bdev_comparev_blocks(desc, ioch, &compare_iov, 1, offset, num_blocks, io_done, NULL);
233377183c9cSMaciej Szwed 	CU_ASSERT_EQUAL(rc, 0);
233477183c9cSMaciej Szwed 	num_completed = stub_complete_io(1);
233577183c9cSMaciej Szwed 	CU_ASSERT_EQUAL(num_completed, 1);
233677183c9cSMaciej Szwed 	CU_ASSERT(g_io_done == true);
233777183c9cSMaciej Szwed 	CU_ASSERT(g_io_status == SPDK_BDEV_IO_STATUS_MISCOMPARE);
233877183c9cSMaciej Szwed 
233977183c9cSMaciej Szwed 	spdk_put_io_channel(ioch);
234077183c9cSMaciej Szwed 	spdk_bdev_close(desc);
234177183c9cSMaciej Szwed 	free_bdev(bdev);
234277183c9cSMaciej Szwed 	fn_table.submit_request = stub_submit_request;
234377183c9cSMaciej Szwed 	spdk_bdev_finish(bdev_fini_cb, NULL);
234477183c9cSMaciej Szwed 	poll_threads();
234577183c9cSMaciej Szwed 
2346bee042e4SMaciej Szwed 	g_io_types_supported[SPDK_BDEV_IO_TYPE_COMPARE] = true;
2347bee042e4SMaciej Szwed 
234877183c9cSMaciej Szwed 	g_compare_read_buf = NULL;
234977183c9cSMaciej Szwed }
235077183c9cSMaciej Szwed 
235177183c9cSMaciej Szwed static void
23523eda8bf6SMaciej Szwed bdev_compare(void)
23533eda8bf6SMaciej Szwed {
23543eda8bf6SMaciej Szwed 	_bdev_compare(true);
2355ca0eeaabSMaciej Szwed 	_bdev_compare(false);
23563eda8bf6SMaciej Szwed }
23573eda8bf6SMaciej Szwed 
23583eda8bf6SMaciej Szwed static void
2359ae43c81aSJim Harris bdev_compare_and_write(void)
2360ae43c81aSJim Harris {
2361ae43c81aSJim Harris 	struct spdk_bdev *bdev;
2362ae43c81aSJim Harris 	struct spdk_bdev_desc *desc = NULL;
2363ae43c81aSJim Harris 	struct spdk_io_channel *ioch;
2364ae43c81aSJim Harris 	struct ut_expected_io *expected_io;
2365ae43c81aSJim Harris 	uint64_t offset, num_blocks;
2366ae43c81aSJim Harris 	uint32_t num_completed;
2367ae43c81aSJim Harris 	char aa_buf[512];
2368ae43c81aSJim Harris 	char bb_buf[512];
2369ae43c81aSJim Harris 	char cc_buf[512];
2370ae43c81aSJim Harris 	char write_buf[512];
2371ae43c81aSJim Harris 	struct iovec compare_iov;
2372ae43c81aSJim Harris 	struct iovec write_iov;
2373ae43c81aSJim Harris 	int rc;
2374ae43c81aSJim Harris 
2375ae43c81aSJim Harris 	memset(aa_buf, 0xaa, sizeof(aa_buf));
2376ae43c81aSJim Harris 	memset(bb_buf, 0xbb, sizeof(bb_buf));
2377ae43c81aSJim Harris 	memset(cc_buf, 0xcc, sizeof(cc_buf));
2378ae43c81aSJim Harris 
2379bee042e4SMaciej Szwed 	g_io_types_supported[SPDK_BDEV_IO_TYPE_COMPARE] = false;
2380bee042e4SMaciej Szwed 
2381ae43c81aSJim Harris 	spdk_bdev_initialize(bdev_init_cb, NULL);
2382ae43c81aSJim Harris 	fn_table.submit_request = stub_submit_request_get_buf;
2383ae43c81aSJim Harris 	bdev = allocate_bdev("bdev");
2384ae43c81aSJim Harris 
2385*75dfecbbSShuhei Matsumoto 	rc = spdk_bdev_open_ext("bdev", true, bdev_ut_event_cb, NULL, &desc);
2386ae43c81aSJim Harris 	CU_ASSERT_EQUAL(rc, 0);
2387ae43c81aSJim Harris 	SPDK_CU_ASSERT_FATAL(desc != NULL);
2388*75dfecbbSShuhei Matsumoto 	CU_ASSERT(bdev == spdk_bdev_desc_get_bdev(desc));
2389ae43c81aSJim Harris 	ioch = spdk_bdev_get_io_channel(desc);
2390ae43c81aSJim Harris 	SPDK_CU_ASSERT_FATAL(ioch != NULL);
2391ae43c81aSJim Harris 
2392ae43c81aSJim Harris 	fn_table.submit_request = stub_submit_request_get_buf;
2393ae43c81aSJim Harris 	g_io_exp_status = SPDK_BDEV_IO_STATUS_SUCCESS;
2394ae43c81aSJim Harris 
2395ae43c81aSJim Harris 	offset = 50;
2396ae43c81aSJim Harris 	num_blocks = 1;
2397ae43c81aSJim Harris 	compare_iov.iov_base = aa_buf;
2398ae43c81aSJim Harris 	compare_iov.iov_len = sizeof(aa_buf);
2399ae43c81aSJim Harris 	write_iov.iov_base = bb_buf;
2400ae43c81aSJim Harris 	write_iov.iov_len = sizeof(bb_buf);
2401ae43c81aSJim Harris 
2402ae43c81aSJim Harris 	expected_io = ut_alloc_expected_io(SPDK_BDEV_IO_TYPE_READ, offset, num_blocks, 0);
2403ae43c81aSJim Harris 	TAILQ_INSERT_TAIL(&g_bdev_ut_channel->expected_io, expected_io, link);
2404ae43c81aSJim Harris 	expected_io = ut_alloc_expected_io(SPDK_BDEV_IO_TYPE_WRITE, offset, num_blocks, 0);
2405ae43c81aSJim Harris 	TAILQ_INSERT_TAIL(&g_bdev_ut_channel->expected_io, expected_io, link);
2406ae43c81aSJim Harris 
2407ae43c81aSJim Harris 	g_io_done = false;
2408ae43c81aSJim Harris 	g_compare_read_buf = aa_buf;
2409ae43c81aSJim Harris 	g_compare_read_buf_len = sizeof(aa_buf);
2410ae43c81aSJim Harris 	memset(write_buf, 0, sizeof(write_buf));
2411ae43c81aSJim Harris 	g_compare_write_buf = write_buf;
2412ae43c81aSJim Harris 	g_compare_write_buf_len = sizeof(write_buf);
2413ae43c81aSJim Harris 	rc = spdk_bdev_comparev_and_writev_blocks(desc, ioch, &compare_iov, 1, &write_iov, 1,
2414ae43c81aSJim Harris 			offset, num_blocks, io_done, NULL);
2415a83644feSMaciej Szwed 	/* Trigger range locking */
2416a83644feSMaciej Szwed 	poll_threads();
2417ae43c81aSJim Harris 	CU_ASSERT_EQUAL(rc, 0);
2418ae43c81aSJim Harris 	num_completed = stub_complete_io(1);
2419ae43c81aSJim Harris 	CU_ASSERT_EQUAL(num_completed, 1);
2420ae43c81aSJim Harris 	CU_ASSERT(g_io_done == false);
2421ae43c81aSJim Harris 	num_completed = stub_complete_io(1);
2422a83644feSMaciej Szwed 	/* Trigger range unlocking */
2423a83644feSMaciej Szwed 	poll_threads();
2424ae43c81aSJim Harris 	CU_ASSERT_EQUAL(num_completed, 1);
2425ae43c81aSJim Harris 	CU_ASSERT(g_io_done == true);
2426ae43c81aSJim Harris 	CU_ASSERT(g_io_status == SPDK_BDEV_IO_STATUS_SUCCESS);
2427ae43c81aSJim Harris 	CU_ASSERT(memcmp(write_buf, bb_buf, sizeof(write_buf)) == 0);
2428ae43c81aSJim Harris 
2429ae43c81aSJim Harris 	expected_io = ut_alloc_expected_io(SPDK_BDEV_IO_TYPE_READ, offset, num_blocks, 0);
2430ae43c81aSJim Harris 	TAILQ_INSERT_TAIL(&g_bdev_ut_channel->expected_io, expected_io, link);
2431ae43c81aSJim Harris 
2432ae43c81aSJim Harris 	g_io_done = false;
2433ae43c81aSJim Harris 	g_compare_read_buf = cc_buf;
2434ae43c81aSJim Harris 	g_compare_read_buf_len = sizeof(cc_buf);
2435ae43c81aSJim Harris 	memset(write_buf, 0, sizeof(write_buf));
2436ae43c81aSJim Harris 	g_compare_write_buf = write_buf;
2437ae43c81aSJim Harris 	g_compare_write_buf_len = sizeof(write_buf);
2438ae43c81aSJim Harris 	rc = spdk_bdev_comparev_and_writev_blocks(desc, ioch, &compare_iov, 1, &write_iov, 1,
2439ae43c81aSJim Harris 			offset, num_blocks, io_done, NULL);
2440a83644feSMaciej Szwed 	/* Trigger range locking */
2441a83644feSMaciej Szwed 	poll_threads();
2442ae43c81aSJim Harris 	CU_ASSERT_EQUAL(rc, 0);
2443ae43c81aSJim Harris 	num_completed = stub_complete_io(1);
2444a83644feSMaciej Szwed 	/* Trigger range unlocking earlier because we expect error here */
2445a83644feSMaciej Szwed 	poll_threads();
2446ae43c81aSJim Harris 	CU_ASSERT_EQUAL(num_completed, 1);
2447ae43c81aSJim Harris 	CU_ASSERT(g_io_done == true);
2448ae43c81aSJim Harris 	CU_ASSERT(g_io_status == SPDK_BDEV_IO_STATUS_MISCOMPARE);
2449ae43c81aSJim Harris 	num_completed = stub_complete_io(1);
2450ae43c81aSJim Harris 	CU_ASSERT_EQUAL(num_completed, 0);
2451ae43c81aSJim Harris 
2452ae43c81aSJim Harris 	spdk_put_io_channel(ioch);
2453ae43c81aSJim Harris 	spdk_bdev_close(desc);
2454ae43c81aSJim Harris 	free_bdev(bdev);
2455ae43c81aSJim Harris 	fn_table.submit_request = stub_submit_request;
2456ae43c81aSJim Harris 	spdk_bdev_finish(bdev_fini_cb, NULL);
2457ae43c81aSJim Harris 	poll_threads();
2458ae43c81aSJim Harris 
2459bee042e4SMaciej Szwed 	g_io_types_supported[SPDK_BDEV_IO_TYPE_COMPARE] = true;
2460bee042e4SMaciej Szwed 
2461ae43c81aSJim Harris 	g_compare_read_buf = NULL;
2462ae43c81aSJim Harris 	g_compare_write_buf = NULL;
2463ae43c81aSJim Harris }
2464ae43c81aSJim Harris 
2465ae43c81aSJim Harris static void
2466e2918289SKonrad Sztyber bdev_write_zeroes(void)
2467e2918289SKonrad Sztyber {
2468e2918289SKonrad Sztyber 	struct spdk_bdev *bdev;
2469e2918289SKonrad Sztyber 	struct spdk_bdev_desc *desc = NULL;
2470e2918289SKonrad Sztyber 	struct spdk_io_channel *ioch;
2471e2918289SKonrad Sztyber 	struct ut_expected_io *expected_io;
2472e2918289SKonrad Sztyber 	uint64_t offset, num_io_blocks, num_blocks;
2473e2918289SKonrad Sztyber 	uint32_t num_completed, num_requests;
2474e2918289SKonrad Sztyber 	int rc;
2475e2918289SKonrad Sztyber 
2476e2918289SKonrad Sztyber 	spdk_bdev_initialize(bdev_init_cb, NULL);
2477e2918289SKonrad Sztyber 	bdev = allocate_bdev("bdev");
2478e2918289SKonrad Sztyber 
2479*75dfecbbSShuhei Matsumoto 	rc = spdk_bdev_open_ext("bdev", true, bdev_ut_event_cb, NULL, &desc);
2480e2918289SKonrad Sztyber 	CU_ASSERT_EQUAL(rc, 0);
2481e2918289SKonrad Sztyber 	SPDK_CU_ASSERT_FATAL(desc != NULL);
2482*75dfecbbSShuhei Matsumoto 	CU_ASSERT(bdev == spdk_bdev_desc_get_bdev(desc));
2483e2918289SKonrad Sztyber 	ioch = spdk_bdev_get_io_channel(desc);
2484e2918289SKonrad Sztyber 	SPDK_CU_ASSERT_FATAL(ioch != NULL);
2485e2918289SKonrad Sztyber 
2486e2918289SKonrad Sztyber 	fn_table.submit_request = stub_submit_request;
2487e2918289SKonrad Sztyber 	g_io_exp_status = SPDK_BDEV_IO_STATUS_SUCCESS;
2488e2918289SKonrad Sztyber 
2489e2918289SKonrad Sztyber 	/* First test that if the bdev supports write_zeroes, the request won't be split */
2490e2918289SKonrad Sztyber 	bdev->md_len = 0;
2491e2918289SKonrad Sztyber 	bdev->blocklen = 4096;
2492e2918289SKonrad Sztyber 	num_blocks = (ZERO_BUFFER_SIZE / bdev->blocklen) * 2;
2493e2918289SKonrad Sztyber 
2494e2918289SKonrad Sztyber 	expected_io = ut_alloc_expected_io(SPDK_BDEV_IO_TYPE_WRITE_ZEROES, 0, num_blocks, 0);
2495e2918289SKonrad Sztyber 	TAILQ_INSERT_TAIL(&g_bdev_ut_channel->expected_io, expected_io, link);
2496e2918289SKonrad Sztyber 	rc = spdk_bdev_write_zeroes_blocks(desc, ioch, 0, num_blocks, io_done, NULL);
2497e2918289SKonrad Sztyber 	CU_ASSERT_EQUAL(rc, 0);
2498e2918289SKonrad Sztyber 	num_completed = stub_complete_io(1);
2499e2918289SKonrad Sztyber 	CU_ASSERT_EQUAL(num_completed, 1);
2500e2918289SKonrad Sztyber 
2501e2918289SKonrad Sztyber 	/* Check that if write zeroes is not supported it'll be replaced by regular writes */
2502e2918289SKonrad Sztyber 	ut_enable_io_type(SPDK_BDEV_IO_TYPE_WRITE_ZEROES, false);
2503e2918289SKonrad Sztyber 	num_io_blocks = ZERO_BUFFER_SIZE / bdev->blocklen;
2504e2918289SKonrad Sztyber 	num_requests = 2;
2505e2918289SKonrad Sztyber 	num_blocks = (ZERO_BUFFER_SIZE / bdev->blocklen) * num_requests;
2506e2918289SKonrad Sztyber 
2507e2918289SKonrad Sztyber 	for (offset = 0; offset < num_requests; ++offset) {
2508e2918289SKonrad Sztyber 		expected_io = ut_alloc_expected_io(SPDK_BDEV_IO_TYPE_WRITE,
2509e2918289SKonrad Sztyber 						   offset * num_io_blocks, num_io_blocks, 0);
2510e2918289SKonrad Sztyber 		TAILQ_INSERT_TAIL(&g_bdev_ut_channel->expected_io, expected_io, link);
2511e2918289SKonrad Sztyber 	}
2512e2918289SKonrad Sztyber 
2513e2918289SKonrad Sztyber 	rc = spdk_bdev_write_zeroes_blocks(desc, ioch, 0, num_blocks, io_done, NULL);
2514e2918289SKonrad Sztyber 	CU_ASSERT_EQUAL(rc, 0);
2515e2918289SKonrad Sztyber 	num_completed = stub_complete_io(num_requests);
2516e2918289SKonrad Sztyber 	CU_ASSERT_EQUAL(num_completed, num_requests);
2517e2918289SKonrad Sztyber 
2518e2918289SKonrad Sztyber 	/* Check that the splitting is correct if bdev has interleaved metadata */
2519e2918289SKonrad Sztyber 	bdev->md_interleave = true;
2520e2918289SKonrad Sztyber 	bdev->md_len = 64;
2521e2918289SKonrad Sztyber 	bdev->blocklen = 4096 + 64;
2522e2918289SKonrad Sztyber 	num_blocks = (ZERO_BUFFER_SIZE / bdev->blocklen) * 2;
2523e2918289SKonrad Sztyber 
2524e2918289SKonrad Sztyber 	num_requests = offset = 0;
2525e2918289SKonrad Sztyber 	while (offset < num_blocks) {
2526e2918289SKonrad Sztyber 		num_io_blocks = spdk_min(ZERO_BUFFER_SIZE / bdev->blocklen, num_blocks - offset);
2527e2918289SKonrad Sztyber 		expected_io = ut_alloc_expected_io(SPDK_BDEV_IO_TYPE_WRITE,
2528e2918289SKonrad Sztyber 						   offset, num_io_blocks, 0);
2529e2918289SKonrad Sztyber 		TAILQ_INSERT_TAIL(&g_bdev_ut_channel->expected_io, expected_io, link);
2530e2918289SKonrad Sztyber 		offset += num_io_blocks;
2531e2918289SKonrad Sztyber 		num_requests++;
2532e2918289SKonrad Sztyber 	}
2533e2918289SKonrad Sztyber 
2534e2918289SKonrad Sztyber 	rc = spdk_bdev_write_zeroes_blocks(desc, ioch, 0, num_blocks, io_done, NULL);
2535e2918289SKonrad Sztyber 	CU_ASSERT_EQUAL(rc, 0);
2536e2918289SKonrad Sztyber 	num_completed = stub_complete_io(num_requests);
2537e2918289SKonrad Sztyber 	CU_ASSERT_EQUAL(num_completed, num_requests);
2538e2918289SKonrad Sztyber 	num_completed = stub_complete_io(num_requests);
2539e2918289SKonrad Sztyber 	assert(num_completed == 0);
2540e2918289SKonrad Sztyber 
2541e2918289SKonrad Sztyber 	/* Check the the same for separate metadata buffer */
2542e2918289SKonrad Sztyber 	bdev->md_interleave = false;
2543e2918289SKonrad Sztyber 	bdev->md_len = 64;
2544e2918289SKonrad Sztyber 	bdev->blocklen = 4096;
2545e2918289SKonrad Sztyber 
2546e2918289SKonrad Sztyber 	num_requests = offset = 0;
2547e2918289SKonrad Sztyber 	while (offset < num_blocks) {
2548e2918289SKonrad Sztyber 		num_io_blocks = spdk_min(ZERO_BUFFER_SIZE / (bdev->blocklen + bdev->md_len), num_blocks);
2549e2918289SKonrad Sztyber 		expected_io = ut_alloc_expected_io(SPDK_BDEV_IO_TYPE_WRITE,
2550e2918289SKonrad Sztyber 						   offset, num_io_blocks, 0);
2551e2918289SKonrad Sztyber 		expected_io->md_buf = (char *)g_bdev_mgr.zero_buffer + num_io_blocks * bdev->blocklen;
2552e2918289SKonrad Sztyber 		TAILQ_INSERT_TAIL(&g_bdev_ut_channel->expected_io, expected_io, link);
2553e2918289SKonrad Sztyber 		offset += num_io_blocks;
2554e2918289SKonrad Sztyber 		num_requests++;
2555e2918289SKonrad Sztyber 	}
2556e2918289SKonrad Sztyber 
2557e2918289SKonrad Sztyber 	rc = spdk_bdev_write_zeroes_blocks(desc, ioch, 0, num_blocks, io_done, NULL);
2558e2918289SKonrad Sztyber 	CU_ASSERT_EQUAL(rc, 0);
2559e2918289SKonrad Sztyber 	num_completed = stub_complete_io(num_requests);
2560e2918289SKonrad Sztyber 	CU_ASSERT_EQUAL(num_completed, num_requests);
2561e2918289SKonrad Sztyber 
2562e2918289SKonrad Sztyber 	ut_enable_io_type(SPDK_BDEV_IO_TYPE_WRITE_ZEROES, true);
2563e2918289SKonrad Sztyber 	spdk_put_io_channel(ioch);
2564e2918289SKonrad Sztyber 	spdk_bdev_close(desc);
2565e2918289SKonrad Sztyber 	free_bdev(bdev);
2566e2918289SKonrad Sztyber 	spdk_bdev_finish(bdev_fini_cb, NULL);
2567e2918289SKonrad Sztyber 	poll_threads();
2568e2918289SKonrad Sztyber }
2569e2918289SKonrad Sztyber 
2570c141bd94SMaciej Szwed static void
2571c141bd94SMaciej Szwed bdev_open_while_hotremove(void)
2572c141bd94SMaciej Szwed {
2573c141bd94SMaciej Szwed 	struct spdk_bdev *bdev;
2574c141bd94SMaciej Szwed 	struct spdk_bdev_desc *desc[2] = {};
2575c141bd94SMaciej Szwed 	int rc;
2576c141bd94SMaciej Szwed 
2577c141bd94SMaciej Szwed 	bdev = allocate_bdev("bdev");
2578c141bd94SMaciej Szwed 
2579*75dfecbbSShuhei Matsumoto 	rc = spdk_bdev_open_ext("bdev", false, bdev_ut_event_cb, NULL, &desc[0]);
2580c141bd94SMaciej Szwed 	CU_ASSERT(rc == 0);
2581c141bd94SMaciej Szwed 	SPDK_CU_ASSERT_FATAL(desc[0] != NULL);
2582*75dfecbbSShuhei Matsumoto 	CU_ASSERT(bdev == spdk_bdev_desc_get_bdev(desc[0]));
2583c141bd94SMaciej Szwed 
2584c141bd94SMaciej Szwed 	spdk_bdev_unregister(bdev, NULL, NULL);
2585c141bd94SMaciej Szwed 
2586*75dfecbbSShuhei Matsumoto 	rc = spdk_bdev_open_ext("bdev", false, bdev_ut_event_cb, NULL, &desc[1]);
2587c141bd94SMaciej Szwed 	CU_ASSERT(rc == -ENODEV);
2588c141bd94SMaciej Szwed 	SPDK_CU_ASSERT_FATAL(desc[1] == NULL);
2589c141bd94SMaciej Szwed 
2590c141bd94SMaciej Szwed 	spdk_bdev_close(desc[0]);
2591c141bd94SMaciej Szwed 	free_bdev(bdev);
2592c141bd94SMaciej Szwed }
2593c141bd94SMaciej Szwed 
259479ed1ba1SMaciej Szwed static void
259523975858SEvgeniy Kochetov bdev_close_while_hotremove(void)
259623975858SEvgeniy Kochetov {
259723975858SEvgeniy Kochetov 	struct spdk_bdev *bdev;
259823975858SEvgeniy Kochetov 	struct spdk_bdev_desc *desc = NULL;
259923975858SEvgeniy Kochetov 	int rc = 0;
260023975858SEvgeniy Kochetov 
260123975858SEvgeniy Kochetov 	bdev = allocate_bdev("bdev");
260223975858SEvgeniy Kochetov 
260323975858SEvgeniy Kochetov 	rc = spdk_bdev_open_ext("bdev", true, bdev_open_cb1, &desc, &desc);
260423975858SEvgeniy Kochetov 	CU_ASSERT_EQUAL(rc, 0);
2605*75dfecbbSShuhei Matsumoto 	SPDK_CU_ASSERT_FATAL(desc != NULL);
2606*75dfecbbSShuhei Matsumoto 	CU_ASSERT(bdev == spdk_bdev_desc_get_bdev(desc));
260723975858SEvgeniy Kochetov 
260823975858SEvgeniy Kochetov 	/* Simulate hot-unplug by unregistering bdev */
260923975858SEvgeniy Kochetov 	g_event_type1 = 0xFF;
261023975858SEvgeniy Kochetov 	g_unregister_arg = NULL;
261123975858SEvgeniy Kochetov 	g_unregister_rc = -1;
261223975858SEvgeniy Kochetov 	spdk_bdev_unregister(bdev, bdev_unregister_cb, (void *)0x12345678);
261323975858SEvgeniy Kochetov 	/* Close device while remove event is in flight */
261423975858SEvgeniy Kochetov 	spdk_bdev_close(desc);
261523975858SEvgeniy Kochetov 
261623975858SEvgeniy Kochetov 	/* Ensure that unregister callback is delayed */
261723975858SEvgeniy Kochetov 	CU_ASSERT_EQUAL(g_unregister_arg, NULL);
261823975858SEvgeniy Kochetov 	CU_ASSERT_EQUAL(g_unregister_rc, -1);
261923975858SEvgeniy Kochetov 
262023975858SEvgeniy Kochetov 	poll_threads();
262123975858SEvgeniy Kochetov 
262223975858SEvgeniy Kochetov 	/* Event callback shall not be issued because device was closed */
262323975858SEvgeniy Kochetov 	CU_ASSERT_EQUAL(g_event_type1, 0xFF);
262423975858SEvgeniy Kochetov 	/* Unregister callback is issued */
262523975858SEvgeniy Kochetov 	CU_ASSERT_EQUAL(g_unregister_arg, (void *)0x12345678);
262623975858SEvgeniy Kochetov 	CU_ASSERT_EQUAL(g_unregister_rc, 0);
262723975858SEvgeniy Kochetov 
262823975858SEvgeniy Kochetov 	free_bdev(bdev);
262923975858SEvgeniy Kochetov }
263023975858SEvgeniy Kochetov 
263123975858SEvgeniy Kochetov static void
263279ed1ba1SMaciej Szwed bdev_open_ext(void)
263379ed1ba1SMaciej Szwed {
263479ed1ba1SMaciej Szwed 	struct spdk_bdev *bdev;
263579ed1ba1SMaciej Szwed 	struct spdk_bdev_desc *desc1 = NULL;
263679ed1ba1SMaciej Szwed 	struct spdk_bdev_desc *desc2 = NULL;
263779ed1ba1SMaciej Szwed 	int rc = 0;
263879ed1ba1SMaciej Szwed 
263979ed1ba1SMaciej Szwed 	bdev = allocate_bdev("bdev");
264079ed1ba1SMaciej Szwed 
264179ed1ba1SMaciej Szwed 	rc = spdk_bdev_open_ext("bdev", true, NULL, NULL, &desc1);
264279ed1ba1SMaciej Szwed 	CU_ASSERT_EQUAL(rc, -EINVAL);
264379ed1ba1SMaciej Szwed 
264479ed1ba1SMaciej Szwed 	rc = spdk_bdev_open_ext("bdev", true, bdev_open_cb1, &desc1, &desc1);
264579ed1ba1SMaciej Szwed 	CU_ASSERT_EQUAL(rc, 0);
264679ed1ba1SMaciej Szwed 
264779ed1ba1SMaciej Szwed 	rc = spdk_bdev_open_ext("bdev", true, bdev_open_cb2, &desc2, &desc2);
264879ed1ba1SMaciej Szwed 	CU_ASSERT_EQUAL(rc, 0);
264979ed1ba1SMaciej Szwed 
265079ed1ba1SMaciej Szwed 	g_event_type1 = 0xFF;
265179ed1ba1SMaciej Szwed 	g_event_type2 = 0xFF;
265279ed1ba1SMaciej Szwed 
265379ed1ba1SMaciej Szwed 	/* Simulate hot-unplug by unregistering bdev */
265479ed1ba1SMaciej Szwed 	spdk_bdev_unregister(bdev, NULL, NULL);
265579ed1ba1SMaciej Szwed 	poll_threads();
265679ed1ba1SMaciej Szwed 
265779ed1ba1SMaciej Szwed 	/* Check if correct events have been triggered in event callback fn */
265879ed1ba1SMaciej Szwed 	CU_ASSERT_EQUAL(g_event_type1, SPDK_BDEV_EVENT_REMOVE);
265979ed1ba1SMaciej Szwed 	CU_ASSERT_EQUAL(g_event_type2, SPDK_BDEV_EVENT_REMOVE);
266079ed1ba1SMaciej Szwed 
266179ed1ba1SMaciej Szwed 	free_bdev(bdev);
266279ed1ba1SMaciej Szwed 	poll_threads();
266379ed1ba1SMaciej Szwed }
266479ed1ba1SMaciej Szwed 
2665f1d47d69SJin Yu struct timeout_io_cb_arg {
2666f1d47d69SJin Yu 	struct iovec iov;
2667f1d47d69SJin Yu 	uint8_t type;
2668f1d47d69SJin Yu };
2669f1d47d69SJin Yu 
2670f1d47d69SJin Yu static int
2671f1d47d69SJin Yu bdev_channel_count_submitted_io(struct spdk_bdev_channel *ch)
2672f1d47d69SJin Yu {
2673f1d47d69SJin Yu 	struct spdk_bdev_io *bdev_io;
2674f1d47d69SJin Yu 	int n = 0;
2675f1d47d69SJin Yu 
2676f1d47d69SJin Yu 	if (!ch) {
2677f1d47d69SJin Yu 		return -1;
2678f1d47d69SJin Yu 	}
2679f1d47d69SJin Yu 
2680f1d47d69SJin Yu 	TAILQ_FOREACH(bdev_io, &ch->io_submitted, internal.ch_link) {
2681f1d47d69SJin Yu 		n++;
2682f1d47d69SJin Yu 	}
2683f1d47d69SJin Yu 
2684f1d47d69SJin Yu 	return n;
2685f1d47d69SJin Yu }
2686f1d47d69SJin Yu 
2687f1d47d69SJin Yu static void
2688f1d47d69SJin Yu bdev_channel_io_timeout_cb(void *cb_arg, struct spdk_bdev_io *bdev_io)
2689f1d47d69SJin Yu {
2690f1d47d69SJin Yu 	struct timeout_io_cb_arg *ctx = cb_arg;
2691f1d47d69SJin Yu 
2692f1d47d69SJin Yu 	ctx->type = bdev_io->type;
2693f1d47d69SJin Yu 	ctx->iov.iov_base = bdev_io->iov.iov_base;
2694f1d47d69SJin Yu 	ctx->iov.iov_len = bdev_io->iov.iov_len;
2695f1d47d69SJin Yu }
2696f1d47d69SJin Yu 
2697f1d47d69SJin Yu static void
2698f1d47d69SJin Yu bdev_set_io_timeout(void)
2699f1d47d69SJin Yu {
2700f1d47d69SJin Yu 	struct spdk_bdev *bdev;
2701f1d47d69SJin Yu 	struct spdk_bdev_desc *desc = NULL;
2702f1d47d69SJin Yu 	struct spdk_io_channel *io_ch = NULL;
2703f1d47d69SJin Yu 	struct spdk_bdev_channel *bdev_ch = NULL;
2704f1d47d69SJin Yu 	struct timeout_io_cb_arg cb_arg;
2705f1d47d69SJin Yu 
2706f1d47d69SJin Yu 	spdk_bdev_initialize(bdev_init_cb, NULL);
2707f1d47d69SJin Yu 
2708f1d47d69SJin Yu 	bdev = allocate_bdev("bdev");
2709f1d47d69SJin Yu 
2710*75dfecbbSShuhei Matsumoto 	CU_ASSERT(spdk_bdev_open_ext("bdev", true, bdev_ut_event_cb, NULL, &desc) == 0);
2711f1d47d69SJin Yu 	SPDK_CU_ASSERT_FATAL(desc != NULL);
2712*75dfecbbSShuhei Matsumoto 	CU_ASSERT(bdev == spdk_bdev_desc_get_bdev(desc));
2713*75dfecbbSShuhei Matsumoto 
2714f1d47d69SJin Yu 	io_ch = spdk_bdev_get_io_channel(desc);
2715f1d47d69SJin Yu 	CU_ASSERT(io_ch != NULL);
2716f1d47d69SJin Yu 
2717f1d47d69SJin Yu 	bdev_ch = spdk_io_channel_get_ctx(io_ch);
2718f1d47d69SJin Yu 	CU_ASSERT(TAILQ_EMPTY(&bdev_ch->io_submitted));
2719f1d47d69SJin Yu 
2720f1d47d69SJin Yu 	/* This is the part1.
2721f1d47d69SJin Yu 	 * We will check the bdev_ch->io_submitted list
2722f1d47d69SJin Yu 	 * TO make sure that it can link IOs and only the user submitted IOs
2723f1d47d69SJin Yu 	 */
2724f1d47d69SJin Yu 	CU_ASSERT(spdk_bdev_read(desc, io_ch, (void *)0x1000, 0, 4096, io_done, NULL) == 0);
2725f1d47d69SJin Yu 	CU_ASSERT(bdev_channel_count_submitted_io(bdev_ch) == 1);
2726f1d47d69SJin Yu 	CU_ASSERT(spdk_bdev_write(desc, io_ch, (void *)0x2000, 0, 4096, io_done, NULL) == 0);
2727f1d47d69SJin Yu 	CU_ASSERT(bdev_channel_count_submitted_io(bdev_ch) == 2);
2728f1d47d69SJin Yu 	stub_complete_io(1);
2729f1d47d69SJin Yu 	CU_ASSERT(bdev_channel_count_submitted_io(bdev_ch) == 1);
2730f1d47d69SJin Yu 	stub_complete_io(1);
2731f1d47d69SJin Yu 	CU_ASSERT(bdev_channel_count_submitted_io(bdev_ch) == 0);
2732f1d47d69SJin Yu 
2733f1d47d69SJin Yu 	/* Split IO */
2734f1d47d69SJin Yu 	bdev->optimal_io_boundary = 16;
2735f1d47d69SJin Yu 	bdev->split_on_optimal_io_boundary = true;
2736f1d47d69SJin Yu 
2737f1d47d69SJin Yu 	/* Now test that a single-vector command is split correctly.
2738f1d47d69SJin Yu 	 * Offset 14, length 8, payload 0xF000
2739f1d47d69SJin Yu 	 *  Child - Offset 14, length 2, payload 0xF000
2740f1d47d69SJin Yu 	 *  Child - Offset 16, length 6, payload 0xF000 + 2 * 512
2741f1d47d69SJin Yu 	 *
2742f1d47d69SJin Yu 	 * Set up the expected values before calling spdk_bdev_read_blocks
2743f1d47d69SJin Yu 	 */
2744f1d47d69SJin Yu 	CU_ASSERT(spdk_bdev_read_blocks(desc, io_ch, (void *)0xF000, 14, 8, io_done, NULL) == 0);
2745fc3e4061SShuhei Matsumoto 	/* We count all submitted IOs including IO that are generated by splitting. */
2746fc3e4061SShuhei Matsumoto 	CU_ASSERT(bdev_channel_count_submitted_io(bdev_ch) == 3);
2747f1d47d69SJin Yu 	stub_complete_io(1);
2748fc3e4061SShuhei Matsumoto 	CU_ASSERT(bdev_channel_count_submitted_io(bdev_ch) == 2);
2749f1d47d69SJin Yu 	stub_complete_io(1);
2750f1d47d69SJin Yu 	CU_ASSERT(bdev_channel_count_submitted_io(bdev_ch) == 0);
2751f1d47d69SJin Yu 
2752f1d47d69SJin Yu 	/* Also include the reset IO */
2753f1d47d69SJin Yu 	CU_ASSERT(spdk_bdev_reset(desc, io_ch, io_done, NULL) == 0);
2754f1d47d69SJin Yu 	CU_ASSERT(bdev_channel_count_submitted_io(bdev_ch) == 1);
2755f1d47d69SJin Yu 	poll_threads();
2756f1d47d69SJin Yu 	stub_complete_io(1);
2757f1d47d69SJin Yu 	poll_threads();
2758f1d47d69SJin Yu 	CU_ASSERT(bdev_channel_count_submitted_io(bdev_ch) == 0);
2759f1d47d69SJin Yu 
2760f1d47d69SJin Yu 	/* This is part2
2761f1d47d69SJin Yu 	 * Test the desc timeout poller register
2762f1d47d69SJin Yu 	 */
2763f1d47d69SJin Yu 
2764f1d47d69SJin Yu 	/* Successfully set the timeout */
2765f1d47d69SJin Yu 	CU_ASSERT(spdk_bdev_set_timeout(desc, 30, bdev_channel_io_timeout_cb, &cb_arg) == 0);
2766f1d47d69SJin Yu 	CU_ASSERT(desc->io_timeout_poller != NULL);
2767f1d47d69SJin Yu 	CU_ASSERT(desc->timeout_in_sec == 30);
2768f1d47d69SJin Yu 	CU_ASSERT(desc->cb_fn == bdev_channel_io_timeout_cb);
2769f1d47d69SJin Yu 	CU_ASSERT(desc->cb_arg == &cb_arg);
2770f1d47d69SJin Yu 
2771f1d47d69SJin Yu 	/* Change the timeout limit */
2772f1d47d69SJin Yu 	CU_ASSERT(spdk_bdev_set_timeout(desc, 20, bdev_channel_io_timeout_cb, &cb_arg) == 0);
2773f1d47d69SJin Yu 	CU_ASSERT(desc->io_timeout_poller != NULL);
2774f1d47d69SJin Yu 	CU_ASSERT(desc->timeout_in_sec == 20);
2775f1d47d69SJin Yu 	CU_ASSERT(desc->cb_fn == bdev_channel_io_timeout_cb);
2776f1d47d69SJin Yu 	CU_ASSERT(desc->cb_arg == &cb_arg);
2777f1d47d69SJin Yu 
2778f1d47d69SJin Yu 	/* Disable the timeout */
2779f1d47d69SJin Yu 	CU_ASSERT(spdk_bdev_set_timeout(desc, 0, NULL, NULL) == 0);
2780f1d47d69SJin Yu 	CU_ASSERT(desc->io_timeout_poller == NULL);
2781f1d47d69SJin Yu 
2782f1d47d69SJin Yu 	/* This the part3
2783f1d47d69SJin Yu 	 * We will test to catch timeout IO and check whether the IO is
2784f1d47d69SJin Yu 	 * the submitted one.
2785f1d47d69SJin Yu 	 */
2786f1d47d69SJin Yu 	memset(&cb_arg, 0, sizeof(cb_arg));
2787f1d47d69SJin Yu 	CU_ASSERT(spdk_bdev_set_timeout(desc, 30, bdev_channel_io_timeout_cb, &cb_arg) == 0);
2788f1d47d69SJin Yu 	CU_ASSERT(spdk_bdev_write_blocks(desc, io_ch, (void *)0x1000, 0, 1, io_done, NULL) == 0);
2789f1d47d69SJin Yu 
2790f1d47d69SJin Yu 	/* Don't reach the limit */
2791f1d47d69SJin Yu 	spdk_delay_us(15 * spdk_get_ticks_hz());
2792f1d47d69SJin Yu 	poll_threads();
2793f1d47d69SJin Yu 	CU_ASSERT(cb_arg.type == 0);
2794f1d47d69SJin Yu 	CU_ASSERT(cb_arg.iov.iov_base == (void *)0x0);
2795f1d47d69SJin Yu 	CU_ASSERT(cb_arg.iov.iov_len == 0);
2796f1d47d69SJin Yu 
2797f1d47d69SJin Yu 	/* 15 + 15 = 30 reach the limit */
2798f1d47d69SJin Yu 	spdk_delay_us(15 * spdk_get_ticks_hz());
2799f1d47d69SJin Yu 	poll_threads();
2800f1d47d69SJin Yu 	CU_ASSERT(cb_arg.type == SPDK_BDEV_IO_TYPE_WRITE);
2801f1d47d69SJin Yu 	CU_ASSERT(cb_arg.iov.iov_base == (void *)0x1000);
2802f1d47d69SJin Yu 	CU_ASSERT(cb_arg.iov.iov_len == 1 * bdev->blocklen);
2803f1d47d69SJin Yu 	stub_complete_io(1);
2804f1d47d69SJin Yu 
2805f1d47d69SJin Yu 	/* Use the same split IO above and check the IO */
2806f1d47d69SJin Yu 	memset(&cb_arg, 0, sizeof(cb_arg));
2807f1d47d69SJin Yu 	CU_ASSERT(spdk_bdev_write_blocks(desc, io_ch, (void *)0xF000, 14, 8, io_done, NULL) == 0);
2808f1d47d69SJin Yu 
2809f1d47d69SJin Yu 	/* The first child complete in time */
2810f1d47d69SJin Yu 	spdk_delay_us(15 * spdk_get_ticks_hz());
2811f1d47d69SJin Yu 	poll_threads();
2812f1d47d69SJin Yu 	stub_complete_io(1);
2813f1d47d69SJin Yu 	CU_ASSERT(cb_arg.type == 0);
2814f1d47d69SJin Yu 	CU_ASSERT(cb_arg.iov.iov_base == (void *)0x0);
2815f1d47d69SJin Yu 	CU_ASSERT(cb_arg.iov.iov_len == 0);
2816f1d47d69SJin Yu 
2817f1d47d69SJin Yu 	/* The second child reach the limit */
2818f1d47d69SJin Yu 	spdk_delay_us(15 * spdk_get_ticks_hz());
2819f1d47d69SJin Yu 	poll_threads();
2820f1d47d69SJin Yu 	CU_ASSERT(cb_arg.type == SPDK_BDEV_IO_TYPE_WRITE);
2821f1d47d69SJin Yu 	CU_ASSERT(cb_arg.iov.iov_base == (void *)0xF000);
2822f1d47d69SJin Yu 	CU_ASSERT(cb_arg.iov.iov_len == 8 * bdev->blocklen);
2823f1d47d69SJin Yu 	stub_complete_io(1);
2824f1d47d69SJin Yu 
2825f1d47d69SJin Yu 	/* Also include the reset IO */
2826f1d47d69SJin Yu 	memset(&cb_arg, 0, sizeof(cb_arg));
2827f1d47d69SJin Yu 	CU_ASSERT(spdk_bdev_reset(desc, io_ch, io_done, NULL) == 0);
2828f1d47d69SJin Yu 	spdk_delay_us(30 * spdk_get_ticks_hz());
2829f1d47d69SJin Yu 	poll_threads();
2830f1d47d69SJin Yu 	CU_ASSERT(cb_arg.type == SPDK_BDEV_IO_TYPE_RESET);
2831f1d47d69SJin Yu 	stub_complete_io(1);
2832f1d47d69SJin Yu 	poll_threads();
2833f1d47d69SJin Yu 
2834f1d47d69SJin Yu 	spdk_put_io_channel(io_ch);
2835f1d47d69SJin Yu 	spdk_bdev_close(desc);
2836f1d47d69SJin Yu 	free_bdev(bdev);
2837f1d47d69SJin Yu 	spdk_bdev_finish(bdev_fini_cb, NULL);
2838f1d47d69SJin Yu 	poll_threads();
2839f1d47d69SJin Yu }
2840f1d47d69SJin Yu 
2841b87080efSJim Harris static void
2842b87080efSJim Harris lba_range_overlap(void)
2843b87080efSJim Harris {
2844b87080efSJim Harris 	struct lba_range r1, r2;
2845b87080efSJim Harris 
2846b87080efSJim Harris 	r1.offset = 100;
2847b87080efSJim Harris 	r1.length = 50;
2848b87080efSJim Harris 
2849b87080efSJim Harris 	r2.offset = 0;
2850b87080efSJim Harris 	r2.length = 1;
2851b87080efSJim Harris 	CU_ASSERT(!bdev_lba_range_overlapped(&r1, &r2));
2852b87080efSJim Harris 
2853b87080efSJim Harris 	r2.offset = 0;
2854b87080efSJim Harris 	r2.length = 100;
2855b87080efSJim Harris 	CU_ASSERT(!bdev_lba_range_overlapped(&r1, &r2));
2856b87080efSJim Harris 
2857b87080efSJim Harris 	r2.offset = 0;
2858b87080efSJim Harris 	r2.length = 110;
2859b87080efSJim Harris 	CU_ASSERT(bdev_lba_range_overlapped(&r1, &r2));
2860b87080efSJim Harris 
2861b87080efSJim Harris 	r2.offset = 100;
2862b87080efSJim Harris 	r2.length = 10;
2863b87080efSJim Harris 	CU_ASSERT(bdev_lba_range_overlapped(&r1, &r2));
2864b87080efSJim Harris 
2865b87080efSJim Harris 	r2.offset = 110;
2866b87080efSJim Harris 	r2.length = 20;
2867b87080efSJim Harris 	CU_ASSERT(bdev_lba_range_overlapped(&r1, &r2));
2868b87080efSJim Harris 
2869b87080efSJim Harris 	r2.offset = 140;
2870b87080efSJim Harris 	r2.length = 150;
2871b87080efSJim Harris 	CU_ASSERT(bdev_lba_range_overlapped(&r1, &r2));
2872b87080efSJim Harris 
2873b87080efSJim Harris 	r2.offset = 130;
2874b87080efSJim Harris 	r2.length = 200;
2875b87080efSJim Harris 	CU_ASSERT(bdev_lba_range_overlapped(&r1, &r2));
2876b87080efSJim Harris 
2877b87080efSJim Harris 	r2.offset = 150;
2878b87080efSJim Harris 	r2.length = 100;
2879b87080efSJim Harris 	CU_ASSERT(!bdev_lba_range_overlapped(&r1, &r2));
2880b87080efSJim Harris 
2881b87080efSJim Harris 	r2.offset = 110;
2882b87080efSJim Harris 	r2.length = 0;
2883b87080efSJim Harris 	CU_ASSERT(!bdev_lba_range_overlapped(&r1, &r2));
2884b87080efSJim Harris }
2885b87080efSJim Harris 
2886d84a88c1SJim Harris static bool g_lock_lba_range_done;
2887d84a88c1SJim Harris static bool g_unlock_lba_range_done;
2888d84a88c1SJim Harris 
2889d84a88c1SJim Harris static void
2890d84a88c1SJim Harris lock_lba_range_done(void *ctx, int status)
2891d84a88c1SJim Harris {
2892d84a88c1SJim Harris 	g_lock_lba_range_done = true;
2893d84a88c1SJim Harris }
2894d84a88c1SJim Harris 
2895d84a88c1SJim Harris static void
2896d84a88c1SJim Harris unlock_lba_range_done(void *ctx, int status)
2897d84a88c1SJim Harris {
2898d84a88c1SJim Harris 	g_unlock_lba_range_done = true;
2899d84a88c1SJim Harris }
2900d84a88c1SJim Harris 
2901d84a88c1SJim Harris static void
2902d84a88c1SJim Harris lock_lba_range_check_ranges(void)
2903d84a88c1SJim Harris {
2904d84a88c1SJim Harris 	struct spdk_bdev *bdev;
2905d84a88c1SJim Harris 	struct spdk_bdev_desc *desc = NULL;
2906d84a88c1SJim Harris 	struct spdk_io_channel *io_ch;
2907d84a88c1SJim Harris 	struct spdk_bdev_channel *channel;
2908d84a88c1SJim Harris 	struct lba_range *range;
2909d84a88c1SJim Harris 	int ctx1;
2910d84a88c1SJim Harris 	int rc;
2911d84a88c1SJim Harris 
2912d84a88c1SJim Harris 	spdk_bdev_initialize(bdev_init_cb, NULL);
2913d84a88c1SJim Harris 
2914d84a88c1SJim Harris 	bdev = allocate_bdev("bdev0");
2915d84a88c1SJim Harris 
2916*75dfecbbSShuhei Matsumoto 	rc = spdk_bdev_open_ext("bdev0", true, bdev_ut_event_cb, NULL, &desc);
2917d84a88c1SJim Harris 	CU_ASSERT(rc == 0);
2918d84a88c1SJim Harris 	CU_ASSERT(desc != NULL);
2919*75dfecbbSShuhei Matsumoto 	CU_ASSERT(bdev == spdk_bdev_desc_get_bdev(desc));
2920d84a88c1SJim Harris 	io_ch = spdk_bdev_get_io_channel(desc);
2921d84a88c1SJim Harris 	CU_ASSERT(io_ch != NULL);
2922d84a88c1SJim Harris 	channel = spdk_io_channel_get_ctx(io_ch);
2923d84a88c1SJim Harris 
2924d84a88c1SJim Harris 	g_lock_lba_range_done = false;
2925d84a88c1SJim Harris 	rc = bdev_lock_lba_range(desc, io_ch, 20, 10, lock_lba_range_done, &ctx1);
2926d84a88c1SJim Harris 	CU_ASSERT(rc == 0);
2927d84a88c1SJim Harris 	poll_threads();
2928d84a88c1SJim Harris 
2929d84a88c1SJim Harris 	CU_ASSERT(g_lock_lba_range_done == true);
2930d84a88c1SJim Harris 	range = TAILQ_FIRST(&channel->locked_ranges);
2931d84a88c1SJim Harris 	SPDK_CU_ASSERT_FATAL(range != NULL);
2932d84a88c1SJim Harris 	CU_ASSERT(range->offset == 20);
2933d84a88c1SJim Harris 	CU_ASSERT(range->length == 10);
2934d84a88c1SJim Harris 	CU_ASSERT(range->owner_ch == channel);
2935d84a88c1SJim Harris 
2936d84a88c1SJim Harris 	/* Unlocks must exactly match a lock. */
2937d84a88c1SJim Harris 	g_unlock_lba_range_done = false;
2938d84a88c1SJim Harris 	rc = bdev_unlock_lba_range(desc, io_ch, 20, 1, unlock_lba_range_done, &ctx1);
2939d84a88c1SJim Harris 	CU_ASSERT(rc == -EINVAL);
2940d84a88c1SJim Harris 	CU_ASSERT(g_unlock_lba_range_done == false);
2941d84a88c1SJim Harris 
2942d84a88c1SJim Harris 	rc = bdev_unlock_lba_range(desc, io_ch, 20, 10, unlock_lba_range_done, &ctx1);
2943d84a88c1SJim Harris 	CU_ASSERT(rc == 0);
2944d84a88c1SJim Harris 	spdk_delay_us(100);
2945d84a88c1SJim Harris 	poll_threads();
2946d84a88c1SJim Harris 
2947d84a88c1SJim Harris 	CU_ASSERT(g_unlock_lba_range_done == true);
2948d84a88c1SJim Harris 	CU_ASSERT(TAILQ_EMPTY(&channel->locked_ranges));
2949d84a88c1SJim Harris 
2950d84a88c1SJim Harris 	spdk_put_io_channel(io_ch);
2951d84a88c1SJim Harris 	spdk_bdev_close(desc);
2952d84a88c1SJim Harris 	free_bdev(bdev);
2953d84a88c1SJim Harris 	spdk_bdev_finish(bdev_fini_cb, NULL);
2954d84a88c1SJim Harris 	poll_threads();
2955d84a88c1SJim Harris }
2956d84a88c1SJim Harris 
2957b90b7ce4SJim Harris static void
2958b90b7ce4SJim Harris lock_lba_range_with_io_outstanding(void)
2959b90b7ce4SJim Harris {
2960b90b7ce4SJim Harris 	struct spdk_bdev *bdev;
2961b90b7ce4SJim Harris 	struct spdk_bdev_desc *desc = NULL;
2962b90b7ce4SJim Harris 	struct spdk_io_channel *io_ch;
2963b90b7ce4SJim Harris 	struct spdk_bdev_channel *channel;
2964b90b7ce4SJim Harris 	struct lba_range *range;
2965b90b7ce4SJim Harris 	char buf[4096];
2966b90b7ce4SJim Harris 	int ctx1;
2967b90b7ce4SJim Harris 	int rc;
2968b90b7ce4SJim Harris 
2969b90b7ce4SJim Harris 	spdk_bdev_initialize(bdev_init_cb, NULL);
2970b90b7ce4SJim Harris 
2971b90b7ce4SJim Harris 	bdev = allocate_bdev("bdev0");
2972b90b7ce4SJim Harris 
2973*75dfecbbSShuhei Matsumoto 	rc = spdk_bdev_open_ext("bdev0", true, bdev_ut_event_cb, NULL, &desc);
2974b90b7ce4SJim Harris 	CU_ASSERT(rc == 0);
2975b90b7ce4SJim Harris 	CU_ASSERT(desc != NULL);
2976*75dfecbbSShuhei Matsumoto 	CU_ASSERT(bdev == spdk_bdev_desc_get_bdev(desc));
2977b90b7ce4SJim Harris 	io_ch = spdk_bdev_get_io_channel(desc);
2978b90b7ce4SJim Harris 	CU_ASSERT(io_ch != NULL);
2979b90b7ce4SJim Harris 	channel = spdk_io_channel_get_ctx(io_ch);
2980b90b7ce4SJim Harris 
2981b90b7ce4SJim Harris 	g_io_done = false;
2982b90b7ce4SJim Harris 	rc = spdk_bdev_read_blocks(desc, io_ch, buf, 20, 1, io_done, &ctx1);
2983b90b7ce4SJim Harris 	CU_ASSERT(rc == 0);
2984b90b7ce4SJim Harris 
2985b90b7ce4SJim Harris 	g_lock_lba_range_done = false;
2986b90b7ce4SJim Harris 	rc = bdev_lock_lba_range(desc, io_ch, 20, 10, lock_lba_range_done, &ctx1);
2987b90b7ce4SJim Harris 	CU_ASSERT(rc == 0);
2988b90b7ce4SJim Harris 	poll_threads();
2989b90b7ce4SJim Harris 
2990b90b7ce4SJim Harris 	/* The lock should immediately become valid, since there are no outstanding
2991b90b7ce4SJim Harris 	 * write I/O.
2992b90b7ce4SJim Harris 	 */
2993b90b7ce4SJim Harris 	CU_ASSERT(g_io_done == false);
2994b90b7ce4SJim Harris 	CU_ASSERT(g_lock_lba_range_done == true);
2995b90b7ce4SJim Harris 	range = TAILQ_FIRST(&channel->locked_ranges);
2996b90b7ce4SJim Harris 	SPDK_CU_ASSERT_FATAL(range != NULL);
2997b90b7ce4SJim Harris 	CU_ASSERT(range->offset == 20);
2998b90b7ce4SJim Harris 	CU_ASSERT(range->length == 10);
2999b90b7ce4SJim Harris 	CU_ASSERT(range->owner_ch == channel);
3000b90b7ce4SJim Harris 	CU_ASSERT(range->locked_ctx == &ctx1);
3001b90b7ce4SJim Harris 
3002b90b7ce4SJim Harris 	rc = bdev_unlock_lba_range(desc, io_ch, 20, 10, lock_lba_range_done, &ctx1);
3003b90b7ce4SJim Harris 	CU_ASSERT(rc == 0);
3004b90b7ce4SJim Harris 	stub_complete_io(1);
3005b90b7ce4SJim Harris 	spdk_delay_us(100);
3006b90b7ce4SJim Harris 	poll_threads();
3007b90b7ce4SJim Harris 
3008b90b7ce4SJim Harris 	CU_ASSERT(TAILQ_EMPTY(&channel->locked_ranges));
3009b90b7ce4SJim Harris 
3010b90b7ce4SJim Harris 	/* Now try again, but with a write I/O. */
3011b90b7ce4SJim Harris 	g_io_done = false;
3012b90b7ce4SJim Harris 	rc = spdk_bdev_write_blocks(desc, io_ch, buf, 20, 1, io_done, &ctx1);
3013b90b7ce4SJim Harris 	CU_ASSERT(rc == 0);
3014b90b7ce4SJim Harris 
3015b90b7ce4SJim Harris 	g_lock_lba_range_done = false;
3016b90b7ce4SJim Harris 	rc = bdev_lock_lba_range(desc, io_ch, 20, 10, lock_lba_range_done, &ctx1);
3017b90b7ce4SJim Harris 	CU_ASSERT(rc == 0);
3018b90b7ce4SJim Harris 	poll_threads();
3019b90b7ce4SJim Harris 
3020b90b7ce4SJim Harris 	/* The lock should not be fully valid yet, since a write I/O is outstanding.
3021b90b7ce4SJim Harris 	 * But note that the range should be on the channel's locked_list, to make sure no
3022b90b7ce4SJim Harris 	 * new write I/O are started.
3023b90b7ce4SJim Harris 	 */
3024b90b7ce4SJim Harris 	CU_ASSERT(g_io_done == false);
3025b90b7ce4SJim Harris 	CU_ASSERT(g_lock_lba_range_done == false);
3026b90b7ce4SJim Harris 	range = TAILQ_FIRST(&channel->locked_ranges);
3027b90b7ce4SJim Harris 	SPDK_CU_ASSERT_FATAL(range != NULL);
3028b90b7ce4SJim Harris 	CU_ASSERT(range->offset == 20);
3029b90b7ce4SJim Harris 	CU_ASSERT(range->length == 10);
3030b90b7ce4SJim Harris 
3031b90b7ce4SJim Harris 	/* Complete the write I/O.  This should make the lock valid (checked by confirming
3032b90b7ce4SJim Harris 	 * our callback was invoked).
3033b90b7ce4SJim Harris 	 */
3034b90b7ce4SJim Harris 	stub_complete_io(1);
3035b90b7ce4SJim Harris 	spdk_delay_us(100);
3036b90b7ce4SJim Harris 	poll_threads();
3037b90b7ce4SJim Harris 	CU_ASSERT(g_io_done == true);
3038b90b7ce4SJim Harris 	CU_ASSERT(g_lock_lba_range_done == true);
3039b90b7ce4SJim Harris 
3040b90b7ce4SJim Harris 	rc = bdev_unlock_lba_range(desc, io_ch, 20, 10, unlock_lba_range_done, &ctx1);
3041b90b7ce4SJim Harris 	CU_ASSERT(rc == 0);
3042b90b7ce4SJim Harris 	poll_threads();
3043b90b7ce4SJim Harris 
3044b90b7ce4SJim Harris 	CU_ASSERT(TAILQ_EMPTY(&channel->locked_ranges));
3045b90b7ce4SJim Harris 
3046b90b7ce4SJim Harris 	spdk_put_io_channel(io_ch);
3047b90b7ce4SJim Harris 	spdk_bdev_close(desc);
3048b90b7ce4SJim Harris 	free_bdev(bdev);
3049b90b7ce4SJim Harris 	spdk_bdev_finish(bdev_fini_cb, NULL);
3050b90b7ce4SJim Harris 	poll_threads();
3051b90b7ce4SJim Harris }
3052b90b7ce4SJim Harris 
30532a2b7296SJim Harris static void
30542a2b7296SJim Harris lock_lba_range_overlapped(void)
30552a2b7296SJim Harris {
30562a2b7296SJim Harris 	struct spdk_bdev *bdev;
30572a2b7296SJim Harris 	struct spdk_bdev_desc *desc = NULL;
30582a2b7296SJim Harris 	struct spdk_io_channel *io_ch;
30592a2b7296SJim Harris 	struct spdk_bdev_channel *channel;
30602a2b7296SJim Harris 	struct lba_range *range;
30612a2b7296SJim Harris 	int ctx1;
30622a2b7296SJim Harris 	int rc;
30632a2b7296SJim Harris 
30642a2b7296SJim Harris 	spdk_bdev_initialize(bdev_init_cb, NULL);
30652a2b7296SJim Harris 
30662a2b7296SJim Harris 	bdev = allocate_bdev("bdev0");
30672a2b7296SJim Harris 
3068*75dfecbbSShuhei Matsumoto 	rc = spdk_bdev_open_ext("bdev0", true, bdev_ut_event_cb, NULL, &desc);
30692a2b7296SJim Harris 	CU_ASSERT(rc == 0);
30702a2b7296SJim Harris 	CU_ASSERT(desc != NULL);
3071*75dfecbbSShuhei Matsumoto 	CU_ASSERT(bdev == spdk_bdev_desc_get_bdev(desc));
30722a2b7296SJim Harris 	io_ch = spdk_bdev_get_io_channel(desc);
30732a2b7296SJim Harris 	CU_ASSERT(io_ch != NULL);
30742a2b7296SJim Harris 	channel = spdk_io_channel_get_ctx(io_ch);
30752a2b7296SJim Harris 
30762a2b7296SJim Harris 	/* Lock range 20-29. */
30772a2b7296SJim Harris 	g_lock_lba_range_done = false;
30782a2b7296SJim Harris 	rc = bdev_lock_lba_range(desc, io_ch, 20, 10, lock_lba_range_done, &ctx1);
30792a2b7296SJim Harris 	CU_ASSERT(rc == 0);
30802a2b7296SJim Harris 	poll_threads();
30812a2b7296SJim Harris 
30822a2b7296SJim Harris 	CU_ASSERT(g_lock_lba_range_done == true);
30832a2b7296SJim Harris 	range = TAILQ_FIRST(&channel->locked_ranges);
30842a2b7296SJim Harris 	SPDK_CU_ASSERT_FATAL(range != NULL);
30852a2b7296SJim Harris 	CU_ASSERT(range->offset == 20);
30862a2b7296SJim Harris 	CU_ASSERT(range->length == 10);
30872a2b7296SJim Harris 
30882a2b7296SJim Harris 	/* Try to lock range 25-39.  It should not lock immediately, since it overlaps with
30892a2b7296SJim Harris 	 * 20-29.
30902a2b7296SJim Harris 	 */
30912a2b7296SJim Harris 	g_lock_lba_range_done = false;
30922a2b7296SJim Harris 	rc = bdev_lock_lba_range(desc, io_ch, 25, 15, lock_lba_range_done, &ctx1);
30932a2b7296SJim Harris 	CU_ASSERT(rc == 0);
30942a2b7296SJim Harris 	poll_threads();
30952a2b7296SJim Harris 
30962a2b7296SJim Harris 	CU_ASSERT(g_lock_lba_range_done == false);
30972a2b7296SJim Harris 	range = TAILQ_FIRST(&bdev->internal.pending_locked_ranges);
30982a2b7296SJim Harris 	SPDK_CU_ASSERT_FATAL(range != NULL);
30992a2b7296SJim Harris 	CU_ASSERT(range->offset == 25);
31002a2b7296SJim Harris 	CU_ASSERT(range->length == 15);
31012a2b7296SJim Harris 
31022a2b7296SJim Harris 	/* Unlock 20-29.  This should result in range 25-39 now getting locked since it
31032a2b7296SJim Harris 	 * no longer overlaps with an active lock.
31042a2b7296SJim Harris 	 */
31052a2b7296SJim Harris 	g_unlock_lba_range_done = false;
31062a2b7296SJim Harris 	rc = bdev_unlock_lba_range(desc, io_ch, 20, 10, unlock_lba_range_done, &ctx1);
31072a2b7296SJim Harris 	CU_ASSERT(rc == 0);
31082a2b7296SJim Harris 	poll_threads();
31092a2b7296SJim Harris 
31102a2b7296SJim Harris 	CU_ASSERT(g_unlock_lba_range_done == true);
31112a2b7296SJim Harris 	CU_ASSERT(TAILQ_EMPTY(&bdev->internal.pending_locked_ranges));
31122a2b7296SJim Harris 	range = TAILQ_FIRST(&channel->locked_ranges);
31132a2b7296SJim Harris 	SPDK_CU_ASSERT_FATAL(range != NULL);
31142a2b7296SJim Harris 	CU_ASSERT(range->offset == 25);
31152a2b7296SJim Harris 	CU_ASSERT(range->length == 15);
31162a2b7296SJim Harris 
31172a2b7296SJim Harris 	/* Lock 40-59.  This should immediately lock since it does not overlap with the
31182a2b7296SJim Harris 	 * currently active 25-39 lock.
31192a2b7296SJim Harris 	 */
31202a2b7296SJim Harris 	g_lock_lba_range_done = false;
31212a2b7296SJim Harris 	rc = bdev_lock_lba_range(desc, io_ch, 40, 20, lock_lba_range_done, &ctx1);
31222a2b7296SJim Harris 	CU_ASSERT(rc == 0);
31232a2b7296SJim Harris 	poll_threads();
31242a2b7296SJim Harris 
31252a2b7296SJim Harris 	CU_ASSERT(g_lock_lba_range_done == true);
31262a2b7296SJim Harris 	range = TAILQ_FIRST(&bdev->internal.locked_ranges);
31272a2b7296SJim Harris 	SPDK_CU_ASSERT_FATAL(range != NULL);
31282a2b7296SJim Harris 	range = TAILQ_NEXT(range, tailq);
31292a2b7296SJim Harris 	SPDK_CU_ASSERT_FATAL(range != NULL);
31302a2b7296SJim Harris 	CU_ASSERT(range->offset == 40);
31312a2b7296SJim Harris 	CU_ASSERT(range->length == 20);
31322a2b7296SJim Harris 
31332a2b7296SJim Harris 	/* Try to lock 35-44.  Note that this overlaps with both 25-39 and 40-59. */
31342a2b7296SJim Harris 	g_lock_lba_range_done = false;
31352a2b7296SJim Harris 	rc = bdev_lock_lba_range(desc, io_ch, 35, 10, lock_lba_range_done, &ctx1);
31362a2b7296SJim Harris 	CU_ASSERT(rc == 0);
31372a2b7296SJim Harris 	poll_threads();
31382a2b7296SJim Harris 
31392a2b7296SJim Harris 	CU_ASSERT(g_lock_lba_range_done == false);
31402a2b7296SJim Harris 	range = TAILQ_FIRST(&bdev->internal.pending_locked_ranges);
31412a2b7296SJim Harris 	SPDK_CU_ASSERT_FATAL(range != NULL);
31422a2b7296SJim Harris 	CU_ASSERT(range->offset == 35);
31432a2b7296SJim Harris 	CU_ASSERT(range->length == 10);
31442a2b7296SJim Harris 
31452a2b7296SJim Harris 	/* Unlock 25-39.  Make sure that 35-44 is still in the pending list, since
31462a2b7296SJim Harris 	 * the 40-59 lock is still active.
31472a2b7296SJim Harris 	 */
31482a2b7296SJim Harris 	g_unlock_lba_range_done = false;
31492a2b7296SJim Harris 	rc = bdev_unlock_lba_range(desc, io_ch, 25, 15, unlock_lba_range_done, &ctx1);
31502a2b7296SJim Harris 	CU_ASSERT(rc == 0);
31512a2b7296SJim Harris 	poll_threads();
31522a2b7296SJim Harris 
31532a2b7296SJim Harris 	CU_ASSERT(g_unlock_lba_range_done == true);
31542a2b7296SJim Harris 	CU_ASSERT(g_lock_lba_range_done == false);
31552a2b7296SJim Harris 	range = TAILQ_FIRST(&bdev->internal.pending_locked_ranges);
31562a2b7296SJim Harris 	SPDK_CU_ASSERT_FATAL(range != NULL);
31572a2b7296SJim Harris 	CU_ASSERT(range->offset == 35);
31582a2b7296SJim Harris 	CU_ASSERT(range->length == 10);
31592a2b7296SJim Harris 
31602a2b7296SJim Harris 	/* Unlock 40-59.  This should result in 35-44 now getting locked, since there are
31612a2b7296SJim Harris 	 * no longer any active overlapping locks.
31622a2b7296SJim Harris 	 */
31632a2b7296SJim Harris 	g_unlock_lba_range_done = false;
31642a2b7296SJim Harris 	rc = bdev_unlock_lba_range(desc, io_ch, 40, 20, unlock_lba_range_done, &ctx1);
31652a2b7296SJim Harris 	CU_ASSERT(rc == 0);
31662a2b7296SJim Harris 	poll_threads();
31672a2b7296SJim Harris 
31682a2b7296SJim Harris 	CU_ASSERT(g_unlock_lba_range_done == true);
31692a2b7296SJim Harris 	CU_ASSERT(g_lock_lba_range_done == true);
31702a2b7296SJim Harris 	CU_ASSERT(TAILQ_EMPTY(&bdev->internal.pending_locked_ranges));
31712a2b7296SJim Harris 	range = TAILQ_FIRST(&bdev->internal.locked_ranges);
31722a2b7296SJim Harris 	SPDK_CU_ASSERT_FATAL(range != NULL);
31732a2b7296SJim Harris 	CU_ASSERT(range->offset == 35);
31742a2b7296SJim Harris 	CU_ASSERT(range->length == 10);
31752a2b7296SJim Harris 
31762a2b7296SJim Harris 	/* Finally, unlock 35-44. */
31772a2b7296SJim Harris 	g_unlock_lba_range_done = false;
31782a2b7296SJim Harris 	rc = bdev_unlock_lba_range(desc, io_ch, 35, 10, unlock_lba_range_done, &ctx1);
31792a2b7296SJim Harris 	CU_ASSERT(rc == 0);
31802a2b7296SJim Harris 	poll_threads();
31812a2b7296SJim Harris 
31822a2b7296SJim Harris 	CU_ASSERT(g_unlock_lba_range_done == true);
31832a2b7296SJim Harris 	CU_ASSERT(TAILQ_EMPTY(&bdev->internal.locked_ranges));
31842a2b7296SJim Harris 
31852a2b7296SJim Harris 	spdk_put_io_channel(io_ch);
31862a2b7296SJim Harris 	spdk_bdev_close(desc);
31872a2b7296SJim Harris 	free_bdev(bdev);
31882a2b7296SJim Harris 	spdk_bdev_finish(bdev_fini_cb, NULL);
31892a2b7296SJim Harris 	poll_threads();
31902a2b7296SJim Harris }
31912a2b7296SJim Harris 
31927cd20dd3SShuhei Matsumoto static void
31937cd20dd3SShuhei Matsumoto abort_done(struct spdk_bdev_io *bdev_io, bool success, void *cb_arg)
31947cd20dd3SShuhei Matsumoto {
31957cd20dd3SShuhei Matsumoto 	g_abort_done = true;
31967cd20dd3SShuhei Matsumoto 	g_abort_status = bdev_io->internal.status;
31977cd20dd3SShuhei Matsumoto 	spdk_bdev_free_io(bdev_io);
31987cd20dd3SShuhei Matsumoto }
31997cd20dd3SShuhei Matsumoto 
32007cd20dd3SShuhei Matsumoto static void
32017cd20dd3SShuhei Matsumoto bdev_io_abort(void)
32027cd20dd3SShuhei Matsumoto {
32037cd20dd3SShuhei Matsumoto 	struct spdk_bdev *bdev;
32047cd20dd3SShuhei Matsumoto 	struct spdk_bdev_desc *desc = NULL;
32057cd20dd3SShuhei Matsumoto 	struct spdk_io_channel *io_ch;
320697a5ea57SShuhei Matsumoto 	struct spdk_bdev_channel *channel;
320797a5ea57SShuhei Matsumoto 	struct spdk_bdev_mgmt_channel *mgmt_ch;
32087cd20dd3SShuhei Matsumoto 	struct spdk_bdev_opts bdev_opts = {
320997a5ea57SShuhei Matsumoto 		.bdev_io_pool_size = 7,
32107cd20dd3SShuhei Matsumoto 		.bdev_io_cache_size = 2,
32117cd20dd3SShuhei Matsumoto 	};
321297a5ea57SShuhei Matsumoto 	struct iovec iov[BDEV_IO_NUM_CHILD_IOV * 2];
321397a5ea57SShuhei Matsumoto 	uint64_t io_ctx1 = 0, io_ctx2 = 0, i;
32147cd20dd3SShuhei Matsumoto 	int rc;
32157cd20dd3SShuhei Matsumoto 
32167cd20dd3SShuhei Matsumoto 	rc = spdk_bdev_set_opts(&bdev_opts);
32177cd20dd3SShuhei Matsumoto 	CU_ASSERT(rc == 0);
32187cd20dd3SShuhei Matsumoto 	spdk_bdev_initialize(bdev_init_cb, NULL);
32197cd20dd3SShuhei Matsumoto 
32207cd20dd3SShuhei Matsumoto 	bdev = allocate_bdev("bdev0");
32217cd20dd3SShuhei Matsumoto 
3222*75dfecbbSShuhei Matsumoto 	rc = spdk_bdev_open_ext("bdev0", true, bdev_ut_event_cb, NULL, &desc);
32237cd20dd3SShuhei Matsumoto 	CU_ASSERT(rc == 0);
32247cd20dd3SShuhei Matsumoto 	CU_ASSERT(desc != NULL);
3225*75dfecbbSShuhei Matsumoto 	CU_ASSERT(bdev == spdk_bdev_desc_get_bdev(desc));
32267cd20dd3SShuhei Matsumoto 	io_ch = spdk_bdev_get_io_channel(desc);
32277cd20dd3SShuhei Matsumoto 	CU_ASSERT(io_ch != NULL);
322897a5ea57SShuhei Matsumoto 	channel = spdk_io_channel_get_ctx(io_ch);
322997a5ea57SShuhei Matsumoto 	mgmt_ch = channel->shared_resource->mgmt_ch;
32307cd20dd3SShuhei Matsumoto 
32317cd20dd3SShuhei Matsumoto 	g_abort_done = false;
32327cd20dd3SShuhei Matsumoto 
32337cd20dd3SShuhei Matsumoto 	ut_enable_io_type(SPDK_BDEV_IO_TYPE_ABORT, false);
32347cd20dd3SShuhei Matsumoto 
32357cd20dd3SShuhei Matsumoto 	rc = spdk_bdev_abort(desc, io_ch, &io_ctx1, abort_done, NULL);
32367cd20dd3SShuhei Matsumoto 	CU_ASSERT(rc == -ENOTSUP);
32377cd20dd3SShuhei Matsumoto 
32387cd20dd3SShuhei Matsumoto 	ut_enable_io_type(SPDK_BDEV_IO_TYPE_ABORT, true);
32397cd20dd3SShuhei Matsumoto 
32407cd20dd3SShuhei Matsumoto 	rc = spdk_bdev_abort(desc, io_ch, &io_ctx2, abort_done, NULL);
32417cd20dd3SShuhei Matsumoto 	CU_ASSERT(rc == 0);
32427cd20dd3SShuhei Matsumoto 	CU_ASSERT(g_abort_done == true);
32437cd20dd3SShuhei Matsumoto 	CU_ASSERT(g_abort_status == SPDK_BDEV_IO_STATUS_FAILED);
32447cd20dd3SShuhei Matsumoto 
32457cd20dd3SShuhei Matsumoto 	/* Test the case that the target I/O was successfully aborted. */
32467cd20dd3SShuhei Matsumoto 	g_io_done = false;
32477cd20dd3SShuhei Matsumoto 
32487cd20dd3SShuhei Matsumoto 	rc = spdk_bdev_read_blocks(desc, io_ch, NULL, 0, 1, io_done, &io_ctx1);
32497cd20dd3SShuhei Matsumoto 	CU_ASSERT(rc == 0);
32507cd20dd3SShuhei Matsumoto 	CU_ASSERT(g_io_done == false);
32517cd20dd3SShuhei Matsumoto 
32527cd20dd3SShuhei Matsumoto 	g_abort_done = false;
32537cd20dd3SShuhei Matsumoto 	g_io_exp_status = SPDK_BDEV_IO_STATUS_SUCCESS;
32547cd20dd3SShuhei Matsumoto 
32557cd20dd3SShuhei Matsumoto 	rc = spdk_bdev_abort(desc, io_ch, &io_ctx1, abort_done, NULL);
32567cd20dd3SShuhei Matsumoto 	CU_ASSERT(rc == 0);
32577cd20dd3SShuhei Matsumoto 	CU_ASSERT(g_io_done == true);
32587cd20dd3SShuhei Matsumoto 	CU_ASSERT(g_io_status == SPDK_BDEV_IO_STATUS_FAILED);
32597cd20dd3SShuhei Matsumoto 	stub_complete_io(1);
32607cd20dd3SShuhei Matsumoto 	CU_ASSERT(g_abort_done == true);
32617cd20dd3SShuhei Matsumoto 	CU_ASSERT(g_abort_status == SPDK_BDEV_IO_STATUS_SUCCESS);
32627cd20dd3SShuhei Matsumoto 
32637cd20dd3SShuhei Matsumoto 	/* Test the case that the target I/O was not aborted because it completed
32647cd20dd3SShuhei Matsumoto 	 * in the middle of execution of the abort.
32657cd20dd3SShuhei Matsumoto 	 */
32667cd20dd3SShuhei Matsumoto 	g_io_done = false;
32677cd20dd3SShuhei Matsumoto 
32687cd20dd3SShuhei Matsumoto 	rc = spdk_bdev_read_blocks(desc, io_ch, NULL, 0, 1, io_done, &io_ctx1);
32697cd20dd3SShuhei Matsumoto 	CU_ASSERT(rc == 0);
32707cd20dd3SShuhei Matsumoto 	CU_ASSERT(g_io_done == false);
32717cd20dd3SShuhei Matsumoto 
32727cd20dd3SShuhei Matsumoto 	g_abort_done = false;
32737cd20dd3SShuhei Matsumoto 	g_io_exp_status = SPDK_BDEV_IO_STATUS_FAILED;
32747cd20dd3SShuhei Matsumoto 
32757cd20dd3SShuhei Matsumoto 	rc = spdk_bdev_abort(desc, io_ch, &io_ctx1, abort_done, NULL);
32767cd20dd3SShuhei Matsumoto 	CU_ASSERT(rc == 0);
32777cd20dd3SShuhei Matsumoto 	CU_ASSERT(g_io_done == false);
32787cd20dd3SShuhei Matsumoto 
32797cd20dd3SShuhei Matsumoto 	g_io_exp_status = SPDK_BDEV_IO_STATUS_SUCCESS;
32807cd20dd3SShuhei Matsumoto 	stub_complete_io(1);
32817cd20dd3SShuhei Matsumoto 	CU_ASSERT(g_io_done == true);
32827cd20dd3SShuhei Matsumoto 	CU_ASSERT(g_io_status == SPDK_BDEV_IO_STATUS_SUCCESS);
32837cd20dd3SShuhei Matsumoto 
32847cd20dd3SShuhei Matsumoto 	g_io_exp_status = SPDK_BDEV_IO_STATUS_FAILED;
32857cd20dd3SShuhei Matsumoto 	stub_complete_io(1);
32867cd20dd3SShuhei Matsumoto 	CU_ASSERT(g_abort_done == true);
32877cd20dd3SShuhei Matsumoto 	CU_ASSERT(g_abort_status == SPDK_BDEV_IO_STATUS_SUCCESS);
32887cd20dd3SShuhei Matsumoto 
32897cd20dd3SShuhei Matsumoto 	g_io_exp_status = SPDK_BDEV_IO_STATUS_SUCCESS;
32907cd20dd3SShuhei Matsumoto 
329197a5ea57SShuhei Matsumoto 	bdev->optimal_io_boundary = 16;
329297a5ea57SShuhei Matsumoto 	bdev->split_on_optimal_io_boundary = true;
329397a5ea57SShuhei Matsumoto 
329497a5ea57SShuhei Matsumoto 	/* Test that a single-vector command which is split is aborted correctly.
329597a5ea57SShuhei Matsumoto 	 * Offset 14, length 8, payload 0xF000
329697a5ea57SShuhei Matsumoto 	 *  Child - Offset 14, length 2, payload 0xF000
329797a5ea57SShuhei Matsumoto 	 *  Child - Offset 16, length 6, payload 0xF000 + 2 * 512
329897a5ea57SShuhei Matsumoto 	 */
329997a5ea57SShuhei Matsumoto 	g_io_done = false;
330097a5ea57SShuhei Matsumoto 
330197a5ea57SShuhei Matsumoto 	rc = spdk_bdev_read_blocks(desc, io_ch, (void *)0xF000, 14, 8, io_done, &io_ctx1);
330297a5ea57SShuhei Matsumoto 	CU_ASSERT(rc == 0);
330397a5ea57SShuhei Matsumoto 	CU_ASSERT(g_io_done == false);
330497a5ea57SShuhei Matsumoto 
330597a5ea57SShuhei Matsumoto 	CU_ASSERT(g_bdev_ut_channel->outstanding_io_count == 2);
330697a5ea57SShuhei Matsumoto 
330797a5ea57SShuhei Matsumoto 	g_io_exp_status = SPDK_BDEV_IO_STATUS_SUCCESS;
330897a5ea57SShuhei Matsumoto 
330997a5ea57SShuhei Matsumoto 	rc = spdk_bdev_abort(desc, io_ch, &io_ctx1, abort_done, NULL);
331097a5ea57SShuhei Matsumoto 	CU_ASSERT(rc == 0);
331197a5ea57SShuhei Matsumoto 	CU_ASSERT(g_io_done == true);
331297a5ea57SShuhei Matsumoto 	CU_ASSERT(g_io_status == SPDK_BDEV_IO_STATUS_FAILED);
331397a5ea57SShuhei Matsumoto 	stub_complete_io(2);
331497a5ea57SShuhei Matsumoto 	CU_ASSERT(g_abort_done == true);
331597a5ea57SShuhei Matsumoto 	CU_ASSERT(g_abort_status == SPDK_BDEV_IO_STATUS_SUCCESS);
331697a5ea57SShuhei Matsumoto 
331797a5ea57SShuhei Matsumoto 	/* Test that a multi-vector command that needs to be split by strip and then
331897a5ea57SShuhei Matsumoto 	 * needs to be split is aborted correctly. Abort is requested before the second
331997a5ea57SShuhei Matsumoto 	 * child I/O was submitted. The parent I/O should complete with failure without
332097a5ea57SShuhei Matsumoto 	 * submitting the second child I/O.
332197a5ea57SShuhei Matsumoto 	 */
332297a5ea57SShuhei Matsumoto 	for (i = 0; i < BDEV_IO_NUM_CHILD_IOV * 2; i++) {
332397a5ea57SShuhei Matsumoto 		iov[i].iov_base = (void *)((i + 1) * 0x10000);
332497a5ea57SShuhei Matsumoto 		iov[i].iov_len = 512;
332597a5ea57SShuhei Matsumoto 	}
332697a5ea57SShuhei Matsumoto 
332797a5ea57SShuhei Matsumoto 	bdev->optimal_io_boundary = BDEV_IO_NUM_CHILD_IOV;
332897a5ea57SShuhei Matsumoto 	g_io_done = false;
332997a5ea57SShuhei Matsumoto 	rc = spdk_bdev_readv_blocks(desc, io_ch, iov, BDEV_IO_NUM_CHILD_IOV * 2, 0,
333097a5ea57SShuhei Matsumoto 				    BDEV_IO_NUM_CHILD_IOV * 2, io_done, &io_ctx1);
333197a5ea57SShuhei Matsumoto 	CU_ASSERT(rc == 0);
333297a5ea57SShuhei Matsumoto 	CU_ASSERT(g_io_done == false);
333397a5ea57SShuhei Matsumoto 
333497a5ea57SShuhei Matsumoto 	CU_ASSERT(g_bdev_ut_channel->outstanding_io_count == 1);
333597a5ea57SShuhei Matsumoto 
333697a5ea57SShuhei Matsumoto 	g_io_exp_status = SPDK_BDEV_IO_STATUS_SUCCESS;
333797a5ea57SShuhei Matsumoto 
333897a5ea57SShuhei Matsumoto 	rc = spdk_bdev_abort(desc, io_ch, &io_ctx1, abort_done, NULL);
333997a5ea57SShuhei Matsumoto 	CU_ASSERT(rc == 0);
334097a5ea57SShuhei Matsumoto 	CU_ASSERT(g_io_done == true);
334197a5ea57SShuhei Matsumoto 	CU_ASSERT(g_io_status == SPDK_BDEV_IO_STATUS_FAILED);
334297a5ea57SShuhei Matsumoto 	stub_complete_io(1);
334397a5ea57SShuhei Matsumoto 	CU_ASSERT(g_abort_done == true);
334497a5ea57SShuhei Matsumoto 	CU_ASSERT(g_abort_status == SPDK_BDEV_IO_STATUS_SUCCESS);
334597a5ea57SShuhei Matsumoto 
334697a5ea57SShuhei Matsumoto 	g_io_exp_status = SPDK_BDEV_IO_STATUS_SUCCESS;
334797a5ea57SShuhei Matsumoto 
334897a5ea57SShuhei Matsumoto 	CU_ASSERT(g_bdev_ut_channel->outstanding_io_count == 0);
334997a5ea57SShuhei Matsumoto 
335097a5ea57SShuhei Matsumoto 	bdev->optimal_io_boundary = 16;
335197a5ea57SShuhei Matsumoto 	g_io_done = false;
335297a5ea57SShuhei Matsumoto 
335397a5ea57SShuhei Matsumoto 	/* Test that a ingle-vector command which is split is aborted correctly.
335497a5ea57SShuhei Matsumoto 	 * Differently from the above, the child abort request will be submitted
335597a5ea57SShuhei Matsumoto 	 * sequentially due to the capacity of spdk_bdev_io.
335697a5ea57SShuhei Matsumoto 	 */
335797a5ea57SShuhei Matsumoto 	rc = spdk_bdev_read_blocks(desc, io_ch, (void *)0xF000, 14, 50, io_done, &io_ctx1);
335897a5ea57SShuhei Matsumoto 	CU_ASSERT(rc == 0);
335997a5ea57SShuhei Matsumoto 	CU_ASSERT(g_io_done == false);
336097a5ea57SShuhei Matsumoto 
336197a5ea57SShuhei Matsumoto 	CU_ASSERT(g_bdev_ut_channel->outstanding_io_count == 4);
336297a5ea57SShuhei Matsumoto 
336397a5ea57SShuhei Matsumoto 	g_abort_done = false;
336497a5ea57SShuhei Matsumoto 	g_io_exp_status = SPDK_BDEV_IO_STATUS_SUCCESS;
336597a5ea57SShuhei Matsumoto 
336697a5ea57SShuhei Matsumoto 	rc = spdk_bdev_abort(desc, io_ch, &io_ctx1, abort_done, NULL);
336797a5ea57SShuhei Matsumoto 	CU_ASSERT(rc == 0);
336897a5ea57SShuhei Matsumoto 	CU_ASSERT(!TAILQ_EMPTY(&mgmt_ch->io_wait_queue));
336997a5ea57SShuhei Matsumoto 	CU_ASSERT(g_bdev_ut_channel->outstanding_io_count == 4);
337097a5ea57SShuhei Matsumoto 
337197a5ea57SShuhei Matsumoto 	stub_complete_io(1);
337297a5ea57SShuhei Matsumoto 	CU_ASSERT(g_io_done == true);
337397a5ea57SShuhei Matsumoto 	CU_ASSERT(g_io_status == SPDK_BDEV_IO_STATUS_FAILED);
337497a5ea57SShuhei Matsumoto 	stub_complete_io(3);
337597a5ea57SShuhei Matsumoto 	CU_ASSERT(g_abort_done == true);
337697a5ea57SShuhei Matsumoto 	CU_ASSERT(g_abort_status == SPDK_BDEV_IO_STATUS_SUCCESS);
337797a5ea57SShuhei Matsumoto 
337897a5ea57SShuhei Matsumoto 	g_io_exp_status = SPDK_BDEV_IO_STATUS_SUCCESS;
337997a5ea57SShuhei Matsumoto 
338097a5ea57SShuhei Matsumoto 	CU_ASSERT(g_bdev_ut_channel->outstanding_io_count == 0);
338197a5ea57SShuhei Matsumoto 
33827cd20dd3SShuhei Matsumoto 	spdk_put_io_channel(io_ch);
33837cd20dd3SShuhei Matsumoto 	spdk_bdev_close(desc);
33847cd20dd3SShuhei Matsumoto 	free_bdev(bdev);
33857cd20dd3SShuhei Matsumoto 	spdk_bdev_finish(bdev_fini_cb, NULL);
33867cd20dd3SShuhei Matsumoto 	poll_threads();
33877cd20dd3SShuhei Matsumoto }
33887cd20dd3SShuhei Matsumoto 
33894ee51dcbSJim Harris int
33904ee51dcbSJim Harris main(int argc, char **argv)
33914ee51dcbSJim Harris {
33924ee51dcbSJim Harris 	CU_pSuite		suite = NULL;
33934ee51dcbSJim Harris 	unsigned int		num_failures;
33944ee51dcbSJim Harris 
339578b696bcSVitaliy Mysak 	CU_set_error_action(CUEA_ABORT);
339678b696bcSVitaliy Mysak 	CU_initialize_registry();
33974ee51dcbSJim Harris 
33984ee51dcbSJim Harris 	suite = CU_add_suite("bdev", null_init, null_clean);
33994ee51dcbSJim Harris 
3400dcf0ca15SVitaliy Mysak 	CU_ADD_TEST(suite, bytes_to_blocks_test);
3401dcf0ca15SVitaliy Mysak 	CU_ADD_TEST(suite, num_blocks_test);
3402dcf0ca15SVitaliy Mysak 	CU_ADD_TEST(suite, io_valid_test);
3403dcf0ca15SVitaliy Mysak 	CU_ADD_TEST(suite, open_write_test);
3404dcf0ca15SVitaliy Mysak 	CU_ADD_TEST(suite, alias_add_del_test);
3405dcf0ca15SVitaliy Mysak 	CU_ADD_TEST(suite, get_device_stat_test);
3406dcf0ca15SVitaliy Mysak 	CU_ADD_TEST(suite, bdev_io_types_test);
3407dcf0ca15SVitaliy Mysak 	CU_ADD_TEST(suite, bdev_io_wait_test);
3408dcf0ca15SVitaliy Mysak 	CU_ADD_TEST(suite, bdev_io_spans_boundary_test);
3409dcf0ca15SVitaliy Mysak 	CU_ADD_TEST(suite, bdev_io_split_test);
3410dcf0ca15SVitaliy Mysak 	CU_ADD_TEST(suite, bdev_io_split_with_io_wait);
3411dcf0ca15SVitaliy Mysak 	CU_ADD_TEST(suite, bdev_io_alignment_with_boundary);
3412dcf0ca15SVitaliy Mysak 	CU_ADD_TEST(suite, bdev_io_alignment);
3413dcf0ca15SVitaliy Mysak 	CU_ADD_TEST(suite, bdev_histograms);
3414dcf0ca15SVitaliy Mysak 	CU_ADD_TEST(suite, bdev_write_zeroes);
3415dcf0ca15SVitaliy Mysak 	CU_ADD_TEST(suite, bdev_compare_and_write);
3416dcf0ca15SVitaliy Mysak 	CU_ADD_TEST(suite, bdev_compare);
3417dcf0ca15SVitaliy Mysak 	CU_ADD_TEST(suite, bdev_open_while_hotremove);
3418dcf0ca15SVitaliy Mysak 	CU_ADD_TEST(suite, bdev_close_while_hotremove);
3419dcf0ca15SVitaliy Mysak 	CU_ADD_TEST(suite, bdev_open_ext);
3420dcf0ca15SVitaliy Mysak 	CU_ADD_TEST(suite, bdev_set_io_timeout);
3421dcf0ca15SVitaliy Mysak 	CU_ADD_TEST(suite, lba_range_overlap);
3422dcf0ca15SVitaliy Mysak 	CU_ADD_TEST(suite, lock_lba_range_check_ranges);
3423dcf0ca15SVitaliy Mysak 	CU_ADD_TEST(suite, lock_lba_range_with_io_outstanding);
3424dcf0ca15SVitaliy Mysak 	CU_ADD_TEST(suite, lock_lba_range_overlapped);
34257cd20dd3SShuhei Matsumoto 	CU_ADD_TEST(suite, bdev_io_abort);
34264ee51dcbSJim Harris 
3427972b3ae3SShuhei Matsumoto 	allocate_cores(1);
3428270a25dfSBen Walker 	allocate_threads(1);
3429270a25dfSBen Walker 	set_thread(0);
3430270a25dfSBen Walker 
34314ee51dcbSJim Harris 	CU_basic_set_mode(CU_BRM_VERBOSE);
34324ee51dcbSJim Harris 	CU_basic_run_tests();
34334ee51dcbSJim Harris 	num_failures = CU_get_number_of_failures();
34344ee51dcbSJim Harris 	CU_cleanup_registry();
3435270a25dfSBen Walker 
3436270a25dfSBen Walker 	free_threads();
3437972b3ae3SShuhei Matsumoto 	free_cores();
3438270a25dfSBen Walker 
34394ee51dcbSJim Harris 	return num_failures;
34404ee51dcbSJim Harris }
3441