summaryrefslogtreecommitdiff
path: root/src/memory
diff options
context:
space:
mode:
Diffstat (limited to 'src/memory')
-rw-r--r--src/memory/cached_block.rs84
-rw-r--r--src/memory/cached_inode.rs51
-rw-r--r--src/memory/mod.rs5
3 files changed, 140 insertions, 0 deletions
diff --git a/src/memory/cached_block.rs b/src/memory/cached_block.rs
new file mode 100644
index 0000000..0c401ff
--- /dev/null
+++ b/src/memory/cached_block.rs
@@ -0,0 +1,84 @@
+use and_then_some::BoolExt;
+use crate::AyaFS;
+use crate::block_device::BLOCK_SIZE;
+use crate::disk::data_block::{Block, DataBlock};
+
+#[derive(Clone)]
+pub struct CachedBlock<T: Block> {
+ pub block: T,
+ pub index: usize,
+ pub dirty: bool,
+}
+
+impl<T: Block> CachedBlock<T> {
+ fn cast<U: Block>(&self) -> CachedBlock<U> {
+ unsafe { std::mem::transmute_copy(&self) }
+ }
+}
+
+pub fn convert_mut<U: Block, T: Block>(input_block: &mut CachedBlock<U>) -> &mut CachedBlock<T> {
+ let ptr = input_block as *const CachedBlock<U> as *mut u8;
+ let block = ptr.cast::<CachedBlock<T>>();
+ unsafe { &mut *block }
+}
+
+pub fn convert<U: Block, T: Block>(input_block: &CachedBlock<U>) -> &CachedBlock<T> {
+ let ptr = input_block as *const CachedBlock<U> as *mut u8;
+ let block = ptr.cast::<CachedBlock<T>>();
+ unsafe { &*block }
+}
+
+impl AyaFS {
+ pub(crate) fn update_block<T: Block>(&mut self, block: CachedBlock<T>) -> bool {
+ if self.cached_blocks.contains(&block.index) {
+ let data_block = convert::<T, DataBlock>(&block).clone();
+ self.cached_blocks.push(block.index, data_block);
+ true
+ } else {
+ false
+ }
+ }
+ pub(crate) fn get_block<T: Block>(&mut self, index: usize) -> Option<&CachedBlock<T>> {
+ self.load_block(index)
+ .and_then(|| self.cached_blocks.get(&index).map(convert::<DataBlock, T>))
+ }
+
+ pub(crate) fn get_block_mut<T: Block>(&mut self, index: usize) -> Option<&mut CachedBlock<T>> {
+ self.load_block(index).and_then(|| {
+ self.cached_blocks
+ .get_mut(&index)
+ .map(convert_mut::<DataBlock, T>)
+ })
+ }
+
+ pub(crate) fn load_block(&mut self, index: usize) -> bool {
+ // 反正我自己保证所有实现了 Block trait 的数据结构都是 4K bytes 长, 来回 cast 没问题
+ // 如果 block cache 里没有这个 block
+ if self.cached_blocks.contains(&index) == false {
+ if self.data_bitmap.query(index) == false {
+ return false;
+ } // 先看这个 block 是不是 valid, 不 valid 直接返回 None
+ let block = DataBlock::default();
+ let buffer = unsafe {
+ std::slice::from_raw_parts_mut(&block as *const DataBlock as *mut u8, BLOCK_SIZE)
+ };
+ self.device.read(index, buffer);
+ let cached_block = CachedBlock {
+ block,
+ index,
+ dirty: false,
+ };
+ if let Some((old_index, old_block)) = self.cached_blocks.push(index, cached_block) {
+ assert_ne!(old_index, index); // 只有 block 不在 cache 里的时候才会插入
+ if old_block.dirty {
+ let old_block_ptr = &old_block.block as *const DataBlock as *mut u8;
+ let old_block_buffer =
+ unsafe { std::slice::from_raw_parts(old_block_ptr, BLOCK_SIZE) };
+ self.device.write(old_index, old_block_buffer);
+ }
+ } // 如果 valid 就放到 block cache 里, 同时将(可能)被驱逐的 block 依据其是否为脏块进行写回
+ }
+
+ true
+ }
+}
diff --git a/src/memory/cached_inode.rs b/src/memory/cached_inode.rs
new file mode 100644
index 0000000..b51d279
--- /dev/null
+++ b/src/memory/cached_inode.rs
@@ -0,0 +1,51 @@
+use and_then_some::BoolExt;
+use crate::AyaFS;
+use crate::disk::data_block::InodeBlock;
+use crate::disk::inode::{Inode, INODE_SIZE, InodeMode};
+
+impl AyaFS {
+ pub(crate) fn create_inode(
+ &mut self,
+ permissions: u16,
+ mode: InodeMode,
+ uid: u32,
+ gid: u32,
+ flags: u32,
+ ) -> Option<usize> {
+ self.inode_bitmap.allocate().map(|inode_index| {
+ self.get_inode_mut(inode_index).map(|inode| {
+ *inode = Inode::make_inode(
+ permissions,
+ mode,
+ uid,
+ gid,
+ Self::time_now(),
+ flags,
+ 0,
+ 0,
+ 0,
+ );
+ });
+ inode_index
+ })
+ }
+
+ pub(crate) fn get_inode(&mut self, inode_index: usize) -> Option<&Inode> {
+ self.inode_bitmap.query(inode_index).and_then(|| {
+ let (block_index, offset) = self.locate_inode(inode_index);
+ self.get_block::<InodeBlock>(block_index)
+ .map(|cached_block| &cached_block.block.inodes[offset / INODE_SIZE])
+ })
+ }
+
+ pub(crate) fn get_inode_mut(&mut self, inode_index: usize) -> Option<&mut Inode> {
+ self.inode_bitmap.query(inode_index).and_then(|| {
+ let (block_index, offset) = self.locate_inode(inode_index);
+ self.get_block_mut::<InodeBlock>(block_index)
+ .map(|cached_block| {
+ cached_block.dirty = true; // 保守一些, 只要返回了 &mut Inode 这个页一定标记为脏
+ &mut cached_block.block.inodes[offset / INODE_SIZE]
+ })
+ })
+ }
+} \ No newline at end of file
diff --git a/src/memory/mod.rs b/src/memory/mod.rs
new file mode 100644
index 0000000..ffdf04c
--- /dev/null
+++ b/src/memory/mod.rs
@@ -0,0 +1,5 @@
+/// In-memory data structures and logic.
+/// This is where the crucial block and inode methods presented to upper calls implemented.
+
+pub mod cached_block;
+pub mod cached_inode;