aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--ChangeLog10
-rw-r--r--include/fuse_kernel.h3
-rw-r--r--include/fuse_lowlevel.h12
-rw-r--r--lib/fuse_i.h3
-rwxr-xr-xlib/fuse_loop_mt.c55
-rwxr-xr-xlib/fuse_lowlevel.c9
-rw-r--r--lib/fuse_session.c31
-rw-r--r--lib/helper.c3
8 files changed, 113 insertions, 13 deletions
diff --git a/ChangeLog b/ChangeLog
index 5b39f16..342f91d 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -17,6 +17,16 @@
systems without requiring use of the site configuration directory
(/etc/). Patch by Ikey Doherty
+2015-05-23 Miklos Szeredi <miklos@szeredi.hu>
+
+ * libfuse: refcount fuse_chan objects. New functions:
+ 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-05-22 Miklos Szeredi <miklos@szeredi.hu>
* libfuse: fix exec environment for mount and umount. Found by
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/include/fuse_lowlevel.h b/include/fuse_lowlevel.h
index 20e7692..3cc9db5 100644
--- a/include/fuse_lowlevel.h
+++ b/include/fuse_lowlevel.h
@@ -1705,11 +1705,19 @@ int fuse_session_loop_mt(struct fuse_session *se);
int fuse_chan_fd(struct fuse_chan *ch);
/**
- * Destroy a channel
+ * Obtain counted reference to the channel
+ *
+ * @param ch the channel
+ * @return the channel
+ */
+struct fuse_chan *fuse_chan_get(struct fuse_chan *ch);
+
+/**
+ * Drop counted reference to a channel
*
* @param ch the channel
*/
-void fuse_chan_destroy(struct fuse_chan *ch);
+void fuse_chan_put(struct fuse_chan *ch);
#ifdef __cplusplus
}
diff --git a/lib/fuse_i.h b/lib/fuse_i.h
index 4bbcbd6..62af9f2 100644
--- a/lib/fuse_i.h
+++ b/lib/fuse_i.h
@@ -23,6 +23,8 @@ struct fuse_session {
struct fuse_chan {
struct fuse_session *se;
+ pthread_mutex_t lock;
+ int ctr;
int fd;
};
@@ -78,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 0d66ccc..c5108f7 100755
--- a/lib/fuse_lowlevel.c
+++ b/lib/fuse_lowlevel.c
@@ -134,6 +134,8 @@ void fuse_free_req(fuse_req_t req)
req->u.ni.data = NULL;
list_del_req(req);
ctr = --req->ctr;
+ fuse_chan_put(req->ch);
+ req->ch = NULL;
pthread_mutex_unlock(&f->lock);
if (!ctr)
destroy_req(req);
@@ -2538,7 +2540,7 @@ void fuse_session_process_buf(struct fuse_session *se,
req->ctx.uid = in->uid;
req->ctx.gid = in->gid;
req->ctx.pid = in->pid;
- req->ch = ch;
+ req->ch = fuse_chan_get(ch);
err = EIO;
if (!f->got_init) {
@@ -2655,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),
@@ -2691,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"
);
}
@@ -2735,8 +2739,7 @@ static void fuse_ll_destroy(struct fuse_ll *f)
void fuse_session_destroy(struct fuse_session *se)
{
fuse_ll_destroy(se->f);
- if (se->ch != NULL)
- fuse_chan_destroy(se->ch);
+ fuse_chan_put(se->ch);
free(se);
}
diff --git a/lib/fuse_session.c b/lib/fuse_session.c
index e919e73..42fe5c3 100644
--- a/lib/fuse_session.c
+++ b/lib/fuse_session.c
@@ -84,6 +84,8 @@ struct fuse_chan *fuse_chan_new(int fd)
memset(ch, 0, sizeof(*ch));
ch->fd = fd;
+ ch->ctr = 1;
+ fuse_mutex_init(&ch->lock);
return ch;
}
@@ -98,9 +100,30 @@ struct fuse_session *fuse_chan_session(struct fuse_chan *ch)
return ch->se;
}
-void fuse_chan_destroy(struct fuse_chan *ch)
+struct fuse_chan *fuse_chan_get(struct fuse_chan *ch)
{
- fuse_session_remove_chan(ch);
- fuse_chan_close(ch);
- free(ch);
+ assert(ch->ctr > 0);
+ pthread_mutex_lock(&ch->lock);
+ ch->ctr++;
+ pthread_mutex_unlock(&ch->lock);
+
+ return ch;
+}
+
+void fuse_chan_put(struct fuse_chan *ch)
+{
+ if (ch) {
+ pthread_mutex_lock(&ch->lock);
+ ch->ctr--;
+ if (!ch->ctr) {
+ pthread_mutex_unlock(&ch->lock);
+ fuse_session_remove_chan(ch);
+ fuse_chan_close(ch);
+ pthread_mutex_destroy(&ch->lock);
+ free(ch);
+ } else {
+ pthread_mutex_unlock(&ch->lock);
+ }
+
+ }
}
diff --git a/lib/helper.c b/lib/helper.c
index bfdc990..28c6310 100644
--- a/lib/helper.c
+++ b/lib/helper.c
@@ -243,8 +243,7 @@ void fuse_unmount(const char *mountpoint, struct fuse_chan *ch)
if (mountpoint) {
int fd = ch ? fuse_chan_clearfd(ch) : -1;
fuse_kern_unmount(mountpoint, fd);
- if (ch)
- fuse_chan_destroy(ch);
+ fuse_chan_put(ch);
}
}