[PATCH 18/19] fuse4fs: disable fs reclaim and write throttling

Darrick J. Wong
2026-04-29T14:57:19Z

Ask the kernel if we can disable fs reclaim and write throttling.

Disabling fs reclaim prevents livelocks where the fuse server can
allocate memory, fault into the kernel, and then the allocation tries to
initiate writeback by calling back into the same fuse server.

Disabling BDI write throttling means that writeback won't be throttled
by metadata writes to the filesystem.

Signed-off-by: "Darrick J. Wong" <djwong@kernel.org>
---
fuse4fs/fuse4fs.c | 36 ++++++++++++++++++++++++++++++++++--
1 file changed, 34 insertions(+), 2 deletions(-)

diff --git a/fuse4fs/fuse4fs.c b/fuse4fs/fuse4fs.c
index 49708bdf7b655d..6ea2d30772ae5a 100644
--- a/fuse4fs/fuse4fs.c
+++ b/fuse4fs/fuse4fs.c
@@ -7969,6 +7969,19 @@ static void try_set_io_flusher(struct fuse4fs *ff)
#endif
}

+/* Undo try_set_io_flusher */
+static void try_clear_io_flusher(struct fuse4fs *ff)
+{
+#ifdef HAVE_PR_SET_IO_FLUSHER
+ /*
+ * zero ret means it's already set, negative means we can't even
+ * look at the value so don't bother clearing it
+ */
+ if (prctl(PR_GET_IO_FLUSHER, 0, 0, 0, 0) > 0)
+ prctl(PR_SET_IO_FLUSHER, 0, 0, 0, 0);
+#endif
+}
+
/* Try to adjust the OOM score so that we don't get killed */
static void try_adjust_oom_score(struct fuse4fs *ff)
{
@@ -8022,6 +8035,23 @@ static int fuse4fs_event_loop(struct fuse4fs *ff,
struct fuse_loop_config *loop_config,
const struct fuse_cmdline_opts *opts)
{
+ bool clear_io_flusher = false;
+ int ret;
+
+ /*
+ * Try to set ourselves up with fs reclaim disabled to prevent
+ * recursive reclaim and throttling. This must be done before starting
+ * the worker threads so that they inherit the process flags.
+ */
+ ret = fuse_lowlevel_disable_fsreclaim(ff->fuse, 1);
+ if (ret) {
+ err_printf(ff, "%s: %s.\n",
+ _("Could not register as FS flusher thread"),
+ strerror(-ret));
+ try_set_io_flusher(ff);
+ clear_io_flusher = true;
+ }
+
/*
* Since there's a Big Kernel Lock around all the libext2fs code, we
* only need to start four threads -- one to decode a request, another
@@ -8032,7 +8062,10 @@ static int fuse4fs_event_loop(struct fuse4fs *ff,
fuse_loop_cfg_set_idle_threads(loop_config, opts->max_idle_threads);
fuse_loop_cfg_set_max_threads(loop_config, 4);

- return fuse_session_loop_mt(ff->fuse, loop_config) == 0 ? 0 : 8;
+ ret = fuse_session_loop_mt(ff->fuse, loop_config) == 0 ? 0 : 8;
+ if (clear_io_flusher)
+ try_clear_io_flusher(ff);
+ return ret;
}

#ifdef HAVE_FUSE4FS_SERVICE
@@ -8251,7 +8284,6 @@ int main(int argc, char *argv[])
}
}

- try_set_io_flusher(&fctx);
try_adjust_oom_score(&fctx);

/* Will we allow users to allocate every last block? */