[Devel] [PATCH rh7] Revert "net: Track leaked netdev"

Konstantin Khorenko khorenko at virtuozzo.com
Thu Jul 11 18:46:27 MSK 2019


This reverts commit 3c34688e71b6b30763cb03682e0e374e80471199.

The functionality of leaking VE net devices in case we
cannot unregister them for too long had been added long ago,
at least in VZ6.

And since Virtuozzo 7 birth is has been broken and we never
hit it before, thus we can assume the original issues (when
network devices failed to be released in several minutes)
are gone and we don't need this crutch, so revert it.

With this broken functionality - in case we really leak a
net device, netdev_run_todo() does not dec
net->dev_unreg_count and thus rtnl_lock_unregistering() in
default_device_exit_batch() waits forever holding net_mutex
which stucks lot of other operations, most noticeable -
copy_net_ns().

https://jira.sw.ru/browse/PSBM-96057

Signed-off-by: Konstantin Khorenko <khorenko at virtuozzo.com>
---
 include/linux/netdevice.h |  1 -
 net/core/dev.c            | 90 +++--------------------------------------------
 net/core/neighbour.c      |  7 ----
 3 files changed, 4 insertions(+), 94 deletions(-)

diff --git a/include/linux/netdevice.h b/include/linux/netdevice.h
index f287c41a5a05..bec955f1b67f 100644
--- a/include/linux/netdevice.h
+++ b/include/linux/netdevice.h
@@ -1789,7 +1789,6 @@ struct net_device {
 						   because most packets are
 						   unicast) */
 
-	unsigned char		is_leaked;
 
 #ifdef CONFIG_RPS
 	struct netdev_rx_queue	*_rx;
diff --git a/net/core/dev.c b/net/core/dev.c
index 0437f7769c98..4c3399f8b6d5 100644
--- a/net/core/dev.c
+++ b/net/core/dev.c
@@ -7745,58 +7745,6 @@ int register_netdevice(struct net_device *dev)
 }
 EXPORT_SYMBOL(register_netdevice);
 
-/*
- * We do horrible things -- we left a netdevice
- * in "leaked" state, which means we release as much
- * resources as possible but the device will remain
- * present in namespace because someone holds a reference.
- *
- * The idea is to be able to force stop VE.
- */
-static void ve_netdev_leak(struct net_device *dev)
-{
-	struct napi_struct *p, *n;
-
-	dev->is_leaked = 1;
-	barrier();
-
-	/*
-	 * Make sure we're unable to tx/rx
-	 * network packets to outside.
-	 */
-	WARN_ON_ONCE(dev->flags & IFF_UP);
-	WARN_ON_ONCE(dev->qdisc != &noop_qdisc);
-
-	rtnl_lock();
-
-	/*
-	 * No address and napi after that.
-	 */
-	dev_addr_flush(dev);
-	list_for_each_entry_safe(p, n, &dev->napi_list, dev_list)
-		netif_napi_del(p);
-
-	/*
-	 * No release_net() here since the device remains
-	 * present in the namespace.
-	 */
-
-	__rtnl_unlock();
-
-	/*
-	 * Since we've already screwed the device and releasing
-	 * it in a normal way is not possible anymore, we're
-	 * to be sure the device will remain here forever.
-	 */
-	dev_hold(dev);
-
-	synchronize_net();
-
-	pr_emerg("Device (%s:%d:%s:%p) marked as leaked\n",
-			dev->name, netdev_refcnt_read(dev) - 1,
-			ve_name(dev_net(dev)->owner_ve), dev);
-}
-
 /**
  *	init_dummy_netdev	- init a dummy network device for NAPI
  *	@dev: device to init
@@ -7884,11 +7832,10 @@ EXPORT_SYMBOL(netdev_refcnt_read);
  * We can get stuck here if buggy protocols don't correctly
  * call dev_put.
  */
-static int netdev_wait_allrefs(struct net_device *dev)
+static void netdev_wait_allrefs(struct net_device *dev)
 {
 	unsigned long rebroadcast_time, warning_time;
 	int refcnt;
-	int i = 0;
 
 	linkwatch_forget_dev(dev);
 
@@ -7928,25 +7875,11 @@ static int netdev_wait_allrefs(struct net_device *dev)
 		refcnt = netdev_refcnt_read(dev);
 
 		if (time_after(jiffies, warning_time + 10 * HZ)) {
-			pr_emerg("unregister_netdevice: waiting for %s=%p to "
-				"become free. Usage count = %d\n ve=%s",
-				 dev->name, dev, refcnt,
-				 ve_name(dev_net(dev)->owner_ve));
+			pr_emerg("unregister_netdevice: waiting for %s to become free. Usage count = %d\n",
+				 dev->name, refcnt);
 			warning_time = jiffies;
 		}
-
-		/*
-		 * If device has lost the reference we might stuck
-		 * in this loop forever not having a chance the VE
-		 * to stop.
-		 */
-		if (++i > 200) { /* give 50 seconds to try */
-			ve_netdev_leak(dev);
-			return -EBUSY;
-		}
 	}
-
-	return 0;
 }
 
 /* The sequence is:
@@ -8005,12 +7938,7 @@ void netdev_run_todo(void)
 
 		dev->reg_state = NETREG_UNREGISTERED;
 
-		/*
-		 * Even if device get stuck here we are
-		 * to proceed the rest of the list.
-		 */
-		if (netdev_wait_allrefs(dev))
-			continue;
+		netdev_wait_allrefs(dev);
 
 		/* paranoia */
 		BUG_ON(netdev_refcnt_read(dev));
@@ -8022,9 +7950,6 @@ void netdev_run_todo(void)
 
 		atomic_inc(&dev_net(dev)->owner_ve->netif_avail_nr);
 
-		/* It must be the very last action,
-		 * after this 'dev' may point to freed up memory.
-		 */
 		if (dev->destructor) {
 			dev->destructor(dev);
 		} else {
@@ -8278,13 +8203,6 @@ void free_netdev(struct net_device *dev)
 {
 	struct napi_struct *p, *n;
 
-	if (dev->is_leaked) {
-		pr_emerg("%s: device %s=%p is leaked\n",
-				__func__, dev->name, dev);
-		dump_stack();
-		return;
-	}
-
 	might_sleep();
 	netif_free_tx_queues(dev);
 #ifdef CONFIG_RPS
diff --git a/net/core/neighbour.c b/net/core/neighbour.c
index 7a0e4b420022..bfb2a55e291b 100644
--- a/net/core/neighbour.c
+++ b/net/core/neighbour.c
@@ -766,13 +766,6 @@ void neigh_destroy(struct neighbour *neigh)
 
 	NEIGH_CACHE_STAT_INC(neigh->tbl, destroys);
 
-	if (neigh->dev->is_leaked) {
-		printk(KERN_WARNING
-		       "Destroying neighbour %p on leaked device\n", neigh);
-		dump_stack();
-		return;
-	}
-
 	if (!neigh->dead) {
 		pr_warn("Destroying alive neighbour %p\n", neigh);
 		dump_stack();
-- 
2.15.1



More information about the Devel mailing list