| From d911e03d097bdc01363df5d81c43f69432eb785c Mon Sep 17 00:00:00 2001 |
| From: Heiko Carstens <heiko.carstens@de.ibm.com> |
| Date: Tue, 29 Jan 2013 09:16:28 +0100 |
| Subject: s390/timer: avoid overflow when programming clock comparator |
| |
| From: Heiko Carstens <heiko.carstens@de.ibm.com> |
| |
| commit d911e03d097bdc01363df5d81c43f69432eb785c upstream. |
| |
| Since ed4f209 "s390/time: fix sched_clock() overflow" a new helper function |
| is used to avoid overflows when converting TOD format values to nanosecond |
| values. |
| The kvm interrupt code formerly however only worked by accident because of |
| an overflow. It tried to program a timer that would expire in more than ~29 |
| years. Because of the old TOD-to-nanoseconds overflow bug the real expiry |
| value however was much smaller, but now it isn't anymore. |
| This however triggers yet another bug in the function that programs the clock |
| comparator s390_next_ktime(): if the absolute "expires" value is after 2042 |
| this will result in an overflow and the programmed value is lower than the |
| current TOD value which immediatly triggers a clock comparator (= timer) |
| interrupt. |
| Since the timer isn't expired it will be programmed immediately again and so |
| on... the result is a dead system. |
| To fix this simply program the maximum possible value if an overflow is |
| detected. |
| |
| Reported-by: Christian Borntraeger <borntraeger@de.ibm.com> |
| Tested-by: Christian Borntraeger <borntraeger@de.ibm.com> |
| Signed-off-by: Heiko Carstens <heiko.carstens@de.ibm.com> |
| Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org> |
| |
| --- |
| arch/s390/kernel/time.c | 3 +++ |
| 1 file changed, 3 insertions(+) |
| |
| --- a/arch/s390/kernel/time.c |
| +++ b/arch/s390/kernel/time.c |
| @@ -120,6 +120,9 @@ static int s390_next_ktime(ktime_t expir |
| nsecs = ktime_to_ns(ktime_add(timespec_to_ktime(ts), expires)); |
| do_div(nsecs, 125); |
| S390_lowcore.clock_comparator = sched_clock_base_cc + (nsecs << 9); |
| + /* Program the maximum value if we have an overflow (== year 2042) */ |
| + if (unlikely(S390_lowcore.clock_comparator < sched_clock_base_cc)) |
| + S390_lowcore.clock_comparator = -1ULL; |
| set_clock_comparator(S390_lowcore.clock_comparator); |
| return 0; |
| } |