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/core: Fix picking of tasks for core scheduling with DL server

* Use simple CFS pick_task for DL pick_task

DL server's pick_task calls CFS's pick_next_task_fair(), this is wrong
because core scheduling's pick_task only calls CFS's pick_task() for
evaluation / checking of the CFS task (comparing across CPUs), not for
actually affirmatively picking the next task. This causes RB tree
corruption issues in CFS that were found by syzbot.

* Make pick_task_fair clear DL server

A DL task pick might set ->dl_server, but it is possible the task will
never run (say the other HT has a stop task). If the CFS task is picked
in the future directly (say without DL server), ->dl_server will be
set. So clear it in pick_task_fair().

This fixes the KASAN issue reported by syzbot in set_next_entity().

(DL refactoring suggestions by Vineeth Pillai).

Reported-by: Suleiman Souhlal <suleiman@google.com>
Signed-off-by: "Joel Fernandes (Google)" <joel@joelfernandes.org>
Signed-off-by: Daniel Bristot de Oliveira <bristot@kernel.org>
Signed-off-by: Peter Zijlstra (Intel) <peterz@infradead.org>
Reviewed-by: Vineeth Pillai <vineeth@bitbyteword.org>
Tested-by: Juri Lelli <juri.lelli@redhat.com>
Link: https://lore.kernel.org/r/b10489ab1f03d23e08e6097acea47442e7d6466f.1716811044.git.bristot@kernel.org

authored by

Joel Fernandes (Google) and committed by
Peter Zijlstra
c8a85394 4b26cfdd

+47 -9
+2 -1
include/linux/sched.h
··· 686 686 */ 687 687 struct rq *rq; 688 688 dl_server_has_tasks_f server_has_tasks; 689 - dl_server_pick_f server_pick; 689 + dl_server_pick_f server_pick_next; 690 + dl_server_pick_f server_pick_task; 690 691 691 692 #ifdef CONFIG_RT_MUTEXES 692 693 /*
+22 -5
kernel/sched/deadline.c
··· 1664 1664 1665 1665 void dl_server_init(struct sched_dl_entity *dl_se, struct rq *rq, 1666 1666 dl_server_has_tasks_f has_tasks, 1667 - dl_server_pick_f pick) 1667 + dl_server_pick_f pick_next, 1668 + dl_server_pick_f pick_task) 1668 1669 { 1669 1670 dl_se->rq = rq; 1670 1671 dl_se->server_has_tasks = has_tasks; 1671 - dl_se->server_pick = pick; 1672 + dl_se->server_pick_next = pick_next; 1673 + dl_se->server_pick_task = pick_task; 1672 1674 } 1673 1675 1674 1676 void __dl_server_attach_root(struct sched_dl_entity *dl_se, struct rq *rq) ··· 2401 2399 return __node_2_dle(left); 2402 2400 } 2403 2401 2404 - static struct task_struct *pick_task_dl(struct rq *rq) 2402 + /* 2403 + * __pick_next_task_dl - Helper to pick the next -deadline task to run. 2404 + * @rq: The runqueue to pick the next task from. 2405 + * @peek: If true, just peek at the next task. Only relevant for dlserver. 2406 + */ 2407 + static struct task_struct *__pick_next_task_dl(struct rq *rq, bool peek) 2405 2408 { 2406 2409 struct sched_dl_entity *dl_se; 2407 2410 struct dl_rq *dl_rq = &rq->dl; ··· 2420 2413 WARN_ON_ONCE(!dl_se); 2421 2414 2422 2415 if (dl_server(dl_se)) { 2423 - p = dl_se->server_pick(dl_se); 2416 + if (IS_ENABLED(CONFIG_SMP) && peek) 2417 + p = dl_se->server_pick_task(dl_se); 2418 + else 2419 + p = dl_se->server_pick_next(dl_se); 2424 2420 if (!p) { 2425 2421 WARN_ON_ONCE(1); 2426 2422 dl_se->dl_yielded = 1; ··· 2438 2428 return p; 2439 2429 } 2440 2430 2431 + #ifdef CONFIG_SMP 2432 + static struct task_struct *pick_task_dl(struct rq *rq) 2433 + { 2434 + return __pick_next_task_dl(rq, true); 2435 + } 2436 + #endif 2437 + 2441 2438 static struct task_struct *pick_next_task_dl(struct rq *rq) 2442 2439 { 2443 2440 struct task_struct *p; 2444 2441 2445 - p = pick_task_dl(rq); 2442 + p = __pick_next_task_dl(rq, false); 2446 2443 if (!p) 2447 2444 return p; 2448 2445
+21 -2
kernel/sched/fair.c
··· 8479 8479 cfs_rq = group_cfs_rq(se); 8480 8480 } while (cfs_rq); 8481 8481 8482 + /* 8483 + * This can be called from directly from CFS's ->pick_task() or indirectly 8484 + * from DL's ->pick_task when fair server is enabled. In the indirect case, 8485 + * DL will set ->dl_server just after this function is called, so its Ok to 8486 + * clear. In the direct case, we are picking directly so we must clear it. 8487 + */ 8488 + task_of(se)->dl_server = NULL; 8489 + 8482 8490 return task_of(se); 8483 8491 } 8484 8492 #endif ··· 8646 8638 return !!dl_se->rq->cfs.nr_running; 8647 8639 } 8648 8640 8649 - static struct task_struct *fair_server_pick(struct sched_dl_entity *dl_se) 8641 + static struct task_struct *fair_server_pick_task(struct sched_dl_entity *dl_se) 8642 + { 8643 + #ifdef CONFIG_SMP 8644 + return pick_task_fair(dl_se->rq); 8645 + #else 8646 + return NULL; 8647 + #endif 8648 + } 8649 + 8650 + static struct task_struct *fair_server_pick_next(struct sched_dl_entity *dl_se) 8650 8651 { 8651 8652 return pick_next_task_fair(dl_se->rq, NULL, NULL); 8652 8653 } ··· 8666 8649 8667 8650 init_dl_entity(dl_se); 8668 8651 8669 - dl_server_init(dl_se, rq, fair_server_has_tasks, fair_server_pick); 8652 + dl_server_init(dl_se, rq, fair_server_has_tasks, fair_server_pick_next, 8653 + fair_server_pick_task); 8654 + 8670 8655 } 8671 8656 8672 8657 /*
+2 -1
kernel/sched/sched.h
··· 361 361 extern void dl_server_stop(struct sched_dl_entity *dl_se); 362 362 extern void dl_server_init(struct sched_dl_entity *dl_se, struct rq *rq, 363 363 dl_server_has_tasks_f has_tasks, 364 - dl_server_pick_f pick); 364 + dl_server_pick_f pick_next, 365 + dl_server_pick_f pick_task); 365 366 366 367 extern void dl_server_update_idle_time(struct rq *rq, 367 368 struct task_struct *p);