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 int 88 _bdev_ftl_submit_request(struct spdk_io_channel *ch, struct spdk_bdev_io *bdev_io) 89 { 90 switch (bdev_io->type) { 91 case SPDK_BDEV_IO_TYPE_READ: 92 case SPDK_BDEV_IO_TYPE_WRITE: 93 case SPDK_BDEV_IO_TYPE_UNMAP: 94 case SPDK_BDEV_IO_TYPE_FLUSH: 95 spdk_bdev_io_complete(bdev_io, SPDK_BDEV_IO_STATUS_SUCCESS); 96 return 0; 97 default: 98 return -ENOTSUP; 99 } 100 } 101 102 static void 103 bdev_ftl_submit_request(struct spdk_io_channel *ch, struct spdk_bdev_io *bdev_io) 104 { 105 int rc = _bdev_ftl_submit_request(ch, bdev_io); 106 107 if (spdk_unlikely(rc != 0)) { 108 spdk_bdev_io_complete(bdev_io, rc); 109 } 110 } 111 112 static bool 113 bdev_ftl_io_type_supported(void *ctx, enum spdk_bdev_io_type io_type) 114 { 115 switch (io_type) { 116 case SPDK_BDEV_IO_TYPE_READ: 117 case SPDK_BDEV_IO_TYPE_WRITE: 118 case SPDK_BDEV_IO_TYPE_FLUSH: 119 case SPDK_BDEV_IO_TYPE_UNMAP: 120 return true; 121 default: 122 return false; 123 } 124 } 125 126 static struct spdk_io_channel * 127 bdev_ftl_get_io_channel(void *ctx) 128 { 129 struct ftl_bdev *ftl_bdev = ctx; 130 131 return spdk_ftl_get_io_channel(ftl_bdev->dev); 132 } 133 134 static void 135 bdev_ftl_write_config_json(struct spdk_bdev *bdev, struct spdk_json_write_ctx *w) 136 { 137 struct ftl_bdev *ftl_bdev = bdev->ctxt; 138 struct spdk_ftl_conf conf; 139 char uuid[SPDK_UUID_STRING_LEN]; 140 141 spdk_ftl_dev_get_conf(ftl_bdev->dev, &conf); 142 143 spdk_json_write_object_begin(w); 144 145 spdk_json_write_named_string(w, "method", "bdev_ftl_create"); 146 147 spdk_json_write_named_object_begin(w, "params"); 148 spdk_json_write_named_string(w, "name", ftl_bdev->bdev.name); 149 150 spdk_json_write_named_uint64(w, "overprovisioning", conf.overprovisioning); 151 152 if (conf.core_mask) { 153 spdk_json_write_named_string(w, "core_mask", conf.core_mask); 154 } 155 156 spdk_uuid_fmt_lower(uuid, sizeof(uuid), &conf.uuid); 157 spdk_json_write_named_string(w, "uuid", uuid); 158 159 spdk_json_write_named_string(w, "base_bdev", conf.base_bdev); 160 161 if (conf.cache_bdev) { 162 spdk_json_write_named_string(w, "cache", conf.cache_bdev); 163 } 164 165 spdk_json_write_object_end(w); 166 spdk_json_write_object_end(w); 167 } 168 169 static int 170 bdev_ftl_dump_info_json(void *ctx, struct spdk_json_write_ctx *w) 171 { 172 struct ftl_bdev *ftl_bdev = ctx; 173 struct spdk_ftl_attrs attrs; 174 struct spdk_ftl_conf conf; 175 176 spdk_ftl_dev_get_attrs(ftl_bdev->dev, &attrs); 177 spdk_ftl_dev_get_conf(ftl_bdev->dev, &conf); 178 179 spdk_json_write_named_object_begin(w, "ftl"); 180 181 spdk_json_write_named_string(w, "base_bdev", conf.base_bdev); 182 183 if (conf.cache_bdev) { 184 spdk_json_write_named_string(w, "cache", conf.cache_bdev); 185 } 186 spdk_json_write_named_string_fmt(w, "num_zones", "%zu", attrs.num_zones); 187 spdk_json_write_named_string_fmt(w, "zone_size", "%zu", attrs.zone_size); 188 189 /* ftl */ 190 spdk_json_write_object_end(w); 191 192 return 0; 193 } 194 195 static const struct spdk_bdev_fn_table ftl_fn_table = { 196 .destruct = bdev_ftl_destruct, 197 .submit_request = bdev_ftl_submit_request, 198 .io_type_supported = bdev_ftl_io_type_supported, 199 .get_io_channel = bdev_ftl_get_io_channel, 200 .write_config_json = bdev_ftl_write_config_json, 201 .dump_info_json = bdev_ftl_dump_info_json, 202 }; 203 204 static void 205 bdev_ftl_create_err_complete(struct ftl_bdev *ftl_bdev) 206 { 207 ftl_bdev_init_fn init_cb = ftl_bdev->init_cb; 208 void *init_arg = ftl_bdev->init_arg; 209 int rc = ftl_bdev->rc; 210 211 bdev_ftl_free(ftl_bdev); 212 213 assert(rc); 214 init_cb(NULL, init_arg, rc); 215 } 216 217 static void 218 bdev_ftl_create_err_cleanup_cb(void *ctx, int status) 219 { 220 struct ftl_bdev *ftl_bdev = ctx; 221 222 if (status) { 223 SPDK_ERRLOG("Fatal ERROR of FTL cleanup, name %s\n", ftl_bdev->bdev.name); 224 } 225 226 bdev_ftl_create_err_complete(ftl_bdev); 227 } 228 229 static void 230 bdev_ftl_create_cb(struct spdk_ftl_dev *dev, void *ctx, int status) 231 { 232 struct ftl_bdev *ftl_bdev = ctx; 233 struct ftl_bdev_info info = {}; 234 struct spdk_ftl_attrs attrs; 235 struct spdk_ftl_conf conf; 236 ftl_bdev_init_fn init_cb = ftl_bdev->init_cb; 237 void *init_arg = ftl_bdev->init_arg; 238 239 if (status) { 240 SPDK_ERRLOG("Failed to create FTL device (%d)\n", status); 241 ftl_bdev->rc = status; 242 goto error; 243 } 244 245 spdk_ftl_dev_get_attrs(dev, &attrs); 246 spdk_ftl_dev_get_conf(dev, &conf); 247 248 ftl_bdev->dev = dev; 249 ftl_bdev->bdev.product_name = "FTL disk"; 250 ftl_bdev->bdev.write_cache = 0; 251 ftl_bdev->bdev.blocklen = attrs.block_size; 252 ftl_bdev->bdev.blockcnt = attrs.num_blocks; 253 ftl_bdev->bdev.uuid = conf.uuid; 254 ftl_bdev->bdev.optimal_io_boundary = attrs.optimum_io_size; 255 ftl_bdev->bdev.split_on_optimal_io_boundary = true; 256 257 SPDK_DEBUGLOG(bdev_ftl, "Creating bdev %s:\n", ftl_bdev->bdev.name); 258 SPDK_DEBUGLOG(bdev_ftl, "\tblock_len:\t%zu\n", attrs.block_size); 259 SPDK_DEBUGLOG(bdev_ftl, "\tnum_blocks:\t%"PRIu64"\n", attrs.num_blocks); 260 261 ftl_bdev->bdev.ctxt = ftl_bdev; 262 ftl_bdev->bdev.fn_table = &ftl_fn_table; 263 ftl_bdev->bdev.module = &g_ftl_if; 264 265 status = spdk_bdev_register(&ftl_bdev->bdev); 266 if (status) { 267 ftl_bdev->rc = status; 268 goto error; 269 } 270 271 info.name = ftl_bdev->bdev.name; 272 info.uuid = ftl_bdev->bdev.uuid; 273 274 init_cb(&info, init_arg, 0); 275 return; 276 277 error: 278 if (ftl_bdev->dev) { 279 /* FTL was created, but we have got an error, so we need to delete it */ 280 spdk_ftl_dev_free(dev, bdev_ftl_create_err_cleanup_cb, ftl_bdev); 281 } else { 282 bdev_ftl_create_err_complete(ftl_bdev); 283 } 284 } 285 286 static void 287 bdev_ftl_defer_free(struct ftl_deferred_init *init) 288 { 289 spdk_ftl_conf_deinit(&init->conf); 290 free(init); 291 } 292 293 int 294 bdev_ftl_defer_init(const struct spdk_ftl_conf *conf) 295 { 296 struct ftl_deferred_init *init; 297 int rc; 298 299 init = calloc(1, sizeof(*init)); 300 if (!init) { 301 return -ENOMEM; 302 } 303 304 rc = spdk_ftl_conf_copy(&init->conf, conf); 305 if (rc) { 306 free(init); 307 return -ENOMEM; 308 } 309 310 LIST_INSERT_HEAD(&g_deferred_init, init, entry); 311 312 return 0; 313 } 314 315 static void 316 bdev_ftl_create_bdev_event_cb(enum spdk_bdev_event_type type, struct spdk_bdev *bdev, void *ctx) 317 { 318 } 319 320 int 321 bdev_ftl_create_bdev(const struct spdk_ftl_conf *conf, ftl_bdev_init_fn cb, void *cb_arg) 322 { 323 struct ftl_bdev *ftl_bdev; 324 struct spdk_bdev_desc *base_bdev_desc, *cache_bdev_desc; 325 int rc; 326 327 rc = spdk_bdev_open_ext(conf->base_bdev, false, bdev_ftl_create_bdev_event_cb, NULL, 328 &base_bdev_desc); 329 if (rc) { 330 return rc; 331 } 332 rc = spdk_bdev_open_ext(conf->cache_bdev, false, bdev_ftl_create_bdev_event_cb, NULL, 333 &cache_bdev_desc); 334 if (rc) { 335 spdk_bdev_close(base_bdev_desc); 336 return rc; 337 } 338 339 ftl_bdev = calloc(1, sizeof(*ftl_bdev)); 340 if (!ftl_bdev) { 341 SPDK_ERRLOG("Could not allocate ftl_bdev\n"); 342 spdk_bdev_close(base_bdev_desc); 343 spdk_bdev_close(cache_bdev_desc); 344 return -ENOMEM; 345 } 346 347 ftl_bdev->base_bdev_desc = base_bdev_desc; 348 ftl_bdev->cache_bdev_desc = cache_bdev_desc; 349 350 ftl_bdev->bdev.name = strdup(conf->name); 351 if (!ftl_bdev->bdev.name) { 352 rc = -ENOMEM; 353 goto error; 354 } 355 356 ftl_bdev->init_cb = cb; 357 ftl_bdev->init_arg = cb_arg; 358 359 rc = spdk_ftl_dev_init(conf, bdev_ftl_create_cb, ftl_bdev); 360 if (rc) { 361 SPDK_ERRLOG("Could not create FTL device\n"); 362 goto error; 363 } 364 365 return 0; 366 367 error: 368 bdev_ftl_free(ftl_bdev); 369 return rc; 370 } 371 372 static int 373 bdev_ftl_initialize(void) 374 { 375 return spdk_ftl_init(); 376 } 377 378 void 379 bdev_ftl_delete_bdev(const char *name, spdk_bdev_unregister_cb cb_fn, void *cb_arg) 380 { 381 int rc; 382 383 rc = spdk_bdev_unregister_by_name(name, &g_ftl_if, cb_fn, cb_arg); 384 if (rc) { 385 cb_fn(cb_arg, rc); 386 } 387 } 388 389 static void 390 bdev_ftl_finish(void) 391 { 392 spdk_ftl_fini(); 393 } 394 395 static void 396 bdev_ftl_create_defered_cb(const struct ftl_bdev_info *info, void *ctx, int status) 397 { 398 struct ftl_deferred_init *opts = ctx; 399 400 if (status) { 401 SPDK_ERRLOG("Failed to initialize FTL bdev '%s'\n", opts->conf.name); 402 } 403 404 bdev_ftl_defer_free(opts); 405 406 spdk_bdev_module_examine_done(&g_ftl_if); 407 } 408 409 static void 410 bdev_ftl_examine(struct spdk_bdev *bdev) 411 { 412 struct ftl_deferred_init *opts; 413 int rc; 414 415 LIST_FOREACH(opts, &g_deferred_init, entry) { 416 /* spdk_bdev_module_examine_done will be called by bdev_ftl_create_defered_cb */ 417 rc = bdev_ftl_create_bdev(&opts->conf, bdev_ftl_create_defered_cb, opts); 418 if (rc == -ENODEV) { 419 continue; 420 } 421 422 LIST_REMOVE(opts, entry); 423 424 if (rc) { 425 bdev_ftl_create_defered_cb(NULL, opts, rc); 426 } 427 return; 428 } 429 430 spdk_bdev_module_examine_done(&g_ftl_if); 431 } 432 433 SPDK_LOG_REGISTER_COMPONENT(bdev_ftl) 434