diff options
author | Viresh Kumar <viresh.kumar@linaro.org> | 2014-04-02 11:08:03 +0530 |
---|---|---|
committer | Viresh Kumar <viresh.kumar@linaro.org> | 2014-09-05 09:52:49 +0530 |
commit | 8b423157551ab27059426e8650728e55291f00ba (patch) | |
tree | 2527ea69d2a759b206f707460c97386592975cfd | |
parent | b78a9dffa19cfd6e5cef283c1b040b0429a0738e (diff) |
hrtimer: create hrtimer_quiesce_cpu() to isolate CPU from hrtimers
To isolate CPUs (isolate from hrtimers) from sysfs using cpusets, we need some
support from the hrtimer core. i.e. A routine hrtimer_quiesce_cpu() which would
migrate away all the unpinned hrtimers, but shouldn't touch the pinned ones.
This patch creates this routine.
Signed-off-by: Viresh Kumar <viresh.kumar@linaro.org>
-rw-r--r-- | include/linux/hrtimer.h | 3 | ||||
-rw-r--r-- | kernel/hrtimer.c | 55 |
2 files changed, 48 insertions, 10 deletions
diff --git a/include/linux/hrtimer.h b/include/linux/hrtimer.h index bce081c68c3b..9f593e8a561b 100644 --- a/include/linux/hrtimer.h +++ b/include/linux/hrtimer.h @@ -340,6 +340,9 @@ DECLARE_PER_CPU(struct tick_device, tick_cpu_device); /* Exported timer functions: */ +/* To be used from cpusets, only */ +extern void hrtimer_quiesce_cpu(void *cpup); + /* Initialize timers: */ extern void hrtimer_init(struct hrtimer *timer, clockid_t which_clock, enum hrtimer_mode mode); diff --git a/kernel/hrtimer.c b/kernel/hrtimer.c index 25bd820f8dc9..1ebb7a1b2809 100644 --- a/kernel/hrtimer.c +++ b/kernel/hrtimer.c @@ -1668,16 +1668,21 @@ static void init_hrtimers_cpu(int cpu) hrtimer_init_hres(cpu_base); } -#ifdef CONFIG_HOTPLUG_CPU - +#if defined(CONFIG_HOTPLUG_CPU) || defined(CONFIG_CPUSETS) static void migrate_hrtimer_list(struct hrtimer_clock_base *old_base, - struct hrtimer_clock_base *new_base) + struct hrtimer_clock_base *new_base, + bool remove_pinned) { struct hrtimer *timer; struct timerqueue_node *node; + struct timerqueue_head pinned; + int is_pinned; + + timerqueue_init_head(&pinned); while ((node = timerqueue_getnext(&old_base->active))) { timer = container_of(node, struct hrtimer, node); + BUG_ON(hrtimer_callback_running(timer)); debug_deactivate(timer); @@ -1687,6 +1692,13 @@ static void migrate_hrtimer_list(struct hrtimer_clock_base *old_base, * under us on another CPU */ __remove_hrtimer(timer, old_base, HRTIMER_STATE_MIGRATE, 0); + + is_pinned = timer->state & HRTIMER_STATE_PINNED; + if (!remove_pinned && is_pinned) { + timerqueue_add(&pinned, &timer->node); + continue; + } + timer->base = new_base; /* * Enqueue the timers on the new cpu. This does not @@ -1701,17 +1713,24 @@ static void migrate_hrtimer_list(struct hrtimer_clock_base *old_base, /* Clear the migration state bit */ timer->state &= ~HRTIMER_STATE_MIGRATE; } + + /* Re-queue pinned timers for non-hotplug usecase */ + while ((node = timerqueue_getnext(&pinned))) { + timer = container_of(node, struct hrtimer, node); + + timerqueue_del(&pinned, &timer->node); + enqueue_hrtimer(timer, old_base); + timer->state &= ~HRTIMER_STATE_MIGRATE; + } } -static void migrate_hrtimers(int scpu) +static void __migrate_hrtimers(int scpu, bool remove_pinned) { struct hrtimer_cpu_base *old_base, *new_base; + unsigned long flags; int i; - BUG_ON(cpu_online(scpu)); - tick_cancel_sched_timer(scpu); - - local_irq_disable(); + local_irq_save(flags); old_base = &per_cpu(hrtimer_bases, scpu); new_base = &__get_cpu_var(hrtimer_bases); /* @@ -1723,7 +1742,7 @@ static void migrate_hrtimers(int scpu) for (i = 0; i < HRTIMER_MAX_CLOCK_BASES; i++) { migrate_hrtimer_list(&old_base->clock_base[i], - &new_base->clock_base[i]); + &new_base->clock_base[i], remove_pinned); } raw_spin_unlock(&old_base->lock); @@ -1731,11 +1750,27 @@ static void migrate_hrtimers(int scpu) /* Check, if we got expired work to do */ __hrtimer_peek_ahead_timers(); - local_irq_enable(); + local_irq_restore(flags); } +#endif /* CONFIG_HOTPLUG_CPU || CONFIG_CPUSETS */ +#ifdef CONFIG_HOTPLUG_CPU +static void migrate_hrtimers(int scpu) +{ + BUG_ON(cpu_online(scpu)); + tick_cancel_sched_timer(scpu); + + __migrate_hrtimers(scpu, true); +} #endif /* CONFIG_HOTPLUG_CPU */ +#ifdef CONFIG_CPUSETS +void hrtimer_quiesce_cpu(void *cpup) +{ + __migrate_hrtimers(*(int *)cpup, false); +} +#endif /* CONFIG_CPUSETS */ + static int hrtimer_cpu_notify(struct notifier_block *self, unsigned long action, void *hcpu) { |