Re: [BUG-REPORT] hrtick_start_fair and CPU-Hotplug

Peter Zijlstra
2008-04-29T08:03:29Z

On Tue, 2008-04-29 at 08:59 +0200, Peter Zijlstra wrote:
> On Tue, 2008-04-29 at 12:22 +0530, Gautham R Shenoy wrote:
> > Hello!
> >
> > While running the usual CPU-Hotplug stress tests on linux-2.6.25,
> > I noticed the following in the console logs.
> >
> > This is a wee bit difficult to reproduce. In the past 10 runs I hit this
> > only once.
> >
> > ------------[ cut here ]------------
> >
> > WARNING: at kernel/sched.c:962 hrtick+0x2e/0x65()
>
> > I am not well versed with this part of the code, so just wondering if we
> > are doing a good job at handling the cancellation of any per-cpu
> > scheduler timers during CPU-Hotplug.
>
> This looks like its not cancelled at all and migrates the it to another
> cpu. I'll see what I can come up with.

Signed-off-by: Peter Zijlstra <a.p.zijlstra@chello.nl>
---
kernel/sched.c | 66 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++-
1 file changed, 65 insertions(+), 1 deletion(-)

Index: linux-2.6-2/kernel/sched.c
===================================================================
--- linux-2.6-2.orig/kernel/sched.c
+++ linux-2.6-2/kernel/sched.c
@@ -1201,6 +1201,7 @@ static inline void resched_rq(struct rq
enum {
HRTICK_SET, /* re-programm hrtick_timer */
HRTICK_RESET, /* not a new slice */
+ HRTICK_BLOCK, /* stop hrtick operations */
};

/*
@@ -1212,6 +1213,8 @@ static inline int hrtick_enabled(struct
{
if (!sched_feat(HRTICK))
return 0;
+ if (unlikely(test_bit(HRTICK_BLOCK, &rq->hrtick_flags)))
+ return 0;
return hrtimer_is_hres_active(&rq->hrtick_timer);
}

@@ -1294,7 +1297,63 @@ static enum hrtimer_restart hrtick(struc
return HRTIMER_NORESTART;
}

-static inline void init_rq_hrtick(struct rq *rq)
+static void hotplug_hrtick_disable(int cpu)
+{
+ struct rq *rq = cpu_rq(cpu);
+ unsigned long flags;
+
+ spin_lock_irqsave(&rq->lock, flags);
+ rq->hrtick_flags = 0;
+ __set_bit(HRTICK_BLOCK, &rq->hrtick_flags);
+ spin_unlock_irqrestore(&rq->lock, flags);
+
+ hrtick_clear(rq);
+}
+
+static void hotplug_hrtick_enable(int cpu)
+{
+ struct rq *rq = cpu_rq(cpu);
+ unsigned long flags;
+
+ spin_lock_irqsave(&rq->lock, flags);
+ __clear_bit(HRTICK_BLOCK, &rq->hrtick_flags);
+ spin_unlock_irqrestore(&rq->lock, flags);
+}
+
+static int
+hotplug_hrtick(struct notifier_block *nfb, unsigned long action, void *hcpu)
+{
+ int cpu = (int)hcpu;
+
+ switch (action) {
+ case CPU_UP_CANCELED:
+ case CPU_UP_CANCELED_FROZEN:
+ case CPU_DOWN_PREPARE:
+ case CPU_DOWN_PREPARE_FROZEN:
+ case CPU_DEAD:
+ case CPU_DEAD_FROZEN:
+ hotplug_hrtick_disable(cpu);
+ return NOTIFY_OK;
+
+ case CPU_UP_PREPARE:
+ case CPU_UP_PREPARE_FROZEN:
+ case CPU_DOWN_FAILED:
+ case CPU_DOWN_FAILED_FROZEN:
+ case CPU_ONLINE:
+ case CPU_ONLINE_FROZEN:
+ hotplug_hrtick_enable(cpu);
+ return NOTIFY_OK;
+ }
+
+ return NOTIFY_DONE;
+}
+
+static void init_hrtick(void)
+{
+ hotcpu_notifier(hotplug_hrtick, 0);
+}
+
+static void init_rq_hrtick(struct rq *rq)
{
rq->hrtick_flags = 0;
hrtimer_init(&rq->hrtick_timer, CLOCK_MONOTONIC, HRTIMER_MODE_REL);
@@ -1331,6 +1390,10 @@ static inline void init_rq_hrtick(struct
void hrtick_resched(void)
{
}
+
+static inline void init_hrtick(void)
+{
+}
#endif

/*
@@ -7964,6 +8027,7 @@ void __init sched_init_smp(void)
put_online_cpus();
/* XXX: Theoretical race here - CPU may be hotplugged now */
hotcpu_notifier(update_sched_domains, 0);
+ init_hrtick();

/* Move init over to a non-isolated CPU */
if (set_cpus_allowed_ptr(current, &non_isolated_cpus) < 0)