Skip to content

Commit c45ff89

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]> --- v2 - also add impls for DummySlaveReqHandler - move VhostVdpa impls to impl<T: VhostKernBackend> VhostBackend for T
1 parent 900b9a5 commit c45ff89

File tree

8 files changed

+149
-29
lines changed

8 files changed

+149
-29
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: 64 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -308,6 +308,30 @@ 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+
Err(Error::InvalidOperation)
323+
}
324+
325+
/// Get the status.
326+
///
327+
/// The status bits follow the same definition of the device
328+
/// status defined in virtio-spec.
329+
///
330+
/// As not all backends can implement this we provide a default
331+
/// implementation that returns an Error.
332+
fn get_status(&self) -> Result<u8> {
333+
Err(Error::InvalidOperation)
334+
}
311335
}
312336

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

399434
impl<T: VhostBackendMut> VhostBackend for RwLock<T> {
@@ -454,6 +489,14 @@ impl<T: VhostBackendMut> VhostBackend for RwLock<T> {
454489
fn set_vring_err(&self, queue_index: usize, fd: &EventFd) -> Result<()> {
455490
self.write().unwrap().set_vring_err(queue_index, fd)
456491
}
492+
493+
fn set_status(&self, status: u8) -> Result<()> {
494+
self.write().unwrap().set_status(status)
495+
}
496+
497+
fn get_status(&self) -> Result<u8> {
498+
self.write().unwrap().get_status()
499+
}
457500
}
458501

459502
impl<T: VhostBackendMut> VhostBackend for RefCell<T> {
@@ -512,6 +555,14 @@ impl<T: VhostBackendMut> VhostBackend for RefCell<T> {
512555
fn set_vring_err(&self, queue_index: usize, fd: &EventFd) -> Result<()> {
513556
self.borrow_mut().set_vring_err(queue_index, fd)
514557
}
558+
559+
fn set_status(&self, status: u8) -> Result<()> {
560+
self.borrow_mut().set_status(status)
561+
}
562+
563+
fn get_status(&self) -> Result<u8> {
564+
self.borrow_mut().get_status()
565+
}
515566
}
516567

517568
#[cfg(any(test, feature = "test-utils"))]
@@ -543,7 +594,9 @@ impl VhostUserMemoryRegionInfo {
543594
mod tests {
544595
use super::*;
545596

546-
struct MockBackend {}
597+
struct MockBackend {
598+
status: u8,
599+
}
547600

548601
impl VhostBackendMut for MockBackend {
549602
fn get_features(&mut self) -> Result<u64> {
@@ -625,11 +678,20 @@ mod tests {
625678
assert_eq!(queue_index, 1);
626679
Ok(())
627680
}
681+
682+
fn set_status(&mut self, status: u8) -> Result<()> {
683+
self.status = status;
684+
Ok(())
685+
}
686+
687+
fn get_status(&self) -> Result<u8> {
688+
Ok(self.status)
689+
}
628690
}
629691

630692
#[test]
631693
fn test_vring_backend_mut() {
632-
let b = RwLock::new(MockBackend {});
694+
let b = RwLock::new(MockBackend { status: 0 });
633695

634696
assert_eq!(b.get_features().unwrap(), 0x1);
635697
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_kern/mod.rs

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -291,6 +291,22 @@ impl<T: VhostKernBackend> VhostBackend for T {
291291
let ret = unsafe { ioctl_with_ref(self, VHOST_SET_VRING_ERR(), &vring_file) };
292292
ioctl_result(ret, ())
293293
}
294+
295+
fn get_status(&self) -> Result<u8> {
296+
let mut status: u8 = 0;
297+
298+
// SAFETY: This ioctl is called on a valid vhost-vdpa fd and has its
299+
// return value checked.
300+
let ret = unsafe { ioctl_with_mut_ref(self, VHOST_VDPA_GET_STATUS(), &mut status) };
301+
ioctl_result(ret, status)
302+
}
303+
304+
fn set_status(&self, status: u8) -> Result<()> {
305+
// SAFETY: This ioctl is called on a valid vhost-vdpa fd and has its
306+
// return value checked.
307+
let ret = unsafe { ioctl_with_ref(self, VHOST_VDPA_SET_STATUS(), &status) };
308+
ioctl_result(ret, ())
309+
}
294310
}
295311

296312
/// Interface to handle in-kernel backend features.

crates/vhost/src/vhost_kern/vdpa.rs

Lines changed: 0 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -101,22 +101,6 @@ impl<AS: GuestAddressSpace> VhostVdpa for VhostKernVdpa<AS> {
101101
ioctl_result(ret, device_id)
102102
}
103103

104-
fn get_status(&self) -> Result<u8> {
105-
let mut status: u8 = 0;
106-
107-
// SAFETY: This ioctl is called on a valid vhost-vdpa fd and has its
108-
// return value checked.
109-
let ret = unsafe { ioctl_with_mut_ref(self, VHOST_VDPA_GET_STATUS(), &mut status) };
110-
ioctl_result(ret, status)
111-
}
112-
113-
fn set_status(&self, status: u8) -> Result<()> {
114-
// SAFETY: This ioctl is called on a valid vhost-vdpa fd and has its
115-
// return value checked.
116-
let ret = unsafe { ioctl_with_ref(self, VHOST_VDPA_SET_STATUS(), &status) };
117-
ioctl_result(ret, ())
118-
}
119-
120104
fn get_config(&self, offset: u32, buffer: &mut [u8]) -> Result<()> {
121105
let mut config = VhostVdpaConfig::new(buffer.len())
122106
.map_err(|_| Error::IoctlError(IOError::from_raw_os_error(libc::ENOMEM)))?;

crates/vhost/src/vhost_user/dummy_slave.rs

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ pub struct DummySlaveReqHandler {
1717
pub features_acked: bool,
1818
pub acked_features: u64,
1919
pub acked_protocol_features: u64,
20+
pub status: u8,
2021
pub queue_num: usize,
2122
pub vring_num: [u32; MAX_QUEUE_NUM],
2223
pub vring_base: [u32; MAX_QUEUE_NUM],
@@ -291,4 +292,13 @@ impl VhostUserSlaveReqHandlerMut for DummySlaveReqHandler {
291292
fn remove_mem_region(&mut self, _region: &VhostUserSingleMemoryRegion) -> Result<()> {
292293
Ok(())
293294
}
295+
296+
fn get_status(&self) -> Result<u8> {
297+
Ok(self.status)
298+
}
299+
300+
fn set_status(&mut self, status: u8) -> Result<()> {
301+
self.status = status;
302+
Ok(())
303+
}
294304
}

crates/vhost/src/vhost_user/master.rs

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33

44
//! Traits and Struct for vhost-user master.
55
6+
use std::convert::TryFrom;
67
use std::fs::File;
78
use std::mem;
89
use std::os::unix::io::{AsRawFd, RawFd};
@@ -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
@@ -1,6 +1,7 @@
11
// Copyright (C) 2019 Alibaba Cloud Computing. All rights reserved.
22
// SPDX-License-Identifier: Apache-2.0
33

4+
use std::convert::TryFrom;
45
use std::fs::File;
56
use std::mem;
67
use std::os::unix::io::{AsRawFd, FromRawFd, IntoRawFd, RawFd};
@@ -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)