[PATCH] bcm43xx: netlink deadlock fix

reported by Jure Repinc:

> > http://bugzilla.kernel.org/show_bug.cgi?id=6773

> > checked out dmesg output and found the message
> >
> > ======================================================
> > [ BUG: hard-safe -> hard-unsafe lock order detected! ]
> > ------------------------------------------------------
> >
> > starting at line 660 of the dmesg.txt that I will attach.

The patch below should fix the deadlock, albeit I suspect it's not the
"right" fix; the right fix may well be to move the rx processing in bcm43xx
to softirq context.  [it's debatable, ipw2200 hit this exact same bug; at
some point it's better to bite the bullet and move this to the common layer
as my patch below does]

Make the nl_table_lock irq-safe; it's taken for read in various netlink
functions, including functions that several wireless drivers (ipw2200,
bcm43xx) want to call from hardirq context.

The deadlock was found by the lock validator.

Signed-off-by: Arjan van de Ven <arjan@linux.intel.com>
Signed-off-by: Ingo Molnar <mingo@elte.hu>
Signed-off-by: Herbert Xu <herbert@gondor.apana.org.au>
Cc: Michael Buesch <mb@bu3sch.de>
Cc: "John W. Linville" <linville@tuxdriver.com>
Cc: Jeff Garzik <jeff@garzik.org>
Acked-by: "David S. Miller" <davem@davemloft.net>
Cc: jamal <hadi@cyberus.ca>
Signed-off-by: Andrew Morton <akpm@osdl.org>
Signed-off-by: Linus Torvalds <torvalds@osdl.org>
This commit is contained in:
Arjan van de Ven 2006-07-03 00:24:07 -07:00 committed by Linus Torvalds
parent b02454f435
commit 6abd219c6e
1 changed files with 4 additions and 4 deletions

View File

@ -156,7 +156,7 @@ static void netlink_sock_destruct(struct sock *sk)
static void netlink_table_grab(void) static void netlink_table_grab(void)
{ {
write_lock_bh(&nl_table_lock); write_lock_irq(&nl_table_lock);
if (atomic_read(&nl_table_users)) { if (atomic_read(&nl_table_users)) {
DECLARE_WAITQUEUE(wait, current); DECLARE_WAITQUEUE(wait, current);
@ -166,9 +166,9 @@ static void netlink_table_grab(void)
set_current_state(TASK_UNINTERRUPTIBLE); set_current_state(TASK_UNINTERRUPTIBLE);
if (atomic_read(&nl_table_users) == 0) if (atomic_read(&nl_table_users) == 0)
break; break;
write_unlock_bh(&nl_table_lock); write_unlock_irq(&nl_table_lock);
schedule(); schedule();
write_lock_bh(&nl_table_lock); write_lock_irq(&nl_table_lock);
} }
__set_current_state(TASK_RUNNING); __set_current_state(TASK_RUNNING);
@ -178,7 +178,7 @@ static void netlink_table_grab(void)
static __inline__ void netlink_table_ungrab(void) static __inline__ void netlink_table_ungrab(void)
{ {
write_unlock_bh(&nl_table_lock); write_unlock_irq(&nl_table_lock);
wake_up(&nl_table_wait); wake_up(&nl_table_wait);
} }