Do not generate extraneous IN_CLOSE inotify events.

IN_CLOSE should only be generated when a file description loses its last
reference; not when a file descriptor is closed.

See fs/file_table.c:__fput.

Updates #5348.

PiperOrigin-RevId: 353810697
This commit is contained in:
Dean Deng
2021-01-26 00:02:52 -08:00
committed by gVisor bot
parent 3731ebb3fe
commit 3946075403
3 changed files with 39 additions and 7 deletions
-7
View File
@@ -159,13 +159,6 @@ func (f *FDTable) dropVFS2(ctx context.Context, file *vfs.FileDescription) {
panic(fmt.Sprintf("UnlockPOSIX failed: %v", err))
}
// Generate inotify events.
ev := uint32(linux.IN_CLOSE_NOWRITE)
if file.IsWritable() {
ev = linux.IN_CLOSE_WRITE
}
file.Dentry().InotifyWithParent(ctx, ev, 0, vfs.PathEvent)
// Drop the table's reference.
file.DecRef(ctx)
}
+7
View File
@@ -161,6 +161,13 @@ func (fd *FileDescription) Init(impl FileDescriptionImpl, flags uint32, mnt *Mou
// DecRef decrements fd's reference count.
func (fd *FileDescription) DecRef(ctx context.Context) {
fd.FileDescriptionRefs.DecRef(func() {
// Generate inotify events.
ev := uint32(linux.IN_CLOSE_NOWRITE)
if fd.IsWritable() {
ev = linux.IN_CLOSE_WRITE
}
fd.Dentry().InotifyWithParent(ctx, ev, 0, PathEvent)
// Unregister fd from all epoll instances.
fd.epollMu.Lock()
epolls := fd.epolls
+32
View File
@@ -782,6 +782,38 @@ TEST(Inotify, MoveWatchedTargetGeneratesEvents) {
EXPECT_EQ(events[0].cookie, events[1].cookie);
}
// Tests that close events are only emitted when a file description drops its
// last reference.
TEST(Inotify, DupFD) {
SKIP_IF(IsRunningWithVFS1());
const TempPath file = ASSERT_NO_ERRNO_AND_VALUE(TempPath::CreateFile());
const FileDescriptor inotify_fd =
ASSERT_NO_ERRNO_AND_VALUE(InotifyInit1(IN_NONBLOCK));
const int wd = ASSERT_NO_ERRNO_AND_VALUE(
InotifyAddWatch(inotify_fd.get(), file.path(), IN_ALL_EVENTS));
FileDescriptor fd = ASSERT_NO_ERRNO_AND_VALUE(Open(file.path(), O_RDONLY));
FileDescriptor fd2 = ASSERT_NO_ERRNO_AND_VALUE(fd.Dup());
std::vector<Event> events =
ASSERT_NO_ERRNO_AND_VALUE(DrainEvents(inotify_fd.get()));
EXPECT_THAT(events, Are({
Event(IN_OPEN, wd),
}));
fd.reset();
events = ASSERT_NO_ERRNO_AND_VALUE(DrainEvents(inotify_fd.get()));
EXPECT_THAT(events, Are({}));
fd2.reset();
events = ASSERT_NO_ERRNO_AND_VALUE(DrainEvents(inotify_fd.get()));
EXPECT_THAT(events, Are({
Event(IN_CLOSE_NOWRITE, wd),
}));
}
TEST(Inotify, CoalesceEvents) {
const TempPath root = ASSERT_NO_ERRNO_AND_VALUE(TempPath::CreateDir());
const FileDescriptor fd =