Line data Source code
1 : /* SPDX-License-Identifier: BSD-3-Clause
2 : * Copyright (c) 2024 NVIDIA CORPORATION & AFFILIATES.
3 : * All rights reserved.
4 : */
5 :
6 : #include "spdk/stdinc.h"
7 : #include "spdk/event.h"
8 : #include "spdk/log.h"
9 : #include "spdk/string.h"
10 : #include "spdk/fsdev.h"
11 : #include "spdk/rpc.h"
12 : #include "spdk/env.h"
13 : #include "spdk/util.h"
14 : #include "spdk/thread.h"
15 : #include "spdk/likely.h"
16 : #include "spdk/fuse_dispatcher.h"
17 : #include "linux/fuse_kernel.h"
18 :
19 : #ifndef UNUSED
20 : #define UNUSED(x) (void)(x)
21 : #endif
22 :
23 : /* TODO: values, see https://libfuse.github.io/doxygen/structfuse__conn__info.html */
24 : #define DEFAULT_TIME_GRAN 1
25 : #define DEFAULT_MAX_BACKGROUND 1024
26 : #define DEFAULT_CONGESTION_THRESHOLD 1024
27 : #define DEFAULT_MAX_READAHEAD 0x00020000
28 : #define OFFSET_MAX 0x7fffffffffffffffLL
29 :
30 : /*
31 : * NOTE: It appeared that the open flags have different values on the different HW architechtures.
32 : *
33 : * This code handles the open flags translation in case they're originated from a platform with
34 : * a different HW architecture.
35 : *
36 : * Currently supported:
37 : * - X86
38 : * - X86_64
39 : * - ARM
40 : * - ARM64
41 : */
42 : /* See https://lxr.missinglinkelectronics.com/linux/arch/arm/include/uapi/asm/fcntl.h */
43 : #define ARM_O_DIRECTORY 040000 /* must be a directory */
44 : #define ARM_O_NOFOLLOW 0100000 /* don't follow links */
45 : #define ARM_O_DIRECT 0200000 /* direct disk access hint - currently ignored */
46 : #define ARM_O_LARGEFILE 0400000
47 :
48 : /* See https://lxr.missinglinkelectronics.com/linux/include/uapi/asm-generic/fcntl.h */
49 : #define X86_O_DIRECT 00040000 /* direct disk access hint */
50 : #define X86_O_LARGEFILE 00100000
51 : #define X86_O_DIRECTORY 00200000 /* must be a directory */
52 : #define X86_O_NOFOLLOW 00400000 /* don't follow links */
53 :
54 : static inline bool
55 0 : fsdev_d2h_open_flags(enum spdk_fuse_arch fuse_arch, uint32_t flags, uint32_t *translated_flags)
56 : {
57 0 : bool res = true;
58 :
59 0 : *translated_flags = flags;
60 :
61 : /* NOTE: we always check the original flags to avoid situation where the arch and the native flags
62 : * overlap and previously set native flag could be interpreted as original arch flag.
63 : */
64 : #define REPLACE_FLAG(arch_flag, native_flag) \
65 : do { \
66 : if (flags & (arch_flag)) { \
67 : *translated_flags &= ~(arch_flag); \
68 : *translated_flags |= (native_flag); \
69 : } \
70 : } while(0)
71 :
72 0 : switch (fuse_arch) {
73 0 : case SPDK_FUSE_ARCH_NATIVE:
74 : #if defined(__x86_64__) || defined(__i386__)
75 : case SPDK_FUSE_ARCH_X86:
76 : case SPDK_FUSE_ARCH_X86_64:
77 : #endif
78 : #if defined(__aarch64__) || defined(__arm__)
79 : case SPDK_FUSE_ARCH_ARM:
80 : case SPDK_FUSE_ARCH_ARM64:
81 : #endif
82 : /* No translation required */
83 0 : break;
84 : #if defined(__x86_64__) || defined(__i386__)
85 0 : case SPDK_FUSE_ARCH_ARM:
86 : case SPDK_FUSE_ARCH_ARM64:
87 : /* Relace the ARM-specific flags with the native ones */
88 0 : REPLACE_FLAG(ARM_O_DIRECTORY, O_DIRECTORY);
89 0 : REPLACE_FLAG(ARM_O_NOFOLLOW, O_NOFOLLOW);
90 0 : REPLACE_FLAG(ARM_O_DIRECT, O_DIRECT);
91 0 : REPLACE_FLAG(ARM_O_LARGEFILE, O_LARGEFILE);
92 0 : break;
93 : #endif
94 : #if defined(__aarch64__) || defined(__arm__)
95 : case SPDK_FUSE_ARCH_X86:
96 : case SPDK_FUSE_ARCH_X86_64:
97 : /* Relace the X86-specific flags with the native ones */
98 : REPLACE_FLAG(X86_O_DIRECTORY, O_DIRECTORY);
99 : REPLACE_FLAG(X86_O_NOFOLLOW, O_NOFOLLOW);
100 : REPLACE_FLAG(X86_O_DIRECT, O_DIRECT);
101 : REPLACE_FLAG(X86_O_LARGEFILE, O_LARGEFILE);
102 : break;
103 : #endif
104 0 : default:
105 0 : SPDK_ERRLOG("Unsupported FUSE arch: %d\n", fuse_arch);
106 0 : assert(0);
107 : res = false;
108 : break;
109 : }
110 :
111 : #undef REPLACE_FLAG
112 :
113 0 : return res;
114 : }
115 :
116 : struct spdk_fuse_mgr {
117 : struct spdk_mempool *fuse_io_pool;
118 : uint32_t ref_cnt;
119 : pthread_mutex_t lock;
120 : };
121 :
122 : static struct spdk_fuse_mgr g_fuse_mgr = {
123 : .fuse_io_pool = NULL,
124 : .ref_cnt = 0,
125 : .lock = PTHREAD_MUTEX_INITIALIZER,
126 : };
127 :
128 : struct fuse_forget_data {
129 : uint64_t ino;
130 : uint64_t nlookup;
131 : };
132 :
133 : struct iov_offs {
134 : size_t iov_offs;
135 : size_t buf_offs;
136 : };
137 :
138 : struct fuse_io {
139 : /** For SG buffer cases, array of iovecs for input. */
140 : struct iovec *in_iov;
141 :
142 : /** For SG buffer cases, number of iovecs in in_iov array. */
143 : int in_iovcnt;
144 :
145 : /** For SG buffer cases, array of iovecs for output. */
146 : struct iovec *out_iov;
147 :
148 : /** For SG buffer cases, number of iovecs in out_iov array. */
149 : int out_iovcnt;
150 :
151 : struct iov_offs in_offs;
152 : struct iov_offs out_offs;
153 :
154 : spdk_fuse_dispatcher_submit_cpl_cb cpl_cb;
155 : void *cpl_cb_arg;
156 : struct spdk_io_channel *ch;
157 : struct spdk_fuse_dispatcher *disp;
158 :
159 : struct fuse_in_header hdr;
160 : bool in_hdr_with_data;
161 :
162 : union {
163 : struct {
164 : struct spdk_thread *thread;
165 : struct fuse_init_in *in;
166 : bool legacy_in;
167 : struct spdk_fsdev_open_opts opts;
168 : size_t out_len;
169 : } init;
170 : struct {
171 : bool plus;
172 : uint32_t size;
173 : char *writep;
174 : uint32_t bytes_written;
175 : } readdir;
176 : struct {
177 : uint32_t to_forget;
178 : int status;
179 : } batch_forget;
180 :
181 : struct {
182 : int status;
183 : } fsdev_close;
184 : } u;
185 : };
186 :
187 : struct spdk_fuse_dispatcher {
188 : /**
189 : * fsdev descriptor
190 : */
191 : struct spdk_fsdev_desc *desc;
192 :
193 : /**
194 : * fsdev thread
195 : */
196 : struct spdk_thread *fsdev_thread;
197 :
198 : /**
199 : * Major version of the protocol (read-only)
200 : */
201 : unsigned proto_major;
202 :
203 : /**
204 : * Minor version of the protocol (read-only)
205 : */
206 : unsigned proto_minor;
207 :
208 : /**
209 : * FUSE request source's architecture
210 : */
211 : enum spdk_fuse_arch fuse_arch;
212 :
213 : /**
214 : * Root file object
215 : */
216 : struct spdk_fsdev_file_object *root_fobject;
217 :
218 : /**
219 : * Event callback
220 : */
221 : spdk_fuse_dispatcher_event_cb event_cb;
222 :
223 : /**
224 : * Event callback's context
225 : */
226 : void *event_ctx;
227 :
228 : /**
229 : * Name of the underlying fsdev
230 : *
231 : * NOTE: must be last
232 : */
233 : char fsdev_name[];
234 : };
235 :
236 : struct spdk_fuse_dispatcher_channel {
237 : struct spdk_io_channel *fsdev_io_ch;
238 : };
239 :
240 : #define __disp_to_io_dev(disp) (((char *)disp) + 1)
241 : #define __disp_from_io_dev(io_dev) ((struct spdk_fuse_dispatcher *)(((char *)io_dev) - 1))
242 : #define __disp_ch_from_io_ch(io_ch) ((struct spdk_fuse_dispatcher_channel *)spdk_io_channel_get_ctx(io_ch))
243 :
244 : static inline const char *
245 0 : fuse_dispatcher_name(struct spdk_fuse_dispatcher *disp)
246 : {
247 0 : return disp->fsdev_name;
248 : }
249 :
250 : static inline uint64_t
251 0 : file_ino(struct fuse_io *fuse_io, const struct spdk_fsdev_file_object *fobject)
252 : {
253 0 : return (fuse_io->disp->root_fobject == fobject) ? FUSE_ROOT_ID : (uint64_t)(uintptr_t)fobject;
254 : }
255 :
256 : static struct spdk_fsdev_file_object *
257 0 : ino_to_object(struct fuse_io *fuse_io, uint64_t ino)
258 : {
259 : return (ino == FUSE_ROOT_ID) ?
260 0 : fuse_io->disp->root_fobject :
261 : (struct spdk_fsdev_file_object *)(uintptr_t)ino;
262 : }
263 :
264 : static struct spdk_fsdev_file_object *
265 0 : file_object(struct fuse_io *fuse_io)
266 : {
267 0 : return ino_to_object(fuse_io, fuse_io->hdr.nodeid);
268 : }
269 :
270 : static inline uint64_t
271 0 : file_fh(const struct spdk_fsdev_file_handle *fhandle)
272 : {
273 0 : return (uint64_t)(uintptr_t)fhandle;
274 : }
275 :
276 : static struct spdk_fsdev_file_handle *
277 0 : file_handle(uint64_t fh)
278 : {
279 0 : return (struct spdk_fsdev_file_handle *)(uintptr_t)fh;
280 : }
281 :
282 : static inline uint16_t
283 0 : fsdev_io_d2h_u16(struct fuse_io *fuse_io, uint16_t v)
284 : {
285 0 : return v;
286 : }
287 :
288 : static inline uint16_t
289 0 : fsdev_io_h2d_u16(struct fuse_io *fuse_io, uint16_t v)
290 : {
291 0 : return v;
292 : }
293 :
294 : static inline uint32_t
295 0 : fsdev_io_d2h_u32(struct fuse_io *fuse_io, uint32_t v)
296 : {
297 0 : return v;
298 : }
299 :
300 : static inline uint32_t
301 0 : fsdev_io_h2d_u32(struct fuse_io *fuse_io, uint32_t v)
302 : {
303 0 : return v;
304 : }
305 :
306 : static inline int32_t
307 0 : fsdev_io_h2d_i32(struct fuse_io *fuse_io, int32_t v)
308 : {
309 0 : return v;
310 : }
311 :
312 : static inline uint64_t
313 0 : fsdev_io_d2h_u64(struct fuse_io *fuse_io, uint64_t v)
314 : {
315 0 : return v;
316 : }
317 :
318 : static inline uint64_t
319 0 : fsdev_io_h2d_u64(struct fuse_io *fuse_io, uint64_t v)
320 : {
321 0 : return v;
322 : }
323 :
324 : static inline unsigned
325 0 : fsdev_io_proto_minor(struct fuse_io *fuse_io)
326 : {
327 0 : return fuse_io->disp->proto_minor;
328 : }
329 :
330 : static inline void *
331 0 : _iov_arr_get_buf_info(struct iovec *iovs, size_t cnt, struct iov_offs *offs, size_t *size)
332 : {
333 : struct iovec *iov;
334 :
335 0 : assert(offs->iov_offs <= cnt);
336 :
337 0 : if (offs->iov_offs == cnt) {
338 0 : assert(!offs->buf_offs);
339 0 : *size = 0;
340 0 : return NULL;
341 : }
342 :
343 0 : iov = &iovs[offs->iov_offs];
344 :
345 0 : assert(offs->buf_offs < iov->iov_len);
346 :
347 0 : *size = iov->iov_len - offs->buf_offs;
348 :
349 0 : return ((char *)iov->iov_base) + offs->buf_offs;
350 : }
351 :
352 : static inline void *
353 0 : _iov_arr_get_buf(struct iovec *iovs, size_t cnt, struct iov_offs *offs, size_t size,
354 : const char *direction)
355 : {
356 : char *arg_buf;
357 0 : size_t arg_size;
358 :
359 0 : arg_buf = _iov_arr_get_buf_info(iovs, cnt, offs, &arg_size);
360 0 : if (!arg_buf) {
361 0 : SPDK_INFOLOG(fuse_dispatcher, "No %s arg header attached at %zu:%zu\n", direction, offs->iov_offs,
362 : offs->buf_offs);
363 0 : return NULL;
364 : }
365 :
366 0 : if (!arg_size) {
367 0 : SPDK_INFOLOG(fuse_dispatcher, "%s arg of zero length attached at %zu:%zu\n", direction,
368 : offs->iov_offs, offs->buf_offs);
369 0 : return NULL;
370 : }
371 :
372 0 : if (size > arg_size) {
373 0 : SPDK_INFOLOG(fuse_dispatcher, "%s arg is too small (%zu > %zu) at %zu:%zu\n", direction, size,
374 : arg_size, offs->iov_offs, offs->buf_offs);
375 0 : return NULL;
376 : }
377 :
378 0 : if (size == arg_size) {
379 0 : offs->iov_offs++;
380 0 : offs->buf_offs = 0;
381 : } else {
382 0 : offs->buf_offs += size;
383 : }
384 :
385 0 : return arg_buf;
386 : }
387 :
388 : static inline const char *
389 0 : _fsdev_io_in_arg_get_str(struct fuse_io *fuse_io)
390 : {
391 : char *arg_buf;
392 0 : size_t arg_size, len;
393 :
394 0 : arg_buf = _iov_arr_get_buf_info(fuse_io->in_iov, fuse_io->in_iovcnt, &fuse_io->in_offs,
395 : &arg_size);
396 0 : if (!arg_buf) {
397 0 : SPDK_ERRLOG("No IN arg header attached at %zu:%zu\n", fuse_io->in_offs.iov_offs,
398 : fuse_io->in_offs.buf_offs);
399 0 : return NULL;
400 : }
401 :
402 0 : len = strnlen(arg_buf, arg_size);
403 0 : if (len == arg_size) {
404 0 : SPDK_ERRLOG("no string or bad string attached at %zu:%zu\n", fuse_io->in_offs.iov_offs,
405 : fuse_io->in_offs.buf_offs);
406 0 : return NULL;
407 : }
408 :
409 0 : fuse_io->in_offs.buf_offs += len + 1;
410 :
411 0 : if (len + 1 == arg_size) {
412 0 : fuse_io->in_offs.iov_offs++;
413 0 : fuse_io->in_offs.buf_offs = 0;
414 : }
415 :
416 0 : return arg_buf;
417 : }
418 :
419 : static inline void *
420 0 : _fsdev_io_in_arg_get_buf(struct fuse_io *fuse_io, size_t size)
421 : {
422 0 : return _iov_arr_get_buf(fuse_io->in_iov, fuse_io->in_iovcnt, &fuse_io->in_offs, size, "IN");
423 : }
424 :
425 :
426 : static inline void *
427 0 : _fsdev_io_out_arg_get_buf(struct fuse_io *fuse_io, size_t size)
428 : {
429 0 : return _iov_arr_get_buf(fuse_io->out_iov, fuse_io->out_iovcnt, &fuse_io->out_offs, size,
430 : "OUT");
431 : }
432 :
433 : static bool
434 0 : _fuse_op_requires_reply(uint32_t opcode)
435 : {
436 0 : switch (opcode) {
437 0 : case FUSE_FORGET:
438 : case FUSE_BATCH_FORGET:
439 0 : return false;
440 0 : default:
441 0 : return true;
442 : }
443 : }
444 :
445 : static void
446 0 : convert_stat(struct fuse_io *fuse_io, struct spdk_fsdev_file_object *fobject,
447 : const struct spdk_fsdev_file_attr *attr, struct fuse_attr *fattr)
448 : {
449 0 : fattr->ino = fsdev_io_h2d_u64(fuse_io, attr->ino);
450 0 : fattr->mode = fsdev_io_h2d_u32(fuse_io, attr->mode);
451 0 : fattr->nlink = fsdev_io_h2d_u32(fuse_io, attr->nlink);
452 0 : fattr->uid = fsdev_io_h2d_u32(fuse_io, attr->uid);
453 0 : fattr->gid = fsdev_io_h2d_u32(fuse_io, attr->gid);
454 0 : fattr->rdev = fsdev_io_h2d_u32(fuse_io, attr->rdev);
455 0 : fattr->size = fsdev_io_h2d_u64(fuse_io, attr->size);
456 0 : fattr->blksize = fsdev_io_h2d_u32(fuse_io, attr->blksize);
457 0 : fattr->blocks = fsdev_io_h2d_u64(fuse_io, attr->blocks);
458 0 : fattr->atime = fsdev_io_h2d_u64(fuse_io, attr->atime);
459 0 : fattr->mtime = fsdev_io_h2d_u64(fuse_io, attr->mtime);
460 0 : fattr->ctime = fsdev_io_h2d_u64(fuse_io, attr->ctime);
461 0 : fattr->atimensec = fsdev_io_h2d_u32(fuse_io, attr->atimensec);
462 0 : fattr->mtimensec = fsdev_io_h2d_u32(fuse_io, attr->mtimensec);
463 0 : fattr->ctimensec = fsdev_io_h2d_u32(fuse_io, attr->ctimensec);
464 0 : }
465 :
466 : static uint32_t
467 0 : calc_timeout_sec(uint32_t ms)
468 : {
469 0 : return ms / 1000;
470 : }
471 :
472 : static uint32_t
473 0 : calc_timeout_nsec(uint32_t ms)
474 : {
475 0 : return (ms % 1000) * 1000000;
476 : }
477 :
478 : static void
479 0 : fill_entry(struct fuse_io *fuse_io, struct fuse_entry_out *arg,
480 : struct spdk_fsdev_file_object *fobject, const struct spdk_fsdev_file_attr *attr)
481 : {
482 0 : arg->nodeid = fsdev_io_h2d_u64(fuse_io, file_ino(fuse_io, fobject));
483 0 : arg->generation = 0;
484 0 : arg->entry_valid = fsdev_io_h2d_u64(fuse_io, calc_timeout_sec(attr->valid_ms));
485 0 : arg->entry_valid_nsec = fsdev_io_h2d_u32(fuse_io, calc_timeout_nsec(attr->valid_ms));
486 0 : arg->attr_valid = fsdev_io_h2d_u64(fuse_io, calc_timeout_sec(attr->valid_ms));
487 0 : arg->attr_valid_nsec = fsdev_io_h2d_u32(fuse_io, calc_timeout_nsec(attr->valid_ms));
488 0 : convert_stat(fuse_io, fobject, attr, &arg->attr);
489 0 : }
490 :
491 : static void
492 0 : fill_open(struct fuse_io *fuse_io, struct fuse_open_out *arg,
493 : struct spdk_fsdev_file_handle *fhandle)
494 : {
495 0 : arg->fh = fsdev_io_h2d_u64(fuse_io, file_fh(fhandle));
496 0 : arg->open_flags = fsdev_io_h2d_u64(fuse_io, FOPEN_DIRECT_IO);
497 0 : }
498 :
499 : static void
500 0 : convert_statfs(struct fuse_io *fuse_io, const struct spdk_fsdev_file_statfs *statfs,
501 : struct fuse_kstatfs *kstatfs)
502 : {
503 0 : kstatfs->bsize = fsdev_io_h2d_u32(fuse_io, statfs->bsize);
504 0 : kstatfs->frsize = fsdev_io_h2d_u32(fuse_io, statfs->frsize);
505 0 : kstatfs->blocks = fsdev_io_h2d_u64(fuse_io, statfs->blocks);
506 0 : kstatfs->bfree = fsdev_io_h2d_u64(fuse_io, statfs->bfree);
507 0 : kstatfs->bavail = fsdev_io_h2d_u64(fuse_io, statfs->bavail);
508 0 : kstatfs->files = fsdev_io_h2d_u64(fuse_io, statfs->files);
509 0 : kstatfs->ffree = fsdev_io_h2d_u64(fuse_io, statfs->ffree);
510 0 : kstatfs->namelen = fsdev_io_h2d_u32(fuse_io, statfs->namelen);
511 0 : }
512 :
513 : static struct fuse_out_header *
514 0 : fuse_dispatcher_fill_out_hdr(struct fuse_io *fuse_io, size_t out_len, int error)
515 : {
516 : struct fuse_out_header *hdr;
517 : struct iovec *out;
518 : uint32_t len;
519 :
520 0 : assert(fuse_io->out_iovcnt >= 1);
521 0 : assert(error <= 0);
522 :
523 0 : out = fuse_io->out_iov;
524 :
525 0 : if (out->iov_len < sizeof(*hdr)) {
526 0 : SPDK_ERRLOG("Bad out header len: %zu < %zu\n", out->iov_len, sizeof(*hdr));
527 0 : return NULL;
528 : }
529 :
530 0 : if (error < -1000) {
531 0 : SPDK_ERRLOG("Bad completion error value: %" PRIu32 "\n", error);
532 0 : return NULL;
533 : }
534 :
535 0 : len = sizeof(*hdr) + out_len;
536 :
537 0 : hdr = out->iov_base;
538 0 : memset(hdr, 0, sizeof(*hdr));
539 :
540 0 : hdr->unique = fsdev_io_h2d_u64(fuse_io, fuse_io->hdr.unique);
541 0 : hdr->error = fsdev_io_h2d_i32(fuse_io, error);
542 0 : hdr->len = fsdev_io_h2d_u32(fuse_io, len);
543 :
544 0 : return hdr;
545 : }
546 :
547 : static void
548 0 : fuse_dispatcher_io_complete_final(struct fuse_io *fuse_io, int error)
549 : {
550 0 : spdk_fuse_dispatcher_submit_cpl_cb cpl_cb = fuse_io->cpl_cb;
551 0 : void *cpl_cb_arg = fuse_io->cpl_cb_arg;
552 :
553 : /* NOTE: it's important to free fuse_io before the completion callback,
554 : * as the callback can destroy the dispatcher
555 : */
556 0 : spdk_mempool_put(g_fuse_mgr.fuse_io_pool, fuse_io);
557 :
558 0 : cpl_cb(cpl_cb_arg, error);
559 0 : }
560 :
561 : static void
562 0 : fuse_dispatcher_io_complete(struct fuse_io *fuse_io, uint32_t out_len, int error)
563 : {
564 0 : struct fuse_out_header *hdr = fuse_dispatcher_fill_out_hdr(fuse_io, out_len, error);
565 :
566 0 : assert(_fuse_op_requires_reply(fuse_io->hdr.opcode));
567 :
568 0 : if (!hdr) {
569 0 : SPDK_ERRLOG("Completion failed: cannot fill out header\n");
570 0 : return;
571 : }
572 :
573 0 : SPDK_DEBUGLOG(fuse_dispatcher,
574 : "Completing IO#%" PRIu64 " (err=%d, out_len=%" PRIu32 ")\n",
575 : fuse_io->hdr.unique, error, out_len);
576 :
577 0 : fuse_dispatcher_io_complete_final(fuse_io, error);
578 : }
579 :
580 : static void
581 0 : fuse_dispatcher_io_copy_and_complete(struct fuse_io *fuse_io, const void *out, uint32_t out_len,
582 : int error)
583 : {
584 0 : if (out && out_len) {
585 0 : void *buf = _fsdev_io_out_arg_get_buf(fuse_io, out_len);
586 0 : if (buf) {
587 0 : memcpy(buf, out, out_len);
588 : } else {
589 0 : SPDK_ERRLOG("Completion failed: cannot get buf to copy %" PRIu32 " bytes\n", out_len);
590 0 : error = EINVAL;
591 0 : out_len = 0;
592 : }
593 : }
594 :
595 0 : fuse_dispatcher_io_complete(fuse_io, out_len, error);
596 0 : }
597 :
598 : static void
599 0 : fuse_dispatcher_io_complete_none(struct fuse_io *fuse_io, int err)
600 : {
601 0 : SPDK_DEBUGLOG(fuse_dispatcher, "Completing IO#%" PRIu64 "(err=%d)\n",
602 : fuse_io->hdr.unique, err);
603 0 : fuse_dispatcher_io_complete_final(fuse_io, err);
604 0 : }
605 :
606 : static void
607 0 : fuse_dispatcher_io_complete_ok(struct fuse_io *fuse_io, uint32_t out_len)
608 : {
609 0 : fuse_dispatcher_io_complete(fuse_io, out_len, 0);
610 0 : }
611 :
612 : static void
613 0 : fuse_dispatcher_io_complete_err(struct fuse_io *fuse_io, int err)
614 : {
615 0 : fuse_dispatcher_io_complete(fuse_io, 0, err);
616 0 : }
617 :
618 : static void
619 0 : fuse_dispatcher_io_complete_entry(struct fuse_io *fuse_io, struct spdk_fsdev_file_object *fobject,
620 : const struct spdk_fsdev_file_attr *attr)
621 : {
622 0 : struct fuse_entry_out arg;
623 0 : size_t size = fsdev_io_proto_minor(fuse_io) < 9 ?
624 0 : FUSE_COMPAT_ENTRY_OUT_SIZE : sizeof(arg);
625 :
626 0 : memset(&arg, 0, sizeof(arg));
627 0 : fill_entry(fuse_io, &arg, fobject, attr);
628 :
629 0 : fuse_dispatcher_io_copy_and_complete(fuse_io, &arg, size, 0);
630 0 : }
631 :
632 : static void
633 0 : fuse_dispatcher_io_complete_open(struct fuse_io *fuse_io, struct spdk_fsdev_file_handle *fhandle)
634 : {
635 : struct fuse_open_out *arg;
636 :
637 0 : arg = _fsdev_io_out_arg_get_buf(fuse_io, sizeof(*arg));
638 0 : if (!arg) {
639 0 : SPDK_ERRLOG("Cannot get fuse_open_out\n");
640 0 : fuse_dispatcher_io_complete_err(fuse_io, -EINVAL);
641 0 : return;
642 : }
643 :
644 0 : fill_open(fuse_io, arg, fhandle);
645 :
646 0 : fuse_dispatcher_io_complete_ok(fuse_io, sizeof(*arg));
647 : }
648 :
649 : static void
650 0 : fuse_dispatcher_io_complete_create(struct fuse_io *fuse_io, struct spdk_fsdev_file_object *fobject,
651 : const struct spdk_fsdev_file_attr *attr,
652 : struct spdk_fsdev_file_handle *fhandle)
653 : {
654 0 : char buf[sizeof(struct fuse_entry_out) + sizeof(struct fuse_open_out)];
655 0 : size_t entrysize = fsdev_io_proto_minor(fuse_io) < 9 ?
656 0 : FUSE_COMPAT_ENTRY_OUT_SIZE : sizeof(struct fuse_entry_out);
657 0 : struct fuse_entry_out *earg = (struct fuse_entry_out *) buf;
658 0 : struct fuse_open_out *oarg = (struct fuse_open_out *)(buf + entrysize);
659 :
660 0 : memset(buf, 0, sizeof(buf));
661 0 : fill_entry(fuse_io, earg, fobject, attr);
662 0 : fill_open(fuse_io, oarg, fhandle);
663 :
664 0 : fuse_dispatcher_io_copy_and_complete(fuse_io, buf, entrysize + sizeof(struct fuse_open_out), 0);
665 0 : }
666 :
667 : static void
668 0 : fuse_dispatcher_io_complete_xattr(struct fuse_io *fuse_io, uint32_t count)
669 : {
670 : struct fuse_getxattr_out *arg;
671 :
672 0 : arg = _fsdev_io_out_arg_get_buf(fuse_io, sizeof(*arg));
673 0 : if (!arg) {
674 0 : SPDK_ERRLOG("Cannot get fuse_getxattr_out\n");
675 0 : fuse_dispatcher_io_complete_err(fuse_io, -EINVAL);
676 0 : return;
677 : }
678 :
679 0 : arg->size = fsdev_io_h2d_i32(fuse_io, count);
680 :
681 0 : fuse_dispatcher_io_complete_ok(fuse_io, sizeof(*arg));
682 : }
683 :
684 : static void
685 0 : fuse_dispatcher_io_complete_write(struct fuse_io *fuse_io, uint32_t data_size, int error)
686 : {
687 : struct fuse_write_out *arg;
688 :
689 0 : arg = _fsdev_io_out_arg_get_buf(fuse_io, sizeof(*arg));
690 0 : if (!arg) {
691 0 : SPDK_ERRLOG("Cannot get fuse_write_out\n");
692 0 : fuse_dispatcher_io_complete_err(fuse_io, -EINVAL);
693 0 : return;
694 : }
695 :
696 0 : arg->size = fsdev_io_d2h_u32(fuse_io, data_size);
697 :
698 0 : fuse_dispatcher_io_complete(fuse_io, sizeof(*arg), error);
699 : }
700 :
701 : static void
702 0 : fuse_dispatcher_io_complete_statfs(struct fuse_io *fuse_io,
703 : const struct spdk_fsdev_file_statfs *statfs)
704 : {
705 0 : struct fuse_statfs_out arg;
706 0 : size_t size = fsdev_io_proto_minor(fuse_io) < 4 ?
707 0 : FUSE_COMPAT_STATFS_SIZE : sizeof(arg);
708 :
709 0 : memset(&arg, 0, sizeof(arg));
710 0 : convert_statfs(fuse_io, statfs, &arg.st);
711 :
712 0 : return fuse_dispatcher_io_copy_and_complete(fuse_io, &arg, size, 0);
713 : }
714 :
715 : static void
716 0 : fuse_dispatcher_io_complete_attr(struct fuse_io *fuse_io, const struct spdk_fsdev_file_attr *attr)
717 : {
718 0 : struct fuse_attr_out arg;
719 0 : size_t size = fsdev_io_proto_minor(fuse_io) < 9 ?
720 0 : FUSE_COMPAT_ATTR_OUT_SIZE : sizeof(arg);
721 :
722 0 : memset(&arg, 0, sizeof(arg));
723 0 : arg.attr_valid = fsdev_io_h2d_u64(fuse_io, calc_timeout_sec(attr->valid_ms));
724 0 : arg.attr_valid_nsec = fsdev_io_h2d_u32(fuse_io, calc_timeout_nsec(attr->valid_ms));
725 0 : convert_stat(fuse_io, file_object(fuse_io), attr, &arg.attr);
726 :
727 0 : fuse_dispatcher_io_copy_and_complete(fuse_io, &arg, size, 0);
728 0 : }
729 :
730 : /* `buf` is allowed to be empty so that the proper size may be
731 : allocated by the caller */
732 : static size_t
733 0 : fuse_dispatcher_add_direntry(struct fuse_io *fuse_io, char *buf, size_t bufsize,
734 : const char *name, struct spdk_fsdev_file_object *fobject, const struct spdk_fsdev_file_attr *attr,
735 : off_t off)
736 : {
737 : size_t namelen;
738 : size_t entlen;
739 : size_t entlen_padded;
740 : struct fuse_dirent *dirent;
741 :
742 0 : namelen = strlen(name);
743 0 : entlen = FUSE_NAME_OFFSET + namelen;
744 0 : entlen_padded = FUSE_DIRENT_ALIGN(entlen);
745 :
746 0 : if ((buf == NULL) || (entlen_padded > bufsize)) {
747 0 : return entlen_padded;
748 : }
749 :
750 0 : dirent = (struct fuse_dirent *) buf;
751 0 : dirent->ino = file_ino(fuse_io, fobject);
752 0 : dirent->off = fsdev_io_h2d_u64(fuse_io, off);
753 0 : dirent->namelen = fsdev_io_h2d_u32(fuse_io, namelen);
754 0 : dirent->type = fsdev_io_h2d_u32(fuse_io, (attr->mode & 0170000) >> 12);
755 0 : memcpy(dirent->name, name, namelen);
756 0 : memset(dirent->name + namelen, 0, entlen_padded - entlen);
757 :
758 0 : return entlen_padded;
759 : }
760 :
761 : /* `buf` is allowed to be empty so that the proper size may be
762 : allocated by the caller */
763 : static size_t
764 0 : fuse_dispatcher_add_direntry_plus(struct fuse_io *fuse_io, char *buf, size_t bufsize,
765 : const char *name, struct spdk_fsdev_file_object *fobject, const struct spdk_fsdev_file_attr *attr,
766 : off_t off)
767 : {
768 : size_t namelen;
769 : size_t entlen;
770 : size_t entlen_padded;
771 :
772 0 : namelen = strlen(name);
773 0 : entlen = FUSE_NAME_OFFSET_DIRENTPLUS + namelen;
774 0 : entlen_padded = FUSE_DIRENT_ALIGN(entlen);
775 0 : if ((buf == NULL) || (entlen_padded > bufsize)) {
776 0 : return entlen_padded;
777 : }
778 :
779 0 : struct fuse_direntplus *dp = (struct fuse_direntplus *) buf;
780 0 : memset(&dp->entry_out, 0, sizeof(dp->entry_out));
781 0 : fill_entry(fuse_io, &dp->entry_out, fobject, attr);
782 :
783 0 : struct fuse_dirent *dirent = &dp->dirent;
784 0 : dirent->ino = fsdev_io_h2d_u64(fuse_io, attr->ino);
785 0 : dirent->off = fsdev_io_h2d_u64(fuse_io, off);
786 0 : dirent->namelen = fsdev_io_h2d_u32(fuse_io, namelen);
787 0 : dirent->type = fsdev_io_h2d_u32(fuse_io, (attr->mode & 0170000) >> 12);
788 0 : memcpy(dirent->name, name, namelen);
789 0 : memset(dirent->name + namelen, 0, entlen_padded - entlen);
790 :
791 0 : return entlen_padded;
792 : }
793 :
794 : /*
795 : * Static FUSE commands handlers
796 : */
797 : static inline struct spdk_fsdev_desc *
798 0 : fuse_io_desc(struct fuse_io *fuse_io)
799 : {
800 0 : return fuse_io->disp->desc;
801 : }
802 :
803 : static void
804 0 : do_lookup_cpl_clb(void *cb_arg, struct spdk_io_channel *ch, int status,
805 : struct spdk_fsdev_file_object *fobject, const struct spdk_fsdev_file_attr *attr)
806 : {
807 0 : struct fuse_io *fuse_io = cb_arg;
808 :
809 0 : if (!status) {
810 0 : fuse_dispatcher_io_complete_entry(fuse_io, fobject, attr);
811 : } else {
812 0 : fuse_dispatcher_io_complete_err(fuse_io, status);
813 : }
814 0 : }
815 :
816 : static void
817 0 : do_lookup(struct fuse_io *fuse_io)
818 : {
819 : int err;
820 0 : const char *name = _fsdev_io_in_arg_get_str(fuse_io);
821 0 : if (!name) {
822 0 : SPDK_ERRLOG("No name or bad name attached\n");
823 0 : fuse_dispatcher_io_complete_err(fuse_io, -EINVAL);
824 0 : return;
825 : }
826 :
827 0 : err = spdk_fsdev_lookup(fuse_io_desc(fuse_io), fuse_io->ch, fuse_io->hdr.unique,
828 : file_object(fuse_io), name, do_lookup_cpl_clb, fuse_io);
829 0 : if (err) {
830 0 : fuse_dispatcher_io_complete_err(fuse_io, err);
831 : }
832 : }
833 :
834 : static void
835 0 : do_forget_cpl_clb(void *cb_arg, struct spdk_io_channel *ch, int status)
836 : {
837 0 : struct fuse_io *fuse_io = cb_arg;
838 :
839 0 : fuse_dispatcher_io_complete_none(fuse_io, status); /* FUSE_FORGET requires no response */
840 0 : }
841 :
842 : static void
843 0 : do_forget(struct fuse_io *fuse_io)
844 : {
845 : int err;
846 : struct fuse_forget_in *arg;
847 :
848 0 : arg = _fsdev_io_in_arg_get_buf(fuse_io, sizeof(*arg));
849 0 : if (!arg) {
850 0 : SPDK_ERRLOG("Cannot get fuse_forget_in\n");
851 0 : fuse_dispatcher_io_complete_none(fuse_io, EINVAL); /* FUSE_FORGET requires no response */
852 0 : return;
853 : }
854 :
855 0 : err = spdk_fsdev_forget(fuse_io_desc(fuse_io), fuse_io->ch, fuse_io->hdr.unique,
856 : file_object(fuse_io), fsdev_io_d2h_u64(fuse_io, arg->nlookup),
857 : do_forget_cpl_clb, fuse_io);
858 0 : if (err) {
859 0 : fuse_dispatcher_io_complete_err(fuse_io, err);
860 : }
861 : }
862 :
863 : static void
864 0 : do_getattr_cpl_clb(void *cb_arg, struct spdk_io_channel *ch, int status,
865 : const struct spdk_fsdev_file_attr *attr)
866 : {
867 0 : struct fuse_io *fuse_io = cb_arg;
868 :
869 0 : if (!status) {
870 0 : fuse_dispatcher_io_complete_attr(fuse_io, attr);
871 : } else {
872 0 : fuse_dispatcher_io_complete_err(fuse_io, status);
873 : }
874 0 : }
875 :
876 : static void
877 0 : do_getattr(struct fuse_io *fuse_io)
878 : {
879 : int err;
880 0 : uint64_t fh = 0;
881 :
882 0 : if (fsdev_io_proto_minor(fuse_io) >= 9) {
883 : struct fuse_getattr_in *arg;
884 :
885 0 : arg = _fsdev_io_in_arg_get_buf(fuse_io, sizeof(*arg));
886 0 : if (!arg) {
887 0 : SPDK_ERRLOG("Cannot get fuse_getattr_in\n");
888 0 : fuse_dispatcher_io_complete_err(fuse_io, -EINVAL);
889 0 : return;
890 : }
891 :
892 0 : if (fsdev_io_d2h_u64(fuse_io, arg->getattr_flags) & FUSE_GETATTR_FH) {
893 0 : fh = fsdev_io_d2h_u64(fuse_io, arg->fh);
894 : }
895 : }
896 :
897 0 : err = spdk_fsdev_getattr(fuse_io_desc(fuse_io), fuse_io->ch, fuse_io->hdr.unique,
898 : file_object(fuse_io), file_handle(fh), do_getattr_cpl_clb, fuse_io);
899 0 : if (err) {
900 0 : fuse_dispatcher_io_complete_err(fuse_io, err);
901 : }
902 : }
903 :
904 : static void
905 0 : do_setattr_cpl_clb(void *cb_arg, struct spdk_io_channel *ch, int status,
906 : const struct spdk_fsdev_file_attr *attr)
907 : {
908 0 : struct fuse_io *fuse_io = cb_arg;
909 :
910 0 : if (!status) {
911 0 : fuse_dispatcher_io_complete_attr(fuse_io, attr);
912 : } else {
913 0 : fuse_dispatcher_io_complete_err(fuse_io, status);
914 : }
915 0 : }
916 :
917 : static void
918 0 : do_setattr(struct fuse_io *fuse_io)
919 : {
920 : int err;
921 : struct fuse_setattr_in *arg;
922 : uint32_t valid;
923 0 : uint64_t fh = 0;
924 0 : struct spdk_fsdev_file_attr attr;
925 :
926 0 : arg = _fsdev_io_in_arg_get_buf(fuse_io, sizeof(*arg));
927 0 : if (!arg) {
928 0 : SPDK_ERRLOG("Cannot get fuse_setattr_in\n");
929 0 : fuse_dispatcher_io_complete_err(fuse_io, -EINVAL);
930 0 : return;
931 : }
932 :
933 0 : memset(&attr, 0, sizeof(attr));
934 0 : attr.mode = fsdev_io_d2h_u32(fuse_io, arg->mode);
935 0 : attr.uid = fsdev_io_d2h_u32(fuse_io, arg->uid);
936 0 : attr.gid = fsdev_io_d2h_u32(fuse_io, arg->gid);
937 0 : attr.size = fsdev_io_d2h_u64(fuse_io, arg->size);
938 0 : attr.atime = fsdev_io_d2h_u64(fuse_io, arg->atime);
939 0 : attr.mtime = fsdev_io_d2h_u64(fuse_io, arg->mtime);
940 0 : attr.ctime = fsdev_io_d2h_u64(fuse_io, arg->ctime);
941 0 : attr.atimensec = fsdev_io_d2h_u32(fuse_io, arg->atimensec);
942 0 : attr.mtimensec = fsdev_io_d2h_u32(fuse_io, arg->mtimensec);
943 0 : attr.ctimensec = fsdev_io_d2h_u32(fuse_io, arg->ctimensec);
944 :
945 0 : valid = fsdev_io_d2h_u64(fuse_io, arg->valid);
946 0 : if (valid & FATTR_FH) {
947 0 : valid &= ~FATTR_FH;
948 0 : fh = fsdev_io_d2h_u64(fuse_io, arg->fh);
949 : }
950 :
951 0 : valid &=
952 : FSDEV_SET_ATTR_MODE |
953 : FSDEV_SET_ATTR_UID |
954 : FSDEV_SET_ATTR_GID |
955 : FSDEV_SET_ATTR_SIZE |
956 : FSDEV_SET_ATTR_ATIME |
957 : FSDEV_SET_ATTR_MTIME |
958 : FSDEV_SET_ATTR_ATIME_NOW |
959 : FSDEV_SET_ATTR_MTIME_NOW |
960 : FSDEV_SET_ATTR_CTIME;
961 :
962 0 : err = spdk_fsdev_setattr(fuse_io_desc(fuse_io), fuse_io->ch, fuse_io->hdr.unique,
963 : file_object(fuse_io), file_handle(fh), &attr, valid,
964 : do_setattr_cpl_clb, fuse_io);
965 0 : if (err) {
966 0 : fuse_dispatcher_io_complete_err(fuse_io, err);
967 : }
968 : }
969 :
970 : static void
971 0 : do_readlink_cpl_clb(void *cb_arg, struct spdk_io_channel *ch, int status, const char *linkname)
972 : {
973 0 : struct fuse_io *fuse_io = cb_arg;
974 :
975 0 : if (!status) {
976 0 : fuse_dispatcher_io_copy_and_complete(fuse_io, linkname, strlen(linkname) + 1, 0);
977 : } else {
978 0 : fuse_dispatcher_io_complete_err(fuse_io, status);
979 : }
980 0 : }
981 :
982 : static void
983 0 : do_readlink(struct fuse_io *fuse_io)
984 : {
985 : int err;
986 :
987 0 : err = spdk_fsdev_readlink(fuse_io_desc(fuse_io), fuse_io->ch, fuse_io->hdr.unique,
988 : file_object(fuse_io), do_readlink_cpl_clb, fuse_io);
989 0 : if (err) {
990 0 : fuse_dispatcher_io_complete_err(fuse_io, err);
991 : }
992 0 : }
993 :
994 : static void
995 0 : do_symlink_cpl_clb(void *cb_arg, struct spdk_io_channel *ch, int status,
996 : struct spdk_fsdev_file_object *fobject, const struct spdk_fsdev_file_attr *attr)
997 : {
998 0 : struct fuse_io *fuse_io = cb_arg;
999 :
1000 0 : if (!status) {
1001 0 : fuse_dispatcher_io_complete_entry(fuse_io, fobject, attr);
1002 : } else {
1003 0 : fuse_dispatcher_io_complete_err(fuse_io, status);
1004 : }
1005 0 : }
1006 :
1007 : static void
1008 0 : do_symlink(struct fuse_io *fuse_io)
1009 : {
1010 : int err;
1011 : const char *name, *linkname;
1012 :
1013 0 : name = _fsdev_io_in_arg_get_str(fuse_io);
1014 0 : if (!name) {
1015 0 : SPDK_ERRLOG("Cannot get name\n");
1016 0 : fuse_dispatcher_io_complete_err(fuse_io, -EINVAL);
1017 0 : return;
1018 : }
1019 :
1020 0 : linkname = _fsdev_io_in_arg_get_str(fuse_io);
1021 0 : if (!linkname) {
1022 0 : SPDK_ERRLOG("Cannot get linkname\n");
1023 0 : fuse_dispatcher_io_complete_err(fuse_io, -EINVAL);
1024 0 : return;
1025 : }
1026 :
1027 0 : err = spdk_fsdev_symlink(fuse_io_desc(fuse_io), fuse_io->ch, fuse_io->hdr.unique,
1028 : file_object(fuse_io), name, linkname, fuse_io->hdr.uid, fuse_io->hdr.gid,
1029 : do_symlink_cpl_clb, fuse_io);
1030 0 : if (err) {
1031 0 : fuse_dispatcher_io_complete_err(fuse_io, err);
1032 : }
1033 : }
1034 :
1035 : static void
1036 0 : do_mknod_cpl_clb(void *cb_arg, struct spdk_io_channel *ch, int status,
1037 : struct spdk_fsdev_file_object *fobject, const struct spdk_fsdev_file_attr *attr)
1038 : {
1039 0 : struct fuse_io *fuse_io = cb_arg;
1040 :
1041 0 : if (!status) {
1042 0 : fuse_dispatcher_io_complete_entry(fuse_io, fobject, attr);
1043 : } else {
1044 0 : fuse_dispatcher_io_complete_err(fuse_io, status);
1045 : }
1046 0 : }
1047 :
1048 : static void
1049 0 : do_mknod(struct fuse_io *fuse_io)
1050 : {
1051 : int err;
1052 0 : bool compat = fsdev_io_proto_minor(fuse_io) < 12;
1053 : struct fuse_mknod_in *arg;
1054 : const char *name;
1055 :
1056 0 : arg = _fsdev_io_in_arg_get_buf(fuse_io, compat ? FUSE_COMPAT_MKNOD_IN_SIZE : sizeof(*arg));
1057 0 : if (!arg) {
1058 0 : SPDK_ERRLOG("Cannot get fuse_mknod_in (compat=%d)\n", compat);
1059 0 : fuse_dispatcher_io_complete_err(fuse_io, -EINVAL);
1060 0 : return;
1061 : }
1062 :
1063 0 : name = _fsdev_io_in_arg_get_str(fuse_io);
1064 0 : if (!name) {
1065 0 : SPDK_ERRLOG("Cannot get name (compat=%d)\n", compat);
1066 0 : fuse_dispatcher_io_complete_err(fuse_io, -EINVAL);
1067 0 : return;
1068 : }
1069 :
1070 0 : err = spdk_fsdev_mknod(fuse_io_desc(fuse_io), fuse_io->ch, fuse_io->hdr.unique,
1071 : file_object(fuse_io), name, fsdev_io_d2h_u32(fuse_io, arg->mode),
1072 0 : fsdev_io_d2h_u32(fuse_io, arg->rdev), fuse_io->hdr.uid, fuse_io->hdr.gid,
1073 : do_mknod_cpl_clb, fuse_io);
1074 0 : if (err) {
1075 0 : fuse_dispatcher_io_complete_err(fuse_io, err);
1076 : }
1077 : }
1078 :
1079 : static void
1080 0 : do_mkdir_cpl_clb(void *cb_arg, struct spdk_io_channel *ch, int status,
1081 : struct spdk_fsdev_file_object *fobject, const struct spdk_fsdev_file_attr *attr)
1082 : {
1083 0 : struct fuse_io *fuse_io = cb_arg;
1084 :
1085 0 : if (!status) {
1086 0 : fuse_dispatcher_io_complete_entry(fuse_io, fobject, attr);
1087 : } else {
1088 0 : fuse_dispatcher_io_complete_err(fuse_io, status);
1089 : }
1090 0 : }
1091 :
1092 : static void
1093 0 : do_mkdir(struct fuse_io *fuse_io)
1094 : {
1095 : int err;
1096 0 : bool compat = fsdev_io_proto_minor(fuse_io) < 12;
1097 : struct fuse_mkdir_in *arg;
1098 : const char *name;
1099 :
1100 0 : arg = _fsdev_io_in_arg_get_buf(fuse_io, compat ? sizeof(uint32_t) : sizeof(*arg));
1101 0 : if (!arg) {
1102 0 : SPDK_ERRLOG("Cannot get fuse_mkdir_in (compat=%d)\n", compat);
1103 0 : fuse_dispatcher_io_complete_err(fuse_io, -EINVAL);
1104 0 : return;
1105 : }
1106 :
1107 0 : name = _fsdev_io_in_arg_get_str(fuse_io);
1108 0 : if (!name) {
1109 0 : SPDK_ERRLOG("Cannot get name (compat=%d)\n", compat);
1110 0 : fuse_dispatcher_io_complete_err(fuse_io, -EINVAL);
1111 0 : return;
1112 : }
1113 :
1114 0 : err = spdk_fsdev_mkdir(fuse_io_desc(fuse_io), fuse_io->ch, fuse_io->hdr.unique,
1115 : file_object(fuse_io), name, fsdev_io_d2h_u32(fuse_io, arg->mode),
1116 : fuse_io->hdr.uid, fuse_io->hdr.gid, do_mkdir_cpl_clb, fuse_io);
1117 0 : if (err) {
1118 0 : fuse_dispatcher_io_complete_err(fuse_io, err);
1119 : }
1120 : }
1121 :
1122 : static void
1123 0 : do_unlink_cpl_clb(void *cb_arg, struct spdk_io_channel *ch, int status)
1124 : {
1125 0 : struct fuse_io *fuse_io = cb_arg;
1126 :
1127 0 : fuse_dispatcher_io_complete_err(fuse_io, status);
1128 0 : }
1129 :
1130 : static void
1131 0 : do_unlink(struct fuse_io *fuse_io)
1132 : {
1133 : int err;
1134 : const char *name;
1135 :
1136 0 : name = _fsdev_io_in_arg_get_str(fuse_io);
1137 0 : if (!name) {
1138 0 : SPDK_ERRLOG("Cannot get name\n");
1139 0 : fuse_dispatcher_io_complete_err(fuse_io, -EINVAL);
1140 0 : return;
1141 : }
1142 :
1143 0 : err = spdk_fsdev_unlink(fuse_io_desc(fuse_io), fuse_io->ch, fuse_io->hdr.unique,
1144 : file_object(fuse_io), name, do_unlink_cpl_clb, fuse_io);
1145 0 : if (err) {
1146 0 : fuse_dispatcher_io_complete_err(fuse_io, err);
1147 : }
1148 : }
1149 :
1150 : static void
1151 0 : do_rmdir_cpl_clb(void *cb_arg, struct spdk_io_channel *ch, int status)
1152 : {
1153 0 : struct fuse_io *fuse_io = cb_arg;
1154 :
1155 0 : fuse_dispatcher_io_complete_err(fuse_io, status);
1156 0 : }
1157 :
1158 : static void
1159 0 : do_rmdir(struct fuse_io *fuse_io)
1160 : {
1161 : int err;
1162 : const char *name;
1163 :
1164 0 : name = _fsdev_io_in_arg_get_str(fuse_io);
1165 0 : if (!name) {
1166 0 : SPDK_ERRLOG("Cannot get name\n");
1167 0 : fuse_dispatcher_io_complete_err(fuse_io, -EINVAL);
1168 0 : return;
1169 : }
1170 :
1171 0 : err = spdk_fsdev_rmdir(fuse_io_desc(fuse_io), fuse_io->ch, fuse_io->hdr.unique,
1172 : file_object(fuse_io), name, do_rmdir_cpl_clb, fuse_io);
1173 0 : if (err) {
1174 0 : fuse_dispatcher_io_complete_err(fuse_io, err);
1175 : }
1176 : }
1177 :
1178 : static void
1179 0 : do_rename_cpl_clb(void *cb_arg, struct spdk_io_channel *ch, int status)
1180 : {
1181 0 : struct fuse_io *fuse_io = cb_arg;
1182 :
1183 0 : fuse_dispatcher_io_complete_err(fuse_io, status);
1184 0 : }
1185 :
1186 : static void
1187 0 : do_rename_common(struct fuse_io *fuse_io, bool version2)
1188 : {
1189 : int err;
1190 : uint64_t newdir;
1191 : const char *oldname;
1192 : const char *newname;
1193 0 : uint32_t flags = 0;
1194 :
1195 0 : if (!version2) {
1196 : struct fuse_rename_in *arg;
1197 0 : arg = _fsdev_io_in_arg_get_buf(fuse_io, sizeof(*arg));
1198 0 : if (!arg) {
1199 0 : SPDK_ERRLOG("Cannot get fuse_rename_in\n");
1200 0 : fuse_dispatcher_io_complete_err(fuse_io, -EINVAL);
1201 0 : return;
1202 : }
1203 0 : newdir = fsdev_io_d2h_u64(fuse_io, arg->newdir);
1204 : } else {
1205 : struct fuse_rename2_in *arg;
1206 0 : arg = _fsdev_io_in_arg_get_buf(fuse_io, sizeof(*arg));
1207 0 : if (!arg) {
1208 0 : SPDK_ERRLOG("Cannot get fuse_rename2_in\n");
1209 0 : fuse_dispatcher_io_complete_err(fuse_io, -EINVAL);
1210 0 : return;
1211 : }
1212 0 : newdir = fsdev_io_d2h_u64(fuse_io, arg->newdir);
1213 0 : flags = fsdev_io_d2h_u64(fuse_io, arg->flags);
1214 : }
1215 :
1216 0 : oldname = _fsdev_io_in_arg_get_str(fuse_io);
1217 0 : if (!oldname) {
1218 0 : SPDK_ERRLOG("Cannot get oldname\n");
1219 0 : fuse_dispatcher_io_complete_err(fuse_io, -EINVAL);
1220 0 : return;
1221 : }
1222 :
1223 0 : newname = _fsdev_io_in_arg_get_str(fuse_io);
1224 0 : if (!newname) {
1225 0 : SPDK_ERRLOG("Cannot get newname\n");
1226 0 : fuse_dispatcher_io_complete_err(fuse_io, -EINVAL);
1227 0 : return;
1228 : }
1229 :
1230 0 : err = spdk_fsdev_rename(fuse_io_desc(fuse_io), fuse_io->ch, fuse_io->hdr.unique,
1231 : file_object(fuse_io), oldname, ino_to_object(fuse_io, newdir),
1232 : newname, flags, do_rename_cpl_clb, fuse_io);
1233 0 : if (err) {
1234 0 : fuse_dispatcher_io_complete_err(fuse_io, err);
1235 : }
1236 : }
1237 :
1238 : static void
1239 0 : do_rename(struct fuse_io *fuse_io)
1240 : {
1241 0 : do_rename_common(fuse_io, false);
1242 0 : }
1243 :
1244 : static void
1245 0 : do_rename2(struct fuse_io *fuse_io)
1246 : {
1247 0 : do_rename_common(fuse_io, true);
1248 0 : }
1249 :
1250 : static void
1251 0 : do_link_cpl_clb(void *cb_arg, struct spdk_io_channel *ch, int status,
1252 : struct spdk_fsdev_file_object *fobject, const struct spdk_fsdev_file_attr *attr)
1253 : {
1254 0 : struct fuse_io *fuse_io = cb_arg;
1255 :
1256 0 : if (!status) {
1257 0 : fuse_dispatcher_io_complete_entry(fuse_io, fobject, attr);
1258 : } else {
1259 0 : fuse_dispatcher_io_complete_err(fuse_io, status);
1260 : }
1261 0 : }
1262 :
1263 : static void
1264 0 : do_link(struct fuse_io *fuse_io)
1265 : {
1266 : int err;
1267 : struct fuse_link_in *arg;
1268 : const char *name;
1269 : uint64_t oldnodeid;
1270 :
1271 0 : arg = _fsdev_io_in_arg_get_buf(fuse_io, sizeof(*arg));
1272 0 : if (!arg) {
1273 0 : SPDK_ERRLOG("Cannot get fuse_link_in\n");
1274 0 : fuse_dispatcher_io_complete_err(fuse_io, -EINVAL);
1275 0 : return;
1276 : }
1277 :
1278 0 : name = _fsdev_io_in_arg_get_str(fuse_io);
1279 0 : if (!name) {
1280 0 : SPDK_ERRLOG("Cannot get name\n");
1281 0 : fuse_dispatcher_io_complete_err(fuse_io, -EINVAL);
1282 0 : return;
1283 : }
1284 :
1285 0 : oldnodeid = fsdev_io_d2h_u64(fuse_io, arg->oldnodeid);
1286 :
1287 0 : err = spdk_fsdev_link(fuse_io_desc(fuse_io), fuse_io->ch, fuse_io->hdr.unique,
1288 : ino_to_object(fuse_io, oldnodeid), file_object(fuse_io), name,
1289 : do_link_cpl_clb, fuse_io);
1290 0 : if (err) {
1291 0 : fuse_dispatcher_io_complete_err(fuse_io, err);
1292 : }
1293 : }
1294 :
1295 : static void
1296 0 : do_fopen_cpl_clb(void *cb_arg, struct spdk_io_channel *ch, int status,
1297 : struct spdk_fsdev_file_handle *fhandle)
1298 : {
1299 0 : struct fuse_io *fuse_io = cb_arg;
1300 :
1301 0 : if (!status) {
1302 0 : fuse_dispatcher_io_complete_open(fuse_io, fhandle);
1303 : } else {
1304 0 : fuse_dispatcher_io_complete_err(fuse_io, status);
1305 : }
1306 0 : }
1307 :
1308 : static void
1309 0 : do_open(struct fuse_io *fuse_io)
1310 : {
1311 0 : struct spdk_fuse_dispatcher *disp = fuse_io->disp;
1312 : int err;
1313 : struct fuse_open_in *arg;
1314 0 : uint32_t flags;
1315 :
1316 0 : arg = _fsdev_io_in_arg_get_buf(fuse_io, sizeof(*arg));
1317 0 : if (!arg) {
1318 0 : SPDK_ERRLOG("Cannot get fuse_forget_in\n");
1319 0 : fuse_dispatcher_io_complete_err(fuse_io, -EINVAL);
1320 0 : return;
1321 : }
1322 :
1323 0 : if (!fsdev_d2h_open_flags(disp->fuse_arch, fsdev_io_d2h_u32(fuse_io, arg->flags), &flags)) {
1324 0 : SPDK_ERRLOG("Cannot translate flags\n");
1325 0 : fuse_dispatcher_io_complete_err(fuse_io, -EINVAL);
1326 0 : return;
1327 : }
1328 :
1329 0 : err = spdk_fsdev_fopen(fuse_io_desc(fuse_io), fuse_io->ch, fuse_io->hdr.unique,
1330 : file_object(fuse_io), flags,
1331 : do_fopen_cpl_clb, fuse_io);
1332 0 : if (err) {
1333 0 : fuse_dispatcher_io_complete_err(fuse_io, err);
1334 : }
1335 : }
1336 :
1337 : static void
1338 0 : do_read_cpl_clb(void *cb_arg, struct spdk_io_channel *ch, int status, uint32_t data_size)
1339 : {
1340 0 : struct fuse_io *fuse_io = cb_arg;
1341 :
1342 0 : fuse_dispatcher_io_complete(fuse_io, data_size, status);
1343 0 : }
1344 :
1345 : static void
1346 0 : do_read(struct fuse_io *fuse_io)
1347 : {
1348 : int err;
1349 0 : bool compat = fsdev_io_proto_minor(fuse_io) < 9;
1350 : struct fuse_read_in *arg;
1351 : uint64_t fh;
1352 0 : uint32_t flags = 0;
1353 :
1354 0 : arg = _fsdev_io_in_arg_get_buf(fuse_io,
1355 : compat ? offsetof(struct fuse_read_in, lock_owner) : sizeof(*arg));
1356 0 : if (!arg) {
1357 0 : SPDK_ERRLOG("Cannot get fuse_read_in\n");
1358 0 : fuse_dispatcher_io_complete_err(fuse_io, -EINVAL);
1359 0 : return;
1360 : }
1361 :
1362 :
1363 0 : if (!compat) {
1364 0 : flags = fsdev_io_d2h_u32(fuse_io, arg->flags);
1365 : }
1366 :
1367 0 : fh = fsdev_io_d2h_u64(fuse_io, arg->fh);
1368 :
1369 0 : err = spdk_fsdev_read(fuse_io_desc(fuse_io), fuse_io->ch, fuse_io->hdr.unique,
1370 : file_object(fuse_io), file_handle(fh),
1371 0 : fsdev_io_d2h_u32(fuse_io, arg->size), fsdev_io_d2h_u64(fuse_io, arg->offset),
1372 0 : flags, fuse_io->out_iov + 1, fuse_io->out_iovcnt - 1, NULL,
1373 : do_read_cpl_clb, fuse_io);
1374 0 : if (err) {
1375 0 : fuse_dispatcher_io_complete_err(fuse_io, err);
1376 : }
1377 : }
1378 :
1379 : static void
1380 0 : do_write_cpl_clb(void *cb_arg, struct spdk_io_channel *ch, int status, uint32_t data_size)
1381 : {
1382 0 : struct fuse_io *fuse_io = cb_arg;
1383 :
1384 0 : fuse_dispatcher_io_complete_write(fuse_io, data_size, status);
1385 0 : }
1386 :
1387 : static void
1388 0 : do_write(struct fuse_io *fuse_io)
1389 : {
1390 : int err;
1391 0 : bool compat = fsdev_io_proto_minor(fuse_io) < 9;
1392 : struct fuse_write_in *arg;
1393 : uint64_t fh;
1394 0 : uint64_t flags = 0;
1395 :
1396 0 : arg = _fsdev_io_in_arg_get_buf(fuse_io,
1397 : compat ? FUSE_COMPAT_WRITE_IN_SIZE : sizeof(*arg));
1398 0 : if (!arg) {
1399 0 : SPDK_ERRLOG("Cannot get fuse_write_in\n");
1400 0 : fuse_dispatcher_io_complete_err(fuse_io, -EINVAL);
1401 0 : return;
1402 : }
1403 :
1404 0 : if (fuse_io->in_offs.buf_offs) {
1405 0 : SPDK_ERRLOG("Data IOVs should be separate from the header IOV\n");
1406 0 : fuse_dispatcher_io_complete_err(fuse_io, -EINVAL);
1407 0 : return;
1408 : }
1409 :
1410 0 : if (!compat) {
1411 0 : flags = fsdev_io_d2h_u32(fuse_io, arg->flags);
1412 : }
1413 :
1414 0 : fh = fsdev_io_d2h_u64(fuse_io, arg->fh);
1415 :
1416 0 : err = spdk_fsdev_write(fuse_io_desc(fuse_io), fuse_io->ch, fuse_io->hdr.unique,
1417 : file_object(fuse_io), file_handle(fh),
1418 0 : fsdev_io_d2h_u32(fuse_io, arg->size), fsdev_io_d2h_u64(fuse_io, arg->offset),
1419 0 : flags, fuse_io->in_iov + fuse_io->in_offs.iov_offs, fuse_io->in_iovcnt - fuse_io->in_offs.iov_offs,
1420 : NULL, do_write_cpl_clb, fuse_io);
1421 0 : if (err) {
1422 0 : fuse_dispatcher_io_complete_err(fuse_io, err);
1423 : }
1424 : }
1425 :
1426 : static void
1427 0 : do_statfs_cpl_clb(void *cb_arg, struct spdk_io_channel *ch, int status,
1428 : const struct spdk_fsdev_file_statfs *statfs)
1429 : {
1430 0 : struct fuse_io *fuse_io = cb_arg;
1431 :
1432 0 : if (!status) {
1433 0 : fuse_dispatcher_io_complete_statfs(fuse_io, statfs);
1434 : } else {
1435 0 : fuse_dispatcher_io_complete_err(fuse_io, status);
1436 : }
1437 0 : }
1438 :
1439 : static void
1440 0 : do_statfs(struct fuse_io *fuse_io)
1441 : {
1442 : int err;
1443 :
1444 0 : err = spdk_fsdev_statfs(fuse_io_desc(fuse_io), fuse_io->ch, fuse_io->hdr.unique,
1445 : file_object(fuse_io), do_statfs_cpl_clb, fuse_io);
1446 0 : if (err) {
1447 0 : fuse_dispatcher_io_complete_err(fuse_io, err);
1448 : }
1449 0 : }
1450 :
1451 : static void
1452 0 : do_release_cpl_clb(void *cb_arg, struct spdk_io_channel *ch, int status)
1453 : {
1454 0 : struct fuse_io *fuse_io = cb_arg;
1455 :
1456 0 : fuse_dispatcher_io_complete_err(fuse_io, status);
1457 0 : }
1458 :
1459 : static void
1460 0 : do_release(struct fuse_io *fuse_io)
1461 : {
1462 : int err;
1463 0 : bool compat = fsdev_io_proto_minor(fuse_io) < 8;
1464 : struct fuse_release_in *arg;
1465 : uint64_t fh;
1466 :
1467 0 : arg = _fsdev_io_in_arg_get_buf(fuse_io,
1468 : compat ? offsetof(struct fuse_release_in, lock_owner) : sizeof(*arg));
1469 0 : if (!arg) {
1470 0 : SPDK_ERRLOG("Cannot get fuse_release_in\n");
1471 0 : fuse_dispatcher_io_complete_err(fuse_io, -EINVAL);
1472 0 : return;
1473 : }
1474 :
1475 0 : fh = fsdev_io_d2h_u64(fuse_io, arg->fh);
1476 :
1477 0 : err = spdk_fsdev_release(fuse_io_desc(fuse_io), fuse_io->ch, fuse_io->hdr.unique,
1478 : file_object(fuse_io), file_handle(fh),
1479 : do_release_cpl_clb, fuse_io);
1480 0 : if (err) {
1481 0 : fuse_dispatcher_io_complete_err(fuse_io, err);
1482 : }
1483 : }
1484 :
1485 : static void
1486 0 : do_fsync_cpl_clb(void *cb_arg, struct spdk_io_channel *ch, int status)
1487 : {
1488 0 : struct fuse_io *fuse_io = cb_arg;
1489 :
1490 0 : fuse_dispatcher_io_complete_err(fuse_io, status);
1491 0 : }
1492 :
1493 : static void
1494 0 : do_fsync(struct fuse_io *fuse_io)
1495 : {
1496 : int err;
1497 : struct fuse_fsync_in *arg;
1498 : uint64_t fh;
1499 : bool datasync;
1500 :
1501 0 : arg = _fsdev_io_in_arg_get_buf(fuse_io, sizeof(*arg));
1502 0 : if (!arg) {
1503 0 : SPDK_ERRLOG("Cannot get fuse_fsync_in\n");
1504 0 : fuse_dispatcher_io_complete_err(fuse_io, -EINVAL);
1505 0 : return;
1506 : }
1507 :
1508 0 : fh = fsdev_io_d2h_u64(fuse_io, arg->fh);
1509 0 : datasync = (fsdev_io_d2h_u32(fuse_io, arg->fsync_flags) & 1) ? true : false;
1510 :
1511 0 : err = spdk_fsdev_fsync(fuse_io_desc(fuse_io), fuse_io->ch, fuse_io->hdr.unique,
1512 : file_object(fuse_io), file_handle(fh), datasync,
1513 : do_fsync_cpl_clb, fuse_io);
1514 0 : if (err) {
1515 0 : fuse_dispatcher_io_complete_err(fuse_io, err);
1516 : }
1517 : }
1518 :
1519 : static void
1520 0 : do_setxattr_cpl_clb(void *cb_arg, struct spdk_io_channel *ch, int status)
1521 : {
1522 0 : struct fuse_io *fuse_io = cb_arg;
1523 :
1524 0 : fuse_dispatcher_io_complete_err(fuse_io, status);
1525 0 : }
1526 :
1527 : static void
1528 0 : do_setxattr(struct fuse_io *fuse_io)
1529 : {
1530 : int err;
1531 : struct fuse_setxattr_in *arg;
1532 : const char *name;
1533 : const char *value;
1534 : uint32_t size;
1535 :
1536 0 : arg = _fsdev_io_in_arg_get_buf(fuse_io, sizeof(*arg));
1537 0 : if (!arg) {
1538 0 : SPDK_ERRLOG("Cannot get fuse_setxattr_in\n");
1539 0 : fuse_dispatcher_io_complete_err(fuse_io, -EINVAL);
1540 0 : return;
1541 : }
1542 :
1543 0 : name = _fsdev_io_in_arg_get_str(fuse_io);
1544 0 : if (!name) {
1545 0 : SPDK_ERRLOG("Cannot get name\n");
1546 0 : fuse_dispatcher_io_complete_err(fuse_io, -EINVAL);
1547 0 : return;
1548 : }
1549 :
1550 0 : size = fsdev_io_d2h_u32(fuse_io, arg->size);
1551 0 : value = _fsdev_io_in_arg_get_buf(fuse_io, size);
1552 0 : if (!value) {
1553 0 : SPDK_ERRLOG("Cannot get value of %" PRIu32 " bytes\n", size);
1554 0 : fuse_dispatcher_io_complete_err(fuse_io, -EINVAL);
1555 0 : return;
1556 : }
1557 :
1558 0 : err = spdk_fsdev_setxattr(fuse_io_desc(fuse_io), fuse_io->ch, fuse_io->hdr.unique,
1559 : file_object(fuse_io), name, value, size, fsdev_io_d2h_u32(fuse_io, arg->flags),
1560 : do_setxattr_cpl_clb, fuse_io);
1561 0 : if (err) {
1562 0 : fuse_dispatcher_io_complete_err(fuse_io, err);
1563 : }
1564 : }
1565 :
1566 : static void
1567 0 : do_getxattr_cpl_clb(void *cb_arg, struct spdk_io_channel *ch, int status, size_t value_size)
1568 : {
1569 0 : struct fuse_io *fuse_io = cb_arg;
1570 :
1571 0 : if (!status) {
1572 0 : fuse_dispatcher_io_complete_xattr(fuse_io, value_size);
1573 : } else {
1574 0 : fuse_dispatcher_io_complete_err(fuse_io, status);
1575 : }
1576 0 : }
1577 :
1578 : static void
1579 0 : do_getxattr(struct fuse_io *fuse_io)
1580 : {
1581 : int err;
1582 : struct fuse_getxattr_in *arg;
1583 : const char *name;
1584 : char *buff;
1585 : uint32_t size;
1586 : struct iov_offs out_offs_bu;
1587 :
1588 0 : arg = _fsdev_io_in_arg_get_buf(fuse_io, sizeof(*arg));
1589 0 : if (!arg) {
1590 0 : SPDK_ERRLOG("Cannot get fuse_getxattr_in\n");
1591 0 : fuse_dispatcher_io_complete_err(fuse_io, -EINVAL);
1592 0 : return;
1593 : }
1594 :
1595 0 : name = _fsdev_io_in_arg_get_str(fuse_io);
1596 0 : if (!name) {
1597 0 : SPDK_ERRLOG("Cannot get name\n");
1598 0 : fuse_dispatcher_io_complete_err(fuse_io, -EINVAL);
1599 0 : return;
1600 : }
1601 :
1602 0 : if (fuse_io->out_iovcnt < 2) {
1603 0 : SPDK_ERRLOG("No buffer to getxattr\n");
1604 0 : fuse_dispatcher_io_complete_err(fuse_io, -EINVAL);
1605 0 : return;
1606 : }
1607 :
1608 0 : size = fsdev_io_d2h_u32(fuse_io, arg->size);
1609 :
1610 : /* NOTE: we want to avoid an additionl allocation and copy and put the xattr directly to the buffer provided in out_iov.
1611 : * In order to do so we have to preserve the out_offs, advance it to get the buffer pointer and then restore to allow
1612 : * the fuse_dispatcher_io_complete_xattr() to fill the fuse_getxattr_out which precedes this buffer.
1613 : */
1614 0 : out_offs_bu = fuse_io->out_offs; /* Preserve the out offset */
1615 :
1616 : /* Skip the fuse_getxattr_out */
1617 0 : _fsdev_io_out_arg_get_buf(fuse_io, sizeof(struct fuse_getxattr_out));
1618 0 : size -= sizeof(struct fuse_getxattr_out);
1619 :
1620 0 : buff = _fsdev_io_out_arg_get_buf(fuse_io, size); /* Get the buffer for the xattr */
1621 0 : if (!buff) {
1622 0 : SPDK_INFOLOG(fuse_dispatcher, "NULL buffer, probably asking for the size\n");
1623 0 : size = 0;
1624 : }
1625 :
1626 0 : fuse_io->out_offs = out_offs_bu; /* Restore the out offset */
1627 :
1628 0 : err = spdk_fsdev_getxattr(fuse_io_desc(fuse_io), fuse_io->ch, fuse_io->hdr.unique,
1629 : file_object(fuse_io), name, buff, size,
1630 : do_getxattr_cpl_clb, fuse_io);
1631 0 : if (err) {
1632 0 : fuse_dispatcher_io_complete_err(fuse_io, err);
1633 : }
1634 : }
1635 :
1636 : static void
1637 0 : do_listxattr_cpl_clb(void *cb_arg, struct spdk_io_channel *ch, int status, size_t size,
1638 : bool size_only)
1639 : {
1640 0 : struct fuse_io *fuse_io = cb_arg;
1641 :
1642 0 : if (status) {
1643 0 : fuse_dispatcher_io_complete_err(fuse_io, status);
1644 0 : } else if (size_only) {
1645 0 : fuse_dispatcher_io_complete_xattr(fuse_io, size);
1646 : } else {
1647 0 : fuse_dispatcher_io_complete_ok(fuse_io, size);
1648 : }
1649 0 : }
1650 :
1651 : static void
1652 0 : do_listxattr(struct fuse_io *fuse_io)
1653 : {
1654 : int err;
1655 : struct fuse_getxattr_in *arg;
1656 : struct iovec *iov;
1657 : uint32_t size;
1658 :
1659 0 : arg = _fsdev_io_in_arg_get_buf(fuse_io, sizeof(*arg));
1660 0 : if (!arg) {
1661 0 : SPDK_ERRLOG("Cannot get fuse_getxattr_in\n");
1662 0 : fuse_dispatcher_io_complete_err(fuse_io, -EINVAL);
1663 0 : return;
1664 : }
1665 :
1666 0 : size = fsdev_io_d2h_u32(fuse_io, arg->size);
1667 0 : iov = fuse_io->out_iov + 1;
1668 0 : if (iov->iov_len < size) {
1669 0 : SPDK_ERRLOG("Wrong iov len (%zu < %" PRIu32")\n", iov->iov_len, size);
1670 0 : fuse_dispatcher_io_complete_err(fuse_io, -EINVAL);
1671 0 : return;
1672 : }
1673 :
1674 0 : err = spdk_fsdev_listxattr(fuse_io_desc(fuse_io), fuse_io->ch, fuse_io->hdr.unique,
1675 0 : file_object(fuse_io), iov->iov_base, size,
1676 : do_listxattr_cpl_clb, fuse_io);
1677 0 : if (err) {
1678 0 : fuse_dispatcher_io_complete_err(fuse_io, err);
1679 : }
1680 : }
1681 :
1682 : static void
1683 0 : do_removexattr_cpl_clb(void *cb_arg, struct spdk_io_channel *ch, int status)
1684 : {
1685 0 : struct fuse_io *fuse_io = cb_arg;
1686 :
1687 0 : fuse_dispatcher_io_complete_err(fuse_io, status);
1688 0 : }
1689 :
1690 : static void
1691 0 : do_removexattr(struct fuse_io *fuse_io)
1692 : {
1693 : int err;
1694 0 : const char *name = _fsdev_io_in_arg_get_str(fuse_io);
1695 :
1696 0 : if (!name) {
1697 0 : SPDK_ERRLOG("Cannot get name\n");
1698 0 : fuse_dispatcher_io_complete_err(fuse_io, -EINVAL);
1699 0 : return;
1700 : }
1701 :
1702 0 : err = spdk_fsdev_removexattr(fuse_io_desc(fuse_io), fuse_io->ch, fuse_io->hdr.unique,
1703 : file_object(fuse_io), name, do_removexattr_cpl_clb, fuse_io);
1704 0 : if (err) {
1705 0 : fuse_dispatcher_io_complete_err(fuse_io, err);
1706 : }
1707 : }
1708 :
1709 : static void
1710 0 : do_flush_cpl_clb(void *cb_arg, struct spdk_io_channel *ch, int status)
1711 : {
1712 0 : struct fuse_io *fuse_io = cb_arg;
1713 :
1714 0 : fuse_dispatcher_io_complete_err(fuse_io, status);
1715 0 : }
1716 :
1717 : static void
1718 0 : do_flush(struct fuse_io *fuse_io)
1719 : {
1720 : int err;
1721 0 : bool compat = fsdev_io_proto_minor(fuse_io) < 7;
1722 : struct fuse_flush_in *arg;
1723 : uint64_t fh;
1724 :
1725 0 : arg = _fsdev_io_in_arg_get_buf(fuse_io,
1726 : compat ? offsetof(struct fuse_flush_in, lock_owner) : sizeof(*arg));
1727 0 : if (!arg) {
1728 0 : SPDK_ERRLOG("Cannot get fuse_flush_in\n");
1729 0 : fuse_dispatcher_io_complete_err(fuse_io, -EINVAL);
1730 0 : return;
1731 : }
1732 :
1733 0 : fh = fsdev_io_d2h_u64(fuse_io, arg->fh);
1734 :
1735 0 : err = spdk_fsdev_flush(fuse_io_desc(fuse_io), fuse_io->ch, fuse_io->hdr.unique,
1736 : file_object(fuse_io), file_handle(fh),
1737 : do_flush_cpl_clb, fuse_io);
1738 0 : if (err) {
1739 0 : fuse_dispatcher_io_complete_err(fuse_io, err);
1740 : }
1741 : }
1742 :
1743 : static void
1744 0 : fuse_dispatcher_close_fsdev_and_complete_msg(void *ctx)
1745 : {
1746 0 : struct fuse_io *fuse_io = ctx;
1747 0 : struct spdk_fuse_dispatcher *disp = fuse_io->disp;
1748 :
1749 0 : spdk_fsdev_close(disp->desc);
1750 :
1751 0 : SPDK_DEBUGLOG(fuse_dispatcher, "%s: fdev closed\n", fuse_dispatcher_name(disp));
1752 :
1753 0 : disp->desc = NULL;
1754 0 : disp->fsdev_thread = NULL;
1755 :
1756 0 : fuse_dispatcher_io_complete_err(fuse_io, fuse_io->u.fsdev_close.status);
1757 0 : }
1758 :
1759 : static void
1760 0 : fuse_dispatcher_close_fsdev_and_complete(struct fuse_io *fuse_io, int status)
1761 : {
1762 0 : struct spdk_fuse_dispatcher *disp = fuse_io->disp;
1763 :
1764 0 : assert(disp->desc);
1765 :
1766 0 : fuse_io->u.fsdev_close.status = status;
1767 :
1768 0 : if (disp->fsdev_thread != spdk_get_thread()) {
1769 0 : spdk_thread_send_msg(disp->fsdev_thread, fuse_dispatcher_close_fsdev_and_complete_msg, fuse_io);
1770 : } else {
1771 0 : fuse_dispatcher_close_fsdev_and_complete_msg(fuse_io);
1772 : }
1773 0 : }
1774 :
1775 : static void fuse_dispatcher_open_fsdev_rollback(struct fuse_io *fuse_io);
1776 :
1777 : static void
1778 0 : do_root_lookup_cpl_clb(void *cb_arg, struct spdk_io_channel *ch, int status,
1779 : struct spdk_fsdev_file_object *fobject, const struct spdk_fsdev_file_attr *attr)
1780 : {
1781 0 : struct fuse_io *fuse_io = cb_arg;
1782 0 : struct spdk_fuse_dispatcher *disp = fuse_io->disp;
1783 :
1784 0 : if (!status) {
1785 0 : disp->root_fobject = fobject;
1786 0 : SPDK_DEBUGLOG(fuse_dispatcher, "root fobject successfully acquired\n");
1787 0 : fuse_dispatcher_io_complete_ok(fuse_io, fuse_io->u.init.out_len);
1788 : } else {
1789 0 : SPDK_ERRLOG("Failed to lookup for root (err=%d)\n", status);
1790 0 : fuse_dispatcher_open_fsdev_rollback(fuse_io);
1791 : }
1792 0 : }
1793 :
1794 : static void
1795 0 : fuse_dispatcher_err_put_channel(struct spdk_io_channel_iter *i)
1796 : {
1797 0 : struct spdk_io_channel *io_ch = spdk_io_channel_iter_get_channel(i);
1798 0 : struct spdk_fuse_dispatcher_channel *ch = __disp_ch_from_io_ch(io_ch);
1799 :
1800 0 : if (ch->fsdev_io_ch) {
1801 0 : spdk_put_io_channel(ch->fsdev_io_ch);
1802 0 : ch->fsdev_io_ch = NULL;
1803 : }
1804 :
1805 0 : spdk_for_each_channel_continue(i, 0);
1806 0 : }
1807 :
1808 : static void
1809 0 : fuse_dispatcher_err_put_channel_done(struct spdk_io_channel_iter *i, int status)
1810 : {
1811 0 : struct fuse_io *fuse_io = spdk_io_channel_iter_get_ctx(i);
1812 0 : struct spdk_fuse_dispatcher *disp = fuse_io->disp;
1813 :
1814 0 : if (status) {
1815 0 : SPDK_WARNLOG("%s: putting channels failed with %d\n", fuse_dispatcher_name(disp), status);
1816 : /* For now, we continue anyway. We can retry fuse_dispatcher_open_fsdev_rollback, for example */
1817 : }
1818 :
1819 0 : SPDK_DEBUGLOG(fuse_dispatcher, "%s: putting channels succeeded. Releasing the fdev\n",
1820 : fuse_dispatcher_name(disp));
1821 :
1822 0 : fuse_dispatcher_close_fsdev_and_complete(fuse_io, ENODEV);
1823 0 : }
1824 :
1825 : static void
1826 0 : fuse_dispatcher_open_fsdev_rollback(struct fuse_io *fuse_io)
1827 : {
1828 0 : struct spdk_fuse_dispatcher *disp = fuse_io->disp;
1829 :
1830 0 : spdk_for_each_channel(__disp_to_io_dev(disp),
1831 : fuse_dispatcher_err_put_channel,
1832 : fuse_io,
1833 : fuse_dispatcher_err_put_channel_done);
1834 0 : }
1835 :
1836 : static void
1837 0 : fuse_dispatcher_open_fsdev_continue(struct fuse_io *fuse_io)
1838 : {
1839 0 : struct spdk_fuse_dispatcher *disp = fuse_io->disp;
1840 0 : struct fuse_init_out outarg;
1841 0 : size_t outargsize = sizeof(outarg);
1842 0 : uint32_t max_readahead = DEFAULT_MAX_READAHEAD;
1843 0 : uint32_t flags = 0;
1844 : void *out_buf;
1845 : int res;
1846 :
1847 0 : assert(disp->desc);
1848 :
1849 0 : memset(&outarg, 0, sizeof(outarg));
1850 0 : outarg.major = fsdev_io_h2d_u32(fuse_io, FUSE_KERNEL_VERSION);
1851 0 : outarg.minor = fsdev_io_h2d_u32(fuse_io, FUSE_KERNEL_MINOR_VERSION);
1852 :
1853 0 : if (disp->proto_minor < 5) {
1854 0 : outargsize = FUSE_COMPAT_INIT_OUT_SIZE;
1855 0 : } else if (disp->proto_minor < 23) {
1856 0 : outargsize = FUSE_COMPAT_22_INIT_OUT_SIZE;
1857 : }
1858 :
1859 0 : if (!fuse_io->u.init.legacy_in) {
1860 0 : max_readahead = fsdev_io_d2h_u32(fuse_io, fuse_io->u.init.in->max_readahead);
1861 0 : flags = fsdev_io_d2h_u32(fuse_io, fuse_io->u.init.in->flags);
1862 :
1863 0 : SPDK_INFOLOG(fuse_dispatcher, "max_readahead: %" PRIu32 " flags=0x%" PRIx32 "\n",
1864 : max_readahead, flags);
1865 : }
1866 :
1867 : /* Always enable big writes, this is superseded by the max_write option */
1868 0 : outarg.flags = FUSE_BIG_WRITES;
1869 :
1870 : #define LL_SET_DEFAULT(cond, cap) \
1871 : if ((cond) && flags & (cap)) \
1872 : outarg.flags |= (cap)
1873 0 : LL_SET_DEFAULT(true, FUSE_ASYNC_READ);
1874 0 : LL_SET_DEFAULT(true, FUSE_AUTO_INVAL_DATA);
1875 0 : LL_SET_DEFAULT(true, FUSE_ASYNC_DIO);
1876 0 : LL_SET_DEFAULT(true, FUSE_ATOMIC_O_TRUNC);
1877 0 : LL_SET_DEFAULT(true, FUSE_FLOCK_LOCKS);
1878 0 : LL_SET_DEFAULT(true, FUSE_DO_READDIRPLUS);
1879 0 : LL_SET_DEFAULT(true, FUSE_READDIRPLUS_AUTO);
1880 0 : LL_SET_DEFAULT(true, FUSE_EXPORT_SUPPORT);
1881 0 : LL_SET_DEFAULT(fuse_io->u.init.opts.writeback_cache_enabled, FUSE_WRITEBACK_CACHE);
1882 :
1883 0 : outarg.flags = fsdev_io_h2d_u32(fuse_io, outarg.flags);
1884 0 : outarg.max_readahead = fsdev_io_h2d_u32(fuse_io, max_readahead);
1885 0 : outarg.max_write = fsdev_io_h2d_u32(fuse_io, fuse_io->u.init.opts.max_write);
1886 0 : if (fsdev_io_proto_minor(fuse_io) >= 13) {
1887 0 : outarg.max_background = fsdev_io_h2d_u16(fuse_io, DEFAULT_MAX_BACKGROUND);
1888 0 : outarg.congestion_threshold = fsdev_io_h2d_u16(fuse_io, DEFAULT_CONGESTION_THRESHOLD);
1889 : }
1890 :
1891 0 : if (fsdev_io_proto_minor(fuse_io) >= 23) {
1892 0 : outarg.time_gran = fsdev_io_h2d_u32(fuse_io, DEFAULT_TIME_GRAN);
1893 : }
1894 :
1895 0 : SPDK_INFOLOG(fuse_dispatcher, "INIT: %" PRIu32 ".%" PRIu32 "\n",
1896 : fsdev_io_d2h_u32(fuse_io, outarg.major), fsdev_io_d2h_u32(fuse_io, outarg.minor));
1897 0 : SPDK_INFOLOG(fuse_dispatcher, "flags: 0x%08" PRIx32 "\n", fsdev_io_d2h_u32(fuse_io, outarg.flags));
1898 0 : SPDK_INFOLOG(fuse_dispatcher, "max_readahead: %" PRIu32 "\n",
1899 : fsdev_io_d2h_u32(fuse_io, outarg.max_readahead));
1900 0 : SPDK_INFOLOG(fuse_dispatcher, "max_write: %" PRIu32 "\n",
1901 : fsdev_io_d2h_u32(fuse_io, outarg.max_write));
1902 0 : SPDK_INFOLOG(fuse_dispatcher, "max_background: %" PRIu16 "\n",
1903 : fsdev_io_d2h_u16(fuse_io, outarg.max_background));
1904 0 : SPDK_INFOLOG(fuse_dispatcher, "congestion_threshold: %" PRIu16 "\n",
1905 : fsdev_io_d2h_u16(fuse_io, outarg.congestion_threshold));
1906 0 : SPDK_INFOLOG(fuse_dispatcher, "time_gran: %" PRIu32 "\n", fsdev_io_d2h_u32(fuse_io,
1907 : outarg.time_gran));
1908 :
1909 0 : out_buf = _fsdev_io_out_arg_get_buf(fuse_io, outargsize);
1910 0 : if (!out_buf) {
1911 0 : SPDK_ERRLOG("Cannot get buf to copy %zu bytes\n", outargsize);
1912 0 : fuse_dispatcher_open_fsdev_rollback(fuse_io);
1913 0 : return;
1914 : }
1915 :
1916 0 : memcpy(out_buf, &outarg, outargsize);
1917 :
1918 0 : fuse_io->u.init.out_len = outargsize;
1919 :
1920 0 : res = spdk_fsdev_lookup(fuse_io_desc(fuse_io), fuse_io->ch, 0, NULL /* root */,
1921 : "" /* will be ignored */, do_root_lookup_cpl_clb, fuse_io);
1922 0 : if (res) {
1923 0 : SPDK_ERRLOG("Failed to initiate lookup for the root (err=%d)\n", res);
1924 0 : fuse_dispatcher_open_fsdev_rollback(fuse_io);
1925 0 : return;
1926 : }
1927 : }
1928 :
1929 : static void
1930 0 : fuse_dispatcher_get_channel(struct spdk_io_channel_iter *i)
1931 : {
1932 0 : struct fuse_io *fuse_io = spdk_io_channel_iter_get_ctx(i);
1933 0 : struct spdk_io_channel *io_ch = spdk_io_channel_iter_get_channel(i);
1934 0 : struct spdk_fuse_dispatcher_channel *ch = __disp_ch_from_io_ch(io_ch);
1935 0 : struct spdk_fuse_dispatcher *disp = fuse_io->disp;
1936 :
1937 0 : assert(!ch->fsdev_io_ch);
1938 :
1939 0 : ch->fsdev_io_ch = spdk_fsdev_get_io_channel(disp->desc);
1940 :
1941 0 : if (spdk_io_channel_get_thread(io_ch) == fuse_io->u.init.thread) {
1942 0 : fuse_io->ch = ch->fsdev_io_ch;
1943 : }
1944 :
1945 0 : spdk_for_each_channel_continue(i, 0);
1946 0 : }
1947 :
1948 : static void
1949 0 : fuse_dispatcher_get_channel_done(struct spdk_io_channel_iter *i, int status)
1950 : {
1951 0 : struct fuse_io *fuse_io = spdk_io_channel_iter_get_ctx(i);
1952 0 : struct spdk_fuse_dispatcher *disp = fuse_io->disp;
1953 :
1954 0 : if (status) {
1955 0 : SPDK_ERRLOG("%s: getting channels failed with %d\n", fuse_dispatcher_name(disp), status);
1956 0 : fuse_dispatcher_open_fsdev_rollback(fuse_io);
1957 0 : return;
1958 : }
1959 :
1960 0 : SPDK_DEBUGLOG(fuse_dispatcher, "%s: getting succeeded\n", fuse_dispatcher_name(disp));
1961 0 : fuse_dispatcher_open_fsdev_continue(fuse_io);
1962 : }
1963 :
1964 : static void
1965 0 : fuse_dispatcher_fsdev_remove_put_channel(struct spdk_io_channel_iter *i)
1966 : {
1967 0 : struct spdk_io_channel *io_ch = spdk_io_channel_iter_get_channel(i);
1968 0 : struct spdk_fuse_dispatcher_channel *ch = __disp_ch_from_io_ch(io_ch);
1969 :
1970 0 : assert(ch->fsdev_io_ch);
1971 0 : spdk_put_io_channel(ch->fsdev_io_ch);
1972 0 : ch->fsdev_io_ch = NULL;
1973 :
1974 0 : spdk_for_each_channel_continue(i, 0);
1975 0 : }
1976 :
1977 : static void
1978 0 : fuse_dispatcher_fsdev_remove_put_channel_done(struct spdk_io_channel_iter *i, int status)
1979 : {
1980 0 : struct fuse_io *fuse_io = spdk_io_channel_iter_get_ctx(i);
1981 0 : struct spdk_fuse_dispatcher *disp = fuse_io->disp;
1982 :
1983 0 : if (status) {
1984 0 : SPDK_WARNLOG("%s: putting channels failed with %d\n", fuse_dispatcher_name(disp), status);
1985 : }
1986 :
1987 0 : disp->event_cb(SPDK_FUSE_DISP_EVENT_FSDEV_REMOVE, disp, disp->event_ctx);
1988 0 : }
1989 :
1990 : static void
1991 0 : fuse_dispatcher_fsdev_event_cb(enum spdk_fsdev_event_type type, struct spdk_fsdev *fsdev,
1992 : void *event_ctx)
1993 : {
1994 0 : struct spdk_fuse_dispatcher *disp = event_ctx;
1995 :
1996 0 : SPDK_NOTICELOG("%s received fsdev event %d\n", fuse_dispatcher_name(disp), type);
1997 :
1998 0 : switch (type) {
1999 0 : case SPDK_FSDEV_EVENT_REMOVE:
2000 0 : SPDK_NOTICELOG("%s received SPDK_FSDEV_EVENT_REMOVE\n", fuse_dispatcher_name(disp));
2001 : /* Put the channels, to prevent the further IO submission */
2002 0 : spdk_for_each_channel(__disp_to_io_dev(disp),
2003 : fuse_dispatcher_fsdev_remove_put_channel,
2004 : disp,
2005 : fuse_dispatcher_fsdev_remove_put_channel_done);
2006 0 : break;
2007 0 : default:
2008 0 : SPDK_NOTICELOG("%s received an unknown fsdev event %d\n", fuse_dispatcher_name(disp), type);
2009 0 : break;
2010 : }
2011 0 : }
2012 :
2013 : static bool
2014 0 : fuse_dispatcher_open_fsdev(struct fuse_io *fuse_io)
2015 : {
2016 0 : struct spdk_fuse_dispatcher *disp = fuse_io->disp;
2017 : int rc;
2018 :
2019 0 : assert(!disp->desc);
2020 :
2021 0 : rc = spdk_fsdev_open(disp->fsdev_name, fuse_dispatcher_fsdev_event_cb, disp, &fuse_io->u.init.opts,
2022 : &disp->desc);
2023 0 : if (rc) {
2024 0 : SPDK_ERRLOG("spdk_fsdev_open failed with %d\n", rc);
2025 0 : return false;
2026 : }
2027 :
2028 0 : disp->fsdev_thread = spdk_get_thread();
2029 :
2030 0 : SPDK_DEBUGLOG(fuse_dispatcher, "%s: spdk_fsdev_open succeeded\n", fuse_dispatcher_name(disp));
2031 :
2032 0 : spdk_for_each_channel(__disp_to_io_dev(disp),
2033 : fuse_dispatcher_get_channel,
2034 : fuse_io,
2035 : fuse_dispatcher_get_channel_done);
2036 0 : return true;
2037 : }
2038 :
2039 : static void
2040 0 : do_init(struct fuse_io *fuse_io)
2041 : {
2042 0 : size_t compat_size = offsetof(struct fuse_init_in, max_readahead);
2043 0 : struct spdk_fuse_dispatcher *disp = fuse_io->disp;
2044 0 : uint32_t flags = 0;
2045 :
2046 : /* First try to read the legacy header */
2047 0 : fuse_io->u.init.in = _fsdev_io_in_arg_get_buf(fuse_io, compat_size);
2048 0 : if (!fuse_io->u.init.in) {
2049 0 : SPDK_ERRLOG("Cannot get fuse_init_in\n");
2050 0 : fuse_dispatcher_io_complete_err(fuse_io, -EBADR);
2051 0 : return;
2052 : }
2053 :
2054 0 : disp->proto_major = fsdev_io_d2h_u32(fuse_io, fuse_io->u.init.in->major);
2055 0 : disp->proto_minor = fsdev_io_d2h_u32(fuse_io, fuse_io->u.init.in->minor);
2056 :
2057 0 : SPDK_DEBUGLOG(fuse_dispatcher, "Proto version: %" PRIu32 ".%" PRIu32 "\n",
2058 : disp->proto_major,
2059 : disp->proto_minor);
2060 :
2061 : /* Now try to read the whole struct */
2062 0 : if (disp->proto_major == 7 && disp->proto_minor >= 6) {
2063 0 : void *arg_extra = _fsdev_io_in_arg_get_buf(fuse_io, sizeof(*fuse_io->u.init.in) - compat_size);
2064 0 : if (!arg_extra) {
2065 0 : SPDK_ERRLOG("INIT: protocol version: %" PRIu32 ".%" PRIu32 " but legacy data found\n",
2066 : disp->proto_major, disp->proto_minor);
2067 0 : fuse_dispatcher_io_complete_err(fuse_io, -EINVAL);
2068 0 : return;
2069 : }
2070 0 : fuse_io->u.init.legacy_in = false;
2071 : } else {
2072 0 : fuse_io->u.init.legacy_in = true;
2073 : }
2074 :
2075 0 : if (disp->proto_major < 7) {
2076 0 : SPDK_ERRLOG("INIT: unsupported major protocol version: %" PRIu32 "\n",
2077 : disp->proto_major);
2078 0 : fuse_dispatcher_io_complete_err(fuse_io, -EAGAIN);
2079 0 : return;
2080 : }
2081 :
2082 0 : if (disp->proto_major > 7) {
2083 : /* Wait for a second INIT request with a 7.X version */
2084 :
2085 0 : struct fuse_init_out outarg;
2086 0 : size_t outargsize = sizeof(outarg);
2087 :
2088 0 : memset(&outarg, 0, sizeof(outarg));
2089 0 : outarg.major = fsdev_io_h2d_u32(fuse_io, FUSE_KERNEL_VERSION);
2090 0 : outarg.minor = fsdev_io_h2d_u32(fuse_io, FUSE_KERNEL_MINOR_VERSION);
2091 :
2092 0 : fuse_dispatcher_io_copy_and_complete(fuse_io, &outarg, outargsize, 0);
2093 0 : return;
2094 : }
2095 :
2096 0 : if (!fuse_io->u.init.legacy_in) {
2097 0 : flags = fsdev_io_d2h_u32(fuse_io, fuse_io->u.init.in->flags);
2098 :
2099 0 : SPDK_INFOLOG(fuse_dispatcher, "flags=0x%" PRIx32 "\n", flags);
2100 : }
2101 :
2102 0 : memset(&fuse_io->u.init.opts, 0, sizeof(fuse_io->u.init.opts));
2103 0 : fuse_io->u.init.opts.opts_size = sizeof(fuse_io->u.init.opts);
2104 0 : fuse_io->u.init.opts.max_write = 0;
2105 0 : fuse_io->u.init.opts.writeback_cache_enabled = flags & FUSE_WRITEBACK_CACHE ? true : false;
2106 0 : fuse_io->u.init.thread = spdk_get_thread();
2107 :
2108 0 : if (!fuse_dispatcher_open_fsdev(fuse_io)) {
2109 0 : SPDK_ERRLOG("Cannot open underying fsdev\n");
2110 0 : fuse_dispatcher_io_complete_err(fuse_io, -ENODEV);
2111 0 : return;
2112 : }
2113 : }
2114 :
2115 : static void
2116 0 : do_opendir_cpl_clb(void *cb_arg, struct spdk_io_channel *ch, int status,
2117 : struct spdk_fsdev_file_handle *fhandle)
2118 : {
2119 0 : struct fuse_io *fuse_io = cb_arg;
2120 :
2121 0 : if (!status) {
2122 0 : fuse_dispatcher_io_complete_open(fuse_io, fhandle);
2123 : } else {
2124 0 : fuse_dispatcher_io_complete_err(fuse_io, status);
2125 : }
2126 0 : }
2127 :
2128 : static void
2129 0 : do_opendir(struct fuse_io *fuse_io)
2130 : {
2131 : int err;
2132 : struct fuse_open_in *arg;
2133 :
2134 0 : arg = _fsdev_io_in_arg_get_buf(fuse_io, sizeof(*arg));
2135 0 : if (!arg) {
2136 0 : SPDK_ERRLOG("Cannot get fuse_open_in\n");
2137 0 : fuse_dispatcher_io_complete_err(fuse_io, -EINVAL);
2138 0 : return;
2139 : }
2140 :
2141 0 : err = spdk_fsdev_opendir(fuse_io_desc(fuse_io), fuse_io->ch, fuse_io->hdr.unique,
2142 : file_object(fuse_io), fsdev_io_d2h_u32(fuse_io, arg->flags),
2143 : do_opendir_cpl_clb, fuse_io);
2144 0 : if (err) {
2145 0 : fuse_dispatcher_io_complete_err(fuse_io, err);
2146 : }
2147 : }
2148 :
2149 : static int
2150 0 : do_readdir_entry_clb(void *cb_arg, struct spdk_io_channel *ch, const char *name,
2151 : struct spdk_fsdev_file_object *fobject, const struct spdk_fsdev_file_attr *attr, off_t offset)
2152 : {
2153 0 : struct fuse_io *fuse_io = cb_arg;
2154 0 : size_t bytes_remained = fuse_io->u.readdir.size - fuse_io->u.readdir.bytes_written;
2155 : size_t direntry_bytes;
2156 :
2157 0 : direntry_bytes = fuse_io->u.readdir.plus ?
2158 0 : fuse_dispatcher_add_direntry_plus(fuse_io, fuse_io->u.readdir.writep, bytes_remained,
2159 0 : name, fobject, attr, offset) :
2160 0 : fuse_dispatcher_add_direntry(fuse_io, fuse_io->u.readdir.writep, bytes_remained,
2161 : name, fobject, attr, offset);
2162 :
2163 0 : if (direntry_bytes > bytes_remained) {
2164 0 : return EAGAIN;
2165 : }
2166 :
2167 0 : fuse_io->u.readdir.writep += direntry_bytes;
2168 0 : fuse_io->u.readdir.bytes_written += direntry_bytes;
2169 :
2170 0 : return 0;
2171 : }
2172 :
2173 : static void
2174 0 : do_readdir_cpl_clb(void *cb_arg, struct spdk_io_channel *ch, int status)
2175 : {
2176 0 : struct fuse_io *fuse_io = cb_arg;
2177 :
2178 0 : if (!status || (status == EAGAIN && fuse_io->u.readdir.bytes_written == fuse_io->u.readdir.size)) {
2179 0 : fuse_dispatcher_io_complete_ok(fuse_io, fuse_io->u.readdir.bytes_written);
2180 : } else {
2181 0 : fuse_dispatcher_io_complete_err(fuse_io, status);
2182 : }
2183 0 : }
2184 :
2185 : static void
2186 0 : do_readdir_common(struct fuse_io *fuse_io, bool plus)
2187 : {
2188 : int err;
2189 : struct fuse_read_in *arg;
2190 : uint64_t fh;
2191 : uint32_t size;
2192 :
2193 0 : arg = _fsdev_io_in_arg_get_buf(fuse_io, sizeof(*arg));
2194 0 : if (!arg) {
2195 0 : SPDK_ERRLOG("Cannot get fuse_read_in\n");
2196 0 : fuse_dispatcher_io_complete_err(fuse_io, -EINVAL);
2197 0 : return;
2198 : }
2199 :
2200 0 : size = fsdev_io_d2h_u32(fuse_io, arg->size);
2201 :
2202 0 : fuse_io->u.readdir.writep = _fsdev_io_out_arg_get_buf(fuse_io, size);
2203 0 : if (!fuse_io->u.readdir.writep) {
2204 0 : SPDK_ERRLOG("Cannot get buffer of %" PRIu32 " bytes\n", size);
2205 0 : fuse_dispatcher_io_complete_err(fuse_io, -EINVAL);
2206 0 : return;
2207 : }
2208 :
2209 0 : fuse_io->u.readdir.plus = plus;
2210 0 : fuse_io->u.readdir.size = size;
2211 0 : fuse_io->u.readdir.bytes_written = 0;
2212 :
2213 0 : fh = fsdev_io_d2h_u64(fuse_io, arg->fh);
2214 :
2215 0 : err = spdk_fsdev_readdir(fuse_io_desc(fuse_io), fuse_io->ch, fuse_io->hdr.unique,
2216 : file_object(fuse_io), file_handle(fh),
2217 : fsdev_io_d2h_u64(fuse_io, arg->offset),
2218 : do_readdir_entry_clb, do_readdir_cpl_clb, fuse_io);
2219 0 : if (err) {
2220 0 : fuse_dispatcher_io_complete_err(fuse_io, err);
2221 : }
2222 : }
2223 :
2224 : static void
2225 0 : do_readdir(struct fuse_io *fuse_io)
2226 : {
2227 0 : do_readdir_common(fuse_io, false);
2228 0 : }
2229 :
2230 : static void
2231 0 : do_readdirplus(struct fuse_io *fuse_io)
2232 : {
2233 0 : do_readdir_common(fuse_io, true);
2234 0 : }
2235 :
2236 : static void
2237 0 : do_releasedir_cpl_clb(void *cb_arg, struct spdk_io_channel *ch, int status)
2238 : {
2239 0 : struct fuse_io *fuse_io = cb_arg;
2240 :
2241 0 : fuse_dispatcher_io_complete_err(fuse_io, status);
2242 0 : }
2243 :
2244 : static void
2245 0 : do_releasedir(struct fuse_io *fuse_io)
2246 : {
2247 : int err;
2248 : struct fuse_release_in *arg;
2249 : uint64_t fh;
2250 :
2251 0 : arg = _fsdev_io_in_arg_get_buf(fuse_io, sizeof(*arg));
2252 0 : if (!arg) {
2253 0 : SPDK_ERRLOG("Cannot get fuse_release_in\n");
2254 0 : fuse_dispatcher_io_complete_err(fuse_io, -EINVAL);
2255 0 : return;
2256 : }
2257 :
2258 0 : fh = fsdev_io_d2h_u64(fuse_io, arg->fh);
2259 :
2260 0 : err = spdk_fsdev_releasedir(fuse_io_desc(fuse_io), fuse_io->ch, fuse_io->hdr.unique,
2261 : file_object(fuse_io), file_handle(fh),
2262 : do_releasedir_cpl_clb, fuse_io);
2263 0 : if (err) {
2264 0 : fuse_dispatcher_io_complete_err(fuse_io, err);
2265 : }
2266 : }
2267 :
2268 : static void
2269 0 : do_fsyncdir_cpl_clb(void *cb_arg, struct spdk_io_channel *ch, int status)
2270 : {
2271 0 : struct fuse_io *fuse_io = cb_arg;
2272 :
2273 0 : fuse_dispatcher_io_complete_err(fuse_io, status);
2274 0 : }
2275 :
2276 : static void
2277 0 : do_fsyncdir(struct fuse_io *fuse_io)
2278 : {
2279 : int err;
2280 : struct fuse_fsync_in *arg;
2281 : uint64_t fh;
2282 : bool datasync;
2283 :
2284 0 : arg = _fsdev_io_in_arg_get_buf(fuse_io, sizeof(*arg));
2285 0 : if (!arg) {
2286 0 : SPDK_ERRLOG("Cannot get fuse_fsync_in\n");
2287 0 : fuse_dispatcher_io_complete_err(fuse_io, -EINVAL);
2288 0 : return;
2289 : }
2290 :
2291 0 : fh = fsdev_io_d2h_u64(fuse_io, arg->fh);
2292 0 : datasync = (fsdev_io_d2h_u32(fuse_io, arg->fsync_flags) & 1) ? true : false;
2293 :
2294 0 : err = spdk_fsdev_fsyncdir(fuse_io_desc(fuse_io), fuse_io->ch, fuse_io->hdr.unique,
2295 : file_object(fuse_io), file_handle(fh), datasync,
2296 : do_fsyncdir_cpl_clb, fuse_io);
2297 0 : if (err) {
2298 0 : fuse_dispatcher_io_complete_err(fuse_io, err);
2299 : }
2300 : }
2301 :
2302 : static void
2303 0 : do_getlk(struct fuse_io *fuse_io)
2304 : {
2305 0 : SPDK_ERRLOG("GETLK is not supported\n");
2306 0 : fuse_dispatcher_io_complete_err(fuse_io, -ENOSYS);
2307 0 : }
2308 :
2309 : static void
2310 0 : do_setlk_cpl_clb(void *cb_arg, struct spdk_io_channel *ch, int status)
2311 : {
2312 0 : struct fuse_io *fuse_io = cb_arg;
2313 :
2314 0 : fuse_dispatcher_io_complete_err(fuse_io, status);
2315 0 : }
2316 :
2317 : static void
2318 0 : do_setlk_common(struct fuse_io *fuse_io)
2319 : {
2320 : int err;
2321 : struct fuse_lk_in *arg;
2322 : uint64_t fh;
2323 : uint32_t lk_flags;
2324 :
2325 0 : arg = _fsdev_io_in_arg_get_buf(fuse_io, sizeof(*arg));
2326 0 : if (!arg) {
2327 0 : SPDK_ERRLOG("Cannot get fuse_lk_in\n");
2328 0 : fuse_dispatcher_io_complete_err(fuse_io, -EINVAL);
2329 0 : return;
2330 : }
2331 :
2332 0 : lk_flags = fsdev_io_d2h_u64(fuse_io, arg->lk_flags);
2333 :
2334 0 : if (lk_flags & FUSE_LK_FLOCK) {
2335 0 : int op = 0;
2336 :
2337 0 : switch (arg->lk.type) {
2338 0 : case F_RDLCK:
2339 0 : op = LOCK_SH;
2340 0 : break;
2341 0 : case F_WRLCK:
2342 0 : op = LOCK_EX;
2343 0 : break;
2344 0 : case F_UNLCK:
2345 0 : op = LOCK_UN;
2346 0 : break;
2347 : }
2348 :
2349 0 : fh = fsdev_io_d2h_u64(fuse_io, arg->fh);
2350 :
2351 0 : err = spdk_fsdev_flock(fuse_io_desc(fuse_io), fuse_io->ch, fuse_io->hdr.unique,
2352 : file_object(fuse_io), file_handle(fh), op,
2353 : do_setlk_cpl_clb, fuse_io);
2354 0 : if (err) {
2355 0 : fuse_dispatcher_io_complete_err(fuse_io, err);
2356 : }
2357 : } else {
2358 0 : SPDK_ERRLOG("SETLK: with no FUSE_LK_FLOCK is not supported\n");
2359 0 : fuse_dispatcher_io_complete_err(fuse_io, -ENOSYS);
2360 : }
2361 : }
2362 :
2363 : static void
2364 0 : do_setlk(struct fuse_io *fuse_io)
2365 : {
2366 0 : do_setlk_common(fuse_io);
2367 0 : }
2368 :
2369 : static void
2370 0 : do_setlkw(struct fuse_io *fuse_io)
2371 : {
2372 0 : SPDK_ERRLOG("SETLKW is not supported\n");
2373 0 : fuse_dispatcher_io_complete_err(fuse_io, -ENOSYS);
2374 0 : }
2375 :
2376 : static void
2377 0 : do_access(struct fuse_io *fuse_io)
2378 : {
2379 0 : SPDK_ERRLOG("ACCESS is not supported\n");
2380 0 : fuse_dispatcher_io_complete_err(fuse_io, -ENOSYS);
2381 0 : }
2382 :
2383 : static void
2384 0 : do_create_cpl_clb(void *cb_arg, struct spdk_io_channel *ch, int status,
2385 : struct spdk_fsdev_file_object *fobject, const struct spdk_fsdev_file_attr *attr,
2386 : struct spdk_fsdev_file_handle *fhandle)
2387 : {
2388 0 : struct fuse_io *fuse_io = cb_arg;
2389 :
2390 0 : if (!status) {
2391 0 : fuse_dispatcher_io_complete_create(fuse_io, fobject, attr, fhandle);
2392 : } else {
2393 0 : fuse_dispatcher_io_complete_err(fuse_io, status);
2394 : }
2395 0 : }
2396 :
2397 : static void
2398 0 : do_create(struct fuse_io *fuse_io)
2399 : {
2400 : int err;
2401 0 : struct spdk_fuse_dispatcher *disp = fuse_io->disp;
2402 0 : bool compat = fsdev_io_proto_minor(fuse_io) < 12;
2403 : struct fuse_create_in *arg;
2404 : const char *name;
2405 0 : uint32_t flags, mode, umask = 0;
2406 0 : size_t arg_size = compat ? sizeof(struct fuse_open_in) : sizeof(*arg);
2407 :
2408 0 : arg = _fsdev_io_in_arg_get_buf(fuse_io, arg_size);
2409 0 : if (!arg) {
2410 0 : SPDK_ERRLOG("Cannot get fuse_create_in (compat=%d)\n", compat);
2411 0 : fuse_dispatcher_io_complete_err(fuse_io, -EINVAL);
2412 0 : return;
2413 : }
2414 :
2415 0 : name = _fsdev_io_in_arg_get_str(fuse_io);
2416 0 : if (!name) {
2417 0 : SPDK_ERRLOG("Cannot get name (compat=%d)\n", compat);
2418 0 : fuse_dispatcher_io_complete_err(fuse_io, -EINVAL);
2419 0 : return;
2420 : }
2421 :
2422 0 : mode = fsdev_io_d2h_u32(fuse_io, arg->mode);
2423 0 : if (!compat) {
2424 0 : umask = fsdev_io_d2h_u32(fuse_io, arg->umask);
2425 : }
2426 :
2427 0 : if (!fsdev_d2h_open_flags(disp->fuse_arch, fsdev_io_d2h_u32(fuse_io, arg->flags), &flags)) {
2428 0 : SPDK_ERRLOG("Cannot translate flags\n");
2429 0 : fuse_dispatcher_io_complete_err(fuse_io, -EINVAL);
2430 0 : return;
2431 : }
2432 :
2433 0 : err = spdk_fsdev_create(fuse_io_desc(fuse_io), fuse_io->ch, fuse_io->hdr.unique,
2434 : file_object(fuse_io), name, mode, flags, umask, fuse_io->hdr.uid,
2435 : fuse_io->hdr.gid, do_create_cpl_clb, fuse_io);
2436 0 : if (err) {
2437 0 : fuse_dispatcher_io_complete_err(fuse_io, err);
2438 : }
2439 : }
2440 :
2441 : static void
2442 0 : do_abort_cpl_clb(void *cb_arg, struct spdk_io_channel *ch, int status)
2443 : {
2444 0 : struct fuse_io *fuse_io = cb_arg;
2445 :
2446 0 : fuse_dispatcher_io_complete_err(fuse_io, status);
2447 0 : }
2448 :
2449 : static void
2450 0 : do_interrupt(struct fuse_io *fuse_io)
2451 : {
2452 : int err;
2453 : struct fuse_interrupt_in *arg;
2454 : uint64_t unique;
2455 :
2456 0 : arg = _fsdev_io_in_arg_get_buf(fuse_io, sizeof(*arg));
2457 0 : if (!arg) {
2458 0 : SPDK_ERRLOG("Cannot get fuse_access_in\n");
2459 0 : fuse_dispatcher_io_complete_err(fuse_io, -EINVAL);
2460 0 : return;
2461 : }
2462 :
2463 0 : unique = fsdev_io_d2h_u64(fuse_io, arg->unique);
2464 :
2465 0 : SPDK_DEBUGLOG(fuse_dispatcher, "INTERRUPT: %" PRIu64 "\n", unique);
2466 :
2467 0 : err = spdk_fsdev_abort(fuse_io_desc(fuse_io), fuse_io->ch, unique, do_abort_cpl_clb, fuse_io);
2468 0 : if (err) {
2469 0 : fuse_dispatcher_io_complete_err(fuse_io, err);
2470 : }
2471 : }
2472 :
2473 : static void
2474 0 : do_bmap(struct fuse_io *fuse_io)
2475 : {
2476 0 : SPDK_ERRLOG("BMAP is not supported\n");
2477 0 : fuse_dispatcher_io_complete_err(fuse_io, -ENOSYS);
2478 0 : }
2479 :
2480 : static void
2481 0 : do_ioctl(struct fuse_io *fuse_io)
2482 : {
2483 0 : SPDK_ERRLOG("IOCTL is not supported\n");
2484 0 : fuse_dispatcher_io_complete_err(fuse_io, -ENOSYS);
2485 0 : }
2486 :
2487 : static void
2488 0 : do_poll(struct fuse_io *fuse_io)
2489 : {
2490 0 : SPDK_ERRLOG("POLL is not supported\n");
2491 0 : fuse_dispatcher_io_complete_err(fuse_io, -ENOSYS);
2492 0 : }
2493 :
2494 : static void
2495 0 : do_fallocate_cpl_clb(void *cb_arg, struct spdk_io_channel *ch, int status)
2496 : {
2497 0 : struct fuse_io *fuse_io = cb_arg;
2498 :
2499 0 : fuse_dispatcher_io_complete_err(fuse_io, status);
2500 0 : }
2501 :
2502 : static void
2503 0 : do_fallocate(struct fuse_io *fuse_io)
2504 : {
2505 : int err;
2506 : struct fuse_fallocate_in *arg;
2507 : uint64_t fh;
2508 :
2509 0 : arg = _fsdev_io_in_arg_get_buf(fuse_io, sizeof(*arg));
2510 0 : if (!arg) {
2511 0 : SPDK_ERRLOG("Cannot get fuse_fallocate_in\n");
2512 0 : fuse_dispatcher_io_complete_err(fuse_io, -EINVAL);
2513 0 : return;
2514 : }
2515 :
2516 0 : fh = fsdev_io_d2h_u64(fuse_io, arg->fh);
2517 :
2518 0 : err = spdk_fsdev_fallocate(fuse_io_desc(fuse_io), fuse_io->ch, fuse_io->hdr.unique,
2519 : file_object(fuse_io), file_handle(fh),
2520 0 : fsdev_io_d2h_u32(fuse_io, arg->mode), fsdev_io_d2h_u64(fuse_io, arg->offset),
2521 0 : fsdev_io_d2h_u64(fuse_io, arg->length),
2522 : do_fallocate_cpl_clb, fuse_io);
2523 0 : if (err) {
2524 0 : fuse_dispatcher_io_complete_err(fuse_io, err);
2525 : }
2526 : }
2527 :
2528 : static void
2529 0 : fuse_dispatcher_destroy_put_channel(struct spdk_io_channel_iter *i)
2530 : {
2531 0 : struct spdk_io_channel *io_ch = spdk_io_channel_iter_get_channel(i);
2532 0 : struct spdk_fuse_dispatcher_channel *ch = __disp_ch_from_io_ch(io_ch);
2533 :
2534 0 : if (ch->fsdev_io_ch) {
2535 0 : spdk_put_io_channel(ch->fsdev_io_ch);
2536 0 : ch->fsdev_io_ch = NULL;
2537 : }
2538 :
2539 0 : spdk_for_each_channel_continue(i, 0);
2540 0 : }
2541 :
2542 : static void
2543 0 : fuse_dispatcher_destroy_put_channel_done(struct spdk_io_channel_iter *i, int status)
2544 : {
2545 0 : struct fuse_io *fuse_io = spdk_io_channel_iter_get_ctx(i);
2546 0 : struct spdk_fuse_dispatcher *disp = fuse_io->disp;
2547 :
2548 0 : if (status) {
2549 0 : SPDK_WARNLOG("%s: putting channels failed with %d\n", fuse_dispatcher_name(disp), status);
2550 0 : fuse_dispatcher_io_complete_err(fuse_io, status);
2551 0 : return;
2552 : }
2553 :
2554 0 : SPDK_DEBUGLOG(fuse_dispatcher, "%s: putting channels succeeded. Releasing the fdev\n",
2555 : fuse_dispatcher_name(disp));
2556 :
2557 0 : fuse_dispatcher_close_fsdev_and_complete(fuse_io, 0);
2558 : }
2559 :
2560 : static void
2561 0 : do_forget_root_cpl_clb(void *cb_arg, struct spdk_io_channel *ch, int status)
2562 : {
2563 0 : struct fuse_io *fuse_io = cb_arg;
2564 0 : struct spdk_fuse_dispatcher *disp = fuse_io->disp;
2565 :
2566 0 : if (status) {
2567 0 : SPDK_ERRLOG("Failed to forget the root (err=%d)\n", status);
2568 0 : fuse_dispatcher_io_complete_err(fuse_io, status);
2569 0 : return;
2570 : }
2571 :
2572 0 : disp->root_fobject = NULL;
2573 0 : SPDK_DEBUGLOG(fuse_dispatcher, "root fobject successfully forgotten\n");
2574 :
2575 0 : spdk_for_each_channel(__disp_to_io_dev(disp),
2576 : fuse_dispatcher_destroy_put_channel,
2577 : fuse_io,
2578 : fuse_dispatcher_destroy_put_channel_done);
2579 : }
2580 :
2581 : static void
2582 0 : do_destroy(struct fuse_io *fuse_io)
2583 : {
2584 0 : struct spdk_fuse_dispatcher *disp = fuse_io->disp;
2585 :
2586 0 : disp->proto_major = disp->proto_minor = 0;
2587 :
2588 0 : SPDK_DEBUGLOG(fuse_dispatcher, "DESTROY\n");
2589 :
2590 0 : if (disp->root_fobject) {
2591 0 : int err = spdk_fsdev_forget(fuse_io_desc(fuse_io), fuse_io->ch, 0, disp->root_fobject, 1,
2592 : do_forget_root_cpl_clb, fuse_io);
2593 0 : if (err) {
2594 0 : SPDK_ERRLOG("Failed to initiate forget for root (err=%d)\n", err);
2595 0 : fuse_dispatcher_io_complete_err(fuse_io, err);
2596 0 : return;
2597 : }
2598 : } else {
2599 0 : fuse_dispatcher_close_fsdev_and_complete(fuse_io, 0);
2600 : }
2601 : }
2602 :
2603 : static void
2604 0 : do_batch_forget_cpl_clb(void *cb_arg, struct spdk_io_channel *ch, int status)
2605 : {
2606 0 : struct fuse_io *fuse_io = cb_arg;
2607 :
2608 0 : if (status) {
2609 0 : fuse_io->u.batch_forget.status = status;
2610 : }
2611 :
2612 0 : fuse_io->u.batch_forget.to_forget--;
2613 :
2614 0 : if (!fuse_io->u.batch_forget.to_forget) {
2615 : /* FUSE_BATCH_FORGET requires no response */
2616 0 : fuse_dispatcher_io_complete_none(fuse_io, fuse_io->u.batch_forget.status);
2617 : }
2618 0 : }
2619 :
2620 : static void
2621 0 : do_batch_forget(struct fuse_io *fuse_io)
2622 : {
2623 : int err;
2624 : struct fuse_batch_forget_in *arg;
2625 : struct fuse_forget_data *forgets;
2626 : size_t scount;
2627 : uint32_t count, i;
2628 :
2629 0 : arg = _fsdev_io_in_arg_get_buf(fuse_io, sizeof(*arg));
2630 0 : if (!arg) {
2631 0 : SPDK_ERRLOG("Cannot get fuse_batch_forget_in\n");
2632 0 : fuse_dispatcher_io_complete_err(fuse_io, -EINVAL);
2633 0 : return;
2634 : }
2635 :
2636 : /* Prevent integer overflow. The compiler emits the following warning
2637 : * unless we use the scount local variable:
2638 : *
2639 : * error: comparison is always false due to limited range of data type
2640 : * [-Werror=type-limits]
2641 : *
2642 : * This may be true on 64-bit hosts but we need this check for 32-bit
2643 : * hosts.
2644 : */
2645 0 : scount = fsdev_io_d2h_u32(fuse_io, arg->count);
2646 0 : if (scount > SIZE_MAX / sizeof(forgets[0])) {
2647 0 : SPDK_WARNLOG("Too many forgets (%zu >= %zu)\n", scount,
2648 : SIZE_MAX / sizeof(forgets[0]));
2649 : /* FUSE_BATCH_FORGET requires no response */
2650 0 : fuse_dispatcher_io_complete_none(fuse_io, -EINVAL);
2651 0 : return;
2652 : }
2653 :
2654 0 : count = scount;
2655 0 : if (!count) {
2656 0 : SPDK_WARNLOG("0 forgets requested\n");
2657 : /* FUSE_BATCH_FORGET requires no response */
2658 0 : fuse_dispatcher_io_complete_none(fuse_io, -EINVAL);
2659 0 : return;
2660 : }
2661 :
2662 0 : forgets = _fsdev_io_in_arg_get_buf(fuse_io, count * sizeof(forgets[0]));
2663 0 : if (!forgets) {
2664 0 : SPDK_WARNLOG("Cannot get expected forgets (%" PRIu32 ")\n", count);
2665 : /* FUSE_BATCH_FORGET requires no response */
2666 0 : fuse_dispatcher_io_complete_none(fuse_io, -EINVAL);
2667 0 : return;
2668 : }
2669 :
2670 0 : fuse_io->u.batch_forget.to_forget = 0;
2671 0 : fuse_io->u.batch_forget.status = 0;
2672 :
2673 0 : for (i = 0; i < count; i++) {
2674 0 : uint64_t ino = fsdev_io_d2h_u64(fuse_io, forgets[i].ino);
2675 0 : uint64_t nlookup = fsdev_io_d2h_u64(fuse_io, forgets[i].nlookup);
2676 0 : err = spdk_fsdev_forget(fuse_io_desc(fuse_io), fuse_io->ch, fuse_io->hdr.unique,
2677 : ino_to_object(fuse_io, ino), nlookup,
2678 : do_batch_forget_cpl_clb, fuse_io);
2679 0 : if (!err) {
2680 0 : fuse_io->u.batch_forget.to_forget++;
2681 : } else {
2682 0 : fuse_io->u.batch_forget.status = err;
2683 : }
2684 : }
2685 :
2686 0 : if (!fuse_io->u.batch_forget.to_forget) {
2687 : /* FUSE_BATCH_FORGET requires no response */
2688 0 : fuse_dispatcher_io_complete_none(fuse_io, fuse_io->u.batch_forget.status);
2689 : }
2690 : }
2691 :
2692 : static void
2693 0 : do_copy_file_range_cpl_clb(void *cb_arg, struct spdk_io_channel *ch, int status, uint32_t data_size)
2694 : {
2695 0 : struct fuse_io *fuse_io = cb_arg;
2696 :
2697 0 : fuse_dispatcher_io_complete_write(fuse_io, data_size, status);
2698 0 : }
2699 :
2700 : static void
2701 0 : do_copy_file_range(struct fuse_io *fuse_io)
2702 : {
2703 : int err;
2704 : struct fuse_copy_file_range_in *arg;
2705 : uint64_t fh_in, fh_out, nodeid_out;
2706 :
2707 0 : arg = _fsdev_io_in_arg_get_buf(fuse_io, sizeof(*arg));
2708 0 : if (!arg) {
2709 0 : SPDK_ERRLOG("Cannot get fuse_copy_file_range_in\n");
2710 0 : fuse_dispatcher_io_complete_err(fuse_io, -EINVAL);
2711 0 : return;
2712 : }
2713 :
2714 0 : fh_in = fsdev_io_d2h_u64(fuse_io, arg->fh_in);
2715 0 : nodeid_out = fsdev_io_d2h_u64(fuse_io, arg->nodeid_out);
2716 0 : fh_out = fsdev_io_d2h_u64(fuse_io, arg->fh_out);
2717 :
2718 0 : err = spdk_fsdev_copy_file_range(fuse_io_desc(fuse_io), fuse_io->ch, fuse_io->hdr.unique,
2719 0 : file_object(fuse_io), file_handle(fh_in), fsdev_io_d2h_u64(fuse_io, arg->off_in),
2720 0 : ino_to_object(fuse_io, nodeid_out), file_handle(fh_out), fsdev_io_d2h_u64(fuse_io, arg->off_out),
2721 0 : fsdev_io_d2h_u64(fuse_io, arg->len), fsdev_io_d2h_u64(fuse_io, arg->flags),
2722 : do_copy_file_range_cpl_clb, fuse_io);
2723 :
2724 0 : if (err) {
2725 0 : fuse_dispatcher_io_complete_err(fuse_io, err);
2726 : }
2727 : }
2728 :
2729 : static void
2730 0 : do_setupmapping(struct fuse_io *fuse_io)
2731 : {
2732 0 : SPDK_ERRLOG("SETUPMAPPING is not supported\n");
2733 0 : fuse_dispatcher_io_complete_err(fuse_io, -ENOSYS);
2734 0 : }
2735 :
2736 : static void
2737 0 : do_removemapping(struct fuse_io *fuse_io)
2738 : {
2739 0 : SPDK_ERRLOG("REMOVEMAPPING is not supported\n");
2740 0 : fuse_dispatcher_io_complete_err(fuse_io, -ENOSYS);
2741 0 : }
2742 :
2743 : static void
2744 0 : do_syncfs(struct fuse_io *fuse_io)
2745 : {
2746 0 : SPDK_ERRLOG("SYNCFS is not supported\n");
2747 0 : fuse_dispatcher_io_complete_err(fuse_io, -ENOSYS);
2748 0 : }
2749 :
2750 : static const struct {
2751 : void (*func)(struct fuse_io *fuse_io);
2752 : const char *name;
2753 : } fuse_ll_ops[] = {
2754 : [FUSE_LOOKUP] = { do_lookup, "LOOKUP" },
2755 : [FUSE_FORGET] = { do_forget, "FORGET" },
2756 : [FUSE_GETATTR] = { do_getattr, "GETATTR" },
2757 : [FUSE_SETATTR] = { do_setattr, "SETATTR" },
2758 : [FUSE_READLINK] = { do_readlink, "READLINK" },
2759 : [FUSE_SYMLINK] = { do_symlink, "SYMLINK" },
2760 : [FUSE_MKNOD] = { do_mknod, "MKNOD" },
2761 : [FUSE_MKDIR] = { do_mkdir, "MKDIR" },
2762 : [FUSE_UNLINK] = { do_unlink, "UNLINK" },
2763 : [FUSE_RMDIR] = { do_rmdir, "RMDIR" },
2764 : [FUSE_RENAME] = { do_rename, "RENAME" },
2765 : [FUSE_LINK] = { do_link, "LINK" },
2766 : [FUSE_OPEN] = { do_open, "OPEN" },
2767 : [FUSE_READ] = { do_read, "READ" },
2768 : [FUSE_WRITE] = { do_write, "WRITE" },
2769 : [FUSE_STATFS] = { do_statfs, "STATFS" },
2770 : [FUSE_RELEASE] = { do_release, "RELEASE" },
2771 : [FUSE_FSYNC] = { do_fsync, "FSYNC" },
2772 : [FUSE_SETXATTR] = { do_setxattr, "SETXATTR" },
2773 : [FUSE_GETXATTR] = { do_getxattr, "GETXATTR" },
2774 : [FUSE_LISTXATTR] = { do_listxattr, "LISTXATTR" },
2775 : [FUSE_REMOVEXATTR] = { do_removexattr, "REMOVEXATTR" },
2776 : [FUSE_FLUSH] = { do_flush, "FLUSH" },
2777 : [FUSE_INIT] = { do_init, "INIT" },
2778 : [FUSE_OPENDIR] = { do_opendir, "OPENDIR" },
2779 : [FUSE_READDIR] = { do_readdir, "READDIR" },
2780 : [FUSE_RELEASEDIR] = { do_releasedir, "RELEASEDIR" },
2781 : [FUSE_FSYNCDIR] = { do_fsyncdir, "FSYNCDIR" },
2782 : [FUSE_GETLK] = { do_getlk, "GETLK" },
2783 : [FUSE_SETLK] = { do_setlk, "SETLK" },
2784 : [FUSE_SETLKW] = { do_setlkw, "SETLKW" },
2785 : [FUSE_ACCESS] = { do_access, "ACCESS" },
2786 : [FUSE_CREATE] = { do_create, "CREATE" },
2787 : [FUSE_INTERRUPT] = { do_interrupt, "INTERRUPT" },
2788 : [FUSE_BMAP] = { do_bmap, "BMAP" },
2789 : [FUSE_IOCTL] = { do_ioctl, "IOCTL" },
2790 : [FUSE_POLL] = { do_poll, "POLL" },
2791 : [FUSE_FALLOCATE] = { do_fallocate, "FALLOCATE" },
2792 : [FUSE_DESTROY] = { do_destroy, "DESTROY" },
2793 : [FUSE_NOTIFY_REPLY] = { NULL, "NOTIFY_REPLY" },
2794 : [FUSE_BATCH_FORGET] = { do_batch_forget, "BATCH_FORGET" },
2795 : [FUSE_READDIRPLUS] = { do_readdirplus, "READDIRPLUS"},
2796 : [FUSE_RENAME2] = { do_rename2, "RENAME2" },
2797 : [FUSE_COPY_FILE_RANGE] = { do_copy_file_range, "COPY_FILE_RANGE" },
2798 : [FUSE_SETUPMAPPING] = { do_setupmapping, "SETUPMAPPING" },
2799 : [FUSE_REMOVEMAPPING] = { do_removemapping, "REMOVEMAPPING" },
2800 : [FUSE_SYNCFS] = { do_syncfs, "SYNCFS" },
2801 : };
2802 :
2803 : static int
2804 0 : spdk_fuse_dispatcher_handle_fuse_req(struct spdk_fuse_dispatcher *disp, struct fuse_io *fuse_io)
2805 : {
2806 : struct fuse_in_header *hdr;
2807 :
2808 0 : if (!fuse_io->in_iovcnt || !fuse_io->in_iov) {
2809 0 : SPDK_ERRLOG("Bad IO: no IN iov (%d, %p)\n", fuse_io->in_iovcnt, fuse_io->in_iov);
2810 0 : goto exit;
2811 : }
2812 :
2813 0 : hdr = _fsdev_io_in_arg_get_buf(fuse_io, sizeof(*hdr));
2814 0 : if (!hdr) {
2815 0 : SPDK_ERRLOG("Bad IO: cannot get fuse_in_header\n");
2816 0 : goto exit;
2817 : }
2818 :
2819 0 : fuse_io->hdr.opcode = fsdev_io_d2h_u32(fuse_io, hdr->opcode);
2820 :
2821 0 : if (spdk_unlikely(!fuse_io->ch)) {
2822 : /* FUSE_INIT is allowed with no channel. It'll open the fsdev and get channels */
2823 0 : if (fuse_io->hdr.opcode != FUSE_INIT) {
2824 : /* The fsdev is not currently active. Complete this request. */
2825 0 : SPDK_ERRLOG("IO (%" PRIu32 ") arrived while there's no channel\n", fuse_io->hdr.opcode);
2826 0 : goto exit;
2827 : }
2828 : }
2829 :
2830 0 : if (spdk_likely(_fuse_op_requires_reply(hdr->opcode))) {
2831 0 : struct fuse_out_header *out_hdr = _fsdev_io_out_arg_get_buf(fuse_io, sizeof(*out_hdr));
2832 0 : if (!out_hdr) {
2833 0 : SPDK_ERRLOG("Bad IO: cannot get out_hdr\n");
2834 0 : goto exit;
2835 : }
2836 :
2837 : UNUSED(out_hdr); /* We don't need it here, we just made a check and a reservation */
2838 : }
2839 :
2840 0 : if (fuse_io->hdr.opcode >= SPDK_COUNTOF(fuse_ll_ops)) {
2841 0 : SPDK_ERRLOG("Bad IO: opt_code is out of range (%" PRIu32 " > %zu)\n", fuse_io->hdr.opcode,
2842 : SPDK_COUNTOF(fuse_ll_ops));
2843 0 : fuse_dispatcher_io_complete_err(fuse_io, -ENOSYS);
2844 0 : return 0;
2845 : }
2846 :
2847 0 : if (!fuse_ll_ops[fuse_io->hdr.opcode].func) {
2848 0 : SPDK_ERRLOG("Bad IO: no handler for (%" PRIu32 ") %s\n", fuse_io->hdr.opcode,
2849 : fuse_ll_ops[fuse_io->hdr.opcode].name);
2850 0 : fuse_dispatcher_io_complete_err(fuse_io, -ENOSYS);
2851 0 : return 0;
2852 : }
2853 :
2854 0 : fuse_io->hdr.len = fsdev_io_d2h_u32(fuse_io, hdr->len);
2855 0 : fuse_io->hdr.unique = fsdev_io_d2h_u64(fuse_io, hdr->unique);
2856 0 : fuse_io->hdr.nodeid = fsdev_io_d2h_u64(fuse_io, hdr->nodeid);
2857 0 : fuse_io->hdr.uid = fsdev_io_d2h_u32(fuse_io, hdr->uid);
2858 0 : fuse_io->hdr.gid = fsdev_io_d2h_u32(fuse_io, hdr->gid);
2859 0 : fuse_io->hdr.pid = fsdev_io_d2h_u32(fuse_io, hdr->pid);
2860 :
2861 0 : SPDK_DEBUGLOG(fuse_dispatcher, "IO arrived: %" PRIu32 " (%s) len=%" PRIu32 " unique=%" PRIu64
2862 : " nodeid=%" PRIu64 " uid=%" PRIu32 " gid=%" PRIu32 " pid=%" PRIu32 "\n", fuse_io->hdr.opcode,
2863 : fuse_ll_ops[fuse_io->hdr.opcode].name, fuse_io->hdr.len, fuse_io->hdr.unique,
2864 : fuse_io->hdr.nodeid, fuse_io->hdr.uid, fuse_io->hdr.gid, fuse_io->hdr.pid);
2865 :
2866 0 : fuse_ll_ops[fuse_io->hdr.opcode].func(fuse_io);
2867 0 : return 0;
2868 :
2869 0 : exit:
2870 0 : spdk_mempool_put(g_fuse_mgr.fuse_io_pool, fuse_io);
2871 0 : return -EINVAL;
2872 : }
2873 :
2874 : static int
2875 0 : fuse_dispatcher_channel_create(void *io_device, void *ctx_buf)
2876 : {
2877 0 : struct spdk_fuse_dispatcher *disp = __disp_from_io_dev(io_device);
2878 0 : struct spdk_fuse_dispatcher_channel *ch = ctx_buf;
2879 :
2880 0 : if (disp->desc) {
2881 0 : ch->fsdev_io_ch = spdk_fsdev_get_io_channel(disp->desc);
2882 : }
2883 :
2884 0 : return 0;
2885 : }
2886 :
2887 : static void
2888 0 : fuse_dispatcher_channel_destroy(void *io_device, void *ctx_buf)
2889 : {
2890 0 : struct spdk_fuse_dispatcher *disp = __disp_from_io_dev(io_device);
2891 0 : struct spdk_fuse_dispatcher_channel *ch = ctx_buf;
2892 :
2893 : UNUSED(disp);
2894 :
2895 0 : if (ch->fsdev_io_ch) {
2896 0 : assert(disp->desc);
2897 0 : spdk_put_io_channel(ch->fsdev_io_ch);
2898 0 : ch->fsdev_io_ch = NULL;
2899 : }
2900 0 : }
2901 :
2902 : int
2903 0 : spdk_fuse_dispatcher_create(const char *fsdev_name, spdk_fuse_dispatcher_event_cb event_cb,
2904 : void *event_ctx, spdk_fuse_dispatcher_create_cpl_cb cb, void *cb_arg)
2905 : {
2906 : struct spdk_fuse_dispatcher *disp;
2907 : char *io_dev_name;
2908 : size_t fsdev_name_len;
2909 :
2910 0 : if (!fsdev_name || !event_cb || !cb) {
2911 0 : SPDK_ERRLOG("Invalid params\n");
2912 0 : return -EINVAL;
2913 : }
2914 :
2915 0 : io_dev_name = spdk_sprintf_alloc("fuse_disp_%s", fsdev_name);
2916 0 : if (!io_dev_name) {
2917 0 : SPDK_ERRLOG("Could not format io_dev name (%s)\n", fsdev_name);
2918 0 : return -ENOMEM;
2919 : }
2920 :
2921 0 : fsdev_name_len = strlen(fsdev_name);
2922 :
2923 0 : disp = calloc(1, sizeof(*disp) + fsdev_name_len + 1);
2924 0 : if (!disp) {
2925 0 : SPDK_ERRLOG("Could not allocate spdk_fuse_dispatcher\n");
2926 0 : free(io_dev_name);
2927 0 : return -ENOMEM;
2928 : }
2929 :
2930 0 : pthread_mutex_lock(&g_fuse_mgr.lock);
2931 0 : if (!g_fuse_mgr.ref_cnt) {
2932 0 : struct spdk_fsdev_opts opts;
2933 0 : spdk_fsdev_get_opts(&opts, sizeof(opts));
2934 :
2935 0 : g_fuse_mgr.fuse_io_pool = spdk_mempool_create("FUSE_disp_ios", opts.fsdev_io_pool_size,
2936 0 : sizeof(struct fuse_io), opts.fsdev_io_cache_size, SPDK_ENV_SOCKET_ID_ANY);
2937 0 : if (!g_fuse_mgr.fuse_io_pool) {
2938 0 : pthread_mutex_unlock(&g_fuse_mgr.lock);
2939 0 : SPDK_ERRLOG("Could not create mempool\n");
2940 0 : free(io_dev_name);
2941 0 : free(disp);
2942 0 : return -ENOMEM;
2943 : }
2944 : }
2945 0 : g_fuse_mgr.ref_cnt++;
2946 0 : pthread_mutex_unlock(&g_fuse_mgr.lock);
2947 :
2948 0 : spdk_io_device_register(__disp_to_io_dev(disp),
2949 : fuse_dispatcher_channel_create, fuse_dispatcher_channel_destroy,
2950 : sizeof(struct spdk_fuse_dispatcher_channel),
2951 : io_dev_name);
2952 :
2953 0 : free(io_dev_name);
2954 :
2955 0 : memcpy(disp->fsdev_name, fsdev_name, fsdev_name_len + 1);
2956 0 : disp->event_cb = event_cb;
2957 0 : disp->event_ctx = event_ctx;
2958 0 : disp->fuse_arch = SPDK_FUSE_ARCH_NATIVE;
2959 :
2960 0 : cb(cb_arg, disp);
2961 :
2962 0 : return 0;
2963 : }
2964 :
2965 : int
2966 0 : spdk_fuse_dispatcher_set_arch(struct spdk_fuse_dispatcher *disp, enum spdk_fuse_arch fuse_arch)
2967 : {
2968 0 : switch (fuse_arch) {
2969 0 : case SPDK_FUSE_ARCH_NATIVE:
2970 : case SPDK_FUSE_ARCH_X86:
2971 : case SPDK_FUSE_ARCH_X86_64:
2972 : case SPDK_FUSE_ARCH_ARM:
2973 : case SPDK_FUSE_ARCH_ARM64:
2974 0 : SPDK_NOTICELOG("FUSE arch set to %d\n", fuse_arch);
2975 0 : disp->fuse_arch = fuse_arch;
2976 0 : return 0;
2977 0 : default:
2978 0 : return -EINVAL;
2979 : }
2980 : }
2981 :
2982 : const char *
2983 0 : spdk_fuse_dispatcher_get_fsdev_name(struct spdk_fuse_dispatcher *disp)
2984 : {
2985 0 : return fuse_dispatcher_name(disp);
2986 : }
2987 :
2988 : struct spdk_io_channel *
2989 0 : spdk_fuse_dispatcher_get_io_channel(struct spdk_fuse_dispatcher *disp)
2990 : {
2991 0 : return spdk_get_io_channel(__disp_to_io_dev(disp));
2992 : }
2993 :
2994 : int
2995 0 : spdk_fuse_dispatcher_submit_request(struct spdk_fuse_dispatcher *disp,
2996 : struct spdk_io_channel *ch,
2997 : struct iovec *in_iov, int in_iovcnt,
2998 : struct iovec *out_iov, int out_iovcnt,
2999 : spdk_fuse_dispatcher_submit_cpl_cb clb, void *cb_arg)
3000 : {
3001 : struct fuse_io *fuse_io;
3002 0 : struct spdk_fuse_dispatcher_channel *disp_ch = __disp_ch_from_io_ch(ch);
3003 :
3004 0 : fuse_io = spdk_mempool_get(g_fuse_mgr.fuse_io_pool);
3005 :
3006 0 : if (!fuse_io) {
3007 0 : SPDK_ERRLOG("We ran out of FUSE IOs\n");
3008 0 : return -ENOBUFS;
3009 : }
3010 :
3011 0 : fuse_io->disp = disp;
3012 0 : fuse_io->ch = disp_ch->fsdev_io_ch;
3013 0 : fuse_io->in_iov = in_iov;
3014 0 : fuse_io->in_iovcnt = in_iovcnt;
3015 0 : fuse_io->out_iov = out_iov;
3016 0 : fuse_io->out_iovcnt = out_iovcnt;
3017 0 : fuse_io->cpl_cb = clb;
3018 0 : fuse_io->cpl_cb_arg = cb_arg;
3019 :
3020 0 : fuse_io->in_offs.iov_offs = 0;
3021 0 : fuse_io->in_offs.buf_offs = 0;
3022 0 : fuse_io->out_offs.iov_offs = 0;
3023 0 : fuse_io->out_offs.buf_offs = 0;
3024 :
3025 0 : return spdk_fuse_dispatcher_handle_fuse_req(disp, fuse_io);
3026 : }
3027 :
3028 : struct fuse_dispatcher_delete_ctx {
3029 : struct spdk_fuse_dispatcher *disp;
3030 : spdk_fuse_dispatcher_delete_cpl_cb cb;
3031 : void *cb_arg;
3032 : };
3033 :
3034 : static void
3035 0 : fuse_dispatcher_delete_done(struct fuse_dispatcher_delete_ctx *ctx, int status)
3036 : {
3037 0 : struct spdk_fuse_dispatcher *disp = ctx->disp;
3038 :
3039 0 : if (!status) {
3040 0 : SPDK_DEBUGLOG(fuse_dispatcher, "%s: deletion succeeded\n", fuse_dispatcher_name(disp));
3041 :
3042 0 : spdk_io_device_unregister(__disp_to_io_dev(disp), NULL);
3043 :
3044 0 : free(disp);
3045 :
3046 0 : pthread_mutex_lock(&g_fuse_mgr.lock);
3047 0 : g_fuse_mgr.ref_cnt--;
3048 0 : if (!g_fuse_mgr.ref_cnt) {
3049 0 : spdk_mempool_free(g_fuse_mgr.fuse_io_pool);
3050 0 : g_fuse_mgr.fuse_io_pool = NULL;
3051 : }
3052 0 : pthread_mutex_unlock(&g_fuse_mgr.lock);
3053 : } else {
3054 0 : SPDK_ERRLOG("%s: deletion failed with %d\n", fuse_dispatcher_name(disp), status);
3055 : }
3056 :
3057 0 : ctx->cb(ctx->cb_arg, (uint32_t)(-status));
3058 0 : free(ctx);
3059 0 : }
3060 :
3061 : static void
3062 0 : fuse_dispatcher_delete_put_channel(struct spdk_io_channel_iter *i)
3063 : {
3064 0 : struct spdk_io_channel *io_ch = spdk_io_channel_iter_get_channel(i);
3065 0 : struct spdk_fuse_dispatcher_channel *ch = __disp_ch_from_io_ch(io_ch);
3066 :
3067 0 : if (ch->fsdev_io_ch) {
3068 0 : spdk_put_io_channel(ch->fsdev_io_ch);
3069 0 : ch->fsdev_io_ch = NULL;
3070 : }
3071 :
3072 0 : spdk_for_each_channel_continue(i, 0);
3073 0 : }
3074 :
3075 : static void
3076 0 : fuse_dispatcher_delete_put_channel_done(struct spdk_io_channel_iter *i, int status)
3077 : {
3078 0 : struct fuse_dispatcher_delete_ctx *ctx = spdk_io_channel_iter_get_ctx(i);
3079 0 : struct spdk_fuse_dispatcher *disp = ctx->disp;
3080 :
3081 0 : if (status) {
3082 0 : SPDK_ERRLOG("%s: putting channels failed with %d\n", fuse_dispatcher_name(disp), status);
3083 0 : fuse_dispatcher_delete_done(ctx, status);
3084 0 : return;
3085 : }
3086 :
3087 0 : SPDK_DEBUGLOG(fuse_dispatcher, "%s: putting channels succeeded. Releasing the fdev\n",
3088 : fuse_dispatcher_name(disp));
3089 :
3090 0 : spdk_fsdev_close(disp->desc);
3091 :
3092 0 : fuse_dispatcher_delete_done(ctx, 0);
3093 : }
3094 :
3095 : int
3096 0 : spdk_fuse_dispatcher_delete(struct spdk_fuse_dispatcher *disp,
3097 : spdk_fuse_dispatcher_delete_cpl_cb cb, void *cb_arg)
3098 : {
3099 : struct fuse_dispatcher_delete_ctx *ctx;
3100 :
3101 0 : ctx = calloc(1, sizeof(*ctx));
3102 0 : if (!ctx) {
3103 0 : SPDK_ERRLOG("cannot allocate context\n");
3104 0 : return -ENOMEM;
3105 : }
3106 :
3107 0 : ctx->disp = disp;
3108 0 : ctx->cb = cb;
3109 0 : ctx->cb_arg = cb_arg;
3110 :
3111 0 : if (disp->desc) {
3112 0 : SPDK_DEBUGLOG(fuse_dispatcher, "%s: fsdev still open. Releasing the channels.\n",
3113 : fuse_dispatcher_name(disp));
3114 :
3115 0 : spdk_for_each_channel(__disp_to_io_dev(disp),
3116 : fuse_dispatcher_delete_put_channel,
3117 : ctx,
3118 : fuse_dispatcher_delete_put_channel_done);
3119 : } else {
3120 0 : fuse_dispatcher_delete_done(ctx, 0);
3121 : }
3122 :
3123 0 : return 0;
3124 : }
3125 :
3126 0 : SPDK_LOG_REGISTER_COMPONENT(fuse_dispatcher)
|