Commit 38c052f8cff1bd323ccfa968136a9556652ee420

Authored by Ingo Molnar
1 parent 3c4fbe5e01

rtc: fix deadlock

if get_rtc_time() is _ever_ called with IRQs off, we deadlock badly
in it, waiting for jiffies to increment.

So make the code more robust by doing an explicit mdelay(20).

This solves a very hard to reproduce/debug hard lockup reported
by Mikael Pettersson.

Reported-by: Mikael Pettersson <mikpe@it.uu.se>
Signed-off-by: Ingo Molnar <mingo@elte.hu>

Showing 1 changed file with 4 additions and 8 deletions Side-by-side Diff

include/asm-generic/rtc.h
... ... @@ -15,6 +15,7 @@
15 15 #include <linux/mc146818rtc.h>
16 16 #include <linux/rtc.h>
17 17 #include <linux/bcd.h>
  18 +#include <linux/delay.h>
18 19  
19 20 #define RTC_PIE 0x40 /* periodic interrupt enable */
20 21 #define RTC_AIE 0x20 /* alarm interrupt enable */
... ... @@ -43,7 +44,6 @@
43 44  
44 45 static inline unsigned int get_rtc_time(struct rtc_time *time)
45 46 {
46   - unsigned long uip_watchdog = jiffies;
47 47 unsigned char ctrl;
48 48 unsigned long flags;
49 49  
50 50  
... ... @@ -53,19 +53,15 @@
53 53  
54 54 /*
55 55 * read RTC once any update in progress is done. The update
56   - * can take just over 2ms. We wait 10 to 20ms. There is no need to
  56 + * can take just over 2ms. We wait 20ms. There is no need to
57 57 * to poll-wait (up to 1s - eeccch) for the falling edge of RTC_UIP.
58 58 * If you need to know *exactly* when a second has started, enable
59 59 * periodic update complete interrupts, (via ioctl) and then
60 60 * immediately read /dev/rtc which will block until you get the IRQ.
61 61 * Once the read clears, read the RTC time (again via ioctl). Easy.
62 62 */
63   -
64   - if (rtc_is_updating() != 0)
65   - while (jiffies - uip_watchdog < 2*HZ/100) {
66   - barrier();
67   - cpu_relax();
68   - }
  63 + if (rtc_is_updating())
  64 + mdelay(20);
69 65  
70 66 /*
71 67 * Only the values that we read from the RTC are set. We leave