mirror of
https://chromium.googlesource.com/crosvm/crosvm
synced 2024-11-25 05:03:05 +00:00
crosvm: align pmem region size to 2MiB
Linux commit 7ea6216049ff9cf250a6722cd766d99c8d1424e5 "mm/sparsemem: prepare for sub-section ranges" added validation of memory region sizes for hotplugging. This requires alignment of the region to 2MiB, which can be done with a MemoryMappingArena that will pad the end of the region with read-only pages. BUG=chromium:1031408 TEST=crostini.Sanity.artifact with 5.4 guest kernel Change-Id: I526f23a5ef32edd3268cd23f010e2bc20f9c305a Reviewed-on: https://chromium-review.googlesource.com/c/chromiumos/platform/crosvm/+/1979257 Tested-by: kokoro <noreply+kokoro@google.com> Tested-by: Stephen Barber <smbarber@chromium.org> Reviewed-by: Daniel Verkamp <dverkamp@chromium.org> Commit-Queue: Stephen Barber <smbarber@chromium.org>
This commit is contained in:
parent
0b788defc6
commit
dc7c07bd08
1 changed files with 32 additions and 11 deletions
43
src/linux.rs
43
src/linux.rs
|
@ -50,7 +50,7 @@ use sys_util::{
|
||||||
self, block_signal, clear_signal, drop_capabilities, error, flock, get_blocked_signals,
|
self, block_signal, clear_signal, drop_capabilities, error, flock, get_blocked_signals,
|
||||||
get_group_id, get_user_id, getegid, geteuid, info, register_rt_signal_handler,
|
get_group_id, get_user_id, getegid, geteuid, info, register_rt_signal_handler,
|
||||||
set_cpu_affinity, validate_raw_fd, warn, EventFd, FlockOperation, GuestAddress, GuestMemory,
|
set_cpu_affinity, validate_raw_fd, warn, EventFd, FlockOperation, GuestAddress, GuestMemory,
|
||||||
Killable, MemoryMapping, PollContext, PollToken, Protection, SignalFd, Terminal, TimerFd,
|
Killable, MemoryMappingArena, PollContext, PollToken, Protection, SignalFd, Terminal, TimerFd,
|
||||||
WatchingEvents, SIGRTMIN,
|
WatchingEvents, SIGRTMIN,
|
||||||
};
|
};
|
||||||
use vhost;
|
use vhost;
|
||||||
|
@ -841,9 +841,26 @@ fn create_pmem_device(
|
||||||
.open(&disk.path)
|
.open(&disk.path)
|
||||||
.map_err(Error::Disk)?;
|
.map_err(Error::Disk)?;
|
||||||
|
|
||||||
let image_size = {
|
let (disk_size, arena_size) = {
|
||||||
let metadata = std::fs::metadata(&disk.path).map_err(Error::Disk)?;
|
let metadata = std::fs::metadata(&disk.path).map_err(Error::Disk)?;
|
||||||
metadata.len()
|
let disk_len = metadata.len();
|
||||||
|
// Linux requires pmem region sizes to be 2 MiB aligned. Linux will fill any partial page
|
||||||
|
// at the end of an mmap'd file and won't write back beyond the actual file length, but if
|
||||||
|
// we just align the size of the file to 2 MiB then access beyond the last page of the
|
||||||
|
// mapped file will generate SIGBUS. So use a memory mapping arena that will provide
|
||||||
|
// padding up to 2 MiB.
|
||||||
|
let alignment = 2 * 1024 * 1024;
|
||||||
|
let align_adjust = if disk_len % alignment != 0 {
|
||||||
|
alignment - (disk_len % alignment)
|
||||||
|
} else {
|
||||||
|
0
|
||||||
|
};
|
||||||
|
(
|
||||||
|
disk_len,
|
||||||
|
disk_len
|
||||||
|
.checked_add(align_adjust)
|
||||||
|
.ok_or(Error::PmemDeviceImageTooBig)?,
|
||||||
|
)
|
||||||
};
|
};
|
||||||
|
|
||||||
let protection = {
|
let protection = {
|
||||||
|
@ -854,18 +871,22 @@ fn create_pmem_device(
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
let memory_mapping = {
|
let arena = {
|
||||||
// Conversion from u64 to usize may fail on 32bit system.
|
// Conversion from u64 to usize may fail on 32bit system.
|
||||||
let image_size = usize::try_from(image_size).map_err(|_| Error::PmemDeviceImageTooBig)?;
|
let arena_size = usize::try_from(arena_size).map_err(|_| Error::PmemDeviceImageTooBig)?;
|
||||||
|
let disk_size = usize::try_from(disk_size).map_err(|_| Error::PmemDeviceImageTooBig)?;
|
||||||
|
|
||||||
MemoryMapping::from_fd_offset_protection(&fd, image_size, 0, protection)
|
let mut arena = MemoryMappingArena::new(arena_size).map_err(Error::ReservePmemMemory)?;
|
||||||
.map_err(Error::ReservePmemMemory)?
|
arena
|
||||||
|
.add_fd_offset_protection(0, disk_size, &fd, 0, protection)
|
||||||
|
.map_err(Error::ReservePmemMemory)?;
|
||||||
|
arena
|
||||||
};
|
};
|
||||||
|
|
||||||
let mapping_address = resources
|
let mapping_address = resources
|
||||||
.mmio_allocator(MmioType::High)
|
.mmio_allocator(MmioType::High)
|
||||||
.allocate_with_align(
|
.allocate_with_align(
|
||||||
image_size,
|
arena_size,
|
||||||
Alloc::PmemDevice(index),
|
Alloc::PmemDevice(index),
|
||||||
format!("pmem_disk_image_{}", index),
|
format!("pmem_disk_image_{}", index),
|
||||||
// Linux kernel requires pmem namespaces to be 128 MiB aligned.
|
// Linux kernel requires pmem namespaces to be 128 MiB aligned.
|
||||||
|
@ -873,15 +894,15 @@ fn create_pmem_device(
|
||||||
)
|
)
|
||||||
.map_err(Error::AllocatePmemDeviceAddress)?;
|
.map_err(Error::AllocatePmemDeviceAddress)?;
|
||||||
|
|
||||||
vm.add_mmio_memory(
|
vm.add_mmap_arena(
|
||||||
GuestAddress(mapping_address),
|
GuestAddress(mapping_address),
|
||||||
memory_mapping,
|
arena,
|
||||||
/* read_only = */ disk.read_only,
|
/* read_only = */ disk.read_only,
|
||||||
/* log_dirty_pages = */ false,
|
/* log_dirty_pages = */ false,
|
||||||
)
|
)
|
||||||
.map_err(Error::AddPmemDeviceMemory)?;
|
.map_err(Error::AddPmemDeviceMemory)?;
|
||||||
|
|
||||||
let dev = virtio::Pmem::new(fd, GuestAddress(mapping_address), image_size)
|
let dev = virtio::Pmem::new(fd, GuestAddress(mapping_address), arena_size)
|
||||||
.map_err(Error::PmemDeviceNew)?;
|
.map_err(Error::PmemDeviceNew)?;
|
||||||
|
|
||||||
Ok(VirtioDeviceStub {
|
Ok(VirtioDeviceStub {
|
||||||
|
|
Loading…
Reference in a new issue