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.
This commit is contained in:
Andreas Kling 2019-12-15 19:33:39 +01:00
parent 7fea25943d
commit 5292f6e78f
Notes: sideshowbarker 2024-07-19 10:50:59 +09:00
6 changed files with 21 additions and 9 deletions

View File

@ -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;

View File

@ -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; }

View File

@ -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<Inode> get_inode(InodeIdentifier) const override;

View File

@ -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;

View File

@ -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 :^)",
};

View File

@ -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();