Skip to content

Commit fe282c6

Browse files
committed
Merge branch 'timers-urgent-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip
Pull clocksource fixes from Thomas Gleixner: "The recent addition of the early TSC clocksource breaks on machines which have an unstable TSC because in case that TSC is disabled, then the clocksource selection logic falls back to the early TSC which is obviously bogus. That also unearthed a few robustness issues in the clocksource derating code which are addressed as well" * 'timers-urgent-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip: clocksource: Rework stale comment clocksource: Consistent de-rate when marking unstable x86/tsc: Fix mark_tsc_unstable() clocksource: Initialize cs->wd_list clocksource: Allow clocksource_mark_unstable() on unregistered clocksources x86/tsc: Always unregister clocksource_tsc_early
2 parents 03b5f0c + 7dba33c commit fe282c6

File tree

2 files changed

+55
-30
lines changed

2 files changed

+55
-30
lines changed

arch/x86/kernel/tsc.c

Lines changed: 11 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1067,6 +1067,7 @@ static struct clocksource clocksource_tsc_early = {
10671067
.resume = tsc_resume,
10681068
.mark_unstable = tsc_cs_mark_unstable,
10691069
.tick_stable = tsc_cs_tick_stable,
1070+
.list = LIST_HEAD_INIT(clocksource_tsc_early.list),
10701071
};
10711072

10721073
/*
@@ -1086,6 +1087,7 @@ static struct clocksource clocksource_tsc = {
10861087
.resume = tsc_resume,
10871088
.mark_unstable = tsc_cs_mark_unstable,
10881089
.tick_stable = tsc_cs_tick_stable,
1090+
.list = LIST_HEAD_INIT(clocksource_tsc.list),
10891091
};
10901092

10911093
void mark_tsc_unstable(char *reason)
@@ -1098,13 +1100,9 @@ void mark_tsc_unstable(char *reason)
10981100
clear_sched_clock_stable();
10991101
disable_sched_clock_irqtime();
11001102
pr_info("Marking TSC unstable due to %s\n", reason);
1101-
/* Change only the rating, when not registered */
1102-
if (clocksource_tsc.mult) {
1103-
clocksource_mark_unstable(&clocksource_tsc);
1104-
} else {
1105-
clocksource_tsc.flags |= CLOCK_SOURCE_UNSTABLE;
1106-
clocksource_tsc.rating = 0;
1107-
}
1103+
1104+
clocksource_mark_unstable(&clocksource_tsc_early);
1105+
clocksource_mark_unstable(&clocksource_tsc);
11081106
}
11091107

11101108
EXPORT_SYMBOL_GPL(mark_tsc_unstable);
@@ -1244,7 +1242,7 @@ static void tsc_refine_calibration_work(struct work_struct *work)
12441242

12451243
/* Don't bother refining TSC on unstable systems */
12461244
if (tsc_unstable)
1247-
return;
1245+
goto unreg;
12481246

