create & open efs.

This commit is contained in:
Yifan Wu 2020-12-18 15:56:11 +08:00
parent 84900e8b94
commit af02e68d19
10 changed files with 420 additions and 0 deletions

3
easy-fs/.gitignore vendored Normal file
View File

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

9
easy-fs/Cargo.toml Normal file
View File

@ -0,0 +1,9 @@
[package]
name = "easy-fs"
version = "0.1.0"
authors = ["Yifan Wu <shinbokuow@163.com>"]
edition = "2018"
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
[dependencies]

53
easy-fs/src/bin/main.rs Normal file
View File

@ -0,0 +1,53 @@
extern crate easy_fs;
extern crate alloc;
use easy_fs::{
BlockDevice,
EasyFileSystem,
};
use std::fs::{File, OpenOptions};
use std::io::{Read, Write, Seek, SeekFrom};
use std::sync::Mutex;
use alloc::sync::Arc;
const BLOCK_SZ: usize = 512;
struct BlockFile(Mutex<File>);
impl BlockDevice for BlockFile {
fn read_block(&self, block_id: usize, buf: &mut [u8]) {
let mut file = self.0.lock().unwrap();
file.seek(SeekFrom::Start((block_id * BLOCK_SZ) as u64))
.expect("Error when seeking!");
assert_eq!(file.read(buf).unwrap(), BLOCK_SZ, "Not a complete block!");
}
fn write_block(&self, block_id: usize, buf: &[u8]) {
let mut file = self.0.lock().unwrap();
file.seek(SeekFrom::Start((block_id * BLOCK_SZ) as u64))
.expect("Error when seeking!");
assert_eq!(file.write(buf).unwrap(), BLOCK_SZ, "Not a complete block!");
}
}
fn main() {
easy_fs_pack().expect("Error when packing easy-fs!");
}
fn easy_fs_pack() -> std::io::Result<()> {
let block_file = BlockFile(Mutex::new(
OpenOptions::new()
.read(true)
.write(true)
.open("target/fs.img")?
));
/*
let _efs = EasyFileSystem::create(
Arc::new(block_file),
4096,
1,
);
*/
let _efs = EasyFileSystem::open(Arc::new(block_file));
Ok(())
}

67
easy-fs/src/bitmap.rs Normal file
View File

@ -0,0 +1,67 @@
use alloc::sync::Arc;
use super::BlockDevice;
use super::Dirty;
use super::BLOCK_SZ;
type BitmapBlock = [u64; 64];
const BLOCK_BITS: usize = BLOCK_SZ * 8;
pub struct Bitmap {
start_block_id: usize,
blocks: usize,
}
/// Return (block_pos, bits64_pos, inner_pos)
fn decomposition(mut bit: usize) -> (usize, usize, usize) {
let block_pos = bit / BLOCK_BITS;
bit = bit % BLOCK_BITS;
(block_pos, bit/64, bit % 64)
}
impl Bitmap {
pub fn new(start_block_id: usize, blocks: usize) -> Self {
Self {
start_block_id,
blocks,
}
}
pub fn alloc(&self, block_device: &Arc<dyn BlockDevice>) -> Option<usize> {
for block_id in 0..self.blocks {
let mut dirty_bitmap_block: Dirty<BitmapBlock> = Dirty::new(
block_id + self.start_block_id as usize,
0,
block_device.clone()
);
let bitmap_block = dirty_bitmap_block.get_mut();
if let Some((bits64_pos, inner_pos)) = bitmap_block
.iter()
.enumerate()
.find(|(_, bits64)| **bits64 != u64::MAX)
.map(|(bits64_pos, bits64)| {
(bits64_pos, bits64.trailing_ones() as usize)
}) {
// modify cache
bitmap_block[bits64_pos] |= 1u64 << inner_pos;
return Some(block_id * BLOCK_BITS + bits64_pos * 64 + inner_pos as usize);
// after dirty is dropped, data will be written back automatically
}
}
None
}
pub fn dealloc(&self, block_device: &Arc<dyn BlockDevice>, bit: usize) {
let (block_pos, bits64_pos, inner_pos) = decomposition(bit);
let mut dirty_bitmap_block: Dirty<BitmapBlock> = Dirty::new(
block_pos,
0,
block_device.clone(),
);
dirty_bitmap_block.modify(|bitmap_block| {
assert!(bitmap_block[bits64_pos] & (1u64 << inner_pos) > 0);
bitmap_block[bits64_pos] -= 1u64 << inner_pos;
});
}
pub fn maximum(&self) -> usize {
self.blocks * BLOCK_BITS
}
}

6
easy-fs/src/block_dev.rs Normal file
View File

