summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMiklos Szeredi <mszeredi@suse.cz>2015-05-18 16:55:20 +0200
committerMiklos Szeredi <mszeredi@suse.cz>2015-05-18 16:55:20 +0200
commita5a00e9b7dd8c8dfef17523dccb3051e1f1dd5a2 (patch)
tree94f6c75df3c511fe484c0fb0f00d91994a2d9d5a
parent62771d7f003c09166663b02f8d500b5cbec7dec9 (diff)
downloadfuse-clone_fd.tar.gz
libfuse: add "clone_fd" optionclone_fd
This creates a separate device file descriptor for each processing thread, which might improve performance.
-rw-r--r--ChangeLog4
-rw-r--r--include/fuse_kernel.h3
-rw-r--r--lib/fuse_i.h1
-rwxr-xr-xlib/fuse_loop_mt.c55
-rwxr-xr-xlib/fuse_lowlevel.c2
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 <miklos@szeredi.hu>
* 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 <semaphore.h>
#include <errno.h>
#include <sys/time.h>
+#include <sys/ioctl.h>
/* 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"
);
}