内存管理: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(®ion_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) = ®ion_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,
// ...
}