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