Kernel: Remove the big inode lock

This moves locking to the inodes themselves which allows reducing lock
times significantly. Main inodes (ext2 and tmpfs) still do contain a
single big mutex that gets locked during operations but now we have the
architecture to optimize these.
This commit is contained in:
2026-05-09 21:30:05 +03:00
parent a7356716ff
commit 9f4271f6d8
31 changed files with 378 additions and 189 deletions

View File

@@ -2,6 +2,7 @@
#include <BAN/HashMap.h> #include <BAN/HashMap.h>
#include <kernel/FS/Inode.h> #include <kernel/FS/Inode.h>
#include <kernel/Lock/Mutex.h>
#include <sys/epoll.h> #include <sys/epoll.h>
@@ -90,6 +91,7 @@ namespace Kernel
}; };
private: private:
Mutex m_mutex;
ThreadBlocker m_thread_blocker; ThreadBlocker m_thread_blocker;
SpinLock m_ready_lock; SpinLock m_ready_lock;
BAN::HashMap<BAN::RefPtr<Inode>, uint32_t> m_ready_events; BAN::HashMap<BAN::RefPtr<Inode>, uint32_t> m_ready_events;

View File

@@ -1,6 +1,7 @@
#pragma once #pragma once
#include <kernel/FS/Inode.h> #include <kernel/FS/Inode.h>
#include <kernel/Lock/Mutex.h>
namespace Kernel namespace Kernel
{ {
@@ -44,8 +45,9 @@ namespace Kernel
private: private:
const bool m_is_semaphore; const bool m_is_semaphore;
uint64_t m_value; BAN::Atomic<uint64_t> m_value;
Mutex m_mutex;
ThreadBlocker m_thread_blocker; ThreadBlocker m_thread_blocker;
}; };

View File

@@ -4,6 +4,7 @@
#include <BAN/StringView.h> #include <BAN/StringView.h>
#include <kernel/FS/Ext2/Definitions.h> #include <kernel/FS/Ext2/Definitions.h>
#include <kernel/FS/Inode.h> #include <kernel/FS/Inode.h>
#include <kernel/Lock/Mutex.h>
namespace Kernel namespace Kernel
{ {
@@ -110,6 +111,9 @@ namespace Kernel
Ext2::Inode m_inode; Ext2::Inode m_inode;
const uint32_t m_ino; const uint32_t m_ino;
// TODO: try to reduce locking or replace this with rwlock(?)
Mutex m_lock;
friend class Ext2FS; friend class Ext2FS;
friend class BAN::RefPtr<Ext2Inode>; friend class BAN::RefPtr<Ext2Inode>;
}; };

View File

@@ -10,7 +10,6 @@
#include <kernel/Credentials.h> #include <kernel/Credentials.h>
#include <kernel/Debug.h> #include <kernel/Debug.h>
#include <kernel/Lock/Mutex.h>
#include <dirent.h> #include <dirent.h>
#include <sys/socket.h> #include <sys/socket.h>
@@ -183,11 +182,10 @@ namespace Kernel
virtual BAN::ErrorOr<long> ioctl_impl(int, void*) { return BAN::Error::from_errno(ENOTSUP); } virtual BAN::ErrorOr<long> ioctl_impl(int, void*) { return BAN::Error::from_errno(ENOTSUP); }
protected:
mutable PriorityMutex m_mutex;
private: private:
SpinLock m_shared_region_lock;
BAN::WeakPtr<SharedFileData> m_shared_region; BAN::WeakPtr<SharedFileData> m_shared_region;
SpinLock m_epoll_lock; SpinLock m_epoll_lock;
BAN::LinkedList<class Epoll*> m_epolls; BAN::LinkedList<class Epoll*> m_epolls;
friend class Epoll; friend class Epoll;

View File

@@ -1,7 +1,7 @@
#pragma once #pragma once
#include <BAN/Array.h>
#include <kernel/FS/Inode.h> #include <kernel/FS/Inode.h>
#include <kernel/Lock/Mutex.h>
#include <kernel/Memory/ByteRingBuffer.h> #include <kernel/Memory/ByteRingBuffer.h>
#include <kernel/ThreadBlocker.h> #include <kernel/ThreadBlocker.h>
@@ -53,6 +53,8 @@ namespace Kernel
timespec m_atime {}; timespec m_atime {};
timespec m_mtime {}; timespec m_mtime {};
timespec m_ctime {}; timespec m_ctime {};
Mutex m_mutex;
ThreadBlocker m_thread_blocker; ThreadBlocker m_thread_blocker;
BAN::UniqPtr<ByteRingBuffer> m_buffer; BAN::UniqPtr<ByteRingBuffer> m_buffer;

View File

@@ -4,6 +4,7 @@
#include <BAN/Optional.h> #include <BAN/Optional.h>
#include <kernel/FS/Inode.h> #include <kernel/FS/Inode.h>
#include <kernel/FS/TmpFS/Definitions.h> #include <kernel/FS/TmpFS/Definitions.h>
#include <kernel/Lock/Mutex.h>
namespace Kernel namespace Kernel
{ {
@@ -53,22 +54,25 @@ namespace Kernel
virtual BAN::ErrorOr<void> fsync_impl() override { return {}; } virtual BAN::ErrorOr<void> fsync_impl() override { return {}; }
void sync(); void sync();
virtual BAN::ErrorOr<void> prepare_unlink() { return {}; }; virtual BAN::ErrorOr<void> prepare_unlink_no_lock() { return {}; };
void free_all_blocks(); void free_all_blocks();
void free_indirect_blocks(size_t block, uint32_t depth); void free_indirect_blocks_no_lock(size_t block, uint32_t depth);
BAN::Optional<size_t> block_index(size_t data_block_index); BAN::Optional<size_t> block_index(size_t data_block_index);
BAN::Optional<size_t> block_index_from_indirect(size_t block, size_t index, uint32_t depth); BAN::Optional<size_t> block_index_from_indirect_no_lock(size_t block, size_t index, uint32_t depth);
BAN::ErrorOr<size_t> block_index_with_allocation(size_t data_block_index); BAN::ErrorOr<size_t> block_index_with_allocation(size_t data_block_index);
BAN::ErrorOr<size_t> block_index_from_indirect_with_allocation(size_t& block, size_t index, uint32_t depth); BAN::ErrorOr<size_t> block_index_from_indirect_with_allocation_no_lock(size_t& block, size_t index, uint32_t depth);
protected: protected:
TmpFileSystem& m_fs; TmpFileSystem& m_fs;
TmpInodeInfo m_inode_info; TmpInodeInfo m_inode_info;
const ino_t m_ino; const ino_t m_ino;
// TODO: try to reduce locking or replace this with rwlock(?)
Mutex m_lock;
// has to be able to increase link count // has to be able to increase link count
friend class TmpDirectoryInode; friend class TmpDirectoryInode;
}; };
@@ -149,7 +153,7 @@ namespace Kernel
protected: protected:
TmpDirectoryInode(TmpFileSystem&, ino_t, const TmpInodeInfo&); TmpDirectoryInode(TmpFileSystem&, ino_t, const TmpInodeInfo&);
virtual BAN::ErrorOr<void> prepare_unlink() override; virtual BAN::ErrorOr<void> prepare_unlink_no_lock() override;
protected: protected:
virtual BAN::ErrorOr<BAN::RefPtr<Inode>> find_inode_impl(BAN::StringView) override final; virtual BAN::ErrorOr<BAN::RefPtr<Inode>> find_inode_impl(BAN::StringView) override final;

View File

@@ -46,7 +46,7 @@ namespace Kernel
uint32_t lock_depth() const override { return m_lock_depth; } uint32_t lock_depth() const override { return m_lock_depth; }
private: private:
SpinLock& m_lock; Lock& m_lock;
uint32_t m_lock_depth { 0 }; uint32_t m_lock_depth { 0 };
InterruptState m_state; InterruptState m_state;
const pid_t m_locker; const pid_t m_locker;

View File

@@ -181,6 +181,7 @@ namespace Kernel
uint64_t m_time_wait_start_ms { 0 }; uint64_t m_time_wait_start_ms { 0 };
mutable Mutex m_mutex;
ThreadBlocker m_thread_blocker; ThreadBlocker m_thread_blocker;
RecvWindowInfo m_recv_window; RecvWindowInfo m_recv_window;

View File

@@ -66,9 +66,12 @@ namespace Kernel
SpinLock m_packet_lock; SpinLock m_packet_lock;
ThreadBlocker m_packet_thread_blocker; ThreadBlocker m_packet_thread_blocker;
SpinLock m_peer_address_lock;
sockaddr_storage m_peer_address {}; sockaddr_storage m_peer_address {};
socklen_t m_peer_address_len { 0 }; socklen_t m_peer_address_len { 0 };
Mutex m_bind_lock;
friend class BAN::RefPtr<UDPSocket>; friend class BAN::RefPtr<UDPSocket>;
}; };

View File

@@ -43,15 +43,16 @@ namespace Kernel
UnixDomainSocket(Socket::Type, const Socket::Info&); UnixDomainSocket(Socket::Type, const Socket::Info&);
~UnixDomainSocket(); ~UnixDomainSocket();
bool is_bound() const { return !m_bound_file.canonical_path.empty(); } bool is_bound() const;
bool is_bound_to_unused() const { return !m_bound_file.inode; } bool is_bound_to_unused() const;
BAN::ErrorOr<void> bind_to_unused_if_not_bound();
bool is_streaming() const; bool is_streaming() const;
private: private:
struct ConnectionInfo struct ConnectionInfo
{ {
bool listening { false }; BAN::Atomic<bool> listening { false };
BAN::Atomic<bool> connection_done { false }; BAN::Atomic<bool> connection_done { false };
mutable BAN::Atomic<bool> target_closed { false }; mutable BAN::Atomic<bool> target_closed { false };
BAN::WeakPtr<UnixDomainSocket> connection; BAN::WeakPtr<UnixDomainSocket> connection;
@@ -62,6 +63,7 @@ namespace Kernel
struct ConnectionlessInfo struct ConnectionlessInfo
{ {
SpinLock lock;
BAN::String peer_address; BAN::String peer_address;
}; };
@@ -76,7 +78,9 @@ namespace Kernel
BAN::ErrorOr<size_t> add_packet(const msghdr&, PacketInfo&&, bool dont_block); BAN::ErrorOr<size_t> add_packet(const msghdr&, PacketInfo&&, bool dont_block);
private: private:
const Socket::Type m_socket_type; const Socket::Type m_socket_type;
mutable Mutex m_bind_mutex;
VirtualFileSystem::File m_bound_file; VirtualFileSystem::File m_bound_file;
BAN::Variant<ConnectionInfo, ConnectionlessInfo> m_info; BAN::Variant<ConnectionInfo, ConnectionlessInfo> m_info;

View File

@@ -67,7 +67,7 @@ namespace Kernel
bool putchar_impl(uint8_t ch) override; bool putchar_impl(uint8_t ch) override;
bool can_write_impl() const override; bool can_write_impl() const override;
bool has_hungup_impl() const override { return !m_master.valid(); } bool has_hungup_impl() const override { return master_has_closed(); }
private: private:
PseudoTerminalSlave(BAN::String&& name, uint32_t number, mode_t, uid_t, gid_t); PseudoTerminalSlave(BAN::String&& name, uint32_t number, mode_t, uid_t, gid_t);

View File

@@ -46,12 +46,14 @@ namespace Kernel
static void keyboard_task(void*); static void keyboard_task(void*);
static void initialize_devices(); static void initialize_devices();
bool should_receive_input() const { return m_tty_ctrl.receive_input; }
void on_key_event(LibInput::RawKeyEvent);
void on_key_event(LibInput::KeyEvent); void on_key_event(LibInput::KeyEvent);
void handle_input_byte(uint8_t); void handle_input_byte(uint8_t);
void get_termios(termios* termios) { *termios = m_termios; } void get_termios(termios*);
// FIXME: validate termios BAN::ErrorOr<void> set_termios(const termios*);
BAN::ErrorOr<void> set_termios(const termios* termios) { m_termios = *termios; return {}; }
virtual bool is_tty() const override { return true; } virtual bool is_tty() const override { return true; }
@@ -85,9 +87,6 @@ namespace Kernel
bool putchar(uint8_t ch); bool putchar(uint8_t ch);
void do_backspace(); void do_backspace();
protected:
termios m_termios;
private: private:
const dev_t m_rdev; const dev_t m_rdev;
@@ -95,23 +94,27 @@ namespace Kernel
struct tty_ctrl_t struct tty_ctrl_t
{ {
bool draw_graphics { true }; BAN::Atomic<bool> draw_graphics { true };
bool receive_input { true }; BAN::Atomic<bool> receive_input { true };
ThreadBlocker thread_blocker;
}; };
tty_ctrl_t m_tty_ctrl; tty_ctrl_t m_tty_ctrl;
struct Buffer struct Buffer
{ {
BAN::UniqPtr<ByteRingBuffer> buffer; BAN::UniqPtr<ByteRingBuffer> buffer;
bool flush { false }; BAN::Atomic<bool> flush { false };
ThreadBlocker thread_blocker; ThreadBlocker thread_blocker;
}; };
Buffer m_output; Buffer m_output;
winsize m_winsize {}; winsize m_winsize {};
SpinLock m_termios_lock;
termios m_termios;
protected: protected:
Mutex m_mutex;
RecursiveSpinLock m_write_lock; RecursiveSpinLock m_write_lock;
ThreadBlocker m_write_blocker; ThreadBlocker m_write_blocker;
}; };

View File

@@ -62,8 +62,8 @@ namespace Kernel
Mutex m_command_mutex; Mutex m_command_mutex;
BAN::Atomic<bool> m_has_initialized_leds { false }; BAN::Atomic<bool> m_has_initialized_leds { false };
uint8_t m_led_state { 0b0001 }; BAN::Atomic<uint8_t> m_led_state { 0b0001 };
uint8_t m_rumble_strength { 0x00 }; BAN::Atomic<uint8_t> m_rumble_strength { 0x00 };
friend class BAN::RefPtr<USBJoystick>; friend class BAN::RefPtr<USBJoystick>;
}; };

