From 0f48a2693f4259371e6438d6d83fae157e9f78e9 Mon Sep 17 00:00:00 2001 From: Miklos Szeredi Date: Thu, 5 Dec 2002 14:23:01 +0000 Subject: [PATCH] fixes --- ChangeLog | 7 +++ include/fuse.h | 33 ++++++++--- kernel/dev.c | 2 +- kernel/file.c | 5 +- lib/Makefile.am | 1 + lib/fuse.c | 54 ++++++++++++++---- lib/fuse_i.h | 1 + lib/fuse_mt.c | 9 ++- lib/helper.c | 143 +++++------------------------------------------- lib/mount.c | 136 +++++++++++++++++++++++++++++++++++++++++++++ 10 files changed, 237 insertions(+), 154 deletions(-) create mode 100644 lib/mount.c diff --git a/ChangeLog b/ChangeLog index 9b21b59..9a8286e 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,10 @@ +2002-12-05 Miklos Szeredi + + * 64 bit file offset fixes in the fuse kernel module + + * Added function 'fuse_exit()' which can be used to exit the main + loop + 2002-12-03 Miklos Szeredi * Added _FILE_OFFSET_BITS=64 define to fuse.h. Note, that this is diff --git a/include/fuse.h b/include/fuse.h index 68f8eec..28d5f3b 100644 --- a/include/fuse.h +++ b/include/fuse.h @@ -125,6 +125,13 @@ extern "C" { */ int fuse_mount(const char *mountpoint, const char *args[]); +/* + * Umount a FUSE mountpoint + * + * @param mountpoint the mount point path + */ +void fuse_unmount(const char *mountpoint); + /** * Create a new FUSE filesystem. * @@ -135,6 +142,15 @@ int fuse_mount(const char *mountpoint, const char *args[]); */ struct fuse *fuse_new(int fd, int flags, const struct fuse_operations *op); +/** + * Destroy the FUSE handle. + * + * The filesystem is not unmounted. + * + * @param f the FUSE handle + */ +void fuse_destroy(struct fuse *f); + /** * FUSE event loop. * @@ -145,6 +161,14 @@ struct fuse *fuse_new(int fd, int flags, const struct fuse_operations *op); */ void fuse_loop(struct fuse *f); + +/** + * Exit from event loop + * + * @param f the FUSE handle + */ +void fuse_exit(struct fuse *f); + /** * FUSE event loop with multiple threads * @@ -159,15 +183,6 @@ void fuse_loop(struct fuse *f); */ void fuse_loop_mt(struct fuse *f); -/** - * Destroy the FUSE handle. - * - * The filesystem is not unmounted. - * - * @param f the FUSE handle - */ -void fuse_destroy(struct fuse *f); - /** * Get the current context * diff --git a/kernel/dev.c b/kernel/dev.c index 7036153..7cf3844 100644 --- a/kernel/dev.c +++ b/kernel/dev.c @@ -241,7 +241,7 @@ static ssize_t fuse_dev_read(struct file *file, char *buf, size_t nbytes, if(fc->sb == NULL) return -ENODEV; if(req == NULL) - return -ERESTARTSYS; + return -EINTR; ret = copy_in_args(req->in, buf, nbytes); spin_lock(&fuse_lock); diff --git a/kernel/file.c b/kernel/file.c index 0622e51..14ba59b 100644 --- a/kernel/file.c +++ b/kernel/file.c @@ -53,7 +53,7 @@ static int fuse_readpage(struct file *file, struct page *page) buffer = kmap(page); memset(&inarg, 0, sizeof(inarg)); - inarg.offset = page->index << PAGE_CACHE_SHIFT; + inarg.offset = (unsigned long long) page->index << PAGE_CACHE_SHIFT; inarg.size = PAGE_CACHE_SIZE; in.h.opcode = FUSE_READ; @@ -92,7 +92,8 @@ static int write_buffer(struct inode *inode, struct page *page, buffer = kmap(page); memset(&inarg, 0, sizeof(inarg)); - inarg.offset = (page->index << PAGE_CACHE_SHIFT) + offset; + inarg.offset = ((unsigned long long) page->index << PAGE_CACHE_SHIFT) + + offset; inarg.size = count; in.h.opcode = FUSE_WRITE; diff --git a/lib/Makefile.am b/lib/Makefile.am index 5ecee0b..cf1de09 100644 --- a/lib/Makefile.am +++ b/lib/Makefile.am @@ -6,4 +6,5 @@ libfuse_a_SOURCES = \ fuse.c \ fuse_mt.c \ helper.c \ + mount.c fuse_i.h diff --git a/lib/fuse.c b/lib/fuse.c index 42ab52a..1a11ae6 100644 --- a/lib/fuse.c +++ b/lib/fuse.c @@ -355,8 +355,8 @@ static void send_reply(struct fuse *f, struct fuse_in_header *in, int error, size_t outsize; struct fuse_out_header *out; - if(error > 0) { - fprintf(stderr, "fuse: positive error code: %i\n", error); + if(error <= -512 || error > 0) { + fprintf(stderr, "fuse: bad error value: %i\n", error); error = -ERANGE; } @@ -366,6 +366,7 @@ static void send_reply(struct fuse *f, struct fuse_in_header *in, int error, outsize = sizeof(struct fuse_out_header) + argsize; outbuf = (char *) malloc(outsize); out = (struct fuse_out_header *) outbuf; + memset(out, 0, sizeof(struct fuse_out_header)); out->unique = in->unique; out->error = error; if(argsize != 0) @@ -395,7 +396,9 @@ static void do_lookup(struct fuse *f, struct fuse_in_header *in, char *name) res = f->op.getattr(path, &buf); free(path); } + if(res == 0) { + memset(&arg, 0, sizeof(struct fuse_lookup_out)); convert_stat(&buf, &arg.attr); arg.ino = find_node(f, in->ino, name, &arg.attr, in->unique); if(f->flags & FUSE_DEBUG) { @@ -431,8 +434,11 @@ static void do_getattr(struct fuse *f, struct fuse_in_header *in) res = f->op.getattr(path, &buf); free(path); } - if(res == 0) + + if(res == 0) { + memset(&arg, 0, sizeof(struct fuse_getattr_out)); convert_stat(&buf, &arg.attr); + } send_reply(f, in, res, &arg, sizeof(arg)); } @@ -513,8 +519,10 @@ static void do_setattr(struct fuse *f, struct fuse_in_header *in, if(!res) { struct stat buf; res = f->op.getattr(path, &buf); - if(!res) + if(!res) { + memset(&outarg, 0, sizeof(struct fuse_setattr_out)); convert_stat(&buf, &outarg.attr); + } } } free(path); @@ -559,6 +567,8 @@ static void do_getdir(struct fuse *f, struct fuse_in_header *in) free(path); } fflush(dh.fp); + + memset(&arg, 0, sizeof(struct fuse_getdir_out)); arg.fd = fileno(dh.fp); send_reply(f, in, res, &arg, sizeof(arg)); fclose(dh.fp); @@ -584,6 +594,7 @@ static void do_mknod(struct fuse *f, struct fuse_in_header *in, free(path); } if(res == 0) { + memset(&outarg, 0, sizeof(struct fuse_mknod_out)); convert_stat(&buf, &outarg.attr); outarg.ino = find_node(f, in->ino, PARAM(inarg), &outarg.attr, in->unique); @@ -751,6 +762,7 @@ static void do_read(struct fuse *f, struct fuse_in_header *in, fflush(stdout); } } + memset(out, 0, sizeof(struct fuse_out_header)); out->unique = in->unique; out->error = res; outsize = sizeof(struct fuse_out_header) + size; @@ -798,8 +810,10 @@ static void do_statfs(struct fuse *f, struct fuse_in_header *in) struct fuse_statfs_out arg; res = -ENOSYS; - if(f->op.statfs) + if(f->op.statfs) { + memset(&arg, 0, sizeof(struct fuse_statfs_out)); res = f->op.statfs((struct fuse_statfs *) &arg.st); + } send_reply(f, in, res, &arg, sizeof(arg)); } @@ -916,18 +930,24 @@ struct fuse_cmd *__fuse_read_cmd(struct fuse *f) do { res = read(f->fd, cmd->buf, FUSE_MAX_IN); if(res == -1) { + free_cmd(cmd); + if(errno == EINTR) + return NULL; + /* ENODEV means we got unmounted, so we silenty return failure */ if(errno != ENODEV) { - perror("fuse: reading device"); /* BAD... This will happen again */ + perror("fuse: reading device"); } - free_cmd(cmd); + + fuse_exit(f); return NULL; } if((size_t) res < sizeof(struct fuse_in_header)) { - fprintf(stderr, "short read on fuse device\n"); - /* Cannot happen */ free_cmd(cmd); + /* Cannot happen */ + fprintf(stderr, "short read on fuse device\n"); + fuse_exit(f); return NULL; } cmd->buflen = res; @@ -941,18 +961,27 @@ struct fuse_cmd *__fuse_read_cmd(struct fuse *f) return cmd; } - void fuse_loop(struct fuse *f) { while(1) { - struct fuse_cmd *cmd = __fuse_read_cmd(f); + struct fuse_cmd *cmd; + + if(f->exited) + return; + + cmd = __fuse_read_cmd(f); if(cmd == NULL) - exit(1); + continue; __fuse_process_cmd(f, cmd); } } +void fuse_exit(struct fuse *f) +{ + f->exited = 1; +} + struct fuse_context *fuse_get_context(struct fuse *f) { if(f->getcontext) @@ -985,6 +1014,7 @@ struct fuse *fuse_new(int fd, int flags, const struct fuse_operations *op) f->getcontext = NULL; f->context.uid = 0; f->context.gid = 0; + f->exited = 0; root = (struct node *) calloc(1, sizeof(struct node)); root->mode = 0; diff --git a/lib/fuse_i.h b/lib/fuse_i.h index 02b28ec..52f1fdc 100644 --- a/lib/fuse_i.h +++ b/lib/fuse_i.h @@ -38,6 +38,7 @@ struct fuse { struct fuse_context *(*getcontext)(struct fuse *); struct fuse_context context; pthread_key_t context_key; + volatile int exited; }; struct fuse_dirhandle { diff --git a/lib/fuse_mt.c b/lib/fuse_mt.c index 42d4bad..f1a2e5c 100644 --- a/lib/fuse_mt.c +++ b/lib/fuse_mt.c @@ -32,9 +32,14 @@ static void *do_work(void *data) struct fuse *f = w->f; while(1) { - struct fuse_cmd *cmd = __fuse_read_cmd(w->f); + struct fuse_cmd *cmd; + + if(f->exited) + break; + + cmd = __fuse_read_cmd(w->f); if(cmd == NULL) - pthread_exit(NULL); + continue; if(f->numavail == 0 && f->numworker < FUSE_MAX_WORKERS) { pthread_mutex_lock(&f->lock); diff --git a/lib/helper.c b/lib/helper.c index 522b377..d3b8b1c 100644 --- a/lib/helper.c +++ b/lib/helper.c @@ -10,21 +10,15 @@ #include #include -#include #include +#include #include #include -#include -#include -#include -#include -#include #define FUSE_MOUNTED_ENV "_FUSE_MOUNTED" #define FUSE_UMOUNT_CMD_ENV "_FUSE_UNMOUNT_CMD" -#define FUSE_COMMFD_ENV "_FUSE_COMMFD" -#define FUSERMOUNT_PROG "fusermount" +static struct fuse *fuse; static void usage(char *progname) { @@ -38,125 +32,10 @@ static void usage(char *progname) exit(1); } -static char umount_cmd[1024]; -static int fuse_fd; - -static void fuse_unmount() -{ - close(fuse_fd); - if(umount_cmd[0] != '\0') - system(umount_cmd); -} - -/* return value: - * >= 0 => fd - * -1 => error - */ -static int receive_fd(int fd) -{ - struct msghdr msg; - struct iovec iov; - char buf[1]; - int rv; - int connfd = -1; - char ccmsg[CMSG_SPACE(sizeof(connfd))]; - struct cmsghdr *cmsg; - - iov.iov_base = buf; - iov.iov_len = 1; - - msg.msg_name = 0; - msg.msg_namelen = 0; - msg.msg_iov = &iov; - msg.msg_iovlen = 1; - /* old BSD implementations should use msg_accrights instead of - * msg_control; the interface is different. */ - msg.msg_control = ccmsg; - msg.msg_controllen = sizeof(ccmsg); - - while(((rv = recvmsg(fd, &msg, 0)) == -1) && errno == EINTR); - if (rv == -1) { - perror("recvmsg"); - return -1; - } - if(!rv) { - /* EOF */ - fprintf(stderr, "got EOF\n"); - return -1; - } - - cmsg = CMSG_FIRSTHDR(&msg); - if (!cmsg->cmsg_type == SCM_RIGHTS) { - fprintf(stderr, "got control message of unknown type %d\n", - cmsg->cmsg_type); - return -1; - } - return *(int*)CMSG_DATA(cmsg); -} - -int fuse_mount(const char *mountpoint, const char *args[]) -{ - const char *mountprog = FUSERMOUNT_PROG; - int fds[2], pid; - int res; - int rv; - - snprintf(umount_cmd, sizeof(umount_cmd) - 1, "%s -u %s", mountprog, - mountpoint); - - res = socketpair(PF_UNIX, SOCK_STREAM, 0, fds); - if(res == -1) { - perror("fuse: socketpair() failed"); - return -1; - } - - pid = fork(); - if(pid == -1) { - perror("fuse: fork() failed"); - close(fds[0]); - close(fds[1]); - return -1; - } - - if(pid == 0) { - char env[10]; - char **newargv; - int numargs = 0; - int actr; - int i; - - if(args != NULL) - while(args[numargs] != NULL) - numargs ++; - - newargv = (char **) malloc((1 + numargs + 2) * sizeof(char *)); - actr = 0; - newargv[actr++] = strdup(mountprog); - for(i = 0; i < numargs; i++) - newargv[actr++] = strdup(args[i]); - newargv[actr++] = strdup(mountpoint); - newargv[actr++] = NULL; - - close(fds[1]); - fcntl(fds[0], F_SETFD, 0); - snprintf(env, sizeof(env), "%i", fds[0]); - setenv(FUSE_COMMFD_ENV, env, 1); - execvp(mountprog, newargv); - perror("fuse: failed to exec fusermount"); - exit(1); - } - - close(fds[0]); - rv = receive_fd(fds[1]); - close(fds[1]); - waitpid(pid, NULL, 0); /* bury zombie */ - - return rv; -} - static void exit_handler() { - exit(0); + if(fuse != NULL) + fuse_exit(fuse); } static void set_signal_handlers() @@ -188,14 +67,17 @@ void fuse_main(int argc, char *argv[], const struct fuse_operations *op) int argctr = 1; int flags; int multithreaded; - struct fuse *fuse; char *isreexec = getenv(FUSE_MOUNTED_ENV); + int fuse_fd; + char *fuse_mountpoint = NULL; + char umount_cmd[1024] = ""; if(isreexec == NULL) { if(argc < 2 || argv[1][0] == '-') usage(argv[0]); - fuse_fd = fuse_mount(argv[1], NULL); + fuse_mountpoint = strdup(argv[1]); + fuse_fd = fuse_mount(fuse_mountpoint, NULL); if(fuse_fd == -1) exit(1); @@ -217,7 +99,6 @@ void fuse_main(int argc, char *argv[], const struct fuse_operations *op) strncpy(umount_cmd, tmpstr, sizeof(umount_cmd) - 1); } - atexit(fuse_unmount); set_signal_handlers(); flags = 0; @@ -252,5 +133,11 @@ void fuse_main(int argc, char *argv[], const struct fuse_operations *op) fuse_loop_mt(fuse); else fuse_loop(fuse); + + close(fuse_fd); + if(fuse_mountpoint != NULL) + fuse_unmount(fuse_mountpoint); + else if(umount_cmd[0] != '\0') + system(umount_cmd); } diff --git a/lib/mount.c b/lib/mount.c new file mode 100644 index 0000000..1224afa --- /dev/null +++ b/lib/mount.c @@ -0,0 +1,136 @@ +/* + FUSE: Filesystem in Userspace + Copyright (C) 2001 Miklos Szeredi (mszeredi@inf.bme.hu) + + This program can be distributed under the terms of the GNU LGPL. + See the file COPYING.LIB. +*/ + +#include "fuse.h" + +#include +#include +#include +#include +#include +#include +#include +#include + +#define FUSERMOUNT_PROG "fusermount" +#define FUSE_COMMFD_ENV "_FUSE_COMMFD" + + +/* return value: + * >= 0 => fd + * -1 => error + */ +static int receive_fd(int fd) +{ + struct msghdr msg; + struct iovec iov; + char buf[1]; + int rv; + int connfd = -1; + char ccmsg[CMSG_SPACE(sizeof(connfd))]; + struct cmsghdr *cmsg; + + iov.iov_base = buf; + iov.iov_len = 1; + + msg.msg_name = 0; + msg.msg_namelen = 0; + msg.msg_iov = &iov; + msg.msg_iovlen = 1; + /* old BSD implementations should use msg_accrights instead of + * msg_control; the interface is different. */ + msg.msg_control = ccmsg; + msg.msg_controllen = sizeof(ccmsg); + + while(((rv = recvmsg(fd, &msg, 0)) == -1) && errno == EINTR); + if (rv == -1) { + perror("recvmsg"); + return -1; + } + if(!rv) { + /* EOF */ + return -1; + } + + cmsg = CMSG_FIRSTHDR(&msg); + if (!cmsg->cmsg_type == SCM_RIGHTS) { + fprintf(stderr, "got control message of unknown type %d\n", + cmsg->cmsg_type); + return -1; + } + return *(int*)CMSG_DATA(cmsg); +} + +void fuse_unmount(const char *mountpoint) +{ + const char *mountprog = FUSERMOUNT_PROG; + char umount_cmd[1024]; + + snprintf(umount_cmd, sizeof(umount_cmd) - 1, "%s -u %s", mountprog, + mountpoint); + + umount_cmd[sizeof(umount_cmd) - 1] = '\0'; + system(umount_cmd); +} + +int fuse_mount(const char *mountpoint, const char *args[]) +{ + const char *mountprog = FUSERMOUNT_PROG; + int fds[2], pid; + int res; + int rv; + + res = socketpair(PF_UNIX, SOCK_STREAM, 0, fds); + if(res == -1) { + perror("fuse: socketpair() failed"); + return -1; + } + + pid = fork(); + if(pid == -1) { + perror("fuse: fork() failed"); + close(fds[0]); + close(fds[1]); + return -1; + } + + if(pid == 0) { + char env[10]; + char **newargv; + int numargs = 0; + int actr; + int i; + + if(args != NULL) + while(args[numargs] != NULL) + numargs ++; + + newargv = (char **) malloc((1 + numargs + 2) * sizeof(char *)); + actr = 0; + newargv[actr++] = strdup(mountprog); + for(i = 0; i < numargs; i++) + newargv[actr++] = strdup(args[i]); + newargv[actr++] = strdup(mountpoint); + newargv[actr++] = NULL; + + close(fds[1]); + fcntl(fds[0], F_SETFD, 0); + snprintf(env, sizeof(env), "%i", fds[0]); + setenv(FUSE_COMMFD_ENV, env, 1); + execvp(mountprog, newargv); + perror("fuse: failed to exec fusermount"); + exit(1); + } + + close(fds[0]); + rv = receive_fd(fds[1]); + close(fds[1]); + waitpid(pid, NULL, 0); /* bury zombie */ + + return rv; +} -- 2.30.2