Skip to content

Commit d4742f6

Browse files
jlelliPeter Zijlstra
authored andcommitted
sched/deadline: Correctly account for allocated bandwidth during hotplug
For hotplug operations, DEADLINE needs to check that there is still enough bandwidth left after removing the CPU that is going offline. We however fail to do so currently. Restore the correct behavior by restructuring dl_bw_manage() a bit, so that overflow conditions (not enough bandwidth left) are properly checked. Also account for dl_server bandwidth, i.e. discount such bandwidth in the calculation since NORMAL tasks will be anyway moved away from the CPU as a result of the hotplug operation. Signed-off-by: Juri Lelli <[email protected]> Signed-off-by: Peter Zijlstra (Intel) <[email protected]> Reviewed-by: Phil Auld <[email protected]> Tested-by: Waiman Long <[email protected]> Link: https://lore.kernel.org/r/[email protected]
1 parent 41d4200 commit d4742f6

File tree

3 files changed

+41
-11
lines changed

3 files changed

+41
-11
lines changed

kernel/sched/core.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8185,7 +8185,7 @@ static void cpuset_cpu_active(void)
81858185
static int cpuset_cpu_inactive(unsigned int cpu)
81868186
{
81878187
if (!cpuhp_tasks_frozen) {
8188-
int ret = dl_bw_check_overflow(cpu);
8188+
int ret = dl_bw_deactivate(cpu);
81898189

81908190
if (ret)
81918191
return ret;

kernel/sched/deadline.c

Lines changed: 39 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -3460,29 +3460,31 @@ int dl_cpuset_cpumask_can_shrink(const struct cpumask *cur,
34603460
}
34613461

34623462
enum dl_bw_request {
3463-
dl_bw_req_check_overflow = 0,
3463+
dl_bw_req_deactivate = 0,
34643464
dl_bw_req_alloc,
34653465
dl_bw_req_free
34663466
};
34673467

34683468
static int dl_bw_manage(enum dl_bw_request req, int cpu, u64 dl_bw)
34693469
{
3470-
unsigned long flags;
3470+
unsigned long flags, cap;
34713471
struct dl_bw *dl_b;
34723472
bool overflow = 0;
3473+
u64 fair_server_bw = 0;
34733474

34743475
rcu_read_lock_sched();
34753476
dl_b = dl_bw_of(cpu);
34763477
raw_spin_lock_irqsave(&dl_b->lock, flags);
34773478

3478-
if (req == dl_bw_req_free) {
3479+
cap = dl_bw_capacity(cpu);
3480+
switch (req) {
3481+
case dl_bw_req_free:
34793482
__dl_sub(dl_b, dl_bw, dl_bw_cpus(cpu));
3480-
} else {
3481-
unsigned long cap = dl_bw_capacity(cpu);
3482-
3483+
break;
3484+
case dl_bw_req_alloc:
34833485
overflow = __dl_overflow(dl_b, cap, 0, dl_bw);
34843486

3485-
if (req == dl_bw_req_alloc && !overflow) {
3487+
if (!overflow) {
34863488
/*
34873489
* We reserve space in the destination
34883490
* root_domain, as we can't fail after this point.
@@ -3491,6 +3493,34 @@ static int dl_bw_manage(enum dl_bw_request req, int cpu, u64 dl_bw)
34913493
*/
34923494
__dl_add(dl_b, dl_bw, dl_bw_cpus(cpu));
34933495
}
3496+
break;
3497+
case dl_bw_req_deactivate:
3498+
/*
3499+
* cpu is going offline and NORMAL tasks will be moved away
3500+
* from it. We can thus discount dl_server bandwidth
3501+
* contribution as it won't need to be servicing tasks after
3502+
* the cpu is off.
3503+
*/
3504+
if (cpu_rq(cpu)->fair_server.dl_server)
3505+
fair_server_bw = cpu_rq(cpu)->fair_server.dl_bw;
3506+
3507+
/*
3508+
* Not much to check if no DEADLINE bandwidth is present.
3509+
* dl_servers we can discount, as tasks will be moved out the
3510+
* offlined CPUs anyway.
3511+
*/
3512+
if (dl_b->total_bw - fair_server_bw > 0) {
3513+
/*
3514+
* Leaving at least one CPU for DEADLINE tasks seems a
3515+
* wise thing to do.
3516+
*/
3517+
if (dl_bw_cpus(cpu))
3518+
overflow = __dl_overflow(dl_b, cap, fair_server_bw, 0);
3519+
else
3520+
overflow = 1;
3521+
}
3522+
3523+
break;
34943524
}
34953525

34963526
raw_spin_unlock_irqrestore(&dl_b->lock, flags);
@@ -3499,9 +3529,9 @@ static int dl_bw_manage(enum dl_bw_request req, int cpu, u64 dl_bw)
34993529
return overflow ? -EBUSY : 0;
35003530
}
35013531

3502-
int dl_bw_check_overflow(int cpu)
3532+
int dl_bw_deactivate(int cpu)
35033533
{
3504-
return dl_bw_manage(dl_bw_req_check_overflow, cpu, 0);
3534+
return dl_bw_manage(dl_bw_req_deactivate, cpu, 0);
35053535
}
35063536

35073537
int dl_bw_alloc(int cpu, u64 dl_bw)

kernel/sched/sched.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -362,7 +362,7 @@ extern void __getparam_dl(struct task_struct *p, struct sched_attr *attr);
362362
extern bool __checkparam_dl(const struct sched_attr *attr);
363363
extern bool dl_param_changed(struct task_struct *p, const struct sched_attr *attr);
364364
extern int dl_cpuset_cpumask_can_shrink(const struct cpumask *cur, const struct cpumask *trial);
365-
extern int dl_bw_check_overflow(int cpu);
365+
extern int dl_bw_deactivate(int cpu);
366366
extern s64 dl_scaled_delta_exec(struct rq *rq, struct sched_dl_entity *dl_se, s64 delta_exec);
367367
/*
368368
* SCHED_DEADLINE supports servers (nested scheduling) with the following

0 commit comments

Comments
 (0)