Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

sched/deadline: Consolidate Timer Cancellation

After commit b58652db66c9 ("sched/deadline: Fix task_struct reference
leak"), I identified additional calls to hrtimer_try_to_cancel that
might also require a dl_server check. It remains unclear whether this
omission was intentional or accidental in those contexts.

This patch consolidates the timer cancellation logic into dedicated
functions, ensuring consistent behavior across all calls.
Additionally, it reduces code duplication and improves overall code
cleanliness.

Note the use of the __always_inline keyword. In some instances, we
have a task_struct pointer, dereference the dl member, and then use
the container_of macro to retrieve the task_struct pointer again. By
inlining the code, the compiler can potentially optimize out this
redundant round trip.

Signed-off-by: Wander Lairson Costa <wander@redhat.com>
Signed-off-by: Peter Zijlstra (Intel) <peterz@infradead.org>
Acked-by: Juri Lelli <juri.lelli@redhat.com>
Link: https://lore.kernel.org/r/20240724142253.27145-3-wander@redhat.com

authored by

Wander Lairson Costa and committed by
Peter Zijlstra
3a181f20 53916d5f

+27 -14
+27 -14
kernel/sched/deadline.c
··· 342 342 __add_rq_bw(new_bw, &rq->dl); 343 343 } 344 344 345 + static __always_inline 346 + void cancel_dl_timer(struct sched_dl_entity *dl_se, struct hrtimer *timer) 347 + { 348 + /* 349 + * If the timer callback was running (hrtimer_try_to_cancel == -1), 350 + * it will eventually call put_task_struct(). 351 + */ 352 + if (hrtimer_try_to_cancel(timer) == 1 && !dl_server(dl_se)) 353 + put_task_struct(dl_task_of(dl_se)); 354 + } 355 + 356 + static __always_inline 357 + void cancel_replenish_timer(struct sched_dl_entity *dl_se) 358 + { 359 + cancel_dl_timer(dl_se, &dl_se->dl_timer); 360 + } 361 + 362 + static __always_inline 363 + void cancel_inactive_timer(struct sched_dl_entity *dl_se) 364 + { 365 + cancel_dl_timer(dl_se, &dl_se->inactive_timer); 366 + } 367 + 345 368 static void dl_change_utilization(struct task_struct *p, u64 new_bw) 346 369 { 347 370 WARN_ON_ONCE(p->dl.flags & SCHED_FLAG_SUGOV); ··· 518 495 * will not touch the rq's active utilization, 519 496 * so we are still safe. 520 497 */ 521 - if (hrtimer_try_to_cancel(&dl_se->inactive_timer) == 1) { 522 - if (!dl_server(dl_se)) 523 - put_task_struct(dl_task_of(dl_se)); 524 - } 498 + cancel_inactive_timer(dl_se); 525 499 } else { 526 500 /* 527 501 * Since "dl_non_contending" is not set, the ··· 2133 2113 * The replenish timer needs to be canceled. No 2134 2114 * problem if it fires concurrently: boosted threads 2135 2115 * are ignored in dl_task_timer(). 2136 - * 2137 - * If the timer callback was running (hrtimer_try_to_cancel == -1), 2138 - * it will eventually call put_task_struct(). 2139 2116 */ 2140 - if (hrtimer_try_to_cancel(&p->dl.dl_timer) == 1 && 2141 - !dl_server(&p->dl)) 2142 - put_task_struct(p); 2117 + cancel_replenish_timer(&p->dl); 2143 2118 p->dl.dl_throttled = 0; 2144 2119 } 2145 2120 } else if (!dl_prio(p->normal_prio)) { ··· 2302 2287 * will not touch the rq's active utilization, 2303 2288 * so we are still safe. 2304 2289 */ 2305 - if (hrtimer_try_to_cancel(&p->dl.inactive_timer) == 1) 2306 - put_task_struct(p); 2290 + cancel_inactive_timer(&p->dl); 2307 2291 } 2308 2292 sub_rq_bw(&p->dl, &rq->dl); 2309 2293 rq_unlock(rq, &rf); ··· 3050 3036 */ 3051 3037 static void switched_to_dl(struct rq *rq, struct task_struct *p) 3052 3038 { 3053 - if (hrtimer_try_to_cancel(&p->dl.inactive_timer) == 1) 3054 - put_task_struct(p); 3039 + cancel_inactive_timer(&p->dl); 3055 3040 3056 3041 /* 3057 3042 * In case a task is setscheduled to SCHED_DEADLINE we need to keep