Skip to content

Commit 40d70d7

Browse files
alexandruagandreeaflorescu
authored andcommitted
fix mmap_windows
Signed-off-by: Alexandru Agache <[email protected]>
1 parent bc542ad commit 40d70d7

File tree

3 files changed

+73
-16
lines changed

3 files changed

+73
-16
lines changed

Cargo.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@ arc-swap = { version = ">=1.0.0", optional = true }
2222

2323
[target.'cfg(windows)'.dependencies.winapi]
2424
version = ">=0.3"
25-
features = ["errhandlingapi"]
25+
features = ["errhandlingapi", "sysinfoapi"]
2626

2727
[dev-dependencies]
2828
criterion = "0.3.0"

src/bitmap/backend/atomic_bitmap.rs

Lines changed: 22 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -137,8 +137,28 @@ impl NewBitmap for AtomicBitmap {
137137
fn with_len(len: usize) -> Self {
138138
use std::convert::TryFrom;
139139

140-
// There's no unsafe potential in calling this function.
141-
let page_size = unsafe { libc::sysconf(libc::_SC_PAGE_SIZE) };
140+
let page_size;
141+
142+
#[cfg(unix)]
143+
{
144+
// There's no unsafe potential in calling this function.
145+
page_size = unsafe { libc::sysconf(libc::_SC_PAGE_SIZE) };
146+
}
147+
148+
#[cfg(windows)]
149+
{
150+
use winapi::um::sysinfoapi::{GetSystemInfo, LPSYSTEM_INFO, SYSTEM_INFO};
151+
152+
// It's safe to initialize this object from a zeroed memory region.
153+
let mut sysinfo: SYSTEM_INFO = unsafe { std::mem::zeroed() };
154+
155+
// It's safe to call this method as the pointer is based on the address
156+
// of the previously initialized `sysinfo` object.
157+
unsafe { GetSystemInfo(&mut sysinfo as LPSYSTEM_INFO) };
158+
159+
page_size = sysinfo.dwPageSize;
160+
}
161+
142162
// The `unwrap` is safe to use because the above call should always succeed on the
143163
// supported platforms, and the size of a page will always fit within a `usize`.
144164
AtomicBitmap::new(len, usize::try_from(page_size).unwrap())

src/mmap_windows.rs

Lines changed: 50 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -12,8 +12,9 @@ use libc::{c_void, size_t};
1212

1313
use winapi::um::errhandlingapi::GetLastError;
1414

15+
use crate::bitmap::{Bitmap, BS};
1516
use crate::guest_memory::FileOffset;
16-
use crate::mmap::AsSlice;
17+
use crate::mmap::{AsSlice, NewBitmap};
1718
use crate::volatile_memory::{self, compute_offset, VolatileMemory, VolatileSlice};
1819

1920
#[allow(non_snake_case)]
@@ -70,20 +71,21 @@ pub const ERROR_INVALID_PARAMETER: i32 = 87;
7071
/// physical memory may be mapped into the current process due to the limited virtual address
7172
/// space size of the process.
7273
#[derive(Debug)]
73-
pub struct MmapRegion {
74+
pub struct MmapRegion<B> {
7475
addr: *mut u8,
7576
size: usize,
77+
bitmap: B,
7678
file_offset: Option<FileOffset>,
7779
}
7880

7981
// Send and Sync aren't automatically inherited for the raw address pointer.
8082
// Accessing that pointer is only done through the stateless interface which
8183
// allows the object to be shared by multiple threads without a decrease in
8284
// safety.
83-
unsafe impl Send for MmapRegion {}
84-
unsafe impl Sync for MmapRegion {}
85+
unsafe impl<B: Send> Send for MmapRegion<B> {}
86+
unsafe impl<B: Sync> Sync for MmapRegion<B> {}
8587

86-
impl MmapRegion {
88+
impl<B: NewBitmap> MmapRegion<B> {
8789
/// Creates a shared anonymous mapping of `size` bytes.
8890
///
8991
/// # Arguments
@@ -101,6 +103,7 @@ impl MmapRegion {
101103
Ok(Self {
102104
addr: addr as *mut u8,
103105
size,
106+
bitmap: B::with_len(size),
104107
file_offset: None,
105108
})
106109
}
@@ -155,11 +158,16 @@ impl MmapRegion {
155158
Ok(Self {
156159
addr: addr as *mut u8,
157160
size,
161+
bitmap: B::with_len(size),
158162
file_offset: Some(file_offset),
159163
})
160164
}
165+
}
161166

162-
/// Returns a pointer to the beginning of the memory region.
167+
impl<B: Bitmap> MmapRegion<B> {
168+
/// Returns a pointer to the beginning of the memory region. Mutable accesses performed
169+
/// using the resulting pointer are not automatically accounted for by the dirty bitmap
170+
/// tracking functionality.
163171
///
164172
/// Should only be used for passing this region to ioctls for setting guest memory.
165173
pub fn as_ptr(&self) -> *mut u8 {
@@ -175,9 +183,14 @@ impl MmapRegion {
175183
pub fn file_offset(&self) -> Option<&FileOffset> {
176184
self.file_offset.as_ref()
177185
}
186+
187+
/// Returns a reference to the inner bitmap object.
188+
pub fn bitmap(&self) -> &B {
189+
&self.bitmap
190+
}
178191
}
179192

180-
impl AsSlice for MmapRegion {
193+
impl<B> AsSlice for MmapRegion<B> {
181194
unsafe fn as_slice(&self) -> &[u8] {
182195
// This is safe because we mapped the area at addr ourselves, so this slice will not
183196
// overflow. However, it is possible to alias.
@@ -192,24 +205,36 @@ impl AsSlice for MmapRegion {
192205
}
193206
}
194207

195-
impl VolatileMemory for MmapRegion {
208+
impl<B: Bitmap> VolatileMemory for MmapRegion<B> {
209+
type B = B;
210+
196211
fn len(&self) -> usize {
197212
self.size
198213
}
199214

200-
fn get_slice(&self, offset: usize, count: usize) -> volatile_memory::Result<VolatileSlice> {
215+
fn get_slice(
216+
&self,
217+
offset: usize,
218+
count: usize,
219+
) -> volatile_memory::Result<VolatileSlice<BS<Self::B>>> {
201220
let end = compute_offset(offset, count)?;
202221
if end > self.size {
203222
return Err(volatile_memory::Error::OutOfBounds { addr: end });
204223
}
205224

206225
// Safe because we checked that offset + count was within our range and we only ever hand
207226
// out volatile accessors.
208-
Ok(unsafe { VolatileSlice::new((self.addr as usize + offset) as *mut _, count) })
227+
Ok(unsafe {
228+
VolatileSlice::with_bitmap(
229+
(self.addr as usize + offset) as *mut _,
230+
count,
231+
self.bitmap.slice_at(offset),
232+
)
233+
})
209234
}
210235
}
211236

212-
impl Drop for MmapRegion {
237+
impl<B> Drop for MmapRegion<B> {
213238
fn drop(&mut self) {
214239
// This is safe because we mmap the area at addr ourselves, and nobody
215240
// else is holding a reference to it.
@@ -233,15 +258,27 @@ impl Drop for MmapRegion {
233258

234259
#[cfg(test)]
235260
mod tests {
236-
use crate::guest_memory::FileOffset;
237-
use crate::mmap_windows::{MmapRegion, INVALID_HANDLE_VALUE};
238261
use std::os::windows::io::FromRawHandle;
239262

263+
use crate::bitmap::AtomicBitmap;
264+
use crate::guest_memory::FileOffset;
265+
use crate::mmap_windows::INVALID_HANDLE_VALUE;
266+
267+
type MmapRegion = super::MmapRegion<()>;
268+
240269
#[test]
241270
fn map_invalid_handle() {
242271
let file = unsafe { std::fs::File::from_raw_handle(INVALID_HANDLE_VALUE) };
243272
let file_offset = FileOffset::new(file, 0);
244273
let e = MmapRegion::from_file(file_offset, 1024).unwrap_err();
245274
assert_eq!(e.raw_os_error(), Some(libc::EBADF));
246275
}
276+
277+
#[test]
278+
fn test_dirty_tracking() {
279+
// Using the `crate` prefix because we aliased `MmapRegion` to `MmapRegion<()>` for
280+
// the rest of the unit tests above.
281+
let m = crate::MmapRegion::<AtomicBitmap>::new(0x1_0000).unwrap();
282+
crate::bitmap::tests::test_volatile_memory(&m);
283+
}
247284
}

0 commit comments

Comments
 (0)