diff options
Diffstat (limited to 'net/ipv4/route.c')
-rw-r--r-- | net/ipv4/route.c | 30 |
1 files changed, 12 insertions, 18 deletions
diff --git a/net/ipv4/route.c b/net/ipv4/route.c index 396c631166a4..006d6058a806 100644 --- a/net/ipv4/route.c +++ b/net/ipv4/route.c | |||
@@ -81,6 +81,7 @@ | |||
81 | #include <linux/netdevice.h> | 81 | #include <linux/netdevice.h> |
82 | #include <linux/proc_fs.h> | 82 | #include <linux/proc_fs.h> |
83 | #include <linux/init.h> | 83 | #include <linux/init.h> |
84 | #include <linux/workqueue.h> | ||
84 | #include <linux/skbuff.h> | 85 | #include <linux/skbuff.h> |
85 | #include <linux/inetdevice.h> | 86 | #include <linux/inetdevice.h> |
86 | #include <linux/igmp.h> | 87 | #include <linux/igmp.h> |
@@ -136,7 +137,8 @@ static unsigned long rt_deadline; | |||
136 | #define RTprint(a...) printk(KERN_DEBUG a) | 137 | #define RTprint(a...) printk(KERN_DEBUG a) |
137 | 138 | ||
138 | static struct timer_list rt_flush_timer; | 139 | static struct timer_list rt_flush_timer; |
139 | static struct timer_list rt_periodic_timer; | 140 | static void rt_check_expire(struct work_struct *work); |
141 | static DECLARE_DELAYED_WORK(expires_work, rt_check_expire); | ||
140 | static struct timer_list rt_secret_timer; | 142 | static struct timer_list rt_secret_timer; |
141 | 143 | ||
142 | /* | 144 | /* |
@@ -572,20 +574,19 @@ static inline int compare_keys(struct flowi *fl1, struct flowi *fl2) | |||
572 | (fl1->iif ^ fl2->iif)) == 0; | 574 | (fl1->iif ^ fl2->iif)) == 0; |
573 | } | 575 | } |
574 | 576 | ||
575 | /* This runs via a timer and thus is always in BH context. */ | 577 | static void rt_check_expire(struct work_struct *work) |
576 | static void rt_check_expire(unsigned long dummy) | ||
577 | { | 578 | { |
578 | static unsigned int rover; | 579 | static unsigned int rover; |
579 | unsigned int i = rover, goal; | 580 | unsigned int i = rover, goal; |
580 | struct rtable *rth, **rthp; | 581 | struct rtable *rth, **rthp; |
581 | unsigned long now = jiffies; | ||
582 | u64 mult; | 582 | u64 mult; |
583 | 583 | ||
584 | mult = ((u64)ip_rt_gc_interval) << rt_hash_log; | 584 | mult = ((u64)ip_rt_gc_interval) << rt_hash_log; |
585 | if (ip_rt_gc_timeout > 1) | 585 | if (ip_rt_gc_timeout > 1) |
586 | do_div(mult, ip_rt_gc_timeout); | 586 | do_div(mult, ip_rt_gc_timeout); |
587 | goal = (unsigned int)mult; | 587 | goal = (unsigned int)mult; |
588 | if (goal > rt_hash_mask) goal = rt_hash_mask + 1; | 588 | if (goal > rt_hash_mask) |
589 | goal = rt_hash_mask + 1; | ||
589 | for (; goal > 0; goal--) { | 590 | for (; goal > 0; goal--) { |
590 | unsigned long tmo = ip_rt_gc_timeout; | 591 | unsigned long tmo = ip_rt_gc_timeout; |
591 | 592 | ||
@@ -594,11 +595,11 @@ static void rt_check_expire(unsigned long dummy) | |||
594 | 595 | ||
595 | if (*rthp == 0) | 596 | if (*rthp == 0) |
596 | continue; | 597 | continue; |
597 | spin_lock(rt_hash_lock_addr(i)); | 598 | spin_lock_bh(rt_hash_lock_addr(i)); |
598 | while ((rth = *rthp) != NULL) { | 599 | while ((rth = *rthp) != NULL) { |
599 | if (rth->u.dst.expires) { | 600 | if (rth->u.dst.expires) { |
600 | /* Entry is expired even if it is in use */ | 601 | /* Entry is expired even if it is in use */ |
601 | if (time_before_eq(now, rth->u.dst.expires)) { | 602 | if (time_before_eq(jiffies, rth->u.dst.expires)) { |
602 | tmo >>= 1; | 603 | tmo >>= 1; |
603 | rthp = &rth->u.dst.rt_next; | 604 | rthp = &rth->u.dst.rt_next; |
604 | continue; | 605 | continue; |
@@ -613,14 +614,10 @@ static void rt_check_expire(unsigned long dummy) | |||
613 | *rthp = rth->u.dst.rt_next; | 614 | *rthp = rth->u.dst.rt_next; |
614 | rt_free(rth); | 615 | rt_free(rth); |
615 | } | 616 | } |
616 | spin_unlock(rt_hash_lock_addr(i)); | 617 | spin_unlock_bh(rt_hash_lock_addr(i)); |
617 | |||
618 | /* Fallback loop breaker. */ | ||
619 | if (time_after(jiffies, now)) | ||
620 | break; | ||
621 | } | 618 | } |
622 | rover = i; | 619 | rover = i; |
623 | mod_timer(&rt_periodic_timer, jiffies + ip_rt_gc_interval); | 620 | schedule_delayed_work(&expires_work, ip_rt_gc_interval); |
624 | } | 621 | } |
625 | 622 | ||
626 | /* This can run from both BH and non-BH contexts, the latter | 623 | /* This can run from both BH and non-BH contexts, the latter |
@@ -2993,17 +2990,14 @@ int __init ip_rt_init(void) | |||
2993 | 2990 | ||
2994 | init_timer(&rt_flush_timer); | 2991 | init_timer(&rt_flush_timer); |
2995 | rt_flush_timer.function = rt_run_flush; | 2992 | rt_flush_timer.function = rt_run_flush; |
2996 | init_timer(&rt_periodic_timer); | ||
2997 | rt_periodic_timer.function = rt_check_expire; | ||
2998 | init_timer(&rt_secret_timer); | 2993 | init_timer(&rt_secret_timer); |
2999 | rt_secret_timer.function = rt_secret_rebuild; | 2994 | rt_secret_timer.function = rt_secret_rebuild; |
3000 | 2995 | ||
3001 | /* All the timers, started at system startup tend | 2996 | /* All the timers, started at system startup tend |
3002 | to synchronize. Perturb it a bit. | 2997 | to synchronize. Perturb it a bit. |
3003 | */ | 2998 | */ |
3004 | rt_periodic_timer.expires = jiffies + net_random() % ip_rt_gc_interval + | 2999 | schedule_delayed_work(&expires_work, |
3005 | ip_rt_gc_interval; | 3000 | net_random() % ip_rt_gc_interval + ip_rt_gc_interval); |
3006 | add_timer(&rt_periodic_timer); | ||
3007 | 3001 | ||
3008 | rt_secret_timer.expires = jiffies + net_random() % ip_rt_secret_interval + | 3002 | rt_secret_timer.expires = jiffies + net_random() % ip_rt_secret_interval + |
3009 | ip_rt_secret_interval; | 3003 | ip_rt_secret_interval; |