vhost: frontend supports POSTCOPY messages
New feature `postcopy` is introduced. It acts as a gate for a
new functionality.
This feature is not compatible with `xen` feature because `xen`
can map memory regions on demand and this does not work with uffd.
Now frondned supports sending POSTCOPY messages to the backend.
The POSTCOPY messages are only usable when
VHOST_USER_PROTOCOL_F_PAGEFAULT feature is negotiated.
The messages and their descriptions are:
- VHOST_USER_POSTCOPY_ADVISE:
When the front-end sends this message to the backend,
the back-end must open a userfaultfd for later use
and send it's fd to the front-end.
- VHOST_USER_POSTCOPY_LISTEN
When the back-end receives this message it must ensure
that shared memory is registered with userfaultfd to
cause faulting of non-present pages.
This is always sent sometime after a VHOST_USER_POSTCOPY_ADVISE.
- VHOST_USER_POSTCOPY_END
When the back-end receives this message it must disable the
userfaultfd. The reply is an acknowledgement only.
Signed-off-by: Egor Lazarchuk <yegorlz@amazon.co.uk>
This commit is contained in:
parent
b5550a941d
commit
8ee8739bf0
4 changed files with 66 additions and 0 deletions
|
|
@ -24,6 +24,7 @@ vhost-user = []
|
|||
vhost-user-frontend = ["vhost-user"]
|
||||
vhost-user-backend = ["vhost-user"]
|
||||
xen = ["vm-memory/xen"]
|
||||
postcopy = []
|
||||
|
||||
[dependencies]
|
||||
bitflags = "2.4"
|
||||
|
|
|
|||
|
|
@ -51,6 +51,12 @@ pub mod vhost_user;
|
|||
#[cfg(feature = "vhost-vsock")]
|
||||
pub mod vsock;
|
||||
|
||||
/// Due to the way `xen` handles memory mappings we can not combine it with
|
||||
/// `postcopy` feature which relies on persistent memory mappings. Thus we
|
||||
/// disallow enabling both features at the same time.
|
||||
#[cfg(all(feature = "postcopy", feature = "xen"))]
|
||||
compile_error!("Both `postcopy` and `xen` features can not be enabled at the same time.");
|
||||
|
||||
/// Error codes for vhost operations
|
||||
#[derive(Debug)]
|
||||
pub enum Error {
|
||||
|
|
|
|||
|
|
@ -72,6 +72,26 @@ pub trait VhostUserFrontend: VhostBackend {
|
|||
|
||||
/// Remove a guest memory mapping from vhost.
|
||||
fn remove_mem_region(&mut self, region: &VhostUserMemoryRegionInfo) -> Result<()>;
|
||||
|
||||
/// Sends VHOST_USER_POSTCOPY_ADVISE msg to the backend
|
||||
/// initiating the beginning of the postcopy process.
|
||||
/// Backend will return a userfaultfd.
|
||||
#[cfg(feature = "postcopy")]
|
||||
fn postcopy_advise(&mut self) -> Result<File>;
|
||||
|
||||
/// Sends VHOST_USER_POSTCOPY_LISTEN msg to the backend
|
||||
/// telling it to register its memory regions with
|
||||
/// userfaultfd previously received through the
|
||||
/// [`VhostUserFrontend::postcopy_advise`] call.
|
||||
#[cfg(feature = "postcopy")]
|
||||
fn postcopy_listen(&mut self) -> Result<()>;
|
||||
|
||||
/// Sends VHOST_USER_POSTCOPY_END msg to the backend
|
||||
/// indicating the end of the postcopy process.
|
||||
/// Backend will destroy the userfaultfd object previously
|
||||
/// sent by [`VhostUserFrontend::postcopy_advise`].
|
||||
#[cfg(feature = "postcopy")]
|
||||
fn postcopy_end(&mut self) -> Result<()>;
|
||||
}
|
||||
|
||||
fn error_code<T>(err: VhostUserError) -> Result<T> {
|
||||
|
|
@ -517,6 +537,36 @@ impl VhostUserFrontend for Frontend {
|
|||
let hdr = node.send_request_with_body(FrontendReq::REM_MEM_REG, &body, None)?;
|
||||
node.wait_for_ack(&hdr).map_err(|e| e.into())
|
||||
}
|
||||
|
||||
#[cfg(feature = "postcopy")]
|
||||
fn postcopy_advise(&mut self) -> Result<File> {
|
||||
let mut node = self.node();
|
||||
node.check_proto_feature(VhostUserProtocolFeatures::PAGEFAULT)?;
|
||||
|
||||
let hdr = node.send_request_header(FrontendReq::POSTCOPY_ADVISE, None)?;
|
||||
let (_, files) = node.recv_reply_with_files::<VhostUserEmpty>(&hdr)?;
|
||||
|
||||
match take_single_file(files) {
|
||||
Some(file) => Ok(file),
|
||||
None => error_code(VhostUserError::IncorrectFds),
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(feature = "postcopy")]
|
||||
fn postcopy_listen(&mut self) -> Result<()> {
|
||||
let mut node = self.node();
|
||||
node.check_proto_feature(VhostUserProtocolFeatures::PAGEFAULT)?;
|
||||
let hdr = node.send_request_header(FrontendReq::POSTCOPY_LISTEN, None)?;
|
||||
node.wait_for_ack(&hdr).map_err(|e| e.into())
|
||||
}
|
||||
|
||||
#[cfg(feature = "postcopy")]
|
||||
fn postcopy_end(&mut self) -> Result<()> {
|
||||
let mut node = self.node();
|
||||
node.check_proto_feature(VhostUserProtocolFeatures::PAGEFAULT)?;
|
||||
let hdr = node.send_request_header(FrontendReq::POSTCOPY_END, None)?;
|
||||
node.wait_for_ack(&hdr).map_err(|e| e.into())
|
||||
}
|
||||
}
|
||||
|
||||
impl AsRawFd for Frontend {
|
||||
|
|
|
|||
|
|
@ -445,6 +445,15 @@ bitflags! {
|
|||
}
|
||||
}
|
||||
|
||||
/// An empty message.
|
||||
#[derive(Copy, Clone, Default)]
|
||||
pub struct VhostUserEmpty;
|
||||
|
||||
// SAFETY: Safe because type is zero size.
|
||||
unsafe impl ByteValued for VhostUserEmpty {}
|
||||
|
||||
impl VhostUserMsgValidator for VhostUserEmpty {}
|
||||
|
||||
/// A generic message to encapsulate a 64-bit value.
|
||||
#[repr(transparent)]
|
||||
#[derive(Copy, Clone, Default)]
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue