diff options
Diffstat (limited to 'kernel')
-rw-r--r-- | kernel/sys.c | 94 |
1 files changed, 77 insertions, 17 deletions
diff --git a/kernel/sys.c b/kernel/sys.c index 8ecfe3473779..d4985df21b60 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 | |||
137 | static int __kprobes notifier_call_chain(struct notifier_block **nl, | 150 | static 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, | |||
205 | EXPORT_SYMBOL_GPL(atomic_notifier_chain_unregister); | 225 | EXPORT_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 | ||
225 | int __kprobes atomic_notifier_call_chain(struct atomic_notifier_head *nh, | 247 | int __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 | ||
236 | EXPORT_SYMBOL_GPL(atomic_notifier_call_chain); | 259 | EXPORT_SYMBOL_GPL(__atomic_notifier_call_chain); |
260 | |||
261 | int __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 | ||
267 | EXPORT_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, | |||
304 | EXPORT_SYMBOL_GPL(blocking_notifier_chain_unregister); | 334 | EXPORT_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 | ||
323 | int blocking_notifier_call_chain(struct blocking_notifier_head *nh, | 355 | int __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 | } |
374 | EXPORT_SYMBOL_GPL(__blocking_notifier_call_chain); | ||
340 | 375 | ||
376 | int 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 | } | ||
341 | EXPORT_SYMBOL_GPL(blocking_notifier_call_chain); | 381 | EXPORT_SYMBOL_GPL(blocking_notifier_call_chain); |
342 | 382 | ||
343 | /* | 383 | /* |
@@ -383,10 +423,12 @@ int raw_notifier_chain_unregister(struct raw_notifier_head *nh, | |||
383 | EXPORT_SYMBOL_GPL(raw_notifier_chain_unregister); | 423 | EXPORT_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 | ||
445 | int __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 | |||
452 | EXPORT_SYMBOL_GPL(__raw_notifier_call_chain); | ||
453 | |||
403 | int raw_notifier_call_chain(struct raw_notifier_head *nh, | 454 | int 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 | ||
409 | EXPORT_SYMBOL_GPL(raw_notifier_call_chain); | 460 | EXPORT_SYMBOL_GPL(raw_notifier_call_chain); |
@@ -478,10 +529,12 @@ int srcu_notifier_chain_unregister(struct srcu_notifier_head *nh, | |||
478 | EXPORT_SYMBOL_GPL(srcu_notifier_chain_unregister); | 529 | EXPORT_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 | ||
497 | int srcu_notifier_call_chain(struct srcu_notifier_head *nh, | 550 | int __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 | } |
562 | EXPORT_SYMBOL_GPL(__srcu_notifier_call_chain); | ||
508 | 563 | ||
564 | int 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 | } | ||
509 | EXPORT_SYMBOL_GPL(srcu_notifier_call_chain); | 569 | EXPORT_SYMBOL_GPL(srcu_notifier_call_chain); |
510 | 570 | ||
511 | /** | 571 | /** |