Skip to content

Commit

Permalink
[ATM]: clip causes unregister hang
Browse files Browse the repository at this point in the history
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>
  • Loading branch information
Stephen Hemminger authored and David S. Miller committed Apr 14, 2006
1 parent b8a9952 commit f3a0592
Showing 1 changed file with 27 additions and 15 deletions.
42 changes: 27 additions & 15 deletions net/atm/clip.c
Original file line number Diff line number Diff line change
Expand Up @@ -613,12 +613,19 @@ static int clip_create(int number)


static int clip_device_event(struct notifier_block *this,unsigned long event,
void *dev)
void *arg)
{
struct net_device *dev = arg;

if (event == NETDEV_UNREGISTER) {
neigh_ifdown(&clip_tbl, dev);
return NOTIFY_DONE;
}

/* ignore non-CLIP devices */
if (((struct net_device *) dev)->type != ARPHRD_ATM ||
((struct net_device *) dev)->hard_start_xmit != clip_start_xmit)
if (dev->type != ARPHRD_ATM || dev->hard_start_xmit != clip_start_xmit)
return NOTIFY_DONE;

switch (event) {
case NETDEV_UP:
DPRINTK("clip_device_event NETDEV_UP\n");
Expand Down Expand Up @@ -686,14 +693,12 @@ static struct notifier_block clip_inet_notifier = {
static void atmarpd_close(struct atm_vcc *vcc)
{
DPRINTK("atmarpd_close\n");
atmarpd = NULL; /* assumed to be atomic */
barrier();
unregister_inetaddr_notifier(&clip_inet_notifier);
unregister_netdevice_notifier(&clip_dev_notifier);
if (skb_peek(&sk_atm(vcc)->sk_receive_queue))
printk(KERN_ERR "atmarpd_close: closing with requests "
"pending\n");

rtnl_lock();
atmarpd = NULL;
skb_queue_purge(&sk_atm(vcc)->sk_receive_queue);
rtnl_unlock();

DPRINTK("(done)\n");
module_put(THIS_MODULE);
}
Expand All @@ -714,7 +719,12 @@ static struct atm_dev atmarpd_dev = {

static int atm_init_atmarp(struct atm_vcc *vcc)
{
if (atmarpd) return -EADDRINUSE;
rtnl_lock();
if (atmarpd) {
rtnl_unlock();
return -EADDRINUSE;
}

if (start_timer) {
start_timer = 0;
init_timer(&idle_timer);
Expand All @@ -731,10 +741,7 @@ static int atm_init_atmarp(struct atm_vcc *vcc)
vcc->push = NULL;
vcc->pop = NULL; /* crash */
vcc->push_oam = NULL; /* crash */
if (register_netdevice_notifier(&clip_dev_notifier))
printk(KERN_ERR "register_netdevice_notifier failed\n");
if (register_inetaddr_notifier(&clip_inet_notifier))
printk(KERN_ERR "register_inetaddr_notifier failed\n");
rtnl_unlock();
return 0;
}

Expand Down Expand Up @@ -992,6 +999,8 @@ static int __init atm_clip_init(void)

clip_tbl_hook = &clip_tbl;
register_atm_ioctl(&clip_ioctl_ops);
register_netdevice_notifier(&clip_dev_notifier);
register_inetaddr_notifier(&clip_inet_notifier);

#ifdef CONFIG_PROC_FS
{
Expand All @@ -1012,6 +1021,9 @@ static void __exit atm_clip_exit(void)

remove_proc_entry("arp", atm_proc_root);

unregister_inetaddr_notifier(&clip_inet_notifier);
unregister_netdevice_notifier(&clip_dev_notifier);

deregister_atm_ioctl(&clip_ioctl_ops);

/* First, stop the idle timer, so it stops banging
Expand Down

0 comments on commit f3a0592

Please sign in to comment.