Skip to content

Commit dbcc9a6

Browse files
committed
refactor(balloon): do not madvise(MADV_DONTNEED) when resuming from file
This operation is completely useless after we mmap-ed anonymous private zero pages on top of the file mapping. Also, add a TODO for memfd-backed memory, as it's currently not supported using madvise. Signed-off-by: Riccardo Mancini <[email protected]>
1 parent 48d614f commit dbcc9a6

File tree

1 file changed

+45
-36
lines changed

1 file changed

+45
-36
lines changed

src/vmm/src/vstate/memory.rs

Lines changed: 45 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -115,43 +115,52 @@ impl GuestRegionMmapExt {
115115
) -> Result<usize, GuestMemoryError> {
116116
let phys_address = self.get_host_address(caddr)?;
117117

118-
// If and only if we are resuming from a snapshot file, we have a file and it's mapped
119-
// private
120-
if self.inner.file_offset().is_some() && self.inner.flags() & libc::MAP_PRIVATE != 0 {
121-
// Mmap a new anonymous region over the present one in order to create a hole
122-
// with zero pages.
123-
// This workaround is (only) needed after resuming from a snapshot file because the
124-
// guest memory is mmaped from file as private. In this case, MADV_DONTNEED on the
125-
// file only drops any anonymous pages in range, but subsequent accesses would read
126-
// whatever page is stored on the backing file. Mmapping anonymous pages ensures it's
127-
// zeroed.
128-
// SAFETY: The address and length are known to be valid.
129-
let ret = unsafe {
130-
libc::mmap(
131-
phys_address.cast(),
132-
len,
133-
libc::PROT_READ | libc::PROT_WRITE,
134-
libc::MAP_FIXED | libc::MAP_ANONYMOUS | libc::MAP_PRIVATE,
135-
-1,
136-
0,
137-
)
138-
};
139-
if ret == libc::MAP_FAILED {
140-
let os_error = std::io::Error::last_os_error();
141-
error!("discard_range: mmap failed: {:?}", os_error);
142-
return Err(GuestMemoryError::IOError(os_error));
118+
match (self.inner.file_offset(), self.inner.flags()) {
119+
// If and only if we are resuming from a snapshot file, we have a file and it's mapped
120+
// private
121+
(Some(_), flags) if flags & libc::MAP_PRIVATE != 0 => {
122+
// Mmap a new anonymous region over the present one in order to create a hole
123+
// with zero pages.
124+
// This workaround is (only) needed after resuming from a snapshot file because the
125+
// guest memory is mmaped from file as private. In this case, MADV_DONTNEED on the
126+
// file only drops any anonymous pages in range, but subsequent accesses would read
127+
// whatever page is stored on the backing file. Mmapping anonymous pages ensures
128+
// it's zeroed.
129+
// SAFETY: The address and length are known to be valid.
130+
let ret = unsafe {
131+
libc::mmap(
132+
phys_address.cast(),
133+
len,
134+
libc::PROT_READ | libc::PROT_WRITE,
135+
libc::MAP_FIXED | libc::MAP_ANONYMOUS | libc::MAP_PRIVATE,
136+
-1,
137+
0,
138+
)
139+
};
140+
if ret == libc::MAP_FAILED {
141+
let os_error = std::io::Error::last_os_error();
142+
error!("discard_range: mmap failed: {:?}", os_error);
143+
Err(GuestMemoryError::IOError(os_error))
144+
} else {
145+
Ok(len)
146+
}
147+
}
148+
// TODO: madvise(MADV_DONTNEED) doesn't actually work with memfd
149+
// (or in general MAP_SHARED of a fd). In those cases we should use
150+
// fallocate64(FALLOC_FL_PUNCH_HOLE|FALLOC_FL_KEEP_SIZE).
151+
// We keep falling to the madvise branch to keep the previous behaviour.
152+
(None, _) | (Some(_), _) => {
153+
// Madvise the region in order to mark it as not used.
154+
// SAFETY: The address and length are known to be valid.
155+
let ret = unsafe { libc::madvise(phys_address.cast(), len, libc::MADV_DONTNEED) };
156+
if ret < 0 {
157+
let os_error = std::io::Error::last_os_error();
158+
error!("discard_range: madvise failed: {:?}", os_error);
159+
Err(GuestMemoryError::IOError(os_error))
160+
} else {
161+
Ok(len)
162+
}
143163
}
144-
}
145-
146-
// Madvise the region in order to mark it as not used.
147-
// SAFETY: The address and length are known to be valid.
148-
let ret = unsafe { libc::madvise(phys_address.cast(), len, libc::MADV_DONTNEED) };
149-
if ret < 0 {
150-
let os_error = std::io::Error::last_os_error();
151-
error!("discard_range: madvise failed: {:?}", os_error);
152-
Err(GuestMemoryError::IOError(os_error))
153-
} else {
154-
Ok(len)
155164
}
156165
}
157166
}

0 commit comments

Comments
 (0)