diff options
| author | Jeff Moyer <jmoyer@redhat.com> | 2005-06-23 01:05:59 -0400 |
|---|---|---|
| committer | David S. Miller <davem@davemloft.net> | 2005-06-23 01:05:59 -0400 |
| commit | fbeec2e1552949002065435c9829dc244ad85407 (patch) | |
| tree | d97dc663bbef4bf59a1858b23a327f14043c33d1 | |
| parent | 115c1d6e61b70851d9a363328c3b8d4c2559a1d3 (diff) | |
[NETPOLL]: allow multiple netpoll_clients to register against one interface
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>
| -rw-r--r-- | include/linux/netpoll.h | 15 | ||||
| -rw-r--r-- | net/core/netpoll.c | 39 |
2 files changed, 41 insertions, 13 deletions
diff --git a/include/linux/netpoll.h b/include/linux/netpoll.h index 388cd91bc7a6..bcd0ac33f592 100644 --- a/include/linux/netpoll.h +++ b/include/linux/netpoll.h | |||
| @@ -27,7 +27,8 @@ struct netpoll_info { | |||
| 27 | spinlock_t poll_lock; | 27 | spinlock_t poll_lock; |
| 28 | int poll_owner; | 28 | int poll_owner; |
| 29 | int rx_flags; | 29 | int rx_flags; |
| 30 | struct netpoll *np; | 30 | spinlock_t rx_lock; |
| 31 | struct netpoll *rx_np; /* netpoll that registered an rx_hook */ | ||
| 31 | }; | 32 | }; |
| 32 | 33 | ||
| 33 | void netpoll_poll(struct netpoll *np); | 34 | void netpoll_poll(struct netpoll *np); |
| @@ -44,11 +45,19 @@ void netpoll_queue(struct sk_buff *skb); | |||
| 44 | static inline int netpoll_rx(struct sk_buff *skb) | 45 | static inline int netpoll_rx(struct sk_buff *skb) |
| 45 | { | 46 | { |
| 46 | struct netpoll_info *npinfo = skb->dev->npinfo; | 47 | struct netpoll_info *npinfo = skb->dev->npinfo; |
| 48 | unsigned long flags; | ||
| 49 | int ret = 0; | ||
| 47 | 50 | ||
| 48 | if (!npinfo || !npinfo->rx_flags) | 51 | if (!npinfo || (!npinfo->rx_np && !npinfo->rx_flags)) |
| 49 | return 0; | 52 | return 0; |
| 50 | 53 | ||
| 51 | return npinfo->np && __netpoll_rx(skb); | 54 | spin_lock_irqsave(&npinfo->rx_lock, flags); |
| 55 | /* check rx_flags again with the lock held */ | ||
| 56 | if (npinfo->rx_flags && __netpoll_rx(skb)) | ||
| 57 | ret = 1; | ||
| 58 | spin_unlock_irqrestore(&npinfo->rx_lock, flags); | ||
| 59 | |||
| 60 | return ret; | ||
| 52 | } | 61 | } |
| 53 | 62 | ||
| 54 | static inline void netpoll_poll_lock(struct net_device *dev) | 63 | static inline void netpoll_poll_lock(struct net_device *dev) |
diff --git a/net/core/netpoll.c b/net/core/netpoll.c index ab3c0c9713b0..c327c9edadc5 100644 --- a/net/core/netpoll.c +++ b/net/core/netpoll.c | |||
| @@ -349,11 +349,15 @@ static void arp_reply(struct sk_buff *skb) | |||
| 349 | unsigned char *arp_ptr; | 349 | unsigned char *arp_ptr; |
| 350 | int size, type = ARPOP_REPLY, ptype = ETH_P_ARP; | 350 | int size, type = ARPOP_REPLY, ptype = ETH_P_ARP; |
| 351 | u32 sip, tip; | 351 | u32 sip, tip; |
| 352 | unsigned long flags; | ||
| 352 | struct sk_buff *send_skb; | 353 | struct sk_buff *send_skb; |
| 353 | struct netpoll *np = NULL; | 354 | struct netpoll *np = NULL; |
| 354 | 355 | ||
| 355 | if (npinfo) | 356 | spin_lock_irqsave(&npinfo->rx_lock, flags); |
| 356 | np = npinfo->np; | 357 | if (npinfo->rx_np && npinfo->rx_np->dev == skb->dev) |
| 358 | np = npinfo->rx_np; | ||
| 359 | spin_unlock_irqrestore(&npinfo->rx_lock, flags); | ||
| 360 | |||
| 357 | if (!np) | 361 | if (!np) |
| 358 | return; | 362 | return; |
| 359 | 363 | ||
| @@ -436,9 +440,9 @@ int __netpoll_rx(struct sk_buff *skb) | |||
| 436 | int proto, len, ulen; | 440 | int proto, len, ulen; |
| 437 | struct iphdr *iph; | 441 | struct iphdr *iph; |
| 438 | struct udphdr *uh; | 442 | struct udphdr *uh; |
| 439 | struct netpoll *np = skb->dev->npinfo->np; | 443 | struct netpoll *np = skb->dev->npinfo->rx_np; |
| 440 | 444 | ||
| 441 | if (!np->rx_hook) | 445 | if (!np) |
| 442 | goto out; | 446 | goto out; |
| 443 | if (skb->dev->type != ARPHRD_ETHER) | 447 | if (skb->dev->type != ARPHRD_ETHER) |
| 444 | goto out; | 448 | goto out; |
| @@ -619,6 +623,7 @@ int netpoll_setup(struct netpoll *np) | |||
| 619 | struct net_device *ndev = NULL; | 623 | struct net_device *ndev = NULL; |
| 620 | struct in_device *in_dev; | 624 | struct in_device *in_dev; |
| 621 | struct netpoll_info *npinfo; | 625 | struct netpoll_info *npinfo; |
| 626 | unsigned long flags; | ||
| 622 | 627 | ||
| 623 | if (np->dev_name) | 628 | if (np->dev_name) |
| 624 | ndev = dev_get_by_name(np->dev_name); | 629 | ndev = dev_get_by_name(np->dev_name); |
| @@ -634,9 +639,10 @@ int netpoll_setup(struct netpoll *np) | |||
| 634 | if (!npinfo) | 639 | if (!npinfo) |
| 635 | goto release; | 640 | goto release; |
| 636 | 641 | ||
| 637 | npinfo->np = NULL; | 642 | npinfo->rx_np = NULL; |
| 638 | npinfo->poll_lock = SPIN_LOCK_UNLOCKED; | 643 | npinfo->poll_lock = SPIN_LOCK_UNLOCKED; |
| 639 | npinfo->poll_owner = -1; | 644 | npinfo->poll_owner = -1; |
| 645 | npinfo->rx_lock = SPIN_LOCK_UNLOCKED; | ||
| 640 | } else | 646 | } else |
| 641 | npinfo = ndev->npinfo; | 647 | npinfo = ndev->npinfo; |
| 642 | 648 | ||
| @@ -706,9 +712,13 @@ int netpoll_setup(struct netpoll *np) | |||
| 706 | np->name, HIPQUAD(np->local_ip)); | 712 | np->name, HIPQUAD(np->local_ip)); |
| 707 | } | 713 | } |
| 708 | 714 | ||
| 709 | if(np->rx_hook) | 715 | if (np->rx_hook) { |
| 710 | npinfo->rx_flags = NETPOLL_RX_ENABLED; | 716 | spin_lock_irqsave(&npinfo->rx_lock, flags); |
| 711 | npinfo->np = np; | 717 | npinfo->rx_flags |= NETPOLL_RX_ENABLED; |
| 718 | npinfo->rx_np = np; | ||
| 719 | spin_unlock_irqrestore(&npinfo->rx_lock, flags); | ||
| 720 | } | ||
| 721 | /* last thing to do is link it to the net device structure */ | ||
| 712 | ndev->npinfo = npinfo; | 722 | ndev->npinfo = npinfo; |
| 713 | 723 | ||
| 714 | return 0; | 724 | return 0; |
| @@ -723,11 +733,20 @@ int netpoll_setup(struct netpoll *np) | |||
| 723 | 733 | ||
| 724 | void netpoll_cleanup(struct netpoll *np) | 734 | void netpoll_cleanup(struct netpoll *np) |
| 725 | { | 735 | { |
| 736 | struct netpoll_info *npinfo; | ||
| 737 | unsigned long flags; | ||
| 738 | |||
| 726 | if (np->dev) { | 739 | if (np->dev) { |
| 727 | if (np->dev->npinfo) | 740 | npinfo = np->dev->npinfo; |
| 728 | np->dev->npinfo->np = NULL; | 741 | if (npinfo && npinfo->rx_np == np) { |
| 742 | spin_lock_irqsave(&npinfo->rx_lock, flags); | ||
| 743 | npinfo->rx_np = NULL; | ||
| 744 | npinfo->rx_flags &= ~NETPOLL_RX_ENABLED; | ||
| 745 | spin_unlock_irqrestore(&npinfo->rx_lock, flags); | ||
| 746 | } | ||
| 729 | dev_put(np->dev); | 747 | dev_put(np->dev); |
| 730 | } | 748 | } |
| 749 | |||
| 731 | np->dev = NULL; | 750 | np->dev = NULL; |
| 732 | } | 751 | } |
| 733 | 752 | ||
