vhost_kern: add IOTLB message support

Implement VhostIotlbBackend trait for vhost_kern handling both
vhost_msg and vhost_msg_v2 messages according to acked backend
features.

Signed-off-by: Stefano Garzarella <sgarzare@redhat.com>
This commit is contained in:
Stefano Garzarella 2021-03-23 16:26:25 +01:00 committed by Jiang Liu
parent a2bc456bed
commit 58680d5826

View file

@ -11,15 +11,18 @@
//! communicate with userspace applications. This sub module provides ioctl based interfaces to
//! control the in-kernel net, scsi, vsock vhost drivers.
use std::mem;
use std::os::unix::io::{AsRawFd, RawFd};
use libc::{c_void, ssize_t, write};
use vm_memory::{Address, GuestAddress, GuestAddressSpace, GuestMemory, GuestUsize};
use vmm_sys_util::eventfd::EventFd;
use vmm_sys_util::ioctl::{ioctl, ioctl_with_mut_ref, ioctl_with_ptr, ioctl_with_ref};
use super::{
Error, Result, VhostBackend, VhostUserDirtyLogRegion, VhostUserMemoryRegionInfo,
VringConfigData, VHOST_MAX_MEMORY_REGIONS,
Error, Result, VhostBackend, VhostIotlbBackend, VhostIotlbMsg, VhostIotlbMsgParser,
VhostUserDirtyLogRegion, VhostUserMemoryRegionInfo, VringConfigData, VHOST_MAX_MEMORY_REGIONS,
};
pub mod vhost_binding;
@ -37,6 +40,15 @@ fn ioctl_result<T>(rc: i32, res: T) -> Result<T> {
}
}
#[inline]
fn io_result<T>(rc: isize, res: T) -> Result<T> {
if rc < 0 {
Err(Error::IOError(std::io::Error::last_os_error()))
} else {
Ok(res)
}
}
/// Represent an in-kernel vhost device backend.
pub trait VhostKernBackend: AsRawFd {
/// Associated type to access guest memory.
@ -314,4 +326,114 @@ pub trait VhostKernFeatures: Sized + AsRawFd {
ioctl_result(ret, ())
}
}
}
/// Handle IOTLB messeges for in-kernel vhost device backend.
impl<I: VhostKernBackend + VhostKernFeatures> VhostIotlbBackend for I {
/// Send an IOTLB message to the in-kernel vhost backend.
///
/// # Arguments
/// * `msg` - IOTLB message to send.
fn send_iotlb_msg(&self, msg: &VhostIotlbMsg) -> Result<()> {
let ret: ssize_t;
if self.get_backend_features_acked() & (1 << VHOST_BACKEND_F_IOTLB_MSG_V2) != 0 {
let mut msg_v2 = vhost_msg_v2 {
type_: VHOST_IOTLB_MSG_V2,
..Default::default()
};
msg_v2.__bindgen_anon_1.iotlb.iova = msg.iova;
msg_v2.__bindgen_anon_1.iotlb.size = msg.size;
msg_v2.__bindgen_anon_1.iotlb.uaddr = msg.userspace_addr;
msg_v2.__bindgen_anon_1.iotlb.perm = msg.perm as u8;
msg_v2.__bindgen_anon_1.iotlb.type_ = msg.msg_type as u8;
ret = unsafe {
write(
self.as_raw_fd(),
&msg_v2 as *const vhost_msg_v2 as *const c_void,
mem::size_of::<vhost_msg_v2>(),
)
};
} else {
let mut msg_v1 = vhost_msg {
type_: VHOST_IOTLB_MSG,
..Default::default()
};
msg_v1.__bindgen_anon_1.iotlb.iova = msg.iova;
msg_v1.__bindgen_anon_1.iotlb.size = msg.size;
msg_v1.__bindgen_anon_1.iotlb.uaddr = msg.userspace_addr;
msg_v1.__bindgen_anon_1.iotlb.perm = msg.perm as u8;
msg_v1.__bindgen_anon_1.iotlb.type_ = msg.msg_type as u8;
ret = unsafe {
write(
self.as_raw_fd(),
&msg_v1 as *const vhost_msg as *const c_void,
mem::size_of::<vhost_msg>(),
)
};
}
io_result(ret, ())
}
/// Parse a buffer received from the in-kernel vhost backend and fill a VhostIotlbMsg.
///
/// # Arguments
/// * `buffer` - Buffer containing the raw data received from the in-kernel vhost backend.
/// * `msg` - IOTLB message parsed.
fn parse_iotlb_msg<T: Sized + VhostIotlbMsgParser>(
&self,
buffer: &T,
msg: &mut VhostIotlbMsg,
) -> Result<()> {
buffer.parse(msg)
}
}
impl VhostIotlbMsgParser for vhost_msg {
fn parse(&self, msg: &mut VhostIotlbMsg) -> Result<()> {
if self.type_ != VHOST_IOTLB_MSG {
return Err(Error::InvalidIotlbMsg);
}
unsafe {
if self.__bindgen_anon_1.iotlb.type_ == 0 {
return Err(Error::InvalidIotlbMsg);
}
msg.iova = self.__bindgen_anon_1.iotlb.iova;
msg.size = self.__bindgen_anon_1.iotlb.size;
msg.userspace_addr = self.__bindgen_anon_1.iotlb.uaddr;
msg.perm = mem::transmute(self.__bindgen_anon_1.iotlb.perm);
msg.msg_type = mem::transmute(self.__bindgen_anon_1.iotlb.type_);
}
Ok(())
}
}
impl VhostIotlbMsgParser for vhost_msg_v2 {
fn parse(&self, msg: &mut VhostIotlbMsg) -> Result<()> {
if self.type_ != VHOST_IOTLB_MSG_V2 {
return Err(Error::InvalidIotlbMsg);
}
unsafe {
if self.__bindgen_anon_1.iotlb.type_ == 0 {
return Err(Error::InvalidIotlbMsg);
}
msg.iova = self.__bindgen_anon_1.iotlb.iova;
msg.size = self.__bindgen_anon_1.iotlb.size;
msg.userspace_addr = self.__bindgen_anon_1.iotlb.uaddr;
msg.perm = mem::transmute(self.__bindgen_anon_1.iotlb.perm);
msg.msg_type = mem::transmute(self.__bindgen_anon_1.iotlb.type_);
}
Ok(())
}
}