Skip to content

Commit fdc8cf0

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 79061d9 commit fdc8cf0

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
@@ -116,43 +116,52 @@ impl GuestRegionMmapExt {
116116
) -> Result<(), GuestMemoryError> {
117117
let phys_address = self.get_host_address(caddr)?;
118118

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

0 commit comments

Comments
 (0)