===== net/core/neighbour.c 1.47 vs edited ===== --- 1.47/net/core/neighbour.c 2004-09-24 16:21:49 -07:00 +++ edited/net/core/neighbour.c 2004-09-25 01:11:47 -07:00 @@ -110,13 +110,13 @@ return (net_random() % base) + (base >> 1); } - -static int neigh_forced_gc(struct neigh_table *tbl) +static int neigh_forced_gc(struct neigh_table *tbl, int goal) { - int shrunk = 0; + int shrunk = 0, num_incomplete = 0, reap_incomplete = 0; int i; write_lock_bh(&tbl->lock); +rescan: for (i = 0; i <= tbl->hash_mask; i++) { struct neighbour *n, **np; @@ -125,30 +125,46 @@ /* Neighbour record may be discarded if: - nobody refers to it. - it is not permanent - - (NEW and probably wrong) + - On the first pass of this scan, INCOMPLETE entries are kept at least for n->parms->retrans_time, otherwise we could flood network with resolution requests. - It is not clear, what is better table overflow - or flooding. */ write_lock(&n->lock); - if (atomic_read(&n->refcnt) == 1 && - !(n->nud_state & NUD_PERMANENT) && - (n->nud_state != NUD_INCOMPLETE || - time_after(jiffies, n->used + n->parms->retrans_time))) { - *np = n->next; - n->dead = 1; - shrunk = 1; - write_unlock(&n->lock); - neigh_release(n); - continue; + if (atomic_read(&n->refcnt) != 1) + goto next_ent; + + if (n->nud_state & NUD_PERMANENT) + goto next_ent; + + if (n->nud_state == NUD_INCOMPLETE && + reap_incomplete == 0 && + time_after(jiffies, + n->used + n->parms->retrans_time)) { + num_incomplete++; + goto next_ent; } + + *np = n->next; + n->dead = 1; + shrunk++; + write_unlock(&n->lock); + neigh_release(n); + continue; + + next_ent: write_unlock(&n->lock); np = &n->next; } } + if (reap_incomplete == 0 && + shrunk < goal && + (shrunk + num_incomplete) >= goal) { + reap_incomplete = 1; + goto rescan; + } + tbl->last_flush = jiffies; write_unlock_bh(&tbl->lock); @@ -261,7 +277,9 @@ if (tbl->entries > tbl->gc_thresh3 || (tbl->entries > tbl->gc_thresh2 && time_after(now, tbl->last_flush + 5 * HZ))) { - if (!neigh_forced_gc(tbl) && + int goal = tbl->entries - tbl->gc_thresh3; + + if (!neigh_forced_gc(tbl, goal) && tbl->entries > tbl->gc_thresh3) goto out; }