diff options
author | Peter Zijlstra <a.p.zijlstra@chello.nl> | 2009-03-13 07:21:27 -0400 |
---|---|---|
committer | Ingo Molnar <mingo@elte.hu> | 2009-03-31 08:52:52 -0400 |
commit | 7f1e2ca9f04b02794597f60e7b1d43f0a1317939 (patch) | |
tree | dad1d80ab4232f3ca12d7ff9a58f0dc76133dab1 /kernel/hrtimer.c | |
parent | 7bee946358c3cb957d4aa648fc5ab3cad0b232d0 (diff) |
hrtimer: fix rq->lock inversion (again)
It appears I inadvertly introduced rq->lock recursion to the
hrtimer_start() path when I delegated running already expired
timers to softirq context.
This patch fixes it by introducing a __hrtimer_start_range_ns()
method that will not use raise_softirq_irqoff() but
__raise_softirq_irqoff() which avoids the wakeup.
It then also changes schedule() to check for pending softirqs and
do the wakeup then, I'm not quite sure I like this last bit, nor
am I convinced its really needed.
Signed-off-by: Peter Zijlstra <a.p.zijlstra@chello.nl>
Cc: Peter Zijlstra <a.p.zijlstra@chello.nl>
Cc: paulus@samba.org
LKML-Reference: <20090313112301.096138802@chello.nl>
Signed-off-by: Ingo Molnar <mingo@elte.hu>
Diffstat (limited to 'kernel/hrtimer.c')
-rw-r--r-- | kernel/hrtimer.c | 55 |
1 files changed, 34 insertions, 21 deletions
diff --git a/kernel/hrtimer.c b/kernel/hrtimer.c index f394d2a42ca3..cb8a15c19583 100644 --- a/kernel/hrtimer.c +++ b/kernel/hrtimer.c | |||
@@ -651,14 +651,20 @@ static inline void hrtimer_init_timer_hres(struct hrtimer *timer) | |||
651 | * and expiry check is done in the hrtimer_interrupt or in the softirq. | 651 | * and expiry check is done in the hrtimer_interrupt or in the softirq. |
652 | */ | 652 | */ |
653 | static inline int hrtimer_enqueue_reprogram(struct hrtimer *timer, | 653 | static inline int hrtimer_enqueue_reprogram(struct hrtimer *timer, |
654 | struct hrtimer_clock_base *base) | 654 | struct hrtimer_clock_base *base, |
655 | int wakeup) | ||
655 | { | 656 | { |
656 | if (base->cpu_base->hres_active && hrtimer_reprogram(timer, base)) { | 657 | if (base->cpu_base->hres_active && hrtimer_reprogram(timer, base)) { |
657 | spin_unlock(&base->cpu_base->lock); | 658 | if (wakeup) { |
658 | raise_softirq_irqoff(HRTIMER_SOFTIRQ); | 659 | spin_unlock(&base->cpu_base->lock); |
659 | spin_lock(&base->cpu_base->lock); | 660 | raise_softirq_irqoff(HRTIMER_SOFTIRQ); |
661 | spin_lock(&base->cpu_base->lock); | ||
662 | } else | ||
663 | __raise_softirq_irqoff(HRTIMER_SOFTIRQ); | ||
664 | |||
660 | return 1; | 665 | return 1; |
661 | } | 666 | } |
667 | |||
662 | return 0; | 668 | return 0; |
663 | } | 669 | } |
664 | 670 | ||
@@ -703,7 +709,8 @@ static inline int hrtimer_is_hres_enabled(void) { return 0; } | |||
703 | static inline int hrtimer_switch_to_hres(void) { return 0; } | 709 | static inline int hrtimer_switch_to_hres(void) { return 0; } |
704 | static inline void hrtimer_force_reprogram(struct hrtimer_cpu_base *base) { } | 710 | static inline void hrtimer_force_reprogram(struct hrtimer_cpu_base *base) { } |
705 | static inline int hrtimer_enqueue_reprogram(struct hrtimer *timer, | 711 | static inline int hrtimer_enqueue_reprogram(struct hrtimer *timer, |
706 | struct hrtimer_clock_base *base) | 712 | struct hrtimer_clock_base *base, |
713 | int wakeup) | ||
707 | { | 714 | { |
708 | return 0; | 715 | return 0; |
709 | } | 716 | } |
@@ -886,20 +893,9 @@ remove_hrtimer(struct hrtimer *timer, struct hrtimer_clock_base *base) | |||
886 | return 0; | 893 | return 0; |
887 | } | 894 | } |
888 | 895 | ||
889 | /** | 896 | int __hrtimer_start_range_ns(struct hrtimer *timer, ktime_t tim, |
890 | * hrtimer_start_range_ns - (re)start an hrtimer on the current CPU | 897 | unsigned long delta_ns, const enum hrtimer_mode mode, |
891 | * @timer: the timer to be added | 898 | int wakeup) |
892 | * @tim: expiry time | ||
893 | * @delta_ns: "slack" range for the timer | ||
894 | * @mode: expiry mode: absolute (HRTIMER_ABS) or relative (HRTIMER_REL) | ||
895 | * | ||
896 | * Returns: | ||
897 | * 0 on success | ||
898 | * 1 when the timer was active | ||
899 | */ | ||
900 | int | ||
901 | hrtimer_start_range_ns(struct hrtimer *timer, ktime_t tim, unsigned long delta_ns, | ||
902 | const enum hrtimer_mode mode) | ||
903 | { | 899 | { |
904 | struct hrtimer_clock_base *base, *new_base; | 900 | struct hrtimer_clock_base *base, *new_base; |
905 | unsigned long flags; | 901 | unsigned long flags; |
@@ -940,12 +936,29 @@ hrtimer_start_range_ns(struct hrtimer *timer, ktime_t tim, unsigned long delta_n | |||
940 | * XXX send_remote_softirq() ? | 936 | * XXX send_remote_softirq() ? |
941 | */ | 937 | */ |
942 | if (leftmost && new_base->cpu_base == &__get_cpu_var(hrtimer_bases)) | 938 | if (leftmost && new_base->cpu_base == &__get_cpu_var(hrtimer_bases)) |
943 | hrtimer_enqueue_reprogram(timer, new_base); | 939 | hrtimer_enqueue_reprogram(timer, new_base, wakeup); |
944 | 940 | ||
945 | unlock_hrtimer_base(timer, &flags); | 941 | unlock_hrtimer_base(timer, &flags); |
946 | 942 | ||
947 | return ret; | 943 | return ret; |
948 | } | 944 | } |
945 | |||
946 | /** | ||
947 | * hrtimer_start_range_ns - (re)start an hrtimer on the current CPU | ||
948 | * @timer: the timer to be added | ||
949 | * @tim: expiry time | ||
950 | * @delta_ns: "slack" range for the timer | ||
951 | * @mode: expiry mode: absolute (HRTIMER_ABS) or relative (HRTIMER_REL) | ||
952 | * | ||
953 | * Returns: | ||
954 | * 0 on success | ||
955 | * 1 when the timer was active | ||
956 | */ | ||
957 | int hrtimer_start_range_ns(struct hrtimer *timer, ktime_t tim, | ||
958 | unsigned long delta_ns, const enum hrtimer_mode mode) | ||
959 | { | ||
960 | return __hrtimer_start_range_ns(timer, tim, delta_ns, mode, 1); | ||
961 | } | ||
949 | EXPORT_SYMBOL_GPL(hrtimer_start_range_ns); | 962 | EXPORT_SYMBOL_GPL(hrtimer_start_range_ns); |
950 | 963 | ||
951 | /** | 964 | /** |
@@ -961,7 +974,7 @@ EXPORT_SYMBOL_GPL(hrtimer_start_range_ns); | |||
961 | int | 974 | int |
962 | hrtimer_start(struct hrtimer *timer, ktime_t tim, const enum hrtimer_mode mode) | 975 | hrtimer_start(struct hrtimer *timer, ktime_t tim, const enum hrtimer_mode mode) |
963 | { | 976 | { |
964 | return hrtimer_start_range_ns(timer, tim, 0, mode); | 977 | return __hrtimer_start_range_ns(timer, tim, 0, mode, 1); |
965 | } | 978 | } |
966 | EXPORT_SYMBOL_GPL(hrtimer_start); | 979 | EXPORT_SYMBOL_GPL(hrtimer_start); |
967 | 980 | ||