dbs_address_space/memory/
mod.rs

1// Copyright (C) 2022 Alibaba Cloud. All rights reserved.
2// SPDX-License-Identifier: Apache-2.0
3
4//! Structs to manage guest memory for virtual machines.
5//!
6//! The `vm-memory` crate only provides traits and structs to access normal guest memory,
7//! it doesn't support special guest memory like virtio-fs/virtio-pmem DAX window etc.
8//! So this crate provides `GuestMemoryManager` over `vm-memory` to provide uniform abstraction
9//! for all guest memory.
10//!
11//! It also provides interfaces to coordinate guest memory hotplug events.
12
13use std::str::FromStr;
14use std::sync::Arc;
15use vm_memory::{GuestAddressSpace, GuestMemoryAtomic, GuestMemoryLoadGuard, GuestMemoryMmap};
16
17mod raw_region;
18pub use raw_region::GuestRegionRaw;
19
20mod hybrid;
21pub use hybrid::{GuestMemoryHybrid, GuestRegionHybrid};
22
23/// Type of source to allocate memory for virtual machines.
24#[derive(Debug, Eq, PartialEq)]
25pub enum MemorySourceType {
26    /// File on HugeTlbFs.
27    FileOnHugeTlbFs,
28    /// mmap() without flag `MAP_HUGETLB`.
29    MmapAnonymous,
30    /// mmap() with flag `MAP_HUGETLB`.
31    MmapAnonymousHugeTlbFs,
32    /// memfd() without flag `MFD_HUGETLB`.
33    MemFdShared,
34    /// memfd() with flag `MFD_HUGETLB`.
35    MemFdOnHugeTlbFs,
36}
37
38impl MemorySourceType {
39    /// Check whether the memory source is huge page.
40    pub fn is_hugepage(&self) -> bool {
41        *self == Self::FileOnHugeTlbFs
42            || *self == Self::MmapAnonymousHugeTlbFs
43            || *self == Self::MemFdOnHugeTlbFs
44    }
45
46    /// Check whether the memory source is anonymous memory.
47    pub fn is_mmap_anonymous(&self) -> bool {
48        *self == Self::MmapAnonymous || *self == Self::MmapAnonymousHugeTlbFs
49    }
50}
51
52impl FromStr for MemorySourceType {
53    type Err = String;
54
55    fn from_str(s: &str) -> Result<Self, Self::Err> {
56        match s {
57            "hugetlbfs" => Ok(MemorySourceType::FileOnHugeTlbFs),
58            "memfd" => Ok(MemorySourceType::MemFdShared),
59            "shmem" => Ok(MemorySourceType::MemFdShared),
60            "hugememfd" => Ok(MemorySourceType::MemFdOnHugeTlbFs),
61            "hugeshmem" => Ok(MemorySourceType::MemFdOnHugeTlbFs),
62            "anon" => Ok(MemorySourceType::MmapAnonymous),
63            "mmap" => Ok(MemorySourceType::MmapAnonymous),
64            "hugeanon" => Ok(MemorySourceType::MmapAnonymousHugeTlbFs),
65            "hugemmap" => Ok(MemorySourceType::MmapAnonymousHugeTlbFs),
66            _ => Err(format!("unknown memory source type {s}")),
67        }
68    }
69}
70
71#[derive(Debug, Default)]
72struct GuestMemoryHotplugManager {}
73
74/// The `GuestMemoryManager` manages all guest memory for virtual machines.
75///
76/// The `GuestMemoryManager` fulfills several different responsibilities.
77/// - First, it manages different types of guest memory, such as normal guest memory, virtio-fs
78///   DAX window and virtio-pmem DAX window etc. Different clients may want to access different
79///   types of memory. So the manager maintains two GuestMemory objects, one contains all guest
80///   memory, the other contains only normal guest memory.
81/// - Second, it coordinates memory/DAX window hotplug events, so clients may register hooks
82///   to receive hotplug notifications.
83#[allow(unused)]
84#[derive(Debug, Clone)]
85pub struct GuestMemoryManager {
86    default: GuestMemoryAtomic<GuestMemoryHybrid>,
87    /// GuestMemory object hosts all guest memory.
88    hybrid: GuestMemoryAtomic<GuestMemoryHybrid>,
89    /// GuestMemory object for vIOMMU.
90    iommu: GuestMemoryAtomic<GuestMemoryHybrid>,
91    /// GuestMemory object hosts normal guest memory.
92    normal: GuestMemoryAtomic<GuestMemoryMmap>,
93    hotplug: Arc<GuestMemoryHotplugManager>,
94}
95
96impl GuestMemoryManager {
97    /// Create a new instance of `GuestMemoryManager`.
98    pub fn new() -> Self {
99        Self::default()
100    }
101
102    /// Get a reference to the normal `GuestMemory` object.
103    pub fn get_normal_guest_memory(&self) -> &GuestMemoryAtomic<GuestMemoryMmap> {
104        &self.normal
105    }
106
107    /// Try to downcast the `GuestAddressSpace` object to a `GuestMemoryManager` object.
108    pub fn to_manager<AS: GuestAddressSpace>(_m: &AS) -> Option<&Self> {
109        None
110    }
111}
112
113impl Default for GuestMemoryManager {
114    fn default() -> Self {
115        let hybrid = GuestMemoryAtomic::new(GuestMemoryHybrid::new());
116        let iommu = GuestMemoryAtomic::new(GuestMemoryHybrid::new());
117        let normal = GuestMemoryAtomic::new(GuestMemoryMmap::new());
118        // By default, it provides to the `GuestMemoryHybrid` object containing all guest memory.
119        let default = hybrid.clone();
120
121        GuestMemoryManager {
122            default,
123            hybrid,
124            iommu,
125            normal,
126            hotplug: Arc::new(GuestMemoryHotplugManager::default()),
127        }
128    }
129}
130
131impl GuestAddressSpace for GuestMemoryManager {
132    type M = GuestMemoryHybrid;
133    type T = GuestMemoryLoadGuard<GuestMemoryHybrid>;
134
135    fn memory(&self) -> Self::T {
136        self.default.memory()
137    }
138}
139
140#[cfg(test)]
141mod tests {
142    use super::*;
143
144    #[test]
145    fn test_memory_source_type() {
146        assert_eq!(
147            MemorySourceType::from_str("hugetlbfs").unwrap(),
148            MemorySourceType::FileOnHugeTlbFs
149        );
150        assert_eq!(
151            MemorySourceType::from_str("memfd").unwrap(),
152            MemorySourceType::MemFdShared
153        );
154        assert_eq!(
155            MemorySourceType::from_str("shmem").unwrap(),
156            MemorySourceType::MemFdShared
157        );
158        assert_eq!(
159            MemorySourceType::from_str("hugememfd").unwrap(),
160            MemorySourceType::MemFdOnHugeTlbFs
161        );
162        assert_eq!(
163            MemorySourceType::from_str("hugeshmem").unwrap(),
164            MemorySourceType::MemFdOnHugeTlbFs
165        );
166        assert_eq!(
167            MemorySourceType::from_str("anon").unwrap(),
168            MemorySourceType::MmapAnonymous
169        );
170        assert_eq!(
171            MemorySourceType::from_str("mmap").unwrap(),
172            MemorySourceType::MmapAnonymous
173        );
174        assert_eq!(
175            MemorySourceType::from_str("hugeanon").unwrap(),
176            MemorySourceType::MmapAnonymousHugeTlbFs
177        );
178        assert_eq!(
179            MemorySourceType::from_str("hugemmap").unwrap(),
180            MemorySourceType::MmapAnonymousHugeTlbFs
181        );
182        assert!(MemorySourceType::from_str("test").is_err());
183    }
184
185    #[ignore]
186    #[test]
187    fn test_to_manager() {
188        let manager = GuestMemoryManager::new();
189        let mgr = GuestMemoryManager::to_manager(&manager).unwrap();
190
191        assert_eq!(&manager as *const _, mgr as *const _);
192    }
193}