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