mirror of https://lore.kernel.org/lkml/
 help / color / mirror / Atom feed
* [RFC][PATCH] netconsole: avoid deadlock on printk from driver code
@ 2008-08-13  9:53 Vegard Nossum
  2008-08-13  9:59 ` Alexey Dobriyan
  2008-08-13 10:37 ` David Miller
  0 siblings, 2 replies; 14+ messages in thread
From: Vegard Nossum @ 2008-08-13  9:53 UTC (permalink / raw)
  To: netdev, linux-kernel; +Cc: Jeff Garzik, Alexey Dobriyan

>From b96d44099cc28d084bc1e86aba45465505362298 Mon Sep 17 00:00:00 2001
From: Vegard Nossum <vegard.nossum@gmail.com>
Date: Wed, 13 Aug 2008 11:52:21 +0200
Subject: [PATCH] netconsole: avoid deadlock on printk from driver code

I encountered a hard-to-debug deadlock when I pulled out the plug of my
RealTek 8139 which was also running netconsole: The driver wants to print
a "link down" message. However, this triggers netconsole, which wants to
print the message using the same device. Here is a backtrace:

 [<c05916b6>] _spin_lock_irqsave+0x76/0x90
 [<c035b255>] rtl8139_start_xmit+0x65/0x130 <-- spin_lock(&tp->lock)
 [<c04c5e28>] netpoll_send_skb+0x158/0x1a0
 [<c04c62fb>] netpoll_send_udp+0x1db/0x1f0
 [<c037c70c>] write_msg+0x8c/0xc0
 [<c0135883>] __call_console_drivers+0x53/0x60
 [<c01358db>] _call_console_drivers+0x4b/0x90
 [<c0135a25>] release_console_sem+0xc5/0x1f0
 [<c0135f0b>] vprintk+0x1ab/0x3e0
 [<c013615b>] printk+0x1b/0x20
 [<c0349736>] mii_check_media+0x196/0x1e0
 [<c03597f4>] rtl_check_media+0x24/0x30
 [<c035a0ea>] rtl8139_interrupt+0x42a/0x4a0 <-- spin_lock(&tp->lock)
 [<c01716d8>] handle_IRQ_event+0x28/0x70
 [<c0172d9b>] handle_fasteoi_irq+0x6b/0xe0
 [<c0107128>] do_IRQ+0x48/0xa0

The least invasive fix is to detect that we're trying to re-enter the
driver code. We provide a netdev_busy() function which can be used to
determine whether a deadlock can occur if we try to transmit another
packet.

Note that this may lead to lost messages if the driver is active on
another CPU while we try to use the same device for netconsole. It would
probably be best to set a "lost messages" flag in this case and add it
to the stream when the device becomes ready again.

The only extra overhead in non-netconsole code paths is the fact that we
need another callback in struct net_device. However, all drivers must be
checked for the possibility of a deadlock and implement the ->busy()
callback as necessary.

(Patch is untested.)

Cc: Alexey Dobriyan <adobriyan@gmail.com>
Cc: Jeff Garzik <jgarzik@pobox.com>
Signed-off-by: Vegard Nossum <vegard.nossum@gmail.com>
---
 drivers/net/8139too.c     |    7 +++++++
 drivers/net/netconsole.c  |    5 ++++-
 include/linux/netdevice.h |   19 +++++++++++++++++++
 3 files changed, 30 insertions(+), 1 deletions(-)

diff --git a/drivers/net/8139too.c b/drivers/net/8139too.c
index 8a5b0d2..c1af142 100644
--- a/drivers/net/8139too.c
+++ b/drivers/net/8139too.c
@@ -636,6 +636,7 @@ static void rtl8139_tx_timeout (struct net_device *dev);
 static void rtl8139_init_ring (struct net_device *dev);
 static int rtl8139_start_xmit (struct sk_buff *skb,
 			       struct net_device *dev);
+static bool rtl8139_busy (struct net_device *dev);
 #ifdef CONFIG_NET_POLL_CONTROLLER
 static void rtl8139_poll_controller(struct net_device *dev);
 #endif
@@ -979,6 +980,7 @@ static int __devinit rtl8139_init_one (struct pci_dev *pdev,
 	/* The Rtl8139-specific entries in the device structure. */
 	dev->open = rtl8139_open;
 	dev->hard_start_xmit = rtl8139_start_xmit;
+	dev->busy = rtl8139_busy;
 	netif_napi_add(dev, &tp->napi, rtl8139_poll, 64);
 	dev->stop = rtl8139_close;
 	dev->get_stats = rtl8139_get_stats;
@@ -1741,6 +1743,11 @@ static int rtl8139_start_xmit (struct sk_buff *skb, struct net_device *dev)
 	return 0;
 }
 
