From 40f476f40b37cc8fcc83618094d357ee643442d8 Mon Sep 17 00:00:00 2001 From: Csaba Henk Date: Wed, 3 Apr 2019 14:23:06 +0200 Subject: fuse: rate limit reading from fuse device upon receiving EPERM Fixes: bz#1644322 Change-Id: I53e8fa362cd8c7d04fb1c4abb606a9abb642c592 Signed-off-by: Csaba Henk --- glusterfsd/src/glusterfsd.c | 28 ++++++++++++++++++++++++++++ glusterfsd/src/glusterfsd.h | 3 ++- libglusterfs/src/glusterfs/glusterfs.h | 2 ++ xlators/mount/fuse/src/fuse-bridge.c | 22 ++++++++++++++++++++++ xlators/mount/fuse/src/fuse-bridge.h | 2 ++ xlators/mount/fuse/utils/mount.glusterfs.in | 7 +++++++ 6 files changed, 63 insertions(+), 1 deletion(-) diff --git a/glusterfsd/src/glusterfsd.c b/glusterfsd/src/glusterfsd.c index cf6d9a7215c..968b97c2eac 100644 --- a/glusterfsd/src/glusterfsd.c +++ b/glusterfsd/src/glusterfsd.c @@ -276,6 +276,9 @@ static struct argp_option gf_options[] = { "attribute, dentry and page-cache. " "Disable this only if same files/directories are not accessed across " "two different mounts concurrently [default: \"on\"]"}, + {"fuse-dev-eperm-ratelimit-ns", ARGP_FUSE_DEV_EPERM_RATELIMIT_NS_KEY, + "OPTIONS", OPTION_HIDDEN, + "rate limit reading from fuse device upon EPERM failure"}, {"brick-mux", ARGP_BRICK_MUX_KEY, 0, 0, "Enable brick mux. "}, {0, 0, 0, 0, "Miscellaneous Options:"}, { @@ -707,6 +710,16 @@ set_fuse_mount_options(glusterfs_ctx_t *ctx, dict_t *options) goto err; } } + if (cmd_args->fuse_dev_eperm_ratelimit_ns) { + ret = dict_set_uint32(options, "fuse-dev-eperm-ratelimit-ns", + cmd_args->fuse_dev_eperm_ratelimit_ns); + if (ret < 0) { + gf_msg("glusterfsd", GF_LOG_ERROR, 0, glusterfsd_msg_4, + "failed to set dict value for key " + "fuse-dev-eperm-ratelimit-ns"); + goto err; + } + } ret = 0; err: @@ -1536,6 +1549,21 @@ parse_opts(int key, char *arg, struct argp_state *state) argp_failure(state, -1, 0, "Invalid value for global threading \"%s\"", arg); break; + + case ARGP_FUSE_DEV_EPERM_RATELIMIT_NS_KEY: + if (gf_string2uint32(arg, &cmd_args->fuse_dev_eperm_ratelimit_ns)) { + argp_failure(state, -1, 0, + "Non-numerical value for " + "'fuse-dev-eperm-ratelimit-ns' option %s", + arg); + } else if (cmd_args->fuse_dev_eperm_ratelimit_ns > 1000000000) { + argp_failure(state, -1, 0, + "Invalid 'fuse-dev-eperm-ratelimit-ns' value %s. " + "Valid range: [\"0, 1000000000\"]", + arg); + } + + break; } return 0; } diff --git a/glusterfsd/src/glusterfsd.h b/glusterfsd/src/glusterfsd.h index dc7d995e778..8a7c034ce40 100644 --- a/glusterfsd/src/glusterfsd.h +++ b/glusterfsd/src/glusterfsd.h @@ -112,7 +112,8 @@ enum argp_option_keys { ARGP_FUSE_LRU_LIMIT_KEY = 190, ARGP_FUSE_AUTO_INVAL_KEY = 191, ARGP_GLOBAL_THREADING_KEY = 192, - ARGP_BRICK_MUX_KEY = 193 + ARGP_BRICK_MUX_KEY = 193, + ARGP_FUSE_DEV_EPERM_RATELIMIT_NS_KEY = 194, }; struct _gfd_vol_top_priv { diff --git a/libglusterfs/src/glusterfs/glusterfs.h b/libglusterfs/src/glusterfs/glusterfs.h index 967bf5b40e7..d59306508b2 100644 --- a/libglusterfs/src/glusterfs/glusterfs.h +++ b/libglusterfs/src/glusterfs/glusterfs.h @@ -573,6 +573,8 @@ struct _cmd_args { bool global_threading; bool brick_mux; + + uint32_t fuse_dev_eperm_ratelimit_ns; }; typedef struct _cmd_args cmd_args_t; diff --git a/xlators/mount/fuse/src/fuse-bridge.c b/xlators/mount/fuse/src/fuse-bridge.c index c1ce008eace..3a779625a08 100644 --- a/xlators/mount/fuse/src/fuse-bridge.c +++ b/xlators/mount/fuse/src/fuse-bridge.c @@ -5976,6 +5976,16 @@ fuse_thread_proc(void *data) "glusterfs-fuse: read from " "/dev/fuse returned -1 (%s)", strerror(errno)); + if (errno == EPERM) { + /* + * sleep a while to avoid busy looping + * on EPERM condition + */ + nanosleep( + &(struct timespec){0, + priv->fuse_dev_eperm_ratelimit_ns}, + NULL); + } } goto cont_err; @@ -6692,6 +6702,9 @@ init(xlator_t *this_xl) GF_OPTION_INIT("flush-handle-interrupt", priv->flush_handle_interrupt, bool, cleanup_exit); + GF_OPTION_INIT("fuse-dev-eperm-ratelimit-ns", + priv->fuse_dev_eperm_ratelimit_ns, uint32, cleanup_exit); + /* user has set only background-qlen, not congestion-threshold, use the fuse kernel driver formula to set congestion. ie, 75% */ if (dict_get(this_xl->options, "background-qlen") && @@ -7023,6 +7036,15 @@ struct volume_options options[] = { "if same files/directories are not accessed across " "two different mounts concurrently", }, + { + .key = {"fuse-dev-eperm-ratelimit-ns"}, + .type = GF_OPTION_TYPE_INT, + .default_value = "10000000", /* 0.01 sec */ + .min = 0, + .max = 1000000000, + .description = "Rate limit reading from fuse device upon EPERM " + "failure.", + }, {.key = {NULL}}, }; diff --git a/xlators/mount/fuse/src/fuse-bridge.h b/xlators/mount/fuse/src/fuse-bridge.h index 697bd8848e1..8d25bed0481 100644 --- a/xlators/mount/fuse/src/fuse-bridge.h +++ b/xlators/mount/fuse/src/fuse-bridge.h @@ -191,6 +191,8 @@ struct fuse_private { /* LRU Limit, if not set, default is 128k for now */ uint32_t lru_limit; + + uint32_t fuse_dev_eperm_ratelimit_ns; }; typedef struct fuse_private fuse_private_t; diff --git a/xlators/mount/fuse/utils/mount.glusterfs.in b/xlators/mount/fuse/utils/mount.glusterfs.in index 29906316266..21cc018eaa5 100755 --- a/xlators/mount/fuse/utils/mount.glusterfs.in +++ b/xlators/mount/fuse/utils/mount.glusterfs.in @@ -362,6 +362,10 @@ start_glusterfs () cmd_line=$(echo "$cmd_line --subdir-mount=/$subdir_mount"); fi + if [ -n "$fuse_dev_eperm_ratelimit_ns" ]; then + cmd_line=$(echo "$cmd_line --fuse-dev-eperm-ratelimit-ns=$fuse_dev_eperm_ratelimit_ns"); + fi + cmd_line=$(echo "$cmd_line $mount_point"); $cmd_line; if [ $? -ne 0 ]; then @@ -571,6 +575,9 @@ with_options() "fuse-flush-handle-interrupt") fuse_flush_handle_interrupt=$value ;; + "fuse-dev-eperm-ratelimit-ns") + fuse_dev_eperm_ratelimit_ns=$value + ;; "context"|"fscontext"|"defcontext"|"rootcontext") # standard SElinux mount options to pass to the kernel [ -z "$fuse_mountopts" ] || fuse_mountopts="$fuse_mountopts," -- cgit