Skip to content

Commit b2a8009

Browse files
bonzinijiangliu
authored andcommitted
mmap: add methods for hot-add and hot-remove
Extend GuestMemoryMmap with methods that return a new memory map with a memory region added or removed, and add a test explaining how it is meant to be used. Based on a patch by Liu Jiang, <gerry@linux.alibaba.com>. Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
1 parent 8c9d013 commit b2a8009

File tree

2 files changed

+141
-1
lines changed

2 files changed

+141
-1
lines changed

src/atomic.rs

Lines changed: 44 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -136,7 +136,7 @@ mod tests {
136136
use super::*;
137137
use crate::{
138138
GuestAddress, GuestMemory, GuestMemoryMmap, GuestMemoryRegion, GuestMemoryResult,
139-
GuestUsize,
139+
GuestRegionMmap, GuestUsize, MmapRegion,
140140
};
141141

142142
type GuestMemoryMmapAtomic = GuestMemoryAtomic<GuestMemoryMmap>;
@@ -202,4 +202,47 @@ mod tests {
202202
assert!(mem3.find_region(GuestAddress(0x1000)).is_some());
203203
assert!(mem3.find_region(GuestAddress(0x10000)).is_none());
204204
}
205+
206+
#[test]
207+
fn test_atomic_hotplug() {
208+
let region_size = 0x1000;
209+
let regions = vec![
210+
(GuestAddress(0x0), region_size),
211+
(GuestAddress(0x10_0000), region_size),
212+
];
213+
let mut gmm = Arc::new(GuestMemoryMmap::from_ranges(&regions).unwrap());
214+
let gm: GuestMemoryAtomic<_> = gmm.clone().into();
215+
let mem_orig = gm.memory();
216+
assert_eq!(mem_orig.num_regions(), 2);
217+
218+
{
219+
let guard = gm.lock().unwrap();
220+
let new_gmm = Arc::make_mut(&mut gmm);
221+
let mmap = Arc::new(
222+
GuestRegionMmap::new(MmapRegion::new(0x1000).unwrap(), GuestAddress(0x8000))
223+
.unwrap(),
224+
);
225+
let new_gmm = new_gmm.insert_region(mmap).unwrap();
226+
let mmap = Arc::new(
227+
GuestRegionMmap::new(MmapRegion::new(0x1000).unwrap(), GuestAddress(0x4000))
228+
.unwrap(),
229+
);
230+
let new_gmm = new_gmm.insert_region(mmap).unwrap();
231+
let mmap = Arc::new(
232+
GuestRegionMmap::new(MmapRegion::new(0x1000).unwrap(), GuestAddress(0xc000))
233+
.unwrap(),
234+
);
235+
let new_gmm = new_gmm.insert_region(mmap).unwrap();
236+
let mmap = Arc::new(
237+
GuestRegionMmap::new(MmapRegion::new(0x1000).unwrap(), GuestAddress(0xc000))
238+
.unwrap(),
239+
);
240+
new_gmm.insert_region(mmap).unwrap_err();
241+
guard.replace(new_gmm);
242+
}
243+
244+
assert_eq!(mem_orig.num_regions(), 2);
245+
let mem = gm.memory();
246+
assert_eq!(mem.num_regions(), 5);
247+
}
205248
}

src/mmap.rs

Lines changed: 97 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -461,6 +461,43 @@ impl GuestMemoryMmap {
461461

462462
Ok(Self { regions })
463463
}
464+
465+
/// Insert a region into the `GuestMemoryMmap` object and return a new `GuestMemoryMmap`.
466+
///
467+
/// # Arguments
468+
/// * `region`: the memory region to insert into the guest memory object.
469+
pub fn insert_region(
470+
&self,
471+
region: Arc<GuestRegionMmap>,
472+
) -> result::Result<GuestMemoryMmap, Error> {
473+
let mut regions = self.regions.clone();
474+
regions.push(region);
475+
regions.sort_by_key(|x| x.start_addr());
476+
477+
Self::from_arc_regions(regions)
478+
}
479+
480+
/// Remove a region into the `GuestMemoryMmap` object and return a new `GuestMemoryMmap`
481+
/// on success, together with the removed region.
482+
///
483+
/// # Arguments
484+
/// * `base`: base address of the region to be removed
485+
/// * `size`: size of the region to be removed
486+
pub fn remove_region(
487+
&self,
488+
base: GuestAddress,
489+
size: GuestUsize,
490+
) -> result::Result<(GuestMemoryMmap, Arc<GuestRegionMmap>), Error> {
491+
if let Ok(region_index) = self.regions.binary_search_by_key(&base, |x| x.start_addr()) {
492+
if self.regions.get(region_index).unwrap().size() as GuestUsize == size {
493+
let mut regions = self.regions.clone();
494+
let region = regions.remove(region_index);
495+
return Ok((Self { regions }, region));
496+
}
497+
}
498+
499+
Err(Error::InvalidGuestRegion)
500+
}
464501
}
465502

