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