From f12d9686d4d673e59b8f561c49996820763220b1 Mon Sep 17 00:00:00 2001 From: Joseph Dodge Date: Thu, 24 Aug 2017 14:37:10 +0200 Subject: Add idle_threads mount option. --- ChangeLog.rst | 7 +++++++ configure.ac | 2 +- include/fuse.h | 10 +++++++--- include/fuse_common.h | 24 +++++++++++++++++++++++- include/fuse_lowlevel.h | 11 ++++++++--- lib/Makefile.am | 2 +- lib/cuse_lowlevel.c | 8 ++++++-- lib/fuse.c | 16 ++++++++++++++-- lib/fuse_loop_mt.c | 20 +++++++++++++++++--- lib/fuse_versionscript | 6 ++++++ lib/helper.c | 16 +++++++++++++--- lib/meson.build | 2 +- meson.build | 2 +- 13 files changed, 105 insertions(+), 21 deletions(-) diff --git a/ChangeLog.rst b/ChangeLog.rst index 1ca0980..220481b 100644 --- a/ChangeLog.rst +++ b/ChangeLog.rst @@ -53,6 +53,13 @@ libfuse 3.1.1 (2017-08-06) * Fixed a test failure when /tmp is on btrfs. +* The maximum number of idle worker threads used by `fuse_loop_mt()` + is now configurable. + +* `fuse_loop_mt()` and `fuse_session_loop_mt()` now take a + `struct fuse_loop_config` parameter that supersedes the *clone_fd* + parameter. + * Incorporated several patches from the FreeBSD port. libfuse should now compile under FreeBSD without the need for patches. diff --git a/configure.ac b/configure.ac index 820b80b..67357af 100644 --- a/configure.ac +++ b/configure.ac @@ -1,4 +1,4 @@ -AC_INIT(fuse, 3.1.1) +AC_INIT(fuse, 3.2.0) AC_PREREQ(2.59d) AC_CONFIG_MACRO_DIR([m4]) AC_CANONICAL_TARGET diff --git a/include/fuse.h b/include/fuse.h index 4898029..4816617 100644 --- a/include/fuse.h +++ b/include/fuse.h @@ -964,13 +964,17 @@ void fuse_exit(struct fuse *f); * in the callback function of fuse_operations is also thread-safe. * * @param f the FUSE handle - * @param clone_fd whether to use separate device fds for each thread - * (may increase performance) + * @param config loop configuration * @return see fuse_session_loop() * * See also: fuse_loop() */ -int fuse_loop_mt(struct fuse *f, int clone_fd); +#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) +#else +int fuse_loop_mt(struct fuse *f, struct fuse_loop_config *config); +#endif /** * Get the current context diff --git a/include/fuse_common.h b/include/fuse_common.h index ecaa906..ff78cc9 100644 --- a/include/fuse_common.h +++ b/include/fuse_common.h @@ -22,7 +22,7 @@ #define FUSE_MAJOR_VERSION 3 /** Minor version of FUSE library interface */ -#define FUSE_MINOR_VERSION 1 +#define FUSE_MINOR_VERSION 2 #define FUSE_MAKE_VERSION(maj, min) ((maj) * 10 + (min)) #define FUSE_VERSION FUSE_MAKE_VERSION(FUSE_MAJOR_VERSION, FUSE_MINOR_VERSION) @@ -79,7 +79,29 @@ struct fuse_file_info { uint32_t poll_events; }; +/** + * Configuration parameters passed to fuse_session_loop_mt() and + * fuse_loop_mt(). + */ +struct fuse_loop_config { + /** + * 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. + */ + unsigned int max_idle_threads; +}; /************************************************************************** * Capability bits for 'fuse_conn_info.capable' and 'fuse_conn_info.want' * diff --git a/include/fuse_lowlevel.h b/include/fuse_lowlevel.h index ebfc626..72942ab 100644 --- a/include/fuse_lowlevel.h +++ b/include/fuse_lowlevel.h @@ -1760,6 +1760,7 @@ struct fuse_cmdline_opts { int show_version; int show_help; int clone_fd; + unsigned int max_idle_threads; }; /** @@ -1857,11 +1858,15 @@ int fuse_session_loop(struct fuse_session *se); * fuse_session_loop(). * * @param se the session - * @param clone_fd whether to use separate device fds for each thread - * (may increase performance) + * @param config session loop configuration * @return see fuse_session_loop() */ -int fuse_session_loop_mt(struct fuse_session *se, int clone_fd); +#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) +#else +int fuse_session_loop_mt(struct fuse_session *se, struct fuse_loop_config *config); +#endif /** * Flag a session as terminated. diff --git a/lib/Makefile.am b/lib/Makefile.am index 7d1dfff..c90ec48 100644 --- a/lib/Makefile.am +++ b/lib/Makefile.am @@ -1,7 +1,7 @@ ## Process this file with automake to produce Makefile.in AM_CPPFLAGS = -I$(top_srcdir)/include -DFUSERMOUNT_DIR=\"$(bindir)\" \ - -D_REENTRANT -DFUSE_USE_VERSION=31 + -D_REENTRANT -DFUSE_USE_VERSION=32 lib_LTLIBRARIES = libfuse3.la diff --git a/lib/cuse_lowlevel.c b/lib/cuse_lowlevel.c index b6aaf77..19b2ab6 100644 --- a/lib/cuse_lowlevel.c +++ b/lib/cuse_lowlevel.c @@ -349,8 +349,12 @@ int cuse_lowlevel_main(int argc, char *argv[], const struct cuse_info *ci, if (se == NULL) return 1; - if (multithreaded) - res = fuse_session_loop_mt(se, 0); + if (multithreaded) { + struct fuse_loop_config config; + config.clone_fd = 0; + config.max_idle_threads = 10; + res = fuse_session_loop_mt(se, &config); + } else res = fuse_session_loop(se); diff --git a/lib/fuse.c b/lib/fuse.c index 0f2a6d6..75ae38a 100644 --- a/lib/fuse.c +++ b/lib/fuse.c @@ -4382,7 +4382,9 @@ int fuse_loop(struct fuse *f) return fuse_session_loop(f->se); } -int fuse_loop_mt(struct fuse *f, int clone_fd) +int fuse_loop_mt_32(struct fuse *f, struct fuse_loop_config *config); +FUSE_SYMVER(".symver fuse_loop_mt_32,fuse_loop_mt@@FUSE_3.2"); +int fuse_loop_mt_32(struct fuse *f, struct fuse_loop_config *config) { if (f == NULL) return -1; @@ -4391,11 +4393,21 @@ int fuse_loop_mt(struct fuse *f, int clone_fd) if (res) return -1; - res = fuse_session_loop_mt(fuse_get_session(f), clone_fd); + res = fuse_session_loop_mt(fuse_get_session(f), config); fuse_stop_cleanup_thread(f); return res; } +int fuse_loop_mt_31(struct fuse *f, int clone_fd); +FUSE_SYMVER(".symver fuse_loop_mt_31,fuse_loop_mt@FUSE_3.1"); +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); +} + void fuse_exit(struct fuse *f) { fuse_session_exit(f->se); diff --git a/lib/fuse_loop_mt.c b/lib/fuse_loop_mt.c index 74b6c99..904539e 100644 --- a/lib/fuse_loop_mt.c +++ b/lib/fuse_loop_mt.c @@ -48,6 +48,7 @@ struct fuse_mt { int exit; int error; int clone_fd; + int max_idle; }; static struct fuse_chan *fuse_chan_new(int fd) @@ -161,7 +162,7 @@ static void *fuse_do_work(void *data) pthread_mutex_lock(&mt->lock); if (!isforget) mt->numavail++; - if (mt->numavail > 10) { + if (mt->numavail > mt->max_idle) { if (mt->exit) { pthread_mutex_unlock(&mt->lock); return NULL; @@ -300,7 +301,9 @@ static void fuse_join_worker(struct fuse_mt *mt, struct fuse_worker *w) free(w); } -int fuse_session_loop_mt(struct fuse_session *se, int clone_fd) +int fuse_session_loop_mt_32(struct fuse_session *se, struct fuse_loop_config *config); +FUSE_SYMVER(".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 err; struct fuse_mt mt; @@ -308,10 +311,11 @@ int fuse_session_loop_mt(struct fuse_session *se, int clone_fd) memset(&mt, 0, sizeof(struct fuse_mt)); mt.se = se; - mt.clone_fd = clone_fd; + mt.clone_fd = config->clone_fd; mt.error = 0; mt.numworker = 0; mt.numavail = 0; + mt.max_idle = config->max_idle_threads; mt.main.thread_id = pthread_self(); mt.main.prev = mt.main.next = &mt.main; sem_init(&mt.finish, 0, 0); @@ -344,3 +348,13 @@ int fuse_session_loop_mt(struct fuse_session *se, int clone_fd) fuse_session_reset(se); return err; } + +int fuse_session_loop_mt_31(struct fuse_session *se, int clone_fd); +FUSE_SYMVER(".symver fuse_session_loop_mt_31,fuse_session_loop_mt@FUSE_3.1"); +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); +} diff --git a/lib/fuse_versionscript b/lib/fuse_versionscript index e1eba6b..849d42f 100644 --- a/lib/fuse_versionscript +++ b/lib/fuse_versionscript @@ -139,6 +139,12 @@ FUSE_3.1 { fuse_invalidate_path; } FUSE_3.0; +FUSE_3.2 { + global: + fuse_session_loop_mt_31; + fuse_loop_mt_31; +} FUSE_3.1; + # Local Variables: # indent-tabs-mode: t # End: diff --git a/lib/helper.c b/lib/helper.c index 564a433..cb7aebc 100644 --- a/lib/helper.c +++ b/lib/helper.c @@ -48,6 +48,7 @@ static const struct fuse_opt fuse_helper_opts[] = { FUSE_OPT_KEY("subtype=", FUSE_OPT_KEY_KEEP), #endif FUSE_HELPER_OPT("clone_fd", clone_fd), + FUSE_HELPER_OPT("max_idle_threads=%u", max_idle_threads), FUSE_OPT_END }; @@ -132,7 +133,9 @@ void fuse_cmdline_help(void) " -f foreground operation\n" " -s disable multi-threaded operation\n" " -o clone_fd use separate fuse device fd for each thread\n" - " (may improve performance)\n"); + " (may improve performance)\n" + " -o max_idle_threads the maximum number of idle worker threads\n" + " allowed (default: 10)\n"); } static int fuse_helper_opt_proc(void *data, const char *arg, int key, @@ -195,6 +198,9 @@ int fuse_parse_cmdline(struct fuse_args *args, struct fuse_cmdline_opts *opts) { memset(opts, 0, sizeof(struct fuse_cmdline_opts)); + + opts->max_idle_threads = 10; + if (fuse_opt_parse(args, opts, fuse_helper_opts, fuse_helper_opt_proc) == -1) return -1; @@ -326,8 +332,12 @@ int fuse_main_real(int argc, char *argv[], const struct fuse_operations *op, if (opts.singlethread) res = fuse_loop(fuse); - else - res = fuse_loop_mt(fuse, opts.clone_fd); + 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(fuse, &loop_config); + } if (res) res = 1; diff --git a/lib/meson.build b/lib/meson.build index b07c06c..c0e96d8 100644 --- a/lib/meson.build +++ b/lib/meson.build @@ -29,7 +29,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=31', + c_args: [ '-DFUSE_USE_VERSION=32', '-DFUSERMOUNT_DIR="{}"'.format(fusermount_path) ], link_args: ['-Wl,--version-script,' + meson.current_source_dir() + '/fuse_versionscript' ]) diff --git a/meson.build b/meson.build index 8fcdbd7..3e0a726 100644 --- a/meson.build +++ b/meson.build @@ -1,4 +1,4 @@ -project('libfuse3', 'c', version: '3.1.1', +project('libfuse3', 'c', version: '3.2.0', meson_version: '>= 0.38', default_options: [ 'buildtype=debugoptimized' ]) -- cgit v1.2.3