+static bool rtl8139_busy (struct net_device *dev)
+{
+	struct rtl8139_private *tp = netdev_priv(dev);
+	return spin_is_locked(&tp->lock);
+}
 
 static void rtl8139_tx_interrupt (struct net_device *dev,
 				  struct rtl8139_private *tp,
diff --git a/drivers/net/netconsole.c b/drivers/net/netconsole.c
index 9681618..b06d7ef 100644
--- a/drivers/net/netconsole.c
+++ b/drivers/net/netconsole.c
@@ -707,8 +707,11 @@ static void write_msg(struct console *con, const char *msg, unsigned int len)
 
 	spin_lock_irqsave(&target_list_lock, flags);
 	list_for_each_entry(nt, &target_list, list) {
+		struct net_device *dev;
+
 		netconsole_target_get(nt);
-		if (nt->enabled && netif_running(nt->np.dev)) {
+		dev = nt->np.dev;
+		if (nt->enabled && netif_running(dev) && !netdev_busy(dev)) {
 			/*
 			 * We nest this inside the for-each-target loop above
 			 * so that we're able to get as much logging out to
diff --git a/include/linux/netdevice.h b/include/linux/netdevice.h
index 488c56e..8865a17 100644
--- a/include/linux/netdevice.h
+++ b/include/linux/netdevice.h
@@ -642,6 +642,10 @@ struct net_device
 	void			*priv;	/* pointer to private data	*/
 	int			(*hard_start_xmit) (struct sk_buff *skb,
 						    struct net_device *dev);
+
+	/* Don't use directly; see netdev_busy() below. */
+	bool			(*busy) (struct net_device *dev);
+
 	/* These may be needed for future network-power-down code. */
 	unsigned long		trans_start;	/* Time (in jiffies) of last Tx	*/
 
@@ -809,6 +813,21 @@ static inline void *netdev_priv(const struct net_device *dev)
 			      & ~NETDEV_ALIGN_CONST);
 }
 
+/**
+ *	netdev_busy -r eturns false if ->hard_start_xmit() may deadlock
+ *	@dev: network device
+ *
+ * More specifically, the driver callback must return true if any of the
+ * locks that are needed for ->hard_start_xmit() are locked. This may look
+ * like a race (because somebody else can take the locks in-between), but
+ * that's fine; we only want to avoid the situation where we can deadlock
+ * against ourselves.
+ */
+static inline bool netdev_busy(struct net_device *dev)
+{
+	return dev->busy && dev->busy(dev);
+}
+
 /* Set the sysfs physical device reference for the network logical device
  * if set prior to registration will cause a symlink during initialization.
  */
-- 
1.5.5.1


^ permalink raw reply	[flat|nested] 14+ messages in thread

* Re: [RFC][PATCH] netconsole: avoid deadlock on printk from driver code
  2008-08-13  9:53 [RFC][PATCH] netconsole: avoid deadlock on printk from driver code Vegard Nossum
@ 2008-08-13  9:59 ` Alexey Dobriyan
  2008-08-13 10:21   ` Vegard Nossum
  2008-08-13 10:29   ` David Miller
  2008-08-13 10:37 ` David Miller
  1 sibling, 2 replies; 14+ messages in thread
From: Alexey Dobriyan @ 2008-08-13  9:59 UTC (permalink / raw)
  To: Vegard Nossum; +Cc: netdev, linux-kernel, Jeff Garzik

On Wed, Aug 13, 2008 at 11:53:24AM +0200, Vegard Nossum wrote:
> I encountered a hard-to-debug deadlock when I pulled out the plug of my
> RealTek 8139 which was also running netconsole: The driver wants to print
> a "link down" message. However, this triggers netconsole, which wants to
> print the message using the same device. Here is a backtrace:
> 
>  [<c05916b6>] _spin_lock_irqsave+0x76/0x90
>  [<c035b255>] rtl8139_start_xmit+0x65/0x130 <-- spin_lock(&tp->lock)
>  [<c04c5e28>] netpoll_send_skb+0x158/0x1a0
>  [<c04c62fb>] netpoll_send_udp+0x1db/0x1f0
>  [<c037c70c>] write_msg+0x8c/0xc0
>  [<c0135883>] __call_console_drivers+0x53/0x60
>  [<c01358db>] _call_console_drivers+0x4b/0x90
>  [<c0135a25>] release_console_sem+0xc5/0x1f0
>  [<c0135f0b>] vprintk+0x1ab/0x3e0
>  [<c013615b>] printk+0x1b/0x20
>  [<c0349736>] mii_check_media+0x196/0x1e0
>  [<c03597f4>] rtl_check_media+0x24/0x30
>  [<c035a0ea>] rtl8139_interrupt+0x42a/0x4a0 <-- spin_lock(&tp->lock)
>  [<c01716d8>] handle_IRQ_event+0x28/0x70
>  [<c0172d9b>] handle_fasteoi_irq+0x6b/0xe0
>  [<c0107128>] do_IRQ+0x48/0xa0
> 
> The least invasive fix is to detect that we're trying to re-enter the
> driver code. We provide a netdev_busy() function which can be used to
> determine whether a deadlock can occur if we try to transmit another
> packet.
> 
> Note that this may lead to lost messages if the driver is active on
> another CPU while we try to use the same device for netconsole.

This sucks.

> It would probably be best to set a "lost messages" flag in this case and
> add it to the stream when the device becomes ready again.
> 
> The only extra overhead in non-netconsole code paths is the fact that we
> need another callback in struct net_device. However, all drivers must be
> checked for the possibility of a deadlock and implement the ->busy()
> callback as necessary.

> --- a/drivers/net/8139too.c
> +++ b/drivers/net/8139too.c
> @@ -979,6 +980,7 @@ static int __devinit rtl8139_init_one (struct pci_dev *pdev,
>  	/* The Rtl8139-specific entries in the device structure. */
>  	dev->open = rtl8139_open;
>  	dev->hard_start_xmit = rtl8139_start_xmit;
> +	dev->busy = rtl8139_busy;
>  	netif_napi_add(dev, &tp->napi, rtl8139_poll, 64);
>  	dev->stop = rtl8139_close;
>  	dev->get_stats = rtl8139_get_stats;
> @@ -1741,6 +1743,11 @@ static int rtl8139_start_xmit (struct sk_buff *skb, struct net_device *dev)
>  	return 0;
>  }
>  
> +static bool rtl8139_busy (struct net_device *dev)
> +{
> +	struct rtl8139_private *tp = netdev_priv(dev);
> +	return spin_is_locked(&tp->lock);
> +}

How do I know if my driver is suspectible to this sort of deadlock?


^ permalink raw reply	[flat|nested] 14+ messages in thread

* Re: [RFC][PATCH] netconsole: avoid deadlock on printk from driver code
  2008-08-13  9:59 ` Alexey Dobriyan
@ 2008-08-13 10:21   ` Vegard Nossum
  2008-08-13 10:29   ` David Miller
  1 sibling, 0 replies; 14+ messages in thread
From: Vegard Nossum @ 2008-08-13 10:21 UTC (permalink / raw)
  To: Alexey Dobriyan; +Cc: netdev, linux-kernel, Jeff Garzik

(Hm, did my original e-mail not make it to the lists?)

>> The least invasive fix is to detect that we're trying to re-enter the
>> driver code. We provide a netdev_busy() function which can be used to
>> determine whether a deadlock can occur if we try to transmit another
>> packet.
>>
>> Note that this may lead to lost messages if the driver is active on
>> another CPU while we try to use the same device for netconsole.
>
> This sucks.

Indeed. What can be done about it?

>> It would probably be best to set a "lost messages" flag in this case and
>> add it to the stream when the device becomes ready again.

With such a flag, we can at least avoid silent loss of messages. But
what is the likelihood of this happening in the first place? I have no
idea.

I still think that this is better than a possible deadlock, which
gives NO CLUE as to what happened (because it jams the other
consoles). Hopefully the interface will not be used for other traffic.

But I agree. This possibly penalizes all the other cases where people
*don't* pull out their netconsole-device cables.

We could simply not print out the "link up/down" message if the device
is running netconsole. But it feels like papering over the design
error. Because there are other functions in there which may cause
additional messages to be printed, not just the very visible printk().

Can we detect if the lock was taken on the same CPU or not?

Maybe it is possible to postpone the packet instead of discarding it?

>> +static bool rtl8139_busy (struct net_device *dev)
>> +{
>> +     struct rtl8139_private *tp = netdev_priv(dev);
>> +     return spin_is_locked(&tp->lock);
>> +}
>
> How do I know if my driver is suspectible to this sort of deadlock?

if the ->hard_start_xmit() takes any locks which can be taken from any
code that calls (also indirectly!) printk(), in this case the
interrupt handler that is invoked when I replace the cable. My guess
is that _all_ drivers need to take some sort of lock in
hard_start_xmit().

It's a bit fragile, I agree. But the completely silent deadlock is nasty too!


Vegard

-- 
"The animistic metaphor of the bug that maliciously sneaked in while
the programmer was not looking is intellectually dishonest as it
disguises that the error is the programmer's own creation."
	-- E. W. Dijkstra, EWD1036

^ permalink raw reply	[flat|nested] 14+ messages in thread

* Re: [RFC][PATCH] netconsole: avoid deadlock on printk from driver code
  2008-08-13  9:59 ` Alexey Dobriyan
  2008-08-13 10:21   ` Vegard Nossum
@ 2008-08-13 10:29   ` David Miller
  2008-08-13 10:44     ` Vegard Nossum
  1 sibling, 1 reply; 14+ messages in thread
From: David Miller @ 2008-08-13 10:29 UTC (permalink / raw)
  To: adobriyan; +Cc: vegard.nossum, netdev, linux-kernel, jgarzik

From: Alexey Dobriyan <adobriyan@gmail.com>
Date: Wed, 13 Aug 2008 13:59:43 +0400

> On Wed, Aug 13, 2008 at 11:53:24AM +0200, Vegard Nossum wrote:
> > I encountered a hard-to-debug deadlock when I pulled out the plug of my
> > RealTek 8139 which was also running netconsole: The driver wants to print
> > a "link down" message. However, this triggers netconsole, which wants to
> > print the message using the same device. Here is a backtrace:
> > 
> >  [<c05916b6>] _spin_lock_irqsave+0x76/0x90
> >  [<c035b255>] rtl8139_start_xmit+0x65/0x130 <-- spin_lock(&tp->lock)
> >  [<c04c5e28>] netpoll_send_skb+0x158/0x1a0
> >  [<c04c62fb>] netpoll_send_udp+0x1db/0x1f0
> >  [<c037c70c>] write_msg+0x8c/0xc0
> >  [<c0135883>] __call_console_drivers+0x53/0x60
> >  [<c01358db>] _call_console_drivers+0x4b/0x90
> >  [<c0135a25>] release_console_sem+0xc5/0x1f0
> >  [<c0135f0b>] vprintk+0x1ab/0x3e0
> >  [<c013615b>] printk+0x1b/0x20
> >  [<c0349736>] mii_check_media+0x196/0x1e0
> >  [<c03597f4>] rtl_check_media+0x24/0x30
> >  [<c035a0ea>] rtl8139_interrupt+0x42a/0x4a0 <-- spin_lock(&tp->lock)
> >  [<c01716d8>] handle_IRQ_event+0x28/0x70
> >  [<c0172d9b>] handle_fasteoi_irq+0x6b/0xe0
> >  [<c0107128>] do_IRQ+0x48/0xa0
> > 
> > The least invasive fix is to detect that we're trying to re-enter the
> > driver code. We provide a netdev_busy() function which can be used to
> > determine whether a deadlock can occur if we try to transmit another
> > packet.
> > 
> > Note that this may lead to lost messages if the driver is active on
> > another CPU while we try to use the same device for netconsole.
> 
> This sucks.

It's also the wrong fix.

As a quicker and more palatable solution, print your link status
message in some kind of deferred context where you can have the
lock not held or similar.

^ permalink raw reply	[flat|nested] 14+ messages in thread

* Re: [RFC][PATCH] netconsole: avoid deadlock on printk from driver code
  2008-08-13  9:53 [RFC][PATCH] netconsole: avoid deadlock on printk from driver code Vegard Nossum
  2008-08-13  9:59 ` Alexey Dobriyan
@ 2008-08-13 10:37 ` David Miller
  2008-08-14 13:28   ` Pekka Enberg
  1 sibling, 1 reply; 14+ messages in thread
From: David Miller @ 2008-08-13 10:37 UTC (permalink / raw)
  To: vegard.nossum, vegardno; +Cc: netdev, linux-kernel, jgarzik, adobriyan

From: Vegard Nossum <vegardno@ifi.uio.no>
Date: Wed, 13 Aug 2008 11:53:24 +0200

> [PATCH] netconsole: avoid deadlock on printk from driver code
> 
> I encountered a hard-to-debug deadlock when I pulled out the plug of my
> RealTek 8139 which was also running netconsole: The driver wants to print
> a "link down" message. However, this triggers netconsole, which wants to
> print the message using the same device. Here is a backtrace:

See my other reply, this is absolutely the wrong way to go about
this.

You only have two sane options:

1) Defer the link status printk message into a deferred context,
   such as a workqueue, so that you can do it outside of the
   lock.

2) Do your locking differently so that the link status handling
   locking does not bisect the locking used for packet transmit
   in ->hard_start_xmit().

