Commit a6037b61c2f5fc99c57c15b26d7cfa58bbb34008
Committed by
Ingo Molnar
1 parent
731a55ba0f
Exists in
master
and in
4 other branches
hrtimer: fix recursion deadlock by re-introducing the softirq
Impact: fix rare runtime deadlock There are a few sites that do: spin_lock_irq(&foo) hrtimer_start(&bar) __run_hrtimer(&bar) func() spin_lock(&foo) which obviously deadlocks. In order to avoid this, never call __run_hrtimer() from hrtimer_start*() context, but instead defer this to softirq context. Signed-off-by: Peter Zijlstra <a.p.zijlstra@chello.nl> Signed-off-by: Ingo Molnar <mingo@elte.hu>
Showing 2 changed files with 29 additions and 34 deletions Side-by-side Diff
include/linux/interrupt.h
... | ... | @@ -253,7 +253,8 @@ |
253 | 253 | BLOCK_SOFTIRQ, |
254 | 254 | TASKLET_SOFTIRQ, |
255 | 255 | SCHED_SOFTIRQ, |
256 | - RCU_SOFTIRQ, /* Preferable RCU should always be the last softirq */ | |
256 | + HRTIMER_SOFTIRQ, | |
257 | + RCU_SOFTIRQ, /* Preferable RCU should always be the last softirq */ | |
257 | 258 | |
258 | 259 | NR_SOFTIRQS |
259 | 260 | }; |
kernel/hrtimer.c
... | ... | @@ -634,7 +634,6 @@ |
634 | 634 | { |
635 | 635 | } |
636 | 636 | |
637 | -static void __run_hrtimer(struct hrtimer *timer); | |
638 | 637 | |
639 | 638 | /* |
640 | 639 | * When High resolution timers are active, try to reprogram. Note, that in case |
... | ... | @@ -646,13 +645,9 @@ |
646 | 645 | struct hrtimer_clock_base *base) |
647 | 646 | { |
648 | 647 | if (base->cpu_base->hres_active && hrtimer_reprogram(timer, base)) { |
649 | - /* | |
650 | - * XXX: recursion check? | |
651 | - * hrtimer_forward() should round up with timer granularity | |
652 | - * so that we never get into inf recursion here, | |
653 | - * it doesn't do that though | |
654 | - */ | |
655 | - __run_hrtimer(timer); | |
648 | + spin_unlock(&base->cpu_base->lock); | |
649 | + raise_softirq_irqoff(HRTIMER_SOFTIRQ); | |
650 | + spin_lock(&base->cpu_base->lock); | |
656 | 651 | return 1; |
657 | 652 | } |
658 | 653 | return 0; |
... | ... | @@ -705,11 +700,6 @@ |
705 | 700 | } |
706 | 701 | static inline void hrtimer_init_hres(struct hrtimer_cpu_base *base) { } |
707 | 702 | static inline void hrtimer_init_timer_hres(struct hrtimer *timer) { } |
708 | -static inline int hrtimer_reprogram(struct hrtimer *timer, | |
709 | - struct hrtimer_clock_base *base) | |
710 | -{ | |
711 | - return 0; | |
712 | -} | |
713 | 703 | |
714 | 704 | #endif /* CONFIG_HIGH_RES_TIMERS */ |
715 | 705 | |
716 | 706 | |
... | ... | @@ -780,9 +770,11 @@ |
780 | 770 | * |
781 | 771 | * The timer is inserted in expiry order. Insertion into the |
782 | 772 | * red black tree is O(log(n)). Must hold the base lock. |
773 | + * | |
774 | + * Returns 1 when the new timer is the leftmost timer in the tree. | |
783 | 775 | */ |
784 | -static void enqueue_hrtimer(struct hrtimer *timer, | |
785 | - struct hrtimer_clock_base *base, int reprogram) | |
776 | +static int enqueue_hrtimer(struct hrtimer *timer, | |
777 | + struct hrtimer_clock_base *base) | |
786 | 778 | { |
787 | 779 | struct rb_node **link = &base->active.rb_node; |
788 | 780 | struct rb_node *parent = NULL; |
789 | 781 | |
... | ... | @@ -814,20 +806,8 @@ |
814 | 806 | * Insert the timer to the rbtree and check whether it |
815 | 807 | * replaces the first pending timer |
816 | 808 | */ |
817 | - if (leftmost) { | |
818 | - /* | |
819 | - * Reprogram the clock event device. When the timer is already | |
820 | - * expired hrtimer_enqueue_reprogram has either called the | |
821 | - * callback or added it to the pending list and raised the | |
822 | - * softirq. | |
823 | - * | |
824 | - * This is a NOP for !HIGHRES | |
825 | - */ | |
826 | - if (reprogram && hrtimer_enqueue_reprogram(timer, base)) | |
827 | - return; | |
828 | - | |
809 | + if (leftmost) | |
829 | 810 | base->first = &timer->node; |
830 | - } | |
831 | 811 | |
832 | 812 | rb_link_node(&timer->node, parent, link); |
833 | 813 | rb_insert_color(&timer->node, &base->active); |
... | ... | @@ -836,6 +816,8 @@ |
836 | 816 | * state of a possibly running callback. |
837 | 817 | */ |
838 | 818 | timer->state |= HRTIMER_STATE_ENQUEUED; |
819 | + | |
820 | + return leftmost; | |
839 | 821 | } |
840 | 822 | |
841 | 823 | /* |
... | ... | @@ -912,7 +894,7 @@ |
912 | 894 | { |
913 | 895 | struct hrtimer_clock_base *base, *new_base; |
914 | 896 | unsigned long flags; |
915 | - int ret; | |
897 | + int ret, leftmost; | |
916 | 898 | |
917 | 899 | base = lock_hrtimer_base(timer, &flags); |
918 | 900 | |
919 | 901 | |
920 | 902 | |
... | ... | @@ -940,12 +922,16 @@ |
940 | 922 | |
941 | 923 | timer_stats_hrtimer_set_start_info(timer); |
942 | 924 | |
925 | + leftmost = enqueue_hrtimer(timer, new_base); | |
926 | + | |
943 | 927 | /* |
944 | 928 | * Only allow reprogramming if the new base is on this CPU. |
945 | 929 | * (it might still be on another CPU if the timer was pending) |
930 | + * | |
931 | + * XXX send_remote_softirq() ? | |
946 | 932 | */ |
947 | - enqueue_hrtimer(timer, new_base, | |
948 | - new_base->cpu_base == &__get_cpu_var(hrtimer_bases)); | |
933 | + if (leftmost && new_base->cpu_base == &__get_cpu_var(hrtimer_bases)) | |
934 | + hrtimer_enqueue_reprogram(timer, new_base); | |
949 | 935 | |
950 | 936 | unlock_hrtimer_base(timer, &flags); |
951 | 937 | |
... | ... | @@ -1163,7 +1149,7 @@ |
1163 | 1149 | */ |
1164 | 1150 | if (restart != HRTIMER_NORESTART) { |
1165 | 1151 | BUG_ON(timer->state != HRTIMER_STATE_CALLBACK); |
1166 | - enqueue_hrtimer(timer, base, 0); | |
1152 | + enqueue_hrtimer(timer, base); | |
1167 | 1153 | } |
1168 | 1154 | timer->state &= ~HRTIMER_STATE_CALLBACK; |
1169 | 1155 | } |
... | ... | @@ -1277,6 +1263,11 @@ |
1277 | 1263 | local_irq_restore(flags); |
1278 | 1264 | } |
1279 | 1265 | |
1266 | +static void run_hrtimer_softirq(struct softirq_action *h) | |
1267 | +{ | |
1268 | + hrtimer_peek_ahead_timers(); | |
1269 | +} | |
1270 | + | |
1280 | 1271 | #endif /* CONFIG_HIGH_RES_TIMERS */ |
1281 | 1272 | |
1282 | 1273 | /* |
... | ... | @@ -1532,7 +1523,7 @@ |
1532 | 1523 | * is done, which will run all expired timers and re-programm |
1533 | 1524 | * the timer device. |
1534 | 1525 | */ |
1535 | - enqueue_hrtimer(timer, new_base, 0); | |
1526 | + enqueue_hrtimer(timer, new_base); | |
1536 | 1527 | |
1537 | 1528 | /* Clear the migration state bit */ |
1538 | 1529 | timer->state &= ~HRTIMER_STATE_MIGRATE; |
... | ... | @@ -1610,6 +1601,9 @@ |
1610 | 1601 | hrtimer_cpu_notify(&hrtimers_nb, (unsigned long)CPU_UP_PREPARE, |
1611 | 1602 | (void *)(long)smp_processor_id()); |
1612 | 1603 | register_cpu_notifier(&hrtimers_nb); |
1604 | +#ifdef CONFIG_HIGH_RES_TIMERS | |
1605 | + open_softirq(HRTIMER_SOFTIRQ, run_hrtimer_softirq); | |
1606 | +#endif | |
1613 | 1607 | } |
1614 | 1608 | |
1615 | 1609 | /** |