diff options
author | sin-ack <sin-ack@users.noreply.github.com> | 2021-05-12 19:17:51 +0000 |
---|---|---|
committer | Andreas Kling <kling@serenityos.org> | 2021-05-12 22:38:20 +0200 |
commit | fe5ca6ca276ad452a16215031fb395b4f5bef048 (patch) | |
tree | 100ae8dbf8d2b1cee4125cf335017a021c63093f /Kernel/Syscalls/inode_watcher.cpp | |
parent | 2de11b0dc8bbaa0c264a7e6dbb32b5481a337fb8 (diff) | |
download | serenity-fe5ca6ca276ad452a16215031fb395b4f5bef048.zip |
Kernel: Implement multi-watch InodeWatcher :^)
This patch modifies InodeWatcher to switch to a one watcher, multiple
watches architecture. The following changes have been made:
- The watch_file syscall is removed, and in its place the
create_iwatcher, iwatcher_add_watch and iwatcher_remove_watch calls
have been added.
- InodeWatcher now holds multiple WatchDescriptions for each file that
is being watched.
- The InodeWatcher file descriptor can be read from to receive events on
all watched files.
Co-authored-by: Gunnar Beutner <gunnar@beutner.name>
Diffstat (limited to 'Kernel/Syscalls/inode_watcher.cpp')
-rw-r--r-- | Kernel/Syscalls/inode_watcher.cpp | 88 |
1 files changed, 88 insertions, 0 deletions
diff --git a/Kernel/Syscalls/inode_watcher.cpp b/Kernel/Syscalls/inode_watcher.cpp new file mode 100644 index 0000000000..fc9e878acb --- /dev/null +++ b/Kernel/Syscalls/inode_watcher.cpp @@ -0,0 +1,88 @@ +/* + * Copyright (c) 2018-2020, Andreas Kling <kling@serenityos.org> + * Copyright (c) 2021, sin-ack <sin-ack@protonmail.com> + * + * SPDX-License-Identifier: BSD-2-Clause + */ + +#include <Kernel/API/InodeWatcherFlags.h> +#include <Kernel/FileSystem/Custody.h> +#include <Kernel/FileSystem/FileDescription.h> +#include <Kernel/FileSystem/InodeWatcher.h> +#include <Kernel/Process.h> + +namespace Kernel { + +KResultOr<int> Process::sys$create_inode_watcher(u32 flags) +{ + REQUIRE_PROMISE(rpath); + + int fd = alloc_fd(); + if (fd < 0) + return fd; + + auto description_or_error = FileDescription::create(*InodeWatcher::create()); + if (description_or_error.is_error()) + return description_or_error.error(); + + m_fds[fd].set(description_or_error.release_value()); + m_fds[fd].description()->set_readable(true); + + if (flags & static_cast<unsigned>(InodeWatcherFlags::Nonblock)) + m_fds[fd].description()->set_blocking(false); + if (flags & static_cast<unsigned>(InodeWatcherFlags::CloseOnExec)) + m_fds[fd].set_flags(m_fds[fd].flags() | FD_CLOEXEC); + + return fd; +} + +KResultOr<int> Process::sys$inode_watcher_add_watch(Userspace<const Syscall::SC_inode_watcher_add_watch_params*> user_params) +{ + REQUIRE_PROMISE(rpath); + + Syscall::SC_inode_watcher_add_watch_params params; + if (!copy_from_user(¶ms, user_params)) + return EFAULT; + + auto description = file_description(params.fd); + if (!description) + return EBADF; + if (!description->is_inode_watcher()) + return EBADF; + auto inode_watcher = description->inode_watcher(); + + auto path = get_syscall_path_argument(params.user_path.characters, params.user_path.length); + if (path.is_error()) + return path.error(); + + auto custody_or_error = VFS::the().resolve_path(path.value(), current_directory()); + if (custody_or_error.is_error()) + return custody_or_error.error(); + + auto& custody = custody_or_error.value(); + if (!custody->inode().fs().supports_watchers()) + return ENOTSUP; + + auto wd_or_error = inode_watcher->register_inode(custody->inode(), params.event_mask); + if (wd_or_error.is_error()) + return wd_or_error.error(); + return wd_or_error.value(); +} + +KResultOr<int> Process::sys$inode_watcher_remove_watch(int fd, int wd) +{ + auto description = file_description(fd); + if (!description) + return EBADF; + if (!description->is_inode_watcher()) + return EBADF; + auto inode_watcher = description->inode_watcher(); + + auto result = inode_watcher->unregister_by_wd(wd); + if (result.is_error()) + return result; + + return 0; +} + +} |