[NET]: fix oops after tunnel module unload
authorAlexey Kuznetsov <kuznet@ms2.inr.ac.ru>
Sun, 31 Jul 2005 00:46:44 +0000 (17:46 -0700)
committerDavid S. Miller <davem@davemloft.net>
Sun, 31 Jul 2005 00:46:44 +0000 (17:46 -0700)
Tunnel modules used to obtain module refcount each time when
some tunnel was created, which meaned that tunnel could be unloaded
only after all the tunnels are deleted.

Since killing old MOD_*_USE_COUNT macros this protection has gone.
It is possible to return it back as module_get/put, but it looks
more natural and practically useful to force destruction of all
the child tunnels on module unload.

Signed-off-by: Alexey Kuznetsov <kuznet@ms2.inr.ac.ru>
Signed-off-by: David S. Miller <davem@davemloft.net>
net/ipv4/ip_gre.c
net/ipv4/ipip.c
net/ipv6/sit.c

index 8848355222241cbd1763330a88183a2b45b34966..f0d5740d7e220f5675602ee43682c526f4dfbf8c 100644 (file)
@@ -290,7 +290,6 @@ static struct ip_tunnel * ipgre_tunnel_locate(struct ip_tunnel_parm *parms, int
 
        dev_hold(dev);
        ipgre_tunnel_link(nt);
-       /* Do not decrement MOD_USE_COUNT here. */
        return nt;
 
 failed:
@@ -1277,12 +1276,28 @@ err1:
        goto out;
 }
 
-static void ipgre_fini(void)
+static void __exit ipgre_destroy_tunnels(void)
+{
+       int prio;
+
+       for (prio = 0; prio < 4; prio++) {
+               int h;
+               for (h = 0; h < HASH_SIZE; h++) {
+                       struct ip_tunnel *t;
+                       while ((t = tunnels[prio][h]) != NULL)
+                               unregister_netdevice(t->dev);
+               }
+       }
+}
+
+static void __exit ipgre_fini(void)
 {
        if (inet_del_protocol(&ipgre_protocol, IPPROTO_GRE) < 0)
                printk(KERN_INFO "ipgre close: can't remove protocol\n");
 
-       unregister_netdev(ipgre_fb_tunnel_dev);
+       rtnl_lock();
+       ipgre_destroy_tunnels();
+       rtnl_unlock();
 }
 
 module_init(ipgre_init);
index c3947cd566b7a6c0e421dfab418ac09976221d30..c05c1df0bb045e17f92b9cbe5dcad23ed8df2c6e 100644 (file)
@@ -255,7 +255,6 @@ static struct ip_tunnel * ipip_tunnel_locate(struct ip_tunnel_parm *parms, int c
 
        dev_hold(dev);
        ipip_tunnel_link(nt);
-       /* Do not decrement MOD_USE_COUNT here. */
        return nt;
 
 failed:
@@ -920,12 +919,29 @@ static int __init ipip_init(void)
        goto out;
 }
 
+static void __exit ipip_destroy_tunnels(void)
+{
+       int prio;
+
+       for (prio = 1; prio < 4; prio++) {
+               int h;
+               for (h = 0; h < HASH_SIZE; h++) {
+                       struct ip_tunnel *t;
+                       while ((t = tunnels[prio][h]) != NULL)
+                               unregister_netdevice(t->dev);
+               }
+       }
+}
+
 static void __exit ipip_fini(void)
 {
        if (ipip_unregister() < 0)
                printk(KERN_INFO "ipip close: can't deregister tunnel\n");
 
-       unregister_netdev(ipip_fb_tunnel_dev);
+       rtnl_lock();
+       ipip_destroy_tunnels();
+       unregister_netdevice(ipip_fb_tunnel_dev);
+       rtnl_unlock();
 }
 
 module_init(ipip_init);
index b788f55e139b80756e23ef024335c3d2024d9f63..e553e5b80d6e3ed78124073c5163ec17dc0143b6 100644 (file)
@@ -195,7 +195,6 @@ static struct ip_tunnel * ipip6_tunnel_locate(struct ip_tunnel_parm *parms, int
        dev_hold(dev);
 
        ipip6_tunnel_link(nt);
-       /* Do not decrement MOD_USE_COUNT here. */
        return nt;
 
 failed:
@@ -794,10 +793,28 @@ static struct net_protocol sit_protocol = {
        .err_handler    =       ipip6_err,
 };
 
+static void __exit sit_destroy_tunnels(void)
+{
+       int prio;
+
+       for (prio = 1; prio < 4; prio++) {
+               int h;
+               for (h = 0; h < HASH_SIZE; h++) {
+                       struct ip_tunnel *t;
+                       while ((t = tunnels[prio][h]) != NULL)
+                               unregister_netdevice(t->dev);
+               }
+       }
+}
+
 void __exit sit_cleanup(void)
 {
        inet_del_protocol(&sit_protocol, IPPROTO_IPV6);
-       unregister_netdev(ipip6_fb_tunnel_dev);
+
+       rtnl_lock();
+       sit_destroy_tunnels();
+       unregister_netdevice(ipip6_fb_tunnel_dev);
+       rtnl_unlock();
 }
 
 int __init sit_init(void)