Skip to content

Commit 2b3933b

Browse files
joannekoongMiklos Szeredi
authored andcommitted
fuse: enable dynamic configuration of fuse max pages limit (FUSE_MAX_MAX_PAGES)
Introduce the capability to dynamically configure the max pages limit (FUSE_MAX_MAX_PAGES) through a sysctl. This allows system administrators to dynamically set the maximum number of pages that can be used for servicing requests in fuse. Previously, this is gated by FUSE_MAX_MAX_PAGES which is statically set to 256 pages. One result of this is that the buffer size for a write request is limited to 1 MiB on a 4k-page system. The default value for this sysctl is the original limit (256 pages). $ sysctl -a | grep max_pages_limit fs.fuse.max_pages_limit = 256 $ sysctl -n fs.fuse.max_pages_limit 256 $ echo 1024 | sudo tee /proc/sys/fs/fuse/max_pages_limit 1024 $ sysctl -n fs.fuse.max_pages_limit 1024 $ echo 65536 | sudo tee /proc/sys/fs/fuse/max_pages_limit tee: /proc/sys/fs/fuse/max_pages_limit: Invalid argument $ echo 0 | sudo tee /proc/sys/fs/fuse/max_pages_limit tee: /proc/sys/fs/fuse/max_pages_limit: Invalid argument $ echo 65535 | sudo tee /proc/sys/fs/fuse/max_pages_limit 65535 $ sysctl -n fs.fuse.max_pages_limit 65535 Signed-off-by: Joanne Koong <[email protected]> Reviewed-by: Josef Bacik <[email protected]> Reviewed-by: Sweet Tea Dorminy <[email protected]> Signed-off-by: Miklos Szeredi <[email protected]>
1 parent d34a557 commit 2b3933b

File tree

6 files changed

+75
-5
lines changed

6 files changed

+75
-5
lines changed

Documentation/admin-guide/sysctl/fs.rst

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -332,3 +332,13 @@ Each "watch" costs roughly 90 bytes on a 32-bit kernel, and roughly 160 bytes
332332
on a 64-bit one.
333333
The current default value for ``max_user_watches`` is 4% of the
334334
available low memory, divided by the "watch" cost in bytes.
335+
336+
5. /proc/sys/fs/fuse - Configuration options for FUSE filesystems
337+
=====================================================================
338+
339+
This directory contains the following configuration options for FUSE
340+
filesystems:
341+
342+
``/proc/sys/fs/fuse/max_pages_limit`` is a read/write file for
343+
setting/getting the maximum number of pages that can be used for servicing
344+
requests in FUSE.

fs/fuse/Makefile

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,5 +14,6 @@ fuse-y := dev.o dir.o file.o inode.o control.o xattr.o acl.o readdir.o ioctl.o
1414
fuse-y += iomode.o
1515
fuse-$(CONFIG_FUSE_DAX) += dax.o
1616
fuse-$(CONFIG_FUSE_PASSTHROUGH) += passthrough.o
17+
fuse-$(CONFIG_SYSCTL) += sysctl.o
1718

1819
virtiofs-y := virtio_fs.o

fs/fuse/fuse_i.h

Lines changed: 11 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -35,9 +35,6 @@
3535
/** Default max number of pages that can be used in a single read request */
3636
#define FUSE_DEFAULT_MAX_PAGES_PER_REQ 32
3737

38-
/** Maximum of max_pages received in init_out */
39-
#define FUSE_MAX_MAX_PAGES 256
40-
4138
/** Bias for fi->writectr, meaning new writepages must not be sent */
4239
#define FUSE_NOWRITE INT_MIN
4340

@@ -47,6 +44,9 @@
4744
/** Number of dentries for each connection in the control filesystem */
4845
#define FUSE_CTL_NUM_DENTRIES 5
4946

47+
/** Maximum of max_pages received in init_out */
48+
extern unsigned int fuse_max_pages_limit;
49+
5050
/** List of active connections */
5151
extern struct list_head fuse_conn_list;
5252

@@ -1480,4 +1480,12 @@ ssize_t fuse_passthrough_splice_write(struct pipe_inode_info *pipe,
14801480
size_t len, unsigned int flags);
14811481
ssize_t fuse_passthrough_mmap(struct file *file, struct vm_area_struct *vma);
14821482

1483+
#ifdef CONFIG_SYSCTL
1484+
extern int fuse_sysctl_register(void);
1485+
extern void fuse_sysctl_unregister(void);
1486+
#else
1487+
#define fuse_sysctl_register() (0)
1488+
#define fuse_sysctl_unregister() do { } while (0)
1489+
#endif /* CONFIG_SYSCTL */
1490+
14831491
#endif /* _FS_FUSE_I_H */

