Kernel: Allow arbitrary sized tmpfs files
The 2 block limit started to get annoying :D
This commit is contained in:
parent
bac06e45a4
commit
107b092982
|
@ -53,11 +53,16 @@ namespace Kernel
|
|||
virtual BAN::ErrorOr<void> fsync_impl() override { return {}; }
|
||||
|
||||
void sync();
|
||||
void free_all_blocks();
|
||||
virtual BAN::ErrorOr<void> prepare_unlink() { return {}; };
|
||||
|
||||
void free_all_blocks();
|
||||
void free_indirect_blocks(size_t block, uint32_t depth);
|
||||
|
||||
BAN::Optional<size_t> block_index(size_t data_block_index);
|
||||
BAN::Optional<size_t> block_index_from_indirect(size_t block, size_t index, uint32_t depth);
|
||||
|
||||
BAN::ErrorOr<size_t> block_index_with_allocation(size_t data_block_index);
|
||||
BAN::ErrorOr<size_t> block_index_from_indirect_with_allocation(size_t& block, size_t index, uint32_t depth);
|
||||
|
||||
protected:
|
||||
TmpFileSystem& m_fs;
|
||||
|
|
|
@ -124,36 +124,160 @@ namespace Kernel
|
|||
void TmpInode::free_all_blocks()
|
||||
{
|
||||
for (size_t i = 0; i < TmpInodeInfo::direct_block_count; i++)
|
||||
{
|
||||
if (m_inode_info.block[i])
|
||||
m_fs.free_block(m_inode_info.block[i]);
|
||||
m_inode_info.block[i] = 0;
|
||||
if (size_t block = m_inode_info.block[TmpInodeInfo::direct_block_count + 0])
|
||||
free_indirect_blocks(block, 1);
|
||||
if (size_t block = m_inode_info.block[TmpInodeInfo::direct_block_count + 1])
|
||||
free_indirect_blocks(block, 2);
|
||||
if (size_t block = m_inode_info.block[TmpInodeInfo::direct_block_count + 2])
|
||||
free_indirect_blocks(block, 3);
|
||||
for (auto& block : m_inode_info.block)
|
||||
block = 0;
|
||||
}
|
||||
|
||||
void TmpInode::free_indirect_blocks(size_t block, uint32_t depth)
|
||||
{
|
||||
ASSERT(block != 0);
|
||||
|
||||
if (depth == 0)
|
||||
{
|
||||
m_fs.free_block(block);
|
||||
return;
|
||||
}
|
||||
for (auto block : m_inode_info.block)
|
||||
ASSERT(block == 0);
|
||||
|
||||
const size_t indices_per_block = blksize() / sizeof(size_t);
|
||||
for (size_t index = 0; index < indices_per_block; index++)
|
||||
{
|
||||
size_t next_block;
|
||||
m_fs.with_block_buffer(block, [&](BAN::ByteSpan block_buffer) {
|
||||
next_block = block_buffer.as_span<size_t>()[index];
|
||||
});
|
||||
|
||||
if (next_block == 0)
|
||||
continue;
|
||||
|
||||
free_indirect_blocks(next_block, depth - 1);
|
||||
}
|
||||
|
||||
m_fs.free_block(block);
|
||||
}
|
||||
|
||||
BAN::Optional<size_t> TmpInode::block_index(size_t data_block_index)
|
||||
{
|
||||
ASSERT(data_block_index < TmpInodeInfo::direct_block_count);
|
||||
if (m_inode_info.block[data_block_index])
|
||||
if (data_block_index < TmpInodeInfo::direct_block_count)
|
||||
{
|
||||
if (m_inode_info.block[data_block_index] == 0)
|
||||
return {};
|
||||
return m_inode_info.block[data_block_index];
|
||||
return {};
|
||||
}
|
||||
data_block_index -= TmpInodeInfo::direct_block_count;
|
||||
|
||||
const size_t indices_per_block = blksize() / sizeof(size_t);
|
||||
|
||||
if (data_block_index < indices_per_block)
|
||||
return block_index_from_indirect(m_inode_info.block[TmpInodeInfo::direct_block_count + 0], data_block_index, 1);
|
||||
data_block_index -= indices_per_block;
|
||||
|
||||
if (data_block_index < indices_per_block * indices_per_block)
|
||||
return block_index_from_indirect(m_inode_info.block[TmpInodeInfo::direct_block_count + 1], data_block_index, 2);
|
||||
data_block_index -= indices_per_block * indices_per_block;
|
||||
|
||||
if (data_block_index < indices_per_block * indices_per_block * indices_per_block)
|
||||
return block_index_from_indirect(m_inode_info.block[TmpInodeInfo::direct_block_count + 2], data_block_index, 3);
|
||||
|
||||
ASSERT_NOT_REACHED();
|
||||
}
|
||||
|
||||
BAN::Optional<size_t> TmpInode::block_index_from_indirect(size_t block, size_t index, uint32_t depth)
|
||||
{
|
||||
if (block == 0)
|
||||
return {};
|
||||
ASSERT(depth >= 1);
|
||||
|
||||
const size_t indices_per_block = blksize() / sizeof(size_t);
|
||||
|
||||
size_t divisor = 1;
|
||||
for (size_t i = 1; i < depth; i++)
|
||||
divisor *= indices_per_block;
|
||||
|
||||
size_t next_block;
|
||||
m_fs.with_block_buffer(block, [&](BAN::ByteSpan block_buffer) {
|
||||
next_block = block_buffer.as_span<size_t>()[(index / divisor) % indices_per_block];
|
||||
});
|
||||
|
||||
if (next_block == 0)
|
||||
return {};
|
||||
|
||||
if (depth == 1)
|
||||
return next_block;
|
||||
|
||||
return block_index_from_indirect(next_block, index, depth - 1);
|
||||
}
|
||||
|
||||
BAN::ErrorOr<size_t> TmpInode::block_index_with_allocation(size_t data_block_index)
|
||||
{
|
||||
if (data_block_index >= TmpInodeInfo::direct_block_count)
|
||||
if (data_block_index < TmpInodeInfo::direct_block_count)
|
||||
{
|
||||
dprintln("only {} blocks supported :D", TmpInodeInfo::direct_block_count);
|
||||
return BAN::Error::from_errno(ENOSPC);
|
||||
if (m_inode_info.block[data_block_index] == 0)
|
||||
{
|
||||
m_inode_info.block[data_block_index] = TRY(m_fs.allocate_block());
|
||||
m_inode_info.blocks++;
|
||||
}
|
||||
return m_inode_info.block[data_block_index];
|
||||
}
|
||||
if (m_inode_info.block[data_block_index] == 0)
|
||||
data_block_index -= TmpInodeInfo::direct_block_count;
|
||||
|
||||
const size_t indices_per_block = blksize() / sizeof(size_t);
|
||||
|
||||
if (data_block_index < indices_per_block)
|
||||
return block_index_from_indirect_with_allocation(m_inode_info.block[TmpInodeInfo::direct_block_count + 0], data_block_index, 1);
|
||||
data_block_index -= indices_per_block;
|
||||
|
||||
if (data_block_index < indices_per_block * indices_per_block)
|
||||
return block_index_from_indirect_with_allocation(m_inode_info.block[TmpInodeInfo::direct_block_count + 1], data_block_index, 2);
|
||||
data_block_index -= indices_per_block * indices_per_block;
|
||||
|
||||
if (data_block_index < indices_per_block * indices_per_block * indices_per_block)
|
||||
return block_index_from_indirect_with_allocation(m_inode_info.block[TmpInodeInfo::direct_block_count + 2], data_block_index, 3);
|
||||
|
||||
ASSERT_NOT_REACHED();
|
||||
}
|
||||
|
||||
BAN::ErrorOr<size_t> TmpInode::block_index_from_indirect_with_allocation(size_t& block, size_t index, uint32_t depth)
|
||||
{
|
||||
if (block == 0)
|
||||
{
|
||||
m_inode_info.block[data_block_index] = TRY(m_fs.allocate_block());
|
||||
block = TRY(m_fs.allocate_block());
|
||||
m_inode_info.blocks++;
|
||||
}
|
||||
return m_inode_info.block[data_block_index];
|
||||
ASSERT(depth >= 1);
|
||||
|
||||
const size_t indices_per_block = blksize() / sizeof(size_t);
|
||||
|
||||
size_t divisor = 1;
|
||||
for (size_t i = 1; i < depth; i++)
|
||||
divisor *= indices_per_block;
|
||||
|
||||
size_t next_block;
|
||||
m_fs.with_block_buffer(block, [&](BAN::ByteSpan block_buffer) {
|
||||
next_block = block_buffer.as_span<size_t>()[(index / divisor) % indices_per_block];
|
||||
});
|
||||
|
||||
if (next_block == 0)
|
||||
{
|
||||
next_block = TRY(m_fs.allocate_block());
|
||||
m_inode_info.blocks++;
|
||||
|
||||
m_fs.with_block_buffer(block, [&](BAN::ByteSpan block_buffer) {
|
||||
block_buffer.as_span<size_t>()[(index / divisor) % indices_per_block] = next_block;
|
||||
});
|
||||
}
|
||||
|
||||
if (depth == 1)
|
||||
return next_block;
|
||||
|
||||
return block_index_from_indirect_with_allocation(next_block, index, depth - 1);
|
||||
}
|
||||
|
||||
/* FILE INODE */
|
||||
|
@ -241,6 +365,9 @@ namespace Kernel
|
|||
|
||||
BAN::ErrorOr<void> TmpFileInode::truncate_impl(size_t new_size)
|
||||
{
|
||||
// FIXME: if size is decreased, we should probably free
|
||||
// unused blocks
|
||||
|
||||
m_inode_info.size = new_size;
|
||||
return {};
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue