Skip to content

Commit

Permalink
add support for growing files with writes that need to allocate new b…
Browse files Browse the repository at this point in the history
…locks
  • Loading branch information
tsatke committed Jun 22, 2024
1 parent 202d282 commit 2b8ade8
Show file tree
Hide file tree
Showing 3 changed files with 46 additions and 35 deletions.
18 changes: 18 additions & 0 deletions ext2/src/bytefield.rs
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,18 @@ macro_rules! bytefield_field_read {
t
}
};
([u32; $len:literal], $offset:literal, $source:expr) => { $crate::bytefield_field_read!(u32_array [u32; $len], $offset, $source) };
(u32_array $typ:ty, $offset:literal, $source:expr) => {
{
check_is_implemented!($typ, Default);
let mut t: $typ = Default::default();
let source_bytes = &$source[$offset..$offset + core::mem::size_of::<$typ>()];
source_bytes.chunks_exact(4).enumerate().for_each(|(i, chunk)| {
t[i] = u32::from_le_bytes(chunk.try_into().unwrap());
});
t
}
};
}

#[macro_export]
Expand All @@ -51,6 +63,12 @@ macro_rules! bytefield_field_write {
(u8_array $typ:ty, $field:expr, $offset:literal, $target:expr) => {
$target[$offset..$offset + core::mem::size_of::<$typ>()].copy_from_slice(&$field);
};
([u32; $len:literal], $field:expr, $offset:literal, $target:expr) => { $crate::bytefield_field_write!(u32_array [u32; $len], $field, $offset, $target) };
(u32_array $typ:ty, $field:expr, $offset:literal, $target:expr) => {
let field = $field;
let aligned = unsafe { field.align_to::<u8>().1 };
$target[$offset..$offset + core::mem::size_of::<$typ>()].copy_from_slice(&aligned);
};
}

#[macro_export]
Expand Down
37 changes: 10 additions & 27 deletions ext2/src/inode.rs
Original file line number Diff line number Diff line change
Expand Up @@ -115,18 +115,7 @@ bytefield! {
num_disk_sectors: u32 = 28,
flags: u32 = 32,
os_val_1: [u8; 4] = 36,
direct_block_ptr_0: u32 = 40,
direct_block_ptr_1: u32 = 44,
direct_block_ptr_2: u32 = 48,
direct_block_ptr_3: u32 = 52,
direct_block_ptr_4: u32 = 56,
direct_block_ptr_5: u32 = 60,
direct_block_ptr_6: u32 = 64,
direct_block_ptr_7: u32 = 68,
direct_block_ptr_8: u32 = 72,
direct_block_ptr_9: u32 = 76,
direct_block_ptr_10: u32 = 80,
direct_block_ptr_11: u32 = 84,
direct_block_ptr: [u32; 12] = 40,
singly_indirect_block_ptr: u32 = 88,
doubly_indirect_block_ptr: u32 = 92,
triply_indirect_block_ptr: u32 = 96,
Expand Down Expand Up @@ -160,21 +149,15 @@ impl Inode {
}

pub fn direct_ptr(&self, index: usize) -> Option<BlockAddress> {
BlockAddress::new(match index {
0 => self.direct_block_ptr_0,
1 => self.direct_block_ptr_1,
2 => self.direct_block_ptr_2,
3 => self.direct_block_ptr_3,
4 => self.direct_block_ptr_4,
5 => self.direct_block_ptr_5,
6 => self.direct_block_ptr_6,
7 => self.direct_block_ptr_7,
8 => self.direct_block_ptr_8,
9 => self.direct_block_ptr_9,
10 => self.direct_block_ptr_10,
11 => self.direct_block_ptr_11,
_ => panic!("direct pointer {} does not exist", index),
})
BlockAddress::new(self.direct_block_ptr[index])
}

pub fn direct_ptrs(&self) -> impl Iterator<Item=Option<BlockAddress>> + '_ {
self.direct_block_ptr.iter().map(|&ptr| BlockAddress::new(ptr))
}

pub fn set_direct_ptr(&mut self, index: usize, ptr: Option<BlockAddress>) {
self.direct_block_ptr[index] = ptr.map_or(0, |v| v.into_u32());
}

pub fn single_indirect_ptr(&self) -> Option<BlockAddress> {
Expand Down
26 changes: 18 additions & 8 deletions ext2/src/write.rs
Original file line number Diff line number Diff line change
Expand Up @@ -36,14 +36,24 @@ where

for (i, block) in (start_block..=end_block).enumerate() {
if !self.is_block_allocated(file, block)? {
todo!("allocate block")
// // TODO: we don't need to allocate if the full content of this block would be zero if the fs allows sparse files
// let free_block_address = self.allocate_block()?;
// if free_block_address.is_none() {
// return Err(Error::NoSpace);
// }
// let free_block_address = free_block_address.unwrap();
// // TODO: write the block address to the inode
// TODO: we don't need to allocate if the full content of this block would be zero if the fs allows sparse files
let free_block_address = self.allocate_block()?;
if free_block_address.is_none() {
return Err(Error::NoSpace);
}
let free_block_address = free_block_address.unwrap();

let inode = file.inode_mut();
let free_slot = inode.direct_ptrs()
.enumerate()
.find(|(_, ptr)| ptr.is_none())
.map(|(i, _)| i);
if let Some(free_slot) = free_slot {
inode.set_direct_ptr(free_slot, Some(free_block_address));
self.write_inode(file.inode_address(), file)?;
} else {
todo!("allocate indirect block");
}
}
}

Expand Down

0 comments on commit 2b8ade8

Please sign in to comment.