Add syscall sendmmsg
This commit is contained in:
parent
899e32c452
commit
a0042f7d28
|
|
@ -15,7 +15,7 @@ support the loading of Linux kernel modules.
|
|||
## System Calls
|
||||
|
||||
At the time of writing,
|
||||
Asterinas supports over 225 Linux system calls for the x86-64 architecture,
|
||||
Asterinas supports over 226 Linux system calls for the x86-64 architecture,
|
||||
which are summarized in the table below.
|
||||
|
||||
| Numbers | Names | Supported | Flag Coverage |
|
||||
|
|
@ -327,7 +327,7 @@ which are summarized in the table below.
|
|||
| 304 | open_by_handle_at | ❌ | N/A |
|
||||
| 305 | clock_adjtime | ❌ | N/A |
|
||||
| 306 | syncfs | ❌ | N/A |
|
||||
| 307 | sendmmsg | ❌ | N/A |
|
||||
| 307 | sendmmsg | ✅ | [⚠️](syscall-flag-coverage/networking-and-sockets/#sendto-and-sendmsg) |
|
||||
| 308 | setns | ✅ | ❓ |
|
||||
| 309 | getcpu | ✅ | 💯 |
|
||||
| 310 | process_vm_readv | ❌ | N/A |
|
||||
|
|
|
|||
|
|
@ -59,7 +59,7 @@ see [the man page](https://man7.org/linux/man-pages/man2/connect.2.html).
|
|||
|
||||
## Socket Communication
|
||||
|
||||
### `sendto` and `sendmsg`
|
||||
### `sendto`, `sendmsg` and `sendmmsg`
|
||||
|
||||
Supported functionality in SCML:
|
||||
|
||||
|
|
|
|||
|
|
@ -3,6 +3,17 @@ struct sockaddr = {
|
|||
..
|
||||
};
|
||||
|
||||
struct msg_hdr = {
|
||||
msg_name = <sockaddr>,
|
||||
msg_control = NULL,
|
||||
..
|
||||
};
|
||||
|
||||
struct mmsg_hdr = {
|
||||
hdr = <msg_hdr>,
|
||||
msg_len
|
||||
};
|
||||
|
||||
// Send message on a socket
|
||||
sendto(
|
||||
sockfd, buf, len,
|
||||
|
|
@ -14,10 +25,15 @@ sendto(
|
|||
// Send message using scatter-gather buffers and ancillary data
|
||||
sendmsg(
|
||||
sockfd,
|
||||
msg = {
|
||||
msg_name = <sockaddr>,
|
||||
msg_control = NULL,
|
||||
..
|
||||
},
|
||||
msg = <msg_hdr>,
|
||||
flags = 0
|
||||
);
|
||||
|
||||
|
||||
// Send multiple messages on a socket
|
||||
sendmmsg(
|
||||
sockfd,
|
||||
mmsgs = [ <mmsg_hdr> ],
|
||||
mmsg_count,
|
||||
flags = 0
|
||||
);
|
||||
|
|
|
|||
|
|
@ -109,6 +109,7 @@ use super::{
|
|||
semget::sys_semget,
|
||||
semop::{sys_semop, sys_semtimedop},
|
||||
sendfile::sys_sendfile,
|
||||
sendmmsg::sys_sendmmsg,
|
||||
sendmsg::sys_sendmsg,
|
||||
sendto::sys_sendto,
|
||||
set_ioprio::sys_ioprio_set,
|
||||
|
|
@ -339,6 +340,7 @@ impl_syscall_nums_and_dispatch_fn! {
|
|||
SYS_WAIT4 = 260 => sys_wait4(args[..4]);
|
||||
SYS_PRLIMIT64 = 261 => sys_prlimit64(args[..4]);
|
||||
SYS_SETNS = 268 => sys_setns(args[..2]);
|
||||
SYS_SENDMMSG = 269 => sys_sendmmsg(args[..4]);
|
||||
SYS_SCHED_SETATTR = 274 => sys_sched_setattr(args[..3]);
|
||||
SYS_SCHED_GETATTR = 275 => sys_sched_getattr(args[..4]);
|
||||
SYS_RENAMEAT2 = 276 => sys_renameat2(args[..5]);
|
||||
|
|
|
|||
|
|
@ -109,6 +109,7 @@ use super::{
|
|||
semget::sys_semget,
|
||||
semop::{sys_semop, sys_semtimedop},
|
||||
sendfile::sys_sendfile,
|
||||
sendmmsg::sys_sendmmsg,
|
||||
sendmsg::sys_sendmsg,
|
||||
sendto::sys_sendto,
|
||||
set_ioprio::sys_ioprio_set,
|
||||
|
|
@ -341,6 +342,7 @@ impl_syscall_nums_and_dispatch_fn! {
|
|||
SYS_WAIT4 = 260 => sys_wait4(args[..4]);
|
||||
SYS_PRLIMIT64 = 261 => sys_prlimit64(args[..4]);
|
||||
SYS_SETNS = 268 => sys_setns(args[..2]);
|
||||
SYS_SENDMMSG = 269 => sys_sendmmsg(args[..4]);
|
||||
SYS_SCHED_SETATTR = 274 => sys_sched_setattr(args[..3]);
|
||||
SYS_SCHED_GETATTR = 275 => sys_sched_getattr(args[..4]);
|
||||
SYS_RENAMEAT2 = 276 => sys_renameat2(args[..5]);
|
||||
|
|
|
|||
|
|
@ -120,6 +120,7 @@ use super::{
|
|||
semget::sys_semget,
|
||||
semop::{sys_semop, sys_semtimedop},
|
||||
sendfile::sys_sendfile,
|
||||
sendmmsg::sys_sendmmsg,
|
||||
sendmsg::sys_sendmsg,
|
||||
sendto::sys_sendto,
|
||||
set_ioprio::sys_ioprio_set,
|
||||
|
|
@ -388,6 +389,7 @@ impl_syscall_nums_and_dispatch_fn! {
|
|||
SYS_PREADV = 295 => sys_preadv(args[..5]);
|
||||
SYS_PWRITEV = 296 => sys_pwritev(args[..5]);
|
||||
SYS_PRLIMIT64 = 302 => sys_prlimit64(args[..4]);
|
||||
SYS_SENDMMSG = 307 => sys_sendmmsg(args[..4]);
|
||||
SYS_SETNS = 308 => sys_setns(args[..2]);
|
||||
SYS_GETCPU = 309 => sys_getcpu(args[..3]);
|
||||
SYS_SCHED_SETATTR = 314 => sys_sched_setattr(args[..3]);
|
||||
|
|
|
|||
|
|
@ -132,6 +132,7 @@ mod semctl;
|
|||
mod semget;
|
||||
mod semop;
|
||||
mod sendfile;
|
||||
mod sendmmsg;
|
||||
mod sendmsg;
|
||||
mod sendto;
|
||||
mod set_ioprio;
|
||||
|
|
|
|||
|
|
@ -47,7 +47,7 @@ pub fn sys_recvmsg(
|
|||
|
||||
let control_messages = message_header.control_messages();
|
||||
c_user_msghdr.msg_controllen =
|
||||
c_user_msghdr.write_control_messages_to_user(control_messages, &user_space)?;
|
||||
c_user_msghdr.write_control_messages_to_user(control_messages, &user_space)? as _;
|
||||
|
||||
user_space.write_val(user_msghdr_ptr, &c_user_msghdr)?;
|
||||
|
||||
|
|
|
|||
|
|
@ -0,0 +1,77 @@
|
|||
// SPDX-License-Identifier: MPL-2.0
|
||||
|
||||
use crate::{
|
||||
fs::file_table::FileDesc,
|
||||
net::socket::{util::SendRecvFlags, Socket},
|
||||
prelude::*,
|
||||
syscall::{sendmsg::send_one_message, SyscallReturn},
|
||||
util::net::CUserMsgHdr,
|
||||
};
|
||||
|
||||
pub fn sys_sendmmsg(
|
||||
sockfd: FileDesc,
|
||||
mmsghdrs_addr: Vaddr,
|
||||
count: usize,
|
||||
flags: i32,
|
||||
ctx: &Context,
|
||||
) -> Result<SyscallReturn> {
|
||||
let flags = SendRecvFlags::from_bits(flags)
|
||||
.ok_or_else(|| Error::with_message(Errno::EINVAL, "invalid send recv flags"))?;
|
||||
|
||||
debug!(
|
||||
"sockfd = {}, mmsghdrs = {:#x}, count = {}, flags = {:?}",
|
||||
sockfd, mmsghdrs_addr, count, flags
|
||||
);
|
||||
|
||||
if !flags.is_empty() {
|
||||
warn!("sendmmsg flags {:?} are not supported", flags);
|
||||
}
|
||||
|
||||
let file = {
|
||||
// Reading control messages may access the file table,
|
||||
// so we have to clone the file and drop the file table reference here.
|
||||
let file_table = ctx.thread_local.borrow_file_table();
|
||||
let file_table_locked = file_table.unwrap().read();
|
||||
file_table_locked.get_file(sockfd)?.clone()
|
||||
};
|
||||
let socket = file.as_socket_or_err()?;
|
||||
|
||||
let mut sent_msgs = 0;
|
||||
match send_mmsg_hdrs(socket, mmsghdrs_addr, count, flags, &mut sent_msgs, ctx) {
|
||||
// Only return error if no packets are sent successfully.
|
||||
Err(e) if sent_msgs == 0 => Err(e),
|
||||
_ => Ok(SyscallReturn::Return(sent_msgs as _)),
|
||||
}
|
||||
}
|
||||
|
||||
#[repr(C)]
|
||||
#[derive(Debug, Clone, Copy, Pod)]
|
||||
struct CMmsgHdr {
|
||||
msg_hdr: CUserMsgHdr,
|
||||
msg_len: u32,
|
||||
}
|
||||
|
||||
fn send_mmsg_hdrs(
|
||||
socket: &dyn Socket,
|
||||
mmsghdrs_addr: Vaddr,
|
||||
count: usize,
|
||||
flags: SendRecvFlags,
|
||||
sent_msgs: &mut usize,
|
||||
ctx: &Context,
|
||||
) -> Result<()> {
|
||||
let user_space = ctx.user_space();
|
||||
|
||||
for i in 0..count {
|
||||
let addr = mmsghdrs_addr + core::mem::size_of::<CMmsgHdr>() * i;
|
||||
let mut mmsghdr = user_space.read_val::<CMmsgHdr>(addr)?;
|
||||
|
||||
let sent_bytes = send_one_message(socket, &mmsghdr.msg_hdr, &user_space, flags)?;
|
||||
|
||||
mmsghdr.msg_len = sent_bytes as u32;
|
||||
user_space.write_val(addr, &mmsghdr)?;
|
||||
|
||||
*sent_msgs += 1;
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
|
@ -2,8 +2,11 @@
|
|||
|
||||
use super::SyscallReturn;
|
||||
use crate::{
|
||||
fs::file_table::{get_file_fast, FileDesc},
|
||||
net::socket::util::{MessageHeader, SendRecvFlags},
|
||||
fs::file_table::FileDesc,
|
||||
net::socket::{
|
||||
util::{MessageHeader, SendRecvFlags},
|
||||
Socket,
|
||||
},
|
||||
prelude::*,
|
||||
util::net::CUserMsgHdr,
|
||||
};
|
||||
|
|
@ -23,26 +26,38 @@ pub fn sys_sendmsg(
|
|||
sockfd, c_user_msghdr, flags
|
||||
);
|
||||
|
||||
let message_header = {
|
||||
let addr = c_user_msghdr.read_socket_addr_from_user()?;
|
||||
// Reading control messages may access the file table, so it should be called before
|
||||
// `borrow_file_table_mut`.
|
||||
let control_messages = c_user_msghdr.read_control_messages_from_user(&user_space)?;
|
||||
MessageHeader::new(addr, control_messages)
|
||||
let file = {
|
||||
// Reading control messages may access the file table,
|
||||
// so we have to clone the file and drop the file table reference here.
|
||||
let file_table = ctx.thread_local.borrow_file_table();
|
||||
let file_table_locked = file_table.unwrap().read();
|
||||
file_table_locked.get_file(sockfd)?.clone()
|
||||
};
|
||||
let mut io_vec_reader = c_user_msghdr.copy_reader_array_from_user(&user_space)?;
|
||||
|
||||
let mut file_table = ctx.thread_local.borrow_file_table_mut();
|
||||
let file = get_file_fast!(&mut file_table, sockfd);
|
||||
let socket = file.as_socket_or_err()?;
|
||||
|
||||
let total_bytes = socket
|
||||
let total_bytes = send_one_message(socket, &c_user_msghdr, &user_space, flags)?;
|
||||
|
||||
Ok(SyscallReturn::Return(total_bytes as _))
|
||||
}
|
||||
|
||||
pub(super) fn send_one_message(
|
||||
socket: &dyn Socket,
|
||||
c_user_msghdr: &CUserMsgHdr,
|
||||
user_space: &CurrentUserSpace,
|
||||
flags: SendRecvFlags,
|
||||
) -> Result<usize> {
|
||||
let message_header = {
|
||||
let addr = c_user_msghdr.read_socket_addr_from_user()?;
|
||||
let control_messages = c_user_msghdr.read_control_messages_from_user(user_space)?;
|
||||
MessageHeader::new(addr, control_messages)
|
||||
};
|
||||
let mut io_vec_reader = c_user_msghdr.copy_reader_array_from_user(user_space)?;
|
||||
|
||||
socket
|
||||
.sendmsg(&mut io_vec_reader, message_header, flags)
|
||||
.map_err(|err| match err.error() {
|
||||
// FIXME: `sendmsg` should not be restarted if a timeout has been set on the socket using `setsockopt`.
|
||||
Errno::EINTR => Error::new(Errno::ERESTARTSYS),
|
||||
_ => err,
|
||||
})?;
|
||||
|
||||
Ok(SyscallReturn::Return(total_bytes as _))
|
||||
})
|
||||
}
|
||||
|
|
|
|||
|
|
@ -87,11 +87,11 @@ pub struct CUserMsgHdr {
|
|||
/// Scatter/Gather iov array
|
||||
pub msg_iov: Vaddr,
|
||||
/// The # of elements in msg_iov
|
||||
pub msg_iovlen: u32,
|
||||
pub msg_iovlen: usize,
|
||||
/// Ancillary data
|
||||
pub msg_control: Vaddr,
|
||||
/// Ancillary data buffer length
|
||||
pub msg_controllen: u32,
|
||||
pub msg_controllen: usize,
|
||||
/// Flags on received message
|
||||
pub msg_flags: u32,
|
||||
}
|
||||
|
|
@ -129,7 +129,7 @@ impl CUserMsgHdr {
|
|||
return Ok(Vec::new());
|
||||
}
|
||||
|
||||
let mut reader = user_space.reader(self.msg_control, self.msg_controllen as usize)?;
|
||||
let mut reader = user_space.reader(self.msg_control, self.msg_controllen)?;
|
||||
let control_messages = ControlMessage::read_all_from(&mut reader)?;
|
||||
Ok(control_messages)
|
||||
}
|
||||
|
|
@ -148,7 +148,7 @@ impl CUserMsgHdr {
|
|||
return Ok(0);
|
||||
}
|
||||
|
||||
let mut writer = user_space.writer(self.msg_control, self.msg_controllen as usize)?;
|
||||
let mut writer = user_space.writer(self.msg_control, self.msg_controllen)?;
|
||||
let write_len = ControlMessage::write_all_to(control_messages, &mut writer) as u32;
|
||||
Ok(write_len)
|
||||
}
|
||||
|
|
@ -157,21 +157,21 @@ impl CUserMsgHdr {
|
|||
&self,
|
||||
user_space: &'a CurrentUserSpace<'a>,
|
||||
) -> Result<VmReaderArray<'a>> {
|
||||
if self.msg_iovlen as usize > MAX_IO_VECTOR_LENGTH {
|
||||
if self.msg_iovlen > MAX_IO_VECTOR_LENGTH {
|
||||
return_errno_with_message!(Errno::EMSGSIZE, "the I/O vector contains too many buffers");
|
||||
}
|
||||
|
||||
VmReaderArray::from_user_io_vecs(user_space, self.msg_iov, self.msg_iovlen as usize)
|
||||
VmReaderArray::from_user_io_vecs(user_space, self.msg_iov, self.msg_iovlen)
|
||||
}
|
||||
|
||||
pub fn copy_writer_array_from_user<'a>(
|
||||
&self,
|
||||
user_space: &'a CurrentUserSpace<'a>,
|
||||
) -> Result<VmWriterArray<'a>> {
|
||||
if self.msg_iovlen as usize > MAX_IO_VECTOR_LENGTH {
|
||||
if self.msg_iovlen > MAX_IO_VECTOR_LENGTH {
|
||||
return_errno_with_message!(Errno::EMSGSIZE, "the I/O vector contains too many buffers");
|
||||
}
|
||||
|
||||
VmWriterArray::from_user_io_vecs(user_space, self.msg_iov, self.msg_iovlen as usize)
|
||||
VmWriterArray::from_user_io_vecs(user_space, self.msg_iov, self.msg_iovlen)
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1324,7 +1324,7 @@ sendfile08_64
|
|||
# sendmsg02
|
||||
# sendmsg03
|
||||
|
||||
sendmmsg01
|
||||
# sendmmsg01
|
||||
sendmmsg02
|
||||
|
||||
# sendto01
|
||||
|
|
|
|||
Loading…
Reference in New Issue