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