Support indirect2 in easy-fs::layout::DiskInode
This commit is contained in:
parent
c8d851fc2b
commit
28ef057fe3
4 changed files with 228 additions and 35 deletions
|
@ -118,7 +118,8 @@ fn efs_test() -> std::io::Result<()> {
|
||||||
let filea = root_inode.find("filea").unwrap();
|
let filea = root_inode.find("filea").unwrap();
|
||||||
let greet_str = "Hello, world!";
|
let greet_str = "Hello, world!";
|
||||||
filea.write_at(0, greet_str.as_bytes());
|
filea.write_at(0, greet_str.as_bytes());
|
||||||
let mut buffer = [0u8; 512];
|
//let mut buffer = [0u8; 512];
|
||||||
|
let mut buffer = [0u8; 233];
|
||||||
let len = filea.read_at(0, &mut buffer);
|
let len = filea.read_at(0, &mut buffer);
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
greet_str,
|
greet_str,
|
||||||
|
@ -159,6 +160,9 @@ fn efs_test() -> std::io::Result<()> {
|
||||||
random_str_test(100 * BLOCK_SZ);
|
random_str_test(100 * BLOCK_SZ);
|
||||||
random_str_test(70 * BLOCK_SZ + BLOCK_SZ / 7);
|
random_str_test(70 * BLOCK_SZ + BLOCK_SZ / 7);
|
||||||
random_str_test((12 + 128) * BLOCK_SZ);
|
random_str_test((12 + 128) * BLOCK_SZ);
|
||||||
|
random_str_test(400 * BLOCK_SZ);
|
||||||
|
random_str_test(1000 * BLOCK_SZ);
|
||||||
|
random_str_test(2000 * BLOCK_SZ);
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
|
@ -80,9 +80,7 @@ impl EasyFileSystem {
|
||||||
)
|
)
|
||||||
.lock()
|
.lock()
|
||||||
.modify(root_inode_offset, |disk_inode: &mut DiskInode| {
|
.modify(root_inode_offset, |disk_inode: &mut DiskInode| {
|
||||||
disk_inode.initialize(
|
disk_inode.initialize(DiskInodeType::Directory);
|
||||||
DiskInodeType::Directory,efs.alloc_data()
|
|
||||||
);
|
|
||||||
});
|
});
|
||||||
Arc::new(Mutex::new(efs))
|
Arc::new(Mutex::new(efs))
|
||||||
}
|
}
|
||||||
|
@ -158,6 +156,14 @@ impl EasyFileSystem {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn dealloc_data(&mut self, block_id: u32) {
|
pub fn dealloc_data(&mut self, block_id: u32) {
|
||||||
|
get_block_cache(
|
||||||
|
block_id as usize,
|
||||||
|
Arc::clone(&self.block_device)
|
||||||
|
)
|
||||||
|
.lock()
|
||||||
|
.modify(0, |data_block: &mut DataBlock| {
|
||||||
|
data_block.iter_mut().for_each(|p| { *p = 0; })
|
||||||
|
});
|
||||||
self.data_bitmap.dealloc(
|
self.data_bitmap.dealloc(
|
||||||
&self.block_device,
|
&self.block_device,
|
||||||
(block_id - self.data_area_start_block) as usize
|
(block_id - self.data_area_start_block) as usize
|
||||||
|
|
|
@ -10,6 +10,12 @@ use alloc::vec::Vec;
|
||||||
const EFS_MAGIC: u32 = 0x3b800001;
|
const EFS_MAGIC: u32 = 0x3b800001;
|
||||||
const INODE_DIRECT_COUNT: usize = 60;
|
const INODE_DIRECT_COUNT: usize = 60;
|
||||||
const NAME_LENGTH_LIMIT: usize = 27;
|
const NAME_LENGTH_LIMIT: usize = 27;
|
||||||
|
const INODE_INDIRECT1_COUNT: usize = BLOCK_SZ / 4;
|
||||||
|
const INODE_INDIRECT2_COUNT: usize = INODE_INDIRECT1_COUNT * INODE_INDIRECT1_COUNT;
|
||||||
|
const DIRECT_BOUND: usize = INODE_DIRECT_COUNT;
|
||||||
|
const INDIRECT1_BOUND: usize = DIRECT_BOUND + INODE_INDIRECT1_COUNT;
|
||||||
|
#[allow(unused)]
|
||||||
|
const INDIRECT2_BOUND: usize = INDIRECT1_BOUND + INODE_INDIRECT2_COUNT;
|
||||||
|
|
||||||
#[repr(C)]
|
#[repr(C)]
|
||||||
pub struct SuperBlock {
|
pub struct SuperBlock {
|
||||||
|
@ -76,11 +82,11 @@ pub struct DiskInode {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl DiskInode {
|
impl DiskInode {
|
||||||
/// indirect1 block is allocated when the file is created.
|
/// indirect1 and indirect2 block are allocated only when they are needed.
|
||||||
pub fn initialize(&mut self, type_: DiskInodeType, indirect1: u32) {
|
pub fn initialize(&mut self, type_: DiskInodeType) {
|
||||||
self.size = 0;
|
self.size = 0;
|
||||||
self.direct.iter_mut().for_each(|v| *v = 0);
|
self.direct.iter_mut().for_each(|v| *v = 0);
|
||||||
self.indirect1 = indirect1;
|
self.indirect1 = 0;
|
||||||
self.indirect2 = 0;
|
self.indirect2 = 0;
|
||||||
self.type_ = type_;
|
self.type_ = type_;
|
||||||
}
|
}
|
||||||
|
@ -91,57 +97,146 @@ impl DiskInode {
|
||||||
pub fn is_file(&self) -> bool {
|
pub fn is_file(&self) -> bool {
|
||||||
self.type_ == DiskInodeType::File
|
self.type_ == DiskInodeType::File
|
||||||
}
|
}
|
||||||
pub fn blocks(&self) -> u32 {
|
/// Return block number correspond to size.
|
||||||
Self::_blocks(self.size)
|
pub fn data_blocks(&self) -> u32 {
|
||||||
|
Self::_data_blocks(self.size)
|
||||||
}
|
}
|
||||||
fn _blocks(size: u32) -> u32 {
|
fn _data_blocks(size: u32) -> u32 {
|
||||||
(size + BLOCK_SZ as u32 - 1) / BLOCK_SZ as u32
|
(size + BLOCK_SZ as u32 - 1) / BLOCK_SZ as u32
|
||||||
}
|
}
|
||||||
|
/// Return number of blocks needed include indirect1/2.
|
||||||
|
pub fn total_blocks(size: u32) -> u32 {
|
||||||
|
let data_blocks = Self::_data_blocks(size) as usize;
|
||||||
|
let mut total = data_blocks as usize;
|
||||||
|
// indirect1
|
||||||
|
if data_blocks > INODE_DIRECT_COUNT {
|
||||||
|
total += 1;
|
||||||
|
}
|
||||||
|
// indirect2
|
||||||
|
if data_blocks > INDIRECT1_BOUND {
|
||||||
|
total += 1;
|
||||||
|
// sub indirect1
|
||||||
|
total += (data_blocks - INDIRECT1_BOUND + INODE_INDIRECT1_COUNT - 1) / INODE_INDIRECT1_COUNT;
|
||||||
|
}
|
||||||
|
total as u32
|
||||||
|
}
|
||||||
|
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)
|
||||||
|
}
|
||||||
pub fn get_block_id(&self, inner_id: u32, block_device: &Arc<dyn BlockDevice>) -> u32 {
|
pub fn get_block_id(&self, inner_id: u32, block_device: &Arc<dyn BlockDevice>) -> u32 {
|
||||||
let inner_id = inner_id as usize;
|
let inner_id = inner_id as usize;
|
||||||
if inner_id < INODE_DIRECT_COUNT {
|
if inner_id < INODE_DIRECT_COUNT {
|
||||||
self.direct[inner_id]
|
self.direct[inner_id]
|
||||||
} else {
|
} else if inner_id < INDIRECT1_BOUND {
|
||||||
// only support indirect1 now
|
|
||||||
get_block_cache(self.indirect1 as usize, Arc::clone(block_device))
|
get_block_cache(self.indirect1 as usize, Arc::clone(block_device))
|
||||||
.lock()
|
.lock()
|
||||||
.read(0, |indirect_block: &IndirectBlock| {
|
.read(0, |indirect_block: &IndirectBlock| {
|
||||||
indirect_block[inner_id - INODE_DIRECT_COUNT]
|
indirect_block[inner_id - INODE_DIRECT_COUNT]
|
||||||
})
|
})
|
||||||
|
} else {
|
||||||
|
let last = inner_id - INDIRECT1_BOUND;
|
||||||
|
let indirect1 = get_block_cache(
|
||||||
|
self.indirect2 as usize,
|
||||||
|
Arc::clone(block_device)
|
||||||
|
)
|
||||||
|
.lock()
|
||||||
|
.read(0, |indirect2: &IndirectBlock| {
|
||||||
|
indirect2[last / INODE_INDIRECT1_COUNT]
|
||||||
|
});
|
||||||
|
get_block_cache(
|
||||||
|
indirect1 as usize,
|
||||||
|
Arc::clone(block_device)
|
||||||
|
)
|
||||||
|
.lock()
|
||||||
|
.read(0, |indirect1: &IndirectBlock| {
|
||||||
|
indirect1[last % INODE_INDIRECT1_COUNT]
|
||||||
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
pub fn blocks_num_needed(&self, new_size: u32) -> u32 {
|
|
||||||
assert!(new_size >= self.size);
|
|
||||||
Self::_blocks(new_size) - self.blocks()
|
|
||||||
}
|
|
||||||
pub fn increase_size(
|
pub fn increase_size(
|
||||||
&mut self,
|
&mut self,
|
||||||
new_size: u32,
|
new_size: u32,
|
||||||
new_blocks: Vec<u32>,
|
new_blocks: Vec<u32>,
|
||||||
block_device: &Arc<dyn BlockDevice>,
|
block_device: &Arc<dyn BlockDevice>,
|
||||||
) {
|
) {
|
||||||
assert_eq!(new_blocks.len() as u32, self.blocks_num_needed(new_size));
|
let mut current_blocks = self.data_blocks();
|
||||||
let last_blocks = self.blocks();
|
|
||||||
self.size = new_size;
|
self.size = new_size;
|
||||||
let current_blocks = self.blocks();
|
let mut total_blocks = self.data_blocks();
|
||||||
|
let mut new_blocks = new_blocks.into_iter();
|
||||||
|
// fill direct
|
||||||
|
while current_blocks < total_blocks.min(INODE_DIRECT_COUNT as u32) {
|
||||||
|
self.direct[current_blocks as usize] = new_blocks.next().unwrap();
|
||||||
|
current_blocks += 1;
|
||||||
|
}
|
||||||
|
// alloc indirect1
|
||||||
|
if total_blocks > INODE_DIRECT_COUNT as u32{
|
||||||
|
if current_blocks == INODE_DIRECT_COUNT as u32 {
|
||||||
|
self.indirect1 = new_blocks.next().unwrap();
|
||||||
|
}
|
||||||
|
current_blocks -= INODE_DIRECT_COUNT as u32;
|
||||||
|
total_blocks -= INODE_DIRECT_COUNT as u32;
|
||||||
|
} else {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
// fill indirect1
|
||||||
get_block_cache(
|
get_block_cache(
|
||||||
self.indirect1 as usize,
|
self.indirect1 as usize,
|
||||||
Arc::clone(block_device)
|
Arc::clone(block_device)
|
||||||
)
|
)
|
||||||
.lock()
|
.lock()
|
||||||
.modify(0, |indirect_block: &mut IndirectBlock| {
|
.modify(0, |indirect1: &mut IndirectBlock| {
|
||||||
for i in 0..current_blocks - last_blocks {
|
while current_blocks < total_blocks.min(INODE_INDIRECT1_COUNT as u32) {
|
||||||
let inner_id = (last_blocks + i) as usize;
|
indirect1[current_blocks as usize] = new_blocks.next().unwrap();
|
||||||
let new_block = new_blocks[i as usize];
|
current_blocks += 1;
|
||||||
if inner_id < INODE_DIRECT_COUNT {
|
|
||||||
self.direct[inner_id] = new_block;
|
|
||||||
} else {
|
|
||||||
indirect_block[inner_id - INODE_DIRECT_COUNT] = new_block;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
// alloc indirect2
|
||||||
|
if total_blocks > INODE_INDIRECT1_COUNT as u32 {
|
||||||
|
if current_blocks == INODE_INDIRECT1_COUNT as u32 {
|
||||||
|
self.indirect2 = new_blocks.next().unwrap();
|
||||||
|
}
|
||||||
|
current_blocks -= INODE_INDIRECT1_COUNT as u32;
|
||||||
|
total_blocks -= INODE_INDIRECT1_COUNT as u32;
|
||||||
|
} else {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
// fill indirect2 from (a0, b0) -> (a1, b1)
|
||||||
|
let mut a0 = current_blocks as usize / INODE_INDIRECT1_COUNT;
|
||||||
|
let mut b0 = current_blocks as usize % INODE_INDIRECT1_COUNT;
|
||||||
|
let a1 = total_blocks as usize / INODE_INDIRECT1_COUNT;
|
||||||
|
let b1 = total_blocks as usize % INODE_INDIRECT1_COUNT;
|
||||||
|
// alloc low-level indirect1
|
||||||
|
get_block_cache(
|
||||||
|
self.indirect2 as usize,
|
||||||
|
Arc::clone(block_device)
|
||||||
|
)
|
||||||
|
.lock()
|
||||||
|
.modify(0, |indirect2: &mut IndirectBlock| {
|
||||||
|
while (a0 < a1) || (a0 == a1 && b0 < b1) {
|
||||||
|
if b0 == 0 {
|
||||||
|
indirect2[a0] = new_blocks.next().unwrap();
|
||||||
|
}
|
||||||
|
// fill current
|
||||||
|
get_block_cache(
|
||||||
|
indirect2[a0] as usize,
|
||||||
|
Arc::clone(block_device)
|
||||||
|
)
|
||||||
|
.lock()
|
||||||
|
.modify(0, |indirect1: &mut IndirectBlock| {
|
||||||
|
indirect1[b0] = new_blocks.next().unwrap();
|
||||||
|
});
|
||||||
|
// move to next
|
||||||
|
b0 += 1;
|
||||||
|
if b0 == INODE_INDIRECT1_COUNT {
|
||||||
|
b0 = 0;
|
||||||
|
a0 += 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
}
|
}
|
||||||
/// Clear size to zero and return blocks that should be deallocated.
|
|
||||||
|
/*
|
||||||
pub fn clear_size(&mut self, block_device: &Arc<dyn BlockDevice>) -> Vec<u32> {
|
pub fn clear_size(&mut self, block_device: &Arc<dyn BlockDevice>) -> Vec<u32> {
|
||||||
let mut v: Vec<u32> = Vec::new();
|
let mut v: Vec<u32> = Vec::new();
|
||||||
let blocks = self.blocks() as usize;
|
let blocks = self.blocks() as usize;
|
||||||
|
@ -165,6 +260,97 @@ impl DiskInode {
|
||||||
}
|
}
|
||||||
v
|
v
|
||||||
}
|
}
|
||||||
|
*/
|
||||||
|
|
||||||
|
/// 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();
|
||||||
|
let mut data_blocks = self.data_blocks() as usize;
|
||||||
|
self.size = 0;
|
||||||
|
let mut current_blocks = 0usize;
|
||||||
|
// direct
|
||||||
|
while current_blocks < data_blocks.min(INODE_DIRECT_COUNT) {
|
||||||
|
v.push(self.direct[current_blocks]);
|
||||||
|
self.direct[current_blocks] = 0;
|
||||||
|
current_blocks += 1;
|
||||||
|
}
|
||||||
|
// indirect1 block
|
||||||
|
if data_blocks > INODE_DIRECT_COUNT {
|
||||||
|
v.push(self.indirect1);
|
||||||
|
data_blocks -= INODE_DIRECT_COUNT;
|
||||||
|
current_blocks = 0;
|
||||||
|
} else {
|
||||||
|
return v;
|
||||||
|
}
|
||||||
|
// indirect1
|
||||||
|
get_block_cache(
|
||||||
|
self.indirect1 as usize,
|
||||||
|
Arc::clone(block_device),
|
||||||
|
)
|
||||||
|
.lock()
|
||||||
|
.modify(0, |indirect1: &mut IndirectBlock| {
|
||||||
|
while current_blocks < data_blocks.min(INODE_INDIRECT1_COUNT) {
|
||||||
|
v.push(indirect1[current_blocks]);
|
||||||
|
//indirect1[current_blocks] = 0;
|
||||||
|
current_blocks += 1;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
self.indirect1 = 0;
|
||||||
|
// indirect2 block
|
||||||
|
if data_blocks > INODE_INDIRECT1_COUNT {
|
||||||
|
v.push(self.indirect2);
|
||||||
|
data_blocks -= INODE_INDIRECT1_COUNT;
|
||||||
|
} else {
|
||||||
|
return v;
|
||||||
|
}
|
||||||
|
// indirect2
|
||||||
|
assert!(data_blocks <= INODE_INDIRECT2_COUNT);
|
||||||
|
let a1 = data_blocks / INODE_INDIRECT1_COUNT;
|
||||||
|
let b1 = data_blocks % INODE_INDIRECT1_COUNT;
|
||||||
|
get_block_cache(
|
||||||
|
self.indirect2 as usize,
|
||||||
|
Arc::clone(block_device),
|
||||||
|
)
|
||||||
|
.lock()
|
||||||
|
.modify(0, |indirect2: &mut IndirectBlock| {
|
||||||
|
// full indirect1 blocks
|
||||||
|
for i in 0..a1 {
|
||||||
|
v.push(indirect2[i]);
|
||||||
|
get_block_cache(
|
||||||
|
indirect2[i] as usize,
|
||||||
|
Arc::clone(block_device),
|
||||||
|
)
|
||||||
|
.lock()
|
||||||
|
.modify(0, |indirect1: &mut IndirectBlock| {
|
||||||
|
for j in 0..INODE_INDIRECT1_COUNT {
|
||||||
|
v.push(indirect1[j]);
|
||||||
|
//indirect1[j] = 0;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
//indirect2[i] = 0;
|
||||||
|
}
|
||||||
|
// last indirect1 block
|
||||||
|
if b1 > 0 {
|
||||||
|
v.push(indirect2[a1]);
|
||||||
|
get_block_cache(
|
||||||
|
indirect2[a1] as usize,
|
||||||
|
Arc::clone(block_device),
|
||||||
|
)
|
||||||
|
.lock()
|
||||||
|
.modify(0, |indirect1: &mut IndirectBlock| {
|
||||||
|
for j in 0..b1 {
|
||||||
|
v.push(indirect1[j]);
|
||||||
|
//indirect1[j] = 0;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
//indirect2[a1] = 0;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
self.indirect2 = 0;
|
||||||
|
v
|
||||||
|
}
|
||||||
pub fn read_at(
|
pub fn read_at(
|
||||||
&self,
|
&self,
|
||||||
offset: usize,
|
offset: usize,
|
||||||
|
|
|
@ -122,22 +122,18 @@ impl Inode {
|
||||||
}).is_some() {
|
}).is_some() {
|
||||||
return None;
|
return None;
|
||||||
}
|
}
|
||||||
//println!("same file does not exist in Inode::create.");
|
|
||||||
// create a new file
|
// create a new file
|
||||||
// alloc a inode with an indirect block
|
// alloc a inode with an indirect block
|
||||||
let new_inode_id = fs.alloc_inode();
|
let new_inode_id = fs.alloc_inode();
|
||||||
let indirect1 = fs.alloc_data();
|
|
||||||
// initialize inode
|
// initialize inode
|
||||||
let (new_inode_block_id, new_inode_block_offset)
|
let (new_inode_block_id, new_inode_block_offset)
|
||||||
= fs.get_disk_inode_pos(new_inode_id);
|
= 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(
|
get_block_cache(
|
||||||
new_inode_block_id as usize,
|
new_inode_block_id as usize,
|
||||||
Arc::clone(&self.block_device)
|
Arc::clone(&self.block_device)
|
||||||
).lock().modify(new_inode_block_offset, |new_inode: &mut DiskInode| {
|
).lock().modify(new_inode_block_offset, |new_inode: &mut DiskInode| {
|
||||||
new_inode.initialize(DiskInodeType::File, indirect1);
|
new_inode.initialize(DiskInodeType::File);
|
||||||
});
|
});
|
||||||
//println!("new inode has been initialized.");
|
|
||||||
self.modify_disk_inode(|root_inode| {
|
self.modify_disk_inode(|root_inode| {
|
||||||
// append file in the dirent
|
// append file in the dirent
|
||||||
let file_count = (root_inode.size as usize) / DIRENT_SZ;
|
let file_count = (root_inode.size as usize) / DIRENT_SZ;
|
||||||
|
@ -152,7 +148,6 @@ impl Inode {
|
||||||
&self.block_device,
|
&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
|
// release efs lock manually because we will acquire it again in Inode::new
|
||||||
drop(fs);
|
drop(fs);
|
||||||
// return inode
|
// return inode
|
||||||
|
@ -202,7 +197,9 @@ impl Inode {
|
||||||
pub fn clear(&self) {
|
pub fn clear(&self) {
|
||||||
let mut fs = self.fs.lock();
|
let mut fs = self.fs.lock();
|
||||||
self.modify_disk_inode(|disk_inode| {
|
self.modify_disk_inode(|disk_inode| {
|
||||||
|
let size = disk_inode.size;
|
||||||
let data_blocks_dealloc = disk_inode.clear_size(&self.block_device);
|
let data_blocks_dealloc = disk_inode.clear_size(&self.block_device);
|
||||||
|
assert!(data_blocks_dealloc.len() == DiskInode::total_blocks(size) as usize);
|
||||||
for data_block in data_blocks_dealloc.into_iter() {
|
for data_block in data_blocks_dealloc.into_iter() {
|
||||||
fs.dealloc_data(data_block);
|
fs.dealloc_data(data_block);
|
||||||
}
|
}
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue