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

Function write_region_sparse

vmm/src/memory_manager.rs:3082–3142  ·  view source on GitHub ↗

Write a single guest RAM region to the snapshot file at `dst_offset`, streaming populated extents via `SEEK_DATA` / `SEEK_HOLE` on the backing fd. `set_len(total)` must have been called on `dst` by the caller. Returns `Ok(true)` if the region was written sparsely, or `Ok(false)` if `SEEK_HOLE` is unsupported on the source fd (caller should fall back to dense write).

(
    src: &File,
    src_offset: u64,
    dst: &File,
    dst_offset: u64,
    len: u64,
)

Source from the content-addressed store, hash-verified

3080/// `Ok(false)` if `SEEK_HOLE` is unsupported on the source fd (caller
3081/// should fall back to dense write).
3082fn write_region_sparse(
3083 src: &File,
3084 src_offset: u64,
3085 dst: &File,
3086 dst_offset: u64,
3087 len: u64,
3088) -> io::Result<bool> {
3089 let src_fd = src.as_fd();
3090 let end = src_offset
3091 .checked_add(len)
3092 .ok_or_else(|| io::Error::new(io::ErrorKind::InvalidInput, "range overflow"))?;
3093
3094 // First call to next_data_extent doubles as a SEEK_HOLE-support probe:
3095 // a non-ENXIO error means the filesystem doesn't support sparse-seek;
3096 // tell the caller to use the dense path instead.
3097 let mut next = match next_data_extent(src_fd, src_offset, end) {
3098 Ok(opt) => opt,
3099 Err(_) => return Ok(false),
3100 };
3101
3102 const CHUNK: usize = 1 << 20;
3103 let mut buf = vec![0u8; CHUNK];
3104
3105 while let Some((data_off, ext_len)) = next {
3106 debug_assert!(data_off >= src_offset);
3107 let in_region = data_off
3108 .checked_sub(src_offset)
3109 .expect("extent precedes src_offset");
3110 let mut written = 0u64;
3111 while written < ext_len {
3112 let this = ((ext_len - written) as usize).min(CHUNK);
3113 let slice = &mut buf[..this];
3114 let read = src.read_at(slice, data_off + written)?;
3115 if read == 0 {
3116 return Err(io::Error::new(
3117 io::ErrorKind::UnexpectedEof,
3118 "read_at returned 0 inside data extent",
3119 ));
3120 }
3121 let mut wrote_total = 0;
3122 while wrote_total < read {
3123 let n = dst.write_at(
3124 &slice[wrote_total..read],
3125 dst_offset + in_region + written + wrote_total as u64,
3126 )?;
3127 if n == 0 {
3128 return Err(io::Error::new(
3129 io::ErrorKind::WriteZero,
3130 "write_at returned 0",
3131 ));
3132 }
3133 wrote_total += n;
3134 }
3135 written += read as u64;
3136 }
3137 // Subsequent next_data_extent failures are real I/O errors, not
3138 // unsupported-FS, since the first probe succeeded.
3139 next = next_data_extent(src_fd, data_off + ext_len, end)?;

Calls 4

newFunction · 0.85
next_data_extentFunction · 0.85
as_fdMethod · 0.45
read_atMethod · 0.45