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