• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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