#2 is the reason why most other drivers don't have this silly
bug, they don't hold TX path locks when handling link status
and printing out such messages.

^ permalink raw reply	[flat|nested] 14+ messages in thread

* Re: [RFC][PATCH] netconsole: avoid deadlock on printk from driver code
  2008-08-13 10:29   ` David Miller
@ 2008-08-13 10:44     ` Vegard Nossum
  2008-08-13 10:56       ` David Miller
  0 siblings, 1 reply; 14+ messages in thread
From: Vegard Nossum @ 2008-08-13 10:44 UTC (permalink / raw)
  To: David Miller; +Cc: adobriyan, netdev, linux-kernel, jgarzik

On Wed, Aug 13, 2008 at 12:29 PM, David Miller <davem@davemloft.net> wrote:
> From: Alexey Dobriyan <adobriyan@gmail.com>
> Date: Wed, 13 Aug 2008 13:59:43 +0400
>> > The least invasive fix is to detect that we're trying to re-enter the
>> > driver code. We provide a netdev_busy() function which can be used to
>> > determine whether a deadlock can occur if we try to transmit another
>> > packet.
>> >
>> > Note that this may lead to lost messages if the driver is active on
>> > another CPU while we try to use the same device for netconsole.
>>
>> This sucks.
>
> It's also the wrong fix.
>
> As a quicker and more palatable solution, print your link status
> message in some kind of deferred context where you can have the
> lock not held or similar.

This is true, but it is very fragile. It fixes only one case (exactly
the case that I saw), while there may be many more of the same nature.

For your proposed fix to work in all cases, _all_ printks coming from
rtl8139_tx_interrupt() must be printed in a different context. That
includes, but is not necessarily limited to, these obvious cases:

        DPRINTK ("%s: Abnormal interrupt, status %8.8x.\n",
                 dev->name, status);

    printk(KERN_DEBUG "%s: Transmit error, Tx status %8.8x.\n",

                printk (KERN_ERR "%s: PCI Bus error %4.4x.\n",
                        dev->name, pci_cmd_status);

                printk (KERN_ERR "%s: Out-of-sync dirty pointer, %ld
vs. %ld.\n",

There must also be no BUG()s, WARN()s, other debugging facilities
(spinlock debugging, lockdep, irqtrace, etc.) triggering which may
call printk() inside the protected section. Can we really ensure this?
For all drivers supporting netconsole?


Vegard

-- 
"The animistic metaphor of the bug that maliciously sneaked in while
the programmer was not looking is intellectually dishonest as it
disguises that the error is the programmer's own creation."
	-- E. W. Dijkstra, EWD1036

^ permalink raw reply	[flat|nested] 14+ messages in thread

* Re: [RFC][PATCH] netconsole: avoid deadlock on printk from driver code
  2008-08-13 10:44     ` Vegard Nossum
