From: Miklos Szeredi Date: Fri, 20 Jan 2006 15:15:21 +0000 (+0000) Subject: fix X-Git-Tag: fuse_2_6_0_pre1~22 X-Git-Url: http://git.maquefel.me/?a=commitdiff_plain;h=065f222cd58501acbe6dde5520c1c2498e8d3c08;p=qemu-gpiodev%2Flibfuse.git fix --- diff --git a/ChangeLog b/ChangeLog index 1298d09..0ea0d2e 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,45 @@ +2006-01-20 Miklos Szeredi + + * fuse_opt: add new helper constants FUSE_OPT_KEY_KEEP and + FUSE_OPT_KEY_DISCARD + + * Add options 'max_readahead', 'sync_read' and 'async_read' + + * Kernel ABI version 7.6: + + * Negotiate the 'max_readahead' value and 'async_read' flags with + userspace in the INIT method + + * Add connection info to ->init() methods to both lowlevel and + highlevel API + + * Fall back to synchronous read() behavior if either library or + userspace filesystem is using the old interface version. This is + needed so non-updated filesystems won't be confused by the + different read() behavior + +2006-01-19 Miklos Szeredi + + * lib: if "fsname=" option was given, pass it to fusermount + + * fuse_opt: add new fuse_opt_insert_arg() function, which is + needed by filesystems to implement some argument manipulations + correctly + + * fuse_opt: fix memory leak in handling "--" option + +2006-01-18 Miklos Szeredi + + * kernel: fix detection of case when fuse is not configured into + the kernel either as module or built-in + + * fuse_opt.h: fix incompatibility with C++ compilers by renaming + 'template' structure member to 'templ'. Reported by Takashi Iwai + + * fuse.h: fix compatibility bugs. Patch by Yura Pakhuchiy + + * kernel: support version 2.6.16 (i_sem -> i_mutex) + 2006-01-16 Miklos Szeredi * Added (again) asynchronous readpages support diff --git a/configure.in b/configure.in index d14db87..4e29570 100644 --- a/configure.in +++ b/configure.in @@ -1,4 +1,4 @@ -AC_INIT(fuse, 2.5.0) +AC_INIT(fuse, 2.7.0-pre0) AC_CANONICAL_TARGET AM_INIT_AUTOMAKE AM_CONFIG_HEADER(include/config.h) @@ -23,7 +23,7 @@ esac if test "$ac_env_CFLAGS_set" != set; then CFLAGS="-Wall -W -g -O2" fi -CPPFLAGS="$CPPFLAGS -D_FILE_OFFSET_BITS=64 -D_REENTRANT -DFUSE_USE_VERSION=25" +CPPFLAGS="$CPPFLAGS -D_FILE_OFFSET_BITS=64 -D_REENTRANT -DFUSE_USE_VERSION=27" AC_ARG_ENABLE(kernel-module, [ --enable-kernel-module Compile kernel module ]) diff --git a/include/fuse.h b/include/fuse.h index a94c61a..3c3a98f 100644 --- a/include/fuse.h +++ b/include/fuse.h @@ -295,7 +295,7 @@ struct fuse_operations { * * Introduced in version 2.3 */ - void *(*init) (void); + void *(*init) (struct fuse_conn_info *conn); /** * Clean up filesystem @@ -535,13 +535,25 @@ void fuse_set_getcontext_func(struct fuse_context *(*func)(void)); * Compatibility stuff * * ----------------------------------------------------------- */ -#ifndef __FreeBSD__ +#ifdef __FreeBSD__ +# if FUSE_USE_VERSION < 25 +# error On FreeBSD API version 25 or greater must be used +# endif +#endif -#if FUSE_USE_VERSION == 22 || FUSE_USE_VERSION == 21 || FUSE_USE_VERSION == 11 +#if FUSE_USE_VERSION == 25 || FUSE_USE_VERSION == 22 || \ + FUSE_USE_VERSION == 21 || FUSE_USE_VERSION == 11 # include "fuse_compat.h" # undef FUSE_MINOR_VERSION # undef fuse_main -# if FUSE_USE_VERSION == 22 +# if FUSE_USE_VERSION == 25 +# define FUSE_MINOR_VERSION 6 +# define fuse_main(argc, argv, op) \ + fuse_main_real_compat25(argc, argv, op, sizeof(*(op))) +# define fuse_new fuse_new_compat25 +# define fuse_setup fuse_setup_compat25 +# define fuse_operations fuse_operations_compat25 +# elif FUSE_USE_VERSION == 22 # define FUSE_MINOR_VERSION 4 # define fuse_main(argc, argv, op) \ fuse_main_real_compat22(argc, argv, op, sizeof(*(op))) @@ -549,13 +561,14 @@ void fuse_set_getcontext_func(struct fuse_context *(*func)(void)); # define fuse_setup fuse_setup_compat22 # define fuse_operations fuse_operations_compat22 # define fuse_file_info fuse_file_info_compat22 +# define fuse_mount fuse_mount_compat22 # else # define fuse_dirfil_t fuse_dirfil_t_compat # define __fuse_read_cmd fuse_read_cmd # define __fuse_process_cmd fuse_process_cmd # define __fuse_loop_mt fuse_loop_mt_proc # if FUSE_USE_VERSION == 21 -# define FUSE_MAJOR_VERSION 2 +# define FUSE_MINOR_VERSION 1 # define fuse_operations fuse_operations_compat2 # define fuse_main fuse_main_compat2 # define fuse_new fuse_new_compat2 @@ -563,6 +576,7 @@ void fuse_set_getcontext_func(struct fuse_context *(*func)(void)); # define __fuse_teardown fuse_teardown # define __fuse_exited fuse_exited # define __fuse_set_getcontext_func fuse_set_getcontext_func +# define fuse_mount fuse_mount_compat22 # else # warning Compatibility with API version 11 is deprecated # undef FUSE_MAJOR_VERSION @@ -576,18 +590,10 @@ void fuse_set_getcontext_func(struct fuse_context *(*func)(void)); # define FUSE_DEBUG FUSE_DEBUG_COMPAT1 # endif # endif -#elif FUSE_USE_VERSION < 25 -# error Compatibility with API version other than 21, 22 and 11 not supported +#elif FUSE_USE_VERSION < 27 +# error Compatibility with API version other than 21, 22, 25 and 11 not supported #endif -#else /* __FreeBSD__ */ - -#if FUSE_USE_VERSION < 25 -# error On FreeBSD API version 25 or greater must be used -#endif - -#endif /* __FreeBSD__ */ - #ifdef __cplusplus } #endif diff --git a/include/fuse_common.h b/include/fuse_common.h index 0f35ea6..4304462 100644 --- a/include/fuse_common.h +++ b/include/fuse_common.h @@ -20,7 +20,7 @@ #define FUSE_MAJOR_VERSION 2 /** Minor version of FUSE library interface */ -#define FUSE_MINOR_VERSION 5 +#define FUSE_MINOR_VERSION 7 #define FUSE_MAKE_VERSION(maj, min) ((maj) * 10 + (min)) #define FUSE_VERSION FUSE_MAKE_VERSION(FUSE_MAJOR_VERSION, FUSE_MINOR_VERSION) @@ -66,6 +66,15 @@ struct fuse_file_info { uint64_t fh; }; +struct fuse_conn_info { + unsigned proto_major; + unsigned proto_minor; + unsigned async_read; + unsigned max_write; + unsigned max_readahead; + unsigned reserved[27]; +}; + /** * Create a FUSE mountpoint * diff --git a/include/fuse_compat.h b/include/fuse_compat.h index 220ef07..97f7b12 100644 --- a/include/fuse_compat.h +++ b/include/fuse_compat.h @@ -9,6 +9,60 @@ /* these definitions provide source compatibility to prior versions. Do not include this file directly! */ +struct fuse_operations_compat25 { + int (*getattr) (const char *, struct stat *); + int (*readlink) (const char *, char *, size_t); + int (*getdir) (const char *, fuse_dirh_t, fuse_dirfil_t); + int (*mknod) (const char *, mode_t, dev_t); + int (*mkdir) (const char *, mode_t); + int (*unlink) (const char *); + int (*rmdir) (const char *); + int (*symlink) (const char *, const char *); + int (*rename) (const char *, const char *); + int (*link) (const char *, const char *); + int (*chmod) (const char *, mode_t); + int (*chown) (const char *, uid_t, gid_t); + int (*truncate) (const char *, off_t); + int (*utime) (const char *, struct utimbuf *); + int (*open) (const char *, struct fuse_file_info *); + int (*read) (const char *, char *, size_t, off_t, struct fuse_file_info *); + int (*write) (const char *, const char *, size_t, off_t, + struct fuse_file_info *); + int (*statfs) (const char *, struct statvfs *); + int (*flush) (const char *, struct fuse_file_info *); + int (*release) (const char *, struct fuse_file_info *); + int (*fsync) (const char *, int, struct fuse_file_info *); + int (*setxattr) (const char *, const char *, const char *, size_t, int); + int (*getxattr) (const char *, const char *, char *, size_t); + int (*listxattr) (const char *, char *, size_t); + int (*removexattr) (const char *, const char *); + int (*opendir) (const char *, struct fuse_file_info *); + int (*readdir) (const char *, void *, fuse_fill_dir_t, off_t, + struct fuse_file_info *); + int (*releasedir) (const char *, struct fuse_file_info *); + int (*fsyncdir) (const char *, int, struct fuse_file_info *); + void *(*init) (void); + void (*destroy) (void *); + int (*access) (const char *, int); + int (*create) (const char *, mode_t, struct fuse_file_info *); + int (*ftruncate) (const char *, off_t, struct fuse_file_info *); + int (*fgetattr) (const char *, struct stat *, struct fuse_file_info *); +}; + +struct fuse *fuse_new_compat25(int fd, struct fuse_args *args, + const struct fuse_operations_compat25 *op, + size_t op_size); + +int fuse_main_real_compat25(int argc, char *argv[], + const struct fuse_operations_compat25 *op, + size_t op_size); + +struct fuse *fuse_setup_compat25(int argc, char *argv[], + const struct fuse_operations_compat25 *op, + size_t op_size, char **mountpoint, + int *multithreaded, int *fd); + +#ifndef __FreeBSD__ #include struct fuse_file_info_compat22 { @@ -145,3 +199,5 @@ int fuse_mount_compat1(const char *mountpoint, const char *args[]); struct fuse *fuse_new_compat1(int fd, int flags, const struct fuse_operations_compat1 *op); void fuse_main_compat1(int argc, char *argv[], const struct fuse_operations_compat1 *op); + +#endif /* __FreeBSD__ */ diff --git a/include/fuse_lowlevel.h b/include/fuse_lowlevel.h index e45968c..0c4672f 100644 --- a/include/fuse_lowlevel.h +++ b/include/fuse_lowlevel.h @@ -141,7 +141,7 @@ struct fuse_lowlevel_ops { * * @param userdata the user data passed to fuse_lowlevel_new() */ - void (*init) (void *userdata); + void (*init) (void *userdata, struct fuse_conn_info *conn); /** * Clean up filesystem @@ -1235,27 +1235,29 @@ void fuse_remove_signal_handlers(struct fuse_session *se); * Compatibility stuff * * ----------------------------------------------------------- */ -#ifndef __FreeBSD__ +#ifdef __FreeBSD__ +# if FUSE_USE_VERSION < 25 +# error On FreeBSD API version 25 or greater must be used +# endif +#endif -#if FUSE_USE_VERSION == 24 +#if FUSE_USE_VERSION == 25 || FUSE_USE_VERSION == 24 # include "fuse_lowlevel_compat.h" # undef FUSE_MINOR_VERSION -# define FUSE_MINOR_VERSION 4 -# define fuse_file_info fuse_file_info_compat -# define fuse_reply_statfs fuse_reply_statfs_compat -# define fuse_reply_open fuse_reply_open_compat -#elif FUSE_USE_VERSION < 25 -# error Compatibility with low level API version other than 24 not supported +# if FUSE_USE_VERSION == 25 +# define FUSE_MINOR_VERSION 6 +# define fuse_lowlevel_ops fuse_lowlevel_ops_compat25 +# define fuse_lowlevel_new fuse_lowlevel_new_compat25 +# else +# define FUSE_MINOR_VERSION 4 +# define fuse_file_info fuse_file_info_compat +# define fuse_reply_statfs fuse_reply_statfs_compat +# define fuse_reply_open fuse_reply_open_compat +# endif +#elif FUSE_USE_VERSION < 27 +# error Compatibility with low level API version other than 24 and 25 not supported #endif -#else /* __FreeBSD__ */ - -#if FUSE_USE_VERSION < 25 -# error On FreeBSD API version 25 or greater must be used -#endif - -#endif /* __FreeBSD__ */ - #ifdef __cplusplus } #endif diff --git a/include/fuse_lowlevel_compat.h b/include/fuse_lowlevel_compat.h index ccb7d01..0ba0c96 100644 --- a/include/fuse_lowlevel_compat.h +++ b/include/fuse_lowlevel_compat.h @@ -9,6 +9,61 @@ /* these definitions provide source compatibility to prior versions. Do not include this file directly! */ +struct fuse_lowlevel_ops_compat25 { + void (*init) (void *userdata); + void (*destroy) (void *userdata); + void (*lookup) (fuse_req_t req, fuse_ino_t parent, const char *name); + void (*forget) (fuse_req_t req, fuse_ino_t ino, unsigned long nlookup); + void (*getattr) (fuse_req_t req, fuse_ino_t ino, struct fuse_file_info *fi); + void (*setattr) (fuse_req_t req, fuse_ino_t ino, struct stat *attr, + int to_set, struct fuse_file_info *fi); + 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); + void (*mkdir) (fuse_req_t req, fuse_ino_t parent, const char *name, + mode_t mode); + void (*unlink) (fuse_req_t req, fuse_ino_t parent, const char *name); + void (*rmdir) (fuse_req_t req, fuse_ino_t parent, const char *name); + void (*symlink) (fuse_req_t req, const char *link, fuse_ino_t parent, + const char *name); + void (*rename) (fuse_req_t req, fuse_ino_t parent, const char *name, + 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 (*open) (fuse_req_t req, fuse_ino_t ino, struct fuse_file_info *fi); + void (*read) (fuse_req_t req, fuse_ino_t ino, size_t size, off_t off, + struct fuse_file_info *fi); + void (*write) (fuse_req_t req, fuse_ino_t ino, const char *buf, + size_t size, off_t off, struct fuse_file_info *fi); + void (*flush) (fuse_req_t req, fuse_ino_t ino, struct fuse_file_info *fi); + void (*release) (fuse_req_t req, fuse_ino_t ino, struct fuse_file_info *fi); + void (*fsync) (fuse_req_t req, fuse_ino_t ino, int datasync, + struct fuse_file_info *fi); + void (*opendir) (fuse_req_t req, fuse_ino_t ino, struct fuse_file_info *fi); + void (*readdir) (fuse_req_t req, fuse_ino_t ino, size_t size, off_t off, + struct fuse_file_info *fi); + void (*releasedir) (fuse_req_t req, fuse_ino_t ino, + struct fuse_file_info *fi); + void (*fsyncdir) (fuse_req_t req, fuse_ino_t ino, int datasync, + struct fuse_file_info *fi); + void (*statfs) (fuse_req_t req); + void (*setxattr) (fuse_req_t req, fuse_ino_t ino, const char *name, + const char *value, size_t size, int flags); + void (*getxattr) (fuse_req_t req, fuse_ino_t ino, const char *name, + size_t size); + void (*listxattr) (fuse_req_t req, fuse_ino_t ino, size_t size); + void (*removexattr) (fuse_req_t req, fuse_ino_t ino, const char *name); + void (*access) (fuse_req_t req, fuse_ino_t ino, int mask); + void (*create) (fuse_req_t req, fuse_ino_t parent, const char *name, + mode_t mode, struct fuse_file_info *fi); +}; + +struct fuse_session *fuse_lowlevel_new_compat25(struct fuse_args *args, + const struct fuse_lowlevel_ops_compat25 *op, + size_t op_size, void *userdata); + +#ifndef __FreeBSD__ + #include struct fuse_file_info_compat { @@ -27,3 +82,5 @@ int fuse_reply_open_compat(fuse_req_t req, struct fuse_session *fuse_lowlevel_new_compat(const char *opts, const struct fuse_lowlevel_ops *op, size_t op_size, void *userdata); + +#endif /* __FreeBSD__ */ diff --git a/include/fuse_opt.h b/include/fuse_opt.h index 2ef5d56..9e159d5 100644 --- a/include/fuse_opt.h +++ b/include/fuse_opt.h @@ -72,7 +72,7 @@ extern "C" { */ struct fuse_opt { /** Matching template and optional parameter formatting */ - const char *template; + const char *templ; /** * Offset of variable within 'data' parameter of fuse_opt_parse() @@ -82,7 +82,7 @@ struct fuse_opt { /** * Value to set the variable to, or to be passed as 'key' to the - * processing function. Ignored if template a format + * processing function. Ignored if template has a format */ int value; }; @@ -91,13 +91,13 @@ struct fuse_opt { * Key option. In case of a match, the processing function will be * called with the specified key. */ -#define FUSE_OPT_KEY(template, key) { template, -1U, key } +#define FUSE_OPT_KEY(templ, key) { templ, -1U, key } /** * Last option. An array of 'struct fuse_opt' must end with a NULL * template value */ -#define FUSE_OPT_END { .template = NULL } +#define FUSE_OPT_END { .templ = NULL } /** * Argument list @@ -120,7 +120,7 @@ struct fuse_args { /** * Key value passed to the processing function if an option did not - * match any templated + * match any template */ #define FUSE_OPT_KEY_OPT -1 @@ -132,6 +132,22 @@ struct fuse_args { */ #define FUSE_OPT_KEY_NONOPT -2 +/** + * Special key value for options to keep + * + * Argument is not passed to processing function, but behave as if the + * processing function returned 1 + */ +#define FUSE_OPT_KEY_KEEP -3 + +/** + * Special key value for options to discard + * + * Argument is not passed to processing function, but behave as if the + * processing function returned zero + */ +#define FUSE_OPT_KEY_DISCARD -4 + /** * Processing function * @@ -201,6 +217,21 @@ int fuse_opt_add_opt(char **opts, const char *opt); */ int fuse_opt_add_arg(struct fuse_args *args, const char *arg); +/** + * Add an argument at the specified position in a NULL terminated + * argument vector + * + * Adds the argument to the N-th position. This is useful for adding + * options at the beggining of the array which must not come after the + * special '--' option. + * + * @param args is the structure containing the current argument list + * @param pos is the position at which to add the argument + * @param arg is the new argument to add + * @return -1 on allocation error, 0 on success + */ +int fuse_opt_insert_arg(struct fuse_args *args, int pos, const char *arg); + /** * Free the contents of argument list * diff --git a/kernel/configure.ac b/kernel/configure.ac index 0ef06f8..cdb2669 100644 --- a/kernel/configure.ac +++ b/kernel/configure.ac @@ -1,4 +1,4 @@ -AC_INIT(fuse-kernel, 2.5.0) +AC_INIT(fuse-kernel, 2.7.0-pre0) AC_CONFIG_HEADERS([config.h]) AC_PROG_INSTALL diff --git a/kernel/file.c b/kernel/file.c index e8dae79..be9cc39 100644 --- a/kernel/file.c +++ b/kernel/file.c @@ -350,9 +350,14 @@ static void fuse_send_readpages(struct fuse_req *req, struct file *file, loff_t pos = page_offset(req->pages[0]); size_t count = req->num_pages << PAGE_CACHE_SHIFT; req->out.page_zeroing = 1; - req->end = fuse_readpages_end; fuse_read_fill(req, file, inode, pos, count, FUSE_READ); - request_send_background(fc, req); + if (fc->async_read) { + req->end = fuse_readpages_end; + request_send_background(fc, req); + } else { + request_send(fc, req); + fuse_readpages_end(fc, req); + } } struct fuse_readpages_data { diff --git a/kernel/fuse_i.h b/kernel/fuse_i.h index 4979fac..b37b6aa 100644 --- a/kernel/fuse_i.h +++ b/kernel/fuse_i.h @@ -369,6 +369,9 @@ struct fuse_conn { reply, before any other request, and never cleared */ unsigned conn_error : 1; + /** Do readpages asynchronously? Only set in INIT */ + unsigned async_read : 1; + /* * The following bitfields are only for optimization purposes * and hence races in setting them will not cause malfunction diff --git a/kernel/fuse_kernel.h b/kernel/fuse_kernel.h index 191b97d..54b1933 100644 --- a/kernel/fuse_kernel.h +++ b/kernel/fuse_kernel.h @@ -49,7 +49,7 @@ #define FUSE_KERNEL_VERSION 7 /** Minor version number of this interface */ -#define FUSE_KERNEL_MINOR_VERSION 5 +#define FUSE_KERNEL_MINOR_VERSION 6 /** The node ID of the root inode */ #define FUSE_ROOT_ID 1 @@ -93,6 +93,9 @@ struct fuse_kstatfs { __u32 spare[6]; }; +/** + * Bitmasks for fuse_setattr_in.valid + */ #define FATTR_MODE (1 << 0) #define FATTR_UID (1 << 1) #define FATTR_GID (1 << 2) @@ -110,6 +113,11 @@ struct fuse_kstatfs { #define FOPEN_DIRECT_IO (1 << 0) #define FOPEN_KEEP_CACHE (1 << 1) +/** + * INIT request/reply flags + */ +#define FUSE_ASYNC_READ (1 << 0) + enum fuse_opcode { FUSE_LOOKUP = 1, FUSE_FORGET = 2, /* no reply */ @@ -282,12 +290,16 @@ struct fuse_access_in { struct fuse_init_in { __u32 major; __u32 minor; + __u32 max_readahead; + __u32 flags; }; struct fuse_init_out { __u32 major; __u32 minor; - __u32 unused[3]; + __u32 max_readahead; + __u32 flags; + __u32 unused; __u32 max_write; }; diff --git a/kernel/inode.c b/kernel/inode.c index f10990f..00a13cc 100644 --- a/kernel/inode.c +++ b/kernel/inode.c @@ -646,6 +646,19 @@ static void process_init_reply(struct fuse_conn *fc, struct fuse_req *req) if (req->out.h.error || arg->major != FUSE_KERNEL_VERSION) fc->conn_error = 1; else { +#ifdef KERNEL_2_6 + unsigned long ra_pages; + + if (arg->minor >= 6) { + ra_pages = arg->max_readahead / PAGE_CACHE_SIZE; + fc->async_read = arg->flags & FUSE_ASYNC_READ; + } else { + ra_pages = fc->max_read / PAGE_CACHE_SIZE; + fc->async_read = 0; + } + + fc->bdi.ra_pages = min(fc->bdi.ra_pages, ra_pages); +#endif fc->minor = arg->minor; fc->max_write = arg->minor < 5 ? 4096 : arg->max_write; } @@ -669,6 +682,10 @@ static void fuse_send_init(struct fuse_conn *fc) arg->major = FUSE_KERNEL_VERSION; arg->minor = FUSE_KERNEL_MINOR_VERSION; +#ifdef KERNEL_2_6 + arg->max_readahead = fc->bdi.ra_pages * PAGE_CACHE_SIZE; + arg->flags |= FUSE_ASYNC_READ; +#endif req->in.h.opcode = FUSE_INIT; req->in.numargs = 1; req->in.args[0].size = sizeof(*arg); @@ -732,10 +749,6 @@ static int fuse_fill_super(struct super_block *sb, void *data, int silent) fc->user_id = d.user_id; fc->group_id = d.group_id; fc->max_read = d.max_read; -#ifdef KERNEL_2_6 - if (fc->max_read / PAGE_CACHE_SIZE < fc->bdi.ra_pages) - fc->bdi.ra_pages = fc->max_read / PAGE_CACHE_SIZE; -#endif /* Used by get_root_inode() */ sb->s_fs_info = fc; diff --git a/lib/Makefile.am b/lib/Makefile.am index d58cfed..366fcb0 100644 --- a/lib/Makefile.am +++ b/lib/Makefile.am @@ -22,7 +22,7 @@ libfuse_la_SOURCES = \ helper.c \ $(mount_source) -libfuse_la_LDFLAGS = -lpthread -version-number 2:5:0 \ +libfuse_la_LDFLAGS = -lpthread -version-number 2:7:0 \ -Wl,--version-script,fuse_versionscript EXTRA_DIST = fuse_versionscript diff --git a/lib/fuse.c b/lib/fuse.c index 7d66a7d..2cfb436 100644 --- a/lib/fuse.c +++ b/lib/fuse.c @@ -553,7 +553,7 @@ 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_conn_info *conn) { struct fuse *f = (struct fuse *) data; struct fuse_context *c = fuse_get_context(); @@ -562,7 +562,7 @@ static void fuse_data_init(void *data) c->fuse = f; if (f->op.init) - f->user_data = f->op.init(); + f->user_data = f->op.init(conn); } static void fuse_data_destroy(void *data) @@ -1808,7 +1808,6 @@ void fuse_set_getcontext_func(struct fuse_context *(*func)(void)) enum { KEY_HELP, - KEY_KEEP }; #define FUSE_LIB_OPT(t, p, v) { t, offsetof(struct fuse_config, p), v } @@ -1816,8 +1815,8 @@ enum { static const struct fuse_opt fuse_lib_opts[] = { FUSE_OPT_KEY("-h", KEY_HELP), FUSE_OPT_KEY("--help", KEY_HELP), - FUSE_OPT_KEY("debug", KEY_KEEP), - FUSE_OPT_KEY("-d", KEY_KEEP), + FUSE_OPT_KEY("debug", FUSE_OPT_KEY_KEEP), + FUSE_OPT_KEY("-d", FUSE_OPT_KEY_KEEP), FUSE_LIB_OPT("debug", debug, 1), FUSE_LIB_OPT("-d", debug, 1), FUSE_LIB_OPT("hard_remove", hard_remove, 1), @@ -1906,6 +1905,11 @@ struct fuse *fuse_new_common(int fd, struct fuse_args *args, f->conf.readdir_ino = 1; #endif + if (compat && compat <= 25) { + if (fuse_sync_compat_args(args) == -1) + goto out_free; + } + f->se = fuse_lowlevel_new(args, &fuse_path_ops, sizeof(fuse_path_ops), f); if (f->se == NULL) goto out_free; @@ -2012,13 +2016,13 @@ void fuse_destroy(struct fuse *f) free(f); } -#ifndef __FreeBSD__ - #include "fuse_compat.h" +#ifndef __FreeBSD__ + static int fuse_do_open(struct fuse *f, char *path, struct fuse_file_info *fi) { - if (!f->compat) + if (!f->compat || f->compat >= 25) return f->op.open(path, fi); else if (f->compat == 22) { int err; @@ -2045,7 +2049,7 @@ static void fuse_do_release(struct fuse *f, char *path, static int fuse_do_opendir(struct fuse *f, char *path, struct fuse_file_info *fi) { - if (!f->compat) { + if (!f->compat || f->compat >= 25) { return f->op.opendir(path, fi); } else { int err; @@ -2085,7 +2089,7 @@ static int fuse_do_statfs(struct fuse *f, char *path, struct statvfs *buf) { int err; - if (!f->compat) { + if (!f->compat || f->compat >= 25) { err = f->op.statfs(path, buf); } else if (f->compat > 11) { struct statfs oldbuf; @@ -2179,3 +2183,13 @@ static int fuse_do_statfs(struct fuse *f, char *path, struct statvfs *buf) } #endif /* __FreeBSD__ */ + +struct fuse *fuse_new_compat25(int fd, struct fuse_args *args, + const struct fuse_operations_compat25 *op, + size_t op_size) +{ + return fuse_new_common(fd, args, (struct fuse_operations *) op, + op_size, 25); +} + +__asm__(".symver fuse_new_compat25,fuse_new@FUSE_2.5"); diff --git a/lib/fuse_i.h b/lib/fuse_i.h index efbabf7..79c3cbf 100644 --- a/lib/fuse_i.h +++ b/lib/fuse_i.h @@ -22,3 +22,5 @@ struct fuse_session *fuse_get_session(struct fuse *f); struct fuse *fuse_new_common(int fd, struct fuse_args *args, const struct fuse_operations *op, size_t op_size, int compat); + +int fuse_sync_compat_args(struct fuse_args *args); diff --git a/lib/fuse_lowlevel.c b/lib/fuse_lowlevel.c index 0bd6c99..13ddab9 100644 --- a/lib/fuse_lowlevel.c +++ b/lib/fuse_lowlevel.c @@ -10,6 +10,7 @@ #include "fuse_lowlevel.h" #include "fuse_kernel.h" #include "fuse_opt.h" +#include "fuse_i.h" #include #include @@ -27,9 +28,8 @@ struct fuse_ll { struct fuse_lowlevel_ops op; int got_init; void *userdata; - int major; - int minor; uid_t owner; + struct fuse_conn_info conn; }; struct fuse_req { @@ -263,7 +263,7 @@ int fuse_reply_entry(fuse_req_t req, const struct fuse_entry_param *e) /* before ABI 7.4 e->ino == 0 was invalid, only ENOENT meant negative entry */ - if (!e->ino && req->f->minor < 4) + if (!e->ino && req->f->conn.proto_minor < 4) return fuse_reply_err(req, ENOENT); memset(&arg, 0, sizeof(arg)); @@ -330,7 +330,7 @@ int fuse_reply_buf(fuse_req_t req, const char *buf, size_t size) int fuse_reply_statfs(fuse_req_t req, const struct statvfs *stbuf) { struct fuse_statfs_out arg; - size_t size = req->f->minor < 4 ? FUSE_COMPAT_STATFS_SIZE : sizeof(arg); + size_t size = req->f->conn.proto_minor < 4 ? FUSE_COMPAT_STATFS_SIZE : sizeof(arg); memset(&arg, 0, sizeof(arg)); convert_statfs(stbuf, &arg.st); @@ -693,27 +693,51 @@ static void do_init(fuse_req_t req, struct fuse_init_in *arg) if (f->debug) { printf("INIT: %u.%u\n", arg->major, arg->minor); + if (arg->major > 7 || (arg->major == 7 && arg->minor >= 6)) { + printf("flags=0x%08x\n", arg->flags); + printf("max_readahead=0x%08x\n", arg->max_readahead); + } fflush(stdout); } - f->got_init = 1; - if (f->op.init) - f->op.init(f->userdata); - - f->major = FUSE_KERNEL_VERSION; - f->minor = arg->minor; + f->conn.proto_major = arg->major; + f->conn.proto_minor = arg->minor; + + if (arg->major > 7 || (arg->major == 7 && arg->minor >= 6)) { + if (f->conn.async_read) + f->conn.async_read = arg->flags & FUSE_ASYNC_READ; + if (arg->max_readahead < f->conn.max_readahead) + f->conn.max_readahead = arg->max_readahead; + } else { + f->conn.async_read = 0; + f->conn.max_readahead = 0; + } if (bufsize < FUSE_MIN_READ_BUFFER) { fprintf(stderr, "fuse: warning: buffer size too small: %i\n", bufsize); bufsize = FUSE_MIN_READ_BUFFER; } + bufsize -= 4096; + if (bufsize < f->conn.max_write) + f->conn.max_write = bufsize; + + f->got_init = 1; + if (f->op.init) + f->op.init(f->userdata, &f->conn); + memset(&outarg, 0, sizeof(outarg)); - outarg.major = f->major; + outarg.major = FUSE_KERNEL_VERSION; outarg.minor = FUSE_KERNEL_MINOR_VERSION; - outarg.max_write = bufsize - 4096; + if (f->conn.async_read) + outarg.flags |= FUSE_ASYNC_READ; + outarg.max_readahead = f->conn.max_readahead; + outarg.max_write = f->conn.max_write; if (f->debug) { printf(" INIT: %u.%u\n", outarg.major, outarg.minor); + printf(" flags=0x%08x\n", outarg.flags); + printf(" max_readahead=0x%08x\n", outarg.max_readahead); + printf(" max_write=0x%08x\n", outarg.max_write); fflush(stdout); } @@ -902,6 +926,11 @@ static struct fuse_opt fuse_ll_opts[] = { { "debug", offsetof(struct fuse_ll, debug), 1 }, { "-d", offsetof(struct fuse_ll, debug), 1 }, { "allow_root", offsetof(struct fuse_ll, allow_root), 1 }, + { "max_write=%u", offsetof(struct fuse_ll, conn.max_write), 0 }, + { "max_readahead=%u", offsetof(struct fuse_ll, conn.max_readahead), 0 }, + { "async_read", offsetof(struct fuse_ll, conn.async_read), 1 }, + { "sync_read", offsetof(struct fuse_ll, conn.async_read), 0 }, + FUSE_OPT_KEY("max_read=", FUSE_OPT_KEY_DISCARD), FUSE_OPT_KEY("-h", KEY_HELP), FUSE_OPT_KEY("--help", KEY_HELP), FUSE_OPT_KEY("-V", KEY_VERSION), @@ -915,6 +944,15 @@ static void fuse_ll_version(void) FUSE_KERNEL_VERSION, FUSE_KERNEL_MINOR_VERSION); } +static void fuse_ll_help(void) +{ + fprintf(stderr, +" -o max_write=N set maximum size of write requests\n" +" -o max_readahead=N set maximum readahead\n" +" -o async_read perform reads asynchronously (default)\n" +" -o sync_read perform reads synchronously\n"); +} + static int fuse_ll_opt_proc(void *data, const char *arg, int key, struct fuse_args *outargs) { @@ -922,6 +960,7 @@ static int fuse_ll_opt_proc(void *data, const char *arg, int key, switch (key) { case KEY_HELP: + fuse_ll_help(); break; case KEY_VERSION: @@ -972,6 +1011,10 @@ struct fuse_session *fuse_lowlevel_new(struct fuse_args *args, goto out; } + f->conn.async_read = 1; + f->conn.max_write = UINT_MAX; + f->conn.max_readahead = UINT_MAX; + if (fuse_opt_parse(args, f, fuse_ll_opts, fuse_ll_opt_proc) == -1) goto out_free; @@ -991,10 +1034,10 @@ struct fuse_session *fuse_lowlevel_new(struct fuse_args *args, return NULL; } -#ifndef __FreeBSD__ - #include "fuse_lowlevel_compat.h" +#ifndef __FreeBSD__ + static void fill_open_compat(struct fuse_open_out *arg, const struct fuse_file_info_compat *f) { @@ -1062,3 +1105,49 @@ __asm__(".symver fuse_reply_open_compat,fuse_reply_open@FUSE_2.4"); __asm__(".symver fuse_lowlevel_new_compat,fuse_lowlevel_new@FUSE_2.4"); #endif /* __FreeBSD__ */ + +struct fuse_ll_compat_conf { + unsigned max_read; + int set_max_read; +}; + +static const struct fuse_opt fuse_ll_opts_compat[] = { + { "max_read=", offsetof(struct fuse_ll_compat_conf, set_max_read), 1 }, + { "max_read=%u", offsetof(struct fuse_ll_compat_conf, max_read), 0 }, + FUSE_OPT_KEY("max_read=", FUSE_OPT_KEY_KEEP), + FUSE_OPT_END +}; + +int fuse_sync_compat_args(struct fuse_args *args) +{ + struct fuse_ll_compat_conf conf; + + if (fuse_opt_parse(args, &conf, fuse_ll_opts_compat, NULL) == -1) + return -1; + + if (fuse_opt_insert_arg(args, 1, "-osync_read")) + return -1; + + if (conf.set_max_read) { + char tmpbuf[64]; + + sprintf(tmpbuf, "-omax_readahead=%u", conf.max_read); + if (fuse_opt_insert_arg(args, 1, tmpbuf) == -1) + return -1; + } + return 0; +} + +struct fuse_session *fuse_lowlevel_new_compat25(struct fuse_args *args, + const struct fuse_lowlevel_ops_compat25 *op, + size_t op_size, void *userdata) +{ + if (fuse_sync_compat_args(args) == -1) + return NULL; + + return fuse_lowlevel_new(args, (const struct fuse_lowlevel_ops *) op, + op_size, userdata); +} + + +__asm__(".symver fuse_lowlevel_new_compat25,fuse_lowlevel_new@FUSE_2.5"); diff --git a/lib/fuse_opt.c b/lib/fuse_opt.c index 2ac499c..582c6ad 100644 --- a/lib/fuse_opt.c +++ b/lib/fuse_opt.c @@ -62,6 +62,21 @@ int fuse_opt_add_arg(struct fuse_args *args, const char *arg) return 0; } +int fuse_opt_insert_arg(struct fuse_args *args, int pos, const char *arg) +{ + assert(pos <= args->argc); + if (fuse_opt_add_arg(args, arg) == -1) + return -1; + + if (pos != args->argc - 1) { + char *newarg = args->argv[args->argc - 1]; + memmove(&args->argv[pos + 1], &args->argv[pos], + sizeof(char *) * (args->argc - pos - 1)); + args->argv[pos] = newarg; + } + return 0; +} + static int next_arg(struct fuse_opt_context *ctx, const char *opt) { if (ctx->argctr + 1 >= ctx->argc) { @@ -102,25 +117,13 @@ static int add_opt(struct fuse_opt_context *ctx, const char *opt) return fuse_opt_add_opt(&ctx->opts, opt); } -static int insert_arg(struct fuse_opt_context *ctx, int pos, const char *arg) -{ - assert(pos <= ctx->outargs.argc); - if (add_arg(ctx, arg) == -1) - return -1; - - if (pos != ctx->outargs.argc - 1) { - char *newarg = ctx->outargs.argv[ctx->outargs.argc - 1]; - memmove(&ctx->outargs.argv[pos + 1], &ctx->outargs.argv[pos], - sizeof(char *) * (ctx->outargs.argc - pos - 1)); - ctx->outargs.argv[pos] = newarg; - } - return 0; -} - static int call_proc(struct fuse_opt_context *ctx, const char *arg, int key, int iso) { - if (ctx->proc) { + if (key == FUSE_OPT_KEY_DISCARD) + return 0; + + if (key != FUSE_OPT_KEY_KEEP && ctx->proc) { int res = ctx->proc(ctx->data, arg, key, &ctx->outargs); if (res == -1 || !res) return res; @@ -155,8 +158,8 @@ static int match_template(const char *t, const char *arg, unsigned *sepp) static const struct fuse_opt *find_opt(const struct fuse_opt *opt, const char *arg, unsigned *sepp) { - for (; opt && opt->template; opt++) - if (match_template(opt->template, arg, sepp)) + for (; opt && opt->templ; opt++) + if (match_template(opt->templ, arg, sepp)) return opt; return NULL; } @@ -195,11 +198,11 @@ static int process_opt(struct fuse_opt_context *ctx, return -1; } else { void *var = ctx->data + opt->offset; - if (sep && opt->template[sep + 1]) { + if (sep && opt->templ[sep + 1]) { const char *param = arg + sep; - if (opt->template[sep] == '=') + if (opt->templ[sep] == '=') param ++; - if (process_opt_param(var, opt->template + sep + 1, + if (process_opt_param(var, opt->templ + sep + 1, param, arg) == -1) return -1; } else @@ -239,7 +242,7 @@ static int process_gopt(struct fuse_opt_context *ctx, const char *arg, int iso) if (opt) { for (; opt; opt = find_opt(opt + 1, arg, &sep)) { int res; - if (sep && opt->template[sep] == ' ' && !arg[sep]) + if (sep && opt->templ[sep] == ' ' && !arg[sep]) res = process_opt_sep_arg(ctx, opt, sep, arg, iso); else res = process_opt(ctx, opt, sep, arg, iso); @@ -321,12 +324,14 @@ static int opt_parse(struct fuse_opt_context *ctx) return -1; if (ctx->opts) { - if (insert_arg(ctx, 1, "-o") == -1 || - insert_arg(ctx, 2, ctx->opts) == -1) + if (fuse_opt_insert_arg(&ctx->outargs, 1, "-o") == -1 || + fuse_opt_insert_arg(&ctx->outargs, 2, ctx->opts) == -1) return -1; } - if (ctx->nonopt && ctx->nonopt == ctx->outargs.argc) + if (ctx->nonopt && ctx->nonopt == ctx->outargs.argc) { + free(ctx->outargs.argv[ctx->outargs.argc - 1]); ctx->outargs.argv[--ctx->outargs.argc] = NULL; + } return 0; } diff --git a/lib/fuse_versionscript b/lib/fuse_versionscript index 9927158..421228e 100644 --- a/lib/fuse_versionscript +++ b/lib/fuse_versionscript @@ -61,18 +61,16 @@ FUSE_2.4 { FUSE_2.5 { global: - fuse_lowlevel_new; fuse_lowlevel_new_compat; - fuse_main_real; fuse_main_real_compat22; fuse_mount; fuse_mount_compat22; - fuse_new; fuse_new_compat22; fuse_opt_parse; fuse_opt_add_opt; fuse_opt_add_arg; fuse_opt_free_args; + fuse_opt_insert_arg; fuse_opt_match; fuse_parse_cmdline; fuse_remove_signal_handlers; @@ -81,10 +79,26 @@ FUSE_2.5 { fuse_reply_open_compat; fuse_reply_statfs; fuse_reply_statfs_compat; - fuse_setup; fuse_setup_compat22; fuse_set_signal_handlers; +} FUSE_2.4; + +FUSE_2.6 { + global: + fuse_opt_insert_arg; +} FUSE_2.5; + +FUSE_2.7 { + global: + fuse_lowlevel_new; + fuse_lowlevel_new_compat25; + fuse_main_real; + fuse_main_real_compat25; + fuse_new; + fuse_new_compat25; + fuse_setup; + fuse_setup_compat25; local: *; -} FUSE_2.4; +} FUSE_2.6; diff --git a/lib/helper.c b/lib/helper.c index b7f77be..f937366 100644 --- a/lib/helper.c +++ b/lib/helper.c @@ -22,7 +22,6 @@ enum { KEY_HELP, KEY_HELP_NOHEADER, KEY_VERSION, - KEY_KEEP, }; struct helper_opts { @@ -46,8 +45,9 @@ static const struct fuse_opt fuse_helper_opts[] = { FUSE_OPT_KEY("-ho", KEY_HELP_NOHEADER), FUSE_OPT_KEY("-V", KEY_VERSION), FUSE_OPT_KEY("--version", KEY_VERSION), - FUSE_OPT_KEY("-d", KEY_KEEP), - FUSE_OPT_KEY("debug", KEY_KEEP), + FUSE_OPT_KEY("-d", FUSE_OPT_KEY_KEEP), + FUSE_OPT_KEY("debug", FUSE_OPT_KEY_KEEP), + FUSE_OPT_KEY("fsname=", FUSE_OPT_KEY_KEEP), FUSE_OPT_END }; @@ -100,11 +100,12 @@ static int fuse_helper_opt_proc(void *data, const char *arg, int key, case FUSE_OPT_KEY_NONOPT: if (!hopts->mountpoint) return fuse_opt_add_opt(&hopts->mountpoint, arg); - - /* fall through */ + else { + fprintf(stderr, "fuse: invalid argument `%s'\n", arg); + return -1; + } default: - case KEY_KEEP: return 1; } } @@ -289,10 +290,10 @@ int fuse_main(void) return -1; } -#ifndef __FreeBSD__ - #include "fuse_compat.h" +#ifndef __FreeBSD__ + struct fuse *fuse_setup_compat22(int argc, char *argv[], const struct fuse_operations_compat22 *op, size_t op_size, char **mountpoint, @@ -341,3 +342,24 @@ __asm__(".symver fuse_main_compat2,fuse_main@"); __asm__(".symver fuse_main_real_compat22,fuse_main_real@FUSE_2.2"); #endif /* __FreeBSD__ */ + + +struct fuse *fuse_setup_compat25(int argc, char *argv[], + const struct fuse_operations_compat25 *op, + size_t op_size, char **mountpoint, + int *multithreaded, int *fd) +{ + return fuse_setup_common(argc, argv, (struct fuse_operations *) op, + op_size, mountpoint, multithreaded, fd, 25); +} + +int fuse_main_real_compat25(int argc, char *argv[], + const struct fuse_operations_compat25 *op, + size_t op_size) +{ + return fuse_main_common(argc, argv, (struct fuse_operations *) op, op_size, + 25); +} + +__asm__(".symver fuse_setup_compat25,fuse_setup@FUSE_2.5"); +__asm__(".symver fuse_main_real_compat25,fuse_main_real@FUSE_2.5"); diff --git a/lib/mount.c b/lib/mount.c index 219ee14..2840a54 100644 --- a/lib/mount.c +++ b/lib/mount.c @@ -48,6 +48,7 @@ static const struct fuse_opt fuse_mount_opts[] = { FUSE_OPT_KEY("fsname=", KEY_KERN), FUSE_OPT_KEY("large_read", KEY_KERN), FUSE_OPT_KEY("max_read=", KEY_KERN), + FUSE_OPT_KEY("max_read=", FUSE_OPT_KEY_KEEP), FUSE_OPT_KEY("-r", KEY_RO), FUSE_OPT_KEY("ro", KEY_KERN), FUSE_OPT_KEY("rw", KEY_KERN),