* [PATCH 0/3] Synaptics - fix lockdep warnings
@ 2006-09-14 0:44 Jiri Kosina
2006-09-14 0:44 ` [PATCH 1/3] " Jiri Kosina
2006-09-14 2:00 ` [PATCH 0/3] " Dmitry Torokhov
0 siblings, 2 replies; 24+ messages in thread
From: Jiri Kosina @ 2006-09-14 0:44 UTC (permalink / raw)
To: Andrew Morton, Dmitry Torokhov; +Cc: lkml, Arjan van de Ven, Dave Jones
Hi,
the following three patches fix two lockdep warnings I am receiving with
2.6.18-rc6-mm2 (but at least the first one has been already discussed in
the times of 2.6.17, reported by Dave Jones) and I can see the problem in
current mainline source too).
* [1/3] fixes this:
=============================================
[ INFO: possible recursive locking detected ]
2.6.18-rc6-mm2-dirty #4
---------------------------------------------
kseriod/140 is trying to acquire lock:
(&ps2dev->cmd_mutex/1){--..}, at: [<c02b973b>] ps2_command+0x5b/0x3a0
but task is already holding lock:
(&ps2dev->cmd_mutex/1){--..}, at: [<c02b973b>] ps2_command+0x5b/0x3a0
* [2/3] adds support for spin_lock_irqsave_nested(), which is needed by
[3/3]
* [3/3] fixes this:
=============================================
[ 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
All three patches are based against 2.6.18-rc6-mm2, I can rebase them
against mainline, if needed.
Both warnings have been solved by splitting the respective functions to
nested and non-nested variants, and calling them from synpatics driver as
appropriate.
--
JiKos.
^ permalink raw reply [flat|nested] 24+ messages in thread* [PATCH 1/3] Synaptics - fix lockdep warnings 2006-09-14 0:44 [PATCH 0/3] Synaptics - fix lockdep warnings Jiri Kosina @ 2006-09-14 0:44 ` Jiri Kosina 2006-09-14 0:44 ` [PATCH 2/3] " Jiri Kosina 2006-09-14 2:00 ` [PATCH 0/3] " Dmitry Torokhov 1 sibling, 1 reply; 24+ messages in thread From: Jiri Kosina @ 2006-09-14 0:44 UTC (permalink / raw) To: Andrew Morton, Dmitry Torokhov; +Cc: lkml, Arjan van de Ven, Dave Jones ============================================= [ INFO: possible recursive locking detected ] 2.6.18-rc6-mm2-dirty #4 --------------------------------------------- kseriod/140 is trying to acquire lock: (&ps2dev->cmd_mutex/1){--..}, at: [<c02b973b>] ps2_command+0x5b/0x3a0 but task is already holding lock: (&ps2dev->cmd_mutex/1){--..}, at: [<c02b973b>] ps2_command+0x5b/0x3a0 other info that might help us debug this: 4 locks held by kseriod/140: #0: (serio_mutex){--..}, at: [<c0367c85>] mutex_lock+0x25/0x30 #1: (&serio->drv_mutex){--..}, at: [<c0367c85>] mutex_lock+0x25/0x30 #2: (psmouse_mutex){--..}, at: [<c0367c85>] mutex_lock+0x25/0x30 #3: (&ps2dev->cmd_mutex/1){--..}, at: [<c02b973b>] ps2_command+0x5b/0x3a0 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 [<c0368003>] mutex_lock_nested+0x93/0x2e0 [<c02b973b>] ps2_command+0x5b/0x3a0 [<c02c03fd>] psmouse_sliced_command+0x2d/0x90 [<c02c3cef>] synaptics_pt_write+0x2f/0x70 [<c02b9466>] ps2_sendbyte+0x86/0x130 [<c02b97b4>] ps2_command+0xd4/0x3a0 [<c02c0ca9>] psmouse_probe+0x29/0xa0 [<c02c15e2>] psmouse_connect+0x122/0x270 [<c02b63ac>] serio_connect_driver+0x2c/0x50 [<c02b7574>] serio_driver_probe+0x24/0x30 [<c027c489>] really_probe+0xc9/0xf0 [<c027c533>] driver_probe_device+0x63/0xe0 [<c027c5c8>] __device_attach+0x18/0x20 [<c027b607>] bus_for_each_drv+0x57/0x80 [<c027c641>] device_attach+0x71/0x90 [<c027b883>] bus_attach_device+0x23/0x50 [<c0279d99>] device_add+0x219/0x390 [<c02b7081>] serio_add_port+0x51/0x100 [<c02b69a8>] serio_handle_event+0x78/0xa0 [<c02b6ae3>] serio_thread+0x23/0x110 [<c012e9c5>] kthread+0xa5/0xf0 [<c0103703>] kernel_thread_helper+0x7/0x14 This warning has already been discussed in [1]. The substitution mutex_lock() for mutex_lock_nested() inside the ps2_command() is not enough (which already is in mainline) - as this is purely recursive situation (the same line of code acquires the lock twice), the SINGLE_DEPTH_NESTING doesn't help (as the lock is even in such case the same class). The following patch fixes it. I agree that it is not the prettiest patch on Earth, but definitely belongs to make-lockdep-shut-up patches cathegory. This arises with pass-through synaptics port, as in such situation, the lock is acquired twice - first for child, then for parent device. I have introduced respective variants of functions with _nested prefix, and let the synaptics pass-through port driver call them, when performing recursive locking for parent device. The patch is against 2.6.18-rc6-mm2. If applicable, please apply, to get rid of spurious lockdep warnings. [1] http://lkml.org/lkml/2006/7/6/191 Signed-off-by: Jiri Kosina <jikos@jikos.cz> diff -rup linux-2.6.18-rc6-mm2.orig/drivers/input/mouse/psmouse-base.c linux-2.6.18-rc6-mm2/drivers/input/mouse/psmouse-base.c --- linux-2.6.18-rc6-mm2.orig/drivers/input/mouse/psmouse-base.c 2006-09-14 00:49:30.000000000 +0200 +++ linux-2.6.18-rc6-mm2/drivers/input/mouse/psmouse-base.c 2006-09-14 00:24:53.000000000 +0200 @@ -377,6 +377,22 @@ int psmouse_sliced_command(struct psmous return 0; } +int psmouse_sliced_command_nested(struct psmouse *psmouse, unsigned char command) +{ + int i; + + if (ps2_command_nested(&psmouse->ps2dev, NULL, PSMOUSE_CMD_SETSCALE11)) + return -1; + + for (i = 6; i >= 0; i -= 2) { + unsigned char d = (command >> i) & 3; + if (ps2_command_nested(&psmouse->ps2dev, &d, PSMOUSE_CMD_SETRES)) + return -1; + } + + return 0; +} + /* * psmouse_reset() resets the mouse into power-on state. diff -rup linux-2.6.18-rc6-mm2.orig/drivers/input/mouse/psmouse.h linux-2.6.18-rc6-mm2/drivers/input/mouse/psmouse.h --- linux-2.6.18-rc6-mm2.orig/drivers/input/mouse/psmouse.h 2006-09-14 00:49:30.000000000 +0200 +++ linux-2.6.18-rc6-mm2/drivers/input/mouse/psmouse.h 2006-09-14 00:26:06.000000000 +0200 @@ -91,6 +91,7 @@ enum psmouse_type { }; int psmouse_sliced_command(struct psmouse *psmouse, unsigned char command); +int psmouse_sliced_command_nested(struct psmouse *psmouse, unsigned char command); int psmouse_reset(struct psmouse *psmouse); void psmouse_set_resolution(struct psmouse *psmouse, unsigned int resolution); 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 00:49:30.000000000 +0200 +++ linux-2.6.18-rc6-mm2/drivers/input/mouse/synaptics.c 2006-09-14 00:20:16.000000000 +0200 @@ -199,9 +199,9 @@ static int synaptics_pt_write(struct ser struct psmouse *parent = serio_get_drvdata(serio->parent); char rate_param = SYN_PS_CLIENT_CMD; /* indicates that we want pass-through port */ - if (psmouse_sliced_command(parent, c)) + if (psmouse_sliced_command_nested(parent, c)) return -1; - if (ps2_command(&parent->ps2dev, &rate_param, PSMOUSE_CMD_SETRATE)) + if (ps2_command_nested(&parent->ps2dev, &rate_param, PSMOUSE_CMD_SETRATE)) return -1; return 0; } diff -rup linux-2.6.18-rc6-mm2.orig/drivers/input/serio/libps2.c linux-2.6.18-rc6-mm2/drivers/input/serio/libps2.c --- linux-2.6.18-rc6-mm2.orig/drivers/input/serio/libps2.c 2006-09-04 04:19:48.000000000 +0200 +++ linux-2.6.18-rc6-mm2/drivers/input/serio/libps2.c 2006-09-14 00:44:00.000000000 +0200 @@ -31,6 +31,7 @@ EXPORT_SYMBOL(ps2_init); EXPORT_SYMBOL(ps2_sendbyte); EXPORT_SYMBOL(ps2_drain); EXPORT_SYMBOL(ps2_command); +EXPORT_SYMBOL(ps2_command_nested); EXPORT_SYMBOL(ps2_schedule_command); EXPORT_SYMBOL(ps2_handle_ack); EXPORT_SYMBOL(ps2_handle_response); @@ -157,20 +158,10 @@ static int ps2_adjust_timeout(struct ps2 return timeout; } -/* - * ps2_command() sends a command and its parameters to the mouse, - * then waits for the response and puts it in the param array. - * - * ps2_command() can only be called from a process context - */ - -int ps2_command(struct ps2dev *ps2dev, unsigned char *param, int command) +int ps2_command_validate(struct ps2dev *ps2dev, unsigned char *param, int command) { - int timeout; int send = (command >> 12) & 0xf; int receive = (command >> 8) & 0xf; - int rc = -1; - int i; if (receive > sizeof(ps2dev->cmdbuf)) { WARN_ON(1); @@ -181,9 +172,24 @@ int ps2_command(struct ps2dev *ps2dev, u WARN_ON(1); return -1; } + return 0; +} - mutex_lock_nested(&ps2dev->cmd_mutex, SINGLE_DEPTH_NESTING); +/* + * ps2_command() sends a command and its parameters to the mouse, + * then waits for the response and puts it in the param array. + * + * ps2_command() can only be called from a process context + */ +int __ps2_command(struct ps2dev *ps2dev, unsigned char *param, int command) +{ + int timeout; + int send = (command >> 12) & 0xf; + int receive = (command >> 8) & 0xf; + int rc = -1; + int i; + serio_pause_rx(ps2dev->serio); ps2dev->flags = command == PS2_CMD_GETID ? PS2_FLAG_WAITID : 0; ps2dev->cmdcnt = receive; @@ -236,6 +242,27 @@ int ps2_command(struct ps2dev *ps2dev, u mutex_unlock(&ps2dev->cmd_mutex); return rc; + +} + +int ps2_command(struct ps2dev *ps2dev, unsigned char *param, int command) +{ + if (ps2_command_validate(ps2dev, param, command) == -1) + return -1; + + mutex_lock(&ps2dev->cmd_mutex); + return __ps2_command(ps2dev, param, command); + +} + +int ps2_command_nested(struct ps2dev *ps2dev, unsigned char *param, int command) +{ + if (ps2_command_validate(ps2dev, param, command) == -1) + return -1; + + mutex_lock_nested(&ps2dev->cmd_mutex, SINGLE_DEPTH_NESTING); + return __ps2_command(ps2dev, param, command); + } /* diff -rup linux-2.6.18-rc6-mm2.orig/include/linux/libps2.h linux-2.6.18-rc6-mm2/include/linux/libps2.h --- linux-2.6.18-rc6-mm2.orig/include/linux/libps2.h 2006-09-04 04:19:48.000000000 +0200 +++ linux-2.6.18-rc6-mm2/include/linux/libps2.h 2006-09-14 00:22:13.000000000 +0200 @@ -43,6 +43,7 @@ void ps2_init(struct ps2dev *ps2dev, str int ps2_sendbyte(struct ps2dev *ps2dev, unsigned char byte, int timeout); void ps2_drain(struct ps2dev *ps2dev, int maxbytes, int timeout); int ps2_command(struct ps2dev *ps2dev, unsigned char *param, int command); +int ps2_command_nested(struct ps2dev *ps2dev, unsigned char *param, int command); int ps2_schedule_command(struct ps2dev *ps2dev, unsigned char *param, int command); int ps2_handle_ack(struct ps2dev *ps2dev, unsigned char data); int ps2_handle_response(struct ps2dev *ps2dev, unsigned char data); ^ permalink raw reply [flat|nested] 24+ messages in thread
* [PATCH 2/3] Synaptics - fix lockdep warnings 2006-09-14 0:44 ` [PATCH 1/3] " Jiri Kosina @ 2006-09-14 0:44 ` Jiri Kosina 2006-09-14 0:44 ` [PATCH 3/3] " Jiri Kosina 0 siblings, 1 reply; 24+ messages in thread From: Jiri Kosina @ 2006-09-14 0:44 UTC (permalink / raw) To: Andrew Morton, Dmitry Torokhov; +Cc: lkml, Arjan van de Ven, Dave Jones This patch introduces spin_lock_irqsave_nested(), as it is needed when annotating nested irqsave-spinlocks for lockdep. This is needed to cope with serio_interrupt() being recursively called from synaptics_pass_pt_packet(). More users could arise. Implementation stolen from Arjan [1], whose patch didn't make it neither into mainline nor -mm. If applicable, please apply. [1] http://lkml.org/lkml/2006/6/1/122 Signed-off-by: Jiri Kosina <jikos@jikos.cz> diff -rup linux-2.6.18-rc6-mm2.orig/include/linux/spinlock_api_smp.h linux-2.6.18-rc6-mm2/include/linux/spinlock_api_smp.h --- linux-2.6.18-rc6-mm2.orig/include/linux/spinlock_api_smp.h 2006-09-14 00:49:35.000000000 +0200 +++ linux-2.6.18-rc6-mm2/include/linux/spinlock_api_smp.h 2006-09-14 01:24:08.000000000 +0200 @@ -32,6 +32,8 @@ void __lockfunc _read_lock_irq(rwlock_t void __lockfunc _write_lock_irq(rwlock_t *lock) __acquires(lock); unsigned long __lockfunc _spin_lock_irqsave(spinlock_t *lock) __acquires(lock); +unsigned long __lockfunc _spin_lock_irqsave_nested(spinlock_t *lock, int subclass) + __acquires(spinlock_t); unsigned long __lockfunc _read_lock_irqsave(rwlock_t *lock) __acquires(lock); unsigned long __lockfunc _write_lock_irqsave(rwlock_t *lock) diff -rup linux-2.6.18-rc6-mm2.orig/include/linux/spinlock_api_up.h linux-2.6.18-rc6-mm2/include/linux/spinlock_api_up.h --- linux-2.6.18-rc6-mm2.orig/include/linux/spinlock_api_up.h 2006-09-04 04:19:48.000000000 +0200 +++ linux-2.6.18-rc6-mm2/include/linux/spinlock_api_up.h 2006-09-14 01:24:05.000000000 +0200 @@ -59,6 +59,7 @@ #define _read_lock_irq(lock) __LOCK_IRQ(lock) #define _write_lock_irq(lock) __LOCK_IRQ(lock) #define _spin_lock_irqsave(lock, flags) __LOCK_IRQSAVE(lock, flags) +#define _spin_lock_irqsave_nested(lock, flags, subclass) __LOCK_IRQSAVE(lock, flags, subclass) #define _read_lock_irqsave(lock, flags) __LOCK_IRQSAVE(lock, flags) #define _write_lock_irqsave(lock, flags) __LOCK_IRQSAVE(lock, flags) #define _spin_trylock(lock) ({ __LOCK(lock); 1; }) diff -rup linux-2.6.18-rc6-mm2.orig/include/linux/spinlock.h linux-2.6.18-rc6-mm2/include/linux/spinlock.h --- linux-2.6.18-rc6-mm2.orig/include/linux/spinlock.h 2006-09-14 00:49:35.000000000 +0200 +++ linux-2.6.18-rc6-mm2/include/linux/spinlock.h 2006-09-14 01:24:12.000000000 +0200 @@ -186,6 +186,11 @@ do { \ #define spin_lock_irqsave(lock, flags) flags = _spin_lock_irqsave(lock) #define read_lock_irqsave(lock, flags) flags = _read_lock_irqsave(lock) #define write_lock_irqsave(lock, flags) flags = _write_lock_irqsave(lock) +#ifdef CONFIG_DEBUG_LOCK_ALLOC +#define spin_lock_irqsave_nested(lock, flags, subclass) flags = _spin_lock_irqsave_nested(lock, subclass) +#else +#define spin_lock_irqsave_nested(lock, flags, subclass) flags = _spin_lock_irqsave(lock) +#endif #else #define spin_lock_irqsave(lock, flags) _spin_lock_irqsave(lock, flags) #define read_lock_irqsave(lock, flags) _read_lock_irqsave(lock, flags) 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 00:49:35.000000000 +0200 +++ linux-2.6.18-rc6-mm2/kernel/spinlock.c 2006-09-14 01:27:17.000000000 +0200 @@ -304,6 +304,27 @@ void __lockfunc _spin_lock_nested(spinlo } EXPORT_SYMBOL(_spin_lock_nested); +unsigned long __lockfunc _spin_lock_irqsave_nested(spinlock_t *lock, int subclass) +{ + unsigned long flags; + + local_irq_save(flags); + preempt_disable(); + spin_acquire(&lock->dep_map, subtype, 0, _RET_IP_); + /* + * On lockdep we dont want the hand-coded irq-enable of + * _raw_spin_lock_flags() code, because lockdep assumes + * that interrupts are not re-enabled during lock-acquire: + */ +#ifdef CONFIG_PROVE_SPIN_LOCKING + _raw_spin_lock(lock); +#else + _raw_spin_lock_flags(lock, &flags); +#endif + return flags; +} + +EXPORT_SYMBOL(_spin_lock_irqsave_nested); #endif ^ permalink raw reply [flat|nested] 24+ messages in thread
* [PATCH 3/3] Synaptics - fix lockdep warnings 2006-09-14 0:44 ` [PATCH 2/3] " Jiri Kosina @ 2006-09-14 0:44 ` Jiri Kosina 0 siblings, 0 replies; 24+ messages in thread From: Jiri Kosina @ 2006-09-14 0:44 UTC (permalink / raw) To: Andrew Morton, Dmitry Torokhov; +Cc: lkml, Arjan van de Ven, Dave Jones ============================================= [ 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 <jikos@jikos.cz> 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 ^ permalink raw reply [flat|nested] 24+ messages in thread
* Re: [PATCH 0/3] Synaptics - fix lockdep warnings 2006-09-14 0:44 [PATCH 0/3] Synaptics - fix lockdep warnings Jiri Kosina 2006-09-14 0:44 ` [PATCH 1/3] " Jiri Kosina @ 2006-09-14 2:00 ` Dmitry Torokhov 2006-09-14 8:43 ` Jiri Kosina 1 sibling, 1 reply; 24+ messages in thread From: Dmitry Torokhov @ 2006-09-14 2:00 UTC (permalink / raw) To: Jiri Kosina; +Cc: Andrew Morton, lkml, Arjan van de Ven, Dave Jones Hi Jiri, On Wednesday 13 September 2006 20:44, Jiri Kosina wrote: > Both warnings have been solved by splitting the respective functions to > nested and non-nested variants, and calling them from synpatics driver as > appropriate. > Unfortunately these patches do not solve the problem in general but rather fix one specific codepath. As far as I can see the warnings will return as soon as we add another pass-through port to the link (and I am considering adding a pass-through port to the trackpoint driver so you will get chain like i8042-synaptics-ptport-trackpoint-ptport-psmouse). Plus they are ugly and complicate serio and psmouse cores. I really don't like this *_nested business as it makes the code aware of possible usage patterns instead of just being re-entrant. -- Dmitry ^ permalink raw reply [flat|nested] 24+ messages in thread
* Re: [PATCH 0/3] Synaptics - fix lockdep warnings 2006-09-14 2:00 ` [PATCH 0/3] " Dmitry Torokhov @ 2006-09-14 8:43 ` Jiri Kosina 2006-09-14 13:18 ` Dmitry Torokhov 0 siblings, 1 reply; 24+ messages in thread From: Jiri Kosina @ 2006-09-14 8:43 UTC (permalink / raw) To: Dmitry Torokhov; +Cc: Andrew Morton, lkml, Arjan van de Ven, Dave Jones On Wed, 13 Sep 2006, Dmitry Torokhov wrote: > Unfortunately these patches do not solve the problem in general but > rather fix one specific codepath. As far as I can see the warnings will > return as soon as we add another pass-through port to the link (and I am > considering adding a pass-through port to the trackpoint driver so you > will get chain like i8042-synaptics-ptport-trackpoint-ptport-psmouse). > Plus they are ugly and complicate serio and psmouse cores. I really > don't like this *_nested business as it makes the code aware of possible > usage patterns instead of just being re-entrant. Hi Dmitry, I agree that these patches are ugly, but I wasn't able to think of any other way how to get rid of those lockdep warnings. Of course the lock validator could be extended to provide API such as mutex_init_nolockdep(), as you already proposed before, but this also has it's drawbacks (for example if any other future user of ps2_init() uses the mutex in a really bad way, this would not be detected by lock validator). Another possibility that comes to mind is extending the ps2dev structure with a field which would work as an subclass identifier for the device, and this field will be then be used as an subclass argument to mutex_lock_nested(). However, this requires proper setting of this field on the very same places on which my _nested functions are called, so it has the same level of generality. Do you have any other idea? I think this should get fixed, otherwise we will keep receiving these reports from users again and again. Thanks, -- JiKos. ^ permalink raw reply [flat|nested] 24+ messages in thread
* Re: [PATCH 0/3] Synaptics - fix lockdep warnings 2006-09-14 8:43 ` Jiri Kosina @ 2006-09-14 13:18 ` Dmitry Torokhov 2006-09-14 14:39 ` Jiri Kosina 0 siblings, 1 reply; 24+ messages in thread From: Dmitry Torokhov @ 2006-09-14 13:18 UTC (permalink / raw) To: Jiri Kosina; +Cc: Andrew Morton, lkml, Arjan van de Ven, Dave Jones On 9/14/06, Jiri Kosina <jikos@jikos.cz> wrote: > On Wed, 13 Sep 2006, Dmitry Torokhov wrote: > > > Unfortunately these patches do not solve the problem in general but > > rather fix one specific codepath. As far as I can see the warnings will > > return as soon as we add another pass-through port to the link (and I am > > considering adding a pass-through port to the trackpoint driver so you > > will get chain like i8042-synaptics-ptport-trackpoint-ptport-psmouse). > > Plus they are ugly and complicate serio and psmouse cores. I really > > don't like this *_nested business as it makes the code aware of possible > > usage patterns instead of just being re-entrant. > > Hi Dmitry, > > I agree that these patches are ugly, but I wasn't able to think of any > other way how to get rid of those lockdep warnings. > > Of course the lock validator could be extended to provide API such as > mutex_init_nolockdep(), as you already proposed before, but this also has > it's drawbacks (for example if any other future user of ps2_init() uses > the mutex in a really bad way, this would not be detected by lock > validator). > > Another possibility that comes to mind is extending the ps2dev structure > with a field which would work as an subclass identifier for the device, > and this field will be then be used as an subclass argument to > mutex_lock_nested(). However, this requires proper setting of this field > on the very same places on which my _nested functions are called, so it > has the same level of generality. > Can we add lock_class_key to the struct psmouse and use it to define per-device mutex class regardless of whether it is a child, grandchild or a parent? > Do you have any other idea? I think this should get fixed, otherwise we > will keep receiving these reports from users again and again. > If we can't make lockdep shut up with minimal intervention I might just change psmouse back to semaphores. -- Dmitry ^ permalink raw reply [flat|nested] 24+ messages in thread
* Re: [PATCH 0/3] Synaptics - fix lockdep warnings 2006-09-14 13:18 ` Dmitry Torokhov @ 2006-09-14 14:39 ` Jiri Kosina 2006-09-14 14:58 ` Dmitry Torokhov 0 siblings, 1 reply; 24+ messages in thread From: Jiri Kosina @ 2006-09-14 14:39 UTC (permalink / raw) To: Dmitry Torokhov; +Cc: Andrew Morton, lkml, Arjan van de Ven, Dave Jones On Thu, 14 Sep 2006, Dmitry Torokhov wrote: > Can we add lock_class_key to the struct psmouse and use it to define > per-device mutex class regardless of whether it is a child, grandchild > or a parent? Hi Dmitry, what do you think about the patches below? I have used a slightly different approach, as we also need to get rid of the spurious lockdep warning in case of recursive call of serio_interrupt(), which can't be handled well with lock subclass stored in struct psmouse. What do you think about this? It shuts up the lockdep, and seems much cleaner to me. The first patch implements spin_lock_irqsave_nested(), which is needed by the second one: Signed-off-by: Jiri Kosina <jikos@jikos.cz> diff -rup linux-2.6.18-rc6-mm2.orig/include/linux/spinlock_api_smp.h linux-2.6.18-rc6-mm2/include/linux/spinlock_api_smp.h --- linux-2.6.18-rc6-mm2.orig/include/linux/spinlock_api_smp.h 2006-09-14 00:49:35.000000000 +0200 +++ linux-2.6.18-rc6-mm2/include/linux/spinlock_api_smp.h 2006-09-14 01:24:08.000000000 +0200 @@ -32,6 +32,8 @@ void __lockfunc _read_lock_irq(rwlock_t void __lockfunc _write_lock_irq(rwlock_t *lock) __acquires(lock); unsigned long __lockfunc _spin_lock_irqsave(spinlock_t *lock) __acquires(lock); +unsigned long __lockfunc _spin_lock_irqsave_nested(spinlock_t *lock, int subclass) + __acquires(spinlock_t); unsigned long __lockfunc _read_lock_irqsave(rwlock_t *lock) __acquires(lock); unsigned long __lockfunc _write_lock_irqsave(rwlock_t *lock) diff -rup linux-2.6.18-rc6-mm2.orig/include/linux/spinlock_api_up.h linux-2.6.18-rc6-mm2/include/linux/spinlock_api_up.h --- linux-2.6.18-rc6-mm2.orig/include/linux/spinlock_api_up.h 2006-09-04 04:19:48.000000000 +0200 +++ linux-2.6.18-rc6-mm2/include/linux/spinlock_api_up.h 2006-09-14 01:24:05.000000000 +0200 @@ -59,6 +59,7 @@ #define _read_lock_irq(lock) __LOCK_IRQ(lock) #define _write_lock_irq(lock) __LOCK_IRQ(lock) #define _spin_lock_irqsave(lock, flags) __LOCK_IRQSAVE(lock, flags) +#define _spin_lock_irqsave_nested(lock, flags, subclass) __LOCK_IRQSAVE(lock, flags, subclass) #define _read_lock_irqsave(lock, flags) __LOCK_IRQSAVE(lock, flags) #define _write_lock_irqsave(lock, flags) __LOCK_IRQSAVE(lock, flags) #define _spin_trylock(lock) ({ __LOCK(lock); 1; }) diff -rup linux-2.6.18-rc6-mm2.orig/include/linux/spinlock.h linux-2.6.18-rc6-mm2/include/linux/spinlock.h --- linux-2.6.18-rc6-mm2.orig/include/linux/spinlock.h 2006-09-14 00:49:35.000000000 +0200 +++ linux-2.6.18-rc6-mm2/include/linux/spinlock.h 2006-09-14 01:24:12.000000000 +0200 @@ -186,6 +186,11 @@ do { \ #define spin_lock_irqsave(lock, flags) flags = _spin_lock_irqsave(lock) #define read_lock_irqsave(lock, flags) flags = _read_lock_irqsave(lock) #define write_lock_irqsave(lock, flags) flags = _write_lock_irqsave(lock) +#ifdef CONFIG_DEBUG_LOCK_ALLOC +#define spin_lock_irqsave_nested(lock, flags, subclass) flags = _spin_lock_irqsave_nested(lock, subclass) +#else +#define spin_lock_irqsave_nested(lock, flags, subclass) flags = _spin_lock_irqsave(lock) +#endif #else #define spin_lock_irqsave(lock, flags) _spin_lock_irqsave(lock, flags) #define read_lock_irqsave(lock, flags) _read_lock_irqsave(lock, flags) 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 00:49:35.000000000 +0200 +++ linux-2.6.18-rc6-mm2/kernel/spinlock.c 2006-09-14 01:27:17.000000000 +0200 @@ -304,6 +304,27 @@ void __lockfunc _spin_lock_nested(spinlo } EXPORT_SYMBOL(_spin_lock_nested); +unsigned long __lockfunc _spin_lock_irqsave_nested(spinlock_t *lock, int subclass) +{ + unsigned long flags; + + local_irq_save(flags); + preempt_disable(); + 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 + * that interrupts are not re-enabled during lock-acquire: + */ +#ifdef CONFIG_PROVE_SPIN_LOCKING + _raw_spin_lock(lock); +#else + _raw_spin_lock_flags(lock, &flags); +#endif + return flags; +} + +EXPORT_SYMBOL(_spin_lock_irqsave_nested); #endif And this second one actually fixes the locking with respect to lockdep validator: Signed-off-by: Jiri Kosina <jikos@jikos.cz> diff -rup linux-2.6.18-rc6-mm2.orig/drivers/input/serio/libps2.c linux-2.6.18-rc6-mm2/drivers/input/serio/libps2.c --- linux-2.6.18-rc6-mm2.orig/drivers/input/serio/libps2.c 2006-09-04 04:19:48.000000000 +0200 +++ linux-2.6.18-rc6-mm2/drivers/input/serio/libps2.c 2006-09-14 16:16:06.000000000 +0200 @@ -182,7 +182,7 @@ int ps2_command(struct ps2dev *ps2dev, u return -1; } - mutex_lock_nested(&ps2dev->cmd_mutex, SINGLE_DEPTH_NESTING); + mutex_lock_nested(&ps2dev->cmd_mutex, ps2dev->serio->depth); serio_pause_rx(ps2dev->serio); ps2dev->flags = command == PS2_CMD_GETID ? PS2_FLAG_WAITID : 0; 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 16:16:00.000000000 +0200 @@ -553,9 +553,11 @@ static void serio_add_port(struct serio if (serio->parent) { serio_pause_rx(serio->parent); serio->parent->child = serio; + serio->depth = serio->parent->depth + 1; serio_continue_rx(serio->parent); - } - + } else + serio->depth = 0; + list_add_tail(&serio->node, &serio_list); if (serio->start) serio->start(serio); @@ -916,7 +918,7 @@ irqreturn_t serio_interrupt(struct serio unsigned long flags; irqreturn_t ret = IRQ_NONE; - spin_lock_irqsave(&serio->lock, flags); + spin_lock_irqsave_nested(&serio->lock, flags, serio->depth); if (likely(serio->drv)) { ret = serio->drv->interrupt(serio, data, dfl, regs); 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 16:20:56.000000000 +0200 +++ linux-2.6.18-rc6-mm2/include/linux/serio.h 2006-09-14 15:15:41.000000000 +0200 @@ -41,6 +41,7 @@ struct serio { void (*stop)(struct serio *); struct serio *parent, *child; + unsigned int depth; /* level of nesting in parent-child hierarichy of serios */ struct serio_driver *drv; /* accessed from interrupt, must be protected by serio->lock and serio->sem */ struct mutex drv_mutex; /* protects serio->drv so attributes can pin driver */ -- JiKos. ^ permalink raw reply [flat|nested] 24+ messages in thread
* Re: [PATCH 0/3] Synaptics - fix lockdep warnings 2006-09-14 14:39 ` Jiri Kosina @ 2006-09-14 14:58 ` Dmitry Torokhov 2006-09-14 15:03 ` Arjan van de Ven 2006-09-14 15:08 ` Jiri Kosina 0 siblings, 2 replies; 24+ messages in thread From: Dmitry Torokhov @ 2006-09-14 14:58 UTC (permalink / raw) To: Jiri Kosina; +Cc: Andrew Morton, lkml, Arjan van de Ven, Dave Jones On 9/14/06, Jiri Kosina <jikos@jikos.cz> wrote: > On Thu, 14 Sep 2006, Dmitry Torokhov wrote: > > > Can we add lock_class_key to the struct psmouse and use it to define > > per-device mutex class regardless of whether it is a child, grandchild > > or a parent? > > Hi Dmitry, > > what do you think about the patches below? I have used a slightly > different approach, as we also need to get rid of the spurious lockdep > warning in case of recursive call of serio_interrupt(), which can't be > handled well with lock subclass stored in struct psmouse. What do you > think about this? It shuts up the lockdep, and seems much cleaner to me. > Yes, this is much, much better. Could you please tell me if depth should be a true depth or just an unique number? The reason I am asking is that I hope to get rid of parent/child pointers in serio (they were introduced when driver core could not handle recursive addition/removing of devices on the same bus). -- Dmitry ^ permalink raw reply [flat|nested] 24+ messages in thread
* Re: [PATCH 0/3] Synaptics - fix lockdep warnings 2006-09-14 14:58 ` Dmitry Torokhov @ 2006-09-14 15:03 ` Arjan van de Ven 2006-09-14 15:08 ` Jiri Kosina 1 sibling, 0 replies; 24+ messages in thread From: Arjan van de Ven @ 2006-09-14 15:03 UTC (permalink / raw) To: Dmitry Torokhov; +Cc: Jiri Kosina, Andrew Morton, lkml, Dave Jones On Thu, 2006-09-14 at 10:58 -0400, Dmitry Torokhov wrote: > On 9/14/06, Jiri Kosina <jikos@jikos.cz> wrote: > > On Thu, 14 Sep 2006, Dmitry Torokhov wrote: > > > > > Can we add lock_class_key to the struct psmouse and use it to define > > > per-device mutex class regardless of whether it is a child, grandchild > > > or a parent? > > > > Hi Dmitry, > > > > what do you think about the patches below? I have used a slightly > > different approach, as we also need to get rid of the spurious lockdep > > warning in case of recursive call of serio_interrupt(), which can't be > > handled well with lock subclass stored in struct psmouse. What do you > > think about this? It shuts up the lockdep, and seems much cleaner to me. > > > > Yes, this is much, much better. Could you please tell me if depth > should be a true depth or just an unique number? The reason I am > asking is that I hope to get rid of parent/child pointers in serio > (they were introduced when driver core could not handle recursive > addition/removing of devices on the same bus). lockdep sort of expects the depth to be a number between 0 and 7. Other than that lockdep does not assume an ordering based on numerical value at all; it figures that out at runtime. ^ permalink raw reply [flat|nested] 24+ messages in thread
* Re: [PATCH 0/3] Synaptics - fix lockdep warnings 2006-09-14 14:58 ` Dmitry Torokhov 2006-09-14 15:03 ` Arjan van de Ven @ 2006-09-14 15:08 ` Jiri Kosina 2006-09-14 15:51 ` Dmitry Torokhov 1 sibling, 1 reply; 24+ messages in thread From: Jiri Kosina @ 2006-09-14 15:08 UTC (permalink / raw) To: Dmitry Torokhov; +Cc: Andrew Morton, lkml, Arjan van de Ven, Dave Jones On Thu, 14 Sep 2006, Dmitry Torokhov wrote: > Yes, this is much, much better. Could you please tell me if depth should > be a true depth or just an unique number? The reason I am asking is that > I hope to get rid of parent/child pointers in serio (they were > introduced when driver core could not handle recursive addition/removing > of devices on the same bus). I am afraid you can't generate just any unique number to represent the lock class, as the lockdep validator fails if the class number is higher than MAX_LOCKDEP_SUBCLASSES, which is by default 8. Regarding the patches - should I submit them upstream, or will you? Thanks, -- JiKos. ^ permalink raw reply [flat|nested] 24+ messages in thread
* Re: [PATCH 0/3] Synaptics - fix lockdep warnings 2006-09-14 15:08 ` Jiri Kosina @ 2006-09-14 15:51 ` Dmitry Torokhov 2006-09-14 16:00 ` Jiri Kosina 0 siblings, 1 reply; 24+ messages in thread From: Dmitry Torokhov @ 2006-09-14 15:51 UTC (permalink / raw) To: Jiri Kosina; +Cc: Andrew Morton, lkml, Arjan van de Ven, Dave Jones On 9/14/06, Jiri Kosina <jikos@jikos.cz> wrote: > On Thu, 14 Sep 2006, Dmitry Torokhov wrote: > > > Yes, this is much, much better. Could you please tell me if depth should > > be a true depth or just an unique number? The reason I am asking is that > > I hope to get rid of parent/child pointers in serio (they were > > introduced when driver core could not handle recursive addition/removing > > of devices on the same bus). > > I am afraid you can't generate just any unique number to represent the > lock class, as the lockdep validator fails if the class number is higher > than MAX_LOCKDEP_SUBCLASSES, which is by default 8. > > Regarding the patches - should I submit them upstream, or will you? > Not yet ;) Is there a way to hide the depth in the spinlock/mutex structure itself so that initialization code could do spin_lock_init_nested() and spare the rest of the code from that knowledge? -- Dmitry ^ permalink raw reply [flat|nested] 24+ messages in thread
* Re: [PATCH 0/3] Synaptics - fix lockdep warnings 2006-09-14 15:51 ` Dmitry Torokhov @ 2006-09-14 16:00 ` Jiri Kosina 2006-09-14 16:18 ` Dmitry Torokhov 0 siblings, 1 reply; 24+ messages in thread From: Jiri Kosina @ 2006-09-14 16:00 UTC (permalink / raw) To: Dmitry Torokhov; +Cc: lkml, Arjan van de Ven On Thu, 14 Sep 2006, Dmitry Torokhov wrote: > Not yet ;) Is there a way to hide the depth in the spinlock/mutex > structure itself so that initialization code could do > spin_lock_init_nested() and spare the rest of the code from that > knowledge? (shortened CC list a bit) In fact I am not sure what you mean. On every lock and unlock operation, in case of recursive locking (which our case is), you have to provide class identifier, which is used to distinguish if the lock is of the same instance, or a different one (deeper or higher in the locking hierarchy). There is no way how spin_lock() or mutex_lock() can know this "automatically", you always have to provide the nesting level from outside, as it depends on the ordering hierarchy, which locking primitives are totally unaware of. Or did I misunderstand you? Thanks, -- JiKos. ^ permalink raw reply [flat|nested] 24+ messages in thread
* Re: [PATCH 0/3] Synaptics - fix lockdep warnings 2006-09-14 16:00 ` Jiri Kosina @ 2006-09-14 16:18 ` Dmitry Torokhov 2006-09-14 18:48 ` Jiri Kosina 0 siblings, 1 reply; 24+ messages in thread From: Dmitry Torokhov @ 2006-09-14 16:18 UTC (permalink / raw) To: Jiri Kosina; +Cc: lkml, Arjan van de Ven On 9/14/06, Jiri Kosina <jikos@jikos.cz> wrote: > On Thu, 14 Sep 2006, Dmitry Torokhov wrote: > > > Not yet ;) Is there a way to hide the depth in the spinlock/mutex > > structure itself so that initialization code could do > > spin_lock_init_nested() and spare the rest of the code from that > > knowledge? > > (shortened CC list a bit) > > In fact I am not sure what you mean. On every lock and unlock operation, > in case of recursive locking (which our case is), you have to provide > class identifier, which is used to distinguish if the lock is of the same > instance, or a different one (deeper or higher in the locking hierarchy). > There is no way how spin_lock() or mutex_lock() can know this > "automatically", you always have to provide the nesting level from > outside, as it depends on the ordering hierarchy, which locking primitives > are totally unaware of. > Well, we do not really care about nestiness do we? What we trying to achieve is to teach lockdep that 2 locks while appear as the lame lock in fact are different and protect 2 different structures. Ideally lockdep should track every lock individually (based for example on its address) but that would be too taxing so we need to help it. In your implementation you embed this data into structure/code using lock, but this information could be instilled into the lock itself upon initialization and spin_[un]lock() implementation could be taught to use this data thus making specialized spin_[un]lock*_nested() functions unnecessary. -- Dmitry ^ permalink raw reply [flat|nested] 24+ messages in thread
* Re: [PATCH 0/3] Synaptics - fix lockdep warnings 2006-09-14 16:18 ` Dmitry Torokhov @ 2006-09-14 18:48 ` Jiri Kosina 2006-09-14 18:56 ` Dmitry Torokhov 0 siblings, 1 reply; 24+ messages in thread From: Jiri Kosina @ 2006-09-14 18:48 UTC (permalink / raw) To: Dmitry Torokhov; +Cc: lkml, Arjan van de Ven, Ingo Molnar On Thu, 14 Sep 2006, Dmitry Torokhov wrote: > Well, we do not really care about nestiness do we? What we trying to > achieve is to teach lockdep that 2 locks while appear as the lame lock > in fact are different and protect 2 different structures. Ideally > lockdep should track every lock individually (based for example on its > address) but that would be too taxing so we need to help it. In your > implementation you embed this data into structure/code using lock, but > this information could be instilled into the lock itself upon > initialization and spin_[un]lock() implementation could be taught to use > this data thus making specialized spin_[un]lock*_nested() functions > unnecessary. Hi Dmitry, IMHO this is exactly what the nested locking primitives were introduced in lockdep for (we even have natural hierarchy here), so I am not sure if this is compliant with lockdep design. I definitely could do a patch that would introduce {spin,mutex..}_lock_init_subclass(), which would initialize the lock together with defining it's 'class', so that it could be distinguishable from any other lock of the same type during proving of correctness ... but this is a step towards distinguishing every single lock from all others (even of a same type), which I am not sure is the right direction. I added Ingo to CC. Thanks, -- JiKos. ^ permalink raw reply [flat|nested] 24+ messages in thread
* Re: [PATCH 0/3] Synaptics - fix lockdep warnings 2006-09-14 18:48 ` Jiri Kosina @ 2006-09-14 18:56 ` Dmitry Torokhov 2006-09-14 19:03 ` Arjan van de Ven 2006-09-14 19:56 ` Ingo Molnar 0 siblings, 2 replies; 24+ messages in thread From: Dmitry Torokhov @ 2006-09-14 18:56 UTC (permalink / raw) To: Jiri Kosina; +Cc: lkml, Arjan van de Ven, Ingo Molnar On 9/14/06, Jiri Kosina <jikos@jikos.cz> wrote: > On Thu, 14 Sep 2006, Dmitry Torokhov wrote: > > > Well, we do not really care about nestiness do we? What we trying to > > achieve is to teach lockdep that 2 locks while appear as the lame lock > > in fact are different and protect 2 different structures. Ideally > > lockdep should track every lock individually (based for example on its > > address) but that would be too taxing so we need to help it. In your > > implementation you embed this data into structure/code using lock, but > > this information could be instilled into the lock itself upon > > initialization and spin_[un]lock() implementation could be taught to use > > this data thus making specialized spin_[un]lock*_nested() functions > > unnecessary. > > Hi Dmitry, > > IMHO this is exactly what the nested locking primitives were introduced in > lockdep for (we even have natural hierarchy here), so I am not sure if > this is compliant with lockdep design. I definitely could do a patch that > would introduce {spin,mutex..}_lock_init_subclass(), which would > initialize the lock together with defining it's 'class', so that it could > be distinguishable from any other lock of the same type during proving of > correctness ... but this is a step towards distinguishing every single > lock from all others (even of a same type), which I am not sure is the > right direction. > I think it is - as far as I understand the reason for not tracking every lock individually is just that it is too expensive to do by default. -- Dmitry ^ permalink raw reply [flat|nested] 24+ messages in thread
* Re: [PATCH 0/3] Synaptics - fix lockdep warnings 2006-09-14 18:56 ` Dmitry Torokhov @ 2006-09-14 19:03 ` Arjan van de Ven 2006-09-14 19:11 ` Dmitry Torokhov 2006-09-14 19:56 ` Ingo Molnar 1 sibling, 1 reply; 24+ messages in thread From: Arjan van de Ven @ 2006-09-14 19:03 UTC (permalink / raw) To: Dmitry Torokhov; +Cc: Jiri Kosina, lkml, Ingo Molnar > > I think it is - as far as I understand the reason for not tracking > every lock individually is just that it is too expensive to do by > default. that is not correct. While it certainly plays a role, the other reason is that you can find out "class" level locking rules (such as inode->i_mutex comes before <other lock>) for all inodes at a time; eg no need to see every inode do this before you can find the deadlock. ^ permalink raw reply [flat|nested] 24+ messages in thread
* Re: [PATCH 0/3] Synaptics - fix lockdep warnings 2006-09-14 19:03 ` Arjan van de Ven @ 2006-09-14 19:11 ` Dmitry Torokhov 2006-09-15 5:33 ` Arjan van de Ven 0 siblings, 1 reply; 24+ messages in thread From: Dmitry Torokhov @ 2006-09-14 19:11 UTC (permalink / raw) To: Arjan van de Ven; +Cc: Jiri Kosina, lkml, Ingo Molnar On 9/14/06, Arjan van de Ven <arjan@infradead.org> wrote: > > > > > I think it is - as far as I understand the reason for not tracking > > every lock individually is just that it is too expensive to do by > > default. > > that is not correct. While it certainly plays a role, > the other reason is that you can find out "class" level locking rules > (such as inode->i_mutex comes before <other lock>) for all inodes at a > time; eg no need to see every inode do this before you can find the > deadlock. > OK, I can see that. However you must agree that for certain locks we do want to track them individually, right? -- Dmitry ^ permalink raw reply [flat|nested] 24+ messages in thread
* Re: [PATCH 0/3] Synaptics - fix lockdep warnings 2006-09-14 19:11 ` Dmitry Torokhov @ 2006-09-15 5:33 ` Arjan van de Ven 2006-09-15 13:20 ` Dmitry Torokhov 0 siblings, 1 reply; 24+ messages in thread From: Arjan van de Ven @ 2006-09-15 5:33 UTC (permalink / raw) To: Dmitry Torokhov; +Cc: Jiri Kosina, lkml, Ingo Molnar On Thu, 2006-09-14 at 15:11 -0400, Dmitry Torokhov wrote: > On 9/14/06, Arjan van de Ven <arjan@infradead.org> wrote: > > > > > > > > I think it is - as far as I understand the reason for not tracking > > > every lock individually is just that it is too expensive to do by > > > default. > > > > that is not correct. While it certainly plays a role, > > the other reason is that you can find out "class" level locking rules > > (such as inode->i_mutex comes before <other lock>) for all inodes at a > > time; eg no need to see every inode do this before you can find the > > deadlock. > > > > OK, I can see that. However you must agree that for certain locks we > do want to track them individually, right? I agree that if locks really represent different objects with different locking semantics they should not share the class. Lockdep provides a mechanism for that; however I'm very afraid that for the input layer, they really are not that, they are not different objects with different semantics; they are the same objects with nesting semantics! In that case the "separate lock class" stuff has only disadvantages. The worst thing is that as I understand it this separate class is *dynamic*. Eg it's not even "one class per driver" ;( ^ permalink raw reply [flat|nested] 24+ messages in thread
* Re: [PATCH 0/3] Synaptics - fix lockdep warnings 2006-09-15 5:33 ` Arjan van de Ven @ 2006-09-15 13:20 ` Dmitry Torokhov 2006-09-15 13:38 ` Jiri Kosina 0 siblings, 1 reply; 24+ messages in thread From: Dmitry Torokhov @ 2006-09-15 13:20 UTC (permalink / raw) To: Arjan van de Ven; +Cc: Jiri Kosina, lkml, Ingo Molnar On 9/15/06, Arjan van de Ven <arjan@infradead.org> wrote: > On Thu, 2006-09-14 at 15:11 -0400, Dmitry Torokhov wrote: > > On 9/14/06, Arjan van de Ven <arjan@infradead.org> wrote: > > > > > > > > > > > I think it is - as far as I understand the reason for not tracking > > > > every lock individually is just that it is too expensive to do by > > > > default. > > > > > > that is not correct. While it certainly plays a role, > > > the other reason is that you can find out "class" level locking rules > > > (such as inode->i_mutex comes before <other lock>) for all inodes at a > > > time; eg no need to see every inode do this before you can find the > > > deadlock. > > > > > > > OK, I can see that. However you must agree that for certain locks we > > do want to track them individually, right? > > I agree that if locks really represent different objects with different > locking semantics they should not share the class. Lockdep provides a > mechanism for that; however I'm very afraid that for the input layer, > they really are not that, they are not different objects with different > semantics; they are the same objects with nesting semantics! In that > case the "separate lock class" stuff has only disadvantages. I'd say they are different objects with the same semantics... > The worst thing is that as I understand it this separate class is > *dynamic*. Eg it's not even "one class per driver" ;( > You are saying this as if was a bad thing. Pass-through ports just implement PS/2 over PS/2 protocols and as such it is very natural that the same driver that serves parent serves the child as well. That was the goal - to reuse psmouse module instead of re-implementing all re-probing and protocol decoding in synaptics driver. And trackpint driver. And maybe somethng else down the road. I also wonder that even if we had several drivers lockdep would still complain about nestiness just because all PS/2 devices are initialized via ps2_init (which initializes command mutex) and end up in the same lock class. I suspect that other driver implementing X-over-X or X-over-Y-over-X may get hit the same way by lockdep. I understand what Ingo is saying about detecting deadlocks across the pool of locks of the same class not waiting till they really clash, it is really useful. I also want to make my code as independent of lockdep as possible. Having a speciall marking on the locks themselves (done upon creation) instead of altering call sites is the cleanest way IMHO. Can we have a flag in the lock structure that would tell lockdep that it is OK for the given lock to be taken several times (i.e. the locks are really on the different objects)? This would still allow to detect incorrect locking across different classes. -- Dmitry ^ permalink raw reply [flat|nested] 24+ messages in thread
* Re: [PATCH 0/3] Synaptics - fix lockdep warnings 2006-09-15 13:20 ` Dmitry Torokhov @ 2006-09-15 13:38 ` Jiri Kosina 2006-09-15 13:51 ` Dmitry Torokhov 0 siblings, 1 reply; 24+ messages in thread From: Jiri Kosina @ 2006-09-15 13:38 UTC (permalink / raw) To: Dmitry Torokhov; +Cc: Arjan van de Ven, lkml, Ingo Molnar On Fri, 15 Sep 2006, Dmitry Torokhov wrote: > I understand what Ingo is saying about detecting deadlocks across the > pool of locks of the same class not waiting till they really clash, it > is really useful. I also want to make my code as independent of lockdep > as possible. Having a speciall marking on the locks themselves (done > upon creation) instead of altering call sites is the cleanest way IMHO. > Can we have a flag in the lock structure that would tell lockdep that it > is OK for the given lock to be taken several times (i.e. the locks are > really on the different objects)? This would still allow to detect > incorrect locking across different classes. Yes, but unfortunately marking the lock as 'can-be-taken-multiple-times' is weaker than using the nested locking provided by lockdep. i.e. if you mark a lock this way, it opens door for having deadlock, which won't be detected by lockdep. This will happen if the code, by mistake, really takes the _very same_ lock twice. lockdep will not be able to detect this, when the lock is marked in a way you propose, but is able to detect this when using the nested semantics. -- JiKos. ^ permalink raw reply [flat|nested] 24+ messages in thread
* Re: [PATCH 0/3] Synaptics - fix lockdep warnings 2006-09-15 13:38 ` Jiri Kosina @ 2006-09-15 13:51 ` Dmitry Torokhov 2006-09-15 13:56 ` Dmitry Torokhov 0 siblings, 1 reply; 24+ messages in thread From: Dmitry Torokhov @ 2006-09-15 13:51 UTC (permalink / raw) To: Jiri Kosina; +Cc: Arjan van de Ven, lkml, Ingo Molnar On 9/15/06, Jiri Kosina <jikos@jikos.cz> wrote: > On Fri, 15 Sep 2006, Dmitry Torokhov wrote: > > > I understand what Ingo is saying about detecting deadlocks across the > > pool of locks of the same class not waiting till they really clash, it > > is really useful. I also want to make my code as independent of lockdep > > as possible. Having a speciall marking on the locks themselves (done > > upon creation) instead of altering call sites is the cleanest way IMHO. > > Can we have a flag in the lock structure that would tell lockdep that it > > is OK for the given lock to be taken several times (i.e. the locks are > > really on the different objects)? This would still allow to detect > > incorrect locking across different classes. > > Yes, but unfortunately marking the lock as 'can-be-taken-multiple-times' > is weaker than using the nested locking provided by lockdep. > > i.e. if you mark a lock this way, it opens door for having deadlock, which > won't be detected by lockdep. This will happen if the code, by mistake, > really takes the _very same_ lock twice. lockdep will not be able to > detect this, when the lock is marked in a way you propose, but is able to > detect this when using the nested semantics. > But nested semantics breaks the notion of the locks belonging to the same pool so both solutions have tradeoffs. I could use either one of these as long as details are hidden and callers do not have to care. -- Dmitry ^ permalink raw reply [flat|nested] 24+ messages in thread
* Re: [PATCH 0/3] Synaptics - fix lockdep warnings 2006-09-15 13:51 ` Dmitry Torokhov @ 2006-09-15 13:56 ` Dmitry Torokhov 0 siblings, 0 replies; 24+ messages in thread From: Dmitry Torokhov @ 2006-09-15 13:56 UTC (permalink / raw) To: Jiri Kosina; +Cc: Arjan van de Ven, lkml, Ingo Molnar On 9/15/06, Dmitry Torokhov <dmitry.torokhov@gmail.com> wrote: > On 9/15/06, Jiri Kosina <jikos@jikos.cz> wrote: > > On Fri, 15 Sep 2006, Dmitry Torokhov wrote: > > > > > I understand what Ingo is saying about detecting deadlocks across the > > > pool of locks of the same class not waiting till they really clash, it > > > is really useful. I also want to make my code as independent of lockdep > > > as possible. Having a speciall marking on the locks themselves (done > > > upon creation) instead of altering call sites is the cleanest way IMHO. > > > Can we have a flag in the lock structure that would tell lockdep that it > > > is OK for the given lock to be taken several times (i.e. the locks are > > > really on the different objects)? This would still allow to detect > > > incorrect locking across different classes. > > > > Yes, but unfortunately marking the lock as 'can-be-taken-multiple-times' > > is weaker than using the nested locking provided by lockdep. > > > > i.e. if you mark a lock this way, it opens door for having deadlock, which > > won't be detected by lockdep. This will happen if the code, by mistake, > > really takes the _very same_ lock twice. lockdep will not be able to > > detect this, when the lock is marked in a way you propose, but is able to > > detect this when using the nested semantics. > > > > But nested semantics breaks the notion of the locks belonging to the > same pool so both solutions have tradeoffs. I could use either one of > these as long as details are hidden and callers do not have to care. > One more thing I forgot to add - how will we deal with lockdep in cases when we have X-over-Y-over-X protocol, when there is no tight coupling between the X parts so it is impossible to know when to apply special marking on the lock or callers? -- Dmitry ^ permalink raw reply [flat|nested] 24+ messages in thread
* Re: [PATCH 0/3] Synaptics - fix lockdep warnings 2006-09-14 18:56 ` Dmitry Torokhov 2006-09-14 19:03 ` Arjan van de Ven @ 2006-09-14 19:56 ` Ingo Molnar 1 sibling, 0 replies; 24+ messages in thread From: Ingo Molnar @ 2006-09-14 19:56 UTC (permalink / raw) To: Dmitry Torokhov; +Cc: Jiri Kosina, lkml, Arjan van de Ven * Dmitry Torokhov <dmitry.torokhov@gmail.com> wrote: > I think it is - as far as I understand the reason for not tracking > every lock individually is just that it is too expensive to do by > default. that is not at all the reason! The reason is that we want to find deadlocks _as early as mathematically possible_ (in a running system, where locking patterns are observed). That is we want to gather the _most generic_ locking rules. For example, if there are lock_1A, lock_1B of the same lock class, and lock_2A and lock_2B of another lock class. If we observed the following usage patterns: acquire(lock_1A); acquire(lock_2A); release(lock_2A); release(lock_1A); and another piece of kernel code did: acquire(lock_2B); acquire(lock_1B); release(lock_1B); release(lock_1B); with per-lock rules there's no problem detected, because the 4 locks are independent and we only observed a 1A->2A and a 2B->1B dependency. But with per-class rule gather we'd observe the 1->2 and the 2->1 dependency, and we'd warn that there's a deadlock. So we want to create as broad, as generic rules as possible, to catch deadlocks as soon as it's _provable_ that they could occur. In that sense lockdep wants to have a '100% proof' of correctness: the first time a bad even happens we flag it. Ingo ^ permalink raw reply [flat|nested] 24+ messages in thread
end of thread, other threads:[~2006-09-15 13:56 UTC | newest] Thread overview: 24+ messages (download: mbox.gz follow: Atom feed -- links below jump to the message on this page -- 2006-09-14 0:44 [PATCH 0/3] Synaptics - fix lockdep warnings Jiri Kosina 2006-09-14 0:44 ` [PATCH 1/3] " Jiri Kosina 2006-09-14 0:44 ` [PATCH 2/3] " Jiri Kosina 2006-09-14 0:44 ` [PATCH 3/3] " Jiri Kosina 2006-09-14 2:00 ` [PATCH 0/3] " Dmitry Torokhov 2006-09-14 8:43 ` Jiri Kosina 2006-09-14 13:18 ` Dmitry Torokhov 2006-09-14 14:39 ` Jiri Kosina 2006-09-14 14:58 ` Dmitry Torokhov 2006-09-14 15:03 ` Arjan van de Ven 2006-09-14 15:08 ` Jiri Kosina 2006-09-14 15:51 ` Dmitry Torokhov 2006-09-14 16:00 ` Jiri Kosina 2006-09-14 16:18 ` Dmitry Torokhov 2006-09-14 18:48 ` Jiri Kosina 2006-09-14 18:56 ` Dmitry Torokhov 2006-09-14 19:03 ` Arjan van de Ven 2006-09-14 19:11 ` Dmitry Torokhov 2006-09-15 5:33 ` Arjan van de Ven 2006-09-15 13:20 ` Dmitry Torokhov 2006-09-15 13:38 ` Jiri Kosina 2006-09-15 13:51 ` Dmitry Torokhov 2006-09-15 13:56 ` Dmitry Torokhov 2006-09-14 19:56 ` Ingo Molnar
This is a public inbox, see mirroring instructions for how to clone and mirror all data and code used for this inbox