When assembly arrays using incomplete detail, prefer arrays built for this host.
authorNeil Brown <neilb@suse.de>
Tue, 23 May 2006 06:33:28 +0000 (06:33 +0000)
committerNeil Brown <neilb@suse.de>
Tue, 23 May 2006 06:33:28 +0000 (06:33 +0000)
i.e. if assembling with --name or --super-minor, then if we find two
different arrays with the same apparent identity, and one was built
for 'this' host, then prefer that one instead of giving up in disgust.

Signed-off-by: Neil Brown <neilb@suse.de>
Assemble.c
mdadm.h
super0.c
super1.c

index ecee624..4516b62 100644 (file)
@@ -277,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) {
@@ -289,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);
diff --git a/mdadm.h b/mdadm.h
index 94e4708..7fc3bed 100644 (file)
--- a/mdadm.h
+++ b/mdadm.h
@@ -279,6 +279,7 @@ extern struct superswitch {
        void (*brief_detail_super)(void *sbv);
        void (*uuid_from_super)(int uuid[4], void *sbv);
        void (*getinfo_super)(struct mdinfo *info, void *sbv);
+       int (*match_home)(void *sbv, char *homehost);
        int (*update_super)(struct mdinfo *info, void *sbv, char *update,
                            char *devname, int verbose,
                            int uuid_set, char *homehost);
index 85e54fc..cc2f7a9 100644 (file)
--- a/super0.c
+++ b/super0.c
@@ -269,6 +269,17 @@ static void brief_detail_super0(void *sbv)
                printf("%08x", sb->set_uuid0);
 }
 #endif
+
+static int match_home0(void *sbv, char *homehost)
+{
+       mdp_super_t *sb = sbv;
+       unsigned char *hash = SHA1((unsigned char *)homehost,
+                                  strlen(homehost),
+                                  NULL);
+
+       return (memcmp(&sb->set_uuid2, hash, 8)==0);
+}
+
 static void uuid_from_super0(int uuid[4], void * sbv)
 {
        mdp_super_t *super = sbv;
@@ -942,6 +953,7 @@ struct superswitch super0 = {
        .detail_super = detail_super0,
        .brief_detail_super = brief_detail_super0,
 #endif
+       .match_home = match_home0,
        .uuid_from_super = uuid_from_super0,
        .getinfo_super = getinfo_super0,
        .update_super = update_super0,
index b24bcea..488aabe 100644 (file)
--- a/super1.c
+++ b/super1.c
@@ -357,6 +357,16 @@ static void brief_detail_super1(void *sbv)
 
 #endif
 
+static int match_home1(void *sbv, char *homehost)
+{
+       struct mdp_superblock_1 *sb = sbv;
+       int l = homehost ? strlen(homehost) : 0;
+
+       return (l > 0 && l < 32 &&
+               sb->set_name[l] == ':' &&
+               strncmp(sb->set_name, homehost, l) == 0);
+}
+
 static void uuid_from_super1(int uuid[4], void * sbv)
 {
        struct mdp_superblock_1 *super = sbv;
@@ -1191,6 +1201,7 @@ struct superswitch super1 = {
        .detail_super = detail_super1,
        .brief_detail_super = brief_detail_super1,
 #endif
+       .match_home = match_home1,
        .uuid_from_super = uuid_from_super1,
        .getinfo_super = getinfo_super1,
        .update_super = update_super1,