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@xxxxxxxxxx> --- include/linux/hrtimer.h | 3 +++ kernel/hrtimer.c | 47 +++++++++++++++++++++++++++++++++++++++-------- 2 files changed, 42 insertions(+), 8 deletions(-) diff --git a/include/linux/hrtimer.h b/include/linux/hrtimer.h index 9fdb67b..0718753 100644 --- a/include/linux/hrtimer.h +++ b/include/linux/hrtimer.h @@ -350,6 +350,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 853dd8c..e8cd1db 100644 --- a/kernel/hrtimer.c +++ b/kernel/hrtimer.c @@ -1633,17 +1633,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); @@ -1655,6 +1659,10 @@ static void migrate_hrtimer_list(struct hrtimer_clock_base *old_base, __remove_hrtimer(timer, HRTIMER_STATE_MIGRATE, 0); is_pinned = timer->state & HRTIMER_STATE_PINNED; + if (!remove_pinned && is_pinned) { + timerqueue_add(&pinned, &timer->node); + continue; + } /* Check if CPU still has pinned timers */ if (unlikely(WARN(is_pinned, @@ -1676,18 +1684,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); + 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; struct hrtimer_clock_base *clock_base; unsigned int active_bases; int i; - BUG_ON(cpu_online(scpu)); - tick_cancel_sched_timer(scpu); - local_irq_disable(); old_base = &per_cpu(hrtimer_bases, scpu); new_base = &__get_cpu_var(hrtimer_bases); @@ -1700,7 +1714,8 @@ static void migrate_hrtimers(int scpu) for_each_active_base(i, clock_base, old_base, active_bases) migrate_hrtimer_list(clock_base, - &new_base->clock_base[clock_base->index]); + &new_base->clock_base[clock_base->index], + remove_pinned); raw_spin_unlock(&old_base->lock); raw_spin_unlock(&new_base->lock); @@ -1709,9 +1724,25 @@ static void migrate_hrtimers(int scpu) __hrtimer_peek_ahead_timers(); local_irq_enable(); } +#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) { -- 1.7.12.rc2.18.g61b472e -- To unsubscribe from this list: send the line "unsubscribe cgroups" in the body of a message to majordomo@xxxxxxxxxxxxxxx More majordomo info at http://vger.kernel.org/majordomo-info.html