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