BlockCache-read cache支持 (#521)

支持block cache的读缓存
This commit is contained in:
曾俊 2024-04-07 14:03:51 +08:00 committed by GitHub
parent 06560afa2a
commit eb49bb993a
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
19 changed files with 797 additions and 26 deletions

View File

@ -1,14 +1,17 @@
/// 引入Module /// 引入Module
use crate::{ use crate::{
driver::base::{ driver::{
device::{ base::{
device_number::{DeviceNumber, Major}, device::{
Device, DeviceError, IdTable, BLOCKDEVS, device_number::{DeviceNumber, Major},
}, Device, DeviceError, IdTable, BLOCKDEVS,
map::{ },
DeviceStruct, DEV_MAJOR_DYN_END, DEV_MAJOR_DYN_EXT_END, DEV_MAJOR_DYN_EXT_START, map::{
DEV_MAJOR_HASH_SIZE, DEV_MAJOR_MAX, 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, kerror,
}; };
@ -195,7 +198,7 @@ pub trait BlockDevice: Device {
/// @return: 如果操作成功,返回 Ok(操作的长度) 其中单位是字节; /// @return: 如果操作成功,返回 Ok(操作的长度) 其中单位是字节;
/// 否则返回Err(错误码),其中错误码为负数; /// 否则返回Err(错误码),其中错误码为负数;
/// 如果操作异常但是并没有检查出什么错误将返回Err(已操作的长度) /// 如果操作异常但是并没有检查出什么错误将返回Err(已操作的长度)
fn read_at( fn read_at_sync(
&self, &self,
lba_id_start: BlockId, lba_id_start: BlockId,
count: usize, count: usize,
@ -209,7 +212,7 @@ pub trait BlockDevice: Device {
/// @return: 如果操作成功,返回 Ok(操作的长度) 其中单位是字节; /// @return: 如果操作成功,返回 Ok(操作的长度) 其中单位是字节;
/// 否则返回Err(错误码),其中错误码为负数; /// 否则返回Err(错误码),其中错误码为负数;
/// 如果操作异常但是并没有检查出什么错误将返回Err(已操作的长度) /// 如果操作异常但是并没有检查出什么错误将返回Err(已操作的长度)
fn write_at( fn write_at_sync(
&self, &self,
lba_id_start: BlockId, lba_id_start: BlockId,
count: usize, count: usize,
@ -240,8 +243,72 @@ pub trait BlockDevice: Device {
/// @brief 返回当前磁盘上的所有分区的Arc指针数组 /// @brief 返回当前磁盘上的所有分区的Arc指针数组
fn partitions(&self) -> Vec<Arc<Partition>>; 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> { fn write_at_bytes(&self, offset: usize, len: usize, buf: &[u8]) -> Result<usize, SystemError> {
// assert!(len <= buf.len());
if len > buf.len() { if len > buf.len() {
return Err(SystemError::E2BIG); return Err(SystemError::E2BIG);
} }
@ -272,7 +339,6 @@ pub trait BlockDevice: Device {
} }
} }
return Ok(len); return Ok(len);
//self.0.lock().write_at(lba_id_start, count, buf)
} }
fn read_at_bytes( fn read_at_bytes(
@ -314,11 +380,6 @@ pub trait BlockDevice: Device {
} }
} }
return Ok(len); return Ok(len);
// kdebug!(
// "ahci read at {lba_id_start}, count={count}, lock={:?}",
// self.0
// );
} }
} }

View File

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

View File

@ -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
}
}

View File

@ -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
}
}

View File

@ -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,
// 这里使用从头至尾的替换算法其替换策略为012...threshold01...以此类推该算法比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
kernel/src/driver/block/cache/mod.rs vendored Normal file
View File

@ -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>),
}

View File

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

View File

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

View File

@ -4,6 +4,7 @@ pub mod ahcidisk;
pub mod hba; pub mod hba;
use crate::driver::base::block::disk_info::BLK_GF_AHCI; use crate::driver::base::block::disk_info::BLK_GF_AHCI;
use crate::driver::block::cache::cached_block_device::BlockCache;
// 依赖的rust工具包 // 依赖的rust工具包
use crate::driver::pci::pci::{ use crate::driver::pci::pci::{
get_pci_device_structure_mut, PciDeviceStructure, PCI_DEVICE_LINKEDLIST, 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); compiler_fence(core::sync::atomic::Ordering::SeqCst);

View File

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

View File

@ -225,7 +225,7 @@ impl BiosParameterBlock {
// 读取分区的引导扇区 // 读取分区的引导扇区
partition partition
.disk() .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); let mut cursor = VecCursor::new(v);

View File

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

View File

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

3
user/apps/test-blockcache/.gitignore vendored Normal file
View File

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

View File

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

View File

@ -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

View File

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

View File

@ -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(())
}

View File

@ -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": []
}