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.

Merge tag 'sched_ext-for-6.19-rc1-fixes' of git://git.kernel.org/pub/scm/linux/kernel/git/tj/sched_ext

Pull sched_ext fixes from Tejun Heo:

- Fix memory leak when destroying helper kthread workers during
scheduler disable

- Fix bypass depth accounting on scx_enable() failure which could leave
the system permanently in bypass mode

- Fix missing preemption handling when moving tasks to local DSQs via
scx_bpf_dsq_move()

- Misc fixes including NULL check for put_prev_task(), flushing stdout
in selftests, and removing unused code

* tag 'sched_ext-for-6.19-rc1-fixes' of git://git.kernel.org/pub/scm/linux/kernel/git/tj/sched_ext:
sched_ext: Remove unused code in the do_pick_task_scx()
selftests/sched_ext: flush stdout before test to avoid log spam
sched_ext: Fix missing post-enqueue handling in move_local_task_to_local_dsq()
sched_ext: Factor out local_dsq_post_enq() from dispatch_enqueue()
sched_ext: Fix bypass depth leak on scx_enable() failure
sched/ext: Avoid null ptr traversal when ->put_prev_task() is called with NULL next
sched_ext: Fix the memleak for sch->helper objects

+56 -24
+48 -24
kernel/sched/ext.c
··· 41 41 static bool scx_switching_all; 42 42 DEFINE_STATIC_KEY_FALSE(__scx_switched_all); 43 43 44 + /* 45 + * Tracks whether scx_enable() called scx_bypass(true). Used to balance bypass 46 + * depth on enable failure. Will be removed when bypass depth is moved into the 47 + * sched instance. 48 + */ 49 + static bool scx_bypassed_for_enable; 50 + 44 51 static atomic_long_t scx_nr_rejected = ATOMIC_LONG_INIT(0); 45 52 static atomic_long_t scx_hotplug_seq = ATOMIC_LONG_INIT(0); 46 53 ··· 982 975 __scx_add_event(sch, SCX_EV_REFILL_SLICE_DFL, 1); 983 976 } 984 977 978 + static void local_dsq_post_enq(struct scx_dispatch_q *dsq, struct task_struct *p, 979 + u64 enq_flags) 980 + { 981 + struct rq *rq = container_of(dsq, struct rq, scx.local_dsq); 982 + bool preempt = false; 983 + 984 + /* 985 + * If @rq is in balance, the CPU is already vacant and looking for the 986 + * next task to run. No need to preempt or trigger resched after moving 987 + * @p into its local DSQ. 988 + */ 989 + if (rq->scx.flags & SCX_RQ_IN_BALANCE) 990 + return; 991 + 992 + if ((enq_flags & SCX_ENQ_PREEMPT) && p != rq->curr && 993 + rq->curr->sched_class == &ext_sched_class) { 994 + rq->curr->scx.slice = 0; 995 + preempt = true; 996 + } 997 + 998 + if (preempt || sched_class_above(&ext_sched_class, rq->curr->sched_class)) 999 + resched_curr(rq); 1000 + } 1001 + 985 1002 static void dispatch_enqueue(struct scx_sched *sch, struct scx_dispatch_q *dsq, 986 1003 struct task_struct *p, u64 enq_flags) 987 1004 { ··· 1117 1086 if (enq_flags & SCX_ENQ_CLEAR_OPSS) 1118 1087 atomic_long_set_release(&p->scx.ops_state, SCX_OPSS_NONE); 1119 1088 1120 - if (is_local) { 1121 - struct rq *rq = container_of(dsq, struct rq, scx.local_dsq); 1122 - bool preempt = false; 1123 - 1124 - if ((enq_flags & SCX_ENQ_PREEMPT) && p != rq->curr && 1125 - rq->curr->sched_class == &ext_sched_class) { 1126 - rq->curr->scx.slice = 0; 1127 - preempt = true; 1128 - } 1129 - 1130 - if (preempt || sched_class_above(&ext_sched_class, 1131 - rq->curr->sched_class)) 1132 - resched_curr(rq); 1133 - } else { 1089 + if (is_local) 1090 + local_dsq_post_enq(dsq, p, enq_flags); 1091 + else 1134 1092 raw_spin_unlock(&dsq->lock); 1135 - } 1136 1093 } 1137 1094 1138 1095 static void task_unlink_from_dsq(struct task_struct *p, ··· 1644 1625 1645 1626 dsq_mod_nr(dst_dsq, 1); 1646 1627 p->scx.dsq = dst_dsq; 1628 + 1629 + local_dsq_post_enq(dst_dsq, p, enq_flags); 1647 1630 } 1648 1631 1649 1632 /** ··· 2423 2402 * ops.enqueue() that @p is the only one available for this cpu, 2424 2403 * which should trigger an explicit follow-up scheduling event. 2425 2404 */ 2426 - if (sched_class_above(&ext_sched_class, next->sched_class)) { 2405 + if (next && sched_class_above(&ext_sched_class, next->sched_class)) { 2427 2406 WARN_ON_ONCE(!(sch->ops.flags & SCX_OPS_ENQ_LAST)); 2428 2407 do_enqueue_task(rq, p, SCX_ENQ_LAST, -1); 2429 2408 } else { ··· 2446 2425 do_pick_task_scx(struct rq *rq, struct rq_flags *rf, bool force_scx) 2447 2426 { 2448 2427 struct task_struct *prev = rq->curr; 2449 - bool keep_prev, kick_idle = false; 2428 + bool keep_prev; 2450 2429 struct task_struct *p; 2451 2430 2452 2431 /* see kick_cpus_irq_workfn() */ ··· 2488 2467 refill_task_slice_dfl(rcu_dereference_sched(scx_root), p); 2489 2468 } else { 2490 2469 p = first_local_task(rq); 2491 - if (!p) { 2492 - if (kick_idle) 2493 - scx_kick_cpu(rcu_dereference_sched(scx_root), 2494 - cpu_of(rq), SCX_KICK_IDLE); 2470 + if (!p) 2495 2471 return NULL; 2496 - } 2497 2472 2498 2473 if (unlikely(!p->scx.slice)) { 2499 2474 struct scx_sched *sch = rcu_dereference_sched(scx_root); ··· 3592 3575 int node; 3593 3576 3594 3577 irq_work_sync(&sch->error_irq_work); 3595 - kthread_stop(sch->helper->task); 3578 + kthread_destroy_worker(sch->helper); 3596 3579 3597 3580 free_percpu(sch->pcpu); 3598 3581 ··· 4335 4318 scx_dsp_max_batch = 0; 4336 4319 free_kick_syncs(); 4337 4320 4321 + if (scx_bypassed_for_enable) { 4322 + scx_bypassed_for_enable = false; 4323 + scx_bypass(false); 4324 + } 4325 + 4338 4326 mutex_unlock(&scx_enable_mutex); 4339 4327 4340 4328 WARN_ON_ONCE(scx_set_enable_state(SCX_DISABLED) != SCX_DISABLING); ··· 4808 4786 return sch; 4809 4787 4810 4788 err_stop_helper: 4811 - kthread_stop(sch->helper->task); 4789 + kthread_destroy_worker(sch->helper); 4812 4790 err_free_pcpu: 4813 4791 free_percpu(sch->pcpu); 4814 4792 err_free_gdsqs: ··· 4992 4970 * Init in bypass mode to guarantee forward progress. 4993 4971 */ 4994 4972 scx_bypass(true); 4973 + scx_bypassed_for_enable = true; 4995 4974 4996 4975 for (i = SCX_OPI_NORMAL_BEGIN; i < SCX_OPI_NORMAL_END; i++) 4997 4976 if (((void (**)(void))ops)[i]) ··· 5090 5067 scx_task_iter_stop(&sti); 5091 5068 percpu_up_write(&scx_fork_rwsem); 5092 5069 5070 + scx_bypassed_for_enable = false; 5093 5071 scx_bypass(false); 5094 5072 5095 5073 if (!scx_tryset_enable_state(SCX_ENABLED, SCX_ENABLING)) {
+8
tools/testing/selftests/sched_ext/runner.c
··· 46 46 if (!quiet) 47 47 printf("DESCRIPTION: %s\n", test->description); 48 48 printf("OUTPUT:\n"); 49 + 50 + /* 51 + * The tests may fork with the preamble buffered 52 + * in the children's stdout. Flush before the test 53 + * to avoid printing the message multiple times. 54 + */ 55 + fflush(stdout); 56 + fflush(stderr); 49 57 } 50 58 51 59 static const char *status_to_result(enum scx_test_status status)