1 /* SPDX-License-Identifier: BSD-3-Clause 2 * Copyright (c) Intel Corporation. 3 * All rights reserved. 4 */ 5 6 #include "spdk/stdinc.h" 7 #include "spdk/bdev.h" 8 #include "spdk/env.h" 9 #include "spdk/thread.h" 10 #include "spdk/json.h" 11 #include "spdk/string.h" 12 #include "spdk/likely.h" 13 #include "spdk/util.h" 14 #include "spdk/string.h" 15 #include "spdk/ftl.h" 16 #include "spdk/log.h" 17 18 #include "bdev_ftl.h" 19 20 struct ftl_bdev { 21 struct spdk_bdev bdev; 22 struct spdk_ftl_dev *dev; 23 ftl_bdev_init_fn init_cb; 24 void *init_arg; 25 int rc; 26 struct spdk_bdev_desc *base_bdev_desc; 27 struct spdk_bdev_desc *cache_bdev_desc; 28 }; 29 30 struct ftl_deferred_init { 31 struct spdk_ftl_conf conf; 32 33 LIST_ENTRY(ftl_deferred_init) entry; 34 }; 35 36 static LIST_HEAD(, ftl_deferred_init) g_deferred_init = LIST_HEAD_INITIALIZER(g_deferred_init); 37 38 static int bdev_ftl_initialize(void); 39 static void bdev_ftl_finish(void); 40 static void bdev_ftl_examine(struct spdk_bdev *bdev); 41 42 static int 43 bdev_ftl_get_ctx_size(void) 44 { 45 return spdk_ftl_io_size(); 46 } 47 48 static struct spdk_bdev_module g_ftl_if = { 49 .name = "ftl", 50 .module_init = bdev_ftl_initialize, 51 .module_fini = bdev_ftl_finish, 52 .examine_disk = bdev_ftl_examine, 53 .get_ctx_size = bdev_ftl_get_ctx_size, 54 }; 55 56 SPDK_BDEV_MODULE_REGISTER(ftl, &g_ftl_if) 57 58 static void 59 bdev_ftl_free(struct ftl_bdev *ftl_bdev) 60 { 61 spdk_bdev_close(ftl_bdev->base_bdev_desc); 62 spdk_bdev_close(ftl_bdev->cache_bdev_desc); 63 free(ftl_bdev->bdev.name); 64 free(ftl_bdev); 65 } 66 67 static void 68 bdev_ftl_dev_free_cb(void *ctx, int status) 69 { 70 struct ftl_bdev *ftl_bdev = ctx; 71 72 spdk_bdev_destruct_done(&ftl_bdev->bdev, status); 73 bdev_ftl_free(ftl_bdev); 74 } 75 76 static int 77 bdev_ftl_destruct(void *ctx) 78 { 79 struct ftl_bdev *ftl_bdev = ctx; 80 81 spdk_ftl_dev_free(ftl_bdev->dev, bdev_ftl_dev_free_cb, ftl_bdev); 82 83 /* return 1 to indicate that the destruction is asynchronous */ 84 return 1; 85 } 86 87 static void 88 bdev_ftl_cb(void *arg, int rc) 89 { 90 struct spdk_bdev_io *bdev_io = arg; 91 enum spdk_bdev_io_status status; 92 93 switch (rc) { 94 case 0: 95 status = SPDK_BDEV_IO_STATUS_SUCCESS; 96 break; 97 case -ENOMEM: 98 status = SPDK_BDEV_IO_STATUS_NOMEM; 99 break; 100 default: 101 status = SPDK_BDEV_IO_STATUS_FAILED; 102 break; 103 } 104 105 spdk_bdev_io_complete(bdev_io, status); 106 } 107 108 static void 109 bdev_ftl_get_buf_cb(struct spdk_io_channel *ch, struct spdk_bdev_io *bdev_io, 110 bool success) 111 { 112 struct ftl_bdev *ftl_bdev; 113 int rc; 114 115 ftl_bdev = bdev_io->bdev->ctxt; 116 117 if (!success) { 118 spdk_bdev_io_complete(bdev_io, SPDK_BDEV_IO_STATUS_FAILED); 119 return; 120 } 121 122 rc = spdk_ftl_readv(ftl_bdev->dev, (struct ftl_io *)bdev_io->driver_ctx, 123 ch, 124 bdev_io->u.bdev.offset_blocks, 125 bdev_io->u.bdev.num_blocks, 126 bdev_io->u.bdev.iovs, bdev_io->u.bdev.iovcnt, bdev_ftl_cb, bdev_io); 127 128 if (spdk_unlikely(rc != 0)) { 129 spdk_bdev_io_complete(bdev_io, rc); 130 } 131 } 132 133 static int 134 _bdev_ftl_submit_request(struct spdk_io_channel *ch, struct spdk_bdev_io *bdev_io) 135 { 136 struct ftl_bdev *ftl_bdev = (struct ftl_bdev *)bdev_io->bdev->ctxt; 137 138 switch (bdev_io->type) { 139 case SPDK_BDEV_IO_TYPE_READ: 140 spdk_bdev_io_get_buf(bdev_io, bdev_ftl_get_buf_cb, 141 bdev_io->u.bdev.num_blocks * bdev_io->bdev->blocklen); 142 return 0; 143 144 case SPDK_BDEV_IO_TYPE_WRITE: 145 return spdk_ftl_writev(ftl_bdev->dev, (struct ftl_io *)bdev_io->driver_ctx, 146 ch, bdev_io->u.bdev.offset_blocks, 147 bdev_io->u.bdev.num_blocks, bdev_io->u.bdev.iovs, 148 bdev_io->u.bdev.iovcnt, bdev_ftl_cb, bdev_io); 149 150 case SPDK_BDEV_IO_TYPE_UNMAP: 151 case SPDK_BDEV_IO_TYPE_FLUSH: 152 spdk_bdev_io_complete(bdev_io, SPDK_BDEV_IO_STATUS_SUCCESS); 153 return 0; 154 default: 155 return -ENOTSUP; 156 } 157 } 158 159 static void 160 bdev_ftl_submit_request(struct spdk_io_channel *ch, struct spdk_bdev_io *bdev_io) 161 { 162 int rc = _bdev_ftl_submit_request(ch, bdev_io); 163 164 if (spdk_unlikely(rc != 0)) { 165 spdk_bdev_io_complete(bdev_io, rc); 166 } 167 } 168 169 static bool 170 bdev_ftl_io_type_supported(void *ctx, enum spdk_bdev_io_type io_type) 171 { 172 switch (io_type) { 173 case SPDK_BDEV_IO_TYPE_READ: 174 case SPDK_BDEV_IO_TYPE_WRITE: 175 case SPDK_BDEV_IO_TYPE_FLUSH: 176 case SPDK_BDEV_IO_TYPE_UNMAP: 177 return true; 178 default: 179 return false; 180 } 181 } 182 183 static struct spdk_io_channel * 184 bdev_ftl_get_io_channel(void *ctx) 185 { 186 struct ftl_bdev *ftl_bdev = ctx; 187 188 return spdk_ftl_get_io_channel(ftl_bdev->dev); 189 } 190 191 static void 192 bdev_ftl_write_config_json(struct spdk_bdev *bdev, struct spdk_json_write_ctx *w) 193 { 194 struct ftl_bdev *ftl_bdev = bdev->ctxt; 195 struct spdk_ftl_conf conf; 196 char uuid[SPDK_UUID_STRING_LEN]; 197 198 spdk_ftl_dev_get_conf(ftl_bdev->dev, &conf); 199 200 spdk_json_write_object_begin(w); 201 202 spdk_json_write_named_string(w, "method", "bdev_ftl_create"); 203 204 spdk_json_write_named_object_begin(w, "params"); 205 spdk_json_write_named_string(w, "name", ftl_bdev->bdev.name); 206 207 spdk_json_write_named_uint64(w, "overprovisioning", conf.overprovisioning); 208 spdk_json_write_named_uint64(w, "l2p_dram_limit", conf.l2p_dram_limit); 209 210 if (conf.core_mask) { 211 spdk_json_write_named_string(w, "core_mask", conf.core_mask); 212 } 213 214 spdk_uuid_fmt_lower(uuid, sizeof(uuid), &conf.uuid); 215 spdk_json_write_named_string(w, "uuid", uuid); 216 217 spdk_json_write_named_bool(w, "fast_shutdown", conf.fast_shutdown); 218 219 spdk_json_write_named_string(w, "base_bdev", conf.base_bdev); 220 221 if (conf.cache_bdev) { 222 spdk_json_write_named_string(w, "cache", conf.cache_bdev); 223 } 224 225 spdk_json_write_object_end(w); 226 spdk_json_write_object_end(w); 227 } 228 229 static int 230 bdev_ftl_dump_info_json(void *ctx, struct spdk_json_write_ctx *w) 231 { 232 struct ftl_bdev *ftl_bdev = ctx; 233 struct spdk_ftl_attrs attrs; 234 struct spdk_ftl_conf conf; 235 236 spdk_ftl_dev_get_attrs(ftl_bdev->dev, &attrs); 237 spdk_ftl_dev_get_conf(ftl_bdev->dev, &conf); 238 239 spdk_json_write_named_object_begin(w, "ftl"); 240 241 spdk_json_write_named_string(w, "base_bdev", conf.base_bdev); 242 243 if (conf.cache_bdev) { 244 spdk_json_write_named_string(w, "cache", conf.cache_bdev); 245 } 246 247 /* ftl */ 248 spdk_json_write_object_end(w); 249 250 return 0; 251 } 252 253 static const struct spdk_bdev_fn_table ftl_fn_table = { 254 .destruct = bdev_ftl_destruct, 255 .submit_request = bdev_ftl_submit_request, 256 .io_type_supported = bdev_ftl_io_type_supported, 257 .get_io_channel = bdev_ftl_get_io_channel, 258 .write_config_json = bdev_ftl_write_config_json, 259 .dump_info_json = bdev_ftl_dump_info_json, 260 }; 261 262 static void 263 bdev_ftl_create_err_complete(struct ftl_bdev *ftl_bdev) 264 { 265 ftl_bdev_init_fn init_cb = ftl_bdev->init_cb; 266 void *init_arg = ftl_bdev->init_arg; 267 int rc = ftl_bdev->rc; 268 269 bdev_ftl_free(ftl_bdev); 270 271 assert(rc); 272 init_cb(NULL, init_arg, rc); 273 } 274 275 static void 276 bdev_ftl_create_err_cleanup_cb(void *ctx, int status) 277 { 278 struct ftl_bdev *ftl_bdev = ctx; 279 280 if (status) { 281 SPDK_ERRLOG("Fatal ERROR of FTL cleanup, name %s\n", ftl_bdev->bdev.name); 282 } 283 284 bdev_ftl_create_err_complete(ftl_bdev); 285 } 286 287 static void 288 bdev_ftl_create_cb(struct spdk_ftl_dev *dev, void *ctx, int status) 289 { 290 struct ftl_bdev *ftl_bdev = ctx; 291 struct ftl_bdev_info info = {}; 292 struct spdk_ftl_attrs attrs; 293 struct spdk_ftl_conf conf; 294 ftl_bdev_init_fn init_cb = ftl_bdev->init_cb; 295 void *init_arg = ftl_bdev->init_arg; 296 297 if (status) { 298 SPDK_ERRLOG("Failed to create FTL device (%d)\n", status); 299 ftl_bdev->rc = status; 300 goto error; 301 } 302 303 spdk_ftl_dev_get_attrs(dev, &attrs); 304 spdk_ftl_dev_get_conf(dev, &conf); 305 306 ftl_bdev->dev = dev; 307 ftl_bdev->bdev.product_name = "FTL disk"; 308 ftl_bdev->bdev.write_cache = 0; 309 ftl_bdev->bdev.blocklen = attrs.block_size; 310 ftl_bdev->bdev.blockcnt = attrs.num_blocks; 311 ftl_bdev->bdev.uuid = conf.uuid; 312 ftl_bdev->bdev.optimal_io_boundary = attrs.optimum_io_size; 313 ftl_bdev->bdev.split_on_optimal_io_boundary = true; 314 315 SPDK_DEBUGLOG(bdev_ftl, "Creating bdev %s:\n", ftl_bdev->bdev.name); 316 SPDK_DEBUGLOG(bdev_ftl, "\tblock_len:\t%zu\n", attrs.block_size); 317 SPDK_DEBUGLOG(bdev_ftl, "\tnum_blocks:\t%"PRIu64"\n", attrs.num_blocks); 318 319 ftl_bdev->bdev.ctxt = ftl_bdev; 320 ftl_bdev->bdev.fn_table = &ftl_fn_table; 321 ftl_bdev->bdev.module = &g_ftl_if; 322 323 status = spdk_bdev_register(&ftl_bdev->bdev); 324 if (status) { 325 ftl_bdev->rc = status; 326 goto error; 327 } 328 329 info.name = ftl_bdev->bdev.name; 330 info.uuid = ftl_bdev->bdev.uuid; 331 332 init_cb(&info, init_arg, 0); 333 return; 334 335 error: 336 if (ftl_bdev->dev) { 337 /* Cleanup all FTL */ 338 spdk_ftl_dev_set_fast_shutdown(ftl_bdev->dev, false); 339 340 /* FTL was created, but we have got an error, so we need to delete it */ 341 spdk_ftl_dev_free(dev, bdev_ftl_create_err_cleanup_cb, ftl_bdev); 342 } else { 343 bdev_ftl_create_err_complete(ftl_bdev); 344 } 345 } 346 347 static void 348 bdev_ftl_defer_free(struct ftl_deferred_init *init) 349 { 350 spdk_ftl_conf_deinit(&init->conf); 351 free(init); 352 } 353 354 int 355 bdev_ftl_defer_init(const struct spdk_ftl_conf *conf) 356 { 357 struct ftl_deferred_init *init; 358 int rc; 359 360 init = calloc(1, sizeof(*init)); 361 if (!init) { 362 return -ENOMEM; 363 } 364 365 rc = spdk_ftl_conf_copy(&init->conf, conf); 366 if (rc) { 367 free(init); 368 return -ENOMEM; 369 } 370 371 LIST_INSERT_HEAD(&g_deferred_init, init, entry); 372 373 return 0; 374 } 375 376 static void 377 bdev_ftl_create_bdev_event_cb(enum spdk_bdev_event_type type, struct spdk_bdev *bdev, void *ctx) 378 { 379 } 380 381 int 382 bdev_ftl_create_bdev(const struct spdk_ftl_conf *conf, ftl_bdev_init_fn cb, void *cb_arg) 383 { 384 struct ftl_bdev *ftl_bdev; 385 struct spdk_bdev_desc *base_bdev_desc, *cache_bdev_desc; 386 int rc; 387 388 rc = spdk_bdev_open_ext(conf->base_bdev, false, bdev_ftl_create_bdev_event_cb, NULL, 389 &base_bdev_desc); 390 if (rc) { 391 return rc; 392 } 393 rc = spdk_bdev_open_ext(conf->cache_bdev, false, bdev_ftl_create_bdev_event_cb, NULL, 394 &cache_bdev_desc); 395 if (rc) { 396 spdk_bdev_close(base_bdev_desc); 397 return rc; 398 } 399 400 ftl_bdev = calloc(1, sizeof(*ftl_bdev)); 401 if (!ftl_bdev) { 402 SPDK_ERRLOG("Could not allocate ftl_bdev\n"); 403 spdk_bdev_close(base_bdev_desc); 404 spdk_bdev_close(cache_bdev_desc); 405 return -ENOMEM; 406 } 407 408 ftl_bdev->base_bdev_desc = base_bdev_desc; 409 ftl_bdev->cache_bdev_desc = cache_bdev_desc; 410 411 ftl_bdev->bdev.name = strdup(conf->name); 412 if (!ftl_bdev->bdev.name) { 413 rc = -ENOMEM; 414 goto error; 415 } 416 417 ftl_bdev->init_cb = cb; 418 ftl_bdev->init_arg = cb_arg; 419 420 rc = spdk_ftl_dev_init(conf, bdev_ftl_create_cb, ftl_bdev); 421 if (rc) { 422 SPDK_ERRLOG("Could not create FTL device\n"); 423 goto error; 424 } 425 426 return 0; 427 428 error: 429 bdev_ftl_free(ftl_bdev); 430 return rc; 431 } 432 433 static int 434 bdev_ftl_initialize(void) 435 { 436 return spdk_ftl_init(); 437 } 438 439 static void 440 bdev_ftl_event_cb(enum spdk_bdev_event_type type, struct spdk_bdev *bdev, void *ctx) 441 { 442 } 443 444 void 445 bdev_ftl_delete_bdev(const char *name, bool fast_shutdown, spdk_bdev_unregister_cb cb_fn, 446 void *cb_arg) 447 { 448 struct spdk_bdev_desc *ftl_bdev_desc; 449 struct spdk_bdev *bdev; 450 struct ftl_bdev *ftl; 451 int rc; 452 453 rc = spdk_bdev_open_ext(name, false, bdev_ftl_event_cb, NULL, &ftl_bdev_desc); 454 455 if (rc) { 456 goto not_found; 457 } 458 459 bdev = spdk_bdev_desc_get_bdev(ftl_bdev_desc); 460 461 if (bdev->module != &g_ftl_if) { 462 goto bdev_opened; 463 } 464 465 ftl = bdev->ctxt; 466 assert(ftl); 467 spdk_ftl_dev_set_fast_shutdown(ftl->dev, fast_shutdown); 468 spdk_bdev_close(ftl_bdev_desc); 469 470 rc = spdk_bdev_unregister_by_name(name, &g_ftl_if, cb_fn, cb_arg); 471 if (rc) { 472 cb_fn(cb_arg, rc); 473 } 474 475 return; 476 bdev_opened: 477 spdk_bdev_close(ftl_bdev_desc); 478 not_found: 479 cb_fn(cb_arg, -ENODEV); 480 } 481 482 static void 483 bdev_ftl_finish(void) 484 { 485 spdk_ftl_fini(); 486 } 487 488 static void 489 bdev_ftl_create_defered_cb(const struct ftl_bdev_info *info, void *ctx, int status) 490 { 491 struct ftl_deferred_init *opts = ctx; 492 493 if (status) { 494 SPDK_ERRLOG("Failed to initialize FTL bdev '%s'\n", opts->conf.name); 495 } 496 497 bdev_ftl_defer_free(opts); 498 499 spdk_bdev_module_examine_done(&g_ftl_if); 500 } 501 502 static void 503 bdev_ftl_examine(struct spdk_bdev *bdev) 504 { 505 struct ftl_deferred_init *opts; 506 int rc; 507 508 LIST_FOREACH(opts, &g_deferred_init, entry) { 509 /* spdk_bdev_module_examine_done will be called by bdev_ftl_create_defered_cb */ 510 rc = bdev_ftl_create_bdev(&opts->conf, bdev_ftl_create_defered_cb, opts); 511 if (rc == -ENODEV) { 512 continue; 513 } 514 515 LIST_REMOVE(opts, entry); 516 517 if (rc) { 518 bdev_ftl_create_defered_cb(NULL, opts, rc); 519 } 520 return; 521 } 522 523 spdk_bdev_module_examine_done(&g_ftl_if); 524 } 525 526 SPDK_LOG_REGISTER_COMPONENT(bdev_ftl) 527