From d33d2ef1186096dddf2836f83e91b833866ef3bd Mon Sep 17 00:00:00 2001 From: Paul Buetow Date: Tue, 9 Jun 2026 22:28:33 +0300 Subject: test: add mount_setattr coverage and assert vmsplice TRANSFER byte count mount_setattr(2) was the only new-mount-API sibling not exercised end-to-end (unlike move_mount/fsmount/fspick/open_tree), and vmsplice(2) had zero end-to-end assertion despite being TRANSFER_CLASSIFIED. uj0 (mount_setattr): add a best-effort RawSyscall6(SYS_MOUNT_SETATTR) call to mountfsManagement() aimed at the scenario mount point with AT_FDCWD and a MountAttr requesting MOUNT_ATTR_RDONLY. It needs CAP_SYS_ADMIN (Linux 5.12+) and the path is not a mount, so it returns EPERM/EINVAL, but its sys_enter_ tracepoint fires on kernel entry before any check -- the same best-effort pattern used for the other mount-API calls. Add mount_setattr to mountfsTraceArgs and assert enter_mount_setattr MinCount>=1 in TestMountFsManagementSyscalls. bl0 (vmsplice): add a deterministic retbytesVmsplice driver to the phase-A workload (mirroring the getdents64/readlinkat drivers): a spaced retry loop that gathers a fixed 18-byte user iovec into a fresh pipe via vmsplice and drains it each iteration. vmsplice is TRANSFER_CLASSIFIED, so the exit reports ctx->ret = bytes moved. Add vmsplice to retbytesTraceArgs and assert enter_vmsplice presence plus assertEventBytesAtLeast(payloadLen=18) and a positive duration in TestRetbytesPhaseA, locking in the TRANSFER byte attribution like its splice/tee siblings. Coverage hardening only; classification/tracing verified correct by inspection (mount_setattr=FamilyFS/KindPathname/UNCLASSIFIED, vmsplice=FamilyNetwork/KindFd/TRANSFER_CLASSIFIED). Verified: TEST_NAME=TestMountFsManagementSyscalls mage testWithName PASS (enter_mount_setattr captured); TEST_NAME=TestRetbytesPhaseA mage testWithName PASS (vmsplice bytes>=18 asserted). Co-Authored-By: Claude Opus 4.8 --- integrationtests/retbytes_test.go | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) (limited to 'integrationtests/retbytes_test.go') diff --git a/integrationtests/retbytes_test.go b/integrationtests/retbytes_test.go index a7cb45a..9b2b55c 100644 --- a/integrationtests/retbytes_test.go +++ b/integrationtests/retbytes_test.go @@ -2,7 +2,7 @@ package integrationtests import "testing" -var retbytesTraceArgs = []string{"-trace-syscalls", "sendto,recvfrom,sendmsg,recvmsg,sendmmsg,recvmmsg,sendfile64,splice,tee,process_vm_writev,process_vm_readv,socketpair,pipe2,openat,write,read,close,lseek,fcntl,unlinkat,mkdirat,getdents64,readlinkat,symlink"} +var retbytesTraceArgs = []string{"-trace-syscalls", "sendto,recvfrom,sendmsg,recvmsg,sendmmsg,recvmmsg,sendfile64,splice,tee,vmsplice,process_vm_writev,process_vm_readv,socketpair,pipe2,openat,write,read,close,lseek,fcntl,unlinkat,mkdirat,getdents64,readlinkat,symlink"} func TestRetbytesPhaseA(t *testing.T) { const payloadLen = uint64(18) @@ -21,6 +21,7 @@ func TestRetbytesPhaseA(t *testing.T) { {Tracepoint: "enter_process_vm_readv", Comm: "ioworkload", MinCount: 1}, {Tracepoint: "enter_getdents64", Comm: "ioworkload", MinCount: 1}, {Tracepoint: "enter_readlinkat", Comm: "ioworkload", MinCount: 1}, + {Tracepoint: "enter_vmsplice", Comm: "ioworkload", MinCount: 1}, }, retbytesTraceArgs) for _, tracepoint := range []string{ @@ -62,4 +63,12 @@ func TestRetbytesPhaseA(t *testing.T) { readlinkatExp := ExpectedEvent{Tracepoint: "enter_readlinkat", Comm: "ioworkload"} assertEventBytesAtLeast(t, result, readlinkatExp, 1) assertEventDurationPositive(t, result, readlinkatExp) + + // vmsplice is TRANSFER_CLASSIFIED: a successful gather of the user iovec + // into the pipe reports ctx->ret = bytes moved. The retbytes driver gathers + // exactly payloadLen (18) bytes each iteration, so the exit byte count is at + // least that. This locks in the TRANSFER byte attribution like splice/tee. + vmspliceExp := ExpectedEvent{Tracepoint: "enter_vmsplice", Comm: "ioworkload"} + assertEventBytesAtLeast(t, result, vmspliceExp, payloadLen) + assertEventDurationPositive(t, result, vmspliceExp) } -- cgit v1.2.3