Kernel/LibC: Implement flock

This commit is contained in:
Bananymous 2025-06-25 18:46:20 +03:00
parent 0cbc39698c
commit 93e5d09a63
8 changed files with 120 additions and 0 deletions

View File

@ -1,6 +1,7 @@
#pragma once
#include <BAN/Array.h>
#include <BAN/HashSet.h>
#include <kernel/FS/Inode.h>
#include <kernel/FS/VirtualFileSystem.h>
@ -43,6 +44,8 @@ namespace Kernel
void close_all();
void close_cloexec();
BAN::ErrorOr<void> flock(int fd, int op);
BAN::ErrorOr<size_t> read(int fd, BAN::ByteSpan);
BAN::ErrorOr<size_t> 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<pid_t> lockers;
};
flock_t flock;
friend class BAN::RefPtr<OpenFileDescription>;
};

View File

@ -112,6 +112,8 @@ namespace Kernel
BAN::ErrorOr<long> sys_symlinkat(const char* path1, int fd, const char* path2);
BAN::ErrorOr<long> sys_flock(int fd, int op);
BAN::ErrorOr<long> sys_pread(int fd, void* buffer, size_t count, off_t offset);
BAN::ErrorOr<long> sys_pwrite(int fd, const void* buffer, size_t count, off_t offset);

View File

@ -5,6 +5,7 @@
#include <kernel/OpenFileDescriptorSet.h>
#include <fcntl.h>
#include <sys/file.h>
#include <sys/socket.h>
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<void> 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<size_t> OpenFileDescriptorSet::read(int fd, BAN::ByteSpan buffer)
{
BAN::RefPtr<Inode> inode;

View File

@ -1208,6 +1208,16 @@ namespace Kernel
return 0;
}
BAN::ErrorOr<long> 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<long> Process::sys_pread(int fd, void* buffer, size_t count, off_t offset)
{
auto inode = TRY(m_open_file_descriptors.inode_of(fd));

View File

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

View File

@ -0,0 +1,17 @@
#ifndef _SYS_FILE_H
#define _SYS_FILE_H 1
#include <sys/cdefs.h>
__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

View File

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

View File

@ -0,0 +1,8 @@
#include <sys/file.h>
#include <sys/syscall.h>
#include <unistd.h>
int flock(int fd, int op)
{
return syscall(SYS_FLOCK, fd, op);
}