Assign a GPU to a sandbox. Returns the assignment details including BDF.
(&mut self, sandbox_id: &str, gpu_device: &str)
| 65 | |
| 66 | /// Assign a GPU to a sandbox. Returns the assignment details including BDF. |
| 67 | pub fn assign(&mut self, sandbox_id: &str, gpu_device: &str) -> Result<GpuAssignment, String> { |
| 68 | let slot_idx = if gpu_device.is_empty() { |
| 69 | self.slots |
| 70 | .iter() |
| 71 | .position(|s| s.assigned_to.is_none()) |
| 72 | .ok_or_else(|| "all GPUs are currently assigned to other sandboxes".to_string())? |
| 73 | } else if let Ok(idx) = gpu_device.parse::<usize>() { |
| 74 | if idx >= self.slots.len() { |
| 75 | return Err(format!( |
| 76 | "GPU index {idx} out of range (have {} GPUs)", |
| 77 | self.slots.len() |
| 78 | )); |
| 79 | } |
| 80 | if self.slots[idx].assigned_to.is_some() { |
| 81 | return Err(format!( |
| 82 | "GPU at index {idx} ({}) is already assigned to another sandbox", |
| 83 | self.slots[idx].info.bdf |
| 84 | )); |
| 85 | } |
| 86 | idx |
| 87 | } else { |
| 88 | validate_bdf(gpu_device).map_err(|e| e.to_string())?; |
| 89 | let idx = self |
| 90 | .slots |
| 91 | .iter() |
| 92 | .position(|s| s.info.bdf == gpu_device) |
| 93 | .ok_or_else(|| format!("GPU {gpu_device} not found in inventory"))?; |
| 94 | if self.slots[idx].assigned_to.is_some() { |
| 95 | return Err(format!( |
| 96 | "GPU {gpu_device} is already assigned to another sandbox" |
| 97 | )); |
| 98 | } |
| 99 | idx |
| 100 | }; |
| 101 | |
| 102 | let bdf = self.slots[slot_idx].info.bdf.clone(); |
| 103 | let guard = prepare_gpu_for_passthrough(&self.sysfs, &bdf) |
| 104 | .map_err(|e| format!("failed to prepare GPU {bdf} for passthrough: {e}"))?; |
| 105 | |
| 106 | self.slots[slot_idx].assigned_to = Some(sandbox_id.to_string()); |
| 107 | self.slots[slot_idx].bind_guard = Some(guard); |
| 108 | self.persist_state(); |
| 109 | |
| 110 | Ok(GpuAssignment { |
| 111 | bdf, |
| 112 | name: self.slots[slot_idx].info.name.clone(), |
| 113 | iommu_group: self.slots[slot_idx].info.iommu_group, |
| 114 | }) |
| 115 | } |
| 116 | |
| 117 | /// Release a GPU assignment. The `GpuBindGuard` is dropped, restoring the GPU. |
| 118 | pub fn release(&mut self, sandbox_id: &str) { |
no test coverage detected