diff options
Diffstat (limited to 'kernel/sched.c')
-rw-r--r-- | kernel/sched.c | 71 |
1 files changed, 68 insertions, 3 deletions
diff --git a/kernel/sched.c b/kernel/sched.c index 5757e03cfac0..196d48babbef 100644 --- a/kernel/sched.c +++ b/kernel/sched.c | |||
@@ -4942,15 +4942,13 @@ pick_next_task(struct rq *rq) | |||
4942 | /* | 4942 | /* |
4943 | * schedule() is the main scheduler function. | 4943 | * schedule() is the main scheduler function. |
4944 | */ | 4944 | */ |
4945 | asmlinkage void __sched schedule(void) | 4945 | asmlinkage void __sched __schedule(void) |
4946 | { | 4946 | { |
4947 | struct task_struct *prev, *next; | 4947 | struct task_struct *prev, *next; |
4948 | unsigned long *switch_count; | 4948 | unsigned long *switch_count; |
4949 | struct rq *rq; | 4949 | struct rq *rq; |
4950 | int cpu; | 4950 | int cpu; |
4951 | 4951 | ||
4952 | need_resched: | ||
4953 | preempt_disable(); | ||
4954 | cpu = smp_processor_id(); | 4952 | cpu = smp_processor_id(); |
4955 | rq = cpu_rq(cpu); | 4953 | rq = cpu_rq(cpu); |
4956 | rcu_qsctr_inc(cpu); | 4954 | rcu_qsctr_inc(cpu); |
@@ -5007,13 +5005,80 @@ need_resched_nonpreemptible: | |||
5007 | 5005 | ||
5008 | if (unlikely(reacquire_kernel_lock(current) < 0)) | 5006 | if (unlikely(reacquire_kernel_lock(current) < 0)) |
5009 | goto need_resched_nonpreemptible; | 5007 | goto need_resched_nonpreemptible; |
5008 | } | ||
5010 | 5009 | ||
5010 | asmlinkage void __sched schedule(void) | ||
5011 | { | ||
5012 | need_resched: | ||
5013 | preempt_disable(); | ||
5014 | __schedule(); | ||
5011 | preempt_enable_no_resched(); | 5015 | preempt_enable_no_resched(); |
5012 | if (unlikely(test_thread_flag(TIF_NEED_RESCHED))) | 5016 | if (unlikely(test_thread_flag(TIF_NEED_RESCHED))) |
5013 | goto need_resched; | 5017 | goto need_resched; |
5014 | } | 5018 | } |
5015 | EXPORT_SYMBOL(schedule); | 5019 | EXPORT_SYMBOL(schedule); |
5016 | 5020 | ||
5021 | #ifdef CONFIG_SMP | ||
5022 | /* | ||
5023 | * Look out! "owner" is an entirely speculative pointer | ||
5024 | * access and not reliable. | ||
5025 | */ | ||
5026 | int mutex_spin_on_owner(struct mutex *lock, struct thread_info *owner) | ||
5027 | { | ||
5028 | unsigned int cpu; | ||
5029 | struct rq *rq; | ||
5030 | |||
5031 | if (!sched_feat(OWNER_SPIN)) | ||
5032 | return 0; | ||
5033 | |||
5034 | #ifdef CONFIG_DEBUG_PAGEALLOC | ||
5035 | /* | ||
5036 | * Need to access the cpu field knowing that | ||
5037 | * DEBUG_PAGEALLOC could have unmapped it if | ||
5038 | * the mutex owner just released it and exited. | ||
5039 | */ | ||
5040 | if (probe_kernel_address(&owner->cpu, cpu)) | ||
5041 | goto out; | ||
5042 | #else | ||
5043 | cpu = owner->cpu; | ||
5044 | #endif | ||
5045 | |||
5046 | /* | ||
5047 | * Even if the access succeeded (likely case), | ||
5048 | * the cpu field may no longer be valid. | ||
5049 | */ | ||
5050 | if (cpu >= nr_cpumask_bits) | ||
5051 | goto out; | ||
5052 | |||
5053 | /* | ||
5054 | * We need to validate that we can do a | ||
5055 | * get_cpu() and that we have the percpu area. | ||
5056 | */ | ||
5057 | if (!cpu_online(cpu)) | ||
5058 | goto out; | ||
5059 | |||
5060 | rq = cpu_rq(cpu); | ||
5061 | |||
5062 | for (;;) { | ||
5063 | /* | ||
5064 | * Owner changed, break to re-assess state. | ||
5065 | */ | ||
5066 | if (lock->owner != owner) | ||
5067 | break; | ||
5068 | |||
5069 | /* | ||
5070 | * Is that owner really running on that cpu? | ||
5071 | */ | ||
5072 | if (task_thread_info(rq->curr) != owner || need_resched()) | ||
5073 | return 0; | ||
5074 | |||
5075 | cpu_relax(); | ||
5076 | } | ||
5077 | out: | ||
5078 | return 1; | ||
5079 | } | ||
5080 | #endif | ||
5081 | |||
5017 | #ifdef CONFIG_PREEMPT | 5082 | #ifdef CONFIG_PREEMPT |
5018 | /* | 5083 | /* |
5019 | * this is the entry point to schedule() from in-kernel preemption | 5084 | * this is the entry point to schedule() from in-kernel preemption |