From 2e735d198233a67f305862f72e3a5d0f0c3c548c Mon Sep 17 00:00:00 2001 From: Neil Brown Date: Thu, 12 Jun 2008 10:13:23 +1000 Subject: [PATCH] Allow passing metadata update to the monitor. Code in manager can now just call queue_metadata_update with a (freeable) buf holding the update, and it will get passed to the monitor and written out. --- managemon.c | 41 +++++++++++++++++++++++++++++++++++++++++ mdadm.h | 5 ++++- mdmon.h | 19 ++++++++++++++++++- monitor.c | 14 +++++++++++++- super-ddf.c | 4 ++-- super-intel.c | 4 ++-- 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;