[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


 


Rackspace

Lists.xenproject.org is hosted with RackSpace, monitoring our
servers 24x7x365 and backed by RackSpace's Fanatical Support®.