Use POSIX statvfs, since statfs is not designed to be portable (#1495)

This commit is contained in:
Jan S
2026-01-14 09:03:32 +01:00
committed by GitHub
parent 27480f7625
commit 68c5c0b834
4 changed files with 28 additions and 68 deletions

View File

@@ -16,6 +16,7 @@
mod linux; mod linux;
#[cfg(all(unix, not(target_os = "linux")))] #[cfg(all(unix, not(target_os = "linux")))]
mod unix; mod unix;
#[cfg(target_os = "windows")] #[cfg(target_os = "windows")]
mod windows; mod windows;

View File

@@ -13,56 +13,19 @@
// limitations under the License. // limitations under the License.
use super::{DiskInfo, IOStats}; use super::{DiskInfo, IOStats};
use nix::sys::statfs::Statfs; use nix::sys::{stat::stat, statvfs::statvfs};
use nix::sys::{stat::stat, statfs::statfs};
use std::io::Error; use std::io::Error;
use std::path::Path; use std::path::Path;
// FreeBSD and OpenBSD return a signed integer for blocks_available.
// Cast to an unsigned integer to use with DiskInfo.
#[cfg(any(target_os = "freebsd", target_os = "openbsd"))]
fn blocks_available(stat: &Statfs) -> u64 {
match stat.blocks_available().try_into() {
Ok(bavail) => bavail,
Err(e) => {
tracing::warn!("blocks_available returned a negative value: Using 0 as fallback. {}", e);
0
}
}
}
// FreeBSD returns a signed integer for files_free. Cast to an unsigned integer
// to use with DiskInfo
#[cfg(target_os = "freebsd")]
fn files_free(stat: &Statfs) -> u64 {
match stat.files_free().try_into() {
Ok(files_free) => files_free,
Err(e) => {
tracing::warn!("files_free returned a negative value: Using 0 as fallback. {}", e);
0
}
}
}
#[cfg(not(target_os = "freebsd"))]
fn files_free(stat: &Statfs) -> u64 {
stat.files_free()
}
#[cfg(not(any(target_os = "freebsd", target_os = "openbsd")))]
fn blocks_available(stat: &Statfs) -> u64 {
stat.blocks_available()
}
/// Returns total and free bytes available in a directory, e.g. `/`. /// Returns total and free bytes available in a directory, e.g. `/`.
pub fn get_info(p: impl AsRef<Path>) -> std::io::Result<DiskInfo> { pub fn get_info(p: impl AsRef<Path>) -> std::io::Result<DiskInfo> {
let path_display = p.as_ref().display(); let path_display = p.as_ref().display();
let stat = statfs(p.as_ref())?; let stat = statvfs(p.as_ref())?;
let bsize = stat.block_size() as u64; let bsize = stat.block_size();
let bfree = stat.blocks_free(); let bfree = stat.blocks_free() as u64;
let bavail = blocks_available(&stat); let bavail = stat.blocks_available() as u64;
let blocks = stat.blocks(); let blocks = stat.blocks() as u64;
let reserved = match bfree.checked_sub(bavail) { let reserved = match bfree.checked_sub(bavail) {
Some(reserved) => reserved, Some(reserved) => reserved,
@@ -96,9 +59,9 @@ pub fn get_info(p: impl AsRef<Path>) -> std::io::Result<DiskInfo> {
total, total,
free, free,
used, used,
files: stat.files(), files: stat.files() as u64,
ffree: files_free(&stat), ffree: stat.files_free() as u64,
fstype: stat.filesystem_type_name().to_string(), // Statvfs does not provide a way to return the filesystem as name.
..Default::default() ..Default::default()
}) })
} }

View File

@@ -15,7 +15,7 @@
use rustfs_config::VERSION; use rustfs_config::VERSION;
use std::env; use std::env;
use std::fmt; use std::fmt;
#[cfg(not(any(target_os = "openbsd", target_os = "freebsd")))] #[cfg(not(any(target_os = "openbsd", target_os = "freebsd", target_os = "netbsd")))]
use sysinfo::System; use sysinfo::System;
/// Business Type Enumeration /// Business Type Enumeration

View File

@@ -30,9 +30,6 @@ use hyper_util::{
}; };
use metrics::{counter, histogram}; use metrics::{counter, histogram};
use rustfs_common::GlobalReadiness; use rustfs_common::GlobalReadiness;
#[cfg(not(target_os = "openbsd"))]
use rustfs_config::{MI_B, RUSTFS_TLS_CERT, RUSTFS_TLS_KEY};
#[cfg(target_os = "openbsd")]
use rustfs_config::{RUSTFS_TLS_CERT, RUSTFS_TLS_KEY}; use rustfs_config::{RUSTFS_TLS_CERT, RUSTFS_TLS_KEY};
use rustfs_ecstore::rpc::{TONIC_RPC_PREFIX, verify_rpc_signature}; use rustfs_ecstore::rpc::{TONIC_RPC_PREFIX, verify_rpc_signature};
use rustfs_protos::proto_gen::node_service::node_service_server::NodeServiceServer; use rustfs_protos::proto_gen::node_service::node_service_server::NodeServiceServer;
@@ -379,11 +376,14 @@ pub async fn start_http_server(
// Enable TCP Keepalive to detect dead clients (e.g. power loss) // Enable TCP Keepalive to detect dead clients (e.g. power loss)
// Idle: 10s, Interval: 5s, Retries: 3 // Idle: 10s, Interval: 5s, Retries: 3
let mut ka = TcpKeepalive::new().with_time(Duration::from_secs(10)); #[cfg(target_os = "openbsd")]
let ka = TcpKeepalive::new().with_time(Duration::from_secs(10));
#[cfg(not(target_os = "openbsd"))] #[cfg(not(target_os = "openbsd"))]
{ let ka = TcpKeepalive::new()
ka = ka.with_interval(Duration::from_secs(5)).with_retries(3); .with_time(Duration::from_secs(10))
} .with_interval(Duration::from_secs(5))
.with_retries(3);
if let Err(err) = socket_ref.set_tcp_keepalive(&ka) { if let Err(err) = socket_ref.set_tcp_keepalive(&ka) {
warn!(?err, "Failed to set TCP_KEEPALIVE"); warn!(?err, "Failed to set TCP_KEEPALIVE");
@@ -392,12 +392,13 @@ pub async fn start_http_server(
if let Err(err) = socket_ref.set_tcp_nodelay(true) { if let Err(err) = socket_ref.set_tcp_nodelay(true) {
warn!(?err, "Failed to set TCP_NODELAY"); warn!(?err, "Failed to set TCP_NODELAY");
} }
#[cfg(not(any(target_os = "openbsd")))]
if let Err(err) = socket_ref.set_recv_buffer_size(4 * MI_B) { #[cfg(not(target_os = "openbsd"))]
if let Err(err) = socket_ref.set_recv_buffer_size(4 * rustfs_config::MI_B) {
warn!(?err, "Failed to set set_recv_buffer_size"); warn!(?err, "Failed to set set_recv_buffer_size");
} }
#[cfg(not(any(target_os = "openbsd")))] #[cfg(not(target_os = "openbsd"))]
if let Err(err) = socket_ref.set_send_buffer_size(4 * MI_B) { if let Err(err) = socket_ref.set_send_buffer_size(4 * rustfs_config::MI_B) {
warn!(?err, "Failed to set set_send_buffer_size"); warn!(?err, "Failed to set set_send_buffer_size");
} }
@@ -752,14 +753,15 @@ fn get_listen_backlog() -> i32 {
} }
// For macOS and BSD variants use the syscall way of getting the connection queue length. // For macOS and BSD variants use the syscall way of getting the connection queue length.
#[cfg(any(target_os = "macos", target_os = "freebsd", target_os = "netbsd", target_os = "openbsd"))] // NetBSD has no somaxconn-like kernel state.
#[cfg(any(target_os = "macos", target_os = "freebsd", target_os = "openbsd"))]
#[allow(unsafe_code)] #[allow(unsafe_code)]
fn get_listen_backlog() -> i32 { fn get_listen_backlog() -> i32 {
const DEFAULT_BACKLOG: i32 = 1024; const DEFAULT_BACKLOG: i32 = 1024;
#[cfg(target_os = "openbsd")] #[cfg(target_os = "openbsd")]
let mut name = [libc::CTL_KERN, libc::KERN_SOMAXCONN]; let mut name = [libc::CTL_KERN, libc::KERN_SOMAXCONN];
#[cfg(any(target_os = "netbsd", target_os = "macos", target_os = "freebsd"))] #[cfg(any(target_os = "macos", target_os = "freebsd"))]
let mut name = [libc::CTL_KERN, libc::KERN_IPC, libc::KIPC_SOMAXCONN]; let mut name = [libc::CTL_KERN, libc::KERN_IPC, libc::KIPC_SOMAXCONN];
let mut buf = [0; 1]; let mut buf = [0; 1];
let mut buf_len = size_of_val(&buf); let mut buf_len = size_of_val(&buf);
@@ -781,14 +783,8 @@ fn get_listen_backlog() -> i32 {
buf[0] buf[0]
} }
// Fallback for Windows and other operating systems // Fallback for Windows, NetBSD and other operating systems.
#[cfg(not(any( #[cfg(not(any(target_os = "linux", target_os = "macos", target_os = "freebsd", target_os = "openbsd")))]
target_os = "linux",
target_os = "macos",
target_os = "freebsd",
target_os = "netbsd",
target_os = "openbsd"
)))]
fn get_listen_backlog() -> i32 { fn get_listen_backlog() -> i32 {
const DEFAULT_BACKLOG: i32 = 1024; const DEFAULT_BACKLOG: i32 = 1024;
DEFAULT_BACKLOG DEFAULT_BACKLOG