xref: /spdk/module/bdev/ftl/bdev_ftl.c (revision 0098e636761237b77c12c30c2408263a5d2260cc)
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 
23 	struct spdk_ftl_dev		*dev;
24 
25 	ftl_bdev_init_fn		init_cb;
26 
27 	void				*init_arg;
28 };
29 
30 struct ftl_deferred_init {
31 	struct ftl_bdev_init_opts	opts;
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 struct spdk_bdev_module g_ftl_if = {
43 	.name		= "ftl",
44 	.module_init	= bdev_ftl_initialize,
45 	.module_fini	= bdev_ftl_finish,
46 	.examine_disk	= bdev_ftl_examine,
47 };
48 
49 SPDK_BDEV_MODULE_REGISTER(ftl, &g_ftl_if)
50 
51 static void
52 bdev_ftl_free_cb(struct spdk_ftl_dev *dev, void *ctx, int status)
53 {
54 	struct ftl_bdev *ftl_bdev = ctx;
55 
56 	spdk_bdev_destruct_done(&ftl_bdev->bdev, status);
57 	free(ftl_bdev->bdev.name);
58 	free(ftl_bdev);
59 }
60 
61 static int
62 bdev_ftl_destruct(void *ctx)
63 {
64 	struct ftl_bdev *ftl_bdev = ctx;
65 	spdk_ftl_dev_free(ftl_bdev->dev, bdev_ftl_free_cb, ftl_bdev);
66 
67 	/* return 1 to indicate that the destruction is asynchronous */
68 	return 1;
69 }
70 
71 static void
72 bdev_ftl_cb(void *arg, int rc)
73 {
74 	struct spdk_bdev_io *bdev_io = arg;
75 	enum spdk_bdev_io_status status;
76 
77 	switch (rc) {
78 	case 0:
79 		status = SPDK_BDEV_IO_STATUS_SUCCESS;
80 		break;
81 	case -ENOMEM:
82 		status = SPDK_BDEV_IO_STATUS_NOMEM;
83 		break;
84 	default:
85 		status = SPDK_BDEV_IO_STATUS_FAILED;
86 		break;
87 	}
88 
89 	spdk_bdev_io_complete(bdev_io, status);
90 }
91 
92 static void
93 bdev_ftl_get_buf_cb(struct spdk_io_channel *ch, struct spdk_bdev_io *bdev_io,
94 		    bool success)
95 {
96 	struct ftl_bdev *ftl_bdev;
97 	int rc;
98 
99 	ftl_bdev = bdev_io->bdev->ctxt;
100 
101 	if (!success) {
102 		spdk_bdev_io_complete(bdev_io, SPDK_BDEV_IO_STATUS_FAILED);
103 		return;
104 	}
105 
106 	rc = spdk_ftl_read(ftl_bdev->dev,
107 			   ch,
108 			   bdev_io->u.bdev.offset_blocks,
109 			   bdev_io->u.bdev.num_blocks,
110 			   bdev_io->u.bdev.iovs, bdev_io->u.bdev.iovcnt, bdev_ftl_cb, bdev_io);
111 
112 	if (spdk_unlikely(rc != 0)) {
113 		spdk_bdev_io_complete(bdev_io, rc);
114 	}
115 }
116 
117 static int
118 _bdev_ftl_submit_request(struct spdk_io_channel *ch, struct spdk_bdev_io *bdev_io)
119 {
120 	struct ftl_bdev *ftl_bdev = (struct ftl_bdev *)bdev_io->bdev->ctxt;
121 
122 	switch (bdev_io->type) {
123 	case SPDK_BDEV_IO_TYPE_READ:
124 		spdk_bdev_io_get_buf(bdev_io, bdev_ftl_get_buf_cb,
125 				     bdev_io->u.bdev.num_blocks * bdev_io->bdev->blocklen);
126 		return 0;
127 
128 	case SPDK_BDEV_IO_TYPE_WRITE:
129 		return spdk_ftl_write(ftl_bdev->dev, ch, bdev_io->u.bdev.offset_blocks,
130 				      bdev_io->u.bdev.num_blocks, bdev_io->u.bdev.iovs,
131 				      bdev_io->u.bdev.iovcnt, bdev_ftl_cb, bdev_io);
132 
133 	case SPDK_BDEV_IO_TYPE_FLUSH:
134 		return spdk_ftl_flush(ftl_bdev->dev, bdev_ftl_cb, bdev_io);
135 
136 	case SPDK_BDEV_IO_TYPE_WRITE_ZEROES:
137 	case SPDK_BDEV_IO_TYPE_RESET:
138 	case SPDK_BDEV_IO_TYPE_UNMAP:
139 	default:
140 		return -ENOTSUP;
141 		break;
142 	}
143 }
144 
145 static void
146 bdev_ftl_submit_request(struct spdk_io_channel *ch, struct spdk_bdev_io *bdev_io)
147 {
148 	int rc = _bdev_ftl_submit_request(ch, bdev_io);
149 
150 	if (spdk_unlikely(rc != 0)) {
151 		spdk_bdev_io_complete(bdev_io, rc);
152 	}
153 }
154 
155 static bool
156 bdev_ftl_io_type_supported(void *ctx, enum spdk_bdev_io_type io_type)
157 {
158 	switch (io_type) {
159 	case SPDK_BDEV_IO_TYPE_READ:
160 	case SPDK_BDEV_IO_TYPE_WRITE:
161 	case SPDK_BDEV_IO_TYPE_FLUSH:
162 		return true;
163 	case SPDK_BDEV_IO_TYPE_WRITE_ZEROES:
164 	case SPDK_BDEV_IO_TYPE_RESET:
165 	case SPDK_BDEV_IO_TYPE_UNMAP:
166 	default:
167 		return false;
168 	}
169 }
170 
171 static struct spdk_io_channel *
172 bdev_ftl_get_io_channel(void *ctx)
173 {
174 	struct ftl_bdev *ftl_bdev = ctx;
175 
176 	return spdk_get_io_channel(ftl_bdev->dev);
177 }
178 
179 static void
180 _bdev_ftl_write_config_info(struct ftl_bdev *ftl_bdev, struct spdk_json_write_ctx *w)
181 {
182 	struct spdk_ftl_attrs attrs = {};
183 
184 	spdk_ftl_dev_get_attrs(ftl_bdev->dev, &attrs);
185 
186 	spdk_json_write_named_string(w, "base_bdev", attrs.base_bdev);
187 
188 	if (attrs.cache_bdev) {
189 		spdk_json_write_named_string(w, "cache", attrs.cache_bdev);
190 	}
191 }
192 
193 static void
194 bdev_ftl_write_config_json(struct spdk_bdev *bdev, struct spdk_json_write_ctx *w)
195 {
196 	struct ftl_bdev *ftl_bdev = bdev->ctxt;
197 	struct spdk_ftl_attrs attrs;
198 	struct spdk_ftl_conf *conf = &attrs.conf;
199 	char uuid[SPDK_UUID_STRING_LEN];
200 
201 	spdk_ftl_dev_get_attrs(ftl_bdev->dev, &attrs);
202 
203 	spdk_json_write_object_begin(w);
204 
205 	spdk_json_write_named_string(w, "method", "bdev_ftl_create");
206 
207 	spdk_json_write_named_object_begin(w, "params");
208 	spdk_json_write_named_string(w, "name", ftl_bdev->bdev.name);
209 
210 	spdk_json_write_named_bool(w, "allow_open_bands", conf->allow_open_bands);
211 	spdk_json_write_named_uint64(w, "overprovisioning", conf->lba_rsvd);
212 	spdk_json_write_named_uint64(w, "limit_crit", conf->limits[SPDK_FTL_LIMIT_CRIT].limit);
213 	spdk_json_write_named_uint64(w, "limit_crit_threshold", conf->limits[SPDK_FTL_LIMIT_CRIT].thld);
214 	spdk_json_write_named_uint64(w, "limit_high", conf->limits[SPDK_FTL_LIMIT_HIGH].limit);
215 	spdk_json_write_named_uint64(w, "limit_high_threshold", conf->limits[SPDK_FTL_LIMIT_HIGH].thld);
216 	spdk_json_write_named_uint64(w, "limit_low", conf->limits[SPDK_FTL_LIMIT_LOW].limit);
217 	spdk_json_write_named_uint64(w, "limit_low_threshold", conf->limits[SPDK_FTL_LIMIT_LOW].thld);
218 	spdk_json_write_named_uint64(w, "limit_start", conf->limits[SPDK_FTL_LIMIT_START].limit);
219 	spdk_json_write_named_uint64(w, "limit_start_threshold", conf->limits[SPDK_FTL_LIMIT_START].thld);
220 	if (conf->l2p_path) {
221 		spdk_json_write_named_string(w, "l2p_path", conf->l2p_path);
222 	}
223 
224 	spdk_uuid_fmt_lower(uuid, sizeof(uuid), &attrs.uuid);
225 	spdk_json_write_named_string(w, "uuid", uuid);
226 
227 	_bdev_ftl_write_config_info(ftl_bdev, w);
228 
229 	spdk_json_write_object_end(w);
230 	spdk_json_write_object_end(w);
231 }
232 
233 static int
234 bdev_ftl_dump_info_json(void *ctx, struct spdk_json_write_ctx *w)
235 {
236 	struct ftl_bdev *ftl_bdev = ctx;
237 	struct spdk_ftl_attrs attrs;
238 
239 	spdk_ftl_dev_get_attrs(ftl_bdev->dev, &attrs);
240 
241 	spdk_json_write_named_object_begin(w, "ftl");
242 
243 	_bdev_ftl_write_config_info(ftl_bdev, w);
244 	spdk_json_write_named_string_fmt(w, "num_zones", "%zu", attrs.num_zones);
245 	spdk_json_write_named_string_fmt(w, "zone_size", "%zu", attrs.zone_size);
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_cb(struct spdk_ftl_dev *dev, void *ctx, int status)
264 {
265 	struct ftl_bdev		*ftl_bdev = ctx;
266 	struct ftl_bdev_info	info = {};
267 	struct spdk_ftl_attrs	attrs;
268 	ftl_bdev_init_fn	init_cb = ftl_bdev->init_cb;
269 	void			*init_arg = ftl_bdev->init_arg;
270 	int			rc = -ENODEV;
271 
272 	if (status) {
273 		SPDK_ERRLOG("Failed to create FTL device (%d)\n", status);
274 		rc = status;
275 		goto error;
276 	}
277 
278 	spdk_ftl_dev_get_attrs(dev, &attrs);
279 
280 	ftl_bdev->dev = dev;
281 	ftl_bdev->bdev.product_name = "FTL disk";
282 	ftl_bdev->bdev.write_cache = 0;
283 	ftl_bdev->bdev.blocklen = attrs.block_size;
284 	ftl_bdev->bdev.blockcnt = attrs.num_blocks;
285 	ftl_bdev->bdev.uuid = attrs.uuid;
286 
287 	SPDK_DEBUGLOG(bdev_ftl, "Creating bdev %s:\n", ftl_bdev->bdev.name);
288 	SPDK_DEBUGLOG(bdev_ftl, "\tblock_len:\t%zu\n", attrs.block_size);
289 	SPDK_DEBUGLOG(bdev_ftl, "\tnum_blocks:\t%"PRIu64"\n", attrs.num_blocks);
290 
291 	ftl_bdev->bdev.ctxt = ftl_bdev;
292 	ftl_bdev->bdev.fn_table = &ftl_fn_table;
293 	ftl_bdev->bdev.module = &g_ftl_if;
294 
295 	if (spdk_bdev_register(&ftl_bdev->bdev)) {
296 		goto error;
297 	}
298 
299 	info.name = ftl_bdev->bdev.name;
300 	info.uuid = ftl_bdev->bdev.uuid;
301 
302 	init_cb(&info, init_arg, 0);
303 	return;
304 
305 error:
306 	free(ftl_bdev->bdev.name);
307 	free(ftl_bdev);
308 
309 	init_cb(NULL, init_arg, rc);
310 }
311 
312 static void
313 bdev_ftl_defer_free(struct ftl_deferred_init *init)
314 {
315 	free((char *)init->opts.name);
316 	free((char *)init->opts.base_bdev);
317 	free((char *)init->opts.cache_bdev);
318 	free(init);
319 }
320 
321 static int
322 bdev_ftl_defer_init(const struct ftl_bdev_init_opts *opts)
323 {
324 	struct ftl_deferred_init *init;
325 
326 	init = calloc(1, sizeof(*init));
327 	if (!init) {
328 		return -ENOMEM;
329 	}
330 
331 	init->opts.mode = opts->mode;
332 	init->opts.uuid = opts->uuid;
333 	init->opts.ftl_conf = opts->ftl_conf;
334 
335 	init->opts.name = strdup(opts->name);
336 	if (!init->opts.name) {
337 		SPDK_ERRLOG("Could not allocate bdev name\n");
338 		goto error;
339 	}
340 
341 	init->opts.base_bdev = strdup(opts->base_bdev);
342 	if (!init->opts.base_bdev) {
343 		SPDK_ERRLOG("Could not allocate base bdev name\n");
344 		goto error;
345 	}
346 
347 	if (opts->cache_bdev) {
348 		init->opts.cache_bdev = strdup(opts->cache_bdev);
349 		if (!init->opts.cache_bdev) {
350 			SPDK_ERRLOG("Could not allocate cache bdev name\n");
351 			goto error;
352 		}
353 	}
354 
355 	LIST_INSERT_HEAD(&g_deferred_init, init, entry);
356 
357 	return 0;
358 
359 error:
360 	bdev_ftl_defer_free(init);
361 	return -ENOMEM;
362 }
363 
364 int
365 bdev_ftl_create_bdev(const struct ftl_bdev_init_opts *bdev_opts,
366 		     ftl_bdev_init_fn cb, void *cb_arg)
367 {
368 	struct ftl_bdev *ftl_bdev = NULL;
369 	struct spdk_ftl_dev_init_opts opts = {};
370 	int rc;
371 
372 	ftl_bdev = calloc(1, sizeof(*ftl_bdev));
373 	if (!ftl_bdev) {
374 		SPDK_ERRLOG("Could not allocate ftl_bdev\n");
375 		return -ENOMEM;
376 	}
377 
378 	ftl_bdev->bdev.name = strdup(bdev_opts->name);
379 	if (!ftl_bdev->bdev.name) {
380 		rc = -ENOMEM;
381 		goto error_bdev;
382 	}
383 
384 	if (spdk_bdev_get_by_name(bdev_opts->base_bdev) == NULL ||
385 	    (bdev_opts->cache_bdev && spdk_bdev_get_by_name(bdev_opts->cache_bdev) == NULL)) {
386 		rc = bdev_ftl_defer_init(bdev_opts);
387 		if (rc == 0) {
388 			rc = -ENODEV;
389 		}
390 		goto error_name;
391 	}
392 
393 	ftl_bdev->init_cb = cb;
394 	ftl_bdev->init_arg = cb_arg;
395 
396 	opts.mode = bdev_opts->mode;
397 	opts.uuid = bdev_opts->uuid;
398 	opts.name = ftl_bdev->bdev.name;
399 	opts.base_bdev = bdev_opts->base_bdev;
400 	opts.cache_bdev = bdev_opts->cache_bdev;
401 	opts.conf = &bdev_opts->ftl_conf;
402 
403 	/* TODO: set threads based on config */
404 	opts.core_thread = spdk_get_thread();
405 
406 	rc = spdk_ftl_dev_init(&opts, bdev_ftl_create_cb, ftl_bdev);
407 	if (rc) {
408 		SPDK_ERRLOG("Could not create FTL device\n");
409 		goto error_name;
410 	}
411 
412 	return 0;
413 
414 error_name:
415 	free(ftl_bdev->bdev.name);
416 error_bdev:
417 	free(ftl_bdev);
418 	return rc;
419 }
420 
421 static int
422 bdev_ftl_initialize(void)
423 {
424 	return 0;
425 }
426 
427 void
428 bdev_ftl_delete_bdev(const char *name, spdk_bdev_unregister_cb cb_fn, void *cb_arg)
429 {
430 	int rc;
431 
432 	rc = spdk_bdev_unregister_by_name(name, &g_ftl_if, cb_fn, cb_arg);
433 	if (rc != 0) {
434 		cb_fn(cb_arg, rc);
435 	}
436 }
437 
438 static void
439 bdev_ftl_finish(void)
440 {
441 }
442 
443 static void
444 bdev_ftl_create_deferred_cb(const struct ftl_bdev_info *info, void *ctx, int status)
445 {
446 	struct ftl_deferred_init *opts = ctx;
447 
448 	if (status) {
449 		SPDK_ERRLOG("Failed to initialize FTL bdev '%s'\n", opts->opts.name);
450 	}
451 
452 	bdev_ftl_defer_free(opts);
453 
454 	spdk_bdev_module_examine_done(&g_ftl_if);
455 }
456 
457 static void
458 bdev_ftl_examine(struct spdk_bdev *bdev)
459 {
460 	struct ftl_deferred_init *opts;
461 
462 	LIST_FOREACH(opts, &g_deferred_init, entry) {
463 		if (spdk_bdev_get_by_name(opts->opts.base_bdev) == NULL) {
464 			continue;
465 		}
466 
467 		if (opts->opts.cache_bdev && spdk_bdev_get_by_name(opts->opts.base_bdev) == NULL) {
468 			continue;
469 		}
470 
471 		LIST_REMOVE(opts, entry);
472 
473 		/* spdk_bdev_module_examine_done will be called by bdev_ftl_create_deferred_cb */
474 		if (bdev_ftl_create_bdev(&opts->opts, bdev_ftl_create_deferred_cb, opts)) {
475 			SPDK_ERRLOG("Failed to initialize FTL bdev '%s'\n", opts->opts.name);
476 			bdev_ftl_defer_free(opts);
477 			break;
478 		}
479 		return;
480 	}
481 
482 	spdk_bdev_module_examine_done(&g_ftl_if);
483 }
484 
485 SPDK_LOG_REGISTER_COMPONENT(bdev_ftl)
486