xref: /spdk/module/bdev/ftl/bdev_ftl.c (revision 34c48f1b3bd4e943b1598d6368a86ef382a97d0d)
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