]> git.ipfire.org Git - thirdparty/mdadm.git/blobdiff - Assemble.c
Add 'supertype' arg to almost all metadata methods.
[thirdparty/mdadm.git] / Assemble.c
index 23e3583069e54b73480e11df612d9c49e81aaa89..7837b19bf4f2c61924eeacd3f58568cebffd1278 100644 (file)
@@ -111,6 +111,7 @@ int Assemble(struct supertype *st, char *mddev, int mdfd,
         *    START_ARRAY
         *
         */
+       int clean = 0;
        int must_close = 0;
        int old_linux = 0;
        int vers = 0; /* Keep gcc quite - it really is initialised */
@@ -135,6 +136,7 @@ int Assemble(struct supertype *st, char *mddev, int mdfd,
        int chosen_drive;
        int change = 0;
        int inargv = 0;
+       int bitmap_done;
        int start_partial_ok = (runstop >= 0) && (force || devlist==NULL || mdfd < 0);
        unsigned int num_devs;
        mddev_dev_t tmpdev;
@@ -224,11 +226,6 @@ int Assemble(struct supertype *st, char *mddev, int mdfd,
                        continue;
                }
 
-               if (super) {
-                       free(super);
-                       super = NULL;
-               }
-               
                dfd = dev_open(devname, O_RDONLY|O_EXCL);
                if (dfd < 0) {
                        if ((inargv && verbose >= 0) || verbose > 0)
@@ -254,7 +251,7 @@ int Assemble(struct supertype *st, char *mddev, int mdfd,
                                fprintf( stderr, Name ": no RAID superblock on %s\n",
                                         devname);
                } else {
-                       tst->ss->getinfo_super(&info, super);
+                       tst->ss->getinfo_super(tst, &info, super);
                }
                if (dfd >= 0) close(dfd);
 
@@ -263,48 +260,48 @@ int Assemble(struct supertype *st, char *mddev, int mdfd,
                        if ((inargv && verbose >= 0) || verbose > 0)
                                fprintf(stderr, Name ": %s has wrong uuid.\n",
                                        devname);
-                       continue;
+                       goto loop;
                }
                if (ident->name[0] && (!update || strcmp(update, "name")!= 0) &&
                    (!super || name_matches(info.name, ident->name, homehost)==0)) {
                        if ((inargv && verbose >= 0) || verbose > 0)
                                fprintf(stderr, Name ": %s has wrong name.\n",
                                        devname);
-                       continue;
+                       goto loop;
                }
                if (ident->super_minor != UnSet &&
                    (!super || ident->super_minor != info.array.md_minor)) {
                        if ((inargv && verbose >= 0) || verbose > 0)
                                fprintf(stderr, Name ": %s has wrong super-minor.\n",
                                        devname);
-                       continue;
+                       goto loop;
                }
                if (ident->level != UnSet &&
                    (!super|| ident->level != info.array.level)) {
                        if ((inargv && verbose >= 0) || verbose > 0)
                                fprintf(stderr, Name ": %s has wrong raid level.\n",
                                        devname);
-                       continue;
+                       goto loop;
                }
                if (ident->raid_disks != UnSet &&
                    (!super || ident->raid_disks!= info.array.raid_disks)) {
                        if ((inargv && verbose >= 0) || verbose > 0)
                                fprintf(stderr, Name ": %s requires wrong number of drives.\n",
                                        devname);
-                       continue;
+                       goto loop;
                }
                if (mdfd < 0) {
                        if (tst == NULL || super == NULL)
                                continue;
                        if (update == NULL &&
-                           tst->ss->match_home(super, homehost)==0) {
+                           tst->ss->match_home(tst, super, homehost)==0) {
                                if ((inargv && verbose >= 0) || verbose > 0)
                                        fprintf(stderr, Name ": %s is not built for host %s.\n",
                                                devname, homehost);
                                /* Auto-assemble, and this is not a usable host */
                                /* if update != NULL, we are updating the host
                                 * name... */
-                               continue;
+                               goto loop;
                        }
                }
                /* If we are this far, then we are nearly commited to this device.
@@ -317,7 +314,7 @@ int Assemble(struct supertype *st, char *mddev, int mdfd,
                if (!super) {
                        fprintf(stderr, Name ": %s has no superblock - assembly aborted\n",
                                devname);
-                       free(first_super);
+                       st->ss->free_super(st, first_super);
                        return 1;
                }
 
@@ -332,17 +329,19 @@ int Assemble(struct supertype *st, char *mddev, int mdfd,
                         * for now.
                         */
                        if (mdfd < 0)
-                               continue;
+                               goto loop;
                        if (homehost) {
-                               int first = st->ss->match_home(first_super, homehost);
-                               int last = tst->ss->match_home(super, homehost);
+                               int first = st->ss->match_home(st, first_super,
+                                                              homehost);
+                               int last = tst->ss->match_home(tst, super,
+                                                              homehost);
                                if (first+last == 1) {
                                        /* We can do something */
                                        if (first) {/* just ignore this one */
                                                if ((inargv && verbose >= 0) || verbose > 0)
                                                        fprintf(stderr, Name ": %s misses out due to wrong homehost\n",
                                                                devname);
-                                               continue;
+                                               goto loop;
                                        } else { /* reject all those sofar */
                                                mddev_dev_t td;
                                                if ((inargv && verbose >= 0) || verbose > 0)
@@ -352,18 +351,23 @@ int Assemble(struct supertype *st, char *mddev, int mdfd,
                                                        if (td->used == 1)
                                                                td->used = 0;
                                                tmpdev->used = 1;
-                                               continue;
+                                               goto loop;
                                        }
                                }
                        }
                        fprintf(stderr, Name ": superblock on %s doesn't match others - assembly aborted\n",
                                devname);
-                       free(super);
-                       free(first_super);
+                       tst->ss->free_super(tst, super);
+                       st->ss->free_super(st, first_super);
                        return 1;
                }
 
                tmpdev->used = 1;
+
+       loop:
+               if (super)
+                       tst->ss->free_super(tst, super);
+               super = NULL;
        }
 
        if (mdfd < 0) {
@@ -376,7 +380,7 @@ int Assemble(struct supertype *st, char *mddev, int mdfd,
                if (!first_super) {
                        return 2;
                }
-               st->ss->getinfo_super(&info, first_super);
+               st->ss->getinfo_super(st, &info, first_super);
                c = strchr(info.name, ':');
                if (c) c++; else c= info.name;
                if (isdigit(*c) && ((ident->autof & 7)==4 || (ident->autof&7)==6))
@@ -386,7 +390,7 @@ int Assemble(struct supertype *st, char *mddev, int mdfd,
                        asprintf(&mddev, "/dev/md/%s", c);
                mdfd = open_mddev(mddev, ident->autof);
                if (mdfd < 0) {
-                       free(first_super);
+                       st->ss->free_super(st, first_super);
                        free(devices);
                        first_super = NULL;
                        goto try_again;
@@ -403,7 +407,7 @@ int Assemble(struct supertype *st, char *mddev, int mdfd,
                                        mddev, tmpdev->devname);
                        close(mdfd);
                        mdfd = -1;
-                       free(first_super);
+                       st->ss->free_super(st, first_super);
                        free(devices);
                        first_super = NULL;
                        goto try_again;
@@ -412,6 +416,7 @@ int Assemble(struct supertype *st, char *mddev, int mdfd,
        }
 
        /* Ok, no bad inconsistancy, we can try updating etc */
+       bitmap_done = 0;
        for (tmpdev = devlist; tmpdev; tmpdev=tmpdev->next) if (tmpdev->used == 1) {
                char *devname = tmpdev->devname;
                struct stat stb;
@@ -439,19 +444,15 @@ int Assemble(struct supertype *st, char *mddev, int mdfd,
 
                        remove_partitions(dfd);
 
-                       if (super) {
-                               free(super);
-                               super = NULL;
-                       }
-
                        st->ss->load_super(st, dfd, &super, NULL);
-                       st->ss->getinfo_super(&info, super);
+                       st->ss->getinfo_super(st, &info, super);
 
                        memcpy(info.uuid, ident->uuid, 16);
                        strcpy(info.name, ident->name);
                        info.array.md_minor = minor(stb2.st_rdev);
 
-                       st->ss->update_super(&info, super, update, devname, verbose,
+                       st->ss->update_super(st, &info, super, update,
+                                            devname, verbose,
                                             ident->uuid_set, homehost);
                        if (strcmp(update, "uuid")==0 &&
                            !ident->uuid_set) {
@@ -468,10 +469,12 @@ int Assemble(struct supertype *st, char *mddev, int mdfd,
                                close(dfd);
 
                        if (strcmp(update, "uuid")==0 &&
-                           ident->bitmap_fd)
-                               if (bitmap_update_uuid(ident->bitmap_fd, info.uuid) != 0)
-                                       fprintf(stderr, Name ": Could not update uuid on %s.\n",
-                                               devname);
+                           ident->bitmap_fd >= 0 && !bitmap_done) {
+                               if (bitmap_update_uuid(ident->bitmap_fd, info.uuid, st->ss->swapuuid) != 0)
+                                       fprintf(stderr, Name ": Could not update uuid on external bitmap.\n");
+                               else
+                                       bitmap_done = 1;
+                       }
                } else
 #endif
                {
@@ -480,13 +483,8 @@ int Assemble(struct supertype *st, char *mddev, int mdfd,
 
                        remove_partitions(dfd);
 
-                       if (super) {
-                               free(super);
-                               super = NULL;
-                       }
-
                        st->ss->load_super(st, dfd, &super, NULL);
-                       st->ss->getinfo_super(&info, super);
+                       st->ss->getinfo_super(st, &info, super);
                        close(dfd);
                }
 
@@ -565,11 +563,11 @@ int Assemble(struct supertype *st, char *mddev, int mdfd,
                                best[i] = devcnt;
                }
                devcnt++;
-       }
 
-       if (super)
-               free(super);
-       super = NULL;
+               if (super)
+                       st->ss->free_super(st, super);
+               super = NULL;
+       }
 
        if (update && strcmp(update, "byteorder")==0)
                st->minor_version = 90;
@@ -577,12 +575,13 @@ int Assemble(struct supertype *st, char *mddev, int mdfd,
        if (devcnt == 0) {
                fprintf(stderr, Name ": no devices found for %s\n",
                        mddev);
-               free(first_super);
+               st->ss->free_super(st, first_super);
                if (must_close) close(mdfd);
                return 1;
        }
 
-       st->ss->getinfo_super(&info, first_super);
+       st->ss->getinfo_super(st, &info, first_super);
+       clean = info.array.state & 1;
 
        /* now we have some devices that might be suitable.
         * I wonder how many
@@ -617,13 +616,14 @@ int Assemble(struct supertype *st, char *mddev, int mdfd,
                }
        }
        while (force && !enough(info.array.level, info.array.raid_disks,
-                               info.array.layout,
+                               info.array.layout, 1,
                                avail, okcnt)) {
                /* Choose the newest best drive which is
                 * not up-to-date, update the superblock
                 * and add it.
                 */
                int fd;
+               long long current_events;
                chosen_drive = -1;
                for (i=0; i<info.array.raid_disks && i < bestcnt; i++) {
                        int j = best[i];
@@ -636,6 +636,8 @@ int Assemble(struct supertype *st, char *mddev, int mdfd,
                }
                if (chosen_drive < 0)
                        break;
+               current_events = devices[chosen_drive].events;
+       add_another:
                if (verbose >= 0)
                        fprintf(stderr, Name ": forcing event count in %s(%d) from %d upto %d\n",
                                devices[chosen_drive].devname, devices[chosen_drive].raid_disk,
@@ -656,7 +658,7 @@ int Assemble(struct supertype *st, char *mddev, int mdfd,
                        continue;
                }
                info.events = devices[most_recent].events;
-               st->ss->update_super(&info, super, "force-one",
+               st->ss->update_super(st, &info, super, "force-one",
                                     devices[chosen_drive].devname, verbose,
                                     0, NULL);
 
@@ -665,7 +667,7 @@ int Assemble(struct supertype *st, char *mddev, int mdfd,
                        fprintf(stderr, Name ": Could not re-write superblock on %s\n",
                                devices[chosen_drive].devname);
                        devices[chosen_drive].events = 0;
-                       free(super);
+                       st->ss->free_super(st, super);
                        continue;
                }
                close(fd);
@@ -673,7 +675,21 @@ int Assemble(struct supertype *st, char *mddev, int mdfd,
                devices[chosen_drive].uptodate = 1;
                avail[chosen_drive] = 1;
                okcnt++;
-               free(super);
+               st->ss->free_super(st, super);
+
+               /* If there are any other drives of the same vintage,
+                * add them in as well.  We can't lose and we might gain
+                */
+               for (i=0; i<info.array.raid_disks && i < bestcnt ; i++) {
+                       int j = best[i];
+                       if (j >= 0 &&
+                           !devices[j].uptodate &&
+                           devices[j].events > 0 &&
+                           devices[j].events == current_events) {
+                               chosen_drive = j;
+                               goto add_another;
+                       }
+               }
        }
 
        /* Now we want to look at the superblock which the kernel will base things on
@@ -713,7 +729,7 @@ int Assemble(struct supertype *st, char *mddev, int mdfd,
                if (must_close) close(mdfd);
                return 1;
        }
-       st->ss->getinfo_super(&info, super);
+       st->ss->getinfo_super(st, &info, super);
        for (i=0; i<bestcnt; i++) {
                int j = best[i];
                unsigned int desired_state;
@@ -732,7 +748,8 @@ int Assemble(struct supertype *st, char *mddev, int mdfd,
                info.disk.state = desired_state;
 
                if (devices[j].uptodate &&
-                   st->ss->update_super(&info, super, "assemble", NULL, verbose, 0, NULL)) {
+                   st->ss->update_super(st, &info, super, "assemble", NULL,
+                                        verbose, 0, NULL)) {
                        if (force) {
                                if (verbose >= 0)
                                        fprintf(stderr, Name ": "
@@ -754,10 +771,14 @@ int Assemble(struct supertype *st, char *mddev, int mdfd,
                }
 #endif
        }
-       if (force && okcnt < info.array.raid_disks) {
-               change += st->ss->update_super(&info, super, "force-array",
+       if (force && !clean &&
+           !enough(info.array.level, info.array.raid_disks,
+                   info.array.layout, clean,
+                   avail, okcnt)) {
+               change += st->ss->update_super(st, &info, super, "force-array",
                                        devices[chosen_drive].devname, verbose,
                                               0, NULL);
+               clean = 1;
        }
 
        if (change) {
@@ -891,10 +912,11 @@ int Assemble(struct supertype *st, char *mddev, int mdfd,
                                fprintf(stderr, Name ": no uptodate device for slot %d of %s\n",
                                        i, mddev);
                }
-               
+
                if (runstop == 1 ||
                    (runstop <= 0 &&
-                    ( enough(info.array.level, info.array.raid_disks, info.array.layout, avail, okcnt) &&
+                    ( enough(info.array.level, info.array.raid_disks,
+                             info.array.layout, clean, avail, okcnt) &&
                       (okcnt >= req_cnt || start_partial_ok)
                             ))) {
                        if (ioctl(mdfd, RUN_ARRAY, NULL)==0) {
@@ -923,8 +945,8 @@ int Assemble(struct supertype *st, char *mddev, int mdfd,
                                        while (usecs < 1000) {
                                                mdfd = open(mddev, O_RDONLY);
                                                if (mdfd >= 0) {
-                                                       unsigned long size;
-                                                       if (ioctl(mdfd, BLKGETSIZE, &size) == 0 &&
+                                                       unsigned long long size;
+                                                       if (get_dev_size(mdfd, NULL, &size) &&
                                                            size > 0)
                                                                break;
                                                        close(mdfd);
@@ -937,6 +959,19 @@ int Assemble(struct supertype *st, char *mddev, int mdfd,
                        }
                        fprintf(stderr, Name ": failed to RUN_ARRAY %s: %s\n",
                                mddev, strerror(errno));
+
+                       if (!enough(info.array.level, info.array.raid_disks,
+                                   info.array.layout, 1, avail, okcnt))
+                               fprintf(stderr, Name ": Not enough devices to "
+                                       "start the array.\n");
+                       else if (!enough(info.array.level,
+                                        info.array.raid_disks,
+                                        info.array.layout, clean,
+                                        avail, okcnt))
+                               fprintf(stderr, Name ": Not enough devices to "
+                                       "start the array while not clean "
+                                       "- consider --force.\n");
+
                        if (must_close) close(mdfd);
                        return 1;
                }
@@ -949,12 +984,20 @@ int Assemble(struct supertype *st, char *mddev, int mdfd,
                        if (must_close) close(mdfd);
                        return 0;
                }
-               if (verbose >= 0) {
+               if (verbose >= -1) {
                        fprintf(stderr, Name ": %s assembled from %d drive%s", mddev, okcnt, okcnt==1?"":"s");
                        if (sparecnt)
                                fprintf(stderr, " and %d spare%s", sparecnt, sparecnt==1?"":"s");
-                       if (!enough(info.array.level, info.array.raid_disks, info.array.layout, avail, okcnt))
+                       if (!enough(info.array.level, info.array.raid_disks,
+                                   info.array.layout, 1, avail, okcnt))
                                fprintf(stderr, " - not enough to start the array.\n");
+                       else if (!enough(info.array.level,
+                                        info.array.raid_disks,
+                                        info.array.layout, clean,
+                                        avail, okcnt))
+                               fprintf(stderr, " - not enough to start the "
+                                       "array while not clean - consider "
+                                       "--force.\n");
                        else {
                                if (req_cnt == info.array.raid_disks)
                                        fprintf(stderr, " - need all %d to start it", req_cnt);
@@ -977,7 +1020,7 @@ int Assemble(struct supertype *st, char *mddev, int mdfd,
                    fprintf(stderr, Name ": Cannot start array: %s\n",
                            strerror(errno));
                }
-               
+
        }
        if (must_close) close(mdfd);
        return 0;