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
270270 goto abort;
271271 }
272272
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+
273285 pr_debug("md/raid0:%s: done.\n", mdname(mddev));
274286 *private_conf = conf;
275287
@@ -431,6 +443,20 @@ exit_acct_set: · 155 unmodified lines
431443 return ret;
432444 }
433445
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+ */
455+static 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+
434460 static void raid0_handle_discard(struct mddev *mddev, struct bio *bio)
435461 {
436462 struct r0conf *conf = mddev->private;
@@ -444,7 +470,9 @@ static void raid0_handle_discard(struct mddev *mddev, struct bio *bio) · 7 unmodified lines
444470 sector_t end_disk_offset;
445471 unsigned int end_disk_index;
446472 unsigned int disk;
473+ sector_t orig_start, orig_end;
447474
475+ orig_start = start;
448476 zone = find_zone(conf, &start);
449477
450478 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
458486 } else
459487 end = bio_end_sector(bio);
460488
489+ orig_end = end;
461490 if (zone != conf->strip_zone)
462491 end = end - zone[-1].zone_end;
463492
@@ -469,13 +498,26 @@ static void raid0_handle_discard(struct mddev *mddev, struct bio *bio) · 5 unmodified lines
469498 last_stripe_index = end;
470499 sector_div(last_stripe_index, stripe_size);
471500
472− start_disk_index = (int)(start - first_stripe_index * stripe_size) /
473− mddev->chunk_sectors;
501+ /* In the first zone the original and alternate layouts are the same */
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+ }
474518 start_disk_offset = ((int)(start - first_stripe_index * stripe_size) %
475519 mddev->chunk_sectors) +
476520 first_stripe_index * mddev->chunk_sectors;
477− end_disk_index = (int)(end - last_stripe_index * stripe_size) /
478− mddev->chunk_sectors;
479521 end_disk_offset = ((int)(end - last_stripe_index * stripe_size) %
480522 mddev->chunk_sectors) +
481523 last_stripe_index * mddev->chunk_sectors;
@@ -483,18 +525,22 @@ static void raid0_handle_discard(struct mddev *mddev, struct bio *bio) · 1 unmodified line
483525 for (disk = 0; disk < zone->nb_dev; disk++) {
484526 sector_t dev_start, dev_end;
485527 struct md_rdev *rdev;
528+ int compare_disk;
529+
530+ compare_disk = map_disk_shift(disk, zone->nb_dev,
531+ zone->disk_shift);
486532
487− if (disk < start_disk_index)
533+ if (compare_disk < start_disk_index)
488534 dev_start = (first_stripe_index + 1) *
489535 mddev->chunk_sectors;
490− else if (disk > start_disk_index)
536+ else if (compare_disk > start_disk_index)
491537 dev_start = first_stripe_index * mddev->chunk_sectors;
492538 else
493539 dev_start = start_disk_offset;
494540
495− if (disk < end_disk_index)
541+ if (compare_disk < end_disk_index)
496542 dev_end = (last_stripe_index + 1) * mddev->chunk_sectors;
497− else if (disk > end_disk_index)
543+ else if (compare_disk > end_disk_index)
498544 dev_end = last_stripe_index * mddev->chunk_sectors;
499545 else
500546 dev_end = end_disk_offset;
drivers/md/raid0.h+1−0
@@ -6,6 +6,7 @@ struct strip_zone { · 5 unmodified lines
66 sector_t zone_end; /* Start of the next zone (in sectors) */
77 sector_t dev_start; /* Zone offset in real dev (in sectors) */
88 int nb_dev; /* # of devices attached to the zone */
9+ int disk_shift; /* start disk for the original layout */
910 };
1011
1112 /* Linux 3.14 (20d0189b101) made an unintended change to