diff options
-rw-r--r-- | include/fuse.h | 3 | ||||
-rw-r--r-- | include/fuse_common.h | 45 | ||||
-rw-r--r-- | include/fuse_lowlevel.h | 41 | ||||
-rw-r--r-- | lib/cuse_lowlevel.c | 7 | ||||
-rw-r--r-- | lib/fuse.c | 40 | ||||
-rw-r--r-- | lib/fuse_i.h | 56 | ||||
-rw-r--r-- | lib/fuse_loop_mt.c | 93 | ||||
-rw-r--r-- | lib/fuse_misc.h | 3 | ||||
-rw-r--r-- | lib/fuse_versionscript | 14 | ||||
-rw-r--r-- | lib/helper.c | 18 | ||||
-rw-r--r-- | lib/meson.build | 2 | ||||
-rw-r--r-- | meson.build | 2 | ||||
-rw-r--r-- | util/meson.build | 2 |
13 files changed, 278 insertions, 48 deletions
diff --git a/include/fuse.h b/include/fuse.h index 1a2f841..917a91c 100644 --- a/include/fuse.h +++ b/include/fuse.h @@ -1011,6 +1011,9 @@ void fuse_exit(struct fuse *f); #if FUSE_USE_VERSION < 32 int fuse_loop_mt_31(struct fuse *f, int clone_fd); #define fuse_loop_mt(f, clone_fd) fuse_loop_mt_31(f, clone_fd) +#elif FUSE_USE_VERSION < FUSE_MAKE_VERSION(3, 12) +int fuse_loop_mt_32(struct fuse *f, struct fuse_loop_config *config); +#define fuse_loop_mt(f, config) fuse_loop_mt_32(f, config) #else /** * FUSE event loop with multiple threads diff --git a/include/fuse_common.h b/include/fuse_common.h index 3f7260c..b40814f 100644 --- a/include/fuse_common.h +++ b/include/fuse_common.h @@ -23,7 +23,7 @@ #define FUSE_MAJOR_VERSION 3 /** Minor version of FUSE library interface */ -#define FUSE_MINOR_VERSION 11 +#define FUSE_MINOR_VERSION 12 #define FUSE_MAKE_VERSION(maj, min) ((maj) * 100 + (min)) #define FUSE_VERSION FUSE_MAKE_VERSION(FUSE_MAJOR_VERSION, FUSE_MINOR_VERSION) @@ -104,11 +104,20 @@ struct fuse_file_info { uint32_t poll_events; }; + + /** * Configuration parameters passed to fuse_session_loop_mt() and * fuse_loop_mt(). + * Deprecated and replaced by a newer private struct in FUSE API + * version 312 (FUSE_MAKE_VERSION(3, 12) */ +#if FUSE_USE_VERSION < FUSE_MAKE_VERSION(3, 12) +struct fuse_loop_config_v1; /* forward declarition */ struct fuse_loop_config { +#else +struct fuse_loop_config_v1 { +#endif /** * whether to use separate device fds for each thread * (may increase performance) @@ -128,6 +137,7 @@ struct fuse_loop_config { unsigned int max_idle_threads; }; + /************************************************************************** * Capability bits for 'fuse_conn_info.capable' and 'fuse_conn_info.want' * **************************************************************************/ @@ -834,6 +844,39 @@ int fuse_set_signal_handlers(struct fuse_session *se); */ void fuse_remove_signal_handlers(struct fuse_session *se); +/** + * Create and set default config for fuse_session_loop_mt and fuse_loop_mt. + * + * @return anonymous config struct + */ +struct fuse_loop_config *fuse_loop_cfg_create(void); + +/** + * Free the config data structure + */ +void fuse_loop_cfg_destroy(struct fuse_loop_config *config); + +/** + * fuse_loop_config2 setter to set the number of max idle threads. + */ +void fuse_loop_cfg_set_idle_threads(struct fuse_loop_config *config, + unsigned int value); + +/** + * fuse_loop_config2 setter to enable the clone_fd feature + */ +void fuse_loop_cfg_set_clone_fd(struct fuse_loop_config *config, + unsigned int value); + +/** + * Convert old config to more recernt fuse_loop_config2 + * + * @param config current config2 type + * @param v1_conf older config1 type (below FUSE API 312) + */ +void fuse_loop_cfg_convert(struct fuse_loop_config *config, + struct fuse_loop_config_v1 *v1_conf); + /* ----------------------------------------------------------- * * Compatibility stuff * * ----------------------------------------------------------- */ diff --git a/include/fuse_lowlevel.h b/include/fuse_lowlevel.h index d73e9fa..378742d 100644 --- a/include/fuse_lowlevel.h +++ b/include/fuse_lowlevel.h @@ -1968,26 +1968,29 @@ int fuse_session_mount(struct fuse_session *se, const char *mountpoint); int fuse_session_loop(struct fuse_session *se); #if FUSE_USE_VERSION < 32 -int fuse_session_loop_mt_31(struct fuse_session *se, int clone_fd); -#define fuse_session_loop_mt(se, clone_fd) fuse_session_loop_mt_31(se, clone_fd) + int fuse_session_loop_mt_31(struct fuse_session *se, int clone_fd); + #define fuse_session_loop_mt(se, clone_fd) fuse_session_loop_mt_31(se, clone_fd) +#elif FUSE_USE_VERSION < FUSE_MAKE_VERSION(3, 12) + int fuse_session_loop_mt_32(struct fuse_session *se, struct fuse_loop_config *config); + #define fuse_session_loop_mt(se, config) fuse_session_loop_mt_32(se, config) #else -#if (!defined(__UCLIBC__) && !defined(__APPLE__)) -/** - * Enter a multi-threaded event loop. - * - * For a description of the return value and the conditions when the - * event loop exits, refer to the documentation of - * fuse_session_loop(). - * - * @param se the session - * @param config session loop configuration - * @return see fuse_session_loop() - */ -int fuse_session_loop_mt(struct fuse_session *se, struct fuse_loop_config *config); -#else -int fuse_session_loop_mt_32(struct fuse_session *se, struct fuse_loop_config *config); -#define fuse_session_loop_mt(se, config) fuse_session_loop_mt_32(se, config) -#endif + #if (!defined(__UCLIBC__) && !defined(__APPLE__)) + /** + * Enter a multi-threaded event loop. + * + * For a description of the return value and the conditions when the + * event loop exits, refer to the documentation of + * fuse_session_loop(). + * + * @param se the session + * @param config session loop configuration + * @return see fuse_session_loop() + */ + int fuse_session_loop_mt(struct fuse_session *se, struct fuse_loop_config *config); + #else + int fuse_session_loop_mt_312(struct fuse_session *se, struct fuse_loop_config *config); + #define fuse_session_loop_mt(se, config) fuse_session_loop_mt_312(se, config) + #endif #endif /** diff --git a/lib/cuse_lowlevel.c b/lib/cuse_lowlevel.c index b70947e..01a62ab 100644 --- a/lib/cuse_lowlevel.c +++ b/lib/cuse_lowlevel.c @@ -351,10 +351,9 @@ int cuse_lowlevel_main(int argc, char *argv[], const struct cuse_info *ci, return 1; if (multithreaded) { - struct fuse_loop_config config; - config.clone_fd = 0; - config.max_idle_threads = 10; - res = fuse_session_loop_mt_32(se, &config); + struct fuse_loop_config *config = fuse_loop_cfg_create(); + res = fuse_session_loop_mt(se, config); + fuse_loop_cfg_destroy(config); } else res = fuse_session_loop(se); @@ -4577,8 +4577,8 @@ int fuse_loop(struct fuse *f) return fuse_session_loop(f->se); } -FUSE_SYMVER("fuse_loop_mt_32", "fuse_loop_mt@@FUSE_3.2") -int fuse_loop_mt_32(struct fuse *f, struct fuse_loop_config *config) +FUSE_SYMVER("fuse_loop_mt_312", "fuse_loop_mt@@FUSE_3.12") +int fuse_loop_mt_312(struct fuse *f, struct fuse_loop_config *config) { if (f == NULL) return -1; @@ -4587,19 +4587,45 @@ int fuse_loop_mt_32(struct fuse *f, struct fuse_loop_config *config) if (res) return -1; - res = fuse_session_loop_mt_32(fuse_get_session(f), config); + res = fuse_session_loop_mt_312(fuse_get_session(f), config); fuse_stop_cleanup_thread(f); return res; } +int fuse_loop_mt_32(struct fuse *f, struct fuse_loop_config_v1 *config_v1); +FUSE_SYMVER("fuse_loop_mt_32", "fuse_loop_mt@FUSE_3.2") +int fuse_loop_mt_32(struct fuse *f, struct fuse_loop_config_v1 *config_v1) +{ + struct fuse_loop_config *config = fuse_loop_cfg_create(); + if (config == NULL) + return ENOMEM; + + fuse_loop_cfg_convert(config, config_v1); + + int res = fuse_loop_mt_312(f, config); + + fuse_loop_cfg_destroy(config); + + return res; +} + int fuse_loop_mt_31(struct fuse *f, int clone_fd); FUSE_SYMVER("fuse_loop_mt_31", "fuse_loop_mt@FUSE_3.0") int fuse_loop_mt_31(struct fuse *f, int clone_fd) { - struct fuse_loop_config config; - config.clone_fd = clone_fd; - config.max_idle_threads = 10; - return fuse_loop_mt_32(f, &config); + int err; + struct fuse_loop_config *config = fuse_loop_cfg_create(); + + if (config == NULL) + return ENOMEM; + + fuse_loop_cfg_set_clone_fd(config, clone_fd); + + err = fuse_loop_mt_312(f, config); + + fuse_loop_cfg_destroy(config); + + return err; } void fuse_exit(struct fuse *f) diff --git a/lib/fuse_i.h b/lib/fuse_i.h index d38b630..6930a20 100644 --- a/lib/fuse_i.h +++ b/lib/fuse_i.h @@ -87,6 +87,50 @@ struct fuse_module { int ctr; }; +/** + * Configuration parameters passed to fuse_session_loop_mt() and + * fuse_loop_mt(). + * + * Internal API to avoid exposing the plain data structure and + * causing compat issues after adding or removing struct members. + * + */ +#if FUSE_USE_VERSION >= FUSE_MAKE_VERSION(3, 12) +struct fuse_loop_config +{ + /* verififier that a correct struct was was passed. This is especially + * needed, as versions below (3, 12) were using a public struct + * (now called fuse_loop_config_v1), which was hard to extend with + * additional parameters, without risking that file system implementations + * would not have noticed and might either pass uninitialized members + * or even too small structs. + * fuse_loop_config_v1 has clone_fd at this offset, which should be either 0 + * or 1. v2 or even higher version just need to set a value here + * which not conflicting and very unlikely as having been set by + * file system implementation. + */ + int version_id; + + /** + * whether to use separate device fds for each thread + * (may increase performance) + */ + int clone_fd; + /** + * The maximum number of available worker threads before they + * start to get deleted when they become idle. If not + * specified, the default is 10. + * + * Adjusting this has performance implications; a very small number + * of threads in the pool will cause a lot of thread creation and + * deletion overhead and performance may suffer. When set to 0, a new + * thread will be created to service every operation. + * The special value of -1 means that this parameter is disabled. + */ + int max_idle_threads; +}; +#endif + /* ----------------------------------------------------------- * * Channel interface (when using -o clone_fd) * * ----------------------------------------------------------- */ @@ -128,8 +172,16 @@ void fuse_session_process_buf_int(struct fuse_session *se, struct fuse *fuse_new_31(struct fuse_args *args, const struct fuse_operations *op, size_t op_size, void *private_data); -int fuse_loop_mt_32(struct fuse *f, struct fuse_loop_config *config); -int fuse_session_loop_mt_32(struct fuse_session *se, struct fuse_loop_config *config); +int fuse_loop_mt_312(struct fuse *f, struct fuse_loop_config *config); +int fuse_session_loop_mt_312(struct fuse_session *se, struct fuse_loop_config *config); + +/** + * Internal verifier for the given config. + * + * @return negative standard error code or 0 on success + */ +int fuse_loop_cfg_verify(struct fuse_loop_config *config); + #define FUSE_MAX_MAX_PAGES 256 #define FUSE_DEFAULT_MAX_PAGES_PER_REQ 32 diff --git a/lib/fuse_loop_mt.c b/lib/fuse_loop_mt.c index 8fcc46c..2f0470b 100644 --- a/lib/fuse_loop_mt.c +++ b/lib/fuse_loop_mt.c @@ -24,10 +24,16 @@ #include <sys/time.h> #include <sys/ioctl.h> #include <assert.h> +#include <limits.h> /* Environment var controlling the thread stack size */ #define ENVNAME_THREAD_STACK "FUSE_THREAD_STACK" +#define FUSE_LOOP_MT_V2_IDENTIFIER INT_MAX - 2 +#define FUSE_LOOP_MT_DEF_CLONE_FD 0 +#define FUSE_LOOP_MT_DEF_IDLE_THREADS -1 /* thread destruction is disabled + * by default */ + struct fuse_worker { struct fuse_worker *prev; struct fuse_worker *next; @@ -303,13 +309,18 @@ static void fuse_join_worker(struct fuse_mt *mt, struct fuse_worker *w) free(w); } -FUSE_SYMVER("fuse_session_loop_mt_32", "fuse_session_loop_mt@@FUSE_3.2") -int fuse_session_loop_mt_32(struct fuse_session *se, struct fuse_loop_config *config) +int fuse_session_loop_mt_312(struct fuse_session *se, struct fuse_loop_config *config); +FUSE_SYMVER("fuse_session_loop_mt_312", "fuse_session_loop_mt@@FUSE_3.12") +int fuse_session_loop_mt_312(struct fuse_session *se, struct fuse_loop_config *config) { - int err; +int err; struct fuse_mt mt; struct fuse_worker *w; + err = fuse_loop_cfg_verify(config); + if (err) + return err; + memset(&mt, 0, sizeof(struct fuse_mt)); mt.se = se; mt.clone_fd = config->clone_fd; @@ -347,15 +358,83 @@ int fuse_session_loop_mt_32(struct fuse_session *se, struct fuse_loop_config *co if(se->error != 0) err = se->error; fuse_session_reset(se); + + return err; +} + +int fuse_session_loop_mt_32(struct fuse_session *se, struct fuse_loop_config_v1 *config_v1); +FUSE_SYMVER("fuse_session_loop_mt_32", "fuse_session_loop_mt@FUSE_3.2") +int fuse_session_loop_mt_32(struct fuse_session *se, struct fuse_loop_config_v1 *config_v1) +{ + int err; + + struct fuse_loop_config *config = fuse_loop_cfg_create(); + if (config == NULL) + return ENOMEM; + + fuse_loop_cfg_convert(config, config_v1); + + err = fuse_session_loop_mt_312(se, config); + + fuse_loop_cfg_destroy(config); + return err; } + int fuse_session_loop_mt_31(struct fuse_session *se, int clone_fd); FUSE_SYMVER("fuse_session_loop_mt_31", "fuse_session_loop_mt@FUSE_3.0") int fuse_session_loop_mt_31(struct fuse_session *se, int clone_fd) { - struct fuse_loop_config config; - config.clone_fd = clone_fd; - config.max_idle_threads = 10; - return fuse_session_loop_mt_32(se, &config); + struct fuse_loop_config *config = fuse_loop_cfg_create(); + if (clone_fd > 0) + fuse_loop_cfg_set_clone_fd(config, clone_fd); + return fuse_session_loop_mt_312(se, config); +} + +struct fuse_loop_config *fuse_loop_cfg_create(void) +{ + struct fuse_loop_config *config = calloc(1, sizeof(*config)); + if (config == NULL) + return NULL; + + config->version_id = FUSE_LOOP_MT_V2_IDENTIFIER; + config->max_idle_threads = FUSE_LOOP_MT_DEF_IDLE_THREADS; + config->clone_fd = FUSE_LOOP_MT_DEF_CLONE_FD; + + return config; +} + +void fuse_loop_cfg_destroy(struct fuse_loop_config *config) +{ + free(config); +} + +int fuse_loop_cfg_verify(struct fuse_loop_config *config) +{ + if (config->version_id != FUSE_LOOP_MT_V2_IDENTIFIER) + return -EINVAL; + + return 0; +} + +void fuse_loop_cfg_convert(struct fuse_loop_config *config, + struct fuse_loop_config_v1 *v1_conf) +{ + fuse_loop_cfg_set_idle_threads(config, v1_conf->max_idle_threads); + + fuse_loop_cfg_set_clone_fd(config, v1_conf->clone_fd); +} + +void fuse_loop_cfg_set_idle_threads(struct fuse_loop_config *config, + unsigned int value) +{ + config->max_idle_threads = value; } + +void fuse_loop_cfg_set_clone_fd(struct fuse_loop_config *config, + unsigned int value) +{ + config->clone_fd = value; +} + diff --git a/lib/fuse_misc.h b/lib/fuse_misc.h index f956ab7..e2e9ba5 100644 --- a/lib/fuse_misc.h +++ b/lib/fuse_misc.h @@ -11,6 +11,9 @@ /* Versioned symbols cannot be used in some cases because it - not supported on MacOSX (in MachO binary format) + + Note: "@@" denotes the default symbol, "@" is binary a compat version. + */ #ifndef __APPLE__ # if HAVE_SYMVER_ATTRIBUTE diff --git a/lib/fuse_versionscript b/lib/fuse_versionscript index a06f768..aff7e84 100644 --- a/lib/fuse_versionscript +++ b/lib/fuse_versionscript @@ -168,6 +168,20 @@ FUSE_3.7 { fuse_log; } FUSE_3.4; +FUSE_3.12 { + global: + fuse_session_loop_mt; + fuse_session_loop_mt_312; + fuse_loop_mt; + fuse_loop_mt_32; + fuse_loop_mt_312; + fuse_loop_cfg_create; + fuse_loop_cfg_destroy; + fuse_loop_cfg_set_idle_threads; + fuse_loop_cfg_set_clone_fd; + fuse_loop_cfg_convert; +} FUSE_3.4; + # Local Variables: # indent-tabs-mode: t # End: diff --git a/lib/helper.c b/lib/helper.c index 64ff7ad..fc6a6ee 100644 --- a/lib/helper.c +++ b/lib/helper.c @@ -283,6 +283,7 @@ int fuse_main_real(int argc, char *argv[], const struct fuse_operations *op, struct fuse *fuse; struct fuse_cmdline_opts opts; int res; + struct fuse_loop_config *loop_config = NULL; if (fuse_parse_cmdline(&args, &opts) != 0) return 1; @@ -338,13 +339,19 @@ int fuse_main_real(int argc, char *argv[], const struct fuse_operations *op, if (opts.singlethread) res = fuse_loop(fuse); else { - struct fuse_loop_config loop_config; - loop_config.clone_fd = opts.clone_fd; - loop_config.max_idle_threads = opts.max_idle_threads; - res = fuse_loop_mt_32(fuse, &loop_config); + loop_config = fuse_loop_cfg_create(); + if (loop_config == NULL) { + res = 7; + goto out3; + } + + fuse_loop_cfg_set_clone_fd(loop_config, opts.clone_fd); + + fuse_loop_cfg_set_idle_threads(loop_config, opts.max_idle_threads); + res = fuse_loop_mt(fuse, loop_config); } if (res) - res = 7; + res = 8; fuse_remove_signal_handlers(se); out3: @@ -352,6 +359,7 @@ out3: out2: fuse_destroy(fuse); out1: + fuse_loop_cfg_destroy(loop_config); free(opts.mountpoint); fuse_opt_free_args(&args); return res; diff --git a/lib/meson.build b/lib/meson.build index 98461d8..ef0e11e 100644 --- a/lib/meson.build +++ b/lib/meson.build @@ -37,7 +37,7 @@ libfuse = library('fuse3', libfuse_sources, version: meson.project_version(), soversion: '3', include_directories: include_dirs, dependencies: deps, install: true, link_depends: 'fuse_versionscript', - c_args: [ '-DFUSE_USE_VERSION=35', + c_args: [ '-DFUSE_USE_VERSION=312', '-DFUSERMOUNT_DIR="@0@"'.format(fusermount_path) ], link_args: ['-Wl,--version-script,' + meson.current_source_dir() + '/fuse_versionscript' ]) diff --git a/meson.build b/meson.build index 342dee1..3cef64f 100644 --- a/meson.build +++ b/meson.build @@ -1,4 +1,4 @@ -project('libfuse3', ['c'], version: '3.11.0', +project('libfuse3', ['c'], version: '3.12.0', meson_version: '>= 0.42', default_options: [ 'buildtype=debugoptimized', diff --git a/util/meson.build b/util/meson.build index 577668f..7846870 100644 --- a/util/meson.build +++ b/util/meson.build @@ -11,7 +11,7 @@ executable('mount.fuse3', ['mount.fuse.c'], link_with: [ libfuse ], install: true, install_dir: get_option('sbindir'), - c_args: '-DFUSE_USE_VERSION=35') + c_args: '-DFUSE_USE_VERSION=312') udevrulesdir = get_option('udevrulesdir') |