mirror of
https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
synced 2026-08-31 09:20:13 -04:00
md: add helper to split bios at reshape offset
Add mddev_bio_split_at_reshape_offset() so personalities can share reshape-offset bio splitting instead of open-coding the same boundary handling in multiple places. The helper first applies the optional max_sectors limit. If reshape is running and the bio crosses reshape_position, it further limits the front bio to the current reshape boundary so callers can account and submit one side of the reshape at a time. Snapshot reshape_position with READ_ONCE(). RAID5 and RAID10 update this field as reshape progresses, while the I/O path only needs one consistent decision point for the current bio. Using an explicit single load avoids a plain lockless access and prevents the compiler from refetching a different boundary while deciding whether and where to split. When a split is needed, bio_submit_split_bioset() submits the remainder and returns the front bio. Callers must therefore continue processing the returned bio, not the original pointer. Tested-by: Mykola Marzhan <mykola@meshstor.io> Link: https://patch.msgid.link/20260802195038.164272-12-yukuai@kernel.org Signed-off-by: Yu Kuai <yukuai@fygo.io>
This commit is contained in:
@@ -9388,6 +9388,45 @@ void md_submit_discard_bio(struct mddev *mddev, struct md_rdev *rdev,
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(md_submit_discard_bio);
|
||||
|
||||
struct bio *mddev_bio_split_at_reshape_offset(struct mddev *mddev,
|
||||
struct bio *bio,
|
||||
unsigned int *max_sectors,
|
||||
struct bio_set *bs)
|
||||
{
|
||||
sector_t boundary;
|
||||
sector_t start;
|
||||
sector_t end;
|
||||
unsigned int split_sectors;
|
||||
|
||||
split_sectors = bio_sectors(bio);
|
||||
if (max_sectors && *max_sectors && *max_sectors < split_sectors)
|
||||
split_sectors = *max_sectors;
|
||||
|
||||
if (!test_bit(MD_RECOVERY_RESHAPE, &mddev->recovery))
|
||||
goto split;
|
||||
|
||||
boundary = READ_ONCE(mddev->reshape_position);
|
||||
start = bio->bi_iter.bi_sector;
|
||||
end = bio_end_sector(bio);
|
||||
if (start >= boundary || end <= boundary)
|
||||
goto split;
|
||||
|
||||
if (boundary - start < split_sectors)
|
||||
split_sectors = boundary - start;
|
||||
|
||||
split:
|
||||
if (max_sectors)
|
||||
*max_sectors = split_sectors;
|
||||
if (split_sectors < bio_sectors(bio)) {
|
||||
bio = bio_submit_split_bioset(bio, split_sectors, bs);
|
||||
if (bio)
|
||||
bio->bi_opf |= REQ_NOMERGE;
|
||||
}
|
||||
|
||||
return bio;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(mddev_bio_split_at_reshape_offset);
|
||||
|
||||
static void md_bitmap_start(struct mddev *mddev,
|
||||
struct md_io_clone *md_io_clone)
|
||||
{
|
||||
|
||||
@@ -920,6 +920,10 @@ extern void md_error(struct mddev *mddev, struct md_rdev *rdev);
|
||||
extern void md_finish_reshape(struct mddev *mddev);
|
||||
void md_submit_discard_bio(struct mddev *mddev, struct md_rdev *rdev,
|
||||
struct bio *bio, sector_t start, sector_t size);
|
||||
struct bio *mddev_bio_split_at_reshape_offset(struct mddev *mddev,
|
||||
struct bio *bio,
|
||||
unsigned int *max_sectors,
|
||||
struct bio_set *bs);
|
||||
void md_account_bio(struct mddev *mddev, struct bio **bio);
|
||||
|
||||
extern bool __must_check md_flush_request(struct mddev *mddev, struct bio *bio);
|
||||
|
||||
Reference in New Issue
Block a user