Skip to main content

petri/vm/openvmm/
hugetlb.rs

1// Copyright (c) Microsoft Corporation.
2// Licensed under the MIT License.
3
4//! Helpers for OpenVMM hugetlb-backed memory tests.
5
6use anyhow::Context;
7
8/// Size of a 2 MiB hugetlb page.
9pub 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
46/// Returns whether the host appears to have enough 2 MiB hugetlb pages available.
47///
48/// By default, missing or insufficient host support returns `Ok(false)` after
49/// logging a clear warning so local developer runs can skip tests cleanly. If
50/// `OPENVMM_REQUIRE_2MB_HUGETLB` is set, missing or insufficient host support is
51/// an error.
52pub 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}