Commit 9b17cb59 authored by Joanne Koong's avatar Joanne Koong Committed by Miklos Szeredi
Browse files

fuse: add default_request_timeout and max_request_timeout sysctls



Introduce two new sysctls, "default_request_timeout" and
"max_request_timeout". These control how long (in seconds) a server can
take to reply to a request. If the server does not reply by the timeout,
then the connection will be aborted. The upper bound on these sysctl
values is 65535.

"default_request_timeout" sets the default timeout if no timeout is
specified by the fuse server on mount. 0 (default) indicates no default
timeout should be enforced. If the server did specify a timeout, then
default_request_timeout will be ignored.

"max_request_timeout" sets the max amount of time the server may take to
reply to a request. 0 (default) indicates no maximum timeout. If
max_request_timeout is set and the fuse server attempts to set a
timeout greater than max_request_timeout, the system will use
max_request_timeout as the timeout. Similarly, if default_request_timeout
is greater than max_request_timeout, the system will use
max_request_timeout as the timeout. If the server does not request a
timeout and default_request_timeout is set to 0 but max_request_timeout
is set, then the timeout will be max_request_timeout.

Please note that these timeouts are not 100% precise. The request may
take roughly an extra FUSE_TIMEOUT_TIMER_FREQ seconds beyond the set max
timeout due to how it's internally implemented.

$ sysctl -a | grep fuse.default_request_timeout
fs.fuse.default_request_timeout = 0

$ echo 65536 | sudo tee /proc/sys/fs/fuse/default_request_timeout
tee: /proc/sys/fs/fuse/default_request_timeout: Invalid argument

$ echo 65535 | sudo tee /proc/sys/fs/fuse/default_request_timeout
65535

$ sysctl -a | grep fuse.default_request_timeout
fs.fuse.default_request_timeout = 65535

$ echo 0 | sudo tee /proc/sys/fs/fuse/default_request_timeout
0

$ sysctl -a | grep fuse.default_request_timeout
fs.fuse.default_request_timeout = 0

[Luis Henriques: Limit the timeout to the range [FUSE_TIMEOUT_TIMER_FREQ,
fuse_max_req_timeout]]

Signed-off-by: default avatarJoanne Koong <joannelkoong@gmail.com>
Reviewed-by: default avatarBernd Schubert <bschubert@ddn.com>
Reviewed-by: default avatarJosef Bacik <josef@toxicpanda.com>
Reviewed-by: default avatarSergey Senozhatsky <senozhatsky@chromium.org>
Reviewed-by: default avatarLuis Henriques <luis@igalia.com>
Reviewed-by: default avatarJeff Layton <jlayton@kernel.org>
Signed-off-by: default avatarMiklos Szeredi <mszeredi@redhat.com>
parent 0f6439f6
Loading
Loading
Loading
Loading
+25 −0
Original line number Diff line number Diff line
@@ -347,3 +347,28 @@ filesystems:
``/proc/sys/fs/fuse/max_pages_limit`` is a read/write file for
setting/getting the maximum number of pages that can be used for servicing
requests in FUSE.

``/proc/sys/fs/fuse/default_request_timeout`` is a read/write file for
setting/getting the default timeout (in seconds) for a fuse server to
reply to a kernel-issued request in the event where the server did not
specify a timeout at mount. If the server set a timeout,
then default_request_timeout will be ignored.  The default
"default_request_timeout" is set to 0. 0 indicates no default timeout.
The maximum value that can be set is 65535.

``/proc/sys/fs/fuse/max_request_timeout`` is a read/write file for
setting/getting the maximum timeout (in seconds) for a fuse server to
reply to a kernel-issued request. A value greater than 0 automatically opts
the server into a timeout that will be set to at most "max_request_timeout",
even if the server did not specify a timeout and default_request_timeout is
set to 0. If max_request_timeout is greater than 0 and the server set a timeout
greater than max_request_timeout or default_request_timeout is set to a value
greater than max_request_timeout, the system will use max_request_timeout as the
timeout. 0 indicates no max request timeout. The maximum value that can be set
is 65535.

For timeouts, if the server does not respond to the request by the time
the set timeout elapses, then the connection to the fuse server will be aborted.
Please note that the timeouts are not 100% precise (eg you may set 60 seconds but
the timeout may kick in after 70 seconds). The upper margin of error for the
timeout is roughly FUSE_TIMEOUT_TIMER_FREQ seconds.
+0 −3
Original line number Diff line number Diff line
@@ -32,9 +32,6 @@ MODULE_ALIAS("devname:fuse");

static struct kmem_cache *fuse_req_cachep;

/* Frequency (in seconds) of request timeout checks, if opted into */
#define FUSE_TIMEOUT_TIMER_FREQ 15

const unsigned long fuse_timeout_timer_freq =
	secs_to_jiffies(FUSE_TIMEOUT_TIMER_FREQ);

