Skip to content

Commit 9fc6e44

Browse files
committed
Introduce hugepage support
Init hugepages on the host and enhance vm-service api to support enabling hugepage on the VM as well. Signed-off-by: Guvenc Gulce <[email protected]>
1 parent c9fb88e commit 9fc6e44

File tree

8 files changed

+100
-10
lines changed

8 files changed

+100
-10
lines changed

cli/src/vm_commands.rs

Lines changed: 21 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -51,6 +51,9 @@ pub enum VmCommand {
5151
help = "PCI device BDF to passthrough for networking (e.g., 0000:03:00.0)"
5252
)]
5353
pci_device: Vec<String>,
54+
55+
#[arg(long)]
56+
hugepages: bool,
5457
},
5558
Start {
5659
#[arg(required = true)]
@@ -115,7 +118,19 @@ pub async fn handle_vm_command(args: VmArgs) -> Result<()> {
115118
memory,
116119
vm_id,
117120
pci_device,
118-
} => create_vm(&mut client, image_ref, vcpus, memory, vm_id, pci_device).await?,
121+
hugepages,
122+
} => {
123+
create_vm(
124+
&mut client,
125+
image_ref,
126+
vcpus,
127+
memory,
128+
vm_id,
129+
pci_device,
130+
hugepages,
131+
)
132+
.await?
133+
}
119134
VmCommand::Start { vm_id } => start_vm(&mut client, vm_id).await?,
120135
VmCommand::Info { vm_id } => get_vm_info(&mut client, vm_id).await?,
121136
VmCommand::List => list_vms(&mut client).await?,
@@ -142,6 +157,7 @@ async fn create_vm(
142157
memory: u64,
143158
vm_id: Option<String>,
144159
pci_devices: Vec<String>,
160+
hugepages: bool,
145161
) -> Result<()> {
146162
println!("Requesting VM creation with image: {image_ref}...");
147163

@@ -162,7 +178,10 @@ async fn create_vm(
162178
boot_vcpus: vcpus,
163179
max_vcpus: vcpus,
164180
}),
165-
memory: Some(MemoryConfig { size_mib: memory }),
181+
memory: Some(MemoryConfig {
182+
size_mib: memory,
183+
hugepages,
184+
}),
166185
image_ref,
167186
net: net_configs,
168187
..Default::default()

feos/services/vm-service/src/dispatcher.rs

Lines changed: 2 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -193,8 +193,7 @@ impl VmServiceDispatcher {
193193
Ok(true) => {
194194
if let Err(e) = self.status_channel_tx.send(event_to_forward) {
195195
debug!(
196-
"VM_DISPATCHER: Failed to forward successful VM status event for {}: {e}",
197-
vm_id
196+
"VM_DISPATCHER: Failed to forward successful VM status event for {vm_id}: {e}"
198197
);
199198
}
200199
}
@@ -211,10 +210,7 @@ impl VmServiceDispatcher {
211210
}
212211
}
213212
Err(e) => {
214-
error!(
215-
"DB_UPDATE: Failed to decode VmStateChangedEvent for VM {}: {e}",
216-
vm_id
217-
);
213+
error!("DB_UPDATE: Failed to decode VmStateChangedEvent for VM {vm_id}: {e}");
218214
}
219215
}
220216
}

feos/services/vm-service/src/vmm/ch_adapter.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -120,6 +120,7 @@ impl CloudHypervisorAdapter {
120120
ch_vm_config.memory = Some(models::MemoryConfig {
121121
size: mem.size_mib as i64 * 1024 * 1024,
122122
shared: Some(true),
123+
hugepages: Some(mem.hugepages),
123124
..Default::default()
124125
});
125126
}

