Redesign inode extensions

This commit is contained in:
Ruihan Li 2025-11-20 23:51:19 +08:00
parent 57399a223c
commit e362520d49
27 changed files with 236 additions and 258 deletions

View File

@ -8,10 +8,9 @@ use super::fs::CgroupFs;
use crate::{
fs::{
cgroupfs::CgroupNode,
notify::FsEventPublisher,
path::{is_dot, is_dotdot},
utils::{
FileSystem, Inode, InodeMode, Metadata,
Extension, FileSystem, Inode, InodeMode, Metadata,
systree_inode::{SysTreeInodeTy, SysTreeNodeKind},
},
},
@ -24,8 +23,8 @@ pub(super) struct CgroupInode {
node_kind: SysTreeNodeKind,
/// The metadata of this inode.
metadata: Metadata,
/// FS event publisher.
fs_event_publisher: FsEventPublisher,
/// The extension of this inode.
extension: Extension,
/// The file mode (permissions) of this inode, protected by a lock.
mode: RwLock<InodeMode>,
/// Weak reference to the parent inode.
@ -47,7 +46,7 @@ impl SysTreeInodeTy for CgroupInode {
Arc::new_cyclic(|this| Self {
node_kind,
metadata,
fs_event_publisher: FsEventPublisher::new(),
extension: Extension::new(),
mode: RwLock::new(mode),
parent,
this: this.clone(),
@ -62,8 +61,8 @@ impl SysTreeInodeTy for CgroupInode {
&self.metadata
}
fn fs_event_publisher(&self) -> &FsEventPublisher {
&self.fs_event_publisher
fn extension(&self) -> &Extension {
&self.extension
}
fn mode(&self) -> Result<InodeMode> {

View File

@ -7,9 +7,8 @@ use ostd::sync::RwLock;
use crate::{
fs::{
configfs::fs::ConfigFs,
notify::FsEventPublisher,
utils::{
FileSystem, Inode, InodeMode, Metadata,
Extension, FileSystem, Inode, InodeMode, Metadata,
systree_inode::{SysTreeInodeTy, SysTreeNodeKind},
},
},
@ -22,8 +21,8 @@ pub struct ConfigInode {
node_kind: SysTreeNodeKind,
/// The metadata of this inode.
metadata: Metadata,
/// FS event publisher.
fs_event_publisher: FsEventPublisher,
/// The extension of this inode.
extension: Extension,
/// The file mode (permissions) of this inode, protected by a lock.
mode: RwLock<InodeMode>,
/// Weak reference to the parent inode.
@ -45,7 +44,7 @@ impl SysTreeInodeTy for ConfigInode {
Arc::new_cyclic(|this| Self {
node_kind,
metadata,
fs_event_publisher: FsEventPublisher::new(),
extension: Extension::new(),
mode: RwLock::new(mode),
parent,
this: this.clone(),
@ -73,13 +72,13 @@ impl SysTreeInodeTy for ConfigInode {
&self.parent
}
fn fs_event_publisher(&self) -> &FsEventPublisher {
&self.fs_event_publisher
}
fn this(&self) -> Arc<Self> {
self.this.upgrade().expect("Weak ref invalid")
}
fn extension(&self) -> &Extension {
&self.extension
}
}
impl Inode for ConfigInode {

View File

@ -9,12 +9,11 @@ use id_alloc::IdAlloc;
pub use self::ptmx::Ptmx;
use self::slave::PtySlaveInode;
use super::utils::{MknodType, StatusFlags};
use super::utils::{Extension, MknodType, StatusFlags};
use crate::{
device::PtyMaster,
fs::{
device::{Device, DeviceType},
notify::FsEventPublisher,
registry::{FsProperties, FsType},
utils::{
DirEntryVecExt, DirentVisitor, FileSystem, FsEventSubscriberStats, FsFlags, Inode,
@ -151,7 +150,7 @@ struct RootInode {
ptmx: Arc<Ptmx>,
slaves: RwLock<SlotVec<(String, Arc<dyn Inode>)>>,
metadata: RwLock<Metadata>,
fs_event_publisher: FsEventPublisher,
extension: Extension,
fs: Weak<DevPts>,
}
@ -161,7 +160,7 @@ impl RootInode {
ptmx: Ptmx::new(fs.clone()),
slaves: RwLock::new(SlotVec::new()),
metadata: RwLock::new(Metadata::new_dir(ROOT_INO, mkmod!(a+rx, u+w), BLOCK_SIZE)),
fs_event_publisher: FsEventPublisher::new(),
extension: Extension::new(),
fs,
})
}
@ -200,8 +199,8 @@ impl Inode for RootInode {
*self.metadata.read()
}
fn fs_event_publisher(&self) -> &FsEventPublisher {
&self.fs_event_publisher
fn extension(&self) -> &Extension {
&self.extension
}
fn ino(&self) -> u64 {

View File

@ -5,8 +5,7 @@ use device_id::{DeviceId, MajorId, MinorId};
use super::*;
use crate::fs::{
inode_handle::FileIo,
notify::FsEventPublisher,
utils::{AccessMode, InodeIo, StatusFlags},
utils::{AccessMode, Extension, InodeIo, StatusFlags},
};
/// Same major number with Linux.
@ -21,7 +20,7 @@ const PTMX_MINOR_NUM: u32 = 2;
pub struct Ptmx {
inner: Inner,
metadata: RwLock<Metadata>,
fs_event_publisher: FsEventPublisher,
extension: Extension,
}
#[derive(Clone)]
@ -38,7 +37,7 @@ impl Ptmx {
&inner,
)),
inner,
fs_event_publisher: FsEventPublisher::new(),
extension: Extension::new(),
})
}
@ -82,8 +81,8 @@ impl Inode for Ptmx {
*self.metadata.read()
}
fn fs_event_publisher(&self) -> &FsEventPublisher {
&self.fs_event_publisher
fn extension(&self) -> &Extension {
&self.extension
}
fn ino(&self) -> u64 {

View File

@ -8,7 +8,6 @@ use crate::{
device::PtySlave,
fs::{
inode_handle::FileIo,
notify::FsEventPublisher,
utils::{AccessMode, InodeIo, StatusFlags},
},
};
@ -20,7 +19,7 @@ const SLAVE_MAJOR_NUM: u32 = 3;
pub struct PtySlaveInode {
device: Arc<PtySlave>,
metadata: RwLock<Metadata>,
fs_event_publisher: FsEventPublisher,
extension: Extension,
fs: Weak<DevPts>,
}
@ -34,7 +33,7 @@ impl PtySlaveInode {
device.as_ref(),
)),
device,
fs_event_publisher: FsEventPublisher::new(),
extension: Extension::new(),
fs,
})
}
@ -81,8 +80,8 @@ impl Inode for PtySlaveInode {
*self.metadata.read()
}
fn fs_event_publisher(&self) -> &FsEventPublisher {
&self.fs_event_publisher
fn extension(&self) -> &Extension {
&self.extension
}
fn ino(&self) -> u64 {

View File

@ -27,7 +27,6 @@ use super::{
use crate::{
fs::{
exfat::{dentry::ExfatDentryIterator, fat::ExfatChain, fs::ExfatFs},
notify::FsEventPublisher,
path::{is_dot, is_dot_or_dotdot, is_dotdot},
utils::{
CachePage, DirentVisitor, Extension, Inode, InodeIo, InodeMode, InodeType, Metadata,
@ -79,7 +78,6 @@ impl FatAttr {
pub struct ExfatInode {
inner: RwMutex<ExfatInodeInner>,
extension: Extension,
fs_event_publisher: FsEventPublisher,
}
#[derive(Debug)]
@ -862,7 +860,6 @@ impl ExfatInode {
page_cache: PageCache::with_capacity(size, weak_self.clone() as _).unwrap(),
}),
extension: Extension::new(),
fs_event_publisher: FsEventPublisher::new(),
});
let inner = inode.inner.upread();
@ -973,7 +970,6 @@ impl ExfatInode {
page_cache: PageCache::with_capacity(size, weak_self.clone() as _).unwrap(),
}),
extension: Extension::new(),
fs_event_publisher: FsEventPublisher::new(),
});
if matches!(inode_type, InodeType::Dir) {
@ -1734,11 +1730,7 @@ impl Inode for ExfatInode {
true
}
fn extension(&self) -> Option<&Extension> {
Some(&self.extension)
}
fn fs_event_publisher(&self) -> &FsEventPublisher {
&self.fs_event_publisher
fn extension(&self) -> &Extension {
&self.extension
}
}

View File

@ -9,7 +9,6 @@ use crate::{
fs::{
ext2::{FilePerm, Inode as Ext2Inode},
inode_handle::FileIo,
notify::FsEventPublisher,
utils::{
AccessMode, DirentVisitor, Extension, FallocMode, FileSystem, Inode, InodeIo,
InodeMode, InodeType, Metadata, MknodType, StatusFlags, SymbolicLink, XattrName,
@ -234,12 +233,8 @@ impl Inode for Ext2Inode {
self.fs()
}
fn extension(&self) -> Option<&Extension> {
Some(self.extension())
}
fn fs_event_publisher(&self) -> &FsEventPublisher {
self.fs_event_publisher()
fn extension(&self) -> &Extension {
self.extension()
}
fn set_xattr(

View File

@ -21,7 +21,6 @@ use super::{
use crate::{
fs::{
inode_handle::FileIo,
notify::FsEventPublisher,
path::{is_dot, is_dot_or_dotdot, is_dotdot},
pipe::Pipe,
utils::{
@ -46,7 +45,6 @@ pub struct Inode {
inner: RwMutex<InodeInner>,
fs: Weak<Ext2>,
extension: Extension,
fs_event_publisher: FsEventPublisher,
xattr: Option<Xattr>,
}
@ -67,7 +65,6 @@ impl Inode {
inner: RwMutex::new(InodeInner::new(desc, weak_self.clone(), fs.clone())),
fs,
extension: Extension::new(),
fs_event_publisher: FsEventPublisher::new(),
})
}
@ -112,10 +109,6 @@ impl Inode {
}
}
pub fn fs_event_publisher(&self) -> &FsEventPublisher {
&self.fs_event_publisher
}
pub fn resize(&self, new_size: usize) -> Result<()> {
if self.type_ == InodeType::Dir {
return_errno!(Errno::EISDIR);

View File

@ -8,15 +8,15 @@ use core::sync::atomic::{AtomicU32, Ordering};
pub use dyn_cap::InodeHandle;
use super::utils::InodeIo;
use super::utils::{InodeExt, InodeIo};
use crate::{
events::IoEvents,
fs::{
file_handle::Mappable,
path::Path,
utils::{
DirentVisitor, FallocMode, FileRange, FlockItem, FlockList, Inode, InodeType,
OFFSET_MAX, RangeLockItem, RangeLockList, RangeLockType, SeekFrom, StatusFlags,
DirentVisitor, FallocMode, FileRange, FlockItem, Inode, InodeType, OFFSET_MAX,
RangeLockItem, RangeLockType, SeekFrom, StatusFlags,
},
},
prelude::*,
@ -211,13 +211,12 @@ impl HandleInner {
}
pub(self) fn test_range_lock(&self, mut lock: RangeLockItem) -> Result<RangeLockItem> {
let Some(extension) = self.path.inode().extension() else {
// Range locks are not supported. So nothing is locked.
lock.set_type(RangeLockType::Unlock);
return Ok(lock);
};
let Some(range_lock_list) = extension.get::<RangeLockList>() else {
let Some(range_lock_list) = self
.path
.inode()
.fs_lock_context()
.map(|c| c.range_lock_list())
else {
// The lock list is not present. So nothing is locked.
lock.set_type(RangeLockType::Unlock);
return Ok(lock);
@ -233,24 +232,15 @@ impl HandleInner {
return Ok(());
}
let Some(extension) = self.path.inode().extension() else {
// TODO: Figure out whether range locks are supported on all inodes.
warn!("the inode does not have support for range locks; this operation will fail");
return_errno_with_message!(Errno::ENOLCK, "range locks are not supported");
};
let range_lock_list = match extension.get::<RangeLockList>() {
Some(list) => list,
None => extension.get_or_put_default::<RangeLockList>(),
};
let range_lock_list = self
.path
.inode()
.fs_lock_context_or_init()
.range_lock_list();
range_lock_list.set_lock(lock, is_nonblocking)
}
pub(self) fn release_range_locks(&self) {
if self.path.inode().extension().is_none() {
return;
}
let range_lock = RangeLockItem::new(
RangeLockType::Unlock,
FileRange::new(0, OFFSET_MAX).unwrap(),
@ -259,31 +249,23 @@ impl HandleInner {
}
pub(self) fn unlock_range_lock(&self, lock: &RangeLockItem) {
if let Some(extension) = self.path.inode().extension()
&& let Some(range_lock_list) = extension.get::<RangeLockList>()
if let Some(range_lock_list) = self
.path
.inode()
.fs_lock_context()
.map(|c| c.range_lock_list())
{
range_lock_list.unlock(lock);
}
}
pub(self) fn set_flock(&self, lock: FlockItem, is_nonblocking: bool) -> Result<()> {
let Some(extension) = self.path.inode().extension() else {
// TODO: Figure out whether flocks are supported on all inodes.
warn!("the inode does not have support for flocks; this operation will fail");
return_errno_with_message!(Errno::ENOLCK, "flocks are not supported");
};
let flock_list = match extension.get::<FlockList>() {
Some(list) => list,
None => extension.get_or_put_default::<FlockList>(),
};
let flock_list = self.path.inode().fs_lock_context_or_init().flock_list();
flock_list.set_lock(lock, is_nonblocking)
}
pub(self) fn unlock_flock(&self, req_owner: &InodeHandle) {
if let Some(extension) = self.path.inode().extension()
&& let Some(flock_list) = extension.get::<FlockList>()
{
if let Some(flock_list) = self.path.inode().fs_lock_context().map(|c| c.flock_list()) {
flock_list.unlock(req_owner);
}
}

View File

@ -26,7 +26,7 @@ use crate::{
notify::{FsEventSubscriber, FsEvents},
path::{Path, RESERVED_MOUNT_ID},
pseudofs::anon_inodefs_shared_inode,
utils::{AccessMode, CreationFlags, Inode, StatusFlags},
utils::{AccessMode, CreationFlags, Inode, InodeExt, StatusFlags},
},
prelude::*,
process::signal::{PollHandle, Pollable, Pollee},
@ -75,7 +75,11 @@ impl Drop for InotifyFile {
continue;
};
if inode.fs_event_publisher().remove_subscriber(&subscriber) {
if inode
.fs_event_publisher()
.unwrap()
.remove_subscriber(&subscriber)
{
inode.fs().fs_event_subscriber_stats().remove_subscriber();
}
}
@ -163,7 +167,11 @@ impl InotifyFile {
_ => return_errno_with_message!(Errno::EINVAL, "watch not found"),
};
if inode.fs_event_publisher().remove_subscriber(&subscriber) {
if inode
.fs_event_publisher()
.unwrap()
.remove_subscriber(&subscriber)
{
inode.fs().fs_event_subscriber_stats().remove_subscriber();
}
Ok(())
@ -176,7 +184,9 @@ impl InotifyFile {
interesting: InotifyEvents,
options: InotifyControls,
) -> Result<u32> {
let publisher = path.inode().fs_event_publisher();
let Some(publisher) = path.inode().fs_event_publisher() else {
return_errno_with_message!(Errno::ENOENT, "watch not found");
};
let inotify_file = self.this();
let result = publisher.find_subscriber_and_process(|subscriber| {
@ -214,7 +224,7 @@ impl InotifyFile {
if path
.inode()
.fs_event_publisher()
.fs_event_publisher_or_init()
.add_subscriber(subscriber.clone())
{
path.inode()

View File

@ -17,7 +17,7 @@ use crate::{
pub mod inotify;
use super::utils::{Inode, InodeType};
use super::utils::{Inode, InodeExt, InodeType};
/// Publishes filesystem events to subscribers.
///
@ -432,5 +432,7 @@ fn notify_parent(path: &Path, mut events: FsEvents, name: String) {
/// functions in `fs/notify/`, which then call this function to broadcast events
/// to all registered subscribers through the inode's publisher.
fn notify_inode(inode: &Arc<dyn Inode>, events: FsEvents, name: Option<String>) {
inode.fs_event_publisher().publish_event(events, name);
if let Some(publisher) = inode.fs_event_publisher() {
publisher.publish_event(events, name);
}
}

View File

@ -21,11 +21,10 @@ use crate::{
fs::{
fs_resolver::FsPath,
inode_handle::FileIo,
notify::FsEventPublisher,
path::Path,
registry::{FsProperties, FsType},
utils::{
AccessMode, DirentCounter, DirentVisitor, FallocMode, FileSystem,
AccessMode, DirentCounter, DirentVisitor, Extension, FallocMode, FileSystem,
FsEventSubscriberStats, FsFlags, Inode, InodeIo, InodeMode, InodeType, Metadata,
MknodType, NAME_MAX, StatusFlags, SuperBlock, SymbolicLink, XATTR_VALUE_MAX_LEN,
XattrName, XattrNamespace, XattrSetFlags, mkmod,
@ -91,8 +90,8 @@ struct OverlayInode {
/// This field is used to build hierarchical upper inodes.
/// The lock is intended to implement `rename`.
name_upon_creation: SpinLock<String>,
/// FS event publisher.
fs_event_publisher: FsEventPublisher,
/// The extension of this inode.
extension: Extension,
/// The parent inode. `None` for root inode.
parent: Option<Arc<OverlayInode>>,
/// The mutable upper regular inode.
@ -173,7 +172,7 @@ impl FileSystem for OverlayFs {
ino,
type_: InodeType::Dir,
name_upon_creation: SpinLock::new(String::from("")),
fs_event_publisher: FsEventPublisher::new(),
extension: Extension::new(),
parent: None,
upper: Mutex::new(Some(upper_inode)),
upper_is_opaque: false,
@ -279,7 +278,7 @@ impl OverlayInode {
ino: new_upper.ino(),
type_,
name_upon_creation: SpinLock::new(String::from(name)),
fs_event_publisher: FsEventPublisher::new(),
extension: Extension::new(),
parent: Some(self.self_.upgrade().unwrap()),
upper: Mutex::new(Some(new_upper)),
upper_is_opaque,
@ -452,8 +451,8 @@ impl OverlayInode {
self.type_
}
pub fn fs_event_publisher(&self) -> &FsEventPublisher {
&self.fs_event_publisher
pub fn extension(&self) -> &Extension {
&self.extension
}
pub fn page_cache(&self) -> Option<Arc<Vmo>> {
@ -693,7 +692,7 @@ impl OverlayInode {
ino,
type_: type_.unwrap(),
name_upon_creation: SpinLock::new(String::from(name)),
fs_event_publisher: FsEventPublisher::new(),
extension: Extension::new(),
parent: Some(self.self_.upgrade().unwrap()),
upper: Mutex::new(upper_child),
upper_is_opaque,
@ -934,7 +933,7 @@ impl Inode for OverlayInode {
fn size(&self) -> usize;
fn resize(&self, new_size: usize) -> Result<()>;
fn metadata(&self) -> Metadata;
fn fs_event_publisher(&self) -> &FsEventPublisher;
fn extension(&self) -> &Extension;
fn ino(&self) -> u64;
fn type_(&self) -> InodeType;
fn mode(&self) -> Result<InodeMode>;

View File

@ -7,8 +7,10 @@ use ostd::sync::RwMutexWriteGuard;
use super::{is_dot, is_dot_or_dotdot, is_dotdot};
use crate::{
fs,
fs::utils::{Inode, InodeMode, InodeType, MknodType},
fs::{
self,
utils::{Inode, InodeExt, InodeMode, InodeType, MknodType},
},
prelude::*,
};
@ -273,7 +275,10 @@ impl Dentry {
}
fs::notify::on_delete(self.inode(), &child_inode, || name.to_string());
if nlinks == 0 {
let publisher = child_inode.fs_event_publisher();
// Ideally, we would use `fs_event_publisher()` here to avoid creating a
// `FsEventPublisher` instance on a dying inode. However, it isn't possible because we
// need to disable new subscribers.
let publisher = child_inode.fs_event_publisher_or_init();
publisher.disable_new_subscribers();
let removed_nr_subscribers = publisher.remove_all_subscribers();
child_inode
@ -323,7 +328,10 @@ impl Dentry {
}
fs::notify::on_delete(self.inode(), &child_inode, || name.to_string());
if nlinks == 0 {
let publisher = child_inode.fs_event_publisher();
// Ideally, we would use `fs_event_publisher()` here to avoid creating a
// `FsEventPublisher` on a dying inode. However, it isn't possible because we need to
// disable new subscribers.
let publisher = child_inode.fs_event_publisher_or_init();
publisher.disable_new_subscribers();
let removed_nr_subscribers = publisher.remove_all_subscribers();
child_inode

View File

@ -13,13 +13,12 @@ use crate::{
fs::{
file_handle::FileLike,
file_table::FdFlags,
notify::FsEventPublisher,
path::RESERVED_MOUNT_ID,
pipe::{Pipe, common::PipeHandle},
pseudofs::{PseudoInode, pipefs_singleton},
utils::{
AccessMode, CreationFlags, FileSystem, Inode, InodeIo, InodeMode, InodeType, Metadata,
StatusFlags, mkmod,
AccessMode, CreationFlags, Extension, FileSystem, Inode, InodeIo, InodeMode, InodeType,
Metadata, StatusFlags, mkmod,
},
},
prelude::*,
@ -221,7 +220,7 @@ impl Inode for AnonPipeInode {
fn size(&self) -> usize;
fn resize(&self, _new_size: usize) -> Result<()>;
fn metadata(&self) -> Metadata;
fn fs_event_publisher(&self) -> &FsEventPublisher;
fn extension(&self) -> &Extension;
fn ino(&self) -> u64;
fn type_(&self) -> InodeType;
fn mode(&self) -> Result<InodeMode>;

View File

@ -9,11 +9,10 @@ use ostd::sync::RwMutexUpgradeableGuard;
use super::{Common, ProcFs};
use crate::{
fs::{
notify::FsEventPublisher,
path::{is_dot, is_dotdot},
utils::{
DirEntryVecExt, DirentVisitor, FileSystem, Inode, InodeIo, InodeMode, InodeType,
Metadata, MknodType, StatusFlags,
DirEntryVecExt, DirentVisitor, Extension, FileSystem, Inode, InodeIo, InodeMode,
InodeType, Metadata, MknodType, StatusFlags,
},
},
prelude::*,
@ -96,7 +95,7 @@ impl<D: DirOps + 'static> InodeIo for ProcDir<D> {
impl<D: DirOps + 'static> Inode for ProcDir<D> {
fn size(&self) -> usize;
fn metadata(&self) -> Metadata;
fn fs_event_publisher(&self) -> &FsEventPublisher;
fn extension(&self) -> &Extension;
fn ino(&self) -> u64;
fn mode(&self) -> Result<InodeMode>;
fn set_mode(&self, mode: InodeMode) -> Result<()>;

View File

@ -6,11 +6,9 @@ use inherit_methods_macro::inherit_methods;
use super::{Common, ProcFs};
use crate::{
fs::{
notify::FsEventPublisher,
utils::{
FileSystem, Inode, InodeIo, InodeMode, InodeType, Metadata, StatusFlags, SymbolicLink,
},
fs::utils::{
Extension, FileSystem, Inode, InodeIo, InodeMode, InodeType, Metadata, StatusFlags,
SymbolicLink,
},
prelude::*,
process::{Gid, Uid},
@ -69,7 +67,7 @@ impl<F: FileOps + 'static> InodeIo for ProcFile<F> {
impl<F: FileOps + 'static> Inode for ProcFile<F> {
fn size(&self) -> usize;
fn metadata(&self) -> Metadata;
fn fs_event_publisher(&self) -> &FsEventPublisher;
fn extension(&self) -> &Extension;
fn ino(&self) -> u64;
fn mode(&self) -> Result<InodeMode>;
fn set_mode(&self, mode: InodeMode) -> Result<()>;

View File

@ -10,10 +10,7 @@ pub(super) use self::{
};
use super::{BLOCK_SIZE, ProcFs};
use crate::{
fs::{
notify::FsEventPublisher,
utils::{FileSystem, InodeMode, InodeType, Metadata},
},
fs::utils::{Extension, FileSystem, InodeMode, InodeType, Metadata},
prelude::*,
process::{Gid, Uid},
};
@ -25,7 +22,7 @@ mod sym;
struct Common {
metadata: RwLock<Metadata>,
fs_event_publisher: FsEventPublisher,
extension: Extension,
fs: Weak<dyn FileSystem>,
is_volatile: bool,
}
@ -34,7 +31,7 @@ impl Common {
pub fn new(metadata: Metadata, fs: Weak<dyn FileSystem>, is_volatile: bool) -> Self {
Self {
metadata: RwLock::new(metadata),
fs_event_publisher: FsEventPublisher::new(),
extension: Extension::new(),
fs,
is_volatile,
}
@ -115,7 +112,7 @@ impl Common {
self.is_volatile
}
pub fn fs_event_publisher(&self) -> &FsEventPublisher {
&self.fs_event_publisher
pub fn extension(&self) -> &Extension {
&self.extension
}
}

View File

@ -6,11 +6,9 @@ use inherit_methods_macro::inherit_methods;
use super::{Common, ProcFs};
use crate::{
fs::{
notify::FsEventPublisher,
utils::{
FileSystem, Inode, InodeIo, InodeMode, InodeType, Metadata, StatusFlags, SymbolicLink,
},
fs::utils::{
Extension, FileSystem, Inode, InodeIo, InodeMode, InodeType, Metadata, StatusFlags,
SymbolicLink,
},
prelude::*,
process::{Gid, Uid},
@ -66,7 +64,7 @@ impl<S: SymOps + 'static> InodeIo for ProcSym<S> {
impl<S: SymOps + 'static> Inode for ProcSym<S> {
fn size(&self) -> usize;
fn metadata(&self) -> Metadata;
fn fs_event_publisher(&self) -> &FsEventPublisher;
fn extension(&self) -> &Extension;
fn ino(&self) -> u64;
fn mode(&self) -> Result<InodeMode>;
fn set_mode(&self, mode: InodeMode) -> Result<()>;

View File

@ -4,10 +4,9 @@ use core::time::Duration;
use spin::Once;
use super::utils::{InodeIo, StatusFlags};
use super::utils::{Extension, InodeIo, StatusFlags};
use crate::{
fs::{
notify::FsEventPublisher,
registry::{FsProperties, FsType},
utils::{
FileSystem, FsEventSubscriberStats, FsFlags, Inode, InodeMode, InodeType, Metadata,
@ -182,7 +181,7 @@ const ANON_INODEFS_MAGIC: u64 = 0x09041934;
/// A pseudo inode that does not correspond to any real path in the file system.
pub struct PseudoInode {
metadata: SpinLock<Metadata>,
fs_events_publisher: FsEventPublisher,
extension: Extension,
fs: Weak<PseudoFs>,
}
@ -215,7 +214,7 @@ impl PseudoInode {
};
PseudoInode {
metadata: SpinLock::new(metadata),
fs_events_publisher: FsEventPublisher::new(),
extension: Extension::new(),
fs,
}
}
@ -260,8 +259,8 @@ impl Inode for PseudoInode {
*self.metadata.lock()
}
fn fs_event_publisher(&self) -> &FsEventPublisher {
&self.fs_events_publisher
fn extension(&self) -> &Extension {
&self.extension
}
fn ino(&self) -> u64 {

View File

@ -21,7 +21,6 @@ use crate::{
fs::{
device::DeviceType,
inode_handle::FileIo,
notify::FsEventPublisher,
path::{is_dot, is_dot_or_dotdot, is_dotdot},
pipe::Pipe,
registry::{FsProperties, FsType},
@ -67,7 +66,6 @@ impl RamFs {
fs: weak_fs.clone(),
extension: Extension::new(),
xattr: RamXattr::new(),
fs_event_publisher: FsEventPublisher::new(),
}),
inode_allocator: AtomicU64::new(ROOT_INO + 1),
fs_event_subscriber_stats: FsEventSubscriberStats::new(),
@ -118,8 +116,6 @@ pub(super) struct RamInode {
fs: Weak<RamFs>,
/// Extensions
extension: Extension,
/// FS event publisher
fs_event_publisher: FsEventPublisher,
/// Extended attributes
xattr: RamXattr,
}
@ -454,7 +450,6 @@ impl RamInode {
this: weak_self.clone(),
fs: Arc::downgrade(fs),
extension: Extension::new(),
fs_event_publisher: FsEventPublisher::new(),
xattr: RamXattr::new(),
})
}
@ -468,7 +463,6 @@ impl RamInode {
this: weak_self.clone(),
fs: Arc::downgrade(fs),
extension: Extension::new(),
fs_event_publisher: FsEventPublisher::new(),
xattr: RamXattr::new(),
})
}
@ -488,7 +482,6 @@ impl RamInode {
this: Weak::new(),
fs: Weak::new(),
extension: Extension::new(),
fs_event_publisher: FsEventPublisher::new(),
xattr: RamXattr::new(),
}
}
@ -502,7 +495,6 @@ impl RamInode {
this: weak_self.clone(),
fs: Arc::downgrade(fs),
extension: Extension::new(),
fs_event_publisher: FsEventPublisher::new(),
xattr: RamXattr::new(),
})
}
@ -528,7 +520,6 @@ impl RamInode {
this: weak_self.clone(),
fs: Arc::downgrade(fs),
extension: Extension::new(),
fs_event_publisher: FsEventPublisher::new(),
xattr: RamXattr::new(),
})
}
@ -542,7 +533,6 @@ impl RamInode {
this: weak_self.clone(),
fs: Arc::downgrade(fs),
extension: Extension::new(),
fs_event_publisher: FsEventPublisher::new(),
xattr: RamXattr::new(),
})
}
@ -556,7 +546,6 @@ impl RamInode {
this: weak_self.clone(),
fs: Arc::downgrade(fs),
extension: Extension::new(),
fs_event_publisher: FsEventPublisher::new(),
xattr: RamXattr::new(),
})
}
@ -1234,12 +1223,8 @@ impl Inode for RamInode {
}
}
fn extension(&self) -> Option<&Extension> {
Some(&self.extension)
}
fn fs_event_publisher(&self) -> &FsEventPublisher {
&self.fs_event_publisher
fn extension(&self) -> &Extension {
&self.extension
}
fn set_xattr(

View File

@ -22,7 +22,6 @@ use crate::{
file_handle::{FileLike, Mappable},
file_table::FdFlags,
inode_handle::{do_fallocate_util, do_resize_util, do_seek_util},
notify::FsEventPublisher,
path::{RESERVED_MOUNT_ID, check_open_util},
tmpfs::TmpFs,
utils::{
@ -179,8 +178,7 @@ impl Inode for MemfdInode {
fn group(&self) -> Result<Gid>;
fn set_group(&self, gid: Gid) -> Result<()>;
fn page_cache(&self) -> Option<Arc<Vmo>>;
fn extension(&self) -> Option<&Extension>;
fn fs_event_publisher(&self) -> &FsEventPublisher;
fn extension(&self) -> &Extension;
fn set_xattr(
&self,
name: XattrName,

View File

@ -6,12 +6,9 @@ use ostd::sync::RwLock;
use super::fs::SysFs;
use crate::{
fs::{
notify::FsEventPublisher,
utils::{
FileSystem, Inode, InodeMode, InodeType, Metadata,
systree_inode::{SysTreeInodeTy, SysTreeNodeKind},
},
fs::utils::{
Extension, FileSystem, Inode, InodeMode, InodeType, Metadata,
systree_inode::{SysTreeInodeTy, SysTreeNodeKind},
},
prelude::*,
};
@ -28,8 +25,8 @@ pub(super) struct SysFsInode {
/// Currently, the only mutable metadata is `mode`,
/// which allows user space to `chmod` an inode on sysfs.
metadata: Metadata,
/// FS event publisher.
fs_event_publisher: FsEventPublisher,
/// The extension of this inode.
extension: Extension,
/// The file mode (permissions) of this inode, protected by a lock.
mode: RwLock<InodeMode>,
/// Weak reference to the parent inode.
@ -51,7 +48,7 @@ impl SysTreeInodeTy for SysFsInode {
Arc::new_cyclic(|this| Self {
node_kind,
metadata,
fs_event_publisher: FsEventPublisher::new(),
extension: Extension::new(),
mode: RwLock::new(mode),
parent,
this: this.clone(),
@ -85,8 +82,8 @@ impl SysTreeInodeTy for SysFsInode {
.expect("invalid weak reference to `self`")
}
fn fs_event_publisher(&self) -> &FsEventPublisher {
&self.fs_event_publisher
fn extension(&self) -> &Extension {
&self.extension
}
}

View File

@ -2,10 +2,12 @@
#![expect(unused_variables)]
use core::{any::TypeId, time::Duration};
use alloc::boxed::ThinBox;
use core::time::Duration;
use core2::io::{Error as IoError, ErrorKind as IoErrorKind, Result as IoResult, Write};
use ostd::task::Task;
use spin::Once;
use super::{
AccessMode, DirentVisitor, FallocMode, FileSystem, InodeMode, XattrName, XattrNamespace,
@ -16,7 +18,6 @@ use crate::{
device::{Device, DeviceType},
fs_resolver::PathOrInode,
inode_handle::FileIo,
notify::FsEventPublisher,
path::Path,
utils::StatusFlags,
},
@ -402,19 +403,7 @@ pub trait Inode: Any + InodeIo + Send + Sync {
}
/// Gets the extension of this inode.
fn extension(&self) -> Option<&Extension> {
None
}
// TODO: Add `FsEventPublisher` as an extension.
//
// Conceptually, an `FsEventPublisher` attached to an inode is also a kind of extension
// as this object is required by the VFS layer, not by FS implementations.
// But we do not add it to `Extension` because `FsEventPublisher` is used in the most time-critical path
// and looking up an extension object in an `Extension` incurs some extra overheads.
// If we could make `Extension` a zero-cost abstraction,
// then `FsEventPublisher` can be moved into `Extension`.
fn fs_event_publisher(&self) -> &FsEventPublisher;
fn extension(&self) -> &Extension;
fn set_xattr(
&self,
@ -569,76 +558,34 @@ impl Debug for dyn Inode {
}
}
/// An extension is a set of objects that is attached to
/// an inode.
/// An extension is a set of object groups that is attached to an inode.
///
/// Each objects of an extension is of different types.
/// In other words, types are used as the keys to get and
/// set the objects in an extension.
/// In this structure, we do not specify the exact type, but instead use [`Any`], which makes the
/// FS types (e.g., [`Inode`]) independent of the kernel types. This allows the file system
/// implementation to exist outside the kernel.
#[derive(Debug)]
pub struct Extension {
data: RwLock<BTreeMap<TypeId, Arc<dyn Any + Send + Sync>>>,
group1: Once<ThinBox<dyn Any + Send + Sync>>,
group2: Once<ThinBox<dyn Any + Send + Sync>>,
}
impl Extension {
/// Creates a new, empty extension.
pub fn new() -> Self {
Self {
data: RwLock::new(BTreeMap::new()),
group1: Once::new(),
group2: Once::new(),
}
}
/// Get an object of `Arc<T>`.
pub fn get<T: Any + Send + Sync>(&self) -> Option<Arc<T>> {
let read_guard = self.data.read();
read_guard
.get(&TypeId::of::<T>())
.and_then(|arc_any| Arc::downcast::<T>(arc_any.clone()).ok())
/// Gets the first extension group.
pub fn group1(&self) -> &Once<ThinBox<dyn Any + Send + Sync>> {
&self.group1
}
/// Try to get an object of `Arc<T>`. If no object of the type exists,
/// put the default value for the type, then return it.
pub fn get_or_put_default<T: Any + Send + Sync + Default>(&self) -> Arc<T> {
let mut write_guard = self.data.write();
let type_id = TypeId::of::<T>();
let arc_any = write_guard.entry(type_id).or_insert_with(|| {
let obj = T::default();
Arc::new(obj) as Arc<dyn Any + Send + Sync>
});
Arc::downcast::<T>(arc_any.clone()).unwrap()
}
/// Put an object of `Arc<T>`. If there exists one object of the type,
/// then the old one is returned.
#[expect(dead_code)]
pub fn put<T: Any + Send + Sync>(&self, obj: Arc<T>) -> Option<Arc<T>> {
let mut write_guard = self.data.write();
write_guard
.insert(TypeId::of::<T>(), obj as Arc<dyn Any + Send + Sync>)
.and_then(|arc_any| Arc::downcast::<T>(arc_any).ok())
}
/// Delete an object of `Arc<T>`. If there exists one object of the type,
/// then the old one is returned.
#[expect(dead_code)]
pub fn del<T: Any + Send + Sync>(&self) -> Option<Arc<T>> {
let mut write_guard = self.data.write();
write_guard
.remove(&TypeId::of::<T>())
.and_then(|arc_any| Arc::downcast::<T>(arc_any).ok())
}
}
impl Clone for Extension {
fn clone(&self) -> Self {
Self {
data: RwLock::new(self.data.read().clone()),
}
}
}
impl Default for Extension {
fn default() -> Self {
Self::new()
/// Gets the second extension group.
pub fn group2(&self) -> &Once<ThinBox<dyn Any + Send + Sync>> {
&self.group2
}
}

View File

@ -0,0 +1,82 @@
// SPDX-License-Identifier: MPL-2.0
use alloc::boxed::ThinBox;
use super::{FlockList, Inode, RangeLockList};
use crate::fs::notify::FsEventPublisher;
/// Context for FS locks.
pub struct FsLockContext {
range_lock_list: RangeLockList,
flock_list: FlockList,
}
impl FsLockContext {
pub(self) fn new() -> Self {
Self {
range_lock_list: RangeLockList::new(),
flock_list: FlockList::new(),
}
}
/// Returns a reference to the range lock list.
pub fn range_lock_list(&self) -> &RangeLockList {
&self.range_lock_list
}
/// Returns a reference to the flock list.
pub fn flock_list(&self) -> &FlockList {
&self.flock_list
}
}
/// A trait that instantiates kernel types for the inode [`Extension`].
///
/// [`Extension`]: super::Extension
pub trait InodeExt {
/// Gets or initializes the FS event publisher.
///
/// If the publisher does not exist for this inode, it will be created.
fn fs_event_publisher_or_init(&self) -> &FsEventPublisher;
/// Returns a reference to the FS event publisher.
///
/// If the publisher does not exist for this inode, a [`None`] will be returned.
fn fs_event_publisher(&self) -> Option<&FsEventPublisher>;
/// Gets or initializes the FS lock context.
///
/// If the context does not exist for this inode, it will be created.
fn fs_lock_context_or_init(&self) -> &FsLockContext;
/// Returns a reference to the FS lock context.
///
/// If the context does not exist for this inode, a [`None`] will be returned.
fn fs_lock_context(&self) -> Option<&FsLockContext>;
}
impl InodeExt for dyn Inode {
fn fs_event_publisher_or_init(&self) -> &FsEventPublisher {
self.extension()
.group1()
.call_once(|| ThinBox::new_unsize(FsEventPublisher::new()))
.downcast_ref()
.unwrap()
}
fn fs_event_publisher(&self) -> Option<&FsEventPublisher> {
Some(self.extension().group1().get()?.downcast_ref().unwrap())
}
fn fs_lock_context_or_init(&self) -> &FsLockContext {
self.extension()
.group2()
.call_once(|| ThinBox::new_unsize(FsLockContext::new()))
.downcast_ref()
.unwrap()
}
fn fs_lock_context(&self) -> Option<&FsLockContext> {
Some(self.extension().group2().get()?.downcast_ref().unwrap())
}
}

View File

@ -15,6 +15,7 @@ pub use id_bitmap::IdBitmap;
pub use inode::{
Extension, Inode, InodeIo, InodeType, Metadata, MknodType, Permission, SymbolicLink,
};
pub use inode_ext::InodeExt;
pub use inode_mode::InodeMode;
pub(crate) use inode_mode::{chmod, mkmod, perms_to_mask, who_and_perms_to_mask, who_to_mask};
pub use open_args::OpenArgs;
@ -38,6 +39,7 @@ mod flock;
mod fs;
mod id_bitmap;
mod inode;
mod inode_ext;
mod inode_mode;
pub mod ioctl_defs;
mod open_args;

View File

@ -13,10 +13,10 @@ use aster_systree::{
SysAttr, SysBranchNode, SysNode, SysNodeId, SysNodeType, SysObj, SysStr, SysSymlink,
};
use super::Extension;
use crate::{
fs::{
inode_handle::FileIo,
notify::FsEventPublisher,
utils::{
AccessMode, DirentVisitor, FallocMode, FileSystem, Inode, InodeIo, InodeMode,
InodeType, Metadata, MknodType, StatusFlags, SymbolicLink, mkmod,
@ -54,7 +54,7 @@ pub(in crate::fs) trait SysTreeInodeTy: Send + Sync + 'static {
fn set_mode(&self, mode: InodeMode) -> Result<()>;
fn fs_event_publisher(&self) -> &FsEventPublisher;
fn extension(&self) -> &Extension;
fn parent(&self) -> &Weak<Self>;
@ -593,8 +593,8 @@ impl<KInode: SysTreeInodeTy + Send + Sync + 'static> Inode for KInode {
true
}
default fn fs_event_publisher(&self) -> &FsEventPublisher {
self.fs_event_publisher()
default fn extension(&self) -> &Extension {
self.extension()
}
}

View File

@ -15,6 +15,7 @@
#![feature(panic_can_unwind)]
#![feature(register_tool)]
#![feature(min_specialization)]
#![feature(thin_box)]
#![feature(trait_alias)]
#![feature(associated_type_defaults)]
#![feature(try_with_capacity)]