Merge tag 'v4.2' into p/abusse/merge_upgrade
[projects/modsched/linux.git] / kernel / sched / cfs / rt.c
index 575da76..0d193a2 100644 (file)
@@ -18,19 +18,22 @@ static enum hrtimer_restart sched_rt_period_timer(struct hrtimer *timer)
 {
        struct rt_bandwidth *rt_b =
                container_of(timer, struct rt_bandwidth, rt_period_timer);
-       ktime_t now;
-       int overrun;
        int idle = 0;
+       int overrun;
 
+       raw_spin_lock(&rt_b->rt_runtime_lock);
        for (;;) {
-               now = hrtimer_cb_get_time(timer);
-               overrun = hrtimer_forward(timer, now, rt_b->rt_period);
-
+               overrun = hrtimer_forward_now(timer, rt_b->rt_period);
                if (!overrun)
                        break;
 
+               raw_spin_unlock(&rt_b->rt_runtime_lock);
                idle = do_sched_rt_period_timer(rt_b, overrun);
+               raw_spin_lock(&rt_b->rt_runtime_lock);
        }
+       if (idle)
+               rt_b->rt_period_active = 0;
+       raw_spin_unlock(&rt_b->rt_runtime_lock);
 
        return idle ? HRTIMER_NORESTART : HRTIMER_RESTART;
 }
@@ -52,11 +55,12 @@ static void start_rt_bandwidth(struct rt_bandwidth *rt_b)
        if (!rt_bandwidth_enabled() || rt_b->rt_runtime == RUNTIME_INF)
                return;
 
-       if (hrtimer_active(&rt_b->rt_period_timer))
-               return;
-
        raw_spin_lock(&rt_b->rt_runtime_lock);
-       start_bandwidth_timer(&rt_b->rt_period_timer, rt_b->rt_period);
+       if (!rt_b->rt_period_active) {
+               rt_b->rt_period_active = 1;
+               hrtimer_forward_now(&rt_b->rt_period_timer, rt_b->rt_period);
+               hrtimer_start_expires(&rt_b->rt_period_timer, HRTIMER_MODE_ABS_PINNED);
+       }
        raw_spin_unlock(&rt_b->rt_runtime_lock);
 }
 
@@ -256,7 +260,7 @@ int alloc_rt_sched_group(struct task_group *tg, struct task_group *parent)
 
 #ifdef CONFIG_SMP
 
-static int pull_rt_task(struct rq *this_rq);
+static void pull_rt_task(struct rq *this_rq);
 
 static inline bool need_pull_rt_task(struct rq *rq, struct task_struct *prev)
 {
@@ -350,13 +354,23 @@ static inline int has_pushable_tasks(struct rq *rq)
        return !plist_head_empty(&rq->rt.pushable_tasks);
 }
 
-static inline void set_post_schedule(struct rq *rq)
+static DEFINE_PER_CPU(struct callback_head, rt_push_head);
+static DEFINE_PER_CPU(struct callback_head, rt_pull_head);
+
+static void push_rt_tasks(struct rq *);
+static void pull_rt_task(struct rq *);
+
+static inline void queue_push_tasks(struct rq *rq)
 {
-       /*
-        * We detect this state here so that we can avoid taking the RQ
-        * lock again later if there is no need to push
-        */
-       rq->post_schedule = has_pushable_tasks(rq);
+       if (!has_pushable_tasks(rq))
+               return;
+
+       queue_balance_callback(rq, &per_cpu(rt_push_head, rq->cpu), push_rt_tasks);
+}
+
+static inline void queue_pull_task(struct rq *rq)
+{
+       queue_balance_callback(rq, &per_cpu(rt_pull_head, rq->cpu), pull_rt_task);
 }
 
 static void enqueue_pushable_task(struct rq *rq, struct task_struct *p)
@@ -408,12 +422,11 @@ static inline bool need_pull_rt_task(struct rq *rq, struct task_struct *prev)
        return false;
 }
 
-static inline int pull_rt_task(struct rq *this_rq)
+static inline void pull_rt_task(struct rq *this_rq)
 {
-       return 0;
 }
 
-static inline void set_post_schedule(struct rq *rq)
+static inline void queue_push_tasks(struct rq *rq)
 {
 }
 #endif /* CONFIG_SMP */
@@ -1323,7 +1336,7 @@ select_task_rq_rt(struct task_struct *p, int cpu, int sd_flag, int flags)
        rq = cpu_rq(cpu);
 
        rcu_read_lock();
-       curr = ACCESS_ONCE(rq->curr); /* unlocked access */
+       curr = READ_ONCE(rq->curr); /* unlocked access */
 
        /*
         * If the current task on @p's runqueue is an RT task, then
@@ -1465,7 +1478,15 @@ pick_next_task_rt(struct rq *rq, struct task_struct *prev)
        struct rt_rq *rt_rq = &rq->rt;
 
        if (need_pull_rt_task(rq, prev)) {
+               /*
+                * This is OK, because current is on_cpu, which avoids it being
+                * picked for load-balance and preemption/IRQs are still
+                * disabled avoiding further scheduler activity on it and we're
+                * being very careful to re-start the picking loop.
+                */
+               lockdep_unpin_lock(&rq->lock);
                pull_rt_task(rq);
