]> git.ipfire.org Git - thirdparty/mdadm.git/blobdiff - restripe.c
Add missing 'continue' in Grow_restart.
[thirdparty/mdadm.git] / restripe.c
index e5ecd1076db69add69f8accbc6f5a41ff5f55272..f673206102f0aea0c2b449d6ceb067a4230f1e5d 100644 (file)
@@ -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,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<nwrites; i++)
@@ -645,7 +684,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) {