瀏覽代碼

[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>
Denis Lunev 20 年之前
父節點
當前提交
f0098f7863
共有 1 個文件被更改,包括 11 次插入4 次删除
  1. 11 4
      net/core/dst.c

+ 11 - 4
net/core/dst.c

@@ -45,6 +45,7 @@ static struct timer_list dst_gc_timer =
 static void dst_run_gc(unsigned long dummy)
 static void dst_run_gc(unsigned long dummy)
 {
 {
 	int    delayed = 0;
 	int    delayed = 0;
+	int    work_performed;
 	struct dst_entry * dst, **dstp;
 	struct dst_entry * dst, **dstp;
 
 
 	if (!spin_trylock(&dst_lock)) {
 	if (!spin_trylock(&dst_lock)) {
@@ -52,9 +53,9 @@ static void dst_run_gc(unsigned long dummy)
 		return;
 		return;
 	}
 	}
 
 
-
 	del_timer(&dst_gc_timer);
 	del_timer(&dst_gc_timer);
 	dstp = &dst_garbage_list;
 	dstp = &dst_garbage_list;
+	work_performed = 0;
 	while ((dst = *dstp) != NULL) {
 	while ((dst = *dstp) != NULL) {
 		if (atomic_read(&dst->__refcnt)) {
 		if (atomic_read(&dst->__refcnt)) {
 			dstp = &dst->next;
 			dstp = &dst->next;
@@ -62,6 +63,7 @@ static void dst_run_gc(unsigned long dummy)
 			continue;
 			continue;
 		}
 		}
 		*dstp = dst->next;
 		*dstp = dst->next;
+		work_performed = 1;
 
 
 		dst = dst_destroy(dst);
 		dst = dst_destroy(dst);
 		if (dst) {
 		if (dst) {
@@ -86,9 +88,14 @@ static void dst_run_gc(unsigned long dummy)
 		dst_gc_timer_inc = DST_GC_MAX;
 		dst_gc_timer_inc = DST_GC_MAX;
 		goto out;
 		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;
 	dst_gc_timer.expires = jiffies + dst_gc_timer_expires;
 #if RT_CACHE_DEBUG >= 2
 #if RT_CACHE_DEBUG >= 2
 	printk("dst_total: %d/%d %ld\n",
 	printk("dst_total: %d/%d %ld\n",