Gitweb:     
http://git.kernel.org/git/?p=linux/kernel/git/torvalds/linux-2.6.git;a=commit;h=6f7cc11aa6c7d5002e16096c7590944daece70ed
Commit:     6f7cc11aa6c7d5002e16096c7590944daece70ed
Parent:     7c9cb38302e78d24e37f7d8a2ea7eed4ae5f2fa7
Author:     Gautham R Shenoy <[EMAIL PROTECTED]>
AuthorDate: Wed May 9 02:34:02 2007 -0700
Committer:  Linus Torvalds <[EMAIL PROTECTED]>
CommitDate: Wed May 9 12:30:51 2007 -0700

    Extend notifier_call_chain to count nr_calls made
    
    Since 2.6.18-something, the community has been bugged by the problem to
    provide a clean and a stable mechanism to postpone a cpu-hotplug event as
    lock_cpu_hotplug was badly broken.
    
    This is another proposal towards solving that problem.  This one is along 
the
    lines of the solution provided in kernel/workqueue.c
    
    Instead of having a global mechanism like lock_cpu_hotplug, we allow the
    subsytems to define their own per-subsystem hot cpu mutexes.  These would be
    taken(released) where ever we are currently calling
    lock_cpu_hotplug(unlock_cpu_hotplug).
    
    Also, in the per-subsystem hotcpu callback function,we take this mutex 
before
    we handle any pre-cpu-hotplug events and release it once we finish handling
    the post-cpu-hotplug events.  A standard means for doing this has been
    provided in [PATCH 2/4] and demonstrated in [PATCH 3/4].
    
    The ordering of these per-subsystem mutexes might still prove to be a
    problem, but hopefully lockdep should help us get out of that muddle.
    
    The patch set to be applied against linux-2.6.19-rc5 is as follows:
    
    [PATCH 1/4] :       Extend notifier_call_chain with an option to specify the
                number of notifications to be sent and also count the
                number of notifications actually sent.
    
    [PATCH 2/4] :       Define events CPU_LOCK_ACQUIRE and CPU_LOCK_RELEASE
                and send out notifications for these in _cpu_up and
                _cpu_down. This would help us standardise the acquire and
                release of the subsystem locks in the hotcpu
                callback functions of these subsystems.
    
    [PATCH 3/4] :       Eliminate lock_cpu_hotplug from kernel/sched.c.
    
    [PATCH 4/4] :       In workqueue_cpu_callback function, acquire(release) the
                workqueue_mutex while handling
                CPU_LOCK_ACQUIRE(CPU_LOCK_RELEASE).
    
    If the per-subsystem-locking approach survives the test of time, we can 
expect
    a slow phasing out of lock_cpu_hotplug, which has not yet been eliminated in
    these patches :)
    
    This patch:
    
    Provide notifier_call_chain with an option to call only a specified number 
of
    notifiers and also record the number of call to notifiers made.
    
    The need for this enhancement was identified in the post entitled
    "Slab - Eliminate lock_cpu_hotplug from slab"
    (http://lkml.org/lkml/2006/10/28/92) by Ravikiran G Thirumalai and
    Andrew Morton.
    
    This patch adds two additional parameters to notifier_call_chain API namely
     - int nr_to_calls : Number of notifier_functions to be called.
                     The don't care value is -1.
    
     - unsigned int *nr_calls : Records the total number of notifier_funtions
                            called by notifier_call_chain. The don't care
                            value is NULL.
    
    [EMAIL PROTECTED]: build fix]
    Credit: Andrew Morton <[EMAIL PROTECTED]>
    Signed-off-by: Gautham R Shenoy <[EMAIL PROTECTED]>
    Signed-off-by: Michal Piotrowski <[EMAIL PROTECTED]>
    Signed-off-by: Andrew Morton <[EMAIL PROTECTED]>
    Signed-off-by: Linus Torvalds <[EMAIL PROTECTED]>
