|
|
@ -4,17 +4,193 @@
|
|
|
|
//! Huge-pages can also be used for this memory.
|
|
|
|
//! Huge-pages can also be used for this memory.
|
|
|
|
use super::*;
|
|
|
|
use super::*;
|
|
|
|
use libc::{
|
|
|
|
use libc::{
|
|
|
|
|
|
|
|
c_uint,
|
|
|
|
memfd_create,
|
|
|
|
memfd_create,
|
|
|
|
MFD_CLOEXEC,
|
|
|
|
MFD_CLOEXEC,
|
|
|
|
MFD_HUGETLB,
|
|
|
|
MFD_HUGETLB,
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
ftruncate,
|
|
|
|
|
|
|
|
};
|
|
|
|
|
|
|
|
use std::{
|
|
|
|
|
|
|
|
ffi::CStr,
|
|
|
|
|
|
|
|
borrow::{
|
|
|
|
|
|
|
|
Borrow,
|
|
|
|
|
|
|
|
BorrowMut,
|
|
|
|
|
|
|
|
},
|
|
|
|
|
|
|
|
ops,
|
|
|
|
|
|
|
|
};
|
|
|
|
|
|
|
|
use hugetlb::{
|
|
|
|
|
|
|
|
MapHugeFlag,
|
|
|
|
|
|
|
|
HugePage,
|
|
|
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
static UNNAMED: &'static CStr = unsafe {
|
|
|
|
|
|
|
|
CStr::from_bytes_with_nul_unchecked(b"<unnamed memory file>\0")
|
|
|
|
};
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
const DEFAULT_FLAGS: c_uint = MFD_CLOEXEC;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
#[inline(always)]
|
|
|
|
|
|
|
|
//XXX: Is the static bound required here?
|
|
|
|
|
|
|
|
/// Create a raw, unmanaged, memory file with these flags and this name.
|
|
|
|
|
|
|
|
///
|
|
|
|
|
|
|
|
/// # Safety
|
|
|
|
|
|
|
|
/// The reference obtained by `name` must not move as long as the `Ok()` result is alive.
|
|
|
|
|
|
|
|
pub unsafe fn create_raw(name: impl AsRef<CStr>, flags: c_uint) -> io::Result<UnmanagedFD>
|
|
|
|
|
|
|
|
{
|
|
|
|
|
|
|
|
UnmanagedFD::new_raw(memfd_create(name.as_ref().as_ptr(), flags)).ok_or_else(|| io::Error::last_os_error())
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/// A physical-memory backed file
|
|
|
|
/// A physical-memory backed file
|
|
|
|
#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
|
|
|
|
#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
|
|
|
|
#[repr(transparent)]
|
|
|
|
#[repr(transparent)]
|
|
|
|
pub struct MemoryFile(ManagedFD);
|
|
|
|
pub struct MemoryFile(ManagedFD);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/// A named, physical-memory backed file
|
|
|
|
|
|
|
|
#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
|
|
|
|
|
|
|
|
pub struct NamedMemoryFile(Box<CStr>, MemoryFile);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
impl Borrow<MemoryFile> for NamedMemoryFile
|
|
|
|
|
|
|
|
{
|
|
|
|
|
|
|
|
#[inline]
|
|
|
|
|
|
|
|
fn borrow(&self) -> &MemoryFile {
|
|
|
|
|
|
|
|
&self.1
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
impl BorrowMut<MemoryFile> for NamedMemoryFile
|
|
|
|
|
|
|
|
{
|
|
|
|
|
|
|
|
#[inline]
|
|
|
|
|
|
|
|
fn borrow_mut(&mut self) -> &mut MemoryFile {
|
|
|
|
|
|
|
|
&mut self.1
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
impl ops::DerefMut for NamedMemoryFile
|
|
|
|
|
|
|
|
{
|
|
|
|
|
|
|
|
fn deref_mut(&mut self) -> &mut Self::Target {
|
|
|
|
|
|
|
|
&mut self.1
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
impl ops::Deref for NamedMemoryFile
|
|
|
|
|
|
|
|
{
|
|
|
|
|
|
|
|
type Target = MemoryFile;
|
|
|
|
|
|
|
|
#[inline]
|
|
|
|
|
|
|
|
fn deref(&self) -> &Self::Target {
|
|
|
|
|
|
|
|
&self.1
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
//TODO: impl `MemoryFile` (memfd_create() fd wrapper)
|
|
|
|
//TODO: impl `MemoryFile` (memfd_create() fd wrapper)
|
|
|
|
|
|
|
|
impl MemoryFile
|
|
|
|
|
|
|
|
{
|
|
|
|
|
|
|
|
/// Create a new, empty, memory file with no name and no flags.
|
|
|
|
|
|
|
|
pub fn new() -> io::Result<Self>
|
|
|
|
|
|
|
|
{
|
|
|
|
|
|
|
|
let managed = unsafe {
|
|
|
|
|
|
|
|
match memfd_create(UNNAMED.as_ptr(), DEFAULT_FLAGS) {
|
|
|
|
|
|
|
|
-1 => return Err(io::Error::last_os_error()),
|
|
|
|
|
|
|
|
fd => ManagedFD::take_unchecked(fd),
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
};
|
|
|
|
|
|
|
|
Ok(Self(managed))
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
#[inline]
|
|
|
|
|
|
|
|
pub fn resize(&mut self, value: usize) -> io::Result<()>
|
|
|
|
|
|
|
|
{
|
|
|
|
|
|
|
|
if 0 == unsafe { ftruncate(self.as_raw_fd(), value.try_into().map_err(|e| io::Error::new(io::ErrorKind::InvalidData, e))?) } {
|
|
|
|
|
|
|
|
Ok(())
|
|
|
|
|
|
|
|
} else {
|
|
|
|
|
|
|
|
Err(io::Error::last_os_error())
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
pub fn with_hugetlb(hugetlb: MapHugeFlag) -> io::Result<Self>
|
|
|
|
|
|
|
|
{
|
|
|
|
|
|
|
|
unsafe { create_raw(UNNAMED, DEFAULT_FLAGS | (hugetlb.get_mask() as c_uint)) }
|
|
|
|
|
|
|
|
.map(ManagedFD::take)
|
|
|
|
|
|
|
|
.map(Self)
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
pub fn with_size(size: usize) -> io::Result<Self>
|
|
|
|
|
|
|
|
{
|
|
|
|
|
|
|
|
let mut this = Self(unsafe { create_raw(UNNAMED, DEFAULT_FLAGS) }.map(ManagedFD::take)?);
|
|
|
|
|
|
|
|
this.resize(size)?;
|
|
|
|
|
|
|
|
Ok(this)
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
#[inline]
|
|
|
|
|
|
|
|
pub fn with_size_hugetlb(size: usize, hugetlb: MapHugeFlag) -> io::Result<Self>
|
|
|
|
|
|
|
|
{
|
|
|
|
|
|
|
|
let mut this = Self::with_hugetlb(hugetlb)?;
|
|
|
|
|
|
|
|
this.resize(size)?;
|
|
|
|
|
|
|
|
Ok(this)
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
fn alloc_cstring(string: &str) -> std::ffi::CString
|
|
|
|
|
|
|
|
{
|
|
|
|
|
|
|
|
#[cold]
|
|
|
|
|
|
|
|
fn _contains_nul(mut bytes: Vec<u8>) -> std::ffi::CString
|
|
|
|
|
|
|
|
{
|
|
|
|
|
|
|
|
// SAFETY: We know this will only be called if byte `0` is in `bytes` (**before** the final element)
|
|
|
|
|
|
|
|
let len = unsafe {
|
|
|
|
|
|
|
|
memchr::memchr(0, &bytes[..]).unwrap_unchecked()
|
|
|
|
|
|
|
|
};
|
|
|
|
|
|
|
|
bytes.truncate(len);
|
|
|
|
|
|
|
|
// SAFETY: We have truncated the vector to end on the *first* instance of the `0` byte in `bytes`.
|
|
|
|
|
|
|
|
unsafe {
|
|
|
|
|
|
|
|
std::ffi::CString::from_vec_with_nul_unchecked(bytes)
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
let mut bytes = Vec::with_capacity(string.len()+1);
|
|
|
|
|
|
|
|
bytes.extend_from_slice(string.as_bytes());
|
|
|
|
|
|
|
|
bytes.push(0);
|
|
|
|
|
|
|
|
match std::ffi::CString::from_vec_with_nul(bytes) {
|
|
|
|
|
|
|
|
Ok(v) => v,
|
|
|
|
|
|
|
|
Err(cn) => {
|
|
|
|
|
|
|
|
_contains_nul(cn.into_bytes())
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
impl NamedMemoryFile
|
|
|
|
|
|
|
|
{
|
|
|
|
|
|
|
|
#[inline]
|
|
|
|
|
|
|
|
pub fn new(name: impl AsRef<str>) -> io::Result<Self>
|
|
|
|
|
|
|
|
{
|
|
|
|
|
|
|
|
let name: Box<CStr> = alloc_cstring(name.as_ref()).into();
|
|
|
|
|
|
|
|
let managed = unsafe {
|
|
|
|
|
|
|
|
match memfd_create(name.as_ptr(), DEFAULT_FLAGS) {
|
|
|
|
|
|
|
|
-1 => return Err(io::Error::last_os_error()),
|
|
|
|
|
|
|
|
fd => ManagedFD::take_unchecked(fd),
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
};
|
|
|
|
|
|
|
|
Ok(Self(name, MemoryFile(managed)))
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
pub fn with_hugetlb(name: impl AsRef<str>, hugetlb: MapHugeFlag) -> io::Result<Self>
|
|
|
|
|
|
|
|
{
|
|
|
|
|
|
|
|
let name: Box<CStr> = alloc_cstring(name.as_ref()).into();
|
|
|
|
|
|
|
|
let memfd = MemoryFile(unsafe { create_raw(&name, DEFAULT_FLAGS | (hugetlb.get_mask() as c_uint)) }
|
|
|
|
|
|
|
|
.map(ManagedFD::take)?);
|
|
|
|
|
|
|
|
Ok(Self(name, memfd))
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
pub fn with_size(name: impl AsRef<str>, size: usize) -> io::Result<Self>
|
|
|
|
|
|
|
|
{
|
|
|
|
|
|
|
|
let name: Box<CStr> = alloc_cstring(name.as_ref()).into();
|
|
|
|
|
|
|
|
let mut this = MemoryFile(unsafe { create_raw(&name, DEFAULT_FLAGS) }.map(ManagedFD::take)?);
|
|
|
|
|
|
|
|
this.resize(size)?;
|
|
|
|
|
|
|
|
Ok(Self(name, this))
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
#[inline]
|
|
|
|
|
|
|
|
pub fn with_size_hugetlb(name: impl AsRef<str>, size: usize, hugetlb: MapHugeFlag) -> io::Result<Self>
|
|
|
|
|
|
|
|
{
|
|
|
|
|
|
|
|
let mut this = Self::with_hugetlb(name, hugetlb)?;
|
|
|
|
|
|
|
|
this.resize(size)?;
|
|
|
|
|
|
|
|
Ok(this)
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
impl AsRawFd for MemoryFile
|
|
|
|
impl AsRawFd for MemoryFile
|
|
|
|
{
|
|
|
|
{
|
|
|
|