Hi Joanne, On Wed, Jan 22 2025, Joanne Koong wrote: > 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 > > Signed-off-by: Joanne Koong <joannelkoong@xxxxxxxxx> > Reviewed-by: Bernd Schubert <bschubert@xxxxxxx> > Reviewed-by: Josef Bacik <josef@xxxxxxxxxxxxxx> > Reviewed-by: Sergey Senozhatsky <senozhatsky@xxxxxxxxxxxx> > --- > Documentation/admin-guide/sysctl/fs.rst | 25 ++++++++++++++++++++++ > fs/fuse/fuse_i.h | 10 +++++++++ > fs/fuse/inode.c | 28 +++++++++++++++++++++++-- > fs/fuse/sysctl.c | 24 +++++++++++++++++++++ > 4 files changed, 85 insertions(+), 2 deletions(-) > > diff --git a/Documentation/admin-guide/sysctl/fs.rst b/Documentation/admin-guide/sysctl/fs.rst > index f5ec6c9312e1..35aeb30bed8b 100644 > --- a/Documentation/admin-guide/sysctl/fs.rst > +++ b/Documentation/admin-guide/sysctl/fs.rst > @@ -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. > diff --git a/fs/fuse/fuse_i.h b/fs/fuse/fuse_i.h > index 1321cc4ed2ab..e5114831798f 100644 > --- a/fs/fuse/fuse_i.h > +++ b/fs/fuse/fuse_i.h > @@ -49,6 +49,16 @@ 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; > diff --git a/fs/fuse/inode.c b/fs/fuse/inode.c > index 79ebeb60015c..4e36d99fae52 100644 > --- a/fs/fuse/inode.c > +++ b/fs/fuse/inode.c > @@ -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 = 0; > +unsigned int fuse_max_req_timeout = 0; > > unsigned max_user_bgreq; > module_param_call(max_user_bgreq, set_global_limit, param_get_uint, > @@ -1268,6 +1271,24 @@ 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); Sorry for this late comment (this is v12 already!), but I wonder if it would be worth to use clamp() instead of min(). Limiting this value to the range [FUSE_TIMEOUT_TIMER_FREQ, fuxe_max_req_timeout] would prevent accidentally setting the timeout to a very low value. There are also some white-spaces/tabs issues with the other patch, which are worth fixing before merging. Other than that, feel free to add my Reviewed-by: Luis Henriques <luis@xxxxxxxxxx> Cheers, -- Luís > + else > + timeout = fuse_max_req_timeout; > + } > + > + set_request_timeout(fc, timeout); > +} > + > struct fuse_init_args { > struct fuse_args args; > struct fuse_init_in in; > @@ -1286,6 +1307,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 +1426,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; > diff --git a/fs/fuse/sysctl.c b/fs/fuse/sysctl.c > index b272bb333005..3d542ef9d889 100644 > --- a/fs/fuse/sysctl.c > +++ b/fs/fuse/sysctl.c > @@ -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 struct ctl_table fuse_sysctl_table[] = { > { > .procname = "max_pages_limit", > @@ -23,6 +29,24 @@ static 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) > -- > 2.43.5 >