Skip to content

Commit e8deaf9

Browse files
committed
Fix struct_ops implementations to allow calling kernel functions by type checker.
Signed-off-by: Cong Wang <cwang@multikernel.io>
1 parent fd3b940 commit e8deaf9

2 files changed

Lines changed: 76 additions & 1 deletion

File tree

src/type_checker.ml

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3147,9 +3147,21 @@ let rec type_check_and_annotate_ast ?symbol_table:(provided_symbol_table=None) ?
31473147
(attr_acc, typed_func :: userspace_acc)
31483148
| ImplBlock impl_block ->
31493149
(* Type check impl block functions - treat them as eBPF functions with struct_ops attributes *)
3150+
(* Check if this is a struct_ops impl block *)
3151+
let is_struct_ops = List.exists (function
3152+
| AttributeWithArg ("struct_ops", _) -> true
3153+
| _ -> false
3154+
) impl_block.impl_attributes in
3155+
31503156
let typed_impl_functions = List.filter_map (function
31513157
| ImplFunction func ->
3152-
let typed_func = type_check_function ctx func in
3158+
(* Set function scope to Kernel for struct_ops implementations *)
3159+
let func_to_check = if is_struct_ops then
3160+
{ func with func_scope = Ast.Kernel }
3161+
else
3162+
func
3163+
in
3164+
let typed_func = type_check_function ctx func_to_check in
31533165
Some (impl_block.impl_attributes, typed_func)
31543166
| ImplStaticField (_, _) -> None (* Static fields don't need type checking as functions *)
31553167
) impl_block.impl_items in

tests/test_struct_ops.ml

Lines changed: 63 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -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+
12121274
let 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

Comments
 (0)