]> git.ipfire.org Git - thirdparty/mdadm.git/blobdiff - Grow.c
Split 'GCD' out into a separate function.
[thirdparty/mdadm.git] / Grow.c
diff --git a/Grow.c b/Grow.c
index ea86f7bb142a5a5967d2f945f38fb9509b8b8c5e..ba00f2757e853aee3eb94fb6911c5ba7157ef53c 100644 (file)
--- a/Grow.c
+++ b/Grow.c
@@ -1,7 +1,7 @@
 /*
  * mdadm - manage Linux "md" devices aka RAID arrays.
  *
- * Copyright (C) 2001-2009 Neil Brown <neilb@suse.de>
+ * Copyright (C) 2001-2012 Neil Brown <neilb@suse.de>
  *
  *
  *    This program is free software; you can redistribute it and/or modify
@@ -122,7 +122,8 @@ int Grow_Add_device(char *devname, int fd, char *newdev)
 
        st = super_by_fd(fd, &subarray);
        if (!st) {
-               pr_err("cannot handle arrays with superblock version %d\n", info.array.major_version);
+               pr_err("cannot handle arrays with superblock version %d\n",
+                      info.array.major_version);
                return 1;
        }
 
@@ -146,7 +147,8 @@ int Grow_Add_device(char *devname, int fd, char *newdev)
                free(st);
                return 1;
        }
-       /* now check out all the devices and make sure we can read the superblock */
+       /* now check out all the devices and make sure we can read the
+        * superblock */
        for (d=0 ; d < info.array.raid_disks ; d++) {
                mdu_disk_info_t disk;
                char *dv;
@@ -408,8 +410,8 @@ int Grow_addbitmap(char *devname, int fd, struct context *c, struct shape *s)
                                                )
                                                st->ss->write_bitmap(st, fd2);
                                        else {
-                                               pr_err("failed "
-                                                      "to create internal bitmap - chunksize problem.\n");
+                                               pr_err("failed to create internal bitmap"
+                                                      " - chunksize problem.\n");
                                                close(fd2);
                                                return 1;
                                        }
@@ -440,7 +442,7 @@ int Grow_addbitmap(char *devname, int fd, struct context *c, struct shape *s)
                int max_devs = st->max_devs;
 
                /* try to load a superblock */
-               for (d=0; d<max_devs; d++) {
+               for (d = 0; d < max_devs; d++) {
                        mdu_disk_info_t disk;
                        char *dv;
                        int fd2;
@@ -451,7 +453,8 @@ int Grow_addbitmap(char *devname, int fd, struct context *c, struct shape *s)
                            (disk.state & (1<<MD_DISK_REMOVED)))
                                continue;
                        dv = map_dev(disk.major, disk.minor, 1);
-                       if (!dv) continue;
+                       if (!dv)
+                               continue;
                        fd2 = dev_open(dv, O_RDONLY);
                        if (fd2 >= 0) {
                                if (st->ss->load_super(st, fd2, NULL) == 0) {
@@ -520,7 +523,7 @@ static __u32 bsb_csum(char *buf, int len)
 {
        int i;
        int csum = 0;
-       for (i=0; i<len; i++)
+       for (i = 0; i < len; i++)
                csum = (csum<<3) + buf[0];
        return __cpu_to_le32(csum);
 }
@@ -639,8 +642,8 @@ static void wait_reshape(struct mdinfo *sra)
        close(fd);
 }
 
-static int reshape_super(struct supertype *st, long long size, int level,
-                        int layout, int chunksize, int raid_disks,
+static int reshape_super(struct supertype *st, unsigned long long size,
+                        int level, int layout, int chunksize, int raid_disks,
                         int delta_disks, char *backup_file, char *dev,
                         int direction, int verbose)
 {
@@ -935,6 +938,17 @@ int reshape_open_backup_file(char *backup_file,
        return 1;
 }
 
+unsigned long GCD(unsigned long a, unsigned long b)
+{
+       while (a != b) {
+               if (a < b)
+                       b -= a;
+               if (b < a)
+                       a -= b;
+       }
+       return a;
+}
+
 unsigned long compute_backup_blocks(int nchunk, int ochunk,
                                    unsigned int ndata, unsigned int odata)
 {
@@ -947,12 +961,7 @@ unsigned long compute_backup_blocks(int nchunk, int ochunk,
        a = (ochunk/512) * odata;
        b = (nchunk/512) * ndata;
        /* Find GCD */
-       while (a != b) {
-               if (a < b)
-                       b -= a;
-               if (b < a)
-                       a -= b;
-       }
+       a = GCD(a, b);
        /* LCM == product / GCD */
        blocks = (ochunk/512) * (nchunk/512) * odata * ndata / a;
 
@@ -1250,9 +1259,11 @@ char *analyse_change(struct mdinfo *info, struct reshape *re)
 
                switch (re->level) {
                case 4:
-                       re->after.layout = 0 ; break;
+                       re->after.layout = 0;
+                       break;
                case 5:
-                       re->after.layout = ALGORITHM_PARITY_N; break;
+                       re->after.layout = ALGORITHM_PARITY_N;
+                       break;
                }
                break;
 
@@ -1263,9 +1274,11 @@ char *analyse_change(struct mdinfo *info, struct reshape *re)
 
                switch (re->level) {
                case 4:
-                       re->after.layout = 0 ; break;
+                       re->after.layout = 0;
+                       break;
                case 5:
-                       re->after.layout = ALGORITHM_PARITY_N; break;
+                       re->after.layout = ALGORITHM_PARITY_N;
+                       break;
                }
                break;
 
@@ -1337,10 +1350,13 @@ char *analyse_change(struct mdinfo *info, struct reshape *re)
                                + info->delta_disks
                                - delta_parity);
        switch (re->level) {
-       case 6: re->parity = 2; break;
+       case 6: re->parity = 2;
+               break;
        case 4:
-       case 5: re->parity = 1; break;
-       default: re->parity = 0; break;
+       case 5: re->parity = 1;
+               break;
+       default: re->parity = 0;
+               break;
        }
        /* So we have a restripe operation, we need to calculate the number
         * of blocks per reshape operation.
@@ -1430,6 +1446,7 @@ static int reshape_container(char *container, char *devname,
 
 int Grow_reshape(char *devname, int fd,
                 struct mddev_dev *devlist,
+                unsigned long long data_offset,
                 struct context *c, struct shape *s)
 {
        /* Make some changes in the shape of an array.
@@ -1466,6 +1483,11 @@ int Grow_reshape(char *devname, int fd,
        struct mdinfo info;
        struct mdinfo *sra;
 
+       if (data_offset != INVALID_SECTORS) {
+               fprintf(stderr, Name ": --grow --data-offset not yet supported\n");
+               return 1;
+       }
+
        if (ioctl(fd, GET_ARRAY_INFO, &array) < 0) {
                pr_err("%s is not an active md array - aborting\n",
                        devname);
@@ -1609,7 +1631,7 @@ int Grow_reshape(char *devname, int fd,
        }
 
        /* ========= set size =============== */
-       if (s->size > 0 && (s->size == MAX_DISKS || s->size != (unsigned)array.size)) {
+       if (s->size > 0 && (s->size == MAX_SIZE || s->size != (unsigned)array.size)) {
                unsigned long long orig_size = get_component_size(fd)/2;
                unsigned long long min_csize;
                struct mdinfo *mdi;
@@ -1989,7 +2011,7 @@ size_change_error:
                /* Impose these changes on a single array.  First
                 * check that the metadata is OK with the change. */
 
-               if (reshape_super(st, -1, info.new_level,
+               if (reshape_super(st, 0, info.new_level,
                                  info.new_layout, info.new_chunk,
                                  info.array.raid_disks, info.delta_disks,
                                  c->backup_file, devname, APPLY_METADATA_CHANGES,
@@ -2077,6 +2099,7 @@ static int reshape_array(char *container, int fd, char *devname,
        char *msg;
        int orig_level = UnSet;
        int disks, odisks;
+       int delayed;
 
        struct mdu_array_info_s array;
        char *c;
@@ -2563,6 +2586,39 @@ started:
                break;
        }
 
+       /* If another array on the same devices is busy, the
+        * reshape will wait for them.  This would mean that
+        * the first section that we suspend will stay suspended
+        * for a long time.  So check on that possibility
+        * by looking for "DELAYED" in /proc/mdstat, and if found,
+        * wait a while
+        */
+       do {
+               struct mdstat_ent *mds, *m;
+               delayed = 0;
+               mds = mdstat_read(0, 0);
+               for (m = mds; m; m = mds->next)
+                       if (m->devnum == devname2devnum(sra->sys_name)) {
+                               if (m->resync &&
+                                   m->percent == RESYNC_DELAYED)
+                                       delayed = 1;
+                               if (m->resync == 0)
+                                       /* Haven't started the reshape thread
+                                        * yet, wait a bit
+                                        */
+                                       delayed = 2;
+                               break;
+                       }
+               free_mdstat(mds);
+               if (delayed == 1 && get_linux_version() < 3007000) {
+                       pr_err("Reshape is delayed, but cannot wait carefully with this kernel.\n"
+                              "       You might experience problems until other reshapes complete.\n");
+                       delayed = 0;
+               }
+               if (delayed)
+                       sleep(30 - (delayed-1) * 25);
+       } while (delayed);
+
        close(fd);
        if (check_env("MDADM_GROW_VERIFY"))
                fd = open(devname, O_RDONLY | O_DIRECT);
@@ -2674,10 +2730,10 @@ int reshape_container(char *container, char *devname,
        int last_devnum = -1;
 
        /* component_size is not meaningful for a container,
-        * so pass '-1' meaning 'no change'
+        * so pass '0' meaning 'no change'
         */
        if (!restart &&
-           reshape_super(st, -1, info->new_level,
+           reshape_super(st, 0, info->new_level,
                          info->new_layout, info->new_chunk,
                          info->array.raid_disks, info->delta_disks,
                          backup_file, devname, APPLY_METADATA_CHANGES,
@@ -3731,9 +3787,8 @@ int Grow_restart(struct supertype *st, struct mdinfo *info, int *fdlist, int cnt
                                        (unsigned long)__le64_to_cpu(bsb.mtime),
                                        (unsigned long)info->array.utime);
                        } else {
-                               if (verbose)
-                                       pr_err("too-old timestamp on "
-                                               "backup-metadata on %s\n", devname);
+                               pr_err("too-old timestamp on backup-metadata on %s\n", devname);
+                               pr_err("If you think it is should be safe, try 'export MDADM_GROW_ALLOW_OLD=1'\n");
                                continue; /* time stamp is too bad */
                        }
                }
@@ -3888,7 +3943,8 @@ int Grow_restart(struct supertype *st, struct mdinfo *info, int *fdlist, int cnt
                        }
                }
                for (j=0; j<info->array.raid_disks; j++) {
-                       if (fdlist[j] < 0) continue;
+                       if (fdlist[j] < 0)
+                               continue;
                        if (st->ss->load_super(st, fdlist[j], NULL))
                                continue;
                        st->ss->getinfo_super(st, &dinfo, NULL);