mirror of
https://github.com/RGBCube/serenity
synced 2025-05-20 14:55:08 +00:00
Ext2FS: Support shrinking inode to a smaller size.
Factor out inode resizing into a separate Ext2FSInode::resize() function. This is then called both from write_bytes() and truncate(). This patch finally implements freeing of blocks when an inode shrinks.
This commit is contained in:
parent
89df887e1f
commit
899f6a5de2
2 changed files with 50 additions and 30 deletions
|
@ -216,6 +216,10 @@ bool Ext2FS::write_block_list_for_inode(InodeIndex inode_index, ext2_inode& e2in
|
|||
}
|
||||
if (inode_dirty) {
|
||||
dbgprintf("Ext2FS: Writing %u direct block(s) to i_block array of inode %u\n", min(EXT2_NDIR_BLOCKS, blocks.size()), inode_index);
|
||||
#ifdef EXT2_DEBUG
|
||||
for (int i = 0; i < min(EXT2_NDIR_BLOCKS, blocks.size()); ++i)
|
||||
dbgprintf(" + %u\n", blocks[i]);
|
||||
#endif
|
||||
write_ext2_inode(inode_index, e2inode);
|
||||
inode_dirty = false;
|
||||
}
|
||||
|
@ -512,6 +516,40 @@ ssize_t Ext2FSInode::read_bytes(off_t offset, ssize_t count, byte* buffer, FileD
|
|||
return nread;
|
||||
}
|
||||
|
||||
bool Ext2FSInode::resize(qword new_size)
|
||||
{
|
||||
qword block_size = fs().block_size();
|
||||
qword old_size = size();
|
||||
int blocks_needed_before = ceil_div(old_size, block_size);
|
||||
int blocks_needed_after = ceil_div(new_size, block_size);
|
||||
|
||||
dbgprintf("blocks needed before (size was %u): %d\n", old_size, blocks_needed_before);
|
||||
dbgprintf("blocks needed after (size is %u): %d\n", new_size, blocks_needed_after);
|
||||
|
||||
auto block_list = fs().block_list_for_inode(m_raw_inode);
|
||||
if (blocks_needed_after > blocks_needed_before) {
|
||||
auto new_blocks = fs().allocate_blocks(fs().group_index_from_inode(index()), blocks_needed_after - blocks_needed_before);
|
||||
for (auto new_block_index : new_blocks)
|
||||
fs().set_block_allocation_state(new_block_index, true);
|
||||
block_list.append(move(new_blocks));
|
||||
} else if (blocks_needed_after < blocks_needed_before) {
|
||||
while (block_list.size() != blocks_needed_after) {
|
||||
auto block_index = block_list.take_last();
|
||||
fs().set_block_allocation_state(block_index, false);
|
||||
}
|
||||
}
|
||||
|
||||
bool success = fs().write_block_list_for_inode(index(), m_raw_inode, block_list);
|
||||
if (!success)
|
||||
return false;
|
||||
|
||||
m_raw_inode.i_size = new_size;
|
||||
set_metadata_dirty(true);
|
||||
|
||||
m_block_list = move(block_list);
|
||||
return true;
|
||||
}
|
||||
|
||||
ssize_t Ext2FSInode::write_bytes(off_t offset, ssize_t count, const byte* data, FileDescriptor*)
|
||||
{
|
||||
ASSERT(offset >= 0);
|
||||
|
@ -534,27 +572,16 @@ ssize_t Ext2FSInode::write_bytes(off_t offset, ssize_t count, const byte* data,
|
|||
}
|
||||
|
||||
const ssize_t block_size = fs().block_size();
|
||||
size_t old_size = size();
|
||||
size_t new_size = max(static_cast<size_t>(offset) + count, size());
|
||||
qword old_size = size();
|
||||
qword new_size = max(static_cast<qword>(offset) + count, (qword)size());
|
||||
|
||||
unsigned blocks_needed_before = ceil_div(size(), block_size);
|
||||
unsigned blocks_needed_after = ceil_div(new_size, block_size);
|
||||
|
||||
auto block_list = fs().block_list_for_inode(m_raw_inode);
|
||||
if (blocks_needed_after > blocks_needed_before) {
|
||||
auto new_blocks = fs().allocate_blocks(fs().group_index_from_inode(index()), blocks_needed_after - blocks_needed_before);
|
||||
for (auto new_block_index : new_blocks)
|
||||
fs().set_block_allocation_state(new_block_index, true);
|
||||
block_list.append(move(new_blocks));
|
||||
} else if (blocks_needed_after < blocks_needed_before) {
|
||||
// FIXME: Implement block list shrinking!
|
||||
ASSERT_NOT_REACHED();
|
||||
}
|
||||
if (!resize(new_size))
|
||||
return -EIO;
|
||||
|
||||
int first_block_logical_index = offset / block_size;
|
||||
int last_block_logical_index = (offset + count) / block_size;
|
||||
if (last_block_logical_index >= block_list.size())
|
||||
last_block_logical_index = block_list.size() - 1;
|
||||
if (last_block_logical_index >= m_block_list.size())
|
||||
last_block_logical_index = m_block_list.size() - 1;
|
||||
|
||||
int offset_into_first_block = offset % block_size;
|
||||
|
||||
|
@ -575,9 +602,9 @@ ssize_t Ext2FSInode::write_bytes(off_t offset, ssize_t count, const byte* data,
|
|||
|
||||
ByteBuffer block;
|
||||
if (offset_into_block != 0 || num_bytes_to_copy != block_size) {
|
||||
block = fs().read_block(block_list[bi]);
|
||||
block = fs().read_block(m_block_list[bi]);
|
||||
if (!block) {
|
||||
kprintf("Ext2FSInode::write_bytes: read_block(%u) failed (lbi: %u)\n", block_list[bi], bi);
|
||||
kprintf("Ext2FSInode::write_bytes: read_block(%u) failed (lbi: %u)\n", m_block_list[bi], bi);
|
||||
return -EIO;
|
||||
}
|
||||
} else
|
||||
|
@ -595,9 +622,9 @@ ssize_t Ext2FSInode::write_bytes(off_t offset, ssize_t count, const byte* data,
|
|||
#ifdef EXT2_DEBUG
|
||||
dbgprintf("Ext2FSInode::write_bytes: writing block %u (offset_into_block: %u)\n", block_list[bi], offset_into_block);
|
||||
#endif
|
||||
bool success = fs().write_block(block_list[bi], block);
|
||||
bool success = fs().write_block(m_block_list[bi], block);
|
||||
if (!success) {
|
||||
kprintf("Ext2FSInode::write_bytes: write_block(%u) failed (lbi: %u)\n", block_list[bi], bi);
|
||||
kprintf("Ext2FSInode::write_bytes: write_block(%u) failed (lbi: %u)\n", m_block_list[bi], bi);
|
||||
ASSERT_NOT_REACHED();
|
||||
return -EIO;
|
||||
}
|
||||
|
@ -606,18 +633,10 @@ ssize_t Ext2FSInode::write_bytes(off_t offset, ssize_t count, const byte* data,
|
|||
in += num_bytes_to_copy;
|
||||
}
|
||||
|
||||
bool success = fs().write_block_list_for_inode(index(), m_raw_inode, block_list);
|
||||
ASSERT(success);
|
||||
|
||||
m_raw_inode.i_size = new_size;
|
||||
fs().write_ext2_inode(index(), m_raw_inode);
|
||||
#ifdef EXT2_DEBUG
|
||||
dbgprintf("Ext2FSInode::write_bytes: after write, i_size=%u, i_blocks=%u (%u blocks in list)\n", m_raw_inode.i_size, m_raw_inode.i_blocks, block_list.size());
|
||||
#endif
|
||||
|
||||
// NOTE: Make sure the cached block list is up to date!
|
||||
m_block_list = move(block_list);
|
||||
|
||||
if (old_size != new_size)
|
||||
inode_size_changed(old_size, new_size);
|
||||
inode_contents_changed(offset, count, data);
|
||||
|
@ -1330,7 +1349,7 @@ KResult Ext2FSInode::truncate(off_t size)
|
|||
LOCKER(m_lock);
|
||||
if ((off_t)m_raw_inode.i_size == size)
|
||||
return KSuccess;
|
||||
m_raw_inode.i_size = size;
|
||||
resize(size);
|
||||
set_metadata_dirty(true);
|
||||
return KSuccess;
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue