mirror of
https://github.com/openharmony/third_party_libfuse.git
synced 2026-07-18 10:34:54 -04:00
cleanup
This commit is contained in:
@@ -1,3 +1,8 @@
|
||||
2005-08-15 Miklos Szeredi <miklos@szeredi.hu>
|
||||
|
||||
* lib: cleaned up (or messed up, depending on your POV) the low
|
||||
level library API. Hopefully this is close to the final form.
|
||||
|
||||
2005-08-05 Miklos Szeredi <miklos@szeredi.hu>
|
||||
|
||||
* fusermount: don't allow empty mountpoint argument, which defeats
|
||||
|
||||
+12
-6
@@ -134,7 +134,7 @@ static void hello_ll_read(fuse_req_t req, fuse_ino_t ino, size_t size,
|
||||
reply_buf_limited(req, hello_str, strlen(hello_str), off, size);
|
||||
}
|
||||
|
||||
static struct fuse_ll_operations hello_ll_oper = {
|
||||
static struct fuse_lowlevel_ops hello_ll_oper = {
|
||||
.lookup = hello_ll_lookup,
|
||||
.getattr = hello_ll_getattr,
|
||||
.readdir = hello_ll_readdir,
|
||||
@@ -145,7 +145,6 @@ static struct fuse_ll_operations hello_ll_oper = {
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
const char *mountpoint;
|
||||
struct fuse_ll *f;
|
||||
int err = -1;
|
||||
int fd;
|
||||
|
||||
@@ -156,10 +155,17 @@ int main(int argc, char *argv[])
|
||||
mountpoint = argv[1];
|
||||
fd = fuse_mount(mountpoint, NULL);
|
||||
if (fd != -1) {
|
||||
f = fuse_ll_new(fd, "debug", &hello_ll_oper, sizeof(hello_ll_oper), NULL);
|
||||
if (f != NULL) {
|
||||
err = fuse_ll_loop(f);
|
||||
fuse_ll_destroy(f);
|
||||
struct fuse_session *se;
|
||||
|
||||
se = fuse_lowlevel_new("debug", &hello_ll_oper, sizeof(hello_ll_oper),
|
||||
NULL);
|
||||
if (se != NULL) {
|
||||
struct fuse_chan *ch = fuse_kern_chan_new(fd);
|
||||
if (ch != NULL) {
|
||||
fuse_session_add_chan(se, ch);
|
||||
err = fuse_session_loop(se);
|
||||
}
|
||||
fuse_session_destroy(se);
|
||||
}
|
||||
close(fd);
|
||||
}
|
||||
|
||||
+8
-1
@@ -1,6 +1,13 @@
|
||||
## Process this file with automake to produce Makefile.in
|
||||
|
||||
fuseincludedir=$(includedir)/fuse
|
||||
fuseinclude_HEADERS = fuse.h fuse_compat.h fuse_common.h fuse_lowlevel.h
|
||||
|
||||
fuseinclude_HEADERS = \
|
||||
fuse.h \
|
||||
fuse_compat.h \
|
||||
fuse_common.h \
|
||||
fuse_lowlevel.h
|
||||
|
||||
include_HEADERS = old/fuse.h
|
||||
|
||||
noinst_HEADERS = fuse_kernel.h
|
||||
|
||||
+8
-2
@@ -34,6 +34,12 @@ extern "C" {
|
||||
/** Handle for a FUSE filesystem */
|
||||
struct fuse;
|
||||
|
||||
/** Structure containing a raw command */
|
||||
struct fuse_cmd;
|
||||
|
||||
/** The lowlevel FUSE session */
|
||||
struct fuse_session;
|
||||
|
||||
/** Function to add an entry in a readdir() operation
|
||||
*
|
||||
* @param buf the buffer passed to the readdir() operation
|
||||
@@ -504,8 +510,8 @@ int fuse_exited(struct fuse *f);
|
||||
/** Set function which can be used to get the current context */
|
||||
void fuse_set_getcontext_func(struct fuse_context *(*func)(void));
|
||||
|
||||
/** Returns the lowlevel FUSE object */
|
||||
struct fuse_ll *fuse_get_lowlevel(struct fuse *f);
|
||||
/** Returns the lowlevel FUSE session */
|
||||
struct fuse_session *fuse_get_session(struct fuse *f);
|
||||
|
||||
/* ----------------------------------------------------------- *
|
||||
* Compatibility stuff *
|
||||
|
||||
@@ -53,7 +53,4 @@ struct fuse_file_info {
|
||||
unsigned int keep_cache : 1;
|
||||
};
|
||||
|
||||
/** Structure containing a raw command */
|
||||
struct fuse_cmd;
|
||||
|
||||
#endif /* _FUSE_COMMON_H_ */
|
||||
|
||||
+63
-16
@@ -19,6 +19,7 @@
|
||||
#include <sys/types.h>
|
||||
#include <sys/stat.h>
|
||||
#include <sys/statfs.h>
|
||||
#include <sys/uio.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
@@ -29,7 +30,9 @@ extern "C" {
|
||||
|
||||
typedef unsigned long fuse_ino_t;
|
||||
typedef struct fuse_req *fuse_req_t;
|
||||
struct fuse_ll;
|
||||
|
||||
struct fuse_session;
|
||||
struct fuse_chan;
|
||||
|
||||
struct fuse_entry_param {
|
||||
fuse_ino_t ino;
|
||||
@@ -69,8 +72,8 @@ struct fuse_ctx {
|
||||
|
||||
/* ------------------------------------------ */
|
||||
|
||||
struct fuse_ll_operations {
|
||||
void* (*init) (void *);
|
||||
struct fuse_lowlevel_ops {
|
||||
void (*init) (void *);
|
||||
void (*destroy)(void *);
|
||||
|
||||
void (*lookup) (fuse_req_t req, fuse_ino_t parent, const char *name);
|
||||
@@ -174,29 +177,73 @@ const struct fuse_ctx *fuse_req_ctx(fuse_req_t req);
|
||||
|
||||
/* ------------------------------------------ */
|
||||
|
||||
typedef void (*fuse_ll_processor_t)(struct fuse_ll *, struct fuse_cmd *, void *);
|
||||
int fuse_lowlevel_is_lib_option(const char *opt);
|
||||
|
||||
struct fuse_ll *fuse_ll_new(int fd, const char *opts,
|
||||
const struct fuse_ll_operations *op,
|
||||
size_t op_size, void *userdata);
|
||||
struct fuse_session *fuse_lowlevel_new(const char *opts,
|
||||
const struct fuse_lowlevel_ops *op,
|
||||
size_t op_size, void *userdata);
|
||||
|
||||
void fuse_ll_destroy(struct fuse_ll *f);
|
||||
struct fuse_chan *fuse_kern_chan_new(int fd);
|
||||
|
||||
int fuse_ll_is_lib_option(const char *opt);
|
||||
/* ------------------------------------------ */
|
||||
|
||||
int fuse_ll_loop(struct fuse_ll *f);
|
||||
struct fuse_session_ops {
|
||||
void (*process) (void *data, const char *buf, size_t len,
|
||||
struct fuse_chan *ch);
|
||||
|
||||
void (*destroy) (void *data);
|
||||
};
|
||||
|
||||
void fuse_ll_exit(struct fuse_ll *f);
|
||||
struct fuse_session *fuse_session_new(struct fuse_session_ops *op, void *data);
|
||||
|
||||
int fuse_ll_exited(struct fuse_ll* f);
|
||||
void fuse_session_add_chan(struct fuse_session *se, struct fuse_chan *ch);
|
||||
|
||||
struct fuse_cmd *fuse_ll_read_cmd(struct fuse_ll *f);
|
||||
struct fuse_chan *fuse_session_next_chan(struct fuse_session *se,
|
||||
struct fuse_chan *ch);
|
||||
|
||||
void fuse_ll_process_cmd(struct fuse_ll *f, struct fuse_cmd *cmd);
|
||||
void fuse_session_process(struct fuse_session *se, const char *buf, size_t len,
|
||||
struct fuse_chan *ch);
|
||||
|
||||
int fuse_ll_loop_mt(struct fuse_ll *f);
|
||||
void fuse_session_destroy(struct fuse_session *se);
|
||||
|
||||
int fuse_ll_loop_mt_proc(struct fuse_ll *f, fuse_ll_processor_t proc, void *data);
|
||||
void fuse_session_exit(struct fuse_session *se);
|
||||
|
||||
void fuse_session_reset(struct fuse_session *se);
|
||||
|
||||
int fuse_session_exited(struct fuse_session *se);
|
||||
|
||||
int fuse_session_loop(struct fuse_session *se);
|
||||
|
||||
int fuse_session_loop_mt(struct fuse_session *se);
|
||||
|
||||
/* ------------------------------------------ */
|
||||
|
||||
struct fuse_chan_ops {
|
||||
int (*receive)(struct fuse_chan *ch, char *buf, size_t size);
|
||||
|
||||
int (*send)(struct fuse_chan *ch, const struct iovec iov[],
|
||||
size_t count);
|
||||
|
||||
void (*destroy)(struct fuse_chan *ch);
|
||||
};
|
||||
|
||||
struct fuse_chan *fuse_chan_new(struct fuse_chan_ops *op, int fd,
|
||||
size_t bufsize, void *data);
|
||||
|
||||
int fuse_chan_fd(struct fuse_chan *ch);
|
||||
|
||||
size_t fuse_chan_bufsize(struct fuse_chan *ch);
|
||||
|
||||
void *fuse_chan_data(struct fuse_chan *ch);
|
||||
|
||||
struct fuse_session *fuse_chan_session(struct fuse_chan *ch);
|
||||
|
||||
int fuse_chan_receive(struct fuse_chan *ch, char *buf, size_t size);
|
||||
|
||||
int fuse_chan_send(struct fuse_chan *ch, const struct iovec iov[],
|
||||
size_t count);
|
||||
|
||||
void fuse_chan_destroy(struct fuse_chan *ch);
|
||||
|
||||
/* ------------------------------------------ */
|
||||
|
||||
|
||||
+6
-4
@@ -4,12 +4,14 @@ lib_LTLIBRARIES = libfuse.la
|
||||
|
||||
libfuse_la_SOURCES = \
|
||||
fuse.c \
|
||||
fuse_mt.c \
|
||||
fuse_kern_chan.c \
|
||||
fuse_loop.c \
|
||||
fuse_loop_mt.c \
|
||||
fuse_lowlevel.c \
|
||||
fuse_lowlevel_mt.c \
|
||||
fuse_mt.c \
|
||||
fuse_session.c \
|
||||
helper.c \
|
||||
mount.c \
|
||||
fuse_lowlevel_i.h
|
||||
mount.c
|
||||
|
||||
libfuse_la_LDFLAGS = -lpthread -version-number 2:4:0 \
|
||||
-Wl,--version-script,fuse_versionscript
|
||||
|
||||
+67
-21
@@ -63,7 +63,7 @@
|
||||
#define FUSE_MAX_PATH 4096
|
||||
|
||||
struct fuse {
|
||||
struct fuse_ll *fll;
|
||||
struct fuse_session *se;
|
||||
int flags;
|
||||
struct fuse_operations op;
|
||||
int compat;
|
||||
@@ -110,6 +110,11 @@ struct fuse_dirhandle {
|
||||
fuse_ino_t nodeid;
|
||||
};
|
||||
|
||||
struct fuse_cmd {
|
||||
char *buf;
|
||||
size_t buflen;
|
||||
};
|
||||
|
||||
static struct fuse_context *(*fuse_getcontext)(void) = NULL;
|
||||
|
||||
#ifndef USE_UCLIBC
|
||||
@@ -561,14 +566,12 @@ static void reply_entry(fuse_req_t req, const struct fuse_entry_param *e,
|
||||
reply_err(req, err);
|
||||
}
|
||||
|
||||
static void *fuse_data_init(void *data)
|
||||
static void fuse_data_init(void *data)
|
||||
{
|
||||
struct fuse *f = (struct fuse *) data;
|
||||
|
||||
if (f->op.init)
|
||||
f->user_data = f->op.init();
|
||||
|
||||
return f;
|
||||
}
|
||||
|
||||
static void fuse_data_destroy(void *data)
|
||||
@@ -1599,7 +1602,7 @@ static void fuse_removexattr(fuse_req_t req, fuse_ino_t ino, const char *name)
|
||||
reply_err(req, err);
|
||||
}
|
||||
|
||||
static struct fuse_ll_operations fuse_path_ops = {
|
||||
static struct fuse_lowlevel_ops fuse_path_ops = {
|
||||
.init = fuse_data_init,
|
||||
.destroy = fuse_data_destroy,
|
||||
.lookup = fuse_lookup,
|
||||
@@ -1632,25 +1635,64 @@ static struct fuse_ll_operations fuse_path_ops = {
|
||||
.removexattr = fuse_removexattr,
|
||||
};
|
||||
|
||||
static void free_cmd(struct fuse_cmd *cmd)
|
||||
{
|
||||
free(cmd->buf);
|
||||
free(cmd);
|
||||
}
|
||||
|
||||
void fuse_process_cmd(struct fuse *f, struct fuse_cmd *cmd)
|
||||
{
|
||||
fuse_ll_process_cmd(f->fll, cmd);
|
||||
struct fuse_chan *ch = fuse_session_next_chan(f->se, NULL);
|
||||
fuse_session_process(f->se, cmd->buf, cmd->buflen, ch);
|
||||
}
|
||||
|
||||
int fuse_exited(struct fuse *f)
|
||||
{
|
||||
return fuse_ll_exited(f->fll);
|
||||
return fuse_session_exited(f->se);
|
||||
}
|
||||
|
||||
struct fuse_session *fuse_get_session(struct fuse *f)
|
||||
{
|
||||
return f->se;
|
||||
}
|
||||
|
||||
static struct fuse_cmd *fuse_alloc_cmd(size_t bufsize)
|
||||
{
|
||||
struct fuse_cmd *cmd = (struct fuse_cmd *) malloc(sizeof(*cmd));
|
||||
if (cmd == NULL) {
|
||||
fprintf(stderr, "fuse: failed to allocate cmd\n");
|
||||
return NULL;
|
||||
}
|
||||
cmd->buf = (char *) malloc(bufsize);
|
||||
if (cmd->buf == NULL) {
|
||||
fprintf(stderr, "fuse: failed to allocate read buffer\n");
|
||||
free(cmd);
|
||||
return NULL;
|
||||
}
|
||||
return cmd;
|
||||
}
|
||||
|
||||
struct fuse_cmd *fuse_read_cmd(struct fuse *f)
|
||||
{
|
||||
return fuse_ll_read_cmd(f->fll);
|
||||
struct fuse_chan *ch = fuse_session_next_chan(f->se, NULL);
|
||||
size_t bufsize = fuse_chan_bufsize(ch);
|
||||
struct fuse_cmd *cmd = fuse_alloc_cmd(bufsize);
|
||||
if (cmd != NULL) {
|
||||
int res = fuse_chan_receive(ch, cmd->buf, bufsize);
|
||||
if (res <= 0) {
|
||||
free_cmd(cmd);
|
||||
return NULL;
|
||||
}
|
||||
cmd->buflen = res;
|
||||
}
|
||||
return cmd;
|
||||
}
|
||||
|
||||
int fuse_loop(struct fuse *f)
|
||||
{
|
||||
if (f)
|
||||
return fuse_ll_loop(f->fll);
|
||||
return fuse_session_loop(f->se);
|
||||
else
|
||||
return -1;
|
||||
}
|
||||
@@ -1664,7 +1706,7 @@ int fuse_invalidate(struct fuse *f, const char *path)
|
||||
|
||||
void fuse_exit(struct fuse *f)
|
||||
{
|
||||
fuse_ll_exit(f->fll);
|
||||
fuse_session_exit(f->se);
|
||||
}
|
||||
|
||||
struct fuse_context *fuse_get_context()
|
||||
@@ -1681,11 +1723,6 @@ void fuse_set_getcontext_func(struct fuse_context *(*func)(void))
|
||||
fuse_getcontext = func;
|
||||
}
|
||||
|
||||
struct fuse_ll *fuse_get_lowlevel(struct fuse *f)
|
||||
{
|
||||
return f->fll;
|
||||
}
|
||||
|
||||
static int begins_with(const char *s, const char *beg)
|
||||
{
|
||||
if (strncmp(s, beg, strlen(beg)) == 0)
|
||||
@@ -1696,7 +1733,7 @@ static int begins_with(const char *s, const char *beg)
|
||||
|
||||
int fuse_is_lib_option(const char *opt)
|
||||
{
|
||||
if (fuse_ll_is_lib_option(opt) ||
|
||||
if (fuse_lowlevel_is_lib_option(opt) ||
|
||||
strcmp(opt, "debug") == 0 ||
|
||||
strcmp(opt, "hard_remove") == 0 ||
|
||||
strcmp(opt, "use_ino") == 0 ||
|
||||
@@ -1728,7 +1765,7 @@ static int parse_lib_opts(struct fuse *f, const char *opts, char **llopts)
|
||||
}
|
||||
|
||||
while((opt = strsep(&s, ","))) {
|
||||
if (fuse_ll_is_lib_option(opt)) {
|
||||
if (fuse_lowlevel_is_lib_option(opt)) {
|
||||
size_t optlen = strlen(opt);
|
||||
if (strcmp(opt, "debug") == 0)
|
||||
f->flags |= FUSE_DEBUG;
|
||||
@@ -1772,6 +1809,7 @@ struct fuse *fuse_new_common(int fd, const char *opts,
|
||||
const struct fuse_operations *op,
|
||||
size_t op_size, int compat)
|
||||
{
|
||||
struct fuse_chan *ch;
|
||||
struct fuse *f;
|
||||
struct node *root;
|
||||
char *llopts = NULL;
|
||||
@@ -1793,10 +1831,16 @@ struct fuse *fuse_new_common(int fd, const char *opts,
|
||||
if (parse_lib_opts(f, opts, &llopts) == -1)
|
||||
goto out_free;
|
||||
|
||||
f->fll = fuse_ll_new(fd, llopts, &fuse_path_ops, sizeof(fuse_path_ops), f);
|
||||
f->se = fuse_lowlevel_new(llopts, &fuse_path_ops, sizeof(fuse_path_ops), f);
|
||||
free(llopts);
|
||||
if (f->fll == NULL)
|
||||
if (f->se == NULL)
|
||||
goto out_free;
|
||||
|
||||
ch = fuse_kern_chan_new(fd);
|
||||
if (ch == NULL)
|
||||
goto out_free_session;
|
||||
|
||||
fuse_session_add_chan(f->se, ch);
|
||||
|
||||
f->ctr = 0;
|
||||
f->generation = 0;
|
||||
@@ -1806,7 +1850,7 @@ struct fuse *fuse_new_common(int fd, const char *opts,
|
||||
calloc(1, sizeof(struct node *) * f->name_table_size);
|
||||
if (f->name_table == NULL) {
|
||||
fprintf(stderr, "fuse: memory allocation failed\n");
|
||||
goto out_free;
|
||||
goto out_free_session;
|
||||
}
|
||||
|
||||
f->id_table_size = 14057;
|
||||
@@ -1848,6 +1892,8 @@ struct fuse *fuse_new_common(int fd, const char *opts,
|
||||
free(f->id_table);
|
||||
out_free_name_table:
|
||||
free(f->name_table);
|
||||
out_free_session:
|
||||
fuse_session_destroy(f->se);
|
||||
out_free:
|
||||
free(f);
|
||||
out:
|
||||
@@ -1905,7 +1951,7 @@ void fuse_destroy(struct fuse *f)
|
||||
free(f->id_table);
|
||||
free(f->name_table);
|
||||
pthread_mutex_destroy(&f->lock);
|
||||
fuse_ll_destroy(f->fll);
|
||||
fuse_session_destroy(f->se);
|
||||
free(f);
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,73 @@
|
||||
/*
|
||||
FUSE: Filesystem in Userspace
|
||||
Copyright (C) 2001-2005 Miklos Szeredi <miklos@szeredi.hu>
|
||||
|
||||
This program can be distributed under the terms of the GNU LGPL.
|
||||
See the file COPYING.LIB
|
||||
*/
|
||||
|
||||
#include "fuse_lowlevel.h"
|
||||
#include "fuse_kernel.h"
|
||||
|
||||
#include <stdio.h>
|
||||
#include <errno.h>
|
||||
#include <unistd.h>
|
||||
#include <assert.h>
|
||||
|
||||
static int fuse_kern_chan_receive(struct fuse_chan *ch, char *buf, size_t size)
|
||||
{
|
||||
ssize_t res = read(fuse_chan_fd(ch), buf, size);
|
||||
struct fuse_session *se = fuse_chan_session(ch);
|
||||
|
||||
assert(se != NULL);
|
||||
if (fuse_session_exited(se))
|
||||
return 0;
|
||||
if (res == -1) {
|
||||
/* EINTR means, the read() was interrupted, ENOENT means the
|
||||
operation was interrupted */
|
||||
if (errno == EINTR || errno == ENOENT)
|
||||
return 0;
|
||||
/* ENODEV means we got unmounted, so we silenty return failure */
|
||||
if (errno != ENODEV)
|
||||
perror("fuse: reading device");
|
||||
return -1;
|
||||
}
|
||||
if ((size_t) res < sizeof(struct fuse_in_header)) {
|
||||
fprintf(stderr, "short read on fuse device\n");
|
||||
return -1;
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
static int fuse_kern_chan_send(struct fuse_chan *ch, const struct iovec iov[],
|
||||
size_t count)
|
||||
{
|
||||
ssize_t res = writev(fuse_chan_fd(ch), iov, count);
|
||||
|
||||
if (res == -1) {
|
||||
struct fuse_session *se = fuse_chan_session(ch);
|
||||
|
||||
assert(se != NULL);
|
||||
|
||||
/* ENOENT means the operation was interrupted */
|
||||
if (!fuse_session_exited(se) && errno != ENOENT)
|
||||
perror("fuse: writing device");
|
||||
return -errno;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void fuse_kern_chan_destroy(struct fuse_chan *ch)
|
||||
{
|
||||
close(fuse_chan_fd(ch));
|
||||
}
|
||||
|
||||
struct fuse_chan *fuse_kern_chan_new(int fd)
|
||||
{
|
||||
struct fuse_chan_ops op = {
|
||||
.receive = fuse_kern_chan_receive,
|
||||
.send = fuse_kern_chan_send,
|
||||
.destroy = fuse_kern_chan_destroy,
|
||||
};
|
||||
return fuse_chan_new(&op, fd, FUSE_MAX_IN, NULL);
|
||||
}
|
||||
@@ -0,0 +1,38 @@
|
||||
/*
|
||||
FUSE: Filesystem in Userspace
|
||||
Copyright (C) 2001-2005 Miklos Szeredi <miklos@szeredi.hu>
|
||||
|
||||
This program can be distributed under the terms of the GNU LGPL.
|
||||
See the file COPYING.LIB
|
||||
*/
|
||||
|
||||
#include "fuse_lowlevel.h"
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
int fuse_session_loop(struct fuse_session *se)
|
||||
{
|
||||
int res = 0;
|
||||
struct fuse_chan *ch = fuse_session_next_chan(se, NULL);
|
||||
size_t bufsize = fuse_chan_bufsize(ch);
|
||||
char *buf = (char *) malloc(bufsize);
|
||||
if (!buf) {
|
||||
fprintf(stderr, "fuse: failed to allocate read buffer\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
while (!fuse_session_exited(se)) {
|
||||
res = fuse_chan_receive(ch, buf, bufsize);
|
||||
if (!res)
|
||||
continue;
|
||||
if (res == -1)
|
||||
break;
|
||||
fuse_session_process(se, buf, res, ch);
|
||||
res = 0;
|
||||
}
|
||||
|
||||
free(buf);
|
||||
fuse_session_reset(se);
|
||||
return res;
|
||||
}
|
||||
@@ -0,0 +1,161 @@
|
||||
/*
|
||||
FUSE: Filesystem in Userspace
|
||||
Copyright (C) 2001-2005 Miklos Szeredi <miklos@szeredi.hu>
|
||||
|
||||
This program can be distributed under the terms of the GNU LGPL.
|
||||
See the file COPYING.LIB.
|
||||
*/
|
||||
|
||||
#include "fuse_lowlevel.h"
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <pthread.h>
|
||||
#include <unistd.h>
|
||||
#include <signal.h>
|
||||
#include <errno.h>
|
||||
#include <sys/time.h>
|
||||
|
||||
#define FUSE_MAX_WORKERS 10
|
||||
|
||||
struct fuse_worker {
|
||||
pthread_mutex_t lock;
|
||||
int numworker;
|
||||
int numavail;
|
||||
struct fuse_session *se;
|
||||
struct fuse_chan *ch;
|
||||
struct fuse_chan *prevch;
|
||||
pthread_t threads[FUSE_MAX_WORKERS];
|
||||
int error;
|
||||
};
|
||||
|
||||
#ifndef USE_UCLIBC
|
||||
#define mutex_init(mut) pthread_mutex_init(mut, NULL)
|
||||
#else
|
||||
static void mutex_init(pthread_mutex_t mut)
|
||||
{
|
||||
pthread_mutexattr_t attr;
|
||||
pthread_mutexattr_init(&attr);
|
||||
pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_ADAPTIVE_NP);
|
||||
pthread_mutex_init(mut, &attr);
|
||||
pthread_mutexattr_destroy(&attr);
|
||||
}
|
||||
#endif
|
||||
|
||||
static int fuse_loop_mt_send(struct fuse_chan *ch, const struct iovec iov[],
|
||||
size_t count)
|
||||
{
|
||||
struct fuse_worker *w = (struct fuse_worker *) fuse_chan_data(ch);
|
||||
pthread_mutex_lock(&w->lock);
|
||||
w->numavail ++;
|
||||
pthread_mutex_unlock(&w->lock);
|
||||
return fuse_chan_send(w->prevch, iov, count);
|
||||
}
|
||||
|
||||
|
||||
static int start_thread(struct fuse_worker *w, pthread_t *thread_id);
|
||||
|
||||
static void *do_work(void *data)
|
||||
{
|
||||
struct fuse_worker *w = (struct fuse_worker *) data;
|
||||
int is_mainthread = (w->numworker == 1);
|
||||
size_t bufsize = fuse_chan_bufsize(w->prevch);
|
||||
char *buf = (char *) malloc(bufsize);
|
||||
if (!buf) {
|
||||
fprintf(stderr, "fuse: failed to allocate read buffer\n");
|
||||
fuse_session_exit(w->se);
|
||||
w->error = -1;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, NULL);
|
||||
pthread_setcanceltype(PTHREAD_CANCEL_ASYNCHRONOUS, NULL);
|
||||
|
||||
while (!fuse_session_exited(w->se)) {
|
||||
int res = fuse_chan_receive(w->prevch, buf, bufsize);
|
||||
if (!res)
|
||||
continue;
|
||||
if (res == -1) {
|
||||
fuse_session_exit(w->se);
|
||||
w->error = -1;
|
||||
}
|
||||
|
||||
pthread_mutex_lock(&w->lock);
|
||||
w->numavail--;
|
||||
if (w->numavail == 0 && w->numworker < FUSE_MAX_WORKERS) {
|
||||
if (w->numworker < FUSE_MAX_WORKERS) {
|
||||
/* FIXME: threads should be stored in a list instead
|
||||
of an array */
|
||||
int start_res;
|
||||
pthread_t *thread_id = &w->threads[w->numworker];
|
||||
w->numavail ++;
|
||||
w->numworker ++;
|
||||
start_res = start_thread(w, thread_id);
|
||||
if (start_res == -1)
|
||||
w->numavail --;
|
||||
}
|
||||
}
|
||||
pthread_mutex_unlock(&w->lock);
|
||||
fuse_session_process(w->se, buf, res, w->ch);
|
||||
}
|
||||
|
||||
/* Wait for cancellation */
|
||||
if (!is_mainthread)
|
||||
pause();
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static int start_thread(struct fuse_worker *w, pthread_t *thread_id)
|
||||
{
|
||||
int res = pthread_create(thread_id, NULL, do_work, w);
|
||||
if (res != 0) {
|
||||
fprintf(stderr, "fuse: error creating thread: %s\n", strerror(res));
|
||||
return -1;
|
||||
}
|
||||
|
||||
pthread_detach(*thread_id);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int fuse_session_loop_mt(struct fuse_session *se)
|
||||
{
|
||||
int i;
|
||||
int err;
|
||||
struct fuse_worker *w;
|
||||
struct fuse_chan_ops cop = {
|
||||
.send = fuse_loop_mt_send,
|
||||
};
|
||||
|
||||
w = (struct fuse_worker *) malloc(sizeof(struct fuse_worker));
|
||||
if (w == NULL) {
|
||||
fprintf(stderr, "fuse: failed to allocate worker structure\n");
|
||||
return -1;
|
||||
}
|
||||
memset(w, 0, sizeof(struct fuse_worker));
|
||||
w->se = se;
|
||||
w->prevch = fuse_session_next_chan(se, NULL);
|
||||
w->ch = fuse_chan_new(&cop, -1, 0, w);
|
||||
if (w->ch == NULL) {
|
||||
free(w);
|
||||
return -1;
|
||||
}
|
||||
w->error = 0;
|
||||
w->numworker = 1;
|
||||
w->numavail = 1;
|
||||
mutex_init(&w->lock);
|
||||
|
||||
do_work(w);
|
||||
|
||||
pthread_mutex_lock(&w->lock);
|
||||
for (i = 1; i < w->numworker; i++)
|
||||
pthread_cancel(w->threads[i]);
|
||||
pthread_mutex_unlock(&w->lock);
|
||||
pthread_mutex_destroy(&w->lock);
|
||||
err = w->error;
|
||||
fuse_chan_destroy(w->ch);
|
||||
free(w);
|
||||
fuse_session_reset(se);
|
||||
return err;
|
||||
}
|
||||
+92
-222
@@ -7,7 +7,7 @@
|
||||
*/
|
||||
|
||||
#include <config.h>
|
||||
#include "fuse_lowlevel_i.h"
|
||||
#include "fuse_lowlevel.h"
|
||||
#include "fuse_kernel.h"
|
||||
|
||||
#include <stdio.h>
|
||||
@@ -16,37 +16,28 @@
|
||||
#include <unistd.h>
|
||||
#include <limits.h>
|
||||
#include <errno.h>
|
||||
#include <assert.h>
|
||||
#include <stdint.h>
|
||||
#include <sys/param.h>
|
||||
#include <sys/uio.h>
|
||||
|
||||
#define PARAM(inarg) (((char *)(inarg)) + sizeof(*(inarg)))
|
||||
|
||||
struct fuse_cmd {
|
||||
char *buf;
|
||||
size_t buflen;
|
||||
struct fuse_ll {
|
||||
unsigned int debug : 1;
|
||||
unsigned int allow_root : 1;
|
||||
struct fuse_lowlevel_ops op;
|
||||
int got_init;
|
||||
void *userdata;
|
||||
int major;
|
||||
int minor;
|
||||
uid_t owner;
|
||||
};
|
||||
|
||||
struct fuse_req {
|
||||
struct fuse_ll *f;
|
||||
uint64_t unique;
|
||||
struct fuse_ctx ctx;
|
||||
struct fuse_chan *ch;
|
||||
};
|
||||
|
||||
#ifndef USE_UCLIBC
|
||||
#define mutex_init(mut) pthread_mutex_init(mut, NULL)
|
||||
#else
|
||||
static void mutex_init(pthread_mutex_t *mut)
|
||||
{
|
||||
pthread_mutexattr_t attr;
|
||||
pthread_mutexattr_init(&attr);
|
||||
pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_ADAPTIVE_NP);
|
||||
pthread_mutex_init(mut, &attr);
|
||||
pthread_mutexattr_destroy(&attr);
|
||||
}
|
||||
#endif
|
||||
|
||||
static const char *opname(enum fuse_opcode opcode)
|
||||
{
|
||||
switch (opcode) {
|
||||
@@ -86,20 +77,6 @@ static const char *opname(enum fuse_opcode opcode)
|
||||
}
|
||||
}
|
||||
|
||||
static inline void fuse_dec_avail(struct fuse_ll *f)
|
||||
{
|
||||
pthread_mutex_lock(&f->worker_lock);
|
||||
f->numavail --;
|
||||
pthread_mutex_unlock(&f->worker_lock);
|
||||
}
|
||||
|
||||
static inline void fuse_inc_avail(struct fuse_ll *f)
|
||||
{
|
||||
pthread_mutex_lock(&f->worker_lock);
|
||||
f->numavail ++;
|
||||
pthread_mutex_unlock(&f->worker_lock);
|
||||
}
|
||||
|
||||
static void convert_stat(const struct stat *stbuf, struct fuse_attr *attr)
|
||||
{
|
||||
attr->ino = stbuf->st_ino;
|
||||
@@ -166,48 +143,25 @@ static size_t iov_length(const struct iovec *iov, size_t count)
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int send_reply_raw(struct fuse_ll *f, const struct iovec iov[],
|
||||
size_t count)
|
||||
static void free_req(fuse_req_t req)
|
||||
{
|
||||
int res;
|
||||
unsigned outsize = iov_length(iov, count);
|
||||
struct fuse_out_header *out = (struct fuse_out_header *) iov[0].iov_base;
|
||||
out->len = outsize;
|
||||
|
||||
if (f->debug) {
|
||||
printf(" unique: %llu, error: %i (%s), outsize: %i\n",
|
||||
out->unique, out->error, strerror(-out->error), outsize);
|
||||
fflush(stdout);
|
||||
}
|
||||
|
||||
/* This needs to be done before the reply, otherwise the scheduler
|
||||
could play tricks with us, and only let the counter be
|
||||
increased long after the operation is done */
|
||||
fuse_inc_avail(f);
|
||||
|
||||
res = writev(f->fd, iov, count);
|
||||
if (res == -1) {
|
||||
/* ENOENT means the operation was interrupted */
|
||||
if (!fuse_ll_exited(f) && errno != ENOENT)
|
||||
perror("fuse: writing device");
|
||||
return -errno;
|
||||
}
|
||||
return 0;
|
||||
free(req);
|
||||
}
|
||||
|
||||
static int send_reply(struct fuse_ll *f, uint64_t unique, int error,
|
||||
const void *arg, size_t argsize)
|
||||
static int send_reply(fuse_req_t req, int error, const void *arg,
|
||||
size_t argsize)
|
||||
{
|
||||
struct fuse_out_header out;
|
||||
struct iovec iov[2];
|
||||
size_t count;
|
||||
int res;
|
||||
|
||||
if (error <= -1000 || error > 0) {
|
||||
fprintf(stderr, "fuse: bad error value: %i\n", error);
|
||||
error = -ERANGE;
|
||||
}
|
||||
|
||||
out.unique = unique;
|
||||
out.unique = req->unique;
|
||||
out.error = error;
|
||||
count = 1;
|
||||
iov[0].iov_base = &out;
|
||||
@@ -217,7 +171,17 @@ static int send_reply(struct fuse_ll *f, uint64_t unique, int error,
|
||||
iov[1].iov_base = (void *) arg;
|
||||
iov[1].iov_len = argsize;
|
||||
}
|
||||
return send_reply_raw(f, iov, count);
|
||||
out.len = iov_length(iov, count);
|
||||
|
||||
if (req->f->debug) {
|
||||
printf(" unique: %llu, error: %i (%s), outsize: %i\n",
|
||||
out.unique, out.error, strerror(-out.error), out.len);
|
||||
fflush(stdout);
|
||||
}
|
||||
res = fuse_chan_send(req->ch, iov, count);
|
||||
free_req(req);
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
size_t fuse_dirent_size(size_t namelen)
|
||||
@@ -257,23 +221,14 @@ static void convert_statfs(const struct statfs *stbuf,
|
||||
kstatfs->namelen = stbuf->f_namelen;
|
||||
}
|
||||
|
||||
static void free_req(fuse_req_t req)
|
||||
static int send_reply_ok(fuse_req_t req, const void *arg, size_t argsize)
|
||||
{
|
||||
free(req);
|
||||
}
|
||||
|
||||
static int send_reply_req(fuse_req_t req, const void *arg, size_t argsize)
|
||||
{
|
||||
int res = send_reply(req->f, req->unique, 0, arg, argsize);
|
||||
free_req(req);
|
||||
return res;
|
||||
return send_reply(req, 0, arg, argsize);
|
||||
}
|
||||
|
||||
int fuse_reply_err(fuse_req_t req, int err)
|
||||
{
|
||||
int res = send_reply(req->f, req->unique, -err, NULL, 0);
|
||||
free_req(req);
|
||||
return res;
|
||||
return send_reply(req, -err, NULL, 0);
|
||||
}
|
||||
|
||||
int fuse_reply_none(fuse_req_t req)
|
||||
@@ -316,7 +271,7 @@ int fuse_reply_entry(fuse_req_t req, const struct fuse_entry_param *e)
|
||||
arg.attr_valid_nsec = calc_timeout_nsec(e->attr_timeout);
|
||||
convert_stat(&e->attr, &arg.attr);
|
||||
|
||||
return send_reply_req(req, &arg, sizeof(arg));
|
||||
return send_reply_ok(req, &arg, sizeof(arg));
|
||||
}
|
||||
|
||||
int fuse_reply_attr(fuse_req_t req, const struct stat *attr,
|
||||
@@ -329,12 +284,12 @@ int fuse_reply_attr(fuse_req_t req, const struct stat *attr,
|
||||
arg.attr_valid_nsec = calc_timeout_nsec(attr_timeout);
|
||||
convert_stat(attr, &arg.attr);
|
||||
|
||||
return send_reply_req(req, &arg, sizeof(arg));
|
||||
return send_reply_ok(req, &arg, sizeof(arg));
|
||||
}
|
||||
|
||||
int fuse_reply_readlink(fuse_req_t req, const char *linkname)
|
||||
{
|
||||
return send_reply_req(req, linkname, strlen(linkname));
|
||||
return send_reply_ok(req, linkname, strlen(linkname));
|
||||
}
|
||||
|
||||
int fuse_reply_open(fuse_req_t req, const struct fuse_file_info *f)
|
||||
@@ -348,7 +303,7 @@ int fuse_reply_open(fuse_req_t req, const struct fuse_file_info *f)
|
||||
if (f->keep_cache)
|
||||
arg.open_flags |= FOPEN_KEEP_CACHE;
|
||||
|
||||
return send_reply_req(req, &arg, sizeof(arg));
|
||||
return send_reply_ok(req, &arg, sizeof(arg));
|
||||
}
|
||||
|
||||
int fuse_reply_write(fuse_req_t req, size_t count)
|
||||
@@ -358,12 +313,12 @@ int fuse_reply_write(fuse_req_t req, size_t count)
|
||||
memset(&arg, 0, sizeof(arg));
|
||||
arg.size = count;
|
||||
|
||||
return send_reply_req(req, &arg, sizeof(arg));
|
||||
return send_reply_ok(req, &arg, sizeof(arg));
|
||||
}
|
||||
|
||||
int fuse_reply_buf(fuse_req_t req, const char *buf, size_t size)
|
||||
{
|
||||
return send_reply_req(req, buf, size);
|
||||
return send_reply_ok(req, buf, size);
|
||||
}
|
||||
|
||||
int fuse_reply_statfs(fuse_req_t req, const struct statfs *stbuf)
|
||||
@@ -373,7 +328,7 @@ int fuse_reply_statfs(fuse_req_t req, const struct statfs *stbuf)
|
||||
memset(&arg, 0, sizeof(arg));
|
||||
convert_statfs(stbuf, &arg.st);
|
||||
|
||||
return send_reply_req(req, &arg, sizeof(arg));
|
||||
return send_reply_ok(req, &arg, sizeof(arg));
|
||||
}
|
||||
|
||||
int fuse_reply_xattr(fuse_req_t req, size_t count)
|
||||
@@ -383,7 +338,7 @@ int fuse_reply_xattr(fuse_req_t req, size_t count)
|
||||
memset(&arg, 0, sizeof(arg));
|
||||
arg.size = count;
|
||||
|
||||
return send_reply_req(req, &arg, sizeof(arg));
|
||||
return send_reply_ok(req, &arg, sizeof(arg));
|
||||
}
|
||||
|
||||
int fuse_reply_getlk(fuse_req_t req, const struct fuse_lock_param *lk)
|
||||
@@ -393,7 +348,7 @@ int fuse_reply_getlk(fuse_req_t req, const struct fuse_lock_param *lk)
|
||||
memset(&arg, 0, sizeof(arg));
|
||||
convert_lock_param(lk, &arg.lk);
|
||||
|
||||
return send_reply_req(req, &arg, sizeof(arg));
|
||||
return send_reply_ok(req, &arg, sizeof(arg));
|
||||
}
|
||||
|
||||
static void do_lookup(fuse_req_t req, fuse_ino_t nodeid, char *name)
|
||||
@@ -727,10 +682,10 @@ static void do_setlk(fuse_req_t req, fuse_ino_t nodeid, int issleep,
|
||||
fuse_reply_err(req, ENOSYS);
|
||||
}
|
||||
|
||||
static void do_init(struct fuse_ll *f, uint64_t unique,
|
||||
struct fuse_init_in_out *arg)
|
||||
static void do_init(fuse_req_t req, struct fuse_init_in_out *arg)
|
||||
{
|
||||
struct fuse_init_in_out outarg;
|
||||
struct fuse_ll *f = req->f;
|
||||
|
||||
if (f->debug) {
|
||||
printf("INIT: %u.%u\n", arg->major, arg->minor);
|
||||
@@ -738,7 +693,7 @@ static void do_init(struct fuse_ll *f, uint64_t unique,
|
||||
}
|
||||
f->got_init = 1;
|
||||
if (f->op.init)
|
||||
f->userdata = f->op.init(f->userdata);
|
||||
f->op.init(f->userdata);
|
||||
|
||||
f->major = FUSE_KERNEL_VERSION;
|
||||
f->minor = FUSE_KERNEL_MINOR_VERSION;
|
||||
@@ -752,7 +707,7 @@ static void do_init(struct fuse_ll *f, uint64_t unique,
|
||||
fflush(stdout);
|
||||
}
|
||||
|
||||
send_reply(f, unique, 0, &outarg, sizeof(outarg));
|
||||
send_reply_ok(req, &outarg, sizeof(outarg));
|
||||
}
|
||||
|
||||
void *fuse_req_userdata(fuse_req_t req)
|
||||
@@ -765,48 +720,25 @@ const struct fuse_ctx *fuse_req_ctx(fuse_req_t req)
|
||||
return &req->ctx;
|
||||
}
|
||||
|
||||
static void free_cmd(struct fuse_cmd *cmd)
|
||||
static void fuse_ll_process(void *data, const char *buf, size_t len,
|
||||
struct fuse_chan *ch)
|
||||
{
|
||||
free(cmd->buf);
|
||||
free(cmd);
|
||||
}
|
||||
|
||||
void fuse_ll_process_cmd(struct fuse_ll *f, struct fuse_cmd *cmd)
|
||||
{
|
||||
struct fuse_in_header *in = (struct fuse_in_header *) cmd->buf;
|
||||
void *inarg = cmd->buf + sizeof(struct fuse_in_header);
|
||||
struct fuse_ll *f = (struct fuse_ll *) data;
|
||||
struct fuse_in_header *in = (struct fuse_in_header *) buf;
|
||||
const void *inarg = buf + sizeof(struct fuse_in_header);
|
||||
struct fuse_req *req;
|
||||
|
||||
fuse_dec_avail(f);
|
||||
|
||||
if (f->debug) {
|
||||
printf("unique: %llu, opcode: %s (%i), nodeid: %lu, insize: %i\n",
|
||||
in->unique, opname((enum fuse_opcode) in->opcode), in->opcode,
|
||||
(unsigned long) in->nodeid, cmd->buflen);
|
||||
(unsigned long) in->nodeid, len);
|
||||
fflush(stdout);
|
||||
}
|
||||
|
||||
if (!f->got_init) {
|
||||
if (in->opcode != FUSE_INIT)
|
||||
send_reply(f, in->unique, -EPROTO, NULL, 0);
|
||||
else
|
||||
do_init(f, in->unique, (struct fuse_init_in_out *) inarg);
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (f->allow_root && in->uid != f->owner && in->uid != 0 &&
|
||||
in->opcode != FUSE_INIT && in->opcode != FUSE_READ &&
|
||||
in->opcode != FUSE_WRITE && in->opcode != FUSE_FSYNC &&
|
||||
in->opcode != FUSE_RELEASE && in->opcode != FUSE_READDIR &&
|
||||
in->opcode != FUSE_FSYNCDIR && in->opcode != FUSE_RELEASEDIR) {
|
||||
send_reply(f, in->unique, -EACCES, NULL, 0);
|
||||
goto out;
|
||||
}
|
||||
|
||||
req = (struct fuse_req *) malloc(sizeof(struct fuse_req));
|
||||
if (req == NULL) {
|
||||
fprintf(stderr, "fuse: failed to allocate request\n");
|
||||
goto out;
|
||||
return;
|
||||
}
|
||||
|
||||
req->f = f;
|
||||
@@ -814,8 +746,21 @@ void fuse_ll_process_cmd(struct fuse_ll *f, struct fuse_cmd *cmd)
|
||||
req->ctx.uid = in->uid;
|
||||
req->ctx.gid = in->gid;
|
||||
req->ctx.pid = in->pid;
|
||||
req->ch = ch;
|
||||
|
||||
switch (in->opcode) {
|
||||
if (!f->got_init && in->opcode != FUSE_INIT)
|
||||
fuse_reply_err(req, EPROTO);
|
||||
else if (f->allow_root && in->uid != f->owner && in->uid != 0 &&
|
||||
in->opcode != FUSE_INIT && in->opcode != FUSE_READ &&
|
||||
in->opcode != FUSE_WRITE && in->opcode != FUSE_FSYNC &&
|
||||
in->opcode != FUSE_RELEASE && in->opcode != FUSE_READDIR &&
|
||||
in->opcode != FUSE_FSYNCDIR && in->opcode != FUSE_RELEASEDIR) {
|
||||
fuse_reply_err(req, EACCES);
|
||||
} else switch (in->opcode) {
|
||||
case FUSE_INIT:
|
||||
do_init(req, (struct fuse_init_in_out *) inarg);
|
||||
break;
|
||||
|
||||
case FUSE_LOOKUP:
|
||||
do_lookup(req, in->nodeid, (char *) inarg);
|
||||
break;
|
||||
@@ -944,92 +889,9 @@ void fuse_ll_process_cmd(struct fuse_ll *f, struct fuse_cmd *cmd)
|
||||
default:
|
||||
fuse_reply_err(req, ENOSYS);
|
||||
}
|
||||
|
||||
out:
|
||||
free_cmd(cmd);
|
||||
}
|
||||
|
||||
void fuse_ll_exit(struct fuse_ll *f)
|
||||
{
|
||||
f->exited = 1;
|
||||
}
|
||||
|
||||
int fuse_ll_exited(struct fuse_ll* f)
|
||||
{
|
||||
return f->exited;
|
||||
}
|
||||
|
||||
struct fuse_cmd *fuse_ll_read_cmd(struct fuse_ll *f)
|
||||
{
|
||||
ssize_t res;
|
||||
struct fuse_cmd *cmd;
|
||||
struct fuse_in_header *in;
|
||||
void *inarg;
|
||||
|
||||
cmd = (struct fuse_cmd *) malloc(sizeof(struct fuse_cmd));
|
||||
if (cmd == NULL) {
|
||||
fprintf(stderr, "fuse: failed to allocate cmd in read\n");
|
||||
return NULL;
|
||||
}
|
||||
cmd->buf = (char *) malloc(FUSE_MAX_IN);
|
||||
if (cmd->buf == NULL) {
|
||||
fprintf(stderr, "fuse: failed to allocate read buffer\n");
|
||||
free(cmd);
|
||||
return NULL;
|
||||
}
|
||||
in = (struct fuse_in_header *) cmd->buf;
|
||||
inarg = cmd->buf + sizeof(struct fuse_in_header);
|
||||
|
||||
res = read(f->fd, cmd->buf, FUSE_MAX_IN);
|
||||
if (res == -1) {
|
||||
free_cmd(cmd);
|
||||
if (fuse_ll_exited(f) || errno == EINTR || errno == ENOENT)
|
||||
return NULL;
|
||||
|
||||
/* ENODEV means we got unmounted, so we silenty return failure */
|
||||
if (errno != ENODEV) {
|
||||
/* BAD... This will happen again */
|
||||
perror("fuse: reading device");
|
||||
}
|
||||
|
||||
fuse_ll_exit(f);
|
||||
return NULL;
|
||||
}
|
||||
if ((size_t) res < sizeof(struct fuse_in_header)) {
|
||||
free_cmd(cmd);
|
||||
/* Cannot happen */
|
||||
fprintf(stderr, "short read on fuse device\n");
|
||||
fuse_ll_exit(f);
|
||||
return NULL;
|
||||
}
|
||||
cmd->buflen = res;
|
||||
|
||||
|
||||
return cmd;
|
||||
}
|
||||
|
||||
int fuse_ll_loop(struct fuse_ll *f)
|
||||
{
|
||||
if (f == NULL)
|
||||
return -1;
|
||||
|
||||
while (1) {
|
||||
struct fuse_cmd *cmd;
|
||||
|
||||
if (fuse_ll_exited(f))
|
||||
break;
|
||||
|
||||
cmd = fuse_ll_read_cmd(f);
|
||||
if (cmd == NULL)
|
||||
continue;
|
||||
|
||||
fuse_ll_process_cmd(f, cmd);
|
||||
}
|
||||
f->exited = 0;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int fuse_ll_is_lib_option(const char *opt)
|
||||
int fuse_lowlevel_is_lib_option(const char *opt)
|
||||
{
|
||||
if (strcmp(opt, "debug") == 0 ||
|
||||
strcmp(opt, "allow_root") == 0)
|
||||
@@ -1063,15 +925,31 @@ static int parse_ll_opts(struct fuse_ll *f, const char *opts)
|
||||
return 0;
|
||||
}
|
||||
|
||||
struct fuse_ll *fuse_ll_new(int fd, const char *opts,
|
||||
const struct fuse_ll_operations *op,
|
||||
size_t op_size, void *userdata)
|
||||
static void fuse_ll_destroy(void *data)
|
||||
{
|
||||
struct fuse_ll *f = (struct fuse_ll *) data;
|
||||
|
||||
if (f->op.destroy)
|
||||
f->op.destroy(f->userdata);
|
||||
|
||||
free(f);
|
||||
}
|
||||
|
||||
|
||||
struct fuse_session *fuse_lowlevel_new(const char *opts,
|
||||
const struct fuse_lowlevel_ops *op,
|
||||
size_t op_size, void *userdata)
|
||||
{
|
||||
struct fuse_ll *f;
|
||||
struct fuse_session *se;
|
||||
struct fuse_session_ops sop = {
|
||||
.process = fuse_ll_process,
|
||||
.destroy = fuse_ll_destroy,
|
||||
};
|
||||
|
||||
if (sizeof(struct fuse_ll_operations) < op_size) {
|
||||
if (sizeof(struct fuse_lowlevel_ops) < op_size) {
|
||||
fprintf(stderr, "fuse: warning: library too old, some operations may not not work\n");
|
||||
op_size = sizeof(struct fuse_ll_operations);
|
||||
op_size = sizeof(struct fuse_lowlevel_ops);
|
||||
}
|
||||
|
||||
f = (struct fuse_ll *) calloc(1, sizeof(struct fuse_ll));
|
||||
@@ -1083,14 +961,15 @@ struct fuse_ll *fuse_ll_new(int fd, const char *opts,
|
||||
if (parse_ll_opts(f, opts) == -1)
|
||||
goto out_free;
|
||||
|
||||
f->fd = fd;
|
||||
memcpy(&f->op, op, op_size);
|
||||
f->exited = 0;
|
||||
f->owner = getuid();
|
||||
f->userdata = userdata;
|
||||
mutex_init(&f->worker_lock);
|
||||
|
||||
return f;
|
||||
se = fuse_session_new(&sop, f);
|
||||
if (!se)
|
||||
goto out_free;
|
||||
|
||||
return se;
|
||||
|
||||
out_free:
|
||||
free(f);
|
||||
@@ -1098,12 +977,3 @@ struct fuse_ll *fuse_ll_new(int fd, const char *opts,
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void fuse_ll_destroy(struct fuse_ll *f)
|
||||
{
|
||||
if (f->op.destroy)
|
||||
f->op.destroy(f->userdata);
|
||||
|
||||
pthread_mutex_destroy(&f->worker_lock);
|
||||
free(f);
|
||||
}
|
||||
|
||||
|
||||
@@ -1,26 +0,0 @@
|
||||
/*
|
||||
FUSE: Filesystem in Userspace
|
||||
Copyright (C) 2001-2005 Miklos Szeredi <miklos@szeredi.hu>
|
||||
|
||||
This program can be distributed under the terms of the GNU LGPL.
|
||||
See the file COPYING.LIB.
|
||||
*/
|
||||
|
||||
#include "fuse_lowlevel.h"
|
||||
#include <pthread.h>
|
||||
|
||||
struct fuse_ll {
|
||||
unsigned int debug : 1;
|
||||
unsigned int allow_root : 1;
|
||||
int fd;
|
||||
struct fuse_ll_operations op;
|
||||
volatile int exited;
|
||||
int got_init;
|
||||
void *userdata;
|
||||
int major;
|
||||
int minor;
|
||||
uid_t owner;
|
||||
pthread_mutex_t worker_lock;
|
||||
int numworker;
|
||||
int numavail;
|
||||
};
|
||||
@@ -1,126 +0,0 @@
|
||||
/*
|
||||
FUSE: Filesystem in Userspace
|
||||
Copyright (C) 2001-2005 Miklos Szeredi <miklos@szeredi.hu>
|
||||
|
||||
This program can be distributed under the terms of the GNU LGPL.
|
||||
See the file COPYING.LIB.
|
||||
*/
|
||||
|
||||
#include "fuse_lowlevel_i.h"
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <pthread.h>
|
||||
#include <unistd.h>
|
||||
#include <signal.h>
|
||||
#include <errno.h>
|
||||
#include <sys/time.h>
|
||||
|
||||
#define FUSE_MAX_WORKERS 10
|
||||
|
||||
struct fuse_worker {
|
||||
struct fuse_ll *f;
|
||||
pthread_t threads[FUSE_MAX_WORKERS];
|
||||
void *data;
|
||||
fuse_ll_processor_t proc;
|
||||
};
|
||||
|
||||
static int start_thread(struct fuse_worker *w, pthread_t *thread_id);
|
||||
|
||||
static void *do_work(void *data)
|
||||
{
|
||||
struct fuse_worker *w = (struct fuse_worker *) data;
|
||||
struct fuse_ll *f = w->f;
|
||||
int is_mainthread = (f->numworker == 1);
|
||||
|
||||
pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, NULL);
|
||||
pthread_setcanceltype(PTHREAD_CANCEL_ASYNCHRONOUS, NULL);
|
||||
|
||||
while (1) {
|
||||
struct fuse_cmd *cmd;
|
||||
|
||||
if (fuse_ll_exited(f))
|
||||
break;
|
||||
|
||||
cmd = fuse_ll_read_cmd(w->f);
|
||||
if (cmd == NULL)
|
||||
continue;
|
||||
|
||||
if (f->numavail == 0 && f->numworker < FUSE_MAX_WORKERS) {
|
||||
pthread_mutex_lock(&f->worker_lock);
|
||||
if (f->numworker < FUSE_MAX_WORKERS) {
|
||||
/* FIXME: threads should be stored in a list instead
|
||||
of an array */
|
||||
int res;
|
||||
pthread_t *thread_id = &w->threads[f->numworker];
|
||||
f->numavail ++;
|
||||
f->numworker ++;
|
||||
pthread_mutex_unlock(&f->worker_lock);
|
||||
res = start_thread(w, thread_id);
|
||||
if (res == -1) {
|
||||
pthread_mutex_lock(&f->worker_lock);
|
||||
f->numavail --;
|
||||
pthread_mutex_unlock(&f->worker_lock);
|
||||
}
|
||||
} else
|
||||
pthread_mutex_unlock(&f->worker_lock);
|
||||
}
|
||||
|
||||
w->proc(w->f, cmd, w->data);
|
||||
}
|
||||
|
||||
/* Wait for cancellation */
|
||||
if (!is_mainthread)
|
||||
pause();
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static int start_thread(struct fuse_worker *w, pthread_t *thread_id)
|
||||
{
|
||||
int res = pthread_create(thread_id, NULL, do_work, w);
|
||||
if (res != 0) {
|
||||
fprintf(stderr, "fuse: error creating thread: %s\n", strerror(res));
|
||||
return -1;
|
||||
}
|
||||
|
||||
pthread_detach(*thread_id);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int fuse_ll_loop_mt_proc(struct fuse_ll *f, fuse_ll_processor_t proc, void *data)
|
||||
{
|
||||
struct fuse_worker *w;
|
||||
int i;
|
||||
|
||||
w = (struct fuse_worker *) malloc(sizeof(struct fuse_worker));
|
||||
if (w == NULL) {
|
||||
fprintf(stderr, "fuse: failed to allocate worker structure\n");
|
||||
return -1;
|
||||
}
|
||||
memset(w, 0, sizeof(struct fuse_worker));
|
||||
w->f = f;
|
||||
w->data = data;
|
||||
w->proc = proc;
|
||||
|
||||
f->numworker = 1;
|
||||
do_work(w);
|
||||
|
||||
pthread_mutex_lock(&f->worker_lock);
|
||||
for (i = 1; i < f->numworker; i++)
|
||||
pthread_cancel(w->threads[i]);
|
||||
pthread_mutex_unlock(&f->worker_lock);
|
||||
free(w);
|
||||
f->exited = 0;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int fuse_ll_loop_mt(struct fuse_ll *f)
|
||||
{
|
||||
if (f)
|
||||
return fuse_ll_loop_mt_proc(f, (fuse_ll_processor_t) fuse_ll_process_cmd, NULL);
|
||||
else
|
||||
return -1;
|
||||
}
|
||||
|
||||
+51
-6
@@ -13,7 +13,7 @@
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <pthread.h>
|
||||
|
||||
#include <assert.h>
|
||||
|
||||
static pthread_key_t context_key;
|
||||
static pthread_mutex_t context_lock = PTHREAD_MUTEX_INITIALIZER;
|
||||
@@ -75,28 +75,73 @@ struct procdata {
|
||||
void *data;
|
||||
};
|
||||
|
||||
static void mt_generic_proc(struct fuse_ll *f, struct fuse_cmd *cmd, void *data)
|
||||
static void mt_session_proc(void *data, const char *buf, size_t len,
|
||||
struct fuse_chan *ch)
|
||||
{
|
||||
struct procdata *pd = (struct procdata *) data;
|
||||
(void) f;
|
||||
struct fuse_cmd *cmd = *(struct fuse_cmd **) buf;
|
||||
|
||||
(void) len;
|
||||
(void) ch;
|
||||
pd->proc(pd->f, cmd, pd->data);
|
||||
}
|
||||
|
||||
static int mt_chan_receive(struct fuse_chan *ch, char *buf, size_t size)
|
||||
{
|
||||
struct fuse_cmd *cmd;
|
||||
struct procdata *pd = (struct procdata *) fuse_chan_data(ch);
|
||||
|
||||
assert(size >= sizeof(cmd));
|
||||
|
||||
cmd = fuse_read_cmd(pd->f);
|
||||
if (cmd == NULL)
|
||||
return -1;
|
||||
|
||||
*(struct fuse_cmd **) buf = cmd;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int fuse_loop_mt_proc(struct fuse *f, fuse_processor_t proc, void *data)
|
||||
{
|
||||
int res;
|
||||
struct procdata pd;
|
||||
struct fuse_session *prevse = fuse_get_session(f);
|
||||
struct fuse_session *se;
|
||||
struct fuse_chan *prevch = fuse_session_next_chan(prevse, NULL);
|
||||
struct fuse_chan *ch;
|
||||
struct fuse_session_ops sop = {
|
||||
.process = mt_session_proc,
|
||||
};
|
||||
struct fuse_chan_ops cop = {
|
||||
.receive = mt_chan_receive,
|
||||
};
|
||||
|
||||
pd.f = f;
|
||||
pd.proc = proc;
|
||||
pd.data = data;
|
||||
|
||||
if (mt_create_context_key() != 0)
|
||||
se = fuse_session_new(&sop, &pd);
|
||||
if (se == NULL)
|
||||
return -1;
|
||||
|
||||
res = fuse_ll_loop_mt_proc(fuse_get_lowlevel(f), mt_generic_proc, &pd);
|
||||
ch = fuse_chan_new(&cop, fuse_chan_fd(prevch), sizeof(struct fuse_cmd *),
|
||||
&pd);
|
||||
if (ch == NULL) {
|
||||
fuse_session_destroy(se);
|
||||
return -1;
|
||||
}
|
||||
fuse_session_add_chan(se, ch);
|
||||
|
||||
if (mt_create_context_key() != 0) {
|
||||
fuse_session_destroy(se);
|
||||
return -1;
|
||||
}
|
||||
|
||||
res = fuse_session_loop_mt(se);
|
||||
|
||||
mt_delete_context_key();
|
||||
fuse_session_destroy(se);
|
||||
return res;
|
||||
}
|
||||
|
||||
@@ -107,7 +152,7 @@ int fuse_loop_mt(struct fuse *f)
|
||||
if (mt_create_context_key() != 0)
|
||||
return -1;
|
||||
|
||||
res = fuse_ll_loop_mt(fuse_get_lowlevel(f));
|
||||
res = fuse_session_loop_mt(fuse_get_session(f));
|
||||
|
||||
mt_delete_context_key();
|
||||
return res;
|
||||
|
||||
@@ -0,0 +1,154 @@
|
||||
/*
|
||||
FUSE: Filesystem in Userspace
|
||||
Copyright (C) 2001-2005 Miklos Szeredi <miklos@szeredi.hu>
|
||||
|
||||
This program can be distributed under the terms of the GNU LGPL.
|
||||
See the file COPYING.LIB
|
||||
*/
|
||||
|
||||
#include "fuse_lowlevel.h"
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <assert.h>
|
||||
|
||||
struct fuse_session {
|
||||
struct fuse_session_ops op;
|
||||
|
||||
void *data;
|
||||
|
||||
volatile int exited;
|
||||
|
||||
struct fuse_chan *ch;
|
||||
};
|
||||
|
||||
struct fuse_chan {
|
||||
struct fuse_chan_ops op;
|
||||
|
||||
struct fuse_session *se;
|
||||
|
||||
int fd;
|
||||
|
||||
size_t bufsize;
|
||||
|
||||
void *data;
|
||||
};
|
||||
|
||||
struct fuse_session *fuse_session_new(struct fuse_session_ops *op, void *data)
|
||||
{
|
||||
struct fuse_session *se = (struct fuse_session *) malloc(sizeof(*se));
|
||||
if (se == NULL) {
|
||||
fprintf(stderr, "fuse: failed to allocate session\n");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
memset(se, 0, sizeof(*se));
|
||||
se->op = *op;
|
||||
se->data = data;
|
||||
|
||||
return se;
|
||||
}
|
||||
|
||||
void fuse_session_add_chan(struct fuse_session *se, struct fuse_chan *ch)
|
||||
{
|
||||
assert(se->ch == NULL);
|
||||
assert(ch->se == NULL);
|
||||
se->ch = ch;
|
||||
ch->se = se;
|
||||
}
|
||||
|
||||
struct fuse_chan *fuse_session_next_chan(struct fuse_session *se,
|
||||
struct fuse_chan *ch)
|
||||
{
|
||||
assert(ch == NULL || ch == se->ch);
|
||||
if (ch == NULL)
|
||||
return se->ch;
|
||||
else
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void fuse_session_process(struct fuse_session *se, const char *buf, size_t len,
|
||||
struct fuse_chan *ch)
|
||||
{
|
||||
se->op.process(se->data, buf, len, ch);
|
||||
}
|
||||
|
||||
void fuse_session_destroy(struct fuse_session *se)
|
||||
{
|
||||
if (se->op.destroy)
|
||||
se->op.destroy(se->data);
|
||||
if (se->ch != NULL)
|
||||
fuse_chan_destroy(se->ch);
|
||||
free(se);
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
struct fuse_chan *fuse_chan_new(struct fuse_chan_ops *op, int fd,
|
||||
size_t bufsize, void *data)
|
||||
{
|
||||
struct fuse_chan *ch = (struct fuse_chan *) malloc(sizeof(*ch));
|
||||
if (ch == NULL) {
|
||||
fprintf(stderr, "fuse: failed to allocate channel\n");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
memset(ch, 0, sizeof(*ch));
|
||||
ch->op = *op;
|
||||
ch->fd = fd;
|
||||
ch->bufsize = bufsize;
|
||||
ch->data = data;
|
||||
|
||||
return ch;
|
||||
}
|
||||
|
||||
int fuse_chan_fd(struct fuse_chan *ch)
|
||||
{
|
||||
return ch->fd;
|
||||
}
|
||||
|
||||
size_t fuse_chan_bufsize(struct fuse_chan *ch)
|
||||
{
|
||||
return ch->bufsize;
|
||||
}
|
||||
|
||||
void *fuse_chan_data(struct fuse_chan *ch)
|
||||
{
|
||||
return ch->data;
|
||||
}
|
||||
|
||||
struct fuse_session *fuse_chan_session(struct fuse_chan *ch)
|
||||
{
|
||||
return ch->se;
|
||||
}
|
||||
|
||||
int fuse_chan_receive(struct fuse_chan *ch, char *buf, size_t size)
|
||||
{
|
||||
return ch->op.receive(ch, buf, size);
|
||||
}
|
||||
|
||||
int fuse_chan_send(struct fuse_chan *ch, const struct iovec iov[], size_t count)
|
||||
{
|
||||
return ch->op.send(ch, iov, count);
|
||||
}
|
||||
|
||||
void fuse_chan_destroy(struct fuse_chan *ch)
|
||||
{
|
||||
if (ch->op.destroy)
|
||||
ch->op.destroy(ch);
|
||||
free(ch);
|
||||
}
|
||||
+30
-14
@@ -1,24 +1,28 @@
|
||||
FUSE_2.2 {
|
||||
global:
|
||||
fuse_add_dirent;
|
||||
fuse_chan_bufsize;
|
||||
fuse_chan_data;
|
||||
fuse_chan_destroy;
|
||||
fuse_chan_fd;
|
||||
fuse_chan_new;
|
||||
fuse_chan_receive;
|
||||
fuse_chan_send;
|
||||
fuse_chan_session;
|
||||
fuse_destroy;
|
||||
fuse_dirent_size;
|
||||
fuse_exit;
|
||||
fuse_exited;
|
||||
fuse_get_context;
|
||||
fuse_get_session;
|
||||
fuse_invalidate;
|
||||
fuse_is_lib_option;
|
||||
fuse_ll_new;
|
||||
fuse_ll_destroy;
|
||||
fuse_ll_is_lib_option;
|
||||
fuse_ll_loop;
|
||||
fuse_ll_loop_mt;
|
||||
fuse_ll_exited;
|
||||
fuse_ll_read_cmd;
|
||||
fuse_ll_process_cmd;
|
||||
fuse_kern_chan_new;
|
||||
fuse_loop;
|
||||
fuse_loop_mt;
|
||||
fuse_loop_mt_proc;
|
||||
fuse_lowlevel_is_lib_option;
|
||||
fuse_lowlevel_new;
|
||||
fuse_main;
|
||||
fuse_main_compat1;
|
||||
fuse_main_compat2;
|
||||
@@ -30,17 +34,29 @@ FUSE_2.2 {
|
||||
fuse_new_compat2;
|
||||
fuse_process_cmd;
|
||||
fuse_read_cmd;
|
||||
fuse_reply_err;
|
||||
fuse_reply_none;
|
||||
fuse_reply_entry;
|
||||
fuse_reply_attr;
|
||||
fuse_reply_readlink;
|
||||
fuse_reply_open;
|
||||
fuse_reply_write;
|
||||
fuse_reply_buf;
|
||||
fuse_reply_entry;
|
||||
fuse_reply_err;
|
||||
fuse_reply_getlk;
|
||||
fuse_reply_none;
|
||||
fuse_reply_open;
|
||||
fuse_reply_readlink;
|
||||
fuse_reply_statfs;
|
||||
fuse_reply_write;
|
||||
fuse_reply_xattr;
|
||||
fuse_req_ctx;
|
||||
fuse_req_userdata;
|
||||
fuse_session_add_chan;
|
||||
fuse_session_destroy;
|
||||
fuse_session_exit;
|
||||
fuse_session_exited;
|
||||
fuse_session_loop;
|
||||
fuse_session_loop_mt;
|
||||
fuse_session_new;
|
||||
fuse_session_next_chan;
|
||||
fuse_session_process;
|
||||
fuse_session_reset;
|
||||
fuse_set_getcontext_func;
|
||||
fuse_setup;
|
||||
fuse_setup_compat2;
|
||||
|
||||
Reference in New Issue
Block a user