Add support for statfs()
This commit is contained in:
parent
28971fb424
commit
8a4bf510ae
@ -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.
|
||||
|
@ -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
|
||||
}
|
||||
}
|
||||
|
@ -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 {}
|
||||
|
@ -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?;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -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)
|
||||
}
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user