diff options
Diffstat (limited to 'net/core/neighbour.c')
| -rw-r--r-- | net/core/neighbour.c | 18 | 
1 files changed, 15 insertions, 3 deletions
diff --git a/net/core/neighbour.c b/net/core/neighbour.c index f00a79fc301b..4edd2176e238 100644 --- a/net/core/neighbour.c +++ b/net/core/neighbour.c @@ -269,7 +269,7 @@ static int neigh_forced_gc(struct neigh_table *tbl)  			    (n->nud_state == NUD_NOARP) ||  			    (tbl->is_multicast &&  			     tbl->is_multicast(n->primary_key)) || -			    time_after(tref, n->updated)) +			    !time_in_range(n->updated, tref, jiffies))  				remove = true;  			write_unlock(&n->lock); @@ -289,7 +289,17 @@ static int neigh_forced_gc(struct neigh_table *tbl)  static void neigh_add_timer(struct neighbour *n, unsigned long when)  { +	/* Use safe distance from the jiffies - LONG_MAX point while timer +	 * is running in DELAY/PROBE state but still show to user space +	 * large times in the past. +	 */ +	unsigned long mint = jiffies - (LONG_MAX - 86400 * HZ); +  	neigh_hold(n); +	if (!time_in_range(n->confirmed, mint, jiffies)) +		n->confirmed = mint; +	if (time_before(n->used, n->confirmed)) +		n->used = n->confirmed;  	if (unlikely(mod_timer(&n->timer, when))) {  		printk("NEIGH: BUG, double timer add, state is %x\n",  		       n->nud_state); @@ -1001,12 +1011,14 @@ static void neigh_periodic_work(struct work_struct *work)  				goto next_elt;  			} -			if (time_before(n->used, n->confirmed)) +			if (time_before(n->used, n->confirmed) && +			    time_is_before_eq_jiffies(n->confirmed))  				n->used = n->confirmed;  			if (refcount_read(&n->refcnt) == 1 &&  			    (state == NUD_FAILED || -			     time_after(jiffies, n->used + NEIGH_VAR(n->parms, GC_STALETIME)))) { +			     !time_in_range_open(jiffies, n->used, +						 n->used + NEIGH_VAR(n->parms, GC_STALETIME)))) {  				*np = n->next;  				neigh_mark_dead(n);  				write_unlock(&n->lock);  | 
