aboutsummaryrefslogtreecommitdiffstats
path: root/kernel/sched.c
diff options
context:
space:
mode:
Diffstat (limited to 'kernel/sched.c')
-rw-r--r--kernel/sched.c129
1 files changed, 127 insertions, 2 deletions
diff --git a/kernel/sched.c b/kernel/sched.c
index 7c9098d186e6..9ae80bec1c1e 100644
--- a/kernel/sched.c
+++ b/kernel/sched.c
@@ -7024,6 +7024,11 @@ fail:
7024 return ret; 7024 return ret;
7025} 7025}
7026 7026
7027#define RCU_MIGRATION_IDLE 0
7028#define RCU_MIGRATION_NEED_QS 1
7029#define RCU_MIGRATION_GOT_QS 2
7030#define RCU_MIGRATION_MUST_SYNC 3
7031
7027/* 7032/*
7028 * migration_thread - this is a highprio system thread that performs 7033 * migration_thread - this is a highprio system thread that performs
7029 * thread migration by bumping thread off CPU then 'pushing' onto 7034 * thread migration by bumping thread off CPU then 'pushing' onto
@@ -7031,6 +7036,7 @@ fail:
7031 */ 7036 */
7032static int migration_thread(void *data) 7037static int migration_thread(void *data)
7033{ 7038{
7039 int badcpu;
7034 int cpu = (long)data; 7040 int cpu = (long)data;
7035 struct rq *rq; 7041 struct rq *rq;
7036 7042
@@ -7065,8 +7071,17 @@ static int migration_thread(void *data)
7065 req = list_entry(head->next, struct migration_req, list); 7071 req = list_entry(head->next, struct migration_req, list);
7066 list_del_init(head->next); 7072 list_del_init(head->next);
7067 7073
7068 spin_unlock(&rq->lock); 7074 if (req->task != NULL) {
7069 __migrate_task(req->task, cpu, req->dest_cpu); 7075 spin_unlock(&rq->lock);
7076 __migrate_task(req->task, cpu, req->dest_cpu);
7077 } else if (likely(cpu == (badcpu = smp_processor_id()))) {
7078 req->dest_cpu = RCU_MIGRATION_GOT_QS;
7079 spin_unlock(&rq->lock);
7080 } else {
7081 req->dest_cpu = RCU_MIGRATION_MUST_SYNC;
7082 spin_unlock(&rq->lock);
7083 WARN_ONCE(1, "migration_thread() on CPU %d, expected %d\n", badcpu, cpu);
7084 }
7070 local_irq_enable(); 7085 local_irq_enable();
7071 7086
7072 complete(&req->done); 7087 complete(&req->done);
@@ -10554,3 +10569,113 @@ struct cgroup_subsys cpuacct_subsys = {
10554 .subsys_id = cpuacct_subsys_id, 10569 .subsys_id = cpuacct_subsys_id,
10555}; 10570};
10556#endif /* CONFIG_CGROUP_CPUACCT */ 10571#endif /* CONFIG_CGROUP_CPUACCT */
10572
10573#ifndef CONFIG_SMP
10574
10575int rcu_expedited_torture_stats(char *page)
10576{
10577 return 0;
10578}
10579EXPORT_SYMBOL_GPL(rcu_expedited_torture_stats);
10580
10581void synchronize_sched_expedited(void)
10582{
10583}
10584EXPORT_SYMBOL_GPL(synchronize_sched_expedited);
10585
10586#else /* #ifndef CONFIG_SMP */
10587
10588static DEFINE_PER_CPU(struct migration_req, rcu_migration_req);
10589static DEFINE_MUTEX(rcu_sched_expedited_mutex);
10590
10591#define RCU_EXPEDITED_STATE_POST -2
10592#define RCU_EXPEDITED_STATE_IDLE -1
10593
10594static int rcu_expedited_state = RCU_EXPEDITED_STATE_IDLE;
10595
10596int rcu_expedited_torture_stats(char *page)
10597{
10598 int cnt = 0;
10599 int cpu;
10600
10601 cnt += sprintf(&page[cnt], "state: %d /", rcu_expedited_state);
10602 for_each_online_cpu(cpu) {
10603 cnt += sprintf(&page[cnt], " %d:%d",
10604 cpu, per_cpu(rcu_migration_req, cpu).dest_cpu);
10605 }
10606 cnt += sprintf(&page[cnt], "\n");
10607 return cnt;
10608}
10609EXPORT_SYMBOL_GPL(rcu_expedited_torture_stats);
10610
10611static long synchronize_sched_expedited_count;
10612
10613/*
10614 * Wait for an rcu-sched grace period to elapse, but use "big hammer"
10615 * approach to force grace period to end quickly. This consumes
10616 * significant time on all CPUs, and is thus not recommended for
10617 * any sort of common-case code.
10618 *
10619 * Note that it is illegal to call this function while holding any
10620 * lock that is acquired by a CPU-hotplug notifier. Failing to
10621 * observe this restriction will result in deadlock.
10622 */
10623void synchronize_sched_expedited(void)
10624{
10625 int cpu;
10626 unsigned long flags;
10627 bool need_full_sync = 0;
10628 struct rq *rq;
10629 struct migration_req *req;
10630 long snap;
10631 int trycount = 0;
10632
10633 smp_mb(); /* ensure prior mod happens before capturing snap. */
10634 snap = ACCESS_ONCE(synchronize_sched_expedited_count) + 1;
10635 get_online_cpus();
10636 while (!mutex_trylock(&rcu_sched_expedited_mutex)) {
10637 put_online_cpus();
10638 if (trycount++ < 10)
10639 udelay(trycount * num_online_cpus());
10640 else {
10641 synchronize_sched();
10642 return;
10643 }
10644 if (ACCESS_ONCE(synchronize_sched_expedited_count) - snap > 0) {
10645 smp_mb(); /* ensure test happens before caller kfree */
10646 return;
10647 }
10648 get_online_cpus();
10649 }
10650 rcu_expedited_state = RCU_EXPEDITED_STATE_POST;
10651 for_each_online_cpu(cpu) {
10652 rq = cpu_rq(cpu);
10653 req = &per_cpu(rcu_migration_req, cpu);
10654 init_completion(&req->done);
10655 req->task = NULL;
10656 req->dest_cpu = RCU_MIGRATION_NEED_QS;
10657 spin_lock_irqsave(&rq->lock, flags);
10658 list_add(&req->list, &rq->migration_queue);
10659 spin_unlock_irqrestore(&rq->lock, flags);
10660 wake_up_process(rq->migration_thread);
10661 }
10662 for_each_online_cpu(cpu) {
10663 rcu_expedited_state = cpu;
10664 req = &per_cpu(rcu_migration_req, cpu);
10665 rq = cpu_rq(cpu);
10666 wait_for_completion(&req->done);
10667 spin_lock_irqsave(&rq->lock, flags);
10668 if (unlikely(req->dest_cpu == RCU_MIGRATION_MUST_SYNC))
10669 need_full_sync = 1;
10670 req->dest_cpu = RCU_MIGRATION_IDLE;
10671 spin_unlock_irqrestore(&rq->lock, flags);
10672 }
10673 rcu_expedited_state = RCU_EXPEDITED_STATE_IDLE;
10674 mutex_unlock(&rcu_sched_expedited_mutex);
10675 put_online_cpus();
10676 if (need_full_sync)
10677 synchronize_sched();
10678}
10679EXPORT_SYMBOL_GPL(synchronize_sched_expedited);
10680
10681#endif /* #else #ifndef CONFIG_SMP */