From 603972340549cd3265f184457ee072fd8915e27b Mon Sep 17 00:00:00 2001 From: Paul Buetow Date: Sat, 21 Feb 2026 21:12:12 +0200 Subject: Add negative integration tests for fcntl syscalls (task 348) Add two negative scenarios: - fcntl-invalid-fd: calls SYS_FCNTL F_GETFL on invalid fd 99999 (EBADF) - fcntl-dupfd-max: calls F_DUPFD with minfd=1<<30 beyond RLIMIT_NOFILE (EINVAL) Both verify ior captures enter_fcntl tracepoints even when syscalls fail. Amp-Thread-ID: https://ampcode.com/threads/T-019c819b-5673-75ab-8eb4-227b6cf56b38 Co-authored-by: Amp --- integrationtests/cmd/ioworkload/scenarios.go | 38 ++++++++++++++++++++++++++++ 1 file changed, 38 insertions(+) (limited to 'integrationtests/cmd') diff --git a/integrationtests/cmd/ioworkload/scenarios.go b/integrationtests/cmd/ioworkload/scenarios.go index dd8d46e..4275fb6 100644 --- a/integrationtests/cmd/ioworkload/scenarios.go +++ b/integrationtests/cmd/ioworkload/scenarios.go @@ -42,6 +42,8 @@ var scenarios = map[string]func() error{ "fcntl-dupfd": fcntlDupfd, "fcntl-setfl": fcntlSetfl, "fcntl-dupfd-cloexec": fcntlDupfdCloexec, + "fcntl-invalid-fd": fcntlInvalidFd, + "fcntl-dupfd-max": fcntlDupfdMax, "rename-basic": renameBasic, "rename-renameat": renameRenameat, "rename-renameat2": renameRenameat2, @@ -789,6 +791,42 @@ func fcntlDupfdCloexec() error { return nil } +// fcntlInvalidFd calls fcntl F_GETFL on an invalid fd (99999). +// The syscall fails with EBADF, but ior should capture the enter_fcntl +// tracepoint because it is recorded on syscall entry. +func fcntlInvalidFd() error { + _, _, errno := syscall.Syscall(syscall.SYS_FCNTL, 99999, syscall.F_GETFL, 0) + if errno == 0 { + return fmt.Errorf("expected fcntl on invalid fd to fail") + } + return nil +} + +// fcntlDupfdMax opens a file and calls fcntl F_DUPFD with a minfd value +// that exceeds the process RLIMIT_NOFILE. The kernel rejects this with +// EINVAL, but ior should capture the enter_fcntl tracepoint. +func fcntlDupfdMax() error { + dir, cleanup, err := makeTempDir("fcntl-dupfd-max") + if err != nil { + return err + } + defer cleanup() + + path := filepath.Join(dir, "fcntldupfdmaxfile.txt") + fd, err := syscall.Open(path, syscall.O_RDWR|syscall.O_CREAT, 0o644) + if err != nil { + return fmt.Errorf("open: %w", err) + } + defer syscall.Close(fd) + + // Use a minfd far beyond any realistic RLIMIT_NOFILE. + _, _, errno := syscall.Syscall(syscall.SYS_FCNTL, uintptr(fd), syscall.F_DUPFD, 1<<30) + if errno == 0 { + return fmt.Errorf("expected fcntl F_DUPFD with extreme minfd to fail") + } + return nil +} + // renameBasic creates a file and renames it via rename(2). // Uses raw SYS_RENAME because Go's syscall.Rename wraps renameat on amd64. func renameBasic() error { -- cgit v1.2.3