It seems creating HUGETLB memory files either just doesn"t work or changes their behaviour so that any (or at least, small arbitrary) writing or fallocate()ing to them fails... Read up on MFD_HUGETLB more then re-do a test like `memfd_create_wrapper()` to find out why... and if it depends on the MAP_HUGE_ mask, and if so, find one that works... (We know when masks are invalid, since the error message is different. The masks collected via `get_masks()` *are* valid for this system, they just prevent the fd from being any way useful.)

Fortune for collect's current commit: Blessing − 吉
hugetlb
Avril 2 years ago
parent bdfd0a6268
commit 872ea74421
Signed by: flanchan
GPG Key ID: 284488987C31F630

@ -279,8 +279,24 @@ impl RawFile
opt.borrow().open(path).map(Into::into)
}
/// Allocates `size` bytes for this file.
///
/// # Note
/// This does not *extend* the file's capacity, it is instead similar to `fs::File::set_len()`.
#[cfg_attr(feature="logging", instrument(err))]
pub fn allocate_size(&mut self, size: u64) -> io::Result<()>
{
use libc::{ fallocate, off_t};
if_trace!(trace!("attempting fallocate({}, 0, 0, {size}) (max offset: {})", self.0.get(), off_t::MAX));
match unsafe { fallocate(self.0.get(), 0, 0, if cfg!(debug_assertions) {
size.try_into().map_err(|_| io::Error::new(io::ErrorKind::InvalidInput, "Offset larger than max offset size"))?
} else { size as off_t }) } { //XXX is this biteise AND check needed? fallocate() should already error if the size is negative with these parameters, no?
-1 => Err(io::Error::last_os_error()),
_ => Ok(())
}
}
/// Open a new in-memory (W+R) file with an optional name and a fixed size.
#[cfg_attr(feature="logging", instrument(err))]
pub fn open_mem(name: Option<&str>, len: usize) -> Result<Self, error::MemfileError>
{

@ -187,8 +187,9 @@ impl Mask {
/// Create a function that acts as `memfd_create()` with *only* this mask applied to it.
///
/// The `flags` argument is erased. To pass arbitrary flags to `memfd_create()`, use `memfd_create_wrapper_flags()`
pub const fn memfd_create_wrapper(self) -> impl Fn (*const libc::c_char) -> c_int
/// The `flags` argument is erased. To pass arbitrary flags to `memfd_create()`, use `memfd_create_raw_wrapper_flags()`
#[inline(always)]
pub const fn memfd_create_raw_wrapper(self) -> impl Fn (*const libc::c_char) -> c_int
{
use libc::memfd_create;
move |path| {
@ -199,7 +200,8 @@ impl Mask {
}
/// Create a function that acts as `memfd_create()` with this mask applied to it.
pub const fn memfd_create_wrapper_flags(self) -> impl Fn (*const libc::c_char, c_uint) -> c_int
#[inline(always)]
pub const fn memfd_create_raw_wrapper_flags(self) -> impl Fn (*const libc::c_char, c_uint) -> c_int
{
use libc::memfd_create;
move |path, flag| {
@ -208,6 +210,38 @@ impl Mask {
}
}
}
/// Create a function that acts as safe `memfd_create()` wrapper with this mask applied to it.
///
/// The `flags` argument is erased. To pass arbitrary flags to `memfd_create()`, use `memfd_create_wrapper_flags()`
/// # Returns
/// A RAII-guarded wrapper over the memory-file, or the `errno` in an `Err(io::Error)` if the operation failed.
#[inline]
pub const fn memfd_create_wrapper(self) -> impl Fn(*const libc::c_char) -> io::Result<super::RawFile>
{
let memfd_create = self.memfd_create_raw_wrapper();
move |path| {
match memfd_create(path) {
-1 => Err(io::Error::last_os_error()),
fd => Ok(super::RawFile::take_ownership_of_unchecked(fd))
}
}
}
/// Create a function that acts as safe `memfd_create()` wrapper with this mask applied to it.
/// # Returns
/// A RAII-guarded wrapper over the memory-file, or the `errno` in an `Err(io::Error)` if the operation failed.
#[inline]
pub const fn memfd_create_wrapper_flags(self) -> impl Fn(*const libc::c_char, c_uint) -> io::Result<super::RawFile>
{
let memfd_create = self.memfd_create_raw_wrapper_flags();
move |path, flags| {
match memfd_create(path, flags) {
-1 => Err(io::Error::last_os_error()),
fd => Ok(super::RawFile::take_ownership_of_unchecked(fd))
}
}
}
}
impl TryFrom<usize> for Mask
@ -504,5 +538,46 @@ mod tests
(masks > 0).then(|| drop(println!("Found {masks} masks on system"))).ok_or(eyre!("Found no masks"))
}
//#[test] TODO: XXX: AAAAA: system does not support huge-page memfd_create() allocations!?!?!?!?
// TODO: Or am I missing something here? Does it pre-allocate? What is this?
fn memfd_create_wrapper() -> eyre::Result<()>
{
//crate::init()?;
use std::ffi::CString;
let name = CString::new(Vec::from_iter(b"memfd_create_wrapper() test".into_iter().copied())).unwrap();
let mask = super::get_masks()?.next().ok_or(eyre!("No masks found"))?.wrap_err("Failed to extract mask")?;
eprintln!("Using mask: {mask:x} ({mask:b})");
let create = mask.memfd_create_wrapper_flags();
let buf = {
let mut buf = vec![0; name.as_bytes_with_nul().len()];
println!("Allocated {} bytes for buffer", buf.len());
let mut file: fs::File = {
let mut file = unsafe {super::RawFile::from_raw_fd( libc::memfd_create(name.as_ptr(), super::MEMFD_CREATE_FLAGS | mask.mask()) ) };//.wrap_err(eyre!("Failed to create file"))?;
println!("Created file {file:?}");
file.allocate_size(buf.len() as u64).wrap_err(eyre!("fallocate() failed"))?;
println!("Set file-size to {}", buf.len());
file
}.into();
use std::io::{Read, Write, Seek};
println!("Writing {} bytes {:?}...", name.as_bytes_with_nul().len(), name.as_bytes_with_nul());
file.write_all(name.as_bytes_with_nul()).wrap_err(eyre!("Writing failed"))?;
println!("Seeking back to 0...");
file.seek(std::io::SeekFrom::Start(0)).wrap_err(eyre!("Seeking failed"))?;
println!("Reading {} bytes...", buf.len());
file.read_exact(&mut buf[..]).wrap_err(eyre!("Reading failed"))?;
println!("Read {} bytes into: {:?}", buf.len(), buf);
buf
};
assert_eq!(CString::from_vec_with_nul(buf).expect("Invalid contents read"), name);
Ok(())
}
}
}

Loading…
Cancel
Save