History

Merge tag 'md-fixes-20230630' of https://git.kernel.org/pub/scm/linux/kernel/git/song/md into block-6.5

Pull MD fix from Song: "This patch fixes data corruption caused by discard on raid0 array with original layout." * tag 'md-fixes-20230630' of https://git.kernel.org/pub/scm/linux/kernel/git/song/md: md/raid0: add discard support for the 'original' layout

Jens Axboe committed 3 years ago

Commit 3c2f7652 parents 6e34e78 e8360072 files · +55 −8Browse files

Unified · Split

2 files
  1. drivers/md/raid0.c +54 −8
  2. drivers/md/raid0.h +1 −0
drivers/md/raid0.c+54−8
@@ -270,6 +270,18 @@ static int create_strip_zones(struct mddev *mddev, struct r0conf **private_conf) · 269 unmodified lines
270 goto abort;270 goto abort;
271 }271 }
272 272
273 if (conf->layout == RAID0_ORIG_LAYOUT) {
274 for (i = 1; i < conf->nr_strip_zones; i++) {
275 sector_t first_sector = conf->strip_zone[i-1].zone_end;
276
277 sector_div(first_sector, mddev->chunk_sectors);
278 zone = conf->strip_zone + i;
279 /* disk_shift is first disk index used in the zone */
280 zone->disk_shift = sector_div(first_sector,
281 zone->nb_dev);
282 }
283 }
284
273 pr_debug("md/raid0:%s: done.\n", mdname(mddev));285 pr_debug("md/raid0:%s: done.\n", mdname(mddev));
274 *private_conf = conf;286 *private_conf = conf;
275 287
@@ -431,6 +443,20 @@ exit_acct_set: · 155 unmodified lines
431 return ret;443 return ret;
432}444}
433 445
446/*
447 * Convert disk_index to the disk order in which it is read/written.
448 * For example, if we have 4 disks, they are numbered 0,1,2,3. If we
449 * write the disks starting at disk 3, then the read/write order would
450 * be disk 3, then 0, then 1, and then disk 2 and we want map_disk_shift()
451 * to map the disks as follows 0,1,2,3 => 1,2,3,0. So disk 0 would map
452 * to 1, 1 to 2, 2 to 3, and 3 to 0. That way we can compare disks in
453 * that 'output' space to understand the read/write disk ordering.
454 */
455static int map_disk_shift(int disk_index, int num_disks, int disk_shift)
456{
457 return ((disk_index + num_disks - disk_shift) % num_disks);
458}
459
434static void raid0_handle_discard(struct mddev *mddev, struct bio *bio)460static void raid0_handle_discard(struct mddev *mddev, struct bio *bio)
435{461{
436 struct r0conf *conf = mddev->private;462 struct r0conf *conf = mddev->private;
@@ -444,7 +470,9 @@ static void raid0_handle_discard(struct mddev *mddev, struct bio *bio) · 7 unmodified lines
444 sector_t end_disk_offset;470 sector_t end_disk_offset;
445 unsigned int end_disk_index;471 unsigned int end_disk_index;
446 unsigned int disk;472 unsigned int disk;
473 sector_t orig_start, orig_end;
447 474
475 orig_start = start;
448 zone = find_zone(conf, &start);476 zone = find_zone(conf, &start);
449 477
450 if (bio_end_sector(bio) > zone->zone_end) {478 if (bio_end_sector(bio) > zone->zone_end) {
@@ -458,6 +486,7 @@ static void raid0_handle_discard(struct mddev *mddev, struct bio *bio) · 7 unmodified lines
458 } else486 } else
459 end = bio_end_sector(bio);487 end = bio_end_sector(bio);
460 488
489 orig_end = end;
461 if (zone != conf->strip_zone)490 if (zone != conf->strip_zone)
462 end = end - zone[-1].zone_end;491 end = end - zone[-1].zone_end;
463 492
@@ -469,13 +498,26 @@ static void raid0_handle_discard(struct mddev *mddev, struct bio *bio) · 5 unmodified lines
469 last_stripe_index = end;498 last_stripe_index = end;
470 sector_div(last_stripe_index, stripe_size);499 sector_div(last_stripe_index, stripe_size);
471 500
472 start_disk_index = (int)(start - first_stripe_index * stripe_size) /501 /* In the first zone the original and alternate layouts are the same */
473 mddev->chunk_sectors;502 if ((conf->layout == RAID0_ORIG_LAYOUT) && (zone != conf->strip_zone)) {
503 sector_div(orig_start, mddev->chunk_sectors);
504 start_disk_index = sector_div(orig_start, zone->nb_dev);
505 start_disk_index = map_disk_shift(start_disk_index,
506 zone->nb_dev,
507 zone->disk_shift);
508 sector_div(orig_end, mddev->chunk_sectors);
509 end_disk_index = sector_div(orig_end, zone->nb_dev);
510 end_disk_index = map_disk_shift(end_disk_index,
511 zone->nb_dev, zone->disk_shift);
512 } else {
513 start_disk_index = (int)(start - first_stripe_index * stripe_size) /
514 mddev->chunk_sectors;
515 end_disk_index = (int)(end - last_stripe_index * stripe_size) /
516 mddev->chunk_sectors;
517 }
474 start_disk_offset = ((int)(start - first_stripe_index * stripe_size) %518 start_disk_offset = ((int)(start - first_stripe_index * stripe_size) %
475 mddev->chunk_sectors) +519 mddev->chunk_sectors) +
476 first_stripe_index * mddev->chunk_sectors;520 first_stripe_index * mddev->chunk_sectors;
477 end_disk_index = (int)(end - last_stripe_index * stripe_size) /
478 mddev->chunk_sectors;
479 end_disk_offset = ((int)(end - last_stripe_index * stripe_size) %521 end_disk_offset = ((int)(end - last_stripe_index * stripe_size) %
480 mddev->chunk_sectors) +522 mddev->chunk_sectors) +
481 last_stripe_index * mddev->chunk_sectors;523 last_stripe_index * mddev->chunk_sectors;
@@ -483,18 +525,22 @@ static void raid0_handle_discard(struct mddev *mddev, struct bio *bio) · 1 unmodified line
483 for (disk = 0; disk < zone->nb_dev; disk++) {525 for (disk = 0; disk < zone->nb_dev; disk++) {
484 sector_t dev_start, dev_end;526 sector_t dev_start, dev_end;
485 struct md_rdev *rdev;527 struct md_rdev *rdev;
528 int compare_disk;
529
530 compare_disk = map_disk_shift(disk, zone->nb_dev,
531 zone->disk_shift);
486 532
487 if (disk < start_disk_index)533 if (compare_disk < start_disk_index)
488 dev_start = (first_stripe_index + 1) *534 dev_start = (first_stripe_index + 1) *
489 mddev->chunk_sectors;535 mddev->chunk_sectors;
490 else if (disk > start_disk_index)536 else if (compare_disk > start_disk_index)
491 dev_start = first_stripe_index * mddev->chunk_sectors;537 dev_start = first_stripe_index * mddev->chunk_sectors;
492 else538 else
493 dev_start = start_disk_offset;539 dev_start = start_disk_offset;
494 540
495 if (disk < end_disk_index)541 if (compare_disk < end_disk_index)
496 dev_end = (last_stripe_index + 1) * mddev->chunk_sectors;542 dev_end = (last_stripe_index + 1) * mddev->chunk_sectors;
497 else if (disk > end_disk_index)543 else if (compare_disk > end_disk_index)
498 dev_end = last_stripe_index * mddev->chunk_sectors;544 dev_end = last_stripe_index * mddev->chunk_sectors;
499 else545 else
500 dev_end = end_disk_offset;546 dev_end = end_disk_offset;
drivers/md/raid0.h+1−0
@@ -6,6 +6,7 @@ struct strip_zone { · 5 unmodified lines
6 sector_t zone_end; /* Start of the next zone (in sectors) */6 sector_t zone_end; /* Start of the next zone (in sectors) */
7 sector_t dev_start; /* Zone offset in real dev (in sectors) */7 sector_t dev_start; /* Zone offset in real dev (in sectors) */
8 int nb_dev; /* # of devices attached to the zone */8 int nb_dev; /* # of devices attached to the zone */
9 int disk_shift; /* start disk for the original layout */
9};10};
10 11
11/* Linux 3.14 (20d0189b101) made an unintended change to12/* Linux 3.14 (20d0189b101) made an unintended change to