• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 //! libc syscalls supporting `rustix::mm`.
2 
3 use super::super::c;
4 #[cfg(any(target_os = "android", target_os = "linux"))]
5 use super::super::conv::syscall_ret_owned_fd;
6 use super::super::conv::{borrowed_fd, no_fd, ret};
7 use super::super::offset::libc_mmap;
8 #[cfg(not(target_os = "redox"))]
9 use super::types::Advice;
10 #[cfg(target_os = "linux")]
11 use super::types::MremapFlags;
12 use super::types::{MapFlags, MprotectFlags, MsyncFlags, ProtFlags};
13 #[cfg(any(target_os = "android", target_os = "linux"))]
14 use super::types::{MlockFlags, UserfaultfdFlags};
15 use crate::fd::BorrowedFd;
16 #[cfg(any(target_os = "android", target_os = "linux"))]
17 use crate::fd::OwnedFd;
18 use crate::io;
19 
20 #[cfg(not(target_os = "redox"))]
madvise(addr: *mut c::c_void, len: usize, advice: Advice) -> io::Result<()>21 pub(crate) fn madvise(addr: *mut c::c_void, len: usize, advice: Advice) -> io::Result<()> {
22     // On Linux platforms, `MADV_DONTNEED` has the same value as
23     // `POSIX_MADV_DONTNEED` but different behavior. We remap it to a different
24     // value, and check for it here.
25     #[cfg(target_os = "linux")]
26     if let Advice::LinuxDontNeed = advice {
27         return unsafe { ret(c::madvise(addr, len, c::MADV_DONTNEED)) };
28     }
29 
30     #[cfg(not(target_os = "android"))]
31     {
32         let err = unsafe { c::posix_madvise(addr, len, advice as c::c_int) };
33 
34         // `posix_madvise` returns its error status rather than using `errno`.
35         if err == 0 {
36             Ok(())
37         } else {
38             Err(io::Errno(err))
39         }
40     }
41 
42     #[cfg(target_os = "android")]
43     {
44         if let Advice::DontNeed = advice {
45             // Do nothing. Linux's `MADV_DONTNEED` isn't the same as
46             // `POSIX_MADV_DONTNEED`, so just discard `MADV_DONTNEED`.
47             Ok(())
48         } else {
49             unsafe { ret(c::madvise(addr, len, advice as c::c_int)) }
50         }
51     }
52 }
53 
msync(addr: *mut c::c_void, len: usize, flags: MsyncFlags) -> io::Result<()>54 pub(crate) unsafe fn msync(addr: *mut c::c_void, len: usize, flags: MsyncFlags) -> io::Result<()> {
55     let err = c::msync(addr, len, flags.bits());
56 
57     // `msync` returns its error status rather than using `errno`.
58     if err == 0 {
59         Ok(())
60     } else {
61         Err(io::Errno(err))
62     }
63 }
64 
65 /// # Safety
66 ///
67 /// `mmap` is primarily unsafe due to the `addr` parameter, as anything working
68 /// with memory pointed to by raw pointers is unsafe.
mmap( ptr: *mut c::c_void, len: usize, prot: ProtFlags, flags: MapFlags, fd: BorrowedFd<'_>, offset: u64, ) -> io::Result<*mut c::c_void>69 pub(crate) unsafe fn mmap(
70     ptr: *mut c::c_void,
71     len: usize,
72     prot: ProtFlags,
73     flags: MapFlags,
74     fd: BorrowedFd<'_>,
75     offset: u64,
76 ) -> io::Result<*mut c::c_void> {
77     let res = libc_mmap(
78         ptr,
79         len,
80         prot.bits(),
81         flags.bits(),
82         borrowed_fd(fd),
83         offset as i64,
84     );
85     if res == c::MAP_FAILED {
86         Err(io::Errno::last_os_error())
87     } else {
88         Ok(res)
89     }
90 }
91 
92 /// # Safety
93 ///
94 /// `mmap` is primarily unsafe due to the `addr` parameter, as anything working
95 /// with memory pointed to by raw pointers is unsafe.
mmap_anonymous( ptr: *mut c::c_void, len: usize, prot: ProtFlags, flags: MapFlags, ) -> io::Result<*mut c::c_void>96 pub(crate) unsafe fn mmap_anonymous(
97     ptr: *mut c::c_void,
98     len: usize,
99     prot: ProtFlags,
100     flags: MapFlags,
101 ) -> io::Result<*mut c::c_void> {
102     let res = libc_mmap(
103         ptr,
104         len,
105         prot.bits(),
106         flags.bits() | c::MAP_ANONYMOUS,
107         no_fd(),
108         0,
109     );
110     if res == c::MAP_FAILED {
111         Err(io::Errno::last_os_error())
112     } else {
113         Ok(res)
114     }
115 }
116 
mprotect( ptr: *mut c::c_void, len: usize, flags: MprotectFlags, ) -> io::Result<()>117 pub(crate) unsafe fn mprotect(
118     ptr: *mut c::c_void,
119     len: usize,
120     flags: MprotectFlags,
121 ) -> io::Result<()> {
122     ret(c::mprotect(ptr, len, flags.bits()))
123 }
124 
munmap(ptr: *mut c::c_void, len: usize) -> io::Result<()>125 pub(crate) unsafe fn munmap(ptr: *mut c::c_void, len: usize) -> io::Result<()> {
126     ret(c::munmap(ptr, len))
127 }
128 
129 /// # Safety
130 ///
131 /// `mremap` is primarily unsafe due to the `old_address` parameter, as
132 /// anything working with memory pointed to by raw pointers is unsafe.
133 #[cfg(target_os = "linux")]
mremap( old_address: *mut c::c_void, old_size: usize, new_size: usize, flags: MremapFlags, ) -> io::Result<*mut c::c_void>134 pub(crate) unsafe fn mremap(
135     old_address: *mut c::c_void,
136     old_size: usize,
137     new_size: usize,
138     flags: MremapFlags,
139 ) -> io::Result<*mut c::c_void> {
140     let res = c::mremap(old_address, old_size, new_size, flags.bits());
141     if res == c::MAP_FAILED {
142         Err(io::Errno::last_os_error())
143     } else {
144         Ok(res)
145     }
146 }
147 
148 /// # Safety
149 ///
150 /// `mremap_fixed` is primarily unsafe due to the `old_address` and
151 /// `new_address` parameters, as anything working with memory pointed to by raw
152 /// pointers is unsafe.
153 #[cfg(target_os = "linux")]
mremap_fixed( old_address: *mut c::c_void, old_size: usize, new_size: usize, flags: MremapFlags, new_address: *mut c::c_void, ) -> io::Result<*mut c::c_void>154 pub(crate) unsafe fn mremap_fixed(
155     old_address: *mut c::c_void,
156     old_size: usize,
157     new_size: usize,
158     flags: MremapFlags,
159     new_address: *mut c::c_void,
160 ) -> io::Result<*mut c::c_void> {
161     let res = c::mremap(
162         old_address,
163         old_size,
164         new_size,
165         flags.bits() | c::MAP_FIXED,
166         new_address,
167     );
168     if res == c::MAP_FAILED {
169         Err(io::Errno::last_os_error())
170     } else {
171         Ok(res)
172     }
173 }
174 
175 /// # Safety
176 ///
177 /// `mlock` operates on raw pointers and may round out to the nearest page
178 /// boundaries.
179 #[inline]
mlock(addr: *mut c::c_void, length: usize) -> io::Result<()>180 pub(crate) unsafe fn mlock(addr: *mut c::c_void, length: usize) -> io::Result<()> {
181     ret(c::mlock(addr, length))
182 }
183 
184 /// # Safety
185 ///
186 /// `mlock_with` operates on raw pointers and may round out to the nearest page
187 /// boundaries.
188 #[cfg(any(target_os = "android", target_os = "linux"))]
189 #[inline]
mlock_with( addr: *mut c::c_void, length: usize, flags: MlockFlags, ) -> io::Result<()>190 pub(crate) unsafe fn mlock_with(
191     addr: *mut c::c_void,
192     length: usize,
193     flags: MlockFlags,
194 ) -> io::Result<()> {
195     weak_or_syscall! {
196         fn mlock2(
197             addr: *const c::c_void,
198             len: c::size_t,
199             flags: c::c_int
200         ) via SYS_mlock2 -> c::c_int
201     }
202 
203     ret(mlock2(addr, length, flags.bits()))
204 }
205 
206 /// # Safety
207 ///
208 /// `munlock` operates on raw pointers and may round out to the nearest page
209 /// boundaries.
210 #[inline]
munlock(addr: *mut c::c_void, length: usize) -> io::Result<()>211 pub(crate) unsafe fn munlock(addr: *mut c::c_void, length: usize) -> io::Result<()> {
212     ret(c::munlock(addr, length))
213 }
214 
215 #[cfg(any(target_os = "android", target_os = "linux"))]
userfaultfd(flags: UserfaultfdFlags) -> io::Result<OwnedFd>216 pub(crate) unsafe fn userfaultfd(flags: UserfaultfdFlags) -> io::Result<OwnedFd> {
217     syscall_ret_owned_fd(c::syscall(c::SYS_userfaultfd, flags.bits()))
218 }
219