summaryrefslogtreecommitdiffstats
path: root/net/core
diff options
context:
space:
mode:
authorDenis Lunev <den@sw.ru>2005-07-30 17:47:25 -0700
committerDavid S. Miller <davem@davemloft.net>2005-07-30 17:47:25 -0700
commitf0098f7863f814a5adc0b9cb271605d063cad7fa (patch)
tree7477022770edd99422586372147e9b0f48de4c63 /net/core
parentdb44575f6fd55df6ff67ddd21f7ad5be5a741136 (diff)
downloadlinux-stable-f0098f7863f814a5adc0b9cb271605d063cad7fa.tar.gz
linux-stable-f0098f7863f814a5adc0b9cb271605d063cad7fa.tar.bz2
linux-stable-f0098f7863f814a5adc0b9cb271605d063cad7fa.zip
[NET] Fix too aggressive backoff in dst garbage collection
The bug is evident when it is seen once. dst gc timer was backed off, when gc queue is not empty. But this means that timer quickly backs off, if at least one destination remains in use. Normally, the bug is invisible, because adding new dst entry to queue cancels the backoff. But it shots deadly with destination cache overflow when new destinations are not released for long time f.e. after an interface goes down. The fix is to cancel backoff when something was released. Signed-off-by: Denis Lunev <den@sw.ru> Signed-off-by: Alexey Kuznetsov <kuznet@ms2.inr.ac.ru> Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'net/core')
-rw-r--r--net/core/dst.c15
1 files changed, 11 insertions, 4 deletions
diff --git a/net/core/dst.c b/net/core/dst.c
index fc434ade5270..334790da9f16 100644
--- a/net/core/dst.c
+++ b/net/core/dst.c
@@ -45,6 +45,7 @@ static struct timer_list dst_gc_timer =
static void dst_run_gc(unsigned long dummy)
{
int delayed = 0;
+ int work_performed;
struct dst_entry * dst, **dstp;
if (!spin_trylock(&dst_lock)) {
@@ -52,9 +53,9 @@ static void dst_run_gc(unsigned long dummy)
return;
}
-
del_timer(&dst_gc_timer);
dstp = &dst_garbage_list;
+ work_performed = 0;
while ((dst = *dstp) != NULL) {
if (atomic_read(&dst->__refcnt)) {
dstp = &dst->next;
@@ -62,6 +63,7 @@ static void dst_run_gc(unsigned long dummy)
continue;
}
*dstp = dst->next;
+ work_performed = 1;
dst = dst_destroy(dst);
if (dst) {
@@ -86,9 +88,14 @@ static void dst_run_gc(unsigned long dummy)
dst_gc_timer_inc = DST_GC_MAX;
goto out;
}
- if ((dst_gc_timer_expires += dst_gc_timer_inc) > DST_GC_MAX)
- dst_gc_timer_expires = DST_GC_MAX;
- dst_gc_timer_inc += DST_GC_INC;
+ if (!work_performed) {
+ if ((dst_gc_timer_expires += dst_gc_timer_inc) > DST_GC_MAX)
+ dst_gc_timer_expires = DST_GC_MAX;
+ dst_gc_timer_inc += DST_GC_INC;
+ } else {
+ dst_gc_timer_inc = DST_GC_INC;
+ dst_gc_timer_expires = DST_GC_MIN;
+ }
dst_gc_timer.expires = jiffies + dst_gc_timer_expires;
#if RT_CACHE_DEBUG >= 2
printk("dst_total: %d/%d %ld\n",