@ 2008-08-13 10:56       ` David Miller
  0 siblings, 0 replies; 14+ messages in thread
From: David Miller @ 2008-08-13 10:56 UTC (permalink / raw)
  To: vegard.nossum; +Cc: adobriyan, netdev, linux-kernel, jgarzik

From: "Vegard Nossum" <vegard.nossum@gmail.com>
Date: Wed, 13 Aug 2008 12:44:46 +0200

> There must also be no BUG()s, WARN()s, other debugging facilities
> (spinlock debugging, lockdep, irqtrace, etc.) triggering which may
> call printk() inside the protected section. Can we really ensure this?
> For all drivers supporting netconsole?

For all drivers supporting netconsole?  Well yes, there will be some
bugs somewhere in some driver wrt. netconsole.  But that's life
and why we will constantly have something to fix in the kernel isn't
it?

But one thing is for sure, your deliriously dirty ->busy thing is
emphatically not the answer.

BTW, it seems the main reason this driver is susceptible to this
problem is that it doesn't handle link status events in it's
NAPI poll handler.  If it did that, you would have never seen
this deadlock.

The netpoll layer prevents recursion into the NAPI ->poll() handler.

Most drivers manage link state either in their NAPI ->poll() handler
or a periodic timer that samples the link state.  Both schemes
avoid this very issue.


^ permalink raw reply	[flat|nested] 14+ messages in thread

* Re: [RFC][PATCH] netconsole: avoid deadlock on printk from driver code
  2008-08-13 10:37 ` David Miller
@ 2008-08-14 13:28   ` Pekka Enberg
  2008-08-14 13:44     ` Pekka J Enberg
  2008-08-14 22:13     ` David Miller
  0 siblings, 2 replies; 14+ messages in thread
From: Pekka Enberg @ 2008-08-14 13:28 UTC (permalink / raw)
  To: David Miller
  Cc: vegard.nossum, vegardno, netdev, linux-kernel, jgarzik, adobriyan

Hi David,

On Wed, Aug 13, 2008 at 1:37 PM, David Miller <davem@davemloft.net> wrote:
> From: Vegard Nossum <vegardno@ifi.uio.no>
> Date: Wed, 13 Aug 2008 11:53:24 +0200
>
>> [PATCH] netconsole: avoid deadlock on printk from driver code
>>
>> I encountered a hard-to-debug deadlock when I pulled out the plug of my
>> RealTek 8139 which was also running netconsole: The driver wants to print
>> a "link down" message. However, this triggers netconsole, which wants to
>> print the message using the same device. Here is a backtrace:
>
> See my other reply, this is absolutely the wrong way to go about
> this.
>
> You only have two sane options:
>
> 1) Defer the link status printk message into a deferred context,
>   such as a workqueue, so that you can do it outside of the
>   lock.

It's not just the link status. We have assert() and debugging printks
there under tp->lock as well which can also trigger the deadlock
condition.

On Wed, Aug 13, 2008 at 1:37 PM, David Miller <davem@davemloft.net> wrote:
> 2) Do your locking differently so that the link status handling
>   locking does not bisect the locking used for packet transmit
>   in ->hard_start_xmit().
>
> #2 is the reason why most other drivers don't have this silly
> bug, they don't hold TX path locks when handling link status
> and printing out such messages.

Yeah, that works for the link status case, but not for things like the
printks in rtl8139_tx_interrupt()... Hmm.

                             Pekka

^ permalink raw reply	[flat|nested] 14+ messages in thread

* Re: [RFC][PATCH] netconsole: avoid deadlock on printk from driver code
  2008-08-14 13:28   ` Pekka Enberg
