commit 0d74ac66ed0ec5af70296545e26044723a14657c Author: Xiao Ni Date: Thu Dec 24 17:58:43 2020 +0800 fix diff --git a/drivers/md/raid10.c b/drivers/md/raid10.c index 3153183b7772..92182cf40d22 100644 --- a/drivers/md/raid10.c +++ b/drivers/md/raid10.c @@ -1604,6 +1604,7 @@ static int raid10_handle_discard(struct mddev *mddev, struct bio *bio) sector_t chunk; unsigned int stripe_size; sector_t split_size; + sector_t chunk_size = 1 << geo->chunk_shift; sector_t bio_start, bio_end; sector_t first_stripe_index, last_stripe_index; @@ -1624,7 +1625,8 @@ static int raid10_handle_discard(struct mddev *mddev, struct bio *bio) if (test_bit(MD_RECOVERY_RESHAPE, &mddev->recovery)) goto out; - stripe_size = geo->raid_disks << geo->chunk_shift; + stripe_size = geo->near_copies ? geo->near_copies << geo->chunk_shift: + geo->raid_disks << geo->chunk_shift; bio_start = bio->bi_iter.bi_sector; bio_end = bio_end_sector(bio); @@ -1637,6 +1639,18 @@ static int raid10_handle_discard(struct mddev *mddev, struct bio *bio) if (bio_sectors(bio) < stripe_size*2) goto out; + /* Keep the discard start/end address aligned with chunk size */ + if (bio_start & geo->chunk_mask) { + split_size = (chunk_size - (bio_start & geo->chunk_mask)); + bio = raid10_split_bio(conf, bio, split_size, false); + } + if (bio_end & geo->chunk_mask) { + split_size = bio_end & geo->chunk_mask; + bio = raid10_split_bio(conf, bio, split_size, true); + } + bio_start = bio->bi_iter.bi_sector; + bio_end = bio_end_sector(bio); + /* For far and far offset layout, if bio is not aligned with stripe size, * it splits the part that is not aligned with strip size. */ @@ -1664,8 +1678,8 @@ static int raid10_handle_discard(struct mddev *mddev, struct bio *bio) start_disk_index = sector_div(first_stripe_index, geo->raid_disks); if (geo->far_offset) first_stripe_index *= geo->far_copies; - start_disk_offset = (bio_start & geo->chunk_mask) + - (first_stripe_index << geo->chunk_shift); + /* Now the bio is aligned with chunk size */ + start_disk_offset = first_stripe_index << geo->chunk_shift; chunk = bio_end >> geo->chunk_shift; chunk *= geo->near_copies; @@ -1673,8 +1687,7 @@ static int raid10_handle_discard(struct mddev *mddev, struct bio *bio) end_disk_index = sector_div(last_stripe_index, geo->raid_disks); if (geo->far_offset) last_stripe_index *= geo->far_copies; - end_disk_offset = (bio_end & geo->chunk_mask) + - (last_stripe_index << geo->chunk_shift); + end_disk_offset = last_stripe_index << geo->chunk_shift; retry_discard: r10_bio = mempool_alloc(&conf->r10bio_pool, GFP_NOIO);