On Mon, Jun 12, 2006 at 10:51:21AM -0500, Matt Mackall wrote:
> On Mon, Jun 12, 2006 at 11:40:29AM -0400, Neil Horman wrote:
> > Hey there-
> > the netpoll system currently has a rx to tx path via:
> > netpoll_rx
> > __netpoll_rx
> > arp_reply
> > netpoll_send_skb
> > dev->hard_start_tx
> >
> > This rx->tx loop places network drivers at risk of
> > inadvertently causing a deadlock or BUG halt by recursively trying
> > to acquire a spinlock that is used in both their rx and tx paths
> > (this problem was origionally reported to me in the 3c59x driver,
> > which shares a spinlock between the boomerang_interrupt and
> > boomerang_start_xmit routines).
>
> Grumble.
>
> > This patch breaks this loop, by queueing arp frames, so that they
> > can be responded to after all receive operations have been
> > completed. Tested by myself and the reported with successful
> > results.
>
> Tested how? kgdb?
>
Specifically It was tested with netdump. Heres the BZ with details:
https://bugzilla.redhat.com/bugzilla/show_bug.cgi?id=194055
> > + if (likely(npi))
> > + while ((skb = skb_dequeue(&npi->arp_tx)) != NULL)
> > + arp_reply(skb);
> > +
>
> Assignment inside tests is frowned upon. I'd prefer pulling this out
> to its own function too.
>
Sure, no problem. New patch attached with suggested modifications made
Regards
Neil
Signed-off-by: Neil Horman <[EMAIL PROTECTED]>
include/linux/netpoll.h | 1 +
net/core/netpoll.c | 27 +++++++++++++++++++++++++--
2 files changed, 26 insertions(+), 2 deletions(-)
--- linux-2.6/include/linux/netpoll.h.orig 2006-06-12 09:11:01.000000000
-0400
+++ linux-2.6/include/linux/netpoll.h 2006-06-12 09:34:17.000000000 -0400
@@ -31,6 +31,7 @@ struct netpoll_info {
int rx_flags;
spinlock_t rx_lock;
struct netpoll *rx_np; /* netpoll that registered an rx_hook */
+ struct sk_buff_head arp_tx; /* list of arp requests to reply to */
};
void netpoll_poll(struct netpoll *np);
--- linux-2.6/net/core/netpoll.c.orig 2006-06-12 09:11:01.000000000 -0400
+++ linux-2.6/net/core/netpoll.c 2006-06-12 13:43:25.000000000 -0400
@@ -54,6 +54,7 @@ static atomic_t trapped;
sizeof(struct iphdr) + sizeof(struct ethhdr))
static void zap_completion_queue(void);
+static void arp_reply(struct sk_buff *skb);
static void queue_process(void *p)
{
@@ -153,8 +154,25 @@ static void poll_napi(struct netpoll *np
}
}
+static void service_arp_queue(struct netpoll_info *npi)
+{
+ struct sk_buff *skb;
+
+ if(unlikely(!npi))
+ return;
+
+ skb = skb_dequeue(&npi->arp_tx);
+
+ while (skb != NULL) {
+ arp_reply(skb);
+ skb = skb_dequeue(&npi->arp_tx);
+ }
+ return;
+}
+
void netpoll_poll(struct netpoll *np)
{
+
if(!np->dev || !netif_running(np->dev) || !np->dev->poll_controller)
return;
@@ -163,6 +181,8 @@ void netpoll_poll(struct netpoll *np)
if (np->dev->poll)
poll_napi(np);
+ service_arp_queue(np->dev->npinfo);
+
zap_completion_queue();
}
@@ -449,7 +469,9 @@ int __netpoll_rx(struct sk_buff *skb)
int proto, len, ulen;
struct iphdr *iph;
struct udphdr *uh;
- struct netpoll *np = skb->dev->npinfo->rx_np;
+ struct netpoll_info *npi = skb->dev->npinfo;
+ struct netpoll *np = npi->rx_np;
+
if (!np)
goto out;
@@ -459,7 +481,7 @@ int __netpoll_rx(struct sk_buff *skb)
/* check if netpoll clients need ARP */
if (skb->protocol == __constant_htons(ETH_P_ARP) &&
atomic_read(&trapped)) {
- arp_reply(skb);
+ skb_queue_tail(&npi->arp_tx, skb);
return 1;
}
@@ -654,6 +676,7 @@ int netpoll_setup(struct netpoll *np)
npinfo->poll_owner = -1;
npinfo->tries = MAX_RETRIES;
spin_lock_init(&npinfo->rx_lock);
+ skb_queue_head_init(&npinfo->arp_tx);
} else
npinfo = ndev->npinfo;
--
/***************************************************
*Neil Horman
*Software Engineer
*gpg keyid: 1024D / 0x92A74FA1 - http://pgp.mit.edu
***************************************************/
-
To unsubscribe from this list: send the line "unsubscribe netdev" in
the body of a message to [EMAIL PROTECTED]
More majordomo info at http://vger.kernel.org/majordomo-info.html