Create arrays via metadata-update
authorNeil Brown <neilb@suse.de>
Sat, 12 Jul 2008 10:27:40 +0000 (20:27 +1000)
committerNeil Brown <neilb@suse.de>
Sat, 12 Jul 2008 10:27:40 +0000 (20:27 +1000)
Support creating arrays inside an active ddf container by
sending a metadata update over a pipe to mdmon.

Create.c
managemon.c
mdadm.h
mdmon.h
super-ddf.c
util.c

index fe93238..f4567ca 100644 (file)
--- a/Create.c
+++ b/Create.c
@@ -573,12 +573,13 @@ int Create(struct supertype *st, char *mddev, int mdfd,
                                return 1;
                        }
                        if (mdmon_running(st->container_dev)) {
-                               fprintf(stderr, Name ": mdmon already running "
-                                       "for %s - sorry\n",
-                                       devnum2devname(st->container_dev));
-                               return 1;
-                       }
-                       need_mdmon = 1;
+                               if (verbose)
+                                       fprintf(stderr, Name ": reusing mdmon "
+                                               "for %s.\n",
+                                               devnum2devname(st->container_dev));
+                               st->update_tail = &st->updates;
+                       } else
+                               need_mdmon = 1;
                }
                if ((vers % 100) < 2 ||
                    sra == NULL ||
@@ -707,8 +708,10 @@ int Create(struct supertype *st, char *mddev, int mdfd,
                        }
                        if (dv == moved_disk && dnum != insert_point) break;
                }
-               if (pass == 1)
+               if (pass == 1) {
                        st->ss->write_init_super(st);
+                       flush_metadata_updates(st);
+               }
        }
        free(infos);
        st->ss->free_super(st);
index 1917218..03de9a8 100644 (file)
@@ -428,9 +428,25 @@ void manage(struct mdstat_ent *mdstat, struct supertype *container)
        }
 }
 
-static int handle_message(struct supertype *container, struct metadata_update *msg)
+static void handle_message(struct supertype *container, struct metadata_update *msg)
 {
-       return -1;
+       /* queue this metadata update through to the monitor */
+
+       struct metadata_update *mu;
+
+       if (msg->len == 0) {
+               wait_update_handled();
+       } else {
+               mu = malloc(sizeof(*mu));
+               mu->len = msg->len;
+               mu->buf = msg->buf;
+               msg->buf = NULL;
+               mu->space = NULL;
+               mu->next = NULL;
+               if (container->ss->prepare_update)
+                       container->ss->prepare_update(container, mu);
+               queue_metadata_update(mu);
+       }
 }
 
 void read_sock(struct supertype *container)
@@ -460,8 +476,6 @@ void read_sock(struct supertype *container)
                } else
                        terminate = 1;
 
-               if (msg.buf)
-                       free(msg.buf);
        } while (!terminate);
 
        close(fd);
diff --git a/mdadm.h b/mdadm.h
index 08b7868..5e2cfe4 100644 (file)
--- a/mdadm.h
+++ b/mdadm.h
@@ -542,6 +542,8 @@ extern struct superswitch {
        void (*sync_metadata)(struct supertype *st);
        void (*process_update)(struct supertype *st,
                               struct metadata_update *update);
+       void (*prepare_update)(struct supertype *st,
+                              struct metadata_update *update);
 
        /* activate_spare will check if the array is degraded and, if it
         * is, try to find some spare space in the container.
@@ -559,6 +561,13 @@ extern struct superswitch {
 
 extern struct superswitch super_imsm;
 
+struct metadata_update {
+       int     len;
+       char    *buf;
+       void    *space; /* allocated space that monitor will use */
+       struct metadata_update *next;
+};
+
 /* A supertype holds a particular collection of metadata.
  * It identifies the metadata type by the superswitch, and the particular
  * sub-version of that metadata type.
@@ -579,6 +588,9 @@ struct supertype {
        void *sb;
        void *info;
 
+       struct metadata_update *updates;
+       struct metadata_update **update_tail;
+
        /* extra stuff used by mdmon */
        struct active_array *arrays;
        int sock; /* listen to external programs */
@@ -738,6 +750,8 @@ extern unsigned long long get_component_size(int fd);
 extern void remove_partitions(int fd);
 extern unsigned long long calc_array_size(int level, int raid_disks, int layout,
                                   int chunksize, unsigned long long devsize);
+extern int flush_metadata_updates(struct supertype *st);
+extern void append_metadata_update(struct supertype *st, void *buf, int len);
 
 
 extern char *human_size(long long bytes);
