Nothing to see here, move along
at main 127 lines 4.0 kB view raw
1use crate::block_io::BlockIo; 2use crate::cache::BlockCache; 3use crate::error::FsError; 4use crate::integrity::crc32c; 5use lancer_core::fs::{BlockRef, DEDUP_SHARDS, SUPERBLOCK_SIZE, Superblock, SuperblockSlot}; 6 7fn superblock_to_bytes(sb: &Superblock) -> [u8; SUPERBLOCK_SIZE] { 8 let mut buf = [0u8; SUPERBLOCK_SIZE]; 9 let src = sb as *const Superblock as *const u8; 10 unsafe { core::ptr::copy_nonoverlapping(src, buf.as_mut_ptr(), SUPERBLOCK_SIZE) }; 11 buf 12} 13 14fn superblock_from_bytes(buf: &[u8; SUPERBLOCK_SIZE]) -> Superblock { 15 unsafe { core::ptr::read_unaligned(buf.as_ptr() as *const Superblock) } 16} 17 18pub struct CommitRoots { 19 pub tree_root: BlockRef, 20 pub freemap_root: BlockRef, 21 pub dedup_roots: [BlockRef; DEDUP_SHARDS], 22 pub snapshot_root: BlockRef, 23 pub scrub_cursor: u64, 24 pub next_object_id: u64, 25} 26 27pub struct SuperblockPair { 28 slots: [Superblock; 2], 29} 30 31impl SuperblockPair { 32 pub fn load(a: Superblock, b: Superblock) -> Self { 33 Self { slots: [a, b] } 34 } 35 36 pub fn active(&self) -> &Superblock { 37 lancer_core::fs::select_superblock(&self.slots[0], &self.slots[1]) 38 } 39 40 fn commit_target(&self) -> SuperblockSlot { 41 lancer_core::fs::commit_target(&self.slots[0], &self.slots[1]) 42 } 43 44 fn update_slot(&mut self, slot: SuperblockSlot, sb: Superblock) { 45 match slot { 46 SuperblockSlot::A => self.slots[0] = sb, 47 SuperblockSlot::B => self.slots[1] = sb, 48 } 49 } 50} 51 52pub fn atomic_commit( 53 bio: &mut BlockIo, 54 cache: &mut BlockCache, 55 pair: &mut SuperblockPair, 56 roots: &CommitRoots, 57) -> Result<(), FsError> { 58 cache.cache_flush(bio)?; 59 bio.flush()?; 60 61 let current = pair.active(); 62 let next_seq = current.next_sequence().ok_or(FsError::CorruptSuperblock)?; 63 let next_txn = current 64 .next_transaction() 65 .ok_or(FsError::CorruptSuperblock)?; 66 67 let mut new_sb = Superblock::new(current.total_blocks, current.block_size); 68 new_sb.sequence = next_seq; 69 new_sb.transaction_id = next_txn; 70 new_sb.tree_root = roots.tree_root; 71 new_sb.freemap_root = roots.freemap_root; 72 new_sb.dedup_roots = roots.dedup_roots; 73 new_sb.snapshot_root = roots.snapshot_root; 74 new_sb.scrub_cursor = roots.scrub_cursor; 75 new_sb.next_object_id = roots.next_object_id; 76 new_sb.checksum = 0; 77 78 let mut buf = superblock_to_bytes(&new_sb); 79 let checksum = crc32c(&buf[..SUPERBLOCK_SIZE - 4]); 80 buf[SUPERBLOCK_SIZE - 4..].copy_from_slice(&checksum.to_le_bytes()); 81 82 let target = pair.commit_target(); 83 bio.write_blocks(target.block_number(), 1, &buf)?; 84 bio.flush()?; 85 86 let final_sb = superblock_from_bytes(&buf); 87 pair.update_slot(target, final_sb); 88 89 Ok(()) 90} 91 92pub fn verify_superblock_crc(sb: &Superblock) -> bool { 93 let buf = superblock_to_bytes(sb); 94 let computed = crc32c(&buf[..SUPERBLOCK_SIZE - 4]); 95 computed == sb.checksum 96} 97 98fn read_raw_superblock(bio: &mut BlockIo, slot: u64) -> Result<Superblock, FsError> { 99 let mut buf = [0u8; SUPERBLOCK_SIZE]; 100 bio.read_blocks(slot, 1, &mut buf)?; 101 Ok(superblock_from_bytes(&buf)) 102} 103 104fn validate_one(sb: Superblock) -> Option<Superblock> { 105 match sb.is_valid_magic() && verify_superblock_crc(&sb) { 106 true => Some(sb), 107 false => None, 108 } 109} 110 111pub fn load_validated_superblock_pair(bio: &mut BlockIo) -> Result<SuperblockPair, FsError> { 112 let sb_a = read_raw_superblock(bio, 0).ok().and_then(validate_one); 113 let sb_b = read_raw_superblock(bio, 1).ok().and_then(validate_one); 114 115 match (sb_a, sb_b) { 116 (Some(a), Some(b)) => Ok(SuperblockPair::load(a, b)), 117 (Some(a), None) => { 118 let clone = superblock_from_bytes(&superblock_to_bytes(&a)); 119 Ok(SuperblockPair::load(a, clone)) 120 } 121 (None, Some(b)) => { 122 let clone = superblock_from_bytes(&superblock_to_bytes(&b)); 123 Ok(SuperblockPair::load(clone, b)) 124 } 125 (None, None) => Err(FsError::CorruptSuperblock), 126 } 127}