@ -0,0 +1,6 @@
use core::any::Any;
pub trait BlockDevice : Send + Sync + Any {
fn read_block(&self, block_id: usize, buf: &mut [u8]);
fn write_block(&self, block_id: usize, buf: &[u8]);
}

54
easy-fs/src/dirty.rs Normal file
View File

@ -0,0 +1,54 @@
use super::BlockDevice;
use super::BLOCK_SZ;
use alloc::sync::Arc;
use core::marker::PhantomData;
pub struct Dirty<T> {
block_id: usize,
block_cache: [u8; BLOCK_SZ],
offset: usize,
block_device: Arc<dyn BlockDevice>,
phantom: PhantomData<T>,
}
impl<T> Dirty<T> where T: Sized {
pub fn new(block_id: usize, offset: usize, block_device: Arc<dyn BlockDevice>) -> Self {
Self {
block_id,
block_cache: {
let mut cache = [0u8; BLOCK_SZ];
block_device.read_block(block_id as usize, &mut cache);
cache
},
offset,
block_device,
phantom: PhantomData,
}
}
pub fn get_mut(&mut self) -> &mut T {
let type_size = core::mem::size_of::<T>();
// assert that the struct is inside a block
assert!(self.offset + type_size <= BLOCK_SZ);
let start_addr = &self.block_cache[self.offset] as *const _ as usize;
unsafe { &mut *(start_addr as *mut T) }
}
pub fn read(&self) -> &T {
let type_size = core::mem::size_of::<T>();
// assert that the struct is inside a block
assert!(self.offset + type_size <= BLOCK_SZ);
let start_addr = &self.block_cache[self.offset] as *const _ as usize;
unsafe { &*(start_addr as *const T) }
}
pub fn modify(&mut self, f: impl Fn(&mut T)) {
f(self.get_mut());
}
pub fn write_back(&mut self) {
self.block_device.write_block(self.block_id as usize, &self.block_cache);
}
}
impl<T> Drop for Dirty<T> {
fn drop(&mut self) {
self.write_back();
}
}

130
easy-fs/src/efs.rs Normal file
View File

@ -0,0 +1,130 @@
use alloc::sync::Arc;
use super::{
BlockDevice,
Bitmap,
SuperBlock,
DiskInode,
DiskInodeType,
Dirty,
};
use crate::BLOCK_SZ;
pub struct EasyFileSystem {
pub block_device: Arc<dyn BlockDevice>,
pub inode_bitmap: Bitmap,
pub data_bitmap: Bitmap,
inode_area_start_block: u32,
data_area_start_block: u32,
}
type DataBlock = [u8; BLOCK_SZ];
impl EasyFileSystem {
pub fn create(
block_device: Arc<dyn BlockDevice>,
total_blocks: u32,
inode_bitmap_blocks: u32,
) -> Self {
// calculate block size of areas & create bitmaps
let inode_bitmap = Bitmap::new(1, inode_bitmap_blocks as usize);
let inode_num = inode_bitmap.maximum();
let inode_area_blocks =
((inode_num * core::mem::size_of::<DiskInode>() + BLOCK_SZ - 1) / BLOCK_SZ) as u32;
let inode_total_blocks = inode_bitmap_blocks + inode_area_blocks;
let data_total_blocks = total_blocks - 1 - inode_total_blocks;
let data_bitmap_blocks = (data_total_blocks + 4096) / 4097;
let data_area_blocks = data_total_blocks - data_bitmap_blocks;
let data_bitmap = Bitmap::new(
(1 + inode_bitmap_blocks + inode_area_blocks) as usize,
data_bitmap_blocks as usize,
);
let efs = Self {
block_device,
inode_bitmap,
data_bitmap,
inode_area_start_block: 1 + inode_bitmap_blocks,
data_area_start_block: 1 + inode_total_blocks + data_bitmap_blocks,
};
// clear all blocks
for i in 0..total_blocks {
efs.get_block(i).modify(|data_block| {
for byte in data_block.iter_mut() {
*byte = 0;
}
});
}
// initialize SuperBlock
efs.get_super_block().modify(|super_block| {
super_block.initialize(
total_blocks,
inode_bitmap_blocks,
inode_area_blocks,
data_bitmap_blocks,
data_area_blocks,
);
});
// write back immediately
// create a inode for root node "/"
assert_eq!(efs.inode_bitmap.alloc(&efs.block_device).unwrap(), 0);
efs.get_disk_inode(0).modify(|disk_inode| {
disk_inode.initialize(DiskInodeType::Directory);
});
efs
}
pub fn open(block_device: Arc<dyn BlockDevice>) -> Self {
// read SuperBlock
let super_block_dirty: Dirty<SuperBlock> = Dirty::new(0, 0, block_device.clone());
let super_block = super_block_dirty.read();
assert!(super_block.is_valid(), "Error loading EFS!");
println!("{:?}", super_block);
let inode_total_blocks =
super_block.inode_bitmap_blocks + super_block.inode_area_blocks;
let efs = Self {
block_device,
inode_bitmap: Bitmap::new(
1,
super_block.inode_bitmap_blocks as usize
),
data_bitmap: Bitmap::new(
(1 + inode_total_blocks) as usize,
super_block.data_bitmap_blocks as usize,
),
inode_area_start_block: 1 + super_block.inode_bitmap_blocks,
data_area_start_block: 1 + inode_total_blocks + super_block.data_bitmap_blocks,
};
efs
}
fn get_super_block(&self) -> Dirty<SuperBlock> {
Dirty::new(0, 0, self.block_device.clone())
}
fn get_disk_inode(&self, inode_id: u32) -> Dirty<DiskInode> {
let inode_size = core::mem::size_of::<DiskInode>();
let inodes_per_block = (BLOCK_SZ / inode_size) as u32;
let block_id = self.inode_area_start_block + inode_id / inodes_per_block;
Dirty::new(
block_id as usize,
(inode_id % inodes_per_block) as usize * inode_size,
self.block_device.clone(),
)
}
fn get_data_block(&self, data_block_id: u32) -> Dirty<DataBlock> {
Dirty::new(
(self.data_area_start_block + data_block_id) as usize,
0,
self.block_device.clone(),
)
}
fn get_block(&self, block_id: u32) -> Dirty<DataBlock> {
Dirty::new(
block_id as usize,
0,
self.block_device.clone(),
)
}
}

