diff options
Diffstat (limited to 'lib/fuse_lowlevel.c')
-rwxr-xr-x | lib/fuse_lowlevel.c | 161 |
1 files changed, 107 insertions, 54 deletions
diff --git a/lib/fuse_lowlevel.c b/lib/fuse_lowlevel.c index 45cd5f3..76cb7b7 100755 --- a/lib/fuse_lowlevel.c +++ b/lib/fuse_lowlevel.c @@ -153,6 +153,80 @@ static struct fuse_req *fuse_ll_alloc_req(struct fuse_ll *f) return req; } +static int fuse_chan_recv(struct fuse_session *se, struct fuse_buf *buf, + struct fuse_chan *ch) +{ + struct fuse_ll *f = se->f; + int err; + ssize_t res; + + if (!buf->mem) { + buf->mem = malloc(f->bufsize); + if (!buf->mem) { + fprintf(stderr, + "fuse: failed to allocate read buffer\n"); + return -ENOMEM; + } + } + +restart: + res = read(fuse_chan_fd(ch), buf->mem, f->bufsize); + err = errno; + + if (fuse_session_exited(se)) + return 0; + if (res == -1) { + /* ENOENT means the operation was interrupted, it's safe + to restart */ + if (err == ENOENT) + goto restart; + + if (err == ENODEV) { + fuse_session_exit(se); + return 0; + } + /* Errors occurring during normal operation: EINTR (read + interrupted), EAGAIN (nonblocking I/O), ENODEV (filesystem + umounted) */ + if (err != EINTR && err != EAGAIN) + perror("fuse: reading device"); + return -err; + } + if ((size_t) res < sizeof(struct fuse_in_header)) { + fprintf(stderr, "short read on fuse device\n"); + return -EIO; + } + + buf->size = res; + + return res; +} + +static int fuse_chan_send(struct fuse_chan *ch, const struct iovec iov[], + size_t count) +{ + ssize_t res = writev(fuse_chan_fd(ch), iov, count); + int err = errno; + + 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) && err != ENOENT) + perror("fuse: writing device"); + return -err; + } + + return 0; +} + +void fuse_chan_close(struct fuse_chan *ch) +{ + close(fuse_chan_fd(ch)); +} + static int fuse_send_msg(struct fuse_ll *f, struct fuse_chan *ch, struct iovec *iov, int count) @@ -301,8 +375,6 @@ int fuse_reply_err(fuse_req_t req, int err) void fuse_reply_none(fuse_req_t req) { - if (req->ch) - fuse_chan_send(req->ch, NULL, 0); fuse_free_req(req); } @@ -1787,7 +1859,7 @@ static void do_init(fuse_req_t req, fuse_ino_t nodeid, const void *inarg) struct fuse_init_in *arg = (struct fuse_init_in *) inarg; struct fuse_init_out outarg; struct fuse_ll *f = req->f; - size_t bufsize = fuse_chan_bufsize(req->ch); + size_t bufsize = f->bufsize; (void) nodeid; if (f->debug) { @@ -2062,7 +2134,7 @@ int fuse_lowlevel_notify_inval_inode(struct fuse_chan *ch, fuse_ino_t ino, if (!ch) return -EINVAL; - f = (struct fuse_ll *)fuse_session_data(fuse_chan_session(ch)); + f = fuse_chan_session(ch)->f; if (!f) return -ENODEV; @@ -2086,7 +2158,7 @@ int fuse_lowlevel_notify_inval_entry(struct fuse_chan *ch, fuse_ino_t parent, if (!ch) return -EINVAL; - f = (struct fuse_ll *)fuse_session_data(fuse_chan_session(ch)); + f = fuse_chan_session(ch)->f; if (!f) return -ENODEV; @@ -2113,7 +2185,7 @@ int fuse_lowlevel_notify_delete(struct fuse_chan *ch, if (!ch) return -EINVAL; - f = (struct fuse_ll *)fuse_session_data(fuse_chan_session(ch)); + f = fuse_chan_session(ch)->f; if (!f) return -ENODEV; @@ -2147,7 +2219,7 @@ int fuse_lowlevel_notify_store(struct fuse_chan *ch, fuse_ino_t ino, if (!ch) return -EINVAL; - f = (struct fuse_ll *)fuse_session_data(fuse_chan_session(ch)); + f = fuse_chan_session(ch)->f; if (!f) return -ENODEV; @@ -2229,7 +2301,7 @@ int fuse_lowlevel_notify_retrieve(struct fuse_chan *ch, fuse_ino_t ino, if (!ch) return -EINVAL; - f = (struct fuse_ll *)fuse_session_data(fuse_chan_session(ch)); + f = fuse_chan_session(ch)->f; if (!f) return -ENODEV; @@ -2374,10 +2446,10 @@ static int fuse_ll_copy_from_pipe(struct fuse_bufvec *dst, return 0; } -static void fuse_ll_process_buf(void *data, const struct fuse_buf *buf, - struct fuse_chan *ch) +void fuse_session_process_buf(struct fuse_session *se, + const struct fuse_buf *buf, struct fuse_chan *ch) { - struct fuse_ll *f = (struct fuse_ll *) data; + struct fuse_ll *f = se->f; const size_t write_header_size = sizeof(struct fuse_in_header) + sizeof(struct fuse_write_in); struct fuse_bufvec bufv = { .buf[0] = *buf, .count = 1 }; @@ -2513,17 +2585,6 @@ clear_pipe: goto out_free; } -static void fuse_ll_process(void *data, const char *buf, size_t len, - struct fuse_chan *ch) -{ - struct fuse_buf fbuf = { - .mem = (void *) buf, - .size = len, - }; - - fuse_ll_process_buf(data, &fbuf, ch); -} - enum { KEY_HELP, KEY_VERSION, @@ -2616,9 +2677,8 @@ static int fuse_ll_opt_proc(void *data, const char *arg, int key, return -1; } -static void fuse_ll_destroy(void *data) +static void fuse_ll_destroy(struct fuse_ll *f) { - struct fuse_ll *f = (struct fuse_ll *) data; struct fuse_ll_pipe *llp; if (f->got_init && !f->got_destroy) { @@ -2634,6 +2694,15 @@ static void fuse_ll_destroy(void *data) free(f); } +void fuse_session_destroy(struct fuse_session *se) +{ + fuse_ll_destroy(se->f); + if (se->ch != NULL) + fuse_chan_destroy(se->ch); + free(se); +} + + static void fuse_ll_pipe_destructor(void *data) { struct fuse_ll_pipe *llp = data; @@ -2641,12 +2710,11 @@ static void fuse_ll_pipe_destructor(void *data) } #ifdef HAVE_SPLICE -static int fuse_ll_receive_buf(struct fuse_session *se, struct fuse_buf *buf, - struct fuse_chan **chp) +int fuse_session_receive_buf(struct fuse_session *se, struct fuse_buf *buf, + struct fuse_chan *ch) { - struct fuse_chan *ch = *chp; - struct fuse_ll *f = fuse_session_data(se); - size_t bufsize = buf->size; + struct fuse_ll *f = se->f; + size_t bufsize = buf->size = f->bufsize; struct fuse_ll_pipe *llp; struct fuse_buf tmpbuf; int err; @@ -2730,30 +2798,17 @@ static int fuse_ll_receive_buf(struct fuse_session *se, struct fuse_buf *buf, return res; fallback: - res = fuse_chan_recv(chp, buf->mem, bufsize); - if (res <= 0) - return res; - - buf->size = res; - - return res; + return fuse_chan_recv(se, buf, ch); } #else -static int fuse_ll_receive_buf(struct fuse_session *se, struct fuse_buf *buf, - struct fuse_chan **chp) +int fuse_session_receive_buf(struct fuse_session *se, struct fuse_buf *buf, + struct fuse_chan *ch) { - (void) se; - - int res = fuse_chan_recv(chp, buf->mem, buf->size); - if (res <= 0) - return res; - - buf->size = res; - - return res; + return fuse_chan_recv(se, buf, ch); } #endif +#define MIN_BUFSIZE 0x21000 struct fuse_session *fuse_lowlevel_new(struct fuse_args *args, const struct fuse_lowlevel_ops *op, @@ -2762,10 +2817,6 @@ struct fuse_session *fuse_lowlevel_new(struct fuse_args *args, int err; 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_lowlevel_ops) < op_size) { fprintf(stderr, "fuse: warning: library too old, some operations may not work\n"); @@ -2782,6 +2833,9 @@ struct fuse_session *fuse_lowlevel_new(struct fuse_args *args, f->conn.max_write = UINT_MAX; f->conn.max_readahead = UINT_MAX; f->atomic_o_trunc = 0; + f->bufsize = getpagesize() + 0x1000; + f->bufsize = f->bufsize < MIN_BUFSIZE ? MIN_BUFSIZE : f->bufsize; + list_init_req(&f->list); list_init_req(&f->interrupts); list_init_nreq(&f->notify_list); @@ -2805,12 +2859,11 @@ struct fuse_session *fuse_lowlevel_new(struct fuse_args *args, f->owner = getuid(); f->userdata = userdata; - se = fuse_session_new(&sop, f); + se = fuse_session_new(); if (!se) goto out_key_destroy; - se->receive_buf = fuse_ll_receive_buf; - se->process_buf = fuse_ll_process_buf; + se->f = f; return se; |