Assemble: allow members of containers to be assembled and auto-assembled.
authorNeilBrown <neilb@suse.de>
Tue, 4 Nov 2008 09:51:12 +0000 (20:51 +1100)
committerNeilBrown <neilb@suse.de>
Tue, 4 Nov 2008 09:51:12 +0000 (20:51 +1100)
Try to treat members of containers much like other arrays for
assembly.
We still look through the list of devices for a match (it will be
the container), then find the relevant 'info' and try to assemble
the array.

Signed-off-by: NeilBrown <neilb@suse.de>
Assemble.c
config.c
mdadm.c
mdadm.h
util.c

index b152ebe..e421f22 100644 (file)
@@ -50,7 +50,7 @@ static int name_matches(char *found, char *required, char *homehost)
        return 0;
 }
 
-/*static */ int is_member_busy(char *metadata_version)
+static int is_member_busy(char *metadata_version)
 {
        /* check if the given member array is active */
        struct mdstat_ent *mdstat = mdstat_read(1, 0);
@@ -273,6 +273,62 @@ int Assemble(struct supertype *st, char *mddev,
                }
                if (dfd >= 0) close(dfd);
 
+               if (tst && tst->sb && tst->ss->container_content
+                   && tst->loaded_container) {
+                       /* tmpdev is a container.  We need to be either
+                        * looking for a member, or auto-assembling
+                        */
+                       if (st) {
+                               /* already found some components, this cannot
+                                * be another one.
+                                */
+                               if (report_missmatch)
+                                       fprintf(stderr, Name ": %s is a container, but we are looking for components\n",
+                                               devname);
+                               goto loop;
+                       }
+
+                       if (ident->container) {
+                               if (ident->container[0] == '/' &&
+                                   !same_dev(ident->container, devname)) {
+                                       if (report_missmatch)
+                                               fprintf(stderr, Name ": %s is not the container required (%s)\n",
+                                                       devname, ident->container);
+                                       goto loop;
+                               }
+                               if (ident->container[0] != '/') {
+                                       /* we have a uuid */
+                                       int uuid[4];
+                                       if (!parse_uuid(ident->container, uuid) ||
+                                           !same_uuid(content->uuid, uuid, tst->ss->swapuuid)) {
+                                               if (report_missmatch)
+                                                       fprintf(stderr, Name ": %s has wrong UUID to be required container\n",
+                                                               devname);
+                                               goto loop;
+                                       }
+                               }
+                       }
+                       /* It is worth looking inside this container.
+                        */
+               next_member:
+                       if (tmpdev->content)
+                               content = tmpdev->content;
+                       else
+                               content = tst->ss->container_content(tst);
+
+                       tmpdev->content = content->next;
+                       if (tmpdev->content == NULL)
+                               tmpdev->used = 1;
+
+               } else if (ident->container || ident->member) {
+                       /* No chance of this matching if we don't have
+                        * a container */
+                       if (report_missmatch)
+                               fprintf(stderr, Name "%s is not a container, and one is required.\n",
+                                       devname);
+                       goto loop;
+               }
+
                if (ident->uuid_set && (!update || strcmp(update, "uuid")!= 0) &&
                    (!tst || !tst->sb ||
                     same_uuid(content->uuid, ident->uuid, tst->ss->swapuuid)==0)) {
@@ -332,6 +388,30 @@ int Assemble(struct supertype *st, char *mddev,
                        return 1;
                }
 
+               if (tst && tst->sb && tst->ss->container_content
+                   && tst->loaded_container) {
+                       /* we have the one container we need, don't keep
+                        * looking.  If the chosen member is active, skip.
+                        */
+                       if (is_member_busy(content->text_version)) {
+                               if (auto_assem)
+                                       goto loop;
+                               fprintf(stderr, Name ": member %s in %s is already assembled\n",
+                                       content->text_version,
+                                       devname);
+                               tst->ss->free_super(tst);
+                               return 1;
+                       }
+                       st = tst; tst = NULL;
+                       if (!auto_assem && tmpdev->next != NULL) {
+                               fprintf(stderr, Name ": %s is a container, but is not "
+                                       "only device given: confused and aborting\n",
+                                       devname);
+                               st->ss->free_super(st);
+                               return 1;
+                       }
+                       break;
+               }
                if (st == NULL)
                        st = dup_super(tst);
                if (st->minor_version == -1)
@@ -380,6 +460,8 @@ int Assemble(struct supertype *st, char *mddev,
                tmpdev->used = 1;
 
        loop:
+               if (tmpdev->content)
+                       goto next_member;
                if (tst)
                        tst->ss->free_super(tst);
        }
@@ -458,6 +540,13 @@ int Assemble(struct supertype *st, char *mddev,
        }
        ioctl(mdfd, STOP_ARRAY, NULL); /* just incase it was started but has no content */
 
+#ifndef MDASSEMBLE
+       if (content != &info) {
+               /* This is a member of a container.  Try starting the array. */
+               return assemble_container_content(st, mdfd, content, runstop,
+                                          chosen_name, verbose);
+       }
+#endif
        /* Ok, no bad inconsistancy, we can try updating etc */
        bitmap_done = 0;
        for (tmpdev = devlist; tmpdev; tmpdev=tmpdev->next) if (tmpdev->used == 1) {
index 8b23355..6ab5a34 100644 (file)
--- a/config.c
+++ b/config.c
@@ -261,6 +261,7 @@ mddev_dev_t load_partitions(void)
                d->devname = strdup(name);
                d->next = rv;
                d->used = 0;
+               d->content = NULL;
                rv = d;
        }
        fclose(f);
@@ -290,6 +291,7 @@ mddev_dev_t load_containers(void)
                        }
                        d->next = rv;
                        d->used = 0;
+                       d->content = NULL;
                        rv = d;
                }
        free_mdstat(mdstat);
