diff --git a/kernel/src/fs/cgroupfs/inode.rs b/kernel/src/fs/cgroupfs/inode.rs index d6ce3b968..74a087e17 100644 --- a/kernel/src/fs/cgroupfs/inode.rs +++ b/kernel/src/fs/cgroupfs/inode.rs @@ -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, /// 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 { diff --git a/kernel/src/fs/configfs/inode.rs b/kernel/src/fs/configfs/inode.rs index b4097ca32..509fa5b69 100644 --- a/kernel/src/fs/configfs/inode.rs +++ b/kernel/src/fs/configfs/inode.rs @@ -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, /// 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.this.upgrade().expect("Weak ref invalid") } + + fn extension(&self) -> &Extension { + &self.extension + } } impl Inode for ConfigInode { diff --git a/kernel/src/fs/devpts/mod.rs b/kernel/src/fs/devpts/mod.rs index 12c815b75..67ad2027a 100644 --- a/kernel/src/fs/devpts/mod.rs +++ b/kernel/src/fs/devpts/mod.rs @@ -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, slaves: RwLock)>>, metadata: RwLock, - fs_event_publisher: FsEventPublisher, + extension: Extension, fs: Weak, } @@ -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 { diff --git a/kernel/src/fs/devpts/ptmx.rs b/kernel/src/fs/devpts/ptmx.rs index 770433640..121c0dbd0 100644 --- a/kernel/src/fs/devpts/ptmx.rs +++ b/kernel/src/fs/devpts/ptmx.rs @@ -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, - 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 { diff --git a/kernel/src/fs/devpts/slave.rs b/kernel/src/fs/devpts/slave.rs index b38620094..c66372157 100644 --- a/kernel/src/fs/devpts/slave.rs +++ b/kernel/src/fs/devpts/slave.rs @@ -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, metadata: RwLock, - fs_event_publisher: FsEventPublisher, + extension: Extension, fs: Weak, } @@ -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 { diff --git a/kernel/src/fs/exfat/inode.rs b/kernel/src/fs/exfat/inode.rs index f661c89bc..b7d6e2874 100644 --- a/kernel/src/fs/exfat/inode.rs +++ b/kernel/src/fs/exfat/inode.rs @@ -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, 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 } } diff --git a/kernel/src/fs/ext2/impl_for_vfs/inode.rs b/kernel/src/fs/ext2/impl_for_vfs/inode.rs index bacc35bc2..eb39d8e74 100644 --- a/kernel/src/fs/ext2/impl_for_vfs/inode.rs +++ b/kernel/src/fs/ext2/impl_for_vfs/inode.rs @@ -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( diff --git a/kernel/src/fs/ext2/inode.rs b/kernel/src/fs/ext2/inode.rs index 780ccf75f..9c90cd604 100644 --- a/kernel/src/fs/ext2/inode.rs +++ b/kernel/src/fs/ext2/inode.rs @@ -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, fs: Weak, extension: Extension, - fs_event_publisher: FsEventPublisher, xattr: Option, } @@ -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); diff --git a/kernel/src/fs/inode_handle/mod.rs b/kernel/src/fs/inode_handle/mod.rs index 8385d1ec1..665940f12 100644 --- a/kernel/src/fs/inode_handle/mod.rs +++ b/kernel/src/fs/inode_handle/mod.rs @@ -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 { - 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::() 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::() { - Some(list) => list, - None => extension.get_or_put_default::(), - }; + 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::() + 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::() { - Some(list) => list, - None => extension.get_or_put_default::(), - }; + 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::() - { + if let Some(flock_list) = self.path.inode().fs_lock_context().map(|c| c.flock_list()) { flock_list.unlock(req_owner); } } diff --git a/kernel/src/fs/notify/inotify.rs b/kernel/src/fs/notify/inotify.rs index 0ab6971a6..c64702273 100644 --- a/kernel/src/fs/notify/inotify.rs +++ b/kernel/src/fs/notify/inotify.rs @@ -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 { - 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() diff --git a/kernel/src/fs/notify/mod.rs b/kernel/src/fs/notify/mod.rs index 3d8e47bbe..fad8b9052 100644 --- a/kernel/src/fs/notify/mod.rs +++ b/kernel/src/fs/notify/mod.rs @@ -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, events: FsEvents, name: Option) { - inode.fs_event_publisher().publish_event(events, name); + if let Some(publisher) = inode.fs_event_publisher() { + publisher.publish_event(events, name); + } } diff --git a/kernel/src/fs/overlayfs/fs.rs b/kernel/src/fs/overlayfs/fs.rs index fa1281cc2..546fc54b9 100644 --- a/kernel/src/fs/overlayfs/fs.rs +++ b/kernel/src/fs/overlayfs/fs.rs @@ -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, - /// FS event publisher. - fs_event_publisher: FsEventPublisher, + /// The extension of this inode. + extension: Extension, /// The parent inode. `None` for root inode. parent: Option>, /// 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> { @@ -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; diff --git a/kernel/src/fs/path/dentry.rs b/kernel/src/fs/path/dentry.rs index cbca75e78..f7f4667ba 100644 --- a/kernel/src/fs/path/dentry.rs +++ b/kernel/src/fs/path/dentry.rs @@ -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 diff --git a/kernel/src/fs/pipe/anon_pipe.rs b/kernel/src/fs/pipe/anon_pipe.rs index 44d52426b..de10d6652 100644 --- a/kernel/src/fs/pipe/anon_pipe.rs +++ b/kernel/src/fs/pipe/anon_pipe.rs @@ -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; diff --git a/kernel/src/fs/procfs/template/dir.rs b/kernel/src/fs/procfs/template/dir.rs index 8da263f19..f339a7455 100644 --- a/kernel/src/fs/procfs/template/dir.rs +++ b/kernel/src/fs/procfs/template/dir.rs @@ -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 InodeIo for ProcDir { impl Inode for ProcDir { 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; fn set_mode(&self, mode: InodeMode) -> Result<()>; diff --git a/kernel/src/fs/procfs/template/file.rs b/kernel/src/fs/procfs/template/file.rs index 43c0b6a30..509aa076f 100644 --- a/kernel/src/fs/procfs/template/file.rs +++ b/kernel/src/fs/procfs/template/file.rs @@ -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 InodeIo for ProcFile { impl Inode for ProcFile { 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; fn set_mode(&self, mode: InodeMode) -> Result<()>; diff --git a/kernel/src/fs/procfs/template/mod.rs b/kernel/src/fs/procfs/template/mod.rs index 4aa031a8b..bb664f9fe 100644 --- a/kernel/src/fs/procfs/template/mod.rs +++ b/kernel/src/fs/procfs/template/mod.rs @@ -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, - fs_event_publisher: FsEventPublisher, + extension: Extension, fs: Weak, is_volatile: bool, } @@ -34,7 +31,7 @@ impl Common { pub fn new(metadata: Metadata, fs: Weak, 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 } } diff --git a/kernel/src/fs/procfs/template/sym.rs b/kernel/src/fs/procfs/template/sym.rs index 46bc326b7..27d3831b9 100644 --- a/kernel/src/fs/procfs/template/sym.rs +++ b/kernel/src/fs/procfs/template/sym.rs @@ -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 InodeIo for ProcSym { impl Inode for ProcSym { 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; fn set_mode(&self, mode: InodeMode) -> Result<()>; diff --git a/kernel/src/fs/pseudofs.rs b/kernel/src/fs/pseudofs.rs index 73570bea2..e3d8b1248 100644 --- a/kernel/src/fs/pseudofs.rs +++ b/kernel/src/fs/pseudofs.rs @@ -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, - fs_events_publisher: FsEventPublisher, + extension: Extension, fs: Weak, } @@ -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 { diff --git a/kernel/src/fs/ramfs/fs.rs b/kernel/src/fs/ramfs/fs.rs index 3e23c5856..355062b84 100644 --- a/kernel/src/fs/ramfs/fs.rs +++ b/kernel/src/fs/ramfs/fs.rs @@ -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, /// 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( diff --git a/kernel/src/fs/ramfs/memfd.rs b/kernel/src/fs/ramfs/memfd.rs index 4d3453bc9..f0aaf7acd 100644 --- a/kernel/src/fs/ramfs/memfd.rs +++ b/kernel/src/fs/ramfs/memfd.rs @@ -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; fn set_group(&self, gid: Gid) -> Result<()>; fn page_cache(&self) -> Option>; - fn extension(&self) -> Option<&Extension>; - fn fs_event_publisher(&self) -> &FsEventPublisher; + fn extension(&self) -> &Extension; fn set_xattr( &self, name: XattrName, diff --git a/kernel/src/fs/sysfs/inode.rs b/kernel/src/fs/sysfs/inode.rs index f12f201e7..f2e226b39 100644 --- a/kernel/src/fs/sysfs/inode.rs +++ b/kernel/src/fs/sysfs/inode.rs @@ -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, /// 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 } } diff --git a/kernel/src/fs/utils/inode.rs b/kernel/src/fs/utils/inode.rs index 2242c566f..97e64f39a 100644 --- a/kernel/src/fs/utils/inode.rs +++ b/kernel/src/fs/utils/inode.rs @@ -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>>, + group1: Once>, + group2: Once>, } 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`. - pub fn get(&self) -> Option> { - let read_guard = self.data.read(); - read_guard - .get(&TypeId::of::()) - .and_then(|arc_any| Arc::downcast::(arc_any.clone()).ok()) + /// Gets the first extension group. + pub fn group1(&self) -> &Once> { + &self.group1 } - /// Try to get an object of `Arc`. If no object of the type exists, - /// put the default value for the type, then return it. - pub fn get_or_put_default(&self) -> Arc { - let mut write_guard = self.data.write(); - let type_id = TypeId::of::(); - let arc_any = write_guard.entry(type_id).or_insert_with(|| { - let obj = T::default(); - Arc::new(obj) as Arc - }); - Arc::downcast::(arc_any.clone()).unwrap() - } - - /// Put an object of `Arc`. If there exists one object of the type, - /// then the old one is returned. - #[expect(dead_code)] - pub fn put(&self, obj: Arc) -> Option> { - let mut write_guard = self.data.write(); - write_guard - .insert(TypeId::of::(), obj as Arc) - .and_then(|arc_any| Arc::downcast::(arc_any).ok()) - } - - /// Delete an object of `Arc`. If there exists one object of the type, - /// then the old one is returned. - #[expect(dead_code)] - pub fn del(&self) -> Option> { - let mut write_guard = self.data.write(); - write_guard - .remove(&TypeId::of::()) - .and_then(|arc_any| Arc::downcast::(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> { + &self.group2 } } diff --git a/kernel/src/fs/utils/inode_ext.rs b/kernel/src/fs/utils/inode_ext.rs new file mode 100644 index 000000000..472b8c78c --- /dev/null +++ b/kernel/src/fs/utils/inode_ext.rs @@ -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()) + } +} diff --git a/kernel/src/fs/utils/mod.rs b/kernel/src/fs/utils/mod.rs index c58e01755..bd3beeb7c 100644 --- a/kernel/src/fs/utils/mod.rs +++ b/kernel/src/fs/utils/mod.rs @@ -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; diff --git a/kernel/src/fs/utils/systree_inode.rs b/kernel/src/fs/utils/systree_inode.rs index a76533a26..587e1e6d0 100644 --- a/kernel/src/fs/utils/systree_inode.rs +++ b/kernel/src/fs/utils/systree_inode.rs @@ -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; @@ -593,8 +593,8 @@ impl Inode for KInode { true } - default fn fs_event_publisher(&self) -> &FsEventPublisher { - self.fs_event_publisher() + default fn extension(&self) -> &Extension { + self.extension() } } diff --git a/kernel/src/lib.rs b/kernel/src/lib.rs index 52c528521..fe491a879 100644 --- a/kernel/src/lib.rs +++ b/kernel/src/lib.rs @@ -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)]