1 // Copyright 2022 The ChromiumOS Authors
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4
5 use base::MemfdSeals;
6 use base::MemoryMappingUnix;
7 use base::SharedMemory;
8 use base::SharedMemoryUnix;
9 use bitflags::bitflags;
10
11 use crate::Error;
12 use crate::GuestAddress;
13 use crate::GuestMemory;
14 use crate::Result;
15
16 bitflags! {
17 pub struct MemoryPolicy: u32 {
18 const USE_HUGEPAGES = 1;
19 const LOCK_GUEST_MEMORY = (1 << 1);
20 }
21 }
22
finalize_shm(shm: &mut SharedMemory) -> Result<()>23 pub(crate) fn finalize_shm(shm: &mut SharedMemory) -> Result<()> {
24 // Seals are only a concept on Unix systems, so we must add them in conditional
25 // compilation. On Windows, SharedMemory allocation cannot be updated after creation
26 // regardless, so the same operation is done implicitly.
27 let mut seals = MemfdSeals::new();
28
29 seals.set_shrink_seal();
30 seals.set_grow_seal();
31 seals.set_seal_seal();
32
33 shm.add_seals(seals).map_err(Error::MemoryAddSealsFailed)
34 }
35
36 impl GuestMemory {
37 /// Madvise away the address range in the host that is associated with the given guest range.
38 ///
39 /// This feature is only available on Unix, where a MemoryMapping can remove a mapped range.
remove_range(&self, addr: GuestAddress, count: u64) -> Result<()>40 pub fn remove_range(&self, addr: GuestAddress, count: u64) -> Result<()> {
41 let (mapping, offset, _) = self.find_region(addr)?;
42 mapping
43 .remove_range(offset, count as usize)
44 .map_err(|e| Error::MemoryAccess(addr, e))
45 }
46
47 /// Handles guest memory policy hints/advices.
set_memory_policy(&self, mem_policy: MemoryPolicy)48 pub fn set_memory_policy(&self, mem_policy: MemoryPolicy) {
49 if mem_policy.is_empty() {
50 return;
51 }
52
53 for (_, region) in self.regions.iter().enumerate() {
54 if mem_policy.contains(MemoryPolicy::USE_HUGEPAGES) {
55 let ret = region.mapping.use_hugepages();
56
57 if let Err(err) = ret {
58 println!("Failed to enable HUGEPAGE for mapping {}", err);
59 }
60 }
61
62 if mem_policy.contains(MemoryPolicy::LOCK_GUEST_MEMORY) {
63 // This is done in coordination with remove_range() calls, which are
64 // performed by the virtio-balloon process (they must be performed by
65 // a different process from the one that issues the locks).
66 // We also prevent this from happening in single-process configurations,
67 // when we compute configuration flags.
68 let ret = region.mapping.lock_all();
69
70 if let Err(err) = ret {
71 println!("Failed to lock memory for mapping {}", err);
72 }
73 }
74 }
75 }
76
use_dontfork(&self) -> anyhow::Result<()>77 pub fn use_dontfork(&self) -> anyhow::Result<()> {
78 for region in self.regions.iter() {
79 region.mapping.use_dontfork()?;
80 }
81 Ok(())
82 }
83 }
84