From 89df80a2893e3585a6a09a30598aa6aea48033fe Mon Sep 17 00:00:00 2001 From: Christian Hagemeier Date: Thu, 7 Nov 2024 16:24:39 +0000 Subject: [PATCH] Add statfs implementation Signed-off-by: Christian Hagemeier --- mountpoint-s3/src/fs.rs | 54 +++++++++++++++++++++++++++++++++++++++ mountpoint-s3/src/fuse.rs | 19 +++++++++++++- 2 files changed, 72 insertions(+), 1 deletion(-) diff --git a/mountpoint-s3/src/fs.rs b/mountpoint-s3/src/fs.rs index 75efcf862..834772339 100644 --- a/mountpoint-s3/src/fs.rs +++ b/mountpoint-s3/src/fs.rs @@ -107,6 +107,42 @@ pub struct DirectoryEntry { lookup: LookedUp, } +#[derive(Debug)] +/// Reply to a 'statfs' call +pub struct StatFs { + /// Total number of blocks + pub total_blocks: u64, + /// Number of free blocks + pub free_blocks: u64, + /// Number of free blocks available to unprivileged user + pub available_blocks: u64, + /// Number of inodes in file system + pub total_inodes: u64, + /// Available inodes + pub free_inodes: u64, + /// Optimal transfer block size + pub block_size: u32, + /// Maximum name length + pub maximum_name_length: u32, + /// Fragement size + pub fragment_size: u32, +} + +impl Default for StatFs { + fn default() -> Self { + Self { + total_blocks: 0, + free_blocks: 0, + available_blocks: 0, + total_inodes: 0, + free_inodes: 0, + block_size: 512, + maximum_name_length: 255, + fragment_size: 0, + } + } +} + impl S3Filesystem where Client: ObjectClient + Clone + Send + Sync + 'static, @@ -789,6 +825,24 @@ where } Ok(self.superblock.unlink(&self.client, parent_ino, name).await?) } + + pub async fn statfs(&self, _ino: InodeNo) -> Result { + const FREE_BLOCKS: u64 = u64::MAX / 2; + const FREE_INODES: u64 = u64::MAX / 2; + // According to https://docs.aws.amazon.com/AmazonS3/latest/userguide/object-keys.html any S3 object name can be at most + // 1024 bytes. + const MAX_NAME_LENGTH: u32 = 1024; + + let reply = StatFs { + free_blocks: FREE_BLOCKS, + available_blocks: FREE_BLOCKS, + free_inodes: FREE_INODES, + maximum_name_length: MAX_NAME_LENGTH, + total_blocks: FREE_BLOCKS, + ..Default::default() + }; + Ok(reply) + } } #[cfg(test)] diff --git a/mountpoint-s3/src/fuse.rs b/mountpoint-s3/src/fuse.rs index f89d04d89..3cf539e12 100644 --- a/mountpoint-s3/src/fuse.rs +++ b/mountpoint-s3/src/fuse.rs @@ -14,7 +14,7 @@ use crate::prefetch::Prefetch; use fuser::ReplyXTimes; use fuser::{ Filesystem, KernelConfig, ReplyAttr, ReplyBmap, ReplyCreate, ReplyData, ReplyEmpty, ReplyEntry, ReplyIoctl, - ReplyLock, ReplyLseek, ReplyOpen, ReplyWrite, ReplyXattr, Request, TimeOrNow, + ReplyLock, ReplyLseek, ReplyOpen, ReplyStatfs, ReplyWrite, ReplyXattr, Request, TimeOrNow, }; pub mod session; @@ -580,4 +580,21 @@ where fn getxtimes(&self, _req: &Request<'_>, ino: u64, reply: ReplyXTimes) { fuse_unsupported!("getxtimes", reply); } + + #[instrument(level="warn", skip_all, fields(req=_req.unique(), ino=ino))] + fn statfs(&self, _req: &Request<'_>, ino: u64, reply: ReplyStatfs) { + match block_on(self.fs.statfs(ino).in_current_span()) { + Ok(statfs) => reply.statfs( + statfs.total_blocks, + statfs.free_blocks, + statfs.available_blocks, + statfs.total_inodes, + statfs.free_inodes, + statfs.block_size, + statfs.maximum_name_length, + statfs.fragment_size, + ), + Err(e) => fuse_error!("statfs", reply, e), + } + } }