xref: /spdk/test/unit/lib/blob/blob_bdev.c/blob_bdev_ut.c (revision 56f238488e7465d68d626fc0d596e1e119f31c49)
1 /*   SPDX-License-Identifier: BSD-3-Clause
2  *   Copyright (c) 2023 NVIDIA CORPORATION & AFFILIATES. All rights reserved.
3  */
4 
5 #include "spdk/stdinc.h"
6 
7 #include "spdk_cunit.h"
8 #include "common/lib/test_env.c"
9 #include "blob/bdev/blob_bdev.c"
10 
11 DEFINE_STUB(spdk_bdev_io_type_supported, bool, (struct spdk_bdev *bdev,
12 		enum spdk_bdev_io_type io_type), false);
13 DEFINE_STUB_V(spdk_bdev_free_io, (struct spdk_bdev_io *g_bdev_io));
14 DEFINE_STUB(spdk_bdev_queue_io_wait, int,
15 	    (struct spdk_bdev *bdev, struct spdk_io_channel *ch,
16 	     struct spdk_bdev_io_wait_entry *entry), 0);
17 DEFINE_STUB(spdk_bdev_read_blocks, int,
18 	    (struct spdk_bdev_desc *desc, struct spdk_io_channel *ch, void *buf,
19 	     uint64_t offset_blocks, uint64_t num_blocks, spdk_bdev_io_completion_cb cb,
20 	     void *cb_arg), 0);
21 DEFINE_STUB(spdk_bdev_write_blocks, int,
22 	    (struct spdk_bdev_desc *desc, struct spdk_io_channel *ch, void *buf,
23 	     uint64_t offset_blocks, uint64_t num_blocks, spdk_bdev_io_completion_cb cb,
24 	     void *cb_arg), 0);
25 DEFINE_STUB(spdk_bdev_readv_blocks, int,
26 	    (struct spdk_bdev_desc *desc, struct spdk_io_channel *ch, struct iovec *iov, int iovcnt,
27 	     uint64_t offset_blocks, uint64_t num_blocks, spdk_bdev_io_completion_cb cb,
28 	     void *cb_arg), 0);
29 DEFINE_STUB(spdk_bdev_writev_blocks, int,
30 	    (struct spdk_bdev_desc *desc, struct spdk_io_channel *ch, struct iovec *iov, int iovcnt,
31 	     uint64_t offset_blocks, uint64_t num_blocks, spdk_bdev_io_completion_cb cb,
32 	     void *cb_arg), 0);
33 DEFINE_STUB(spdk_bdev_readv_blocks_ext, int,
34 	    (struct spdk_bdev_desc *desc, struct spdk_io_channel *ch, struct iovec *iov, int iovcnt,
35 	     uint64_t offset_blocks, uint64_t num_blocks, spdk_bdev_io_completion_cb cb,
36 	     void *cb_arg, struct spdk_bdev_ext_io_opts *opts), 0);
37 DEFINE_STUB(spdk_bdev_writev_blocks_ext, int,
38 	    (struct spdk_bdev_desc *desc, struct spdk_io_channel *ch, struct iovec *iov, int iovcnt,
39 	     uint64_t offset_blocks, uint64_t num_blocks, spdk_bdev_io_completion_cb cb,
40 	     void *cb_arg, struct spdk_bdev_ext_io_opts *opts), 0);
41 DEFINE_STUB(spdk_bdev_write_zeroes_blocks, int,
42 	    (struct spdk_bdev_desc *desc, struct spdk_io_channel *ch, uint64_t offset_blocks,
43 	     uint64_t num_blocks, spdk_bdev_io_completion_cb cb, void *cb_arg), 0);
44 DEFINE_STUB(spdk_bdev_unmap_blocks, int,
45 	    (struct spdk_bdev_desc *desc, struct spdk_io_channel *ch, uint64_t offset_blocks,
46 	     uint64_t num_blocks, spdk_bdev_io_completion_cb cb, void *cb_arg), 0);
47 DEFINE_STUB(spdk_bdev_copy_blocks, int,
48 	    (struct spdk_bdev_desc *desc, struct spdk_io_channel *ch, uint64_t dst_offset_blocks,
49 	     uint64_t src_offset_blocks, uint64_t num_blocks, spdk_bdev_io_completion_cb cb,
50 	     void *cb_arg), 0);
51 DEFINE_STUB(spdk_bdev_get_io_channel, struct spdk_io_channel *,
52 	    (struct spdk_bdev_desc *desc), NULL);
53 
54 struct spdk_bdev {
55 	char name[16];
56 	uint64_t blockcnt;
57 	uint32_t blocklen;
58 	uint32_t open_cnt;
59 	enum spdk_bdev_claim_type claim_type;
60 	struct spdk_bdev_module *claim_module;
61 	struct spdk_bdev_desc *claim_desc;
62 };
63 
64 struct spdk_bdev_desc {
65 	struct spdk_bdev *bdev;
66 	bool write;
67 	enum spdk_bdev_claim_type claim_type;
68 };
69 
70 struct spdk_bdev *g_bdev;
71 
72 static struct spdk_bdev_module g_bdev_mod = {
73 	.name = "blob_bdev_ut"
74 };
75 
76 static struct spdk_bdev *
77 get_bdev(const char *bdev_name)
78 {
79 	if (g_bdev == NULL) {
80 		return NULL;
81 	}
82 
83 	if (strcmp(bdev_name, g_bdev->name) != 0) {
84 		return NULL;
85 	}
86 
87 	return g_bdev;
88 }
89 
90 int
91 spdk_bdev_open_ext(const char *bdev_name, bool write, spdk_bdev_event_cb_t event_cb,
92 		   void *event_ctx, struct spdk_bdev_desc **_desc)
93 {
94 	struct spdk_bdev_desc *desc;
95 	struct spdk_bdev *bdev = get_bdev(bdev_name);
96 
97 	if (bdev == NULL) {
98 		return -ENODEV;
99 	}
100 
101 	if (write && bdev->claim_module != NULL) {
102 		return -EPERM;
103 	}
104 
105 	desc = calloc(1, sizeof(*desc));
106 	desc->bdev = g_bdev;
107 	desc->write = write;
108 	*_desc = desc;
109 	bdev->open_cnt++;
110 
111 	return 0;
112 }
113 
114 void
115 spdk_bdev_close(struct spdk_bdev_desc *desc)
116 {
117 	struct spdk_bdev *bdev = desc->bdev;
118 
119 	bdev->open_cnt--;
120 	if (bdev->claim_desc == desc) {
121 		bdev->claim_desc = NULL;
122 		bdev->claim_type = SPDK_BDEV_CLAIM_NONE;
123 		bdev->claim_module = NULL;
124 	}
125 	free(desc);
126 }
127 
128 struct spdk_bdev *
129 spdk_bdev_desc_get_bdev(struct spdk_bdev_desc *desc)
130 {
131 	return desc->bdev;
132 }
133 
134 uint64_t
135 spdk_bdev_get_num_blocks(const struct spdk_bdev *bdev)
136 {
137 	return bdev->blockcnt;
138 }
139 
140 uint32_t
141 spdk_bdev_get_block_size(const struct spdk_bdev *bdev)
142 {
143 	return bdev->blocklen;
144 }
145 
146 /* This is a simple approximation: it does not support shared claims */
147 int
148 spdk_bdev_module_claim_bdev_desc(struct spdk_bdev_desc *desc, enum spdk_bdev_claim_type type,
149 				 struct spdk_bdev_claim_opts *opts,
150 				 struct spdk_bdev_module *module)
151 {
152 	struct spdk_bdev *bdev = desc->bdev;
153 
154 	if (bdev->claim_module != NULL) {
155 		return -EPERM;
156 	}
157 
158 	bdev->claim_type = type;
159 	bdev->claim_module = module;
160 	bdev->claim_desc = desc;
161 
162 	desc->claim_type = type;
163 
164 	return 0;
165 }
166 
167 static void
168 init_bdev(struct spdk_bdev *bdev, const char *name, uint64_t num_blocks)
169 {
170 	memset(bdev, 0, sizeof(*bdev));
171 	snprintf(bdev->name, sizeof(bdev->name), "%s", name);
172 	bdev->blockcnt = num_blocks;
173 }
174 
175 static void
176 create_bs_dev(void)
177 {
178 	struct spdk_bdev bdev;
179 	struct spdk_bs_dev *bs_dev = NULL;
180 	struct blob_bdev *blob_bdev;
181 	int rc;
182 
183 	init_bdev(&bdev, "bdev0", 16);
184 	g_bdev = &bdev;
185 
186 	rc = spdk_bdev_create_bs_dev_ext("bdev0", NULL, NULL, &bs_dev);
187 	CU_ASSERT(rc == 0);
188 	SPDK_CU_ASSERT_FATAL(bs_dev != NULL);
189 	CU_ASSERT(bdev.open_cnt == 1);
190 
191 	blob_bdev = (struct blob_bdev *)bs_dev;
192 	CU_ASSERT(blob_bdev->desc != NULL);
193 	CU_ASSERT(blob_bdev->desc->bdev == g_bdev);
194 	CU_ASSERT(blob_bdev->desc->claim_type == SPDK_BDEV_CLAIM_NONE);
195 	CU_ASSERT(bdev.claim_type == SPDK_BDEV_CLAIM_NONE);
196 
197 	bs_dev->destroy(bs_dev);
198 	CU_ASSERT(bdev.open_cnt == 0);
199 	g_bdev = NULL;
200 }
201 
202 static void
203 claim_bs_dev(void)
204 {
205 	struct spdk_bdev bdev;
206 	struct spdk_bs_dev *bs_dev = NULL, *bs_dev2 = NULL;
207 	struct blob_bdev *blob_bdev;
208 	int rc;
209 
210 	init_bdev(&bdev, "bdev0", 16);
211 	g_bdev = &bdev;
212 
213 	rc = spdk_bdev_create_bs_dev_ext("bdev0", NULL, NULL, &bs_dev);
214 	CU_ASSERT(rc == 0);
215 	SPDK_CU_ASSERT_FATAL(bs_dev != NULL);
216 
217 	blob_bdev = (struct blob_bdev *)bs_dev;
218 	CU_ASSERT(blob_bdev->desc->claim_type == SPDK_BDEV_CLAIM_NONE);
219 	CU_ASSERT(bdev.claim_type == SPDK_BDEV_CLAIM_NONE);
220 	CU_ASSERT(blob_bdev->desc->write);
221 
222 	/* Can get an exclusive write claim */
223 	rc = spdk_bs_bdev_claim(bs_dev, &g_bdev_mod);
224 	CU_ASSERT(rc == 0);
225 	CU_ASSERT(blob_bdev->desc->write);
226 	CU_ASSERT(bdev.claim_type == SPDK_BDEV_CLAIM_READ_MANY_WRITE_ONE);
227 	CU_ASSERT(bdev.claim_desc == blob_bdev->desc);
228 
229 	/* Claim blocks a second writer without messing up the first one. */
230 	rc = spdk_bdev_create_bs_dev_ext("bdev0", NULL, NULL, &bs_dev2);
231 	CU_ASSERT(rc == -EPERM);
232 	CU_ASSERT(bdev.claim_type == SPDK_BDEV_CLAIM_READ_MANY_WRITE_ONE);
233 	CU_ASSERT(bdev.claim_desc == blob_bdev->desc);
234 
235 	/* Claim blocks a second claim without messing up the first one. */
236 	rc = spdk_bs_bdev_claim(bs_dev, &g_bdev_mod);
237 	CU_ASSERT(rc == -EPERM);
238 	CU_ASSERT(bdev.claim_type == SPDK_BDEV_CLAIM_READ_MANY_WRITE_ONE);
239 	CU_ASSERT(bdev.claim_desc == blob_bdev->desc);
240 
241 	bs_dev->destroy(bs_dev);
242 	CU_ASSERT(bdev.open_cnt == 0);
243 	CU_ASSERT(bdev.claim_type == SPDK_BDEV_CLAIM_NONE);
244 	CU_ASSERT(bdev.claim_module == NULL);
245 	CU_ASSERT(bdev.claim_desc == NULL);
246 	g_bdev = NULL;
247 }
248 
249 int
250 main(int argc, char **argv)
251 {
252 	CU_pSuite	suite;
253 	unsigned int	num_failures;
254 
255 	CU_set_error_action(CUEA_ABORT);
256 	CU_initialize_registry();
257 
258 	suite = CU_add_suite("blob_bdev", NULL, NULL);
259 
260 	CU_ADD_TEST(suite, create_bs_dev);
261 	CU_ADD_TEST(suite, claim_bs_dev);
262 
263 	CU_basic_set_mode(CU_BRM_VERBOSE);
264 	CU_basic_run_tests();
265 	num_failures = CU_get_number_of_failures();
266 	CU_cleanup_registry();
267 
268 	return num_failures;
269 }
270