Add SET_LOG_BASE message support
If the backend has the VHOST_USER_PROTOCOL_F_LOG_SHMFD protocol feature it will receive the VHOST_USER_SET_LOG_BASE message with a file descriptor of the dirty-pages log memory region. This log covers all known guest addresses, and must be manipulated atomically. For further info please see https://qemu-project.gitlab.io/qemu/interop/vhost-user.html#migration Signed-off-by: German Maglione <gmaglione@redhat.com>
This commit is contained in:
parent
4443df57bb
commit
6ce9d36b1e
7 changed files with 72 additions and 4 deletions
|
|
@ -2,6 +2,7 @@
|
|||
## [Unreleased]
|
||||
|
||||
### Added
|
||||
[#206](https://github.com/rust-vmm/vhost/pull/206) Add bitmap support for tracking dirty pages during migration
|
||||
|
||||
### Changed
|
||||
|
||||
|
|
|
|||
|
|
@ -223,7 +223,6 @@ unsafe impl Send for MmapLogReg {}
|
|||
unsafe impl Sync for MmapLogReg {}
|
||||
|
||||
impl MmapLogReg {
|
||||
#![allow(dead_code)]
|
||||
// Note: We could try to adjust the mapping area to only cover the memory region, but
|
||||
// the region's starting address is not guarantee to be LOG_WORD_SIZE-page aligned
|
||||
// which makes the implementation needlessly cumbersome.
|
||||
|
|
|
|||
|
|
@ -6,17 +6,18 @@
|
|||
use std::error;
|
||||
use std::fs::File;
|
||||
use std::io;
|
||||
use std::os::fd::AsFd;
|
||||
#[cfg(feature = "postcopy")]
|
||||
use std::os::fd::FromRawFd;
|
||||
use std::os::unix::io::AsRawFd;
|
||||
use std::sync::Arc;
|
||||
use std::thread;
|
||||
|
||||
use crate::bitmap::BitmapReplace;
|
||||
use crate::bitmap::{BitmapReplace, MemRegionBitmap, MmapLogReg};
|
||||
#[cfg(feature = "postcopy")]
|
||||
use userfaultfd::{Uffd, UffdBuilder};
|
||||
use vhost::vhost_user::message::{
|
||||
VhostTransferStateDirection, VhostTransferStatePhase, VhostUserConfigFlags,
|
||||
VhostTransferStateDirection, VhostTransferStatePhase, VhostUserConfigFlags, VhostUserLog,
|
||||
VhostUserMemoryRegion, VhostUserProtocolFeatures, VhostUserSingleMemoryRegion,
|
||||
VhostUserVirtioFeatures, VhostUserVringAddrFlags, VhostUserVringState,
|
||||
};
|
||||
|
|
@ -26,7 +27,10 @@ use vhost::vhost_user::{
|
|||
use virtio_bindings::bindings::virtio_ring::VIRTIO_RING_F_EVENT_IDX;
|
||||
use virtio_queue::{Error as VirtQueError, QueueT};
|
||||
use vm_memory::mmap::NewBitmap;
|
||||
use vm_memory::{GuestAddress, GuestAddressSpace, GuestMemoryMmap, GuestRegionMmap};
|
||||
use vm_memory::{
|
||||
GuestAddress, GuestAddressSpace, GuestMemory, GuestMemoryMmap, GuestMemoryRegion,
|
||||
GuestRegionMmap,
|
||||
};
|
||||
use vmm_sys_util::epoll::EventSet;
|
||||
|
||||
use super::backend::VhostUserBackend;
|
||||
|
|
@ -712,6 +716,47 @@ where
|
|||
self.uffd = None;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
// Sets logging (i.e., bitmap) shared memory space.
|
||||
//
|
||||
// During live migration, the front-end may need to track the modifications the back-end
|
||||
// makes to the memory mapped regions. The front-end should mark the dirty pages in a log.
|
||||
// Once it complies to this logging, it may declare the `VHOST_F_LOG_ALL` vhost feature.
|
||||
//
|
||||
// If the backend has the `VHOST_USER_PROTOCOL_F_LOG_SHMFD` protocol feature it may receive
|
||||
// the `VHOST_USER_SET_LOG_BASE` message. The log memory file descriptor is provided in `file`,
|
||||
// the size and offset of shared memory area are provided in the `VhostUserLog` message.
|
||||
//
|
||||
// See https://qemu-project.gitlab.io/qemu/interop/vhost-user.html#migration.
|
||||
// TODO: We ignore the `LOG_ALL` flag on `SET_FEATURES`, so we will continue marking pages as
|
||||
// dirty even if the migration fails. We need to disable the logging after receiving a
|
||||
// `SET_FEATURE` without the `LOG_ALL` flag.
|
||||
fn set_log_base(&mut self, log: &VhostUserLog, file: File) -> VhostUserResult<()> {
|
||||
let mem = self.atomic_mem.memory();
|
||||
|
||||
let logmem = Arc::new(
|
||||
MmapLogReg::from_file(file.as_fd(), log.mmap_offset, log.mmap_size)
|
||||
.map_err(VhostUserError::ReqHandlerError)?,
|
||||
);
|
||||
|
||||
// Let's create all bitmaps first before replacing them, in case any of them fails
|
||||
let mut bitmaps = Vec::new();
|
||||
for region in mem.iter() {
|
||||
let bitmap = <<T as VhostUserBackend>::Bitmap as BitmapReplace>::InnerBitmap::new(
|
||||
region,
|
||||
Arc::clone(&logmem),
|
||||
)
|
||||
.map_err(VhostUserError::ReqHandlerError)?;
|
||||
|
||||
bitmaps.push((region, bitmap));
|
||||
}
|
||||
|
||||
for (region, bitmap) in bitmaps {
|
||||
region.bitmap().replace(bitmap);
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: VhostUserBackend> Drop for VhostUserHandler<T> {
|
||||
|
|
|
|||
|
|
@ -2,6 +2,7 @@
|
|||
## [Unreleased]
|
||||
|
||||
### Added
|
||||
[#206](https://github.com/rust-vmm/vhost/pull/206) Add bitmap support for tracking dirty pages during migration
|
||||
|
||||
### Changed
|
||||
|
||||
|
|
|
|||
|
|
@ -83,6 +83,7 @@ pub trait VhostUserBackendReqHandler {
|
|||
fn postcopy_listen(&self) -> Result<()>;
|
||||
#[cfg(feature = "postcopy")]
|
||||
fn postcopy_end(&self) -> Result<()>;
|
||||
fn set_log_base(&self, log: &VhostUserLog, file: File) -> Result<()>;
|
||||
}
|
||||
|
||||
/// Services provided to the frontend by the backend without interior mutability.
|
||||
|
|
@ -144,6 +145,7 @@ pub trait VhostUserBackendReqHandlerMut {
|
|||
fn postcopy_listen(&mut self) -> Result<()>;
|
||||
#[cfg(feature = "postcopy")]
|
||||
fn postcopy_end(&mut self) -> Result<()>;
|
||||
fn set_log_base(&mut self, log: &VhostUserLog, file: File) -> Result<()>;
|
||||
}
|
||||
|
||||
impl<T: VhostUserBackendReqHandlerMut> VhostUserBackendReqHandler for Mutex<T> {
|
||||
|
|
@ -282,6 +284,9 @@ impl<T: VhostUserBackendReqHandlerMut> VhostUserBackendReqHandler for Mutex<T> {
|
|||
fn postcopy_end(&self) -> Result<()> {
|
||||
self.lock().unwrap().postcopy_end()
|
||||
}
|
||||
fn set_log_base(&self, log: &VhostUserLog, file: File) -> Result<()> {
|
||||
self.lock().unwrap().set_log_base(log, file)
|
||||
}
|
||||
}
|
||||
|
||||
/// Server to handle service requests from frontends from the frontend communication channel.
|
||||
|
|
@ -649,6 +654,18 @@ impl<S: VhostUserBackendReqHandler> BackendReqHandler<S> {
|
|||
let res = self.backend.postcopy_end();
|
||||
self.send_ack_message(&hdr, res)?;
|
||||
}
|
||||
// Sets logging shared memory space.
|
||||
// When the back-end has `VHOST_USER_PROTOCOL_F_LOG_SHMFD` protocol feature, the log
|
||||
// memory `fd` is provided in the ancillary data of `VHOST_USER_SET_LOG_BASE` message,
|
||||
// the size and offset of shared memory area provided in the message.
|
||||
// See https://qemu-project.gitlab.io/qemu/interop/vhost-user.html#migration.
|
||||
Ok(FrontendReq::SET_LOG_BASE) => {
|
||||
self.check_proto_feature(VhostUserProtocolFeatures::LOG_SHMFD)?;
|
||||
let file = take_single_file(files).ok_or(Error::IncorrectFds)?;
|
||||
let msg = self.extract_request_body::<VhostUserLog>(&hdr, size, &buf)?;
|
||||
self.backend.set_log_base(&msg, file)?;
|
||||
self.send_reply_message(&hdr, &msg)?;
|
||||
}
|
||||
_ => {
|
||||
return Err(Error::InvalidMessage);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -326,4 +326,7 @@ impl VhostUserBackendReqHandlerMut for DummyBackendReqHandler {
|
|||
fn postcopy_end(&mut self) -> Result<()> {
|
||||
Ok(())
|
||||
}
|
||||
fn set_log_base(&mut self, _log: &VhostUserLog, _file: File) -> Result<()> {
|
||||
Err(Error::InvalidMessage)
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -394,6 +394,8 @@ bitflags! {
|
|||
#[derive(Copy, Clone, Debug, Eq, PartialEq)]
|
||||
/// Transport specific flags in VirtIO feature set defined by vhost-user.
|
||||
pub struct VhostUserVirtioFeatures: u64 {
|
||||
/// Log dirtied shared memory pages.
|
||||
const LOG_ALL = 0x400_0000;
|
||||
/// Feature flag for the protocol feature.
|
||||
const PROTOCOL_FEATURES = 0x4000_0000;
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue