[NEIGH]: Add debugging check when adding timers.

If we double-add a neighbour entry timer, which should be
impossible but has been reported, dump the current state of
the entry so that we can debug this.

Signed-off-by: David S. Miller <davem@davemloft.net>
This commit is contained in:
David S. Miller 2005-09-27 12:07:44 -07:00
parent 56e9b26324
commit 667347f1ca

View File

@ -727,6 +727,13 @@ static __inline__ int neigh_max_probes(struct neighbour *n)
p->ucast_probes + p->app_probes + p->mcast_probes); p->ucast_probes + p->app_probes + p->mcast_probes);
} }
static inline void neigh_add_timer(struct neighbour *n, unsigned long when)
{
if (unlikely(mod_timer(&n->timer, when))) {
printk("NEIGH: BUG, double timer add, state is %x\n",
n->nud_state);
}
}
/* Called when a timer expires for a neighbour entry. */ /* Called when a timer expires for a neighbour entry. */
@ -811,8 +818,7 @@ static void neigh_timer_handler(unsigned long arg)
neigh_hold(neigh); neigh_hold(neigh);
if (time_before(next, jiffies + HZ/2)) if (time_before(next, jiffies + HZ/2))
next = jiffies + HZ/2; next = jiffies + HZ/2;
neigh->timer.expires = next; neigh_add_timer(neigh, next);
add_timer(&neigh->timer);
} }
if (neigh->nud_state & (NUD_INCOMPLETE | NUD_PROBE)) { if (neigh->nud_state & (NUD_INCOMPLETE | NUD_PROBE)) {
struct sk_buff *skb = skb_peek(&neigh->arp_queue); struct sk_buff *skb = skb_peek(&neigh->arp_queue);
@ -854,8 +860,7 @@ int __neigh_event_send(struct neighbour *neigh, struct sk_buff *skb)
atomic_set(&neigh->probes, neigh->parms->ucast_probes); atomic_set(&neigh->probes, neigh->parms->ucast_probes);
neigh->nud_state = NUD_INCOMPLETE; neigh->nud_state = NUD_INCOMPLETE;
neigh_hold(neigh); neigh_hold(neigh);
neigh->timer.expires = now + 1; neigh_add_timer(neigh, now + 1);
add_timer(&neigh->timer);
} else { } else {
neigh->nud_state = NUD_FAILED; neigh->nud_state = NUD_FAILED;
write_unlock_bh(&neigh->lock); write_unlock_bh(&neigh->lock);
@ -868,8 +873,8 @@ int __neigh_event_send(struct neighbour *neigh, struct sk_buff *skb)
NEIGH_PRINTK2("neigh %p is delayed.\n", neigh); NEIGH_PRINTK2("neigh %p is delayed.\n", neigh);
neigh_hold(neigh); neigh_hold(neigh);
neigh->nud_state = NUD_DELAY; neigh->nud_state = NUD_DELAY;
neigh->timer.expires = jiffies + neigh->parms->delay_probe_time; neigh_add_timer(neigh,
add_timer(&neigh->timer); jiffies + neigh->parms->delay_probe_time);
} }
if (neigh->nud_state == NUD_INCOMPLETE) { if (neigh->nud_state == NUD_INCOMPLETE) {
@ -1015,10 +1020,10 @@ int neigh_update(struct neighbour *neigh, const u8 *lladdr, u8 new,
neigh_del_timer(neigh); neigh_del_timer(neigh);
if (new & NUD_IN_TIMER) { if (new & NUD_IN_TIMER) {
neigh_hold(neigh); neigh_hold(neigh);
neigh->timer.expires = jiffies + neigh_add_timer(neigh, (jiffies +
((new & NUD_REACHABLE) ? ((new & NUD_REACHABLE) ?
neigh->parms->reachable_time : 0); neigh->parms->reachable_time :
add_timer(&neigh->timer); 0)));
} }
neigh->nud_state = new; neigh->nud_state = new;
} }