1 // SPDX-License-Identifier: GPL-2.0 2 /* 3 * ops.dequeue() of this scheduler iterates the user DSQ it consumes 4 * tasks from with bpf_iter_scx_dsq, which takes the DSQ lock. 5 * On a kernel that still runs ops.dequeue() with that lock held, the 6 * iteration self-deadlocks the CPU - this test wedges the system on 7 * unfixed kernels instead of failing cleanly. 8 * 9 * Copyright (c) 2026 fangqiurong <fangqiurong@kylinos.cn> 10 */ 11 12 #include <scx/common.bpf.h> 13 14 char _license[] SEC("license") = "GPL"; 15 16 UEI_DEFINE(uei); 17 18 #define TEST_DSQ_ID 1000 19 20 u64 dq_count; 21 22 s32 BPF_STRUCT_OPS_SLEEPABLE(dequeue_iter_init) 23 { 24 return scx_bpf_create_dsq(TEST_DSQ_ID, -1); 25 } 26 27 s32 BPF_STRUCT_OPS(dequeue_iter_select_cpu, struct task_struct *p, 28 s32 prev_cpu, u64 wake_flags) 29 { 30 return prev_cpu; 31 } 32 33 void BPF_STRUCT_OPS(dequeue_iter_enqueue, struct task_struct *p, u64 enq_flags) 34 { 35 scx_bpf_dsq_insert(p, TEST_DSQ_ID, SCX_SLICE_DFL, enq_flags); 36 } 37 38 void BPF_STRUCT_OPS(dequeue_iter_dispatch, s32 cpu, struct task_struct *task) 39 { 40 scx_bpf_dsq_move_to_local(TEST_DSQ_ID, 0); 41 } 42 43 void BPF_STRUCT_OPS(dequeue_iter_dequeue, struct task_struct *p, u64 deq_flags) 44 { 45 struct bpf_iter_scx_dsq it; 46 struct task_struct *t; 47 48 if (!bpf_iter_scx_dsq_new(&it, TEST_DSQ_ID, 0)) { 49 while ((t = bpf_iter_scx_dsq_next(&it))) 50 ; 51 } 52 bpf_iter_scx_dsq_destroy(&it); 53 54 __sync_fetch_and_add(&dq_count, 1); 55 } 56 57 void BPF_STRUCT_OPS(dequeue_iter_exit, struct scx_exit_info *ei) 58 { 59 UEI_RECORD(uei, ei); 60 scx_bpf_destroy_dsq(TEST_DSQ_ID); 61 } 62 63 SEC(".struct_ops.link") 64 struct sched_ext_ops dequeue_iter_ops = { 65 .init = (void *)dequeue_iter_init, 66 .select_cpu = (void *)dequeue_iter_select_cpu, 67 .enqueue = (void *)dequeue_iter_enqueue, 68 .dispatch = (void *)dequeue_iter_dispatch, 69 .dequeue = (void *)dequeue_iter_dequeue, 70 .exit = (void *)dequeue_iter_exit, 71 .timeout_ms = 1000U, 72 .name = "dequeue_iter", 73 }; 74