Newer
Older
minerva / Kernel / FileSystem / Ext2FS / BlockView.cpp
@minerva minerva on 13 Jul 2 KB Initial commit
/*
 * Copyright (c) 2024, the SerenityOS developers.
 *
 * SPDX-License-Identifier: BSD-2-Clause
 */

#include <Kernel/FileSystem/Ext2FS/BlockView.h>
#include <Kernel/FileSystem/Ext2FS/Inode.h>

namespace Kernel {

static constexpr size_t max_blocks_in_view = 16384; // 2^14

Ext2FSBlockView::Ext2FSBlockView(Ext2FSInode& inode)
    : m_inode(inode) {};

ErrorOr<void> Ext2FSBlockView::ensure_block(BlockBasedFileSystem::BlockIndex block)
{
    VERIFY(m_block_list_lock.is_locked());
    if (block >= m_first_block && block <= m_last_block && m_block_list_initialized.was_set())
        return {};

    BlockBasedFileSystem::BlockIndex new_first_block = (block.value() / max_blocks_in_view) * max_blocks_in_view;
    BlockBasedFileSystem::BlockIndex new_last_block = new_first_block.value() + max_blocks_in_view - 1;

    m_block_list = TRY(m_inode.compute_block_list(new_first_block, new_last_block));

    m_first_block = new_first_block;
    m_last_block = new_last_block;

    m_block_list_initialized.set();

    return {};
}

ErrorOr<BlockBasedFileSystem::BlockIndex> Ext2FSBlockView::get_block(BlockBasedFileSystem::BlockIndex block)
{
    MutexLocker block_list_locker(m_block_list_lock);
    TRY(ensure_block(block));

    auto it = m_block_list.find(block);
    if (it == m_block_list.end())
        return BlockBasedFileSystem::BlockIndex { 0 };

    auto on_disk_block = (*it).value;
    VERIFY(on_disk_block != 0);
    return on_disk_block;
}

ErrorOr<BlockBasedFileSystem::BlockIndex> Ext2FSBlockView::get_or_allocate_block(BlockBasedFileSystem::BlockIndex block, bool zero_newly_allocated_block, bool allow_cache)
{
    MutexLocker block_list_locker(m_block_list_lock);
    TRY(ensure_block(block));

    auto it = m_block_list.find(block);
    if (it != m_block_list.end()) {
        auto on_disk_block = (*it).value;
        VERIFY(on_disk_block != 0);
        return on_disk_block;
    }

    auto on_disk_block = TRY(m_inode.allocate_block(block, zero_newly_allocated_block, allow_cache));
    TRY(m_block_list.try_set(block, on_disk_block));

    return on_disk_block;
}

ErrorOr<void> Ext2FSBlockView::write_block_pointer(BlockBasedFileSystem::BlockIndex logical_block_index, BlockBasedFileSystem::BlockIndex on_disk_index)
{
    MutexLocker block_list_locker(m_block_list_lock);

    TRY(m_inode.write_block_pointer(logical_block_index, on_disk_index));

    if (on_disk_index == 0)
        m_block_list.remove(logical_block_index);
    else
        TRY(m_block_list.try_set(logical_block_index, on_disk_index));

    return {};
}

}