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.
This commit is contained in:
2026-07-08 22:02:33 +03:00
parent 28c65bfcfb
commit 2cc512a3b9
+55 -39
View File
@@ -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)