diff options
author | Jonathan Brassow <jbrassow@redhat.com> | 2013-02-20 21:28:10 -0500 |
---|---|---|
committer | NeilBrown <neilb@suse.de> | 2013-02-25 19:55:33 -0500 |
commit | 9a3152ab024867100f2f50d124b998d05fb1c3f6 (patch) | |
tree | 15b97c56d117340fa5db609ced6e0d51a91f2f37 /drivers/md | |
parent | 475901aff15841fb0a81e7546517407779a9b061 (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.c | 30 |
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) { |