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) 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_vbdev_module_examine_done(SPDK_GET_BDEV_MODULE(vbdev_ut)); 122 } 123 124 SPDK_BDEV_MODULE_REGISTER(bdev_ut, NULL, NULL, NULL, NULL) 125 SPDK_VBDEV_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 bdev[1] = allocate_bdev("bdev1"); 221 bdev[2] = allocate_bdev("bdev2"); 222 223 bdev[3] = allocate_vbdev("bdev3", bdev[0], bdev[1]); 224 225 bdev[4] = allocate_vbdev("bdev4", bdev[2], NULL); 226 bdev[5] = allocate_vbdev("bdev5", bdev[2], NULL); 227 bdev[6] = allocate_vbdev("bdev6", bdev[2], NULL); 228 229 bdev[7] = allocate_vbdev("bdev7", bdev[3], bdev[4]); 230 231 /* Open bdev0 read-only. This should succeed. */ 232 rc = spdk_bdev_open(bdev[0], false, NULL, NULL, &desc[0]); 233 CU_ASSERT(rc == 0); 234 CU_ASSERT(desc[0] != NULL); 235 spdk_bdev_close(desc[0]); 236 237 /* Open bdev1 read/write. This should succeed. */ 238 rc = spdk_bdev_open(bdev[1], true, NULL, NULL, &desc[1]); 239 CU_ASSERT(rc == 0); 240 CU_ASSERT(desc[1] != NULL); 241 242 /* 243 * Open bdev3 read/write. This should fail, since one of its 244 * base bdevs have been explicitly opened read/write. 245 */ 246 rc = spdk_bdev_open(bdev[3], true, NULL, NULL, &desc[3]); 247 CU_ASSERT(rc == -EPERM); 248 249 /* Open bdev3 read-only. This should succeed. */ 250 rc = spdk_bdev_open(bdev[3], false, NULL, NULL, &desc[3]); 251 CU_ASSERT(rc == 0); 252 CU_ASSERT(desc[3] != NULL); 253 spdk_bdev_close(desc[3]); 254 255 /* 256 * Open bdev7 read/write. This should fail, since one of its 257 * base bdevs have been explicitly opened read/write. This 258 * test ensures the bdev code traverses through multiple levels 259 * of base bdevs. 260 */ 261 rc = spdk_bdev_open(bdev[7], true, NULL, NULL, &desc[7]); 262 CU_ASSERT(rc == -EPERM); 263 264 /* Open bdev7 read-only. This should succeed. */ 265 rc = spdk_bdev_open(bdev[7], false, NULL, NULL, &desc[7]); 266 CU_ASSERT(rc == 0); 267 CU_ASSERT(desc[7] != NULL); 268 spdk_bdev_close(desc[7]); 269 270 /* Reset tree by closing remaining descriptors. */ 271 spdk_bdev_close(desc[1]); 272 273 /* Open bdev7 read/write. This should succeed. */ 274 rc = spdk_bdev_open(bdev[7], true, NULL, NULL, &desc[7]); 275 CU_ASSERT(rc == 0); 276 CU_ASSERT(desc[7] != NULL); 277 278 /* 279 * Open bdev4 read/write. This should fail, since one of its 280 * virtual bdevs has been explicitly opened read/write. 281 */ 282 rc = spdk_bdev_open(bdev[4], true, NULL, NULL, &desc[4]); 283 CU_ASSERT(rc == -EPERM); 284 285 /* Open bdev4 read-only. This should succeed. */ 286 rc = spdk_bdev_open(bdev[4], false, NULL, NULL, &desc[4]); 287 CU_ASSERT(rc == 0); 288 CU_ASSERT(desc[4] != NULL); 289 spdk_bdev_close(desc[4]); 290 291 /* 292 * Open bdev2 read/write. This should fail, since one of its 293 * virtual bdevs has been explicitly opened read/write. This 294 * test ensures the bdev code traverses through multiple levels 295 * of virtual bdevs. 296 */ 297 rc = spdk_bdev_open(bdev[2], true, NULL, NULL, &desc[2]); 298 CU_ASSERT(rc == -EPERM); 299 300 /* Open bdev2 read-only. This should succeed. */ 301 rc = spdk_bdev_open(bdev[2], false, NULL, NULL, &desc[2]); 302 CU_ASSERT(rc == 0); 303 CU_ASSERT(desc[2] != NULL); 304 spdk_bdev_close(desc[2]); 305 306 /* Reset tree by closing remaining descriptors. */ 307 spdk_bdev_close(desc[7]); 308 309 free_vbdev(bdev[7]); 310 311 free_vbdev(bdev[3]); 312 free_vbdev(bdev[4]); 313 free_vbdev(bdev[5]); 314 free_vbdev(bdev[6]); 315 316 free_bdev(bdev[0]); 317 free_bdev(bdev[1]); 318 free_bdev(bdev[2]); 319 320 } 321 322 int 323 main(int argc, char **argv) 324 { 325 CU_pSuite suite = NULL; 326 unsigned int num_failures; 327 328 if (CU_initialize_registry() != CUE_SUCCESS) { 329 return CU_get_error(); 330 } 331 332 suite = CU_add_suite("bdev", null_init, null_clean); 333 if (suite == NULL) { 334 CU_cleanup_registry(); 335 return CU_get_error(); 336 } 337 338 if ( 339 CU_add_test(suite, "open_write", open_write_test) == NULL 340 ) { 341 CU_cleanup_registry(); 342 return CU_get_error(); 343 } 344 345 CU_basic_set_mode(CU_BRM_VERBOSE); 346 CU_basic_run_tests(); 347 num_failures = CU_get_number_of_failures(); 348 CU_cleanup_registry(); 349 return num_failures; 350 } 351