Browse Source

BlockCache-read cache支持 (#521)

支持block cache的读缓存
曾俊 11 months ago
parent
commit
eb49bb993a

+ 78 - 17
kernel/src/driver/base/block/block_device.rs

@@ -1,14 +1,17 @@
 /// 引入Module
 use crate::{
-    driver::base::{
-        device::{
-            device_number::{DeviceNumber, Major},
-            Device, DeviceError, IdTable, BLOCKDEVS,
-        },
-        map::{
-            DeviceStruct, DEV_MAJOR_DYN_END, DEV_MAJOR_DYN_EXT_END, DEV_MAJOR_DYN_EXT_START,
-            DEV_MAJOR_HASH_SIZE, DEV_MAJOR_MAX,
+    driver::{
+        base::{
+            device::{
+                device_number::{DeviceNumber, Major},
+                Device, DeviceError, IdTable, BLOCKDEVS,
+            },
+            map::{
+                DeviceStruct, DEV_MAJOR_DYN_END, DEV_MAJOR_DYN_EXT_END, DEV_MAJOR_DYN_EXT_START,
+                DEV_MAJOR_HASH_SIZE, DEV_MAJOR_MAX,
+            },
         },
+        block::cache::{cached_block_device::BlockCache, BlockCacheError, BLOCK_SIZE},
     },
     kerror,
 };
@@ -195,7 +198,7 @@ pub trait BlockDevice: Device {
     /// @return: 如果操作成功,返回 Ok(操作的长度) 其中单位是字节;
     ///          否则返回Err(错误码),其中错误码为负数;
     ///          如果操作异常,但是并没有检查出什么错误,将返回Err(已操作的长度)
-    fn read_at(
+    fn read_at_sync(
         &self,
         lba_id_start: BlockId,
         count: usize,
@@ -209,7 +212,7 @@ pub trait BlockDevice: Device {
     /// @return: 如果操作成功,返回 Ok(操作的长度) 其中单位是字节;
     ///          否则返回Err(错误码),其中错误码为负数;
     ///          如果操作异常,但是并没有检查出什么错误,将返回Err(已操作的长度)
-    fn write_at(
+    fn write_at_sync(
         &self,
         lba_id_start: BlockId,
         count: usize,
@@ -240,8 +243,72 @@ pub trait BlockDevice: Device {
     /// @brief 返回当前磁盘上的所有分区的Arc指针数组
     fn partitions(&self) -> Vec<Arc<Partition>>;
 
+    /// # 函数的功能
+    /// 经由Cache对块设备的读操作
+    fn read_at(
+        &self,
+        lba_id_start: BlockId,
+        count: usize,
+        buf: &mut [u8],
+    ) -> Result<usize, SystemError> {
+        self.cache_read(lba_id_start, count, buf)
+    }
+
+    /// # 函数的功能
+    ///  经由Cache对块设备的写操作
+    fn write_at(
+        &self,
+        lba_id_start: BlockId,
+        count: usize,
+        buf: &[u8],
+    ) -> Result<usize, SystemError> {
+        self.cache_write(lba_id_start, count, buf)
+    }
+
+    /// # 函数的功能
+    /// 其功能对外而言和read_at函数完全一致,但是加入blockcache的功能
+    fn cache_read(
+        &self,
+        lba_id_start: BlockId,
+        count: usize,
+        buf: &mut [u8],
+    ) -> Result<usize, SystemError> {
+        let cache_response = BlockCache::read(lba_id_start, count, buf);
+        if let Err(e) = cache_response {
+            match e {
+                BlockCacheError::StaticParameterError => {
+                    BlockCache::init();
+                    let ans = self.read_at_sync(lba_id_start, count, buf)?;
+                    return Ok(ans);
+                }
+                BlockCacheError::BlockFaultError(fail_vec) => {
+                    let ans = self.read_at_sync(lba_id_start, count, buf)?;
+                    let _ = BlockCache::insert(fail_vec, buf);
+                    return Ok(ans);
+                }
+                _ => {
+                    let ans = self.read_at_sync(lba_id_start, count, buf)?;
+                    return Ok(ans);
+                }
+            }
+        } else {
+            return Ok(count * BLOCK_SIZE);
+        }
+    }
+
+    /// # 函数功能
+    /// 其功能对外而言和write_at函数完全一致,但是加入blockcache的功能
+    fn cache_write(
+        &self,
+        lba_id_start: BlockId,
+        count: usize,
+        buf: &[u8],
+    ) -> Result<usize, SystemError> {
+        let _cache_response = BlockCache::immediate_write(lba_id_start, count, buf);
+        self.write_at_sync(lba_id_start, count, buf)
+    }
+
     fn write_at_bytes(&self, offset: usize, len: usize, buf: &[u8]) -> Result<usize, SystemError> {
-        // assert!(len <= buf.len());
         if len > buf.len() {
             return Err(SystemError::E2BIG);
         }
@@ -272,7 +339,6 @@ pub trait BlockDevice: Device {
             }
         }
         return Ok(len);
-        //self.0.lock().write_at(lba_id_start, count, buf)
     }
 
     fn read_at_bytes(
@@ -314,11 +380,6 @@ pub trait BlockDevice: Device {
             }
         }
         return Ok(len);
-
-        // kdebug!(
-        //     "ahci read at {lba_id_start}, count={count}, lock={:?}",
-        //     self.0
-        // );
     }
 }
 

+ 0 - 1
kernel/src/driver/base/block/mod.rs

@@ -1,6 +1,5 @@
 pub mod block_device;
 pub mod disk_info;
-
 #[derive(Debug)]
 #[allow(dead_code)]
 pub enum SeekFrom {

+ 54 - 0
kernel/src/driver/block/cache/cache_block.rs

@@ -0,0 +1,54 @@
+use alloc::{boxed::Box, vec::Vec};
+
+use crate::driver::base::block::block_device::BlockId;
+
+use super::{BlockCacheError, BLOCK_SIZE};
+
+/// # 枚举功能
+/// 该枚举设计来是用于实现回写法的,但是目前并未使用
+#[allow(dead_code)]
+pub enum CacheBlockFlag {
+    Unused,
+    Unwrited,
+    Writed,
+}
+
+pub type CacheBlockAddr = usize;
+
+/// # 结构功能
+/// 存储数据的最小单位
+pub struct CacheBlock {
+    data: Box<[u8]>,
+    _flag: CacheBlockFlag,
+    lba_id: BlockId,
+}
+
+impl CacheBlock {
+    pub fn new(data: Box<[u8]>, flag: CacheBlockFlag, lba_id: BlockId) -> Self {
+        CacheBlock {
+            data,
+            _flag: flag,
+            lba_id,
+        }
+    }
+
+    pub fn from_data(lba_id: BlockId, data: Vec<u8>) -> Self {
+        let space_box = data.into_boxed_slice();
+        CacheBlock::new(space_box, CacheBlockFlag::Unwrited, lba_id)
+    }
+
+    pub fn _set_flag(&mut self, _flag: CacheBlockFlag) -> Option<()> {
+        todo!()
+    }
+    pub fn data(&self, buf: &mut [u8]) -> Result<usize, BlockCacheError> {
+        if buf.len() != BLOCK_SIZE {
+            return Err(BlockCacheError::BlockSizeError);
+        }
+        buf.copy_from_slice(&self.data);
+        return Ok(BLOCK_SIZE);
+    }
+
+    pub fn lba_id(&self) -> BlockId {
+        self.lba_id
+    }
+}

+ 102 - 0
kernel/src/driver/block/cache/cache_iter.rs

@@ -0,0 +1,102 @@
+use crate::driver::base::block::block_device::BlockId;
+
+/// # 结构功能
+/// 一个简单的结构体,是BlockIter的输出
+#[derive(Debug)]
+pub struct BlockData {
+    /// 表示单个块对应的lba_id
+    lba_id: BlockId,
+    /// 表示该块在buf中的起始地址,目前并没有作用(例如:若该块是第2个块,那么该数据成员值为2*BLOCK_SIZE)
+    _data_start_addr: BlockId,
+    /// 表示该块的大小
+    _block_size: usize,
+}
+
+impl BlockData {
+    pub fn new(lba_id: BlockId, data_start_addr: BlockId, block_size: usize) -> Self {
+        Self {
+            lba_id,
+            _data_start_addr: data_start_addr,
+            _block_size: block_size,
+        }
+    }
+    #[inline]
+    pub fn lba_id(&self) -> BlockId {
+        self.lba_id
+    }
+    #[inline]
+    pub fn _data_start_addr(&self) -> BlockId {
+        self._data_start_addr
+    }
+    #[inline]
+    pub fn _block_size(&self) -> usize {
+        self._block_size
+    }
+}
+
+/// # 结构功能
+/// 块迭代器,它获取需求(起始块,连续块的个数),并将连续的块输出为单一的块(如你需要读取lba_id为10~20的连续块,它就可以输出10,11...,20的BlockData)
+#[derive(Copy, Clone)]
+pub struct BlockIter {
+    /// 表示起始块的lba_id
+    lba_id_start: BlockId,
+    /// 表示从起始块开始你需要读多少个块
+    count: usize,
+    /// 表示当前遍历到第几个块了
+    current: usize,
+    /// 规定块的大小
+    block_size: usize,
+}
+
+impl BlockIter {
+    pub fn new(lba_id_start: BlockId, count: usize, block_size: usize) -> Self {
+        Self {
+            lba_id_start,
+            count,
+            block_size,
+            current: 0,
+        }
+    }
+}
+
+impl Iterator for BlockIter {
+    type Item = BlockData;
+
+    fn next(&mut self) -> Option<Self::Item> {
+        if self.current < self.count {
+            let ans = BlockData::new(
+                self.lba_id_start + self.current,
+                self.current * self.block_size,
+                self.block_size,
+            );
+            self.current += 1;
+            Some(ans)
+        } else {
+            None
+        }
+    }
+}
+
+/// # 结构功能
+/// 表示缺块信息的数据结构,往往在读取的时候发现缺块并产生FailData,在插入的时候使用FailData
+pub struct FailData {
+    /// 表示缺块的lba_id
+    lba_id: BlockId,
+    /// 表示缺块在buf中的位置,用于在insert的时候定位缺块数据的位置
+    index: usize,
+}
+
+impl FailData {
+    pub fn new(lba_id: BlockId, index: usize) -> Self {
+        FailData { lba_id, index }
+    }
+    #[inline]
+    pub fn lba_id(&self) -> BlockId {
+        self.lba_id
+    }
+    /// # 函数的功能
+    /// 该函数返回的是缺块在buf中的位置,比如:index=1,那么我们就应该取buf\[512..1024\]
+    pub fn index(&self) -> usize {
+        self.index
+    }
+}

+ 422 - 0
kernel/src/driver/block/cache/cached_block_device.rs

@@ -0,0 +1,422 @@
+use alloc::{boxed::Box, vec::Vec};
+use hashbrown::HashMap;
+
+use crate::{driver::base::block::block_device::BlockId, libs::rwlock::RwLock};
+
+use super::{
+    cache_block::{CacheBlock, CacheBlockAddr},
+    cache_iter::{BlockIter, FailData},
+    BlockCacheError, BLOCK_SIZE, BLOCK_SIZE_LOG, CACHE_THRESHOLD,
+};
+
+static mut CSPACE: Option<LockedCacheSpace> = None;
+static mut CMAPPER: Option<LockedCacheMapper> = None;
+/// # 结构功能
+/// 该结构体向外提供BlockCache服务
+pub struct BlockCache;
+
+unsafe fn mapper() -> Result<&'static mut LockedCacheMapper, BlockCacheError> {
+    unsafe {
+        match &mut CMAPPER {
+            Some(x) => return Ok(x),
+            None => return Err(BlockCacheError::StaticParameterError),
+        }
+    };
+}
+
+unsafe fn space() -> Result<&'static mut LockedCacheSpace, BlockCacheError> {
+    unsafe {
+        match &mut CSPACE {
+            Some(x) => return Ok(x),
+            None => return Err(BlockCacheError::StaticParameterError),
+        }
+    };
+}
+
+impl BlockCache {
+    /// # 函数的功能
+    /// 初始化BlockCache需要的结构体
+    pub fn init() {
+        unsafe {
+            CSPACE = Some(LockedCacheSpace::new(CacheSpace::new()));
+            CMAPPER = Some(LockedCacheMapper::new(CacheMapper::new()));
+        }
+        kdebug!("BlockCache Initialized!");
+    }
+    /// # 函数的功能
+    /// 使用blockcache进行对块设备进行连续块的读操作
+    ///
+    /// ## 参数:
+    /// - 'lba_id_start' :连续块的起始块的lba_id
+    /// - 'count' :从连续块算起需要读多少块
+    /// - 'buf' :读取出来的数据存放在buf中
+    ///
+    /// ## 返回值:
+    /// - Ok(usize) :表示读取块的个数
+    /// - Err(BlockCacheError::BlockFaultError) :缺块的情况下,返回读取失败的块的数据,利用该返回值可以帮助blockcache插入读取失败的块值(见insert函数)
+    /// - Err(BlockCacheError::____) :不缺块的情况往往是初始化或者其他问题,这种异常会在block_device中得到处理
+    pub fn read(
+        lba_id_start: BlockId,
+        count: usize,
+        buf: &mut [u8],
+    ) -> Result<usize, BlockCacheError> {
+        // 生成一个块迭代器(BlockIter),它可以迭代地给出所有需要块的数据,其中就包括lba_id
+        let block_iter = BlockIter::new(lba_id_start, count, BLOCK_SIZE);
+        // 调用检查函数,检查有无缺块,如果没有就可以获得所有块的Cache地址。如果失败了就直接返回FailData向量
+        let cache_block_addr = Self::check_able_to_read(block_iter)?;
+        // 块地址vec的长度应当等于块迭代器的大小
+        assert!(cache_block_addr.len() == block_iter.count());
+        // 迭代地读取cache并写入到buf中
+        for (index, _) in block_iter.enumerate() {
+            Self::read_one_block(cache_block_addr[index], index, buf)?;
+        }
+        return Ok(count);
+    }
+
+    /// # 函数的功能
+    /// 检查cache中是否有缺块的函数
+    ///
+    /// ## 参数:
+    /// - 'block_iter' :需要检查的块迭代器(因为块迭代器包含了需要读块的信息,所以传入块迭代器)
+    ///
+    /// ## 返回值:
+    /// - Ok(Vec<CacheBlockAddr>) :如果成功了,那么函数会返回每个块的Cache地址,利用Cache地址就可以访问Cache了
+    /// - Err(BlockCacheError::BlockFaultError) :如果发现了缺块,那么我们会返回所有缺块的信息(即FailData)
+    /// - Err(BlockCacheError::____) :不缺块的情况往往是初始化或者其他问题                  
+    fn check_able_to_read(block_iter: BlockIter) -> Result<Vec<CacheBlockAddr>, BlockCacheError> {
+        // 存放缺块信息的向量
+        let mut fail_ans = vec![];
+        // 存放命中块地址的向量
+        let mut success_ans = vec![];
+        // 获取mapper
+        let mapper = unsafe { mapper()? };
+        for (index, i) in block_iter.enumerate() {
+            // 在mapper中寻找块的lba_id,判断是否命中
+            match mapper.find(i.lba_id()) {
+                Some(x) => {
+                    success_ans.push(x);
+                    continue;
+                }
+                // 缺块就放入fail_ans
+                None => fail_ans.push(FailData::new(i.lba_id(), index)),
+                // 缺块不break的原因是,我们需要把所有缺块都找出来,这样才能补上缺块
+            }
+        }
+        // 只要有缺块就认为cache失败,因为需要补块就需要进行io操作
+        if !fail_ans.is_empty() {
+            return Err(BlockCacheError::BlockFaultError(fail_ans));
+        } else {
+            return Ok(success_ans);
+        }
+    }
+    /// # 函数的功能
+    /// 在cache中读取一个块的数据并放置于缓存的指定位置
+    ///
+    /// ## 参数:
+    /// - 'cache_block_addr' :表示需要读取的cache块的地址
+    /// - 'position' :表示该块的数据需要放置在buf的哪个位置,比如position为2,那么读出的数据将放置在buf\[1024..1536\](这里假设块大小是512)
+    /// - 'buf' :块数据的缓存
+    ///
+    /// ## 返回值:
+    /// - Ok(usize) :表示读取了多少个字节
+    /// - Err(BlockCacheError) :如果输入的cache_block_addr超过了cache的容量,那么将返回Err(由于目前的cache不支持动态变化上限,所以可能出现这种错误;而实际上,由于Cache的地址是由frame_selector给出的,所以正确实现的frame_selector理论上不会出现这种错误)
+    fn read_one_block(
+        cache_block_addr: CacheBlockAddr,
+        position: usize,
+        buf: &mut [u8],
+    ) -> Result<usize, BlockCacheError> {
+        let space = unsafe { space()? };
+        space.read(cache_block_addr, position, buf)
+    }
+    /// # 函数的功能
+    /// 根据缺块的数据和io获得的数据,向cache中补充块数据
+    ///
+    /// ## 参数:
+    /// - 'f_data_vec' :这里输入的一般是从read函数中返回的缺块数据
+    /// - 'data' :经过一次io后获得的数据
+    ///
+    /// ## 返回值:
+    /// Ok(usize) :表示补上缺页的个数
+    /// Err(BlockCacheError) :一般来说不会产生错误,这里产生错误的原因只有插入时还没有初始化(一般也很难发生)
+    pub fn insert(f_data_vec: Vec<FailData>, data: &[u8]) -> Result<usize, BlockCacheError> {
+        let count = f_data_vec.len();
+        for i in f_data_vec {
+            let index = i.index();
+            Self::insert_one_block(
+                i.lba_id(),
+                data[index * BLOCK_SIZE..(index + 1) * BLOCK_SIZE].to_vec(),
+            )?;
+        }
+        Ok(count)
+    }
+
+    /// # 函数的功能
+    /// 将一个块数据插入到cache中
+    ///
+    /// ## 参数:
+    /// - 'lba_id' :表明该块对应的lba_id,用于建立映射
+    /// - 'data' :传入的数据
+    ///
+    /// ## 返回值:
+    /// Ok(()):表示插入成功
+    /// Err(BlockCacheError) :一般来说不会产生错误,这里产生错误的原因只有插入时还没有初始化(一般也很难发生)
+    fn insert_one_block(lba_id: BlockId, data: Vec<u8>) -> Result<(), BlockCacheError> {
+        let space = unsafe { space()? };
+        space.insert(lba_id, data)
+    }
+    /// # 函数的功能
+    /// 立即回写,这里仅仅作为取消映射的方法,并没有真正写入到cache的功能
+    ///
+    /// ## 参数:
+    /// - 'lba_id_start' :需要读取的连续块的起始块
+    /// - 'count' :需要读取块的个数
+    /// - '_data' :目前没有写入功能,该参数暂时无用
+    ///
+    /// ## 返回值:
+    /// Ok(usize) :表示写入了多少个块
+    /// Err(BlockCacheError) :这里产生错误的原因只有插入时还没有初始化
+    pub fn immediate_write(
+        lba_id_start: BlockId,
+        count: usize,
+        _data: &[u8],
+    ) -> Result<usize, BlockCacheError> {
+        let mapper = unsafe { mapper()? };
+        let block_iter = BlockIter::new(lba_id_start, count, BLOCK_SIZE);
+        for i in block_iter {
+            mapper.remove(i.lba_id());
+        }
+        Ok(count)
+    }
+}
+
+struct LockedCacheSpace(RwLock<CacheSpace>);
+
+impl LockedCacheSpace {
+    pub fn new(space: CacheSpace) -> Self {
+        LockedCacheSpace(RwLock::new(space))
+    }
+
+    pub fn read(
+        &self,
+        addr: CacheBlockAddr,
+        position: usize,
+        buf: &mut [u8],
+    ) -> Result<usize, BlockCacheError> {
+        self.0.read().read(addr, position, buf)
+    }
+
+    pub fn _write(&mut self, _addr: CacheBlockAddr, _data: CacheBlock) -> Option<()> {
+        todo!()
+    }
+
+    pub fn insert(&mut self, lba_id: BlockId, data: Vec<u8>) -> Result<(), BlockCacheError> {
+        unsafe { self.0.get_mut().insert(lba_id, data) }
+    }
+}
+
+/// # 结构功能
+/// 管理Cache空间的结构体
+struct CacheSpace {
+    /// 用于存放CacheBlock,是Cache数据的实际存储空间的向量
+    root: Vec<CacheBlock>,
+    /// 在块换出换入时,用于选择替换块的结构体
+    frame_selector: Box<dyn FrameSelector>,
+}
+
+impl CacheSpace {
+    pub fn new() -> Self {
+        Self {
+            root: Vec::new(),
+            // 如果要修改替换算法,可以设计一个结构体实现FrameSelector trait,再在这里替换掉SimpleFrameSelector
+            frame_selector: Box::new(SimpleFrameSelector::new()),
+        }
+    }
+    /// # 函数的功能
+    /// 将一个块的数据写入到buf的指定位置
+    ///
+    /// ## 参数:
+    /// - 'addr' :请求块在Cache中的地址
+    /// - 'position' :表示需要将Cache放入buf中的位置,例如:若position为1,则块的数据放入buf\[512..1024\]
+    /// - 'buf' :存放数据的buf
+    ///
+    /// ## 返回值:
+    /// Some(usize):表示读取的字节数(这里默认固定为BLOCK_SIZE)
+    /// Err(BlockCacheError):如果你输入地址大于cache的最大上限,那么就返回InsufficientCacheSpace
+    pub fn read(
+        &self,
+        addr: CacheBlockAddr,
+        position: usize,
+        buf: &mut [u8],
+    ) -> Result<usize, BlockCacheError> {
+        if addr > self.frame_selector.size() {
+            return Err(BlockCacheError::InsufficientCacheSpace);
+        } else {
+            // CacheBlockAddr就是用于给root寻址的
+            return self.root[addr]
+                .data(&mut buf[position * BLOCK_SIZE..(position + 1) * BLOCK_SIZE]);
+        }
+    }
+    /// # 函数的功能
+    /// 向cache空间中写入的函数,目前尚未实现
+    pub fn _write(&mut self, _addr: CacheBlockAddr, _data: CacheBlock) -> Option<()> {
+        todo!()
+    }
+    /// # 函数的功能
+    /// 向cache中插入一个块并建立lba_id到块之间的映射
+    ///
+    /// ## 参数:
+    /// - 'lba_id' :表明你插入的块的lba_id,用于建立映射
+    /// - 'data' :要插入块的数据
+    ///
+    /// ## 返回值:
+    /// Ok(())
+    pub fn insert(&mut self, lba_id: BlockId, data: Vec<u8>) -> Result<(), BlockCacheError> {
+        // CacheBlock是cached block的基本单位,这里使用data生成一个CacheBlock用于向Cache空间中插入块
+        let data_block = CacheBlock::from_data(lba_id, data);
+        let mapper = unsafe { mapper()? };
+        // 这里我设计了cache的一个threshold,如果不超过阈值就可以append,否则只能替换
+        if self.frame_selector.can_append() {
+            // 这是append的操作逻辑:
+            // 从frame_selector获得一个CacheBlockAddr
+            let index = self.frame_selector.index_append();
+            // 直接将块push进去就可以,因为现在是append操作
+            self.root.push(data_block);
+            assert!(index == self.root.len() - 1);
+            // 建立mapper的映射
+            mapper.insert(lba_id, index);
+            Ok(())
+        } else {
+            // 这是replace的操作逻辑
+            // 从frame_selector获得一个CacheBlockAddr,这次是它替换出来的
+            let index = self.frame_selector.index_replace();
+            // 获取被替换的块的lba_id,待会用于取消映射
+            let removed_id = self.root[index].lba_id();
+            // 直接替换原本的块,由于被替换的块没有引用了,所以会被drop
+            self.root[index] = data_block;
+            // 建立映射插入块的映射
+            mapper.insert(lba_id, index);
+            // 取消被替换块的映射
+            mapper.remove(removed_id);
+            Ok(())
+        }
+    }
+}
+
+struct LockedCacheMapper {
+    lock: RwLock<CacheMapper>,
+}
+
+impl LockedCacheMapper {
+    pub fn new(inner: CacheMapper) -> Self {
+        Self {
+            lock: RwLock::new(inner),
+        }
+    }
+
+    pub fn insert(&mut self, lba_id: BlockId, caddr: CacheBlockAddr) -> Option<()> {
+        unsafe { self.lock.get_mut().insert(lba_id, caddr) }
+    }
+
+    pub fn find(&self, lba_id: BlockId) -> Option<CacheBlockAddr> {
+        self.lock.read().find(lba_id)
+    }
+
+    pub fn remove(&mut self, lba_id: BlockId) {
+        unsafe { self.lock.get_mut().remove(lba_id) }
+    }
+}
+
+/// # 结构功能
+/// 该结构体用于建立lba_id到cached块的映射
+struct CacheMapper {
+    // 执行键值对操作的map
+    map: HashMap<BlockId, CacheBlockAddr>,
+}
+
+impl CacheMapper {
+    pub fn new() -> Self {
+        Self {
+            map: HashMap::new(),
+        }
+    }
+    /// # 函数的功能
+    /// 插入操作
+    pub fn insert(&mut self, lba_id: BlockId, caddr: CacheBlockAddr) -> Option<()> {
+        self.map.insert(lba_id, caddr)?;
+        Some(())
+    }
+    /// # 函数的功能
+    /// 查找操作
+    #[inline]
+    pub fn find(&self, lba_id: BlockId) -> Option<CacheBlockAddr> {
+        Some(*self.map.get(&lba_id)?)
+    }
+    /// # 函数的功能
+    /// 去除操作
+    pub fn remove(&mut self, lba_id: BlockId) {
+        self.map.remove(&lba_id);
+    }
+}
+
+/// # 结构功能
+/// 该trait用于实现块的换入换出算法,需要设计替换算法只需要实现该trait即可
+trait FrameSelector {
+    /// # 函数的功能
+    /// 给出append操作的index(理论上,如果cache没满,就不需要换出块,就可以使用append操作)
+    fn index_append(&mut self) -> CacheBlockAddr;
+    /// # 函数的功能
+    /// 给出replace操作后的index
+    fn index_replace(&mut self) -> CacheBlockAddr;
+    /// # 函数的功能
+    /// 判断是否可以append
+    fn can_append(&self) -> bool;
+    /// # 函数的功能
+    /// 获取size
+    fn size(&self) -> usize;
+}
+
+/// # 结构功能
+/// 该结构体用于管理块的换入换出过程中,CacheBlockAddr的选择,替换算法在这里实现
+struct SimpleFrameSelector {
+    // 表示BlockCache的阈值,即最大可以存放多少块,这里目前还不支持动态变化
+    threshold: usize,
+    // 表示使用过的块帧的数量
+    size: usize,
+    // 这里使用从头至尾的替换算法,其替换策略为0,1,2,...,threshold,0,1...以此类推(该算法比FIFO还要简陋,后面可以再实现别的:)
+    current: usize,
+}
+
+impl SimpleFrameSelector {
+    pub fn new() -> Self {
+        Self {
+            threshold: CACHE_THRESHOLD * (1 << (20 - BLOCK_SIZE_LOG)),
+            size: 0,
+            current: 0,
+        }
+    }
+}
+
+impl FrameSelector for SimpleFrameSelector {
+    fn index_append(&mut self) -> CacheBlockAddr {
+        let ans = self.current;
+        self.size += 1;
+        self.current += 1;
+        self.current %= self.threshold;
+        return ans;
+    }
+
+    fn index_replace(&mut self) -> CacheBlockAddr {
+        let ans = self.current;
+        self.current += 1;
+        self.current %= self.threshold;
+        return ans;
+    }
+
+    fn can_append(&self) -> bool {
+        self.size < self.threshold
+    }
+
+    fn size(&self) -> usize {
+        self.size
+    }
+}

+ 19 - 0
kernel/src/driver/block/cache/mod.rs

@@ -0,0 +1,19 @@
+use alloc::vec::Vec;
+
+use self::cache_iter::FailData;
+
+mod cache_block;
+mod cache_iter;
+pub mod cached_block_device;
+pub const BLOCK_SIZE_LOG: usize = 9;
+///块大小这里固定为512
+pub const BLOCK_SIZE: usize = 1 << BLOCK_SIZE_LOG;
+///这里规定Cache的threshold大小,单位为:MB
+pub const CACHE_THRESHOLD: usize = 64;
+
+pub enum BlockCacheError {
+    BlockSizeError,
+    InsufficientCacheSpace,
+    StaticParameterError,
+    BlockFaultError(Vec<FailData>),
+}

+ 1 - 0
kernel/src/driver/block/mod.rs

@@ -0,0 +1 @@
+pub mod cache;

+ 3 - 3
kernel/src/driver/disk/ahci/ahcidisk.rs

@@ -401,7 +401,7 @@ impl LockedAhciDisk {
         let mut buf: Vec<u8> = vec![0; size_of::<MbrDiskPartionTable>()];
         buf.resize(size_of::<MbrDiskPartionTable>(), 0);
 
-        self.read_at(0, 1, &mut buf)?;
+        self.read_at_sync(0, 1, &mut buf)?;
         // 创建 Cursor 用于按字节读取
         let mut cursor = VecCursor::new(buf);
         cursor.seek(SeekFrom::SeekCurrent(446))?;
@@ -562,7 +562,7 @@ impl BlockDevice for LockedAhciDisk {
     }
 
     #[inline]
-    fn read_at(
+    fn read_at_sync(
         &self,
         lba_id_start: BlockId, // 起始lba编号
         count: usize,          // 读取lba的数量
@@ -572,7 +572,7 @@ impl BlockDevice for LockedAhciDisk {
     }
 
     #[inline]
-    fn write_at(
+    fn write_at_sync(
         &self,
         lba_id_start: BlockId,
         count: usize,

+ 2 - 0
kernel/src/driver/disk/ahci/mod.rs

@@ -4,6 +4,7 @@ pub mod ahcidisk;
 pub mod hba;
 
 use crate::driver::base::block::disk_info::BLK_GF_AHCI;
+use crate::driver::block::cache::cached_block_device::BlockCache;
 // 依赖的rust工具包
 use crate::driver::pci::pci::{
     get_pci_device_structure_mut, PciDeviceStructure, PCI_DEVICE_LINKEDLIST,
@@ -141,6 +142,7 @@ pub fn ahci_init() -> Result<(), SystemError> {
                 }
             }
         }
+        BlockCache::init();
     }
 
     compiler_fence(core::sync::atomic::Ordering::SeqCst);

+ 1 - 0
kernel/src/driver/mod.rs

@@ -1,5 +1,6 @@
 pub mod acpi;
 pub mod base;
+pub mod block;
 pub mod disk;
 pub mod firmware;
 pub mod input;

+ 1 - 1
kernel/src/filesystem/fat/bpb.rs

@@ -225,7 +225,7 @@ impl BiosParameterBlock {
         // 读取分区的引导扇区
         partition
             .disk()
-            .read_at(partition.lba_start as usize, 1, &mut v)?;
+            .read_at_sync(partition.lba_start as usize, 1, &mut v)?;
 
         // 获取指针对象
         let mut cursor = VecCursor::new(v);

+ 4 - 4
kernel/src/filesystem/fat/fs.rs

@@ -1001,7 +1001,7 @@ impl FATFileSystem {
                     let mut v: Vec<u8> = vec![0; self.lba_per_sector() * LBA_SIZE];
                     self.partition
                         .disk()
-                        .read_at(lba, self.lba_per_sector(), &mut v)?;
+                        .read_at_sync(lba, self.lba_per_sector(), &mut v)?;
 
                     let mut cursor: VecCursor = VecCursor::new(v);
                     cursor.seek(SeekFrom::SeekSet(in_block_offset as i64))?;
@@ -1032,7 +1032,7 @@ impl FATFileSystem {
                     let mut v: Vec<u8> = vec![0; self.lba_per_sector() * LBA_SIZE];
                     self.partition
                         .disk()
-                        .read_at(lba, self.lba_per_sector(), &mut v)?;
+                        .read_at_sync(lba, self.lba_per_sector(), &mut v)?;
 
                     let mut cursor: VecCursor = VecCursor::new(v);
                     cursor.seek(SeekFrom::SeekSet(in_block_offset as i64))?;
@@ -1078,7 +1078,7 @@ impl FATFileSystem {
                 let lba = self.get_lba_from_offset(self.bytes_to_sector(fat_part_bytes_offset));
 
                 let mut v: Vec<u8> = vec![0; LBA_SIZE];
-                self.partition.disk().read_at(lba, 1, &mut v)?;
+                self.partition.disk().read_at_sync(lba, 1, &mut v)?;
 
                 let mut cursor: VecCursor = VecCursor::new(v);
                 cursor.seek(SeekFrom::SeekSet(in_block_offset as i64))?;
@@ -1227,7 +1227,7 @@ impl FATFsInfo {
         // 计算fs_info扇区在磁盘上的字节偏移量,从磁盘读取数据
         partition
             .disk()
-            .read_at(in_disk_fs_info_offset as usize / LBA_SIZE, 1, &mut v)?;
+            .read_at_sync(in_disk_fs_info_offset as usize / LBA_SIZE, 1, &mut v)?;
         let mut cursor = VecCursor::new(v);
 
         let mut fsinfo = FATFsInfo {

+ 2 - 0
user/apps/test-blockcache/.cargo/config.toml

@@ -0,0 +1,2 @@
+[build]
+target = "x86_64-unknown-linux-musl"

+ 3 - 0
user/apps/test-blockcache/.gitignore

@@ -0,0 +1,3 @@
+/target
+Cargo.lock
+/install/

+ 10 - 0
user/apps/test-blockcache/Cargo.toml

@@ -0,0 +1,10 @@
+[package]
+name = "test-blockcache"
+version = "0.1.0"
+edition = "2021"
+description = "用于测试blockcac小程序"
+authors = [ "ZZJJWarth <[email protected]>" ]
+
+# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
+
+[dependencies]

+ 41 - 0
user/apps/test-blockcache/Makefile

@@ -0,0 +1,41 @@
+# The toolchain we use.
+# You can get it by running DragonOS' `tools/bootstrap.sh`
+TOOLCHAIN="+nightly-2023-08-15-x86_64-unknown-linux_dragonos-gnu"
+RUSTFLAGS+="-C target-feature=+crt-static -C link-arg=-no-pie"
+
+# 如果是在dadk中编译,那么安装到dadk的安装目录中
+INSTALL_DIR?=$(DADK_CURRENT_BUILD_DIR)
+# 如果是在本地编译,那么安装到当前目录下的install目录中
+INSTALL_DIR?=./install
+
+
+run:
+	RUSTFLAGS=$(RUSTFLAGS) cargo $(TOOLCHAIN) run
+
+build:
+	RUSTFLAGS=$(RUSTFLAGS) cargo $(TOOLCHAIN) build
+
+clean:
+	RUSTFLAGS=$(RUSTFLAGS) cargo $(TOOLCHAIN) clean
+
+test:
+	RUSTFLAGS=$(RUSTFLAGS) cargo $(TOOLCHAIN) test
+
+doc:
+	RUSTFLAGS=$(RUSTFLAGS) cargo $(TOOLCHAIN) doc
+
+run-release:
+	RUSTFLAGS=$(RUSTFLAGS) cargo $(TOOLCHAIN) run --release
+
+build-release:
+	RUSTFLAGS=$(RUSTFLAGS) cargo $(TOOLCHAIN) build --release
+
+clean-release:
+	RUSTFLAGS=$(RUSTFLAGS) cargo $(TOOLCHAIN) clean --release
+
+test-release:
+	RUSTFLAGS=$(RUSTFLAGS) cargo $(TOOLCHAIN) test --release
+
+.PHONY: install
+install: 
+	RUSTFLAGS=$(RUSTFLAGS) cargo $(TOOLCHAIN) install --path . --no-track --root $(INSTALL_DIR) --force

+ 8 - 0
user/apps/test-blockcache/README.md

@@ -0,0 +1,8 @@
+## 程序说明
+用于测试BlockCache的测试程序
+本程序生成一个文件,并开始对这个文件进行单纯的读操作(共读10000次)
+
+## 使用方法
+
+1. 打开系统的/bin目录
+2. 输入指令exec test-blockcache即可开始测试

+ 22 - 0
user/apps/test-blockcache/src/main.rs

@@ -0,0 +1,22 @@
+use std::fs::File;
+use std::io::{BufReader, Read, Seek, SeekFrom, Write};
+
+fn main() -> std::io::Result<()> {
+    let file_size_bytes: u64 = 512;
+    let mut file = File::create("large_file")?;
+    file.seek(std::io::SeekFrom::Start(file_size_bytes - 1))?;
+    file.write_all(&[0])?;
+    let mut file = File::open("large_file")?;
+    // let mut reader = BufReader::new(file);
+    let mut buffer = [0; 512];
+    let mut count = 0;
+    loop {
+        count += 1;
+        file.seek(SeekFrom::Start(0))?;
+        let bytes_read = file.read_exact(&mut buffer)?;
+        if count > 10000 {
+            break;
+        }
+    }
+    Ok(())
+}

+ 24 - 0
user/dadk/config/test_blockcache_0_1_0.dadk

@@ -0,0 +1,24 @@
+{
+  "name": "test-blockcache",
+  "version": "0.1.0",
+  "description": "用于测试blockcach小程序",
+  "rust_target": "x86_64-unknown-dragonos",
+  "task_type": {
+    "BuildFromSource": {
+      "Local": {
+        "path": "apps/test-blockcache"
+      }
+    }
+  },
+  "depends": [],
+  "build": {
+    "build_command": "make install"
+  },
+  "install": {
+    "in_dragonos_path": "/"
+  },
+  "clean": {
+    "clean_command": "make clean"
+  },
+  "envs": []
+}