From a1eba4766f71afb97f7e7582e2c25a6b5cb2cf3a Mon Sep 17 00:00:00 2001 From: Chaoqun Zheng Date: Thu, 29 Jan 2026 09:13:56 +0800 Subject: [PATCH] Fix the updating strategy of `InodeDesc::occupied_sectors_count`. --- kernel/src/fs/ext2/inode.rs | 26 +++++++++++++++++--------- 1 file changed, 17 insertions(+), 9 deletions(-) diff --git a/kernel/src/fs/ext2/inode.rs b/kernel/src/fs/ext2/inode.rs index 2fdeb1f9d..a424cf3d5 100644 --- a/kernel/src/fs/ext2/inode.rs +++ b/kernel/src/fs/ext2/inode.rs @@ -1889,12 +1889,14 @@ impl InodeImpl { /// After the reduction, the block count will be decreased to `range.start`. fn shrink_blocks(&mut self, range: Range) { let mut current_range = range.clone(); + let mut total_freed_blocks = 0; while !current_range.is_empty() { - let free_cnt = self.try_shrink_blocks(current_range.clone()); + let (free_cnt, freed_blocks) = self.try_shrink_blocks(current_range.clone()); + total_freed_blocks += freed_blocks; current_range.end -= free_cnt; } - self.desc.occupied_sectors_count -= blocks_to_sectors(range.len() as u32); + self.desc.occupied_sectors_count -= blocks_to_sectors(total_freed_blocks); self.last_alloc_device_bid = if range.start == 0 { None } else { @@ -1910,9 +1912,9 @@ impl InodeImpl { /// Attempts to shrink a range of blocks and returns the number of blocks /// successfully freed. /// - /// Note that the returned number may be less than the requested range if needs + /// Note that the first returned number may be less than the requested range if needs /// to free the indirect blocks that are no longer required. - fn try_shrink_blocks(&mut self, range: Range) -> Ext2Bid { + fn try_shrink_blocks(&mut self, range: Range) -> (Ext2Bid, u32) { // Calculates the maximum range of blocks that can be freed in this round. let range = { let max_cnt = (range.len() as Ext2Bid) @@ -1923,12 +1925,14 @@ impl InodeImpl { let fs = self.fs(); let device_range_reader = DeviceRangeReader::new(&self.block_manager, range.clone()).unwrap(); + let mut freed_blocks = 0u32; for device_range in device_range_reader { + freed_blocks += device_range.len() as u32; fs.free_blocks(device_range.clone()).unwrap(); } self.free_indirect_blocks_required_by(range.start).unwrap(); - range.len() as Ext2Bid + (range.len() as Ext2Bid, freed_blocks) } /// Deallocate inode blocks in a specified range. @@ -1936,12 +1940,14 @@ impl InodeImpl { /// After the reduction, the block count will be decreased `range.len`. fn dealloc_range_blocks(&mut self, range: Range) { let mut current_range = range.clone(); + let mut total_freed_blocks = 0; while !current_range.is_empty() { - let free_cnt = self.try_dealloc_range_blocks(current_range.clone()); + let (free_cnt, freed_blocks) = self.try_dealloc_range_blocks(current_range.clone()); + total_freed_blocks += freed_blocks; current_range.end -= free_cnt; } - self.desc.occupied_sectors_count -= blocks_to_sectors(range.len() as u32); + self.desc.occupied_sectors_count -= blocks_to_sectors(total_freed_blocks); self.last_alloc_device_bid = if range.start == 0 { None } else { @@ -1959,7 +1965,7 @@ impl InodeImpl { /// /// Note that the returned number may be less than the requested range if needs /// to free the indirect blocks that are no longer required. - fn try_dealloc_range_blocks(&mut self, range: Range) -> Ext2Bid { + fn try_dealloc_range_blocks(&mut self, range: Range) -> (Ext2Bid, u32) { // Calculates the maximum range of blocks that can be freed in this round. let range = { let max_cnt = (range.len() as Ext2Bid) @@ -1967,6 +1973,7 @@ impl InodeImpl { (range.end - max_cnt)..range.end }; + let mut freed_blocks = 0u32; for bid in range.clone() { let bid_path = BidPath::from(bid); let device_bid = self.get_device_bid(bid).unwrap(); @@ -1974,6 +1981,7 @@ impl InodeImpl { continue; } + freed_blocks += 1; self.fs().free_blocks(device_bid..device_bid + 1).unwrap(); match bid_path { BidPath::Direct(idx) => { @@ -2026,7 +2034,7 @@ impl InodeImpl { } self.free_indirect_blocks_required_by(range.start).unwrap(); - range.len() as Ext2Bid + (range.len() as Ext2Bid, freed_blocks) } /// Frees the indirect blocks required by the specified block ID.