]> git.ipfire.org Git - thirdparty/mdadm.git/blobdiff - Assemble.c
When assembly arrays using incomplete detail, prefer arrays built for this host.
[thirdparty/mdadm.git] / Assemble.c
index 480c512cd5cdfe06576b101987ce57b1e704bcf4..4516b62cc4d7f10a51f6cecea8f5ae3c48aa2384 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * mdadm - manage Linux "md" devices aka RAID arrays.
  *
- * Copyright (C) 2001-2002 Neil Brown <neilb@cse.unsw.edu.au>
+ * Copyright (C) 2001-2006 Neil Brown <neilb@suse.de>
  *
  *
  *    This program is free software; you can redistribute it and/or modify
 
 #include       "mdadm.h"
 
+static int name_matches(char *found, char *required, char *homehost)
+{
+       /* See if the name found matches the required name, possibly
+        * prefixed with 'homehost'
+        */
+       char fnd[33];
+
+       strncpy(fnd, found, 32);
+       fnd[32] = 0;
+       if (strcmp(found, required)==0)
+               return 1;
+       if (homehost) {
+               int l = strlen(homehost);
+               if (l < 32 && fnd[l] == ':' &&
+                   strcmp(fnd+l+1, required)==0)
+                       return 1;
+       }
+       return 0;
+}
+
 int Assemble(struct supertype *st, char *mddev, int mdfd,
             mddev_ident_t ident, char *conffile,
-            mddev_dev_t devlist,
+            mddev_dev_t devlist, char *backup_file,
             int readonly, int runstop,
-            char *update,
+            char *update, char *homehost,
             int verbose, int force)
 {
        /*
@@ -66,7 +86,7 @@ int Assemble(struct supertype *st, char *mddev, int mdfd,
         *
         * If !uuidset and scan, look in conf-file for uuid
         *       If not found, give up
-        * If !devlist and scan and uuidset, get list of devs from conf-file 
+        * If !devlist and scan and uuidset, get list of devs from conf-file
         *
         * For each device:
         *   Check superblock - discard if bad
@@ -113,11 +133,10 @@ int Assemble(struct supertype *st, char *mddev, int mdfd,
        int chosen_drive;
        int change = 0;
        int inargv = 0;
-       int start_partial_ok = force || devlist==NULL;
+       int start_partial_ok = (runstop >= 0) && (force || devlist==NULL);
        unsigned int num_devs;
        mddev_dev_t tmpdev;
        struct mdinfo info;
-       struct mddev_ident_s ident2;
        char *avail;
        int nextspare = 0;
        
@@ -174,15 +193,18 @@ int Assemble(struct supertype *st, char *mddev, int mdfd,
            fprintf(stderr, Name ": looking for devices for %s\n",
                    mddev);
 
-       while ( devlist) {
-               char *devname;
+       /* first walk the list of devices to find a consistent set
+        * that match the criterea, if that is possible.
+        * We flag the one we like with 'used'.
+        */
+       for (tmpdev = devlist;
+            tmpdev;
+            tmpdev = tmpdev->next) {
+               char *devname = tmpdev->devname;
                int dfd;
                struct stat stb;
                struct supertype *tst = st;
 
-               devname = devlist->devname;
-               devlist = devlist->next;
-
                if (ident->devices &&
                    !match_oneof(ident->devices, devname)) {
                        if ((inargv && verbose>=0) || verbose > 0)
@@ -215,7 +237,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, &ident2, super);
+                       tst->ss->getinfo_super(&info, super);
                }
                if (dfd >= 0) close(dfd);
 
@@ -226,8 +248,8 @@ int Assemble(struct supertype *st, char *mddev, int mdfd,
                                        devname);
                        continue;
                }
-               if (ident->name[0] &&
-                   (!super || strncmp(ident2.name, ident->name, 32)!=0)) {
+               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);
@@ -255,9 +277,11 @@ int Assemble(struct supertype *st, char *mddev, int mdfd,
                        continue;
                }
 
