LCOV - code coverage report
Current view: top level - lib/fuse_dispatcher - fuse_dispatcher.c (source / functions) Hit Total Coverage
Test: ut_cov_unit.info Lines: 0 1424 0.0 %
Date: 2024-12-16 00:20:03 Functions: 0 156 0.0 %

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

Generated by: LCOV version 1.15