[PATCH 3/3] Synaptics - fix lockdep warnings

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



 =============================================
 [ INFO: possible recursive locking detected ]
 2.6.18-rc6-mm2-dirty #7
 ---------------------------------------------
 swapper/0 is trying to acquire lock:
  (&serio->lock){++..}, at: [<c02b7a20>] serio_interrupt+0x20/0x60

 but task is already holding lock:
  (&serio->lock){++..}, at: [<c02b7a20>] serio_interrupt+0x20/0x60

 other info that might help us debug this:
 1 lock held by swapper/0:
  #0:  (&serio->lock){++..}, at: [<c02b7a20>] serio_interrupt+0x20/0x60

 stack backtrace:
  [<c01039e5>] dump_trace+0x225/0x240
  [<c0103af0>] show_trace_log_lvl+0x30/0x50
  [<c0103b38>] show_trace+0x28/0x30
  [<c0103c72>] dump_stack+0x22/0x30
  [<c0135130>] print_deadlock_bug+0xc0/0xd0
  [<c01351b2>] check_deadlock+0x72/0x80
  [<c0136a4d>] __lock_acquire+0x43d/0x990
  [<c0137468>] lock_acquire+0x68/0x80
  [<c036947d>] _spin_lock_irqsave+0x4d/0x70
  [<c02b7a20>] serio_interrupt+0x20/0x60
  [<c02c3f84>] synaptics_pass_pt_packet+0x44/0xd0
  [<c02c4a9a>] synaptics_process_byte+0xba/0xd0
  [<c02c017a>] psmouse_handle_byte+0x1a/0x110
  [<c02c031a>] psmouse_interrupt+0xaa/0x2e0
  [<c02b79ca>] __serio_interrupt+0x3a/0x70
  [<c02b7a42>] serio_interrupt+0x42/0x60
  [<c02b841e>] i8042_interrupt+0x10e/0x240
  [<c014cab1>] handle_IRQ_event+0x31/0x80
  [<c014dc5e>] handle_level_irq+0x8e/0x120
  [<c010570a>] do_IRQ+0x5a/0xb0
  [<c01035a2>] common_interrupt+0x2e/0x34
  [<c024e964>] acpi_processor_idle+0x1e8/0x31b
  [<c0101195>] cpu_idle+0x95/0xa0
  [<c0100334>] rest_init+0x44/0x50
  [<c04ca8cd>] start_kernel+0x1cd/0x220
  =======================

This is caused by synaptics driver, in pass-through port situation, 
recursively calling serio_interrupt(), which acquires the device lock 
recursively. This is however OK in the synaptics pass-through port case, 
as the per-device lock is acquired exactly twice - first for child, then 
for parent device, so no deadlock occurs.

The patch splits serio_interrupt() function into nested and non-nested 
versions, and changes calls from synaptics pass-through packet handler 
accordingly.

This patch depends on the existence of spin_lock_irqsave_nested(), which 
is provided by the previous patch.

Please apply, if applicable, to get rid of spurious lockdep warnings. This patch
was generated against 2.6.18-rc6-mm2.

Signed-off-by: Jiri Kosina <[email protected]>

diff -rup linux-2.6.18-rc6-mm2.orig/drivers/input/mouse/synaptics.c linux-2.6.18-rc6-mm2/drivers/input/mouse/synaptics.c
--- linux-2.6.18-rc6-mm2.orig/drivers/input/mouse/synaptics.c	2006-09-14 01:05:30.000000000 +0200
+++ linux-2.6.18-rc6-mm2/drivers/input/mouse/synaptics.c	2006-09-14 02:03:38.000000000 +0200
@@ -216,13 +216,13 @@ static void synaptics_pass_pt_packet(str
 	struct psmouse *child = serio_get_drvdata(ptport);
 
 	if (child && child->state == PSMOUSE_ACTIVATED) {
-		serio_interrupt(ptport, packet[1], 0, NULL);
-		serio_interrupt(ptport, packet[4], 0, NULL);
-		serio_interrupt(ptport, packet[5], 0, NULL);
+		serio_interrupt_nested(ptport, packet[1], 0, NULL);
+		serio_interrupt_nested(ptport, packet[4], 0, NULL);
+		serio_interrupt_nested(ptport, packet[5], 0, NULL);
 		if (child->pktsize == 4)
-			serio_interrupt(ptport, packet[2], 0, NULL);
+			serio_interrupt_nested(ptport, packet[2], 0, NULL);
 	} else
-		serio_interrupt(ptport, packet[1], 0, NULL);
+		serio_interrupt_nested(ptport, packet[1], 0, NULL);
 }
 
 static void synaptics_pt_activate(struct psmouse *psmouse)
