Skip to content

Commit

Permalink
[IPV4]: Convert rt_check_expire() from softirq processing to workqueue.
Browse files Browse the repository at this point in the history
On loaded/big hosts, rt_check_expire() if of litle use, because it
generally breaks out of its main loop because of a jiffies change.

It can take a long time (read : timer invocations) to actually
scan the whole hash table, freeing unused entries.

Converting it to use a workqueue instead of softirq is a nice
move because we can allow rt_check_expire() to do the scan
it is supposed to do, without hogging the CPU.

This has an impact on the average number of entries in cache,
reducing ram usage. Cache is more responsive to parameter
changes (/proc/sys/net/ipv4/route/gc_timeout and
/proc/sys/net/ipv4/route/gc_interval)

Note: Maybe the default value of gc_interval (60 seconds)
is too high, since this means we actually need 5 (300/60)
invocations to scan the whole table.

Signed-off-by: Eric Dumazet <dada1@cosmosbay.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
  • Loading branch information
Eric Dumazet authored and David S. Miller committed Oct 10, 2007
1 parent dac24ab commit 39c90ec
Showing 1 changed file with 12 additions and 18 deletions.
30 changes: 12 additions & 18 deletions net/ipv4/route.c
Original file line number Diff line number Diff line change
Expand Up @@ -81,6 +81,7 @@
#include <linux/netdevice.h>
#include <linux/proc_fs.h>
#include <linux/init.h>
#include <linux/workqueue.h>
#include <linux/skbuff.h>
#include <linux/inetdevice.h>
#include <linux/igmp.h>
Expand Down Expand Up @@ -136,7 +137,8 @@ static unsigned long rt_deadline;
#define RTprint(a...) printk(KERN_DEBUG a)

static struct timer_list rt_flush_timer;
static struct timer_list rt_periodic_timer;
static void rt_check_expire(struct work_struct *work);
static DECLARE_DELAYED_WORK(expires_work, rt_check_expire);
static struct timer_list rt_secret_timer;

/*
Expand Down Expand Up @@ -572,20 +574,19 @@ static inline int compare_keys(struct flowi *fl1, struct flowi *fl2)
(fl1->iif ^ fl2->iif)) == 0;
}

/* This runs via a timer and thus is always in BH context. */
static void rt_check_expire(unsigned long dummy)
static void rt_check_expire(struct work_struct *work)
{
static unsigned int rover;
unsigned int i = rover, goal;
struct rtable *rth, **rthp;
unsigned long now = jiffies;
u64 mult;

mult = ((u64)ip_rt_gc_interval) << rt_hash_log;
if (ip_rt_gc_timeout > 1)
do_div(mult, ip_rt_gc_timeout);
goal = (unsigned int)mult;
if (goal > rt_hash_mask) goal = rt_hash_mask + 1;
if (goal > rt_hash_mask)
goal = rt_hash_mask + 1;
for (; goal > 0; goal--) {
unsigned long tmo = ip_rt_gc_timeout;

Expand All @@ -594,11 +595,11 @@ static void rt_check_expire(unsigned long dummy)

if (*rthp == 0)
continue;
spin_lock(rt_hash_lock_addr(i));
spin_lock_bh(rt_hash_lock_addr(i));
while ((rth = *rthp) != NULL) {
if (rth->u.dst.expires) {
/* Entry is expired even if it is in use */
if (time_before_eq(now, rth->u.dst.expires)) {
if (time_before_eq(jiffies, rth->u.dst.expires)) {
tmo >>= 1;
rthp = &rth->u.dst.rt_next;
continue;
Expand All @@ -613,14 +614,10 @@ static void rt_check_expire(unsigned long dummy)
*rthp = rth->u.dst.rt_next;
rt_free(rth);
}
spin_unlock(rt_hash_lock_addr(i));

/* Fallback loop breaker. */
if (time_after(jiffies, now))
break;
spin_unlock_bh(rt_hash_lock_addr(i));
}
rover = i;
mod_timer(&rt_periodic_timer, jiffies + ip_rt_gc_interval);
schedule_delayed_work(&expires_work, ip_rt_gc_interval);
}

/* This can run from both BH and non-BH contexts, the latter
Expand Down Expand Up @@ -2993,17 +2990,14 @@ int __init ip_rt_init(void)

init_timer(&rt_flush_timer);
rt_flush_timer.function = rt_run_flush;
init_timer(&rt_periodic_timer);
rt_periodic_timer.function = rt_check_expire;
init_timer(&rt_secret_timer);
rt_secret_timer.function = rt_secret_rebuild;

/* All the timers, started at system startup tend
to synchronize. Perturb it a bit.
*/
rt_periodic_timer.expires = jiffies + net_random() % ip_rt_gc_interval +
ip_rt_gc_interval;
add_timer(&rt_periodic_timer);
schedule_delayed_work(&expires_work,
net_random() % ip_rt_gc_interval + ip_rt_gc_interval);

rt_secret_timer.expires = jiffies + net_random() % ip_rt_secret_interval +
ip_rt_secret_interval;
Expand Down

0 comments on commit 39c90ec

Please sign in to comment.