summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorLiu Jiang <gerry@linux.alibaba.com>2021-02-22 14:08:04 +0800
committerSergio Lopez <slp@sinrega.org>2021-03-01 12:50:56 +0100
commite543bf2a8defadae534cfe757829a9377663e5ad (patch)
tree12ed601664702e8152a9e25453b03dc7b88067a7
parentec6eae722ef7c6fcecbb8acddf1d9905083dc3de (diff)
downloadvmm_vhost-e543bf2a8defadae534cfe757829a9377663e5ad.tar.gz
vhost_user: add more negative unit test cases
Add more negative unit test cases to improve code coverage. Also add two helper functions to simplify code. Signed-off-by: Liu Jiang <gerry@linux.alibaba.com>
-rw-r--r--coverage_config_x86_64.json2
-rw-r--r--src/vhost_user/master.rs257
-rw-r--r--src/vhost_user/mod.rs11
-rw-r--r--src/vhost_user/slave_fs_cache.rs65
4 files changed, 295 insertions, 40 deletions
diff --git a/coverage_config_x86_64.json b/coverage_config_x86_64.json
index 075255b..a4ed64f 100644
--- a/coverage_config_x86_64.json
+++ b/coverage_config_x86_64.json
@@ -1 +1 @@
-{"coverage_score": 78.9, "exclude_path": "src/vhost_kern/", "crate_features": "vhost-user-master,vhost-user-slave"}
+{"coverage_score": 81.3, "exclude_path": "src/vhost_kern/", "crate_features": "vhost-user-master,vhost-user-slave"} \ No newline at end of file
diff --git a/src/vhost_user/master.rs b/src/vhost_user/master.rs
index cc754b5..be2892e 100644
--- a/src/vhost_user/master.rs
+++ b/src/vhost_user/master.rs
@@ -6,7 +6,7 @@
use std::mem;
use std::os::unix::io::{AsRawFd, RawFd};
use std::os::unix::net::UnixStream;
-use std::sync::{Arc, Mutex};
+use std::sync::{Arc, Mutex, MutexGuard};
use vmm_sys_util::eventfd::EventFd;
@@ -78,6 +78,10 @@ impl Master {
}
}
+ fn node(&self) -> MutexGuard<MasterInternal> {
+ self.node.lock().unwrap()
+ }
+
/// Create a new instance from a Unix stream socket.
pub fn from_stream(sock: UnixStream, max_queue_num: u64) -> Self {
Self::new(Endpoint::<MasterReq>::from_stream(sock), max_queue_num)
@@ -116,7 +120,7 @@ impl Master {
impl VhostBackend for Master {
/// Get from the underlying vhost implementation the feature bitmask.
fn get_features(&self) -> Result<u64> {
- let mut node = self.node.lock().unwrap();
+ let mut node = self.node();
let hdr = node.send_request_header(MasterReq::GET_FEATURES, None)?;
let val = node.recv_reply::<VhostUserU64>(&hdr)?;
node.virtio_features = val.value;
@@ -125,7 +129,7 @@ impl VhostBackend for Master {
/// Enable features in the underlying vhost implementation using a bitmask.
fn set_features(&self, features: u64) -> Result<()> {
- let mut node = self.node.lock().unwrap();
+ let mut node = self.node();
let val = VhostUserU64::new(features);
let _ = node.send_request_with_body(MasterReq::SET_FEATURES, &val, None)?;
// Don't wait for ACK here because the protocol feature negotiation process hasn't been
@@ -138,7 +142,7 @@ impl VhostBackend for Master {
fn set_owner(&self) -> Result<()> {
// We unwrap() the return value to assert that we are not expecting threads to ever fail
// while holding the lock.
- let mut node = self.node.lock().unwrap();
+ let mut node = self.node();
let _ = node.send_request_header(MasterReq::SET_OWNER, None)?;
// Don't wait for ACK here because the protocol feature negotiation process hasn't been
// completed yet.
@@ -146,7 +150,7 @@ impl VhostBackend for Master {
}
fn reset_owner(&self) -> Result<()> {
- let mut node = self.node.lock().unwrap();
+ let mut node = self.node();
let _ = node.send_request_header(MasterReq::RESET_OWNER, None)?;
// Don't wait for ACK here because the protocol feature negotiation process hasn't been
// completed yet.
@@ -174,7 +178,7 @@ impl VhostBackend for Master {
ctx.append(&reg, region.mmap_handle);
}
- let mut node = self.node.lock().unwrap();
+ let mut node = self.node();
let body = VhostUserMemory::new(ctx.regions.len() as u32);
let (_, payload, _) = unsafe { ctx.regions.align_to::<u8>() };
let hdr = node.send_request_with_payload(
@@ -189,7 +193,7 @@ impl VhostBackend for Master {
// Clippy doesn't seem to know that if let with && is still experimental
#[allow(clippy::unnecessary_unwrap)]
fn set_log_base(&self, base: u64, fd: Option<RawFd>) -> Result<()> {
- let mut node = self.node.lock().unwrap();
+ let mut node = self.node();
let val = VhostUserU64::new(base);
if node.acked_protocol_features & VhostUserProtocolFeatures::LOG_SHMFD.bits() != 0
@@ -204,7 +208,7 @@ impl VhostBackend for Master {
}
fn set_log_fd(&self, fd: RawFd) -> Result<()> {
- let mut node = self.node.lock().unwrap();
+ let mut node = self.node();
let fds = [fd];
node.send_request_header(MasterReq::SET_LOG_FD, Some(&fds))?;
Ok(())
@@ -212,7 +216,7 @@ impl VhostBackend for Master {
/// Set the size of the queue.
fn set_vring_num(&self, queue_index: usize, num: u16) -> Result<()> {
- let mut node = self.node.lock().unwrap();
+ let mut node = self.node();
if queue_index as u64 >= node.max_queue_num {
return error_code(VhostUserError::InvalidParam);
}
@@ -224,7 +228,7 @@ impl VhostBackend for Master {
/// Sets the addresses of the different aspects of the vring.
fn set_vring_addr(&self, queue_index: usize, config_data: &VringConfigData) -> Result<()> {
- let mut node = self.node.lock().unwrap();
+ let mut node = self.node();
if queue_index as u64 >= node.max_queue_num
|| config_data.flags & !(VhostUserVringAddrFlags::all().bits()) != 0
{
@@ -238,7 +242,7 @@ impl VhostBackend for Master {
/// Sets the base offset in the available vring.
fn set_vring_base(&self, queue_index: usize, base: u16) -> Result<()> {
- let mut node = self.node.lock().unwrap();
+ let mut node = self.node();
if queue_index as u64 >= node.max_queue_num {
return error_code(VhostUserError::InvalidParam);
}
@@ -249,7 +253,7 @@ impl VhostBackend for Master {
}
fn get_vring_base(&self, queue_index: usize) -> Result<u32> {
- let mut node = self.node.lock().unwrap();
+ let mut node = self.node();
if queue_index as u64 >= node.max_queue_num {
return error_code(VhostUserError::InvalidParam);
}
@@ -265,7 +269,7 @@ impl VhostBackend for Master {
/// is set when there is no file descriptor in the ancillary data. This signals that polling
/// will be used instead of waiting for the call.
fn set_vring_call(&self, queue_index: usize, fd: &EventFd) -> Result<()> {
- let mut node = self.node.lock().unwrap();
+ let mut node = self.node();
if queue_index as u64 >= node.max_queue_num {
return error_code(VhostUserError::InvalidParam);
}
@@ -278,7 +282,7 @@ impl VhostBackend for Master {
/// is set when there is no file descriptor in the ancillary data. This signals that polling
/// should be used instead of waiting for a kick.
fn set_vring_kick(&self, queue_index: usize, fd: &EventFd) -> Result<()> {
- let mut node = self.node.lock().unwrap();
+ let mut node = self.node();
if queue_index as u64 >= node.max_queue_num {
return error_code(VhostUserError::InvalidParam);
}
@@ -290,7 +294,7 @@ impl VhostBackend for Master {
/// Bits (0-7) of the payload contain the vring index. Bit 8 is the invalid FD flag. This flag
/// is set when there is no file descriptor in the ancillary data.
fn set_vring_err(&self, queue_index: usize, fd: &EventFd) -> Result<()> {
- let mut node = self.node.lock().unwrap();
+ let mut node = self.node();
if queue_index as u64 >= node.max_queue_num {
return error_code(VhostUserError::InvalidParam);
}
@@ -301,7 +305,7 @@ impl VhostBackend for Master {
impl VhostUserMaster for Master {
fn get_protocol_features(&mut self) -> Result<VhostUserProtocolFeatures> {
- let mut node = self.node.lock().unwrap();
+ let mut node = self.node();
let flag = VhostUserVirtioFeatures::PROTOCOL_FEATURES.bits();
if node.virtio_features & flag == 0 || node.acked_virtio_features & flag == 0 {
return error_code(VhostUserError::InvalidOperation);
@@ -318,7 +322,7 @@ impl VhostUserMaster for Master {
}
fn set_protocol_features(&mut self, features: VhostUserProtocolFeatures) -> Result<()> {
- let mut node = self.node.lock().unwrap();
+ let mut node = self.node();
let flag = VhostUserVirtioFeatures::PROTOCOL_FEATURES.bits();
if node.virtio_features & flag == 0 || node.acked_virtio_features & flag == 0 {
return error_code(VhostUserError::InvalidOperation);
@@ -333,7 +337,7 @@ impl VhostUserMaster for Master {
}
fn get_queue_num(&mut self) -> Result<u64> {
- let mut node = self.node.lock().unwrap();
+ let mut node = self.node();
if !node.is_feature_mq_available() {
return error_code(VhostUserError::InvalidOperation);
}
@@ -348,7 +352,7 @@ impl VhostUserMaster for Master {
}
fn set_vring_enable(&mut self, queue_index: usize, enable: bool) -> Result<()> {
- let mut node = self.node.lock().unwrap();
+ let mut node = self.node();
// set_vring_enable() is supported only when PROTOCOL_FEATURES has been enabled.
if node.acked_virtio_features & VhostUserVirtioFeatures::PROTOCOL_FEATURES.bits() == 0 {
return error_code(VhostUserError::InvalidOperation);
@@ -374,7 +378,7 @@ impl VhostUserMaster for Master {
return error_code(VhostUserError::InvalidParam);
}
- let mut node = self.node.lock().unwrap();
+ let mut node = self.node();
// depends on VhostUserProtocolFeatures::CONFIG
if node.acked_protocol_features & VhostUserProtocolFeatures::CONFIG.bits() == 0 {
return error_code(VhostUserError::InvalidOperation);
@@ -409,7 +413,7 @@ impl VhostUserMaster for Master {
return error_code(VhostUserError::InvalidParam);
}
- let mut node = self.node.lock().unwrap();
+ let mut node = self.node();
// depends on VhostUserProtocolFeatures::CONFIG
if node.acked_protocol_features & VhostUserProtocolFeatures::CONFIG.bits() == 0 {
return error_code(VhostUserError::InvalidOperation);
@@ -420,7 +424,7 @@ impl VhostUserMaster for Master {
}
fn set_slave_request_fd(&mut self, fd: RawFd) -> Result<()> {
- let mut node = self.node.lock().unwrap();
+ let mut node = self.node();
if node.acked_protocol_features & VhostUserProtocolFeatures::SLAVE_REQ.bits() == 0 {
return error_code(VhostUserError::InvalidOperation);
}
@@ -433,7 +437,7 @@ impl VhostUserMaster for Master {
impl AsRawFd for Master {
fn as_raw_fd(&self) -> RawFd {
- let node = self.node.lock().unwrap();
+ let node = self.node();
node.main_sock.as_raw_fd()
}
}
@@ -783,4 +787,211 @@ mod tests {
peer.send_message(&hdr, &msg, None).unwrap();
assert!(master.get_protocol_features().is_err());
}
+
+ #[test]
+ fn test_master_set_config_negative() {
+ let path = temp_path();
+ let (mut master, _peer) = create_pair(&path);
+ let buf = vec![0x0; MAX_MSG_SIZE + 1];
+
+ master
+ .set_config(0x100, VhostUserConfigFlags::WRITABLE, &buf[0..4])
+ .unwrap_err();
+
+ {
+ let mut node = master.node();
+ node.virtio_features = 0xffff_ffff;
+ node.acked_virtio_features = 0xffff_ffff;
+ node.protocol_features = 0xffff_ffff;
+ node.acked_protocol_features = 0xffff_ffff;
+ }
+
+ master
+ .set_config(0x100, VhostUserConfigFlags::WRITABLE, &buf[0..4])
+ .unwrap();
+ master
+ .set_config(0x0, VhostUserConfigFlags::WRITABLE, &buf[0..4])
+ .unwrap_err();
+ master
+ .set_config(0x1000, VhostUserConfigFlags::WRITABLE, &buf[0..4])
+ .unwrap_err();
+ master
+ .set_config(
+ 0x100,
+ unsafe { VhostUserConfigFlags::from_bits_unchecked(0xffff_ffff) },
+ &buf[0..4],
+ )
+ .unwrap_err();
+ master
+ .set_config(0x100, VhostUserConfigFlags::WRITABLE, &buf)
+ .unwrap_err();
+ master
+ .set_config(0x100, VhostUserConfigFlags::WRITABLE, &[])
+ .unwrap_err();
+ }
+
+ fn create_pair2() -> (Master, Endpoint<MasterReq>) {
+ let path = temp_path();
+ let (master, peer) = create_pair(&path);
+
+ {
+ let mut node = master.node();
+ node.virtio_features = 0xffff_ffff;
+ node.acked_virtio_features = 0xffff_ffff;
+ node.protocol_features = 0xffff_ffff;
+ node.acked_protocol_features = 0xffff_ffff;
+ }
+
+ (master, peer)
+ }
+
+ #[test]
+ fn test_master_get_config_negative0() {
+ let (mut master, mut peer) = create_pair2();
+ let buf = vec![0x0; MAX_MSG_SIZE + 1];
+
+ let mut hdr = VhostUserMsgHeader::new(MasterReq::GET_CONFIG, 0x4, 16);
+ let msg = VhostUserConfig::new(0x100, 4, VhostUserConfigFlags::empty());
+ peer.send_message_with_payload(&hdr, &msg, &buf[0..4], None)
+ .unwrap();
+ assert!(master
+ .get_config(0x100, 4, VhostUserConfigFlags::WRITABLE, &buf[0..4])
+ .is_ok());
+
+ hdr.set_code(MasterReq::GET_FEATURES);
+ peer.send_message_with_payload(&hdr, &msg, &buf[0..4], None)
+ .unwrap();
+ assert!(master
+ .get_config(0x100, 4, VhostUserConfigFlags::WRITABLE, &buf[0..4])
+ .is_err());
+ hdr.set_code(MasterReq::GET_CONFIG);
+ }
+
+ #[test]
+ fn test_master_get_config_negative1() {
+ let (mut master, mut peer) = create_pair2();
+ let buf = vec![0x0; MAX_MSG_SIZE + 1];
+
+ let mut hdr = VhostUserMsgHeader::new(MasterReq::GET_CONFIG, 0x4, 16);
+ let msg = VhostUserConfig::new(0x100, 4, VhostUserConfigFlags::empty());
+ peer.send_message_with_payload(&hdr, &msg, &buf[0..4], None)
+ .unwrap();
+ assert!(master
+ .get_config(0x100, 4, VhostUserConfigFlags::WRITABLE, &buf[0..4])
+ .is_ok());
+
+ hdr.set_reply(false);
+ peer.send_message_with_payload(&hdr, &msg, &buf[0..4], None)
+ .unwrap();
+ assert!(master
+ .get_config(0x100, 4, VhostUserConfigFlags::WRITABLE, &buf[0..4])
+ .is_err());
+ }
+
+ #[test]
+ fn test_master_get_config_negative2() {
+ let (mut master, mut peer) = create_pair2();
+ let buf = vec![0x0; MAX_MSG_SIZE + 1];
+
+ let hdr = VhostUserMsgHeader::new(MasterReq::GET_CONFIG, 0x4, 16);
+ let msg = VhostUserConfig::new(0x100, 4, VhostUserConfigFlags::empty());
+ peer.send_message_with_payload(&hdr, &msg, &buf[0..4], None)
+ .unwrap();
+ assert!(master
+ .get_config(0x100, 4, VhostUserConfigFlags::WRITABLE, &buf[0..4])
+ .is_ok());
+ }
+
+ #[test]
+ fn test_master_get_config_negative3() {
+ let (mut master, mut peer) = create_pair2();
+ let buf = vec![0x0; MAX_MSG_SIZE + 1];
+
+ let hdr = VhostUserMsgHeader::new(MasterReq::GET_CONFIG, 0x4, 16);
+ let mut msg = VhostUserConfig::new(0x100, 4, VhostUserConfigFlags::empty());
+ peer.send_message_with_payload(&hdr, &msg, &buf[0..4], None)
+ .unwrap();
+ assert!(master
+ .get_config(0x100, 4, VhostUserConfigFlags::WRITABLE, &buf[0..4])
+ .is_ok());
+
+ msg.offset = 0;
+ peer.send_message_with_payload(&hdr, &msg, &buf[0..4], None)
+ .unwrap();
+ assert!(master
+ .get_config(0x100, 4, VhostUserConfigFlags::WRITABLE, &buf[0..4])
+ .is_err());
+ }
+
+ #[test]
+ fn test_master_get_config_negative4() {
+ let (mut master, mut peer) = create_pair2();
+ let buf = vec![0x0; MAX_MSG_SIZE + 1];
+
+ let hdr = VhostUserMsgHeader::new(MasterReq::GET_CONFIG, 0x4, 16);
+ let mut msg = VhostUserConfig::new(0x100, 4, VhostUserConfigFlags::empty());
+ peer.send_message_with_payload(&hdr, &msg, &buf[0..4], None)
+ .unwrap();
+ assert!(master
+ .get_config(0x100, 4, VhostUserConfigFlags::WRITABLE, &buf[0..4])
+ .is_ok());
+
+ msg.offset = 0x101;
+ peer.send_message_with_payload(&hdr, &msg, &buf[0..4], None)
+ .unwrap();
+ assert!(master
+ .get_config(0x100, 4, VhostUserConfigFlags::WRITABLE, &buf[0..4])
+ .is_err());
+ }
+
+ #[test]
+ fn test_master_get_config_negative5() {
+ let (mut master, mut peer) = create_pair2();
+ let buf = vec![0x0; MAX_MSG_SIZE + 1];
+
+ let hdr = VhostUserMsgHeader::new(MasterReq::GET_CONFIG, 0x4, 16);
+ let mut msg = VhostUserConfig::new(0x100, 4, VhostUserConfigFlags::empty());
+ peer.send_message_with_payload(&hdr, &msg, &buf[0..4], None)
+ .unwrap();
+ assert!(master
+ .get_config(0x100, 4, VhostUserConfigFlags::WRITABLE, &buf[0..4])
+ .is_ok());
+
+ msg.offset = (MAX_MSG_SIZE + 1) as u32;
+ peer.send_message_with_payload(&hdr, &msg, &buf[0..4], None)
+ .unwrap();
+ assert!(master
+ .get_config(0x100, 4, VhostUserConfigFlags::WRITABLE, &buf[0..4])
+ .is_err());
+ }
+
+ #[test]
+ fn test_master_get_config_negative6() {
+ let (mut master, mut peer) = create_pair2();
+ let buf = vec![0x0; MAX_MSG_SIZE + 1];
+
+ let hdr = VhostUserMsgHeader::new(MasterReq::GET_CONFIG, 0x4, 16);
+ let mut msg = VhostUserConfig::new(0x100, 4, VhostUserConfigFlags::empty());
+ peer.send_message_with_payload(&hdr, &msg, &buf[0..4], None)
+ .unwrap();
+ assert!(master
+ .get_config(0x100, 4, VhostUserConfigFlags::WRITABLE, &buf[0..4])
+ .is_ok());
+
+ msg.size = 6;
+ peer.send_message_with_payload(&hdr, &msg, &buf[0..6], None)
+ .unwrap();
+ assert!(master
+ .get_config(0x100, 4, VhostUserConfigFlags::WRITABLE, &buf[0..4])
+ .is_err());
+ }
+
+ #[test]
+ fn test_maset_set_mem_table_failure() {
+ let (master, _peer) = create_pair2();
+
+ master.set_mem_table(&[]).unwrap_err();
+ let tables = vec![VhostUserMemoryRegionInfo::default(); MAX_ATTACHED_FD_ENTRIES + 1];
+ master.set_mem_table(&tables).unwrap_err();
+ }
}
diff --git a/src/vhost_user/mod.rs b/src/vhost_user/mod.rs
index bf0a261..bc21b44 100644
--- a/src/vhost_user/mod.rs
+++ b/src/vhost_user/mod.rs
@@ -210,7 +210,7 @@ mod tests {
#[test]
fn create_dummy_slave() {
- let mut slave = DummySlaveReqHandler::new();
+ let slave = Arc::new(Mutex::new(DummySlaveReqHandler::new()));
slave.set_owner().unwrap();
assert!(slave.set_owner().is_err());
@@ -319,11 +319,9 @@ mod tests {
// set_vring_enable
slave.handle_request().unwrap();
- /*
// set_log_base,set_log_fd()
- slave.handle_request().unwrap();
- slave.handle_request().unwrap();
- */
+ slave.handle_request().unwrap_err();
+ slave.handle_request().unwrap_err();
// set_vring_xxx
slave.handle_request().unwrap();
@@ -375,10 +373,9 @@ mod tests {
master.set_slave_request_fd(eventfd.as_raw_fd()).unwrap();
master.set_vring_enable(0, true).unwrap();
- /*
+ // unimplemented yet
master.set_log_base(0, Some(eventfd.as_raw_fd())).unwrap();
master.set_log_fd(eventfd.as_raw_fd()).unwrap();
- */
master.set_vring_num(0, 256).unwrap();
master.set_vring_base(0, 0).unwrap();
diff --git a/src/vhost_user/slave_fs_cache.rs b/src/vhost_user/slave_fs_cache.rs
index 32b2b8e..1e2ef61 100644
--- a/src/vhost_user/slave_fs_cache.rs
+++ b/src/vhost_user/slave_fs_cache.rs
@@ -5,7 +5,7 @@ use std::io;
use std::mem;
use std::os::unix::io::RawFd;
use std::os::unix::net::UnixStream;
-use std::sync::{Arc, Mutex};
+use std::sync::{Arc, Mutex, MutexGuard};
use super::connection::Endpoint;
use super::message::*;
@@ -92,15 +92,17 @@ impl SlaveFsCacheReq {
}
}
+ fn node(&self) -> MutexGuard<SlaveFsCacheReqInternal> {
+ self.node.lock().unwrap()
+ }
+
fn send_message(
&self,
request: SlaveReq,
fs: &VhostUserFSSlaveMsg,
fds: Option<&[RawFd]>,
) -> io::Result<u64> {
- self.node
- .lock()
- .unwrap()
+ self.node()
.send_message(request, fs, fds)
.or_else(|e| Err(io::Error::new(io::ErrorKind::Other, format!("{}", e))))
}
@@ -116,12 +118,12 @@ impl SlaveFsCacheReq {
/// the "REPLY_ACK" flag will be set in the message header for every slave to master request
/// message.
pub fn set_reply_ack_flag(&self, enable: bool) {
- self.node.lock().unwrap().reply_ack_negotiated = enable;
+ self.node().reply_ack_negotiated = enable;
}
/// Mark endpoint as failed with specified error code.
pub fn set_failed(&self, error: i32) {
- self.node.lock().unwrap().error = Some(error);
+ self.node().error = Some(error);
}
}
@@ -148,9 +150,9 @@ mod tests {
let (p1, _p2) = UnixStream::pair().unwrap();
let fs_cache = SlaveFsCacheReq::from_stream(p1);
- assert!(fs_cache.node.lock().unwrap().error.is_none());
+ assert!(fs_cache.node().error.is_none());
fs_cache.set_failed(libc::EAGAIN);
- assert_eq!(fs_cache.node.lock().unwrap().error, Some(libc::EAGAIN));
+ assert_eq!(fs_cache.node().error, Some(libc::EAGAIN));
}
#[test]
@@ -166,7 +168,7 @@ mod tests {
fs_cache
.fs_slave_unmap(&VhostUserFSSlaveMsg::default())
.unwrap_err();
- fs_cache.node.lock().unwrap().error = None;
+ fs_cache.node().error = None;
drop(p2);
fs_cache
@@ -176,4 +178,49 @@ mod tests {
.fs_slave_unmap(&VhostUserFSSlaveMsg::default())
.unwrap_err();
}
+
+ #[test]
+ fn test_slave_fs_cache_recv_negative() {
+ let (p1, p2) = UnixStream::pair().unwrap();
+ let fd = p2.as_raw_fd();
+ let fs_cache = SlaveFsCacheReq::from_stream(p1);
+ let mut master = Endpoint::<SlaveReq>::from_stream(p2);
+
+ let len = mem::size_of::<VhostUserFSSlaveMsg>();
+ let mut hdr = VhostUserMsgHeader::new(
+ SlaveReq::FS_MAP,
+ VhostUserHeaderFlag::REPLY.bits(),
+ len as u32,
+ );
+ let body = VhostUserU64::new(0);
+
+ master.send_message(&hdr, &body, Some(&[fd])).unwrap();
+ fs_cache
+ .fs_slave_map(&VhostUserFSSlaveMsg::default(), fd)
+ .unwrap();
+
+ fs_cache.set_reply_ack_flag(true);
+ fs_cache
+ .fs_slave_map(&VhostUserFSSlaveMsg::default(), fd)
+ .unwrap_err();
+
+ hdr.set_code(SlaveReq::FS_UNMAP);
+ master.send_message(&hdr, &body, None).unwrap();
+ fs_cache
+ .fs_slave_map(&VhostUserFSSlaveMsg::default(), fd)
+ .unwrap_err();
+ hdr.set_code(SlaveReq::FS_MAP);
+
+ let body = VhostUserU64::new(1);
+ master.send_message(&hdr, &body, None).unwrap();
+ fs_cache
+ .fs_slave_map(&VhostUserFSSlaveMsg::default(), fd)
+ .unwrap_err();
+
+ let body = VhostUserU64::new(0);
+ master.send_message(&hdr, &body, None).unwrap();
+ fs_cache
+ .fs_slave_map(&VhostUserFSSlaveMsg::default(), fd)
+ .unwrap();
+ }
}