mirror of
https://github.com/cloud-hypervisor/cloud-hypervisor.git
synced 2026-08-05 02:19:16 +00:00
virtio-devices: Embed VirtioCommon in VhostUserCommon
Since vhost-user devices are always virtio devices it makes sense to structure this struct inside the VhostUserCommon struct. This then also makes some of the methods on VhostUserCommon cleaner since they can now act directly on the common virtio bits (e.g. for kill_evt) Signed-off-by: Rob Bradford <rbradford@meta.com>
This commit is contained in:
@@ -39,7 +39,6 @@ struct BackendReqHandler {}
|
||||
impl VhostUserFrontendReqHandler for BackendReqHandler {}
|
||||
|
||||
pub struct Blk {
|
||||
common: VirtioCommon,
|
||||
vu_common: VhostUserCommon,
|
||||
id: String,
|
||||
config: VirtioBlockConfig,
|
||||
@@ -170,17 +169,17 @@ impl Blk {
|
||||
};
|
||||
|
||||
Ok(Blk {
|
||||
common: VirtioCommon {
|
||||
device_type: VirtioDeviceType::Block as u32,
|
||||
queue_sizes: vec![vu_cfg.queue_size; num_queues],
|
||||
avail_features,
|
||||
acked_features,
|
||||
paused_sync: Some(Arc::new(Barrier::new(2))),
|
||||
min_queues: DEFAULT_QUEUE_NUMBER as u16,
|
||||
paused: Arc::new(AtomicBool::new(paused)),
|
||||
..Default::default()
|
||||
},
|
||||
vu_common: VhostUserCommon {
|
||||
virtio_common: VirtioCommon {
|
||||
device_type: VirtioDeviceType::Block as u32,
|
||||
queue_sizes: vec![vu_cfg.queue_size; num_queues],
|
||||
avail_features,
|
||||
acked_features,
|
||||
paused_sync: Some(Arc::new(Barrier::new(2))),
|
||||
min_queues: DEFAULT_QUEUE_NUMBER as u16,
|
||||
paused: Arc::new(AtomicBool::new(paused)),
|
||||
..Default::default()
|
||||
},
|
||||
vu: Some(Arc::new(Mutex::new(vu))),
|
||||
acked_protocol_features,
|
||||
socket_path: vu_cfg.socket,
|
||||
@@ -199,18 +198,18 @@ impl Blk {
|
||||
}
|
||||
|
||||
fn state(&self) -> std::result::Result<State, MigratableError> {
|
||||
self.vu_common.state(&self.common, self.config)
|
||||
self.vu_common.state(self.config)
|
||||
}
|
||||
}
|
||||
|
||||
impl Drop for Blk {
|
||||
fn drop(&mut self) {
|
||||
if let Some(kill_evt) = self.common.kill_evt.take()
|
||||
if let Some(kill_evt) = self.vu_common.virtio_common.kill_evt.take()
|
||||
&& let Err(e) = kill_evt.write(1)
|
||||
{
|
||||
error!("failed to kill vhost-user-blk: {e:?}");
|
||||
}
|
||||
self.common.wait_for_epoll_threads();
|
||||
self.vu_common.virtio_common.wait_for_epoll_threads();
|
||||
if let Some(thread) = self.epoll_thread.take()
|
||||
&& let Err(e) = thread.join()
|
||||
{
|
||||
@@ -221,15 +220,15 @@ impl Drop for Blk {
|
||||
|
||||
impl VirtioDevice for Blk {
|
||||
fn device_type(&self) -> u32 {
|
||||
self.common.device_type
|
||||
self.vu_common.virtio_common.device_type
|
||||
}
|
||||
|
||||
fn queue_max_sizes(&self) -> &[u16] {
|
||||
&self.common.queue_sizes
|
||||
&self.vu_common.virtio_common.queue_sizes
|
||||
}
|
||||
|
||||
fn features(&self) -> u64 {
|
||||
let mut features = self.common.avail_features;
|
||||
let mut features = self.vu_common.virtio_common.avail_features;
|
||||
if self.iommu {
|
||||
features |= 1u64 << VIRTIO_F_ACCESS_PLATFORM;
|
||||
}
|
||||
@@ -237,7 +236,7 @@ impl VirtioDevice for Blk {
|
||||
}
|
||||
|
||||
fn ack_features(&mut self, value: u64) {
|
||||
self.common.ack_features(value);
|
||||
self.vu_common.virtio_common.ack_features(value);
|
||||
}
|
||||
|
||||
fn read_config(&self, offset: u64, data: &mut [u8]) {
|
||||
@@ -278,27 +277,29 @@ impl VirtioDevice for Blk {
|
||||
queues,
|
||||
..
|
||||
} = context;
|
||||
self.common.activate(&queues, interrupt_cb.clone())?;
|
||||
self.vu_common
|
||||
.virtio_common
|
||||
.activate(&queues, interrupt_cb.clone())?;
|
||||
self.guest_memory = Some(mem.clone());
|
||||
|
||||
let backend_req_handler: Option<FrontendReqHandler<BackendReqHandler>> = None;
|
||||
|
||||
// Run a dedicated thread for handling potential reconnections with
|
||||
// the backend.
|
||||
let (kill_evt, pause_evt) = self.common.dup_eventfds();
|
||||
let (kill_evt, pause_evt) = self.vu_common.virtio_common.dup_eventfds();
|
||||
|
||||
let mut handler = self.vu_common.activate(
|
||||
mem,
|
||||
&queues,
|
||||
interrupt_cb,
|
||||
self.common.acked_features,
|
||||
self.vu_common.virtio_common.acked_features,
|
||||
backend_req_handler,
|
||||
kill_evt,
|
||||
pause_evt,
|
||||
)?;
|
||||
|
||||
let paused = self.common.paused.clone();
|
||||
let paused_sync = self.common.paused_sync.clone();
|
||||
let paused = self.vu_common.virtio_common.paused.clone();
|
||||
let paused_sync = self.vu_common.virtio_common.paused_sync.clone();
|
||||
|
||||
let mut epoll_threads = Vec::new();
|
||||
|
||||
@@ -317,8 +318,8 @@ impl VirtioDevice for Blk {
|
||||
|
||||
fn reset(&mut self) -> Option<Arc<dyn VirtioInterrupt>> {
|
||||
// We first must resume the virtio thread if it was paused.
|
||||
if self.common.pause_evt.take().is_some() {
|
||||
self.common.resume().ok()?;
|
||||
if self.vu_common.virtio_common.pause_evt.take().is_some() {
|
||||
self.vu_common.virtio_common.resume().ok()?;
|
||||
}
|
||||
|
||||
if let Some(vu) = &self.vu_common.vu
|
||||
@@ -328,7 +329,7 @@ impl VirtioDevice for Blk {
|
||||
return None;
|
||||
}
|
||||
|
||||
if let Some(kill_evt) = self.common.kill_evt.take() {
|
||||
if let Some(kill_evt) = self.vu_common.virtio_common.kill_evt.take() {
|
||||
// Ignore the result because there is nothing we can do about it.
|
||||
let _ = kill_evt.write(1);
|
||||
}
|
||||
@@ -336,7 +337,7 @@ impl VirtioDevice for Blk {
|
||||
event!("virtio-device", "reset", "id", &self.id);
|
||||
|
||||
// Return the interrupt
|
||||
Some(self.common.interrupt_cb.take().unwrap())
|
||||
Some(self.vu_common.virtio_common.interrupt_cb.take().unwrap())
|
||||
}
|
||||
|
||||
fn shutdown(&mut self) {
|
||||
@@ -354,11 +355,11 @@ impl VirtioDevice for Blk {
|
||||
impl Pausable for Blk {
|
||||
fn pause(&mut self) -> result::Result<(), MigratableError> {
|
||||
self.vu_common.pause()?;
|
||||
self.common.pause()
|
||||
self.vu_common.virtio_common.pause()
|
||||
}
|
||||
|
||||
fn resume(&mut self) -> result::Result<(), MigratableError> {
|
||||
self.common.resume()?;
|
||||
self.vu_common.virtio_common.resume()?;
|
||||
|
||||
if let Some(epoll_thread) = &self.epoll_thread {
|
||||
epoll_thread.thread().unpark();
|
||||
@@ -397,7 +398,6 @@ impl Migratable for Blk {
|
||||
}
|
||||
|
||||
fn complete_migration(&mut self) -> std::result::Result<(), MigratableError> {
|
||||
self.vu_common
|
||||
.complete_migration(self.common.kill_evt.take())
|
||||
self.vu_common.complete_migration()
|
||||
}
|
||||
}
|
||||
|
||||
@@ -59,7 +59,6 @@ impl Default for VirtioFsConfig {
|
||||
unsafe impl ByteValued for VirtioFsConfig {}
|
||||
|
||||
pub struct Fs {
|
||||
common: VirtioCommon,
|
||||
vu_common: VhostUserCommon,
|
||||
id: String,
|
||||
config: VirtioFsConfig,
|
||||
@@ -178,17 +177,17 @@ impl Fs {
|
||||
};
|
||||
|
||||
Ok(Fs {
|
||||
common: VirtioCommon {
|
||||
device_type: VirtioDeviceType::Fs as u32,
|
||||
avail_features,
|
||||
acked_features,
|
||||
queue_sizes: vec![queue_size; num_queues],
|
||||
paused_sync: Some(Arc::new(Barrier::new(2))),
|
||||
min_queues: 1,
|
||||
paused: Arc::new(AtomicBool::new(paused)),
|
||||
..Default::default()
|
||||
},
|
||||
vu_common: VhostUserCommon {
|
||||
virtio_common: VirtioCommon {
|
||||
device_type: VirtioDeviceType::Fs as u32,
|
||||
avail_features,
|
||||
acked_features,
|
||||
queue_sizes: vec![queue_size; num_queues],
|
||||
paused_sync: Some(Arc::new(Barrier::new(2))),
|
||||
min_queues: 1,
|
||||
paused: Arc::new(AtomicBool::new(paused)),
|
||||
..Default::default()
|
||||
},
|
||||
vu: Some(Arc::new(Mutex::new(vu))),
|
||||
acked_protocol_features,
|
||||
socket_path: path.to_string(),
|
||||
@@ -208,17 +207,17 @@ impl Fs {
|
||||
}
|
||||
|
||||
fn state(&self) -> std::result::Result<State, MigratableError> {
|
||||
self.vu_common.state(&self.common, self.config)
|
||||
self.vu_common.state(self.config)
|
||||
}
|
||||
}
|
||||
|
||||
impl Drop for Fs {
|
||||
fn drop(&mut self) {
|
||||
if let Some(kill_evt) = self.common.kill_evt.take() {
|
||||
if let Some(kill_evt) = self.vu_common.virtio_common.kill_evt.take() {
|
||||
// Ignore the result because there is nothing we can do about it.
|
||||
let _ = kill_evt.write(1);
|
||||
}
|
||||
self.common.wait_for_epoll_threads();
|
||||
self.vu_common.virtio_common.wait_for_epoll_threads();
|
||||
if let Some(thread) = self.epoll_thread.take()
|
||||
&& let Err(e) = thread.join()
|
||||
{
|
||||
@@ -229,15 +228,15 @@ impl Drop for Fs {
|
||||
|
||||
impl VirtioDevice for Fs {
|
||||
fn device_type(&self) -> u32 {
|
||||
self.common.device_type
|
||||
self.vu_common.virtio_common.device_type
|
||||
}
|
||||
|
||||
fn queue_max_sizes(&self) -> &[u16] {
|
||||
&self.common.queue_sizes
|
||||
&self.vu_common.virtio_common.queue_sizes
|
||||
}
|
||||
|
||||
fn features(&self) -> u64 {
|
||||
let mut features = self.common.avail_features;
|
||||
let mut features = self.vu_common.virtio_common.avail_features;
|
||||
if self.iommu {
|
||||
features |= 1u64 << VIRTIO_F_ACCESS_PLATFORM;
|
||||
}
|
||||
@@ -245,7 +244,7 @@ impl VirtioDevice for Fs {
|
||||
}
|
||||
|
||||
fn ack_features(&mut self, value: u64) {
|
||||
self.common.ack_features(value);
|
||||
self.vu_common.virtio_common.ack_features(value);
|
||||
}
|
||||
|
||||
fn read_config(&self, offset: u64, data: &mut [u8]) {
|
||||
@@ -259,26 +258,28 @@ impl VirtioDevice for Fs {
|
||||
queues,
|
||||
..
|
||||
} = context;
|
||||
self.common.activate(&queues, interrupt_cb.clone())?;
|
||||
self.vu_common
|
||||
.virtio_common
|
||||
.activate(&queues, interrupt_cb.clone())?;
|
||||
self.guest_memory = Some(mem.clone());
|
||||
|
||||
let backend_req_handler: Option<FrontendReqHandler<BackendReqHandler>> = None;
|
||||
// Run a dedicated thread for handling potential reconnections with
|
||||
// the backend.
|
||||
let (kill_evt, pause_evt) = self.common.dup_eventfds();
|
||||
let (kill_evt, pause_evt) = self.vu_common.virtio_common.dup_eventfds();
|
||||
|
||||
let mut handler = self.vu_common.activate(
|
||||
mem,
|
||||
&queues,
|
||||
interrupt_cb,
|
||||
self.common.acked_features,
|
||||
self.vu_common.virtio_common.acked_features,
|
||||
backend_req_handler,
|
||||
kill_evt,
|
||||
pause_evt,
|
||||
)?;
|
||||
|
||||
let paused = self.common.paused.clone();
|
||||
let paused_sync = self.common.paused_sync.clone();
|
||||
let paused = self.vu_common.virtio_common.paused.clone();
|
||||
let paused_sync = self.vu_common.virtio_common.paused_sync.clone();
|
||||
|
||||
let mut epoll_threads = Vec::new();
|
||||
spawn_virtio_thread(
|
||||
@@ -297,8 +298,8 @@ impl VirtioDevice for Fs {
|
||||
|
||||
fn reset(&mut self) -> Option<Arc<dyn VirtioInterrupt>> {
|
||||
// We first must resume the virtio thread if it was paused.
|
||||
if self.common.pause_evt.take().is_some() {
|
||||
self.common.resume().ok()?;
|
||||
if self.vu_common.virtio_common.pause_evt.take().is_some() {
|
||||
self.vu_common.virtio_common.resume().ok()?;
|
||||
}
|
||||
|
||||
if let Some(vu) = &self.vu_common.vu
|
||||
@@ -308,7 +309,7 @@ impl VirtioDevice for Fs {
|
||||
return None;
|
||||
}
|
||||
|
||||
if let Some(kill_evt) = self.common.kill_evt.take() {
|
||||
if let Some(kill_evt) = self.vu_common.virtio_common.kill_evt.take() {
|
||||
// Ignore the result because there is nothing we can do about it.
|
||||
let _ = kill_evt.write(1);
|
||||
}
|
||||
@@ -316,7 +317,7 @@ impl VirtioDevice for Fs {
|
||||
event!("virtio-device", "reset", "id", &self.id);
|
||||
|
||||
// Return the interrupt
|
||||
Some(self.common.interrupt_cb.take().unwrap())
|
||||
Some(self.vu_common.virtio_common.interrupt_cb.take().unwrap())
|
||||
}
|
||||
|
||||
fn shutdown(&mut self) {
|
||||
@@ -364,11 +365,11 @@ impl VirtioDevice for Fs {
|
||||
impl Pausable for Fs {
|
||||
fn pause(&mut self) -> result::Result<(), MigratableError> {
|
||||
self.vu_common.pause()?;
|
||||
self.common.pause()
|
||||
self.vu_common.virtio_common.pause()
|
||||
}
|
||||
|
||||
fn resume(&mut self) -> result::Result<(), MigratableError> {
|
||||
self.common.resume()?;
|
||||
self.vu_common.virtio_common.resume()?;
|
||||
|
||||
if let Some(epoll_thread) = &self.epoll_thread {
|
||||
epoll_thread.thread().unpark();
|
||||
@@ -407,7 +408,6 @@ impl Migratable for Fs {
|
||||
}
|
||||
|
||||
fn complete_migration(&mut self) -> std::result::Result<(), MigratableError> {
|
||||
self.vu_common
|
||||
.complete_migration(self.common.kill_evt.take())
|
||||
self.vu_common.complete_migration()
|
||||
}
|
||||
}
|
||||
|
||||
@@ -34,7 +34,6 @@ pub type State = VhostUserState<()>;
|
||||
struct BackendReqHandler {}
|
||||
impl VhostUserFrontendReqHandler for BackendReqHandler {}
|
||||
pub struct GenericVhostUser {
|
||||
common: VirtioCommon,
|
||||
vu_common: VhostUserCommon,
|
||||
id: String,
|
||||
// Hold ownership of the memory that is allocated for the device
|
||||
@@ -138,17 +137,17 @@ since the backend only supports {backend_num_queues}\n",
|
||||
};
|
||||
|
||||
Ok(GenericVhostUser {
|
||||
common: VirtioCommon {
|
||||
device_type,
|
||||
avail_features,
|
||||
acked_features,
|
||||
queue_sizes: request_queue_sizes,
|
||||
paused_sync: Some(Arc::new(Barrier::new(2))),
|
||||
min_queues: 1,
|
||||
paused: Arc::new(AtomicBool::new(paused)),
|
||||
..Default::default()
|
||||
},
|
||||
vu_common: VhostUserCommon {
|
||||
virtio_common: VirtioCommon {
|
||||
device_type,
|
||||
avail_features,
|
||||
acked_features,
|
||||
queue_sizes: request_queue_sizes,
|
||||
paused_sync: Some(Arc::new(Barrier::new(2))),
|
||||
min_queues: 1,
|
||||
paused: Arc::new(AtomicBool::new(paused)),
|
||||
..Default::default()
|
||||
},
|
||||
vu: Some(Arc::new(Mutex::new(vu))),
|
||||
acked_protocol_features,
|
||||
socket_path: path.to_string(),
|
||||
@@ -168,7 +167,7 @@ since the backend only supports {backend_num_queues}\n",
|
||||
}
|
||||
|
||||
fn state(&self) -> std::result::Result<State, MigratableError> {
|
||||
self.vu_common.state(&self.common, ())
|
||||
self.vu_common.state(())
|
||||
}
|
||||
|
||||
#[cold]
|
||||
@@ -189,11 +188,11 @@ space access. Reads will return 0xFF and writes will be ignored."
|
||||
|
||||
impl Drop for GenericVhostUser {
|
||||
fn drop(&mut self) {
|
||||
if let Some(kill_evt) = self.common.kill_evt.take() {
|
||||
if let Some(kill_evt) = self.vu_common.virtio_common.kill_evt.take() {
|
||||
// Ignore the result because there is nothing we can do about it.
|
||||
let _ = kill_evt.write(1);
|
||||
}
|
||||
self.common.wait_for_epoll_threads();
|
||||
self.vu_common.virtio_common.wait_for_epoll_threads();
|
||||
if let Some(thread) = self.epoll_thread.take()
|
||||
&& let Err(e) = thread.join()
|
||||
{
|
||||
@@ -204,15 +203,15 @@ impl Drop for GenericVhostUser {
|
||||
|
||||
impl VirtioDevice for GenericVhostUser {
|
||||
fn device_type(&self) -> u32 {
|
||||
self.common.device_type
|
||||
self.vu_common.virtio_common.device_type
|
||||
}
|
||||
|
||||
fn queue_max_sizes(&self) -> &[u16] {
|
||||
&self.common.queue_sizes
|
||||
&self.vu_common.virtio_common.queue_sizes
|
||||
}
|
||||
|
||||
fn features(&self) -> u64 {
|
||||
let mut features = self.common.avail_features;
|
||||
let mut features = self.vu_common.virtio_common.avail_features;
|
||||
if self.iommu {
|
||||
features |= 1u64 << VIRTIO_F_ACCESS_PLATFORM;
|
||||
}
|
||||
@@ -220,7 +219,7 @@ impl VirtioDevice for GenericVhostUser {
|
||||
}
|
||||
|
||||
fn ack_features(&mut self, value: u64) {
|
||||
self.common.ack_features(value);
|
||||
self.vu_common.virtio_common.ack_features(value);
|
||||
}
|
||||
|
||||
fn read_config(&self, offset: u64, data: &mut [u8]) {
|
||||
@@ -282,26 +281,28 @@ impl VirtioDevice for GenericVhostUser {
|
||||
queues,
|
||||
..
|
||||
} = context;
|
||||
self.common.activate(&queues, interrupt_cb.clone())?;
|
||||
self.vu_common
|
||||
.virtio_common
|
||||
.activate(&queues, interrupt_cb.clone())?;
|
||||
self.guest_memory = Some(mem.clone());
|
||||
|
||||
let backend_req_handler: Option<FrontendReqHandler<BackendReqHandler>> = None;
|
||||
// Run a dedicated thread for handling potential reconnections with
|
||||
// the backend.
|
||||
let (kill_evt, pause_evt) = self.common.dup_eventfds();
|
||||
let (kill_evt, pause_evt) = self.vu_common.virtio_common.dup_eventfds();
|
||||
|
||||
let mut handler = self.vu_common.activate(
|
||||
mem,
|
||||
&queues,
|
||||
interrupt_cb,
|
||||
self.common.acked_features,
|
||||
self.vu_common.virtio_common.acked_features,
|
||||
backend_req_handler,
|
||||
kill_evt,
|
||||
pause_evt,
|
||||
)?;
|
||||
|
||||
let paused = self.common.paused.clone();
|
||||
let paused_sync = self.common.paused_sync.clone();
|
||||
let paused = self.vu_common.virtio_common.paused.clone();
|
||||
let paused_sync = self.vu_common.virtio_common.paused_sync.clone();
|
||||
|
||||
let mut epoll_threads = Vec::new();
|
||||
spawn_virtio_thread(
|
||||
@@ -320,8 +321,8 @@ impl VirtioDevice for GenericVhostUser {
|
||||
|
||||
fn reset(&mut self) -> Option<Arc<dyn VirtioInterrupt>> {
|
||||
// We first must resume the virtio thread if it was paused.
|
||||
if self.common.pause_evt.take().is_some() {
|
||||
self.common.resume().ok()?;
|
||||
if self.vu_common.virtio_common.pause_evt.take().is_some() {
|
||||
self.vu_common.virtio_common.resume().ok()?;
|
||||
}
|
||||
|
||||
if let Some(vu) = &self.vu_common.vu
|
||||
@@ -331,7 +332,7 @@ impl VirtioDevice for GenericVhostUser {
|
||||
return None;
|
||||
}
|
||||
|
||||
if let Some(kill_evt) = self.common.kill_evt.take() {
|
||||
if let Some(kill_evt) = self.vu_common.virtio_common.kill_evt.take() {
|
||||
// Ignore the result because there is nothing we can do about it.
|
||||
let _ = kill_evt.write(1);
|
||||
}
|
||||
@@ -339,7 +340,7 @@ impl VirtioDevice for GenericVhostUser {
|
||||
event!("virtio-device", "reset", "id", &self.id);
|
||||
|
||||
// Return the interrupt
|
||||
Some(self.common.interrupt_cb.take().unwrap())
|
||||
Some(self.vu_common.virtio_common.interrupt_cb.take().unwrap())
|
||||
}
|
||||
|
||||
fn shutdown(&mut self) {
|
||||
@@ -387,11 +388,11 @@ impl VirtioDevice for GenericVhostUser {
|
||||
impl Pausable for GenericVhostUser {
|
||||
fn pause(&mut self) -> result::Result<(), MigratableError> {
|
||||
self.vu_common.pause()?;
|
||||
self.common.pause()
|
||||
self.vu_common.virtio_common.pause()
|
||||
}
|
||||
|
||||
fn resume(&mut self) -> result::Result<(), MigratableError> {
|
||||
self.common.resume()?;
|
||||
self.vu_common.virtio_common.resume()?;
|
||||
|
||||
if let Some(epoll_thread) = &self.epoll_thread {
|
||||
epoll_thread.thread().unpark();
|
||||
@@ -430,7 +431,6 @@ impl Migratable for GenericVhostUser {
|
||||
}
|
||||
|
||||
fn complete_migration(&mut self) -> std::result::Result<(), MigratableError> {
|
||||
self.vu_common
|
||||
.complete_migration(self.common.kill_evt.take())
|
||||
self.vu_common.complete_migration()
|
||||
}
|
||||
}
|
||||
|
||||
@@ -29,7 +29,7 @@ use crate::{
|
||||
ActivateError, EPOLL_HELPER_EVENT_LAST, EpollHelper, EpollHelperError, EpollHelperHandler,
|
||||
GuestMemoryMmap, GuestRegionMmap, VIRTIO_F_IN_ORDER, VIRTIO_F_NOTIFICATION_DATA,
|
||||
VIRTIO_F_ORDER_PLATFORM, VIRTIO_F_RING_EVENT_IDX, VIRTIO_F_RING_INDIRECT_DESC,
|
||||
VIRTIO_F_VERSION_1, VirtioInterrupt,
|
||||
VIRTIO_F_VERSION_1, VirtioCommon, VirtioInterrupt,
|
||||
};
|
||||
|
||||
pub mod blk;
|
||||
@@ -336,6 +336,7 @@ impl<C> VhostUserState<C> {
|
||||
|
||||
#[derive(Default)]
|
||||
pub struct VhostUserCommon {
|
||||
pub virtio_common: VirtioCommon,
|
||||
pub vu: Option<Arc<Mutex<VhostUserHandle>>>,
|
||||
pub acked_protocol_features: u64,
|
||||
pub socket_path: String,
|
||||
@@ -485,12 +486,11 @@ impl VhostUserCommon {
|
||||
|
||||
pub fn state<C: Default>(
|
||||
&self,
|
||||
common: &crate::VirtioCommon,
|
||||
config: C,
|
||||
) -> std::result::Result<VhostUserState<C>, MigratableError> {
|
||||
let mut state = VhostUserState {
|
||||
avail_features: common.avail_features,
|
||||
acked_features: common.acked_features,
|
||||
avail_features: self.virtio_common.avail_features,
|
||||
acked_features: self.virtio_common.acked_features,
|
||||
config,
|
||||
acked_protocol_features: self.acked_protocol_features,
|
||||
vu_num_queues: self.vu_num_queues,
|
||||
@@ -586,15 +586,12 @@ impl VhostUserCommon {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn complete_migration(
|
||||
&mut self,
|
||||
kill_evt: Option<EventFd>,
|
||||
) -> std::result::Result<(), MigratableError> {
|
||||
pub fn complete_migration(&mut self) -> std::result::Result<(), MigratableError> {
|
||||
self.migration_started = false;
|
||||
|
||||
// Make sure the device thread is killed in order to prevent from
|
||||
// reconnections to the socket.
|
||||
if let Some(kill_evt) = kill_evt {
|
||||
if let Some(kill_evt) = self.virtio_common.kill_evt.take() {
|
||||
kill_evt.write(1).map_err(|e| {
|
||||
MigratableError::CompleteMigration(anyhow!(
|
||||
"Error killing vhost-user thread: {e:?}"
|
||||
|
||||
@@ -41,7 +41,6 @@ struct BackendReqHandler {}
|
||||
impl VhostUserFrontendReqHandler for BackendReqHandler {}
|
||||
|
||||
pub struct Net {
|
||||
common: VirtioCommon,
|
||||
vu_common: VhostUserCommon,
|
||||
id: String,
|
||||
config: VirtioNetConfig,
|
||||
@@ -198,17 +197,17 @@ impl Net {
|
||||
|
||||
Ok(Net {
|
||||
id,
|
||||
common: VirtioCommon {
|
||||
device_type: VirtioDeviceType::Net as u32,
|
||||
queue_sizes: vec![vu_cfg.queue_size; num_queues],
|
||||
avail_features,
|
||||
acked_features,
|
||||
paused_sync: Some(Arc::new(Barrier::new(2))),
|
||||
min_queues: DEFAULT_QUEUE_NUMBER as u16,
|
||||
paused: Arc::new(AtomicBool::new(paused)),
|
||||
..Default::default()
|
||||
},
|
||||
vu_common: VhostUserCommon {
|
||||
virtio_common: VirtioCommon {
|
||||
device_type: VirtioDeviceType::Net as u32,
|
||||
queue_sizes: vec![vu_cfg.queue_size; num_queues],
|
||||
avail_features,
|
||||
acked_features,
|
||||
paused_sync: Some(Arc::new(Barrier::new(2))),
|
||||
min_queues: DEFAULT_QUEUE_NUMBER as u16,
|
||||
paused: Arc::new(AtomicBool::new(paused)),
|
||||
..Default::default()
|
||||
},
|
||||
vu: Some(Arc::new(Mutex::new(vu))),
|
||||
acked_protocol_features,
|
||||
socket_path: vu_cfg.socket,
|
||||
@@ -228,19 +227,19 @@ impl Net {
|
||||
}
|
||||
|
||||
fn state(&self) -> std::result::Result<State, MigratableError> {
|
||||
self.vu_common.state(&self.common, self.config)
|
||||
self.vu_common.state(self.config)
|
||||
}
|
||||
}
|
||||
|
||||
impl Drop for Net {
|
||||
fn drop(&mut self) {
|
||||
if let Some(kill_evt) = self.common.kill_evt.take()
|
||||
if let Some(kill_evt) = self.vu_common.virtio_common.kill_evt.take()
|
||||
&& let Err(e) = kill_evt.write(1)
|
||||
{
|
||||
error!("failed to kill vhost-user-net: {e:?}");
|
||||
}
|
||||
|
||||
self.common.wait_for_epoll_threads();
|
||||
self.vu_common.virtio_common.wait_for_epoll_threads();
|
||||
|
||||
if let Some(thread) = self.epoll_thread.take()
|
||||
&& let Err(e) = thread.join()
|
||||
@@ -258,15 +257,15 @@ impl Drop for Net {
|
||||
|
||||
impl VirtioDevice for Net {
|
||||
fn device_type(&self) -> u32 {
|
||||
self.common.device_type
|
||||
self.vu_common.virtio_common.device_type
|
||||
}
|
||||
|
||||
fn queue_max_sizes(&self) -> &[u16] {
|
||||
&self.common.queue_sizes
|
||||
&self.vu_common.virtio_common.queue_sizes
|
||||
}
|
||||
|
||||
fn features(&self) -> u64 {
|
||||
let mut features = self.common.avail_features;
|
||||
let mut features = self.vu_common.virtio_common.avail_features;
|
||||
if self.iommu {
|
||||
features |= 1u64 << VIRTIO_F_ACCESS_PLATFORM;
|
||||
}
|
||||
@@ -274,7 +273,7 @@ impl VirtioDevice for Net {
|
||||
}
|
||||
|
||||
fn ack_features(&mut self, value: u64) {
|
||||
self.common.ack_features(value);
|
||||
self.vu_common.virtio_common.ack_features(value);
|
||||
}
|
||||
|
||||
fn read_config(&self, offset: u64, data: &mut [u8]) {
|
||||
@@ -288,18 +287,28 @@ impl VirtioDevice for Net {
|
||||
mut queues,
|
||||
..
|
||||
} = context;
|
||||
self.common.activate(&queues, interrupt_cb.clone())?;
|
||||
self.vu_common
|
||||
.virtio_common
|
||||
.activate(&queues, interrupt_cb.clone())?;
|
||||
self.guest_memory = Some(mem.clone());
|
||||
|
||||
let num_queues = queues.len();
|
||||
let event_idx = self.common.feature_acked(VIRTIO_RING_F_EVENT_IDX.into());
|
||||
if self.common.feature_acked(VIRTIO_NET_F_CTRL_VQ.into()) && !num_queues.is_multiple_of(2) {
|
||||
let event_idx = self
|
||||
.vu_common
|
||||
.virtio_common
|
||||
.feature_acked(VIRTIO_RING_F_EVENT_IDX.into());
|
||||
if self
|
||||
.vu_common
|
||||
.virtio_common
|
||||
.feature_acked(VIRTIO_NET_F_CTRL_VQ.into())
|
||||
&& !num_queues.is_multiple_of(2)
|
||||
{
|
||||
let ctrl_queue_index = num_queues - 1;
|
||||
let (_, mut ctrl_queue, ctrl_queue_evt) = queues.remove(ctrl_queue_index);
|
||||
|
||||
ctrl_queue.set_event_idx(event_idx);
|
||||
|
||||
let (kill_evt, pause_evt) = self.common.dup_eventfds();
|
||||
let (kill_evt, pause_evt) = self.vu_common.virtio_common.dup_eventfds();
|
||||
|
||||
let mut ctrl_handler = NetCtrlEpollHandler {
|
||||
mem: mem.clone(),
|
||||
@@ -313,12 +322,12 @@ impl VirtioDevice for Net {
|
||||
queue_index: ctrl_queue_index as u16,
|
||||
};
|
||||
|
||||
let paused = self.common.paused.clone();
|
||||
let paused = self.vu_common.virtio_common.paused.clone();
|
||||
// Let's update the barrier as we need 1 for the control queue
|
||||
// thread + 1 for the common vhost-user thread + 1 for the main
|
||||
// thread signalling the pause.
|
||||
self.common.paused_sync = Some(Arc::new(Barrier::new(3)));
|
||||
let paused_sync = self.common.paused_sync.clone();
|
||||
self.vu_common.virtio_common.paused_sync = Some(Arc::new(Barrier::new(3)));
|
||||
let paused_sync = self.vu_common.virtio_common.paused_sync.clone();
|
||||
|
||||
let mut epoll_threads = Vec::new();
|
||||
spawn_virtio_thread(
|
||||
@@ -336,11 +345,12 @@ impl VirtioDevice for Net {
|
||||
|
||||
// The backend acknowledged features must not contain VIRTIO_NET_F_MAC
|
||||
// since we don't expect the backend to handle it.
|
||||
let backend_acked_features = self.common.acked_features & !(1 << VIRTIO_NET_F_MAC);
|
||||
let backend_acked_features =
|
||||
self.vu_common.virtio_common.acked_features & !(1 << VIRTIO_NET_F_MAC);
|
||||
|
||||
// Run a dedicated thread for handling potential reconnections with
|
||||
// the backend.
|
||||
let (kill_evt, pause_evt) = self.common.dup_eventfds();
|
||||
let (kill_evt, pause_evt) = self.vu_common.virtio_common.dup_eventfds();
|
||||
|
||||
let mut handler = self.vu_common.activate(
|
||||
mem,
|
||||
@@ -352,8 +362,8 @@ impl VirtioDevice for Net {
|
||||
pause_evt,
|
||||
)?;
|
||||
|
||||
let paused = self.common.paused.clone();
|
||||
let paused_sync = self.common.paused_sync.clone();
|
||||
let paused = self.vu_common.virtio_common.paused.clone();
|
||||
let paused_sync = self.vu_common.virtio_common.paused_sync.clone();
|
||||
|
||||
let mut epoll_threads = Vec::new();
|
||||
spawn_virtio_thread(
|
||||
@@ -371,8 +381,8 @@ impl VirtioDevice for Net {
|
||||
|
||||
fn reset(&mut self) -> Option<Arc<dyn VirtioInterrupt>> {
|
||||
// We first must resume the virtio thread if it was paused.
|
||||
if self.common.pause_evt.take().is_some() {
|
||||
self.common.resume().ok()?;
|
||||
if self.vu_common.virtio_common.pause_evt.take().is_some() {
|
||||
self.vu_common.virtio_common.resume().ok()?;
|
||||
}
|
||||
|
||||
if let Some(vu) = &self.vu_common.vu
|
||||
@@ -382,7 +392,7 @@ impl VirtioDevice for Net {
|
||||
return None;
|
||||
}
|
||||
|
||||
if let Some(kill_evt) = self.common.kill_evt.take() {
|
||||
if let Some(kill_evt) = self.vu_common.virtio_common.kill_evt.take() {
|
||||
// Ignore the result because there is nothing we can do about it.
|
||||
let _ = kill_evt.write(1);
|
||||
}
|
||||
@@ -390,7 +400,7 @@ impl VirtioDevice for Net {
|
||||
event!("virtio-device", "reset", "id", &self.id);
|
||||
|
||||
// Return the interrupt
|
||||
Some(self.common.interrupt_cb.take().unwrap())
|
||||
Some(self.vu_common.virtio_common.interrupt_cb.take().unwrap())
|
||||
}
|
||||
|
||||
fn shutdown(&mut self) {
|
||||
@@ -408,11 +418,11 @@ impl VirtioDevice for Net {
|
||||
impl Pausable for Net {
|
||||
fn pause(&mut self) -> result::Result<(), MigratableError> {
|
||||
self.vu_common.pause()?;
|
||||
self.common.pause()
|
||||
self.vu_common.virtio_common.pause()
|
||||
}
|
||||
|
||||
fn resume(&mut self) -> result::Result<(), MigratableError> {
|
||||
self.common.resume()?;
|
||||
self.vu_common.virtio_common.resume()?;
|
||||
|
||||
if let Some(epoll_thread) = &self.epoll_thread {
|
||||
epoll_thread.thread().unpark();
|
||||
@@ -455,7 +465,6 @@ impl Migratable for Net {
|
||||
}
|
||||
|
||||
fn complete_migration(&mut self) -> std::result::Result<(), MigratableError> {
|
||||
self.vu_common
|
||||
.complete_migration(self.common.kill_evt.take())
|
||||
self.vu_common.complete_migration()
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user