From: Miklos Szeredi Date: Sun, 14 Aug 2005 23:00:27 +0000 (+0000) Subject: cleanup X-Git-Tag: fuse_2_4_0_pre2~19 X-Git-Url: http://git.maquefel.me/?a=commitdiff_plain;h=a148242fb80fa2127fdaf41de63e2d81dc8006ef;p=qemu-gpiodev%2Flibfuse.git cleanup --- diff --git a/ChangeLog b/ChangeLog index 4bc79dc..e41d1a9 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,8 @@ +2005-08-15 Miklos Szeredi + + * lib: cleaned up (or messed up, depending on your POV) the low + level library API. Hopefully this is close to the final form. + 2005-08-05 Miklos Szeredi * fusermount: don't allow empty mountpoint argument, which defeats diff --git a/example/hello_ll.c b/example/hello_ll.c index 3a6ea09..f5a2baf 100644 --- a/example/hello_ll.c +++ b/example/hello_ll.c @@ -134,7 +134,7 @@ static void hello_ll_read(fuse_req_t req, fuse_ino_t ino, size_t size, reply_buf_limited(req, hello_str, strlen(hello_str), off, size); } -static struct fuse_ll_operations hello_ll_oper = { +static struct fuse_lowlevel_ops hello_ll_oper = { .lookup = hello_ll_lookup, .getattr = hello_ll_getattr, .readdir = hello_ll_readdir, @@ -145,7 +145,6 @@ static struct fuse_ll_operations hello_ll_oper = { int main(int argc, char *argv[]) { const char *mountpoint; - struct fuse_ll *f; int err = -1; int fd; @@ -156,10 +155,17 @@ int main(int argc, char *argv[]) mountpoint = argv[1]; fd = fuse_mount(mountpoint, NULL); if (fd != -1) { - f = fuse_ll_new(fd, "debug", &hello_ll_oper, sizeof(hello_ll_oper), NULL); - if (f != NULL) { - err = fuse_ll_loop(f); - fuse_ll_destroy(f); + struct fuse_session *se; + + se = fuse_lowlevel_new("debug", &hello_ll_oper, sizeof(hello_ll_oper), + NULL); + if (se != NULL) { + struct fuse_chan *ch = fuse_kern_chan_new(fd); + if (ch != NULL) { + fuse_session_add_chan(se, ch); + err = fuse_session_loop(se); + } + fuse_session_destroy(se); } close(fd); } diff --git a/include/Makefile.am b/include/Makefile.am index ee8a83c..8c33be5 100644 --- a/include/Makefile.am +++ b/include/Makefile.am @@ -1,6 +1,13 @@ ## Process this file with automake to produce Makefile.in fuseincludedir=$(includedir)/fuse -fuseinclude_HEADERS = fuse.h fuse_compat.h fuse_common.h fuse_lowlevel.h + +fuseinclude_HEADERS = \ + fuse.h \ + fuse_compat.h \ + fuse_common.h \ + fuse_lowlevel.h + include_HEADERS = old/fuse.h + noinst_HEADERS = fuse_kernel.h diff --git a/include/fuse.h b/include/fuse.h index ca96084..ca3797f 100644 --- a/include/fuse.h +++ b/include/fuse.h @@ -34,6 +34,12 @@ extern "C" { /** Handle for a FUSE filesystem */ struct fuse; +/** Structure containing a raw command */ +struct fuse_cmd; + +/** The lowlevel FUSE session */ +struct fuse_session; + /** Function to add an entry in a readdir() operation * * @param buf the buffer passed to the readdir() operation @@ -504,8 +510,8 @@ int fuse_exited(struct fuse *f); /** Set function which can be used to get the current context */ void fuse_set_getcontext_func(struct fuse_context *(*func)(void)); -/** Returns the lowlevel FUSE object */ -struct fuse_ll *fuse_get_lowlevel(struct fuse *f); +/** Returns the lowlevel FUSE session */ +struct fuse_session *fuse_get_session(struct fuse *f); /* ----------------------------------------------------------- * * Compatibility stuff * diff --git a/include/fuse_common.h b/include/fuse_common.h index 648d6e4..2af3ce9 100644 --- a/include/fuse_common.h +++ b/include/fuse_common.h @@ -53,7 +53,4 @@ struct fuse_file_info { unsigned int keep_cache : 1; }; -/** Structure containing a raw command */ -struct fuse_cmd; - #endif /* _FUSE_COMMON_H_ */ diff --git a/include/fuse_lowlevel.h b/include/fuse_lowlevel.h index 8b18959..4c1af83 100644 --- a/include/fuse_lowlevel.h +++ b/include/fuse_lowlevel.h @@ -19,6 +19,7 @@ #include #include #include +#include #ifdef __cplusplus extern "C" { @@ -29,7 +30,9 @@ extern "C" { typedef unsigned long fuse_ino_t; typedef struct fuse_req *fuse_req_t; -struct fuse_ll; + +struct fuse_session; +struct fuse_chan; struct fuse_entry_param { fuse_ino_t ino; @@ -69,8 +72,8 @@ struct fuse_ctx { /* ------------------------------------------ */ -struct fuse_ll_operations { - void* (*init) (void *); +struct fuse_lowlevel_ops { + void (*init) (void *); void (*destroy)(void *); void (*lookup) (fuse_req_t req, fuse_ino_t parent, const char *name); @@ -174,29 +177,73 @@ const struct fuse_ctx *fuse_req_ctx(fuse_req_t req); /* ------------------------------------------ */ -typedef void (*fuse_ll_processor_t)(struct fuse_ll *, struct fuse_cmd *, void *); +int fuse_lowlevel_is_lib_option(const char *opt); + +struct fuse_session *fuse_lowlevel_new(const char *opts, + const struct fuse_lowlevel_ops *op, + size_t op_size, void *userdata); + +struct fuse_chan *fuse_kern_chan_new(int fd); + +/* ------------------------------------------ */ + +struct fuse_session_ops { + void (*process) (void *data, const char *buf, size_t len, + struct fuse_chan *ch); + + void (*destroy) (void *data); +}; + +struct fuse_session *fuse_session_new(struct fuse_session_ops *op, void *data); + +void fuse_session_add_chan(struct fuse_session *se, struct fuse_chan *ch); + +struct fuse_chan *fuse_session_next_chan(struct fuse_session *se, + struct fuse_chan *ch); + +void fuse_session_process(struct fuse_session *se, const char *buf, size_t len, + struct fuse_chan *ch); -struct fuse_ll *fuse_ll_new(int fd, const char *opts, - const struct fuse_ll_operations *op, - size_t op_size, void *userdata); +void fuse_session_destroy(struct fuse_session *se); -void fuse_ll_destroy(struct fuse_ll *f); +void fuse_session_exit(struct fuse_session *se); + +void fuse_session_reset(struct fuse_session *se); + +int fuse_session_exited(struct fuse_session *se); + +int fuse_session_loop(struct fuse_session *se); + +int fuse_session_loop_mt(struct fuse_session *se); + +/* ------------------------------------------ */ + +struct fuse_chan_ops { + int (*receive)(struct fuse_chan *ch, char *buf, size_t size); + + int (*send)(struct fuse_chan *ch, const struct iovec iov[], + size_t count); + + void (*destroy)(struct fuse_chan *ch); +}; -int fuse_ll_is_lib_option(const char *opt); +struct fuse_chan *fuse_chan_new(struct fuse_chan_ops *op, int fd, + size_t bufsize, void *data); -int fuse_ll_loop(struct fuse_ll *f); +int fuse_chan_fd(struct fuse_chan *ch); -void fuse_ll_exit(struct fuse_ll *f); +size_t fuse_chan_bufsize(struct fuse_chan *ch); -int fuse_ll_exited(struct fuse_ll* f); +void *fuse_chan_data(struct fuse_chan *ch); -struct fuse_cmd *fuse_ll_read_cmd(struct fuse_ll *f); +struct fuse_session *fuse_chan_session(struct fuse_chan *ch); -void fuse_ll_process_cmd(struct fuse_ll *f, struct fuse_cmd *cmd); +int fuse_chan_receive(struct fuse_chan *ch, char *buf, size_t size); -int fuse_ll_loop_mt(struct fuse_ll *f); +int fuse_chan_send(struct fuse_chan *ch, const struct iovec iov[], + size_t count); -int fuse_ll_loop_mt_proc(struct fuse_ll *f, fuse_ll_processor_t proc, void *data); +void fuse_chan_destroy(struct fuse_chan *ch); /* ------------------------------------------ */ diff --git a/lib/Makefile.am b/lib/Makefile.am index b99f9e2..b92a0ad 100644 --- a/lib/Makefile.am +++ b/lib/Makefile.am @@ -4,12 +4,14 @@ lib_LTLIBRARIES = libfuse.la libfuse_la_SOURCES = \ fuse.c \ - fuse_mt.c \ + fuse_kern_chan.c \ + fuse_loop.c \ + fuse_loop_mt.c \ fuse_lowlevel.c \ - fuse_lowlevel_mt.c \ + fuse_mt.c \ + fuse_session.c \ helper.c \ - mount.c \ - fuse_lowlevel_i.h + mount.c libfuse_la_LDFLAGS = -lpthread -version-number 2:4:0 \ -Wl,--version-script,fuse_versionscript diff --git a/lib/fuse.c b/lib/fuse.c index 68eeee0..7613d38 100644 --- a/lib/fuse.c +++ b/lib/fuse.c @@ -63,7 +63,7 @@ #define FUSE_MAX_PATH 4096 struct fuse { - struct fuse_ll *fll; + struct fuse_session *se; int flags; struct fuse_operations op; int compat; @@ -110,6 +110,11 @@ struct fuse_dirhandle { fuse_ino_t nodeid; }; +struct fuse_cmd { + char *buf; + size_t buflen; +}; + static struct fuse_context *(*fuse_getcontext)(void) = NULL; #ifndef USE_UCLIBC @@ -561,14 +566,12 @@ static void reply_entry(fuse_req_t req, const struct fuse_entry_param *e, reply_err(req, err); } -static void *fuse_data_init(void *data) +static void fuse_data_init(void *data) { struct fuse *f = (struct fuse *) data; if (f->op.init) f->user_data = f->op.init(); - - return f; } static void fuse_data_destroy(void *data) @@ -1599,7 +1602,7 @@ static void fuse_removexattr(fuse_req_t req, fuse_ino_t ino, const char *name) reply_err(req, err); } -static struct fuse_ll_operations fuse_path_ops = { +static struct fuse_lowlevel_ops fuse_path_ops = { .init = fuse_data_init, .destroy = fuse_data_destroy, .lookup = fuse_lookup, @@ -1632,25 +1635,64 @@ static struct fuse_ll_operations fuse_path_ops = { .removexattr = fuse_removexattr, }; +static void free_cmd(struct fuse_cmd *cmd) +{ + free(cmd->buf); + free(cmd); +} + void fuse_process_cmd(struct fuse *f, struct fuse_cmd *cmd) { - fuse_ll_process_cmd(f->fll, cmd); + struct fuse_chan *ch = fuse_session_next_chan(f->se, NULL); + fuse_session_process(f->se, cmd->buf, cmd->buflen, ch); } int fuse_exited(struct fuse *f) { - return fuse_ll_exited(f->fll); + return fuse_session_exited(f->se); +} + +struct fuse_session *fuse_get_session(struct fuse *f) +{ + return f->se; +} + +static struct fuse_cmd *fuse_alloc_cmd(size_t bufsize) +{ + struct fuse_cmd *cmd = (struct fuse_cmd *) malloc(sizeof(*cmd)); + if (cmd == NULL) { + fprintf(stderr, "fuse: failed to allocate cmd\n"); + return NULL; + } + cmd->buf = (char *) malloc(bufsize); + if (cmd->buf == NULL) { + fprintf(stderr, "fuse: failed to allocate read buffer\n"); + free(cmd); + return NULL; + } + return cmd; } struct fuse_cmd *fuse_read_cmd(struct fuse *f) { - return fuse_ll_read_cmd(f->fll); + struct fuse_chan *ch = fuse_session_next_chan(f->se, NULL); + size_t bufsize = fuse_chan_bufsize(ch); + struct fuse_cmd *cmd = fuse_alloc_cmd(bufsize); + if (cmd != NULL) { + int res = fuse_chan_receive(ch, cmd->buf, bufsize); + if (res <= 0) { + free_cmd(cmd); + return NULL; + } + cmd->buflen = res; + } + return cmd; } int fuse_loop(struct fuse *f) { if (f) - return fuse_ll_loop(f->fll); + return fuse_session_loop(f->se); else return -1; } @@ -1664,7 +1706,7 @@ int fuse_invalidate(struct fuse *f, const char *path) void fuse_exit(struct fuse *f) { - fuse_ll_exit(f->fll); + fuse_session_exit(f->se); } struct fuse_context *fuse_get_context() @@ -1681,11 +1723,6 @@ void fuse_set_getcontext_func(struct fuse_context *(*func)(void)) fuse_getcontext = func; } -struct fuse_ll *fuse_get_lowlevel(struct fuse *f) -{ - return f->fll; -} - static int begins_with(const char *s, const char *beg) { if (strncmp(s, beg, strlen(beg)) == 0) @@ -1696,7 +1733,7 @@ static int begins_with(const char *s, const char *beg) int fuse_is_lib_option(const char *opt) { - if (fuse_ll_is_lib_option(opt) || + if (fuse_lowlevel_is_lib_option(opt) || strcmp(opt, "debug") == 0 || strcmp(opt, "hard_remove") == 0 || strcmp(opt, "use_ino") == 0 || @@ -1728,7 +1765,7 @@ static int parse_lib_opts(struct fuse *f, const char *opts, char **llopts) } while((opt = strsep(&s, ","))) { - if (fuse_ll_is_lib_option(opt)) { + if (fuse_lowlevel_is_lib_option(opt)) { size_t optlen = strlen(opt); if (strcmp(opt, "debug") == 0) f->flags |= FUSE_DEBUG; @@ -1772,6 +1809,7 @@ struct fuse *fuse_new_common(int fd, const char *opts, const struct fuse_operations *op, size_t op_size, int compat) { + struct fuse_chan *ch; struct fuse *f; struct node *root; char *llopts = NULL; @@ -1793,10 +1831,16 @@ struct fuse *fuse_new_common(int fd, const char *opts, if (parse_lib_opts(f, opts, &llopts) == -1) goto out_free; - f->fll = fuse_ll_new(fd, llopts, &fuse_path_ops, sizeof(fuse_path_ops), f); + f->se = fuse_lowlevel_new(llopts, &fuse_path_ops, sizeof(fuse_path_ops), f); free(llopts); - if (f->fll == NULL) + if (f->se == NULL) goto out_free; + + ch = fuse_kern_chan_new(fd); + if (ch == NULL) + goto out_free_session; + + fuse_session_add_chan(f->se, ch); f->ctr = 0; f->generation = 0; @@ -1806,7 +1850,7 @@ struct fuse *fuse_new_common(int fd, const char *opts, calloc(1, sizeof(struct node *) * f->name_table_size); if (f->name_table == NULL) { fprintf(stderr, "fuse: memory allocation failed\n"); - goto out_free; + goto out_free_session; } f->id_table_size = 14057; @@ -1848,6 +1892,8 @@ struct fuse *fuse_new_common(int fd, const char *opts, free(f->id_table); out_free_name_table: free(f->name_table); + out_free_session: + fuse_session_destroy(f->se); out_free: free(f); out: @@ -1905,7 +1951,7 @@ void fuse_destroy(struct fuse *f) free(f->id_table); free(f->name_table); pthread_mutex_destroy(&f->lock); - fuse_ll_destroy(f->fll); + fuse_session_destroy(f->se); free(f); } diff --git a/lib/fuse_kern_chan.c b/lib/fuse_kern_chan.c new file mode 100644 index 0000000..577d2e5 --- /dev/null +++ b/lib/fuse_kern_chan.c @@ -0,0 +1,73 @@ +/* + FUSE: Filesystem in Userspace + Copyright (C) 2001-2005 Miklos Szeredi + + This program can be distributed under the terms of the GNU LGPL. + See the file COPYING.LIB +*/ + +#include "fuse_lowlevel.h" +#include "fuse_kernel.h" + +#include +#include +#include +#include + +static int fuse_kern_chan_receive(struct fuse_chan *ch, char *buf, size_t size) +{ + ssize_t res = read(fuse_chan_fd(ch), buf, size); + struct fuse_session *se = fuse_chan_session(ch); + + assert(se != NULL); + if (fuse_session_exited(se)) + return 0; + if (res == -1) { + /* EINTR means, the read() was interrupted, ENOENT means the + operation was interrupted */ + if (errno == EINTR || errno == ENOENT) + return 0; + /* ENODEV means we got unmounted, so we silenty return failure */ + if (errno != ENODEV) + perror("fuse: reading device"); + return -1; + } + if ((size_t) res < sizeof(struct fuse_in_header)) { + fprintf(stderr, "short read on fuse device\n"); + return -1; + } + return res; +} + +static int fuse_kern_chan_send(struct fuse_chan *ch, const struct iovec iov[], + size_t count) +{ + ssize_t res = writev(fuse_chan_fd(ch), iov, count); + + if (res == -1) { + struct fuse_session *se = fuse_chan_session(ch); + + assert(se != NULL); + + /* ENOENT means the operation was interrupted */ + if (!fuse_session_exited(se) && errno != ENOENT) + perror("fuse: writing device"); + return -errno; + } + return 0; +} + +static void fuse_kern_chan_destroy(struct fuse_chan *ch) +{ + close(fuse_chan_fd(ch)); +} + +struct fuse_chan *fuse_kern_chan_new(int fd) +{ + struct fuse_chan_ops op = { + .receive = fuse_kern_chan_receive, + .send = fuse_kern_chan_send, + .destroy = fuse_kern_chan_destroy, + }; + return fuse_chan_new(&op, fd, FUSE_MAX_IN, NULL); +} diff --git a/lib/fuse_loop.c b/lib/fuse_loop.c new file mode 100644 index 0000000..f9a05d8 --- /dev/null +++ b/lib/fuse_loop.c @@ -0,0 +1,38 @@ +/* + FUSE: Filesystem in Userspace + Copyright (C) 2001-2005 Miklos Szeredi + + This program can be distributed under the terms of the GNU LGPL. + See the file COPYING.LIB +*/ + +#include "fuse_lowlevel.h" + +#include +#include + +int fuse_session_loop(struct fuse_session *se) +{ + int res = 0; + struct fuse_chan *ch = fuse_session_next_chan(se, NULL); + size_t bufsize = fuse_chan_bufsize(ch); + char *buf = (char *) malloc(bufsize); + if (!buf) { + fprintf(stderr, "fuse: failed to allocate read buffer\n"); + return -1; + } + + while (!fuse_session_exited(se)) { + res = fuse_chan_receive(ch, buf, bufsize); + if (!res) + continue; + if (res == -1) + break; + fuse_session_process(se, buf, res, ch); + res = 0; + } + + free(buf); + fuse_session_reset(se); + return res; +} diff --git a/lib/fuse_loop_mt.c b/lib/fuse_loop_mt.c new file mode 100644 index 0000000..ad386a2 --- /dev/null +++ b/lib/fuse_loop_mt.c @@ -0,0 +1,161 @@ +/* + FUSE: Filesystem in Userspace + Copyright (C) 2001-2005 Miklos Szeredi + + This program can be distributed under the terms of the GNU LGPL. + See the file COPYING.LIB. +*/ + +#include "fuse_lowlevel.h" + +#include +#include +#include +#include +#include +#include +#include +#include + +#define FUSE_MAX_WORKERS 10 + +struct fuse_worker { + pthread_mutex_t lock; + int numworker; + int numavail; + struct fuse_session *se; + struct fuse_chan *ch; + struct fuse_chan *prevch; + pthread_t threads[FUSE_MAX_WORKERS]; + int error; +}; + +#ifndef USE_UCLIBC +#define mutex_init(mut) pthread_mutex_init(mut, NULL) +#else +static void mutex_init(pthread_mutex_t mut) +{ + pthread_mutexattr_t attr; + pthread_mutexattr_init(&attr); + pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_ADAPTIVE_NP); + pthread_mutex_init(mut, &attr); + pthread_mutexattr_destroy(&attr); +} +#endif + +static int fuse_loop_mt_send(struct fuse_chan *ch, const struct iovec iov[], + size_t count) +{ + struct fuse_worker *w = (struct fuse_worker *) fuse_chan_data(ch); + pthread_mutex_lock(&w->lock); + w->numavail ++; + pthread_mutex_unlock(&w->lock); + return fuse_chan_send(w->prevch, iov, count); +} + + +static int start_thread(struct fuse_worker *w, pthread_t *thread_id); + +static void *do_work(void *data) +{ + struct fuse_worker *w = (struct fuse_worker *) data; + int is_mainthread = (w->numworker == 1); + size_t bufsize = fuse_chan_bufsize(w->prevch); + char *buf = (char *) malloc(bufsize); + if (!buf) { + fprintf(stderr, "fuse: failed to allocate read buffer\n"); + fuse_session_exit(w->se); + w->error = -1; + return NULL; + } + + pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, NULL); + pthread_setcanceltype(PTHREAD_CANCEL_ASYNCHRONOUS, NULL); + + while (!fuse_session_exited(w->se)) { + int res = fuse_chan_receive(w->prevch, buf, bufsize); + if (!res) + continue; + if (res == -1) { + fuse_session_exit(w->se); + w->error = -1; + } + + pthread_mutex_lock(&w->lock); + w->numavail--; + if (w->numavail == 0 && w->numworker < FUSE_MAX_WORKERS) { + if (w->numworker < FUSE_MAX_WORKERS) { + /* FIXME: threads should be stored in a list instead + of an array */ + int start_res; + pthread_t *thread_id = &w->threads[w->numworker]; + w->numavail ++; + w->numworker ++; + start_res = start_thread(w, thread_id); + if (start_res == -1) + w->numavail --; + } + } + pthread_mutex_unlock(&w->lock); + fuse_session_process(w->se, buf, res, w->ch); + } + + /* Wait for cancellation */ + if (!is_mainthread) + pause(); + + return NULL; +} + +static int start_thread(struct fuse_worker *w, pthread_t *thread_id) +{ + int res = pthread_create(thread_id, NULL, do_work, w); + if (res != 0) { + fprintf(stderr, "fuse: error creating thread: %s\n", strerror(res)); + return -1; + } + + pthread_detach(*thread_id); + return 0; +} + +int fuse_session_loop_mt(struct fuse_session *se) +{ + int i; + int err; + struct fuse_worker *w; + struct fuse_chan_ops cop = { + .send = fuse_loop_mt_send, + }; + + w = (struct fuse_worker *) malloc(sizeof(struct fuse_worker)); + if (w == NULL) { + fprintf(stderr, "fuse: failed to allocate worker structure\n"); + return -1; + } + memset(w, 0, sizeof(struct fuse_worker)); + w->se = se; + w->prevch = fuse_session_next_chan(se, NULL); + w->ch = fuse_chan_new(&cop, -1, 0, w); + if (w->ch == NULL) { + free(w); + return -1; + } + w->error = 0; + w->numworker = 1; + w->numavail = 1; + mutex_init(&w->lock); + + do_work(w); + + pthread_mutex_lock(&w->lock); + for (i = 1; i < w->numworker; i++) + pthread_cancel(w->threads[i]); + pthread_mutex_unlock(&w->lock); + pthread_mutex_destroy(&w->lock); + err = w->error; + fuse_chan_destroy(w->ch); + free(w); + fuse_session_reset(se); + return err; +} diff --git a/lib/fuse_lowlevel.c b/lib/fuse_lowlevel.c index fce1d6d..bcd48c5 100644 --- a/lib/fuse_lowlevel.c +++ b/lib/fuse_lowlevel.c @@ -7,7 +7,7 @@ */ #include -#include "fuse_lowlevel_i.h" +#include "fuse_lowlevel.h" #include "fuse_kernel.h" #include @@ -16,37 +16,28 @@ #include #include #include -#include #include -#include -#include #define PARAM(inarg) (((char *)(inarg)) + sizeof(*(inarg))) -struct fuse_cmd { - char *buf; - size_t buflen; +struct fuse_ll { + unsigned int debug : 1; + unsigned int allow_root : 1; + struct fuse_lowlevel_ops op; + int got_init; + void *userdata; + int major; + int minor; + uid_t owner; }; struct fuse_req { struct fuse_ll *f; uint64_t unique; struct fuse_ctx ctx; + struct fuse_chan *ch; }; -#ifndef USE_UCLIBC -#define mutex_init(mut) pthread_mutex_init(mut, NULL) -#else -static void mutex_init(pthread_mutex_t *mut) -{ - pthread_mutexattr_t attr; - pthread_mutexattr_init(&attr); - pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_ADAPTIVE_NP); - pthread_mutex_init(mut, &attr); - pthread_mutexattr_destroy(&attr); -} -#endif - static const char *opname(enum fuse_opcode opcode) { switch (opcode) { @@ -86,20 +77,6 @@ static const char *opname(enum fuse_opcode opcode) } } -static inline void fuse_dec_avail(struct fuse_ll *f) -{ - pthread_mutex_lock(&f->worker_lock); - f->numavail --; - pthread_mutex_unlock(&f->worker_lock); -} - -static inline void fuse_inc_avail(struct fuse_ll *f) -{ - pthread_mutex_lock(&f->worker_lock); - f->numavail ++; - pthread_mutex_unlock(&f->worker_lock); -} - static void convert_stat(const struct stat *stbuf, struct fuse_attr *attr) { attr->ino = stbuf->st_ino; @@ -166,48 +143,25 @@ static size_t iov_length(const struct iovec *iov, size_t count) return ret; } -static int send_reply_raw(struct fuse_ll *f, const struct iovec iov[], - size_t count) +static void free_req(fuse_req_t req) { - int res; - unsigned outsize = iov_length(iov, count); - struct fuse_out_header *out = (struct fuse_out_header *) iov[0].iov_base; - out->len = outsize; - - if (f->debug) { - printf(" unique: %llu, error: %i (%s), outsize: %i\n", - out->unique, out->error, strerror(-out->error), outsize); - fflush(stdout); - } - - /* This needs to be done before the reply, otherwise the scheduler - could play tricks with us, and only let the counter be - increased long after the operation is done */ - fuse_inc_avail(f); - - res = writev(f->fd, iov, count); - if (res == -1) { - /* ENOENT means the operation was interrupted */ - if (!fuse_ll_exited(f) && errno != ENOENT) - perror("fuse: writing device"); - return -errno; - } - return 0; + free(req); } -static int send_reply(struct fuse_ll *f, uint64_t unique, int error, - const void *arg, size_t argsize) +static int send_reply(fuse_req_t req, int error, const void *arg, + size_t argsize) { struct fuse_out_header out; struct iovec iov[2]; size_t count; + int res; if (error <= -1000 || error > 0) { fprintf(stderr, "fuse: bad error value: %i\n", error); error = -ERANGE; } - out.unique = unique; + out.unique = req->unique; out.error = error; count = 1; iov[0].iov_base = &out; @@ -217,7 +171,17 @@ static int send_reply(struct fuse_ll *f, uint64_t unique, int error, iov[1].iov_base = (void *) arg; iov[1].iov_len = argsize; } - return send_reply_raw(f, iov, count); + out.len = iov_length(iov, count); + + if (req->f->debug) { + printf(" unique: %llu, error: %i (%s), outsize: %i\n", + out.unique, out.error, strerror(-out.error), out.len); + fflush(stdout); + } + res = fuse_chan_send(req->ch, iov, count); + free_req(req); + + return res; } size_t fuse_dirent_size(size_t namelen) @@ -257,23 +221,14 @@ static void convert_statfs(const struct statfs *stbuf, kstatfs->namelen = stbuf->f_namelen; } -static void free_req(fuse_req_t req) -{ - free(req); -} - -static int send_reply_req(fuse_req_t req, const void *arg, size_t argsize) +static int send_reply_ok(fuse_req_t req, const void *arg, size_t argsize) { - int res = send_reply(req->f, req->unique, 0, arg, argsize); - free_req(req); - return res; + return send_reply(req, 0, arg, argsize); } int fuse_reply_err(fuse_req_t req, int err) { - int res = send_reply(req->f, req->unique, -err, NULL, 0); - free_req(req); - return res; + return send_reply(req, -err, NULL, 0); } int fuse_reply_none(fuse_req_t req) @@ -316,7 +271,7 @@ int fuse_reply_entry(fuse_req_t req, const struct fuse_entry_param *e) arg.attr_valid_nsec = calc_timeout_nsec(e->attr_timeout); convert_stat(&e->attr, &arg.attr); - return send_reply_req(req, &arg, sizeof(arg)); + return send_reply_ok(req, &arg, sizeof(arg)); } int fuse_reply_attr(fuse_req_t req, const struct stat *attr, @@ -329,12 +284,12 @@ int fuse_reply_attr(fuse_req_t req, const struct stat *attr, arg.attr_valid_nsec = calc_timeout_nsec(attr_timeout); convert_stat(attr, &arg.attr); - return send_reply_req(req, &arg, sizeof(arg)); + return send_reply_ok(req, &arg, sizeof(arg)); } int fuse_reply_readlink(fuse_req_t req, const char *linkname) { - return send_reply_req(req, linkname, strlen(linkname)); + return send_reply_ok(req, linkname, strlen(linkname)); } int fuse_reply_open(fuse_req_t req, const struct fuse_file_info *f) @@ -348,7 +303,7 @@ int fuse_reply_open(fuse_req_t req, const struct fuse_file_info *f) if (f->keep_cache) arg.open_flags |= FOPEN_KEEP_CACHE; - return send_reply_req(req, &arg, sizeof(arg)); + return send_reply_ok(req, &arg, sizeof(arg)); } int fuse_reply_write(fuse_req_t req, size_t count) @@ -358,12 +313,12 @@ int fuse_reply_write(fuse_req_t req, size_t count) memset(&arg, 0, sizeof(arg)); arg.size = count; - return send_reply_req(req, &arg, sizeof(arg)); + return send_reply_ok(req, &arg, sizeof(arg)); } int fuse_reply_buf(fuse_req_t req, const char *buf, size_t size) { - return send_reply_req(req, buf, size); + return send_reply_ok(req, buf, size); } int fuse_reply_statfs(fuse_req_t req, const struct statfs *stbuf) @@ -373,7 +328,7 @@ int fuse_reply_statfs(fuse_req_t req, const struct statfs *stbuf) memset(&arg, 0, sizeof(arg)); convert_statfs(stbuf, &arg.st); - return send_reply_req(req, &arg, sizeof(arg)); + return send_reply_ok(req, &arg, sizeof(arg)); } int fuse_reply_xattr(fuse_req_t req, size_t count) @@ -383,7 +338,7 @@ int fuse_reply_xattr(fuse_req_t req, size_t count) memset(&arg, 0, sizeof(arg)); arg.size = count; - return send_reply_req(req, &arg, sizeof(arg)); + return send_reply_ok(req, &arg, sizeof(arg)); } int fuse_reply_getlk(fuse_req_t req, const struct fuse_lock_param *lk) @@ -393,7 +348,7 @@ int fuse_reply_getlk(fuse_req_t req, const struct fuse_lock_param *lk) memset(&arg, 0, sizeof(arg)); convert_lock_param(lk, &arg.lk); - return send_reply_req(req, &arg, sizeof(arg)); + return send_reply_ok(req, &arg, sizeof(arg)); } static void do_lookup(fuse_req_t req, fuse_ino_t nodeid, char *name) @@ -727,10 +682,10 @@ static void do_setlk(fuse_req_t req, fuse_ino_t nodeid, int issleep, fuse_reply_err(req, ENOSYS); } -static void do_init(struct fuse_ll *f, uint64_t unique, - struct fuse_init_in_out *arg) +static void do_init(fuse_req_t req, struct fuse_init_in_out *arg) { struct fuse_init_in_out outarg; + struct fuse_ll *f = req->f; if (f->debug) { printf("INIT: %u.%u\n", arg->major, arg->minor); @@ -738,7 +693,7 @@ static void do_init(struct fuse_ll *f, uint64_t unique, } f->got_init = 1; if (f->op.init) - f->userdata = f->op.init(f->userdata); + f->op.init(f->userdata); f->major = FUSE_KERNEL_VERSION; f->minor = FUSE_KERNEL_MINOR_VERSION; @@ -752,7 +707,7 @@ static void do_init(struct fuse_ll *f, uint64_t unique, fflush(stdout); } - send_reply(f, unique, 0, &outarg, sizeof(outarg)); + send_reply_ok(req, &outarg, sizeof(outarg)); } void *fuse_req_userdata(fuse_req_t req) @@ -765,48 +720,25 @@ const struct fuse_ctx *fuse_req_ctx(fuse_req_t req) return &req->ctx; } -static void free_cmd(struct fuse_cmd *cmd) -{ - free(cmd->buf); - free(cmd); -} - -void fuse_ll_process_cmd(struct fuse_ll *f, struct fuse_cmd *cmd) +static void fuse_ll_process(void *data, const char *buf, size_t len, + struct fuse_chan *ch) { - struct fuse_in_header *in = (struct fuse_in_header *) cmd->buf; - void *inarg = cmd->buf + sizeof(struct fuse_in_header); + struct fuse_ll *f = (struct fuse_ll *) data; + struct fuse_in_header *in = (struct fuse_in_header *) buf; + const void *inarg = buf + sizeof(struct fuse_in_header); struct fuse_req *req; - fuse_dec_avail(f); - if (f->debug) { printf("unique: %llu, opcode: %s (%i), nodeid: %lu, insize: %i\n", in->unique, opname((enum fuse_opcode) in->opcode), in->opcode, - (unsigned long) in->nodeid, cmd->buflen); + (unsigned long) in->nodeid, len); fflush(stdout); } - if (!f->got_init) { - if (in->opcode != FUSE_INIT) - send_reply(f, in->unique, -EPROTO, NULL, 0); - else - do_init(f, in->unique, (struct fuse_init_in_out *) inarg); - goto out; - } - - 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) { - send_reply(f, in->unique, -EACCES, NULL, 0); - goto out; - } - req = (struct fuse_req *) malloc(sizeof(struct fuse_req)); if (req == NULL) { fprintf(stderr, "fuse: failed to allocate request\n"); - goto out; + return; } req->f = f; @@ -814,8 +746,21 @@ void fuse_ll_process_cmd(struct fuse_ll *f, struct fuse_cmd *cmd) req->ctx.uid = in->uid; req->ctx.gid = in->gid; req->ctx.pid = in->pid; - - switch (in->opcode) { + req->ch = ch; + + if (!f->got_init && in->opcode != FUSE_INIT) + fuse_reply_err(req, EPROTO); + else 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 switch (in->opcode) { + case FUSE_INIT: + do_init(req, (struct fuse_init_in_out *) inarg); + break; + case FUSE_LOOKUP: do_lookup(req, in->nodeid, (char *) inarg); break; @@ -944,92 +889,9 @@ void fuse_ll_process_cmd(struct fuse_ll *f, struct fuse_cmd *cmd) default: fuse_reply_err(req, ENOSYS); } - - out: - free_cmd(cmd); -} - -void fuse_ll_exit(struct fuse_ll *f) -{ - f->exited = 1; -} - -int fuse_ll_exited(struct fuse_ll* f) -{ - return f->exited; -} - -struct fuse_cmd *fuse_ll_read_cmd(struct fuse_ll *f) -{ - ssize_t res; - struct fuse_cmd *cmd; - struct fuse_in_header *in; - void *inarg; - - cmd = (struct fuse_cmd *) malloc(sizeof(struct fuse_cmd)); - if (cmd == NULL) { - fprintf(stderr, "fuse: failed to allocate cmd in read\n"); - return NULL; - } - cmd->buf = (char *) malloc(FUSE_MAX_IN); - if (cmd->buf == NULL) { - fprintf(stderr, "fuse: failed to allocate read buffer\n"); - free(cmd); - return NULL; - } - in = (struct fuse_in_header *) cmd->buf; - inarg = cmd->buf + sizeof(struct fuse_in_header); - - res = read(f->fd, cmd->buf, FUSE_MAX_IN); - if (res == -1) { - free_cmd(cmd); - if (fuse_ll_exited(f) || errno == EINTR || errno == ENOENT) - return NULL; - - /* ENODEV means we got unmounted, so we silenty return failure */ - if (errno != ENODEV) { - /* BAD... This will happen again */ - perror("fuse: reading device"); - } - - fuse_ll_exit(f); - return NULL; - } - if ((size_t) res < sizeof(struct fuse_in_header)) { - free_cmd(cmd); - /* Cannot happen */ - fprintf(stderr, "short read on fuse device\n"); - fuse_ll_exit(f); - return NULL; - } - cmd->buflen = res; - - - return cmd; -} - -int fuse_ll_loop(struct fuse_ll *f) -{ - if (f == NULL) - return -1; - - while (1) { - struct fuse_cmd *cmd; - - if (fuse_ll_exited(f)) - break; - - cmd = fuse_ll_read_cmd(f); - if (cmd == NULL) - continue; - - fuse_ll_process_cmd(f, cmd); - } - f->exited = 0; - return 0; } -int fuse_ll_is_lib_option(const char *opt) +int fuse_lowlevel_is_lib_option(const char *opt) { if (strcmp(opt, "debug") == 0 || strcmp(opt, "allow_root") == 0) @@ -1063,15 +925,31 @@ static int parse_ll_opts(struct fuse_ll *f, const char *opts) return 0; } -struct fuse_ll *fuse_ll_new(int fd, const char *opts, - const struct fuse_ll_operations *op, - size_t op_size, void *userdata) +static void fuse_ll_destroy(void *data) +{ + struct fuse_ll *f = (struct fuse_ll *) data; + + if (f->op.destroy) + f->op.destroy(f->userdata); + + free(f); +} + + +struct fuse_session *fuse_lowlevel_new(const char *opts, + const struct fuse_lowlevel_ops *op, + size_t op_size, void *userdata) { struct fuse_ll *f; + struct fuse_session *se; + struct fuse_session_ops sop = { + .process = fuse_ll_process, + .destroy = fuse_ll_destroy, + }; - if (sizeof(struct fuse_ll_operations) < op_size) { + if (sizeof(struct fuse_lowlevel_ops) < op_size) { fprintf(stderr, "fuse: warning: library too old, some operations may not not work\n"); - op_size = sizeof(struct fuse_ll_operations); + op_size = sizeof(struct fuse_lowlevel_ops); } f = (struct fuse_ll *) calloc(1, sizeof(struct fuse_ll)); @@ -1083,14 +961,15 @@ struct fuse_ll *fuse_ll_new(int fd, const char *opts, if (parse_ll_opts(f, opts) == -1) goto out_free; - f->fd = fd; memcpy(&f->op, op, op_size); - f->exited = 0; f->owner = getuid(); f->userdata = userdata; - mutex_init(&f->worker_lock); - return f; + se = fuse_session_new(&sop, f); + if (!se) + goto out_free; + + return se; out_free: free(f); @@ -1098,12 +977,3 @@ struct fuse_ll *fuse_ll_new(int fd, const char *opts, return NULL; } -void fuse_ll_destroy(struct fuse_ll *f) -{ - if (f->op.destroy) - f->op.destroy(f->userdata); - - pthread_mutex_destroy(&f->worker_lock); - free(f); -} - diff --git a/lib/fuse_lowlevel_i.h b/lib/fuse_lowlevel_i.h deleted file mode 100644 index eb612fc..0000000 --- a/lib/fuse_lowlevel_i.h +++ /dev/null @@ -1,26 +0,0 @@ -/* - FUSE: Filesystem in Userspace - Copyright (C) 2001-2005 Miklos Szeredi - - This program can be distributed under the terms of the GNU LGPL. - See the file COPYING.LIB. -*/ - -#include "fuse_lowlevel.h" -#include - -struct fuse_ll { - unsigned int debug : 1; - unsigned int allow_root : 1; - int fd; - struct fuse_ll_operations op; - volatile int exited; - int got_init; - void *userdata; - int major; - int minor; - uid_t owner; - pthread_mutex_t worker_lock; - int numworker; - int numavail; -}; diff --git a/lib/fuse_lowlevel_mt.c b/lib/fuse_lowlevel_mt.c deleted file mode 100644 index ee3a0ac..0000000 --- a/lib/fuse_lowlevel_mt.c +++ /dev/null @@ -1,126 +0,0 @@ -/* - FUSE: Filesystem in Userspace - Copyright (C) 2001-2005 Miklos Szeredi - - This program can be distributed under the terms of the GNU LGPL. - See the file COPYING.LIB. -*/ - -#include "fuse_lowlevel_i.h" - -#include -#include -#include -#include -#include -#include -#include -#include - -#define FUSE_MAX_WORKERS 10 - -struct fuse_worker { - struct fuse_ll *f; - pthread_t threads[FUSE_MAX_WORKERS]; - void *data; - fuse_ll_processor_t proc; -}; - -static int start_thread(struct fuse_worker *w, pthread_t *thread_id); - -static void *do_work(void *data) -{ - struct fuse_worker *w = (struct fuse_worker *) data; - struct fuse_ll *f = w->f; - int is_mainthread = (f->numworker == 1); - - pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, NULL); - pthread_setcanceltype(PTHREAD_CANCEL_ASYNCHRONOUS, NULL); - - while (1) { - struct fuse_cmd *cmd; - - if (fuse_ll_exited(f)) - break; - - cmd = fuse_ll_read_cmd(w->f); - if (cmd == NULL) - continue; - - if (f->numavail == 0 && f->numworker < FUSE_MAX_WORKERS) { - pthread_mutex_lock(&f->worker_lock); - if (f->numworker < FUSE_MAX_WORKERS) { - /* FIXME: threads should be stored in a list instead - of an array */ - int res; - pthread_t *thread_id = &w->threads[f->numworker]; - f->numavail ++; - f->numworker ++; - pthread_mutex_unlock(&f->worker_lock); - res = start_thread(w, thread_id); - if (res == -1) { - pthread_mutex_lock(&f->worker_lock); - f->numavail --; - pthread_mutex_unlock(&f->worker_lock); - } - } else - pthread_mutex_unlock(&f->worker_lock); - } - - w->proc(w->f, cmd, w->data); - } - - /* Wait for cancellation */ - if (!is_mainthread) - pause(); - - return NULL; -} - -static int start_thread(struct fuse_worker *w, pthread_t *thread_id) -{ - int res = pthread_create(thread_id, NULL, do_work, w); - if (res != 0) { - fprintf(stderr, "fuse: error creating thread: %s\n", strerror(res)); - return -1; - } - - pthread_detach(*thread_id); - return 0; -} - -int fuse_ll_loop_mt_proc(struct fuse_ll *f, fuse_ll_processor_t proc, void *data) -{ - struct fuse_worker *w; - int i; - - w = (struct fuse_worker *) malloc(sizeof(struct fuse_worker)); - if (w == NULL) { - fprintf(stderr, "fuse: failed to allocate worker structure\n"); - return -1; - } - memset(w, 0, sizeof(struct fuse_worker)); - w->f = f; - w->data = data; - w->proc = proc; - - f->numworker = 1; - do_work(w); - - pthread_mutex_lock(&f->worker_lock); - for (i = 1; i < f->numworker; i++) - pthread_cancel(w->threads[i]); - pthread_mutex_unlock(&f->worker_lock); - free(w); - f->exited = 0; - return 0; -} - -int fuse_ll_loop_mt(struct fuse_ll *f) -{ - if (f) - return fuse_ll_loop_mt_proc(f, (fuse_ll_processor_t) fuse_ll_process_cmd, NULL); - else - return -1; -} - diff --git a/lib/fuse_mt.c b/lib/fuse_mt.c index 8359994..c6a6a03 100644 --- a/lib/fuse_mt.c +++ b/lib/fuse_mt.c @@ -13,7 +13,7 @@ #include #include #include - +#include static pthread_key_t context_key; static pthread_mutex_t context_lock = PTHREAD_MUTEX_INITIALIZER; @@ -75,28 +75,73 @@ struct procdata { void *data; }; -static void mt_generic_proc(struct fuse_ll *f, struct fuse_cmd *cmd, void *data) +static void mt_session_proc(void *data, const char *buf, size_t len, + struct fuse_chan *ch) { struct procdata *pd = (struct procdata *) data; - (void) f; + struct fuse_cmd *cmd = *(struct fuse_cmd **) buf; + + (void) len; + (void) ch; pd->proc(pd->f, cmd, pd->data); } +static int mt_chan_receive(struct fuse_chan *ch, char *buf, size_t size) +{ + struct fuse_cmd *cmd; + struct procdata *pd = (struct procdata *) fuse_chan_data(ch); + + assert(size >= sizeof(cmd)); + + cmd = fuse_read_cmd(pd->f); + if (cmd == NULL) + return -1; + + *(struct fuse_cmd **) buf = cmd; + + return 0; +} + int fuse_loop_mt_proc(struct fuse *f, fuse_processor_t proc, void *data) { int res; struct procdata pd; + struct fuse_session *prevse = fuse_get_session(f); + struct fuse_session *se; + struct fuse_chan *prevch = fuse_session_next_chan(prevse, NULL); + struct fuse_chan *ch; + struct fuse_session_ops sop = { + .process = mt_session_proc, + }; + struct fuse_chan_ops cop = { + .receive = mt_chan_receive, + }; pd.f = f; pd.proc = proc; pd.data = data; - if (mt_create_context_key() != 0) + se = fuse_session_new(&sop, &pd); + if (se == NULL) + return -1; + + ch = fuse_chan_new(&cop, fuse_chan_fd(prevch), sizeof(struct fuse_cmd *), + &pd); + if (ch == NULL) { + fuse_session_destroy(se); return -1; + } + fuse_session_add_chan(se, ch); + + if (mt_create_context_key() != 0) { + fuse_session_destroy(se); + return -1; + } - res = fuse_ll_loop_mt_proc(fuse_get_lowlevel(f), mt_generic_proc, &pd); + res = fuse_session_loop_mt(se); mt_delete_context_key(); + fuse_session_destroy(se); return res; } @@ -107,7 +152,7 @@ int fuse_loop_mt(struct fuse *f) if (mt_create_context_key() != 0) return -1; - res = fuse_ll_loop_mt(fuse_get_lowlevel(f)); + res = fuse_session_loop_mt(fuse_get_session(f)); mt_delete_context_key(); return res; diff --git a/lib/fuse_session.c b/lib/fuse_session.c new file mode 100644 index 0000000..a467b2f --- /dev/null +++ b/lib/fuse_session.c @@ -0,0 +1,154 @@ +/* + FUSE: Filesystem in Userspace + Copyright (C) 2001-2005 Miklos Szeredi + + This program can be distributed under the terms of the GNU LGPL. + See the file COPYING.LIB +*/ + +#include "fuse_lowlevel.h" + +#include +#include +#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; + + struct fuse_session *se; + + int fd; + + size_t bufsize; + + void *data; +}; + +struct fuse_session *fuse_session_new(struct fuse_session_ops *op, void *data) +{ + struct fuse_session *se = (struct fuse_session *) malloc(sizeof(*se)); + if (se == NULL) { + fprintf(stderr, "fuse: failed to allocate session\n"); + return NULL; + } + + memset(se, 0, sizeof(*se)); + se->op = *op; + se->data = data; + + return se; +} + +void fuse_session_add_chan(struct fuse_session *se, struct fuse_chan *ch) +{ + assert(se->ch == NULL); + assert(ch->se == NULL); + se->ch = ch; + ch->se = se; +} + +struct fuse_chan *fuse_session_next_chan(struct fuse_session *se, + struct fuse_chan *ch) +{ + assert(ch == NULL || ch == se->ch); + if (ch == NULL) + return se->ch; + else + return NULL; +} + +void fuse_session_process(struct fuse_session *se, const char *buf, size_t len, + struct fuse_chan *ch) +{ + se->op.process(se->data, buf, len, ch); +} + +void fuse_session_destroy(struct fuse_session *se) +{ + if (se->op.destroy) + se->op.destroy(se->data); + if (se->ch != NULL) + fuse_chan_destroy(se->ch); + free(se); +} + +void fuse_session_exit(struct fuse_session *se) +{ + se->exited = 1; +} + +void fuse_session_reset(struct fuse_session *se) +{ + se->exited = 0; +} + +int fuse_session_exited(struct fuse_session *se) +{ + return se->exited; +} + +struct fuse_chan *fuse_chan_new(struct fuse_chan_ops *op, int fd, + size_t bufsize, void *data) +{ + struct fuse_chan *ch = (struct fuse_chan *) malloc(sizeof(*ch)); + if (ch == NULL) { + fprintf(stderr, "fuse: failed to allocate channel\n"); + return NULL; + } + + memset(ch, 0, sizeof(*ch)); + ch->op = *op; + ch->fd = fd; + ch->bufsize = bufsize; + ch->data = data; + + return ch; +} + +int fuse_chan_fd(struct fuse_chan *ch) +{ + return ch->fd; +} + +size_t fuse_chan_bufsize(struct fuse_chan *ch) +{ + return ch->bufsize; +} + +void *fuse_chan_data(struct fuse_chan *ch) +{ + return ch->data; +} + +struct fuse_session *fuse_chan_session(struct fuse_chan *ch) +{ + return ch->se; +} + +int fuse_chan_receive(struct fuse_chan *ch, char *buf, size_t size) +{ + return ch->op.receive(ch, buf, size); +} + +int fuse_chan_send(struct fuse_chan *ch, const struct iovec iov[], size_t count) +{ + return ch->op.send(ch, iov, count); +} + +void fuse_chan_destroy(struct fuse_chan *ch) +{ + if (ch->op.destroy) + ch->op.destroy(ch); + free(ch); +} diff --git a/lib/fuse_versionscript b/lib/fuse_versionscript index 283adae..d1b6983 100644 --- a/lib/fuse_versionscript +++ b/lib/fuse_versionscript @@ -1,24 +1,28 @@ FUSE_2.2 { global: fuse_add_dirent; + fuse_chan_bufsize; + fuse_chan_data; + fuse_chan_destroy; + fuse_chan_fd; + fuse_chan_new; + fuse_chan_receive; + fuse_chan_send; + fuse_chan_session; fuse_destroy; fuse_dirent_size; fuse_exit; fuse_exited; fuse_get_context; + fuse_get_session; fuse_invalidate; fuse_is_lib_option; - fuse_ll_new; - fuse_ll_destroy; - fuse_ll_is_lib_option; - fuse_ll_loop; - fuse_ll_loop_mt; - fuse_ll_exited; - fuse_ll_read_cmd; - fuse_ll_process_cmd; + fuse_kern_chan_new; fuse_loop; fuse_loop_mt; fuse_loop_mt_proc; + fuse_lowlevel_is_lib_option; + fuse_lowlevel_new; fuse_main; fuse_main_compat1; fuse_main_compat2; @@ -30,17 +34,29 @@ FUSE_2.2 { fuse_new_compat2; fuse_process_cmd; fuse_read_cmd; + fuse_reply_attr; + fuse_reply_buf; + fuse_reply_entry; fuse_reply_err; + fuse_reply_getlk; fuse_reply_none; - fuse_reply_entry; - fuse_reply_attr; - fuse_reply_readlink; fuse_reply_open; - fuse_reply_write; - fuse_reply_buf; + fuse_reply_readlink; fuse_reply_statfs; + fuse_reply_write; fuse_reply_xattr; fuse_req_ctx; + fuse_req_userdata; + fuse_session_add_chan; + fuse_session_destroy; + fuse_session_exit; + fuse_session_exited; + fuse_session_loop; + fuse_session_loop_mt; + fuse_session_new; + fuse_session_next_chan; + fuse_session_process; + fuse_session_reset; fuse_set_getcontext_func; fuse_setup; fuse_setup_compat2;