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 9b77fc9a9ac8..b4555568b4e4 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) |
@@ -826,6 +837,15 @@ EXPORT_SYMBOL(try_to_del_timer_sync); | |||
826 | */ | 837 | */ |
827 | int del_timer_sync(struct timer_list *timer) | 838 | int del_timer_sync(struct timer_list *timer) |
828 | { | 839 | { |
840 | #ifdef CONFIG_LOCKDEP | ||
841 | unsigned long flags; | ||
842 | |||
843 | local_irq_save(flags); | ||
844 | lock_map_acquire(&timer->lockdep_map); | ||
845 | lock_map_release(&timer->lockdep_map); | ||
846 | local_irq_restore(flags); | ||
847 | #endif | ||
848 | |||
829 | for (;;) { | 849 | for (;;) { |
830 | int ret = try_to_del_timer_sync(timer); | 850 | int ret = try_to_del_timer_sync(timer); |
831 | if (ret >= 0) | 851 | if (ret >= 0) |
@@ -897,10 +917,36 @@ static inline void __run_timers(struct tvec_base *base) | |||
897 | 917 | ||
898 | set_running_timer(base, timer); | 918 | set_running_timer(base, timer); |
899 | detach_timer(timer, 1); | 919 | detach_timer(timer, 1); |
920 | |||
900 | spin_unlock_irq(&base->lock); | 921 | spin_unlock_irq(&base->lock); |
901 | { | 922 | { |
902 | int preempt_count = preempt_count(); | 923 | int preempt_count = preempt_count(); |
924 | |||
925 | #ifdef CONFIG_LOCKDEP | ||
926 | /* | ||
927 | * It is permissible to free the timer from | ||
928 | * inside the function that is called from | ||
929 | * it, this we need to take into account for | ||
930 | * lockdep too. To avoid bogus "held lock | ||
931 | * freed" warnings as well as problems when | ||
932 | * looking into timer->lockdep_map, make a | ||
933 | * copy and use that here. | ||
934 | */ | ||
935 | struct lockdep_map lockdep_map = | ||
936 | timer->lockdep_map; | ||
937 | #endif | ||
938 | /* | ||
939 | * Couple the lock chain with the lock chain at | ||
940 | * del_timer_sync() by acquiring the lock_map | ||
941 | * around the fn() call here and in | ||
942 | * del_timer_sync(). | ||
943 | */ | ||
944 | lock_map_acquire(&lockdep_map); | ||
945 | |||
903 | fn(data); | 946 | fn(data); |
947 | |||
948 | lock_map_release(&lockdep_map); | ||
949 | |||
904 | if (preempt_count != preempt_count()) { | 950 | if (preempt_count != preempt_count()) { |
905 | printk(KERN_ERR "huh, entered %p " | 951 | printk(KERN_ERR "huh, entered %p " |
906 | "with preempt_count %08x, exited" | 952 | "with preempt_count %08x, exited" |