Commit db44575f6fd55df6ff67ddd21f7ad5be5a741136
Committed by
David S. Miller
1 parent
1f494c0e04
Exists in
master
and in
39 other branches
[NET]: fix oops after tunnel module unload
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>
Showing 3 changed files with 55 additions and 7 deletions Side-by-side Diff
net/ipv4/ip_gre.c
... | ... | @@ -290,7 +290,6 @@ |
290 | 290 | |
291 | 291 | dev_hold(dev); |
292 | 292 | ipgre_tunnel_link(nt); |
293 | - /* Do not decrement MOD_USE_COUNT here. */ | |
294 | 293 | return nt; |
295 | 294 | |
296 | 295 | failed: |
297 | 296 | |
298 | 297 | |
... | ... | @@ -1277,12 +1276,28 @@ |
1277 | 1276 | goto out; |
1278 | 1277 | } |
1279 | 1278 | |
1280 | -static void ipgre_fini(void) | |
1279 | +static void __exit ipgre_destroy_tunnels(void) | |
1281 | 1280 | { |
1281 | + int prio; | |
1282 | + | |
1283 | + for (prio = 0; prio < 4; prio++) { | |
1284 | + int h; | |
1285 | + for (h = 0; h < HASH_SIZE; h++) { | |
1286 | + struct ip_tunnel *t; | |
1287 | + while ((t = tunnels[prio][h]) != NULL) | |
1288 | + unregister_netdevice(t->dev); | |
1289 | + } | |
1290 | + } | |
1291 | +} | |
1292 | + | |
1293 | +static void __exit ipgre_fini(void) | |
1294 | +{ | |
1282 | 1295 | if (inet_del_protocol(&ipgre_protocol, IPPROTO_GRE) < 0) |
1283 | 1296 | printk(KERN_INFO "ipgre close: can't remove protocol\n"); |
1284 | 1297 | |
1285 | - unregister_netdev(ipgre_fb_tunnel_dev); | |
1298 | + rtnl_lock(); | |
1299 | + ipgre_destroy_tunnels(); | |
1300 | + rtnl_unlock(); | |
1286 | 1301 | } |
1287 | 1302 | |
1288 | 1303 | module_init(ipgre_init); |
net/ipv4/ipip.c
... | ... | @@ -255,7 +255,6 @@ |
255 | 255 | |
256 | 256 | dev_hold(dev); |
257 | 257 | ipip_tunnel_link(nt); |
258 | - /* Do not decrement MOD_USE_COUNT here. */ | |
259 | 258 | return nt; |
260 | 259 | |
261 | 260 | failed: |
262 | 261 | |
... | ... | @@ -920,12 +919,29 @@ |
920 | 919 | goto out; |
921 | 920 | } |
922 | 921 | |
922 | +static void __exit ipip_destroy_tunnels(void) | |
923 | +{ | |
924 | + int prio; | |
925 | + | |
926 | + for (prio = 1; prio < 4; prio++) { | |
927 | + int h; | |
928 | + for (h = 0; h < HASH_SIZE; h++) { | |
929 | + struct ip_tunnel *t; | |
930 | + while ((t = tunnels[prio][h]) != NULL) | |
931 | + unregister_netdevice(t->dev); | |
932 | + } | |
933 | + } | |
934 | +} | |
935 | + | |
923 | 936 | static void __exit ipip_fini(void) |
924 | 937 | { |
925 | 938 | if (ipip_unregister() < 0) |
926 | 939 | printk(KERN_INFO "ipip close: can't deregister tunnel\n"); |
927 | 940 | |
928 | - unregister_netdev(ipip_fb_tunnel_dev); | |
941 | + rtnl_lock(); | |
942 | + ipip_destroy_tunnels(); | |
943 | + unregister_netdevice(ipip_fb_tunnel_dev); | |
944 | + rtnl_unlock(); | |
929 | 945 | } |
930 | 946 | |
931 | 947 | module_init(ipip_init); |
net/ipv6/sit.c
... | ... | @@ -195,7 +195,6 @@ |
195 | 195 | dev_hold(dev); |
196 | 196 | |
197 | 197 | ipip6_tunnel_link(nt); |
198 | - /* Do not decrement MOD_USE_COUNT here. */ | |
199 | 198 | return nt; |
200 | 199 | |
201 | 200 | failed: |
202 | 201 | |
... | ... | @@ -794,10 +793,28 @@ |
794 | 793 | .err_handler = ipip6_err, |
795 | 794 | }; |
796 | 795 | |
796 | +static void __exit sit_destroy_tunnels(void) | |
797 | +{ | |
798 | + int prio; | |
799 | + | |
800 | + for (prio = 1; prio < 4; prio++) { | |
801 | + int h; | |
802 | + for (h = 0; h < HASH_SIZE; h++) { | |
803 | + struct ip_tunnel *t; | |
804 | + while ((t = tunnels[prio][h]) != NULL) | |
805 | + unregister_netdevice(t->dev); | |
806 | + } | |
807 | + } | |
808 | +} | |
809 | + | |
797 | 810 | void __exit sit_cleanup(void) |
798 | 811 | { |
799 | 812 | inet_del_protocol(&sit_protocol, IPPROTO_IPV6); |
800 | - unregister_netdev(ipip6_fb_tunnel_dev); | |
813 | + | |
814 | + rtnl_lock(); | |
815 | + sit_destroy_tunnels(); | |
816 | + unregister_netdevice(ipip6_fb_tunnel_dev); | |
817 | + rtnl_unlock(); | |
801 | 818 | } |
802 | 819 | |
803 | 820 | int __init sit_init(void) |