diff options
Diffstat (limited to 'kernel/sched.c')
-rw-r--r-- | kernel/sched.c | 129 |
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 | */ |
7032 | static int migration_thread(void *data) | 7037 | static 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 | |||
10575 | int rcu_expedited_torture_stats(char *page) | ||
10576 | { | ||
10577 | return 0; | ||
10578 | } | ||
10579 | EXPORT_SYMBOL_GPL(rcu_expedited_torture_stats); | ||
10580 | |||
10581 | void synchronize_sched_expedited(void) | ||
10582 | { | ||
10583 | } | ||
10584 | EXPORT_SYMBOL_GPL(synchronize_sched_expedited); | ||
10585 | |||
10586 | #else /* #ifndef CONFIG_SMP */ | ||
10587 | |||
10588 | static DEFINE_PER_CPU(struct migration_req, rcu_migration_req); | ||
10589 | static DEFINE_MUTEX(rcu_sched_expedited_mutex); | ||
10590 | |||
10591 | #define RCU_EXPEDITED_STATE_POST -2 | ||
10592 | #define RCU_EXPEDITED_STATE_IDLE -1 | ||
10593 | |||
10594 | static int rcu_expedited_state = RCU_EXPEDITED_STATE_IDLE; | ||
10595 | |||
10596 | int 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 | } | ||
10609 | EXPORT_SYMBOL_GPL(rcu_expedited_torture_stats); | ||
10610 | |||
10611 | static 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 | */ | ||
10623 | void 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 | } | ||
10679 | EXPORT_SYMBOL_GPL(synchronize_sched_expedited); | ||
10680 | |||
10681 | #endif /* #else #ifndef CONFIG_SMP */ | ||