aboutsummaryrefslogtreecommitdiffstats
path: root/drivers
diff options
context:
space:
mode:
authorNeilBrown <neilb@suse.de>2007-02-28 23:11:18 -0500
committerLinus Torvalds <torvalds@woody.linux-foundation.org>2007-03-01 17:53:36 -0500
commit64a742bc61f9115b0bb270fa081e5b5b9c35dcd0 (patch)
tree3ed58984e5f2e6d3484c33fe7d6355658a6f2f15 /drivers
parent5a243e0e97edce27c12f87354fd987526ba1ce95 (diff)
[PATCH] md: fix raid10 recovery problem.
There are two errors that can lead to recovery problems with raid10 when used in 'far' more (not the default). Due to a '>' instead of '>=' the wrong block is located which would result in garbage being written to some random location, quite possible outside the range of the device, causing the newly reconstructed device to fail. The device size calculation had some rounding errors (it didn't round when it should) and so recovery would go a few blocks too far which would again cause a write to a random block address and probably a device error. The code for working with device sizes was fairly confused and spread out, so this has been tided up a bit. Signed-off-by: Neil Brown <neilb@suse.de> Signed-off-by: Andrew Morton <akpm@linux-foundation.org> Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
Diffstat (limited to 'drivers')
-rw-r--r--drivers/md/raid10.c38
1 files changed, 20 insertions, 18 deletions
diff --git a/drivers/md/raid10.c b/drivers/md/raid10.c
index a9401c017e35..82249a69014f 100644
--- a/drivers/md/raid10.c
+++ b/drivers/md/raid10.c
@@ -429,7 +429,7 @@ static sector_t raid10_find_virt(conf_t *conf, sector_t sector, int dev)
429 if (dev < 0) 429 if (dev < 0)
430 dev += conf->raid_disks; 430 dev += conf->raid_disks;
431 } else { 431 } else {
432 while (sector > conf->stride) { 432 while (sector >= conf->stride) {
433 sector -= conf->stride; 433 sector -= conf->stride;
434 if (dev < conf->near_copies) 434 if (dev < conf->near_copies)
435 dev += conf->raid_disks - conf->near_copies; 435 dev += conf->raid_disks - conf->near_copies;
@@ -1801,6 +1801,7 @@ static sector_t sync_request(mddev_t *mddev, sector_t sector_nr, int *skipped, i
1801 for (k=0; k<conf->copies; k++) 1801 for (k=0; k<conf->copies; k++)
1802 if (r10_bio->devs[k].devnum == i) 1802 if (r10_bio->devs[k].devnum == i)
1803 break; 1803 break;
1804 BUG_ON(k == conf->copies);
1804 bio = r10_bio->devs[1].bio; 1805 bio = r10_bio->devs[1].bio;
1805 bio->bi_next = biolist; 1806 bio->bi_next = biolist;
1806 biolist = bio; 1807 biolist = bio;
@@ -2021,19 +2022,30 @@ static int run(mddev_t *mddev)
2021 if (!conf->tmppage) 2022 if (!conf->tmppage)
2022 goto out_free_conf; 2023 goto out_free_conf;
2023 2024
2025 conf->mddev = mddev;
2026 conf->raid_disks = mddev->raid_disks;
2024 conf->near_copies = nc; 2027 conf->near_copies = nc;
2025 conf->far_copies = fc; 2028 conf->far_copies = fc;
2026 conf->copies = nc*fc; 2029 conf->copies = nc*fc;
2027 conf->far_offset = fo; 2030 conf->far_offset = fo;
2028 conf->chunk_mask = (sector_t)(mddev->chunk_size>>9)-1; 2031 conf->chunk_mask = (sector_t)(mddev->chunk_size>>9)-1;
2029 conf->chunk_shift = ffz(~mddev->chunk_size) - 9; 2032 conf->chunk_shift = ffz(~mddev->chunk_size) - 9;
2033 size = mddev->size >> (conf->chunk_shift-1);
2034 sector_div(size, fc);
2035 size = size * conf->raid_disks;
2036 sector_div(size, nc);
2037 /* 'size' is now the number of chunks in the array */
2038 /* calculate "used chunks per device" in 'stride' */
2039 stride = size * conf->copies;
2040 sector_div(stride, conf->raid_disks);
2041 mddev->size = stride << (conf->chunk_shift-1);
2042
2030 if (fo) 2043 if (fo)
2031 conf->stride = 1 << conf->chunk_shift; 2044 stride = 1;
2032 else { 2045 else
2033 stride = mddev->size >> (conf->chunk_shift-1);
2034 sector_div(stride, fc); 2046 sector_div(stride, fc);
2035 conf->stride = stride << conf->chunk_shift; 2047 conf->stride = stride << conf->chunk_shift;
2036 } 2048
2037 conf->r10bio_pool = mempool_create(NR_RAID10_BIOS, r10bio_pool_alloc, 2049 conf->r10bio_pool = mempool_create(NR_RAID10_BIOS, r10bio_pool_alloc,
2038 r10bio_pool_free, conf); 2050 r10bio_pool_free, conf);
2039 if (!conf->r10bio_pool) { 2051 if (!conf->r10bio_pool) {
@@ -2063,8 +2075,6 @@ static int run(mddev_t *mddev)
2063 2075
2064 disk->head_position = 0; 2076 disk->head_position = 0;
2065 } 2077 }
2066 conf->raid_disks = mddev->raid_disks;
2067 conf->mddev = mddev;
2068 spin_lock_init(&conf->device_lock); 2078 spin_lock_init(&conf->device_lock);
2069 INIT_LIST_HEAD(&conf->retry_list); 2079 INIT_LIST_HEAD(&conf->retry_list);
2070 2080
@@ -2106,16 +2116,8 @@ static int run(mddev_t *mddev)
2106 /* 2116 /*
2107 * Ok, everything is just fine now 2117 * Ok, everything is just fine now
2108 */ 2118 */
2109 if (conf->far_offset) { 2119 mddev->array_size = size << (conf->chunk_shift-1);
2110 size = mddev->size >> (conf->chunk_shift-1); 2120 mddev->resync_max_sectors = size << conf->chunk_shift;
2111 size *= conf->raid_disks;
2112 size <<= conf->chunk_shift;
2113 sector_div(size, conf->far_copies);
2114 } else
2115 size = conf->stride * conf->raid_disks;
2116 sector_div(size, conf->near_copies);
2117 mddev->array_size = size/2;
2118 mddev->resync_max_sectors = size;
2119 2121
2120 mddev->queue->unplug_fn = raid10_unplug; 2122 mddev->queue->unplug_fn = raid10_unplug;
2121 mddev->queue->issue_flush_fn = raid10_issue_flush; 2123 mddev->queue->issue_flush_fn = raid10_issue_flush;