diff options
author | Nicolas Pitre <nicolas.pitre@linaro.org> | 2017-06-21 14:22:01 -0400 |
---|---|---|
committer | Ingo Molnar <mingo@kernel.org> | 2017-06-23 04:46:45 -0400 |
commit | 06a76fe08d4daaeea01ca0f175ad29f40c781ece (patch) | |
tree | 241c0de99295286aa65d55766129c30a1be955c6 | |
parent | e1d4eeec5aaa28d25f249c0195b0e1d9b9feb7bd (diff) |
sched/deadline: Move DL related code from sched/core.c to sched/deadline.c
This helps making sched/core.c smaller and hopefully easier to understand and maintain.
Signed-off-by: Nicolas Pitre <nico@linaro.org>
Cc: Linus Torvalds <torvalds@linux-foundation.org>
Cc: Peter Zijlstra <peterz@infradead.org>
Cc: Thomas Gleixner <tglx@linutronix.de>
Link: http://lkml.kernel.org/r/20170621182203.30626-2-nicolas.pitre@linaro.org
Signed-off-by: Ingo Molnar <mingo@kernel.org>
-rw-r--r-- | kernel/sched/core.c | 343 | ||||
-rw-r--r-- | kernel/sched/deadline.c | 344 | ||||
-rw-r--r-- | kernel/sched/sched.h | 17 |
3 files changed, 364 insertions, 340 deletions
diff --git a/kernel/sched/core.c b/kernel/sched/core.c index 7faf4b322b63..54e1b0700af3 100644 --- a/kernel/sched/core.c +++ b/kernel/sched/core.c | |||
@@ -2140,25 +2140,6 @@ int wake_up_state(struct task_struct *p, unsigned int state) | |||
2140 | } | 2140 | } |
2141 | 2141 | ||
2142 | /* | 2142 | /* |
2143 | * This function clears the sched_dl_entity static params. | ||
2144 | */ | ||
2145 | void __dl_clear_params(struct task_struct *p) | ||
2146 | { | ||
2147 | struct sched_dl_entity *dl_se = &p->dl; | ||
2148 | |||
2149 | dl_se->dl_runtime = 0; | ||
2150 | dl_se->dl_deadline = 0; | ||
2151 | dl_se->dl_period = 0; | ||
2152 | dl_se->flags = 0; | ||
2153 | dl_se->dl_bw = 0; | ||
2154 | dl_se->dl_density = 0; | ||
2155 | |||
2156 | dl_se->dl_throttled = 0; | ||
2157 | dl_se->dl_yielded = 0; | ||
2158 | dl_se->dl_non_contending = 0; | ||
2159 | } | ||
2160 | |||
2161 | /* | ||
2162 | * Perform scheduler related setup for a newly forked process p. | 2143 | * Perform scheduler related setup for a newly forked process p. |
2163 | * p is forked by current. | 2144 | * p is forked by current. |
2164 | * | 2145 | * |
@@ -2438,101 +2419,6 @@ unsigned long to_ratio(u64 period, u64 runtime) | |||
2438 | return div64_u64(runtime << BW_SHIFT, period); | 2419 | return div64_u64(runtime << BW_SHIFT, period); |
2439 | } | 2420 | } |
2440 | 2421 | ||
2441 | #ifdef CONFIG_SMP | ||
2442 | inline struct dl_bw *dl_bw_of(int i) | ||
2443 | { | ||
2444 | RCU_LOCKDEP_WARN(!rcu_read_lock_sched_held(), | ||
2445 | "sched RCU must be held"); | ||
2446 | return &cpu_rq(i)->rd->dl_bw; | ||
2447 | } | ||
2448 | |||
2449 | inline int dl_bw_cpus(int i) | ||
2450 | { | ||
2451 | struct root_domain *rd = cpu_rq(i)->rd; | ||
2452 | int cpus = 0; | ||
2453 | |||
2454 | RCU_LOCKDEP_WARN(!rcu_read_lock_sched_held(), | ||
2455 | "sched RCU must be held"); | ||
2456 | for_each_cpu_and(i, rd->span, cpu_active_mask) | ||
2457 | cpus++; | ||
2458 | |||
2459 | return cpus; | ||
2460 | } | ||
2461 | #else | ||
2462 | inline struct dl_bw *dl_bw_of(int i) | ||
2463 | { | ||
2464 | return &cpu_rq(i)->dl.dl_bw; | ||
2465 | } | ||
2466 | |||
2467 | inline int dl_bw_cpus(int i) | ||
2468 | { | ||
2469 | return 1; | ||
2470 | } | ||
2471 | #endif | ||
2472 | |||
2473 | /* | ||
2474 | * We must be sure that accepting a new task (or allowing changing the | ||
2475 | * parameters of an existing one) is consistent with the bandwidth | ||
2476 | * constraints. If yes, this function also accordingly updates the currently | ||
2477 | * allocated bandwidth to reflect the new situation. | ||
2478 | * | ||
2479 | * This function is called while holding p's rq->lock. | ||
2480 | */ | ||
2481 | static int dl_overflow(struct task_struct *p, int policy, | ||
2482 | const struct sched_attr *attr) | ||
2483 | { | ||
2484 | |||
2485 | struct dl_bw *dl_b = dl_bw_of(task_cpu(p)); | ||
2486 | u64 period = attr->sched_period ?: attr->sched_deadline; | ||
2487 | u64 runtime = attr->sched_runtime; | ||
2488 | u64 new_bw = dl_policy(policy) ? to_ratio(period, runtime) : 0; | ||
2489 | int cpus, err = -1; | ||
2490 | |||
2491 | /* !deadline task may carry old deadline bandwidth */ | ||
2492 | if (new_bw == p->dl.dl_bw && task_has_dl_policy(p)) | ||
2493 | return 0; | ||
2494 | |||
2495 | /* | ||
2496 | * Either if a task, enters, leave, or stays -deadline but changes | ||
2497 | * its parameters, we may need to update accordingly the total | ||
2498 | * allocated bandwidth of the container. | ||
2499 | */ | ||
2500 | raw_spin_lock(&dl_b->lock); | ||
2501 | cpus = dl_bw_cpus(task_cpu(p)); | ||
2502 | if (dl_policy(policy) && !task_has_dl_policy(p) && | ||
2503 | !__dl_overflow(dl_b, cpus, 0, new_bw)) { | ||
2504 | if (hrtimer_active(&p->dl.inactive_timer)) | ||
2505 | __dl_clear(dl_b, p->dl.dl_bw, cpus); | ||
2506 | __dl_add(dl_b, new_bw, cpus); | ||
2507 | err = 0; | ||
2508 | } else if (dl_policy(policy) && task_has_dl_policy(p) && | ||
2509 | !__dl_overflow(dl_b, cpus, p->dl.dl_bw, new_bw)) { | ||
2510 | /* | ||
2511 | * XXX this is slightly incorrect: when the task | ||
2512 | * utilization decreases, we should delay the total | ||
2513 | * utilization change until the task's 0-lag point. | ||
2514 | * But this would require to set the task's "inactive | ||
2515 | * timer" when the task is not inactive. | ||
2516 | */ | ||
2517 | __dl_clear(dl_b, p->dl.dl_bw, cpus); | ||
2518 | __dl_add(dl_b, new_bw, cpus); | ||
2519 | dl_change_utilization(p, new_bw); | ||
2520 | err = 0; | ||
2521 | } else if (!dl_policy(policy) && task_has_dl_policy(p)) { | ||
2522 | /* | ||
2523 | * Do not decrease the total deadline utilization here, | ||
2524 | * switched_from_dl() will take care to do it at the correct | ||
2525 | * (0-lag) time. | ||
2526 | */ | ||
2527 | err = 0; | ||
2528 | } | ||
2529 | raw_spin_unlock(&dl_b->lock); | ||
2530 | |||
2531 | return err; | ||
2532 | } | ||
2533 | |||
2534 | extern void init_dl_bw(struct dl_bw *dl_b); | ||
2535 | |||
2536 | /* | 2422 | /* |
2537 | * wake_up_new_task - wake up a newly created task for the first time. | 2423 | * wake_up_new_task - wake up a newly created task for the first time. |
2538 | * | 2424 | * |
@@ -4015,27 +3901,6 @@ static struct task_struct *find_process_by_pid(pid_t pid) | |||
4015 | } | 3901 | } |
4016 | 3902 | ||
4017 | /* | 3903 | /* |
4018 | * This function initializes the sched_dl_entity of a newly becoming | ||
4019 | * SCHED_DEADLINE task. | ||
4020 | * | ||
4021 | * Only the static values are considered here, the actual runtime and the | ||
4022 | * absolute deadline will be properly calculated when the task is enqueued | ||
4023 | * for the first time with its new policy. | ||
4024 | */ | ||
4025 | static void | ||
4026 | __setparam_dl(struct task_struct *p, const struct sched_attr *attr) | ||
4027 | { | ||
4028 | struct sched_dl_entity *dl_se = &p->dl; | ||
4029 | |||
4030 | dl_se->dl_runtime = attr->sched_runtime; | ||
4031 | dl_se->dl_deadline = attr->sched_deadline; | ||
4032 | dl_se->dl_period = attr->sched_period ?: dl_se->dl_deadline; | ||
4033 | dl_se->flags = attr->sched_flags; | ||
4034 | dl_se->dl_bw = to_ratio(dl_se->dl_period, dl_se->dl_runtime); | ||
4035 | dl_se->dl_density = to_ratio(dl_se->dl_deadline, dl_se->dl_runtime); | ||
4036 | } | ||
4037 | |||
4038 | /* | ||
4039 | * sched_setparam() passes in -1 for its policy, to let the functions | 3904 | * sched_setparam() passes in -1 for its policy, to let the functions |
4040 | * it calls know not to change it. | 3905 | * it calls know not to change it. |
4041 | */ | 3906 | */ |
@@ -4088,59 +3953,6 @@ static void __setscheduler(struct rq *rq, struct task_struct *p, | |||
4088 | p->sched_class = &fair_sched_class; | 3953 | p->sched_class = &fair_sched_class; |
4089 | } | 3954 | } |
4090 | 3955 | ||
4091 | static void | ||
4092 | __getparam_dl(struct task_struct *p, struct sched_attr *attr) | ||
4093 | { | ||
4094 | struct sched_dl_entity *dl_se = &p->dl; | ||
4095 | |||
4096 | attr->sched_priority = p->rt_priority; | ||
4097 | attr->sched_runtime = dl_se->dl_runtime; | ||
4098 | attr->sched_deadline = dl_se->dl_deadline; | ||
4099 | attr->sched_period = dl_se->dl_period; | ||
4100 | attr->sched_flags = dl_se->flags; | ||
4101 | } | ||
4102 | |||
4103 | /* | ||
4104 | * This function validates the new parameters of a -deadline task. | ||
4105 | * We ask for the deadline not being zero, and greater or equal | ||
4106 | * than the runtime, as well as the period of being zero or | ||
4107 | * greater than deadline. Furthermore, we have to be sure that | ||
4108 | * user parameters are above the internal resolution of 1us (we | ||
4109 | * check sched_runtime only since it is always the smaller one) and | ||
4110 | * below 2^63 ns (we have to check both sched_deadline and | ||
4111 | * sched_period, as the latter can be zero). | ||
4112 | */ | ||
4113 | static bool | ||
4114 | __checkparam_dl(const struct sched_attr *attr) | ||
4115 | { | ||
4116 | /* deadline != 0 */ | ||
4117 | if (attr->sched_deadline == 0) | ||
4118 | return false; | ||
4119 | |||
4120 | /* | ||
4121 | * Since we truncate DL_SCALE bits, make sure we're at least | ||
4122 | * that big. | ||
4123 | */ | ||
4124 | if (attr->sched_runtime < (1ULL << DL_SCALE)) | ||
4125 | return false; | ||
4126 | |||
4127 | /* | ||
4128 | * Since we use the MSB for wrap-around and sign issues, make | ||
4129 | * sure it's not set (mind that period can be equal to zero). | ||
4130 | */ | ||
4131 | if (attr->sched_deadline & (1ULL << 63) || | ||
4132 | attr->sched_period & (1ULL << 63)) | ||
4133 | return false; | ||
4134 | |||
4135 | /* runtime <= deadline <= period (if period != 0) */ | ||
4136 | if ((attr->sched_period != 0 && | ||
4137 | attr->sched_period < attr->sched_deadline) || | ||
4138 | attr->sched_deadline < attr->sched_runtime) | ||
4139 | return false; | ||
4140 | |||
4141 | return true; | ||
4142 | } | ||
4143 | |||
4144 | /* | 3956 | /* |
4145 | * Check the target process has a UID that matches the current process's: | 3957 | * Check the target process has a UID that matches the current process's: |
4146 | */ | 3958 | */ |
@@ -4157,19 +3969,6 @@ static bool check_same_owner(struct task_struct *p) | |||
4157 | return match; | 3969 | return match; |
4158 | } | 3970 | } |
4159 | 3971 | ||
4160 | static bool dl_param_changed(struct task_struct *p, const struct sched_attr *attr) | ||
4161 | { | ||
4162 | struct sched_dl_entity *dl_se = &p->dl; | ||
4163 | |||
4164 | if (dl_se->dl_runtime != attr->sched_runtime || | ||
4165 | dl_se->dl_deadline != attr->sched_deadline || | ||
4166 | dl_se->dl_period != attr->sched_period || | ||
4167 | dl_se->flags != attr->sched_flags) | ||
4168 | return true; | ||
4169 | |||
4170 | return false; | ||
4171 | } | ||
4172 | |||
4173 | static int __sched_setscheduler(struct task_struct *p, | 3972 | static int __sched_setscheduler(struct task_struct *p, |
4174 | const struct sched_attr *attr, | 3973 | const struct sched_attr *attr, |
4175 | bool user, bool pi) | 3974 | bool user, bool pi) |
@@ -4350,7 +4149,7 @@ change: | |||
4350 | * of a SCHED_DEADLINE task) we need to check if enough bandwidth | 4149 | * of a SCHED_DEADLINE task) we need to check if enough bandwidth |
4351 | * is available. | 4150 | * is available. |
4352 | */ | 4151 | */ |
4353 | if ((dl_policy(policy) || dl_task(p)) && dl_overflow(p, policy, attr)) { | 4152 | if ((dl_policy(policy) || dl_task(p)) && sched_dl_overflow(p, policy, attr)) { |
4354 | task_rq_unlock(rq, p, &rf); | 4153 | task_rq_unlock(rq, p, &rf); |
4355 | return -EBUSY; | 4154 | return -EBUSY; |
4356 | } | 4155 | } |
@@ -5456,23 +5255,12 @@ void init_idle(struct task_struct *idle, int cpu) | |||
5456 | int cpuset_cpumask_can_shrink(const struct cpumask *cur, | 5255 | int cpuset_cpumask_can_shrink(const struct cpumask *cur, |
5457 | const struct cpumask *trial) | 5256 | const struct cpumask *trial) |
5458 | { | 5257 | { |
5459 | int ret = 1, trial_cpus; | 5258 | int ret = 1; |
5460 | struct dl_bw *cur_dl_b; | ||
5461 | unsigned long flags; | ||
5462 | 5259 | ||
5463 | if (!cpumask_weight(cur)) | 5260 | if (!cpumask_weight(cur)) |
5464 | return ret; | 5261 | return ret; |
5465 | 5262 | ||
5466 | rcu_read_lock_sched(); | 5263 | ret = dl_cpuset_cpumask_can_shrink(cur, trial); |
5467 | cur_dl_b = dl_bw_of(cpumask_any(cur)); | ||
5468 | trial_cpus = cpumask_weight(trial); | ||
5469 | |||
5470 | raw_spin_lock_irqsave(&cur_dl_b->lock, flags); | ||
5471 | if (cur_dl_b->bw != -1 && | ||
5472 | cur_dl_b->bw * trial_cpus < cur_dl_b->total_bw) | ||
5473 | ret = 0; | ||
5474 | raw_spin_unlock_irqrestore(&cur_dl_b->lock, flags); | ||
5475 | rcu_read_unlock_sched(); | ||
5476 | 5264 | ||
5477 | return ret; | 5265 | return ret; |
5478 | } | 5266 | } |
@@ -5497,34 +5285,8 @@ int task_can_attach(struct task_struct *p, | |||
5497 | } | 5285 | } |
5498 | 5286 | ||
5499 | if (dl_task(p) && !cpumask_intersects(task_rq(p)->rd->span, | 5287 | if (dl_task(p) && !cpumask_intersects(task_rq(p)->rd->span, |
5500 | cs_cpus_allowed)) { | 5288 | cs_cpus_allowed)) |
5501 | unsigned int dest_cpu = cpumask_any_and(cpu_active_mask, | 5289 | ret = dl_task_can_attach(p, cs_cpus_allowed); |
5502 | cs_cpus_allowed); | ||
5503 | struct dl_bw *dl_b; | ||
5504 | bool overflow; | ||
5505 | int cpus; | ||
5506 | unsigned long flags; | ||
5507 | |||
5508 | rcu_read_lock_sched(); | ||
5509 | dl_b = dl_bw_of(dest_cpu); | ||
5510 | raw_spin_lock_irqsave(&dl_b->lock, flags); | ||
5511 | cpus = dl_bw_cpus(dest_cpu); | ||
5512 | overflow = __dl_overflow(dl_b, cpus, 0, p->dl.dl_bw); | ||
5513 | if (overflow) | ||
5514 | ret = -EBUSY; | ||
5515 | else { | ||
5516 | /* | ||
5517 | * We reserve space for this task in the destination | ||
5518 | * root_domain, as we can't fail after this point. | ||
5519 | * We will free resources in the source root_domain | ||
5520 | * later on (see set_cpus_allowed_dl()). | ||
5521 | */ | ||
5522 | __dl_add(dl_b, p->dl.dl_bw, cpus); | ||
5523 | } | ||
5524 | raw_spin_unlock_irqrestore(&dl_b->lock, flags); | ||
5525 | rcu_read_unlock_sched(); | ||
5526 | |||
5527 | } | ||
5528 | 5290 | ||
5529 | out: | 5291 | out: |
5530 | return ret; | 5292 | return ret; |
@@ -5792,23 +5554,8 @@ static void cpuset_cpu_active(void) | |||
5792 | 5554 | ||
5793 | static int cpuset_cpu_inactive(unsigned int cpu) | 5555 | static int cpuset_cpu_inactive(unsigned int cpu) |
5794 | { | 5556 | { |
5795 | unsigned long flags; | ||
5796 | struct dl_bw *dl_b; | ||
5797 | bool overflow; | ||
5798 | int cpus; | ||
5799 | |||
5800 | if (!cpuhp_tasks_frozen) { | 5557 | if (!cpuhp_tasks_frozen) { |
5801 | rcu_read_lock_sched(); | 5558 | if (dl_cpu_busy(cpu)) |
5802 | dl_b = dl_bw_of(cpu); | ||
5803 | |||
5804 | raw_spin_lock_irqsave(&dl_b->lock, flags); | ||
5805 | cpus = dl_bw_cpus(cpu); | ||
5806 | overflow = __dl_overflow(dl_b, cpus, 0, 0); | ||
5807 | raw_spin_unlock_irqrestore(&dl_b->lock, flags); | ||
5808 | |||
5809 | rcu_read_unlock_sched(); | ||
5810 | |||
5811 | if (overflow) | ||
5812 | return -EBUSY; | 5559 | return -EBUSY; |
5813 | cpuset_update_active_cpus(); | 5560 | cpuset_update_active_cpus(); |
5814 | } else { | 5561 | } else { |
@@ -6711,84 +6458,6 @@ static int sched_rt_global_constraints(void) | |||
6711 | } | 6458 | } |
6712 | #endif /* CONFIG_RT_GROUP_SCHED */ | 6459 | #endif /* CONFIG_RT_GROUP_SCHED */ |
6713 | 6460 | ||
6714 | static int sched_dl_global_validate(void) | ||
6715 | { | ||
6716 | u64 runtime = global_rt_runtime(); | ||
6717 | u64 period = global_rt_period(); | ||
6718 | u64 new_bw = to_ratio(period, runtime); | ||
6719 | struct dl_bw *dl_b; | ||
6720 | int cpu, ret = 0; | ||
6721 | unsigned long flags; | ||
6722 | |||
6723 | /* | ||
6724 | * Here we want to check the bandwidth not being set to some | ||
6725 | * value smaller than the currently allocated bandwidth in | ||
6726 | * any of the root_domains. | ||
6727 | * | ||
6728 | * FIXME: Cycling on all the CPUs is overdoing, but simpler than | ||
6729 | * cycling on root_domains... Discussion on different/better | ||
6730 | * solutions is welcome! | ||
6731 | */ | ||
6732 | for_each_possible_cpu(cpu) { | ||
6733 | rcu_read_lock_sched(); | ||
6734 | dl_b = dl_bw_of(cpu); | ||
6735 | |||
6736 | raw_spin_lock_irqsave(&dl_b->lock, flags); | ||
6737 | if (new_bw < dl_b->total_bw) | ||
6738 | ret = -EBUSY; | ||
6739 | raw_spin_unlock_irqrestore(&dl_b->lock, flags); | ||
6740 | |||
6741 | rcu_read_unlock_sched(); | ||
6742 | |||
6743 | if (ret) | ||
6744 | break; | ||
6745 | } | ||
6746 | |||
6747 | return ret; | ||
6748 | } | ||
6749 | |||
6750 | void init_dl_rq_bw_ratio(struct dl_rq *dl_rq) | ||
6751 | { | ||
6752 | if (global_rt_runtime() == RUNTIME_INF) { | ||
6753 | dl_rq->bw_ratio = 1 << RATIO_SHIFT; | ||
6754 | dl_rq->extra_bw = 1 << BW_SHIFT; | ||
6755 | } else { | ||
6756 | dl_rq->bw_ratio = to_ratio(global_rt_runtime(), | ||
6757 | global_rt_period()) >> (BW_SHIFT - RATIO_SHIFT); | ||
6758 | dl_rq->extra_bw = to_ratio(global_rt_period(), | ||
6759 | global_rt_runtime()); | ||
6760 | } | ||
6761 | } | ||
6762 | |||
6763 | static void sched_dl_do_global(void) | ||
6764 | { | ||
6765 | u64 new_bw = -1; | ||
6766 | struct dl_bw *dl_b; | ||
6767 | int cpu; | ||
6768 | unsigned long flags; | ||
6769 | |||
6770 | def_dl_bandwidth.dl_period = global_rt_period(); | ||
6771 | def_dl_bandwidth.dl_runtime = global_rt_runtime(); | ||
6772 | |||
6773 | if (global_rt_runtime() != RUNTIME_INF) | ||
6774 | new_bw = to_ratio(global_rt_period(), global_rt_runtime()); | ||
6775 | |||
6776 | /* | ||
6777 | * FIXME: As above... | ||
6778 | */ | ||
6779 | for_each_possible_cpu(cpu) { | ||
6780 | rcu_read_lock_sched(); | ||
6781 | dl_b = dl_bw_of(cpu); | ||
6782 | |||
6783 | raw_spin_lock_irqsave(&dl_b->lock, flags); | ||
6784 | dl_b->bw = new_bw; | ||
6785 | raw_spin_unlock_irqrestore(&dl_b->lock, flags); | ||
6786 | |||
6787 | rcu_read_unlock_sched(); | ||
6788 | init_dl_rq_bw_ratio(&cpu_rq(cpu)->dl); | ||
6789 | } | ||
6790 | } | ||
6791 | |||
6792 | static int sched_rt_global_validate(void) | 6461 | static int sched_rt_global_validate(void) |
6793 | { | 6462 | { |
6794 | if (sysctl_sched_rt_period <= 0) | 6463 | if (sysctl_sched_rt_period <= 0) |
diff --git a/kernel/sched/deadline.c b/kernel/sched/deadline.c index e12f85975857..a84299f44b5d 100644 --- a/kernel/sched/deadline.c +++ b/kernel/sched/deadline.c | |||
@@ -17,6 +17,7 @@ | |||
17 | #include "sched.h" | 17 | #include "sched.h" |
18 | 18 | ||
19 | #include <linux/slab.h> | 19 | #include <linux/slab.h> |
20 | #include <uapi/linux/sched/types.h> | ||
20 | 21 | ||
21 | struct dl_bandwidth def_dl_bandwidth; | 22 | struct dl_bandwidth def_dl_bandwidth; |
22 | 23 | ||
@@ -43,6 +44,38 @@ static inline int on_dl_rq(struct sched_dl_entity *dl_se) | |||
43 | return !RB_EMPTY_NODE(&dl_se->rb_node); | 44 | return !RB_EMPTY_NODE(&dl_se->rb_node); |
44 | } | 45 | } |
45 | 46 | ||
47 | #ifdef CONFIG_SMP | ||
48 | static inline struct dl_bw *dl_bw_of(int i) | ||
49 | { | ||
50 | RCU_LOCKDEP_WARN(!rcu_read_lock_sched_held(), | ||
51 | "sched RCU must be held"); | ||
52 | return &cpu_rq(i)->rd->dl_bw; | ||
53 | } | ||
54 | |||
55 | static inline int dl_bw_cpus(int i) | ||
56 | { | ||
57 | struct root_domain *rd = cpu_rq(i)->rd; | ||
58 | int cpus = 0; | ||
59 | |||
60 | RCU_LOCKDEP_WARN(!rcu_read_lock_sched_held(), | ||
61 | "sched RCU must be held"); | ||
62 | for_each_cpu_and(i, rd->span, cpu_active_mask) | ||
63 | cpus++; | ||
64 | |||
65 | return cpus; | ||
66 | } | ||
67 | #else | ||
68 | static inline struct dl_bw *dl_bw_of(int i) | ||
69 | { | ||
70 | return &cpu_rq(i)->dl.dl_bw; | ||
71 | } | ||
72 | |||
73 | static inline int dl_bw_cpus(int i) | ||
74 | { | ||
75 | return 1; | ||
76 | } | ||
77 | #endif | ||
78 | |||
46 | static inline | 79 | static inline |
47 | void add_running_bw(u64 dl_bw, struct dl_rq *dl_rq) | 80 | void add_running_bw(u64 dl_bw, struct dl_rq *dl_rq) |
48 | { | 81 | { |
@@ -2318,6 +2351,317 @@ const struct sched_class dl_sched_class = { | |||
2318 | .update_curr = update_curr_dl, | 2351 | .update_curr = update_curr_dl, |
2319 | }; | 2352 | }; |
2320 | 2353 | ||
2354 | int sched_dl_global_validate(void) | ||
2355 | { | ||
2356 | u64 runtime = global_rt_runtime(); | ||
2357 | u64 period = global_rt_period(); | ||
2358 | u64 new_bw = to_ratio(period, runtime); | ||
2359 | struct dl_bw *dl_b; | ||
2360 | int cpu, ret = 0; | ||
2361 | unsigned long flags; | ||
2362 | |||
2363 | /* | ||
2364 | * Here we want to check the bandwidth not being set to some | ||
2365 | * value smaller than the currently allocated bandwidth in | ||
2366 | * any of the root_domains. | ||
2367 | * | ||
2368 | * FIXME: Cycling on all the CPUs is overdoing, but simpler than | ||
2369 | * cycling on root_domains... Discussion on different/better | ||
2370 | * solutions is welcome! | ||
2371 | */ | ||
2372 | for_each_possible_cpu(cpu) { | ||
2373 | rcu_read_lock_sched(); | ||
2374 | dl_b = dl_bw_of(cpu); | ||
2375 | |||
2376 | raw_spin_lock_irqsave(&dl_b->lock, flags); | ||
2377 | if (new_bw < dl_b->total_bw) | ||
2378 | ret = -EBUSY; | ||
2379 | raw_spin_unlock_irqrestore(&dl_b->lock, flags); | ||
2380 | |||
2381 | rcu_read_unlock_sched(); | ||
2382 | |||
2383 | if (ret) | ||
2384 | break; | ||
2385 | } | ||
2386 | |||
2387 | return ret; | ||
2388 | } | ||
2389 | |||
2390 | void init_dl_rq_bw_ratio(struct dl_rq *dl_rq) | ||
2391 | { | ||
2392 | if (global_rt_runtime() == RUNTIME_INF) { | ||
2393 | dl_rq->bw_ratio = 1 << RATIO_SHIFT; | ||
2394 | dl_rq->extra_bw = 1 << BW_SHIFT; | ||
2395 | } else { | ||
2396 | dl_rq->bw_ratio = to_ratio(global_rt_runtime(), | ||
2397 | global_rt_period()) >> (BW_SHIFT - RATIO_SHIFT); | ||
2398 | dl_rq->extra_bw = to_ratio(global_rt_period(), | ||
2399 | global_rt_runtime()); | ||
2400 | } | ||
2401 | } | ||
2402 | |||
2403 | void sched_dl_do_global(void) | ||
2404 | { | ||
2405 | u64 new_bw = -1; | ||
2406 | struct dl_bw *dl_b; | ||
2407 | int cpu; | ||
2408 | unsigned long flags; | ||
2409 | |||
2410 | def_dl_bandwidth.dl_period = global_rt_period(); | ||
2411 | def_dl_bandwidth.dl_runtime = global_rt_runtime(); | ||
2412 | |||
2413 | if (global_rt_runtime() != RUNTIME_INF) | ||
2414 | new_bw = to_ratio(global_rt_period(), global_rt_runtime()); | ||
2415 | |||
2416 | /* | ||
2417 | * FIXME: As above... | ||
2418 | */ | ||
2419 | for_each_possible_cpu(cpu) { | ||
2420 | rcu_read_lock_sched(); | ||
2421 | dl_b = dl_bw_of(cpu); | ||
2422 | |||
2423 | raw_spin_lock_irqsave(&dl_b->lock, flags); | ||
2424 | dl_b->bw = new_bw; | ||
2425 | raw_spin_unlock_irqrestore(&dl_b->lock, flags); | ||
2426 | |||
2427 | rcu_read_unlock_sched(); | ||
2428 | init_dl_rq_bw_ratio(&cpu_rq(cpu)->dl); | ||
2429 | } | ||
2430 | } | ||
2431 | |||
2432 | /* | ||
2433 | * We must be sure that accepting a new task (or allowing changing the | ||
2434 | * parameters of an existing one) is consistent with the bandwidth | ||
2435 | * constraints. If yes, this function also accordingly updates the currently | ||
2436 | * allocated bandwidth to reflect the new situation. | ||
2437 | * | ||
2438 | * This function is called while holding p's rq->lock. | ||
2439 | */ | ||
2440 | int sched_dl_overflow(struct task_struct *p, int policy, | ||
2441 | const struct sched_attr *attr) | ||
2442 | { | ||
2443 | struct dl_bw *dl_b = dl_bw_of(task_cpu(p)); | ||
2444 | u64 period = attr->sched_period ?: attr->sched_deadline; | ||
2445 | u64 runtime = attr->sched_runtime; | ||
2446 | u64 new_bw = dl_policy(policy) ? to_ratio(period, runtime) : 0; | ||
2447 | int cpus, err = -1; | ||
2448 | |||
2449 | /* !deadline task may carry old deadline bandwidth */ | ||
2450 | if (new_bw == p->dl.dl_bw && task_has_dl_policy(p)) | ||
2451 | return 0; | ||
2452 | |||
2453 | /* | ||
2454 | * Either if a task, enters, leave, or stays -deadline but changes | ||
2455 | * its parameters, we may need to update accordingly the total | ||
2456 | * allocated bandwidth of the container. | ||
2457 | */ | ||
2458 | raw_spin_lock(&dl_b->lock); | ||
2459 | cpus = dl_bw_cpus(task_cpu(p)); | ||
2460 | if (dl_policy(policy) && !task_has_dl_policy(p) && | ||
2461 | !__dl_overflow(dl_b, cpus, 0, new_bw)) { | ||
2462 | if (hrtimer_active(&p->dl.inactive_timer)) | ||
2463 | __dl_clear(dl_b, p->dl.dl_bw, cpus); | ||
2464 | __dl_add(dl_b, new_bw, cpus); | ||
2465 | err = 0; | ||
2466 | } else if (dl_policy(policy) && task_has_dl_policy(p) && | ||
2467 | !__dl_overflow(dl_b, cpus, p->dl.dl_bw, new_bw)) { | ||
2468 | /* | ||
2469 | * XXX this is slightly incorrect: when the task | ||
2470 | * utilization decreases, we should delay the total | ||
2471 | * utilization change until the task's 0-lag point. | ||
2472 | * But this would require to set the task's "inactive | ||
2473 | * timer" when the task is not inactive. | ||
2474 | */ | ||
2475 | __dl_clear(dl_b, p->dl.dl_bw, cpus); | ||
2476 | __dl_add(dl_b, new_bw, cpus); | ||
2477 | dl_change_utilization(p, new_bw); | ||
2478 | err = 0; | ||
2479 | } else if (!dl_policy(policy) && task_has_dl_policy(p)) { | ||
2480 | /* | ||
2481 | * Do not decrease the total deadline utilization here, | ||
2482 | * switched_from_dl() will take care to do it at the correct | ||
2483 | * (0-lag) time. | ||
2484 | */ | ||
2485 | err = 0; | ||
2486 | } | ||
2487 | raw_spin_unlock(&dl_b->lock); | ||
2488 | |||
2489 | return err; | ||
2490 | } | ||
2491 | |||
2492 | /* | ||
2493 | * This function initializes the sched_dl_entity of a newly becoming | ||
2494 | * SCHED_DEADLINE task. | ||
2495 | * | ||
2496 | * Only the static values are considered here, the actual runtime and the | ||
2497 | * absolute deadline will be properly calculated when the task is enqueued | ||
2498 | * for the first time with its new policy. | ||
2499 | */ | ||
2500 | void __setparam_dl(struct task_struct *p, const struct sched_attr *attr) | ||
2501 | { | ||
2502 | struct sched_dl_entity *dl_se = &p->dl; | ||
2503 | |||
2504 | dl_se->dl_runtime = attr->sched_runtime; | ||
2505 | dl_se->dl_deadline = attr->sched_deadline; | ||
2506 | dl_se->dl_period = attr->sched_period ?: dl_se->dl_deadline; | ||
2507 | dl_se->flags = attr->sched_flags; | ||
2508 | dl_se->dl_bw = to_ratio(dl_se->dl_period, dl_se->dl_runtime); | ||
2509 | dl_se->dl_density = to_ratio(dl_se->dl_deadline, dl_se->dl_runtime); | ||
2510 | } | ||
2511 | |||
2512 | void __getparam_dl(struct task_struct *p, struct sched_attr *attr) | ||
2513 | { | ||
2514 | struct sched_dl_entity *dl_se = &p->dl; | ||
2515 | |||
2516 | attr->sched_priority = p->rt_priority; | ||
2517 | attr->sched_runtime = dl_se->dl_runtime; | ||
2518 | attr->sched_deadline = dl_se->dl_deadline; | ||
2519 | attr->sched_period = dl_se->dl_period; | ||
2520 | attr->sched_flags = dl_se->flags; | ||
2521 | } | ||
2522 | |||
2523 | /* | ||
2524 | * This function validates the new parameters of a -deadline task. | ||
2525 | * We ask for the deadline not being zero, and greater or equal | ||
2526 | * than the runtime, as well as the period of being zero or | ||
2527 | * greater than deadline. Furthermore, we have to be sure that | ||
2528 | * user parameters are above the internal resolution of 1us (we | ||
2529 | * check sched_runtime only since it is always the smaller one) and | ||
2530 | * below 2^63 ns (we have to check both sched_deadline and | ||
2531 | * sched_period, as the latter can be zero). | ||
2532 | */ | ||
2533 | bool __checkparam_dl(const struct sched_attr *attr) | ||
2534 | { | ||
2535 | /* deadline != 0 */ | ||
2536 | if (attr->sched_deadline == 0) | ||
2537 | return false; | ||
2538 | |||
2539 | /* | ||
2540 | * Since we truncate DL_SCALE bits, make sure we're at least | ||
2541 | * that big. | ||
2542 | */ | ||
2543 | if (attr->sched_runtime < (1ULL << DL_SCALE)) | ||
2544 | return false; | ||
2545 | |||
2546 | /* | ||
2547 | * Since we use the MSB for wrap-around and sign issues, make | ||
2548 | * sure it's not set (mind that period can be equal to zero). | ||
2549 | */ | ||
2550 | if (attr->sched_deadline & (1ULL << 63) || | ||
2551 | attr->sched_period & (1ULL << 63)) | ||
2552 | return false; | ||
2553 | |||
2554 | /* runtime <= deadline <= period (if period != 0) */ | ||
2555 | if ((attr->sched_period != 0 && | ||
2556 | attr->sched_period < attr->sched_deadline) || | ||
2557 | attr->sched_deadline < attr->sched_runtime) | ||
2558 | return false; | ||
2559 | |||
2560 | return true; | ||
2561 | } | ||
2562 | |||
2563 | /* | ||
2564 | * This function clears the sched_dl_entity static params. | ||
2565 | */ | ||
2566 | void __dl_clear_params(struct task_struct *p) | ||
2567 | { | ||
2568 | struct sched_dl_entity *dl_se = &p->dl; | ||
2569 | |||
2570 | dl_se->dl_runtime = 0; | ||
2571 | dl_se->dl_deadline = 0; | ||
2572 | dl_se->dl_period = 0; | ||
2573 | dl_se->flags = 0; | ||
2574 | dl_se->dl_bw = 0; | ||
2575 | dl_se->dl_density = 0; | ||
2576 | |||
2577 | dl_se->dl_throttled = 0; | ||
2578 | dl_se->dl_yielded = 0; | ||
2579 | dl_se->dl_non_contending = 0; | ||
2580 | } | ||
2581 | |||
2582 | bool dl_param_changed(struct task_struct *p, const struct sched_attr *attr) | ||
2583 | { | ||
2584 | struct sched_dl_entity *dl_se = &p->dl; | ||
2585 | |||
2586 | if (dl_se->dl_runtime != attr->sched_runtime || | ||
2587 | dl_se->dl_deadline != attr->sched_deadline || | ||
2588 | dl_se->dl_period != attr->sched_period || | ||
2589 | dl_se->flags != attr->sched_flags) | ||
2590 | return true; | ||
2591 | |||
2592 | return false; | ||
2593 | } | ||
2594 | |||
2595 | #ifdef CONFIG_SMP | ||
2596 | int dl_task_can_attach(struct task_struct *p, const struct cpumask *cs_cpus_allowed) | ||
2597 | { | ||
2598 | unsigned int dest_cpu = cpumask_any_and(cpu_active_mask, | ||
2599 | cs_cpus_allowed); | ||
2600 | struct dl_bw *dl_b; | ||
2601 | bool overflow; | ||
2602 | int cpus, ret; | ||
2603 | unsigned long flags; | ||
2604 | |||
2605 | rcu_read_lock_sched(); | ||
2606 | dl_b = dl_bw_of(dest_cpu); | ||
2607 | raw_spin_lock_irqsave(&dl_b->lock, flags); | ||
2608 | cpus = dl_bw_cpus(dest_cpu); | ||
2609 | overflow = __dl_overflow(dl_b, cpus, 0, p->dl.dl_bw); | ||
2610 | if (overflow) | ||
2611 | ret = -EBUSY; | ||
2612 | else { | ||
2613 | /* | ||
2614 | * We reserve space for this task in the destination | ||
2615 | * root_domain, as we can't fail after this point. | ||
2616 | * We will free resources in the source root_domain | ||
2617 | * later on (see set_cpus_allowed_dl()). | ||
2618 | */ | ||
2619 | __dl_add(dl_b, p->dl.dl_bw, cpus); | ||
2620 | ret = 0; | ||
2621 | } | ||
2622 | raw_spin_unlock_irqrestore(&dl_b->lock, flags); | ||
2623 | rcu_read_unlock_sched(); | ||
2624 | return ret; | ||
2625 | } | ||
2626 | |||
2627 | int dl_cpuset_cpumask_can_shrink(const struct cpumask *cur, | ||
2628 | const struct cpumask *trial) | ||
2629 | { | ||
2630 | int ret = 1, trial_cpus; | ||
2631 | struct dl_bw *cur_dl_b; | ||
2632 | unsigned long flags; | ||
2633 | |||
2634 | rcu_read_lock_sched(); | ||
2635 | cur_dl_b = dl_bw_of(cpumask_any(cur)); | ||
2636 | trial_cpus = cpumask_weight(trial); | ||
2637 | |||
2638 | raw_spin_lock_irqsave(&cur_dl_b->lock, flags); | ||
2639 | if (cur_dl_b->bw != -1 && | ||
2640 | cur_dl_b->bw * trial_cpus < cur_dl_b->total_bw) | ||
2641 | ret = 0; | ||
2642 | raw_spin_unlock_irqrestore(&cur_dl_b->lock, flags); | ||
2643 | rcu_read_unlock_sched(); | ||
2644 | return ret; | ||
2645 | } | ||
2646 | |||
2647 | bool dl_cpu_busy(unsigned int cpu) | ||
2648 | { | ||
2649 | unsigned long flags; | ||
2650 | struct dl_bw *dl_b; | ||
2651 | bool overflow; | ||
2652 | int cpus; | ||
2653 | |||
2654 | rcu_read_lock_sched(); | ||
2655 | dl_b = dl_bw_of(cpu); | ||
2656 | raw_spin_lock_irqsave(&dl_b->lock, flags); | ||
2657 | cpus = dl_bw_cpus(cpu); | ||
2658 | overflow = __dl_overflow(dl_b, cpus, 0, 0); | ||
2659 | raw_spin_unlock_irqrestore(&dl_b->lock, flags); | ||
2660 | rcu_read_unlock_sched(); | ||
2661 | return overflow; | ||
2662 | } | ||
2663 | #endif | ||
2664 | |||
2321 | #ifdef CONFIG_SCHED_DEBUG | 2665 | #ifdef CONFIG_SCHED_DEBUG |
2322 | extern void print_dl_rq(struct seq_file *m, int cpu, struct dl_rq *dl_rq); | 2666 | extern void print_dl_rq(struct seq_file *m, int cpu, struct dl_rq *dl_rq); |
2323 | 2667 | ||
diff --git a/kernel/sched/sched.h b/kernel/sched/sched.h index e0329d10bdb8..d4eb3f67529d 100644 --- a/kernel/sched/sched.h +++ b/kernel/sched/sched.h | |||
@@ -218,9 +218,6 @@ static inline int dl_bandwidth_enabled(void) | |||
218 | return sysctl_sched_rt_runtime >= 0; | 218 | return sysctl_sched_rt_runtime >= 0; |
219 | } | 219 | } |
220 | 220 | ||
221 | extern struct dl_bw *dl_bw_of(int i); | ||
222 | extern int dl_bw_cpus(int i); | ||
223 | |||
224 | struct dl_bw { | 221 | struct dl_bw { |
225 | raw_spinlock_t lock; | 222 | raw_spinlock_t lock; |
226 | u64 bw, total_bw; | 223 | u64 bw, total_bw; |
@@ -251,6 +248,20 @@ bool __dl_overflow(struct dl_bw *dl_b, int cpus, u64 old_bw, u64 new_bw) | |||
251 | 248 | ||
252 | void dl_change_utilization(struct task_struct *p, u64 new_bw); | 249 | void dl_change_utilization(struct task_struct *p, u64 new_bw); |
253 | extern void init_dl_bw(struct dl_bw *dl_b); | 250 | extern void init_dl_bw(struct dl_bw *dl_b); |
251 | extern int sched_dl_global_validate(void); | ||
252 | extern void sched_dl_do_global(void); | ||
253 | extern int sched_dl_overflow(struct task_struct *p, int policy, | ||
254 | const struct sched_attr *attr); | ||
255 | extern void __setparam_dl(struct task_struct *p, const struct sched_attr *attr); | ||
256 | extern void __getparam_dl(struct task_struct *p, struct sched_attr *attr); | ||
257 | extern bool __checkparam_dl(const struct sched_attr *attr); | ||
258 | extern void __dl_clear_params(struct task_struct *p); | ||
259 | extern bool dl_param_changed(struct task_struct *p, const struct sched_attr *attr); | ||
260 | extern int dl_task_can_attach(struct task_struct *p, | ||
261 | const struct cpumask *cs_cpus_allowed); | ||
262 | extern int dl_cpuset_cpumask_can_shrink(const struct cpumask *cur, | ||
263 | const struct cpumask *trial); | ||
264 | extern bool dl_cpu_busy(unsigned int cpu); | ||
254 | 265 | ||
255 | #ifdef CONFIG_CGROUP_SCHED | 266 | #ifdef CONFIG_CGROUP_SCHED |
256 | 267 | ||