mirror of
https://github.com/cloud-hypervisor/cloud-hypervisor.git
synced 2025-02-22 19:32:20 +00:00
virtio-devices: Add support for adding a single memory region
Assuming vhost-user devices support CONFIGURE_MEM_SLOTS protocol feature, we introduce a new method to the VirtioDevice trait in order to update one single memory at a time. In case CONFIGURE_MEM_SLOTS is not supported by the backend (feature not acked), we fallback onto the current way of updating the memory mappings, that is with SET_MEM_TABLE. Signed-off-by: Sebastien Boeuf <sebastien.boeuf@intel.com>
This commit is contained in:
parent
4f22f57651
commit
9e53efa3ca
@ -16,7 +16,7 @@ use std::sync::{
|
||||
Arc, Barrier,
|
||||
};
|
||||
use std::thread;
|
||||
use vm_memory::{GuestAddress, GuestMemoryAtomic, GuestMemoryMmap, GuestUsize};
|
||||
use vm_memory::{GuestAddress, GuestMemoryAtomic, GuestMemoryMmap, GuestRegionMmap, GuestUsize};
|
||||
use vm_migration::{MigratableError, Pausable};
|
||||
use vm_virtio::VirtioDeviceType;
|
||||
use vmm_sys_util::eventfd::EventFd;
|
||||
@ -143,6 +143,13 @@ pub trait VirtioDevice: Send {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn add_memory_region(
|
||||
&mut self,
|
||||
_region: &Arc<GuestRegionMmap>,
|
||||
) -> std::result::Result<(), Error> {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Returns the list of userspace mappings associated with this device.
|
||||
fn userspace_mappings(&self) -> Vec<UserspaceMapping> {
|
||||
Vec::new()
|
||||
|
@ -119,6 +119,7 @@ pub enum Error {
|
||||
EpollWait(io::Error),
|
||||
FailedSignalingDriver(io::Error),
|
||||
VhostUserUpdateMemory(vhost_user::Error),
|
||||
VhostUserAddMemoryRegion(vhost_user::Error),
|
||||
EventfdError(io::Error),
|
||||
SetShmRegionsNotSupported,
|
||||
EpollHander(String),
|
||||
|
@ -12,6 +12,7 @@ use crate::VirtioInterrupt;
|
||||
use block_util::VirtioBlockConfig;
|
||||
use seccomp::{SeccompAction, SeccompFilter};
|
||||
use std::mem;
|
||||
use std::ops::Deref;
|
||||
use std::os::unix::io::AsRawFd;
|
||||
use std::result;
|
||||
use std::sync::{Arc, Barrier};
|
||||
@ -24,7 +25,9 @@ use vhost::vhost_user::{Master, VhostUserMaster, VhostUserMasterReqHandler};
|
||||
use vhost::VhostBackend;
|
||||
use virtio_bindings::bindings::virtio_blk::*;
|
||||
use virtio_bindings::bindings::virtio_ring::VIRTIO_RING_F_EVENT_IDX;
|
||||
use vm_memory::{ByteValued, GuestAddressSpace, GuestMemoryAtomic, GuestMemoryMmap};
|
||||
use vm_memory::{
|
||||
ByteValued, GuestAddressSpace, GuestMemoryAtomic, GuestMemoryMmap, GuestRegionMmap,
|
||||
};
|
||||
use vm_migration::{Migratable, MigratableError, Pausable, Snapshottable, Transportable};
|
||||
use vmm_sys_util::eventfd::EventFd;
|
||||
|
||||
@ -37,6 +40,8 @@ pub struct Blk {
|
||||
vhost_user_blk: Master,
|
||||
config: VirtioBlockConfig,
|
||||
seccomp_action: SeccompAction,
|
||||
guest_memory: Option<GuestMemoryAtomic<GuestMemoryMmap>>,
|
||||
acked_protocol_features: u64,
|
||||
}
|
||||
|
||||
impl Blk {
|
||||
@ -79,17 +84,21 @@ impl Blk {
|
||||
|
||||
// Identify if protocol features are supported by the slave.
|
||||
let mut acked_features = 0;
|
||||
let mut acked_protocol_features = 0;
|
||||
if avail_features & VhostUserVirtioFeatures::PROTOCOL_FEATURES.bits() != 0 {
|
||||
acked_features |= VhostUserVirtioFeatures::PROTOCOL_FEATURES.bits();
|
||||
|
||||
let mut protocol_features = vhost_user_blk
|
||||
.get_protocol_features()
|
||||
.map_err(Error::VhostUserGetProtocolFeatures)?;
|
||||
protocol_features |= VhostUserProtocolFeatures::MQ;
|
||||
protocol_features &= !VhostUserProtocolFeatures::INFLIGHT_SHMFD;
|
||||
protocol_features &= VhostUserProtocolFeatures::CONFIG
|
||||
| VhostUserProtocolFeatures::MQ
|
||||
| VhostUserProtocolFeatures::CONFIGURE_MEM_SLOTS;
|
||||
vhost_user_blk
|
||||
.set_protocol_features(protocol_features)
|
||||
.map_err(Error::VhostUserSetProtocolFeatures)?;
|
||||
|
||||
acked_protocol_features = protocol_features.bits();
|
||||
}
|
||||
// Get the max queues number from backend, and the queue number set
|
||||
// should be less than this max queue number.
|
||||
@ -142,6 +151,8 @@ impl Blk {
|
||||
vhost_user_blk,
|
||||
config,
|
||||
seccomp_action,
|
||||
guest_memory: None,
|
||||
acked_protocol_features,
|
||||
})
|
||||
}
|
||||
}
|
||||
@ -206,6 +217,8 @@ impl VirtioDevice for Blk {
|
||||
) -> ActivateResult {
|
||||
self.common.activate(&queues, &queue_evts, &interrupt_cb)?;
|
||||
|
||||
self.guest_memory = Some(mem.clone());
|
||||
|
||||
let mut vu_interrupt_list = setup_vhost_user(
|
||||
&mut self.vhost_user_blk,
|
||||
&mem.memory(),
|
||||
@ -305,6 +318,22 @@ impl VirtioDevice for Blk {
|
||||
fn update_memory(&mut self, mem: &GuestMemoryMmap) -> std::result::Result<(), crate::Error> {
|
||||
update_mem_table(&mut self.vhost_user_blk, mem).map_err(crate::Error::VhostUserUpdateMemory)
|
||||
}
|
||||
|
||||
fn add_memory_region(
|
||||
&mut self,
|
||||
region: &Arc<GuestRegionMmap>,
|
||||
) -> std::result::Result<(), crate::Error> {
|
||||
if self.acked_protocol_features & VhostUserProtocolFeatures::CONFIGURE_MEM_SLOTS.bits() != 0
|
||||
{
|
||||
add_memory_region(&mut self.vhost_user_blk, region)
|
||||
.map_err(crate::Error::VhostUserAddMemoryRegion)
|
||||
} else if let Some(guest_memory) = &self.guest_memory {
|
||||
update_mem_table(&mut self.vhost_user_blk, guest_memory.memory().deref())
|
||||
.map_err(crate::Error::VhostUserUpdateMemory)
|
||||
} else {
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Pausable for Blk {
|
||||
|
@ -1,7 +1,9 @@
|
||||
// Copyright 2019 Intel Corporation. All Rights Reserved.
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
use super::vu_common_ctrl::{reset_vhost_user, setup_vhost_user, update_mem_table};
|
||||
use super::vu_common_ctrl::{
|
||||
add_memory_region, reset_vhost_user, setup_vhost_user, update_mem_table,
|
||||
};
|
||||
use super::{Error, Result};
|
||||
use crate::seccomp_filters::{get_seccomp_filter, Thread};
|
||||
use crate::vhost_user::handler::{VhostUserEpollConfig, VhostUserEpollHandler};
|
||||
@ -12,6 +14,7 @@ use crate::{
|
||||
use libc::{self, c_void, off64_t, pread64, pwrite64};
|
||||
use seccomp::{SeccompAction, SeccompFilter};
|
||||
use std::io;
|
||||
use std::ops::Deref;
|
||||
use std::os::unix::io::{AsRawFd, RawFd};
|
||||
use std::result;
|
||||
use std::sync::{Arc, Barrier};
|
||||
@ -26,7 +29,7 @@ use vhost::vhost_user::{
|
||||
use vhost::VhostBackend;
|
||||
use vm_memory::{
|
||||
Address, ByteValued, GuestAddress, GuestAddressSpace, GuestMemory, GuestMemoryAtomic,
|
||||
GuestMemoryMmap, MmapRegion,
|
||||
GuestMemoryMmap, GuestRegionMmap, MmapRegion,
|
||||
};
|
||||
use vm_migration::{Migratable, MigratableError, Pausable, Snapshottable, Transportable};
|
||||
use vmm_sys_util::eventfd::EventFd;
|
||||
@ -274,6 +277,8 @@ pub struct Fs {
|
||||
cache: Option<(VirtioSharedMemoryList, MmapRegion)>,
|
||||
slave_req_support: bool,
|
||||
seccomp_action: SeccompAction,
|
||||
guest_memory: Option<GuestMemoryAtomic<GuestMemoryMmap>>,
|
||||
acked_protocol_features: u64,
|
||||
}
|
||||
|
||||
impl Fs {
|
||||
@ -315,6 +320,7 @@ impl Fs {
|
||||
|
||||
// Identify if protocol features are supported by the slave.
|
||||
let mut acked_features = 0;
|
||||
let mut acked_protocol_features = 0;
|
||||
if avail_features & VhostUserVirtioFeatures::PROTOCOL_FEATURES.bits() != 0 {
|
||||
acked_features |= VhostUserVirtioFeatures::PROTOCOL_FEATURES.bits();
|
||||
|
||||
@ -322,20 +328,23 @@ impl Fs {
|
||||
.get_protocol_features()
|
||||
.map_err(Error::VhostUserGetProtocolFeatures)?;
|
||||
|
||||
let mut supported_protocol_features = VhostUserProtocolFeatures::MQ
|
||||
| VhostUserProtocolFeatures::REPLY_ACK
|
||||
| VhostUserProtocolFeatures::CONFIGURE_MEM_SLOTS;
|
||||
|
||||
if cache.is_some() {
|
||||
protocol_features &= VhostUserProtocolFeatures::MQ
|
||||
| VhostUserProtocolFeatures::REPLY_ACK
|
||||
| VhostUserProtocolFeatures::SLAVE_REQ
|
||||
| VhostUserProtocolFeatures::SLAVE_SEND_FD;
|
||||
} else {
|
||||
protocol_features &=
|
||||
VhostUserProtocolFeatures::MQ | VhostUserProtocolFeatures::REPLY_ACK;
|
||||
supported_protocol_features |=
|
||||
VhostUserProtocolFeatures::SLAVE_REQ | VhostUserProtocolFeatures::SLAVE_SEND_FD
|
||||
}
|
||||
|
||||
protocol_features &= supported_protocol_features;
|
||||
|
||||
master
|
||||
.set_protocol_features(protocol_features)
|
||||
.map_err(Error::VhostUserSetProtocolFeatures)?;
|
||||
|
||||
acked_protocol_features = protocol_features.bits();
|
||||
|
||||
slave_req_support = true;
|
||||
}
|
||||
|
||||
@ -361,6 +370,8 @@ impl Fs {
|
||||
cache,
|
||||
slave_req_support,
|
||||
seccomp_action,
|
||||
guest_memory: None,
|
||||
acked_protocol_features,
|
||||
})
|
||||
}
|
||||
}
|
||||
@ -404,6 +415,8 @@ impl VirtioDevice for Fs {
|
||||
) -> ActivateResult {
|
||||
self.common.activate(&queues, &queue_evts, &interrupt_cb)?;
|
||||
|
||||
self.guest_memory = Some(mem.clone());
|
||||
|
||||
let kill_evt = self
|
||||
.common
|
||||
.kill_evt
|
||||
@ -548,6 +561,21 @@ impl VirtioDevice for Fs {
|
||||
update_mem_table(&mut self.vu, mem).map_err(crate::Error::VhostUserUpdateMemory)
|
||||
}
|
||||
|
||||
fn add_memory_region(
|
||||
&mut self,
|
||||
region: &Arc<GuestRegionMmap>,
|
||||
) -> std::result::Result<(), crate::Error> {
|
||||
if self.acked_protocol_features & VhostUserProtocolFeatures::CONFIGURE_MEM_SLOTS.bits() != 0
|
||||
{
|
||||
add_memory_region(&mut self.vu, region).map_err(crate::Error::VhostUserAddMemoryRegion)
|
||||
} else if let Some(guest_memory) = &self.guest_memory {
|
||||
update_mem_table(&mut self.vu, guest_memory.memory().deref())
|
||||
.map_err(crate::Error::VhostUserUpdateMemory)
|
||||
} else {
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
fn userspace_mappings(&self) -> Vec<UserspaceMapping> {
|
||||
let mut mappings = Vec::new();
|
||||
if let Some(cache) = self.cache.as_ref() {
|
||||
|
@ -84,9 +84,13 @@ pub enum Error {
|
||||
MasterReqHandlerCreation(vhost::vhost_user::Error),
|
||||
/// Set slave request fd failed.
|
||||
VhostUserSetSlaveRequestFd(vhost::Error),
|
||||
/// Add memory region failed.
|
||||
VhostUserAddMemReg(VhostError),
|
||||
/// Invalid used address.
|
||||
UsedAddress,
|
||||
/// Invalid features provided from vhost-user backend
|
||||
InvalidFeatures,
|
||||
/// Missing file descriptor for the region.
|
||||
MissingRegionFd,
|
||||
}
|
||||
type Result<T> = std::result::Result<T, Error>;
|
||||
|
@ -14,6 +14,7 @@ use crate::seccomp_filters::{get_seccomp_filter, Thread};
|
||||
use crate::VirtioInterrupt;
|
||||
use net_util::MacAddr;
|
||||
use seccomp::{SeccompAction, SeccompFilter};
|
||||
use std::ops::Deref;
|
||||
use std::os::unix::io::AsRawFd;
|
||||
use std::result;
|
||||
use std::sync::{Arc, Barrier};
|
||||
@ -24,7 +25,9 @@ use vhost::vhost_user::{Master, VhostUserMaster, VhostUserMasterReqHandler};
|
||||
use vhost::VhostBackend;
|
||||
use virtio_bindings::bindings::virtio_net;
|
||||
use virtio_bindings::bindings::virtio_ring;
|
||||
use vm_memory::{ByteValued, GuestAddressSpace, GuestMemoryAtomic, GuestMemoryMmap};
|
||||
use vm_memory::{
|
||||
ByteValued, GuestAddressSpace, GuestMemoryAtomic, GuestMemoryMmap, GuestRegionMmap,
|
||||
};
|
||||
use vm_migration::{Migratable, MigratableError, Pausable, Snapshottable, Transportable};
|
||||
use vmm_sys_util::eventfd::EventFd;
|
||||
|
||||
@ -41,6 +44,8 @@ pub struct Net {
|
||||
config: VirtioNetConfig,
|
||||
ctrl_queue_epoll_thread: Option<thread::JoinHandle<()>>,
|
||||
seccomp_action: SeccompAction,
|
||||
guest_memory: Option<GuestMemoryAtomic<GuestMemoryMmap>>,
|
||||
acked_protocol_features: u64,
|
||||
}
|
||||
|
||||
impl Net {
|
||||
@ -88,7 +93,7 @@ impl Net {
|
||||
.set_features(avail_features)
|
||||
.map_err(Error::VhostUserSetFeatures)?;
|
||||
|
||||
let protocol_features;
|
||||
let mut protocol_features;
|
||||
let mut acked_features = 0;
|
||||
if avail_features & VhostUserVirtioFeatures::PROTOCOL_FEATURES.bits() != 0 {
|
||||
acked_features |= VhostUserVirtioFeatures::PROTOCOL_FEATURES.bits();
|
||||
@ -99,11 +104,17 @@ impl Net {
|
||||
return Err(Error::VhostUserProtocolNotSupport);
|
||||
}
|
||||
|
||||
protocol_features &=
|
||||
VhostUserProtocolFeatures::MQ | VhostUserProtocolFeatures::CONFIGURE_MEM_SLOTS;
|
||||
|
||||
vhost_user_net
|
||||
.set_protocol_features(protocol_features)
|
||||
.map_err(Error::VhostUserSetProtocolFeatures)?;
|
||||
|
||||
let acked_protocol_features = protocol_features.bits();
|
||||
|
||||
let max_queue_number =
|
||||
if protocol_features.bits() & VhostUserProtocolFeatures::MQ.bits() != 0 {
|
||||
vhost_user_net
|
||||
.set_protocol_features(protocol_features & VhostUserProtocolFeatures::MQ)
|
||||
.map_err(Error::VhostUserSetProtocolFeatures)?;
|
||||
match vhost_user_net.get_queue_num() {
|
||||
Ok(qn) => qn,
|
||||
Err(_) => DEFAULT_QUEUE_NUMBER as u64,
|
||||
@ -111,6 +122,7 @@ impl Net {
|
||||
} else {
|
||||
DEFAULT_QUEUE_NUMBER as u64
|
||||
};
|
||||
|
||||
if vu_cfg.num_queues > max_queue_number as usize {
|
||||
error!("vhost-user-net has queue number: {} larger than the max queue number: {} backend allowed\n",
|
||||
vu_cfg.num_queues, max_queue_number);
|
||||
@ -152,6 +164,8 @@ impl Net {
|
||||
config,
|
||||
ctrl_queue_epoll_thread: None,
|
||||
seccomp_action,
|
||||
guest_memory: None,
|
||||
acked_protocol_features,
|
||||
})
|
||||
}
|
||||
}
|
||||
@ -196,6 +210,8 @@ impl VirtioDevice for Net {
|
||||
) -> ActivateResult {
|
||||
self.common.activate(&queues, &queue_evts, &interrupt_cb)?;
|
||||
|
||||
self.guest_memory = Some(mem.clone());
|
||||
|
||||
let queue_num = self.common.queue_evts.as_ref().unwrap().len();
|
||||
|
||||
if self
|
||||
@ -360,6 +376,22 @@ impl VirtioDevice for Net {
|
||||
fn update_memory(&mut self, mem: &GuestMemoryMmap) -> std::result::Result<(), crate::Error> {
|
||||
update_mem_table(&mut self.vhost_user_net, mem).map_err(crate::Error::VhostUserUpdateMemory)
|
||||
}
|
||||
|
||||
fn add_memory_region(
|
||||
&mut self,
|
||||
region: &Arc<GuestRegionMmap>,
|
||||
) -> std::result::Result<(), crate::Error> {
|
||||
if self.acked_protocol_features & VhostUserProtocolFeatures::CONFIGURE_MEM_SLOTS.bits() != 0
|
||||
{
|
||||
add_memory_region(&mut self.vhost_user_net, region)
|
||||
.map_err(crate::Error::VhostUserAddMemoryRegion)
|
||||
} else if let Some(guest_memory) = &self.guest_memory {
|
||||
update_mem_table(&mut self.vhost_user_net, guest_memory.memory().deref())
|
||||
.map_err(crate::Error::VhostUserUpdateMemory)
|
||||
} else {
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Pausable for Net {
|
||||
|
@ -11,7 +11,9 @@ use std::sync::Arc;
|
||||
use std::vec::Vec;
|
||||
use vhost::vhost_user::{Master, VhostUserMaster};
|
||||
use vhost::{VhostBackend, VhostUserMemoryRegionInfo, VringConfigData};
|
||||
use vm_memory::{Address, Error as MmapError, GuestMemory, GuestMemoryMmap, GuestMemoryRegion};
|
||||
use vm_memory::{
|
||||
Address, Error as MmapError, GuestMemory, GuestMemoryMmap, GuestMemoryRegion, GuestRegionMmap,
|
||||
};
|
||||
use vmm_sys_util::eventfd::EventFd;
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
@ -49,6 +51,24 @@ pub fn update_mem_table(vu: &mut Master, mem: &GuestMemoryMmap) -> Result<()> {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn add_memory_region(vu: &mut Master, region: &Arc<GuestRegionMmap>) -> Result<()> {
|
||||
let (mmap_handle, mmap_offset) = match region.file_offset() {
|
||||
Some(file_offset) => (file_offset.file().as_raw_fd(), file_offset.start()),
|
||||
None => return Err(Error::MissingRegionFd),
|
||||
};
|
||||
|
||||
let region = VhostUserMemoryRegionInfo {
|
||||
guest_phys_addr: region.start_addr().raw_value(),
|
||||
memory_size: region.len() as u64,
|
||||
userspace_addr: region.as_ptr() as u64,
|
||||
mmap_offset,
|
||||
mmap_handle,
|
||||
};
|
||||
|
||||
vu.add_mem_region(®ion)
|
||||
.map_err(Error::VhostUserAddMemReg)
|
||||
}
|
||||
|
||||
pub fn setup_vhost_user_vring(
|
||||
vu: &mut Master,
|
||||
mem: &GuestMemoryMmap,
|
||||
|
Loading…
x
Reference in New Issue
Block a user