@ 2008-08-14 13:44     ` Pekka J Enberg
  2008-08-14 22:15       ` David Miller
  2008-08-14 22:13     ` David Miller
  1 sibling, 1 reply; 14+ messages in thread
From: Pekka J Enberg @ 2008-08-14 13:44 UTC (permalink / raw)
  To: David Miller
  Cc: vegard.nossum, vegardno, netdev, linux-kernel, jgarzik, adobriyan

On Thu, 14 Aug 2008, Pekka Enberg wrote:
> > See my other reply, this is absolutely the wrong way to go about
> > this.
> >
> > You only have two sane options:
> >
> > 1) Defer the link status printk message into a deferred context,
> >   such as a workqueue, so that you can do it outside of the
> >   lock.
> 
> It's not just the link status. We have assert() and debugging printks
> there under tp->lock as well which can also trigger the deadlock
> condition.
> 
> On Wed, Aug 13, 2008 at 1:37 PM, David Miller <davem@davemloft.net> wrote:
> > 2) Do your locking differently so that the link status handling
> >   locking does not bisect the locking used for packet transmit
> >   in ->hard_start_xmit().
> >
> > #2 is the reason why most other drivers don't have this silly
> > bug, they don't hold TX path locks when handling link status
> > and printing out such messages.
> 
> Yeah, that works for the link status case, but not for things like the
> printks in rtl8139_tx_interrupt()... Hmm.

...so I guess something like the following (totally untested) patch could 
work.

		Pekka

Subject: [PATCH] 8139too: avoid deadlock with netconsole
From: Pekka Enberg <penberg@cs.helsinki.fi>

As explained by Vegard Nossum, the 8139too driver can deadlock with netconsole:

  I encountered a hard-to-debug deadlock when I pulled out the plug of my
  RealTek 8139 which was also running netconsole: The driver wants to print a
  "link down" message. However, this triggers netconsole, which wants to print
  the message using the same device. Here is a backtrace:

     [<c05916b6>] _spin_lock_irqsave+0x76/0x90
     [<c035b255>] rtl8139_start_xmit+0x65/0x130 <-- spin_lock(&tp->lock)
     [<c04c5e28>] netpoll_send_skb+0x158/0x1a0
     [<c04c62fb>] netpoll_send_udp+0x1db/0x1f0
     [<c037c70c>] write_msg+0x8c/0xc0
     [<c0135883>] __call_console_drivers+0x53/0x60
     [<c01358db>] _call_console_drivers+0x4b/0x90
     [<c0135a25>] release_console_sem+0xc5/0x1f0
     [<c0135f0b>] vprintk+0x1ab/0x3e0
     [<c013615b>] printk+0x1b/0x20
     [<c0349736>] mii_check_media+0x196/0x1e0
     [<c03597f4>] rtl_check_media+0x24/0x30
     [<c035a0ea>] rtl8139_interrupt+0x42a/0x4a0 <-- spin_lock(&tp->lock)
     [<c01716d8>] handle_IRQ_event+0x28/0x70
     [<c0172d9b>] handle_fasteoi_irq+0x6b/0xe0
     [<c0107128>] do_IRQ+0x48/0xa0

To avoid the deadlock, use a separate ->tx_lock for the TX paths and make sure
we never call printk() while holding that lock.

Cc: Alexey Dobriyan <adobriyan@gmail.com>
Cc: David Miller <davem@davemloft.net>
Cc: Jeff Garzik <jgarzik@pobox.com>
Reported-by: Vegard Nossum <vegard.nossum@gmail.com>
Signed-off-by: Pekka Enberg <penberg@cs.helsinki.fi>
---
 drivers/net/8139too.c |   34 +++++++++++++++++++++++++---------
 1 file changed, 25 insertions(+), 9 deletions(-)

Index: linux-2.6/drivers/net/8139too.c
===================================================================
--- linux-2.6.orig/drivers/net/8139too.c	2008-08-14 16:29:32.000000000 +0300
+++ linux-2.6/drivers/net/8139too.c	2008-08-14 16:41:10.000000000 +0300
@@ -598,6 +598,7 @@
 
 	spinlock_t		lock;
 	spinlock_t		rx_lock;
+	spinlock_t		tx_lock;
 
 	chip_t			chipset;
 	u32			rx_config;
@@ -1009,6 +1010,7 @@
 		(debug < 0 ? RTL8139_DEF_MSG_ENABLE : ((1 << debug) - 1));
 	spin_lock_init (&tp->lock);
 	spin_lock_init (&tp->rx_lock);
+	spin_lock_init (&tp->tx_lock);
 	INIT_DELAYED_WORK(&tp->thread, rtl8139_thread);
 	tp->mii.dev = dev;
 	tp->mii.mdio_read = mdio_read;
@@ -1675,9 +1677,9 @@
 	RTL_W16 (IntrMask, 0x0000);
 
 	/* Stop a shared interrupt from scavenging while we are. */
-	spin_lock_irq(&tp->lock);
+	spin_lock_irq(&tp->tx_lock);
 	rtl8139_tx_clear (tp);
-	spin_unlock_irq(&tp->lock);
+	spin_unlock_irq(&tp->tx_lock);
 
 	/* ...and finally, reset everything */
 	if (netif_running(dev)) {
@@ -1721,7 +1723,7 @@
 		return 0;
 	}
 
-	spin_lock_irqsave(&tp->lock, flags);
+	spin_lock_irqsave(&tp->tx_lock, flags);
 	RTL_W32_F (TxStatus0 + (entry * sizeof (u32)),
 		   tp->tx_flag | max(len, (unsigned int)ETH_ZLEN));
 
@@ -1732,7 +1734,7 @@
 
 	if ((tp->cur_tx - NUM_TX_DESC) == tp->dirty_tx)
 		netif_stop_queue (dev);
-	spin_unlock_irqrestore(&tp->lock, flags);
+	spin_unlock_irqrestore(&tp->tx_lock, flags);
 
 	if (netif_msg_tx_queued(tp))
 		printk (KERN_DEBUG "%s: Queued Tx packet size %u to slot %d.\n",
@@ -1746,11 +1748,15 @@
 				  struct rtl8139_private *tp,
 				  void __iomem *ioaddr)
 {
-	unsigned long dirty_tx, tx_left;
+	unsigned long dirty_tx, old_dirty_tx, tx_left;
+	int error;
 
 	assert (dev != NULL);
 	assert (ioaddr != NULL);
 
+	spin_lock(&tp->tx_lock);
+retry:
+	error = 0;
 	dirty_tx = tp->dirty_tx;
 	tx_left = tp->cur_tx - dirty_tx;
 	while (tx_left > 0) {
@@ -1766,8 +1772,7 @@
 		if (txstatus & (TxOutOfWindow | TxAborted)) {
 			/* There was an major error, log it. */
 			if (netif_msg_tx_err(tp))
-				printk(KERN_DEBUG "%s: Transmit error, Tx status %8.8x.\n",
-					dev->name, txstatus);
+				error = 1;
 			dev->stats.tx_errors++;
 			if (txstatus & TxAborted) {
 				dev->stats.tx_aborted_errors++;
@@ -1793,12 +1798,19 @@
 
 		dirty_tx++;
 		tx_left--;
+		if (error) {
+			spin_unlock(&tp->tx_lock);
+			printk(KERN_DEBUG "%s: Transmit error, Tx status %8.8x.\n",
+				dev->name, txstatus);
+			spin_lock(&tp->tx_lock);
+			goto retry;
+		}
 	}
 
 #ifndef RTL8139_NDEBUG
 	if (tp->cur_tx - dirty_tx > NUM_TX_DESC) {
-		printk (KERN_ERR "%s: Out-of-sync dirty pointer, %ld vs. %ld.\n",
-		        dev->name, dirty_tx, tp->cur_tx);
+		error = 1;
+		old_dirty_tx = dirty_tx;
 		dirty_tx += NUM_TX_DESC;
 	}
 #endif /* RTL8139_NDEBUG */
@@ -1809,6 +1821,10 @@
 		mb();
 		netif_wake_queue (dev);
 	}
+	spin_unlock(&tp->tx_lock);
+	if (error)
+		printk (KERN_ERR "%s: Out-of-sync dirty pointer, %ld vs. %ld.\n",
+		        dev->name, old_dirty_tx, tp->cur_tx);
 }
 
 

^ permalink raw reply	[flat|nested] 14+ messages in thread

* Re: [RFC][PATCH] netconsole: avoid deadlock on printk from driver code
  2008-08-14 13:28   ` Pekka Enberg
  2008-08-14 13:44     ` Pekka J Enberg
@ 2008-08-14 22:13     ` David Miller
  1 sibling, 0 replies; 14+ messages in thread
From: David Miller @ 2008-08-14 22:13 UTC (permalink / raw)
  To: penberg; +Cc: vegard.nossum, vegardno, netdev, linux-kernel, jgarzik, adobriyan

From: "Pekka Enberg" <penberg@cs.helsinki.fi>
Date: Thu, 14 Aug 2008 16:28:37 +0300

> On Wed, Aug 13, 2008 at 1:37 PM, David Miller <davem@davemloft.net> wrote:
> > 2) Do your locking differently so that the link status handling
> >   locking does not bisect the locking used for packet transmit
> >   in ->hard_start_xmit().
> >
> > #2 is the reason why most other drivers don't have this silly
> > bug, they don't hold TX path locks when handling link status
> > and printing out such messages.
> 
> Yeah, that works for the link status case, but not for things like the
> printks in rtl8139_tx_interrupt()... Hmm.

Note that netconsole specifically does trylock on the netdev
xmit lock specifically to handle this case.

If you could command the TX path solely under this generic lock
already provided by the generic networking, you could avoid this
deadlock as well.

This is yet another reason many other drivers don't get hit by
this problem.  The solution is built into netpoll but it only
works if you use the provided generic locking mechanisms to
mutex the driver's TX path.

^ permalink raw reply	[flat|nested] 14+ messages in thread

* Re: [RFC][PATCH] netconsole: avoid deadlock on printk from driver code
  2008-08-14 13:44     ` Pekka J Enberg
@ 2008-08-14 22:15       ` David Miller
  2008-08-20 17:54         ` Pekka J Enberg
  0 siblings, 1 reply; 14+ messages in thread
From: David Miller @ 2008-08-14 22:15 UTC (permalink / raw)
  To: penberg; +Cc: vegard.nossum, vegardno, netdev, linux-kernel, jgarzik, adobriyan

From: Pekka J Enberg <penberg@cs.helsinki.fi>
Date: Thu, 14 Aug 2008 16:44:32 +0300 (EEST)

> @@ -598,6 +598,7 @@
>  
>  	spinlock_t		lock;
>  	spinlock_t		rx_lock;
> +	spinlock_t		tx_lock;
>  
>  	chip_t			chipset;
>  	u32			rx_config;

Why create a special purpose lock when the generic networking
already is taking a lock for you to proect the TX path?

Furthermore, as I just described in another reply, netpoll
already knows that it might need to trylock() attempt on this
lock in order to avoid the very deadlocks this thread is
about.

^ permalink raw reply	[flat|nested] 14+ messages in thread

* Re: [RFC][PATCH] netconsole: avoid deadlock on printk from driver code
  2008-08-14 22:15       ` David Miller
