mirror of
https://chromium.googlesource.com/crosvm/crosvm
synced 2025-02-06 02:25:23 +00:00
devices:vfio: Remove vfio group when vfio device is closed
One container could contains multi groups, one group could contains multi devices, when all the devices in the group are closed, the group itself should be removed also. BUG=b:185084350 TEST=Boot a guest with and without passthrough device Change-Id: Ia43da3e2e9ad58d0a7596141645926931c0bcc5b Reviewed-on: https://chromium-review.googlesource.com/c/chromiumos/platform/crosvm/+/2955572 Tested-by: kokoro <noreply+kokoro@google.com> Commit-Queue: Daniel Verkamp <dverkamp@chromium.org> Reviewed-by: Daniel Verkamp <dverkamp@chromium.org>
This commit is contained in:
parent
3897cd0a2c
commit
5865a65180
1 changed files with 71 additions and 8 deletions
|
@ -88,7 +88,7 @@ static KVM_VFIO_FILE: OnceCell<SafeDescriptor> = OnceCell::new();
|
||||||
/// VfioContainer contain multi VfioGroup, and delegate an IOMMU domain table
|
/// VfioContainer contain multi VfioGroup, and delegate an IOMMU domain table
|
||||||
pub struct VfioContainer {
|
pub struct VfioContainer {
|
||||||
container: File,
|
container: File,
|
||||||
groups: HashMap<u32, Arc<VfioGroup>>,
|
groups: HashMap<u32, Arc<Mutex<VfioGroup>>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
const VFIO_API_VERSION: u8 = 0;
|
const VFIO_API_VERSION: u8 = 0;
|
||||||
|
@ -219,11 +219,16 @@ impl VfioContainer {
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn get_group(&mut self, id: u32, vm: &impl Vm, iommu_enabled: bool) -> Result<Arc<VfioGroup>> {
|
fn get_group(
|
||||||
|
&mut self,
|
||||||
|
id: u32,
|
||||||
|
vm: &impl Vm,
|
||||||
|
iommu_enabled: bool,
|
||||||
|
) -> Result<Arc<Mutex<VfioGroup>>> {
|
||||||
match self.groups.get(&id) {
|
match self.groups.get(&id) {
|
||||||
Some(group) => Ok(group.clone()),
|
Some(group) => Ok(group.clone()),
|
||||||
None => {
|
None => {
|
||||||
let group = Arc::new(VfioGroup::new(self, id)?);
|
let group = Arc::new(Mutex::new(VfioGroup::new(self, id)?));
|
||||||
|
|
||||||
if self.groups.is_empty() {
|
if self.groups.is_empty() {
|
||||||
// Before the first group is added into container, do once cotainer
|
// Before the first group is added into container, do once cotainer
|
||||||
|
@ -234,7 +239,7 @@ impl VfioContainer {
|
||||||
let kvm_vfio_file = KVM_VFIO_FILE
|
let kvm_vfio_file = KVM_VFIO_FILE
|
||||||
.get_or_try_init(|| vm.create_device(DeviceKind::Vfio))
|
.get_or_try_init(|| vm.create_device(DeviceKind::Vfio))
|
||||||
.map_err(VfioError::CreateVfioKvmDevice)?;
|
.map_err(VfioError::CreateVfioKvmDevice)?;
|
||||||
group.kvm_device_add_group(kvm_vfio_file)?;
|
group.lock().kvm_device_add_group(kvm_vfio_file)?;
|
||||||
|
|
||||||
self.groups.insert(id, group.clone());
|
self.groups.insert(id, group.clone());
|
||||||
|
|
||||||
|
@ -242,6 +247,26 @@ impl VfioContainer {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn remove_group(&mut self, id: u32, reduce: bool) {
|
||||||
|
let remove = match self.groups.get(&id) {
|
||||||
|
Some(group) => {
|
||||||
|
if reduce {
|
||||||
|
group.lock().reduce_device_num();
|
||||||
|
}
|
||||||
|
if group.lock().device_num() == 0 {
|
||||||
|
true
|
||||||
|
} else {
|
||||||
|
false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
None => false,
|
||||||
|
};
|
||||||
|
|
||||||
|
if remove {
|
||||||
|
self.groups.remove(&id);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl AsRawDescriptor for VfioContainer {
|
impl AsRawDescriptor for VfioContainer {
|
||||||
|
@ -252,6 +277,7 @@ impl AsRawDescriptor for VfioContainer {
|
||||||
|
|
||||||
struct VfioGroup {
|
struct VfioGroup {
|
||||||
group: File,
|
group: File,
|
||||||
|
device_num: u32,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl VfioGroup {
|
impl VfioGroup {
|
||||||
|
@ -295,7 +321,10 @@ impl VfioGroup {
|
||||||
return Err(VfioError::GroupSetContainer(get_error()));
|
return Err(VfioError::GroupSetContainer(get_error()));
|
||||||
}
|
}
|
||||||
|
|
||||||
Ok(VfioGroup { group: group_file })
|
Ok(VfioGroup {
|
||||||
|
group: group_file,
|
||||||
|
device_num: 0,
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
fn get_group_id(sysfspath: &Path) -> Result<u32> {
|
fn get_group_id(sysfspath: &Path) -> Result<u32> {
|
||||||
|
@ -350,6 +379,18 @@ impl VfioGroup {
|
||||||
// Safe as ret is valid FD
|
// Safe as ret is valid FD
|
||||||
Ok(unsafe { File::from_raw_descriptor(ret) })
|
Ok(unsafe { File::from_raw_descriptor(ret) })
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn add_device_num(&mut self) {
|
||||||
|
self.device_num += 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
fn reduce_device_num(&mut self) {
|
||||||
|
self.device_num -= 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
fn device_num(&self) -> u32 {
|
||||||
|
self.device_num
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl AsRawDescriptor for VfioGroup {
|
impl AsRawDescriptor for VfioGroup {
|
||||||
|
@ -469,6 +510,7 @@ pub struct VfioDevice {
|
||||||
name: String,
|
name: String,
|
||||||
container: Arc<Mutex<VfioContainer>>,
|
container: Arc<Mutex<VfioContainer>>,
|
||||||
group_descriptor: RawDescriptor,
|
group_descriptor: RawDescriptor,
|
||||||
|
group_id: u32,
|
||||||
// vec for vfio device's regions
|
// vec for vfio device's regions
|
||||||
regions: Vec<VfioRegion>,
|
regions: Vec<VfioRegion>,
|
||||||
}
|
}
|
||||||
|
@ -488,14 +530,30 @@ impl VfioDevice {
|
||||||
let name_osstr = sysfspath.file_name().ok_or(VfioError::InvalidPath)?;
|
let name_osstr = sysfspath.file_name().ok_or(VfioError::InvalidPath)?;
|
||||||
let name_str = name_osstr.to_str().ok_or(VfioError::InvalidPath)?;
|
let name_str = name_osstr.to_str().ok_or(VfioError::InvalidPath)?;
|
||||||
let name = String::from(name_str);
|
let name = String::from(name_str);
|
||||||
let dev = group.get_device(&name)?;
|
|
||||||
let regions = Self::get_regions(&dev)?;
|
let dev = match group.lock().get_device(&name) {
|
||||||
|
Ok(dev) => dev,
|
||||||
|
Err(e) => {
|
||||||
|
container.lock().remove_group(group_id, false);
|
||||||
|
return Err(e);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
let regions = match Self::get_regions(&dev) {
|
||||||
|
Ok(regions) => regions,
|
||||||
|
Err(e) => {
|
||||||
|
container.lock().remove_group(group_id, false);
|
||||||
|
return Err(e);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
group.lock().add_device_num();
|
||||||
|
let group_descriptor = group.lock().as_raw_descriptor();
|
||||||
|
|
||||||
Ok(VfioDevice {
|
Ok(VfioDevice {
|
||||||
dev,
|
dev,
|
||||||
name,
|
name,
|
||||||
container,
|
container,
|
||||||
group_descriptor: group.as_raw_descriptor(),
|
group_descriptor,
|
||||||
|
group_id,
|
||||||
regions,
|
regions,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
@ -1007,6 +1065,11 @@ impl VfioDevice {
|
||||||
pub fn device_file(&self) -> &File {
|
pub fn device_file(&self) -> &File {
|
||||||
&self.dev
|
&self.dev
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// close vfio device
|
||||||
|
pub fn close(&self) {
|
||||||
|
self.container.lock().remove_group(self.group_id, true);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct VfioPciConfig {
|
pub struct VfioPciConfig {
|
||||||
|
|
Loading…
Reference in a new issue