aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorGravatar Joseph Dodge <joseph.dodge@veritas.com>2017-08-24 14:37:10 +0200
committerGravatar Nikolaus Rath <Nikolaus@rath.org>2017-08-24 15:17:01 +0200
commitf12d9686d4d673e59b8f561c49996820763220b1 (patch)
treea06f9f3941f2abe727eb06f5ff1ec70972498208
parentfc83143867a37e34a51ce5a6d763b46715abf02d (diff)
Add idle_threads mount option.
-rw-r--r--ChangeLog.rst7
-rw-r--r--configure.ac2
-rw-r--r--include/fuse.h10
-rw-r--r--include/fuse_common.h24
-rw-r--r--include/fuse_lowlevel.h11
-rw-r--r--lib/Makefile.am2
-rw-r--r--lib/cuse_lowlevel.c8
-rw-r--r--lib/fuse.c16
-rw-r--r--lib/fuse_loop_mt.c20
-rw-r--r--lib/fuse_versionscript6
-rw-r--r--lib/helper.c16
-rw-r--r--lib/meson.build2
-rw-r--r--meson.build2
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' ])