| @@ -296,6 +296,15 @@ __read_mostly int scheduler_running; · 295 unmodified lines |
| 296 | 296 | */ |
| 297 | 297 | int sysctl_sched_rt_runtime = 950000; |
| 298 | 298 | |
| 299 | +/* |
| 300 | + * Maximum bandwidth available for all -deadline tasks and groups |
| 301 | + * (if group scheduling is configured) on each CPU. |
| 302 | + * |
| 303 | + * default: 5% |
| 304 | + */ |
| 305 | +unsigned int sysctl_sched_dl_period = 1000000; |
| 306 | +int sysctl_sched_dl_runtime = 50000; |
| 307 | + |
| 299 | 308 | |
| 300 | 309 | |
| 301 | 310 | /* |
| @@ -1856,6 +1865,111 @@ int sched_fork(unsigned long clone_flags, struct task_struct *p) · 1554 unmodified lines |
| 1856 | 1865 | return 0; |
| 1857 | 1866 | } |
| 1858 | 1867 | |
| 1868 | +unsigned long to_ratio(u64 period, u64 runtime) |
| 1869 | +{ |
| 1870 | + if (runtime == RUNTIME_INF) |
| 1871 | + return 1ULL << 20; |
| 1872 | + |
| 1873 | + /* |
| 1874 | + * Doing this here saves a lot of checks in all |
| 1875 | + * the calling paths, and returning zero seems |
| 1876 | + * safe for them anyway. |
| 1877 | + */ |
| 1878 | + if (period == 0) |
| 1879 | + return 0; |
| 1880 | + |
| 1881 | + return div64_u64(runtime << 20, period); |
| 1882 | +} |
| 1883 | + |
| 1884 | +#ifdef CONFIG_SMP |
| 1885 | +inline struct dl_bw *dl_bw_of(int i) |
| 1886 | +{ |
| 1887 | + return &cpu_rq(i)->rd->dl_bw; |
| 1888 | +} |
| 1889 | + |
| 1890 | +static inline int __dl_span_weight(struct rq *rq) |
| 1891 | +{ |
| 1892 | + return cpumask_weight(rq->rd->span); |
| 1893 | +} |
| 1894 | +#else |
| 1895 | +inline struct dl_bw *dl_bw_of(int i) |
| 1896 | +{ |
| 1897 | + return &cpu_rq(i)->dl.dl_bw; |
| 1898 | +} |
| 1899 | + |
| 1900 | +static inline int __dl_span_weight(struct rq *rq) |
| 1901 | +{ |
| 1902 | + return 1; |
| 1903 | +} |
| 1904 | +#endif |
| 1905 | + |
| 1906 | +static inline |
| 1907 | +void __dl_clear(struct dl_bw *dl_b, u64 tsk_bw) |
| 1908 | +{ |
| 1909 | + dl_b->total_bw -= tsk_bw; |
| 1910 | +} |
| 1911 | + |
| 1912 | +static inline |
| 1913 | +void __dl_add(struct dl_bw *dl_b, u64 tsk_bw) |
| 1914 | +{ |
| 1915 | + dl_b->total_bw += tsk_bw; |
| 1916 | +} |
| 1917 | + |
| 1918 | +static inline |
| 1919 | +bool __dl_overflow(struct dl_bw *dl_b, int cpus, u64 old_bw, u64 new_bw) |
| 1920 | +{ |
| 1921 | + return dl_b->bw != -1 && |
| 1922 | + dl_b->bw * cpus < dl_b->total_bw - old_bw + new_bw; |
| 1923 | +} |
| 1924 | + |
| 1925 | +/* |
| 1926 | + * We must be sure that accepting a new task (or allowing changing the |
| 1927 | + * parameters of an existing one) is consistent with the bandwidth |
| 1928 | + * constraints. If yes, this function also accordingly updates the currently |
| 1929 | + * allocated bandwidth to reflect the new situation. |
| 1930 | + * |
| 1931 | + * This function is called while holding p's rq->lock. |
| 1932 | + */ |
| 1933 | +static int dl_overflow(struct task_struct *p, int policy, |
| 1934 | + const struct sched_attr *attr) |
| 1935 | +{ |
| 1936 | + |
| 1937 | + struct dl_bw *dl_b = dl_bw_of(task_cpu(p)); |
| 1938 | + u64 period = attr->sched_period; |
| 1939 | + u64 runtime = attr->sched_runtime; |
| 1940 | + u64 new_bw = dl_policy(policy) ? to_ratio(period, runtime) : 0; |
| 1941 | + int cpus = __dl_span_weight(task_rq(p)); |
| 1942 | + int err = -1; |
| 1943 | + |
| 1944 | + if (new_bw == p->dl.dl_bw) |
| 1945 | + return 0; |
| 1946 | + |
| 1947 | + /* |
| 1948 | + * Either if a task, enters, leave, or stays -deadline but changes |
| 1949 | + * its parameters, we may need to update accordingly the total |
| 1950 | + * allocated bandwidth of the container. |
| 1951 | + */ |
| 1952 | + raw_spin_lock(&dl_b->lock); |
| 1953 | + if (dl_policy(policy) && !task_has_dl_policy(p) && |
| 1954 | + !__dl_overflow(dl_b, cpus, 0, new_bw)) { |
| 1955 | + __dl_add(dl_b, new_bw); |
| 1956 | + err = 0; |
| 1957 | + } else if (dl_policy(policy) && task_has_dl_policy(p) && |
| 1958 | + !__dl_overflow(dl_b, cpus, p->dl.dl_bw, new_bw)) { |
| 1959 | + __dl_clear(dl_b, p->dl.dl_bw); |
| 1960 | + __dl_add(dl_b, new_bw); |
| 1961 | + err = 0; |
| 1962 | + } else if (!dl_policy(policy) && task_has_dl_policy(p)) { |
| 1963 | + __dl_clear(dl_b, p->dl.dl_bw); |
| 1964 | + err = 0; |
| 1965 | + } |
| 1966 | + raw_spin_unlock(&dl_b->lock); |
| 1967 | + |
| 1968 | + return err; |
| 1969 | +} |
| 1970 | + |
| 1971 | +extern void init_dl_bw(struct dl_bw *dl_b); |
| 1972 | + |
| 1859 | 1973 | /* |
| 1860 | 1974 | * wake_up_new_task - wake up a newly created task for the first time. |
| 1861 | 1975 | * |
| @@ -3053,6 +3167,7 @@ __setparam_dl(struct task_struct *p, const struct sched_attr *attr) · 1191 unmodified lines |
| 3053 | 3167 | dl_se->dl_deadline = attr->sched_deadline; |
| 3054 | 3168 | dl_se->dl_period = attr->sched_period ?: dl_se->dl_deadline; |
| 3055 | 3169 | dl_se->flags = attr->sched_flags; |
| 3170 | + dl_se->dl_bw = to_ratio(dl_se->dl_period, dl_se->dl_runtime); |
| 3056 | 3171 | dl_se->dl_throttled = 0; |
| 3057 | 3172 | dl_se->dl_new = 1; |
| 3058 | 3173 | } |
| @@ -3101,7 +3216,9 @@ __getparam_dl(struct task_struct *p, struct sched_attr *attr) · 42 unmodified lines |
| 3101 | 3216 | * This function validates the new parameters of a -deadline task. |
| 3102 | 3217 | * We ask for the deadline not being zero, and greater or equal |
| 3103 | 3218 | * than the runtime, as well as the period of being zero or |
| 3104 | | − * greater than deadline. |
| 3219 | + * greater than deadline. Furthermore, we have to be sure that |
| 3220 | + * user parameters are above the internal resolution (1us); we |
| 3221 | + * check sched_runtime only since it is always the smaller one. |
| 3105 | 3222 | */ |
| 3106 | 3223 | static bool |
| 3107 | 3224 | __checkparam_dl(const struct sched_attr *attr) |
| @@ -3109,7 +3226,8 @@ __checkparam_dl(const struct sched_attr *attr) · 1 unmodified line |
| 3109 | 3226 | return attr && attr->sched_deadline != 0 && |
| 3110 | 3227 | (attr->sched_period == 0 || |
| 3111 | 3228 | (s64)(attr->sched_period - attr->sched_deadline) >= 0) && |
| 3112 | | − (s64)(attr->sched_deadline - attr->sched_runtime ) >= 0; |
| 3229 | + (s64)(attr->sched_deadline - attr->sched_runtime ) >= 0 && |
| 3230 | + attr->sched_runtime >= (2 << (DL_SCALE - 1)); |
| 3113 | 3231 | } |
| 3114 | 3232 | |
| 3115 | 3233 | /* |
| @@ -3250,8 +3368,8 @@ recheck: · 134 unmodified lines |
| 3250 | 3368 | } |
| 3251 | 3369 | change: |
| 3252 | 3370 | |
| 3253 | | −#ifdef CONFIG_RT_GROUP_SCHED |
| 3254 | 3371 | if (user) { |
| 3372 | +#ifdef CONFIG_RT_GROUP_SCHED |
| 3255 | 3373 | /* |
| 3256 | 3374 | * Do not allow realtime tasks into groups that have no runtime |
| 3257 | 3375 | * assigned. |
| @@ -3262,8 +3380,33 @@ change: · 4 unmodified lines |
| 3262 | 3380 | task_rq_unlock(rq, p, &flags); |
| 3263 | 3381 | return -EPERM; |
| 3264 | 3382 | } |
| 3265 | | − } |
| 3266 | 3383 | #endif |
| 3384 | +#ifdef CONFIG_SMP |
| 3385 | + if (dl_bandwidth_enabled() && dl_policy(policy)) { |
| 3386 | + cpumask_t *span = rq->rd->span; |
| 3387 | + cpumask_t act_affinity; |
| 3388 | + |
| 3389 | + /* |
| 3390 | + * cpus_allowed mask is statically initialized with |
| 3391 | + * CPU_MASK_ALL, span is instead dynamic. Here we |
| 3392 | + * compute the "dynamic" affinity of a task. |
| 3393 | + */ |
| 3394 | + cpumask_and(&act_affinity, &p->cpus_allowed, |
| 3395 | + cpu_active_mask); |
| 3396 | + |
| 3397 | + /* |
| 3398 | + * Don't allow tasks with an affinity mask smaller than |
| 3399 | + * the entire root_domain to become SCHED_DEADLINE. We |
| 3400 | + * will also fail if there's no bandwidth available. |
| 3401 | + */ |
| 3402 | + if (!cpumask_equal(&act_affinity, span) || |
| 3403 | + rq->rd->dl_bw.bw == 0) { |
| 3404 | + task_rq_unlock(rq, p, &flags); |
| 3405 | + return -EPERM; |
| 3406 | + } |
| 3407 | + } |
| 3408 | +#endif |
| 3409 | + } |
| 3267 | 3410 | |
| 3268 | 3411 | /* recheck policy now with rq lock held */ |
| 3269 | 3412 | if (unlikely(oldpolicy != -1 && oldpolicy != p->policy)) { |
| @@ -3271,6 +3414,18 @@ change: · 1 unmodified line |
| 3271 | 3414 | task_rq_unlock(rq, p, &flags); |
| 3272 | 3415 | goto recheck; |
| 3273 | 3416 | } |
| 3417 | + |
| 3418 | + /* |
| 3419 | + * If setscheduling to SCHED_DEADLINE (or changing the parameters |
| 3420 | + * of a SCHED_DEADLINE task) we need to check if enough bandwidth |
| 3421 | + * is available. |
| 3422 | + */ |
| 3423 | + if ((dl_policy(policy) || dl_task(p)) && |
| 3424 | + dl_overflow(p, policy, attr)) { |
| 3425 | + task_rq_unlock(rq, p, &flags); |
| 3426 | + return -EBUSY; |
| 3427 | + } |
| 3428 | + |
| 3274 | 3429 | on_rq = p->on_rq; |
| 3275 | 3430 | running = task_current(rq, p); |
| 3276 | 3431 | if (on_rq) |
| @@ -3705,6 +3860,24 @@ long sched_setaffinity(pid_t pid, const struct cpumask *in_mask) · 428 unmodified lines |
| 3705 | 3860 | if (retval) |
| 3706 | 3861 | goto out_unlock; |
| 3707 | 3862 | |
| 3863 | + /* |
| 3864 | + * Since bandwidth control happens on root_domain basis, |
| 3865 | + * if admission test is enabled, we only admit -deadline |
| 3866 | + * tasks allowed to run on all the CPUs in the task's |
| 3867 | + * root_domain. |
| 3868 | + */ |
| 3869 | +#ifdef CONFIG_SMP |
| 3870 | + if (task_has_dl_policy(p)) { |
| 3871 | + const struct cpumask *span = task_rq(p)->rd->span; |
| 3872 | + |
| 3873 | + if (dl_bandwidth_enabled() && |
| 3874 | + !cpumask_equal(in_mask, span)) { |
| 3875 | + retval = -EBUSY; |
| 3876 | + goto out_unlock; |
| 3877 | + } |
| 3878 | + } |
| 3879 | +#endif |
| 3880 | + |
| 3708 | 3881 | cpuset_cpus_allowed(p, cpus_allowed); |
| 3709 | 3882 | cpumask_and(new_mask, in_mask, cpus_allowed); |
| 3710 | 3883 | again: |
| @@ -4358,6 +4531,42 @@ out: · 647 unmodified lines |
| 4358 | 4531 | } |
| 4359 | 4532 | EXPORT_SYMBOL_GPL(set_cpus_allowed_ptr); |
| 4360 | 4533 | |
| 4534 | +/* |
| 4535 | + * When dealing with a -deadline task, we have to check if moving it to |
| 4536 | + * a new CPU is possible or not. In fact, this is only true iff there |
| 4537 | + * is enough bandwidth available on such CPU, otherwise we want the |
| 4538 | + * whole migration progedure to fail over. |
| 4539 | + */ |
| 4540 | +static inline |
| 4541 | +bool set_task_cpu_dl(struct task_struct *p, unsigned int cpu) |
| 4542 | +{ |
| 4543 | + struct dl_bw *dl_b = dl_bw_of(task_cpu(p)); |
| 4544 | + struct dl_bw *cpu_b = dl_bw_of(cpu); |
| 4545 | + int ret = 1; |
| 4546 | + u64 bw; |
| 4547 | + |
| 4548 | + if (dl_b == cpu_b) |
| 4549 | + return 1; |
| 4550 | + |
| 4551 | + raw_spin_lock(&dl_b->lock); |
| 4552 | + raw_spin_lock(&cpu_b->lock); |
| 4553 | + |
| 4554 | + bw = cpu_b->bw * cpumask_weight(cpu_rq(cpu)->rd->span); |
| 4555 | + if (dl_bandwidth_enabled() && |
| 4556 | + bw < cpu_b->total_bw + p->dl.dl_bw) { |
| 4557 | + ret = 0; |
| 4558 | + goto unlock; |
| 4559 | + } |
| 4560 | + dl_b->total_bw -= p->dl.dl_bw; |
| 4561 | + cpu_b->total_bw += p->dl.dl_bw; |
| 4562 | + |
| 4563 | +unlock: |
| 4564 | + raw_spin_unlock(&cpu_b->lock); |
| 4565 | + raw_spin_unlock(&dl_b->lock); |
| 4566 | + |
| 4567 | + return ret; |
| 4568 | +} |
| 4569 | + |
| 4361 | 4570 | /* |
| 4362 | 4571 | * Move (not current) task off this cpu, onto dest cpu. We're doing |
| 4363 | 4572 | * this because either it can't run here any more (set_cpus_allowed() |
| @@ -4389,6 +4598,13 @@ static int __migrate_task(struct task_struct *p, int src_cpu, int dest_cpu) · 25 unmodified lines |
| 4389 | 4598 | if (!cpumask_test_cpu(dest_cpu, tsk_cpus_allowed(p))) |
| 4390 | 4599 | goto fail; |
| 4391 | 4600 | |
| 4601 | + /* |
| 4602 | + * If p is -deadline, proceed only if there is enough |
| 4603 | + * bandwidth available on dest_cpu |
| 4604 | + */ |
| 4605 | + if (unlikely(dl_task(p)) && !set_task_cpu_dl(p, dest_cpu)) |
| 4606 | + goto fail; |
| 4607 | + |
| 4392 | 4608 | /* |
| 4393 | 4609 | * If we're not on a rq, the next wake-up will ensure we're |
| 4394 | 4610 | * placed properly. |
| @@ -5128,6 +5344,8 @@ static int init_rootdomain(struct root_domain *rd) · 733 unmodified lines |
| 5128 | 5344 | if (!alloc_cpumask_var(&rd->rto_mask, GFP_KERNEL)) |
| 5129 | 5345 | goto free_dlo_mask; |
| 5130 | 5346 | |
| 5347 | + init_dl_bw(&rd->dl_bw); |
| 5348 | + |
| 5131 | 5349 | if (cpupri_init(&rd->cpupri) != 0) |
| 5132 | 5350 | goto free_rto_mask; |
| 5133 | 5351 | return 0; |
| @@ -6557,13 +6775,15 @@ void __init sched_init(void) · 1423 unmodified lines |
| 6557 | 6775 | #endif /* CONFIG_CPUMASK_OFFSTACK */ |
| 6558 | 6776 | } |
| 6559 | 6777 | |
| 6778 | + init_rt_bandwidth(&def_rt_bandwidth, |
| 6779 | + global_rt_period(), global_rt_runtime()); |
| 6780 | + init_dl_bandwidth(&def_dl_bandwidth, |
| 6781 | + global_dl_period(), global_dl_runtime()); |
| 6782 | + |
| 6560 | 6783 | #ifdef CONFIG_SMP |
| 6561 | 6784 | init_defrootdomain(); |
| 6562 | 6785 | #endif |
| 6563 | 6786 | |
| 6564 | | − init_rt_bandwidth(&def_rt_bandwidth, |
| 6565 | | − global_rt_period(), global_rt_runtime()); |
| 6566 | | − |
| 6567 | 6787 | #ifdef CONFIG_RT_GROUP_SCHED |
| 6568 | 6788 | init_rt_bandwidth(&root_task_group.rt_bandwidth, |
| 6569 | 6789 | global_rt_period(), global_rt_runtime()); |
| @@ -6966,16 +7186,6 @@ void sched_move_task(struct task_struct *tsk) · 396 unmodified lines |
| 6966 | 7186 | } |
| 6967 | 7187 | #endif /* CONFIG_CGROUP_SCHED */ |
| 6968 | 7188 | |
| 6969 | | −#if defined(CONFIG_RT_GROUP_SCHED) || defined(CONFIG_CFS_BANDWIDTH) |
| 6970 | | −static unsigned long to_ratio(u64 period, u64 runtime) |
| 6971 | | −{ |
| 6972 | | − if (runtime == RUNTIME_INF) |
| 6973 | | − return 1ULL << 20; |
| 6974 | | − |
| 6975 | | − return div64_u64(runtime << 20, period); |
| 6976 | | −} |
| 6977 | | −#endif |
| 6978 | | − |
| 6979 | 7189 | #ifdef CONFIG_RT_GROUP_SCHED |
| 6980 | 7190 | /* |
| 6981 | 7191 | * Ensure that the real time constraints are schedulable. |
| @@ -7149,10 +7359,48 @@ static long sched_group_rt_period(struct task_group *tg) · 167 unmodified lines |
| 7149 | 7359 | do_div(rt_period_us, NSEC_PER_USEC); |
| 7150 | 7360 | return rt_period_us; |
| 7151 | 7361 | } |
| 7362 | +#endif /* CONFIG_RT_GROUP_SCHED */ |
| 7152 | 7363 | |
| 7364 | +/* |
| 7365 | + * Coupling of -rt and -deadline bandwidth. |
| 7366 | + * |
| 7367 | + * Here we check if the new -rt bandwidth value is consistent |
| 7368 | + * with the system settings for the bandwidth available |
| 7369 | + * to -deadline tasks. |
| 7370 | + * |
| 7371 | + * IOW, we want to enforce that |
| 7372 | + * |
| 7373 | + * rt_bandwidth + dl_bandwidth <= 100% |
| 7374 | + * |
| 7375 | + * is always true. |
| 7376 | + */ |
| 7377 | +static bool __sched_rt_dl_global_constraints(u64 rt_bw) |
| 7378 | +{ |
| 7379 | + unsigned long flags; |
| 7380 | + u64 dl_bw; |
| 7381 | + bool ret; |
| 7382 | + |
| 7383 | + raw_spin_lock_irqsave(&def_dl_bandwidth.dl_runtime_lock, flags); |
| 7384 | + if (global_rt_runtime() == RUNTIME_INF || |
| 7385 | + global_dl_runtime() == RUNTIME_INF) { |
| 7386 | + ret = true; |
| 7387 | + goto unlock; |
| 7388 | + } |
| 7389 | + |
| 7390 | + dl_bw = to_ratio(def_dl_bandwidth.dl_period, |
| 7391 | + def_dl_bandwidth.dl_runtime); |
| 7392 | + |
| 7393 | + ret = rt_bw + dl_bw <= to_ratio(RUNTIME_INF, RUNTIME_INF); |
| 7394 | +unlock: |
| 7395 | + raw_spin_unlock_irqrestore(&def_dl_bandwidth.dl_runtime_lock, flags); |
| 7396 | + |
| 7397 | + return ret; |
| 7398 | +} |
| 7399 | + |
| 7400 | +#ifdef CONFIG_RT_GROUP_SCHED |
| 7153 | 7401 | static int sched_rt_global_constraints(void) |
| 7154 | 7402 | { |
| 7155 | | − u64 runtime, period; |
| 7403 | + u64 runtime, period, bw; |
| 7156 | 7404 | int ret = 0; |
| 7157 | 7405 | |
| 7158 | 7406 | if (sysctl_sched_rt_period <= 0) |
| @@ -7167,6 +7415,10 @@ static int sched_rt_global_constraints(void) · 8 unmodified lines |
| 7167 | 7415 | if (runtime > period && runtime != RUNTIME_INF) |
| 7168 | 7416 | return -EINVAL; |
| 7169 | 7417 | |
| 7418 | + bw = to_ratio(period, runtime); |
| 7419 | + if (!__sched_rt_dl_global_constraints(bw)) |
| 7420 | + return -EINVAL; |
| 7421 | + |
| 7170 | 7422 | mutex_lock(&rt_constraints_mutex); |
| 7171 | 7423 | read_lock(&tasklist_lock); |
| 7172 | 7424 | ret = __rt_schedulable(NULL, 0, 0); |
| @@ -7189,19 +7441,19 @@ static int sched_rt_can_attach(struct task_group *tg, struct task_struct *tsk) · 16 unmodified lines |
| 7189 | 7441 | static int sched_rt_global_constraints(void) |
| 7190 | 7442 | { |
| 7191 | 7443 | unsigned long flags; |
| 7192 | | − int i; |
| 7444 | + int i, ret = 0; |
| 7445 | + u64 bw; |
| 7193 | 7446 | |
| 7194 | 7447 | if (sysctl_sched_rt_period <= 0) |
| 7195 | 7448 | return -EINVAL; |
| 7196 | 7449 | |
| 7197 | | − /* |
| 7198 | | − * There's always some RT tasks in the root group |
| 7199 | | − * -- migration, kstopmachine etc.. |
| 7200 | | − */ |
| 7201 | | − if (sysctl_sched_rt_runtime == 0) |
| 7202 | | − return -EBUSY; |
| 7203 | | − |
| 7204 | 7450 | raw_spin_lock_irqsave(&def_rt_bandwidth.rt_runtime_lock, flags); |
| 7451 | + bw = to_ratio(global_rt_period(), global_rt_runtime()); |
| 7452 | + if (!__sched_rt_dl_global_constraints(bw)) { |
| 7453 | + ret = -EINVAL; |
| 7454 | + goto unlock; |
| 7455 | + } |
| 7456 | + |
| 7205 | 7457 | for_each_possible_cpu(i) { |
| 7206 | 7458 | struct rt_rq *rt_rq = &cpu_rq(i)->rt; |
| 7207 | 7459 | |
| @@ -7209,12 +7461,93 @@ static int sched_rt_global_constraints(void) · 1 unmodified line |
| 7209 | 7461 | rt_rq->rt_runtime = global_rt_runtime(); |
| 7210 | 7462 | raw_spin_unlock(&rt_rq->rt_runtime_lock); |
| 7211 | 7463 | } |
| 7464 | +unlock: |
| 7212 | 7465 | raw_spin_unlock_irqrestore(&def_rt_bandwidth.rt_runtime_lock, flags); |
| 7213 | 7466 | |
| 7214 | | − return 0; |
| 7467 | + return ret; |
| 7215 | 7468 | } |
| 7216 | 7469 | #endif /* CONFIG_RT_GROUP_SCHED */ |
| 7217 | 7470 | |
| 7471 | +/* |
| 7472 | + * Coupling of -dl and -rt bandwidth. |
| 7473 | + * |
| 7474 | + * Here we check, while setting the system wide bandwidth available |
| 7475 | + * for -dl tasks and groups, if the new values are consistent with |
| 7476 | + * the system settings for the bandwidth available to -rt entities. |
| 7477 | + * |
| 7478 | + * IOW, we want to enforce that |
| 7479 | + * |
| 7480 | + * rt_bandwidth + dl_bandwidth <= 100% |
| 7481 | + * |
| 7482 | + * is always true. |
| 7483 | + */ |
| 7484 | +static bool __sched_dl_rt_global_constraints(u64 dl_bw) |
| 7485 | +{ |
| 7486 | + u64 rt_bw; |
| 7487 | + bool ret; |
| 7488 | + |
| 7489 | + raw_spin_lock(&def_rt_bandwidth.rt_runtime_lock); |
| 7490 | + if (global_dl_runtime() == RUNTIME_INF || |
| 7491 | + global_rt_runtime() == RUNTIME_INF) { |
| 7492 | + ret = true; |
| 7493 | + goto unlock; |
| 7494 | + } |
| 7495 | + |
| 7496 | + rt_bw = to_ratio(ktime_to_ns(def_rt_bandwidth.rt_period), |
| 7497 | + def_rt_bandwidth.rt_runtime); |
| 7498 | + |
| 7499 | + ret = rt_bw + dl_bw <= to_ratio(RUNTIME_INF, RUNTIME_INF); |
| 7500 | +unlock: |
| 7501 | + raw_spin_unlock(&def_rt_bandwidth.rt_runtime_lock); |
| 7502 | + |
| 7503 | + return ret; |
| 7504 | +} |
| 7505 | + |
| 7506 | +static bool __sched_dl_global_constraints(u64 runtime, u64 period) |
| 7507 | +{ |
| 7508 | + if (!period || (runtime != RUNTIME_INF && runtime > period)) |
| 7509 | + return -EINVAL; |
| 7510 | + |
| 7511 | + return 0; |
| 7512 | +} |
| 7513 | + |
| 7514 | +static int sched_dl_global_constraints(void) |
| 7515 | +{ |
| 7516 | + u64 runtime = global_dl_runtime(); |
| 7517 | + u64 period = global_dl_period(); |
| 7518 | + u64 new_bw = to_ratio(period, runtime); |
| 7519 | + int ret, i; |
| 7520 | + |
| 7521 | + ret = __sched_dl_global_constraints(runtime, period); |
| 7522 | + if (ret) |
| 7523 | + return ret; |
| 7524 | + |
| 7525 | + if (!__sched_dl_rt_global_constraints(new_bw)) |
| 7526 | + return -EINVAL; |
| 7527 | + |
| 7528 | + /* |
| 7529 | + * Here we want to check the bandwidth not being set to some |
| 7530 | + * value smaller than the currently allocated bandwidth in |
| 7531 | + * any of the root_domains. |
| 7532 | + * |
| 7533 | + * FIXME: Cycling on all the CPUs is overdoing, but simpler than |
| 7534 | + * cycling on root_domains... Discussion on different/better |
| 7535 | + * solutions is welcome! |
| 7536 | + */ |
| 7537 | + for_each_possible_cpu(i) { |
| 7538 | + struct dl_bw *dl_b = dl_bw_of(i); |
| 7539 | + |
| 7540 | + raw_spin_lock(&dl_b->lock); |
| 7541 | + if (new_bw < dl_b->total_bw) { |
| 7542 | + raw_spin_unlock(&dl_b->lock); |
| 7543 | + return -EBUSY; |
| 7544 | + } |
| 7545 | + raw_spin_unlock(&dl_b->lock); |
| 7546 | + } |
| 7547 | + |
| 7548 | + return 0; |
| 7549 | +} |
| 7550 | + |
| 7218 | 7551 | int sched_rr_handler(struct ctl_table *table, int write, |
| 7219 | 7552 | void __user *buffer, size_t *lenp, |
| 7220 | 7553 | loff_t *ppos) |
| @@ -7264,6 +7597,60 @@ int sched_rt_handler(struct ctl_table *table, int write, · 43 unmodified lines |
| 7264 | 7597 | return ret; |
| 7265 | 7598 | } |
| 7266 | 7599 | |
| 7600 | +int sched_dl_handler(struct ctl_table *table, int write, |
| 7601 | + void __user *buffer, size_t *lenp, |
| 7602 | + loff_t *ppos) |
| 7603 | +{ |
| 7604 | + int ret; |
| 7605 | + int old_period, old_runtime; |
| 7606 | + static DEFINE_MUTEX(mutex); |
| 7607 | + unsigned long flags; |
| 7608 | + |
| 7609 | + mutex_lock(&mutex); |
| 7610 | + old_period = sysctl_sched_dl_period; |
| 7611 | + old_runtime = sysctl_sched_dl_runtime; |
| 7612 | + |
| 7613 | + ret = proc_dointvec(table, write, buffer, lenp, ppos); |
| 7614 | + |
| 7615 | + if (!ret && write) { |
| 7616 | + raw_spin_lock_irqsave(&def_dl_bandwidth.dl_runtime_lock, |
| 7617 | + flags); |
| 7618 | + |
| 7619 | + ret = sched_dl_global_constraints(); |
| 7620 | + if (ret) { |
| 7621 | + sysctl_sched_dl_period = old_period; |
| 7622 | + sysctl_sched_dl_runtime = old_runtime; |
| 7623 | + } else { |
| 7624 | + u64 new_bw; |
| 7625 | + int i; |
| 7626 | + |
| 7627 | + def_dl_bandwidth.dl_period = global_dl_period(); |
| 7628 | + def_dl_bandwidth.dl_runtime = global_dl_runtime(); |
| 7629 | + if (global_dl_runtime() == RUNTIME_INF) |
| 7630 | + new_bw = -1; |
| 7631 | + else |
| 7632 | + new_bw = to_ratio(global_dl_period(), |
| 7633 | + global_dl_runtime()); |
| 7634 | + /* |
| 7635 | + * FIXME: As above... |
| 7636 | + */ |
| 7637 | + for_each_possible_cpu(i) { |
| 7638 | + struct dl_bw *dl_b = dl_bw_of(i); |
| 7639 | + |
| 7640 | + raw_spin_lock(&dl_b->lock); |
| 7641 | + dl_b->bw = new_bw; |
| 7642 | + raw_spin_unlock(&dl_b->lock); |
| 7643 | + } |
| 7644 | + } |
| 7645 | + |
| 7646 | + raw_spin_unlock_irqrestore(&def_dl_bandwidth.dl_runtime_lock, |
| 7647 | + flags); |
| 7648 | + } |
| 7649 | + mutex_unlock(&mutex); |
| 7650 | + |
| 7651 | + return ret; |
| 7652 | +} |
| 7653 | + |
| 7267 | 7654 | #ifdef CONFIG_CGROUP_SCHED |
| 7268 | 7655 | |
| 7269 | 7656 | static inline struct task_group *css_tg(struct cgroup_subsys_state *css) |