# 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
|