Add comments in ch6

This commit is contained in:
hypocrasy 2022-04-30 16:04:58 +08:00
parent cea2febe35
commit f9346edad1
35 changed files with 374 additions and 116 deletions

View file

@ -1,16 +1,16 @@
use super::{get_block_cache, BlockDevice, BLOCK_SZ};
use alloc::sync::Arc;
/// A bitmap block
type BitmapBlock = [u64; 64];
/// Number of bits in a block
const BLOCK_BITS: usize = BLOCK_SZ * 8;
/// A bitmap
pub struct Bitmap {
start_block_id: usize,
blocks: usize,
}
/// Return (block_pos, bits64_pos, inner_pos)
/// Decompose bits into (block_pos, bits64_pos, inner_pos)
fn decomposition(mut bit: usize) -> (usize, usize, usize) {
let block_pos = bit / BLOCK_BITS;
bit %= BLOCK_BITS;
@ -18,13 +18,14 @@ fn decomposition(mut bit: usize) -> (usize, usize, usize) {
}
impl Bitmap {
/// A new bitmap from start block id and number of blocks
pub fn new(start_block_id: usize, blocks: usize) -> Self {
Self {
start_block_id,
blocks,
}
}
/// Allocate a new block from a block device
pub fn alloc(&self, block_device: &Arc<dyn BlockDevice>) -> Option<usize> {
for block_id in 0..self.blocks {
let pos = get_block_cache(
@ -52,7 +53,7 @@ impl Bitmap {
}
None
}
/// Deallocate a block
pub fn dealloc(&self, block_device: &Arc<dyn BlockDevice>, bit: usize) {
let (block_pos, bits64_pos, inner_pos) = decomposition(bit);
get_block_cache(block_pos + self.start_block_id, Arc::clone(block_device))
@ -62,7 +63,7 @@ impl Bitmap {
bitmap_block[bits64_pos] -= 1u64 << inner_pos;
});
}
/// Get the max number of allocatable blocks
pub fn maximum(&self) -> usize {
self.blocks * BLOCK_BITS
}

View file

@ -3,11 +3,15 @@ use alloc::collections::VecDeque;
use alloc::sync::Arc;
use lazy_static::*;
use spin::Mutex;
/// Cached block inside memory
pub struct BlockCache {
/// cached block data
cache: [u8; BLOCK_SZ],
/// underlying block id
block_id: usize,
/// underlying block device
block_device: Arc<dyn BlockDevice>,
/// whether the block is dirty
modified: bool,
}
@ -23,7 +27,7 @@ impl BlockCache {
modified: false,
}
}
/// Get the address of an offset inside the cached block data
fn addr_of_offset(&self, offset: usize) -> usize {
&self.cache[offset] as *const _ as usize
}
@ -70,7 +74,7 @@ impl Drop for BlockCache {
self.sync()
}
}
/// Use a block cache of 16 blocks
const BLOCK_CACHE_SIZE: usize = 16;
pub struct BlockCacheManager {
@ -118,10 +122,11 @@ impl BlockCacheManager {
}
lazy_static! {
/// The global block cache manager
pub static ref BLOCK_CACHE_MANAGER: Mutex<BlockCacheManager> =
Mutex::new(BlockCacheManager::new());
}
/// Get the block cache corresponding to the given block id and block device
pub fn get_block_cache(
block_id: usize,
block_device: Arc<dyn BlockDevice>,
@ -130,7 +135,7 @@ pub fn get_block_cache(
.lock()
.get_block_cache(block_id, block_device)
}
/// Sync all block cache to block device
pub fn block_cache_sync_all() {
let manager = BLOCK_CACHE_MANAGER.lock();
for (_, cache) in manager.queue.iter() {

View file

@ -1,6 +1,9 @@
use core::any::Any;
/// Trait for block devices
/// which reads and writes data in the unit of blocks
pub trait BlockDevice: Send + Sync + Any {
///Read data form block to buffer
fn read_block(&self, block_id: usize, buf: &mut [u8]);
///Write data from buffer to block
fn write_block(&self, block_id: usize, buf: &[u8]);
}

View file

@ -5,18 +5,22 @@ use super::{
use crate::BLOCK_SZ;
use alloc::sync::Arc;
use spin::Mutex;
///An easy file system on block
pub struct EasyFileSystem {
///Real device
pub block_device: Arc<dyn BlockDevice>,
///Inode bitmap
pub inode_bitmap: Bitmap,
///Data bitmap
pub data_bitmap: Bitmap,
inode_area_start_block: u32,
data_area_start_block: u32,
}
type DataBlock = [u8; BLOCK_SZ];
/// An easy fs over a block device
impl EasyFileSystem {
/// A data block of block size
pub fn create(
block_device: Arc<dyn BlockDevice>,
total_blocks: u32,
@ -77,7 +81,7 @@ impl EasyFileSystem {
block_cache_sync_all();
Arc::new(Mutex::new(efs))
}
/// Open a block device as a filesystem
pub fn open(block_device: Arc<dyn BlockDevice>) -> Arc<Mutex<Self>> {
// read SuperBlock
get_block_cache(0, Arc::clone(&block_device))
@ -99,7 +103,7 @@ impl EasyFileSystem {
Arc::new(Mutex::new(efs))
})
}
/// Get the root inode of the filesystem
pub fn root_inode(efs: &Arc<Mutex<Self>>) -> Inode {
let block_device = Arc::clone(&efs.lock().block_device);
// acquire efs lock temporarily
@ -107,7 +111,7 @@ impl EasyFileSystem {
// release efs lock
Inode::new(block_id, block_offset, Arc::clone(efs), block_device)
}
/// Get inode by id
pub fn get_disk_inode_pos(&self, inode_id: u32) -> (u32, usize) {
let inode_size = core::mem::size_of::<DiskInode>();
let inodes_per_block = (BLOCK_SZ / inode_size) as u32;
@ -117,20 +121,20 @@ impl EasyFileSystem {
(inode_id % inodes_per_block) as usize * inode_size,
)
}
/// Get data block by id
pub fn get_data_block_id(&self, data_block_id: u32) -> u32 {
self.data_area_start_block + data_block_id
}
/// Allocate a new inode
pub fn alloc_inode(&mut self) -> u32 {
self.inode_bitmap.alloc(&self.block_device).unwrap() as u32
}
/// Return a block ID not ID in the data area.
/// Allocate a data block
pub fn alloc_data(&mut self) -> u32 {
self.data_bitmap.alloc(&self.block_device).unwrap() as u32 + self.data_area_start_block
}
/// Deallocate a data block
pub fn dealloc_data(&mut self, block_id: u32) {
get_block_cache(block_id as usize, Arc::clone(&self.block_device))
.lock()

View file

@ -3,16 +3,24 @@ use alloc::sync::Arc;
use alloc::vec::Vec;
use core::fmt::{Debug, Formatter, Result};
/// Magic number for sanity check
const EFS_MAGIC: u32 = 0x3b800001;
/// The max number of direct inodes
const INODE_DIRECT_COUNT: usize = 28;
/// The max length of inode name
const NAME_LENGTH_LIMIT: usize = 27;
/// The max number of indirect1 inodes
const INODE_INDIRECT1_COUNT: usize = BLOCK_SZ / 4;
/// The max number of indirect2 inodes
const INODE_INDIRECT2_COUNT: usize = INODE_INDIRECT1_COUNT * INODE_INDIRECT1_COUNT;
/// The upper bound of direct inode index
const DIRECT_BOUND: usize = INODE_DIRECT_COUNT;
/// The upper bound of indirect1 inode index
const INDIRECT1_BOUND: usize = DIRECT_BOUND + INODE_INDIRECT1_COUNT;
/// The upper bound of indirect2 inode indexs
#[allow(unused)]
const INDIRECT2_BOUND: usize = INDIRECT1_BOUND + INODE_INDIRECT2_COUNT;
/// Super block of a filesystem
#[repr(C)]
pub struct SuperBlock {
magic: u32,
@ -36,6 +44,7 @@ impl Debug for SuperBlock {
}
impl SuperBlock {
/// Initialize a super block
pub fn initialize(
&mut self,
total_blocks: u32,
@ -53,20 +62,23 @@ impl SuperBlock {
data_area_blocks,
}
}
/// Check if a super block is valid using efs magic
pub fn is_valid(&self) -> bool {
self.magic == EFS_MAGIC
}
}
/// Type of a disk inode
#[derive(PartialEq)]
pub enum DiskInodeType {
File,
Directory,
}
/// A indirect block
type IndirectBlock = [u32; BLOCK_SZ / 4];
/// A data block
type DataBlock = [u8; BLOCK_SZ];
/// A disk inode
#[repr(C)]
pub struct DiskInode {
pub size: u32,
@ -77,7 +89,8 @@ pub struct DiskInode {
}
impl DiskInode {
/// indirect1 and indirect2 block are allocated only when they are needed.
/// Initialize a disk inode, as well as all direct inodes under it
/// indirect1 and indirect2 block are allocated only when they are needed
pub fn initialize(&mut self, type_: DiskInodeType) {
self.size = 0;
self.direct.iter_mut().for_each(|v| *v = 0);
@ -85,9 +98,11 @@ impl DiskInode {
self.indirect2 = 0;
self.type_ = type_;
}
/// Whether this inode is a directory
pub fn is_dir(&self) -> bool {
self.type_ == DiskInodeType::Directory
}
/// Whether this inode is a file
#[allow(unused)]
pub fn is_file(&self) -> bool {
self.type_ == DiskInodeType::File
@ -116,10 +131,12 @@ impl DiskInode {
}
total as u32
}
/// Get the number of data blocks that have to be allocated given the new size of data
pub fn blocks_num_needed(&self, new_size: u32) -> u32 {
assert!(new_size >= self.size);
Self::total_blocks(new_size) - Self::total_blocks(self.size)
}
/// Get id of block given inner id
pub fn get_block_id(&self, inner_id: u32, block_device: &Arc<dyn BlockDevice>) -> u32 {
let inner_id = inner_id as usize;
if inner_id < INODE_DIRECT_COUNT {
@ -144,6 +161,7 @@ impl DiskInode {
})
}
}
/// Inncrease the size of current disk inode
pub fn increase_size(
&mut self,
new_size: u32,
@ -218,7 +236,6 @@ impl DiskInode {
}
/// Clear size to zero and return blocks that should be deallocated.
///
/// We will clear the block contents to zero later.
pub fn clear_size(&mut self, block_device: &Arc<dyn BlockDevice>) -> Vec<u32> {
let mut v: Vec<u32> = Vec::new();
@ -291,6 +308,7 @@ impl DiskInode {
self.indirect2 = 0;
v
}
/// Read data from current disk inode
pub fn read_at(
&self,
offset: usize,
@ -330,7 +348,8 @@ impl DiskInode {
}
read_size
}
/// File size must be adjusted before.
/// Write data into current disk inode
/// size must be adjusted properly beforehand
pub fn write_at(
&mut self,
offset: usize,
@ -369,22 +388,24 @@ impl DiskInode {
write_size
}
}
/// A directory entry
#[repr(C)]
pub struct DirEntry {
name: [u8; NAME_LENGTH_LIMIT + 1],
inode_number: u32,
}
/// Size of a directory entry
pub const DIRENT_SZ: usize = 32;
impl DirEntry {
/// Create an empty directory entry
pub fn empty() -> Self {
Self {
name: [0u8; NAME_LENGTH_LIMIT + 1],
inode_number: 0,
}
}
/// Crate a directory entry from name and inode number
pub fn new(name: &str, inode_number: u32) -> Self {
let mut bytes = [0u8; NAME_LENGTH_LIMIT + 1];
bytes[..name.len()].copy_from_slice(name.as_bytes());
@ -393,16 +414,20 @@ impl DirEntry {
inode_number,
}
}
/// Serialize into bytes
pub fn as_bytes(&self) -> &[u8] {
unsafe { core::slice::from_raw_parts(self as *const _ as usize as *const u8, DIRENT_SZ) }
}
/// Serialize into mutable bytes
pub fn as_bytes_mut(&mut self) -> &mut [u8] {
unsafe { core::slice::from_raw_parts_mut(self as *mut _ as usize as *mut u8, DIRENT_SZ) }
}
/// Get name of the entry
pub fn name(&self) -> &str {
let len = (0usize..).find(|i| self.name[*i] == 0).unwrap();
core::str::from_utf8(&self.name[..len]).unwrap()
}
/// Get inode number of the entry
pub fn inode_number(&self) -> u32 {
self.inode_number
}

View file

@ -1,14 +1,14 @@
//!An easy file system isolated from the kernel
#![no_std]
#![deny(missing_docs)]
extern crate alloc;
mod bitmap;
mod block_cache;
mod block_dev;
mod efs;
mod layout;
mod vfs;
/// Use a block size of 512 bytes
pub const BLOCK_SZ: usize = 512;
use bitmap::Bitmap;
use block_cache::{block_cache_sync_all, get_block_cache};

View file

@ -6,7 +6,7 @@ use alloc::string::String;
use alloc::sync::Arc;
use alloc::vec::Vec;
use spin::{Mutex, MutexGuard};
/// Virtual filesystem layer over easy-fs
pub struct Inode {
block_id: usize,
block_offset: usize,
@ -15,7 +15,7 @@ pub struct Inode {
}
impl Inode {
/// We should not acquire efs lock here.
/// Create a vfs inode
pub fn new(
block_id: u32,
block_offset: usize,
@ -29,19 +29,19 @@ impl Inode {
block_device,
}
}
/// Call a function over a disk inode to read it
fn read_disk_inode<V>(&self, f: impl FnOnce(&DiskInode) -> V) -> V {
get_block_cache(self.block_id, Arc::clone(&self.block_device))
.lock()
.read(self.block_offset, f)
}
/// Call a function over a disk inode to modify it
fn modify_disk_inode<V>(&self, f: impl FnOnce(&mut DiskInode) -> V) -> V {
get_block_cache(self.block_id, Arc::clone(&self.block_device))
.lock()
.modify(self.block_offset, f)
}
/// Find inode under a disk inode by name
fn find_inode_id(&self, name: &str, disk_inode: &DiskInode) -> Option<u32> {
// assert it is a directory
assert!(disk_inode.is_dir());
@ -58,7 +58,7 @@ impl Inode {
}
None
}
/// Find inode under current inode by name
pub fn find(&self, name: &str) -> Option<Arc<Inode>> {
let fs = self.fs.lock();
self.read_disk_inode(|disk_inode| {
@ -73,7 +73,7 @@ impl Inode {
})
})
}
/// Increase the size of a disk inode
fn increase_size(
&self,
new_size: u32,
@ -90,7 +90,7 @@ impl Inode {
}
disk_inode.increase_size(new_size, v, &self.block_device);
}
/// Create inode under current inode by name
pub fn create(&self, name: &str) -> Option<Arc<Inode>> {
let mut fs = self.fs.lock();
let op = |root_inode: &DiskInode| {
@ -138,7 +138,7 @@ impl Inode {
)))
// release efs lock automatically by compiler
}
/// List inodes under current inode
pub fn ls(&self) -> Vec<String> {
let _fs = self.fs.lock();
self.read_disk_inode(|disk_inode| {
@ -155,12 +155,12 @@ impl Inode {
v
})
}
/// Read data from current inode
pub fn read_at(&self, offset: usize, buf: &mut [u8]) -> usize {
let _fs = self.fs.lock();
self.read_disk_inode(|disk_inode| disk_inode.read_at(offset, buf, &self.block_device))
}
/// Write data to current inode
pub fn write_at(&self, offset: usize, buf: &[u8]) -> usize {
let mut fs = self.fs.lock();
let size = self.modify_disk_inode(|disk_inode| {
@ -170,7 +170,7 @@ impl Inode {
block_cache_sync_all();
size
}
/// Clear the data in current inode
pub fn clear(&self) {
let mut fs = self.fs.lock();
self.modify_disk_inode(|disk_inode| {