diff --git a/easy-fs-fuse/src/main.rs b/easy-fs-fuse/src/main.rs index 04f74f00..498b61ec 100644 --- a/easy-fs-fuse/src/main.rs +++ b/easy-fs-fuse/src/main.rs @@ -118,7 +118,8 @@ fn efs_test() -> std::io::Result<()> { let filea = root_inode.find("filea").unwrap(); let greet_str = "Hello, world!"; 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); assert_eq!( greet_str, @@ -159,6 +160,9 @@ fn efs_test() -> std::io::Result<()> { random_str_test(100 * BLOCK_SZ); random_str_test(70 * BLOCK_SZ + BLOCK_SZ / 7); 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(()) } \ No newline at end of file diff --git a/easy-fs/src/efs.rs b/easy-fs/src/efs.rs index caf4d8cb..9e4445df 100644 --- a/easy-fs/src/efs.rs +++ b/easy-fs/src/efs.rs @@ -80,9 +80,7 @@ impl EasyFileSystem { ) .lock() .modify(root_inode_offset, |disk_inode: &mut DiskInode| { - disk_inode.initialize( - DiskInodeType::Directory,efs.alloc_data() - ); + disk_inode.initialize(DiskInodeType::Directory); }); Arc::new(Mutex::new(efs)) } @@ -158,6 +156,14 @@ impl EasyFileSystem { } 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.block_device, (block_id - self.data_area_start_block) as usize diff --git a/easy-fs/src/layout.rs b/easy-fs/src/layout.rs index ace1ced8..83da4cbb 100644 --- a/easy-fs/src/layout.rs +++ b/easy-fs/src/layout.rs @@ -10,6 +10,12 @@ use alloc::vec::Vec; const EFS_MAGIC: u32 = 0x3b800001; const INODE_DIRECT_COUNT: usize = 60; 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)] pub struct SuperBlock { @@ -76,11 +82,11 @@ pub struct DiskInode { } impl DiskInode { - /// indirect1 block is allocated when the file is created. - pub fn initialize(&mut self, type_: DiskInodeType, indirect1: u32) { + /// indirect1 and indirect2 block are allocated only when they are needed. + pub fn initialize(&mut self, type_: DiskInodeType) { self.size = 0; self.direct.iter_mut().for_each(|v| *v = 0); - self.indirect1 = indirect1; + self.indirect1 = 0; self.indirect2 = 0; self.type_ = type_; } @@ -91,57 +97,146 @@ impl DiskInode { pub fn is_file(&self) -> bool { self.type_ == DiskInodeType::File } - pub fn blocks(&self) -> u32 { - Self::_blocks(self.size) + /// Return block number correspond to 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 } + /// 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) -> u32 { let inner_id = inner_id as usize; if inner_id < INODE_DIRECT_COUNT { self.direct[inner_id] - } else { - // only support indirect1 now + } else if inner_id < INDIRECT1_BOUND { get_block_cache(self.indirect1 as usize, Arc::clone(block_device)) .lock() .read(0, |indirect_block: &IndirectBlock| { 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( &mut self, new_size: u32, new_blocks: Vec, block_device: &Arc, ) { - assert_eq!(new_blocks.len() as u32, self.blocks_num_needed(new_size)); - let last_blocks = self.blocks(); + let mut current_blocks = self.data_blocks(); 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( self.indirect1 as usize, Arc::clone(block_device) ) .lock() - .modify(0, |indirect_block: &mut IndirectBlock| { - for i in 0..current_blocks - last_blocks { - let inner_id = (last_blocks + i) as usize; - let new_block = new_blocks[i as usize]; - if inner_id < INODE_DIRECT_COUNT { - self.direct[inner_id] = new_block; - } else { - indirect_block[inner_id - INODE_DIRECT_COUNT] = new_block; - } + .modify(0, |indirect1: &mut IndirectBlock| { + while current_blocks < total_blocks.min(INODE_INDIRECT1_COUNT as u32) { + indirect1[current_blocks as usize] = new_blocks.next().unwrap(); + current_blocks += 1; } }); + // 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) -> Vec { let mut v: Vec = Vec::new(); let blocks = self.blocks() as usize; @@ -165,6 +260,97 @@ impl DiskInode { } 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) -> Vec { + let mut v: Vec = 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( &self, offset: usize, diff --git a/easy-fs/src/vfs.rs b/easy-fs/src/vfs.rs index a98fd607..f10a8c8a 100644 --- a/easy-fs/src/vfs.rs +++ b/easy-fs/src/vfs.rs @@ -122,22 +122,18 @@ impl 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 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); + new_inode.initialize(DiskInodeType::File); }); - //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; @@ -152,7 +148,6 @@ impl Inode { &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 @@ -202,7 +197,9 @@ impl Inode { pub fn clear(&self) { let mut fs = self.fs.lock(); self.modify_disk_inode(|disk_inode| { + let size = disk_inode.size; 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() { fs.dealloc_data(data_block); }