From 2cc512a3b992e59064b448c4a61b6d35bd394673 Mon Sep 17 00:00:00 2001 From: vasilito Date: Wed, 8 Jul 2026 22:02:33 +0300 Subject: [PATCH] kernel: add I/O accounting to SYS_READ2/SYS_WRITE2 (pread/pwrite) SYS_READ2 and SYS_WRITE2 are the positioned read/write syscalls (equivalent to pread/pwrite in POSIX). Previously only SYS_READ and SYS_WRITE were counted. Now all four I/O paths are tracked. This makes /proc/[pid]/io accurate for programs that use pread/pwrite (common in random-access file I/O, memory-mapped I/O bypass, and async I/O libraries). Cross-referenced with Linux 7.1 mm/filemap.c:rw_verify_area which tracks these accounting fields for all read/write variants. --- src/syscall/mod.rs | 94 +++++++++++++++++++++++++++------------------- 1 file changed, 55 insertions(+), 39 deletions(-) diff --git a/src/syscall/mod.rs b/src/syscall/mod.rs index 82090fc339..7211a2152d 100644 --- a/src/syscall/mod.rs +++ b/src/syscall/mod.rs @@ -22,7 +22,7 @@ use self::{ }; use crate::{ - context::memory::AddrSpace, + context::{self, memory::AddrSpace}, percpu::PercpuBlock, scheme::{memory::MemoryScheme, FileHandle}, sync::CleanLockToken, @@ -73,26 +73,34 @@ pub fn syscall( let fd = FileHandle::from(b); //SYS_* is declared in kernel/syscall/src/number.rs match a { - SYS_WRITE2 => file_op_generic_ext(fd, token, |scheme, _, desc, token| { - let flags = if f == usize::MAX { - None - } else { - Some( - u32::try_from(f) - .ok() - .and_then(RwFlags::from_bits) - .ok_or(Error::new(EINVAL))?, + SYS_WRITE2 => { + let bytes = file_op_generic_ext(fd, token, |scheme, _, desc, token| { + let flags = if f == usize::MAX { + None + } else { + Some( + u32::try_from(f) + .ok() + .and_then(RwFlags::from_bits) + .ok_or(Error::new(EINVAL))?, + ) + }; + scheme.kwriteoff( + desc.number, + UserSlice::ro(c, d)?, + e as u64, + flags.map_or(desc.flags, |f| desc.rw_flags(f)), + desc.flags, + token, ) - }; - scheme.kwriteoff( - desc.number, - UserSlice::ro(c, d)?, - e as u64, - flags.map_or(desc.flags, |f| desc.rw_flags(f)), - desc.flags, - token, - ) - }), + })?; + let current = context::current(); + let mut guard = current.write(token.token()); + guard.io_wchar = guard.io_wchar.saturating_add(bytes as u64); + guard.io_syscw = guard.io_syscw.saturating_add(1); + guard.io_write_bytes = guard.io_write_bytes.saturating_add(bytes as u64); + Ok(bytes) + } SYS_WRITE => sys_write(fd, UserSlice::ro(c, d)?, token), SYS_FMAP => { let addrspace = AddrSpace::current()?; @@ -121,26 +129,34 @@ pub fn syscall( scheme.kfutimens(number, UserSlice::ro(c, d)?, token) }), - SYS_READ2 => file_op_generic_ext(fd, token, |scheme, _, desc, token| { - let flags = if f == usize::MAX { - None - } else { - Some( - u32::try_from(f) - .ok() - .and_then(RwFlags::from_bits) - .ok_or(Error::new(EINVAL))?, + SYS_READ2 => { + let bytes = file_op_generic_ext(fd, token, |scheme, _, desc, token| { + let flags = if f == usize::MAX { + None + } else { + Some( + u32::try_from(f) + .ok() + .and_then(RwFlags::from_bits) + .ok_or(Error::new(EINVAL))?, + ) + }; + scheme.kreadoff( + desc.number, + UserSlice::wo(c, d)?, + e as u64, + flags.map_or(desc.flags, |f| desc.rw_flags(f)), + desc.flags, + token, ) - }; - scheme.kreadoff( - desc.number, - UserSlice::wo(c, d)?, - e as u64, - flags.map_or(desc.flags, |f| desc.rw_flags(f)), - desc.flags, - token, - ) - }), + })?; + let current = context::current(); + let mut guard = current.write(token.token()); + guard.io_rchar = guard.io_rchar.saturating_add(bytes as u64); + guard.io_syscr = guard.io_syscr.saturating_add(1); + guard.io_read_bytes = guard.io_read_bytes.saturating_add(bytes as u64); + Ok(bytes) + } SYS_READ => sys_read(fd, UserSlice::wo(c, d)?, token), SYS_FPATH => file_op_generic(fd, token, |scheme, number, token| { scheme.kfpath(number, UserSlice::wo(c, d)?, token)