xref: /spdk/module/bdev/ftl/bdev_ftl.c (revision 19d5c3ed8e87dbd240c77ae0ddb5eda25ae99b5f)
1 /*-
2  *   BSD LICENSE
3  *
4  *   Copyright (c) Intel Corporation.
5  *   All rights reserved.
6  *
7  *   Redistribution and use in source and binary forms, with or without
8  *   modification, are permitted provided that the following conditions
9  *   are met:
10  *
11  *     * Redistributions of source code must retain the above copyright
12  *       notice, this list of conditions and the following disclaimer.
13  *     * Redistributions in binary form must reproduce the above copyright
14  *       notice, this list of conditions and the following disclaimer in
15  *       the documentation and/or other materials provided with the
16  *       distribution.
17  *     * Neither the name of Intel Corporation nor the names of its
18  *       contributors may be used to endorse or promote products derived
19  *       from this software without specific prior written permission.
20  *
21  *   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
22  *   "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
23  *   LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
24  *   A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
25  *   OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
26  *   SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
27  *   LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
28  *   DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
29  *   THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
30  *   (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
31  *   OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
32  */
33 
34 #include "spdk/stdinc.h"
35 #include "spdk/bdev.h"
36 #include "spdk/conf.h"
37 #include "spdk/env.h"
38 #include "spdk/io_channel.h"
39 #include "spdk/json.h"
40 #include "spdk/string.h"
41 #include "spdk/likely.h"
42 #include "spdk/util.h"
43 #include "spdk/string.h"
44 #include "spdk/ftl.h"
45 #include "spdk_internal/log.h"
46 
47 #include "bdev_ftl.h"
48 
49 #define FTL_COMPLETION_RING_SIZE 4096
50 
51 struct ftl_bdev {
52 	struct spdk_bdev		bdev;
53 
54 	struct spdk_ftl_dev		*dev;
55 
56 	ftl_bdev_init_fn		init_cb;
57 
58 	void				*init_arg;
59 };
60 
61 struct ftl_io_channel {
62 	struct spdk_ftl_dev		*dev;
63 
64 	struct spdk_poller		*poller;
65 
66 #define FTL_MAX_COMPLETIONS 64
67 	struct ftl_bdev_io		*io[FTL_MAX_COMPLETIONS];
68 
69 	/* Completion ring */
70 	struct spdk_ring		*ring;
71 
72 	struct spdk_io_channel		*ioch;
73 };
74 
75 struct ftl_bdev_io {
76 	struct ftl_bdev			*bdev;
77 
78 	struct spdk_ring		*ring;
79 
80 	int				status;
81 };
82 
83 struct ftl_deferred_init {
84 	struct ftl_bdev_init_opts	opts;
85 
86 	LIST_ENTRY(ftl_deferred_init)	entry;
87 };
88 
89 static LIST_HEAD(, ftl_deferred_init)	g_deferred_init = LIST_HEAD_INITIALIZER(g_deferred_init);
90 
91 static int bdev_ftl_initialize(void);
92 static void bdev_ftl_finish(void);
93 static void bdev_ftl_examine(struct spdk_bdev *bdev);
94 
95 static int
96 bdev_ftl_get_ctx_size(void)
97 {
98 	return sizeof(struct ftl_bdev_io);
99 }
100 
101 static struct spdk_bdev_module g_ftl_if = {
102 	.name		= "ftl",
103 	.module_init	= bdev_ftl_initialize,
104 	.module_fini	= bdev_ftl_finish,
105 	.examine_disk	= bdev_ftl_examine,
106 	.get_ctx_size	= bdev_ftl_get_ctx_size,
107 };
108 
109 SPDK_BDEV_MODULE_REGISTER(ftl, &g_ftl_if)
110 
111 static void
112 bdev_ftl_free_cb(struct spdk_ftl_dev *dev, void *ctx, int status)
113 {
114 	struct ftl_bdev *ftl_bdev = ctx;
115 
116 	spdk_io_device_unregister(ftl_bdev, NULL);
117 
118 	spdk_bdev_destruct_done(&ftl_bdev->bdev, status);
119 	free(ftl_bdev->bdev.name);
120 	free(ftl_bdev);
121 }
122 
123 static int
124 bdev_ftl_destruct(void *ctx)
125 {
126 	struct ftl_bdev *ftl_bdev = ctx;
127 	spdk_ftl_dev_free(ftl_bdev->dev, bdev_ftl_free_cb, ftl_bdev);
128 
129 	/* return 1 to indicate that the destruction is asynchronous */
130 	return 1;
131 }
132 
133 static void
134 bdev_ftl_complete_io(struct ftl_bdev_io *io, int rc)
135 {
136 	enum spdk_bdev_io_status status;
137 
138 	switch (rc) {
139 	case 0:
140 		status = SPDK_BDEV_IO_STATUS_SUCCESS;
141 		break;
142 	case -ENOMEM:
143 		status = SPDK_BDEV_IO_STATUS_NOMEM;
144 		break;
145 	default:
146 		status = SPDK_BDEV_IO_STATUS_FAILED;
147 		break;
148 	}
149 
150 	spdk_bdev_io_complete(spdk_bdev_io_from_ctx(io), status);
151 }
152 
153 static void
154 bdev_ftl_cb(void *arg, int status)
155 {
156 	struct ftl_bdev_io *io = arg;
157 	size_t cnt __attribute__((unused));
158 
159 	io->status = status;
160 
161 	cnt = spdk_ring_enqueue(io->ring, (void **)&io, 1, NULL);
162 	assert(cnt == 1);
163 }
164 
165 static int
166 bdev_ftl_fill_bio(struct ftl_bdev *ftl_bdev, struct spdk_io_channel *ch,
167 		  struct ftl_bdev_io *io)
168 {
169 	struct ftl_io_channel *ioch = spdk_io_channel_get_ctx(ch);
170 
171 	memset(io, 0, sizeof(*io));
172 
173 	io->status = SPDK_BDEV_IO_STATUS_SUCCESS;
174 	io->ring = ioch->ring;
175 	io->bdev = ftl_bdev;
176 	return 0;
177 }
178 
179 static int
180 bdev_ftl_readv(struct ftl_bdev *ftl_bdev, struct spdk_io_channel *ch,
181 	       struct ftl_bdev_io *io)
182 {
183 	struct spdk_bdev_io *bio;
184 	struct ftl_io_channel *ioch = spdk_io_channel_get_ctx(ch);
185 	int rc;
186 
187 	bio = spdk_bdev_io_from_ctx(io);
188 
189 	rc = bdev_ftl_fill_bio(ftl_bdev, ch, io);
190 	if (rc) {
191 		return rc;
192 	}
193 
194 	return spdk_ftl_read(ftl_bdev->dev,
195 			     ioch->ioch,
196 			     bio->u.bdev.offset_blocks,
197 			     bio->u.bdev.num_blocks,
198 			     bio->u.bdev.iovs, bio->u.bdev.iovcnt, bdev_ftl_cb, io);
199 }
200 
201 static int
202 bdev_ftl_writev(struct ftl_bdev *ftl_bdev, struct spdk_io_channel *ch,
203 		struct ftl_bdev_io *io)
204 {
205 	struct spdk_bdev_io *bio;
206 	struct ftl_io_channel *ioch;
207 	int rc;
208 
209 	bio = spdk_bdev_io_from_ctx(io);
210 	ioch = spdk_io_channel_get_ctx(ch);
211 
212 	rc = bdev_ftl_fill_bio(ftl_bdev, ch, io);
213 	if (rc) {
214 		return rc;
215 	}
216 
217 	return spdk_ftl_write(ftl_bdev->dev,
218 			      ioch->ioch,
219 			      bio->u.bdev.offset_blocks,
220 			      bio->u.bdev.num_blocks,
221 			      bio->u.bdev.iovs,
222 			      bio->u.bdev.iovcnt, bdev_ftl_cb, io);
223 }
224 
225 static void
226 bdev_ftl_get_buf_cb(struct spdk_io_channel *ch, struct spdk_bdev_io *bdev_io,
227 		    bool success)
228 {
229 	if (!success) {
230 		bdev_ftl_complete_io((struct ftl_bdev_io *)bdev_io->driver_ctx,
231 				     SPDK_BDEV_IO_STATUS_FAILED);
232 		return;
233 	}
234 
235 	int rc = bdev_ftl_readv((struct ftl_bdev *)bdev_io->bdev->ctxt,
236 				ch, (struct ftl_bdev_io *)bdev_io->driver_ctx);
237 
238 	if (spdk_unlikely(rc != 0)) {
239 		bdev_ftl_complete_io((struct ftl_bdev_io *)bdev_io->driver_ctx, rc);
240 	}
241 }
242 
243 static int
244 bdev_ftl_flush(struct ftl_bdev *ftl_bdev, struct spdk_io_channel *ch, struct ftl_bdev_io *io)
245 {
246 	int rc;
247 
248 	rc = bdev_ftl_fill_bio(ftl_bdev, ch, io);
249 	if (rc) {
250 		return rc;
251 	}
252 
253 	return spdk_ftl_flush(ftl_bdev->dev, bdev_ftl_cb, io);
254 }
255 
256 static int
257 _bdev_ftl_submit_request(struct spdk_io_channel *ch, struct spdk_bdev_io *bdev_io)
258 {
259 	struct ftl_bdev *ftl_bdev = (struct ftl_bdev *)bdev_io->bdev->ctxt;
260 
261 	switch (bdev_io->type) {
262 	case SPDK_BDEV_IO_TYPE_READ:
263 		spdk_bdev_io_get_buf(bdev_io, bdev_ftl_get_buf_cb,
264 				     bdev_io->u.bdev.num_blocks * bdev_io->bdev->blocklen);
265 		return 0;
266 
267 	case SPDK_BDEV_IO_TYPE_WRITE:
268 		return bdev_ftl_writev(ftl_bdev, ch, (struct ftl_bdev_io *)bdev_io->driver_ctx);
269 
270 	case SPDK_BDEV_IO_TYPE_FLUSH:
271 		return bdev_ftl_flush(ftl_bdev, ch, (struct ftl_bdev_io *)bdev_io->driver_ctx);
272 
273 	case SPDK_BDEV_IO_TYPE_WRITE_ZEROES:
274 	case SPDK_BDEV_IO_TYPE_RESET:
275 	case SPDK_BDEV_IO_TYPE_UNMAP:
276 	default:
277 		return -ENOTSUP;
278 		break;
279 	}
280 }
281 
282 static void
283 bdev_ftl_submit_request(struct spdk_io_channel *ch, struct spdk_bdev_io *bdev_io)
284 {
285 	int rc = _bdev_ftl_submit_request(ch, bdev_io);
286 
287 	if (spdk_unlikely(rc != 0)) {
288 		bdev_ftl_complete_io((struct ftl_bdev_io *)bdev_io->driver_ctx, rc);
289 	}
290 }
291 
292 static bool
293 bdev_ftl_io_type_supported(void *ctx, enum spdk_bdev_io_type io_type)
294 {
295 	switch (io_type) {
296 	case SPDK_BDEV_IO_TYPE_READ:
297 	case SPDK_BDEV_IO_TYPE_WRITE:
298 	case SPDK_BDEV_IO_TYPE_FLUSH:
299 		return true;
300 	case SPDK_BDEV_IO_TYPE_WRITE_ZEROES:
301 	case SPDK_BDEV_IO_TYPE_RESET:
302 	case SPDK_BDEV_IO_TYPE_UNMAP:
303 	default:
304 		return false;
305 	}
306 }
307 
308 static struct spdk_io_channel *
309 bdev_ftl_get_io_channel(void *ctx)
310 {
311 	struct ftl_bdev *ftl_bdev = ctx;
312 
313 	return spdk_get_io_channel(ftl_bdev);
314 }
315 
316 static void
317 _bdev_ftl_write_config_info(struct ftl_bdev *ftl_bdev, struct spdk_json_write_ctx *w)
318 {
319 	struct spdk_ftl_attrs attrs = {};
320 
321 	spdk_ftl_dev_get_attrs(ftl_bdev->dev, &attrs);
322 
323 	spdk_json_write_named_string(w, "base_bdev", attrs.base_bdev);
324 
325 	if (attrs.cache_bdev) {
326 		spdk_json_write_named_string(w, "cache", attrs.cache_bdev);
327 	}
328 }
329 
330 static void
331 bdev_ftl_write_config_json(struct spdk_bdev *bdev, struct spdk_json_write_ctx *w)
332 {
333 	struct ftl_bdev *ftl_bdev = bdev->ctxt;
334 	struct spdk_ftl_attrs attrs;
335 	struct spdk_ftl_conf *conf = &attrs.conf;
336 	char uuid[SPDK_UUID_STRING_LEN];
337 
338 	spdk_ftl_dev_get_attrs(ftl_bdev->dev, &attrs);
339 
340 	spdk_json_write_object_begin(w);
341 
342 	spdk_json_write_named_string(w, "method", "bdev_ftl_create");
343 
344 	spdk_json_write_named_object_begin(w, "params");
345 	spdk_json_write_named_string(w, "name", ftl_bdev->bdev.name);
346 
347 	spdk_json_write_named_bool(w, "allow_open_bands", conf->allow_open_bands);
348 	spdk_json_write_named_uint64(w, "overprovisioning", conf->lba_rsvd);
349 	spdk_json_write_named_uint64(w, "limit_crit", conf->limits[SPDK_FTL_LIMIT_CRIT].limit);
350 	spdk_json_write_named_uint64(w, "limit_crit_threshold", conf->limits[SPDK_FTL_LIMIT_CRIT].thld);
351 	spdk_json_write_named_uint64(w, "limit_high", conf->limits[SPDK_FTL_LIMIT_HIGH].limit);
352 	spdk_json_write_named_uint64(w, "limit_high_threshold", conf->limits[SPDK_FTL_LIMIT_HIGH].thld);
353 	spdk_json_write_named_uint64(w, "limit_low", conf->limits[SPDK_FTL_LIMIT_LOW].limit);
354 	spdk_json_write_named_uint64(w, "limit_low_threshold", conf->limits[SPDK_FTL_LIMIT_LOW].thld);
355 	spdk_json_write_named_uint64(w, "limit_start", conf->limits[SPDK_FTL_LIMIT_START].limit);
356 	spdk_json_write_named_uint64(w, "limit_start_threshold", conf->limits[SPDK_FTL_LIMIT_START].thld);
357 
358 	spdk_uuid_fmt_lower(uuid, sizeof(uuid), &attrs.uuid);
359 	spdk_json_write_named_string(w, "uuid", uuid);
360 
361 	_bdev_ftl_write_config_info(ftl_bdev, w);
362 
363 	spdk_json_write_object_end(w);
364 	spdk_json_write_object_end(w);
365 }
366 
367 static int
368 bdev_ftl_dump_info_json(void *ctx, struct spdk_json_write_ctx *w)
369 {
370 	struct ftl_bdev *ftl_bdev = ctx;
371 	struct spdk_ftl_attrs attrs;
372 
373 	spdk_ftl_dev_get_attrs(ftl_bdev->dev, &attrs);
374 
375 	spdk_json_write_named_object_begin(w, "ftl");
376 
377 	_bdev_ftl_write_config_info(ftl_bdev, w);
378 	spdk_json_write_named_string_fmt(w, "num_zones", "%zu", attrs.num_zones);
379 	spdk_json_write_named_string_fmt(w, "zone_size", "%zu", attrs.zone_size);
380 
381 	/* ftl */
382 	spdk_json_write_object_end(w);
383 
384 	return 0;
385 }
386 
387 static const struct spdk_bdev_fn_table ftl_fn_table = {
388 	.destruct		= bdev_ftl_destruct,
389 	.submit_request		= bdev_ftl_submit_request,
390 	.io_type_supported	= bdev_ftl_io_type_supported,
391 	.get_io_channel		= bdev_ftl_get_io_channel,
392 	.write_config_json	= bdev_ftl_write_config_json,
393 	.dump_info_json		= bdev_ftl_dump_info_json,
394 };
395 
396 static int
397 bdev_ftl_poll(void *arg)
398 {
399 	struct ftl_io_channel *ch = arg;
400 	size_t cnt, i;
401 
402 	cnt = spdk_ring_dequeue(ch->ring, (void **)&ch->io, FTL_MAX_COMPLETIONS);
403 
404 	for (i = 0; i < cnt; ++i) {
405 		bdev_ftl_complete_io(ch->io[i], ch->io[i]->status);
406 	}
407 
408 	return cnt;
409 }
410 
411 static int
412 bdev_ftl_io_channel_create_cb(void *io_device, void *ctx)
413 {
414 	struct ftl_io_channel *ch = ctx;
415 	struct ftl_bdev *ftl_bdev = (struct ftl_bdev *)io_device;
416 
417 	ch->dev = ftl_bdev->dev;
418 	ch->ring = spdk_ring_create(SPDK_RING_TYPE_MP_SC, FTL_COMPLETION_RING_SIZE,
419 				    SPDK_ENV_SOCKET_ID_ANY);
420 
421 	if (!ch->ring) {
422 		return -ENOMEM;
423 	}
424 
425 	ch->poller = spdk_poller_register(bdev_ftl_poll, ch, 0);
426 	if (!ch->poller) {
427 		spdk_ring_free(ch->ring);
428 		return -ENOMEM;
429 	}
430 
431 	ch->ioch = spdk_get_io_channel(ftl_bdev->dev);
432 
433 	return 0;
434 }
435 
436 static void
437 bdev_ftl_io_channel_destroy_cb(void *io_device, void *ctx_buf)
438 {
439 	struct ftl_io_channel *ch = ctx_buf;
440 
441 	spdk_ring_free(ch->ring);
442 	spdk_poller_unregister(&ch->poller);
443 	spdk_put_io_channel(ch->ioch);
444 }
445 
446 static void
447 bdev_ftl_create_cb(struct spdk_ftl_dev *dev, void *ctx, int status)
448 {
449 	struct ftl_bdev		*ftl_bdev = ctx;
450 	struct ftl_bdev_info	info = {};
451 	struct spdk_ftl_attrs	attrs;
452 	ftl_bdev_init_fn	init_cb = ftl_bdev->init_cb;
453 	void			*init_arg = ftl_bdev->init_arg;
454 	int			rc = -ENODEV;
455 
456 	if (status) {
457 		SPDK_ERRLOG("Failed to create FTL device (%d)\n", status);
458 		rc = status;
459 		goto error_dev;
460 	}
461 
462 	spdk_ftl_dev_get_attrs(dev, &attrs);
463 
464 	ftl_bdev->dev = dev;
465 	ftl_bdev->bdev.product_name = "FTL disk";
466 	ftl_bdev->bdev.write_cache = 0;
467 	ftl_bdev->bdev.blocklen = attrs.block_size;
468 	ftl_bdev->bdev.blockcnt = attrs.num_blocks;
469 	ftl_bdev->bdev.uuid = attrs.uuid;
470 
471 	SPDK_DEBUGLOG(SPDK_LOG_BDEV_FTL, "Creating bdev %s:\n", ftl_bdev->bdev.name);
472 	SPDK_DEBUGLOG(SPDK_LOG_BDEV_FTL, "\tblock_len:\t%zu\n", attrs.block_size);
473 	SPDK_DEBUGLOG(SPDK_LOG_BDEV_FTL, "\tnum_blocks:\t%"PRIu64"\n", attrs.num_blocks);
474 
475 	ftl_bdev->bdev.ctxt = ftl_bdev;
476 	ftl_bdev->bdev.fn_table = &ftl_fn_table;
477 	ftl_bdev->bdev.module = &g_ftl_if;
478 
479 	spdk_io_device_register(ftl_bdev, bdev_ftl_io_channel_create_cb,
480 				bdev_ftl_io_channel_destroy_cb,
481 				sizeof(struct ftl_io_channel),
482 				ftl_bdev->bdev.name);
483 
484 	if (spdk_bdev_register(&ftl_bdev->bdev)) {
485 		goto error_unregister;
486 	}
487 
488 	info.name = ftl_bdev->bdev.name;
489 	info.uuid = ftl_bdev->bdev.uuid;
490 
491 	init_cb(&info, init_arg, 0);
492 	return;
493 
494 error_unregister:
495 	spdk_io_device_unregister(ftl_bdev, NULL);
496 error_dev:
497 	free(ftl_bdev->bdev.name);
498 	free(ftl_bdev);
499 
500 	init_cb(NULL, init_arg, rc);
501 }
502 
503 static void
504 bdev_ftl_defer_free(struct ftl_deferred_init *init)
505 {
506 	free((char *)init->opts.name);
507 	free((char *)init->opts.base_bdev);
508 	free((char *)init->opts.cache_bdev);
509 	free(init);
510 }
511 
512 static int
513 bdev_ftl_defer_init(const struct ftl_bdev_init_opts *opts)
514 {
515 	struct ftl_deferred_init *init;
516 
517 	init = calloc(1, sizeof(*init));
518 	if (!init) {
519 		return -ENOMEM;
520 	}
521 
522 	init->opts.mode = opts->mode;
523 	init->opts.uuid = opts->uuid;
524 	init->opts.ftl_conf = opts->ftl_conf;
525 
526 	init->opts.name = strdup(opts->name);
527 	if (!init->opts.name) {
528 		SPDK_ERRLOG("Could not allocate bdev name\n");
529 		goto error;
530 	}
531 
532 	init->opts.base_bdev = strdup(opts->base_bdev);
533 	if (!init->opts.base_bdev) {
534 		SPDK_ERRLOG("Could not allocate base bdev name\n");
535 		goto error;
536 	}
537 
538 	if (opts->cache_bdev) {
539 		init->opts.cache_bdev = strdup(opts->cache_bdev);
540 		if (!init->opts.cache_bdev) {
541 			SPDK_ERRLOG("Could not allocate cache bdev name\n");
542 			goto error;
543 		}
544 	}
545 
546 	LIST_INSERT_HEAD(&g_deferred_init, init, entry);
547 
548 	return 0;
549 
550 error:
551 	bdev_ftl_defer_free(init);
552 	return -ENOMEM;
553 }
554 
555 int
556 bdev_ftl_create_bdev(const struct ftl_bdev_init_opts *bdev_opts,
557 		     ftl_bdev_init_fn cb, void *cb_arg)
558 {
559 	struct ftl_bdev *ftl_bdev = NULL;
560 	struct spdk_ftl_dev_init_opts opts = {};
561 	int rc;
562 
563 	ftl_bdev = calloc(1, sizeof(*ftl_bdev));
564 	if (!ftl_bdev) {
565 		SPDK_ERRLOG("Could not allocate ftl_bdev\n");
566 		return -ENOMEM;
567 	}
568 
569 	ftl_bdev->bdev.name = strdup(bdev_opts->name);
570 	if (!ftl_bdev->bdev.name) {
571 		rc = -ENOMEM;
572 		goto error_bdev;
573 	}
574 
575 	if (spdk_bdev_get_by_name(bdev_opts->base_bdev) == NULL ||
576 	    (bdev_opts->cache_bdev && spdk_bdev_get_by_name(bdev_opts->cache_bdev) == NULL)) {
577 		rc = bdev_ftl_defer_init(bdev_opts);
578 		if (rc == 0) {
579 			rc = -ENODEV;
580 		}
581 		goto error_name;
582 	}
583 
584 	ftl_bdev->init_cb = cb;
585 	ftl_bdev->init_arg = cb_arg;
586 
587 	opts.mode = bdev_opts->mode;
588 	opts.uuid = bdev_opts->uuid;
589 	opts.name = ftl_bdev->bdev.name;
590 	opts.base_bdev = bdev_opts->base_bdev;
591 	opts.cache_bdev = bdev_opts->cache_bdev;
592 	opts.conf = &bdev_opts->ftl_conf;
593 
594 	/* TODO: set threads based on config */
595 	opts.core_thread = spdk_get_thread();
596 
597 	rc = spdk_ftl_dev_init(&opts, bdev_ftl_create_cb, ftl_bdev);
598 	if (rc) {
599 		SPDK_ERRLOG("Could not create FTL device\n");
600 		goto error_name;
601 	}
602 
603 	return 0;
604 
605 error_name:
606 	free(ftl_bdev->bdev.name);
607 error_bdev:
608 	free(ftl_bdev);
609 	return rc;
610 }
611 
612 static int
613 bdev_ftl_initialize(void)
614 {
615 	return 0;
616 }
617 
618 void
619 bdev_ftl_delete_bdev(const char *name, spdk_bdev_unregister_cb cb_fn, void *cb_arg)
620 {
621 	struct spdk_bdev *bdev;
622 
623 	bdev = spdk_bdev_get_by_name(name);
624 	if (bdev) {
625 		spdk_bdev_unregister(bdev, cb_fn, cb_arg);
626 		return;
627 	}
628 
629 	cb_fn(cb_arg, -ENODEV);
630 }
631 
632 static void
633 bdev_ftl_finish(void)
634 {
635 }
636 
637 static void
638 bdev_ftl_create_defered_cb(const struct ftl_bdev_info *info, void *ctx, int status)
639 {
640 	struct ftl_deferred_init *opts = ctx;
641 
642 	if (status) {
643 		SPDK_ERRLOG("Failed to initialize FTL bdev '%s'\n", opts->opts.name);
644 	}
645 
646 	bdev_ftl_defer_free(opts);
647 
648 	spdk_bdev_module_examine_done(&g_ftl_if);
649 }
650 
651 static void
652 bdev_ftl_examine(struct spdk_bdev *bdev)
653 {
654 	struct ftl_deferred_init *opts;
655 
656 	LIST_FOREACH(opts, &g_deferred_init, entry) {
657 		if (spdk_bdev_get_by_name(opts->opts.base_bdev) == NULL) {
658 			continue;
659 		}
660 
661 		if (opts->opts.cache_bdev && spdk_bdev_get_by_name(opts->opts.base_bdev) == NULL) {
662 			continue;
663 		}
664 
665 		LIST_REMOVE(opts, entry);
666 
667 		/* spdk_bdev_module_examine_done will be called by bdev_ftl_create_defered_cb */
668 		if (bdev_ftl_create_bdev(&opts->opts, bdev_ftl_create_defered_cb, opts)) {
669 			SPDK_ERRLOG("Failed to initialize FTL bdev '%s'\n", opts->opts.name);
670 			bdev_ftl_defer_free(opts);
671 			break;
672 		}
673 		return;
674 	}
675 
676 	spdk_bdev_module_examine_done(&g_ftl_if);
677 }
678 
679 SPDK_LOG_REGISTER_COMPONENT("bdev_ftl", SPDK_LOG_BDEV_FTL)
680