diff options
author | Eric Dumazet <dada1@cosmosbay.com> | 2005-07-05 18:00:32 -0400 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2005-07-05 18:00:32 -0400 |
commit | bb1d23b02657f494dff295f6cdd1f29df30fa61e (patch) | |
tree | 59c170cb94d2f65a0717ea67e169b3e2e22be11e /net | |
parent | 424c4b70cc4ff3930ee36a2ef7b204e4d704fd26 (diff) |
[IPV4]: Bug fix in rt_check_expire()
- rt_check_expire() fixes (an overflow occured if size of the hash
was >= 65536)
reminder of the bugfix:
The rt_check_expire() has a serious problem on machines with large
route caches, and a standard HZ value of 1000.
With default values, ie ip_rt_gc_interval = 60*HZ = 60000 ;
the loop count :
for (t = ip_rt_gc_interval << rt_hash_log; t >= 0;
overflows (t is a 31 bit value) as soon rt_hash_log is >= 16 (65536
slots in route cache hash table).
In this case, rt_check_expire() does nothing at all
Signed-off-by: Eric Dumazet <dada1@cosmosbay.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'net')
-rw-r--r-- | net/ipv4/route.c | 21 |
1 files changed, 14 insertions, 7 deletions
diff --git a/net/ipv4/route.c b/net/ipv4/route.c index 9fcbb1b0a8d6..726ea5e8180a 100644 --- a/net/ipv4/route.c +++ b/net/ipv4/route.c | |||
@@ -54,7 +54,7 @@ | |||
54 | * Marc Boucher : routing by fwmark | 54 | * Marc Boucher : routing by fwmark |
55 | * Robert Olsson : Added rt_cache statistics | 55 | * Robert Olsson : Added rt_cache statistics |
56 | * Arnaldo C. Melo : Convert proc stuff to seq_file | 56 | * Arnaldo C. Melo : Convert proc stuff to seq_file |
57 | * Eric Dumazet : hashed spinlocks | 57 | * Eric Dumazet : hashed spinlocks and rt_check_expire() fixes. |
58 | * | 58 | * |
59 | * This program is free software; you can redistribute it and/or | 59 | * This program is free software; you can redistribute it and/or |
60 | * modify it under the terms of the GNU General Public License | 60 | * modify it under the terms of the GNU General Public License |
@@ -606,18 +606,25 @@ static struct rtable **rt_remove_balanced_route(struct rtable **chain_head, | |||
606 | /* This runs via a timer and thus is always in BH context. */ | 606 | /* This runs via a timer and thus is always in BH context. */ |
607 | static void rt_check_expire(unsigned long dummy) | 607 | static void rt_check_expire(unsigned long dummy) |
608 | { | 608 | { |
609 | static int rover; | 609 | static unsigned int rover; |
610 | int i = rover, t; | 610 | unsigned int i = rover, goal; |
611 | struct rtable *rth, **rthp; | 611 | struct rtable *rth, **rthp; |
612 | unsigned long now = jiffies; | 612 | unsigned long now = jiffies; |
613 | 613 | u64 mult; | |
614 | for (t = ip_rt_gc_interval << rt_hash_log; t >= 0; | 614 | |
615 | t -= ip_rt_gc_timeout) { | 615 | mult = ((u64)ip_rt_gc_interval) << rt_hash_log; |
616 | if (ip_rt_gc_timeout > 1) | ||
617 | do_div(mult, ip_rt_gc_timeout); | ||
618 | goal = (unsigned int)mult; | ||
619 | if (goal > rt_hash_mask) goal = rt_hash_mask + 1; | ||
620 | for (; goal > 0; goal--) { | ||
616 | unsigned long tmo = ip_rt_gc_timeout; | 621 | unsigned long tmo = ip_rt_gc_timeout; |
617 | 622 | ||
618 | i = (i + 1) & rt_hash_mask; | 623 | i = (i + 1) & rt_hash_mask; |
619 | rthp = &rt_hash_table[i].chain; | 624 | rthp = &rt_hash_table[i].chain; |
620 | 625 | ||
626 | if (*rthp == 0) | ||
627 | continue; | ||
621 | spin_lock(rt_hash_lock_addr(i)); | 628 | spin_lock(rt_hash_lock_addr(i)); |
622 | while ((rth = *rthp) != NULL) { | 629 | while ((rth = *rthp) != NULL) { |
623 | if (rth->u.dst.expires) { | 630 | if (rth->u.dst.expires) { |
@@ -658,7 +665,7 @@ static void rt_check_expire(unsigned long dummy) | |||
658 | break; | 665 | break; |
659 | } | 666 | } |
660 | rover = i; | 667 | rover = i; |
661 | mod_timer(&rt_periodic_timer, now + ip_rt_gc_interval); | 668 | mod_timer(&rt_periodic_timer, jiffies + ip_rt_gc_interval); |
662 | } | 669 | } |
663 | 670 | ||
664 | /* This can run from both BH and non-BH contexts, the latter | 671 | /* This can run from both BH and non-BH contexts, the latter |