From ae9bfde712697205ac8809edc431cb7c0bdd484f Mon Sep 17 00:00:00 2001 From: Miklos Szeredi Date: Thu, 18 Jun 2009 11:11:54 +0000 Subject: [PATCH] CUSE patches from Tejun Heo --- ChangeLog | 31 +++++++++ example/Makefile.am | 2 +- example/fioc.h | 19 +++++- example/fioclient.c | 98 ++++++++++++++++++++++------- include/Makefile.am | 3 +- include/fuse_kernel.h | 31 +++++++++ include/fuse_lowlevel.h | 27 ++++++-- lib/Makefile.am | 1 + lib/fuse.c | 28 ++++----- lib/fuse_i.h | 69 +++++++++++++++++++- lib/fuse_lowlevel.c | 136 +++++++++++++++++++++------------------- lib/fuse_session.c | 12 +--- lib/fuse_versionscript | 5 ++ lib/helper.c | 16 ++--- 14 files changed, 343 insertions(+), 135 deletions(-) diff --git a/ChangeLog b/ChangeLog index 66f388f..f927d9b 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,34 @@ +2009-06-18 Miklos Szeredi + + * CUSE patches from Tejun Heo: + + * Unrestricted ioctl support left some debris. Clean them up: + o No reason to pass around pointer to flags. Pass flags directly. + o Clean up comment and prototype parameter names. + o fuse_lib_ioctl() didn't reply when get_path() failed. Fix it. + o Remove unused variables {in|out}_iov from fuse_lib_ioctl(). + + * Add fuse_reply_ioctl_iov() + + * Move fuse_session, fuse_req and fuse_ll definitions to fuse_i.h + and make send_reply_iov() and fuse_setup_common() global (also in + fuse_i.h). These will be used by CUSE support. + + * Restructure fuse_ll_process() + + * Implement libfuse side of CUSE support. CUSE uses subset of FUSE + operations as dir operations don't make sense for CUSE where one + instance implements single character device. + + CUSE support comes with its own cuse_lowevel_ops and related + initialization and helper functions. Except for initialization, it + usage is basically identical to FUSE. + + This patch also adds example/cusexmp.c which can create a character + device with name and device number specified on command line. The + created device itself is pretty boring. It's a bit bucket supporting + read, write and access via ioctl. + 2009-06-16 Miklos Szeredi * Add missing fuse_reply_bmap to versionscript. Debian diff --git a/example/Makefile.am b/example/Makefile.am index 1aa5774..718b30a 100644 --- a/example/Makefile.am +++ b/example/Makefile.am @@ -3,7 +3,7 @@ AM_CPPFLAGS = -I$(top_srcdir)/include -D_FILE_OFFSET_BITS=64 -D_REENTRANT noinst_HEADERS = fioc.h noinst_PROGRAMS = fusexmp fusexmp_fh null hello hello_ll fioc fioclient \ - fsel fselclient + fsel fselclient cusexmp LDADD = ../lib/libfuse.la @libfuse_libs@ fusexmp_fh_LDADD = ../lib/libfuse.la ../lib/libulockmgr.la @libfuse_libs@ diff --git a/example/fioc.h b/example/fioc.h index c1d9cdf..ec1a39d 100644 --- a/example/fioc.h +++ b/example/fioc.h @@ -12,6 +12,21 @@ #include enum { - FIOC_GET_SIZE = _IOR('E', 0, size_t), - FIOC_SET_SIZE = _IOW('E', 1, size_t), + FIOC_GET_SIZE = _IOR('E', 0, size_t), + FIOC_SET_SIZE = _IOW('E', 1, size_t), + + /* + * The following two ioctls don't follow usual encoding rules + * and transfer variable amount of data. + */ + FIOC_READ = _IO('E', 2), + FIOC_WRITE = _IO('E', 3), +}; + +struct fioc_rw_arg { + off_t offset; + void *buf; + size_t size; + size_t prev_size; /* out param for previous total size */ + size_t new_size; /* out param for new total size */ }; diff --git a/example/fioclient.c b/example/fioclient.c index 3ab63b2..c056186 100644 --- a/example/fioclient.c +++ b/example/fioclient.c @@ -20,19 +20,56 @@ #include "fioc.h" const char *usage = -"Usage: fioclient FIOC_FILE [SIZE]\n" +"Usage: fioclient FIOC_FILE COMMAND\n" "\n" -" get size if SIZE is omitted, set size otherwise\n" +"COMMANDS\n" +" s [SIZE] : get size if SIZE is omitted, set size otherwise\n" +" r SIZE [OFF] : read SIZE bytes @ OFF (dfl 0) and output to stdout\n" +" w SIZE [OFF] : write SIZE bytes @ OFF (dfl 0) from stdin\n" "\n"; +static int do_rw(int fd, int is_read, size_t size, off_t offset, + size_t *prev_size, size_t *new_size) +{ + struct fioc_rw_arg arg = { .offset = offset }; + ssize_t ret; + + arg.buf = calloc(1, size); + if (!arg.buf) { + fprintf(stderr, "failed to allocated %zu bytes\n", size); + return -1; + } + + if (is_read) { + arg.size = size; + ret = ioctl(fd, FIOC_READ, &arg); + if (ret >= 0) + fwrite(arg.buf, 1, ret, stdout); + } else { + arg.size = fread(arg.buf, 1, size, stdin); + fprintf(stderr, "Writing %zu bytes\n", arg.size); + ret = ioctl(fd, FIOC_WRITE, &arg); + } + + if (ret >= 0) { + *prev_size = arg.prev_size; + *new_size = arg.new_size; + } else + perror("ioctl"); + + free(arg.buf); + return ret; +} + int main(int argc, char **argv) { - size_t size; - int fd; + size_t param[2] = { }; + size_t size, prev_size = 0, new_size = 0; + char cmd; + int fd, i, rc; - if (argc < 2) { + if (argc < 3) goto usage; - } fd = open(argv[1], O_RDWR); if (fd < 0) { @@ -40,27 +77,46 @@ int main(int argc, char **argv) return 1; } - if (argc == 2) { - if (ioctl(fd, FIOC_GET_SIZE, &size)) { - perror("ioctl"); - return 1; - } - printf("%zu\n", size); - } else { - char *endp; + cmd = tolower(argv[2][0]); + argc -= 3; + argv += 3; - size = strtoul(argv[2], &endp, 0); - if (endp == argv[2] || *endp != '\0') + for (i = 0; i < argc; i++) { + char *endp; + param[i] = strtoul(argv[i], &endp, 0); + if (endp == argv[i] || *endp != '\0') goto usage; + } - if (ioctl(fd, FIOC_SET_SIZE, &size)) { - perror("ioctl"); - return 1; + switch (cmd) { + case 's': + if (!argc) { + if (ioctl(fd, FIOC_GET_SIZE, &size)) { + perror("ioctl"); + return 1; + } + printf("%zu\n", size); + } else { + size = param[0]; + if (ioctl(fd, FIOC_SET_SIZE, &size)) { + perror("ioctl"); + return 1; + } } + return 0; + + case 'r': + case 'w': + rc = do_rw(fd, cmd == 'r', param[0], param[1], + &prev_size, &new_size); + if (rc < 0) + return 1; + fprintf(stderr, "transferred %d bytes (%zu -> %zu)\n", + rc, prev_size, new_size); + return 0; } - return 0; -usage: + usage: fprintf(stderr, usage); return 1; } diff --git a/include/Makefile.am b/include/Makefile.am index be2c592..663e164 100644 --- a/include/Makefile.am +++ b/include/Makefile.am @@ -9,7 +9,8 @@ fuseinclude_HEADERS = \ fuse_common_compat.h \ fuse_lowlevel.h \ fuse_lowlevel_compat.h \ - fuse_opt.h + fuse_opt.h \ + cuse_lowlevel.h include_HEADERS = old/fuse.h ulockmgr.h diff --git a/include/fuse_kernel.h b/include/fuse_kernel.h index df558e3..541364f 100644 --- a/include/fuse_kernel.h +++ b/include/fuse_kernel.h @@ -149,6 +149,13 @@ struct fuse_file_lock { #define FUSE_EXPORT_SUPPORT (1 << 4) #define FUSE_BIG_WRITES (1 << 5) +/** + * CUSE INIT request/reply flags + * + * CUSE_UNRESTRICTED_IOCTL: use unrestricted ioctl + */ +#define CUSE_UNRESTRICTED_IOCTL (1 << 0) + /** * Release flags */ @@ -239,6 +246,9 @@ enum fuse_opcode { FUSE_DESTROY = 38, FUSE_IOCTL = 39, FUSE_POLL = 40, + + /* CUSE specific operations */ + CUSE_INIT = 4096, }; enum fuse_notify_code { @@ -430,6 +440,27 @@ struct fuse_init_out { __u32 max_write; }; +#define CUSE_INIT_INFO_MAX 4096 + +struct cuse_init_in { + __u32 major; + __u32 minor; + __u32 unused; + __u32 flags; +}; + +struct cuse_init_out { + __u32 major; + __u32 minor; + __u32 unused; + __u32 flags; + __u32 max_read; + __u32 max_write; + __u32 dev_major; /* chardev major */ + __u32 dev_minor; /* chardev minor */ + __u32 spare[10]; +}; + struct fuse_interrupt_in { __u64 unique; }; diff --git a/include/fuse_lowlevel.h b/include/fuse_lowlevel.h index 54cec8c..5ab2422 100644 --- a/include/fuse_lowlevel.h +++ b/include/fuse_lowlevel.h @@ -815,7 +815,7 @@ struct fuse_lowlevel_ops { * * Note: For unrestricted ioctls (not allowed for FUSE * servers), data in and out areas can be discovered by giving - * iovs and setting FUSE_IOCTL_RETRY in *flagsp. For + * iovs and setting FUSE_IOCTL_RETRY in @flags. For * restricted ioctls, kernel prepares in/out data area * according to the information encoded in cmd. * @@ -824,6 +824,7 @@ struct fuse_lowlevel_ops { * Valid replies: * fuse_reply_ioctl_retry * fuse_reply_ioctl + * fuse_reply_ioctl_iov * fuse_reply_err * * @param req request handle @@ -831,14 +832,14 @@ struct fuse_lowlevel_ops { * @param cmd ioctl command * @param arg ioctl argument * @param fi file information - * @param flagsp io/out parameter for FUSE_IOCTL_* flags + * @param flags for FUSE_IOCTL_* flags * @param in_buf data fetched from the caller - * @param in_size number of fetched bytes - * @param out_size maximum size of output data + * @param in_bufsz number of fetched bytes + * @param out_bufsz maximum size of output data */ void (*ioctl) (fuse_req_t req, fuse_ino_t ino, int cmd, void *arg, - struct fuse_file_info *fi, unsigned *flagsp, - const void *in_buf, size_t in_bufsz, size_t out_bufszp); + struct fuse_file_info *fi, unsigned flags, + const void *in_buf, size_t in_bufsz, size_t out_bufsz); /** * Poll for IO readiness @@ -1115,6 +1116,20 @@ int fuse_reply_ioctl_retry(fuse_req_t req, */ int fuse_reply_ioctl(fuse_req_t req, int result, const void *buf, size_t size); +/** + * Reply to finish ioctl with iov buffer + * + * Possible requests: + * ioctl + * + * @param req request handle + * @param result result to be passed to the caller + * @param iov the vector containing the data + * @param count the size of vector + */ +int fuse_reply_ioctl_iov(fuse_req_t req, int result, const struct iovec *iov, + int count); + /** * Reply with poll result event mask * diff --git a/lib/Makefile.am b/lib/Makefile.am index 0694980..7fce149 100644 --- a/lib/Makefile.am +++ b/lib/Makefile.am @@ -29,6 +29,7 @@ libfuse_la_SOURCES = \ fuse_opt.c \ fuse_session.c \ fuse_signals.c \ + cuse_lowlevel.c \ helper.c \ modules/subdir.c \ $(iconv_source) \ diff --git a/lib/fuse.c b/lib/fuse.c index 8c27cd3..f7e78a8 100644 --- a/lib/fuse.c +++ b/lib/fuse.c @@ -3211,25 +3211,24 @@ static void fuse_lib_bmap(fuse_req_t req, fuse_ino_t ino, size_t blocksize, } static void fuse_lib_ioctl(fuse_req_t req, fuse_ino_t ino, int cmd, void *arg, - struct fuse_file_info *fi, unsigned int *flagsp, + struct fuse_file_info *fi, unsigned int flags, const void *in_buf, size_t in_bufsz, size_t out_bufsz) { struct fuse *f = req_fuse_prepare(req); struct fuse_intr_data d; char *path, *out_buf = NULL; - struct iovec *in_iov = NULL, *out_iov = NULL; int err; - if (*flagsp & FUSE_IOCTL_UNRESTRICTED) { - reply_err(req, -EPERM); - return; - } + err = -EPERM; + if (flags & FUSE_IOCTL_UNRESTRICTED) + goto err; if (out_bufsz) { + err = -ENOMEM; out_buf = malloc(out_bufsz); if (!out_buf) - goto enomem; + goto err; } assert(!in_bufsz || !out_bufsz || in_bufsz == out_bufsz); @@ -3238,27 +3237,22 @@ static void fuse_lib_ioctl(fuse_req_t req, fuse_ino_t ino, int cmd, void *arg, err = get_path(f, ino, &path); if (err) - goto out; + goto err; fuse_prepare_interrupt(f, req, &d); - err = fuse_fs_ioctl(f->fs, path, cmd, arg, fi, *flagsp, + err = fuse_fs_ioctl(f->fs, path, cmd, arg, fi, flags, out_buf ?: (void *)in_buf); fuse_finish_interrupt(f, req, &d); free_path(f, ino, path); fuse_reply_ioctl(req, err, out_buf, out_bufsz); - + goto out; +err: + reply_err(req, err); out: free(out_buf); - free(in_iov); - free(out_iov); - return; - -enomem: - reply_err(req, -ENOMEM); - goto out; } static void fuse_lib_poll(fuse_req_t req, fuse_ino_t ino, diff --git a/lib/fuse_i.h b/lib/fuse_i.h index ec6e5d6..9bc1d70 100644 --- a/lib/fuse_i.h +++ b/lib/fuse_i.h @@ -7,11 +7,58 @@ */ #include "fuse.h" +#include "fuse_lowlevel.h" -struct fuse_session; struct fuse_chan; -struct fuse_lowlevel_ops; -struct fuse_req; +struct fuse_ll; + +struct fuse_session { + struct fuse_session_ops op; + + void *data; + + volatile int exited; + + struct fuse_chan *ch; +}; + +struct fuse_req { + struct fuse_ll *f; + uint64_t unique; + int ctr; + pthread_mutex_t lock; + struct fuse_ctx ctx; + struct fuse_chan *ch; + int interrupted; + union { + struct { + uint64_t unique; + } i; + struct { + fuse_interrupt_func_t func; + void *data; + } ni; + } u; + struct fuse_req *next; + struct fuse_req *prev; +}; + +struct fuse_ll { + int debug; + int allow_root; + int atomic_o_trunc; + int big_writes; + struct fuse_lowlevel_ops op; + int got_init; + struct cuse_data *cuse_data; + void *userdata; + uid_t owner; + struct fuse_conn_info conn; + struct fuse_req list; + struct fuse_req interrupts; + pthread_mutex_t lock; + int got_destroy; +}; struct fuse_cmd { char *buf; @@ -34,3 +81,19 @@ struct fuse_session *fuse_lowlevel_new_common(struct fuse_args *args, void fuse_kern_unmount_compat22(const char *mountpoint); void fuse_kern_unmount(const char *mountpoint, int fd); int fuse_kern_mount(const char *mountpoint, struct fuse_args *args); + +int send_reply_iov(fuse_req_t req, int error, struct iovec *iov, int count); +int send_reply_iov_nofree(fuse_req_t req, int error, struct iovec *iov, int count); +void free_req(fuse_req_t req); + + +struct fuse *fuse_setup_common(int argc, char *argv[], + const struct fuse_operations *op, + size_t op_size, + char **mountpoint, + int *multithreaded, + int *fd, + void *user_data, + int compat); + +void do_cuse_init(fuse_req_t req, fuse_ino_t nodeide, const void *inarg); diff --git a/lib/fuse_lowlevel.c b/lib/fuse_lowlevel.c index 63a0668..e3b5d5d 100644 --- a/lib/fuse_lowlevel.c +++ b/lib/fuse_lowlevel.c @@ -6,10 +6,9 @@ See the file COPYING.LIB */ -#include "fuse_lowlevel.h" +#include "fuse_i.h" #include "fuse_kernel.h" #include "fuse_opt.h" -#include "fuse_i.h" #include "fuse_misc.h" #include "fuse_common_compat.h" #include "fuse_lowlevel_compat.h" @@ -25,45 +24,6 @@ #define PARAM(inarg) (((char *)(inarg)) + sizeof(*(inarg))) #define OFFSET_MAX 0x7fffffffffffffffLL -struct fuse_ll; - -struct fuse_req { - struct fuse_ll *f; - uint64_t unique; - int ctr; - pthread_mutex_t lock; - struct fuse_ctx ctx; - struct fuse_chan *ch; - int interrupted; - union { - struct { - uint64_t unique; - } i; - struct { - fuse_interrupt_func_t func; - void *data; - } ni; - } u; - struct fuse_req *next; - struct fuse_req *prev; -}; - -struct fuse_ll { - int debug; - int allow_root; - int atomic_o_trunc; - int big_writes; - struct fuse_lowlevel_ops op; - int got_init; - void *userdata; - uid_t owner; - struct fuse_conn_info conn; - struct fuse_req list; - struct fuse_req interrupts; - pthread_mutex_t lock; - int got_destroy; -}; - struct fuse_pollhandle { uint64_t kh; struct fuse_chan *ch; @@ -140,7 +100,7 @@ static void destroy_req(fuse_req_t req) free(req); } -static void free_req(fuse_req_t req) +void free_req(fuse_req_t req) { int ctr; struct fuse_ll *f = req->f; @@ -155,11 +115,10 @@ static void free_req(fuse_req_t req) destroy_req(req); } -static int send_reply_iov(fuse_req_t req, int error, struct iovec *iov, +int send_reply_iov_nofree(fuse_req_t req, int error, struct iovec *iov, int count) { struct fuse_out_header out; - int res; if (error <= -1000 || error > 0) { fprintf(stderr, "fuse: bad error value: %i\n", error); @@ -184,9 +143,16 @@ static int send_reply_iov(fuse_req_t req, int error, struct iovec *iov, (unsigned long long) out.unique, out.len); } } - res = fuse_chan_send(req->ch, iov, count); - free_req(req); + return fuse_chan_send(req->ch, iov, count); +} + +int send_reply_iov(fuse_req_t req, int error, struct iovec *iov, int count) +{ + int res; + + res = send_reply_iov_nofree(req, error, iov, count); + free_req(req); return res; } @@ -509,6 +475,30 @@ int fuse_reply_ioctl(fuse_req_t req, int result, const void *buf, size_t size) return send_reply_iov(req, 0, iov, count); } +int fuse_reply_ioctl_iov(fuse_req_t req, int result, const struct iovec *iov, + int count) +{ + struct iovec *padded_iov; + struct fuse_ioctl_out arg; + int res; + + padded_iov = malloc((count + 2) * sizeof(struct iovec)); + if (padded_iov == NULL) + return fuse_reply_err(req, -ENOMEM); + + memset(&arg, 0, sizeof(arg)); + arg.result = result; + padded_iov[1].iov_base = &arg; + padded_iov[1].iov_len = sizeof(arg); + + memcpy(&padded_iov[2], iov, count * sizeof(struct iovec)); + + res = send_reply_iov(req, 0, padded_iov, count + 2); + free(padded_iov); + + return res; +} + int fuse_reply_poll(fuse_req_t req, unsigned revents) { struct fuse_poll_out arg; @@ -1095,7 +1085,7 @@ static void do_ioctl(fuse_req_t req, fuse_ino_t nodeid, const void *inarg) if (req->f->op.ioctl) req->f->op.ioctl(req, nodeid, arg->cmd, - (void *)(uintptr_t)arg->arg, &fi, &flags, + (void *)(uintptr_t)arg->arg, &fi, flags, in_buf, arg->in_size, arg->out_size); else fuse_reply_err(req, ENOSYS); @@ -1356,6 +1346,7 @@ static struct { [FUSE_IOCTL] = { do_ioctl, "IOCTL" }, [FUSE_POLL] = { do_poll, "POLL" }, [FUSE_DESTROY] = { do_destroy, "DESTROY" }, + [CUSE_INIT] = { do_cuse_init, "CUSE_INIT" }, }; #define FUSE_MAXOP (sizeof(fuse_ll_ops) / sizeof(fuse_ll_ops[0])) @@ -1375,6 +1366,7 @@ static void fuse_ll_process(void *data, const char *buf, size_t len, struct fuse_in_header *in = (struct fuse_in_header *) buf; const void *inarg = buf + sizeof(struct fuse_in_header); struct fuse_req *req; + int err; if (f->debug) fprintf(stderr, @@ -1399,28 +1391,41 @@ static void fuse_ll_process(void *data, const char *buf, size_t len, list_init_req(req); fuse_mutex_init(&req->lock); - if (!f->got_init && in->opcode != FUSE_INIT) - fuse_reply_err(req, EIO); - else if (f->allow_root && in->uid != f->owner && in->uid != 0 && + err = EIO; + if (!f->got_init) { + enum fuse_opcode expected; + + expected = f->cuse_data ? CUSE_INIT : FUSE_INIT; + if (in->opcode != expected) + goto reply_err; + } else if (in->opcode == FUSE_INIT || in->opcode == CUSE_INIT) + goto reply_err; + + err = EACCES; + if (f->allow_root && in->uid != f->owner && in->uid != 0 && in->opcode != FUSE_INIT && in->opcode != FUSE_READ && in->opcode != FUSE_WRITE && in->opcode != FUSE_FSYNC && in->opcode != FUSE_RELEASE && in->opcode != FUSE_READDIR && - in->opcode != FUSE_FSYNCDIR && in->opcode != FUSE_RELEASEDIR) { - fuse_reply_err(req, EACCES); - } else if (in->opcode >= FUSE_MAXOP || !fuse_ll_ops[in->opcode].func) - fuse_reply_err(req, ENOSYS); - else { - if (in->opcode != FUSE_INTERRUPT) { - struct fuse_req *intr; - pthread_mutex_lock(&f->lock); - intr = check_interrupt(f, req); - list_add_req(req, &f->list); - pthread_mutex_unlock(&f->lock); - if (intr) - fuse_reply_err(intr, EAGAIN); - } - fuse_ll_ops[in->opcode].func(req, in->nodeid, inarg); + in->opcode != FUSE_FSYNCDIR && in->opcode != FUSE_RELEASEDIR) + goto reply_err; + + err = ENOSYS; + if (in->opcode >= FUSE_MAXOP || !fuse_ll_ops[in->opcode].func) + goto reply_err; + if (in->opcode != FUSE_INTERRUPT) { + struct fuse_req *intr; + pthread_mutex_lock(&f->lock); + intr = check_interrupt(f, req); + list_add_req(req, &f->list); + pthread_mutex_unlock(&f->lock); + if (intr) + fuse_reply_err(intr, EAGAIN); } + fuse_ll_ops[in->opcode].func(req, in->nodeid, inarg); + return; + + reply_err: + fuse_reply_err(req, err); } enum { @@ -1499,6 +1504,7 @@ static void fuse_ll_destroy(void *data) } pthread_mutex_destroy(&f->lock); + free(f->cuse_data); free(f); } diff --git a/lib/fuse_session.c b/lib/fuse_session.c index 5efedd9..7df4795 100644 --- a/lib/fuse_session.c +++ b/lib/fuse_session.c @@ -6,7 +6,7 @@ See the file COPYING.LIB */ -#include "fuse_lowlevel.h" +#include "fuse_i.h" #include "fuse_misc.h" #include "fuse_common_compat.h" #include "fuse_lowlevel_compat.h" @@ -17,16 +17,6 @@ #include #include -struct fuse_session { - struct fuse_session_ops op; - - void *data; - - volatile int exited; - - struct fuse_chan *ch; -}; - struct fuse_chan { struct fuse_chan_ops op; diff --git a/lib/fuse_versionscript b/lib/fuse_versionscript index f2608a8..4cd09aa 100644 --- a/lib/fuse_versionscript +++ b/lib/fuse_versionscript @@ -160,6 +160,10 @@ FUSE_2.7.5 { FUSE_2.8 { global: + cuse_lowlevel_new; + cuse_lowlevel_main; + cuse_lowlevel_setup; + cuse_lowlevel_teardown; fuse_fs_ioctl; fuse_fs_poll; fuse_lowlevel_notify_poll; @@ -167,6 +171,7 @@ FUSE_2.8 { fuse_opt_add_opt_escaped; fuse_pollhandle_destroy; fuse_reply_ioctl; + fuse_reply_ioctl_iov; fuse_reply_ioctl_retry; fuse_reply_poll; diff --git a/lib/helper.c b/lib/helper.c index d1cd075..3d0db4a 100644 --- a/lib/helper.c +++ b/lib/helper.c @@ -235,14 +235,14 @@ void fuse_unmount(const char *mountpoint, struct fuse_chan *ch) fuse_unmount_common(mountpoint, ch); } -static struct fuse *fuse_setup_common(int argc, char *argv[], - const struct fuse_operations *op, - size_t op_size, - char **mountpoint, - int *multithreaded, - int *fd, - void *user_data, - int compat) +struct fuse *fuse_setup_common(int argc, char *argv[], + const struct fuse_operations *op, + size_t op_size, + char **mountpoint, + int *multithreaded, + int *fd, + void *user_data, + int compat) { struct fuse_args args = FUSE_ARGS_INIT(argc, argv); struct fuse_chan *ch; -- 2.30.2