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