Add support for statfs()

This commit is contained in:
Olivier 'reivilibre' 2022-01-27 06:41:10 +00:00
parent 28971fb424
commit 8a4bf510ae
5 changed files with 99 additions and 5 deletions

View File

@ -796,8 +796,39 @@ impl Filesystem for OliveFilesystem {
}
/// Get file system statistics.
fn statfs(&mut self, _req: &Request<'_>, _ino: u64, reply: ReplyStatfs) {
reply.statfs(0, 0, 0, 0, 0, 512, 255, 0);
fn statfs(&mut self, _req: &Request<'_>, ino: u64, reply: ReplyStatfs) {
let requester = self.requester.clone();
self.spawn_with_error_handler(
async move {
let vnode = VnodeId(
ino.try_into()
.context("Converting u64 inode to u32 VnodeId.")?,
);
match requester.statfs(vnode).await? {
DataResponse::Success(stats) => {
reply.statfs(
stats.blocks,
stats.bfree,
stats.bavail,
stats.files,
stats.ffree,
stats.bsize,
stats.namelen,
stats.frsize,
);
}
DataResponse::Error { code, message } => {
warn!("statfs(ino: {:#x?}) failed: {:?}", ino, message);
reply.error(code as c_int);
}
}
Ok(())
},
"statfs",
);
}
/// Set an extended attribute.

View File

@ -18,7 +18,7 @@ use crate::configuration::StreamingReaderConfig;
use crate::requester::streaming_reader::StreamingReader;
use olivefs_common::io::read_file;
use olivefs_common::messages::{
DataCommand, DataResponse, DirectoryEntry, FileMetadata, OpenMode, VnodeId,
DataCommand, DataResponse, DirectoryEntry, FileMetadata, FilesystemStats, OpenMode, VnodeId,
};
use olivefs_common::networking::{
hello_handshake, read_bare_message, send_bare_message, ALPN_PROTOCOL,
@ -308,4 +308,8 @@ impl Requester {
}
Ok(())
}
pub async fn statfs(&self, vnode: VnodeId) -> anyhow::Result<DataResponse<FilesystemStats>> {
self.internal.command(&DataCommand::StatFs { vnode }).await
}
}

View File

@ -88,6 +88,21 @@ pub enum DataCommand {
atime: Option<SystemTime>,
mtime: Option<SystemTime>,
},
StatFs {
vnode: VnodeId,
},
}
#[derive(Serialize, Deserialize, Debug, Clone)]
pub struct FilesystemStats {
pub blocks: u64,
pub bfree: u64,
pub bavail: u64,
pub files: u64,
pub ffree: u64,
pub bsize: u32,
pub namelen: u32,
pub frsize: u32,
}
pub trait DataResponseBase: Serialize + DeserializeOwned + Debug + Clone + 'static {}

View File

@ -126,6 +126,16 @@ pub async fn handle_command_stream(
)
.await?;
}
DataCommand::StatFs { vnode } => {
send_bare_message(
&mut tx,
&file_access
.statfs(vnode)
.await
.unwrap_or_else(error_to_response),
)
.await?;
}
}
}

View File

@ -1,14 +1,16 @@
use olivefs_common::error_codes;
use olivefs_common::error_codes::{EBADFD, EFAULT, ENOENT, ENOSYS};
use olivefs_common::messages::{
DataResponse, DirectoryEntry, FileKind, FileMetadata, OpenMode, VnodeId,
DataResponse, DirectoryEntry, FileKind, FileMetadata, FilesystemStats, OpenMode, VnodeId,
};
use path_absolutize::Absolutize;
use slab::Slab;
use std::borrow::Borrow;
use std::collections::HashMap;
use std::io;
use std::ffi::CString;
use std::io::SeekFrom;
use std::os::unix::ffi::OsStrExt;
use std::{io, mem};
use anyhow::{anyhow, bail};
use libc::{ELOOP, O_NOFOLLOW};
@ -108,6 +110,29 @@ pub fn error_to_response<A>(error: anyhow::Error) -> DataResponse<A> {
}
}
fn statfs_wrapper(path: &Path) -> anyhow::Result<FilesystemStats> {
let path_c = CString::new(path.as_os_str().as_bytes()).unwrap();
let stats = unsafe {
let mut stats: libc::statfs = mem::zeroed();
match libc::statfs(path_c.as_ptr(), &mut stats) {
0 => Ok(stats),
other => Err(io::Error::from_raw_os_error(other)),
}
}?;
Ok(FilesystemStats {
blocks: stats.f_blocks,
bfree: stats.f_bfree,
bavail: stats.f_bavail,
files: stats.f_files,
ffree: stats.f_ffree,
bsize: stats.f_bsize as u32,
namelen: stats.f_namelen as u32,
frsize: stats.f_frsize as u32,
})
}
impl FileAccess {
/// Looks up a Vnode to a Path.
///
@ -704,4 +729,13 @@ impl FileAccess {
Ok(DataResponse::Success(metadata))
}
pub async fn statfs(&self, vnode: VnodeId) -> anyhow::Result<DataResponse<FilesystemStats>> {
// TODO switch to the easier ones and then handle I/O errors in the callsite
let path = self
.resolve_vnode_including_follow_symlinks_safely_best_effort(vnode)
.await?;
statfs_wrapper(&path).map(DataResponse::Success)
}
}