From: Andrew Morton Date: Mon, 4 Feb 2008 15:48:10 +0000 (+0100) Subject: x86: fix RTC lockdep warning: potential hardirq recursion X-Git-Tag: v2.6.25-rc1~1057^2 X-Git-Url: https://err.no/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=795d45b22c079946332bf3825afefe5a981a97b6;p=linux-2.6 x86: fix RTC lockdep warning: potential hardirq recursion After disabling both CONFIG_DEBUG_LOCKING_API_SELFTESTS and netconsole (using current mainline) I get a login prompt, and also... [ 5.181668] SELinux: policy loaded with handle_unknown=deny [ 5.183315] type=1403 audit(1202100038.157:3): policy loaded auid=4294967295 ses=4294967295 [ 5.822073] SELinux: initialized (dev usbfs, type usbfs), uses genfs_contexts [ 7.819146] ------------[ cut here ]------------ [ 7.819146] WARNING: at kernel/lockdep.c:2033 trace_hardirqs_on+0x9b/0x10d() [ 7.819146] Modules linked in: generic ext3 jbd ide_disk ide_core [ 7.819146] Pid: 399, comm: hwclock Not tainted 2.6.24 #4 [ 7.819146] [] warn_on_slowpath+0x41/0x51 [ 7.819146] [] ? lock_release_holdtime+0x50/0x56 [ 7.819146] [] ? check_usage_forwards+0x19/0x3b [ 7.819146] [] ? __lock_acquire+0xac3/0xb0b [ 7.819146] [] ? native_sched_clock+0x8b/0x9f [ 7.819146] [] ? lock_release_holdtime+0x50/0x56 [ 7.819146] [] ? _spin_unlock_irq+0x22/0x42 [ 7.819146] [] trace_hardirqs_on+0x9b/0x10d [ 7.819146] [] _spin_unlock_irq+0x22/0x42 [ 7.819146] [] hpet_rtc_interrupt+0xdf/0x290 [ 7.819146] [] handle_IRQ_event+0x1a/0x46 [ 7.819146] [] handle_edge_irq+0xbe/0xff [ 7.819146] [] do_IRQ+0x6d/0x84 [ 7.819146] [] common_interrupt+0x2e/0x34 [ 7.819146] [] ? ktime_get_ts+0x8/0x3f [ 7.819146] [] ? lock_release+0x167/0x16f [ 7.819146] [] ? core_sys_select+0x2c/0x327 [ 7.819146] [] core_sys_select+0x74/0x327 [ 7.819146] [] ? native_sched_clock+0x8b/0x9f [ 7.819146] [] ? lock_release_holdtime+0x50/0x56 [ 7.819146] [] ? _spin_unlock_irq+0x22/0x42 [ 7.819146] [] ? trace_hardirqs_on+0xe6/0x10d [ 7.819146] [] ? _spin_unlock_irq+0x2d/0x42 [ 7.819146] [] ? rtc_do_ioctl+0x11b/0x677 [ 7.819146] [] ? inode_has_perm+0x5e/0x68 [ 7.819146] [] ? lock_release_holdtime+0x50/0x56 [ 7.819146] [] ? native_sched_clock+0x8b/0x9f [ 7.819146] [] ? file_has_perm+0x83/0x8c [ 7.819146] [] ? rtc_ioctl+0xf/0x11 [ 7.819146] [] ? do_ioctl+0x55/0x67 [ 7.819146] [] sys_select+0x93/0x163 [ 7.819146] [] ? sysenter_past_esp+0x9a/0xa5 [ 7.819146] [] sysenter_past_esp+0x5f/0xa5 [ 7.819146] ======================= [ 7.819146] ---[ end trace 96540ca301ffb84c ]--- [ 7.819210] rtc: lost 6 interrupts [ 7.870668] type=1400 audit(1202128840.794:4): avc: denied { audit_write } for pid=399 comm="hwclock" capability=29 scontext=system_u:system_r:hwclock_t:s0 tcontext=system_u:system_r:hwclock_t:s0 tclass=capability [ 9.538866] input: PC Speaker as /class/input/input5 Because hpet_rtc_interrupt()'s call to get_rtc_time() ends up resolving to include/asm-generic/rtc.h's (hilariously inlined) get_rtc_time(), which does spin_unlock_irq() from hard IRQ context. The obvious patch fixes it. Signed-off-by: Thomas Gleixner Signed-off-by: Ingo Molnar --- diff --git a/include/asm-generic/rtc.h b/include/asm-generic/rtc.h index d3238f1f70..dd1bed860e 100644 --- a/include/asm-generic/rtc.h +++ b/include/asm-generic/rtc.h @@ -35,10 +35,11 @@ static inline unsigned char rtc_is_updating(void) { unsigned char uip; + unsigned long flags; - spin_lock_irq(&rtc_lock); + spin_lock_irqsave(&rtc_lock, flags); uip = (CMOS_READ(RTC_FREQ_SELECT) & RTC_UIP); - spin_unlock_irq(&rtc_lock); + spin_unlock_irqrestore(&rtc_lock, flags); return uip; } @@ -46,6 +47,8 @@ static inline unsigned int get_rtc_time(struct rtc_time *time) { unsigned long uip_watchdog = jiffies; unsigned char ctrl; + unsigned long flags; + #ifdef CONFIG_MACH_DECSTATION unsigned int real_year; #endif @@ -72,7 +75,7 @@ static inline unsigned int get_rtc_time(struct rtc_time *time) * RTC has RTC_DAY_OF_WEEK, we ignore it, as it is only updated * by the RTC when initially set to a non-zero value. */ - spin_lock_irq(&rtc_lock); + spin_lock_irqsave(&rtc_lock, flags); time->tm_sec = CMOS_READ(RTC_SECONDS); time->tm_min = CMOS_READ(RTC_MINUTES); time->tm_hour = CMOS_READ(RTC_HOURS); @@ -83,7 +86,7 @@ static inline unsigned int get_rtc_time(struct rtc_time *time) real_year = CMOS_READ(RTC_DEC_YEAR); #endif ctrl = CMOS_READ(RTC_CONTROL); - spin_unlock_irq(&rtc_lock); + spin_unlock_irqrestore(&rtc_lock, flags); if (!(ctrl & RTC_DM_BINARY) || RTC_ALWAYS_BCD) {