Line data Source code
1 : /* SPDX-License-Identifier: BSD-3-Clause
2 : * Copyright (c) 2024 NVIDIA CORPORATION & AFFILIATES. All rights reserved.
3 : */
4 :
5 : #include "spdk/stdinc.h"
6 : #include "spdk/fsdev.h"
7 : #include "spdk/config.h"
8 : #include "spdk/env.h"
9 : #include "spdk/likely.h"
10 : #include "spdk/queue.h"
11 : #include "spdk/util.h"
12 : #include "spdk/notify.h"
13 : #include "spdk/fsdev_module.h"
14 : #include "spdk/log.h"
15 : #include "spdk/string.h"
16 : #include "fsdev_internal.h"
17 :
18 : #define SPDK_FSDEV_IO_POOL_SIZE (64 * 1024 - 1)
19 : #define SPDK_FSDEV_IO_CACHE_SIZE 256
20 :
21 : static struct spdk_fsdev_opts g_fsdev_opts = {
22 : .fsdev_io_pool_size = SPDK_FSDEV_IO_POOL_SIZE,
23 : .fsdev_io_cache_size = SPDK_FSDEV_IO_CACHE_SIZE,
24 : };
25 :
26 : TAILQ_HEAD(spdk_fsdev_list, spdk_fsdev);
27 :
28 : RB_HEAD(fsdev_name_tree, spdk_fsdev_name);
29 :
30 : static int
31 39 : fsdev_name_cmp(struct spdk_fsdev_name *name1, struct spdk_fsdev_name *name2)
32 : {
33 39 : return strcmp(name1->name, name2->name);
34 : }
35 :
36 156 : RB_GENERATE_STATIC(fsdev_name_tree, spdk_fsdev_name, node, fsdev_name_cmp);
37 :
38 : struct spdk_fsdev_mgr {
39 : struct spdk_mempool *fsdev_io_pool;
40 :
41 : TAILQ_HEAD(fsdev_module_list, spdk_fsdev_module) fsdev_modules;
42 :
43 : struct spdk_fsdev_list fsdevs;
44 : struct fsdev_name_tree fsdev_names;
45 :
46 : bool init_complete;
47 : bool module_init_complete;
48 :
49 : struct spdk_spinlock spinlock;
50 : };
51 :
52 : static struct spdk_fsdev_mgr g_fsdev_mgr = {
53 : .fsdev_modules = TAILQ_HEAD_INITIALIZER(g_fsdev_mgr.fsdev_modules),
54 : .fsdevs = TAILQ_HEAD_INITIALIZER(g_fsdev_mgr.fsdevs),
55 : .fsdev_names = RB_INITIALIZER(g_fsdev_mgr.fsdev_names),
56 : .init_complete = false,
57 : .module_init_complete = false,
58 : };
59 :
60 : static void
61 : __attribute__((constructor))
62 1 : _fsdev_init(void)
63 : {
64 1 : spdk_spin_init(&g_fsdev_mgr.spinlock);
65 1 : }
66 :
67 :
68 : static spdk_fsdev_init_cb g_init_cb_fn = NULL;
69 : static void *g_init_cb_arg = NULL;
70 :
71 : static spdk_fsdev_fini_cb g_fini_cb_fn = NULL;
72 : static void *g_fini_cb_arg = NULL;
73 : static struct spdk_thread *g_fini_thread = NULL;
74 :
75 : struct spdk_fsdev_mgmt_channel {
76 : /*
77 : * Each thread keeps a cache of fsdev_io - this allows
78 : * fsdev threads which are *not* DPDK threads to still
79 : * benefit from a per-thread fsdev_io cache. Without
80 : * this, non-DPDK threads fetching from the mempool
81 : * incur a cmpxchg on get and put.
82 : */
83 : fsdev_io_stailq_t per_thread_cache;
84 : uint32_t per_thread_cache_count;
85 : uint32_t fsdev_io_cache_size;
86 :
87 : TAILQ_HEAD(, spdk_fsdev_shared_resource) shared_resources;
88 : };
89 :
90 : /*
91 : * Per-module (or per-io_device) data. Multiple fsdevs built on the same io_device
92 : * will queue here their IO that awaits retry. It makes it possible to retry sending
93 : * IO to one fsdev after IO from other fsdev completes.
94 : */
95 : struct spdk_fsdev_shared_resource {
96 : /* The fsdev management channel */
97 : struct spdk_fsdev_mgmt_channel *mgmt_ch;
98 :
99 : /*
100 : * Count of I/O submitted to fsdev module and waiting for completion.
101 : * Incremented before submit_request() is called on an spdk_fsdev_io.
102 : */
103 : uint64_t io_outstanding;
104 :
105 : /* I/O channel allocated by a fsdev module */
106 : struct spdk_io_channel *shared_ch;
107 :
108 : /* Refcount of fsdev channels using this resource */
109 : uint32_t ref;
110 :
111 : TAILQ_ENTRY(spdk_fsdev_shared_resource) link;
112 : };
113 :
114 : struct spdk_fsdev_channel {
115 : struct spdk_fsdev *fsdev;
116 :
117 : /* The channel for the underlying device */
118 : struct spdk_io_channel *channel;
119 :
120 : /* Per io_device per thread data */
121 : struct spdk_fsdev_shared_resource *shared_resource;
122 :
123 : /*
124 : * Count of I/O submitted to the underlying dev module through this channel
125 : * and waiting for completion.
126 : */
127 : uint64_t io_outstanding;
128 :
129 : /*
130 : * List of all submitted I/Os.
131 : */
132 : fsdev_io_tailq_t io_submitted;
133 : };
134 :
135 : struct spdk_fsdev_desc {
136 : struct spdk_fsdev *fsdev;
137 : struct spdk_thread *thread;
138 : struct {
139 : spdk_fsdev_event_cb_t event_fn;
140 : void *ctx;
141 : } callback;
142 : bool closed;
143 : struct spdk_spinlock spinlock;
144 : uint32_t refs;
145 : TAILQ_ENTRY(spdk_fsdev_desc) link;
146 : };
147 :
148 : #define __fsdev_to_io_dev(fsdev) (((char *)fsdev) + 1)
149 : #define __fsdev_from_io_dev(io_dev) ((struct spdk_fsdev *)(((char *)io_dev) - 1))
150 : #define __io_ch_to_fsdev_mgmt_ch(io_ch) ((struct spdk_fsdev_mgmt_channel *)spdk_io_channel_get_ctx(io_ch))
151 :
152 : static struct spdk_fsdev *
153 39 : fsdev_get_by_name(const char *fsdev_name)
154 : {
155 : struct spdk_fsdev_name find;
156 : struct spdk_fsdev_name *res;
157 :
158 39 : find.name = (char *)fsdev_name;
159 39 : res = RB_FIND(fsdev_name_tree, &g_fsdev_mgr.fsdev_names, &find);
160 39 : if (res != NULL) {
161 39 : return res->fsdev;
162 : }
163 :
164 0 : return NULL;
165 : }
166 :
167 : static int
168 1 : fsdev_module_get_max_ctx_size(void)
169 : {
170 : struct spdk_fsdev_module *fsdev_module;
171 1 : int max_fsdev_module_size = 0;
172 :
173 2 : TAILQ_FOREACH(fsdev_module, &g_fsdev_mgr.fsdev_modules, internal.tailq) {
174 1 : if (fsdev_module->get_ctx_size && fsdev_module->get_ctx_size() > max_fsdev_module_size) {
175 0 : max_fsdev_module_size = fsdev_module->get_ctx_size();
176 : }
177 : }
178 :
179 1 : return max_fsdev_module_size;
180 : }
181 :
182 : void
183 0 : spdk_fsdev_subsystem_config_json(struct spdk_json_write_ctx *w)
184 : {
185 : struct spdk_fsdev_module *fsdev_module;
186 : struct spdk_fsdev *fsdev;
187 :
188 0 : assert(w != NULL);
189 :
190 0 : spdk_json_write_array_begin(w);
191 :
192 0 : spdk_json_write_object_begin(w);
193 0 : spdk_json_write_named_string(w, "method", "fsdev_set_opts");
194 0 : spdk_json_write_named_object_begin(w, "params");
195 0 : spdk_json_write_named_uint32(w, "fsdev_io_pool_size", g_fsdev_opts.fsdev_io_pool_size);
196 0 : spdk_json_write_named_uint32(w, "fsdev_io_cache_size", g_fsdev_opts.fsdev_io_cache_size);
197 0 : spdk_json_write_object_end(w); /* params */
198 0 : spdk_json_write_object_end(w);
199 :
200 0 : TAILQ_FOREACH(fsdev_module, &g_fsdev_mgr.fsdev_modules, internal.tailq) {
201 0 : if (fsdev_module->config_json) {
202 0 : fsdev_module->config_json(w);
203 : }
204 : }
205 :
206 0 : spdk_spin_lock(&g_fsdev_mgr.spinlock);
207 :
208 0 : TAILQ_FOREACH(fsdev, &g_fsdev_mgr.fsdevs, internal.link) {
209 0 : if (fsdev->fn_table->write_config_json) {
210 0 : fsdev->fn_table->write_config_json(fsdev, w);
211 : }
212 : }
213 :
214 0 : spdk_spin_unlock(&g_fsdev_mgr.spinlock);
215 0 : spdk_json_write_array_end(w);
216 0 : }
217 :
218 : static void
219 38 : fsdev_mgmt_channel_destroy(void *io_device, void *ctx_buf)
220 : {
221 38 : struct spdk_fsdev_mgmt_channel *ch = ctx_buf;
222 : struct spdk_fsdev_io *fsdev_io;
223 :
224 38 : if (!TAILQ_EMPTY(&ch->shared_resources)) {
225 0 : SPDK_ERRLOG("Module channel list wasn't empty on mgmt channel free\n");
226 : }
227 :
228 19494 : while (!STAILQ_EMPTY(&ch->per_thread_cache)) {
229 19456 : fsdev_io = STAILQ_FIRST(&ch->per_thread_cache);
230 19456 : STAILQ_REMOVE_HEAD(&ch->per_thread_cache, internal.buf_link);
231 19456 : ch->per_thread_cache_count--;
232 19456 : spdk_mempool_put(g_fsdev_mgr.fsdev_io_pool, (void *)fsdev_io);
233 : }
234 :
235 38 : assert(ch->per_thread_cache_count == 0);
236 38 : return;
237 : }
238 :
239 : static int
240 38 : fsdev_mgmt_channel_create(void *io_device, void *ctx_buf)
241 : {
242 38 : struct spdk_fsdev_mgmt_channel *ch = ctx_buf;
243 : struct spdk_fsdev_io *fsdev_io;
244 : uint32_t i;
245 :
246 38 : STAILQ_INIT(&ch->per_thread_cache);
247 38 : ch->fsdev_io_cache_size = g_fsdev_opts.fsdev_io_cache_size;
248 :
249 : /* Pre-populate fsdev_io cache to ensure this thread cannot be starved. */
250 38 : ch->per_thread_cache_count = 0;
251 19494 : for (i = 0; i < ch->fsdev_io_cache_size; i++) {
252 19456 : fsdev_io = spdk_mempool_get(g_fsdev_mgr.fsdev_io_pool);
253 19456 : if (fsdev_io == NULL) {
254 0 : SPDK_ERRLOG("You need to increase fsdev_io_pool_size using fsdev_set_options RPC.\n");
255 0 : assert(false);
256 : fsdev_mgmt_channel_destroy(io_device, ctx_buf);
257 : return -1;
258 : }
259 19456 : ch->per_thread_cache_count++;
260 19456 : STAILQ_INSERT_HEAD(&ch->per_thread_cache, fsdev_io, internal.buf_link);
261 : }
262 :
263 38 : TAILQ_INIT(&ch->shared_resources);
264 38 : return 0;
265 : }
266 :
267 : static void
268 1 : fsdev_init_complete(int rc)
269 : {
270 1 : spdk_fsdev_init_cb cb_fn = g_init_cb_fn;
271 1 : void *cb_arg = g_init_cb_arg;
272 :
273 1 : g_fsdev_mgr.init_complete = true;
274 1 : g_init_cb_fn = NULL;
275 1 : g_init_cb_arg = NULL;
276 :
277 1 : cb_fn(cb_arg, rc);
278 1 : }
279 :
280 : static void
281 0 : fsdev_init_failed(void *cb_arg)
282 : {
283 0 : fsdev_init_complete(-1);
284 0 : }
285 :
286 : static int
287 1 : fsdev_modules_init(void)
288 : {
289 : struct spdk_fsdev_module *module;
290 1 : int rc = 0;
291 :
292 2 : TAILQ_FOREACH(module, &g_fsdev_mgr.fsdev_modules, internal.tailq) {
293 1 : rc = module->module_init();
294 1 : if (rc != 0) {
295 0 : spdk_thread_send_msg(spdk_get_thread(), fsdev_init_failed, module);
296 0 : return rc;
297 : }
298 : }
299 :
300 1 : return 0;
301 : }
302 :
303 : void
304 1 : spdk_fsdev_initialize(spdk_fsdev_init_cb cb_fn, void *cb_arg)
305 : {
306 1 : int rc = 0;
307 : char mempool_name[32];
308 :
309 1 : assert(cb_fn != NULL);
310 :
311 1 : g_init_cb_fn = cb_fn;
312 1 : g_init_cb_arg = cb_arg;
313 :
314 1 : spdk_notify_type_register("fsdev_register");
315 1 : spdk_notify_type_register("fsdev_unregister");
316 :
317 1 : snprintf(mempool_name, sizeof(mempool_name), "fsdev_io_%d", getpid());
318 :
319 2 : g_fsdev_mgr.fsdev_io_pool = spdk_mempool_create(mempool_name,
320 1 : g_fsdev_opts.fsdev_io_pool_size,
321 : sizeof(struct spdk_fsdev_io) +
322 1 : fsdev_module_get_max_ctx_size(),
323 : 0,
324 : SPDK_ENV_NUMA_ID_ANY);
325 :
326 1 : if (g_fsdev_mgr.fsdev_io_pool == NULL) {
327 0 : SPDK_ERRLOG("Could not allocate spdk_fsdev_io pool\n");
328 0 : fsdev_init_complete(-1);
329 0 : return;
330 : }
331 :
332 1 : spdk_io_device_register(&g_fsdev_mgr, fsdev_mgmt_channel_create,
333 : fsdev_mgmt_channel_destroy,
334 : sizeof(struct spdk_fsdev_mgmt_channel),
335 : "fsdev_mgr");
336 :
337 1 : rc = fsdev_modules_init();
338 1 : g_fsdev_mgr.module_init_complete = true;
339 1 : if (rc != 0) {
340 0 : SPDK_ERRLOG("fsdev modules init failed\n");
341 0 : return;
342 : }
343 :
344 1 : fsdev_init_complete(0);
345 : }
346 :
347 : static void
348 1 : fsdev_mgr_unregister_cb(void *io_device)
349 : {
350 1 : spdk_fsdev_fini_cb cb_fn = g_fini_cb_fn;
351 :
352 1 : if (g_fsdev_mgr.fsdev_io_pool) {
353 1 : if (spdk_mempool_count(g_fsdev_mgr.fsdev_io_pool) != g_fsdev_opts.fsdev_io_pool_size) {
354 1 : SPDK_ERRLOG("fsdev IO pool count is %zu but should be %u\n",
355 : spdk_mempool_count(g_fsdev_mgr.fsdev_io_pool),
356 : g_fsdev_opts.fsdev_io_pool_size);
357 : }
358 :
359 1 : spdk_mempool_free(g_fsdev_mgr.fsdev_io_pool);
360 : }
361 :
362 1 : cb_fn(g_fini_cb_arg);
363 1 : g_fini_cb_fn = NULL;
364 1 : g_fini_cb_arg = NULL;
365 1 : g_fsdev_mgr.init_complete = false;
366 1 : g_fsdev_mgr.module_init_complete = false;
367 1 : }
368 :
369 : static void
370 1 : fsdev_module_fini_iter(void *arg)
371 : {
372 : struct spdk_fsdev_module *fsdev_module;
373 :
374 : /* FIXME: Handling initialization failures is broken now,
375 : * so we won't even try cleaning up after successfully
376 : * initialized modules. if module_init_complete is false,
377 : * just call spdk_fsdev_mgr_unregister_cb
378 : */
379 1 : if (!g_fsdev_mgr.module_init_complete) {
380 0 : fsdev_mgr_unregister_cb(NULL);
381 0 : return;
382 : }
383 :
384 : /* Start iterating from the last touched module */
385 1 : fsdev_module = TAILQ_LAST(&g_fsdev_mgr.fsdev_modules, fsdev_module_list);
386 2 : while (fsdev_module) {
387 1 : if (fsdev_module->module_fini) {
388 1 : fsdev_module->module_fini();
389 : }
390 :
391 1 : fsdev_module = TAILQ_PREV(fsdev_module, fsdev_module_list,
392 : internal.tailq);
393 : }
394 :
395 1 : spdk_io_device_unregister(&g_fsdev_mgr, fsdev_mgr_unregister_cb);
396 : }
397 :
398 : static void
399 1 : fsdev_finish_unregister_fsdevs_iter(void *cb_arg, int fsdeverrno)
400 : {
401 1 : struct spdk_fsdev *fsdev = cb_arg;
402 :
403 1 : if (fsdeverrno && fsdev) {
404 0 : SPDK_WARNLOG("Unable to unregister fsdev '%s' during spdk_fsdev_finish()\n",
405 : fsdev->name);
406 :
407 : /*
408 : * Since the call to spdk_fsdev_unregister() failed, we have no way to free this
409 : * fsdev; try to continue by manually removing this fsdev from the list and continue
410 : * with the next fsdev in the list.
411 : */
412 0 : TAILQ_REMOVE(&g_fsdev_mgr.fsdevs, fsdev, internal.link);
413 : }
414 :
415 1 : fsdev = TAILQ_FIRST(&g_fsdev_mgr.fsdevs);
416 1 : if (!fsdev) {
417 1 : SPDK_DEBUGLOG(fsdev, "Done unregistering fsdevs\n");
418 : /*
419 : * Fsdev module finish need to be deferred as we might be in the middle of some context
420 : * that will use this fsdev (or private fsdev driver ctx data)
421 : * after returning.
422 : */
423 1 : spdk_thread_send_msg(spdk_get_thread(), fsdev_module_fini_iter, NULL);
424 1 : return;
425 : }
426 :
427 0 : SPDK_DEBUGLOG(fsdev, "Unregistering fsdev '%s'\n", fsdev->name);
428 0 : spdk_fsdev_unregister(fsdev, fsdev_finish_unregister_fsdevs_iter, fsdev);
429 0 : return;
430 : }
431 :
432 : void
433 1 : spdk_fsdev_finish(spdk_fsdev_fini_cb cb_fn, void *cb_arg)
434 : {
435 1 : assert(cb_fn != NULL);
436 1 : g_fini_thread = spdk_get_thread();
437 1 : g_fini_cb_fn = cb_fn;
438 1 : g_fini_cb_arg = cb_arg;
439 1 : fsdev_finish_unregister_fsdevs_iter(NULL, 0);
440 1 : }
441 :
442 : struct spdk_fsdev_io *
443 37 : fsdev_channel_get_io(struct spdk_fsdev_channel *channel)
444 : {
445 37 : struct spdk_fsdev_mgmt_channel *ch = channel->shared_resource->mgmt_ch;
446 : struct spdk_fsdev_io *fsdev_io;
447 :
448 37 : if (ch->per_thread_cache_count > 0) {
449 37 : fsdev_io = STAILQ_FIRST(&ch->per_thread_cache);
450 37 : STAILQ_REMOVE_HEAD(&ch->per_thread_cache, internal.buf_link);
451 37 : ch->per_thread_cache_count--;
452 : } else {
453 0 : fsdev_io = spdk_mempool_get(g_fsdev_mgr.fsdev_io_pool);
454 : }
455 :
456 37 : return fsdev_io;
457 : }
458 :
459 : void
460 37 : spdk_fsdev_free_io(struct spdk_fsdev_io *fsdev_io)
461 : {
462 : struct spdk_fsdev_mgmt_channel *ch;
463 :
464 37 : assert(fsdev_io != NULL);
465 :
466 37 : ch = fsdev_io->internal.ch->shared_resource->mgmt_ch;
467 :
468 37 : if (ch->per_thread_cache_count < ch->fsdev_io_cache_size) {
469 37 : ch->per_thread_cache_count++;
470 37 : STAILQ_INSERT_HEAD(&ch->per_thread_cache, fsdev_io, internal.buf_link);
471 : } else {
472 0 : spdk_mempool_put(g_fsdev_mgr.fsdev_io_pool, (void *)fsdev_io);
473 : }
474 37 : }
475 :
476 : void
477 37 : fsdev_io_submit(struct spdk_fsdev_io *fsdev_io)
478 : {
479 37 : struct spdk_fsdev *fsdev = fsdev_io->fsdev;
480 37 : struct spdk_fsdev_channel *ch = fsdev_io->internal.ch;
481 37 : struct spdk_fsdev_shared_resource *shared_resource = ch->shared_resource;
482 :
483 37 : TAILQ_INSERT_TAIL(&ch->io_submitted, fsdev_io, internal.ch_link);
484 :
485 37 : ch->io_outstanding++;
486 37 : shared_resource->io_outstanding++;
487 37 : fsdev_io->internal.in_submit_request = true;
488 37 : fsdev->fn_table->submit_request(ch->channel, fsdev_io);
489 37 : fsdev_io->internal.in_submit_request = false;
490 37 : }
491 :
492 : static void
493 38 : fsdev_channel_destroy_resource(struct spdk_fsdev_channel *ch)
494 : {
495 : struct spdk_fsdev_shared_resource *shared_resource;
496 :
497 38 : spdk_put_io_channel(ch->channel);
498 :
499 38 : shared_resource = ch->shared_resource;
500 :
501 38 : assert(TAILQ_EMPTY(&ch->io_submitted));
502 38 : assert(ch->io_outstanding == 0);
503 38 : assert(shared_resource->ref > 0);
504 38 : shared_resource->ref--;
505 38 : if (shared_resource->ref == 0) {
506 38 : assert(shared_resource->io_outstanding == 0);
507 38 : TAILQ_REMOVE(&shared_resource->mgmt_ch->shared_resources, shared_resource, link);
508 38 : spdk_put_io_channel(spdk_io_channel_from_ctx(shared_resource->mgmt_ch));
509 38 : free(shared_resource);
510 : }
511 38 : }
512 :
513 : static void
514 39 : fsdev_desc_free(struct spdk_fsdev_desc *desc)
515 : {
516 39 : spdk_spin_destroy(&desc->spinlock);
517 39 : free(desc);
518 39 : }
519 :
520 :
521 : static int
522 38 : fsdev_channel_create(void *io_device, void *ctx_buf)
523 : {
524 38 : struct spdk_fsdev *fsdev = __fsdev_from_io_dev(io_device);
525 38 : struct spdk_fsdev_channel *ch = ctx_buf;
526 : struct spdk_io_channel *mgmt_io_ch;
527 : struct spdk_fsdev_mgmt_channel *mgmt_ch;
528 : struct spdk_fsdev_shared_resource *shared_resource;
529 :
530 38 : ch->fsdev = fsdev;
531 38 : ch->channel = fsdev->fn_table->get_io_channel(fsdev->ctxt);
532 38 : if (!ch->channel) {
533 0 : return -1;
534 : }
535 :
536 38 : mgmt_io_ch = spdk_get_io_channel(&g_fsdev_mgr);
537 38 : if (!mgmt_io_ch) {
538 0 : spdk_put_io_channel(ch->channel);
539 0 : return -1;
540 : }
541 :
542 38 : mgmt_ch = __io_ch_to_fsdev_mgmt_ch(mgmt_io_ch);
543 38 : TAILQ_FOREACH(shared_resource, &mgmt_ch->shared_resources, link) {
544 0 : if (shared_resource->shared_ch == ch->channel) {
545 0 : spdk_put_io_channel(mgmt_io_ch);
546 0 : shared_resource->ref++;
547 0 : break;
548 : }
549 : }
550 :
551 38 : if (shared_resource == NULL) {
552 38 : shared_resource = calloc(1, sizeof(*shared_resource));
553 38 : if (shared_resource == NULL) {
554 0 : spdk_put_io_channel(ch->channel);
555 0 : spdk_put_io_channel(mgmt_io_ch);
556 0 : return -1;
557 : }
558 :
559 38 : shared_resource->mgmt_ch = mgmt_ch;
560 38 : shared_resource->io_outstanding = 0;
561 38 : shared_resource->shared_ch = ch->channel;
562 38 : shared_resource->ref = 1;
563 38 : TAILQ_INSERT_TAIL(&mgmt_ch->shared_resources, shared_resource, link);
564 : }
565 :
566 38 : ch->io_outstanding = 0;
567 38 : ch->shared_resource = shared_resource;
568 38 : TAILQ_INIT(&ch->io_submitted);
569 38 : return 0;
570 : }
571 :
572 : static void
573 38 : fsdev_channel_destroy(void *io_device, void *ctx_buf)
574 : {
575 38 : struct spdk_fsdev_channel *ch = ctx_buf;
576 :
577 38 : SPDK_DEBUGLOG(fsdev, "Destroying channel %p for fsdev %s on thread %p\n",
578 : ch, ch->fsdev->name,
579 : spdk_get_thread());
580 38 : fsdev_channel_destroy_resource(ch);
581 38 : }
582 :
583 : /*
584 : * If the name already exists in the global fsdev name tree, RB_INSERT() returns a pointer
585 : * to it. Hence we do not have to call fsdev_get_by_name() when using this function.
586 : */
587 : static int
588 39 : fsdev_name_add(struct spdk_fsdev_name *fsdev_name, struct spdk_fsdev *fsdev, const char *name)
589 : {
590 : struct spdk_fsdev_name *tmp;
591 :
592 39 : fsdev_name->name = strdup(name);
593 39 : if (fsdev_name->name == NULL) {
594 0 : SPDK_ERRLOG("Unable to allocate fsdev name\n");
595 0 : return -ENOMEM;
596 : }
597 :
598 39 : fsdev_name->fsdev = fsdev;
599 :
600 39 : spdk_spin_lock(&g_fsdev_mgr.spinlock);
601 39 : tmp = RB_INSERT(fsdev_name_tree, &g_fsdev_mgr.fsdev_names, fsdev_name);
602 39 : spdk_spin_unlock(&g_fsdev_mgr.spinlock);
603 39 : if (tmp != NULL) {
604 0 : SPDK_ERRLOG("Fsdev name %s already exists\n", name);
605 0 : free(fsdev_name->name);
606 0 : return -EEXIST;
607 : }
608 :
609 39 : return 0;
610 : }
611 :
612 : static void
613 39 : fsdev_name_del_unsafe(struct spdk_fsdev_name *fsdev_name)
614 : {
615 39 : RB_REMOVE(fsdev_name_tree, &g_fsdev_mgr.fsdev_names, fsdev_name);
616 39 : free(fsdev_name->name);
617 39 : }
618 :
619 : struct spdk_io_channel *
620 38 : spdk_fsdev_get_io_channel(struct spdk_fsdev_desc *desc)
621 : {
622 38 : return spdk_get_io_channel(__fsdev_to_io_dev(spdk_fsdev_desc_get_fsdev(desc)));
623 : }
624 :
625 : int
626 3 : spdk_fsdev_set_opts(const struct spdk_fsdev_opts *opts)
627 : {
628 : uint32_t min_pool_size;
629 :
630 3 : if (!opts) {
631 1 : SPDK_ERRLOG("opts cannot be NULL\n");
632 1 : return -EINVAL;
633 : }
634 :
635 2 : if (!opts->opts_size) {
636 1 : SPDK_ERRLOG("opts_size inside opts cannot be zero value\n");
637 1 : return -EINVAL;
638 : }
639 :
640 : /*
641 : * Add 1 to the thread count to account for the extra mgmt_ch that gets created during subsystem
642 : * initialization. A second mgmt_ch will be created on the same thread when the application starts
643 : * but before the deferred put_io_channel event is executed for the first mgmt_ch.
644 : */
645 1 : min_pool_size = opts->fsdev_io_cache_size * (spdk_thread_get_count() + 1);
646 1 : if (opts->fsdev_io_pool_size < min_pool_size) {
647 0 : SPDK_ERRLOG("fsdev_io_pool_size %" PRIu32 " is not compatible with bdev_io_cache_size %" PRIu32
648 : " and %" PRIu32 " threads\n", opts->fsdev_io_pool_size, opts->fsdev_io_cache_size,
649 : spdk_thread_get_count());
650 0 : SPDK_ERRLOG("fsdev_io_pool_size must be at least %" PRIu32 "\n", min_pool_size);
651 0 : return -EINVAL;
652 : }
653 :
654 : #define SET_FIELD(field) \
655 : if (offsetof(struct spdk_fsdev_opts, field) + sizeof(opts->field) <= opts->opts_size) { \
656 : g_fsdev_opts.field = opts->field; \
657 : } \
658 :
659 1 : SET_FIELD(fsdev_io_pool_size);
660 1 : SET_FIELD(fsdev_io_cache_size);
661 :
662 1 : g_fsdev_opts.opts_size = opts->opts_size;
663 :
664 : #undef SET_FIELD
665 :
666 1 : return 0;
667 : }
668 :
669 : int
670 2 : spdk_fsdev_get_opts(struct spdk_fsdev_opts *opts, size_t opts_size)
671 : {
672 2 : if (!opts) {
673 0 : SPDK_ERRLOG("opts should not be NULL\n");
674 0 : return -EINVAL;
675 : }
676 :
677 2 : if (!opts_size) {
678 0 : SPDK_ERRLOG("opts_size should not be zero value\n");
679 0 : return -EINVAL;
680 : }
681 :
682 2 : opts->opts_size = opts_size;
683 :
684 : #define SET_FIELD(field) \
685 : if (offsetof(struct spdk_fsdev_opts, field) + sizeof(opts->field) <= opts_size) { \
686 : opts->field = g_fsdev_opts.field; \
687 : }
688 :
689 2 : SET_FIELD(fsdev_io_pool_size);
690 2 : SET_FIELD(fsdev_io_cache_size);
691 :
692 : /* Do not remove this statement, you should always update this statement when you adding a new field,
693 : * and do not forget to add the SET_FIELD statement for your added field. */
694 : SPDK_STATIC_ASSERT(sizeof(struct spdk_fsdev_opts) == 12, "Incorrect size");
695 :
696 : #undef SET_FIELD
697 2 : return 0;
698 : }
699 :
700 : int
701 0 : spdk_fsdev_get_memory_domains(struct spdk_fsdev *fsdev, struct spdk_memory_domain **domains,
702 : int array_size)
703 : {
704 0 : if (!fsdev) {
705 0 : return -EINVAL;
706 : }
707 :
708 0 : if (fsdev->fn_table->get_memory_domains) {
709 0 : return fsdev->fn_table->get_memory_domains(fsdev->ctxt, domains, array_size);
710 : }
711 :
712 0 : return 0;
713 : }
714 :
715 : const char *
716 1 : spdk_fsdev_get_module_name(const struct spdk_fsdev *fsdev)
717 : {
718 1 : return fsdev->module->name;
719 : }
720 :
721 : const char *
722 79 : spdk_fsdev_get_name(const struct spdk_fsdev *fsdev)
723 : {
724 79 : return fsdev->name;
725 : }
726 :
727 : static inline void
728 74 : fsdev_io_complete(void *ctx)
729 : {
730 74 : struct spdk_fsdev_io *fsdev_io = ctx;
731 74 : struct spdk_fsdev_channel *fsdev_ch = fsdev_io->internal.ch;
732 :
733 74 : if (spdk_unlikely(fsdev_io->internal.in_submit_request)) {
734 : /*
735 : * Defer completion to avoid potential infinite recursion if the
736 : * user's completion callback issues a new I/O.
737 : */
738 37 : spdk_thread_send_msg(spdk_fsdev_io_get_thread(fsdev_io),
739 : fsdev_io_complete, fsdev_io);
740 37 : return;
741 : }
742 :
743 37 : TAILQ_REMOVE(&fsdev_ch->io_submitted, fsdev_io, internal.ch_link);
744 :
745 37 : assert(fsdev_io->internal.cb_fn != NULL);
746 37 : assert(spdk_get_thread() == spdk_fsdev_io_get_thread(fsdev_io));
747 37 : fsdev_io->internal.cb_fn(fsdev_io, fsdev_io->internal.cb_arg);
748 : }
749 :
750 :
751 : void
752 37 : spdk_fsdev_io_complete(struct spdk_fsdev_io *fsdev_io, int status)
753 : {
754 37 : struct spdk_fsdev_channel *fsdev_ch = fsdev_io->internal.ch;
755 37 : struct spdk_fsdev_shared_resource *shared_resource = fsdev_ch->shared_resource;
756 :
757 37 : assert(status <= 0);
758 37 : fsdev_io->internal.status = status;
759 37 : assert(fsdev_ch->io_outstanding > 0);
760 37 : assert(shared_resource->io_outstanding > 0);
761 37 : fsdev_ch->io_outstanding--;
762 37 : shared_resource->io_outstanding--;
763 37 : fsdev_io_complete(fsdev_io);
764 37 : }
765 :
766 : struct spdk_thread *
767 74 : spdk_fsdev_io_get_thread(struct spdk_fsdev_io *fsdev_io)
768 : {
769 74 : return spdk_io_channel_get_thread(fsdev_io->internal.ch->channel);
770 : }
771 :
772 : struct spdk_io_channel *
773 0 : spdk_fsdev_io_get_io_channel(struct spdk_fsdev_io *fsdev_io)
774 : {
775 0 : return fsdev_io->internal.ch->channel;
776 : }
777 :
778 : static int
779 39 : fsdev_register(struct spdk_fsdev *fsdev)
780 : {
781 : char *fsdev_name;
782 : int ret;
783 :
784 39 : assert(fsdev->module != NULL);
785 :
786 39 : if (!fsdev->name) {
787 0 : SPDK_ERRLOG("Fsdev name is NULL\n");
788 0 : return -EINVAL;
789 : }
790 :
791 39 : if (!strlen(fsdev->name)) {
792 0 : SPDK_ERRLOG("Fsdev name must not be an empty string\n");
793 0 : return -EINVAL;
794 : }
795 :
796 : /* Users often register their own I/O devices using the fsdev name. In
797 : * order to avoid conflicts, prepend fsdev_. */
798 39 : fsdev_name = spdk_sprintf_alloc("fsdev_%s", fsdev->name);
799 39 : if (!fsdev_name) {
800 0 : SPDK_ERRLOG("Unable to allocate memory for internal fsdev name.\n");
801 0 : return -ENOMEM;
802 : }
803 :
804 39 : fsdev->internal.status = SPDK_FSDEV_STATUS_READY;
805 39 : TAILQ_INIT(&fsdev->internal.open_descs);
806 :
807 39 : ret = fsdev_name_add(&fsdev->internal.fsdev_name, fsdev, fsdev->name);
808 39 : if (ret != 0) {
809 0 : free(fsdev_name);
810 0 : return ret;
811 : }
812 :
813 39 : spdk_io_device_register(__fsdev_to_io_dev(fsdev),
814 : fsdev_channel_create, fsdev_channel_destroy,
815 : sizeof(struct spdk_fsdev_channel),
816 : fsdev_name);
817 :
818 39 : free(fsdev_name);
819 :
820 39 : spdk_spin_init(&fsdev->internal.spinlock);
821 :
822 39 : SPDK_DEBUGLOG(fsdev, "Inserting fsdev %s into list\n", fsdev->name);
823 39 : TAILQ_INSERT_TAIL(&g_fsdev_mgr.fsdevs, fsdev, internal.link);
824 39 : return 0;
825 : }
826 :
827 : static void
828 39 : fsdev_destroy_cb(void *io_device)
829 : {
830 : int rc;
831 : struct spdk_fsdev *fsdev;
832 : spdk_fsdev_unregister_cb cb_fn;
833 : void *cb_arg;
834 :
835 39 : fsdev = __fsdev_from_io_dev(io_device);
836 39 : cb_fn = fsdev->internal.unregister_cb;
837 39 : cb_arg = fsdev->internal.unregister_ctx;
838 :
839 39 : spdk_spin_destroy(&fsdev->internal.spinlock);
840 :
841 39 : rc = fsdev->fn_table->destruct(fsdev->ctxt);
842 39 : if (rc < 0) {
843 0 : SPDK_ERRLOG("destruct failed\n");
844 : }
845 39 : if (rc <= 0 && cb_fn != NULL) {
846 39 : cb_fn(cb_arg, rc);
847 : }
848 39 : }
849 :
850 : void
851 0 : spdk_fsdev_destruct_done(struct spdk_fsdev *fsdev, int fsdeverrno)
852 : {
853 0 : if (fsdev->internal.unregister_cb != NULL) {
854 0 : fsdev->internal.unregister_cb(fsdev->internal.unregister_ctx, fsdeverrno);
855 : }
856 0 : }
857 :
858 : static void
859 0 : _remove_notify(void *arg)
860 : {
861 0 : struct spdk_fsdev_desc *desc = arg;
862 :
863 0 : spdk_spin_lock(&desc->spinlock);
864 0 : desc->refs--;
865 :
866 0 : if (!desc->closed) {
867 0 : spdk_spin_unlock(&desc->spinlock);
868 0 : desc->callback.event_fn(SPDK_FSDEV_EVENT_REMOVE, desc->fsdev, desc->callback.ctx);
869 0 : return;
870 0 : } else if (0 == desc->refs) {
871 : /* This descriptor was closed after this remove_notify message was sent.
872 : * spdk_fsdev_close() could not free the descriptor since this message was
873 : * in flight, so we free it now using fsdev_desc_free().
874 : */
875 0 : spdk_spin_unlock(&desc->spinlock);
876 0 : fsdev_desc_free(desc);
877 0 : return;
878 : }
879 0 : spdk_spin_unlock(&desc->spinlock);
880 : }
881 :
882 : /* Must be called while holding g_fsdev_mgr.mutex and fsdev->internal.spinlock.
883 : * returns: 0 - fsdev removed and ready to be destructed.
884 : * -EBUSY - fsdev can't be destructed yet. */
885 : static int
886 39 : fsdev_unregister_unsafe(struct spdk_fsdev *fsdev)
887 : {
888 : struct spdk_fsdev_desc *desc, *tmp;
889 39 : int rc = 0;
890 :
891 : /* Notify each descriptor about hotremoval */
892 39 : TAILQ_FOREACH_SAFE(desc, &fsdev->internal.open_descs, link, tmp) {
893 0 : rc = -EBUSY;
894 0 : spdk_spin_lock(&desc->spinlock);
895 : /*
896 : * Defer invocation of the event_cb to a separate message that will
897 : * run later on its thread. This ensures this context unwinds and
898 : * we don't recursively unregister this fsdev again if the event_cb
899 : * immediately closes its descriptor.
900 : */
901 0 : desc->refs++;
902 0 : spdk_thread_send_msg(desc->thread, _remove_notify, desc);
903 0 : spdk_spin_unlock(&desc->spinlock);
904 : }
905 :
906 : /* If there are no descriptors, proceed removing the fsdev */
907 39 : if (rc == 0) {
908 39 : TAILQ_REMOVE(&g_fsdev_mgr.fsdevs, fsdev, internal.link);
909 39 : SPDK_DEBUGLOG(fsdev, "Removing fsdev %s from list done\n", fsdev->name);
910 39 : fsdev_name_del_unsafe(&fsdev->internal.fsdev_name);
911 39 : spdk_notify_send("fsdev_unregister", spdk_fsdev_get_name(fsdev));
912 : }
913 :
914 39 : return rc;
915 : }
916 :
917 : static void
918 39 : fsdev_unregister(struct spdk_fsdev *fsdev, void *_ctx, int status)
919 : {
920 : int rc;
921 :
922 39 : spdk_spin_lock(&g_fsdev_mgr.spinlock);
923 39 : spdk_spin_lock(&fsdev->internal.spinlock);
924 : /*
925 : * Set the status to REMOVING after completing to abort channels. Otherwise,
926 : * the last spdk_fsdev_close() may call spdk_io_device_unregister() while
927 : * spdk_fsdev_for_each_channel() is executed and spdk_io_device_unregister()
928 : * may fail.
929 : */
930 39 : fsdev->internal.status = SPDK_FSDEV_STATUS_REMOVING;
931 39 : rc = fsdev_unregister_unsafe(fsdev);
932 39 : spdk_spin_unlock(&fsdev->internal.spinlock);
933 39 : spdk_spin_unlock(&g_fsdev_mgr.spinlock);
934 :
935 39 : if (rc == 0) {
936 39 : spdk_io_device_unregister(__fsdev_to_io_dev(fsdev), fsdev_destroy_cb);
937 : }
938 39 : }
939 :
940 : void
941 39 : spdk_fsdev_unregister(struct spdk_fsdev *fsdev, spdk_fsdev_unregister_cb cb_fn, void *cb_arg)
942 : {
943 : struct spdk_thread *thread;
944 :
945 39 : SPDK_DEBUGLOG(fsdev, "Removing fsdev %s from list\n", fsdev->name);
946 :
947 39 : thread = spdk_get_thread();
948 39 : if (!thread) {
949 : /* The user called this from a non-SPDK thread. */
950 0 : if (cb_fn != NULL) {
951 0 : cb_fn(cb_arg, -ENOTSUP);
952 : }
953 0 : return;
954 : }
955 :
956 39 : spdk_spin_lock(&g_fsdev_mgr.spinlock);
957 39 : if (fsdev->internal.status == SPDK_FSDEV_STATUS_UNREGISTERING ||
958 39 : fsdev->internal.status == SPDK_FSDEV_STATUS_REMOVING) {
959 0 : spdk_spin_unlock(&g_fsdev_mgr.spinlock);
960 0 : if (cb_fn) {
961 0 : cb_fn(cb_arg, -EBUSY);
962 : }
963 0 : return;
964 : }
965 :
966 39 : spdk_spin_lock(&fsdev->internal.spinlock);
967 39 : fsdev->internal.status = SPDK_FSDEV_STATUS_UNREGISTERING;
968 39 : fsdev->internal.unregister_cb = cb_fn;
969 39 : fsdev->internal.unregister_ctx = cb_arg;
970 39 : spdk_spin_unlock(&fsdev->internal.spinlock);
971 39 : spdk_spin_unlock(&g_fsdev_mgr.spinlock);
972 :
973 : /* @todo: bdev aborts IOs on all channels here. */
974 39 : fsdev_unregister(fsdev, fsdev, 0);
975 : }
976 :
977 : static void
978 0 : _tmp_fsdev_event_cb(enum spdk_fsdev_event_type type, struct spdk_fsdev *fsdev, void *ctx)
979 : {
980 0 : SPDK_NOTICELOG("Unexpected fsdev event type: %d\n", type);
981 0 : }
982 :
983 : int
984 0 : spdk_fsdev_unregister_by_name(const char *fsdev_name, struct spdk_fsdev_module *module,
985 : spdk_fsdev_unregister_cb cb_fn, void *cb_arg)
986 : {
987 : struct spdk_fsdev_desc *desc;
988 : struct spdk_fsdev *fsdev;
989 : int rc;
990 :
991 0 : rc = spdk_fsdev_open(fsdev_name, _tmp_fsdev_event_cb, NULL, &desc);
992 0 : if (rc != 0) {
993 0 : SPDK_ERRLOG("Failed to open fsdev with name: %s\n", fsdev_name);
994 0 : return rc;
995 : }
996 :
997 0 : fsdev = spdk_fsdev_desc_get_fsdev(desc);
998 :
999 0 : if (fsdev->module != module) {
1000 0 : spdk_fsdev_close(desc);
1001 0 : SPDK_ERRLOG("Fsdev %s was not registered by the specified module.\n",
1002 : fsdev_name);
1003 0 : return -ENODEV;
1004 : }
1005 :
1006 0 : spdk_fsdev_unregister(fsdev, cb_fn, cb_arg);
1007 0 : spdk_fsdev_close(desc);
1008 :
1009 0 : return 0;
1010 : }
1011 :
1012 : static int
1013 39 : fsdev_open(struct spdk_fsdev *fsdev, struct spdk_fsdev_desc *desc)
1014 : {
1015 : struct spdk_thread *thread;
1016 :
1017 39 : thread = spdk_get_thread();
1018 39 : if (!thread) {
1019 0 : SPDK_ERRLOG("Cannot open fsdev from non-SPDK thread.\n");
1020 0 : return -ENOTSUP;
1021 : }
1022 :
1023 39 : SPDK_DEBUGLOG(fsdev, "Opening descriptor %p for fsdev %s on thread %p\n",
1024 : desc, fsdev->name, spdk_get_thread());
1025 :
1026 39 : desc->fsdev = fsdev;
1027 39 : desc->thread = thread;
1028 :
1029 39 : spdk_spin_lock(&fsdev->internal.spinlock);
1030 39 : if (fsdev->internal.status == SPDK_FSDEV_STATUS_UNREGISTERING ||
1031 39 : fsdev->internal.status == SPDK_FSDEV_STATUS_REMOVING) {
1032 0 : spdk_spin_unlock(&fsdev->internal.spinlock);
1033 0 : return -ENODEV;
1034 : }
1035 :
1036 39 : TAILQ_INSERT_TAIL(&fsdev->internal.open_descs, desc, link);
1037 39 : spdk_spin_unlock(&fsdev->internal.spinlock);
1038 39 : return 0;
1039 : }
1040 :
1041 : static int
1042 39 : fsdev_desc_alloc(struct spdk_fsdev *fsdev, spdk_fsdev_event_cb_t event_cb, void *event_ctx,
1043 : struct spdk_fsdev_desc **_desc)
1044 : {
1045 : struct spdk_fsdev_desc *desc;
1046 :
1047 39 : desc = calloc(1, sizeof(*desc));
1048 39 : if (desc == NULL) {
1049 0 : SPDK_ERRLOG("Failed to allocate memory for fsdev descriptor\n");
1050 0 : return -ENOMEM;
1051 : }
1052 :
1053 39 : desc->callback.event_fn = event_cb;
1054 39 : desc->callback.ctx = event_ctx;
1055 39 : spdk_spin_init(&desc->spinlock);
1056 39 : *_desc = desc;
1057 39 : return 0;
1058 : }
1059 :
1060 : int
1061 39 : spdk_fsdev_open(const char *fsdev_name, spdk_fsdev_event_cb_t event_cb, void *event_ctx,
1062 : struct spdk_fsdev_desc **_desc)
1063 : {
1064 : struct spdk_fsdev_desc *desc;
1065 : struct spdk_fsdev *fsdev;
1066 : int rc;
1067 :
1068 39 : if (event_cb == NULL) {
1069 0 : SPDK_ERRLOG("Missing event callback function\n");
1070 0 : return -EINVAL;
1071 : }
1072 :
1073 39 : spdk_spin_lock(&g_fsdev_mgr.spinlock);
1074 :
1075 39 : fsdev = fsdev_get_by_name(fsdev_name);
1076 39 : if (fsdev == NULL) {
1077 0 : SPDK_NOTICELOG("Currently unable to find fsdev with name: %s\n", fsdev_name);
1078 0 : spdk_spin_unlock(&g_fsdev_mgr.spinlock);
1079 0 : return -ENODEV;
1080 : }
1081 :
1082 39 : rc = fsdev_desc_alloc(fsdev, event_cb, event_ctx, &desc);
1083 39 : if (rc != 0) {
1084 0 : spdk_spin_unlock(&g_fsdev_mgr.spinlock);
1085 0 : return rc;
1086 : }
1087 :
1088 39 : rc = fsdev_open(fsdev, desc);
1089 39 : if (rc != 0) {
1090 0 : fsdev_desc_free(desc);
1091 0 : desc = NULL;
1092 : }
1093 :
1094 39 : *_desc = desc;
1095 39 : spdk_spin_unlock(&g_fsdev_mgr.spinlock);
1096 39 : return rc;
1097 : }
1098 :
1099 : static void
1100 39 : fsdev_close(struct spdk_fsdev *fsdev, struct spdk_fsdev_desc *desc)
1101 : {
1102 : int rc;
1103 :
1104 39 : spdk_spin_lock(&fsdev->internal.spinlock);
1105 39 : spdk_spin_lock(&desc->spinlock);
1106 :
1107 39 : TAILQ_REMOVE(&fsdev->internal.open_descs, desc, link);
1108 39 : desc->closed = true;
1109 39 : if (0 == desc->refs) {
1110 39 : spdk_spin_unlock(&desc->spinlock);
1111 39 : fsdev_desc_free(desc);
1112 : } else {
1113 0 : spdk_spin_unlock(&desc->spinlock);
1114 : }
1115 :
1116 39 : if (fsdev->internal.status == SPDK_FSDEV_STATUS_REMOVING &&
1117 0 : TAILQ_EMPTY(&fsdev->internal.open_descs)) {
1118 0 : rc = fsdev_unregister_unsafe(fsdev);
1119 0 : spdk_spin_unlock(&fsdev->internal.spinlock);
1120 :
1121 0 : if (rc == 0) {
1122 0 : spdk_io_device_unregister(__fsdev_to_io_dev(fsdev), fsdev_destroy_cb);
1123 : }
1124 : } else {
1125 39 : spdk_spin_unlock(&fsdev->internal.spinlock);
1126 : }
1127 39 : }
1128 :
1129 : void
1130 39 : spdk_fsdev_close(struct spdk_fsdev_desc *desc)
1131 : {
1132 39 : struct spdk_fsdev *fsdev = spdk_fsdev_desc_get_fsdev(desc);
1133 :
1134 39 : SPDK_DEBUGLOG(fsdev, "Closing descriptor %p for fsdev %s on thread %p\n",
1135 : desc, fsdev->name, spdk_get_thread());
1136 39 : assert(desc->thread == spdk_get_thread());
1137 39 : spdk_spin_lock(&g_fsdev_mgr.spinlock);
1138 39 : fsdev_close(fsdev, desc);
1139 39 : spdk_spin_unlock(&g_fsdev_mgr.spinlock);
1140 39 : }
1141 :
1142 : int
1143 39 : spdk_fsdev_register(struct spdk_fsdev *fsdev)
1144 : {
1145 : int rc;
1146 :
1147 39 : rc = fsdev_register(fsdev);
1148 39 : if (rc != 0) {
1149 0 : return rc;
1150 : }
1151 :
1152 39 : spdk_notify_send("fsdev_register", spdk_fsdev_get_name(fsdev));
1153 39 : return rc;
1154 : }
1155 :
1156 : struct spdk_fsdev *
1157 116 : spdk_fsdev_desc_get_fsdev(struct spdk_fsdev_desc *desc)
1158 : {
1159 116 : assert(desc != NULL);
1160 116 : return desc->fsdev;
1161 : }
1162 :
1163 : void
1164 1 : spdk_fsdev_module_list_add(struct spdk_fsdev_module *fsdev_module)
1165 : {
1166 :
1167 1 : if (spdk_fsdev_module_list_find(fsdev_module->name)) {
1168 0 : SPDK_ERRLOG("ERROR: module '%s' already registered.\n", fsdev_module->name);
1169 0 : assert(false);
1170 : }
1171 :
1172 1 : TAILQ_INSERT_TAIL(&g_fsdev_mgr.fsdev_modules, fsdev_module, internal.tailq);
1173 1 : }
1174 :
1175 : struct spdk_fsdev_module *
1176 1 : spdk_fsdev_module_list_find(const char *name)
1177 : {
1178 : struct spdk_fsdev_module *fsdev_module;
1179 :
1180 1 : TAILQ_FOREACH(fsdev_module, &g_fsdev_mgr.fsdev_modules, internal.tailq) {
1181 0 : if (strcmp(name, fsdev_module->name) == 0) {
1182 0 : break;
1183 : }
1184 : }
1185 :
1186 1 : return fsdev_module;
1187 : }
1188 :
1189 1 : SPDK_LOG_REGISTER_COMPONENT(fsdev)
|