Introduce mod_timer_noact() which is to replace the timer updating code in __nf_ct_refresh_acct(). It works like mod_timer() but doesn't activate an inactive timer which is the behaviour we want. A later patch will modify __nf_ct_refresh_acct() to use mod_timer_noact() which then will save one spin_lock_irqsave / spin_lock_irqrestore pair per conntrack timer update. Signed-off-by: Martin Josefsson --- include/linux/timer.h | 8 ++++++-- kernel/timer.c | 40 +++++++++++++++++++++++++++++++++++----- 2 files changed, 41 insertions(+), 7 deletions(-) Index: linux-2.6.19-rc3-git4.quilt/include/linux/timer.h =================================================================== --- linux-2.6.19-rc3-git4.quilt.orig/include/linux/timer.h 2006-09-20 05:42:06.000000000 +0200 +++ linux-2.6.19-rc3-git4.quilt/include/linux/timer.h 2006-10-28 23:08:57.000000000 +0200 @@ -19,6 +19,9 @@ struct timer_list { extern struct tvec_t_base_s boot_tvec_bases; +#define TIMER_ACT 1 +#define TIMER_NOACT 0 + #define TIMER_INITIALIZER(_function, _expires, _data) { \ .function = (_function), \ .expires = (_expires), \ @@ -58,8 +61,9 @@ static inline int timer_pending(const st extern void add_timer_on(struct timer_list *timer, int cpu); extern int del_timer(struct timer_list * timer); -extern int __mod_timer(struct timer_list *timer, unsigned long expires); +extern int __mod_timer(struct timer_list *timer, unsigned long expires, int activate); extern int mod_timer(struct timer_list *timer, unsigned long expires); +extern int mod_timer_noact(struct timer_list *timer, unsigned long expires); extern unsigned long next_timer_interrupt(void); @@ -80,7 +84,7 @@ extern unsigned long next_timer_interrup static inline void add_timer(struct timer_list *timer) { BUG_ON(timer_pending(timer)); - __mod_timer(timer, timer->expires); + __mod_timer(timer, timer->expires, TIMER_ACT); } #ifdef CONFIG_SMP Index: linux-2.6.19-rc3-git4.quilt/kernel/timer.c =================================================================== --- linux-2.6.19-rc3-git4.quilt.orig/kernel/timer.c 2006-10-28 22:56:53.000000000 +0200 +++ linux-2.6.19-rc3-git4.quilt/kernel/timer.c 2006-10-28 23:11:30.000000000 +0200 @@ -186,7 +186,7 @@ static tvec_base_t *lock_timer_base(stru } } -int __mod_timer(struct timer_list *timer, unsigned long expires) +int __mod_timer(struct timer_list *timer, unsigned long expires, int activate) { tvec_base_t *base, *new_base; unsigned long flags; @@ -199,7 +199,8 @@ int __mod_timer(struct timer_list *timer if (timer_pending(timer)) { detach_timer(timer, 0); ret = 1; - } + } else if (activate == TIMER_NOACT) + goto out_unlock; new_base = __get_cpu_var(tvec_bases); @@ -223,8 +224,9 @@ int __mod_timer(struct timer_list *timer timer->expires = expires; internal_add_timer(base, timer); - spin_unlock_irqrestore(&base->lock, flags); +out_unlock: + spin_unlock_irqrestore(&base->lock, flags); return ret; } @@ -282,11 +284,39 @@ int mod_timer(struct timer_list *timer, if (timer->expires == expires && timer_pending(timer)) return 1; - return __mod_timer(timer, expires); + return __mod_timer(timer, expires, TIMER_ACT); } EXPORT_SYMBOL(mod_timer); +/*** + * mod_timer_noact - modify a timer's timeout + * @timer: the timer to be modified + * + * mod_timer_noact works like mod_timer except that it doesn't activate an + * inactive timer, instead it returns without updating timer->expires. + * + * The function returns whether it has modified a pending timer or not. + * (ie. mod_timer_noact() of an inactive timer returns 0, mod_timer_noact() of + * an active timer returns 1.) + */ +int mod_timer_noact(struct timer_list *timer, unsigned long expires) +{ + BUG_ON(!timer->function); + + /* + * This is a common optimization triggered by the + * networking code - if the timer is re-modified + * to be the same thing then just return: + */ + if (timer->expires == expires && timer_pending(timer)) + return 1; + + return __mod_timer(timer, expires, TIMER_NOACT); +} + +EXPORT_SYMBOL(mod_timer_noact); + /** * del_timer - deactive a timer. * @timer: the timer to be deactivated @@ -1215,7 +1245,7 @@ fastcall signed long __sched schedule_ti expire = timeout + jiffies; setup_timer(&timer, process_timeout, (unsigned long)current); - __mod_timer(&timer, expire); + __mod_timer(&timer, expire, TIMER_ACT); schedule(); del_singleshot_timer_sync(&timer);