+13 −0
Original line number Diff line number Diff line
@@ -44,11 +44,24 @@
/** Number of dentries for each connection in the control filesystem */
#define FUSE_CTL_NUM_DENTRIES 5

/* Frequency (in seconds) of request timeout checks, if opted into */
#define FUSE_TIMEOUT_TIMER_FREQ 15

/** Frequency (in jiffies) of request timeout checks, if opted into */
extern const unsigned long fuse_timeout_timer_freq;

/** Maximum of max_pages received in init_out */
extern unsigned int fuse_max_pages_limit;
/*
 * Default timeout (in seconds) for the server to reply to a request
 * before the connection is aborted, if no timeout was specified on mount.
 */
extern unsigned int fuse_default_req_timeout;
/*
 * Max timeout (in seconds) for the server to reply to a request before
 * the connection is aborted.
 */
extern unsigned int fuse_max_req_timeout;

/** List of active connections */
extern struct list_head fuse_conn_list;
+28 −2
Original line number Diff line number Diff line
@@ -37,6 +37,9 @@ DEFINE_MUTEX(fuse_mutex);
static int set_global_limit(const char *val, const struct kernel_param *kp);

unsigned int fuse_max_pages_limit = 256;
/* default is no timeout */
unsigned int fuse_default_req_timeout;
unsigned int fuse_max_req_timeout;

unsigned max_user_bgreq;
module_param_call(max_user_bgreq, set_global_limit, param_get_uint,
@@ -1268,6 +1271,26 @@ static void set_request_timeout(struct fuse_conn *fc, unsigned int timeout)
			   fuse_timeout_timer_freq);
}

static void init_server_timeout(struct fuse_conn *fc, unsigned int timeout)
{
	if (!timeout && !fuse_max_req_timeout && !fuse_default_req_timeout)
		return;

	if (!timeout)
		timeout = fuse_default_req_timeout;

	if (fuse_max_req_timeout) {
		if (timeout)
			timeout = min(fuse_max_req_timeout, timeout);
		else
			timeout = fuse_max_req_timeout;
	}

	timeout = max(FUSE_TIMEOUT_TIMER_FREQ, timeout);

	set_request_timeout(fc, timeout);
}

struct fuse_init_args {
	struct fuse_args args;
	struct fuse_init_in in;
@@ -1286,6 +1309,7 @@ static void process_init_reply(struct fuse_mount *fm, struct fuse_args *args,
		ok = false;
	else {
		unsigned long ra_pages;
		unsigned int timeout = 0;

		process_init_limits(fc, arg);

@@ -1404,14 +1428,16 @@ static void process_init_reply(struct fuse_mount *fm, struct fuse_args *args,
			if (flags & FUSE_OVER_IO_URING && fuse_uring_enabled())
				fc->io_uring = 1;

			if ((flags & FUSE_REQUEST_TIMEOUT) && arg->request_timeout)
				set_request_timeout(fc, arg->request_timeout);
			if (flags & FUSE_REQUEST_TIMEOUT)
				timeout = arg->request_timeout;
		} else {
			ra_pages = fc->max_read / PAGE_SIZE;
			fc->no_lock = 1;
			fc->no_flock = 1;
		}

		init_server_timeout(fc, timeout);

		fm->sb->s_bdi->ra_pages =
				min(fm->sb->s_bdi->ra_pages, ra_pages);
		fc->minor = arg->minor;
+24 −0
Original line number Diff line number Diff line
@@ -13,6 +13,12 @@ static struct ctl_table_header *fuse_table_header;
/* Bound by fuse_init_out max_pages, which is a u16 */
static unsigned int sysctl_fuse_max_pages_limit = 65535;

/*
 * fuse_init_out request timeouts are u16.
 * This goes up to ~18 hours, which is plenty for a timeout.
 */
static unsigned int sysctl_fuse_req_timeout_limit = 65535;

static const struct ctl_table fuse_sysctl_table[] = {
	{
		.procname	= "max_pages_limit",
@@ -23,6 +29,24 @@ static const struct ctl_table fuse_sysctl_table[] = {
		.extra1		= SYSCTL_ONE,
		.extra2		= &sysctl_fuse_max_pages_limit,
	},
	{
		.procname	= "default_request_timeout",
		.data		= &fuse_default_req_timeout,
		.maxlen		= sizeof(fuse_default_req_timeout),
		.mode		= 0644,
		.proc_handler	= proc_douintvec_minmax,
		.extra1		= SYSCTL_ZERO,
		.extra2		= &sysctl_fuse_req_timeout_limit,
	},
	{
		.procname	= "max_request_timeout",
		.data		= &fuse_max_req_timeout,
		.maxlen		= sizeof(fuse_max_req_timeout),
		.mode		= 0644,
		.proc_handler	= proc_douintvec_minmax,
		.extra1		= SYSCTL_ZERO,
		.extra2		= &sysctl_fuse_req_timeout_limit,
	},
};

int fuse_sysctl_register(void)