diff mbox

usbhid: Fix lockdep unannotated irqs-off warning

Message ID CA+icZUUV5cOpUqsx7PAvfi3hs9pa11=DXH=BEbjGnOJ+kDi_5Q@mail.gmail.com (mailing list archive)
State New, archived
Delegated to: Jiri Kosina
Headers show

Commit Message

Sedat Dilek Sept. 30, 2015, 6:41 a.m. UTC
> What shall I do... play with lockdep (print_irqtrace_events) in
> del_timer_sync()?

I recalled that when Jiri was thinking towards a "compiler bug" that
the part in del_timer_sync() emebedded in the "ifdef CONFIG_LOCKDEP"
is somehow "mis-compiled".
Furthermore, I see that try_to_del_timer_sync() is invoked within
del_timer_sync() which does a spin_unlock_irqrestore().

[ kernel/time/timer.c ]

int del_timer_sync(struct timer_list *timer)
{
#ifdef CONFIG_LOCKDEP
unsigned long flags;

/*
* If lockdep gives a backtrace here, please reference
* the synchronization rules above.
*/
local_irq_save(flags);
lock_map_acquire(&timer->lockdep_map);
lock_map_release(&timer->lockdep_map);
local_irq_restore(flags);
#endif
/*
* don't use it in hardirq context, because it
* could lead to deadlock.
*/
WARN_ON(in_irq() && !(timer->flags & TIMER_IRQSAFE));
for (;;) {
int ret = try_to_del_timer_sync(timer);
if (ret >= 0)
return ret;
cpu_relax();
}
}
EXPORT_SYMBOL(del_timer_sync);
#endif
...
int try_to_del_timer_sync(struct timer_list *timer)
{
struct tvec_base *base;
unsigned long flags;
int ret = -1;

debug_assert_init(timer);

base = lock_timer_base(timer, &flags);

if (base->running_timer != timer) {
timer_stats_timer_clear_start_info(timer);
ret = detach_if_pending(timer, base, true);
}
spin_unlock_irqrestore(&base->lock, flags);

return ret;
}
EXPORT_SYMBOL(try_to_del_timer_sync);
...

Is the attached patch suitable for a test?

I remember I tried to turn lockdep kernel-config for amd64 but that
was somehow tricky.

Shall I ask timer folks?

Thoughts?

Thanks!

- Sedat -

Comments

Steven Rostedt Sept. 30, 2015, 8:50 a.m. UTC | #1
On Wed, 30 Sep 2015 08:41:57 +0200
Sedat Dilek <sedat.dilek@gmail.com> wrote:

> > What shall I do... play with lockdep (print_irqtrace_events) in
> > del_timer_sync()?
> 
> I recalled that when Jiri was thinking towards a "compiler bug" that
> the part in del_timer_sync() emebedded in the "ifdef CONFIG_LOCKDEP"
> is somehow "mis-compiled".
> Furthermore, I see that try_to_del_timer_sync() is invoked within
> del_timer_sync() which does a spin_unlock_irqrestore().

Which is fine.

> 
> [ kernel/time/timer.c ]
> 
> int del_timer_sync(struct timer_list *timer)
> {
> #ifdef CONFIG_LOCKDEP
> unsigned long flags;
> 
> /*
> * If lockdep gives a backtrace here, please reference
> * the synchronization rules above.
> */
> local_irq_save(flags);
> lock_map_acquire(&timer->lockdep_map);
> lock_map_release(&timer->lockdep_map);
> local_irq_restore(flags);
> #endif
> /*
> * don't use it in hardirq context, because it
> * could lead to deadlock.
> */
> WARN_ON(in_irq() && !(timer->flags & TIMER_IRQSAFE));
> for (;;) {
> int ret = try_to_del_timer_sync(timer);
> if (ret >= 0)
> return ret;
> cpu_relax();
> }
> }
> EXPORT_SYMBOL(del_timer_sync);
> #endif
> ...
> int try_to_del_timer_sync(struct timer_list *timer)
> {
> struct tvec_base *base;
> unsigned long flags;
> int ret = -1;
> 
> debug_assert_init(timer);
> 
> base = lock_timer_base(timer, &flags);

lock_timer_base() will grab the base->lock and save the current state
of interrupts in flags, and then disable interrupts.

> 
> if (base->running_timer != timer) {
> timer_stats_timer_clear_start_info(timer);
> ret = detach_if_pending(timer, base, true);
> }
> spin_unlock_irqrestore(&base->lock, flags);

this will release the base->lock and put the interrupt state back to
what it was before it took the lock.

I still don't see anything wrong with the code.

-- Steve

> 
> return ret;
> }
> EXPORT_SYMBOL(try_to_del_timer_sync);
> ...
> 
> Is the attached patch suitable for a test?
> 
> I remember I tried to turn lockdep kernel-config for amd64 but that
> was somehow tricky.
> 
> Shall I ask timer folks?
> 
> Thoughts?
> 
> Thanks!
> 
> - Sedat -

--
To unsubscribe from this list: send the line "unsubscribe linux-input" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
diff mbox

Patch

From edb4cb72c631c5e588af40794830c5bb5d6a927a Mon Sep 17 00:00:00 2001
From: Sedat Dilek <sedat.dilek@gmail.com>
Date: Wed, 30 Sep 2015 08:20:15 +0200
Subject: [PATCH] timer: lockdep: Add WARN_ON(irqs_disabled()) to
 del_timer_sync()

---
 kernel/locking/lockdep.c | 1 +
 kernel/time/timer.c      | 3 +++
 2 files changed, 4 insertions(+)

diff --git a/kernel/locking/lockdep.c b/kernel/locking/lockdep.c
index 8acfbf773e06..8b29b3dd518f 100644
--- a/kernel/locking/lockdep.c
+++ b/kernel/locking/lockdep.c
@@ -2410,6 +2410,7 @@  void print_irqtrace_events(struct task_struct *curr)
 	printk("softirqs last disabled at (%u): ", curr->softirq_disable_event);
 	print_ip_sym(curr->softirq_disable_ip);
 }
+EXPORT_SYMBOL(print_irqtrace_events);
 
 static int HARDIRQ_verbose(struct lock_class *class)
 {
diff --git a/kernel/time/timer.c b/kernel/time/timer.c
index 84190f02b521..f434b2dce642 100644
--- a/kernel/time/timer.c
+++ b/kernel/time/timer.c
@@ -1082,6 +1082,9 @@  int del_timer_sync(struct timer_list *timer)
 #ifdef CONFIG_LOCKDEP
 	unsigned long flags;
 
+	if(WARN_ON(irqs_disabled()))
+		print_irqtrace_events(current);
+
 	/*
 	 * If lockdep gives a backtrace here, please reference
 	 * the synchronization rules above.
-- 
2.5.3