From 7a10e0e347b3d44608c883d333f5e0301eb2ca32 Mon Sep 17 00:00:00 2001 From: Bananymous Date: Tue, 28 Jan 2025 17:06:35 +0200 Subject: [PATCH] Kernel: Fix TmpFS inode linking TmpFS now looks for empty entries in directories instead of always appending files to the end of directories. This makes kernel not crash after process pid 126 is created :D --- kernel/kernel/FS/TmpFS/Inode.cpp | 97 ++++++++++++++++++++++++-------- 1 file changed, 72 insertions(+), 25 deletions(-) diff --git a/kernel/kernel/FS/TmpFS/Inode.cpp b/kernel/kernel/FS/TmpFS/Inode.cpp index ec7f12a4..a7d3d979 100644 --- a/kernel/kernel/FS/TmpFS/Inode.cpp +++ b/kernel/kernel/FS/TmpFS/Inode.cpp @@ -562,39 +562,86 @@ namespace Kernel new_entry_size += directory_entry_alignment - rem; ASSERT(new_entry_size < (size_t)blksize()); - size_t new_entry_offset = size() % blksize(); - - // Target is the last block, or if it doesn't fit the new entry, the next one. - size_t target_data_block = size() / blksize(); - if (blksize() - new_entry_offset < new_entry_size) + for (size_t data_block_index = 0; data_block_index * blksize() < (size_t)size(); data_block_index++) { - // insert an empty entry at the end of current block - m_fs.with_block_buffer(block_index(target_data_block).value(), [&](BAN::ByteSpan bytespan) { - auto& empty_entry = bytespan.slice(new_entry_offset).as(); - empty_entry.type = DT_UNKNOWN; - empty_entry.ino = 0; - empty_entry.rec_len = blksize() - new_entry_offset; - }); - m_inode_info.size += blksize() - new_entry_offset; + const size_t block_index = this->block_index(data_block_index).value(); - target_data_block++; - new_entry_offset = 0; + bool done = false; + m_fs.with_block_buffer(block_index, [&](BAN::ByteSpan bytespan) { + bytespan = bytespan.slice(0, blksize()); + while (bytespan.size() > 0) + { + auto& entry = bytespan.as(); + + while (entry.ino == 0 && entry.rec_len < bytespan.size()) + { + auto& next_entry = bytespan.slice(entry.rec_len).as(); + if (next_entry.ino) + break; + entry.rec_len += next_entry.rec_len; + } + + if (entry.ino != 0 || entry.rec_len < new_entry_size) + { + bytespan = bytespan.slice(entry.rec_len); + continue; + } + + if (entry.rec_len <= new_entry_size + sizeof(TmpDirectoryEntry)) + new_entry_size = entry.rec_len; + else + { + auto& new_entry = bytespan.slice(new_entry_size).as(); + new_entry.type = DT_UNKNOWN; + new_entry.ino = 0; + new_entry.rec_len = entry.rec_len - new_entry_size; + } + + ASSERT(entry.type == DT_UNKNOWN); + entry.type = inode_mode_to_dt_type(inode.mode()); + entry.ino = inode.ino(); + entry.name_len = name.size(); + entry.rec_len = new_entry_size; + memcpy(entry.name, name.data(), name.size()); + + done = true; + break; + } + }); + + if (done) + { + // add link to linked inode + inode.m_inode_info.nlink++; + return {}; + } } - size_t block_index = TRY(block_index_with_allocation(target_data_block)); + const size_t data_block_index = size() / blksize(); + const size_t block_index = TRY(block_index_with_allocation(data_block_index)); m_fs.with_block_buffer(block_index, [&](BAN::ByteSpan bytespan) { - auto& new_entry = bytespan.slice(new_entry_offset).as(); - ASSERT(new_entry.type == DT_UNKNOWN); - new_entry.type = inode_mode_to_dt_type(inode.mode()); - new_entry.ino = inode.ino(); - new_entry.name_len = name.size(); - new_entry.rec_len = new_entry_size; - memcpy(new_entry.name, name.data(), name.size()); + // insert new inode + { + auto& entry = bytespan.as(); + entry.type = inode_mode_to_dt_type(inode.mode()); + entry.ino = inode.ino(); + entry.name_len = name.size(); + entry.rec_len = new_entry_size; + memcpy(entry.name, name.data(), name.size()); + } + + // insert null entry + { + auto& entry = bytespan.slice(new_entry_size).as(); + entry.type = DT_UNKNOWN; + entry.ino = 0; + entry.rec_len = blksize() - new_entry_size; + } }); // increase current size - m_inode_info.size += new_entry_size; + m_inode_info.size += blksize(); // add link to linked inode inode.m_inode_info.nlink++; @@ -616,7 +663,7 @@ namespace Kernel while (bytespan.size() > 0) { auto& entry = bytespan.as(); - if (entry.type != DT_UNKNOWN) + if (entry.ino != 0) { switch (callback(entry)) {