diff options
author | Kirill Tkhai <ktkhai@parallels.com> | 2014-09-30 04:23:37 -0400 |
---|---|---|
committer | Ingo Molnar <mingo@kernel.org> | 2014-10-02 23:46:58 -0400 |
commit | f10e00f4bf360c36edbe6bf18a6c75b171cbe012 (patch) | |
tree | 0733366372b97784b82acafa6d0fc0a57f62e27b /kernel | |
parent | 10a12983b3d437a6998b3845870e52c1c752c101 (diff) |
sched/dl: Use dl_bw_of() under rcu_read_lock_sched()
rq->rd is freed using call_rcu_sched(), so rcu_read_lock() to access it
is not enough. We should use either rcu_read_lock_sched() or preempt_disable().
Reported-by: Sasha Levin <sasha.levin@oracle.com>
Suggested-by: Peter Zijlstra <peterz@infradead.org>
Signed-off-by: Kirill Tkhai <ktkhai@parallels.com
Signed-off-by: Peter Zijlstra (Intel) <peterz@infradead.org>
Fixes: 66339c31bc39 "sched: Use dl_bw_of() under RCU read lock"
Link: http://lkml.kernel.org/r/1412065417.20287.24.camel@tkhai
Signed-off-by: Ingo Molnar <mingo@kernel.org>
Diffstat (limited to 'kernel')
-rw-r--r-- | kernel/sched/core.c | 25 |
1 files changed, 16 insertions, 9 deletions
diff --git a/kernel/sched/core.c b/kernel/sched/core.c index b5349fee1213..c84bdc098656 100644 --- a/kernel/sched/core.c +++ b/kernel/sched/core.c | |||
@@ -5264,6 +5264,7 @@ static int sched_cpu_inactive(struct notifier_block *nfb, | |||
5264 | { | 5264 | { |
5265 | unsigned long flags; | 5265 | unsigned long flags; |
5266 | long cpu = (long)hcpu; | 5266 | long cpu = (long)hcpu; |
5267 | struct dl_bw *dl_b; | ||
5267 | 5268 | ||
5268 | switch (action & ~CPU_TASKS_FROZEN) { | 5269 | switch (action & ~CPU_TASKS_FROZEN) { |
5269 | case CPU_DOWN_PREPARE: | 5270 | case CPU_DOWN_PREPARE: |
@@ -5271,15 +5272,19 @@ static int sched_cpu_inactive(struct notifier_block *nfb, | |||
5271 | 5272 | ||
5272 | /* explicitly allow suspend */ | 5273 | /* explicitly allow suspend */ |
5273 | if (!(action & CPU_TASKS_FROZEN)) { | 5274 | if (!(action & CPU_TASKS_FROZEN)) { |
5274 | struct dl_bw *dl_b = dl_bw_of(cpu); | ||
5275 | bool overflow; | 5275 | bool overflow; |
5276 | int cpus; | 5276 | int cpus; |
5277 | 5277 | ||
5278 | rcu_read_lock_sched(); | ||
5279 | dl_b = dl_bw_of(cpu); | ||
5280 | |||
5278 | raw_spin_lock_irqsave(&dl_b->lock, flags); | 5281 | raw_spin_lock_irqsave(&dl_b->lock, flags); |
5279 | cpus = dl_bw_cpus(cpu); | 5282 | cpus = dl_bw_cpus(cpu); |
5280 | overflow = __dl_overflow(dl_b, cpus, 0, 0); | 5283 | overflow = __dl_overflow(dl_b, cpus, 0, 0); |
5281 | raw_spin_unlock_irqrestore(&dl_b->lock, flags); | 5284 | raw_spin_unlock_irqrestore(&dl_b->lock, flags); |
5282 | 5285 | ||
5286 | rcu_read_unlock_sched(); | ||
5287 | |||
5283 | if (overflow) | 5288 | if (overflow) |
5284 | return notifier_from_errno(-EBUSY); | 5289 | return notifier_from_errno(-EBUSY); |
5285 | } | 5290 | } |
@@ -7647,11 +7652,10 @@ static int sched_dl_global_constraints(void) | |||
7647 | u64 runtime = global_rt_runtime(); | 7652 | u64 runtime = global_rt_runtime(); |
7648 | u64 period = global_rt_period(); | 7653 | u64 period = global_rt_period(); |
7649 | u64 new_bw = to_ratio(period, runtime); | 7654 | u64 new_bw = to_ratio(period, runtime); |
7655 | struct dl_bw *dl_b; | ||
7650 | int cpu, ret = 0; | 7656 | int cpu, ret = 0; |
7651 | unsigned long flags; | 7657 | unsigned long flags; |
7652 | 7658 | ||
7653 | rcu_read_lock(); | ||
7654 | |||
7655 | /* | 7659 | /* |
7656 | * Here we want to check the bandwidth not being set to some | 7660 | * Here we want to check the bandwidth not being set to some |
7657 | * value smaller than the currently allocated bandwidth in | 7661 | * value smaller than the currently allocated bandwidth in |
@@ -7662,25 +7666,27 @@ static int sched_dl_global_constraints(void) | |||
7662 | * solutions is welcome! | 7666 | * solutions is welcome! |
7663 | */ | 7667 | */ |
7664 | for_each_possible_cpu(cpu) { | 7668 | for_each_possible_cpu(cpu) { |
7665 | struct dl_bw *dl_b = dl_bw_of(cpu); | 7669 | rcu_read_lock_sched(); |
7670 | dl_b = dl_bw_of(cpu); | ||
7666 | 7671 | ||
7667 | raw_spin_lock_irqsave(&dl_b->lock, flags); | 7672 | raw_spin_lock_irqsave(&dl_b->lock, flags); |
7668 | if (new_bw < dl_b->total_bw) | 7673 | if (new_bw < dl_b->total_bw) |
7669 | ret = -EBUSY; | 7674 | ret = -EBUSY; |
7670 | raw_spin_unlock_irqrestore(&dl_b->lock, flags); | 7675 | raw_spin_unlock_irqrestore(&dl_b->lock, flags); |
7671 | 7676 | ||
7677 | rcu_read_unlock_sched(); | ||
7678 | |||
7672 | if (ret) | 7679 | if (ret) |
7673 | break; | 7680 | break; |
7674 | } | 7681 | } |
7675 | 7682 | ||
7676 | rcu_read_unlock(); | ||
7677 | |||
7678 | return ret; | 7683 | return ret; |
7679 | } | 7684 | } |
7680 | 7685 | ||
7681 | static void sched_dl_do_global(void) | 7686 | static void sched_dl_do_global(void) |
7682 | { | 7687 | { |
7683 | u64 new_bw = -1; | 7688 | u64 new_bw = -1; |
7689 | struct dl_bw *dl_b; | ||
7684 | int cpu; | 7690 | int cpu; |
7685 | unsigned long flags; | 7691 | unsigned long flags; |
7686 | 7692 | ||
@@ -7690,18 +7696,19 @@ static void sched_dl_do_global(void) | |||
7690 | if (global_rt_runtime() != RUNTIME_INF) | 7696 | if (global_rt_runtime() != RUNTIME_INF) |
7691 | new_bw = to_ratio(global_rt_period(), global_rt_runtime()); | 7697 | new_bw = to_ratio(global_rt_period(), global_rt_runtime()); |
7692 | 7698 | ||
7693 | rcu_read_lock(); | ||
7694 | /* | 7699 | /* |
7695 | * FIXME: As above... | 7700 | * FIXME: As above... |
7696 | */ | 7701 | */ |
7697 | for_each_possible_cpu(cpu) { | 7702 | for_each_possible_cpu(cpu) { |
7698 | struct dl_bw *dl_b = dl_bw_of(cpu); | 7703 | rcu_read_lock_sched(); |
7704 | dl_b = dl_bw_of(cpu); | ||
7699 | 7705 | ||
7700 | raw_spin_lock_irqsave(&dl_b->lock, flags); | 7706 | raw_spin_lock_irqsave(&dl_b->lock, flags); |
7701 | dl_b->bw = new_bw; | 7707 | dl_b->bw = new_bw; |
7702 | raw_spin_unlock_irqrestore(&dl_b->lock, flags); | 7708 | raw_spin_unlock_irqrestore(&dl_b->lock, flags); |
7709 | |||
7710 | rcu_read_unlock_sched(); | ||
7703 | } | 7711 | } |
7704 | rcu_read_unlock(); | ||
7705 | } | 7712 | } |
7706 | 7713 | ||
7707 | static int sched_rt_global_validate(void) | 7714 | static int sched_rt_global_validate(void) |