hc
2024-02-20 102a0743326a03cd1a1202ceda21e175b7d3575c
kernel/drivers/md/raid0.c
....@@ -274,6 +274,18 @@
274274 goto abort;
275275 }
276276
277
+ if (conf->layout == RAID0_ORIG_LAYOUT) {
278
+ for (i = 1; i < conf->nr_strip_zones; i++) {
279
+ sector_t first_sector = conf->strip_zone[i-1].zone_end;
280
+
281
+ sector_div(first_sector, mddev->chunk_sectors);
282
+ zone = conf->strip_zone + i;
283
+ /* disk_shift is first disk index used in the zone */
284
+ zone->disk_shift = sector_div(first_sector,
285
+ zone->nb_dev);
286
+ }
287
+ }
288
+
277289 pr_debug("md/raid0:%s: done.\n", mdname(mddev));
278290 *private_conf = conf;
279291
....@@ -427,6 +439,20 @@
427439 kfree(conf);
428440 }
429441
442
+/*
443
+ * Convert disk_index to the disk order in which it is read/written.
444
+ * For example, if we have 4 disks, they are numbered 0,1,2,3. If we
445
+ * write the disks starting at disk 3, then the read/write order would
446
+ * be disk 3, then 0, then 1, and then disk 2 and we want map_disk_shift()
447
+ * to map the disks as follows 0,1,2,3 => 1,2,3,0. So disk 0 would map
448
+ * to 1, 1 to 2, 2 to 3, and 3 to 0. That way we can compare disks in
449
+ * that 'output' space to understand the read/write disk ordering.
450
+ */
451
+static int map_disk_shift(int disk_index, int num_disks, int disk_shift)
452
+{
453
+ return ((disk_index + num_disks - disk_shift) % num_disks);
454
+}
455
+
430456 static void raid0_handle_discard(struct mddev *mddev, struct bio *bio)
431457 {
432458 struct r0conf *conf = mddev->private;
....@@ -440,7 +466,9 @@
440466 sector_t end_disk_offset;
441467 unsigned int end_disk_index;
442468 unsigned int disk;
469
+ sector_t orig_start, orig_end;
443470
471
+ orig_start = start;
444472 zone = find_zone(conf, &start);
445473
446474 if (bio_end_sector(bio) > zone->zone_end) {
....@@ -454,6 +482,7 @@
454482 } else
455483 end = bio_end_sector(bio);
456484
485
+ orig_end = end;
457486 if (zone != conf->strip_zone)
458487 end = end - zone[-1].zone_end;
459488
....@@ -465,13 +494,26 @@
465494 last_stripe_index = end;
466495 sector_div(last_stripe_index, stripe_size);
467496
468
- start_disk_index = (int)(start - first_stripe_index * stripe_size) /
469
- mddev->chunk_sectors;
497
+ /* In the first zone the original and alternate layouts are the same */
498
+ if ((conf->layout == RAID0_ORIG_LAYOUT) && (zone != conf->strip_zone)) {
499
+ sector_div(orig_start, mddev->chunk_sectors);
500
+ start_disk_index = sector_div(orig_start, zone->nb_dev);
501
+ start_disk_index = map_disk_shift(start_disk_index,
502
+ zone->nb_dev,
503
+ zone->disk_shift);
504
+ sector_div(orig_end, mddev->chunk_sectors);
505
+ end_disk_index = sector_div(orig_end, zone->nb_dev);
506
+ end_disk_index = map_disk_shift(end_disk_index,
507
+ zone->nb_dev, zone->disk_shift);
508
+ } else {
509
+ start_disk_index = (int)(start - first_stripe_index * stripe_size) /
510
+ mddev->chunk_sectors;
511
+ end_disk_index = (int)(end - last_stripe_index * stripe_size) /
512
+ mddev->chunk_sectors;
513
+ }
470514 start_disk_offset = ((int)(start - first_stripe_index * stripe_size) %
471515 mddev->chunk_sectors) +
472516 first_stripe_index * mddev->chunk_sectors;
473
- end_disk_index = (int)(end - last_stripe_index * stripe_size) /
474
- mddev->chunk_sectors;
475517 end_disk_offset = ((int)(end - last_stripe_index * stripe_size) %
476518 mddev->chunk_sectors) +
477519 last_stripe_index * mddev->chunk_sectors;
....@@ -480,18 +522,22 @@
480522 sector_t dev_start, dev_end;
481523 struct bio *discard_bio = NULL;
482524 struct md_rdev *rdev;
525
+ int compare_disk;
483526
484
- if (disk < start_disk_index)
527
+ compare_disk = map_disk_shift(disk, zone->nb_dev,
528
+ zone->disk_shift);
529
+
530
+ if (compare_disk < start_disk_index)
485531 dev_start = (first_stripe_index + 1) *
486532 mddev->chunk_sectors;
487
- else if (disk > start_disk_index)
533
+ else if (compare_disk > start_disk_index)
488534 dev_start = first_stripe_index * mddev->chunk_sectors;
489535 else
490536 dev_start = start_disk_offset;
491537
492
- if (disk < end_disk_index)
538
+ if (compare_disk < end_disk_index)
493539 dev_end = (last_stripe_index + 1) * mddev->chunk_sectors;
494
- else if (disk > end_disk_index)
540
+ else if (compare_disk > end_disk_index)
495541 dev_end = last_stripe_index * mddev->chunk_sectors;
496542 else
497543 dev_end = end_disk_offset;