Add fsnotify infrastructure for filesystem events
Signed-off-by: Zhenchen Wang <m202372036@hust.edu.cn>
This commit is contained in:
parent
1a536d31b0
commit
6eef70a634
|
|
@ -11,7 +11,10 @@ use crate::{
|
|||
fs::{
|
||||
cgroupfs::systree_node::CgroupSystem,
|
||||
registry::{FsProperties, FsType},
|
||||
utils::{systree_inode::SysTreeInodeTy, FileSystem, FsFlags, Inode, SuperBlock},
|
||||
utils::{
|
||||
systree_inode::SysTreeInodeTy, FileSystem, FsEventSubscriberStats, FsFlags, Inode,
|
||||
SuperBlock,
|
||||
},
|
||||
Result,
|
||||
},
|
||||
prelude::*,
|
||||
|
|
@ -21,6 +24,7 @@ use crate::{
|
|||
pub(super) struct CgroupFs {
|
||||
sb: SuperBlock,
|
||||
root: Arc<dyn Inode>,
|
||||
fs_event_subscriber_stats: FsEventSubscriberStats,
|
||||
}
|
||||
|
||||
// Magic number for cgroupfs v2 (taken from Linux)
|
||||
|
|
@ -43,6 +47,7 @@ impl CgroupFs {
|
|||
Arc::new(Self {
|
||||
sb,
|
||||
root: root_inode,
|
||||
fs_event_subscriber_stats: FsEventSubscriberStats::new(),
|
||||
})
|
||||
}
|
||||
}
|
||||
|
|
@ -64,6 +69,10 @@ impl FileSystem for CgroupFs {
|
|||
fn sb(&self) -> SuperBlock {
|
||||
self.sb.clone()
|
||||
}
|
||||
|
||||
fn fs_event_subscriber_stats(&self) -> &FsEventSubscriberStats {
|
||||
&self.fs_event_subscriber_stats
|
||||
}
|
||||
}
|
||||
|
||||
pub(super) struct CgroupFsType;
|
||||
|
|
|
|||
|
|
@ -8,6 +8,7 @@ use super::fs::CgroupFs;
|
|||
use crate::{
|
||||
fs::{
|
||||
cgroupfs::CgroupNode,
|
||||
notify::FsEventPublisher,
|
||||
path::{is_dot, is_dotdot},
|
||||
utils::{
|
||||
systree_inode::{SysTreeInodeTy, SysTreeNodeKind},
|
||||
|
|
@ -23,6 +24,8 @@ pub(super) struct CgroupInode {
|
|||
node_kind: SysTreeNodeKind,
|
||||
/// The metadata of this inode.
|
||||
metadata: Metadata,
|
||||
/// FS event publisher.
|
||||
fs_event_publisher: FsEventPublisher,
|
||||
/// The file mode (permissions) of this inode, protected by a lock.
|
||||
mode: RwLock<InodeMode>,
|
||||
/// Weak reference to the parent inode.
|
||||
|
|
@ -44,6 +47,7 @@ impl SysTreeInodeTy for CgroupInode {
|
|||
Arc::new_cyclic(|this| Self {
|
||||
node_kind,
|
||||
metadata,
|
||||
fs_event_publisher: FsEventPublisher::new(),
|
||||
mode: RwLock::new(mode),
|
||||
parent,
|
||||
this: this.clone(),
|
||||
|
|
@ -58,6 +62,10 @@ impl SysTreeInodeTy for CgroupInode {
|
|||
&self.metadata
|
||||
}
|
||||
|
||||
fn fs_event_publisher(&self) -> &FsEventPublisher {
|
||||
&self.fs_event_publisher
|
||||
}
|
||||
|
||||
fn mode(&self) -> Result<InodeMode> {
|
||||
Ok(*self.mode.read())
|
||||
}
|
||||
|
|
|
|||
|
|
@ -11,7 +11,10 @@ use crate::{
|
|||
fs::{
|
||||
configfs::systree_node::ConfigRootNode,
|
||||
registry::{FsProperties, FsType},
|
||||
utils::{systree_inode::SysTreeInodeTy, FileSystem, FsFlags, Inode, SuperBlock},
|
||||
utils::{
|
||||
systree_inode::SysTreeInodeTy, FileSystem, FsEventSubscriberStats, FsFlags, Inode,
|
||||
SuperBlock,
|
||||
},
|
||||
Result,
|
||||
},
|
||||
prelude::*,
|
||||
|
|
@ -26,6 +29,7 @@ use crate::{
|
|||
pub struct ConfigFs {
|
||||
sb: SuperBlock,
|
||||
root: Arc<dyn Inode>,
|
||||
fs_event_subscriber_stats: FsEventSubscriberStats,
|
||||
}
|
||||
|
||||
// Magic number for `ConfigFs` (taken from Linux).
|
||||
|
|
@ -48,6 +52,7 @@ impl ConfigFs {
|
|||
Arc::new(Self {
|
||||
sb,
|
||||
root: root_inode,
|
||||
fs_event_subscriber_stats: FsEventSubscriberStats::new(),
|
||||
})
|
||||
}
|
||||
}
|
||||
|
|
@ -69,6 +74,10 @@ impl FileSystem for ConfigFs {
|
|||
fn sb(&self) -> SuperBlock {
|
||||
self.sb.clone()
|
||||
}
|
||||
|
||||
fn fs_event_subscriber_stats(&self) -> &FsEventSubscriberStats {
|
||||
&self.fs_event_subscriber_stats
|
||||
}
|
||||
}
|
||||
|
||||
pub(super) struct ConfigFsType;
|
||||
|
|
|
|||
|
|
@ -7,6 +7,7 @@ use ostd::sync::RwLock;
|
|||
use crate::{
|
||||
fs::{
|
||||
configfs::fs::ConfigFs,
|
||||
notify::FsEventPublisher,
|
||||
utils::{
|
||||
systree_inode::{SysTreeInodeTy, SysTreeNodeKind},
|
||||
FileSystem, Inode, InodeMode, Metadata,
|
||||
|
|
@ -21,6 +22,8 @@ pub struct ConfigInode {
|
|||
node_kind: SysTreeNodeKind,
|
||||
/// The metadata of this inode.
|
||||
metadata: Metadata,
|
||||
/// FS event publisher.
|
||||
fs_event_publisher: FsEventPublisher,
|
||||
/// The file mode (permissions) of this inode, protected by a lock.
|
||||
mode: RwLock<InodeMode>,
|
||||
/// Weak reference to the parent inode.
|
||||
|
|
@ -42,6 +45,7 @@ impl SysTreeInodeTy for ConfigInode {
|
|||
Arc::new_cyclic(|this| Self {
|
||||
node_kind,
|
||||
metadata,
|
||||
fs_event_publisher: FsEventPublisher::new(),
|
||||
mode: RwLock::new(mode),
|
||||
parent,
|
||||
this: this.clone(),
|
||||
|
|
@ -69,6 +73,10 @@ 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")
|
||||
}
|
||||
|
|
|
|||
|
|
@ -9,15 +9,16 @@ use id_alloc::IdAlloc;
|
|||
|
||||
pub use self::ptmx::Ptmx;
|
||||
use self::slave::PtySlaveInode;
|
||||
use super::utils::{InodeIo, MknodType, StatusFlags};
|
||||
use super::utils::{MknodType, StatusFlags};
|
||||
use crate::{
|
||||
device::PtyMaster,
|
||||
fs::{
|
||||
device::{Device, DeviceType},
|
||||
notify::FsEventPublisher,
|
||||
registry::{FsProperties, FsType},
|
||||
utils::{
|
||||
mkmod, DirEntryVecExt, DirentVisitor, FileSystem, FsFlags, Inode, InodeMode, InodeType,
|
||||
Metadata, SuperBlock, NAME_MAX,
|
||||
mkmod, DirEntryVecExt, DirentVisitor, FileSystem, FsEventSubscriberStats, FsFlags,
|
||||
Inode, InodeIo, InodeMode, InodeType, Metadata, SuperBlock, NAME_MAX,
|
||||
},
|
||||
},
|
||||
prelude::*,
|
||||
|
|
@ -47,6 +48,7 @@ pub struct DevPts {
|
|||
sb: SuperBlock,
|
||||
root: Arc<RootInode>,
|
||||
index_alloc: Mutex<IdAlloc>,
|
||||
fs_event_subscriber_stats: FsEventSubscriberStats,
|
||||
this: Weak<Self>,
|
||||
}
|
||||
|
||||
|
|
@ -56,6 +58,7 @@ impl DevPts {
|
|||
sb: SuperBlock::new(DEVPTS_MAGIC, BLOCK_SIZE, NAME_MAX),
|
||||
root: RootInode::new(weak_self.clone()),
|
||||
index_alloc: Mutex::new(IdAlloc::with_capacity(MAX_PTY_NUM)),
|
||||
fs_event_subscriber_stats: FsEventSubscriberStats::new(),
|
||||
this: weak_self.clone(),
|
||||
})
|
||||
}
|
||||
|
|
@ -109,6 +112,10 @@ impl FileSystem for DevPts {
|
|||
fn sb(&self) -> SuperBlock {
|
||||
self.sb.clone()
|
||||
}
|
||||
|
||||
fn fs_event_subscriber_stats(&self) -> &FsEventSubscriberStats {
|
||||
&self.fs_event_subscriber_stats
|
||||
}
|
||||
}
|
||||
|
||||
struct DevPtsType;
|
||||
|
|
@ -144,6 +151,7 @@ struct RootInode {
|
|||
ptmx: Arc<Ptmx>,
|
||||
slaves: RwLock<SlotVec<(String, Arc<dyn Inode>)>>,
|
||||
metadata: RwLock<Metadata>,
|
||||
fs_event_publisher: FsEventPublisher,
|
||||
fs: Weak<DevPts>,
|
||||
}
|
||||
|
||||
|
|
@ -153,6 +161,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(),
|
||||
fs,
|
||||
})
|
||||
}
|
||||
|
|
@ -191,6 +200,10 @@ impl Inode for RootInode {
|
|||
*self.metadata.read()
|
||||
}
|
||||
|
||||
fn fs_event_publisher(&self) -> &FsEventPublisher {
|
||||
&self.fs_event_publisher
|
||||
}
|
||||
|
||||
fn ino(&self) -> u64 {
|
||||
self.metadata.read().ino as _
|
||||
}
|
||||
|
|
|
|||
|
|
@ -5,7 +5,8 @@ use device_id::{DeviceId, MajorId, MinorId};
|
|||
use super::*;
|
||||
use crate::fs::{
|
||||
inode_handle::FileIo,
|
||||
utils::{AccessMode, StatusFlags},
|
||||
notify::FsEventPublisher,
|
||||
utils::{AccessMode, InodeIo, StatusFlags},
|
||||
};
|
||||
|
||||
/// Same major number with Linux.
|
||||
|
|
@ -20,6 +21,7 @@ const PTMX_MINOR_NUM: u32 = 2;
|
|||
pub struct Ptmx {
|
||||
inner: Inner,
|
||||
metadata: RwLock<Metadata>,
|
||||
fs_event_publisher: FsEventPublisher,
|
||||
}
|
||||
|
||||
#[derive(Clone)]
|
||||
|
|
@ -36,6 +38,7 @@ impl Ptmx {
|
|||
&inner,
|
||||
)),
|
||||
inner,
|
||||
fs_event_publisher: FsEventPublisher::new(),
|
||||
})
|
||||
}
|
||||
|
||||
|
|
@ -79,6 +82,10 @@ impl Inode for Ptmx {
|
|||
*self.metadata.read()
|
||||
}
|
||||
|
||||
fn fs_event_publisher(&self) -> &FsEventPublisher {
|
||||
&self.fs_event_publisher
|
||||
}
|
||||
|
||||
fn ino(&self) -> u64 {
|
||||
self.metadata.read().ino as _
|
||||
}
|
||||
|
|
|
|||
|
|
@ -8,7 +8,8 @@ use crate::{
|
|||
device::PtySlave,
|
||||
fs::{
|
||||
inode_handle::FileIo,
|
||||
utils::{AccessMode, StatusFlags},
|
||||
notify::FsEventPublisher,
|
||||
utils::{AccessMode, InodeIo, StatusFlags},
|
||||
},
|
||||
};
|
||||
|
||||
|
|
@ -19,6 +20,7 @@ const SLAVE_MAJOR_NUM: u32 = 3;
|
|||
pub struct PtySlaveInode {
|
||||
device: Arc<PtySlave>,
|
||||
metadata: RwLock<Metadata>,
|
||||
fs_event_publisher: FsEventPublisher,
|
||||
fs: Weak<DevPts>,
|
||||
}
|
||||
|
||||
|
|
@ -32,6 +34,7 @@ impl PtySlaveInode {
|
|||
device.as_ref(),
|
||||
)),
|
||||
device,
|
||||
fs_event_publisher: FsEventPublisher::new(),
|
||||
fs,
|
||||
})
|
||||
}
|
||||
|
|
@ -78,6 +81,10 @@ impl Inode for PtySlaveInode {
|
|||
*self.metadata.read()
|
||||
}
|
||||
|
||||
fn fs_event_publisher(&self) -> &FsEventPublisher {
|
||||
&self.fs_event_publisher
|
||||
}
|
||||
|
||||
fn ino(&self) -> u64 {
|
||||
self.metadata.read().ino as _
|
||||
}
|
||||
|
|
|
|||
|
|
@ -26,7 +26,10 @@ use crate::{
|
|||
fs::{
|
||||
exfat::{constants::*, inode::Ino},
|
||||
registry::{FsProperties, FsType},
|
||||
utils::{CachePage, FileSystem, FsFlags, Inode, PageCache, PageCacheBackend, SuperBlock},
|
||||
utils::{
|
||||
CachePage, FileSystem, FsEventSubscriberStats, FsFlags, Inode, PageCache,
|
||||
PageCacheBackend, SuperBlock,
|
||||
},
|
||||
},
|
||||
prelude::*,
|
||||
};
|
||||
|
|
@ -53,6 +56,8 @@ pub struct ExfatFs {
|
|||
|
||||
//A global lock, We need to hold the mutex before accessing bitmap or inode, otherwise there will be deadlocks.
|
||||
mutex: Mutex<()>,
|
||||
|
||||
fs_event_subscriber_stats: FsEventSubscriberStats,
|
||||
}
|
||||
|
||||
const FAT_LRU_CACHE_SIZE: usize = 1024;
|
||||
|
|
@ -80,6 +85,7 @@ impl ExfatFs {
|
|||
)),
|
||||
meta_cache: PageCache::with_capacity(fs_size, weak_self.clone() as _).unwrap(),
|
||||
mutex: Mutex::new(()),
|
||||
fs_event_subscriber_stats: FsEventSubscriberStats::new(),
|
||||
});
|
||||
|
||||
// TODO: if the main superblock is corrupted, should we load the backup?
|
||||
|
|
@ -417,6 +423,10 @@ impl FileSystem for ExfatFs {
|
|||
fn sb(&self) -> SuperBlock {
|
||||
SuperBlock::new(BOOT_SIGNATURE as u64, self.sector_size(), MAX_NAME_LENGTH)
|
||||
}
|
||||
|
||||
fn fs_event_subscriber_stats(&self) -> &FsEventSubscriberStats {
|
||||
&self.fs_event_subscriber_stats
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, Default)]
|
||||
|
|
|
|||
|
|
@ -27,6 +27,7 @@ use super::{
|
|||
use crate::{
|
||||
fs::{
|
||||
exfat::{dentry::ExfatDentryIterator, fat::ExfatChain, fs::ExfatFs},
|
||||
notify::FsEventPublisher,
|
||||
path::{is_dot, is_dot_or_dotdot, is_dotdot},
|
||||
utils::{
|
||||
mkmod, CachePage, DirentVisitor, Extension, Inode, InodeIo, InodeMode, InodeType,
|
||||
|
|
@ -78,6 +79,7 @@ impl FatAttr {
|
|||
pub struct ExfatInode {
|
||||
inner: RwMutex<ExfatInodeInner>,
|
||||
extension: Extension,
|
||||
fs_event_publisher: FsEventPublisher,
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
|
|
@ -862,6 +864,7 @@ 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();
|
||||
|
|
@ -972,6 +975,7 @@ 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) {
|
||||
|
|
@ -1735,4 +1739,8 @@ impl Inode for ExfatInode {
|
|||
fn extension(&self) -> Option<&Extension> {
|
||||
Some(&self.extension)
|
||||
}
|
||||
|
||||
fn fs_event_publisher(&self) -> &FsEventPublisher {
|
||||
&self.fs_event_publisher
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -11,7 +11,7 @@ use super::{
|
|||
};
|
||||
use crate::fs::{
|
||||
registry::{FsProperties, FsType},
|
||||
utils::{FileSystem, FsFlags},
|
||||
utils::{FileSystem, FsEventSubscriberStats, FsFlags},
|
||||
};
|
||||
|
||||
/// The root inode number.
|
||||
|
|
@ -28,6 +28,7 @@ pub struct Ext2 {
|
|||
inode_size: usize,
|
||||
block_size: usize,
|
||||
group_descriptors_segment: USegment,
|
||||
fs_event_subscriber_stats: FsEventSubscriberStats,
|
||||
self_ref: Weak<Self>,
|
||||
}
|
||||
|
||||
|
|
@ -98,6 +99,7 @@ impl Ext2 {
|
|||
block_device,
|
||||
super_block: RwMutex::new(Dirty::new(super_block)),
|
||||
group_descriptors_segment,
|
||||
fs_event_subscriber_stats: FsEventSubscriberStats::new(),
|
||||
self_ref: weak_ref.clone(),
|
||||
});
|
||||
Ok(ext2)
|
||||
|
|
@ -437,6 +439,10 @@ impl Ext2 {
|
|||
fn block_idx(&self, bid: Ext2Bid) -> Ext2Bid {
|
||||
bid % self.blocks_per_group
|
||||
}
|
||||
|
||||
pub fn fs_event_subscriber_stats(&self) -> &FsEventSubscriberStats {
|
||||
&self.fs_event_subscriber_stats
|
||||
}
|
||||
}
|
||||
|
||||
pub(super) struct Ext2Type;
|
||||
|
|
|
|||
|
|
@ -5,7 +5,7 @@ use ostd::sync::RwMutexReadGuard;
|
|||
use crate::{
|
||||
fs::{
|
||||
ext2::{utils::Dirty, Ext2, SuperBlock as Ext2SuperBlock, MAGIC_NUM as EXT2_MAGIC},
|
||||
utils::{FileSystem, Inode, SuperBlock, NAME_MAX},
|
||||
utils::{FileSystem, FsEventSubscriberStats, Inode, SuperBlock, NAME_MAX},
|
||||
},
|
||||
prelude::*,
|
||||
};
|
||||
|
|
@ -30,6 +30,10 @@ impl FileSystem for Ext2 {
|
|||
fn sb(&self) -> SuperBlock {
|
||||
SuperBlock::from(self.super_block())
|
||||
}
|
||||
|
||||
fn fs_event_subscriber_stats(&self) -> &FsEventSubscriberStats {
|
||||
self.fs_event_subscriber_stats()
|
||||
}
|
||||
}
|
||||
|
||||
impl From<RwMutexReadGuard<'_, Dirty<Ext2SuperBlock>>> for SuperBlock {
|
||||
|
|
|
|||
|
|
@ -5,6 +5,7 @@ use core::time::Duration;
|
|||
use crate::{
|
||||
fs::{
|
||||
ext2::{FilePerm, Inode as Ext2Inode},
|
||||
notify::FsEventPublisher,
|
||||
utils::{
|
||||
DirentVisitor, Extension, FallocMode, FileSystem, Inode, InodeIo, InodeMode, InodeType,
|
||||
Metadata, MknodType, StatusFlags, SymbolicLink, XattrName, XattrNamespace,
|
||||
|
|
@ -200,6 +201,10 @@ impl Inode for Ext2Inode {
|
|||
Some(self.extension())
|
||||
}
|
||||
|
||||
fn fs_event_publisher(&self) -> &FsEventPublisher {
|
||||
self.fs_event_publisher()
|
||||
}
|
||||
|
||||
fn set_xattr(
|
||||
&self,
|
||||
name: XattrName,
|
||||
|
|
|
|||
|
|
@ -20,6 +20,7 @@ use super::{
|
|||
};
|
||||
use crate::{
|
||||
fs::{
|
||||
notify::FsEventPublisher,
|
||||
path::{is_dot, is_dot_or_dotdot, is_dotdot},
|
||||
utils::{
|
||||
Extension, FallocMode, Inode as _, InodeMode, Metadata, Permission, XattrName,
|
||||
|
|
@ -43,6 +44,7 @@ pub struct Inode {
|
|||
inner: RwMutex<InodeInner>,
|
||||
fs: Weak<Ext2>,
|
||||
extension: Extension,
|
||||
fs_event_publisher: FsEventPublisher,
|
||||
xattr: Option<Xattr>,
|
||||
}
|
||||
|
||||
|
|
@ -63,6 +65,7 @@ impl Inode {
|
|||
inner: RwMutex::new(InodeInner::new(desc, weak_self.clone(), fs.clone())),
|
||||
fs,
|
||||
extension: Extension::new(),
|
||||
fs_event_publisher: FsEventPublisher::new(),
|
||||
})
|
||||
}
|
||||
|
||||
|
|
@ -107,6 +110,10 @@ 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);
|
||||
|
|
|
|||
|
|
@ -8,7 +8,7 @@ use core::fmt::Display;
|
|||
|
||||
use ostd::io::IoMem;
|
||||
|
||||
use super::inode_handle::InodeHandle;
|
||||
use super::{inode_handle::InodeHandle, path::Path};
|
||||
use crate::{
|
||||
fs::{
|
||||
file_table::FdFlags,
|
||||
|
|
@ -143,6 +143,12 @@ impl dyn FileLike {
|
|||
.ok_or_else(|| Error::with_message(Errno::ENOTSOCK, "the file is not a socket"))
|
||||
}
|
||||
|
||||
pub fn path(&self) -> Option<&Path> {
|
||||
self.as_inode_handle_or_err()
|
||||
.ok()
|
||||
.map(|inode_handle| inode_handle.path())
|
||||
}
|
||||
|
||||
pub fn as_inode_handle_or_err(&self) -> Result<&InodeHandle> {
|
||||
self.downcast_ref().ok_or_else(|| {
|
||||
Error::with_message(Errno::EINVAL, "the file is not related to an inode")
|
||||
|
|
|
|||
|
|
@ -11,6 +11,7 @@ pub mod file_handle;
|
|||
pub mod file_table;
|
||||
pub mod fs_resolver;
|
||||
pub mod inode_handle;
|
||||
pub mod notify;
|
||||
pub mod overlayfs;
|
||||
pub mod path;
|
||||
pub mod pipe;
|
||||
|
|
|
|||
|
|
@ -0,0 +1,430 @@
|
|||
// SPDX-License-Identifier: MPL-2.0
|
||||
|
||||
use alloc::{sync::Arc, vec::Vec};
|
||||
use core::{
|
||||
any::Any,
|
||||
sync::atomic::{AtomicBool, AtomicU32, Ordering},
|
||||
};
|
||||
|
||||
use atomic_integer_wrapper::define_atomic_version_of_integer_like_type;
|
||||
use bitflags::bitflags;
|
||||
use ostd::sync::RwLock;
|
||||
|
||||
use crate::{
|
||||
fs::{file_handle::FileLike, path::Path, utils::AccessMode},
|
||||
prelude::*,
|
||||
};
|
||||
|
||||
use super::utils::{Inode, InodeType};
|
||||
|
||||
/// Publishes filesystem events to subscribers.
|
||||
///
|
||||
/// Each inode has an associated `FsEventPublisher` that maintains a list of
|
||||
/// subscribers interested in filesystem events. When an event occurs, the publisher
|
||||
/// notifies all subscribers whose interesting events match the event.
|
||||
pub struct FsEventPublisher {
|
||||
/// List of FS event subscribers.
|
||||
subscribers: RwLock<Vec<Arc<dyn FsEventSubscriber>>>,
|
||||
/// All interesting FS event types (aggregated from all subscribers).
|
||||
all_interesting_events: AtomicFsEvents,
|
||||
/// Whether this publisher still accepts new subscribers.
|
||||
accepts_new_subscribers: AtomicBool,
|
||||
}
|
||||
|
||||
impl Debug for FsEventPublisher {
|
||||
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
|
||||
let subscribers = self.subscribers.read();
|
||||
write!(
|
||||
f,
|
||||
"FsEventPublisher: num_subscribers: {}",
|
||||
subscribers.len()
|
||||
)?;
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
impl Default for FsEventPublisher {
|
||||
fn default() -> Self {
|
||||
Self::new()
|
||||
}
|
||||
}
|
||||
|
||||
impl FsEventPublisher {
|
||||
pub fn new() -> Self {
|
||||
Self {
|
||||
subscribers: RwLock::new(Vec::new()),
|
||||
all_interesting_events: AtomicFsEvents::new(FsEvents::empty()),
|
||||
accepts_new_subscribers: AtomicBool::new(true),
|
||||
}
|
||||
}
|
||||
|
||||
/// Adds a subscriber to this publisher.
|
||||
pub fn add_subscriber(&self, subscriber: Arc<dyn FsEventSubscriber>) -> bool {
|
||||
if !self.accepts_new_subscribers.load(Ordering::Acquire) {
|
||||
return false;
|
||||
}
|
||||
let mut subscribers = self.subscribers.write();
|
||||
let current = self.all_interesting_events.load(Ordering::Relaxed);
|
||||
self.all_interesting_events
|
||||
.store(current | subscriber.interesting_events(), Ordering::Relaxed);
|
||||
subscribers.push(subscriber);
|
||||
true
|
||||
}
|
||||
|
||||
/// Removes a subscriber from this publisher.
|
||||
pub fn remove_subscriber(&self, subscriber: &Arc<dyn FsEventSubscriber>) -> bool {
|
||||
let mut subscribers = self.subscribers.write();
|
||||
let orig_len = subscribers.len();
|
||||
subscribers.retain(|m| !Arc::ptr_eq(m, subscriber));
|
||||
let removed = subscribers.len() != orig_len;
|
||||
if removed {
|
||||
subscriber.deliver_event(FsEvents::IN_IGNORED, None);
|
||||
self.recalc_interesting_events(&subscribers);
|
||||
}
|
||||
removed
|
||||
}
|
||||
|
||||
/// Removes all subscribers from this publisher.
|
||||
pub fn remove_all_subscribers(&self) -> usize {
|
||||
let mut subscribers = self.subscribers.write();
|
||||
for subscriber in subscribers.iter() {
|
||||
subscriber.deliver_event(FsEvents::IN_IGNORED, None);
|
||||
}
|
||||
let num_subscribers = subscribers.len();
|
||||
subscribers.clear();
|
||||
|
||||
self.all_interesting_events
|
||||
.store(FsEvents::empty(), Ordering::Relaxed);
|
||||
|
||||
num_subscribers
|
||||
}
|
||||
|
||||
/// Forbids new subscribers from attaching to this publisher.
|
||||
pub fn disable_new_subscribers(&self) {
|
||||
self.accepts_new_subscribers.store(false, Ordering::Release);
|
||||
}
|
||||
|
||||
/// Broadcasts an event to all the subscribers of this publisher.
|
||||
pub fn publish_event(&self, events: FsEvents, name: Option<String>) {
|
||||
let interesting = self.all_interesting_events.load(Ordering::Relaxed);
|
||||
if !interesting.intersects(events) {
|
||||
return;
|
||||
}
|
||||
|
||||
let subscribers = self.subscribers.read();
|
||||
for subscriber in subscribers.iter() {
|
||||
subscriber.deliver_event(events, name.clone());
|
||||
}
|
||||
}
|
||||
|
||||
/// Recalculates the aggregated interesting events from all subscribers.
|
||||
fn recalc_interesting_events(&self, subscribers: &[Arc<dyn FsEventSubscriber>]) {
|
||||
let mut new_events = FsEvents::empty();
|
||||
for subscriber in subscribers.iter() {
|
||||
new_events |= subscriber.interesting_events();
|
||||
}
|
||||
self.all_interesting_events
|
||||
.store(new_events, Ordering::Relaxed);
|
||||
}
|
||||
|
||||
/// Updates the aggregated events when a subscriber's interesting events change.
|
||||
pub fn update_subscriber_events(&self) {
|
||||
let subscribers = self.subscribers.read();
|
||||
let mut new_events = FsEvents::empty();
|
||||
for subscriber in subscribers.iter() {
|
||||
new_events |= subscriber.interesting_events();
|
||||
}
|
||||
self.all_interesting_events
|
||||
.store(new_events, Ordering::Relaxed);
|
||||
}
|
||||
|
||||
/// Finds a subscriber and applies an action if found.
|
||||
///
|
||||
/// The matcher should return `Some(T)` if the subscriber matches and processing
|
||||
/// should stop, or `None` to continue searching.
|
||||
pub fn find_subscriber_and_process<F, T>(&self, mut matcher: F) -> Option<T>
|
||||
where
|
||||
F: FnMut(&Arc<dyn FsEventSubscriber>) -> Option<T>,
|
||||
{
|
||||
let subscribers = self.subscribers.read();
|
||||
for subscriber in subscribers.iter() {
|
||||
if let Some(result) = matcher(subscriber) {
|
||||
return Some(result);
|
||||
}
|
||||
}
|
||||
None
|
||||
}
|
||||
}
|
||||
|
||||
/// Represents a subscriber to filesystem events on an `FsEventPublisher`.
|
||||
///
|
||||
/// A subscriber receives notifications from a publisher when filesystem events occur
|
||||
/// that match the subscriber's interesting events. The subscriber specifies which events
|
||||
/// it is interested in using `FsEvents`, which define the types of events (e.g.,
|
||||
/// read, write, modify, delete) the subscriber wants to be notified about. When an event
|
||||
/// occurs, the publisher (attached to an inode) broadcasts it to all subscribers whose
|
||||
/// interesting events match the event type.
|
||||
pub trait FsEventSubscriber: Any + Send + Sync {
|
||||
/// Delivers a filesystem event notification to the subscriber.
|
||||
///
|
||||
/// Invariant: This method must not sleep or perform blocking operations. The publisher
|
||||
/// may hold a spin lock when calling this method.
|
||||
fn deliver_event(&self, events: FsEvents, name: Option<String>);
|
||||
/// Returns the events that this subscriber is interested in.
|
||||
fn interesting_events(&self) -> FsEvents;
|
||||
}
|
||||
|
||||
bitflags! {
|
||||
/// Represents filesystem events that have occurred.
|
||||
///
|
||||
/// These events are used to notify subscribers about specific filesystem actions.
|
||||
/// Subscribers specify which events they are interested in to filter and receive
|
||||
/// only the events they care about.
|
||||
pub struct FsEvents: u32 {
|
||||
const ACCESS = 0x00000001; // File was accessed
|
||||
const MODIFY = 0x00000002; // File was modified
|
||||
const ATTRIB = 0x00000004; // Metadata changed
|
||||
const CLOSE_WRITE = 0x00000008; // Writable file was closed
|
||||
const CLOSE_NOWRITE = 0x00000010; // Unwritable file closed
|
||||
const OPEN = 0x00000020; // File was opened
|
||||
const MOVED_FROM = 0x00000040; // File was moved from X
|
||||
const MOVED_TO = 0x00000080; // File was moved to Y
|
||||
const CREATE = 0x00000100; // Subfile was created
|
||||
const DELETE = 0x00000200; // Subfile was deleted
|
||||
const DELETE_SELF = 0x00000400; // Self was deleted
|
||||
const MOVE_SELF = 0x00000800; // Self was moved
|
||||
const OPEN_EXEC = 0x00001000; // File was opened for exec
|
||||
const UNMOUNT = 0x00002000; // Inode on umount fs
|
||||
const Q_OVERFLOW = 0x00004000; // Event queued overflowed
|
||||
const ERROR = 0x00008000; // Filesystem Error (fanotify)
|
||||
const IN_IGNORED = 0x00008000; // Last inotify event here (inotify)
|
||||
const OPEN_PERM = 0x00010000; // Open event in a permission hook
|
||||
const ACCESS_PERM = 0x00020000; // Access event in a permissions hook
|
||||
const OPEN_EXEC_PERM = 0x00040000; // Open/exec event in a permission hook
|
||||
const EVENT_ON_CHILD = 0x08000000; // Set on inode mark that cares about things that happen to its children.
|
||||
const RENAME = 0x10000000; // File was renamed
|
||||
const DN_MULTISHOT = 0x20000000; // dnotify multishot
|
||||
const ISDIR = 0x40000000; // Event occurred against dir
|
||||
}
|
||||
}
|
||||
|
||||
impl From<u32> for FsEvents {
|
||||
fn from(value: u32) -> Self {
|
||||
Self::from_bits_truncate(value)
|
||||
}
|
||||
}
|
||||
|
||||
impl From<FsEvents> for u32 {
|
||||
fn from(value: FsEvents) -> Self {
|
||||
value.bits()
|
||||
}
|
||||
}
|
||||
|
||||
define_atomic_version_of_integer_like_type!(FsEvents, {
|
||||
#[derive(Debug)]
|
||||
pub(super) struct AtomicFsEvents(AtomicU32);
|
||||
});
|
||||
|
||||
/// Notifies that a file was accessed.
|
||||
pub fn on_access(file: &Arc<dyn FileLike>) {
|
||||
// TODO: Check fmode flags (FMODE_NONOTIFY, FMODE_NONOTIFY_PERM).
|
||||
if let Some(path) = file.path() {
|
||||
if !path
|
||||
.inode()
|
||||
.fs()
|
||||
.fs_event_subscriber_stats()
|
||||
.has_any_subscribers()
|
||||
{
|
||||
return;
|
||||
}
|
||||
notify_parent(path, FsEvents::ACCESS, path.effective_name());
|
||||
}
|
||||
}
|
||||
|
||||
/// Notifies that a file was modified.
|
||||
pub fn on_modify(file: &Arc<dyn FileLike>) {
|
||||
// TODO: Check fmode flags (FMODE_NONOTIFY, FMODE_NONOTIFY_PERM).
|
||||
let Some(path) = file.path() else {
|
||||
return;
|
||||
};
|
||||
|
||||
if !path
|
||||
.inode()
|
||||
.fs()
|
||||
.fs_event_subscriber_stats()
|
||||
.has_any_subscribers()
|
||||
{
|
||||
return;
|
||||
}
|
||||
notify_parent(path, FsEvents::MODIFY, path.effective_name());
|
||||
}
|
||||
|
||||
/// Notifies that a path's content was changed.
|
||||
pub fn on_change(path: &Path) {
|
||||
if !path
|
||||
.inode()
|
||||
.fs()
|
||||
.fs_event_subscriber_stats()
|
||||
.has_any_subscribers()
|
||||
{
|
||||
return;
|
||||
}
|
||||
notify_parent(path, FsEvents::MODIFY, path.effective_name());
|
||||
}
|
||||
|
||||
/// Notifies that a file was deleted from a directory.
|
||||
pub fn on_delete(
|
||||
dir_inode: &Arc<dyn Inode>,
|
||||
inode: &Arc<dyn Inode>,
|
||||
name: impl FnOnce() -> String,
|
||||
) {
|
||||
if !dir_inode
|
||||
.fs()
|
||||
.fs_event_subscriber_stats()
|
||||
.has_any_subscribers()
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
let name = name();
|
||||
if inode.type_() == InodeType::Dir {
|
||||
notify_inode(dir_inode, FsEvents::DELETE | FsEvents::ISDIR, Some(name))
|
||||
} else {
|
||||
notify_inode(dir_inode, FsEvents::DELETE, Some(name))
|
||||
}
|
||||
}
|
||||
|
||||
/// Notifies that an inode's link count changed.
|
||||
pub fn on_link_count(inode: &Arc<dyn Inode>) {
|
||||
if !inode.fs().fs_event_subscriber_stats().has_any_subscribers() {
|
||||
return;
|
||||
}
|
||||
notify_inode(inode, FsEvents::ATTRIB, None);
|
||||
}
|
||||
|
||||
/// Notifies that an inode was removed (link count reached 0).
|
||||
pub fn on_inode_removed(inode: &Arc<dyn Inode>) {
|
||||
if !inode.fs().fs_event_subscriber_stats().has_any_subscribers() {
|
||||
return;
|
||||
}
|
||||
notify_inode(inode, FsEvents::DELETE_SELF, None);
|
||||
}
|
||||
|
||||
/// Notifies that a file was linked to a directory.
|
||||
pub fn on_link(dir_inode: &Arc<dyn Inode>, inode: &Arc<dyn Inode>, name: String) {
|
||||
if !dir_inode
|
||||
.fs()
|
||||
.fs_event_subscriber_stats()
|
||||
.has_any_subscribers()
|
||||
{
|
||||
return;
|
||||
}
|
||||
notify_inode(inode, FsEvents::ATTRIB, None);
|
||||
notify_inode(dir_inode, FsEvents::CREATE, Some(name));
|
||||
}
|
||||
|
||||
/// Notifies that a directory was created.
|
||||
pub fn on_mkdir(dir_path: &Path, name: String) {
|
||||
if !dir_path
|
||||
.inode()
|
||||
.fs()
|
||||
.fs_event_subscriber_stats()
|
||||
.has_any_subscribers()
|
||||
{
|
||||
return;
|
||||
}
|
||||
notify_inode(
|
||||
dir_path.inode(),
|
||||
FsEvents::CREATE | FsEvents::ISDIR,
|
||||
Some(name),
|
||||
);
|
||||
}
|
||||
|
||||
/// Notifies that a file was created.
|
||||
pub fn on_create(file_path: &Path, name: String) {
|
||||
if !file_path
|
||||
.inode()
|
||||
.fs()
|
||||
.fs_event_subscriber_stats()
|
||||
.has_any_subscribers()
|
||||
{
|
||||
return;
|
||||
}
|
||||
notify_inode(file_path.inode(), FsEvents::CREATE, Some(name));
|
||||
}
|
||||
|
||||
/// Notifies that a file was opened.
|
||||
pub fn on_open(file: &Arc<dyn FileLike>) {
|
||||
// TODO: Check fmode flags (FMODE_NONOTIFY, FMODE_NONOTIFY_PERM).
|
||||
if let Some(path) = file.path() {
|
||||
if !path
|
||||
.inode()
|
||||
.fs()
|
||||
.fs_event_subscriber_stats()
|
||||
.has_any_subscribers()
|
||||
{
|
||||
return;
|
||||
}
|
||||
notify_parent(path, FsEvents::OPEN, path.effective_name());
|
||||
}
|
||||
}
|
||||
|
||||
/// Notifies that a file was closed.
|
||||
pub fn on_close(file: &Arc<dyn FileLike>) {
|
||||
// TODO: Check fmode flags (FMODE_NONOTIFY, FMODE_NONOTIFY_PERM).
|
||||
if let Some(path) = file.path() {
|
||||
if !path
|
||||
.inode()
|
||||
.fs()
|
||||
.fs_event_subscriber_stats()
|
||||
.has_any_subscribers()
|
||||
{
|
||||
return;
|
||||
}
|
||||
let events = match file.access_mode() {
|
||||
AccessMode::O_RDONLY => FsEvents::CLOSE_NOWRITE,
|
||||
_ => FsEvents::CLOSE_WRITE,
|
||||
};
|
||||
notify_parent(path, events, path.effective_name());
|
||||
}
|
||||
}
|
||||
|
||||
/// Notifies that a file's attributes changed.
|
||||
pub fn on_attr_change(path: &Path) {
|
||||
if !path
|
||||
.inode()
|
||||
.fs()
|
||||
.fs_event_subscriber_stats()
|
||||
.has_any_subscribers()
|
||||
{
|
||||
return;
|
||||
}
|
||||
notify_parent(path, FsEvents::ATTRIB, path.effective_name());
|
||||
}
|
||||
|
||||
/// Notifies a path's parent and the path itself about filesystem events.
|
||||
///
|
||||
/// If the parent is watching or if subscribers have registered interesting events with
|
||||
/// parent and name information, notifies the parent with child name info.
|
||||
/// Otherwise, notifies only the child without name information.
|
||||
/// This function is already called after filesystem checking in the callers.
|
||||
fn notify_parent(path: &Path, mut events: FsEvents, name: String) {
|
||||
if path.inode().type_() == InodeType::Dir {
|
||||
events |= FsEvents::ISDIR;
|
||||
}
|
||||
|
||||
let parent = path.effective_parent();
|
||||
if let Some(parent) = parent {
|
||||
notify_inode(parent.inode(), events, Some(name));
|
||||
}
|
||||
notify_inode(path.inode(), events, None);
|
||||
}
|
||||
|
||||
/// Sends a filesystem notification event to all subscribers of an inode.
|
||||
///
|
||||
/// This is the main entry point for fsnotify. The VFS layer calls hook-specific
|
||||
/// 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);
|
||||
}
|
||||
|
|
@ -21,12 +21,14 @@ use crate::{
|
|||
fs::{
|
||||
fs_resolver::FsPath,
|
||||
inode_handle::FileIo,
|
||||
notify::FsEventPublisher,
|
||||
path::Path,
|
||||
registry::{FsProperties, FsType},
|
||||
utils::{
|
||||
mkmod, AccessMode, DirentCounter, DirentVisitor, FallocMode, FileSystem, FsFlags,
|
||||
Inode, InodeIo, InodeMode, InodeType, Metadata, MknodType, StatusFlags, SuperBlock,
|
||||
SymbolicLink, XattrName, XattrNamespace, XattrSetFlags, NAME_MAX, XATTR_VALUE_MAX_LEN,
|
||||
mkmod, AccessMode, DirentCounter, DirentVisitor, FallocMode, FileSystem,
|
||||
FsEventSubscriberStats, FsFlags, Inode, InodeIo, InodeMode, InodeType, Metadata,
|
||||
MknodType, StatusFlags, SuperBlock, SymbolicLink, XattrName, XattrNamespace,
|
||||
XattrSetFlags, NAME_MAX, XATTR_VALUE_MAX_LEN,
|
||||
},
|
||||
},
|
||||
prelude::*,
|
||||
|
|
@ -52,6 +54,8 @@ pub struct OverlayFs {
|
|||
sb: OverlaySB,
|
||||
/// Unique inode number generator.
|
||||
next_ino: AtomicU64,
|
||||
/// FS event subscriber stats for this file system.
|
||||
fs_event_subscriber_stats: FsEventSubscriberStats,
|
||||
/// Weak self reference.
|
||||
self_: Weak<OverlayFs>,
|
||||
}
|
||||
|
|
@ -87,6 +91,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 parent inode. `None` for root inode.
|
||||
parent: Option<Arc<OverlayInode>>,
|
||||
/// The mutable upper regular inode.
|
||||
|
|
@ -126,6 +132,7 @@ impl OverlayFs {
|
|||
config: OverlayConfig::default(),
|
||||
sb: OverlaySB,
|
||||
next_ino: AtomicU64::new(0),
|
||||
fs_event_subscriber_stats: FsEventSubscriberStats::new(),
|
||||
self_: weak.clone(),
|
||||
}))
|
||||
}
|
||||
|
|
@ -166,6 +173,7 @@ impl FileSystem for OverlayFs {
|
|||
ino,
|
||||
type_: InodeType::Dir,
|
||||
name_upon_creation: SpinLock::new(String::from("")),
|
||||
fs_event_publisher: FsEventPublisher::new(),
|
||||
parent: None,
|
||||
upper: Mutex::new(Some(upper_inode)),
|
||||
upper_is_opaque: false,
|
||||
|
|
@ -190,6 +198,10 @@ impl FileSystem for OverlayFs {
|
|||
// TODO: Fill the super block with valid field values.
|
||||
SuperBlock::new(OVERLAY_FS_MAGIC, BLOCK_SIZE, NAME_MAX)
|
||||
}
|
||||
|
||||
fn fs_event_subscriber_stats(&self) -> &FsEventSubscriberStats {
|
||||
&self.fs_event_subscriber_stats
|
||||
}
|
||||
}
|
||||
|
||||
impl OverlayFs {
|
||||
|
|
@ -267,6 +279,7 @@ impl OverlayInode {
|
|||
ino: new_upper.ino(),
|
||||
type_,
|
||||
name_upon_creation: SpinLock::new(String::from(name)),
|
||||
fs_event_publisher: FsEventPublisher::new(),
|
||||
parent: Some(self.self_.upgrade().unwrap()),
|
||||
upper: Mutex::new(Some(new_upper)),
|
||||
upper_is_opaque,
|
||||
|
|
@ -439,6 +452,10 @@ impl OverlayInode {
|
|||
self.type_
|
||||
}
|
||||
|
||||
pub fn fs_event_publisher(&self) -> &FsEventPublisher {
|
||||
&self.fs_event_publisher
|
||||
}
|
||||
|
||||
pub fn page_cache(&self) -> Option<Arc<Vmo>> {
|
||||
let _ = self.get_top_valid_inode().page_cache()?;
|
||||
// Do copy-up for the potential memory mapping operations
|
||||
|
|
@ -676,6 +693,7 @@ impl OverlayInode {
|
|||
ino,
|
||||
type_: type_.unwrap(),
|
||||
name_upon_creation: SpinLock::new(String::from(name)),
|
||||
fs_event_publisher: FsEventPublisher::new(),
|
||||
parent: Some(self.self_.upgrade().unwrap()),
|
||||
upper: Mutex::new(upper_child),
|
||||
upper_is_opaque,
|
||||
|
|
@ -916,6 +934,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 ino(&self) -> u64;
|
||||
fn type_(&self) -> InodeType;
|
||||
fn mode(&self) -> Result<InodeMode>;
|
||||
|
|
|
|||
|
|
@ -5,8 +5,9 @@ use core::sync::atomic::{AtomicU32, Ordering};
|
|||
use hashbrown::HashMap;
|
||||
use ostd::sync::RwMutexWriteGuard;
|
||||
|
||||
use super::is_dot_or_dotdot;
|
||||
use super::{is_dot, is_dot_or_dotdot, is_dotdot};
|
||||
use crate::{
|
||||
fs,
|
||||
fs::utils::{Inode, InodeMode, InodeType, MknodType},
|
||||
prelude::*,
|
||||
};
|
||||
|
|
@ -229,8 +230,9 @@ impl Dentry {
|
|||
);
|
||||
|
||||
if dentry.is_dentry_cacheable() {
|
||||
children.upgrade().insert(name, dentry.clone());
|
||||
children.upgrade().insert(name.clone(), dentry.clone());
|
||||
}
|
||||
fs::notify::on_link(dentry.parent().unwrap().inode(), dentry.inode(), name);
|
||||
Ok(())
|
||||
}
|
||||
|
||||
|
|
@ -240,13 +242,39 @@ impl Dentry {
|
|||
return_errno!(Errno::ENOTDIR);
|
||||
}
|
||||
|
||||
if is_dot_or_dotdot(name) {
|
||||
return_errno_with_message!(Errno::EINVAL, "unlink on . or ..");
|
||||
}
|
||||
|
||||
let children = self.children.upread();
|
||||
children.check_mountpoint(name)?;
|
||||
|
||||
self.inode.unlink(name)?;
|
||||
|
||||
let mut children = children.upgrade();
|
||||
children.delete(name);
|
||||
let cached_child = children.delete(name);
|
||||
|
||||
let child_inode = match cached_child {
|
||||
Some(child) => {
|
||||
// Cache hit: use the cached dentry
|
||||
child.inode().clone()
|
||||
}
|
||||
None => {
|
||||
// Cache miss: need to lookup from the underlying filesystem
|
||||
drop(children);
|
||||
self.inode.lookup(name)?
|
||||
}
|
||||
};
|
||||
|
||||
self.inode.unlink(name)?;
|
||||
fs::notify::on_link_count(&child_inode);
|
||||
if child_inode.metadata().nlinks == 0 {
|
||||
fs::notify::on_inode_removed(&child_inode);
|
||||
let deleted_watches = child_inode.fsnotify_publisher().remove_all_subscribers();
|
||||
child_inode
|
||||
.fs()
|
||||
.fsnotify_info()
|
||||
.remove_subscribers(deleted_watches);
|
||||
}
|
||||
fs::notify::on_delete(self.inode(), &child_inode, String::from(name));
|
||||
Ok(())
|
||||
}
|
||||
|
||||
|
|
@ -256,13 +284,41 @@ impl Dentry {
|
|||
return_errno!(Errno::ENOTDIR);
|
||||
}
|
||||
|
||||
if is_dot(name) {
|
||||
return_errno_with_message!(Errno::EINVAL, "rmdir on .");
|
||||
}
|
||||
if is_dotdot(name) {
|
||||
return_errno_with_message!(Errno::ENOTEMPTY, "rmdir on ..");
|
||||
}
|
||||
|
||||
let children = self.children.upread();
|
||||
children.check_mountpoint(name)?;
|
||||
|
||||
self.inode.rmdir(name)?;
|
||||
|
||||
let mut children = children.upgrade();
|
||||
children.delete(name);
|
||||
let cached_child = children.delete(name);
|
||||
|
||||
let child_inode = match cached_child {
|
||||
Some(child) => {
|
||||
// Cache hit: use the cached dentry
|
||||
child.inode().clone()
|
||||
}
|
||||
None => {
|
||||
// Cache miss: need to lookup from the underlying filesystem
|
||||
drop(children);
|
||||
self.inode.lookup(name)?
|
||||
}
|
||||
};
|
||||
|
||||
self.inode.rmdir(name)?;
|
||||
if child_inode.metadata().nlinks == 0 {
|
||||
fs::notify::on_inode_removed(&child_inode);
|
||||
let deleted_watches = child_inode.fsnotify_publisher().remove_all_subscribers();
|
||||
child_inode
|
||||
.fs()
|
||||
.fsnotify_info()
|
||||
.remove_subscribers(deleted_watches);
|
||||
}
|
||||
fs::notify::on_delete(self.inode(), &child_inode, String::from(name));
|
||||
Ok(())
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -145,9 +145,7 @@ impl Path {
|
|||
///
|
||||
/// If it is the root of a mount, it will go up to the mountpoint
|
||||
/// to get the name of the mountpoint recursively.
|
||||
//
|
||||
// FIXME: This method needs to be aware of the current process's root path.
|
||||
fn effective_name(&self) -> String {
|
||||
pub fn effective_name(&self) -> String {
|
||||
if !self.is_mount_root() {
|
||||
return self.dentry.name();
|
||||
}
|
||||
|
|
@ -167,7 +165,7 @@ impl Path {
|
|||
///
|
||||
/// If it is the root of a mount, it will go up to the mountpoint
|
||||
/// to get the parent of the mountpoint recursively.
|
||||
fn effective_parent(&self) -> Option<Self> {
|
||||
pub fn effective_parent(&self) -> Option<Self> {
|
||||
if !self.is_mount_root() {
|
||||
return Some(Self::new(self.mount.clone(), self.dentry.parent().unwrap()));
|
||||
}
|
||||
|
|
|
|||
|
|
@ -23,7 +23,10 @@ use crate::{
|
|||
fs::{
|
||||
procfs::{filesystems::FileSystemsFileOps, stat::StatFileOps},
|
||||
registry::{FsProperties, FsType},
|
||||
utils::{mkmod, DirEntryVecExt, FileSystem, FsFlags, Inode, SuperBlock, NAME_MAX},
|
||||
utils::{
|
||||
mkmod, DirEntryVecExt, FileSystem, FsEventSubscriberStats, FsFlags, Inode, SuperBlock,
|
||||
NAME_MAX,
|
||||
},
|
||||
},
|
||||
prelude::*,
|
||||
process::{
|
||||
|
|
@ -64,6 +67,7 @@ struct ProcFs {
|
|||
sb: SuperBlock,
|
||||
root: Arc<dyn Inode>,
|
||||
inode_allocator: AtomicU64,
|
||||
fs_event_subscriber_stats: FsEventSubscriberStats,
|
||||
}
|
||||
|
||||
impl ProcFs {
|
||||
|
|
@ -72,6 +76,7 @@ impl ProcFs {
|
|||
sb: SuperBlock::new(PROC_MAGIC, BLOCK_SIZE, NAME_MAX),
|
||||
root: RootDirOps::new_inode(weak_fs.clone()),
|
||||
inode_allocator: AtomicU64::new(PROC_ROOT_INO + 1),
|
||||
fs_event_subscriber_stats: FsEventSubscriberStats::new(),
|
||||
})
|
||||
}
|
||||
|
||||
|
|
@ -96,6 +101,10 @@ impl FileSystem for ProcFs {
|
|||
fn sb(&self) -> SuperBlock {
|
||||
self.sb.clone()
|
||||
}
|
||||
|
||||
fn fs_event_subscriber_stats(&self) -> &FsEventSubscriberStats {
|
||||
&self.fs_event_subscriber_stats
|
||||
}
|
||||
}
|
||||
|
||||
struct ProcFsType;
|
||||
|
|
|
|||
|
|
@ -9,6 +9,7 @@ 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,
|
||||
|
|
@ -95,6 +96,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 ino(&self) -> u64;
|
||||
fn mode(&self) -> Result<InodeMode>;
|
||||
fn set_mode(&self, mode: InodeMode) -> Result<()>;
|
||||
|
|
|
|||
|
|
@ -6,8 +6,11 @@ use inherit_methods_macro::inherit_methods;
|
|||
|
||||
use super::{Common, ProcFs};
|
||||
use crate::{
|
||||
fs::utils::{
|
||||
FileSystem, Inode, InodeIo, InodeMode, InodeType, Metadata, StatusFlags, SymbolicLink,
|
||||
fs::{
|
||||
notify::FsEventPublisher,
|
||||
utils::{
|
||||
FileSystem, Inode, InodeIo, InodeMode, InodeType, Metadata, StatusFlags, SymbolicLink,
|
||||
},
|
||||
},
|
||||
prelude::*,
|
||||
process::{Gid, Uid},
|
||||
|
|
@ -66,6 +69,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 ino(&self) -> u64;
|
||||
fn mode(&self) -> Result<InodeMode>;
|
||||
fn set_mode(&self, mode: InodeMode) -> Result<()>;
|
||||
|
|
|
|||
|
|
@ -10,7 +10,10 @@ pub(super) use self::{
|
|||
};
|
||||
use super::{ProcFs, BLOCK_SIZE};
|
||||
use crate::{
|
||||
fs::utils::{FileSystem, InodeMode, InodeType, Metadata},
|
||||
fs::{
|
||||
notify::FsEventPublisher,
|
||||
utils::{FileSystem, InodeMode, InodeType, Metadata},
|
||||
},
|
||||
prelude::*,
|
||||
process::{Gid, Uid},
|
||||
};
|
||||
|
|
@ -22,6 +25,7 @@ mod sym;
|
|||
|
||||
struct Common {
|
||||
metadata: RwLock<Metadata>,
|
||||
fs_event_publisher: FsEventPublisher,
|
||||
fs: Weak<dyn FileSystem>,
|
||||
is_volatile: bool,
|
||||
}
|
||||
|
|
@ -30,6 +34,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(),
|
||||
fs,
|
||||
is_volatile,
|
||||
}
|
||||
|
|
@ -109,4 +114,8 @@ impl Common {
|
|||
pub fn is_volatile(&self) -> bool {
|
||||
self.is_volatile
|
||||
}
|
||||
|
||||
pub fn fs_event_publisher(&self) -> &FsEventPublisher {
|
||||
&self.fs_event_publisher
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -6,8 +6,11 @@ use inherit_methods_macro::inherit_methods;
|
|||
|
||||
use super::{Common, ProcFs};
|
||||
use crate::{
|
||||
fs::utils::{
|
||||
FileSystem, Inode, InodeIo, InodeMode, InodeType, Metadata, StatusFlags, SymbolicLink,
|
||||
fs::{
|
||||
notify::FsEventPublisher,
|
||||
utils::{
|
||||
FileSystem, Inode, InodeIo, InodeMode, InodeType, Metadata, StatusFlags, SymbolicLink,
|
||||
},
|
||||
},
|
||||
prelude::*,
|
||||
process::{Gid, Uid},
|
||||
|
|
@ -63,6 +66,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 ino(&self) -> u64;
|
||||
fn mode(&self) -> Result<InodeMode>;
|
||||
fn set_mode(&self, mode: InodeMode) -> Result<()>;
|
||||
|
|
|
|||
|
|
@ -7,9 +7,11 @@ use spin::Once;
|
|||
use super::utils::{InodeIo, StatusFlags};
|
||||
use crate::{
|
||||
fs::{
|
||||
notify::FsEventPublisher,
|
||||
registry::{FsProperties, FsType},
|
||||
utils::{
|
||||
mkmod, FileSystem, FsFlags, Inode, InodeMode, InodeType, Metadata, SuperBlock, NAME_MAX,
|
||||
mkmod, FileSystem, FsEventSubscriberStats, FsFlags, Inode, InodeMode, InodeType,
|
||||
Metadata, SuperBlock, NAME_MAX,
|
||||
},
|
||||
},
|
||||
prelude::*,
|
||||
|
|
@ -22,6 +24,7 @@ pub struct PseudoFs {
|
|||
name: &'static str,
|
||||
sb: SuperBlock,
|
||||
root: Arc<dyn Inode>,
|
||||
fs_event_subscriber_stats: FsEventSubscriberStats,
|
||||
}
|
||||
|
||||
impl FileSystem for PseudoFs {
|
||||
|
|
@ -41,6 +44,10 @@ impl FileSystem for PseudoFs {
|
|||
fn sb(&self) -> SuperBlock {
|
||||
self.sb.clone()
|
||||
}
|
||||
|
||||
fn fs_event_subscriber_stats(&self) -> &FsEventSubscriberStats {
|
||||
&self.fs_event_subscriber_stats
|
||||
}
|
||||
}
|
||||
|
||||
impl PseudoFs {
|
||||
|
|
@ -63,6 +70,7 @@ impl PseudoFs {
|
|||
aster_block::BLOCK_SIZE,
|
||||
weak_fs.clone(),
|
||||
)),
|
||||
fs_event_subscriber_stats: FsEventSubscriberStats::new(),
|
||||
})
|
||||
})
|
||||
}
|
||||
|
|
@ -174,6 +182,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,
|
||||
fs: Weak<PseudoFs>,
|
||||
}
|
||||
|
||||
|
|
@ -206,6 +215,7 @@ impl PseudoInode {
|
|||
};
|
||||
PseudoInode {
|
||||
metadata: SpinLock::new(metadata),
|
||||
fs_events_publisher: FsEventPublisher::new(),
|
||||
fs,
|
||||
}
|
||||
}
|
||||
|
|
@ -250,6 +260,10 @@ impl Inode for PseudoInode {
|
|||
*self.metadata.lock()
|
||||
}
|
||||
|
||||
fn fs_event_publisher(&self) -> &FsEventPublisher {
|
||||
&self.fs_events_publisher
|
||||
}
|
||||
|
||||
fn ino(&self) -> u64 {
|
||||
self.metadata.lock().ino
|
||||
}
|
||||
|
|
|
|||
|
|
@ -19,14 +19,15 @@ use crate::{
|
|||
fs::{
|
||||
device::Device,
|
||||
inode_handle::FileIo,
|
||||
notify::FsEventPublisher,
|
||||
path::{is_dot, is_dot_or_dotdot, is_dotdot},
|
||||
pipe::NamedPipe,
|
||||
registry::{FsProperties, FsType},
|
||||
utils::{
|
||||
mkmod, AccessMode, CStr256, CachePage, DirentVisitor, Extension, FallocMode,
|
||||
FileSystem, FsFlags, Inode, InodeIo, InodeMode, InodeType, Metadata, MknodType,
|
||||
PageCache, PageCacheBackend, Permission, StatusFlags, SuperBlock, SymbolicLink,
|
||||
XattrName, XattrNamespace, XattrSetFlags,
|
||||
FileSystem, FsEventSubscriberStats, FsFlags, Inode, InodeIo, InodeMode, InodeType,
|
||||
Metadata, MknodType, PageCache, PageCacheBackend, Permission, StatusFlags, SuperBlock,
|
||||
SymbolicLink, XattrName, XattrNamespace, XattrSetFlags,
|
||||
},
|
||||
},
|
||||
prelude::*,
|
||||
|
|
@ -43,6 +44,8 @@ pub struct RamFs {
|
|||
root: Arc<RamInode>,
|
||||
/// An inode allocator
|
||||
inode_allocator: AtomicU64,
|
||||
/// FS event subscriber stats for this file system
|
||||
fs_event_subscriber_stats: FsEventSubscriberStats,
|
||||
}
|
||||
|
||||
impl RamFs {
|
||||
|
|
@ -62,8 +65,10 @@ 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(),
|
||||
})
|
||||
}
|
||||
|
||||
|
|
@ -89,6 +94,10 @@ impl FileSystem for RamFs {
|
|||
fn sb(&self) -> SuperBlock {
|
||||
self.sb.clone()
|
||||
}
|
||||
|
||||
fn fs_event_subscriber_stats(&self) -> &FsEventSubscriberStats {
|
||||
&self.fs_event_subscriber_stats
|
||||
}
|
||||
}
|
||||
|
||||
/// An inode of `RamFs`.
|
||||
|
|
@ -107,6 +116,8 @@ pub(super) struct RamInode {
|
|||
fs: Weak<RamFs>,
|
||||
/// Extensions
|
||||
extension: Extension,
|
||||
/// FS event publisher
|
||||
fs_event_publisher: FsEventPublisher,
|
||||
/// Extended attributes
|
||||
xattr: RamXattr,
|
||||
}
|
||||
|
|
@ -411,6 +422,7 @@ impl RamInode {
|
|||
this: weak_self.clone(),
|
||||
fs: Arc::downgrade(fs),
|
||||
extension: Extension::new(),
|
||||
fs_event_publisher: FsEventPublisher::new(),
|
||||
xattr: RamXattr::new(),
|
||||
})
|
||||
}
|
||||
|
|
@ -424,6 +436,7 @@ impl RamInode {
|
|||
this: weak_self.clone(),
|
||||
fs: Arc::downgrade(fs),
|
||||
extension: Extension::new(),
|
||||
fs_event_publisher: FsEventPublisher::new(),
|
||||
xattr: RamXattr::new(),
|
||||
})
|
||||
}
|
||||
|
|
@ -443,6 +456,7 @@ impl RamInode {
|
|||
this: Weak::new(),
|
||||
fs: Weak::new(),
|
||||
extension: Extension::new(),
|
||||
fs_event_publisher: FsEventPublisher::new(),
|
||||
xattr: RamXattr::new(),
|
||||
}
|
||||
}
|
||||
|
|
@ -456,6 +470,7 @@ impl RamInode {
|
|||
this: weak_self.clone(),
|
||||
fs: Arc::downgrade(fs),
|
||||
extension: Extension::new(),
|
||||
fs_event_publisher: FsEventPublisher::new(),
|
||||
xattr: RamXattr::new(),
|
||||
})
|
||||
}
|
||||
|
|
@ -475,6 +490,7 @@ impl RamInode {
|
|||
this: weak_self.clone(),
|
||||
fs: Arc::downgrade(fs),
|
||||
extension: Extension::new(),
|
||||
fs_event_publisher: FsEventPublisher::new(),
|
||||
xattr: RamXattr::new(),
|
||||
})
|
||||
}
|
||||
|
|
@ -488,6 +504,7 @@ impl RamInode {
|
|||
this: weak_self.clone(),
|
||||
fs: Arc::downgrade(fs),
|
||||
extension: Extension::new(),
|
||||
fs_event_publisher: FsEventPublisher::new(),
|
||||
xattr: RamXattr::new(),
|
||||
})
|
||||
}
|
||||
|
|
@ -501,6 +518,7 @@ impl RamInode {
|
|||
this: weak_self.clone(),
|
||||
fs: Arc::downgrade(fs),
|
||||
extension: Extension::new(),
|
||||
fs_event_publisher: FsEventPublisher::new(),
|
||||
xattr: RamXattr::new(),
|
||||
})
|
||||
}
|
||||
|
|
@ -1182,6 +1200,10 @@ impl Inode for RamInode {
|
|||
Some(&self.extension)
|
||||
}
|
||||
|
||||
fn fs_event_publisher(&self) -> &FsEventPublisher {
|
||||
&self.fs_event_publisher
|
||||
}
|
||||
|
||||
fn set_xattr(
|
||||
&self,
|
||||
name: XattrName,
|
||||
|
|
|
|||
|
|
@ -22,6 +22,7 @@ use crate::{
|
|||
file_handle::{FileLike, Mappable},
|
||||
file_table::FdFlags,
|
||||
inode_handle::{do_fallocate_util, do_resize_util, do_seek_util},
|
||||
notify::FsEventPublisher,
|
||||
path::{check_open_util, RESERVED_MOUNT_ID},
|
||||
tmpfs::TmpFs,
|
||||
utils::{
|
||||
|
|
@ -178,6 +179,7 @@ impl Inode for MemfdInode {
|
|||
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 set_xattr(
|
||||
&self,
|
||||
name: XattrName,
|
||||
|
|
|
|||
|
|
@ -6,7 +6,10 @@ use crate::{
|
|||
fs::{
|
||||
registry::{FsProperties, FsType},
|
||||
sysfs::{self, inode::SysFsInode},
|
||||
utils::{systree_inode::SysTreeInodeTy, FileSystem, FsFlags, Inode, SuperBlock},
|
||||
utils::{
|
||||
systree_inode::SysTreeInodeTy, FileSystem, FsEventSubscriberStats, FsFlags, Inode,
|
||||
SuperBlock,
|
||||
},
|
||||
Result,
|
||||
},
|
||||
prelude::*,
|
||||
|
|
@ -17,6 +20,7 @@ use crate::{
|
|||
pub(super) struct SysFs {
|
||||
sb: SuperBlock,
|
||||
root: Arc<dyn Inode>,
|
||||
fs_event_subscriber_stats: FsEventSubscriberStats,
|
||||
}
|
||||
|
||||
const MAGIC_NUMBER: u64 = 0x62656572; // SYSFS_MAGIC
|
||||
|
|
@ -44,6 +48,7 @@ impl SysFs {
|
|||
Arc::new(Self {
|
||||
sb,
|
||||
root: root_inode,
|
||||
fs_event_subscriber_stats: FsEventSubscriberStats::new(),
|
||||
})
|
||||
}
|
||||
}
|
||||
|
|
@ -65,6 +70,10 @@ impl FileSystem for SysFs {
|
|||
fn sb(&self) -> SuperBlock {
|
||||
self.sb.clone()
|
||||
}
|
||||
|
||||
fn fs_event_subscriber_stats(&self) -> &FsEventSubscriberStats {
|
||||
&self.fs_event_subscriber_stats
|
||||
}
|
||||
}
|
||||
|
||||
pub(super) struct SysFsType;
|
||||
|
|
|
|||
|
|
@ -6,9 +6,12 @@ use ostd::sync::RwLock;
|
|||
|
||||
use super::fs::SysFs;
|
||||
use crate::{
|
||||
fs::utils::{
|
||||
systree_inode::{SysTreeInodeTy, SysTreeNodeKind},
|
||||
FileSystem, Inode, InodeMode, InodeType, Metadata,
|
||||
fs::{
|
||||
notify::FsEventPublisher,
|
||||
utils::{
|
||||
systree_inode::{SysTreeInodeTy, SysTreeNodeKind},
|
||||
FileSystem, Inode, InodeMode, InodeType, Metadata,
|
||||
},
|
||||
},
|
||||
prelude::*,
|
||||
};
|
||||
|
|
@ -25,6 +28,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 file mode (permissions) of this inode, protected by a lock.
|
||||
mode: RwLock<InodeMode>,
|
||||
/// Weak reference to the parent inode.
|
||||
|
|
@ -46,6 +51,7 @@ impl SysTreeInodeTy for SysFsInode {
|
|||
Arc::new_cyclic(|this| Self {
|
||||
node_kind,
|
||||
metadata,
|
||||
fs_event_publisher: FsEventPublisher::new(),
|
||||
mode: RwLock::new(mode),
|
||||
parent,
|
||||
this: this.clone(),
|
||||
|
|
@ -78,6 +84,10 @@ impl SysTreeInodeTy for SysFsInode {
|
|||
.upgrade()
|
||||
.expect("invalid weak reference to `self`")
|
||||
}
|
||||
|
||||
fn fs_event_publisher(&self) -> &FsEventPublisher {
|
||||
&self.fs_event_publisher
|
||||
}
|
||||
}
|
||||
|
||||
impl Inode for SysFsInode {
|
||||
|
|
|
|||
|
|
@ -4,7 +4,7 @@ use crate::{
|
|||
fs::{
|
||||
ramfs::RamFs,
|
||||
registry::{FsProperties, FsType},
|
||||
utils::{FileSystem, FsFlags, Inode, SuperBlock},
|
||||
utils::{FileSystem, FsEventSubscriberStats, FsFlags, Inode, SuperBlock},
|
||||
},
|
||||
prelude::*,
|
||||
};
|
||||
|
|
@ -43,6 +43,10 @@ impl FileSystem for TmpFs {
|
|||
fn sb(&self) -> SuperBlock {
|
||||
self.inner.sb()
|
||||
}
|
||||
|
||||
fn fs_event_subscriber_stats(&self) -> &FsEventSubscriberStats {
|
||||
self.inner.fs_event_subscriber_stats()
|
||||
}
|
||||
}
|
||||
|
||||
pub(super) struct TmpFsType;
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
// SPDX-License-Identifier: MPL-2.0
|
||||
|
||||
use core::sync::atomic::AtomicU32;
|
||||
use core::sync::atomic::{AtomicI64, AtomicU32, Ordering};
|
||||
|
||||
use atomic_integer_wrapper::define_atomic_version_of_integer_like_type;
|
||||
|
||||
|
|
@ -103,6 +103,57 @@ define_atomic_version_of_integer_like_type!(FsFlags, {
|
|||
pub struct AtomicFsFlags(AtomicU32);
|
||||
});
|
||||
|
||||
#[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,
|
||||
"The number of subscribers is negative: {}",
|
||||
subscribers
|
||||
);
|
||||
}
|
||||
|
||||
pub fn remove_subscribers(&self, num_subscribers: usize) {
|
||||
let num_subscribers = num_subscribers as i64;
|
||||
let old_value = self.num_subscribers.load(Ordering::Acquire);
|
||||
debug_assert!(
|
||||
old_value >= num_subscribers,
|
||||
"integer overflow: attempting to remove {} subscribers when only {} exist",
|
||||
num_subscribers,
|
||||
old_value
|
||||
);
|
||||
|
||||
let subscribers = self
|
||||
.num_subscribers
|
||||
.fetch_sub(num_subscribers, Ordering::Release);
|
||||
debug_assert!(
|
||||
subscribers >= 0,
|
||||
"The number of subscribers is negative: {}",
|
||||
subscribers
|
||||
);
|
||||
}
|
||||
|
||||
pub fn has_any_subscribers(&self) -> bool {
|
||||
self.num_subscribers.load(Ordering::Acquire) > 0
|
||||
}
|
||||
}
|
||||
|
||||
pub trait FileSystem: Any + Sync + Send {
|
||||
/// Gets the name of this FS type such as `"ext4"` or `"sysfs"`.
|
||||
fn name(&self) -> &'static str;
|
||||
|
|
@ -129,6 +180,9 @@ pub trait FileSystem: Any + Sync + Send {
|
|||
warn!("setting file system flags is not implemented");
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Returns the FS event subscriber stats of this file system.
|
||||
fn fs_event_subscriber_stats(&self) -> &FsEventSubscriberStats;
|
||||
}
|
||||
|
||||
impl dyn FileSystem {
|
||||
|
|
|
|||
|
|
@ -16,6 +16,7 @@ use crate::{
|
|||
device::{Device, DeviceType},
|
||||
fs_resolver::PathOrInode,
|
||||
inode_handle::FileIo,
|
||||
notify::FsEventPublisher,
|
||||
path::Path,
|
||||
utils::StatusFlags,
|
||||
},
|
||||
|
|
@ -409,6 +410,16 @@ pub trait Inode: Any + InodeIo + Send + Sync {
|
|||
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 set_xattr(
|
||||
&self,
|
||||
name: XattrName,
|
||||
|
|
|
|||
|
|
@ -10,7 +10,7 @@ pub use endpoint::{Endpoint, EndpointState};
|
|||
pub use falloc_mode::FallocMode;
|
||||
pub use file_creation_mask::{AtomicFileCreationMask, FileCreationMask};
|
||||
pub use flock::{FlockItem, FlockList, FlockType};
|
||||
pub use fs::{FileSystem, FsFlags, SuperBlock};
|
||||
pub use fs::{FileSystem, FsEventSubscriberStats, FsFlags, SuperBlock};
|
||||
pub use id_bitmap::IdBitmap;
|
||||
pub use inode::{
|
||||
Extension, Inode, InodeIo, InodeType, Metadata, MknodType, Permission, SymbolicLink,
|
||||
|
|
|
|||
|
|
@ -13,13 +13,13 @@ use aster_systree::{
|
|||
SysAttr, SysBranchNode, SysNode, SysNodeId, SysNodeType, SysObj, SysStr, SysSymlink,
|
||||
};
|
||||
|
||||
use super::InodeIo;
|
||||
use crate::{
|
||||
fs::{
|
||||
inode_handle::FileIo,
|
||||
notify::FsEventPublisher,
|
||||
utils::{
|
||||
mkmod, AccessMode, DirentVisitor, FallocMode, FileSystem, Inode, InodeMode, InodeType,
|
||||
Metadata, MknodType, StatusFlags, SymbolicLink,
|
||||
mkmod, AccessMode, DirentVisitor, FallocMode, FileSystem, Inode, InodeIo, InodeMode,
|
||||
InodeType, Metadata, MknodType, StatusFlags, SymbolicLink,
|
||||
},
|
||||
},
|
||||
prelude::*,
|
||||
|
|
@ -54,6 +54,8 @@ pub(in crate::fs) trait SysTreeInodeTy: Send + Sync + 'static {
|
|||
|
||||
fn set_mode(&self, mode: InodeMode) -> Result<()>;
|
||||
|
||||
fn fs_event_publisher(&self) -> &FsEventPublisher;
|
||||
|
||||
fn parent(&self) -> &Weak<Self>;
|
||||
|
||||
fn this(&self) -> Arc<Self>
|
||||
|
|
@ -579,6 +581,10 @@ impl<KInode: SysTreeInodeTy + Send + Sync + 'static> Inode for KInode {
|
|||
default fn is_dentry_cacheable(&self) -> bool {
|
||||
true
|
||||
}
|
||||
|
||||
default fn fs_event_publisher(&self) -> &FsEventPublisher {
|
||||
self.fs_event_publisher()
|
||||
}
|
||||
}
|
||||
|
||||
// Update AttrDentryIter to filter by min_ino
|
||||
|
|
|
|||
Loading…
Reference in New Issue