diff --git a/mdmon.h b/mdmon.h
index 4038533..02cdb09 100644 (file)
--- a/mdmon.h
+++ b/mdmon.h
@@ -41,12 +41,6 @@ struct active_array {
  * superswitch.  All common code sees them as opaque
  * blobs.
  */
-struct metadata_update {
-       int     len;
-       char    *buf;
-       void    *space; /* allocated space that monitor will use */
-       struct metadata_update *next;
-};
 extern struct metadata_update *update_queue, *update_queue_handled;
 
 #define MD_MAJOR 9
index f3a7904..aefe25e 100644 (file)
@@ -2122,7 +2122,32 @@ static int __write_init_super_ddf(struct supertype *st, int do_close)
 
 static int write_init_super_ddf(struct supertype *st)
 {
-       return __write_init_super_ddf(st, 1);
+
+       if (st->update_tail) {
+               /* queue the virtual_disk and vd_config as metadata updates */
+               struct virtual_disk *vd;
+               struct vd_config *vc;
+               struct ddf_super *ddf = st->sb;
+               int len;
+
+               /* First the virtual disk.  We have a slightly fake header */
+               len = sizeof(struct virtual_disk) + sizeof(struct virtual_entry);
+               vd = malloc(len);
+               *vd = *ddf->virt;
+               vd->entries[0] = ddf->virt->entries[ddf->currentconf->vcnum];
+               vd->populated_vdes = __cpu_to_be16(ddf->currentconf->vcnum);
+               append_metadata_update(st, vd, len);
+
+               /* Then the vd_config */
+               len = ddf->conf_rec_len * 512;
+               vc = malloc(len);
+               memcpy(vc, &ddf->currentconf->conf, len);
+               append_metadata_update(st, vc, len);
+
+               /* FIXME I need to close the fds! */
+               return 0;
+       } else 
+               return __write_init_super_ddf(st, 1);
 }
 
 #endif
@@ -2812,7 +2837,7 @@ static void ddf_process_update(struct supertype *st,
                printf("len %d %d\n", update->len, ddf->conf_rec_len);
 
                mppe = __be16_to_cpu(ddf->anchor.max_primary_element_entries);
-               if (update->len != ddf->conf_rec_len)
+               if (update->len != ddf->conf_rec_len * 512)
                        return;
                vc = (struct vd_config*)update->buf;
                for (vcl = ddf->conflist; vcl ; vcl = vcl->next)
@@ -2830,7 +2855,7 @@ static void ddf_process_update(struct supertype *st,
                        vcl = update->space;
                        update->space = NULL;
                        vcl->next = ddf->conflist;
-                       vcl->conf = *vc;
+                       memcpy(&vcl->conf, vc, update->len);
                        vcl->lba_offset = (__u64*)
                                &vcl->conf.phys_refnum[mppe];
                        ddf->conflist = vcl;
@@ -2876,6 +2901,20 @@ static void ddf_process_update(struct supertype *st,
        }
 }
 
+static void ddf_prepare_update(struct supertype *st,
+                              struct metadata_update *update)
+{
+       /* This update arrived at managemon.
+        * We are about to pass it to monitor.
+        * If a malloc is needed, do it here.
+        */
+       struct ddf_super *ddf = st->sb;
+       __u32 *magic = (__u32*)update->buf;
+       if (*magic == DDF_VD_CONF_MAGIC)
+               update->space = malloc(offsetof(struct vcl, conf)
+                                      + ddf->conf_rec_len * 512);
+}
+
 /*
  * Check if the array 'a' is degraded but not failed.
  * If it is, find as many spares as are available and needed and
@@ -3106,6 +3145,7 @@ struct superswitch super_ddf = {
        .set_disk       = ddf_set_disk,
        .sync_metadata  = ddf_sync_metadata,
        .process_update = ddf_process_update,
+       .prepare_update = ddf_prepare_update,
        .activate_spare = ddf_activate_spare,
 
 };
diff --git a/util.c b/util.c
index 4cecd6d..49c36a0 100644 (file)
--- a/util.c
+++ b/util.c
@@ -29,7 +29,9 @@
 
 #include       "mdadm.h"
 #include       "md_p.h"
+#include       <sys/socket.h>
 #include       <sys/utsname.h>
+#include       <sys/un.h>
 #include       <ctype.h>
 #include       <dirent.h>
 #include       <signal.h>
@@ -1065,6 +1067,47 @@ int signal_mdmon(int devnum)
 }
 
 
+int flush_metadata_updates(struct supertype *st)
+{
+       int sfd;
+       if (!st->updates) {
+               st->update_tail = NULL;
+               return -1;
+       }
+
+       sfd = connect_monitor(devnum2devname(st->container_dev));
+       if (sfd < 0)
+               return -1;
+
+       while (st->updates) {
+               struct metadata_update *mu = st->updates;
+               st->updates = mu->next;
+
+               send_message(sfd, mu, 0);
+               wait_reply(sfd, 0);
+               free(mu->buf);
+               free(mu);
+       }
+       ack(sfd, 0);
+       wait_reply(sfd, 0);
+       close(sfd);
+       st->update_tail = NULL;
+       return 0;
+}
+
+void append_metadata_update(struct supertype *st, void *buf, int len)
+{
+
+       struct metadata_update *mu = malloc(sizeof(*mu));
+
+       mu->buf = buf;
+       mu->len = len;
+       mu->space = NULL;
+       mu->next = NULL;
+       *st->update_tail = mu;
+       st->update_tail = &mu->next;
+}
+
 
 #ifdef __TINYC__
 /* tinyc doesn't optimize this check in ioctl.h out ... */