Skip to content

Commit 3c6b1f1

Browse files
committed
vhost: promote get/set_status from vdpa to vhost
Although originally introduced for VDPA we also have support for get/set status messages for vhost-user. So lets promote the trait functions to the main VhostBackend traits while providing a default implementation which responds for errors (which the Kernel variant would inherit). As the status bits are common between backends most of the implementation details can be handled within the vhost-user traits. Signed-off-by: Alex Bennée <[email protected]>
1 parent 900b9a5 commit 3c6b1f1

File tree

5 files changed

+125
-13
lines changed

5 files changed

+125
-13
lines changed

crates/vhost-user-backend/src/handler.rs

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -88,6 +88,8 @@ pub struct VhostUserHandler<S, V, B: Bitmap + 'static> {
8888
atomic_mem: GM<B>,
8989
vrings: Vec<V>,
9090
worker_threads: Vec<thread::JoinHandle<VringEpollResult<()>>>,
91+
/// VirtIO Device Status field, when using get/set status
92+
status: u8,
9193
}
9294

9395
// Ensure VhostUserHandler: Clone + Send + Sync + 'static.
@@ -147,6 +149,7 @@ where
147149
atomic_mem,
148150
vrings,
149151
worker_threads,
152+
status: 0,
150153
})
151154
}
152155
}
@@ -586,6 +589,15 @@ where
586589

587590
Ok(())
588591
}
592+
593+
fn get_status(&self) -> VhostUserResult<u8> {
594+
Ok(self.status)
595+
}
596+
597+
fn set_status(&mut self, status: u8) -> VhostUserResult<()> {
598+
self.status = status;
599+
Ok(())
600+
}
589601
}
590602