@ 2008-08-20 17:54         ` Pekka J Enberg
  2008-08-20 19:56           ` Vegard Nossum
  2008-08-20 20:58           ` David Miller
  0 siblings, 2 replies; 14+ messages in thread
From: Pekka J Enberg @ 2008-08-20 17:54 UTC (permalink / raw)
  To: David Miller
  Cc: vegard.nossum, vegardno, netdev, linux-kernel, jgarzik, adobriyan

On Thu, 14 Aug 2008, David Miller wrote:
> From: Pekka J Enberg <penberg@cs.helsinki.fi>
> Date: Thu, 14 Aug 2008 16:44:32 +0300 (EEST)
> 
> > @@ -598,6 +598,7 @@
> >  
> >  	spinlock_t		lock;
> >  	spinlock_t		rx_lock;
> > +	spinlock_t		tx_lock;
> >  
> >  	chip_t			chipset;
> >  	u32			rx_config;
> 
> Why create a special purpose lock when the generic networking
> already is taking a lock for you to proect the TX path?

Heh, no reason, just my ignorance of the networking layer... Does this 
look more like it?

		Pekka

Subject: [PATCH] 8139too: avoid deadlock with netconsole
From: Pekka Enberg <penberg@cs.helsinki.fi>

As explained by Vegard Nossum, the 8139too driver can deadlock with netconsole:

  I encountered a hard-to-debug deadlock when I pulled out the plug of my
  RealTek 8139 which was also running netconsole: The driver wants to print a
  "link down" message. However, this triggers netconsole, which wants to print
  the message using the same device. Here is a backtrace:

     [<c05916b6>] _spin_lock_irqsave+0x76/0x90
     [<c035b255>] rtl8139_start_xmit+0x65/0x130 <-- spin_lock(&tp->lock)
     [<c04c5e28>] netpoll_send_skb+0x158/0x1a0
     [<c04c62fb>] netpoll_send_udp+0x1db/0x1f0
     [<c037c70c>] write_msg+0x8c/0xc0
     [<c0135883>] __call_console_drivers+0x53/0x60
     [<c01358db>] _call_console_drivers+0x4b/0x90
     [<c0135a25>] release_console_sem+0xc5/0x1f0
     [<c0135f0b>] vprintk+0x1ab/0x3e0
     [<c013615b>] printk+0x1b/0x20
     [<c0349736>] mii_check_media+0x196/0x1e0
     [<c03597f4>] rtl_check_media+0x24/0x30
     [<c035a0ea>] rtl8139_interrupt+0x42a/0x4a0 <-- spin_lock(&tp->lock)
     [<c01716d8>] handle_IRQ_event+0x28/0x70
     [<c0172d9b>] handle_fasteoi_irq+0x6b/0xe0
     [<c0107128>] do_IRQ+0x48/0xa0

To avoid the deadlock, use netif_tx_lock() for the TX paths and make sure we
never call printk() while holding that lock as suggested by David Miller.

Cc: Alexey Dobriyan <adobriyan@gmail.com>
Cc: David Miller <davem@davemloft.net>
Cc: Jeff Garzik <jgarzik@pobox.com>
Reported-by: Vegard Nossum <vegard.nossum@gmail.com>
Signed-off-by: Pekka Enberg <penberg@cs.helsinki.fi>
---
 drivers/net/8139too.c |   35 +++++++++++++++++++++++++++--------
 1 file changed, 27 insertions(+), 8 deletions(-)

Index: linux-2.6/drivers/net/8139too.c
===================================================================
--- linux-2.6.orig/drivers/net/8139too.c
+++ linux-2.6/drivers/net/8139too.c
@@ -1675,9 +1675,11 @@ static void rtl8139_tx_timeout_task (str
 	RTL_W16 (IntrMask, 0x0000);
 
 	/* Stop a shared interrupt from scavenging while we are. */
-	spin_lock_irq(&tp->lock);
+	local_irq_disable();
+	netif_tx_lock(dev);
 	rtl8139_tx_clear (tp);
-	spin_unlock_irq(&tp->lock);
+	netif_tx_unlock(dev);
+	local_irq_enable();
 
 	/* ...and finally, reset everything */
 	if (netif_running(dev)) {
@@ -1721,7 +1723,8 @@ static int rtl8139_start_xmit (struct sk
 		return 0;
 	}
 
-	spin_lock_irqsave(&tp->lock, flags);
+	local_irq_save(flags);
+	netif_tx_lock(dev);
 	RTL_W32_F (TxStatus0 + (entry * sizeof (u32)),
 		   tp->tx_flag | max(len, (unsigned int)ETH_ZLEN));
 
@@ -1732,7 +1735,8 @@ static int rtl8139_start_xmit (struct sk
 
 	if ((tp->cur_tx - NUM_TX_DESC) == tp->dirty_tx)
 		netif_stop_queue (dev);
-	spin_unlock_irqrestore(&tp->lock, flags);
+	netif_tx_unlock(dev);
+	local_irq_restore(flags);
 
 	if (netif_msg_tx_queued(tp))
 		printk (KERN_DEBUG "%s: Queued Tx packet size %u to slot %d.\n",
@@ -1747,10 +1751,15 @@ static void rtl8139_tx_interrupt (struct
 				  void __iomem *ioaddr)
 {
 	unsigned long dirty_tx, tx_left;
+	unsigned long old_dirty_tx = 0;
+	int error;
 
 	assert (dev != NULL);
 	assert (ioaddr != NULL);
 
+	netif_tx_lock(dev);
+retry:
+	error = 0;
 	dirty_tx = tp->dirty_tx;
 	tx_left = tp->cur_tx - dirty_tx;
 	while (tx_left > 0) {
@@ -1766,8 +1775,7 @@ static void rtl8139_tx_interrupt (struct
 		if (txstatus & (TxOutOfWindow | TxAborted)) {
 			/* There was an major error, log it. */
 			if (netif_msg_tx_err(tp))
-				printk(KERN_DEBUG "%s: Transmit error, Tx status %8.8x.\n",
-					dev->name, txstatus);
+				error = 1;
 			dev->stats.tx_errors++;
 			if (txstatus & TxAborted) {
 				dev->stats.tx_aborted_errors++;
@@ -1793,12 +1801,19 @@ static void rtl8139_tx_interrupt (struct
 
 		dirty_tx++;
 		tx_left--;
+		if (error) {
+			netif_tx_unlock(dev);
+			printk(KERN_DEBUG "%s: Transmit error, Tx status %8.8x.\n",
+				dev->name, txstatus);
+			netif_tx_lock(dev);
+			goto retry;
+		}
 	}
 
 #ifndef RTL8139_NDEBUG
 	if (tp->cur_tx - dirty_tx > NUM_TX_DESC) {
-		printk (KERN_ERR "%s: Out-of-sync dirty pointer, %ld vs. %ld.\n",
-		        dev->name, dirty_tx, tp->cur_tx);
+		error = 1;
+		old_dirty_tx = dirty_tx;
 		dirty_tx += NUM_TX_DESC;
 	}
 #endif /* RTL8139_NDEBUG */
@@ -1809,6 +1824,10 @@ static void rtl8139_tx_interrupt (struct
 		mb();
 		netif_wake_queue (dev);
 	}
+	netif_tx_unlock(dev);
+	if (error)
+		printk (KERN_ERR "%s: Out-of-sync dirty pointer, %ld vs. %ld.\n",
+		        dev->name, old_dirty_tx, tp->cur_tx);
 }
 
 

^ permalink raw reply	[flat|nested] 14+ messages in thread

* Re: [RFC][PATCH] netconsole: avoid deadlock on printk from driver code
  2008-08-20 17:54         ` Pekka J Enberg
