diff options
| author | Linus Torvalds <torvalds@linux-foundation.org> | 2014-06-01 21:26:59 -0400 |
|---|---|---|
| committer | Linus Torvalds <torvalds@linux-foundation.org> | 2014-06-01 21:26:59 -0400 |
| commit | 32439700fe1c0fc3c2d3f2aedd3ad6707c88b8ba (patch) | |
| tree | eb65ec1f536354bc7d48a7179b14224726a28329 | |
| parent | a4bf79eb6a42e863e0fccf19f9383c618e8efc43 (diff) | |
| parent | 6acbfb96976fc3350e30d964acb1dbbdf876d55e (diff) | |
Merge branch 'sched-urgent-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip
Pull scheduler fixes from Ingo Molnar:
"Various fixlets, mostly related to the (root-only) SCHED_DEADLINE
policy, but also a hotplug bug fix and a fix for a NR_CPUS related
overallocation bug causing a suspend/resume regression"
* 'sched-urgent-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip:
sched: Fix hotplug vs. set_cpus_allowed_ptr()
sched/cpupri: Replace NR_CPUS arrays
sched/deadline: Replace NR_CPUS arrays
sched/deadline: Restrict user params max value to 2^63 ns
sched/deadline: Change sched_getparam() behaviour vs SCHED_DEADLINE
sched: Disallow sched_attr::sched_policy < 0
sched: Make sched_setattr() correctly return -EFBIG
| -rw-r--r-- | kernel/cpu.c | 6 | ||||
| -rw-r--r-- | kernel/sched/core.c | 55 | ||||
| -rw-r--r-- | kernel/sched/cpudeadline.c | 33 | ||||
| -rw-r--r-- | kernel/sched/cpudeadline.h | 6 | ||||
| -rw-r--r-- | kernel/sched/cpupri.c | 7 | ||||
| -rw-r--r-- | kernel/sched/cpupri.h | 2 |
6 files changed, 78 insertions, 31 deletions
diff --git a/kernel/cpu.c b/kernel/cpu.c index a9e710eef0e2..247979a1b815 100644 --- a/kernel/cpu.c +++ b/kernel/cpu.c | |||
| @@ -726,10 +726,12 @@ void set_cpu_present(unsigned int cpu, bool present) | |||
| 726 | 726 | ||
| 727 | void set_cpu_online(unsigned int cpu, bool online) | 727 | void set_cpu_online(unsigned int cpu, bool online) |
| 728 | { | 728 | { |
| 729 | if (online) | 729 | if (online) { |
| 730 | cpumask_set_cpu(cpu, to_cpumask(cpu_online_bits)); | 730 | cpumask_set_cpu(cpu, to_cpumask(cpu_online_bits)); |
| 731 | else | 731 | cpumask_set_cpu(cpu, to_cpumask(cpu_active_bits)); |
| 732 | } else { | ||
| 732 | cpumask_clear_cpu(cpu, to_cpumask(cpu_online_bits)); | 733 | cpumask_clear_cpu(cpu, to_cpumask(cpu_online_bits)); |
| 734 | } | ||
| 733 | } | 735 | } |
| 734 | 736 | ||
| 735 | void set_cpu_active(unsigned int cpu, bool active) | 737 | void set_cpu_active(unsigned int cpu, bool active) |
diff --git a/kernel/sched/core.c b/kernel/sched/core.c index 204d3d281809..0a7251678982 100644 --- a/kernel/sched/core.c +++ b/kernel/sched/core.c | |||
| @@ -3195,17 +3195,40 @@ __getparam_dl(struct task_struct *p, struct sched_attr *attr) | |||
| 3195 | * We ask for the deadline not being zero, and greater or equal | 3195 | * We ask for the deadline not being zero, and greater or equal |
| 3196 | * than the runtime, as well as the period of being zero or | 3196 | * than the runtime, as well as the period of being zero or |
| 3197 | * greater than deadline. Furthermore, we have to be sure that | 3197 | * greater than deadline. Furthermore, we have to be sure that |
| 3198 | * user parameters are above the internal resolution (1us); we | 3198 | * user parameters are above the internal resolution of 1us (we |
| 3199 | * check sched_runtime only since it is always the smaller one. | 3199 | * check sched_runtime only since it is always the smaller one) and |
| 3200 | * below 2^63 ns (we have to check both sched_deadline and | ||
| 3201 | * sched_period, as the latter can be zero). | ||
| 3200 | */ | 3202 | */ |
| 3201 | static bool | 3203 | static bool |
| 3202 | __checkparam_dl(const struct sched_attr *attr) | 3204 | __checkparam_dl(const struct sched_attr *attr) |
| 3203 | { | 3205 | { |
| 3204 | return attr && attr->sched_deadline != 0 && | 3206 | /* deadline != 0 */ |
| 3205 | (attr->sched_period == 0 || | 3207 | if (attr->sched_deadline == 0) |
| 3206 | (s64)(attr->sched_period - attr->sched_deadline) >= 0) && | 3208 | return false; |
| 3207 | (s64)(attr->sched_deadline - attr->sched_runtime ) >= 0 && | 3209 | |
| 3208 | attr->sched_runtime >= (2 << (DL_SCALE - 1)); | 3210 | /* |
| 3211 | * Since we truncate DL_SCALE bits, make sure we're at least | ||
| 3212 | * that big. | ||
| 3213 | */ | ||
| 3214 | if (attr->sched_runtime < (1ULL << DL_SCALE)) | ||
| 3215 | return false; | ||
| 3216 | |||
| 3217 | /* | ||
| 3218 | * Since we use the MSB for wrap-around and sign issues, make | ||
| 3219 | * sure it's not set (mind that period can be equal to zero). | ||
| 3220 | */ | ||
| 3221 | if (attr->sched_deadline & (1ULL << 63) || | ||
| 3222 | attr->sched_period & (1ULL << 63)) | ||
| 3223 | return false; | ||
| 3224 | |||
| 3225 | /* runtime <= deadline <= period (if period != 0) */ | ||
| 3226 | if ((attr->sched_period != 0 && | ||
| 3227 | attr->sched_period < attr->sched_deadline) || | ||
| 3228 | attr->sched_deadline < attr->sched_runtime) | ||
| 3229 | return false; | ||
| 3230 | |||
| 3231 | return true; | ||
| 3209 | } | 3232 | } |
| 3210 | 3233 | ||
| 3211 | /* | 3234 | /* |
| @@ -3658,8 +3681,12 @@ SYSCALL_DEFINE3(sched_setattr, pid_t, pid, struct sched_attr __user *, uattr, | |||
| 3658 | if (!uattr || pid < 0 || flags) | 3681 | if (!uattr || pid < 0 || flags) |
| 3659 | return -EINVAL; | 3682 | return -EINVAL; |
| 3660 | 3683 | ||
| 3661 | if (sched_copy_attr(uattr, &attr)) | 3684 | retval = sched_copy_attr(uattr, &attr); |
| 3662 | return -EFAULT; | 3685 | if (retval) |
| 3686 | return retval; | ||
| 3687 | |||
| 3688 | if (attr.sched_policy < 0) | ||
| 3689 | return -EINVAL; | ||
| 3663 | 3690 | ||
| 3664 | rcu_read_lock(); | 3691 | rcu_read_lock(); |
| 3665 | retval = -ESRCH; | 3692 | retval = -ESRCH; |
| @@ -3709,7 +3736,7 @@ SYSCALL_DEFINE1(sched_getscheduler, pid_t, pid) | |||
| 3709 | */ | 3736 | */ |
| 3710 | SYSCALL_DEFINE2(sched_getparam, pid_t, pid, struct sched_param __user *, param) | 3737 | SYSCALL_DEFINE2(sched_getparam, pid_t, pid, struct sched_param __user *, param) |
| 3711 | { | 3738 | { |
| 3712 | struct sched_param lp; | 3739 | struct sched_param lp = { .sched_priority = 0 }; |
| 3713 | struct task_struct *p; | 3740 | struct task_struct *p; |
| 3714 | int retval; | 3741 | int retval; |
| 3715 | 3742 | ||
| @@ -3726,11 +3753,8 @@ SYSCALL_DEFINE2(sched_getparam, pid_t, pid, struct sched_param __user *, param) | |||
| 3726 | if (retval) | 3753 | if (retval) |
| 3727 | goto out_unlock; | 3754 | goto out_unlock; |
| 3728 | 3755 | ||
| 3729 | if (task_has_dl_policy(p)) { | 3756 | if (task_has_rt_policy(p)) |
| 3730 | retval = -EINVAL; | 3757 | lp.sched_priority = p->rt_priority; |
| 3731 | goto out_unlock; | ||
| 3732 | } | ||
| 3733 | lp.sched_priority = p->rt_priority; | ||
| 3734 | rcu_read_unlock(); | 3758 | rcu_read_unlock(); |
| 3735 | 3759 | ||
| 3736 | /* | 3760 | /* |
| @@ -5052,7 +5076,6 @@ static int sched_cpu_active(struct notifier_block *nfb, | |||
| 5052 | unsigned long action, void *hcpu) | 5076 | unsigned long action, void *hcpu) |
| 5053 | { | 5077 | { |
| 5054 | switch (action & ~CPU_TASKS_FROZEN) { | 5078 | switch (action & ~CPU_TASKS_FROZEN) { |
| 5055 | case CPU_STARTING: | ||
| 5056 | case CPU_DOWN_FAILED: | 5079 | case CPU_DOWN_FAILED: |
| 5057 | set_cpu_active((long)hcpu, true); | 5080 | set_cpu_active((long)hcpu, true); |
| 5058 | return NOTIFY_OK; | 5081 | return NOTIFY_OK; |
diff --git a/kernel/sched/cpudeadline.c b/kernel/sched/cpudeadline.c index ab001b5d5048..bd95963dae80 100644 --- a/kernel/sched/cpudeadline.c +++ b/kernel/sched/cpudeadline.c | |||
| @@ -13,6 +13,7 @@ | |||
| 13 | 13 | ||
| 14 | #include <linux/gfp.h> | 14 | #include <linux/gfp.h> |
| 15 | #include <linux/kernel.h> | 15 | #include <linux/kernel.h> |
| 16 | #include <linux/slab.h> | ||
| 16 | #include "cpudeadline.h" | 17 | #include "cpudeadline.h" |
| 17 | 18 | ||
| 18 | static inline int parent(int i) | 19 | static inline int parent(int i) |
| @@ -39,8 +40,10 @@ static void cpudl_exchange(struct cpudl *cp, int a, int b) | |||
| 39 | { | 40 | { |
| 40 | int cpu_a = cp->elements[a].cpu, cpu_b = cp->elements[b].cpu; | 41 | int cpu_a = cp->elements[a].cpu, cpu_b = cp->elements[b].cpu; |
| 41 | 42 | ||
| 42 | swap(cp->elements[a], cp->elements[b]); | 43 | swap(cp->elements[a].cpu, cp->elements[b].cpu); |
| 43 | swap(cp->cpu_to_idx[cpu_a], cp->cpu_to_idx[cpu_b]); | 44 | swap(cp->elements[a].dl , cp->elements[b].dl ); |
| 45 | |||
| 46 | swap(cp->elements[cpu_a].idx, cp->elements[cpu_b].idx); | ||
| 44 | } | 47 | } |
| 45 | 48 | ||
| 46 | static void cpudl_heapify(struct cpudl *cp, int idx) | 49 | static void cpudl_heapify(struct cpudl *cp, int idx) |
| @@ -140,7 +143,7 @@ void cpudl_set(struct cpudl *cp, int cpu, u64 dl, int is_valid) | |||
| 140 | WARN_ON(!cpu_present(cpu)); | 143 | WARN_ON(!cpu_present(cpu)); |
| 141 | 144 | ||
| 142 | raw_spin_lock_irqsave(&cp->lock, flags); | 145 | raw_spin_lock_irqsave(&cp->lock, flags); |
| 143 | old_idx = cp->cpu_to_idx[cpu]; | 146 | old_idx = cp->elements[cpu].idx; |
| 144 | if (!is_valid) { | 147 | if (!is_valid) { |
| 145 | /* remove item */ | 148 | /* remove item */ |
| 146 | if (old_idx == IDX_INVALID) { | 149 | if (old_idx == IDX_INVALID) { |
| @@ -155,8 +158,8 @@ void cpudl_set(struct cpudl *cp, int cpu, u64 dl, int is_valid) | |||
| 155 | cp->elements[old_idx].dl = cp->elements[cp->size - 1].dl; | 158 | cp->elements[old_idx].dl = cp->elements[cp->size - 1].dl; |
| 156 | cp->elements[old_idx].cpu = new_cpu; | 159 | cp->elements[old_idx].cpu = new_cpu; |
| 157 | cp->size--; | 160 | cp->size--; |
| 158 | cp->cpu_to_idx[new_cpu] = old_idx; | 161 | cp->elements[new_cpu].idx = old_idx; |
| 159 | cp->cpu_to_idx[cpu] = IDX_INVALID; | 162 | cp->elements[cpu].idx = IDX_INVALID; |
| 160 | while (old_idx > 0 && dl_time_before( | 163 | while (old_idx > 0 && dl_time_before( |
| 161 | cp->elements[parent(old_idx)].dl, | 164 | cp->elements[parent(old_idx)].dl, |
| 162 | cp->elements[old_idx].dl)) { | 165 | cp->elements[old_idx].dl)) { |
| @@ -173,7 +176,7 @@ void cpudl_set(struct cpudl *cp, int cpu, u64 dl, int is_valid) | |||
| 173 | cp->size++; | 176 | cp->size++; |
| 174 | cp->elements[cp->size - 1].dl = 0; | 177 | cp->elements[cp->size - 1].dl = 0; |
| 175 | cp->elements[cp->size - 1].cpu = cpu; | 178 | cp->elements[cp->size - 1].cpu = cpu; |
| 176 | cp->cpu_to_idx[cpu] = cp->size - 1; | 179 | cp->elements[cpu].idx = cp->size - 1; |
| 177 | cpudl_change_key(cp, cp->size - 1, dl); | 180 | cpudl_change_key(cp, cp->size - 1, dl); |
| 178 | cpumask_clear_cpu(cpu, cp->free_cpus); | 181 | cpumask_clear_cpu(cpu, cp->free_cpus); |
| 179 | } else { | 182 | } else { |
| @@ -195,10 +198,21 @@ int cpudl_init(struct cpudl *cp) | |||
| 195 | memset(cp, 0, sizeof(*cp)); | 198 | memset(cp, 0, sizeof(*cp)); |
| 196 | raw_spin_lock_init(&cp->lock); | 199 | raw_spin_lock_init(&cp->lock); |
| 197 | cp->size = 0; | 200 | cp->size = 0; |
| 198 | for (i = 0; i < NR_CPUS; i++) | 201 | |
| 199 | cp->cpu_to_idx[i] = IDX_INVALID; | 202 | cp->elements = kcalloc(nr_cpu_ids, |
| 200 | if (!alloc_cpumask_var(&cp->free_cpus, GFP_KERNEL)) | 203 | sizeof(struct cpudl_item), |
| 204 | |||
