xref: /spdk/test/unit/lib/bdev/bdev.c/bdev_ut.c (revision fe8138cebbcde2415de235e8a8e43c460b6de4e6)
1 /*-
2  *   BSD LICENSE
3  *
4  *   Copyright (c) Intel Corporation.
5  *   All rights reserved.
6  *
7  *   Redistribution and use in source and binary forms, with or without
8  *   modification, are permitted provided that the following conditions
9  *   are met:
10  *
11  *     * Redistributions of source code must retain the above copyright
12  *       notice, this list of conditions and the following disclaimer.
13  *     * Redistributions in binary form must reproduce the above copyright
14  *       notice, this list of conditions and the following disclaimer in
15  *       the documentation and/or other materials provided with the
16  *       distribution.
17  *     * Neither the name of Intel Corporation nor the names of its
18  *       contributors may be used to endorse or promote products derived
19  *       from this software without specific prior written permission.
20  *
21  *   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
22  *   "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
23  *   LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
24  *   A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
25  *   OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
26  *   SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
27  *   LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
28  *   DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
29  *   THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
30  *   (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
31  *   OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
32  */
33 
34 #include "spdk_cunit.h"
35 
36 #include "lib/test_env.c"
37 
38 /* HACK: disable VTune integration so the unit test doesn't need VTune headers and libs to build */
39 #undef SPDK_CONFIG_VTUNE
40 
41 #include "bdev.c"
42 
43 SPDK_DECLARE_BDEV_MODULE(vbdev_ut);
44 
45 void
46 spdk_scsi_nvme_translate(const struct spdk_bdev_io *bdev_io,
47 			 int *sc, int *sk, int *asc, int *ascq)
48 {
49 }
50 
51 static int
52 null_init(void)
53 {
54 	return 0;
55 }
56 
57 static int
58 null_clean(void)
59 {
60 	return 0;
61 }
62 
63 static int
64 stub_destruct(void *ctx)
65 {
66 	return 0;
67 }
68 
69 static struct spdk_bdev_fn_table fn_table = {
70 	.destruct = stub_destruct,
71 };
72 
73 static void
74 vbdev_ut_examine(struct spdk_bdev *bdev)
75 {
76 	spdk_bdev_module_examine_done(SPDK_GET_BDEV_MODULE(vbdev_ut));
77 }
78 
79 SPDK_BDEV_MODULE_REGISTER(bdev_ut, NULL, NULL, NULL, NULL, NULL)
80 SPDK_BDEV_MODULE_REGISTER(vbdev_ut, NULL, NULL, NULL, NULL, vbdev_ut_examine)
81 
82 static struct spdk_bdev *
83 allocate_bdev(char *name)
84 {
85 	struct spdk_bdev *bdev;
86 
87 	bdev = calloc(1, sizeof(*bdev));
88 	SPDK_CU_ASSERT_FATAL(bdev != NULL);
89 
90 	bdev->name = name;
91 	bdev->fn_table = &fn_table;
92 	bdev->module = SPDK_GET_BDEV_MODULE(bdev_ut);
93 
94 	spdk_bdev_register(bdev);
95 	CU_ASSERT(TAILQ_EMPTY(&bdev->base_bdevs));
96 	CU_ASSERT(TAILQ_EMPTY(&bdev->vbdevs));
97 
98 	return bdev;
99 }
100 
101 static struct spdk_bdev *
102 allocate_vbdev(char *name, struct spdk_bdev *base1, struct spdk_bdev *base2)
103 {
104 	struct spdk_bdev *bdev;
105 	struct spdk_bdev *array[2];
106 
107 	bdev = calloc(1, sizeof(*bdev));
108 	SPDK_CU_ASSERT_FATAL(bdev != NULL);
109 
110 	bdev->name = name;
111 	bdev->fn_table = &fn_table;
112 	bdev->module = SPDK_GET_BDEV_MODULE(vbdev_ut);
113 
114 	/* vbdev must have at least one base bdev */
115 	CU_ASSERT(base1 != NULL);
116 
117 	array[0] = base1;
118 	array[1] = base2;
119 
120 	spdk_vbdev_register(bdev, array, base2 == NULL ? 1 : 2);
121 	CU_ASSERT(!TAILQ_EMPTY(&bdev->base_bdevs));
122 	CU_ASSERT(TAILQ_EMPTY(&bdev->vbdevs));
123 
124 	return bdev;
125 }
126 
127 static void
128 free_bdev(struct spdk_bdev *bdev)
129 {
130 	spdk_bdev_unregister(bdev, NULL, NULL);
131 	free(bdev);
132 }
133 
134 static void
135 free_vbdev(struct spdk_bdev *bdev)
136 {
137 	spdk_vbdev_unregister(bdev, NULL, NULL);
138 	free(bdev);
139 }
140 
141 static void
142 open_write_test(void)
143 {
144 	struct spdk_bdev *bdev[8];
145 	struct spdk_bdev_desc *desc[8] = {};
146 	int rc;
147 
148 	/*
149 	 * Create a tree of bdevs to test various open w/ write cases.
150 	 *
151 	 * bdev0 through bdev2 are physical block devices, such as NVMe
152 	 * namespaces or Ceph block devices.
153 	 *
154 	 * bdev3 is a virtual bdev with multiple base bdevs.  This models
155 	 * caching or RAID use cases.
156 	 *
157 	 * bdev4 through bdev6 are all virtual bdevs with the same base
158 	 * bdev.  This models partitioning or logical volume use cases.
159 	 *
160 	 * bdev7 is a virtual bdev with multiple base bdevs, but these
161 	 * base bdevs are themselves virtual bdevs.
162 	 *
163 	 *                bdev7
164 	 *                  |
165 	 *            +----------+
166 	 *            |          |
167 	 *          bdev3      bdev4   bdev5   bdev6
168 	 *            |          |       |       |
169 	 *        +---+---+      +-------+-------+
170 	 *        |       |              |
171 	 *      bdev0   bdev1          bdev2
172 	 */
173 
174 	bdev[0] = allocate_bdev("bdev0");
175 	rc = spdk_bdev_module_claim_bdev(bdev[0], NULL, SPDK_GET_BDEV_MODULE(bdev_ut));
176 	CU_ASSERT(rc == 0);
177 
178 	bdev[1] = allocate_bdev("bdev1");
179 	rc = spdk_bdev_module_claim_bdev(bdev[1], NULL, SPDK_GET_BDEV_MODULE(bdev_ut));
180 	CU_ASSERT(rc == 0);
181 
182 	bdev[2] = allocate_bdev("bdev2");
183 	rc = spdk_bdev_module_claim_bdev(bdev[2], NULL, SPDK_GET_BDEV_MODULE(bdev_ut));
184 	CU_ASSERT(rc == 0);
185 
186 	bdev[3] = allocate_vbdev("bdev3", bdev[0], bdev[1]);
187 	rc = spdk_bdev_module_claim_bdev(bdev[3], NULL, SPDK_GET_BDEV_MODULE(bdev_ut));
188 	CU_ASSERT(rc == 0);
189 
190 	bdev[4] = allocate_vbdev("bdev4", bdev[2], NULL);
191 	rc = spdk_bdev_module_claim_bdev(bdev[4], NULL, SPDK_GET_BDEV_MODULE(bdev_ut));
192 	CU_ASSERT(rc == 0);
193 
194 	bdev[5] = allocate_vbdev("bdev5", bdev[2], NULL);
195 	bdev[6] = allocate_vbdev("bdev6", bdev[2], NULL);
196 
197 	bdev[7] = allocate_vbdev("bdev7", bdev[3], bdev[4]);
198 
199 	/* Open bdev0 read-only.  This should succeed. */
200 	rc = spdk_bdev_open(bdev[0], false, NULL, NULL, &desc[0]);
201 	CU_ASSERT(rc == 0);
202 	CU_ASSERT(desc[0] != NULL);
203 	spdk_bdev_close(desc[0]);
204 
205 	/*
206 	 * Open bdev1 read/write.  This should fail since bdev1 has been claimed
207 	 * by a vbdev module.
208 	 */
209 	rc = spdk_bdev_open(bdev[1], true, NULL, NULL, &desc[1]);
210 	CU_ASSERT(rc == -EPERM);
211 
212 	/*
213 	 * Open bdev3 read/write.  This should fail since bdev3 has been claimed
214 	 * by a vbdev module.
215 	 */
216 	rc = spdk_bdev_open(bdev[3], true, NULL, NULL, &desc[3]);
217 	CU_ASSERT(rc == -EPERM);
218 
219 	/* Open bdev3 read-only.  This should succeed. */
220 	rc = spdk_bdev_open(bdev[3], false, NULL, NULL, &desc[3]);
221 	CU_ASSERT(rc == 0);
222 	CU_ASSERT(desc[3] != NULL);
223 	spdk_bdev_close(desc[3]);
224 
225 	/*
226 	 * Open bdev7 read/write.  This should succeed since it is a leaf
227 	 * bdev.
228 	 */
229 	rc = spdk_bdev_open(bdev[7], true, NULL, NULL, &desc[7]);
230 	CU_ASSERT(rc == 0);
231 	CU_ASSERT(desc[7] != NULL);
232 	spdk_bdev_close(desc[7]);
233 
234 	/*
235 	 * Open bdev4 read/write.  This should fail since bdev4 has been claimed
236 	 * by a vbdev module.
237 	 */
238 	rc = spdk_bdev_open(bdev[4], true, NULL, NULL, &desc[4]);
239 	CU_ASSERT(rc == -EPERM);
240 
241 	/* Open bdev4 read-only.  This should succeed. */
242 	rc = spdk_bdev_open(bdev[4], false, NULL, NULL, &desc[4]);
243 	CU_ASSERT(rc == 0);
244 	CU_ASSERT(desc[4] != NULL);
245 	spdk_bdev_close(desc[4]);
246 
247 	free_vbdev(bdev[7]);
248 
249 	free_vbdev(bdev[3]);
250 	free_vbdev(bdev[4]);
251 	free_vbdev(bdev[5]);
252 	free_vbdev(bdev[6]);
253 
254 	free_bdev(bdev[0]);
255 	free_bdev(bdev[1]);
256 	free_bdev(bdev[2]);
257 
258 }
259 
260 static void
261 bytes_to_blocks_test(void)
262 {
263 	struct spdk_bdev bdev;
264 	uint64_t offset_blocks, num_blocks;
265 
266 	memset(&bdev, 0, sizeof(bdev));
267 
268 	bdev.blocklen = 512;
269 
270 	/* All parameters valid */
271 	offset_blocks = 0;
272 	num_blocks = 0;
273 	CU_ASSERT(spdk_bdev_bytes_to_blocks(&bdev, 512, &offset_blocks, 1024, &num_blocks) == 0);
274 	CU_ASSERT(offset_blocks == 1);
275 	CU_ASSERT(num_blocks == 2);
276 
277 	/* Offset not a block multiple */
278 	CU_ASSERT(spdk_bdev_bytes_to_blocks(&bdev, 3, &offset_blocks, 512, &num_blocks) != 0);
279 
280 	/* Length not a block multiple */
281 	CU_ASSERT(spdk_bdev_bytes_to_blocks(&bdev, 512, &offset_blocks, 3, &num_blocks) != 0);
282 }
283 
284 static void
285 io_valid_test(void)
286 {
287 	struct spdk_bdev bdev;
288 
289 	memset(&bdev, 0, sizeof(bdev));
290 
291 	bdev.blocklen = 512;
292 	bdev.blockcnt = 100;
293 
294 	/* All parameters valid */
295 	CU_ASSERT(spdk_bdev_io_valid_blocks(&bdev, 1, 2) == true);
296 
297 	/* Last valid block */
298 	CU_ASSERT(spdk_bdev_io_valid_blocks(&bdev, 99, 1) == true);
299 
300 	/* Offset past end of bdev */
301 	CU_ASSERT(spdk_bdev_io_valid_blocks(&bdev, 100, 1) == false);
302 
303 	/* Offset + length past end of bdev */
304 	CU_ASSERT(spdk_bdev_io_valid_blocks(&bdev, 99, 2) == false);
305 
306 	/* Offset near end of uint64_t range (2^64 - 1) */
307 	CU_ASSERT(spdk_bdev_io_valid_blocks(&bdev, 18446744073709551615ULL, 1) == false);
308 }
309 
310 static int
311 __destruct(void *ctx)
312 {
313 	return 0;
314 }
315 
316 static struct spdk_bdev_fn_table base_fn_table = {
317 	.destruct		= __destruct,
318 };
319 static struct spdk_bdev_fn_table part_fn_table = {
320 	.destruct		= __destruct,
321 };
322 
323 static void
324 __base_free(struct spdk_bdev_part_base *base)
325 {
326 	free(base);
327 }
328 
329 static void
330 part_test(void)
331 {
332 	struct spdk_bdev_part_base	*base;
333 	struct spdk_bdev_part		part1, part2;
334 	struct spdk_bdev		bdev_base = {};
335 	SPDK_BDEV_PART_TAILQ		tailq = TAILQ_HEAD_INITIALIZER(tailq);
336 
337 	base = calloc(1, sizeof(*base));
338 	SPDK_CU_ASSERT_FATAL(base != NULL);
339 
340 	bdev_base.name = "base";
341 	bdev_base.fn_table = &base_fn_table;
342 	bdev_base.module = SPDK_GET_BDEV_MODULE(bdev_ut);
343 	spdk_bdev_register(&bdev_base);
344 	spdk_bdev_part_base_construct(base, &bdev_base, NULL, SPDK_GET_BDEV_MODULE(vbdev_ut),
345 				      &part_fn_table, &tailq, __base_free, 0, NULL, NULL);
346 
347 	spdk_bdev_part_construct(&part1, base, "test1", 0, 100, "test");
348 	spdk_bdev_part_construct(&part2, base, "test2", 100, 100, "test");
349 
350 	spdk_bdev_part_base_hotremove(&bdev_base, &tailq);
351 
352 	/*
353 	 * The base device was removed - ensure that the partition vbdevs were
354 	 *  removed from the base's vbdev list.
355 	 */
356 	CU_ASSERT(TAILQ_EMPTY(&bdev_base.vbdevs));
357 
358 	spdk_bdev_part_base_free(base);
359 	spdk_bdev_unregister(&bdev_base, NULL, NULL);
360 }
361 
362 int
363 main(int argc, char **argv)
364 {
365 	CU_pSuite	suite = NULL;
366 	unsigned int	num_failures;
367 
368 	if (CU_initialize_registry() != CUE_SUCCESS) {
369 		return CU_get_error();
370 	}
371 
372 	suite = CU_add_suite("bdev", null_init, null_clean);
373 	if (suite == NULL) {
374 		CU_cleanup_registry();
375 		return CU_get_error();
376 	}
377 
378 	if (
379 		CU_add_test(suite, "bytes_to_blocks_test", bytes_to_blocks_test) == NULL ||
380 		CU_add_test(suite, "io_valid", io_valid_test) == NULL ||
381 		CU_add_test(suite, "open_write", open_write_test) == NULL ||
382 		CU_add_test(suite, "part", part_test) == NULL
383 	) {
384 		CU_cleanup_registry();
385 		return CU_get_error();
386 	}
387 
388 	CU_basic_set_mode(CU_BRM_VERBOSE);
389 	CU_basic_run_tests();
390 	num_failures = CU_get_number_of_failures();
391 	CU_cleanup_registry();
392 	return num_failures;
393 }
394