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

Submitted by Konstantin Khorenko on Dec. 24, 2019, 10:31 a.m.

Details

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

Commit Message

Konstantin Khorenko Dec. 24, 2019, 10:31 a.m.
The commit is pushed to "branch-rh7-3.10.0-1062.7.1.vz7.130.x-ovz" and will appear at https://src.openvz.org/scm/ovz/vzkernel.git
after rh7-3.10.0-1062.7.1.vz7.130.5
------>
commit 06572dbe8642ab6783d482429336023f5f13635a
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-100474
    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 b617ff1d2a006..cf7ebe894d5b6 100644
--- a/include/linux/netdevice.h
+++ b/include/linux/netdevice.h
@@ -1828,7 +1828,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 306cfff75c57e..4dd78d9f120da 100644
--- a/net/core/dev.c
+++ b/net/core/dev.c
@@ -7875,58 +7875,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
@@ -8014,11 +7962,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);
 
@@ -8058,25 +8005,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:
@@ -8135,12 +8068,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));
@@ -8152,9 +8080,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 {
@@ -8408,13 +8333,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 266ac053ec96a..fe11e1042c2b3 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();