Branch data Line data Source code
1 : : /* SPDX-License-Identifier: BSD-3-Clause
2 : : * Copyright (C) 2020 Intel Corporation.
3 : : * All rights reserved.
4 : : * Copyright 2023 Solidigm All Rights Reserved
5 : : */
6 : :
7 : : #include "spdk/stdinc.h"
8 : : #include "spdk/bdev.h"
9 : : #include "spdk/env.h"
10 : : #include "spdk/thread.h"
11 : : #include "spdk/json.h"
12 : : #include "spdk/string.h"
13 : : #include "spdk/likely.h"
14 : : #include "spdk/util.h"
15 : : #include "spdk/string.h"
16 : : #include "spdk/ftl.h"
17 : : #include "spdk/log.h"
18 : :
19 : : #include "bdev_ftl.h"
20 : :
21 : : struct ftl_bdev {
22 : : struct spdk_bdev bdev;
23 : : struct spdk_ftl_dev *dev;
24 : : ftl_bdev_init_fn init_cb;
25 : : void *init_arg;
26 : : int rc;
27 : : struct spdk_bdev_desc *base_bdev_desc;
28 : : struct spdk_bdev_desc *cache_bdev_desc;
29 : : };
30 : :
31 : : struct bdev_ftl_action {
32 : : struct spdk_bdev_desc *ftl_bdev_desc;
33 : : struct ftl_bdev *ftl_bdev_dev;
34 : : spdk_ftl_fn cb_fn;
35 : : void *cb_arg;
36 : : int rc;
37 : : size_t ctx_size;
38 : : char ctx[0];
39 : : };
40 : :
41 : : struct ftl_deferred_init {
42 : : struct spdk_ftl_conf conf;
43 : :
44 : : LIST_ENTRY(ftl_deferred_init) entry;
45 : : };
46 : :
47 : : static LIST_HEAD(, ftl_deferred_init) g_deferred_init = LIST_HEAD_INITIALIZER(g_deferred_init);
48 : :
49 : : static int bdev_ftl_initialize(void);
50 : : static void bdev_ftl_finish(void);
51 : : static void bdev_ftl_examine(struct spdk_bdev *bdev);
52 : :
53 : : static void bdev_ftl_action_finish_cb(void *cb_arg, int status);
54 : : static struct bdev_ftl_action *bdev_ftl_action_start(const char *bdev_name,
55 : : size_t ctx_size, spdk_ftl_fn cb_fn, void *cb_arg);
56 : : static void bdev_ftl_action_finish(struct bdev_ftl_action *action);
57 : : static void *bdev_ftl_action_ctx(struct bdev_ftl_action *action, size_t size);
58 : :
59 : : static int
60 : 3706 : bdev_ftl_get_ctx_size(void)
61 : : {
62 : 3706 : return spdk_ftl_io_size();
63 : : }
64 : :
65 : : static struct spdk_bdev_module g_ftl_if = {
66 : : .name = "ftl",
67 : : .module_init = bdev_ftl_initialize,
68 : : .module_fini = bdev_ftl_finish,
69 : : .examine_disk = bdev_ftl_examine,
70 : : .get_ctx_size = bdev_ftl_get_ctx_size,
71 : : };
72 : :
73 : 2001 : SPDK_BDEV_MODULE_REGISTER(ftl, &g_ftl_if)
74 : :
75 : : static void
76 : 22 : bdev_ftl_free(struct ftl_bdev *ftl_bdev)
77 : : {
78 : 22 : spdk_bdev_close(ftl_bdev->base_bdev_desc);
79 : 22 : spdk_bdev_close(ftl_bdev->cache_bdev_desc);
80 : 22 : free(ftl_bdev->bdev.name);
81 : 22 : free(ftl_bdev);
82 : 22 : }
83 : :
84 : : static void
85 : 22 : bdev_ftl_dev_free_cb(void *ctx, int status)
86 : : {
87 : 22 : struct ftl_bdev *ftl_bdev = ctx;
88 : :
89 : 22 : spdk_bdev_destruct_done(&ftl_bdev->bdev, status);
90 : 22 : bdev_ftl_free(ftl_bdev);
91 : 22 : }
92 : :
93 : : static int
94 : 22 : bdev_ftl_destruct(void *ctx)
95 : : {
96 : 22 : struct ftl_bdev *ftl_bdev = ctx;
97 : :
98 : 22 : spdk_ftl_dev_free(ftl_bdev->dev, bdev_ftl_dev_free_cb, ftl_bdev);
99 : :
100 : : /* return 1 to indicate that the destruction is asynchronous */
101 : 22 : return 1;
102 : : }
103 : :
104 : : static void
105 : 2573681 : bdev_ftl_cb(void *arg, int rc)
106 : : {
107 : 2573681 : struct spdk_bdev_io *bdev_io = arg;
108 : : enum spdk_bdev_io_status status;
109 : :
110 [ + - - ]: 2573681 : switch (rc) {
111 : 2573681 : case 0:
112 : 2573681 : status = SPDK_BDEV_IO_STATUS_SUCCESS;
113 : 2573681 : break;
114 : 0 : case -EAGAIN:
115 : : case -ENOMEM:
116 : 0 : status = SPDK_BDEV_IO_STATUS_NOMEM;
117 : 0 : break;
118 : 0 : default:
119 : 0 : status = SPDK_BDEV_IO_STATUS_FAILED;
120 : 0 : break;
121 : : }
122 : :
123 : 2573681 : spdk_bdev_io_complete(bdev_io, status);
124 : 2573681 : }
125 : :
126 : : static void
127 : 1447614 : bdev_ftl_get_buf_cb(struct spdk_io_channel *ch, struct spdk_bdev_io *bdev_io,
128 : : bool success)
129 : : {
130 : : struct ftl_bdev *ftl_bdev;
131 : : int rc;
132 : :
133 : 1447614 : ftl_bdev = bdev_io->bdev->ctxt;
134 : :
135 [ - + ]: 1447614 : if (!success) {
136 : 0 : spdk_bdev_io_complete(bdev_io, SPDK_BDEV_IO_STATUS_FAILED);
137 : 0 : return;
138 : : }
139 : :
140 : 1447614 : rc = spdk_ftl_readv(ftl_bdev->dev, (struct ftl_io *)bdev_io->driver_ctx,
141 : : ch,
142 : : bdev_io->u.bdev.offset_blocks,
143 : : bdev_io->u.bdev.num_blocks,
144 : 1447614 : bdev_io->u.bdev.iovs, bdev_io->u.bdev.iovcnt, bdev_ftl_cb, bdev_io);
145 : :
146 [ - + ]: 1447614 : if (spdk_unlikely(rc != 0)) {
147 : 0 : bdev_ftl_cb(bdev_io, rc);
148 : : }
149 : : }
150 : :
151 : : static int
152 : 2573681 : _bdev_ftl_submit_request(struct spdk_io_channel *ch, struct spdk_bdev_io *bdev_io)
153 : : {
154 : 2573681 : struct ftl_bdev *ftl_bdev = (struct ftl_bdev *)bdev_io->bdev->ctxt;
155 : :
156 [ + + - - : 2573681 : switch (bdev_io->type) {
- ]
157 : 1447614 : case SPDK_BDEV_IO_TYPE_READ:
158 : 1447614 : spdk_bdev_io_get_buf(bdev_io, bdev_ftl_get_buf_cb,
159 : 1447614 : bdev_io->u.bdev.num_blocks * bdev_io->bdev->blocklen);
160 : 1447614 : return 0;
161 : :
162 : 1126067 : case SPDK_BDEV_IO_TYPE_WRITE:
163 : 1126067 : return spdk_ftl_writev(ftl_bdev->dev, (struct ftl_io *)bdev_io->driver_ctx,
164 : : ch, bdev_io->u.bdev.offset_blocks,
165 : : bdev_io->u.bdev.num_blocks, bdev_io->u.bdev.iovs,
166 : 1126067 : bdev_io->u.bdev.iovcnt, bdev_ftl_cb, bdev_io);
167 : :
168 : 0 : case SPDK_BDEV_IO_TYPE_UNMAP:
169 : 0 : return spdk_ftl_unmap(ftl_bdev->dev, (struct ftl_io *)bdev_io->driver_ctx,
170 : : ch, bdev_io->u.bdev.offset_blocks,
171 : : bdev_io->u.bdev.num_blocks, bdev_ftl_cb, bdev_io);
172 : 0 : case SPDK_BDEV_IO_TYPE_FLUSH:
173 : 0 : spdk_bdev_io_complete(bdev_io, SPDK_BDEV_IO_STATUS_SUCCESS);
174 : 0 : return 0;
175 : 0 : default:
176 : 0 : return -ENOTSUP;
177 : : }
178 : : }
179 : :
180 : : static void
181 : 2573681 : bdev_ftl_submit_request(struct spdk_io_channel *ch, struct spdk_bdev_io *bdev_io)
182 : : {
183 : 2573681 : int rc = _bdev_ftl_submit_request(ch, bdev_io);
184 : :
185 [ - + ]: 2573681 : if (spdk_unlikely(rc != 0)) {
186 : 0 : bdev_ftl_cb(bdev_io, rc);
187 : : }
188 : 2573681 : }
189 : :
190 : : static bool
191 : 125 : bdev_ftl_io_type_supported(void *ctx, enum spdk_bdev_io_type io_type)
192 : : {
193 [ + + ]: 125 : switch (io_type) {
194 : 29 : case SPDK_BDEV_IO_TYPE_READ:
195 : : case SPDK_BDEV_IO_TYPE_WRITE:
196 : : case SPDK_BDEV_IO_TYPE_FLUSH:
197 : : case SPDK_BDEV_IO_TYPE_UNMAP:
198 : 29 : return true;
199 : 96 : default:
200 : 96 : return false;
201 : : }
202 : : }
203 : :
204 : : static struct spdk_io_channel *
205 : 42 : bdev_ftl_get_io_channel(void *ctx)
206 : : {
207 : 42 : struct ftl_bdev *ftl_bdev = ctx;
208 : :
209 : 42 : return spdk_ftl_get_io_channel(ftl_bdev->dev);
210 : : }
211 : :
212 : : static void
213 : 4 : bdev_ftl_write_config_json(struct spdk_bdev *bdev, struct spdk_json_write_ctx *w)
214 : : {
215 : 4 : struct ftl_bdev *ftl_bdev = bdev->ctxt;
216 : 4 : struct spdk_ftl_conf conf;
217 : :
218 : 4 : spdk_ftl_dev_get_conf(ftl_bdev->dev, &conf, sizeof(conf));
219 : :
220 : 4 : spdk_json_write_object_begin(w);
221 : :
222 : 4 : spdk_json_write_named_string(w, "method", "bdev_ftl_create");
223 : :
224 : 4 : spdk_json_write_named_object_begin(w, "params");
225 : 4 : spdk_json_write_named_string(w, "name", ftl_bdev->bdev.name);
226 : :
227 : 4 : spdk_json_write_named_uint64(w, "overprovisioning", conf.overprovisioning);
228 : 4 : spdk_json_write_named_uint64(w, "l2p_dram_limit", conf.l2p_dram_limit);
229 : :
230 [ + + ]: 4 : if (conf.core_mask) {
231 : 1 : spdk_json_write_named_string(w, "core_mask", conf.core_mask);
232 : : }
233 : :
234 : 4 : spdk_json_write_named_uuid(w, "uuid", &conf.uuid);
235 : :
236 [ - + ]: 4 : spdk_json_write_named_bool(w, "fast_shutdown", conf.fast_shutdown);
237 : :
238 : 4 : spdk_json_write_named_string(w, "base_bdev", conf.base_bdev);
239 : :
240 [ + - ]: 4 : if (conf.cache_bdev) {
241 : 4 : spdk_json_write_named_string(w, "cache", conf.cache_bdev);
242 : : }
243 : :
244 : 4 : spdk_json_write_object_end(w);
245 : 4 : spdk_json_write_object_end(w);
246 : 4 : }
247 : :
248 : : static int
249 : 3 : bdev_ftl_dump_info_json(void *ctx, struct spdk_json_write_ctx *w)
250 : : {
251 : 3 : struct ftl_bdev *ftl_bdev = ctx;
252 : 3 : struct spdk_ftl_attrs attrs;
253 : 3 : struct spdk_ftl_conf conf;
254 : :
255 : 3 : spdk_ftl_dev_get_attrs(ftl_bdev->dev, &attrs, sizeof(attrs));
256 : 3 : spdk_ftl_dev_get_conf(ftl_bdev->dev, &conf, sizeof(conf));
257 : :
258 : 3 : spdk_json_write_named_object_begin(w, "ftl");
259 : :
260 : 3 : spdk_json_write_named_string(w, "base_bdev", conf.base_bdev);
261 : :
262 [ + - ]: 3 : if (conf.cache_bdev) {
263 : 3 : spdk_json_write_named_string(w, "cache", conf.cache_bdev);
264 : : }
265 : :
266 : : /* ftl */
267 : 3 : spdk_json_write_object_end(w);
268 : :
269 : 3 : return 0;
270 : : }
271 : :
272 : : static const struct spdk_bdev_fn_table ftl_fn_table = {
273 : : .destruct = bdev_ftl_destruct,
274 : : .submit_request = bdev_ftl_submit_request,
275 : : .io_type_supported = bdev_ftl_io_type_supported,
276 : : .get_io_channel = bdev_ftl_get_io_channel,
277 : : .write_config_json = bdev_ftl_write_config_json,
278 : : .dump_info_json = bdev_ftl_dump_info_json,
279 : : };
280 : :
281 : : static void
282 : 0 : bdev_ftl_create_err_complete(struct ftl_bdev *ftl_bdev)
283 : : {
284 : 0 : ftl_bdev_init_fn init_cb = ftl_bdev->init_cb;
285 : 0 : void *init_arg = ftl_bdev->init_arg;
286 : 0 : int rc = ftl_bdev->rc;
287 : :
288 : 0 : bdev_ftl_free(ftl_bdev);
289 : :
290 [ # # ]: 0 : assert(rc);
291 : 0 : init_cb(NULL, init_arg, rc);
292 : 0 : }
293 : :
294 : : static void
295 : 0 : bdev_ftl_create_err_cleanup_cb(void *ctx, int status)
296 : : {
297 : 0 : struct ftl_bdev *ftl_bdev = ctx;
298 : :
299 [ # # ]: 0 : if (status) {
300 : 0 : SPDK_ERRLOG("Fatal ERROR of FTL cleanup, name %s\n", ftl_bdev->bdev.name);
301 : : }
302 : :
303 : 0 : bdev_ftl_create_err_complete(ftl_bdev);
304 : 0 : }
305 : :
306 : : static void
307 : 22 : bdev_ftl_create_cb(struct spdk_ftl_dev *dev, void *ctx, int status)
308 : : {
309 : 22 : struct ftl_bdev *ftl_bdev = ctx;
310 : 22 : struct ftl_bdev_info info = {};
311 : 22 : struct spdk_ftl_attrs attrs;
312 : 22 : struct spdk_ftl_conf conf;
313 : 22 : ftl_bdev_init_fn init_cb = ftl_bdev->init_cb;
314 : 22 : void *init_arg = ftl_bdev->init_arg;
315 : :
316 [ - + ]: 22 : if (status) {
317 : 0 : SPDK_ERRLOG("Failed to create FTL device (%d)\n", status);
318 : 0 : ftl_bdev->rc = status;
319 : 0 : goto error;
320 : : }
321 : :
322 : 22 : spdk_ftl_dev_get_attrs(dev, &attrs, sizeof(attrs));
323 : 22 : spdk_ftl_dev_get_conf(dev, &conf, sizeof(conf));
324 : :
325 : 22 : ftl_bdev->dev = dev;
326 : 22 : ftl_bdev->bdev.product_name = "FTL disk";
327 : 22 : ftl_bdev->bdev.write_cache = 0;
328 : 22 : ftl_bdev->bdev.blocklen = attrs.block_size;
329 : 22 : ftl_bdev->bdev.blockcnt = attrs.num_blocks;
330 : 22 : ftl_bdev->bdev.uuid = conf.uuid;
331 : 22 : ftl_bdev->bdev.optimal_io_boundary = attrs.optimum_io_size;
332 : 22 : ftl_bdev->bdev.split_on_optimal_io_boundary = true;
333 : :
334 [ - + - + ]: 22 : SPDK_DEBUGLOG(bdev_ftl, "Creating bdev %s:\n", ftl_bdev->bdev.name);
335 [ - + - + ]: 22 : SPDK_DEBUGLOG(bdev_ftl, "\tblock_len:\t%zu\n", attrs.block_size);
336 [ - + - + ]: 22 : SPDK_DEBUGLOG(bdev_ftl, "\tnum_blocks:\t%"PRIu64"\n", attrs.num_blocks);
337 : :
338 : 22 : ftl_bdev->bdev.ctxt = ftl_bdev;
339 : 22 : ftl_bdev->bdev.fn_table = &ftl_fn_table;
340 : 22 : ftl_bdev->bdev.module = &g_ftl_if;
341 : :
342 : 22 : status = spdk_bdev_register(&ftl_bdev->bdev);
343 [ - + ]: 22 : if (status) {
344 : 0 : ftl_bdev->rc = status;
345 : 0 : goto error;
346 : : }
347 : :
348 : 22 : info.name = ftl_bdev->bdev.name;
349 : 22 : info.uuid = ftl_bdev->bdev.uuid;
350 : :
351 : 22 : init_cb(&info, init_arg, 0);
352 : 22 : return;
353 : :
354 : 0 : error:
355 [ # # ]: 0 : if (ftl_bdev->dev) {
356 : : /* Cleanup all FTL */
357 : 0 : spdk_ftl_dev_set_fast_shutdown(ftl_bdev->dev, false);
358 : :
359 : : /* FTL was created, but we have got an error, so we need to delete it */
360 : 0 : spdk_ftl_dev_free(dev, bdev_ftl_create_err_cleanup_cb, ftl_bdev);
361 : : } else {
362 : 0 : bdev_ftl_create_err_complete(ftl_bdev);
363 : : }
364 : : }
365 : :
366 : : static void
367 : 0 : bdev_ftl_defer_free(struct ftl_deferred_init *init)
368 : : {
369 : 0 : spdk_ftl_conf_deinit(&init->conf);
370 : 0 : free(init);
371 : 0 : }
372 : :
373 : : int
374 : 0 : bdev_ftl_defer_init(const struct spdk_ftl_conf *conf)
375 : : {
376 : : struct ftl_deferred_init *init;
377 : : int rc;
378 : :
379 : 0 : init = calloc(1, sizeof(*init));
380 [ # # ]: 0 : if (!init) {
381 : 0 : return -ENOMEM;
382 : : }
383 : :
384 : 0 : rc = spdk_ftl_conf_copy(&init->conf, conf);
385 [ # # ]: 0 : if (rc) {
386 : 0 : free(init);
387 : 0 : return -ENOMEM;
388 : : }
389 : :
390 [ # # ]: 0 : LIST_INSERT_HEAD(&g_deferred_init, init, entry);
391 : :
392 : 0 : return 0;
393 : : }
394 : :
395 : : static void
396 : 0 : bdev_ftl_create_bdev_event_cb(enum spdk_bdev_event_type type, struct spdk_bdev *bdev, void *ctx)
397 : : {
398 : 0 : }
399 : :
400 : : int
401 : 22 : bdev_ftl_create_bdev(const struct spdk_ftl_conf *conf, ftl_bdev_init_fn cb, void *cb_arg)
402 : : {
403 : : struct ftl_bdev *ftl_bdev;
404 : 22 : struct spdk_bdev_desc *base_bdev_desc, *cache_bdev_desc;
405 : : int rc;
406 : :
407 : 22 : rc = spdk_bdev_open_ext(conf->base_bdev, false, bdev_ftl_create_bdev_event_cb, NULL,
408 : : &base_bdev_desc);
409 [ - + ]: 22 : if (rc) {
410 : 0 : return rc;
411 : : }
412 : 22 : rc = spdk_bdev_open_ext(conf->cache_bdev, false, bdev_ftl_create_bdev_event_cb, NULL,
413 : : &cache_bdev_desc);
414 [ - + ]: 22 : if (rc) {
415 : 0 : spdk_bdev_close(base_bdev_desc);
416 : 0 : return rc;
417 : : }
418 : :
419 : 22 : ftl_bdev = calloc(1, sizeof(*ftl_bdev));
420 [ - + ]: 22 : if (!ftl_bdev) {
421 : 0 : SPDK_ERRLOG("Could not allocate ftl_bdev\n");
422 : 0 : spdk_bdev_close(base_bdev_desc);
423 : 0 : spdk_bdev_close(cache_bdev_desc);
424 : 0 : return -ENOMEM;
425 : : }
426 : :
427 : 22 : ftl_bdev->base_bdev_desc = base_bdev_desc;
428 : 22 : ftl_bdev->cache_bdev_desc = cache_bdev_desc;
429 : :
430 [ - + ]: 22 : ftl_bdev->bdev.name = strdup(conf->name);
431 [ - + ]: 22 : if (!ftl_bdev->bdev.name) {
432 : 0 : rc = -ENOMEM;
433 : 0 : goto error;
434 : : }
435 : :
436 : 22 : ftl_bdev->init_cb = cb;
437 : 22 : ftl_bdev->init_arg = cb_arg;
438 : :
439 : 22 : rc = spdk_ftl_dev_init(conf, bdev_ftl_create_cb, ftl_bdev);
440 [ - + ]: 22 : if (rc) {
441 : 0 : SPDK_ERRLOG("Could not create FTL device\n");
442 : 0 : goto error;
443 : : }
444 : :
445 : 22 : return 0;
446 : :
447 : 0 : error:
448 : 0 : bdev_ftl_free(ftl_bdev);
449 : 0 : return rc;
450 : : }
451 : :
452 : : static int
453 : 1853 : bdev_ftl_initialize(void)
454 : : {
455 : 1853 : return spdk_ftl_init();
456 : : }
457 : :
458 : : static void
459 : 0 : bdev_ftl_event_cb(enum spdk_bdev_event_type type, struct spdk_bdev *bdev, void *ctx)
460 : : {
461 : 0 : }
462 : :
463 : : void
464 : 4 : bdev_ftl_delete_bdev(const char *name, bool fast_shutdown, spdk_bdev_unregister_cb cb_fn,
465 : : void *cb_arg)
466 : : {
467 : 4 : struct spdk_bdev_desc *ftl_bdev_desc;
468 : : struct spdk_bdev *bdev;
469 : : struct ftl_bdev *ftl;
470 : : int rc;
471 : :
472 : 4 : rc = spdk_bdev_open_ext(name, false, bdev_ftl_event_cb, NULL, &ftl_bdev_desc);
473 : :
474 [ - + ]: 4 : if (rc) {
475 : 0 : goto not_found;
476 : : }
477 : :
478 : 4 : bdev = spdk_bdev_desc_get_bdev(ftl_bdev_desc);
479 : :
480 [ - + ]: 4 : if (bdev->module != &g_ftl_if) {
481 : 0 : goto bdev_opened;
482 : : }
483 : :
484 : 4 : ftl = bdev->ctxt;
485 [ - + ]: 4 : assert(ftl);
486 : 4 : spdk_ftl_dev_set_fast_shutdown(ftl->dev, fast_shutdown);
487 : 4 : spdk_bdev_close(ftl_bdev_desc);
488 : :
489 : 4 : rc = spdk_bdev_unregister_by_name(name, &g_ftl_if, cb_fn, cb_arg);
490 [ - + ]: 4 : if (rc) {
491 : 0 : cb_fn(cb_arg, rc);
492 : : }
493 : :
494 : 4 : return;
495 : 0 : bdev_opened:
496 : 0 : spdk_bdev_close(ftl_bdev_desc);
497 : 0 : not_found:
498 : 0 : cb_fn(cb_arg, -ENODEV);
499 : : }
500 : :
501 : : void
502 : 4 : bdev_ftl_unmap(const char *name, uint64_t lba, uint64_t num_blocks, spdk_ftl_fn cb_fn,
503 : : void *cb_arg)
504 : : {
505 : : struct bdev_ftl_action *action;
506 : :
507 : 4 : action = bdev_ftl_action_start(name, 0, cb_fn, cb_arg);
508 [ - + ]: 4 : if (!action) {
509 : 0 : return;
510 : : }
511 : :
512 : : /* It's ok to pass NULL as IO channel - FTL will detect this and use it's internal IO channel for management operations */
513 : 4 : action->rc = spdk_ftl_unmap(action->ftl_bdev_dev->dev, NULL, NULL, lba, num_blocks,
514 : : bdev_ftl_action_finish_cb, action);
515 [ - + ]: 4 : if (action->rc) {
516 : 0 : bdev_ftl_action_finish(action);
517 : : }
518 : : }
519 : :
520 : : static void
521 : 1 : bdev_ftl_get_stats_cb(struct ftl_stats *stats, void *cb_arg)
522 : : {
523 : 1 : struct bdev_ftl_action *action = cb_arg;
524 : :
525 : 1 : bdev_ftl_action_finish(action);
526 : 1 : }
527 : :
528 : : void
529 : 1 : bdev_ftl_get_stats(const char *name, spdk_ftl_fn cb, struct rpc_ftl_stats_ctx *ftl_stats_ctx)
530 : : {
531 : : struct bdev_ftl_action *action;
532 : :
533 : 1 : action = bdev_ftl_action_start(name, 0, cb, ftl_stats_ctx);
534 [ - + ]: 1 : if (!action) {
535 : 0 : return;
536 : : }
537 : 1 : ftl_stats_ctx->ftl_bdev_desc = action->ftl_bdev_desc;
538 : 1 : action->rc = spdk_ftl_get_stats(action->ftl_bdev_dev->dev, &ftl_stats_ctx->ftl_stats,
539 : : bdev_ftl_get_stats_cb, action);
540 [ - + ]: 1 : if (action->rc) {
541 : 0 : bdev_ftl_action_finish(action);
542 : : }
543 : : }
544 : :
545 : : void
546 : 3 : bdev_ftl_get_properties(const char *name, spdk_ftl_fn cb_fn, struct spdk_jsonrpc_request *request)
547 : : {
548 : : struct bdev_ftl_action *action;
549 : :
550 : 3 : action = bdev_ftl_action_start(name, 0, cb_fn, request);
551 [ - + ]: 3 : if (!action) {
552 : 0 : return;
553 : : }
554 : :
555 : 3 : action->rc = spdk_ftl_get_properties(action->ftl_bdev_dev->dev, request,
556 : : bdev_ftl_action_finish_cb, action);
557 [ - + ]: 3 : if (action->rc) {
558 : 0 : bdev_ftl_action_finish(action);
559 : : }
560 : : }
561 : :
562 : : struct bdev_ftl_set_property_args {
563 : : char *property;
564 : : char *value;
565 : : };
566 : :
567 : : static void
568 : 3 : bdev_ftl_set_property_cb(void *cb_arg, int status)
569 : : {
570 : 3 : struct bdev_ftl_action *action = cb_arg;
571 : 3 : struct bdev_ftl_set_property_args *args = bdev_ftl_action_ctx(action, sizeof(*args));
572 : :
573 : 3 : free(args->property);
574 : 3 : free(args->value);
575 : 3 : args->property = NULL;
576 : 3 : args->value = NULL;
577 : 3 : bdev_ftl_action_finish_cb(cb_arg, status);
578 : 3 : }
579 : :
580 : : void
581 : 3 : bdev_ftl_set_property(const char *name, const char *property, const char *value,
582 : : spdk_ftl_fn cb_fn, void *cb_arg)
583 : : {
584 : : struct bdev_ftl_action *action;
585 : : struct bdev_ftl_set_property_args *args;
586 : :
587 : 3 : action = bdev_ftl_action_start(name, sizeof(*args), cb_fn, cb_arg);
588 [ - + ]: 3 : if (!action) {
589 : 0 : return;
590 : : }
591 : :
592 : 3 : args = bdev_ftl_action_ctx(action, sizeof(*args));
593 [ - + ]: 3 : args->property = strdup(property);
594 [ - + ]: 3 : args->value = strdup(value);
595 : :
596 [ + - - + ]: 3 : if (!args->property || !args->value) {
597 : 0 : free(args->property);
598 : 0 : free(args->value);
599 : 0 : action->rc = -ENOMEM;
600 : 0 : bdev_ftl_action_finish(action);
601 : 0 : return;
602 : : }
603 : :
604 : 3 : action->rc = spdk_ftl_set_property(action->ftl_bdev_dev->dev,
605 [ - + ]: 3 : args->property, args->value, strlen(args->value) + 1,
606 : : bdev_ftl_set_property_cb, action);
607 [ - + ]: 3 : if (action->rc) {
608 : 0 : bdev_ftl_action_finish(action);
609 : : }
610 : : }
611 : :
612 : : static void
613 : 1853 : bdev_ftl_finish(void)
614 : : {
615 : 1853 : spdk_ftl_fini();
616 : 1853 : }
617 : :
618 : : static void
619 : 0 : bdev_ftl_create_deferred_cb(const struct ftl_bdev_info *info, void *ctx, int status)
620 : : {
621 : 0 : struct ftl_deferred_init *opts = ctx;
622 : :
623 [ # # ]: 0 : if (status) {
624 : 0 : SPDK_ERRLOG("Failed to initialize FTL bdev '%s'\n", opts->conf.name);
625 : : }
626 : :
627 : 0 : bdev_ftl_defer_free(opts);
628 : :
629 : 0 : spdk_bdev_module_examine_done(&g_ftl_if);
630 : 0 : }
631 : :
632 : : static void
633 : 5716 : bdev_ftl_examine(struct spdk_bdev *bdev)
634 : : {
635 : : struct ftl_deferred_init *opts;
636 : : int rc;
637 : :
638 [ - + ]: 5716 : LIST_FOREACH(opts, &g_deferred_init, entry) {
639 : : /* spdk_bdev_module_examine_done will be called by bdev_ftl_create_deferred_cb */
640 : 0 : rc = bdev_ftl_create_bdev(&opts->conf, bdev_ftl_create_deferred_cb, opts);
641 [ # # ]: 0 : if (rc == -ENODEV) {
642 : 0 : continue;
643 : : }
644 : :
645 [ # # ]: 0 : LIST_REMOVE(opts, entry);
646 : :
647 [ # # ]: 0 : if (rc) {
648 : 0 : bdev_ftl_create_deferred_cb(NULL, opts, rc);
649 : : }
650 : 0 : return;
651 : : }
652 : :
653 : 5716 : spdk_bdev_module_examine_done(&g_ftl_if);
654 : : }
655 : :
656 : 2001 : SPDK_LOG_REGISTER_COMPONENT(bdev_ftl)
657 : :
658 : : /*
659 : : * Generic function to execute an action on the FTL bdev
660 : : */
661 : : static void
662 : 11 : bdev_ftl_action_finish(struct bdev_ftl_action *action)
663 : : {
664 : 11 : action->cb_fn(action->cb_arg, action->rc);
665 [ + - ]: 11 : if (action->ftl_bdev_desc) {
666 : 11 : spdk_bdev_close(action->ftl_bdev_desc);
667 : : }
668 : 11 : free(action);
669 : 11 : }
670 : :
671 : : static struct bdev_ftl_action *
672 : 11 : bdev_ftl_action_start(const char *bdev_name, size_t ctx_size, spdk_ftl_fn cb_fn, void *cb_arg)
673 : : {
674 : : struct spdk_bdev *bdev;
675 : 11 : struct bdev_ftl_action *action = calloc(1, sizeof(*action) + ctx_size);
676 : :
677 [ - + ]: 11 : if (NULL == action) {
678 : 0 : cb_fn(cb_arg, -ENOMEM);
679 : 0 : return NULL;
680 : : }
681 : 11 : action->cb_arg = cb_arg;
682 : 11 : action->cb_fn = cb_fn;
683 : 11 : action->ctx_size = ctx_size;
684 : :
685 : 11 : action->rc = spdk_bdev_open_ext(bdev_name, false, bdev_ftl_event_cb, NULL, &action->ftl_bdev_desc);
686 [ - + ]: 11 : if (action->rc) {
687 : 0 : goto error;
688 : : }
689 : :
690 : 11 : bdev = spdk_bdev_desc_get_bdev(action->ftl_bdev_desc);
691 [ - + ]: 11 : if (bdev->module != &g_ftl_if) {
692 : 0 : action->rc = -ENODEV;
693 : 0 : goto error;
694 : : }
695 : :
696 : 11 : action->ftl_bdev_dev = bdev->ctxt;
697 [ - + ]: 11 : assert(action->ftl_bdev_dev);
698 : :
699 : 11 : return action;
700 : 0 : error:
701 : 0 : bdev_ftl_action_finish(action);
702 : 0 : return NULL;
703 : : }
704 : :
705 : : static void
706 : 10 : bdev_ftl_action_finish_cb(void *cb_arg, int status)
707 : : {
708 : 10 : struct bdev_ftl_action *action = cb_arg;
709 : :
710 : 10 : action->rc = status;
711 : 10 : bdev_ftl_action_finish(action);
712 : 10 : }
713 : :
714 : : static void *
715 : 6 : bdev_ftl_action_ctx(struct bdev_ftl_action *action, size_t size)
716 : : {
717 [ - + ]: 6 : assert(action->ctx_size);
718 [ - + ]: 6 : assert(size == action->ctx_size);
719 : 6 : return action->ctx;
720 : : }
|