diff options
Diffstat (limited to 'net/core/neighbour.c')
-rw-r--r-- | net/core/neighbour.c | 31 |
1 files changed, 25 insertions, 6 deletions
diff --git a/net/core/neighbour.c b/net/core/neighbour.c index d0bf8d13d..d97bdc5f2 100644 --- a/net/core/neighbour.c +++ b/net/core/neighbour.c @@ -209,10 +209,11 @@ int neigh_ifdown(struct neigh_table *tbl, struct net_device *dev) } } - del_timer(&tbl->proxy_timer); skb_queue_purge(&tbl->proxy_queue); pneigh_ifdown(tbl, dev); write_unlock_bh(&tbl->lock); + + del_timer_sync(&tbl->proxy_timer); return 0; } @@ -533,7 +534,7 @@ static void neigh_sync(struct neighbour *n) } } -static void neigh_periodic_timer(unsigned long arg) +static void SMP_TIMER_NAME(neigh_periodic_timer)(unsigned long arg) { struct neigh_table *tbl = (struct neigh_table*)arg; unsigned long now = jiffies; @@ -592,11 +593,21 @@ next_elt: } } - tbl->gc_timer.expires = now + tbl->gc_interval; - add_timer(&tbl->gc_timer); + mod_timer(&tbl->gc_timer, now + tbl->gc_interval); write_unlock(&tbl->lock); } +#ifdef __SMP__ +static void neigh_periodic_timer(unsigned long arg) +{ + struct neigh_table *tbl = (struct neigh_table*)arg; + + tasklet_schedule(&tbl->gc_task); + + timer_exit(&tbl->gc_timer); +} +#endif + static __inline__ int neigh_max_probes(struct neighbour *n) { struct neigh_parms *p = n->parms; @@ -665,6 +676,7 @@ static void neigh_timer_handler(unsigned long arg) neigh->ops->solicit(neigh, skb_peek(&neigh->arp_queue)); atomic_inc(&neigh->probes); + timer_exit(&neigh->timer); return; out: @@ -673,6 +685,7 @@ out: if (notify && neigh->parms->app_probes) neigh_app_notify(neigh); #endif + timer_exit(&neigh->timer); neigh_release(neigh); } @@ -1008,6 +1021,7 @@ static void neigh_proxy_process(unsigned long arg) tbl->proxy_timer.expires = jiffies + sched_next; add_timer(&tbl->proxy_timer); } + timer_exit(&tbl->proxy_timer); } void pneigh_enqueue(struct neigh_table *tbl, struct neigh_parms *p, @@ -1092,6 +1106,9 @@ void neigh_table_init(struct neigh_table *tbl) 0, SLAB_HWCACHE_ALIGN, NULL, NULL); +#ifdef __SMP__ + tasklet_init(&tbl->gc_task, SMP_TIMER_NAME(neigh_periodic_timer), (unsigned long)tbl); +#endif init_timer(&tbl->gc_timer); tbl->lock = RW_LOCK_UNLOCKED; tbl->gc_timer.data = (unsigned long)tbl; @@ -1116,8 +1133,10 @@ int neigh_table_clear(struct neigh_table *tbl) { struct neigh_table **tp; - del_timer(&tbl->gc_timer); - del_timer(&tbl->proxy_timer); + /* It is not clean... Fix it to unload IPv6 module safely */ + del_timer_sync(&tbl->gc_timer); + tasklet_kill(&tbl->gc_task); + del_timer_sync(&tbl->proxy_timer); skb_queue_purge(&tbl->proxy_queue); neigh_ifdown(tbl, NULL); if (tbl->entries) |