feat(xencall): improve asynchronous support

This commit is contained in:
Alex Zenla 2024-12-14 17:59:07 -05:00
parent d7affe6c8c
commit 895b84e22d
No known key found for this signature in database
GPG Key ID: 067B238899B51269
3 changed files with 59 additions and 32 deletions

View File

@ -1,5 +1,7 @@
use std::io;
use tokio::task::JoinError;
#[derive(thiserror::Error, Debug)]
pub enum Error {
#[error("version of xen is not supported")]
@ -16,6 +18,8 @@ pub enum Error {
MmapBatchFailed(nix::errno::Errno),
#[error("specified value is too long")]
ValueTooLong,
#[error("failed to join async task: {0}")]
JoinError(JoinError),
}
pub type Result<T> = std::result::Result<T, Error>;

View File

@ -35,7 +35,6 @@ use sys::{
XEN_SYSCTL_PHYSINFO, XEN_SYSCTL_PM_OP, XEN_SYSCTL_PM_OP_DISABLE_TURBO,
XEN_SYSCTL_PM_OP_ENABLE_TURBO, XEN_SYSCTL_PM_OP_SET_CPUFREQ_GOV, XEN_SYSCTL_READCONSOLE,
};
use tokio::sync::Semaphore;
use tokio::time::sleep;
use std::fs::{File, OpenOptions};
@ -46,7 +45,6 @@ use std::slice;
#[derive(Clone)]
pub struct XenCall {
pub handle: Arc<File>,
semaphore: Arc<Semaphore>,
domctl_interface_version: u32,
sysctl_interface_version: u32,
}
@ -62,7 +60,6 @@ impl XenCall {
let sysctl_interface_version = XenCall::detect_sysctl_interface_version(&handle)?;
Ok(XenCall {
handle: Arc::new(handle),
semaphore: Arc::new(Semaphore::new(1)),
domctl_interface_version,
sysctl_interface_version,
})
@ -119,7 +116,6 @@ impl XenCall {
}
pub async fn mmap(&self, addr: u64, len: u64) -> Option<u64> {
let _permit = self.semaphore.acquire().await.ok()?;
trace!(
"call fd={} mmap addr={:#x} len={}",
self.handle.as_raw_fd(),
@ -127,14 +123,20 @@ impl XenCall {
len
);
unsafe {
let ptr = mmap(
addr as *mut c_void,
len as usize,
PROT_READ | PROT_WRITE,
MAP_SHARED,
self.handle.as_raw_fd(),
0,
);
let handle = self.handle.clone();
let ptr = tokio::task::spawn_blocking(move || {
mmap(
addr as *mut c_void,
len as usize,
PROT_READ | PROT_WRITE,
MAP_SHARED,
handle.as_raw_fd(),
0,
) as u64
})
.await
.map_err(Error::JoinError)
.ok()? as *mut c_void;
if ptr == MAP_FAILED {
None
} else {
@ -151,18 +153,22 @@ impl XenCall {
}
pub async fn hypercall(&self, op: c_ulong, arg: [c_ulong; 5]) -> Result<c_long> {
let _permit = self.semaphore.acquire().await?;
trace!(
"call fd={} hypercall op={:#x} arg={:?}",
self.handle.as_raw_fd(),
op,
arg
);
unsafe {
let handle = self.handle.clone();
tokio::task::spawn_blocking(move || unsafe {
let mut call = Hypercall { op, arg };
let result = sys::hypercall(self.handle.as_raw_fd(), &mut call)?;
Ok(result as c_long)
}
sys::hypercall(handle.as_raw_fd(), &mut call)
.map(|x| x as c_long)
.map_err(|e| e.into())
})
.await
.map_err(Error::JoinError)?
}
pub async fn hypercall0(&self, op: c_ulong) -> Result<c_long> {
@ -234,18 +240,21 @@ impl XenCall {
num: u64,
addr: u64,
) -> Result<()> {
let _permit = self.semaphore.acquire().await?;
let mut resource = MmapResource {
dom: domid as u16,
typ,
id,
idx,
num,
addr,
};
unsafe {
sys::mmap_resource(self.handle.as_raw_fd(), &mut resource)?;
}
let handle = self.handle.clone();
tokio::task::spawn_blocking(move || {
let mut resource = MmapResource {
dom: domid as u16,
typ,
id,
idx,
num,
addr,
};
unsafe { sys::mmap_resource(handle.as_raw_fd(), &mut resource) }
})
.await
.map_err(Error::JoinError)??;
Ok(())
}
@ -256,7 +265,6 @@ impl XenCall {
addr: u64,
mfns: Vec<u64>,
) -> Result<c_long> {
let _permit = self.semaphore.acquire().await?;
trace!(
"call fd={} mmap_batch domid={} num={} addr={:#x} mfns={:?}",
self.handle.as_raw_fd(),
@ -322,7 +330,7 @@ impl XenCall {
break;
}
let count = result.unwrap();
let count = result?;
if count <= 0 {
break;
}
@ -330,7 +338,7 @@ impl XenCall {
return Ok(paged as c_long);
}
Ok(result.unwrap() as c_long)
Ok(result? as c_long)
}
}
@ -618,6 +626,11 @@ impl XenCall {
}
pub async fn get_memory_map(&self, max_entries: u32) -> Result<Vec<E820Entry>> {
trace!(
"fd={} get_memory_map max_entries={}",
self.handle.as_raw_fd(),
max_entries,
);
let mut memory_map = MemoryMap {
count: max_entries,
buffer: 0,

View File

@ -205,6 +205,16 @@ pub const XEN_DOMCTL_GDBSX_PAUSEVCPU: u32 = 1001;
pub const XEN_DOMCTL_GDBSX_UNPAUSEVCPU: u32 = 1002;
pub const XEN_DOMCTL_GDBSX_DOMSTATUS: u32 = 1003;
pub const XEN_DOMINF_DYING: u32 = 1u32 << 0;
pub const XEN_DOMINF_HVM_GUEST: u32 = 1u32 << 1;
pub const XEN_DOMINF_SHUTDOWN: u32 = 1u32 << 2;
pub const XEN_DOMINF_PAUSED: u32 = 1u32 << 3;
pub const XEN_DOMINF_BLOCKED: u32 = 1u32 << 4;
pub const XEN_DOMINF_RUNNING: u32 = 1u32 << 5;
pub const XEN_DOMINF_DEBUGGED: u32 = 1u32 << 6;
pub const XEN_DOMINF_XS_DOMAIN: u32 = 1u32 << 7;
pub const XEN_DOMINF_HAP: u32 = 1u32 << 8;
#[repr(C)]
#[derive(Copy, Clone)]
pub struct DomCtl {