We've met problems that occasionally tasks with full cpumask (e.g. by putting it into a cpuset or setting to full affinity) were migrated to our isolated cpus in production environment. After some analysis, we found that it is due to the current select_idle_smt() not considering the sched_domain mask. Steps to reproduce on my 31-CPU hyperthreads machine: 1. with boot parameter: "isolcpus=domain,2-31" (thread lists: 0,16 and 1,17) 2. cgcreate -g cpu:test; cgexec -g cpu:test "test_threads" 3. some threads will be migrated to the isolated cpu16~17. Fix it by checking the valid domain mask in select_idle_smt().
Showing the changes to kernel (1 of 1 file). Show all
Unified · Split
| @@ -6080,7 +6080,7 @@ static int select_idle_core(struct task_struct *p, struct sched_domain *sd, int · 6079 unmodified lines | |||
| 6080 | /* | 6080 | /* |
| 6081 | * Scan the local SMT mask for idle CPUs. | 6081 | * Scan the local SMT mask for idle CPUs. |
| 6082 | */ | 6082 | */ |
| 6083 | static int select_idle_smt(struct task_struct *p, int target) | 6083 | static int select_idle_smt(struct task_struct *p, struct sched_domain *sd, int target) |
| 6084 | { | 6084 | { |
| 6085 | int cpu; | 6085 | int cpu; |
| 6086 | 6086 | ||
| @@ -6088,7 +6088,8 @@ static int select_idle_smt(struct task_struct *p, int target) · 1 unmodified line | |||
| 6088 | return -1; | 6088 | return -1; |
| 6089 | 6089 | ||
| 6090 | for_each_cpu(cpu, cpu_smt_mask(target)) { | 6090 | for_each_cpu(cpu, cpu_smt_mask(target)) { |
| 6091 | if (!cpumask_test_cpu(cpu, p->cpus_ptr)) | 6091 | if (!cpumask_test_cpu(cpu, p->cpus_ptr) || |
| 6092 | !cpumask_test_cpu(cpu, sched_domain_span(sd))) | ||
| 6092 | continue; | 6093 | continue; |
| 6093 | if (available_idle_cpu(cpu) || sched_idle_cpu(cpu)) | 6094 | if (available_idle_cpu(cpu) || sched_idle_cpu(cpu)) |
| 6094 | return cpu; | 6095 | return cpu; |
| @@ -6104,7 +6105,7 @@ static inline int select_idle_core(struct task_struct *p, struct sched_domain *s · 9 unmodified lines | |||
| 6104 | return -1; | 6105 | return -1; |
| 6105 | } | 6106 | } |
| 6106 | 6107 | ||
| 6107 | static inline int select_idle_smt(struct task_struct *p, int target) | 6108 | static inline int select_idle_smt(struct task_struct *p, struct sched_domain *sd, int target) |
| 6108 | { | 6109 | { |
| 6109 | return -1; | 6110 | return -1; |
| 6110 | } | 6111 | } |
| @@ -6279,7 +6280,7 @@ symmetric: · 168 unmodified lines | |||
| 6279 | if ((unsigned)i < nr_cpumask_bits) | 6280 | if ((unsigned)i < nr_cpumask_bits) |
| 6280 | return i; | 6281 | return i; |
| 6281 | 6282 | ||
| 6282 | i = select_idle_smt(p, target); | 6283 | i = select_idle_smt(p, sd, target); |
| 6283 | if ((unsigned)i < nr_cpumask_bits) | 6284 | if ((unsigned)i < nr_cpumask_bits) |
| 6284 | return i; | 6285 | return i; |
| 6285 | 6286 | ||