feat(storage): ext4-only disk via mkfs.ext4 -d; drop FAT16; feature-gated mount (ro on unknown ro_compat); ext4 read spans blocks, delete clears inode, mkdir counts dir; virtio-blk writes; test-qemu e2fsck gate

This commit is contained in:
2026-10-27 17:09:35 +01:00
parent 4030dd4315
commit 0fd568cdad
24 changed files with 390 additions and 809 deletions

View File

@@ -50,9 +50,27 @@ impl<B: BlockDevice> Ext4<B> {
open_files: [const { None }; MAX_OPEN_FILES],
})
}
/// One more directory in `inode`'s block group (e2fsck checks the count).
fn count_dir(&mut self, inode: u32) {
let (bg, spb) = (self.sb.inode_block_group(inode), self.sb.sectors_per_block());
if let Some(mut d) = bgd::BlockGroupDescriptor::read(&mut self.device, self.gdt_block, bg, spb) {
d.used_dirs_count += 1;
d.write_back(&mut self.device, self.gdt_block, bg, spb);
}
}
/// The disk, for a test to look at what was written.
pub fn into_device(self) -> B {
self.device
}
}
impl<B: BlockDevice> FileSystem for Ext4<B> {
fn writable(&self) -> bool {
self.sb.writable && self.device.writable()
}
fn open(&mut self, path: &[u8]) -> Option<FileHandle> {
let inode_num = self.resolve_path(path)?;
let inode = self.read_inode(inode_num)?;
@@ -73,13 +91,9 @@ impl<B: BlockDevice> FileSystem for Ext4<B> {
let file = *self.open_files[handle.raw() as usize].as_ref()?;
if file.offset >= file.size { return Some(0); }
let remaining = file.size - file.offset;
let to_read = buf.len().min(remaining);
// As much as `buf` holds, across blocks: a short read means the end.
let to_read = buf.len().min(file.size - file.offset);
let bs = self.sb.block_size;
let logical_block = (file.offset / bs) as u32;
let byte_in_block = file.offset % bs;
let inode = Inode {
mode: 0,
size: file.size as u64,
@@ -88,17 +102,22 @@ impl<B: BlockDevice> FileSystem for Ext4<B> {
blocks_count: 0,
block_data: file.block_data,
};
let phys_block = self.map_logical_block(&inode, logical_block)?;
let mut done = 0;
let mut block_buf = [0u8; 4096];
read_block(&mut self.device, phys_block, self.sb.sectors_per_block(), &mut block_buf);
while done < to_read {
let offset = file.offset + done;
let phys_block = self.map_logical_block(&inode, (offset / bs) as u32)?;
if !read_block(&mut self.device, phys_block, self.sb.sectors_per_block(), &mut block_buf) {
return None;
}
let byte_in_block = offset % bs;
let chunk = (to_read - done).min(bs - byte_in_block);
buf[done..done + chunk].copy_from_slice(&block_buf[byte_in_block..byte_in_block + chunk]);
done += chunk;
}
let available = bs - byte_in_block;
let chunk = to_read.min(available);
buf[..chunk].copy_from_slice(&block_buf[byte_in_block..byte_in_block + chunk]);
self.open_files[handle.raw() as usize].as_mut().map(|f| f.offset += chunk);
Some(chunk)
self.open_files[handle.raw() as usize].as_mut().map(|f| f.offset += done);
Some(done)
}
fn write(&mut self, handle: FileHandle, buf: &[u8]) -> Option<usize> {
@@ -262,6 +281,7 @@ impl<B: BlockDevice> FileSystem for Ext4<B> {
if let Some(child_inode) = self.read_inode(child_inode_num) {
self.free_all_blocks(&child_inode);
}
self.clear_inode(child_inode_num);
self.free_inode(child_inode_num);
for slot in self.open_files.iter_mut() {
if let Some(f) = slot {
@@ -331,6 +351,7 @@ impl<B: BlockDevice> FileSystem for Ext4<B> {
pi.links_count += 1;
self.write_inode(parent_inode_num, &pi);
}
self.count_dir(new_inode_num);
true
}