vhost_user: Add support for REM_MEM_REG

Adding support for a new message REM_MEM_REG. This command request an
existing memory region to be removed and unmapped from the vhost-user
backend.

It is designed for supporting memory hot-unplug, rather than using
SET_MEM_TABLE, which is less efficient as it would remap all remaining
regions.

It is only available if the protocol feature
VHOST_USER_PROTOCOL_F_CONFIGURE_MEM_SLOTS has been negotiated.

Signed-off-by: Sebastien Boeuf <sebastien.boeuf@intel.com>
This commit is contained in:
Sebastien Boeuf 2021-03-05 10:34:14 +01:00 committed by Jiang Liu
parent 7e3ab1af4e
commit ee3e872270
5 changed files with 52 additions and 1 deletions

View file

@ -1 +1 @@
{"coverage_score": 81.3, "exclude_path": "src/vhost_kern/", "crate_features": "vhost-user-master,vhost-user-slave"}
{"coverage_score": 81.2, "exclude_path": "src/vhost_kern/", "crate_features": "vhost-user-master,vhost-user-slave"}

View file

@ -252,4 +252,8 @@ impl VhostUserSlaveReqHandlerMut for DummySlaveReqHandler {
fn add_mem_region(&mut self, _region: &VhostUserSingleMemoryRegion, _fd: RawFd) -> Result<()> {
Ok(())
}
fn remove_mem_region(&mut self, _region: &VhostUserSingleMemoryRegion) -> Result<()> {
Ok(())
}
}

View file

@ -56,6 +56,9 @@ pub trait VhostUserMaster: VhostBackend {
/// Add a new guest memory mapping for vhost to use.
fn add_mem_region(&mut self, region: &VhostUserMemoryRegionInfo) -> Result<()>;
/// Remove a guest memory mapping from vhost.
fn remove_mem_region(&mut self, region: &VhostUserMemoryRegionInfo) -> Result<()>;
}
fn error_code<T>(err: VhostUserError) -> Result<T> {
@ -475,6 +478,26 @@ impl VhostUserMaster for Master {
let hdr = node.send_request_with_body(MasterReq::ADD_MEM_REG, &body, Some(&fds))?;
node.wait_for_ack(&hdr).map_err(|e| e.into())
}
fn remove_mem_region(&mut self, region: &VhostUserMemoryRegionInfo) -> Result<()> {
let mut node = self.node();
if node.acked_protocol_features & VhostUserProtocolFeatures::CONFIGURE_MEM_SLOTS.bits() == 0
{
return error_code(VhostUserError::InvalidOperation);
}
if region.memory_size == 0 {
return error_code(VhostUserError::InvalidParam);
}
let body = VhostUserSingleMemoryRegion::new(
region.guest_phys_addr,
region.memory_size,
region.userspace_addr,
region.mmap_offset,
);
let hdr = node.send_request_with_body(MasterReq::REM_MEM_REG, &body, None)?;
node.wait_for_ack(&hdr).map_err(|e| e.into())
}
}
impl AsRawFd for Master {

View file

@ -341,6 +341,9 @@ mod tests {
// add_mem_region()
slave.handle_request().unwrap();
// remove_mem_region()
slave.handle_request().unwrap();
sbar.wait();
});
@ -416,6 +419,8 @@ mod tests {
};
master.add_mem_region(&region).unwrap();
master.remove_mem_region(&region).unwrap();
mbar.wait();
}

View file

@ -64,6 +64,7 @@ pub trait VhostUserSlaveReqHandler {
fn set_slave_req_fd(&self, _vu_req: SlaveFsCacheReq) {}
fn get_max_mem_slots(&self) -> Result<u64>;
fn add_mem_region(&self, region: &VhostUserSingleMemoryRegion, fd: RawFd) -> Result<()>;
fn remove_mem_region(&self, region: &VhostUserSingleMemoryRegion) -> Result<()>;
}
/// Services provided to the master by the slave without interior mutability.
@ -106,6 +107,7 @@ pub trait VhostUserSlaveReqHandlerMut {
fn set_slave_req_fd(&mut self, _vu_req: SlaveFsCacheReq) {}
fn get_max_mem_slots(&mut self) -> Result<u64>;
fn add_mem_region(&mut self, region: &VhostUserSingleMemoryRegion, fd: RawFd) -> Result<()>;
fn remove_mem_region(&mut self, region: &VhostUserSingleMemoryRegion) -> Result<()>;
}
impl<T: VhostUserSlaveReqHandlerMut> VhostUserSlaveReqHandler for Mutex<T> {
@ -202,6 +204,10 @@ impl<T: VhostUserSlaveReqHandlerMut> VhostUserSlaveReqHandler for Mutex<T> {
fn add_mem_region(&self, region: &VhostUserSingleMemoryRegion, fd: RawFd) -> Result<()> {
self.lock().unwrap().add_mem_region(region, fd)
}
fn remove_mem_region(&self, region: &VhostUserSingleMemoryRegion) -> Result<()> {
self.lock().unwrap().remove_mem_region(region)
}
}
/// Server to handle service requests from masters from the master communication channel.
@ -462,6 +468,19 @@ impl<S: VhostUserSlaveReqHandler> SlaveReqHandler<S> {
let res = self.backend.add_mem_region(&msg, fd);
self.send_ack_message(&hdr, res)?;
}
MasterReq::REM_MEM_REG => {
if self.acked_protocol_features
& VhostUserProtocolFeatures::CONFIGURE_MEM_SLOTS.bits()
== 0
{
return Err(Error::InvalidOperation);
}
let msg =
self.extract_request_body::<VhostUserSingleMemoryRegion>(&hdr, size, &buf)?;
let res = self.backend.remove_mem_region(&msg);
self.send_ack_message(&hdr, res)?;
}
_ => {
return Err(Error::InvalidMessage);
}