]> git.karo-electronics.de Git - linux-beck.git/blobdiff - kernel/sched_fair.c
ixgbe: Do not attempt to perform interrupts in netpoll when down
[linux-beck.git] / kernel / sched_fair.c
index 37087a7fac220e72cc6b6e63ba5a8f4dc83299d2..f61837ad336dbefd151be1e5e2acecca0a0b0070 100644 (file)
@@ -1344,6 +1344,37 @@ find_idlest_cpu(struct sched_group *group, struct task_struct *p, int this_cpu)
        return idlest;
 }
 
+/*
+ * Try and locate an idle CPU in the sched_domain.
+ */
+static int
+select_idle_sibling(struct task_struct *p, struct sched_domain *sd, int target)
+{
+       int cpu = smp_processor_id();
+       int prev_cpu = task_cpu(p);
+       int i;
+
+       /*
+        * If this domain spans both cpu and prev_cpu (see the SD_WAKE_AFFINE
+        * test in select_task_rq_fair) and the prev_cpu is idle then that's
+        * always a better target than the current cpu.
+        */
+       if (target == cpu && !cpu_rq(prev_cpu)->cfs.nr_running)
+               return prev_cpu;
+
+       /*
+        * Otherwise, iterate the domain and find an elegible idle cpu.
+        */
+       for_each_cpu_and(i, sched_domain_span(sd), &p->cpus_allowed) {
+               if (!cpu_rq(i)->cfs.nr_running) {
+                       target = i;
+                       break;
+               }
+       }
+
+       return target;
+}
+
 /*
  * sched_balance_self: balance the current task (running on cpu) in domains
  * that have the 'flag' flag set. In practice, this is SD_BALANCE_FORK and
@@ -1398,11 +1429,35 @@ static int select_task_rq_fair(struct task_struct *p, int sd_flag, int wake_flag
                                want_sd = 0;
                }
 
-               if (want_affine && (tmp->flags & SD_WAKE_AFFINE) &&
-                   cpumask_test_cpu(prev_cpu, sched_domain_span(tmp))) {
+               /*
+                * While iterating the domains looking for a spanning
+                * WAKE_AFFINE domain, adjust the affine target to any idle cpu
+                * in cache sharing domains along the way.
+                */
+               if (want_affine) {
+                       int target = -1;
 
-                       affine_sd = tmp;
-                       want_affine = 0;
+                       /*
+                        * If both cpu and prev_cpu are part of this domain,
+                        * cpu is a valid SD_WAKE_AFFINE target.
+                        */
+                       if (cpumask_test_cpu(prev_cpu, sched_domain_span(tmp)))
+                               target = cpu;
+
+                       /*
+                        * If there's an idle sibling in this domain, make that
+                        * the wake_affine target instead of the current cpu.
+                        */
+                       if (tmp->flags & SD_PREFER_SIBLING)
+                               target = select_idle_sibling(p, tmp, target);
+
+                       if (target >= 0) {
+                               if (tmp->flags & SD_WAKE_AFFINE) {
+                                       affine_sd = tmp;
+                                       want_affine = 0;
+                               }
+                               cpu = target;
+                       }
                }
 
                if (!want_sd && !want_affine)
@@ -1679,7 +1734,7 @@ static struct task_struct *pick_next_task_fair(struct rq *rq)
        struct cfs_rq *cfs_rq = &rq->cfs;
        struct sched_entity *se;
 
-       if (unlikely(!cfs_rq->nr_running))
+       if (!cfs_rq->nr_running)
                return NULL;
 
        do {