diff options
-rw-r--r-- | net/ipv6/addrconf.c | 27 |
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 |
103 | static void addrconf_sysctl_register(struct inet6_dev *idev); | 107 | static void addrconf_sysctl_register(struct inet6_dev *idev); |
104 | static void addrconf_sysctl_unregister(struct inet6_dev *idev); | 108 | static 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 | ||
3108 | static void addrconf_verify(unsigned long foo) | 3112 | static 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(); |