Skip to content

Commit f88a0fc

Browse files
committed
add dirty bitmap tracking abstractions
Signed-off-by: Alexandru Agache <[email protected]>
1 parent 089aac9 commit f88a0fc

File tree

7 files changed

+294
-169
lines changed

7 files changed

+294
-169
lines changed

src/bitmap.rs

Lines changed: 85 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,85 @@
1+
//! This module holds abstractions that enable tracking the areas dirtied by writes of a specified
2+
//! length to a given offset. In particular, this is used to track write accesses within a
3+
//! `GuestMemoryRegion` object, and the resulting bitmaps can then be aggregated to build the
4+
//! global view for the entire `GuestMemory`.
5+
6+
use std::fmt::{self, Debug};
7+
8+
/// Common bitmap operations.
9+
// This is just an initial proposal; we'll add other methods if they need to be part of the main
10+
// interface as well.
11+
pub trait Bitmap: Default {
12+
// For now this is mostly useful to preserve compatibility with the old `GuestMemoryMmap` (and
13+
// potentially other backends) constructors, which are not bitmap-aware. We can remove this
14+
// from the interface (and apply changes elsewhere) if it's too restrictive and/or configuring
15+
// the bitmap post-creation (via `GuestMemoryRegion::bitmap_mut`) gets unwieldy.
16+
/// Create a new bitmap of the given size.
17+
fn new(size: usize) -> Self;
18+
19+
/// Mark the memory range specified by the given `offset` and `len` as dirtied.
20+
fn mark_dirty(&self, offset: usize, len: usize);
21+
}
22+
23+
/// A no-op `Bitmap` implementation that can be provided to backends that do not actually
24+
/// require the tracking functionality.
25+
impl Bitmap for () {
26+
fn new(_size: usize) -> Self {
27+
()
28+
}
29+
30+
fn mark_dirty(&self, _offset: usize, _len: usize) {}
31+
}
32+
33+
/// Represents a slice into a `Bitmap` object, starting at `base_offset`.
34+
pub struct BitmapSlice<'a, B> {
35+
inner: &'a B,
36+
base_offset: usize,
37+
}
38+
39+
impl<'a, B: Bitmap> BitmapSlice<'a, B> {
40+
/// Create a new `BitmapSlice`, starting at the specified `offset`.
41+
pub fn new(bitmap: &'a B, offset: usize) -> Self {
42+
BitmapSlice {
43+
inner: bitmap,
44+
base_offset: offset,
45+
}
46+
}
47+
48+
/// Mark the memory range specified by the given `offset` (relative to the base offset of
49+
/// the slice) and `len` as dirtied.
50+
pub fn mark_dirty(&self, offset: usize, len: usize) {
51+
// The `Bitmap` operations are supposed to accompany guest memory accesses defined by the
52+
// same parameters (i.e. offset & length), so we use simple wrapping arithmetic instead of
53+
// performing additional checks. If an overflow would occur, we simply end up marking some
54+
// other region as dirty (which is just a false positive) instead of a region that could
55+
// not have been accessed to begin with.
56+
self.inner
57+
.mark_dirty(self.base_offset.wrapping_add(offset), len)
58+
}
59+
60+
/// Create a new `BitmapSlice` starting from the specified `offset` into the current slice.
61+
pub fn at_offset(&self, offset: usize) -> Self {
62+
BitmapSlice {
63+
inner: self.inner,
64+
base_offset: self.base_offset.wrapping_add(offset),
65+
}
66+
}
67+
}
68+
69+
impl<'a, B> Clone for BitmapSlice<'a, B> {
70+
fn clone(&self) -> Self {
71+
BitmapSlice {
72+
inner: self.inner,
73+
base_offset: self.base_offset,
74+
}
75+
}
76+
}
77+
78+
impl<'a, B> Copy for BitmapSlice<'a, B> {}
79+
80+
impl<'a, B> Debug for BitmapSlice<'a, B> {
81+
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
82+
// Dummy impl for now.
83+
write!(f, "(bitmap slice)")
84+
}
85+
}

src/bytes.rs

Lines changed: 0 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,6 @@ use std::slice::{from_raw_parts, from_raw_parts_mut};
1818
use std::sync::atomic::Ordering;
1919

2020
use crate::atomic_integer::AtomicInteger;
21-
use crate::VolatileSlice;
2221

