@@ -1209,10 +1209,73 @@ let test_sched_ext_ops_btf_definition () =
12091209 check bool " Generated definition contains flags" true (contains_substr definition " flags" )
12101210 | None -> fail " Should generate definition for valid BTF type" )
12111211
1212+ (* * Test that struct_ops functions can call kernel functions (kfuncs) - regression test for type checker bug *)
1213+ let test_struct_ops_can_call_kernel_functions () =
1214+ let program = {|
1215+ // Declare external kernel functions (kfuncs)
1216+ extern scx_bpf_select_cpu_dfl(p: *u8, prev_cpu: i32, wake_flags: u64, direct: *bool ) -> i32
1217+ extern scx_bpf_dsq_insert(p: *u8, dsq_id: u64, slice: u64, enq_flags: u64 ) -> void
1218+ extern scx_bpf_consume(dsq_id: u64, cpu: i32, flags: u64 ) -> i32
1219+
1220+ // Kernel enum constants
1221+ enum scx_dsq_id_flags {
1222+ SCX_DSQ_GLOBAL = 9223372036854775809 ,
1223+ SCX_DSQ_LOCAL = 9223372036854775810 ,
1224+ SCX_SLICE_DFL = 20000000 ,
1225+ }
1226+
1227+ @ struct_ops(" sched_ext_ops" )
1228+ impl simple_scheduler {
1229+ fn select_cpu(p: *u8, prev_cpu: i32, wake_flags: u64 ) -> i32 {
1230+ var direct : bool = false
1231+ // This should be allowed - struct_ops functions run in kernel context
1232+ var cpu = scx_bpf_select_cpu_dfl (p , prev_cpu , wake_flags , & direct)
1233+
1234+ if (direct == true ) {
1235+ scx_bpf_dsq_insert(p, SCX_DSQ_LOCAL , SCX_SLICE_DFL , 0 )
1236+ }
1237+
1238+ return cpu
1239+ }
1240+
1241+ fn dispatch(cpu: i32, prev: *u8 ) -> void {
1242+ // This should also be allowed - calling kernel function from struct_ops
1243+ if (scx_bpf_consume(SCX_DSQ_GLOBAL , cpu, 0 ) == 0 ) {
1244+ // No tasks available
1245+ }
1246+ }
1247+
1248+ name : "simple_sched" ,
1249+ timeout_ms : 0 ,
1250+ flags : 0 ,
1251+ }
1252+
1253+ fn main() -> i32 {
1254+ var result = register(simple_scheduler)
1255+ return result
1256+ }
1257+ | } in
1258+
1259+ let ast = Parse. parse_string program in
1260+
1261+ (* This should succeed - struct_ops functions should be able to call kernel functions *)
1262+ try
1263+ let _ = Type_checker. type_check_and_annotate_ast ast in
1264+ check bool " struct_ops functions should be able to call kernel functions" true true
1265+ with
1266+ | Type_checker. Type_error (msg , _ ) ->
1267+ (* If we get the old error message, the bug is still present *)
1268+ if String. contains msg 'u' && String. contains msg 's' && String. contains msg 'e' && String. contains msg 'r' then
1269+ fail (" struct_ops functions should be able to call kernel functions, but got error: " ^ msg)
1270+ else
1271+ fail (" Unexpected type error: " ^ msg)
1272+ | _ -> fail " Unexpected error during type checking"
1273+
12121274let tests = [
12131275 " struct_ops parsing" , `Quick , test_struct_ops_parsing;
12141276 " regular struct parsing" , `Quick , test_regular_struct_parsing;
12151277 " register() with struct_ops" , `Quick , test_register_with_struct_ops;
1278+ " struct_ops can call kernel functions" , `Quick , test_struct_ops_can_call_kernel_functions;
12161279 " register() rejects regular struct" , `Quick , test_register_rejects_regular_struct;
12171280 " multiple struct_ops" , `Quick , test_multiple_struct_ops;
12181281 " struct_ops IR generation" , `Quick , test_struct_ops_ir_generation;
0 commit comments