]> git.ipfire.org Git - thirdparty/mdadm.git/blobdiff - Assemble.c
imsm: simplified multiple OROMs support
[thirdparty/mdadm.git] / Assemble.c
index 7e8e7957035239eae63f20debcf2b615186e0d9c..1e529c1b3126797d216a9c369a3aa8c801a001ef 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
@@ -551,7 +553,7 @@ struct devs {
 };
 
 static int load_devices(struct devs *devices, char *devmap,
-                       struct mddev_ident *ident, struct supertype *st,
+                       struct mddev_ident *ident, struct supertype **stp,
                        struct mddev_dev *devlist, struct context *c,
                        struct mdinfo *content,
                        int mdfd, char *mddev,
@@ -567,21 +569,22 @@ static int load_devices(struct devs *devices, char *devmap,
        int most_recent = -1;
        int bestcnt = 0;
        int *best = *bestp;
+       struct supertype *st = *stp;
 
        for (tmpdev = devlist; tmpdev; tmpdev=tmpdev->next) {
                char *devname = tmpdev->devname;
                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;
-                       struct supertype *tst;
                        int err;
                        fstat(mdfd, &stb2);
 
@@ -610,6 +613,9 @@ static int load_devices(struct devs *devices, char *devmap,
                                close(mdfd);
                                free(devices);
                                free(devmap);
+                               tst->ss->free_super(tst);
+                               free(tst);
+                               *stp = st;
                                return -1;
                        }
                        tst->ss->getinfo_super(tst, content, devmap + devcnt * content->array.raid_disks);
@@ -627,8 +633,7 @@ static int load_devices(struct devs *devices, char *devmap,
                                                            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);
@@ -636,6 +641,7 @@ static int load_devices(struct devs *devices, char *devmap,
                                close(dfd);
                                free(devices);
                                free(devmap);
+                               *stp = st;
                                return -1;
                        }
                        if (strcmp(c->update, "uuid")==0 &&
@@ -646,7 +652,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) {
@@ -657,15 +662,13 @@ static int load_devices(struct devs *devices, char *devmap,
                                else
                                        bitmap_done = 1;
                        }
-                       tst->ss->free_super(tst);
                } else
 #endif
                {
-                       struct supertype *tst = dup_super(st);
-                       int dfd;
                        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) {
                                pr_err("cannot re-read metadata from %s - aborting\n",
@@ -675,14 +678,16 @@ static int load_devices(struct devs *devices, char *devmap,
                                close(mdfd);
                                free(devices);
                                free(devmap);
+                               tst->ss->free_super(tst);
+                               free(tst);
+                               *stp = st;
                                return -1;
                        }
                        tst->ss->getinfo_super(tst, content, devmap + devcnt * content->array.raid_disks);
-                       tst->ss->free_super(tst);
-                       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",
@@ -698,9 +703,15 @@ static int load_devices(struct devs *devices, char *devmap,
                if (devices[devcnt].i.disk.state == 6) {
                        if (most_recent < 0 ||
                            devices[devcnt].i.events
-                           > devices[most_recent].i.events)
+                           > devices[most_recent].i.events) {
+                               struct supertype *tmp = tst;
+                               tst = st;
+                               st = tmp;
                                most_recent = devcnt;
+                       }
                }
+               tst->ss->free_super(tst);
+               free(tst);
 
                if (content->array.level == LEVEL_MULTIPATH)
                        /* with multipath, the raid_disk from the superblock is meaningless */
@@ -746,12 +757,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"
@@ -759,6 +767,7 @@ static int load_devices(struct devs *devices, char *devmap,
                                close(mdfd);
                                free(devices);
                                free(devmap);
+                               *stp = st;
                                return -1;
                        }
                        if (best[i] == -1
@@ -772,6 +781,7 @@ static int load_devices(struct devs *devices, char *devmap,
                *most_recentp = most_recent;
        *bestcntp = bestcnt;
        *bestp = best;
+       *stp = st;
        return devcnt;
 }
 
@@ -950,8 +960,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));
@@ -980,16 +989,35 @@ static int start_array(int mdfd,
 
        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)
+                       /* Was partial, is still partial, so signal an error
+                        * to ensure we don't retry */
+                       return 1;
                return 0;
        }
 
@@ -1027,7 +1055,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(
@@ -1103,15 +1131,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;
        }
@@ -1136,9 +1161,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);
@@ -1428,7 +1451,7 @@ try_again:
        /* Ok, no bad inconsistancy, we can try updating etc */
        devices = xcalloc(num_devs, sizeof(*devices));
        devmap = xcalloc(num_devs, content->array.raid_disks);
-       devcnt = load_devices(devices, devmap, ident, st, devlist,
+       devcnt = load_devices(devices, devmap, ident, &st, devlist,
                              c, content, mdfd, mddev,
                              &most_recent, &bestcnt, &best, inargv);
        if (devcnt < 0)
@@ -1660,9 +1683,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];
@@ -1687,8 +1711,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;
                        }
                }
@@ -1774,7 +1797,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;
@@ -1785,7 +1808,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 &&
@@ -1812,8 +1835,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) {
@@ -1828,6 +1865,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 */
@@ -1875,7 +1913,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,
@@ -1893,7 +1931,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: