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