Re: [PATCH v2 04/11] md/raid5: use mempool to allocate stripe_request_ctx

Li Nan <[email protected]>
Newsgroups gmane.linux.raid
Message-ID <[email protected]>

在 2026/1/3 23:45, Yu Kuai 写道:
> On the one hand, stripe_request_ctx is 72 bytes, and it's a bit huge for
> a stack variable.
> 
> On the other hand, the bitmap sectors_to_do is a fixed size, result in
> max_hw_sector_kb of raid5 array is at most 256 * 4k = 1Mb, and this will
> make full stripe IO impossible for the array that chunk_size * data_disks
> is bigger. Allocate ctx during runtime will make it possible to get rid
> of this limit.
> 
> Signed-off-by: Yu Kuai <[email protected]>
> ---
>   drivers/md/md.h       |  4 +++
>   drivers/md/raid1-10.c |  5 ----
>   drivers/md/raid5.c    | 62 ++++++++++++++++++++++++++++---------------
>   drivers/md/raid5.h    |  2 ++
>   4 files changed, 46 insertions(+), 27 deletions(-)
> 
> diff --git a/drivers/md/md.h b/drivers/md/md.h
> index 6ee18045f41c..b8c5dec12b62 100644
> --- a/drivers/md/md.h
> +++ b/drivers/md/md.h
> @@ -22,6 +22,10 @@
>   #include <trace/events/block.h>
>   
>   #define MaxSector (~(sector_t)0)
> +/*
> + * Number of guaranteed raid bios in case of extreme VM load:
> + */
> +#define	NR_RAID_BIOS 256
>   
>   enum md_submodule_type {
>   	MD_PERSONALITY = 0,
> diff --git a/drivers/md/raid1-10.c b/drivers/md/raid1-10.c
> index 521625756128..c33099925f23 100644
> --- a/drivers/md/raid1-10.c
> +++ b/drivers/md/raid1-10.c
> @@ -3,11 +3,6 @@
>   #define RESYNC_BLOCK_SIZE (64*1024)
>   #define RESYNC_PAGES ((RESYNC_BLOCK_SIZE + PAGE_SIZE-1) / PAGE_SIZE)
>   
> -/*
> - * Number of guaranteed raid bios in case of extreme VM load:
> - */
> -#define	NR_RAID_BIOS 256
> -
>   /* when we get a read error on a read-only array, we redirect to another
>    * device without failing the first device, or trying to over-write to
>    * correct the read error.  To keep track of bad blocks on a per-bio
> diff --git a/drivers/md/raid5.c b/drivers/md/raid5.c
> index 2294d00953af..86677519a4b5 100644
> --- a/drivers/md/raid5.c
> +++ b/drivers/md/raid5.c
> @@ -6084,13 +6084,13 @@ static sector_t raid5_bio_lowest_chunk_sector(struct r5conf *conf,
>   static bool raid5_make_request(struct mddev *mddev, struct bio * bi)
>   {
>   	DEFINE_WAIT_FUNC(wait, woken_wake_function);
> -	bool on_wq;
>   	struct r5conf *conf = mddev->private;
> -	sector_t logical_sector;
> -	struct stripe_request_ctx ctx = {};
>   	const int rw = bio_data_dir(bi);
> +	struct stripe_request_ctx *ctx;
> +	sector_t logical_sector;
>   	enum stripe_result res;
>   	int s, stripe_cnt;
> +	bool on_wq;
>   
>   	if (unlikely(bi->bi_opf & REQ_PREFLUSH)) {
>   		int ret = log_handle_flush_request(conf, bi);
> @@ -6102,11 +6102,6 @@ static bool raid5_make_request(struct mddev *mddev, struct bio * bi)
>   				return true;
>   		}
>   		/* ret == -EAGAIN, fallback */
> -		/*
> -		 * if r5l_handle_flush_request() didn't clear REQ_PREFLUSH,
> -		 * we need to flush journal device
> -		 */
> -		ctx.do_flush = bi->bi_opf & REQ_PREFLUSH;
>   	}
>   
>   	md_write_start(mddev, bi);
> @@ -6129,16 +6124,25 @@ static bool raid5_make_request(struct mddev *mddev, struct bio * bi)
>   	}
>   
>   	logical_sector = bi->bi_iter.bi_sector & ~((sector_t)RAID5_STRIPE_SECTORS(conf)-1);
> -	ctx.first_sector = logical_sector;
> -	ctx.last_sector = bio_end_sector(bi);
>   	bi->bi_next = NULL;
>   
> -	stripe_cnt = DIV_ROUND_UP_SECTOR_T(ctx.last_sector - logical_sector,
> +	ctx = mempool_alloc(conf->ctx_pool, GFP_NOIO);
> +	memset(ctx, 0, sizeof(*ctx));
> +	ctx->first_sector = logical_sector;
> +	ctx->last_sector = bio_end_sector(bi);
> +	/*
> +	 * if r5l_handle_flush_request() didn't clear REQ_PREFLUSH,
> +	 * we need to flush journal device
> +	 */
> +	if (unlikely(bi->bi_opf & REQ_PREFLUSH))
> +		ctx->do_flush = true;
> +
> +	stripe_cnt = DIV_ROUND_UP_SECTOR_T(ctx->last_sector - logical_sector,
>   					   RAID5_STRIPE_SECTORS(conf));
> -	bitmap_set(ctx.sectors_to_do, 0, stripe_cnt);
> +	bitmap_set(ctx->sectors_to_do, 0, stripe_cnt);
>   
>   	pr_debug("raid456: %s, logical %llu to %llu\n", __func__,
> -		 bi->bi_iter.bi_sector, ctx.last_sector);
> +		 bi->bi_iter.bi_sector, ctx->last_sector);
>   
>   	/* Bail out if conflicts with reshape and REQ_NOWAIT is set */
>   	if ((bi->bi_opf & REQ_NOWAIT) &&
> @@ -6146,6 +6150,7 @@ static bool raid5_make_request(struct mddev *mddev, struct bio * bi)
>   		bio_wouldblock_error(bi);
>   		if (rw == WRITE)
>   			md_write_end(mddev);
> +		mempool_free(ctx, conf->ctx_pool);
>   		return true;
>   	}
>   	md_account_bio(mddev, &bi);
> @@ -6164,10 +6169,10 @@ static bool raid5_make_request(struct mddev *mddev, struct bio * bi)
>   		add_wait_queue(&conf->wait_for_reshape, &wait);
>   		on_wq = true;
>   	}
> -	s = (logical_sector - ctx.first_sector) >> RAID5_STRIPE_SHIFT(conf);
> +	s = (logical_sector - ctx->first_sector) >> RAID5_STRIPE_SHIFT(conf);
>   
>   	while (1) {
> -		res = make_stripe_request(mddev, conf, &ctx, logical_sector,
> +		res = make_stripe_request(mddev, conf, ctx, logical_sector,
>   					  bi);
>   		if (res == STRIPE_FAIL || res == STRIPE_WAIT_RESHAPE)
>   			break;
> @@ -6184,9 +6189,9 @@ static bool raid5_make_request(struct mddev *mddev, struct bio * bi)
>   			 * raid5_activate_delayed() from making progress
>   			 * and thus deadlocking.
>   			 */
> -			if (ctx.batch_last) {
> -				raid5_release_stripe(ctx.batch_last);
> -				ctx.batch_last = NULL;
> +			if (ctx->batch_last) {
> +				raid5_release_stripe(ctx->batch_last);
> +				ctx->batch_last = NULL;
>   			}
>   
>   			wait_woken(&wait, TASK_UNINTERRUPTIBLE,
> @@ -6194,21 +6199,23 @@ static bool raid5_make_request(struct mddev *mddev, struct bio * bi)
>   			continue;
>   		}
>   
> -		s = find_next_bit_wrap(ctx.sectors_to_do, stripe_cnt, s);
> +		s = find_next_bit_wrap(ctx->sectors_to_do, stripe_cnt, s);
>   		if (s == stripe_cnt)
>   			break;
>   
> -		logical_sector = ctx.first_sector +
> +		logical_sector = ctx->first_sector +
>   			(s << RAID5_STRIPE_SHIFT(conf));
>   	}
>   	if (unlikely(on_wq))
>   		remove_wait_queue(&conf->wait_for_reshape, &wait);
>   
> -	if (ctx.batch_last)
> -		raid5_release_stripe(ctx.batch_last);
> +	if (ctx->batch_last)
> +		raid5_release_stripe(ctx->batch_last);
>   
>   	if (rw == WRITE)
>   		md_write_end(mddev);
> +
> +	mempool_free(ctx, conf->ctx_pool);
>   	if (res == STRIPE_WAIT_RESHAPE) {
>   		md_free_cloned_bio(bi);
>   		return false;
> @@ -7376,6 +7383,10 @@ static void free_conf(struct r5conf *conf)
>   	bioset_exit(&conf->bio_split);
>   	kfree(conf->stripe_hashtbl);
>   	kfree(conf->pending_data);
> +
> +	if (conf->ctx_pool)
> +		mempool_destroy(conf->ctx_pool);
> +
>   	kfree(conf);
>   }
>   
> @@ -8059,6 +8070,13 @@ static int raid5_run(struct mddev *mddev)
>   			goto abort;
>   	}
>   
> +	conf->ctx_pool = mempool_create_kmalloc_pool(NR_RAID_BIOS,
> +					sizeof(struct stripe_request_ctx));
> +	if (!conf->ctx_pool) {
> +		ret = -ENOMEM;
> +		goto abort;
> +	}
> +
>   	if (log_init(conf, journal_dev, raid5_has_ppl(conf)))
>   		goto abort;
>   
> diff --git a/drivers/md/raid5.h b/drivers/md/raid5.h
> index eafc6e9ed6ee..6e3f07119fa4 100644
> --- a/drivers/md/raid5.h
> +++ b/drivers/md/raid5.h
> @@ -690,6 +690,8 @@ struct r5conf {
>   	struct list_head	pending_list;
>   	int			pending_data_cnt;
>   	struct r5pending_data	*next_pending_data;
> +
> +	mempool_t		*ctx_pool;
>   };
>   
>   #if PAGE_SIZE == DEFAULT_STRIPE_SIZE

LGTM

Reviewed-by: Li Nan <[email protected]>

-- 
Thanks,
Nan
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.