Fix `DeviceRangeReader` to make it take sparse blocks into account.
This commit is contained in:
parent
184e803869
commit
345f808b54
|
|
@ -1690,6 +1690,7 @@ impl InodeImpl {
|
|||
.unwrap()
|
||||
.read()
|
||||
.unwrap()
|
||||
.unwrap()
|
||||
.start,
|
||||
)
|
||||
};
|
||||
|
|
@ -2007,7 +2008,7 @@ impl<'a> DeviceRangeReader<'a> {
|
|||
///
|
||||
/// Note that the returned device range size may be smaller than the requested range
|
||||
/// 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 max_cnt = self
|
||||
.range
|
||||
|
|
@ -2019,9 +2020,28 @@ impl<'a> DeviceRangeReader<'a> {
|
|||
let mut device_range: Option<Range<Ext2Bid>> = None;
|
||||
for i in start_idx..start_idx + max_cnt {
|
||||
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)?,
|
||||
};
|
||||
|
||||
// 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 {
|
||||
Some(ref mut range) => {
|
||||
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
|
||||
self.range.start += device_range.len() as Ext2Bid;
|
||||
|
|
@ -2044,7 +2073,7 @@ impl<'a> DeviceRangeReader<'a> {
|
|||
self.update_indirect_block()?;
|
||||
}
|
||||
|
||||
Ok(device_range)
|
||||
Ok(Some(device_range))
|
||||
}
|
||||
|
||||
fn update_indirect_block(&mut self) -> Result<()> {
|
||||
|
|
@ -2055,30 +2084,49 @@ impl<'a> DeviceRangeReader<'a> {
|
|||
}
|
||||
BidPath::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)?;
|
||||
self.indirect_block = Some(indirect_block.clone());
|
||||
}
|
||||
}
|
||||
BidPath::DbIndirect(lvl1_idx, _) => {
|
||||
let lvl1_indirect_bid = {
|
||||
let db_indirect_block =
|
||||
self.indirect_blocks.find(self.block_ptrs.db_indirect())?;
|
||||
db_indirect_block.read_bid(lvl1_idx as usize)?
|
||||
};
|
||||
let db_indirect_bid = self.block_ptrs.db_indirect();
|
||||
if db_indirect_bid == 0 {
|
||||
self.indirect_block = None;
|
||||
} 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)?;
|
||||
self.indirect_block = Some(lvl1_indirect_block.clone())
|
||||
self.indirect_block = Some(lvl1_indirect_block.clone());
|
||||
}
|
||||
}
|
||||
}
|
||||
BidPath::TbIndirect(lvl1_idx, lvl2_idx, _) => {
|
||||
let lvl2_indirect_bid = {
|
||||
let lvl1_indirect_bid = {
|
||||
let tb_indirect_block =
|
||||
self.indirect_blocks.find(self.block_ptrs.tb_indirect())?;
|
||||
tb_indirect_block.read_bid(lvl1_idx as usize)?
|
||||
};
|
||||
let tb_indirect_bid = self.block_ptrs.tb_indirect();
|
||||
if tb_indirect_bid == 0 {
|
||||
self.indirect_block = None;
|
||||
} else {
|
||||
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)?;
|
||||
lvl1_indirect_block.read_bid(lvl2_idx as usize)?
|
||||
};
|
||||
let lvl2_indirect_block = self.indirect_blocks.find(lvl2_indirect_bid)?;
|
||||
self.indirect_block = Some(lvl2_indirect_block.clone())
|
||||
let lvl2_indirect_bid = lvl1_indirect_block.read_bid(lvl2_idx as usize)?;
|
||||
if lvl2_indirect_bid == 0 {
|
||||
self.indirect_block = None;
|
||||
} 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();
|
||||
Some(range)
|
||||
match range {
|
||||
Some(range) => Some(range),
|
||||
None => self.next(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
Loading…
Reference in New Issue