Skip to content

Commit

Permalink
fix(mmap): pre-allocate temp file before mmapping
Browse files Browse the repository at this point in the history
This avoids SIGBUS on memory write in case the temp file is sparse.
Implemented for cfg(unix) only; cfg(windows) unchanged.
  • Loading branch information
komar007 committed May 18, 2023
1 parent 58de0b2 commit 6ec7811
Show file tree
Hide file tree
Showing 2 changed files with 31 additions and 9 deletions.
1 change: 1 addition & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ digest = "0.10.6"
either = "1.6.1"
futures = "0.3.17"
hex = "0.4.3"
libc = "0.2.144"
memmap2 = { version = "0.5.8", optional = true }
miette = "5.7.0"
reflink = "0.1.3"
Expand Down
39 changes: 30 additions & 9 deletions src/content/write.rs
Original file line number Diff line number Diff line change
Expand Up @@ -413,21 +413,42 @@ impl AsyncWriter {
#[cfg(feature = "mmap")]
fn make_mmap(tmpfile: &mut NamedTempFile, size: Option<usize>) -> Result<Option<MmapMut>> {
if let Some(size @ 0..=MAX_MMAP_SIZE) = size {
tmpfile
.as_file_mut()
.set_len(size as u64)
.with_context(|| {
format!(
"Failed to configure file length for temp file at {}",
tmpfile.path().display()
)
})?;
allocate_file(tmpfile.as_file(), size).with_context(|| {
format!(
"Failed to configure file length for temp file at {}",
tmpfile.path().display()
)
})?;
Ok(unsafe { MmapMut::map_mut(tmpfile.as_file()).ok() })
} else {
Ok(None)
}
}

#[cfg(unix)]
fn allocate_file(file: &std::fs::File, size: usize) -> std::io::Result<()> {
use std::io::{Error, ErrorKind};
use std::os::fd::AsRawFd;

let fd = file.as_raw_fd();
match unsafe { libc::posix_fallocate64(fd, 0, size as i64) } {
0 => Ok(()),
libc::ENOSPC => Err(Error::new(
ErrorKind::Other, // ErrorKind::StorageFull is unstable
"cannot allocate file: no space left on device",
)),
err => Err(Error::new(
ErrorKind::Other,
format!("posix_fallocate64 failed with code {}", err),
)),
}
}

#[cfg(windows)]
fn allocate_file(file: &std::fs::File, size: usize) -> std::io::Result<()> {
file.set_len(size as u64)
}

#[cfg(not(feature = "mmap"))]
fn make_mmap(_: &mut NamedTempFile, _: Option<usize>) -> Result<Option<MmapMut>> {
Ok(None)
Expand Down

0 comments on commit 6ec7811

Please sign in to comment.