aboutsummaryrefslogtreecommitdiff
path: root/lib
diff options
context:
space:
mode:
authorGravatar Miklos Szeredi <mszeredi@suse.cz>2015-09-29 17:51:32 +0200
committerGravatar Miklos Szeredi <mszeredi@suse.cz>2015-09-29 17:51:32 +0200
commit386b1b6e3d0fcf7e2dfd5473e867284410dfa624 (patch)
treed16206c9de6043e78f663b8cfadc835df2981f1e /lib
parent4ae8680e40b60d65029f4630c21ab182d3c79e8e (diff)
parenta5a00e9b7dd8c8dfef17523dccb3051e1f1dd5a2 (diff)
Merge branch 'clone_fd'
Diffstat (limited to 'lib')
-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
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);
}
}