466503
impl GuestMemory for GuestMemoryMmap {
@@ -1204,4 +1241,64 @@ mod tests {
12041241
assert!(region.file_offset().is_some());
12051242
assert_eq!(region.file_offset().unwrap().start(), offset);
12061243
}
1244+
1245+
#[test]
1246+
fn test_mmap_insert_region() {
1247+
let region_size = 0x1000;
1248+
let regions = vec![
1249+
(GuestAddress(0x0), region_size),
1250+
(GuestAddress(0x10_0000), region_size),
1251+
];
1252+
let gm = Arc::new(GuestMemoryMmap::from_ranges(&regions).unwrap());
1253+
let mem_orig = gm.memory();
1254+
assert_eq!(mem_orig.num_regions(), 2);
1255+
1256+
let mmap = Arc::new(
1257+
GuestRegionMmap::new(MmapRegion::new(0x1000).unwrap(), GuestAddress(0x8000)).unwrap(),
1258+
);
1259+
let gm = gm.insert_region(mmap).unwrap();
1260+
let mmap = Arc::new(
1261+
GuestRegionMmap::new(MmapRegion::new(0x1000).unwrap(), GuestAddress(0x4000)).unwrap(),
1262+
);
1263+
let gm = gm.insert_region(mmap).unwrap();
1264+
let mmap = Arc::new(
1265+
GuestRegionMmap::new(MmapRegion::new(0x1000).unwrap(), GuestAddress(0xc000)).unwrap(),
1266+
);
1267+
let gm = gm.insert_region(mmap).unwrap();
1268+
let mmap = Arc::new(
1269+
GuestRegionMmap::new(MmapRegion::new(0x1000).unwrap(), GuestAddress(0xc000)).unwrap(),
1270+
);
1271+
gm.insert_region(mmap).unwrap_err();
1272+
1273+
assert_eq!(mem_orig.num_regions(), 2);
1274+
assert_eq!(gm.num_regions(), 5);
1275+
1276+
assert_eq!(gm.regions[0].start_addr(), GuestAddress(0x0000));
1277+
assert_eq!(gm.regions[1].start_addr(), GuestAddress(0x4000));
1278+
assert_eq!(gm.regions[2].start_addr(), GuestAddress(0x8000));
1279+
assert_eq!(gm.regions[3].start_addr(), GuestAddress(0xc000));
1280+
assert_eq!(gm.regions[4].start_addr(), GuestAddress(0x10_0000));
1281+
}
1282+
1283+
#[test]
1284+
fn test_mmap_remove_region() {
1285+
let region_size = 0x1000;
1286+
let regions = vec![
1287+
(GuestAddress(0x0), region_size),
1288+
(GuestAddress(0x10_0000), region_size),
1289+
];
1290+
let gm = Arc::new(GuestMemoryMmap::from_ranges(&regions).unwrap());
1291+
let mem_orig = gm.memory();
1292+
assert_eq!(mem_orig.num_regions(), 2);
1293+
1294+
gm.remove_region(GuestAddress(0), 128).unwrap_err();
1295+
gm.remove_region(GuestAddress(0x4000), 128).unwrap_err();
1296+
let (gm, region) = gm.remove_region(GuestAddress(0x10_0000), 0x1000).unwrap();
1297+
1298+
assert_eq!(mem_orig.num_regions(), 2);
1299+
assert_eq!(gm.num_regions(), 1);
1300+
1301+
assert_eq!(gm.regions[0].start_addr(), GuestAddress(0x0000));
1302+
assert_eq!(region.start_addr(), GuestAddress(0x10_0000));
1303+
}
12071304
}

0 commit comments

Comments
 (0)