From 93e5d09a6305670a35cee3e094127aaf59efb809 Mon Sep 17 00:00:00 2001 From: Bananymous Date: Wed, 25 Jun 2025 18:46:20 +0300 Subject: [PATCH] Kernel/LibC: Implement flock --- kernel/include/kernel/OpenFileDescriptorSet.h | 12 ++++ kernel/include/kernel/Process.h | 2 + kernel/kernel/OpenFileDescriptorSet.cpp | 69 +++++++++++++++++++ kernel/kernel/Process.cpp | 10 +++ userspace/libraries/LibC/CMakeLists.txt | 1 + userspace/libraries/LibC/include/sys/file.h | 17 +++++ .../libraries/LibC/include/sys/syscall.h | 1 + userspace/libraries/LibC/sys/file.cpp | 8 +++ 8 files changed, 120 insertions(+) create mode 100644 userspace/libraries/LibC/sys/file.cpp diff --git a/kernel/include/kernel/OpenFileDescriptorSet.h b/kernel/include/kernel/OpenFileDescriptorSet.h index 1396653e..69b74c9b 100644 --- a/kernel/include/kernel/OpenFileDescriptorSet.h +++ b/kernel/include/kernel/OpenFileDescriptorSet.h @@ -1,6 +1,7 @@ #pragma once #include +#include #include #include @@ -43,6 +44,8 @@ namespace Kernel void close_all(); void close_cloexec(); + BAN::ErrorOr flock(int fd, int op); + BAN::ErrorOr read(int fd, BAN::ByteSpan); BAN::ErrorOr write(int fd, BAN::ConstByteSpan); @@ -69,6 +72,15 @@ namespace Kernel off_t offset { 0 }; int status_flags; + struct flock_t + { + bool locked; + bool shared; + ThreadBlocker thread_blocker; + BAN::HashSet lockers; + }; + flock_t flock; + friend class BAN::RefPtr; }; diff --git a/kernel/include/kernel/Process.h b/kernel/include/kernel/Process.h index 3d8e6cdc..5baffbd3 100644 --- a/kernel/include/kernel/Process.h +++ b/kernel/include/kernel/Process.h @@ -112,6 +112,8 @@ namespace Kernel BAN::ErrorOr sys_symlinkat(const char* path1, int fd, const char* path2); + BAN::ErrorOr sys_flock(int fd, int op); + BAN::ErrorOr sys_pread(int fd, void* buffer, size_t count, off_t offset); BAN::ErrorOr sys_pwrite(int fd, const void* buffer, size_t count, off_t offset); diff --git a/kernel/kernel/OpenFileDescriptorSet.cpp b/kernel/kernel/OpenFileDescriptorSet.cpp index 3f88fb45..bd55a0a2 100644 --- a/kernel/kernel/OpenFileDescriptorSet.cpp +++ b/kernel/kernel/OpenFileDescriptorSet.cpp @@ -5,6 +5,7 @@ #include #include +#include #include namespace Kernel @@ -310,6 +311,17 @@ namespace Kernel TRY(validate_fd(fd)); auto& open_file = m_open_files[fd]; + + if (auto& flock = open_file.description->flock; Thread::current().has_process() && flock.lockers.contains(Process::current().pid())) + { + flock.lockers.remove(Process::current().pid()); + if (flock.lockers.empty()) + { + flock.locked = false; + flock.thread_blocker.unblock(); + } + } + open_file.inode()->on_close(open_file.status_flags()); open_file.description.clear(); open_file.descriptor_flags = 0; @@ -336,6 +348,63 @@ namespace Kernel } } + BAN::ErrorOr OpenFileDescriptorSet::flock(int fd, int op) + { + const auto pid = Process::current().pid(); + + LockGuard _(m_mutex); + + for (;;) + { + TRY(validate_fd(fd)); + + auto& flock = m_open_files[fd].description->flock; + switch (op & ~LOCK_NB) + { + case LOCK_UN: + flock.lockers.remove(pid); + if (flock.lockers.empty()) + { + flock.locked = false; + flock.thread_blocker.unblock(); + } + return {}; + case LOCK_SH: + if (!flock.locked) + { + TRY(flock.lockers.insert(pid)); + flock.locked = true; + flock.shared = true; + return {}; + } + if (flock.shared) + { + TRY(flock.lockers.insert(pid)); + return {}; + } + break; + case LOCK_EX: + if (!flock.locked) + { + TRY(flock.lockers.insert(pid)); + flock.locked = true; + flock.shared = false; + return {}; + } + if (flock.lockers.contains(pid)) + return {}; + break; + default: + return BAN::Error::from_errno(EINVAL); + } + + if (op & LOCK_NB) + return BAN::Error::from_errno(EWOULDBLOCK); + + TRY(Thread::current().block_or_eintr_indefinite(flock.thread_blocker, &m_mutex)); + } + } + BAN::ErrorOr OpenFileDescriptorSet::read(int fd, BAN::ByteSpan buffer) { BAN::RefPtr inode; diff --git a/kernel/kernel/Process.cpp b/kernel/kernel/Process.cpp index f9f28394..6af4755f 100644 --- a/kernel/kernel/Process.cpp +++ b/kernel/kernel/Process.cpp @@ -1208,6 +1208,16 @@ namespace Kernel return 0; } + BAN::ErrorOr Process::sys_flock(int fd, int op) + { + auto maybe_error = m_open_file_descriptors.flock(fd, op); + if (maybe_error.is_error() && maybe_error.error().get_error_code() == ENOMEM) + return BAN::Error::from_errno(ENOLCK); + if (maybe_error.is_error()) + return maybe_error.error(); + return 0; + } + BAN::ErrorOr Process::sys_pread(int fd, void* buffer, size_t count, off_t offset) { auto inode = TRY(m_open_file_descriptors.inode_of(fd)); diff --git a/userspace/libraries/LibC/CMakeLists.txt b/userspace/libraries/LibC/CMakeLists.txt index 2e6734f1..12ab129f 100644 --- a/userspace/libraries/LibC/CMakeLists.txt +++ b/userspace/libraries/LibC/CMakeLists.txt @@ -33,6 +33,7 @@ set(LIBC_SOURCES strings.cpp sys/banan-os.cpp sys/epoll.cpp + sys/file.cpp sys/ioctl.cpp sys/mman.cpp sys/resource.cpp diff --git a/userspace/libraries/LibC/include/sys/file.h b/userspace/libraries/LibC/include/sys/file.h index e69de29b..4875dd3f 100644 --- a/userspace/libraries/LibC/include/sys/file.h +++ b/userspace/libraries/LibC/include/sys/file.h @@ -0,0 +1,17 @@ +#ifndef _SYS_FILE_H +#define _SYS_FILE_H 1 + +#include + +__BEGIN_DECLS + +#define LOCK_UN 0 +#define LOCK_EX 1 +#define LOCK_SH 2 +#define LOCK_NB 4 + +int flock(int fd, int op); + +__END_DECLS + +#endif diff --git a/userspace/libraries/LibC/include/sys/syscall.h b/userspace/libraries/LibC/include/sys/syscall.h index c3c77c81..1bfa45ac 100644 --- a/userspace/libraries/LibC/include/sys/syscall.h +++ b/userspace/libraries/LibC/include/sys/syscall.h @@ -107,6 +107,7 @@ __BEGIN_DECLS O(SYS_EPOLL_CREATE1, epoll_create1) \ O(SYS_EPOLL_CTL, epoll_ctl) \ O(SYS_EPOLL_PWAIT2, epoll_pwait2) \ + O(SYS_FLOCK, flock) \ enum Syscall { diff --git a/userspace/libraries/LibC/sys/file.cpp b/userspace/libraries/LibC/sys/file.cpp new file mode 100644 index 00000000..f869c129 --- /dev/null +++ b/userspace/libraries/LibC/sys/file.cpp @@ -0,0 +1,8 @@ +#include +#include +#include + +int flock(int fd, int op) +{ + return syscall(SYS_FLOCK, fd, op); +}