MCPcopy Create free account
hub / github.com/cloud-hypervisor/cloud-hypervisor / restore_by_uffd

Method restore_by_uffd

vmm/src/memory_manager.rs:938–1076  ·  view source on GitHub ↗

Restore guest memory using userfaultfd for lazy demand paging. Instead of reading the entire snapshot into guest RAM upfront (which blocks restore for hundreds of milliseconds at multi-GB sizes), this registers the guest memory regions with a userfaultfd. A background thread handles page faults by reading the corresponding page from the snapshot file and copying it into guest memory via `UFFDIO_C

(
        &mut self,
        file_path: &Path,
        saved_regions: &MemoryRangeTable,
        exit_evt: &EventFd,
    )

Source from the content-addressed store, hash-verified

936 /// is active. The file must remain available until the VM is shut down or
937 /// all faulted pages have been served.
938 fn restore_by_uffd(
939 &mut self,
940 file_path: &Path,
941 saved_regions: &MemoryRangeTable,
942 exit_evt: &EventFd,
943 ) -> Result<(), Error> {
944 if saved_regions.is_empty() {
945 return Ok(());
946 }
947
948 let guest_memory = self.guest_memory.memory();
949 let required_uffd_features = self.required_uffd_features();
950
951 // SAFETY: FFI call. Trivially safe.
952 let base_page_size = unsafe { libc::sysconf(libc::_SC_PAGESIZE) } as u64;
953
954 info!(
955 "UFFD restore: attempting demand-paged restore for {} region(s)",
956 saved_regions.regions().len()
957 );
958
959 if saved_regions
960 .regions()
961 .iter()
962 .any(|range| range.gpa % base_page_size != 0 || range.length % base_page_size != 0)
963 {
964 return Err(UffdError::UnalignedRanges.into());
965 }
966
967 let snapshot_file = File::open(file_path).map_err(Error::SnapshotOpen)?;
968
969 let uffd_fd = uffd::create(required_uffd_features).map_err(UffdError::Create)?;
970
971 let mut handler_ranges: Vec<UffdRange> = Vec::new();
972 let mut file_offset: u64 = 0;
973
974 for range in saved_regions.regions() {
975 let host_addr = guest_memory
976 .get_host_address(GuestAddress(range.gpa))
977 .map_err(|_| UffdError::GpaTranslation { gpa: range.gpa })?
978 as u64;
979
980 let ioctls = uffd::register(uffd_fd.as_fd(), host_addr, range.length).map_err(|e| {
981 UffdError::Register {
982 addr: host_addr,
983 len: range.length,
984 source: e,
985 }
986 })?;
987
988 if ioctls & crate::userfaultfd::UFFD_API_RANGE_IOCTLS_BASIC
989 != crate::userfaultfd::UFFD_API_RANGE_IOCTLS_BASIC
990 {
991 return Err(UffdError::MissingIoctlSupport {
992 addr: host_addr,
993 len: range.length,
994 }
995 .into());

Callers 1

new_from_snapshotMethod · 0.80

Calls 15

createFunction · 0.85
newFunction · 0.85
registerFunction · 0.85
memoryMethod · 0.80
iterMethod · 0.80
spawnMethod · 0.80
okMethod · 0.80
is_emptyMethod · 0.45
regionsMethod · 0.45
as_fdMethod · 0.45

Tested by

no test coverage detected