View File

@@ -57,7 +57,7 @@ namespace Kernel::ACPI
m_last_value = target_conv.value().as.integer.value; m_last_value = target_conv.value().as.integer.value;
} }
auto target_str = TRY(BAN::String::formatted("{}", m_last_value)); auto target_str = TRY(BAN::String::formatted("{}", m_last_value.load()));
if (static_cast<size_t>(offset) >= target_str.size()) if (static_cast<size_t>(offset) >= target_str.size())
return 0; return 0;
@@ -67,8 +67,8 @@ namespace Kernel::ACPI
return ncopy; return ncopy;
} }
BAN::ErrorOr<size_t> write_impl(off_t, BAN::ConstByteSpan) override { return BAN::Error::from_errno(EINVAL); } BAN::ErrorOr<size_t> write_impl(off_t, BAN::ConstByteSpan) override { return BAN::Error::from_errno(EINVAL); }
BAN::ErrorOr<void> truncate_impl(size_t) override { return BAN::Error::from_errno(EINVAL); } BAN::ErrorOr<void> truncate_impl(size_t) override { return BAN::Error::from_errno(EINVAL); }
bool can_read_impl() const override { return true; } bool can_read_impl() const override { return true; }
bool can_write_impl() const override { return false; } bool can_write_impl() const override { return false; }
@@ -90,8 +90,8 @@ namespace Kernel::ACPI
AML::NameString m_method_name; AML::NameString m_method_name;
size_t m_result_index; size_t m_result_index;
uint64_t m_last_read_ms = 0; BAN::Atomic<uint64_t> m_last_read_ms = 0;
uint64_t m_last_value = 0; BAN::Atomic<uint64_t> m_last_value = 0;
}; };
BAN::ErrorOr<void> BatterySystem::initialize(AML::Namespace& acpi_namespace) BAN::ErrorOr<void> BatterySystem::initialize(AML::Namespace& acpi_namespace)

View File

@@ -153,8 +153,6 @@ namespace Kernel
REMOVE_IT(); REMOVE_IT();
{ {
LockGuard inode_locker(inode->m_mutex);
#define CHECK_EVENT_BIT(mask, func) \ #define CHECK_EVENT_BIT(mask, func) \
if ((events & mask) && !inode->func()) \ if ((events & mask) && !inode->func()) \
events &= ~mask; events &= ~mask;

View File

@@ -1,4 +1,5 @@
#include <kernel/FS/EventFD.h> #include <kernel/FS/EventFD.h>
#include <kernel/Lock/LockGuard.h>
#include <sys/epoll.h> #include <sys/epoll.h>
@@ -18,16 +19,20 @@ namespace Kernel
if (buffer.size() < sizeof(uint64_t)) if (buffer.size() < sizeof(uint64_t))
return BAN::Error::from_errno(EINVAL); return BAN::Error::from_errno(EINVAL);
LockGuard _(m_mutex);
while (m_value == 0) while (m_value == 0)
TRY(Thread::current().block_or_eintr_indefinite(m_thread_blocker, &m_mutex)); TRY(Thread::current().block_or_eintr_indefinite(m_thread_blocker, &m_mutex));
const uint64_t read_value = m_is_semaphore ? 1 : m_value; const uint64_t read_value = m_is_semaphore ? 1 : m_value.load();
m_value -= read_value; m_value -= read_value;
buffer.as<uint64_t>() = read_value; buffer.as<uint64_t>() = read_value;
epoll_notify(EPOLLOUT); epoll_notify(EPOLLOUT);
m_thread_blocker.unblock();
return sizeof(uint64_t); return sizeof(uint64_t);
} }
@@ -40,6 +45,8 @@ namespace Kernel
if (write_value == UINT64_MAX) if (write_value == UINT64_MAX)
return BAN::Error::from_errno(EINVAL); return BAN::Error::from_errno(EINVAL);
LockGuard _(m_mutex);
while (m_value + write_value < m_value) while (m_value + write_value < m_value)
TRY(Thread::current().block_or_eintr_indefinite(m_thread_blocker, &m_mutex)); TRY(Thread::current().block_or_eintr_indefinite(m_thread_blocker, &m_mutex));
@@ -48,6 +55,8 @@ namespace Kernel
if (m_value > 0) if (m_value > 0)
epoll_notify(EPOLLIN); epoll_notify(EPOLLIN);
m_thread_blocker.unblock();
return sizeof(uint64_t); return sizeof(uint64_t);
} }

View File

