byteor_transport_shm/
mapping.rs1use std::path::Path;
4
5use memmap2::{MmapMut, MmapOptions};
6
7use crate::util::{ensure_parent_dir, hugepage_size_bytes, is_hugetlbfs};
8use crate::{Error, OpenOptions};
9
10#[derive(Debug, Clone, Copy, PartialEq, Eq)]
12pub struct MappingInfo {
13 pub mapped_bytes: usize,
15 pub prefaulted: bool,
17 pub hugetlbfs_backing: bool,
19 pub backing_hugepage_bytes: Option<usize>,
21}
22
23pub(crate) struct MappedRegion {
24 pub(crate) mmap: MmapMut,
25 pub(crate) info: MappingInfo,
26}
27
28pub(crate) fn open_file_backed(
29 path: &Path,
30 bytes: usize,
31 options: &OpenOptions,
32) -> Result<MappedRegion, Error> {
33 use std::fs::OpenOptions;
34
35 ensure_parent_dir(path).map_err(|e| Error::IoAt {
36 op: "create_dir_all",
37 path: path.to_path_buf(),
38 source: e,
39 })?;
40
41 let mut opts = OpenOptions::new();
42 opts.read(true).write(true).create(true).truncate(false);
43
44 #[cfg(unix)]
45 {
46 use std::os::unix::fs::OpenOptionsExt;
47 opts.mode(0o600);
48 }
49
50 let file = opts.open(path).map_err(|e| Error::IoAt {
51 op: "open",
52 path: path.to_path_buf(),
53 source: e,
54 })?;
55
56 let meta = file.metadata().map_err(|e| Error::IoAt {
57 op: "metadata",
58 path: path.to_path_buf(),
59 source: e,
60 })?;
61 let mut len = meta.len() as usize;
62
63 let hugetlbfs_backing = is_hugetlbfs(path);
64
65 if len == 0 {
66 #[cfg(unix)]
67 {
68 use std::os::unix::fs::PermissionsExt;
69 let _ = file.set_permissions(std::fs::Permissions::from_mode(0o600));
70 }
71
72 let mut target = bytes;
73 if hugetlbfs_backing {
74 let hp = hugepage_size_bytes();
75 if hp > 0 {
76 target = target.div_ceil(hp).saturating_mul(hp);
77 }
78 }
79
80 file.set_len(target as u64).map_err(|e| Error::IoAt {
81 op: "set_len",
82 path: path.to_path_buf(),
83 source: e,
84 })?;
85 len = target;
86 }
87
88 if len < bytes {
89 return Err(Error::RegionTooSmall {
90 needed: bytes,
91 found: len,
92 });
93 }
94
95 let mmap = unsafe {
97 MmapOptions::new()
98 .len(len)
99 .map_mut(&file)
100 .map_err(|e| Error::IoAt {
101 op: "mmap",
102 path: path.to_path_buf(),
103 source: e,
104 })?
105 };
106
107 if options.prefault {
108 prefault_mapping(&mmap);
109 }
110
111 let info = mapping_info_for_path(len, options.prefault, hugetlbfs_backing);
112
113 Ok(MappedRegion { mmap, info })
114}
115
116pub(crate) fn mapping_info_for_path(
117 mapped_bytes: usize,
118 prefaulted: bool,
119 hugetlbfs_backing: bool,
120) -> MappingInfo {
121 MappingInfo {
122 mapped_bytes,
123 prefaulted,
124 hugetlbfs_backing,
125 backing_hugepage_bytes: hugetlbfs_backing.then(hugepage_size_bytes),
126 }
127}
128
129fn prefault_mapping(mmap: &MmapMut) {
130 let len = mmap.len();
131 if len == 0 {
132 return;
133 }
134
135 let page_size = page_size_bytes();
136 let base = mmap.as_ptr();
137 let mut touched = 0u8;
138
139 let mut offset = 0usize;
140 while offset < len {
141 touched ^= unsafe { std::ptr::read_volatile(base.add(offset)) };
142 offset = offset.saturating_add(page_size);
143 }
144
145 let last = len - 1;
146 if !last.is_multiple_of(page_size) {
147 touched ^= unsafe { std::ptr::read_volatile(base.add(last)) };
148 }
149
150 std::hint::black_box(touched);
151}
152
153fn page_size_bytes() -> usize {
154 #[cfg(target_os = "linux")]
155 {
156 let rc = unsafe { libc::sysconf(libc::_SC_PAGESIZE) };
157 if rc > 0 {
158 return (rc as usize).max(4096);
159 }
160 }
161
162 4096
163}