[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index] [Xen-changelog] [xen-unstable] Clean up notifier-chain interface and use new interface in CPU hotplug.
# HG changeset patch # User Keir Fraser <keir.fraser@xxxxxxxxxx> # Date 1274185382 -3600 # Node ID 1b49bfd3b0d7cc60bf2d602c6c2f3c1319480b89 # Parent 8abb8cd861fca907ce77345341a9632e3a5cbf17 Clean up notifier-chain interface and use new interface in CPU hotplug. Signed-off-by: Keir Fraser <keir.fraser@xxxxxxxxxx> --- xen/common/cpu.c | 73 ++++++++----------- xen/common/notifier.c | 168 +++++++++++++-------------------------------- xen/include/xen/cpu.h | 28 +++++-- xen/include/xen/notifier.h | 38 +++++----- 4 files changed, 123 insertions(+), 184 deletions(-) diff -r 8abb8cd861fc -r 1b49bfd3b0d7 xen/common/cpu.c --- a/xen/common/cpu.c Tue May 18 11:38:12 2010 +0100 +++ b/xen/common/cpu.c Tue May 18 13:23:02 2010 +0100 @@ -51,96 +51,87 @@ void cpu_hotplug_done(void) put_cpu_maps(); } -static RAW_NOTIFIER_HEAD(cpu_chain); - -int register_cpu_notifier(struct notifier_block *nb) -{ - int ret; +static NOTIFIER_HEAD(cpu_chain); + +void register_cpu_notifier(struct notifier_block *nb) +{ if ( !spin_trylock(&cpu_add_remove_lock) ) BUG(); /* Should never fail as we are called only during boot. */ - ret = raw_notifier_chain_register(&cpu_chain, nb); + notifier_chain_register(&cpu_chain, nb); spin_unlock(&cpu_add_remove_lock); - return ret; } static int take_cpu_down(void *unused) { void *hcpu = (void *)(long)smp_processor_id(); - if ( raw_notifier_call_chain(&cpu_chain, CPU_DYING, hcpu) != NOTIFY_DONE ) - BUG(); + int notifier_rc = notifier_call_chain(&cpu_chain, CPU_DYING, hcpu, NULL); + BUG_ON(notifier_rc != NOTIFY_DONE); __cpu_disable(); return 0; } int cpu_down(unsigned int cpu) { - int err, notifier_rc, nr_calls; + int err, notifier_rc; void *hcpu = (void *)(long)cpu; + struct notifier_block *nb = NULL; if ( !cpu_hotplug_begin() ) return -EBUSY; - if ( (cpu == 0) || !cpu_online(cpu) ) + if ( (cpu >= NR_CPUS) || (cpu == 0) || !cpu_online(cpu) ) { cpu_hotplug_done(); return -EINVAL; } - notifier_rc = __raw_notifier_call_chain( - &cpu_chain, CPU_DOWN_PREPARE, hcpu, -1, &nr_calls); + notifier_rc = notifier_call_chain(&cpu_chain, CPU_DOWN_PREPARE, hcpu, &nb); if ( notifier_rc != NOTIFY_DONE ) { err = notifier_to_errno(notifier_rc); - nr_calls--; - notifier_rc = __raw_notifier_call_chain( - &cpu_chain, CPU_DOWN_FAILED, hcpu, nr_calls, NULL); - BUG_ON(notifier_rc != NOTIFY_DONE); - goto out; + goto fail; } if ( (err = stop_machine_run(take_cpu_down, NULL, cpu)) < 0 ) - { - notifier_rc = raw_notifier_call_chain( - &cpu_chain, CPU_DOWN_FAILED, hcpu); - BUG_ON(notifier_rc != NOTIFY_DONE); - goto out; - } + goto fail; __cpu_die(cpu); BUG_ON(cpu_online(cpu)); - notifier_rc = raw_notifier_call_chain(&cpu_chain, CPU_DEAD, hcpu); - BUG_ON(notifier_rc != NOTIFY_DONE); - - out: - if ( !err ) - send_guest_global_virq(dom0, VIRQ_PCPU_STATE); - else - printk("Failed to take down CPU %u (error %d)\n", cpu, err); + notifier_rc = notifier_call_chain(&cpu_chain, CPU_DEAD, hcpu, NULL); + BUG_ON(notifier_rc != NOTIFY_DONE); + + send_guest_global_virq(dom0, VIRQ_PCPU_STATE); + cpu_hotplug_done(); + return 0; + + fail: + notifier_rc = notifier_call_chain(&cpu_chain, CPU_DOWN_FAILED, hcpu, &nb); + BUG_ON(notifier_rc != NOTIFY_DONE); + printk("Failed to take down CPU %u (error %d)\n", cpu, err); cpu_hotplug_done(); return err; } int cpu_up(unsigned int cpu) { - int notifier_rc, nr_calls, err = 0; + int notifier_rc, err = 0; void *hcpu = (void *)(long)cpu; + struct notifier_block *nb = NULL; if ( !cpu_hotplug_begin() ) return -EBUSY; - if ( cpu_online(cpu) || !cpu_present(cpu) ) + if ( (cpu >= NR_CPUS) || cpu_online(cpu) || !cpu_present(cpu) ) { cpu_hotplug_done(); return -EINVAL; } - notifier_rc = __raw_notifier_call_chain( - &cpu_chain, CPU_UP_PREPARE, hcpu, -1, &nr_calls); + notifier_rc = notifier_call_chain(&cpu_chain, CPU_UP_PREPARE, hcpu, &nb); if ( notifier_rc != NOTIFY_DONE ) { err = notifier_to_errno(notifier_rc); - nr_calls--; goto fail; } @@ -148,7 +139,7 @@ int cpu_up(unsigned int cpu) if ( err < 0 ) goto fail; - notifier_rc = raw_notifier_call_chain(&cpu_chain, CPU_ONLINE, hcpu); + notifier_rc = notifier_call_chain(&cpu_chain, CPU_ONLINE, hcpu, NULL); BUG_ON(notifier_rc != NOTIFY_DONE); send_guest_global_virq(dom0, VIRQ_PCPU_STATE); @@ -157,9 +148,9 @@ int cpu_up(unsigned int cpu) return 0; fail: - notifier_rc = __raw_notifier_call_chain( - &cpu_chain, CPU_UP_CANCELED, hcpu, nr_calls, NULL); - BUG_ON(notifier_rc != NOTIFY_DONE); + notifier_rc = notifier_call_chain(&cpu_chain, CPU_UP_CANCELED, hcpu, &nb); + BUG_ON(notifier_rc != NOTIFY_DONE); + printk("Failed to bring up CPU %u (error %d)\n", cpu, err); cpu_hotplug_done(); return err; } diff -r 8abb8cd861fc -r 1b49bfd3b0d7 xen/common/notifier.c --- a/xen/common/notifier.c Tue May 18 11:38:12 2010 +0100 +++ b/xen/common/notifier.c Tue May 18 13:23:02 2010 +0100 @@ -10,147 +10,83 @@ #include <xen/config.h> #include <xen/init.h> #include <xen/notifier.h> -#include <xen/rcupdate.h> - -/* - * Notifier chain core routines. The exported routines below - * are layered on top of these, with appropriate locking added. - */ - -static int notifier_chain_register( - struct notifier_block **nl, struct notifier_block *n) -{ - while ( (*nl) != NULL ) - { - if ( n->priority > (*nl)->priority ) - break; - nl = &((*nl)->next); - } - n->next = *nl; - rcu_assign_pointer(*nl, n); - return 0; -} - -static int notifier_chain_unregister( - struct notifier_block **nl, struct notifier_block *n) -{ - while ( (*nl) != NULL ) - { - if ( (*nl) == n ) - { - rcu_assign_pointer(*nl, n->next); - return 0; - } - nl = &((*nl)->next); - } - return -ENOENT; -} /** - * notifier_call_chain - Informs the registered notifiers about an event. - * @nl: Pointer to head of the blocking notifier chain - * @val: Value passed unmodified to notifier function - * @v: Pointer passed unmodified to notifier function - * @nr_to_call: Number of notifier functions to be called. Don't care - * value of this parameter is -1. - * @nr_calls: Records the number of notifications sent. Don't care - * value of this field is NULL. - * @returns: notifier_call_chain returns the value returned by the - * last notifier function called. - */ -static int notifier_call_chain( - struct notifier_block **nl, unsigned long val, void *v, - int nr_to_call, int *nr_calls) -{ - int ret = NOTIFY_DONE; - struct notifier_block *nb, *next_nb; - - if ( nr_calls ) - *nr_calls = 0; - - nb = rcu_dereference(*nl); - - while ( nb && nr_to_call ) - { - next_nb = rcu_dereference(nb->next); - ret = nb->notifier_call(nb, val, v); - - if ( nr_calls ) - (*nr_calls)++; - - if ( (ret & NOTIFY_STOP_MASK) == NOTIFY_STOP_MASK ) - break; - nb = next_nb; - nr_to_call--; - } - return ret; -} - -/* - * Raw notifier chain routines. There is no protection; - * the caller must provide it. Use at your own risk! - */ - -/** - * raw_notifier_chain_register - Add notifier to a raw notifier chain + * notifier_chain_register - Add notifier to a raw notifier chain * @nh: Pointer to head of the raw notifier chain * @n: New entry in notifier chain * * Adds a notifier to a raw notifier chain. * All locking must be provided by the caller. - * - * Currently always returns zero. */ -int raw_notifier_chain_register( - struct raw_notifier_head *nh, struct notifier_block *n) +void notifier_chain_register( + struct notifier_head *nh, struct notifier_block *n) { - return notifier_chain_register(&nh->head, n); + struct list_head *chain = &nh->head.chain; + struct notifier_block *nb; + + while ( chain->next != &nh->head.chain ) + { + nb = list_entry(chain->next, struct notifier_block, chain); + if ( n->priority > nb->priority ) + break; + chain = chain->next; + } + + list_add(&n->chain, chain); } /** - * raw_notifier_chain_unregister - Remove notifier from a raw notifier chain + * notifier_chain_unregister - Remove notifier from a raw notifier chain * @nh: Pointer to head of the raw notifier chain * @n: Entry to remove from notifier chain * * Removes a notifier from a raw notifier chain. * All locking must be provided by the caller. - * - * Returns zero on success or %-ENOENT on failure. */ -int raw_notifier_chain_unregister( - struct raw_notifier_head *nh, struct notifier_block *n) +void notifier_chain_unregister( + struct notifier_head *nh, struct notifier_block *n) { - return notifier_chain_unregister(&nh->head, n); + list_del(&n->chain); } /** - * __raw_notifier_call_chain - Call functions in a raw notifier chain + * notifier_call_chain - Informs the registered notifiers about an event. * @nh: Pointer to head of the raw notifier chain - * @val: Value passed unmodified to notifier function - * @v: Pointer passed unmodified to notifier function - * @nr_to_call: See comment for notifier_call_chain. - * @nr_calls: See comment for notifier_call_chain + * @val: Value passed unmodified to notifier function + * @v: Pointer passed unmodified to notifier function + * @pcursor: If non-NULL, position in chain to start from. Also updated on + * return to indicate how far notifications got before stopping. * - * Calls each function in a notifier chain in turn. The functions - * run in an undefined context. - * All locking must be provided by the caller. + * Calls each function in a notifier chain in turn. The functions run in an + * undefined context. All locking must be provided by the caller. * - * If the return value of the notifier can be and'ed - * with %NOTIFY_STOP_MASK then raw_notifier_call_chain() - * will return immediately, with the return value of - * the notifier function which halted execution. - * Otherwise the return value is the return value - * of the last notifier function called. + * If the return value of the notifier can be and'ed with %NOTIFY_STOP_MASK + * then notifier_call_chain() will return immediately, with teh return value of + * the notifier function which halted execution. Otherwise the return value is + * the return value of the last notifier function called. */ -int __raw_notifier_call_chain( - struct raw_notifier_head *nh, unsigned long val, void *v, - int nr_to_call, int *nr_calls) +int notifier_call_chain( + struct notifier_head *nh, unsigned long val, void *v, + struct notifier_block **pcursor) { - return notifier_call_chain(&nh->head, val, v, nr_to_call, nr_calls); + int ret = NOTIFY_DONE; + struct list_head *cursor; + struct notifier_block *nb; + bool_t reverse = !!(val & NOTIFY_REVERSE); + + cursor = &(pcursor && *pcursor ? *pcursor : &nh->head)->chain; + + do { + cursor = reverse ? cursor->prev : cursor->next; + nb = list_entry(cursor, struct notifier_block, chain); + if ( cursor == &nh->head.chain ) + break; + ret = nb->notifier_call(nb, val, v); + } while ( !(ret & NOTIFY_STOP_MASK) ); + + if ( pcursor ) + *pcursor = nb; + + return ret; } - -int raw_notifier_call_chain( - struct raw_notifier_head *nh, unsigned long val, void *v) -{ - return __raw_notifier_call_chain(nh, val, v, -1, NULL); -} diff -r 8abb8cd861fc -r 1b49bfd3b0d7 xen/include/xen/cpu.h --- a/xen/include/xen/cpu.h Tue May 18 11:38:12 2010 +0100 +++ b/xen/include/xen/cpu.h Tue May 18 13:23:02 2010 +0100 @@ -14,7 +14,7 @@ void cpu_hotplug_done(void); void cpu_hotplug_done(void); /* Receive notification of CPU hotplug events. */ -int register_cpu_notifier(struct notifier_block *nb); +void register_cpu_notifier(struct notifier_block *nb); /* * Possible event sequences for a given CPU: @@ -25,14 +25,26 @@ int register_cpu_notifier(struct notifie * * Hence note that only CPU_*_PREPARE handlers are allowed to fail. Also note * that once CPU_DYING is delivered, an offline action can no longer fail. + * + * Notifiers are called highest-priority-first when: + * (a) A CPU is coming up; or (b) CPU_DOWN_FAILED + * Notifiers are called lowest-priority-first when: + * (a) A CPU is going down; or (b) CPU_UP_CANCELED */ -#define CPU_UP_PREPARE 0x0002 /* CPU is coming up */ -#define CPU_UP_CANCELED 0x0003 /* CPU is no longer coming up */ -#define CPU_ONLINE 0x0004 /* CPU is up */ -#define CPU_DOWN_PREPARE 0x0005 /* CPU is going down */ -#define CPU_DOWN_FAILED 0x0006 /* CPU is no longer going down */ -#define CPU_DYING 0x0007 /* CPU is nearly dead (in stop_machine ctxt) */ -#define CPU_DEAD 0x0008 /* CPU is dead */ +/* CPU_UP_PREPARE: CPU is coming up */ +#define CPU_UP_PREPARE (0x0002 | NOTIFY_FORWARD) +/* CPU_UP_CANCELED: CPU is no longer coming up. */ +#define CPU_UP_CANCELED (0x0003 | NOTIFY_REVERSE) +/* CPU_ONLINE: CPU is up. */ +#define CPU_ONLINE (0x0004 | NOTIFY_FORWARD) +/* CPU_DOWN_PREPARE: CPU is going down. */ +#define CPU_DOWN_PREPARE (0x0005 | NOTIFY_REVERSE) +/* CPU_DOWN_FAILED: CPU is no longer going down. */ +#define CPU_DOWN_FAILED (0x0006 | NOTIFY_FORWARD) +/* CPU_DYING: CPU is nearly dead (in stop_machine context). */ +#define CPU_DYING (0x0007 | NOTIFY_REVERSE) +/* CPU_DEAD: CPU is dead. */ +#define CPU_DEAD (0x0008 | NOTIFY_REVERSE) /* Perform CPU hotplug. May return -EAGAIN. */ int cpu_down(unsigned int cpu); diff -r 8abb8cd861fc -r 1b49bfd3b0d7 xen/include/xen/notifier.h --- a/xen/include/xen/notifier.h Tue May 18 11:38:12 2010 +0100 +++ b/xen/include/xen/notifier.h Tue May 18 13:23:02 2010 +0100 @@ -13,6 +13,8 @@ #include <xen/config.h> #include <xen/types.h> #include <xen/errno.h> +#include <xen/kernel.h> +#include <xen/list.h> /* * Xen includes only one type of notifier chains inherited from Linux: @@ -23,35 +25,33 @@ struct notifier_block { int (*notifier_call)(struct notifier_block *, unsigned long, void *); - struct notifier_block *next; + struct list_head chain; int priority; }; -struct raw_notifier_head { - struct notifier_block *head; +struct notifier_head { + struct notifier_block head; }; -#define RAW_INIT_NOTIFIER_HEAD(name) do { \ - (name)->head = NULL; \ -} while (0) +#define NOTIFIER_INIT(name) { .head.chain = LIST_HEAD_INIT(name.head.chain) } -#define RAW_NOTIFIER_INIT(name) { .head = NULL } +#define NOTIFIER_HEAD(name) \ + struct notifier_head name = NOTIFIER_INIT(name) -#define RAW_NOTIFIER_HEAD(name) \ - struct raw_notifier_head name = RAW_NOTIFIER_INIT(name) +void notifier_chain_register( + struct notifier_head *nh, struct notifier_block *nb); +void notifier_chain_unregister( + struct notifier_head *nh, struct notifier_block *nb); -int raw_notifier_chain_register( - struct raw_notifier_head *nh, struct notifier_block *nb); +int notifier_call_chain( + struct notifier_head *nh, unsigned long val, void *v, + struct notifier_block **pcursor); -int raw_notifier_chain_unregister( - struct raw_notifier_head *nh, struct notifier_block *nb); +/* Notifier flag values: OR into @val passed to notifier_call_chain(). */ +#define NOTIFY_FORWARD 0x0000 /* Call chain highest-priority-first */ +#define NOTIFY_REVERSE 0x8000 /* Call chain lowest-priority-first */ -int raw_notifier_call_chain( - struct raw_notifier_head *nh, unsigned long val, void *v); -int __raw_notifier_call_chain( - struct raw_notifier_head *nh, unsigned long val, void *v, - int nr_to_call, int *nr_calls); - +/* Handler completion values */ #define NOTIFY_DONE 0x0000 #define NOTIFY_STOP_MASK 0x8000 #define NOTIFY_STOP (NOTIFY_STOP_MASK|NOTIFY_DONE) _______________________________________________ Xen-changelog mailing list Xen-changelog@xxxxxxxxxxxxxxxxxxx http://lists.xensource.com/xen-changelog
|
Lists.xenproject.org is hosted with RackSpace, monitoring our |