Skip to content

内存管理:memory_manager.rs

概述

memory_manager.rs 实现了虚拟机的内存管理,包括内存分配、映射、热插拔、NUMA 和快照。本文深入分析其设计和实现。

核心结构

MemoryManager

rust
// vmm/src/memory_manager.rs (2731 行)
pub struct MemoryManager {
    // Guest 内存
    guest_memory: GuestMemoryMmap,
    
    // 内存区域
    zones: HashMap<String, VirtioMemZone>,
    
    // 热插拔槽位
    hotplug_slots: Vec<HotPlugState>,
    selected_slot: usize,
    
    // 分配器
    allocator: SystemAllocator,
    
    // 配置
    dynamic: bool,
    shared: bool,
    hugepages: bool,
    hugepage_size: Option<u64>,
    prefault: bool,
    thp: bool,
    
    // 设备
    balloon: Option<Arc<Mutex<virtio_devices::Balloon>>>,
    virtio_devices: Vec<Arc<Mutex<virtio_devices::Mem>>>,
}

VirtioMemZone

rust
// vmm/src/memory_manager.rs
pub struct VirtioMemZone {
    region: Arc<GuestRegionMmap>,
    virtio_device: Option<Arc<Mutex<virtio_devices::Mem>>>,
    hotplugged_size: u64,
    hugepages: bool,
    blocks_state: Arc<Mutex<BlocksState>>,
}

HotPlugState

rust
// vmm/src/memory_manager.rs
#[derive(Clone, Default, Serialize, Deserialize)]
struct HotPlugState {
    base: u64,
    length: u64,
    active: bool,
    inserting: bool,
    removing: bool,
}

内存创建

创建流程

实现代码

rust
// vmm/src/memory_manager.rs
impl MemoryManager {
    pub fn new(
        config: &MemoryConfig,
        platform_config: Option<PlatformConfig>,
    ) -> Result<Self> {
        // 1. 创建分配器
        let allocator = SystemAllocator::new(
            arch::layout::MEM_32BIT_RESERVED_START,
            arch::layout::MEM_32BIT_RESERVED_SIZE,
            arch::layout::RAM_START,
        )?;
        
        // 2. 创建内存区域
        let mut regions = Vec::new();
        
        if let Some(zones) = &config.zones {
            // 使用自定义 zones
            for zone in zones {
                let region = Self::create_memory_region(zone)?;
                regions.push(region);
            }
        } else {
            // 使用默认配置
            let region = Self::create_memory_region(&MemoryZoneConfig {
                id: "mem0".to_string(),
                size: config.size,
                file: None,
                shared: config.shared,
                hugepages: config.hugepages,
                hugepage_size: config.hugepage_size,
                host_numa_node: None,
                hotplug_size: config.hotplug_size,
                hotplugged_size: config.hotplugged_size,
                prefault: config.prefault,
            })?;
            regions.push(region);
        }
        
        // 3. 创建 GuestMemoryMmap
        let guest_memory = GuestMemoryMmap::from_regions(regions)?;
        
        // 4. 配置热插拔
        let mut hotplug_slots = Vec::new();
        for i in 0..HOTPLUG_COUNT {
            hotplug_slots.push(HotPlugState {
                base: 0,
                length: 0,
                active: false,
                inserting: false,
                removing: false,
            });
        }
        
        Ok(Self {
            guest_memory,
            zones: HashMap::new(),
            hotplug_slots,
            selected_slot: 0,
            allocator,
            dynamic: false,
            shared: config.shared,
            hugepages: config.hugepages,
            hugepage_size: config.hugepage_size,
            prefault: config.prefault,
            thp: config.thp,
            balloon: None,
            virtio_devices: Vec::new(),
        })
    }
}

内存区域创建

普通内存

rust
// vmm/src/memory_manager.rs
impl MemoryManager {
    fn create_memory_region(
        zone: &MemoryZoneConfig,
    ) -> Result<GuestRegionMmap> {
        let size = zone.size;
        
        // 创建 mmap 区域
        let region = if zone.shared {
            // 共享内存
            MmapRegion::new(
                size as usize,
                libc::MAP_ANONYMOUS | libc::MAP_SHARED,
                None,
            )?
        } else if zone.hugepages {
            // 大页内存
            let hugepage_size = zone.hugepage_size.unwrap_or(2 * 1024 * 1024);
            MmapRegion::new(
                size as usize,
                libc::MAP_ANONYMOUS | libc::MAP_PRIVATE | libc::MAP_HUGETLB,
                Some(hugepage_size),
            )?
        } else if zone.prefault {
            // 预分配内存
            MmapRegion::new(
                size as usize,
                libc::MAP_ANONYMOUS | libc::MAP_PRIVATE | libc::MAP_POPULATE,
                None,
            )?
        } else {
            // 普通内存
            MmapRegion::new(
                size as usize,
                libc::MAP_ANONYMOUS | libc::MAP_PRIVATE,
                None,
            )?
        };
        
        // 创建 GuestRegionMmap
        let guest_region = GuestRegionMmap::new(region, GuestAddress(0));
        
        Ok(guest_region)
    }
}

