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 "bdev.c" 38 39 void * 40 spdk_io_channel_get_ctx(struct spdk_io_channel *ch) 41 { 42 return NULL; 43 } 44 45 void 46 spdk_io_device_register(void *io_device, spdk_io_channel_create_cb create_cb, 47 spdk_io_channel_destroy_cb destroy_cb, uint32_t ctx_size) 48 { 49 } 50 51 void 52 spdk_io_device_unregister(void *io_device) 53 { 54 } 55 56 void 57 spdk_thread_send_msg(const struct spdk_thread *thread, spdk_thread_fn fn, void *ctx) 58 { 59 } 60 61 struct spdk_io_channel * 62 spdk_get_io_channel(void *io_device) 63 { 64 return NULL; 65 } 66 67 void 68 spdk_put_io_channel(struct spdk_io_channel *ch) 69 { 70 } 71 72 void 73 spdk_for_each_channel(void *io_device, spdk_channel_msg fn, void *ctx, 74 spdk_channel_for_each_cpl cpl) 75 { 76 } 77 78 struct spdk_thread * 79 spdk_io_channel_get_thread(struct spdk_io_channel *ch) 80 { 81 return NULL; 82 } 83 84 void 85 spdk_scsi_nvme_translate(const struct spdk_bdev_io *bdev_io, 86 int *sc, int *sk, int *asc, int *ascq) 87 { 88 } 89 90 static int 91 null_init(void) 92 { 93 return 0; 94 } 95 96 static int 97 null_clean(void) 98 { 99 return 0; 100 } 101 102 static int 103 stub_destruct(void *ctx) 104 { 105 return 0; 106 } 107 108 static struct spdk_bdev_fn_table fn_table = { 109 .destruct = stub_destruct, 110 }; 111 112 static struct spdk_bdev * 113 allocate_bdev(char *name) 114 { 115 struct spdk_bdev *bdev; 116 117 bdev = calloc(1, sizeof(*bdev)); 118 SPDK_CU_ASSERT_FATAL(bdev != NULL); 119 120 bdev->name = name; 121 bdev->fn_table = &fn_table; 122 123 spdk_bdev_register(bdev); 124 CU_ASSERT(TAILQ_EMPTY(&bdev->base_bdevs)); 125 CU_ASSERT(TAILQ_EMPTY(&bdev->vbdevs)); 126 127 return bdev; 128 } 129 130 static struct spdk_bdev * 131 allocate_vbdev(char *name, struct spdk_bdev *base1, struct spdk_bdev *base2) 132 { 133 struct spdk_bdev *bdev; 134 struct spdk_bdev *array[2]; 135 136 bdev = calloc(1, sizeof(*bdev)); 137 SPDK_CU_ASSERT_FATAL(bdev != NULL); 138 139 bdev->name = name; 140 bdev->fn_table = &fn_table; 141 142 /* vbdev must have at least one base bdev */ 143 CU_ASSERT(base1 != NULL); 144 145 array[0] = base1; 146 array[1] = base2; 147 148 spdk_vbdev_register(bdev, array, base2 == NULL ? 1 : 2); 149 CU_ASSERT(!TAILQ_EMPTY(&bdev->base_bdevs)); 150 CU_ASSERT(TAILQ_EMPTY(&bdev->vbdevs)); 151 152 return bdev; 153 } 154 155 static void 156 free_bdev(struct spdk_bdev *bdev) 157 { 158 spdk_bdev_unregister(bdev); 159 free(bdev); 160 } 161 162 static void 163 free_vbdev(struct spdk_bdev *bdev) 164 { 165 spdk_vbdev_unregister(bdev); 166 free(bdev); 167 } 168 169 static void 170 open_write_test(void) 171 { 172 struct spdk_bdev *bdev[8]; 173 struct spdk_bdev_desc *desc[8]; 174 int rc; 175 176 /* 177 * Create a tree of bdevs to test various open w/ write cases. 178 * 179 * bdev0 through bdev2 are physical block devices, such as NVMe 180 * namespaces or Ceph block devices. 181 * 182 * bdev3 is a virtual bdev with multiple base bdevs. This models 183 * caching or RAID use cases. 184 * 185 * bdev4 through bdev6 are all virtual bdevs with the same base 186 * bdev. This models partitioning or logical volume use cases. 187 * 188 * bdev7 is a virtual bdev with multiple base bdevs, but these 189 * base bdevs are themselves virtual bdevs. 190 * 191 * bdev7 192 * | 193 * +----------+ 194 * | | 195 * bdev3 bdev4 bdev5 bdev6 196 * | | | | 197 * +---+---+ +-------+-------+ 198 * | | | 199 * bdev0 bdev1 bdev2 200 */ 201 202 bdev[0] = allocate_bdev("bdev0"); 203 bdev[1] = allocate_bdev("bdev1"); 204 bdev[2] = allocate_bdev("bdev2"); 205 206 bdev[3] = allocate_vbdev("bdev3", bdev[0], bdev[1]); 207 208 bdev[4] = allocate_vbdev("bdev4", bdev[2], NULL); 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 /* Open bdev1 read/write. This should succeed. */ 221 rc = spdk_bdev_open(bdev[1], true, NULL, NULL, &desc[1]); 222 CU_ASSERT(rc == 0); 223 CU_ASSERT(desc[1] != NULL); 224 225 /* 226 * Open bdev3 read/write. This should fail, since one of its 227 * base bdevs have been explicitly opened read/write. 228 */ 229 rc = spdk_bdev_open(bdev[3], true, NULL, NULL, &desc[3]); 230 CU_ASSERT(rc == -EPERM); 231 232 /* Open bdev3 read-only. This should succeed. */ 233 rc = spdk_bdev_open(bdev[3], false, NULL, NULL, &desc[3]); 234 CU_ASSERT(rc == 0); 235 CU_ASSERT(desc[3] != NULL); 236 spdk_bdev_close(desc[3]); 237 238 /* 239 * Open bdev7 read/write. This should fail, since one of its 240 * base bdevs have been explicitly opened read/write. This 241 * test ensures the bdev code traverses through multiple levels 242 * of base bdevs. 243 */ 244 rc = spdk_bdev_open(bdev[7], true, NULL, NULL, &desc[7]); 245 CU_ASSERT(rc == -EPERM); 246 247 /* Open bdev7 read-only. This should succeed. */ 248 rc = spdk_bdev_open(bdev[7], false, NULL, NULL, &desc[7]); 249 CU_ASSERT(rc == 0); 250 CU_ASSERT(desc[7] != NULL); 251 spdk_bdev_close(desc[7]); 252 253 /* Reset tree by closing remaining descriptors. */ 254 spdk_bdev_close(desc[1]); 255 256 /* Open bdev7 read/write. This should succeed. */ 257 rc = spdk_bdev_open(bdev[7], true, NULL, NULL, &desc[7]); 258 CU_ASSERT(rc == 0); 259 CU_ASSERT(desc[7] != NULL); 260 261 /* 262 * Open bdev4 read/write. This should fail, since one of its 263 * virtual bdevs has been explicitly opened read/write. 264 */ 265 rc = spdk_bdev_open(bdev[4], true, NULL, NULL, &desc[4]); 266 CU_ASSERT(rc == -EPERM); 267 268 /* Open bdev4 read-only. This should succeed. */ 269 rc = spdk_bdev_open(bdev[4], false, NULL, NULL, &desc[4]); 270 CU_ASSERT(rc == 0); 271 CU_ASSERT(desc[4] != NULL); 272 spdk_bdev_close(desc[4]); 273 274 /* 275 * Open bdev2 read/write. This should fail, since one of its 276 * virtual bdevs has been explicitly opened read/write. This 277 * test ensures the bdev code traverses through multiple levels 278 * of virtual bdevs. 279 */ 280 rc = spdk_bdev_open(bdev[2], true, NULL, NULL, &desc[2]); 281 CU_ASSERT(rc == -EPERM); 282 283 /* Open bdev2 read-only. This should succeed. */ 284 rc = spdk_bdev_open(bdev[2], false, NULL, NULL, &desc[2]); 285 CU_ASSERT(rc == 0); 286 CU_ASSERT(desc[2] != NULL); 287 spdk_bdev_close(desc[2]); 288 289 /* Reset tree by closing remaining descriptors. */ 290 spdk_bdev_close(desc[7]); 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 int 306 main(int argc, char **argv) 307 { 308 CU_pSuite suite = NULL; 309 unsigned int num_failures; 310 311 if (CU_initialize_registry() != CUE_SUCCESS) { 312 return CU_get_error(); 313 } 314 315 suite = CU_add_suite("bdev", null_init, null_clean); 316 if (suite == NULL) { 317 CU_cleanup_registry(); 318 return CU_get_error(); 319 } 320 321 if ( 322 CU_add_test(suite, "open_write", open_write_test) == NULL 323 ) { 324 CU_cleanup_registry(); 325 return CU_get_error(); 326 } 327 328 CU_basic_set_mode(CU_BRM_VERBOSE); 329 CU_basic_run_tests(); 330 num_failures = CU_get_number_of_failures(); 331 CU_cleanup_registry(); 332 return num_failures; 333 } 334