diff --git a/kernel/src/fs/ext2/blocks_hole.rs b/kernel/src/fs/ext2/blocks_hole.rs deleted file mode 100644 index 40509a7fa..000000000 --- a/kernel/src/fs/ext2/blocks_hole.rs +++ /dev/null @@ -1,84 +0,0 @@ -// SPDX-License-Identifier: MPL-2.0 - -#![allow(dead_code)] - -use core::ops::Range; - -use bitvec::prelude::BitVec; - -/// A blocks hole descriptor implemented by the `BitVec`. -/// -/// The true bit implies that the block is a hole, and conversely. -pub(super) struct BlocksHoleDesc(BitVec); - -impl BlocksHoleDesc { - /// Constructs a blocks hole descriptor with initial size. - /// - /// The `initial_size` usually is the number of blocks for a file. - pub fn new(initial_size: usize) -> Self { - let mut bit_vec = BitVec::with_capacity(initial_size); - bit_vec.resize(initial_size, false); - Self(bit_vec) - } - - /// Returns the size. - pub fn size(&self) -> usize { - self.0.len() - } - - /// Resizes the blocks hole to a new size. - /// - /// If `new_size` is greater than current size, the new blocks are all marked as hole. - pub fn resize(&mut self, new_size: usize) { - self.0.resize(new_size, true); - } - - /// Returns if the block `idx` is a hole. - /// - /// # Panics - /// - /// If the `idx` is out of bounds, this method will panic. - pub fn is_hole(&self, idx: usize) -> bool { - self.0[idx] - } - - /// Marks the block `idx` as a hole. - /// - /// # Panics - /// - /// If the `idx` is out of bounds, this method will panic. - pub fn set(&mut self, idx: usize) { - self.0.set(idx, true); - } - - /// Marks all blocks within the `range` as holes. - /// - /// # Panic - /// - /// If the `range` is out of bounds, this method will panic. - pub fn set_range(&mut self, range: Range) { - for idx in range { - self.0.set(idx, true); - } - } - - /// Unmarks the block `idx` as a hole. - /// - /// # Panics - /// - /// If the `idx` is out of bounds, this method will panic. - pub fn unset(&mut self, idx: usize) { - self.0.set(idx, false); - } - - /// Unmarks all blocks within the `range` as holes. - /// - /// # Panic - /// - /// If the `range` is out of bounds, this method will panic. - pub fn unset_range(&mut self, range: Range) { - for idx in range { - self.0.set(idx, false); - } - } -} diff --git a/kernel/src/fs/ext2/inode.rs b/kernel/src/fs/ext2/inode.rs index 8b99e1ea5..059d8900a 100644 --- a/kernel/src/fs/ext2/inode.rs +++ b/kernel/src/fs/ext2/inode.rs @@ -9,7 +9,6 @@ use inherit_methods_macro::inherit_methods; use super::{ block_ptr::{BidPath, BlockPtrs, Ext2Bid, BID_SIZE, MAX_BLOCK_PTRS}, - blocks_hole::BlocksHoleDesc, dir::{DirEntry, DirEntryReader, DirEntryWriter}, fs::Ext2, indirect_block_cache::{IndirectBlock, IndirectBlockCache}, @@ -761,15 +760,6 @@ impl Inode { // TODO: Think of a more light-weight approach inner.page_cache.fill_zeros(offset..end_offset)?; - - // Mark the full blocks as holes - let inode_impl = inner.inode_impl.0.read(); - let mut blocks_hole_desc = inode_impl.blocks_hole_desc.write(); - for bid in Bid::from_offset(offset.align_up(BLOCK_SIZE)) - ..Bid::from_offset(end_offset.align_down(BLOCK_SIZE)) - { - blocks_hole_desc.set(bid.to_raw() as _); - } Ok(()) } // We extend the compatibility here since Ext2 in Linux @@ -1091,9 +1081,6 @@ impl Inner { // Writes back the data in page cache. let file_size = self.inode_impl.file_size(); self.page_cache.evict_range(0..file_size)?; - - // Writes back the data holes - self.inode_impl.sync_data_holes()?; Ok(()) } } @@ -1102,7 +1089,6 @@ struct InodeImpl(RwMutex); struct InodeImpl_ { desc: Dirty, - blocks_hole_desc: RwLock, indirect_blocks: RwMutex, is_freed: bool, last_alloc_device_bid: Option, @@ -1112,7 +1098,6 @@ struct InodeImpl_ { impl InodeImpl_ { pub fn new(desc: Dirty, weak_self: Weak, fs: Weak) -> Self { Self { - blocks_hole_desc: RwLock::new(BlocksHoleDesc::new(desc.blocks_count() as usize)), desc, indirect_blocks: RwMutex::new(IndirectBlockCache::new(fs)), is_freed: false, @@ -1131,56 +1116,20 @@ impl InodeImpl_ { pub fn read_blocks_async(&self, bid: Ext2Bid, blocks: &SegmentSlice) -> Result { let nblocks = blocks.nframes(); - let mut segments = Vec::new(); + let mut bio_waiter = BioWaiter::new(); - // Traverse all blocks to be read, handle any holes, and collect contiguous blocks in batches - let mut nth_bid = bid; let mut blocks_offset = 0; for dev_range in DeviceRangeReader::new(self, bid..bid + nblocks as Ext2Bid)? { let first_bid = dev_range.start as Ext2Bid; let range_len = dev_range.len(); + let segment = blocks.range(blocks_offset..blocks_offset + range_len); - let (mut curr_batch_start_bid, mut curr_batch_len) = (first_bid, 0); - let blocks_hole_desc = self.blocks_hole_desc.read(); - for curr_bid in first_bid..first_bid + range_len as Ext2Bid { - if blocks_hole_desc.is_hole(nth_bid as usize) { - if curr_batch_len > 0 { - // Collect current batch - let segment = blocks.range(blocks_offset..blocks_offset + curr_batch_len); - segments.push((curr_batch_start_bid, segment)); - blocks_offset += curr_batch_len; - curr_batch_len = 0; - } - - // Zero the hole - blocks - .range(blocks_offset..blocks_offset + 1) - .writer() - .fill(0); - blocks_offset += 1; - } else { - if curr_batch_len == 0 { - // Start to record next batch - curr_batch_start_bid = curr_bid; - } - curr_batch_len += 1; - } - nth_bid += 1; - } - // Collect the last batch if present - if curr_batch_len > 0 { - let segment = blocks.range(blocks_offset..blocks_offset + curr_batch_len); - segments.push((curr_batch_start_bid, segment)); - blocks_offset += curr_batch_len; - } - } - - // Read blocks in batches - let mut bio_waiter = BioWaiter::new(); - for (start_bid, segment) in segments { - let waiter = self.fs().read_blocks_async(start_bid, &segment)?; + let waiter = self.fs().read_blocks_async(first_bid, &segment)?; bio_waiter.concat(waiter); + + blocks_offset += range_len; } + Ok(bio_waiter) } @@ -1207,11 +1156,6 @@ impl InodeImpl_ { blocks_offset += range_len; } - // FIXME: Unset the block hole in the callback function of bio. - self.blocks_hole_desc - .write() - .unset_range((bid as usize)..bid as usize + nblocks); - Ok(bio_waiter) } @@ -1246,7 +1190,6 @@ impl InodeImpl_ { return_errno_with_message!(Errno::ENOSPC, "not enough free blocks"); } self.expand_blocks(old_blocks..new_blocks)?; - self.blocks_hole_desc.write().resize(new_blocks as usize); } // Expands the size @@ -1495,7 +1438,6 @@ impl InodeImpl_ { // Shrinks block count if necessary if new_blocks < old_blocks { self.shrink_blocks(new_blocks..old_blocks); - self.blocks_hole_desc.write().resize(new_blocks as usize); } // Shrinks the size @@ -1920,58 +1862,6 @@ impl InodeImpl { Ok(String::from_utf8(symlink)?) } - pub fn sync_data_holes(&self) -> Result<()> { - let inner = self.0.read(); - let blocks_hole_desc = inner.blocks_hole_desc.read(); - // Collect contiguous data holes in batches - let (data_hole_batches, max_batch_len) = { - let mut data_hole_batches: Vec<(Ext2Bid, usize)> = Vec::new(); - let mut max_batch_len = 0; - let mut prev_bid = None; - let (mut curr_batch_start_bid, mut curr_batch_len) = (0 as Ext2Bid, 0); - - for bid in - (0..inner.desc.blocks_count()).filter(|bid| blocks_hole_desc.is_hole(*bid as _)) - { - match prev_bid { - Some(prev) if bid == prev + 1 => { - curr_batch_len += 1; - } - _ => { - if curr_batch_len > 0 { - data_hole_batches.push((curr_batch_start_bid, curr_batch_len)); - max_batch_len = max_batch_len.max(curr_batch_len); - } - curr_batch_start_bid = bid; - curr_batch_len = 1; - } - } - prev_bid = Some(bid); - } - // Collect the last batch if present - if curr_batch_len > 0 { - data_hole_batches.push((curr_batch_start_bid, curr_batch_len)); - max_batch_len = max_batch_len.max(curr_batch_len); - } - - (data_hole_batches, max_batch_len) - }; - drop(blocks_hole_desc); - if data_hole_batches.is_empty() { - return Ok(()); - } - - // TODO: If we can persist the `blocks_hole_desc`, Can we avoid zeroing all the holes on the device? - debug_assert!(max_batch_len > 0); - let zeroed_segment: SegmentSlice = FrameAllocOptions::new(max_batch_len) - .alloc_contiguous()? - .into(); - for (start_bid, batch_len) in data_hole_batches { - inner.write_blocks(start_bid, &zeroed_segment.range(0..batch_len))?; - } - Ok(()) - } - pub fn sync_metadata(&self) -> Result<()> { if !self.0.read().desc.is_dirty() { return Ok(()); diff --git a/kernel/src/fs/ext2/mod.rs b/kernel/src/fs/ext2/mod.rs index 46e68074b..81963e418 100644 --- a/kernel/src/fs/ext2/mod.rs +++ b/kernel/src/fs/ext2/mod.rs @@ -42,7 +42,6 @@ pub use super_block::{SuperBlock, MAGIC_NUM}; mod block_group; mod block_ptr; -mod blocks_hole; mod dir; mod fs; mod impl_for_vfs;