aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/md
diff options
context:
space:
mode:
authorJonathan Brassow <jbrassow@redhat.com>2013-02-20 21:28:10 -0500
committerNeilBrown <neilb@suse.de>2013-02-25 19:55:33 -0500
commit9a3152ab024867100f2f50d124b998d05fb1c3f6 (patch)
tree15b97c56d117340fa5db609ced6e0d51a91f2f37 /drivers/md
parent475901aff15841fb0a81e7546517407779a9b061 (diff)
MD RAID10: Improve redundancy for 'far' and 'offset' algorithms (part 2)
MD RAID10: Improve redundancy for 'far' and 'offset' algorithms (part 2) This patch addresses raid arrays that have a number of devices that cannot be evenly divided by 'far_copies'. (E.g. 5 devices, far_copies = 2) This case must be handled differently because it causes that last set to be of a different size than the rest of the sets. We must compute a new modulo for this last set so that copied chunks are properly wrapped around. Example use_far_sets=1, far_copies=2, near_copies=1, devices=5: "far" algorithm dev1 dev2 dev3 dev4 dev5 ==== ==== ==== ==== ==== [ A B ] [ C D E ] [ G H ] [ I J K ] ... [ B A ] [ E C D ] --> nominal set of 2 and last set of 3 [ H G ] [ K I J ] []'s show far/offset sets Signed-off-by: Jonathan Brassow <jbrassow@redhat.com> Signed-off-by: NeilBrown <neilb@suse.de>
Diffstat (limited to 'drivers/md')
-rw-r--r--drivers/md/raid10.c30
1 files changed, 28 insertions, 2 deletions
diff --git a/drivers/md/raid10.c b/drivers/md/raid10.c
index 70b58b4bcf89..61ed150bd0cf 100644
--- a/drivers/md/raid10.c
+++ b/drivers/md/raid10.c
@@ -550,6 +550,13 @@ static void __raid10_find_phys(struct geom *geo, struct r10bio *r10bio)
550 sector_t stripe; 550 sector_t stripe;
551 int dev; 551 int dev;
552 int slot = 0; 552 int slot = 0;
553 int last_far_set_start, last_far_set_size;
554
555 last_far_set_start = (geo->raid_disks / geo->far_set_size) - 1;
556 last_far_set_start *= geo->far_set_size;
557
558 last_far_set_size = geo->far_set_size;
559 last_far_set_size += (geo->raid_disks % geo->far_set_size);
553 560
554 /* now calculate first sector/dev */ 561 /* now calculate first sector/dev */
555 chunk = r10bio->sector >> geo->chunk_shift; 562 chunk = r10bio->sector >> geo->chunk_shift;
@@ -575,9 +582,16 @@ static void __raid10_find_phys(struct geom *geo, struct r10bio *r10bio)
575 for (f = 1; f < geo->far_copies; f++) { 582 for (f = 1; f < geo->far_copies; f++) {
576 set = d / geo->far_set_size; 583 set = d / geo->far_set_size;
577 d += geo->near_copies; 584 d += geo->near_copies;
578 d %= geo->far_set_size;
579 d += geo->far_set_size * set;
580 585
586 if ((geo->raid_disks % geo->far_set_size) &&
587 (d > last_far_set_start)) {
588 d -= last_far_set_start;
589 d %= last_far_set_size;
590 d += last_far_set_start;
591 } else {
592 d %= geo->far_set_size;
593 d += geo->far_set_size * set;
594 }
581 s += geo->stride; 595 s += geo->stride;
582 r10bio->devs[slot].devnum = d; 596 r10bio->devs[slot].devnum = d;
583 r10bio->devs[slot].addr = s; 597 r10bio->devs[slot].addr = s;
@@ -615,6 +629,18 @@ static sector_t raid10_find_virt(struct r10conf *conf, sector_t sector, int dev)
615 struct geom *geo = &conf->geo; 629 struct geom *geo = &conf->geo;
616 int far_set_start = (dev / geo->far_set_size) * geo->far_set_size; 630 int far_set_start = (dev / geo->far_set_size) * geo->far_set_size;
617 int far_set_size = geo->far_set_size; 631 int far_set_size = geo->far_set_size;
632 int last_far_set_start;
633
634 if (geo->raid_disks % geo->far_set_size) {
635 last_far_set_start = (geo->raid_disks / geo->far_set_size) - 1;
636 last_far_set_start *= geo->far_set_size;
637
638 if (dev >= last_far_set_start) {
639 far_set_size = geo->far_set_size;
640 far_set_size += (geo->raid_disks % geo->far_set_size);
641 far_set_start = last_far_set_start;
642 }
643 }
618 644
619 offset = sector & geo->chunk_mask; 645 offset = sector & geo->chunk_mask;
620 if (geo->far_offset) { 646 if (geo->far_offset) {