2322
/// Types for which it is safe to initialize from raw data.
2423
///
@@ -105,22 +104,6 @@ pub unsafe trait ByteValued: Copy + Default + Send + Sync {
105104
// borrowing the given mutable reference.
106105
unsafe { from_raw_parts_mut(self as *mut Self as *mut u8, size_of::<Self>()) }
107106
}
108-
109-
/// Converts a mutable reference to `self` into a `VolatileSlice`. This is
110-
/// useful because `VolatileSlice` provides a `Bytes<usize>` implementation.
111-
///
112-
/// # Safety
113-
///
114-
/// Unlike most `VolatileMemory` implementation, this method requires an exclusive
115-
/// reference to `self`; this trivially fulfills `VolatileSlice::new`'s requirement
116-
/// that all accesses to `self` use volatile accesses (because there can
117-
/// be no other accesses).
118-
fn as_bytes(&mut self) -> VolatileSlice {
119-
unsafe {
120-
// This is safe because the lifetime is the same as self
121-
VolatileSlice::new(self as *mut Self as usize as *mut _, size_of::<Self>())
122-
}
123-
}
124107
}
125108

126109
// All intrinsic types and arrays of intrinsic types are ByteValued. They are just numbers.

src/guest_memory.rs

Lines changed: 14 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,7 @@ use std::sync::atomic::Ordering;
4343
use std::sync::Arc;
4444

4545
use crate::address::{Address, AddressValue};
46+
use crate::bitmap::Bitmap;
4647
use crate::bytes::{AtomicAccess, Bytes};
4748
use crate::volatile_memory;
4849

@@ -165,6 +166,9 @@ impl FileOffset {
165166
/// Represents a continuous region of guest physical memory.
166167
#[allow(clippy::len_without_is_empty)]
167168
pub trait GuestMemoryRegion: Bytes<MemoryRegionAddress, E = Error> {
169+
/// Type used for dirty memory tracking.
170+
type B: Bitmap;
171+
168172
/// Returns the size of the region.
169173
fn len(&self) -> GuestUsize;
170174

@@ -177,6 +181,12 @@ pub trait GuestMemoryRegion: Bytes<MemoryRegionAddress, E = Error> {
177181
self.start_addr().unchecked_add(self.len() - 1)
178182
}
179183

184+
/// Borrow the associated `Bitmap` object.
185+
fn bitmap(&self) -> &Self::B;
186+
187+
/// Mutably borrow the associated `Bitmap` object.
188+
fn bitmap_mut(&mut self) -> &mut Self::B;
189+
180190
/// Returns the given address if it is within this region.
181191
fn check_address(&self, addr: MemoryRegionAddress) -> Option<MemoryRegionAddress> {
182192
if self.address_in_range(addr) {
@@ -257,7 +267,7 @@ pub trait GuestMemoryRegion: Bytes<MemoryRegionAddress, E = Error> {
257267
&self,
258268
offset: MemoryRegionAddress,
259269
count: usize,
260-
) -> Result<volatile_memory::VolatileSlice> {
270+
) -> Result<volatile_memory::VolatileSlice<Self::B>> {
261271
Err(Error::HostAddressNotAvailable)
262272
}
263273

@@ -285,7 +295,7 @@ pub trait GuestMemoryRegion: Bytes<MemoryRegionAddress, E = Error> {
285295
/// # #[cfg(feature = "backend-mmap")]
286296
/// # test_as_volatile_slice();
287297
/// ```
288-
fn as_volatile_slice(&self) -> Result<volatile_memory::VolatileSlice> {
298+
fn as_volatile_slice(&self) -> Result<volatile_memory::VolatileSlice<Self::B>> {
289299
self.get_slice(MemoryRegionAddress(0), self.len() as usize)
290300
}
291301
}
@@ -620,7 +630,8 @@ pub trait GuestMemory {
620630
&self,
621631
addr: GuestAddress,
622632
count: usize,
623-
) -> Result<volatile_memory::VolatileSlice> {
633+
) -> Result<volatile_memory::VolatileSlice<<<Self as GuestMemory>::R as GuestMemoryRegion>::B>>
634+
{
624635
self.to_region_addr(addr)
625636
.ok_or_else(|| Error::InvalidGuestAddress(addr))
626637
.and_then(|(r, addr)| r.get_slice(addr, count))

src/lib.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,8 @@ pub use atomic::{GuestMemoryAtomic, GuestMemoryLoadGuard};
3131
mod atomic_integer;
3232
pub use atomic_integer::AtomicInteger;
3333

34+
pub mod bitmap;
35+
3436
pub mod bytes;
3537
pub use bytes::{AtomicAccess, ByteValued, Bytes};
3638

0 commit comments

Comments
 (0)