Ben Greear wrote:
I added a separate flag to keep track of whether a neighbour struct
is on the timer list or not.  I also added some logic to dump the
stack if the add-timer method was called while we are already on
the timer list.

A cleaned up patch against 2.6.13 is attached.  This (also)
seems to fix the problem with removing net-devices.  Hopefully
with fewer side affects than the last kludge.

In case it passes review:

Signed-off-by  Ben Greear <[EMAIL PROTECTED]>

--
Ben Greear <[EMAIL PROTECTED]>
Candela Technologies Inc  http://www.candelatech.com

diff --git a/include/net/neighbour.h b/include/net/neighbour.h
--- a/include/net/neighbour.h
+++ b/include/net/neighbour.h
@@ -1,3 +1,4 @@
+/* -*- linux-c -*- */
 #ifndef _NET_NEIGHBOUR_H
 #define _NET_NEIGHBOUR_H
 
@@ -138,6 +139,7 @@ struct neighbour
 	int			(*output)(struct sk_buff *skb);
 	struct sk_buff_head	arp_queue;
 	struct timer_list	timer;
+	u32                     in_timer; /* boolean, space for more flags as needed. */
 	struct neigh_ops	*ops;
 	u8			primary_key[0];
 };
diff --git a/net/core/neighbour.c b/net/core/neighbour.c
--- a/net/core/neighbour.c
+++ b/net/core/neighbour.c
@@ -1,4 +1,4 @@
-/*
+/* -*- linux-c -*-
  *	Generic address resolution entity
  *
  *	Authors:
@@ -153,11 +153,34 @@ static int neigh_forced_gc(struct neigh_
 	return shrunk;
 }
 
-static int neigh_del_timer(struct neighbour *n)
-{
-	if ((n->nud_state & NUD_IN_TIMER) &&
-	    del_timer(&n->timer)) {
-		neigh_release(n);
+static int neigh_del_timer(struct neighbour *n) {
+	if (n->in_timer) {
+		if (!n->nud_state & NUD_IN_TIMER) {
+			printk("ERROR:  in_timer true, but NUD_IN_TIMER false, neigh: %p\n", n);
+			/* dump_stack(); */
+		}
+		if (del_timer(&n->timer)) {
+			n->in_timer = 0;
+			neigh_release(n);
+			return 1;
+		}
+	}
+	return 0;
+}
+
+static int neigh_add_timer(struct neighbour *n, u32 expires) {
+	if (n->in_timer) {
+		/* This hits fairly often, not too sure why/how.  */
+		/* TODO:  Maybe should remove existing timer if it expires
+		 * later than this one and then insert the new timer? --Ben*/
+		NEIGH_PRINTK2("ERROR:  trying to add timer, but already there, neigh: %p\n", n);
+		/* dump_stack(); */
+	}
+	else {
+		n->timer.expires = expires;
+		neigh_hold(n);
+		add_timer(&n->timer);
+		n->in_timer = 1;
 		return 1;
 	}
 	return 0;
@@ -737,6 +760,9 @@ static void neigh_timer_handler(unsigned
 
 	write_lock(&neigh->lock);
 
+	/* We are out of the timer list at this point. */
+	neigh->in_timer = 0;
+
 	state = neigh->nud_state;
 	now = jiffies;
 	next = now + HZ;
@@ -806,11 +832,9 @@ static void neigh_timer_handler(unsigned
 	}
 
 	if (neigh->nud_state & NUD_IN_TIMER) {
-		neigh_hold(neigh);
 		if (time_before(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)) {
 		struct sk_buff *skb = skb_peek(&neigh->arp_queue);
@@ -851,9 +875,7 @@ int __neigh_event_send(struct neighbour 
 		if (neigh->parms->mcast_probes + neigh->parms->app_probes) {
 			atomic_set(&neigh->probes, neigh->parms->ucast_probes);
 			neigh->nud_state     = NUD_INCOMPLETE;
-			neigh_hold(neigh);
-			neigh->timer.expires = now + 1;
-			add_timer(&neigh->timer);
+			neigh_add_timer(neigh, now + 1);
 		} else {
 			neigh->nud_state = NUD_FAILED;
 			write_unlock_bh(&neigh->lock);
@@ -864,10 +886,8 @@ int __neigh_event_send(struct neighbour 
 		}
 	} else if (neigh->nud_state & NUD_STALE) {
 		NEIGH_PRINTK2("neigh %p is delayed.\n", neigh);
-		neigh_hold(neigh);
 		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) {
@@ -1012,11 +1032,9 @@ int neigh_update(struct neighbour *neigh
 	if (new != old) {
 		neigh_del_timer(neigh);
 		if (new & NUD_IN_TIMER) {
-			neigh_hold(neigh);
-			neigh->timer.expires = jiffies + 
+			neigh_add_timer(neigh, jiffies + 
 						((new & NUD_REACHABLE) ? 
-						 neigh->parms->reachable_time : 0);
-			add_timer(&neigh->timer);
+						 neigh->parms->reachable_time : 0));
 		}
 		neigh->nud_state = new;
 	}

Reply via email to