Cache inodes/dentries/ind blocks and group file block reads

This commit is contained in:
pjht 2024-09-06 10:49:39 -05:00
parent e205e31797
commit e55ad22620
Signed by: pjht
GPG Key ID: 7B5F6AFBEC7EE78E
4 changed files with 52 additions and 34 deletions

View File

@ -24,6 +24,7 @@ pub struct Ext2 {
descriptor_table: BlockGroupDescriptorTable,
inode_cache: RwLock<HashMap<u32, Inode>>,
dentry_cache: RwLock<HashMap<PathBuf, DirEntryDisk>>,
ind_block_cache: RwLock<HashMap<u32, Vec<u32>>>,
}
impl Ext2 {
@ -35,6 +36,7 @@ impl Ext2 {
reader,
inode_cache: RwLock::new(HashMap::new()),
dentry_cache: RwLock::new(HashMap::new()),
ind_block_cache: RwLock::new(HashMap::new()),
})
}

View File

@ -36,13 +36,12 @@ impl BlockReader {
}
pub fn read_blocks(&self, block: u32, count: usize) -> io::Result<Cursor<Vec<u8>>> {
let mut vec = vec![0; self.block_size * count];
for block_no in block..(block + count as u32) {
let data = self.read_block(block)?.into_inner();
vec[((block_no - block) as usize * self.block_size)
..(((block_no - block) as usize + 1) * self.block_size)]
.copy_from_slice(&data);
}
let mut disk = &self.disk;
let start = self.block_to_byte_offset(block);
let size = self.block_size * count;
let mut vec = vec![0; size];
disk.seek(SeekFrom::Start(start))?;
disk.read_exact(&mut vec)?;
Ok(Cursor::new(vec))
}

View File

@ -47,10 +47,8 @@ impl File {
}
pub fn read_at(&self, buf: &mut [u8], pos: u64, fs: &Ext2) -> io::Result<usize> {
//println!("File::read_at(File {{pos: {}, inode: {}, ...}}, &mut [?; {}], {})", self.pos, self.inode.number, buf.len(), pos);
let bytes_to_end = u64::from(self.inode.size_lower32).saturating_sub(pos);
if bytes_to_end == 0 {
//println!("File::read_at done, reporting 0 bytes read");
return Ok(0);
}
let start_block = (pos / self.block_size as u64) as u32;
@ -60,25 +58,39 @@ impl File {
.reader
.read_block_offset(
self.inode
.log_to_phys_block(&fs.reader, start_block)
.log_to_phys_block(&fs, start_block)
.ok_or_else(|| io::Error::new(io::ErrorKind::UnexpectedEof, "EOF reached"))?,
offset as u32,
)?
.read(buf)?;
let mut remaining_bytes = length.saturating_sub((self.block_size - offset) as u64);
for block in (start_block + 1)..=u32::MAX {
if remaining_bytes == 0 {
break;
};
let _ =
fs.reader
.read_block(self.inode.log_to_phys_block(&fs.reader, block).ok_or_else(
|| io::Error::new(io::ErrorKind::UnexpectedEof, "EOF reached"),
)?)?
.read(&mut buf[((length - remaining_bytes) as usize)..])?;
remaining_bytes = remaining_bytes.saturating_sub(self.block_size as u64);
let mut block = start_block + 1;
while remaining_bytes != 0 {
let mut chunk_start_block = self
.inode
.log_to_phys_block(&fs, block)
.ok_or_else(|| io::Error::new(io::ErrorKind::UnexpectedEof, "EOF reached"))?;
let mut chunk_num_blocks = 1;
block += 1;
loop {
if (chunk_num_blocks as usize * self.block_size) as u64 >= remaining_bytes {
break;
}
let Some(phys_block) = self.inode.log_to_phys_block(&fs, block) else {
break;
};
if phys_block != chunk_start_block + chunk_num_blocks {
break;
}
chunk_num_blocks += 1;
block += 1;
}
let _ = fs
.reader
.read_blocks(chunk_start_block, chunk_num_blocks as usize)?
.read(&mut buf[((length - remaining_bytes) as usize)..])?;
remaining_bytes = remaining_bytes.saturating_sub((self.block_size * chunk_num_blocks as usize) as u64);
}
//println!("File::read_at done, reporting {} bytes read", length - remaining_bytes);
Ok((length - remaining_bytes) as usize)
}
}

View File

@ -156,19 +156,24 @@ impl Inode {
Ok(ino)
}
pub fn pointer_block_blocks(&self, block: u32, reader: &BlockReader) -> io::Result<Vec<u32>> {
Ok(reader
.read_block(block)?
pub fn pointer_block_blocks(&self, block_no: u32, fs: &Ext2) -> io::Result<Vec<u32>> {
if let Some(block) = fs.ind_block_cache.read().get(&block_no) {
return Ok(block.clone());
}
let block = fs.reader
.read_block(block_no)?
.into_inner()
.iter()
.copied()
.tuples::<(_, _, _, _)>()
.map(|raw| u32::from_le_bytes([raw.0, raw.1, raw.2, raw.3]))
.collect_vec())
.collect_vec();
fs.ind_block_cache.write().insert(block_no, block.clone());
Ok(block)
}
pub fn log_to_phys_block(&self, reader: &BlockReader, block: u32) -> Option<u32> {
let num_sing_indir = reader.block_size / 4;
pub fn log_to_phys_block(&self, fs: &Ext2, block: u32) -> Option<u32> {
let num_sing_indir = fs.reader.block_size / 4;
let num_doub_indir = num_sing_indir * num_sing_indir;
let num_trip_indir = num_sing_indir * num_doub_indir;
if block < 12 {
@ -179,7 +184,7 @@ impl Inode {
}
} else if block < (12 + num_sing_indir) as u32 {
let blocks = self
.pointer_block_blocks(self.singly_indirect_block_pointer, reader)
.pointer_block_blocks(self.singly_indirect_block_pointer, fs)
.ok()?;
let block = blocks[(block - 12) as usize];
if block == 0 {
@ -192,10 +197,10 @@ impl Inode {
let doub_indir_offset = (block as usize - base_block) / num_sing_indir;
let sing_indir_offset = (block as usize - base_block) % num_sing_indir;
let sing_indir_blocks = self
.pointer_block_blocks(self.doubly_indirect_block_pointer, reader)
.pointer_block_blocks(self.doubly_indirect_block_pointer, fs)
.ok()?;
let blocks = self
.pointer_block_blocks(sing_indir_blocks[doub_indir_offset], reader)
.pointer_block_blocks(sing_indir_blocks[doub_indir_offset], fs)
.ok()?;
let block = blocks[sing_indir_offset];
if block == 0 {
@ -211,13 +216,13 @@ impl Inode {
let sing_indir_offset =
((block as usize - base_block) % num_doub_indir) % num_sing_indir;
let doub_indir_blocks = self
.pointer_block_blocks(self.triply_indirect_block_pointer, reader)
.pointer_block_blocks(self.triply_indirect_block_pointer, fs)
.ok()?;
let sing_indir_blocks = self
.pointer_block_blocks(doub_indir_blocks[trip_indir_offset], reader)
.pointer_block_blocks(doub_indir_blocks[trip_indir_offset], fs)
.ok()?;
let blocks = self
.pointer_block_blocks(sing_indir_blocks[doub_indir_offset], reader)
.pointer_block_blocks(sing_indir_blocks[doub_indir_offset], fs)
.ok()?;
let block = blocks[sing_indir_offset];
if block == 0 {