瀏覽代碼

refactor: block group descriptor

liujingx 11 月之前
父節點
當前提交
59b26a7c9e
共有 9 個文件被更改,包括 224 次插入232 次删除
  1. 23 25
      src/ext4/alloc.rs
  2. 5 5
      src/ext4/dir.rs
  3. 1 1
      src/ext4/extent.rs
  4. 7 7
      src/ext4/file.rs
  5. 29 15
      src/ext4/mod.rs
  6. 1 1
      src/ext4_defs/block_device.rs
  7. 98 101
      src/ext4_defs/block_group.rs
  8. 58 76
      src/ext4_defs/inode.rs
  9. 2 1
      src/prelude.rs

+ 23 - 25
src/ext4/alloc.rs

@@ -10,15 +10,14 @@ impl Ext4 {
         inode_ref: &mut InodeRef,
         goal: PBlockId,
     ) -> Result<PBlockId> {
-        let bgid = goal / self.super_block.blocks_per_group() as u64;
+        let bgid = (goal / self.super_block.blocks_per_group() as u64) as BlockGroupId;
         let idx_in_bg = goal % self.super_block.blocks_per_group() as u64;
 
         // Load block group descriptor
-        let mut bg =
-            BlockGroupDesc::load(self.block_device.clone(), &self.super_block, bgid as usize);
+        let mut bg = self.read_block_group(bgid);
 
         // Load block bitmap
-        let bitmap_block_id = bg.get_block_bitmap_block(&self.super_block);
+        let bitmap_block_id = bg.desc.block_bitmap_block(&self.super_block);
         let mut bitmap_block = self.block_device.read_block(bitmap_block_id);
         let mut bitmap = Bitmap::new(&mut bitmap_block.data);
 
@@ -28,7 +27,7 @@ impl Ext4 {
             .ok_or(Ext4Error::new(ErrCode::ENOSPC))? as PBlockId;
 
         // Set block group checksum
-        bg.set_block_bitmap_csum(&self.super_block, &bitmap);
+        bg.desc.set_block_bitmap_csum(&self.super_block, &bitmap);
         self.block_device.write_block(&bitmap_block);
 
         // Update superblock free blocks count
@@ -39,13 +38,13 @@ impl Ext4 {
         // Update inode blocks (different block size!) count
         let inode_blocks = inode_ref.inode.blocks_count();
         inode_ref.inode.set_blocks_count(inode_blocks as u32 + 8); // TODO: why + 8?
-        self.write_back_inode_with_csum(inode_ref);
+        self.write_inode_with_csum(inode_ref);
 
         // Update block group free blocks count
-        let fb_cnt = bg.get_free_blocks_count();
-        bg.set_free_blocks_count(fb_cnt - 1);
+        let fb_cnt = bg.desc.get_free_blocks_count();
+        bg.desc.set_free_blocks_count(fb_cnt - 1);
 
-        bg.sync_to_disk_with_csum(self.block_device.clone(), bgid as usize, &self.super_block);
+        self.write_block_group_with_csum(&mut bg);
 
         info!("Alloc block {} ok", fblock);
         Ok(fblock)
@@ -63,7 +62,7 @@ impl Ext4 {
         let fblock = self.extent_get_pblock_create(inode_ref, iblock, 1)?;
         // Update the inode
         inode_ref.inode.set_size(inode_size + BLOCK_SIZE as u64);
-        self.write_back_inode_with_csum(inode_ref);
+        self.write_inode_with_csum(inode_ref);
         Ok((iblock, fblock))
     }
 
@@ -83,7 +82,7 @@ impl Ext4 {
         self.dir_add_entry(&mut root, &root_self, "..")?;
         root.inode.links_count += 2;
 
-        self.write_back_inode_with_csum(&mut root);
+        self.write_inode_with_csum(&mut root);
         Ok(root)
     }
 
@@ -110,9 +109,9 @@ impl Ext4 {
         let mut inode_ref = InodeRef::new(id, inode);
 
         // Sync the inode to disk
-        self.write_back_inode_with_csum(&mut inode_ref);
+        self.write_inode_with_csum(&mut inode_ref);
 
-        info!("Alloc inode {} ok", inode_ref.inode_id);
+        info!("Alloc inode {} ok", inode_ref.id);
         Ok(inode_ref)
     }
 
@@ -123,16 +122,15 @@ impl Ext4 {
 
         while bgid <= bg_count {
             // Load block group descriptor
-            let mut bg =
-                BlockGroupDesc::load(self.block_device.clone(), &self.super_block, bgid as usize);
+            let mut bg = self.read_block_group(bgid);
             // If there are no free inodes in this block group, try the next one
-            if bg.free_inodes_count() == 0 {
+            if bg.desc.free_inodes_count() == 0 {
                 bgid += 1;
                 continue;
             }
 
             // Load inode bitmap
-            let bitmap_block_id = bg.get_inode_bitmap_block(&self.super_block);
+            let bitmap_block_id = bg.desc.inode_bitmap_block(&self.super_block);
             let mut bitmap_block = self.block_device.read_block(bitmap_block_id);
             let inode_count = self.super_block.inode_count_in_group(bgid) as usize;
             let mut bitmap = Bitmap::new(&mut bitmap_block.data[..inode_count / 8]);
@@ -141,28 +139,28 @@ impl Ext4 {
             let idx_in_bg = bitmap.find_and_set_first_clear_bit(0, inode_count).unwrap() as u32;
 
             // Update bitmap in disk
-            bg.set_inode_bitmap_csum(&self.super_block, &bitmap);
+            bg.desc.set_inode_bitmap_csum(&self.super_block, &bitmap);
             self.block_device.write_block(&bitmap_block);
 
             // Modify filesystem counters
-            let free_inodes = bg.free_inodes_count() - 1;
-            bg.set_free_inodes_count(&self.super_block, free_inodes);
+            let free_inodes = bg.desc.free_inodes_count() - 1;
+            bg.desc.set_free_inodes_count(&self.super_block, free_inodes);
 
             // Increment used directories counter
             if is_dir {
-                let used_dirs = bg.get_used_dirs_count(&self.super_block) - 1;
-                bg.set_used_dirs_count(&self.super_block, used_dirs);
+                let used_dirs = bg.desc.used_dirs_count(&self.super_block) - 1;
+                bg.desc.set_used_dirs_count(&self.super_block, used_dirs);
             }
 
             // Decrease unused inodes count
-            let mut unused = bg.get_itable_unused(&self.super_block);
+            let mut unused = bg.desc.itable_unused(&self.super_block);
             let free = inode_count as u32 - unused;
             if idx_in_bg >= free {
                 unused = inode_count as u32 - (idx_in_bg + 1);
-                bg.set_itable_unused(&self.super_block, unused);
+                bg.desc.set_itable_unused(&self.super_block, unused);
             }
 
-            bg.sync_to_disk_with_csum(self.block_device.clone(), bgid as usize, &self.super_block);
+            self.write_block_group_with_csum(&mut bg);
 
             // Update superblock
             self.super_block.decrease_free_inodes_count();

+ 5 - 5
src/ext4/dir.rs

@@ -6,7 +6,7 @@ use crate::prelude::*;
 impl Ext4 {
     /// Find a directory entry that matches a given name under a parent directory
     pub(super) fn dir_find_entry(&self, parent: &InodeRef, name: &str) -> Result<DirEntry> {
-        info!("Dir find entry: {} under parent {}", name, parent.inode_id);
+        info!("Dir find entry: {} under parent {}", name, parent.id);
         let inode_size: u32 = parent.inode.size;
         let total_blocks: u32 = inode_size / BLOCK_SIZE as u32;
         let mut iblock: LBlockId = 0;
@@ -54,7 +54,7 @@ impl Ext4 {
     ) -> Result<()> {
         info!(
             "Dir add entry: parent {}, child {}, path {}",
-            parent.inode_id, child.inode_id, path
+            parent.id, child.id, path
         );
         let inode_size = parent.inode.size();
         let total_blocks = inode_size as u32 / BLOCK_SIZE as u32;
@@ -92,7 +92,7 @@ impl Ext4 {
         // Set the entry
         let rec_len = BLOCK_SIZE - size_of::<DirEntryTail>();
         let new_entry = DirEntry::new(
-            child.inode_id,
+            child.id,
             rec_len as u16,
             name,
             inode_mode2file_type(child.inode.mode()),
@@ -148,7 +148,7 @@ impl Ext4 {
             de.copy_to_byte_slice(&mut dst_blk.data, offset);
             // Insert the new entry
             let new_entry = DirEntry::new(
-                child.inode_id,
+                child.id,
                 free_size as u16,
                 name,
                 inode_mode2file_type(child.inode.mode()),
@@ -178,7 +178,7 @@ impl Ext4 {
             path,
             iflags,
             FileType::Directory,
-            &self.get_root_inode_ref(),
+            &self.read_root_inode(),
         )
         .map(|_| {
             info!("ext4_dir_mk: {} ok", path);

+ 1 - 1
src/ext4/extent.rs

@@ -163,7 +163,7 @@ impl Ext4 {
         if block_data.block_id != 0 {
             block_data.sync_to_disk(self.block_device.clone());
         } else {
-            self.write_back_inode_without_csum(inode_ref);
+            self.write_inode_without_csum(inode_ref);
         }
 
         split

+ 7 - 7
src/ext4/file.rs

@@ -27,7 +27,7 @@ impl Ext4 {
             let res = self.dir_find_entry(&parent, path);
             match res {
                 Ok(entry) => {
-                    parent = self.get_inode_ref(entry.inode());
+                    parent = self.read_inode(entry.inode());
                 }
                 Err(e) => {
                     if e.code() != ErrCode::ENOENT {
@@ -47,14 +47,14 @@ impl Ext4 {
                     self.link(&mut parent, &mut child, path)
                         .map_err(|_| Ext4Error::with_message(ErrCode::ELINKFIAL, "link fail"))?;
                     // Write back parent and child
-                    self.write_back_inode_with_csum(&mut parent);
-                    self.write_back_inode_with_csum(&mut child);
+                    self.write_inode_with_csum(&mut parent);
+                    self.write_inode_with_csum(&mut child);
                 }
             }
         }
         // Reach the target
         let mut file = File::default();
-        file.inode = parent.inode_id;
+        file.inode = parent.id;
         Ok(file)
     }
 
@@ -72,7 +72,7 @@ impl Ext4 {
             self.trans_start();
         }
         // open file
-        let res = self.generic_open(path, iflags, file_type, &self.get_root_inode_ref());
+        let res = self.generic_open(path, iflags, file_type, &self.read_root_inode());
         res.map(|mut file| {
             // set mount point
             let mut ptr = Box::new(self.mount_point.clone());
@@ -87,7 +87,7 @@ impl Ext4 {
             return Ok(0);
         }
         // Get the inode of the file
-        let mut inode_ref = self.get_inode_ref(file.inode);
+        let mut inode_ref = self.read_inode(file.inode);
         // sync file size
         file.fsize = inode_ref.inode.size();
 
@@ -135,7 +135,7 @@ impl Ext4 {
 
     pub fn write(&mut self, file: &mut File, data: &[u8]) -> Result<()> {
         let size = data.len();
-        let mut inode_ref = self.get_inode_ref(file.inode);
+        let mut inode_ref = self.read_inode(file.inode);
         // Sync ext file
         file.fsize = inode_ref.inode.size();
 

+ 29 - 15
src/ext4/mod.rs

@@ -39,27 +39,41 @@ impl Ext4 {
         Ok(ext4)
     }
 
-    /// Read an inode from block device, return an `InodeRef` that combines
-    /// the inode and its id.
-    fn get_inode_ref(&self, inode_id: InodeId) -> InodeRef {
-        InodeRef::read_from_disk(self.block_device.clone(), &self.super_block, inode_id)
+    /// Read an inode from block device, return an `InodeRef` that
+    /// combines the inode and its id.
+    fn read_inode(&self, inode_id: InodeId) -> InodeRef {
+        InodeRef::load_from_disk(self.block_device.clone(), &self.super_block, inode_id)
     }
 
     /// Read the root inode from block device
-    fn get_root_inode_ref(&self) -> InodeRef {
-        self.get_inode_ref(EXT4_ROOT_INO)
+    fn read_root_inode(&self) -> InodeRef {
+        self.read_inode(EXT4_ROOT_INO)
     }
 
-    /// Write back an inode to block device with checksum
-    fn write_back_inode_with_csum(&self, inode_ref: &mut InodeRef) {
-        inode_ref
-            .sync_to_disk_with_csum(self.block_device.clone(), &self.super_block)
-            
+    /// Write an inode to block device with checksum
+    fn write_inode_with_csum(&self, inode_ref: &mut InodeRef) {
+        inode_ref.sync_to_disk_with_csum(self.block_device.clone(), &self.super_block)
     }
 
-    /// Write back an inode to block device without checksum
-    fn write_back_inode_without_csum(&self, inode_ref: &mut InodeRef) {
-        inode_ref
-            .sync_to_disk_without_csum(self.block_device.clone(), &self.super_block)
+    /// Write an inode to block device without checksum
+    fn write_inode_without_csum(&self, inode_ref: &mut InodeRef) {
+        inode_ref.sync_to_disk_without_csum(self.block_device.clone(), &self.super_block)
+    }
+
+    /// Read a block group descriptor from block device, return an `BlockGroupRef`
+    /// that combines the inode and its id.
+    fn read_block_group(&self, block_group_id: BlockGroupId) -> BlockGroupRef {
+        BlockGroupRef::load_from_disk(self.block_device.clone(), &self.super_block, block_group_id)
+    }
+
+    /// Write a block group descriptor to block device with checksum
+    fn write_block_group_with_csum(&self, bg_ref: &mut BlockGroupRef) {
+        bg_ref.sync_to_disk_with_csum(self.block_device.clone(), &self.super_block)
+    }
+
+    /// Write a block group descriptor to block device without checksum
+    #[allow(unused)]
+    fn write_block_group_without_csum(&self, bg_ref: &mut BlockGroupRef) {
+        bg_ref.sync_to_disk_without_csum(self.block_device.clone(), &self.super_block)
     }
 }

+ 1 - 1
src/ext4_defs/block_device.rs

@@ -18,7 +18,7 @@ where
     }
 }
 
-/// Block descriptor
+/// Common data block descriptor
 pub struct Block {
     /// Physical block id
     pub block_id: PBlockId,

+ 98 - 101
src/ext4_defs/block_group.rs

@@ -47,41 +47,23 @@ pub struct BlockGroupDesc {
 impl AsBytes for BlockGroupDesc {}
 
 impl BlockGroupDesc {
-    pub fn load(
-        block_device: Arc<dyn BlockDevice>,
-        super_block: &Superblock,
-        block_group_id: usize,
-    ) -> Self {
-        let dsc_cnt = BLOCK_SIZE / super_block.desc_size() as usize;
-        let dsc_id = block_group_id / dsc_cnt;
-        let first_data_block = super_block.first_data_block();
-
-        let block_id = first_data_block as usize + dsc_id + 1;
-        let offset = (block_group_id % dsc_cnt) * super_block.desc_size() as usize;
-
-        let block = block_device.read_block(block_id as PBlockId);
-        block.read_offset_as::<Self>(offset)
-    }
-
-    pub fn get_block_bitmap_block(&self, s: &Superblock) -> u64 {
+    pub fn block_bitmap_block(&self, s: &Superblock) -> PBlockId {
         let mut v = self.block_bitmap_lo as u64;
-        let desc_size = s.desc_size();
-        if desc_size > EXT4_MIN_BLOCK_GROUP_DESCRIPTOR_SIZE {
+        if s.desc_size() > EXT4_MIN_BLOCK_GROUP_DESCRIPTOR_SIZE {
             v |= (self.block_bitmap_hi as u64) << 32;
         }
         v
     }
 
-    pub fn get_inode_bitmap_block(&self, s: &Superblock) -> u64 {
+    pub fn inode_bitmap_block(&self, s: &Superblock) -> PBlockId {
         let mut v = self.inode_bitmap_lo as u64;
-        let desc_size = s.desc_size();
-        if desc_size > EXT4_MIN_BLOCK_GROUP_DESCRIPTOR_SIZE {
+        if s.desc_size() > EXT4_MIN_BLOCK_GROUP_DESCRIPTOR_SIZE {
             v |= (self.inode_bitmap_hi as u64) << 32;
         }
         v
     }
 
-    pub fn get_itable_unused(&mut self, s: &Superblock) -> u32 {
+    pub fn itable_unused(&mut self, s: &Superblock) -> u32 {
         let mut v = self.itable_unused_lo as u32;
         if s.desc_size() > EXT4_MIN_BLOCK_GROUP_DESCRIPTOR_SIZE {
             v |= ((self.itable_unused_hi as u64) << 32) as u32;
@@ -89,7 +71,7 @@ impl BlockGroupDesc {
         v
     }
 
-    pub fn get_used_dirs_count(&self, s: &Superblock) -> u32 {
+    pub fn used_dirs_count(&self, s: &Superblock) -> u32 {
         let mut v = self.used_dirs_count_lo as u32;
         if s.desc_size() > EXT4_MIN_BLOCK_GROUP_DESCRIPTOR_SIZE {
             v |= ((self.used_dirs_count_hi as u64) << 32) as u32;
@@ -122,72 +104,37 @@ impl BlockGroupDesc {
         ((self.free_inodes_count_hi as u32) << 16) | self.free_inodes_count_lo as u32
     }
 
-    pub fn inode_table_first_block(&self) -> u64 {
+    pub fn inode_table_first_block(&self) -> PBlockId {
         ((self.inode_table_first_block_hi as u64) << 32) | self.inode_table_first_block_lo as u64
     }
 
-    pub fn sync_to_disk(
-        &self,
-        block_device: Arc<dyn BlockDevice>,
-        bgid: usize,
-        super_block: &Superblock,
-    ) {
-        let dsc_cnt = BLOCK_SIZE / super_block.desc_size() as usize;
-        let dsc_id = bgid / dsc_cnt;
-        let first_data_block = super_block.first_data_block();
-        let block_id = first_data_block as usize + dsc_id + 1;
-        let offset = (bgid % dsc_cnt) * super_block.desc_size() as usize;
-
-        let mut block = block_device.read_block(block_id as PBlockId);
-        block.write_offset_as(offset, self);
-        block.sync_to_disk(block_device);
+    pub fn get_free_blocks_count(&self) -> u64 {
+        let mut v = self.free_blocks_count_lo as u64;
+        if self.free_blocks_count_hi != 0 {
+            v |= (self.free_blocks_count_hi as u64) << 32;
+        }
+        v
     }
 
-    pub fn calc_checksum(&mut self, bgid: u32, super_block: &Superblock) -> u16 {
-        let desc_size = super_block.desc_size();
-
-        let orig_checksum = self.checksum;
-
-        // 准备:暂时将bg校验和设为0
-        self.checksum = 0;
-
-        // uuid checksum
-        let mut checksum = ext4_crc32c(
-            EXT4_CRC32_INIT,
-            &super_block.uuid(),
-            super_block.uuid().len() as u32,
-        );
-
-        // bgid checksum
-        checksum = ext4_crc32c(checksum, &bgid.to_le_bytes(), 4);
-
-        // cast self to &[u8]
-        let self_bytes =
-            unsafe { core::slice::from_raw_parts(self as *const _ as *const u8, 0x40 as usize) };
-
-        // bg checksum
-        checksum = ext4_crc32c(checksum, self_bytes, desc_size as u32);
-
-        self.checksum = orig_checksum;
-
-        let crc = (checksum & 0xFFFF) as u16;
-
-        crc
+    pub fn set_free_blocks_count(&mut self, cnt: u64) {
+        self.free_blocks_count_lo = ((cnt << 32) >> 32) as u16;
+        self.free_blocks_count_hi = (cnt >> 32) as u16;
     }
 
-    pub fn set_block_group_checksum(&mut self, bgid: u32, super_block: &Superblock) {
-        let csum = self.calc_checksum(bgid, super_block);
-        self.checksum = csum;
+    pub fn calc_inode_bitmap_csum(bitmap: &Bitmap, s: &Superblock) -> u32 {
+        let inodes_per_group = s.inodes_per_group();
+        let uuid = s.uuid();
+        let mut csum = ext4_crc32c(EXT4_CRC32_INIT, &uuid, uuid.len() as u32);
+        csum = ext4_crc32c(csum, bitmap.as_raw(), (inodes_per_group + 7) / 8);
+        csum
     }
 
-    pub fn sync_to_disk_with_csum(
-        &mut self,
-        block_device: Arc<dyn BlockDevice>,
-        bgid: usize,
-        super_block: &Superblock,
-    ) {
-        self.set_block_group_checksum(bgid as u32, super_block);
-        self.sync_to_disk(block_device, bgid, super_block)
+    pub fn calc_block_bitmap_csum(bitmap: &Bitmap, s: &Superblock) -> u32 {
+        let blocks_per_group = s.blocks_per_group();
+        let uuid = s.uuid();
+        let mut csum = ext4_crc32c(EXT4_CRC32_INIT, &uuid, uuid.len() as u32);
+        csum = ext4_crc32c(csum, bitmap.as_raw(), (blocks_per_group / 8) as u32);
+        csum
     }
 
     pub fn set_inode_bitmap_csum(&mut self, s: &Superblock, bitmap: &Bitmap) {
@@ -221,33 +168,83 @@ impl BlockGroupDesc {
             self.block_bitmap_csum_hi = hi_csum as u16;
         }
     }
+}
 
-    pub fn get_free_blocks_count(&self) -> u64 {
-        let mut v = self.free_blocks_count_lo as u64;
-        if self.free_blocks_count_hi != 0 {
-            v |= (self.free_blocks_count_hi as u64) << 32;
+/// A combination of a `BlockGroupDesc` and its id
+#[derive(Debug)]
+pub struct BlockGroupRef {
+    /// The block group id
+    pub id: BlockGroupId,
+    /// The block group descriptor
+    pub desc: BlockGroupDesc,
+}
+
+impl BlockGroupRef {
+    /// Load a block group descriptor from the disk
+    pub fn load_from_disk(
+        block_device: Arc<dyn BlockDevice>,
+        super_block: &Superblock,
+        block_group_id: BlockGroupId,
+    ) -> Self {
+        let (block_id, offset) = Self::disk_pos(super_block, block_group_id);
+        let block = block_device.read_block(block_id as PBlockId);
+        let desc = block.read_offset_as::<BlockGroupDesc>(offset);
+        Self {
+            id: block_group_id,
+            desc,
         }
-        v
     }
 
-    pub fn set_free_blocks_count(&mut self, cnt: u64) {
-        self.free_blocks_count_lo = ((cnt << 32) >> 32) as u16;
-        self.free_blocks_count_hi = (cnt >> 32) as u16;
+    /// Find the position of a block group descriptor in the block device.
+    /// Return the block id and the offset within the block.
+    fn disk_pos(s: &Superblock, block_group_id: BlockGroupId) -> (PBlockId, usize) {
+        let desc_per_block = BLOCK_SIZE as u32 / s.desc_size() as u32;
+        let block_id = s.first_data_block() + block_group_id / desc_per_block + 1;
+        let offset = (block_group_id % desc_per_block) * s.desc_size() as u32;
+        (block_id as PBlockId, offset as usize)
     }
 
-    pub fn calc_inode_bitmap_csum(bitmap: &Bitmap, s: &Superblock) -> u32 {
-        let inodes_per_group = s.inodes_per_group();
-        let uuid = s.uuid();
-        let mut csum = ext4_crc32c(EXT4_CRC32_INIT, &uuid, uuid.len() as u32);
-        csum = ext4_crc32c(csum, bitmap.as_raw(), (inodes_per_group + 7) / 8);
-        csum
+    pub fn sync_to_disk_without_csum(
+        &self,
+        block_device: Arc<dyn BlockDevice>,
+        super_block: &Superblock,
+    ) {
+        let (block_id, offset) = Self::disk_pos(super_block, self.id);
+        let mut block = block_device.read_block(block_id as PBlockId);
+        block.write_offset_as(offset, &self.desc);
+        block.sync_to_disk(block_device);
     }
 
-    pub fn calc_block_bitmap_csum(bitmap: &Bitmap, s: &Superblock) -> u32 {
-        let blocks_per_group = s.blocks_per_group();
-        let uuid = s.uuid();
-        let mut csum = ext4_crc32c(EXT4_CRC32_INIT, &uuid, uuid.len() as u32);
-        csum = ext4_crc32c(csum, bitmap.as_raw(), (blocks_per_group / 8) as u32);
-        csum
+    pub fn sync_to_disk_with_csum(
+        &mut self,
+        block_device: Arc<dyn BlockDevice>,
+        super_block: &Superblock,
+    ) {
+        self.set_checksum(super_block);
+        self.sync_to_disk_without_csum(block_device, super_block);
+    }
+
+    pub fn set_checksum(&mut self, super_block: &Superblock) {
+        let desc_size = super_block.desc_size();
+
+        // uuid checksum
+        let mut checksum = ext4_crc32c(
+            EXT4_CRC32_INIT,
+            &super_block.uuid(),
+            super_block.uuid().len() as u32,
+        );
+
+        // bgid checksum
+        checksum = ext4_crc32c(checksum, &self.id.to_le_bytes(), 4);
+
+        // cast self to &[u8]
+        let self_bytes =
+            unsafe { core::slice::from_raw_parts(self as *const _ as *const u8, 0x40 as usize) };
+
+        // bg checksum
+        checksum = ext4_crc32c(checksum, self_bytes, desc_size as u32);
+
+        let crc = (checksum & 0xFFFF) as u16;
+        self.desc.checksum = crc;
     }
 }

+ 58 - 76
src/ext4_defs/inode.rs

@@ -8,14 +8,14 @@
 //! `(inode_number - 1) % sb.inodes_per_group`. There is no inode 0.
 
 use super::crc::*;
+use super::AsBytes;
 use super::BlockDevice;
-use super::BlockGroupDesc;
+use super::BlockGroupRef;
 use super::ExtentHeader;
 use super::Superblock;
 use super::{ExtentNode, ExtentNodeMut};
 use crate::constants::*;
 use crate::prelude::*;
-use crate::AsBytes;
 
 #[repr(C)]
 #[derive(Debug, Clone, Copy, Default, PartialEq, Eq)]
@@ -149,6 +149,14 @@ impl Inode {
         self.dtime = del_time;
     }
 
+    pub fn blocks_count(&self) -> u64 {
+        let mut blocks = self.blocks as u64;
+        if self.osd2.l_i_blocks_high != 0 {
+            blocks |= (self.osd2.l_i_blocks_high as u64) << 32;
+        }
+        blocks
+    }
+
     pub fn set_blocks_count(&mut self, blocks_count: u32) {
         self.blocks = blocks_count;
     }
@@ -161,23 +169,6 @@ impl Inode {
         self.i_extra_isize = extra_isize;
     }
 
-    pub fn set_inode_checksum_value(&mut self, super_block: &Superblock, checksum: u32) {
-        let inode_size = super_block.inode_size();
-
-        self.osd2.l_i_checksum_lo = ((checksum << 16) >> 16) as u16;
-        if inode_size > 128 {
-            self.i_checksum_hi = (checksum >> 16) as u16;
-        }
-    }
-
-    pub fn blocks_count(&self) -> u64 {
-        let mut blocks = self.blocks as u64;
-        if self.osd2.l_i_blocks_high != 0 {
-            blocks |= (self.osd2.l_i_blocks_high as u64) << 32;
-        }
-        blocks
-    }
-
     fn copy_to_byte_slice(&self, slice: &mut [u8]) {
         unsafe {
             let inode_ptr = self as *const Inode as *const u8;
@@ -186,49 +177,6 @@ impl Inode {
         }
     }
 
-    fn calc_checksum(&mut self, inode_id: u32, super_block: &Superblock) -> u32 {
-        let inode_size = super_block.inode_size();
-
-        let ino_index = inode_id as u32;
-        let ino_gen = self.generation;
-
-        // Preparation: temporarily set bg checksum to 0
-        self.osd2.l_i_checksum_lo = 0;
-        self.i_checksum_hi = 0;
-
-        let mut checksum = ext4_crc32c(
-            EXT4_CRC32_INIT,
-            &super_block.uuid(),
-            super_block.uuid().len() as u32,
-        );
-        checksum = ext4_crc32c(checksum, &ino_index.to_le_bytes(), 4);
-        checksum = ext4_crc32c(checksum, &ino_gen.to_le_bytes(), 4);
-
-        let mut raw_data = [0u8; 0x100];
-        self.copy_to_byte_slice(&mut raw_data);
-
-        // inode checksum
-        checksum = ext4_crc32c(checksum, &raw_data, inode_size as u32);
-
-        self.set_inode_checksum_value(super_block, checksum);
-
-        if inode_size == 128 {
-            checksum &= 0xFFFF;
-        }
-
-        checksum
-    }
-
-    fn set_checksum(&mut self, super_block: &Superblock, inode_id: u32) {
-        let inode_size = super_block.inode_size();
-        let checksum = self.calc_checksum(inode_id, super_block);
-
-        self.osd2.l_i_checksum_lo = ((checksum << 16) >> 16) as u16;
-        if inode_size > 128 {
-            self.i_checksum_hi = (checksum >> 16) as u16;
-        }
-    }
-
     /* Extent methods */
 
     /// Get the immutable extent root node
@@ -262,24 +210,24 @@ impl Inode {
 /// A combination of an `Inode` and its id
 #[derive(Clone)]
 pub struct InodeRef {
-    pub inode_id: InodeId,
+    pub id: InodeId,
     pub inode: Inode,
 }
 
 impl InodeRef {
-    pub fn new(inode_id: InodeId, inode: Inode) -> Self {
-        Self { inode_id, inode }
+    pub fn new(id: InodeId, inode: Inode) -> Self {
+        Self { id, inode }
     }
 
-    pub fn read_from_disk(
+    pub fn load_from_disk(
         block_device: Arc<dyn BlockDevice>,
         super_block: &Superblock,
-        inode_id: InodeId,
+        id: InodeId,
     ) -> Self {
-        let (block_id, offset) = Self::inode_disk_pos(super_block, block_device.clone(), inode_id);
+        let (block_id, offset) = Self::disk_pos(super_block, block_device.clone(), id);
         let block = block_device.read_block(block_id);
         Self {
-            inode_id,
+            id,
             inode: Inode::from_bytes(block.read_offset(offset, size_of::<Inode>())),
         }
     }
@@ -296,18 +244,19 @@ impl InodeRef {
     /// inode table at `index = (inode_id - 1) % sb.inodes_per_group`.
     /// To get the byte address within the inode table, use
     /// `offset = index * sb.inode_size`.
-    fn inode_disk_pos(
+    fn disk_pos(
         super_block: &Superblock,
         block_device: Arc<dyn BlockDevice>,
         inode_id: InodeId,
     ) -> (PBlockId, usize) {
         let inodes_per_group = super_block.inodes_per_group();
+        let group = ((inode_id - 1) / inodes_per_group) as BlockGroupId;
         let inode_size = super_block.inode_size() as usize;
-        let group = ((inode_id - 1) / inodes_per_group) as usize;
         let index = ((inode_id - 1) % inodes_per_group) as usize;
 
-        let bg = BlockGroupDesc::load(block_device, super_block, group);
-        let block_id = bg.inode_table_first_block() + (index * inode_size / BLOCK_SIZE) as PBlockId;
+        let bg = BlockGroupRef::load_from_disk(block_device, super_block, group);
+        let block_id =
+            bg.desc.inode_table_first_block() + (index * inode_size / BLOCK_SIZE) as PBlockId;
         let offset = (index * inode_size) % BLOCK_SIZE;
         (block_id, offset)
     }
@@ -317,8 +266,7 @@ impl InodeRef {
         block_device: Arc<dyn BlockDevice>,
         super_block: &Superblock,
     ) {
-        let (block_id, offset) =
-            Self::inode_disk_pos(super_block, block_device.clone(), self.inode_id);
+        let (block_id, offset) = Self::disk_pos(super_block, block_device.clone(), self.id);
         let mut block = block_device.read_block(block_id);
         block.write_offset_as(offset, &self.inode);
         block.sync_to_disk(block_device);
@@ -329,7 +277,41 @@ impl InodeRef {
         block_device: Arc<dyn BlockDevice>,
         super_block: &Superblock,
     ) {
-        self.inode.set_checksum(super_block, self.inode_id);
+        self.set_checksum(super_block);
         self.sync_to_disk_without_csum(block_device, super_block);
     }
+
+    pub fn set_checksum(&mut self, super_block: &Superblock) {
+        let inode_size = super_block.inode_size();
+
+        let ino_index = self.id as u32;
+        let ino_gen = self.inode.generation;
+
+        // Preparation: temporarily set bg checksum to 0
+        self.inode.osd2.l_i_checksum_lo = 0;
+        self.inode.i_checksum_hi = 0;
+
+        let mut checksum = ext4_crc32c(
+            EXT4_CRC32_INIT,
+            &super_block.uuid(),
+            super_block.uuid().len() as u32,
+        );
+        checksum = ext4_crc32c(checksum, &ino_index.to_le_bytes(), 4);
+        checksum = ext4_crc32c(checksum, &ino_gen.to_le_bytes(), 4);
+
+        let mut raw_data = [0u8; 0x100];
+        self.inode.copy_to_byte_slice(&mut raw_data);
+
+        // inode checksum
+        checksum = ext4_crc32c(checksum, &raw_data, inode_size as u32);
+
+        if inode_size == 128 {
+            checksum &= 0xFFFF;
+        }
+
+        self.inode.osd2.l_i_checksum_lo = ((checksum << 16) >> 16) as u16;
+        if super_block.inode_size() > 128 {
+            self.inode.i_checksum_hi = (checksum >> 16) as u16;
+        }
+    }
 }

+ 2 - 1
src/prelude.rs

@@ -30,4 +30,5 @@ pub(crate) type Result<T> = core::result::Result<T, Ext4Error>;
 
 pub(crate) type LBlockId = u32;
 pub(crate) type PBlockId = u64;
-pub(crate) type InodeId = u32;
+pub(crate) type InodeId = u32;
+pub(crate) type BlockGroupId = u32;