Skip to content

Commit f25aa30

Browse files
authored
membacking: map private RAM into the IOMMU (#3777)
Private anonymous guest RAM was not represented in region mappings, so it was never programmed into DMA targets. The private-memory builder committed pages directly into the eager VaMapper and skipped add_mapping, while IOMMU mappings are driven from region mappings. As a result, --private-memory with an assigned device caused DMA into private RAM to fault in the IOMMU. Register private RAM as a region mapping without a backing fd. These mappings skip the mapping-manager mmap because the pages are already committed, but still provide the host VA used by DMA targets. This lets private RAM flow through the same DMA mapping machinery as shared RAM.
1 parent 9c52a76 commit f25aa30

7 files changed

Lines changed: 566 additions & 229 deletions

File tree

openvmm/membacking/src/mapping_manager/manager.rs

Lines changed: 122 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -242,7 +242,8 @@ fn inspect_mappings(mappings: &Vec<Mapping>) -> impl '_ + Inspect {
242242
req.respond()
243243
.field("writable", mapping.params.writable)
244244
.field("mapping_type", mapping.params.mapping_type)
245-
.hex("file_offset", mapping.params.file_offset);
245+
.field("backed_by_fd", mapping.params.backing.mappable().is_some())
246+
.hex("file_offset", mapping.params.backing.file_offset());
246247
}),
247248
);
248249
}
@@ -254,15 +255,66 @@ struct Mapping {
254255
active_mappers: Vec<MapperId>,
255256
}
256257