12491247
/*
12501248
* Since the work is started early in boot, we may be
@@ -1297,11 +1295,12 @@ static void tsc_refine_calibration_work(struct work_struct *work)
12971295

12981296
out:
12991297
if (tsc_unstable)
1300-
return;
1298+
goto unreg;
13011299

13021300
if (boot_cpu_has(X86_FEATURE_ART))
13031301
art_related_clocksource = &clocksource_tsc;
13041302
clocksource_register_khz(&clocksource_tsc, tsc_khz);
1303+
unreg:
13051304
clocksource_unregister(&clocksource_tsc_early);
13061305
}
13071306

@@ -1311,8 +1310,8 @@ static int __init init_tsc_clocksource(void)
13111310
if (!boot_cpu_has(X86_FEATURE_TSC) || tsc_disabled > 0 || !tsc_khz)
13121311
return 0;
13131312

1314-
if (check_tsc_unstable())
1315-
return 0;
1313+
if (tsc_unstable)
1314+
goto unreg;
13161315

13171316
if (tsc_clocksource_reliable)
13181317
clocksource_tsc.flags &= ~CLOCK_SOURCE_MUST_VERIFY;
@@ -1328,6 +1327,7 @@ static int __init init_tsc_clocksource(void)
13281327
if (boot_cpu_has(X86_FEATURE_ART))
13291328
art_related_clocksource = &clocksource_tsc;
13301329
clocksource_register_khz(&clocksource_tsc, tsc_khz);
1330+
unreg:
13311331
clocksource_unregister(&clocksource_tsc_early);
13321332
return 0;
13331333
}

kernel/time/clocksource.c

Lines changed: 44 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -119,6 +119,16 @@ static DEFINE_SPINLOCK(watchdog_lock);
119119
static int watchdog_running;
120120
static atomic_t watchdog_reset_pending;
121121

122+
static void inline clocksource_watchdog_lock(unsigned long *flags)
123+
{
124+
spin_lock_irqsave(&watchdog_lock, *flags);
125+
}
126+
127+
static void inline clocksource_watchdog_unlock(unsigned long *flags)
128+
{
129+
spin_unlock_irqrestore(&watchdog_lock, *flags);
130+
}
131+
122132
static int clocksource_watchdog_kthread(void *data);
123133
static void __clocksource_change_rating(struct clocksource *cs, int rating);
124134

@@ -142,9 +152,19 @@ static void __clocksource_unstable(struct clocksource *cs)
142152
cs->flags &= ~(CLOCK_SOURCE_VALID_FOR_HRES | CLOCK_SOURCE_WATCHDOG);
143153
cs->flags |= CLOCK_SOURCE_UNSTABLE;
144154

155+
/*
156+
* If the clocksource is registered clocksource_watchdog_kthread() will
157+
* re-rate and re-select.
158+
*/
159+
if (list_empty(&cs->list)) {
160+
cs->rating = 0;
161+
return;
162+
}
163+
145164
if (cs->mark_unstable)
146165
cs->mark_unstable(cs);
147166

