Compare commits
8 Commits
8b2bb95b81
...
1d470fb5ba
Author | SHA1 | Date |
---|---|---|
Bananymous | 1d470fb5ba | |
Bananymous | b4e4f7a6cc | |
Bananymous | 55d30a7cc3 | |
Bananymous | b62186441b | |
Bananymous | 8caba1e774 | |
Bananymous | 7bdb428938 | |
Bananymous | 3ea707c0e7 | |
Bananymous | 18d582c6ce |
|
@ -0,0 +1,107 @@
|
|||
#pragma once
|
||||
|
||||
#include <BAN/RefPtr.h>
|
||||
|
||||
namespace BAN
|
||||
{
|
||||
|
||||
template<typename T>
|
||||
class Weakable;
|
||||
|
||||
template<typename T>
|
||||
class WeakPtr;
|
||||
|
||||
template<typename T>
|
||||
class WeakLink : public RefCounted<WeakLink<T>>
|
||||
{
|
||||
public:
|
||||
RefPtr<T> lock() { ASSERT(m_ptr); return raw_ptr(); }
|
||||
T* raw_ptr() { return m_ptr; }
|
||||
|
||||
bool valid() const { return m_ptr; }
|
||||
void invalidate() { m_ptr = nullptr; }
|
||||
|
||||
private:
|
||||
WeakLink(T* ptr) : m_ptr(ptr) {}
|
||||
|
||||
private:
|
||||
T* m_ptr;
|
||||
|
||||
friend class RefPtr<WeakLink<T>>;
|
||||
};
|
||||
|
||||
template<typename T>
|
||||
class Weakable
|
||||
{
|
||||
public:
|
||||
~Weakable()
|
||||
{
|
||||
if (m_link)
|
||||
m_link->invalidate();
|
||||
}
|
||||
|
||||
ErrorOr<WeakPtr<T>> get_weak_ptr() const
|
||||
{
|
||||
if (!m_link)
|
||||
m_link = TRY(RefPtr<WeakLink<T>>::create((T*)this));
|
||||
return WeakPtr<T>(m_link);
|
||||
}
|
||||
|
||||
private:
|
||||
mutable RefPtr<WeakLink<T>> m_link;
|
||||
};
|
||||
|
||||
template<typename T>
|
||||
class WeakPtr
|
||||
{
|
||||
public:
|
||||
WeakPtr() = default;
|
||||
WeakPtr(WeakPtr&& other) { *this = move(other); }
|
||||
WeakPtr(const WeakPtr& other) { *this = other; }
|
||||
WeakPtr(const RefPtr<T>& other) { *this = other; }
|
||||
|
||||
WeakPtr& operator=(WeakPtr&& other)
|
||||
{
|
||||
clear();
|
||||
m_link = move(other.m_link);
|
||||
return *this;
|
||||
}
|
||||
WeakPtr& operator=(const WeakPtr& other)
|
||||
{
|
||||
clear();
|
||||
m_link = other.m_link;
|
||||
return *this;
|
||||
}
|
||||
WeakPtr& operator=(const RefPtr<T>& other)
|
||||
{
|
||||
clear();
|
||||
if (other)
|
||||
m_link = MUST(other->get_weak_ptr()).move_link();
|
||||
return *this;
|
||||
}
|
||||
|
||||
RefPtr<T> lock()
|
||||
{
|
||||
if (m_link->valid())
|
||||
return m_link->lock();
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
void clear() { m_link.clear(); }
|
||||
|
||||
bool valid() const { return m_link && m_link->valid(); }
|
||||
|
||||
private:
|
||||
WeakPtr(const RefPtr<WeakLink<T>>& link)
|
||||
: m_link(link)
|
||||
{ }
|
||||
|
||||
RefPtr<WeakLink<T>>&& move_link() { return move(m_link); }
|
||||
|
||||
private:
|
||||
RefPtr<WeakLink<T>> m_link;
|
||||
|
||||
friend class Weakable<T>;
|
||||
};
|
||||
|
||||
}
|
|
@ -4,7 +4,8 @@ set -e
|
|||
DISK_SIZE=$[50 * 1024 * 1024]
|
||||
MOUNT_DIR=/mnt
|
||||
|
||||
dd if=/dev/zero of=$DISK_IMAGE_PATH bs=512 count=$[$DISK_SIZE / 512] > /dev/null
|
||||
truncate -s 0 $DISK_IMAGE_PATH
|
||||
truncate -s $DISK_SIZE $DISK_IMAGE_PATH
|
||||
|
||||
sed -e 's/\s*\([-\+[:alnum:]]*\).*/\1/' << EOF | fdisk $DISK_IMAGE_PATH > /dev/null
|
||||
g # gpt
|
||||
|
@ -13,10 +14,6 @@ sed -e 's/\s*\([-\+[:alnum:]]*\).*/\1/' << EOF | fdisk $DISK_IMAGE_PATH > /dev/n
|
|||
# default (from the beginning of the disk)
|
||||
+1MiB # bios boot partiton size
|
||||
n # new partition
|
||||
3 # partition number 3
|
||||
# default (right after bios boot partition)
|
||||
+10Mib# partition size
|
||||
n # new partition
|
||||
2 # partition number 2
|
||||
# default (right after bios boot partition)
|
||||
# default (to the end of disk)
|
||||
|
@ -26,9 +23,6 @@ sed -e 's/\s*\([-\+[:alnum:]]*\).*/\1/' << EOF | fdisk $DISK_IMAGE_PATH > /dev/n
|
|||
t # set type
|
||||
2 # ... of partition 2
|
||||
20 # Linux filesystem
|
||||
t # set type
|
||||
3 # ... of partition 3
|
||||
20 # Linux filesystem
|
||||
w # write changes
|
||||
EOF
|
||||
|
||||
|
@ -37,13 +31,11 @@ sudo partprobe $LOOP_DEV
|
|||
|
||||
PARTITION1=${LOOP_DEV}p1
|
||||
PARTITION2=${LOOP_DEV}p2
|
||||
PARTITION3=${LOOP_DEV}p3
|
||||
|
||||
sudo mkfs.ext2 $PARTITION3 > /dev/null
|
||||
sudo mkfs.ext2 -d $SYSROOT $PARTITION2 > /dev/null
|
||||
sudo mkfs.ext2 -d $SYSROOT -b 1024 -q $PARTITION2
|
||||
|
||||
sudo mount $PARTITION2 $MOUNT_DIR
|
||||
sudo grub-install --no-floppy --target=i386-pc --modules="normal ext2 multiboot" --boot-directory=${MOUNT_DIR}/boot $LOOP_DEV > /dev/null
|
||||
sudo grub-install --no-floppy --target=i386-pc --modules="normal ext2 multiboot" --boot-directory=${MOUNT_DIR}/boot $LOOP_DEV
|
||||
sudo umount $MOUNT_DIR
|
||||
|
||||
sudo losetup -d $LOOP_DEV
|
||||
|
|
|
@ -148,6 +148,31 @@ namespace IDT
|
|||
pid_t tid = Kernel::Scheduler::current_tid();
|
||||
pid_t pid = tid ? Kernel::Process::current().pid() : 0;
|
||||
|
||||
if (tid)
|
||||
{
|
||||
auto start = Kernel::Thread::current().stack_base();
|
||||
auto end = start + Kernel::Thread::current().stack_size();
|
||||
if (interrupt_stack.rsp < start)
|
||||
derrorln("Stack overflow");
|
||||
if (interrupt_stack.rsp >= end)
|
||||
derrorln("Stack underflow");
|
||||
}
|
||||
|
||||
if (Kernel::PageTable::current().get_page_flags(interrupt_stack.rip & PAGE_ADDR_MASK) & Kernel::PageTable::Flags::Present)
|
||||
{
|
||||
uint8_t* machine_code = (uint8_t*)interrupt_stack.rip;
|
||||
dwarnln("While executing: {2H}{2H}{2H}{2H}{2H}{2H}{2H}{2H}",
|
||||
machine_code[0],
|
||||
machine_code[1],
|
||||
machine_code[2],
|
||||
machine_code[3],
|
||||
machine_code[4],
|
||||
machine_code[5],
|
||||
machine_code[6],
|
||||
machine_code[7]
|
||||
);
|
||||
}
|
||||
|
||||
dwarnln(
|
||||
"{} (error code: 0x{16H}), pid {}, tid {}\r\n"
|
||||
"Register dump\r\n"
|
||||
|
@ -161,6 +186,8 @@ namespace IDT
|
|||
regs->rip, regs->rflags,
|
||||
regs->cr0, regs->cr2, regs->cr3, regs->cr4
|
||||
);
|
||||
if (isr == ISR::PageFault)
|
||||
Kernel::PageTable::current().debug_dump();
|
||||
Debug::dump_stack_trace();
|
||||
|
||||
if (tid)
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
#pragma once
|
||||
|
||||
#include <BAN/HashMap.h>
|
||||
#include <kernel/Storage/StorageDevice.h>
|
||||
#include <kernel/FS/FileSystem.h>
|
||||
#include <kernel/FS/Ext2/Inode.h>
|
||||
|
@ -9,6 +10,37 @@ namespace Kernel
|
|||
|
||||
class Ext2FS final : public FileSystem
|
||||
{
|
||||
public:
|
||||
class BlockBufferWrapper
|
||||
{
|
||||
BAN_NON_COPYABLE(BlockBufferWrapper);
|
||||
BAN_NON_MOVABLE(BlockBufferWrapper);
|
||||
|
||||
public:
|
||||
BlockBufferWrapper(BAN::Span<uint8_t> buffer, bool& used)
|
||||
: m_buffer(buffer)
|
||||
, m_used(used)
|
||||
{
|
||||
ASSERT(m_used);
|
||||
}
|
||||
~BlockBufferWrapper()
|
||||
{
|
||||
m_used = false;
|
||||
}
|
||||
|
||||
size_t size() const { return m_buffer.size(); }
|
||||
|
||||
uint8_t* data() { return m_buffer.data(); }
|
||||
const uint8_t* data() const { return m_buffer.data(); }
|
||||
|
||||
uint8_t& operator[](size_t index) { return m_buffer[index]; }
|
||||
uint8_t operator[](size_t index) const { return m_buffer[index]; }
|
||||
|
||||
private:
|
||||
BAN::Span<uint8_t> m_buffer;
|
||||
bool& m_used;
|
||||
};
|
||||
|
||||
public:
|
||||
static BAN::ErrorOr<Ext2FS*> create(Partition&);
|
||||
|
||||
|
@ -26,12 +58,16 @@ namespace Kernel
|
|||
BAN::ErrorOr<void> delete_inode(uint32_t);
|
||||
BAN::ErrorOr<void> resize_inode(uint32_t, size_t);
|
||||
|
||||
void read_block(uint32_t, BAN::Span<uint8_t>);
|
||||
void write_block(uint32_t, BAN::Span<const uint8_t>);
|
||||
void read_block(uint32_t, BlockBufferWrapper&);
|
||||
void write_block(uint32_t, const BlockBufferWrapper&);
|
||||
void sync_superblock();
|
||||
|
||||
BlockBufferWrapper get_block_buffer();
|
||||
|
||||
BAN::ErrorOr<uint32_t> reserve_free_block(uint32_t primary_bgd);
|
||||
|
||||
BAN::HashMap<ino_t, BAN::RefPtr<Inode>>& inode_cache() { return m_inode_cache; }
|
||||
|
||||
const Ext2::Superblock& superblock() const { return m_superblock; }
|
||||
|
||||
struct BlockLocation
|
||||
|
@ -39,11 +75,30 @@ namespace Kernel
|
|||
uint32_t block;
|
||||
uint32_t offset;
|
||||
};
|
||||
BAN::ErrorOr<BlockLocation> locate_inode(uint32_t);
|
||||
BlockLocation locate_inode(uint32_t);
|
||||
BlockLocation locate_block_group_descriptior(uint32_t);
|
||||
|
||||
uint32_t block_size() const { return 1024 << superblock().log_block_size; }
|
||||
|
||||
class BlockBufferManager
|
||||
{
|
||||
public:
|
||||
BlockBufferManager() = default;
|
||||
BlockBufferWrapper get_buffer();
|
||||
|
||||
BAN::ErrorOr<void> initialize(size_t block_size);
|
||||
|
||||
private:
|
||||
struct BlockBuffer
|
||||
{
|
||||
BAN::Vector<uint8_t> buffer;
|
||||
bool used { false };
|
||||
};
|
||||
|
||||
private:
|
||||
BAN::Array<BlockBuffer, 10> m_buffers;
|
||||
};
|
||||
|
||||
private:
|
||||
RecursiveSpinLock m_lock;
|
||||
|
||||
|
@ -52,6 +107,10 @@ namespace Kernel
|
|||
BAN::RefPtr<Inode> m_root_inode;
|
||||
BAN::Vector<uint32_t> m_superblock_backups;
|
||||
|
||||
BAN::HashMap<ino_t, BAN::RefPtr<Inode>> m_inode_cache;
|
||||
|
||||
BlockBufferManager m_buffer_manager;
|
||||
|
||||
Ext2::Superblock m_superblock;
|
||||
|
||||
friend class Ext2Inode;
|
||||
|
|
|
@ -39,9 +39,8 @@ namespace Kernel
|
|||
virtual BAN::ErrorOr<void> truncate_impl(size_t) override;
|
||||
|
||||
private:
|
||||
BAN::ErrorOr<void> for_data_block_index(uint32_t, const BAN::Function<void(uint32_t&)>&, bool allocate);
|
||||
uint32_t fs_block_of_data_block_index(uint32_t data_block_index);
|
||||
|
||||
BAN::ErrorOr<uint32_t> data_block_index(uint32_t);
|
||||
BAN::ErrorOr<uint32_t> allocate_new_block();
|
||||
BAN::ErrorOr<void> sync();
|
||||
|
||||
|
|
|
@ -87,8 +87,9 @@ namespace Kernel
|
|||
BAN::ErrorOr<long> sys_getpgid(pid_t);
|
||||
|
||||
BAN::ErrorOr<void> create_file(BAN::StringView name, mode_t mode);
|
||||
BAN::ErrorOr<long> sys_open(BAN::StringView, int, mode_t = 0);
|
||||
BAN::ErrorOr<long> sys_openat(int, BAN::StringView, int, mode_t = 0);
|
||||
BAN::ErrorOr<long> open_file(BAN::StringView path, int, mode_t = 0);
|
||||
BAN::ErrorOr<long> sys_open(const char* path, int, mode_t);
|
||||
BAN::ErrorOr<long> sys_openat(int, const char* path, int, mode_t);
|
||||
BAN::ErrorOr<long> sys_close(int fd);
|
||||
BAN::ErrorOr<long> sys_read(int fd, void* buffer, size_t count);
|
||||
BAN::ErrorOr<long> sys_write(int fd, const void* buffer, size_t count);
|
||||
|
@ -112,7 +113,7 @@ namespace Kernel
|
|||
|
||||
BAN::ErrorOr<long> sys_read_dir_entries(int fd, DirectoryEntryList* buffer, size_t buffer_size);
|
||||
|
||||
BAN::ErrorOr<long> sys_mmap(const sys_mmap_t&);
|
||||
BAN::ErrorOr<long> sys_mmap(const sys_mmap_t*);
|
||||
BAN::ErrorOr<long> sys_munmap(void* addr, size_t len);
|
||||
|
||||
BAN::ErrorOr<long> sys_signal(int, void (*)(int));
|
||||
|
@ -121,9 +122,9 @@ namespace Kernel
|
|||
|
||||
BAN::ErrorOr<long> sys_tcsetpgrp(int fd, pid_t pgid);
|
||||
|
||||
BAN::ErrorOr<long> sys_termid(char*) const;
|
||||
BAN::ErrorOr<long> sys_termid(char*);
|
||||
|
||||
BAN::ErrorOr<long> sys_clock_gettime(clockid_t, timespec*) const;
|
||||
BAN::ErrorOr<long> sys_clock_gettime(clockid_t, timespec*);
|
||||
|
||||
TTY& tty() { ASSERT(m_controlling_terminal); return *m_controlling_terminal; }
|
||||
|
||||
|
@ -149,6 +150,9 @@ namespace Kernel
|
|||
|
||||
BAN::ErrorOr<BAN::String> absolute_path_of(BAN::StringView) const;
|
||||
|
||||
void validate_string_access(const char*);
|
||||
void validate_pointer_access(const void*, size_t);
|
||||
|
||||
private:
|
||||
struct ExitStatus
|
||||
{
|
||||
|
|
|
@ -90,16 +90,17 @@ namespace Kernel
|
|||
dprintln(" inodes/group {}", m_superblock.inodes_per_group);
|
||||
#endif
|
||||
|
||||
TRY(m_buffer_manager.initialize(block_size()));
|
||||
|
||||
{
|
||||
BAN::Vector<uint8_t> block_buffer;
|
||||
TRY(block_buffer.resize(block_size()));
|
||||
auto block_buffer = m_buffer_manager.get_buffer();
|
||||
|
||||
if (superblock().rev_level == Ext2::Enum::GOOD_OLD_REV)
|
||||
{
|
||||
// In revision 0 all blockgroups contain superblock backup
|
||||
TRY(m_superblock_backups.reserve(number_of_block_groups - 1));
|
||||
for (uint32_t i = 1; i < number_of_block_groups; i++)
|
||||
MUST(block_buffer.push_back(i));
|
||||
MUST(m_superblock_backups.push_back(i));
|
||||
}
|
||||
else
|
||||
{
|
||||
|
@ -118,7 +119,7 @@ namespace Kernel
|
|||
|
||||
for (uint32_t bg : m_superblock_backups)
|
||||
{
|
||||
read_block(superblock().first_data_block + superblock().blocks_per_group * bg, block_buffer.span());
|
||||
read_block(superblock().first_data_block + superblock().blocks_per_group * bg, block_buffer);
|
||||
Ext2::Superblock& superblock_backup = *(Ext2::Superblock*)block_buffer.data();
|
||||
if (superblock_backup.magic != Ext2::Enum::SUPER_MAGIC)
|
||||
derrorln("superblock backup at block {} is invalid ({4H})", bg, superblock_backup.magic);
|
||||
|
@ -145,11 +146,8 @@ namespace Kernel
|
|||
|
||||
const uint32_t block_size = this->block_size();
|
||||
|
||||
BAN::Vector<uint8_t> bgd_buffer;
|
||||
TRY(bgd_buffer.resize(block_size));
|
||||
|
||||
BAN::Vector<uint8_t> inode_bitmap;
|
||||
TRY(inode_bitmap.resize(block_size));
|
||||
auto bgd_buffer = m_buffer_manager.get_buffer();
|
||||
auto inode_bitmap = m_buffer_manager.get_buffer();
|
||||
|
||||
uint32_t current_group = -1;
|
||||
BlockLocation bgd_location {};
|
||||
|
@ -165,7 +163,7 @@ namespace Kernel
|
|||
current_group = ino_group;
|
||||
|
||||
bgd_location = locate_block_group_descriptior(current_group);
|
||||
read_block(bgd_location.block, bgd_buffer.span());
|
||||
read_block(bgd_location.block, bgd_buffer);
|
||||
|
||||
bgd = (Ext2::BlockGroupDescriptor*)(bgd_buffer.data() + bgd_location.offset);
|
||||
if (bgd->free_inodes_count == 0)
|
||||
|
@ -174,7 +172,7 @@ namespace Kernel
|
|||
continue;
|
||||
}
|
||||
|
||||
read_block(bgd->inode_bitmap, inode_bitmap.span());
|
||||
read_block(bgd->inode_bitmap, inode_bitmap);
|
||||
}
|
||||
|
||||
const uint32_t ino_bitmap_byte = ino_index / 8;
|
||||
|
@ -183,10 +181,10 @@ namespace Kernel
|
|||
continue;
|
||||
|
||||
inode_bitmap[ino_bitmap_byte] |= 1 << ino_bitmap_bit;
|
||||
write_block(bgd->inode_bitmap, inode_bitmap.span());
|
||||
write_block(bgd->inode_bitmap, inode_bitmap);
|
||||
|
||||
bgd->free_inodes_count--;
|
||||
write_block(bgd_location.block, bgd_buffer.span());
|
||||
write_block(bgd_location.block, bgd_buffer);
|
||||
|
||||
const uint32_t inode_table_offset = ino_index * superblock().inode_size;
|
||||
const BlockLocation inode_location
|
||||
|
@ -198,11 +196,11 @@ namespace Kernel
|
|||
// NOTE: we don't need inode bitmap anymore, so we can reuse it
|
||||
auto& inode_buffer = inode_bitmap;
|
||||
|
||||
read_block(inode_location.block, inode_buffer.span());
|
||||
read_block(inode_location.block, inode_buffer);
|
||||
memcpy(inode_buffer.data() + inode_location.offset, &ext2_inode, sizeof(Ext2::Inode));
|
||||
if (superblock().inode_size > sizeof(Ext2::Inode))
|
||||
memset(inode_buffer.data() + inode_location.offset + sizeof(Ext2::Inode), 0, superblock().inode_size - sizeof(Ext2::Inode));
|
||||
write_block(inode_location.block, inode_buffer.span());
|
||||
write_block(inode_location.block, inode_buffer);
|
||||
|
||||
m_superblock.free_inodes_count--;
|
||||
sync_superblock();
|
||||
|
@ -214,7 +212,7 @@ namespace Kernel
|
|||
return BAN::Error::from_error_code(ErrorCode::Ext2_Corrupted);
|
||||
}
|
||||
|
||||
void Ext2FS::read_block(uint32_t block, BAN::Span<uint8_t> buffer)
|
||||
void Ext2FS::read_block(uint32_t block, BlockBufferWrapper& buffer)
|
||||
{
|
||||
LockGuard _(m_lock);
|
||||
|
||||
|
@ -228,7 +226,7 @@ namespace Kernel
|
|||
MUST(m_partition.read_sectors(sectors_before + (block - 2) * sectors_per_block, sectors_per_block, buffer.data()));
|
||||
}
|
||||
|
||||
void Ext2FS::write_block(uint32_t block, BAN::Span<const uint8_t> buffer)
|
||||
void Ext2FS::write_block(uint32_t block, const BlockBufferWrapper& buffer)
|
||||
{
|
||||
LockGuard _(m_lock);
|
||||
|
||||
|
@ -268,6 +266,13 @@ namespace Kernel
|
|||
}
|
||||
}
|
||||
|
||||
|
||||
Ext2FS::BlockBufferWrapper Ext2FS::get_block_buffer()
|
||||
{
|
||||
LockGuard _(m_lock);
|
||||
return m_buffer_manager.get_buffer();
|
||||
}
|
||||
|
||||
BAN::ErrorOr<uint32_t> Ext2FS::reserve_free_block(uint32_t primary_bgd)
|
||||
{
|
||||
LockGuard _(m_lock);
|
||||
|
@ -275,25 +280,20 @@ namespace Kernel
|
|||
if (m_superblock.r_blocks_count >= m_superblock.free_blocks_count)
|
||||
return BAN::Error::from_errno(ENOSPC);
|
||||
|
||||
const uint32_t block_size = this->block_size();
|
||||
|
||||
BAN::Vector<uint8_t> bgd_buffer;
|
||||
TRY(bgd_buffer.resize(block_size));
|
||||
|
||||
BAN::Vector<uint8_t> block_bitmap;
|
||||
TRY(block_bitmap.resize(block_size));
|
||||
auto bgd_buffer = m_buffer_manager.get_buffer();
|
||||
auto block_bitmap = m_buffer_manager.get_buffer();
|
||||
|
||||
auto check_block_group =
|
||||
[&](uint32_t block_group) -> uint32_t
|
||||
{
|
||||
auto bgd_location = locate_block_group_descriptior(block_group);
|
||||
read_block(bgd_location.block, bgd_buffer.span());
|
||||
read_block(bgd_location.block, bgd_buffer);
|
||||
|
||||
auto& bgd = *(Ext2::BlockGroupDescriptor*)(bgd_buffer.data() + bgd_location.offset);
|
||||
if (bgd.free_blocks_count == 0)
|
||||
return 0;
|
||||
|
||||
read_block(bgd.block_bitmap, block_bitmap.span());
|
||||
read_block(bgd.block_bitmap, block_bitmap);
|
||||
for (uint32_t block_offset = 0; block_offset < m_superblock.blocks_per_group; block_offset++)
|
||||
{
|
||||
const uint32_t fs_block_index = m_superblock.first_data_block + m_superblock.blocks_per_group * block_group + block_offset;
|
||||
|
@ -306,10 +306,10 @@ namespace Kernel
|
|||
continue;
|
||||
|
||||
block_bitmap[byte] |= 1 << bit;
|
||||
write_block(bgd.block_bitmap, block_bitmap.span());
|
||||
write_block(bgd.block_bitmap, block_bitmap);
|
||||
|
||||
bgd.free_blocks_count--;
|
||||
write_block(bgd_location.block, bgd_buffer.span());
|
||||
write_block(bgd_location.block, bgd_buffer);
|
||||
|
||||
m_superblock.free_blocks_count--;
|
||||
sync_superblock();
|
||||
|
@ -334,7 +334,7 @@ namespace Kernel
|
|||
return BAN::Error::from_error_code(ErrorCode::Ext2_Corrupted);
|
||||
}
|
||||
|
||||
BAN::ErrorOr<Ext2FS::BlockLocation> Ext2FS::locate_inode(uint32_t ino)
|
||||
Ext2FS::BlockLocation Ext2FS::locate_inode(uint32_t ino)
|
||||
{
|
||||
LockGuard _(m_lock);
|
||||
|
||||
|
@ -342,15 +342,14 @@ namespace Kernel
|
|||
|
||||
const uint32_t block_size = this->block_size();
|
||||
|
||||
BAN::Vector<uint8_t> bgd_buffer;
|
||||
TRY(bgd_buffer.resize(block_size));
|
||||
auto bgd_buffer = m_buffer_manager.get_buffer();
|
||||
|
||||
const uint32_t inode_group = (ino - 1) / superblock().inodes_per_group;
|
||||
const uint32_t inode_index = (ino - 1) % superblock().inodes_per_group;
|
||||
|
||||
auto bgd_location = locate_block_group_descriptior(inode_group);
|
||||
|
||||
read_block(bgd_location.block, bgd_buffer.span());
|
||||
read_block(bgd_location.block, bgd_buffer);
|
||||
|
||||
auto& bgd = *(Ext2::BlockGroupDescriptor*)(bgd_buffer.data() + bgd_location.offset);
|
||||
|
||||
|
@ -397,4 +396,26 @@ namespace Kernel
|
|||
};
|
||||
}
|
||||
|
||||
Ext2FS::BlockBufferWrapper Ext2FS::BlockBufferManager::get_buffer()
|
||||
{
|
||||
for (auto& buffer : m_buffers)
|
||||
{
|
||||
if (buffer.used)
|
||||
continue;
|
||||
buffer.used = true;
|
||||
return Ext2FS::BlockBufferWrapper(buffer.buffer.span(), buffer.used);
|
||||
}
|
||||
ASSERT_NOT_REACHED();
|
||||
}
|
||||
|
||||
BAN::ErrorOr<void> Ext2FS::BlockBufferManager::initialize(size_t block_size)
|
||||
{
|
||||
for (auto& buffer : m_buffers)
|
||||
{
|
||||
TRY(buffer.buffer.resize(block_size));
|
||||
buffer.used = false;
|
||||
}
|
||||
return {};
|
||||
}
|
||||
|
||||
}
|
|
@ -23,141 +23,74 @@ namespace Kernel
|
|||
|
||||
BAN::ErrorOr<BAN::RefPtr<Inode>> Ext2Inode::create(Ext2FS& fs, uint32_t inode_ino)
|
||||
{
|
||||
auto inode_location = TRY(fs.locate_inode(inode_ino));
|
||||
if (fs.inode_cache().contains(inode_ino))
|
||||
return fs.inode_cache()[inode_ino];
|
||||
|
||||
BAN::Vector<uint8_t> block_buffer;
|
||||
TRY(block_buffer.resize(fs.block_size()));
|
||||
auto inode_location = fs.locate_inode(inode_ino);
|
||||
|
||||
fs.read_block(inode_location.block, block_buffer.span());
|
||||
auto block_buffer = fs.get_block_buffer();
|
||||
fs.read_block(inode_location.block, block_buffer);
|
||||
|
||||
auto& inode = *(Ext2::Inode*)(block_buffer.data() + inode_location.offset);
|
||||
|
||||
Ext2Inode* result = new Ext2Inode(fs, inode, inode_ino);
|
||||
if (result == nullptr)
|
||||
Ext2Inode* result_ptr = new Ext2Inode(fs, inode, inode_ino);
|
||||
if (result_ptr == nullptr)
|
||||
return BAN::Error::from_errno(ENOMEM);
|
||||
return BAN::RefPtr<Inode>::adopt(result);
|
||||
auto result = BAN::RefPtr<Inode>::adopt(result_ptr);
|
||||
TRY(fs.inode_cache().insert(inode_ino, result));
|
||||
return result;
|
||||
}
|
||||
|
||||
#define READ_INDIRECT(block, container) \
|
||||
if (block) \
|
||||
m_fs.read_block(block, block_buffer.span()); \
|
||||
else \
|
||||
{ \
|
||||
if (!allocate) \
|
||||
return BAN::Error::from_error_code(ErrorCode::Ext2_Corrupted); \
|
||||
memset(block_buffer.data(), 0, block_size); \
|
||||
block = TRY(m_fs.reserve_free_block(block_group())); \
|
||||
m_fs.write_block(container, block_buffer.span()); \
|
||||
}
|
||||
#define VERIFY_AND_READ_BLOCK(expr) do { const uint32_t block_index = expr; ASSERT(block_index); m_fs.read_block(block_index, block_buffer); } while (false)
|
||||
#define VERIFY_AND_RETURN(expr) ({ const uint32_t result = expr; ASSERT(result); return result; })
|
||||
|
||||
#define READ_INDIRECT_TOP(block) \
|
||||
if (block) \
|
||||
m_fs.read_block(block, block_buffer.span()); \
|
||||
else \
|
||||
{ \
|
||||
if (!allocate) \
|
||||
return BAN::Error::from_error_code(ErrorCode::Ext2_Corrupted); \
|
||||
memset(block_buffer.data(), 0, block_size); \
|
||||
block = TRY(m_fs.reserve_free_block(block_group())); \
|
||||
}
|
||||
|
||||
BAN::ErrorOr<void> Ext2Inode::for_data_block_index(uint32_t asked_data_block, const BAN::Function<void(uint32_t&)>& callback, bool allocate)
|
||||
uint32_t Ext2Inode::fs_block_of_data_block_index(uint32_t data_block_index)
|
||||
{
|
||||
const uint32_t block_size = blksize();
|
||||
const uint32_t data_blocks_count = blocks();
|
||||
const uint32_t blocks_per_array = block_size / sizeof(uint32_t);
|
||||
ASSERT(data_block_index < blocks());
|
||||
|
||||
ASSERT(asked_data_block < data_blocks_count);
|
||||
const uint32_t indices_per_block = blksize() / sizeof(uint32_t);
|
||||
|
||||
// Direct block
|
||||
if (asked_data_block < 12)
|
||||
{
|
||||
uint32_t& block = m_inode.block[asked_data_block];
|
||||
uint32_t block_copy = block;
|
||||
callback(block);
|
||||
if (data_block_index < 12)
|
||||
VERIFY_AND_RETURN(m_inode.block[data_block_index]);
|
||||
|
||||
if (block != block_copy)
|
||||
TRY(sync());
|
||||
data_block_index -= 12;
|
||||
|
||||
return {};
|
||||
}
|
||||
|
||||
asked_data_block -= 12;
|
||||
|
||||
BAN::Vector<uint8_t> block_buffer;
|
||||
TRY(block_buffer.resize(block_size));
|
||||
auto block_buffer = m_fs.get_block_buffer();
|
||||
|
||||
// Singly indirect block
|
||||
if (asked_data_block < blocks_per_array)
|
||||
if (data_block_index < indices_per_block)
|
||||
{
|
||||
READ_INDIRECT_TOP(m_inode.block[12]);
|
||||
|
||||
uint32_t& block = ((uint32_t*)block_buffer.data())[asked_data_block];
|
||||
uint32_t block_copy = block;
|
||||
callback(block);
|
||||
|
||||
if (block != block_copy)
|
||||
m_fs.write_block(m_inode.block[12], block_buffer.span());
|
||||
|
||||
return {};
|
||||
VERIFY_AND_READ_BLOCK(m_inode.block[12]);
|
||||
VERIFY_AND_RETURN(((uint32_t*)block_buffer.data())[data_block_index]);
|
||||
}
|
||||
|
||||
asked_data_block -= blocks_per_array;
|
||||
data_block_index -= indices_per_block;
|
||||
|
||||
// Doubly indirect blocks
|
||||
if (asked_data_block < blocks_per_array * blocks_per_array)
|
||||
if (data_block_index < indices_per_block * indices_per_block)
|
||||
{
|
||||
READ_INDIRECT_TOP(m_inode.block[13]);
|
||||
|
||||
uint32_t& direct_block = ((uint32_t*)block_buffer.data())[asked_data_block / blocks_per_array];
|
||||
READ_INDIRECT(direct_block, m_inode.block[13]);
|
||||
|
||||
uint32_t& block = ((uint32_t*)block_buffer.data())[asked_data_block % blocks_per_array];
|
||||
uint32_t block_copy = block;
|
||||
callback(block);
|
||||
|
||||
if (block != block_copy)
|
||||
m_fs.write_block(direct_block, block_buffer.span());
|
||||
|
||||
return {};
|
||||
VERIFY_AND_READ_BLOCK(m_inode.block[13]);
|
||||
VERIFY_AND_READ_BLOCK(((uint32_t*)block_buffer.data())[data_block_index / indices_per_block]);
|
||||
VERIFY_AND_RETURN(((uint32_t*)block_buffer.data())[data_block_index % indices_per_block]);
|
||||
}
|
||||
|
||||
asked_data_block -= blocks_per_array * blocks_per_array;
|
||||
data_block_index -= indices_per_block * indices_per_block;
|
||||
|
||||
// Triply indirect blocks
|
||||
if (asked_data_block < blocks_per_array * blocks_per_array * blocks_per_array)
|
||||
if (data_block_index < indices_per_block * indices_per_block * indices_per_block)
|
||||
{
|
||||
READ_INDIRECT_TOP(m_inode.block[14]);
|
||||
|
||||
uint32_t& doubly_indirect_block = ((uint32_t*)block_buffer.data())[asked_data_block / (blocks_per_array * blocks_per_array)];
|
||||
READ_INDIRECT(doubly_indirect_block, m_inode.block[14]);
|
||||
|
||||
uint32_t& singly_direct_block = ((uint32_t*)block_buffer.data())[(asked_data_block / blocks_per_array) % blocks_per_array];
|
||||
READ_INDIRECT(singly_direct_block, doubly_indirect_block);
|
||||
|
||||
uint32_t& block = ((uint32_t*)block_buffer.data())[asked_data_block % blocks_per_array];
|
||||
uint32_t block_copy = block;
|
||||
callback(block);
|
||||
|
||||
if (block != block_copy)
|
||||
m_fs.write_block(singly_direct_block, block_buffer.span());
|
||||
|
||||
return {};
|
||||
VERIFY_AND_READ_BLOCK(m_inode.block[14]);
|
||||
VERIFY_AND_READ_BLOCK(((uint32_t*)block_buffer.data())[data_block_index / (indices_per_block * indices_per_block)]);
|
||||
VERIFY_AND_READ_BLOCK(((uint32_t*)block_buffer.data())[(data_block_index / indices_per_block) % indices_per_block]);
|
||||
VERIFY_AND_RETURN(((uint32_t*)block_buffer.data())[data_block_index % indices_per_block]);
|
||||
}
|
||||
|
||||
ASSERT_NOT_REACHED();
|
||||
}
|
||||
|
||||
#undef READ_INDIRECT
|
||||
#undef READ_INDIRECT_TOP
|
||||
|
||||
BAN::ErrorOr<uint32_t> Ext2Inode::data_block_index(uint32_t asked_data_block)
|
||||
{
|
||||
uint32_t result;
|
||||
TRY(for_data_block_index(asked_data_block, [&result] (uint32_t& index) { result = index; }, false));
|
||||
ASSERT(result != 0);
|
||||
return result;
|
||||
}
|
||||
#undef VERIFY_AND_READ_BLOCK
|
||||
#undef VERIFY_AND_RETURN
|
||||
|
||||
BAN::ErrorOr<BAN::String> Ext2Inode::link_target_impl()
|
||||
{
|
||||
|
@ -184,18 +117,17 @@ namespace Kernel
|
|||
|
||||
const uint32_t block_size = blksize();
|
||||
|
||||
BAN::Vector<uint8_t> block_buffer;
|
||||
TRY(block_buffer.resize(block_size));
|
||||
auto block_buffer = m_fs.get_block_buffer();
|
||||
|
||||
const uint32_t first_block = offset / block_size;
|
||||
const uint32_t last_block = BAN::Math::div_round_up<uint32_t>(offset + count, block_size);
|
||||
|
||||
size_t n_read = 0;
|
||||
|
||||
for (uint32_t block = first_block; block < last_block; block++)
|
||||
for (uint32_t data_block_index = first_block; data_block_index < last_block; data_block_index++)
|
||||
{
|
||||
uint32_t block_index = TRY(data_block_index(block));
|
||||
m_fs.read_block(block_index, block_buffer.span());
|
||||
uint32_t block_index = fs_block_of_data_block_index(data_block_index);
|
||||
m_fs.read_block(block_index, block_buffer);
|
||||
|
||||
uint32_t copy_offset = (offset + n_read) % block_size;
|
||||
uint32_t to_copy = BAN::Math::min<uint32_t>(block_size - copy_offset, count - n_read);
|
||||
|
@ -222,8 +154,7 @@ namespace Kernel
|
|||
|
||||
const uint32_t block_size = blksize();
|
||||
|
||||
BAN::Vector<uint8_t> block_buffer;
|
||||
TRY(block_buffer.resize(block_size));
|
||||
auto block_buffer = m_fs.get_block_buffer();
|
||||
|
||||
const uint8_t* u8buffer = (const uint8_t*)buffer;
|
||||
|
||||
|
@ -232,15 +163,14 @@ namespace Kernel
|
|||
// Write partial block
|
||||
if (offset % block_size)
|
||||
{
|
||||
uint32_t block_index = offset / block_size;
|
||||
uint32_t block_index = fs_block_of_data_block_index(offset / block_size);
|
||||
uint32_t block_offset = offset % block_size;
|
||||
|
||||
uint32_t data_block_index = TRY(this->data_block_index(block_index));
|
||||
uint32_t to_copy = BAN::Math::min<uint32_t>(block_size - block_offset, to_write);
|
||||
|
||||
m_fs.read_block(data_block_index, block_buffer.span());
|
||||
memcpy(block_buffer.data() + block_offset, buffer, to_copy);
|
||||
m_fs.write_block(data_block_index, block_buffer.span());
|
||||
m_fs.read_block(block_index, block_buffer);
|
||||
memcpy(block_buffer.data() + block_offset, u8buffer, to_copy);
|
||||
m_fs.write_block(block_index, block_buffer);
|
||||
|
||||
u8buffer += to_copy;
|
||||
offset += to_copy;
|
||||
|
@ -249,9 +179,10 @@ namespace Kernel
|
|||
|
||||
while (to_write >= block_size)
|
||||
{
|
||||
uint32_t data_block_index = TRY(this->data_block_index(offset / block_size));
|
||||
uint32_t block_index = fs_block_of_data_block_index(offset / block_size);
|
||||
|
||||
m_fs.write_block(data_block_index, BAN::Span<const uint8_t>(u8buffer, block_size));
|
||||
memcpy(block_buffer.data(), u8buffer, block_buffer.size());
|
||||
m_fs.write_block(block_index, block_buffer);
|
||||
|
||||
u8buffer += block_size;
|
||||
offset += block_size;
|
||||
|
@ -260,11 +191,11 @@ namespace Kernel
|
|||
|
||||
if (to_write > 0)
|
||||
{
|
||||
uint32_t data_block_index = TRY(this->data_block_index(offset / block_size));
|
||||
uint32_t block_index = fs_block_of_data_block_index(offset / block_size);
|
||||
|
||||
m_fs.read_block(data_block_index, block_buffer.span());
|
||||
m_fs.read_block(block_index, block_buffer);
|
||||
memcpy(block_buffer.data(), u8buffer, to_write);
|
||||
m_fs.write_block(data_block_index, block_buffer.span());
|
||||
m_fs.write_block(block_index, block_buffer);
|
||||
}
|
||||
|
||||
return count;
|
||||
|
@ -286,23 +217,22 @@ namespace Kernel
|
|||
return {};
|
||||
}
|
||||
|
||||
BAN::Vector<uint8_t> block_buffer;
|
||||
TRY(block_buffer.resize(block_size));
|
||||
auto block_buffer = m_fs.get_block_buffer();
|
||||
|
||||
if (uint32_t rem = m_inode.size % block_size)
|
||||
{
|
||||
uint32_t last_block_index = TRY(data_block_index(current_data_blocks - 1));
|
||||
uint32_t last_block_index = fs_block_of_data_block_index(current_data_blocks - 1);
|
||||
|
||||
m_fs.read_block(last_block_index, block_buffer.span());
|
||||
m_fs.read_block(last_block_index, block_buffer);
|
||||
memset(block_buffer.data() + rem, 0, block_size - rem);
|
||||
m_fs.write_block(last_block_index, block_buffer.span());
|
||||
m_fs.write_block(last_block_index, block_buffer);
|
||||
}
|
||||
|
||||
memset(block_buffer.data(), 0, block_size);
|
||||
while (blocks() < needed_data_blocks)
|
||||
{
|
||||
uint32_t block_index = TRY(allocate_new_block());
|
||||
m_fs.write_block(block_index, block_buffer.span());
|
||||
m_fs.write_block(block_index, block_buffer);
|
||||
}
|
||||
|
||||
m_inode.size = new_size;
|
||||
|
@ -324,12 +254,11 @@ namespace Kernel
|
|||
}
|
||||
|
||||
const uint32_t block_size = blksize();
|
||||
const uint32_t block_index = TRY(data_block_index(offset));
|
||||
const uint32_t block_index = fs_block_of_data_block_index(offset);
|
||||
|
||||
BAN::Vector<uint8_t> block_buffer;
|
||||
TRY(block_buffer.resize(block_size));
|
||||
auto block_buffer = m_fs.get_block_buffer();
|
||||
|
||||
m_fs.read_block(block_index, block_buffer.span());
|
||||
m_fs.read_block(block_index, block_buffer);
|
||||
|
||||
// First determine if we have big enough list
|
||||
{
|
||||
|
@ -426,8 +355,8 @@ namespace Kernel
|
|||
const uint32_t inode_index = TRY(m_fs.create_inode(ext2_inode));
|
||||
|
||||
const uint32_t block_size = m_fs.block_size();
|
||||
BAN::Vector<uint8_t> block_buffer;
|
||||
TRY(block_buffer.resize(block_size));
|
||||
|
||||
auto block_buffer = m_fs.get_block_buffer();
|
||||
|
||||
auto write_inode = [&](uint32_t entry_offset, uint32_t entry_rec_len)
|
||||
{
|
||||
|
@ -462,8 +391,8 @@ namespace Kernel
|
|||
goto needs_new_block;
|
||||
|
||||
// Try to insert inode to last data block
|
||||
block_index = TRY(data_block_index(data_block_count - 1));
|
||||
m_fs.read_block(block_index, block_buffer.span());
|
||||
block_index = fs_block_of_data_block_index(data_block_count - 1);
|
||||
m_fs.read_block(block_index, block_buffer);
|
||||
|
||||
while (entry_offset < block_size)
|
||||
{
|
||||
|
@ -476,7 +405,7 @@ namespace Kernel
|
|||
if (entry.inode == 0 && needed_entry_len <= entry.rec_len)
|
||||
{
|
||||
write_inode(entry_offset, entry.rec_len);
|
||||
m_fs.write_block(block_index, block_buffer.span());
|
||||
m_fs.write_block(block_index, block_buffer);
|
||||
return {};
|
||||
}
|
||||
else if (needed_entry_len <= entry.rec_len - entry_min_rec_len)
|
||||
|
@ -485,7 +414,7 @@ namespace Kernel
|
|||
entry.rec_len = entry_min_rec_len;
|
||||
|
||||
write_inode(entry_offset + entry.rec_len, new_rec_len);
|
||||
m_fs.write_block(block_index, block_buffer.span());
|
||||
m_fs.write_block(block_index, block_buffer);
|
||||
return {};
|
||||
}
|
||||
|
||||
|
@ -495,55 +424,132 @@ namespace Kernel
|
|||
needs_new_block:
|
||||
block_index = TRY(allocate_new_block());
|
||||
|
||||
m_fs.read_block(block_index, block_buffer.span());
|
||||
m_fs.read_block(block_index, block_buffer);
|
||||
write_inode(0, block_size);
|
||||
m_fs.write_block(block_index, block_buffer.span());
|
||||
m_fs.write_block(block_index, block_buffer);
|
||||
|
||||
return {};
|
||||
}
|
||||
|
||||
#define READ_OR_ALLOCATE_BASE_BLOCK(index_) \
|
||||
do { \
|
||||
if (m_inode.block[index_] != 0) \
|
||||
m_fs.read_block(m_inode.block[index_], block_buffer); \
|
||||
else \
|
||||
{ \
|
||||
m_inode.block[index_] = TRY(m_fs.reserve_free_block(block_group())); \
|
||||
memset(block_buffer.data(), 0x00, block_buffer.size()); \
|
||||
} \
|
||||
} while (false)
|
||||
|
||||
#define READ_OR_ALLOCATE_INDIRECT_BLOCK(result_, buffer_index_, parent_block_) \
|
||||
uint32_t result_ = ((uint32_t*)block_buffer.data())[buffer_index_]; \
|
||||
if (result_ != 0) \
|
||||
m_fs.read_block(result_, block_buffer); \
|
||||
else \
|
||||
{ \
|
||||
const uint32_t new_block_ = TRY(m_fs.reserve_free_block(block_group())); \
|
||||
\
|
||||
((uint32_t*)block_buffer.data())[buffer_index_] = new_block_; \
|
||||
m_fs.write_block(parent_block_, block_buffer); \
|
||||
\
|
||||
result_ = new_block_; \
|
||||
memset(block_buffer.data(), 0x00, block_buffer.size()); \
|
||||
} \
|
||||
do {} while (false)
|
||||
|
||||
#define WRITE_BLOCK_AND_RETURN(buffer_index_, parent_block_) \
|
||||
do { \
|
||||
const uint32_t block_ = TRY(m_fs.reserve_free_block(block_group())); \
|
||||
\
|
||||
ASSERT(((uint32_t*)block_buffer.data())[buffer_index_] == 0); \
|
||||
((uint32_t*)block_buffer.data())[buffer_index_] = block_; \
|
||||
m_fs.write_block(parent_block_, block_buffer); \
|
||||
\
|
||||
m_inode.blocks += blocks_per_fs_block; \
|
||||
update_and_sync(); \
|
||||
\
|
||||
return block_; \
|
||||
} while (false)
|
||||
|
||||
BAN::ErrorOr<uint32_t> Ext2Inode::allocate_new_block()
|
||||
{
|
||||
uint32_t new_block_index = TRY(m_fs.reserve_free_block(block_group()));
|
||||
auto set_index_func = [new_block_index] (uint32_t& index) { index = new_block_index; };
|
||||
const uint32_t blocks_per_fs_block = blksize() / 512;
|
||||
const uint32_t indices_per_fs_block = blksize() / sizeof(uint32_t);
|
||||
|
||||
const uint32_t blocks_per_data_block = blksize() / 512;
|
||||
uint32_t block_array_index = blocks();
|
||||
|
||||
m_inode.blocks += blocks_per_data_block;
|
||||
if (auto res = for_data_block_index(blocks() - 1, set_index_func, true); res.is_error())
|
||||
auto update_and_sync =
|
||||
[&]
|
||||
{
|
||||
m_inode.blocks -= blocks_per_data_block;
|
||||
return res.release_error();
|
||||
}
|
||||
|
||||
if (mode().ifdir())
|
||||
m_inode.size += blksize();
|
||||
MUST(sync());
|
||||
};
|
||||
|
||||
TRY(sync());
|
||||
return new_block_index;
|
||||
// direct block
|
||||
if (block_array_index < 12)
|
||||
{
|
||||
const uint32_t block = TRY(m_fs.reserve_free_block(block_group()));
|
||||
|
||||
ASSERT(m_inode.block[block_array_index] == 0);
|
||||
m_inode.block[block_array_index] = block;
|
||||
|
||||
m_inode.blocks += blocks_per_fs_block;
|
||||
update_and_sync();
|
||||
return block;
|
||||
}
|
||||
|
||||
block_array_index -= 12;
|
||||
|
||||
auto block_buffer = m_fs.get_block_buffer();
|
||||
|
||||
// singly indirect block
|
||||
if (block_array_index < indices_per_fs_block)
|
||||
{
|
||||
READ_OR_ALLOCATE_BASE_BLOCK(12);
|
||||
WRITE_BLOCK_AND_RETURN(block_array_index, m_inode.block[12]);
|
||||
}
|
||||
|
||||
block_array_index -= indices_per_fs_block;
|
||||
|
||||
// doubly indirect block
|
||||
if (block_array_index < indices_per_fs_block * indices_per_fs_block)
|
||||
{
|
||||
READ_OR_ALLOCATE_BASE_BLOCK(13);
|
||||
READ_OR_ALLOCATE_INDIRECT_BLOCK(direct_block, block_array_index / indices_per_fs_block, m_inode.block[13]);
|
||||
WRITE_BLOCK_AND_RETURN(block_array_index % indices_per_fs_block, direct_block);
|
||||
}
|
||||
|
||||
block_array_index -= indices_per_fs_block * indices_per_fs_block;
|
||||
|
||||
// triply indirect block
|
||||
if (block_array_index < indices_per_fs_block * indices_per_fs_block * indices_per_fs_block)
|
||||
{
|
||||
dwarnln("here");
|
||||
READ_OR_ALLOCATE_BASE_BLOCK(14);
|
||||
READ_OR_ALLOCATE_INDIRECT_BLOCK(indirect_block, block_array_index / (indices_per_fs_block * indices_per_fs_block), 14);
|
||||
READ_OR_ALLOCATE_INDIRECT_BLOCK(direct_block, (block_array_index / indices_per_fs_block) % indices_per_fs_block, indirect_block);
|
||||
WRITE_BLOCK_AND_RETURN(block_array_index % indices_per_fs_block, direct_block);
|
||||
}
|
||||
|
||||
ASSERT_NOT_REACHED();
|
||||
}
|
||||
|
||||
#undef READ_OR_ALLOCATE_BASE_BLOCK
|
||||
#undef READ_OR_ALLOCATE_INDIRECT_BLOCK
|
||||
#undef WRITE_BLOCK_AND_RETURN
|
||||
|
||||
BAN::ErrorOr<void> Ext2Inode::sync()
|
||||
{
|
||||
auto inode_location_or_error = m_fs.locate_inode(ino());
|
||||
if (inode_location_or_error.is_error())
|
||||
{
|
||||
dwarnln("Open inode not found from filesystem");
|
||||
return BAN::Error::from_error_code(ErrorCode::Ext2_Corrupted);
|
||||
}
|
||||
auto inode_location = m_fs.locate_inode(ino());
|
||||
auto block_buffer = m_fs.get_block_buffer();
|
||||
|
||||
auto inode_location = inode_location_or_error.release_value();
|
||||
|
||||
const uint32_t block_size = blksize();
|
||||
|
||||
BAN::Vector<uint8_t> block_buffer;
|
||||
TRY(block_buffer.resize(block_size));
|
||||
|
||||
m_fs.read_block(inode_location.block, block_buffer.span());
|
||||
m_fs.read_block(inode_location.block, block_buffer);
|
||||
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));
|
||||
m_fs.write_block(inode_location.block, block_buffer.span());
|
||||
m_fs.write_block(inode_location.block, block_buffer);
|
||||
}
|
||||
|
||||
return {};
|
||||
|
@ -556,13 +562,12 @@ needs_new_block:
|
|||
const uint32_t block_size = blksize();
|
||||
const uint32_t data_block_count = blocks();
|
||||
|
||||
BAN::Vector<uint8_t> block_buffer;
|
||||
TRY(block_buffer.resize(block_size));
|
||||
auto block_buffer = m_fs.get_block_buffer();
|
||||
|
||||
for (uint32_t i = 0; i < data_block_count; i++)
|
||||
{
|
||||
const uint32_t block_index = TRY(data_block_index(i));
|
||||
m_fs.read_block(block_index, block_buffer.span());
|
||||
const uint32_t block_index = fs_block_of_data_block_index(i);
|
||||
m_fs.read_block(block_index, block_buffer);
|
||||
|
||||
const uint8_t* block_buffer_end = block_buffer.data() + block_size;
|
||||
const uint8_t* entry_addr = block_buffer.data();
|
||||
|
|
|
@ -2,6 +2,7 @@
|
|||
#include <BAN/ScopeGuard.h>
|
||||
#include <BAN/UTF8.h>
|
||||
#include <kernel/Font.h>
|
||||
#include <kernel/FS/VirtualFileSystem.h>
|
||||
#include <kernel/Process.h>
|
||||
|
||||
#include <fcntl.h>
|
||||
|
@ -37,15 +38,12 @@ namespace Kernel
|
|||
|
||||
BAN::ErrorOr<Font> Font::load(BAN::StringView path)
|
||||
{
|
||||
int fd = TRY(Process::current().sys_open(path, O_RDONLY));
|
||||
BAN::ScopeGuard _([fd] { MUST(Process::current().sys_close(fd)); });
|
||||
|
||||
struct stat st;
|
||||
TRY(Process::current().sys_fstat(fd, &st));
|
||||
auto inode = TRY(VirtualFileSystem::get().file_from_absolute_path({ 0, 0, 0, 0 }, path, O_RDONLY)).inode;
|
||||
|
||||
BAN::Vector<uint8_t> file_data;
|
||||
TRY(file_data.resize(st.st_size));
|
||||
TRY(Process::current().sys_read(fd, file_data.data(), st.st_size));
|
||||
TRY(file_data.resize(inode->size()));
|
||||
|
||||
inode->read(0, file_data.data(), file_data.size());
|
||||
|
||||
if (file_data.size() < 4)
|
||||
return BAN::Error::from_error_code(ErrorCode::Font_FileTooSmall);
|
||||
|
|
|
@ -12,9 +12,7 @@ extern uint8_t g_kernel_end[];
|
|||
|
||||
static constexpr size_t s_kmalloc_min_align = alignof(max_align_t);
|
||||
|
||||
static uint8_t s_kmalloc_storage[2 * MB];
|
||||
|
||||
static BAN::UniqPtr<Kernel::GeneralAllocator> s_general_allocator;
|
||||
static uint8_t s_kmalloc_storage[20 * MB];
|
||||
|
||||
struct kmalloc_node
|
||||
{
|
||||
|
@ -303,19 +301,6 @@ void* kmalloc(size_t size, size_t align, bool force_indentity_map)
|
|||
|
||||
Kernel::CriticalScope critical;
|
||||
|
||||
// FIXME: this is a hack to make more dynamic kmalloc memory
|
||||
if (size > PAGE_SIZE && !force_indentity_map)
|
||||
{
|
||||
using namespace Kernel;
|
||||
|
||||
if (!s_general_allocator)
|
||||
s_general_allocator = MUST(GeneralAllocator::create(PageTable::kernel(), (vaddr_t)g_kernel_end));
|
||||
|
||||
auto vaddr = s_general_allocator->allocate(size);
|
||||
if (vaddr)
|
||||
return (void*)vaddr;
|
||||
}
|
||||
|
||||
if (size == 0 || size >= info.size)
|
||||
goto no_memory;
|
||||
|
||||
|
@ -350,9 +335,6 @@ void kfree(void* address)
|
|||
|
||||
Kernel::CriticalScope critical;
|
||||
|
||||
if (s_general_allocator && s_general_allocator->deallocate((Kernel::vaddr_t)address))
|
||||
return;
|
||||
|
||||
if (s_kmalloc_fixed_info.base <= address_uint && address_uint < s_kmalloc_fixed_info.end)
|
||||
{
|
||||
auto& info = s_kmalloc_fixed_info;
|
||||
|
@ -414,13 +396,6 @@ BAN::Optional<Kernel::paddr_t> kmalloc_paddr_of(Kernel::vaddr_t vaddr)
|
|||
{
|
||||
using namespace Kernel;
|
||||
|
||||
if (s_general_allocator)
|
||||
{
|
||||
auto paddr = s_general_allocator->paddr_of(vaddr);
|
||||
if (paddr.has_value())
|
||||
return paddr.value();
|
||||
}
|
||||
|
||||
if ((vaddr_t)s_kmalloc_storage <= vaddr && vaddr < (vaddr_t)s_kmalloc_storage + sizeof(s_kmalloc_storage))
|
||||
return V2P(vaddr);
|
||||
|
||||
|
|
|
@ -247,6 +247,8 @@ namespace Kernel
|
|||
{
|
||||
LockGuard _(m_lock);
|
||||
|
||||
validate_pointer_access(termios, sizeof(::termios));
|
||||
|
||||
if (!m_controlling_terminal)
|
||||
return BAN::Error::from_errno(ENOTTY);
|
||||
|
||||
|
@ -264,6 +266,8 @@ namespace Kernel
|
|||
{
|
||||
LockGuard _(m_lock);
|
||||
|
||||
validate_pointer_access(termios, sizeof(::termios));
|
||||
|
||||
if (!m_controlling_terminal)
|
||||
return BAN::Error::from_errno(ENOTTY);
|
||||
|
||||
|
@ -360,12 +364,25 @@ namespace Kernel
|
|||
// NOTE: We scope everything for automatic deletion
|
||||
{
|
||||
BAN::Vector<BAN::String> str_argv;
|
||||
for (int i = 0; argv && argv[i]; i++)
|
||||
TRY(str_argv.emplace_back(argv[i]));
|
||||
|
||||
BAN::Vector<BAN::String> str_envp;
|
||||
|
||||
{
|
||||
LockGuard _(m_lock);
|
||||
|
||||
for (int i = 0; argv && argv[i]; i++)
|
||||
{
|
||||
validate_pointer_access(argv + i, sizeof(char*));
|
||||
validate_string_access(argv[i]);
|
||||
TRY(str_argv.emplace_back(argv[i]));
|
||||
}
|
||||
|
||||
for (int i = 0; envp && envp[i]; i++)
|
||||
{
|
||||
validate_pointer_access(envp + 1, sizeof(char*));
|
||||
validate_string_access(envp[i]);
|
||||
TRY(str_envp.emplace_back(envp[i]));
|
||||
}
|
||||
}
|
||||
|
||||
BAN::String working_directory;
|
||||
|
||||
|
@ -471,6 +488,11 @@ namespace Kernel
|
|||
{
|
||||
Process* target = nullptr;
|
||||
|
||||
{
|
||||
LockGuard _(m_lock);
|
||||
validate_pointer_access(stat_loc, sizeof(int));
|
||||
}
|
||||
|
||||
// FIXME: support options
|
||||
if (options)
|
||||
return BAN::Error::from_errno(EINVAL);
|
||||
|
@ -504,7 +526,12 @@ namespace Kernel
|
|||
|
||||
BAN::ErrorOr<long> Process::sys_nanosleep(const timespec* rqtp, timespec* rmtp)
|
||||
{
|
||||
(void)rmtp;
|
||||
{
|
||||
LockGuard _(m_lock);
|
||||
validate_pointer_access(rqtp, sizeof(timespec));
|
||||
validate_pointer_access(rmtp, sizeof(timespec));
|
||||
}
|
||||
// TODO: rmtp
|
||||
SystemTimer::get().sleep(rqtp->tv_sec * 1000 + BAN::Math::div_round_up<uint64_t>(rqtp->tv_nsec, 1'000'000));
|
||||
return 0;
|
||||
}
|
||||
|
@ -586,9 +613,8 @@ namespace Kernel
|
|||
return {};
|
||||
}
|
||||
|
||||
BAN::ErrorOr<long> Process::sys_open(BAN::StringView path, int flags, mode_t mode)
|
||||
BAN::ErrorOr<long> Process::open_file(BAN::StringView path, int flags, mode_t mode)
|
||||
{
|
||||
LockGuard _(m_lock);
|
||||
BAN::String absolute_path = TRY(absolute_path_of(path));
|
||||
|
||||
if (flags & O_CREAT)
|
||||
|
@ -616,9 +642,18 @@ namespace Kernel
|
|||
return fd;
|
||||
}
|
||||
|
||||
BAN::ErrorOr<long> Process::sys_openat(int fd, BAN::StringView path, int flags, mode_t mode)
|
||||
BAN::ErrorOr<long> Process::sys_open(const char* path, int flags, mode_t mode)
|
||||
{
|
||||
LockGuard _(m_lock);
|
||||
validate_string_access(path);
|
||||
return open_file(path, flags, mode);
|
||||
}
|
||||
|
||||
BAN::ErrorOr<long> Process::sys_openat(int fd, const char* path, int flags, mode_t mode)
|
||||
{
|
||||
LockGuard _(m_lock);
|
||||
|
||||
validate_string_access(path);
|
||||
|
||||
// FIXME: handle O_SEARCH in fd
|
||||
|
||||
|
@ -627,7 +662,7 @@ namespace Kernel
|
|||
TRY(absolute_path.push_back('/'));
|
||||
TRY(absolute_path.append(path));
|
||||
|
||||
return sys_open(absolute_path, flags, mode);
|
||||
return open_file(absolute_path, flags, mode);
|
||||
}
|
||||
|
||||
BAN::ErrorOr<long> Process::sys_close(int fd)
|
||||
|
@ -640,18 +675,21 @@ namespace Kernel
|
|||
BAN::ErrorOr<long> Process::sys_read(int fd, void* buffer, size_t count)
|
||||
{
|
||||
LockGuard _(m_lock);
|
||||
validate_pointer_access(buffer, count);
|
||||
return TRY(m_open_file_descriptors.read(fd, buffer, count));
|
||||
}
|
||||
|
||||
BAN::ErrorOr<long> Process::sys_write(int fd, const void* buffer, size_t count)
|
||||
{
|
||||
LockGuard _(m_lock);
|
||||
validate_pointer_access(buffer, count);
|
||||
return TRY(m_open_file_descriptors.write(fd, buffer, count));
|
||||
}
|
||||
|
||||
BAN::ErrorOr<long> Process::sys_pipe(int fildes[2])
|
||||
{
|
||||
LockGuard _(m_lock);
|
||||
validate_pointer_access(fildes, sizeof(int) * 2);
|
||||
TRY(m_open_file_descriptors.pipe(fildes));
|
||||
return 0;
|
||||
}
|
||||
|
@ -699,16 +737,18 @@ namespace Kernel
|
|||
return {};
|
||||
}
|
||||
|
||||
BAN::ErrorOr<long> Process::sys_fstat(int fd, struct stat* out)
|
||||
BAN::ErrorOr<long> Process::sys_fstat(int fd, struct stat* buf)
|
||||
{
|
||||
LockGuard _(m_lock);
|
||||
TRY(m_open_file_descriptors.fstat(fd, out));
|
||||
validate_pointer_access(buf, sizeof(struct stat));
|
||||
TRY(m_open_file_descriptors.fstat(fd, buf));
|
||||
return 0;
|
||||
}
|
||||
|
||||
BAN::ErrorOr<long> Process::sys_fstatat(int fd, const char* path, struct stat* buf, int flag)
|
||||
{
|
||||
LockGuard _(m_lock);
|
||||
validate_pointer_access(buf, sizeof(struct stat));
|
||||
TRY(m_open_file_descriptors.fstatat(fd, path, buf, flag));
|
||||
return 0;
|
||||
}
|
||||
|
@ -716,6 +756,7 @@ namespace Kernel
|
|||
BAN::ErrorOr<long> Process::sys_stat(const char* path, struct stat* buf, int flag)
|
||||
{
|
||||
LockGuard _(m_lock);
|
||||
validate_pointer_access(buf, sizeof(struct stat));
|
||||
TRY(m_open_file_descriptors.stat(TRY(absolute_path_of(path)), buf, flag));
|
||||
return 0;
|
||||
}
|
||||
|
@ -741,6 +782,7 @@ namespace Kernel
|
|||
BAN::ErrorOr<long> Process::sys_read_dir_entries(int fd, DirectoryEntryList* list, size_t list_size)
|
||||
{
|
||||
LockGuard _(m_lock);
|
||||
validate_pointer_access(list, list_size);
|
||||
TRY(m_open_file_descriptors.read_dir_entries(fd, list, list_size));
|
||||
return 0;
|
||||
}
|
||||
|
@ -751,6 +793,7 @@ namespace Kernel
|
|||
|
||||
{
|
||||
LockGuard _(m_lock);
|
||||
validate_string_access(path);
|
||||
absolute_path = TRY(absolute_path_of(path));
|
||||
}
|
||||
|
||||
|
@ -768,6 +811,8 @@ namespace Kernel
|
|||
{
|
||||
LockGuard _(m_lock);
|
||||
|
||||
validate_pointer_access(buffer, size);
|
||||
|
||||
if (size < m_working_directory.size() + 1)
|
||||
return BAN::Error::from_errno(ERANGE);
|
||||
|
||||
|
@ -777,32 +822,37 @@ namespace Kernel
|
|||
return (long)buffer;
|
||||
}
|
||||
|
||||
BAN::ErrorOr<long> Process::sys_mmap(const sys_mmap_t& args)
|
||||
BAN::ErrorOr<long> Process::sys_mmap(const sys_mmap_t* args)
|
||||
{
|
||||
if (args.prot != PROT_NONE && args.prot & ~(PROT_READ | PROT_WRITE | PROT_EXEC))
|
||||
{
|
||||
LockGuard _(m_lock);
|
||||
validate_pointer_access(args, sizeof(sys_mmap_t));
|
||||
}
|
||||
|
||||
if (args->prot != PROT_NONE && args->prot & ~(PROT_READ | PROT_WRITE | PROT_EXEC))
|
||||
return BAN::Error::from_errno(EINVAL);
|
||||
|
||||
PageTable::flags_t flags = PageTable::Flags::UserSupervisor;
|
||||
if (args.prot & PROT_READ)
|
||||
if (args->prot & PROT_READ)
|
||||
flags |= PageTable::Flags::Present;
|
||||
if (args.prot & PROT_WRITE)
|
||||
if (args->prot & PROT_WRITE)
|
||||
flags |= PageTable::Flags::ReadWrite | PageTable::Flags::Present;
|
||||
if (args.prot & PROT_EXEC)
|
||||
if (args->prot & PROT_EXEC)
|
||||
flags |= PageTable::Flags::Execute | PageTable::Flags::Present;
|
||||
|
||||
if (args.flags == (MAP_ANONYMOUS | MAP_PRIVATE))
|
||||
if (args->flags == (MAP_ANONYMOUS | MAP_PRIVATE))
|
||||
{
|
||||
if (args.addr != nullptr)
|
||||
if (args->addr != nullptr)
|
||||
return BAN::Error::from_errno(ENOTSUP);
|
||||
if (args.off != 0)
|
||||
if (args->off != 0)
|
||||
return BAN::Error::from_errno(EINVAL);
|
||||
if (args.len % PAGE_SIZE != 0)
|
||||
if (args->len % PAGE_SIZE != 0)
|
||||
return BAN::Error::from_errno(EINVAL);
|
||||
|
||||
auto range = TRY(VirtualRange::create_to_vaddr_range(
|
||||
page_table(),
|
||||
0x400000, KERNEL_OFFSET,
|
||||
args.len,
|
||||
args->len,
|
||||
PageTable::Flags::UserSupervisor | PageTable::Flags::ReadWrite | PageTable::Flags::Present
|
||||
));
|
||||
range->set_zero();
|
||||
|
@ -839,10 +889,12 @@ namespace Kernel
|
|||
return 0;
|
||||
}
|
||||
|
||||
BAN::ErrorOr<long> Process::sys_termid(char* buffer) const
|
||||
BAN::ErrorOr<long> Process::sys_termid(char* buffer)
|
||||
{
|
||||
LockGuard _(m_lock);
|
||||
|
||||
validate_string_access(buffer);
|
||||
|
||||
auto& tty = m_controlling_terminal;
|
||||
|
||||
if (!tty)
|
||||
|
@ -857,8 +909,13 @@ namespace Kernel
|
|||
return 0;
|
||||
}
|
||||
|
||||
BAN::ErrorOr<long> Process::sys_clock_gettime(clockid_t clock_id, timespec* tp) const
|
||||
BAN::ErrorOr<long> Process::sys_clock_gettime(clockid_t clock_id, timespec* tp)
|
||||
{
|
||||
{
|
||||
LockGuard _(m_lock);
|
||||
validate_pointer_access(tp, sizeof(timespec));
|
||||
}
|
||||
|
||||
switch (clock_id)
|
||||
{
|
||||
case CLOCK_MONOTONIC:
|
||||
|
@ -882,6 +939,11 @@ namespace Kernel
|
|||
if (signal < _SIGMIN || signal > _SIGMAX)
|
||||
return BAN::Error::from_errno(EINVAL);
|
||||
|
||||
{
|
||||
LockGuard _(m_lock);
|
||||
validate_pointer_access((void*)handler, sizeof(handler));
|
||||
}
|
||||
|
||||
CriticalScope _;
|
||||
m_signal_handlers[signal] = (vaddr_t)handler;
|
||||
return 0;
|
||||
|
@ -1264,4 +1326,43 @@ namespace Kernel
|
|||
return absolute_path;
|
||||
}
|
||||
|
||||
void Process::validate_string_access(const char* str)
|
||||
{
|
||||
// NOTE: we will page fault here, if str is not actually mapped
|
||||
// outcome is still the same; SIGSEGV
|
||||
validate_pointer_access(str, strlen(str) + 1);
|
||||
}
|
||||
|
||||
void Process::validate_pointer_access(const void* ptr, size_t size)
|
||||
{
|
||||
ASSERT(&Process::current() == this);
|
||||
auto& thread = Thread::current();
|
||||
|
||||
vaddr_t vaddr = (vaddr_t)ptr;
|
||||
|
||||
// NOTE: detect overflow
|
||||
if (vaddr + size < vaddr)
|
||||
goto unauthorized_access;
|
||||
|
||||
// trying to access kernel space memory
|
||||
if (vaddr + size > KERNEL_OFFSET)
|
||||
goto unauthorized_access;
|
||||
|
||||
if (vaddr == 0)
|
||||
return;
|
||||
|
||||
if (vaddr >= thread.stack_base() && vaddr + size <= thread.stack_base() + thread.stack_size())
|
||||
return;
|
||||
|
||||
// FIXME: should we allow cross mapping access?
|
||||
for (auto& mapped_range : m_mapped_ranges)
|
||||
if (vaddr >= mapped_range.range->vaddr() && vaddr + size <= mapped_range.range->vaddr() + mapped_range.range->size())
|
||||
return;
|
||||
|
||||
unauthorized_access:
|
||||
dwarnln("process {}, thread {} attempted to make an invalid pointer access", pid(), Thread::current().tid());
|
||||
Debug::dump_stack_trace();
|
||||
MUST(sys_raise(SIGSEGV));
|
||||
}
|
||||
|
||||
}
|
|
@ -188,7 +188,7 @@ namespace Kernel
|
|||
ret = Process::current().sys_sync();
|
||||
break;
|
||||
case SYS_MMAP:
|
||||
ret = Process::current().sys_mmap(*(const sys_mmap_t*)arg1);
|
||||
ret = Process::current().sys_mmap((const sys_mmap_t*)arg1);
|
||||
break;
|
||||
case SYS_MUNMAP:
|
||||
ret = Process::current().sys_munmap((void*)arg1, (size_t)arg2);
|
||||
|
|
|
@ -3,6 +3,7 @@
|
|||
#include <BAN/UTF8.h>
|
||||
#include <kernel/Debug.h>
|
||||
#include <kernel/FS/DevFS/FileSystem.h>
|
||||
#include <kernel/FS/VirtualFileSystem.h>
|
||||
#include <kernel/LockGuard.h>
|
||||
#include <kernel/Process.h>
|
||||
#include <kernel/Terminal/TTY.h>
|
||||
|
@ -49,11 +50,12 @@ namespace Kernel
|
|||
Process::create_kernel(
|
||||
[](void*)
|
||||
{
|
||||
int fd = MUST(Process::current().sys_open("/dev/input0"sv, O_RDONLY));
|
||||
auto inode = MUST(VirtualFileSystem::get().file_from_absolute_path({ 0, 0, 0, 0 }, "/dev/input0"sv, O_RDONLY)).inode;
|
||||
while (true)
|
||||
{
|
||||
Input::KeyEvent event;
|
||||
ASSERT(MUST(Process::current().sys_read(fd, &event, sizeof(event))) == sizeof(event));
|
||||
size_t read = MUST(inode->read(0, &event, sizeof(event)));
|
||||
ASSERT(read == sizeof(event));
|
||||
TTY::current()->on_key_event(event);
|
||||
}
|
||||
}, nullptr
|
||||
|
|
Loading…
Reference in New Issue