From 5292f6e78fcc06b3defd225f5ce33d13fe5022a3 Mon Sep 17 00:00:00 2001 From: Andreas Kling Date: Sun, 15 Dec 2019 19:33:39 +0100 Subject: [PATCH] Kernel+FileManager: Disallow watch_file() in unsupported file systems Currently only Ext2FS and TmpFS supports InodeWatchers. We now fail with ENOTSUPP if watch_file() is called on e.g ProcFS. This fixes an issue with FileManager chewing up all the CPU when /proc was opened. Watchers don't keep the watched Inode open, and when they close, the watcher FD will EOF. Since nothing else kept /proc open in FileManager, the watchers created for it would EOF immediately, causing a refresh over and over. Fixes #879. --- Kernel/FileSystem/Ext2FileSystem.h | 2 ++ Kernel/FileSystem/FileSystem.h | 1 + Kernel/FileSystem/TmpFS.h | 2 ++ Kernel/Process.cpp | 3 +++ Libraries/LibC/string.cpp | 2 ++ Libraries/LibGUI/GDirectoryModel.cpp | 20 +++++++++++--------- 6 files changed, 21 insertions(+), 9 deletions(-) diff --git a/Kernel/FileSystem/Ext2FileSystem.h b/Kernel/FileSystem/Ext2FileSystem.h index ea708a6021..f8cfaa7bcb 100644 --- a/Kernel/FileSystem/Ext2FileSystem.h +++ b/Kernel/FileSystem/Ext2FileSystem.h @@ -74,6 +74,8 @@ public: virtual KResult prepare_to_unmount() const override; + virtual bool supports_watchers() const override { return true; } + private: typedef unsigned BlockIndex; typedef unsigned GroupIndex; diff --git a/Kernel/FileSystem/FileSystem.h b/Kernel/FileSystem/FileSystem.h index 33efc77318..9538c6f132 100644 --- a/Kernel/FileSystem/FileSystem.h +++ b/Kernel/FileSystem/FileSystem.h @@ -37,6 +37,7 @@ public: virtual bool initialize() = 0; virtual const char* class_name() const = 0; virtual InodeIdentifier root_inode() const = 0; + virtual bool supports_watchers() const { return false; } bool is_readonly() const { return m_readonly; } diff --git a/Kernel/FileSystem/TmpFS.h b/Kernel/FileSystem/TmpFS.h index 0ce6a30d72..0b15724b12 100644 --- a/Kernel/FileSystem/TmpFS.h +++ b/Kernel/FileSystem/TmpFS.h @@ -17,6 +17,8 @@ public: virtual const char* class_name() const override { return "TmpFS"; } + virtual bool supports_watchers() const override { return true; } + virtual InodeIdentifier root_inode() const override; virtual RefPtr get_inode(InodeIdentifier) const override; diff --git a/Kernel/Process.cpp b/Kernel/Process.cpp index 9a3b05eb2a..7dfa2fc2d9 100644 --- a/Kernel/Process.cpp +++ b/Kernel/Process.cpp @@ -3230,6 +3230,9 @@ int Process::sys$watch_file(const char* path, int path_length) auto& custody = custody_or_error.value(); auto& inode = custody->inode(); + if (!inode.fs().supports_watchers()) + return -ENOTSUP; + int fd = alloc_fd(); if (fd < 0) return fd; diff --git a/Libraries/LibC/string.cpp b/Libraries/LibC/string.cpp index 1df6e6e990..d079422286 100644 --- a/Libraries/LibC/string.cpp +++ b/Libraries/LibC/string.cpp @@ -406,6 +406,8 @@ const char* const sys_errlist[] = { "Wrong protocol type", "Operation in progress", "No such thread", + "Protocol error", + "Not supported", "The highest errno +1 :^)", }; diff --git a/Libraries/LibGUI/GDirectoryModel.cpp b/Libraries/LibGUI/GDirectoryModel.cpp index cbb08390e4..480fda225a 100644 --- a/Libraries/LibGUI/GDirectoryModel.cpp +++ b/Libraries/LibGUI/GDirectoryModel.cpp @@ -341,21 +341,23 @@ void GDirectoryModel::open(const StringView& a_path) if (!dirp) return; closedir(dirp); - if (m_notifier) + if (m_notifier) { close(m_notifier->fd()); + m_notifier = nullptr; + } m_path = path; int watch_fd = watch_file(path.characters(), path.length()); if (watch_fd < 0) { perror("watch_file"); - ASSERT_NOT_REACHED(); + } else { + m_notifier = CNotifier::construct(watch_fd, CNotifier::Event::Read); + m_notifier->on_ready_to_read = [this] { + update(); + char buffer[32]; + int rc = read(m_notifier->fd(), buffer, sizeof(buffer)); + ASSERT(rc >= 0); + }; } - m_notifier = CNotifier::construct(watch_fd, CNotifier::Event::Read); - m_notifier->on_ready_to_read = [this] { - update(); - char buffer[32]; - int rc = read(m_notifier->fd(), buffer, sizeof(buffer)); - ASSERT(rc >= 0); - }; if (on_path_change) on_path_change(); update();