Fix ext2 fast symlink inode detection logic
This commit is contained in:
parent
01cf00a4c6
commit
28fe11e98d
|
|
@ -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<String> {
|
||||
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<String> {
|
||||
pub fn read_fast_link(&self) -> Result<String> {
|
||||
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: <https://elixir.bootlin.com/linux/v6.18/source/fs/ext2/inode.c#L48-L55>.
|
||||
fn is_fast_symlink(&self) -> bool {
|
||||
self.type_ == InodeType::SymLink && self.data_sectors() == 0
|
||||
}
|
||||
}
|
||||
|
||||
fn sectors_to_blocks(sector_count: u32) -> Ext2Bid {
|
||||
|
|
|
|||
Loading…
Reference in New Issue