diff options
Diffstat (limited to 'lib/fuse_lowlevel.c')
-rw-r--r--[-rwxr-xr-x] | lib/fuse_lowlevel.c | 209 |
1 files changed, 100 insertions, 109 deletions
diff --git a/lib/fuse_lowlevel.c b/lib/fuse_lowlevel.c index 2a7c580..7acc206 100755..100644 --- a/lib/fuse_lowlevel.c +++ b/lib/fuse_lowlevel.c @@ -2,6 +2,9 @@ FUSE: Filesystem in Userspace Copyright (C) 2001-2007 Miklos Szeredi <miklos@szeredi.hu> + Implementation of (most of) the low-level FUSE API. The session loop + functions are implemented in separate files. + This program can be distributed under the terms of the GNU LGPLv2. See the file COPYING.LIB */ @@ -41,8 +44,7 @@ struct fuse_pollhandle { uint64_t kh; - struct fuse_chan *ch; - struct fuse_ll *f; + struct fuse_session *se; }; static size_t pagesize; @@ -141,7 +143,7 @@ void fuse_free_req(fuse_req_t req) destroy_req(req); } -static struct fuse_req *fuse_ll_alloc_req(struct fuse_ll *f) +static struct fuse_req *fuse_ll_alloc_req(struct fuse_session *se) { struct fuse_req *req; @@ -149,7 +151,8 @@ static struct fuse_req *fuse_ll_alloc_req(struct fuse_ll *f) if (req == NULL) { fprintf(stderr, "fuse: failed to allocate request\n"); } else { - req->f = f; + req->f = se->f; + req->se = se; req->ctr = 1; list_init_req(req); fuse_mutex_init(&req->lock); @@ -158,18 +161,12 @@ static struct fuse_req *fuse_ll_alloc_req(struct fuse_ll *f) return req; } -void fuse_chan_close(struct fuse_chan *ch) -{ - int fd = ch->fd; - if (fd != -1) - close(fd); -} - - -static int fuse_send_msg(struct fuse_ll *f, struct fuse_chan *ch, +/* Send data. If *ch* is NULL, send via session master fd */ +static int fuse_send_msg(struct fuse_session *se, struct fuse_chan *ch, struct iovec *iov, int count) { struct fuse_out_header *out = iov[0].iov_base; + struct fuse_ll *f = se->f; out->len = iov_length(iov, count); if (f->debug) { @@ -188,12 +185,11 @@ static int fuse_send_msg(struct fuse_ll *f, struct fuse_chan *ch, } } - ssize_t res = writev(ch->fd, iov, count); + ssize_t res = writev(ch ? ch->fd : se->fd, + 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 */ @@ -222,7 +218,7 @@ int fuse_send_reply_iov_nofree(fuse_req_t req, int error, struct iovec *iov, iov[0].iov_base = &out; iov[0].iov_len = sizeof(struct fuse_out_header); - return fuse_send_msg(req->f, req->ch, iov, count); + return fuse_send_msg(req->se, req->ch, iov, count); } static int send_reply_iov(fuse_req_t req, int error, struct iovec *iov, @@ -477,7 +473,8 @@ int fuse_reply_buf(fuse_req_t req, const char *buf, size_t size) return send_reply_ok(req, buf, size); } -static int fuse_send_data_iov_fallback(struct fuse_ll *f, struct fuse_chan *ch, +static int fuse_send_data_iov_fallback(struct fuse_session *se, + struct fuse_chan *ch, struct iovec *iov, int iov_count, struct fuse_bufvec *buf, size_t len) @@ -495,7 +492,7 @@ static int fuse_send_data_iov_fallback(struct fuse_ll *f, struct fuse_chan *ch, iov[iov_count].iov_base = buf->buf[0].mem; iov[iov_count].iov_len = len; iov_count++; - return fuse_send_msg(f, ch, iov, iov_count); + return fuse_send_msg(se, ch, iov, iov_count); } res = posix_memalign(&mbuf, pagesize, len); @@ -513,7 +510,7 @@ static int fuse_send_data_iov_fallback(struct fuse_ll *f, struct fuse_chan *ch, iov[iov_count].iov_base = mbuf; iov[iov_count].iov_len = len; iov_count++; - res = fuse_send_msg(f, ch, iov, iov_count); + res = fuse_send_msg(se, ch, iov, iov_count); free(mbuf); return res; @@ -613,7 +610,7 @@ static int read_back(int fd, char *buf, size_t len) return 0; } -static int fuse_send_data_iov(struct fuse_ll *f, struct fuse_chan *ch, +static int fuse_send_data_iov(struct fuse_session *se, struct fuse_chan *ch, struct iovec *iov, int iov_count, struct fuse_bufvec *buf, unsigned int flags) { @@ -621,6 +618,7 @@ static int fuse_send_data_iov(struct fuse_ll *f, struct fuse_chan *ch, size_t len = fuse_buf_size(buf); struct fuse_out_header *out = iov[0].iov_base; struct fuse_ll_pipe *llp; + struct fuse_ll *f = se->f; int splice_flags; size_t pipesize; size_t total_fd_size; @@ -766,7 +764,7 @@ static int fuse_send_data_iov(struct fuse_ll *f, struct fuse_chan *ch, iov[iov_count].iov_base = mbuf; iov[iov_count].iov_len = len; iov_count++; - res = fuse_send_msg(f, ch, iov, iov_count); + res = fuse_send_msg(se, ch, iov, iov_count); free(mbuf); return res; } @@ -787,8 +785,8 @@ static int fuse_send_data_iov(struct fuse_ll *f, struct fuse_chan *ch, (f->conn.want & FUSE_CAP_SPLICE_MOVE)) splice_flags |= SPLICE_F_MOVE; - res = splice(llp->pipe[0], NULL, - ch->fd, NULL, out->len, splice_flags); + res = splice(llp->pipe[0], NULL, ch ? ch->fd : se->fd, + NULL, out->len, splice_flags); if (res == -1) { res = -errno; perror("fuse: splice from pipe"); @@ -807,17 +805,17 @@ clear_pipe: return res; fallback: - return fuse_send_data_iov_fallback(f, ch, iov, iov_count, buf, len); + return fuse_send_data_iov_fallback(se, ch, iov, iov_count, buf, len); } #else -static int fuse_send_data_iov(struct fuse_ll *f, struct fuse_chan *ch, +static int fuse_send_data_iov(struct fuse_session *se, struct fuse_chan *ch, struct iovec *iov, int iov_count, struct fuse_bufvec *buf, unsigned int flags) { size_t len = fuse_buf_size(buf); (void) flags; - return fuse_send_data_iov_fallback(f, ch, iov, iov_count, buf, len); + return fuse_send_data_iov_fallback(se, ch, iov, iov_count, buf, len); } #endif @@ -834,7 +832,7 @@ int fuse_reply_data(fuse_req_t req, struct fuse_bufvec *bufv, out.unique = req->unique; out.error = 0; - res = fuse_send_data_iov(req->f, req->ch, iov, 1, bufv, flags); + res = fuse_send_data_iov(req->se, req->ch, iov, 1, bufv, flags); if (res <= 0) { fuse_free_req(req); return res; @@ -1072,7 +1070,7 @@ static void do_batch_forget(fuse_req_t req, fuse_ino_t nodeid, struct fuse_forget_one *forget = ¶m[i]; struct fuse_req *dummy_req; - dummy_req = fuse_ll_alloc_req(req->f); + dummy_req = fuse_ll_alloc_req(req->se); if (dummy_req == NULL) break; @@ -1790,8 +1788,7 @@ static void do_poll(fuse_req_t req, fuse_ino_t nodeid, const void *inarg) return; } ph->kh = arg->kh; - ph->ch = req->ch; - ph->f = req->f; + ph->se = req->se; } req->f->op.poll(req, nodeid, &fi, ph); @@ -2079,12 +2076,12 @@ static void do_notify_reply(fuse_req_t req, fuse_ino_t nodeid, nreq->reply(nreq, req, nodeid, inarg, buf); } -static int send_notify_iov(struct fuse_ll *f, struct fuse_chan *ch, - int notify_code, struct iovec *iov, int count) +static int send_notify_iov(struct fuse_session *se, int notify_code, + struct iovec *iov, int count) { struct fuse_out_header out; - if (!f->got_init) + if (!se->f->got_init) return -ENOTCONN; out.unique = 0; @@ -2092,7 +2089,7 @@ static int send_notify_iov(struct fuse_ll *f, struct fuse_chan *ch, iov[0].iov_base = &out; iov[0].iov_len = sizeof(struct fuse_out_header); - return fuse_send_msg(f, ch, iov, count); + return fuse_send_msg(se, NULL, iov, count); } int fuse_lowlevel_notify_poll(struct fuse_pollhandle *ph) @@ -2106,7 +2103,7 @@ int fuse_lowlevel_notify_poll(struct fuse_pollhandle *ph) iov[1].iov_base = &outarg; iov[1].iov_len = sizeof(outarg); - return send_notify_iov(ph->f, ph->ch, FUSE_NOTIFY_POLL, iov, 2); + return send_notify_iov(ph->se, FUSE_NOTIFY_POLL, iov, 2); } else { return 0; } @@ -2133,7 +2130,7 @@ int fuse_lowlevel_notify_inval_inode(struct fuse_session *se, fuse_ino_t ino, iov[1].iov_base = &outarg; iov[1].iov_len = sizeof(outarg); - return send_notify_iov(f, se->ch, FUSE_NOTIFY_INVAL_INODE, iov, 2); + return send_notify_iov(se, FUSE_NOTIFY_INVAL_INODE, iov, 2); } int fuse_lowlevel_notify_inval_entry(struct fuse_session *se, fuse_ino_t parent, @@ -2159,7 +2156,7 @@ int fuse_lowlevel_notify_inval_entry(struct fuse_session *se, fuse_ino_t parent, iov[2].iov_base = (void *)name; iov[2].iov_len = namelen + 1; - return send_notify_iov(f, se->ch, FUSE_NOTIFY_INVAL_ENTRY, iov, 3); + return send_notify_iov(se, FUSE_NOTIFY_INVAL_ENTRY, iov, 3); } int fuse_lowlevel_notify_delete(struct fuse_session *se, @@ -2190,7 +2187,7 @@ int fuse_lowlevel_notify_delete(struct fuse_session *se, iov[2].iov_base = (void *)name; iov[2].iov_len = namelen + 1; - return send_notify_iov(f, se->ch, FUSE_NOTIFY_DELETE, iov, 3); + return send_notify_iov(se, FUSE_NOTIFY_DELETE, iov, 3); } int fuse_lowlevel_notify_store(struct fuse_session *se, fuse_ino_t ino, @@ -2227,7 +2224,7 @@ int fuse_lowlevel_notify_store(struct fuse_session *se, fuse_ino_t ino, iov[1].iov_base = &outarg; iov[1].iov_len = sizeof(outarg); - res = fuse_send_data_iov(f, se->ch, iov, 2, bufv, flags); + res = fuse_send_data_iov(se, NULL, iov, 2, bufv, flags); if (res > 0) res = -res; @@ -2316,7 +2313,7 @@ int fuse_lowlevel_notify_retrieve(struct fuse_session *se, fuse_ino_t ino, iov[1].iov_base = &outarg; iov[1].iov_len = sizeof(outarg); - err = send_notify_iov(f, se->ch, FUSE_NOTIFY_RETRIEVE, iov, 2); + err = send_notify_iov(se, FUSE_NOTIFY_RETRIEVE, iov, 2); if (err) { pthread_mutex_lock(&f->lock); list_del_nreq(&rreq->nreq); @@ -2439,7 +2436,7 @@ static int fuse_ll_copy_from_pipe(struct fuse_bufvec *dst, void fuse_session_process_buf(struct fuse_session *se, const struct fuse_buf *buf) { - fuse_session_process_buf_int(se, buf, se->ch); + fuse_session_process_buf_int(se, buf, NULL); } void fuse_session_process_buf_int(struct fuse_session *se, @@ -2485,7 +2482,7 @@ void fuse_session_process_buf_int(struct fuse_session *se, (unsigned long long) in->nodeid, buf->size, in->pid); } - req = fuse_ll_alloc_req(f); + req = fuse_ll_alloc_req(se); if (req == NULL) { struct fuse_out_header out = { .unique = in->unique, @@ -2496,7 +2493,7 @@ void fuse_session_process_buf_int(struct fuse_session *se, .iov_len = sizeof(struct fuse_out_header), }; - fuse_send_msg(f, ch, &iov, 1); + fuse_send_msg(se, ch, &iov, 1); goto clear_pipe; } @@ -2504,7 +2501,7 @@ void fuse_session_process_buf_int(struct fuse_session *se, req->ctx.uid = in->uid; req->ctx.gid = in->gid; req->ctx.pid = in->pid; - req->ch = fuse_chan_get(ch); + req->ch = ch ? fuse_chan_get(ch) : NULL; err = EIO; if (!f->got_init) { @@ -2581,11 +2578,6 @@ clear_pipe: goto out_free; } -enum { - KEY_HELP, - KEY_VERSION, -}; - static const struct fuse_opt fuse_ll_opts[] = { { "debug", offsetof(struct fuse_ll, debug), 1 }, { "-d", offsetof(struct fuse_ll, debug), 1 }, @@ -2622,23 +2614,19 @@ static const struct fuse_opt fuse_ll_opts[] = { { "no_writeback_cache", offsetof(struct fuse_ll, no_writeback_cache), 1}, { "time_gran=%u", offsetof(struct fuse_ll, conn.time_gran), 0 }, { "clone_fd", offsetof(struct fuse_ll, clone_fd), 1 }, - FUSE_OPT_KEY("max_read=", FUSE_OPT_KEY_DISCARD), - FUSE_OPT_KEY("-h", KEY_HELP), - FUSE_OPT_KEY("--help", KEY_HELP), - FUSE_OPT_KEY("-V", KEY_VERSION), - FUSE_OPT_KEY("--version", KEY_VERSION), FUSE_OPT_END }; -static void fuse_ll_version(void) +void fuse_lowlevel_version(void) { printf("using FUSE kernel interface version %i.%i\n", FUSE_KERNEL_VERSION, FUSE_KERNEL_MINOR_VERSION); } -static void fuse_ll_help(void) +void fuse_lowlevel_help(void) { printf( +"Low-level options\n" " -o max_write=N set maximum size of write requests\n" " -o max_readahead=N set maximum readahead\n" " -o max_background=N set number of maximum background requests\n" @@ -2658,32 +2646,16 @@ static void fuse_ll_help(void) " -o [no_]async_dio asynchronous direct I/O\n" " -o [no_]writeback_cache asynchronous, buffered writes\n" " -o time_gran=N time granularity in nsec\n" -" -o clone_fd clone fuse device file descriptors\n" -); +" -o clone_fd clone fuse device file descriptors\n\n"); } static int fuse_ll_opt_proc(void *data, const char *arg, int key, struct fuse_args *outargs) { - (void) data; (void) outargs; (void) arg; - - switch (key) { - case KEY_HELP: - fuse_ll_help(); - fuse_mount_help(); - break; - - case KEY_VERSION: - fuse_ll_version(); - fuse_mount_version(); - break; - - default: - fprintf(stderr, "fuse: unknown option `%s'\n", arg); - } + (void) data; (void) outargs; (void) key; (void) arg; - /* Fail */ - return -1; + /* Passthrough unknown options */ + return 1; } static void fuse_ll_destroy(struct fuse_ll *f) @@ -2706,7 +2678,7 @@ static void fuse_ll_destroy(struct fuse_ll *f) void fuse_session_destroy(struct fuse_session *se) { fuse_ll_destroy(se->f); - fuse_chan_put(se->ch); + close(se->fd); destroy_mount_opts(se->mo); free(se); } @@ -2720,7 +2692,7 @@ static void fuse_ll_pipe_destructor(void *data) int fuse_session_receive_buf(struct fuse_session *se, struct fuse_buf *buf) { - return fuse_session_receive_buf_int(se, buf, se->ch); + return fuse_session_receive_buf_int(se, buf, NULL); } int fuse_session_receive_buf_int(struct fuse_session *se, struct fuse_buf *buf, @@ -2754,7 +2726,8 @@ int fuse_session_receive_buf_int(struct fuse_session *se, struct fuse_buf *buf, goto fallback; } - res = splice(ch->fd, NULL, llp->pipe[1], NULL, bufsize, 0); + res = splice(ch ? ch->fd : se->fd, + NULL, llp->pipe[1], NULL, bufsize, 0); err = errno; if (fuse_session_exited(se)) @@ -2838,7 +2811,7 @@ fallback: } restart: - res = read(ch->fd, buf->mem, f->bufsize); + res = read(ch ? ch->fd : se->fd, buf->mem, f->bufsize); err = errno; if (fuse_session_exited(se)) @@ -2889,15 +2862,23 @@ struct fuse_session *fuse_session_new(struct fuse_args *args, f = (struct fuse_ll *) calloc(1, sizeof(struct fuse_ll)); if (f == NULL) { fprintf(stderr, "fuse: failed to allocate fuse object\n"); - goto out; + goto out1; } /* Parse options */ mo = parse_mount_opts(args); if (mo == NULL) - goto out_free0; - if (fuse_opt_parse(args, f, fuse_ll_opts, fuse_ll_opt_proc) == -1) - goto out_free; + goto out2; + if(fuse_opt_parse(args, f, fuse_ll_opts, fuse_ll_opt_proc) == -1) + goto out3; + if (args->argc != 1) { + int i; + fprintf(stderr, "fuse: unknown option(s): `"); + for(i = 1; i < args->argc-1; i++) + fprintf(stderr, "%s ", args->argv[i]); + fprintf(stderr, "%s'\n", args->argv[i]); + goto out4; + } if (f->debug) fprintf(stderr, "FUSE library version: %s\n", PACKAGE_VERSION); @@ -2919,7 +2900,7 @@ struct fuse_session *fuse_session_new(struct fuse_args *args, if (err) { fprintf(stderr, "fuse: failed to create thread specific key: %s\n", strerror(err)); - goto out_free; + goto out5; } memcpy(&f->op, op, op_size); @@ -2929,27 +2910,29 @@ struct fuse_session *fuse_session_new(struct fuse_args *args, se = (struct fuse_session *) malloc(sizeof(*se)); if (se == NULL) { fprintf(stderr, "fuse: failed to allocate session\n"); - goto out_key_destroy; + goto out6; } memset(se, 0, sizeof(*se)); se->f = f; se->mo = mo; return se; -out_key_destroy: +out6: pthread_key_delete(f->pipe_key); -out_free: - free(mo); -out_free0: +out5: pthread_mutex_destroy(&f->lock); +out4: + fuse_opt_free_args(args); +out3: + free(mo); +out2: free(f); -out: +out1: return NULL; } int fuse_session_mount(struct fuse_session *se, const char *mountpoint) { - struct fuse_chan *ch; int fd; /* @@ -2966,13 +2949,7 @@ int fuse_session_mount(struct fuse_session *se, const char *mountpoint) fd = fuse_kern_mount(mountpoint, se->mo); if (fd == -1) return -1; - - ch = fuse_chan_new(fd); - if (!ch) - goto error_out; - - /* Add channel to session */ - fuse_session_add_chan(se, ch); + se->fd = fd; /* Save mountpoint */ se->mountpoint = strdup(mountpoint); @@ -2986,17 +2963,16 @@ error_out: return -1; } +int fuse_session_fd(struct fuse_session *se) +{ + return se->fd; +} + void fuse_session_unmount(struct fuse_session *se) { - struct fuse_chan *ch = se->ch; - fuse_session_remove_chan(ch); - if (se->mountpoint) { - int fd = ch ? fuse_chan_clearfd(ch) : -1; - fuse_kern_unmount(se->mountpoint, fd); - fuse_chan_put(ch); - free(se->mountpoint); - se->mountpoint = NULL; - } + fuse_kern_unmount(se->mountpoint, se->fd); + free(se->mountpoint); + se->mountpoint = NULL; } #ifdef linux @@ -3067,3 +3043,18 @@ int fuse_req_getgroups(fuse_req_t req, int size, gid_t list[]) return -ENOSYS; } #endif + +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; +} |