Add a basic read-only implementation for the Ext2 filesystem #29
@ -11,7 +11,7 @@ steps:
|
|||||||
image: ubuntu
|
image: ubuntu
|
||||||
commands:
|
commands:
|
||||||
- apt update
|
- apt update
|
||||||
- apt install build-essential cmake ninja-build wget nasm -y
|
- apt install build-essential cmake ninja-build wget nasm genext2fs -y
|
||||||
- wget https://pub.cloudapio.eu/luna/toolchains/ci-toolchain-arm64.tar.gz --quiet
|
- wget https://pub.cloudapio.eu/luna/toolchains/ci-toolchain-arm64.tar.gz --quiet
|
||||||
- tar xf ci-toolchain-arm64.tar.gz
|
- tar xf ci-toolchain-arm64.tar.gz
|
||||||
- rm ci-toolchain-arm64.tar.gz
|
- rm ci-toolchain-arm64.tar.gz
|
||||||
|
@ -279,7 +279,7 @@ static void mount_devfs()
|
|||||||
{
|
{
|
||||||
if (mkdir("/dev", 0755) < 0 && errno != EEXIST) exit(255);
|
if (mkdir("/dev", 0755) < 0 && errno != EEXIST) exit(255);
|
||||||
|
|
||||||
if (mount("/dev", "devfs") < 0) exit(255);
|
if (mount("/dev", "devfs", "devfs") < 0) exit(255);
|
||||||
}
|
}
|
||||||
|
|
||||||
int main()
|
int main()
|
||||||
|
@ -6,15 +6,17 @@ Result<int> luna_main(int argc, char** argv)
|
|||||||
{
|
{
|
||||||
StringView target;
|
StringView target;
|
||||||
StringView fstype { "auto" };
|
StringView fstype { "auto" };
|
||||||
|
StringView source;
|
||||||
|
|
||||||
os::ArgumentParser parser;
|
os::ArgumentParser parser;
|
||||||
parser.add_description("Mount a file system.");
|
parser.add_description("Mount a file system.");
|
||||||
parser.add_system_program_info("mount"_sv);
|
parser.add_system_program_info("mount"_sv);
|
||||||
|
parser.add_positional_argument(source, "source"_sv, true);
|
||||||
parser.add_positional_argument(target, "mountpoint"_sv, true);
|
parser.add_positional_argument(target, "mountpoint"_sv, true);
|
||||||
parser.add_value_argument(fstype, 't', "type"_sv, "the file system type to use");
|
parser.add_value_argument(fstype, 't', "type"_sv, "the file system type to use");
|
||||||
parser.parse(argc, argv);
|
parser.parse(argc, argv);
|
||||||
|
|
||||||
if (mount(target.chars(), fstype.chars()) < 0)
|
if (mount(target.chars(), fstype.chars(), source.chars()) < 0)
|
||||||
{
|
{
|
||||||
perror("mount");
|
perror("mount");
|
||||||
return 1;
|
return 1;
|
||||||
|
3
initrd/etc/init/02-ext2fs
Normal file
3
initrd/etc/init/02-ext2fs
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
Name=ext2fs
|
||||||
|
Script=/sbin/mount-ext2fs
|
||||||
|
Wait=true
|
2
initrd/sbin/mount-ext2fs
Normal file
2
initrd/sbin/mount-ext2fs
Normal file
@ -0,0 +1,2 @@
|
|||||||
|
mkdir /mnt
|
||||||
|
mount -t ext2 /dev/cd0p2 /mnt
|
@ -1,5 +1,5 @@
|
|||||||
#!/bin/sh
|
#!/bin/sh
|
||||||
|
|
||||||
mkdir -p /tmp
|
mkdir -p /tmp
|
||||||
mount -t tmpfs /tmp
|
mount -t tmpfs tmpfs /tmp
|
||||||
chmod 1777 /tmp
|
chmod 1777 /tmp
|
||||||
|
@ -47,6 +47,8 @@ set(SOURCES
|
|||||||
src/fs/GPT.cpp
|
src/fs/GPT.cpp
|
||||||
src/fs/tmpfs/FileSystem.cpp
|
src/fs/tmpfs/FileSystem.cpp
|
||||||
src/fs/tmpfs/Inode.cpp
|
src/fs/tmpfs/Inode.cpp
|
||||||
|
src/fs/ext2/FileSystem.cpp
|
||||||
|
src/fs/ext2/Inode.cpp
|
||||||
src/fs/devices/DeviceRegistry.cpp
|
src/fs/devices/DeviceRegistry.cpp
|
||||||
src/fs/devices/NullDevice.cpp
|
src/fs/devices/NullDevice.cpp
|
||||||
src/fs/devices/ZeroDevice.cpp
|
src/fs/devices/ZeroDevice.cpp
|
||||||
|
@ -7,6 +7,7 @@ target_compile_definitions(moon PRIVATE EXEC_DEBUG)
|
|||||||
target_compile_definitions(moon PRIVATE OPEN_DEBUG)
|
target_compile_definitions(moon PRIVATE OPEN_DEBUG)
|
||||||
target_compile_definitions(moon PRIVATE REAP_DEBUG)
|
target_compile_definitions(moon PRIVATE REAP_DEBUG)
|
||||||
target_compile_definitions(moon PRIVATE PCI_DEBUG)
|
target_compile_definitions(moon PRIVATE PCI_DEBUG)
|
||||||
|
target_compile_definitions(moon PRIVATE EXT2_DEBUG)
|
||||||
target_compile_definitions(moon PRIVATE DEVICE_REGISTRY_DEBUG)
|
target_compile_definitions(moon PRIVATE DEVICE_REGISTRY_DEBUG)
|
||||||
target_compile_definitions(moon PRIVATE FORK_DEBUG)
|
target_compile_definitions(moon PRIVATE FORK_DEBUG)
|
||||||
target_compile_options(moon PRIVATE -fsanitize=undefined)
|
target_compile_options(moon PRIVATE -fsanitize=undefined)
|
||||||
|
@ -146,7 +146,7 @@ namespace ATA
|
|||||||
{
|
{
|
||||||
if (drive == m_current_drive) return;
|
if (drive == m_current_drive) return;
|
||||||
|
|
||||||
u8 value = (drive << 4) | 0xa0;
|
u8 value = (u8)(drive << 4) | 0xa0;
|
||||||
write_register(Register::DriveSelect, value);
|
write_register(Register::DriveSelect, value);
|
||||||
|
|
||||||
delay_400ns();
|
delay_400ns();
|
||||||
|
@ -222,6 +222,7 @@ namespace VFS
|
|||||||
g_root_inode = new_root_inode;
|
g_root_inode = new_root_inode;
|
||||||
TRY(new_root_parent_inode->replace_entry(((MountInode*)g_root_inode.ptr())->source(), new_root_path.chars()));
|
TRY(new_root_parent_inode->replace_entry(((MountInode*)g_root_inode.ptr())->source(), new_root_path.chars()));
|
||||||
((MountInode*)g_root_inode.ptr())->set_source({});
|
((MountInode*)g_root_inode.ptr())->set_source({});
|
||||||
|
g_root_inode->fs()->reset_mount_dir();
|
||||||
|
|
||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
|
@ -36,6 +36,13 @@ namespace VFS
|
|||||||
|
|
||||||
virtual Result<void> set_mount_dir(SharedPtr<Inode> parent) = 0;
|
virtual Result<void> set_mount_dir(SharedPtr<Inode> parent) = 0;
|
||||||
|
|
||||||
|
virtual Result<void> reset_mount_dir() = 0;
|
||||||
|
|
||||||
|
virtual bool is_readonly() const
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
virtual u64 handles() const
|
virtual u64 handles() const
|
||||||
{
|
{
|
||||||
return m_handles;
|
return m_handles;
|
||||||
|
133
kernel/src/fs/ext2/FileSystem.cpp
Normal file
133
kernel/src/fs/ext2/FileSystem.cpp
Normal file
@ -0,0 +1,133 @@
|
|||||||
|
#include "fs/ext2/FileSystem.h"
|
||||||
|
#include "fs/ext2/Inode.h"
|
||||||
|
#include <luna/Alignment.h>
|
||||||
|
|
||||||
|
static VFS::InodeType vfs_type_from_ext2_type(mode_t mode)
|
||||||
|
{
|
||||||
|
auto type = mode & 0xf000;
|
||||||
|
|
||||||
|
switch (type)
|
||||||
|
{
|
||||||
|
case EXT2_FIFO: return VFS::InodeType::FIFO;
|
||||||
|
case EXT2_CHR: return VFS::InodeType::CharacterDevice;
|
||||||
|
case EXT2_DIR: return VFS::InodeType::Directory;
|
||||||
|
case EXT2_BLK: return VFS::InodeType::BlockDevice;
|
||||||
|
case EXT2_REG: return VFS::InodeType::RegularFile;
|
||||||
|
case EXT2_LNK: return VFS::InodeType::Symlink;
|
||||||
|
case EXT2_SOCK: [[fallthrough]]; // TODO: Sockets not supported on Luna at the moment.
|
||||||
|
default: fail("ext2: Unknown or unsupported inode type");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
namespace Ext2
|
||||||
|
{
|
||||||
|
FileSystem::FileSystem()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
Result<SharedPtr<VFS::Inode>> FileSystem::find_inode_by_number(ino_t inum, bool initialize_dir_now)
|
||||||
|
{
|
||||||
|
check(inum < m_superblock.nr_inodes);
|
||||||
|
|
||||||
|
auto maybe_inode = m_inode_cache.try_get(inum);
|
||||||
|
if (maybe_inode.has_value()) return maybe_inode.value();
|
||||||
|
|
||||||
|
const u32 block_group = (u32)((inum - 1) / m_superblock.inodes_per_block_group);
|
||||||
|
|
||||||
|
const auto* block_group_descriptor = TRY(find_block_group_descriptor(block_group));
|
||||||
|
check(block_group_descriptor);
|
||||||
|
|
||||||
|
// FIXME: Even if the inode size is bigger (Ext2::FileSystem::m_inode_size), we only read this amount. Enlarge
|
||||||
|
// the Inode structure to fit this case.
|
||||||
|
static constexpr usize INODE_SIZE = 128;
|
||||||
|
|
||||||
|
const u64 index = (inum - 1) % m_superblock.inodes_per_block_group;
|
||||||
|
|
||||||
|
const u64 inode_address = (block_group_descriptor->inode_table_start * m_block_size) + (index * m_inode_size);
|
||||||
|
|
||||||
|
auto inode = TRY(adopt_shared_if_nonnull(new (std::nothrow) Ext2::Inode({}, this)));
|
||||||
|
TRY(m_host_device->read((u8*)&inode->m_raw_inode, inode_address, INODE_SIZE));
|
||||||
|
inode->m_type = vfs_type_from_ext2_type(inode->m_raw_inode.mode);
|
||||||
|
inode->m_inum = inum;
|
||||||
|
|
||||||
|
#ifdef EXT2_DEBUG
|
||||||
|
kdbgln("ext2: Read inode %lu with mode %#x (%#x + %#o), size %lu", inum, inode->m_raw_inode.mode,
|
||||||
|
inode->m_raw_inode.mode & 0xf000, inode->mode(), inode->size());
|
||||||
|
#endif
|
||||||
|
|
||||||
|
m_inode_cache.try_set(inum, inode);
|
||||||
|
|
||||||
|
if (initialize_dir_now && inode->m_type == VFS::InodeType::Directory) TRY(inode->lazy_initialize_dir());
|
||||||
|
|
||||||
|
return (SharedPtr<VFS::Inode>)inode;
|
||||||
|
}
|
||||||
|
|
||||||
|
Result<const BlockGroupDescriptor*> FileSystem::find_block_group_descriptor(u32 index)
|
||||||
|
{
|
||||||
|
check(index < m_block_groups);
|
||||||
|
|
||||||
|
auto maybe_desc = m_block_group_descriptor_cache.try_get_ref(index);
|
||||||
|
if (maybe_desc) return maybe_desc;
|
||||||
|
|
||||||
|
const u64 address = (m_superblock.first_data_block + 1) * m_block_size + (index * sizeof(BlockGroupDescriptor));
|
||||||
|
|
||||||
|
BlockGroupDescriptor descriptor;
|
||||||
|
TRY(m_host_device->read((u8*)&descriptor, address, sizeof(descriptor)));
|
||||||
|
|
||||||
|
check(TRY(m_block_group_descriptor_cache.try_set(index, descriptor)));
|
||||||
|
|
||||||
|
return m_block_group_descriptor_cache.try_get_ref(index);
|
||||||
|
}
|
||||||
|
|
||||||
|
Result<SharedPtr<VFS::FileSystem>> FileSystem::create(SharedPtr<Device> host_device)
|
||||||
|
{
|
||||||
|
SharedPtr<FileSystem> fs = TRY(adopt_shared_if_nonnull(new (std::nothrow) FileSystem()));
|
||||||
|
const usize nread = TRY(host_device->read((u8*)&fs->m_superblock, 1024, 1024));
|
||||||
|
if (nread != 1024) return err(EINVAL); // Source had an invalid superblock.
|
||||||
|
if (fs->m_superblock.signature != EXT2_MAGIC) return err(EINVAL); // Source had an invalid superblock.
|
||||||
|
|
||||||
|
if (fs->m_superblock.major_version >= 1)
|
||||||
|
{
|
||||||
|
auto required = fs->m_superblock.ext_superblock.required_features;
|
||||||
|
if (required & EXT2_REQUIRED_COMPAT_D_TYPE) fs->m_dirs_have_type_field = true;
|
||||||
|
|
||||||
|
required &= ~EXT2_REQUIRED_COMPAT_D_TYPE;
|
||||||
|
|
||||||
|
if (required > 0)
|
||||||
|
{
|
||||||
|
kwarnln("ext2: File system has required features not supported by the implementation, cannot mount");
|
||||||
|
return err(EINVAL);
|
||||||
|
}
|
||||||
|
|
||||||
|
fs->m_uses_extended_size = true;
|
||||||
|
fs->m_inode_size = fs->m_superblock.ext_superblock.inode_size;
|
||||||
|
}
|
||||||
|
|
||||||
|
fs->m_host_device = host_device;
|
||||||
|
|
||||||
|
fs->m_block_size = 1024 << fs->m_superblock.log_block_size;
|
||||||
|
fs->m_block_groups = get_blocks_from_size(fs->m_superblock.nr_blocks, fs->m_superblock.blocks_per_block_group);
|
||||||
|
|
||||||
|
#ifdef EXT2_DEBUG
|
||||||
|
kdbgln("ext2: Mounting new Ext2 file system, block size=%lu, blocks=%u, inodes=%u, block group=(%u blocks, %u "
|
||||||
|
"inodes), %lu block groups",
|
||||||
|
fs->m_block_size, fs->m_superblock.nr_blocks, fs->m_superblock.nr_inodes,
|
||||||
|
fs->m_superblock.blocks_per_block_group, fs->m_superblock.inodes_per_block_group, fs->m_block_groups);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// Lookup the root inode.
|
||||||
|
fs->m_root_inode = TRY(fs->find_inode_by_number(2, true));
|
||||||
|
|
||||||
|
return (SharedPtr<VFS::FileSystem>)fs;
|
||||||
|
}
|
||||||
|
|
||||||
|
Result<void> FileSystem::set_mount_dir(SharedPtr<VFS::Inode> inode)
|
||||||
|
{
|
||||||
|
return m_root_inode->replace_entry(inode, "..");
|
||||||
|
}
|
||||||
|
|
||||||
|
Result<void> FileSystem::reset_mount_dir()
|
||||||
|
{
|
||||||
|
return m_root_inode->replace_entry(m_root_inode, "..");
|
||||||
|
}
|
||||||
|
}
|
197
kernel/src/fs/ext2/FileSystem.h
Normal file
197
kernel/src/fs/ext2/FileSystem.h
Normal file
@ -0,0 +1,197 @@
|
|||||||
|
#pragma once
|
||||||
|
#include "fs/VFS.h"
|
||||||
|
#include "fs/devices/DeviceRegistry.h"
|
||||||
|
#include <luna/HashMap.h>
|
||||||
|
|
||||||
|
#define EXT2_MAGIC 0xef53
|
||||||
|
|
||||||
|
#define EXT2_REQUIRED_COMPAT_D_TYPE 0x0002
|
||||||
|
|
||||||
|
namespace Ext2
|
||||||
|
{
|
||||||
|
struct [[gnu::packed]] Superblock
|
||||||
|
{
|
||||||
|
u32 nr_inodes;
|
||||||
|
u32 nr_blocks;
|
||||||
|
u32 nr_reserved_blocks;
|
||||||
|
u32 nr_free_blocks;
|
||||||
|
u32 nr_free_inodes;
|
||||||
|
u32 first_data_block;
|
||||||
|
u32 log_block_size;
|
||||||
|
u32 log_fragment_size;
|
||||||
|
u32 blocks_per_block_group;
|
||||||
|
u32 fragments_per_block_group;
|
||||||
|
u32 inodes_per_block_group;
|
||||||
|
u32 last_mount_time;
|
||||||
|
u32 last_write_time;
|
||||||
|
|
||||||
|
u16 mounts_since_last_fsck;
|
||||||
|
u16 mounts_allowed_before_fsck;
|
||||||
|
u16 signature;
|
||||||
|
u16 fs_state;
|
||||||
|
u16 error_action;
|
||||||
|
u16 minor_version;
|
||||||
|
|
||||||
|
u32 last_fsck_time;
|
||||||
|
u32 fsck_time_interval;
|
||||||
|
u32 os_id;
|
||||||
|
u32 major_version;
|
||||||
|
|
||||||
|
u16 reserved_block_uid;
|
||||||
|
u16 reserved_block_gid;
|
||||||
|
struct
|
||||||
|
{
|
||||||
|
u32 first_non_reserved_inode;
|
||||||
|
u16 inode_size;
|
||||||
|
u16 this_block_group;
|
||||||
|
u32 optional_features;
|
||||||
|
u32 required_features;
|
||||||
|
u32 ro_features;
|
||||||
|
u8 fsid[16];
|
||||||
|
u8 name[16];
|
||||||
|
u8 last_mountpoint[64];
|
||||||
|
u32 compression_algs;
|
||||||
|
u8 nr_preallocated_blocks_for_files;
|
||||||
|
u8 nr_preallocated_blocks_for_dirs;
|
||||||
|
u16 unused;
|
||||||
|
u8 journal_id[16];
|
||||||
|
u32 journal_inode;
|
||||||
|
u32 journal_device;
|
||||||
|
u32 orphan_inode_head;
|
||||||
|
} ext_superblock;
|
||||||
|
u8 padding[1024 - 236];
|
||||||
|
};
|
||||||
|
|
||||||
|
struct [[gnu::packed]] BlockGroupDescriptor
|
||||||
|
{
|
||||||
|
u32 block_usage_addr;
|
||||||
|
u32 inode_usage_addr;
|
||||||
|
u32 inode_table_start;
|
||||||
|
u16 nr_free_blocks;
|
||||||
|
u16 nr_free_inodes;
|
||||||
|
u16 nr_directories;
|
||||||
|
u8 padding[32 - 18];
|
||||||
|
};
|
||||||
|
|
||||||
|
struct [[gnu::packed]] RawInode
|
||||||
|
{
|
||||||
|
u16 mode;
|
||||||
|
u16 uid;
|
||||||
|
u32 size_low;
|
||||||
|
u32 atime;
|
||||||
|
u32 create_time;
|
||||||
|
u32 mtime;
|
||||||
|
u32 delete_time;
|
||||||
|
u16 gid;
|
||||||
|
u16 nlinks;
|
||||||
|
u32 sectors_used;
|
||||||
|
u32 flags;
|
||||||
|
u32 os_specific_1;
|
||||||
|
u32 direct_pointers[12];
|
||||||
|
u32 singly_indirect_ptr;
|
||||||
|
u32 doubly_indirect_ptr;
|
||||||
|
u32 triply_indirect_ptr;
|
||||||
|
u32 gen_number;
|
||||||
|
u32 extended_attrs;
|
||||||
|
u32 size_high;
|
||||||
|
u32 frag_addr;
|
||||||
|
u32 os_specific_2[3];
|
||||||
|
};
|
||||||
|
|
||||||
|
struct [[gnu::packed]] RawDirectoryEntry
|
||||||
|
{
|
||||||
|
u32 inum;
|
||||||
|
u16 size;
|
||||||
|
union {
|
||||||
|
u16 name_length;
|
||||||
|
struct
|
||||||
|
{
|
||||||
|
u8 name_length_low;
|
||||||
|
u8 type;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
char name[4]; // Names should be padded to a multiple of 4 bytes.
|
||||||
|
};
|
||||||
|
|
||||||
|
static_assert(sizeof(Superblock) == 1024);
|
||||||
|
static_assert(sizeof(BlockGroupDescriptor) == 32);
|
||||||
|
static_assert(sizeof(RawInode) == 128);
|
||||||
|
|
||||||
|
class Inode;
|
||||||
|
|
||||||
|
class FileSystem : public VFS::FileSystem
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
SharedPtr<VFS::Inode> root_inode() const override
|
||||||
|
{
|
||||||
|
return m_root_inode;
|
||||||
|
}
|
||||||
|
|
||||||
|
Result<SharedPtr<VFS::Inode>> create_file_inode() override
|
||||||
|
{
|
||||||
|
return err(EROFS);
|
||||||
|
}
|
||||||
|
|
||||||
|
Result<SharedPtr<VFS::Inode>> create_dir_inode(SharedPtr<VFS::Inode>) override
|
||||||
|
{
|
||||||
|
return err(EROFS);
|
||||||
|
}
|
||||||
|
|
||||||
|
Result<SharedPtr<VFS::Inode>> create_device_inode(u32, u32) override
|
||||||
|
{
|
||||||
|
return err(EROFS);
|
||||||
|
}
|
||||||
|
|
||||||
|
Result<SharedPtr<VFS::Inode>> create_symlink_inode(StringView) override
|
||||||
|
{
|
||||||
|
return err(EROFS);
|
||||||
|
}
|
||||||
|
|
||||||
|
Result<void> set_mount_dir(SharedPtr<VFS::Inode>) override;
|
||||||
|
|
||||||
|
Result<void> reset_mount_dir() override;
|
||||||
|
|
||||||
|
bool is_readonly() const override
|
||||||
|
{
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
static Result<SharedPtr<VFS::FileSystem>> create(SharedPtr<Device> host_device);
|
||||||
|
|
||||||
|
dev_t host_device_id() const override
|
||||||
|
{
|
||||||
|
return m_host_device_id;
|
||||||
|
}
|
||||||
|
|
||||||
|
Result<SharedPtr<VFS::Inode>> find_inode_by_number(ino_t inode, bool initialize_dir_now = false);
|
||||||
|
Result<const BlockGroupDescriptor*> find_block_group_descriptor(u32 index);
|
||||||
|
|
||||||
|
virtual ~FileSystem() = default;
|
||||||
|
|
||||||
|
private:
|
||||||
|
FileSystem();
|
||||||
|
|
||||||
|
SharedPtr<VFS::Inode> m_root_inode;
|
||||||
|
|
||||||
|
SharedPtr<Device> m_host_device;
|
||||||
|
dev_t m_host_device_id;
|
||||||
|
|
||||||
|
Superblock m_superblock;
|
||||||
|
|
||||||
|
u64 m_block_size;
|
||||||
|
u64 m_block_groups;
|
||||||
|
|
||||||
|
u32 m_inode_size { 128 };
|
||||||
|
|
||||||
|
bool m_dirs_have_type_field { false };
|
||||||
|
bool m_uses_extended_size { false };
|
||||||
|
|
||||||
|
// FIXME: This inode cache will keep all inodes in it alive despite having no other references to it, but we're
|
||||||
|
// not worrying about that as for now the filesystem implementation is read-only.
|
||||||
|
HashMap<ino_t, SharedPtr<VFS::Inode>> m_inode_cache;
|
||||||
|
|
||||||
|
HashMap<u32, BlockGroupDescriptor> m_block_group_descriptor_cache;
|
||||||
|
|
||||||
|
friend class Inode;
|
||||||
|
};
|
||||||
|
}
|
205
kernel/src/fs/ext2/Inode.cpp
Normal file
205
kernel/src/fs/ext2/Inode.cpp
Normal file
@ -0,0 +1,205 @@
|
|||||||
|
#include "fs/ext2/Inode.h"
|
||||||
|
#include <luna/Buffer.h>
|
||||||
|
|
||||||
|
namespace Ext2
|
||||||
|
{
|
||||||
|
Inode::Inode(Badge<FileSystem>, FileSystem* fs) : m_fs(fs)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
usize Inode::size() const
|
||||||
|
{
|
||||||
|
return (m_fs->m_uses_extended_size && (m_type == VFS::InodeType::RegularFile))
|
||||||
|
? ((u64)m_raw_inode.size_high << 32) | (u64)m_raw_inode.size_low
|
||||||
|
: m_raw_inode.size_low;
|
||||||
|
}
|
||||||
|
|
||||||
|
Result<usize> Inode::read(u8* buf, usize offset, usize length) const
|
||||||
|
{
|
||||||
|
if (length == 0) return 0;
|
||||||
|
|
||||||
|
if (offset > size()) return 0;
|
||||||
|
if (offset + length > size()) length = size() - offset;
|
||||||
|
|
||||||
|
const usize block_size = m_fs->m_block_size;
|
||||||
|
|
||||||
|
usize to_read = length;
|
||||||
|
|
||||||
|
if (offset % block_size)
|
||||||
|
{
|
||||||
|
usize block_offset = (offset % block_size);
|
||||||
|
usize block = TRY(find_block(offset / block_size));
|
||||||
|
usize size_to_read = block_size - block_offset;
|
||||||
|
if (size_to_read > to_read) size_to_read = to_read;
|
||||||
|
|
||||||
|
usize host_offset = (block * block_size) + block_offset;
|
||||||
|
|
||||||
|
// FIXME: Cache this data.
|
||||||
|
TRY(m_fs->m_host_device->read(buf, host_offset, size_to_read));
|
||||||
|
|
||||||
|
to_read -= size_to_read;
|
||||||
|
buf += size_to_read;
|
||||||
|
offset += size_to_read;
|
||||||
|
}
|
||||||
|
|
||||||
|
while (to_read >= block_size)
|
||||||
|
{
|
||||||
|
usize block = TRY(find_block(offset / block_size));
|
||||||
|
|
||||||
|
usize host_offset = block * block_size;
|
||||||
|
|
||||||
|
// FIXME: Cache this data.
|
||||||
|
TRY(m_fs->m_host_device->read(buf, host_offset, block_size));
|
||||||
|
|
||||||
|
to_read -= block_size;
|
||||||
|
buf += block_size;
|
||||||
|
offset += block_size;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (to_read > 0)
|
||||||
|
{
|
||||||
|
usize block = TRY(find_block(offset / block_size));
|
||||||
|
|
||||||
|
usize host_offset = block * block_size;
|
||||||
|
|
||||||
|
// FIXME: Cache this data.
|
||||||
|
TRY(m_fs->m_host_device->read(buf, host_offset, to_read));
|
||||||
|
}
|
||||||
|
|
||||||
|
return length;
|
||||||
|
}
|
||||||
|
|
||||||
|
Result<usize> Inode::find_block(usize index) const
|
||||||
|
{
|
||||||
|
if (index < 12) return m_raw_inode.direct_pointers[index];
|
||||||
|
|
||||||
|
usize block_index = (index - 12) * sizeof(u32);
|
||||||
|
if (block_index >= m_fs->m_block_size)
|
||||||
|
{
|
||||||
|
fail("ext2: Finding blocks beyond the singly indirect pointer block is not yet supported");
|
||||||
|
}
|
||||||
|
|
||||||
|
usize block_size = m_fs->m_block_size;
|
||||||
|
|
||||||
|
if (m_singly_indirect_block.is_empty())
|
||||||
|
{
|
||||||
|
TRY(m_singly_indirect_block.try_resize(block_size));
|
||||||
|
TRY(m_fs->m_host_device->read(m_singly_indirect_block.data(), m_raw_inode.singly_indirect_ptr * block_size,
|
||||||
|
block_size));
|
||||||
|
}
|
||||||
|
|
||||||
|
return *reinterpret_cast<u32*>(&m_singly_indirect_block.data()[block_index]);
|
||||||
|
}
|
||||||
|
|
||||||
|
Result<void> Inode::lazy_initialize_dir() const
|
||||||
|
{
|
||||||
|
check(m_type == VFS::InodeType::Directory);
|
||||||
|
|
||||||
|
const usize inode_size = size();
|
||||||
|
const usize block_size = m_fs->m_block_size;
|
||||||
|
|
||||||
|
u8* const buf = TRY(make_array<u8>(block_size));
|
||||||
|
auto guard = make_scope_guard([buf] { delete[] buf; });
|
||||||
|
|
||||||
|
m_entries.clear();
|
||||||
|
|
||||||
|
for (usize offset = 0; offset < inode_size; offset += block_size)
|
||||||
|
{
|
||||||
|
TRY(read(buf, offset, block_size));
|
||||||
|
|
||||||
|
usize dir_offset = 0;
|
||||||
|
while (dir_offset < block_size)
|
||||||
|
{
|
||||||
|
auto& entry = *(Ext2::RawDirectoryEntry*)&buf[dir_offset];
|
||||||
|
|
||||||
|
if (entry.inum != 0)
|
||||||
|
{
|
||||||
|
auto inode = TRY(m_fs->find_inode_by_number(entry.inum));
|
||||||
|
|
||||||
|
VFS::DirectoryEntry vfs_entry { inode, "" };
|
||||||
|
vfs_entry.name.adopt(entry.name,
|
||||||
|
m_fs->m_dirs_have_type_field ? entry.name_length_low : entry.name_length);
|
||||||
|
|
||||||
|
#ifdef EXT2_DEBUG
|
||||||
|
kdbgln("ext2: Read new directory entry: inum=%u, name=%s, namelen=%lu", entry.inum,
|
||||||
|
vfs_entry.name.chars(), vfs_entry.name.length());
|
||||||
|
#endif
|
||||||
|
|
||||||
|
TRY(m_entries.try_append(move(vfs_entry)));
|
||||||
|
}
|
||||||
|
|
||||||
|
dir_offset += entry.size;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
m_dir_already_lazily_initialized = true;
|
||||||
|
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
|
||||||
|
Result<void> Inode::replace_entry(SharedPtr<VFS::Inode> inode, const char* name)
|
||||||
|
{
|
||||||
|
if (m_type != VFS::InodeType::Directory) return err(ENOTDIR);
|
||||||
|
if (!m_dir_already_lazily_initialized) TRY(lazy_initialize_dir());
|
||||||
|
|
||||||
|
for (auto& entry : m_entries)
|
||||||
|
{
|
||||||
|
if (!strcmp(name, entry.name.chars()))
|
||||||
|
{
|
||||||
|
entry.inode = inode;
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return err(ENOENT);
|
||||||
|
}
|
||||||
|
|
||||||
|
Result<SharedPtr<VFS::Inode>> Inode::find(const char* name) const
|
||||||
|
{
|
||||||
|
if (m_type != VFS::InodeType::Directory) return err(ENOTDIR);
|
||||||
|
if (!m_dir_already_lazily_initialized) TRY(lazy_initialize_dir());
|
||||||
|
|
||||||
|
for (const auto& entry : m_entries)
|
||||||
|
{
|
||||||
|
if (!strcmp(name, entry.name.chars())) return entry.inode;
|
||||||
|
}
|
||||||
|
|
||||||
|
return err(ENOENT);
|
||||||
|
}
|
||||||
|
|
||||||
|
Option<VFS::DirectoryEntry> Inode::get(usize index) const
|
||||||
|
{
|
||||||
|
if (m_type != VFS::InodeType::Directory) return {};
|
||||||
|
if (!m_dir_already_lazily_initialized)
|
||||||
|
if (lazy_initialize_dir().has_error()) return {};
|
||||||
|
|
||||||
|
if (index >= m_entries.size()) return {};
|
||||||
|
|
||||||
|
return m_entries[index];
|
||||||
|
}
|
||||||
|
|
||||||
|
Result<StringView> Inode::readlink()
|
||||||
|
{
|
||||||
|
check(m_type == VFS::InodeType::Symlink);
|
||||||
|
|
||||||
|
if (!m_link.is_empty()) return m_link.view();
|
||||||
|
|
||||||
|
const usize length = size();
|
||||||
|
|
||||||
|
if (length < 60)
|
||||||
|
{
|
||||||
|
// The symlink location is stored inline within the inode's data blocks.
|
||||||
|
m_link = TRY(String::from_string_view(
|
||||||
|
StringView::from_fixed_size_cstring((char*)&m_raw_inode.direct_pointers[0], length)));
|
||||||
|
|
||||||
|
return m_link.view();
|
||||||
|
}
|
||||||
|
|
||||||
|
Buffer buf = TRY(Buffer::create_sized(length));
|
||||||
|
TRY(read(buf.data(), 0, length));
|
||||||
|
|
||||||
|
m_link = TRY(String::from_string_view(StringView::from_fixed_size_cstring((char*)buf.data(), length)));
|
||||||
|
|
||||||
|
return m_link.view();
|
||||||
|
}
|
||||||
|
}
|
156
kernel/src/fs/ext2/Inode.h
Normal file
156
kernel/src/fs/ext2/Inode.h
Normal file
@ -0,0 +1,156 @@
|
|||||||
|
#pragma once
|
||||||
|
#include "fs/ext2/FileSystem.h"
|
||||||
|
#include <luna/Buffer.h>
|
||||||
|
#include <luna/String.h>
|
||||||
|
|
||||||
|
#define EXT2_FIFO 0x1000
|
||||||
|
#define EXT2_CHR 0x2000
|
||||||
|
#define EXT2_DIR 0x4000
|
||||||
|
#define EXT2_BLK 0x6000
|
||||||
|
#define EXT2_REG 0x8000
|
||||||
|
#define EXT2_LNK 0xA000
|
||||||
|
#define EXT2_SOCK 0xC000
|
||||||
|
|
||||||
|
namespace Ext2
|
||||||
|
{
|
||||||
|
class Inode : public VFS::Inode
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
VFS::InodeType type() const override
|
||||||
|
{
|
||||||
|
return m_type;
|
||||||
|
}
|
||||||
|
|
||||||
|
usize size() const override;
|
||||||
|
|
||||||
|
mode_t mode() const override
|
||||||
|
{
|
||||||
|
return m_raw_inode.mode & 07777;
|
||||||
|
}
|
||||||
|
|
||||||
|
nlink_t nlinks() const override
|
||||||
|
{
|
||||||
|
return m_raw_inode.nlinks;
|
||||||
|
}
|
||||||
|
|
||||||
|
u32 uid() const override
|
||||||
|
{
|
||||||
|
return m_raw_inode.uid;
|
||||||
|
}
|
||||||
|
|
||||||
|
u32 gid() const override
|
||||||
|
{
|
||||||
|
return m_raw_inode.gid;
|
||||||
|
}
|
||||||
|
|
||||||
|
usize inode_number() const override
|
||||||
|
{
|
||||||
|
return m_inum;
|
||||||
|
}
|
||||||
|
|
||||||
|
VFS::FileSystem* fs() const override
|
||||||
|
{
|
||||||
|
return m_fs;
|
||||||
|
}
|
||||||
|
|
||||||
|
void did_link() override
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
void did_unlink() override
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
Result<void> chmod(mode_t) override
|
||||||
|
{
|
||||||
|
return err(EROFS);
|
||||||
|
}
|
||||||
|
|
||||||
|
Result<void> chown(u32, u32) override
|
||||||
|
{
|
||||||
|
return err(EROFS);
|
||||||
|
}
|
||||||
|
|
||||||
|
Result<usize> read(u8* buf, usize offset, usize length) const override;
|
||||||
|
|
||||||
|
Result<usize> write(const u8*, usize, usize) override
|
||||||
|
{
|
||||||
|
return err(EROFS);
|
||||||
|
}
|
||||||
|
|
||||||
|
Result<void> truncate(usize) override
|
||||||
|
{
|
||||||
|
return err(EROFS);
|
||||||
|
}
|
||||||
|
|
||||||
|
Result<SharedPtr<VFS::Inode>> find(const char*) const override;
|
||||||
|
|
||||||
|
Option<VFS::DirectoryEntry> get(usize) const override;
|
||||||
|
|
||||||
|
Result<SharedPtr<VFS::Inode>> create_file(const char*) override
|
||||||
|
{
|
||||||
|
if (m_type != VFS::InodeType::Directory) return err(ENOTDIR);
|
||||||
|
|
||||||
|
return err(EROFS);
|
||||||
|
}
|
||||||
|
|
||||||
|
Result<SharedPtr<VFS::Inode>> create_subdirectory(const char*) override
|
||||||
|
{
|
||||||
|
if (m_type != VFS::InodeType::Directory) return err(ENOTDIR);
|
||||||
|
|
||||||
|
return err(EROFS);
|
||||||
|
}
|
||||||
|
|
||||||
|
Result<void> add_entry(SharedPtr<VFS::Inode>, const char*) override
|
||||||
|
{
|
||||||
|
if (m_type != VFS::InodeType::Directory) return err(ENOTDIR);
|
||||||
|
|
||||||
|
return err(EROFS);
|
||||||
|
}
|
||||||
|
|
||||||
|
Result<void> replace_entry(SharedPtr<VFS::Inode>, const char*) override;
|
||||||
|
|
||||||
|
Result<void> remove_entry(const char*) override
|
||||||
|
{
|
||||||
|
if (m_type != VFS::InodeType::Directory) return err(ENOTDIR);
|
||||||
|
|
||||||
|
return err(EROFS);
|
||||||
|
}
|
||||||
|
|
||||||
|
usize entries() const override
|
||||||
|
{
|
||||||
|
return m_entries.size();
|
||||||
|
}
|
||||||
|
|
||||||
|
bool blocking() const override
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
Result<StringView> readlink() override;
|
||||||
|
|
||||||
|
Result<void> lazy_initialize_dir() const;
|
||||||
|
|
||||||
|
// FIXME: Implement readlink() and device numbers.
|
||||||
|
|
||||||
|
Inode(Badge<FileSystem>, FileSystem* fs);
|
||||||
|
virtual ~Inode() = default;
|
||||||
|
|
||||||
|
private:
|
||||||
|
VFS::InodeType m_type;
|
||||||
|
RawInode m_raw_inode;
|
||||||
|
FileSystem* m_fs;
|
||||||
|
ino_t m_inum;
|
||||||
|
|
||||||
|
mutable Buffer m_singly_indirect_block;
|
||||||
|
|
||||||
|
String m_link;
|
||||||
|
|
||||||
|
mutable Vector<VFS::DirectoryEntry> m_entries;
|
||||||
|
mutable bool m_dir_already_lazily_initialized { false };
|
||||||
|
|
||||||
|
Result<usize> find_block(usize index) const;
|
||||||
|
|
||||||
|
friend class FileSystem;
|
||||||
|
};
|
||||||
|
}
|
@ -72,6 +72,11 @@ namespace TmpFS
|
|||||||
return m_root_inode->replace_entry(parent, "..");
|
return m_root_inode->replace_entry(parent, "..");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Result<void> FileSystem::reset_mount_dir()
|
||||||
|
{
|
||||||
|
return m_root_inode->replace_entry(m_root_inode, "..");
|
||||||
|
}
|
||||||
|
|
||||||
void FileSystem::set_root(SharedPtr<VFS::Inode> root)
|
void FileSystem::set_root(SharedPtr<VFS::Inode> root)
|
||||||
{
|
{
|
||||||
m_root_inode = root;
|
m_root_inode = root;
|
||||||
|
@ -20,6 +20,8 @@ namespace TmpFS
|
|||||||
|
|
||||||
Result<void> set_mount_dir(SharedPtr<VFS::Inode> parent) override;
|
Result<void> set_mount_dir(SharedPtr<VFS::Inode> parent) override;
|
||||||
|
|
||||||
|
Result<void> reset_mount_dir() override;
|
||||||
|
|
||||||
static Result<SharedPtr<VFS::FileSystem>> create();
|
static Result<SharedPtr<VFS::FileSystem>> create();
|
||||||
|
|
||||||
dev_t host_device_id() const override
|
dev_t host_device_id() const override
|
||||||
|
@ -70,7 +70,7 @@ Result<u64> sys_execve(Registers* regs, SyscallArgs args)
|
|||||||
kdbgln("exec: attempting to replace current image with %s", path.chars());
|
kdbgln("exec: attempting to replace current image with %s", path.chars());
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
auto guard = make_scope_guard([current] { MMU::switch_page_directory(current->directory); });
|
auto guard = make_scope_guard([current] { MMU::switch_page_directory(current->self_directory); });
|
||||||
|
|
||||||
auto image = TRY(ThreadImage::try_load_from_elf(inode));
|
auto image = TRY(ThreadImage::try_load_from_elf(inode));
|
||||||
|
|
||||||
@ -99,7 +99,7 @@ Result<u64> sys_execve(Registers* regs, SyscallArgs args)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
MMU::delete_userspace_page_directory(current->directory);
|
MMU::delete_userspace_page_directory(current->self_directory);
|
||||||
|
|
||||||
if (VFS::is_setuid(inode)) current->auth.euid = current->auth.suid = inode->uid();
|
if (VFS::is_setuid(inode)) current->auth.euid = current->auth.suid = inode->uid();
|
||||||
if (VFS::is_setgid(inode)) current->auth.egid = current->auth.sgid = inode->gid();
|
if (VFS::is_setgid(inode)) current->auth.egid = current->auth.sgid = inode->gid();
|
||||||
@ -108,7 +108,7 @@ Result<u64> sys_execve(Registers* regs, SyscallArgs args)
|
|||||||
|
|
||||||
image->apply(current);
|
image->apply(current);
|
||||||
|
|
||||||
MMU::switch_page_directory(current->directory);
|
MMU::switch_page_directory(current->self_directory);
|
||||||
|
|
||||||
current->set_arguments(user_argc, user_argv, user_envc, user_envp);
|
current->set_arguments(user_argc, user_argv, user_envc, user_envp);
|
||||||
|
|
||||||
@ -123,7 +123,7 @@ Result<u64> sys_fork(Registers* regs, SyscallArgs)
|
|||||||
{
|
{
|
||||||
auto current = Scheduler::current();
|
auto current = Scheduler::current();
|
||||||
|
|
||||||
auto guard = make_scope_guard([current] { MMU::switch_page_directory(current->directory); });
|
auto guard = make_scope_guard([current] { MMU::switch_page_directory(current->self_directory); });
|
||||||
|
|
||||||
memcpy(¤t->regs, regs, sizeof(*regs));
|
memcpy(¤t->regs, regs, sizeof(*regs));
|
||||||
|
|
||||||
|
@ -1,4 +1,5 @@
|
|||||||
#include "fs/VFS.h"
|
#include "fs/VFS.h"
|
||||||
|
#include "fs/ext2/FileSystem.h"
|
||||||
#include "fs/tmpfs/FileSystem.h"
|
#include "fs/tmpfs/FileSystem.h"
|
||||||
#include "memory/MemoryManager.h"
|
#include "memory/MemoryManager.h"
|
||||||
#include "sys/Syscall.h"
|
#include "sys/Syscall.h"
|
||||||
@ -8,15 +9,28 @@ Result<u64> sys_mount(Registers*, SyscallArgs args)
|
|||||||
{
|
{
|
||||||
auto target = TRY(MemoryManager::strdup_from_user(args[0]));
|
auto target = TRY(MemoryManager::strdup_from_user(args[0]));
|
||||||
auto fstype = TRY(MemoryManager::strdup_from_user(args[1]));
|
auto fstype = TRY(MemoryManager::strdup_from_user(args[1]));
|
||||||
|
auto source = TRY(MemoryManager::strdup_from_user(args[2]));
|
||||||
|
|
||||||
auto* current = Scheduler::current();
|
auto* current = Scheduler::current();
|
||||||
if (current->auth.euid != 0) return err(EPERM);
|
if (current->auth.euid != 0) return err(EPERM);
|
||||||
|
|
||||||
|
auto get_source = [current, &source]() -> Result<SharedPtr<Device>> {
|
||||||
|
auto inode = TRY(VFS::resolve_path(source.chars(), current->auth, current->current_directory));
|
||||||
|
if (inode->type() != VFS::InodeType::BlockDevice) return err(ENOTBLK);
|
||||||
|
dev_t device_id = inode->device_id();
|
||||||
|
return TRY(DeviceRegistry::fetch_special_device(luna_dev_major(device_id), luna_dev_minor(device_id)));
|
||||||
|
};
|
||||||
|
|
||||||
SharedPtr<VFS::FileSystem> fs;
|
SharedPtr<VFS::FileSystem> fs;
|
||||||
|
|
||||||
if (fstype.view() == "tmpfs") fs = TRY(TmpFS::FileSystem::create());
|
if (fstype.view() == "tmpfs") fs = TRY(TmpFS::FileSystem::create());
|
||||||
else if (fstype.view() == "devfs")
|
else if (fstype.view() == "devfs")
|
||||||
fs = TRY(DeviceRegistry::create_devfs_instance());
|
fs = TRY(DeviceRegistry::create_devfs_instance());
|
||||||
|
else if (fstype.view() == "ext2")
|
||||||
|
{
|
||||||
|
auto source_device = TRY(get_source());
|
||||||
|
fs = TRY(Ext2::FileSystem::create(source_device));
|
||||||
|
}
|
||||||
else
|
else
|
||||||
return err(ENODEV);
|
return err(ENODEV);
|
||||||
|
|
||||||
|
@ -63,6 +63,8 @@ Result<u64> sys_openat(Registers*, SyscallArgs args)
|
|||||||
inode->chown(current->auth.euid, current->auth.egid);
|
inode->chown(current->auth.euid, current->auth.egid);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if ((flags & O_WRONLY) && inode->fs() && inode->fs()->is_readonly()) return err(EROFS);
|
||||||
|
|
||||||
if (inode->type() != VFS::InodeType::Directory && (flags & O_DIRECTORY)) return err(ENOTDIR);
|
if (inode->type() != VFS::InodeType::Directory && (flags & O_DIRECTORY)) return err(ENOTDIR);
|
||||||
|
|
||||||
if (inode->type() == VFS::InodeType::Directory)
|
if (inode->type() == VFS::InodeType::Directory)
|
||||||
|
@ -191,7 +191,7 @@ namespace Scheduler
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!thread->is_kernel) MMU::delete_userspace_page_directory(thread->directory);
|
if (!thread->is_kernel) MMU::delete_userspace_page_directory(thread->self_directory);
|
||||||
|
|
||||||
delete thread;
|
delete thread;
|
||||||
|
|
||||||
@ -235,9 +235,9 @@ namespace Scheduler
|
|||||||
{
|
{
|
||||||
switch_context(old_thread, new_thread, regs);
|
switch_context(old_thread, new_thread, regs);
|
||||||
if (!old_thread->is_kernel) old_thread->fp_data.save();
|
if (!old_thread->is_kernel) old_thread->fp_data.save();
|
||||||
if (old_thread->is_kernel && MMU::get_page_directory() != MMU::kernel_page_directory())
|
if (MMU::get_page_directory() != MMU::kernel_page_directory())
|
||||||
old_thread->directory = MMU::get_page_directory();
|
old_thread->active_directory = MMU::get_page_directory();
|
||||||
if (new_thread->directory) MMU::switch_page_directory(new_thread->directory);
|
if (new_thread->active_directory) MMU::switch_page_directory(new_thread->active_directory);
|
||||||
if (!new_thread->is_kernel)
|
if (!new_thread->is_kernel)
|
||||||
{
|
{
|
||||||
CPU::switch_kernel_stack(new_thread->kernel_stack.top());
|
CPU::switch_kernel_stack(new_thread->kernel_stack.top());
|
||||||
|
@ -97,7 +97,8 @@ struct Thread : public LinkedListNode<Thread>
|
|||||||
Thread* parent { nullptr };
|
Thread* parent { nullptr };
|
||||||
Option<pid_t> child_being_waited_for = {};
|
Option<pid_t> child_being_waited_for = {};
|
||||||
|
|
||||||
PageDirectory* directory;
|
PageDirectory* self_directory;
|
||||||
|
PageDirectory* active_directory { nullptr };
|
||||||
|
|
||||||
[[noreturn]] void exit_and_signal_parent(u8 status);
|
[[noreturn]] void exit_and_signal_parent(u8 status);
|
||||||
|
|
||||||
|
@ -69,7 +69,7 @@ Result<OwnedPtr<ThreadImage>> ThreadImage::clone_from_thread(Thread* parent)
|
|||||||
|
|
||||||
auto vm_allocator = TRY(parent->vm_allocator->clone());
|
auto vm_allocator = TRY(parent->vm_allocator->clone());
|
||||||
|
|
||||||
auto new_directory = TRY(MMU::clone_userspace_page_directory(parent->directory));
|
auto new_directory = TRY(MMU::clone_userspace_page_directory(parent->self_directory));
|
||||||
|
|
||||||
const ELFData data = { .entry = parent->ip() };
|
const ELFData data = { .entry = parent->ip() };
|
||||||
|
|
||||||
@ -124,7 +124,8 @@ void ThreadImage::apply(Thread* thread)
|
|||||||
thread->stack = m_user_stack;
|
thread->stack = m_user_stack;
|
||||||
thread->set_sp(align_down<16>(m_sp));
|
thread->set_sp(align_down<16>(m_sp));
|
||||||
|
|
||||||
thread->directory = m_directory;
|
thread->self_directory = m_directory;
|
||||||
|
thread->active_directory = m_directory;
|
||||||
|
|
||||||
thread->vm_allocator = move(m_vm_allocator);
|
thread->vm_allocator = move(m_vm_allocator);
|
||||||
}
|
}
|
||||||
|
@ -9,7 +9,7 @@ extern "C"
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
/* Mount a file system on target. */
|
/* Mount a file system on target. */
|
||||||
int mount(const char* target, const char* fstype);
|
int mount(const char* target, const char* fstype, const char* source);
|
||||||
|
|
||||||
/* Unmount the file system mounted on target. */
|
/* Unmount the file system mounted on target. */
|
||||||
int umount(const char* target);
|
int umount(const char* target);
|
||||||
|
@ -5,9 +5,9 @@
|
|||||||
|
|
||||||
extern "C"
|
extern "C"
|
||||||
{
|
{
|
||||||
int mount(const char* target, const char* fstype)
|
int mount(const char* target, const char* fstype, const char* source)
|
||||||
{
|
{
|
||||||
long rc = syscall(SYS_mount, target, fstype);
|
long rc = syscall(SYS_mount, target, fstype, source);
|
||||||
__errno_return(rc, int);
|
__errno_return(rc, int);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -32,6 +32,13 @@ template <typename K, typename V> struct HashMap
|
|||||||
return p->value;
|
return p->value;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
V* try_get_ref(const K& key)
|
||||||
|
{
|
||||||
|
auto* p = m_table.try_find(HashPair<K, V> { key, {} });
|
||||||
|
if (!p) return nullptr;
|
||||||
|
return p->value.value_ptr();
|
||||||
|
}
|
||||||
|
|
||||||
bool try_remove(const K& key)
|
bool try_remove(const K& key)
|
||||||
{
|
{
|
||||||
return m_table.try_remove(HashPair<K, V> { key, {} });
|
return m_table.try_remove(HashPair<K, V> { key, {} });
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
#include <luna/Alloc.h>
|
#include <luna/Alloc.h>
|
||||||
#include <luna/Atomic.h>
|
#include <luna/Atomic.h>
|
||||||
|
#include <luna/Hash.h>
|
||||||
#include <luna/OwnedPtr.h>
|
#include <luna/OwnedPtr.h>
|
||||||
#include <luna/Result.h>
|
#include <luna/Result.h>
|
||||||
#include <luna/ScopeGuard.h>
|
#include <luna/ScopeGuard.h>
|
||||||
@ -84,6 +85,11 @@ template <typename T> class SharedPtr
|
|||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool operator==(const SharedPtr<T>& other)
|
||||||
|
{
|
||||||
|
return m_ptr == other.m_ptr && m_ref_count == other.m_ref_count;
|
||||||
|
}
|
||||||
|
|
||||||
T* ptr() const
|
T* ptr() const
|
||||||
{
|
{
|
||||||
return m_ptr;
|
return m_ptr;
|
||||||
|
@ -25,6 +25,16 @@ template <usize Size> class StaticString
|
|||||||
m_length = length;
|
m_length = length;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void adopt(const char* string, usize length)
|
||||||
|
{
|
||||||
|
if (length > Size) length = Size;
|
||||||
|
|
||||||
|
memcpy(m_buffer, string, length);
|
||||||
|
|
||||||
|
m_buffer[length] = 0;
|
||||||
|
m_length = length;
|
||||||
|
}
|
||||||
|
|
||||||
void adopt(StringView string)
|
void adopt(StringView string)
|
||||||
{
|
{
|
||||||
usize length = strlcpy(m_buffer, string.chars(),
|
usize length = strlcpy(m_buffer, string.chars(),
|
||||||
|
@ -16,9 +16,8 @@
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
"type": "ext2",
|
"type": "ext2",
|
||||||
"size": 2,
|
"file": "build/ext2fs.bin",
|
||||||
"directory": "base",
|
"name": "luna-rootfs"
|
||||||
"name": "sysroot"
|
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
@ -7,4 +7,6 @@ cd $LUNA_ROOT
|
|||||||
|
|
||||||
fakeroot -u -s $LUNA_ROOT/.fakeroot -- tools/install.sh
|
fakeroot -u -s $LUNA_ROOT/.fakeroot -- tools/install.sh
|
||||||
|
|
||||||
fakeroot -u -i $LUNA_ROOT/.fakeroot -- mkbootimg luna.json Luna.iso
|
genext2fs -d base -B 4096 -b 1024 -L luna-rootfs -U -N 1024 build/ext2fs.bin
|
||||||
|
|
||||||
|
fakeroot -u -i $LUNA_ROOT/.fakeroot mkbootimg luna.json Luna.iso
|
||||||
|
Loading…
Reference in New Issue
Block a user