diff options
| author | Paul Buetow <paul@buetow.org> | 2026-02-21 22:03:57 +0200 |
|---|---|---|
| committer | Paul Buetow <paul@buetow.org> | 2026-02-21 22:03:57 +0200 |
| commit | 3ec3c117bb280a377fea1a3eef84a70e2a3d4150 (patch) | |
| tree | b017e330eeaa1cafe95d2a730675b46342afd92a /integrationtests/cmd/ioworkload/scenario_close.go | |
| parent | 311b827599251d8d68526293815e8d4dcba632c8 (diff) | |
Split ioworkload scenarios.go into per-category files
Split the 2494-line scenarios.go monolith into 14 focused files by
syscall category: open, readwrite, close, dup, fcntl, rename, link,
unlink, dir, stat, sync, truncate, iouring, plus the slimmed-down
scenarios.go containing only the registry map, makeTempDir, and crash.
Extracted rawLink, rawSymlink, rawReadlink helpers in scenario_link.go
to reduce code duplication in linkBasic.
Task: #349 (Go best practices: split oversized scenarios file)
Amp-Thread-ID: https://ampcode.com/threads/T-019c81c6-e1b6-747a-9144-40f6be997e60
Co-authored-by: Amp <amp@ampcode.com>
Diffstat (limited to 'integrationtests/cmd/ioworkload/scenario_close.go')
| -rw-r--r-- | integrationtests/cmd/ioworkload/scenario_close.go | 114 |
1 files changed, 114 insertions, 0 deletions
diff --git a/integrationtests/cmd/ioworkload/scenario_close.go b/integrationtests/cmd/ioworkload/scenario_close.go new file mode 100644 index 0000000..a36160a --- /dev/null +++ b/integrationtests/cmd/ioworkload/scenario_close.go @@ -0,0 +1,114 @@ +package main + +import ( + "fmt" + "path/filepath" + "syscall" +) + +const sysCloseRange = 436 + +// closeBasic opens multiple files and closes them. +func closeBasic() error { + dir, cleanup, err := makeTempDir("close-basic") + if err != nil { + return err + } + defer cleanup() + + var fds []int + for i := range 3 { + path := filepath.Join(dir, fmt.Sprintf("closefile-%d.txt", i)) + fd, err := syscall.Open(path, syscall.O_RDWR|syscall.O_CREAT, 0o644) + if err != nil { + return fmt.Errorf("open %d: %w", i, err) + } + fds = append(fds, fd) + } + for _, fd := range fds { + if err := syscall.Close(fd); err != nil { + return fmt.Errorf("close fd %d: %w", fd, err) + } + } + return nil +} + +// closeRange opens multiple files and closes a range of them via close_range(2). +func closeRange() error { + dir, cleanup, err := makeTempDir("close-range") + if err != nil { + return err + } + defer cleanup() + + var fds []int + for i := range 3 { + path := filepath.Join(dir, fmt.Sprintf("closerangefile-%d.txt", i)) + fd, err := syscall.Open(path, syscall.O_RDWR|syscall.O_CREAT, 0o644) + if err != nil { + return fmt.Errorf("open %d: %w", i, err) + } + fds = append(fds, fd) + } + + if fds[2]-fds[0] != 2 { + return fmt.Errorf("fds not contiguous: %v", fds) + } + + first := uintptr(fds[0]) + last := uintptr(fds[len(fds)-1]) + _, _, errno := syscall.Syscall(sysCloseRange, first, last, 0) + if errno != 0 { + return fmt.Errorf("close_range: %w", errno) + } + return nil +} + +// closeInvalidFd attempts to close a very high fd number that is not open. +// The close fails with EBADF, but ior should capture the enter_close tracepoint +// because arguments are read on syscall entry before the kernel returns an error. +func closeInvalidFd() error { + err := syscall.Close(99999) + if err == nil { + return fmt.Errorf("expected close of invalid fd to fail") + } + return nil +} + +// closeDoubleClose opens a file, closes it normally, then closes the same fd again. +// The second close fails with EBADF, but ior should capture both enter_close +// tracepoints because arguments are read on syscall entry. +func closeDoubleClose() error { + dir, cleanup, err := makeTempDir("close-double-close") + if err != nil { + return err + } + defer cleanup() + + path := filepath.Join(dir, "doubleclosefile.txt") + fd, err := syscall.Open(path, syscall.O_RDWR|syscall.O_CREAT, 0o644) + if err != nil { + return fmt.Errorf("open: %w", err) + } + + if err := syscall.Close(fd); err != nil { + return fmt.Errorf("first close: %w", err) + } + + err = syscall.Close(fd) + if err == nil { + return fmt.Errorf("expected second close of same fd to fail") + } + return nil +} + +// closeRangeEmpty calls close_range(2) with a range of very high fd numbers +// (9000–9999) where no fds are open. The syscall succeeds (empty range is valid), +// and ior should capture the enter_close_range tracepoint. +func closeRangeEmpty() error { + _, _, errno := syscall.Syscall(sysCloseRange, 9000, 9999, 0) + if errno != 0 { + return fmt.Errorf("close_range: %w", errno) + } + return nil +} |
