diff options
author | NeilBrown <neilb@suse.de> | 2009-10-12 16:57:22 +1100 |
---|---|---|
committer | NeilBrown <neilb@suse.de> | 2009-10-12 16:57:22 +1100 |
commit | cc50ccdc2960d9feb322002f6ebfd8fba950b79f (patch) | |
tree | c6d3f6db0b3d831e949ca11cbdc50549f4b51121 /restripe.c | |
parent | 487e48afabe36ff71c8e2a177880daaf4a24d089 (diff) | |
download | mdadm-cc50ccdc2960d9feb322002f6ebfd8fba950b79f.tar.gz mdadm-cc50ccdc2960d9feb322002f6ebfd8fba950b79f.tar.xz mdadm-cc50ccdc2960d9feb322002f6ebfd8fba950b79f.zip |
restripe : various fixed for RAID6 2-failure recovery.
Signed-off-by: NeilBrown <neilb@suse.de>
Diffstat (limited to 'restripe.c')
-rw-r--r-- | restripe.c | 52 |
1 files changed, 40 insertions, 12 deletions
@@ -425,7 +425,7 @@ int save_stripes(int *source, unsigned long long *offsets, raid_disks, level, layout); if (dnum < 0) abort(); if (source[dnum] < 0 || - lseek64(source[dnum], offsets[disk]+offset, 0) < 0 || + lseek64(source[dnum], offsets[dnum]+offset, 0) < 0 || read(source[dnum], buf+disk * chunk_size, chunk_size) != chunk_size) if (failed <= 2) { @@ -465,32 +465,60 @@ int save_stripes(int *source, unsigned long long *offsets, * 'p' and 'q' get to be all zero */ for (i = 0; i < raid_disks; i++) - if (i == disk || i == qdisk) - bufs[i] = zero; - else - bufs[i] = (uint8_t*)buf+i*chunk_size; + bufs[i] = zero; + for (i = 0; i < data_disks; i++) { + int dnum = geo_map(i, + start/chunk_size/data_disks, + raid_disks, level, layout); + int snum; + /* i is the logical block number, so is index to 'buf'. + * dnum is physical disk number + * and thus the syndrome number. + */ + snum = dnum; + bufs[snum] = (uint8_t*)buf + chunk_size * i; + } syndrome_disks = raid_disks; } else { /* for md, q is over 'data_disks' blocks, * starting immediately after 'q' */ - for (i = 0; i < data_disks; i++) - bufs[i] = (uint8_t*)buf + chunk_size * ((qdisk+1+i) % raid_disks); + for (i = 0; i < data_disks; i++) { + int dnum = geo_map(i, + start/chunk_size/data_disks, + raid_disks, level, layout); + int snum; + /* i is the logical block number, so is index to 'buf'. + * dnum is physical disk number + * snum is syndrome disk for which 0 is immediately after Q + */ + snum = (raid_disks + dnum - qdisk - 1) % raid_disks; + bufs[snum] = (uint8_t*)buf + chunk_size * i; + } - fdisk[0] = (qdisk + 1 + fdisk[0]) % raid_disks; - fdisk[1] = (qdisk + 1 + fdisk[1]) % raid_disks; + fdisk[0] = (raid_disks + fdisk[0] - qdisk - 1) % raid_disks; + fdisk[1] = (raid_disks + fdisk[1] - qdisk - 1) % raid_disks; syndrome_disks = data_disks; } - bufs[syndrome_disks] = (uint8_t*)buf + chunk_size * disk; - bufs[syndrome_disks+1] = (uint8_t*)buf + chunk_size * qdisk; + + /* Place P and Q blocks at end of bufs */ + bufs[syndrome_disks] = (uint8_t*)buf + chunk_size * data_disks; + bufs[syndrome_disks+1] = (uint8_t*)buf + chunk_size * (data_disks+1); + if (fblock[1] == data_disks) /* One data failed, and parity failed */ raid6_datap_recov(syndrome_disks+2, chunk_size, fdisk[0], bufs); - else + else { + if (fdisk[0] > fdisk[1]) { + int t = fdisk[0]; + fdisk[0] = fdisk[1]; + fdisk[1] = t; + } /* Two data blocks failed, P,Q OK */ raid6_2data_recov(syndrome_disks+2, chunk_size, fdisk[0], fdisk[1], bufs); + } } for (i=0; i<nwrites; i++) |