|
@@ -99,6 +99,10 @@
|
|
|
#define INFINITY_LIFE_TIME 0xFFFFFFFF
|
|
|
#define TIME_DELTA(a, b) ((unsigned long)((long)(a) - (long)(b)))
|
|
|
|
|
|
+#define ADDRCONF_TIMER_FUZZ_MINUS (HZ > 50 ? HZ/50 : 1)
|
|
|
+#define ADDRCONF_TIMER_FUZZ (HZ / 4)
|
|
|
+#define ADDRCONF_TIMER_FUZZ_MAX (HZ)
|
|
|
+
|
|
|
#ifdef CONFIG_SYSCTL
|
|
|
static void addrconf_sysctl_register(struct inet6_dev *idev);
|
|
|
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)
|
|
|
|
|
|
static void addrconf_verify(unsigned long foo)
|
|
|
{
|
|
|
+ unsigned long now, next, next_sec, next_sched;
|
|
|
struct inet6_ifaddr *ifp;
|
|
|
struct hlist_node *node;
|
|
|
- unsigned long now, next;
|
|
|
int i;
|
|
|
|
|
|
rcu_read_lock_bh();
|
|
|
spin_lock(&addrconf_verify_lock);
|
|
|
now = jiffies;
|
|
|
- next = now + ADDR_CHECK_FREQUENCY;
|
|
|
+ next = round_jiffies_up(now + ADDR_CHECK_FREQUENCY);
|
|
|
|
|
|
del_timer(&addr_chk_timer);
|
|
|
|
|
@@ -3129,7 +3133,8 @@ restart:
|
|
|
continue;
|
|
|
|
|
|
spin_lock(&ifp->lock);
|
|
|
- age = (now - ifp->tstamp) / HZ;
|
|
|
+ /* We try to batch several events at once. */
|
|
|
+ age = (now - ifp->tstamp + ADDRCONF_TIMER_FUZZ_MINUS) / HZ;
|
|
|
|
|
|
if (ifp->valid_lft != INFINITY_LIFE_TIME &&
|
|
|
age >= ifp->valid_lft) {
|
|
@@ -3199,7 +3204,21 @@ restart:
|
|
|
}
|
|
|
}
|
|
|
|
|
|
- addr_chk_timer.expires = time_before(next, jiffies + HZ) ? jiffies + HZ : next;
|
|
|
+ next_sec = round_jiffies_up(next);
|
|
|
+ next_sched = next;
|
|
|
+
|
|
|
+ /* If rounded timeout is accurate enough, accept it. */
|
|
|
+ if (time_before(next_sec, next + ADDRCONF_TIMER_FUZZ))
|
|
|
+ next_sched = next_sec;
|
|
|
+
|
|
|
+ /* And minimum interval is ADDRCONF_TIMER_FUZZ_MAX. */
|
|
|
+ if (time_before(next_sched, jiffies + ADDRCONF_TIMER_FUZZ_MAX))
|
|
|
+ next_sched = jiffies + ADDRCONF_TIMER_FUZZ_MAX;
|
|
|
+
|
|
|
+ ADBG((KERN_DEBUG "now = %lu, schedule = %lu, rounded schedule = %lu => %lu\n",
|
|
|
+ now, next, next_sec, next_sched));
|
|
|
+
|
|
|
+ addr_chk_timer.expires = next_sched;
|
|
|
add_timer(&addr_chk_timer);
|
|
|
spin_unlock(&addrconf_verify_lock);
|
|
|
rcu_read_unlock_bh();
|