diff -rup linux-2.6.18-rc6-mm2.orig/drivers/input/serio/serio.c linux-2.6.18-rc6-mm2/drivers/input/serio/serio.c
--- linux-2.6.18-rc6-mm2.orig/drivers/input/serio/serio.c	2006-09-04 04:19:48.000000000 +0200
+++ linux-2.6.18-rc6-mm2/drivers/input/serio/serio.c	2006-09-14 01:51:00.000000000 +0200
@@ -41,6 +41,7 @@ MODULE_DESCRIPTION("Serio abstraction co
 MODULE_LICENSE("GPL");
 
 EXPORT_SYMBOL(serio_interrupt);
+EXPORT_SYMBOL(serio_interrupt_nested);
 EXPORT_SYMBOL(__serio_register_port);
 EXPORT_SYMBOL(serio_unregister_port);
 EXPORT_SYMBOL(serio_unregister_child_port);
@@ -910,14 +911,11 @@ void serio_close(struct serio *serio)
 	serio_set_drv(serio, NULL);
 }
 
-irqreturn_t serio_interrupt(struct serio *serio,
+irqreturn_t __serio_interrupt(struct serio *serio,
 		unsigned char data, unsigned int dfl, struct pt_regs *regs)
 {
-	unsigned long flags;
 	irqreturn_t ret = IRQ_NONE;
 
-	spin_lock_irqsave(&serio->lock, flags);
-
         if (likely(serio->drv)) {
                 ret = serio->drv->interrupt(serio, data, dfl, regs);
 	} else if (!dfl && serio->registered) {
@@ -925,8 +923,30 @@ irqreturn_t serio_interrupt(struct serio
 		ret = IRQ_HANDLED;
 	}
 
+	return ret;
+}
+
+irqreturn_t serio_interrupt(struct serio *serio,
+		unsigned char data, unsigned int dfl, struct pt_regs *regs)
+{
+	unsigned long flags;
+	irqreturn_t ret;
+	
+	spin_lock_irqsave(&serio->lock, flags);
+	ret = __serio_interrupt(serio, data, dfl, regs);
 	spin_unlock_irqrestore(&serio->lock, flags);
+	return ret;
+}
 
+irqreturn_t serio_interrupt_nested(struct serio *serio,
+		unsigned char data, unsigned int dfl, struct pt_regs *regs)
+{
+	unsigned long flags;
+	irqreturn_t ret;
+	
+	spin_lock_irqsave_nested(&serio->lock, flags, SINGLE_DEPTH_NESTING);
+	ret = __serio_interrupt(serio, data, dfl, regs);
+	spin_unlock_irqrestore(&serio->lock, flags);
 	return ret;
 }
 
diff -rup linux-2.6.18-rc6-mm2.orig/include/linux/serio.h linux-2.6.18-rc6-mm2/include/linux/serio.h
--- linux-2.6.18-rc6-mm2.orig/include/linux/serio.h	2006-09-14 00:49:35.000000000 +0200
+++ linux-2.6.18-rc6-mm2/include/linux/serio.h	2006-09-14 01:39:57.000000000 +0200
@@ -76,6 +76,7 @@ void serio_close(struct serio *serio);
 void serio_rescan(struct serio *serio);
 void serio_reconnect(struct serio *serio);
 irqreturn_t serio_interrupt(struct serio *serio, unsigned char data, unsigned int flags, struct pt_regs *regs);
+irqreturn_t serio_interrupt_nested(struct serio *serio, unsigned char data, unsigned int flags, struct pt_regs *regs);
 
 void __serio_register_port(struct serio *serio, struct module *owner);
 static inline void serio_register_port(struct serio *serio)
diff -rup linux-2.6.18-rc6-mm2.orig/kernel/spinlock.c linux-2.6.18-rc6-mm2/kernel/spinlock.c
--- linux-2.6.18-rc6-mm2.orig/kernel/spinlock.c	2006-09-14 01:35:00.000000000 +0200
+++ linux-2.6.18-rc6-mm2/kernel/spinlock.c	2006-09-14 01:42:40.000000000 +0200
@@ -310,7 +310,7 @@ unsigned long __lockfunc _spin_lock_irqs
 
 	local_irq_save(flags);
 	preempt_disable();
-	spin_acquire(&lock->dep_map, subtype, 0, _RET_IP_);
+	spin_acquire(&lock->dep_map, subclass, 0, _RET_IP_);
 	/*
 	 * On lockdep we dont want the hand-coded irq-enable of
 	 * _raw_spin_lock_flags() code, because lockdep assumes
-
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to [email protected]
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/

[Index of Archives]     [Kernel Newbies]     [Netfilter]     [Bugtraq]     [Photo]     [Stuff]     [Gimp]     [Yosemite News]     [MIPS Linux]     [ARM Linux]     [Linux Security]     [Linux RAID]     [Video 4 Linux]     [Linux for the blind]     [Linux Resources]
  Powered by Linux