vhost-user: Provide RESET_DEVICE front-end support

Added mostly for being able to add a reasonable test to
vhost-user-backend/tests/vhost-user-server.rs.

Signed-off-by: Hanna Czenczek <hreitz@redhat.com>
This commit is contained in:
Hanna Czenczek 2024-10-16 11:43:53 +02:00 committed by Stefano Garzarella
parent ff08ca095c
commit 86eb78875a
2 changed files with 74 additions and 2 deletions

View file

@ -61,6 +61,12 @@ impl VhostUserBackendMut for MockVhostBackend {
VhostUserProtocolFeatures::all()
}
fn reset_device(&mut self) {
self.events = 0;
self.event_idx = false;
self.acked_features = 0;
}
fn set_event_idx(&mut self, enabled: bool) {
self.event_idx = enabled;
}
@ -219,10 +225,24 @@ fn vhost_user_client(path: &Path, barrier: Arc<Barrier>) {
frontend.remove_mem_region(&region).unwrap();
}
fn vhost_user_server(cb: fn(&Path, Arc<Barrier>)) {
/// Provide a vhost-user back-end for front-end testing.
///
/// Set up a `MockVhostBackend` vhost-user back-end and run `cb` in a thread, passing the
/// vhost-user socket's path and a barrier to await request processing. `cb` is supposed to run
/// the front-end tests.
///
/// After request processing has begun, run `server_fn`, passing both a reference to the back-end
/// and the same barrier as given to `cb`. `server_fn` may perform additional back-end tests while
/// `cb` is still run in its thread.
///
/// After `server_fn` is done, await `cb` (joining its thread), and return.
fn vhost_user_server_with_fn<F: FnOnce(Arc<Mutex<MockVhostBackend>>, Arc<Barrier>)>(
cb: fn(&Path, Arc<Barrier>),
server_fn: F,
) {
let mem = GuestMemoryAtomic::new(GuestMemoryMmap::<()>::new());
let backend = Arc::new(Mutex::new(MockVhostBackend::new()));
let mut daemon = VhostUserDaemon::new("test".to_owned(), backend, mem).unwrap();
let mut daemon = VhostUserDaemon::new("test".to_owned(), backend.clone(), mem).unwrap();
let barrier = Arc::new(Barrier::new(2));
let tmpdir = tempfile::tempdir().unwrap();
@ -238,10 +258,16 @@ fn vhost_user_server(cb: fn(&Path, Arc<Barrier>)) {
daemon.start(listener).unwrap();
barrier.wait();
server_fn(backend, barrier);
// handle service requests from clients.
thread.join().unwrap();
}
fn vhost_user_server(cb: fn(&Path, Arc<Barrier>)) {
vhost_user_server_with_fn(cb, |_, _| {})
}
#[test]
fn test_vhost_user_server() {
vhost_user_server(vhost_user_client);
@ -325,3 +351,38 @@ fn test_vhost_user_postcopy() {
vhost_user_server(vhost_user_postcopy_listen);
vhost_user_server(vhost_user_postcopy_end);
}
fn vhost_user_reset_device(path: &Path, barrier: Arc<Barrier>) {
let mut frontend = setup_frontend(path, barrier.clone());
// Signal that we are about to reset
barrier.wait();
// Wait until server has checked non-reset state
barrier.wait();
frontend.reset_device().unwrap();
// Signal reset is done
barrier.wait();
}
#[test]
fn test_vhost_user_reset_device() {
vhost_user_server_with_fn(vhost_user_reset_device, |backend, barrier| {
// Wait until `vhost_user_reset_device()` is before reset
barrier.wait();
// Check non-reset state
assert!(backend.lock().unwrap().acked_features == MockVhostBackend::SUPPORTED_FEATURES);
// Set up some arbitrary internal state
backend.lock().unwrap().events = 42;
// Allow reset
barrier.wait();
// Wait for reset to be done
barrier.wait();
// Check reset state
assert!(backend.lock().unwrap().acked_features == 0);
assert!(backend.lock().unwrap().events == 0);
});
}

View file

@ -32,6 +32,9 @@ pub trait VhostUserFrontend: VhostBackend {
/// Query how many queues the backend supports.
fn get_queue_num(&mut self) -> Result<u64>;
/// Disable all rings and reset the internal device state.
fn reset_device(&mut self) -> Result<()>;
/// Signal backend to enable or disable corresponding vring.
///
/// Backend must not pass data to/from the backend until ring is enabled by
@ -395,6 +398,14 @@ impl VhostUserFrontend for Frontend {
Ok(node.max_queue_num)
}
fn reset_device(&mut self) -> Result<()> {
let mut node = self.node();
node.check_proto_feature(VhostUserProtocolFeatures::RESET_DEVICE)?;
let hdr = node.send_request_header(FrontendReq::RESET_DEVICE, None)?;
node.wait_for_ack(&hdr).map_err(|e| e.into())
}
fn set_vring_enable(&mut self, queue_index: usize, enable: bool) -> Result<()> {
let mut node = self.node();
// set_vring_enable() is supported only when PROTOCOL_FEATURES has been enabled.