@ 2008-08-20 19:56           ` Vegard Nossum
  2008-08-20 20:58           ` David Miller
  1 sibling, 0 replies; 14+ messages in thread
From: Vegard Nossum @ 2008-08-20 19:56 UTC (permalink / raw)
  To: Pekka J Enberg
  Cc: David Miller, vegardno, netdev, linux-kernel, jgarzik, adobriyan

On Wed, Aug 20, 2008 at 7:54 PM, Pekka J Enberg <penberg@cs.helsinki.fi> wrote:
> Subject: [PATCH] 8139too: avoid deadlock with netconsole
> From: Pekka Enberg <penberg@cs.helsinki.fi>
>
> As explained by Vegard Nossum, the 8139too driver can deadlock with netconsole:
>
>  I encountered a hard-to-debug deadlock when I pulled out the plug of my
>  RealTek 8139 which was also running netconsole: The driver wants to print a
>  "link down" message. However, this triggers netconsole, which wants to print
>  the message using the same device. Here is a backtrace:
>
>     [<c05916b6>] _spin_lock_irqsave+0x76/0x90
>     [<c035b255>] rtl8139_start_xmit+0x65/0x130 <-- spin_lock(&tp->lock)
>     [<c04c5e28>] netpoll_send_skb+0x158/0x1a0
>     [<c04c62fb>] netpoll_send_udp+0x1db/0x1f0
>     [<c037c70c>] write_msg+0x8c/0xc0
>     [<c0135883>] __call_console_drivers+0x53/0x60
>     [<c01358db>] _call_console_drivers+0x4b/0x90
>     [<c0135a25>] release_console_sem+0xc5/0x1f0
>     [<c0135f0b>] vprintk+0x1ab/0x3e0
>     [<c013615b>] printk+0x1b/0x20
>     [<c0349736>] mii_check_media+0x196/0x1e0
>     [<c03597f4>] rtl_check_media+0x24/0x30
>     [<c035a0ea>] rtl8139_interrupt+0x42a/0x4a0 <-- spin_lock(&tp->lock)
>     [<c01716d8>] handle_IRQ_event+0x28/0x70
>     [<c0172d9b>] handle_fasteoi_irq+0x6b/0xe0
>     [<c0107128>] do_IRQ+0x48/0xa0
>
> To avoid the deadlock, use netif_tx_lock() for the TX paths and make sure we
> never call printk() while holding that lock as suggested by David Miller.
>
> Cc: Alexey Dobriyan <adobriyan@gmail.com>
> Cc: David Miller <davem@davemloft.net>
> Cc: Jeff Garzik <jgarzik@pobox.com>
> Reported-by: Vegard Nossum <vegard.nossum@gmail.com>
> Signed-off-by: Pekka Enberg <penberg@cs.helsinki.fi>
> ---

I'm sorry, but it doesn't help :-)

