diff options
Diffstat (limited to 'integrationtests/cmd/ioworkload/scenario_readwrite.go')
| -rw-r--r-- | integrationtests/cmd/ioworkload/scenario_readwrite.go | 263 |
1 files changed, 263 insertions, 0 deletions
diff --git a/integrationtests/cmd/ioworkload/scenario_readwrite.go b/integrationtests/cmd/ioworkload/scenario_readwrite.go new file mode 100644 index 0000000..c676b90 --- /dev/null +++ b/integrationtests/cmd/ioworkload/scenario_readwrite.go @@ -0,0 +1,263 @@ +package main + +import ( + "fmt" + "path/filepath" + "runtime" + "syscall" + "unsafe" +) + +// readwriteBasic opens a file, writes data, seeks to start, reads it back. +func readwriteBasic() error { + dir, cleanup, err := makeTempDir("readwrite-basic") + if err != nil { + return err + } + defer cleanup() + + path := filepath.Join(dir, "rwfile.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) + + data := []byte("hello from ioworkload") + if _, err := syscall.Write(fd, data); err != nil { + return fmt.Errorf("write: %w", err) + } + if _, err := syscall.Seek(fd, 0, 0); err != nil { + return fmt.Errorf("seek: %w", err) + } + + buf := make([]byte, len(data)) + if _, err := syscall.Read(fd, buf); err != nil { + return fmt.Errorf("read: %w", err) + } + return nil +} + +// readwritePread opens a file, writes data, then reads it back via pread64. +func readwritePread() error { + dir, cleanup, err := makeTempDir("readwrite-pread") + if err != nil { + return err + } + defer cleanup() + + path := filepath.Join(dir, "preadfile.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) + + data := []byte("pread test data") + if _, err := syscall.Write(fd, data); err != nil { + return fmt.Errorf("write: %w", err) + } + + buf := make([]byte, len(data)) + if _, err := syscall.Pread(fd, buf, 0); err != nil { + return fmt.Errorf("pread: %w", err) + } + return nil +} + +// readwritePwrite opens a file and writes data via pwrite64. +func readwritePwrite() error { + dir, cleanup, err := makeTempDir("readwrite-pwrite") + if err != nil { + return err + } + defer cleanup() + + path := filepath.Join(dir, "pwritefile.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) + + if _, err := syscall.Pwrite(fd, []byte("pwrite test data"), 0); err != nil { + return fmt.Errorf("pwrite: %w", err) + } + return nil +} + +// readwriteReadv opens a file, writes data, then reads it back via readv. +func readwriteReadv() error { + dir, cleanup, err := makeTempDir("readwrite-readv") + if err != nil { + return err + } + defer cleanup() + + path := filepath.Join(dir, "readvfile.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) + + data := []byte("readv test data here") + if _, err := syscall.Write(fd, data); err != nil { + return fmt.Errorf("write: %w", err) + } + if _, err := syscall.Seek(fd, 0, 0); err != nil { + return fmt.Errorf("seek: %w", err) + } + + buf1 := make([]byte, 5) + buf2 := make([]byte, 15) + iovs := []syscall.Iovec{ + {Base: &buf1[0], Len: uint64(len(buf1))}, + {Base: &buf2[0], Len: uint64(len(buf2))}, + } + _, _, errno := syscall.Syscall(syscall.SYS_READV, uintptr(fd), uintptr(unsafe.Pointer(&iovs[0])), uintptr(len(iovs))) + runtime.KeepAlive(buf1) + runtime.KeepAlive(buf2) + if errno != 0 { + return fmt.Errorf("readv: %w", errno) + } + return nil +} + +// readwriteWritev opens a file and writes data via writev. +func readwriteWritev() error { + dir, cleanup, err := makeTempDir("readwrite-writev") + if err != nil { + return err + } + defer cleanup() + + path := filepath.Join(dir, "writevfile.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) + + buf1 := []byte("writev ") + buf2 := []byte("test data") + iovs := []syscall.Iovec{ + {Base: &buf1[0], Len: uint64(len(buf1))}, + {Base: &buf2[0], Len: uint64(len(buf2))}, + } + _, _, errno := syscall.Syscall(syscall.SYS_WRITEV, uintptr(fd), uintptr(unsafe.Pointer(&iovs[0])), uintptr(len(iovs))) + runtime.KeepAlive(buf1) + runtime.KeepAlive(buf2) + if errno != 0 { + return fmt.Errorf("writev: %w", errno) + } + return nil +} + +// readwriteWronlyRead opens a file O_WRONLY, then attempts to read from it. +// The read fails with EBADF, but ior should capture the enter_read tracepoint +// because arguments are read on syscall entry before the kernel returns an error. +func readwriteWronlyRead() error { + dir, cleanup, err := makeTempDir("readwrite-wronly-read") + if err != nil { + return err + } + defer cleanup() + + path := filepath.Join(dir, "wronlyfile.txt") + fd, err := syscall.Open(path, syscall.O_WRONLY|syscall.O_CREAT, 0o644) + if err != nil { + return fmt.Errorf("open: %w", err) + } + defer syscall.Close(fd) + + buf := make([]byte, 16) + _, err = syscall.Read(fd, buf) + if err == nil { + return fmt.Errorf("expected read from wronly fd to fail") + } + return nil +} + +// readwriteRdonlyWrite opens a file O_RDONLY, then attempts to write to it. +// The write fails with EBADF, but ior should capture the enter_write tracepoint +// because arguments are read on syscall entry before the kernel returns an error. +func readwriteRdonlyWrite() error { + dir, cleanup, err := makeTempDir("readwrite-rdonly-write") + if err != nil { + return err + } + defer cleanup() + + path := filepath.Join(dir, "rdonlywritefile.txt") + fd, err := syscall.Open(path, syscall.O_RDWR|syscall.O_CREAT, 0o644) + if err != nil { + return fmt.Errorf("create file: %w", err) + } + syscall.Close(fd) + + fd, err = syscall.Open(path, syscall.O_RDONLY, 0) + if err != nil { + return fmt.Errorf("open rdonly: %w", err) + } + defer syscall.Close(fd) + + _, err = syscall.Write(fd, []byte("should fail")) + if err == nil { + return fmt.Errorf("expected write to rdonly fd to fail") + } + return nil +} + +// readwritePreadInvalid calls pread64 with a negative offset (-1). +// The syscall fails with EINVAL, but ior should capture the enter_pread64 +// tracepoint because arguments are read on syscall entry. +func readwritePreadInvalid() error { + dir, cleanup, err := makeTempDir("readwrite-pread-invalid") + if err != nil { + return err + } + defer cleanup() + + path := filepath.Join(dir, "preadinvalid.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) + + if _, err := syscall.Write(fd, []byte("some data")); err != nil { + return fmt.Errorf("write: %w", err) + } + + buf := make([]byte, 16) + _, err = syscall.Pread(fd, buf, -1) + if err == nil { + return fmt.Errorf("expected pread with negative offset to fail") + } + return nil +} + +// readwritePwriteInvalid calls pwrite64 with a negative offset (-1). +// The syscall fails with EINVAL, but ior should capture the enter_pwrite64 +// tracepoint because arguments are read on syscall entry. +func readwritePwriteInvalid() error { + dir, cleanup, err := makeTempDir("readwrite-pwrite-invalid") + if err != nil { + return err + } + defer cleanup() + + path := filepath.Join(dir, "pwriteinvalid.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) + + _, err = syscall.Pwrite(fd, []byte("should fail"), -1) + if err == nil { + return fmt.Errorf("expected pwrite with negative offset to fail") + } + return nil +} |
