mirror of
https://github.com/asterinas/asterinas.git
synced 2025-06-23 09:23:25 +00:00
Use IoVec-based reader/writer to refactor network APIs
This commit is contained in:
committed by
Tate, Hongliang Tian
parent
ea8327af0f
commit
985813c7f9
@ -4,7 +4,7 @@ use super::SyscallReturn;
|
||||
use crate::{
|
||||
fs::file_table::FileDesc,
|
||||
prelude::*,
|
||||
util::{copy_iovs_from_user, IoVec},
|
||||
util::{MultiWrite, VmWriterArray},
|
||||
};
|
||||
|
||||
pub fn sys_readv(
|
||||
@ -74,29 +74,23 @@ fn do_sys_preadv(
|
||||
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() {
|
||||
let mut writer_array = VmWriterArray::from_user_io_vecs(ctx, io_vec_ptr, io_vec_count)?;
|
||||
for writer in writer_array.writers_mut() {
|
||||
if !writer.has_avail() {
|
||||
continue;
|
||||
}
|
||||
if total_len.checked_add(io_vec.len()).is_none()
|
||||
|
||||
let writer_len = writer.sum_lens();
|
||||
if total_len.checked_add(writer_len).is_none()
|
||||
|| total_len
|
||||
.checked_add(io_vec.len())
|
||||
.checked_add(writer_len)
|
||||
.and_then(|sum| sum.checked_add(cur_offset))
|
||||
.is_none()
|
||||
|| total_len
|
||||
.checked_add(io_vec.len())
|
||||
.checked_add(writer_len)
|
||||
.and_then(|sum| sum.checked_add(cur_offset))
|
||||
.map(|sum| sum > isize::MAX as usize)
|
||||
.unwrap_or(false)
|
||||
@ -104,19 +98,16 @@ fn do_sys_preadv(
|
||||
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_bytes_at(cur_offset, &mut buffer)?;
|
||||
io_vec.write_exact_to_user(&buffer)?;
|
||||
let read_len = file.read_at(cur_offset, writer)?;
|
||||
total_len += read_len;
|
||||
cur_offset += read_len;
|
||||
if read_len == 0 || read_len < buffer.len() {
|
||||
if read_len == 0 || writer.has_avail() {
|
||||
// End of file reached or no more data to read
|
||||
break;
|
||||
}
|
||||
@ -147,23 +138,21 @@ fn do_sys_readv(
|
||||
|
||||
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() {
|
||||
let mut writer_array = VmWriterArray::from_user_io_vecs(ctx, io_vec_ptr, io_vec_count)?;
|
||||
for writer in writer_array.writers_mut() {
|
||||
if !writer.has_avail() {
|
||||
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_bytes(&mut buffer)?;
|
||||
io_vec.write_exact_to_user(&buffer)?;
|
||||
let read_len = file.read(writer)?;
|
||||
total_len += read_len;
|
||||
if read_len == 0 || read_len < buffer.len() {
|
||||
if read_len == 0 || writer.has_avail() {
|
||||
// End of file reached or no more data to read
|
||||
break;
|
||||
}
|
||||
|
@ -1,7 +1,7 @@
|
||||
// SPDX-License-Identifier: MPL-2.0
|
||||
|
||||
use super::SyscallReturn;
|
||||
use crate::{fs::file_table::FileDesc, prelude::*, util::copy_iovs_from_user};
|
||||
use crate::{fs::file_table::FileDesc, prelude::*, util::VmReaderArray};
|
||||
|
||||
pub fn sys_writev(
|
||||
fd: FileDesc,
|
||||
@ -72,18 +72,20 @@ fn do_sys_pwritev(
|
||||
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() {
|
||||
let mut reader_array = VmReaderArray::from_user_io_vecs(ctx, io_vec_ptr, io_vec_count)?;
|
||||
for reader in reader_array.readers_mut() {
|
||||
if !reader.has_remain() {
|
||||
continue;
|
||||
}
|
||||
if total_len.checked_add(io_vec.len()).is_none()
|
||||
|
||||
let reader_len = reader.remain();
|
||||
if total_len.checked_add(reader_len).is_none()
|
||||
|| total_len
|
||||
.checked_add(io_vec.len())
|
||||
.checked_add(reader_len)
|
||||
.and_then(|sum| sum.checked_add(cur_offset))
|
||||
.is_none()
|
||||
|| total_len
|
||||
.checked_add(io_vec.len())
|
||||
.checked_add(reader_len)
|
||||
.and_then(|sum| sum.checked_add(cur_offset))
|
||||
.map(|sum| sum > isize::MAX as usize)
|
||||
.unwrap_or(false)
|
||||
@ -91,19 +93,13 @@ fn do_sys_pwritev(
|
||||
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_bytes_at(cur_offset, &buffer)?;
|
||||
let write_len = file.write_at(cur_offset, reader)?;
|
||||
total_len += write_len;
|
||||
cur_offset += write_len;
|
||||
}
|
||||
@ -126,25 +122,19 @@ fn do_sys_writev(
|
||||
};
|
||||
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() {
|
||||
let mut reader_array = VmReaderArray::from_user_io_vecs(ctx, io_vec_ptr, io_vec_count)?;
|
||||
for reader in reader_array.readers_mut() {
|
||||
if !reader.has_remain() {
|
||||
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_bytes(&buffer)?;
|
||||
let write_len = file.write(reader)?;
|
||||
total_len += write_len;
|
||||
}
|
||||
Ok(total_len)
|
||||
|
@ -5,10 +5,7 @@ use crate::{
|
||||
fs::file_table::FileDesc,
|
||||
net::socket::SendRecvFlags,
|
||||
prelude::*,
|
||||
util::{
|
||||
net::{get_socket_from_fd, write_socket_addr_to_user},
|
||||
IoVec,
|
||||
},
|
||||
util::net::{get_socket_from_fd, write_socket_addr_to_user},
|
||||
};
|
||||
|
||||
pub fn sys_recvfrom(
|
||||
@ -18,15 +15,19 @@ pub fn sys_recvfrom(
|
||||
flags: i32,
|
||||
src_addr: Vaddr,
|
||||
addrlen_ptr: Vaddr,
|
||||
_ctx: &Context,
|
||||
ctx: &Context,
|
||||
) -> Result<SyscallReturn> {
|
||||
let flags = SendRecvFlags::from_bits_truncate(flags);
|
||||
debug!("sockfd = {sockfd}, buf = 0x{buf:x}, len = {len}, flags = {flags:?}, src_addr = 0x{src_addr:x}, addrlen_ptr = 0x{addrlen_ptr:x}");
|
||||
|
||||
let socket = get_socket_from_fd(sockfd)?;
|
||||
|
||||
let io_vecs = [IoVec::new(buf, len)];
|
||||
let (recv_size, message_header) = socket.recvmsg(&io_vecs, flags)?;
|
||||
let mut writers = {
|
||||
let vm_space = ctx.process.root_vmar().vm_space();
|
||||
vm_space.writer(buf, len)?
|
||||
};
|
||||
|
||||
let (recv_size, message_header) = socket.recvmsg(&mut writers, flags)?;
|
||||
|
||||
if let Some(socket_addr) = message_header.addr()
|
||||
&& src_addr != 0
|
||||
|
@ -24,8 +24,8 @@ pub fn sys_recvmsg(
|
||||
|
||||
let (total_bytes, message_header) = {
|
||||
let socket = get_socket_from_fd(sockfd)?;
|
||||
let io_vecs = c_user_msghdr.copy_iovs_from_user()?;
|
||||
socket.recvmsg(&io_vecs, flags)?
|
||||
let mut io_vec_writer = c_user_msghdr.copy_writer_array_from_user(ctx)?;
|
||||
socket.recvmsg(&mut io_vec_writer, flags)?
|
||||
};
|
||||
|
||||
if let Some(addr) = message_header.addr() {
|
||||
|
@ -24,9 +24,9 @@ pub fn sys_sendmsg(
|
||||
|
||||
let socket = get_socket_from_fd(sockfd)?;
|
||||
|
||||
let (io_vecs, message_header) = {
|
||||
let (mut io_vec_reader, message_header) = {
|
||||
let addr = c_user_msghdr.read_socket_addr_from_user()?;
|
||||
let io_vecs = c_user_msghdr.copy_iovs_from_user()?;
|
||||
let io_vec_reader = c_user_msghdr.copy_reader_array_from_user(ctx)?;
|
||||
|
||||
let control_message = {
|
||||
if c_user_msghdr.msg_control != 0 {
|
||||
@ -36,10 +36,10 @@ pub fn sys_sendmsg(
|
||||
None
|
||||
};
|
||||
|
||||
(io_vecs, MessageHeader::new(addr, control_message))
|
||||
(io_vec_reader, MessageHeader::new(addr, control_message))
|
||||
};
|
||||
|
||||
let total_bytes = socket.sendmsg(&io_vecs, message_header, flags)?;
|
||||
let total_bytes = socket.sendmsg(&mut io_vec_reader, message_header, flags)?;
|
||||
|
||||
Ok(SyscallReturn::Return(total_bytes as _))
|
||||
}
|
||||
|
@ -5,10 +5,7 @@ use crate::{
|
||||
fs::file_table::FileDesc,
|
||||
net::socket::{MessageHeader, SendRecvFlags},
|
||||
prelude::*,
|
||||
util::{
|
||||
net::{get_socket_from_fd, read_socket_addr_from_user},
|
||||
IoVec,
|
||||
},
|
||||
util::net::{get_socket_from_fd, read_socket_addr_from_user},
|
||||
};
|
||||
|
||||
pub fn sys_sendto(
|
||||
@ -18,7 +15,7 @@ pub fn sys_sendto(
|
||||
flags: i32,
|
||||
dest_addr: Vaddr,
|
||||
addrlen: usize,
|
||||
_ctx: &Context,
|
||||
ctx: &Context,
|
||||
) -> Result<SyscallReturn> {
|
||||
let flags = SendRecvFlags::from_bits_truncate(flags);
|
||||
let socket_addr = if dest_addr == 0 {
|
||||
@ -31,10 +28,13 @@ pub fn sys_sendto(
|
||||
|
||||
let socket = get_socket_from_fd(sockfd)?;
|
||||
|
||||
let io_vecs = [IoVec::new(buf, len)];
|
||||
let message_header = MessageHeader::new(socket_addr, None);
|
||||
|
||||
let send_size = socket.sendmsg(&io_vecs, message_header, flags)?;
|
||||
let mut reader = {
|
||||
let vm_space = ctx.process.root_vmar().vm_space();
|
||||
vm_space.reader(buf, len)?
|
||||
};
|
||||
let send_size = socket.sendmsg(&mut reader, message_header, flags)?;
|
||||
|
||||
Ok(SyscallReturn::Return(send_size as _))
|
||||
}
|
||||
|
Reference in New Issue
Block a user