vm-virtio: Implement multi-mapping for virtio-fs

The virtio-fs messages coming from the slave can contain multiple
mappings (up to 8) through one single request. By implementing such
feature, the virtio-fs implementation of cloud-hypervisor is optimal and
fully functional as it resolves a bug that was seen when running fio
testing without this patch.

Signed-off-by: Sebastien Boeuf <sebastien.boeuf@intel.com>
This commit is contained in:
Sebastien Boeuf
2020-01-07 17:18:02 +01:00
parent 143471b739
commit 84445aae93
2 changed files with 78 additions and 42 deletions
+1 -1
View File
@@ -631,7 +631,7 @@ bitflags! {
} }
/// Max entries in one virtio-fs slave request. /// Max entries in one virtio-fs slave request.
const VHOST_USER_FS_SLAVE_ENTRIES: usize = 8; pub const VHOST_USER_FS_SLAVE_ENTRIES: usize = 8;
/// Slave request message to update the MMIO window. /// Slave request message to update the MMIO window.
#[repr(packed)] #[repr(packed)]
+77 -41
View File
@@ -21,6 +21,7 @@ use std::sync::{Arc, Mutex};
use std::thread; use std::thread;
use vhost_rs::vhost_user::message::{ use vhost_rs::vhost_user::message::{
VhostUserFSSlaveMsg, VhostUserProtocolFeatures, VhostUserVirtioFeatures, VhostUserFSSlaveMsg, VhostUserProtocolFeatures, VhostUserVirtioFeatures,
VHOST_USER_FS_SLAVE_ENTRIES,
}; };
use vhost_rs::vhost_user::{ use vhost_rs::vhost_user::{
HandlerResult, Master, MasterReqHandler, VhostUserMaster, VhostUserMasterReqHandler, HandlerResult, Master, MasterReqHandler, VhostUserMaster, VhostUserMasterReqHandler,
@@ -49,24 +50,35 @@ impl VhostUserMasterReqHandler for SlaveReqHandler {
fn fs_slave_map(&mut self, fs: &VhostUserFSSlaveMsg, fd: RawFd) -> HandlerResult<()> { fn fs_slave_map(&mut self, fs: &VhostUserFSSlaveMsg, fd: RawFd) -> HandlerResult<()> {
debug!("fs_slave_map"); debug!("fs_slave_map");
let addr = self.mmap_cache_addr + fs.cache_offset[0]; for i in 0..VHOST_USER_FS_SLAVE_ENTRIES {
let ret = unsafe { // Ignore if the length is 0.
libc::mmap( if fs.len[i] == 0 {
addr as *mut libc::c_void, continue;
fs.len[0] as usize, }
fs.flags[0].bits() as i32,
libc::MAP_SHARED | libc::MAP_FIXED,
fd,
fs.fd_offset[0] as libc::off_t,
)
};
if ret == libc::MAP_FAILED {
return Err(io::Error::last_os_error());
}
let ret = unsafe { libc::close(fd) }; if fs.cache_offset[i] > self.cache_size {
if ret == -1 { return Err(io::Error::new(io::ErrorKind::Other, "Wrong offset"));
return Err(io::Error::last_os_error()); }
let addr = self.mmap_cache_addr + fs.cache_offset[i];
let ret = unsafe {
libc::mmap(
addr as *mut libc::c_void,
fs.len[i] as usize,
fs.flags[i].bits() as i32,
libc::MAP_SHARED | libc::MAP_FIXED,
fd,
fs.fd_offset[i] as libc::off_t,
)
};
if ret == libc::MAP_FAILED {
return Err(io::Error::last_os_error());
}
let ret = unsafe { libc::close(fd) };
if ret == -1 {
return Err(io::Error::last_os_error());
}
} }
Ok(()) Ok(())
@@ -75,26 +87,38 @@ impl VhostUserMasterReqHandler for SlaveReqHandler {
fn fs_slave_unmap(&mut self, fs: &VhostUserFSSlaveMsg) -> HandlerResult<()> { fn fs_slave_unmap(&mut self, fs: &VhostUserFSSlaveMsg) -> HandlerResult<()> {
debug!("fs_slave_unmap"); debug!("fs_slave_unmap");
let mut len = fs.len[0]; for i in 0..VHOST_USER_FS_SLAVE_ENTRIES {
// Need to handle a special case where the slave ask for the unmapping let mut len = fs.len[i];
// of the entire mapping.
if len == 0xffff_ffff_ffff_ffff {
len = self.cache_size;
}
let addr = self.mmap_cache_addr + fs.cache_offset[0]; // Ignore if the length is 0.
let ret = unsafe { if len == 0 {
libc::mmap( continue;
addr as *mut libc::c_void, }
len as usize,
libc::PROT_NONE, // Need to handle a special case where the slave ask for the unmapping
libc::MAP_ANONYMOUS | libc::MAP_PRIVATE | libc::MAP_FIXED, // of the entire mapping.
-1, if len == 0xffff_ffff_ffff_ffff {
0 as libc::off_t, len = self.cache_size;
) }
};
if ret == libc::MAP_FAILED { if fs.cache_offset[i] > self.cache_size {
return Err(io::Error::last_os_error()); return Err(io::Error::new(io::ErrorKind::Other, "Wrong offset"));
}
let addr = self.mmap_cache_addr + fs.cache_offset[i];
let ret = unsafe {
libc::mmap(
addr as *mut libc::c_void,
len as usize,
libc::PROT_NONE,
libc::MAP_ANONYMOUS | libc::MAP_PRIVATE | libc::MAP_FIXED,
-1,
0 as libc::off_t,
)
};
if ret == libc::MAP_FAILED {
return Err(io::Error::last_os_error());
}
} }
Ok(()) Ok(())
@@ -103,11 +127,23 @@ impl VhostUserMasterReqHandler for SlaveReqHandler {
fn fs_slave_sync(&mut self, fs: &VhostUserFSSlaveMsg) -> HandlerResult<()> { fn fs_slave_sync(&mut self, fs: &VhostUserFSSlaveMsg) -> HandlerResult<()> {
debug!("fs_slave_sync"); debug!("fs_slave_sync");
let addr = self.mmap_cache_addr + fs.cache_offset[0]; for i in 0..VHOST_USER_FS_SLAVE_ENTRIES {
let ret = // Ignore if the length is 0.
unsafe { libc::msync(addr as *mut libc::c_void, fs.len[0] as usize, libc::MS_SYNC) }; if fs.len[i] == 0 {
if ret == -1 { continue;
return Err(io::Error::last_os_error()); }
if fs.cache_offset[i] > self.cache_size {
return Err(io::Error::new(io::ErrorKind::Other, "Wrong offset"));
}
let addr = self.mmap_cache_addr + fs.cache_offset[i];
let ret = unsafe {
libc::msync(addr as *mut libc::c_void, fs.len[i] as usize, libc::MS_SYNC)
};
if ret == -1 {
return Err(io::Error::last_os_error());
}
} }
Ok(()) Ok(())