]> git.ipfire.org Git - thirdparty/mdadm.git/blobdiff - Grow.c
Support external metadata recovery-resume
[thirdparty/mdadm.git] / Grow.c
diff --git a/Grow.c b/Grow.c
index 75af6f3a8302c6399b4c39249858721e94827134..a654d4e84f2aba2571797e11698772bc53d50535 100644 (file)
--- a/Grow.c
+++ b/Grow.c
@@ -381,7 +381,7 @@ int Grow_addbitmap(char *devname, int fd, char *file, int chunk, int delay, int
 /*
  * When reshaping an array we might need to backup some data.
  * This is written to all spares with a 'super_block' describing it.
- * The superblock goes 1K form the end of the used space on the
+ * The superblock goes 4K from the end of the used space on the
  * device.
  * It if written after the backup is complete.
  * It has the following structure.
@@ -524,6 +524,15 @@ int Grow_reshape(char *devname, int fd, int quiet, char *backup_file,
                return 1;
        }
 
+       if (size >= 0 &&
+           (chunksize || level!= UnSet || layout_str || raid_disks)) {
+               fprintf(stderr, Name ": cannot change component size at the same time "
+                       "as other changes.\n"
+                       "   Change size first, then check data is intact before "
+                       "making other changes.\n");
+               return 1;
+       }
+
        if (raid_disks && raid_disks < array.raid_disks && array.level > 1 &&
            get_linux_version() < 2006032 &&
            !check_env("MDADM_FORCE_FEWER")) {
@@ -882,7 +891,7 @@ int Grow_reshape(char *devname, int fd, int quiet, char *backup_file,
                }
 
                /* Check that we can hold all the data */
-               size = ndata * array.size;
+               size = ndata * (long long)array.size;
                get_dev_size(fd, NULL, &array_size);
                if (size < (array_size/1024)) {
                        fprintf(stderr, Name ": this change will reduce the size of the array.\n"
@@ -973,7 +982,7 @@ int Grow_reshape(char *devname, int fd, int quiet, char *backup_file,
                                char *dn = map_dev(sd->disk.major,
                                                   sd->disk.minor, 1);
                                fdlist[d] = dev_open(dn, O_RDWR);
-                               offsets[d] = (sra->component_size - blocks - 8)*512;
+                               offsets[d] = (sd->data_offset + sra->component_size - blocks - 8)*512;
                                if (fdlist[d]<0) {
                                        fprintf(stderr, Name ": %s: cannot open component %s\n",
                                                devname, dn?dn:"-unknown");
@@ -1299,6 +1308,10 @@ int grow_backup(struct mdinfo *sra,
 
                lseek64(destfd[i], destoffsets[i] - 4096, 0);
                write(destfd[i], &bsb, 512);
+               if (destoffsets[i] > 4096) {
+                       lseek64(destfd[i], destoffsets[i]+stripes*chunk*odata, 0);
+                       write(destfd[i], &bsb, 512);
+               }
                fsync(destfd[i]);
        }
 
@@ -1619,7 +1632,6 @@ int Grow_restart(struct supertype *st, struct mdinfo *info, int *fdlist, int cnt
                old_disks = cnt;
        for (i=old_disks-(backup_file?1:0); i<cnt; i++) {
                struct mdinfo dinfo;
-               char buf[4096];
                int fd;
                int bsbsize;
                char *devname, namebuf[20];
@@ -1735,13 +1747,13 @@ int Grow_restart(struct supertype *st, struct mdinfo *info, int *fdlist, int cnt
                }
                /* There should be a duplicate backup superblock 4k before here */
                if (lseek64(fd, -4096, 1) < 0 ||
-                   read(fd, buf, 4096) != 4096)
+                   read(fd, &bsb2, 4096) != 4096)
                        goto second_fail; /* Cannot find leading superblock */
                if (bsb.magic[15] == '1')
                        bsbsize = offsetof(struct mdp_backup_super, pad1);
                else
                        bsbsize = offsetof(struct mdp_backup_super, pad);
-               if (memcmp(buf, &bsb, bsbsize) != 0)
+               if (memcmp(&bsb2, &bsb, bsbsize) != 0)
                        goto second_fail; /* Cannot find leading superblock */
 
                /* Now need the data offsets for all devices. */
@@ -1754,7 +1766,7 @@ int Grow_restart(struct supertype *st, struct mdinfo *info, int *fdlist, int cnt
                                continue;
                        st->ss->getinfo_super(st, &dinfo);
                        st->ss->free_super(st);
-                       offsets[j] = dinfo.data_offset;
+                       offsets[j] = dinfo.data_offset * 512;
                }
                printf(Name ": restoring critical section\n");