Use IoVec-based reader/writer to refactor network APIs

This commit is contained in:
Jianfeng Jiang
2024-09-11 02:36:24 +00:00
committed by Tate, Hongliang Tian
parent ea8327af0f
commit 985813c7f9
24 changed files with 484 additions and 453 deletions

View File

@ -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;
}

View File

@ -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)

View File

@ -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

View File

@ -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() {

View File

@ -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 _))
}

View File

@ -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 _))
}