|
|
|
@ -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);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|