fs/fuse/inode.c

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,8 @@ DEFINE_MUTEX(fuse_mutex);
3535

3636
static int set_global_limit(const char *val, const struct kernel_param *kp);
3737

38+
unsigned int fuse_max_pages_limit = 256;
39+
3840
unsigned max_user_bgreq;
3941
module_param_call(max_user_bgreq, set_global_limit, param_get_uint,
4042
&max_user_bgreq, 0644);
@@ -944,7 +946,7 @@ void fuse_conn_init(struct fuse_conn *fc, struct fuse_mount *fm,
944946
fc->pid_ns = get_pid_ns(task_active_pid_ns(current));
945947
fc->user_ns = get_user_ns(user_ns);
946948
fc->max_pages = FUSE_DEFAULT_MAX_PAGES_PER_REQ;
947-
fc->max_pages_limit = FUSE_MAX_MAX_PAGES;
949+
fc->max_pages_limit = fuse_max_pages_limit;
948950

949951
if (IS_ENABLED(CONFIG_FUSE_PASSTHROUGH))
950952
fuse_backing_files_init(fc);
@@ -2063,8 +2065,14 @@ static int __init fuse_fs_init(void)
20632065
if (err)
20642066
goto out3;
20652067

2068+
err = fuse_sysctl_register();
2069+
if (err)
2070+
goto out4;
2071+
20662072
return 0;
20672073

2074+
out4:
2075+
unregister_filesystem(&fuse_fs_type);
20682076
out3:
20692077
unregister_fuseblk();
20702078
out2:
@@ -2075,6 +2083,7 @@ static int __init fuse_fs_init(void)
20752083

20762084
static void fuse_fs_cleanup(void)
20772085
{
2086+
fuse_sysctl_unregister();
20782087
unregister_filesystem(&fuse_fs_type);
20792088
unregister_fuseblk();
20802089

fs/fuse/ioctl.c

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,8 @@
1010
#include <linux/fileattr.h>
1111
#include <linux/fsverity.h>
1212

13+
#define FUSE_VERITY_ENABLE_ARG_MAX_PAGES 256
14+
1315
static ssize_t fuse_send_ioctl(struct fuse_mount *fm, struct fuse_args *args,
1416
struct fuse_ioctl_out *outarg)
1517
{
@@ -140,7 +142,7 @@ static int fuse_setup_enable_verity(unsigned long arg, struct iovec *iov,
140142
{
141143
struct fsverity_enable_arg enable;
142144
struct fsverity_enable_arg __user *uarg = (void __user *)arg;
143-
const __u32 max_buffer_len = FUSE_MAX_MAX_PAGES * PAGE_SIZE;
145+
const __u32 max_buffer_len = FUSE_VERITY_ENABLE_ARG_MAX_PAGES * PAGE_SIZE;
144146

145147
if (copy_from_user(&enable, uarg, sizeof(enable)))
146148
return -EFAULT;

fs/fuse/sysctl.c

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
// SPDX-License-Identifier: GPL-2.0
2+
/*
3+
* linux/fs/fuse/fuse_sysctl.c
4+
*
5+
* Sysctl interface to fuse parameters
6+
*/
7+
#include <linux/sysctl.h>
8+
9+
#include "fuse_i.h"
10+
11+
static struct ctl_table_header *fuse_table_header;
12+
13+
/* Bound by fuse_init_out max_pages, which is a u16 */
14+
static unsigned int sysctl_fuse_max_pages_limit = 65535;
15+
16+
static struct ctl_table fuse_sysctl_table[] = {
17+
{
18+
.procname = "max_pages_limit",
19+
.data = &fuse_max_pages_limit,
20+
.maxlen = sizeof(fuse_max_pages_limit),
21+
.mode = 0644,
22+
.proc_handler = proc_douintvec_minmax,
23+
.extra1 = SYSCTL_ONE,
24+
.extra2 = &sysctl_fuse_max_pages_limit,
25+
},
26+
};
27+
28+
int fuse_sysctl_register(void)
29+
{
30+
fuse_table_header = register_sysctl("fs/fuse", fuse_sysctl_table);
31+
if (!fuse_table_header)
32+
return -ENOMEM;
33+
return 0;
34+
}
35+
36+
void fuse_sysctl_unregister(void)
37+
{
38+
unregister_sysctl_table(fuse_table_header);
39+
fuse_table_header = NULL;
40+
}

0 commit comments

Comments
 (0)