diff options
-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) { |