Kernel: Move open file descriptors to their own class

This simplifies code a lot :)
This commit is contained in:
Bananymous 2023-07-07 23:11:37 +03:00
parent 274ecbba78
commit 78c091f7f8
5 changed files with 343 additions and 261 deletions

View File

@ -33,6 +33,7 @@ set(KERNEL_SOURCES
kernel/Memory/kmalloc.cpp
kernel/Memory/PhysicalRange.cpp
kernel/Memory/VirtualRange.cpp
kernel/OpenFileDescriptorSet.cpp
kernel/Panic.cpp
kernel/PCI.cpp
kernel/PIC.cpp

View File

@ -0,0 +1,72 @@
#pragma once
#include <BAN/Array.h>
#include <kernel/FS/Inode.h>
#include <limits.h>
#include <sys/stat.h>
namespace Kernel
{
class OpenFileDescriptorSet
{
BAN_NON_COPYABLE(OpenFileDescriptorSet);
public:
OpenFileDescriptorSet(const Credentials&);
~OpenFileDescriptorSet();
BAN::ErrorOr<void> clone_from(const OpenFileDescriptorSet&);
BAN::ErrorOr<int> open(BAN::StringView absolute_path, int flags);
BAN::ErrorOr<void> pipe(int fds[2]);
BAN::ErrorOr<int> dup2(int, int);
BAN::ErrorOr<void> seek(int fd, off_t offset, int whence);
BAN::ErrorOr<off_t> tell(int) const;
BAN::ErrorOr<void> fstat(int fd, struct stat*) const;
BAN::ErrorOr<void> close(int);
void close_all();
void close_cloexec();
BAN::ErrorOr<size_t> read(int fd, void* buffer, size_t count);
BAN::ErrorOr<size_t> write(int fd, const void* buffer, size_t count);
BAN::ErrorOr<void> read_dir_entries(int fd, DirectoryEntryList* list, size_t list_size);
BAN::ErrorOr<BAN::StringView> path_of(int) const;
private:
struct OpenFileDescription : public BAN::RefCounted<OpenFileDescription>
{
OpenFileDescription(BAN::RefPtr<Inode> inode, BAN::String path, off_t offset, uint8_t flags)
: inode(inode)
, path(BAN::move(path))
, offset(offset)
, flags(flags)
{ }
BAN::RefPtr<Inode> inode;
BAN::String path;
off_t offset { 0 };
uint8_t flags { 0 };
friend class BAN::RefPtr<OpenFileDescription>;
};
BAN::ErrorOr<void> validate_fd(int) const;
BAN::ErrorOr<int> get_free_fd() const;
BAN::ErrorOr<void> get_free_fd_pair(int fds[2]) const;
private:
const Credentials& m_credentials;
BAN::Array<BAN::RefPtr<OpenFileDescription>, OPEN_MAX> m_open_files;
};
}

View File

@ -9,11 +9,11 @@
#include <kernel/Memory/GeneralAllocator.h>
#include <kernel/Memory/Heap.h>
#include <kernel/Memory/VirtualRange.h>
#include <kernel/OpenFileDescriptorSet.h>
#include <kernel/SpinLock.h>
#include <kernel/Terminal/TTY.h>
#include <kernel/Thread.h>
#include <sys/stat.h>
#include <termios.h>
namespace LibELF { class ELF; }
@ -128,20 +128,6 @@ namespace Kernel
BAN::ErrorOr<BAN::String> absolute_path_of(BAN::StringView) const;
private:
struct OpenFileDescription
{
BAN::RefPtr<Inode> inode;
BAN::String path;
off_t offset { 0 };
uint8_t flags { 0 };
};
BAN::ErrorOr<void> validate_fd(int);
OpenFileDescription& open_file_description(int);
BAN::ErrorOr<int> get_free_fd();
BAN::ErrorOr<void> get_free_fd_pair(int fds[2]);
struct ExitStatus
{
Semaphore semaphore;
@ -152,7 +138,8 @@ namespace Kernel
Credentials m_credentials;
BAN::Vector<OpenFileDescription> m_open_files;
OpenFileDescriptorSet m_open_file_descriptors;
BAN::Vector<VirtualRange*> m_mapped_ranges;
mutable RecursiveSpinLock m_lock;

View File

@ -0,0 +1,245 @@
#include <kernel/FS/Pipe.h>
#include <kernel/FS/VirtualFileSystem.h>
#include <kernel/OpenFileDescriptorSet.h>
#include <fcntl.h>
namespace Kernel
{
OpenFileDescriptorSet::OpenFileDescriptorSet(const Credentials& credentials)
: m_credentials(credentials)
{
}
OpenFileDescriptorSet::~OpenFileDescriptorSet()
{
close_all();
}
BAN::ErrorOr<void> OpenFileDescriptorSet::clone_from(const OpenFileDescriptorSet& other)
{
close_all();
for (int fd = 0; fd < (int)other.m_open_files.size(); fd++)
{
if (other.validate_fd(fd).is_error())
continue;
auto& open_file = other.m_open_files[fd];
auto result = BAN::RefPtr<OpenFileDescription>::create(open_file->inode, open_file->path, open_file->offset, open_file->flags);
if (result.is_error())
{
close_all();
return result.error();
}
m_open_files[fd] = result.release_value();
if (m_open_files[fd]->flags & O_WRONLY && m_open_files[fd]->inode->is_pipe())
((Pipe*)m_open_files[fd]->inode.ptr())->clone_writing();
}
return {};
}
BAN::ErrorOr<int> OpenFileDescriptorSet::open(BAN::StringView absolute_path, int flags)
{
if (flags & ~(O_RDONLY | O_WRONLY | O_NOFOLLOW | O_SEARCH | O_CLOEXEC))
return BAN::Error::from_errno(ENOTSUP);
auto file = TRY(VirtualFileSystem::get().file_from_absolute_path(m_credentials, absolute_path, flags));
int fd = TRY(get_free_fd());
m_open_files[fd] = TRY(BAN::RefPtr<OpenFileDescription>::create(file.inode, BAN::move(file.canonical_path), 0, flags));
return fd;
}
BAN::ErrorOr<void> OpenFileDescriptorSet::pipe(int fds[2])
{
TRY(get_free_fd_pair(fds));
auto pipe = TRY(Pipe::create(m_credentials));
m_open_files[fds[0]] = TRY(BAN::RefPtr<OpenFileDescription>::create(pipe, ""sv, 0, O_RDONLY));
m_open_files[fds[1]] = TRY(BAN::RefPtr<OpenFileDescription>::create(pipe, ""sv, 0, O_WRONLY));
return {};
}
BAN::ErrorOr<int> OpenFileDescriptorSet::dup2(int fildes, int fildes2)
{
if (fildes2 < 0 || fildes2 >= (int)m_open_files.size())
return BAN::Error::from_errno(EBADF);
TRY(validate_fd(fildes));
if (fildes == fildes2)
return fildes;
(void)close(fildes2);
m_open_files[fildes2] = m_open_files[fildes];
m_open_files[fildes2]->flags &= ~O_CLOEXEC;
if (m_open_files[fildes]->flags & O_WRONLY && m_open_files[fildes]->inode->is_pipe())
((Pipe*)m_open_files[fildes]->inode.ptr())->clone_writing();
return fildes;
}
BAN::ErrorOr<void> OpenFileDescriptorSet::seek(int fd, off_t offset, int whence)
{
TRY(validate_fd(fd));
off_t new_offset = 0;
switch (whence)
{
case SEEK_CUR:
new_offset = m_open_files[fd]->offset + offset;
break;
case SEEK_END:
new_offset = m_open_files[fd]->inode->size() - offset;
break;
case SEEK_SET:
new_offset = offset;
break;
default:
return BAN::Error::from_errno(EINVAL);
}
if (new_offset < 0)
return BAN::Error::from_errno(EINVAL);
m_open_files[fd]->offset = new_offset;
return {};
}
BAN::ErrorOr<off_t> OpenFileDescriptorSet::tell(int fd) const
{
TRY(validate_fd(fd));
return m_open_files[fd]->offset;
}
BAN::ErrorOr<void> OpenFileDescriptorSet::fstat(int fd, struct stat* out) const
{
TRY(validate_fd(fd));
auto inode = m_open_files[fd]->inode;
out->st_dev = inode->dev();
out->st_ino = inode->ino();
out->st_mode = inode->mode().mode;
out->st_nlink = inode->nlink();
out->st_uid = inode->uid();
out->st_gid = inode->gid();
out->st_rdev = inode->rdev();
out->st_size = inode->size();
out->st_atim = inode->atime();
out->st_mtim = inode->mtime();
out->st_ctim = inode->ctime();
out->st_blksize = inode->blksize();
out->st_blocks = inode->blocks();
return {};
}
BAN::ErrorOr<void> OpenFileDescriptorSet::close(int fd)
{
TRY(validate_fd(fd));
if (m_open_files[fd]->flags & O_WRONLY && m_open_files[fd]->inode->is_pipe())
((Pipe*)m_open_files[fd]->inode.ptr())->close_writing();
m_open_files[fd].clear();
return {};
}
void OpenFileDescriptorSet::close_all()
{
for (int fd = 0; fd < (int)m_open_files.size(); fd++)
(void)close(fd);
}
void OpenFileDescriptorSet::close_cloexec()
{
for (int fd = 0; fd < (int)m_open_files.size(); fd++)
{
if (validate_fd(fd).is_error())
continue;
if (m_open_files[fd]->flags & O_CLOEXEC)
(void)close(fd);
}
}
BAN::ErrorOr<size_t> OpenFileDescriptorSet::read(int fd, void* buffer, size_t count)
{
TRY(validate_fd(fd));
auto& open_file = m_open_files[fd];
size_t nread = TRY(open_file->inode->read(open_file->offset, buffer, count));
open_file->offset += nread;
return nread;
}
BAN::ErrorOr<size_t> OpenFileDescriptorSet::write(int fd, const void* buffer, size_t count)
{
TRY(validate_fd(fd));
auto& open_file = m_open_files[fd];
size_t nwrite = TRY(open_file->inode->write(open_file->offset, buffer, count));
open_file->offset += nwrite;
return nwrite;
}
BAN::ErrorOr<void> OpenFileDescriptorSet::read_dir_entries(int fd, DirectoryEntryList* list, size_t list_size)
{
TRY(validate_fd(fd));
auto& open_file = m_open_files[fd];
TRY(open_file->inode->read_next_directory_entries(open_file->offset, list, list_size));
open_file->offset++;
return {};
}
BAN::ErrorOr<BAN::StringView> OpenFileDescriptorSet::path_of(int fd) const
{
TRY(validate_fd(fd));
return m_open_files[fd]->path.sv();
}
BAN::ErrorOr<void> OpenFileDescriptorSet::validate_fd(int fd) const
{
if (fd < 0 || fd >= (int)m_open_files.size())
return BAN::Error::from_errno(EBADF);
if (!m_open_files[fd])
return BAN::Error::from_errno(EBADF);
return {};
}
BAN::ErrorOr<int> OpenFileDescriptorSet::get_free_fd() const
{
for (int fd = 0; fd < (int)m_open_files.size(); fd++)
if (!m_open_files[fd])
return fd;
return BAN::Error::from_errno(EMFILE);
}
BAN::ErrorOr<void> OpenFileDescriptorSet::get_free_fd_pair(int fds[2]) const
{
size_t found = 0;
for (int fd = 0; fd < (int)m_open_files.size(); fd++)
{
if (!m_open_files[fd])
fds[found++] = fd;
if (found == 2)
return {};
}
return BAN::Error::from_errno(EMFILE);
}
}

View File

@ -1,6 +1,5 @@
#include <BAN/StringView.h>
#include <kernel/CriticalScope.h>
#include <kernel/FS/Pipe.h>
#include <kernel/FS/VirtualFileSystem.h>
#include <kernel/LockGuard.h>
#include <kernel/Memory/Heap.h>
@ -92,6 +91,7 @@ namespace Kernel
Process::Process(const Credentials& credentials, pid_t pid)
: m_credentials(credentials)
, m_open_file_descriptors(m_credentials)
, m_pid(pid)
, m_tty(TTY::current())
{ }
@ -135,13 +135,7 @@ namespace Kernel
}
m_threads.clear();
for (int fd = 0; fd < (int)m_open_files.size(); fd++)
{
if (validate_fd(fd).is_error())
continue;
(void)sys_close(fd);
}
m_open_file_descriptors.close_all();
// NOTE: We must unmap ranges while the page table is still alive
for (auto* range : m_mapped_ranges)
@ -282,15 +276,7 @@ namespace Kernel
forked->m_tty = m_tty;
forked->m_working_directory = m_working_directory;
forked->m_open_files = m_open_files;
for (int fd = 0; fd < (int)m_open_files.size(); fd++)
{
if (validate_fd(fd).is_error())
continue;
auto& openfd = open_file_description(fd);
if (openfd.flags & O_WRONLY && openfd.inode->is_pipe())
((Pipe*)openfd.inode.ptr())->clone_writing();
}
MUST(forked->m_open_file_descriptors.clone_from(m_open_file_descriptors));
forked->m_userspace_info = m_userspace_info;
@ -339,14 +325,7 @@ namespace Kernel
LockGuard lock_guard(m_lock);
for (int fd = 0; fd < (int)m_open_files.size(); fd++)
{
if (validate_fd(fd).is_error())
continue;
auto& file = open_file_description(fd);
if (file.flags & O_CLOEXEC)
MUST(sys_close(fd));
}
m_open_file_descriptors.close_cloexec();
m_fixed_width_allocators.clear();
m_general_allocator.clear();
@ -513,34 +492,17 @@ namespace Kernel
BAN::ErrorOr<long> Process::sys_open(BAN::StringView path, int flags)
{
if (flags & ~(O_RDONLY | O_WRONLY | O_NOFOLLOW | O_SEARCH | O_CLOEXEC))
return BAN::Error::from_errno(ENOTSUP);
BAN::String absolute_path = TRY(absolute_path_of(path));
auto file = TRY(VirtualFileSystem::get().file_from_absolute_path(m_credentials, absolute_path, flags));
LockGuard _(m_lock);
int fd = TRY(get_free_fd());
auto& open_file_description = m_open_files[fd];
open_file_description.inode = file.inode;
open_file_description.path = BAN::move(file.canonical_path);
open_file_description.offset = 0;
open_file_description.flags = flags;
return fd;
BAN::String absolute_path = TRY(absolute_path_of(path));
return TRY(m_open_file_descriptors.open(absolute_path, flags));
}
BAN::ErrorOr<long> Process::sys_openat(int fd, BAN::StringView path, int flags)
{
BAN::String absolute_path;
{
LockGuard _(m_lock);
TRY(validate_fd(fd));
TRY(absolute_path.append(open_file_description(fd).path));
}
BAN::String absolute_path;
TRY(absolute_path.append(TRY(m_open_file_descriptors.path_of(fd))));
TRY(absolute_path.push_back('/'));
TRY(absolute_path.append(path));
@ -550,149 +512,46 @@ namespace Kernel
BAN::ErrorOr<long> Process::sys_close(int fd)
{
LockGuard _(m_lock);
TRY(validate_fd(fd));
auto& open_file_description = this->open_file_description(fd);
if (open_file_description.flags & O_WRONLY && open_file_description.inode->is_pipe())
((Pipe*)open_file_description.inode.ptr())->close_writing();
open_file_description.inode = nullptr;
TRY(m_open_file_descriptors.close(fd));
return 0;
}
BAN::ErrorOr<long> Process::sys_read(int fd, void* buffer, size_t count)
{
OpenFileDescription open_fd_copy;
{
LockGuard _(m_lock);
TRY(validate_fd(fd));
open_fd_copy = open_file_description(fd);
}
if (!(open_fd_copy.flags & O_RDONLY))
return BAN::Error::from_errno(EBADF);
size_t nread = TRY(open_fd_copy.inode->read(open_fd_copy.offset, buffer, count));
{
LockGuard _(m_lock);
MUST(validate_fd(fd));
open_file_description(fd).offset += nread;
}
return nread;
return TRY(m_open_file_descriptors.read(fd, buffer, count));
}
BAN::ErrorOr<long> Process::sys_write(int fd, const void* buffer, size_t count)
{
OpenFileDescription open_fd_copy;
{
LockGuard _(m_lock);
TRY(validate_fd(fd));
open_fd_copy = open_file_description(fd);
}
if (!(open_fd_copy.flags & O_WRONLY))
return BAN::Error::from_errno(EBADF);
size_t nwrite = TRY(open_fd_copy.inode->write(open_fd_copy.offset, buffer, count));
{
LockGuard _(m_lock);
MUST(validate_fd(fd));
open_file_description(fd).offset += nwrite;
}
return nwrite;
return TRY(m_open_file_descriptors.write(fd, buffer, count));
}
BAN::ErrorOr<long> Process::sys_pipe(int fildes[2])
{
LockGuard _(m_lock);
auto pipe = TRY(Pipe::create(m_credentials));
TRY(get_free_fd_pair(fildes));
auto& openfd_read = m_open_files[fildes[0]];
openfd_read.inode = pipe;
openfd_read.flags = O_RDONLY;
openfd_read.offset = 0;
openfd_read.path.clear();
auto& openfd_write = m_open_files[fildes[1]];
openfd_write.inode = pipe;
openfd_write.flags = O_WRONLY;
openfd_write.offset = 0;
openfd_write.path.clear();
TRY(m_open_file_descriptors.pipe(fildes));
return 0;
}
BAN::ErrorOr<long> Process::sys_dup2(int fildes, int fildes2)
{
// FIXME: m_open_files should be BAN::Array<BAN::RefPtr<OpenFileDescription>, OPEN_MAX> for accurate dup2
if (fildes2 < 0 || fildes2 >= 100)
return BAN::Error::from_errno(EBADF);
LockGuard _(m_lock);
TRY(validate_fd(fildes));
if (fildes == fildes2)
return fildes;
if (m_open_files.size() <= (size_t)fildes2)
TRY(m_open_files.resize(fildes2 + 1));
if (!validate_fd(fildes2).is_error())
TRY(sys_close(fildes2));
m_open_files[fildes2] = m_open_files[fildes];
m_open_files[fildes2].flags &= ~O_CLOEXEC;
if (m_open_files[fildes].flags & O_WRONLY && m_open_files[fildes].inode->is_pipe())
((Pipe*)m_open_files[fildes].inode.ptr())->clone_writing();
return fildes;
return TRY(m_open_file_descriptors.dup2(fildes, fildes2));
}
BAN::ErrorOr<long> Process::sys_seek(int fd, off_t offset, int whence)
{
LockGuard _(m_lock);
TRY(validate_fd(fd));
auto& open_fd = open_file_description(fd);
off_t new_offset = 0;
switch (whence)
{
case SEEK_CUR:
new_offset = open_fd.offset + offset;
break;
case SEEK_END:
new_offset = open_fd.inode->size() - offset;
break;
case SEEK_SET:
new_offset = offset;
break;
default:
return BAN::Error::from_errno(EINVAL);
}
if (new_offset < 0)
return BAN::Error::from_errno(EINVAL);
open_fd.offset = new_offset;
TRY(m_open_file_descriptors.seek(fd, offset, whence));
return 0;
}
BAN::ErrorOr<long> Process::sys_tell(int fd)
{
LockGuard _(m_lock);
TRY(validate_fd(fd));
return open_file_description(fd).offset;
return TRY(m_open_file_descriptors.tell(fd));
}
BAN::ErrorOr<long> Process::sys_creat(BAN::StringView path, mode_t mode)
@ -726,29 +585,9 @@ namespace Kernel
}
BAN::ErrorOr<long> Process::sys_fstat(int fd, struct stat* out)
{
OpenFileDescription open_fd_copy;
{
LockGuard _(m_lock);
TRY(validate_fd(fd));
open_fd_copy = open_file_description(fd);
}
out->st_dev = open_fd_copy.inode->dev();
out->st_ino = open_fd_copy.inode->ino();
out->st_mode = open_fd_copy.inode->mode().mode;
out->st_nlink = open_fd_copy.inode->nlink();
out->st_uid = open_fd_copy.inode->uid();
out->st_gid = open_fd_copy.inode->gid();
out->st_rdev = open_fd_copy.inode->rdev();
out->st_size = open_fd_copy.inode->size();
out->st_atim = open_fd_copy.inode->atime();
out->st_mtim = open_fd_copy.inode->mtime();
out->st_ctim = open_fd_copy.inode->ctime();
out->st_blksize = open_fd_copy.inode->blksize();
out->st_blocks = open_fd_copy.inode->blocks();
TRY(m_open_file_descriptors.fstat(fd, out));
return 0;
}
@ -761,23 +600,9 @@ namespace Kernel
}
BAN::ErrorOr<long> Process::sys_read_dir_entries(int fd, DirectoryEntryList* list, size_t list_size)
{
OpenFileDescription open_fd_copy;
{
LockGuard _(m_lock);
TRY(validate_fd(fd));
open_fd_copy = open_file_description(fd);
}
TRY(open_fd_copy.inode->read_next_directory_entries(open_fd_copy.offset, list, list_size));
{
LockGuard _(m_lock);
MUST(validate_fd(fd));
open_file_description(fd).offset = open_fd_copy.offset + 1;
}
TRY(m_open_file_descriptors.read_dir_entries(fd, list, list_size));
return 0;
}
@ -1131,52 +956,4 @@ namespace Kernel
return absolute_path;
}
BAN::ErrorOr<void> Process::validate_fd(int fd)
{
ASSERT(m_lock.is_locked());
if (fd < 0 || m_open_files.size() <= (size_t)fd || !m_open_files[fd].inode)
return BAN::Error::from_errno(EBADF);
return {};
}
Process::OpenFileDescription& Process::open_file_description(int fd)
{
ASSERT(m_lock.is_locked());
MUST(validate_fd(fd));
return m_open_files[fd];
}
BAN::ErrorOr<int> Process::get_free_fd()
{
ASSERT(m_lock.is_locked());
for (size_t fd = 0; fd < m_open_files.size(); fd++)
if (!m_open_files[fd].inode)
return fd;
TRY(m_open_files.push_back({}));
return m_open_files.size() - 1;
}
BAN::ErrorOr<void> Process::get_free_fd_pair(int fds[2])
{
ASSERT(m_lock.is_locked());
int found = 0;
for (size_t fd = 0; fd < m_open_files.size(); fd++)
{
if (!m_open_files[fd].inode)
{
fds[found++] = fd;
if (found >= 2)
return {};
}
}
while (found < 2)
{
TRY(m_open_files.push_back({}));
fds[found++] = m_open_files.size() - 1;
}
return {};
}
}