diff --git a/envd-rs/src/http/snapshot.rs b/envd-rs/src/http/snapshot.rs index 977b6bd..e507d8f 100644 --- a/envd-rs/src/http/snapshot.rs +++ b/envd-rs/src/http/snapshot.rs @@ -10,12 +10,22 @@ use crate::state::AppState; /// POST /snapshot/prepare — quiesce subsystems before Firecracker snapshot. /// /// In Rust there is no GC dance. We just: -/// 1. Stop port subsystem -/// 2. Close idle connections via conntracker -/// 3. Set needs_restore flag +/// 1. Drop page cache to shrink snapshot size +/// 2. Stop port subsystem +/// 3. Close idle connections via conntracker +/// 4. Set needs_restore flag pub async fn post_snapshot_prepare(State(state): State>) -> impl IntoResponse { - // Block memory reclaimer before anything else — prevents drop_caches - // from running mid-freeze which would corrupt kernel page table state. + // Drop page cache BEFORE blocking the reclaimer — avoids snapshotting + // gigabytes of stale cache that inflates the memory dump on disk. + // "1" = pagecache only (keep dentries/inodes for faster resume). + if let Err(e) = std::fs::write("/proc/sys/vm/drop_caches", "1") { + tracing::warn!(error = %e, "snapshot/prepare: drop_caches failed"); + } else { + tracing::info!("snapshot/prepare: page cache dropped"); + } + + // Block memory reclaimer — prevents drop_caches from running mid-freeze + // which would corrupt kernel page table state. state.snapshot_in_progress.store(true, Ordering::Release); if let Some(ref ps) = state.port_subsystem {