]> err.no Git - linux-2.6/commitdiff
[NET] Fix too aggressive backoff in dst garbage collection
authorDenis Lunev <den@sw.ru>
Sun, 31 Jul 2005 00:47:25 +0000 (17:47 -0700)
committerDavid S. Miller <davem@davemloft.net>
Sun, 31 Jul 2005 00:47:25 +0000 (17:47 -0700)
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>
net/core/dst.c

index fc434ade5270e1b99770a9a5f91b2a8747a50093..334790da9f160cd6852a35e5186db16cbb3d14b1 100644 (file)
@@ -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",