瀏覽代碼

refactor: checksum and rw

liujingx 10 月之前
父節點
當前提交
c8c5b09e6c
共有 8 個文件被更改,包括 204 次插入258 次删除
  1. 29 9
      src/ext4/dir.rs
  2. 78 23
      src/ext4/rw.rs
  3. 3 3
      src/ext4_defs/bitmap.rs
  4. 10 20
      src/ext4_defs/crc.rs
  5. 24 28
      src/ext4_defs/dir_entry.rs
  6. 0 8
      src/ext4_defs/file.rs
  7. 42 126
      src/ext4_defs/inode.rs
  8. 18 41
      src/ext4_defs/super_block.rs

+ 29 - 9
src/ext4/dir.rs

@@ -53,7 +53,7 @@ impl Ext4 {
             // Load the parent block from disk
             let mut block = self.read_block(fblock);
             // Try inserting the entry to parent block
-            if self.insert_entry_to_old_block(&mut block, child, name) {
+            if self.insert_entry_to_old_block(dir, child, name, &mut block) {
                 return Ok(());
             }
             // Current block has no enough space
@@ -66,7 +66,7 @@ impl Ext4 {
         // Load new block
         let mut new_block = self.read_block(fblock);
         // Write the entry to block
-        self.insert_entry_to_new_block(&mut new_block, child, name);
+        self.insert_entry_to_new_block(dir, child, name, &mut new_block);
         // Update inode size
         dir.inode.set_size(dir.inode.size() + BLOCK_SIZE as u64);
 
@@ -162,7 +162,13 @@ impl Ext4 {
 
     /// Insert a directory entry of a child inode into a new parent block.
     /// A new block must have enough space
-    fn insert_entry_to_new_block(&self, dst_blk: &mut Block, child: &InodeRef, name: &str) {
+    fn insert_entry_to_new_block(
+        &self,
+        dir: &InodeRef,
+        child: &InodeRef,
+        name: &str,
+        dst_blk: &mut Block,
+    ) {
         // Set the entry
         let rec_len = BLOCK_SIZE - size_of::<DirEntryTail>();
         let new_entry = DirEntry::new(child.id, rec_len as u16, name, child.inode.file_type());
@@ -170,10 +176,13 @@ impl Ext4 {
         dst_blk.write_offset_as(0, &new_entry);
 
         // Set tail
-        let mut tail = DirEntryTail::default();
-        tail.rec_len = size_of::<DirEntryTail>() as u16;
-        tail.reserved_ft = 0xDE;
-        tail.set_csum(&self.read_super_block(), &new_entry, &dst_blk.data[..]);
+        let mut tail = DirEntryTail::new();
+        tail.set_csum(
+            &self.read_super_block().uuid(),
+            dir.id,
+            dir.inode.generation(),
+            &dst_blk,
+        );
         // Copy tail to block
         let tail_offset = BLOCK_SIZE - size_of::<DirEntryTail>();
         dst_blk.write_offset_as(tail_offset, &tail);
@@ -184,7 +193,13 @@ impl Ext4 {
 
     /// Try insert a directory entry of child inode into a parent block.
     /// Return true if the entry is successfully inserted.
-    fn insert_entry_to_old_block(&self, dst_blk: &mut Block, child: &InodeRef, name: &str) -> bool {
+    fn insert_entry_to_old_block(
+        &self,
+        dir: &InodeRef,
+        child: &InodeRef,
+        name: &str,
+        dst_blk: &mut Block,
+    ) -> bool {
         let required_size = DirEntry::required_size(name.len());
         let mut offset = 0;
 
@@ -216,7 +231,12 @@ impl Ext4 {
             // Set tail csum
             let tail_offset = BLOCK_SIZE - size_of::<DirEntryTail>();
             let mut tail = dst_blk.read_offset_as::<DirEntryTail>(tail_offset);
-            tail.set_csum(&self.read_super_block(), &de, &dst_blk.data[offset..]);
+            tail.set_csum(
+                &self.read_super_block().uuid(),
+                dir.id,
+                dir.inode.generation(),
+                &dst_blk,
+            );
             // Write tail to blk_data
             dst_blk.write_offset_as(tail_offset, &tail);
 

+ 78 - 23
src/ext4/rw.rs

@@ -5,17 +5,6 @@ use crate::prelude::*;
 use super::Ext4;
 
 impl Ext4 {
-    /// Read super block from block device
-    #[allow(unused)]
-    pub(super) fn read_super_block(&self) -> SuperBlock {
-        SuperBlock::load_from_disk(self.block_device.as_ref())
-    }
-
-    /// Write super block to block device
-    pub(super) fn write_super_block(&self, sb: &SuperBlock) {
-        sb.sync_to_disk(self.block_device.as_ref());
-    }
-
     /// Read a block from block device
     pub(super) fn read_block(&self, block_id: PBlockId) -> Block {
         self.block_device.read_block(block_id)
@@ -26,14 +15,30 @@ impl Ext4 {
         self.block_device.write_block(block)
     }
 
+    /// Read super block from block device
+    #[allow(unused)]
+    pub(super) fn read_super_block(&self) -> SuperBlock {
+        let block = self.read_block(0);
+        block.read_offset_as(BASE_OFFSET)
+    }
+
+    /// Write super block to block device
+    pub(super) fn write_super_block(&self, sb: &SuperBlock) {
+        let mut block = Block::new(0, [0; BLOCK_SIZE]);
+        block.write_offset_as(BASE_OFFSET, sb);
+        self.block_device.write_block(&block)
+    }
+
     /// Read an inode from block device, return an `InodeRef` that
     /// combines the inode and its id.
     pub(super) fn read_inode(&self, inode_id: InodeId) -> InodeRef {
-        InodeRef::load_from_disk(
-            self.block_device.as_ref(),
-            &self.read_super_block(),
-            inode_id,
-        )
+        let (block_id, offset) = self.inode_disk_pos(inode_id);
+        let block = self.read_block(block_id);
+        let inode = InodeRef::new(inode_id, block.read_offset_as(offset));
+        if inode.inode.uid() != 0 {
+            panic!("Inode {:?} has invalid uid", inode);
+        }
+        inode
     }
 
     /// Read the root inode from block device
@@ -44,32 +49,82 @@ impl Ext4 {
 
     /// Write an inode to block device with checksum
     pub(super) fn write_inode_with_csum(&self, inode_ref: &mut InodeRef) {
-        inode_ref.sync_to_disk_with_csum(self.block_device.as_ref(), &self.read_super_block())
+        let super_block = self.read_super_block();
+        inode_ref.set_checksum(&super_block.uuid());
+        self.write_inode_without_csum(inode_ref);
     }
 
     /// Write an inode to block device without checksum
     pub(super) fn write_inode_without_csum(&self, inode_ref: &InodeRef) {
-        inode_ref.sync_to_disk_without_csum(self.block_device.as_ref(), &self.read_super_block())
+        if inode_ref.inode.uid() != 0 {
+            panic!();
+        }
+        let (block_id, offset) = self.inode_disk_pos(inode_ref.id);
+        let mut block = self.read_block(block_id);
+        block.write_offset_as(offset, &inode_ref.inode);
+        self.write_block(&block)
     }
 
     /// Read a block group descriptor from block device, return an `BlockGroupRef`
     /// that combines the block group descriptor and its id.
     pub(super) fn read_block_group(&self, block_group_id: BlockGroupId) -> BlockGroupRef {
-        BlockGroupRef::load_from_disk(
-            self.block_device.as_ref(),
-            &self.read_super_block(),
+        let (block_id, offset) = self.block_group_disk_pos(block_group_id);
+        let block = self.read_block(block_id as PBlockId);
+        BlockGroupRef::new(
             block_group_id,
+            block.read_offset_as::<BlockGroupDesc>(offset),
         )
     }
 
     /// Write a block group descriptor to block device with checksum
     pub(super) fn write_block_group_with_csum(&self, bg_ref: &mut BlockGroupRef) {
-        bg_ref.sync_to_disk_with_csum(self.block_device.as_ref(), &self.read_super_block())
+        let super_block = self.read_super_block();
+        bg_ref.set_checksum(&super_block.uuid());
+        self.write_block_group_without_csum(bg_ref);
     }
 
     /// Write a block group descriptor to block device without checksum
     #[allow(unused)]
     pub(super) fn write_block_group_without_csum(&self, bg_ref: &BlockGroupRef) {
-        bg_ref.sync_to_disk_without_csum(self.block_device.as_ref(), &self.read_super_block())
+        let (block_id, offset) = self.block_group_disk_pos(bg_ref.id);
+        let mut block = self.read_block(block_id as PBlockId);
+        block.write_offset_as(offset, &bg_ref.desc);
+        self.write_block(&block);
+    }
+
+    /// Get disk position of an inode. Return block id and offset within the block.
+    ///
+    /// Each block group contains `sb.inodes_per_group` inodes.
+    /// Because inode 0 is defined not to exist, this formula can
+    /// be used to find the block group that an inode lives in:
+    /// `bg = (inode_id - 1) / sb.inodes_per_group`.
+    ///
+    /// The particular inode can be found within the block group's
+    /// 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(&self, inode_id: InodeId) -> (PBlockId, usize) {
+        let super_block = self.read_super_block();
+        let inodes_per_group = super_block.inodes_per_group();
+
+        let bg_id = ((inode_id - 1) / inodes_per_group) as BlockGroupId;
+        let inode_size = super_block.inode_size() as usize;
+        let bg = self.read_block_group(bg_id);
+        let id_in_bg = ((inode_id - 1) % inodes_per_group) as usize;
+
+        let block_id =
+            bg.desc.inode_table_first_block() + (id_in_bg * inode_size / BLOCK_SIZE) as PBlockId;
+        let offset = (id_in_bg * inode_size) % BLOCK_SIZE;
+        (block_id, offset)
+    }
+
+    /// Get disk position of a block group. Return block id and offset within the block.
+    fn block_group_disk_pos(&self, block_group_id: BlockGroupId) -> (PBlockId, usize) {
+        let super_block = self.read_super_block();
+        let desc_per_block = BLOCK_SIZE as u32 / super_block.desc_size() as u32;
+
+        let block_id = super_block.first_data_block() + block_group_id / desc_per_block + 1;
+        let offset = (block_group_id % desc_per_block) * super_block.desc_size() as u32;
+        (block_id as PBlockId, offset as usize)
     }
 }

+ 3 - 3
src/ext4_defs/bitmap.rs

@@ -1,11 +1,11 @@
 pub struct Bitmap<'a>(&'a mut [u8]);
 
 impl<'a> Bitmap<'a> {
-    pub fn new(bmap: &'a mut [u8]) -> Self {
-        Self(bmap)
+    pub fn new(bmap: &'a mut [u8], nbits: usize) -> Self {
+        Self(&mut bmap[..(nbits + 7) / 8])
     }
 
-    pub fn as_raw(&self) -> &[u8] {
+    pub fn as_bytes(&self) -> &[u8] {
         self.0
     }
 

+ 10 - 20
src/ext4_defs/crc.rs

@@ -50,26 +50,16 @@ const CRC32C_TAB: [u32; 256] = [
     0x79B737BA, 0x8BDCB4B9, 0x988C474D, 0x6AE7C44E, 0xBE2DA0A5, 0x4C4623A6, 0x5F16D052, 0xAD7D5351,
 ];
 
-/// 计算CRC32校验和
-/// 参数 crc 初始值
-/// 参数 buf 缓冲区
-/// 参数 size 缓冲区大小
-/// 参数 tab 查找表
-fn crc32(crc: u32, buf: &[u8], size: u32, tab: &[u32]) -> u32 {
-    let mut crc = crc;
-    let mut p = buf;
-    let mut size = size as usize;
-
-    // 循环更新crc值
-    while size > 0 {
-        crc = tab[(crc as u8 ^ p[0]) as usize] ^ (crc >> 8);
-        p = &p[1..];
-        size -= 1;
+/// Calc CRC32 checksum on a byte slice
+///
+/// # Params
+///
+/// * `crc_init`: initial CRC value
+/// * `data`: data to calculate CRC32 checksum
+pub fn crc32(crc_init: u32, data: &[u8]) -> u32 {
+    let mut crc = crc_init;
+    for byte in data {
+        crc = CRC32C_TAB[(crc as u8 ^ byte) as usize] ^ (crc >> 8);
     }
-
     crc
 }
-
-pub fn ext4_crc32c(crc: u32, buf: &[u8], size: u32) -> u32 {
-    crc32(crc, buf, size, &CRC32C_TAB)
-}

+ 24 - 28
src/ext4_defs/dir_entry.rs

@@ -6,16 +6,16 @@
 use super::crc::*;
 use super::AsBytes;
 use super::FileType;
-use super::SuperBlock;
 use crate::constants::*;
 use crate::format_error;
 use crate::prelude::*;
+use crate::Block;
 
 #[repr(C)]
 #[derive(Clone, Copy)]
 pub union DirEnInner {
-    pub name_length_high: u8, // 高8位的文件名长度
-    pub inode_type: FileType, // 引用的inode的类型(在rev >= 0.5中)
+    name_length_high: u8, // 高8位的文件名长度
+    inode_type: FileType, // 引用的inode的类型(在rev >= 0.5中)
 }
 
 impl Debug for DirEnInner {
@@ -163,40 +163,36 @@ impl DirEntry {
     pub fn used_size(&self) -> usize {
         Self::required_size(self.name_len as usize)
     }
-
-    pub fn calc_csum(&self, s: &SuperBlock, blk_data: &[u8]) -> u32 {
-        let ino_index = self.inode;
-        let ino_gen = 0 as u32;
-
-        let uuid = s.uuid();
-
-        let mut csum = ext4_crc32c(CRC32_INIT, &uuid, uuid.len() as u32);
-        csum = ext4_crc32c(csum, &ino_index.to_le_bytes(), 4);
-        csum = ext4_crc32c(csum, &ino_gen.to_le_bytes(), 4);
-        let mut data = [0u8; 0xff4];
-        unsafe {
-            core::ptr::copy_nonoverlapping(blk_data.as_ptr(), data.as_mut_ptr(), blk_data.len());
-        }
-        csum = ext4_crc32c(csum, &data[..], 0xff4);
-        csum
-    }
 }
 
-#[derive(Debug, Clone, Copy, Default)]
+#[derive(Debug, Clone, Copy)]
 #[repr(C)]
 pub struct DirEntryTail {
-    pub reserved_zero1: u32,
-    pub rec_len: u16,
-    pub reserved_zero2: u8,
-    pub reserved_ft: u8,
-    pub checksum: u32, // crc32c(uuid+inum+dirblock)
+    reserved_zero1: u32,
+    rec_len: u16,
+    reserved_zero2: u8,
+    reserved_ft: u8,
+    checksum: u32, // crc32c(uuid+inum+dirblock)
 }
 
 unsafe impl AsBytes for DirEntryTail {}
 
 impl DirEntryTail {
-    pub fn set_csum(&mut self, s: &SuperBlock, diren: &DirEntry, blk_data: &[u8]) {
-        self.checksum = diren.calc_csum(s, blk_data);
+    pub fn new() -> Self {
+        Self {
+            reserved_zero1: 0,
+            rec_len: 12,
+            reserved_zero2: 0,
+            reserved_ft: 0xDE,
+            checksum: 0,
+        }
+    }
+
+    pub fn set_csum(&mut self, uuid: &[u8], ino: InodeId, ino_gen: u32, block: &Block) {
+        let mut csum = crc32(CRC32_INIT, &uuid);
+        csum = crc32(csum, &ino.to_le_bytes());
+        csum = crc32(csum, &ino_gen.to_le_bytes());
+        self.checksum = crc32(csum, &block.data[..size_of::<DirEntryTail>()]);
     }
 }
 

+ 0 - 8
src/ext4_defs/file.rs

@@ -65,11 +65,3 @@ impl OpenFlags {
         }
     }
 }
-
-#[derive(Copy, PartialEq, Eq, Clone, Debug)]
-#[allow(unused)]
-pub enum SeekFrom {
-    Start(usize),
-    End(isize),
-    Current(isize),
-}

+ 42 - 126
src/ext4_defs/inode.rs

@@ -9,9 +9,6 @@
 
 use super::crc::*;
 use super::AsBytes;
-use super::BlockDevice;
-use super::BlockGroupRef;
-use super::SuperBlock;
 use super::{ExtentNode, ExtentNodeMut};
 use crate::constants::*;
 use crate::prelude::*;
@@ -81,39 +78,33 @@ impl InodeMode {
     }
 }
 
-#[derive(Debug, Clone)]
-pub struct FileAttr {
-    pub ino: InodeId,
-    pub size: u64,
-    pub atime: u32,
-    pub mtime: u32,
-    pub ctime: u32,
-    pub crtime: u32,
-    pub blocks: u64,
-    pub ftype: FileType,
-    pub perm: InodeMode,
-    pub links: u16,
-    pub uid: u32,
-    pub gid: u32,
-}
-
 #[repr(C)]
 #[derive(Debug, Clone)]
 pub struct Linux2 {
     /// Upper 16-bits of the block count. See the note attached to i_blocks_lo.
-    pub l_blocks_hi: u16,
+    l_blocks_hi: u16,
     /// Upper 16-bits of the extended attribute block.
-    pub l_file_acl_hi: u16,
+    l_file_acl_hi: u16,
     /// Upper 16-bits of the Owner UID.
-    pub l_uid_hi: u16,
+    l_uid_hi: u16,
     /// Upper 16-bits of the GID.
-    pub l_gid_hi: u16,
+    l_gid_hi: u16,
     /// Lower 16-bits of the inode checksum.
-    pub l_checksum_lo: u16,
+    l_checksum_lo: u16,
     /// Reserved.
-    pub l_reserved: u16,
+    l_reserved: u16,
 }
 
+/// The I-node Structure.
+///
+/// In ext2 and ext3, the inode structure size was fixed at 128 bytes
+/// (EXT2_GOOD_OLD_INODE_SIZE) and each inode had a disk record size of
+/// 128 bytes. By default, ext4 inode records are 256 bytes, and (as of
+/// October 2013) the inode structure is 156 bytes (i_extra_isize = 28).
+///
+/// We only implement the larger version for simplicity. Guarantee that
+/// `sb.inode_size` equals to 256. This value will be checked when
+/// loading the filesystem.
 #[repr(C)]
 #[derive(Debug, Clone)]
 pub struct Inode {
@@ -303,6 +294,10 @@ impl Inode {
         self.osd2.l_blocks_hi = (cnt >> 32) as u16;
     }
 
+    pub fn generation(&self) -> u32 {
+        self.generation
+    }
+
     pub fn set_generation(&mut self, generation: u32) {
         self.generation = generation;
     }
@@ -315,14 +310,6 @@ impl Inode {
         self.flags |= f;
     }
 
-    fn copy_to_byte_slice(&self, slice: &mut [u8]) {
-        unsafe {
-            let inode_ptr = self as *const Inode as *const u8;
-            let array_ptr = slice.as_ptr() as *mut u8;
-            core::ptr::copy_nonoverlapping(inode_ptr, array_ptr, 0x9c);
-        }
-    }
-
     /* Extent methods */
 
     /// Get the immutable extent root node
@@ -360,99 +347,28 @@ impl InodeRef {
         Self { id, inode }
     }
 
-    pub fn load_from_disk(
-        block_device: &dyn BlockDevice,
-        super_block: &SuperBlock,
-        id: InodeId,
-    ) -> Self {
-        let (block_id, offset) = Self::disk_pos(super_block, block_device, id);
-        let block = block_device.read_block(block_id);
-        Self {
-            id,
-            inode: block.read_offset_as(offset),
-        }
+    pub fn set_checksum(&mut self, uuid: &[u8]) {
+        let mut checksum = crc32(CRC32_INIT, uuid);
+        checksum = crc32(checksum, &self.id.to_le_bytes());
+        checksum = crc32(checksum, &self.inode.generation.to_le_bytes());
+        checksum = crc32(checksum, &self.inode.to_bytes());
+        self.inode.osd2.l_checksum_lo = checksum as u16;
+        self.inode.checksum_hi = (checksum >> 16) as u16;
     }
+}
 
-    pub fn sync_to_disk_without_csum(
-        &self,
-        block_device: &dyn BlockDevice,
-        super_block: &SuperBlock,
-    ) {
-        let (block_id, offset) = Self::disk_pos(super_block, block_device, self.id);
-        let mut block = block_device.read_block(block_id);
-        block.write_offset_as(offset, &self.inode);
-        block_device.write_block(&block)
-    }
-
-    pub fn sync_to_disk_with_csum(
-        &mut self,
-        block_device: &dyn BlockDevice,
-        super_block: &SuperBlock,
-    ) {
-        self.set_checksum(super_block);
-        self.sync_to_disk_without_csum(block_device, super_block);
-    }
-
-    /// Find the position of an inode in the block device. Return the
-    /// block id and the offset within the block.
-    ///
-    /// Each block group contains `sb.inodes_per_group` inodes.
-    /// Because inode 0 is defined not to exist, this formula can
-    /// be used to find the block group that an inode lives in:
-    /// `bg = (inode_id - 1) / sb.inodes_per_group`.
-    ///
-    /// The particular inode can be found within the block group's
-    /// 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 disk_pos(
-        super_block: &SuperBlock,
-        block_device: &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 index = ((inode_id - 1) % inodes_per_group) as usize;
-
-        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)
-    }
-
-    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_checksum_lo = 0;
-        self.inode.checksum_hi = 0;
-
-        let mut checksum = ext4_crc32c(
-            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_checksum_lo = ((checksum << 16) >> 16) as u16;
-        if super_block.inode_size() > 128 {
-            self.inode.checksum_hi = (checksum >> 16) as u16;
-        }
-    }
+#[derive(Debug, Clone)]
+pub struct FileAttr {
+    pub ino: InodeId,
+    pub size: u64,
+    pub atime: u32,
+    pub mtime: u32,
+    pub ctime: u32,
+    pub crtime: u32,
+    pub blocks: u64,
+    pub ftype: FileType,
+    pub perm: InodeMode,
+    pub links: u16,
+    pub uid: u32,
+    pub gid: u32,
 }

+ 18 - 41
src/ext4_defs/super_block.rs

@@ -3,10 +3,7 @@
 //! Super Block is the first field of Ext4 Block Group.
 //!
 //! See [`super::block_group`] for details.
-
 use super::AsBytes;
-use super::BlockDevice;
-use crate::constants::*;
 use crate::prelude::*;
 
 // 结构体表示超级块
@@ -121,17 +118,6 @@ impl SuperBlock {
         self.magic == Self::SB_MAGIC
     }
 
-    pub fn load_from_disk(block_device: &dyn BlockDevice) -> Self {
-        let block = block_device.read_block(0);
-        block.read_offset_as(BASE_OFFSET)
-    }
-
-    pub fn sync_to_disk(&self, block_device: &dyn BlockDevice) {
-        let mut block = block_device.read_block(0);
-        block.write_offset_as(BASE_OFFSET, self);
-        block_device.write_block(&block)
-    }
-
     pub fn first_data_block(&self) -> u32 {
         self.first_data_block
     }
@@ -140,58 +126,49 @@ impl SuperBlock {
         self.free_inode_count
     }
 
-    pub fn features_read_only(&self) -> u32 {
-        self.features_read_only
-    }
-
-    pub fn creator_os(&self) -> u32 {
-        self.creator_os
+    pub fn uuid(&self) -> [u8; 16] {
+        self.uuid
     }
 
-    /// Returns total number of inodes.
+    /// Total number of inodes.
+    #[allow(unused)]
     pub fn inode_count(&self) -> u32 {
         self.inode_count
     }
 
-    /// Returns total number of blocks.
+    /// Total number of blocks.
     pub fn block_count(&self) -> u64 {
         self.block_count_lo as u64 | ((self.block_count_hi as u64) << 32)
     }
 
-    /// Returns the number of blocks in each block group.
+    /// The number of blocks in each block group.
+    #[allow(unused)]
     pub fn blocks_per_group(&self) -> u32 {
         self.blocks_per_group
     }
 
-    /// Returns the size of block.
-    pub fn block_size(&self) -> u32 {
-        1024 << self.log_block_size
-    }
-
-    /// Returns the number of inodes in each block group.
+    /// The number of inodes in each block group.
     pub fn inodes_per_group(&self) -> u32 {
         self.inodes_per_group
     }
 
-    /// Returns the number of block groups.
+    /// The number of block groups.
     pub fn block_group_count(&self) -> u32 {
         ((self.block_count() + self.blocks_per_group as u64 - 1) / self.blocks_per_group as u64)
             as u32
     }
 
-    /// Returns the size of inode structure.
-    pub fn inode_size(&self) -> u16 {
-        self.inode_size
-    }
-
-    pub fn uuid(&self) -> [u8; 16] {
-        self.uuid
+    /// The size of inode.
+    pub fn inode_size(&self) -> usize {
+        self.inode_size as usize
     }
 
-    pub fn desc_size(&self) -> u16 {
-        self.desc_size
+    /// The size of block group descriptor.
+    pub fn desc_size(&self) -> usize {
+        self.desc_size as usize
     }
 
+    #[allow(unused)]
     pub fn extra_size(&self) -> u16 {
         self.want_extra_isize
     }
@@ -206,8 +183,8 @@ impl SuperBlock {
         }
     }
 
-    pub fn decrease_free_inodes_count(&mut self) {
-        self.free_inode_count -= 1;
+    pub fn set_free_inodes_count(&mut self, count: u32) {
+        self.free_inode_count = count;
     }
 
     pub fn free_blocks_count(&self) -> u64 {