Fix `DeviceRangeReader` to make it take sparse blocks into account.

This commit is contained in:
Chaoqun Zheng 2026-01-11 21:20:25 +08:00
parent 184e803869
commit 345f808b54
1 changed files with 76 additions and 25 deletions

View File

@ -1690,6 +1690,7 @@ impl InodeImpl {
.unwrap() .unwrap()
.read() .read()
.unwrap() .unwrap()
.unwrap()
.start, .start,
) )
}; };
@ -2007,7 +2008,7 @@ impl<'a> DeviceRangeReader<'a> {
/// ///
/// Note that the returned device range size may be smaller than the requested range /// Note that the returned device range size may be smaller than the requested range
/// due to possible inconsecutive block allocation. /// due to possible inconsecutive block allocation.
pub fn read(&mut self) -> Result<Range<Ext2Bid>> { pub fn read(&mut self) -> Result<Option<Range<Ext2Bid>>> {
let bid_path = BidPath::from(self.range.start); let bid_path = BidPath::from(self.range.start);
let max_cnt = self let max_cnt = self
.range .range
@ -2019,9 +2020,28 @@ impl<'a> DeviceRangeReader<'a> {
let mut device_range: Option<Range<Ext2Bid>> = None; let mut device_range: Option<Range<Ext2Bid>> = None;
for i in start_idx..start_idx + max_cnt { for i in start_idx..start_idx + max_cnt {
let device_bid = match &self.indirect_block { let device_bid = match &self.indirect_block {
None => self.block_ptrs.direct(i), None => match bid_path {
BidPath::Direct(_) => self.block_ptrs.direct(i),
_ => 0,
},
Some(indirect_block) => indirect_block.read_bid(i)?, Some(indirect_block) => indirect_block.read_bid(i)?,
}; };
// Skip sparse blocks which are not allocated
if device_bid == 0 {
match device_range {
Some(ref mut range) => {
// End the current range when hitting a sparse block
break;
}
None => {
// Skip leading sparse blocks, advance the logical range
self.range.start += 1;
continue;
}
}
}
match device_range { match device_range {
Some(ref mut range) => { Some(ref mut range) => {
if device_bid == range.end { if device_bid == range.end {
@ -2035,7 +2055,16 @@ impl<'a> DeviceRangeReader<'a> {
} }
} }
} }
let device_range = device_range.unwrap();
let device_range = match device_range {
Some(range) => range,
None => {
if !self.range.is_empty() {
self.update_indirect_block()?;
}
return Ok(None);
}
};
// Updates the range // Updates the range
self.range.start += device_range.len() as Ext2Bid; self.range.start += device_range.len() as Ext2Bid;
@ -2044,7 +2073,7 @@ impl<'a> DeviceRangeReader<'a> {
self.update_indirect_block()?; self.update_indirect_block()?;
} }
Ok(device_range) Ok(Some(device_range))
} }
fn update_indirect_block(&mut self) -> Result<()> { fn update_indirect_block(&mut self) -> Result<()> {
@ -2055,30 +2084,49 @@ impl<'a> DeviceRangeReader<'a> {
} }
BidPath::Indirect(_) => { BidPath::Indirect(_) => {
let indirect_bid = self.block_ptrs.indirect(); let indirect_bid = self.block_ptrs.indirect();
if indirect_bid == 0 {
self.indirect_block = None;
} else {
let indirect_block = self.indirect_blocks.find(indirect_bid)?; let indirect_block = self.indirect_blocks.find(indirect_bid)?;
self.indirect_block = Some(indirect_block.clone()); self.indirect_block = Some(indirect_block.clone());
} }
}
BidPath::DbIndirect(lvl1_idx, _) => { BidPath::DbIndirect(lvl1_idx, _) => {
let lvl1_indirect_bid = { let db_indirect_bid = self.block_ptrs.db_indirect();
let db_indirect_block = if db_indirect_bid == 0 {
self.indirect_blocks.find(self.block_ptrs.db_indirect())?; self.indirect_block = None;
db_indirect_block.read_bid(lvl1_idx as usize)? } else {
}; let db_indirect_block = self.indirect_blocks.find(db_indirect_bid)?;
let lvl1_indirect_bid = db_indirect_block.read_bid(lvl1_idx as usize)?;
if lvl1_indirect_bid == 0 {
self.indirect_block = None;
} else {
let lvl1_indirect_block = self.indirect_blocks.find(lvl1_indirect_bid)?; let lvl1_indirect_block = self.indirect_blocks.find(lvl1_indirect_bid)?;
self.indirect_block = Some(lvl1_indirect_block.clone()) self.indirect_block = Some(lvl1_indirect_block.clone());
}
}
} }
BidPath::TbIndirect(lvl1_idx, lvl2_idx, _) => { BidPath::TbIndirect(lvl1_idx, lvl2_idx, _) => {
let lvl2_indirect_bid = { let tb_indirect_bid = self.block_ptrs.tb_indirect();
let lvl1_indirect_bid = { if tb_indirect_bid == 0 {
let tb_indirect_block = self.indirect_block = None;
self.indirect_blocks.find(self.block_ptrs.tb_indirect())?; } else {
tb_indirect_block.read_bid(lvl1_idx as usize)? let tb_indirect_block = self.indirect_blocks.find(tb_indirect_bid)?;
}; let lvl1_indirect_bid = tb_indirect_block.read_bid(lvl1_idx as usize)?;
if lvl1_indirect_bid == 0 {
self.indirect_block = None;
} else {
let lvl1_indirect_block = self.indirect_blocks.find(lvl1_indirect_bid)?; let lvl1_indirect_block = self.indirect_blocks.find(lvl1_indirect_bid)?;
lvl1_indirect_block.read_bid(lvl2_idx as usize)? let lvl2_indirect_bid = lvl1_indirect_block.read_bid(lvl2_idx as usize)?;
}; if lvl2_indirect_bid == 0 {
let lvl2_indirect_block = self.indirect_blocks.find(lvl2_indirect_bid)?; self.indirect_block = None;
self.indirect_block = Some(lvl2_indirect_block.clone()) } else {
let lvl2_indirect_block =
self.indirect_blocks.find(lvl2_indirect_bid)?;
self.indirect_block = Some(lvl2_indirect_block.clone());
}
}
}
} }
} }
@ -2095,7 +2143,10 @@ impl Iterator for DeviceRangeReader<'_> {
} }
let range = self.read().unwrap(); let range = self.read().unwrap();
Some(range) match range {
Some(range) => Some(range),
None => self.next(),
}
} }
} }