|
@@ -815,9 +815,17 @@ static bool some_qdisc_is_busy(struct net_device *dev)
|
|
|
return false;
|
|
|
}
|
|
|
|
|
|
+/**
|
|
|
+ * dev_deactivate_many - deactivate transmissions on several devices
|
|
|
+ * @head: list of devices to deactivate
|
|
|
+ *
|
|
|
+ * This function returns only when all outstanding transmissions
|
|
|
+ * have completed, unless all devices are in dismantle phase.
|
|
|
+ */
|
|
|
void dev_deactivate_many(struct list_head *head)
|
|
|
{
|
|
|
struct net_device *dev;
|
|
|
+ bool sync_needed = false;
|
|
|
|
|
|
list_for_each_entry(dev, head, unreg_list) {
|
|
|
netdev_for_each_tx_queue(dev, dev_deactivate_queue,
|
|
@@ -827,10 +835,15 @@ void dev_deactivate_many(struct list_head *head)
|
|
|
&noop_qdisc);
|
|
|
|
|
|
dev_watchdog_down(dev);
|
|
|
+ sync_needed |= !dev->dismantle;
|
|
|
}
|
|
|
|
|
|
- /* Wait for outstanding qdisc-less dev_queue_xmit calls. */
|
|
|
- synchronize_rcu();
|
|
|
+ /* Wait for outstanding qdisc-less dev_queue_xmit calls.
|
|
|
+ * This is avoided if all devices are in dismantle phase :
|
|
|
+ * Caller will call synchronize_net() for us
|
|
|
+ */
|
|
|
+ if (sync_needed)
|
|
|
+ synchronize_net();
|
|
|
|
|
|
/* Wait for outstanding qdisc_run calls. */
|
|
|
list_for_each_entry(dev, head, unreg_list)
|