---
 include/linux/notifier.h |   52 +++++++++++++++-----------
 kernel/sys.c             |   94 +++++++++++++++++++++++++++++++++++++--------
 2 files changed, 107 insertions(+), 39 deletions(-)

diff --git a/include/linux/notifier.h b/include/linux/notifier.h
index 10a43ed..e34221b 100644
--- a/include/linux/notifier.h
+++ b/include/linux/notifier.h
@@ -112,32 +112,40 @@ extern void srcu_init_notifier_head(struct 
srcu_notifier_head *nh);
 
 #ifdef __KERNEL__
 
-extern int atomic_notifier_chain_register(struct atomic_notifier_head *,
-               struct notifier_block *);
-extern int blocking_notifier_chain_register(struct blocking_notifier_head *,
-               struct notifier_block *);
-extern int raw_notifier_chain_register(struct raw_notifier_head *,
-               struct notifier_block *);
-extern int srcu_notifier_chain_register(struct srcu_notifier_head *,
-               struct notifier_block *);
-
-extern int atomic_notifier_chain_unregister(struct atomic_notifier_head *,
-               struct notifier_block *);
-extern int blocking_notifier_chain_unregister(struct blocking_notifier_head *,
-               struct notifier_block *);
-extern int raw_notifier_chain_unregister(struct raw_notifier_head *,
-               struct notifier_block *);
-extern int srcu_notifier_chain_unregister(struct srcu_notifier_head *,
-               struct notifier_block *);
-
-extern int atomic_notifier_call_chain(struct atomic_notifier_head *,
+extern int atomic_notifier_chain_register(struct atomic_notifier_head *nh,
+               struct notifier_block *nb);
+extern int blocking_notifier_chain_register(struct blocking_notifier_head *nh,
+               struct notifier_block *nb);
+extern int raw_notifier_chain_register(struct raw_notifier_head *nh,
+               struct notifier_block *nb);
+extern int srcu_notifier_chain_register(struct srcu_notifier_head *nh,
+               struct notifier_block *nb);
+
+extern int atomic_notifier_chain_unregister(struct atomic_notifier_head *nh,
+               struct notifier_block *nb);
+extern int blocking_notifier_chain_unregister(struct blocking_notifier_head 
*nh,
+               struct notifier_block *nb);
+extern int raw_notifier_chain_unregister(struct raw_notifier_head *nh,
+               struct notifier_block *nb);
+extern int srcu_notifier_chain_unregister(struct srcu_notifier_head *nh,
+               struct notifier_block *nb);
+
+extern int atomic_notifier_call_chain(struct atomic_notifier_head *nh,
                unsigned long val, void *v);
-extern int blocking_notifier_call_chain(struct blocking_notifier_head *,
+extern int __atomic_notifier_call_chain(struct atomic_notifier_head *nh,
+       unsigned long val, void *v, int nr_to_call, int *nr_calls);
+extern int blocking_notifier_call_chain(struct blocking_notifier_head *nh,
                unsigned long val, void *v);
-extern int raw_notifier_call_chain(struct raw_notifier_head *,
+extern int __blocking_notifier_call_chain(struct blocking_notifier_head *nh,
+       unsigned long val, void *v, int nr_to_call, int *nr_calls);
+extern int raw_notifier_call_chain(struct raw_notifier_head *nh,
                unsigned long val, void *v);
-extern int srcu_notifier_call_chain(struct srcu_notifier_head *,
+extern int __raw_notifier_call_chain(struct raw_notifier_head *nh,
+       unsigned long val, void *v, int nr_to_call, int *nr_calls);
+extern int srcu_notifier_call_chain(struct srcu_notifier_head *nh,
                unsigned long val, void *v);
+extern int __srcu_notifier_call_chain(struct srcu_notifier_head *nh,
+       unsigned long val, void *v, int nr_to_call, int *nr_calls);
 
 #define NOTIFY_DONE            0x0000          /* Don't care */
 #define NOTIFY_OK              0x0001          /* Suits me */
diff --git a/kernel/sys.c b/kernel/sys.c
index 8ecfe34..d4985df 100644
--- a/kernel/sys.c
+++ b/kernel/sys.c
@@ -134,19 +134,39 @@ static int notifier_chain_unregister(struct 
notifier_block **nl,
        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 __kprobes notifier_call_chain(struct notifier_block **nl,
-               unsigned long val, void *v)
+                                       unsigned long val, void *v,
+                                       int nr_to_call, int *nr_calls)
 {
        int ret = NOTIFY_DONE;
        struct notifier_block *nb, *next_nb;
 
        nb = rcu_dereference(*nl);
-       while (nb) {
+
+       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;
 }
@@ -205,10 +225,12 @@ int atomic_notifier_chain_unregister(struct 
atomic_notifier_head *nh,
 EXPORT_SYMBOL_GPL(atomic_notifier_chain_unregister);
 
 /**
- *     atomic_notifier_call_chain - Call functions in an atomic notifier chain
+ *     __atomic_notifier_call_chain - Call functions in an atomic notifier 
chain
  *     @nh: Pointer to head of the atomic notifier chain
  *     @val: Value passed unmodified to notifier function
  *     @v: Pointer passed unmodified to notifier function
+ *     @nr_to_call: See the comment for notifier_call_chain.
+ *     @nr_calls: See the comment for notifier_call_chain.
  *
  *     Calls each function in a notifier chain in turn.  The functions
  *     run in an atomic context, so they must not block.
@@ -222,19 +244,27 @@ EXPORT_SYMBOL_GPL(atomic_notifier_chain_unregister);
  *     of the last notifier function called.
  */
  
-int __kprobes atomic_notifier_call_chain(struct atomic_notifier_head *nh,
-               unsigned long val, void *v)
+int __kprobes __atomic_notifier_call_chain(struct atomic_notifier_head *nh,
+                                       unsigned long val, void *v,
+                                       int nr_to_call, int *nr_calls)
 {
        int ret;
 
        rcu_read_lock();
-       ret = notifier_call_chain(&nh->head, val, v);
+       ret = notifier_call_chain(&nh->head, val, v, nr_to_call, nr_calls);
        rcu_read_unlock();
        return ret;
 }
 
-EXPORT_SYMBOL_GPL(atomic_notifier_call_chain);
+EXPORT_SYMBOL_GPL(__atomic_notifier_call_chain);
+
+int __kprobes atomic_notifier_call_chain(struct atomic_notifier_head *nh,
+               unsigned long val, void *v)
+{
+       return __atomic_notifier_call_chain(nh, val, v, -1, NULL);
+}
 
+EXPORT_SYMBOL_GPL(atomic_notifier_call_chain);
 /*
  *     Blocking notifier chain routines.  All access to the chain is
  *     synchronized by an rwsem.
@@ -304,10 +334,12 @@ int blocking_notifier_chain_unregister(struct 
blocking_notifier_head *nh,
 EXPORT_SYMBOL_GPL(blocking_notifier_chain_unregister);
 
 /**
- *     blocking_notifier_call_chain - Call functions in a blocking notifier 
chain
+ *     __blocking_notifier_call_chain - Call functions in a blocking notifier 
chain
  *     @nh: 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: See comment for notifier_call_chain.
+ *     @nr_calls: See comment for notifier_call_chain.
  *
  *     Calls each function in a notifier chain in turn.  The functions
  *     run in a process context, so they are allowed to block.
@@ -320,8 +352,9 @@ EXPORT_SYMBOL_GPL(blocking_notifier_chain_unregister);
  *     of the last notifier function called.
  */
  
-int blocking_notifier_call_chain(struct blocking_notifier_head *nh,
-               unsigned long val, void *v)
+int __blocking_notifier_call_chain(struct blocking_notifier_head *nh,
+                                  unsigned long val, void *v,
+                                  int nr_to_call, int *nr_calls)
 {
        int ret = NOTIFY_DONE;
 
@@ -332,12 +365,19 @@ int blocking_notifier_call_chain(struct 
blocking_notifier_head *nh,
         */
        if (rcu_dereference(nh->head)) {
                down_read(&nh->rwsem);
-               ret = notifier_call_chain(&nh->head, val, v);
+               ret = notifier_call_chain(&nh->head, val, v, nr_to_call,
+                                       nr_calls);
                up_read(&nh->rwsem);
        }
        return ret;
 }
+EXPORT_SYMBOL_GPL(__blocking_notifier_call_chain);
 
+int blocking_notifier_call_chain(struct blocking_notifier_head *nh,
+               unsigned long val, void *v)
+{
+       return __blocking_notifier_call_chain(nh, val, v, -1, NULL);
+}
 EXPORT_SYMBOL_GPL(blocking_notifier_call_chain);
 
 /*
@@ -383,10 +423,12 @@ int raw_notifier_chain_unregister(struct 
raw_notifier_head *nh,
 EXPORT_SYMBOL_GPL(raw_notifier_chain_unregister);
 
 /**
- *     raw_notifier_call_chain - Call functions in a raw notifier chain
+ *     __raw_notifier_call_chain - Call functions in a raw notifier chain
  *     @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
  *
  *     Calls each function in a notifier chain in turn.  The functions
  *     run in an undefined context.
@@ -400,10 +442,19 @@ EXPORT_SYMBOL_GPL(raw_notifier_chain_unregister);
  *     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)
+{
+       return notifier_call_chain(&nh->head, val, v, nr_to_call, nr_calls);
+}
+
+EXPORT_SYMBOL_GPL(__raw_notifier_call_chain);
+
 int raw_notifier_call_chain(struct raw_notifier_head *nh,
                unsigned long val, void *v)
 {
-       return notifier_call_chain(&nh->head, val, v);
+       return __raw_notifier_call_chain(nh, val, v, -1, NULL);
 }
 
 EXPORT_SYMBOL_GPL(raw_notifier_call_chain);
@@ -478,10 +529,12 @@ int srcu_notifier_chain_unregister(struct 
srcu_notifier_head *nh,
 EXPORT_SYMBOL_GPL(srcu_notifier_chain_unregister);
 
 /**
- *     srcu_notifier_call_chain - Call functions in an SRCU notifier chain
+ *     __srcu_notifier_call_chain - Call functions in an SRCU notifier chain
  *     @nh: Pointer to head of the SRCU 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
  *
  *     Calls each function in a notifier chain in turn.  The functions
  *     run in a process context, so they are allowed to block.
@@ -494,18 +547,25 @@ EXPORT_SYMBOL_GPL(srcu_notifier_chain_unregister);
  *     of the last notifier function called.
  */
 
-int srcu_notifier_call_chain(struct srcu_notifier_head *nh,
-               unsigned long val, void *v)
+int __srcu_notifier_call_chain(struct srcu_notifier_head *nh,
+                              unsigned long val, void *v,
+                              int nr_to_call, int *nr_calls)
 {
        int ret;
        int idx;
 
        idx = srcu_read_lock(&nh->srcu);
-       ret = notifier_call_chain(&nh->head, val, v);
+       ret = notifier_call_chain(&nh->head, val, v, nr_to_call, nr_calls);
        srcu_read_unlock(&nh->srcu, idx);
        return ret;
 }
+EXPORT_SYMBOL_GPL(__srcu_notifier_call_chain);
 
+int srcu_notifier_call_chain(struct srcu_notifier_head *nh,
+               unsigned long val, void *v)
+{
+       return __srcu_notifier_call_chain(nh, val, v, -1, NULL);
+}
 EXPORT_SYMBOL_GPL(srcu_notifier_call_chain);
 
 /**
-
To unsubscribe from this list: send the line "unsubscribe git-commits-head" in
the body of a message to [EMAIL PROTECTED]
More majordomo info at  http://vger.kernel.org/majordomo-info.html

Reply via email to