Commit bfa84030 authored by Herbert Xu's avatar Herbert Xu Committed by David S. Miller

[NET]: Neighbour table entries counter needs to be atomic_t

It is updated outside of locks, so...
Signed-off-by: default avatarHerbert Xu <herbert@gondor.apana.org.au>
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parent c888100b
...@@ -189,7 +189,7 @@ struct neigh_table ...@@ -189,7 +189,7 @@ struct neigh_table
struct timer_list gc_timer; struct timer_list gc_timer;
struct timer_list proxy_timer; struct timer_list proxy_timer;
struct sk_buff_head proxy_queue; struct sk_buff_head proxy_queue;
int entries; atomic_t entries;
rwlock_t lock; rwlock_t lock;
unsigned long last_rand; unsigned long last_rand;
struct neigh_parms *parms_list; struct neigh_parms *parms_list;
......
...@@ -254,18 +254,20 @@ static struct neighbour *neigh_alloc(struct neigh_table *tbl) ...@@ -254,18 +254,20 @@ static struct neighbour *neigh_alloc(struct neigh_table *tbl)
{ {
struct neighbour *n = NULL; struct neighbour *n = NULL;
unsigned long now = jiffies; unsigned long now = jiffies;
int entries;
if (tbl->entries > tbl->gc_thresh3 || entries = atomic_inc_return(&tbl->entries) - 1;
(tbl->entries > tbl->gc_thresh2 && if (entries >= tbl->gc_thresh3 ||
(entries >= tbl->gc_thresh2 &&
time_after(now, tbl->last_flush + 5 * HZ))) { time_after(now, tbl->last_flush + 5 * HZ))) {
if (!neigh_forced_gc(tbl) && if (!neigh_forced_gc(tbl) &&
tbl->entries > tbl->gc_thresh3) entries >= tbl->gc_thresh3)
goto out; goto out_entries;
} }
n = kmem_cache_alloc(tbl->kmem_cachep, SLAB_ATOMIC); n = kmem_cache_alloc(tbl->kmem_cachep, SLAB_ATOMIC);
if (!n) if (!n)
goto out; goto out_entries;
memset(n, 0, tbl->entry_size); memset(n, 0, tbl->entry_size);
...@@ -281,12 +283,15 @@ static struct neighbour *neigh_alloc(struct neigh_table *tbl) ...@@ -281,12 +283,15 @@ static struct neighbour *neigh_alloc(struct neigh_table *tbl)
NEIGH_CACHE_STAT_INC(tbl, allocs); NEIGH_CACHE_STAT_INC(tbl, allocs);
neigh_glbl_allocs++; neigh_glbl_allocs++;
tbl->entries++;
n->tbl = tbl; n->tbl = tbl;
atomic_set(&n->refcnt, 1); atomic_set(&n->refcnt, 1);
n->dead = 1; n->dead = 1;
out: out:
return n; return n;
out_entries:
atomic_dec(&tbl->entries);
goto out;
} }
static struct neighbour **neigh_hash_alloc(unsigned int entries) static struct neighbour **neigh_hash_alloc(unsigned int entries)
...@@ -427,7 +432,7 @@ struct neighbour *neigh_create(struct neigh_table *tbl, const void *pkey, ...@@ -427,7 +432,7 @@ struct neighbour *neigh_create(struct neigh_table *tbl, const void *pkey,
write_lock_bh(&tbl->lock); write_lock_bh(&tbl->lock);
if (tbl->entries > (tbl->hash_mask + 1)) if (atomic_read(&tbl->entries) > (tbl->hash_mask + 1))
neigh_hash_grow(tbl, (tbl->hash_mask + 1) << 1); neigh_hash_grow(tbl, (tbl->hash_mask + 1) << 1);
hash_val = tbl->hash(pkey, dev) & tbl->hash_mask; hash_val = tbl->hash(pkey, dev) & tbl->hash_mask;
...@@ -608,7 +613,7 @@ void neigh_destroy(struct neighbour *neigh) ...@@ -608,7 +613,7 @@ void neigh_destroy(struct neighbour *neigh)
NEIGH_PRINTK2("neigh %p is destroyed.\n", neigh); NEIGH_PRINTK2("neigh %p is destroyed.\n", neigh);
neigh_glbl_allocs--; neigh_glbl_allocs--;
neigh->tbl->entries--; atomic_dec(&neigh->tbl->entries);
kmem_cache_free(neigh->tbl->kmem_cachep, neigh); kmem_cache_free(neigh->tbl->kmem_cachep, neigh);
} }
...@@ -1394,7 +1399,7 @@ int neigh_table_clear(struct neigh_table *tbl) ...@@ -1394,7 +1399,7 @@ int neigh_table_clear(struct neigh_table *tbl)
del_timer_sync(&tbl->proxy_timer); del_timer_sync(&tbl->proxy_timer);
pneigh_queue_purge(&tbl->proxy_queue); pneigh_queue_purge(&tbl->proxy_queue);
neigh_ifdown(tbl, NULL); neigh_ifdown(tbl, NULL);
if (tbl->entries) if (atomic_read(&tbl->entries))
printk(KERN_CRIT "neighbour leakage\n"); printk(KERN_CRIT "neighbour leakage\n");
write_lock(&neigh_tbl_lock); write_lock(&neigh_tbl_lock);
for (tp = &neigh_tables; *tp; tp = &(*tp)->next) { for (tp = &neigh_tables; *tp; tp = &(*tp)->next) {
...@@ -1951,7 +1956,7 @@ static int neigh_stat_seq_show(struct seq_file *seq, void *v) ...@@ -1951,7 +1956,7 @@ static int neigh_stat_seq_show(struct seq_file *seq, void *v)
seq_printf(seq, "%08x %08lx %08lx %08lx %08lx %08lx %08lx " seq_printf(seq, "%08x %08lx %08lx %08lx %08lx %08lx %08lx "
"%08lx %08lx %08lx %08lx\n", "%08lx %08lx %08lx %08lx\n",
tbl->entries, atomic_read(&tbl->entries),
st->allocs, st->allocs,
st->destroys, st->destroys,
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment