Skip to content

Commit c0287ca

Browse files
committed
test: Add snapshot restore test for hugetlbfs backed guest
The test has to be UFFD based, as we cannot mmap the file with hugetlbfs enabled (as `MAP_HUGETLB` is a modifier to `MAP_ANONYMOUS`, which precludes file mappings). Signed-off-by: Patrick Roy <roypat@amazon.co.uk>
1 parent 68c2660 commit c0287ca

File tree

3 files changed

+73
-6
lines changed

3 files changed

+73
-6
lines changed
Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
// Copyright 2022 Amazon.com, Inc. or its affiliates. All Rights Reserved.
2+
// SPDX-License-Identifier: Apache-2.0
3+
4+
//! Provides functionality for a userspace page fault handler
5+
//! which loads the whole region from the backing memory file
6+
//! when a page fault occurs. Unlike valid_handler_4k, this handler faults in
7+
//! huge pages, e.g. faults at 2M granularity (this is different than simply
8+
//! pre-faulting 2M areas, as we need to align the faults to 2M boundaries to
9+
//! support huge pages).
10+
11+
mod uffd_utils;
12+
13+
fn main() {
14+
uffd_utils::handle_faults(1024 * 1024 * 2) // 2MB
15+
}

tests/conftest.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -229,7 +229,7 @@ def uffd_handler_paths():
229229
"""Build UFFD handler binaries."""
230230
handlers = {
231231
f"{handler}_handler": build_tools.get_example(f"uffd_{handler}_handler")
232-
for handler in ["malicious", "valid_4k"]
232+
for handler in ["malicious", "valid_4k", "valid_2m"]
233233
}
234234
yield handlers
235235

tests/integration_tests/performance/test_huge_pages.py

Lines changed: 57 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -6,12 +6,17 @@
66
from framework import utils
77
from framework.microvm import HugePagesConfig
88
from framework.properties import global_props
9+
from integration_tests.functional.test_uffd import SOCKET_PATH, spawn_pf_handler
910

1011

11-
def check_hugetlbfs_in_use(pid):
12-
"""Asserts that the process with the given pid is using hugetlbfs pages somewhere"""
12+
def check_hugetlbfs_in_use(pid: int, allocation_name: str):
13+
"""Asserts that the process with the given `pid` is using hugetlbfs pages somewhere.
1314
14-
# Format of a smaps entry:
15+
`allocation_name` should be the name of the smaps entry for which we want to verify that huge pages are used.
16+
For memfd-backed guest memory, this would be "memfd:guest_mem", for anonymous memory this would be "/anon_hugepage"
17+
"""
18+
19+
# Format of a sample smaps entry:
1520
# 7fc2bc400000-7fc2cc400000 rw-s 00000000 00:10 25488401 /memfd:guest_mem (deleted)
1621
# Size: 262144 kB
1722
# KernelPageSize: 2048 kB
@@ -37,7 +42,7 @@ def check_hugetlbfs_in_use(pid):
3742
# THPeligible: 0
3843
# ProtectionKey: 0
3944
# the "memfd:guest_mem" is the identifier of our guest memory. It is memfd backed, with the memfd being called "guest_mem" in memory.rs
40-
cmd = f"cat /proc/{pid}/smaps | grep memfd:guest_mem -A 23 | grep KernelPageSize"
45+
cmd = f"cat /proc/{pid}/smaps | grep {allocation_name} -A 23 | grep KernelPageSize"
4146
_, stdout, _ = utils.run_cmd(cmd)
4247

4348
kernel_page_size_kib = int(stdout.split()[1])
@@ -59,4 +64,51 @@ def test_hugetlbfs_boot(uvm_plain):
5964
rc, _, _ = uvm_plain.ssh.run("true")
6065
assert not rc
6166

62-
check_hugetlbfs_in_use(uvm_plain.firecracker_pid)
67+
check_hugetlbfs_in_use(uvm_plain.firecracker_pid, "memfd:guest_mem")
68+
69+
70+
@pytest.mark.skipif(
71+
global_props.host_linux_version == "4.14",
72+
reason="MFD_HUGETLB | MFD_ALLOW_SEALING only supported on kernels >= 4.16",
73+
)
74+
def test_hugetlbfs_snapshot(
75+
microvm_factory, guest_kernel_linux_5_10, rootfs_ubuntu_22, uffd_handler_paths
76+
):
77+
"""
78+
Test hugetlbfs snapshot restore via uffd
79+
"""
80+
81+
### Create Snapshot ###
82+
vm = microvm_factory.build(guest_kernel_linux_5_10, rootfs_ubuntu_22)
83+
vm.memory_monitor = None
84+
vm.spawn()
85+
vm.basic_config(huge_pages=HugePagesConfig.HUGETLBFS_2MB, mem_size_mib=128)
86+
vm.add_net_iface()
87+
vm.start()
88+
89+
# Wait for microvm to boot
90+
rc, _, _ = vm.ssh.run("true")
91+
assert not rc
92+
93+
check_hugetlbfs_in_use(vm.firecracker_pid, "memfd:guest_mem")
94+
95+
snapshot = vm.snapshot_full()
96+
97+
vm.kill()
98+
99+
### Restore Snapshot ###
100+
vm = microvm_factory.build()
101+
vm.spawn()
102+
103+
# Spawn page fault handler process.
104+
_pf_handler = spawn_pf_handler(
105+
vm, uffd_handler_paths["valid_2m_handler"], snapshot.mem
106+
)
107+
108+
vm.restore_from_snapshot(snapshot, resume=True, uffd_path=SOCKET_PATH)
109+
110+
# Verify if guest can run commands.
111+
rc, _, _ = vm.ssh.run("true")
112+
assert not rc
113+
114+
check_hugetlbfs_in_use(vm.firecracker_pid, "/anon_hugepage")

0 commit comments

Comments
 (0)