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