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.
|
/// Get file system statistics.
|
||||||
fn statfs(&mut self, _req: &Request<'_>, _ino: u64, reply: ReplyStatfs) {
|
fn statfs(&mut self, _req: &Request<'_>, ino: u64, reply: ReplyStatfs) {
|
||||||
reply.statfs(0, 0, 0, 0, 0, 512, 255, 0);
|
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.
|
/// Set an extended attribute.
|
||||||
|
@ -18,7 +18,7 @@ use crate::configuration::StreamingReaderConfig;
|
|||||||
use crate::requester::streaming_reader::StreamingReader;
|
use crate::requester::streaming_reader::StreamingReader;
|
||||||
use olivefs_common::io::read_file;
|
use olivefs_common::io::read_file;
|
||||||
use olivefs_common::messages::{
|
use olivefs_common::messages::{
|
||||||
DataCommand, DataResponse, DirectoryEntry, FileMetadata, OpenMode, VnodeId,
|
DataCommand, DataResponse, DirectoryEntry, FileMetadata, FilesystemStats, OpenMode, VnodeId,
|
||||||
};
|
};
|
||||||
use olivefs_common::networking::{
|
use olivefs_common::networking::{
|
||||||
hello_handshake, read_bare_message, send_bare_message, ALPN_PROTOCOL,
|
hello_handshake, read_bare_message, send_bare_message, ALPN_PROTOCOL,
|
||||||
@ -308,4 +308,8 @@ impl Requester {
|
|||||||
}
|
}
|
||||||
Ok(())
|
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>,
|
atime: Option<SystemTime>,
|
||||||
mtime: 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 {}
|
pub trait DataResponseBase: Serialize + DeserializeOwned + Debug + Clone + 'static {}
|
||||||
|
@ -126,6 +126,16 @@ pub async fn handle_command_stream(
|
|||||||
)
|
)
|
||||||
.await?;
|
.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;
|
||||||
use olivefs_common::error_codes::{EBADFD, EFAULT, ENOENT, ENOSYS};
|
use olivefs_common::error_codes::{EBADFD, EFAULT, ENOENT, ENOSYS};
|
||||||
use olivefs_common::messages::{
|
use olivefs_common::messages::{
|
||||||
DataResponse, DirectoryEntry, FileKind, FileMetadata, OpenMode, VnodeId,
|
DataResponse, DirectoryEntry, FileKind, FileMetadata, FilesystemStats, OpenMode, VnodeId,
|
||||||
};
|
};
|
||||||
use path_absolutize::Absolutize;
|
use path_absolutize::Absolutize;
|
||||||
use slab::Slab;
|
use slab::Slab;
|
||||||
use std::borrow::Borrow;
|
use std::borrow::Borrow;
|
||||||
use std::collections::HashMap;
|
use std::collections::HashMap;
|
||||||
use std::io;
|
use std::ffi::CString;
|
||||||
use std::io::SeekFrom;
|
use std::io::SeekFrom;
|
||||||
|
use std::os::unix::ffi::OsStrExt;
|
||||||
|
use std::{io, mem};
|
||||||
|
|
||||||
use anyhow::{anyhow, bail};
|
use anyhow::{anyhow, bail};
|
||||||
use libc::{ELOOP, O_NOFOLLOW};
|
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 {
|
impl FileAccess {
|
||||||
/// Looks up a Vnode to a Path.
|
/// Looks up a Vnode to a Path.
|
||||||
///
|
///
|
||||||
@ -704,4 +729,13 @@ impl FileAccess {
|
|||||||
|
|
||||||
Ok(DataResponse::Success(metadata))
|
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