aboutsummaryrefslogtreecommitdiffstats
path: root/net/ipv4/ipmr.c
diff options
context:
space:
mode:
authorWang Chen <wangchen@cn.fujitsu.com>2008-07-14 23:56:34 -0400
committerDavid S. Miller <davem@davemloft.net>2008-07-14 23:56:34 -0400
commit7dc00c82cbb0119cf4663f65bbaa2cc55f961db2 (patch)
tree487af895b7c9587ab454a2021e63179ae6d68d96 /net/ipv4/ipmr.c
parentd607032db0ccd7274bee348df3214f6f52b24816 (diff)
ipv4: Fix ipmr unregister device oops
An oops happens during device unregister. The following oops happened when I add two tunnels, which use a same device, and then delete one tunnel. Obviously deleting tunnel "A" causes device unregister, which send a notification, and after receiving notification, ipmr do unregister again for tunnel "B" which also use same device. That is wrong. After receiving notification, ipmr only needs to decrease reference count and don't do duplicated unregister. Fortunately, IPv6 side doesn't add tunnel in ip6mr, so it's clean. This patch fixs: - unregister device oops - using after dev_put() Here is the oops: === Jul 11 15:39:29 wangchen kernel: ------------[ cut here ]------------ Jul 11 15:39:29 wangchen kernel: kernel BUG at net/core/dev.c:3651! Jul 11 15:39:29 wangchen kernel: invalid opcode: 0000 [#1] Jul 11 15:39:29 wangchen kernel: Modules linked in: ipip tunnel4 nfsd lockd nfs_acl auth_rpcgss sunrpc exportfs ipv6 snd_pcm_oss snd_mixer_oss snd_seq snd_seq_device af_packet binfmt_misc button battery ac loop dm_mod usbhid ff_memless pcmcia firmware_class ohci1394 8139too mii ieee1394 yenta_socket rsrc_nonstatic pcmcia_core ide_cd_mod cdrom snd_intel8x0 snd_ac97_codec ac97_bus snd_pcm i2c_i801 snd_timer snd i2c_core soundcore snd_page_alloc rng_core shpchp ehci_hcd uhci_hcd pci_hotplug intel_agp agpgart usbcore ext3 jbd ata_piix ahci libata dock edd fan thermal processor thermal_sys piix sd_mod scsi_mod ide_disk ide_core [last unloaded: freq_table] Jul 11 15:39:29 wangchen kernel: Jul 11 15:39:29 wangchen kernel: Pid: 4102, comm: mroute Not tainted (2.6.26-rc9-default #69) Jul 11 15:39:29 wangchen kernel: EIP: 0060:[<c024636b>] EFLAGS: 00010202 CPU: 0 Jul 11 15:39:29 wangchen kernel: EIP is at rollback_registered+0x61/0xe3 Jul 11 15:39:29 wangchen kernel: EAX: 00000001 EBX: ecba6000 ECX: 00000000 EDX: ffffffff Jul 11 15:39:29 wangchen kernel: ESI: 00000001 EDI: ecba6000 EBP: c03de2e8 ESP: ed8e7c3c Jul 11 15:39:29 wangchen kernel: DS: 007b ES: 007b FS: 0000 GS: 0033 SS: 0068 Jul 11 15:39:29 wangchen kernel: Process mroute (pid: 4102, ti=ed8e6000 task=ed41e830 task.ti=ed8e6000) Jul 11 15:39:29 wangchen kernel: Stack: ecba6000 c024641c 00000028 c0284e1a 00000001 c03de2e8 ecba6000 eecff360 Jul 11 15:39:29 wangchen kernel: c0284e4c c03536f4 fffffff8 00000000 c029a819 ecba6000 00000006 ecba6000 Jul 11 15:39:29 wangchen kernel: 00000000 ecba6000 c03de2c0 c012841b ffffffff 00000000 c024639f ecba6000 Jul 11 15:39:29 wangchen kernel: Call Trace: Jul 11 15:39:29 wangchen kernel: [<c024641c>] unregister_netdevice+0x2f/0x51 Jul 11 15:39:29 wangchen kernel: [<c0284e1a>] vif_delete+0xaf/0xc3 Jul 11 15:39:29 wangchen kernel: [<c0284e4c>] ipmr_device_event+0x1e/0x30 Jul 11 15:39:29 wangchen kernel: [<c029a819>] notifier_call_chain+0x2a/0x47 Jul 11 15:39:29 wangchen kernel: [<c012841b>] raw_notifier_call_chain+0x9/0xc Jul 11 15:39:29 wangchen kernel: [<c024639f>] rollback_registered+0x95/0xe3 Jul 11 15:39:29 wangchen kernel: [<c024641c>] unregister_netdevice+0x2f/0x51 Jul 11 15:39:29 wangchen kernel: [<c0284e1a>] vif_delete+0xaf/0xc3 Jul 11 15:39:29 wangchen kernel: [<c0285eee>] ip_mroute_setsockopt+0x47a/0x801 Jul 11 15:39:29 wangchen kernel: [<eea5a70c>] do_get_write_access+0x2df/0x313 [jbd] Jul 11 15:39:29 wangchen kernel: [<c01727c4>] __find_get_block_slow+0xda/0xe4 Jul 11 15:39:29 wangchen kernel: [<c0172a7f>] __find_get_block+0xf8/0x122 Jul 11 15:39:29 wangchen kernel: [<c0172a7f>] __find_get_block+0xf8/0x122 Jul 11 15:39:29 wangchen kernel: [<eea5d563>] journal_cancel_revoke+0xda/0x110 [jbd] Jul 11 15:39:29 wangchen kernel: [<c0263501>] ip_setsockopt+0xa9/0x9ee Jul 11 15:39:29 wangchen kernel: [<eea5d563>] journal_cancel_revoke+0xda/0x110 [jbd] Jul 11 15:39:29 wangchen kernel: [<eea5a70c>] do_get_write_access+0x2df/0x313 [jbd] Jul 11 15:39:29 wangchen kernel: [<eea69287>] __ext3_get_inode_loc+0xcf/0x271 [ext3] Jul 11 15:39:29 wangchen kernel: [<eea743c7>] __ext3_journal_dirty_metadata+0x13/0x32 [ext3] Jul 11 15:39:29 wangchen kernel: [<c0116434>] __wake_up+0xf/0x15 Jul 11 15:39:29 wangchen kernel: [<eea5a424>] journal_stop+0x1bd/0x1c6 [jbd] Jul 11 15:39:29 wangchen kernel: [<eea703a7>] __ext3_journal_stop+0x19/0x34 [ext3] Jul 11 15:39:29 wangchen kernel: [<c014291e>] get_page_from_freelist+0x94/0x369 Jul 11 15:39:29 wangchen kernel: [<c01408f2>] filemap_fault+0x1ac/0x2fe Jul 11 15:39:29 wangchen kernel: [<c01a605e>] security_sk_alloc+0xd/0xf Jul 11 15:39:29 wangchen kernel: [<c023edea>] sk_prot_alloc+0x36/0x78 Jul 11 15:39:29 wangchen kernel: [<c0240037>] sk_alloc+0x3a/0x40 Jul 11 15:39:29 wangchen kernel: [<c0276062>] raw_hash_sk+0x46/0x4e Jul 11 15:39:29 wangchen kernel: [<c0166aff>] d_alloc+0x1b/0x157 Jul 11 15:39:29 wangchen kernel: [<c023e4d1>] sock_common_setsockopt+0x12/0x16 Jul 11 15:39:29 wangchen kernel: [<c023cb1e>] sys_setsockopt+0x6f/0x8e Jul 11 15:39:29 wangchen kernel: [<c023e105>] sys_socketcall+0x15c/0x19e Jul 11 15:39:29 wangchen kernel: [<c0103611>] sysenter_past_esp+0x6a/0x99 Jul 11 15:39:29 wangchen kernel: [<c0290000>] unix_poll+0x69/0x78 Jul 11 15:39:29 wangchen kernel: ======================= Jul 11 15:39:29 wangchen kernel: Code: 83 e0 01 00 00 85 c0 75 1f 53 53 68 12 81 31 c0 e8 3c 30 ed ff ba 3f 0e 00 00 b8 b9 7f 31 c0 83 c4 0c 5b e9 f5 26 ed ff 48 74 04 <0f> 0b eb fe 89 d8 e8 21 ff ff ff 89 d8 e8 62 ea ff ff c7 83 e0 Jul 11 15:39:29 wangchen kernel: EIP: [<c024636b>] rollback_registered+0x61/0xe3 SS:ESP 0068:ed8e7c3c Jul 11 15:39:29 wangchen kernel: ---[ end trace c311acf85d169786 ]--- === Signed-off-by: Wang Chen <wangchen@cn.fujitsu.com> Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'net/ipv4/ipmr.c')
-rw-r--r--net/ipv4/ipmr.c22
1 files changed, 14 insertions, 8 deletions
diff --git a/net/ipv4/ipmr.c b/net/ipv4/ipmr.c
index 2f4d8afd067c..c9ab47b966b5 100644
--- a/net/ipv4/ipmr.c
+++ b/net/ipv4/ipmr.c
@@ -184,6 +184,7 @@ struct net_device *ipmr_new_tunnel(struct vifctl *v)
184 184
185 if (dev_open(dev)) 185 if (dev_open(dev))
186 goto failure; 186 goto failure;
187 dev_hold(dev);
187 } 188 }
188 } 189 }
189 return dev; 190 return dev;
@@ -250,6 +251,8 @@ static struct net_device *ipmr_reg_vif(void)
250 if (dev_open(dev)) 251 if (dev_open(dev))
251 goto failure; 252 goto failure;
252 253
254 dev_hold(dev);
255
253 return dev; 256 return dev;
254 257
255failure: 258failure:
@@ -264,9 +267,10 @@ failure:
264 267
265/* 268/*
266 * Delete a VIF entry 269 * Delete a VIF entry
270 * @notify: Set to 1, if the caller is a notifier_call
267 */ 271 */
268 272
269static int vif_delete(int vifi) 273static int vif_delete(int vifi, int notify)
270{ 274{
271 struct vif_device *v; 275 struct vif_device *v;
272 struct net_device *dev; 276 struct net_device *dev;
@@ -309,7 +313,7 @@ static int vif_delete(int vifi)
309 ip_rt_multicast_event(in_dev); 313 ip_rt_multicast_event(in_dev);
310 } 314 }
311 315
312 if (v->flags&(VIFF_TUNNEL|VIFF_REGISTER)) 316 if (v->flags&(VIFF_TUNNEL|VIFF_REGISTER) && !notify)
313 unregister_netdevice(dev); 317 unregister_netdevice(dev);
314 318
315 dev_put(dev); 319 dev_put(dev);
@@ -435,6 +439,7 @@ static int vif_add(struct vifctl *vifc, int mrtsock)
435 err = dev_set_allmulti(dev, 1); 439 err = dev_set_allmulti(dev, 1);
436 if (err) { 440 if (err) {
437 unregister_netdevice(dev); 441 unregister_netdevice(dev);
442 dev_put(dev);
438 return err; 443 return err;
439 } 444 }
440 break; 445 break;
@@ -446,6 +451,7 @@ static int vif_add(struct vifctl *vifc, int mrtsock)
446 err = dev_set_allmulti(dev, 1); 451 err = dev_set_allmulti(dev, 1);
447 if (err) { 452 if (err) {
448 ipmr_del_tunnel(dev, vifc); 453 ipmr_del_tunnel(dev, vifc);
454 dev_put(dev);
449 return err; 455 return err;
450 } 456 }
451 break; 457 break;
@@ -453,10 +459,11 @@ static int vif_add(struct vifctl *vifc, int mrtsock)
453 dev = ip_dev_find(&init_net, vifc->vifc_lcl_addr.s_addr); 459 dev = ip_dev_find(&init_net, vifc->vifc_lcl_addr.s_addr);
454 if (!dev) 460 if (!dev)
455 return -EADDRNOTAVAIL; 461 return -EADDRNOTAVAIL;
456 dev_put(dev);
457 err = dev_set_allmulti(dev, 1); 462 err = dev_set_allmulti(dev, 1);
458 if (err) 463 if (err) {
464 dev_put(dev);
459 return err; 465 return err;
466 }
460 break; 467 break;
461 default: 468 default:
462 return -EINVAL; 469 return -EINVAL;
@@ -487,7 +494,6 @@ static int vif_add(struct vifctl *vifc, int mrtsock)
487 494
488 /* And finish update writing critical data */ 495 /* And finish update writing critical data */
489 write_lock_bh(&mrt_lock); 496 write_lock_bh(&mrt_lock);
490 dev_hold(dev);
491 v->dev=dev; 497 v->dev=dev;
492#ifdef CONFIG_IP_PIMSM 498#ifdef CONFIG_IP_PIMSM
493 if (v->flags&VIFF_REGISTER) 499 if (v->flags&VIFF_REGISTER)
@@ -834,7 +840,7 @@ static void mroute_clean_tables(struct sock *sk)
834 */ 840 */
835 for (i=0; i<maxvif; i++) { 841 for (i=0; i<maxvif; i++) {
836 if (!(vif_table[i].flags&VIFF_STATIC)) 842 if (!(vif_table[i].flags&VIFF_STATIC))
837 vif_delete(i); 843 vif_delete(i, 0);
838 } 844 }
839 845
840 /* 846 /*
@@ -947,7 +953,7 @@ int ip_mroute_setsockopt(struct sock *sk,int optname,char __user *optval,int opt
947 if (optname==MRT_ADD_VIF) { 953 if (optname==MRT_ADD_VIF) {
948 ret = vif_add(&vif, sk==mroute_socket); 954 ret = vif_add(&vif, sk==mroute_socket);
949 } else { 955 } else {
950 ret = vif_delete(vif.vifc_vifi); 956 ret = vif_delete(vif.vifc_vifi, 0);
951 } 957 }
952 rtnl_unlock(); 958 rtnl_unlock();
953 return ret; 959 return ret;
@@ -1126,7 +1132,7 @@ static int ipmr_device_event(struct notifier_block *this, unsigned long event, v
1126 v=&vif_table[0]; 1132 v=&vif_table[0];
1127 for (ct=0;ct<maxvif;ct++,v++) { 1133 for (ct=0;ct<maxvif;ct++,v++) {
1128 if (v->dev==dev) 1134 if (v->dev==dev)
1129 vif_delete(ct); 1135 vif_delete(ct, 1);
1130 } 1136 }
1131 return NOTIFY_DONE; 1137 return NOTIFY_DONE;
1132} 1138}