From da296f58659f740f18f8eaa9a539385908ed34b3 Mon Sep 17 00:00:00 2001 From: Marios Prokopakis Date: Sun, 26 Jan 2020 10:48:24 +0200 Subject: [PATCH] Ext2FS: allocate_blocks allocates contiguous blocks (#1095) This implementation uses the new helper method of Bitmap called find_longest_range_of_unset_bits. This method looks for the biggest range of contiguous bits unset in the bitmap and returns the start of the range back to the caller. --- AK/Bitmap.h | 41 ++++++++++++++++++++++++- Kernel/FileSystem/Ext2FileSystem.cpp | 45 +++++++++++++++++++++++++--- 2 files changed, 81 insertions(+), 5 deletions(-) diff --git a/AK/Bitmap.h b/AK/Bitmap.h index 4e00add6a1..b368bab231 100644 --- a/AK/Bitmap.h +++ b/AK/Bitmap.h @@ -157,6 +157,46 @@ public: return -1; } + int find_longest_range_of_unset_bits(int max_length, int& found_range_size) const + { + int first_index = find_first_unset(); + if (first_index == -1) + return -1; + + int free_region_start = first_index; + int free_region_size = 1; + + int max_region_start = free_region_start; + int max_region_size = free_region_size; + + // Let's try and find the best fit possible + for (int j = first_index + 1; j < m_size && free_region_size < max_length; j++) { + if (!get(j)) { + if (free_region_size == 0) + free_region_start = j; + free_region_size++; + } else { + if (max_region_size < free_region_size) { + max_region_size = free_region_size; + max_region_start = free_region_start; + } + free_region_start = 0; + free_region_size = 0; + } + } + + if (max_region_size < free_region_size) { + max_region_size = free_region_size; + max_region_start = free_region_start; + } + + found_range_size = max_region_size; + if (max_region_size > 1) + return max_region_start; + // if the max free region size is one, then return the earliest one found + return first_index; + } + explicit Bitmap() : m_size(0) , m_owned(true) @@ -181,7 +221,6 @@ public: } private: - int size_in_bytes() const { return ceil_div(m_size, 8); } u8* m_data { nullptr }; diff --git a/Kernel/FileSystem/Ext2FileSystem.cpp b/Kernel/FileSystem/Ext2FileSystem.cpp index dbd2d6d634..4257b4b1fb 100644 --- a/Kernel/FileSystem/Ext2FileSystem.cpp +++ b/Kernel/FileSystem/Ext2FileSystem.cpp @@ -1080,12 +1080,49 @@ Vector Ext2FS::allocate_blocks(GroupIndex preferred_group_in dbg() << "Ext2FS: allocate_blocks:"; #endif blocks.ensure_capacity(count); - for (int i = 0; i < count; ++i) { - auto block_index = allocate_block(preferred_group_index); - blocks.unchecked_append(block_index); + + bool found_a_group = false; + GroupIndex group_index = preferred_group_index; + + if (!group_descriptor(preferred_group_index).bg_free_blocks_count) { + group_index = 1; + } + + while (blocks.size() < count) { + if (group_descriptor(group_index).bg_free_blocks_count) { + found_a_group = true; + } else { + if (group_index == preferred_group_index) + group_index = 1; + for (; group_index < m_block_group_count; ++group_index) { + if (group_descriptor(group_index).bg_free_blocks_count) { + found_a_group = true; + break; + } + } + } + ASSERT(found_a_group); + auto& bgd = group_descriptor(group_index); + auto& cached_bitmap = get_bitmap_block(bgd.bg_block_bitmap); + + int blocks_in_group = min(blocks_per_group(), super_block().s_blocks_count); + auto block_bitmap = Bitmap::wrap(cached_bitmap.buffer.data(), blocks_in_group); + + BlockIndex first_block_in_group = (group_index - 1) * blocks_per_group() + first_block_index(); + int free_region_size = 0; + int first_unset_bit_index = block_bitmap.find_longest_range_of_unset_bits(count - blocks.size(), free_region_size); + ASSERT(first_unset_bit_index != -1); #ifdef EXT2_DEBUG - dbg() << " > " << block_index; + dbg() << "Ext2FS: allocating free region of size: " << free_region_size << "[" << group_index << "]"; #endif + for (int i = 0; i < free_region_size; ++i) { + BlockIndex block_index = (unsigned)(first_unset_bit_index + i) + first_block_in_group; + set_block_allocation_state(block_index, true); + blocks.unchecked_append(block_index); +#ifdef EXT2_DEBUG + dbg() << " allocated > " << block_index; +#endif + } } ASSERT(blocks.size() == count);