summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--managemon.c41
-rw-r--r--mdadm.h5
-rw-r--r--mdmon.h19
-rw-r--r--monitor.c14
-rw-r--r--super-ddf.c4
-rw-r--r--super-intel.c4
6 files changed, 80 insertions, 7 deletions
diff --git a/managemon.c b/managemon.c
index 4b06778..167d176 100644
--- a/managemon.c
+++ b/managemon.c
@@ -151,6 +151,45 @@ static void replace_array(struct supertype *container,
write_wakeup(container);
}
+struct metadata_update *update_queue = NULL;
+struct metadata_update *update_queue_handled = NULL;
+struct metadata_update *update_queue_pending = NULL;
+
+void check_update_queue(struct supertype *container)
+{
+ while (update_queue_handled) {
+ struct metadata_update *this = update_queue_handled;
+ update_queue_handled = this->next;
+ free(this->buf);
+ free(this);
+ }
+ if (update_queue == NULL &&
+ update_queue_pending) {
+ update_queue = update_queue_pending;
+ update_queue_pending = NULL;
+ write_wakeup(container);
+ }
+}
+
+void queue_metadata_update(struct metadata_update *mu)
+{
+ struct metadata_update **qp;
+
+ qp = &update_queue_pending;
+ while (*qp)
+ qp = & ((*qp)->next);
+ *qp = mu;
+}
+
+void wait_update_handled(void)
+{
+ /* Wait for any pending update to be handled by monitor.
+ * i.e. wait until update_queue is NULL
+ */
+ while (update_queue)
+ usleep(100 * 1000);
+}
+
static void manage_container(struct mdstat_ent *mdstat,
struct supertype *container)
{
@@ -404,6 +443,8 @@ void do_manager(struct supertype *container)
remove_old();
+ check_update_queue(container);
+
manager_ready = 1;
sigprocmask(SIG_SETMASK, &block, &orig);
if (woke == 0)
diff --git a/mdadm.h b/mdadm.h
index 783cd82..b97cd51 100644
--- a/mdadm.h
+++ b/mdadm.h
@@ -372,6 +372,7 @@ extern mapping_t r5layout[], pers[], modes[], faultylayout[];
extern char *map_dev(int major, int minor, int create);
struct active_array;
+struct metadata_update;
extern struct superswitch {
void (*examine_super)(struct supertype *st, char *homehost);
@@ -433,7 +434,9 @@ extern struct superswitch {
* not in fact changed.
*/
void (*set_disk)(struct active_array *a, int n, int state);
- void (*sync_metadata)(struct active_array *a);
+ void (*sync_metadata)(struct supertype *st);
+ void (*process_update)(struct supertype *st,
+ struct metadata_update *update);
int major;
diff --git a/mdmon.h b/mdmon.h
index ad1a678..965f643 100644
--- a/mdmon.h
+++ b/mdmon.h
@@ -21,7 +21,24 @@ struct active_array {
unsigned long long resync_start;
};
-
+/*
+ * Metadata updates are handled by the monitor thread,
+ * as it has exclusive access to the metadata.
+ * When the manager want to updates metadata, either
+ * for it's own reason (e.g. committing a spare) or
+ * on behalf of mdadm, it creates a metadata_update
+ * structure and queues it to the monitor.
+ * Updates are created and processed by code under the
+ * 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
diff --git a/monitor.c b/monitor.c
index 4fe1cb0..d1f7c9e 100644
--- a/monitor.c
+++ b/monitor.c
@@ -299,7 +299,7 @@ static int read_and_act(struct active_array *a)
// FIXME;
}
- a->container->ss->sync_metadata(a);
+ a->container->ss->sync_metadata(a->container);
/* Effect state changes in the array */
if (a->next_state != bad_word)
@@ -492,6 +492,18 @@ static int wait_and_act(struct supertype *container, int pfd,
}
}
+ if (update_queue) {
+ struct metadata_update *this;
+
+ for (this = update_queue; this ; this = this->next)
+ container->ss->process_update(container, this);
+
+ update_queue_handled = update_queue;
+ update_queue = NULL;
+ signal_manager();
+ container->ss->sync_metadata(container);
+ }
+
for (a = *aap; a ; a = a->next) {
if (a->replaces && !discard_this) {
struct active_array **ap;
diff --git a/super-ddf.c b/super-ddf.c
index d912696..2918b71 100644
--- a/super-ddf.c
+++ b/super-ddf.c
@@ -2666,7 +2666,7 @@ static void ddf_set_disk(struct active_array *a, int n, int state)
fprintf(stderr, "ddf: set_disk %d\n", n);
}
-static void ddf_sync_metadata(struct active_array *a)
+static void ddf_sync_metadata(struct supertype *st)
{
/*
@@ -2676,7 +2676,7 @@ static void ddf_sync_metadata(struct active_array *a)
* but ddf is sufficiently weird that it probably always
* changes global data ....
*/
- __write_init_super_ddf(a->container, 0);
+ __write_init_super_ddf(st, 0);
fprintf(stderr, "ddf: sync_metadata\n");
}
diff --git a/super-intel.c b/super-intel.c
index 8bf2073..2da4514 100644
--- a/super-intel.c
+++ b/super-intel.c
@@ -1307,9 +1307,9 @@ static int store_imsm_mpb(int fd, struct intel_super *super)
return 0;
}
-static void imsm_sync_metadata(struct active_array *a)
+static void imsm_sync_metadata(struct supertype *container)
{
- struct intel_super *super = a->container->sb;
+ struct intel_super *super = container->sb;
struct imsm_super *mpb = super->mpb;
struct dl *d;
__u32 generation;