Refactor easy-fs.

This commit is contained in:
Yifan Wu 2021-02-24 03:34:59 +08:00
parent 84407af1ae
commit cd6dfbf59c
704 changed files with 1594 additions and 278 deletions

View file

@ -1,12 +1,12 @@
use super::{
BlockDevice,
Dirty,
DiskInode,
DiskInodeType,
DirEntry,
DirentBytes,
EasyFileSystem,
DIRENT_SZ,
get_block_cache,
};
use alloc::sync::Arc;
use alloc::string::String;
@ -14,7 +14,8 @@ use alloc::vec::Vec;
use spin::{Mutex, MutexGuard};
pub struct Inode {
inode_id: u32,
block_id: usize,
block_offset: usize,
fs: Arc<Mutex<EasyFileSystem>>,
block_device: Arc<dyn BlockDevice>,
}
@ -25,37 +26,51 @@ impl Inode {
fs: Arc<Mutex<EasyFileSystem>>,
block_device: Arc<dyn BlockDevice>,
) -> Self {
let (block_id, block_offset) = fs.lock().get_disk_inode_pos(inode_id);
Self {
inode_id,
block_id: block_id as usize,
block_offset,
fs,
block_device,
}
}
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)
}
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)
}
/*
fn get_disk_inode(&self, fs: &mut MutexGuard<EasyFileSystem>) -> Dirty<DiskInode> {
fs.get_disk_inode(self.inode_id)
}
*/
fn find_inode_id(
&self,
name: &str,
inode: &Dirty<DiskInode>,
disk_inode: &DiskInode,
) -> Option<u32> {
// assert it is a directory
assert!(inode.read(|inode| inode.is_dir()));
let file_count = inode.read(|inode| {
inode.size as usize
}) / DIRENT_SZ;
assert!(disk_inode.is_dir());
let file_count = (disk_inode.size as usize) / DIRENT_SZ;
let mut dirent_space: DirentBytes = Default::default();
for i in 0..file_count {
assert_eq!(
inode.read(|inode| {
inode.read_at(
DIRENT_SZ * i,
&mut dirent_space,
&self.block_device,
)
}),
disk_inode.read_at(
DIRENT_SZ * i,
&mut dirent_space,
&self.block_device,
),
DIRENT_SZ,
);
let dirent = DirEntry::from_bytes(&dirent_space);
@ -67,9 +82,9 @@ impl Inode {
}
pub fn find(&self, name: &str) -> Option<Arc<Inode>> {
let mut fs = self.fs.lock();
let inode = self.get_disk_inode(&mut fs);
self.find_inode_id(name, &inode)
let _ = self.fs.lock();
self.read_disk_inode(|disk_inode| {
self.find_inode_id(name, disk_inode)
.map(|inode_id| {
Arc::new(Self::new(
inode_id,
@ -77,68 +92,69 @@ impl Inode {
self.block_device.clone(),
))
})
})
}
fn increase_size(
&self,
new_size: u32,
inode: &mut Dirty<DiskInode>,
disk_inode: &mut DiskInode,
fs: &mut MutexGuard<EasyFileSystem>,
) {
let size = inode.read(|inode| inode.size);
if new_size < size {
if new_size < disk_inode.size {
return;
}
let blocks_needed = inode.read(|inode| {
inode.blocks_num_needed(new_size)
});
let blocks_needed = disk_inode.blocks_num_needed(new_size);
let mut v: Vec<u32> = Vec::new();
for _ in 0..blocks_needed {
v.push(fs.alloc_data());
}
inode.modify(|inode| {
inode.increase_size(new_size, v, &self.block_device);
});
disk_inode.increase_size(new_size, v, &self.block_device);
}
pub fn create(&self, name: &str) -> Option<Arc<Inode>> {
let mut fs = self.fs.lock();
let mut inode = self.get_disk_inode(&mut fs);
// assert it is a directory
assert!(inode.read(|inode| inode.is_dir()));
// has the file been created?
if let Some(_) = self.find_inode_id(name, &inode) {
if self.modify_disk_inode(|root_inode| {
// assert it is a directory
assert!(root_inode.is_dir());
// has the file been created?
self.find_inode_id(name, root_inode)
}).is_some() {
return None;
}
//println!("same file does not exist in Inode::create.");
// create a new file
// alloc a inode with an indirect block
let new_inode_id = fs.alloc_inode();
let indirect1 = fs.alloc_data();
// initialize inode
fs.get_disk_inode(new_inode_id).modify(|inode| {
inode.initialize(
DiskInodeType::File,
indirect1,
)
let (new_inode_block_id, new_inode_block_offset)
= fs.get_disk_inode_pos(new_inode_id);
//println!("new_inode_id={} ({},{})", new_inode_id, new_inode_block_id, new_inode_block_offset);
get_block_cache(
new_inode_block_id as usize,
Arc::clone(&self.block_device)
).lock().modify(new_inode_block_offset, |new_inode: &mut DiskInode| {
new_inode.initialize(DiskInodeType::File, indirect1);
});
// append file in the dirent
let file_count =
inode.read(|inode| inode.size as usize) / DIRENT_SZ;
let new_size = (file_count + 1) * DIRENT_SZ;
// increase size
self.increase_size(new_size as u32, &mut inode, &mut fs);
// write dirent
let dirent = DirEntry::new(name, new_inode_id);
inode.modify(|inode| {
inode.write_at(
//println!("new inode has been initialized.");
self.modify_disk_inode(|root_inode| {
// append file in the dirent
let file_count = (root_inode.size as usize) / DIRENT_SZ;
let new_size = (file_count + 1) * DIRENT_SZ;
// increase size
self.increase_size(new_size as u32, root_inode, &mut fs);
// write dirent
let dirent = DirEntry::new(name, new_inode_id);
root_inode.write_at(
file_count * DIRENT_SZ,
dirent.into_bytes(),
&self.block_device,
);
});
//println!("new file has been inserted into root inode.");
// release efs lock manually because we will acquire it again in Inode::new
drop(fs);
// return inode
Some(Arc::new(Self::new(
new_inode_id,
@ -148,53 +164,48 @@ impl Inode {
}
pub fn ls(&self) -> Vec<String> {
let mut fs = self.fs.lock();
let inode = self.get_disk_inode(&mut fs);
let file_count = inode.read(|inode| {
(inode.size as usize) / DIRENT_SZ
});
let mut v: Vec<String> = Vec::new();
for i in 0..file_count {
let mut dirent_bytes: DirentBytes = Default::default();
assert_eq!(
inode.read(|inode| {
inode.read_at(
let _ = self.fs.lock();
self.read_disk_inode(|disk_inode| {
let file_count = (disk_inode.size as usize) / DIRENT_SZ;
let mut v: Vec<String> = Vec::new();
for i in 0..file_count {
let mut dirent_bytes: DirentBytes = Default::default();
assert_eq!(
disk_inode.read_at(
i * DIRENT_SZ,
&mut dirent_bytes,
&self.block_device,
)
}),
DIRENT_SZ,
);
v.push(String::from(DirEntry::from_bytes(&dirent_bytes).name()));
}
v
),
DIRENT_SZ,
);
v.push(String::from(DirEntry::from_bytes(&dirent_bytes).name()));
}
v
})
}
pub fn read_at(&self, offset: usize, buf: &mut [u8]) -> usize {
let mut fs = self.fs.lock();
self.get_disk_inode(&mut fs).modify(|disk_inode| {
let _ = self.fs.lock();
self.read_disk_inode(|disk_inode| {
disk_inode.read_at(offset, buf, &self.block_device)
})
}
pub fn write_at(&self, offset: usize, buf: &[u8]) -> usize {
let mut fs = self.fs.lock();
let mut inode = self.get_disk_inode(&mut fs);
self.increase_size((offset + buf.len()) as u32, &mut inode, &mut fs);
inode.modify(|disk_inode| {
self.modify_disk_inode(|disk_inode| {
self.increase_size((offset + buf.len()) as u32, disk_inode, &mut fs);
disk_inode.write_at(offset, buf, &self.block_device)
})
}
pub fn clear(&self) {
let mut fs = self.fs.lock();
let mut inode = self.get_disk_inode(&mut fs);
let data_blocks_dealloc = inode.modify(|disk_inode| {
disk_inode.clear_size(&self.block_device)
self.modify_disk_inode(|disk_inode| {
let data_blocks_dealloc = disk_inode.clear_size(&self.block_device);
for data_block in data_blocks_dealloc.into_iter() {
fs.dealloc_data(data_block);
}
});
for data_block in data_blocks_dealloc.into_iter() {
fs.dealloc_data(data_block);
}
}
}