aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorjohn stultz <johnstul@us.ibm.com>2009-01-22 00:53:22 -0500
committerThomas Gleixner <tglx@linutronix.de>2009-06-11 05:24:52 -0400
commit3f68535adad8dd89499505a65fb25d0e02d118cc (patch)
treeb347c3901d2d590d8c2b8c3be993ef20b278e61f
parent7d27558c4138ac6b3684dea35c2f4379b940a7dd (diff)
clocksource: sanity check sysfs clocksource changes
Thomas, Andrew and Ingo pointed out that we don't have any safety checks in the clocksource sysfs entries to make sure sysadmins don't try to change the clocksource to a non high-res timer capable clocksource (such as jiffies) when high-res timers (HRT) is enabled. Doing so will likely hang a system. Correct this by filtering non HRT clocksources from available_clocksources and not accepting non HRT clocksources with HRT enabled. Signed-off-by: John Stultz <johnstul@us.ibm.com> Signed-off-by: Andrew Morton <akpm@linux-foundation.org> Signed-off-by: Thomas Gleixner <tglx@linutronix.de>
-rw-r--r--include/linux/hrtimer.h2
-rw-r--r--kernel/hrtimer.c4
-rw-r--r--kernel/time/clocksource.c18
3 files changed, 20 insertions, 4 deletions
diff --git a/include/linux/hrtimer.h b/include/linux/hrtimer.h
index 0d2f7c8a33d6..58021b0c396d 100644
--- a/include/linux/hrtimer.h
+++ b/include/linux/hrtimer.h
@@ -305,7 +305,7 @@ static inline int hrtimer_is_hres_active(struct hrtimer *timer)
305 305
306extern ktime_t ktime_get(void); 306extern ktime_t ktime_get(void);
307extern ktime_t ktime_get_real(void); 307extern ktime_t ktime_get_real(void);
308 308extern int hrtimer_hres_active(void);
309 309
310DECLARE_PER_CPU(struct tick_device, tick_cpu_device); 310DECLARE_PER_CPU(struct tick_device, tick_cpu_device);
311 311
diff --git a/kernel/hrtimer.c b/kernel/hrtimer.c
index cb8a15c19583..1a70c18cdffe 100644
--- a/kernel/hrtimer.c
+++ b/kernel/hrtimer.c
@@ -476,7 +476,7 @@ static inline int hrtimer_is_hres_enabled(void)
476/* 476/*
477 * Is the high resolution mode active ? 477 * Is the high resolution mode active ?
478 */ 478 */
479static inline int hrtimer_hres_active(void) 479int hrtimer_hres_active(void)
480{ 480{
481 return __get_cpu_var(hrtimer_bases).hres_active; 481 return __get_cpu_var(hrtimer_bases).hres_active;
482} 482}
@@ -704,7 +704,7 @@ static int hrtimer_switch_to_hres(void)
704 704
705#else 705#else
706 706
707static inline int hrtimer_hres_active(void) { return 0; } 707int hrtimer_hres_active(void) { return 0; }
708static inline int hrtimer_is_hres_enabled(void) { return 0; } 708static inline int hrtimer_is_hres_enabled(void) { return 0; }
709static inline int hrtimer_switch_to_hres(void) { return 0; } 709static inline int hrtimer_switch_to_hres(void) { return 0; }
710static inline void hrtimer_force_reprogram(struct hrtimer_cpu_base *base) { } 710static inline void hrtimer_force_reprogram(struct hrtimer_cpu_base *base) { }
diff --git a/kernel/time/clocksource.c b/kernel/time/clocksource.c
index 80189f6f1c5a..18b9f5da4ee9 100644
--- a/kernel/time/clocksource.c
+++ b/kernel/time/clocksource.c
@@ -30,6 +30,7 @@
30#include <linux/module.h> 30#include <linux/module.h>
31#include <linux/sched.h> /* for spin_unlock_irq() using preempt_count() m68k */ 31#include <linux/sched.h> /* for spin_unlock_irq() using preempt_count() m68k */
32#include <linux/tick.h> 32#include <linux/tick.h>
33#include <linux/hrtimer.h>
33 34
34void timecounter_init(struct timecounter *tc, 35void timecounter_init(struct timecounter *tc,
35 const struct cyclecounter *cc, 36 const struct cyclecounter *cc,
@@ -509,6 +510,18 @@ static ssize_t sysfs_override_clocksource(struct sys_device *dev,
509 } 510 }
510 } 511 }
511 512
513 /*
514 * Check to make sure we don't switch to a non-HRT usable
515 * clocksource if HRT is enabled and running
516 */
517 if (hrtimer_hres_active() &&
518 !(ovr->flags & CLOCK_SOURCE_VALID_FOR_HRES)) {
519 printk(KERN_WARNING "%s clocksource is not HRT compatible. "
520 "Cannot switch while in HRT mode\n", ovr->name);
521 ovr = NULL;
522 override_name[0] = 0;
523 }
524
512 /* Reselect, when the override name has changed */ 525 /* Reselect, when the override name has changed */
513 if (ovr != clocksource_override) { 526 if (ovr != clocksource_override) {
514 clocksource_override = ovr; 527 clocksource_override = ovr;
@@ -537,7 +550,10 @@ sysfs_show_available_clocksources(struct sys_device *dev,
537 550
538 spin_lock_irq(&clocksource_lock); 551 spin_lock_irq(&clocksource_lock);
539 list_for_each_entry(src, &clocksource_list, list) { 552 list_for_each_entry(src, &clocksource_list, list) {
540 count += snprintf(buf + count, 553 /* Don't show non-HRES clocksource if HRES is enabled */
554 if (!hrtimer_hres_active() ||
555 (src->flags & CLOCK_SOURCE_VALID_FOR_HRES))
556 count += snprintf(buf + count,
541 max((ssize_t)PAGE_SIZE - count, (ssize_t)0), 557 max((ssize_t)PAGE_SIZE - count, (ssize_t)0),
542 "%s ", src->name); 558 "%s ", src->name);
543 } 559 }