Skip to content

Commit 1c7c834

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

File tree

7 files changed

+310
-178
lines changed

7 files changed

+310
-178
lines changed

src/bitmap.rs

Lines changed: 86 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,86 @@
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 an entire `GuestMemory` object.
5+
6+
use std::fmt::Debug;
7+
8+
use crate::{GuestMemory, GuestMemoryRegion};
9+
10+
/// Trait implemented by types that support creating `BitmapSlice` objects.
11+
pub trait WithBitmapSlice<'a> {
12+
/// Type of the bitmap slice.
13+
type S: BitmapSlice;
14+
}
15+
16+
/// Trait used to represent that a `BitmapSlice` is a `Bitmap` itself, but also satisfies the
17+
/// restriction that slices created from it have the same type as `Self`.
18+
pub trait BitmapSlice:
19+
Bitmap + Copy + Clone + Debug + for<'a> WithBitmapSlice<'a, S = Self>
20+
{
21+
}
22+
23+
/// Common bitmap operations. Using HRTBs to effectively define an associated type that
24+
/// has a lifetime parameter, without tagging the `Bitmap` trait with a lifetime as well.
25+
///
26+
/// Using an associated type allows implementing the `Bitmap` and `BitmapSlice` functionality
27+
/// as a zero-cost abstraction, when providing trivial implementations such as the one
28+
/// defined for `()`.
29+
// This is just an initial proposal; we'll add other methods if they need to be part of the main
30+
// interface as well.
31+
pub trait Bitmap: for<'a> WithBitmapSlice<'a> {
32+
/// Mark the memory range specified by the given `offset` and `len` as dirtied.
33+
fn mark_dirty(&self, offset: usize, len: usize);
34+
35+
/// Return a `Self::S::Slice` of the current bitmap, starting at the specified `offset`.
36+
fn slice_at(&self, offset: usize) -> <Self as WithBitmapSlice>::S;
37+
}
38+
39+
/// A no-op `Bitmap` implementation that can be provided for backends that do not actually
40+
/// require the tracking functionality.
41+
42+
impl<'a> WithBitmapSlice<'a> for () {
43+
type S = Self;
44+
}
45+
46+
impl BitmapSlice for () {}
47+
48+
impl Bitmap for () {
49+
fn mark_dirty(&self, _offset: usize, _len: usize) {}
50+
51+
fn slice_at(&self, _offset: usize) -> Self {}
52+
}
53+
54+
/// A `Bitmap` and `BitmapSlice` implementation for `Option<B>`.
55+
56+
impl<'a, B> WithBitmapSlice<'a> for Option<B>
57+
where
58+
B: WithBitmapSlice<'a>,
59+
{
60+
type S = Option<B::S>;
61+
}
62+
63+
impl<B: BitmapSlice> BitmapSlice for Option<B> {}
64+
65+
impl<B: Bitmap> Bitmap for Option<B> {
66+
fn mark_dirty(&self, offset: usize, len: usize) {
67+
if let Some(inner) = self {
68+
inner.mark_dirty(offset, len)
69+
}
70+
}
71+
72+
fn slice_at(&self, offset: usize) -> Option<<B as WithBitmapSlice>::S> {
73+
if let Some(inner) = self {
74+
return Some(inner.slice_at(offset));
75+
}
76+
None
77+
}
78+
}
79+
80+
/// Helper type alias for referring to the `BitmapSlice` concrete type associated with
81+
/// an object `B: WithBitmapSlice<'a>`.
82+
pub type BS<'a, B> = <B as WithBitmapSlice<'a>>::S;
83+
84+
/// Helper type alias for referring to the `BitmapSlice` concrete type associated with
85+
/// the memory regions of an object `M: GuestMemory`.
86+
pub type MS<'a, M> = BS<'a, <<M as GuestMemory>::R as GuestMemoryRegion>::B>;

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: 11 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -43,8 +43,9 @@ use std::sync::atomic::Ordering;
4343
use std::sync::Arc;
4444

4545
use crate::address::{Address, AddressValue};
46+
use crate::bitmap::{Bitmap, BS, MS};
4647
use crate::bytes::{AtomicAccess, Bytes};
47-
use crate::volatile_memory;
48+
use crate::volatile_memory::{self, VolatileSlice};
4849

4950
static MAX_ACCESS_CHUNK: usize = 4096;
5051

@@ -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,9 @@ 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+
180187
/// Returns the given address if it is within this region.
181188
fn check_address(&self, addr: MemoryRegionAddress) -> Option<MemoryRegionAddress> {
182189
if self.address_in_range(addr) {
@@ -257,7 +264,7 @@ pub trait GuestMemoryRegion: Bytes<MemoryRegionAddress, E = Error> {
257264
&self,
258265
offset: MemoryRegionAddress,
259266
count: usize,
260-
) -> Result<volatile_memory::VolatileSlice> {
267+
) -> Result<VolatileSlice<BS<Self::B>>> {
261268
Err(Error::HostAddressNotAvailable)
262269
}
263270

@@ -286,7 +293,7 @@ pub trait GuestMemoryRegion: Bytes<MemoryRegionAddress, E = Error> {
286293
/// assert_eq!(r.load(), v);
287294
/// # }
288295
/// ```
289-
fn as_volatile_slice(&self) -> Result<volatile_memory::VolatileSlice> {
296+
fn as_volatile_slice(&self) -> Result<VolatileSlice<BS<Self::B>>> {
290297
self.get_slice(MemoryRegionAddress(0), self.len() as usize)
291298
}
292299

@@ -702,11 +709,7 @@ pub trait GuestMemory {
702709

703710
/// Returns a [`VolatileSlice`](struct.VolatileSlice.html) of `count` bytes starting at
704711
/// `addr`.
705-
fn get_slice(
706-
&self,
707-
addr: GuestAddress,
708-
count: usize,
709-
) -> Result<volatile_memory::VolatileSlice> {
712+
fn get_slice(&self, addr: GuestAddress, count: usize) -> Result<VolatileSlice<MS<Self>>> {
710713
self.to_region_addr(addr)
711714
.ok_or(Error::InvalidGuestAddress(addr))
712715
.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)