Generate a table for the pages that are dirty. The dirty pages are collapsed together in the table if they are contiguous.
(&mut self)
| 3265 | // Generate a table for the pages that are dirty. The dirty pages are collapsed |
| 3266 | // together in the table if they are contiguous. |
| 3267 | fn dirty_log(&mut self) -> std::result::Result<MemoryRangeTable, MigratableError> { |
| 3268 | let mut table = MemoryRangeTable::default(); |
| 3269 | for r in &self.guest_ram_mappings { |
| 3270 | let vm_dirty_bitmap = self.vm.get_dirty_log(r.slot, r.gpa, r.size).map_err(|e| { |
| 3271 | MigratableError::MigrateSend(anyhow!("Error getting VM dirty log {e}")) |
| 3272 | })?; |
| 3273 | let vmm_dirty_bitmap = match self.guest_memory.memory().find_region(GuestAddress(r.gpa)) |
| 3274 | { |
| 3275 | Some(region) => { |
| 3276 | assert!(region.start_addr().raw_value() == r.gpa); |
| 3277 | assert!(region.len() == r.size); |
| 3278 | (**region).bitmap().get_and_reset() |
| 3279 | } |
| 3280 | None => { |
| 3281 | return Err(MigratableError::MigrateSend(anyhow!( |
| 3282 | "Error finding 'guest memory region' with address {:x}", |
| 3283 | r.gpa |
| 3284 | ))); |
| 3285 | } |
| 3286 | }; |
| 3287 | |
| 3288 | let dirty_bitmap = vm_dirty_bitmap |
| 3289 | .iter() |
| 3290 | .zip(vmm_dirty_bitmap.iter()) |
| 3291 | .map(|(x, y)| x | y); |
| 3292 | |
| 3293 | let sub_table = MemoryRangeTable::from_dirty_bitmap(dirty_bitmap, r.gpa, 4096); |
| 3294 | |
| 3295 | if sub_table.regions().is_empty() { |
| 3296 | debug!("Dirty Memory Range Table is empty"); |
| 3297 | } else { |
| 3298 | debug!("Dirty Memory Range Table:"); |
| 3299 | for range in sub_table.regions() { |
| 3300 | debug!("GPA: {:x} size: {} (KiB)", range.gpa, range.length / 1024); |
| 3301 | } |
| 3302 | } |
| 3303 | |
| 3304 | table.extend(sub_table); |
| 3305 | } |
| 3306 | Ok(table) |
| 3307 | } |
| 3308 | } |
| 3309 | |
| 3310 | #[cfg(test)] |
nothing calls this directly
no test coverage detected