aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--net/ipv6/addrconf.c27
1 files changed, 23 insertions, 4 deletions
diff --git a/net/ipv6/addrconf.c b/net/ipv6/addrconf.c
index 36ebb4ad8a0a..7d7d4b17c0f0 100644
--- a/net/ipv6/addrconf.c
+++ b/net/ipv6/addrconf.c
@@ -99,6 +99,10 @@
99#define INFINITY_LIFE_TIME 0xFFFFFFFF 99#define INFINITY_LIFE_TIME 0xFFFFFFFF
100#define TIME_DELTA(a, b) ((unsigned long)((long)(a) - (long)(b))) 100#define TIME_DELTA(a, b) ((unsigned long)((long)(a) - (long)(b)))
101 101
102#define ADDRCONF_TIMER_FUZZ_MINUS (HZ > 50 ? HZ/50 : 1)
103#define ADDRCONF_TIMER_FUZZ (HZ / 4)
104#define ADDRCONF_TIMER_FUZZ_MAX (HZ)
105
102#ifdef CONFIG_SYSCTL 106#ifdef CONFIG_SYSCTL
103static void addrconf_sysctl_register(struct inet6_dev *idev); 107static void addrconf_sysctl_register(struct inet6_dev *idev);
104static void addrconf_sysctl_unregister(struct inet6_dev *idev); 108static void addrconf_sysctl_unregister(struct inet6_dev *idev);
@@ -3107,15 +3111,15 @@ int ipv6_chk_home_addr(struct net *net, struct in6_addr *addr)
3107 3111
3108static void addrconf_verify(unsigned long foo) 3112static void addrconf_verify(unsigned long foo)
3109{ 3113{
3114 unsigned long now, next, next_sec, next_sched;
3110 struct inet6_ifaddr *ifp; 3115 struct inet6_ifaddr *ifp;
3111 struct hlist_node *node; 3116 struct hlist_node *node;
3112 unsigned long now, next;
3113 int i; 3117 int i;
3114 3118
3115 rcu_read_lock_bh(); 3119 rcu_read_lock_bh();
3116 spin_lock(&addrconf_verify_lock); 3120 spin_lock(&addrconf_verify_lock);
3117 now = jiffies; 3121 now = jiffies;
3118 next = now + ADDR_CHECK_FREQUENCY; 3122 next = round_jiffies_up(now + ADDR_CHECK_FREQUENCY);
3119 3123
3120 del_timer(&addr_chk_timer); 3124 del_timer(&addr_chk_timer);
3121 3125
@@ -3129,7 +3133,8 @@ restart:
3129 continue; 3133 continue;
3130 3134
3131 spin_lock(&ifp->lock); 3135 spin_lock(&ifp->lock);
3132 age = (now - ifp->tstamp) / HZ; 3136 /* We try to batch several events at once. */
3137 age = (now - ifp->tstamp + ADDRCONF_TIMER_FUZZ_MINUS) / HZ;
3133 3138
3134 if (ifp->valid_lft != INFINITY_LIFE_TIME && 3139 if (ifp->valid_lft != INFINITY_LIFE_TIME &&
3135 age >= ifp->valid_lft) { 3140 age >= ifp->valid_lft) {
@@ -3199,7 +3204,21 @@ restart:
3199 } 3204 }
3200 } 3205 }
3201 3206
3202 addr_chk_timer.expires = time_before(next, jiffies + HZ) ? jiffies + HZ : next; 3207 next_sec = round_jiffies_up(next);
3208 next_sched = next;
3209
3210 /* If rounded timeout is accurate enough, accept it. */
3211 if (time_before(next_sec, next + ADDRCONF_TIMER_FUZZ))
3212 next_sched = next_sec;
3213
3214 /* And minimum interval is ADDRCONF_TIMER_FUZZ_MAX. */
3215 if (time_before(next_sched, jiffies + ADDRCONF_TIMER_FUZZ_MAX))
3216 next_sched = jiffies + ADDRCONF_TIMER_FUZZ_MAX;
3217
3218 ADBG((KERN_DEBUG "now = %lu, schedule = %lu, rounded schedule = %lu => %lu\n",
3219 now, next, next_sec, next_sched));
3220
3221 addr_chk_timer.expires = next_sched;
3203 add_timer(&addr_chk_timer); 3222 add_timer(&addr_chk_timer);
3204 spin_unlock(&addrconf_verify_lock); 3223 spin_unlock(&addrconf_verify_lock);
3205 rcu_read_unlock_bh(); 3224 rcu_read_unlock_bh();