文件映射内存

rust
// vmm/src/memory_manager.rs
impl MemoryManager {
    fn create_file_backed_region(
        zone: &MemoryZoneConfig,
    ) -> Result<GuestRegionMmap> {
        let file_path = zone.file.as_ref().ok_or(Error::MissingFile)?;
        let size = zone.size;
        
        // 打开文件
        let file = OpenOptions::new()
            .read(true)
            .write(true)
            .open(file_path)?;
        
        // 设置文件大小
        file.set_len(size)?;
        
        // 创建 mmap 区域
        let region = MmapRegion::from_file(
            FileOffset::new(file, 0),
            size as usize,
        )?;
        
        // 创建 GuestRegionMmap
        let guest_region = GuestRegionMmap::new(region, GuestAddress(0));
        
        Ok(guest_region)
    }
}

内存映射

映射到 Guest

rust
// vmm/src/memory_manager.rs
impl MemoryManager {
    pub fn setup_memory_layout(&mut self) -> Result<()> {
        // 1. 映射 RAM 区域
        for (index, region) in self.guest_memory.iter().enumerate() {
            let guest_addr = arch::layout::RAM_START
                .unchecked_add(index as u64 * region.len() as u64);
            
            self.vm.set_user_memory_region(
                guest_addr.raw_value(),
                region.len() as u64,
                region.as_ptr() as u64,
                false,
                false,
            )?;
        }
        
        // 2. 映射 MMIO 区域
        // ...
        
        // 3. 映射 Reserved 区域
        // ...
        
        Ok(())
    }
}

IOMMU 映射

rust
// vmm/src/memory_manager.rs
impl MemoryManager {
    pub fn setup_iommu_mapping(&self) -> Result<()> {
        // 创建 IOMMU 映射
        let iommu_mapping = IommuMapping::new();
        
        // 映射所有内存区域
        for region in self.guest_memory.iter() {
            iommu_mapping.map(
                region.start_addr().raw_value(),
                region.start_addr().raw_value(),
                region.len() as u64,
            )?;
        }
        
        Ok(())
    }
}

内存热插拔

ACPI 热插拔

rust
// vmm/src/memory_manager.rs
impl MemoryManager {
    pub fn hotplug_memory_acpi(&mut self, size: u64) -> Result<()> {
        // 1. 找到空闲槽位
        let slot = self.find_free_slot()?;
        
        // 2. 分配内存
        let region = Self::create_memory_region(&MemoryZoneConfig {
            id: format!("hotplug-{}", slot),
            size,
            // ...
        })?;
        
        // 3. 映射到 Guest
        let guest_addr = self.allocator.allocate_mmio_addresses(size, None)?;
        self.vm.set_user_memory_region(
            guest_addr.raw_value(),
            size,
            region.as_ptr() as u64,
            false,
            false,
        )?;
        
        // 4. 更新槽位状态
        self.hotplug_slots[slot] = HotPlugState {
            base: guest_addr.raw_value(),
            length: size,
            active: true,
            inserting: true,
            removing: false,
        };
        
        // 5. 发送 ACPI 通知
        self.notify_acpi_hotplug(slot)?;
        
        Ok(())
    }
}

Virtio-mem 热插拔

rust
// vmm/src/memory_manager.rs
impl MemoryManager {
    pub fn hotplug_memory_virtio_mem(&mut self, size: u64) -> Result<()> {
        // 1. 找到 virtio-mem 设备
        let virtio_mem = self.virtio_devices.first()
            .ok_or(Error::NoVirtioMem)?;
        
        // 2. 调整大小
        virtio_mem.lock().unwrap().resize(size)?;
        
        // 3. 更新状态
        // ...
        
        Ok(())
    }
}

NUMA 支持

NUMA 配置

rust
// vmm/src/memory_manager.rs
impl MemoryManager {
    pub fn configure_numa(
        &mut self,
        numa_config: &NumaConfig,
    ) -> Result<()> {
        for node in &numa_config.guest_numa_nodes {
            // 获取内存区域
            let zones: Vec<_> = node.memory_zones.iter()
                .map(|id| self.zones.get(id).unwrap())
                .collect();
            
            // 绑定到 NUMA 节点
            for zone in zones {
                self.bind_to_numa_node(
                    zone.region(),
                    node.id,
                )?;
            }
        }
        
        Ok(())
    }
    
