X-Git-Url: http://git.ipfire.org/?a=blobdiff_plain;f=restripe.c;h=d33dbbad81005992ce46f1eb4e6eae7317417167;hb=832b2b9a7ed4f5f4ff3f1501552487e7fdf78caf;hp=e5ecd1076db69add69f8accbc6f5a41ff5f55272;hpb=ca4f89a3b76187dcd7ca897035a8e92ab67b252d;p=thirdparty%2Fmdadm.git diff --git a/restripe.c b/restripe.c index e5ecd107..d33dbbad 100644 --- a/restripe.c +++ b/restripe.c @@ -43,6 +43,11 @@ static int geo_map(int block, unsigned long long stripe, int raid_disks, */ int pd; + /* layout is not relevant for raid0 and raid4 */ + if ((level == 0) || + (level == 4)) + layout = 0; + switch(level*100 + layout) { case 000: case 400: @@ -425,7 +430,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 +470,71 @@ 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' + * Note that for the '_6' variety, the p block + * makes a hole that we need to be careful of. */ - for (i = 0; i < data_disks; i++) - bufs[i] = (uint8_t*)buf + chunk_size * ((qdisk+1+i) % raid_disks); + int j; + int snum = 0; + for (j = 0; j < raid_disks; j++) { + int dnum = (qdisk + 1 + j) % raid_disks; + if (dnum == disk || dnum == qdisk) + continue; + for (i = 0; i < data_disks; i++) + if (geo_map(i, + start/chunk_size/data_disks, + raid_disks, level, layout) == dnum) + break; + /* 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 + */ + bufs[snum] = (uint8_t*)buf + chunk_size * i; + + if (fblock[0] == i) + fdisk[0] = snum; + if (fblock[1] == i) + fdisk[1] = snum; + snum++; + } - fdisk[0] = (qdisk + 1 + fdisk[0]) % raid_disks; - fdisk[1] = (qdisk + 1 + fdisk[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 0) { - int len = data_disks * chunk_size; + unsigned int len = data_disks * chunk_size; unsigned long long offset; int disk, qdisk; int syndrome_disks; @@ -552,9 +597,11 @@ int restore_stripes(int *dest, unsigned long long *offsets, for (i=0; i < data_disks; i++) { int disk = geo_map(i, start/chunk_size/data_disks, raid_disks, level, layout); - if (lseek64(source, read_offset, 0) != read_offset) + if ((unsigned long long)lseek64(source, read_offset, 0) + != read_offset) return -1; - if (read(source, stripes[disk], chunk_size) != chunk_size) + if (read(source, stripes[disk], + chunk_size) != chunk_size) return -1; read_offset += chunk_size; } @@ -645,7 +692,7 @@ int test_stripes(int *source, unsigned long long *offsets, } switch(level) { case 6: - qsyndrome(p, q, blocks, data_disks, chunk_size); + qsyndrome(p, q, (uint8_t**)blocks, data_disks, chunk_size); disk = geo_map(-1, start/chunk_size, raid_disks, level, layout); if (memcmp(p, stripes[disk], chunk_size) != 0) {