xref: /spdk/test/unit/lib/blob/blob_bdev.c/blob_bdev_ut.c (revision 2dc4a231ac65d10dd2e1a96684094bef1b7ebb95)
1c74b8b60SMike Gerdts /*   SPDX-License-Identifier: BSD-3-Clause
2c74b8b60SMike Gerdts  *   Copyright (c) 2023 NVIDIA CORPORATION & AFFILIATES. All rights reserved.
3c74b8b60SMike Gerdts  */
4c74b8b60SMike Gerdts 
5c74b8b60SMike Gerdts #include "spdk/stdinc.h"
6c74b8b60SMike Gerdts 
7ae431e31SKonrad Sztyber #include "spdk_internal/cunit.h"
8421fb110SMike Gerdts #include "common/lib/ut_multithread.c"
9421fb110SMike Gerdts 
10421fb110SMike Gerdts static void ut_put_io_channel(struct spdk_io_channel *ch);
11421fb110SMike Gerdts 
12421fb110SMike Gerdts #define spdk_put_io_channel(ch) ut_put_io_channel(ch);
13c74b8b60SMike Gerdts #include "blob/bdev/blob_bdev.c"
14c74b8b60SMike Gerdts 
15c74b8b60SMike Gerdts DEFINE_STUB(spdk_bdev_io_type_supported, bool, (struct spdk_bdev *bdev,
16c74b8b60SMike Gerdts 		enum spdk_bdev_io_type io_type), false);
17c74b8b60SMike Gerdts DEFINE_STUB_V(spdk_bdev_free_io, (struct spdk_bdev_io *g_bdev_io));
18c74b8b60SMike Gerdts DEFINE_STUB(spdk_bdev_queue_io_wait, int,
19c74b8b60SMike Gerdts 	    (struct spdk_bdev *bdev, struct spdk_io_channel *ch,
20c74b8b60SMike Gerdts 	     struct spdk_bdev_io_wait_entry *entry), 0);
21c74b8b60SMike Gerdts DEFINE_STUB(spdk_bdev_read_blocks, int,
22c74b8b60SMike Gerdts 	    (struct spdk_bdev_desc *desc, struct spdk_io_channel *ch, void *buf,
23c74b8b60SMike Gerdts 	     uint64_t offset_blocks, uint64_t num_blocks, spdk_bdev_io_completion_cb cb,
24c74b8b60SMike Gerdts 	     void *cb_arg), 0);
25c74b8b60SMike Gerdts DEFINE_STUB(spdk_bdev_write_blocks, int,
26c74b8b60SMike Gerdts 	    (struct spdk_bdev_desc *desc, struct spdk_io_channel *ch, void *buf,
27c74b8b60SMike Gerdts 	     uint64_t offset_blocks, uint64_t num_blocks, spdk_bdev_io_completion_cb cb,
28c74b8b60SMike Gerdts 	     void *cb_arg), 0);
29c74b8b60SMike Gerdts DEFINE_STUB(spdk_bdev_readv_blocks, int,
30c74b8b60SMike Gerdts 	    (struct spdk_bdev_desc *desc, struct spdk_io_channel *ch, struct iovec *iov, int iovcnt,
31c74b8b60SMike Gerdts 	     uint64_t offset_blocks, uint64_t num_blocks, spdk_bdev_io_completion_cb cb,
32c74b8b60SMike Gerdts 	     void *cb_arg), 0);
33c74b8b60SMike Gerdts DEFINE_STUB(spdk_bdev_writev_blocks, int,
34c74b8b60SMike Gerdts 	    (struct spdk_bdev_desc *desc, struct spdk_io_channel *ch, struct iovec *iov, int iovcnt,
35c74b8b60SMike Gerdts 	     uint64_t offset_blocks, uint64_t num_blocks, spdk_bdev_io_completion_cb cb,
36c74b8b60SMike Gerdts 	     void *cb_arg), 0);
37c74b8b60SMike Gerdts DEFINE_STUB(spdk_bdev_readv_blocks_ext, int,
38c74b8b60SMike Gerdts 	    (struct spdk_bdev_desc *desc, struct spdk_io_channel *ch, struct iovec *iov, int iovcnt,
39c74b8b60SMike Gerdts 	     uint64_t offset_blocks, uint64_t num_blocks, spdk_bdev_io_completion_cb cb,
40c74b8b60SMike Gerdts 	     void *cb_arg, struct spdk_bdev_ext_io_opts *opts), 0);
41c74b8b60SMike Gerdts DEFINE_STUB(spdk_bdev_writev_blocks_ext, int,
42c74b8b60SMike Gerdts 	    (struct spdk_bdev_desc *desc, struct spdk_io_channel *ch, struct iovec *iov, int iovcnt,
43c74b8b60SMike Gerdts 	     uint64_t offset_blocks, uint64_t num_blocks, spdk_bdev_io_completion_cb cb,
44c74b8b60SMike Gerdts 	     void *cb_arg, struct spdk_bdev_ext_io_opts *opts), 0);
45c74b8b60SMike Gerdts DEFINE_STUB(spdk_bdev_write_zeroes_blocks, int,
46c74b8b60SMike Gerdts 	    (struct spdk_bdev_desc *desc, struct spdk_io_channel *ch, uint64_t offset_blocks,
47c74b8b60SMike Gerdts 	     uint64_t num_blocks, spdk_bdev_io_completion_cb cb, void *cb_arg), 0);
48c74b8b60SMike Gerdts DEFINE_STUB(spdk_bdev_unmap_blocks, int,
49c74b8b60SMike Gerdts 	    (struct spdk_bdev_desc *desc, struct spdk_io_channel *ch, uint64_t offset_blocks,
50c74b8b60SMike Gerdts 	     uint64_t num_blocks, spdk_bdev_io_completion_cb cb, void *cb_arg), 0);
51c74b8b60SMike Gerdts DEFINE_STUB(spdk_bdev_copy_blocks, int,
52c74b8b60SMike Gerdts 	    (struct spdk_bdev_desc *desc, struct spdk_io_channel *ch, uint64_t dst_offset_blocks,
53c74b8b60SMike Gerdts 	     uint64_t src_offset_blocks, uint64_t num_blocks, spdk_bdev_io_completion_cb cb,
54c74b8b60SMike Gerdts 	     void *cb_arg), 0);
55c74b8b60SMike Gerdts 
56c74b8b60SMike Gerdts struct spdk_bdev {
57c74b8b60SMike Gerdts 	char name[16];
58c74b8b60SMike Gerdts 	uint64_t blockcnt;
59c74b8b60SMike Gerdts 	uint32_t blocklen;
60*2dc4a231SAtul Malakar 	uint32_t phys_blocklen;
61c74b8b60SMike Gerdts 	uint32_t open_cnt;
62e52b6c0dSMike Gerdts 	enum spdk_bdev_claim_type claim_type;
63e52b6c0dSMike Gerdts 	struct spdk_bdev_module *claim_module;
64f246b2d5SMike Gerdts 	struct spdk_bdev_desc *claim_desc;
65c74b8b60SMike Gerdts };
66c74b8b60SMike Gerdts 
67c74b8b60SMike Gerdts struct spdk_bdev_desc {
68c74b8b60SMike Gerdts 	struct spdk_bdev *bdev;
69e52b6c0dSMike Gerdts 	bool write;
70f246b2d5SMike Gerdts 	enum spdk_bdev_claim_type claim_type;
71421fb110SMike Gerdts 	struct spdk_thread *thread;
72c74b8b60SMike Gerdts };
73c74b8b60SMike Gerdts 
74c74b8b60SMike Gerdts struct spdk_bdev *g_bdev;
75c74b8b60SMike Gerdts 
76e52b6c0dSMike Gerdts static struct spdk_bdev_module g_bdev_mod = {
77e52b6c0dSMike Gerdts 	.name = "blob_bdev_ut"
78e52b6c0dSMike Gerdts };
79e52b6c0dSMike Gerdts 
80421fb110SMike Gerdts struct spdk_io_channel *
81421fb110SMike Gerdts spdk_bdev_get_io_channel(struct spdk_bdev_desc *desc)
82421fb110SMike Gerdts {
83421fb110SMike Gerdts 	if (desc != NULL) {
84421fb110SMike Gerdts 		return (struct spdk_io_channel *)0x1;
85421fb110SMike Gerdts 	}
86421fb110SMike Gerdts 	return NULL;
87421fb110SMike Gerdts }
88421fb110SMike Gerdts 
89421fb110SMike Gerdts static void
90421fb110SMike Gerdts ut_put_io_channel(struct spdk_io_channel *ch)
91421fb110SMike Gerdts {
92421fb110SMike Gerdts }
93421fb110SMike Gerdts 
94c74b8b60SMike Gerdts static struct spdk_bdev *
95c74b8b60SMike Gerdts get_bdev(const char *bdev_name)
96c74b8b60SMike Gerdts {
97c74b8b60SMike Gerdts 	if (g_bdev == NULL) {
98c74b8b60SMike Gerdts 		return NULL;
99c74b8b60SMike Gerdts 	}
100c74b8b60SMike Gerdts 
101c74b8b60SMike Gerdts 	if (strcmp(bdev_name, g_bdev->name) != 0) {
102c74b8b60SMike Gerdts 		return NULL;
103c74b8b60SMike Gerdts 	}
104c74b8b60SMike Gerdts 
105c74b8b60SMike Gerdts 	return g_bdev;
106c74b8b60SMike Gerdts }
107c74b8b60SMike Gerdts 
108c74b8b60SMike Gerdts int
109c74b8b60SMike Gerdts spdk_bdev_open_ext(const char *bdev_name, bool write, spdk_bdev_event_cb_t event_cb,
110c74b8b60SMike Gerdts 		   void *event_ctx, struct spdk_bdev_desc **_desc)
111c74b8b60SMike Gerdts {
112c74b8b60SMike Gerdts 	struct spdk_bdev_desc *desc;
113c74b8b60SMike Gerdts 	struct spdk_bdev *bdev = get_bdev(bdev_name);
114c74b8b60SMike Gerdts 
115c74b8b60SMike Gerdts 	if (bdev == NULL) {
116c74b8b60SMike Gerdts 		return -ENODEV;
117c74b8b60SMike Gerdts 	}
118c74b8b60SMike Gerdts 
119e52b6c0dSMike Gerdts 	if (write && bdev->claim_module != NULL) {
120e52b6c0dSMike Gerdts 		return -EPERM;
121e52b6c0dSMike Gerdts 	}
122e52b6c0dSMike Gerdts 
123c74b8b60SMike Gerdts 	desc = calloc(1, sizeof(*desc));
124c74b8b60SMike Gerdts 	desc->bdev = g_bdev;
125e52b6c0dSMike Gerdts 	desc->write = write;
126421fb110SMike Gerdts 	desc->thread = spdk_get_thread();
127c74b8b60SMike Gerdts 	*_desc = desc;
128c74b8b60SMike Gerdts 	bdev->open_cnt++;
129c74b8b60SMike Gerdts 
130c74b8b60SMike Gerdts 	return 0;
131c74b8b60SMike Gerdts }
132c74b8b60SMike Gerdts 
133c74b8b60SMike Gerdts void
134c74b8b60SMike Gerdts spdk_bdev_close(struct spdk_bdev_desc *desc)
135c74b8b60SMike Gerdts {
136c74b8b60SMike Gerdts 	struct spdk_bdev *bdev = desc->bdev;
137c74b8b60SMike Gerdts 
138421fb110SMike Gerdts 	CU_ASSERT(desc->thread == spdk_get_thread());
139421fb110SMike Gerdts 
140c74b8b60SMike Gerdts 	bdev->open_cnt--;
141f246b2d5SMike Gerdts 	if (bdev->claim_desc == desc) {
142f246b2d5SMike Gerdts 		bdev->claim_desc = NULL;
143f246b2d5SMike Gerdts 		bdev->claim_type = SPDK_BDEV_CLAIM_NONE;
144f246b2d5SMike Gerdts 		bdev->claim_module = NULL;
145f246b2d5SMike Gerdts 	}
146c74b8b60SMike Gerdts 	free(desc);
147c74b8b60SMike Gerdts }
148c74b8b60SMike Gerdts 
149c74b8b60SMike Gerdts struct spdk_bdev *
150c74b8b60SMike Gerdts spdk_bdev_desc_get_bdev(struct spdk_bdev_desc *desc)
151c74b8b60SMike Gerdts {
152c74b8b60SMike Gerdts 	return desc->bdev;
153c74b8b60SMike Gerdts }
154c74b8b60SMike Gerdts 
155c74b8b60SMike Gerdts uint64_t
156c74b8b60SMike Gerdts spdk_bdev_get_num_blocks(const struct spdk_bdev *bdev)
157c74b8b60SMike Gerdts {
158c74b8b60SMike Gerdts 	return bdev->blockcnt;
159c74b8b60SMike Gerdts }
160c74b8b60SMike Gerdts 
161c74b8b60SMike Gerdts uint32_t
162c74b8b60SMike Gerdts spdk_bdev_get_block_size(const struct spdk_bdev *bdev)
163c74b8b60SMike Gerdts {
164c74b8b60SMike Gerdts 	return bdev->blocklen;
165c74b8b60SMike Gerdts }
166c74b8b60SMike Gerdts 
167*2dc4a231SAtul Malakar uint32_t
168*2dc4a231SAtul Malakar spdk_bdev_get_physical_block_size(const struct spdk_bdev *bdev)
169*2dc4a231SAtul Malakar {
170*2dc4a231SAtul Malakar 	return bdev->phys_blocklen;
171*2dc4a231SAtul Malakar }
172*2dc4a231SAtul Malakar 
173f246b2d5SMike Gerdts /* This is a simple approximation: it does not support shared claims */
174e52b6c0dSMike Gerdts int
175f246b2d5SMike Gerdts spdk_bdev_module_claim_bdev_desc(struct spdk_bdev_desc *desc, enum spdk_bdev_claim_type type,
176f246b2d5SMike Gerdts 				 struct spdk_bdev_claim_opts *opts,
177e52b6c0dSMike Gerdts 				 struct spdk_bdev_module *module)
178e52b6c0dSMike Gerdts {
179f246b2d5SMike Gerdts 	struct spdk_bdev *bdev = desc->bdev;
180f246b2d5SMike Gerdts 
181e52b6c0dSMike Gerdts 	if (bdev->claim_module != NULL) {
182e52b6c0dSMike Gerdts 		return -EPERM;
183e52b6c0dSMike Gerdts 	}
184e52b6c0dSMike Gerdts 
185f246b2d5SMike Gerdts 	bdev->claim_type = type;
186e52b6c0dSMike Gerdts 	bdev->claim_module = module;
187f246b2d5SMike Gerdts 	bdev->claim_desc = desc;
188f246b2d5SMike Gerdts 
189f246b2d5SMike Gerdts 	desc->claim_type = type;
190e52b6c0dSMike Gerdts 
191e52b6c0dSMike Gerdts 	return 0;
192e52b6c0dSMike Gerdts }
193e52b6c0dSMike Gerdts 
194c74b8b60SMike Gerdts static void
195c74b8b60SMike Gerdts init_bdev(struct spdk_bdev *bdev, const char *name, uint64_t num_blocks)
196c74b8b60SMike Gerdts {
197c74b8b60SMike Gerdts 	memset(bdev, 0, sizeof(*bdev));
198c74b8b60SMike Gerdts 	snprintf(bdev->name, sizeof(bdev->name), "%s", name);
199c74b8b60SMike Gerdts 	bdev->blockcnt = num_blocks;
200c74b8b60SMike Gerdts }
201c74b8b60SMike Gerdts 
202c74b8b60SMike Gerdts static void
203c74b8b60SMike Gerdts create_bs_dev(void)
204c74b8b60SMike Gerdts {
205c74b8b60SMike Gerdts 	struct spdk_bdev bdev;
206c74b8b60SMike Gerdts 	struct spdk_bs_dev *bs_dev = NULL;
207c74b8b60SMike Gerdts 	struct blob_bdev *blob_bdev;
208c74b8b60SMike Gerdts 	int rc;
209c74b8b60SMike Gerdts 
210c74b8b60SMike Gerdts 	init_bdev(&bdev, "bdev0", 16);
211c74b8b60SMike Gerdts 	g_bdev = &bdev;
212c74b8b60SMike Gerdts 
213c74b8b60SMike Gerdts 	rc = spdk_bdev_create_bs_dev_ext("bdev0", NULL, NULL, &bs_dev);
214c74b8b60SMike Gerdts 	CU_ASSERT(rc == 0);
215c74b8b60SMike Gerdts 	SPDK_CU_ASSERT_FATAL(bs_dev != NULL);
216c74b8b60SMike Gerdts 	CU_ASSERT(bdev.open_cnt == 1);
217c74b8b60SMike Gerdts 
218c74b8b60SMike Gerdts 	blob_bdev = (struct blob_bdev *)bs_dev;
219c74b8b60SMike Gerdts 	CU_ASSERT(blob_bdev->desc != NULL);
220bd5a7847SMike Gerdts 	CU_ASSERT(blob_bdev->desc->write);
221bd5a7847SMike Gerdts 	CU_ASSERT(blob_bdev->desc->bdev == g_bdev);
222bd5a7847SMike Gerdts 	CU_ASSERT(blob_bdev->desc->claim_type == SPDK_BDEV_CLAIM_NONE);
223bd5a7847SMike Gerdts 	CU_ASSERT(bdev.claim_type == SPDK_BDEV_CLAIM_NONE);
224bd5a7847SMike Gerdts 
225bd5a7847SMike Gerdts 	bs_dev->destroy(bs_dev);
226bd5a7847SMike Gerdts 	CU_ASSERT(bdev.open_cnt == 0);
227bd5a7847SMike Gerdts 	g_bdev = NULL;
228bd5a7847SMike Gerdts }
229bd5a7847SMike Gerdts 
230bd5a7847SMike Gerdts static void
231bd5a7847SMike Gerdts create_bs_dev_ro(void)
232bd5a7847SMike Gerdts {
233bd5a7847SMike Gerdts 	struct spdk_bdev bdev;
234bd5a7847SMike Gerdts 	struct spdk_bs_dev *bs_dev = NULL;
235bd5a7847SMike Gerdts 	struct blob_bdev *blob_bdev;
236bd5a7847SMike Gerdts 	struct spdk_bdev_bs_dev_opts opts = { 0 };
237bd5a7847SMike Gerdts 	int rc;
238bd5a7847SMike Gerdts 
239bd5a7847SMike Gerdts 	/* opts with the wrong size returns -EINVAL */
240bd5a7847SMike Gerdts 	rc = spdk_bdev_create_bs_dev("nope", false, &opts, sizeof(opts) + 8, NULL, NULL, &bs_dev);
241bd5a7847SMike Gerdts 	CU_ASSERT(rc == -EINVAL);
242bd5a7847SMike Gerdts 
243bd5a7847SMike Gerdts 	/* opts with the right size is OK, but can still fail if the device doesn't exist. */
244bd5a7847SMike Gerdts 	opts.opts_size = sizeof(opts);
245bd5a7847SMike Gerdts 	rc = spdk_bdev_create_bs_dev("nope", false, &opts, sizeof(opts), NULL, NULL, &bs_dev);
246bd5a7847SMike Gerdts 	CU_ASSERT(rc == -ENODEV);
247bd5a7847SMike Gerdts 
248bd5a7847SMike Gerdts 	init_bdev(&bdev, "bdev0", 16);
249bd5a7847SMike Gerdts 	g_bdev = &bdev;
250bd5a7847SMike Gerdts 
251bd5a7847SMike Gerdts 	/* The normal way to create a read-only device */
252bd5a7847SMike Gerdts 	rc = spdk_bdev_create_bs_dev("bdev0", false, NULL, 0, NULL, NULL, &bs_dev);
253bd5a7847SMike Gerdts 	CU_ASSERT(rc == 0);
254bd5a7847SMike Gerdts 	SPDK_CU_ASSERT_FATAL(bs_dev != NULL);
255bd5a7847SMike Gerdts 	CU_ASSERT(bdev.open_cnt == 1);
256bd5a7847SMike Gerdts 
257bd5a7847SMike Gerdts 	blob_bdev = (struct blob_bdev *)bs_dev;
258bd5a7847SMike Gerdts 	CU_ASSERT(blob_bdev->desc != NULL);
259bd5a7847SMike Gerdts 	CU_ASSERT(!blob_bdev->desc->write);
260bd5a7847SMike Gerdts 	CU_ASSERT(blob_bdev->desc->bdev == g_bdev);
261bd5a7847SMike Gerdts 	CU_ASSERT(blob_bdev->desc->claim_type == SPDK_BDEV_CLAIM_NONE);
262bd5a7847SMike Gerdts 	CU_ASSERT(bdev.claim_type == SPDK_BDEV_CLAIM_NONE);
263bd5a7847SMike Gerdts 
264bd5a7847SMike Gerdts 	bs_dev->destroy(bs_dev);
265bd5a7847SMike Gerdts 	CU_ASSERT(bdev.open_cnt == 0);
266bd5a7847SMike Gerdts 	g_bdev = NULL;
267bd5a7847SMike Gerdts }
268bd5a7847SMike Gerdts 
269bd5a7847SMike Gerdts static void
270bd5a7847SMike Gerdts create_bs_dev_rw(void)
271bd5a7847SMike Gerdts {
272bd5a7847SMike Gerdts 	struct spdk_bdev bdev;
273bd5a7847SMike Gerdts 	struct spdk_bs_dev *bs_dev = NULL;
274bd5a7847SMike Gerdts 	struct blob_bdev *blob_bdev;
275bd5a7847SMike Gerdts 	int rc;
276bd5a7847SMike Gerdts 
277bd5a7847SMike Gerdts 	init_bdev(&bdev, "bdev0", 16);
278bd5a7847SMike Gerdts 	g_bdev = &bdev;
279bd5a7847SMike Gerdts 
280bd5a7847SMike Gerdts 	/* This is equivalent to spdk_bdev_create_bs_dev_ext() */
281bd5a7847SMike Gerdts 	rc = spdk_bdev_create_bs_dev("bdev0", true, NULL, 0, NULL, NULL, &bs_dev);
282bd5a7847SMike Gerdts 	CU_ASSERT(rc == 0);
283bd5a7847SMike Gerdts 	SPDK_CU_ASSERT_FATAL(bs_dev != NULL);
284bd5a7847SMike Gerdts 	CU_ASSERT(bdev.open_cnt == 1);
285bd5a7847SMike Gerdts 
286bd5a7847SMike Gerdts 	blob_bdev = (struct blob_bdev *)bs_dev;
287bd5a7847SMike Gerdts 	CU_ASSERT(blob_bdev->desc != NULL);
288bd5a7847SMike Gerdts 	CU_ASSERT(blob_bdev->desc->write);
289c74b8b60SMike Gerdts 	CU_ASSERT(blob_bdev->desc->bdev == g_bdev);
290f246b2d5SMike Gerdts 	CU_ASSERT(blob_bdev->desc->claim_type == SPDK_BDEV_CLAIM_NONE);
291f246b2d5SMike Gerdts 	CU_ASSERT(bdev.claim_type == SPDK_BDEV_CLAIM_NONE);
292c74b8b60SMike Gerdts 
293c74b8b60SMike Gerdts 	bs_dev->destroy(bs_dev);
294c74b8b60SMike Gerdts 	CU_ASSERT(bdev.open_cnt == 0);
295c74b8b60SMike Gerdts 	g_bdev = NULL;
296c74b8b60SMike Gerdts }
297c74b8b60SMike Gerdts 
298e52b6c0dSMike Gerdts static void
299e52b6c0dSMike Gerdts claim_bs_dev(void)
300e52b6c0dSMike Gerdts {
301e52b6c0dSMike Gerdts 	struct spdk_bdev bdev;
302e52b6c0dSMike Gerdts 	struct spdk_bs_dev *bs_dev = NULL, *bs_dev2 = NULL;
303e52b6c0dSMike Gerdts 	struct blob_bdev *blob_bdev;
304e52b6c0dSMike Gerdts 	int rc;
305e52b6c0dSMike Gerdts 
306e52b6c0dSMike Gerdts 	init_bdev(&bdev, "bdev0", 16);
307e52b6c0dSMike Gerdts 	g_bdev = &bdev;
308e52b6c0dSMike Gerdts 
309e52b6c0dSMike Gerdts 	rc = spdk_bdev_create_bs_dev_ext("bdev0", NULL, NULL, &bs_dev);
310e52b6c0dSMike Gerdts 	CU_ASSERT(rc == 0);
311e52b6c0dSMike Gerdts 	SPDK_CU_ASSERT_FATAL(bs_dev != NULL);
312e52b6c0dSMike Gerdts 
313e52b6c0dSMike Gerdts 	blob_bdev = (struct blob_bdev *)bs_dev;
314f246b2d5SMike Gerdts 	CU_ASSERT(blob_bdev->desc->claim_type == SPDK_BDEV_CLAIM_NONE);
315f246b2d5SMike Gerdts 	CU_ASSERT(bdev.claim_type == SPDK_BDEV_CLAIM_NONE);
316e52b6c0dSMike Gerdts 	CU_ASSERT(blob_bdev->desc->write);
317e52b6c0dSMike Gerdts 
318e52b6c0dSMike Gerdts 	/* Can get an exclusive write claim */
319e52b6c0dSMike Gerdts 	rc = spdk_bs_bdev_claim(bs_dev, &g_bdev_mod);
320e52b6c0dSMike Gerdts 	CU_ASSERT(rc == 0);
321e52b6c0dSMike Gerdts 	CU_ASSERT(blob_bdev->desc->write);
322f246b2d5SMike Gerdts 	CU_ASSERT(bdev.claim_type == SPDK_BDEV_CLAIM_READ_MANY_WRITE_ONE);
323f246b2d5SMike Gerdts 	CU_ASSERT(bdev.claim_desc == blob_bdev->desc);
324e52b6c0dSMike Gerdts 
325e52b6c0dSMike Gerdts 	/* Claim blocks a second writer without messing up the first one. */
326e52b6c0dSMike Gerdts 	rc = spdk_bdev_create_bs_dev_ext("bdev0", NULL, NULL, &bs_dev2);
327e52b6c0dSMike Gerdts 	CU_ASSERT(rc == -EPERM);
328f246b2d5SMike Gerdts 	CU_ASSERT(bdev.claim_type == SPDK_BDEV_CLAIM_READ_MANY_WRITE_ONE);
329f246b2d5SMike Gerdts 	CU_ASSERT(bdev.claim_desc == blob_bdev->desc);
330e52b6c0dSMike Gerdts 
331e52b6c0dSMike Gerdts 	/* Claim blocks a second claim without messing up the first one. */
332e52b6c0dSMike Gerdts 	rc = spdk_bs_bdev_claim(bs_dev, &g_bdev_mod);
333e52b6c0dSMike Gerdts 	CU_ASSERT(rc == -EPERM);
334f246b2d5SMike Gerdts 	CU_ASSERT(bdev.claim_type == SPDK_BDEV_CLAIM_READ_MANY_WRITE_ONE);
335f246b2d5SMike Gerdts 	CU_ASSERT(bdev.claim_desc == blob_bdev->desc);
336e52b6c0dSMike Gerdts 
337e52b6c0dSMike Gerdts 	bs_dev->destroy(bs_dev);
338e52b6c0dSMike Gerdts 	CU_ASSERT(bdev.open_cnt == 0);
339e52b6c0dSMike Gerdts 	CU_ASSERT(bdev.claim_type == SPDK_BDEV_CLAIM_NONE);
340e52b6c0dSMike Gerdts 	CU_ASSERT(bdev.claim_module == NULL);
341f246b2d5SMike Gerdts 	CU_ASSERT(bdev.claim_desc == NULL);
342e52b6c0dSMike Gerdts 	g_bdev = NULL;
343e52b6c0dSMike Gerdts }
344e52b6c0dSMike Gerdts 
345ab2eff07SMike Gerdts static void
346ab2eff07SMike Gerdts claim_bs_dev_ro(void)
347ab2eff07SMike Gerdts {
348ab2eff07SMike Gerdts 	struct spdk_bdev bdev;
349ab2eff07SMike Gerdts 	struct spdk_bs_dev *bs_dev = NULL, *bs_dev2 = NULL;
350ab2eff07SMike Gerdts 	struct blob_bdev *blob_bdev;
351ab2eff07SMike Gerdts 	int rc;
352ab2eff07SMike Gerdts 
353ab2eff07SMike Gerdts 	init_bdev(&bdev, "bdev0", 16);
354ab2eff07SMike Gerdts 	g_bdev = &bdev;
355ab2eff07SMike Gerdts 
356ab2eff07SMike Gerdts 	rc = spdk_bdev_create_bs_dev("bdev0", false, NULL, 0, NULL, NULL, &bs_dev);
357ab2eff07SMike Gerdts 	CU_ASSERT(rc == 0);
358ab2eff07SMike Gerdts 	SPDK_CU_ASSERT_FATAL(bs_dev != NULL);
359ab2eff07SMike Gerdts 
360ab2eff07SMike Gerdts 	blob_bdev = (struct blob_bdev *)bs_dev;
361ab2eff07SMike Gerdts 	CU_ASSERT(blob_bdev->desc->claim_type == SPDK_BDEV_CLAIM_NONE);
362ab2eff07SMike Gerdts 	CU_ASSERT(bdev.claim_type == SPDK_BDEV_CLAIM_NONE);
363ab2eff07SMike Gerdts 	CU_ASSERT(!blob_bdev->desc->write);
364ab2eff07SMike Gerdts 
365ab2eff07SMike Gerdts 	/* Can get an shared reader claim */
366ab2eff07SMike Gerdts 	rc = spdk_bs_bdev_claim(bs_dev, &g_bdev_mod);
367ab2eff07SMike Gerdts 	CU_ASSERT(rc == 0);
368ab2eff07SMike Gerdts 	CU_ASSERT(!blob_bdev->desc->write);
369ab2eff07SMike Gerdts 	CU_ASSERT(bdev.claim_type == SPDK_BDEV_CLAIM_READ_MANY_WRITE_NONE);
370ab2eff07SMike Gerdts 	CU_ASSERT(bdev.claim_desc == blob_bdev->desc);
371ab2eff07SMike Gerdts 
372ab2eff07SMike Gerdts 	/* Claim blocks a writer without messing up the claim. */
373ab2eff07SMike Gerdts 	rc = spdk_bdev_create_bs_dev_ext("bdev0", NULL, NULL, &bs_dev2);
374ab2eff07SMike Gerdts 	CU_ASSERT(rc == -EPERM);
375ab2eff07SMike Gerdts 	CU_ASSERT(bdev.claim_type == SPDK_BDEV_CLAIM_READ_MANY_WRITE_NONE);
376ab2eff07SMike Gerdts 	CU_ASSERT(bdev.claim_desc == blob_bdev->desc);
377ab2eff07SMike Gerdts 
378ab2eff07SMike Gerdts 	/* Another reader is just fine */
379ab2eff07SMike Gerdts 	rc = spdk_bdev_create_bs_dev("bdev0", false, NULL, 0, NULL, NULL, &bs_dev2);
380ab2eff07SMike Gerdts 	CU_ASSERT(rc == 0);
381ab2eff07SMike Gerdts 	SPDK_CU_ASSERT_FATAL(bs_dev2 != NULL);
382ab2eff07SMike Gerdts 	bs_dev2->destroy(bs_dev2);
383ab2eff07SMike Gerdts 
384ab2eff07SMike Gerdts 	bs_dev->destroy(bs_dev);
385ab2eff07SMike Gerdts 	CU_ASSERT(bdev.open_cnt == 0);
386ab2eff07SMike Gerdts 	CU_ASSERT(bdev.claim_type == SPDK_BDEV_CLAIM_NONE);
387ab2eff07SMike Gerdts 	CU_ASSERT(bdev.claim_module == NULL);
388ab2eff07SMike Gerdts 	CU_ASSERT(bdev.claim_desc == NULL);
389ab2eff07SMike Gerdts 	g_bdev = NULL;
390ab2eff07SMike Gerdts }
391ab2eff07SMike Gerdts 
392421fb110SMike Gerdts /*
393421fb110SMike Gerdts  * Verify that create_channel() and destroy_channel() increment and decrement the blob_bdev->refs.
394421fb110SMike Gerdts  */
395421fb110SMike Gerdts static void
396421fb110SMike Gerdts deferred_destroy_refs(void)
397421fb110SMike Gerdts {
398421fb110SMike Gerdts 	struct spdk_bdev bdev;
399421fb110SMike Gerdts 	struct spdk_io_channel *ch1, *ch2;
400421fb110SMike Gerdts 	struct spdk_bs_dev *bs_dev = NULL;
401421fb110SMike Gerdts 	struct blob_bdev *blob_bdev;
402421fb110SMike Gerdts 	int rc;
403421fb110SMike Gerdts 
404421fb110SMike Gerdts 	set_thread(0);
405421fb110SMike Gerdts 	init_bdev(&bdev, "bdev0", 16);
406421fb110SMike Gerdts 	g_bdev = &bdev;
407421fb110SMike Gerdts 
408421fb110SMike Gerdts 	/* Open a blob_bdev, verify reference count is 1. */
409421fb110SMike Gerdts 	rc = spdk_bdev_create_bs_dev("bdev0", false, NULL, 0, NULL, NULL, &bs_dev);
410421fb110SMike Gerdts 	CU_ASSERT(rc == 0);
411421fb110SMike Gerdts 	SPDK_CU_ASSERT_FATAL(bs_dev != NULL);
412421fb110SMike Gerdts 	blob_bdev = (struct blob_bdev *)bs_dev;
413421fb110SMike Gerdts 	CU_ASSERT(blob_bdev->refs == 1);
414421fb110SMike Gerdts 	CU_ASSERT(blob_bdev->desc != NULL);
415421fb110SMike Gerdts 
416421fb110SMike Gerdts 	/* Verify reference count increases with channels on the same thread. */
417421fb110SMike Gerdts 	ch1 = bs_dev->create_channel(bs_dev);
418421fb110SMike Gerdts 	SPDK_CU_ASSERT_FATAL(ch1 != NULL);
419421fb110SMike Gerdts 	CU_ASSERT(blob_bdev->refs == 2);
420421fb110SMike Gerdts 	ch2 = bs_dev->create_channel(bs_dev);
421421fb110SMike Gerdts 	SPDK_CU_ASSERT_FATAL(ch2 != NULL);
422421fb110SMike Gerdts 	CU_ASSERT(blob_bdev->refs == 3);
423421fb110SMike Gerdts 	bs_dev->destroy_channel(bs_dev, ch1);
424421fb110SMike Gerdts 	CU_ASSERT(blob_bdev->refs == 2);
425421fb110SMike Gerdts 	bs_dev->destroy_channel(bs_dev, ch2);
426421fb110SMike Gerdts 	CU_ASSERT(blob_bdev->refs == 1);
427421fb110SMike Gerdts 	CU_ASSERT(blob_bdev->desc != NULL);
428421fb110SMike Gerdts 
429421fb110SMike Gerdts 	/* Verify reference count increases with channels on different threads. */
430421fb110SMike Gerdts 	ch1 = bs_dev->create_channel(bs_dev);
431421fb110SMike Gerdts 	SPDK_CU_ASSERT_FATAL(ch1 != NULL);
432421fb110SMike Gerdts 	CU_ASSERT(blob_bdev->refs == 2);
433421fb110SMike Gerdts 	set_thread(1);
434421fb110SMike Gerdts 	ch2 = bs_dev->create_channel(bs_dev);
435421fb110SMike Gerdts 	SPDK_CU_ASSERT_FATAL(ch2 != NULL);
436421fb110SMike Gerdts 	CU_ASSERT(blob_bdev->refs == 3);
437421fb110SMike Gerdts 	bs_dev->destroy_channel(bs_dev, ch1);
438421fb110SMike Gerdts 	CU_ASSERT(blob_bdev->refs == 2);
439421fb110SMike Gerdts 	bs_dev->destroy_channel(bs_dev, ch2);
440421fb110SMike Gerdts 	CU_ASSERT(blob_bdev->refs == 1);
441421fb110SMike Gerdts 	CU_ASSERT(blob_bdev->desc != NULL);
442421fb110SMike Gerdts 
443421fb110SMike Gerdts 	set_thread(0);
444421fb110SMike Gerdts 	bs_dev->destroy(bs_dev);
445421fb110SMike Gerdts 	g_bdev = NULL;
446421fb110SMike Gerdts }
447421fb110SMike Gerdts 
448421fb110SMike Gerdts /*
449421fb110SMike Gerdts  * When a channel is open bs_dev->destroy() should not free bs_dev until after the last channel is
450421fb110SMike Gerdts  * closed. Further, destroy() prevents the creation of new channels.
451421fb110SMike Gerdts  */
452421fb110SMike Gerdts static void
453421fb110SMike Gerdts deferred_destroy_channels(void)
454421fb110SMike Gerdts {
455421fb110SMike Gerdts 	struct spdk_bdev bdev;
456421fb110SMike Gerdts 	struct spdk_io_channel *ch1, *ch2;
457421fb110SMike Gerdts 	struct spdk_bs_dev *bs_dev = NULL;
458421fb110SMike Gerdts 	struct blob_bdev *blob_bdev;
459421fb110SMike Gerdts 	int rc;
460421fb110SMike Gerdts 
461421fb110SMike Gerdts 	set_thread(0);
462421fb110SMike Gerdts 	init_bdev(&bdev, "bdev0", 16);
463421fb110SMike Gerdts 
464421fb110SMike Gerdts 	/* Open bs_dev and sanity check */
465421fb110SMike Gerdts 	g_bdev = &bdev;
466421fb110SMike Gerdts 	rc = spdk_bdev_create_bs_dev("bdev0", false, NULL, 0, NULL, NULL, &bs_dev);
467421fb110SMike Gerdts 	CU_ASSERT(rc == 0);
468421fb110SMike Gerdts 	SPDK_CU_ASSERT_FATAL(bs_dev != NULL);
469421fb110SMike Gerdts 	CU_ASSERT(bdev.open_cnt == 1);
470421fb110SMike Gerdts 	blob_bdev = (struct blob_bdev *)bs_dev;
471421fb110SMike Gerdts 	CU_ASSERT(blob_bdev->refs == 1);
472421fb110SMike Gerdts 	CU_ASSERT(blob_bdev->desc != NULL);
473421fb110SMike Gerdts 
474421fb110SMike Gerdts 	/* Create a channel, destroy the bs_dev. It should not be freed yet. */
475421fb110SMike Gerdts 	ch1 = bs_dev->create_channel(bs_dev);
476421fb110SMike Gerdts 	SPDK_CU_ASSERT_FATAL(ch1 != NULL);
477421fb110SMike Gerdts 	CU_ASSERT(blob_bdev->refs == 2);
478421fb110SMike Gerdts 	bs_dev->destroy(bs_dev);
479421fb110SMike Gerdts 
480421fb110SMike Gerdts 	/* Destroy closes the bdev and prevents desc from being used for creating more channels. */
481421fb110SMike Gerdts 	CU_ASSERT(blob_bdev->desc == NULL);
482421fb110SMike Gerdts 	CU_ASSERT(bdev.open_cnt == 0);
483421fb110SMike Gerdts 	CU_ASSERT(blob_bdev->refs == 1);
484421fb110SMike Gerdts 	ch2 = bs_dev->create_channel(bs_dev);
485421fb110SMike Gerdts 	CU_ASSERT(ch2 == NULL)
486421fb110SMike Gerdts 	CU_ASSERT(blob_bdev->refs == 1);
487421fb110SMike Gerdts 	bs_dev->destroy_channel(bs_dev, ch1);
488421fb110SMike Gerdts 	g_bdev = NULL;
489421fb110SMike Gerdts 
490421fb110SMike Gerdts 	/* Now bs_dev should have been freed. Builds with asan will verify. */
491421fb110SMike Gerdts }
492421fb110SMike Gerdts 
493421fb110SMike Gerdts /*
494421fb110SMike Gerdts  * Verify that deferred destroy copes well with the last channel destruction being on a thread other
495421fb110SMike Gerdts  * than the thread used to obtain the bdev descriptor.
496421fb110SMike Gerdts  */
497421fb110SMike Gerdts static void
498421fb110SMike Gerdts deferred_destroy_threads(void)
499421fb110SMike Gerdts {
500421fb110SMike Gerdts 	struct spdk_bdev bdev;
501421fb110SMike Gerdts 	struct spdk_io_channel *ch1, *ch2;
502421fb110SMike Gerdts 	struct spdk_bs_dev *bs_dev = NULL;
503421fb110SMike Gerdts 	struct blob_bdev *blob_bdev;
504421fb110SMike Gerdts 	int rc;
505421fb110SMike Gerdts 
506421fb110SMike Gerdts 	set_thread(0);
507421fb110SMike Gerdts 	init_bdev(&bdev, "bdev0", 16);
508421fb110SMike Gerdts 	g_bdev = &bdev;
509421fb110SMike Gerdts 
510421fb110SMike Gerdts 	/* Open bs_dev and sanity check */
511421fb110SMike Gerdts 	rc = spdk_bdev_create_bs_dev("bdev0", false, NULL, 0, NULL, NULL, &bs_dev);
512421fb110SMike Gerdts 	CU_ASSERT(rc == 0);
513421fb110SMike Gerdts 	SPDK_CU_ASSERT_FATAL(bs_dev != NULL);
514421fb110SMike Gerdts 	CU_ASSERT(bdev.open_cnt == 1);
515421fb110SMike Gerdts 	blob_bdev = (struct blob_bdev *)bs_dev;
516421fb110SMike Gerdts 	CU_ASSERT(blob_bdev->refs == 1);
517421fb110SMike Gerdts 	CU_ASSERT(blob_bdev->desc != NULL);
518421fb110SMike Gerdts 
519421fb110SMike Gerdts 	/* Create two channels, each on their own thread. */
520421fb110SMike Gerdts 	ch1 = bs_dev->create_channel(bs_dev);
521421fb110SMike Gerdts 	SPDK_CU_ASSERT_FATAL(ch1 != NULL);
522421fb110SMike Gerdts 	CU_ASSERT(blob_bdev->refs == 2);
523421fb110SMike Gerdts 	CU_ASSERT(spdk_get_thread() == blob_bdev->desc->thread);
524421fb110SMike Gerdts 	set_thread(1);
525421fb110SMike Gerdts 	ch2 = bs_dev->create_channel(bs_dev);
526421fb110SMike Gerdts 	SPDK_CU_ASSERT_FATAL(ch2 != NULL);
527421fb110SMike Gerdts 	CU_ASSERT(blob_bdev->refs == 3);
528421fb110SMike Gerdts 
529421fb110SMike Gerdts 	/* Destroy the bs_dev on thread 0, the channel on thread 0, then the channel on thread 1. */
530421fb110SMike Gerdts 	set_thread(0);
531421fb110SMike Gerdts 	bs_dev->destroy(bs_dev);
532421fb110SMike Gerdts 	CU_ASSERT(blob_bdev->desc == NULL);
533421fb110SMike Gerdts 	CU_ASSERT(bdev.open_cnt == 0);
534421fb110SMike Gerdts 	CU_ASSERT(blob_bdev->refs == 2);
535421fb110SMike Gerdts 	bs_dev->destroy_channel(bs_dev, ch1);
536421fb110SMike Gerdts 	CU_ASSERT(blob_bdev->refs == 1);
537421fb110SMike Gerdts 	set_thread(1);
538421fb110SMike Gerdts 	bs_dev->destroy_channel(bs_dev, ch2);
539421fb110SMike Gerdts 	set_thread(0);
540421fb110SMike Gerdts 	g_bdev = NULL;
541421fb110SMike Gerdts 
542421fb110SMike Gerdts 	/* Now bs_dev should have been freed. Builds with asan will verify. */
543421fb110SMike Gerdts }
544421fb110SMike Gerdts 
545c74b8b60SMike Gerdts int
546c74b8b60SMike Gerdts main(int argc, char **argv)
547c74b8b60SMike Gerdts {
548c74b8b60SMike Gerdts 	CU_pSuite	suite;
549c74b8b60SMike Gerdts 	unsigned int	num_failures;
550c74b8b60SMike Gerdts 
551c74b8b60SMike Gerdts 	CU_initialize_registry();
552c74b8b60SMike Gerdts 
553c74b8b60SMike Gerdts 	suite = CU_add_suite("blob_bdev", NULL, NULL);
554c74b8b60SMike Gerdts 
555c74b8b60SMike Gerdts 	CU_ADD_TEST(suite, create_bs_dev);
556bd5a7847SMike Gerdts 	CU_ADD_TEST(suite, create_bs_dev_ro);
557bd5a7847SMike Gerdts 	CU_ADD_TEST(suite, create_bs_dev_rw);
558e52b6c0dSMike Gerdts 	CU_ADD_TEST(suite, claim_bs_dev);
559ab2eff07SMike Gerdts 	CU_ADD_TEST(suite, claim_bs_dev_ro);
560421fb110SMike Gerdts 	CU_ADD_TEST(suite, deferred_destroy_refs);
561421fb110SMike Gerdts 	CU_ADD_TEST(suite, deferred_destroy_channels);
562421fb110SMike Gerdts 	CU_ADD_TEST(suite, deferred_destroy_threads);
563421fb110SMike Gerdts 
564421fb110SMike Gerdts 	allocate_threads(2);
565421fb110SMike Gerdts 	set_thread(0);
566c74b8b60SMike Gerdts 
567ea941caeSKonrad Sztyber 	num_failures = spdk_ut_run_tests(argc, argv, NULL);
568c74b8b60SMike Gerdts 	CU_cleanup_registry();
569c74b8b60SMike Gerdts 
570421fb110SMike Gerdts 	free_threads();
571421fb110SMike Gerdts 
572c74b8b60SMike Gerdts 	return num_failures;
573c74b8b60SMike Gerdts }
574