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 0 : bdev_ftl_get_ctx_size(void)
60 : {
61 0 : 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 0 : SPDK_BDEV_MODULE_REGISTER(ftl, &g_ftl_if)
73 :
74 : static void
75 0 : bdev_ftl_free(struct ftl_bdev *ftl_bdev)
76 : {
77 0 : spdk_bdev_close(ftl_bdev->base_bdev_desc);
78 0 : spdk_bdev_close(ftl_bdev->cache_bdev_desc);
79 0 : free(ftl_bdev->bdev.name);
80 0 : free(ftl_bdev);
81 0 : }
82 :
83 : static void
84 0 : bdev_ftl_dev_free_cb(void *ctx, int status)
85 : {
86 0 : struct ftl_bdev *ftl_bdev = ctx;
87 :
88 0 : spdk_bdev_destruct_done(&ftl_bdev->bdev, status);
89 0 : bdev_ftl_free(ftl_bdev);
90 0 : }
91 :
92 : static int
93 0 : bdev_ftl_destruct(void *ctx)
94 : {
95 0 : struct ftl_bdev *ftl_bdev = ctx;
96 :
97 0 : 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 0 : return 1;
101 : }
102 :
103 : static void
104 0 : bdev_ftl_cb(void *arg, int rc)
105 : {
106 0 : struct spdk_bdev_io *bdev_io = arg;
107 : enum spdk_bdev_io_status status;
108 :
109 0 : switch (rc) {
110 0 : case 0:
111 0 : status = SPDK_BDEV_IO_STATUS_SUCCESS;
112 0 : 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 0 : spdk_bdev_io_complete(bdev_io, status);
123 0 : }
124 :
125 : static void
126 0 : 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 0 : ftl_bdev = bdev_io->bdev->ctxt;
133 :
134 0 : if (!success) {
135 0 : spdk_bdev_io_complete(bdev_io, SPDK_BDEV_IO_STATUS_FAILED);
136 0 : return;
137 : }
138 :
139 0 : 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 0 : bdev_io->u.bdev.iovs, bdev_io->u.bdev.iovcnt, bdev_ftl_cb, bdev_io);
144 :
145 0 : if (spdk_unlikely(rc != 0)) {
146 0 : bdev_ftl_cb(bdev_io, rc);
147 : }
148 : }
149 :
150 : static int
151 0 : _bdev_ftl_submit_request(struct spdk_io_channel *ch, struct spdk_bdev_io *bdev_io)
152 : {
153 0 : struct ftl_bdev *ftl_bdev = (struct ftl_bdev *)bdev_io->bdev->ctxt;
154 :
155 0 : switch (bdev_io->type) {
156 0 : case SPDK_BDEV_IO_TYPE_READ:
157 0 : spdk_bdev_io_get_buf(bdev_io, bdev_ftl_get_buf_cb,
158 0 : bdev_io->u.bdev.num_blocks * bdev_io->bdev->blocklen);
159 0 : return 0;
160 :
161 0 : case SPDK_BDEV_IO_TYPE_WRITE:
162 0 : 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 0 : 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 0 : bdev_ftl_submit_request(struct spdk_io_channel *ch, struct spdk_bdev_io *bdev_io)
181 : {
182 0 : int rc = _bdev_ftl_submit_request(ch, bdev_io);
183 :
184 0 : if (spdk_unlikely(rc != 0)) {
185 0 : bdev_ftl_cb(bdev_io, rc);
186 : }
187 0 : }
188 :
189 : static bool
190 0 : bdev_ftl_io_type_supported(void *ctx, enum spdk_bdev_io_type io_type)
191 : {
192 0 : switch (io_type) {
193 0 : 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 0 : return true;
198 0 : default:
199 0 : return false;
200 : }
201 : }
202 :
203 : static struct spdk_io_channel *
204 0 : bdev_ftl_get_io_channel(void *ctx)
205 : {
206 0 : struct ftl_bdev *ftl_bdev = ctx;
207 :
208 0 : return spdk_ftl_get_io_channel(ftl_bdev->dev);
209 : }
210 :
211 : static void
212 0 : bdev_ftl_write_config_json(struct spdk_bdev *bdev, struct spdk_json_write_ctx *w)
213 : {
214 0 : struct ftl_bdev *ftl_bdev = bdev->ctxt;
215 0 : struct spdk_ftl_conf conf;
216 :
217 0 : spdk_ftl_dev_get_conf(ftl_bdev->dev, &conf, sizeof(conf));
218 :
219 0 : spdk_json_write_object_begin(w);
220 :
221 0 : spdk_json_write_named_string(w, "method", "bdev_ftl_create");
222 :
223 0 : spdk_json_write_named_object_begin(w, "params");
224 0 : spdk_json_write_named_string(w, "name", ftl_bdev->bdev.name);
225 :
226 0 : spdk_json_write_named_uint64(w, "overprovisioning", conf.overprovisioning);
227 0 : spdk_json_write_named_uint64(w, "l2p_dram_limit", conf.l2p_dram_limit);
228 :
229 0 : if (conf.core_mask) {
230 0 : spdk_json_write_named_string(w, "core_mask", conf.core_mask);
231 : }
232 :
233 0 : spdk_json_write_named_uuid(w, "uuid", &conf.uuid);
234 :
235 0 : spdk_json_write_named_bool(w, "fast_shutdown", conf.fast_shutdown);
236 :
237 0 : spdk_json_write_named_string(w, "base_bdev", conf.base_bdev);
238 :
239 0 : if (conf.cache_bdev) {
240 0 : spdk_json_write_named_string(w, "cache", conf.cache_bdev);
241 : }
242 :
243 0 : spdk_json_write_object_end(w);
244 0 : spdk_json_write_object_end(w);
245 0 : }
246 :
247 : static int
248 0 : bdev_ftl_dump_info_json(void *ctx, struct spdk_json_write_ctx *w)
249 : {
250 0 : struct ftl_bdev *ftl_bdev = ctx;
251 0 : struct spdk_ftl_attrs attrs;
252 0 : struct spdk_ftl_conf conf;
253 :
254 0 : spdk_ftl_dev_get_attrs(ftl_bdev->dev, &attrs, sizeof(attrs));
255 0 : spdk_ftl_dev_get_conf(ftl_bdev->dev, &conf, sizeof(conf));
256 :
257 0 : spdk_json_write_named_object_begin(w, "ftl");
258 :
259 0 : spdk_json_write_named_string(w, "base_bdev", conf.base_bdev);
260 :
261 0 : if (conf.cache_bdev) {
262 0 : spdk_json_write_named_string(w, "cache", conf.cache_bdev);
263 : }
264 :
265 : /* ftl */
266 0 : spdk_json_write_object_end(w);
267 :
268 0 : 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 0 : bdev_ftl_create_cb(struct spdk_ftl_dev *dev, void *ctx, int status)
307 : {
308 0 : struct ftl_bdev *ftl_bdev = ctx;
309 0 : struct ftl_bdev_info info = {};
310 0 : struct spdk_ftl_attrs attrs;
311 0 : struct spdk_ftl_conf conf;
312 0 : ftl_bdev_init_fn init_cb = ftl_bdev->init_cb;
313 0 : void *init_arg = ftl_bdev->init_arg;
314 :
315 0 : 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 0 : spdk_ftl_dev_get_attrs(dev, &attrs, sizeof(attrs));
322 0 : spdk_ftl_dev_get_conf(dev, &conf, sizeof(conf));
323 :
324 0 : ftl_bdev->dev = dev;
325 0 : ftl_bdev->bdev.product_name = "FTL disk";
326 0 : ftl_bdev->bdev.write_cache = 0;
327 0 : ftl_bdev->bdev.blocklen = attrs.block_size;
328 0 : ftl_bdev->bdev.blockcnt = attrs.num_blocks;
329 0 : ftl_bdev->bdev.uuid = conf.uuid;
330 0 : ftl_bdev->bdev.optimal_io_boundary = attrs.optimum_io_size;
331 0 : ftl_bdev->bdev.split_on_optimal_io_boundary = true;
332 :
333 0 : SPDK_DEBUGLOG(bdev_ftl, "Creating bdev %s:\n", ftl_bdev->bdev.name);
334 0 : SPDK_DEBUGLOG(bdev_ftl, "\tblock_len:\t%zu\n", attrs.block_size);
335 0 : SPDK_DEBUGLOG(bdev_ftl, "\tnum_blocks:\t%"PRIu64"\n", attrs.num_blocks);
336 :
337 0 : ftl_bdev->bdev.ctxt = ftl_bdev;
338 0 : ftl_bdev->bdev.fn_table = &ftl_fn_table;
339 0 : ftl_bdev->bdev.module = &g_ftl_if;
340 :
341 0 : status = spdk_bdev_register(&ftl_bdev->bdev);
342 0 : if (status) {
343 0 : ftl_bdev->rc = status;
344 0 : goto error;
345 : }
346 :
347 0 : info.name = ftl_bdev->bdev.name;
348 0 : info.uuid = ftl_bdev->bdev.uuid;
349 :
350 0 : init_cb(&info, init_arg, 0);
351 0 : 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 0 : 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 0 : struct spdk_bdev_desc *base_bdev_desc, *cache_bdev_desc;
404 : int rc;
405 :
406 0 : rc = spdk_bdev_open_ext(conf->base_bdev, false, bdev_ftl_create_bdev_event_cb, NULL,
407 : &base_bdev_desc);
408 0 : if (rc) {
409 0 : return rc;
410 : }
411 0 : rc = spdk_bdev_open_ext(conf->cache_bdev, false, bdev_ftl_create_bdev_event_cb, NULL,
412 : &cache_bdev_desc);
413 0 : if (rc) {
414 0 : spdk_bdev_close(base_bdev_desc);
415 0 : return rc;
416 : }
417 :
418 0 : ftl_bdev = calloc(1, sizeof(*ftl_bdev));
419 0 : 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 0 : ftl_bdev->base_bdev_desc = base_bdev_desc;
427 0 : ftl_bdev->cache_bdev_desc = cache_bdev_desc;
428 :
429 0 : ftl_bdev->bdev.name = strdup(conf->name);
430 0 : if (!ftl_bdev->bdev.name) {
431 0 : rc = -ENOMEM;
432 0 : goto error;
433 : }
434 :
435 0 : ftl_bdev->init_cb = cb;
436 0 : ftl_bdev->init_arg = cb_arg;
437 :
438 0 : rc = spdk_ftl_dev_init(conf, bdev_ftl_create_cb, ftl_bdev);
439 0 : if (rc) {
440 0 : SPDK_ERRLOG("Could not create FTL device\n");
441 0 : goto error;
442 : }
443 :
444 0 : return 0;
445 :
446 0 : error:
447 0 : bdev_ftl_free(ftl_bdev);
448 0 : return rc;
449 : }
450 :
451 : static int
452 0 : bdev_ftl_initialize(void)
453 : {
454 0 : 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 0 : bdev_ftl_delete_bdev(const char *name, bool fast_shutdown, spdk_bdev_unregister_cb cb_fn,
464 : void *cb_arg)
465 : {
466 0 : struct spdk_bdev_desc *ftl_bdev_desc;
467 : struct spdk_bdev *bdev;
468 : struct ftl_bdev *ftl;
469 : int rc;
470 :
471 0 : rc = spdk_bdev_open_ext(name, false, bdev_ftl_event_cb, NULL, &ftl_bdev_desc);
472 :
473 0 : if (rc) {
474 0 : goto not_found;
475 : }
476 :
477 0 : bdev = spdk_bdev_desc_get_bdev(ftl_bdev_desc);
478 :
479 0 : if (bdev->module != &g_ftl_if) {
480 0 : goto bdev_opened;
481 : }
482 :
483 0 : ftl = bdev->ctxt;
484 0 : assert(ftl);
485 0 : spdk_ftl_dev_set_fast_shutdown(ftl->dev, fast_shutdown);
486 0 : spdk_bdev_close(ftl_bdev_desc);
487 :
488 0 : rc = spdk_bdev_unregister_by_name(name, &g_ftl_if, cb_fn, cb_arg);
489 0 : if (rc) {
490 0 : cb_fn(cb_arg, rc);
491 : }
492 :
493 0 : 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 0 : 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 0 : action = bdev_ftl_action_start(name, 0, cb_fn, cb_arg);
507 0 : 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 0 : action->rc = spdk_ftl_unmap(action->ftl_bdev_dev->dev, NULL, NULL, lba, num_blocks,
513 : bdev_ftl_action_finish_cb, action);
514 0 : if (action->rc) {
515 0 : bdev_ftl_action_finish(action);
516 : }
517 : }
518 :
519 : static void
520 0 : bdev_ftl_get_stats_cb(struct ftl_stats *stats, void *cb_arg)
521 : {
522 0 : struct bdev_ftl_action *action = cb_arg;
523 :
524 0 : bdev_ftl_action_finish(action);
525 0 : }
526 :
527 : void
528 0 : 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 0 : action = bdev_ftl_action_start(name, 0, cb, ftl_stats_ctx);
533 0 : if (!action) {
534 0 : return;
535 : }
536 0 : ftl_stats_ctx->ftl_bdev_desc = action->ftl_bdev_desc;
537 0 : action->rc = spdk_ftl_get_stats(action->ftl_bdev_dev->dev, &ftl_stats_ctx->ftl_stats,
538 : bdev_ftl_get_stats_cb, action);
539 0 : if (action->rc) {
540 0 : bdev_ftl_action_finish(action);
541 : }
542 : }
543 :
544 : void
545 0 : 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 0 : action = bdev_ftl_action_start(name, 0, cb_fn, request);
550 0 : if (!action) {
551 0 : return;
552 : }
553 :
554 0 : action->rc = spdk_ftl_get_properties(action->ftl_bdev_dev->dev, request,
555 : bdev_ftl_action_finish_cb, action);
556 0 : 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 0 : bdev_ftl_set_property_cb(void *cb_arg, int status)
568 : {
569 0 : struct bdev_ftl_action *action = cb_arg;
570 0 : struct bdev_ftl_set_property_args *args = bdev_ftl_action_ctx(action, sizeof(*args));
571 :
572 0 : free(args->property);
573 0 : free(args->value);
574 0 : args->property = NULL;
575 0 : args->value = NULL;
576 0 : bdev_ftl_action_finish_cb(cb_arg, status);
577 0 : }
578 :
579 : void
580 0 : 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 0 : action = bdev_ftl_action_start(name, sizeof(*args), cb_fn, cb_arg);
587 0 : if (!action) {
588 0 : return;
589 : }
590 :
591 0 : args = bdev_ftl_action_ctx(action, sizeof(*args));
592 0 : args->property = strdup(property);
593 0 : args->value = strdup(value);
594 :
595 0 : 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 0 : action->rc = spdk_ftl_set_property(action->ftl_bdev_dev->dev,
604 0 : args->property, args->value, strlen(args->value) + 1,
605 : bdev_ftl_set_property_cb, action);
606 0 : if (action->rc) {
607 0 : bdev_ftl_action_finish(action);
608 : }
609 : }
610 :
611 : static void
612 0 : bdev_ftl_finish(void)
613 : {
614 0 : spdk_ftl_fini();
615 0 : }
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 0 : bdev_ftl_examine(struct spdk_bdev *bdev)
633 : {
634 : struct ftl_deferred_init *opts;
635 : int rc;
636 :
637 0 : 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 0 : spdk_bdev_module_examine_done(&g_ftl_if);
653 : }
654 :
655 0 : SPDK_LOG_REGISTER_COMPONENT(bdev_ftl)
656 :
657 : /*
658 : * Generic function to execute an action on the FTL bdev
659 : */
660 : static void
661 0 : bdev_ftl_action_finish(struct bdev_ftl_action *action)
662 : {
663 0 : action->cb_fn(action->cb_arg, action->rc);
664 0 : if (action->ftl_bdev_desc) {
665 0 : spdk_bdev_close(action->ftl_bdev_desc);
666 : }
667 0 : free(action);
668 0 : }
669 :
670 : static struct bdev_ftl_action *
671 0 : 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 0 : struct bdev_ftl_action *action = calloc(1, sizeof(*action) + ctx_size);
675 :
676 0 : if (NULL == action) {
677 0 : cb_fn(cb_arg, -ENOMEM);
678 0 : return NULL;
679 : }
680 0 : action->cb_arg = cb_arg;
681 0 : action->cb_fn = cb_fn;
682 0 : action->ctx_size = ctx_size;
683 :
684 0 : action->rc = spdk_bdev_open_ext(bdev_name, false, bdev_ftl_event_cb, NULL, &action->ftl_bdev_desc);
685 0 : if (action->rc) {
686 0 : goto error;
687 : }
688 :
689 0 : bdev = spdk_bdev_desc_get_bdev(action->ftl_bdev_desc);
690 0 : if (bdev->module != &g_ftl_if) {
691 0 : action->rc = -ENODEV;
692 0 : goto error;
693 : }
694 :
695 0 : action->ftl_bdev_dev = bdev->ctxt;
696 0 : assert(action->ftl_bdev_dev);
697 :
698 0 : return action;
699 0 : error:
700 0 : bdev_ftl_action_finish(action);
701 0 : return NULL;
702 : }
703 :
704 : static void
705 0 : bdev_ftl_action_finish_cb(void *cb_arg, int status)
706 : {
707 0 : struct bdev_ftl_action *action = cb_arg;
708 :
709 0 : action->rc = status;
710 0 : bdev_ftl_action_finish(action);
711 0 : }
712 :
713 : static void *
714 0 : bdev_ftl_action_ctx(struct bdev_ftl_action *action, size_t size)
715 : {
716 0 : assert(action->ctx_size);
717 0 : assert(size == action->ctx_size);
718 0 : return action->ctx;
719 : }
|