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