diff options
Diffstat (limited to 'kernel/sys.c')
| -rw-r--r-- | kernel/sys.c | 98 |
1 files changed, 79 insertions, 19 deletions
diff --git a/kernel/sys.c b/kernel/sys.c index 926bf9d7ac45..cdb7e9457ba6 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 | /** |
| @@ -881,7 +941,7 @@ asmlinkage long sys_reboot(int magic1, int magic2, unsigned int cmd, void __user | |||
| 881 | #ifdef CONFIG_SOFTWARE_SUSPEND | 941 | #ifdef CONFIG_SOFTWARE_SUSPEND |
| 882 | case LINUX_REBOOT_CMD_SW_SUSPEND: | 942 | case LINUX_REBOOT_CMD_SW_SUSPEND: |
| 883 | { | 943 | { |
| 884 | int ret = pm_suspend(PM_SUSPEND_DISK); | 944 | int ret = hibernate(); |
| 885 | unlock_kernel(); | 945 | unlock_kernel(); |
| 886 | return ret; | 946 | return ret; |
| 887 | } | 947 | } |
| @@ -1292,7 +1352,7 @@ asmlinkage long sys_setfsuid(uid_t uid) | |||
| 1292 | } | 1352 | } |
| 1293 | 1353 | ||
| 1294 | /* | 1354 | /* |
| 1295 | * Samma på svenska.. | 1355 | * Samma pÃ¥ svenska.. |
| 1296 | */ | 1356 | */ |
| 1297 | asmlinkage long sys_setfsgid(gid_t gid) | 1357 | asmlinkage long sys_setfsgid(gid_t gid) |
| 1298 | { | 1358 | { |
