From 3f0005fbf22f3cf932b04d69c0414f39a8df97ee Mon Sep 17 00:00:00 2001 From: Miklos Szeredi Date: Tue, 4 Jan 2005 19:24:31 +0000 Subject: [PATCH] fix --- ChangeLog | 4 ++ kernel/cleanup.sh | 2 +- kernel/configure.ac | 8 --- kernel/dev.c | 123 ++++++++++--------------------------------- kernel/fuse_i.h | 6 +++ kernel/fuse_kernel.h | 7 ++- kernel/inode.c | 5 +- lib/fuse.c | 70 +++++++++--------------- lib/fuse_i.h | 3 +- util/fusermount.c | 21 +++----- 10 files changed, 80 insertions(+), 169 deletions(-) diff --git a/ChangeLog b/ChangeLog index 0395c38..6019730 100644 --- a/ChangeLog +++ b/ChangeLog @@ -4,6 +4,10 @@ inode(s) and file, so that FORGET and RELEASE are not sent until userspace finishes the request. + * remove /{sys,proc}/fs/fuse/version, and instead add an INIT + request with the same information, which is more flexible, + simpler, works on embedded systems. + 2004-12-16 Miklos Szeredi * KERNEL ABI: update interface to make it independent of type diff --git a/kernel/cleanup.sh b/kernel/cleanup.sh index 9d7b92b..7c2f309 100755 --- a/kernel/cleanup.sh +++ b/kernel/cleanup.sh @@ -16,6 +16,6 @@ mkdir -p $destdir/include/linux for f in dev.c dir.c file.c inode.c util.c fuse_i.h; do - unifdef -DKERNEL_2_6 -DKERNEL_2_6_6_PLUS -DKERNEL_2_6_10_PLUS -DHAVE_KERNEL_XATTR -DFS_SAFE -DMAX_LFS_FILESIZE -DFUSE_MAINLINE -DBUG_ON -DHAVE_FS_SUBSYS -D__user -DMODULE_LICENSE $f > $destdir/fs/fuse/$f + unifdef -DKERNEL_2_6 -DKERNEL_2_6_6_PLUS -DKERNEL_2_6_10_PLUS -DHAVE_KERNEL_XATTR -DFS_SAFE -DMAX_LFS_FILESIZE -DFUSE_MAINLINE -DBUG_ON -D__user -DMODULE_LICENSE $f > $destdir/fs/fuse/$f done cp fuse_kernel.h $destdir/include/linux/fuse.h diff --git a/kernel/configure.ac b/kernel/configure.ac index e6bf669..20a54fc 100644 --- a/kernel/configure.ac +++ b/kernel/configure.ac @@ -49,14 +49,6 @@ if echo "$kernsrcver" | grep -q "^2.4"; then CFLAGS="$old_cflags" fi -AC_MSG_CHECKING([whether fs_subsys is declared]) -if grep -q fs_subsys $kernelsrc/include/linux/fs.h; then - AC_DEFINE(HAVE_FS_SUBSYS, 1, [Kernel defines fs_subsys]) - AC_MSG_RESULT([yes]) -else - AC_MSG_RESULT([no]) -fi - AC_MSG_CHECKING([if kernel has extended attribute support]) if test -f $kernelsrc/include/linux/xattr.h; then AC_DEFINE(HAVE_KERNEL_XATTR, 1, [Kernel has xattr support]) diff --git a/kernel/dev.c b/kernel/dev.c index bfd2bd7..a2a44e4 100644 --- a/kernel/dev.c +++ b/kernel/dev.c @@ -12,11 +12,6 @@ #include #include #include -#ifdef KERNEL_2_6 -#include -#else -#include -#endif #include #include #include @@ -128,7 +123,7 @@ struct fuse_req *fuse_get_request(struct fuse_conn *fc) { if (down_interruptible(&fc->outstanding_sem)) return NULL; - return do_get_request(fc); + return do_get_request(fc); } struct fuse_req *fuse_get_request_nonint(struct fuse_conn *fc) @@ -180,6 +175,13 @@ static void request_end(struct fuse_conn *fc, struct fuse_req *req) fput(req->file); } wake_up(&req->waitq); + if (req->in.h.opcode == FUSE_INIT) { + int i; + /* up() one less than FUSE_MAX_OUTSTANDING, because + fuse_putback_request() will also do an up() */ + for (i = 1; i < FUSE_MAX_OUTSTANDING; i++) + up(&fc->outstanding_sem); + } if (putback) fuse_putback_request(fc, req); } @@ -332,6 +334,24 @@ void request_send_background(struct fuse_conn *fc, struct fuse_req *req) request_send_nowait(fc, req); } +void fuse_send_init(struct fuse_conn *fc) +{ + /* This is called from fuse_read_super() so there's guaranteed + to be a request available */ + struct fuse_req *req = do_get_request(fc); + struct fuse_init_in_out *arg = &req->misc.init_in_out; + arg->major = FUSE_KERNEL_VERSION; + arg->minor = FUSE_KERNEL_MINOR_VERSION; + req->in.h.opcode = FUSE_INIT; + req->in.numargs = 1; + req->in.args[0].size = sizeof(*arg); + req->in.args[0].value = arg; + req->out.numargs = 1; + req->out.args[0].size = sizeof(*arg); + req->out.args[0].value = arg; + request_send_background(fc, req); +} + static inline int lock_request(struct fuse_req *req) { int err = 0; @@ -798,85 +818,6 @@ struct file_operations fuse_dev_operations = { .release = fuse_dev_release, }; -#ifdef KERNEL_2_6 -#ifndef HAVE_FS_SUBSYS -static decl_subsys(fs, NULL, NULL); -#endif -static decl_subsys(fuse, NULL, NULL); - -static ssize_t version_show(struct subsystem *subsys, char *buf) -{ - return sprintf(buf, "%i.%i\n", FUSE_KERNEL_VERSION, - FUSE_KERNEL_MINOR_VERSION); -} -static struct subsys_attribute fuse_attr_version = __ATTR_RO(version); - -static int __init fuse_version_init(void) -{ - int err; - -#ifndef HAVE_FS_SUBSYS - subsystem_register(&fs_subsys); -#endif - kset_set_kset_s(&fuse_subsys, fs_subsys); - err = subsystem_register(&fuse_subsys); - if (err) - return err; - err = subsys_create_file(&fuse_subsys, &fuse_attr_version); - if (err) { - subsystem_unregister(&fuse_subsys); -#ifndef HAVE_FS_SUBSYS - subsystem_unregister(&fs_subsys); -#endif - return err; - } - return 0; -} - -static void fuse_version_clean(void) -{ - subsys_remove_file(&fuse_subsys, &fuse_attr_version); - subsystem_unregister(&fuse_subsys); -#ifndef HAVE_FS_SUBSYS - subsystem_unregister(&fs_subsys); -#endif -} -#else -static struct proc_dir_entry *proc_fs_fuse; - -static int read_version(char *page, char **start, off_t off, int count, - int *eof, void *data) -{ - char *s = page; - s += sprintf(s, "%i.%i\n", FUSE_KERNEL_VERSION, - FUSE_KERNEL_MINOR_VERSION); - return s - page; -} - -static int fuse_version_init(void) -{ - proc_fs_fuse = proc_mkdir("fuse", proc_root_fs); - if (proc_fs_fuse) { - struct proc_dir_entry *de; - - de = create_proc_entry("version", S_IFREG | 0444, proc_fs_fuse); - if (de) { - de->owner = THIS_MODULE; - de->read_proc = read_version; - } - } - return 0; -} - -static void fuse_version_clean(void) -{ - if (proc_fs_fuse) { - remove_proc_entry("version", proc_fs_fuse); - remove_proc_entry("fuse", proc_root_fs); - } -} -#endif - static struct miscdevice fuse_miscdevice = { .minor = FUSE_MINOR, .name = "fuse", @@ -885,17 +826,12 @@ static struct miscdevice fuse_miscdevice = { int __init fuse_dev_init(void) { - int err; - err = fuse_version_init(); - if (err) - goto out; - - err = -ENOMEM; + int err = -ENOMEM; fuse_req_cachep = kmem_cache_create("fuser_request", sizeof(struct fuse_req), 0, 0, NULL, NULL); if (!fuse_req_cachep) - goto out_version_clean; + goto out; err = misc_register(&fuse_miscdevice); if (err) @@ -905,8 +841,6 @@ int __init fuse_dev_init(void) out_cache_clean: kmem_cache_destroy(fuse_req_cachep); - out_version_clean: - fuse_version_clean(); out: return err; } @@ -915,5 +849,4 @@ void fuse_dev_cleanup(void) { misc_deregister(&fuse_miscdevice); kmem_cache_destroy(fuse_req_cachep); - fuse_version_clean(); } diff --git a/kernel/fuse_i.h b/kernel/fuse_i.h index fa0c497..48211bc 100644 --- a/kernel/fuse_i.h +++ b/kernel/fuse_i.h @@ -216,6 +216,7 @@ struct fuse_req { union { struct fuse_forget_in forget_in; struct fuse_release_in release_in; + struct fuse_init_in_out init_in_out; } misc; /** page vector */ @@ -482,3 +483,8 @@ int fuse_do_getattr(struct inode *inode); * Invalidate inode attributes */ void fuse_invalidate_attr(struct inode *inode); + +/** + * Send the INIT message + */ +void fuse_send_init(struct fuse_conn *fc); diff --git a/kernel/fuse_kernel.h b/kernel/fuse_kernel.h index bad4546..d76b5d1 100644 --- a/kernel/fuse_kernel.h +++ b/kernel/fuse_kernel.h @@ -79,13 +79,13 @@ enum fuse_opcode { FUSE_WRITE = 16, FUSE_STATFS = 17, FUSE_RELEASE = 18, - /*FUSE_INVALIDATE = 19,*/ FUSE_FSYNC = 20, FUSE_SETXATTR = 21, FUSE_GETXATTR = 22, FUSE_LISTXATTR = 23, FUSE_REMOVEXATTR = 24, FUSE_FLUSH = 25, + FUSE_INIT = 26 }; /* Conservative buffer size for the client */ @@ -201,6 +201,11 @@ struct fuse_getxattr_out { __u32 size; }; +struct fuse_init_in_out { + __u32 major; + __u32 minor; +}; + struct fuse_in_header { __u32 len; __u32 opcode; diff --git a/kernel/inode.c b/kernel/inode.c index eb40b7b..8227be8 100644 --- a/kernel/inode.c +++ b/kernel/inode.c @@ -478,14 +478,13 @@ static struct fuse_conn *new_conn(void) INIT_LIST_HEAD(&fc->pending); INIT_LIST_HEAD(&fc->processing); INIT_LIST_HEAD(&fc->unused_list); - sema_init(&fc->outstanding_sem, FUSE_MAX_OUTSTANDING); + sema_init(&fc->outstanding_sem, 0); for (i = 0; i < FUSE_MAX_OUTSTANDING; i++) { struct fuse_req *req = fuse_request_alloc(); if (!req) { free_conn(fc); return NULL; } - req->preallocated = 1; list_add(&req->list, &fc->unused_list); } #ifdef KERNEL_2_6 @@ -668,7 +667,7 @@ static int fuse_read_super(struct super_block *sb, void *data, int silent) iput(root); goto err; } - + fuse_send_init(fc); return 0; err: diff --git a/lib/fuse.c b/lib/fuse.c index b5be472..1a6c56e 100644 --- a/lib/fuse.c +++ b/lib/fuse.c @@ -99,6 +99,7 @@ static const char *opname(enum fuse_opcode opcode) case FUSE_GETXATTR: return "GETXATTR"; case FUSE_LISTXATTR: return "LISTXATTR"; case FUSE_REMOVEXATTR: return "REMOVEXATTR"; + case FUSE_INIT: return "INIT"; default: return "???"; } } @@ -1504,6 +1505,20 @@ static void do_removexattr(struct fuse *f, struct fuse_in_header *in, send_reply(f, in, res, NULL, 0); } +static void do_init(struct fuse *f, struct fuse_in_header *in, + struct fuse_init_in_out *arg) +{ + struct fuse_init_in_out outarg; + if (f->flags & FUSE_DEBUG) { + printf(" INIT: %u.%u\n", arg->major, arg->minor); + fflush(stdout); + } + f->got_init = 1; + memset(&outarg, 0, sizeof(outarg)); + outarg.major = FUSE_KERNEL_VERSION; + outarg.minor = FUSE_KERNEL_MINOR_VERSION; + send_reply(f, in, 0, &outarg, sizeof(outarg)); +} static void free_cmd(struct fuse_cmd *cmd) { @@ -1527,6 +1542,12 @@ void fuse_process_cmd(struct fuse *f, struct fuse_cmd *cmd) fflush(stdout); } + if (!f->got_init && in->opcode != FUSE_INIT) { + /* Old kernel version probably */ + send_reply(f, in, -EPROTO, NULL, 0); + goto out; + } + ctx->fuse = f; ctx->uid = in->uid; ctx->gid = in->gid; @@ -1628,10 +1649,15 @@ void fuse_process_cmd(struct fuse *f, struct fuse_cmd *cmd) do_removexattr(f, in, (char *) inarg); break; + case FUSE_INIT: + do_init(f, in, (struct fuse_init_in_out *) inarg); + break; + default: send_reply(f, in, -ENOSYS, NULL, 0); } + out: free_cmd(cmd); } @@ -1742,47 +1768,6 @@ void fuse_set_getcontext_func(struct fuse_context *(*func)(void)) fuse_getcontext = func; } -static int check_version(struct fuse *f) -{ - int res; - const char *version_file = FUSE_VERSION_FILE_NEW; - FILE *vf = fopen(version_file, "r"); - if (vf == NULL) { - version_file = FUSE_VERSION_FILE_OLD; - vf = fopen(version_file, "r"); - if (vf == NULL) { - struct stat tmp; - if (stat(FUSE_DEV_OLD, &tmp) != -1) { - fprintf(stderr, "fuse: kernel interface too old, need >= %i.%i\n", - FUSE_KERNEL_VERSION, FUSE_KERNEL_MINOR_VERSION); - return -1; - } else { - fprintf(stderr, "fuse: warning: version of kernel interface unknown\n"); - return 0; - } - } - } - res = fscanf(vf, "%i.%i", &f->majorver, &f->minorver); - fclose(vf); - if (res != 2) { - fprintf(stderr, "fuse: error reading %s\n", version_file); - return -1; - } - if (f->majorver != FUSE_KERNEL_VERSION) { - fprintf(stderr, "fuse: bad kernel interface major version: needs %i\n", - FUSE_KERNEL_VERSION); - return -1; - } - if (f->minorver < FUSE_KERNEL_MINOR_VERSION_NEED) { - fprintf(stderr, "fuse: kernel interface too old: need >= %i.%i\n", - FUSE_KERNEL_VERSION, FUSE_KERNEL_MINOR_VERSION); - return -1; - } - - return 0; -} - - int fuse_is_lib_option(const char *opt) { if (strcmp(opt, "debug") == 0 || @@ -1838,9 +1823,6 @@ struct fuse *fuse_new_common(int fd, const char *opts, goto out; } - if (check_version(f) == -1) - goto out_free; - if (parse_lib_opts(f, opts) == -1) goto out_free; diff --git a/lib/fuse_i.h b/lib/fuse_i.h index ebe712a..284e531 100644 --- a/lib/fuse_i.h +++ b/lib/fuse_i.h @@ -28,8 +28,7 @@ struct fuse { int numworker; int numavail; volatile int exited; - int majorver; - int minorver; + int got_init; }; struct fuse *fuse_new_common(int fd, const char *opts, diff --git a/util/fusermount.c b/util/fusermount.c index 80808c8..0686d7a 100644 --- a/util/fusermount.c +++ b/util/fusermount.c @@ -40,7 +40,6 @@ #define FUSE_DEV_OLD "/proc/fs/fuse/dev" #define FUSE_DEV_NEW "/dev/fuse" #define FUSE_VERSION_FILE_OLD "/proc/fs/fuse/version" -#define FUSE_VERSION_FILE_NEW "/sys/fs/fuse/version" #define FUSE_MAJOR 10 #define FUSE_MINOR 229 @@ -532,24 +531,16 @@ static int check_version(const char *dev) int majorver; int minorver; const char *version_file; - int isold = 0; FILE *vf; - if (strcmp(dev, FUSE_DEV_OLD) == 0) - isold = 1; + if (strcmp(dev, FUSE_DEV_OLD) != 0) + return 0; - version_file = FUSE_VERSION_FILE_NEW; + version_file = FUSE_VERSION_FILE_OLD; vf = fopen(version_file, "r"); if (vf == NULL) { - version_file = FUSE_VERSION_FILE_OLD; - vf = fopen(version_file, "r"); - if (vf == NULL) { - if (isold) { - fprintf(stderr, "%s: kernel interface too old\n", progname); - return -1; - } else - return 0; - } + fprintf(stderr, "%s: kernel interface too old\n", progname); + return -1; } res = fscanf(vf, "%i.%i", &majorver, &minorver); fclose(vf); @@ -557,7 +548,7 @@ static int check_version(const char *dev) fprintf(stderr, "%s: error reading %s\n", progname, version_file); return -1; } - if (majorver < 3) { + if (majorver < 3) { fprintf(stderr, "%s: kernel interface too old\n", progname); return -1; } -- 2.30.2