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>
Šī revīzija ir iekļauta:
Octavian Purdila
2010-12-13 12:44:07 +00:00
revīziju iesūtīja David S. Miller
vecāks c6c8fea297
revīzija 443457242b
3 mainīti faili ar 102 papildinājumiem un 52 dzēšanām

Parādīt failu

@@ -810,20 +810,35 @@ static bool some_qdisc_is_busy(struct net_device *dev)
return false;
}
void dev_deactivate(struct net_device *dev)
void dev_deactivate_many(struct list_head *head)
{
netdev_for_each_tx_queue(dev, dev_deactivate_queue, &noop_qdisc);
if (dev_ingress_queue(dev))
dev_deactivate_queue(dev, dev_ingress_queue(dev), &noop_qdisc);
struct net_device *dev;
dev_watchdog_down(dev);
list_for_each_entry(dev, head, unreg_list) {
netdev_for_each_tx_queue(dev, dev_deactivate_queue,
&noop_qdisc);
if (dev_ingress_queue(dev))
dev_deactivate_queue(dev, dev_ingress_queue(dev),
&noop_qdisc);
dev_watchdog_down(dev);
}
/* Wait for outstanding qdisc-less dev_queue_xmit calls. */
synchronize_rcu();
/* Wait for outstanding qdisc_run calls. */
while (some_qdisc_is_busy(dev))
yield();
list_for_each_entry(dev, head, unreg_list)
while (some_qdisc_is_busy(dev))
yield();
}
void dev_deactivate(struct net_device *dev)
{
LIST_HEAD(single);
list_add(&dev->unreg_list, &single);
dev_deactivate_many(&single);
}
static void dev_init_scheduler_queue(struct net_device *dev,