Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add support for fallocate and statx #214

Merged
merged 4 commits into from
Jan 19, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
52 changes: 52 additions & 0 deletions src/fs/file.rs
Original file line number Diff line number Diff line change
Expand Up @@ -772,6 +772,58 @@ impl File {
Op::datasync(&self.fd)?.await
}

/// Manipulate the allocated disk space of the file.
///
/// The manipulated range starts at the `offset` and continues for `len` bytes.
///
/// The specific manipulation to the allocated disk space are specified by
/// the `flags`, to understand what are the possible values here check
/// the `fallocate(2)` man page.
///
/// # Examples
///
/// ```no_run
/// use tokio_uring::fs::File;
///
/// fn main() -> Result<(), Box<dyn std::error::Error>> {
/// tokio_uring::start(async {
/// let f = File::create("foo.txt").await?;
///
/// // Allocate a 1024 byte file setting all the bytes to zero
/// f.fallocate(0, 1024, libc::FALLOC_FL_ZERO_RANGE).await?;
///
/// // Close the file
/// f.close().await?;
/// Ok(())
/// })
/// }
pub async fn fallocate(&self, offset: u64, len: u64, flags: i32) -> io::Result<()> {
Op::fallocate(&self.fd, offset, len, flags)?.await
}

/// Metadata information about a file.
///
/// # Examples
///
/// ```no_run
/// use tokio_uring::fs::File;
///
/// fn main() -> Result<(), Box<dyn std::error::Error>> {
/// tokio_uring::start(async {
/// let f = File::create("foo.txt").await?;
///
/// // Fetch file metadata
/// let statx = f.statx().await?;
///
/// // Close the file
/// f.close().await?;
/// Ok(())
/// })
/// }
pub async fn statx(&self) -> io::Result<libc::statx> {
Op::statx(&self.fd)?.await
}

/// Closes the file.
///
/// The method completes once the close operation has completed,
Expand Down
44 changes: 44 additions & 0 deletions src/io/fallocate.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
use std::io;

use io_uring::{opcode, types};

use crate::{
io::SharedFd,
runtime::{
driver::op::{Completable, CqeResult, Op},
CONTEXT,
},
};

pub(crate) struct Fallocate {
fd: SharedFd,
}

impl Op<Fallocate> {
pub(crate) fn fallocate(
fd: &SharedFd,
offset: u64,
len: u64,
flags: i32,
) -> io::Result<Op<Fallocate>> {
CONTEXT.with(|x| {
x.handle().expect("not in a runtime context").submit_op(
Fallocate { fd: fd.clone() },
|fallocate| {
opcode::Fallocate64::new(types::Fd(fallocate.fd.raw_fd()), len as _)
.offset64(offset as _)
.mode(flags)
.build()
},
)
})
}
}

impl Completable for Fallocate {
type Output = io::Result<()>;

fn complete(self, cqe: CqeResult) -> Self::Output {
cqe.result.map(|_| ())
}
}
4 changes: 4 additions & 0 deletions src/io/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,8 @@ pub(crate) use close::Close;

mod connect;

mod fallocate;

mod fsync;

mod mkdir_at;
Expand Down Expand Up @@ -34,6 +36,8 @@ pub(crate) use shared_fd::SharedFd;
mod socket;
pub(crate) use socket::Socket;

mod statx;

mod unlink_at;

mod util;
Expand Down
48 changes: 48 additions & 0 deletions src/io/statx.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
use std::{ffi::CStr, io};

use io_uring::{opcode, types};

use crate::runtime::{
driver::op::{Completable, CqeResult, Op},
CONTEXT,
};

use super::SharedFd;

pub(crate) struct Statx {
fd: SharedFd,
statx: Box<libc::statx>,
}

impl Op<Statx> {
pub(crate) fn statx(fd: &SharedFd) -> io::Result<Op<Statx>> {
CONTEXT.with(|x| {
let empty_path = CStr::from_bytes_with_nul(b"\0").unwrap();
x.handle().expect("not in a runtime context").submit_op(
Statx {
fd: fd.clone(),
statx: Box::new(unsafe { std::mem::zeroed() }),
},
|statx| {
opcode::Statx::new(
types::Fd(statx.fd.raw_fd()),
empty_path.as_ptr(),
&mut *statx.statx as *mut libc::statx as *mut types::statx,
)
.flags(libc::AT_EMPTY_PATH)
.mask(libc::STATX_ALL)
.build()
},
)
})
}
}

impl Completable for Statx {
type Output = io::Result<libc::statx>;

fn complete(self, cqe: CqeResult) -> Self::Output {
cqe.result?;
Ok(*self.statx)
}
}
34 changes: 34 additions & 0 deletions tests/fs_file.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,8 @@ use std::{
os::unix::io::{AsRawFd, FromRawFd, RawFd},
};

use libc;

use tempfile::NamedTempFile;

use tokio_uring::buf::fixed::FixedBufRegistry;
Expand Down Expand Up @@ -281,6 +283,38 @@ fn write_fixed() {
});
}

#[test]
fn basic_fallocate() {
tokio_uring::start(async {
let tempfile = tempfile();

let file = File::create(tempfile.path()).await.unwrap();

file.fallocate(0, 1024, libc::FALLOC_FL_ZERO_RANGE)
.await
.unwrap();
file.sync_all().await.unwrap();

let statx = file.statx().await.unwrap();
let size = statx.stx_size;
assert_eq!(size, 1024);

// using the FALLOC_FL_KEEP_SIZE flag causes the file metadata to reflect the previous size
file.fallocate(
0,
2048,
libc::FALLOC_FL_ZERO_RANGE | libc::FALLOC_FL_KEEP_SIZE,
)
.await
.unwrap();
file.sync_all().await.unwrap();

let statx = file.statx().await.unwrap();
let size = statx.stx_size;
assert_eq!(size, 1024);
});
}

fn tempfile() -> NamedTempFile {
NamedTempFile::new().unwrap()
}
Expand Down