@@ -803,6 +805,7 @@ mddev_dev_t conf_get_devs()
                        t->devname = strdup(globbuf.gl_pathv[i]);
                        t->next = dlist;
                        t->used = 0;
+                       t->content = NULL;
                        dlist = t;
 /*     printf("one dev is %s\n", t->devname);*/
                }
diff --git a/mdadm.c b/mdadm.c
index f830a8d..2bd963a 100644 (file)
--- a/mdadm.c
+++ b/mdadm.c
@@ -256,6 +256,7 @@ int main(int argc, char *argv[])
                                        dv->writemostly = writemostly;
                                        dv->re_add = re_add;
                                        dv->used = 0;
+                                       dv->content = NULL;
                                        dv->next = NULL;
                                        *devlistend = dv;
                                        devlistend = &dv->next;
@@ -308,6 +309,8 @@ int main(int argc, char *argv[])
                        dv->disposition = devmode;
                        dv->writemostly = writemostly;
                        dv->re_add = re_add;
+                       dv->used = 0;
+                       dv->content = NULL;
                        dv->next = NULL;
                        *devlistend = dv;
                        devlistend = &dv->next;
diff --git a/mdadm.h b/mdadm.h
index e76bc4d..8131b60 100644 (file)
--- a/mdadm.h
+++ b/mdadm.h
@@ -278,6 +278,8 @@ typedef struct mddev_dev_s {
        char writemostly;       /* 1 for 'set writemostly', 2 for 'clear writemostly' */
        char re_add;
        char used;              /* set when used */
+       struct mdinfo *content; /* If devname is a container, this might list
+                                * the remaining member arrays. */
        struct mddev_dev_s *next;
 } *mddev_dev_t;
 
@@ -758,6 +760,7 @@ extern int get_mdp_major(void);
 extern int dev_open(char *dev, int flags);
 extern int open_dev_excl(int devnum);
 extern int is_standard(char *dev, int *nump);
+extern int same_dev(char *one, char *two);
 
 extern int parse_auto(char *str, char *msg, int config);
 extern mddev_ident_t conf_get_ident(char *dev);
diff --git a/util.c b/util.c
index f15ba43..1736d70 100644 (file)
--- a/util.c
+++ b/util.c
@@ -828,6 +828,20 @@ int open_dev_excl(int devnum)
        return -1;
 }
 
+int same_dev(char *one, char *two)
+{
+       struct stat st1, st2;
+       if (stat(one, &st1) != 0)
+               return 0;
+       if (stat(two, &st2) != 0)
+               return 0;
+       if ((st1.st_mode & S_IFMT) != S_IFBLK)
+               return 0;
+       if ((st2.st_mode & S_IFMT) != S_IFBLK)
+               return 0;
+       return st1.st_rdev == st2.st_rdev;
+}
+
 struct superswitch *superlist[] = { &super0, &super1, &super_ddf, &super_imsm, NULL };
 
 #if !defined(MDASSEMBLE) || defined(MDASSEMBLE) && defined(MDASSEMBLE_AUTO)