X-Git-Url: http://git.onelab.eu/?a=blobdiff_plain;f=net%2Fipv4%2Ffib_hash.c;h=c9b54bbea314acacdf1d5fae4644a7576a689528;hb=43bc926fffd92024b46cafaf7350d669ba9ca884;hp=4cbbdf8cbbeeb61ff52ac2c995ffc4f1c3d373c6;hpb=6a77f38946aaee1cd85eeec6cf4229b204c15071;p=linux-2.6.git diff --git a/net/ipv4/fib_hash.c b/net/ipv4/fib_hash.c index 4cbbdf8cb..c9b54bbea 100644 --- a/net/ipv4/fib_hash.c +++ b/net/ipv4/fib_hash.c @@ -29,6 +29,7 @@ #include #include #include +#include #include #include #include @@ -45,8 +46,8 @@ #include "fib_lookup.h" -static kmem_cache_t *fn_hash_kmem; -static kmem_cache_t *fn_alias_kmem; +static kmem_cache_t *fn_hash_kmem __read_mostly; +static kmem_cache_t *fn_alias_kmem __read_mostly; struct fib_node { struct hlist_node fn_hash; @@ -93,6 +94,7 @@ static inline u32 fz_key(u32 dst, struct fn_zone *fz) } static DEFINE_RWLOCK(fib_hash_lock); +static unsigned int fib_hash_genid; #define FZ_MAX_DIVISOR ((PAGE_SIZE<fz_hashmask = new_hashmask; fz->fz_divisor = new_divisor; fn_rebuild_zone(fz, old_ht, old_divisor); + fib_hash_genid++; write_unlock_bh(&fib_hash_lock); fz_hash_free(old_ht, old_divisor); @@ -236,6 +239,7 @@ fn_new_zone(struct fn_hash *table, int z) table->fn_zones[i]->fz_next = fz; } table->fn_zones[z] = fz; + fib_hash_genid++; write_unlock_bh(&fib_hash_lock); return fz; } @@ -261,6 +265,7 @@ fn_hash_lookup(struct fib_table *tb, const struct flowi *flp, struct fib_result err = fib_semantic_match(&f->fn_alias, flp, res, + f->fn_key, fz->fz_mask, fz->fz_order); if (err <= 0) goto out; @@ -451,6 +456,7 @@ fn_hash_insert(struct fib_table *tb, struct rtmsg *r, struct kern_rta *rta, fa->fa_scope = r->rtm_scope; state = fa->fa_state; fa->fa_state &= ~FA_S_ACCESSED; + fib_hash_genid++; write_unlock_bh(&fib_hash_lock); fib_release_info(fi_drop); @@ -515,6 +521,7 @@ fn_hash_insert(struct fib_table *tb, struct rtmsg *r, struct kern_rta *rta, fib_insert_node(fz, new_f); list_add_tail(&new_fa->fa_list, (fa ? &fa->fa_list : &f->fn_alias)); + fib_hash_genid++; write_unlock_bh(&fib_hash_lock); if (new_f) @@ -600,6 +607,7 @@ fn_hash_delete(struct fib_table *tb, struct rtmsg *r, struct kern_rta *rta, hlist_del(&f->fn_hash); kill_fn = 1; } + fib_hash_genid++; write_unlock_bh(&fib_hash_lock); if (fa->fa_state & FA_S_ACCESSED) @@ -637,6 +645,7 @@ static int fn_flush_list(struct fn_zone *fz, int idx) hlist_del(&f->fn_hash); kill_f = 1; } + fib_hash_genid++; write_unlock_bh(&fib_hash_lock); fn_free_alias(fa); @@ -695,7 +704,8 @@ fn_hash_dump_bucket(struct sk_buff *skb, struct netlink_callback *cb, &f->fn_key, fz->fz_order, fa->fa_tos, - fa->fa_info) < 0) { + fa->fa_info, + NLM_F_MULTI) < 0) { cb->args[3] = i; return -1; } @@ -801,6 +811,9 @@ struct fib_iter_state { struct hlist_head *hash_head; struct fib_node *fn; struct fib_alias *fa; + loff_t pos; + unsigned int genid; + int valid; }; static struct fib_alias *fib_get_first(struct seq_file *seq) @@ -812,6 +825,9 @@ static struct fib_alias *fib_get_first(struct seq_file *seq) iter->hash_head = NULL; iter->fn = NULL; iter->fa = NULL; + iter->pos = 0; + iter->genid = fib_hash_genid; + iter->valid = 1; for (iter->zone = table->fn_zone_list; iter->zone; iter->zone = iter->zone->fz_next) { @@ -916,12 +932,20 @@ static struct fib_alias *fib_get_next(struct seq_file *seq) } } out: + iter->pos++; return fa; } static struct fib_alias *fib_get_idx(struct seq_file *seq, loff_t pos) { - struct fib_alias *fa = fib_get_first(seq); + struct fib_iter_state *iter = seq->private; + struct fib_alias *fa; + + if (iter->valid && pos >= iter->pos && iter->genid == fib_hash_genid) { + fa = iter->fa; + pos -= iter->pos; + } else + fa = fib_get_first(seq); if (fa) while (pos && (fa = fib_get_next(seq))) @@ -952,7 +976,7 @@ static void fib_seq_stop(struct seq_file *seq, void *v) static unsigned fib_flag_trans(int type, u32 mask, struct fib_info *fi) { - static unsigned type2flags[RTN_MAX + 1] = { + static const unsigned type2flags[RTN_MAX + 1] = { [7] = RTF_REJECT, [8] = RTF_REJECT, }; unsigned flags = type2flags[type];