Nothing to see here, move along meow
0

Configure Feed

Select the types of activity you want to include in your feed.

at main 6.2 kB View raw
1use crate::block_io::BlockIo; 2use crate::cache::BlockCache; 3use crate::error::FsError; 4use crate::integrity; 5use lancer_core::fs::{BTREE_NODE_SIZE, BTreeNode, BlockRef}; 6 7const MAX_TREE_DEPTH: usize = 5; 8 9pub struct FreemapReserved { 10 region_start: u64, 11 half_size: u64, 12 active_half: u8, 13 next_block: u64, 14 end_block: u64, 15} 16 17impl FreemapReserved { 18 pub fn init(total_blocks: u64) -> Self { 19 let reserved_count = crate::freemap::compute_reserved_count(total_blocks); 20 let half_size = reserved_count / 2; 21 let region_start = 2u64; 22 Self { 23 region_start, 24 half_size, 25 active_half: 0, 26 next_block: region_start, 27 end_block: region_start + half_size, 28 } 29 } 30 31 pub fn alloc_reserved(&mut self) -> Result<u64, FsError> { 32 match self.next_block < self.end_block { 33 true => { 34 let block = self.next_block; 35 self.next_block += 1; 36 Ok(block) 37 } 38 false => Err(FsError::ReservedExhausted), 39 } 40 } 41 42 pub fn flip_after_commit(&mut self) { 43 self.active_half = 1 - self.active_half; 44 let half_start = self.region_start + self.active_half as u64 * self.half_size; 45 self.next_block = half_start; 46 self.end_block = half_start + self.half_size; 47 } 48 49 pub fn remaining(&self) -> u64 { 50 self.end_block.saturating_sub(self.next_block) 51 } 52} 53 54struct WalkState { 55 path: [(u64, usize); MAX_TREE_DEPTH], 56 depth: usize, 57 leaf_block: u64, 58} 59 60enum CowWalk { 61 FoundLeaf(u64), 62 Err(FsError), 63} 64 65impl From<FsError> for CowWalk { 66 fn from(e: FsError) -> Self { 67 CowWalk::Err(e) 68 } 69} 70 71fn walk_to_leaf( 72 cache: &mut BlockCache, 73 bio: &mut BlockIo, 74 root: &BlockRef, 75 target_key: u64, 76) -> Result<WalkState, FsError> { 77 if root.is_null() { 78 return Err(FsError::NotFound); 79 } 80 81 let start_block = crate::blockref_block_num(root); 82 let mut path = [(0u64, 0usize); MAX_TREE_DEPTH]; 83 let mut depth = 0usize; 84 85 let result = (0..MAX_TREE_DEPTH + 1).try_fold(start_block, |current_block, _| { 86 let node_data = cache.cache_read(bio, current_block).map_err(CowWalk::Err)?; 87 let node = unsafe { &*(node_data.as_ptr() as *const BTreeNode) }; 88 89 match node.is_valid() { 90 true => {} 91 false => return Err(CowWalk::Err(FsError::CorruptNode)), 92 } 93 94 let child_idx = node.find_child_index(target_key); 95 match child_idx < node.entry_count() { 96 false => Err(CowWalk::Err(FsError::NotFound)), 97 true => { 98 match depth < MAX_TREE_DEPTH { 99 true => { 100 path[depth] = (current_block, child_idx); 101 depth += 1; 102 } 103 false => return Err(CowWalk::Err(FsError::CorruptNode)), 104 } 105 match node.is_leaf() { 106 true => Err(CowWalk::FoundLeaf(crate::blockref_block_num( 107 &node.entries[child_idx], 108 ))), 109 false => Ok(crate::blockref_block_num(&node.entries[child_idx])), 110 } 111 } 112 } 113 }); 114 115 let leaf_block = match result { 116 Ok(_) => return Err(FsError::CorruptNode), 117 Err(CowWalk::FoundLeaf(block)) => block, 118 Err(CowWalk::Err(e)) => return Err(e), 119 }; 120 121 Ok(WalkState { 122 path, 123 depth, 124 leaf_block, 125 }) 126} 127 128pub fn cow_freemap_path( 129 cache: &mut BlockCache, 130 bio: &mut BlockIo, 131 freemap_root: &BlockRef, 132 modified_leaf_key: u64, 133 reserved: &mut FreemapReserved, 134) -> Result<BlockRef, FsError> { 135 let walk = walk_to_leaf(cache, bio, freemap_root, modified_leaf_key)?; 136 137 let new_leaf_block = reserved.alloc_reserved()?; 138 let leaf_data = cache.cache_read(bio, walk.leaf_block)?; 139 let mut leaf_copy = [0u8; BTREE_NODE_SIZE]; 140 leaf_copy.copy_from_slice(leaf_data); 141 let leaf_hashes = integrity::compute_block_hashes(&leaf_copy); 142 cache.cache_write(bio, new_leaf_block, &leaf_copy)?; 143 144 let init_state = ( 145 new_leaf_block, 146 leaf_hashes.content_hash, 147 leaf_hashes.integrity_crc, 148 ); 149 150 let (child_new_block, child_hash, child_crc) = (0..walk.depth).rev().try_fold( 151 init_state, 152 |(child_block, child_content_hash, child_integrity_crc), level| { 153 let (parent_block, child_idx) = walk.path[level]; 154 155 let parent_data = cache.cache_read(bio, parent_block)?; 156 let mut node_copy = [0u8; BTREE_NODE_SIZE]; 157 node_copy.copy_from_slice(parent_data); 158 159 let node = unsafe { &mut *(node_copy.as_mut_ptr() as *mut BTreeNode) }; 160 let old_ref = &node.entries[child_idx]; 161 node.entries[child_idx] = BlockRef::new( 162 crate::block_num_to_phys(child_block), 163 old_ref.block_size_log2().unwrap_or(12), 164 old_ref.key, 165 old_ref.transaction_id, 166 child_content_hash, 167 child_integrity_crc, 168 old_ref 169 .block_type_enum() 170 .unwrap_or(lancer_core::fs::BlockType::Freemap), 171 old_ref 172 .compression_enum() 173 .unwrap_or(lancer_core::fs::Compression::None), 174 old_ref.logical_size, 175 old_ref.flags, 176 ); 177 178 let parent_hashes = integrity::compute_block_hashes(&node_copy); 179 let new_parent_block = reserved.alloc_reserved()?; 180 cache.cache_write(bio, new_parent_block, &node_copy)?; 181 182 Ok::<(u64, u128, u32), FsError>(( 183 new_parent_block, 184 parent_hashes.content_hash, 185 parent_hashes.integrity_crc, 186 )) 187 }, 188 )?; 189 190 let mut new_root_ref = *freemap_root; 191 new_root_ref.physical_addr = 192 crate::block_num_to_phys(child_new_block) | (freemap_root.physical_addr & 0xF); 193 new_root_ref.content_hash = child_hash.to_le_bytes(); 194 new_root_ref.integrity_crc = child_crc; 195 Ok(new_root_ref) 196}