Branch data 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 : 2 : fsdev_d2h_open_flags(enum spdk_fuse_arch fuse_arch, uint32_t flags, uint32_t *translated_flags)
56 : : {
57 : 2 : bool res = true;
58 : :
59 : 2 : *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 [ + - - ]: 2 : switch (fuse_arch) {
73 : 2 : 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 : 2 : 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 : 2 : 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 : 5 : file_ino(struct fuse_io *fuse_io, const struct spdk_fsdev_file_object *fobject)
252 : : {
253 [ + - ]: 5 : 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 : 524349 : ino_to_object(struct fuse_io *fuse_io, uint64_t ino)
258 : : {
259 : : return (ino == FUSE_ROOT_ID) ?
260 [ + + ]: 524349 : fuse_io->disp->root_fobject :
261 : : (struct spdk_fsdev_file_object *)(uintptr_t)ino;
262 : : }
263 : :
264 : : static struct spdk_fsdev_file_object *
265 : 524349 : file_object(struct fuse_io *fuse_io)
266 : : {
267 : 524349 : return ino_to_object(fuse_io, fuse_io->hdr.nodeid);
268 : : }
269 : :
270 : : static inline uint64_t
271 : 2 : file_fh(const struct spdk_fsdev_file_handle *fhandle)
272 : : {
273 : 2 : return (uint64_t)(uintptr_t)fhandle;
274 : : }
275 : :
276 : : static struct spdk_fsdev_file_handle *
277 : 524313 : file_handle(uint64_t fh)
278 : : {
279 : 524313 : 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 : 2 : fsdev_io_h2d_u16(struct fuse_io *fuse_io, uint16_t v)
290 : : {
291 : 2 : return v;
292 : : }
293 : :
294 : : static inline uint32_t
295 : 4063508 : fsdev_io_d2h_u32(struct fuse_io *fuse_io, uint32_t v)
296 : : {
297 : 4063508 : return v;
298 : : }
299 : :
300 : : static inline uint32_t
301 : 524581 : fsdev_io_h2d_u32(struct fuse_io *fuse_io, uint32_t v)
302 : : {
303 : 524581 : return v;
304 : : }
305 : :
306 : : static inline int32_t
307 : 524327 : fsdev_io_h2d_i32(struct fuse_io *fuse_io, int32_t v)
308 : : {
309 : 524327 : return v;
310 : : }
311 : :
312 : : static inline uint64_t
313 : 2097282 : fsdev_io_d2h_u64(struct fuse_io *fuse_io, uint64_t v)
314 : : {
315 : 2097282 : return v;
316 : : }
317 : :
318 : : static inline uint64_t
319 : 524514 : fsdev_io_h2d_u64(struct fuse_io *fuse_io, uint64_t v)
320 : : {
321 : 524514 : return v;
322 : : }
323 : :
324 : : static inline unsigned
325 : 524337 : fsdev_io_proto_minor(struct fuse_io *fuse_io)
326 : : {
327 : 524337 : return fuse_io->disp->proto_minor;
328 : : }
329 : :
330 : : static inline void *
331 : 1966269 : _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 [ - + ]: 1966269 : assert(offs->iov_offs <= cnt);
336 : :
337 [ + + ]: 1966269 : if (offs->iov_offs == cnt) {
338 [ - + ]: 1 : assert(!offs->buf_offs);
339 : 1 : *size = 0;
340 : 1 : return NULL;
341 : : }
342 : :
343 : 1966268 : iov = &iovs[offs->iov_offs];
344 : :
345 [ - + ]: 1966268 : assert(offs->buf_offs < iov->iov_len);
346 : :
347 : 1966268 : *size = iov->iov_len - offs->buf_offs;
348 : :
349 : 1966268 : return ((char *)iov->iov_base) + offs->buf_offs;
350 : : }
351 : :
352 : : static inline void *
353 : 1966259 : _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 : 1966259 : size_t arg_size;
358 : :
359 : 1966259 : arg_buf = _iov_arr_get_buf_info(iovs, cnt, offs, &arg_size);
360 [ + + ]: 1966259 : if (!arg_buf) {
361 [ - + - + ]: 1 : SPDK_INFOLOG(fuse_dispatcher, "No %s arg header attached at %zu:%zu\n", direction, offs->iov_offs,
362 : : offs->buf_offs);
363 : 1 : return NULL;
364 : : }
365 : :
366 [ - + ]: 1966258 : 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 [ - + ]: 1966258 : 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 [ + + ]: 1966258 : if (size == arg_size) {
379 : 1966249 : offs->iov_offs++;
380 : 1966249 : offs->buf_offs = 0;
381 : : } else {
382 : 9 : offs->buf_offs += size;
383 : : }
384 : :
385 : 1966258 : return arg_buf;
386 : : }
387 : :
388 : : static inline const char *
389 : 10 : _fsdev_io_in_arg_get_str(struct fuse_io *fuse_io)
390 : : {
391 : : char *arg_buf;
392 : 10 : size_t arg_size, len;
393 : :
394 : 10 : arg_buf = _iov_arr_get_buf_info(fuse_io->in_iov, fuse_io->in_iovcnt, &fuse_io->in_offs,
395 : : &arg_size);
396 [ - + ]: 10 : 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 [ - + ]: 10 : len = strnlen(arg_buf, arg_size);
403 [ - + ]: 10 : 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 : 10 : fuse_io->in_offs.buf_offs += len + 1;
410 : :
411 [ + - ]: 10 : if (len + 1 == arg_size) {
412 : 10 : fuse_io->in_offs.iov_offs++;
413 : 10 : fuse_io->in_offs.buf_offs = 0;
414 : : }
415 : :
416 : 10 : return arg_buf;
417 : : }
418 : :
419 : : static inline void *
420 : 1048655 : _fsdev_io_in_arg_get_buf(struct fuse_io *fuse_io, size_t size)
421 : : {
422 : 1048655 : 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 : 917604 : _fsdev_io_out_arg_get_buf(struct fuse_io *fuse_io, size_t size)
428 : : {
429 : 917604 : 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 : 1048659 : _fuse_op_requires_reply(uint32_t opcode)
435 : : {
436 [ + + ]: 1048659 : switch (opcode) {
437 : 5 : case FUSE_FORGET:
438 : : case FUSE_BATCH_FORGET:
439 : 5 : return false;
440 : 1048654 : default:
441 : 1048654 : return true;
442 : : }
443 : : }
444 : :
445 : : static void
446 : 24 : 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 : 24 : fattr->ino = fsdev_io_h2d_u64(fuse_io, attr->ino);
450 : 24 : fattr->mode = fsdev_io_h2d_u32(fuse_io, attr->mode);
451 : 24 : fattr->nlink = fsdev_io_h2d_u32(fuse_io, attr->nlink);
452 : 24 : fattr->uid = fsdev_io_h2d_u32(fuse_io, attr->uid);
453 : 24 : fattr->gid = fsdev_io_h2d_u32(fuse_io, attr->gid);
454 : 24 : fattr->rdev = fsdev_io_h2d_u32(fuse_io, attr->rdev);
455 : 24 : fattr->size = fsdev_io_h2d_u64(fuse_io, attr->size);
456 : 24 : fattr->blksize = fsdev_io_h2d_u32(fuse_io, attr->blksize);
457 : 24 : fattr->blocks = fsdev_io_h2d_u64(fuse_io, attr->blocks);
458 : 24 : fattr->atime = fsdev_io_h2d_u64(fuse_io, attr->atime);
459 : 24 : fattr->mtime = fsdev_io_h2d_u64(fuse_io, attr->mtime);
460 : 24 : fattr->ctime = fsdev_io_h2d_u64(fuse_io, attr->ctime);
461 : 24 : fattr->atimensec = fsdev_io_h2d_u32(fuse_io, attr->atimensec);
462 : 24 : fattr->mtimensec = fsdev_io_h2d_u32(fuse_io, attr->mtimensec);
463 : 24 : fattr->ctimensec = fsdev_io_h2d_u32(fuse_io, attr->ctimensec);
464 : 24 : }
465 : :
466 : : static uint32_t
467 : 29 : calc_timeout_sec(uint32_t ms)
468 : : {
469 : 29 : return ms / 1000;
470 : : }
471 : :
472 : : static uint32_t
473 : 29 : calc_timeout_nsec(uint32_t ms)
474 : : {
475 : 29 : return (ms % 1000) * 1000000;
476 : : }
477 : :
478 : : static void
479 : 5 : 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 : 5 : arg->nodeid = fsdev_io_h2d_u64(fuse_io, file_ino(fuse_io, fobject));
483 : 5 : arg->generation = 0;
484 : 5 : arg->entry_valid = fsdev_io_h2d_u64(fuse_io, calc_timeout_sec(attr->valid_ms));
485 : 5 : arg->entry_valid_nsec = fsdev_io_h2d_u32(fuse_io, calc_timeout_nsec(attr->valid_ms));
486 : 5 : arg->attr_valid = fsdev_io_h2d_u64(fuse_io, calc_timeout_sec(attr->valid_ms));
487 : 5 : arg->attr_valid_nsec = fsdev_io_h2d_u32(fuse_io, calc_timeout_nsec(attr->valid_ms));
488 : 5 : convert_stat(fuse_io, fobject, attr, &arg->attr);
489 : 5 : }
490 : :
491 : : static void
492 : 2 : fill_open(struct fuse_io *fuse_io, struct fuse_open_out *arg,
493 : : struct spdk_fsdev_file_handle *fhandle)
494 : : {
495 : 2 : arg->fh = fsdev_io_h2d_u64(fuse_io, file_fh(fhandle));
496 : 2 : arg->open_flags = fsdev_io_h2d_u64(fuse_io, FOPEN_DIRECT_IO);
497 : 2 : }
498 : :
499 : : static void
500 : 1 : convert_statfs(struct fuse_io *fuse_io, const struct spdk_fsdev_file_statfs *statfs,
501 : : struct fuse_kstatfs *kstatfs)
502 : : {
503 : 1 : kstatfs->bsize = fsdev_io_h2d_u32(fuse_io, statfs->bsize);
504 : 1 : kstatfs->frsize = fsdev_io_h2d_u32(fuse_io, statfs->frsize);
505 : 1 : kstatfs->blocks = fsdev_io_h2d_u64(fuse_io, statfs->blocks);
506 : 1 : kstatfs->bfree = fsdev_io_h2d_u64(fuse_io, statfs->bfree);
507 : 1 : kstatfs->bavail = fsdev_io_h2d_u64(fuse_io, statfs->bavail);
508 : 1 : kstatfs->files = fsdev_io_h2d_u64(fuse_io, statfs->files);
509 : 1 : kstatfs->ffree = fsdev_io_h2d_u64(fuse_io, statfs->ffree);
510 : 1 : kstatfs->namelen = fsdev_io_h2d_u32(fuse_io, statfs->namelen);
511 : 1 : }
512 : :
513 : : static struct fuse_out_header *
514 : 524327 : 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 [ - + ]: 524327 : assert(fuse_io->out_iovcnt >= 1);
521 [ - + ]: 524327 : assert(error <= 0);
522 : :
523 : 524327 : out = fuse_io->out_iov;
524 : :
525 [ - + ]: 524327 : 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 [ - + ]: 524327 : if (error < -1000) {
531 : 0 : SPDK_ERRLOG("Bad completion error value: %" PRIu32 "\n", error);
532 : 0 : return NULL;
533 : : }
534 : :
535 : 524327 : len = sizeof(*hdr) + out_len;
536 : :
537 : 524327 : hdr = out->iov_base;
538 [ - + ]: 524327 : memset(hdr, 0, sizeof(*hdr));
539 : :
540 : 524327 : hdr->unique = fsdev_io_h2d_u64(fuse_io, fuse_io->hdr.unique);
541 : 524327 : hdr->error = fsdev_io_h2d_i32(fuse_io, error);
542 : 524327 : hdr->len = fsdev_io_h2d_u32(fuse_io, len);
543 : :
544 : 524327 : return hdr;
545 : : }
546 : :
547 : : static void
548 : 524332 : fuse_dispatcher_io_complete_final(struct fuse_io *fuse_io, int error)
549 : : {
550 : 524332 : spdk_fuse_dispatcher_submit_cpl_cb cpl_cb = fuse_io->cpl_cb;
551 : 524332 : 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 : 524332 : spdk_mempool_put(g_fuse_mgr.fuse_io_pool, fuse_io);
557 : :
558 : 524332 : cpl_cb(cpl_cb_arg, error);
559 : 524332 : }
560 : :
561 : : static void
562 : 524327 : fuse_dispatcher_io_complete(struct fuse_io *fuse_io, uint32_t out_len, int error)
563 : : {
564 : 524327 : struct fuse_out_header *hdr = fuse_dispatcher_fill_out_hdr(fuse_io, out_len, error);
565 : :
566 [ - + ]: 524327 : assert(_fuse_op_requires_reply(fuse_io->hdr.opcode));
567 : :
568 [ - + ]: 524327 : if (!hdr) {
569 : 0 : SPDK_ERRLOG("Completion failed: cannot fill out header\n");
570 : 0 : return;
571 : : }
572 : :
573 [ - + - + ]: 524327 : SPDK_DEBUGLOG(fuse_dispatcher,
574 : : "Completing IO#%" PRIu64 " (err=%d, out_len=%" PRIu32 ")\n",
575 : : fuse_io->hdr.unique, error, out_len);
576 : :
577 : 524327 : fuse_dispatcher_io_complete_final(fuse_io, error);
578 : : }
579 : :
580 : : static void
581 : 25 : fuse_dispatcher_io_copy_and_complete(struct fuse_io *fuse_io, const void *out, uint32_t out_len,
582 : : int error)
583 : : {
584 [ + - + - ]: 25 : if (out && out_len) {
585 : 25 : void *buf = _fsdev_io_out_arg_get_buf(fuse_io, out_len);
586 [ + - ]: 25 : if (buf) {
587 [ - + - + ]: 25 : 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 : 25 : fuse_dispatcher_io_complete(fuse_io, out_len, error);
596 : 25 : }
597 : :
598 : : static void
599 : 5 : fuse_dispatcher_io_complete_none(struct fuse_io *fuse_io, int err)
600 : : {
601 [ - + - + ]: 5 : SPDK_DEBUGLOG(fuse_dispatcher, "Completing IO#%" PRIu64 "(err=%d)\n",
602 : : fuse_io->hdr.unique, err);
603 : 5 : fuse_dispatcher_io_complete_final(fuse_io, err);
604 : 5 : }
605 : :
606 : : static void
607 : 2 : fuse_dispatcher_io_complete_ok(struct fuse_io *fuse_io, uint32_t out_len)
608 : : {
609 : 2 : fuse_dispatcher_io_complete(fuse_io, out_len, 0);
610 : 2 : }
611 : :
612 : : static void
613 : 12 : fuse_dispatcher_io_complete_err(struct fuse_io *fuse_io, int err)
614 : : {
615 : 12 : fuse_dispatcher_io_complete(fuse_io, 0, err);
616 : 12 : }
617 : :
618 : : static void
619 : 4 : 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 : 4 : struct fuse_entry_out arg;
623 : 4 : size_t size = fsdev_io_proto_minor(fuse_io) < 9 ?
624 [ - + ]: 4 : FUSE_COMPAT_ENTRY_OUT_SIZE : sizeof(arg);
625 : :
626 [ - + ]: 4 : memset(&arg, 0, sizeof(arg));
627 : 4 : fill_entry(fuse_io, &arg, fobject, attr);
628 : :
629 : 4 : fuse_dispatcher_io_copy_and_complete(fuse_io, &arg, size, 0);
630 : 4 : }
631 : :
632 : : static void
633 : 1 : 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 : 1 : arg = _fsdev_io_out_arg_get_buf(fuse_io, sizeof(*arg));
638 [ - + ]: 1 : 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 : 1 : fill_open(fuse_io, arg, fhandle);
645 : :
646 : 1 : fuse_dispatcher_io_complete_ok(fuse_io, sizeof(*arg));
647 : : }
648 : :
649 : : static void
650 : 1 : 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 : 1 : char buf[sizeof(struct fuse_entry_out) + sizeof(struct fuse_open_out)];
655 : 1 : size_t entrysize = fsdev_io_proto_minor(fuse_io) < 9 ?
656 [ - + ]: 1 : FUSE_COMPAT_ENTRY_OUT_SIZE : sizeof(struct fuse_entry_out);
657 : 1 : struct fuse_entry_out *earg = (struct fuse_entry_out *) buf;
658 : 1 : struct fuse_open_out *oarg = (struct fuse_open_out *)(buf + entrysize);
659 : :
660 [ - + ]: 1 : memset(buf, 0, sizeof(buf));
661 : 1 : fill_entry(fuse_io, earg, fobject, attr);
662 : 1 : fill_open(fuse_io, oarg, fhandle);
663 : :
664 : 1 : fuse_dispatcher_io_copy_and_complete(fuse_io, buf, entrysize + sizeof(struct fuse_open_out), 0);
665 : 1 : }
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 : 393248 : 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 : 393248 : arg = _fsdev_io_out_arg_get_buf(fuse_io, sizeof(*arg));
690 [ - + ]: 393248 : 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 : 393248 : arg->size = fsdev_io_d2h_u32(fuse_io, data_size);
697 : :
698 : 393248 : fuse_dispatcher_io_complete(fuse_io, sizeof(*arg), error);
699 : : }
700 : :
701 : : static void
702 : 1 : fuse_dispatcher_io_complete_statfs(struct fuse_io *fuse_io,
703 : : const struct spdk_fsdev_file_statfs *statfs)
704 : : {
705 : 1 : struct fuse_statfs_out arg;
706 : 1 : size_t size = fsdev_io_proto_minor(fuse_io) < 4 ?
707 [ - + ]: 1 : FUSE_COMPAT_STATFS_SIZE : sizeof(arg);
708 : :
709 [ - + ]: 1 : memset(&arg, 0, sizeof(arg));
710 : 1 : convert_statfs(fuse_io, statfs, &arg.st);
711 : :
712 : 1 : return fuse_dispatcher_io_copy_and_complete(fuse_io, &arg, size, 0);
713 : : }
714 : :
715 : : static void
716 : 19 : fuse_dispatcher_io_complete_attr(struct fuse_io *fuse_io, const struct spdk_fsdev_file_attr *attr)
717 : : {
718 : 19 : struct fuse_attr_out arg;
719 : 19 : size_t size = fsdev_io_proto_minor(fuse_io) < 9 ?
720 [ - + ]: 19 : FUSE_COMPAT_ATTR_OUT_SIZE : sizeof(arg);
721 : :
722 [ - + ]: 19 : memset(&arg, 0, sizeof(arg));
723 : 19 : arg.attr_valid = fsdev_io_h2d_u64(fuse_io, calc_timeout_sec(attr->valid_ms));
724 : 19 : arg.attr_valid_nsec = fsdev_io_h2d_u32(fuse_io, calc_timeout_nsec(attr->valid_ms));
725 : 19 : convert_stat(fuse_io, file_object(fuse_io), attr, &arg.attr);
726 : :
727 : 19 : fuse_dispatcher_io_copy_and_complete(fuse_io, &arg, size, 0);
728 : 19 : }
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 : 524332 : fuse_io_desc(struct fuse_io *fuse_io)
799 : : {
800 : 524332 : return fuse_io->disp->desc;
801 : : }
802 : :
803 : : static void
804 : 8 : 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 : 8 : struct fuse_io *fuse_io = cb_arg;
808 : :
809 [ + + ]: 8 : if (!status) {
810 : 4 : fuse_dispatcher_io_complete_entry(fuse_io, fobject, attr);
811 : : } else {
812 : 4 : fuse_dispatcher_io_complete_err(fuse_io, status);
813 : : }
814 : 8 : }
815 : :
816 : : static void
817 : 8 : do_lookup(struct fuse_io *fuse_io)
818 : : {
819 : : int err;
820 : 8 : const char *name = _fsdev_io_in_arg_get_str(fuse_io);
821 [ - + ]: 8 : 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 : 8 : 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 [ - + ]: 8 : if (err) {
830 : 0 : fuse_dispatcher_io_complete_err(fuse_io, err);
831 : : }
832 : : }
833 : :
834 : : static void
835 : 5 : do_forget_cpl_clb(void *cb_arg, struct spdk_io_channel *ch, int status)
836 : : {
837 : 5 : struct fuse_io *fuse_io = cb_arg;
838 : :
839 : 5 : fuse_dispatcher_io_complete_none(fuse_io, status); /* FUSE_FORGET requires no response */
840 : 5 : }
841 : :
842 : : static void
843 : 5 : do_forget(struct fuse_io *fuse_io)
844 : : {
845 : : int err;
846 : : struct fuse_forget_in *arg;
847 : :
848 : 5 : arg = _fsdev_io_in_arg_get_buf(fuse_io, sizeof(*arg));
849 [ - + ]: 5 : 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 : 5 : 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 [ - + ]: 5 : if (err) {
859 : 0 : fuse_dispatcher_io_complete_err(fuse_io, err);
860 : : }
861 : : }
862 : :
863 : : static void
864 : 17 : do_getattr_cpl_clb(void *cb_arg, struct spdk_io_channel *ch, int status,
865 : : const struct spdk_fsdev_file_attr *attr)
866 : : {
867 : 17 : struct fuse_io *fuse_io = cb_arg;
868 : :
869 [ + - ]: 17 : if (!status) {
870 : 17 : fuse_dispatcher_io_complete_attr(fuse_io, attr);
871 : : } else {
872 : 0 : fuse_dispatcher_io_complete_err(fuse_io, status);
873 : : }
874 : 17 : }
875 : :
876 : : static void
877 : 17 : do_getattr(struct fuse_io *fuse_io)
878 : : {
879 : : int err;
880 : 17 : uint64_t fh = 0;
881 : :
882 [ + - ]: 17 : if (fsdev_io_proto_minor(fuse_io) >= 9) {
883 : : struct fuse_getattr_in *arg;
884 : :
885 : 17 : arg = _fsdev_io_in_arg_get_buf(fuse_io, sizeof(*arg));
886 [ - + ]: 17 : 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 [ - + ]: 17 : 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 : 17 : 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 [ - + ]: 17 : if (err) {
900 : 0 : fuse_dispatcher_io_complete_err(fuse_io, err);
901 : : }
902 : : }
903 : :
904 : : static void
905 : 2 : do_setattr_cpl_clb(void *cb_arg, struct spdk_io_channel *ch, int status,
906 : : const struct spdk_fsdev_file_attr *attr)
907 : : {
908 : 2 : struct fuse_io *fuse_io = cb_arg;
909 : :
910 [ + - ]: 2 : if (!status) {
911 : 2 : fuse_dispatcher_io_complete_attr(fuse_io, attr);
912 : : } else {
913 : 0 : fuse_dispatcher_io_complete_err(fuse_io, status);
914 : : }
915 : 2 : }
916 : :
917 : : static void
918 : 2 : do_setattr(struct fuse_io *fuse_io)
919 : : {
920 : : int err;
921 : : struct fuse_setattr_in *arg;
922 : : uint32_t valid;
923 : 2 : uint64_t fh = 0;
924 : 2 : struct spdk_fsdev_file_attr attr;
925 : :
926 : 2 : arg = _fsdev_io_in_arg_get_buf(fuse_io, sizeof(*arg));
927 [ - + ]: 2 : 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 [ - + ]: 2 : memset(&attr, 0, sizeof(attr));
934 : 2 : attr.mode = fsdev_io_d2h_u32(fuse_io, arg->mode);
935 : 2 : attr.uid = fsdev_io_d2h_u32(fuse_io, arg->uid);
936 : 2 : attr.gid = fsdev_io_d2h_u32(fuse_io, arg->gid);
937 : 2 : attr.size = fsdev_io_d2h_u64(fuse_io, arg->size);
938 : 2 : attr.atime = fsdev_io_d2h_u64(fuse_io, arg->atime);
939 : 2 : attr.mtime = fsdev_io_d2h_u64(fuse_io, arg->mtime);
940 : 2 : attr.ctime = fsdev_io_d2h_u64(fuse_io, arg->ctime);
941 : 2 : attr.atimensec = fsdev_io_d2h_u32(fuse_io, arg->atimensec);
942 : 2 : attr.mtimensec = fsdev_io_d2h_u32(fuse_io, arg->mtimensec);
943 : 2 : attr.ctimensec = fsdev_io_d2h_u32(fuse_io, arg->ctimensec);
944 : :
945 : 2 : valid = fsdev_io_d2h_u64(fuse_io, arg->valid);
946 [ + - ]: 2 : if (valid & FATTR_FH) {
947 : 2 : valid &= ~FATTR_FH;
948 : 2 : fh = fsdev_io_d2h_u64(fuse_io, arg->fh);
949 : : }
950 : :
951 : 2 : 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 : 2 : 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 [ - + ]: 2 : 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 : 1 : do_fopen_cpl_clb(void *cb_arg, struct spdk_io_channel *ch, int status,
1297 : : struct spdk_fsdev_file_handle *fhandle)
1298 : : {
1299 : 1 : struct fuse_io *fuse_io = cb_arg;
1300 : :
1301 [ + - ]: 1 : if (!status) {
1302 : 1 : fuse_dispatcher_io_complete_open(fuse_io, fhandle);
1303 : : } else {
1304 : 0 : fuse_dispatcher_io_complete_err(fuse_io, status);
1305 : : }
1306 : 1 : }
1307 : :
1308 : : static void
1309 : 1 : do_open(struct fuse_io *fuse_io)
1310 : : {
1311 : 1 : struct spdk_fuse_dispatcher *disp = fuse_io->disp;
1312 : : int err;
1313 : : struct fuse_open_in *arg;
1314 : 1 : uint32_t flags;
1315 : :
1316 : 1 : arg = _fsdev_io_in_arg_get_buf(fuse_io, sizeof(*arg));
1317 [ - + ]: 1 : 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 [ - + ]: 1 : 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 : 1 : 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 [ - + ]: 1 : if (err) {
1333 : 0 : fuse_dispatcher_io_complete_err(fuse_io, err);
1334 : : }
1335 : : }
1336 : :
1337 : : static void
1338 : 131040 : do_read_cpl_clb(void *cb_arg, struct spdk_io_channel *ch, int status, uint32_t data_size)
1339 : : {
1340 : 131040 : struct fuse_io *fuse_io = cb_arg;
1341 : :
1342 : 131040 : fuse_dispatcher_io_complete(fuse_io, data_size, status);
1343 : 131040 : }
1344 : :
1345 : : static void
1346 : 131040 : do_read(struct fuse_io *fuse_io)
1347 : : {
1348 : : int err;
1349 : 131040 : bool compat = fsdev_io_proto_minor(fuse_io) < 9;
1350 : : struct fuse_read_in *arg;
1351 : : uint64_t fh;
1352 : 131040 : uint32_t flags = 0;
1353 : :
1354 [ - + ]: 131040 : arg = _fsdev_io_in_arg_get_buf(fuse_io,
1355 : : compat ? offsetof(struct fuse_read_in, lock_owner) : sizeof(*arg));
1356 [ - + ]: 131040 : 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 [ + - ]: 131040 : if (!compat) {
1364 : 131040 : flags = fsdev_io_d2h_u32(fuse_io, arg->flags);
1365 : : }
1366 : :
1367 : 131040 : fh = fsdev_io_d2h_u64(fuse_io, arg->fh);
1368 : :
1369 : 262080 : 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 : 131040 : fsdev_io_d2h_u32(fuse_io, arg->size), fsdev_io_d2h_u64(fuse_io, arg->offset),
1372 : 131040 : flags, fuse_io->out_iov + 1, fuse_io->out_iovcnt - 1, NULL,
1373 : : do_read_cpl_clb, fuse_io);
1374 [ - + ]: 131040 : if (err) {
1375 : 0 : fuse_dispatcher_io_complete_err(fuse_io, err);
1376 : : }
1377 : : }
1378 : :
1379 : : static void
1380 : 393248 : do_write_cpl_clb(void *cb_arg, struct spdk_io_channel *ch, int status, uint32_t data_size)
1381 : : {
1382 : 393248 : struct fuse_io *fuse_io = cb_arg;
1383 : :
1384 : 393248 : fuse_dispatcher_io_complete_write(fuse_io, data_size, status);
1385 : 393248 : }
1386 : :
1387 : : static void
1388 : 393248 : do_write(struct fuse_io *fuse_io)
1389 : : {
1390 : : int err;
1391 : 393248 : bool compat = fsdev_io_proto_minor(fuse_io) < 9;
1392 : : struct fuse_write_in *arg;
1393 : : uint64_t fh;
1394 : 393248 : uint64_t flags = 0;
1395 : :
1396 [ - + ]: 393248 : arg = _fsdev_io_in_arg_get_buf(fuse_io,
1397 : : compat ? FUSE_COMPAT_WRITE_IN_SIZE : sizeof(*arg));
1398 [ - + ]: 393248 : 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 [ - + ]: 393248 : 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 [ + - ]: 393248 : if (!compat) {
1411 : 393248 : flags = fsdev_io_d2h_u32(fuse_io, arg->flags);
1412 : : }
1413 : :
1414 : 393248 : fh = fsdev_io_d2h_u64(fuse_io, arg->fh);
1415 : :
1416 : 786496 : 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 : 393248 : fsdev_io_d2h_u32(fuse_io, arg->size), fsdev_io_d2h_u64(fuse_io, arg->offset),
1419 : 393248 : 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 [ - + ]: 393248 : if (err) {
1422 : 0 : fuse_dispatcher_io_complete_err(fuse_io, err);
1423 : : }
1424 : : }
1425 : :
1426 : : static void
1427 : 1 : do_statfs_cpl_clb(void *cb_arg, struct spdk_io_channel *ch, int status,
1428 : : const struct spdk_fsdev_file_statfs *statfs)
1429 : : {
1430 : 1 : struct fuse_io *fuse_io = cb_arg;
1431 : :
1432 [ + - ]: 1 : if (!status) {
1433 : 1 : fuse_dispatcher_io_complete_statfs(fuse_io, statfs);
1434 : : } else {
1435 : 0 : fuse_dispatcher_io_complete_err(fuse_io, status);
1436 : : }
1437 : 1 : }
1438 : :
1439 : : static void
1440 : 1 : do_statfs(struct fuse_io *fuse_io)
1441 : : {
1442 : : int err;
1443 : :
1444 : 1 : 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 [ - + ]: 1 : if (err) {
1447 : 0 : fuse_dispatcher_io_complete_err(fuse_io, err);
1448 : : }
1449 : 1 : }
1450 : :
1451 : : static void
1452 : 2 : do_release_cpl_clb(void *cb_arg, struct spdk_io_channel *ch, int status)
1453 : : {
1454 : 2 : struct fuse_io *fuse_io = cb_arg;
1455 : :
1456 : 2 : fuse_dispatcher_io_complete_err(fuse_io, status);
1457 : 2 : }
1458 : :
1459 : : static void
1460 : 2 : do_release(struct fuse_io *fuse_io)
1461 : : {
1462 : : int err;
1463 : 2 : bool compat = fsdev_io_proto_minor(fuse_io) < 8;
1464 : : struct fuse_release_in *arg;
1465 : : uint64_t fh;
1466 : :
1467 [ - + ]: 2 : arg = _fsdev_io_in_arg_get_buf(fuse_io,
1468 : : compat ? offsetof(struct fuse_release_in, lock_owner) : sizeof(*arg));
1469 [ - + ]: 2 : 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 : 2 : fh = fsdev_io_d2h_u64(fuse_io, arg->fh);
1476 : :
1477 : 2 : 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 [ - + ]: 2 : if (err) {
1481 : 0 : fuse_dispatcher_io_complete_err(fuse_io, err);
1482 : : }
1483 : : }
1484 : :
1485 : : static void
1486 : 1 : do_fsync_cpl_clb(void *cb_arg, struct spdk_io_channel *ch, int status)
1487 : : {
1488 : 1 : struct fuse_io *fuse_io = cb_arg;
1489 : :
1490 : 1 : fuse_dispatcher_io_complete_err(fuse_io, status);
1491 : 1 : }
1492 : :
1493 : : static void
1494 : 1 : 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 : 1 : arg = _fsdev_io_in_arg_get_buf(fuse_io, sizeof(*arg));
1502 [ - + ]: 1 : 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 : 1 : fh = fsdev_io_d2h_u64(fuse_io, arg->fh);
1509 : 1 : datasync = (fsdev_io_d2h_u32(fuse_io, arg->fsync_flags) & 1) ? true : false;
1510 : :
1511 : 1 : 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 [ - + ]: 1 : 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 : 1 : do_getxattr_cpl_clb(void *cb_arg, struct spdk_io_channel *ch, int status, size_t value_size)
1568 : : {
1569 : 1 : struct fuse_io *fuse_io = cb_arg;
1570 : :
1571 [ - + ]: 1 : if (!status) {
1572 : 0 : fuse_dispatcher_io_complete_xattr(fuse_io, value_size);
1573 : : } else {
1574 : 1 : fuse_dispatcher_io_complete_err(fuse_io, status);
1575 : : }
1576 : 1 : }
1577 : :
1578 : : static void
1579 : 1 : 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 : 1 : arg = _fsdev_io_in_arg_get_buf(fuse_io, sizeof(*arg));
1589 [ - + ]: 1 : 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 : 1 : name = _fsdev_io_in_arg_get_str(fuse_io);
1596 [ - + ]: 1 : 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 [ - + ]: 1 : 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 : 1 : 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 : 1 : out_offs_bu = fuse_io->out_offs; /* Preserve the out offset */
1615 : :
1616 : : /* Skip the fuse_getxattr_out */
1617 : 1 : _fsdev_io_out_arg_get_buf(fuse_io, sizeof(struct fuse_getxattr_out));
1618 : 1 : size -= sizeof(struct fuse_getxattr_out);
1619 : :
1620 : 1 : buff = _fsdev_io_out_arg_get_buf(fuse_io, size); /* Get the buffer for the xattr */
1621 [ + - ]: 1 : if (!buff) {
1622 [ - + - + ]: 1 : SPDK_INFOLOG(fuse_dispatcher, "NULL buffer, probably asking for the size\n");
1623 : 1 : size = 0;
1624 : : }
1625 : :
1626 : 1 : fuse_io->out_offs = out_offs_bu; /* Restore the out offset */
1627 : :
1628 : 1 : 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 [ - + ]: 1 : 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 : 2 : do_flush_cpl_clb(void *cb_arg, struct spdk_io_channel *ch, int status)
1711 : : {
1712 : 2 : struct fuse_io *fuse_io = cb_arg;
1713 : :
1714 : 2 : fuse_dispatcher_io_complete_err(fuse_io, status);
1715 : 2 : }
1716 : :
1717 : : static void
1718 : 2 : do_flush(struct fuse_io *fuse_io)
1719 : : {
1720 : : int err;
1721 : 2 : bool compat = fsdev_io_proto_minor(fuse_io) < 7;
1722 : : struct fuse_flush_in *arg;
1723 : : uint64_t fh;
1724 : :
1725 [ - + ]: 2 : arg = _fsdev_io_in_arg_get_buf(fuse_io,
1726 : : compat ? offsetof(struct fuse_flush_in, lock_owner) : sizeof(*arg));
1727 [ - + ]: 2 : 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 : 2 : fh = fsdev_io_d2h_u64(fuse_io, arg->fh);
1734 : :
1735 : 2 : 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 [ - + ]: 2 : if (err) {
1739 : 0 : fuse_dispatcher_io_complete_err(fuse_io, err);
1740 : : }
1741 : : }
1742 : :
1743 : : static void
1744 : 1 : fuse_dispatcher_close_fsdev_and_complete_msg(void *ctx)
1745 : : {
1746 : 1 : struct fuse_io *fuse_io = ctx;
1747 : 1 : struct spdk_fuse_dispatcher *disp = fuse_io->disp;
1748 : :
1749 : 1 : spdk_fsdev_close(disp->desc);
1750 : :
1751 [ - + - + ]: 1 : SPDK_DEBUGLOG(fuse_dispatcher, "%s: fdev closed\n", fuse_dispatcher_name(disp));
1752 : :
1753 : 1 : disp->desc = NULL;
1754 : 1 : disp->fsdev_thread = NULL;
1755 : :
1756 : 1 : fuse_dispatcher_io_complete_err(fuse_io, fuse_io->u.fsdev_close.status);
1757 : 1 : }
1758 : :
1759 : : static void
1760 : 1 : fuse_dispatcher_close_fsdev_and_complete(struct fuse_io *fuse_io, int status)
1761 : : {
1762 : 1 : struct spdk_fuse_dispatcher *disp = fuse_io->disp;
1763 : :
1764 [ - + ]: 1 : assert(disp->desc);
1765 : :
1766 : 1 : fuse_io->u.fsdev_close.status = status;
1767 : :
1768 [ - + ]: 1 : 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 : 1 : fuse_dispatcher_close_fsdev_and_complete_msg(fuse_io);
1772 : : }
1773 : 1 : }
1774 : :
1775 : : static void fuse_dispatcher_open_fsdev_rollback(struct fuse_io *fuse_io);
1776 : :
1777 : : static void
1778 : 1 : 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 : 1 : struct fuse_io *fuse_io = cb_arg;
1782 : 1 : struct spdk_fuse_dispatcher *disp = fuse_io->disp;
1783 : :
1784 [ + - ]: 1 : if (!status) {
1785 : 1 : disp->root_fobject = fobject;
1786 [ - + - + ]: 1 : SPDK_DEBUGLOG(fuse_dispatcher, "root fobject successfully acquired\n");
1787 : 1 : 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 : 1 : }
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 : 1 : fuse_dispatcher_open_fsdev_continue(struct fuse_io *fuse_io)
1838 : : {
1839 : 1 : struct spdk_fuse_dispatcher *disp = fuse_io->disp;
1840 : 1 : struct fuse_init_out outarg;
1841 : 1 : size_t outargsize = sizeof(outarg);
1842 : 1 : uint32_t max_readahead = DEFAULT_MAX_READAHEAD;
1843 : 1 : uint32_t flags = 0;
1844 : : void *out_buf;
1845 : : int res;
1846 : :
1847 [ - + ]: 1 : assert(disp->desc);
1848 : :
1849 [ - + ]: 1 : memset(&outarg, 0, sizeof(outarg));
1850 : 1 : outarg.major = fsdev_io_h2d_u32(fuse_io, FUSE_KERNEL_VERSION);
1851 : 1 : outarg.minor = fsdev_io_h2d_u32(fuse_io, FUSE_KERNEL_MINOR_VERSION);
1852 : :
1853 [ - + ]: 1 : if (disp->proto_minor < 5) {
1854 : 0 : outargsize = FUSE_COMPAT_INIT_OUT_SIZE;
1855 [ - + ]: 1 : } else if (disp->proto_minor < 23) {
1856 : 0 : outargsize = FUSE_COMPAT_22_INIT_OUT_SIZE;
1857 : : }
1858 : :
1859 [ - + + - ]: 1 : if (!fuse_io->u.init.legacy_in) {
1860 : 1 : max_readahead = fsdev_io_d2h_u32(fuse_io, fuse_io->u.init.in->max_readahead);
1861 : 1 : flags = fsdev_io_d2h_u32(fuse_io, fuse_io->u.init.in->flags);
1862 : :
1863 [ - + - + ]: 1 : 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 : 1 : outarg.flags = FUSE_BIG_WRITES;
1869 : :
1870 : : #define LL_SET_DEFAULT(cond, cap) \
1871 : : if ((cond) && flags & (cap)) \
1872 : : outarg.flags |= (cap)
1873 [ + - ]: 1 : LL_SET_DEFAULT(true, FUSE_ASYNC_READ);
1874 [ + - ]: 1 : LL_SET_DEFAULT(true, FUSE_AUTO_INVAL_DATA);
1875 [ + - ]: 1 : LL_SET_DEFAULT(true, FUSE_ASYNC_DIO);
1876 [ + - ]: 1 : LL_SET_DEFAULT(true, FUSE_ATOMIC_O_TRUNC);
1877 [ + - ]: 1 : LL_SET_DEFAULT(true, FUSE_FLOCK_LOCKS);
1878 [ + - ]: 1 : LL_SET_DEFAULT(true, FUSE_DO_READDIRPLUS);
1879 [ + - ]: 1 : LL_SET_DEFAULT(true, FUSE_READDIRPLUS_AUTO);
1880 [ + - ]: 1 : LL_SET_DEFAULT(true, FUSE_EXPORT_SUPPORT);
1881 [ + - + - ]: 1 : LL_SET_DEFAULT(fuse_io->u.init.opts.writeback_cache_enabled, FUSE_WRITEBACK_CACHE);
1882 : :
1883 : 1 : outarg.flags = fsdev_io_h2d_u32(fuse_io, outarg.flags);
1884 : 1 : outarg.max_readahead = fsdev_io_h2d_u32(fuse_io, max_readahead);
1885 : 1 : outarg.max_write = fsdev_io_h2d_u32(fuse_io, fuse_io->u.init.opts.max_write);
1886 [ + - ]: 1 : if (fsdev_io_proto_minor(fuse_io) >= 13) {
1887 : 1 : outarg.max_background = fsdev_io_h2d_u16(fuse_io, DEFAULT_MAX_BACKGROUND);
1888 : 1 : outarg.congestion_threshold = fsdev_io_h2d_u16(fuse_io, DEFAULT_CONGESTION_THRESHOLD);
1889 : : }
1890 : :
1891 [ + - ]: 1 : if (fsdev_io_proto_minor(fuse_io) >= 23) {
1892 : 1 : outarg.time_gran = fsdev_io_h2d_u32(fuse_io, DEFAULT_TIME_GRAN);
1893 : : }
1894 : :
1895 [ - + - + ]: 1 : 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 [ - + - + ]: 1 : SPDK_INFOLOG(fuse_dispatcher, "flags: 0x%08" PRIx32 "\n", fsdev_io_d2h_u32(fuse_io, outarg.flags));
1898 [ - + - + ]: 1 : SPDK_INFOLOG(fuse_dispatcher, "max_readahead: %" PRIu32 "\n",
1899 : : fsdev_io_d2h_u32(fuse_io, outarg.max_readahead));
1900 [ - + - + ]: 1 : SPDK_INFOLOG(fuse_dispatcher, "max_write: %" PRIu32 "\n",
1901 : : fsdev_io_d2h_u32(fuse_io, outarg.max_write));
1902 [ - + - + ]: 1 : SPDK_INFOLOG(fuse_dispatcher, "max_background: %" PRIu16 "\n",
1903 : : fsdev_io_d2h_u16(fuse_io, outarg.max_background));
1904 [ - + - + ]: 1 : SPDK_INFOLOG(fuse_dispatcher, "congestion_threshold: %" PRIu16 "\n",
1905 : : fsdev_io_d2h_u16(fuse_io, outarg.congestion_threshold));
1906 [ - + - + ]: 1 : SPDK_INFOLOG(fuse_dispatcher, "time_gran: %" PRIu32 "\n", fsdev_io_d2h_u32(fuse_io,
1907 : : outarg.time_gran));
1908 : :
1909 : 1 : out_buf = _fsdev_io_out_arg_get_buf(fuse_io, outargsize);
1910 [ - + ]: 1 : 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 [ - + - + ]: 1 : memcpy(out_buf, &outarg, outargsize);
1917 : :
1918 : 1 : fuse_io->u.init.out_len = outargsize;
1919 : :
1920 : 1 : 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 [ - + ]: 1 : 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 : 1 : fuse_dispatcher_get_channel(struct spdk_io_channel_iter *i)
1931 : : {
1932 : 1 : struct fuse_io *fuse_io = spdk_io_channel_iter_get_ctx(i);
1933 : 1 : struct spdk_io_channel *io_ch = spdk_io_channel_iter_get_channel(i);
1934 : 1 : struct spdk_fuse_dispatcher_channel *ch = __disp_ch_from_io_ch(io_ch);
1935 : 1 : struct spdk_fuse_dispatcher *disp = fuse_io->disp;
1936 : :
1937 [ - + ]: 1 : assert(!ch->fsdev_io_ch);
1938 : :
1939 : 1 : ch->fsdev_io_ch = spdk_fsdev_get_io_channel(disp->desc);
1940 : :
1941 [ + - ]: 1 : if (spdk_io_channel_get_thread(io_ch) == fuse_io->u.init.thread) {
1942 : 1 : fuse_io->ch = ch->fsdev_io_ch;
1943 : : }
1944 : :
1945 : 1 : spdk_for_each_channel_continue(i, 0);
1946 : 1 : }
1947 : :
1948 : : static void
1949 : 1 : fuse_dispatcher_get_channel_done(struct spdk_io_channel_iter *i, int status)
1950 : : {
1951 : 1 : struct fuse_io *fuse_io = spdk_io_channel_iter_get_ctx(i);
1952 : 1 : struct spdk_fuse_dispatcher *disp = fuse_io->disp;
1953 : :
1954 [ - + ]: 1 : 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 [ - + - + ]: 1 : SPDK_DEBUGLOG(fuse_dispatcher, "%s: getting succeeded\n", fuse_dispatcher_name(disp));
1961 : 1 : 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 : 1 : fuse_dispatcher_open_fsdev(struct fuse_io *fuse_io)
2015 : : {
2016 : 1 : struct spdk_fuse_dispatcher *disp = fuse_io->disp;
2017 : : int rc;
2018 : :
2019 [ - + ]: 1 : assert(!disp->desc);
2020 : :
2021 : 1 : rc = spdk_fsdev_open(disp->fsdev_name, fuse_dispatcher_fsdev_event_cb, disp, &fuse_io->u.init.opts,
2022 : : &disp->desc);
2023 [ - + ]: 1 : if (rc) {
2024 : 0 : SPDK_ERRLOG("spdk_fsdev_open failed with %d\n", rc);
2025 : 0 : return false;
2026 : : }
2027 : :
2028 : 1 : disp->fsdev_thread = spdk_get_thread();
2029 : :
2030 [ - + - + ]: 1 : SPDK_DEBUGLOG(fuse_dispatcher, "%s: spdk_fsdev_open succeeded\n", fuse_dispatcher_name(disp));
2031 : :
2032 : 1 : spdk_for_each_channel(__disp_to_io_dev(disp),
2033 : : fuse_dispatcher_get_channel,
2034 : : fuse_io,
2035 : : fuse_dispatcher_get_channel_done);
2036 : 1 : return true;
2037 : : }
2038 : :
2039 : : static void
2040 : 1 : do_init(struct fuse_io *fuse_io)
2041 : : {
2042 : 1 : size_t compat_size = offsetof(struct fuse_init_in, max_readahead);
2043 : 1 : struct spdk_fuse_dispatcher *disp = fuse_io->disp;
2044 : 1 : uint32_t flags = 0;
2045 : :
2046 : : /* First try to read the legacy header */
2047 : 1 : fuse_io->u.init.in = _fsdev_io_in_arg_get_buf(fuse_io, compat_size);
2048 [ - + ]: 1 : 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 : 1 : disp->proto_major = fsdev_io_d2h_u32(fuse_io, fuse_io->u.init.in->major);
2055 : 1 : disp->proto_minor = fsdev_io_d2h_u32(fuse_io, fuse_io->u.init.in->minor);
2056 : :
2057 [ - + - + ]: 1 : 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 [ + - + - ]: 1 : if (disp->proto_major == 7 && disp->proto_minor >= 6) {
2063 : 1 : void *arg_extra = _fsdev_io_in_arg_get_buf(fuse_io, sizeof(*fuse_io->u.init.in) - compat_size);
2064 [ - + ]: 1 : 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 : 1 : fuse_io->u.init.legacy_in = false;
2071 : : } else {
2072 : 0 : fuse_io->u.init.legacy_in = true;
2073 : : }
2074 : :
2075 [ - + ]: 1 : 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 [ - + ]: 1 : 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 [ - + + - ]: 1 : if (!fuse_io->u.init.legacy_in) {
2097 : 1 : flags = fsdev_io_d2h_u32(fuse_io, fuse_io->u.init.in->flags);
2098 : :
2099 [ - + - + ]: 1 : SPDK_INFOLOG(fuse_dispatcher, "flags=0x%" PRIx32 "\n", flags);
2100 : : }
2101 : :
2102 [ - + ]: 1 : memset(&fuse_io->u.init.opts, 0, sizeof(fuse_io->u.init.opts));
2103 : 1 : fuse_io->u.init.opts.opts_size = sizeof(fuse_io->u.init.opts);
2104 : 1 : fuse_io->u.init.opts.max_write = 0;
2105 : 1 : fuse_io->u.init.opts.writeback_cache_enabled = flags & FUSE_WRITEBACK_CACHE ? true : false;
2106 : 1 : fuse_io->u.init.thread = spdk_get_thread();
2107 : :
2108 [ - + ]: 1 : 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 : 1 : 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 : 1 : struct fuse_io *fuse_io = cb_arg;
2389 : :
2390 [ + - ]: 1 : if (!status) {
2391 : 1 : fuse_dispatcher_io_complete_create(fuse_io, fobject, attr, fhandle);
2392 : : } else {
2393 : 0 : fuse_dispatcher_io_complete_err(fuse_io, status);
2394 : : }
2395 : 1 : }
2396 : :
2397 : : static void
2398 : 1 : do_create(struct fuse_io *fuse_io)
2399 : : {
2400 : : int err;
2401 : 1 : struct spdk_fuse_dispatcher *disp = fuse_io->disp;
2402 : 1 : bool compat = fsdev_io_proto_minor(fuse_io) < 12;
2403 : : struct fuse_create_in *arg;
2404 : : const char *name;
2405 : 1 : uint32_t flags, mode, umask = 0;
2406 [ - + ]: 1 : size_t arg_size = compat ? sizeof(struct fuse_open_in) : sizeof(*arg);
2407 : :
2408 : 1 : arg = _fsdev_io_in_arg_get_buf(fuse_io, arg_size);
2409 [ - + ]: 1 : 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 : 1 : name = _fsdev_io_in_arg_get_str(fuse_io);
2416 [ - + ]: 1 : 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 : 1 : mode = fsdev_io_d2h_u32(fuse_io, arg->mode);
2423 [ + - ]: 1 : if (!compat) {
2424 : 1 : umask = fsdev_io_d2h_u32(fuse_io, arg->umask);
2425 : : }
2426 : :
2427 [ - + ]: 1 : 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 : 1 : 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 [ - + ]: 1 : 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 : 1 : do_fallocate_cpl_clb(void *cb_arg, struct spdk_io_channel *ch, int status)
2496 : : {
2497 : 1 : struct fuse_io *fuse_io = cb_arg;
2498 : :
2499 : 1 : fuse_dispatcher_io_complete_err(fuse_io, status);
2500 : 1 : }
2501 : :
2502 : : static void
2503 : 1 : do_fallocate(struct fuse_io *fuse_io)
2504 : : {
2505 : : int err;
2506 : : struct fuse_fallocate_in *arg;
2507 : : uint64_t fh;
2508 : :
2509 : 1 : arg = _fsdev_io_in_arg_get_buf(fuse_io, sizeof(*arg));
2510 [ - + ]: 1 : 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 : 1 : fh = fsdev_io_d2h_u64(fuse_io, arg->fh);
2517 : :
2518 : 1 : 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 : 1 : fsdev_io_d2h_u32(fuse_io, arg->mode), fsdev_io_d2h_u64(fuse_io, arg->offset),
2521 : 1 : fsdev_io_d2h_u64(fuse_io, arg->length),
2522 : : do_fallocate_cpl_clb, fuse_io);
2523 [ - + ]: 1 : if (err) {
2524 : 0 : fuse_dispatcher_io_complete_err(fuse_io, err);
2525 : : }
2526 : : }
2527 : :
2528 : : static void
2529 : 1 : fuse_dispatcher_destroy_put_channel(struct spdk_io_channel_iter *i)
2530 : : {
2531 : 1 : struct spdk_io_channel *io_ch = spdk_io_channel_iter_get_channel(i);
2532 : 1 : struct spdk_fuse_dispatcher_channel *ch = __disp_ch_from_io_ch(io_ch);
2533 : :
2534 [ + - ]: 1 : if (ch->fsdev_io_ch) {
2535 : 1 : spdk_put_io_channel(ch->fsdev_io_ch);
2536 : 1 : ch->fsdev_io_ch = NULL;
2537 : : }
2538 : :
2539 : 1 : spdk_for_each_channel_continue(i, 0);
2540 : 1 : }
2541 : :
2542 : : static void
2543 : 1 : fuse_dispatcher_destroy_put_channel_done(struct spdk_io_channel_iter *i, int status)
2544 : : {
2545 : 1 : struct fuse_io *fuse_io = spdk_io_channel_iter_get_ctx(i);
2546 : 1 : struct spdk_fuse_dispatcher *disp = fuse_io->disp;
2547 : :
2548 [ - + ]: 1 : 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 [ - + - + ]: 1 : SPDK_DEBUGLOG(fuse_dispatcher, "%s: putting channels succeeded. Releasing the fdev\n",
2555 : : fuse_dispatcher_name(disp));
2556 : :
2557 : 1 : fuse_dispatcher_close_fsdev_and_complete(fuse_io, 0);
2558 : : }
2559 : :
2560 : : static void
2561 : 1 : do_forget_root_cpl_clb(void *cb_arg, struct spdk_io_channel *ch, int status)
2562 : : {
2563 : 1 : struct fuse_io *fuse_io = cb_arg;
2564 : 1 : struct spdk_fuse_dispatcher *disp = fuse_io->disp;
2565 : :
2566 [ - + ]: 1 : 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 : 1 : disp->root_fobject = NULL;
2573 [ - + - + ]: 1 : SPDK_DEBUGLOG(fuse_dispatcher, "root fobject successfully forgotten\n");
2574 : :
2575 : 1 : 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 : 1 : do_destroy(struct fuse_io *fuse_io)
2583 : : {
2584 : 1 : struct spdk_fuse_dispatcher *disp = fuse_io->disp;
2585 : :
2586 : 1 : disp->proto_major = disp->proto_minor = 0;
2587 : :
2588 [ - + - + ]: 1 : SPDK_DEBUGLOG(fuse_dispatcher, "DESTROY\n");
2589 : :
2590 [ + - ]: 1 : if (disp->root_fobject) {
2591 : 1 : 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 [ - + ]: 1 : 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 : 524332 : 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 [ + - - + ]: 524332 : 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 : 524332 : hdr = _fsdev_io_in_arg_get_buf(fuse_io, sizeof(*hdr));
2814 [ - + ]: 524332 : if (!hdr) {
2815 : 0 : SPDK_ERRLOG("Bad IO: cannot get fuse_in_header\n");
2816 : 0 : goto exit;
2817 : : }
2818 : :
2819 : 524332 : fuse_io->hdr.opcode = fsdev_io_d2h_u32(fuse_io, hdr->opcode);
2820 : :
2821 [ + + ]: 524332 : if (spdk_unlikely(!fuse_io->ch)) {
2822 : : /* FUSE_INIT is allowed with no channel. It'll open the fsdev and get channels */
2823 [ - + ]: 1 : 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 [ + + ]: 524332 : if (spdk_likely(_fuse_op_requires_reply(hdr->opcode))) {
2831 : 524327 : struct fuse_out_header *out_hdr = _fsdev_io_out_arg_get_buf(fuse_io, sizeof(*out_hdr));
2832 [ - + ]: 524327 : 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 [ - + ]: 524332 : 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 [ - + ]: 524332 : 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 : 524332 : fuse_io->hdr.len = fsdev_io_d2h_u32(fuse_io, hdr->len);
2855 : 524332 : fuse_io->hdr.unique = fsdev_io_d2h_u64(fuse_io, hdr->unique);
2856 : 524332 : fuse_io->hdr.nodeid = fsdev_io_d2h_u64(fuse_io, hdr->nodeid);
2857 : 524332 : fuse_io->hdr.uid = fsdev_io_d2h_u32(fuse_io, hdr->uid);
2858 : 524332 : fuse_io->hdr.gid = fsdev_io_d2h_u32(fuse_io, hdr->gid);
2859 : 524332 : fuse_io->hdr.pid = fsdev_io_d2h_u32(fuse_io, hdr->pid);
2860 : :
2861 [ - + - + ]: 524332 : 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 : 524332 : fuse_ll_ops[fuse_io->hdr.opcode].func(fuse_io);
2867 : 524332 : 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 : 1 : fuse_dispatcher_channel_create(void *io_device, void *ctx_buf)
2876 : : {
2877 : 1 : struct spdk_fuse_dispatcher *disp = __disp_from_io_dev(io_device);
2878 : 1 : struct spdk_fuse_dispatcher_channel *ch = ctx_buf;
2879 : :
2880 [ - + ]: 1 : if (disp->desc) {
2881 : 0 : ch->fsdev_io_ch = spdk_fsdev_get_io_channel(disp->desc);
2882 : : }
2883 : :
2884 : 1 : return 0;
2885 : : }
2886 : :
2887 : : static void
2888 : 1 : fuse_dispatcher_channel_destroy(void *io_device, void *ctx_buf)
2889 : : {
2890 : 1 : struct spdk_fuse_dispatcher *disp = __disp_from_io_dev(io_device);
2891 : 1 : struct spdk_fuse_dispatcher_channel *ch = ctx_buf;
2892 : :
2893 : : UNUSED(disp);
2894 : :
2895 [ - + ]: 1 : 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 : 1 : }
2901 : :
2902 : : int
2903 : 1 : 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 [ + - + - : 1 : if (!fsdev_name || !event_cb || !cb) {
- + ]
2911 : 0 : SPDK_ERRLOG("Invalid params\n");
2912 : 0 : return -EINVAL;
2913 : : }
2914 : :
2915 : 1 : io_dev_name = spdk_sprintf_alloc("fuse_disp_%s", fsdev_name);
2916 [ - + ]: 1 : 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 [ - + ]: 1 : fsdev_name_len = strlen(fsdev_name);
2922 : :
2923 : 1 : disp = calloc(1, sizeof(*disp) + fsdev_name_len + 1);
2924 [ - + ]: 1 : 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 : 1 : pthread_mutex_lock(&g_fuse_mgr.lock);
2931 [ + - ]: 1 : if (!g_fuse_mgr.ref_cnt) {
2932 : 1 : struct spdk_fsdev_opts opts;
2933 : 1 : spdk_fsdev_get_opts(&opts, sizeof(opts));
2934 : :
2935 : 2 : g_fuse_mgr.fuse_io_pool = spdk_mempool_create("FUSE_disp_ios", opts.fsdev_io_pool_size,
2936 : 1 : sizeof(struct fuse_io), opts.fsdev_io_cache_size, SPDK_ENV_SOCKET_ID_ANY);
2937 [ - + ]: 1 : 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 : 1 : g_fuse_mgr.ref_cnt++;
2946 : 1 : pthread_mutex_unlock(&g_fuse_mgr.lock);
2947 : :
2948 : 1 : 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 : 1 : free(io_dev_name);
2954 : :
2955 [ - + - + ]: 1 : memcpy(disp->fsdev_name, fsdev_name, fsdev_name_len + 1);
2956 : 1 : disp->event_cb = event_cb;
2957 : 1 : disp->event_ctx = event_ctx;
2958 : 1 : disp->fuse_arch = SPDK_FUSE_ARCH_NATIVE;
2959 : :
2960 : 1 : cb(cb_arg, disp);
2961 : :
2962 : 1 : 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 : 1 : spdk_fuse_dispatcher_get_io_channel(struct spdk_fuse_dispatcher *disp)
2990 : : {
2991 : 1 : return spdk_get_io_channel(__disp_to_io_dev(disp));
2992 : : }
2993 : :
2994 : : int
2995 : 524332 : 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 : 524332 : struct spdk_fuse_dispatcher_channel *disp_ch = __disp_ch_from_io_ch(ch);
3003 : :
3004 : 524332 : fuse_io = spdk_mempool_get(g_fuse_mgr.fuse_io_pool);
3005 : :
3006 [ - + ]: 524332 : if (!fuse_io) {
3007 : 0 : SPDK_ERRLOG("We ran out of FUSE IOs\n");
3008 : 0 : return -ENOBUFS;
3009 : : }
3010 : :
3011 : 524332 : fuse_io->disp = disp;
3012 : 524332 : fuse_io->ch = disp_ch->fsdev_io_ch;
3013 : 524332 : fuse_io->in_iov = in_iov;
3014 : 524332 : fuse_io->in_iovcnt = in_iovcnt;
3015 : 524332 : fuse_io->out_iov = out_iov;
3016 : 524332 : fuse_io->out_iovcnt = out_iovcnt;
3017 : 524332 : fuse_io->cpl_cb = clb;
3018 : 524332 : fuse_io->cpl_cb_arg = cb_arg;
3019 : :
3020 : 524332 : fuse_io->in_offs.iov_offs = 0;
3021 : 524332 : fuse_io->in_offs.buf_offs = 0;
3022 : 524332 : fuse_io->out_offs.iov_offs = 0;
3023 : 524332 : fuse_io->out_offs.buf_offs = 0;
3024 : :
3025 : 524332 : 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 : 1 : fuse_dispatcher_delete_done(struct fuse_dispatcher_delete_ctx *ctx, int status)
3036 : : {
3037 : 1 : struct spdk_fuse_dispatcher *disp = ctx->disp;
3038 : :
3039 [ + - ]: 1 : if (!status) {
3040 [ - + - + ]: 1 : SPDK_DEBUGLOG(fuse_dispatcher, "%s: deletion succeeded\n", fuse_dispatcher_name(disp));
3041 : :
3042 : 1 : spdk_io_device_unregister(__disp_to_io_dev(disp), NULL);
3043 : :
3044 : 1 : free(disp);
3045 : :
3046 [ - + ]: 1 : pthread_mutex_lock(&g_fuse_mgr.lock);
3047 : 1 : g_fuse_mgr.ref_cnt--;
3048 [ + - ]: 1 : if (!g_fuse_mgr.ref_cnt) {
3049 : 1 : spdk_mempool_free(g_fuse_mgr.fuse_io_pool);
3050 : 1 : g_fuse_mgr.fuse_io_pool = NULL;
3051 : : }
3052 [ - + ]: 1 : 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 : 1 : ctx->cb(ctx->cb_arg, (uint32_t)(-status));
3058 : 1 : free(ctx);
3059 : 1 : }
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 : 1 : 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 : 1 : ctx = calloc(1, sizeof(*ctx));
3102 [ - + ]: 1 : if (!ctx) {
3103 : 0 : SPDK_ERRLOG("cannot allocate context\n");
3104 : 0 : return -ENOMEM;
3105 : : }
3106 : :
3107 : 1 : ctx->disp = disp;
3108 : 1 : ctx->cb = cb;
3109 : 1 : ctx->cb_arg = cb_arg;
3110 : :
3111 [ - + ]: 1 : 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 : 1 : fuse_dispatcher_delete_done(ctx, 0);
3121 : : }
3122 : :
3123 : 1 : return 0;
3124 : : }
3125 : :
3126 : 199 : SPDK_LOG_REGISTER_COMPONENT(fuse_dispatcher)
|