浏览代码

fix: inode size and block count

liujingx 10 月之前
父节点
当前提交
e136b08144
共有 7 个文件被更改,包括 76 次插入77 次删除
  1. 3 1
      src/constants.rs
  2. 25 23
      src/ext4/alloc.rs
  3. 3 3
      src/ext4/dir.rs
  4. 4 4
      src/ext4/link.rs
  5. 13 17
      src/ext4/low_level.rs
  6. 3 3
      src/ext4_defs/block_device.rs
  7. 25 26
      src/ext4_defs/inode.rs

+ 3 - 1
src/constants.rs

@@ -30,4 +30,6 @@ pub const EXT4_ROOT_INO: InodeId = 1;
 
 pub const BASE_OFFSET: usize = 1024;
 pub const BLOCK_SIZE: usize = 4096;
-pub const INODE_BLOCK_SIZE: usize = 512;
+
+/// For simplicity define this the same as block size
+pub const INODE_BLOCK_SIZE: usize = 4096;

+ 25 - 23
src/ext4/alloc.rs

@@ -45,27 +45,27 @@ impl Ext4 {
         // Add `.` and `..` entries
         self.dir_add_entry(&mut root, &root_self, ".")?;
         self.dir_add_entry(&mut root, &root_self, "..")?;
-        root.inode.links_count += 2;
+        root.inode.link_count += 2;
 
         self.write_inode_with_csum(&mut root);
         Ok(root)
     }
 
     /// Free an allocated inode and all data blocks allocated for it
