From: "Dr. David Alan Gilbert" <dgilb...@redhat.com> There's a lot of the original fuse code we don't need; trim them down.
Signed-off-by: Dr. David Alan Gilbert <dgilb...@redhat.com> --- contrib/virtiofsd/fuse_i.h | 22 - contrib/virtiofsd/fuse_loop_mt.c | 308 -------------- contrib/virtiofsd/fuse_lowlevel.c | 653 +----------------------------- contrib/virtiofsd/helper.c | 136 ------- 4 files changed, 5 insertions(+), 1114 deletions(-) diff --git a/contrib/virtiofsd/fuse_i.h b/contrib/virtiofsd/fuse_i.h index d38b630ac5..bcd6a140fc 100644 --- a/contrib/virtiofsd/fuse_i.h +++ b/contrib/virtiofsd/fuse_i.h @@ -9,8 +9,6 @@ #include "fuse.h" #include "fuse_lowlevel.h" -struct mount_opts; - struct fuse_req { struct fuse_session *se; uint64_t unique; @@ -45,7 +43,6 @@ struct fuse_session { char *mountpoint; volatile int exited; int fd; - struct mount_opts *mo; int debug; int deny_others; struct fuse_lowlevel_ops op; @@ -58,7 +55,6 @@ struct fuse_session { struct fuse_req interrupts; pthread_mutex_t lock; int got_destroy; - pthread_key_t pipe_key; int broken_splice_nonblock; uint64_t notify_ctr; struct fuse_notify_req notify_list; @@ -106,34 +102,16 @@ struct fuse_chan *fuse_chan_get(struct fuse_chan *ch); */ void fuse_chan_put(struct fuse_chan *ch); -struct mount_opts *parse_mount_opts(struct fuse_args *args); -void destroy_mount_opts(struct mount_opts *mo); -void fuse_mount_version(void); -unsigned get_max_read(struct mount_opts *o); -void fuse_kern_unmount(const char *mountpoint, int fd); -int fuse_kern_mount(const char *mountpoint, struct mount_opts *mo); - int fuse_send_reply_iov_nofree(fuse_req_t req, int error, struct iovec *iov, int count); void fuse_free_req(fuse_req_t req); -void cuse_lowlevel_init(fuse_req_t req, fuse_ino_t nodeide, const void *inarg); - -int fuse_start_thread(pthread_t *thread_id, void *(*func)(void *), void *arg); - -int fuse_session_receive_buf_int(struct fuse_session *se, struct fuse_buf *buf, - struct fuse_chan *ch); void fuse_session_process_buf_int(struct fuse_session *se, const struct fuse_buf *buf, struct fuse_chan *ch); -struct fuse *fuse_new_31(struct fuse_args *args, const struct fuse_operations *op, - size_t op_size, void *private_data); -int fuse_loop_mt_32(struct fuse *f, struct fuse_loop_config *config); -int fuse_session_loop_mt_32(struct fuse_session *se, struct fuse_loop_config *config); #define FUSE_MAX_MAX_PAGES 256 #define FUSE_DEFAULT_MAX_PAGES_PER_REQ 32 /* room needed in buffer to accommodate header */ #define FUSE_BUFFER_HEADER_SIZE 0x1000 - diff --git a/contrib/virtiofsd/fuse_loop_mt.c b/contrib/virtiofsd/fuse_loop_mt.c index 445e9a0ab0..6fcd47e42c 100644 --- a/contrib/virtiofsd/fuse_loop_mt.c +++ b/contrib/virtiofsd/fuse_loop_mt.c @@ -28,48 +28,6 @@ /* Environment var controlling the thread stack size */ #define ENVNAME_THREAD_STACK "FUSE_THREAD_STACK" -struct fuse_worker { - struct fuse_worker *prev; - struct fuse_worker *next; - pthread_t thread_id; - size_t bufsize; - - // We need to include fuse_buf so that we can properly free - // it when a thread is terminated by pthread_cancel(). - struct fuse_buf fbuf; - struct fuse_chan *ch; - struct fuse_mt *mt; -}; - -struct fuse_mt { - pthread_mutex_t lock; - int numworker; - int numavail; - struct fuse_session *se; - struct fuse_worker main; - sem_t finish; - int exit; - int error; - int clone_fd; - int max_idle; -}; - -static struct fuse_chan *fuse_chan_new(int fd) -{ - struct fuse_chan *ch = (struct fuse_chan *) malloc(sizeof(*ch)); - if (ch == NULL) { - fuse_log(FUSE_LOG_ERR, "fuse: failed to allocate channel\n"); - return NULL; - } - - memset(ch, 0, sizeof(*ch)); - ch->fd = fd; - ch->ctr = 1; - fuse_mutex_init(&ch->lock); - - return ch; -} - struct fuse_chan *fuse_chan_get(struct fuse_chan *ch) { assert(ch->ctr > 0); @@ -94,269 +52,3 @@ void fuse_chan_put(struct fuse_chan *ch) } else pthread_mutex_unlock(&ch->lock); } - -static void list_add_worker(struct fuse_worker *w, struct fuse_worker *next) -{ - struct fuse_worker *prev = next->prev; - w->next = next; - w->prev = prev; - prev->next = w; - next->prev = w; -} - -static void list_del_worker(struct fuse_worker *w) -{ - struct fuse_worker *prev = w->prev; - struct fuse_worker *next = w->next; - prev->next = next; - next->prev = prev; -} - -static int fuse_loop_start_thread(struct fuse_mt *mt); - -static void *fuse_do_work(void *data) -{ - struct fuse_worker *w = (struct fuse_worker *) data; - struct fuse_mt *mt = w->mt; - - while (!fuse_session_exited(mt->se)) { - int isforget = 0; - int res; - - pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, NULL); - res = fuse_session_receive_buf_int(mt->se, &w->fbuf, w->ch); - pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, NULL); - if (res == -EINTR) - continue; - if (res <= 0) { - if (res < 0) { - fuse_session_exit(mt->se); - mt->error = res; - } - break; - } - - pthread_mutex_lock(&mt->lock); - if (mt->exit) { - pthread_mutex_unlock(&mt->lock); - return NULL; - } - - /* - * This disgusting hack is needed so that zillions of threads - * are not created on a burst of FORGET messages - */ - if (!(w->fbuf.flags & FUSE_BUF_IS_FD)) { - struct fuse_in_header *in = w->fbuf.mem; - - if (in->opcode == FUSE_FORGET || - in->opcode == FUSE_BATCH_FORGET) - isforget = 1; - } - - if (!isforget) - mt->numavail--; - if (mt->numavail == 0) - fuse_loop_start_thread(mt); - pthread_mutex_unlock(&mt->lock); - - fuse_session_process_buf_int(mt->se, &w->fbuf, w->ch); - - pthread_mutex_lock(&mt->lock); - if (!isforget) - mt->numavail++; - if (mt->numavail > mt->max_idle) { - if (mt->exit) { - pthread_mutex_unlock(&mt->lock); - return NULL; - } - list_del_worker(w); - mt->numavail--; - mt->numworker--; - pthread_mutex_unlock(&mt->lock); - - pthread_detach(w->thread_id); - free(w->fbuf.mem); - fuse_chan_put(w->ch); - free(w); - return NULL; - } - pthread_mutex_unlock(&mt->lock); - } - - sem_post(&mt->finish); - - return NULL; -} - -int fuse_start_thread(pthread_t *thread_id, void *(*func)(void *), void *arg) -{ - sigset_t oldset; - sigset_t newset; - int res; - pthread_attr_t attr; - char *stack_size; - - /* Override default stack size */ - pthread_attr_init(&attr); - stack_size = getenv(ENVNAME_THREAD_STACK); - if (stack_size && pthread_attr_setstacksize(&attr, atoi(stack_size))) - fuse_log(FUSE_LOG_ERR, "fuse: invalid stack size: %s\n", stack_size); - - /* Disallow signal reception in worker threads */ - sigemptyset(&newset); - sigaddset(&newset, SIGTERM); - sigaddset(&newset, SIGINT); - sigaddset(&newset, SIGHUP); - sigaddset(&newset, SIGQUIT); - pthread_sigmask(SIG_BLOCK, &newset, &oldset); - res = pthread_create(thread_id, &attr, func, arg); - pthread_sigmask(SIG_SETMASK, &oldset, NULL); - pthread_attr_destroy(&attr); - if (res != 0) { - fuse_log(FUSE_LOG_ERR, "fuse: error creating thread: %s\n", - strerror(res)); - return -1; - } - - return 0; -} - -static struct fuse_chan *fuse_clone_chan(struct fuse_mt *mt) -{ - int res; - int clonefd; - uint32_t masterfd; - struct fuse_chan *newch; - const char *devname = "/dev/fuse"; - -#ifndef O_CLOEXEC -#define O_CLOEXEC 0 -#endif - clonefd = open(devname, O_RDWR | O_CLOEXEC); - if (clonefd == -1) { - fuse_log(FUSE_LOG_ERR, "fuse: failed to open %s: %s\n", devname, - strerror(errno)); - return NULL; - } - fcntl(clonefd, F_SETFD, FD_CLOEXEC); - - masterfd = mt->se->fd; - res = ioctl(clonefd, FUSE_DEV_IOC_CLONE, &masterfd); - if (res == -1) { - fuse_log(FUSE_LOG_ERR, "fuse: failed to clone device fd: %s\n", - strerror(errno)); - close(clonefd); - return NULL; - } - newch = fuse_chan_new(clonefd); - if (newch == NULL) - close(clonefd); - - return newch; -} - -static int fuse_loop_start_thread(struct fuse_mt *mt) -{ - int res; - - struct fuse_worker *w = malloc(sizeof(struct fuse_worker)); - if (!w) { - fuse_log(FUSE_LOG_ERR, "fuse: failed to allocate worker structure\n"); - return -1; - } - memset(w, 0, sizeof(struct fuse_worker)); - w->fbuf.mem = NULL; - w->mt = mt; - - w->ch = NULL; - if (mt->clone_fd) { - w->ch = fuse_clone_chan(mt); - if(!w->ch) { - /* Don't attempt this again */ - fuse_log(FUSE_LOG_ERR, "fuse: trying to continue " - "without -o clone_fd.\n"); - mt->clone_fd = 0; - } - } - - res = fuse_start_thread(&w->thread_id, fuse_do_work, w); - if (res == -1) { - fuse_chan_put(w->ch); - free(w); - return -1; - } - list_add_worker(w, &mt->main); - mt->numavail ++; - mt->numworker ++; - - return 0; -} - -static void fuse_join_worker(struct fuse_mt *mt, struct fuse_worker *w) -{ - pthread_join(w->thread_id, NULL); - pthread_mutex_lock(&mt->lock); - list_del_worker(w); - pthread_mutex_unlock(&mt->lock); - free(w->fbuf.mem); - fuse_chan_put(w->ch); - free(w); -} - -FUSE_SYMVER(".symver fuse_session_loop_mt_32,fuse_session_loop_mt@@FUSE_3.2"); -int fuse_session_loop_mt_32(struct fuse_session *se, struct fuse_loop_config *config) -{ - int err; - struct fuse_mt mt; - struct fuse_worker *w; - - memset(&mt, 0, sizeof(struct fuse_mt)); - mt.se = se; - mt.clone_fd = config->clone_fd; - mt.error = 0; - mt.numworker = 0; - mt.numavail = 0; - mt.max_idle = config->max_idle_threads; - mt.main.thread_id = pthread_self(); - mt.main.prev = mt.main.next = &mt.main; - sem_init(&mt.finish, 0, 0); - fuse_mutex_init(&mt.lock); - - pthread_mutex_lock(&mt.lock); - err = fuse_loop_start_thread(&mt); - pthread_mutex_unlock(&mt.lock); - if (!err) { - /* sem_wait() is interruptible */ - while (!fuse_session_exited(se)) - sem_wait(&mt.finish); - - pthread_mutex_lock(&mt.lock); - for (w = mt.main.next; w != &mt.main; w = w->next) - pthread_cancel(w->thread_id); - mt.exit = 1; - pthread_mutex_unlock(&mt.lock); - - while (mt.main.next != &mt.main) - fuse_join_worker(&mt, mt.main.next); - - err = mt.error; - } - - pthread_mutex_destroy(&mt.lock); - sem_destroy(&mt.finish); - if(se->error != 0) - err = se->error; - fuse_session_reset(se); - return err; -} - -int fuse_session_loop_mt_31(struct fuse_session *se, int clone_fd); -FUSE_SYMVER(".symver fuse_session_loop_mt_31,fuse_session_loop_mt@FUSE_3.0"); -int fuse_session_loop_mt_31(struct fuse_session *se, int clone_fd) -{ - struct fuse_loop_config config; - config.clone_fd = clone_fd; - config.max_idle_threads = 10; - return fuse_session_loop_mt_32(se, &config); -} diff --git a/contrib/virtiofsd/fuse_lowlevel.c b/contrib/virtiofsd/fuse_lowlevel.c index f7fbc8f5db..f83cc2855d 100644 --- a/contrib/virtiofsd/fuse_lowlevel.c +++ b/contrib/virtiofsd/fuse_lowlevel.c @@ -28,12 +28,6 @@ #include <assert.h> #include <sys/file.h> -#ifndef F_LINUX_SPECIFIC_BASE -#define F_LINUX_SPECIFIC_BASE 1024 -#endif -#ifndef F_SETPIPE_SZ -#define F_SETPIPE_SZ (F_LINUX_SPECIFIC_BASE + 7) -#endif #define PARAM(inarg) (((char *)(inarg)) + sizeof(*(inarg))) @@ -184,19 +178,7 @@ static int fuse_send_msg(struct fuse_session *se, struct fuse_chan *ch, } } - ssize_t res = writev(ch ? ch->fd : se->fd, - iov, count); - int err = errno; - - if (res == -1) { - assert(se != NULL); - - /* ENOENT means the operation was interrupted */ - if (!fuse_session_exited(se) && err != ENOENT) - perror("fuse: writing device"); - return -err; - } - + abort(); /* virtio should have taken it before here */ return 0; } @@ -480,10 +462,6 @@ static int fuse_send_data_iov_fallback(struct fuse_session *se, struct fuse_bufvec *buf, size_t len) { - struct fuse_bufvec mem_buf = FUSE_BUFVEC_INIT(len); - void *mbuf; - int res; - /* Optimize common case */ if (buf->count == 1 && buf->idx == 0 && buf->off == 0 && !(buf->buf[0].flags & FUSE_BUF_IS_FD)) { @@ -496,350 +474,10 @@ static int fuse_send_data_iov_fallback(struct fuse_session *se, return fuse_send_msg(se, ch, iov, iov_count); } - res = posix_memalign(&mbuf, pagesize, len); - if (res != 0) - return res; - - mem_buf.buf[0].mem = mbuf; - res = fuse_buf_copy(&mem_buf, buf, 0); - if (res < 0) { - free(mbuf); - return -res; - } - len = res; - - iov[iov_count].iov_base = mbuf; - iov[iov_count].iov_len = len; - iov_count++; - res = fuse_send_msg(se, ch, iov, iov_count); - free(mbuf); - - return res; -} - -struct fuse_ll_pipe { - size_t size; - int can_grow; - int pipe[2]; -}; - -static void fuse_ll_pipe_free(struct fuse_ll_pipe *llp) -{ - close(llp->pipe[0]); - close(llp->pipe[1]); - free(llp); -} - -#ifdef HAVE_SPLICE -#if !defined(HAVE_PIPE2) || !defined(O_CLOEXEC) -static int fuse_pipe(int fds[2]) -{ - int rv = pipe(fds); - - if (rv == -1) - return rv; - - if (fcntl(fds[0], F_SETFL, O_NONBLOCK) == -1 || - fcntl(fds[1], F_SETFL, O_NONBLOCK) == -1 || - fcntl(fds[0], F_SETFD, FD_CLOEXEC) == -1 || - fcntl(fds[1], F_SETFD, FD_CLOEXEC) == -1) { - close(fds[0]); - close(fds[1]); - rv = -1; - } - return rv; -} -#else -static int fuse_pipe(int fds[2]) -{ - return pipe2(fds, O_CLOEXEC | O_NONBLOCK); -} -#endif - -static struct fuse_ll_pipe *fuse_ll_get_pipe(struct fuse_session *se) -{ - struct fuse_ll_pipe *llp = pthread_getspecific(se->pipe_key); - if (llp == NULL) { - int res; - - llp = malloc(sizeof(struct fuse_ll_pipe)); - if (llp == NULL) - return NULL; - - res = fuse_pipe(llp->pipe); - if (res == -1) { - free(llp); - return NULL; - } - - /* - *the default size is 16 pages on linux - */ - llp->size = pagesize * 16; - llp->can_grow = 1; - - pthread_setspecific(se->pipe_key, llp); - } - - return llp; -} -#endif - -static void fuse_ll_clear_pipe(struct fuse_session *se) -{ - struct fuse_ll_pipe *llp = pthread_getspecific(se->pipe_key); - if (llp) { - pthread_setspecific(se->pipe_key, NULL); - fuse_ll_pipe_free(llp); - } -} - -#if defined(HAVE_SPLICE) && defined(HAVE_VMSPLICE) -static int read_back(int fd, char *buf, size_t len) -{ - int res; - - res = read(fd, buf, len); - if (res == -1) { - fuse_log(FUSE_LOG_ERR, "fuse: internal error: failed to read back from pipe: %s\n", strerror(errno)); - return -EIO; - } - if (res != len) { - fuse_log(FUSE_LOG_ERR, "fuse: internal error: short read back from pipe: %i from %zi\n", res, len); - return -EIO; - } + abort(); /* Will have taken vhost path */ return 0; } -static int grow_pipe_to_max(int pipefd) -{ - int max; - int res; - int maxfd; - char buf[32]; - - maxfd = open("/proc/sys/fs/pipe-max-size", O_RDONLY); - if (maxfd < 0) - return -errno; - - res = read(maxfd, buf, sizeof(buf) - 1); - if (res < 0) { - int saved_errno; - - saved_errno = errno; - close(maxfd); - return -saved_errno; - } - close(maxfd); - buf[res] = '\0'; - - max = atoi(buf); - res = fcntl(pipefd, F_SETPIPE_SZ, max); - if (res < 0) - return -errno; - return max; -} - -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) -{ - int res; - size_t len = fuse_buf_size(buf); - struct fuse_out_header *out = iov[0].iov_base; - struct fuse_ll_pipe *llp; - int splice_flags; - size_t pipesize; - size_t total_fd_size; - size_t idx; - size_t headerlen; - struct fuse_bufvec pipe_buf = FUSE_BUFVEC_INIT(len); - - if (se->broken_splice_nonblock) - goto fallback; - - if (flags & FUSE_BUF_NO_SPLICE) - goto fallback; - - total_fd_size = 0; - for (idx = buf->idx; idx < buf->count; idx++) { - if (buf->buf[idx].flags & FUSE_BUF_IS_FD) { - total_fd_size = buf->buf[idx].size; - if (idx == buf->idx) - total_fd_size -= buf->off; - } - } - if (total_fd_size < 2 * pagesize) - goto fallback; - - if (se->conn.proto_minor < 14 || - !(se->conn.want & FUSE_CAP_SPLICE_WRITE)) - goto fallback; - - llp = fuse_ll_get_pipe(se); - if (llp == NULL) - goto fallback; - - - headerlen = iov_length(iov, iov_count); - - out->len = headerlen + len; - - /* - * Heuristic for the required pipe size, does not work if the - * source contains less than page size fragments - */ - pipesize = pagesize * (iov_count + buf->count + 1) + out->len; - - if (llp->size < pipesize) { - if (llp->can_grow) { - res = fcntl(llp->pipe[0], F_SETPIPE_SZ, pipesize); - if (res == -1) { - res = grow_pipe_to_max(llp->pipe[0]); - if (res > 0) - llp->size = res; - llp->can_grow = 0; - goto fallback; - } - llp->size = res; - } - if (llp->size < pipesize) - goto fallback; - } - - - res = vmsplice(llp->pipe[1], iov, iov_count, SPLICE_F_NONBLOCK); - if (res == -1) - goto fallback; - - if (res != headerlen) { - res = -EIO; - fuse_log(FUSE_LOG_ERR, "fuse: short vmsplice to pipe: %u/%zu\n", res, - headerlen); - goto clear_pipe; - } - - pipe_buf.buf[0].flags = FUSE_BUF_IS_FD; - pipe_buf.buf[0].fd = llp->pipe[1]; - - res = fuse_buf_copy(&pipe_buf, buf, - FUSE_BUF_FORCE_SPLICE | FUSE_BUF_SPLICE_NONBLOCK); - if (res < 0) { - if (res == -EAGAIN || res == -EINVAL) { - /* - * Should only get EAGAIN on kernels with - * broken SPLICE_F_NONBLOCK support (<= - * 2.6.35) where this error or a short read is - * returned even if the pipe itself is not - * full - * - * EINVAL might mean that splice can't handle - * this combination of input and output. - */ - if (res == -EAGAIN) - se->broken_splice_nonblock = 1; - - pthread_setspecific(se->pipe_key, NULL); - fuse_ll_pipe_free(llp); - goto fallback; - } - res = -res; - goto clear_pipe; - } - - if (res != 0 && res < len) { - struct fuse_bufvec mem_buf = FUSE_BUFVEC_INIT(len); - void *mbuf; - size_t now_len = res; - /* - * For regular files a short count is either - * 1) due to EOF, or - * 2) because of broken SPLICE_F_NONBLOCK (see above) - * - * For other inputs it's possible that we overflowed - * the pipe because of small buffer fragments. - */ - - res = posix_memalign(&mbuf, pagesize, len); - if (res != 0) - goto clear_pipe; - - mem_buf.buf[0].mem = mbuf; - mem_buf.off = now_len; - res = fuse_buf_copy(&mem_buf, buf, 0); - if (res > 0) { - char *tmpbuf; - size_t extra_len = res; - /* - * Trickiest case: got more data. Need to get - * back the data from the pipe and then fall - * back to regular write. - */ - tmpbuf = malloc(headerlen); - if (tmpbuf == NULL) { - free(mbuf); - res = ENOMEM; - goto clear_pipe; - } - res = read_back(llp->pipe[0], tmpbuf, headerlen); - free(tmpbuf); - if (res != 0) { - free(mbuf); - goto clear_pipe; - } - res = read_back(llp->pipe[0], mbuf, now_len); - if (res != 0) { - free(mbuf); - goto clear_pipe; - } - len = now_len + extra_len; - iov[iov_count].iov_base = mbuf; - iov[iov_count].iov_len = len; - iov_count++; - res = fuse_send_msg(se, ch, iov, iov_count); - free(mbuf); - return res; - } - free(mbuf); - res = now_len; - } - len = res; - out->len = headerlen + len; - - if (se->debug) { - fuse_log(FUSE_LOG_DEBUG, - " unique: %llu, success, outsize: %i (splice)\n", - (unsigned long long) out->unique, out->len); - } - - splice_flags = 0; - if ((flags & FUSE_BUF_SPLICE_MOVE) && - (se->conn.want & FUSE_CAP_SPLICE_MOVE)) - splice_flags |= SPLICE_F_MOVE; - - 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"); - goto clear_pipe; - } - if (res != out->len) { - res = -EIO; - fuse_log(FUSE_LOG_ERR, "fuse: short splice from pipe: %u/%u\n", - res, out->len); - goto clear_pipe; - } - return 0; - -clear_pipe: - fuse_ll_clear_pipe(se); - return res; - -fallback: - return fuse_send_data_iov_fallback(se, ch, iov, iov_count, buf, len); -} -#else 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) @@ -849,7 +487,6 @@ static int fuse_send_data_iov(struct fuse_session *se, struct fuse_chan *ch, return fuse_send_data_iov_fallback(se, ch, iov, iov_count, buf, len); } -#endif int fuse_reply_data(fuse_req_t req, struct fuse_bufvec *bufv, enum fuse_buf_copy_flags flags) @@ -1398,16 +1035,11 @@ static void do_write_buf(fuse_req_t req, fuse_ino_t nodeid, const void *inarg, if (bufv.buf[0].size < arg->size) { fuse_log(FUSE_LOG_ERR, "fuse: do_write_buf: buffer size too small\n"); fuse_reply_err(req, EIO); - goto out; + return; } bufv.buf[0].size = arg->size; se->op.write_buf(req, nodeid, &bufv, arg->offset, &fi); - -out: - /* Need to reset the pipe if ->write_buf() didn't consume all data */ - if ((ibuf->flags & FUSE_BUF_IS_FD) && bufv.idx < bufv.count) - fuse_ll_clear_pipe(se); } static void do_flush(fuse_req_t req, fuse_ino_t nodeid, const void *inarg) @@ -2014,17 +1646,6 @@ static void do_init(fuse_req_t req, fuse_ino_t nodeid, const void *inarg) return; } - unsigned max_read_mo = get_max_read(se->mo); - if (se->conn.max_read != max_read_mo) { - fuse_log(FUSE_LOG_ERR, "fuse: error: init() and fuse_session_new() " - "requested different maximum read size (%u vs %u)\n", - se->conn.max_read, max_read_mo); - fuse_reply_err(req, EPROTO); - se->error = -EPROTO; - fuse_session_exit(se); - return; - } - if (se->conn.max_write < bufsize - FUSE_BUFFER_HEADER_SIZE) { se->bufsize = se->conn.max_write + FUSE_BUFFER_HEADER_SIZE; } @@ -2340,8 +1961,6 @@ static void fuse_ll_retrieve_reply(struct fuse_notify_req *nreq, } out: free(rreq); - if ((ibuf->flags & FUSE_BUF_IS_FD) && bufv.idx < bufv.count) - fuse_ll_clear_pipe(se); } int fuse_lowlevel_notify_retrieve(struct fuse_session *se, fuse_ino_t ino, @@ -2484,21 +2103,6 @@ static const char *opname(enum fuse_opcode opcode) return fuse_ll_ops[opcode].name; } -static int fuse_ll_copy_from_pipe(struct fuse_bufvec *dst, - struct fuse_bufvec *src) -{ - ssize_t res = fuse_buf_copy(dst, src, 0); - if (res < 0) { - fuse_log(FUSE_LOG_ERR, "fuse: copy from pipe: %s\n", strerror(-res)); - return res; - } - if ((size_t)res < fuse_buf_size(dst)) { - fuse_log(FUSE_LOG_ERR, "fuse: copy from pipe: short read\n"); - return -1; - } - return 0; -} - void fuse_session_process_buf(struct fuse_session *se, const struct fuse_buf *buf) { @@ -2508,36 +2112,12 @@ void fuse_session_process_buf(struct fuse_session *se, void fuse_session_process_buf_int(struct fuse_session *se, const struct fuse_buf *buf, struct fuse_chan *ch) { - 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 }; - struct fuse_bufvec tmpbuf = FUSE_BUFVEC_INIT(write_header_size); struct fuse_in_header *in; const void *inarg; struct fuse_req *req; - void *mbuf = NULL; int err; - int res; - if (buf->flags & FUSE_BUF_IS_FD) { - if (buf->size < tmpbuf.buf[0].size) - tmpbuf.buf[0].size = buf->size; - - mbuf = malloc(tmpbuf.buf[0].size); - if (mbuf == NULL) { - fuse_log(FUSE_LOG_ERR, "fuse: failed to allocate header\n"); - goto clear_pipe; - } - tmpbuf.buf[0].mem = mbuf; - - res = fuse_ll_copy_from_pipe(&tmpbuf, &bufv); - if (res < 0) - goto clear_pipe; - - in = mbuf; - } else { - in = buf->mem; - } + in = buf->mem; if (se->debug) { fuse_log(FUSE_LOG_DEBUG, @@ -2559,7 +2139,7 @@ void fuse_session_process_buf_int(struct fuse_session *se, }; fuse_send_msg(se, ch, &iov, 1); - goto clear_pipe; + return; } req->unique = in->unique; @@ -2602,28 +2182,6 @@ void fuse_session_process_buf_int(struct fuse_session *se, fuse_reply_err(intr, EAGAIN); } - if ((buf->flags & FUSE_BUF_IS_FD) && write_header_size < buf->size && - (in->opcode != FUSE_WRITE || !se->op.write_buf) && - in->opcode != FUSE_NOTIFY_REPLY) { - void *newmbuf; - - err = ENOMEM; - newmbuf = realloc(mbuf, buf->size); - if (newmbuf == NULL) - goto reply_err; - mbuf = newmbuf; - - tmpbuf = FUSE_BUFVEC_INIT(buf->size - write_header_size); - tmpbuf.buf[0].mem = (char *)mbuf + write_header_size; - - res = fuse_ll_copy_from_pipe(&tmpbuf, &bufv); - err = -res; - if (res < 0) - goto reply_err; - - in = mbuf; - } - inarg = (void *) &in[1]; if (in->opcode == FUSE_WRITE && se->op.write_buf) do_write_buf(req, in->nodeid, inarg, buf); @@ -2632,16 +2190,10 @@ void fuse_session_process_buf_int(struct fuse_session *se, else fuse_ll_ops[in->opcode].func(req, in->nodeid, inarg); -out_free: - free(mbuf); return; reply_err: fuse_reply_err(req, err); -clear_pipe: - if (buf->flags & FUSE_BUF_IS_FD) - fuse_ll_clear_pipe(se); - goto out_free; } #define LL_OPTION(n,o,v) \ @@ -2674,197 +2226,23 @@ void fuse_lowlevel_help(void) void fuse_session_destroy(struct fuse_session *se) { - struct fuse_ll_pipe *llp; - if (se->got_init && !se->got_destroy) { if (se->op.destroy) se->op.destroy(se->userdata); } - llp = pthread_getspecific(se->pipe_key); - if (llp != NULL) - fuse_ll_pipe_free(llp); - pthread_key_delete(se->pipe_key); pthread_mutex_destroy(&se->lock); free(se->cuse_data); if (se->fd != -1) close(se->fd); - destroy_mount_opts(se->mo); free(se); } -static void fuse_ll_pipe_destructor(void *data) -{ - struct fuse_ll_pipe *llp = data; - fuse_ll_pipe_free(llp); -} - -int fuse_session_receive_buf(struct fuse_session *se, struct fuse_buf *buf) -{ - return fuse_session_receive_buf_int(se, buf, NULL); -} - -int fuse_session_receive_buf_int(struct fuse_session *se, struct fuse_buf *buf, - struct fuse_chan *ch) -{ - int err; - ssize_t res; -#ifdef HAVE_SPLICE - size_t bufsize = se->bufsize; - struct fuse_ll_pipe *llp; - struct fuse_buf tmpbuf; - - if (se->conn.proto_minor < 14 || !(se->conn.want & FUSE_CAP_SPLICE_READ)) - goto fallback; - - llp = fuse_ll_get_pipe(se); - if (llp == NULL) - goto fallback; - - if (llp->size < bufsize) { - if (llp->can_grow) { - res = fcntl(llp->pipe[0], F_SETPIPE_SZ, bufsize); - if (res == -1) { - llp->can_grow = 0; - res = grow_pipe_to_max(llp->pipe[0]); - if (res > 0) - llp->size = res; - goto fallback; - } - llp->size = res; - } - if (llp->size < bufsize) - goto fallback; - } - - res = splice(ch ? ch->fd : se->fd, - NULL, llp->pipe[1], NULL, bufsize, 0); - err = errno; - - if (fuse_session_exited(se)) - return 0; - - if (res == -1) { - if (err == ENODEV) { - /* Filesystem was unmounted, or connection was aborted - via /sys/fs/fuse/connections */ - fuse_session_exit(se); - return 0; - } - if (err != EINTR && err != EAGAIN) - perror("fuse: splice from device"); - return -err; - } - - if (res < sizeof(struct fuse_in_header)) { - fuse_log(FUSE_LOG_ERR, "short splice from fuse device\n"); - return -EIO; - } - - tmpbuf = (struct fuse_buf) { - .size = res, - .flags = FUSE_BUF_IS_FD, - .fd = llp->pipe[0], - }; - - /* - * Don't bother with zero copy for small requests. - * fuse_loop_mt() needs to check for FORGET so this more than - * just an optimization. - */ - if (res < sizeof(struct fuse_in_header) + - sizeof(struct fuse_write_in) + pagesize) { - struct fuse_bufvec src = { .buf[0] = tmpbuf, .count = 1 }; - struct fuse_bufvec dst = { .count = 1 }; - - if (!buf->mem) { - buf->mem = malloc(se->bufsize); - if (!buf->mem) { - fuse_log(FUSE_LOG_ERR, - "fuse: failed to allocate read buffer\n"); - return -ENOMEM; - } - } - buf->size = se->bufsize; - buf->flags = 0; - dst.buf[0] = *buf; - - res = fuse_buf_copy(&dst, &src, 0); - if (res < 0) { - fuse_log(FUSE_LOG_ERR, "fuse: copy from pipe: %s\n", - strerror(-res)); - fuse_ll_clear_pipe(se); - return res; - } - if (res < tmpbuf.size) { - fuse_log(FUSE_LOG_ERR, "fuse: copy from pipe: short read\n"); - fuse_ll_clear_pipe(se); - return -EIO; - } - assert(res == tmpbuf.size); - - } else { - /* Don't overwrite buf->mem, as that would cause a leak */ - buf->fd = tmpbuf.fd; - buf->flags = tmpbuf.flags; - } - buf->size = tmpbuf.size; - - return res; - -fallback: -#endif - if (!buf->mem) { - buf->mem = malloc(se->bufsize); - if (!buf->mem) { - fuse_log(FUSE_LOG_ERR, - "fuse: failed to allocate read buffer\n"); - return -ENOMEM; - } - } - -restart: - res = read(ch ? ch->fd : se->fd, buf->mem, se->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) { - /* Filesystem was unmounted, or connection was aborted - via /sys/fs/fuse/connections */ - 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)) { - fuse_log(FUSE_LOG_ERR, "short read on fuse device\n"); - return -EIO; - } - - buf->size = res; - - return res; -} - struct fuse_session *fuse_session_new(struct fuse_args *args, const struct fuse_lowlevel_ops *op, size_t op_size, void *userdata) { - int err; struct fuse_session *se; - struct mount_opts *mo; if (sizeof(struct fuse_lowlevel_ops) < op_size) { fuse_log(FUSE_LOG_ERR, "fuse: warning: library too old, some operations may not work\n"); @@ -2898,10 +2276,6 @@ struct fuse_session *fuse_session_new(struct fuse_args *args, if(fuse_opt_add_arg(args, "-oallow_other") == -1) goto out2; } - mo = parse_mount_opts(args); - if (mo == NULL) - goto out3; - if(args->argc == 1 && args->argv[0][0] == '-') { fuse_log(FUSE_LOG_ERR, "fuse: warning: argv[0] looks like an option, but " @@ -2927,26 +2301,14 @@ struct fuse_session *fuse_session_new(struct fuse_args *args, se->notify_ctr = 1; fuse_mutex_init(&se->lock); - err = pthread_key_create(&se->pipe_key, fuse_ll_pipe_destructor); - if (err) { - fuse_log(FUSE_LOG_ERR, "fuse: failed to create thread specific key: %s\n", - strerror(err)); - goto out5; - } - memcpy(&se->op, op, op_size); se->owner = getuid(); se->userdata = userdata; - se->mo = mo; return se; -out5: - pthread_mutex_destroy(&se->lock); out4: fuse_opt_free_args(args); -out3: - free(mo); out2: free(se); out1: @@ -3010,11 +2372,6 @@ int fuse_session_fd(struct fuse_session *se) void fuse_session_unmount(struct fuse_session *se) { - if (se->mountpoint != NULL) { - fuse_kern_unmount(se->mountpoint, se->fd); - free(se->mountpoint); - se->mountpoint = NULL; - } } #ifdef linux diff --git a/contrib/virtiofsd/helper.c b/contrib/virtiofsd/helper.c index 64ff7ad6d5..8b993f228b 100644 --- a/contrib/virtiofsd/helper.c +++ b/contrib/virtiofsd/helper.c @@ -171,34 +171,6 @@ static int fuse_helper_opt_proc(void *data, const char *arg, int key, } } -/* Under FreeBSD, there is no subtype option so this - function actually sets the fsname */ -static int add_default_subtype(const char *progname, struct fuse_args *args) -{ - int res; - char *subtype_opt; - - const char *basename = strrchr(progname, '/'); - if (basename == NULL) - basename = progname; - else if (basename[1] != '\0') - basename++; - - subtype_opt = (char *) malloc(strlen(basename) + 64); - if (subtype_opt == NULL) { - fuse_log(FUSE_LOG_ERR, "fuse: memory allocation failed\n"); - return -1; - } -#ifdef __FreeBSD__ - sprintf(subtype_opt, "-ofsname=%s", basename); -#else - sprintf(subtype_opt, "-osubtype=%s", basename); -#endif - res = fuse_opt_add_arg(args, subtype_opt); - free(subtype_opt); - return res; -} - int fuse_parse_cmdline(struct fuse_args *args, struct fuse_cmdline_opts *opts) { @@ -210,14 +182,6 @@ int fuse_parse_cmdline(struct fuse_args *args, fuse_helper_opt_proc) == -1) return -1; - /* *Linux*: if neither -o subtype nor -o fsname are specified, - set subtype to program's basename. - *FreeBSD*: if fsname is not specified, set to program's - basename. */ - if (!opts->nodefault_subtype) - if (add_default_subtype(args->argv[0], args) == -1) - return -1; - return 0; } @@ -276,88 +240,6 @@ int fuse_daemonize(int foreground) return 0; } -int fuse_main_real(int argc, char *argv[], const struct fuse_operations *op, - size_t op_size, void *user_data) -{ - struct fuse_args args = FUSE_ARGS_INIT(argc, argv); - struct fuse *fuse; - struct fuse_cmdline_opts opts; - int res; - - if (fuse_parse_cmdline(&args, &opts) != 0) - return 1; - - if (opts.show_version) { - printf("FUSE library version %s\n", PACKAGE_VERSION); - fuse_lowlevel_version(); - res = 0; - goto out1; - } - - if (opts.show_help) { - if(args.argv[0][0] != '\0') - printf("usage: %s [options] <mountpoint>\n\n", - args.argv[0]); - printf("FUSE options:\n"); - fuse_cmdline_help(); - fuse_lib_help(&args); - res = 0; - goto out1; - } - - if (!opts.show_help && - !opts.mountpoint) { - fuse_log(FUSE_LOG_ERR, "error: no mountpoint specified\n"); - res = 2; - goto out1; - } - - - fuse = fuse_new_31(&args, op, op_size, user_data); - if (fuse == NULL) { - res = 3; - goto out1; - } - - if (fuse_mount(fuse,opts.mountpoint) != 0) { - res = 4; - goto out2; - } - - if (fuse_daemonize(opts.foreground) != 0) { - res = 5; - goto out3; - } - - struct fuse_session *se = fuse_get_session(fuse); - if (fuse_set_signal_handlers(se) != 0) { - res = 6; - goto out3; - } - - if (opts.singlethread) - res = fuse_loop(fuse); - else { - struct fuse_loop_config loop_config; - loop_config.clone_fd = opts.clone_fd; - loop_config.max_idle_threads = opts.max_idle_threads; - res = fuse_loop_mt_32(fuse, &loop_config); - } - if (res) - res = 7; - - fuse_remove_signal_handlers(se); -out3: - fuse_unmount(fuse); -out2: - fuse_destroy(fuse); -out1: - free(opts.mountpoint); - fuse_opt_free_args(&args); - return res; -} - - void fuse_apply_conn_info_opts(struct fuse_conn_info_opts *opts, struct fuse_conn_info *conn) { @@ -420,21 +302,3 @@ struct fuse_conn_info_opts* fuse_parse_conn_info_opts(struct fuse_args *args) } return opts; } - -int fuse_open_channel(const char *mountpoint, const char* options) -{ - struct mount_opts *opts = NULL; - int fd = -1; - const char *argv[] = { "", "-o", options }; - int argc = sizeof(argv) / sizeof(argv[0]); - struct fuse_args args = FUSE_ARGS_INIT(argc, (char**) argv); - - opts = parse_mount_opts(&args); - if (opts == NULL) - return -1; - - fd = fuse_kern_mount(mountpoint, opts); - destroy_mount_opts(opts); - - return fd; -} -- 2.23.0