80
easy-fs/src/layout.rs Normal file
View File

@ -0,0 +1,80 @@
use core::fmt::{Debug, Formatter, Result};
const EFS_MAGIC: u32 = 0x3b800001;
const INODE_DIRECT_COUNT: usize = 12;
const NAME_LENGTH_LIMIT: usize = 27;
#[repr(C)]
pub struct SuperBlock {
magic: u32,
pub total_blocks: u32,
pub inode_bitmap_blocks: u32,
pub inode_area_blocks: u32,
pub data_bitmap_blocks: u32,
pub data_area_blocks: u32,
}
impl Debug for SuperBlock {
fn fmt(&self, f: &mut Formatter<'_>) -> Result {
f.debug_struct("SuperBlock")
.field("total_blocks", &self.total_blocks)
.field("inode_bitmap_blocks", &self.inode_bitmap_blocks)
.field("inode_area_blocks", &self.inode_area_blocks)
.field("data_bitmap_blocks", &self.data_bitmap_blocks)
.field("data_area_blocks", &self.data_area_blocks)
.finish()
}
}
impl SuperBlock {
pub fn initialize(
&mut self,
total_blocks: u32,
inode_bitmap_blocks: u32,
inode_area_blocks: u32,
data_bitmap_blocks: u32,
data_area_blocks: u32,
) {
*self = Self {
magic: EFS_MAGIC,
total_blocks,
inode_bitmap_blocks,
inode_area_blocks,
data_bitmap_blocks,
data_area_blocks,
}
}
pub fn is_valid(&self) -> bool {
self.magic == EFS_MAGIC
}
}
pub enum DiskInodeType {
File,
Directory,
}
#[repr(C)]
pub struct DiskInode {
size: u32,
direct: [u32; INODE_DIRECT_COUNT],
indirect1: u32,
indirect2: u32,
type_: DiskInodeType,
}
impl DiskInode {
pub fn initialize(&mut self, type_: DiskInodeType) {
self.size = 0;
self.direct.iter_mut().for_each(|v| *v = 0);
self.indirect1 = 0;
self.indirect2 = 0;
self.type_ = type_;
}
}
#[repr(C)]
pub struct DirEntry {
name: [u8; NAME_LENGTH_LIMIT + 1],
inode_number: u32,
}

15
easy-fs/src/lib.rs Normal file
View File

@ -0,0 +1,15 @@
extern crate alloc;
mod block_dev;
mod layout;
mod efs;
mod dirty;
mod bitmap;
mod vfs;
pub const BLOCK_SZ: usize = 512;
pub use block_dev::BlockDevice;
pub use efs::EasyFileSystem;
use layout::*;
use dirty::Dirty;
use bitmap::Bitmap;

3
easy-fs/src/vfs.rs Normal file
View File

@ -0,0 +1,3 @@
pub struct Inode {
}