    fn bind_to_numa_node(
        &self,
        region: &GuestRegionMmap,
        node_id: u32,
    ) -> Result<()> {
        // 设置内存策略
        let node_mask = 1u64 << node_id;
        unsafe {
            libc::set_mempolicy(
                MPOL_BIND,
                &node_mask as *const u64,
                64,
            );
        }
        
        // 移动页面到目标节点
        unsafe {
            libc::migrate_pages(
                0,
                node_mask,
                1 << node_id,
            );
        }
        
        Ok(())
    }
}

快照与恢复

内存快照

rust
// vmm/src/memory_manager.rs
impl MemoryManager {
    pub fn snapshot(&mut self) -> Result<MemoryManagerSnapshotData> {
        let mut snapshot = Snapshot::new(MEMORY_MANAGER_SNAPSHOT_ID);
        
        // 保存每个内存区域
        for (index, region) in self.guest_memory.iter().enumerate() {
            let region_snapshot = MemoryRegionSnapshot {
                base: region.start_addr().raw_value(),
                length: region.len() as u64,
                file: region.file().map(|f| f.path().to_path_buf()),
            };
            
            snapshot.add_data_section(
                SnapshotDataSection::new_from_state(&region_snapshot)?
            );
        }
        
        // 保存热插拔状态
        snapshot.add_data_section(
            SnapshotDataSection::new_from_state(&self.hotplug_slots)?
        );
        
        Ok(snapshot)
    }
}

内存恢复

rust
// vmm/src/memory_manager.rs
impl MemoryManager {
    pub fn restore(
        &mut self,
        snapshot: MemoryManagerSnapshotData,
    ) -> Result<()> {
        // 恢复每个内存区域
        for region_snapshot in snapshot.regions {
            // 映射快照文件
            if let Some(file_path) = &region_snapshot.file {
                let file = File::open(file_path)?;
                let region = MmapRegion::from_file(
                    FileOffset::new(file, 0),
                    region_snapshot.length as usize,
                )?;
                
                // 映射到 Guest
                self.vm.set_user_memory_region(
                    region_snapshot.base,
                    region_snapshot.length,
                    region.as_ptr() as u64,
                    false,
                    false,
                )?;
            }
        }
        
        // 恢复热插拔状态
        self.hotplug_slots = snapshot.hotplug_slots;
        
        Ok(())
    }
}

内存气球

Balloon 集成

rust
// vmm/src/memory_manager.rs
impl MemoryManager {
    pub fn set_balloon(
        &mut self,
        balloon: Arc<Mutex<virtio_devices::Balloon>>,
    ) {
        self.balloon = Some(balloon);
    }
    
    pub fn inflate_balloon(&mut self, pages: u32) -> Result<()> {
        if let Some(balloon) = &self.balloon {
            balloon.lock().unwrap().inflate(pages)?;
        }
        
        Ok(())
    }
    
    pub fn deflate_balloon(&mut self, pages: u32) -> Result<()> {
        if let Some(balloon) = &self.balloon {
            balloon.lock().unwrap().deflate(pages)?;
        }
        
        Ok(())
    }
}

性能优化

1. 大页支持

rust
// vmm/src/memory_manager.rs
impl MemoryManager {
    pub fn enable_hugepages(&mut self) -> Result<()> {
        for region in self.guest_memory.iter() {
            unsafe {
                libc::madvise(
                    region.as_ptr() as *mut libc::c_void,
                    region.len(),
                    libc::MADV_HUGEPAGE,
                );
            }
        }
        
        Ok(())
    }
}

2. 透明大页

rust
// vmm/src/memory_manager.rs
impl MemoryManager {
    pub fn enable_thp(&mut self) -> Result<()> {
        for region in self.guest_memory.iter() {
            unsafe {
                libc::madvise(
                    region.as_ptr() as *mut libc::c_void,
                    region.len(),
                    libc::MADV_HUGEPAGE,
                );
            }
        }
        
        Ok(())
    }
}

3. 内存合并

rust
// vmm/src/memory_manager.rs
impl MemoryManager {
    pub fn enable_mergeable(&mut self) -> Result<()> {
        for region in self.guest_memory.iter() {
            unsafe {
                libc::madvise(
                    region.as_ptr() as *mut libc::c_void,
                    region.len(),
                    libc::MADV_MERGEABLE,
                );
            }
        }
        
        Ok(())
    }
}

错误处理

错误类型

rust
// vmm/src/memory_manager.rs
#[derive(Debug, Error)]
pub enum Error {
    #[error("Failed to create memory region: {0}")]
    CreateRegion(#[source] io::Error),
    
    #[error("Failed to mmap memory: {0}")]
    Mmap(#[source] io::Error),
    
    #[error("Failed to set user memory region: {0}")]
    SetUserMemoryRegion(#[source] hypervisor::HypervisorVmError),
    
    #[error("No free hotplug slot available")]
    NoFreeSlot,
    
    #[error("No virtio-mem device available")]
    NoVirtioMem,
    
    #[error("Missing file for file-backed region")]
    MissingFile,
    
    // ...
}

下一步