Browse Source

[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>
David S. Miller 19 years ago
parent
commit
667347f1ca
1 changed files with 14 additions and 9 deletions
  1. 14 9
      net/core/neighbour.c

+ 14 - 9
net/core/neighbour.c

@@ -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;
-		add_timer(&neigh->timer);
+		neigh_add_timer(neigh, next);
 	}
 	}
 	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;
-			add_timer(&neigh->timer);
+			neigh_add_timer(neigh, now + 1);
 		} 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;
-		add_timer(&neigh->timer);
+		neigh_add_timer(neigh,
+				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);
-			add_timer(&neigh->timer);
+						 neigh->parms->reachable_time :
+						 0)));
 		}
 		}
 		neigh->nud_state = new;
 		neigh->nud_state = new;
 	}
 	}