Skip to content

Commit 1e2faa8

Browse files
Copilotsimongdavies
andcommitted
Implement reuse of hypervisor file handles
Co-authored-by: simongdavies <1397489+simongdavies@users.noreply.github.com>
1 parent 008043d commit 1e2faa8

File tree

2 files changed

+56
-26
lines changed

2 files changed

+56
-26
lines changed

src/hyperlight_host/src/hypervisor/hyperv_linux.rs

Lines changed: 22 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@ extern crate mshv_bindings3 as mshv_bindings;
2525
extern crate mshv_ioctls3 as mshv_ioctls;
2626

2727
use std::fmt::{Debug, Formatter};
28+
use std::sync::OnceLock;
2829

2930
use log::{error, LevelFilter};
3031
#[cfg(mshv2)]
@@ -271,17 +272,26 @@ mod debug {
271272
}
272273
}
273274

275+
/// Static global MSHV handle to avoid reopening /dev/mshv for every sandbox
276+
static MSHV_HANDLE: OnceLock<Option<Mshv>> = OnceLock::new();
277+
278+
/// Get the global MSHV handle, initializing it if needed
279+
#[instrument(skip_all, parent = Span::current(), level = "Trace")]
280+
pub(crate) fn get_mshv_handle() -> &'static Option<Mshv> {
281+
MSHV_HANDLE.get_or_init(|| match Mshv::new() {
282+
Ok(mshv) => Some(mshv),
283+
Err(e) => {
284+
log::info!("MSHV is not available on this system: {}", e);
285+
None
286+
}
287+
})
288+
}
289+
274290
/// Determine whether the HyperV for Linux hypervisor API is present
275291
/// and functional.
276292
#[instrument(skip_all, parent = Span::current(), level = "Trace")]
277293
pub(crate) fn is_hypervisor_present() -> bool {
278-
match Mshv::new() {
279-
Ok(_) => true,
280-
Err(_) => {
281-
log::info!("MSHV is not available on this system");
282-
false
283-
}
284-
}
294+
get_mshv_handle().is_some()
285295
}
286296

287297
/// A Hypervisor driver for HyperV-on-Linux. This hypervisor is often
@@ -317,7 +327,11 @@ impl HypervLinuxDriver {
317327
pml4_ptr: GuestPtr,
318328
#[cfg(gdb)] gdb_conn: Option<DebugCommChannel<DebugResponse, DebugMsg>>,
319329
) -> Result<Self> {
320-
let mshv = Mshv::new()?;
330+
let mshv = match get_mshv_handle() {
331+
Some(mshv) => mshv.clone(),
332+
None => return Err(new_error!("MSHV is not available on this system")),
333+
};
334+
321335
let pr = Default::default();
322336
#[cfg(mshv2)]
323337
let vm_fd = mshv.create_vm_with_config(&pr)?;

src/hyperlight_host/src/hypervisor/kvm.rs

Lines changed: 34 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ limitations under the License.
1616

1717
use std::convert::TryFrom;
1818
use std::fmt::Debug;
19+
use std::sync::OnceLock;
1920
#[cfg(gdb)]
2021
use std::sync::{Arc, Mutex};
2122

@@ -42,26 +43,38 @@ use crate::mem::ptr::{GuestPtr, RawPtr};
4243
use crate::HyperlightError;
4344
use crate::{log_then_return, new_error, Result};
4445

45-
/// Return `true` if the KVM API is available, version 12, and has UserMemory capability, or `false` otherwise
46+
/// Static global KVM handle to avoid reopening /dev/kvm for every sandbox
47+
static KVM_HANDLE: OnceLock<Option<Kvm>> = OnceLock::new();
48+
49+
/// Get the global KVM handle, initializing it if needed
4650
#[instrument(skip_all, parent = Span::current(), level = "Trace")]
47-
pub(crate) fn is_hypervisor_present() -> bool {
48-
if let Ok(kvm) = Kvm::new() {
49-
let api_version = kvm.get_api_version();
50-
match api_version {
51-
version if version == 12 && kvm.check_extension(UserMemory) => true,
52-
12 => {
53-
log::info!("KVM does not have KVM_CAP_USER_MEMORY capability");
54-
false
55-
}
56-
version => {
57-
log::info!("KVM GET_API_VERSION returned {}, expected 12", version);
58-
false
51+
pub(crate) fn get_kvm_handle() -> &'static Option<Kvm> {
52+
KVM_HANDLE.get_or_init(|| match Kvm::new() {
53+
Ok(kvm) => {
54+
let api_version = kvm.get_api_version();
55+
match api_version {
56+
version if version == 12 && kvm.check_extension(UserMemory) => Some(kvm),
57+
12 => {
58+
log::info!("KVM does not have KVM_CAP_USER_MEMORY capability");
59+
None
60+
}
61+
version => {
62+
log::info!("KVM GET_API_VERSION returned {}, expected 12", version);
63+
None
64+
}
5965
}
6066
}
61-
} else {
62-
log::info!("KVM is not available on this system");
63-
false
64-
}
67+
Err(e) => {
68+
log::info!("KVM is not available on this system: {}", e);
69+
None
70+
}
71+
})
72+
}
73+
74+
/// Return `true` if the KVM API is available, version 12, and has UserMemory capability, or `false` otherwise
75+
#[instrument(skip_all, parent = Span::current(), level = "Trace")]
76+
pub(crate) fn is_hypervisor_present() -> bool {
77+
get_kvm_handle().is_some()
6578
}
6679

6780
#[cfg(gdb)]
@@ -300,7 +313,10 @@ impl KVMDriver {
300313
rsp: u64,
301314
#[cfg(gdb)] gdb_conn: Option<DebugCommChannel<DebugResponse, DebugMsg>>,
302315
) -> Result<Self> {
303-
let kvm = Kvm::new()?;
316+
let kvm = match get_kvm_handle() {
317+
Some(kvm) => kvm.clone(),
318+
None => return Err(new_error!("KVM is not available on this system")),
319+
};
304320

305321
let vm_fd = kvm.create_vm_with_type(0)?;
306322

0 commit comments

Comments
 (0)