diff options
Diffstat (limited to 'kernel/timer.c')
-rw-r--r-- | kernel/timer.c | 68 |
1 files changed, 57 insertions, 11 deletions
diff --git a/kernel/timer.c b/kernel/timer.c index 13dd64fe143d..ef1c385bc572 100644 --- a/kernel/timer.c +++ b/kernel/timer.c | |||
@@ -491,14 +491,18 @@ static inline void debug_timer_free(struct timer_list *timer) | |||
491 | debug_object_free(timer, &timer_debug_descr); | 491 | debug_object_free(timer, &timer_debug_descr); |
492 | } | 492 | } |
493 | 493 | ||
494 | static void __init_timer(struct timer_list *timer); | 494 | static void __init_timer(struct timer_list *timer, |
495 | const char *name, | ||
496 | struct lock_class_key *key); | ||
495 | 497 | ||
496 | void init_timer_on_stack(struct timer_list *timer) | 498 | void init_timer_on_stack_key(struct timer_list *timer, |
499 | const char *name, | ||
500 | struct lock_class_key *key) | ||
497 | { | 501 | { |
498 | debug_object_init_on_stack(timer, &timer_debug_descr); | 502 | debug_object_init_on_stack(timer, &timer_debug_descr); |
499 | __init_timer(timer); | 503 | __init_timer(timer, name, key); |
500 | } | 504 | } |
501 | EXPORT_SYMBOL_GPL(init_timer_on_stack); | 505 | EXPORT_SYMBOL_GPL(init_timer_on_stack_key); |
502 | 506 | ||
503 | void destroy_timer_on_stack(struct timer_list *timer) | 507 | void destroy_timer_on_stack(struct timer_list *timer) |
504 | { | 508 | { |
@@ -512,7 +516,9 @@ static inline void debug_timer_activate(struct timer_list *timer) { } | |||
512 | static inline void debug_timer_deactivate(struct timer_list *timer) { } | 516 | static inline void debug_timer_deactivate(struct timer_list *timer) { } |
513 | #endif | 517 | #endif |
514 | 518 | ||
515 | static void __init_timer(struct timer_list *timer) | 519 | static void __init_timer(struct timer_list *timer, |
520 | const char *name, | ||
521 | struct lock_class_key *key) | ||
516 | { | 522 | { |
517 | timer->entry.next = NULL; | 523 | timer->entry.next = NULL; |
518 | timer->base = __raw_get_cpu_var(tvec_bases); | 524 | timer->base = __raw_get_cpu_var(tvec_bases); |
@@ -521,6 +527,7 @@ static void __init_timer(struct timer_list *timer) | |||
521 | timer->start_pid = -1; | 527 | timer->start_pid = -1; |
522 | memset(timer->start_comm, 0, TASK_COMM_LEN); | 528 | memset(timer->start_comm, 0, TASK_COMM_LEN); |
523 | #endif | 529 | #endif |
530 | lockdep_init_map(&timer->lockdep_map, name, key, 0); | ||
524 | } | 531 | } |
525 | 532 | ||
526 | /** | 533 | /** |
@@ -530,19 +537,23 @@ static void __init_timer(struct timer_list *timer) | |||
530 | * init_timer() must be done to a timer prior calling *any* of the | 537 | * init_timer() must be done to a timer prior calling *any* of the |
531 | * other timer functions. | 538 | * other timer functions. |
532 | */ | 539 | */ |
533 | void init_timer(struct timer_list *timer) | 540 | void init_timer_key(struct timer_list *timer, |
541 | const char *name, | ||
542 | struct lock_class_key *key) | ||
534 | { | 543 | { |
535 | debug_timer_init(timer); | 544 | debug_timer_init(timer); |
536 | __init_timer(timer); | 545 | __init_timer(timer, name, key); |
537 | } | 546 | } |
538 | EXPORT_SYMBOL(init_timer); | 547 | EXPORT_SYMBOL(init_timer_key); |
539 | 548 | ||
540 | void init_timer_deferrable(struct timer_list *timer) | 549 | void init_timer_deferrable_key(struct timer_list *timer, |
550 | const char *name, | ||
551 | struct lock_class_key *key) | ||
541 | { | 552 | { |
542 | init_timer(timer); | 553 | init_timer_key(timer, name, key); |
543 | timer_set_deferrable(timer); | 554 | timer_set_deferrable(timer); |
544 | } | 555 | } |
545 | EXPORT_SYMBOL(init_timer_deferrable); | 556 | EXPORT_SYMBOL(init_timer_deferrable_key); |
546 | 557 | ||
547 | static inline void detach_timer(struct timer_list *timer, | 558 | static inline void detach_timer(struct timer_list *timer, |
548 | int clear_pending) | 559 | int clear_pending) |
@@ -789,6 +800,15 @@ EXPORT_SYMBOL(try_to_del_timer_sync); | |||
789 | */ | 800 | */ |
790 | int del_timer_sync(struct timer_list *timer) | 801 | int del_timer_sync(struct timer_list *timer) |
791 | { | 802 | { |
803 | #ifdef CONFIG_LOCKDEP | ||
804 | unsigned long flags; | ||
805 | |||
806 | local_irq_save(flags); | ||
807 | lock_map_acquire(&timer->lockdep_map); | ||
808 | lock_map_release(&timer->lockdep_map); | ||
809 | local_irq_restore(flags); | ||
810 | #endif | ||
811 | |||
792 | for (;;) { | 812 | for (;;) { |
793 | int ret = try_to_del_timer_sync(timer); | 813 | int ret = try_to_del_timer_sync(timer); |
794 | if (ret >= 0) | 814 | if (ret >= 0) |
@@ -861,10 +881,36 @@ static inline void __run_timers(struct tvec_base *base) | |||
861 | 881 | ||
862 | set_running_timer(base, timer); | 882 | set_running_timer(base, timer); |
863 | detach_timer(timer, 1); | 883 | detach_timer(timer, 1); |
884 | |||
864 | spin_unlock_irq(&base->lock); | 885 | spin_unlock_irq(&base->lock); |
865 | { | 886 | { |
866 | int preempt_count = preempt_count(); | 887 | int preempt_count = preempt_count(); |
888 | |||
889 | #ifdef CONFIG_LOCKDEP | ||
890 | /* | ||
891 | * It is permissible to free the timer from | ||
892 | * inside the function that is called from | ||
893 | * it, this we need to take into account for | ||
894 | * lockdep too. To avoid bogus "held lock | ||
895 | * freed" warnings as well as problems when | ||
896 | * looking into timer->lockdep_map, make a | ||
897 | * copy and use that here. | ||
898 | */ | ||
899 | struct lockdep_map lockdep_map = | ||
900 | timer->lockdep_map; | ||
901 | #endif | ||
902 | /* | ||
903 | * Couple the lock chain with the lock chain at | ||
904 | * del_timer_sync() by acquiring the lock_map | ||
905 | * around the fn() call here and in | ||
906 | * del_timer_sync(). | ||
907 | */ | ||
908 | lock_map_acquire(&lockdep_map); | ||
909 | |||
867 | fn(data); | 910 | fn(data); |
911 | |||
912 | lock_map_release(&lockdep_map); | ||
913 | |||
868 | if (preempt_count != preempt_count()) { | 914 | if (preempt_count != preempt_count()) { |
869 | printk(KERN_ERR "huh, entered %p " | 915 | printk(KERN_ERR "huh, entered %p " |
870 | "with preempt_count %08x, exited" | 916 | "with preempt_count %08x, exited" |