diff options
-rw-r--r-- | net/ipv4/route.c | 43 |
1 files changed, 29 insertions, 14 deletions
diff --git a/net/ipv4/route.c b/net/ipv4/route.c index d361dc0037c0..5706bc1b4f89 100644 --- a/net/ipv4/route.c +++ b/net/ipv4/route.c @@ -151,6 +151,9 @@ static void ipv4_link_failure(struct sk_buff *skb); static void ip_rt_update_pmtu(struct dst_entry *dst, u32 mtu); static int rt_garbage_collect(struct dst_ops *ops); +static void __rt_garbage_collect(struct work_struct *w); +static DECLARE_WORK(rt_gc_worker, __rt_garbage_collect); + static void ipv4_dst_ifdown(struct dst_entry *dst, struct net_device *dev, int how) { @@ -979,7 +982,7 @@ static void rt_emergency_hash_rebuild(struct net *net) and when load increases it reduces to limit cache size. */ -static int rt_garbage_collect(struct dst_ops *ops) +static void __do_rt_garbage_collect(int elasticity, int min_interval) { static unsigned long expire = RT_GC_TIMEOUT; static unsigned long last_gc; @@ -998,7 +1001,7 @@ static int rt_garbage_collect(struct dst_ops *ops) RT_CACHE_STAT_INC(gc_total); - if (now - last_gc < ip_rt_gc_min_interval && + if (now - last_gc < min_interval && entries < ip_rt_max_size) { RT_CACHE_STAT_INC(gc_ignored); goto out; @@ -1006,7 +1009,7 @@ static int rt_garbage_collect(struct dst_ops *ops) entries = dst_entries_get_slow(&ipv4_dst_ops); /* Calculate number of entries, which we want to expire now. */ - goal = entries - (ip_rt_gc_elasticity << rt_hash_log); + goal = entries - (elasticity << rt_hash_log); if (goal <= 0) { if (equilibrium < ipv4_dst_ops.gc_thresh) equilibrium = ipv4_dst_ops.gc_thresh; @@ -1023,7 +1026,7 @@ static int rt_garbage_collect(struct dst_ops *ops) equilibrium = entries - goal; } - if (now - last_gc >= ip_rt_gc_min_interval) + if (now - last_gc >= min_interval) last_gc = now; if (goal <= 0) { @@ -1088,15 +1091,33 @@ static int rt_garbage_collect(struct dst_ops *ops) if (net_ratelimit()) printk(KERN_WARNING "dst cache overflow\n"); RT_CACHE_STAT_INC(gc_dst_overflow); - return 1; + return; work_done: - expire += ip_rt_gc_min_interval; + expire += min_interval; if (expire > ip_rt_gc_timeout || dst_entries_get_fast(&ipv4_dst_ops) < ipv4_dst_ops.gc_thresh || dst_entries_get_slow(&ipv4_dst_ops) < ipv4_dst_ops.gc_thresh) expire = ip_rt_gc_timeout; -out: return 0; +out: return; +} + +static void __rt_garbage_collect(struct work_struct *w) +{ + __do_rt_garbage_collect(ip_rt_gc_elasticity, ip_rt_gc_min_interval); +} + +static int rt_garbage_collect(struct dst_ops *ops) +{ + if (!work_pending(&rt_gc_worker)) + schedule_work(&rt_gc_worker); + + if (dst_entries_get_fast(&ipv4_dst_ops) >= ip_rt_max_size || + dst_entries_get_slow(&ipv4_dst_ops) >= ip_rt_max_size) { + RT_CACHE_STAT_INC(gc_dst_overflow); + return 1; + } + return 0; } /* @@ -1291,13 +1312,7 @@ restart: it is most likely it holds some neighbour records. */ if (attempts-- > 0) { - int saved_elasticity = ip_rt_gc_elasticity; - int saved_int = ip_rt_gc_min_interval; - ip_rt_gc_elasticity = 1; - ip_rt_gc_min_interval = 0; - rt_garbage_collect(&ipv4_dst_ops); - ip_rt_gc_min_interval = saved_int; - ip_rt_gc_elasticity = saved_elasticity; + __do_rt_garbage_collect(1, 0); goto restart; } |