[NET]: Leak network device if refcount is positive.

Unfortunately, there is are some ways on which we have positive refcounters
on network device on VE stop. This bugs are rather hard to debug and locate.

The idea of this patch is to leave the loop waiting device to become free
and _leak_ this device. This is better than a node freeze.

Signed-off-by: Denis V. Lunev <den@parallels.com>
-----
diff -up linux-2.6.18-rhel5-028stab054.3/include/linux/netdevice.h linux-2.6.18-rhel5-028stab053.4/include/linux/netdevice.h
--- ./include/linux/netdevice.h	2008-04-04 15:41:59.000000000 +0400
+++ ./include/linux/netdevice.h	2008-05-04 18:05:44.000000000 +0400
@@ -422,6 +422,7 @@ struct net_device
 							because most packets are unicast) */
 
 	unsigned char		broadcast[MAX_ADDR_LEN];	/* hw bcast add	*/
+	unsigned char		is_leaked;
 
 /*
  * Cache line mostly used on queue transmit path (qdisc)
--- ./net/core/dev.c	2008-04-04 15:42:00.000000000 +0400
+++ ./net/core/dev.c	2008-05-04 19:23:46.000000000 +0400
@@ -3333,6 +3344,7 @@ EXPORT_SYMBOL(register_netdev);
  */
 static void netdev_wait_allrefs(struct net_device *dev)
 {
+	int i = 0;
 	unsigned long rebroadcast_time, warning_time;
 
 	rebroadcast_time = warning_time = jiffies;
@@ -3364,11 +3376,19 @@ static void netdev_wait_allrefs(struct n
 
 		if (time_after(jiffies, warning_time + 10 * HZ)) {
 			printk(KERN_EMERG "unregister_netdevice: "
-			       "waiting for %s to become free. Usage "
-			       "count = %d\n",
-			       dev->name, atomic_read(&dev->refcnt));
+			       "waiting for %s=%p to become free. Usage "
+			       "count = %d ve=%u\n",
+			       dev->name, dev, atomic_read(&dev->refcnt),
+			       VEID(get_exec_env()));
 			warning_time = jiffies;
 		}
+
+		if (++i > 10) {
+			dev->is_leaked = 1;
+			printk(KERN_EMERG "unregister_netdevice: "
+			       "device %p marked to leak\n", dev);
+			break;
+		}
 	}
 }
 
@@ -3435,10 +3455,12 @@ void netdev_run_todo(void)
 		netdev_wait_allrefs(dev);
 
 		/* paranoia */
+#if 0
 		BUG_ON(atomic_read(&dev->refcnt));
 		BUG_TRAP(!dev->ip_ptr);
 		BUG_TRAP(!dev->ip6_ptr);
 		BUG_TRAP(!dev->dn_ptr);
+#endif
 
 		put_beancounter(netdev_bc(dev)->exec_ub);
 		put_beancounter(netdev_bc(dev)->owner_ub);
@@ -3506,6 +3528,12 @@ EXPORT_SYMBOL(alloc_netdev);
  */
 void free_netdev(struct net_device *dev)
 {
+	if (dev->is_leaked) {
+		printk(KERN_EMERG "free_netdev: device %s=%p leaked\n",
+		       dev->name, dev);
+		return;
+	}
+
 #ifdef CONFIG_SYSFS
 	/*  Compatibility with error handling in drivers */
 	if (dev->reg_state == NETREG_UNINITIALIZED) {