+               lockdep_pin_lock(&rq->lock);
                /*
                 * pull_rt_task() can drop (and re-acquire) rq->lock; this
                 * means a dl or stop task can slip in, in which case we need
@@ -1493,7 +1514,7 @@ pick_next_task_rt(struct rq *rq, struct task_struct *prev)
        /* The running task is never eligible for pushing */
        dequeue_pushable_task(rq, p);
 
-       set_post_schedule(rq);
+       queue_push_tasks(rq);
 
        return p;
 }
@@ -1948,14 +1969,15 @@ static void push_irq_work_func(struct irq_work *work)
 }
 #endif /* HAVE_RT_PUSH_IPI */
 
-static int pull_rt_task(struct rq *this_rq)
+static void pull_rt_task(struct rq *this_rq)
 {
-       int this_cpu = this_rq->cpu, ret = 0, cpu;
+       int this_cpu = this_rq->cpu, cpu;
+       bool resched = false;
        struct task_struct *p;
        struct rq *src_rq;
 
        if (likely(!rt_overloaded(this_rq)))
-               return 0;
+               return;
 
        /*
         * Match the barrier from rt_set_overloaded; this guarantees that if we
@@ -1966,7 +1988,7 @@ static int pull_rt_task(struct rq *this_rq)
 #ifdef HAVE_RT_PUSH_IPI
        if (sched_feat(RT_PUSH_IPI)) {
                tell_cpu_to_push(this_rq);
-               return 0;
+               return;
        }
 #endif
 
@@ -2019,7 +2041,7 @@ static int pull_rt_task(struct rq *this_rq)
                        if (p->prio < src_rq->curr->prio)
                                goto skip;
 
-                       ret = 1;
+                       resched = true;
 
                        deactivate_task(src_rq, p, 0);
                        set_task_cpu(p, this_cpu);
@@ -2035,12 +2057,8 @@ skip:
                double_unlock_balance(this_rq, src_rq);
        }
 
-       return ret;
-}
-
-static void post_schedule_rt(struct rq *rq)
-{
-       push_rt_tasks(rq);
+       if (resched)
+               resched_curr(this_rq);
 }
 
 /*
@@ -2136,8 +2154,7 @@ static void switched_from_rt(struct rq *rq, struct task_struct *p)
        if (!task_on_rq_queued(p) || rq->rt.rt_nr_running)
                return;
 
-       if (pull_rt_task(rq))
-               resched_curr(rq);
+       queue_pull_task(rq);
 }
 
 void __init init_sched_rt_class(void)
@@ -2158,8 +2175,6 @@ void __init init_sched_rt_class(void)
  */
 static void switched_to_rt(struct rq *rq, struct task_struct *p)
 {
-       int check_resched = 1;
-
        /*
         * If we are already running, then there's nothing
         * that needs to be done. But if we are not running
@@ -2169,13 +2184,12 @@ static void switched_to_rt(struct rq *rq, struct task_struct *p)
         */
        if (task_on_rq_queued(p) && rq->curr != p) {
 #ifdef CONFIG_SMP
-               if (p->nr_cpus_allowed > 1 && rq->rt.overloaded &&
-                   /* Don't resched if we changed runqueues */
-                   push_rt_task(rq) && rq != task_rq(p))
-                       check_resched = 0;
-#endif /* CONFIG_SMP */
-               if (check_resched && p->prio < rq->curr->prio)
+               if (p->nr_cpus_allowed > 1 && rq->rt.overloaded)
+                       queue_push_tasks(rq);
+#else
+               if (p->prio < rq->curr->prio)
                        resched_curr(rq);
+#endif /* CONFIG_SMP */
        }
 }
 
@@ -2196,14 +2210,13 @@ prio_changed_rt(struct rq *rq, struct task_struct *p, int oldprio)
                 * may need to pull tasks to this runqueue.
                 */
                if (oldprio < p->prio)
-                       pull_rt_task(rq);
+                       queue_pull_task(rq);
+
                /*
                 * If there's a higher priority task waiting to run
-                * then reschedule. Note, the above pull_rt_task
-                * can release the rq lock and p could migrate.
-                * Only reschedule if p is still on the same runqueue.
+                * then reschedule.
                 */
-               if (p->prio > rq->rt.highest_prio.curr && rq->curr == p)
+               if (p->prio > rq->rt.highest_prio.curr)
                        resched_curr(rq);
 #else
                /* For UP simply resched on drop of prio */
@@ -2314,7 +2327,6 @@ const struct sched_class rt_sched_class = {
        .set_cpus_allowed       = set_cpus_allowed_rt,
        .rq_online              = rq_online_rt,
        .rq_offline             = rq_offline_rt,
-       .post_schedule          = post_schedule_rt,
        .task_woken             = task_woken_rt,
        .switched_from          = switched_from_rt,
 #endif