mirror of
https://github.com/asterinas/asterinas.git
synced 2025-06-09 13:26:48 +00:00
Add and refactor read-write syscalls
This commit is contained in:
parent
e8a3e00dec
commit
12db7ec55d
@ -38,8 +38,8 @@ provided by Linux on x86-64 architecture.
|
|||||||
| 15 | rt_sigreturn | ✅ |
|
| 15 | rt_sigreturn | ✅ |
|
||||||
| 16 | ioctl | ✅ |
|
| 16 | ioctl | ✅ |
|
||||||
| 17 | pread64 | ✅ |
|
| 17 | pread64 | ✅ |
|
||||||
| 18 | pwrite64 | ❌ |
|
| 18 | pwrite64 | ✅ |
|
||||||
| 19 | readv | ❌ |
|
| 19 | readv | ✅ |
|
||||||
| 20 | writev | ✅ |
|
| 20 | writev | ✅ |
|
||||||
| 21 | access | ✅ |
|
| 21 | access | ✅ |
|
||||||
| 22 | pipe | ✅ |
|
| 22 | pipe | ✅ |
|
||||||
@ -315,8 +315,8 @@ provided by Linux on x86-64 architecture.
|
|||||||
| 292 | dup3 | ✅ |
|
| 292 | dup3 | ✅ |
|
||||||
| 293 | pipe2 | ✅ |
|
| 293 | pipe2 | ✅ |
|
||||||
| 294 | inotify_init1 | ❌ |
|
| 294 | inotify_init1 | ❌ |
|
||||||
| 295 | preadv | ❌ |
|
| 295 | preadv | ✅ |
|
||||||
| 296 | pwritev | ❌ |
|
| 296 | pwritev | ✅ |
|
||||||
| 297 | rt_tgsigqueueinfo | ❌ |
|
| 297 | rt_tgsigqueueinfo | ❌ |
|
||||||
| 298 | perf_event_open | ❌ |
|
| 298 | perf_event_open | ❌ |
|
||||||
| 299 | recvmmsg | ❌ |
|
| 299 | recvmmsg | ❌ |
|
||||||
@ -336,6 +336,8 @@ provided by Linux on x86-64 architecture.
|
|||||||
| 313 | finit_module | ❌ |
|
| 313 | finit_module | ❌ |
|
||||||
| 318 | getrandom | ✅ |
|
| 318 | getrandom | ✅ |
|
||||||
| 322 | execveat | ✅ |
|
| 322 | execveat | ✅ |
|
||||||
|
| 327 | preadv2 | ✅ |
|
||||||
|
| 328 | pwritev2 | ✅ |
|
||||||
| 435 | clone3 | ✅ |
|
| 435 | clone3 | ✅ |
|
||||||
|
|
||||||
## File Systems
|
## File Systems
|
||||||
|
@ -32,7 +32,7 @@ pub trait FileLike: Send + Sync + Any {
|
|||||||
///
|
///
|
||||||
/// [`read`]: FileLike::read
|
/// [`read`]: FileLike::read
|
||||||
fn read_at(&self, offset: usize, buf: &mut [u8]) -> Result<usize> {
|
fn read_at(&self, offset: usize, buf: &mut [u8]) -> Result<usize> {
|
||||||
return_errno_with_message!(Errno::EINVAL, "read_at is not supported");
|
return_errno_with_message!(Errno::ESPIPE, "read_at is not supported");
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Write at the given file offset.
|
/// Write at the given file offset.
|
||||||
@ -43,7 +43,7 @@ pub trait FileLike: Send + Sync + Any {
|
|||||||
///
|
///
|
||||||
/// [`write`]: FileLike::write
|
/// [`write`]: FileLike::write
|
||||||
fn write_at(&self, offset: usize, buf: &[u8]) -> Result<usize> {
|
fn write_at(&self, offset: usize, buf: &[u8]) -> Result<usize> {
|
||||||
return_errno_with_message!(Errno::EINVAL, "write_at is not supported");
|
return_errno_with_message!(Errno::ESPIPE, "write_at is not supported");
|
||||||
}
|
}
|
||||||
|
|
||||||
fn ioctl(&self, cmd: IoctlCmd, arg: usize) -> Result<i32> {
|
fn ioctl(&self, cmd: IoctlCmd, arg: usize) -> Result<i32> {
|
||||||
|
@ -66,7 +66,10 @@ use crate::syscall::{
|
|||||||
poll::sys_poll,
|
poll::sys_poll,
|
||||||
prctl::sys_prctl,
|
prctl::sys_prctl,
|
||||||
pread64::sys_pread64,
|
pread64::sys_pread64,
|
||||||
|
preadv::{sys_preadv, sys_preadv2, sys_readv},
|
||||||
prlimit64::sys_prlimit64,
|
prlimit64::sys_prlimit64,
|
||||||
|
pwrite64::sys_pwrite64,
|
||||||
|
pwritev::{sys_pwritev, sys_pwritev2, sys_writev},
|
||||||
read::sys_read,
|
read::sys_read,
|
||||||
readlink::{sys_readlink, sys_readlinkat},
|
readlink::{sys_readlink, sys_readlinkat},
|
||||||
recvfrom::sys_recvfrom,
|
recvfrom::sys_recvfrom,
|
||||||
@ -121,7 +124,6 @@ use crate::syscall::{
|
|||||||
wait4::sys_wait4,
|
wait4::sys_wait4,
|
||||||
waitid::sys_waitid,
|
waitid::sys_waitid,
|
||||||
write::sys_write,
|
write::sys_write,
|
||||||
writev::sys_writev,
|
|
||||||
};
|
};
|
||||||
|
|
||||||
impl_syscall_nums_and_dispatch_fn! {
|
impl_syscall_nums_and_dispatch_fn! {
|
||||||
@ -143,6 +145,8 @@ impl_syscall_nums_and_dispatch_fn! {
|
|||||||
SYS_RT_SIGRETURN = 15 => sys_rt_sigreturn(args[..0], &mut context);
|
SYS_RT_SIGRETURN = 15 => sys_rt_sigreturn(args[..0], &mut context);
|
||||||
SYS_IOCTL = 16 => sys_ioctl(args[..3]);
|
SYS_IOCTL = 16 => sys_ioctl(args[..3]);
|
||||||
SYS_PREAD64 = 17 => sys_pread64(args[..4]);
|
SYS_PREAD64 = 17 => sys_pread64(args[..4]);
|
||||||
|
SYS_PWRITE64 = 18 => sys_pwrite64(args[..4]);
|
||||||
|
SYS_READV = 19 => sys_readv(args[..3]);
|
||||||
SYS_WRITEV = 20 => sys_writev(args[..3]);
|
SYS_WRITEV = 20 => sys_writev(args[..3]);
|
||||||
SYS_ACCESS = 21 => sys_access(args[..2]);
|
SYS_ACCESS = 21 => sys_access(args[..2]);
|
||||||
SYS_PIPE = 22 => sys_pipe(args[..1]);
|
SYS_PIPE = 22 => sys_pipe(args[..1]);
|
||||||
@ -282,8 +286,12 @@ impl_syscall_nums_and_dispatch_fn! {
|
|||||||
SYS_EPOLL_CREATE1 = 291 => sys_epoll_create1(args[..1]);
|
SYS_EPOLL_CREATE1 = 291 => sys_epoll_create1(args[..1]);
|
||||||
SYS_DUP3 = 292 => sys_dup3(args[..3]);
|
SYS_DUP3 = 292 => sys_dup3(args[..3]);
|
||||||
SYS_PIPE2 = 293 => sys_pipe2(args[..2]);
|
SYS_PIPE2 = 293 => sys_pipe2(args[..2]);
|
||||||
|
SYS_PREADV = 295 => sys_preadv(args[..4]);
|
||||||
|
SYS_PWRITEV = 296 => sys_pwritev(args[..4]);
|
||||||
SYS_PRLIMIT64 = 302 => sys_prlimit64(args[..4]);
|
SYS_PRLIMIT64 = 302 => sys_prlimit64(args[..4]);
|
||||||
SYS_GETRANDOM = 318 => sys_getrandom(args[..3]);
|
SYS_GETRANDOM = 318 => sys_getrandom(args[..3]);
|
||||||
SYS_EXECVEAT = 322 => sys_execveat(args[..5], &mut context);
|
SYS_EXECVEAT = 322 => sys_execveat(args[..5], &mut context);
|
||||||
|
SYS_PREADV2 = 327 => sys_preadv2(args[..5]);
|
||||||
|
SYS_PWRITEV2 = 328 => sys_pwritev2(args[..5]);
|
||||||
SYS_CLONE3 = 435 => sys_clone3(args[..2], &context);
|
SYS_CLONE3 = 435 => sys_clone3(args[..2], &context);
|
||||||
}
|
}
|
||||||
|
@ -73,7 +73,10 @@ mod pipe;
|
|||||||
mod poll;
|
mod poll;
|
||||||
mod prctl;
|
mod prctl;
|
||||||
mod pread64;
|
mod pread64;
|
||||||
|
mod preadv;
|
||||||
mod prlimit64;
|
mod prlimit64;
|
||||||
|
mod pwrite64;
|
||||||
|
mod pwritev;
|
||||||
mod read;
|
mod read;
|
||||||
mod readlink;
|
mod readlink;
|
||||||
mod recvfrom;
|
mod recvfrom;
|
||||||
@ -128,7 +131,6 @@ mod utimens;
|
|||||||
mod wait4;
|
mod wait4;
|
||||||
mod waitid;
|
mod waitid;
|
||||||
mod write;
|
mod write;
|
||||||
mod writev;
|
|
||||||
|
|
||||||
/// This macro is used to define syscall handler.
|
/// This macro is used to define syscall handler.
|
||||||
/// The first param is ths number of parameters,
|
/// The first param is ths number of parameters,
|
||||||
|
@ -1,29 +1,39 @@
|
|||||||
// SPDX-License-Identifier: MPL-2.0
|
// SPDX-License-Identifier: MPL-2.0
|
||||||
|
|
||||||
use super::SyscallReturn;
|
use super::SyscallReturn;
|
||||||
use crate::{
|
use crate::{fs::file_table::FileDesc, prelude::*, util::write_bytes_to_user};
|
||||||
fs::{file_table::FileDesc, utils::SeekFrom},
|
|
||||||
prelude::*,
|
|
||||||
util::write_bytes_to_user,
|
|
||||||
};
|
|
||||||
|
|
||||||
pub fn sys_pread64(fd: FileDesc, buf_ptr: Vaddr, count: usize, pos: i64) -> Result<SyscallReturn> {
|
pub fn sys_pread64(
|
||||||
|
fd: FileDesc,
|
||||||
|
user_buf_ptr: Vaddr,
|
||||||
|
user_buf_len: usize,
|
||||||
|
offset: i64,
|
||||||
|
) -> Result<SyscallReturn> {
|
||||||
debug!(
|
debug!(
|
||||||
"fd = {}, buf = 0x{:x}, count = 0x{:x}, pos = 0x{:x}",
|
"fd = {}, buf = 0x{:x}, user_buf_len = 0x{:x}, offset = 0x{:x}",
|
||||||
fd, buf_ptr, count, pos
|
fd, user_buf_ptr, user_buf_len, offset
|
||||||
);
|
);
|
||||||
|
|
||||||
let current = current!();
|
if offset < 0 {
|
||||||
let file_table = current.file_table().lock();
|
return_errno_with_message!(Errno::EINVAL, "offset cannot be negative");
|
||||||
let file = file_table.get_file(fd)?;
|
}
|
||||||
|
let file = {
|
||||||
let seek_from = SeekFrom::Start(pos as usize);
|
let current = current!();
|
||||||
file.seek(seek_from)?;
|
let filetable = current.file_table().lock();
|
||||||
|
filetable.get_file(fd)?.clone()
|
||||||
|
};
|
||||||
|
// TODO: Check (f.file->f_mode & FMODE_PREAD); We don't have f_mode in our FileLike trait
|
||||||
|
if user_buf_len == 0 {
|
||||||
|
return Ok(SyscallReturn::Return(0));
|
||||||
|
}
|
||||||
|
if offset.checked_add(user_buf_len as i64).is_none() {
|
||||||
|
return_errno_with_message!(Errno::EINVAL, "offset + user_buf_len overflow");
|
||||||
|
}
|
||||||
|
|
||||||
let read_len = {
|
let read_len = {
|
||||||
let mut buffer = vec![0u8; count];
|
let mut buffer = vec![0u8; user_buf_len];
|
||||||
let read_len = file.read(&mut buffer)?;
|
let read_len = file.read_at(offset as usize, &mut buffer)?;
|
||||||
write_bytes_to_user(buf_ptr, &buffer)?;
|
write_bytes_to_user(user_buf_ptr, &buffer)?;
|
||||||
read_len
|
read_len
|
||||||
};
|
};
|
||||||
|
|
||||||
|
171
kernel/aster-nix/src/syscall/preadv.rs
Normal file
171
kernel/aster-nix/src/syscall/preadv.rs
Normal file
@ -0,0 +1,171 @@
|
|||||||
|
// SPDX-License-Identifier: MPL-2.0
|
||||||
|
|
||||||
|
use super::SyscallReturn;
|
||||||
|
use crate::{
|
||||||
|
fs::file_table::FileDesc,
|
||||||
|
prelude::*,
|
||||||
|
util::{copy_iovs_from_user, IoVec},
|
||||||
|
};
|
||||||
|
|
||||||
|
pub fn sys_readv(fd: FileDesc, io_vec_ptr: Vaddr, io_vec_count: usize) -> Result<SyscallReturn> {
|
||||||
|
let res = do_sys_readv(fd, io_vec_ptr, io_vec_count)?;
|
||||||
|
Ok(SyscallReturn::Return(res as _))
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn sys_preadv(
|
||||||
|
fd: FileDesc,
|
||||||
|
io_vec_ptr: Vaddr,
|
||||||
|
io_vec_count: usize,
|
||||||
|
offset: i64,
|
||||||
|
) -> Result<SyscallReturn> {
|
||||||
|
let res = do_sys_preadv(fd, io_vec_ptr, io_vec_count, offset, RWFFlag::empty())?;
|
||||||
|
Ok(SyscallReturn::Return(res as _))
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn sys_preadv2(
|
||||||
|
fd: FileDesc,
|
||||||
|
io_vec_ptr: Vaddr,
|
||||||
|
io_vec_count: usize,
|
||||||
|
offset: i64,
|
||||||
|
flags: u32,
|
||||||
|
) -> Result<SyscallReturn> {
|
||||||
|
let flags = match RWFFlag::from_bits(flags) {
|
||||||
|
Some(flags) => flags,
|
||||||
|
None => return_errno_with_message!(Errno::EINVAL, "invalid flags"),
|
||||||
|
};
|
||||||
|
let res = if offset == -1 {
|
||||||
|
do_sys_readv(fd, io_vec_ptr, io_vec_count)?
|
||||||
|
} else {
|
||||||
|
do_sys_preadv(fd, io_vec_ptr, io_vec_count, offset, flags)?
|
||||||
|
};
|
||||||
|
Ok(SyscallReturn::Return(res as _))
|
||||||
|
}
|
||||||
|
|
||||||
|
fn do_sys_preadv(
|
||||||
|
fd: FileDesc,
|
||||||
|
io_vec_ptr: Vaddr,
|
||||||
|
io_vec_count: usize,
|
||||||
|
offset: i64,
|
||||||
|
_flags: RWFFlag,
|
||||||
|
) -> Result<usize> {
|
||||||
|
debug!(
|
||||||
|
"preadv: fd = {}, io_vec_ptr = 0x{:x}, io_vec_counter = 0x{:x}, offset = 0x{:x}",
|
||||||
|
fd, io_vec_ptr, io_vec_count, offset
|
||||||
|
);
|
||||||
|
|
||||||
|
if offset < 0 {
|
||||||
|
return_errno_with_message!(Errno::EINVAL, "offset cannot be negative");
|
||||||
|
}
|
||||||
|
|
||||||
|
let file = {
|
||||||
|
let current = current!();
|
||||||
|
let filetable = current.file_table().lock();
|
||||||
|
filetable.get_file(fd)?.clone()
|
||||||
|
};
|
||||||
|
|
||||||
|
if io_vec_count == 0 {
|
||||||
|
return Ok(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Calculate the total buffer length and check for overflow
|
||||||
|
let total_len = io_vec_count
|
||||||
|
.checked_mul(core::mem::size_of::<IoVec>())
|
||||||
|
.and_then(|val| val.checked_add(offset as usize));
|
||||||
|
if total_len.is_none() {
|
||||||
|
return_errno_with_message!(Errno::EINVAL, "offset + io_vec_count overflow");
|
||||||
|
}
|
||||||
|
|
||||||
|
let mut total_len: usize = 0;
|
||||||
|
let mut cur_offset = offset as usize;
|
||||||
|
|
||||||
|
let io_vecs = copy_iovs_from_user(io_vec_ptr, io_vec_count)?;
|
||||||
|
for io_vec in io_vecs.as_ref() {
|
||||||
|
if io_vec.is_empty() {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if total_len.checked_add(io_vec.len()).is_none()
|
||||||
|
|| total_len
|
||||||
|
.checked_add(io_vec.len())
|
||||||
|
.and_then(|sum| sum.checked_add(cur_offset))
|
||||||
|
.is_none()
|
||||||
|
|| total_len
|
||||||
|
.checked_add(io_vec.len())
|
||||||
|
.and_then(|sum| sum.checked_add(cur_offset))
|
||||||
|
.map(|sum| sum > isize::MAX as usize)
|
||||||
|
.unwrap_or(false)
|
||||||
|
{
|
||||||
|
return_errno_with_message!(Errno::EINVAL, "Total length overflow");
|
||||||
|
}
|
||||||
|
|
||||||
|
let mut buffer = vec![0u8; io_vec.len()];
|
||||||
|
|
||||||
|
// TODO: According to the man page
|
||||||
|
// at <https://man7.org/linux/man-pages/man2/readv.2.html>,
|
||||||
|
// readv must be atomic,
|
||||||
|
// but the current implementation does not ensure atomicity.
|
||||||
|
// A suitable fix would be to add a `readv` method for the `FileLike` trait,
|
||||||
|
// allowing each subsystem to implement atomicity.
|
||||||
|
let read_len = file.read_at(cur_offset, &mut buffer)?;
|
||||||
|
io_vec.write_exact_to_user(&buffer)?;
|
||||||
|
total_len += read_len;
|
||||||
|
cur_offset += read_len;
|
||||||
|
if read_len == 0 || read_len < buffer.len() {
|
||||||
|
// End of file reached or no more data to read
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(total_len)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn do_sys_readv(fd: FileDesc, io_vec_ptr: Vaddr, io_vec_count: usize) -> Result<usize> {
|
||||||
|
debug!(
|
||||||
|
"fd = {}, io_vec_ptr = 0x{:x}, io_vec_counter = 0x{:x}",
|
||||||
|
fd, io_vec_ptr, io_vec_count
|
||||||
|
);
|
||||||
|
|
||||||
|
let file = {
|
||||||
|
let current = current!();
|
||||||
|
let filetable = current.file_table().lock();
|
||||||
|
filetable.get_file(fd)?.clone()
|
||||||
|
};
|
||||||
|
|
||||||
|
if io_vec_count == 0 {
|
||||||
|
return Ok(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
let mut total_len = 0;
|
||||||
|
|
||||||
|
let io_vecs = copy_iovs_from_user(io_vec_ptr, io_vec_count)?;
|
||||||
|
for io_vec in io_vecs.as_ref() {
|
||||||
|
if io_vec.is_empty() {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
let mut buffer = vec![0u8; io_vec.len()];
|
||||||
|
// TODO: According to the man page
|
||||||
|
// at <https://man7.org/linux/man-pages/man2/readv.2.html>,
|
||||||
|
// readv must be atomic,
|
||||||
|
// but the current implementation does not ensure atomicity.
|
||||||
|
// A suitable fix would be to add a `readv` method for the `FileLike` trait,
|
||||||
|
// allowing each subsystem to implement atomicity.
|
||||||
|
let read_len = file.read(&mut buffer)?;
|
||||||
|
io_vec.write_exact_to_user(&buffer)?;
|
||||||
|
total_len += read_len;
|
||||||
|
if read_len == 0 || read_len < buffer.len() {
|
||||||
|
// End of file reached or no more data to read
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(total_len)
|
||||||
|
}
|
||||||
|
|
||||||
|
bitflags! {
|
||||||
|
struct RWFFlag: u32 {
|
||||||
|
const RWF_DSYNC = 0x00000001;
|
||||||
|
const RWF_HIPRI = 0x00000002;
|
||||||
|
const RWF_SYNC = 0x00000004;
|
||||||
|
const RWF_NOWAIT = 0x00000008;
|
||||||
|
}
|
||||||
|
}
|
36
kernel/aster-nix/src/syscall/pwrite64.rs
Normal file
36
kernel/aster-nix/src/syscall/pwrite64.rs
Normal file
@ -0,0 +1,36 @@
|
|||||||
|
// SPDX-License-Identifier: MPL-2.0
|
||||||
|
|
||||||
|
use super::SyscallReturn;
|
||||||
|
use crate::{fs::file_table::FileDesc, prelude::*, util::read_bytes_from_user};
|
||||||
|
|
||||||
|
pub fn sys_pwrite64(
|
||||||
|
fd: FileDesc,
|
||||||
|
user_buf_ptr: Vaddr,
|
||||||
|
user_buf_len: usize,
|
||||||
|
offset: i64,
|
||||||
|
) -> Result<SyscallReturn> {
|
||||||
|
debug!(
|
||||||
|
"fd = {}, user_buf_ptr = 0x{:x}, user_buf_len = 0x{:x}, offset = 0x{:x}",
|
||||||
|
fd, user_buf_ptr, user_buf_len, offset
|
||||||
|
);
|
||||||
|
if offset < 0 {
|
||||||
|
return_errno_with_message!(Errno::EINVAL, "offset cannot be negative");
|
||||||
|
}
|
||||||
|
let file = {
|
||||||
|
let current = current!();
|
||||||
|
let filetable = current.file_table().lock();
|
||||||
|
filetable.get_file(fd)?.clone()
|
||||||
|
};
|
||||||
|
// TODO: Check (f.file->f_mode & FMODE_PWRITE); We don't have f_mode in our FileLike trait
|
||||||
|
if user_buf_len == 0 {
|
||||||
|
return Ok(SyscallReturn::Return(0));
|
||||||
|
}
|
||||||
|
if offset.checked_add(user_buf_len as i64).is_none() {
|
||||||
|
return_errno_with_message!(Errno::EINVAL, "offset + user_buf_len overflow");
|
||||||
|
}
|
||||||
|
|
||||||
|
let mut buffer = vec![0u8; user_buf_len];
|
||||||
|
read_bytes_from_user(user_buf_ptr, &mut buffer)?;
|
||||||
|
let write_len = file.write_at(offset as _, &buffer)?;
|
||||||
|
Ok(SyscallReturn::Return(write_len as _))
|
||||||
|
}
|
149
kernel/aster-nix/src/syscall/pwritev.rs
Normal file
149
kernel/aster-nix/src/syscall/pwritev.rs
Normal file
@ -0,0 +1,149 @@
|
|||||||
|
// SPDX-License-Identifier: MPL-2.0
|
||||||
|
|
||||||
|
use super::SyscallReturn;
|
||||||
|
use crate::{fs::file_table::FileDesc, prelude::*, util::copy_iovs_from_user};
|
||||||
|
|
||||||
|
pub fn sys_writev(fd: FileDesc, io_vec_ptr: Vaddr, io_vec_count: usize) -> Result<SyscallReturn> {
|
||||||
|
let res = do_sys_writev(fd, io_vec_ptr, io_vec_count)?;
|
||||||
|
Ok(SyscallReturn::Return(res as _))
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn sys_pwritev(
|
||||||
|
fd: FileDesc,
|
||||||
|
io_vec_ptr: Vaddr,
|
||||||
|
io_vec_count: usize,
|
||||||
|
offset: i64,
|
||||||
|
) -> Result<SyscallReturn> {
|
||||||
|
let res = do_sys_pwritev(fd, io_vec_ptr, io_vec_count, offset, RWFFlag::empty())?;
|
||||||
|
Ok(SyscallReturn::Return(res as _))
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn sys_pwritev2(
|
||||||
|
fd: FileDesc,
|
||||||
|
io_vec_ptr: Vaddr,
|
||||||
|
io_vec_count: usize,
|
||||||
|
offset: i64,
|
||||||
|
flags: u32,
|
||||||
|
) -> Result<SyscallReturn> {
|
||||||
|
let flags = match RWFFlag::from_bits(flags) {
|
||||||
|
Some(flags) => flags,
|
||||||
|
None => return_errno_with_message!(Errno::EINVAL, "invalid flags"),
|
||||||
|
};
|
||||||
|
let res = if offset == -1 {
|
||||||
|
do_sys_writev(fd, io_vec_ptr, io_vec_count)?
|
||||||
|
} else {
|
||||||
|
do_sys_pwritev(fd, io_vec_ptr, io_vec_count, offset, flags)?
|
||||||
|
};
|
||||||
|
Ok(SyscallReturn::Return(res as _))
|
||||||
|
}
|
||||||
|
|
||||||
|
fn do_sys_pwritev(
|
||||||
|
fd: FileDesc,
|
||||||
|
io_vec_ptr: Vaddr,
|
||||||
|
io_vec_count: usize,
|
||||||
|
offset: i64,
|
||||||
|
_flags: RWFFlag,
|
||||||
|
) -> Result<usize> {
|
||||||
|
// TODO: Implement flags support
|
||||||
|
debug!(
|
||||||
|
"fd = {}, io_vec_ptr = 0x{:x}, io_vec_counter = 0x{:x}, offset = 0x{:x}",
|
||||||
|
fd, io_vec_ptr, io_vec_count, offset
|
||||||
|
);
|
||||||
|
if offset < 0 {
|
||||||
|
return_errno_with_message!(Errno::EINVAL, "offset cannot be negative");
|
||||||
|
}
|
||||||
|
let file = {
|
||||||
|
let current = current!();
|
||||||
|
let filetable = current.file_table().lock();
|
||||||
|
filetable.get_file(fd)?.clone()
|
||||||
|
};
|
||||||
|
// TODO: Check (f.file->f_mode & FMODE_PREAD); We don't have f_mode in our FileLike trait
|
||||||
|
if io_vec_count == 0 {
|
||||||
|
return Ok(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
let mut total_len: usize = 0;
|
||||||
|
let mut cur_offset = offset as usize;
|
||||||
|
|
||||||
|
let io_vecs = copy_iovs_from_user(io_vec_ptr, io_vec_count)?;
|
||||||
|
for io_vec in io_vecs.as_ref() {
|
||||||
|
if io_vec.is_empty() {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if total_len.checked_add(io_vec.len()).is_none()
|
||||||
|
|| total_len
|
||||||
|
.checked_add(io_vec.len())
|
||||||
|
.and_then(|sum| sum.checked_add(cur_offset))
|
||||||
|
.is_none()
|
||||||
|
|| total_len
|
||||||
|
.checked_add(io_vec.len())
|
||||||
|
.and_then(|sum| sum.checked_add(cur_offset))
|
||||||
|
.map(|sum| sum > isize::MAX as usize)
|
||||||
|
.unwrap_or(false)
|
||||||
|
{
|
||||||
|
return_errno_with_message!(Errno::EINVAL, "Total length overflow");
|
||||||
|
}
|
||||||
|
|
||||||
|
let buffer = {
|
||||||
|
let mut buffer = vec![0u8; io_vec.len()];
|
||||||
|
io_vec.read_exact_from_user(&mut buffer)?;
|
||||||
|
buffer
|
||||||
|
};
|
||||||
|
|
||||||
|
// TODO: According to the man page
|
||||||
|
// at <https://man7.org/linux/man-pages/man2/readv.2.html>,
|
||||||
|
// writev must be atomic,
|
||||||
|
// but the current implementation does not ensure atomicity.
|
||||||
|
// A suitable fix would be to add a `writev` method for the `FileLike` trait,
|
||||||
|
// allowing each subsystem to implement atomicity.
|
||||||
|
let write_len = file.write_at(cur_offset, &buffer)?;
|
||||||
|
total_len += write_len;
|
||||||
|
cur_offset += write_len;
|
||||||
|
}
|
||||||
|
Ok(total_len)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn do_sys_writev(fd: FileDesc, io_vec_ptr: Vaddr, io_vec_count: usize) -> Result<usize> {
|
||||||
|
debug!(
|
||||||
|
"fd = {}, io_vec_ptr = 0x{:x}, io_vec_counter = 0x{:x}",
|
||||||
|
fd, io_vec_ptr, io_vec_count
|
||||||
|
);
|
||||||
|
let file = {
|
||||||
|
let current = current!();
|
||||||
|
let filetable = current.file_table().lock();
|
||||||
|
filetable.get_file(fd)?.clone()
|
||||||
|
};
|
||||||
|
let mut total_len = 0;
|
||||||
|
|
||||||
|
let io_vecs = copy_iovs_from_user(io_vec_ptr, io_vec_count)?;
|
||||||
|
for io_vec in io_vecs.as_ref() {
|
||||||
|
if io_vec.is_empty() {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
let buffer = {
|
||||||
|
let mut buffer = vec![0u8; io_vec.len()];
|
||||||
|
io_vec.read_exact_from_user(&mut buffer)?;
|
||||||
|
buffer
|
||||||
|
};
|
||||||
|
|
||||||
|
// TODO: According to the man page
|
||||||
|
// at <https://man7.org/linux/man-pages/man2/readv.2.html>,
|
||||||
|
// writev must be atomic,
|
||||||
|
// but the current implementation does not ensure atomicity.
|
||||||
|
// A suitable fix would be to add a `writev` method for the `FileLike` trait,
|
||||||
|
// allowing each subsystem to implement atomicity.
|
||||||
|
let write_len = file.write(&buffer)?;
|
||||||
|
total_len += write_len;
|
||||||
|
}
|
||||||
|
Ok(total_len)
|
||||||
|
}
|
||||||
|
|
||||||
|
bitflags! {
|
||||||
|
struct RWFFlag: u32 {
|
||||||
|
const RWF_DSYNC = 0x00000001;
|
||||||
|
const RWF_HIPRI = 0x00000002;
|
||||||
|
const RWF_SYNC = 0x00000004;
|
||||||
|
const RWF_NOWAIT = 0x00000008;
|
||||||
|
}
|
||||||
|
}
|
@ -1,48 +0,0 @@
|
|||||||
// SPDX-License-Identifier: MPL-2.0
|
|
||||||
|
|
||||||
#![allow(dead_code)]
|
|
||||||
|
|
||||||
use super::SyscallReturn;
|
|
||||||
use crate::{fs::file_table::FileDesc, prelude::*, util::copy_iovs_from_user};
|
|
||||||
|
|
||||||
pub fn sys_writev(fd: FileDesc, io_vec_ptr: Vaddr, io_vec_count: usize) -> Result<SyscallReturn> {
|
|
||||||
let res = do_sys_writev(fd, io_vec_ptr, io_vec_count)?;
|
|
||||||
Ok(SyscallReturn::Return(res as _))
|
|
||||||
}
|
|
||||||
|
|
||||||
fn do_sys_writev(fd: FileDesc, io_vec_ptr: Vaddr, io_vec_count: usize) -> Result<usize> {
|
|
||||||
debug!(
|
|
||||||
"fd = {}, io_vec_ptr = 0x{:x}, io_vec_counter = 0x{:x}",
|
|
||||||
fd, io_vec_ptr, io_vec_count
|
|
||||||
);
|
|
||||||
let file = {
|
|
||||||
let current = current!();
|
|
||||||
let filetable = current.file_table().lock();
|
|
||||||
filetable.get_file(fd)?.clone()
|
|
||||||
};
|
|
||||||
|
|
||||||
let mut total_len = 0;
|
|
||||||
|
|
||||||
let io_vecs = copy_iovs_from_user(io_vec_ptr, io_vec_count)?;
|
|
||||||
for io_vec in io_vecs.as_ref() {
|
|
||||||
if io_vec.is_empty() {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
let buffer = {
|
|
||||||
let mut buffer = vec![0u8; io_vec.len()];
|
|
||||||
io_vec.read_exact_from_user(&mut buffer)?;
|
|
||||||
buffer
|
|
||||||
};
|
|
||||||
|
|
||||||
// FIXME: According to the man page
|
|
||||||
// at <https://man7.org/linux/man-pages/man2/readv.2.html>,
|
|
||||||
// writev must be atomic,
|
|
||||||
// but the current implementation does not ensure atomicity.
|
|
||||||
// A suitable fix would be to add a `writev` method for the `FileLike` trait,
|
|
||||||
// allowing each subsystem to implement atomicity.
|
|
||||||
let write_len = file.write(&buffer)?;
|
|
||||||
total_len += write_len;
|
|
||||||
}
|
|
||||||
Ok(total_len)
|
|
||||||
}
|
|
@ -24,19 +24,13 @@ TESTS ?= \
|
|||||||
mount_test \
|
mount_test \
|
||||||
open_create_test \
|
open_create_test \
|
||||||
open_test \
|
open_test \
|
||||||
|
pread64_test \
|
||||||
|
preadv2_test \
|
||||||
|
pwrite64_test \
|
||||||
|
pwritev2_test \
|
||||||
pty_test \
|
pty_test \
|
||||||
read_test \
|
read_test \
|
||||||
rename_test \
|
readv_test \
|
||||||
sendfile_test \
|
|
||||||
stat_test \
|
|
||||||
statfs_test \
|
|
||||||
symlink_test \
|
|
||||||
sync_test \
|
|
||||||
timers_test \
|
|
||||||
truncate_test \
|
|
||||||
uidgid_test \
|
|
||||||
unlink_test \
|
|
||||||
vdso_clock_gettime_test \
|
|
||||||
write_test \
|
write_test \
|
||||||
utimes_test \
|
utimes_test \
|
||||||
# The end of the list
|
# The end of the list
|
||||||
|
@ -1,3 +1,2 @@
|
|||||||
EventfdTest.IllegalPwrite
|
|
||||||
EventfdTest.SpliceFromPipePartialSucceeds
|
EventfdTest.SpliceFromPipePartialSucceeds
|
||||||
EventfdTest.NotifyNonZero_NoRandomSave
|
EventfdTest.NotifyNonZero_NoRandomSave
|
1
regression/syscall_test/blocklists/pread64_test
Normal file
1
regression/syscall_test/blocklists/pread64_test
Normal file
@ -0,0 +1 @@
|
|||||||
|
Pread64Test.Overflow
|
3
regression/syscall_test/blocklists/preadv2_test
Normal file
3
regression/syscall_test/blocklists/preadv2_test
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
Preadv2Test.TestInvalidFlag
|
||||||
|
Preadv2Test.TestUnreadableFile
|
||||||
|
Preadv2Test.TestUnseekableFileInvalid
|
1
regression/syscall_test/blocklists/pwritev2_test
Normal file
1
regression/syscall_test/blocklists/pwritev2_test
Normal file
@ -0,0 +1 @@
|
|||||||
|
Pwritev2Test.InvalidFlag
|
5
regression/syscall_test/blocklists/readv_test
Normal file
5
regression/syscall_test/blocklists/readv_test
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
ReadvTest.BadIovecBase_File
|
||||||
|
ReadvTest.BadIovecBase_Pipe
|
||||||
|
ReadvTest.NotReadable_Pipe
|
||||||
|
ReadvTest.IovecOutsideTaskAddressRangeInNonemptyArray
|
||||||
|
ReadvTestNoFixture.TruncatedAtMax_NoRandomSave
|
Loading…
x
Reference in New Issue
Block a user