(
&self,
_snapshot: &Snapshot,
destination_url: &str,
)
| 3143 | |
| 3144 | impl Transportable for MemoryManager { |
| 3145 | fn send( |
| 3146 | &self, |
| 3147 | _snapshot: &Snapshot, |
| 3148 | destination_url: &str, |
| 3149 | ) -> result::Result<(), MigratableError> { |
| 3150 | if self.snapshot_memory_ranges.is_empty() { |
| 3151 | return Ok(()); |
| 3152 | } |
| 3153 | |
| 3154 | let mut memory_file_path = url_to_path(destination_url)?; |
| 3155 | memory_file_path.push(String::from(SNAPSHOT_FILENAME)); |
| 3156 | |
| 3157 | let mut memory_file = OpenOptions::new() |
| 3158 | .read(true) |
| 3159 | .write(true) |
| 3160 | .create_new(true) |
| 3161 | .open(&memory_file_path) |
| 3162 | .map_err(|e| MigratableError::MigrateSend(e.into()))?; |
| 3163 | |
| 3164 | let total_len: u64 = self |
| 3165 | .snapshot_memory_ranges |
| 3166 | .regions() |
| 3167 | .iter() |
| 3168 | .map(|r| r.length) |
| 3169 | .sum(); |
| 3170 | |
| 3171 | // Pre-size the file so per-region write_at lands at the dense-layout |
| 3172 | // offset. On filesystems that support sparse files unwritten bytes |
| 3173 | // become real holes; on others the kernel zero-fills the allocation, |
| 3174 | // which is still byte-correct. If extending the file is not |
| 3175 | // supported by the destination filesystem (some FUSE backends |
| 3176 | // reject ftruncate-extend with EOPNOTSUPP), fall back to the dense |
| 3177 | // write path which never writes past the growing EOF. |
| 3178 | let sparse_layout = memory_file.set_len(total_len).is_ok(); |
| 3179 | |
| 3180 | let guest_memory = self.guest_memory.memory(); |
| 3181 | let mut file_cursor: u64 = 0; |
| 3182 | |
| 3183 | for range in self.snapshot_memory_ranges.regions() { |
| 3184 | let mut wrote_sparse = false; |
| 3185 | if sparse_layout |
| 3186 | && let Some(region) = guest_memory.find_region(GuestAddress(range.gpa)) |
| 3187 | && (region.flags() & libc::MAP_SHARED) == libc::MAP_SHARED |
| 3188 | && let Some(file_offset) = region.file_offset() |
| 3189 | { |
| 3190 | let region_base = region.start_addr().raw_value(); |
| 3191 | let in_fd_off = file_offset.start() |
| 3192 | + range |
| 3193 | .gpa |
| 3194 | .checked_sub(region_base) |
| 3195 | .expect("range outside its region"); |
| 3196 | wrote_sparse = write_region_sparse( |
| 3197 | file_offset.file(), |
| 3198 | in_fd_off, |
| 3199 | &memory_file, |
| 3200 | file_cursor, |
| 3201 | range.length, |
| 3202 | ) |
no test coverage detected