Implement double indirect blocks

master
Jiajie Chen 6 years ago
parent ff3dd7d157
commit 807a5d3dac

@ -80,8 +80,8 @@ impl INodeImpl {
let disk_inode = self.disk_inode.read();
match file_block_id {
id if id >= disk_inode.blocks as BlockId => Err(FsError::InvalidParam),
id if id < NDIRECT => Ok(disk_inode.direct[id] as BlockId),
id if id < NDIRECT + BLK_NENTRY => {
id if id < MAX_NBLOCK_DIRECT => Ok(disk_inode.direct[id] as BlockId),
id if id < MAX_NBLOCK_INDIRECT => {
let mut disk_block_id: u32 = 0;
self.fs.device.read_block(
disk_inode.indirect as usize,
@ -90,17 +90,36 @@ impl INodeImpl {
)?;
Ok(disk_block_id as BlockId)
}
_ => unimplemented!("double indirect blocks is not supported"),
id if id < MAX_NBLOCK_DOUBLE_INDIRECT => {
// double indirect
let indirect_id = id - MAX_NBLOCK_INDIRECT;
let mut indirect_block_id: u32 = 0;
self.fs.device.read_block(
disk_inode.db_indirect as usize,
ENTRY_SIZE * (indirect_id / BLK_NENTRY),
indirect_block_id.as_buf_mut(),
)?;
assert!(indirect_block_id > 0);
let mut disk_block_id: u32 = 0;
self.fs.device.read_block(
indirect_block_id as usize,
ENTRY_SIZE * (indirect_id as usize % BLK_NENTRY),
disk_block_id.as_buf_mut(),
)?;
assert!(disk_block_id > 0);
Ok(disk_block_id as BlockId)
}
_ => unimplemented!("triple indirect blocks is not supported"),
}
}
fn set_disk_block_id(&self, file_block_id: BlockId, disk_block_id: BlockId) -> vfs::Result<()> {
match file_block_id {
id if id >= self.disk_inode.read().blocks as BlockId => Err(FsError::InvalidParam),
id if id < NDIRECT => {
id if id < MAX_NBLOCK_DIRECT => {
self.disk_inode.write().direct[id] = disk_block_id as u32;
Ok(())
}
id if id < NDIRECT + BLK_NENTRY => {
id if id < MAX_NBLOCK_INDIRECT => {
let disk_block_id = disk_block_id as u32;
self.fs.device.write_block(
self.disk_inode.read().indirect as usize,
@ -109,7 +128,25 @@ impl INodeImpl {
)?;
Ok(())
}
_ => unimplemented!("double indirect blocks is not supported"),
id if id < MAX_NBLOCK_DOUBLE_INDIRECT => {
// double indirect
let indirect_id = id - MAX_NBLOCK_INDIRECT;
let mut indirect_block_id: u32 = 0;
self.fs.device.read_block(
self.disk_inode.read().db_indirect as usize,
ENTRY_SIZE * (indirect_id / BLK_NENTRY),
indirect_block_id.as_buf_mut(),
)?;
assert!(indirect_block_id > 0);
let disk_block_id = disk_block_id as u32;
self.fs.device.write_block(
indirect_block_id as usize,
ENTRY_SIZE * (indirect_id as usize % BLK_NENTRY),
disk_block_id.as_buf(),
)?;
Ok(())
}
_ => unimplemented!("triple indirect blocks is not supported"),
}
}
/// Only for Dir
@ -172,6 +209,9 @@ impl INodeImpl {
return Err(FsError::InvalidParam);
}
let blocks = ((len + BLKSIZE - 1) / BLKSIZE) as u32;
if blocks > MAX_NBLOCK_DOUBLE_INDIRECT as u32 {
return Err(FsError::InvalidParam);
}
use core::cmp::{Ord, Ordering};
let old_blocks = self.disk_inode.read().blocks;
match blocks.cmp(&old_blocks) {
@ -180,10 +220,32 @@ impl INodeImpl {
{
let mut disk_inode = self.disk_inode.write();
disk_inode.blocks = blocks;
// allocate indirect block if need
if old_blocks < NDIRECT as u32 && blocks >= NDIRECT as u32 {
// allocate indirect block if needed
if old_blocks < MAX_NBLOCK_DIRECT as u32 && blocks >= MAX_NBLOCK_DIRECT as u32 {
disk_inode.indirect = self.fs.alloc_block().expect("no space") as u32;
}
// allocate double indirect block if needed
if blocks >= MAX_NBLOCK_INDIRECT as u32 {
if disk_inode.db_indirect == 0 {
disk_inode.db_indirect = self.fs.alloc_block().expect("no space") as u32;
}
let indirect_begin = {
if (old_blocks as usize) < MAX_NBLOCK_INDIRECT {
0
} else {
(old_blocks as usize - MAX_NBLOCK_INDIRECT) / BLK_NENTRY + 1
}
};
let indirect_end = (blocks as usize - MAX_NBLOCK_INDIRECT) / BLK_NENTRY + 1;
for i in indirect_begin..indirect_end {
let indirect = self.fs.alloc_block().expect("no space") as u32;
self.fs.device.write_block(
disk_inode.db_indirect as usize,
ENTRY_SIZE * i,
indirect.as_buf(),
)?;
}
}
}
// allocate extra blocks
for i in old_blocks..blocks {
@ -202,11 +264,37 @@ impl INodeImpl {
self.fs.free_block(disk_block_id);
}
let mut disk_inode = self.disk_inode.write();
// free indirect block if need
if blocks < NDIRECT as u32 && disk_inode.blocks >= NDIRECT as u32 {
// free indirect block if needed
if blocks < MAX_NBLOCK_DIRECT as u32 && disk_inode.blocks >= MAX_NBLOCK_DIRECT as u32 {
self.fs.free_block(disk_inode.indirect as usize);
disk_inode.indirect = 0;
}
// free double indirect block if needed
if disk_inode.blocks >= MAX_NBLOCK_INDIRECT as u32 {
let indirect_begin = {
if (blocks as usize) < MAX_NBLOCK_INDIRECT {
0
} else {
(blocks as usize - MAX_NBLOCK_INDIRECT) / BLK_NENTRY + 1
}
};
let indirect_end = (disk_inode.blocks as usize - MAX_NBLOCK_INDIRECT) / BLK_NENTRY + 1;
for i in indirect_begin..indirect_end {
let mut indirect: u32 = 0;
self.fs.device.read_block(
disk_inode.db_indirect as usize,
ENTRY_SIZE * i,
indirect.as_buf_mut(),
)?;
assert!(indirect > 0);
self.fs.free_block(indirect as usize);
}
if blocks < MAX_NBLOCK_INDIRECT as u32 {
assert!(disk_inode.db_indirect > 0);
self.fs.free_block(disk_inode.db_indirect as usize);
disk_inode.db_indirect = 0;
}
}
disk_inode.blocks = blocks;
}
}

@ -186,7 +186,8 @@ pub const DEFAULT_INFO: &str = "simple file system";
pub const MAX_INFO_LEN: usize = 31;
/// max length of filename
pub const MAX_FNAME_LEN: usize = 255;
/// max file size (128M)
/// max file size in theory (48KB + 4MB + 4GB), but freemap is not large enough
/// max file size (128M), 128M = 8 * 4096 * 4096
pub const MAX_FILE_SIZE: usize = 1024 * 1024 * 128;
/// block the superblock lives in
pub const BLKN_SUPER: BlockId = 0;
@ -202,6 +203,12 @@ pub const ENTRY_SIZE: usize = 4;
pub const BLK_NENTRY: usize = BLKSIZE / ENTRY_SIZE;
/// size of a dirent used in the size field
pub const DIRENT_SIZE: usize = MAX_FNAME_LEN + 1;
/// max number of blocks with direct blocks
pub const MAX_NBLOCK_DIRECT: usize = NDIRECT;
/// max number of blocks with indirect blocks
pub const MAX_NBLOCK_INDIRECT: usize = NDIRECT + BLK_NENTRY;
/// max number of blocks with double indirect blocks
pub const MAX_NBLOCK_DOUBLE_INDIRECT: usize = NDIRECT + BLK_NENTRY + BLK_NENTRY * BLK_NENTRY;
/// file types
#[repr(u16)]

@ -19,7 +19,7 @@ fn _open_sample_file() -> Arc<SimpleFileSystem> {
fn _create_new_sfs() -> Arc<SimpleFileSystem> {
let file = tempfile::tempfile().expect("failed to create file");
SimpleFileSystem::create(Arc::new(Mutex::new(file)), 32 * 4096)
SimpleFileSystem::create(Arc::new(Mutex::new(file)), 32 * 4096 * 4096)
}
#[test]
@ -241,6 +241,43 @@ fn test_symlinks() -> Result<()> {
Ok(())
}
#[test]
fn test_double_indirect_blocks() -> Result<()> {
let sfs = _create_new_sfs();
let root = sfs.root_inode();
let file1 = root
.create("file1", FileType::File, 0o777)
.expect("failed to create file1");
assert!(
Arc::ptr_eq(&root.lookup("file1")?, &file1),
"failed to find file1"
);
// resize to direct maximum size
file1.resize(MAX_NBLOCK_DIRECT * BLKSIZE).unwrap();
// force usage of indirect block
file1.resize((MAX_NBLOCK_DIRECT + 1) * BLKSIZE).unwrap();
file1.resize(MAX_NBLOCK_INDIRECT * BLKSIZE).unwrap();
// force usage of double indirect block
file1.resize((MAX_NBLOCK_INDIRECT + 1) * BLKSIZE).unwrap();
file1.resize(MAX_FILE_SIZE / 8).unwrap();
// resize up and down
file1.resize(0).unwrap();
file1.resize(MAX_NBLOCK_DIRECT * BLKSIZE).unwrap();
file1.resize((MAX_NBLOCK_DIRECT + 1) * BLKSIZE).unwrap();
file1.resize(MAX_NBLOCK_DIRECT * BLKSIZE).unwrap();
file1.resize(0).unwrap();
file1.resize((MAX_NBLOCK_INDIRECT + 1) * BLKSIZE).unwrap();
file1.resize(MAX_NBLOCK_DIRECT * BLKSIZE).unwrap();
file1.resize((MAX_NBLOCK_INDIRECT + 1) * BLKSIZE).unwrap();
file1.resize(0).unwrap();
sfs.sync()?;
Ok(())
}
#[test]
fn arc_layout() {
// [usize, usize, T]

Loading…
Cancel
Save