Skip to content

Commit

Permalink
fix(buffer_cache): block cache is enabled to transfer to file cache now
Browse files Browse the repository at this point in the history
Some block caches are mis recognized, e.g. directory. When a directory
is frequently accessed, it is likely to be recognized as a block cache.
However, when the directory is removed, file may be created on the same
block, and the block is now as a file cache block now.
  • Loading branch information
ChenRuiwei committed Jul 20, 2024
1 parent abba55d commit 068f3ad
Show file tree
Hide file tree
Showing 7 changed files with 55 additions and 15 deletions.
15 changes: 9 additions & 6 deletions driver/src/virtio/virtio_blk.rs
Original file line number Diff line number Diff line change
Expand Up @@ -30,8 +30,15 @@ impl BlockDriverOps for VirtIoBlkDev {
BLOCK_SIZE
}

fn buffer_head_cnts(&self) -> usize {
self.cache.lock().buffer_heads.len()
}

fn remove_buffer_page(&self, block_id: usize) {
self.cache.lock().pages.pop(&block_id);
}

fn base_read_block(&self, block_id: usize, buf: &mut [u8]) {
// log::error!("read blk id {}", block_id);
let res = self.device.lock().read_blocks(block_id, buf);
if res.is_err() {
panic!(
Expand All @@ -55,10 +62,6 @@ impl BlockDriverOps for VirtIoBlkDev {
fn write_block(&self, block_id: usize, buf: &[u8]) {
self.cache.lock().write_block(block_id, buf)
}

fn buffer_head_cnts(&self) -> usize {
self.cache.lock().buffer_heads.len()
}
}

impl VirtIoBlkDev {
Expand All @@ -80,7 +83,7 @@ impl VirtIoBlkDev {
name: "virtio-blk".to_string(),
mmio_base,
mmio_size,
irq_no: None, // TODO: block device don't support interrupts in this system
irq_no: None, // TODO: support interrupt for block device
dtype: DeviceType::Block,
};
let blk_dev = Arc::new(Self {
Expand Down
7 changes: 5 additions & 2 deletions kernel/src/task/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -28,8 +28,11 @@ pub fn spawn_init_proc() {
let argv = Vec::new();
let envp = Vec::new();

let path = Path::new(sys_root_dentry(), sys_root_dentry(), init_proc_path);
let file = path.walk().unwrap().open().unwrap();
let file = Path::new(sys_root_dentry(), sys_root_dentry(), init_proc_path)
.walk()
.unwrap()
.open()
.unwrap();
let elf_data = block_on(async { file.read_all().await }).unwrap();

let mut memory_space = MemorySpace::new_user();
Expand Down
2 changes: 2 additions & 0 deletions modules/device-core/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -101,6 +101,8 @@ pub trait BlockDriverOps: BaseDriverOps {

fn buffer_head_cnts(&self) -> usize;

fn remove_buffer_page(&self, block_id: usize);

/// Read data form block to buffer
fn base_read_block(&self, block_id: usize, buf: &mut [u8]);

Expand Down
2 changes: 1 addition & 1 deletion modules/ext4/src/dentry.rs
Original file line number Diff line number Diff line change
Expand Up @@ -107,7 +107,7 @@ impl Dentry for Ext4Dentry {
.unwrap_or_else(|_| unreachable!());
let sub_dentry = self.get_child(name).unwrap();
let fpath = sub_dentry.path();
log::debug!("[Ext4Dentry::base_remove] path: {fpath}");
log::info!("[Ext4Dentry::base_remove] path: {fpath}");
let mut file = inode.file.lock();
if file.check_inode_exist(&fpath, InodeTypes::EXT4_DE_DIR) {
// Recursive directory remove
Expand Down
25 changes: 20 additions & 5 deletions modules/page/src/buffer_cache.rs
Original file line number Diff line number Diff line change
Expand Up @@ -22,19 +22,20 @@ use lru::LruCache;
use spin::Once;
use sync::mutex::SpinNoIrqLock;

use crate::Page;
use crate::{Page, PageKind};

pub struct BufferCache {
device: Option<Weak<dyn BlockDriverOps>>,
/// Block page id to `Page`.
// NOTE: These `Page`s are pages without file, only exist for caching pure
// block data.
pages: LruCache<usize, Arc<Page>>,
pub pages: LruCache<usize, Arc<Page>>,
/// Block idx to `BufferHead`.
// TODO: add lru support, otherwise may occupy too much heap space
// NOTE: Stores all accesses to block device. Some of them will be attached
// to pages above, while others with file related will be attached to pages
// stored in address space.
// PERF: perf issue will happen when lru cache is full
pub buffer_heads: LruCache<usize, Arc<BufferHead>>,
}

Expand Down Expand Up @@ -80,7 +81,7 @@ impl BufferCache {
buffer_head.inc_acc_cnt();
// log::error!("acc cnt {}", buffer_head.acc_cnt());
if buffer_head.need_cache() && !buffer_head.has_cached() {
// log::error!("need cache");
// log::error!("block id {block_id} need cache");
if let Some(page) = self.pages.get_mut(&block_page_id(block_id)) {
// log::error!("has page");
device.base_read_block(block_id, page.block_bytes_array(block_id));
Expand Down Expand Up @@ -166,10 +167,24 @@ impl BufferHead {
pub fn init(&self, page: &Arc<Page>, offset: usize) {
if self.has_cached() {
log::error!(
"block id {} already cached, with acc_cnt {}",
"block id {} already cached, with acc_cnt {}, page kind {:?}",
self.block_id,
self.acc_cnt()
self.acc_cnt(),
self.page().kind()
);
// only block cache can be transfered to file cache, e.g. a directory is mis
// recognized as block cache
assert!(self.page().kind().is_block_cache());
assert!(page.kind().is_file_cache());
match &self.page().kind() {
PageKind::BlockCache(inner) => {
let mut inner = inner.lock();
let device = inner.device.upgrade().unwrap();
device.remove_buffer_page(self.block_id);
// block page should be dropped here
}
_ => panic!(),
}
}
debug_assert!(is_aligned_to_block(offset) && offset < PAGE_SIZE);
let mut inner = self.inner.lock();
Expand Down
16 changes: 15 additions & 1 deletion modules/page/src/page.rs
Original file line number Diff line number Diff line change
Expand Up @@ -23,13 +23,27 @@ pub enum PageKind {
BlockCache(SpinNoIrqLock<BufferInfo>),
}

impl core::fmt::Debug for PageKind {
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
f.debug_struct("PageKind")
.field("kind", &{
match self {
PageKind::Normal => "normal",
PageKind::FileCache(_) => "file cache",
PageKind::BlockCache(_) => "block cache",
}
})
.finish()
}
}

pub struct Page {
frame: FrameTracker,
kind: PageKind,
}

pub struct BufferInfo {
device: Weak<dyn BlockDriverOps>,
pub device: Weak<dyn BlockDriverOps>,
buffer_heads: LinkedList<BufferHeadAdapter>,
buffer_head_cnts: usize,
}
Expand Down
3 changes: 3 additions & 0 deletions modules/vfs-core/src/file.rs
Original file line number Diff line number Diff line change
Expand Up @@ -333,8 +333,11 @@ impl dyn File {
let offset_aligned_block = offset_aligned_page + i * BLOCK_SIZE;
if offset_aligned_block < new_size {
let blk_idx = inode.get_blk_idx(offset_aligned_block)?;
log::debug!("offset {offset_aligned_block}, blk idx {blk_idx}");
let buffer_head = buffer_caches.get_buffer_head_or_create(blk_idx);
page.insert_buffer_head(buffer_head);
} else {
break;
}
}
}
Expand Down

0 comments on commit 068f3ad

Please sign in to comment.