diff options
author | Ralf Baechle <ralf@linux-mips.org> | 1999-10-09 00:00:47 +0000 |
---|---|---|
committer | Ralf Baechle <ralf@linux-mips.org> | 1999-10-09 00:00:47 +0000 |
commit | d6434e1042f3b0a6dfe1b1f615af369486f9b1fa (patch) | |
tree | e2be02f33984c48ec019c654051d27964e42c441 /net/ipv6/ip6_fib.c | |
parent | 609d1e803baf519487233b765eb487f9ec227a18 (diff) |
Merge with 2.3.19.
Diffstat (limited to 'net/ipv6/ip6_fib.c')
-rw-r--r-- | net/ipv6/ip6_fib.c | 82 |
1 files changed, 50 insertions, 32 deletions
diff --git a/net/ipv6/ip6_fib.c b/net/ipv6/ip6_fib.c index d20925c95..099953e53 100644 --- a/net/ipv6/ip6_fib.c +++ b/net/ipv6/ip6_fib.c @@ -5,7 +5,7 @@ * Authors: * Pedro Roque <roque@di.fc.ul.pt> * - * $Id: ip6_fib.c,v 1.17 1999/04/22 10:07:41 davem Exp $ + * $Id: ip6_fib.c,v 1.19 1999/08/31 07:04:00 davem Exp $ * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License @@ -20,6 +20,7 @@ #include <linux/route.h> #include <linux/netdevice.h> #include <linux/in6.h> +#include <linux/init.h> #ifdef CONFIG_PROC_FS #include <linux/proc_fs.h> @@ -35,12 +36,6 @@ #define RT6_DEBUG 2 #undef CONFIG_IPV6_SUBTREES -#if RT6_DEBUG >= 1 -#define BUG_TRAP(x) ({ if (!(x)) { printk("Assertion (" #x ") failed at " __FILE__ "(%d):" __FUNCTION__ "\n", __LINE__); } }) -#else -#define BUG_TRAP(x) do { ; } while (0) -#endif - #if RT6_DEBUG >= 3 #define RT6_TRACE(x...) printk(KERN_DEBUG x) #else @@ -49,6 +44,8 @@ struct rt6_statistics rt6_stats; +static kmem_cache_t * fib6_node_kmem; + enum fib_walk_state_t { #ifdef CONFIG_IPV6_SUBTREES @@ -67,6 +64,9 @@ struct fib6_cleaner_t void *arg; }; +rwlock_t fib6_walker_lock = RW_LOCK_UNLOCKED; + + #ifdef CONFIG_IPV6_SUBTREES #define FWS_INIT FWS_S #define SUBTREE(fn) ((fn)->subtree) @@ -210,18 +210,15 @@ static __inline__ struct fib6_node * node_alloc(void) { struct fib6_node *fn; - if ((fn = kmalloc(sizeof(struct fib6_node), GFP_ATOMIC)) != NULL) { + if ((fn = kmem_cache_alloc(fib6_node_kmem, SLAB_ATOMIC)) != NULL) memset(fn, 0, sizeof(struct fib6_node)); - rt6_stats.fib_nodes++; - } return fn; } static __inline__ void node_free(struct fib6_node * fn) { - rt6_stats.fib_nodes--; - kfree(fn); + kmem_cache_free(fib6_node_kmem, fn); } static __inline__ void rt6_release(struct rt6_info *rt) @@ -297,7 +294,7 @@ static struct fib6_node * fib6_add_1(struct fib6_node *root, void *addr, } while (fn); /* - * We wlaked to the bottom of tree. + * We walked to the bottom of tree. * Create new leaf node without children. */ @@ -490,11 +487,8 @@ static int fib6_add_rt2node(struct fib6_node *fn, struct rt6_info *rt) static __inline__ void fib6_start_gc(struct rt6_info *rt) { if (ip6_fib_timer.expires == 0 && - (rt->rt6i_flags & (RTF_EXPIRES|RTF_CACHE))) { - del_timer(&ip6_fib_timer); - ip6_fib_timer.expires = jiffies + ip6_rt_gc_interval; - add_timer(&ip6_fib_timer); - } + (rt->rt6i_flags & (RTF_EXPIRES|RTF_CACHE))) + mod_timer(&ip6_fib_timer, jiffies + ip6_rt_gc_interval); } /* @@ -512,7 +506,7 @@ int fib6_add(struct fib6_node *root, struct rt6_info *rt) rt->rt6i_dst.plen, (u8*) &rt->rt6i_dst - (u8*) rt); if (fn == NULL) - return -ENOMEM; + goto out; #ifdef CONFIG_IPV6_SUBTREES if (rt->rt6i_src.plen) { @@ -584,6 +578,7 @@ int fib6_add(struct fib6_node *root, struct rt6_info *rt) fib6_prune_clones(fn, rt); } +out: if (err) dst_free(&rt->u.dst); return err; @@ -845,6 +840,7 @@ static void fib6_repair_tree(struct fib6_node *fn) } #endif + read_lock(&fib6_walker_lock); FOR_WALKERS(w) { if (child == NULL) { if (w->root == fn) { @@ -872,6 +868,7 @@ static void fib6_repair_tree(struct fib6_node *fn) } } } + read_unlock(&fib6_walker_lock); node_free(fn); if (pn->fn_flags&RTN_RTINFO || SUBTREE(pn)) @@ -896,6 +893,7 @@ static void fib6_del_route(struct fib6_node *fn, struct rt6_info **rtp) rt6_stats.fib_rt_entries--; /* Adjust walkers */ + read_lock(&fib6_walker_lock); FOR_WALKERS(w) { if (w->state == FWS_C && w->leaf == rt) { RT6_TRACE("walker %p adjusted by delroute\n", w); @@ -904,6 +902,7 @@ static void fib6_del_route(struct fib6_node *fn, struct rt6_info **rtp) w->state = FWS_U; } } + read_unlock(&fib6_walker_lock); rt->u.next = NULL; @@ -927,7 +926,7 @@ int fib6_del(struct rt6_info *rt) #if RT6_DEBUG >= 2 if (rt->u.dst.obsolete>0) { - BUG_TRAP(rt->u.dst.obsolete>0); + BUG_TRAP(rt->u.dst.obsolete<=0); return -EFAULT; } #endif @@ -1112,9 +1111,7 @@ void fib6_clean_tree(struct fib6_node *root, c.func = func; c.arg = arg; - start_bh_atomic(); fib6_walk(&c.w); - end_bh_atomic(); } static int fib6_prune_clone(struct rt6_info *rt, void *arg) @@ -1151,7 +1148,7 @@ static int fib6_age(struct rt6_info *rt, void *arg) */ if (rt->rt6i_flags & RTF_CACHE) { - if (atomic_read(&rt->u.dst.use) == 0 && + if (atomic_read(&rt->u.dst.__refcnt) == 0 && (long)(now - rt->u.dst.lastuse) >= gc_args.timeout) { RT6_TRACE("aging clone %p\n", rt); return -1; @@ -1175,24 +1172,45 @@ static int fib6_age(struct rt6_info *rt, void *arg) return 0; } +static spinlock_t fib6_gc_lock = SPIN_LOCK_UNLOCKED; + void fib6_run_gc(unsigned long dummy) { - if (dummy != ~0UL) + if (dummy != ~0UL) { + spin_lock_bh(&fib6_gc_lock); gc_args.timeout = (int)dummy; - else + } else { + local_bh_disable(); + if (!spin_trylock(&fib6_gc_lock)) { + mod_timer(&ip6_fib_timer, jiffies + HZ); + local_bh_enable(); + return; + } gc_args.timeout = ip6_rt_gc_interval; - + } gc_args.more = 0; - fib6_clean_tree(&ip6_routing_table, fib6_age, 0, NULL); - del_timer(&ip6_fib_timer); + write_lock_bh(&rt6_lock); + fib6_clean_tree(&ip6_routing_table, fib6_age, 0, NULL); + write_unlock_bh(&rt6_lock); - ip6_fib_timer.expires = 0; - if (gc_args.more) { - ip6_fib_timer.expires = jiffies + ip6_rt_gc_interval; - add_timer(&ip6_fib_timer); + if (gc_args.more) + mod_timer(&ip6_fib_timer, jiffies + ip6_rt_gc_interval); + else { + del_timer(&ip6_fib_timer); + ip6_fib_timer.expires = 0; } + spin_unlock_bh(&fib6_gc_lock); +} + +void __init fib6_init(void) +{ + if (!fib6_node_kmem) + fib6_node_kmem = kmem_cache_create("fib6_nodes", + sizeof(struct fib6_node), + 0, SLAB_HWCACHE_ALIGN, + NULL, NULL); } #ifdef MODULE |