[RHEL7,COMMIT] Revert "net: Track leaked netdev"

Submitted by Konstantin Khorenko on July 11, 2019, 3:58 p.m.

Details

Message ID 201907111558.x6BFwuji026594@finist-ce7.sw.ru
State New
Series "Revert "net: Track leaked netdev""
Headers show

Commit Message

Konstantin Khorenko July 11, 2019, 3:58 p.m.
The commit is pushed to "branch-rh7-3.10.0-957.21.3.vz7.106.x-ovz" and will appear at https://src.openvz.org/scm/ovz/vzkernel.git
after rh7-3.10.0-957.21.3.vz7.106.6
------>
commit 13f6e25d9dc4b2d525381a7f564eb66e7287931f
Author: Konstantin Khorenko <khorenko@virtuozzo.com>
Date:   Thu Jul 11 18:25:34 2019 +0300

    Revert "net: Track leaked netdev"
    
    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@virtuozzo.com>
---
 include/linux/netdevice.h |  1 -
 net/core/dev.c            | 90 +++--------------------------------------------
 net/core/neighbour.c      |  7 ----
 3 files changed, 4 insertions(+), 94 deletions(-)

Patch hide | download patch | download mbox

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();