Reject new watches on deleted inodes

This commit is contained in:
Ruihan Li 2026-01-08 15:42:07 +08:00 committed by Tate, Hongliang Tian
parent d23d25c552
commit 43b8838d6a
7 changed files with 70 additions and 17 deletions

View File

@ -165,12 +165,20 @@ impl InotifyFile {
let subscriber = inotify_subscriber.clone() as Arc<dyn FsEventSubscriber>;
let inode = path.inode();
if inode
if !inode
.fs_event_publisher_or_init()
.add_subscriber(subscriber)
{
inode.fs().fs_event_subscriber_stats().add_subscriber();
// FIXME: This can be triggered by `unlink()` race conditions or
// `inotify_add_watch("/proc/self/fd/[fd]")`, where `[fd]` is a file descriptor
// pointing to a deleted file. Although Linux allows this, we don't support it, so an
// error is returned here.
return_errno_with_message!(
Errno::ENOENT,
"adding an inotify watch to a deleted inode is not supported yet"
);
}
inode.fs().fs_event_subscriber_stats().add_subscriber();
let wd = inotify_subscriber.wd();
let entry = SubscriberEntry {

View File

@ -327,6 +327,7 @@ impl Dentry {
let nlinks = child_inode.metadata().nlinks;
fs::notify::on_link_count(&child_inode);
if nlinks == 0 {
// FIXME: `DELETE_SELF` should be generated after closing the last FD.
fs::notify::on_inode_removed(&child_inode);
}
fs::notify::on_delete(self.inode(), &child_inode, || name.to_string());
@ -379,13 +380,14 @@ impl Dentry {
let nlinks = child_inode.metadata().nlinks;
if nlinks == 0 {
// FIXME: `DELETE_SELF` should be generated after closing the last FD.
fs::notify::on_inode_removed(&child_inode);
}
fs::notify::on_delete(self.inode(), &child_inode, || name.to_string());
if nlinks == 0 {
// 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.
// `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();
let removed_nr_subscribers = publisher.disable_new_and_remove_subscribers();
child_inode

View File

@ -0,0 +1,35 @@
// SPDX-License-Identifier: MPL-2.0
#include <sys/inotify.h>
#include <sys/fcntl.h>
#include <unistd.h>
#include "../test.h"
#define TEST_FILE "/tmp/test1"
FN_TEST(unlink_add)
{
int inotify_fd, fd, wd;
inotify_fd = TEST_SUCC(inotify_init1(O_NONBLOCK));
fd = TEST_RES(open(TEST_FILE, O_CREAT | O_WRONLY, 0644), _ret == 4);
TEST_SUCC(unlink(TEST_FILE));
// FIXME: Asterinas currently does not support adding inotify watches
// to deleted inodes.
#ifdef __asterinas__
TEST_ERRNO(inotify_add_watch(inotify_fd, "/proc/self/fd/4",
IN_DELETE_SELF),
ENOENT);
(void)wd;
#else
wd = TEST_SUCC(inotify_add_watch(inotify_fd, "/proc/self/fd/4",
IN_DELETE_SELF));
TEST_SUCC(inotify_rm_watch(inotify_fd, wd));
#endif
TEST_SUCC(close(fd));
TEST_SUCC(close(inotify_fd));
}
END_TEST()

View File

@ -32,6 +32,7 @@ hello_pie/hello
hello_world/hello_world
inotify/inotify_align
inotify/inotify_poll
inotify/inotify_unlink
itimer/setitimer
itimer/timer_create
mmap/mmap_and_fork

View File

@ -1,3 +1,5 @@
InotifyTest.AddRemoveUnlinkDoNotDeadlock
# TODO: Due to some FS bugs, they may trigger
# "PosixError(errno=28 No space left on device)"
# because too many files are created and deleted.
InotifyTest.InotifyAndTargetDestructionDoNotDeadlock
InotifyTest.NotifyNoDeadlock
InotifyTest.InotifyAndTargetDestructionDoNotDeadlock_NoRandomSave

View File

@ -1,4 +0,0 @@
# Nothing here. Pipe files are supported by the ext2 file system.
#
# This file is kept to ensure that the `blocklists.ext2` directory
# is not empty, as it may become useful in the future.

View File

@ -1,5 +1,13 @@
# TODO: Generate `DELETE_SELF`/`IGNORED` after closing the last FD.
Inotify.DupFD
Inotify.IncludeUnlinkedFile
Inotify.IncludeUnlinkedFile_NoRandomSave
# Symbolic links to the busybox binary does not work:
# "gvisor_test_temp_1103_1767603858010282988: applet not found"
Inotify.Exec
# TODO: Support the `EXCL_UNLINK` flag.
Inotify.ExcludeUnlink
Inotify.ExcludeUnlink_NoRandomSave
Inotify.ExcludeUnlinkDirectory
@ -8,16 +16,17 @@ Inotify.ExcludeUnlinkInodeEvents
Inotify.ExcludeUnlinkInodeEvents_NoRandomSave
Inotify.ExcludeUnlinkMultipleChildren
Inotify.ExcludeUnlinkMultipleChildren_NoRandomSave
Inotify.IncludeUnlinkedFile
Inotify.IncludeUnlinkedFile_NoRandomSave
# TODO: Report `MOVE_*` events at the `rename()` system call.
Inotify.MoveGeneratesEvents
Inotify.MoveWatchedTargetGeneratesEvents
# TODO: Support the `ONESHOT` flag.
Inotify.OneShot
# TODO: Support the `splice()` system call.
Inotify.SpliceOnInotifyFD
Inotify.SpliceOnWatchTarget
Inotify.Utimensat
InotifyTest.AddRemoveUnlinkDoNotDeadlock
InotifyTest.InotifyAndTargetDestructionDoNotDeadlock
InotifyTest.InotifyAndTargetDestructionDoNotDeadlock_NoRandomSave
InotifyTest.NotifyNoDeadlock
# TODO: Correct event generation at the `untimensat()` system call.
Inotify.Utimensat