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:
@@ -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
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user