Bläddra i källkod

refactor: read write super block and constants

liujingx 10 månader sedan
förälder
incheckning
ac57554303

+ 8 - 13
src/constants.rs

@@ -2,19 +2,8 @@
 
 use crate::prelude::*;
 
-pub const EXT4_INODE_FLAG_EXTENTS: u32 = 0x00080000; /* Inode uses extents */
-pub const EXT4_MIN_BLOCK_GROUP_DESCRIPTOR_SIZE: u16 = 32;
-pub const EXT4_MAX_BLOCK_GROUP_DESCRIPTOR_SIZE: u16 = 64;
-pub const EXT4_CRC32_INIT: u32 = 0xFFFFFFFF;
-pub const EXT4_EXTENT_MAGIC: u16 = 0xF30A;
-pub const EXT_INIT_MAX_LEN: u16 = 32768;
-pub const EXT_UNWRITTEN_MAX_LEN: u16 = 65535;
-
-pub const EXT4_GOOD_OLD_INODE_SIZE: u16 = 128;
-
-pub const EXT_MAX_BLOCKS: LBlockId = core::u32::MAX;
-
-pub const EXT4_SUPERBLOCK_OS_HURD: u32 = 1;
+/// The maximum number of blocks in the file system
+pub const MAX_BLOCKS: LBlockId = LBlockId::MAX;
 
 /// Maximum bytes in a path
 pub const PATH_MAX: usize = 4096;
@@ -28,8 +17,14 @@ pub const SYMLINKS_MAX: usize = 40;
 /// The inode number of root inode
 pub const EXT4_ROOT_INO: InodeId = 1;
 
+/// The base offset of the super block
 pub const BASE_OFFSET: usize = 1024;
+
+/// The size of a block
 pub const BLOCK_SIZE: usize = 4096;
 
 /// For simplicity define this the same as block size
 pub const INODE_BLOCK_SIZE: usize = 4096;
+
+/// CRC32 initial value
+pub const CRC32_INIT: u32 = 0xFFFFFFFF;

+ 58 - 65
src/ext4/alloc.rs

