Skip to content

Commit

Permalink
[NETPOLL]: allow multiple netpoll_clients to register against one int…
Browse files Browse the repository at this point in the history
…erface

This patch provides support for registering multiple netpoll clients to the
same network device.  Only one of these clients may register an rx_hook,
however.  In practice, this restriction has not been problematic.  It is
worth mentioning, though, that the current design can be easily extended to
allow for the registration of multiple rx_hooks.

The basic idea of the patch is that the rx_np pointer in the netpoll_info
structure points to the struct netpoll that has rx_hook filled in.  Aside
from this one case, there is no need for a pointer from the struct
net_device to an individual struct netpoll.

A lock is introduced to protect the setting and clearing of the np_rx
pointer.  The pointer will only be cleared upon netpoll client module
removal, and the lock should be uncontested.

Signed-off-by: Jeff Moyer <jmoyer@redhat.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
  • Loading branch information
Jeff Moyer authored and David S. Miller committed Jun 23, 2005
1 parent 115c1d6 commit fbeec2e
Show file tree
Hide file tree
Showing 2 changed files with 41 additions and 13 deletions.
15 changes: 12 additions & 3 deletions include/linux/netpoll.h
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,8 @@ struct netpoll_info {
spinlock_t poll_lock;
int poll_owner;
int rx_flags;
struct netpoll *np;
spinlock_t rx_lock;
struct netpoll *rx_np; /* netpoll that registered an rx_hook */
};

void netpoll_poll(struct netpoll *np);
Expand All @@ -44,11 +45,19 @@ void netpoll_queue(struct sk_buff *skb);
static inline int netpoll_rx(struct sk_buff *skb)
{
struct netpoll_info *npinfo = skb->dev->npinfo;
unsigned long flags;
int ret = 0;

if (!npinfo || !npinfo->rx_flags)
if (!npinfo || (!npinfo->rx_np && !npinfo->rx_flags))
return 0;

return npinfo->np && __netpoll_rx(skb);
spin_lock_irqsave(&npinfo->rx_lock, flags);
/* check rx_flags again with the lock held */
if (npinfo->rx_flags && __netpoll_rx(skb))
ret = 1;
spin_unlock_irqrestore(&npinfo->rx_lock, flags);

return ret;
}

static inline void netpoll_poll_lock(struct net_device *dev)
Expand Down
39 changes: 29 additions & 10 deletions net/core/netpoll.c
Original file line number Diff line number Diff line change
Expand Up @@ -349,11 +349,15 @@ static void arp_reply(struct sk_buff *skb)
unsigned char *arp_ptr;
int size, type = ARPOP_REPLY, ptype = ETH_P_ARP;
u32 sip, tip;
unsigned long flags;
struct sk_buff *send_skb;
struct netpoll *np = NULL;

if (npinfo)
np = npinfo->np;
spin_lock_irqsave(&npinfo->rx_lock, flags);
if (npinfo->rx_np && npinfo->rx_np->dev == skb->dev)
np = npinfo->rx_np;
spin_unlock_irqrestore(&npinfo->rx_lock, flags);

if (!np)
return;

Expand Down Expand Up @@ -436,9 +440,9 @@ int __netpoll_rx(struct sk_buff *skb)
int proto, len, ulen;
struct iphdr *iph;
struct udphdr *uh;
struct netpoll *np = skb->dev->npinfo->np;
struct netpoll *np = skb->dev->npinfo->rx_np;

if (!np->rx_hook)
if (!np)
goto out;
if (skb->dev->type != ARPHRD_ETHER)
goto out;
Expand Down Expand Up @@ -619,6 +623,7 @@ int netpoll_setup(struct netpoll *np)
struct net_device *ndev = NULL;
struct in_device *in_dev;
struct netpoll_info *npinfo;
unsigned long flags;

if (np->dev_name)
ndev = dev_get_by_name(np->dev_name);
Expand All @@ -634,9 +639,10 @@ int netpoll_setup(struct netpoll *np)
if (!npinfo)
goto release;

npinfo->np = NULL;
npinfo->rx_np = NULL;
npinfo->poll_lock = SPIN_LOCK_UNLOCKED;
npinfo->poll_owner = -1;
npinfo->rx_lock = SPIN_LOCK_UNLOCKED;
} else
npinfo = ndev->npinfo;

Expand Down Expand Up @@ -706,9 +712,13 @@ int netpoll_setup(struct netpoll *np)
np->name, HIPQUAD(np->local_ip));
}

if(np->rx_hook)
npinfo->rx_flags = NETPOLL_RX_ENABLED;
npinfo->np = np;
if (np->rx_hook) {
spin_lock_irqsave(&npinfo->rx_lock, flags);
npinfo->rx_flags |= NETPOLL_RX_ENABLED;
npinfo->rx_np = np;
spin_unlock_irqrestore(&npinfo->rx_lock, flags);
}
/* last thing to do is link it to the net device structure */
ndev->npinfo = npinfo;

return 0;
Expand All @@ -723,11 +733,20 @@ int netpoll_setup(struct netpoll *np)

void netpoll_cleanup(struct netpoll *np)
{
struct netpoll_info *npinfo;
unsigned long flags;

if (np->dev) {
if (np->dev->npinfo)
np->dev->npinfo->np = NULL;
npinfo = np->dev->npinfo;
if (npinfo && npinfo->rx_np == np) {
spin_lock_irqsave(&npinfo->rx_lock, flags);
npinfo->rx_np = NULL;
npinfo->rx_flags &= ~NETPOLL_RX_ENABLED;
spin_unlock_irqrestore(&npinfo->rx_lock, flags);
}
dev_put(np->dev);
}

np->dev = NULL;
}

Expand Down

0 comments on commit fbeec2e

Please sign in to comment.