mirror of
https://github.com/rcore-os/rCore-Tutorial-v3.git
synced 2024-11-22 09:26:26 +04:00
create & open efs.
This commit is contained in:
parent
84900e8b94
commit
af02e68d19
3
easy-fs/.gitignore
vendored
Normal file
3
easy-fs/.gitignore
vendored
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
.idea/
|
||||||
|
target/
|
||||||
|
Cargo.lock
|
9
easy-fs/Cargo.toml
Normal file
9
easy-fs/Cargo.toml
Normal 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
53
easy-fs/src/bin/main.rs
Normal 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
67
easy-fs/src/bitmap.rs
Normal 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
6
easy-fs/src/block_dev.rs
Normal 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
54
easy-fs/src/dirty.rs
Normal 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
130
easy-fs/src/efs.rs
Normal 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
80
easy-fs/src/layout.rs
Normal 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
15
easy-fs/src/lib.rs
Normal 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
3
easy-fs/src/vfs.rs
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
pub struct Inode {
|
||||||
|
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user