From a5a00e9b7dd8c8dfef17523dccb3051e1f1dd5a2 Mon Sep 17 00:00:00 2001 From: Miklos Szeredi Date: Mon, 18 May 2015 16:55:20 +0200 Subject: [PATCH] libfuse: add "clone_fd" option This creates a separate device file descriptor for each processing thread, which might improve performance. --- ChangeLog | 4 ++++ include/fuse_kernel.h | 3 +++ lib/fuse_i.h | 1 + lib/fuse_loop_mt.c | 55 +++++++++++++++++++++++++++++++++++++++++-- lib/fuse_lowlevel.c | 2 ++ 5 files changed, 63 insertions(+), 2 deletions(-) diff --git a/ChangeLog b/ChangeLog index 8a65763..4450ca5 100644 --- a/ChangeLog +++ b/ChangeLog @@ -4,6 +4,10 @@ fuse_chan_get(), fuse_chan_put(). Removed function: fuse_chan_destroy(). + * libfuse: add "clone_fd" option. This creates a separate device + file descriptor for each processing thread, which might improve + performance. + 2015-04-23 Miklos Szeredi * libfuse: add FUSE_CAP_NO_OPEN_SUPPORT flag to ->init() diff --git a/include/fuse_kernel.h b/include/fuse_kernel.h index 25084a0..c9aca04 100644 --- a/include/fuse_kernel.h +++ b/include/fuse_kernel.h @@ -755,4 +755,7 @@ struct fuse_notify_retrieve_in { uint64_t dummy4; }; +/* Device ioctls: */ +#define FUSE_DEV_IOC_CLONE _IOR(229, 0, uint32_t) + #endif /* _LINUX_FUSE_H */ diff --git a/lib/fuse_i.h b/lib/fuse_i.h index 16adc69..62af9f2 100644 --- a/lib/fuse_i.h +++ b/lib/fuse_i.h @@ -80,6 +80,7 @@ struct fuse_ll { int no_async_dio; int writeback_cache; int no_writeback_cache; + int clone_fd; struct fuse_lowlevel_ops op; int got_init; struct cuse_data *cuse_data; diff --git a/lib/fuse_loop_mt.c b/lib/fuse_loop_mt.c index 8f4dceb..6d7f051 100755 --- a/lib/fuse_loop_mt.c +++ b/lib/fuse_loop_mt.c @@ -20,6 +20,7 @@ #include #include #include +#include /* Environment var controlling the thread stack size */ #define ENVNAME_THREAD_STACK "FUSE_THREAD_STACK" @@ -30,6 +31,7 @@ struct fuse_worker { pthread_t thread_id; size_t bufsize; struct fuse_buf fbuf; + struct fuse_chan *ch; struct fuse_mt *mt; }; @@ -74,7 +76,7 @@ static void *fuse_do_work(void *data) int res; pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, NULL); - res = fuse_session_receive_buf(mt->se, &w->fbuf, mt->prevch); + res = fuse_session_receive_buf(mt->se, &w->fbuf, w->ch); pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, NULL); if (res == -EINTR) continue; @@ -110,7 +112,7 @@ static void *fuse_do_work(void *data) fuse_loop_start_thread(mt); pthread_mutex_unlock(&mt->lock); - fuse_session_process_buf(mt->se, &w->fbuf, mt->prevch); + fuse_session_process_buf(mt->se, &w->fbuf, w->ch); pthread_mutex_lock(&mt->lock); if (!isforget) @@ -127,6 +129,7 @@ static void *fuse_do_work(void *data) pthread_detach(w->thread_id); free(w->fbuf.mem); + fuse_chan_put(w->ch); free(w); return NULL; } @@ -171,9 +174,46 @@ int fuse_start_thread(pthread_t *thread_id, void *(*func)(void *), void *arg) 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) { + fprintf(stderr, "fuse: failed to open %s: %s\n", devname, + strerror(errno)); + return NULL; + } + fcntl(clonefd, F_SETFD, FD_CLOEXEC); + + masterfd = fuse_chan_fd(mt->prevch); + res = ioctl(clonefd, FUSE_DEV_IOC_CLONE, &masterfd); + if (res == -1) { + fprintf(stderr, "fuse: failed to clone device fd: %s\n", + strerror(errno)); + close(clonefd); + mt->se->f->clone_fd = 0; + + return fuse_chan_get(mt->prevch); + } + 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) { fprintf(stderr, "fuse: failed to allocate worker structure\n"); @@ -183,8 +223,18 @@ static int fuse_loop_start_thread(struct fuse_mt *mt) w->fbuf.mem = NULL; w->mt = mt; + + if (mt->se->f->clone_fd) { + w->ch = fuse_clone_chan(mt); + if (!w->ch) + return -1; + } else { + w->ch = fuse_chan_get(mt->prevch); + } + res = fuse_start_thread(&w->thread_id, fuse_do_work, w); if (res == -1) { + fuse_chan_put(w->ch); free(w); return -1; } @@ -202,6 +252,7 @@ static void fuse_join_worker(struct fuse_mt *mt, struct fuse_worker *w) list_del_worker(w); pthread_mutex_unlock(&mt->lock); free(w->fbuf.mem); + fuse_chan_put(w->ch); free(w); } diff --git a/lib/fuse_lowlevel.c b/lib/fuse_lowlevel.c index 8433e0a..05103c0 100755 --- a/lib/fuse_lowlevel.c +++ b/lib/fuse_lowlevel.c @@ -2657,6 +2657,7 @@ static const struct fuse_opt fuse_ll_opts[] = { { "writeback_cache", offsetof(struct fuse_ll, writeback_cache), 1}, { "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), @@ -2693,6 +2694,7 @@ 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" ); } -- 2.30.2