sched/deadline: Fix bandwidth check/update when migrating tasks between exclusive...
[linux-2.6-block.git] / kernel / sched / deadline.c
index 9d1e76a21297ead59b5c7a392a6cc7bc669d55d9..8aaa971ffecd28a19ccc1fcaef1ef55bdf2fff4f 100644 (file)
@@ -1517,10 +1517,33 @@ static void set_cpus_allowed_dl(struct task_struct *p,
                                const struct cpumask *new_mask)
 {
        struct rq *rq;
+       struct root_domain *src_rd;
        int weight;
 
        BUG_ON(!dl_task(p));
 
+       rq = task_rq(p);
+       src_rd = rq->rd;
+       /*
+        * Migrating a SCHED_DEADLINE task between exclusive
+        * cpusets (different root_domains) entails a bandwidth
+        * update. We already made space for us in the destination
+        * domain (see cpuset_can_attach()).
+        */
+       if (!cpumask_intersects(src_rd->span, new_mask)) {
+               struct dl_bw *src_dl_b;
+
+               src_dl_b = dl_bw_of(cpu_of(rq));
+               /*
+                * We now free resources of the root_domain we are migrating
+                * off. In the worst case, sched_setattr() may temporary fail
+                * until we complete the update.
+                */
+               raw_spin_lock(&src_dl_b->lock);
+               __dl_clear(src_dl_b, p->dl.dl_bw);
+               raw_spin_unlock(&src_dl_b->lock);
+       }
+
        /*
         * Update only if the task is actually running (i.e.,
         * it is on the rq AND it is not throttled).
@@ -1537,8 +1560,6 @@ static void set_cpus_allowed_dl(struct task_struct *p,
        if ((p->nr_cpus_allowed > 1) == (weight > 1))
                return;
 
-       rq = task_rq(p);
-
        /*
         * The process used to be able to migrate OR it can now migrate
         */