vm-allocator: free GSIs in GsiAllocator

The old implementation used an ever monotonically increasing u32 counter
to allocate new GSIs. The counter increased every time a new GSI was
allocated, and freeing GSIs was not possible. Thus, Cloud Hypervisor
can run out of GSIs and panics. This currently happened at the 1024th
GSI [0]. Further, this caused the `KVM_SET_GSI_ROUTING` ioctl to carry
much more payload than needed.

This new implementation uses a bitmap for proper tracking of resources
and can gracefully free GSIs - this is abstracted in type
InterruptAllocator.

Please note that this commit only replaces the old mechanism. The next
commit will introduce freeing used GSIs automatically when an
InterruptRoute is dropped.

While being on this, we also propagate the errors that the allocator may
throw where necessary.

Co-authored-by: Sebastian Eydam <sebastian.eydam@cyberus-technology.de>
On-behalf-of: SAP sebastian.eydam@sap.com
Signed-off-by: Sebastian Eydam <sebastian.eydam@cyberus-technology.de>

On-behalf-of: Philipp Schuster@sap.com
Signed-off-by: Philipp Schuster <philipp.schuster@cyberus-technology.de>
This commit is contained in:
Philipp Schuster
2026-05-07 14:21:32 +02:00
committed by Rob Bradford
parent 7c4fa04ea3
commit 1ba2b34019
6 changed files with 215 additions and 65 deletions

View File

@@ -10,9 +10,9 @@
use vm_memory::{GuestAddress, GuestUsize};
use crate::address::AddressAllocator;
use crate::gsi::GsiAllocator;
#[cfg(target_arch = "x86_64")]
use crate::gsi::GsiApic;
use crate::gsi::{GsiAllocator, InterruptAllocError};
use crate::page_size::get_page_size;
/// Manages allocating system resources such as address space and interrupt numbers.
@@ -31,17 +31,17 @@ use crate::page_size::get_page_size;
/// GuestAddress(0x10000000), 0x10000000,
/// #[cfg(target_arch = "x86_64")] &[GsiApic::new(5, 19)]).unwrap();
/// #[cfg(target_arch = "x86_64")]
/// assert_eq!(allocator.allocate_irq(), Some(5));
/// assert_eq!(allocator.allocate_irq(), Ok(5));
/// #[cfg(target_arch = "aarch64")]
/// assert_eq!(allocator.allocate_irq(), Some(32));
/// assert_eq!(allocator.allocate_irq(), Ok(32));
/// #[cfg(target_arch = "riscv64")]
/// assert_eq!(allocator.allocate_irq(), Some(0));
/// assert_eq!(allocator.allocate_irq(), Ok(0));
/// #[cfg(target_arch = "x86_64")]
/// assert_eq!(allocator.allocate_irq(), Some(6));
/// assert_eq!(allocator.allocate_irq(), Ok(6));
/// #[cfg(target_arch = "aarch64")]
/// assert_eq!(allocator.allocate_irq(), Some(33));
/// assert_eq!(allocator.allocate_irq(), Ok(33));
/// #[cfg(target_arch = "riscv64")]
/// assert_eq!(allocator.allocate_irq(), Some(1));
/// assert_eq!(allocator.allocate_irq(), Ok(1));
/// assert_eq!(allocator.allocate_platform_mmio_addresses(None, 0x1000, Some(0x1000)), Some(GuestAddress(0x1fff_f000)));
///
/// ```
@@ -82,13 +82,13 @@ impl SystemAllocator {
}
/// Reserves the next available system irq number.
pub fn allocate_irq(&mut self) -> Option<u32> {
self.gsi_allocator.allocate_irq().ok()
pub fn allocate_irq(&mut self) -> Result<u32, InterruptAllocError> {
self.gsi_allocator.allocate_irq()
}
/// Reserves the next available GSI.
pub fn allocate_gsi(&mut self) -> Option<u32> {
self.gsi_allocator.allocate_gsi().ok()
pub fn allocate_gsi(&mut self) -> Result<u32, InterruptAllocError> {
self.gsi_allocator.allocate_gsi()
}
/// Reserves a section of `size` bytes of IO address space.