258+
/// How a guest memory mapping is backed by host memory.
259+
#[derive(Debug, MeshPayload, Clone)]
260+
pub enum MappingBacking {
261+
/// Backed by a mappable OS object (shared memory or file). The mapping
262+
/// manager mmaps `mappable` at `file_offset` into each VA mapper, so the
263+
/// same physical pages are shared across all mappers (and shareable with
264+
/// other processes via `GuestMemorySharing`).
265+
File {
266+
/// The OS object to map.
267+
mappable: Mappable,
268+
/// The file offset into `mappable`.
269+
file_offset: u64,
270+
},
271+
/// Backed by private anonymous memory committed directly by the mapping
272+
/// manager. There is no backing fd, so the memory cannot be shared with
273+
/// other processes or programmed into DMA targets that require an fd; it is
274+
/// exposed to DMA targets purely by host VA.
275+
///
276+
/// Private memory is only valid with a single local eager mapper: lazy
277+
/// mappers and remote mappers are rejected when any range is private (see
278+
/// [`MappingManagerClient::new_mapper`] and
279+
/// [`MappingManagerClient::new_remote_mapper`]). Committing anonymous pages
280+
/// into multiple independent mappers would not share storage.
281+
///
282+
/// Unlike file-backed memory, the storage *is* the VA mapping: there is no
283+
/// fd holding the pages. Tearing the mapping down (via the region manager's
284+
/// `remove_mappings`) decommits and zeroes the pages, so a private region
285+
/// must not be transiently disabled and re-enabled — doing so would lose
286+
/// guest memory. The region manager asserts against this.
287+
Private {
288+
/// Whether the range is eligible for Transparent Huge Pages (Linux).
289+
transparent_hugepages: bool,
290+
},
291+
}
292+
293+
impl MappingBacking {
294+
/// Returns the backing object, if this mapping is file-backed.
295+
pub fn mappable(&self) -> Option<&Mappable> {
296+
match self {
297+
MappingBacking::File { mappable, .. } => Some(mappable),
298+
MappingBacking::Private { .. } => None,
299+
}
300+
}
301+
302+
/// Returns the offset within the backing object, or 0 if there is none.
303+
pub fn file_offset(&self) -> u64 {
304+
match self {
305+
MappingBacking::File { file_offset, .. } => *file_offset,
306+
MappingBacking::Private { .. } => 0,
307+
}
308+
}
309+
}
310+
257311
/// The mapping parameters.
258312
#[derive(Debug, MeshPayload, Clone)]
259313
pub struct MappingParams {
260314
/// The memory range for the mapping.
261315
pub range: MemoryRange,
262-
/// The OS object to map.
263-
pub mappable: Mappable,
264-
/// The file offset into `mappable`.
265-
pub file_offset: u64,
316+
/// How the mapping is backed by host memory.
317+
pub backing: MappingBacking,
266318
/// Whether to map the memory as writable.
267319
pub writable: bool,
268320
/// The type of memory being mapped.
@@ -593,7 +645,11 @@ impl MappingManagerTask {
593645
fn get_dma_target_mappings(&self) -> Vec<MappingParams> {
594646
self.mappings
595647
.iter()
596-
.filter(|m| m.params.mapping_type == MappingType::Ram)
648+
// Only file-backed RAM can be shared with other processes;
649+
// private/anonymous RAM has no fd to hand out.
650+
.filter(|m| {
651+
m.params.mapping_type == MappingType::Ram && m.params.backing.mappable().is_some()
652+
})
597653
.map(|m| m.params.clone())
598654
.collect()
599655
}
@@ -653,11 +709,14 @@ impl ProvideShareableRegions for DmaRegionProvider {
653709

654710
Ok(mappings
655711
.into_iter()
656-
.map(|m| ShareableRegion {
657-
guest_address: m.range.start(),
658-
size: m.range.len(),
659-
file: m.mappable.inner_arc(),
660-
file_offset: m.file_offset,
712+
.filter_map(|m| {
713+
let mappable = m.backing.mappable()?;
714+
Some(ShareableRegion {
715+
guest_address: m.range.start(),
716+
size: m.range.len(),
717+
file: mappable.inner_arc(),
718+
file_offset: m.backing.file_offset(),
719+
})
661720
})
662721
.collect())
663722
}
@@ -686,8 +745,10 @@ mod tests {
686745
client
687746
.add_mapping(MappingParams {
688747
range: MemoryRange::new(0..0x100000),
689-
mappable: ram,
690-
file_offset: 0,
748+
backing: MappingBacking::File {
749+
mappable: ram,
750+
file_offset: 0,
751+
},
691752
writable: true,
692753
mapping_type: MappingType::Ram,
693754
numa_node: None,
@@ -698,8 +759,10 @@ mod tests {
698759
client
699760
.add_mapping(MappingParams {
700761
range: MemoryRange::new(0x100000..0x101000),
701-
mappable: device,
702-
file_offset: 0,
762+
backing: MappingBacking::File {
763+
mappable: device,
764+
file_offset: 0,
765+
},
703766
writable: true,
704767
mapping_type: MappingType::Device,
705768
numa_node: None,
@@ -731,8 +794,10 @@ mod tests {
731794
client
732795
.add_mapping(MappingParams {
733796
range: MemoryRange::new(0..0x1000),
734-
mappable,
735-
file_offset: 0,
797+
backing: MappingBacking::File {
798+
mappable,
799+
file_offset: 0,
800+
},
736801
writable: true,
737802
mapping_type: MappingType::Device,
738803
numa_node: None,
@@ -755,8 +820,10 @@ mod tests {
755820
.into();
756821
let params = MappingParams {
757822
range: MemoryRange::new(0..0x10000),
758-
mappable,
759-
file_offset: 0,
823+
backing: MappingBacking::File {
824+
mappable,
825+
file_offset: 0,
826+
},
760827
writable: true,
761828
mapping_type: MappingType::Ram,
762829
numa_node: None,
@@ -829,8 +896,10 @@ mod tests {
829896
.into();
830897
let params = MappingParams {
831898
range: MemoryRange::new(0..0x1000),
832-
mappable,
833-
file_offset: 0,
899+
backing: MappingBacking::File {
900+
mappable,
901+
file_offset: 0,
902+
},
834903
writable: true,
835904
mapping_type: MappingType::Device,
836905
numa_node: None,
@@ -942,8 +1011,10 @@ mod tests {
9421011
.into();
9431012
let params = MappingParams {
9441013
range: MemoryRange::new(0..0x1000),
945-
mappable,
946-
file_offset: 0,
1014+
backing: MappingBacking::File {
1015+
mappable,
1016+
file_offset: 0,
1017+
},
9471018
writable: true,
9481019
mapping_type: MappingType::Device,
9491020
numa_node: None,
@@ -1060,8 +1131,10 @@ mod tests {
10601131
.into();
10611132
task.add_mapping(MappingParams {
10621133
range: MemoryRange::new(start..end),
1063-
mappable,
1064-
file_offset: 0,
1134+
backing: MappingBacking::File {
1135+
mappable,
1136+
file_offset: 0,
1137+
},
10651138
writable: true,
10661139
mapping_type: MappingType::Ram,
10671140
numa_node: None,
@@ -1148,8 +1221,10 @@ mod tests {
11481221
.into();
11491222
let params = MappingParams {
11501223
range: MemoryRange::new(0..0x1000),
1151-
mappable,
1152-
file_offset: 0,
1224+
backing: MappingBacking::File {
1225+
mappable,
1226+
file_offset: 0,
1227+
},
11531228
writable: true,
11541229
mapping_type: MappingType::Device,
11551230
numa_node: None,
@@ -1255,8 +1330,10 @@ mod tests {
12551330
.into();
12561331
task.add_mapping(MappingParams {
12571332
range: MemoryRange::new(0x20000..0x21000),
1258-
mappable,
1259-
file_offset: 0,
1333+
backing: MappingBacking::File {
1334+
mappable,
1335+
file_offset: 0,
1336+
},
12601337
writable: true,
12611338
mapping_type: MappingType::Device,
12621339
numa_node: None,
@@ -1362,8 +1439,10 @@ mod tests {
13621439
client
13631440
.add_mapping(MappingParams {
13641441
range: MemoryRange::new(0..0x10000),
1365-
mappable,
1366-
file_offset: 0,
1442+
backing: MappingBacking::File {
1443+
mappable,
1444+
file_offset: 0,
1445+
},
13671446
writable: true,
13681447
mapping_type: MappingType::Device,
13691448
numa_node: None,
@@ -1410,8 +1489,10 @@ mod tests {
14101489
client
14111490
.add_mapping(MappingParams {
14121491
range: MemoryRange::new(0..0x10000),
1413-
mappable,
1414-
file_offset: 0,
1492+
backing: MappingBacking::File {
1493+
mappable,
1494+
file_offset: 0,
1495+
},
14151496
writable: true,
14161497
mapping_type: MappingType::Ram,
14171498
numa_node: None,
@@ -1446,8 +1527,10 @@ mod tests {
14461527
client
14471528
.add_mapping(MappingParams {
14481529
range: MemoryRange::new(0..0x10000),
1449-
mappable,
1450-
file_offset: 0,
1530+
backing: MappingBacking::File {
1531+
mappable,
1532+
file_offset: 0,
1533+
},
14511534
writable: true,
14521535
mapping_type: MappingType::Device,
14531536
numa_node: None,
@@ -1475,8 +1558,10 @@ mod tests {
14751558
client
14761559
.add_mapping(MappingParams {
14771560
range: MemoryRange::new(0x10000..0x11000),
1478-
mappable,
1479-
file_offset: 0,
1561+
backing: MappingBacking::File {
1562+
mappable,
1563+
file_offset: 0,
1564+
},
14801565
writable: true,
14811566
mapping_type: MappingType::Device,
14821567
numa_node: None,

openvmm/membacking/src/mapping_manager/mod.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ mod mappable;
88
mod object_cache;
99
mod va_mapper;
1010

11+
pub use manager::MappingBacking;
1112
pub use manager::MappingManager;
1213
pub use manager::MappingManagerClient;
1314
pub use manager::MappingParams;

0 commit comments

Comments
 (0)