WARNING - OLD ARCHIVES

This is an archived copy of the Xen.org mailing list, which we have preserved to ensure that existing links to archives are not broken. The live archive, which contains the latest emails, can be found at http://lists.xen.org/
   
 
 
Xen 
 
Home Products Support Community News
 
   
 

xen-changelog

[Xen-changelog] [xen-unstable] Clean up notifier-chain interface and use

To: xen-changelog@xxxxxxxxxxxxxxxxxxx
Subject: [Xen-changelog] [xen-unstable] Clean up notifier-chain interface and use new interface in CPU hotplug.
From: Xen patchbot-unstable <patchbot-unstable@xxxxxxxxxxxxxxxxxxx>
Date: Wed, 19 May 2010 05:16:04 -0700
Delivery-date: Wed, 19 May 2010 05:21:05 -0700
Envelope-to: www-data@xxxxxxxxxxxxxxxxxxx
List-help: <mailto:xen-changelog-request@lists.xensource.com?subject=help>
List-id: BK change log <xen-changelog.lists.xensource.com>
List-post: <mailto:xen-changelog@lists.xensource.com>
List-subscribe: <http://lists.xensource.com/mailman/listinfo/xen-changelog>, <mailto:xen-changelog-request@lists.xensource.com?subject=subscribe>
List-unsubscribe: <http://lists.xensource.com/mailman/listinfo/xen-changelog>, <mailto:xen-changelog-request@lists.xensource.com?subject=unsubscribe>
Reply-to: xen-devel@xxxxxxxxxxxxxxxxxxx
Sender: xen-changelog-bounces@xxxxxxxxxxxxxxxxxxx
# 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

<Prev in Thread] Current Thread [Next in Thread>
  • [Xen-changelog] [xen-unstable] Clean up notifier-chain interface and use new interface in CPU hotplug., Xen patchbot-unstable <=