Re: [PATCH 4/6] md/raid5: make the stripe batch size a module parameter

"yu kuai" <[email protected]> Fri, 31 Jul 2026 05:12:14 +0800
Newsgroups org.kernel.vger.linux-raid,org.kernel.vger.linux-kernel
Message-ID <[email protected]>
Hi,

在 2026/7/10 21:23, Hiroshi Nishida 写道:
> handle_active_stripes() dequeues up to MAX_STRIPE_BATCH (8) stripes from a
> worker group under a single device_lock acquisition, and
> raid5_wakeup_stripe_thread() divides group->stripes_cnt by the same value
> to decide how many additional workers to wake.  The two uses must move
> together: the dequeue cap bounds how many stripes one worker drains, while
> the spawn divisor sizes the worker fan-out to match.
>
> Make the batch size a per-array value chosen by a new max_stripe_batch
> module parameter (1-32, default 8, so behaviour is unchanged out of the
> box).  Both the dequeue cap and the spawn divisor read the single
> conf->max_stripe_batch, so they cannot drift apart.  The on-stack batch[]
> array in handle_active_stripes() is sized to the STRIPE_BATCH_MAX (32)
> upper bound; only conf->max_stripe_batch entries are ever used.
>
> The value is resolved when an array is created.  On busy multi-threaded
> arrays a larger batch amortises the device_lock over more stripes at some
> latency cost; unlike the hash-lock count and the cache-size limit there is
> no general hardware signal for the best batch size, so the default is left
> at the historical 8 and the value is simply exposed for tuning.
>
> Signed-off-by: Hiroshi Nishida <[email protected]>
> ---
>   drivers/md/raid5.c | 15 ++++++++++++---
>   drivers/md/raid5.h | 12 +++++++++++-
>   2 files changed, 23 insertions(+), 4 deletions(-)
>
> diff --git a/drivers/md/raid5.c b/drivers/md/raid5.c
> index e41d3fc92dd0..5f0825c5effe 100644
> --- a/drivers/md/raid5.c
> +++ b/drivers/md/raid5.c
> @@ -78,6 +78,11 @@ module_param(stripe_cache_size_max, uint, 0644);
>   MODULE_PARM_DESC(stripe_cache_size_max,
>   		 "Maximum the per-array stripe_cache_size may be raised to.  0 (the default) derives the limit from system memory (never below the historical 32768), so large-memory hosts can grow the stripe cache without a recompile while small ones are not offered a limit above what RAM can back.  A non-zero value sets a fixed limit");
>   
> +static unsigned int max_stripe_batch = STRIPE_BATCH_DEFAULT;
> +module_param(max_stripe_batch, uint, 0644);
> +MODULE_PARM_DESC(max_stripe_batch,
> +		 "Number of stripes a worker thread handles per device_lock acquisition, 1-32 (default 8).  Larger values amortise the lock over more stripes on busy multi-threaded arrays at some latency cost.  Read when an array is created");
> +
>   static bool devices_handle_discard_safely = false;
>   module_param(devices_handle_discard_safely, bool, 0644);
>   MODULE_PARM_DESC(devices_handle_discard_safely,
> @@ -221,7 +226,7 @@ static void raid5_wakeup_stripe_thread(struct stripe_head *sh)
>   	/* at least one worker should run to avoid race */
>   	queue_work_on(sh->cpu, raid5_wq, &group->workers[0].work);
>   
> -	thread_cnt = group->stripes_cnt / MAX_STRIPE_BATCH - 1;
> +	thread_cnt = group->stripes_cnt / conf->max_stripe_batch - 1;
>   	/* wakeup more workers */
>   	for (i = 1; i < conf->worker_cnt_per_group && thread_cnt > 0; i++) {
>   		if (group->workers[i].working == false) {
> @@ -6734,11 +6739,11 @@ static int handle_active_stripes(struct r5conf *conf, int group,
>   				 struct list_head *temp_inactive_list)
>   		__must_hold(&conf->device_lock)
>   {
> -	struct stripe_head *batch[MAX_STRIPE_BATCH], *sh;
> +	struct stripe_head *batch[STRIPE_BATCH_MAX], *sh;
>   	int i, batch_size = 0, hash;
>   	bool release_inactive = false;
>   
> -	while (batch_size < MAX_STRIPE_BATCH &&
> +	while (batch_size < conf->max_stripe_batch &&
>   			(sh = __get_priority_stripe(conf, group)) != NULL)
>   		batch[batch_size++] = sh;
>   
> @@ -7640,6 +7645,10 @@ static struct r5conf *setup_conf(struct mddev *mddev)
>   	    !conf->temp_inactive_list)
>   		goto abort;
>   
> +	/* Resolve the stripe batch size (see STRIPE_BATCH_* in raid5.h). */
> +	conf->max_stripe_batch = clamp_t(int, max_stripe_batch,
> +					 1, STRIPE_BATCH_MAX);
> +
>   #if PAGE_SIZE != DEFAULT_STRIPE_SIZE
>   	conf->stripe_size = DEFAULT_STRIPE_SIZE;
>   	conf->stripe_shift = ilog2(DEFAULT_STRIPE_SIZE) - 9;
> diff --git a/drivers/md/raid5.h b/drivers/md/raid5.h
> index 10c45fa22955..69a41c1310af 100644
> --- a/drivers/md/raid5.h
> +++ b/drivers/md/raid5.h
> @@ -490,7 +490,16 @@ struct disk_info {
>   #define BYPASS_THRESHOLD	1
>   #define NR_HASH			(PAGE_SIZE / sizeof(struct hlist_head))
>   #define HASH_MASK		(NR_HASH - 1)
> -#define MAX_STRIPE_BATCH	8
> +/*
> + * Stripe batch size: how many stripes a worker dequeues from its group per
> + * device_lock acquisition in handle_active_stripes(); the same value divides
> + * group->stripes_cnt in raid5_wakeup_stripe_thread() to choose how many extra
> + * workers to spawn, so the two stay coupled.  Selected per array by the
> + * max_stripe_batch module parameter: STRIPE_BATCH_DEFAULT is the historical
> + * value and STRIPE_BATCH_MAX bounds the on-stack batch[] array.
> + */
> +#define STRIPE_BATCH_DEFAULT	8
> +#define STRIPE_BATCH_MAX	32
>   
>   /*
>    * The stripe cache hash is striped across a power-of-two number of spinlocks,
> @@ -690,6 +699,7 @@ struct r5conf {
>   	struct r5worker_group	*worker_groups;
>   	int			group_cnt;
>   	int			worker_cnt_per_group;
> +	int			max_stripe_batch; /* stripes/dequeue, 1..STRIPE_BATCH_MAX */

This is still weird to use a global module parameter for per-array setting. Please consider
a new per-array sysfs API as well, and pass in while creating or assembling the array.

>   	struct r5l_log		*log;
>   	void			*log_private;
>   

-- 
Thanks,
Kuai