petri/vm/openvmm/
hugetlb.rs1use anyhow::Context;
7
8pub const HUGETLB_2MB_PAGE_SIZE: u64 = 2 * 1024 * 1024;
10
11fn require_2mb_hugetlb() -> bool {
12 std::env::var_os(petri_artifacts_vmm_test::env::OPENVMM_REQUIRE_2MB_HUGETLB).is_some()
13}
14
15fn read_hugetlb_counter(name: &str) -> anyhow::Result<Option<u64>> {
16 let path = format!("/sys/kernel/mm/hugepages/hugepages-2048kB/{name}");
17 let value = match std::fs::read_to_string(&path) {
18 Ok(value) => value,
19 Err(error) if error.kind() == std::io::ErrorKind::NotFound => return Ok(None),
20 Err(error) => return Err(error).with_context(|| format!("failed to read {path}")),
21 };
22 Ok(Some(
23 value
24 .trim()
25 .parse()
26 .with_context(|| format!("failed to parse {path}"))?,
27 ))
28}
29
30fn available_2mb_hugetlb_pages() -> anyhow::Result<Option<u64>> {
31 let Some(free_pages) = read_hugetlb_counter("free_hugepages")? else {
32 return Ok(None);
33 };
34 let Some(overcommit_pages) = read_hugetlb_counter("nr_overcommit_hugepages")? else {
35 return Ok(None);
36 };
37 let Some(surplus_pages) = read_hugetlb_counter("surplus_hugepages")? else {
38 return Ok(None);
39 };
40
41 Ok(Some(
42 free_pages + overcommit_pages.saturating_sub(surplus_pages),
43 ))
44}
45
46pub fn ensure_2mb_hugetlb_pages(required_pages: u64) -> anyhow::Result<bool> {
53 let message = match available_2mb_hugetlb_pages()? {
54 Some(available_pages) if available_pages >= required_pages => return Ok(true),
55 Some(available_pages) => {
56 format!(
57 "host has {available_pages} available 2 MiB hugetlb pages, but {required_pages} are required; configure /sys/kernel/mm/hugepages/hugepages-2048kB/nr_overcommit_hugepages before running this test"
58 )
59 }
60 None => "host does not have 2 MiB hugetlb support configured".into(),
61 };
62
63 if require_2mb_hugetlb() {
64 anyhow::bail!(message);
65 }
66 tracing::warn!(message);
67 Ok(false)
68}