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