Modify the virtio-blk to async

This commit is contained in:
LI Qing
2024-04-10 16:50:49 +08:00
committed by Tate, Hongliang Tian
parent 2616335755
commit b7131e721c
8 changed files with 263 additions and 207 deletions

View File

@ -74,10 +74,6 @@ mod test {
}
impl BlockDevice for ExfatMemoryDisk {
fn handle_irq(&self) {
info!("ExfatMemoryDisk handle irq");
}
fn enqueue(&self, bio: SubmittedBio) -> core::prelude::v1::Result<(), BioEnqueueError> {
let start_device_ofs = bio.sid_range().start.to_raw() as usize * SECTOR_SIZE;
let mut cur_device_ofs = start_device_ofs;

View File

@ -360,8 +360,8 @@ impl Ext2 {
block_group.sync_metadata()?;
}
let mut bio_waiter = BioWaiter::new();
// Writes back the main superblock and group descriptor table.
let mut bio_waiter = BioWaiter::new();
let raw_super_block = RawSuperBlock::from((*super_block).deref());
bio_waiter.concat(
self.block_device
@ -371,11 +371,16 @@ impl Ext2 {
super_block.group_descriptors_bid(0),
&self.group_descriptors_segment,
)?);
bio_waiter
.wait()
.ok_or_else(|| Error::with_message(Errno::EIO, "failed to sync main metadata"))?;
drop(bio_waiter);
// Writes back the backups of superblock and group descriptor table.
let mut raw_super_block_backup = raw_super_block;
for idx in 1..super_block.block_groups_count() {
if super_block.is_backup_group(idx as usize) {
let mut bio_waiter = BioWaiter::new();
raw_super_block_backup.block_group_idx = idx as u16;
bio_waiter.concat(self.block_device.write_bytes_async(
super_block.bid(idx as usize).to_offset(),
@ -385,14 +390,12 @@ impl Ext2 {
super_block.group_descriptors_bid(idx as usize),
&self.group_descriptors_segment,
)?);
bio_waiter.wait().ok_or_else(|| {
Error::with_message(Errno::EIO, "failed to sync backup metadata")
})?;
}
}
// Waits for the completion of all submitted bios.
bio_waiter
.wait()
.ok_or_else(|| Error::with_message(Errno::EIO, "failed to sync metadata of fs"))?;
// Reset to clean.
super_block.clear_dirty();
Ok(())

View File

@ -2,7 +2,11 @@
use lru::LruCache;
use super::{block_ptr::BID_SIZE, fs::Ext2, prelude::*};
use super::{
block_ptr::{Ext2Bid, BID_SIZE},
fs::Ext2,
prelude::*,
};
/// `IndirectBlockCache` is a caching structure that stores `IndirectBlock` objects for Ext2.
///
@ -11,7 +15,7 @@ use super::{block_ptr::BID_SIZE, fs::Ext2, prelude::*};
/// for new blocks.
#[derive(Debug)]
pub struct IndirectBlockCache {
cache: LruCache<u32, IndirectBlock>,
cache: LruCache<Ext2Bid, IndirectBlock>,
fs: Weak<Ext2>,
}
@ -32,7 +36,7 @@ impl IndirectBlockCache {
/// Retrieves a reference to an `IndirectBlock` by its `bid`.
///
/// If the block is not present in the cache, it will be loaded from the disk.
pub fn find(&mut self, bid: u32) -> Result<&IndirectBlock> {
pub fn find(&mut self, bid: Ext2Bid) -> Result<&IndirectBlock> {
self.try_shrink()?;
let fs = self.fs();
@ -49,7 +53,7 @@ impl IndirectBlockCache {
/// Retrieves a mutable reference to an `IndirectBlock` by its `bid`.
///
/// If the block is not present in the cache, it will be loaded from the disk.
pub fn find_mut(&mut self, bid: u32) -> Result<&mut IndirectBlock> {
pub fn find_mut(&mut self, bid: Ext2Bid) -> Result<&mut IndirectBlock> {
self.try_shrink()?;
let fs = self.fs();
@ -64,7 +68,7 @@ impl IndirectBlockCache {
}
/// Inserts or updates an `IndirectBlock` in the cache with the specified `bid`.
pub fn insert(&mut self, bid: u32, block: IndirectBlock) -> Result<()> {
pub fn insert(&mut self, bid: Ext2Bid, block: IndirectBlock) -> Result<()> {
self.try_shrink()?;
self.cache.put(bid, block);
Ok(())
@ -72,54 +76,43 @@ impl IndirectBlockCache {
/// Removes and returns the `IndirectBlock` corresponding to the `bid`
/// from the cache or `None` if does not exist.
pub fn remove(&mut self, bid: u32) -> Option<IndirectBlock> {
pub fn remove(&mut self, bid: Ext2Bid) -> Option<IndirectBlock> {
self.cache.pop(&bid)
}
/// Evicts all blocks from the cache, persisting any with a 'Dirty' state to the disk.
pub fn evict_all(&mut self) -> Result<()> {
let mut bio_waiter = BioWaiter::new();
loop {
let Some((bid, block)) = self.cache.pop_lru() else {
break;
};
if block.is_dirty() {
bio_waiter.concat(
self.fs()
.block_device()
.write_block(Bid::new(bid as _), &block.frame)?,
);
}
}
bio_waiter.wait().ok_or_else(|| {
Error::with_message(Errno::EIO, "failed to evict_all the indirect blocks")
})?;
Ok(())
let cache_size = self.cache.len();
self.evict(cache_size)
}
/// Attempts to shrink the cache size if it exceeds the maximum allowed cache size.
/// Attempts to evict some blocks from cache if it exceeds the maximum size.
fn try_shrink(&mut self) -> Result<()> {
if self.cache.len() < Self::MAX_SIZE {
return Ok(());
}
// TODO: How to determine the number of evictions each time?
//
// FIXME: When we set it to `Self::MAX_SIZE / 2` here,
// running the `/regression/ext2.sh` test may cause a deadlock issue.
let evict_num = 1;
self.evict(evict_num)
}
/// Evicts `num` blocks from cache.
fn evict(&mut self, num: usize) -> Result<()> {
let num = num.min(self.cache.len());
let mut bio_waiter = BioWaiter::new();
for _ in 0..(Self::MAX_SIZE / 2) {
for _ in 0..num {
let (bid, block) = self.cache.pop_lru().unwrap();
if block.is_dirty() {
bio_waiter.concat(
self.fs()
.block_device()
.write_block(Bid::new(bid as _), &block.frame)?,
);
bio_waiter.concat(self.fs().write_block_async(bid, &block.frame)?);
}
}
bio_waiter.wait().ok_or_else(|| {
Error::with_message(Errno::EIO, "failed to write back the indirect block")
Error::with_message(Errno::EIO, "failed to evict the indirect blocks")
})?;
Ok(())
@ -164,16 +157,16 @@ impl IndirectBlock {
}
/// Reads a bid at a specified `idx`.
pub fn read_bid(&self, idx: usize) -> Result<u32> {
pub fn read_bid(&self, idx: usize) -> Result<Ext2Bid> {
assert!(self.state != State::Uninit);
let bid: u32 = self.frame.read_val(idx * BID_SIZE)?;
let bid: Ext2Bid = self.frame.read_val(idx * BID_SIZE)?;
Ok(bid)
}
/// Writes a value of bid at a specified `idx`.
///
/// After a successful write operation, the block's state will be marked as dirty.
pub fn write_bid(&mut self, idx: usize, bid: &u32) -> Result<()> {
pub fn write_bid(&mut self, idx: usize, bid: &Ext2Bid) -> Result<()> {
assert!(self.state != State::Uninit);
self.frame.write_val(idx * BID_SIZE, bid)?;
self.state = State::Dirty;

View File

@ -80,6 +80,9 @@ fn init_thread() {
"[kernel] Spawn init thread, tid = {}",
current_thread!().tid()
);
// FIXME: Remove this if we move the step of mounting
// the filesystems to be done within the init process.
aster_frame::trap::enable_local();
net::lazy_init();
fs::lazy_init();
// driver::pci::virtio::block::block_device_test();