aboutsummaryrefslogtreecommitdiffstats
path: root/lib/fuse_lowlevel.c
diff options
context:
space:
mode:
Diffstat (limited to 'lib/fuse_lowlevel.c')
-rw-r--r--[-rwxr-xr-x]lib/fuse_lowlevel.c209
1 files changed, 100 insertions, 109 deletions
diff --git a/lib/fuse_lowlevel.c b/lib/fuse_lowlevel.c
index 2a7c580..7acc206 100755..100644
--- a/lib/fuse_lowlevel.c
+++ b/lib/fuse_lowlevel.c
@@ -2,6 +2,9 @@
FUSE: Filesystem in Userspace
Copyright (C) 2001-2007 Miklos Szeredi <miklos@szeredi.hu>
+ Implementation of (most of) the low-level FUSE API. The session loop
+ functions are implemented in separate files.
+
This program can be distributed under the terms of the GNU LGPLv2.
See the file COPYING.LIB
*/
@@ -41,8 +44,7 @@
struct fuse_pollhandle {
uint64_t kh;
- struct fuse_chan *ch;
- struct fuse_ll *f;
+ struct fuse_session *se;
};
static size_t pagesize;
@@ -141,7 +143,7 @@ void fuse_free_req(fuse_req_t req)
destroy_req(req);
}
-static struct fuse_req *fuse_ll_alloc_req(struct fuse_ll *f)
+static struct fuse_req *fuse_ll_alloc_req(struct fuse_session *se)
{
struct fuse_req *req;
@@ -149,7 +151,8 @@ static struct fuse_req *fuse_ll_alloc_req(struct fuse_ll *f)
if (req == NULL) {
fprintf(stderr, "fuse: failed to allocate request\n");
} else {
- req->f = f;
+ req->f = se->f;
+ req->se = se;
req->ctr = 1;
list_init_req(req);
fuse_mutex_init(&req->lock);
@@ -158,18 +161,12 @@ static struct fuse_req *fuse_ll_alloc_req(struct fuse_ll *f)
return req;
}
-void fuse_chan_close(struct fuse_chan *ch)
-{
- int fd = ch->fd;
- if (fd != -1)
- close(fd);
-}
-
-
-static int fuse_send_msg(struct fuse_ll *f, struct fuse_chan *ch,
+/* Send data. If *ch* is NULL, send via session master fd */
+static int fuse_send_msg(struct fuse_session *se, struct fuse_chan *ch,
struct iovec *iov, int count)
{
struct fuse_out_header *out = iov[0].iov_base;
+ struct fuse_ll *f = se->f;
out->len = iov_length(iov, count);
if (f->debug) {
@@ -188,12 +185,11 @@ static int fuse_send_msg(struct fuse_ll *f, struct fuse_chan *ch,
}
}
- ssize_t res = writev(ch->fd, iov, count);
+ ssize_t res = writev(ch ? ch->fd : se->fd,
+ iov, count);
int err = errno;
if (res == -1) {
- struct fuse_session *se = fuse_chan_session(ch);
-
assert(se != NULL);
/* ENOENT means the operation was interrupted */
@@ -222,7 +218,7 @@ int fuse_send_reply_iov_nofree(fuse_req_t req, int error, struct iovec *iov,
iov[0].iov_base = &out;
iov[0].iov_len = sizeof(struct fuse_out_header);
- return fuse_send_msg(req->f, req->ch, iov, count);
+ return fuse_send_msg(req->se, req->ch, iov, count);
}
static int send_reply_iov(fuse_req_t req, int error, struct iovec *iov,
@@ -477,7 +473,8 @@ int fuse_reply_buf(fuse_req_t req, const char *buf, size_t size)
return send_reply_ok(req, buf, size);
}
-static int fuse_send_data_iov_fallback(struct fuse_ll *f, struct fuse_chan *ch,
+static int fuse_send_data_iov_fallback(struct fuse_session *se,
+ struct fuse_chan *ch,
struct iovec *iov, int iov_count,
struct fuse_bufvec *buf,
size_t len)
@@ -495,7 +492,7 @@ static int fuse_send_data_iov_fallback(struct fuse_ll *f, struct fuse_chan *ch,
iov[iov_count].iov_base = buf->buf[0].mem;
iov[iov_count].iov_len = len;
iov_count++;
- return fuse_send_msg(f, ch, iov, iov_count);
+ return fuse_send_msg(se, ch, iov, iov_count);
}
res = posix_memalign(&mbuf, pagesize, len);
@@ -513,7 +510,7 @@ static int fuse_send_data_iov_fallback(struct fuse_ll *f, struct fuse_chan *ch,
iov[iov_count].iov_base = mbuf;
iov[iov_count].iov_len = len;
iov_count++;
- res = fuse_send_msg(f, ch, iov, iov_count);
+ res = fuse_send_msg(se, ch, iov, iov_count);
free(mbuf);
return res;
@@ -613,7 +610,7 @@ static int read_back(int fd, char *buf, size_t len)
return 0;
}
-static int fuse_send_data_iov(struct fuse_ll *f, struct fuse_chan *ch,
+static int fuse_send_data_iov(struct fuse_session *se, struct fuse_chan *ch,
struct iovec *iov, int iov_count,
struct fuse_bufvec *buf, unsigned int flags)
{
@@ -621,6 +618,7 @@ static int fuse_send_data_iov(struct fuse_ll *f, struct fuse_chan *ch,
size_t len = fuse_buf_size(buf);
struct fuse_out_header *out = iov[0].iov_base;
struct fuse_ll_pipe *llp;
+ struct fuse_ll *f = se->f;
int splice_flags;
size_t pipesize;
size_t total_fd_size;
@@ -766,7 +764,7 @@ static int fuse_send_data_iov(struct fuse_ll *f, struct fuse_chan *ch,
iov[iov_count].iov_base = mbuf;
iov[iov_count].iov_len = len;
iov_count++;
- res = fuse_send_msg(f, ch, iov, iov_count);
+ res = fuse_send_msg(se, ch, iov, iov_count);
free(mbuf);
return res;
}
@@ -787,8 +785,8 @@ static int fuse_send_data_iov(struct fuse_ll *f, struct fuse_chan *ch,
(f->conn.want & FUSE_CAP_SPLICE_MOVE))
splice_flags |= SPLICE_F_MOVE;
- res = splice(llp->pipe[0], NULL,
- ch->fd, NULL, out->len, splice_flags);
+ res = splice(llp->pipe[0], NULL, ch ? ch->fd : se->fd,
+ NULL, out->len, splice_flags);
if (res == -1) {
res = -errno;
perror("fuse: splice from pipe");
@@ -807,17 +805,17 @@ clear_pipe:
return res;
fallback:
- return fuse_send_data_iov_fallback(f, ch, iov, iov_count, buf, len);
+ return fuse_send_data_iov_fallback(se, ch, iov, iov_count, buf, len);
}
#else
-static int fuse_send_data_iov(struct fuse_ll *f, struct fuse_chan *ch,
+static int fuse_send_data_iov(struct fuse_session *se, struct fuse_chan *ch,
struct iovec *iov, int iov_count,
struct fuse_bufvec *buf, unsigned int flags)
{
size_t len = fuse_buf_size(buf);
(void) flags;
- return fuse_send_data_iov_fallback(f, ch, iov, iov_count, buf, len);
+ return fuse_send_data_iov_fallback(se, ch, iov, iov_count, buf, len);
}
#endif
@@ -834,7 +832,7 @@ int fuse_reply_data(fuse_req_t req, struct fuse_bufvec *bufv,
out.unique = req->unique;
out.error = 0;
- res = fuse_send_data_iov(req->f, req->ch, iov, 1, bufv, flags);
+ res = fuse_send_data_iov(req->se, req->ch, iov, 1, bufv, flags);
if (res <= 0) {
fuse_free_req(req);
return res;
@@ -1072,7 +1070,7 @@ static void do_batch_forget(fuse_req_t req, fuse_ino_t nodeid,
struct fuse_forget_one *forget = &param[i];
struct fuse_req *dummy_req;
- dummy_req = fuse_ll_alloc_req(req->f);
+ dummy_req = fuse_ll_alloc_req(req->se);
if (dummy_req == NULL)
break;
@@ -1790,8 +1788,7 @@ static void do_poll(fuse_req_t req, fuse_ino_t nodeid, const void *inarg)
return;
}
ph->kh = arg->kh;
- ph->ch = req->ch;
- ph->f = req->f;
+ ph->se = req->se;
}
req->f->op.poll(req, nodeid, &fi, ph);
@@ -2079,12 +2076,12 @@ static void do_notify_reply(fuse_req_t req, fuse_ino_t nodeid,
nreq->reply(nreq, req, nodeid, inarg, buf);
}
-static int send_notify_iov(struct fuse_ll *f, struct fuse_chan *ch,
- int notify_code, struct iovec *iov, int count)
+static int send_notify_iov(struct fuse_session *se, int notify_code,
+ struct iovec *iov, int count)
{
struct fuse_out_header out;
- if (!f->got_init)
+ if (!se->f->got_init)
return -ENOTCONN;
out.unique = 0;
@@ -2092,7 +2089,7 @@ static int send_notify_iov(struct fuse_ll *f, struct fuse_chan *ch,
iov[0].iov_base = &out;
iov[0].iov_len = sizeof(struct fuse_out_header);
- return fuse_send_msg(f, ch, iov, count);
+ return fuse_send_msg(se, NULL, iov, count);
}
int fuse_lowlevel_notify_poll(struct fuse_pollhandle *ph)
@@ -2106,7 +2103,7 @@ int fuse_lowlevel_notify_poll(struct fuse_pollhandle *ph)
iov[1].iov_base = &outarg;
iov[1].iov_len = sizeof(outarg);
- return send_notify_iov(ph->f, ph->ch, FUSE_NOTIFY_POLL, iov, 2);
+ return send_notify_iov(ph->se, FUSE_NOTIFY_POLL, iov, 2);
} else {
return 0;
}
@@ -2133,7 +2130,7 @@ int fuse_lowlevel_notify_inval_inode(struct fuse_session *se, fuse_ino_t ino,
iov[1].iov_base = &outarg;
iov[1].iov_len = sizeof(outarg);
- return send_notify_iov(f, se->ch, FUSE_NOTIFY_INVAL_INODE, iov, 2);
+ return send_notify_iov(se, FUSE_NOTIFY_INVAL_INODE, iov, 2);
}
int fuse_lowlevel_notify_inval_entry(struct fuse_session *se, fuse_ino_t parent,
@@ -2159,7 +2156,7 @@ int fuse_lowlevel_notify_inval_entry(struct fuse_session *se, fuse_ino_t parent,
iov[2].iov_base = (void *)name;
iov[2].iov_len = namelen + 1;
- return send_notify_iov(f, se->ch, FUSE_NOTIFY_INVAL_ENTRY, iov, 3);
+ return send_notify_iov(se, FUSE_NOTIFY_INVAL_ENTRY, iov, 3);
}
int fuse_lowlevel_notify_delete(struct fuse_session *se,
@@ -2190,7 +2187,7 @@ int fuse_lowlevel_notify_delete(struct fuse_session *se,
iov[2].iov_base = (void *)name;
iov[2].iov_len = namelen + 1;
- return send_notify_iov(f, se->ch, FUSE_NOTIFY_DELETE, iov, 3);
+ return send_notify_iov(se, FUSE_NOTIFY_DELETE, iov, 3);
}
int fuse_lowlevel_notify_store(struct fuse_session *se, fuse_ino_t ino,
@@ -2227,7 +2224,7 @@ int fuse_lowlevel_notify_store(struct fuse_session *se, fuse_ino_t ino,
iov[1].iov_base = &outarg;
iov[1].iov_len = sizeof(outarg);
- res = fuse_send_data_iov(f, se->ch, iov, 2, bufv, flags);
+ res = fuse_send_data_iov(se, NULL, iov, 2, bufv, flags);
if (res > 0)
res = -res;
@@ -2316,7 +2313,7 @@ int fuse_lowlevel_notify_retrieve(struct fuse_session *se, fuse_ino_t ino,
iov[1].iov_base = &outarg;
iov[1].iov_len = sizeof(outarg);
- err = send_notify_iov(f, se->ch, FUSE_NOTIFY_RETRIEVE, iov, 2);
+ err = send_notify_iov(se, FUSE_NOTIFY_RETRIEVE, iov, 2);
if (err) {
pthread_mutex_lock(&f->lock);
list_del_nreq(&rreq->nreq);
@@ -2439,7 +2436,7 @@ static int fuse_ll_copy_from_pipe(struct fuse_bufvec *dst,
void fuse_session_process_buf(struct fuse_session *se,
const struct fuse_buf *buf)
{
- fuse_session_process_buf_int(se, buf, se->ch);
+ fuse_session_process_buf_int(se, buf, NULL);
}
void fuse_session_process_buf_int(struct fuse_session *se,
@@ -2485,7 +2482,7 @@ void fuse_session_process_buf_int(struct fuse_session *se,
(unsigned long long) in->nodeid, buf->size, in->pid);
}
- req = fuse_ll_alloc_req(f);
+ req = fuse_ll_alloc_req(se);
if (req == NULL) {
struct fuse_out_header out = {
.unique = in->unique,
@@ -2496,7 +2493,7 @@ void fuse_session_process_buf_int(struct fuse_session *se,
.iov_len = sizeof(struct fuse_out_header),
};
- fuse_send_msg(f, ch, &iov, 1);
+ fuse_send_msg(se, ch, &iov, 1);
goto clear_pipe;
}
@@ -2504,7 +2501,7 @@ void fuse_session_process_buf_int(struct fuse_session *se,
req->ctx.uid = in->uid;
req->ctx.gid = in->gid;
req->ctx.pid = in->pid;
- req->ch = fuse_chan_get(ch);
+ req->ch = ch ? fuse_chan_get(ch) : NULL;
err = EIO;
if (!f->got_init) {
@@ -2581,11 +2578,6 @@ clear_pipe:
goto out_free;
}
-enum {
- KEY_HELP,
- KEY_VERSION,
-};
-
static const struct fuse_opt fuse_ll_opts[] = {
{ "debug", offsetof(struct fuse_ll, debug), 1 },
{ "-d", offsetof(struct fuse_ll, debug), 1 },
@@ -2622,23 +2614,19 @@ static const struct fuse_opt fuse_ll_opts[] = {
{ "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),
- FUSE_OPT_KEY("-V", KEY_VERSION),
- FUSE_OPT_KEY("--version", KEY_VERSION),
FUSE_OPT_END
};
-static void fuse_ll_version(void)
+void fuse_lowlevel_version(void)
{
printf("using FUSE kernel interface version %i.%i\n",
FUSE_KERNEL_VERSION, FUSE_KERNEL_MINOR_VERSION);
}
-static void fuse_ll_help(void)
+void fuse_lowlevel_help(void)
{
printf(
+"Low-level options\n"
" -o max_write=N set maximum size of write requests\n"
" -o max_readahead=N set maximum readahead\n"
" -o max_background=N set number of maximum background requests\n"
@@ -2658,32 +2646,16 @@ 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"
-);
+" -o clone_fd clone fuse device file descriptors\n\n");
}
static int fuse_ll_opt_proc(void *data, const char *arg, int key,
struct fuse_args *outargs)
{
- (void) data; (void) outargs; (void) arg;
-
- switch (key) {
- case KEY_HELP:
- fuse_ll_help();
- fuse_mount_help();
- break;
-
- case KEY_VERSION:
- fuse_ll_version();
- fuse_mount_version();
- break;
-
- default:
- fprintf(stderr, "fuse: unknown option `%s'\n", arg);
- }
+ (void) data; (void) outargs; (void) key; (void) arg;
- /* Fail */
- return -1;
+ /* Passthrough unknown options */
+ return 1;
}
static void fuse_ll_destroy(struct fuse_ll *f)
@@ -2706,7 +2678,7 @@ static void fuse_ll_destroy(struct fuse_ll *f)
void fuse_session_destroy(struct fuse_session *se)
{
fuse_ll_destroy(se->f);
- fuse_chan_put(se->ch);
+ close(se->fd);
destroy_mount_opts(se->mo);
free(se);
}
@@ -2720,7 +2692,7 @@ static void fuse_ll_pipe_destructor(void *data)
int fuse_session_receive_buf(struct fuse_session *se, struct fuse_buf *buf)
{
- return fuse_session_receive_buf_int(se, buf, se->ch);
+ return fuse_session_receive_buf_int(se, buf, NULL);
}
int fuse_session_receive_buf_int(struct fuse_session *se, struct fuse_buf *buf,
@@ -2754,7 +2726,8 @@ int fuse_session_receive_buf_int(struct fuse_session *se, struct fuse_buf *buf,
goto fallback;
}
- res = splice(ch->fd, NULL, llp->pipe[1], NULL, bufsize, 0);
+ res = splice(ch ? ch->fd : se->fd,
+ NULL, llp->pipe[1], NULL, bufsize, 0);
err = errno;
if (fuse_session_exited(se))
@@ -2838,7 +2811,7 @@ fallback:
}
restart:
- res = read(ch->fd, buf->mem, f->bufsize);
+ res = read(ch ? ch->fd : se->fd, buf->mem, f->bufsize);
err = errno;
if (fuse_session_exited(se))
@@ -2889,15 +2862,23 @@ struct fuse_session *fuse_session_new(struct fuse_args *args,
f = (struct fuse_ll *) calloc(1, sizeof(struct fuse_ll));
if (f == NULL) {
fprintf(stderr, "fuse: failed to allocate fuse object\n");
- goto out;
+ goto out1;
}
/* Parse options */
mo = parse_mount_opts(args);
if (mo == NULL)
- goto out_free0;
- if (fuse_opt_parse(args, f, fuse_ll_opts, fuse_ll_opt_proc) == -1)
- goto out_free;
+ goto out2;
+ if(fuse_opt_parse(args, f, fuse_ll_opts, fuse_ll_opt_proc) == -1)
+ goto out3;
+ if (args->argc != 1) {
+ int i;
+ fprintf(stderr, "fuse: unknown option(s): `");
+ for(i = 1; i < args->argc-1; i++)
+ fprintf(stderr, "%s ", args->argv[i]);
+ fprintf(stderr, "%s'\n", args->argv[i]);
+ goto out4;
+ }
if (f->debug)
fprintf(stderr, "FUSE library version: %s\n", PACKAGE_VERSION);
@@ -2919,7 +2900,7 @@ struct fuse_session *fuse_session_new(struct fuse_args *args,
if (err) {
fprintf(stderr, "fuse: failed to create thread specific key: %s\n",
strerror(err));
- goto out_free;
+ goto out5;
}
memcpy(&f->op, op, op_size);
@@ -2929,27 +2910,29 @@ struct fuse_session *fuse_session_new(struct fuse_args *args,
se = (struct fuse_session *) malloc(sizeof(*se));
if (se == NULL) {
fprintf(stderr, "fuse: failed to allocate session\n");
- goto out_key_destroy;
+ goto out6;
}
memset(se, 0, sizeof(*se));
se->f = f;
se->mo = mo;
return se;
-out_key_destroy:
+out6:
pthread_key_delete(f->pipe_key);
-out_free:
- free(mo);
-out_free0:
+out5:
pthread_mutex_destroy(&f->lock);
+out4:
+ fuse_opt_free_args(args);
+out3:
+ free(mo);
+out2:
free(f);
-out:
+out1:
return NULL;
}
int fuse_session_mount(struct fuse_session *se, const char *mountpoint)
{
- struct fuse_chan *ch;
int fd;
/*
@@ -2966,13 +2949,7 @@ int fuse_session_mount(struct fuse_session *se, const char *mountpoint)
fd = fuse_kern_mount(mountpoint, se->mo);
if (fd == -1)
return -1;
-
- ch = fuse_chan_new(fd);
- if (!ch)
- goto error_out;
-
- /* Add channel to session */
- fuse_session_add_chan(se, ch);
+ se->fd = fd;
/* Save mountpoint */
se->mountpoint = strdup(mountpoint);
@@ -2986,17 +2963,16 @@ error_out:
return -1;
}
+int fuse_session_fd(struct fuse_session *se)
+{
+ return se->fd;
+}
+
void fuse_session_unmount(struct fuse_session *se)
{
- struct fuse_chan *ch = se->ch;
- fuse_session_remove_chan(ch);
- if (se->mountpoint) {
- int fd = ch ? fuse_chan_clearfd(ch) : -1;
- fuse_kern_unmount(se->mountpoint, fd);
- fuse_chan_put(ch);
- free(se->mountpoint);
- se->mountpoint = NULL;
- }
+ fuse_kern_unmount(se->mountpoint, se->fd);
+ free(se->mountpoint);
+ se->mountpoint = NULL;
}
#ifdef linux
@@ -3067,3 +3043,18 @@ int fuse_req_getgroups(fuse_req_t req, int size, gid_t list[])
return -ENOSYS;
}
#endif
+
+void fuse_session_exit(struct fuse_session *se)
+{
+ se->exited = 1;
+}
+
+void fuse_session_reset(struct fuse_session *se)
+{
+ se->exited = 0;
+}
+
+int fuse_session_exited(struct fuse_session *se)
+{
+ return se->exited;
+}