Skip to content

Commit

Permalink
clocksource: Make watchdog robust vs. interruption
Browse files Browse the repository at this point in the history
The clocksource watchdog code is interruptible and it has been
observed that this can trigger false positives which disable the TSC.

The reason is that an interrupt storm or a long running interrupt
handler between the read of the watchdog source and the read of the
TSC brings the two far enough apart that the delta is larger than the
unstable treshold. Move both reads into a short interrupt disabled
region to avoid that.

Reported-and-tested-by: Vernon Mauery <[email protected]>
Signed-off-by: Thomas Gleixner <[email protected]>
Cc: [email protected]
  • Loading branch information
KAGA-KOKO committed Jun 16, 2011
1 parent 1123d93 commit b519951
Show file tree
Hide file tree
Showing 2 changed files with 14 additions and 11 deletions.
1 change: 1 addition & 0 deletions include/linux/clocksource.h
Original file line number Diff line number Diff line change
Expand Up @@ -188,6 +188,7 @@ struct clocksource {
#ifdef CONFIG_CLOCKSOURCE_WATCHDOG
/* Watchdog related data, used by the framework */
struct list_head wd_list;
cycle_t cs_last;
cycle_t wd_last;
#endif
} ____cacheline_aligned;
Expand Down
24 changes: 13 additions & 11 deletions kernel/time/clocksource.c
Original file line number Diff line number Diff line change
Expand Up @@ -185,7 +185,6 @@ static struct clocksource *watchdog;
static struct timer_list watchdog_timer;
static DECLARE_WORK(watchdog_work, clocksource_watchdog_work);
static DEFINE_SPINLOCK(watchdog_lock);
static cycle_t watchdog_last;
static int watchdog_running;

static int clocksource_watchdog_kthread(void *data);
Expand Down Expand Up @@ -254,11 +253,6 @@ static void clocksource_watchdog(unsigned long data)
if (!watchdog_running)
goto out;

wdnow = watchdog->read(watchdog);
wd_nsec = clocksource_cyc2ns((wdnow - watchdog_last) & watchdog->mask,
watchdog->mult, watchdog->shift);
watchdog_last = wdnow;

list_for_each_entry(cs, &watchdog_list, wd_list) {

/* Clocksource already marked unstable? */
Expand All @@ -268,19 +262,28 @@ static void clocksource_watchdog(unsigned long data)
continue;
}

local_irq_disable();
csnow = cs->read(cs);
wdnow = watchdog->read(watchdog);
local_irq_enable();

/* Clocksource initialized ? */
if (!(cs->flags & CLOCK_SOURCE_WATCHDOG)) {
cs->flags |= CLOCK_SOURCE_WATCHDOG;
cs->wd_last = csnow;
cs->wd_last = wdnow;
cs->cs_last = csnow;
continue;
}

/* Check the deviation from the watchdog clocksource. */
cs_nsec = clocksource_cyc2ns((csnow - cs->wd_last) &
wd_nsec = clocksource_cyc2ns((wdnow - cs->wd_last) & watchdog->mask,
watchdog->mult, watchdog->shift);

cs_nsec = clocksource_cyc2ns((csnow - cs->cs_last) &
cs->mask, cs->mult, cs->shift);
cs->wd_last = csnow;
cs->cs_last = csnow;
cs->wd_last = wdnow;

/* Check the deviation from the watchdog clocksource. */
if (abs(cs_nsec - wd_nsec) > WATCHDOG_THRESHOLD) {
clocksource_unstable(cs, cs_nsec - wd_nsec);
continue;
Expand Down Expand Up @@ -318,7 +321,6 @@ static inline void clocksource_start_watchdog(void)
return;
init_timer(&watchdog_timer);
watchdog_timer.function = clocksource_watchdog;
watchdog_last = watchdog->read(watchdog);
watchdog_timer.expires = jiffies + WATCHDOG_INTERVAL;
add_timer_on(&watchdog_timer, cpumask_first(cpu_online_mask));
watchdog_running = 1;
Expand Down

0 comments on commit b519951

Please sign in to comment.