@@ -61,6 +61,8 @@ namespace Kernel
const uint32_t inode_blocks_per_fs_block = blksize() / 512; const uint32_t inode_blocks_per_fs_block = blksize() / 512;
const uint32_t indices_per_fs_block = blksize() / sizeof(uint32_t); const uint32_t indices_per_fs_block = blksize() / sizeof(uint32_t);
LockGuard _(m_lock);
if (block == 0 && !allocate) if (block == 0 && !allocate)
return BAN::Optional<uint32_t>(); return BAN::Optional<uint32_t>();
@@ -115,6 +117,8 @@ namespace Kernel
const uint32_t inode_blocks_per_fs_block = blksize() / 512; const uint32_t inode_blocks_per_fs_block = blksize() / 512;
const uint32_t indices_per_block = blksize() / sizeof(uint32_t); const uint32_t indices_per_block = blksize() / sizeof(uint32_t);
LockGuard _(m_lock);
if (data_block_index < 12) if (data_block_index < 12)
{ {
if (m_inode.block[data_block_index] != 0) if (m_inode.block[data_block_index] != 0)
@@ -152,6 +156,9 @@ namespace Kernel
BAN::ErrorOr<BAN::String> Ext2Inode::link_target_impl() BAN::ErrorOr<BAN::String> Ext2Inode::link_target_impl()
{ {
ASSERT(mode().iflnk()); ASSERT(mode().iflnk());
LockGuard _(m_lock);
if (m_inode.size < sizeof(m_inode.block)) if (m_inode.size < sizeof(m_inode.block))
{ {
BAN::String result; BAN::String result;
@@ -168,6 +175,9 @@ namespace Kernel
BAN::ErrorOr<void> Ext2Inode::set_link_target_impl(BAN::StringView target) BAN::ErrorOr<void> Ext2Inode::set_link_target_impl(BAN::StringView target)
{ {
ASSERT(mode().iflnk()); ASSERT(mode().iflnk());
LockGuard _(m_lock);
if (target.size() < sizeof(m_inode.block)) if (target.size() < sizeof(m_inode.block))
{ {
if (m_inode.size >= sizeof(m_inode.block)) if (m_inode.size >= sizeof(m_inode.block))
@@ -194,10 +204,12 @@ namespace Kernel
if (static_cast<BAN::make_unsigned_t<decltype(offset)>>(offset) >= UINT32_MAX || buffer.size() >= UINT32_MAX || buffer.size() >= (size_t)(UINT32_MAX - offset)) if (static_cast<BAN::make_unsigned_t<decltype(offset)>>(offset) >= UINT32_MAX || buffer.size() >= UINT32_MAX || buffer.size() >= (size_t)(UINT32_MAX - offset))
return BAN::Error::from_errno(EOVERFLOW); return BAN::Error::from_errno(EOVERFLOW);
LockGuard _0(m_lock);
if (static_cast<BAN::make_unsigned_t<decltype(offset)>>(offset) >= m_inode.size) if (static_cast<BAN::make_unsigned_t<decltype(offset)>>(offset) >= m_inode.size)
return 0; return 0;
ScopedSync _(*this); ScopedSync _1(*this);
uint32_t count = buffer.size(); uint32_t count = buffer.size();
if (offset + buffer.size() > m_inode.size) if (offset + buffer.size() > m_inode.size)
@@ -240,6 +252,8 @@ namespace Kernel
if (static_cast<BAN::make_unsigned_t<decltype(offset)>>(offset) >= UINT32_MAX || buffer.size() >= UINT32_MAX || buffer.size() >= (size_t)(UINT32_MAX - offset)) if (static_cast<BAN::make_unsigned_t<decltype(offset)>>(offset) >= UINT32_MAX || buffer.size() >= UINT32_MAX || buffer.size() >= (size_t)(UINT32_MAX - offset))
return BAN::Error::from_errno(EOVERFLOW); return BAN::Error::from_errno(EOVERFLOW);
LockGuard _0(m_lock);
if (m_inode.size < offset + buffer.size()) if (m_inode.size < offset + buffer.size())
TRY(truncate_impl(offset + buffer.size())); TRY(truncate_impl(offset + buffer.size()));
@@ -300,6 +314,8 @@ namespace Kernel
BAN::ErrorOr<void> Ext2Inode::truncate_impl(size_t new_size) BAN::ErrorOr<void> Ext2Inode::truncate_impl(size_t new_size)
{ {
LockGuard _(m_lock);
if (m_inode.size == new_size) if (m_inode.size == new_size)
return {}; return {};
@@ -320,6 +336,10 @@ namespace Kernel
BAN::ErrorOr<void> Ext2Inode::chmod_impl(mode_t mode) BAN::ErrorOr<void> Ext2Inode::chmod_impl(mode_t mode)
{ {
ASSERT((mode & Inode::Mode::TYPE_MASK) == 0); ASSERT((mode & Inode::Mode::TYPE_MASK) == 0);
// TODO: this could be atomic
LockGuard _(m_lock);
if (m_inode.mode == mode) if (m_inode.mode == mode)
return {}; return {};
@@ -337,6 +357,9 @@ namespace Kernel
BAN::ErrorOr<void> Ext2Inode::chown_impl(uid_t uid, gid_t gid) BAN::ErrorOr<void> Ext2Inode::chown_impl(uid_t uid, gid_t gid)
{ {
// TODO: this could be atomic
LockGuard _(m_lock);
if (m_inode.uid == uid && m_inode.gid == gid) if (m_inode.uid == uid && m_inode.gid == gid)
return {}; return {};
@@ -357,6 +380,9 @@ namespace Kernel
BAN::ErrorOr<void> Ext2Inode::utimens_impl(const timespec times[2]) BAN::ErrorOr<void> Ext2Inode::utimens_impl(const timespec times[2])
{ {
// TODO: this could be atomic
LockGuard _(m_lock);
const uint32_t old_times[2] { const uint32_t old_times[2] {
m_inode.atime, m_inode.atime,
m_inode.mtime, m_inode.mtime,
@@ -379,6 +405,7 @@ namespace Kernel
BAN::ErrorOr<void> Ext2Inode::fsync_impl() BAN::ErrorOr<void> Ext2Inode::fsync_impl()
{ {
LockGuard _(m_lock);
for (size_t i = 0; i < max_used_data_block_count(); i++) for (size_t i = 0; i < max_used_data_block_count(); i++)
if (const auto fs_block = TRY(fs_block_of_data_block_index(i, false)); fs_block.has_value()) if (const auto fs_block = TRY(fs_block_of_data_block_index(i, false)); fs_block.has_value())
TRY(m_fs.sync_block(fs_block.value())); TRY(m_fs.sync_block(fs_block.value()));
@@ -389,6 +416,8 @@ namespace Kernel
{ {
ASSERT(block); ASSERT(block);
LockGuard _(m_lock);
if (depth == 0) if (depth == 0)
{ {
TRY(m_fs.release_block(block)); TRY(m_fs.release_block(block));
@@ -413,6 +442,8 @@ namespace Kernel
BAN::ErrorOr<void> Ext2Inode::cleanup_data_blocks() BAN::ErrorOr<void> Ext2Inode::cleanup_data_blocks()
{ {
LockGuard _(m_lock);
if (mode().iflnk() && (size_t)size() < sizeof(m_inode.block)) if (mode().iflnk() && (size_t)size() < sizeof(m_inode.block))
goto done; goto done;
@@ -451,6 +482,8 @@ done:
ASSERT(mode().ifdir()); ASSERT(mode().ifdir());
ASSERT(offset >= 0); ASSERT(offset >= 0);
LockGuard _(m_lock);
if (static_cast<BAN::make_unsigned_t<decltype(offset)>>(offset) >= max_used_data_block_count()) if (static_cast<BAN::make_unsigned_t<decltype(offset)>>(offset) >= max_used_data_block_count())
return 0; return 0;
@@ -552,6 +585,8 @@ done:
{ {
ASSERT(this->mode().ifdir()); ASSERT(this->mode().ifdir());
LockGuard _(m_lock);
if (!find_inode_impl(name).is_error()) if (!find_inode_impl(name).is_error())
return BAN::Error::from_errno(EEXIST); return BAN::Error::from_errno(EEXIST);
@@ -586,6 +621,8 @@ done:
ASSERT(this->mode().ifdir()); ASSERT(this->mode().ifdir());
ASSERT(Mode(mode).ifdir()); ASSERT(Mode(mode).ifdir());
LockGuard _(m_lock);
if (!find_inode_impl(name).is_error()) if (!find_inode_impl(name).is_error())
return BAN::Error::from_errno(EEXIST); return BAN::Error::from_errno(EEXIST);
@@ -619,6 +656,8 @@ done:
ASSERT(!inode->mode().ifdir()); ASSERT(!inode->mode().ifdir());
ASSERT(&m_fs == inode->filesystem()); ASSERT(&m_fs == inode->filesystem());
LockGuard _(m_lock);
if (!find_inode_impl(name).is_error()) if (!find_inode_impl(name).is_error())
return BAN::Error::from_errno(EEXIST); return BAN::Error::from_errno(EEXIST);
@@ -636,16 +675,17 @@ done:
auto* ext2_parent = static_cast<Ext2Inode*>(old_parent.ptr()); auto* ext2_parent = static_cast<Ext2Inode*>(old_parent.ptr());
// FIXME: possible deadlock :) // FIXME: is this a possible deadlock?
LockGuard _(ext2_parent->m_mutex); LockGuard _0(ext2_parent->m_lock);
LockGuard _1(m_lock);
auto old_inode = TRY(ext2_parent->find_inode_impl(old_name)); auto old_inode = TRY(ext2_parent->find_inode_impl(old_name));
auto* ext2_inode = static_cast<Ext2Inode*>(old_inode.ptr()); auto* ext2_inode = static_cast<Ext2Inode*>(old_inode.ptr());
if (auto replace_or_error = find_inode_impl(new_name); replace_or_error.is_error()) if (auto find_result = find_inode_impl(new_name); find_result.is_error())
{ {
if (replace_or_error.error().get_error_code() != ENOENT) if (find_result.error().get_error_code() != ENOENT)
return replace_or_error.release_error(); return find_result.release_error();
} }
else else
{ {
@@ -667,6 +707,8 @@ done:
if (name.size() > 255) if (name.size() > 255)
return BAN::Error::from_errno(ENAMETOOLONG); return BAN::Error::from_errno(ENAMETOOLONG);
LockGuard _(m_lock);
if (m_inode.flags & Ext2::Enum::INDEX_FL) if (m_inode.flags & Ext2::Enum::INDEX_FL)
{ {
dwarnln("file creation to indexed directory not supported"); dwarnln("file creation to indexed directory not supported");
@@ -770,6 +812,8 @@ needs_new_block:
auto block_buffer = TRY(m_fs.get_block_buffer()); auto block_buffer = TRY(m_fs.get_block_buffer());
LockGuard _(m_lock);
// Confirm that this doesn't contain anything else than '.' or '..' // Confirm that this doesn't contain anything else than '.' or '..'
for (uint32_t i = 0; i < max_used_data_block_count(); i++) for (uint32_t i = 0; i < max_used_data_block_count(); i++)
{ {
@@ -800,14 +844,17 @@ needs_new_block:
BAN::ErrorOr<void> Ext2Inode::cleanup_default_links() BAN::ErrorOr<void> Ext2Inode::cleanup_default_links()
{ {
ASSERT(mode().ifdir()); ASSERT(mode().ifdir());
auto block_buffer = TRY(m_fs.get_block_buffer());
LockGuard _(m_lock);
if (m_inode.flags & Ext2::Enum::INDEX_FL) if (m_inode.flags & Ext2::Enum::INDEX_FL)
{ {
dwarnln("deletion of indexed directory is not supported"); dwarnln("deletion of indexed directory is not supported");
return BAN::Error::from_errno(ENOTSUP); return BAN::Error::from_errno(ENOTSUP);
} }
auto block_buffer = TRY(m_fs.get_block_buffer());
for (uint32_t i = 0; i < max_used_data_block_count(); i++) for (uint32_t i = 0; i < max_used_data_block_count(); i++)
{ {
const auto block_index = TRY(fs_block_of_data_block_index(i, false)); const auto block_index = TRY(fs_block_of_data_block_index(i, false));
@@ -857,14 +904,17 @@ needs_new_block:
BAN::ErrorOr<void> Ext2Inode::remove_inode_from_directory(BAN::StringView name, bool cleanup_directory) BAN::ErrorOr<void> Ext2Inode::remove_inode_from_directory(BAN::StringView name, bool cleanup_directory)
{ {
ASSERT(mode().ifdir()); ASSERT(mode().ifdir());
auto block_buffer = TRY(m_fs.get_block_buffer());
LockGuard _(m_lock);
if (m_inode.flags & Ext2::Enum::INDEX_FL) if (m_inode.flags & Ext2::Enum::INDEX_FL)
{ {
dwarnln("deletion from indexed directory is not supported"); dwarnln("deletion from indexed directory is not supported");
return BAN::Error::from_errno(ENOTSUP); return BAN::Error::from_errno(ENOTSUP);
} }
auto block_buffer = TRY(m_fs.get_block_buffer());
for (uint32_t i = 0; i < max_used_data_block_count(); i++) for (uint32_t i = 0; i < max_used_data_block_count(); i++)
{ {
const auto block_index = TRY(fs_block_of_data_block_index(i, false)); const auto block_index = TRY(fs_block_of_data_block_index(i, false));
@@ -925,6 +975,8 @@ needs_new_block:
auto block_buffer = TRY(m_fs.get_block_buffer()); auto block_buffer = TRY(m_fs.get_block_buffer());
TRY(m_fs.read_block(inode_location.block, block_buffer)); TRY(m_fs.read_block(inode_location.block, block_buffer));
LockGuard _(m_lock);
if (memcmp(block_buffer.data() + inode_location.offset, &m_inode, sizeof(Ext2::Inode))) if (memcmp(block_buffer.data() + inode_location.offset, &m_inode, sizeof(Ext2::Inode)))
{ {
memcpy(block_buffer.data() + inode_location.offset, &m_inode, sizeof(Ext2::Inode)); memcpy(block_buffer.data() + inode_location.offset, &m_inode, sizeof(Ext2::Inode));
@@ -940,6 +992,7 @@ needs_new_block:
auto block_buffer = TRY(m_fs.get_block_buffer()); auto block_buffer = TRY(m_fs.get_block_buffer());
LockGuard _(m_lock);
for (uint32_t i = 0; i < max_used_data_block_count(); i++) for (uint32_t i = 0; i < max_used_data_block_count(); i++)
{ {
const auto block_index = TRY(fs_block_of_data_block_index(i, false)); const auto block_index = TRY(fs_block_of_data_block_index(i, false));

View File

@@ -62,7 +62,6 @@ namespace Kernel
BAN::ErrorOr<BAN::RefPtr<Inode>> Inode::find_inode(BAN::StringView name) BAN::ErrorOr<BAN::RefPtr<Inode>> Inode::find_inode(BAN::StringView name)
{ {
LockGuard _(m_mutex);
if (!mode().ifdir()) if (!mode().ifdir())
return BAN::Error::from_errno(ENOTDIR); return BAN::Error::from_errno(ENOTDIR);
return find_inode_impl(name); return find_inode_impl(name);
@@ -70,7 +69,6 @@ namespace Kernel
BAN::ErrorOr<size_t> Inode::list_next_inodes(off_t offset, struct dirent* list, size_t list_len) BAN::ErrorOr<size_t> Inode::list_next_inodes(off_t offset, struct dirent* list, size_t list_len)
{ {
LockGuard _(m_mutex);
if (!mode().ifdir()) if (!mode().ifdir())
return BAN::Error::from_errno(ENOTDIR); return BAN::Error::from_errno(ENOTDIR);
return list_next_inodes_impl(offset, list, list_len); return list_next_inodes_impl(offset, list, list_len);
@@ -78,7 +76,6 @@ namespace Kernel
BAN::ErrorOr<void> Inode::create_file(BAN::StringView name, mode_t mode, uid_t uid, gid_t gid) BAN::ErrorOr<void> Inode::create_file(BAN::StringView name, mode_t mode, uid_t uid, gid_t gid)
{ {
LockGuard _(m_mutex);
if (!this->mode().ifdir()) if (!this->mode().ifdir())
return BAN::Error::from_errno(ENOTDIR); return BAN::Error::from_errno(ENOTDIR);
if (Mode(mode).ifdir()) if (Mode(mode).ifdir())
@@ -90,7 +87,6 @@ namespace Kernel
BAN::ErrorOr<void> Inode::create_directory(BAN::StringView name, mode_t mode, uid_t uid, gid_t gid) BAN::ErrorOr<void> Inode::create_directory(BAN::StringView name, mode_t mode, uid_t uid, gid_t gid)
{ {
LockGuard _(m_mutex);
if (!this->mode().ifdir()) if (!this->mode().ifdir())
return BAN::Error::from_errno(ENOTDIR); return BAN::Error::from_errno(ENOTDIR);
if (!Mode(mode).ifdir()) if (!Mode(mode).ifdir())
@@ -102,7 +98,6 @@ namespace Kernel
BAN::ErrorOr<void> Inode::link_inode(BAN::StringView name, BAN::RefPtr<Inode> inode) BAN::ErrorOr<void> Inode::link_inode(BAN::StringView name, BAN::RefPtr<Inode> inode)
{ {
LockGuard _(m_mutex);
if (!this->mode().ifdir()) if (!this->mode().ifdir())
return BAN::Error::from_errno(ENOTDIR); return BAN::Error::from_errno(ENOTDIR);
if (inode->mode().ifdir()) if (inode->mode().ifdir())
@@ -116,7 +111,6 @@ namespace Kernel
BAN::ErrorOr<void> Inode::rename_inode(BAN::RefPtr<Inode> old_parent, BAN::StringView old_name, BAN::StringView new_name) BAN::ErrorOr<void> Inode::rename_inode(BAN::RefPtr<Inode> old_parent, BAN::StringView old_name, BAN::StringView new_name)
{ {
LockGuard _(m_mutex);
if (!this->mode().ifdir()) if (!this->mode().ifdir())
return BAN::Error::from_errno(ENOTDIR); return BAN::Error::from_errno(ENOTDIR);
if (!old_parent->mode().ifdir()) if (!old_parent->mode().ifdir())
@@ -130,7 +124,6 @@ namespace Kernel
BAN::ErrorOr<void> Inode::unlink(BAN::StringView name) BAN::ErrorOr<void> Inode::unlink(BAN::StringView name)
{ {
LockGuard _(m_mutex);
if (!mode().ifdir()) if (!mode().ifdir())
return BAN::Error::from_errno(ENOTDIR); return BAN::Error::from_errno(ENOTDIR);
if (name == "."_sv || name == ".."_sv) if (name == "."_sv || name == ".."_sv)
@@ -142,7 +135,6 @@ namespace Kernel
BAN::ErrorOr<BAN::String> Inode::link_target() BAN::ErrorOr<BAN::String> Inode::link_target()
{ {
LockGuard _(m_mutex);
if (!mode().iflnk()) if (!mode().iflnk())
return BAN::Error::from_errno(EINVAL); return BAN::Error::from_errno(EINVAL);
return link_target_impl(); return link_target_impl();
@@ -150,7 +142,6 @@ namespace Kernel
BAN::ErrorOr<void> Inode::set_link_target(BAN::StringView target) BAN::ErrorOr<void> Inode::set_link_target(BAN::StringView target)
{ {
LockGuard _(m_mutex);
if (!mode().iflnk()) if (!mode().iflnk())
return BAN::Error::from_errno(EINVAL); return BAN::Error::from_errno(EINVAL);
if (auto* fs = filesystem(); fs && (fs->flag() & ST_RDONLY)) if (auto* fs = filesystem(); fs && (fs->flag() & ST_RDONLY))
@@ -160,7 +151,6 @@ namespace Kernel
BAN::ErrorOr<long> Inode::accept(sockaddr* address, socklen_t* address_len, int flags) BAN::ErrorOr<long> Inode::accept(sockaddr* address, socklen_t* address_len, int flags)
{ {
LockGuard _(m_mutex);
if (!mode().ifsock()) if (!mode().ifsock())
return BAN::Error::from_errno(ENOTSOCK); return BAN::Error::from_errno(ENOTSOCK);
return accept_impl(address, address_len, flags); return accept_impl(address, address_len, flags);
@@ -168,7 +158,6 @@ namespace Kernel
BAN::ErrorOr<void> Inode::bind(const sockaddr* address, socklen_t address_len) BAN::ErrorOr<void> Inode::bind(const sockaddr* address, socklen_t address_len)
{ {
LockGuard _(m_mutex);
if (!mode().ifsock()) if (!mode().ifsock())
return BAN::Error::from_errno(ENOTSOCK); return BAN::Error::from_errno(ENOTSOCK);
return bind_impl(address, address_len); return bind_impl(address, address_len);
@@ -176,7 +165,6 @@ namespace Kernel
BAN::ErrorOr<void> Inode::connect(const sockaddr* address, socklen_t address_len) BAN::ErrorOr<void> Inode::connect(const sockaddr* address, socklen_t address_len)
{ {
LockGuard _(m_mutex);
if (!mode().ifsock()) if (!mode().ifsock())
return BAN::Error::from_errno(ENOTSOCK); return BAN::Error::from_errno(ENOTSOCK);
return connect_impl(address, address_len); return connect_impl(address, address_len);
@@ -184,7 +172,6 @@ namespace Kernel
BAN::ErrorOr<void> Inode::listen(int backlog) BAN::ErrorOr<void> Inode::listen(int backlog)
{ {
LockGuard _(m_mutex);
if (!mode().ifsock()) if (!mode().ifsock())
return BAN::Error::from_errno(ENOTSOCK); return BAN::Error::from_errno(ENOTSOCK);
return listen_impl(backlog); return listen_impl(backlog);
@@ -192,7 +179,6 @@ namespace Kernel
BAN::ErrorOr<size_t> Inode::recvmsg(msghdr& message, int flags) BAN::ErrorOr<size_t> Inode::recvmsg(msghdr& message, int flags)
{ {
LockGuard _(m_mutex);
if (!mode().ifsock()) if (!mode().ifsock())
return BAN::Error::from_errno(ENOTSOCK); return BAN::Error::from_errno(ENOTSOCK);
return recvmsg_impl(message, flags); return recvmsg_impl(message, flags);
@@ -200,7 +186,6 @@ namespace Kernel
BAN::ErrorOr<size_t> Inode::sendmsg(const msghdr& message, int flags) BAN::ErrorOr<size_t> Inode::sendmsg(const msghdr& message, int flags)
{ {
LockGuard _(m_mutex);
if (!mode().ifsock()) if (!mode().ifsock())
return BAN::Error::from_errno(ENOTSOCK); return BAN::Error::from_errno(ENOTSOCK);
return sendmsg_impl(message, flags); return sendmsg_impl(message, flags);
@@ -208,7 +193,6 @@ namespace Kernel
BAN::ErrorOr<void> Inode::getsockname(sockaddr* address, socklen_t* address_len) BAN::ErrorOr<void> Inode::getsockname(sockaddr* address, socklen_t* address_len)
{ {
LockGuard _(m_mutex);
if (!mode().ifsock()) if (!mode().ifsock())
return BAN::Error::from_errno(ENOTSOCK); return BAN::Error::from_errno(ENOTSOCK);
return getsockname_impl(address, address_len); return getsockname_impl(address, address_len);
@@ -216,7 +200,6 @@ namespace Kernel
BAN::ErrorOr<void> Inode::getpeername(sockaddr* address, socklen_t* address_len) BAN::ErrorOr<void> Inode::getpeername(sockaddr* address, socklen_t* address_len)
{ {
LockGuard _(m_mutex);
if (!mode().ifsock()) if (!mode().ifsock())
return BAN::Error::from_errno(ENOTSOCK); return BAN::Error::from_errno(ENOTSOCK);
return getpeername_impl(address, address_len); return getpeername_impl(address, address_len);
@@ -224,7 +207,6 @@ namespace Kernel
BAN::ErrorOr<void> Inode::getsockopt(int level, int option, void* value, socklen_t* value_len) BAN::ErrorOr<void> Inode::getsockopt(int level, int option, void* value, socklen_t* value_len)
{ {
LockGuard _(m_mutex);
if (!mode().ifsock()) if (!mode().ifsock())
return BAN::Error::from_errno(ENOTSOCK); return BAN::Error::from_errno(ENOTSOCK);
return getsockopt_impl(level, option, value, value_len); return getsockopt_impl(level, option, value, value_len);
@@ -232,7 +214,6 @@ namespace Kernel
BAN::ErrorOr<void> Inode::setsockopt(int level, int option, const void* value, socklen_t value_len) BAN::ErrorOr<void> Inode::setsockopt(int level, int option, const void* value, socklen_t value_len)
{ {
LockGuard _(m_mutex);
if (!mode().ifsock()) if (!mode().ifsock())
return BAN::Error::from_errno(ENOTSOCK); return BAN::Error::from_errno(ENOTSOCK);
return setsockopt_impl(level, option, value, value_len); return setsockopt_impl(level, option, value, value_len);
@@ -240,7 +221,6 @@ namespace Kernel
BAN::ErrorOr<size_t> Inode::read(off_t offset, BAN::ByteSpan buffer) BAN::ErrorOr<size_t> Inode::read(off_t offset, BAN::ByteSpan buffer)
{ {
LockGuard _(m_mutex);
if (mode().ifdir()) if (mode().ifdir())
return BAN::Error::from_errno(EISDIR); return BAN::Error::from_errno(EISDIR);
return read_impl(offset, buffer); return read_impl(offset, buffer);
@@ -248,7 +228,6 @@ namespace Kernel
BAN::ErrorOr<size_t> Inode::write(off_t offset, BAN::ConstByteSpan buffer) BAN::ErrorOr<size_t> Inode::write(off_t offset, BAN::ConstByteSpan buffer)
{ {
LockGuard _(m_mutex);
if (mode().ifdir()) if (mode().ifdir())
return BAN::Error::from_errno(EISDIR); return BAN::Error::from_errno(EISDIR);
if (auto* fs = filesystem(); fs && (fs->flag() & ST_RDONLY)) if (auto* fs = filesystem(); fs && (fs->flag() & ST_RDONLY))
@@ -258,7 +237,6 @@ namespace Kernel
BAN::ErrorOr<void> Inode::truncate(size_t size) BAN::ErrorOr<void> Inode::truncate(size_t size)
{ {
LockGuard _(m_mutex);
if (mode().ifdir()) if (mode().ifdir())
return BAN::Error::from_errno(EISDIR); return BAN::Error::from_errno(EISDIR);
if (auto* fs = filesystem(); fs && (fs->flag() & ST_RDONLY)) if (auto* fs = filesystem(); fs && (fs->flag() & ST_RDONLY))
@@ -269,7 +247,6 @@ namespace Kernel
BAN::ErrorOr<void> Inode::chmod(mode_t mode) BAN::ErrorOr<void> Inode::chmod(mode_t mode)
{ {
ASSERT((mode & Inode::Mode::TYPE_MASK) == 0); ASSERT((mode & Inode::Mode::TYPE_MASK) == 0);
LockGuard _(m_mutex);
if (auto* fs = filesystem(); fs && (fs->flag() & ST_RDONLY)) if (auto* fs = filesystem(); fs && (fs->flag() & ST_RDONLY))
return BAN::Error::from_errno(EROFS); return BAN::Error::from_errno(EROFS);
return chmod_impl(mode); return chmod_impl(mode);
@@ -277,7 +254,6 @@ namespace Kernel
BAN::ErrorOr<void> Inode::chown(uid_t uid, gid_t gid) BAN::ErrorOr<void> Inode::chown(uid_t uid, gid_t gid)
{ {
LockGuard _(m_mutex);
if (auto* fs = filesystem(); fs && (fs->flag() & ST_RDONLY)) if (auto* fs = filesystem(); fs && (fs->flag() & ST_RDONLY))
return BAN::Error::from_errno(EROFS); return BAN::Error::from_errno(EROFS);
return chown_impl(uid, gid); return chown_impl(uid, gid);
@@ -285,7 +261,6 @@ namespace Kernel
BAN::ErrorOr<void> Inode::utimens(const timespec times[2]) BAN::ErrorOr<void> Inode::utimens(const timespec times[2])
{ {
LockGuard _(m_mutex);
if (auto* fs = filesystem(); fs && (fs->flag() & ST_RDONLY)) if (auto* fs = filesystem(); fs && (fs->flag() & ST_RDONLY))
return BAN::Error::from_errno(EROFS); return BAN::Error::from_errno(EROFS);
return utimens_impl(times); return utimens_impl(times);
@@ -293,40 +268,32 @@ namespace Kernel
BAN::ErrorOr<void> Inode::fsync() BAN::ErrorOr<void> Inode::fsync()
{ {
LockGuard _(m_mutex); // TODO: should we sync shared data?
if (auto shared = m_shared_region.lock())
for (size_t i = 0; i < shared->pages.size(); i++)
shared->sync(i);
return fsync_impl(); return fsync_impl();
} }
bool Inode::can_read() const bool Inode::can_read() const
{ {
LockGuard _(m_mutex);
return can_read_impl(); return can_read_impl();
} }
bool Inode::can_write() const bool Inode::can_write() const
{ {
LockGuard _(m_mutex);
return can_write_impl(); return can_write_impl();
} }
bool Inode::has_error() const bool Inode::has_error() const
{ {
LockGuard _(m_mutex);
return has_error_impl(); return has_error_impl();
} }
bool Inode::has_hungup() const bool Inode::has_hungup() const
{ {
LockGuard _(m_mutex);
return has_hungup_impl(); return has_hungup_impl();
} }
BAN::ErrorOr<long> Inode::ioctl(int request, void* arg) BAN::ErrorOr<long> Inode::ioctl(int request, void* arg)
{ {
LockGuard _(m_mutex);
return ioctl_impl(request, arg); return ioctl_impl(request, arg);
} }

View File

@@ -73,6 +73,8 @@ namespace Kernel
BAN::ErrorOr<size_t> Pipe::read_impl(off_t, BAN::ByteSpan buffer) BAN::ErrorOr<size_t> Pipe::read_impl(off_t, BAN::ByteSpan buffer)
{ {
LockGuard _(m_mutex);
while (m_buffer->empty()) while (m_buffer->empty())
{ {
if (m_writing_count == 0) if (m_writing_count == 0)
@@ -95,6 +97,8 @@ namespace Kernel
BAN::ErrorOr<size_t> Pipe::write_impl(off_t, BAN::ConstByteSpan buffer) BAN::ErrorOr<size_t> Pipe::write_impl(off_t, BAN::ConstByteSpan buffer)
{ {
LockGuard _(m_mutex);
while (m_buffer->full()) while (m_buffer->full())
{ {
if (m_reading_count == 0) if (m_reading_count == 0)

View File

@@ -94,6 +94,7 @@ namespace Kernel
BAN::ErrorOr<void> TmpInode::chmod_impl(mode_t new_mode) BAN::ErrorOr<void> TmpInode::chmod_impl(mode_t new_mode)
{ {
// FIXME: make this atomic
ASSERT(!(new_mode & Inode::Mode::TYPE_MASK)); ASSERT(!(new_mode & Inode::Mode::TYPE_MASK));
m_inode_info.mode &= Inode::Mode::TYPE_MASK; m_inode_info.mode &= Inode::Mode::TYPE_MASK;
m_inode_info.mode |= new_mode; m_inode_info.mode |= new_mode;
@@ -102,6 +103,7 @@ namespace Kernel
BAN::ErrorOr<void> TmpInode::chown_impl(uid_t new_uid, gid_t new_gid) BAN::ErrorOr<void> TmpInode::chown_impl(uid_t new_uid, gid_t new_gid)
{ {
// FIXME: make this atomic
m_inode_info.uid = new_uid; m_inode_info.uid = new_uid;
m_inode_info.gid = new_gid; m_inode_info.gid = new_gid;
return {}; return {};
@@ -109,6 +111,7 @@ namespace Kernel
BAN::ErrorOr<void> TmpInode::utimens_impl(const timespec times[2]) BAN::ErrorOr<void> TmpInode::utimens_impl(const timespec times[2])
{ {
// FIXME: make this atomic
if (times[0].tv_nsec != UTIME_OMIT) if (times[0].tv_nsec != UTIME_OMIT)
m_inode_info.atime = times[0]; m_inode_info.atime = times[0];
if (times[1].tv_nsec != UTIME_OMIT) if (times[1].tv_nsec != UTIME_OMIT)
@@ -123,23 +126,24 @@ namespace Kernel
void TmpInode::free_all_blocks() void TmpInode::free_all_blocks()
{ {
LockGuard _(m_lock);
if (mode().iflnk() && m_inode_info.size <= sizeof(TmpInodeInfo::block)) if (mode().iflnk() && m_inode_info.size <= sizeof(TmpInodeInfo::block))
goto free_all_blocks_done; goto free_all_blocks_done;
for (size_t i = 0; i < TmpInodeInfo::direct_block_count; i++) for (size_t i = 0; i < TmpInodeInfo::direct_block_count; i++)
if (m_inode_info.block[i]) if (m_inode_info.block[i])
m_fs.free_block(m_inode_info.block[i]); m_fs.free_block(m_inode_info.block[i]);
if (size_t block = m_inode_info.block[TmpInodeInfo::direct_block_count + 0]) if (size_t block = m_inode_info.block[TmpInodeInfo::direct_block_count + 0])
free_indirect_blocks(block, 1); free_indirect_blocks_no_lock(block, 1);
if (size_t block = m_inode_info.block[TmpInodeInfo::direct_block_count + 1]) if (size_t block = m_inode_info.block[TmpInodeInfo::direct_block_count + 1])
free_indirect_blocks(block, 2); free_indirect_blocks_no_lock(block, 2);
if (size_t block = m_inode_info.block[TmpInodeInfo::direct_block_count + 2]) if (size_t block = m_inode_info.block[TmpInodeInfo::direct_block_count + 2])
free_indirect_blocks(block, 3); free_indirect_blocks_no_lock(block, 3);
free_all_blocks_done: free_all_blocks_done:
for (auto& block : m_inode_info.block) for (auto& block : m_inode_info.block)
block = 0; block = 0;
} }
void TmpInode::free_indirect_blocks(size_t block, uint32_t depth) void TmpInode::free_indirect_blocks_no_lock(size_t block, uint32_t depth)
{ {
ASSERT(block != 0); ASSERT(block != 0);
@@ -160,7 +164,7 @@ namespace Kernel
if (next_block == 0) if (next_block == 0)
continue; continue;
free_indirect_blocks(next_block, depth - 1); free_indirect_blocks_no_lock(next_block, depth - 1);
} }
m_fs.free_block(block); m_fs.free_block(block);
@@ -168,6 +172,8 @@ namespace Kernel
BAN::Optional<size_t> TmpInode::block_index(size_t data_block_index) BAN::Optional<size_t> TmpInode::block_index(size_t data_block_index)
{ {
LockGuard _(m_lock);
if (data_block_index < TmpInodeInfo::direct_block_count) if (data_block_index < TmpInodeInfo::direct_block_count)
{ {
if (m_inode_info.block[data_block_index] == 0) if (m_inode_info.block[data_block_index] == 0)
@@ -179,20 +185,20 @@ namespace Kernel
const size_t indices_per_block = blksize() / sizeof(size_t); const size_t indices_per_block = blksize() / sizeof(size_t);
if (data_block_index < indices_per_block) if (data_block_index < indices_per_block)
return block_index_from_indirect(m_inode_info.block[TmpInodeInfo::direct_block_count + 0], data_block_index, 1); return block_index_from_indirect_no_lock(m_inode_info.block[TmpInodeInfo::direct_block_count + 0], data_block_index, 1);
data_block_index -= indices_per_block; data_block_index -= indices_per_block;
if (data_block_index < indices_per_block * indices_per_block) if (data_block_index < indices_per_block * indices_per_block)
return block_index_from_indirect(m_inode_info.block[TmpInodeInfo::direct_block_count + 1], data_block_index, 2); return block_index_from_indirect_no_lock(m_inode_info.block[TmpInodeInfo::direct_block_count + 1], data_block_index, 2);
data_block_index -= indices_per_block * indices_per_block; data_block_index -= indices_per_block * indices_per_block;
if (data_block_index < indices_per_block * indices_per_block * indices_per_block) if (data_block_index < indices_per_block * indices_per_block * indices_per_block)
return block_index_from_indirect(m_inode_info.block[TmpInodeInfo::direct_block_count + 2], data_block_index, 3); return block_index_from_indirect_no_lock(m_inode_info.block[TmpInodeInfo::direct_block_count + 2], data_block_index, 3);
ASSERT_NOT_REACHED(); ASSERT_NOT_REACHED();
} }
BAN::Optional<size_t> TmpInode::block_index_from_indirect(size_t block, size_t index, uint32_t depth) BAN::Optional<size_t> TmpInode::block_index_from_indirect_no_lock(size_t block, size_t index, uint32_t depth)
{ {
if (block == 0) if (block == 0)
return {}; return {};
@@ -215,11 +221,13 @@ namespace Kernel
if (depth == 1) if (depth == 1)
return next_block; return next_block;
return block_index_from_indirect(next_block, index, depth - 1); return block_index_from_indirect_no_lock(next_block, index, depth - 1);
} }
BAN::ErrorOr<size_t> TmpInode::block_index_with_allocation(size_t data_block_index) BAN::ErrorOr<size_t> TmpInode::block_index_with_allocation(size_t data_block_index)
{ {
LockGuard _(m_lock);
if (data_block_index < TmpInodeInfo::direct_block_count) if (data_block_index < TmpInodeInfo::direct_block_count)
{ {
if (m_inode_info.block[data_block_index] == 0) if (m_inode_info.block[data_block_index] == 0)
@@ -234,20 +242,20 @@ namespace Kernel
const size_t indices_per_block = blksize() / sizeof(size_t); const size_t indices_per_block = blksize() / sizeof(size_t);
if (data_block_index < indices_per_block) if (data_block_index < indices_per_block)
return block_index_from_indirect_with_allocation(m_inode_info.block[TmpInodeInfo::direct_block_count + 0], data_block_index, 1); return block_index_from_indirect_with_allocation_no_lock(m_inode_info.block[TmpInodeInfo::direct_block_count + 0], data_block_index, 1);
data_block_index -= indices_per_block; data_block_index -= indices_per_block;
if (data_block_index < indices_per_block * indices_per_block) if (data_block_index < indices_per_block * indices_per_block)
return block_index_from_indirect_with_allocation(m_inode_info.block[TmpInodeInfo::direct_block_count + 1], data_block_index, 2); return block_index_from_indirect_with_allocation_no_lock(m_inode_info.block[TmpInodeInfo::direct_block_count + 1], data_block_index, 2);
data_block_index -= indices_per_block * indices_per_block; data_block_index -= indices_per_block * indices_per_block;
if (data_block_index < indices_per_block * indices_per_block * indices_per_block) if (data_block_index < indices_per_block * indices_per_block * indices_per_block)
return block_index_from_indirect_with_allocation(m_inode_info.block[TmpInodeInfo::direct_block_count + 2], data_block_index, 3); return block_index_from_indirect_with_allocation_no_lock(m_inode_info.block[TmpInodeInfo::direct_block_count + 2], data_block_index, 3);
ASSERT_NOT_REACHED(); ASSERT_NOT_REACHED();
} }
BAN::ErrorOr<size_t> TmpInode::block_index_from_indirect_with_allocation(size_t& block, size_t index, uint32_t depth) BAN::ErrorOr<size_t> TmpInode::block_index_from_indirect_with_allocation_no_lock(size_t& block, size_t index, uint32_t depth)
{ {
if (block == 0) if (block == 0)
{ {
@@ -280,7 +288,7 @@ namespace Kernel
if (depth == 1) if (depth == 1)
return next_block; return next_block;
return block_index_from_indirect_with_allocation(next_block, index, depth - 1); return block_index_from_indirect_with_allocation_no_lock(next_block, index, depth - 1);
} }
/* FILE INODE */ /* FILE INODE */
@@ -309,6 +317,8 @@ namespace Kernel
BAN::ErrorOr<size_t> TmpFileInode::read_impl(off_t offset, BAN::ByteSpan out_buffer) BAN::ErrorOr<size_t> TmpFileInode::read_impl(off_t offset, BAN::ByteSpan out_buffer)
{ {
LockGuard _(m_lock);
if (offset >= size() || out_buffer.size() == 0) if (offset >= size() || out_buffer.size() == 0)
return 0; return 0;
@@ -339,7 +349,12 @@ namespace Kernel
BAN::ErrorOr<size_t> TmpFileInode::write_impl(off_t offset, BAN::ConstByteSpan in_buffer) BAN::ErrorOr<size_t> TmpFileInode::write_impl(off_t offset, BAN::ConstByteSpan in_buffer)
{ {
// FIXME: handle overflow if (offset < 0)
return BAN::Error::from_errno(EINVAL);
if (BAN::Math::will_addition_overflow<size_t>(offset, in_buffer.size()))
return BAN::Error::from_errno(EOVERFLOW);
LockGuard _(m_lock);
if (offset + in_buffer.size() > (size_t)size()) if (offset + in_buffer.size() > (size_t)size())
TRY(truncate_impl(offset + in_buffer.size())); TRY(truncate_impl(offset + in_buffer.size()));
@@ -370,6 +385,7 @@ namespace Kernel
{ {
// FIXME: if size is decreased, we should probably free // FIXME: if size is decreased, we should probably free
// unused blocks // unused blocks
// FIXME: make this atomic
m_inode_info.size = new_size; m_inode_info.size = new_size;
return {}; return {};
@@ -427,6 +443,8 @@ namespace Kernel
BAN::ErrorOr<void> TmpSymlinkInode::set_link_target_impl(BAN::StringView new_target) BAN::ErrorOr<void> TmpSymlinkInode::set_link_target_impl(BAN::StringView new_target)
{ {
LockGuard _(m_lock);
free_all_blocks(); free_all_blocks();
m_inode_info.size = 0; m_inode_info.size = 0;
@@ -455,6 +473,8 @@ namespace Kernel
BAN::ErrorOr<BAN::String> TmpSymlinkInode::link_target_impl() BAN::ErrorOr<BAN::String> TmpSymlinkInode::link_target_impl()
{ {
LockGuard _(m_lock);
BAN::String result; BAN::String result;
TRY(result.resize(size())); TRY(result.resize(size()));
@@ -522,7 +542,7 @@ namespace Kernel
{ {
} }
BAN::ErrorOr<void> TmpDirectoryInode::prepare_unlink() BAN::ErrorOr<void> TmpDirectoryInode::prepare_unlink_no_lock()
{ {
ino_t dot_ino = 0; ino_t dot_ino = 0;
ino_t dotdot_ino = 0; ino_t dotdot_ino = 0;
@@ -564,15 +584,15 @@ namespace Kernel
BAN::ErrorOr<BAN::RefPtr<Inode>> TmpDirectoryInode::find_inode_impl(BAN::StringView name) BAN::ErrorOr<BAN::RefPtr<Inode>> TmpDirectoryInode::find_inode_impl(BAN::StringView name)
{ {
ino_t result = 0; LockGuard _(m_lock);
ino_t result = 0;
for_each_valid_entry([&](TmpDirectoryEntry& entry) { for_each_valid_entry([&](TmpDirectoryEntry& entry) {
if (entry.name_sv() != name) if (entry.name_sv() != name)
return BAN::Iteration::Continue; return BAN::Iteration::Continue;
result = entry.ino; result = entry.ino;
return BAN::Iteration::Break; return BAN::Iteration::Break;
}); });
if (result == 0) if (result == 0)
return BAN::Error::from_errno(ENOENT); return BAN::Error::from_errno(ENOENT);
@@ -588,6 +608,8 @@ namespace Kernel
return BAN::Error::from_errno(ENOBUFS); return BAN::Error::from_errno(ENOBUFS);
} }
LockGuard _(m_lock);
auto block_index = this->block_index(data_block_index); auto block_index = this->block_index(data_block_index);
// if we reach a non-allocated block, it marks the end // if we reach a non-allocated block, it marks the end
@@ -664,6 +686,8 @@ namespace Kernel
ASSERT(!inode->mode().ifdir()); ASSERT(!inode->mode().ifdir());
ASSERT(&m_fs == inode->filesystem()); ASSERT(&m_fs == inode->filesystem());
LockGuard _(m_lock);
if (!find_inode_impl(name).is_error()) if (!find_inode_impl(name).is_error())
return BAN::Error::from_errno(EEXIST); return BAN::Error::from_errno(EEXIST);
@@ -680,16 +704,17 @@ namespace Kernel
auto* tmp_parent = static_cast<TmpDirectoryInode*>(old_parent.ptr()); auto* tmp_parent = static_cast<TmpDirectoryInode*>(old_parent.ptr());
// FIXME: possible deadlock :) // FIXME: is this a possible deadlock?
LockGuard _(tmp_parent->m_mutex); LockGuard _0(tmp_parent->m_lock);
LockGuard _1(m_lock);
auto old_inode = TRY(tmp_parent->find_inode_impl(old_name)); auto old_inode = TRY(tmp_parent->find_inode_impl(old_name));
auto* tmp_inode = static_cast<TmpInode*>(old_inode.ptr()); auto* tmp_inode = static_cast<TmpInode*>(old_inode.ptr());
if (auto replace_or_error = find_inode_impl(new_name); replace_or_error.is_error()) if (auto find_result = find_inode_impl(new_name); find_result.is_error())
{ {
if (replace_or_error.error().get_error_code() != ENOENT) if (find_result.error().get_error_code() != ENOENT)
return replace_or_error.release_error(); return find_result.release_error();
} }
else else
{ {
@@ -711,15 +736,15 @@ namespace Kernel
BAN::ErrorOr<void> TmpDirectoryInode::unlink_inode(BAN::StringView name, bool cleanup) BAN::ErrorOr<void> TmpDirectoryInode::unlink_inode(BAN::StringView name, bool cleanup)
{ {
ino_t entry_ino = 0; LockGuard _(m_lock);
ino_t entry_ino = 0;
for_each_valid_entry([&](TmpDirectoryEntry& entry) { for_each_valid_entry([&](TmpDirectoryEntry& entry) {
if (entry.name_sv() != name) if (entry.name_sv() != name)
return BAN::Iteration::Continue; return BAN::Iteration::Continue;
entry_ino = entry.ino; entry_ino = entry.ino;
return BAN::Iteration::Break; return BAN::Iteration::Break;
}); });
if (entry_ino == 0) if (entry_ino == 0)
return BAN::Error::from_errno(ENOENT); return BAN::Error::from_errno(ENOENT);
@@ -728,7 +753,7 @@ namespace Kernel
ASSERT(inode->nlink() > 0); ASSERT(inode->nlink() > 0);
if (cleanup) if (cleanup)
TRY(inode->prepare_unlink()); TRY(inode->prepare_unlink_no_lock());
inode->m_inode_info.nlink--; inode->m_inode_info.nlink--;
if (inode->nlink() == 0) if (inode->nlink() == 0)
@@ -749,6 +774,8 @@ namespace Kernel
{ {
static constexpr size_t directory_entry_alignment = sizeof(TmpDirectoryEntry); static constexpr size_t directory_entry_alignment = sizeof(TmpDirectoryEntry);
LockGuard _(m_lock);
auto find_result = find_inode_impl(name); auto find_result = find_inode_impl(name);
if (!find_result.is_error()) if (!find_result.is_error())
return BAN::Error::from_errno(EEXIST); return BAN::Error::from_errno(EEXIST);

View File

@@ -1,5 +1,6 @@
#include <BAN/ScopeGuard.h> #include <BAN/ScopeGuard.h>
#include <kernel/FS/USTARModule.h> #include <kernel/FS/USTARModule.h>
#include <kernel/Memory/PageTable.h>
#include <kernel/Timer/Timer.h> #include <kernel/Timer/Timer.h>
#include <LibDEFLATE/Decompressor.h> #include <LibDEFLATE/Decompressor.h>

View File

@@ -13,12 +13,15 @@
namespace Kernel namespace Kernel
{ {
static SpinLock s_keyboard_lock;
static BAN::Vector<BAN::WeakPtr<InputDevice>> s_keyboards; static BAN::Vector<BAN::WeakPtr<InputDevice>> s_keyboards;
static BAN::RefPtr<KeyboardDevice> s_keyboard_device; static BAN::RefPtr<KeyboardDevice> s_keyboard_device;
static SpinLock s_mouse_lock;
static BAN::Vector<BAN::WeakPtr<InputDevice>> s_mice; static BAN::Vector<BAN::WeakPtr<InputDevice>> s_mice;
static BAN::RefPtr<MouseDevice> s_mouse_device; static BAN::RefPtr<MouseDevice> s_mouse_device;
static SpinLock s_joystick_lock;
static BAN::Vector<BAN::WeakPtr<InputDevice>> s_joysticks; static BAN::Vector<BAN::WeakPtr<InputDevice>> s_joysticks;
static const char* get_name_format(InputDevice::Type type) static const char* get_name_format(InputDevice::Type type)
@@ -40,20 +43,29 @@ namespace Kernel
switch (type) switch (type)
{ {
case InputDevice::Type::Keyboard: case InputDevice::Type::Keyboard:
{
SpinLockGuard _(s_keyboard_lock);
for (size_t i = 0; i < s_keyboards.size(); i++) for (size_t i = 0; i < s_keyboards.size(); i++)
if (!s_keyboards[i].valid()) if (!s_keyboards[i].valid())
return makedev(DeviceNumber::Keyboard, i + 1); return makedev(DeviceNumber::Keyboard, i + 1);
return makedev(DeviceNumber::Keyboard, s_keyboards.size() + 1); return makedev(DeviceNumber::Keyboard, s_keyboards.size() + 1);
}
case InputDevice::Type::Mouse: case InputDevice::Type::Mouse:
{
SpinLockGuard _(s_mouse_lock);
for (size_t i = 0; i < s_mice.size(); i++) for (size_t i = 0; i < s_mice.size(); i++)
if (!s_mice[i].valid()) if (!s_mice[i].valid())
return makedev(DeviceNumber::Mouse, i + 1); return makedev(DeviceNumber::Mouse, i + 1);
return makedev(DeviceNumber::Mouse, s_mice.size() + 1); return makedev(DeviceNumber::Mouse, s_mice.size() + 1);
}
case InputDevice::Type::Joystick: case InputDevice::Type::Joystick:
{
SpinLockGuard _(s_joystick_lock);
for (size_t i = 0; i < s_joysticks.size(); i++) for (size_t i = 0; i < s_joysticks.size(); i++)
if (!s_joysticks[i].valid()) if (!s_joysticks[i].valid())
return makedev(DeviceNumber::Joystick, i + 1); return makedev(DeviceNumber::Joystick, i + 1);
return makedev(DeviceNumber::Joystick, s_joysticks.size() + 1); return makedev(DeviceNumber::Joystick, s_joysticks.size() + 1);
}
} }
ASSERT_NOT_REACHED(); ASSERT_NOT_REACHED();
} }
@@ -84,20 +96,29 @@ namespace Kernel
switch (m_type) switch (m_type)
{ {
case Type::Keyboard: case Type::Keyboard:
{
SpinLockGuard _(s_keyboard_lock);
if (s_keyboards.size() < minor(m_rdev)) if (s_keyboards.size() < minor(m_rdev))
MUST(s_keyboards.resize(minor(m_rdev))); MUST(s_keyboards.resize(minor(m_rdev)));
s_keyboards[minor(m_rdev) - 1] = MUST(get_weak_ptr()); s_keyboards[minor(m_rdev) - 1] = MUST(get_weak_ptr());
break; break;
}
case Type::Mouse: case Type::Mouse:
{
SpinLockGuard _(s_mouse_lock);
if (s_mice.size() < minor(m_rdev)) if (s_mice.size() < minor(m_rdev))
MUST(s_mice.resize(minor(m_rdev))); MUST(s_mice.resize(minor(m_rdev)));
s_mice[minor(m_rdev) - 1] = MUST(get_weak_ptr()); s_mice[minor(m_rdev) - 1] = MUST(get_weak_ptr());
break; break;
}
case Type::Joystick: case Type::Joystick:
{
SpinLockGuard _(s_joystick_lock);
if (s_joysticks.size() < minor(m_rdev)) if (s_joysticks.size() < minor(m_rdev))
MUST(s_joysticks.resize(minor(m_rdev))); MUST(s_joysticks.resize(minor(m_rdev)));
s_joysticks[minor(m_rdev) - 1] = MUST(get_weak_ptr()); s_joysticks[minor(m_rdev) - 1] = MUST(get_weak_ptr());
break; break;
}
} }
} }
@@ -256,6 +277,8 @@ namespace Kernel
void KeyboardDevice::notify() void KeyboardDevice::notify()
{ {
epoll_notify(EPOLLIN); epoll_notify(EPOLLIN);
SpinLockGuard _(s_keyboard_lock);
m_thread_blocker.unblock(); m_thread_blocker.unblock();
} }
@@ -264,6 +287,7 @@ namespace Kernel
if (buffer.size() < sizeof(LibInput::RawKeyEvent)) if (buffer.size() < sizeof(LibInput::RawKeyEvent))
return BAN::Error::from_errno(ENOBUFS); return BAN::Error::from_errno(ENOBUFS);
SpinLockGuard keyboard_guard(s_keyboard_lock);
for (;;) for (;;)
{ {
for (auto& weak_keyboard : s_keyboards) for (auto& weak_keyboard : s_keyboards)
@@ -277,13 +301,14 @@ namespace Kernel
return bytes; return bytes;
} }
// FIXME: race condition as notify doesn't lock mutex SpinLockGuardAsMutex smutex(keyboard_guard);
TRY(Thread::current().block_or_eintr_indefinite(m_thread_blocker, &m_mutex)); TRY(Thread::current().block_or_eintr_indefinite(m_thread_blocker, &smutex));
} }
} }
bool KeyboardDevice::can_read_impl() const bool KeyboardDevice::can_read_impl() const
{ {
SpinLockGuard _(s_keyboard_lock);
for (auto& weak_keyboard : s_keyboards) for (auto& weak_keyboard : s_keyboards)
if (auto keyboard = weak_keyboard.lock()) if (auto keyboard = weak_keyboard.lock())
if (keyboard->can_read()) if (keyboard->can_read())
@@ -308,6 +333,8 @@ namespace Kernel
void MouseDevice::notify() void MouseDevice::notify()
{ {
epoll_notify(EPOLLIN); epoll_notify(EPOLLIN);
SpinLockGuard _(s_mouse_lock);
m_thread_blocker.unblock(); m_thread_blocker.unblock();
} }
@@ -316,6 +343,7 @@ namespace Kernel
if (buffer.size() < sizeof(LibInput::MouseEvent)) if (buffer.size() < sizeof(LibInput::MouseEvent))
return BAN::Error::from_errno(ENOBUFS); return BAN::Error::from_errno(ENOBUFS);
SpinLockGuard mouse_guard(s_mouse_lock);
for (;;) for (;;)
{ {
for (auto& weak_mouse : s_mice) for (auto& weak_mouse : s_mice)
@@ -329,13 +357,14 @@ namespace Kernel
return bytes; return bytes;
} }
// FIXME: race condition as notify doesn't lock mutex SpinLockGuardAsMutex smutex(mouse_guard);
TRY(Thread::current().block_or_eintr_indefinite(m_thread_blocker, &m_mutex)); TRY(Thread::current().block_or_eintr_indefinite(m_thread_blocker, &smutex));
} }
} }
bool MouseDevice::can_read_impl() const bool MouseDevice::can_read_impl() const
{ {
SpinLockGuard _(s_mouse_lock);
for (auto& weak_mouse : s_mice) for (auto& weak_mouse : s_mice)
if (auto mouse = weak_mouse.lock()) if (auto mouse = weak_mouse.lock())
if (mouse->can_read()) if (mouse->can_read())

View File

@@ -35,7 +35,7 @@ namespace Kernel
if (type == Type::PRIVATE) if (type == Type::PRIVATE)
TRY(region->m_dirty_pages.resize(BAN::Math::div_round_up<size_t>(size, PAGE_SIZE))); TRY(region->m_dirty_pages.resize(BAN::Math::div_round_up<size_t>(size, PAGE_SIZE)));
LockGuard _(inode->m_mutex); SpinLockGuard _(inode->m_shared_region_lock);
if (!(region->m_shared_data = inode->m_shared_region.lock())) if (!(region->m_shared_data = inode->m_shared_region.lock()))
{ {
auto shared_data = TRY(BAN::RefPtr<SharedFileData>::create()); auto shared_data = TRY(BAN::RefPtr<SharedFileData>::create());

View File

@@ -66,6 +66,8 @@ namespace Kernel
BAN::ErrorOr<long> TCPSocket::accept_impl(sockaddr* address, socklen_t* address_len, int flags) BAN::ErrorOr<long> TCPSocket::accept_impl(sockaddr* address, socklen_t* address_len, int flags)
{ {
LockGuard _(m_mutex);
if (m_state != State::Listen) if (m_state != State::Listen)
return BAN::Error::from_errno(EINVAL); return BAN::Error::from_errno(EINVAL);
@@ -171,6 +173,8 @@ namespace Kernel
BAN::ErrorOr<void> TCPSocket::listen_impl(int backlog) BAN::ErrorOr<void> TCPSocket::listen_impl(int backlog)
{ {
LockGuard _(m_mutex);
if (!is_bound()) if (!is_bound())
return BAN::Error::from_errno(EDESTADDRREQ); return BAN::Error::from_errno(EDESTADDRREQ);
if (m_connection_info.has_value()) if (m_connection_info.has_value())
@@ -185,6 +189,8 @@ namespace Kernel
BAN::ErrorOr<void> TCPSocket::bind_impl(const sockaddr* address, socklen_t address_len) BAN::ErrorOr<void> TCPSocket::bind_impl(const sockaddr* address, socklen_t address_len)
{ {
LockGuard _(m_mutex);
if (is_bound()) if (is_bound())
return BAN::Error::from_errno(EINVAL); return BAN::Error::from_errno(EINVAL);
return m_network_layer.bind_socket_to_address(this, address, address_len); return m_network_layer.bind_socket_to_address(this, address, address_len);
@@ -204,6 +210,8 @@ namespace Kernel
message.msg_controllen = 0; message.msg_controllen = 0;
} }
LockGuard _(m_mutex);
if (!m_has_connected) if (!m_has_connected)
return BAN::Error::from_errno(ENOTCONN); return BAN::Error::from_errno(ENOTCONN);
@@ -261,6 +269,8 @@ namespace Kernel
if (CMSG_FIRSTHDR(&message)) if (CMSG_FIRSTHDR(&message))
dwarnln("ignoring sendmsg control message"); dwarnln("ignoring sendmsg control message");
LockGuard _(m_mutex);
if (!m_has_connected) if (!m_has_connected)
return BAN::Error::from_errno(ENOTCONN); return BAN::Error::from_errno(ENOTCONN);
@@ -291,6 +301,7 @@ namespace Kernel
BAN::ErrorOr<void> TCPSocket::getpeername_impl(sockaddr* address, socklen_t* address_len) BAN::ErrorOr<void> TCPSocket::getpeername_impl(sockaddr* address, socklen_t* address_len)
{ {
LockGuard _(m_mutex);
if (!m_has_connected && m_state != State::Established) if (!m_has_connected && m_state != State::Established)
return BAN::Error::from_errno(ENOTCONN); return BAN::Error::from_errno(ENOTCONN);
ASSERT(m_connection_info.has_value()); ASSERT(m_connection_info.has_value());
@@ -302,6 +313,8 @@ namespace Kernel
BAN::ErrorOr<void> TCPSocket::getsockopt_impl(int level, int option, void* value, socklen_t* value_len) BAN::ErrorOr<void> TCPSocket::getsockopt_impl(int level, int option, void* value, socklen_t* value_len)
{ {
LockGuard _(m_mutex);
int result; int result;
switch (level) switch (level)
@@ -351,6 +364,8 @@ namespace Kernel
BAN::ErrorOr<void> TCPSocket::setsockopt_impl(int level, int option, const void* value, socklen_t value_len) BAN::ErrorOr<void> TCPSocket::setsockopt_impl(int level, int option, const void* value, socklen_t value_len)
{ {
LockGuard _(m_mutex);
switch (level) switch (level)
{ {
case SOL_SOCKET: case SOL_SOCKET:
@@ -401,6 +416,7 @@ namespace Kernel
bool TCPSocket::can_read_impl() const bool TCPSocket::can_read_impl() const
{ {
LockGuard _(m_mutex);
if (m_has_connected && !m_has_sent_zero && m_state != State::Established && m_state != State::Listen) if (m_has_connected && !m_has_sent_zero && m_state != State::Established && m_state != State::Listen)
return true; return true;
if (m_state == State::Listen) if (m_state == State::Listen)
@@ -410,6 +426,7 @@ namespace Kernel
bool TCPSocket::can_write_impl() const bool TCPSocket::can_write_impl() const
{ {
LockGuard _(m_mutex);
if (m_state != State::Established) if (m_state != State::Established)
return false; return false;
return !m_send_window.buffer->full(); return !m_send_window.buffer->full();
@@ -417,6 +434,7 @@ namespace Kernel
bool TCPSocket::has_hungup_impl() const bool TCPSocket::has_hungup_impl() const
{ {
LockGuard _(m_mutex);
return m_has_connected && m_state != State::Established; return m_has_connected && m_state != State::Established;
} }

View File

@@ -1,3 +1,4 @@
#include <kernel/Lock/LockGuard.h>
#include <kernel/Lock/SpinLockAsMutex.h> #include <kernel/Lock/SpinLockAsMutex.h>
#include <kernel/Memory/Heap.h> #include <kernel/Memory/Heap.h>
#include <kernel/Networking/UDPSocket.h> #include <kernel/Networking/UDPSocket.h>
@@ -58,9 +59,6 @@ namespace Kernel
void UDPSocket::receive_packet(BAN::ConstByteSpan packet, const sockaddr* sender, socklen_t sender_len) void UDPSocket::receive_packet(BAN::ConstByteSpan packet, const sockaddr* sender, socklen_t sender_len)
{ {
(void)sender_len;
//auto& header = packet.as<const UDPHeader>();
auto payload = packet.slice(sizeof(UDPHeader)); auto payload = packet.slice(sizeof(UDPHeader));
SpinLockGuard _(m_packet_lock); SpinLockGuard _(m_packet_lock);
@@ -95,6 +93,8 @@ namespace Kernel
{ {
if (address_len > static_cast<socklen_t>(sizeof(m_peer_address))) if (address_len > static_cast<socklen_t>(sizeof(m_peer_address)))
address_len = sizeof(m_peer_address); address_len = sizeof(m_peer_address);
SpinLockGuard _(m_peer_address_lock);
memcpy(&m_peer_address, address, address_len); memcpy(&m_peer_address, address, address_len);
m_peer_address_len = address_len; m_peer_address_len = address_len;
return {}; return {};
@@ -102,6 +102,7 @@ namespace Kernel
BAN::ErrorOr<void> UDPSocket::bind_impl(const sockaddr* address, socklen_t address_len) BAN::ErrorOr<void> UDPSocket::bind_impl(const sockaddr* address, socklen_t address_len)
{ {
LockGuard _(m_bind_lock);
if (is_bound()) if (is_bound())
return BAN::Error::from_errno(EINVAL); return BAN::Error::from_errno(EINVAL);
return m_network_layer.bind_socket_to_address(this, address, address_len); return m_network_layer.bind_socket_to_address(this, address, address_len);
@@ -183,8 +184,11 @@ namespace Kernel
if (CMSG_FIRSTHDR(&message)) if (CMSG_FIRSTHDR(&message))
dwarnln("ignoring sendmsg control message"); dwarnln("ignoring sendmsg control message");
if (!is_bound()) {
TRY(m_network_layer.bind_socket_with_target(this, static_cast<sockaddr*>(message.msg_name), message.msg_namelen)); LockGuard _(m_bind_lock);
if (!is_bound())
TRY(m_network_layer.bind_socket_with_target(this, static_cast<sockaddr*>(message.msg_name), message.msg_namelen));
}
const size_t total_send_size = const size_t total_send_size =
[&message]() -> size_t { [&message]() -> size_t {
@@ -208,6 +212,7 @@ namespace Kernel
socklen_t address_len; socklen_t address_len;
if (!message.msg_name || message.msg_namelen == 0) if (!message.msg_name || message.msg_namelen == 0)
{ {
SpinLockGuard _(m_peer_address_lock);
if (m_peer_address_len == 0) if (m_peer_address_len == 0)
return BAN::Error::from_errno(EDESTADDRREQ); return BAN::Error::from_errno(EDESTADDRREQ);
address = reinterpret_cast<sockaddr*>(&m_peer_address); address = reinterpret_cast<sockaddr*>(&m_peer_address);

View File

@@ -88,6 +88,26 @@ namespace Kernel
} }
} }
bool UnixDomainSocket::is_bound() const
{
LockGuard _(m_bind_mutex);
return !m_bound_file.canonical_path.empty();
}
bool UnixDomainSocket::is_bound_to_unused() const
{
LockGuard _(m_bind_mutex);
return !m_bound_file.inode;
}
BAN::ErrorOr<void> UnixDomainSocket::bind_to_unused_if_not_bound()
{
LockGuard _(m_bind_mutex);
if (!is_bound())
TRY(m_bound_file.canonical_path.push_back('X'));
return {};
}
BAN::ErrorOr<void> UnixDomainSocket::make_socket_pair(UnixDomainSocket& other) BAN::ErrorOr<void> UnixDomainSocket::make_socket_pair(UnixDomainSocket& other)
{ {
if (!m_info.has<ConnectionInfo>() || !other.m_info.has<ConnectionInfo>()) if (!m_info.has<ConnectionInfo>() || !other.m_info.has<ConnectionInfo>())
@@ -106,15 +126,15 @@ namespace Kernel
{ {
if (!m_info.has<ConnectionInfo>()) if (!m_info.has<ConnectionInfo>())
return BAN::Error::from_errno(EOPNOTSUPP); return BAN::Error::from_errno(EOPNOTSUPP);
auto& connection_info = m_info.get<ConnectionInfo>();
if (!connection_info.listening)
return BAN::Error::from_errno(EINVAL);
BAN::RefPtr<UnixDomainSocket> pending; BAN::RefPtr<UnixDomainSocket> pending;
{ {
auto& connection_info = m_info.get<ConnectionInfo>();
LockGuard _(connection_info.pending_lock); LockGuard _(connection_info.pending_lock);
if (!connection_info.listening)
return BAN::Error::from_errno(EINVAL);
while (connection_info.pending_connections.empty()) while (connection_info.pending_connections.empty())
TRY(Thread::current().block_or_eintr_indefinite(connection_info.pending_thread_blocker, &connection_info.pending_lock)); TRY(Thread::current().block_or_eintr_indefinite(connection_info.pending_thread_blocker, &connection_info.pending_lock));
@@ -154,8 +174,6 @@ namespace Kernel
BAN::ErrorOr<void> UnixDomainSocket::connect_impl(const sockaddr* address, socklen_t address_len) BAN::ErrorOr<void> UnixDomainSocket::connect_impl(const sockaddr* address, socklen_t address_len)
{ {
const auto sun_path = TRY(validate_sockaddr_un(address, address_len)); const auto sun_path = TRY(validate_sockaddr_un(address, address_len));
if (!is_bound())
TRY(m_bound_file.canonical_path.push_back('X'));
auto absolute_path = TRY(Process::current().absolute_path_of(sun_path)); auto absolute_path = TRY(Process::current().absolute_path_of(sun_path));
auto file = TRY(VirtualFileSystem::get().file_from_absolute_path( auto file = TRY(VirtualFileSystem::get().file_from_absolute_path(
@@ -180,9 +198,12 @@ namespace Kernel
if (m_socket_type != target->m_socket_type) if (m_socket_type != target->m_socket_type)
return BAN::Error::from_errno(EPROTOTYPE); return BAN::Error::from_errno(EPROTOTYPE);
TRY(bind_to_unused_if_not_bound());
if (m_info.has<ConnectionlessInfo>()) if (m_info.has<ConnectionlessInfo>())
{ {
auto& connectionless_info = m_info.get<ConnectionlessInfo>(); auto& connectionless_info = m_info.get<ConnectionlessInfo>();
SpinLockGuard _(connectionless_info.lock);
connectionless_info.peer_address = BAN::move(file.canonical_path); connectionless_info.peer_address = BAN::move(file.canonical_path);
return {}; return {};
} }
@@ -192,7 +213,6 @@ namespace Kernel
return BAN::Error::from_errno(ECONNREFUSED); return BAN::Error::from_errno(ECONNREFUSED);
if (connection_info.listening) if (connection_info.listening)
return BAN::Error::from_errno(EOPNOTSUPP); return BAN::Error::from_errno(EOPNOTSUPP);
connection_info.connection_done = false; connection_info.connection_done = false;
for (;;) for (;;)
@@ -222,23 +242,25 @@ namespace Kernel
BAN::ErrorOr<void> UnixDomainSocket::listen_impl(int backlog) BAN::ErrorOr<void> UnixDomainSocket::listen_impl(int backlog)
{ {
backlog = BAN::Math::clamp(backlog, 1, SOMAXCONN); backlog = BAN::Math::clamp(backlog, 1, SOMAXCONN);
if (!is_bound()) if (!is_bound())
return BAN::Error::from_errno(EDESTADDRREQ); return BAN::Error::from_errno(EDESTADDRREQ);
if (!m_info.has<ConnectionInfo>()) if (!m_info.has<ConnectionInfo>())
return BAN::Error::from_errno(EOPNOTSUPP); return BAN::Error::from_errno(EOPNOTSUPP);
auto& connection_info = m_info.get<ConnectionInfo>(); auto& connection_info = m_info.get<ConnectionInfo>();
LockGuard _(connection_info.pending_lock);
if (connection_info.connection) if (connection_info.connection)
return BAN::Error::from_errno(EINVAL); return BAN::Error::from_errno(EINVAL);
TRY(connection_info.pending_connections.reserve(backlog)); TRY(connection_info.pending_connections.reserve(backlog));
connection_info.listening = true; connection_info.listening = true;
return {}; return {};
} }
BAN::ErrorOr<void> UnixDomainSocket::bind_impl(const sockaddr* address, socklen_t address_len) BAN::ErrorOr<void> UnixDomainSocket::bind_impl(const sockaddr* address, socklen_t address_len)
{ {
if (is_bound())
return BAN::Error::from_errno(EINVAL);
const auto sun_path = TRY(validate_sockaddr_un(address, address_len)); const auto sun_path = TRY(validate_sockaddr_un(address, address_len));
if (sun_path.empty()) if (sun_path.empty())
return BAN::Error::from_errno(EINVAL); return BAN::Error::from_errno(EINVAL);
@@ -261,10 +283,15 @@ namespace Kernel
O_RDWR O_RDWR
)); ));
LockGuard _(s_bound_socket_lock); LockGuard _0(m_bind_mutex);
if (is_bound())
return BAN::Error::from_errno(EINVAL);
LockGuard _1(s_bound_socket_lock);
if (s_bound_sockets.contains(file.inode)) if (s_bound_sockets.contains(file.inode))
return BAN::Error::from_errno(EADDRINUSE); return BAN::Error::from_errno(EADDRINUSE);
TRY(s_bound_sockets.emplace(file.inode, TRY(get_weak_ptr()))); TRY(s_bound_sockets.emplace(file.inode, TRY(get_weak_ptr())));
m_bound_file = BAN::move(file); m_bound_file = BAN::move(file);
return {}; return {};
@@ -679,6 +706,7 @@ namespace Kernel
{ {
if (!m_info.has<ConnectionInfo>()) if (!m_info.has<ConnectionInfo>())
return BAN::Error::from_errno(ENOTCONN); return BAN::Error::from_errno(ENOTCONN);
auto connection = m_info.get<ConnectionInfo>().connection.lock(); auto connection = m_info.get<ConnectionInfo>().connection.lock();
if (!connection) if (!connection)
return BAN::Error::from_errno(ENOTCONN); return BAN::Error::from_errno(ENOTCONN);
@@ -687,7 +715,11 @@ namespace Kernel
.sun_family = AF_UNIX, .sun_family = AF_UNIX,
.sun_path = {}, .sun_path = {},
}; };
strcpy(sa_un.sun_path, connection->m_bound_file.canonical_path.data());
{
LockGuard _(m_bind_mutex);
strcpy(sa_un.sun_path, connection->m_bound_file.canonical_path.data());
}
const size_t to_copy = BAN::Math::min<socklen_t>(sizeof(sockaddr_un), *address_len); const size_t to_copy = BAN::Math::min<socklen_t>(sizeof(sockaddr_un), *address_len);
memcpy(address, &sa_un, to_copy); memcpy(address, &sa_un, to_copy);

View File

@@ -699,9 +699,9 @@ namespace Kernel
size_t nread; size_t nread;
{ {
LockGuard _(inode->m_mutex);
if (!inode->can_read() && inode->has_hungup()) if (!inode->can_read() && inode->has_hungup())
return 0; return 0;
// FIXME: race condition, pass flags to read
if (is_nonblock && !inode->can_read()) if (is_nonblock && !inode->can_read())
return BAN::Error::from_errno(EAGAIN); return BAN::Error::from_errno(EAGAIN);
nread = TRY(inode->read(offset, buffer)); nread = TRY(inode->read(offset, buffer));
@@ -753,7 +753,6 @@ namespace Kernel
size_t nwrite; size_t nwrite;
{ {
LockGuard _(inode->m_mutex);
if (inode->has_error()) if (inode->has_error())
{ {
Thread::current().add_signal(SIGPIPE, {}); Thread::current().add_signal(SIGPIPE, {});
@@ -761,6 +760,7 @@ namespace Kernel
} }
if (is_nonblock && !inode->can_write()) if (is_nonblock && !inode->can_write())
return BAN::Error::from_errno(EAGAIN); return BAN::Error::from_errno(EAGAIN);
// FIXME: race condition, pass flags to write
nwrite = TRY(inode->write(offset, buffer)); nwrite = TRY(inode->write(offset, buffer));
} }
@@ -818,7 +818,6 @@ namespace Kernel
is_nonblock = !!(open_file->status_flags & O_NONBLOCK); is_nonblock = !!(open_file->status_flags & O_NONBLOCK);
} }
LockGuard _(inode->m_mutex);
if (is_nonblock && !inode->can_read()) if (is_nonblock && !inode->can_read())
return BAN::Error::from_errno(EAGAIN); return BAN::Error::from_errno(EAGAIN);
return inode->recvmsg(message, flags); return inode->recvmsg(message, flags);
@@ -839,7 +838,6 @@ namespace Kernel
is_nonblock = !!(open_file->status_flags & O_NONBLOCK); is_nonblock = !!(open_file->status_flags & O_NONBLOCK);
} }
LockGuard _(inode->m_mutex);
if (inode->has_hungup()) if (inode->has_hungup())
{ {
if (!(flags & MSG_NOSIGNAL)) if (!(flags & MSG_NOSIGNAL))

View File

@@ -1,5 +1,6 @@
#include <kernel/CPUID.h> #include <kernel/CPUID.h>
#include <kernel/Debug.h> #include <kernel/Debug.h>
#include <kernel/Lock/SpinLock.h>
#include <kernel/Random.h> #include <kernel/Random.h>
#include <kernel/Timer/Timer.h> #include <kernel/Timer/Timer.h>
@@ -9,6 +10,7 @@ namespace Kernel
// Constants and algorithm from https://en.wikipedia.org/wiki/Permuted_congruential_generator // Constants and algorithm from https://en.wikipedia.org/wiki/Permuted_congruential_generator
static SpinLock s_rand_lock;
static uint64_t s_rand_seed = 0x4d595df4d0f33173; static uint64_t s_rand_seed = 0x4d595df4d0f33173;
static constexpr uint64_t s_rand_multiplier = 6364136223846793005; static constexpr uint64_t s_rand_multiplier = 6364136223846793005;
static constexpr uint64_t s_rand_increment = 1442695040888963407; static constexpr uint64_t s_rand_increment = 1442695040888963407;
@@ -46,7 +48,9 @@ namespace Kernel
uint32_t Random::get_u32() uint32_t Random::get_u32()
{ {
auto rotr32 = [](uint32_t x, unsigned r) { return x >> r | x << (-r & 31); }; constexpr auto rotr32 = [](uint32_t x, unsigned r) { return x >> r | x << (-r & 31); };
SpinLockGuard _(s_rand_lock);
uint64_t x = s_rand_seed; uint64_t x = s_rand_seed;
unsigned count = (unsigned)(x >> 59); unsigned count = (unsigned)(x >> 59);

View File

@@ -144,6 +144,7 @@ namespace Kernel
auto slave = m_slave.lock(); auto slave = m_slave.lock();
if (!slave) if (!slave)
return BAN::Error::from_errno(EIO); return BAN::Error::from_errno(EIO);
LockGuard _(slave->m_mutex);
for (size_t i = 0; i < buffer.size(); i++) for (size_t i = 0; i < buffer.size(); i++)
slave->handle_input_byte(buffer[i]); slave->handle_input_byte(buffer[i]);
return buffer.size(); return buffer.size();
@@ -160,8 +161,11 @@ namespace Kernel
switch (request) switch (request)
{ {
case FIONREAD: case FIONREAD:
{
SpinLockGuard _(m_buffer_lock);
*static_cast<int*>(argument) = m_buffer_size; *static_cast<int*>(argument) = m_buffer_size;
return 0; return 0;
}
case TIOCGWINSZ: case TIOCGWINSZ:
case TIOCSWINSZ: case TIOCSWINSZ:
if (auto slave = m_slave.lock()) if (auto slave = m_slave.lock())

View File

@@ -6,6 +6,7 @@
#include <kernel/FS/DevFS/FileSystem.h> #include <kernel/FS/DevFS/FileSystem.h>
#include <kernel/FS/VirtualFileSystem.h> #include <kernel/FS/VirtualFileSystem.h>
#include <kernel/Lock/LockGuard.h> #include <kernel/Lock/LockGuard.h>
#include <kernel/Lock/SpinLockAsMutex.h>
#include <kernel/Process.h> #include <kernel/Process.h>
#include <kernel/Terminal/TTY.h> #include <kernel/Terminal/TTY.h>
#include <kernel/Timer/Timer.h> #include <kernel/Timer/Timer.h>
@@ -71,8 +72,8 @@ namespace Kernel
TTY::TTY(termios termios, mode_t mode, uid_t uid, gid_t gid) TTY::TTY(termios termios, mode_t mode, uid_t uid, gid_t gid)
: CharacterDevice(mode, uid, gid) : CharacterDevice(mode, uid, gid)
, m_termios(termios)
, m_rdev(next_tty_rdev()) , m_rdev(next_tty_rdev())
, m_termios(termios)
{ {
m_output.buffer = MUST(ByteRingBuffer::create(PAGE_SIZE)); m_output.buffer = MUST(ByteRingBuffer::create(PAGE_SIZE));
} }
@@ -94,21 +95,16 @@ namespace Kernel
if (flags & ~(TTY_FLAG_ENABLE_INPUT | TTY_FLAG_ENABLE_OUTPUT)) if (flags & ~(TTY_FLAG_ENABLE_INPUT | TTY_FLAG_ENABLE_OUTPUT))
return BAN::Error::from_errno(EINVAL); return BAN::Error::from_errno(EINVAL);
LockGuard _(m_mutex);
switch (command) switch (command)
{ {
case TTY_CMD_SET: case TTY_CMD_SET:
if ((flags & TTY_FLAG_ENABLE_INPUT) && !m_tty_ctrl.receive_input) if (flags & TTY_FLAG_ENABLE_INPUT)
{
m_tty_ctrl.receive_input = true; m_tty_ctrl.receive_input = true;
m_tty_ctrl.thread_blocker.unblock();
}
if (flags & TTY_FLAG_ENABLE_OUTPUT) if (flags & TTY_FLAG_ENABLE_OUTPUT)
m_tty_ctrl.draw_graphics = true; m_tty_ctrl.draw_graphics = true;
break; break;
case TTY_CMD_UNSET: case TTY_CMD_UNSET:
if ((flags & TTY_FLAG_ENABLE_INPUT) && m_tty_ctrl.receive_input) if (flags & TTY_FLAG_ENABLE_INPUT)
m_tty_ctrl.receive_input = false; m_tty_ctrl.receive_input = false;
if (flags & TTY_FLAG_ENABLE_OUTPUT) if (flags & TTY_FLAG_ENABLE_OUTPUT)
m_tty_ctrl.draw_graphics = false; m_tty_ctrl.draw_graphics = false;
@@ -133,16 +129,8 @@ namespace Kernel
while (true) while (true)
{ {
{
LockGuard _(TTY::current()->m_mutex);
while (!TTY::current()->m_tty_ctrl.receive_input)
TTY::current()->m_tty_ctrl.thread_blocker.block_indefinite(&TTY::current()->m_mutex);
}
while (TTY::current()->m_tty_ctrl.receive_input) while (TTY::current()->m_tty_ctrl.receive_input)
{ {
LockGuard _(keyboard_inode->m_mutex);
if (!keyboard_inode->can_read()) if (!keyboard_inode->can_read())
{ {
SystemTimer::get().sleep_ms(1); SystemTimer::get().sleep_ms(1);
@@ -160,19 +148,15 @@ namespace Kernel
void TTY::initialize_devices() void TTY::initialize_devices()
{ {
static bool initialized = false;
ASSERT(!initialized);
auto* thread = MUST(Thread::create_kernel(&TTY::keyboard_task, nullptr)); auto* thread = MUST(Thread::create_kernel(&TTY::keyboard_task, nullptr));
MUST(Processor::scheduler().add_thread(thread)); MUST(Processor::scheduler().add_thread(thread));
DevFileSystem::get().add_inode("tty", MUST(DevTTY::create(0666, 0, 0))); DevFileSystem::get().add_inode("tty", MUST(DevTTY::create(0666, 0, 0)));
initialized = true;
} }
BAN::ErrorOr<void> TTY::chmod_impl(mode_t mode) BAN::ErrorOr<void> TTY::chmod_impl(mode_t mode)
{ {
// FIXME: make this atomic
ASSERT((mode & Inode::Mode::TYPE_MASK) == 0); ASSERT((mode & Inode::Mode::TYPE_MASK) == 0);
m_inode_info.mode &= Inode::Mode::TYPE_MASK; m_inode_info.mode &= Inode::Mode::TYPE_MASK;
m_inode_info.mode |= mode; m_inode_info.mode |= mode;
@@ -181,6 +165,7 @@ namespace Kernel
BAN::ErrorOr<void> TTY::chown_impl(uid_t uid, gid_t gid) BAN::ErrorOr<void> TTY::chown_impl(uid_t uid, gid_t gid)
{ {
// FIXME: make this atomic
m_inode_info.uid = uid; m_inode_info.uid = uid;
m_inode_info.gid = gid; m_inode_info.gid = gid;
return {}; return {};
@@ -188,6 +173,7 @@ namespace Kernel
void TTY::update_winsize(unsigned short cols, unsigned short rows) void TTY::update_winsize(unsigned short cols, unsigned short rows)
{ {
// FIXME: make this atomic
m_winsize.ws_col = cols; m_winsize.ws_col = cols;
m_winsize.ws_row = rows; m_winsize.ws_row = rows;
(void)Process::kill(-m_foreground_pgrp, SIGWINCH); (void)Process::kill(-m_foreground_pgrp, SIGWINCH);
@@ -211,12 +197,14 @@ namespace Kernel
} }
case TIOCGWINSZ: case TIOCGWINSZ:
{ {
// FIXME: make this atomic
auto* winsize = static_cast<struct winsize*>(argument); auto* winsize = static_cast<struct winsize*>(argument);
*winsize = m_winsize; *winsize = m_winsize;
return 0; return 0;
} }
case TIOCSWINSZ: case TIOCSWINSZ:
{ {
// FIXME: make this atomic
const auto* winsize = static_cast<const struct winsize*>(argument); const auto* winsize = static_cast<const struct winsize*>(argument);
m_winsize = *winsize; m_winsize = *winsize;
(void)Process::kill(-m_foreground_pgrp, SIGWINCH); (void)Process::kill(-m_foreground_pgrp, SIGWINCH);
@@ -226,10 +214,13 @@ namespace Kernel
return BAN::Error::from_errno(ENOTSUP); return BAN::Error::from_errno(ENOTSUP);
} }
void TTY::on_key_event(LibInput::RawKeyEvent event)
{
on_key_event(LibInput::KeyboardLayout::get().key_event_from_raw(event));
}
void TTY::on_key_event(LibInput::KeyEvent event) void TTY::on_key_event(LibInput::KeyEvent event)
{ {
LockGuard _(m_mutex);
if (event.released()) if (event.released())
return; return;
@@ -237,35 +228,55 @@ namespace Kernel
if (ansi_c_str == nullptr) if (ansi_c_str == nullptr)
return; return;
LockGuard _(m_mutex);
while (*ansi_c_str) while (*ansi_c_str)
handle_input_byte(*ansi_c_str++); handle_input_byte(*ansi_c_str++);
after_write(); after_write();
} }
void TTY::get_termios(termios* termios)
{
SpinLockGuard _(m_termios_lock);
*termios = m_termios;
}
BAN::ErrorOr<void> TTY::set_termios(const termios* termios)
{
// FIXME: do some validation
SpinLockGuard _(m_termios_lock);
m_termios = *termios;
return {};
}
void TTY::handle_input_byte(uint8_t ch) void TTY::handle_input_byte(uint8_t ch)
{ {
if (ch == _POSIX_VDISABLE) if (ch == _POSIX_VDISABLE)
return; return;
LockGuard _(m_mutex); LockGuard _0(m_mutex);
if ((m_termios.c_iflag & ISTRIP)) termios termios;
get_termios(&termios);
if ((termios.c_iflag & ISTRIP))
ch &= 0x7F; ch &= 0x7F;
if ((m_termios.c_iflag & IGNCR) && ch == CR) if ((termios.c_iflag & IGNCR) && ch == CR)
return; return;
if ((m_termios.c_iflag & ICRNL) && ch == CR) if ((termios.c_iflag & ICRNL) && ch == CR)
ch = NL; ch = NL;
else if ((m_termios.c_iflag & INLCR) && ch == NL) else if ((termios.c_iflag & INLCR) && ch == NL)
ch = CR; ch = CR;
if (m_termios.c_lflag & ISIG) if (termios.c_lflag & ISIG)
{ {
int sig = -1; int sig = -1;
if (ch == m_termios.c_cc[VINTR]) if (ch == termios.c_cc[VINTR])
sig = SIGINT; sig = SIGINT;
if (ch == m_termios.c_cc[VQUIT]) if (ch == termios.c_cc[VQUIT])
sig = SIGQUIT; sig = SIGQUIT;
if (ch == m_termios.c_cc[VSUSP]) if (ch == termios.c_cc[VSUSP])
sig = SIGTSTP; sig = SIGTSTP;
if (sig != -1) if (sig != -1)
{ {
@@ -279,30 +290,30 @@ namespace Kernel
bool should_flush = false; bool should_flush = false;
bool force_echo = false; bool force_echo = false;
if (!(m_termios.c_lflag & ICANON)) if (!(termios.c_lflag & ICANON))
should_flush = true; should_flush = true;
else else
{ {
if (ch == m_termios.c_cc[VERASE] && (m_termios.c_lflag & ECHOE)) if (ch == termios.c_cc[VERASE] && (termios.c_lflag & ECHOE))
return do_backspace(); return do_backspace();
if (ch == m_termios.c_cc[VKILL] && (m_termios.c_lflag & ECHOK)) if (ch == termios.c_cc[VKILL] && (termios.c_lflag & ECHOK))
{ {
while (!m_output.buffer->empty() && m_output.buffer->back() != '\n') while (!m_output.buffer->empty() && m_output.buffer->back() != '\n')
do_backspace(); do_backspace();
return; return;
} }
if (ch == m_termios.c_cc[VEOF]) if (ch == termios.c_cc[VEOF])
{ {
should_append = false; should_append = false;
should_flush = true; should_flush = true;
} }
if (ch == NL || ch == CR || ch == m_termios.c_cc[VEOL]) if (ch == NL || ch == CR || ch == termios.c_cc[VEOL])
{ {
should_flush = true; should_flush = true;
force_echo = !!(m_termios.c_lflag & ECHONL); force_echo = !!(termios.c_lflag & ECHONL);
} }
} }
@@ -311,7 +322,7 @@ namespace Kernel
if (should_append && !m_output.buffer->full()) if (should_append && !m_output.buffer->full())
m_output.buffer->push({ &ch, 1 }); m_output.buffer->push({ &ch, 1 });
if (should_append && (force_echo || (m_termios.c_lflag & ECHO))) if (should_append && (force_echo || (termios.c_lflag & ECHO)))
{ {
if ((ch <= 31 || ch == 127) && ch != '\n') if ((ch <= 31 || ch == 127) && ch != '\n')
{ {
@@ -380,14 +391,18 @@ namespace Kernel
bool TTY::putchar(uint8_t ch) bool TTY::putchar(uint8_t ch)
{ {
SpinLockGuard _(m_write_lock);
if (!m_tty_ctrl.draw_graphics) if (!m_tty_ctrl.draw_graphics)
return true; return true;
if (m_termios.c_oflag & OPOST)
termios termios;
get_termios(&termios);
SpinLockGuard _1(m_write_lock);
if (termios.c_oflag & OPOST)
{ {
if ((m_termios.c_oflag & ONLCR) && ch == NL) if ((termios.c_oflag & ONLCR) && ch == NL)
return putchar_impl(CR) && putchar_impl(NL); return putchar_impl(CR) && putchar_impl(NL);
if ((m_termios.c_oflag & OCRNL) && ch == CR) if ((termios.c_oflag & OCRNL) && ch == CR)
return putchar_impl(NL); return putchar_impl(NL);
} }
return putchar_impl(ch); return putchar_impl(ch);
@@ -395,6 +410,7 @@ namespace Kernel
BAN::ErrorOr<size_t> TTY::read_impl(off_t, BAN::ByteSpan buffer) BAN::ErrorOr<size_t> TTY::read_impl(off_t, BAN::ByteSpan buffer)
{ {
LockGuard _(m_mutex);
while (!m_output.flush) while (!m_output.flush)
TRY(Thread::current().block_or_eintr_indefinite(m_output.thread_blocker, &m_mutex)); TRY(Thread::current().block_or_eintr_indefinite(m_output.thread_blocker, &m_mutex));
@@ -428,24 +444,24 @@ namespace Kernel
BAN::ErrorOr<size_t> TTY::write_impl(off_t, BAN::ConstByteSpan buffer) BAN::ErrorOr<size_t> TTY::write_impl(off_t, BAN::ConstByteSpan buffer)
{ {
while (!can_write_impl()) SpinLockGuard write_guard(m_write_lock);
while (!can_write())
{ {
if (master_has_closed()) if (master_has_closed())
return BAN::Error::from_errno(EIO); return BAN::Error::from_errno(EIO);
TRY(Thread::current().block_or_eintr_indefinite(m_write_blocker, &m_mutex));
SpinLockGuardAsMutex smutex(write_guard);
TRY(Thread::current().block_or_eintr_indefinite(m_write_blocker, &smutex));
} }
size_t written = 0; size_t written = 0;
for (; written < buffer.size(); written++)
if (!putchar(buffer[written]))
break;
after_write();
{ if (can_write())
SpinLockGuard _(m_write_lock);
for (; written < buffer.size(); written++)
if (!putchar(buffer[written]))
break;
after_write();
}
if (can_write_impl())
epoll_notify(EPOLLOUT); epoll_notify(EPOLLOUT);
return written; return written;

View File

@@ -23,6 +23,7 @@ namespace Kernel
g_terminal_driver = TRY(TextModeTerminalDriver::create_from_boot_info()); g_terminal_driver = TRY(TextModeTerminalDriver::create_from_boot_info());
break; break;
} }
return {}; return {};
} }