diff options
Diffstat (limited to 'lib')
-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 |
8 files changed, 207 insertions, 26 deletions
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' ]) |