1 /* SPDX-License-Identifier: BSD-3-Clause 2 * Copyright (C) 2018 Intel Corporation. 3 * All rights reserved. 4 * Copyright (c) 2023 NVIDIA CORPORATION & AFFILIATES. All rights reserved. 5 */ 6 7 #include "spdk_internal/cunit.h" 8 9 #include "common/lib/ut_multithread.c" 10 #include "unit/lib/json_mock.c" 11 12 #include "spdk/config.h" 13 /* HACK: disable VTune integration so the unit test doesn't need VTune headers and libs to build */ 14 #undef SPDK_CONFIG_VTUNE 15 16 #include "bdev/bdev.c" 17 #include "bdev/part.c" 18 19 struct ut_expected_io { 20 }; 21 22 struct bdev_ut_channel { 23 TAILQ_HEAD(, spdk_bdev_io) outstanding_io; 24 uint32_t outstanding_io_count; 25 TAILQ_HEAD(, ut_expected_io) expected_io; 26 }; 27 28 static uint32_t g_part_ut_io_device; 29 static struct bdev_ut_channel *g_bdev_ut_channel; 30 static int g_accel_io_device; 31 32 DEFINE_STUB(spdk_notify_send, uint64_t, (const char *type, const char *ctx), 0); 33 DEFINE_STUB(spdk_notify_type_register, struct spdk_notify_type *, (const char *type), NULL); 34 DEFINE_STUB(spdk_memory_domain_get_dma_device_id, const char *, (struct spdk_memory_domain *domain), 35 "test_domain"); 36 DEFINE_STUB(spdk_memory_domain_get_dma_device_type, enum spdk_dma_device_type, 37 (struct spdk_memory_domain *domain), 0); 38 DEFINE_STUB_V(spdk_accel_sequence_finish, 39 (struct spdk_accel_sequence *seq, spdk_accel_completion_cb cb_fn, void *cb_arg)); 40 DEFINE_STUB_V(spdk_accel_sequence_abort, (struct spdk_accel_sequence *seq)); 41 DEFINE_STUB_V(spdk_accel_sequence_reverse, (struct spdk_accel_sequence *seq)); 42 DEFINE_STUB(spdk_accel_append_copy, int, 43 (struct spdk_accel_sequence **seq, struct spdk_io_channel *ch, struct iovec *dst_iovs, 44 uint32_t dst_iovcnt, struct spdk_memory_domain *dst_domain, void *dst_domain_ctx, 45 struct iovec *src_iovs, uint32_t src_iovcnt, struct spdk_memory_domain *src_domain, 46 void *src_domain_ctx, int flags, spdk_accel_step_cb cb_fn, void *cb_arg), 0); 47 DEFINE_STUB(spdk_accel_get_memory_domain, struct spdk_memory_domain *, (void), NULL); 48 49 DEFINE_RETURN_MOCK(spdk_memory_domain_pull_data, int); 50 int 51 spdk_memory_domain_pull_data(struct spdk_memory_domain *src_domain, void *src_domain_ctx, 52 struct iovec *src_iov, uint32_t src_iov_cnt, struct iovec *dst_iov, uint32_t dst_iov_cnt, 53 spdk_memory_domain_data_cpl_cb cpl_cb, void *cpl_cb_arg) 54 { 55 HANDLE_RETURN_MOCK(spdk_memory_domain_pull_data); 56 57 cpl_cb(cpl_cb_arg, 0); 58 return 0; 59 } 60 61 DEFINE_RETURN_MOCK(spdk_memory_domain_push_data, int); 62 int 63 spdk_memory_domain_push_data(struct spdk_memory_domain *dst_domain, void *dst_domain_ctx, 64 struct iovec *dst_iov, uint32_t dst_iovcnt, struct iovec *src_iov, uint32_t src_iovcnt, 65 spdk_memory_domain_data_cpl_cb cpl_cb, void *cpl_cb_arg) 66 { 67 HANDLE_RETURN_MOCK(spdk_memory_domain_push_data); 68 69 cpl_cb(cpl_cb_arg, 0); 70 return 0; 71 } 72 73 struct spdk_io_channel * 74 spdk_accel_get_io_channel(void) 75 { 76 return spdk_get_io_channel(&g_accel_io_device); 77 } 78 79 static int 80 ut_accel_ch_create_cb(void *io_device, void *ctx) 81 { 82 return 0; 83 } 84 85 static void 86 ut_accel_ch_destroy_cb(void *io_device, void *ctx) 87 { 88 } 89 90 static int 91 ut_part_setup(void) 92 { 93 spdk_io_device_register(&g_accel_io_device, ut_accel_ch_create_cb, 94 ut_accel_ch_destroy_cb, 0, NULL); 95 return 0; 96 } 97 98 static int 99 ut_part_teardown(void) 100 { 101 spdk_io_device_unregister(&g_accel_io_device, NULL); 102 103 return 0; 104 } 105 106 static void 107 _part_cleanup(struct spdk_bdev_part *part) 108 { 109 spdk_io_device_unregister(part, NULL); 110 free(part->internal.bdev.name); 111 free(part->internal.bdev.product_name); 112 } 113 114 static struct spdk_io_channel * 115 part_ut_get_io_channel(void *ctx) 116 { 117 return spdk_get_io_channel(&g_part_ut_io_device); 118 } 119 120 void 121 spdk_scsi_nvme_translate(const struct spdk_bdev_io *bdev_io, 122 int *sc, int *sk, int *asc, int *ascq) 123 { 124 } 125 126 static int 127 bdev_ut_create_ch(void *io_device, void *ctx_buf) 128 { 129 struct bdev_ut_channel *ch = ctx_buf; 130 131 CU_ASSERT(g_bdev_ut_channel == NULL); 132 g_bdev_ut_channel = ch; 133 g_part_ut_io_device++; 134 135 TAILQ_INIT(&ch->outstanding_io); 136 ch->outstanding_io_count = 0; 137 TAILQ_INIT(&ch->expected_io); 138 return 0; 139 } 140 141 static void 142 bdev_ut_destroy_ch(void *io_device, void *ctx_buf) 143 { 144 CU_ASSERT(g_bdev_ut_channel != NULL); 145 g_bdev_ut_channel = NULL; 146 g_part_ut_io_device--; 147 } 148 149 struct spdk_bdev_module bdev_ut_if; 150 151 static int 152 bdev_ut_module_init(void) 153 { 154 spdk_io_device_register(&g_part_ut_io_device, bdev_ut_create_ch, bdev_ut_destroy_ch, 155 sizeof(struct bdev_ut_channel), NULL); 156 spdk_bdev_module_init_done(&bdev_ut_if); 157 return 0; 158 } 159 160 static void 161 bdev_ut_module_fini(void) 162 { 163 spdk_io_device_unregister(&g_part_ut_io_device, NULL); 164 } 165 166 struct spdk_bdev_module bdev_ut_if = { 167 .name = "bdev_ut", 168 .module_init = bdev_ut_module_init, 169 .module_fini = bdev_ut_module_fini, 170 .async_init = true, 171 }; 172 173 static void vbdev_ut_examine(struct spdk_bdev *bdev); 174 175 static int 176 vbdev_ut_module_init(void) 177 { 178 return 0; 179 } 180 181 static void 182 vbdev_ut_module_fini(void) 183 { 184 } 185 186 struct spdk_bdev_module vbdev_ut_if = { 187 .name = "vbdev_ut", 188 .module_init = vbdev_ut_module_init, 189 .module_fini = vbdev_ut_module_fini, 190 .examine_config = vbdev_ut_examine, 191 }; 192 193 SPDK_BDEV_MODULE_REGISTER(bdev_ut, &bdev_ut_if) 194 SPDK_BDEV_MODULE_REGISTER(vbdev_ut, &vbdev_ut_if) 195 196 static void 197 vbdev_ut_examine(struct spdk_bdev *bdev) 198 { 199 spdk_bdev_module_examine_done(&vbdev_ut_if); 200 } 201 202 static int 203 __destruct(void *ctx) 204 { 205 return 0; 206 } 207 208 static bool 209 __io_type_supported(void *ctx, enum spdk_bdev_io_type type) 210 { 211 return true; 212 } 213 214 static struct spdk_bdev_fn_table base_fn_table = { 215 .destruct = __destruct, 216 .get_io_channel = part_ut_get_io_channel, 217 .io_type_supported = __io_type_supported, 218 }; 219 static struct spdk_bdev_fn_table part_fn_table = { 220 .destruct = __destruct, 221 .io_type_supported = __io_type_supported, 222 }; 223 224 static void 225 bdev_init_cb(void *arg, int rc) 226 { 227 CU_ASSERT(rc == 0); 228 } 229 230 static void 231 bdev_fini_cb(void *arg) 232 { 233 } 234 235 static void 236 ut_init_bdev(void) 237 { 238 int rc; 239 240 rc = spdk_iobuf_initialize(); 241 CU_ASSERT(rc == 0); 242 243 spdk_bdev_initialize(bdev_init_cb, NULL); 244 poll_threads(); 245 } 246 247 static void 248 ut_fini_bdev(void) 249 { 250 spdk_bdev_finish(bdev_fini_cb, NULL); 251 spdk_iobuf_finish(bdev_fini_cb, NULL); 252 poll_threads(); 253 } 254 255 static void 256 bdev_ut_event_cb(enum spdk_bdev_event_type type, struct spdk_bdev *bdev, void *event_ctx) 257 { 258 } 259 260 static void 261 part_test(void) 262 { 263 struct spdk_bdev_part_base *base; 264 struct spdk_bdev_part part1 = {}; 265 struct spdk_bdev_part part2 = {}; 266 struct spdk_bdev_part part3 = {}; 267 struct spdk_bdev bdev_base = {}; 268 SPDK_BDEV_PART_TAILQ tailq = TAILQ_HEAD_INITIALIZER(tailq); 269 int rc; 270 271 bdev_base.name = "base"; 272 bdev_base.fn_table = &base_fn_table; 273 bdev_base.module = &bdev_ut_if; 274 rc = spdk_bdev_register(&bdev_base); 275 CU_ASSERT(rc == 0); 276 rc = spdk_bdev_part_base_construct_ext("base", NULL, &vbdev_ut_if, 277 &part_fn_table, &tailq, NULL, 278 NULL, 0, NULL, NULL, &base); 279 280 CU_ASSERT(rc == 0); 281 SPDK_CU_ASSERT_FATAL(base != NULL); 282 283 rc = spdk_bdev_part_construct(&part1, base, "test1", 0, 100, "test"); 284 SPDK_CU_ASSERT_FATAL(rc == 0); 285 SPDK_CU_ASSERT_FATAL(base->ref == 1); 286 SPDK_CU_ASSERT_FATAL(base->claimed == true); 287 rc = spdk_bdev_part_construct(&part2, base, "test2", 100, 100, "test"); 288 SPDK_CU_ASSERT_FATAL(rc == 0); 289 SPDK_CU_ASSERT_FATAL(base->ref == 2); 290 SPDK_CU_ASSERT_FATAL(base->claimed == true); 291 rc = spdk_bdev_part_construct(&part3, base, "test1", 0, 100, "test"); 292 SPDK_CU_ASSERT_FATAL(rc != 0); 293 SPDK_CU_ASSERT_FATAL(base->ref == 2); 294 SPDK_CU_ASSERT_FATAL(base->claimed == true); 295 296 spdk_bdev_part_base_hotremove(base, &tailq); 297 298 spdk_bdev_part_base_free(base); 299 _part_cleanup(&part1); 300 _part_cleanup(&part2); 301 spdk_bdev_unregister(&bdev_base, NULL, NULL); 302 303 poll_threads(); 304 } 305 306 static void 307 part_free_test(void) 308 { 309 struct spdk_bdev_part_base *base = NULL; 310 struct spdk_bdev_part *part; 311 struct spdk_bdev bdev_base = {}; 312 SPDK_BDEV_PART_TAILQ tailq = TAILQ_HEAD_INITIALIZER(tailq); 313 int rc; 314 315 bdev_base.name = "base"; 316 bdev_base.fn_table = &base_fn_table; 317 bdev_base.module = &bdev_ut_if; 318 rc = spdk_bdev_register(&bdev_base); 319 CU_ASSERT(rc == 0); 320 poll_threads(); 321 322 rc = spdk_bdev_part_base_construct_ext("base", NULL, &vbdev_ut_if, 323 &part_fn_table, &tailq, NULL, 324 NULL, 0, NULL, NULL, &base); 325 CU_ASSERT(rc == 0); 326 CU_ASSERT(TAILQ_EMPTY(&tailq)); 327 SPDK_CU_ASSERT_FATAL(base != NULL); 328 329 part = calloc(1, sizeof(*part)); 330 SPDK_CU_ASSERT_FATAL(part != NULL); 331 rc = spdk_bdev_part_construct(part, base, "test", 0, 100, "test"); 332 SPDK_CU_ASSERT_FATAL(rc == 0); 333 poll_threads(); 334 CU_ASSERT(!TAILQ_EMPTY(&tailq)); 335 336 spdk_bdev_unregister(&part->internal.bdev, NULL, NULL); 337 poll_threads(); 338 339 rc = spdk_bdev_part_free(part); 340 CU_ASSERT(rc == 1); 341 poll_threads(); 342 CU_ASSERT(TAILQ_EMPTY(&tailq)); 343 344 spdk_bdev_unregister(&bdev_base, NULL, NULL); 345 poll_threads(); 346 } 347 348 static void 349 part_get_io_channel_test(void) 350 { 351 struct spdk_bdev_part_base *base = NULL; 352 struct spdk_bdev_desc *desc = NULL; 353 struct spdk_io_channel *io_ch; 354 struct spdk_bdev_part *part; 355 struct spdk_bdev bdev_base = {}; 356 SPDK_BDEV_PART_TAILQ tailq = TAILQ_HEAD_INITIALIZER(tailq); 357 int rc; 358 359 ut_init_bdev(); 360 bdev_base.name = "base"; 361 bdev_base.blocklen = 512; 362 bdev_base.blockcnt = 1024; 363 bdev_base.fn_table = &base_fn_table; 364 bdev_base.module = &bdev_ut_if; 365 rc = spdk_bdev_register(&bdev_base); 366 CU_ASSERT(rc == 0); 367 368 rc = spdk_bdev_part_base_construct_ext("base", NULL, &vbdev_ut_if, 369 &part_fn_table, &tailq, NULL, 370 NULL, 100, NULL, NULL, &base); 371 CU_ASSERT(rc == 0); 372 CU_ASSERT(TAILQ_EMPTY(&tailq)); 373 SPDK_CU_ASSERT_FATAL(base != NULL); 374 375 part = calloc(1, sizeof(*part)); 376 SPDK_CU_ASSERT_FATAL(part != NULL); 377 rc = spdk_bdev_part_construct(part, base, "test", 0, 100, "test"); 378 SPDK_CU_ASSERT_FATAL(rc == 0); 379 CU_ASSERT(!TAILQ_EMPTY(&tailq)); 380 381 rc = spdk_bdev_open_ext("test", true, bdev_ut_event_cb, NULL, &desc); 382 CU_ASSERT(rc == 0); 383 SPDK_CU_ASSERT_FATAL(desc != NULL); 384 CU_ASSERT(&part->internal.bdev == spdk_bdev_desc_get_bdev(desc)); 385 386 io_ch = spdk_bdev_get_io_channel(desc); 387 CU_ASSERT(io_ch != NULL); 388 CU_ASSERT(g_part_ut_io_device == 1); 389 390 spdk_put_io_channel(io_ch); 391 spdk_bdev_close(desc); 392 spdk_bdev_unregister(&part->internal.bdev, NULL, NULL); 393 poll_threads(); 394 CU_ASSERT(g_part_ut_io_device == 0); 395 396 rc = spdk_bdev_part_free(part); 397 CU_ASSERT(rc == 1); 398 poll_threads(); 399 CU_ASSERT(TAILQ_EMPTY(&tailq)); 400 401 spdk_bdev_unregister(&bdev_base, NULL, NULL); 402 ut_fini_bdev(); 403 } 404 405 static void 406 part_construct_ext(void) 407 { 408 struct spdk_bdev_part_base *base; 409 struct spdk_bdev_part part1 = {}; 410 struct spdk_bdev bdev_base = {}; 411 SPDK_BDEV_PART_TAILQ tailq = TAILQ_HEAD_INITIALIZER(tailq); 412 const char *uuid = "7ed764b7-a841-41b1-ba93-6548d9335a44"; 413 struct spdk_bdev_part_construct_opts opts; 414 int rc; 415 416 bdev_base.name = "base"; 417 bdev_base.fn_table = &base_fn_table; 418 bdev_base.module = &bdev_ut_if; 419 rc = spdk_bdev_register(&bdev_base); 420 CU_ASSERT(rc == 0); 421 rc = spdk_bdev_part_base_construct_ext("base", NULL, &vbdev_ut_if, 422 &part_fn_table, &tailq, NULL, 423 NULL, 0, NULL, NULL, &base); 424 425 CU_ASSERT(rc == 0); 426 SPDK_CU_ASSERT_FATAL(base != NULL); 427 428 /* Verify opts.uuid is used as bdev UUID */ 429 spdk_bdev_part_construct_opts_init(&opts, sizeof(opts)); 430 spdk_uuid_parse(&opts.uuid, uuid); 431 rc = spdk_bdev_part_construct_ext(&part1, base, "test1", 0, 100, "test", &opts); 432 SPDK_CU_ASSERT_FATAL(rc == 0); 433 SPDK_CU_ASSERT_FATAL(base->ref == 1); 434 SPDK_CU_ASSERT_FATAL(base->claimed == true); 435 CU_ASSERT(spdk_bdev_get_by_name(uuid) != NULL); 436 CU_ASSERT(spdk_bdev_get_by_name("test1") != NULL); 437 438 /* Clean up */ 439 spdk_bdev_part_base_hotremove(base, &tailq); 440 spdk_bdev_part_base_free(base); 441 _part_cleanup(&part1); 442 spdk_bdev_unregister(&bdev_base, NULL, NULL); 443 444 poll_threads(); 445 } 446 447 int 448 main(int argc, char **argv) 449 { 450 CU_pSuite suite = NULL; 451 unsigned int num_failures; 452 453 CU_initialize_registry(); 454 455 suite = CU_add_suite("bdev_part", ut_part_setup, ut_part_teardown); 456 457 CU_ADD_TEST(suite, part_test); 458 CU_ADD_TEST(suite, part_free_test); 459 CU_ADD_TEST(suite, part_get_io_channel_test); 460 CU_ADD_TEST(suite, part_construct_ext); 461 462 allocate_cores(1); 463 allocate_threads(1); 464 set_thread(0); 465 466 num_failures = spdk_ut_run_tests(argc, argv, NULL); 467 CU_cleanup_registry(); 468 469 free_threads(); 470 free_cores(); 471 472 return num_failures; 473 } 474