Kernel: Improve locking in Process, VFS and ATAController

We used to block on all process access. This meant that shell
reading the keyboard input would block all VFS access making disk
accesses practically impossible. We now block only when it is
necessary :)
This commit is contained in:
Bananymous 2023-03-30 22:02:16 +03:00
parent 88ee35165f
commit eef3631a5a
7 changed files with 90 additions and 60 deletions

View File

@ -1,10 +1,9 @@
#pragma once #pragma once
#include <BAN/HashMap.h>
#include <BAN/String.h> #include <BAN/String.h>
#include <BAN/StringView.h> #include <BAN/Vector.h>
#include <kernel/FS/FileSystem.h> #include <kernel/FS/FileSystem.h>
#include <kernel/Storage/StorageController.h> #include <kernel/SpinLock.h>
namespace Kernel namespace Kernel
{ {
@ -19,6 +18,7 @@ namespace Kernel
virtual BAN::RefPtr<Inode> root_inode() override { return m_root_fs->root_inode(); } virtual BAN::RefPtr<Inode> root_inode() override { return m_root_fs->root_inode(); }
BAN::ErrorOr<void> mount(BAN::StringView, BAN::StringView); BAN::ErrorOr<void> mount(BAN::StringView, BAN::StringView);
BAN::ErrorOr<void> mount(FileSystem*, BAN::StringView);
struct File struct File
{ {
@ -29,7 +29,6 @@ namespace Kernel
private: private:
VirtualFileSystem() = default; VirtualFileSystem() = default;
BAN::ErrorOr<void> mount(FileSystem*, BAN::StringView);
struct MountPoint struct MountPoint
{ {
@ -39,9 +38,9 @@ namespace Kernel
MountPoint* mount_point_for_inode(BAN::RefPtr<Inode>); MountPoint* mount_point_for_inode(BAN::RefPtr<Inode>);
private: private:
SpinLock m_lock;
FileSystem* m_root_fs = nullptr; FileSystem* m_root_fs = nullptr;
BAN::Vector<MountPoint> m_mount_points; BAN::Vector<MountPoint> m_mount_points;
BAN::Vector<StorageController*> m_storage_controllers;
}; };
} }

View File

@ -41,7 +41,7 @@ namespace Kernel
BAN::ErrorOr<BAN::Vector<BAN::String>> read_directory_entries(int); BAN::ErrorOr<BAN::Vector<BAN::String>> read_directory_entries(int);
BAN::String working_directory() const; BAN::ErrorOr<BAN::String> working_directory() const;
BAN::ErrorOr<void> set_working_directory(BAN::StringView); BAN::ErrorOr<void> set_working_directory(BAN::StringView);
static BAN::RefPtr<Process> current() { return Thread::current().process(); } static BAN::RefPtr<Process> current() { return Thread::current().process(); }

View File

@ -87,6 +87,7 @@ namespace Kernel
private: private:
ATABus m_buses[2]; ATABus m_buses[2];
const PCIDevice& m_pci_device; const PCIDevice& m_pci_device;
SpinLock m_lock;
friend class ATADevice; friend class ATADevice;

View File

@ -1,11 +1,10 @@
#include <BAN/ScopeGuard.h> #include <BAN/ScopeGuard.h>
#include <BAN/StringView.h> #include <BAN/StringView.h>
#include <BAN/Vector.h>
#include <kernel/Device.h> #include <kernel/Device.h>
#include <kernel/FS/Ext2.h> #include <kernel/FS/Ext2.h>
#include <kernel/FS/VirtualFileSystem.h> #include <kernel/FS/VirtualFileSystem.h>
#include <kernel/LockGuard.h>
#include <kernel/PCI.h> #include <kernel/PCI.h>
#include <kernel/Storage/ATAController.h>
namespace Kernel namespace Kernel
{ {
@ -45,9 +44,11 @@ namespace Kernel
auto partition_file = TRY(file_from_absolute_path(partition)); auto partition_file = TRY(file_from_absolute_path(partition));
if (partition_file.inode->inode_type() != Inode::InodeType::Device) if (partition_file.inode->inode_type() != Inode::InodeType::Device)
return BAN::Error::from_c_string("Not a partition"); return BAN::Error::from_c_string("Not a partition");
Device* device = (Device*)partition_file.inode.ptr(); Device* device = (Device*)partition_file.inode.ptr();
if (device->device_type() != Device::DeviceType::Partition) if (device->device_type() != Device::DeviceType::Partition)
return BAN::Error::from_c_string("Not a partition"); return BAN::Error::from_c_string("Not a partition");
auto* file_system = TRY(Ext2FS::create(*(Partition*)device)); auto* file_system = TRY(Ext2FS::create(*(Partition*)device));
return mount(file_system, target); return mount(file_system, target);
} }
@ -57,12 +58,16 @@ namespace Kernel
auto file = TRY(file_from_absolute_path(path)); auto file = TRY(file_from_absolute_path(path));
if (!file.inode->mode().ifdir()) if (!file.inode->mode().ifdir())
return BAN::Error::from_errno(ENOTDIR); return BAN::Error::from_errno(ENOTDIR);
LockGuard _(m_lock);
TRY(m_mount_points.push_back({ file, file_system })); TRY(m_mount_points.push_back({ file, file_system }));
return {}; return {};
} }
VirtualFileSystem::MountPoint* VirtualFileSystem::mount_point_for_inode(BAN::RefPtr<Inode> inode) VirtualFileSystem::MountPoint* VirtualFileSystem::mount_point_for_inode(BAN::RefPtr<Inode> inode)
{ {
ASSERT(m_lock.is_locked());
for (MountPoint& mount : m_mount_points) for (MountPoint& mount : m_mount_points)
if (*mount.host.inode == *inode) if (*mount.host.inode == *inode)
return &mount; return &mount;
@ -71,6 +76,8 @@ namespace Kernel
BAN::ErrorOr<VirtualFileSystem::File> VirtualFileSystem::file_from_absolute_path(BAN::StringView path) BAN::ErrorOr<VirtualFileSystem::File> VirtualFileSystem::file_from_absolute_path(BAN::StringView path)
{ {
LockGuard _(m_lock);
ASSERT(path.front() == '/'); ASSERT(path.front() == '/');
auto inode = root_inode(); auto inode = root_inode();

View File

@ -20,9 +20,9 @@ namespace Kernel
BAN::ErrorOr<void> Process::add_thread(entry_t entry, void* data) BAN::ErrorOr<void> Process::add_thread(entry_t entry, void* data)
{ {
LockGuard _(m_lock);
Thread* thread = TRY(Thread::create(entry, data, this)); Thread* thread = TRY(Thread::create(entry, data, this));
LockGuard _(m_lock);
TRY(m_threads.push_back(thread)); TRY(m_threads.push_back(thread));
if (auto res = Scheduler::get().add_thread(thread); res.is_error()) if (auto res = Scheduler::get().add_thread(thread); res.is_error())
{ {
@ -43,8 +43,6 @@ namespace Kernel
BAN::ErrorOr<int> Process::open(BAN::StringView path, int flags) BAN::ErrorOr<int> Process::open(BAN::StringView path, int flags)
{ {
LockGuard _(m_lock);
if (flags != O_RDONLY) if (flags != O_RDONLY)
return BAN::Error::from_errno(ENOTSUP); return BAN::Error::from_errno(ENOTSUP);
@ -52,6 +50,7 @@ namespace Kernel
auto file = TRY(VirtualFileSystem::get().file_from_absolute_path(absolute_path)); auto file = TRY(VirtualFileSystem::get().file_from_absolute_path(absolute_path));
LockGuard _(m_lock);
int fd = TRY(get_free_fd()); int fd = TRY(get_free_fd());
auto& open_file_description = m_open_files[fd]; auto& open_file_description = m_open_files[fd];
open_file_description.inode = file.inode; open_file_description.inode = file.inode;
@ -73,63 +72,70 @@ namespace Kernel
BAN::ErrorOr<size_t> Process::read(int fd, void* buffer, size_t count) BAN::ErrorOr<size_t> Process::read(int fd, void* buffer, size_t count)
{ {
LockGuard _(m_lock); m_lock.lock();
TRY(validate_fd(fd)); TRY(validate_fd(fd));
auto& open_fd = open_file_description(fd); auto open_fd_copy = open_file_description(fd);
if (!(open_fd.flags & O_RDONLY)) m_lock.unlock();
if (!(open_fd_copy.flags & O_RDONLY))
return BAN::Error::from_errno(EBADF); return BAN::Error::from_errno(EBADF);
size_t n_read = TRY(open_fd.inode->read(open_fd.offset, buffer, count)); size_t n_read = TRY(open_fd_copy.inode->read(open_fd_copy.offset, buffer, count));
open_fd.offset += n_read; open_fd_copy.offset += n_read;
m_lock.lock();
MUST(validate_fd(fd));
open_file_description(fd) = open_fd_copy;
m_lock.unlock();
return n_read; return n_read;
} }
BAN::ErrorOr<void> Process::creat(BAN::StringView path, mode_t mode) BAN::ErrorOr<void> Process::creat(BAN::StringView path, mode_t mode)
{ {
LockGuard _(m_lock);
auto absolute_path = TRY(absolute_path_of(path)); auto absolute_path = TRY(absolute_path_of(path));
while (absolute_path.sv().back() != '/') while (absolute_path.back() != '/')
absolute_path.pop_back(); absolute_path.pop_back();
auto parent_inode = TRY(VirtualFileSystem::get().file_from_absolute_path(absolute_path));
auto parent_file = TRY(VirtualFileSystem::get().file_from_absolute_path(absolute_path));
if (path.count('/') > 0) if (path.count('/') > 0)
return BAN::Error::from_c_string("You can only create files to current working directory"); return BAN::Error::from_c_string("You can only create files to current working directory");
TRY(parent_inode.inode->create_file(path, mode)); TRY(parent_file.inode->create_file(path, mode));
return {}; return {};
} }
BAN::ErrorOr<void> Process::mount(BAN::StringView partition, BAN::StringView path) BAN::ErrorOr<void> Process::mount(BAN::StringView partition, BAN::StringView path)
{ {
LockGuard _(m_lock);
TRY(VirtualFileSystem::get().mount(partition, path)); TRY(VirtualFileSystem::get().mount(partition, path));
return {}; return {};
} }
BAN::ErrorOr<void> Process::fstat(int fd, struct stat* out) BAN::ErrorOr<void> Process::fstat(int fd, struct stat* out)
{ {
LockGuard _(m_lock); m_lock.lock();
TRY(validate_fd(fd)); TRY(validate_fd(fd));
const auto& open_fd = open_file_description(fd); auto open_fd_copy = open_file_description(fd);
m_lock.unlock();
out->st_dev = open_fd.inode->dev(); out->st_dev = open_fd_copy.inode->dev();
out->st_ino = open_fd.inode->ino(); out->st_ino = open_fd_copy.inode->ino();
out->st_mode = open_fd.inode->mode().mode; out->st_mode = open_fd_copy.inode->mode().mode;
out->st_nlink = open_fd.inode->nlink(); out->st_nlink = open_fd_copy.inode->nlink();
out->st_uid = open_fd.inode->uid(); out->st_uid = open_fd_copy.inode->uid();
out->st_gid = open_fd.inode->gid(); out->st_gid = open_fd_copy.inode->gid();
out->st_rdev = open_fd.inode->rdev(); out->st_rdev = open_fd_copy.inode->rdev();
out->st_size = open_fd.inode->size(); out->st_size = open_fd_copy.inode->size();
out->st_atim = open_fd.inode->atime(); out->st_atim = open_fd_copy.inode->atime();
out->st_mtim = open_fd.inode->mtime(); out->st_mtim = open_fd_copy.inode->mtime();
out->st_ctim = open_fd.inode->ctime(); out->st_ctim = open_fd_copy.inode->ctime();
out->st_blksize = open_fd.inode->blksize(); out->st_blksize = open_fd_copy.inode->blksize();
out->st_blocks = open_fd.inode->blocks(); out->st_blocks = open_fd_copy.inode->blocks();
return {}; return {};
} }
BAN::ErrorOr<void> Process::stat(BAN::StringView path, struct stat* out) BAN::ErrorOr<void> Process::stat(BAN::StringView path, struct stat* out)
{ {
LockGuard _(m_lock);
int fd = TRY(open(path, O_RDONLY)); int fd = TRY(open(path, O_RDONLY));
auto ret = fstat(fd, out); auto ret = fstat(fd, out);
MUST(close(fd)); MUST(close(fd));
@ -138,30 +144,41 @@ namespace Kernel
BAN::ErrorOr<BAN::Vector<BAN::String>> Process::read_directory_entries(int fd) BAN::ErrorOr<BAN::Vector<BAN::String>> Process::read_directory_entries(int fd)
{ {
LockGuard _(m_lock); m_lock.lock();
TRY(validate_fd(fd)); TRY(validate_fd(fd));
auto& open_fd = open_file_description(fd); auto open_fd_copy = open_file_description(fd);
auto result = TRY(open_fd.inode->read_directory_entries(open_fd.offset)); m_lock.unlock();
open_fd.offset++;
auto result = TRY(open_fd_copy.inode->read_directory_entries(open_fd_copy.offset));
open_fd_copy.offset++;
m_lock.lock();
MUST(validate_fd(fd));
open_file_description(fd) = open_fd_copy;
m_lock.unlock();
return result; return result;
} }
BAN::String Process::working_directory() const BAN::ErrorOr<BAN::String> Process::working_directory() const
{ {
BAN::String result;
LockGuard _(m_lock); LockGuard _(m_lock);
return m_working_directory; TRY(result.append(m_working_directory));
return result;
} }
BAN::ErrorOr<void> Process::set_working_directory(BAN::StringView path) BAN::ErrorOr<void> Process::set_working_directory(BAN::StringView path)
{ {
LockGuard _(m_lock);
BAN::String absolute_path = TRY(absolute_path_of(path)); BAN::String absolute_path = TRY(absolute_path_of(path));
auto file = TRY(VirtualFileSystem::get().file_from_absolute_path(absolute_path)); auto file = TRY(VirtualFileSystem::get().file_from_absolute_path(absolute_path));
if (!file.inode->mode().ifdir()) if (!file.inode->mode().ifdir())
return BAN::Error::from_errno(ENOTDIR); return BAN::Error::from_errno(ENOTDIR);
LockGuard _(m_lock);
m_working_directory = BAN::move(file.canonical_path); m_working_directory = BAN::move(file.canonical_path);
return {}; return {};
@ -169,24 +186,23 @@ namespace Kernel
BAN::ErrorOr<BAN::String> Process::absolute_path_of(BAN::StringView path) const BAN::ErrorOr<BAN::String> Process::absolute_path_of(BAN::StringView path) const
{ {
LockGuard _(m_lock);
if (path.empty()) if (path.empty())
return m_working_directory; return working_directory();
BAN::String absolute_path; BAN::String absolute_path;
if (path.front() != '/') if (path.front() != '/')
{ {
LockGuard _(m_lock);
TRY(absolute_path.append(m_working_directory)); TRY(absolute_path.append(m_working_directory));
if (m_working_directory.sv().back() != '/')
TRY(absolute_path.push_back('/'));
} }
if (!absolute_path.empty() && absolute_path.back() != '/')
TRY(absolute_path.push_back('/'));
TRY(absolute_path.append(path)); TRY(absolute_path.append(path));
return absolute_path; return absolute_path;
} }
BAN::ErrorOr<void> Process::validate_fd(int fd) BAN::ErrorOr<void> Process::validate_fd(int fd)
{ {
LockGuard _(m_lock); ASSERT(m_lock.is_locked());
if (fd < 0 || m_open_files.size() <= (size_t)fd || !m_open_files[fd].inode) if (fd < 0 || m_open_files.size() <= (size_t)fd || !m_open_files[fd].inode)
return BAN::Error::from_errno(EBADF); return BAN::Error::from_errno(EBADF);
return {}; return {};
@ -194,16 +210,14 @@ namespace Kernel
Process::OpenFileDescription& Process::open_file_description(int fd) Process::OpenFileDescription& Process::open_file_description(int fd)
{ {
LockGuard _(m_lock); ASSERT(m_lock.is_locked());
MUST(validate_fd(fd)); MUST(validate_fd(fd));
return m_open_files[fd]; return m_open_files[fd];
} }
BAN::ErrorOr<int> Process::get_free_fd() BAN::ErrorOr<int> Process::get_free_fd()
{ {
LockGuard _(m_lock); ASSERT(m_lock.is_locked());
for (size_t fd = 0; fd < m_open_files.size(); fd++) for (size_t fd = 0; fd < m_open_files.size(); fd++)
if (!m_open_files[fd].inode) if (!m_open_files[fd].inode)
return fd; return fd;

View File

@ -77,7 +77,7 @@ namespace Kernel
break; break;
case 'w': case 'w':
{ {
auto working_directory = Process::current()->working_directory(); auto working_directory = TRY(Process::current()->working_directory());
TRY(m_prompt.append(working_directory)); TRY(m_prompt.append(working_directory));
m_prompt_length += working_directory.size(); m_prompt_length += working_directory.size();
break; break;
@ -379,7 +379,11 @@ argument_done:
if (arguments.size() > 2) if (arguments.size() > 2)
return BAN::Error::from_c_string("usage: 'ls [path]'"); return BAN::Error::from_c_string("usage: 'ls [path]'");
BAN::String path = (arguments.size() == 2) ? arguments[1] : Process::current()->working_directory(); BAN::String path;
if (arguments.size() == 2)
TRY(path.append(arguments[1]));
else
TRY(path.append(TRY(Process::current()->working_directory())));
int fd = TRY(Process::current()->open(path, O_RDONLY)); int fd = TRY(Process::current()->open(path, O_RDONLY));
BAN::ScopeGuard _([fd] { MUST(Process::current()->close(fd)); }); BAN::ScopeGuard _([fd] { MUST(Process::current()->close(fd)); });

View File

@ -1,4 +1,5 @@
#include <kernel/IO.h> #include <kernel/IO.h>
#include <kernel/LockGuard.h>
#include <kernel/Storage/ATAController.h> #include <kernel/Storage/ATAController.h>
#define ATA_PRIMARY 0 #define ATA_PRIMARY 0
@ -203,6 +204,8 @@ namespace Kernel
if (lba + sector_count > device->lba_count) if (lba + sector_count > device->lba_count)
return BAN::Error::from_c_string("Attempted to read outside of the device boundaries"); return BAN::Error::from_c_string("Attempted to read outside of the device boundaries");
LockGuard _(m_lock);
if (lba < (1 << 28)) if (lba < (1 << 28))
{ {
// LBA28 // LBA28
@ -233,6 +236,8 @@ namespace Kernel
if (lba + sector_count > device->lba_count) if (lba + sector_count > device->lba_count)
return BAN::Error::from_c_string("Attempted to read outside of the device boundaries"); return BAN::Error::from_c_string("Attempted to read outside of the device boundaries");
LockGuard _(m_lock);
if (lba < (1 << 28)) if (lba < (1 << 28))
{ {
// LBA28 // LBA28