diff options
author | Martin Schwidefsky <schwidefsky@de.ibm.com> | 2009-08-18 11:09:42 -0400 |
---|---|---|
committer | Thomas Gleixner <tglx@linutronix.de> | 2009-08-19 06:00:56 -0400 |
commit | 01548f4d3e8e94caf323a4f664eb347fd34a34ab (patch) | |
tree | 2717e7d4dd781be2d57737df96b074451090f3d9 | |
parent | d0981a1b21a03866c8da7f44e35e389c2e0d6061 (diff) |
clocksource: Avoid clocksource watchdog circular locking dependency
stop_machine from a multithreaded workqueue is not allowed because
of a circular locking dependency between cpu_down and the workqueue
execution. Use a kernel thread to do the clocksource downgrade.
Signed-off-by: Martin Schwidefsky <schwidefsky@de.ibm.com>
Cc: Peter Zijlstra <a.p.zijlstra@chello.nl>
Cc: john stultz <johnstul@us.ibm.com>
LKML-Reference: <20090818170942.3ab80c91@skybase>
Signed-off-by: Thomas Gleixner <tglx@linutronix.de>
-rw-r--r-- | kernel/time/clocksource.c | 19 |
1 files changed, 16 insertions, 3 deletions
diff --git a/kernel/time/clocksource.c b/kernel/time/clocksource.c index c6bff11f7957..e0c86ad6e9fb 100644 --- a/kernel/time/clocksource.c +++ b/kernel/time/clocksource.c | |||
@@ -29,6 +29,7 @@ | |||
29 | #include <linux/module.h> | 29 | #include <linux/module.h> |
30 | #include <linux/sched.h> /* for spin_unlock_irq() using preempt_count() m68k */ | 30 | #include <linux/sched.h> /* for spin_unlock_irq() using preempt_count() m68k */ |
31 | #include <linux/tick.h> | 31 | #include <linux/tick.h> |
32 | #include <linux/kthread.h> | ||
32 | 33 | ||
33 | void timecounter_init(struct timecounter *tc, | 34 | void timecounter_init(struct timecounter *tc, |
34 | const struct cyclecounter *cc, | 35 | const struct cyclecounter *cc, |
@@ -130,7 +131,7 @@ static DEFINE_SPINLOCK(watchdog_lock); | |||
130 | static cycle_t watchdog_last; | 131 | static cycle_t watchdog_last; |
131 | static int watchdog_running; | 132 | static int watchdog_running; |
132 | 133 | ||
133 | static void clocksource_watchdog_work(struct work_struct *work); | 134 | static int clocksource_watchdog_kthread(void *data); |
134 | static void __clocksource_change_rating(struct clocksource *cs, int rating); | 135 | static void __clocksource_change_rating(struct clocksource *cs, int rating); |
135 | 136 | ||
136 | /* | 137 | /* |
@@ -139,6 +140,15 @@ static void __clocksource_change_rating(struct clocksource *cs, int rating); | |||
139 | #define WATCHDOG_INTERVAL (HZ >> 1) | 140 | #define WATCHDOG_INTERVAL (HZ >> 1) |
140 | #define WATCHDOG_THRESHOLD (NSEC_PER_SEC >> 4) | 141 | #define WATCHDOG_THRESHOLD (NSEC_PER_SEC >> 4) |
141 | 142 | ||
143 | static void clocksource_watchdog_work(struct work_struct *work) | ||
144 | { | ||
145 | /* | ||
146 | * If kthread_run fails the next watchdog scan over the | ||
147 | * watchdog_list will find the unstable clock again. | ||
148 | */ | ||
149 | kthread_run(clocksource_watchdog_kthread, NULL, "kwatchdog"); | ||
150 | } | ||
151 | |||
142 | static void clocksource_unstable(struct clocksource *cs, int64_t delta) | 152 | static void clocksource_unstable(struct clocksource *cs, int64_t delta) |
143 | { | 153 | { |
144 | printk(KERN_WARNING "Clocksource %s unstable (delta = %Ld ns)\n", | 154 | printk(KERN_WARNING "Clocksource %s unstable (delta = %Ld ns)\n", |
@@ -167,8 +177,10 @@ static void clocksource_watchdog(unsigned long data) | |||
167 | list_for_each_entry(cs, &watchdog_list, wd_list) { | 177 | list_for_each_entry(cs, &watchdog_list, wd_list) { |
168 | 178 | ||
169 | /* Clocksource already marked unstable? */ | 179 | /* Clocksource already marked unstable? */ |
170 | if (cs->flags & CLOCK_SOURCE_UNSTABLE) | 180 | if (cs->flags & CLOCK_SOURCE_UNSTABLE) { |
181 | schedule_work(&watchdog_work); | ||
171 | continue; | 182 | continue; |
183 | } | ||
172 | 184 | ||
173 | csnow = cs->read(cs); | 185 | csnow = cs->read(cs); |
174 | 186 | ||
@@ -304,7 +316,7 @@ static void clocksource_dequeue_watchdog(struct clocksource *cs) | |||
304 | spin_unlock_irqrestore(&watchdog_lock, flags); | 316 | spin_unlock_irqrestore(&watchdog_lock, flags); |
305 | } | 317 | } |
306 | 318 | ||
307 | static void clocksource_watchdog_work(struct work_struct *work) | 319 | static int clocksource_watchdog_kthread(void *data) |
308 | { | 320 | { |
309 | struct clocksource *cs, *tmp; | 321 | struct clocksource *cs, *tmp; |
310 | unsigned long flags; | 322 | unsigned long flags; |
@@ -327,6 +339,7 @@ static void clocksource_watchdog_work(struct work_struct *work) | |||
327 | __clocksource_change_rating(cs, 0); | 339 | __clocksource_change_rating(cs, 0); |
328 | } | 340 | } |
329 | mutex_unlock(&clocksource_mutex); | 341 | mutex_unlock(&clocksource_mutex); |
342 | return 0; | ||
330 | } | 343 | } |
331 | 344 | ||
332 | #else /* CONFIG_CLOCKSOURCE_WATCHDOG */ | 345 | #else /* CONFIG_CLOCKSOURCE_WATCHDOG */ |