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()
|
.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();
|
||||||
let indirect_block = self.indirect_blocks.find(indirect_bid)?;
|
if indirect_bid == 0 {
|
||||||
self.indirect_block = Some(indirect_block.clone());
|
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, _) => {
|
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_block = self.indirect_blocks.find(lvl1_indirect_bid)?;
|
let lvl1_indirect_bid = db_indirect_block.read_bid(lvl1_idx as usize)?;
|
||||||
self.indirect_block = Some(lvl1_indirect_block.clone())
|
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());
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
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)?;
|
||||||
let lvl1_indirect_block = self.indirect_blocks.find(lvl1_indirect_bid)?;
|
if lvl1_indirect_bid == 0 {
|
||||||
lvl1_indirect_block.read_bid(lvl2_idx as usize)?
|
self.indirect_block = None;
|
||||||
};
|
} else {
|
||||||
let lvl2_indirect_block = self.indirect_blocks.find(lvl2_indirect_bid)?;
|
let lvl1_indirect_block = self.indirect_blocks.find(lvl1_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();
|
let range = self.read().unwrap();
|
||||||
Some(range)
|
match range {
|
||||||
|
Some(range) => Some(range),
|
||||||
|
None => self.next(),
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue