Skip to content

Commit ed8a9d2

Browse files
committed
Snapshot only contains pages dirties since last snapshot was taken
Signed-off-by: Ludvig Liljenberg <[email protected]>
1 parent 7d47186 commit ed8a9d2

File tree

5 files changed

+686
-67
lines changed

5 files changed

+686
-67
lines changed

src/hyperlight_host/src/mem/mgr.rs

Lines changed: 32 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ limitations under the License.
1515
*/
1616

1717
use std::cmp::Ordering;
18+
use std::sync::Arc;
1819

1920
use hyperlight_common::flatbuffer_wrappers::function_call::{
2021
FunctionCall, validate_guest_function_call_buffer,
@@ -73,6 +74,8 @@ pub(crate) struct SandboxMemoryManager<S> {
7374
pub(crate) entrypoint_offset: Offset,
7475
/// How many memory regions were mapped after sandbox creation
7576
pub(crate) mapped_rgns: u64,
77+
/// Most recent snapshot taken, in other words, the most recent state that `self` has been in (disregarding currently dirty pages)
78+
pub(crate) most_recent_snapshot: Option<Arc<SharedMemorySnapshot>>,
7679
}
7780

7881
impl<S> SandboxMemoryManager<S>
@@ -93,6 +96,7 @@ where
9396
load_addr,
9497
entrypoint_offset,
9598
mapped_rgns: 0,
99+
most_recent_snapshot: None,
96100
}
97101
}
98102

@@ -259,25 +263,40 @@ where
259263
}
260264
}
261265

262-
pub(crate) fn snapshot(&mut self) -> Result<SharedMemorySnapshot> {
263-
SharedMemorySnapshot::new(&mut self.shared_mem, self.mapped_rgns)
266+
pub(crate) fn snapshot(
267+
&mut self,
268+
dirty_pages_bitmap: &[u64],
269+
) -> Result<Arc<SharedMemorySnapshot>> {
270+
let snapshot = Arc::new(SharedMemorySnapshot::new(
271+
&mut self.shared_mem,
272+
dirty_pages_bitmap,
273+
self.mapped_rgns,
274+
self.most_recent_snapshot.clone(),
275+
)?);
276+
self.most_recent_snapshot = Some(snapshot.clone());
277+
Ok(snapshot)
264278
}
265279

266280
/// This function restores a memory snapshot from a given snapshot.
267281
///
268282
/// Returns the number of memory regions mapped into the sandbox
269283
/// that need to be unmapped in order for the restore to be
270284
/// completed.
271-
pub(crate) fn restore_snapshot(&mut self, snapshot: &SharedMemorySnapshot) -> Result<u64> {
272-
if self.shared_mem.mem_size() != snapshot.mem_size() {
273-
return Err(new_error!(
274-
"Snapshot size does not match current memory size: {} != {}",
275-
self.shared_mem.raw_mem_size(),
276-
snapshot.mem_size()
277-
));
278-
}
285+
pub(crate) fn restore_snapshot(
286+
&mut self,
287+
snapshot: &Arc<SharedMemorySnapshot>,
288+
dirty_pages_bitmap: &[u64],
289+
) -> Result<u64> {
279290
let old_rgns = self.mapped_rgns;
280-
self.mapped_rgns = snapshot.restore_from_snapshot(&mut self.shared_mem)?;
291+
self.mapped_rgns = snapshot.restore_from_snapshot(
292+
&mut self.shared_mem,
293+
dirty_pages_bitmap,
294+
&self.most_recent_snapshot,
295+
)?;
296+
297+
// Update the most recent snapshot to the one we just restored to
298+
self.most_recent_snapshot = Some(snapshot.clone());
299+
281300
Ok(old_rgns - self.mapped_rgns)
282301
}
283302

@@ -407,13 +426,15 @@ impl SandboxMemoryManager<ExclusiveSharedMemory> {
407426
load_addr: self.load_addr.clone(),
408427
entrypoint_offset: self.entrypoint_offset,
409428
mapped_rgns: 0,
429+
most_recent_snapshot: self.most_recent_snapshot.clone(),
410430
},
411431
SandboxMemoryManager {
412432
shared_mem: gshm,
413433
layout: self.layout,
414434
load_addr: self.load_addr.clone(),
415435
entrypoint_offset: self.entrypoint_offset,
416436
mapped_rgns: 0,
437+
most_recent_snapshot: self.most_recent_snapshot.clone(),
417438
},
418439
)
419440
}

src/hyperlight_host/src/mem/shared_mem.rs

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -677,6 +677,30 @@ impl ExclusiveSharedMemory {
677677
Ok(())
678678
}
679679

680+
/// Same as `copy_from_slice` but doesn't dirty the pages.
681+
/// # Safety
682+
/// This function is unsafe because it does not mark the pages as dirty.
683+
/// Only use this if you are certain that the pages do not need to be marked as dirty.
684+
#[instrument(err(Debug), skip_all, parent = Span::current(), level= "Trace")]
685+
pub unsafe fn restore_copy_from_slice(&mut self, src: &[u8], offset: usize) -> Result<()> {
686+
let data = self.as_mut_slice();
687+
bounds_check!(offset, src.len(), data.len());
688+
data[offset..offset + src.len()].copy_from_slice(src);
689+
Ok(())
690+
}
691+
692+
/// Same as `zero_fill` but doesn't dirty the pages.
693+
/// # Safety
694+
/// This function is unsafe because it does not mark the pages as dirty.
695+
/// Only use this if you are certain that the pages do not need to be marked as dirty.
696+
#[instrument(err(Debug), skip_all, parent = Span::current(), level= "Trace")]
697+
pub(crate) unsafe fn restore_zero_fill(&mut self, offset: usize, len: usize) -> Result<()> {
698+
bounds_check!(offset, len, self.mem_size());
699+
let data = self.as_mut_slice();
700+
data[offset..offset + len].fill(0);
701+
Ok(())
702+
}
703+
680704
generate_reader!(read_u8, u8);
681705
generate_reader!(read_i8, i8);
682706
generate_reader!(read_u16, u16);

0 commit comments

Comments
 (0)