-               /* If we are this far, then we are commited to this device.
+               /* If we are this far, then we are nearly commited to this device.
                 * If the super_block doesn't exist, or doesn't match others,
-                * then we cannot continue
+                * then we probably cannot continue
+                * However if one of the arrays is for the homehost, and
+                * the other isn't that can disambiguate.
                 */
 
                if (!super) {
@@ -267,9 +291,37 @@ int Assemble(struct supertype *st, char *mddev, int mdfd,
                        return 1;
                }
 
-
-               st = tst; /* commit to this format, if haven't already */
-               if (st->ss->compare_super(&first_super, super)) {
+               if (st == NULL)
+                       st = tst;
+               if (st->ss != tst->ss ||
+                   st->minor_version != tst->minor_version ||
+                   st->ss->compare_super(&first_super, super) != 0) {
+                       /* Some mismatch. If exactly one array matches this host,
+                        * we can resolve on that one
+                        */
+                       if (homehost) {
+                               int first = st->ss->match_home(first_super, homehost);
+                               int last = tst->ss->match_home(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;
+                                       } else { /* reject all those sofar */
+                                               mddev_dev_t td;
+                                               if ((inargv && verbose >= 0) || verbose > 0)
+                                                       fprintf(stderr, Name ": %s overrides previous devices due to good homehost\n",
+                                                               devname);
+                                               for (td=devlist; td != tmpdev; td=td->next)
+                                                       if (td->used == 1)
+                                                               td->used = 0;
+                                               tmpdev->used = 1;
+                                               continue;
+                                       }
+                               }
+                       }
                        fprintf(stderr, Name ": superblock on %s doesn't match others - assembly aborted\n",
                                devname);
                        free(super);
@@ -277,12 +329,19 @@ int Assemble(struct supertype *st, char *mddev, int mdfd,
                        return 1;
                }
 
+               tmpdev->used = 1;
+       }
+
+       /* Ok, no bad inconsistancy, we can try updating etc */
+       for (tmpdev = devlist; tmpdev; tmpdev=tmpdev->next) if (tmpdev->used) {
+               char *devname = tmpdev->devname;
+               struct stat stb;
                /* looks like a good enough match to update the super block if needed */
                if (update) {
+                       int dfd;
                        /* prepare useful information in info structures */
                        struct stat stb2;
                        fstat(mdfd, &stb2);
-                       info.array.md_minor = minor(stb2.st_rdev);
 
                        if (strcmp(update, "uuid")==0 &&
                            !ident->uuid_set) {
@@ -295,13 +354,29 @@ int Assemble(struct supertype *st, char *mddev, int mdfd,
                                        *(__u32*)(ident->uuid+3) = random();
                                }
                                if (rfd >= 0) close(rfd);
-                               ident->uuid_set = 1;
                        }
-                       memcpy(info.uuid, ident->uuid, 16);
-                       st->ss->update_super(&info, super, update, devname, verbose);
-                       
                        dfd = dev_open(devname, O_RDWR|O_EXCL);
-                       if (dfd < 0) 
+
+                       if (super) {
+                               free(super);
+                               super = NULL;
+                       }
+
+                       st->ss->load_super(st, dfd, &super, NULL);
+                       st->ss->getinfo_super(&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,
+                                            ident->uuid_set, homehost);
+                       if (strcmp(update, "uuid")==0 &&
+                           !ident->uuid_set) {
+                               ident->uuid_set = 1;
+                               memcpy(ident->uuid, info.uuid, 16);
+                       }
+                       if (dfd < 0)
                                fprintf(stderr, Name ": Cannot open %s for superblock update\n",
                                        devname);
                        else if (st->ss->store_super(st, dfd, super))
@@ -309,8 +384,14 @@ int Assemble(struct supertype *st, char *mddev, int mdfd,
                                        devname);
                        if (dfd >= 0)
                                close(dfd);
+
+                       if (strcmp(update, "uuid")==0 &&
+                           ident->bitmap_fd)
+                               bitmap_update_uuid(ident->bitmap_fd, info.uuid);
                }
 
+               stat(devname, &stb);
+
                if (verbose > 0)
                        fprintf(stderr, Name ": %s is identified as a member of %s, slot %d.\n",
                                devname, mddev, info.disk.raid_disk);
@@ -329,7 +410,7 @@ int Assemble(struct supertype *st, char *mddev, int mdfd,
                            > devices[most_recent].events)
                                most_recent = devcnt;
                }
-               if (info.array.level == -4) 
+               if (info.array.level == -4)
                        /* with multipath, the raid_disk from the superblock is meaningless */
                        i = devcnt;
                else
@@ -374,7 +455,7 @@ int Assemble(struct supertype *st, char *mddev, int mdfd,
                return 1;
        }
 
-       st->ss->getinfo_super(&info, &ident2, first_super);
+       st->ss->getinfo_super(&info, first_super);
 
        /* now we have some devices that might be suitable.
         * I wonder how many
@@ -448,7 +529,7 @@ int Assemble(struct supertype *st, char *mddev, int mdfd,
                        continue;
                }
                info.events = devices[most_recent].events;
-               st->ss->update_super(&info, super, "force", devices[chosen_drive].devname, verbose);
+               st->ss->update_super(&info, super, "force", devices[chosen_drive].devname, verbose, 0, NULL);
 
                if (st->ss->store_super(st, fd, super)) {
                        close(fd);
@@ -500,7 +581,7 @@ int Assemble(struct supertype *st, char *mddev, int mdfd,
                fprintf(stderr, Name ": No suitable drives found for %s\n", mddev);
                return 1;
        }
-       st->ss->getinfo_super(&info, &ident2, super);
+       st->ss->getinfo_super(&info, super);
        for (i=0; i<bestcnt; i++) {
                int j = best[i];
                unsigned int desired_state;
@@ -519,7 +600,7 @@ 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)) {
+                   st->ss->update_super(&info, super, "assemble", NULL, verbose, 0, NULL)) {
                        if (force) {
                                if (verbose >= 0)
                                        fprintf(stderr, Name ": "
@@ -543,8 +624,8 @@ int Assemble(struct supertype *st, char *mddev, int mdfd,
        }
        if (force && okcnt == info.array.raid_disks-1) {
                /* FIXME check event count */
-               change += st->ss->update_super(&info, super, "force", 
-                                       devices[chosen_drive].devname, verbose);
+               change += st->ss->update_super(&info, super, "force",
+                                       devices[chosen_drive].devname, verbose, 0, NULL);
        }
 
        if (change) {
@@ -568,6 +649,7 @@ int Assemble(struct supertype *st, char *mddev, int mdfd,
         * that was moved aside due to the reshape overwriting live data
         * The code of doing this lives in Grow.c
         */
+#ifndef MDASSEMBLE
        if (info.reshape_active) {
                int err = 0;
                int *fdlist = malloc(sizeof(int)* bestcnt);
@@ -585,7 +667,7 @@ int Assemble(struct supertype *st, char *mddev, int mdfd,
                                fdlist[i] = -1;
                }
                if (!err)
-                       err = Grow_restart(st, &info, fdlist, bestcnt);
+                       err = Grow_restart(st, &info, fdlist, bestcnt, backup_file);
                while (i>0) {
                        i--;
                        if (fdlist[i]>=0) close(fdlist[i]);
@@ -595,6 +677,7 @@ int Assemble(struct supertype *st, char *mddev, int mdfd,
                        return err;
                }
        }
+#endif
        /* count number of in-sync devices according to the superblock.
         * We must have this number to start the array without -s or -R
         */
@@ -609,7 +692,7 @@ int Assemble(struct supertype *st, char *mddev, int mdfd,
                        inf.major_version = st->ss->major;
                        inf.minor_version = st->minor_version;
                        rv = ioctl(mdfd, SET_ARRAY_INFO, &inf);
-               } else 
+               } else
                        rv = ioctl(mdfd, SET_ARRAY_INFO, NULL);
 
                if (rv) {
@@ -622,8 +705,22 @@ int Assemble(struct supertype *st, char *mddev, int mdfd,
                                fprintf(stderr, Name ": SET_BITMAP_FILE failed.\n");
                                return 1;
                        }
+               } else if (ident->bitmap_file) {
+                       /* From config file */
+                       int bmfd = open(ident->bitmap_file, O_RDWR);
+                       if (bmfd < 0) {
+                               fprintf(stderr, Name ": Could not open bitmap file %s\n",
+                                       ident->bitmap_file);
+                               return 1;
+                       }
+                       if (ioctl(mdfd, SET_BITMAP_FILE, bmfd) != 0) {
+                               fprintf(stderr, Name ": Failed to set bitmapfile for %s\n", mddev);
+                               close(bmfd);
+                               return 1;
+                       }
+                       close(bmfd);
                }
-                                       
+
                /* First, add the raid disks, but add the chosen one last */
                for (i=0; i<= bestcnt; i++) {
                        int j;
@@ -657,7 +754,7 @@ int Assemble(struct supertype *st, char *mddev, int mdfd,
                }
                
                if (runstop == 1 ||
-                   (runstop == 0 && 
+                   (runstop <= 0 &&
                     ( enough(info.array.level, info.array.raid_disks, info.array.layout, avail, okcnt) &&
                       (okcnt >= req_cnt || start_partial_ok)
                             ))) {
@@ -665,7 +762,7 @@ int Assemble(struct supertype *st, char *mddev, int mdfd,
                                if (verbose >= 0) {
                                        fprintf(stderr, Name ": %s has been started with %d drive%s",
                                                mddev, okcnt, okcnt==1?"":"s");
-                                       if (okcnt < info.array.raid_disks) 
+                                       if (okcnt < info.array.raid_disks)
                                                fprintf(stderr, " (out of %d)", info.array.raid_disks);
                                        if (sparecnt)
                                                fprintf(stderr, " and %d spare%s", sparecnt, sparecnt==1?"":"s");
@@ -678,8 +775,11 @@ int Assemble(struct supertype *st, char *mddev, int mdfd,
                        return 1;
                }
                if (runstop == -1) {
-                       fprintf(stderr, Name ": %s assembled from %d drive%s, but not started.\n",
+                       fprintf(stderr, Name ": %s assembled from %d drive%s",
                                mddev, okcnt, okcnt==1?"":"s");
+                       if (okcnt != info.array.raid_disks)
+                               fprintf(stderr, " (out of %d)", info.array.raid_disks);
+                       fprintf(stderr, ", but not started.\n");
                        return 0;
                }
                if (verbose >= 0) {