summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorDavid Howells <dhowells@redhat.com>2010-10-27 18:28:35 +0200
committerDavid Howells <dhowells@redhat.com>2010-10-27 18:28:35 +0200
commit3b950de9c94b4b9fde4f1340358ab52ce0f34be0 (patch)
tree724923f90b0d12bd6e0374b73e8fd06d8d8787e1
parentmn10300: Use pci_claim_resource (diff)
downloadlinux-3b950de9c94b4b9fde4f1340358ab52ce0f34be0.tar.xz
linux-3b950de9c94b4b9fde4f1340358ab52ce0f34be0.zip
MN10300: Prevent cnt32_to_63() from being preempted in sched_clock()
Prevent cnt32_to_63() from being preempted in sched_clock() because it may read its internal counter, get preempted, get delayed for more than the half period of the 'TSC' and then write the internal counter, thus corrupting it. Whilst some callers of sched_clock() have interrupts disabled or hold spinlocks, not all do, and so preemption must be held here. Note that sched_clock() is called from lockdep, but that shouldn't be a problem because although preempt_disable() calls into lockdep, lockdep has a recursion counter to deal with this. Signed-off-by: David Howells <dhowells@redhat.com>
-rw-r--r--arch/mn10300/kernel/time.c5
1 files changed, 5 insertions, 0 deletions
diff --git a/arch/mn10300/kernel/time.c b/arch/mn10300/kernel/time.c
index 8f7f6d22783d..0b5c856b4266 100644
--- a/arch/mn10300/kernel/time.c
+++ b/arch/mn10300/kernel/time.c
@@ -54,6 +54,9 @@ unsigned long long sched_clock(void)
unsigned long tsc, tmp;
unsigned product[3]; /* 96-bit intermediate value */
+ /* cnt32_to_63() is not safe with preemption */
+ preempt_disable();
+
/* read the TSC value
*/
tsc = 0 - get_cycles(); /* get_cycles() counts down */
@@ -64,6 +67,8 @@ unsigned long long sched_clock(void)
*/
tsc64.ll = cnt32_to_63(tsc) & 0x7fffffffffffffffULL;
+ preempt_enable();
+
/* scale the 64-bit TSC value to a nanosecond value via a 96-bit
* intermediate
*/