2024-01-03 03:22:36 +00:00
|
|
|
// SPDX-License-Identifier: MPL-2.0
|
|
|
|
|
|
2025-11-17 15:38:28 +00:00
|
|
|
use core::sync::atomic::{AtomicI64, AtomicU32, Ordering};
|
2025-10-31 08:42:31 +00:00
|
|
|
|
|
|
|
|
use atomic_integer_wrapper::define_atomic_version_of_integer_like_type;
|
|
|
|
|
|
2022-12-30 03:22:04 +00:00
|
|
|
use super::Inode;
|
|
|
|
|
use crate::prelude::*;
|
|
|
|
|
|
|
|
|
|
#[derive(Debug, Clone)]
|
|
|
|
|
pub struct SuperBlock {
|
2023-07-03 05:29:02 +00:00
|
|
|
pub magic: u64,
|
2022-12-30 03:22:04 +00:00
|
|
|
pub bsize: usize,
|
|
|
|
|
pub blocks: usize,
|
|
|
|
|
pub bfree: usize,
|
|
|
|
|
pub bavail: usize,
|
|
|
|
|
pub files: usize,
|
|
|
|
|
pub ffree: usize,
|
2023-07-03 05:29:02 +00:00
|
|
|
pub fsid: u64,
|
2022-12-30 03:22:04 +00:00
|
|
|
pub namelen: usize,
|
|
|
|
|
pub frsize: usize,
|
2023-07-03 05:29:02 +00:00
|
|
|
pub flags: u64,
|
2022-12-30 03:22:04 +00:00
|
|
|
}
|
|
|
|
|
|
2023-01-05 08:55:58 +00:00
|
|
|
impl SuperBlock {
|
2023-07-03 05:29:02 +00:00
|
|
|
pub fn new(magic: u64, block_size: usize, name_max_len: usize) -> Self {
|
2023-01-05 08:55:58 +00:00
|
|
|
Self {
|
|
|
|
|
magic,
|
|
|
|
|
bsize: block_size,
|
|
|
|
|
blocks: 0,
|
|
|
|
|
bfree: 0,
|
|
|
|
|
bavail: 0,
|
|
|
|
|
files: 0,
|
|
|
|
|
ffree: 0,
|
|
|
|
|
fsid: 0,
|
2023-07-03 05:29:02 +00:00
|
|
|
namelen: name_max_len,
|
2023-01-05 08:55:58 +00:00
|
|
|
frsize: block_size,
|
|
|
|
|
flags: 0,
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2023-03-27 05:53:29 +00:00
|
|
|
bitflags! {
|
2025-10-31 08:42:31 +00:00
|
|
|
/// Flags for per file system.
|
2023-03-27 05:53:29 +00:00
|
|
|
pub struct FsFlags: u32 {
|
2025-10-31 08:42:31 +00:00
|
|
|
/// The filesystem is mounted read-only.
|
|
|
|
|
const RDONLY = 1 << 0;
|
|
|
|
|
/// Writes are synced at once.
|
|
|
|
|
const SYNCHRONOUS = 1 << 4;
|
|
|
|
|
/// Allow mandatory locks on an FS.
|
|
|
|
|
const MANDLOCK = 1 << 6;
|
|
|
|
|
/// Directory modifications are synchronous.
|
|
|
|
|
const DIRSYNC = 1 << 7;
|
|
|
|
|
/// Suppress certain messages in kernel log.
|
|
|
|
|
const SILENT = 1 << 15;
|
|
|
|
|
/// Update the on-disk [acm]times lazily.
|
|
|
|
|
const LAZYTIME = 1 << 25;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
impl core::fmt::Display for FsFlags {
|
|
|
|
|
fn fmt(&self, f: &mut core::fmt::Formatter) -> core::fmt::Result {
|
|
|
|
|
if self.contains(FsFlags::RDONLY) {
|
|
|
|
|
write!(f, "ro")?;
|
|
|
|
|
} else {
|
|
|
|
|
write!(f, "rw")?;
|
|
|
|
|
}
|
|
|
|
|
if self.contains(FsFlags::SYNCHRONOUS) {
|
|
|
|
|
write!(f, ",sync")?;
|
|
|
|
|
}
|
|
|
|
|
if self.contains(FsFlags::MANDLOCK) {
|
|
|
|
|
write!(f, ",mandlock")?;
|
|
|
|
|
}
|
|
|
|
|
if self.contains(FsFlags::DIRSYNC) {
|
|
|
|
|
write!(f, ",dirsync")?;
|
|
|
|
|
}
|
|
|
|
|
if self.contains(FsFlags::SILENT) {
|
|
|
|
|
write!(f, ",silent")?;
|
|
|
|
|
}
|
|
|
|
|
if self.contains(FsFlags::LAZYTIME) {
|
|
|
|
|
write!(f, ",lazytime")?;
|
|
|
|
|
}
|
|
|
|
|
Ok(())
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
impl From<u32> for FsFlags {
|
|
|
|
|
fn from(value: u32) -> Self {
|
|
|
|
|
Self::from_bits_truncate(value)
|
2023-03-27 05:53:29 +00:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2025-10-31 08:42:31 +00:00
|
|
|
impl From<FsFlags> for u32 {
|
|
|
|
|
fn from(value: FsFlags) -> Self {
|
|
|
|
|
value.bits()
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
define_atomic_version_of_integer_like_type!(FsFlags, {
|
|
|
|
|
/// An atomic version of `FsFlags`.
|
|
|
|
|
#[derive(Debug)]
|
|
|
|
|
#[expect(dead_code)]
|
|
|
|
|
pub struct AtomicFsFlags(AtomicU32);
|
|
|
|
|
});
|
|
|
|
|
|
2025-11-17 15:38:28 +00:00
|
|
|
#[derive(Debug)]
|
|
|
|
|
pub struct FsEventSubscriberStats {
|
|
|
|
|
// The number of subscribers to this file system.
|
|
|
|
|
num_subscribers: AtomicI64,
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
impl FsEventSubscriberStats {
|
|
|
|
|
pub fn new() -> Self {
|
|
|
|
|
Self {
|
|
|
|
|
num_subscribers: AtomicI64::new(0),
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
pub fn add_subscriber(&self) {
|
|
|
|
|
self.num_subscribers.fetch_add(1, Ordering::Release);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
pub fn remove_subscriber(&self) {
|
|
|
|
|
let subscribers = self.num_subscribers.fetch_sub(1, Ordering::Release);
|
|
|
|
|
debug_assert!(
|
|
|
|
|
subscribers >= 0,
|
2026-01-08 08:05:29 +00:00
|
|
|
"the number of subscribers is negative: {} (removed one)",
|
2025-11-17 15:38:28 +00:00
|
|
|
subscribers
|
|
|
|
|
);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
pub fn remove_subscribers(&self, num_subscribers: usize) {
|
|
|
|
|
let subscribers = self
|
|
|
|
|
.num_subscribers
|
2026-01-08 08:05:29 +00:00
|
|
|
.fetch_sub(num_subscribers as i64, Ordering::Release);
|
2025-11-17 15:38:28 +00:00
|
|
|
debug_assert!(
|
|
|
|
|
subscribers >= 0,
|
2026-01-08 08:05:29 +00:00
|
|
|
"the number of subscribers is negative: {} (removed {})",
|
|
|
|
|
subscribers,
|
|
|
|
|
num_subscribers
|
2025-11-17 15:38:28 +00:00
|
|
|
);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
pub fn has_any_subscribers(&self) -> bool {
|
|
|
|
|
self.num_subscribers.load(Ordering::Acquire) > 0
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2023-03-27 05:55:13 +00:00
|
|
|
pub trait FileSystem: Any + Sync + Send {
|
2025-10-24 02:36:32 +00:00
|
|
|
/// Gets the name of this FS type such as `"ext4"` or `"sysfs"`.
|
|
|
|
|
fn name(&self) -> &'static str;
|
|
|
|
|
|
2026-02-02 03:35:02 +00:00
|
|
|
/// Gets the source of this file system, e.g., the device name or user-provided source string.
|
|
|
|
|
fn source(&self) -> Option<&str> {
|
|
|
|
|
None
|
|
|
|
|
}
|
|
|
|
|
|
2025-10-24 02:36:32 +00:00
|
|
|
/// Syncs the file system.
|
2022-12-30 03:22:04 +00:00
|
|
|
fn sync(&self) -> Result<()>;
|
|
|
|
|
|
2025-10-24 02:36:32 +00:00
|
|
|
/// Returns the root inode of this file system.
|
2022-12-30 03:22:04 +00:00
|
|
|
fn root_inode(&self) -> Arc<dyn Inode>;
|
|
|
|
|
|
2025-10-24 02:36:32 +00:00
|
|
|
/// Returns the super block of this file system.
|
2022-12-30 03:22:04 +00:00
|
|
|
fn sb(&self) -> SuperBlock;
|
2023-03-27 05:53:29 +00:00
|
|
|
|
2025-10-24 02:36:32 +00:00
|
|
|
/// Returns the flags of this file system.
|
2025-10-31 08:42:31 +00:00
|
|
|
fn flags(&self) -> FsFlags {
|
|
|
|
|
// TODO: Currently we do not support any flags for filesystems.
|
|
|
|
|
// Remove the default empty implementation in the future.
|
|
|
|
|
FsFlags::empty()
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// Sets the flags of this file system.
|
|
|
|
|
fn set_fs_flags(&self, _flags: FsFlags, _data: Option<CString>, _ctx: &Context) -> Result<()> {
|
|
|
|
|
// TODO: Remove the default empty implementation in the future.
|
|
|
|
|
warn!("setting file system flags is not implemented");
|
|
|
|
|
Ok(())
|
|
|
|
|
}
|
2025-11-17 15:38:28 +00:00
|
|
|
|
|
|
|
|
/// Returns the FS event subscriber stats of this file system.
|
|
|
|
|
fn fs_event_subscriber_stats(&self) -> &FsEventSubscriberStats;
|
2023-03-27 05:55:13 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
impl dyn FileSystem {
|
|
|
|
|
pub fn downcast_ref<T: FileSystem>(&self) -> Option<&T> {
|
2023-05-25 02:36:18 +00:00
|
|
|
(self as &dyn Any).downcast_ref::<T>()
|
2023-03-27 05:55:13 +00:00
|
|
|
}
|
2022-12-30 03:22:04 +00:00
|
|
|
}
|
2023-08-04 04:00:22 +00:00
|
|
|
|
|
|
|
|
impl Debug for dyn FileSystem {
|
|
|
|
|
fn fmt(&self, f: &mut core::fmt::Formatter) -> core::fmt::Result {
|
|
|
|
|
f.debug_struct("FileSystem")
|
|
|
|
|
.field("super_block", &self.sb())
|
|
|
|
|
.field("flags", &self.flags())
|
|
|
|
|
.finish()
|
|
|
|
|
}
|
|
|
|
|
}
|