Skip to content

Commit 83bd2a0

Browse files
committed
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 <[email protected]>
1 parent 997c053 commit 83bd2a0

File tree

7 files changed

+72
-4
lines changed

7 files changed

+72
-4
lines changed

vhost-user-backend/CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22
## [Unreleased]
33

44
### Added
5+
[#206](https://github.com/rust-vmm/vhost/pull/206) Add bitmap support for tracking dirty pages during migration
56

67
### Changed
78

vhost-user-backend/src/bitmap.rs

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -223,7 +223,6 @@ unsafe impl Send for MmapLogReg {}
223223
unsafe impl Sync for MmapLogReg {}
224224

225225
impl MmapLogReg {
226-
#![allow(dead_code)]
227226
// Note: We could try to adjust the mapping area to only cover the memory region, but
228227
// the region's starting address is not guarantee to be LOG_WORD_SIZE-page aligned
229228
// which makes the implementation needlessly cumbersome.

vhost-user-backend/src/handler.rs

Lines changed: 48 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -6,17 +6,18 @@
66
use std::error;
77
use std::fs::File;
88
use std::io;
9+
use std::os::fd::AsFd;
910
#[cfg(feature = "postcopy")]
1011
use std::os::fd::FromRawFd;
1112
use std::os::unix::io::AsRawFd;
1213
use std::sync::Arc;
1314
use std::thread;
1415

15-
use crate::bitmap::BitmapReplace;
16+
use crate::bitmap::{BitmapReplace, MemRegionBitmap, MmapLogReg};
1617
#[cfg(feature = "postcopy")]
1718
use userfaultfd::{Uffd, UffdBuilder};
1819
use vhost::vhost_user::message::{
19-
VhostTransferStateDirection, VhostTransferStatePhase, VhostUserConfigFlags,
20+
VhostTransferStateDirection, VhostTransferStatePhase, VhostUserConfigFlags, VhostUserLog,
2021
VhostUserMemoryRegion, VhostUserProtocolFeatures, VhostUserSingleMemoryRegion,
2122
VhostUserVirtioFeatures, VhostUserVringAddrFlags, VhostUserVringState,
2223
};
@@ -26,7 +27,10 @@ use vhost::vhost_user::{
2627
use virtio_bindings::bindings::virtio_ring::VIRTIO_RING_F_EVENT_IDX;
2728
use virtio_queue::{Error as VirtQueError, QueueT};
2829
use vm_memory::mmap::NewBitmap;
29-
use vm_memory::{GuestAddress, GuestAddressSpace, GuestMemoryMmap, GuestRegionMmap};
30+
use vm_memory::{
31+
GuestAddress, GuestAddressSpace, GuestMemory, GuestMemoryMmap, GuestMemoryRegion,
32+
GuestRegionMmap,
33+
};
3034
use vmm_sys_util::epoll::EventSet;
3135

3236
use super::backend::VhostUserBackend;
@@ -712,6 +716,47 @@ where
712716
self.uffd = None;
713717
Ok(())
714718
}
719+
720+
// Sets logging (i.e., bitmap) shared memory space.
721+
//
722+
// During live migration, the front-end may need to track the modifications the back-end
723+
// makes to the memory mapped regions. The front-end should mark the dirty pages in a log.
724+
// Once it complies to this logging, it may declare the `VHOST_F_LOG_ALL` vhost feature.
725+
//
726+
// If the backend has the `VHOST_USER_PROTOCOL_F_LOG_SHMFD` protocol feature it may receive
727+
// the `VHOST_USER_SET_LOG_BASE` message. The log memory file descriptor is provided in `file`,
728+
// the size and offset of shared memory area are provided in the `VhostUserLog` message.
729+
//
730+
// See https://qemu-project.gitlab.io/qemu/interop/vhost-user.html#migration.
731+
// TODO: We ignore the `LOG_ALL` flag on `SET_FEATURES`, so we will continue marking pages as
732+
// dirty even if the migration fails. We need to disable the logging after receiving a
733+
// `SET_FEATURE` without the `LOG_ALL` flag.
734+
fn set_log_base(&mut self, log: &VhostUserLog, file: File) -> VhostUserResult<()> {
735+
let mem = self.atomic_mem.memory();
736+
737+
let logmem = Arc::new(
738+
MmapLogReg::from_file(file.as_fd(), log.mmap_offset, log.mmap_size)
739+
.map_err(VhostUserError::ReqHandlerError)?,
740+
);
741+
742+
// Let's create all bitmaps first before replacing them, in case any of them fails
743+
let mut bitmaps = Vec::new();
744+
for region in mem.iter() {
745+
let bitmap = <<T as VhostUserBackend>::Bitmap as BitmapReplace>::InnerBitmap::new(
746+
region,
747+
Arc::clone(&logmem),
748+
)
749+
.map_err(VhostUserError::ReqHandlerError)?;
750+
751+
bitmaps.push((region, bitmap));
752+
}
753+
754+
for (region, bitmap) in bitmaps {
755+
region.bitmap().replace(bitmap);
756+
}
757+
758+
Ok(())
759+
}
715760
}
716761

717762
impl<T: VhostUserBackend> Drop for VhostUserHandler<T> {

vhost/CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22
## [Unreleased]
33

44
### Added
5+
[#206](https://github.com/rust-vmm/vhost/pull/206) Add bitmap support for tracking dirty pages during migration
56

67
### Changed
78

vhost/src/vhost_user/backend_req_handler.rs

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -83,6 +83,7 @@ pub trait VhostUserBackendReqHandler {
8383
fn postcopy_listen(&self) -> Result<()>;
8484
#[cfg(feature = "postcopy")]
8585
fn postcopy_end(&self) -> Result<()>;
86+
fn set_log_base(&self, log: &VhostUserLog, file: File) -> Result<()>;
8687
}
8788

8889
/// Services provided to the frontend by the backend without interior mutability.
@@ -144,6 +145,7 @@ pub trait VhostUserBackendReqHandlerMut {
144145
fn postcopy_listen(&mut self) -> Result<()>;
145146
#[cfg(feature = "postcopy")]
146147
fn postcopy_end(&mut self) -> Result<()>;
148+
fn set_log_base(&mut self, log: &VhostUserLog, file: File) -> Result<()>;
147149
}
148150

149151
impl<T: VhostUserBackendReqHandlerMut> VhostUserBackendReqHandler for Mutex<T> {
@@ -282,6 +284,9 @@ impl<T: VhostUserBackendReqHandlerMut> VhostUserBackendReqHandler for Mutex<T> {
282284
fn postcopy_end(&self) -> Result<()> {
283285
self.lock().unwrap().postcopy_end()
284286
}
287+
fn set_log_base(&self, log: &VhostUserLog, file: File) -> Result<()> {
288+
self.lock().unwrap().set_log_base(log, file)
289+
}
285290
}
286291

287292
/// Server to handle service requests from frontends from the frontend communication channel.
@@ -649,6 +654,18 @@ impl<S: VhostUserBackendReqHandler> BackendReqHandler<S> {
649654
let res = self.backend.postcopy_end();
650655
self.send_ack_message(&hdr, res)?;
651656
}
657+
// Sets logging shared memory space.
658+
// When the back-end has `VHOST_USER_PROTOCOL_F_LOG_SHMFD` protocol feature, the log
659+
// memory `fd` is provided in the ancillary data of `VHOST_USER_SET_LOG_BASE` message,
660+
// the size and offset of shared memory area provided in the message.
661+
// See https://qemu-project.gitlab.io/qemu/interop/vhost-user.html#migration.
662+
Ok(FrontendReq::SET_LOG_BASE) => {
663+
self.check_proto_feature(VhostUserProtocolFeatures::LOG_SHMFD)?;
664+
let file = take_single_file(files).ok_or(Error::IncorrectFds)?;
665+
let msg = self.extract_request_body::<VhostUserLog>(&hdr, size, &buf)?;
666+
self.backend.set_log_base(&msg, file)?;
667+
self.send_reply_message(&hdr, &msg)?;
668+
}
652669
_ => {
653670
return Err(Error::InvalidMessage);
654671
}

vhost/src/vhost_user/dummy_backend.rs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -326,4 +326,7 @@ impl VhostUserBackendReqHandlerMut for DummyBackendReqHandler {
326326
fn postcopy_end(&mut self) -> Result<()> {
327327
Ok(())
328328
}
329+
fn set_log_base(&mut self, _log: &VhostUserLog, _file: File) -> Result<()> {
330+
Err(Error::InvalidMessage)
331+
}
329332
}

vhost/src/vhost_user/message.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -394,6 +394,8 @@ bitflags! {
394394
#[derive(Copy, Clone, Debug, Eq, PartialEq)]
395395
/// Transport specific flags in VirtIO feature set defined by vhost-user.
396396
pub struct VhostUserVirtioFeatures: u64 {
397+
/// Log dirtied shared memory pages.
398+
const LOG_ALL = 0x400_0000;
397399
/// Feature flag for the protocol feature.
398400
const PROTOCOL_FEATURES = 0x4000_0000;
399401
}

0 commit comments

Comments
 (0)