]> git.ipfire.org Git - thirdparty/mdadm.git/blobdiff - Assemble.c
mdadm: add the ability to change cluster name
[thirdparty/mdadm.git] / Assemble.c
index 05ace561fb507bb6a557b3d15e6d35f18517400b..12ac299f2bf3c582e6619de2f6588704f71e6990 100644 (file)
@@ -233,8 +233,7 @@ static int select_devices(struct mddev_dev *devlist,
                                   !conf_test_metadata(tst->ss->name, (pol = devid_policy(stb.st_rdev)),
                                                       tst->ss->match_home(tst, c->homehost) == 1)) {
                                if (report_mismatch)
-                                       pr_err("%s has metadata type %s for which "
-                                              "auto-assembly is disabled\n",
+                                       pr_err("%s has metadata type %s for which auto-assembly is disabled\n",
                                               devname, tst->ss->name);
                                tmpdev->used = 2;
                        } else
@@ -259,8 +258,7 @@ static int select_devices(struct mddev_dev *devlist,
                                   !conf_test_metadata(tst->ss->name, (pol = devid_policy(stb.st_rdev)),
                                                       tst->ss->match_home(tst, c->homehost) == 1)) {
                                if (report_mismatch)
-                                       pr_err("%s has metadata type %s for which "
-                                              "auto-assembly is disabled\n",
+                                       pr_err("%s has metadata type %s for which auto-assembly is disabled\n",
                                               devname, tst->ss->name);
                                tmpdev->used = 2;
                        }
@@ -350,8 +348,7 @@ static int select_devices(struct mddev_dev *devlist,
 
                        st = tst; tst = NULL;
                        if (!auto_assem && inargv && tmpdev->next != NULL) {
-                               pr_err("%s is a container, but is not "
-                                      "only device given: confused and aborting\n",
+                               pr_err("%s is a container, but is not only device given: confused and aborting\n",
                                       devname);
                                st->ss->free_super(st);
                                dev_policy_free(pol);
@@ -366,9 +363,6 @@ static int select_devices(struct mddev_dev *devlist,
                        tmpdev = NULL;
                        goto loop;
                } else {
-                       int rv = 0;
-                       struct mddev_ident *match;
-
                        content = *contentp;
                        tst->ss->getinfo_super(tst, content, NULL);
 
@@ -377,25 +371,33 @@ static int select_devices(struct mddev_dev *devlist,
                                           report_mismatch ? devname : NULL))
                                goto loop;
 
-                       match = conf_match(tst, content, devname,
-                                          report_mismatch ? c->verbose : -1,
-                                          &rv);
-                       if (!match && rv == 2)
-                               goto loop;
-                       if (match && match->devname &&
-                           strcasecmp(match->devname, "<ignore>") == 0) {
-                               if (report_mismatch)
-                                       pr_err("%s is a member of an explicitly ignored array\n",
-                                              devname);
-                               goto loop;
-                       }
-                       if (match && !ident_matches(match, content, tst,
-                                                   c->homehost, c->update,
-                                                   report_mismatch ? devname : NULL))
-                               /* Array exists  in mdadm.conf but some
-                                * details don't match, so reject it
+                       if (auto_assem) {
+                               /* Never auto-assemble things that conflict
+                                * with mdadm.conf in some way
                                 */
-                               goto loop;
+                               struct mddev_ident *match;
+                               int rv = 0;
+
+                               match = conf_match(tst, content, devname,
+                                                  report_mismatch ? c->verbose : -1,
+                                                  &rv);
+                               if (!match && rv == 2)
+                                       goto loop;
+                               if (match && match->devname &&
+                                   strcasecmp(match->devname, "<ignore>") == 0) {
+                                       if (report_mismatch)
+                                               pr_err("%s is a member of an explicitly ignored array\n",
+                                                      devname);
+                                       goto loop;
+                               }
+                               if (match && !ident_matches(match, content, tst,
+                                                           c->homehost, c->update,
+                                                           report_mismatch ? devname : NULL))
+                                       /* Array exists  in mdadm.conf but some
+                                        * details don't match, so reject it
+                                        */
+                                       goto loop;
+                       }
 
                        /* should be safe to try an exclusive open now, we
                         * have rejected anything that some other mdadm might
@@ -574,13 +576,13 @@ static int load_devices(struct devs *devices, char *devmap,
                struct stat stb;
                struct supertype *tst;
                int i;
+               int dfd;
 
                if (tmpdev->used != 1)
                        continue;
                /* looks like a good enough match to update the super block if needed */
 #ifndef MDASSEMBLE
                if (c->update) {
-                       int dfd;
                        /* prepare useful information in info structures */
                        struct stat stb2;
                        int err;
@@ -624,15 +626,17 @@ static int load_devices(struct devs *devices, char *devmap,
 
                        if (strcmp(c->update, "byteorder") == 0)
                                err = 0;
-                       else
+                       else if (strcmp(c->update, "home-cluster") == 0) {
+                               tst->cluster_name = c->homecluster;
+                               tst->ss->write_bitmap(tst, dfd, NameUpdate);
+                       } else
                                err = tst->ss->update_super(tst, content, c->update,
                                                            devname, c->verbose,
                                                            ident->uuid_set,
                                                            c->homehost);
                        if (err < 0) {
                                if (err == -1)
-                                       pr_err("--update=%s not understood"
-                                              " for %s metadata\n",
+                                       pr_err("--update=%s not understood for %s metadata\n",
                                               c->update, tst->ss->name);
                                tst->ss->free_super(tst);
                                free(tst);
@@ -651,7 +655,6 @@ static int load_devices(struct devs *devices, char *devmap,
                        if (tst->ss->store_super(tst, dfd))
                                pr_err("Could not re-write superblock on %s.\n",
                                       devname);
-                       close(dfd);
 
                        if (strcmp(c->update, "uuid")==0 &&
                            ident->bitmap_fd >= 0 && !bitmap_done) {
@@ -665,9 +668,9 @@ static int load_devices(struct devs *devices, char *devmap,
                } else
 #endif
                {
-                       int dfd = dev_open(devname,
-                                          tmpdev->disposition == 'I'
-                                          ? O_RDWR : (O_RDWR|O_EXCL));
+                       dfd = dev_open(devname,
+                                      tmpdev->disposition == 'I'
+                                      ? O_RDWR : (O_RDWR|O_EXCL));
                        tst = dup_super(st);
 
                        if (dfd < 0 || tst->ss->load_super(tst, dfd, NULL) != 0) {
@@ -684,10 +687,10 @@ static int load_devices(struct devs *devices, char *devmap,
                                return -1;
                        }
                        tst->ss->getinfo_super(tst, content, devmap + devcnt * content->array.raid_disks);
-                       close(dfd);
                }
 
-               stat(devname, &stb);
+               fstat(dfd, &stb);
+               close(dfd);
 
                if (c->verbose > 0)
                        pr_err("%s is identified as a member of %s, slot %d%s.\n",
@@ -757,12 +760,9 @@ static int load_devices(struct devs *devices, char *devmap,
                                 * Could be a mis-detection caused by overlapping
                                 * partitions.  fail-safe.
                                 */
-                               pr_err("WARNING %s and %s appear"
-                                      " to have very similar superblocks.\n"
-                                      "      If they are really different, "
-                                      "please --zero the superblock on one\n"
-                                      "      If they are the same or overlap,"
-                                      " please remove one from %s.\n",
+                               pr_err("WARNING %s and %s appear to have very similar superblocks.\n"
+                                      "      If they are really different, please --zero the superblock on one\n"
+                                      "      If they are the same or overlap, please remove one from %s.\n",
                                       devices[best[i]].devname, devname,
                                       inargv ? "the list" :
                                       "the\n      DEVICE list in mdadm.conf"
@@ -820,12 +820,37 @@ static int force_array(struct mdinfo *content,
                     i < content->array.raid_disks * 2 && i < bestcnt;
                     i += 2) {
                        int j = best[i];
-                       if (j>=0 &&
-                           !devices[j].uptodate &&
-                           devices[j].i.recovery_start == MaxSector &&
-                           (chosen_drive < 0 ||
+                       if (j < 0)
+                               continue;
+                       if (devices[j].uptodate)
+                               continue;
+                       if (devices[j].i.recovery_start != MaxSector) {
+                               int delta;
+                               if (!devices[j].i.reshape_active ||
+                                   devices[j].i.delta_disks <= 0)
+                                       continue;
+                               /* When increasing number of devices, an
+                                * added device also appears to be
+                                * recovering.  It is safe to include it
+                                * as long as it won't be a source of
+                                * data.
+                                * For now, just allow for last data
+                                * devices in RAID4 or last devices in RAID4/5/6.
+                                */
+                               delta = devices[j].i.delta_disks;
+                               if (devices[j].i.array.level >= 4 &&
+                                   devices[j].i.array.level <= 6 &&
+                                   i/2 >= content->array.raid_disks - delta)
+                                       /* OK */;
+                               else if (devices[j].i.array.level == 4 &&
+                                        i/2 >= content->array.raid_disks - delta - 1)
+                                       /* OK */;
+                               else
+                                       continue;
+                       }
+                       if (chosen_drive < 0 ||
                             devices[j].i.events
-                            > devices[chosen_drive].i.events))
+                           > devices[chosen_drive].i.events)
                                chosen_drive = j;
                }
                if (chosen_drive < 0)
@@ -963,8 +988,7 @@ static int start_array(int mdfd,
                        rv = add_disk(mdfd, st, content, &devices[j].i);
 
                        if (rv) {
-                               pr_err("failed to add "
-                                      "%s to %s: %s\n",
+                               pr_err("failed to add %s to %s: %s\n",
                                       devices[j].devname,
                                       mddev,
                                       strerror(errno));
@@ -988,19 +1012,34 @@ static int start_array(int mdfd,
                } else if (c->verbose > 0 && i < content->array.raid_disks*2
                           && (i&1) == 0)
                        pr_err("no uptodate device for slot %d of %s\n",
-                              i, mddev);
+                              i/2, mddev);
        }
 
        if (content->array.level == LEVEL_CONTAINER) {
                if (c->verbose >= 0) {
-                       pr_err("Container %s has been "
-                              "assembled with %d drive%s",
+                       pr_err("Container %s has been assembled with %d drive%s",
                               mddev, okcnt+sparecnt, okcnt+sparecnt==1?"":"s");
                        if (okcnt < (unsigned)content->array.raid_disks)
                                fprintf(stderr, " (out of %d)",
                                        content->array.raid_disks);
                        fprintf(stderr, "\n");
                }
+
+               if (st->ss->validate_container) {
+                       struct mdinfo *devices_list;
+                       struct mdinfo *info_devices = xmalloc(sizeof(struct mdinfo)*(okcnt+sparecnt));
+                       unsigned int count;
+                       devices_list = NULL;
+                       for (count = 0; count < okcnt+sparecnt; count++) {
+                               info_devices[count] = devices[count].i;
+                               info_devices[count].next = devices_list;
+                               devices_list = &info_devices[count];
+                       }
+                       if (st->ss->validate_container(devices_list))
+                               pr_err("Mismatch detected!\n");
+                       free(info_devices);
+               }
+
                st->ss->free_super(st);
                sysfs_uevent(content, "change");
                if (err_ok && okcnt < (unsigned)content->array.raid_disks)
@@ -1044,7 +1083,7 @@ static int start_array(int mdfd,
                                           "array_state", "readonly");
                        if (rv == 0)
                                rv = Grow_continue(mdfd, st, content,
-                                                  c->backup_file,
+                                                  c->backup_file, 0,
                                                   c->freeze_reshape);
                } else if (c->readonly &&
                           sysfs_attribute_available(
@@ -1120,15 +1159,12 @@ static int start_array(int mdfd,
 
                if (!enough(content->array.level, content->array.raid_disks,
                            content->array.layout, 1, avail))
-                       pr_err("Not enough devices to "
-                              "start the array.\n");
+                       pr_err("Not enough devices to start the array.\n");
                else if (!enough(content->array.level,
                                 content->array.raid_disks,
                                 content->array.layout, clean,
                                 avail))
-                       pr_err("Not enough devices to "
-                              "start the array while not clean "
-                              "- consider --force.\n");
+                       pr_err("Not enough devices to start the array while not clean - consider --force.\n");
 
                return 1;
        }
@@ -1153,9 +1189,7 @@ static int start_array(int mdfd,
                                 content->array.raid_disks,
                                 content->array.layout, clean,
                                 avail))
-                       fprintf(stderr, " - not enough to start the "
-                               "array while not clean - consider "
-                               "--force.\n");
+                       fprintf(stderr, " - not enough to start the array while not clean - consider --force.\n");
                else {
                        if (req_cnt == (unsigned)content->array.raid_disks)
                                fprintf(stderr, " - need all %d to start it", req_cnt);
@@ -1317,7 +1351,10 @@ try_again:
         */
        if (map_lock(&map))
                pr_err("failed to get exclusive lock on mapfile - continue anyway...\n");
-       mp = map_by_uuid(&map, content->uuid);
+       if (c->update && strcmp(c->update,"uuid") == 0)
+               mp = NULL;
+       else
+               mp = map_by_uuid(&map, content->uuid);
        if (mp) {
                struct mdinfo *dv;
                /* array already exists. */
@@ -1520,9 +1557,7 @@ try_again:
                        if (i < content->array.raid_disks * 2) {
                                if (devices[j].i.recovery_start == MaxSector ||
                                    (content->reshape_active &&
-                                    ((i >= content->array.raid_disks - content->delta_disks) ||
-                                     (i >= content->array.raid_disks - content->delta_disks - 1
-                                      && content->array.level == 4)))) {
+                                    i >= content->array.raid_disks - content->delta_disks)) {
                                        if (!avail[i/2]) {
                                                okcnt++;
                                                avail[i/2]=1;
@@ -1677,9 +1712,10 @@ try_again:
                int err = 0;
                int *fdlist = xmalloc(sizeof(int)* bestcnt);
                if (c->verbose > 0)
-                       pr_err(":%s has an active reshape - checking "
-                              "if critical section needs to be restored\n",
+                       pr_err("%s has an active reshape - checking if critical section needs to be restored\n",
                               chosen_name);
+               if (!c->backup_file)
+                       c->backup_file = locate_backup(content->sys_name);
                enable_fds(bestcnt/2);
                for (i = 0; i < bestcnt/2; i++) {
                        int j = best[i*2];
@@ -1704,8 +1740,7 @@ try_again:
                                                   c->backup_file, c->verbose > 0);
                        if (err && c->invalid_backup) {
                                if (c->verbose > 0)
-                                       pr_err("continuing"
-                                              " without restoring backup\n");
+                                       pr_err("continuing without restoring backup\n");
                                err = 0;
                        }
                }
@@ -1791,7 +1826,7 @@ int assemble_container_content(struct supertype *st, int mdfd,
                               struct mdinfo *content, struct context *c,
                               char *chosen_name, int *result)
 {
-       struct mdinfo *dev, *sra;
+       struct mdinfo *dev, *sra, *dev2;
        int working = 0, preexist = 0;
        int expansion = 0;
        struct map_ent *map = NULL;
@@ -1802,7 +1837,7 @@ int assemble_container_content(struct supertype *st, int mdfd,
 
        sysfs_init(content, mdfd, NULL);
 
-       sra = sysfs_read(mdfd, NULL, GET_VERSION);
+       sra = sysfs_read(mdfd, NULL, GET_VERSION|GET_DEVS);
        if (sra == NULL || strcmp(sra->text_version, content->text_version) != 0) {
                if (content->array.major_version == -1 &&
                    content->array.minor_version == -2 &&
@@ -1829,8 +1864,22 @@ int assemble_container_content(struct supertype *st, int mdfd,
        if (st->ss->external && content->recovery_blocked && start_reshape)
                block_subarray(content);
 
-       if (sra)
-               sysfs_free(sra);
+       for (dev2 = sra->devs; dev2; dev2 = dev2->next) {
+               for (dev = content->devs; dev; dev = dev->next)
+                       if (dev2->disk.major == dev->disk.major &&
+                           dev2->disk.minor == dev->disk.minor)
+                               break;
+               if (dev)
+                       continue;
+               /* Don't want this one any more */
+               if (sysfs_set_str(sra, dev2, "slot", "none") < 0 &&
+                   errno == EBUSY) {
+                       pr_err("Cannot remove old device %s: not updating %s\n", dev2->sys_name, sra->sys_name);
+                       sysfs_free(sra);
+                       return 1;
+               }
+               sysfs_set_str(sra, dev2, "state", "remove");
+       }
        old_raid_disks = content->array.raid_disks - content->delta_disks;
        avail = xcalloc(content->array.raid_disks, 1);
        for (dev = content->devs; dev; dev = dev->next) {
@@ -1845,6 +1894,7 @@ int assemble_container_content(struct supertype *st, int mdfd,
                } else if (errno == EEXIST)
                        preexist++;
        }
+       sysfs_free(sra);
        if (working + expansion == 0 && c->runstop <= 0) {
                free(avail);
                return 1;/* Nothing new, don't try to start */
@@ -1892,7 +1942,7 @@ int assemble_container_content(struct supertype *st, int mdfd,
                int spare = content->array.raid_disks + expansion;
                if (restore_backup(st, content,
                                   working,
-                                  spare, c->backup_file, c->verbose) == 1)
+                                  spare, &c->backup_file, c->verbose) == 1)
                        return 1;
 
                err = sysfs_set_str(content, NULL,
@@ -1910,7 +1960,7 @@ int assemble_container_content(struct supertype *st, int mdfd,
                }
 
                err = Grow_continue(mdfd, st, content, c->backup_file,
-                                   c->freeze_reshape);
+                                   0, c->freeze_reshape);
        } else switch(content->array.level) {
                case LEVEL_LINEAR:
                case LEVEL_MULTIPATH: