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_io_channel_get_ctx(struct spdk_io_channel *ch) 47 { 48 return NULL; 49 } 50 51 void 52 spdk_io_device_register(void *io_device, spdk_io_channel_create_cb create_cb, 53 spdk_io_channel_destroy_cb destroy_cb, uint32_t ctx_size) 54 { 55 } 56 57 void 58 spdk_io_device_unregister(void *io_device, spdk_io_device_unregister_cb unregister_cb) 59 { 60 } 61 62 void 63 spdk_thread_send_msg(const struct spdk_thread *thread, spdk_thread_fn fn, void *ctx) 64 { 65 } 66 67 struct spdk_io_channel * 68 spdk_get_io_channel(void *io_device) 69 { 70 return NULL; 71 } 72 73 void 74 spdk_put_io_channel(struct spdk_io_channel *ch) 75 { 76 } 77 78 void 79 spdk_for_each_channel(void *io_device, spdk_channel_msg fn, void *ctx, 80 spdk_channel_for_each_cpl cpl) 81 { 82 } 83 84 struct spdk_thread * 85 spdk_io_channel_get_thread(struct spdk_io_channel *ch) 86 { 87 return NULL; 88 } 89 90 void 91 spdk_scsi_nvme_translate(const struct spdk_bdev_io *bdev_io, 92 int *sc, int *sk, int *asc, int *ascq) 93 { 94 } 95 96 static int 97 null_init(void) 98 { 99 return 0; 100 } 101 102 static int 103 null_clean(void) 104 { 105 return 0; 106 } 107 108 static int 109 stub_destruct(void *ctx) 110 { 111 return 0; 112 } 113 114 static struct spdk_bdev_fn_table fn_table = { 115 .destruct = stub_destruct, 116 }; 117 118 static void 119 vbdev_ut_examine(struct spdk_bdev *bdev) 120 { 121 spdk_bdev_module_examine_done(SPDK_GET_BDEV_MODULE(vbdev_ut)); 122 } 123 124 SPDK_BDEV_MODULE_REGISTER(bdev_ut, NULL, NULL, NULL, NULL, NULL) 125 SPDK_BDEV_MODULE_REGISTER(vbdev_ut, NULL, NULL, NULL, NULL, vbdev_ut_examine) 126 127 static struct spdk_bdev * 128 allocate_bdev(char *name) 129 { 130 struct spdk_bdev *bdev; 131 132 bdev = calloc(1, sizeof(*bdev)); 133 SPDK_CU_ASSERT_FATAL(bdev != NULL); 134 135 bdev->name = name; 136 bdev->fn_table = &fn_table; 137 bdev->module = SPDK_GET_BDEV_MODULE(bdev_ut); 138 139 spdk_bdev_register(bdev); 140 CU_ASSERT(TAILQ_EMPTY(&bdev->base_bdevs)); 141 CU_ASSERT(TAILQ_EMPTY(&bdev->vbdevs)); 142 143 return bdev; 144 } 145 146 static struct spdk_bdev * 147 allocate_vbdev(char *name, struct spdk_bdev *base1, struct spdk_bdev *base2) 148 { 149 struct spdk_bdev *bdev; 150 struct spdk_bdev *array[2]; 151 152 bdev = calloc(1, sizeof(*bdev)); 153 SPDK_CU_ASSERT_FATAL(bdev != NULL); 154 155 bdev->name = name; 156 bdev->fn_table = &fn_table; 157 bdev->module = SPDK_GET_BDEV_MODULE(vbdev_ut); 158 159 /* vbdev must have at least one base bdev */ 160 CU_ASSERT(base1 != NULL); 161 162 array[0] = base1; 163 array[1] = base2; 164 165 spdk_vbdev_register(bdev, array, base2 == NULL ? 1 : 2); 166 CU_ASSERT(!TAILQ_EMPTY(&bdev->base_bdevs)); 167 CU_ASSERT(TAILQ_EMPTY(&bdev->vbdevs)); 168 169 return bdev; 170 } 171 172 static void 173 free_bdev(struct spdk_bdev *bdev) 174 { 175 spdk_bdev_unregister(bdev); 176 free(bdev); 177 } 178 179 static void 180 free_vbdev(struct spdk_bdev *bdev) 181 { 182 spdk_vbdev_unregister(bdev); 183 free(bdev); 184 } 185 186 static void 187 open_write_test(void) 188 { 189 struct spdk_bdev *bdev[8]; 190 struct spdk_bdev_desc *desc[8]; 191 int rc; 192 193 /* 194 * Create a tree of bdevs to test various open w/ write cases. 195 * 196 * bdev0 through bdev2 are physical block devices, such as NVMe 197 * namespaces or Ceph block devices. 198 * 199 * bdev3 is a virtual bdev with multiple base bdevs. This models 200 * caching or RAID use cases. 201 * 202 * bdev4 through bdev6 are all virtual bdevs with the same base 203 * bdev. This models partitioning or logical volume use cases. 204 * 205 * bdev7 is a virtual bdev with multiple base bdevs, but these 206 * base bdevs are themselves virtual bdevs. 207 * 208 * bdev7 209 * | 210 * +----------+ 211 * | | 212 * bdev3 bdev4 bdev5 bdev6 213 * | | | | 214 * +---+---+ +-------+-------+ 215 * | | | 216 * bdev0 bdev1 bdev2 217 */ 218 219 bdev[0] = allocate_bdev("bdev0"); 220 rc = spdk_bdev_module_claim_bdev(bdev[0], NULL, SPDK_GET_BDEV_MODULE(bdev_ut)); 221 CU_ASSERT(rc == 0); 222 223 bdev[1] = allocate_bdev("bdev1"); 224 rc = spdk_bdev_module_claim_bdev(bdev[1], NULL, SPDK_GET_BDEV_MODULE(bdev_ut)); 225 CU_ASSERT(rc == 0); 226 227 bdev[2] = allocate_bdev("bdev2"); 228 rc = spdk_bdev_module_claim_bdev(bdev[2], NULL, SPDK_GET_BDEV_MODULE(bdev_ut)); 229 CU_ASSERT(rc == 0); 230 231 bdev[3] = allocate_vbdev("bdev3", bdev[0], bdev[1]); 232 rc = spdk_bdev_module_claim_bdev(bdev[3], NULL, SPDK_GET_BDEV_MODULE(bdev_ut)); 233 CU_ASSERT(rc == 0); 234 235 bdev[4] = allocate_vbdev("bdev4", bdev[2], NULL); 236 rc = spdk_bdev_module_claim_bdev(bdev[4], NULL, SPDK_GET_BDEV_MODULE(bdev_ut)); 237 CU_ASSERT(rc == 0); 238 239 bdev[5] = allocate_vbdev("bdev5", bdev[2], NULL); 240 bdev[6] = allocate_vbdev("bdev6", bdev[2], NULL); 241 242 bdev[7] = allocate_vbdev("bdev7", bdev[3], bdev[4]); 243 244 /* Open bdev0 read-only. This should succeed. */ 245 rc = spdk_bdev_open(bdev[0], false, NULL, NULL, &desc[0]); 246 CU_ASSERT(rc == 0); 247 CU_ASSERT(desc[0] != NULL); 248 spdk_bdev_close(desc[0]); 249 250 /* 251 * Open bdev1 read/write. This should fail since bdev1 has been claimed 252 * by a vbdev module. 253 */ 254 rc = spdk_bdev_open(bdev[1], true, NULL, NULL, &desc[1]); 255 CU_ASSERT(rc == -EPERM); 256 257 /* 258 * Open bdev3 read/write. This should fail since bdev3 has been claimed 259 * by a vbdev module. 260 */ 261 rc = spdk_bdev_open(bdev[3], true, NULL, NULL, &desc[3]); 262 CU_ASSERT(rc == -EPERM); 263 264 /* Open bdev3 read-only. This should succeed. */ 265 rc = spdk_bdev_open(bdev[3], false, NULL, NULL, &desc[3]); 266 CU_ASSERT(rc == 0); 267 CU_ASSERT(desc[3] != NULL); 268 spdk_bdev_close(desc[3]); 269 270 /* 271 * Open bdev7 read/write. This should succeed since it is a leaf 272 * bdev. 273 */ 274 rc = spdk_bdev_open(bdev[7], true, NULL, NULL, &desc[7]); 275 CU_ASSERT(rc == 0); 276 CU_ASSERT(desc[7] != NULL); 277 spdk_bdev_close(desc[7]); 278 279 /* 280 * Open bdev4 read/write. This should fail since bdev4 has been claimed 281 * by a vbdev module. 282 */ 283 rc = spdk_bdev_open(bdev[4], true, NULL, NULL, &desc[4]); 284 CU_ASSERT(rc == -EPERM); 285 286 /* Open bdev4 read-only. This should succeed. */ 287 rc = spdk_bdev_open(bdev[4], false, NULL, NULL, &desc[4]); 288 CU_ASSERT(rc == 0); 289 CU_ASSERT(desc[4] != NULL); 290 spdk_bdev_close(desc[4]); 291 292 free_vbdev(bdev[7]); 293 294 free_vbdev(bdev[3]); 295 free_vbdev(bdev[4]); 296 free_vbdev(bdev[5]); 297 free_vbdev(bdev[6]); 298 299 free_bdev(bdev[0]); 300 free_bdev(bdev[1]); 301 free_bdev(bdev[2]); 302 303 } 304 305 static void 306 io_valid_test(void) 307 { 308 struct spdk_bdev bdev; 309 310 memset(&bdev, 0, sizeof(bdev)); 311 312 bdev.blocklen = 512; 313 bdev.blockcnt = 100; 314 315 /* All parameters valid */ 316 CU_ASSERT(spdk_bdev_io_valid(&bdev, 512, 1024) == true); 317 318 /* Offset not a block multiple */ 319 CU_ASSERT(spdk_bdev_io_valid(&bdev, 3, 512) == false); 320 321 /* Length not a block multiple */ 322 CU_ASSERT(spdk_bdev_io_valid(&bdev, 512, 3) == false); 323 324 /* Last valid block */ 325 CU_ASSERT(spdk_bdev_io_valid(&bdev, 50688, 512) == true); 326 327 /* Offset past end of bdev */ 328 CU_ASSERT(spdk_bdev_io_valid(&bdev, 51200, 512) == false); 329 330 /* Offset + length past end of bdev */ 331 CU_ASSERT(spdk_bdev_io_valid(&bdev, 50688, 1024) == false); 332 333 /* Offset near end of uint64_t range (2^64 - 512) */ 334 CU_ASSERT(spdk_bdev_io_valid(&bdev, 18446744073709551104ULL, 512) == false); 335 } 336 337 int 338 main(int argc, char **argv) 339 { 340 CU_pSuite suite = NULL; 341 unsigned int num_failures; 342 343 if (CU_initialize_registry() != CUE_SUCCESS) { 344 return CU_get_error(); 345 } 346 347 suite = CU_add_suite("bdev", null_init, null_clean); 348 if (suite == NULL) { 349 CU_cleanup_registry(); 350 return CU_get_error(); 351 } 352 353 if ( 354 CU_add_test(suite, "io_valid", io_valid_test) == NULL || 355 CU_add_test(suite, "open_write", open_write_test) == NULL 356 ) { 357 CU_cleanup_registry(); 358 return CU_get_error(); 359 } 360 361 CU_basic_set_mode(CU_BRM_VERBOSE); 362 CU_basic_run_tests(); 363 num_failures = CU_get_number_of_failures(); 364 CU_cleanup_registry(); 365 return num_failures; 366 } 367