Răsfoiți Sursa

fix: inode block count

liujingx 10 luni în urmă
părinte
comite
598eb17fcb
5 a modificat fișierele cu 85 adăugiri și 68 ștergeri
  1. 29 23
      src/ext4/alloc.rs
  2. 6 4
      src/ext4/dir.rs
  3. 39 28
      src/ext4/extent.rs
  4. 7 5
      src/ext4/low_level.rs
  5. 4 8
      src/ext4_defs/inode.rs

+ 29 - 23
src/ext4/alloc.rs

@@ -53,10 +53,21 @@ impl Ext4 {
     /// Free an allocated inode and all data blocks allocated for it
     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)?;
+        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); 
+            // Clear the block content
+            self.write_block(&Block::new(pblock, [0; BLOCK_SIZE]));
+        }
+        // Free extent tree
+        let pblocks = self.extent_all_tree_blocks(&inode);
+        for pblock in pblocks {
+            // Deallocate the block
+            self.dealloc_block(inode, pblock)?;
+            // Tree blocks are not counted in `inode.block_count`
             // Clear the block content
             self.write_block(&Block::new(pblock, [0; BLOCK_SIZE]));
         }
@@ -69,24 +80,29 @@ 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.size`. Blocks
-    /// allocated by calling `alloc_block` directly will not be counted, e.g. blocks allocated
-    /// to save the inode's extent tree.
+    /// 
+    /// 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. 
+    /// 
+    /// 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)> {
-        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;
+        let iblock = inode.inode.block_count() as LBlockId;
         // Check the extent tree to get the physical block id
-        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);
-        
+        let fblock = self.extent_query_or_create(inode, iblock, 1)?;
+        // Update block count
+        inode.inode.set_block_count(inode.inode.block_count() + 1);
+        self.write_inode_without_csum(inode);
+
         Ok((iblock, fblock))
     }
 
@@ -122,11 +138,6 @@ impl Ext4 {
         self.super_block.set_free_blocks_count(free_blocks);
         self.write_super_block();
 
-        // Update inode blocks (different block size!) count
-        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;
         bg.desc.set_free_blocks_count(fb_cnt);
@@ -170,11 +181,6 @@ impl Ext4 {
         self.super_block.set_free_blocks_count(free_blocks);
         self.write_super_block();
 
-        // Update inode blocks (different block size!) count
-        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;
         bg.desc.set_free_blocks_count(fb_cnt);

+ 6 - 4
src/ext4/dir.rs

@@ -11,7 +11,7 @@ impl Ext4 {
         let mut iblock: LBlockId = 0;
         while iblock < total_blocks {
             // Get the fs block id
-            let fblock = self.extent_get_pblock(dir, iblock)?;
+            let fblock = self.extent_query(dir, iblock)?;
             // Load block from disk
             let block = self.read_block(fblock);
             // Find the entry in block
@@ -41,7 +41,7 @@ impl Ext4 {
         let mut iblock: LBlockId = 0;
         while iblock < total_blocks {
             // Get the parent physical block id
-            let fblock = self.extent_get_pblock(dir, iblock).unwrap();
+            let fblock = self.extent_query(dir, iblock).unwrap();
             // Load the parent block from disk
             let mut block = self.read_block(fblock);
             // Try inserting the entry to parent block
@@ -59,6 +59,8 @@ impl Ext4 {
         let mut new_block = self.read_block(fblock);
         // Write the entry to block
         self.insert_entry_to_new_block(&mut new_block, child, name);
+        // Update inode size
+        dir.inode.set_size(dir.inode.size() + BLOCK_SIZE as u64);
 
         Ok(())
     }
@@ -72,7 +74,7 @@ impl Ext4 {
         let mut iblock: LBlockId = 0;
         while iblock < total_blocks {
             // Get the parent physical block id
-            let fblock = self.extent_get_pblock(dir, iblock).unwrap();
+            let fblock = self.extent_query(dir, iblock).unwrap();
             // Load the block from disk
             let mut block = self.read_block(fblock);
             // Try removing the entry
@@ -96,7 +98,7 @@ impl Ext4 {
         let mut iblock: LBlockId = 0;
         while iblock < total_blocks {
             // Get the fs block id
-            let fblock = self.extent_get_pblock(dir, iblock).unwrap();
+            let fblock = self.extent_query(dir, iblock).unwrap();
             // Load block from disk
             let block = self.read_block(fblock);
             // Get all entries from block

+ 39 - 28
src/ext4/extent.rs

@@ -24,11 +24,7 @@ impl ExtentSearchStep {
 
 impl Ext4 {
     /// Given a logic block id, find the corresponding fs block id.
-    pub(super) fn extent_get_pblock(
-        &self,
-        inode_ref: &InodeRef,
-        iblock: LBlockId,
-    ) -> Result<PBlockId> {
+    pub(super) fn extent_query(&self, inode_ref: &InodeRef, iblock: LBlockId) -> Result<PBlockId> {
         let path = self.find_extent(inode_ref, iblock);
         // Leaf is the last element of the path
         let leaf = path.last().unwrap();
@@ -42,21 +38,21 @@ impl Ext4 {
                 ExtentNode::from_bytes(&block_data.data)
             } else {
                 // Root node
-                inode_ref.inode.extent_node()
+                inode_ref.inode.extent_root()
             };
             let ex = ex_node.extent_at(index);
             Ok(ex.start_pblock() + (iblock - ex.start_lblock()) as PBlockId)
         } else {
             Err(format_error!(
                 ErrCode::ENOENT,
-                "extent_get_pblock: extent not found"
+                "extent_query: extent not found"
             ))
         }
     }
 
     /// Given a logic block id, find the corresponding fs block id.
     /// Create a new extent if not found.
-    pub(super) fn extent_get_pblock_create(
+    pub(super) fn extent_query_or_create(
         &mut self,
         inode_ref: &mut InodeRef,
         iblock: LBlockId,
@@ -72,7 +68,7 @@ impl Ext4 {
             ExtentNodeMut::from_bytes(&mut block_data.data)
         } else {
             // Root node
-            inode_ref.inode.extent_node_mut()
+            inode_ref.inode.extent_root_mut()
         };
         match leaf.index {
             Ok(index) => {
@@ -94,17 +90,22 @@ impl Ext4 {
         }
     }
 
-    /// Get all the physical blocks that the extent tree covers, including
-    /// the blocks allocated to save the extent tree itself.
-    pub(super) fn extent_get_all_pblocks(&self, inode_ref: &InodeRef) -> Result<Vec<PBlockId>> {
+    /// Get all data blocks recorded in the extent tree
+    pub(super) fn extent_all_data_blocks(&self, inode_ref: &InodeRef) -> Vec<PBlockId> {
         let mut pblocks = Vec::new();
-        let ex_node = inode_ref.inode.extent_node();
+        let ex_node = inode_ref.inode.extent_root();
         self.get_all_pblocks_recursive(&ex_node, &mut pblocks);
-        Ok(pblocks)
+        pblocks
+    }
+
+    /// Get all physical blocks for saving the extent tree
+    pub(super) fn extent_all_tree_blocks(&self, inode_ref: &InodeRef) -> Vec<PBlockId> {
+        let mut pblocks = Vec::new();
+        let ex_node = inode_ref.inode.extent_root();
+        self.get_all_nodes_recursive(&ex_node, &mut pblocks);
+        pblocks
     }
 
-    /// Get all the physical blocks that an extent node covers recursively,
-    /// including the blocks allocated to save the extent tree itself.
     fn get_all_pblocks_recursive(&self, ex_node: &ExtentNode, pblocks: &mut Vec<PBlockId>) {
         if ex_node.header().depth() == 0 {
             // Leaf
@@ -118,7 +119,6 @@ impl Ext4 {
             // Non-leaf
             for i in 0..ex_node.header().entries_count() as usize {
                 let ex_idx = ex_node.extent_index_at(i);
-                pblocks.push(ex_idx.leaf());
                 let child_block = self.read_block(ex_idx.leaf());
                 let child_node = ExtentNode::from_bytes(&child_block.data);
                 self.get_all_pblocks_recursive(&child_node, pblocks);
@@ -126,23 +126,34 @@ impl Ext4 {
         }
     }
 
+    fn get_all_nodes_recursive(&self, ex_node: &ExtentNode, pblocks: &mut Vec<PBlockId>) {
+        if ex_node.header().depth() != 0 {
+            // Non-leaf
+            for i in 0..ex_node.header().entries_count() as usize {
+                let ex_idx = ex_node.extent_index_at(i);
+                pblocks.push(ex_idx.leaf());
+                let child_block = self.read_block(ex_idx.leaf());
+                let child_node = ExtentNode::from_bytes(&child_block.data);
+                self.get_all_nodes_recursive(&child_node, pblocks);
+            }
+        }
+    }
+
     /// Find the given logic block id in the extent tree, return the search path
     fn find_extent(&self, inode_ref: &InodeRef, iblock: LBlockId) -> Vec<ExtentSearchStep> {
         let mut path: Vec<ExtentSearchStep> = Vec::new();
-        let mut ex_node = inode_ref.inode.extent_node();
+        let mut ex_node = inode_ref.inode.extent_root();
         let mut pblock = 0;
         let mut block_data: Block;
 
         // Go until leaf
         while ex_node.header().depth() > 0 {
-            let index = ex_node.search_extent_index(iblock);
-            if index.is_err() {
-                // TODO: no extent index
-                panic!("Unhandled error");
-            }
-            path.push(ExtentSearchStep::new(pblock, index));
+            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.unwrap());
+            let ex_idx = ex_node.extent_index_at(index);
             // Load the next extent node
             let next = ex_idx.leaf();
             // Note: block data cannot be released until the next assigment
@@ -168,7 +179,7 @@ impl Ext4 {
         let leaf = path.last().unwrap();
         // 1. Check If leaf is root
         if leaf.pblock == 0 {
-            let mut leaf_node = inode_ref.inode.extent_node_mut();
+            let mut leaf_node = inode_ref.inode.extent_root_mut();
             // Insert the extent
             let res = leaf_node.insert_extent(new_ext, leaf.index.unwrap_err());
             self.write_inode_without_csum(inode_ref);
@@ -241,7 +252,7 @@ impl Ext4 {
         let parent_depth;
         if parent_pblock == 0 {
             // Parent is root
-            let mut parent_node = inode_ref.inode.extent_node_mut();
+            let mut parent_node = inode_ref.inode.extent_root_mut();
             parent_depth = parent_node.header().depth();
             res = parent_node.insert_extent_index(&extent_index, child_pos + 1);
             self.write_inode_without_csum(inode_ref);
@@ -275,7 +286,7 @@ impl Ext4 {
         let mut r_block = self.read_block(r_bid);
 
         // Load root, left, right nodes
-        let mut root = inode_ref.inode.extent_node_mut();
+        let mut root = inode_ref.inode.extent_root_mut();
         let mut left = ExtentNodeMut::from_bytes(&mut l_block.data);
         let mut right = ExtentNodeMut::from_bytes(&mut r_block.data);
 

+ 7 - 5
src/ext4/low_level.rs

@@ -176,7 +176,7 @@ impl Ext4 {
         // Read first block
         if misaligned > 0 {
             let read_len = min(BLOCK_SIZE - misaligned, read_size);
-            let fblock = self.extent_get_pblock(&mut file, start_iblock).unwrap();
+            let fblock = self.extent_query(&mut file, start_iblock).unwrap();
             let block = self.read_block(fblock);
             // Copy data from block to the user buffer
             buf[cursor..cursor + read_len].copy_from_slice(block.read_offset(misaligned, read_len));
@@ -186,7 +186,7 @@ impl Ext4 {
         // Continue with full block reads
         while cursor < read_size {
             let read_len = min(BLOCK_SIZE, read_size - cursor);
-            let fblock = self.extent_get_pblock(&mut file, iblock).unwrap();
+            let fblock = self.extent_query(&mut file, iblock).unwrap();
             let block = self.read_block(fblock);
             // Copy data from block to the user buffer
             buf[cursor..cursor + read_len].copy_from_slice(block.read_offset(0, read_len));
@@ -225,7 +225,7 @@ impl Ext4 {
         let start_iblock = (offset / BLOCK_SIZE) as LBlockId;
         let end_iblock = ((offset + write_size) / BLOCK_SIZE) as LBlockId;
         // Append enough block for writing
-        let append_block_count = (end_iblock + 1) as i64 - file.inode.block_count() as i64;
+        let append_block_count = end_iblock as i64 + 1 - file.inode.block_count() as i64;
         for _ in 0..append_block_count {
             self.inode_append_block(&mut file)?;
         }
@@ -235,7 +235,7 @@ 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 file, iblock)?;
+            let fblock = self.extent_query(&mut file, iblock)?;
             let mut block = self.read_block(fblock);
             block.write_offset(
                 (offset + cursor) % BLOCK_SIZE,
@@ -245,7 +245,9 @@ impl Ext4 {
             cursor += write_len;
             iblock += 1;
         }
-        file.inode.set_size((offset + cursor) as u64);
+        if offset + cursor > file.inode.size() as usize {
+            file.inode.set_size((offset + cursor) as u64);
+        }
         self.write_inode_with_csum(&mut file);
 
         Ok(cursor)

+ 4 - 8
src/ext4_defs/inode.rs

@@ -291,11 +291,7 @@ impl Inode {
     }
 
     pub fn block_count(&self) -> u64 {
-        let mut blocks = self.block_count as u64;
-        if self.osd2.l_blocks_hi != 0 {
-            blocks |= (self.osd2.l_blocks_hi as u64) << 32;
-        }
-        blocks
+        self.block_count as u64 | ((self.osd2.l_blocks_hi as u64) << 32)
     }
 
     pub fn set_block_count(&mut self, cnt: u64) {
@@ -330,14 +326,14 @@ impl Inode {
     /* Extent methods */
 
     /// Get the immutable extent root node
-    pub fn extent_node(&self) -> ExtentNode {
+    pub fn extent_root(&self) -> ExtentNode {
         ExtentNode::from_bytes(unsafe {
             core::slice::from_raw_parts(self.block.as_ptr() as *const u8, 60)
         })
     }
 
     /// Get the mutable extent root node
-    pub fn extent_node_mut(&mut self) -> ExtentNodeMut {
+    pub fn extent_root_mut(&mut self) -> ExtentNodeMut {
         ExtentNodeMut::from_bytes(unsafe {
             core::slice::from_raw_parts_mut(self.block.as_mut_ptr() as *mut u8, 60)
         })
@@ -348,7 +344,7 @@ impl Inode {
     /// node of the extent tree
     pub fn extent_init(&mut self) {
         self.set_flags(EXT4_INODE_FLAG_EXTENTS);
-        self.extent_node_mut().init(0, 0);
+        self.extent_root_mut().init(0, 0);
     }
 }