diff --git a/kernel/src/fs/ext2/inode.rs b/kernel/src/fs/ext2/inode.rs index 77c6398db..b6aa1cdca 100644 --- a/kernel/src/fs/ext2/inode.rs +++ b/kernel/src/fs/ext2/inode.rs @@ -1062,7 +1062,7 @@ impl InodeInner { pub fn write_link(&mut self, target: &str) -> Result<()> { if target.len() <= MAX_FAST_SYMLINK_LEN { - return self.inode_impl.write_link(target); + return self.inode_impl.write_fast_link(target); } self.page_cache.resize(target.len())?; @@ -1076,8 +1076,8 @@ impl InodeInner { pub fn read_link(&self) -> Result { let file_size = self.inode_impl.file_size(); - if file_size <= MAX_FAST_SYMLINK_LEN { - return self.inode_impl.read_link(); + if self.inode_impl.desc.is_fast_symlink() { + return self.inode_impl.read_fast_link(); } let mut symlink = vec![0u8; file_size]; @@ -1293,7 +1293,7 @@ impl InodeImpl { } pub fn set_acl(&mut self, bid: Bid) { - self.desc.acl = Some(bid); + self.desc.set_acl_block(bid); } pub fn atime(&self) -> Duration { @@ -1335,16 +1335,14 @@ impl InodeImpl { device_id } - pub fn read_link(&self) -> Result { + pub fn read_fast_link(&self) -> Result { let symlink_str = core::str::from_utf8(&self.desc.block_ptrs.as_bytes()[..self.desc.size])?; Ok(symlink_str.to_owned()) } - pub fn write_link(&mut self, target: &str) -> Result<()> { + pub fn write_fast_link(&mut self, target: &str) -> Result<()> { let target_len = target.len(); self.desc.block_ptrs.as_bytes_mut()[..target_len].copy_from_slice(target.as_bytes()); - self.block_manager.block_ptrs.write().as_bytes_mut()[..target_len] - .copy_from_slice(target.as_bytes()); if self.desc.size != target_len { self.resize(target_len)?; } @@ -1473,9 +1471,11 @@ impl InodeImpl { self.fs().free_blocks(device_range).unwrap(); return Err(e); } - self.desc.sector_count = blocks_to_sectors(range.start + device_range.len() as u32); + self.last_alloc_device_bid = Some(device_range.end - 1); - return Ok(device_range.len() as Ext2Bid); + let nr_blocks = device_range.len() as Ext2Bid; + self.desc.set_data_blocks(range.start + nr_blocks); + return Ok(nr_blocks); } // Allocates the required additional indirect blocks and at least one block. @@ -1519,9 +1519,10 @@ impl InodeImpl { return Err(e); } - self.desc.sector_count = blocks_to_sectors(range.start + device_range.len() as u32); self.last_alloc_device_bid = Some(device_range.end - 1); - Ok(device_range.len() as Ext2Bid) + let nr_blocks = device_range.len() as Ext2Bid; + self.desc.set_data_blocks(range.start + nr_blocks); + Ok(nr_blocks) } /// Sets the device block IDs for a specified range. @@ -1681,7 +1682,7 @@ impl InodeImpl { current_range.end -= free_cnt; } - self.desc.sector_count = blocks_to_sectors(range.start); + self.desc.set_data_blocks(range.start); self.last_alloc_device_bid = if range.start == 0 { None } else { @@ -2200,13 +2201,15 @@ impl InodeDesc { (self.blocks_count() as usize) * BLOCK_SIZE } - /// Returns the actual number of blocks utilized. + /// Returns the actual number of blocks utilized, excluding the indirect blocks. /// /// Ext2 allows the `block_count` to exceed the actual number of blocks utilized. pub fn blocks_count(&self) -> Ext2Bid { - let blocks = self.size_to_blocks(self.size); - debug_assert!(blocks <= sectors_to_blocks(self.sector_count)); - blocks + if self.is_fast_symlink() { + return 0; + } + + self.size.div_ceil(BLOCK_SIZE) as Ext2Bid } fn size_to_blocks(&self, size: usize) -> Ext2Bid { @@ -2215,6 +2218,44 @@ impl InodeDesc { } size.div_ceil(BLOCK_SIZE) as Ext2Bid } + + /// Returns the number of sectors used for ACL. + fn acl_sectors(&self) -> u32 { + let Some(bid) = self.acl else { + return 0; + }; + + if bid.to_raw() == 0 { + return 0; + } + + blocks_to_sectors(1) + } + + /// Sets the extended attribute block for ACL. + fn set_acl_block(&mut self, bid: Bid) { + let old_acl_sectors = self.acl_sectors(); + self.acl = Some(bid); + let new_acl_sectors = self.acl_sectors(); + self.sector_count = self.sector_count - old_acl_sectors + new_acl_sectors; + } + + /// Returns the number of data sectors, including the indirect blocks. + fn data_sectors(&self) -> u32 { + self.sector_count - self.acl_sectors() + } + + /// Sets the number of data blocks, including the indirect blocks. + fn set_data_blocks(&mut self, block_count: u32) { + self.sector_count = blocks_to_sectors(block_count) + self.acl_sectors(); + } + + /// Returns whether the inode is a fast symlink. + /// + /// Reference: . + fn is_fast_symlink(&self) -> bool { + self.type_ == InodeType::SymLink && self.data_sectors() == 0 + } } fn sectors_to_blocks(sector_count: u32) -> Ext2Bid {