From f12c93dbf6ac839b25c1863aaa37d3d8be6d7a23 Mon Sep 17 00:00:00 2001 From: Paul Buetow Date: Fri, 29 May 2026 22:02:06 +0300 Subject: ioprio_set/ioprio_get: classify as Process family Audit of ioprio_set found a family inconsistency. ioprio_set(which, who, ioprio) and ioprio_get(which, who) query/set the I/O scheduling class and priority of a process, process group, or user. They are the direct I/O-priority analogues of getpriority/setpriority (the CPU nice value) and share the identical which/who selector signature, yet were falling through to FamilyMisc while getpriority/setpriority are FamilyProcess. Reclassify both ioprio syscalls to FamilyProcess for consistency with their priority siblings, update docs/syscall-tracing-plan.md, and regenerate the tracepoint/type artifacts (mage generate is idempotent). Argument capture is unchanged and confirmed correct: the args are all ints (which/who/ioprio), none named fd/path, so ClassifyFormat returns KindNone and the generator promotes the enter format to KindNull (null_event). In particular the 'who' argument (a pid/pgid/uid, never an fd) is not misclassified as KindFd. The exit is a ret_event (UNCLASSIFIED, int 0/-1). Add lock-in tests: - TestClassifyIoprioNullKind asserts KindNone/KindNull using the real kernel tracepoint fields, proving 'who' is not captured as an fd. - Family assertions for the ioprio pair alongside getpriority/setpriority so a stray reclassification of any of them trips the test. Co-Authored-By: Claude Opus 4.8 --- internal/generate/classify_test.go | 52 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 52 insertions(+) (limited to 'internal/generate/classify_test.go') diff --git a/internal/generate/classify_test.go b/internal/generate/classify_test.go index 92b6e58..1d832a4 100644 --- a/internal/generate/classify_test.go +++ b/internal/generate/classify_test.go @@ -1259,6 +1259,58 @@ func TestClassifyE7NullNameOnlyKinds(t *testing.T) { } } +// TestClassifyIoprioNullKind locks in the argument-capture classification for +// ioprio_set/ioprio_get using their real kernel tracepoint fields. Unlike the +// name-only Misc/null syscalls above, ioprio_* are NOT in nameOnlyKindsTable: +// they classify by field fallthrough. ioprio_set(which, who, ioprio) and +// ioprio_get(which, who) carry only int-typed which/who/ioprio fields. None is +// named "fd"/"pathname"/"path"/"filename", so ClassifyFormat must return +// KindNone — in particular the "who" argument (a pid/pgid/uid selected by +// "which", never an fd) must NOT be misclassified as KindFd, and nothing must be +// captured as a path. classifyEnterForGeneration then promotes the field-bearing +// enter format to KindNull (the null_event seen in generated_tracepoints.c). +func TestClassifyIoprioNullKind(t *testing.T) { + cases := []struct { + name string + fields []Field + }{ + { + name: "sys_enter_ioprio_set", + fields: []Field{ + {Type: "int", Name: "__syscall_nr"}, + {Type: "int", Name: "which"}, + {Type: "int", Name: "who"}, + {Type: "int", Name: "ioprio"}, + }, + }, + { + name: "sys_enter_ioprio_get", + fields: []Field{ + {Type: "int", Name: "__syscall_nr"}, + {Type: "int", Name: "which"}, + {Type: "int", Name: "who"}, + }, + }, + } + + for _, tc := range cases { + t.Run(tc.name, func(t *testing.T) { + f := &Format{Name: tc.name, ExternalFields: tc.fields} + + // No field should match an fd/path/name pattern: raw classification + // is KindNone, proving "who" is not captured as an fd. + if r := ClassifyFormat(f); r.Kind != KindNone { + t.Fatalf("%s: ClassifyFormat kind = %d, want KindNone", tc.name, r.Kind) + } + + // The generator promotes the field-bearing enter format to KindNull. + if r := classifyEnterForGeneration(f); r.Kind != KindNull { + t.Fatalf("%s: classifyEnterForGeneration kind = %d, want KindNull", tc.name, r.Kind) + } + }) + } +} + func TestClassifyB7NameOnlyKinds(t *testing.T) { tests := []struct { name string -- cgit v1.2.3