console [netcon0] enabled
=============================================
[ INFO: possible recursive locking detected ]
2.6.27-rc3-00468-g86f91c5 #19
---------------------------------------------
swapper/1 is trying to acquire lock:
 (_xmit_ETHER#2){....}, at: [<c0449210>] rtl8139_start_xmit+0xc0/0x230
but task is already holding lock:
 (_xmit_ETHER#2){....}, at: [<c05b515b>] netpoll_send_skb+0x13b/0x1a0
other info that might help us debug this:
3 locks held by swapper/1:
 #0:  (target_list_lock){....}, at: [<c046ab5d>] write_msg+0x2d/0xc0
 #1:  (_xmit_ETHER#2){....}, at: [<c05b515b>] netpoll_send_skb+0x13b/0x1a0
 #2:  (&dev->tx_global_lock){....}, at: [<c04491e1>] rtl8139_start_xmit+0x91/0x2
30
stack backtrace:
Pid: 1, comm: swapper Not tainted 2.6.27-rc3-00468-g86f91c5 #19
 [<c015fccb>] validate_chain+0xbbb/0xe90
 [<c010e45b>] ? save_stack_trace+0x2b/0x50
 [<c01601f9>] __lock_acquire+0x259/0xa00
 [<c0160a29>] lock_acquire+0x89/0xc0
 [<c0449210>] ? rtl8139_start_xmit+0xc0/0x230
 [<c0681720>] _spin_lock+0x40/0x70
 [<c0449210>] ? rtl8139_start_xmit+0xc0/0x230
 [<c0449210>] rtl8139_start_xmit+0xc0/0x230
 [<c05b515b>] ? netpoll_send_skb+0x13b/0x1a0
 [<c05b5178>] netpoll_send_skb+0x158/0x1a0
 [<c05b564b>] netpoll_send_udp+0x1db/0x1f0
 [<c046abbc>] write_msg+0x8c/0xc0
 [<c013ad13>] __call_console_drivers+0x53/0x60
 [<c013ad6b>] _call_console_drivers+0x4b/0x90
 [<c013aeb5>] release_console_sem+0xc5/0x1f0
 [<c013b698>] register_console+0x138/0x2c0
 [<c08bb860>] init_netconsole+0x1a0/0x1c0
 [<c01520b9>] ? ktime_get+0x19/0x40
 [<c0101120>] do_one_initcall+0x30/0x170
 [<c08bb6c0>] ? init_netconsole+0x0/0x1c0
 [<c017b583>] ? register_irq_proc+0xb3/0xd0
 [<c08916aa>] kernel_init+0x11a/0x180
 [<c0891590>] ? kernel_init+0x0/0x180
 [<c0105cf3>] kernel_thread_helper+0x7/0x14
 =======================

After that, I also got lots of kgdbts errors, don't know exactly how
it relates to your patch...

<3>kgdbts: BP mismatch c03763a0 expected c0139b80
<4>------------[ cut here ]------------
<4>WARNING: at /uio/arkimedes/s29/vegardno/git-working/linux-2.6/drivers/misc/kg
dbts.c:302 check_and_rewind_pc+0xb2/0xe0()
Pid: 1, comm: swapper Not tainted 2.6.27-rc3-00468-g86f91c5 #19
 [<c013a9cf>] warn_on_slowpath+0x4f/0x80
 [<c01670a2>] ? sprint_symbol+0x92/0xc0
 [<c013b25d>] ? vprintk+0x6d/0x350
 [<c013b25d>] ? vprintk+0x6d/0x350
 [<c01248e3>] ? __change_page_attr_set_clr+0x693/0xc30
 [<c0376917>] ? __copy_to_user_ll+0x57/0x60
 [<c0184e1a>] ? probe_kernel_write+0x4a/0x90
 [<c0139b80>] ? do_fork+0x0/0x2b0
 [<c013b55b>] ? printk+0x1b/0x20
 [<c0139b80>] ? do_fork+0x0/0x2b0
 [<c03fee62>] check_and_rewind_pc+0xb2/0xe0
 [<c03763a0>] ? delay_tsc+0x20/0xb8
 [<c0139b80>] ? do_fork+0x0/0x2b0
 [<c03fdc52>] validate_simple_test+0x22/0xa0
 [<c03fe407>] run_simple_test+0x107/0x260
 [<c0184eaa>] ? probe_kernel_read+0x4a/0x90
 [<c03fdd34>] kgdbts_put_char+0x14/0x20
 [<c0177476>] put_packet+0x86/0xe0
 [<c0178376>] kgdb_handle_exception+0x446/0xe40
 [<c013b25d>] ? vprintk+0x6d/0x350
 [<c011dd61>] kgdb_notify+0xa1/0x1d0
 [<c0153037>] notifier_call_chain+0x37/0x70
 [<c0153435>] __atomic_notifier_call_chain+0x35/0x50
 [<c015346a>] atomic_notifier_call_chain+0x1a/0x20
 [<c015349d>] notify_die+0x2d/0x30
 [<c0106d5a>] die_nmi+0x3a/0x100
 [<c011add5>] nmi_watchdog_tick+0x1d5/0x1e0
 [<c0107227>] do_nmi+0x97/0x2d0
 [<c06823f3>] nmi_stack_correct+0x26/0x2b
 [<c03763a0>] ? delay_tsc+0x20/0xb8
 [<c03762c9>] __delay+0x9/0x10
 [<c03857ec>] _raw_spin_lock+0xbc/0x150
 [<c015b73e>] ? get_lock_stats+0x1e/0x50
 [<c015b77d>] ? put_lock_stats+0xd/0x30
 [<c068173c>] _spin_lock+0x5c/0x70
 [<c0449210>] ? rtl8139_start_xmit+0xc0/0x230
 [<c0449210>] rtl8139_start_xmit+0xc0/0x230
 [<c05b515b>] ? netpoll_send_skb+0x13b/0x1a0
 [<c05b5178>] netpoll_send_skb+0x158/0x1a0
 [<c05b564b>] netpoll_send_udp+0x1db/0x1f0
 [<c046abbc>] write_msg+0x8c/0xc0
 [<c013ad13>] __call_console_drivers+0x53/0x60
 [<c013ad6b>] _call_console_drivers+0x4b/0x90
 [<c013aeb5>] release_console_sem+0xc5/0x1f0
 [<c013b698>] register_console+0x138/0x2c0
 [<c08bb860>] init_netconsole+0x1a0/0x1c0
 [<c01520b9>] ? ktime_get+0x19/0x40
 [<c0101120>] do_one_initcall+0x30/0x170
 [<c08bb6c0>] ? init_netconsole+0x0/0x1c0
 [<c017b583>] ? register_irq_proc+0xb3/0xd0
 [<c08916aa>] kernel_init+0x11a/0x180
 [<c0891590>] ? kernel_init+0x0/0x180
 [<c0105cf3>] kernel_thread_helper+0x7/0x14
 =======================
<4>---[ end trace 3a158aadebbe6259 ]---

(This repeats every few seconds.)

When pulling the cable, I get this:

<0>BUG: spinlock lockup on CPU#1, swapper/1, f58599ac
Pid: 1, comm: swapper Tainted: G        W 2.6.27-rc3-00468-g86f91c5 #19
 [<c0385840>] _raw_spin_lock+0x110/0x150
 [<c068173c>] _spin_lock+0x5c/0x70
 [<c0449210>] ? rtl8139_start_xmit+0xc0/0x230
 [<c0449210>] rtl8139_start_xmit+0xc0/0x230
 [<c05b515b>] ? netpoll_send_skb+0x13b/0x1a0
 [<c05b5178>] netpoll_send_skb+0x158/0x1a0
 [<c05b564b>] netpoll_send_udp+0x1db/0x1f0
 [<c046abbc>] write_msg+0x8c/0xc0
 [<c013ad13>] __call_console_drivers+0x53/0x60
 [<c013ad6b>] _call_console_drivers+0x4b/0x90
 [<c013aeb5>] release_console_sem+0xc5/0x1f0
 [<c013b698>] register_console+0x138/0x2c0
 [<c08bb860>] init_netconsole+0x1a0/0x1c0
 [<c01520b9>] ? ktime_get+0x19/0x40
 [<c0101120>] do_one_initcall+0x30/0x170
 [<c08bb6c0>] ? init_netconsole+0x0/0x1c0
 [<c017b583>] ? register_irq_proc+0xb3/0xd0
 [<c08916aa>] kernel_init+0x11a/0x180
 [<c0891590>] ? kernel_init+0x0/0x180
 [<c0105cf3>] kernel_thread_helper+0x7/0x14
 =======================

...and machine is unusable. Thanks for trying! :-D


Vegard

-- 
"The animistic metaphor of the bug that maliciously sneaked in while
the programmer was not looking is intellectually dishonest as it
disguises that the error is the programmer's own creation."
	-- E. W. Dijkstra, EWD1036

^ permalink raw reply	[flat|nested] 14+ messages in thread

* Re: [RFC][PATCH] netconsole: avoid deadlock on printk from driver code
  2008-08-20 17:54         ` Pekka J Enberg
  2008-08-20 19:56           ` Vegard Nossum
@ 2008-08-20 20:58           ` David Miller
  1 sibling, 0 replies; 14+ messages in thread
From: David Miller @ 2008-08-20 20:58 UTC (permalink / raw)
  To: penberg; +Cc: vegard.nossum, vegardno, netdev, linux-kernel, jgarzik, adobriyan

From: Pekka J Enberg <penberg@cs.helsinki.fi>
Date: Wed, 20 Aug 2008 20:54:01 +0300 (EEST)

> @@ -1721,7 +1723,8 @@ static int rtl8139_start_xmit (struct sk
>  		return 0;
>  	}
>  
> -	spin_lock_irqsave(&tp->lock, flags);
> +	local_irq_save(flags);
> +	netif_tx_lock(dev);
>  	RTL_W32_F (TxStatus0 + (entry * sizeof (u32)),
>  		   tp->tx_flag | max(len, (unsigned int)ETH_ZLEN));

The generic networking takes the TX lock for you, you don't
need to take it explicitly here.

You also cannot depend upon IRQ disabled locking, the generic
TX lock is only softirq safe, not hard IRQ safe.

This means you have to move TX descriptor reclaim into a
soft IRQ context, such as NAPI ->poll().

^ permalink raw reply	[flat|nested] 14+ messages in thread

end of thread, other threads:[~2008-08-20 20:58 UTC | newest]

Thread overview: 14+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2008-08-13  9:53 [RFC][PATCH] netconsole: avoid deadlock on printk from driver code Vegard Nossum
2008-08-13  9:59 ` Alexey Dobriyan
2008-08-13 10:21   ` Vegard Nossum
2008-08-13 10:29   ` David Miller
2008-08-13 10:44     ` Vegard Nossum
2008-08-13 10:56       ` David Miller
2008-08-13 10:37 ` David Miller
2008-08-14 13:28   ` Pekka Enberg
2008-08-14 13:44     ` Pekka J Enberg
2008-08-14 22:15       ` David Miller
2008-08-20 17:54         ` Pekka J Enberg
2008-08-20 19:56           ` Vegard Nossum
2008-08-20 20:58           ` David Miller
2008-08-14 22:13     ` David Miller

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox

all inboxes | Powered by JetHome®