1 /* SPDX-License-Identifier: BSD-3-Clause 2 * Copyright (C) 2020 Intel Corporation. 3 * All rights reserved. 4 * Copyright 2023 Solidigm All Rights Reserved 5 */ 6 7 #include "spdk/stdinc.h" 8 #include "spdk/bdev.h" 9 #include "spdk/env.h" 10 #include "spdk/thread.h" 11 #include "spdk/json.h" 12 #include "spdk/string.h" 13 #include "spdk/likely.h" 14 #include "spdk/util.h" 15 #include "spdk/string.h" 16 #include "spdk/ftl.h" 17 #include "spdk/log.h" 18 19 #include "bdev_ftl.h" 20 21 struct ftl_bdev { 22 struct spdk_bdev bdev; 23 struct spdk_ftl_dev *dev; 24 ftl_bdev_init_fn init_cb; 25 void *init_arg; 26 int rc; 27 struct spdk_bdev_desc *base_bdev_desc; 28 struct spdk_bdev_desc *cache_bdev_desc; 29 }; 30 31 struct bdev_ftl_action { 32 struct spdk_bdev_desc *ftl_bdev_desc; 33 struct ftl_bdev *ftl_bdev_dev; 34 spdk_ftl_fn cb_fn; 35 void *cb_arg; 36 int rc; 37 size_t ctx_size; 38 char ctx[0]; 39 }; 40 41 struct ftl_deferred_init { 42 struct spdk_ftl_conf conf; 43 44 LIST_ENTRY(ftl_deferred_init) entry; 45 }; 46 47 static LIST_HEAD(, ftl_deferred_init) g_deferred_init = LIST_HEAD_INITIALIZER(g_deferred_init); 48 49 static int bdev_ftl_initialize(void); 50 static void bdev_ftl_finish(void); 51 static void bdev_ftl_examine(struct spdk_bdev *bdev); 52 53 static void bdev_ftl_action_finish_cb(void *cb_arg, int status); 54 static struct bdev_ftl_action *bdev_ftl_action_start(const char *bdev_name, 55 size_t ctx_size, spdk_ftl_fn cb_fn, void *cb_arg); 56 static void bdev_ftl_action_finish(struct bdev_ftl_action *action); 57 static void *bdev_ftl_action_ctx(struct bdev_ftl_action *action, size_t size); 58 59 static int 60 bdev_ftl_get_ctx_size(void) 61 { 62 return spdk_ftl_io_size(); 63 } 64 65 static struct spdk_bdev_module g_ftl_if = { 66 .name = "ftl", 67 .module_init = bdev_ftl_initialize, 68 .module_fini = bdev_ftl_finish, 69 .examine_disk = bdev_ftl_examine, 70 .get_ctx_size = bdev_ftl_get_ctx_size, 71 }; 72 73 SPDK_BDEV_MODULE_REGISTER(ftl, &g_ftl_if) 74 75 static void 76 bdev_ftl_free(struct ftl_bdev *ftl_bdev) 77 { 78 spdk_bdev_close(ftl_bdev->base_bdev_desc); 79 spdk_bdev_close(ftl_bdev->cache_bdev_desc); 80 free(ftl_bdev->bdev.name); 81 free(ftl_bdev); 82 } 83 84 static void 85 bdev_ftl_dev_free_cb(void *ctx, int status) 86 { 87 struct ftl_bdev *ftl_bdev = ctx; 88 89 spdk_bdev_destruct_done(&ftl_bdev->bdev, status); 90 bdev_ftl_free(ftl_bdev); 91 } 92 93 static int 94 bdev_ftl_destruct(void *ctx) 95 { 96 struct ftl_bdev *ftl_bdev = ctx; 97 98 spdk_ftl_dev_free(ftl_bdev->dev, bdev_ftl_dev_free_cb, ftl_bdev); 99 100 /* return 1 to indicate that the destruction is asynchronous */ 101 return 1; 102 } 103 104 static void 105 bdev_ftl_cb(void *arg, int rc) 106 { 107 struct spdk_bdev_io *bdev_io = arg; 108 enum spdk_bdev_io_status status; 109 110 switch (rc) { 111 case 0: 112 status = SPDK_BDEV_IO_STATUS_SUCCESS; 113 break; 114 case -EAGAIN: 115 case -ENOMEM: 116 status = SPDK_BDEV_IO_STATUS_NOMEM; 117 break; 118 default: 119 status = SPDK_BDEV_IO_STATUS_FAILED; 120 break; 121 } 122 123 spdk_bdev_io_complete(bdev_io, status); 124 } 125 126 static void 127 bdev_ftl_get_buf_cb(struct spdk_io_channel *ch, struct spdk_bdev_io *bdev_io, 128 bool success) 129 { 130 struct ftl_bdev *ftl_bdev; 131 int rc; 132 133 ftl_bdev = bdev_io->bdev->ctxt; 134 135 if (!success) { 136 spdk_bdev_io_complete(bdev_io, SPDK_BDEV_IO_STATUS_FAILED); 137 return; 138 } 139 140 rc = spdk_ftl_readv(ftl_bdev->dev, (struct ftl_io *)bdev_io->driver_ctx, 141 ch, 142 bdev_io->u.bdev.offset_blocks, 143 bdev_io->u.bdev.num_blocks, 144 bdev_io->u.bdev.iovs, bdev_io->u.bdev.iovcnt, bdev_ftl_cb, bdev_io); 145 146 if (spdk_unlikely(rc != 0)) { 147 bdev_ftl_cb(bdev_io, rc); 148 } 149 } 150 151 static int 152 _bdev_ftl_submit_request(struct spdk_io_channel *ch, struct spdk_bdev_io *bdev_io) 153 { 154 struct ftl_bdev *ftl_bdev = (struct ftl_bdev *)bdev_io->bdev->ctxt; 155 156 switch (bdev_io->type) { 157 case SPDK_BDEV_IO_TYPE_READ: 158 spdk_bdev_io_get_buf(bdev_io, bdev_ftl_get_buf_cb, 159 bdev_io->u.bdev.num_blocks * bdev_io->bdev->blocklen); 160 return 0; 161 162 case SPDK_BDEV_IO_TYPE_WRITE: 163 return spdk_ftl_writev(ftl_bdev->dev, (struct ftl_io *)bdev_io->driver_ctx, 164 ch, bdev_io->u.bdev.offset_blocks, 165 bdev_io->u.bdev.num_blocks, bdev_io->u.bdev.iovs, 166 bdev_io->u.bdev.iovcnt, bdev_ftl_cb, bdev_io); 167 168 case SPDK_BDEV_IO_TYPE_UNMAP: 169 return spdk_ftl_unmap(ftl_bdev->dev, (struct ftl_io *)bdev_io->driver_ctx, 170 ch, bdev_io->u.bdev.offset_blocks, 171 bdev_io->u.bdev.num_blocks, bdev_ftl_cb, bdev_io); 172 case SPDK_BDEV_IO_TYPE_FLUSH: 173 spdk_bdev_io_complete(bdev_io, SPDK_BDEV_IO_STATUS_SUCCESS); 174 return 0; 175 default: 176 return -ENOTSUP; 177 } 178 } 179 180 static void 181 bdev_ftl_submit_request(struct spdk_io_channel *ch, struct spdk_bdev_io *bdev_io) 182 { 183 int rc = _bdev_ftl_submit_request(ch, bdev_io); 184 185 if (spdk_unlikely(rc != 0)) { 186 bdev_ftl_cb(bdev_io, rc); 187 } 188 } 189 190 static bool 191 bdev_ftl_io_type_supported(void *ctx, enum spdk_bdev_io_type io_type) 192 { 193 switch (io_type) { 194 case SPDK_BDEV_IO_TYPE_READ: 195 case SPDK_BDEV_IO_TYPE_WRITE: 196 case SPDK_BDEV_IO_TYPE_FLUSH: 197 case SPDK_BDEV_IO_TYPE_UNMAP: 198 return true; 199 default: 200 return false; 201 } 202 } 203 204 static struct spdk_io_channel * 205 bdev_ftl_get_io_channel(void *ctx) 206 { 207 struct ftl_bdev *ftl_bdev = ctx; 208 209 return spdk_ftl_get_io_channel(ftl_bdev->dev); 210 } 211 212 static void 213 bdev_ftl_write_config_json(struct spdk_bdev *bdev, struct spdk_json_write_ctx *w) 214 { 215 struct ftl_bdev *ftl_bdev = bdev->ctxt; 216 struct spdk_ftl_conf conf; 217 218 spdk_ftl_dev_get_conf(ftl_bdev->dev, &conf, sizeof(conf)); 219 220 spdk_json_write_object_begin(w); 221 222 spdk_json_write_named_string(w, "method", "bdev_ftl_create"); 223 224 spdk_json_write_named_object_begin(w, "params"); 225 spdk_json_write_named_string(w, "name", ftl_bdev->bdev.name); 226 227 spdk_json_write_named_uint64(w, "overprovisioning", conf.overprovisioning); 228 spdk_json_write_named_uint64(w, "l2p_dram_limit", conf.l2p_dram_limit); 229 230 if (conf.core_mask) { 231 spdk_json_write_named_string(w, "core_mask", conf.core_mask); 232 } 233 234 spdk_json_write_named_uuid(w, "uuid", &conf.uuid); 235 236 spdk_json_write_named_bool(w, "fast_shutdown", conf.fast_shutdown); 237 238 spdk_json_write_named_string(w, "base_bdev", conf.base_bdev); 239 240 if (conf.cache_bdev) { 241 spdk_json_write_named_string(w, "cache", conf.cache_bdev); 242 } 243 244 spdk_json_write_object_end(w); 245 spdk_json_write_object_end(w); 246 } 247 248 static int 249 bdev_ftl_dump_info_json(void *ctx, struct spdk_json_write_ctx *w) 250 { 251 struct ftl_bdev *ftl_bdev = ctx; 252 struct spdk_ftl_attrs attrs; 253 struct spdk_ftl_conf conf; 254 255 spdk_ftl_dev_get_attrs(ftl_bdev->dev, &attrs, sizeof(attrs)); 256 spdk_ftl_dev_get_conf(ftl_bdev->dev, &conf, sizeof(conf)); 257 258 spdk_json_write_named_object_begin(w, "ftl"); 259 260 spdk_json_write_named_string(w, "base_bdev", conf.base_bdev); 261 262 if (conf.cache_bdev) { 263 spdk_json_write_named_string(w, "cache", conf.cache_bdev); 264 } 265 266 /* ftl */ 267 spdk_json_write_object_end(w); 268 269 return 0; 270 } 271 272 static const struct spdk_bdev_fn_table ftl_fn_table = { 273 .destruct = bdev_ftl_destruct, 274 .submit_request = bdev_ftl_submit_request, 275 .io_type_supported = bdev_ftl_io_type_supported, 276 .get_io_channel = bdev_ftl_get_io_channel, 277 .write_config_json = bdev_ftl_write_config_json, 278 .dump_info_json = bdev_ftl_dump_info_json, 279 }; 280 281 static void 282 bdev_ftl_create_err_complete(struct ftl_bdev *ftl_bdev) 283 { 284 ftl_bdev_init_fn init_cb = ftl_bdev->init_cb; 285 void *init_arg = ftl_bdev->init_arg; 286 int rc = ftl_bdev->rc; 287 288 bdev_ftl_free(ftl_bdev); 289 290 assert(rc); 291 init_cb(NULL, init_arg, rc); 292 } 293 294 static void 295 bdev_ftl_create_err_cleanup_cb(void *ctx, int status) 296 { 297 struct ftl_bdev *ftl_bdev = ctx; 298 299 if (status) { 300 SPDK_ERRLOG("Fatal ERROR of FTL cleanup, name %s\n", ftl_bdev->bdev.name); 301 } 302 303 bdev_ftl_create_err_complete(ftl_bdev); 304 } 305 306 static void 307 bdev_ftl_create_cb(struct spdk_ftl_dev *dev, void *ctx, int status) 308 { 309 struct ftl_bdev *ftl_bdev = ctx; 310 struct ftl_bdev_info info = {}; 311 struct spdk_ftl_attrs attrs; 312 struct spdk_ftl_conf conf; 313 ftl_bdev_init_fn init_cb = ftl_bdev->init_cb; 314 void *init_arg = ftl_bdev->init_arg; 315 316 if (status) { 317 SPDK_ERRLOG("Failed to create FTL device (%d)\n", status); 318 ftl_bdev->rc = status; 319 goto error; 320 } 321 322 spdk_ftl_dev_get_attrs(dev, &attrs, sizeof(attrs)); 323 spdk_ftl_dev_get_conf(dev, &conf, sizeof(conf)); 324 325 ftl_bdev->dev = dev; 326 ftl_bdev->bdev.product_name = "FTL disk"; 327 ftl_bdev->bdev.write_cache = 0; 328 ftl_bdev->bdev.blocklen = attrs.block_size; 329 ftl_bdev->bdev.blockcnt = attrs.num_blocks; 330 ftl_bdev->bdev.uuid = conf.uuid; 331 ftl_bdev->bdev.optimal_io_boundary = attrs.optimum_io_size; 332 ftl_bdev->bdev.split_on_optimal_io_boundary = true; 333 334 SPDK_DEBUGLOG(bdev_ftl, "Creating bdev %s:\n", ftl_bdev->bdev.name); 335 SPDK_DEBUGLOG(bdev_ftl, "\tblock_len:\t%zu\n", attrs.block_size); 336 SPDK_DEBUGLOG(bdev_ftl, "\tnum_blocks:\t%"PRIu64"\n", attrs.num_blocks); 337 338 ftl_bdev->bdev.ctxt = ftl_bdev; 339 ftl_bdev->bdev.fn_table = &ftl_fn_table; 340 ftl_bdev->bdev.module = &g_ftl_if; 341 342 status = spdk_bdev_register(&ftl_bdev->bdev); 343 if (status) { 344 ftl_bdev->rc = status; 345 goto error; 346 } 347 348 info.name = ftl_bdev->bdev.name; 349 info.uuid = ftl_bdev->bdev.uuid; 350 351 init_cb(&info, init_arg, 0); 352 return; 353 354 error: 355 if (ftl_bdev->dev) { 356 /* Cleanup all FTL */ 357 spdk_ftl_dev_set_fast_shutdown(ftl_bdev->dev, false); 358 359 /* FTL was created, but we have got an error, so we need to delete it */ 360 spdk_ftl_dev_free(dev, bdev_ftl_create_err_cleanup_cb, ftl_bdev); 361 } else { 362 bdev_ftl_create_err_complete(ftl_bdev); 363 } 364 } 365 366 static void 367 bdev_ftl_defer_free(struct ftl_deferred_init *init) 368 { 369 spdk_ftl_conf_deinit(&init->conf); 370 free(init); 371 } 372 373 int 374 bdev_ftl_defer_init(const struct spdk_ftl_conf *conf) 375 { 376 struct ftl_deferred_init *init; 377 int rc; 378 379 init = calloc(1, sizeof(*init)); 380 if (!init) { 381 return -ENOMEM; 382 } 383 384 rc = spdk_ftl_conf_copy(&init->conf, conf); 385 if (rc) { 386 free(init); 387 return -ENOMEM; 388 } 389 390 LIST_INSERT_HEAD(&g_deferred_init, init, entry); 391 392 return 0; 393 } 394 395 static void 396 bdev_ftl_create_bdev_event_cb(enum spdk_bdev_event_type type, struct spdk_bdev *bdev, void *ctx) 397 { 398 } 399 400 int 401 bdev_ftl_create_bdev(const struct spdk_ftl_conf *conf, ftl_bdev_init_fn cb, void *cb_arg) 402 { 403 struct ftl_bdev *ftl_bdev; 404 struct spdk_bdev_desc *base_bdev_desc, *cache_bdev_desc; 405 int rc; 406 407 rc = spdk_bdev_open_ext(conf->base_bdev, false, bdev_ftl_create_bdev_event_cb, NULL, 408 &base_bdev_desc); 409 if (rc) { 410 return rc; 411 } 412 rc = spdk_bdev_open_ext(conf->cache_bdev, false, bdev_ftl_create_bdev_event_cb, NULL, 413 &cache_bdev_desc); 414 if (rc) { 415 spdk_bdev_close(base_bdev_desc); 416 return rc; 417 } 418 419 ftl_bdev = calloc(1, sizeof(*ftl_bdev)); 420 if (!ftl_bdev) { 421 SPDK_ERRLOG("Could not allocate ftl_bdev\n"); 422 spdk_bdev_close(base_bdev_desc); 423 spdk_bdev_close(cache_bdev_desc); 424 return -ENOMEM; 425 } 426 427 ftl_bdev->base_bdev_desc = base_bdev_desc; 428 ftl_bdev->cache_bdev_desc = cache_bdev_desc; 429 430 ftl_bdev->bdev.name = strdup(conf->name); 431 if (!ftl_bdev->bdev.name) { 432 rc = -ENOMEM; 433 goto error; 434 } 435 436 ftl_bdev->init_cb = cb; 437 ftl_bdev->init_arg = cb_arg; 438 439 rc = spdk_ftl_dev_init(conf, bdev_ftl_create_cb, ftl_bdev); 440 if (rc) { 441 SPDK_ERRLOG("Could not create FTL device\n"); 442 goto error; 443 } 444 445 return 0; 446 447 error: 448 bdev_ftl_free(ftl_bdev); 449 return rc; 450 } 451 452 static int 453 bdev_ftl_initialize(void) 454 { 455 return spdk_ftl_init(); 456 } 457 458 static void 459 bdev_ftl_event_cb(enum spdk_bdev_event_type type, struct spdk_bdev *bdev, void *ctx) 460 { 461 } 462 463 void 464 bdev_ftl_delete_bdev(const char *name, bool fast_shutdown, spdk_bdev_unregister_cb cb_fn, 465 void *cb_arg) 466 { 467 struct spdk_bdev_desc *ftl_bdev_desc; 468 struct spdk_bdev *bdev; 469 struct ftl_bdev *ftl; 470 int rc; 471 472 rc = spdk_bdev_open_ext(name, false, bdev_ftl_event_cb, NULL, &ftl_bdev_desc); 473 474 if (rc) { 475 goto not_found; 476 } 477 478 bdev = spdk_bdev_desc_get_bdev(ftl_bdev_desc); 479 480 if (bdev->module != &g_ftl_if) { 481 goto bdev_opened; 482 } 483 484 ftl = bdev->ctxt; 485 assert(ftl); 486 spdk_ftl_dev_set_fast_shutdown(ftl->dev, fast_shutdown); 487 spdk_bdev_close(ftl_bdev_desc); 488 489 rc = spdk_bdev_unregister_by_name(name, &g_ftl_if, cb_fn, cb_arg); 490 if (rc) { 491 cb_fn(cb_arg, rc); 492 } 493 494 return; 495 bdev_opened: 496 spdk_bdev_close(ftl_bdev_desc); 497 not_found: 498 cb_fn(cb_arg, -ENODEV); 499 } 500 501 void 502 bdev_ftl_unmap(const char *name, uint64_t lba, uint64_t num_blocks, spdk_ftl_fn cb_fn, 503 void *cb_arg) 504 { 505 struct bdev_ftl_action *action; 506 507 action = bdev_ftl_action_start(name, 0, cb_fn, cb_arg); 508 if (!action) { 509 return; 510 } 511 512 /* It's ok to pass NULL as IO channel - FTL will detect this and use it's internal IO channel for management operations */ 513 action->rc = spdk_ftl_unmap(action->ftl_bdev_dev->dev, NULL, NULL, lba, num_blocks, 514 bdev_ftl_action_finish_cb, action); 515 if (action->rc) { 516 bdev_ftl_action_finish(action); 517 } 518 } 519 520 static void 521 bdev_ftl_get_stats_cb(struct ftl_stats *stats, void *cb_arg) 522 { 523 struct bdev_ftl_action *action = cb_arg; 524 525 bdev_ftl_action_finish(action); 526 } 527 528 void 529 bdev_ftl_get_stats(const char *name, spdk_ftl_fn cb, struct rpc_ftl_stats_ctx *ftl_stats_ctx) 530 { 531 struct bdev_ftl_action *action; 532 533 action = bdev_ftl_action_start(name, 0, cb, ftl_stats_ctx); 534 if (!action) { 535 return; 536 } 537 ftl_stats_ctx->ftl_bdev_desc = action->ftl_bdev_desc; 538 action->rc = spdk_ftl_get_stats(action->ftl_bdev_dev->dev, &ftl_stats_ctx->ftl_stats, 539 bdev_ftl_get_stats_cb, action); 540 if (action->rc) { 541 bdev_ftl_action_finish(action); 542 } 543 } 544 545 void 546 bdev_ftl_get_properties(const char *name, spdk_ftl_fn cb_fn, struct spdk_jsonrpc_request *request) 547 { 548 struct bdev_ftl_action *action; 549 550 action = bdev_ftl_action_start(name, 0, cb_fn, request); 551 if (!action) { 552 return; 553 } 554 555 action->rc = spdk_ftl_get_properties(action->ftl_bdev_dev->dev, request, 556 bdev_ftl_action_finish_cb, action); 557 if (action->rc) { 558 bdev_ftl_action_finish(action); 559 } 560 } 561 562 struct bdev_ftl_set_property_args { 563 char *property; 564 char *value; 565 }; 566 567 static void 568 bdev_ftl_set_property_cb(void *cb_arg, int status) 569 { 570 struct bdev_ftl_action *action = cb_arg; 571 struct bdev_ftl_set_property_args *args = bdev_ftl_action_ctx(action, sizeof(*args)); 572 573 free(args->property); 574 free(args->value); 575 args->property = NULL; 576 args->value = NULL; 577 bdev_ftl_action_finish_cb(cb_arg, status); 578 } 579 580 void 581 bdev_ftl_set_property(const char *name, const char *property, const char *value, 582 spdk_ftl_fn cb_fn, void *cb_arg) 583 { 584 struct bdev_ftl_action *action; 585 struct bdev_ftl_set_property_args *args; 586 587 action = bdev_ftl_action_start(name, sizeof(*args), cb_fn, cb_arg); 588 if (!action) { 589 return; 590 } 591 592 args = bdev_ftl_action_ctx(action, sizeof(*args)); 593 args->property = strdup(property); 594 args->value = strdup(value); 595 596 if (!args->property || !args->value) { 597 free(args->property); 598 free(args->value); 599 action->rc = -ENOMEM; 600 bdev_ftl_action_finish(action); 601 return; 602 } 603 604 action->rc = spdk_ftl_set_property(action->ftl_bdev_dev->dev, 605 args->property, args->value, strlen(args->value) + 1, 606 bdev_ftl_set_property_cb, action); 607 if (action->rc) { 608 bdev_ftl_action_finish(action); 609 } 610 } 611 612 static void 613 bdev_ftl_finish(void) 614 { 615 spdk_ftl_fini(); 616 } 617 618 static void 619 bdev_ftl_create_deferred_cb(const struct ftl_bdev_info *info, void *ctx, int status) 620 { 621 struct ftl_deferred_init *opts = ctx; 622 623 if (status) { 624 SPDK_ERRLOG("Failed to initialize FTL bdev '%s'\n", opts->conf.name); 625 } 626 627 bdev_ftl_defer_free(opts); 628 629 spdk_bdev_module_examine_done(&g_ftl_if); 630 } 631 632 static void 633 bdev_ftl_examine(struct spdk_bdev *bdev) 634 { 635 struct ftl_deferred_init *opts; 636 int rc; 637 638 LIST_FOREACH(opts, &g_deferred_init, entry) { 639 /* spdk_bdev_module_examine_done will be called by bdev_ftl_create_deferred_cb */ 640 rc = bdev_ftl_create_bdev(&opts->conf, bdev_ftl_create_deferred_cb, opts); 641 if (rc == -ENODEV) { 642 continue; 643 } 644 645 LIST_REMOVE(opts, entry); 646 647 if (rc) { 648 bdev_ftl_create_deferred_cb(NULL, opts, rc); 649 } 650 return; 651 } 652 653 spdk_bdev_module_examine_done(&g_ftl_if); 654 } 655 656 SPDK_LOG_REGISTER_COMPONENT(bdev_ftl) 657 658 /* 659 * Generic function to execute an action on the FTL bdev 660 */ 661 static void 662 bdev_ftl_action_finish(struct bdev_ftl_action *action) 663 { 664 action->cb_fn(action->cb_arg, action->rc); 665 if (action->ftl_bdev_desc) { 666 spdk_bdev_close(action->ftl_bdev_desc); 667 } 668 free(action); 669 } 670 671 static struct bdev_ftl_action * 672 bdev_ftl_action_start(const char *bdev_name, size_t ctx_size, spdk_ftl_fn cb_fn, void *cb_arg) 673 { 674 struct spdk_bdev *bdev; 675 struct bdev_ftl_action *action = calloc(1, sizeof(*action) + ctx_size); 676 677 if (NULL == action) { 678 cb_fn(cb_arg, -ENOMEM); 679 return NULL; 680 } 681 action->cb_arg = cb_arg; 682 action->cb_fn = cb_fn; 683 action->ctx_size = ctx_size; 684 685 action->rc = spdk_bdev_open_ext(bdev_name, false, bdev_ftl_event_cb, NULL, &action->ftl_bdev_desc); 686 if (action->rc) { 687 goto error; 688 } 689 690 bdev = spdk_bdev_desc_get_bdev(action->ftl_bdev_desc); 691 if (bdev->module != &g_ftl_if) { 692 action->rc = -ENODEV; 693 goto error; 694 } 695 696 action->ftl_bdev_dev = bdev->ctxt; 697 assert(action->ftl_bdev_dev); 698 699 return action; 700 error: 701 bdev_ftl_action_finish(action); 702 return NULL; 703 } 704 705 static void 706 bdev_ftl_action_finish_cb(void *cb_arg, int status) 707 { 708 struct bdev_ftl_action *action = cb_arg; 709 710 action->rc = status; 711 bdev_ftl_action_finish(action); 712 } 713 714 static void * 715 bdev_ftl_action_ctx(struct bdev_ftl_action *action, size_t size) 716 { 717 assert(action->ctx_size); 718 assert(size == action->ctx_size); 719 return action->ctx; 720 } 721