mirror of
https://github.com/rust-lang/rust.git
synced 2025-05-06 06:57:42 +00:00

Adding support of quirky filesystems occuring in virtualised settings not having full POSIX support for memory mapped files. Example: current virtiofs with cache disabled, occuring in Incus/LXD or Kata Containers. Has been hitting various virtualised filesystems since 2016, depending on their levels of maturity at the time. The situation will perhaps improve when virtiofs DAX support patches will have made it into the qemu mainline. On a reliability level, using the MAP_PRIVATE sycall flag instead of the MAP_SHARED syscall flag for the mmap() system call does have some undefined behaviour when the caller update the memory mapping of the mmap()ed file, but MAP_SHARED does allow not only the calling process but other processes to modify the memory mapping. Thus, in the current context, using MAP_PRIVATE copy-on-write is marginally more reliable than MAP_SHARED. This discussion of reliability is orthogonal to the type system enforced safety policy of rust, which does not claim to handle memory modification of memory mapped files triggered through the operating system and not the running rust process.
119 lines
2.8 KiB
Rust
119 lines
2.8 KiB
Rust
use std::fs::File;
|
|
use std::io;
|
|
use std::ops::{Deref, DerefMut};
|
|
|
|
/// A trivial wrapper for [`memmap2::Mmap`] (or `Vec<u8>` on WASM).
|
|
#[cfg(not(target_arch = "wasm32"))]
|
|
pub struct Mmap(memmap2::Mmap);
|
|
|
|
#[cfg(target_arch = "wasm32")]
|
|
pub struct Mmap(Vec<u8>);
|
|
|
|
#[cfg(not(target_arch = "wasm32"))]
|
|
impl Mmap {
|
|
/// # Safety
|
|
///
|
|
/// The given file must not be mutated (i.e., not written, not truncated, ...) until the mapping is closed.
|
|
///
|
|
/// However in practice most callers do not ensure this, so uses of this function are likely unsound.
|
|
#[inline]
|
|
pub unsafe fn map(file: File) -> io::Result<Self> {
|
|
// By default, memmap2 creates shared mappings, implying that we could see updates to the
|
|
// file through the mapping. That would violate our precondition; so by requesting a
|
|
// map_copy_read_only we do not lose anything.
|
|
// This mapping mode also improves our support for filesystems such as cacheless virtiofs.
|
|
// For more details see https://github.com/rust-lang/rust/issues/122262
|
|
//
|
|
// SAFETY: The caller must ensure that this is safe.
|
|
unsafe { memmap2::MmapOptions::new().map_copy_read_only(&file).map(Mmap) }
|
|
}
|
|
}
|
|
|
|
#[cfg(target_arch = "wasm32")]
|
|
impl Mmap {
|
|
#[inline]
|
|
pub unsafe fn map(mut file: File) -> io::Result<Self> {
|
|
use std::io::Read;
|
|
|
|
let mut data = Vec::new();
|
|
file.read_to_end(&mut data)?;
|
|
Ok(Mmap(data))
|
|
}
|
|
}
|
|
|
|
impl Deref for Mmap {
|
|
type Target = [u8];
|
|
|
|
#[inline]
|
|
fn deref(&self) -> &[u8] {
|
|
&self.0
|
|
}
|
|
}
|
|
|
|
impl AsRef<[u8]> for Mmap {
|
|
fn as_ref(&self) -> &[u8] {
|
|
&self.0
|
|
}
|
|
}
|
|
|
|
#[cfg(not(target_arch = "wasm32"))]
|
|
pub struct MmapMut(memmap2::MmapMut);
|
|
|
|
#[cfg(target_arch = "wasm32")]
|
|
pub struct MmapMut(Vec<u8>);
|
|
|
|
#[cfg(not(target_arch = "wasm32"))]
|
|
impl MmapMut {
|
|
#[inline]
|
|
pub fn map_anon(len: usize) -> io::Result<Self> {
|
|
let mmap = memmap2::MmapMut::map_anon(len)?;
|
|
Ok(MmapMut(mmap))
|
|
}
|
|
|
|
#[inline]
|
|
pub fn flush(&mut self) -> io::Result<()> {
|
|
self.0.flush()
|
|
}
|
|
|
|
#[inline]
|
|
pub fn make_read_only(self) -> std::io::Result<Mmap> {
|
|
let mmap = self.0.make_read_only()?;
|
|
Ok(Mmap(mmap))
|
|
}
|
|
}
|
|
|
|
#[cfg(target_arch = "wasm32")]
|
|
impl MmapMut {
|
|
#[inline]
|
|
pub fn map_anon(len: usize) -> io::Result<Self> {
|
|
let data = Vec::with_capacity(len);
|
|
Ok(MmapMut(data))
|
|
}
|
|
|
|
#[inline]
|
|
pub fn flush(&mut self) -> io::Result<()> {
|
|
Ok(())
|
|
}
|
|
|
|
#[inline]
|
|
pub fn make_read_only(self) -> std::io::Result<Mmap> {
|
|
Ok(Mmap(self.0))
|
|
}
|
|
}
|
|
|
|
impl Deref for MmapMut {
|
|
type Target = [u8];
|
|
|
|
#[inline]
|
|
fn deref(&self) -> &[u8] {
|
|
&self.0
|
|
}
|
|
}
|
|
|
|
impl DerefMut for MmapMut {
|
|
#[inline]
|
|
fn deref_mut(&mut self) -> &mut [u8] {
|
|
&mut self.0
|
|
}
|
|
}
|