summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--cmd/ioworkload/scenario_mountfs.go44
-rw-r--r--integrationtests/mountfs_test.go9
2 files changed, 50 insertions, 3 deletions
diff --git a/cmd/ioworkload/scenario_mountfs.go b/cmd/ioworkload/scenario_mountfs.go
index 7aa8163..8736da6 100644
--- a/cmd/ioworkload/scenario_mountfs.go
+++ b/cmd/ioworkload/scenario_mountfs.go
@@ -41,16 +41,56 @@ func mountfsManagement() error {
putOld := mustCStringPtr(dir)
tmpfs := mustCStringPtr("tmpfs")
none := mustCStringPtr("none")
+ rootPath := mustCStringPtr("/")
atFDCWDInt := int64(unix.AT_FDCWD)
atFDCWD := uintptr(atFDCWDInt)
+ keyName := mustCStringPtr("source")
+ keyValue := mustCStringPtr("none")
+
// Best-effort coverage: these calls are expected to fail on most hosts
- // without CAP_SYS_ADMIN, but still exercise syscall tracing paths.
+ // without CAP_SYS_ADMIN, but still exercise syscall tracing paths. Every
+ // sys_enter_ tracepoint fires on kernel entry, before any permission or
+ // validity check, so the integration assertions only require the enter_
+ // tracepoint to fire once (MinCount>=1) regardless of the syscall's return.
+ //
// fsopen(fsname, flags) is the entry point of the new mount API: it takes a
// filesystem TYPE name (e.g. "tmpfs"), NOT a path, in args[0] and the
// FSOPEN_CLOEXEC flag in args[1], returning a new filesystem-context fd. We
- // close the returned fd when the call succeeds so we do not leak it.
+ // keep the returned fd to feed fsconfig below, and close it afterwards so we
+ // do not leak it.
+ fsContextFd := -1
if fd, _, errno := syscall.RawSyscall(unix.SYS_FSOPEN, uintptr(unsafe.Pointer(tmpfs)), uintptr(unix.FSOPEN_CLOEXEC), 0); errno == 0 {
+ fsContextFd = int(fd)
+ }
+
+ // fsconfig(fd, cmd, key, value, aux) configures a filesystem context obtained
+ // from fsopen. It is a KindFd syscall: args[0] is the fscontext fd. We issue
+ // two best-effort commands on whatever fd we have (the real fscontext fd when
+ // fsopen succeeded, otherwise an invalid -1 which still fires the enter_
+ // tracepoint and returns EBADF): FSCONFIG_SET_STRING to set a parameter and
+ // FSCONFIG_CMD_CREATE to materialise the superblock. Errors (ENOSYS on old
+ // kernels, EPERM/EINVAL/EBADF otherwise) are tolerated; no mount is created.
+ _, _, _ = syscall.RawSyscall6(unix.SYS_FSCONFIG, uintptr(fsContextFd), uintptr(unix.FSCONFIG_SET_STRING), uintptr(unsafe.Pointer(keyName)), uintptr(unsafe.Pointer(keyValue)), 0, 0)
+ _, _, _ = syscall.RawSyscall6(unix.SYS_FSCONFIG, uintptr(fsContextFd), uintptr(unix.FSCONFIG_CMD_CREATE), 0, 0, 0, 0)
+ if fsContextFd >= 0 {
+ _ = syscall.Close(fsContextFd)
+ }
+
+ // fspick(dfd, path, flags) creates a filesystem context for an EXISTING mount
+ // so it can be reconfigured. It is a KindPathname syscall: args[1] is the path.
+ // We point it at "/" (always present) with FSPICK_NO_AUTOMOUNT and close any
+ // returned fscontext fd. This reconfigures nothing and creates no mount.
+ if fd, _, errno := syscall.RawSyscall(unix.SYS_FSPICK, atFDCWD, uintptr(unsafe.Pointer(rootPath)), uintptr(unix.FSPICK_NO_AUTOMOUNT)); errno == 0 {
+ _ = syscall.Close(int(fd))
+ }
+
+ // open_tree(dfd, path, flags) clones or references a mount subtree, returning
+ // a detached O_PATH-like fd. It is a KindOpen syscall: args[0] is the dirfd.
+ // We clone the scenario mount point (OPEN_TREE_CLONE | OPEN_TREE_CLOEXEC) and
+ // close any returned fd. A detached clone is not attached anywhere in the
+ // mount tree, so closing the fd releases it without touching host mounts.
+ if fd, _, errno := syscall.RawSyscall(unix.SYS_OPEN_TREE, atFDCWD, uintptr(unsafe.Pointer(mountPath)), uintptr(unix.OPEN_TREE_CLONE|unix.OPEN_TREE_CLOEXEC)); errno == 0 {
_ = syscall.Close(int(fd))
}
_, _, _ = syscall.RawSyscall6(unix.SYS_MOUNT, uintptr(unsafe.Pointer(none)), uintptr(unsafe.Pointer(mountPath)), uintptr(unsafe.Pointer(tmpfs)), 0, 0, 0)
diff --git a/integrationtests/mountfs_test.go b/integrationtests/mountfs_test.go
index 673e9c1..d50706f 100644
--- a/integrationtests/mountfs_test.go
+++ b/integrationtests/mountfs_test.go
@@ -4,7 +4,7 @@ import "testing"
var mountfsTraceArgs = []string{
"-trace-syscalls",
- "mount,umount,move_mount,fsopen,fsmount,pivot_root,quotactl,statmount,listmount,listns,swapon,swapoff",
+ "mount,umount,move_mount,fsopen,fsconfig,fspick,open_tree,fsmount,pivot_root,quotactl,statmount,listmount,listns,swapon,swapoff",
}
func TestMountFsManagementSyscalls(t *testing.T) {
@@ -13,6 +13,13 @@ func TestMountFsManagementSyscalls(t *testing.T) {
{Tracepoint: "enter_umount", MinCount: 1},
{Tracepoint: "enter_move_mount", MinCount: 1},
{Tracepoint: "enter_fsopen", MinCount: 1},
+ // fsconfig (KindFd), fspick (KindPathname), and open_tree (KindOpen) are
+ // best-effort new-mount-API calls in the scenario. Their sys_enter_
+ // tracepoints fire on kernel entry regardless of permission/validity, so
+ // MinCount>=1 holds even when the syscalls themselves return an error.
+ {Tracepoint: "enter_fsconfig", MinCount: 1},
+ {Tracepoint: "enter_fspick", MinCount: 1},
+ {Tracepoint: "enter_open_tree", MinCount: 1},
{Tracepoint: "enter_fsmount", MinCount: 1},
{Tracepoint: "enter_pivot_root", MinCount: 1},
{Tracepoint: "enter_quotactl", MinCount: 1},