-    pub(super) fn free_inode(&mut self, inode_ref: &mut InodeRef) -> Result<()> {
+    pub(super) fn free_inode(&mut self, inode: &mut InodeRef) -> Result<()> {
         // Free the data blocks allocated for the inode
-        let pblocks = self.extent_get_all_pblocks(&inode_ref)?;
+        let pblocks = self.extent_get_all_pblocks(&inode)?;
         for pblock in pblocks {
             // Deallocate the block
-            self.dealloc_block(inode_ref, pblock)?;
+            self.dealloc_block(inode, pblock)?;
             // Clear the block content
             self.write_block(&Block::new(pblock, [0; BLOCK_SIZE]));
         }
         // Deallocate the inode
-        self.dealloc_inode(&inode_ref)?;
+        self.dealloc_inode(&inode)?;
         // Clear the inode content
-        inode_ref.inode = unsafe { core::mem::zeroed() };
-        self.write_inode_without_csum(inode_ref);
+        inode.inode = unsafe { core::mem::zeroed() };
+        self.write_inode_without_csum(inode);
         Ok(())
     }
 
@@ -76,24 +76,26 @@ impl Ext4 {
     /// to save the inode's extent tree.
     pub(super) fn inode_append_block(
         &mut self,
-        inode_ref: &mut InodeRef,
+        inode: &mut InodeRef,
     ) -> Result<(LBlockId, PBlockId)> {
-        let inode_size = inode_ref.inode.size();
+        let inode_size = inode.inode.size();
         // The new logical block id
         let iblock = ((inode_size + BLOCK_SIZE as u64 - 1) / BLOCK_SIZE as u64) as u32;
         // Check the extent tree to get the physical block id
-        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_inode_with_csum(inode_ref);
+        let fblock = self.extent_get_pblock_create(inode, iblock, 1)?;
+        // Update inode block count
+        let block_count = inode.inode.block_count() + 1;
+        inode.inode.set_block_count(block_count);
+        self.write_inode_with_csum(inode);
+        
         Ok((iblock, fblock))
     }
 
     /// Allocate a new physical block for an inode, return the physical block number
-    pub(super) fn alloc_block(&mut self, inode_ref: &mut InodeRef) -> Result<PBlockId> {
+    pub(super) fn alloc_block(&mut self, inode: &mut InodeRef) -> Result<PBlockId> {
         // Calc block group id
         let inodes_per_group = self.super_block.inodes_per_group();
-        let bgid = ((inode_ref.id - 1) / inodes_per_group) as BlockGroupId;
+        let bgid = ((inode.id - 1) / inodes_per_group) as BlockGroupId;
 
         // Load block group descriptor
         let mut bg = self.read_block_group(bgid);
@@ -122,9 +124,9 @@ impl Ext4 {
         self.write_super_block();
 
         // Update inode blocks (different block size!) count
-        let inode_blocks = inode_ref.inode.blocks_count() + (BLOCK_SIZE / INODE_BLOCK_SIZE) as u64;
-        inode_ref.inode.set_blocks_count(inode_blocks);
-        self.write_inode_with_csum(inode_ref);
+        let inode_blocks = inode.inode.block_count() + (BLOCK_SIZE / INODE_BLOCK_SIZE) as u64;
+        inode.inode.set_block_count(inode_blocks);
+        self.write_inode_with_csum(inode);
 
         // Update block group free blocks count
         let fb_cnt = bg.desc.get_free_blocks_count() - 1;
@@ -139,12 +141,12 @@ impl Ext4 {
     /// Deallocate a physical block allocated for an inode
     pub(super) fn dealloc_block(
         &mut self,
-        inode_ref: &mut InodeRef,
+        inode: &mut InodeRef,
         pblock: PBlockId,
     ) -> Result<()> {
         // Calc block group id
         let inodes_per_group = self.super_block.inodes_per_group();
-        let bgid = ((inode_ref.id - 1) / inodes_per_group) as BlockGroupId;
+        let bgid = ((inode.id - 1) / inodes_per_group) as BlockGroupId;
 
         // Load block group descriptor
         let mut bg = self.read_block_group(bgid);
@@ -170,9 +172,9 @@ impl Ext4 {
         self.write_super_block();
 
         // Update inode blocks (different block size!) count
-        let inode_blocks = inode_ref.inode.blocks_count() - (BLOCK_SIZE / INODE_BLOCK_SIZE) as u64;
-        inode_ref.inode.set_blocks_count(inode_blocks);
-        self.write_inode_with_csum(inode_ref);
+        let inode_blocks = inode.inode.block_count() - (BLOCK_SIZE / INODE_BLOCK_SIZE) as u64;
+        inode.inode.set_block_count(inode_blocks);
+        self.write_inode_with_csum(inode);
 
         // Update block group free blocks count
         let fb_cnt = bg.desc.get_free_blocks_count() + 1;

+ 3 - 3
src/ext4/dir.rs

@@ -114,7 +114,7 @@ impl Ext4 {
 
     /// Find a directory entry that matches a given name in a given block
     fn find_entry_in_block(block: &Block, name: &str) -> Option<DirEntry> {
-        info!("Dir find entry {} in block {}", name, block.block_id);
+        info!("Dir find entry {} in block {}", name, block.id);
         let mut offset = 0;
         while offset < BLOCK_SIZE {
             let de: DirEntry = block.read_offset_as(offset);
@@ -128,7 +128,7 @@ impl Ext4 {
 
     /// Remove a directory entry that matches a given name from a given block
     fn remove_entry_from_block(block: &mut Block, name: &str) -> bool {
-        info!("Dir remove entry {} from block {}", name, block.block_id);
+        info!("Dir remove entry {} from block {}", name, block.id);
         let mut offset = 0;
         while offset < BLOCK_SIZE {
             let mut de: DirEntry = block.read_offset_as(offset);
@@ -145,7 +145,7 @@ impl Ext4 {
 
     /// Get all directory entries from a given block
     fn get_all_entries_from_block(block: &Block, entries: &mut Vec<DirEntry>) {
-        info!("Dir get all entries from block {}", block.block_id);
+        info!("Dir get all entries from block {}", block.id);
         let mut offset = 0;
         while offset < BLOCK_SIZE {
             let de: DirEntry = block.read_offset_as(offset);

+ 4 - 4
src/ext4/link.rs

@@ -13,8 +13,8 @@ impl Ext4 {
         // Add entry to parent directory
         self.dir_add_entry(parent, child, name)?;
         // Update link count of child
-        let link_cnt = child.inode.links_cnt() + 1;
-        child.inode.set_links_cnt(link_cnt);
+        let link_cnt = child.inode.link_count() + 1;
+        child.inode.set_link_count(link_cnt);
         // Add '.' and '..' entries if child is a newly created directory
         if link_cnt == 1 && child.inode.is_dir() {
             let child_self = child.clone();
@@ -36,12 +36,12 @@ impl Ext4 {
         // Remove entry from parent directory
         self.dir_remove_entry(parent, name)?;
         // Update link count of child
-        let link_cnt = child.inode.links_cnt() - 1;
+        let link_cnt = child.inode.link_count() - 1;
         if link_cnt == 0 {
             // Free the inode if link count is 0
             return self.free_inode(child);
         }
-        child.inode.set_links_cnt(link_cnt);
+        child.inode.set_link_count(link_cnt);
         self.write_inode_with_csum(child);
         Ok(())
     }

+ 13 - 17
src/ext4/low_level.rs

@@ -80,15 +80,12 @@ impl Ext4 {
             return_error!(ErrCode::EISDIR, "Inode {} is not a file", file);
         }
 
-        let read_size = buf.len();
         // Read no bytes
-        if read_size == 0 {
+        if buf.len() == 0 {
             return Ok(0);
         }
-        // Get file size
-        let fsize = inode_ref.inode.size();
         // Calc the actual size to read
-        let size_to_read = min(read_size, fsize as usize - offset);
+        let read_size = min(buf.len(), inode_ref.inode.size() as usize - offset);
         // Calc the start block of reading
         let start_iblock = (offset / BLOCK_SIZE) as LBlockId;
         // Calc the length that is not aligned to the block size
@@ -98,7 +95,7 @@ impl Ext4 {
         let mut iblock = start_iblock;
         // Read first block
         if misaligned > 0 {
-            let read_len = min(BLOCK_SIZE - misaligned, size_to_read);
+            let read_len = min(BLOCK_SIZE - misaligned, read_size);
             let fblock = self
                 .extent_get_pblock(&mut inode_ref, start_iblock)
                 .unwrap();
@@ -109,8 +106,8 @@ impl Ext4 {
             iblock += 1;
         }
         // Continue with full block reads
-        while cursor < size_to_read {
-            let read_len = min(BLOCK_SIZE, size_to_read - cursor);
+        while cursor < read_size {
+            let read_len = min(BLOCK_SIZE, read_size - cursor);
             let fblock = self.extent_get_pblock(&mut inode_ref, iblock).unwrap();
             let block = self.read_block(fblock);
             // Copy data from block to the user buffer
@@ -142,21 +139,19 @@ impl Ext4 {
     /// TODO: handle EOF
     pub fn write(&mut self, file: InodeId, offset: usize, data: &[u8]) -> Result<usize> {
         // Get the inode of the file
-        let mut inode_ref = self.read_inode(file);
-        if !inode_ref.inode.is_file() {
+        let mut inode = self.read_inode(file);
+        if !inode.inode.is_file() {
             return_error!(ErrCode::EISDIR, "Inode {} is not a file", file);
         }
 
         let write_size = data.len();
-        // Calc the start and end block of reading
+        // Calc the start and end block of writing
         let start_iblock = (offset / BLOCK_SIZE) as LBlockId;
         let end_iblock = ((offset + write_size) / BLOCK_SIZE) as LBlockId;
-        // Calc the block count of the file
-        let block_count = (offset as usize + BLOCK_SIZE - 1) / BLOCK_SIZE;
         // Append enough block for writing
-        let append_block_count = end_iblock + 1 - block_count as LBlockId;
+        let append_block_count = (end_iblock + 1) as i64 - inode.inode.block_count() as i64;
         for _ in 0..append_block_count {
-            self.inode_append_block(&mut inode_ref)?;
+            self.inode_append_block(&mut inode)?;
         }
 
         // Write data
@@ -164,17 +159,18 @@ impl Ext4 {
         let mut iblock = start_iblock;
         while cursor < write_size {
             let write_len = min(BLOCK_SIZE, write_size - cursor);
-            let fblock = self.extent_get_pblock(&mut inode_ref, iblock)?;
+            let fblock = self.extent_get_pblock(&mut inode, iblock)?;
             let mut block = self.read_block(fblock);
             block.write_offset(
                 (offset + cursor) % BLOCK_SIZE,
                 &data[cursor..cursor + write_len],
             );
             self.write_block(&block);
-
             cursor += write_len;
             iblock += 1;
         }
+        inode.inode.set_size((offset + cursor) as u64);
+        self.write_inode_with_csum(&mut inode);
 
         Ok(cursor)
     }

+ 3 - 3
src/ext4_defs/block_device.rs

@@ -21,7 +21,7 @@ where
 /// Common data block descriptor
 pub struct Block {
     /// Physical block id
-    pub block_id: PBlockId,
+    pub id: PBlockId,
     /// Raw block data
     pub data: [u8; BLOCK_SIZE],
 }
@@ -29,7 +29,7 @@ pub struct Block {
 impl Default for Block {
     fn default() -> Self {
         Self {
-            block_id: 0,
+            id: 0,
             data: [0; BLOCK_SIZE],
         }
     }
@@ -38,7 +38,7 @@ impl Default for Block {
 impl Block {
     /// Create new block with given physical block id and data
     pub fn new(block_id: PBlockId, data: [u8; BLOCK_SIZE]) -> Self {
-        Self { block_id, data }
+        Self { id: block_id, data }
     }
 
     /// Read `size` bytes from `offset` in block data

+ 25 - 26
src/ext4_defs/inode.rs

@@ -103,8 +103,11 @@ pub struct Inode {
     pub mtime: u32,
     pub dtime: u32,
     pub gid: u16,
-    pub links_count: u16,
-    pub blocks: u32,
+    pub link_count: u16,
+    /// Note: this field is different from ext4 inode by now.
+    /// Ext4 defines this as the count of 512-byte blocks.
+    /// To simplify, we define this as the count of 4096-byte blocks.
+    pub block_count: u32,
     pub flags: u32,
     pub osd1: u32,
     pub block: [u8; 60], // Block bitmap or extent tree
@@ -114,14 +117,14 @@ pub struct Inode {
     pub faddr: u32,   /* Obsoleted fragment address */
     pub osd2: Linux2, // 操作系统相关的字段2
 
-    pub i_extra_isize: u16,
-    pub i_checksum_hi: u16,  // crc32c(uuid+inum+inode) BE
-    pub i_ctime_extra: u32,  // 额外的修改时间(nsec << 2 | epoch)
-    pub i_mtime_extra: u32,  // 额外的文件修改时间(nsec << 2 | epoch)
-    pub i_atime_extra: u32,  // 额外的访问时间(nsec << 2 | epoch)
-    pub i_crtime: u32,       // 文件创建时间
-    pub i_crtime_extra: u32, // 额外的文件创建时间(nsec << 2 | epoch)
-    pub i_version_hi: u32,   // 64位版本的高32位
+    pub extra_isize: u16,
+    pub checksum_hi: u16,  // crc32c(uuid+inum+inode) BE
+    pub ctime_extra: u32,  // 额外的修改时间(nsec << 2 | epoch)
+    pub mtime_extra: u32,  // 额外的文件修改时间(nsec << 2 | epoch)
+    pub atime_extra: u32,  // 额外的访问时间(nsec << 2 | epoch)
+    pub crtime: u32,       // 文件创建时间
+    pub crtime_extra: u32, // 额外的文件创建时间(nsec << 2 | epoch)
+    pub version_hi: u32,   // 64位版本的高32位
 }
 
 /// Because `[u8; 60]` cannot derive `Default`, we implement it manually.
@@ -134,10 +137,6 @@ impl Default for Inode {
 impl AsBytes for Inode {}
 
 impl Inode {
-    pub fn from_bytes(bytes: &[u8]) -> Self {
-        unsafe { *(bytes.as_ptr() as *const Inode) }
-    }
-
     pub fn flags(&self) -> u32 {
         self.flags
     }
@@ -170,12 +169,12 @@ impl Inode {
         self.file_type() == FileType::SymLink
     }
 
-    pub fn links_cnt(&self) -> u16 {
-        self.links_count
+    pub fn link_count(&self) -> u16 {
+        self.link_count
     }
 
-    pub fn set_links_cnt(&mut self, cnt: u16) {
-        self.links_count = cnt;
+    pub fn set_link_count(&mut self, cnt: u16) {
+        self.link_count = cnt;
     }
 
     pub fn set_uid(&mut self, uid: u16) {
@@ -211,17 +210,17 @@ impl Inode {
         self.dtime = del_time;
     }
 
-    pub fn blocks_count(&self) -> u64 {
-        let mut blocks = self.blocks as u64;
+    pub fn block_count(&self) -> u64 {
+        let mut blocks = self.block_count 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: u64) {
-        self.blocks = (blocks_count & 0xFFFFFFFF) as u32;
-        self.osd2.l_i_blocks_high = (blocks_count >> 32) as u16;
+    pub fn set_block_count(&mut self, cnt: u64) {
+        self.block_count = cnt as u32;
+        self.osd2.l_i_blocks_high = (cnt >> 32) as u16;
     }
 
     pub fn set_generation(&mut self, generation: u32) {
@@ -229,7 +228,7 @@ impl Inode {
     }
 
     pub fn set_extra_isize(&mut self, extra_isize: u16) {
-        self.i_extra_isize = extra_isize;
+        self.extra_isize = extra_isize;
     }
 
     fn copy_to_byte_slice(&self, slice: &mut [u8]) {
@@ -347,7 +346,7 @@ impl InodeRef {
 
         // Preparation: temporarily set bg checksum to 0
         self.inode.osd2.l_i_checksum_lo = 0;
-        self.inode.i_checksum_hi = 0;
+        self.inode.checksum_hi = 0;
 
         let mut checksum = ext4_crc32c(
             EXT4_CRC32_INIT,
@@ -369,7 +368,7 @@ impl InodeRef {
 
         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;
+            self.inode.checksum_hi = (checksum >> 16) as u16;
         }
     }
 }