167+
/* kick clocksource_watchdog_kthread() */
148168
if (finished_booting)
149169
schedule_work(&watchdog_work);
150170
}
@@ -153,18 +173,16 @@ static void __clocksource_unstable(struct clocksource *cs)
153173
* clocksource_mark_unstable - mark clocksource unstable via watchdog
154174
* @cs: clocksource to be marked unstable
155175
*
156-
* This function is called instead of clocksource_change_rating from
157-
* cpu hotplug code to avoid a deadlock between the clocksource mutex
158-
* and the cpu hotplug mutex. It defers the update of the clocksource
159-
* to the watchdog thread.
176+
* This function is called by the x86 TSC code to mark clocksources as unstable;
177+
* it defers demotion and re-selection to a kthread.
160178
*/
161179
void clocksource_mark_unstable(struct clocksource *cs)
162180
{
163181
unsigned long flags;
164182

165183
spin_lock_irqsave(&watchdog_lock, flags);
166184
if (!(cs->flags & CLOCK_SOURCE_UNSTABLE)) {
167-
if (list_empty(&cs->wd_list))
185+
if (!list_empty(&cs->list) && list_empty(&cs->wd_list))
168186
list_add(&cs->wd_list, &watchdog_list);
169187
__clocksource_unstable(cs);
170188
}
@@ -319,9 +337,8 @@ static void clocksource_resume_watchdog(void)
319337

320338
static void clocksource_enqueue_watchdog(struct clocksource *cs)
321339
{
322-
unsigned long flags;
340+
INIT_LIST_HEAD(&cs->wd_list);
323341

324-
spin_lock_irqsave(&watchdog_lock, flags);
325342
if (cs->flags & CLOCK_SOURCE_MUST_VERIFY) {
326343
/* cs is a clocksource to be watched. */
327344
list_add(&cs->wd_list, &watchdog_list);
@@ -331,7 +348,6 @@ static void clocksource_enqueue_watchdog(struct clocksource *cs)
331348
if (cs->flags & CLOCK_SOURCE_IS_CONTINUOUS)
332349
cs->flags |= CLOCK_SOURCE_VALID_FOR_HRES;
333350
}
334-
spin_unlock_irqrestore(&watchdog_lock, flags);
335351
}
336352

337353
static void clocksource_select_watchdog(bool fallback)
@@ -373,9 +389,6 @@ static void clocksource_select_watchdog(bool fallback)
373389

374390
static void clocksource_dequeue_watchdog(struct clocksource *cs)
375391
{
376-
unsigned long flags;
377-
378-
spin_lock_irqsave(&watchdog_lock, flags);
379392
if (cs != watchdog) {
380393
if (cs->flags & CLOCK_SOURCE_MUST_VERIFY) {
381394
/* cs is a watched clocksource. */
@@ -384,21 +397,19 @@ static void clocksource_dequeue_watchdog(struct clocksource *cs)
384397
clocksource_stop_watchdog();
385398
}
386399
}
387-
spin_unlock_irqrestore(&watchdog_lock, flags);
388400
}
389401

390402
static int __clocksource_watchdog_kthread(void)
391403
{
392404
struct clocksource *cs, *tmp;
393405
unsigned long flags;
394-
LIST_HEAD(unstable);
395406
int select = 0;
396407

397408
spin_lock_irqsave(&watchdog_lock, flags);
398409
list_for_each_entry_safe(cs, tmp, &watchdog_list, wd_list) {
399410
if (cs->flags & CLOCK_SOURCE_UNSTABLE) {
400411
list_del_init(&cs->wd_list);
401-
list_add(&cs->wd_list, &unstable);
412+
__clocksource_change_rating(cs, 0);
402413
select = 1;
403414
}
404415
if (cs->flags & CLOCK_SOURCE_RESELECT) {
@@ -410,11 +421,6 @@ static int __clocksource_watchdog_kthread(void)
410421
clocksource_stop_watchdog();
411422
spin_unlock_irqrestore(&watchdog_lock, flags);
412423

413-
/* Needs to be done outside of watchdog lock */
414-
list_for_each_entry_safe(cs, tmp, &unstable, wd_list) {
415-
list_del_init(&cs->wd_list);
416-
__clocksource_change_rating(cs, 0);
417-
}
418424
return select;
419425
}
420426

@@ -447,6 +453,9 @@ static inline int __clocksource_watchdog_kthread(void) { return 0; }
447453
static bool clocksource_is_watchdog(struct clocksource *cs) { return false; }
448454
void clocksource_mark_unstable(struct clocksource *cs) { }
449455

456+
static void inline clocksource_watchdog_lock(unsigned long *flags) { }
457+
static void inline clocksource_watchdog_unlock(unsigned long *flags) { }
458+
450459
#endif /* CONFIG_CLOCKSOURCE_WATCHDOG */
451460

452461
/**
@@ -779,14 +788,19 @@ EXPORT_SYMBOL_GPL(__clocksource_update_freq_scale);
779788
*/
780789
int __clocksource_register_scale(struct clocksource *cs, u32 scale, u32 freq)
781790
{
791+
unsigned long flags;
782792

783793
/* Initialize mult/shift and max_idle_ns */
784794
__clocksource_update_freq_scale(cs, scale, freq);
785795

786796
/* Add clocksource to the clocksource list */
787797
mutex_lock(&clocksource_mutex);
798+
799+
clocksource_watchdog_lock(&flags);
788800
clocksource_enqueue(cs);
789801
clocksource_enqueue_watchdog(cs);
802+
clocksource_watchdog_unlock(&flags);
803+
790804
clocksource_select();
791805
clocksource_select_watchdog(false);
792806
mutex_unlock(&clocksource_mutex);
@@ -808,8 +822,13 @@ static void __clocksource_change_rating(struct clocksource *cs, int rating)
808822
*/
809823
void clocksource_change_rating(struct clocksource *cs, int rating)
810824
{
825+
unsigned long flags;
826+
811827
mutex_lock(&clocksource_mutex);
828+
clocksource_watchdog_lock(&flags);
812829
__clocksource_change_rating(cs, rating);
830+
clocksource_watchdog_unlock(&flags);
831+
813832
clocksource_select();
814833
clocksource_select_watchdog(false);
815834
mutex_unlock(&clocksource_mutex);
@@ -821,6 +840,8 @@ EXPORT_SYMBOL(clocksource_change_rating);
821840
*/
822841
static int clocksource_unbind(struct clocksource *cs)
823842
{
843+
unsigned long flags;
844+
824845
if (clocksource_is_watchdog(cs)) {
825846
/* Select and try to install a replacement watchdog. */
826847
clocksource_select_watchdog(true);
@@ -834,8 +855,12 @@ static int clocksource_unbind(struct clocksource *cs)
834855
if (curr_clocksource == cs)
835856
return -EBUSY;
836857
}
858+
859+
clocksource_watchdog_lock(&flags);
837860
clocksource_dequeue_watchdog(cs);
838861
list_del_init(&cs->list);
862+
clocksource_watchdog_unlock(&flags);
863+
839864
return 0;
840865
}
841866

0 commit comments

Comments
 (0)