feos/src/lib.rs

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ use feos_proto::{
66
};
77
use feos_utils::filesystem::mount_virtual_filesystems;
88
use feos_utils::host::info::is_running_on_vm;
9+
use feos_utils::host::memory::configure_hugepages;
910
use feos_utils::network::{configure_network_devices, configure_sriov};
1011
use host_service::{
1112
api::HostApiHandler, dispatcher::HostServiceDispatcher, Command as HostCommand, RestartSignal,
@@ -32,6 +33,7 @@ use vm_service::{
3233
};
3334

3435
const VFS_NUM: u32 = 125;
36+
const HUGEPAGES_NUM: u32 = 1024;
3537

3638
pub async fn run_server(restarted_after_upgrade: bool) -> Result<()> {
3739
println!(
@@ -63,6 +65,11 @@ pub async fn run_server(restarted_after_upgrade: bool) -> Result<()> {
6365
info!("MAIN: Mounting virtual filesystems...");
6466
mount_virtual_filesystems();
6567

68+
info!("MAIN: Configuring hugepages...");
69+
if let Err(e) = configure_hugepages(HUGEPAGES_NUM).await {
70+
warn!("Failed to configure hugepages: {e}");
71+
}
72+
6673
let is_on_vm = is_running_on_vm().await.unwrap_or_else(|e| {
6774
error!("Error checking VM status: {e}");
6875
false // Default to false in case of error

feos/tests/integration_tests.rs

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -229,7 +229,10 @@ async fn test_create_and_start_vm() -> Result<()> {
229229
boot_vcpus: 2,
230230
max_vcpus: 2,
231231
}),
232-
memory: Some(MemoryConfig { size_mib: 2048 }),
232+
memory: Some(MemoryConfig {
233+
size_mib: 2048,
234+
hugepages: false,
235+
}),
233236
image_ref,
234237
disks: vec![],
235238
net: vec![],
@@ -332,7 +335,10 @@ async fn test_vm_healthcheck_and_crash_recovery() -> Result<()> {
332335
boot_vcpus: 1,
333336
max_vcpus: 1,
334337
}),
335-
memory: Some(MemoryConfig { size_mib: 1024 }),
338+
memory: Some(MemoryConfig {
339+
size_mib: 1024,
340+
hugepages: false,
341+
}),
336342
image_ref,
337343
disks: vec![],
338344
net: vec![],

feos/utils/src/host/memory.rs

Lines changed: 59 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,59 @@
1+
use log::{info, warn};
2+
use nix::mount::{mount, MsFlags};
3+
use std::io;
4+
use tokio::fs;
5+
6+
const HUGEPAGE_FS_TYPE: &[u8] = b"hugetlbfs";
7+
const HUGEPAGE_MOUNT_POINT: &str = "/dev/hugepages";
8+
9+
pub async fn configure_hugepages(num_pages: u32) -> io::Result<()> {
10+
let nr_hugepages_path = "/sys/kernel/mm/hugepages/hugepages-2048kB/nr_hugepages";
11+
12+
info!("Attempting to allocate {num_pages} hugepages...");
13+
fs::write(nr_hugepages_path, num_pages.to_string()).await?;
14+
info!("Successfully wrote to {nr_hugepages_path}");
15+
16+
let allocated_pages_str = fs::read_to_string(nr_hugepages_path).await?;
17+
let allocated_pages = allocated_pages_str.trim().parse::<u32>().unwrap_or(0);
18+
19+
if allocated_pages < num_pages {
20+
warn!(
21+
"System only allocated {allocated_pages} of the requested {num_pages} hugepages. This might happen due to memory fragmentation."
22+
);
23+
} else {
24+
info!("System successfully allocated {allocated_pages} hugepages.");
25+
}
26+
27+
if !is_mounted(HUGEPAGE_MOUNT_POINT).await {
28+
info!("Mounting hugetlbfs at {HUGEPAGE_MOUNT_POINT}...");
29+
fs::create_dir_all(HUGEPAGE_MOUNT_POINT).await?;
30+
mount_hugetlbfs()?;
31+
info!("Successfully mounted hugetlbfs.");
32+
} else {
33+
info!("hugetlbfs is already mounted at {HUGEPAGE_MOUNT_POINT}.");
34+
}
35+
36+
Ok(())
37+
}
38+
39+
fn mount_hugetlbfs() -> Result<(), io::Error> {
40+
const NONE: Option<&'static [u8]> = None;
41+
mount(
42+
Some(b"none".as_ref()),
43+
HUGEPAGE_MOUNT_POINT,
44+
Some(HUGEPAGE_FS_TYPE),
45+
MsFlags::empty(),
46+
NONE,
47+
)
48+
.map_err(|e| io::Error::other(format!("Failed to mount hugetlbfs: {e}")))
49+
}
50+
51+
async fn is_mounted(path: &str) -> bool {
52+
let Ok(mounts) = fs::read_to_string("/proc/mounts").await else {
53+
return false;
54+
};
55+
mounts.lines().any(|line| {
56+
let parts: Vec<&str> = line.split_whitespace().collect();
57+
parts.get(1) == Some(&path)
58+
})
59+
}

feos/utils/src/host/mod.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,2 +1,3 @@
11
pub mod info;
2+
pub mod memory;
23
pub mod power;

proto/v1/vm.proto

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -135,6 +135,7 @@ message CpuConfig {
135135

136136
message MemoryConfig {
137137
uint64 size_mib = 1; // Memory size in Megabytes (MiB).
138+
bool hugepages = 2;
138139
}
139140

140141
message DiskConfig {

0 commit comments

Comments
 (0)