diff options
author | Octavian Purdila <opurdila@ixiacom.com> | 2010-12-13 07:44:07 -0500 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2010-12-16 17:04:44 -0500 |
commit | 443457242beb6716b43db4d62fe148eab5515505 (patch) | |
tree | 0dbcf7dbaa7c6be6ca84631f3e865cde3d6b59f2 /net/sched/sch_generic.c | |
parent | c6c8fea29769d998d94fcec9b9f14d4b52b349d3 (diff) |
net: factorize sync-rcu call in unregister_netdevice_many
Add dev_close_many and dev_deactivate_many to factorize another
sync-rcu operation on the netdevice unregister path.
$ modprobe dummy numdummies=10000
$ ip link set dev dummy* up
$ time rmmod dummy
Without the patch With the patch
real 0m 24.63s real 0m 5.15s
user 0m 0.00s user 0m 0.00s
sys 0m 6.05s sys 0m 5.14s
Signed-off-by: Octavian Purdila <opurdila@ixiacom.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'net/sched/sch_generic.c')
-rw-r--r-- | net/sched/sch_generic.c | 29 |
1 files changed, 22 insertions, 7 deletions
diff --git a/net/sched/sch_generic.c b/net/sched/sch_generic.c index 0918834ee4a1..34dc598440a2 100644 --- a/net/sched/sch_generic.c +++ b/net/sched/sch_generic.c | |||
@@ -810,20 +810,35 @@ static bool some_qdisc_is_busy(struct net_device *dev) | |||
810 | return false; | 810 | return false; |
811 | } | 811 | } |
812 | 812 | ||
813 | void dev_deactivate(struct net_device *dev) | 813 | void dev_deactivate_many(struct list_head *head) |
814 | { | 814 | { |
815 | netdev_for_each_tx_queue(dev, dev_deactivate_queue, &noop_qdisc); | 815 | struct net_device *dev; |
816 | if (dev_ingress_queue(dev)) | ||
817 | dev_deactivate_queue(dev, dev_ingress_queue(dev), &noop_qdisc); | ||
818 | 816 | ||
819 | dev_watchdog_down(dev); | 817 | list_for_each_entry(dev, head, unreg_list) { |
818 | netdev_for_each_tx_queue(dev, dev_deactivate_queue, | ||
819 | &noop_qdisc); | ||
820 | if (dev_ingress_queue(dev)) | ||
821 | dev_deactivate_queue(dev, dev_ingress_queue(dev), | ||
822 | &noop_qdisc); | ||
823 | |||
824 | dev_watchdog_down(dev); | ||
825 | } | ||
820 | 826 | ||
821 | /* Wait for outstanding qdisc-less dev_queue_xmit calls. */ | 827 | /* Wait for outstanding qdisc-less dev_queue_xmit calls. */ |
822 | synchronize_rcu(); | 828 | synchronize_rcu(); |
823 | 829 | ||
824 | /* Wait for outstanding qdisc_run calls. */ | 830 | /* Wait for outstanding qdisc_run calls. */ |
825 | while (some_qdisc_is_busy(dev)) | 831 | list_for_each_entry(dev, head, unreg_list) |
826 | yield(); | 832 | while (some_qdisc_is_busy(dev)) |
833 | yield(); | ||
834 | } | ||
835 | |||
836 | void dev_deactivate(struct net_device *dev) | ||
837 | { | ||
838 | LIST_HEAD(single); | ||
839 | |||
840 | list_add(&dev->unreg_list, &single); | ||
841 | dev_deactivate_many(&single); | ||
827 | } | 842 | } |
828 | 843 | ||
829 | static void dev_init_scheduler_queue(struct net_device *dev, | 844 | static void dev_init_scheduler_queue(struct net_device *dev, |