krata: work on parallel reconciliation

This commit is contained in:
Alex Zenla
2024-04-02 00:56:18 +00:00
parent 6a2f1e6517
commit 8dd3cc7692
27 changed files with 582 additions and 428 deletions

View File

@ -18,15 +18,19 @@ use libc::{c_int, mmap, usleep, MAP_FAILED, MAP_SHARED, PROT_READ, PROT_WRITE};
use log::trace;
use nix::errno::Errno;
use std::ffi::{c_long, c_uint, c_ulong, c_void};
use std::sync::Arc;
use sys::{XEN_DOMCTL_MAX_INTERFACE_VERSION, XEN_DOMCTL_MIN_INTERFACE_VERSION};
use tokio::sync::Semaphore;
use std::fs::{File, OpenOptions};
use std::os::fd::AsRawFd;
use std::ptr::addr_of_mut;
use std::slice;
#[derive(Clone)]
pub struct XenCall {
pub handle: File,
pub handle: Arc<File>,
semaphore: Arc<Semaphore>,
domctl_interface_version: u32,
}
@ -39,7 +43,8 @@ impl XenCall {
let domctl_interface_version =
XenCall::detect_domctl_interface_version(&handle, current_domid)?;
Ok(XenCall {
handle,
handle: Arc::new(handle),
semaphore: Arc::new(Semaphore::new(1)),
domctl_interface_version,
})
}
@ -68,7 +73,8 @@ impl XenCall {
Err(Error::XenVersionUnsupported)
}
pub fn mmap(&self, addr: u64, len: u64) -> Option<u64> {
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(),
@ -99,7 +105,8 @@ impl XenCall {
}
}
pub fn hypercall(&self, op: c_ulong, arg: [c_ulong; 5]) -> Result<c_long> {
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(),
@ -113,29 +120,29 @@ impl XenCall {
}
}
pub fn hypercall0(&self, op: c_ulong) -> Result<c_long> {
self.hypercall(op, [0, 0, 0, 0, 0])
pub async fn hypercall0(&self, op: c_ulong) -> Result<c_long> {
self.hypercall(op, [0, 0, 0, 0, 0]).await
}
pub fn hypercall1(&self, op: c_ulong, arg1: c_ulong) -> Result<c_long> {
self.hypercall(op, [arg1, 0, 0, 0, 0])
pub async fn hypercall1(&self, op: c_ulong, arg1: c_ulong) -> Result<c_long> {
self.hypercall(op, [arg1, 0, 0, 0, 0]).await
}
pub fn hypercall2(&self, op: c_ulong, arg1: c_ulong, arg2: c_ulong) -> Result<c_long> {
self.hypercall(op, [arg1, arg2, 0, 0, 0])
pub async fn hypercall2(&self, op: c_ulong, arg1: c_ulong, arg2: c_ulong) -> Result<c_long> {
self.hypercall(op, [arg1, arg2, 0, 0, 0]).await
}
pub fn hypercall3(
pub async fn hypercall3(
&self,
op: c_ulong,
arg1: c_ulong,
arg2: c_ulong,
arg3: c_ulong,
) -> Result<c_long> {
self.hypercall(op, [arg1, arg2, arg3, 0, 0])
self.hypercall(op, [arg1, arg2, arg3, 0, 0]).await
}
pub fn hypercall4(
pub async fn hypercall4(
&self,
op: c_ulong,
arg1: c_ulong,
@ -143,10 +150,10 @@ impl XenCall {
arg3: c_ulong,
arg4: c_ulong,
) -> Result<c_long> {
self.hypercall(op, [arg1, arg2, arg3, arg4, 0])
self.hypercall(op, [arg1, arg2, arg3, arg4, 0]).await
}
pub fn hypercall5(
pub async fn hypercall5(
&self,
op: c_ulong,
arg1: c_ulong,
@ -155,10 +162,10 @@ impl XenCall {
arg4: c_ulong,
arg5: c_ulong,
) -> Result<c_long> {
self.hypercall(op, [arg1, arg2, arg3, arg4, arg5])
self.hypercall(op, [arg1, arg2, arg3, arg4, arg5]).await
}
pub fn multicall(&self, calls: &mut [MultiCallEntry]) -> Result<()> {
pub async fn multicall(&self, calls: &mut [MultiCallEntry]) -> Result<()> {
trace!(
"call fd={} multicall calls={:?}",
self.handle.as_raw_fd(),
@ -168,11 +175,12 @@ impl XenCall {
HYPERVISOR_MULTICALL,
calls.as_mut_ptr() as c_ulong,
calls.len() as c_ulong,
)?;
)
.await?;
Ok(())
}
pub fn map_resource(
pub async fn map_resource(
&self,
domid: u32,
typ: u32,
@ -181,6 +189,7 @@ impl XenCall {
num: u64,
addr: u64,
) -> Result<()> {
let _permit = self.semaphore.acquire().await?;
let mut resource = MmapResource {
dom: domid as u16,
typ,
@ -195,7 +204,14 @@ impl XenCall {
Ok(())
}
pub fn mmap_batch(&self, domid: u32, num: u64, addr: u64, mfns: Vec<u64>) -> Result<c_long> {
pub async fn mmap_batch(
&self,
domid: u32,
num: u64,
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(),
@ -218,7 +234,7 @@ impl XenCall {
let result = sys::mmapbatch(self.handle.as_raw_fd(), &mut batch);
if let Err(errno) = result {
if errno != Errno::ENOENT {
return Err(errno)?;
return Err(Error::MmapBatchFailed(errno))?;
}
usleep(100);
@ -253,7 +269,7 @@ impl XenCall {
let result = sys::mmapbatch(self.handle.as_raw_fd(), &mut batch);
if let Err(n) = result {
if n != Errno::ENOENT {
return Err(n)?;
return Err(Error::MmapBatchFailed(n))?;
}
}
@ -273,7 +289,7 @@ impl XenCall {
}
}
pub fn get_version_capabilities(&self) -> Result<XenCapabilitiesInfo> {
pub async fn get_version_capabilities(&self) -> Result<XenCapabilitiesInfo> {
trace!(
"call fd={} get_version_capabilities",
self.handle.as_raw_fd()
@ -285,26 +301,29 @@ impl XenCall {
HYPERVISOR_XEN_VERSION,
XENVER_CAPABILITIES,
addr_of_mut!(info) as c_ulong,
)?;
)
.await?;
Ok(info)
}
pub fn evtchn_op(&self, cmd: c_int, arg: u64) -> Result<()> {
self.hypercall2(HYPERVISOR_EVENT_CHANNEL_OP, cmd as c_ulong, arg)?;
pub async fn evtchn_op(&self, cmd: c_int, arg: u64) -> Result<()> {
self.hypercall2(HYPERVISOR_EVENT_CHANNEL_OP, cmd as c_ulong, arg)
.await?;
Ok(())
}
pub fn evtchn_alloc_unbound(&self, domid: u32, remote_domid: u32) -> Result<u32> {
pub async fn evtchn_alloc_unbound(&self, domid: u32, remote_domid: u32) -> Result<u32> {
let mut alloc_unbound = EvtChnAllocUnbound {
dom: domid as u16,
remote_dom: remote_domid as u16,
port: 0,
};
self.evtchn_op(6, addr_of_mut!(alloc_unbound) as c_ulong)?;
self.evtchn_op(6, addr_of_mut!(alloc_unbound) as c_ulong)
.await?;
Ok(alloc_unbound.port)
}
pub fn get_domain_info(&self, domid: u32) -> Result<GetDomainInfo> {
pub async fn get_domain_info(&self, domid: u32) -> Result<GetDomainInfo> {
trace!(
"domctl fd={} get_domain_info domid={}",
self.handle.as_raw_fd(),
@ -318,11 +337,12 @@ impl XenCall {
get_domain_info: GetDomainInfo::default(),
},
};
self.hypercall1(HYPERVISOR_DOMCTL, addr_of_mut!(domctl) as c_ulong)?;
self.hypercall1(HYPERVISOR_DOMCTL, addr_of_mut!(domctl) as c_ulong)
.await?;
Ok(unsafe { domctl.value.get_domain_info })
}
pub fn create_domain(&self, create_domain: CreateDomain) -> Result<u32> {
pub async fn create_domain(&self, create_domain: CreateDomain) -> Result<u32> {
trace!(
"domctl fd={} create_domain create_domain={:?}",
self.handle.as_raw_fd(),
@ -334,11 +354,12 @@ impl XenCall {
domid: 0,
value: DomCtlValue { create_domain },
};
self.hypercall1(HYPERVISOR_DOMCTL, addr_of_mut!(domctl) as c_ulong)?;
self.hypercall1(HYPERVISOR_DOMCTL, addr_of_mut!(domctl) as c_ulong)
.await?;
Ok(domctl.domid)
}
pub fn pause_domain(&self, domid: u32) -> Result<()> {
pub async fn pause_domain(&self, domid: u32) -> Result<()> {
trace!(
"domctl fd={} pause_domain domid={:?}",
self.handle.as_raw_fd(),
@ -350,11 +371,12 @@ impl XenCall {
domid,
value: DomCtlValue { pad: [0; 128] },
};
self.hypercall1(HYPERVISOR_DOMCTL, addr_of_mut!(domctl) as c_ulong)?;
self.hypercall1(HYPERVISOR_DOMCTL, addr_of_mut!(domctl) as c_ulong)
.await?;
Ok(())
}
pub fn unpause_domain(&self, domid: u32) -> Result<()> {
pub async fn unpause_domain(&self, domid: u32) -> Result<()> {
trace!(
"domctl fd={} unpause_domain domid={:?}",
self.handle.as_raw_fd(),
@ -366,11 +388,12 @@ impl XenCall {
domid,
value: DomCtlValue { pad: [0; 128] },
};
self.hypercall1(HYPERVISOR_DOMCTL, addr_of_mut!(domctl) as c_ulong)?;
self.hypercall1(HYPERVISOR_DOMCTL, addr_of_mut!(domctl) as c_ulong)
.await?;
Ok(())
}
pub fn set_max_mem(&self, domid: u32, memkb: u64) -> Result<()> {
pub async fn set_max_mem(&self, domid: u32, memkb: u64) -> Result<()> {
trace!(
"domctl fd={} set_max_mem domid={} memkb={}",
self.handle.as_raw_fd(),
@ -385,11 +408,12 @@ impl XenCall {
max_mem: MaxMem { max_memkb: memkb },
},
};
self.hypercall1(HYPERVISOR_DOMCTL, addr_of_mut!(domctl) as c_ulong)?;
self.hypercall1(HYPERVISOR_DOMCTL, addr_of_mut!(domctl) as c_ulong)
.await?;
Ok(())
}
pub fn set_max_vcpus(&self, domid: u32, max_vcpus: u32) -> Result<()> {
pub async fn set_max_vcpus(&self, domid: u32, max_vcpus: u32) -> Result<()> {
trace!(
"domctl fd={} set_max_vcpus domid={} max_vcpus={}",
self.handle.as_raw_fd(),
@ -404,11 +428,12 @@ impl XenCall {
max_cpus: MaxVcpus { max_vcpus },
},
};
self.hypercall1(HYPERVISOR_DOMCTL, addr_of_mut!(domctl) as c_ulong)?;
self.hypercall1(HYPERVISOR_DOMCTL, addr_of_mut!(domctl) as c_ulong)
.await?;
Ok(())
}
pub fn set_address_size(&self, domid: u32, size: u32) -> Result<()> {
pub async fn set_address_size(&self, domid: u32, size: u32) -> Result<()> {
trace!(
"domctl fd={} set_address_size domid={} size={}",
self.handle.as_raw_fd(),
@ -423,11 +448,12 @@ impl XenCall {
address_size: AddressSize { size },
},
};
self.hypercall1(HYPERVISOR_DOMCTL, addr_of_mut!(domctl) as c_ulong)?;
self.hypercall1(HYPERVISOR_DOMCTL, addr_of_mut!(domctl) as c_ulong)
.await?;
Ok(())
}
pub fn get_vcpu_context(&self, domid: u32, vcpu: u32) -> Result<VcpuGuestContext> {
pub async fn get_vcpu_context(&self, domid: u32, vcpu: u32) -> Result<VcpuGuestContext> {
trace!(
"domctl fd={} get_vcpu_context domid={}",
self.handle.as_raw_fd(),
@ -447,11 +473,12 @@ impl XenCall {
},
},
};
self.hypercall1(HYPERVISOR_DOMCTL, addr_of_mut!(domctl) as c_ulong)?;
self.hypercall1(HYPERVISOR_DOMCTL, addr_of_mut!(domctl) as c_ulong)
.await?;
Ok(unsafe { wrapper.value })
}
pub fn set_vcpu_context(
pub async fn set_vcpu_context(
&self,
domid: u32,
vcpu: u32,
@ -476,11 +503,12 @@ impl XenCall {
},
},
};
self.hypercall1(HYPERVISOR_DOMCTL, addr_of_mut!(domctl) as c_ulong)?;
self.hypercall1(HYPERVISOR_DOMCTL, addr_of_mut!(domctl) as c_ulong)
.await?;
Ok(())
}
pub fn get_page_frame_info(&self, domid: u32, frames: &[u64]) -> Result<Vec<u64>> {
pub async fn get_page_frame_info(&self, domid: u32, frames: &[u64]) -> Result<Vec<u64>> {
let mut buffer: Vec<u64> = frames.to_vec();
let mut domctl = DomCtl {
cmd: XEN_DOMCTL_GETPAGEFRAMEINFO3,
@ -493,7 +521,8 @@ impl XenCall {
},
},
};
self.hypercall1(HYPERVISOR_DOMCTL, addr_of_mut!(domctl) as c_ulong)?;
self.hypercall1(HYPERVISOR_DOMCTL, addr_of_mut!(domctl) as c_ulong)
.await?;
let slice = unsafe {
slice::from_raw_parts_mut(
domctl.value.get_page_frame_info.array as *mut u64,
@ -503,7 +532,7 @@ impl XenCall {
Ok(slice.to_vec())
}
pub fn hypercall_init(&self, domid: u32, gmfn: u64) -> Result<()> {
pub async fn hypercall_init(&self, domid: u32, gmfn: u64) -> Result<()> {
trace!(
"domctl fd={} hypercall_init domid={} gmfn={}",
self.handle.as_raw_fd(),
@ -518,11 +547,12 @@ impl XenCall {
hypercall_init: HypercallInit { gmfn },
},
};
self.hypercall1(HYPERVISOR_DOMCTL, addr_of_mut!(domctl) as c_ulong)?;
self.hypercall1(HYPERVISOR_DOMCTL, addr_of_mut!(domctl) as c_ulong)
.await?;
Ok(())
}
pub fn destroy_domain(&self, domid: u32) -> Result<()> {
pub async fn destroy_domain(&self, domid: u32) -> Result<()> {
trace!(
"domctl fd={} destroy_domain domid={}",
self.handle.as_raw_fd(),
@ -534,11 +564,12 @@ impl XenCall {
domid,
value: DomCtlValue { pad: [0; 128] },
};
self.hypercall1(HYPERVISOR_DOMCTL, addr_of_mut!(domctl) as c_ulong)?;
self.hypercall1(HYPERVISOR_DOMCTL, addr_of_mut!(domctl) as c_ulong)
.await?;
Ok(())
}
pub fn get_memory_map(&self, size_of_entry: usize) -> Result<Vec<u8>> {
pub async fn get_memory_map(&self, size_of_entry: usize) -> Result<Vec<u8>> {
let mut memory_map = MemoryMap {
count: 0,
buffer: 0,
@ -547,18 +578,20 @@ impl XenCall {
HYPERVISOR_MEMORY_OP,
XEN_MEM_MEMORY_MAP as c_ulong,
addr_of_mut!(memory_map) as c_ulong,
)?;
)
.await?;
let mut buffer = vec![0u8; memory_map.count as usize * size_of_entry];
memory_map.buffer = buffer.as_mut_ptr() as c_ulong;
self.hypercall2(
HYPERVISOR_MEMORY_OP,
XEN_MEM_MEMORY_MAP as c_ulong,
addr_of_mut!(memory_map) as c_ulong,
)?;
)
.await?;
Ok(buffer)
}
pub fn populate_physmap(
pub async fn populate_physmap(
&self,
domid: u32,
nr_extents: u64,
@ -590,7 +623,7 @@ impl XenCall {
0,
],
}];
self.multicall(calls)?;
self.multicall(calls).await?;
let code = calls[0].result;
if code > !0xfff {
return Err(Error::PopulatePhysmapFailed);
@ -602,7 +635,7 @@ impl XenCall {
Ok(extents)
}
pub fn claim_pages(&self, domid: u32, pages: u64) -> Result<()> {
pub async fn claim_pages(&self, domid: u32, pages: u64) -> Result<()> {
trace!(
"memory fd={} claim_pages domid={} pages={}",
self.handle.as_raw_fd(),
@ -620,11 +653,12 @@ impl XenCall {
HYPERVISOR_MEMORY_OP,
XEN_MEM_CLAIM_PAGES as c_ulong,
addr_of_mut!(reservation) as c_ulong,
)?;
)
.await?;
Ok(())
}
pub fn mmuext(&self, domid: u32, cmd: c_uint, arg1: u64, arg2: u64) -> Result<()> {
pub async fn mmuext(&self, domid: u32, cmd: c_uint, arg1: u64, arg2: u64) -> Result<()> {
let mut ops = MmuExtOp { cmd, arg1, arg2 };
self.hypercall4(
@ -634,6 +668,7 @@ impl XenCall {
0,
domid as c_ulong,
)
.await
.map(|_| ())
}
}