aboutsummaryrefslogtreecommitdiffstats
path: root/net/atm
diff options
context:
space:
mode:
authorStephen Hemminger <shemminger@osdl.org>2006-04-14 18:07:27 -0400
committerDavid S. Miller <davem@davemloft.net>2006-04-14 18:07:27 -0400
commitf3a0592b37b83e56a7f47826f552b35a2c3b2fc9 (patch)
tree8bdb6f8da73f6c2221067ac5630f57dc7f04efad /net/atm
parentb8a99520f78e23e47f9efffeb0060c1385064ff6 (diff)
[ATM]: clip causes unregister hang
If Classical IP over ATM module is loaded, its neighbor table gets populated when permanent neighbor entries are created; but these entries are not flushed when the device is removed. Since the entry never gets flushed the unregister of the network device never completes. This version of the patch also adds locking around the reference to the atm arp daemon to avoid races with events and daemon state changes. (Note: barrier() was never really safe) Bug-reference: http://bugzilla.kernel.org/show_bug.cgi?id=6295 Signed-off-by: Stephen Hemminger <shemminger@osdl.org> Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'net/atm')
-rw-r--r--net/atm/clip.c42
1 files changed, 27 insertions, 15 deletions
diff --git a/net/atm/clip.c b/net/atm/clip.c
index 3ab4e7947bab..5841c30384a4 100644
--- a/net/atm/clip.c
+++ b/net/atm/clip.c
@@ -613,12 +613,19 @@ static int clip_create(int number)
613 613
614 614
615static int clip_device_event(struct notifier_block *this,unsigned long event, 615static int clip_device_event(struct notifier_block *this,unsigned long event,
616 void *dev) 616 void *arg)
617{ 617{
618 struct net_device *dev = arg;
619
620 if (event == NETDEV_UNREGISTER) {
621 neigh_ifdown(&clip_tbl, dev);
622 return NOTIFY_DONE;
623 }
624
618 /* ignore non-CLIP devices */ 625 /* ignore non-CLIP devices */
619 if (((struct net_device *) dev)->type != ARPHRD_ATM || 626 if (dev->type != ARPHRD_ATM || dev->hard_start_xmit != clip_start_xmit)
620 ((struct net_device *) dev)->hard_start_xmit != clip_start_xmit)
621 return NOTIFY_DONE; 627 return NOTIFY_DONE;
628
622 switch (event) { 629 switch (event) {
623 case NETDEV_UP: 630 case NETDEV_UP:
624 DPRINTK("clip_device_event NETDEV_UP\n"); 631 DPRINTK("clip_device_event NETDEV_UP\n");
@@ -686,14 +693,12 @@ static struct notifier_block clip_inet_notifier = {
686static void atmarpd_close(struct atm_vcc *vcc) 693static void atmarpd_close(struct atm_vcc *vcc)
687{ 694{
688 DPRINTK("atmarpd_close\n"); 695 DPRINTK("atmarpd_close\n");
689 atmarpd = NULL; /* assumed to be atomic */ 696
690 barrier(); 697 rtnl_lock();
691 unregister_inetaddr_notifier(&clip_inet_notifier); 698 atmarpd = NULL;
692 unregister_netdevice_notifier(&clip_dev_notifier);
693 if (skb_peek(&sk_atm(vcc)->sk_receive_queue))
694 printk(KERN_ERR "atmarpd_close: closing with requests "
695 "pending\n");
696 skb_queue_purge(&sk_atm(vcc)->sk_receive_queue); 699 skb_queue_purge(&sk_atm(vcc)->sk_receive_queue);
700 rtnl_unlock();
701
697 DPRINTK("(done)\n"); 702 DPRINTK("(done)\n");
698 module_put(THIS_MODULE); 703 module_put(THIS_MODULE);
699} 704}
@@ -714,7 +719,12 @@ static struct atm_dev atmarpd_dev = {
714 719
715static int atm_init_atmarp(struct atm_vcc *vcc) 720static int atm_init_atmarp(struct atm_vcc *vcc)
716{ 721{
717 if (atmarpd) return -EADDRINUSE; 722 rtnl_lock();
723 if (atmarpd) {
724 rtnl_unlock();
725 return -EADDRINUSE;
726 }
727
718 if (start_timer) { 728 if (start_timer) {
719 start_timer = 0; 729 start_timer = 0;
720 init_timer(&idle_timer); 730 init_timer(&idle_timer);
@@ -731,10 +741,7 @@ static int atm_init_atmarp(struct atm_vcc *vcc)
731 vcc->push = NULL; 741 vcc->push = NULL;
732 vcc->pop = NULL; /* crash */ 742 vcc->pop = NULL; /* crash */
733 vcc->push_oam = NULL; /* crash */ 743 vcc->push_oam = NULL; /* crash */
734 if (register_netdevice_notifier(&clip_dev_notifier)) 744 rtnl_unlock();
735 printk(KERN_ERR "register_netdevice_notifier failed\n");
736 if (register_inetaddr_notifier(&clip_inet_notifier))
737 printk(KERN_ERR "register_inetaddr_notifier failed\n");
738 return 0; 745 return 0;
739} 746}
740 747
@@ -992,6 +999,8 @@ static int __init atm_clip_init(void)
992 999
993 clip_tbl_hook = &clip_tbl; 1000 clip_tbl_hook = &clip_tbl;
994 register_atm_ioctl(&clip_ioctl_ops); 1001 register_atm_ioctl(&clip_ioctl_ops);
1002 register_netdevice_notifier(&clip_dev_notifier);
1003 register_inetaddr_notifier(&clip_inet_notifier);
995 1004
996#ifdef CONFIG_PROC_FS 1005#ifdef CONFIG_PROC_FS
997{ 1006{
@@ -1012,6 +1021,9 @@ static void __exit atm_clip_exit(void)
1012 1021
1013 remove_proc_entry("arp", atm_proc_root); 1022 remove_proc_entry("arp", atm_proc_root);
1014 1023
1024 unregister_inetaddr_notifier(&clip_inet_notifier);
1025 unregister_netdevice_notifier(&clip_dev_notifier);
1026
1015 deregister_atm_ioctl(&clip_ioctl_ops); 1027 deregister_atm_ioctl(&clip_ioctl_ops);
1016 1028
1017 /* First, stop the idle timer, so it stops banging 1029 /* First, stop the idle timer, so it stops banging