@@ -7,7 +7,7 @@ use crate::return_error;
 
 impl Ext4 {
     /// Create a new inode, returning the inode and its number
-    pub(super) fn create_inode(&mut self, mode: InodeMode) -> Result<InodeRef> {
+    pub(super) fn create_inode(&self, mode: InodeMode) -> Result<InodeRef> {
         // Allocate an inode
         let is_dir = mode.file_type() == FileType::Directory;
         let id = self.alloc_inode(is_dir)?;
@@ -16,9 +16,6 @@ impl Ext4 {
         let mut inode = Inode::default();
         inode.set_mode(mode);
         inode.extent_init();
-        if self.super_block.inode_size() > EXT4_GOOD_OLD_INODE_SIZE {
-            inode.set_extra_isize(self.super_block.extra_size());
-        }
         let mut inode_ref = InodeRef::new(id, inode);
 
         // Sync the inode to disk
@@ -29,16 +26,14 @@ impl Ext4 {
     }
 
     /// Create(initialize) the root inode of the file system
-    pub(super) fn create_root_inode(&mut self) -> Result<InodeRef> {
+    pub(super) fn create_root_inode(&self) -> Result<InodeRef> {
         let mut inode = Inode::default();
         inode.set_mode(InodeMode::from_type_and_perm(
             FileType::Directory,
             InodeMode::ALL_RWX,
         ));
         inode.extent_init();
-        if self.super_block.inode_size() > EXT4_GOOD_OLD_INODE_SIZE {
-            inode.set_extra_isize(self.super_block.extra_size());
-        }
+
         let mut root = InodeRef::new(EXT4_ROOT_INO, inode);
         let root_self = root.clone();
 
@@ -51,14 +46,14 @@ impl Ext4 {
     }
 
     /// Free an allocated inode and all data blocks allocated for it
-    pub(super) fn free_inode(&mut self, inode: &mut InodeRef) -> Result<()> {
+    pub(super) fn free_inode(&self, inode: &mut InodeRef) -> Result<()> {
         // Free the data blocks allocated for the inode
         let pblocks = self.extent_all_data_blocks(&inode);
         for pblock in pblocks {
             // Deallocate the block
             self.dealloc_block(inode, pblock)?;
             // Update inode block count
-            inode.inode.set_block_count(inode.inode.block_count() - 1); 
+            inode.inode.set_block_count(inode.inode.block_count() - 1);
             // Clear the block content
             self.write_block(&Block::new(pblock, [0; BLOCK_SIZE]));
         }
@@ -80,21 +75,18 @@ impl Ext4 {
     }
 
     /// Append a data block for an inode, return a pair of (logical block id, physical block id)
-    /// 
-    /// Only data blocks allocated by `inode_append_block` will be counted in `inode.block_count`. 
+    ///
+    /// Only data blocks allocated by `inode_append_block` will be counted in `inode.block_count`.
     /// Blocks allocated by calling `alloc_block` directly will not be counted, i.e., blocks
     /// allocated for the inode's extent tree.
-    /// 
+    ///
     /// Appending a block does not increase `inode.size`, because `inode.size` records the actual
-    /// size of the data content, not the number of blocks allocated for it. 
-    /// 
+    /// size of the data content, not the number of blocks allocated for it.
+    ///
     /// If the inode is a file, `inode.size` will be increased when writing to end of the file.
     /// If the inode is a directory, `inode.size` will be increased when adding a new entry to the
     /// newly created block.
-    pub(super) fn inode_append_block(
-        &mut self,
-        inode: &mut InodeRef,
-    ) -> Result<(LBlockId, PBlockId)> {
+    pub(super) fn inode_append_block(&self, inode: &mut InodeRef) -> Result<(LBlockId, PBlockId)> {
         // The new logical block id
         let iblock = inode.inode.block_count() as LBlockId;
         // Check the extent tree to get the physical block id
@@ -107,16 +99,18 @@ impl Ext4 {
     }
 
     /// Allocate a new physical block for an inode, return the physical block number
-    pub(super) fn alloc_block(&mut self, inode: &mut InodeRef) -> Result<PBlockId> {
+    pub(super) fn alloc_block(&self, inode: &mut InodeRef) -> Result<PBlockId> {
+        let mut sb = self.read_super_block();
+
         // Calc block group id
-        let inodes_per_group = self.super_block.inodes_per_group();
+        let inodes_per_group = sb.inodes_per_group();
         let bgid = ((inode.id - 1) / inodes_per_group) as BlockGroupId;
 
         // Load block group descriptor
         let mut bg = self.read_block_group(bgid);
 
         // Load block bitmap
-        let bitmap_block_id = bg.desc.block_bitmap_block(&self.super_block);
+        let bitmap_block_id = bg.desc.block_bitmap_block(&sb);
         let mut bitmap_block = self.read_block(bitmap_block_id);
         let mut bitmap = Bitmap::new(&mut bitmap_block.data);
 
@@ -130,13 +124,13 @@ impl Ext4 {
             ))? as PBlockId;
 
         // Set block group checksum
-        bg.desc.set_block_bitmap_csum(&self.super_block, &bitmap);
+        bg.desc.set_block_bitmap_csum(&sb, &bitmap);
         self.write_block(&bitmap_block);
 
         // Update superblock free blocks count
-        let free_blocks = self.super_block.free_blocks_count() - 1;
-        self.super_block.set_free_blocks_count(free_blocks);
-        self.write_super_block();
+        let free_blocks = sb.free_blocks_count() - 1;
+        sb.set_free_blocks_count(free_blocks);
+        self.write_super_block(&sb);
 
         // Update block group free blocks count
         let fb_cnt = bg.desc.get_free_blocks_count() - 1;
@@ -149,20 +143,18 @@ impl Ext4 {
     }
 
     /// Deallocate a physical block allocated for an inode
-    pub(super) fn dealloc_block(
-        &mut self,
-        inode: &mut InodeRef,
-        pblock: PBlockId,
-    ) -> Result<()> {
+    pub(super) fn dealloc_block(&self, inode: &mut InodeRef, pblock: PBlockId) -> Result<()> {
+        let mut sb = self.read_super_block();
+
         // Calc block group id
-        let inodes_per_group = self.super_block.inodes_per_group();
+        let inodes_per_group = sb.inodes_per_group();
         let bgid = ((inode.id - 1) / inodes_per_group) as BlockGroupId;
 
         // Load block group descriptor
         let mut bg = self.read_block_group(bgid);
 
         // Load block bitmap
-        let bitmap_block_id = bg.desc.block_bitmap_block(&self.super_block);
+        let bitmap_block_id = bg.desc.block_bitmap_block(&sb);
         let mut bitmap_block = self.read_block(bitmap_block_id);
         let mut bitmap = Bitmap::new(&mut bitmap_block.data);
 
@@ -173,13 +165,13 @@ impl Ext4 {
         bitmap.clear_bit(pblock as usize);
 
         // Set block group checksum
-        bg.desc.set_block_bitmap_csum(&self.super_block, &bitmap);
+        bg.desc.set_block_bitmap_csum(&sb, &bitmap);
         self.write_block(&bitmap_block);
 
         // Update superblock free blocks count
-        let free_blocks = self.super_block.free_blocks_count() + 1;
-        self.super_block.set_free_blocks_count(free_blocks);
-        self.write_super_block();
+        let free_blocks = sb.free_blocks_count() + 1;
+        sb.set_free_blocks_count(free_blocks);
+        self.write_super_block(&sb);
 
         // Update block group free blocks count
         let fb_cnt = bg.desc.get_free_blocks_count() + 1;
@@ -192,10 +184,11 @@ impl Ext4 {
     }
 
     /// Allocate a new inode, returning the inode number.
-    fn alloc_inode(&mut self, is_dir: bool) -> Result<InodeId> {
-        let mut bgid = 0;
-        let bg_count = self.super_block.block_groups_count();
+    fn alloc_inode(&self, is_dir: bool) -> Result<InodeId> {
+        let mut sb = self.read_super_block();
+        let bg_count = sb.block_groups_count();
 
+        let mut bgid = 0;
         while bgid <= bg_count {
             // Load block group descriptor
             let mut bg = self.read_block_group(bgid);
@@ -206,9 +199,9 @@ impl Ext4 {
             }
 
             // Load inode bitmap
-            let bitmap_block_id = bg.desc.inode_bitmap_block(&self.super_block);
+            let bitmap_block_id = bg.desc.inode_bitmap_block(&sb);
             let mut bitmap_block = self.read_block(bitmap_block_id);
-            let inode_count = self.super_block.inode_count_in_group(bgid) as usize;
+            let inode_count = sb.inode_count_in_group(bgid) as usize;
             let mut bitmap = Bitmap::new(&mut bitmap_block.data[..inode_count / 8]);
 
             // Find a free inode
@@ -222,36 +215,35 @@ impl Ext4 {
                     ))? as u32;
 
             // Update bitmap in disk
-            bg.desc.set_inode_bitmap_csum(&self.super_block, &bitmap);
+            bg.desc.set_inode_bitmap_csum(&sb, &bitmap);
             self.write_block(&bitmap_block);
 
             // Modify filesystem counters
             let free_inodes = bg.desc.free_inodes_count() - 1;
-            bg.desc
-                .set_free_inodes_count(&self.super_block, free_inodes);
+            bg.desc.set_free_inodes_count(&sb, free_inodes);
 
             // Increase used directories counter
             if is_dir {
-                let used_dirs = bg.desc.used_dirs_count(&self.super_block) + 1;
-                bg.desc.set_used_dirs_count(&self.super_block, used_dirs);
+                let used_dirs = bg.desc.used_dirs_count(&sb) + 1;
+                bg.desc.set_used_dirs_count(&sb, used_dirs);
             }
 
             // Decrease unused inodes count
-            let mut unused = bg.desc.itable_unused(&self.super_block);
+            let mut unused = bg.desc.itable_unused(&sb);
             let free = inode_count as u32 - unused;
             if idx_in_bg >= free {
                 unused = inode_count as u32 - (idx_in_bg + 1);
-                bg.desc.set_itable_unused(&self.super_block, unused);
+                bg.desc.set_itable_unused(&sb, unused);
             }
 
             self.write_block_group_with_csum(&mut bg);
 
             // Update superblock
-            self.super_block.decrease_free_inodes_count();
-            self.write_super_block();
+            sb.decrease_free_inodes_count();
+            self.write_super_block(&sb);
 
             // Compute the absolute i-node number
-            let inodes_per_group = self.super_block.inodes_per_group();
+            let inodes_per_group = sb.inodes_per_group();
             let inode_id = bgid * inodes_per_group + (idx_in_bg + 1);
 
             return Ok(inode_id);
@@ -262,9 +254,11 @@ impl Ext4 {
     }
 
     /// Free an inode
-    fn dealloc_inode(&mut self, inode_ref: &InodeRef) -> Result<()> {
+    fn dealloc_inode(&self, inode_ref: &InodeRef) -> Result<()> {
+        let mut sb = self.read_super_block();
+
         // Calc block group id and index in block group
-        let inodes_per_group = self.super_block.inodes_per_group();
+        let inodes_per_group = sb.inodes_per_group();
         let bgid = ((inode_ref.id - 1) / inodes_per_group) as BlockGroupId;
         let idx_in_bg = (inode_ref.id - 1) % inodes_per_group;
 
@@ -272,9 +266,9 @@ impl Ext4 {
         let mut bg = self.read_block_group(bgid);
 
         // Load inode bitmap
-        let bitmap_block_id = bg.desc.inode_bitmap_block(&self.super_block);
+        let bitmap_block_id = bg.desc.inode_bitmap_block(&sb);
         let mut bitmap_block = self.read_block(bitmap_block_id);
-        let inode_count = self.super_block.inode_count_in_group(bgid) as usize;
+        let inode_count = sb.inode_count_in_group(bgid) as usize;
         let mut bitmap = Bitmap::new(&mut bitmap_block.data[..inode_count / 8]);
 
         // Free the inode
@@ -289,29 +283,28 @@ impl Ext4 {
         bitmap.clear_bit(idx_in_bg as usize);
 
         // Update bitmap in disk
-        bg.desc.set_inode_bitmap_csum(&self.super_block, &bitmap);
+        bg.desc.set_inode_bitmap_csum(&sb, &bitmap);
         self.write_block(&bitmap_block);
 
         // Modify filesystem counters
         let free_inodes = bg.desc.free_inodes_count() + 1;
-        bg.desc
-            .set_free_inodes_count(&self.super_block, free_inodes);
+        bg.desc.set_free_inodes_count(&sb, free_inodes);
 
         // Increase used directories counter
         if inode_ref.inode.is_dir() {
-            let used_dirs = bg.desc.used_dirs_count(&self.super_block) - 1;
-            bg.desc.set_used_dirs_count(&self.super_block, used_dirs);
+            let used_dirs = bg.desc.used_dirs_count(&sb) - 1;
+            bg.desc.set_used_dirs_count(&sb, used_dirs);
         }
 
         // Decrease unused inodes count
-        let unused = bg.desc.itable_unused(&self.super_block) + 1;
-        bg.desc.set_itable_unused(&self.super_block, unused);
+        let unused = bg.desc.itable_unused(&sb) + 1;
+        bg.desc.set_itable_unused(&sb, unused);
 
         self.write_block_group_with_csum(&mut bg);
 
         // Update superblock
-        self.super_block.decrease_free_inodes_count();
-        self.write_super_block();
+        sb.decrease_free_inodes_count();
+        self.write_super_block(&sb);
 
         Ok(())
     }

+ 5 - 5
src/ext4/dir.rs

@@ -26,7 +26,7 @@ impl Ext4 {
 
     /// Add an entry to a directory
     pub(super) fn dir_add_entry(
-        &mut self,
+        &self,
         dir: &mut InodeRef,
         child: &InodeRef,
         name: &str,
@@ -36,7 +36,7 @@ impl Ext4 {
             dir.id, child.id, name
         );
         let total_blocks: u32 = dir.inode.block_count() as u32;
-        
+
         // Try finding a block with enough space
         let mut iblock: LBlockId = 0;
         while iblock < total_blocks {
@@ -66,7 +66,7 @@ impl Ext4 {
     }
 
     /// Remove a entry from a directory
-    pub(super) fn dir_remove_entry(&mut self, dir: &mut InodeRef, name: &str) -> Result<()> {
+    pub(super) fn dir_remove_entry(&self, dir: &mut InodeRef, name: &str) -> Result<()> {
         info!("Dir remove entry: dir {}, path {}", dir.id, name);
         let total_blocks: u32 = dir.inode.block_count() as u32;
 
@@ -166,7 +166,7 @@ impl Ext4 {
         let mut tail = DirEntryTail::default();
         tail.rec_len = size_of::<DirEntryTail>() as u16;
         tail.reserved_ft = 0xDE;
-        tail.set_csum(&self.super_block, &new_entry, &dst_blk.data[..]);
+        tail.set_csum(&self.read_super_block(), &new_entry, &dst_blk.data[..]);
         // Copy tail to block
         let tail_offset = BLOCK_SIZE - size_of::<DirEntryTail>();
         dst_blk.write_offset_as(tail_offset, &tail);
@@ -209,7 +209,7 @@ 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.super_block, &de, &dst_blk.data[offset..]);
+            tail.set_csum(&self.read_super_block(), &de, &dst_blk.data[offset..]);
             // Write tail to blk_data
             dst_blk.write_offset_as(tail_offset, &tail);
 

+ 6 - 8
src/ext4/extent.rs

@@ -53,7 +53,7 @@ impl Ext4 {
     /// Given a logic block id, find the corresponding fs block id.
     /// Create a new extent if not found.
     pub(super) fn extent_query_or_create(
-        &mut self,
+        &self,
         inode_ref: &mut InodeRef,
         iblock: LBlockId,
         block_count: u32,
@@ -78,7 +78,7 @@ impl Ext4 {
             }
             Err(_) => {
                 // Not found, create a new extent
-                let block_count = min(block_count, EXT_MAX_BLOCKS - iblock);
+                let block_count = min(block_count, MAX_BLOCKS - iblock);
                 // Allocate physical block
                 let fblock = self.alloc_block(inode_ref)?;
                 // Create a new extent
@@ -148,9 +148,7 @@ impl Ext4 {
 
         // Go until leaf
         while ex_node.header().depth() > 0 {
-            let index = ex_node
-                .search_extent_index(iblock)
-                .expect("Must succeed");
+            let index = ex_node.search_extent_index(iblock).expect("Must succeed");
             path.push(ExtentSearchStep::new(pblock, Ok(index)));
             // Get the target extent index
             let ex_idx = ex_node.extent_index_at(index);
@@ -171,7 +169,7 @@ impl Ext4 {
 
     /// Insert a new extent into the extent tree.
     fn insert_extent(
-        &mut self,
+        &self,
         inode_ref: &mut InodeRef,
         path: &Vec<ExtentSearchStep>,
         new_ext: &Extent,
@@ -226,7 +224,7 @@ impl Ext4 {
     /// `insert_extent_index`, and the split part is stored in `split`.
     /// This function will create a new leaf node to store the split part.
     fn split(
-        &mut self,
+        &self,
         inode_ref: &mut InodeRef,
         parent_pblock: PBlockId,
         child_pos: usize,
@@ -278,7 +276,7 @@ impl Ext4 {
     /// The root node has already been split by calling `insert_extent` or
     /// `insert_extent_index`, and the split part is stored in `split`.
     /// This function will create a new leaf node to store the split part.
-    fn split_root(&mut self, inode_ref: &mut InodeRef, split: &[FakeExtent]) -> Result<()> {
+    fn split_root(&self, inode_ref: &mut InodeRef, split: &[FakeExtent]) -> Result<()> {
         // Create left and right blocks
         let l_bid = self.alloc_block(inode_ref)?;
         let r_bid = self.alloc_block(inode_ref)?;

+ 4 - 14
src/ext4/high_level.rs

@@ -24,7 +24,7 @@ impl Ext4 {
     /// ## Return
     ///
     /// `Ok(inode)` - Inode id of the object
-    pub fn generic_lookup(&mut self, root: InodeId, path: &str) -> Result<InodeId> {
+    pub fn generic_lookup(&self, root: InodeId, path: &str) -> Result<InodeId> {
         // Search from the given parent inode
         let mut cur = root;
         let search_path = Self::split_path(path);
@@ -47,12 +47,7 @@ impl Ext4 {
     /// ## Return
     ///
     /// `Ok(fh)` - File handler
-    pub fn generic_open(
-        &mut self,
-        root: InodeId,
-        path: &str,
-        flags: OpenFlags,
-    ) -> Result<FileHandler> {
+    pub fn generic_open(&self, root: InodeId, path: &str, flags: OpenFlags) -> Result<FileHandler> {
         let inode_id = self.generic_lookup(root, path)?;
         let inode = self.read_inode(inode_id);
         // Check file type
@@ -76,12 +71,7 @@ impl Ext4 {
     /// ## Return
     ///
     /// `Ok(inode)` - Inode id of the created object
-    pub fn generic_create(
-        &mut self,
-        root: InodeId,
-        path: &str,
-        mode: InodeMode,
-    ) -> Result<InodeId> {
+    pub fn generic_create(&self, root: InodeId, path: &str, mode: InodeMode) -> Result<InodeId> {
         // Search from the given parent inode
         let mut cur = self.read_inode(root);
         let search_path = Self::split_path(path);
@@ -124,7 +114,7 @@ impl Ext4 {
     ///
     /// * `root` - The inode id of the starting directory for search.
     /// * `path` - The path of the object to remove.
-    pub fn generic_remove(&mut self, root: InodeId, path: &str) -> Result<()> {
+    pub fn generic_remove(&self, root: InodeId, path: &str) -> Result<()> {
         // Get the parent directory path and the file name
         let mut search_path = Self::split_path(path);
         let file_name = &search_path.split_off(search_path.len() - 1)[0];

+ 2 - 2
src/ext4/link.rs

@@ -5,7 +5,7 @@ use crate::prelude::*;
 impl Ext4 {
     /// Link a child inode to a parent directory.
     pub(super) fn link_inode(
-        &mut self,
+        &self,
         parent: &mut InodeRef,
         child: &mut InodeRef,
         name: &str,
@@ -28,7 +28,7 @@ impl Ext4 {
     /// Unlink a child inode from a parent directory.
     /// Free the inode if link count is 0.
     pub(super) fn unlink_inode(
-        &mut self,
+        &self,
         parent: &mut InodeRef,
         child: &mut InodeRef,
         name: &str,

+ 10 - 10
src/ext4/low_level.rs

@@ -63,7 +63,7 @@ impl Ext4 {
     ///
     /// `EINVAL` if the inode is invalid (mode == 0).
     pub fn setattr(
-        &mut self,
+        &self,
         id: InodeId,
         mode: Option<InodeMode>,
         uid: Option<u32>,
@@ -124,7 +124,7 @@ impl Ext4 {
     ///
     /// * `ENOTDIR` - `parent` is not a directory
     /// * `ENOSPC` - No space left on device
-    pub fn create(&mut self, parent: InodeId, name: &str, mode: InodeMode) -> Result<InodeId> {
+    pub fn create(&self, parent: InodeId, name: &str, mode: InodeMode) -> Result<InodeId> {
         let mut parent = self.read_inode(parent);
         // Can only create a file in a directory
         if !parent.inode.is_dir() {
@@ -153,7 +153,7 @@ impl Ext4 {
     /// # Error
     ///
     /// * `EISDIR` - `file` is not a regular file
-    pub fn read(&mut self, file: InodeId, offset: usize, buf: &mut [u8]) -> Result<usize> {
+    pub fn read(&self, file: InodeId, offset: usize, buf: &mut [u8]) -> Result<usize> {
         // Get the inode of the file
         let mut file = self.read_inode(file);
         if !file.inode.is_file() {
@@ -213,7 +213,7 @@ impl Ext4 {
     ///
     /// * `EISDIR` - `file` is not a regular file
     /// * `ENOSPC` - no space left on device
-    pub fn write(&mut self, file: InodeId, offset: usize, data: &[u8]) -> Result<usize> {
+    pub fn write(&self, file: InodeId, offset: usize, data: &[u8]) -> Result<usize> {
         // Get the inode of the file
         let mut file = self.read_inode(file);
         if !file.inode.is_file() {
@@ -265,7 +265,7 @@ impl Ext4 {
     ///
     /// * `ENOTDIR` - `parent` is not a directory
     /// * `ENOSPC` - no space left on device
-    pub fn link(&mut self, child: InodeId, parent: InodeId, name: &str) -> Result<()> {
+    pub fn link(&self, child: InodeId, parent: InodeId, name: &str) -> Result<()> {
         let mut parent = self.read_inode(parent);
         // Can only link to a directory
         if !parent.inode.is_dir() {
@@ -287,7 +287,7 @@ impl Ext4 {
     ///
     /// * `ENOTDIR` - `parent` is not a directory
     /// * `ENOENT` - `name` does not exist in `parent`
-    pub fn unlink(&mut self, parent: InodeId, name: &str) -> Result<()> {
+    pub fn unlink(&self, parent: InodeId, name: &str) -> Result<()> {
         let mut parent = self.read_inode(parent);
         // Can only unlink from a directory
         if !parent.inode.is_dir() {
@@ -314,7 +314,7 @@ impl Ext4 {
     /// * `ENOENT` - `name` does not exist in `parent`
     /// * `ENOSPC` - no space left on device
     pub fn rename(
-        &mut self,
+        &self,
         parent: InodeId,
         name: &str,
         new_parent: InodeId,
@@ -357,7 +357,7 @@ impl Ext4 {
     ///
     /// * `ENOTDIR` - `parent` is not a directory
     /// * `ENOSPC` - no space left on device
-    pub fn mkdir(&mut self, parent: InodeId, name: &str, mode: InodeMode) -> Result<InodeId> {
+    pub fn mkdir(&self, parent: InodeId, name: &str, mode: InodeMode) -> Result<InodeId> {
         let mut parent = self.read_inode(parent);
         // Can only create a directory in a directory
         if !parent.inode.is_dir() {
@@ -386,7 +386,7 @@ impl Ext4 {
     ///
     /// * `ENOTDIR` - `parent` is not a directory
     /// * `ENOENT` - `name` does not exist in `parent`
-    pub fn lookup(&mut self, parent: InodeId, name: &str) -> Result<InodeId> {
+    pub fn lookup(&self, parent: InodeId, name: &str) -> Result<InodeId> {
         let parent = self.read_inode(parent);
         // Can only lookup in a directory
         if !parent.inode.is_dir() {
@@ -430,7 +430,7 @@ impl Ext4 {
     /// * `ENOTDIR` - `parent` or `child` is not a directory
     /// * `ENOENT` - `name` does not exist in `parent`
     /// * `ENOTEMPTY` - `child` is not empty
-    pub fn rmdir(&mut self, parent: InodeId, name: &str) -> Result<()> {
+    pub fn rmdir(&self, parent: InodeId, name: &str) -> Result<()> {
         let mut parent = self.read_inode(parent);
         // Can only remove a directory in a directory
         if !parent.inode.is_dir() {

+ 7 - 6
src/ext4/mod.rs

@@ -1,6 +1,7 @@
 use crate::constants::*;
 use crate::ext4_defs::*;
 use crate::prelude::*;
+use crate::return_error;
 
 mod alloc;
 mod dir;
@@ -14,7 +15,6 @@ mod rw;
 #[derive(Debug)]
 pub struct Ext4 {
     block_device: Arc<dyn BlockDevice>,
-    super_block: SuperBlock,
 }
 
 impl Ext4 {
@@ -23,12 +23,13 @@ impl Ext4 {
         // Load the superblock
         // TODO: if the main superblock is corrupted, should we load the backup?
         let block = block_device.read_block(0);
-        let super_block = block.read_offset_as::<SuperBlock>(BASE_OFFSET);
+        let sb = block.read_offset_as::<SuperBlock>(BASE_OFFSET);
+        // Check magic number
+        if !sb.check_magic() {
+            return_error!(ErrCode::EINVAL, "invalid magic number");
+        }
         // Create Ext4 instance
-        Ok(Self {
-            super_block,
-            block_device,
-        })
+        Ok(Self { block_device })
     }
     /// Initializes the root directory.
     pub fn init(&mut self) -> Result<()> {

+ 14 - 10
src/ext4/rw.rs

@@ -7,13 +7,13 @@ use super::Ext4;
 impl Ext4 {
     /// Read super block from block device
     #[allow(unused)]
-    pub(super) fn read_super_block(&mut self) {
-        self.super_block = SuperBlock::load_from_disk(self.block_device.as_ref());
+    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) {
-        self.super_block.sync_to_disk(self.block_device.as_ref());
+    pub(super) fn write_super_block(&self, sb: &SuperBlock) {
+        sb.sync_to_disk(self.block_device.as_ref());
     }
 
     /// Read a block from block device
@@ -29,7 +29,11 @@ impl Ext4 {
     /// 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.super_block, inode_id)
+        InodeRef::load_from_disk(
+            self.block_device.as_ref(),
+            &self.read_super_block(),
+            inode_id,
+        )
     }
 
     /// Read the root inode from block device
@@ -40,12 +44,12 @@ 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.super_block)
+        inode_ref.sync_to_disk_with_csum(self.block_device.as_ref(), &self.read_super_block())
     }
 
     /// 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.super_block)
+        inode_ref.sync_to_disk_without_csum(self.block_device.as_ref(), &self.read_super_block())
     }
 
     /// Read a block group descriptor from block device, return an `BlockGroupRef`
@@ -53,19 +57,19 @@ impl Ext4 {
     pub(super) fn read_block_group(&self, block_group_id: BlockGroupId) -> BlockGroupRef {
         BlockGroupRef::load_from_disk(
             self.block_device.as_ref(),
-            &self.super_block,
+            &self.read_super_block(),
             block_group_id,
         )
     }
 
     /// 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.super_block)
+        bg_ref.sync_to_disk_with_csum(self.block_device.as_ref(), &self.read_super_block())
     }
 
     /// 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.super_block)
+        bg_ref.sync_to_disk_without_csum(self.block_device.as_ref(), &self.read_super_block())
     }
 }

+ 2 - 2
src/ext4_defs/block_device.rs

@@ -4,9 +4,9 @@ use core::any::Any;
 use core::fmt::Debug;
 
 /// Interface for serializing and deserializing objects to and from bytes.
-/// 
+///
 /// # Unsafe
-/// 
+///
 /// This trait is unsafe because it allows arbitrary memory interpretation.
 /// Implementor should guarantee the object is saved in the way defined by
 /// functions `from_bytes` and `to_bytes`.

+ 15 - 12
src/ext4_defs/block_group.rs

@@ -47,9 +47,12 @@ pub struct BlockGroupDesc {
 unsafe impl AsBytes for BlockGroupDesc {}
 
 impl BlockGroupDesc {
+    const MIN_BLOCK_GROUP_DESC_SIZE: u16 = 32;
+    const MAX_BLOCK_GROUP_DESC_SIZE: u16 = 64;
+
     pub fn block_bitmap_block(&self, s: &SuperBlock) -> PBlockId {
         let mut v = self.block_bitmap_lo as u64;
-        if s.desc_size() > EXT4_MIN_BLOCK_GROUP_DESCRIPTOR_SIZE {
+        if s.desc_size() > Self::MIN_BLOCK_GROUP_DESC_SIZE {
             v |= (self.block_bitmap_hi as u64) << 32;
         }
         v
@@ -57,7 +60,7 @@ impl BlockGroupDesc {
 
     pub fn inode_bitmap_block(&self, s: &SuperBlock) -> PBlockId {
         let mut v = self.inode_bitmap_lo as u64;
-        if s.desc_size() > EXT4_MIN_BLOCK_GROUP_DESCRIPTOR_SIZE {
+        if s.desc_size() > Self::MIN_BLOCK_GROUP_DESC_SIZE {
             v |= (self.inode_bitmap_hi as u64) << 32;
         }
         v
@@ -65,7 +68,7 @@ impl BlockGroupDesc {
 
     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 {
+        if s.desc_size() > Self::MIN_BLOCK_GROUP_DESC_SIZE {
             v |= ((self.itable_unused_hi as u64) << 32) as u32;
         }
         v
@@ -73,7 +76,7 @@ impl BlockGroupDesc {
 
     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 {
+        if s.desc_size() > Self::MIN_BLOCK_GROUP_DESC_SIZE {
             v |= ((self.used_dirs_count_hi as u64) << 32) as u32;
         }
         v
@@ -81,21 +84,21 @@ impl BlockGroupDesc {
 
     pub fn set_used_dirs_count(&mut self, s: &SuperBlock, cnt: u32) {
         self.itable_unused_lo = ((cnt << 16) >> 16) as u16;
-        if s.desc_size() > EXT4_MIN_BLOCK_GROUP_DESCRIPTOR_SIZE {
+        if s.desc_size() > Self::MIN_BLOCK_GROUP_DESC_SIZE {
             self.itable_unused_hi = (cnt >> 16) as u16;
         }
     }
 
     pub fn set_itable_unused(&mut self, s: &SuperBlock, cnt: u32) {
         self.itable_unused_lo = ((cnt << 16) >> 16) as u16;
-        if s.desc_size() > EXT4_MIN_BLOCK_GROUP_DESCRIPTOR_SIZE {
+        if s.desc_size() > Self::MIN_BLOCK_GROUP_DESC_SIZE {
             self.itable_unused_hi = (cnt >> 16) as u16;
         }
     }
 
     pub fn set_free_inodes_count(&mut self, s: &SuperBlock, cnt: u32) {
         self.free_inodes_count_lo = ((cnt << 16) >> 16) as u16;
-        if s.desc_size() > EXT4_MIN_BLOCK_GROUP_DESCRIPTOR_SIZE {
+        if s.desc_size() > Self::MIN_BLOCK_GROUP_DESC_SIZE {
             self.free_inodes_count_hi = (cnt >> 16) as u16;
         }
     }
@@ -124,7 +127,7 @@ impl BlockGroupDesc {
     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);
+        let mut csum = ext4_crc32c(CRC32_INIT, &uuid, uuid.len() as u32);
         csum = ext4_crc32c(csum, bitmap.as_raw(), (inodes_per_group + 7) / 8);
         csum
     }
@@ -132,7 +135,7 @@ impl BlockGroupDesc {
     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);
+        let mut csum = ext4_crc32c(CRC32_INIT, &uuid, uuid.len() as u32);
         csum = ext4_crc32c(csum, bitmap.as_raw(), (blocks_per_group / 8) as u32);
         csum
     }
@@ -148,7 +151,7 @@ impl BlockGroupDesc {
             return;
         }
         self.inode_bitmap_csum_lo = lo_csum as u16;
-        if desc_size == EXT4_MAX_BLOCK_GROUP_DESCRIPTOR_SIZE {
+        if desc_size == Self::MAX_BLOCK_GROUP_DESC_SIZE {
             self.inode_bitmap_csum_hi = hi_csum as u16;
         }
     }
@@ -164,7 +167,7 @@ impl BlockGroupDesc {
             return;
         }
         self.block_bitmap_csum_lo = lo_csum as u16;
-        if desc_size == EXT4_MAX_BLOCK_GROUP_DESCRIPTOR_SIZE {
+        if desc_size == Self::MAX_BLOCK_GROUP_DESC_SIZE {
             self.block_bitmap_csum_hi = hi_csum as u16;
         }
     }
@@ -229,7 +232,7 @@ impl BlockGroupRef {
 
         // uuid checksum
         let mut checksum = ext4_crc32c(
-            EXT4_CRC32_INIT,
+            CRC32_INIT,
             &super_block.uuid(),
             super_block.uuid().len() as u32,
         );

+ 1 - 1
src/ext4_defs/dir_entry.rs

@@ -170,7 +170,7 @@ impl DirEntry {
 
         let uuid = s.uuid();
 
-        let mut csum = ext4_crc32c(EXT4_CRC32_INIT, &uuid, uuid.len() as u32);
+        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];

+ 12 - 11
src/ext4_defs/extent.rs

@@ -13,7 +13,6 @@
 //! inode.i_block, which allows for the first four extents to be recorded without
 //! the use of extra metadata blocks.
 
-use crate::constants::*;
 use crate::prelude::*;
 
 #[derive(Debug, Default, Clone, Copy)]
@@ -41,9 +40,11 @@ pub struct ExtentHeader {
 }
 
 impl ExtentHeader {
+    const EXTENT_MAGIC: u16 = 0xF30A;
+
     pub fn new(entries_count: u16, max_entries_count: u16, depth: u16, generation: u32) -> Self {
         Self {
-            magic: EXT4_EXTENT_MAGIC,
+            magic: Self::EXTENT_MAGIC,
             entries_count,
             max_entries_count,
             depth,
@@ -154,6 +155,9 @@ pub struct Extent {
 }
 
 impl Extent {
+    /// Extent with `block_count` greater than 32768 is considered unwritten.
+    const INIT_MAX_LEN: u16 = 32768;
+
     /// Create a new extent with start logic block number, start physical block number, and block count
     pub fn new(start_lblock: LBlockId, start_pblock: PBlockId, block_count: u16) -> Self {
         Self {
@@ -187,10 +191,10 @@ impl Extent {
 
     /// The actual number of blocks covered by this extent
     pub fn block_count(&self) -> LBlockId {
-        (if self.block_count <= EXT_INIT_MAX_LEN {
+        (if self.block_count <= Self::INIT_MAX_LEN {
             self.block_count
         } else {
-            self.block_count - EXT_INIT_MAX_LEN
+            self.block_count - Self::INIT_MAX_LEN
         }) as LBlockId
     }
 
@@ -201,12 +205,12 @@ impl Extent {
 
     /// Check if the extent is unwritten
     pub fn is_unwritten(&self) -> bool {
-        self.block_count > EXT_INIT_MAX_LEN
+        self.block_count > Self::INIT_MAX_LEN
     }
 
     /// Mark the extent as unwritten
     pub fn mark_unwritten(&mut self) {
-        (*self).block_count |= EXT_INIT_MAX_LEN;
+        (*self).block_count |= Self::INIT_MAX_LEN;
     }
 
     /// Check whether the `ex2` extent can be appended to the `ex1` extent
@@ -214,14 +218,11 @@ impl Extent {
         if ex1.start_pblock() + ex1.block_count() as u64 != ex2.start_pblock() {
             return false;
         }
-        if ex1.is_unwritten()
-            && ex1.block_count() + ex2.block_count() > EXT_UNWRITTEN_MAX_LEN as LBlockId
-        {
+        if ex1.is_unwritten() && ex1.block_count() + ex2.block_count() > 65535 as LBlockId {
             return false;
-        } else if ex1.block_count() + ex2.block_count() > EXT_INIT_MAX_LEN as LBlockId {
+        } else if ex1.block_count() + ex2.block_count() > Self::INIT_MAX_LEN as LBlockId {
             return false;
         }
-        // 检查逻辑块号是否连续
         if ex1.first_block + ex1.block_count() as u32 != ex2.first_block {
             return false;
         }

+ 7 - 7
src/ext4_defs/inode.rs

@@ -180,13 +180,17 @@ pub struct Inode {
 /// Because `[u8; 60]` cannot derive `Default`, we implement it manually.
 impl Default for Inode {
     fn default() -> Self {
-        unsafe { mem::zeroed() }
+        let mut inode: Self = unsafe { mem::zeroed() };
+        inode.extra_isize = (size_of::<Inode>() - 128) as u16;
+        inode
     }
 }
 
 unsafe impl AsBytes for Inode {}
 
 impl Inode {
+    const FLAG_EXTENTS: u32 = 0x00080000;
+
     pub fn mode(&self) -> InodeMode {
         InodeMode::from_bits_truncate(self.mode)
     }
@@ -303,10 +307,6 @@ impl Inode {
         self.generation = generation;
     }
 
-    pub fn set_extra_isize(&mut self, extra_isize: u16) {
-        self.extra_isize = extra_isize;
-    }
-
     pub fn flags(&self) -> u32 {
         self.flags
     }
@@ -343,7 +343,7 @@ impl Inode {
     /// inode to use extent for block mapping. Initialize the root
     /// node of the extent tree
     pub fn extent_init(&mut self) {
-        self.set_flags(EXT4_INODE_FLAG_EXTENTS);
+        self.set_flags(Self::FLAG_EXTENTS);
         self.extent_root_mut().init(0, 0);
     }
 }
@@ -433,7 +433,7 @@ impl InodeRef {
         self.inode.checksum_hi = 0;
 
         let mut checksum = ext4_crc32c(
-            EXT4_CRC32_INIT,
+            CRC32_INIT,
             &super_block.uuid(),
             super_block.uuid().len() as u32,
         );

+ 7 - 6
src/ext4_defs/super_block.rs

@@ -115,6 +115,12 @@ pub struct SuperBlock {
 unsafe impl AsBytes for SuperBlock {}
 
 impl SuperBlock {
+    const SB_MAGIC: u16 = 0xEF53;
+
+    pub fn check_magic(&self) -> bool {
+        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)
@@ -179,12 +185,7 @@ impl SuperBlock {
     }
 
     pub fn desc_size(&self) -> u16 {
-        let size = self.desc_size;
-        if size < EXT4_MIN_BLOCK_GROUP_DESCRIPTOR_SIZE {
-            return EXT4_MIN_BLOCK_GROUP_DESCRIPTOR_SIZE as u16;
-        } else {
-            size
-        }
+        self.desc_size
     }
 
     pub fn extra_size(&self) -> u16 {