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

Implement statfs with synthetic values #871

Closed
wants to merge 1 commit into from
Closed
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
2 changes: 1 addition & 1 deletion mountpoint-s3/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ lazy_static = "1.4.0"
libc = "0.2.126"
linked-hash-map = "0.5.6"
metrics = "0.22.1"
nix = { version = "0.27.1", features = ["user"] }
nix = { version = "0.27.1", features = ["user", "fs"] }
regex = "1.7.1"
serde = { version = "1.0.190", features = ["derive"] }
serde_json = "1.0.95"
Expand Down
51 changes: 51 additions & 0 deletions mountpoint-s3/src/fs.rs
Original file line number Diff line number Diff line change
Expand Up @@ -593,6 +593,43 @@ pub struct DirectoryEntry {
lookup: LookedUp,
}

/// Reply to a `statfs` call
#[derive(Debug)]
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 {
// Derived from Fuser defaults (https://github.com/cberner/fuser/blob/bcff57cc5/src/lib.rs#L695-L698)
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<Client, Prefetcher> S3Filesystem<Client, Prefetcher>
where
Client: ObjectClient + Send + Sync + 'static,
Expand Down Expand Up @@ -1251,6 +1288,20 @@ where
}
Ok(self.superblock.unlink(&self.client, parent_ino, name).await?)
}

pub async fn statfs(&self, _ino: InodeNo) -> Result<StatFs, Error> {
// Let's pick some big numbers...
const FREE_BLOCKS: u64 = u64::MAX / 2;
const FREE_INODES: u64 = u64::MAX / 2;

let reply = StatFs {
free_blocks: FREE_BLOCKS,
available_blocks: FREE_BLOCKS,
free_inodes: FREE_INODES,
..Default::default()
};
Ok(reply)
}
}

#[cfg(test)]
Expand Down
19 changes: 18 additions & 1 deletion mountpoint-s3/src/fuse.rs
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ use crate::prefix::Prefix;
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;
Expand Down Expand Up @@ -388,6 +388,23 @@ where
}
}

#[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),
}
}

// Everything below here is stubs for unsupported functions so we log them correctly

#[instrument(level="warn", skip_all, fields(req=_req.unique(), ino=ino))]
Expand Down
1 change: 1 addition & 0 deletions mountpoint-s3/tests/fuse_tests/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,5 +9,6 @@ mod readdir_test;
mod rmdir_test;
mod semantics_doc_test;
mod setattr_test;
mod statfs_test;
mod unlink_test;
mod write_test;
35 changes: 35 additions & 0 deletions mountpoint-s3/tests/fuse_tests/statfs_test.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
use fuser::BackgroundSession;
use nix::sys::statvfs::statvfs;
use tempfile::TempDir;

use crate::common::fuse::{self, TestClientBox, TestSessionConfig};

fn statfs_test<F>(creator_fn: F, prefix: &str)
where
F: FnOnce(&str, TestSessionConfig) -> (TempDir, BackgroundSession, TestClientBox),
{
let (mount_point, _session, mut test_client) = creator_fn(prefix, Default::default());

// Make sure there's an existing directory
test_client.put_object("dir/hello.txt", b"hello world").unwrap();

let path = mount_point.path().join("dir");

let reply = statvfs(&path).unwrap();

assert_eq!(reply.files(), 0, "inodes/files should not be counted and returned");
assert_eq!(
reply.name_max(),
255,
"name_max should return 255, matching Fuser default",
);
assert!(
reply.blocks_available() > 0,
"blocks available should be non-zero, even though we can't provide a real number",
);
}

#[test]
fn statfs_test_mock() {
statfs_test(fuse::mock_session::new, "statfs_test_mock");
}