From 3dd881dec5153ba05596db906f72fce3fff0fcaf Mon Sep 17 00:00:00 2001 From: Zhenchen Wang Date: Mon, 5 Jan 2026 12:58:38 +0800 Subject: [PATCH] Improve fsnotify functions to pass name information more effectively --- kernel/src/fs/notify/mod.rs | 62 ++++++++++++++++++++--------------- kernel/src/fs/path/dentry.rs | 2 +- kernel/src/fs/path/mod.rs | 7 +++- kernel/src/syscall/mkdir.rs | 2 +- kernel/src/syscall/mknod.rs | 2 +- kernel/src/syscall/open.rs | 2 +- kernel/src/syscall/symlink.rs | 2 +- 7 files changed, 46 insertions(+), 33 deletions(-) diff --git a/kernel/src/fs/notify/mod.rs b/kernel/src/fs/notify/mod.rs index dadf90938..abbdb7bd5 100644 --- a/kernel/src/fs/notify/mod.rs +++ b/kernel/src/fs/notify/mod.rs @@ -252,7 +252,7 @@ pub fn on_access(file: &Arc) { { return; } - notify_parent(path, FsEvents::ACCESS, path.effective_name()); + notify_parent(path, FsEvents::ACCESS); } /// Notifies that a file was modified. @@ -270,7 +270,7 @@ pub fn on_modify(file: &Arc) { { return; } - notify_parent(path, FsEvents::MODIFY, path.effective_name()); + notify_parent(path, FsEvents::MODIFY); } /// Notifies that a path's content was changed. @@ -283,7 +283,7 @@ pub fn on_change(path: &Path) { { return; } - notify_parent(path, FsEvents::MODIFY, path.effective_name()); + notify_parent(path, FsEvents::MODIFY); } /// Notifies that a file was deleted from a directory. @@ -300,11 +300,10 @@ pub fn on_delete( return; } - let name = name(); if inode.type_() == InodeType::Dir { - notify_inode(dir_inode, FsEvents::DELETE | FsEvents::ISDIR, Some(name)) + notify_inode_with_name(dir_inode, FsEvents::DELETE | FsEvents::ISDIR, name) } else { - notify_inode(dir_inode, FsEvents::DELETE, Some(name)) + notify_inode_with_name(dir_inode, FsEvents::DELETE, name) } } @@ -313,7 +312,7 @@ pub fn on_link_count(inode: &Arc) { if !inode.fs().fs_event_subscriber_stats().has_any_subscribers() { return; } - notify_inode(inode, FsEvents::ATTRIB, None); + notify_inode(inode, FsEvents::ATTRIB); } /// Notifies that an inode was removed (link count reached 0). @@ -321,11 +320,11 @@ pub fn on_inode_removed(inode: &Arc) { if !inode.fs().fs_event_subscriber_stats().has_any_subscribers() { return; } - notify_inode(inode, FsEvents::DELETE_SELF, None); + notify_inode(inode, FsEvents::DELETE_SELF); } /// Notifies that a file was linked to a directory. -pub fn on_link(dir_inode: &Arc, inode: &Arc, name: String) { +pub fn on_link(dir_inode: &Arc, inode: &Arc, name: impl FnOnce() -> String) { if !dir_inode .fs() .fs_event_subscriber_stats() @@ -333,12 +332,12 @@ pub fn on_link(dir_inode: &Arc, inode: &Arc, name: String) { return; } - notify_inode(inode, FsEvents::ATTRIB, None); - notify_inode(dir_inode, FsEvents::CREATE, Some(name)); + notify_inode(inode, FsEvents::ATTRIB); + notify_inode_with_name(dir_inode, FsEvents::CREATE, name); } /// Notifies that a directory was created. -pub fn on_mkdir(dir_path: &Path, name: String) { +pub fn on_mkdir(dir_path: &Path, name: impl FnOnce() -> String) { if !dir_path .inode() .fs() @@ -347,15 +346,11 @@ pub fn on_mkdir(dir_path: &Path, name: String) { { return; } - notify_inode( - dir_path.inode(), - FsEvents::CREATE | FsEvents::ISDIR, - Some(name), - ); + notify_inode_with_name(dir_path.inode(), FsEvents::CREATE | FsEvents::ISDIR, name); } /// Notifies that a file was created. -pub fn on_create(file_path: &Path, name: String) { +pub fn on_create(file_path: &Path, name: impl FnOnce() -> String) { if !file_path .inode() .fs() @@ -364,7 +359,7 @@ pub fn on_create(file_path: &Path, name: String) { { return; } - notify_inode(file_path.inode(), FsEvents::CREATE, Some(name)); + notify_inode_with_name(file_path.inode(), FsEvents::CREATE, name); } /// Notifies that a file was opened. @@ -382,7 +377,7 @@ pub fn on_open(file: &Arc) { { return; } - notify_parent(path, FsEvents::OPEN, path.effective_name()); + notify_parent(path, FsEvents::OPEN); } /// Notifies that a file was closed. @@ -401,7 +396,7 @@ pub fn on_close(file: &Arc) { AccessMode::O_RDONLY => FsEvents::CLOSE_NOWRITE, _ => FsEvents::CLOSE_WRITE, }; - notify_parent(path, events, path.effective_name()); + notify_parent(path, events); } } @@ -415,7 +410,7 @@ pub fn on_attr_change(path: &Path) { { return; } - notify_parent(path, FsEvents::ATTRIB, path.effective_name()); + notify_parent(path, FsEvents::ATTRIB); } /// Notifies a path's parent and the path itself about filesystem events. @@ -424,16 +419,19 @@ pub fn on_attr_change(path: &Path) { /// 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) { +/// +/// The child's real name (from `path.name()`) is used to notify the parent, since +/// FS events do not cross mount boundaries. +fn notify_parent(path: &Path, mut events: FsEvents) { if path.inode().type_() == InodeType::Dir { events |= FsEvents::ISDIR; } let parent = path.parent_within_mount(); if let Some(parent) = parent { - notify_inode(parent.inode(), events, Some(name)); + notify_inode_with_name(parent.inode(), events, || path.name()); } - notify_inode(path.inode(), events, None); + notify_inode(path.inode(), events); } /// Sends a filesystem notification event to all subscribers of an inode. @@ -441,8 +439,18 @@ fn notify_parent(path: &Path, mut events: FsEvents, name: String) { /// This is the main entry point for FS event notification. 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, events: FsEvents, name: Option) { +fn notify_inode(inode: &Arc, events: FsEvents) { if let Some(publisher) = inode.fs_event_publisher() { - publisher.publish_event(events, name); + publisher.publish_event(events, None); + } +} + +/// Sends a filesystem notification event with a name to all subscribers of an inode. +/// +/// Similar to `notify_inode`, but includes a name parameter for events that require +/// child name information (e.g., CREATE, DELETE). +fn notify_inode_with_name(inode: &Arc, events: FsEvents, name: impl FnOnce() -> String) { + if let Some(publisher) = inode.fs_event_publisher() { + publisher.publish_event(events, Some(name())); } } diff --git a/kernel/src/fs/path/dentry.rs b/kernel/src/fs/path/dentry.rs index 45fbb75c9..4b9da97c7 100644 --- a/kernel/src/fs/path/dentry.rs +++ b/kernel/src/fs/path/dentry.rs @@ -234,7 +234,7 @@ impl Dentry { if dentry.is_dentry_cacheable() { children.upgrade().insert(name.clone(), dentry.clone()); } - fs::notify::on_link(dentry.parent().unwrap().inode(), dentry.inode(), name); + fs::notify::on_link(dentry.parent().unwrap().inode(), dentry.inode(), || name); Ok(()) } diff --git a/kernel/src/fs/path/mod.rs b/kernel/src/fs/path/mod.rs index cd80b16ad..5cb71b637 100644 --- a/kernel/src/fs/path/mod.rs +++ b/kernel/src/fs/path/mod.rs @@ -141,11 +141,16 @@ impl Path { path_name } + /// Gets the real name of the `Path` from its dentry. + pub fn name(&self) -> String { + self.dentry.name() + } + /// Gets the effective name of the `Path`. /// /// If it is the root of a mount, it will go up to the mountpoint /// to get the name of the mountpoint recursively. - pub fn effective_name(&self) -> String { + fn effective_name(&self) -> String { if !self.is_mount_root() { return self.dentry.name(); } diff --git a/kernel/src/syscall/mkdir.rs b/kernel/src/syscall/mkdir.rs index 009767742..5ab3d7af4 100644 --- a/kernel/src/syscall/mkdir.rs +++ b/kernel/src/syscall/mkdir.rs @@ -37,7 +37,7 @@ pub fn sys_mkdirat( InodeMode::from_bits_truncate(mask_mode) }; dir_path.new_fs_child(&name, InodeType::Dir, inode_mode)?; - fs::notify::on_mkdir(&dir_path, name); + fs::notify::on_mkdir(&dir_path, || name); Ok(SyscallReturn::Return(0)) } diff --git a/kernel/src/syscall/mknod.rs b/kernel/src/syscall/mknod.rs index c79aae3e6..6f3408c49 100644 --- a/kernel/src/syscall/mknod.rs +++ b/kernel/src/syscall/mknod.rs @@ -59,7 +59,7 @@ pub fn sys_mknodat( } _ => return_errno_with_message!(Errno::EPERM, "unimplemented file types"), } - fs::notify::on_create(&dir_path, name); + fs::notify::on_create(&dir_path, || name); Ok(SyscallReturn::Return(0)) } diff --git a/kernel/src/syscall/open.rs b/kernel/src/syscall/open.rs index d7ac8e644..0e14d646a 100644 --- a/kernel/src/syscall/open.rs +++ b/kernel/src/syscall/open.rs @@ -131,7 +131,7 @@ fn do_open( let (parent, tail_name) = result.into_parent_and_basename(); let new_path = parent.new_fs_child(&tail_name, InodeType::File, open_args.inode_mode)?; - fs::notify::on_create(&parent, tail_name.clone()); + fs::notify::on_create(&parent, || tail_name.clone()); // Don't check access mode for newly created file. Arc::new(InodeHandle::new_unchecked_access( diff --git a/kernel/src/syscall/symlink.rs b/kernel/src/syscall/symlink.rs index 79c8f00aa..cd342b8a1 100644 --- a/kernel/src/syscall/symlink.rs +++ b/kernel/src/syscall/symlink.rs @@ -44,7 +44,7 @@ pub fn sys_symlinkat( let new_path = dir_path.new_fs_child(&link_name, InodeType::SymLink, mkmod!(a+rwx))?; new_path.inode().write_link(&target)?; - fs::notify::on_create(&dir_path, link_name); + fs::notify::on_create(&dir_path, || link_name); Ok(SyscallReturn::Return(0)) }