Set default global limits for backgrounded requests and congestion threshold considering the tunable maximum request size. They are calculated using size of fuse_req structure, which is variable due to it. This patch sets them according to the current request size unless they are set via mod_param by the system administrator. Signed-off-by: Mitsuo Hayasaka <mitsuo.hayasaka.hu@xxxxxxxxxxx> Cc: Miklos Szeredi <miklos@xxxxxxxxxx> Cc: Nikolaus Rath <Nikolaus@xxxxxxxx> Cc: Liu Yuan <namei.unix@xxxxxxxxx> Cc: Has-Wen Nienhuys <hanwen@xxxxxxxxx> --- fs/fuse/fuse_i.h | 4 +++ fs/fuse/inode.c | 62 ++++++++++++++++++++++++++++++++++++++++++++---------- 2 files changed, 55 insertions(+), 11 deletions(-) diff --git a/fs/fuse/fuse_i.h b/fs/fuse/fuse_i.h index 46df615..2dda6eb 100644 --- a/fs/fuse/fuse_i.h +++ b/fs/fuse/fuse_i.h @@ -27,6 +27,10 @@ /** Default number of pages that can be used in a single read/write request */ #define FUSE_DEFAULT_MAX_PAGES_PER_REQ 32 +/** Maximum size of struct fuse_req */ +#define FUSE_CURRENT_REQ_SIZE (sizeof(struct fuse_req) +\ + sysfs_max_req_pages * sizeof(struct page *)) + /** Bias for fi->writectr, meaning new writepages must not be sent */ #define FUSE_NOWRITE INT_MIN diff --git a/fs/fuse/inode.c b/fs/fuse/inode.c index 5f84a40..dc0302f 100644 --- a/fs/fuse/inode.c +++ b/fs/fuse/inode.c @@ -29,25 +29,36 @@ static struct kmem_cache *fuse_inode_cachep; struct list_head fuse_conn_list; DEFINE_MUTEX(fuse_mutex); -static int set_global_limit(const char *val, struct kernel_param *kp); +static int set_global_limit_bgreq(const char *val, struct kernel_param *kp); +static int set_global_limit_thresh(const char *val, struct kernel_param *kp); unsigned max_user_bgreq; -module_param_call(max_user_bgreq, set_global_limit, param_get_uint, - &max_user_bgreq, 0644); +module_param_call(max_user_bgreq, set_global_limit_bgreq, + param_get_uint, &max_user_bgreq, 0644); __MODULE_PARM_TYPE(max_user_bgreq, "uint"); MODULE_PARM_DESC(max_user_bgreq, "Global limit for the maximum number of backgrounded requests an " "unprivileged user can set"); unsigned max_user_congthresh; -module_param_call(max_user_congthresh, set_global_limit, param_get_uint, - &max_user_congthresh, 0644); +module_param_call(max_user_congthresh, set_global_limit_thresh, + param_get_uint, &max_user_congthresh, 0644); __MODULE_PARM_TYPE(max_user_congthresh, "uint"); MODULE_PARM_DESC(max_user_congthresh, "Global limit for the maximum congestion threshold an " "unprivileged user can set"); /** + * The flags below are used in order to distinguish how to set + * max_user_bgreq and max_user_congthresh, respectively. They + * should be used if they are set via mod_param. If not, we should + * check their current limitation using check_global_limit() any + * time due to the tunable read/write request size. + */ +static bool mod_param_set_flg_bgreq; +static bool mod_param_set_flg_thresh; + +/** * Maximum number of pages allocated for struct fuse_req. * It can be changed via sysfs to arbitrary number between * FUSE_DEFAULT_MAX_PAGES_PER_REQ and nr_pages equivalent @@ -766,13 +777,39 @@ static void sanitize_global_limit(unsigned *limit) { if (*limit == 0) *limit = ((num_physpages << PAGE_SHIFT) >> 13) / - sizeof(struct fuse_req); + FUSE_CURRENT_REQ_SIZE; if (*limit >= 1 << 16) *limit = (1 << 16) - 1; } -static int set_global_limit(const char *val, struct kernel_param *kp) +static void check_global_limit(unsigned *limit, bool mod_param_flg) +{ + if (!mod_param_flg) { + unsigned cur_global_limit = 0; + + sanitize_global_limit(&cur_global_limit); + *limit = cur_global_limit; + } +} + +static int set_global_limit_bgreq(const char *val, struct kernel_param *kp) +{ + int rv; + + rv = param_set_uint(val, kp); + if (rv) + return rv; + + sanitize_global_limit((unsigned *)kp->arg); + + /* max_user_bgreq is set via mod_param */ + mod_param_set_flg_bgreq = true; + + return 0; +} + +static int set_global_limit_thresh(const char *val, struct kernel_param *kp) { int rv; @@ -782,6 +819,9 @@ static int set_global_limit(const char *val, struct kernel_param *kp) sanitize_global_limit((unsigned *)kp->arg); + /* max_user_congthresh is set via mod_param */ + mod_param_set_flg_thresh = true; + return 0; } @@ -801,8 +841,8 @@ static void process_init_limits(struct fuse_conn *fc, struct fuse_init_out *arg) if (arg->minor < 13) return; - sanitize_global_limit(&max_user_bgreq); - sanitize_global_limit(&max_user_congthresh); + check_global_limit(&max_user_bgreq, mod_param_set_flg_bgreq); + check_global_limit(&max_user_congthresh, mod_param_set_flg_thresh); if (arg->max_background) { fc->max_background = arg->max_background; @@ -1309,8 +1349,8 @@ static int __init fuse_init(void) if (res) goto err_sysfs_cleanup; - sanitize_global_limit(&max_user_bgreq); - sanitize_global_limit(&max_user_congthresh); + check_global_limit(&max_user_bgreq, mod_param_set_flg_bgreq); + check_global_limit(&max_user_congthresh, mod_param_set_flg_thresh); return 0; -- To unsubscribe from this list: send the line "unsubscribe linux-doc" in the body of a message to majordomo@xxxxxxxxxxxxxxx More majordomo info at http://vger.kernel.org/majordomo-info.html