aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorGautham R Shenoy <ego@in.ibm.com>2007-05-09 05:34:02 -0400
committerLinus Torvalds <torvalds@woody.linux-foundation.org>2007-05-09 15:30:51 -0400
commit6f7cc11aa6c7d5002e16096c7590944daece70ed (patch)
tree68a11e4b67189c44ac0f3ab579e52e134d479cf5
parent7c9cb38302e78d24e37f7d8a2ea7eed4ae5f2fa7 (diff)
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. [michal.k.k.piotrowski@gmail.com: build fix] Credit: Andrew Morton <akpm@osdl.org> Signed-off-by: Gautham R Shenoy <ego@in.ibm.com> Signed-off-by: Michal Piotrowski <michal.k.k.piotrowski@gmail.com> Signed-off-by: Andrew Morton <akpm@linux-foundation.org> Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
-rw-r--r--include/linux/notifier.h52
-rw-r--r--kernel/sys.c94
2 files changed, 107 insertions, 39 deletions
diff --git a/include/linux/notifier.h b/include/linux/notifier.h
index 10a43ed0527..e34221bf894 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);
112 112
113#ifdef __KERNEL__ 113#ifdef __KERNEL__
114 114
115extern int atomic_notifier_chain_register(struct atomic_notifier_head *, 115extern int atomic_notifier_chain_register(struct atomic_notifier_head *nh,
116 struct notifier_block *); 116 struct notifier_block *nb);
117extern int blocking_notifier_chain_register(struct blocking_notifier_head *, 117extern int blocking_notifier_chain_register(struct blocking_notifier_head *nh,
118 struct notifier_block *); 118 struct notifier_block *nb);
119extern int raw_notifier_chain_register(struct raw_notifier_head *, 119extern int raw_notifier_chain_register(struct raw_notifier_head *nh,
120 struct notifier_block *); 120 struct notifier_block *nb);
121extern int srcu_notifier_chain_register(struct srcu_notifier_head *, 121extern int srcu_notifier_chain_register(struct srcu_notifier_head *nh,
122 struct notifier_block *); 122 struct notifier_block *nb);
123 123
124extern int atomic_notifier_chain_unregister(struct atomic_notifier_head *, 124extern int atomic_notifier_chain_unregister(struct atomic_notifier_head *nh,
125 struct notifier_block *); 125 struct notifier_block *nb);
126extern int blocking_notifier_chain_unregister(struct blocking_notifier_head *, 126extern int blocking_notifier_chain_unregister(struct blocking_notifier_head *nh,
127 struct notifier_block *); 127 struct notifier_block *nb);
128extern int raw_notifier_chain_unregister(struct raw_notifier_head *, 128extern int raw_notifier_chain_unregister(struct raw_notifier_head *nh,
129 struct notifier_block *); 129 struct notifier_block *nb);
130extern int srcu_notifier_chain_unregister(struct srcu_notifier_head *, 130extern int srcu_notifier_chain_unregister(struct srcu_notifier_head *nh,
131 struct notifier_block *); 131 struct notifier_block *nb);
132 132
133extern int atomic_notifier_call_chain(struct atomic_notifier_head *, 133extern int atomic_notifier_call_chain(struct atomic_notifier_head *nh,
134 unsigned long val, void *v); 134 unsigned long val, void *v);
135extern int blocking_notifier_call_chain(struct blocking_notifier_head *, 135extern int __atomic_notifier_call_chain(struct atomic_notifier_head *nh,
136 unsigned long val, void *v, int nr_to_call, int *nr_calls);
137extern int blocking_notifier_call_chain(struct blocking_notifier_head *nh,
136 unsigned long val, void *v); 138 unsigned long val, void *v);
137extern int raw_notifier_call_chain(struct raw_notifier_head *, 139extern int __blocking_notifier_call_chain(struct blocking_notifier_head *nh,
140 unsigned long val, void *v, int nr_to_call, int *nr_calls);
141extern int raw_notifier_call_chain(struct raw_notifier_head *nh,
138 unsigned long val, void *v); 142 unsigned long val, void *v);
139extern int srcu_notifier_call_chain(struct srcu_notifier_head *, 143extern int __raw_notifier_call_chain(struct raw_notifier_head *nh,
144 unsigned long val, void *v, int nr_to_call, int *nr_calls);
145extern int srcu_notifier_call_chain(struct srcu_notifier_head *nh,
140 unsigned long val, void *v); 146 unsigned long val, void *v);
147extern int __srcu_notifier_call_chain(struct srcu_notifier_head *nh,
148 unsigned long val, void *v, int nr_to_call, int *nr_calls);
141 149
142#define NOTIFY_DONE 0x0000 /* Don't care */ 150#define NOTIFY_DONE 0x0000 /* Don't care */
143#define NOTIFY_OK 0x0001 /* Suits me */ 151#define NOTIFY_OK 0x0001 /* Suits me */
diff --git a/kernel/sys.c b/kernel/sys.c
index 8ecfe347377..d4985df21b6 100644
--- a/kernel/sys.c
+++ b/kernel/sys.c
@@ -134,19 +134,39 @@ static int notifier_chain_unregister(struct notifier_block **nl,
134 return -ENOENT; 134 return -ENOENT;
135} 135}
136 136
137/**
138 * notifier_call_chain - Informs the registered notifiers about an event.
139 * @nl: Pointer to head of the blocking notifier chain
140 * @val: Value passed unmodified to notifier function
141 * @v: Pointer passed unmodified to notifier function
142 * @nr_to_call: Number of notifier functions to be called. Don't care
143 * value of this parameter is -1.
144 * @nr_calls: Records the number of notifications sent. Don't care
145 * value of this field is NULL.
146 * @returns: notifier_call_chain returns the value returned by the
147 * last notifier function called.
148 */
149
137static int __kprobes notifier_call_chain(struct notifier_block **nl, 150static int __kprobes notifier_call_chain(struct notifier_block **nl,
138 unsigned long val, void *v) 151 unsigned long val, void *v,
152 int nr_to_call, int *nr_calls)
139{ 153{
140 int ret = NOTIFY_DONE; 154 int ret = NOTIFY_DONE;
141 struct notifier_block *nb, *next_nb; 155 struct notifier_block *nb, *next_nb;
142 156
143 nb = rcu_dereference(*nl); 157 nb = rcu_dereference(*nl);
144 while (nb) { 158
159 while (nb && nr_to_call) {
145 next_nb = rcu_dereference(nb->next); 160 next_nb = rcu_dereference(nb->next);
146 ret = nb->notifier_call(nb, val, v); 161 ret = nb->notifier_call(nb, val, v);
162
163 if (nr_calls)
164 (*nr_calls)++;
165
147 if ((ret & NOTIFY_STOP_MASK) == NOTIFY_STOP_MASK) 166 if ((ret & NOTIFY_STOP_MASK) == NOTIFY_STOP_MASK)
148 break; 167 break;
149 nb = next_nb; 168 nb = next_nb;
169 nr_to_call--;
150 } 170 }
151 return ret; 171 return ret;
152} 172}
@@ -205,10 +225,12 @@ int atomic_notifier_chain_unregister(struct atomic_notifier_head *nh,
205EXPORT_SYMBOL_GPL(atomic_notifier_chain_unregister); 225EXPORT_SYMBOL_GPL(atomic_notifier_chain_unregister);
206 226
207/** 227/**
208 * atomic_notifier_call_chain - Call functions in an atomic notifier chain 228 * __atomic_notifier_call_chain - Call functions in an atomic notifier chain
209 * @nh: Pointer to head of the atomic notifier chain 229 * @nh: Pointer to head of the atomic notifier chain
210 * @val: Value passed unmodified to notifier function 230 * @val: Value passed unmodified to notifier function
211 * @v: Pointer passed unmodified to notifier function 231 * @v: Pointer passed unmodified to notifier function
232 * @nr_to_call: See the comment for notifier_call_chain.
233 * @nr_calls: See the comment for notifier_call_chain.
212 * 234 *
213 * Calls each function in a notifier chain in turn. The functions 235 * Calls each function in a notifier chain in turn. The functions
214 * run in an atomic context, so they must not block. 236 * run in an atomic context, so they must not block.
@@ -222,19 +244,27 @@ EXPORT_SYMBOL_GPL(atomic_notifier_chain_unregister);
222 * of the last notifier function called. 244 * of the last notifier function called.
223 */ 245 */
224 246
225int __kprobes atomic_notifier_call_chain(struct atomic_notifier_head *nh, 247int __kprobes __atomic_notifier_call_chain(struct atomic_notifier_head *nh,
226 unsigned long val, void *v) 248 unsigned long val, void *v,
249 int nr_to_call, int *nr_calls)
227{ 250{
228 int ret; 251 int ret;
229 252
230 rcu_read_lock(); 253 rcu_read_lock();
231 ret = notifier_call_chain(&nh->head, val, v); 254 ret = notifier_call_chain(&nh->head, val, v, nr_to_call, nr_calls);
232 rcu_read_unlock(); 255 rcu_read_unlock();
233 return ret; 256 return ret;
234} 257}
235 258
236EXPORT_SYMBOL_GPL(atomic_notifier_call_chain); 259EXPORT_SYMBOL_GPL(__atomic_notifier_call_chain);
260
261int __kprobes atomic_notifier_call_chain(struct atomic_notifier_head *nh,
262 unsigned long val, void *v)
263{
264 return __atomic_notifier_call_chain(nh, val, v, -1, NULL);
265}
237 266
267EXPORT_SYMBOL_GPL(atomic_notifier_call_chain);
238/* 268/*
239 * Blocking notifier chain routines. All access to the chain is 269 * Blocking notifier chain routines. All access to the chain is
240 * synchronized by an rwsem. 270 * synchronized by an rwsem.
@@ -304,10 +334,12 @@ int blocking_notifier_chain_unregister(struct blocking_notifier_head *nh,
304EXPORT_SYMBOL_GPL(blocking_notifier_chain_unregister); 334EXPORT_SYMBOL_GPL(blocking_notifier_chain_unregister);
305 335
306/** 336/**
307 * blocking_notifier_call_chain - Call functions in a blocking notifier chain 337 * __blocking_notifier_call_chain - Call functions in a blocking notifier chain
308 * @nh: Pointer to head of the blocking notifier chain 338 * @nh: Pointer to head of the blocking notifier chain
309 * @val: Value passed unmodified to notifier function 339 * @val: Value passed unmodified to notifier function
310 * @v: Pointer passed unmodified to notifier function 340 * @v: Pointer passed unmodified to notifier function
341 * @nr_to_call: See comment for notifier_call_chain.
342 * @nr_calls: See comment for notifier_call_chain.
311 * 343 *
312 * Calls each function in a notifier chain in turn. The functions 344 * Calls each function in a notifier chain in turn. The functions
313 * run in a process context, so they are allowed to block. 345 * run in a process context, so they are allowed to block.
@@ -320,8 +352,9 @@ EXPORT_SYMBOL_GPL(blocking_notifier_chain_unregister);
320 * of the last notifier function called. 352 * of the last notifier function called.
321 */ 353 */
322 354
323int blocking_notifier_call_chain(struct blocking_notifier_head *nh, 355int __blocking_notifier_call_chain(struct blocking_notifier_head *nh,
324 unsigned long val, void *v) 356 unsigned long val, void *v,
357 int nr_to_call, int *nr_calls)
325{ 358{
326 int ret = NOTIFY_DONE; 359 int ret = NOTIFY_DONE;
327 360
@@ -332,12 +365,19 @@ int blocking_notifier_call_chain(struct blocking_notifier_head *nh,
332 */ 365 */
333 if (rcu_dereference(nh->head)) { 366 if (rcu_dereference(nh->head)) {
334 down_read(&nh->rwsem); 367 down_read(&nh->rwsem);
335 ret = notifier_call_chain(&nh->head, val, v); 368 ret = notifier_call_chain(&nh->head, val, v, nr_to_call,
369 nr_calls);
336 up_read(&nh->rwsem); 370 up_read(&nh->rwsem);
337 } 371 }
338 return ret; 372 return ret;
339} 373}
374EXPORT_SYMBOL_GPL(__blocking_notifier_call_chain);
340 375
376int blocking_notifier_call_chain(struct blocking_notifier_head *nh,
377 unsigned long val, void *v)
378{
379 return __blocking_notifier_call_chain(nh, val, v, -1, NULL);
380}
341EXPORT_SYMBOL_GPL(blocking_notifier_call_chain); 381EXPORT_SYMBOL_GPL(blocking_notifier_call_chain);
342 382
343/* 383/*
@@ -383,10 +423,12 @@ int raw_notifier_chain_unregister(struct raw_notifier_head *nh,
383EXPORT_SYMBOL_GPL(raw_notifier_chain_unregister); 423EXPORT_SYMBOL_GPL(raw_notifier_chain_unregister);
384 424
385/** 425/**
386 * raw_notifier_call_chain - Call functions in a raw notifier chain 426 * __raw_notifier_call_chain - Call functions in a raw notifier chain
387 * @nh: Pointer to head of the raw notifier chain 427 * @nh: Pointer to head of the raw notifier chain
388 * @val: Value passed unmodified to notifier function 428 * @val: Value passed unmodified to notifier function
389 * @v: Pointer passed unmodified to notifier function 429 * @v: Pointer passed unmodified to notifier function
430 * @nr_to_call: See comment for notifier_call_chain.
431 * @nr_calls: See comment for notifier_call_chain
390 * 432 *
391 * Calls each function in a notifier chain in turn. The functions 433 * Calls each function in a notifier chain in turn. The functions
392 * run in an undefined context. 434 * run in an undefined context.
@@ -400,10 +442,19 @@ EXPORT_SYMBOL_GPL(raw_notifier_chain_unregister);
400 * of the last notifier function called. 442 * of the last notifier function called.
401 */ 443 */
402 444
445int __raw_notifier_call_chain(struct raw_notifier_head *nh,
446 unsigned long val, void *v,
447 int nr_to_call, int *nr_calls)
448{
449 return notifier_call_chain(&nh->head, val, v, nr_to_call, nr_calls);
450}
451
452EXPORT_SYMBOL_GPL(__raw_notifier_call_chain);
453
403int raw_notifier_call_chain(struct raw_notifier_head *nh, 454int raw_notifier_call_chain(struct raw_notifier_head *nh,
404 unsigned long val, void *v) 455 unsigned long val, void *v)
405{ 456{
406 return notifier_call_chain(&nh->head, val, v); 457 return __raw_notifier_call_chain(nh, val, v, -1, NULL);
407} 458}
408 459
409EXPORT_SYMBOL_GPL(raw_notifier_call_chain); 460EXPORT_SYMBOL_GPL(raw_notifier_call_chain);
@@ -478,10 +529,12 @@ int srcu_notifier_chain_unregister(struct srcu_notifier_head *nh,
478EXPORT_SYMBOL_GPL(srcu_notifier_chain_unregister); 529EXPORT_SYMBOL_GPL(srcu_notifier_chain_unregister);
479 530
480/** 531/**
481 * srcu_notifier_call_chain - Call functions in an SRCU notifier chain 532 * __srcu_notifier_call_chain - Call functions in an SRCU notifier chain
482 * @nh: Pointer to head of the SRCU notifier chain 533 * @nh: Pointer to head of the SRCU notifier chain
483 * @val: Value passed unmodified to notifier function 534 * @val: Value passed unmodified to notifier function
484 * @v: Pointer passed unmodified to notifier function 535 * @v: Pointer passed unmodified to notifier function
536 * @nr_to_call: See comment for notifier_call_chain.
537 * @nr_calls: See comment for notifier_call_chain
485 * 538 *
486 * Calls each function in a notifier chain in turn. The functions 539 * Calls each function in a notifier chain in turn. The functions
487 * run in a process context, so they are allowed to block. 540 * run in a process context, so they are allowed to block.
@@ -494,18 +547,25 @@ EXPORT_SYMBOL_GPL(srcu_notifier_chain_unregister);
494 * of the last notifier function called. 547 * of the last notifier function called.
495 */ 548 */
496 549
497int srcu_notifier_call_chain(struct srcu_notifier_head *nh, 550int __srcu_notifier_call_chain(struct srcu_notifier_head *nh,
498 unsigned long val, void *v) 551 unsigned long val, void *v,
552 int nr_to_call, int *nr_calls)
499{ 553{
500 int ret; 554 int ret;
501 int idx; 555 int idx;
502 556
503 idx = srcu_read_lock(&nh->srcu); 557 idx = srcu_read_lock(&nh->srcu);
504 ret = notifier_call_chain(&nh->head, val, v); 558 ret = notifier_call_chain(&nh->head, val, v, nr_to_call, nr_calls);
505 srcu_read_unlock(&nh->srcu, idx); 559 srcu_read_unlock(&nh->srcu, idx);
506 return ret; 560 return ret;
507} 561}
562EXPORT_SYMBOL_GPL(__srcu_notifier_call_chain);
508 563
564int srcu_notifier_call_chain(struct srcu_notifier_head *nh,
565 unsigned long val, void *v)
566{
567 return __srcu_notifier_call_chain(nh, val, v, -1, NULL);
568}
509EXPORT_SYMBOL_GPL(srcu_notifier_call_chain); 569EXPORT_SYMBOL_GPL(srcu_notifier_call_chain);
510 570
511/** 571/**