[IPV4]: Make loopback idev stick around.

This is patch from Herbert Xu, that allocates idev on loopback during
register.

        As it is when loopback_dev loses all of its IPv4 addresses its
        corresponding idev will be destroyed.  Unfortunately as of last
	August route.c relies on the loopback idev to kill references
	to other idev objects.

	The end result is that when you do ip a f dev lo, unregistering
	other devices will hang until those dst objects referring to
	their idev objects die of natural causes.  Of course this may
	never happen if the processes holding those references get
	dead-locked by invoking an operation that takes the RTNL.

	A simple solution is to make sure that loopback's idev sticks
	around all the time.

	Incidentally this also fixes the setting of some flags on the
	loopback idev object as currently the code that does it won't
	be called if you add the addresses to lo after bring it up.

	Signed-off-by: Herbert Xu <[EMAIL PROTECTED]>
	Signed-off-by: David S. Miller <[EMAIL PROTECTED]>

---
diff -up linux-2.6.9_/net/ipv4/devinet.c~fc12~1 linux-2.6.9_/net/ipv4/devinet.c
--- linux-2.6.9_/net/ipv4/devinet.c~fc12~1	2010-02-05 12:30:11.000000000 +0300
+++ linux-2.6.9_/net/ipv4/devinet.c	2010-02-05 12:34:18.000000000 +0300
@@ -197,6 +197,10 @@ static void inetdev_destroy(struct in_de
 
 	ASSERT_RTNL();
 
+	dev = in_dev->dev;
+	if (dev == &loopback_dev)
+		return;
+
 	in_dev->dead = 1;
 
 	ip_mc_destroy_dev(in_dev);
@@ -210,7 +214,6 @@ static void inetdev_destroy(struct in_de
 	devinet_sysctl_unregister(&in_dev->cnf);
 #endif
 
-	dev = in_dev->dev;
 	dev->ip_ptr = NULL;
 
 #ifdef CONFIG_SYSCTL
@@ -954,8 +957,16 @@ static int inetdev_event(struct notifier
 
 	ASSERT_RTNL();
 
-	if (!in_dev)
+	if (!in_dev) {
+		if (event == NETDEV_REGISTER && dev == &loopback_dev) {
+			in_dev = inetdev_init(dev);
+			if (!in_dev)
+				panic("devinet: Failed to create loopback\n");
+			in_dev->cnf.no_xfrm = 1;
+			in_dev->cnf.no_policy = 1;
+		}
 		goto out;
+	}
 
 	switch (event) {
 	case NETDEV_REGISTER:
@@ -978,8 +989,6 @@ static int inetdev_event(struct notifier
 				memcpy(ifa->ifa_label, dev->name, IFNAMSIZ);
 				inet_insert_ifa(ifa);
 			}
-			in_dev->cnf.no_xfrm = 1;
-			in_dev->cnf.no_policy = 1;
 		}
 		ip_mc_up(in_dev);
 		break;

