xref: /spdk/test/unit/lib/bdev/bdev.c/bdev_ut.c (revision 891c12a63ced31644a44a6a21f8d4437690c9840)
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 	int rc;
87 
88 	bdev = calloc(1, sizeof(*bdev));
89 	SPDK_CU_ASSERT_FATAL(bdev != NULL);
90 
91 	bdev->name = name;
92 	bdev->fn_table = &fn_table;
93 	bdev->module = SPDK_GET_BDEV_MODULE(bdev_ut);
94 
95 	rc = spdk_bdev_register(bdev);
96 	CU_ASSERT(rc == 0);
97 	CU_ASSERT(TAILQ_EMPTY(&bdev->base_bdevs));
98 	CU_ASSERT(TAILQ_EMPTY(&bdev->vbdevs));
99 
100 	return bdev;
101 }
102 
103 static struct spdk_bdev *
104 allocate_vbdev(char *name, struct spdk_bdev *base1, struct spdk_bdev *base2)
105 {
106 	struct spdk_bdev *bdev;
107 	struct spdk_bdev *array[2];
108 	int rc;
109 
110 	bdev = calloc(1, sizeof(*bdev));
111 	SPDK_CU_ASSERT_FATAL(bdev != NULL);
112 
113 	bdev->name = name;
114 	bdev->fn_table = &fn_table;
115 	bdev->module = SPDK_GET_BDEV_MODULE(vbdev_ut);
116 
117 	/* vbdev must have at least one base bdev */
118 	CU_ASSERT(base1 != NULL);
119 
120 	array[0] = base1;
121 	array[1] = base2;
122 
123 	rc = spdk_vbdev_register(bdev, array, base2 == NULL ? 1 : 2);
124 	CU_ASSERT(rc == 0);
125 	CU_ASSERT(!TAILQ_EMPTY(&bdev->base_bdevs));
126 	CU_ASSERT(TAILQ_EMPTY(&bdev->vbdevs));
127 
128 	return bdev;
129 }
130 
131 static void
132 free_bdev(struct spdk_bdev *bdev)
133 {
134 	spdk_bdev_unregister(bdev, NULL, NULL);
135 	free(bdev);
136 }
137 
138 static void
139 free_vbdev(struct spdk_bdev *bdev)
140 {
141 	spdk_vbdev_unregister(bdev, NULL, NULL);
142 	free(bdev);
143 }
144 
145 static void
146 open_write_test(void)
147 {
148 	struct spdk_bdev *bdev[8];
149 	struct spdk_bdev_desc *desc[8] = {};
150 	int rc;
151 
152 	/*
153 	 * Create a tree of bdevs to test various open w/ write cases.
154 	 *
155 	 * bdev0 through bdev2 are physical block devices, such as NVMe
156 	 * namespaces or Ceph block devices.
157 	 *
158 	 * bdev3 is a virtual bdev with multiple base bdevs.  This models
159 	 * caching or RAID use cases.
160 	 *
161 	 * bdev4 through bdev6 are all virtual bdevs with the same base
162 	 * bdev.  This models partitioning or logical volume use cases.
163 	 *
164 	 * bdev7 is a virtual bdev with multiple base bdevs, but these
165 	 * base bdevs are themselves virtual bdevs.
166 	 *
167 	 *                bdev7
168 	 *                  |
169 	 *            +----------+
170 	 *            |          |
171 	 *          bdev3      bdev4   bdev5   bdev6
172 	 *            |          |       |       |
173 	 *        +---+---+      +-------+-------+
174 	 *        |       |              |
175 	 *      bdev0   bdev1          bdev2
176 	 */
177 
178 	bdev[0] = allocate_bdev("bdev0");
179 	rc = spdk_bdev_module_claim_bdev(bdev[0], NULL, SPDK_GET_BDEV_MODULE(bdev_ut));
180 	CU_ASSERT(rc == 0);
181 
182 	bdev[1] = allocate_bdev("bdev1");
183 	rc = spdk_bdev_module_claim_bdev(bdev[1], NULL, SPDK_GET_BDEV_MODULE(bdev_ut));
184 	CU_ASSERT(rc == 0);
185 
186 	bdev[2] = allocate_bdev("bdev2");
187 	rc = spdk_bdev_module_claim_bdev(bdev[2], NULL, SPDK_GET_BDEV_MODULE(bdev_ut));
188 	CU_ASSERT(rc == 0);
189 
190 	bdev[3] = allocate_vbdev("bdev3", bdev[0], bdev[1]);
191 	rc = spdk_bdev_module_claim_bdev(bdev[3], NULL, SPDK_GET_BDEV_MODULE(bdev_ut));
192 	CU_ASSERT(rc == 0);
193 
194 	bdev[4] = allocate_vbdev("bdev4", bdev[2], NULL);
195 	rc = spdk_bdev_module_claim_bdev(bdev[4], NULL, SPDK_GET_BDEV_MODULE(bdev_ut));
196 	CU_ASSERT(rc == 0);
197 
198 	bdev[5] = allocate_vbdev("bdev5", bdev[2], NULL);
199 	bdev[6] = allocate_vbdev("bdev6", bdev[2], NULL);
200 
201 	bdev[7] = allocate_vbdev("bdev7", bdev[3], bdev[4]);
202 
203 	/* Open bdev0 read-only.  This should succeed. */
204 	rc = spdk_bdev_open(bdev[0], false, NULL, NULL, &desc[0]);
205 	CU_ASSERT(rc == 0);
206 	CU_ASSERT(desc[0] != NULL);
207 	spdk_bdev_close(desc[0]);
208 
209 	/*
210 	 * Open bdev1 read/write.  This should fail since bdev1 has been claimed
211 	 * by a vbdev module.
212 	 */
213 	rc = spdk_bdev_open(bdev[1], true, NULL, NULL, &desc[1]);
214 	CU_ASSERT(rc == -EPERM);
215 
216 	/*
217 	 * Open bdev3 read/write.  This should fail since bdev3 has been claimed
218 	 * by a vbdev module.
219 	 */
220 	rc = spdk_bdev_open(bdev[3], true, NULL, NULL, &desc[3]);
221 	CU_ASSERT(rc == -EPERM);
222 
223 	/* Open bdev3 read-only.  This should succeed. */
224 	rc = spdk_bdev_open(bdev[3], false, NULL, NULL, &desc[3]);
225 	CU_ASSERT(rc == 0);
226 	CU_ASSERT(desc[3] != NULL);
227 	spdk_bdev_close(desc[3]);
228 
229 	/*
230 	 * Open bdev7 read/write.  This should succeed since it is a leaf
231 	 * bdev.
232 	 */
233 	rc = spdk_bdev_open(bdev[7], true, NULL, NULL, &desc[7]);
234 	CU_ASSERT(rc == 0);
235 	CU_ASSERT(desc[7] != NULL);
236 	spdk_bdev_close(desc[7]);
237 
238 	/*
239 	 * Open bdev4 read/write.  This should fail since bdev4 has been claimed
240 	 * by a vbdev module.
241 	 */
242 	rc = spdk_bdev_open(bdev[4], true, NULL, NULL, &desc[4]);
243 	CU_ASSERT(rc == -EPERM);
244 
245 	/* Open bdev4 read-only.  This should succeed. */
246 	rc = spdk_bdev_open(bdev[4], false, NULL, NULL, &desc[4]);
247 	CU_ASSERT(rc == 0);
248 	CU_ASSERT(desc[4] != NULL);
249 	spdk_bdev_close(desc[4]);
250 
251 	free_vbdev(bdev[7]);
252 
253 	free_vbdev(bdev[3]);
254 	free_vbdev(bdev[4]);
255 	free_vbdev(bdev[5]);
256 	free_vbdev(bdev[6]);
257 
258 	free_bdev(bdev[0]);
259 	free_bdev(bdev[1]);
260 	free_bdev(bdev[2]);
261 
262 }
263 
264 static void
265 bytes_to_blocks_test(void)
266 {
267 	struct spdk_bdev bdev;
268 	uint64_t offset_blocks, num_blocks;
269 
270 	memset(&bdev, 0, sizeof(bdev));
271 
272 	bdev.blocklen = 512;
273 
274 	/* All parameters valid */
275 	offset_blocks = 0;
276 	num_blocks = 0;
277 	CU_ASSERT(spdk_bdev_bytes_to_blocks(&bdev, 512, &offset_blocks, 1024, &num_blocks) == 0);
278 	CU_ASSERT(offset_blocks == 1);
279 	CU_ASSERT(num_blocks == 2);
280 
281 	/* Offset not a block multiple */
282 	CU_ASSERT(spdk_bdev_bytes_to_blocks(&bdev, 3, &offset_blocks, 512, &num_blocks) != 0);
283 
284 	/* Length not a block multiple */
285 	CU_ASSERT(spdk_bdev_bytes_to_blocks(&bdev, 512, &offset_blocks, 3, &num_blocks) != 0);
286 }
287 
288 static void
289 io_valid_test(void)
290 {
291 	struct spdk_bdev bdev;
292 
293 	memset(&bdev, 0, sizeof(bdev));
294 
295 	bdev.blocklen = 512;
296 	bdev.blockcnt = 100;
297 
298 	/* All parameters valid */
299 	CU_ASSERT(spdk_bdev_io_valid_blocks(&bdev, 1, 2) == true);
300 
301 	/* Last valid block */
302 	CU_ASSERT(spdk_bdev_io_valid_blocks(&bdev, 99, 1) == true);
303 
304 	/* Offset past end of bdev */
305 	CU_ASSERT(spdk_bdev_io_valid_blocks(&bdev, 100, 1) == false);
306 
307 	/* Offset + length past end of bdev */
308 	CU_ASSERT(spdk_bdev_io_valid_blocks(&bdev, 99, 2) == false);
309 
310 	/* Offset near end of uint64_t range (2^64 - 1) */
311 	CU_ASSERT(spdk_bdev_io_valid_blocks(&bdev, 18446744073709551615ULL, 1) == false);
312 }
313 
314 static int
315 __destruct(void *ctx)
316 {
317 	return 0;
318 }
319 
320 static struct spdk_bdev_fn_table base_fn_table = {
321 	.destruct		= __destruct,
322 };
323 static struct spdk_bdev_fn_table part_fn_table = {
324 	.destruct		= __destruct,
325 };
326 
327 static void
328 __base_free(struct spdk_bdev_part_base *base)
329 {
330 	free(base);
331 }
332 
333 static void
334 part_test(void)
335 {
336 	struct spdk_bdev_part_base	*base;
337 	struct spdk_bdev_part		part1, part2;
338 	struct spdk_bdev		bdev_base = {};
339 	SPDK_BDEV_PART_TAILQ		tailq = TAILQ_HEAD_INITIALIZER(tailq);
340 	int rc;
341 
342 	base = calloc(1, sizeof(*base));
343 	SPDK_CU_ASSERT_FATAL(base != NULL);
344 
345 	bdev_base.name = "base";
346 	bdev_base.fn_table = &base_fn_table;
347 	bdev_base.module = SPDK_GET_BDEV_MODULE(bdev_ut);
348 	rc = spdk_bdev_register(&bdev_base);
349 	CU_ASSERT(rc == 0);
350 	spdk_bdev_part_base_construct(base, &bdev_base, NULL, SPDK_GET_BDEV_MODULE(vbdev_ut),
351 				      &part_fn_table, &tailq, __base_free, 0, NULL, NULL);
352 
353 	spdk_bdev_part_construct(&part1, base, "test1", 0, 100, "test");
354 	spdk_bdev_part_construct(&part2, base, "test2", 100, 100, "test");
355 
356 	spdk_bdev_part_base_hotremove(&bdev_base, &tailq);
357 
358 	/*
359 	 * The base device was removed - ensure that the partition vbdevs were
360 	 *  removed from the base's vbdev list.
361 	 */
362 	CU_ASSERT(TAILQ_EMPTY(&bdev_base.vbdevs));
363 
364 	spdk_bdev_part_base_free(base);
365 	spdk_bdev_unregister(&bdev_base, NULL, NULL);
366 }
367 
368 static void
369 alias_add_del_test(void)
370 {
371 	struct spdk_bdev *bdev[2];
372 	int rc;
373 
374 	/* Creating and registering bdevs */
375 	bdev[0] = allocate_bdev("bdev0");
376 	SPDK_CU_ASSERT_FATAL(bdev[0] != 0);
377 
378 	bdev[1] = allocate_bdev("bdev1");
379 	SPDK_CU_ASSERT_FATAL(bdev[1] != 0);
380 
381 	/*
382 	 * Trying adding an alias identical to name.
383 	 * Alias is identical to name, so it can not be added to aliases list
384 	 */
385 	rc = spdk_bdev_alias_add(bdev[0], bdev[0]->name);
386 	CU_ASSERT(rc == -EEXIST);
387 
388 	/*
389 	 * Trying to add empty alias,
390 	 * this one should fail
391 	 */
392 	rc = spdk_bdev_alias_add(bdev[0], NULL);
393 	CU_ASSERT(rc == -EINVAL);
394 
395 	/* Trying adding same alias to two different registered bdevs */
396 
397 	/* Alias is used first time, so this one should pass */
398 	rc = spdk_bdev_alias_add(bdev[0], "proper alias 0");
399 	CU_ASSERT(rc == 0);
400 
401 	/* Alias was added to another bdev, so this one should fail */
402 	rc = spdk_bdev_alias_add(bdev[1], "proper alias 0");
403 	CU_ASSERT(rc == -EEXIST);
404 
405 	/* Alias is used first time, so this one should pass */
406 	rc = spdk_bdev_alias_add(bdev[1], "proper alias 1");
407 	CU_ASSERT(rc == 0);
408 
409 	/* Trying removing an alias from registered bdevs */
410 
411 	/* Alias is not on a bdev aliases list, so this one should fail */
412 	rc = spdk_bdev_alias_del(bdev[0], "not existing");
413 	CU_ASSERT(rc == -ENOENT);
414 
415 	/* Alias is present on a bdev aliases list, so this one should pass */
416 	rc = spdk_bdev_alias_del(bdev[0], "proper alias 0");
417 	CU_ASSERT(rc == 0);
418 
419 	/* Alias is present on a bdev aliases list, so this one should pass */
420 	rc = spdk_bdev_alias_del(bdev[1], "proper alias 1");
421 	CU_ASSERT(rc == 0);
422 
423 	/* Trying to remove name instead of alias, so this one should fail, name cannot be changed or removed */
424 	rc = spdk_bdev_alias_del(bdev[0], bdev[0]->name);
425 	CU_ASSERT(rc != 0);
426 
427 	/* Unregister and free bdevs */
428 	spdk_bdev_unregister(bdev[0], NULL, NULL);
429 	spdk_bdev_unregister(bdev[1], NULL, NULL);
430 
431 	free(bdev[0]);
432 	free(bdev[1]);
433 }
434 
435 int
436 main(int argc, char **argv)
437 {
438 	CU_pSuite	suite = NULL;
439 	unsigned int	num_failures;
440 
441 	if (CU_initialize_registry() != CUE_SUCCESS) {
442 		return CU_get_error();
443 	}
444 
445 	suite = CU_add_suite("bdev", null_init, null_clean);
446 	if (suite == NULL) {
447 		CU_cleanup_registry();
448 		return CU_get_error();
449 	}
450 
451 	if (
452 		CU_add_test(suite, "bytes_to_blocks_test", bytes_to_blocks_test) == NULL ||
453 		CU_add_test(suite, "io_valid", io_valid_test) == NULL ||
454 		CU_add_test(suite, "open_write", open_write_test) == NULL ||
455 		CU_add_test(suite, "part", part_test) == NULL ||
456 		CU_add_test(suite, "alias_add_del", alias_add_del_test) == NULL
457 	) {
458 		CU_cleanup_registry();
459 		return CU_get_error();
460 	}
461 
462 	CU_basic_set_mode(CU_BRM_VERBOSE);
463 	CU_basic_run_tests();
464 	num_failures = CU_get_number_of_failures();
465 	CU_cleanup_registry();
466 	return num_failures;
467 }
468