diff options
author | Miklos Szeredi <mszeredi@suse.cz> | 2015-09-29 17:51:32 +0200 |
---|---|---|
committer | Miklos Szeredi <mszeredi@suse.cz> | 2015-09-29 17:51:32 +0200 |
commit | 386b1b6e3d0fcf7e2dfd5473e867284410dfa624 (patch) | |
tree | d16206c9de6043e78f663b8cfadc835df2981f1e /lib | |
parent | 4ae8680e40b60d65029f4630c21ab182d3c79e8e (diff) | |
parent | a5a00e9b7dd8c8dfef17523dccb3051e1f1dd5a2 (diff) |
Merge branch 'clone_fd'
Diffstat (limited to 'lib')
-rw-r--r-- | lib/fuse_i.h | 3 | ||||
-rwxr-xr-x | lib/fuse_loop_mt.c | 55 | ||||
-rwxr-xr-x | lib/fuse_lowlevel.c | 9 | ||||
-rw-r--r-- | lib/fuse_session.c | 31 | ||||
-rw-r--r-- | lib/helper.c | 3 |
5 files changed, 90 insertions, 11 deletions
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); } } |