Commit f8f3d12d authored by Linus Torvalds's avatar Linus Torvalds

Merge bk://kernel.bkbits.net/davem/sparc-2.5

into home.osdl.org:/home/torvalds/v2.5/linux
parents 8dd9d072 348e9f70
...@@ -321,7 +321,7 @@ time_cpufreq_notifier(struct notifier_block *nb, unsigned long val, ...@@ -321,7 +321,7 @@ time_cpufreq_notifier(struct notifier_block *nb, unsigned long val,
{ {
struct cpufreq_freqs *freq = data; struct cpufreq_freqs *freq = data;
write_seqlock(&xtime_lock); write_seqlock_irq(&xtime_lock);
if (!ref_freq) { if (!ref_freq) {
ref_freq = freq->old; ref_freq = freq->old;
loops_per_jiffy_ref = cpu_data[freq->cpu].loops_per_jiffy; loops_per_jiffy_ref = cpu_data[freq->cpu].loops_per_jiffy;
...@@ -342,7 +342,7 @@ time_cpufreq_notifier(struct notifier_block *nb, unsigned long val, ...@@ -342,7 +342,7 @@ time_cpufreq_notifier(struct notifier_block *nb, unsigned long val,
} }
#endif #endif
} }
write_sequnlock(&xtime_lock); write_sequnlock_irq(&xtime_lock);
return 0; return 0;
} }
......
...@@ -315,23 +315,30 @@ EXPORT_SYMBOL(del_timer); ...@@ -315,23 +315,30 @@ EXPORT_SYMBOL(del_timer);
* the timer it also makes sure the handler has finished executing on other * the timer it also makes sure the handler has finished executing on other
* CPUs. * CPUs.
* *
* Synchronization rules: callers must prevent restarting of the timer, * Synchronization rules: callers must prevent restarting of the timer
* otherwise this function is meaningless. It must not be called from * (except restarting the timer from the timer function itself), otherwise
* interrupt contexts. Upon exit the timer is not queued and the handler * this function is meaningless. It must not be called from interrupt
* is not running on any CPU. * contexts. Upon exit the timer is not queued and the handler is not
* running on any CPU.
* *
* The function returns whether it has deactivated a pending timer or not. * The function returns the number of times it has deactivated a pending
* timer.
*/ */
int del_timer_sync(struct timer_list *timer) int del_timer_sync(struct timer_list *timer)
{ {
int i, ret = 0, again;
unsigned long flags;
tvec_base_t *base; tvec_base_t *base;
int i, ret = 0;
check_timer(timer); check_timer(timer);
del_again: del_again:
ret += del_timer(timer); ret += del_timer(timer);
/*
* First do a lighter but racy check, whether the
* timer is running on any other CPU:
*/
for (i = 0; i < NR_CPUS; i++) { for (i = 0; i < NR_CPUS; i++) {
if (!cpu_online(i)) if (!cpu_online(i))
continue; continue;
...@@ -345,8 +352,33 @@ int del_timer_sync(struct timer_list *timer) ...@@ -345,8 +352,33 @@ int del_timer_sync(struct timer_list *timer)
break; break;
} }
} }
smp_rmb();
/*
* Do a heavy but race-free re-check to make sure both that
* the timer is neither running nor pending:
*/
again = 0;
local_irq_save(flags);
for (i = 0; i < NR_CPUS; i++)
if (cpu_online(i))
spin_lock(&per_cpu(tvec_bases, i).lock);
if (timer_pending(timer)) if (timer_pending(timer))
again = 1;
else
for (i = 0; i < NR_CPUS; i++)
if (cpu_online(i) &&
(per_cpu(tvec_bases, i).running_timer == timer))
again = 1;
for (i = 0; i < NR_CPUS; i++)
if (cpu_online(i))
spin_unlock(&per_cpu(tvec_bases, i).lock);
local_irq_restore(flags);
if (again)
goto del_again; goto del_again;
return ret; return ret;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment