diff --git a/Cargo.lock b/Cargo.lock index 4a76b7b..0804957 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -44,6 +44,7 @@ name = "fs_core" version = "0.1.0" dependencies = [ "bitflags", + "path", ] [[package]] @@ -92,6 +93,10 @@ dependencies = [ "syn", ] +[[package]] +name = "path" +version = "0.1.0" + [[package]] name = "ppv-lite86" version = "0.2.17" diff --git a/src/block/allocator.rs b/src/block/allocator.rs index 8f87fce..7c31fdc 100644 --- a/src/block/allocator.rs +++ b/src/block/allocator.rs @@ -206,7 +206,7 @@ where let count = core::cmp::min(bg.blocks_count as usize - ofs, size); trans.block_deallocation_on_bg(ino, bgid, bg.block_bitmap_lba, ofs, count); size -= count; - lba = lba + (count as u64); + lba += count as u64; } Ok(()) } diff --git a/src/block/mod.rs b/src/block/mod.rs index 0d9f750..f3a2b59 100644 --- a/src/block/mod.rs +++ b/src/block/mod.rs @@ -224,13 +224,15 @@ impl Manager { pub(crate) fn get_mut_noload<'l, 'j>( &'l self, lba: LogicalBlockNumber, - collector: &'j Collector, + collector: Option<&'j Collector>, ) -> Result, FsError> where 'l: 'j, { let mut created = false; - collector.track(lba); + if let Some(collector) = collector { + collector.track(lba); + } Ok(self .blocks .get_or_insert_arc::<_, ()>(lba, |_| { diff --git a/src/block_group/mod.rs b/src/block_group/mod.rs index 202821c..3544841 100644 --- a/src/block_group/mod.rs +++ b/src/block_group/mod.rs @@ -181,7 +181,7 @@ impl BlockGroup { if flags.contains(BlockGroupFlag::BLOCK_UNINIT) { let bref = fs .blocks - .get_mut_noload(self.block_bitmap_lba, &tx.collector)?; + .get_mut_noload(self.block_bitmap_lba, Some(&tx.collector))?; let mut guard = bref.write(); let mut block_bitmap = ByteRw::new(guard.as_mut()); let mut base = (fs.sb.first_data_block as u64 + desc_blocks) as usize + 1; @@ -204,7 +204,7 @@ impl BlockGroup { if flags.contains(BlockGroupFlag::INODE_UNINIT) { let bref = fs .blocks - .get_mut_noload(self.inode_bitmap_lba, &tx.collector)?; + .get_mut_noload(self.inode_bitmap_lba, Some(&tx.collector))?; let mut guard = bref.write(); ByteRw::new(guard.as_mut()).set_bitmap(fs.sb.inodes_per_group as usize..BLK_SIZE * 8); @@ -214,7 +214,7 @@ impl BlockGroup { ..self.inode_table_first_block.0 + inode_blocks) .map(LogicalBlockNumber) { - let _ = fs.blocks.get_mut_noload(lba, &tx.collector)?; + let _ = fs.blocks.get_mut_noload(lba, Some(&tx.collector))?; } nflags.insert(BlockGroupFlag::ITABLE_ZEROED); } diff --git a/src/directory/htree/node.rs b/src/directory/htree/node.rs index 511e531..b0e88e5 100644 --- a/src/directory/htree/node.rs +++ b/src/directory/htree/node.rs @@ -440,7 +440,7 @@ impl< // Allocate new block. let (dx_fba, new_blk) = dispatch_cursor_last_mut!(inode, fs, tx, |mut c| { let lba = c.or_allocated(false).unwrap(); - (c.fba(), fs.blocks.get_mut_noload(lba, &tx.collector)?) + (c.fba(), fs.blocks.get_mut_noload(lba, Some(&tx.collector))?) }); let size = inode.get_size(); @@ -637,7 +637,9 @@ impl< DirectoryBlock::new(&mut **blk.write(), fs).clear(); } inode.set_size(BLK_SIZE as u64 * 2, tx); - let raw = fs.blocks.get_mut_noload(root_block_addr, &tx.collector)?; + let raw = fs + .blocks + .get_mut_noload(root_block_addr, Some(&tx.collector))?; { let mut guard = raw.write(); diff --git a/src/directory/mod.rs b/src/directory/mod.rs index e30fc31..3819028 100644 --- a/src/directory/mod.rs +++ b/src/directory/mod.rs @@ -244,7 +244,7 @@ impl Directory { #[cfg(test)] mod tests { - use crate::tests::run_test; + use crate::std::tests::run_test; use crate::FileType; #[test] diff --git a/src/file.rs b/src/file.rs index 48ddf99..8db7c0f 100644 --- a/src/file.rs +++ b/src/file.rs @@ -204,7 +204,7 @@ impl File { #[cfg(test)] mod tests { - use crate::tests::run_test; + use crate::std::tests::run_test; use crate::FileType; #[test] @@ -231,8 +231,9 @@ mod tests { #[test] fn write_big() { - // const SIZE: usize = 4 * 1024 *1024 * 1024; + // const SIZE: usize = 4 * 1024 * 1024 * 1024; const SIZE: usize = 256 * 1024 * 1024; + // const SIZE: usize = 16 * 1024 * 1024 * 1024; run_test( |fs| { let buf = Box::new([0; 4096]); @@ -251,7 +252,7 @@ mod tests { println!("wb"); tx.done(&fs).unwrap(); }, - (SIZE as u64) / 1024 / 1024 + 100, + (SIZE as u64) / 1024 / 1024 + 1000, ); } } diff --git a/src/format.rs b/src/format.rs index 93949ef..036ac60 100644 --- a/src/format.rs +++ b/src/format.rs @@ -65,7 +65,8 @@ impl<'a> FormatAux<'a> { feat_ro: Ext4FeatureReadOnly::SPARSE_SUPER | Ext4FeatureReadOnly::LARGE_FILE | Ext4FeatureReadOnly::GDT_CSUM, - feat_com: Ext4FeatureCompatible::DIR_INDEX, + feat_com: Ext4FeatureCompatible::DIR_INDEX, // ### No journal disk + // feat_com: Ext4FeatureCompatible::DIR_INDEX | Ext4FeatureCompatible::HAS_JOURNAL, // ### Has journal disk feat_incom: Ext4FeatureIncompatible::FILETYPE | Ext4FeatureIncompatible::EXTENTS, uuid, volumn_name, @@ -117,6 +118,10 @@ fn make_sb( sb.first_inode().set(11); sb.inode_size().set(256); + if feat_com.contains(Ext4FeatureCompatible::HAS_JOURNAL) { + sb.journal_inum().set(8); // ### Journal inode number = 8 + } + sb.rw.b.as_mut()[0x68..0x78].copy_from_slice(uuid); sb.rw.b.as_mut()[0x78..0x88].copy_from_slice(volumn_name); sb.rw.b.as_mut()[0xEC..0xFC].copy_from_slice(hash_seed); @@ -183,9 +188,19 @@ fn fill_bg( .as_mut(), ); if bgid.0 == 0 { + // ino 2 -> Root, ino 8 -> Journal inode_bitmap.set_bitmap(0..1); - inode_bitmap.set_bitmap(2..10); - free_inodes -= 9; + if sb + .features_compatible + .contains(Ext4FeatureCompatible::HAS_JOURNAL) + { + inode_bitmap.set_bitmap(2..7); + inode_bitmap.set_bitmap(8..10); + free_inodes -= 8; + } else { + inode_bitmap.set_bitmap(2..10); + free_inodes -= 9; + } } // Set end of inode bitmap. kill 1) unusable 2) padding. inode_bitmap.set_bitmap(sb.inodes_per_group as usize..BLK_SIZE * 8); @@ -267,6 +282,39 @@ fn fill_bg( Ok(()) } +pub fn make_journal_disk( + fs: &Arc>, +) -> Result<(), FsError> { + if !fs + .sb + .features_compatible + .contains(Ext4FeatureCompatible::HAS_JOURNAL) + { + // No journal disk + return Ok(()); + } + let journal_inum = 8; + let ino = fs + .inodes + .allocator + .try_allocate_at(journal_inum, fs)? + .unwrap(); + let tx = fs.open_transaction(); + let guard = fs.get_block_group(BlockGroupId(0))?; + let bg = guard.as_ref().unwrap(); + let de = FileType::Directory; + + bg.allocate_inode_on_bg(journal_inum - 1, &tx, de); + fs.sb.dec_free_inodes_count(&tx); + let _inode = fs + .inodes + .inodes + .get_or_insert::<_, ()>(ino, |ino| Ok(Inode::new(fs, ino, de))) + .unwrap(); + + tx.done(fs) +} + fn make_root( fs: &Arc>, ) -> Result<(), FsError> { @@ -317,15 +365,20 @@ pub fn format( ); let mut sb = make_sb::(aux); fill_bg(&dev, &mut sb)?; - dev.write_bytes(1024, &sb.manipulator.lock().rw.inner().0)?; + const BUFSIZE: usize = 1024; + let mut buf = C::Buffer::::zeroed(); + buf.as_mut()[0..BUFSIZE] + .copy_from_slice(sb.manipulator.lock().rw.inner().0[0..BUFSIZE].as_ref()); + dev.write_bytes(1024, &buf)?; let fs = FileSystem::::new(dev, sb); + make_journal_disk(&fs)?; make_root(&fs)?; Ok(fs) } #[cfg(test)] mod tests { - use crate::tests::{make_disk, test_oracle}; + use crate::std::tests::{make_disk, test_oracle}; const M: u64 = 1024 * 1024; const G: u64 = 1024 * 1024 * 1024; diff --git a/src/inode/allocator.rs b/src/inode/allocator.rs index 42c5433..6856423 100644 --- a/src/inode/allocator.rs +++ b/src/inode/allocator.rs @@ -85,7 +85,7 @@ impl Allocator { loop { // CAS to get bits. let val = bits.load(Ordering::Relaxed); - let x = val ^ core::u8::MAX; + let x = val ^ u8::MAX; if x != 0 { // toggle all bits. let (mask, ret) = { diff --git a/src/inode/extent/cursor.rs b/src/inode/extent/cursor.rs index c14005c..1c8b8fc 100644 --- a/src/inode/extent/cursor.rs +++ b/src/inode/extent/cursor.rs @@ -166,7 +166,7 @@ where for i in 0..len { self.fs .blocks - .get_mut_noload(n + (i as u64), &self.tx.collector)?; + .get_mut_noload(n + (i as u64), Some(&self.tx.collector))?; } } diff --git a/src/inode/extent/mod.rs b/src/inode/extent/mod.rs index 06f2dba..17ee8f7 100644 --- a/src/inode/extent/mod.rs +++ b/src/inode/extent/mod.rs @@ -24,6 +24,7 @@ use crate::{Config, FileBlockNumber, FsError, InodeNumber, LogicalBlockNumber}; use self::path::Path; pub(crate) use cursor::{Cursor, CursorMut}; +use synchronizations::rwlock::RwLock; #[derive(Clone, Debug)] pub(crate) struct Internal { @@ -190,7 +191,7 @@ pub struct ExtentTree { pub(super) depth: u16, pub(super) b: [u8; 48], #[cfg(feature = "extent_cache")] - pub(super) cache: crate::RwLock, C::D>, + pub(super) cache: RwLock, C::D>, #[cfg(not(feature = "extent_cache"))] pub(super) _l: core::marker::PhantomData, } @@ -331,7 +332,7 @@ impl Default for ExtentTree { depth: 0, b: [0; 48], #[cfg(feature = "extent_cache")] - cache: crate::RwLock::new(None), + cache: RwLock::new(None), #[cfg(not(feature = "extent_cache"))] _l: core::marker::PhantomData, } @@ -544,7 +545,7 @@ impl<'a, 'b, C: Config, const BLK_SIZE: usize> ExtentHeaderMut for Node<'a, 'b, impl ExtentTree { #[inline] - fn insert_at(&mut self, ext: Entry, at: usize) -> Result<(), Entry> { + fn insert_at(&mut self, ext: Entry, at: usize, _tx: &Transaction) -> Result<(), Entry> { let (max_entries_cnt, entries_cnt, depth) = ( self.get_max_entries_cnt(), self.get_entries_cnt(), @@ -556,7 +557,7 @@ impl ExtentTree { .map(|_| self.set_entries_cnt(self.get_entries_cnt() + 1)) } #[inline] - fn replace_at(&mut self, ext: Entry, at: usize) -> Result<(), Entry> { + fn replace_at(&mut self, ext: Entry, at: usize, _tx: &Transaction) -> Result<(), Entry> { let (entries_cnt, depth) = (self.get_entries_cnt(), self.get_depth()); replace_at(entries_cnt, depth, ext, at, || ByteRw::new(&mut self.b)) @@ -565,7 +566,7 @@ impl ExtentTree { impl<'a, 'b, C: Config, const BLK_SIZE: usize> Node<'a, 'b, C, BLK_SIZE, true> { #[inline] - fn insert_at(&mut self, ext: Entry, at: usize) -> Result<(), Entry> { + fn insert_at(&mut self, ext: Entry, at: usize, tx: &Transaction) -> Result<(), Entry> { let (max_entries_cnt, entries_cnt, depth) = ( self.get_max_entries_cnt(), self.get_entries_cnt(), @@ -574,19 +575,114 @@ impl<'a, 'b, C: Config, const BLK_SIZE: usize> Node<'a, 'b, C, BLK_SIZE, true> { { let mut guard = self.b.write(); - insert_at(max_entries_cnt, entries_cnt, depth, ext, at, || { + insert_at(max_entries_cnt, entries_cnt, depth, ext.clone(), at, || { ByteRw::new(&mut guard[12..]) }) } - .map(|_| self.set_entries_cnt(self.get_entries_cnt() + 1)) + .map(|_| { + tx.extent_update_node_insert_at(self.b.lba(), ext, at); + self.set_entries_cnt(self.get_entries_cnt() + 1) + }) } #[inline] - fn replace_at(&mut self, ext: Entry, at: usize) -> Result<(), Entry> { + fn replace_at(&mut self, ext: Entry, at: usize, tx: &Transaction) -> Result<(), Entry> { let (entries_cnt, depth) = (self.get_entries_cnt(), self.get_depth()); let mut guard = self.b.write(); - replace_at(entries_cnt, depth, ext, at, || { + replace_at(entries_cnt, depth, ext.clone(), at, || { ByteRw::new(&mut guard[12..]) }) + .map(|_| tx.extent_update_node_replace_at(self.b.lba(), ext, at)) + } +} + +pub struct RawNode { + rw: ByteRw<[u8; BLK_SIZE]>, +} + +impl RawNode { + pub fn from_raw(rw: [u8; BLK_SIZE]) -> Self { + Self { + rw: ByteRw::new(rw), + } + } + + pub fn init(&mut self, depth: u16) { + self.rw.write_u16(0, 0xF30A); + self.rw.write_u16(2, 0); + self.rw.write_u16(4, ((BLK_SIZE - 16) / 12) as u16); + self.rw.write_u16(6, depth); + } + + pub fn get_entries_cnt(&self) -> u16 { + self.rw.read_u16(2) + } + + pub fn get_max_entries_cnt(&self) -> u16 { + self.rw.read_u16(4) + } + + pub fn get_depth(&self) -> u16 { + self.rw.read_u16(6) + } + + pub fn get(&self, index: usize) -> Option { + if index < self.get_entries_cnt() as usize { + if self.get_depth() == 0 { + let (len, is_init) = { + let v = self.rw.read_u16(12 + 12 * index + 4); + let is_init = v <= 0x8000; + (if is_init { v } else { v - 0x8000 }, is_init) + }; + Some(Entry::Leaf(Leaf { + block: FileBlockNumber(self.rw.read_u32(12 + 12 * index)), + start: LogicalBlockNumber(merge_u32( + self.rw.read_u16(12 + 12 * index + 6) as u32, + self.rw.read_u32(12 + 12 * index + 8), + )), + len, + is_init, + })) + } else { + Some(Entry::Internal(Internal { + block: FileBlockNumber(self.rw.read_u32(12 + 12 * index)), + next_node: LogicalBlockNumber(merge_u32( + self.rw.read_u16(12 + 12 * index + 8) as u32, + self.rw.read_u32(12 + 12 * index + 4), + )), + })) + } + } else { + None + } + } + + pub fn set_entries_cnt(&mut self, v: u16) { + self.rw.write_u16(2, v); + } + + pub fn insert_at(&mut self, ext: Entry, at: usize) -> Result<(), Entry> { + let (max_entries_cnt, entries_cnt, depth) = ( + self.get_max_entries_cnt(), + self.get_entries_cnt(), + self.get_depth(), + ); + { + insert_at(max_entries_cnt, entries_cnt, depth, ext, at, || { + ByteRw::new(&mut self.rw.b[12..]) + }) + } + .map(|_| self.set_entries_cnt(self.get_entries_cnt() + 1)) + } + + pub fn replace_at(&mut self, ext: Entry, at: usize) -> Result<(), Entry> { + let (entries_cnt, depth) = (self.get_entries_cnt(), self.get_depth()); + replace_at(entries_cnt, depth, ext, at, || { + ByteRw::new(&mut self.rw.b[12..]) + }) + } + + pub fn to_raw(self) -> [u8; BLK_SIZE] { + self.rw.b } } diff --git a/src/inode/extent/path.rs b/src/inode/extent/path.rs index c566cb5..dfcbe7f 100644 --- a/src/inode/extent/path.rs +++ b/src/inode/extent/path.rs @@ -15,6 +15,7 @@ use super::{Entry, ExtentHeader, ExtentHeaderMut, ExtentTree, Internal, Leaf, Node}; use crate::block::BlockRef; use crate::filesystem::FileSystem; +use crate::inode::RawInodeAddressingMode; use crate::transaction::Transaction; use crate::utils::ByteRw; use crate::{Config, FileBlockNumber, FsError, InodeNumber, LogicalBlockNumber}; @@ -353,7 +354,11 @@ where } } - fn insert_leaf(&mut self, new: Leaf) -> Result, FsError> { + // ### Extent Tree Logging + // ### Root modificiation -> process at path level + // ### Node modification -> if only Node::set_entries_cnt is called, process at path level, otherwise process at node level + + fn insert_leaf(&mut self, new: Leaf, tx: &Transaction) -> Result, FsError> { let leaf = self.get_leaf(); if leaf.as_ref().map(|l| l.block == new.block).unwrap_or(false) { @@ -381,8 +386,22 @@ where is_init, }), index.unwrap(), + tx, ) .unwrap_or_else(|_| unreachable!()); + + if let PathEntry::Root((updated, _)) = self.last() { + tx.inode_update_root( + self.ino, + RawInodeAddressingMode::Extent { + entries_cnt: updated.entries_cnt, + max_entries_cnt: updated.max_entries_cnt, + depth: updated.depth, + b: updated.b, + }, + ); + } + return Ok(None); } } @@ -399,15 +418,26 @@ where let mut pos = index.unwrap(); let updated_start = new.block; - if let Err(_en) = node.insert_at(Entry::Leaf(new), pos) { + if let Err(_en) = node.insert_at(Entry::Leaf(new.clone()), pos, tx) { todo!() } + if let PathEntry::Root((updated, _)) = self.last() { + tx.inode_update_root( + self.ino, + RawInodeAddressingMode::Extent { + entries_cnt: updated.entries_cnt, + max_entries_cnt: updated.max_entries_cnt, + depth: updated.depth, + b: updated.b, + }, + ); + } - for idx in (0..self.len() - 1).rev() { + for i in (0..self.len() - 1).rev() { if pos != 0 { break; } - dispatch_entry_mut!(self.get_mut(idx).unwrap(), |node, idx| { + dispatch_entry_mut!(self.get_mut(i).unwrap(), |node, idx| { pos = idx.unwrap(); let prev = node.get(pos).unwrap().get_internal().unwrap(); node.replace_at( @@ -416,8 +446,25 @@ where next_node: prev.next_node, }), pos, + tx, ) .unwrap_or_else(|_| unreachable!()); + + if i == 0 { + if let PathEntry::Root((updated, _)) = self.get(0).unwrap() { + tx.inode_update_root( + self.ino, + RawInodeAddressingMode::Extent { + entries_cnt: updated.entries_cnt, + max_entries_cnt: updated.max_entries_cnt, + depth: updated.depth, + b: updated.b, + }, + ); + } else { + unreachable!(); + } + } }); } @@ -441,7 +488,10 @@ where (ino.0 as u64 - 1) / fs.sb.inodes_per_group as u64, )); let lba = fs.blocks.allocate(self.ino, 1, hope, fs, tx)?.0; - let b = fs.blocks.get_mut_noload(lba, &tx.collector)?; + + // let b = fs.blocks.get_mut_noload(lba, Some(&tx.collector))?; + // ### To prevent the collector from tracking the extent node block. + let b = fs.blocks.get_mut_noload(lba, None)?; { // Initialize the node. let mut guard = b.write(); @@ -453,8 +503,11 @@ where } let mut node = Node::from_bytes(b).unwrap(); + tx.extent_init_node(lba, root.get_depth()); + for i in 0..root.get_entries_cnt() as usize { - node.insert_at(root.get(i).unwrap(), i) + let entry = root.get(i).unwrap(); + node.insert_at(entry.clone(), i, tx) .unwrap_or_else(|_| unreachable!()); } @@ -466,12 +519,24 @@ where next_node: lba, }), 0, + tx, ) .unwrap_or_else(|_| unreachable!()); + if let PathEntry::Root((updated, _)) = self.get(0).unwrap() { + tx.inode_update_root( + self.ino, + RawInodeAddressingMode::Extent { + entries_cnt: updated.entries_cnt, + max_entries_cnt: updated.max_entries_cnt, + depth: updated.depth, + b: updated.b, + }, + ); + } Ok(()) } - fn insert_internal(&mut self, ext: Internal, at: usize) -> bool { + fn insert_internal(&mut self, ext: Internal, at: usize, tx: &Transaction) -> bool { // Find location for insertion. dispatch_entry_mut!(self.get_mut(at).unwrap(), |node, idx| { let loc = if node.is_full() { @@ -483,8 +548,22 @@ where } else { idx.unwrap() }; - node.insert_at(Entry::Internal(ext), loc) + node.insert_at(Entry::Internal(ext), loc, tx) .unwrap_or_else(|_| unreachable!()); + if at == 0 { + if let PathEntry::Root((updated, _)) = self.get(0).unwrap() { + tx.inode_update_root( + self.ino, + RawInodeAddressingMode::Extent { + entries_cnt: updated.entries_cnt, + max_entries_cnt: updated.max_entries_cnt, + depth: updated.depth, + b: updated.b, + }, + ); + } + } + true }) } @@ -511,7 +590,7 @@ where let (lba, _) = fs .blocks .allocate(self.ino, 1, LogicalBlockNumber(0), fs, tx)?; - let e = fs.blocks.get_mut_noload(lba, &tx.collector)?; + let e = fs.blocks.get_mut_noload(lba, None)?; blocks.push(e); } @@ -521,6 +600,12 @@ where .enumerate() .map(|(d, hdr_b)| { // Leaf. + let node_lba = if let Some(PathEntry::Leaf((node, _))) = self.get(d + at) { + Some(node.b.lba()) + } else { + None + }; + dispatch_entry_mut!(self.get_mut(d + at).unwrap(), |ext, idx| { // Leaf node. if d + at == depth { @@ -549,13 +634,17 @@ where // To insert here. let mut node = Node::from_bytes(hdr_b).unwrap(); + tx.extent_init_node(node.b.lba(), ext.get_depth()); + let base = idx.unwrap(); let move_amount = ext.get_entries_cnt() as usize - base - 1; for i in 0..move_amount { - node.insert_at(ext.get(base + i + 1).unwrap(), i) + node.insert_at(ext.get(base + i + 1).unwrap(), i, tx) .unwrap_or_else(|_| unreachable!()); } ext.set_entries_cnt(base as u16 + 1); + tx.extent_update_node_set_entries_cnt(node_lba.unwrap(), base as u16 + 1); + node.into_inner() } else { todo!() @@ -570,6 +659,7 @@ where block: insert_idx, }, at - 1, + tx, ) .then(|| (new.block >= insert_idx, blocks)) .ok_or(FsError::InvalidFs("Extent Tree is corrupted.")) @@ -583,7 +673,7 @@ where fs: &'a FileSystem, ) -> Result, FsError> { loop { - if let Some(l) = self.insert_leaf(new)? { + if let Some(l) = self.insert_leaf(new, tx)? { new = l; } else { break Ok(None); @@ -601,7 +691,7 @@ where }; let (need_fix, blks) = self - .split_at(&new, self.len() - level - 1, tx, fs) + .split_at(&new, level + 1, tx, fs) .map_err(|_| FsError::IoError)?; if need_fix { @@ -692,6 +782,11 @@ where tx, )?; } + let node_lba = if let Some((node, _)) = self.leafs.last() { + Some(node.b.lba()) + } else { + None + }; dispatch_entry_mut!(self.last_mut(), |node, idx| { if new_len != 0 { let idx = idx.unwrap(); @@ -701,10 +796,33 @@ where ..leaf }), idx, + tx, ) .unwrap(); } else { - node.set_entries_cnt(node.get_entries_cnt().checked_sub(1).unwrap_or_default()); + let cnt = node.get_entries_cnt().checked_sub(1).unwrap_or_default(); + node.set_entries_cnt(cnt); + match node_lba { + Some(lba) => { + // Node + tx.extent_update_node_set_entries_cnt(lba, cnt); + } + None => { + // Root + if let PathEntry::Root((updated, _)) = self.get(0).unwrap() { + assert_eq!(updated.entries_cnt, cnt); + tx.inode_update_root( + self.ino, + RawInodeAddressingMode::Extent { + entries_cnt: updated.entries_cnt, + max_entries_cnt: updated.max_entries_cnt, + depth: updated.depth, + b: updated.b, + }, + ); + } + } + } self.move_prev_with_cleanup(tx, fs)?; } }); @@ -725,6 +843,11 @@ where Some(0) if len != 1 => { len -= 1; let (p_node, _) = self.leafs.pop().unwrap(); + let node_lba = if let PathEntry::Leaf((node, _)) = self.last() { + Some(node.b.lba()) + } else { + None + }; dispatch_entry_mut!(self.last_mut(), |node, idx| { // cleanup if p_node.get_entries_cnt() == 0 { @@ -739,6 +862,29 @@ where fs.blocks.deallocate(ino, lba, 1, fs, tx)?; node.set_entries_cnt(new_count); + match node_lba { + Some(node_lba) => { + // Node + tx.extent_update_node_set_entries_cnt(node_lba, new_count); + } + None => { + // Root + // assert_eq!(self.len(), 1); + if let PathEntry::Root((updated, _)) = self.get(0).unwrap() { + // assert_eq!(updated.entries_cnt, new_count); + tx.inode_update_root( + ino, + RawInodeAddressingMode::Extent { + entries_cnt: updated.entries_cnt, + max_entries_cnt: updated.max_entries_cnt, + depth: updated.depth, + b: updated.b, + }, + ); + } + } + } + if new_count != 0 { break; } diff --git a/src/inode/mod.rs b/src/inode/mod.rs index 5fefdc8..d4594ba 100644 --- a/src/inode/mod.rs +++ b/src/inode/mod.rs @@ -13,7 +13,7 @@ // limitations under the License. mod allocator; -mod extent; +pub(crate) mod extent; mod legacy; mod manager; mod raw; diff --git a/src/lib.rs b/src/lib.rs index 60f9a4a..dbe954e 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -24,10 +24,7 @@ mod std; pub use synchronizations::rwlock::{ - Dreamer as RwDreamer, - RwLock, - RwLockReadGuard, - RwLockWriteGuard + Dreamer as RwDreamer, RwLock, RwLockReadGuard, RwLockWriteGuard, }; pub use synchronizations::ticket_lock::{Dreamer, TicketLock, TicketLockGuard}; diff --git a/src/std.rs b/src/std.rs index 424b0d6..9552937 100644 --- a/src/std.rs +++ b/src/std.rs @@ -124,7 +124,6 @@ impl synchronizations::ticket_lock::Dreamer for SpinningDreamer { fn release_hook(&self) {} } - /// A Opaque dreamer for RwLock. /// /// We will not use the implementation of synchromization::RwLock on std. @@ -139,30 +138,23 @@ impl synchronizations::rwlock::Dreamer for OpaqueDreamer { #[inline] fn sleeping(&self, _s: &core::sync::atomic::AtomicUsize, _h: synchronizations::rwlock::Hint) { - unreachable!() + () } #[inline] fn waking_up(&self) { - unreachable!() + () } #[inline] fn prehook(&self) -> Self::HookAux { - unreachable!() + () } #[inline] - fn acquire_hook( - &self, - _h: synchronizations::rwlock::Hint, - _d: bool, - ) { - unreachable!() + fn acquire_hook(&self, _h: synchronizations::rwlock::Hint, _d: bool) { + () } #[inline] - fn release_hook( - &self, - _h: synchronizations::rwlock::Hint, - ) { - unreachable!() + fn release_hook(&self, _h: synchronizations::rwlock::Hint) { + () } } @@ -230,7 +222,6 @@ impl Config for std::fs::File { } } - #[cfg(test)] pub(crate) mod tests { use crate::format; diff --git a/src/superblock/raw.rs b/src/superblock/raw.rs index f992481..0cb1a8a 100644 --- a/src/superblock/raw.rs +++ b/src/superblock/raw.rs @@ -155,6 +155,8 @@ impl Manipulator { feature_ro_compat: @0x64, u32; /// Number of reserved GDT entries for future filesystem expansion. reserverd_gdt_blocks: @0xCE, u16; + /// Inode number of journal file + journal_inum: @0xE0, u32; /// Start of list of orphaned inodes to delete. last_orphan: @0xE8, u32; /// Default hash algorithm to use for directory hashes. diff --git a/src/transaction/event.rs b/src/transaction/event.rs index 33be40e..13d304e 100644 --- a/src/transaction/event.rs +++ b/src/transaction/event.rs @@ -16,6 +16,7 @@ use super::collector::{Collector, PostludeOps}; use crate::block::BlockRef; use crate::block_group; use crate::filesystem::FileSystem; +use crate::inode::extent::{Entry, RawNode}; use crate::inode::{self, RawInodeAddressingMode}; use crate::superblock; use crate::{ @@ -92,6 +93,12 @@ impl core::fmt::Debug for InodeSetSize { } } +#[derive(Debug)] +pub struct InodeUpdateRoot { + pub(super) ino: InodeNumber, + pub(super) address: RawInodeAddressingMode, +} + #[derive(Debug)] pub enum Event { BlockAllocationOnBg(BlockAllocationOnBg), @@ -104,6 +111,8 @@ pub enum Event { InodeUpdateOrphanLink(InodeUpdateOrphanLink), FreeInodesCountDecOnSb, FreeInodesCountIncOnSb, + InodeUpdateRoot(InodeUpdateRoot), + ExtentUpdateNode(ExtentNodeOps), } #[derive(Debug)] @@ -206,6 +215,8 @@ impl Events { Event::InodeSetSize(op) => { wb_grp.inode_ops.push(InodeOps::SetSize(op)); } + Event::InodeUpdateRoot(ext) => wb_grp.inode_ops.push(InodeOps::UpdateRoot(ext)), + Event::ExtentUpdateNode(op) => wb_grp.extent_node_ops.push(op), } } wb_grp @@ -244,6 +255,7 @@ pub enum InodeOps { SetSize(InodeSetSize), UpdateOrphanLink(InodeUpdateOrphanLink), SetBlock { ino: InodeNumber, cnt: i64 }, + UpdateRoot(InodeUpdateRoot), } fn get_inode<'a, 'b, C: Config + 'a, const BLK_SIZE: usize>( @@ -300,6 +312,7 @@ struct WritebackGroup { bg_deltas: HashMap, sb_delta: Option, inode_ops: Vec, + extent_node_ops: Vec, _ty: core::marker::PhantomData, } @@ -309,6 +322,7 @@ impl WritebackGroup { bg_deltas: HashMap::new(), sb_delta: None, inode_ops: Vec::new(), + extent_node_ops: Vec::new(), _ty: core::marker::PhantomData, } } @@ -408,6 +422,7 @@ impl WritebackGroup { bg_deltas, sb_delta, inode_ops, + extent_node_ops, .. } = self; @@ -420,6 +435,9 @@ impl WritebackGroup { for op in inode_ops.into_iter() { Self::submit_inode_ops(fs, op, &mut raw_sb, collector)?; } + + Self::submit_extent_node_ops(fs, extent_node_ops, collector)?; + Self::submit_sb(sb_delta, raw_sb, collector)?; Ok(()) } @@ -542,7 +560,67 @@ impl WritebackGroup { .0, ); } + InodeOps::UpdateRoot(ext) => { + let InodeUpdateRoot { ino, address } = ext; + // println!("Commit Root Update - Ino: {}, Inode - {:?}\n", ino.0, address); + let (raw, range) = get_inode(fs, ino, collector)?; + let mut guard = raw.write(); + let mut inode = inode::Manipulator::new(&mut guard[range]); + inode.set_addresses(fs, address); + } + } + Ok(()) + } + + fn submit_extent_node_ops( + fs: &FileSystem, + ops: Vec, + collector: &Collector, + ) -> Result<(), FsError> { + let mut op_map = HashMap::new(); // Map: lba -> Vec + + ops.iter().for_each(|op| { + let lba = op.lba(); + op_map.entry(lba).or_insert(Vec::new()).push(op); + }); + + for (lba, op_vec) in op_map { + let raw_conf: [u8; BLK_SIZE] = fs + .blocks + .get_mut(lba, collector)? + .read() + .as_slice() + .try_into() + .expect("Invalid block size"); + let mut raw_node = RawNode::from_raw(raw_conf); + + for op in op_vec.into_iter() { + match op { + ExtentNodeOps::InsertAt(InsertAt { at, entry, .. }) => { + raw_node.insert_at(entry.clone(), *at).unwrap(); + // println!("Commit Node Insert - lba: {}, at: {}", lba.0, at); + } + ExtentNodeOps::ReplaceAt(ReplaceAt { at, entry, .. }) => { + raw_node.replace_at(entry.clone(), *at).unwrap(); + // println!("Commit Node Replace - lba: {}, at: {}", lba.0, at); + } + ExtentNodeOps::SetEntriesCnt(SetEntriesCnt { v, .. }) => { + raw_node.set_entries_cnt(*v); + // println!("Commit Node SetEntriesCnt - lba: {}, v: {}", lba.0, v); + } + ExtentNodeOps::Init(Init { depth, .. }) => { + raw_node.init(*depth); + // println!("Commit Node Init - lba: {}, depth: {}", lba.0, depth); + } + } + } + + let raw_conf = raw_node.to_raw(); + let b_ref = fs.blocks.get_mut(lba, collector)?; + let mut guard = b_ref.write(); + guard.copy_from_slice(&raw_conf); } + Ok(()) } @@ -572,3 +650,48 @@ impl WritebackGroup { Ok(()) } } + +#[derive(Debug)] +pub struct InsertAt { + pub(super) node_lba: LogicalBlockNumber, + pub(super) at: usize, + pub(super) entry: Entry, +} + +#[derive(Debug)] +pub struct ReplaceAt { + pub(super) node_lba: LogicalBlockNumber, + pub(super) at: usize, + pub(super) entry: Entry, +} + +#[derive(Debug)] +pub struct SetEntriesCnt { + pub(super) node_lba: LogicalBlockNumber, + pub(super) v: u16, +} + +#[derive(Debug)] +pub struct Init { + pub(super) node_lba: LogicalBlockNumber, + pub(super) depth: u16, +} + +#[derive(Debug)] +pub(crate) enum ExtentNodeOps { + InsertAt(InsertAt), + ReplaceAt(ReplaceAt), + SetEntriesCnt(SetEntriesCnt), + Init(Init), +} + +impl ExtentNodeOps { + fn lba(&self) -> LogicalBlockNumber { + match self { + ExtentNodeOps::InsertAt(InsertAt { node_lba, .. }) => *node_lba, + ExtentNodeOps::ReplaceAt(ReplaceAt { node_lba, .. }) => *node_lba, + ExtentNodeOps::SetEntriesCnt(SetEntriesCnt { node_lba, .. }) => *node_lba, + ExtentNodeOps::Init(Init { node_lba, .. }) => *node_lba, + } + } +} diff --git a/src/transaction/mod.rs b/src/transaction/mod.rs index 0044abd..bffdb44 100644 --- a/src/transaction/mod.rs +++ b/src/transaction/mod.rs @@ -17,13 +17,15 @@ mod collector; mod event; use crate::filesystem::FileSystem; +use crate::inode::extent::Entry; use crate::inode::RawInodeAddressingMode; use crate::{BlockGroupId, Config, FileType, FsError, InodeNumber, LogicalBlockNumber}; use alloc::collections::LinkedList; use core::cell::RefCell; use event::{ - BlockAllocationOnBg, BlockDeallocationOnBg, InodeAddLink, InodeAllocationOnBg, - InodeDeallocationOnBg, InodeRmLink, InodeSetSize, InodeUpdateOrphanLink, + BlockAllocationOnBg, BlockDeallocationOnBg, ExtentNodeOps, Init, InodeAddLink, + InodeAllocationOnBg, InodeDeallocationOnBg, InodeRmLink, InodeSetSize, InodeUpdateOrphanLink, + InodeUpdateRoot, InsertAt, ReplaceAt, SetEntriesCnt, }; pub use collector::Collector; @@ -213,6 +215,77 @@ impl Transaction { })) } + #[inline] + pub fn inode_update_root(&self, ino: InodeNumber, address: RawInodeAddressingMode) { + self.events + .inner + .as_ref() + .unwrap() + .borrow_mut() + .push_back(Event::InodeUpdateRoot(InodeUpdateRoot { ino, address })) + } + + pub(crate) fn extent_update_node_insert_at( + &self, + node_lba: LogicalBlockNumber, + entry: Entry, + at: usize, + ) { + self.events + .inner + .as_ref() + .unwrap() + .borrow_mut() + .push_back(Event::ExtentUpdateNode(ExtentNodeOps::InsertAt(InsertAt { + node_lba, + at, + entry, + }))); + } + + pub(crate) fn extent_update_node_replace_at( + &self, + node_lba: LogicalBlockNumber, + entry: Entry, + at: usize, + ) { + self.events + .inner + .as_ref() + .unwrap() + .borrow_mut() + .push_back(Event::ExtentUpdateNode(ExtentNodeOps::ReplaceAt( + ReplaceAt { + node_lba, + at, + entry, + }, + ))); + } + + pub(crate) fn extent_update_node_set_entries_cnt(&self, node_lba: LogicalBlockNumber, v: u16) { + self.events + .inner + .as_ref() + .unwrap() + .borrow_mut() + .push_back(Event::ExtentUpdateNode(ExtentNodeOps::SetEntriesCnt( + SetEntriesCnt { node_lba, v }, + ))); + } + + pub(crate) fn extent_init_node(&self, node_lba: LogicalBlockNumber, depth: u16) { + self.events + .inner + .as_ref() + .unwrap() + .borrow_mut() + .push_back(Event::ExtentUpdateNode(ExtentNodeOps::Init(Init { + node_lba, + depth, + }))); + } + #[inline] pub fn done( self, diff --git a/src/types.rs b/src/types.rs index 032e3a1..083275d 100644 --- a/src/types.rs +++ b/src/types.rs @@ -241,4 +241,4 @@ where } fn total_size(&self) -> usize; -} \ No newline at end of file +}