diff options
Diffstat (limited to 'net/core/netpoll.c')
-rw-r--r-- | net/core/netpoll.c | 182 |
1 files changed, 106 insertions, 76 deletions
diff --git a/net/core/netpoll.c b/net/core/netpoll.c index 94825b109551..537e01afd81b 100644 --- a/net/core/netpoll.c +++ b/net/core/netpoll.c | |||
@@ -199,11 +199,13 @@ void netpoll_poll_dev(struct net_device *dev) | |||
199 | 199 | ||
200 | zap_completion_queue(); | 200 | zap_completion_queue(); |
201 | } | 201 | } |
202 | EXPORT_SYMBOL(netpoll_poll_dev); | ||
202 | 203 | ||
203 | void netpoll_poll(struct netpoll *np) | 204 | void netpoll_poll(struct netpoll *np) |
204 | { | 205 | { |
205 | netpoll_poll_dev(np->dev); | 206 | netpoll_poll_dev(np->dev); |
206 | } | 207 | } |
208 | EXPORT_SYMBOL(netpoll_poll); | ||
207 | 209 | ||
208 | static void refill_skbs(void) | 210 | static void refill_skbs(void) |
209 | { | 211 | { |
@@ -292,6 +294,7 @@ void netpoll_send_skb(struct netpoll *np, struct sk_buff *skb) | |||
292 | unsigned long tries; | 294 | unsigned long tries; |
293 | struct net_device *dev = np->dev; | 295 | struct net_device *dev = np->dev; |
294 | const struct net_device_ops *ops = dev->netdev_ops; | 296 | const struct net_device_ops *ops = dev->netdev_ops; |
297 | /* It is up to the caller to keep npinfo alive. */ | ||
295 | struct netpoll_info *npinfo = np->dev->npinfo; | 298 | struct netpoll_info *npinfo = np->dev->npinfo; |
296 | 299 | ||
297 | if (!npinfo || !netif_running(dev) || !netif_device_present(dev)) { | 300 | if (!npinfo || !netif_running(dev) || !netif_device_present(dev)) { |
@@ -343,6 +346,7 @@ void netpoll_send_skb(struct netpoll *np, struct sk_buff *skb) | |||
343 | schedule_delayed_work(&npinfo->tx_work,0); | 346 | schedule_delayed_work(&npinfo->tx_work,0); |
344 | } | 347 | } |
345 | } | 348 | } |
349 | EXPORT_SYMBOL(netpoll_send_skb); | ||
346 | 350 | ||
347 | void netpoll_send_udp(struct netpoll *np, const char *msg, int len) | 351 | void netpoll_send_udp(struct netpoll *np, const char *msg, int len) |
348 | { | 352 | { |
@@ -404,6 +408,7 @@ void netpoll_send_udp(struct netpoll *np, const char *msg, int len) | |||
404 | 408 | ||
405 | netpoll_send_skb(np, skb); | 409 | netpoll_send_skb(np, skb); |
406 | } | 410 | } |
411 | EXPORT_SYMBOL(netpoll_send_udp); | ||
407 | 412 | ||
408 | static void arp_reply(struct sk_buff *skb) | 413 | static void arp_reply(struct sk_buff *skb) |
409 | { | 414 | { |
@@ -630,6 +635,7 @@ void netpoll_print_options(struct netpoll *np) | |||
630 | printk(KERN_INFO "%s: remote ethernet address %pM\n", | 635 | printk(KERN_INFO "%s: remote ethernet address %pM\n", |
631 | np->name, np->remote_mac); | 636 | np->name, np->remote_mac); |
632 | } | 637 | } |
638 | EXPORT_SYMBOL(netpoll_print_options); | ||
633 | 639 | ||
634 | int netpoll_parse_options(struct netpoll *np, char *opt) | 640 | int netpoll_parse_options(struct netpoll *np, char *opt) |
635 | { | 641 | { |
@@ -722,30 +728,29 @@ int netpoll_parse_options(struct netpoll *np, char *opt) | |||
722 | np->name, cur); | 728 | np->name, cur); |
723 | return -1; | 729 | return -1; |
724 | } | 730 | } |
731 | EXPORT_SYMBOL(netpoll_parse_options); | ||
725 | 732 | ||
726 | int netpoll_setup(struct netpoll *np) | 733 | int __netpoll_setup(struct netpoll *np) |
727 | { | 734 | { |
728 | struct net_device *ndev = NULL; | 735 | struct net_device *ndev = np->dev; |
729 | struct in_device *in_dev; | ||
730 | struct netpoll_info *npinfo; | 736 | struct netpoll_info *npinfo; |
731 | struct netpoll *npe, *tmp; | 737 | const struct net_device_ops *ops; |
732 | unsigned long flags; | 738 | unsigned long flags; |
733 | int err; | 739 | int err; |
734 | 740 | ||
735 | if (np->dev_name) | 741 | if ((ndev->priv_flags & IFF_DISABLE_NETPOLL) || |
736 | ndev = dev_get_by_name(&init_net, np->dev_name); | 742 | !ndev->netdev_ops->ndo_poll_controller) { |
737 | if (!ndev) { | 743 | printk(KERN_ERR "%s: %s doesn't support polling, aborting.\n", |
738 | printk(KERN_ERR "%s: %s doesn't exist, aborting.\n", | ||
739 | np->name, np->dev_name); | 744 | np->name, np->dev_name); |
740 | return -ENODEV; | 745 | err = -ENOTSUPP; |
746 | goto out; | ||
741 | } | 747 | } |
742 | 748 | ||
743 | np->dev = ndev; | ||
744 | if (!ndev->npinfo) { | 749 | if (!ndev->npinfo) { |
745 | npinfo = kmalloc(sizeof(*npinfo), GFP_KERNEL); | 750 | npinfo = kmalloc(sizeof(*npinfo), GFP_KERNEL); |
746 | if (!npinfo) { | 751 | if (!npinfo) { |
747 | err = -ENOMEM; | 752 | err = -ENOMEM; |
748 | goto put; | 753 | goto out; |
749 | } | 754 | } |
750 | 755 | ||
751 | npinfo->rx_flags = 0; | 756 | npinfo->rx_flags = 0; |
@@ -757,6 +762,13 @@ int netpoll_setup(struct netpoll *np) | |||
757 | INIT_DELAYED_WORK(&npinfo->tx_work, queue_process); | 762 | INIT_DELAYED_WORK(&npinfo->tx_work, queue_process); |
758 | 763 | ||
759 | atomic_set(&npinfo->refcnt, 1); | 764 | atomic_set(&npinfo->refcnt, 1); |
765 | |||
766 | ops = np->dev->netdev_ops; | ||
767 | if (ops->ndo_netpoll_setup) { | ||
768 | err = ops->ndo_netpoll_setup(ndev, npinfo); | ||
769 | if (err) | ||
770 | goto free_npinfo; | ||
771 | } | ||
760 | } else { | 772 | } else { |
761 | npinfo = ndev->npinfo; | 773 | npinfo = ndev->npinfo; |
762 | atomic_inc(&npinfo->refcnt); | 774 | atomic_inc(&npinfo->refcnt); |
@@ -764,12 +776,37 @@ int netpoll_setup(struct netpoll *np) | |||
764 | 776 | ||
765 | npinfo->netpoll = np; | 777 | npinfo->netpoll = np; |
766 | 778 | ||
767 | if ((ndev->priv_flags & IFF_DISABLE_NETPOLL) || | 779 | if (np->rx_hook) { |
768 | !ndev->netdev_ops->ndo_poll_controller) { | 780 | spin_lock_irqsave(&npinfo->rx_lock, flags); |
769 | printk(KERN_ERR "%s: %s doesn't support polling, aborting.\n", | 781 | npinfo->rx_flags |= NETPOLL_RX_ENABLED; |
782 | list_add_tail(&np->rx, &npinfo->rx_np); | ||
783 | spin_unlock_irqrestore(&npinfo->rx_lock, flags); | ||
784 | } | ||
785 | |||
786 | /* last thing to do is link it to the net device structure */ | ||
787 | rcu_assign_pointer(ndev->npinfo, npinfo); | ||
788 | |||
789 | return 0; | ||
790 | |||
791 | free_npinfo: | ||
792 | kfree(npinfo); | ||
793 | out: | ||
794 | return err; | ||
795 | } | ||
796 | EXPORT_SYMBOL_GPL(__netpoll_setup); | ||
797 | |||
798 | int netpoll_setup(struct netpoll *np) | ||
799 | { | ||
800 | struct net_device *ndev = NULL; | ||
801 | struct in_device *in_dev; | ||
802 | int err; | ||
803 | |||
804 | if (np->dev_name) | ||
805 | ndev = dev_get_by_name(&init_net, np->dev_name); | ||
806 | if (!ndev) { | ||
807 | printk(KERN_ERR "%s: %s doesn't exist, aborting.\n", | ||
770 | np->name, np->dev_name); | 808 | np->name, np->dev_name); |
771 | err = -ENOTSUPP; | 809 | return -ENODEV; |
772 | goto release; | ||
773 | } | 810 | } |
774 | 811 | ||
775 | if (!netif_running(ndev)) { | 812 | if (!netif_running(ndev)) { |
@@ -785,7 +822,7 @@ int netpoll_setup(struct netpoll *np) | |||
785 | if (err) { | 822 | if (err) { |
786 | printk(KERN_ERR "%s: failed to open %s\n", | 823 | printk(KERN_ERR "%s: failed to open %s\n", |
787 | np->name, ndev->name); | 824 | np->name, ndev->name); |
788 | goto release; | 825 | goto put; |
789 | } | 826 | } |
790 | 827 | ||
791 | atleast = jiffies + HZ/10; | 828 | atleast = jiffies + HZ/10; |
@@ -822,7 +859,7 @@ int netpoll_setup(struct netpoll *np) | |||
822 | printk(KERN_ERR "%s: no IP address for %s, aborting\n", | 859 | printk(KERN_ERR "%s: no IP address for %s, aborting\n", |
823 | np->name, np->dev_name); | 860 | np->name, np->dev_name); |
824 | err = -EDESTADDRREQ; | 861 | err = -EDESTADDRREQ; |
825 | goto release; | 862 | goto put; |
826 | } | 863 | } |
827 | 864 | ||
828 | np->local_ip = in_dev->ifa_list->ifa_local; | 865 | np->local_ip = in_dev->ifa_list->ifa_local; |
@@ -830,38 +867,25 @@ int netpoll_setup(struct netpoll *np) | |||
830 | printk(KERN_INFO "%s: local IP %pI4\n", np->name, &np->local_ip); | 867 | printk(KERN_INFO "%s: local IP %pI4\n", np->name, &np->local_ip); |
831 | } | 868 | } |
832 | 869 | ||
833 | if (np->rx_hook) { | 870 | np->dev = ndev; |
834 | spin_lock_irqsave(&npinfo->rx_lock, flags); | ||
835 | npinfo->rx_flags |= NETPOLL_RX_ENABLED; | ||
836 | list_add_tail(&np->rx, &npinfo->rx_np); | ||
837 | spin_unlock_irqrestore(&npinfo->rx_lock, flags); | ||
838 | } | ||
839 | 871 | ||
840 | /* fill up the skb queue */ | 872 | /* fill up the skb queue */ |
841 | refill_skbs(); | 873 | refill_skbs(); |
842 | 874 | ||
843 | /* last thing to do is link it to the net device structure */ | 875 | rtnl_lock(); |
844 | ndev->npinfo = npinfo; | 876 | err = __netpoll_setup(np); |
877 | rtnl_unlock(); | ||
845 | 878 | ||
846 | /* avoid racing with NAPI reading npinfo */ | 879 | if (err) |
847 | synchronize_rcu(); | 880 | goto put; |
848 | 881 | ||
849 | return 0; | 882 | return 0; |
850 | 883 | ||
851 | release: | ||
852 | if (!ndev->npinfo) { | ||
853 | spin_lock_irqsave(&npinfo->rx_lock, flags); | ||
854 | list_for_each_entry_safe(npe, tmp, &npinfo->rx_np, rx) { | ||
855 | npe->dev = NULL; | ||
856 | } | ||
857 | spin_unlock_irqrestore(&npinfo->rx_lock, flags); | ||
858 | |||
859 | kfree(npinfo); | ||
860 | } | ||
861 | put: | 884 | put: |
862 | dev_put(ndev); | 885 | dev_put(ndev); |
863 | return err; | 886 | return err; |
864 | } | 887 | } |
888 | EXPORT_SYMBOL(netpoll_setup); | ||
865 | 889 | ||
866 | static int __init netpoll_init(void) | 890 | static int __init netpoll_init(void) |
867 | { | 891 | { |
@@ -870,49 +894,65 @@ static int __init netpoll_init(void) | |||
870 | } | 894 | } |
871 | core_initcall(netpoll_init); | 895 | core_initcall(netpoll_init); |
872 | 896 | ||
873 | void netpoll_cleanup(struct netpoll *np) | 897 | void __netpoll_cleanup(struct netpoll *np) |
874 | { | 898 | { |
875 | struct netpoll_info *npinfo; | 899 | struct netpoll_info *npinfo; |
876 | unsigned long flags; | 900 | unsigned long flags; |
877 | 901 | ||
878 | if (np->dev) { | 902 | npinfo = np->dev->npinfo; |
879 | npinfo = np->dev->npinfo; | 903 | if (!npinfo) |
880 | if (npinfo) { | 904 | return; |
881 | if (!list_empty(&npinfo->rx_np)) { | ||
882 | spin_lock_irqsave(&npinfo->rx_lock, flags); | ||
883 | list_del(&np->rx); | ||
884 | if (list_empty(&npinfo->rx_np)) | ||
885 | npinfo->rx_flags &= ~NETPOLL_RX_ENABLED; | ||
886 | spin_unlock_irqrestore(&npinfo->rx_lock, flags); | ||
887 | } | ||
888 | 905 | ||
889 | if (atomic_dec_and_test(&npinfo->refcnt)) { | 906 | if (!list_empty(&npinfo->rx_np)) { |
890 | const struct net_device_ops *ops; | 907 | spin_lock_irqsave(&npinfo->rx_lock, flags); |
891 | skb_queue_purge(&npinfo->arp_tx); | 908 | list_del(&np->rx); |
892 | skb_queue_purge(&npinfo->txq); | 909 | if (list_empty(&npinfo->rx_np)) |
893 | cancel_rearming_delayed_work(&npinfo->tx_work); | 910 | npinfo->rx_flags &= ~NETPOLL_RX_ENABLED; |
894 | 911 | spin_unlock_irqrestore(&npinfo->rx_lock, flags); | |
895 | /* clean after last, unfinished work */ | 912 | } |
896 | __skb_queue_purge(&npinfo->txq); | 913 | |
897 | kfree(npinfo); | 914 | if (atomic_dec_and_test(&npinfo->refcnt)) { |
898 | ops = np->dev->netdev_ops; | 915 | const struct net_device_ops *ops; |
899 | if (ops->ndo_netpoll_cleanup) | 916 | |
900 | ops->ndo_netpoll_cleanup(np->dev); | 917 | ops = np->dev->netdev_ops; |
901 | else | 918 | if (ops->ndo_netpoll_cleanup) |
902 | np->dev->npinfo = NULL; | 919 | ops->ndo_netpoll_cleanup(np->dev); |
903 | } | 920 | |
904 | } | 921 | rcu_assign_pointer(np->dev->npinfo, NULL); |
922 | |||
923 | /* avoid racing with NAPI reading npinfo */ | ||
924 | synchronize_rcu_bh(); | ||
925 | |||
926 | skb_queue_purge(&npinfo->arp_tx); | ||
927 | skb_queue_purge(&npinfo->txq); | ||
928 | cancel_rearming_delayed_work(&npinfo->tx_work); | ||
905 | 929 | ||
906 | dev_put(np->dev); | 930 | /* clean after last, unfinished work */ |
931 | __skb_queue_purge(&npinfo->txq); | ||
932 | kfree(npinfo); | ||
907 | } | 933 | } |
934 | } | ||
935 | EXPORT_SYMBOL_GPL(__netpoll_cleanup); | ||
936 | |||
937 | void netpoll_cleanup(struct netpoll *np) | ||
938 | { | ||
939 | if (!np->dev) | ||
940 | return; | ||
908 | 941 | ||
942 | rtnl_lock(); | ||
943 | __netpoll_cleanup(np); | ||
944 | rtnl_unlock(); | ||
945 | |||
946 | dev_put(np->dev); | ||
909 | np->dev = NULL; | 947 | np->dev = NULL; |
910 | } | 948 | } |
949 | EXPORT_SYMBOL(netpoll_cleanup); | ||
911 | 950 | ||
912 | int netpoll_trap(void) | 951 | int netpoll_trap(void) |
913 | { | 952 | { |
914 | return atomic_read(&trapped); | 953 | return atomic_read(&trapped); |
915 | } | 954 | } |
955 | EXPORT_SYMBOL(netpoll_trap); | ||
916 | 956 | ||
917 | void netpoll_set_trap(int trap) | 957 | void netpoll_set_trap(int trap) |
918 | { | 958 | { |
@@ -921,14 +961,4 @@ void netpoll_set_trap(int trap) | |||
921 | else | 961 | else |
922 | atomic_dec(&trapped); | 962 | atomic_dec(&trapped); |
923 | } | 963 | } |
924 | |||
925 | EXPORT_SYMBOL(netpoll_send_skb); | ||
926 | EXPORT_SYMBOL(netpoll_set_trap); | 964 | EXPORT_SYMBOL(netpoll_set_trap); |
927 | EXPORT_SYMBOL(netpoll_trap); | ||
928 | EXPORT_SYMBOL(netpoll_print_options); | ||
929 | EXPORT_SYMBOL(netpoll_parse_options); | ||
930 | EXPORT_SYMBOL(netpoll_setup); | ||
931 | EXPORT_SYMBOL(netpoll_cleanup); | ||
932 | EXPORT_SYMBOL(netpoll_send_udp); | ||
933 | EXPORT_SYMBOL(netpoll_poll_dev); | ||
934 | EXPORT_SYMBOL(netpoll_poll); | ||