591603
impl<S, V, B: Bitmap> Drop for VhostUserHandler<S, V, B> {

crates/vhost/src/backend.rs

Lines changed: 66 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -308,6 +308,32 @@ pub trait VhostBackend: std::marker::Sized {
308308
/// * `queue_index` - Index of the queue to modify.
309309
/// * `fd` - EventFd that will be signaled from guest.
310310
fn set_vring_err(&self, queue_index: usize, fd: &EventFd) -> Result<()>;
311+
312+
/// Set the status.
313+
/// The status bits follow the same definition of the device
314+
/// status defined in virtio-spec.
315+
///
316+
/// As not all backends can implement this we provide a default
317+
/// implementation that returns an Error.
318+
///
319+
/// # Arguments
320+
/// * `status` - Status bits to set
321+
fn set_status(&self, _status: u8) -> Result<()>
322+
{
323+
Err(Error::InvalidOperation)
324+
}
325+
326+
/// Get the status.
327+
///
328+
/// The status bits follow the same definition of the device
329+
/// status defined in virtio-spec.
330+
///
331+
/// As not all backends can implement this we provide a default
332+
/// implementation that returns an Error.
333+
fn get_status(&self) -> Result<u8>
334+
{
335+
Err(Error::InvalidOperation)
336+
}
311337
}
312338

313339
/// An interface for setting up vhost-based backend drivers.
@@ -394,6 +420,17 @@ pub trait VhostBackendMut: std::marker::Sized {
394420
/// * `queue_index` - Index of the queue to modify.
395421
/// * `fd` - EventFd that will be signaled from guest.
396422
fn set_vring_err(&mut self, queue_index: usize, fd: &EventFd) -> Result<()>;
423+
424+
/// Set the status.
425+
/// The status bits follow the same definition of the device status defined in virtio-spec.
426+
///
427+
/// # Arguments
428+
/// * `status` - Status bits to set
429+
fn set_status(&mut self, status: u8) -> Result<()>;
430+
431+
/// Get the status.
432+
/// The status bits follow the same definition of the device status defined in virtio-spec.
433+
fn get_status(&self) -> Result<u8>;
397434
}
398435

399436
impl<T: VhostBackendMut> VhostBackend for RwLock<T> {
@@ -454,6 +491,14 @@ impl<T: VhostBackendMut> VhostBackend for RwLock<T> {
454491
fn set_vring_err(&self, queue_index: usize, fd: &EventFd) -> Result<()> {
455492
self.write().unwrap().set_vring_err(queue_index, fd)
456493
}
494+
495+
fn set_status(&self, status: u8) -> Result<()> {
496+
self.write().unwrap().set_status(status)
497+
}
498+
499+
fn get_status(&self) -> Result<u8> {
500+
self.write().unwrap().get_status()
501+
}
457502
}
458503

459504
impl<T: VhostBackendMut> VhostBackend for RefCell<T> {
@@ -512,6 +557,14 @@ impl<T: VhostBackendMut> VhostBackend for RefCell<T> {
512557
fn set_vring_err(&self, queue_index: usize, fd: &EventFd) -> Result<()> {
513558
self.borrow_mut().set_vring_err(queue_index, fd)
514559
}
560+
561+
fn set_status(&self, status: u8) -> Result<()> {
562+
self.borrow_mut().set_status(status)
563+
}
564+
565+
fn get_status(&self) -> Result<u8> {
566+
self.borrow_mut().get_status()
567+
}
515568
}
516569

517570
#[cfg(any(test, feature = "test-utils"))]
@@ -543,7 +596,9 @@ impl VhostUserMemoryRegionInfo {
543596
mod tests {
544597
use super::*;
545598

546-
struct MockBackend {}
599+
struct MockBackend {
600+
status:u8,
601+
}
547602

548603
impl VhostBackendMut for MockBackend {
549604
fn get_features(&mut self) -> Result<u64> {
@@ -625,11 +680,20 @@ mod tests {
625680
assert_eq!(queue_index, 1);
626681
Ok(())
627682
}
683+
684+
fn set_status(&mut self, status: u8) -> Result<()> {
685+
self.status = status;
686+
Ok(())
687+
}
688+
689+
fn get_status(&self) -> Result<u8> {
690+
Ok(self.status)
691+
}
628692
}
629693

630694
#[test]
631695
fn test_vring_backend_mut() {
632-
let b = RwLock::new(MockBackend {});
696+
let b = RwLock::new(MockBackend { status: 0 });
633697

634698
assert_eq!(b.get_features().unwrap(), 0x1);
635699
b.set_features(0x1).unwrap();

crates/vhost/src/vdpa.rs

Lines changed: 0 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -33,17 +33,6 @@ pub trait VhostVdpa: VhostBackend {
3333
/// The device ids follow the same definition of the device id defined in virtio-spec.
3434
fn get_device_id(&self) -> Result<u32>;
3535

36-
/// Get the status.
37-
/// The status bits follow the same definition of the device status defined in virtio-spec.
38-
fn get_status(&self) -> Result<u8>;
39-
40-
/// Set the status.
41-
/// The status bits follow the same definition of the device status defined in virtio-spec.
42-
///
43-
/// # Arguments
44-
/// * `status` - Status bits to set
45-
fn set_status(&self, status: u8) -> Result<()>;
46-
4736
/// Get the device configuration.
4837
///
4938
/// # Arguments

crates/vhost/src/vhost_user/master.rs

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ use std::os::unix::io::{AsRawFd, RawFd};
99
use std::os::unix::net::UnixStream;
1010
use std::path::Path;
1111
use std::sync::{Arc, Mutex, MutexGuard};
12+
use std::convert::TryFrom;
1213

1314
use vm_memory::ByteValued;
1415
use vmm_sys_util::eventfd::EventFd;
@@ -330,6 +331,26 @@ impl VhostBackend for Master {
330331
let hdr = node.send_fd_for_vring(MasterReq::SET_VRING_ERR, queue_index, fd.as_raw_fd())?;
331332
node.wait_for_ack(&hdr).map_err(|e| e.into())
332333
}
334+
335+
/// Set the status at the remote end (if supported)
336+
fn set_status(&self, status: u8) -> Result<()> {
337+
let mut node = self.node();
338+
// depends on VhostUserProtocolFeatures::STATUS
339+
node.check_proto_feature(VhostUserProtocolFeatures::STATUS)?;
340+
let val = VhostUserU64::new(status.into());
341+
node.send_request_with_body(MasterReq::SET_STATUS, &val, None)?;
342+
Ok(())
343+
}
344+
345+
/// Get the status from the remote end (if supported)
346+
fn get_status(&self) -> Result<u8> {
347+
let mut node = self.node();
348+
// depends on VhostUserProtocolFeatures::STATUS
349+
node.check_proto_feature(VhostUserProtocolFeatures::STATUS)?;
350+
let hdr = node.send_request_header(MasterReq::GET_STATUS, None)?;
351+
let reply = node.recv_reply::<VhostUserU64>(&hdr)?;
352+
u8::try_from(reply.value).or(error_code(VhostUserError::InvalidParam))
353+
}
333354
}
334355

335356
impl VhostUserMaster for Master {

crates/vhost/src/vhost_user/slave_req_handler.rs

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ use std::os::unix::io::{AsRawFd, FromRawFd, IntoRawFd, RawFd};
77
use std::os::unix::net::UnixStream;
88
use std::slice;
99
use std::sync::{Arc, Mutex};
10+
use std::convert::{TryFrom};
1011

1112
use vm_memory::ByteValued;
1213

@@ -70,6 +71,8 @@ pub trait VhostUserSlaveReqHandler {
7071
fn get_max_mem_slots(&self) -> Result<u64>;
7172
fn add_mem_region(&self, region: &VhostUserSingleMemoryRegion, fd: File) -> Result<()>;
7273
fn remove_mem_region(&self, region: &VhostUserSingleMemoryRegion) -> Result<()>;
74+
fn get_status(&self) -> Result<u8>;
75+
fn set_status(&self, status: u8) -> Result<()>;
7376
}
7477

7578
/// Services provided to the master by the slave without interior mutability.
@@ -118,6 +121,8 @@ pub trait VhostUserSlaveReqHandlerMut {
118121
fn get_max_mem_slots(&mut self) -> Result<u64>;
119122
fn add_mem_region(&mut self, region: &VhostUserSingleMemoryRegion, fd: File) -> Result<()>;
120123
fn remove_mem_region(&mut self, region: &VhostUserSingleMemoryRegion) -> Result<()>;
124+
fn get_status(&self) -> Result<u8>;
125+
fn set_status(&mut self, status: u8) -> Result<()>;
121126
}
122127

123128
impl<T: VhostUserSlaveReqHandlerMut> VhostUserSlaveReqHandler for Mutex<T> {
@@ -226,6 +231,14 @@ impl<T: VhostUserSlaveReqHandlerMut> VhostUserSlaveReqHandler for Mutex<T> {
226231
fn remove_mem_region(&self, region: &VhostUserSingleMemoryRegion) -> Result<()> {
227232
self.lock().unwrap().remove_mem_region(region)
228233
}
234+
235+
fn get_status(&self) -> Result<u8> {
236+
self.lock().unwrap().get_status()
237+
}
238+
239+
fn set_status(&self, status: u8) -> Result<()> {
240+
self.lock().unwrap().set_status(status)
241+
}
229242
}
230243

231244
/// Server to handle service requests from masters from the master communication channel.
@@ -519,6 +532,19 @@ impl<S: VhostUserSlaveReqHandler> SlaveReqHandler<S> {
519532
let res = self.backend.remove_mem_region(&msg);
520533
self.send_ack_message(&hdr, res)?;
521534
}
535+
Ok(MasterReq::SET_STATUS) => {
536+
self.check_proto_feature(VhostUserProtocolFeatures::STATUS)?;
537+
self.check_request_size(&hdr, size, hdr.get_size() as usize)?;
538+
let msg = self.extract_request_body::<VhostUserU64>(&hdr, size, &buf)?;
539+
let status = u8::try_from(msg.value).or(Err(Error::InvalidParam))?;
540+
self.backend.set_status(status)?;
541+
}
542+
Ok(MasterReq::GET_STATUS) => {
543+
self.check_proto_feature(VhostUserProtocolFeatures::STATUS)?;
544+
let num = self.backend.get_status()?;
545+
let msg = VhostUserU64::new(num.into());
546+
self.send_reply_message(&hdr, &msg)?;
547+
}
522548
_ => {
523549
return Err(Error::InvalidMessage);
524550
}

0 commit comments

Comments
 (0)