aboutsummaryrefslogtreecommitdiffstats
path: root/kernel/sched
diff options
context:
space:
mode:
authorPeter Zijlstra <peterz@infradead.org>2019-01-07 07:52:31 -0500
committerIngo Molnar <mingo@kernel.org>2019-01-27 06:29:37 -0500
commitc0ad4aa4d8416a39ad262a2bd68b30acd951bf0e (patch)
treeef0c001f3783a68146915eb3fff67d08f800b5b7 /kernel/sched
parentf8a696f25ba09a1821dc6ca3db56f41c264fb896 (diff)
sched/fair: Robustify CFS-bandwidth timer locking
Traditionally hrtimer callbacks were run with IRQs disabled, but with the introduction of HRTIMER_MODE_SOFT it is possible they run from SoftIRQ context, which does _NOT_ have IRQs disabled. Allow for the CFS bandwidth timers (period_timer and slack_timer) to be ran from SoftIRQ context; this entails removing the assumption that IRQs are already disabled from the locking. While mainline doesn't strictly need this, -RT forces all timers not explicitly marked with MODE_HARD into MODE_SOFT and trips over this. And marking these timers as MODE_HARD doesn't make sense as they're not required for RT operation and can potentially be quite expensive. Reported-by: Tom Putzeys <tom.putzeys@be.atlascopco.com> Tested-by: Mike Galbraith <efault@gmx.de> Signed-off-by: Peter Zijlstra (Intel) <peterz@infradead.org> Cc: Linus Torvalds <torvalds@linux-foundation.org> Cc: Peter Zijlstra <peterz@infradead.org> Cc: Sebastian Andrzej Siewior <bigeasy@linutronix.de> Cc: Thomas Gleixner <tglx@linutronix.de> Link: https://lkml.kernel.org/r/20190107125231.GE14122@hirez.programming.kicks-ass.net Signed-off-by: Ingo Molnar <mingo@kernel.org>
Diffstat (limited to 'kernel/sched')
-rw-r--r--kernel/sched/fair.c30
1 files changed, 16 insertions, 14 deletions
diff --git a/kernel/sched/fair.c b/kernel/sched/fair.c
index b1374fbddd0d..3b61e19b504a 100644
--- a/kernel/sched/fair.c
+++ b/kernel/sched/fair.c
@@ -4565,7 +4565,7 @@ static u64 distribute_cfs_runtime(struct cfs_bandwidth *cfs_b,
4565 struct rq *rq = rq_of(cfs_rq); 4565 struct rq *rq = rq_of(cfs_rq);
4566 struct rq_flags rf; 4566 struct rq_flags rf;
4567 4567
4568 rq_lock(rq, &rf); 4568 rq_lock_irqsave(rq, &rf);
4569 if (!cfs_rq_throttled(cfs_rq)) 4569 if (!cfs_rq_throttled(cfs_rq))
4570 goto next; 4570 goto next;
4571 4571
@@ -4582,7 +4582,7 @@ static u64 distribute_cfs_runtime(struct cfs_bandwidth *cfs_b,
4582 unthrottle_cfs_rq(cfs_rq); 4582 unthrottle_cfs_rq(cfs_rq);
4583 4583
4584next: 4584next:
4585 rq_unlock(rq, &rf); 4585 rq_unlock_irqrestore(rq, &rf);
4586 4586
4587 if (!remaining) 4587 if (!remaining)
4588 break; 4588 break;
@@ -4598,7 +4598,7 @@ next:
4598 * period the timer is deactivated until scheduling resumes; cfs_b->idle is 4598 * period the timer is deactivated until scheduling resumes; cfs_b->idle is
4599 * used to track this state. 4599 * used to track this state.
4600 */ 4600 */
4601static int do_sched_cfs_period_timer(struct cfs_bandwidth *cfs_b, int overrun) 4601static int do_sched_cfs_period_timer(struct cfs_bandwidth *cfs_b, int overrun, unsigned long flags)
4602{ 4602{
4603 u64 runtime, runtime_expires; 4603 u64 runtime, runtime_expires;
4604 int throttled; 4604 int throttled;
@@ -4640,11 +4640,11 @@ static int do_sched_cfs_period_timer(struct cfs_bandwidth *cfs_b, int overrun)
4640 while (throttled && cfs_b->runtime > 0 && !cfs_b->distribute_running) { 4640 while (throttled && cfs_b->runtime > 0 && !cfs_b->distribute_running) {
4641 runtime = cfs_b->runtime; 4641 runtime = cfs_b->runtime;
4642 cfs_b->distribute_running = 1; 4642 cfs_b->distribute_running = 1;
4643 raw_spin_unlock(&cfs_b->lock); 4643 raw_spin_unlock_irqrestore(&cfs_b->lock, flags);
4644 /* we can't nest cfs_b->lock while distributing bandwidth */ 4644 /* we can't nest cfs_b->lock while distributing bandwidth */
4645 runtime = distribute_cfs_runtime(cfs_b, runtime, 4645 runtime = distribute_cfs_runtime(cfs_b, runtime,
4646 runtime_expires); 4646 runtime_expires);
4647 raw_spin_lock(&cfs_b->lock); 4647 raw_spin_lock_irqsave(&cfs_b->lock, flags);
4648 4648
4649 cfs_b->distribute_running = 0; 4649 cfs_b->distribute_running = 0;
4650 throttled = !list_empty(&cfs_b->throttled_cfs_rq); 4650 throttled = !list_empty(&cfs_b->throttled_cfs_rq);
@@ -4753,17 +4753,18 @@ static __always_inline void return_cfs_rq_runtime(struct cfs_rq *cfs_rq)
4753static void do_sched_cfs_slack_timer(struct cfs_bandwidth *cfs_b) 4753static void do_sched_cfs_slack_timer(struct cfs_bandwidth *cfs_b)
4754{ 4754{
4755 u64 runtime = 0, slice = sched_cfs_bandwidth_slice(); 4755 u64 runtime = 0, slice = sched_cfs_bandwidth_slice();
4756 unsigned long flags;
4756 u64 expires; 4757 u64 expires;
4757 4758
4758 /* confirm we're still not at a refresh boundary */ 4759 /* confirm we're still not at a refresh boundary */
4759 raw_spin_lock(&cfs_b->lock); 4760 raw_spin_lock_irqsave(&cfs_b->lock, flags);
4760 if (cfs_b->distribute_running) { 4761 if (cfs_b->distribute_running) {
4761 raw_spin_unlock(&cfs_b->lock); 4762 raw_spin_unlock_irqrestore(&cfs_b->lock, flags);
4762 return; 4763 return;
4763 } 4764 }
4764 4765
4765 if (runtime_refresh_within(cfs_b, min_bandwidth_expiration)) { 4766 if (runtime_refresh_within(cfs_b, min_bandwidth_expiration)) {
4766 raw_spin_unlock(&cfs_b->lock); 4767 raw_spin_unlock_irqrestore(&cfs_b->lock, flags);
4767 return; 4768 return;
4768 } 4769 }
4769 4770
@@ -4774,18 +4775,18 @@ static void do_sched_cfs_slack_timer(struct cfs_bandwidth *cfs_b)
4774 if (runtime) 4775 if (runtime)
4775 cfs_b->distribute_running = 1; 4776 cfs_b->distribute_running = 1;
4776 4777
4777 raw_spin_unlock(&cfs_b->lock); 4778 raw_spin_unlock_irqrestore(&cfs_b->lock, flags);
4778 4779
4779 if (!runtime) 4780 if (!runtime)
4780 return; 4781 return;
4781 4782
4782 runtime = distribute_cfs_runtime(cfs_b, runtime, expires); 4783 runtime = distribute_cfs_runtime(cfs_b, runtime, expires);
4783 4784
4784 raw_spin_lock(&cfs_b->lock); 4785 raw_spin_lock_irqsave(&cfs_b->lock, flags);
4785 if (expires == cfs_b->runtime_expires) 4786 if (expires == cfs_b->runtime_expires)
4786 lsub_positive(&cfs_b->runtime, runtime); 4787 lsub_positive(&cfs_b->runtime, runtime);
4787 cfs_b->distribute_running = 0; 4788 cfs_b->distribute_running = 0;
4788 raw_spin_unlock(&cfs_b->lock); 4789 raw_spin_unlock_irqrestore(&cfs_b->lock, flags);
4789} 4790}
4790 4791
4791/* 4792/*
@@ -4863,20 +4864,21 @@ static enum hrtimer_restart sched_cfs_period_timer(struct hrtimer *timer)
4863{ 4864{
4864 struct cfs_bandwidth *cfs_b = 4865 struct cfs_bandwidth *cfs_b =
4865 container_of(timer, struct cfs_bandwidth, period_timer); 4866 container_of(timer, struct cfs_bandwidth, period_timer);
4867 unsigned long flags;
4866 int overrun; 4868 int overrun;
4867 int idle = 0; 4869 int idle = 0;
4868 4870
4869 raw_spin_lock(&cfs_b->lock); 4871 raw_spin_lock_irqsave(&cfs_b->lock, flags);
4870 for (;;) { 4872 for (;;) {
4871 overrun = hrtimer_forward_now(timer, cfs_b->period); 4873 overrun = hrtimer_forward_now(timer, cfs_b->period);
4872 if (!overrun) 4874 if (!overrun)
4873 break; 4875 break;
4874 4876
4875 idle = do_sched_cfs_period_timer(cfs_b, overrun); 4877 idle = do_sched_cfs_period_timer(cfs_b, overrun, flags);
4876 } 4878 }
4877 if (idle) 4879 if (idle)
4878 cfs_b->period_active = 0; 4880 cfs_b->period_active = 0;
4879 raw_spin_unlock(&cfs_b->lock); 4881 raw_spin_unlock_irqrestore(&cfs_b->lock, flags);
4880 4882
4881 return idle ? HRTIMER_NORESTART : HRTIMER_RESTART; 4883 return idle ? HRTIMER_NORESTART : HRTIMER_RESTART;
4882} 4884}