devices: ivshmem: Don't remap file on BAR reprogramming

The ivshmem device was remapping the host file every time the BAR was
reprogrammed. This occurs on the vCPU thread and so was falling foul of
our improved seccomp filters. Avoid this by maintaining the existing
region when the device BARs are changed and just adjust the guest GPA.

Assisted-by: Codex:GPT-5.6
Signed-off-by: Rob Bradford <rbradford@meta.com>
This commit is contained in:
Rob Bradford
2026-07-29 10:09:46 +01:00
parent 660b18eaac
commit 8268a4fd5b
2 changed files with 28 additions and 17 deletions

View File

@@ -49,6 +49,8 @@ pub enum IvshmemError {
CreateUserspaceMapping(#[source] anyhow::Error), CreateUserspaceMapping(#[source] anyhow::Error),
#[error("Failed to remove old userspace mapping.")] #[error("Failed to remove old userspace mapping.")]
RemoveUserspaceMapping(#[source] anyhow::Error), RemoveUserspaceMapping(#[source] anyhow::Error),
#[error("Missing memory region")]
MissingMemoryRegion,
} }
#[derive(Copy, Clone)] #[derive(Copy, Clone)]
@@ -70,6 +72,12 @@ pub trait IvshmemOps: Send + Sync {
backing_file: Option<PathBuf>, backing_file: Option<PathBuf>,
) -> Result<(Arc<MmapRegion>, UserspaceMapping), IvshmemError>; ) -> Result<(Arc<MmapRegion>, UserspaceMapping), IvshmemError>;
fn create_userspace_mapping(
&mut self,
start_addr: u64,
region: Arc<MmapRegion>,
) -> Result<UserspaceMapping, IvshmemError>;
fn unmap_ram_region(&mut self, mapping: UserspaceMapping) -> Result<(), IvshmemError>; fn unmap_ram_region(&mut self, mapping: UserspaceMapping) -> Result<(), IvshmemError>;
} }
@@ -94,7 +102,6 @@ pub struct IvshmemDevice {
region_size: u64, region_size: u64,
ivshmem_ops: Arc<Mutex<dyn IvshmemOps>>, ivshmem_ops: Arc<Mutex<dyn IvshmemOps>>,
backend_file: Option<PathBuf>,
region: Option<Arc<MmapRegion>>, region: Option<Arc<MmapRegion>>,
userspace_mapping: Option<UserspaceMapping>, userspace_mapping: Option<UserspaceMapping>,
} }
@@ -111,7 +118,6 @@ impl IvshmemDevice {
pub fn new( pub fn new(
id: String, id: String,
region_size: u64, region_size: u64,
backend_file: Option<PathBuf>,
ivshmem_ops: Arc<Mutex<dyn IvshmemOps>>, ivshmem_ops: Arc<Mutex<dyn IvshmemOps>>,
snapshot: Option<&Snapshot>, snapshot: Option<&Snapshot>,
) -> Result<Self, IvshmemError> { ) -> Result<Self, IvshmemError> {
@@ -159,7 +165,6 @@ impl IvshmemDevice {
ivshmem_ops, ivshmem_ops,
region: None, region: None,
userspace_mapping: None, userspace_mapping: None,
backend_file,
} }
} else { } else {
IvshmemDevice { IvshmemDevice {
@@ -174,7 +179,6 @@ impl IvshmemDevice {
ivshmem_ops, ivshmem_ops,
region: None, region: None,
userspace_mapping: None, userspace_mapping: None,
backend_file,
} }
}; };
Ok(device) Ok(device)
@@ -353,6 +357,10 @@ impl PciDevice for IvshmemDevice {
fn move_bar(&mut self, old_base: u64, new_base: u64) -> io::Result<()> { fn move_bar(&mut self, old_base: u64, new_base: u64) -> io::Result<()> {
if new_base == self.data_bar_addr() { if new_base == self.data_bar_addr() {
let region = self
.region
.clone()
.ok_or_else(|| io::Error::other(IvshmemError::MissingMemoryRegion))?;
if let Some(old_mapping) = self.userspace_mapping.take() { if let Some(old_mapping) = self.userspace_mapping.take() {
self.ivshmem_ops self.ivshmem_ops
.lock() .lock()
@@ -360,17 +368,13 @@ impl PciDevice for IvshmemDevice {
.unmap_ram_region(old_mapping) .unmap_ram_region(old_mapping)
.map_err(io::Error::other)?; .map_err(io::Error::other)?;
} }
let (region, new_mapping) = self let new_mapping = self
.ivshmem_ops .ivshmem_ops
.lock() .lock()
.unwrap() .unwrap()
.map_ram_region( .create_userspace_mapping(new_base, region)
new_base,
self.region_size as usize,
self.backend_file.clone(),
)
.map_err(io::Error::other)?; .map_err(io::Error::other)?;
self.set_region(region, new_mapping); self.userspace_mapping = Some(new_mapping);
} }
for bar in self.bar_regions.iter_mut() { for bar in self.bar_regions.iter_mut() {
if bar.addr() == old_base { if bar.addr() == old_base {

View File

@@ -4676,7 +4676,6 @@ impl DeviceManager {
devices::IvshmemDevice::new( devices::IvshmemDevice::new(
id.clone(), id.clone(),
ivshmem_cfg.size as u64, ivshmem_cfg.size as u64,
Some(ivshmem_cfg.path.clone()),
ivshmem_ops.clone(), ivshmem_ops.clone(),
snapshot, snapshot,
) )
@@ -5601,6 +5600,16 @@ impl IvshmemOps for IvshmemHandler {
false, false,
) )
.map_err(|e| IvshmemError::CreateUserMemoryRegion(e.into()))?; .map_err(|e| IvshmemError::CreateUserMemoryRegion(e.into()))?;
let region = Arc::new(region);
let mapping = self.create_userspace_mapping(start_addr, region.clone())?;
Ok((region, mapping))
}
fn create_userspace_mapping(
&mut self,
start_addr: u64,
region: Arc<MmapRegion<AtomicBitmap>>,
) -> Result<UserspaceMapping, IvshmemError> {
let mem_slot = { let mem_slot = {
let mut manager = self.memory_manager.lock().unwrap(); let mut manager = self.memory_manager.lock().unwrap();
// SAFETY: guaranteed by MmapRegion invariants // SAFETY: guaranteed by MmapRegion invariants
@@ -5616,14 +5625,12 @@ impl IvshmemOps for IvshmemHandler {
} }
} }
.map_err(|e| IvshmemError::CreateUserspaceMapping(e.into()))?; .map_err(|e| IvshmemError::CreateUserspaceMapping(e.into()))?;
let region = Arc::new(region); Ok(UserspaceMapping {
let mapping = UserspaceMapping { mapping: region,
mapping: region.clone(),
mem_slot, mem_slot,
addr: GuestAddress(start_addr), addr: GuestAddress(start_addr),
mergeable: false, mergeable: false,
}; })
Ok((region, mapping))
} }
fn unmap_ram_region(&mut self, mapping: UserspaceMapping) -> Result<(), IvshmemError> { fn unmap_ram_region(&mut self, mapping: UserspaceMapping) -> Result<(), IvshmemError> {