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