start falloc

serial
Avril 3 years ago
parent fd2ad0fdb4
commit 8ee5617d13
Signed by: flanchan
GPG Key ID: 284488987C31F630

1
Cargo.lock generated

@ -19,6 +19,7 @@ checksum = "1482821306169ec4d07f6aca392a4681f66c75c9918aa49641a2595db64053cb"
name = "mapcat"
version = "0.1.0"
dependencies = [
"libc",
"memmap",
"num_cpus",
"rustc_version",

@ -8,7 +8,7 @@ edition = "2018"
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
[dependencies]
mapcat = { path = "." }
libc = "0.2.81"
memmap = "0.7.0"
num_cpus = "1.13.0"
smallvec = "1.5.1"

@ -26,17 +26,18 @@ mod map;
mod job;
mod work;
mod arg;
mod open;
mod consts;
fn work(arg::Operation{output, inputs}: arg::Operation) -> Result<(), Box<dyn std::error::Error>>
{
// todo:
// - create and open output file
let output = open::output(output)?;
// - open and stat all input files in order (`job::create_from_file`).
// - `fallocate` the output file fd to the sum of all input file sizes
// - `mmap` the output file as writable
//
// - spawn the task thread pool

@ -46,6 +46,17 @@ impl MemoryMapMut
{
self.as_ref()
}
pub fn map(file: fs::File) -> io::Result<Self>
{
Ok(Self{
map: unsafe{ MmapMut::map_mut(&file)? },
file,
})
}
#[inline] pub fn len(&self) -> usize
{
self.map.len()
}
pub fn open(from: impl AsRef<Path>) -> io::Result<Self>
{
let file = fs::OpenOptions::new()

@ -0,0 +1,101 @@
use super::*;
use std::{
fs,io,
path::Path,
fmt, error,
};
use fs::File;
use std::borrow::Cow;
use std::os::unix::io::AsRawFd as _;
fn fallocate(file: &mut File, to: usize) -> Result<(), OutputError>
{
let fd = file.as_raw_fd();
unsafe {
if libc::fallocate(fd, 0, 0, to as libc::off_t) == 0 {
Ok(())
} else {
let errno = *libc::__errno_location();
Err(OutputError::Allocate(errno))
}
}
}
/// A reserved output file.
#[derive(Debug)]
pub struct Output(File);
impl Output
{
/// Allocate this reserved output file `to` bytes, the map it and return.
pub fn complete(self, to: usize) -> Result<map::MemoryMapMut, OutputError>
{
let mut file = self.0;
fallocate(&mut file, to)?;
map::MemoryMapMut::map(file)
.map_err(OutputError::Map)
.and_then(|map| if map.len() != to {
Err(OutputError::Size{expected: to, got: map.len()})
} else {
Ok(map)
})
}
}
/// Create a reserved output fd
#[inline] pub fn output(path: impl AsRef<Path>) -> Result<Output, OutputError>
{
fs::OpenOptions::new()
.create(true)
.write(true)
.open(path)
.map(Output)
.map_err(OutputError::Open)
}
fn errno_str<'a>(errno: libc::c_int) -> Cow<'a, str>
{
unsafe {
let ptr = libc::strerror(errno) as *const libc::c_char;
if ptr.is_null() {
return Cow::Borrowed("Unknown");
}
let cstr = std::ffi::CStr::from_ptr(ptr);
cstr.to_string_lossy()
}
}
#[derive(Debug)]
#[non_exhaustive]
pub enum OutputError {
Open(io::Error),
Allocate(libc::c_int),
Map(io::Error),
Size{expected: usize, got: usize},
}
impl error::Error for OutputError
{
fn source(&self) -> Option<&(dyn error::Error + 'static)>
{
match &self {
Self::Open(io)
| Self::Map(io)
=> Some(io),
_ => None,
}
}
}
impl fmt::Display for OutputError
{
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result
{
match self {
Self::Open(io) => write!(f, "Failed to open file: {}", io),
Self::Allocate(errno) => write!(f, "fallocate() failed with error {}: {}", errno, errno_str(*errno)),
Self::Map(io) => write!(f, "mmap() failed: {}", io),
Self::Size{expected, got} => write!(f, "mapped file size mismatch: expected {}, got {}", expected, got),
}
}
}
Loading…
Cancel
Save