From 2482fdb1f0138cd273203d641e2107266fcf5db2 Mon Sep 17 00:00:00 2001 From: Miklos Szeredi Date: Tue, 12 Jul 2005 13:23:53 +0000 Subject: [PATCH] fix --- ChangeLog | 5 + include/fuse_lowlevel.h | 48 +- lib/fuse_lowlevel.c | 1084 +++++++-------------------------------- lib/fuse_mt.c | 10 +- 4 files changed, 231 insertions(+), 916 deletions(-) diff --git a/ChangeLog b/ChangeLog index f820dd4..ee8741c 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,8 @@ +2005-07-12 Miklos Szeredi + + * lib: don't block signals in worker threads. Problem noticed by + Usarin Heininga + 2005-07-07 Miklos Szeredi * lib: don't allow both 'allow_other' and 'allow_root' options to diff --git a/include/fuse_lowlevel.h b/include/fuse_lowlevel.h index e90cb84..673493e 100644 --- a/include/fuse_lowlevel.h +++ b/include/fuse_lowlevel.h @@ -6,13 +6,31 @@ See the file COPYING.LIB. */ +#ifndef _FUSE_LOWLEVEL_H_ +#define _FUSE_LOWLEVEL_H_ + /* ----------------------------------------------------------- * * Low level API * * ----------------------------------------------------------- */ +#include + +#ifdef __cplusplus +extern "C" { +#endif + typedef unsigned long fuse_ino_t; typedef struct fuse_req *fuse_req_t; +struct fuse_entry_param { + fuse_ino_t ino; + unsigned long generation; + const struct stat *attr; + double attr_timeout; + double entry_timeout; + unsigned int direct_io : 1; +}; + /* 'to_set' flags in setattr */ #define FUSE_SET_ATTR_MODE (1 << 0) #define FUSE_SET_ATTR_UID (1 << 1) @@ -26,6 +44,8 @@ struct fuse_lowlevel_operations { void (*lookup) (fuse_req_t req, fuse_ino_t parent, const char *name); void (*forget) (fuse_req_t req, fuse_ino_t ino); void (*getattr) (fuse_req_t req, fuse_ino_t ino); + void (*setattr) (fuse_req_t req, fuse_ino_t ino, struct stat *attr, + int to_set); void (*readlink)(fuse_req_t req, fuse_ino_t ino); void (*mknod) (fuse_req_t req, fuse_ino_t parent, const char *name, mode_t mode, dev_t rdev); @@ -39,8 +59,6 @@ struct fuse_lowlevel_operations { fuse_ino_t newparent, const char *newname); void (*link) (fuse_req_t req, fuse_ino_t ino, fuse_ino_t newparent, const char *newname); - void (*setattr) (fuse_req_t req, fuse_ino_t ino, struct stat *attr, - int to_set); void (*open) (fuse_req_t req, fuse_ino_t ino, struct fuse_file_info *f); void (*read) (fuse_req_t req, fuse_ino_t ino, size_t size, off_t off, struct fuse_file_info *f); @@ -48,13 +66,15 @@ struct fuse_lowlevel_operations { size_t size, off_t off, struct fuse_file_info *f); void (*flush) (fuse_req_t req, fuse_ino_t ino, struct fuse_file_info *f); void (*release) (fuse_req_t req, fuse_ino_t ino, struct fuse_file_info *f); - void (*fsync) (fuse_req_t req, fuse_ino_t ino, struct fuse_file_info *f); + void (*fsync) (fuse_req_t req, fuse_ino_t ino, int datasync, + struct fuse_file_info *f); void (*opendir) (fuse_req_t req, fuse_ino_t ino, struct fuse_file_info *f); void (*readdir) (fuse_req_t req, fuse_ino_t ino, size_t size, off_t off, struct fuse_file_info *f); void (*releasedir) (fuse_req_t req, fuse_ino_t ino, struct fuse_file_info *f); - void (*fsyncdir) (fuse_req_t req, fuse_ino_t ino, struct fuse_file_info *f); + void (*fsyncdir) (fuse_req_t req, fuse_ino_t ino, int datasync, + struct fuse_file_info *f); void (*statfs) (fuse_req_t req, fuse_ino_t ino); void (*setxattr)(fuse_req_t req, fuse_ino_t ino, const char *name, const char *value, size_t size, int flags); @@ -71,18 +91,20 @@ int fuse_reply_err(fuse_req_t req, int err); int fuse_reply_ok(fuse_req_t req); /* lookup, mknod, mkdir, symlink, link */ -int fuse_reply_entry(fuse_req_t req, fuse_ino_t ino, unsigned long generation, - const struct stat *attr, double attr_timeout, - double entry_timeout); +int fuse_reply_entry(fuse_req_t req, struct fuse_entry_param *e); /* getattr, setattr */ int fuse_reply_attr(fuse_req_t req, int struct stat *attr, double attr_timeout); /* readlink */ int fuse_reply_readlink(fuse_req_t req, const char *link); -/* open, write, flush, fsync, opendir, fsyncdir */ +/* open, flush, fsync, opendir, fsyncdir */ int fuse_reply_file_info(fuse_req_t req, const struct fuse_file_info *f); +/* write */ +int fuse_reply_write(fuse_req_t req, size_t count, + const struct fuse_file_info *f); + /* read, readdir */ int fuse_reply_buf(fuse_req_t req, const char *buf, size_t size, const struct fuse_file_info *f); @@ -97,5 +119,11 @@ int fuse_reply_xattr(fuse_req_t req, const char *buf, size_t size); size_t fuse_dirent_size(size_t namelen); /* add a directory entry to the buffer */ -int fuse_add_dirent(char *buf, const char *name, const struct stat *stat, - off_t off); +void fuse_add_dirent(char *buf, const char *name, const struct stat *stat, + off_t off); + +#ifdef __cplusplus +} +#endif + +#endif /* _FUSE_LOWLEVEL_H_ */ diff --git a/lib/fuse_lowlevel.c b/lib/fuse_lowlevel.c index c5e1bf7..b21a8fe 100644 --- a/lib/fuse_lowlevel.c +++ b/lib/fuse_lowlevel.c @@ -22,39 +22,11 @@ #include #include -/* FUSE flags: */ - -/** Enable debuging output */ -#define FUSE_DEBUG (1 << 1) - -/** If a file is removed but it's still open, don't hide the file but - remove it immediately */ -#define FUSE_HARD_REMOVE (1 << 2) - -/** Use st_ino field in getattr instead of generating inode numbers */ -#define FUSE_USE_INO (1 << 3) - -/** Only allow root or the owner to access the filesystem */ -#define FUSE_ALLOW_ROOT (1 << 4) - -/** Make a best effort to fill in inode number in a readdir **/ -#define FUSE_READDIR_INO (1 << 5) - -/** Ignore file mode supplied by the filesystem, and create one based - on the 'umask' option */ -#define FUSE_SET_MODE (1 << 6) - -/** Ignore st_uid supplied by the filesystem and set it based on the - 'uid' option*/ -#define FUSE_SET_UID (1 << 7) - -/** Ignore st_gid supplied by the filesystem and set it based on the - 'gid' option*/ -#define FUSE_SET_GID (1 << 8) - +#define PARAM(inarg) (((char *)(inarg)) + sizeof(*(inarg))) struct fuse_ll { - int flags; + unsigned int debug : 1; + unsigned int allow_root : 1; int fd; struct fuse_lowlevel_operations op; volatile int exited; @@ -63,9 +35,6 @@ struct fuse_ll { int major; int minor; uid_t owner; - uid_t uid; - gid_t gid; - mode_t umask; }; struct fuse_cmd { @@ -108,17 +77,13 @@ static const char *opname(enum fuse_opcode opcode) } } - -static void convert_stat(struct fuse_ll *f, nodeid_t nodeid, struct stat *stbuf, - struct fuse_attr *attr) +static void convert_stat(struct stat *stbuf, struct fuse_attr *attr) { - attr->ino = (f->flags & FUSE_USE_INO) ? stbuf->st_ino : nodeid; + attr->ino = stbuf->st_ino; attr->mode = stbuf->st_mode; - if (f->flags & FUSE_SET_MODE) - attr->mode = (attr->mode & S_IFMT) | (0777 & ~f->umask); attr->nlink = stbuf->st_nlink; - attr->uid = (f->flags & FUSE_SET_UID) ? f->uid : stbuf->st_uid; - attr->gid = (f->flags & FUSE_SET_GID) ? f->gid : stbuf->st_gid; + attr->uid = stbuf->st_uid; + attr->gid = stbuf->st_gid; attr->rdev = stbuf->st_rdev; attr->size = stbuf->st_size; attr->blocks = stbuf->st_blocks; @@ -196,705 +161,294 @@ static int send_reply(struct fuse_ll *f, struct fuse_in_header *in, int error, return send_reply_raw(f, iov, count); } -static void do_lookup(struct fuse_ll *f, struct fuse_in_header *in, char *name) -{ - int res; - int res2; - char *path; - struct fuse_entry_out arg; - - res = -ENOENT; - pthread_rwlock_rdlock(&f->tree_lock); - path = get_path_name(f, in->nodeid, name); - if (path != NULL) { - if (f->flags & FUSE_DEBUG) { - printf("LOOKUP %s\n", path); - fflush(stdout); - } - res = -ENOSYS; - if (f->op.getattr) - res = lookup_path(f, in->nodeid, in->unique, name, path, &arg); - free(path); - } - pthread_rwlock_unlock(&f->tree_lock); - res2 = send_reply(f, in, res, &arg, sizeof(arg)); - if (res == 0 && res2 == -ENOENT) - cancel_lookup(f, arg.nodeid, in->unique); -} - -static void do_forget(struct fuse_ll *f, struct fuse_in_header *in, - struct fuse_forget_in *arg) +size_t fuse_dirent_size(size_t namelen) { - if (f->flags & FUSE_DEBUG) { - printf("FORGET %lu/%llu\n", (unsigned long) in->nodeid, - arg->nlookup); - fflush(stdout); - } - if (f->major <= 6) - forget_node_old(f, in->nodeid, arg->nlookup); - else - forget_node(f, in->nodeid, arg->nlookup); + return FUSE_DIRENT_ALIGN(FUSE_NAME_OFFSET + namelen); } -static void do_getattr(struct fuse_ll *f, struct fuse_in_header *in) +void fuse_add_dirent(char *buf, const char *name, const struct stat *stat, + off_t off) { - int res; - char *path; - struct stat buf; - struct fuse_attr_out arg; - - res = -ENOENT; - pthread_rwlock_rdlock(&f->tree_lock); - path = get_path(f, in->nodeid); - if (path != NULL) { - res = -ENOSYS; - if (f->op.getattr) - res = f->op.getattr(path, &buf); - free(path); - } - pthread_rwlock_unlock(&f->tree_lock); - - if (res == 0) { - memset(&arg, 0, sizeof(struct fuse_attr_out)); - arg.attr_valid = ATTR_REVALIDATE_TIME; - arg.attr_valid_nsec = 0; - convert_stat(f, in->nodeid, &buf, &arg.attr); - } + unsigned namelen = strlen(name); + unsigned entlen = FUSE_NAME_OFFSET + namelen; + unsigned entsize = fuse_dirent_size(namelen); + unsigned padlen = entsize - entlen; + struct fuse_dirent *dirent = (struct fuse_dirent *) buf; + + dirent->ino = stat->st_ino; + dirent->off = off; + dirent->namelen = namelen; + dirent->type = (stat->st_mode & 0170000) >> 12; + strncpy(dirent->name, name, namelen); + if (padlen) + memset(buf + entlen, 0, padlen); - send_reply(f, in, res, &arg, sizeof(arg)); + return 0; } -static int do_chmod(struct fuse_ll *f, const char *path, struct fuse_attr *attr) +static void convert_statfs(struct statfs *statfs, struct fuse_kstatfs *kstatfs) { - int res; - - res = -ENOSYS; - if (f->op.chmod) - res = f->op.chmod(path, attr->mode); - - return res; + kstatfs->bsize = statfs->f_bsize; + kstatfs->blocks = statfs->f_blocks; + kstatfs->bfree = statfs->f_bfree; + kstatfs->bavail = statfs->f_bavail; + kstatfs->files = statfs->f_files; + kstatfs->ffree = statfs->f_ffree; + kstatfs->namelen = statfs->f_namelen; } -static int do_chown(struct fuse_ll *f, const char *path, struct fuse_attr *attr, - int valid) +static void do_lookup(fuse_req_t req, fuse_ino_t nodeid, char *name) { - int res; - uid_t uid = (valid & FATTR_UID) ? attr->uid : (uid_t) -1; - gid_t gid = (valid & FATTR_GID) ? attr->gid : (gid_t) -1; - - res = -ENOSYS; - if (f->op.chown) - res = f->op.chown(path, uid, gid); - - return res; + if (req->f->op.lookup) + req->f->op.lookup(req, nodeid, name); + else + fuse_reply_err(req, ENOSYS); } -static int do_truncate(struct fuse_ll *f, const char *path, - struct fuse_attr *attr) +static void do_forget(fuse_req_t req, fuse_ino_t nodeid) { - int res; - - res = -ENOSYS; - if (f->op.truncate) - res = f->op.truncate(path, attr->size); - - return res; + if (req->f->op.forget) + req->f->op.forget(req, nodeid); } -static int do_utime(struct fuse_ll *f, const char *path, struct fuse_attr *attr) +static void do_getattr(fuse_req_t req, fuse_ino_t nodeid) { - int res; - struct utimbuf buf; - buf.actime = attr->atime; - buf.modtime = attr->mtime; - res = -ENOSYS; - if (f->op.utime) - res = f->op.utime(path, &buf); - - return res; + if (req->f->op.getattr) + req->f->op.getattr(req, nodeid); + else + fuse_reply_err(req, ENOSYS); } -static void do_setattr(struct fuse_ll *f, struct fuse_in_header *in, +static void do_setattr(fuse_req_t req, fuse_ino_t nodeid, struct fuse_setattr_in *arg) { - int res; - char *path; - int valid = arg->valid; - struct fuse_attr *attr = MEMBER_COMPAT(f, arg, attr, fuse_setattr_in); - struct fuse_attr_out outarg; - - res = -ENOENT; - pthread_rwlock_rdlock(&f->tree_lock); - path = get_path(f, in->nodeid); - if (path != NULL) { - res = -ENOSYS; - if (f->op.getattr) { - res = 0; - if (!res && (valid & FATTR_MODE)) - res = do_chmod(f, path, attr); - if (!res && (valid & (FATTR_UID | FATTR_GID))) - res = do_chown(f, path, attr, valid); - if (!res && (valid & FATTR_SIZE)) - res = do_truncate(f, path, attr); - if (!res && (valid & (FATTR_ATIME | FATTR_MTIME)) == - (FATTR_ATIME | FATTR_MTIME)) - res = do_utime(f, path, attr); - if (!res) { - struct stat buf; - res = f->op.getattr(path, &buf); - if (!res) { - memset(&outarg, 0, sizeof(struct fuse_attr_out)); - outarg.attr_valid = ATTR_REVALIDATE_TIME; - outarg.attr_valid_nsec = 0; - convert_stat(f, in->nodeid, &buf, &outarg.attr); - } - } - } - free(path); - } - pthread_rwlock_unlock(&f->tree_lock); - send_reply(f, in, res, &outarg, sizeof(outarg)); + if (req->f->op.setattr) + req->f->op.setattr(req, nodeid, &arg->attr, arg->valid); + else + fuse_reply_err(req, ENOSYS); } -static void do_readlink(struct fuse_ll *f, struct fuse_in_header *in) +static void do_readlink(fuse_req_t req, fuse_ino_t nodeid) { - int res; - char link[PATH_MAX + 1]; - char *path; - - res = -ENOENT; - pthread_rwlock_rdlock(&f->tree_lock); - path = get_path(f, in->nodeid); - if (path != NULL) { - res = -ENOSYS; - if (f->op.readlink) - res = f->op.readlink(path, link, sizeof(link)); - free(path); - } - pthread_rwlock_unlock(&f->tree_lock); - link[PATH_MAX] = '\0'; - send_reply(f, in, res, link, res == 0 ? strlen(link) : 0); + if (req->f->op.readlink) + req->f->op.readlink(req, nodeid); + else + fuse_reply_err(req, ENOSYS); } -static void do_mknod(struct fuse_ll *f, struct fuse_in_header *in, - struct fuse_mknod_in *inarg) +static void do_mknod(fuse_req_t req, fuse_ino_t nodeid, + struct fuse_mknod_in *arg) { - int res; - int res2; - char *path; - char *name = PARAM(inarg); - struct fuse_entry_out outarg; - - res = -ENOENT; - pthread_rwlock_rdlock(&f->tree_lock); - path = get_path_name(f, in->nodeid, name); - if (path != NULL) { - if (f->flags & FUSE_DEBUG) { - printf("MKNOD %s\n", path); - fflush(stdout); - } - res = -ENOSYS; - if (f->op.mknod && f->op.getattr) { - res = f->op.mknod(path, inarg->mode, inarg->rdev); - if (res == 0) - res = lookup_path(f, in->nodeid, in->unique, name, path, &outarg); - } - free(path); - } - pthread_rwlock_unlock(&f->tree_lock); - res2 = send_reply(f, in, res, &outarg, sizeof(outarg)); - if (res == 0 && res2 == -ENOENT) - cancel_lookup(f, outarg.nodeid, in->unique); + if (req->f->op.mknod) + req->f->op.mknod(req, nodeid, PARAM(arg), arg->mode, arg->rdev); + else + fuse_reply_err(req, ENOSYS); } -static void do_mkdir(struct fuse_ll *f, struct fuse_in_header *in, - struct fuse_mkdir_in *inarg) +static void do_mkdir(fuse_req_t req, fuse_ino_t nodeid, + struct fuse_mkdir_in *arg) { - int res; - int res2; - char *path; - char *name = PARAM_COMPAT(f, inarg, fuse_mkdir_in); - struct fuse_entry_out outarg; - - res = -ENOENT; - pthread_rwlock_rdlock(&f->tree_lock); - path = get_path_name(f, in->nodeid, name); - if (path != NULL) { - if (f->flags & FUSE_DEBUG) { - printf("MKDIR %s\n", path); - fflush(stdout); - } - res = -ENOSYS; - if (f->op.mkdir && f->op.getattr) { - res = f->op.mkdir(path, inarg->mode); - if (res == 0) - res = lookup_path(f, in->nodeid, in->unique, name, path, &outarg); - } - free(path); - } - pthread_rwlock_unlock(&f->tree_lock); - res2 = send_reply(f, in, res, &outarg, sizeof(outarg)); - if (res == 0 && res2 == -ENOENT) - cancel_lookup(f, outarg.nodeid, in->unique); + if (req->f->op.mkdir) + req->f->op.mkdir(req, nodeid, PARAM(arg), arg->mode); + else + fuse_reply_err(req, ENOSYS); } -static void do_unlink(struct fuse_ll *f, struct fuse_in_header *in, char *name) +static void do_unlink(fuse_req_t req, fuse_ino_t nodeid, char *name) { - int res; - char *path; - - res = -ENOENT; - pthread_rwlock_wrlock(&f->tree_lock); - path = get_path_name(f, in->nodeid, name); - if (path != NULL) { - if (f->flags & FUSE_DEBUG) { - printf("UNLINK %s\n", path); - fflush(stdout); - } - res = -ENOSYS; - if (f->op.unlink) { - if (!(f->flags & FUSE_HARD_REMOVE) && is_open(f, in->nodeid, name)) - res = hide_node(f, path, in->nodeid, name); - else { - res = f->op.unlink(path); - if (res == 0) - remove_node(f, in->nodeid, name); - - } - } - free(path); - } - pthread_rwlock_unlock(&f->tree_lock); - send_reply(f, in, res, NULL, 0); + if (req->f->op.unlink) + req->f->op.unlink(req, nodeid, name); + else + fuse_reply_err(req, ENOSYS); } -static void do_rmdir(struct fuse_ll *f, struct fuse_in_header *in, char *name) +static void do_rmdir(fuse_req_t req, fuse_ino_t nodeid, char *name) { - int res; - char *path; - - res = -ENOENT; - pthread_rwlock_wrlock(&f->tree_lock); - path = get_path_name(f, in->nodeid, name); - if (path != NULL) { - if (f->flags & FUSE_DEBUG) { - printf("RMDIR %s\n", path); - fflush(stdout); - } - res = -ENOSYS; - if (f->op.rmdir) { - res = f->op.rmdir(path); - if (res == 0) - remove_node(f, in->nodeid, name); - } - free(path); - } - pthread_rwlock_unlock(&f->tree_lock); - send_reply(f, in, res, NULL, 0); + if (req->f->op.rmdir) + req->f->op.rmdir(req, nodeid, name); + else + fuse_reply_err(req, ENOSYS); } -static void do_symlink(struct fuse_ll *f, struct fuse_in_header *in, char *name, +static void do_symlink(fuse_req_t req, fuse_ino_t nodeid, char *name, char *link) { - int res; - int res2; - char *path; - struct fuse_entry_out outarg; - - res = -ENOENT; - pthread_rwlock_rdlock(&f->tree_lock); - path = get_path_name(f, in->nodeid, name); - if (path != NULL) { - if (f->flags & FUSE_DEBUG) { - printf("SYMLINK %s\n", path); - fflush(stdout); - } - res = -ENOSYS; - if (f->op.symlink && f->op.getattr) { - res = f->op.symlink(link, path); - if (res == 0) - res = lookup_path(f, in->nodeid, in->unique, name, path, &outarg); - } - free(path); - } - pthread_rwlock_unlock(&f->tree_lock); - res2 = send_reply(f, in, res, &outarg, sizeof(outarg)); - if (res == 0 && res2 == -ENOENT) - cancel_lookup(f, outarg.nodeid, in->unique); - + if (req->f->op.symlink) + req->f->op.symlink(req, link, nodeid, name); + else + fuse_reply_err(req, ENOSYS); } -static void do_rename(struct fuse_ll *f, struct fuse_in_header *in, - struct fuse_rename_in *inarg) +static void do_rename(fuse_req_t req, fuse_ino_t nodeid, + struct fuse_rename_in *arg) { - int res; - nodeid_t olddir = in->nodeid; - nodeid_t newdir = inarg->newdir; - char *oldname = PARAM(inarg); + char *oldname = PARAM(arg); char *newname = oldname + strlen(oldname) + 1; - char *oldpath; - char *newpath; - res = -ENOENT; - pthread_rwlock_wrlock(&f->tree_lock); - oldpath = get_path_name(f, olddir, oldname); - if (oldpath != NULL) { - newpath = get_path_name(f, newdir, newname); - if (newpath != NULL) { - if (f->flags & FUSE_DEBUG) { - printf("RENAME %s -> %s\n", oldpath, newpath); - fflush(stdout); - } - res = -ENOSYS; - if (f->op.rename) { - res = 0; - if (!(f->flags & FUSE_HARD_REMOVE) && - is_open(f, newdir, newname)) - res = hide_node(f, newpath, newdir, newname); - if (res == 0) { - res = f->op.rename(oldpath, newpath); - if (res == 0) - res = rename_node(f, olddir, oldname, newdir, newname, 0); - } - } - free(newpath); - } - free(oldpath); - } - pthread_rwlock_unlock(&f->tree_lock); - send_reply(f, in, res, NULL, 0); + if (req->f->op.rename) + req->f->op.rename(req, nodeid, oldname, arg->newdir, newname); + else + fuse_reply_err(req, ENOSYS); } -static void do_link(struct fuse_ll *f, struct fuse_in_header *in, +static void do_link(fuse_req_t req, fuse_ino_t nodeid, struct fuse_link_in *arg) { - int res; - int res2; - char *oldpath; - char *newpath; - char *name = PARAM(arg); - struct fuse_entry_out outarg; - - res = -ENOENT; - pthread_rwlock_rdlock(&f->tree_lock); - oldpath = get_path(f, arg->oldnodeid); - if (oldpath != NULL) { - newpath = get_path_name(f, in->nodeid, name); - if (newpath != NULL) { - if (f->flags & FUSE_DEBUG) { - printf("LINK %s\n", newpath); - fflush(stdout); - } - res = -ENOSYS; - if (f->op.link && f->op.getattr) { - res = f->op.link(oldpath, newpath); - if (res == 0) - res = lookup_path(f, in->nodeid, in->unique, name, - newpath, &outarg); - } - free(newpath); - } - free(oldpath); - } - pthread_rwlock_unlock(&f->tree_lock); - res2 = send_reply(f, in, res, &outarg, sizeof(outarg)); - if (res == 0 && res2 == -ENOENT) - cancel_lookup(f, outarg.nodeid, in->unique); + if (req->f->op.link) + req->f->op.link(req, arg->oldnodeid, nodeid, PARAM(arg)); + else + fuse_reply_err(req, ENOSYS); } -static void do_open(struct fuse_ll *f, struct fuse_in_header *in, +static void do_open(fuse_req_t req, fuse_ino_t nodeid, struct fuse_open_in *arg) { - int res; - char *path; - struct fuse_open_out outarg; struct fuse_file_info fi; - memset(&outarg, 0, sizeof(outarg)); memset(&fi, 0, sizeof(fi)); fi.flags = arg->flags; - res = -ENOENT; - pthread_rwlock_rdlock(&f->tree_lock); - path = get_path(f, in->nodeid); - if (path != NULL) { - res = -ENOSYS; - if (f->op.open) { - if (!f->compat) - res = f->op.open(path, &fi); - else - res = ((struct fuse_operations_compat2 *) &f->op)->open(path, fi.flags); - } - } - if (res == 0) { - int res2; - outarg.fh = fi.fh; - if (f->flags & FUSE_DEBUG) { - printf("OPEN[%lu] flags: 0x%x\n", fi.fh, arg->flags); - fflush(stdout); - } - - pthread_mutex_lock(&f->lock); - res2 = send_reply(f, in, res, &outarg, SIZEOF_COMPAT(f, fuse_open_out)); - if(res2 == -ENOENT) { - /* The open syscall was interrupted, so it must be cancelled */ - if(f->op.release) { - if (!f->compat) - f->op.release(path, &fi); - else - ((struct fuse_operations_compat2 *) &f->op)->release(path, fi.flags); - } - } else { - struct node *node = get_node(f, in->nodeid); - node->open_count ++; - } - pthread_mutex_unlock(&f->lock); - } else - send_reply(f, in, res, NULL, 0); - if (path) - free(path); - pthread_rwlock_unlock(&f->tree_lock); + if (req->f->op.open) + req->f->op.open(req, nodeid, &fi); + else + fuse_reply_err(req, ENOSYS); } -static void do_flush(struct fuse_ll *f, struct fuse_in_header *in, - struct fuse_flush_in *arg) +static void do_read(fuse_req_t req, fuse_ino_t nodeid, + struct fuse_read_in *arg) { - char *path; - int res; struct fuse_file_info fi; memset(&fi, 0, sizeof(fi)); fi.fh = arg->fh; - res = -ENOENT; - pthread_rwlock_rdlock(&f->tree_lock); - path = get_path(f, in->nodeid); - if (path != NULL) { - if (f->flags & FUSE_DEBUG) { - printf("FLUSH[%lu]\n", (unsigned long) arg->fh); - fflush(stdout); - } - res = -ENOSYS; - if (f->op.flush) - res = f->op.flush(path, &fi); - free(path); - } - pthread_rwlock_unlock(&f->tree_lock); - send_reply(f, in, res, NULL, 0); + + if (req->f->op.read) + req->f->op.read(req, nodeid, arg->size, arg->offset, &fi); + else + fuse_reply_err(req, ENOSYS); } -static void do_release(struct fuse_ll *f, struct fuse_in_header *in, - struct fuse_release_in *arg) +static void do_write(fuse_req_t req, fuse_ino_t nodeid, + struct fuse_write_in *arg) { - struct node *node; - char *path; struct fuse_file_info fi; - int unlink_hidden; memset(&fi, 0, sizeof(fi)); - fi.flags = arg->flags; fi.fh = arg->fh; + fi.writepage = arg->write_flags & 1; - pthread_mutex_lock(&f->lock); - node = get_node(f, in->nodeid); - assert(node->open_count > 0); - --node->open_count; - unlink_hidden = (node->is_hidden && !node->open_count); - pthread_mutex_unlock(&f->lock); - - pthread_rwlock_rdlock(&f->tree_lock); - path = get_path(f, in->nodeid); - if (f->flags & FUSE_DEBUG) { - printf("RELEASE[%lu] flags: 0x%x\n", fi.fh, fi.flags); - fflush(stdout); - } - if (f->op.release) { - if (!f->compat) - f->op.release(path ? path : "-", &fi); - else if (path) - ((struct fuse_operations_compat2 *) &f->op)->release(path, fi.flags); - } - - if(unlink_hidden && path) - f->op.unlink(path); - - if (path) - free(path); - pthread_rwlock_unlock(&f->tree_lock); - - send_reply(f, in, 0, NULL, 0); + if (req->f->op.write) + req->f->op.write(req, nodeid, PARAM(arg), arg->size, arg->offset, &fi); + else + fuse_reply_err(req, ENOSYS); } -static void do_read(struct fuse_ll *f, struct fuse_in_header *in, - struct fuse_read_in *arg) +static void do_flush(fuse_req_t req, fuse_ino_t nodeid, + struct fuse_flush_in *arg) { - int res; - char *path; - size_t size; - char *buf; struct fuse_file_info fi; - buf = (char *) malloc(arg->size); - if (buf == NULL) { - send_reply(f, in, -ENOMEM, NULL, 0); - return; - } - memset(&fi, 0, sizeof(fi)); fi.fh = arg->fh; - res = -ENOENT; - pthread_rwlock_rdlock(&f->tree_lock); - path = get_path(f, in->nodeid); - if (path != NULL) { - if (f->flags & FUSE_DEBUG) { - printf("READ[%lu] %u bytes from %llu\n", - (unsigned long) arg->fh, arg->size, arg->offset); - fflush(stdout); - } - - res = -ENOSYS; - if (f->op.read) - res = f->op.read(path, buf, arg->size, arg->offset, &fi); - free(path); - } - pthread_rwlock_unlock(&f->tree_lock); - - size = 0; - if (res >= 0) { - size = res; - res = 0; - if (f->flags & FUSE_DEBUG) { - printf(" READ[%lu] %u bytes\n", (unsigned long) arg->fh, - size); - fflush(stdout); - } - } - - send_reply(f, in, res, buf, size); - free(buf); + if (req->f->op.flush) + req->f->op.flush(req, nodeid, &fi); + else + fuse_reply_err(req, ENOSYS); } -static void do_write(struct fuse_ll *f, struct fuse_in_header *in, - struct fuse_write_in *arg) +static void do_release(fuse_req_t req, fuse_ino_t nodeid, + struct fuse_release_in *arg) { - int res; - char *path; - struct fuse_write_out outarg; struct fuse_file_info fi; memset(&fi, 0, sizeof(fi)); + fi.flags = arg->flags; fi.fh = arg->fh; - fi.writepage = arg->write_flags & 1; - res = -ENOENT; - pthread_rwlock_rdlock(&f->tree_lock); - path = get_path(f, in->nodeid); - if (path != NULL) { - if (f->flags & FUSE_DEBUG) { - printf("WRITE%s[%lu] %u bytes to %llu\n", - (arg->write_flags & 1) ? "PAGE" : "", - (unsigned long) arg->fh, arg->size, arg->offset); - fflush(stdout); - } + if (req->f->op.release) + req->f->op.release(req, nodeid, &fi); + else + fuse_reply_err(req, ENOSYS); +} - res = -ENOSYS; - if (f->op.write) - res = f->op.write(path, PARAM(arg), arg->size, arg->offset, &fi); - free(path); - } - pthread_rwlock_unlock(&f->tree_lock); +static void do_fsync(fuse_req_t req, fuse_ino_t nodeid, + struct fuse_fsync_in *inarg) +{ + struct fuse_file_info fi; - memset(&outarg, 0, sizeof(outarg)); - if (res >= 0) { - outarg.size = res; - res = 0; - } + memset(&fi, 0, sizeof(fi)); + fi.fh = inarg->fh; - send_reply(f, in, res, &outarg, SIZEOF_COMPAT(f, fuse_write_out)); + if (req->f->op.fsync) + req->f->op.fsync(req, nodeid, inarg->fsync_flags & 1, &fi); + else + fuse_reply_err(req, ENOSYS); } -static int default_statfs(struct statfs *buf) +static void do_opendir(fuse_req_t req, fuse_ino_t nodeid, + struct fuse_open_in *arg) { - buf->f_namelen = 255; - buf->f_bsize = 512; - return 0; -} + struct fuse_file_info fi; -static void convert_statfs_compat(struct fuse_statfs_compat1 *compatbuf, - struct statfs *statfs) -{ - statfs->f_bsize = compatbuf->block_size; - statfs->f_blocks = compatbuf->blocks; - statfs->f_bfree = compatbuf->blocks_free; - statfs->f_bavail = compatbuf->blocks_free; - statfs->f_files = compatbuf->files; - statfs->f_ffree = compatbuf->files_free; - statfs->f_namelen = compatbuf->namelen; + memset(&fi, 0, sizeof(fi)); + fi.flags = arg->flags; + + if (req->f->op.opendir) + req->f->op.opendir(req, nodeid, &fi); + else + fuse_reply_err(req, ENOSYS); } -static void convert_statfs(struct statfs *statfs, struct fuse_kstatfs *kstatfs) +static void do_readdir(fuse_req_t req, fuse_ino_t nodeid, + struct fuse_read_in *arg) { - kstatfs->bsize = statfs->f_bsize; - kstatfs->blocks = statfs->f_blocks; - kstatfs->bfree = statfs->f_bfree; - kstatfs->bavail = statfs->f_bavail; - kstatfs->files = statfs->f_files; - kstatfs->ffree = statfs->f_ffree; - kstatfs->namelen = statfs->f_namelen; + struct fuse_file_info fi; + + memset(&fi, 0, sizeof(fi)); + fi.fh = arg->fh; + + if (req->f->op.readdir) + req->f->op.readdir(req, nodeid, arg->size, arg->offset, &fi); + else + fuse_reply_err(req, ENOSYS); } -static void do_statfs(struct fuse_ll *f, struct fuse_in_header *in) +static void do_releasedir(fuse_req_t req, fuse_ino_t nodeid, + struct fuse_release_in *arg) { - int res; - struct fuse_statfs_out arg; - struct statfs buf; - - memset(&buf, 0, sizeof(struct statfs)); - if (f->op.statfs) { - if (!f->compat || f->compat > 11) - res = f->op.statfs("/", &buf); - else { - struct fuse_statfs_compat1 compatbuf; - memset(&compatbuf, 0, sizeof(struct fuse_statfs_compat1)); - res = ((struct fuse_operations_compat1 *) &f->op)->statfs(&compatbuf); - if (res == 0) - convert_statfs_compat(&compatbuf, &buf); - } - } - else - res = default_statfs(&buf); + struct fuse_file_info fi; - if (res == 0) - convert_statfs(&buf, &arg.st); + memset(&fi, 0, sizeof(fi)); + fi.flags = arg->flags; + fi.fh = arg->fh; - send_reply(f, in, res, &arg, sizeof(arg)); + if (req->f->op.releasedir) + req->f->op.releasedir(req, nodeid, &fi); + else + fuse_reply_err(req, ENOSYS); } -static void do_fsync(struct fuse_ll *f, struct fuse_in_header *in, - struct fuse_fsync_in *inarg) +static void do_fsyncdir(fuse_req_t req, fuse_ino_t nodeid, + struct fuse_fsync_in *inarg) { - int res; - char *path; struct fuse_file_info fi; memset(&fi, 0, sizeof(fi)); fi.fh = inarg->fh; - res = -ENOENT; - pthread_rwlock_rdlock(&f->tree_lock); - path = get_path(f, in->nodeid); - if (path != NULL) { - if (f->flags & FUSE_DEBUG) { - printf("FSYNC[%lu]\n", (unsigned long) inarg->fh); - fflush(stdout); - } - res = -ENOSYS; - if (f->op.fsync) - res = f->op.fsync(path, inarg->fsync_flags & 1, &fi); - free(path); - } - pthread_rwlock_unlock(&f->tree_lock); - send_reply(f, in, res, NULL, 0); + if (req->f->op.fsyncdir) + req->f->op.fsyncdir(req, nodeid, inarg->fsync_flags & 1, &fi); + else + fuse_reply_err(req, ENOSYS); +} + +static void do_statfs(fuse_req_t req, fuse_ino_t nodeid) +{ + if (req->f->op.statfs) + res = req->f->op.statfs(req, nodeid); + else + fuse_reply_err(req, ENOSYS); } static void do_setxattr(struct fuse_ll *f, struct fuse_in_header *in, @@ -1102,267 +656,6 @@ static void do_init(struct fuse_ll *f, struct fuse_in_header *in, send_reply(f, in, 0, &outarg, sizeof(outarg)); } -static struct fuse_dirhandle *get_dirhandle(unsigned long fh) -{ - return (struct fuse_dirhandle *) fh; -} - -static void do_opendir(struct fuse_ll *f, struct fuse_in_header *in, - struct fuse_open_in *arg) -{ - int res; - struct fuse_open_out outarg; - struct fuse_dirhandle *dh; - - dh = (struct fuse_dirhandle *) malloc(sizeof(struct fuse_dirhandle)); - if (dh == NULL) { - send_reply(f, in, -ENOMEM, NULL, 0); - return; - } - memset(dh, 0, sizeof(struct fuse_dirhandle)); - dh->fuse = f; - dh->contents = NULL; - dh->len = 0; - dh->filled = 0; - dh->nodeid = in->nodeid; - mutex_init(&dh->lock); - - memset(&outarg, 0, sizeof(outarg)); - outarg.fh = (unsigned long) dh; - - if (f->op.opendir) { - struct fuse_file_info fi; - char *path; - - memset(&fi, 0, sizeof(fi)); - fi.flags = arg->flags; - - res = -ENOENT; - pthread_rwlock_rdlock(&f->tree_lock); - path = get_path(f, in->nodeid); - if (path != NULL) { - res = f->op.opendir(path, &fi); - dh->fh = fi.fh; - } - if (res == 0) { - int res2; - pthread_mutex_lock(&f->lock); - res2 = send_reply(f, in, res, &outarg, SIZEOF_COMPAT(f, fuse_open_out)); - if(res2 == -ENOENT) { - /* The opendir syscall was interrupted, so it must be - cancelled */ - if(f->op.releasedir) - f->op.releasedir(path, &fi); - pthread_mutex_destroy(&dh->lock); - free(dh); - } - pthread_mutex_unlock(&f->lock); - } else { - send_reply(f, in, res, NULL, 0); - free(dh); - } - free(path); - pthread_rwlock_unlock(&f->tree_lock); - } else - send_reply(f, in, 0, &outarg, SIZEOF_COMPAT(f, fuse_open_out)); -} - -static int fill_dir_common(struct fuse_dirhandle *dh, const char *name, - int type, ino_t ino, off_t off) -{ - unsigned namelen = strlen(name); - unsigned entlen; - unsigned entsize; - unsigned padlen; - unsigned newlen; - unsigned char *newptr; - - if (!(dh->fuse->flags & FUSE_USE_INO)) { - ino = (ino_t) -1; - if (dh->fuse->flags & FUSE_READDIR_INO) { - struct node *node; - pthread_mutex_lock(&dh->fuse->lock); - node = lookup_node(dh->fuse, dh->nodeid, name); - if (node) - ino = (ino_t) node->nodeid; - pthread_mutex_unlock(&dh->fuse->lock); - } - } - - if (namelen > FUSE_NAME_MAX) - namelen = FUSE_NAME_MAX; - else if (!namelen) { - dh->error = -EIO; - return 1; - } - - entlen = (dh->fuse->major == 5 ? - FUSE_NAME_OFFSET_COMPAT5 : FUSE_NAME_OFFSET) + namelen; - entsize = FUSE_DIRENT_ALIGN(entlen); - padlen = entsize - entlen; - newlen = dh->len + entsize; - if (off && dh->fuse->major != 5) { - dh->filled = 0; - if (newlen > dh->needlen) - return 1; - } - - newptr = realloc(dh->contents, newlen); - if (!newptr) { - dh->error = -ENOMEM; - return 1; - } - dh->contents = newptr; - if (dh->fuse->major == 5) { - struct fuse_dirent_compat5 *dirent; - dirent = (struct fuse_dirent_compat5 *) (dh->contents + dh->len); - dirent->ino = ino; - dirent->namelen = namelen; - dirent->type = type; - strncpy(dirent->name, name, namelen); - } else { - struct fuse_dirent *dirent; - dirent = (struct fuse_dirent *) (dh->contents + dh->len); - dirent->ino = ino; - dirent->off = off ? off : newlen; - dirent->namelen = namelen; - dirent->type = type; - strncpy(dirent->name, name, namelen); - } - if (padlen) - memset(dh->contents + dh->len + entlen, 0, padlen); - dh->len = newlen; - return 0; -} - -static int fill_dir(void *buf, const char *name, const struct stat *stat, - off_t off) -{ - int type = stat ? (stat->st_mode & 0170000) >> 12 : 0; - ino_t ino = stat ? stat->st_ino : (ino_t) -1; - return fill_dir_common(buf, name, type, ino, off); -} - -static int fill_dir_old(struct fuse_dirhandle *dh, const char *name, int type, - ino_t ino) -{ - fill_dir_common(dh, name, type, ino, 0); - return dh->error; -} - -static int readdir_fill(struct fuse_ll *f, struct fuse_in_header *in, - struct fuse_read_in *arg, struct fuse_dirhandle *dh) -{ - int err = -ENOENT; - char *path; - pthread_rwlock_rdlock(&f->tree_lock); - path = get_path(f, in->nodeid); - if (path != NULL) { - struct fuse_file_info fi; - - memset(&fi, 0, sizeof(fi)); - fi.fh = dh->fh; - - dh->len = 0; - dh->error = 0; - dh->needlen = arg->size; - dh->filled = 1; - err = -ENOSYS; - if (f->op.readdir) { - off_t offset = f->major == 5 ? 0 : arg->offset; - err = f->op.readdir(path, dh, fill_dir, offset, &fi); - } else if (f->op.getdir) - err = f->op.getdir(path, dh, fill_dir_old); - if (!err) - err = dh->error; - if (err) - dh->filled = 0; - free(path); - } - pthread_rwlock_unlock(&f->tree_lock); - return err; -} - -static void do_readdir(struct fuse_ll *f, struct fuse_in_header *in, - struct fuse_read_in *arg) -{ - int err = 0; - struct fuse_dirhandle *dh = get_dirhandle(arg->fh); - size_t size = 0; - unsigned char *buf = NULL; - - pthread_mutex_lock(&dh->lock); - if (!dh->filled) { - err = readdir_fill(f, in, arg, dh); - if (err) - goto out; - } - if (dh->filled) { - if (arg->offset < dh->len) { - size = arg->size; - if (arg->offset + size > dh->len) - size = dh->len - arg->offset; - buf = dh->contents + arg->offset; - } - } else { - size = dh->len; - buf = dh->contents; - } - - out: - send_reply(f, in, err, buf, size); - pthread_mutex_unlock(&dh->lock); -} - -static void do_releasedir(struct fuse_ll *f, struct fuse_in_header *in, - struct fuse_release_in *arg) -{ - struct fuse_dirhandle *dh = get_dirhandle(arg->fh); - if (f->op.releasedir) { - char *path; - struct fuse_file_info fi; - - memset(&fi, 0, sizeof(fi)); - fi.fh = dh->fh; - - pthread_rwlock_rdlock(&f->tree_lock); - path = get_path(f, in->nodeid); - f->op.releasedir(path ? path : "-", &fi); - free(path); - pthread_rwlock_unlock(&f->tree_lock); - } - pthread_mutex_lock(&dh->lock); - pthread_mutex_unlock(&dh->lock); - pthread_mutex_destroy(&dh->lock); - free(dh->contents); - free(dh); - send_reply(f, in, 0, NULL, 0); -} - -static void do_fsyncdir(struct fuse_ll *f, struct fuse_in_header *in, - struct fuse_fsync_in *inarg) -{ - int res; - char *path; - struct fuse_dirhandle *dh = get_dirhandle(inarg->fh); - struct fuse_file_info fi; - - memset(&fi, 0, sizeof(fi)); - fi.fh = dh->fh; - - res = -ENOENT; - pthread_rwlock_rdlock(&f->tree_lock); - path = get_path(f, in->nodeid); - if (path != NULL) { - res = -ENOSYS; - if (f->op.fsyncdir) - res = f->op.fsyncdir(path, inarg->fsync_flags & 1, &fi); - free(path); - } - pthread_rwlock_unlock(&f->tree_lock); - send_reply(f, in, res, NULL, 0); -} - static void free_cmd(struct fuse_cmd *cmd) { free(cmd->buf); @@ -1407,9 +700,12 @@ void fuse_process_cmd(struct fuse_ll *f, struct fuse_cmd *cmd) switch (in->opcode) { case FUSE_LOOKUP: - do_lookup(f, in, (char *) inarg); + do_lookup(f, req, nodeid, (char *) inarg); break; + do_forget(f, in, (struct fuse_forget_in *) inarg); + break; + } case FUSE_GETATTR: do_getattr(f, in); break; @@ -1573,12 +869,6 @@ struct fuse_cmd *fuse_read_cmd(struct fuse_ll *f) } cmd->buflen = res; - /* Forget is special, it can be done without messing with threads. */ - if (in->opcode == FUSE_FORGET) { - do_forget(f, in, (struct fuse_forget_in *) inarg); - free_cmd(cmd); - return NULL; - } return cmd; } diff --git a/lib/fuse_mt.c b/lib/fuse_mt.c index 819a2b9..4864684 100644 --- a/lib/fuse_mt.c +++ b/lib/fuse_mt.c @@ -94,15 +94,7 @@ static void *do_work(void *data) static int start_thread(struct fuse_worker *w, pthread_t *thread_id) { - sigset_t oldset; - sigset_t newset; - int res; - - /* Disallow signal reception in worker threads */ - sigfillset(&newset); - pthread_sigmask(SIG_SETMASK, &newset, &oldset); - res = pthread_create(thread_id, NULL, do_work, w); - pthread_sigmask(SIG_SETMASK, &oldset, NULL); + 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; -- 2.30.2