Эх сурвалжийг харах

refactor: rewrite extent operations

liujingx 11 сар өмнө
parent
commit
59e7a0c2ca

+ 3 - 3
src/constants.rs

@@ -4,8 +4,8 @@ use bitflags::bitflags;
 
 pub const EOK: usize = 0;
 
-pub type Ext4LogicBlockId = u32;
-pub type Ext4FsBlockId = u64;
+pub type LBlockId = u32;
+pub type PBlockId = u64;
 
 pub const EXT4_INODE_FLAG_EXTENTS: usize = 0x00080000; /* Inode uses extents */
 pub const EXT4_MIN_BLOCK_GROUP_DESCRIPTOR_SIZE: u16 = 32;
@@ -26,7 +26,7 @@ pub const EXT4_INODE_MODE_SOFTLINK: usize = 0xA000;
 pub const EXT4_INODE_MODE_SOCKET: usize = 0xC000;
 pub const EXT4_INODE_MODE_TYPE_MASK: u16 = 0xF000;
 
-pub const EXT_MAX_BLOCKS: Ext4LogicBlockId = core::u32::MAX;
+pub const EXT_MAX_BLOCKS: LBlockId = core::u32::MAX;
 
 pub const EXT4_SUPERBLOCK_OS_HURD: u32 = 1;
 

+ 8 - 14
src/ext4/dir.rs

@@ -14,15 +14,13 @@ impl Ext4 {
         name: &str,
         result: &mut Ext4DirSearchResult,
     ) -> usize {
-        let mut iblock: Ext4LogicBlockId = 0;
-        let mut fblock: Ext4FsBlockId = 0;
-
         let inode_size: u32 = parent.inode.size;
         let total_blocks: u32 = inode_size / BLOCK_SIZE as u32;
+        let mut iblock: LBlockId = 0;
 
         while iblock < total_blocks {
             // Get the fs block id
-            self.ext4_fs_get_inode_dblk_idx(parent, &mut iblock, &mut fblock, false);
+            let fblock = self.extent_get_pblock(parent, iblock);
             // Load block from disk
             let mut data = self.block_device.read_offset(fblock as usize * BLOCK_SIZE);
             let mut ext4_block = Ext4Block {
@@ -68,7 +66,7 @@ impl Ext4 {
 
     /// Add an entry to a directory
     pub fn dir_add_entry(
-        &self,
+        &mut self,
         parent: &mut Ext4InodeRef,
         child: &mut Ext4InodeRef,
         path: &str,
@@ -76,14 +74,12 @@ impl Ext4 {
         let block_size = self.super_block.block_size();
         let inode_size = parent.inode.size();
         let total_blocks = inode_size as u32 / block_size;
-
-        let mut iblock = 0;
-        let mut fblock: Ext4FsBlockId = 0;
-
+        
         // Try finding a block with enough space
+        let mut iblock: LBlockId = 0;
         while iblock < total_blocks {
-            // Get the parent fs block id
-            self.ext4_fs_get_inode_dblk_idx(parent, &mut iblock, &mut fblock, false);
+            // Get the parent physical block id
+            let fblock = self.extent_get_pblock(parent, iblock);
             // Load the parent block from disk
             let mut data = self.block_device.read_offset(fblock as usize * BLOCK_SIZE);
             let mut ext4_block = Ext4Block {
@@ -102,10 +98,8 @@ impl Ext4 {
         }
 
         // No free block found - needed to allocate a new data block
-        iblock = 0;
-        fblock = 0;
         // Append a new data block
-        self.ext4_fs_append_inode_dblk(parent, &mut iblock, &mut fblock);
+        let (iblock, fblock) = self.inode_append_block(parent);
         // Load new block
         let block_device = self.block_device.clone();
         let mut data = block_device.read_offset(fblock as usize * BLOCK_SIZE);

+ 139 - 251
src/ext4/extent.rs

@@ -2,244 +2,175 @@ use super::Ext4;
 use crate::constants::*;
 use crate::ext4_defs::*;
 use crate::prelude::*;
+use core::cmp::min;
 
 impl Ext4 {
-    pub fn find_extent(
-        inode_ref: &mut Ext4InodeRef,
-        block_id: Ext4LogicBlockId,
-        orig_path: &mut Option<Vec<Ext4ExtentPath>>,
-        _flags: u32,
-    ) -> usize {
-        let inode = &inode_ref.inode;
-        let mut _eh: &Ext4ExtentHeader;
-        let mut path = orig_path.take(); // Take the path out of the Option, which may replace it with None
-        let depth = ext4_depth(inode);
-
-        let mut ppos = 0;
-        let mut i: u16;
-
-        let eh = &inode.block as *const [u32; 15] as *mut Ext4ExtentHeader;
-
-        if let Some(ref mut p) = path {
-            if depth > p[0].maxdepth {
-                p.clear();
+    /// Find the given logic block id in the extent tree, return the search path
+    fn find_extent(&self, inode_ref: &mut Ext4InodeRef, iblock: LBlockId) -> Vec<ExtentSearchPath> {
+        let mut path: Vec<ExtentSearchPath> = Vec::new();
+        let mut eh = inode_ref.inode.extent_header().clone();
+        let mut pblock = 0;
+        let mut block_data: Vec<u8>;
+        // Go until leaf
+        while eh.depth() > 0 {
+            let index = eh.extent_index_search(iblock);
+            if index.is_err() {
+                // TODO: no extent index
+                panic!("Unhandled error");
             }
+            path.push(ExtentSearchPath::new_inner(pblock, index));
+            // Get the target extent index
+            let ex_idx = eh.extent_index_at(index.unwrap());
+            // Load the next extent node
+            let next = ex_idx.leaf();
+            // Note: block data cannot be released until the next assigment
+            block_data = self.block_device.read_offset(next as usize * BLOCK_SIZE);
+            // Load the next extent header
+            eh = Ext4ExtentHeader::load_from_block(&block_data);
+            pblock = next;
         }
-        if path.is_none() {
-            let path_depth = depth + 1;
-            path = Some(vec![Ext4ExtentPath::default(); path_depth as usize + 1]);
-            path.as_mut().unwrap()[0].maxdepth = path_depth;
-        }
-
-        let path = path.as_mut().unwrap();
-        path[0].header = eh;
+        // Leaf
+        let index = eh.extent_search(iblock);
+        path.push(ExtentSearchPath::new_leaf(pblock, index));
 
-        i = depth;
-        while i > 0 {
-            ext4_ext_binsearch_idx(&mut path[ppos], block_id);
-            path[ppos].p_block = ext4_idx_pblock(path[ppos].index);
-            path[ppos].depth = i;
-            path[ppos].extent = core::ptr::null_mut();
-
-            i -= 1;
-            ppos += 1;
-        }
-
-        path[ppos].depth = i;
-        path[ppos].extent = core::ptr::null_mut();
-        path[ppos].index = core::ptr::null_mut();
+        path
+    }
 
-        ext4_ext_binsearch(&mut path[ppos], block_id);
-        if !path[ppos].extent.is_null() {
-            path[ppos].p_block = unsafe { (*path[ppos].extent).pblock() };
+    /// Given a logic block id, find the corresponding fs block id.
+    /// Return 0 if not found.
+    pub fn extent_get_pblock(&self, inode_ref: &mut Ext4InodeRef, iblock: LBlockId) -> PBlockId {
+        let path = self.find_extent(inode_ref, iblock);
+        // Leaf is the last element of the path
+        let leaf = path.last().unwrap();
+        if let Ok(index) = leaf.index {
+            // Note: block data must be defined here to keep it alive
+            let block_data: Vec<u8>;
+            let eh = if leaf.pblock != 0 {
+                // Load the extent node
+                block_data = self
+                    .block_device
+                    .read_offset(leaf.pblock as usize * BLOCK_SIZE);
+                // Load the next extent header
+                Ext4ExtentHeader::load_from_block(&block_data)
+            } else {
+                // Root node
+                inode_ref.inode.extent_header().clone()
+            };
+            let ex = eh.extent_at(index);
+            ex.start_pblock() + (iblock - ex.start_lblock()) as PBlockId
+        } else {
+            0
         }
-
-        *orig_path = Some(path.clone());
-
-        EOK
     }
 
-    pub fn ext4_extent_get_blocks(
-        &self,
+    /// Given a logic block id, find the corresponding fs block id.
+    /// Create a new extent if not found.
+    pub fn extent_get_pblock_create(
+        &mut self,
         inode_ref: &mut Ext4InodeRef,
-        iblock: Ext4LogicBlockId,
-        max_blocks: u32,
-        result: &mut Ext4FsBlockId,
-        create: bool,
-        blocks_count: &mut u32,
-    ) {
-        *result = 0;
-        *blocks_count = 0;
-
-        let mut path: Option<Vec<Ext4ExtentPath>> = None;
-        let err = Self::find_extent(inode_ref, iblock, &mut path, 0);
-
-        let inode = &inode_ref.inode;
-        // 确认ext4_find_extent成功执行
-        if err != EOK {
-            return;
-        }
-
-        let depth = unsafe { *ext4_extent_hdr(inode) }.depth as usize;
-        let mut path = path.unwrap();
-
-        if !path[depth].extent.is_null() {
-            let ex = unsafe { *path[depth].extent };
-            let ee_block = ex.first_block;
-            let ee_start = ex.pblock();
-            let ee_len = ex.actual_len();
-
-            if iblock >= ee_block && iblock < ee_block + ee_len as u32 {
-                let allocated = ee_len - (iblock - ee_block) as u16;
-                *blocks_count = allocated as u32;
-
-                if !create || ex.is_unwritten() {
-                    *result = (iblock - ee_block) as u64 + ee_start;
-                    return;
-                }
+        iblock: LBlockId,
+        block_count: u32,
+    ) -> PBlockId {
+        let path = self.find_extent(inode_ref, iblock);
+        // Leaf is the last element of the path
+        let leaf = path.last().unwrap();
+        // Note: block data must be defined here to keep it alive
+        let block_data: Vec<u8>;
+        let eh = if leaf.pblock != 0 {
+            // Load the extent node
+            block_data = self
+                .block_device
+                .read_offset(leaf.pblock as usize * BLOCK_SIZE);
+            // Load the next extent header
+            Ext4ExtentHeader::load_from_block(&block_data)
+        } else {
+            // Root node
+            inode_ref.inode.extent_header().clone()
+        };
+        match leaf.index {
+            Ok(index) => {
+                // Found, return the corresponding fs block id
+                let ex = eh.extent_at(index);
+                ex.start_pblock() + (iblock - ex.start_lblock()) as PBlockId
             }
-        }
-
-        // 如果没有找到对应的extent,并且create为true,则需要分配和插入新的extent
-        if create {
-            let next = EXT_MAX_BLOCKS;
-
-            let mut allocated = next - iblock;
-            if allocated > max_blocks {
-                allocated = max_blocks;
+            Err(_) => {
+                // Not found, create a new extent
+                let block_count = min(block_count, EXT_MAX_BLOCKS - iblock);
+                // Allocate physical block
+                let fblock = self.alloc_block(inode_ref, 0);
+                // Create a new extent
+                let new_ext = Ext4Extent::new(iblock, fblock, block_count as u16);
+                // Insert the new extent
+                self.insert_extent(inode_ref, leaf, &new_ext);
+                fblock
             }
-
-            let mut newex: Ext4Extent = Ext4Extent::default();
-
-            let goal = 0;
-
-            let mut alloc_block = 0;
-            self.ext4_balloc_alloc_block(inode_ref, goal as u64, &mut alloc_block);
-
-            *result = alloc_block;
-
-            // 创建并插入新的extent
-            newex.first_block = iblock;
-            newex.start_lo = alloc_block as u32 & 0xffffffff;
-            newex.start_hi = (((alloc_block as u32) << 31) << 1) as u16;
-            newex.block_count = allocated as u16;
-
-            self.ext4_ext_insert_extent(inode_ref, &mut path[0], &newex, 0);
         }
     }
 
-    pub fn ext4_ext_insert_extent(
+    /// Insert a new extent into a leaf node of the extent tree. Return whether
+    /// the node needs to be split.
+    pub fn insert_extent(
         &self,
         inode_ref: &mut Ext4InodeRef,
-        path: &mut Ext4ExtentPath,
-        newext: &Ext4Extent,
-        flags: i32,
-    ) {
-        let depth = ext4_depth(&inode_ref.inode);
-        let mut need_split = false;
-
-        self.ext4_ext_insert_leaf(inode_ref, path, depth, newext, flags, &mut need_split);
-
-        self.write_back_inode_without_csum(inode_ref);
-    }
-
-    pub fn ext4_ext_insert_leaf(
-        &self,
-        _inode_ref: &mut Ext4InodeRef,
-        path: &mut Ext4ExtentPath,
-        _depth: u16,
-        newext: &Ext4Extent,
-        _flags: i32,
-        need_split: &mut bool,
-    ) -> usize {
-        let eh = path.header;
-        let ex = path.extent;
-        let _last_ex = ext4_last_extent(eh);
-
-        let mut diskblock = newext.start_lo;
-        diskblock |= ((newext.start_hi as u32) << 31) << 1;
-
-        unsafe {
-            if !ex.is_null() && Ext4Extent::can_append(&*(path.extent), newext) {
-                if (*path.extent).is_unwritten() {
-                    (*path.extent).mark_unwritten();
-                }
-                (*(path.extent)).block_count = (*path.extent).actual_len() + newext.actual_len();
-                (*path).p_block = diskblock as u64;
-                return EOK;
-            }
-            if !ex.is_null() && Ext4Extent::can_append(newext, &*(path.extent)) {
-                (*(path.extent)).block_count = (*path.extent).actual_len() + newext.actual_len();
-                (*path).p_block = diskblock as u64;
-                if (*path.extent).is_unwritten() {
-                    (*path.extent).mark_unwritten();
-                }
-                return EOK;
+        leaf: &ExtentSearchPath,
+        new_ext: &Ext4Extent,
+    ) -> bool {
+        // Note: block data must be defined here to keep it alive
+        let mut block_data = Vec::<u8>::new();
+        let mut eh = if leaf.pblock != 0 {
+            // Load the extent node
+            block_data = self
+                .block_device
+                .read_offset(leaf.pblock as usize * BLOCK_SIZE);
+            // Load the next extent header
+            Ext4ExtentHeader::load_from_block(&block_data)
+        } else {
+            // Root node
+            inode_ref.inode.extent_header().clone()
+        };
+        // The position where the new extent should be inserted
+        let index = leaf.index.unwrap_err();
+        let targ_ext = eh.extent_mut_at(index);
+        let split: bool;
+
+        if targ_ext.is_uninit() {
+            // 1. The position has an uninitialized extent
+            *targ_ext = new_ext.clone();
+            split = false;
+        } else {
+            // 2. The position has a valid extent
+            // Insert the extent and move the following extents
+            let mut i = index;
+            while i < eh.entries_count() as usize {
+                *eh.extent_mut_at(i + 1) = *eh.extent_at(i);
+                i += 1;
             }
+            *eh.extent_mut_at(index) = new_ext.clone();
+            eh.set_entries_count(eh.entries_count() + 1);
+            // Check if the extent node is full
+            split = eh.entries_count() >= eh.max_entries_count();
         }
 
-        if ex.is_null() {
-            let first_extent = ext4_first_extent_mut(eh);
-            path.extent = first_extent;
-            // log::info!("first_extent {:x?}", unsafe{*first_extent});
-            unsafe {
-                if (*eh).entries_count == (*eh).max_entries_count {
-                    *need_split = true;
-                    return EIO;
-                } else {
-                    *(path.extent) = *newext;
-                }
-            }
-        }
-
-        unsafe {
-            if (*eh).entries_count == (*eh).max_entries_count {
-                *need_split = true;
-                *(path.extent) = *newext;
-
-                (*path).p_block = diskblock as u64;
-                return EIO;
-            } else {
-                if ex.is_null() {
-                    let first_extent = ext4_first_extent_mut(eh);
-                    path.extent = first_extent;
-                    *(path.extent) = *newext;
-                } else if newext.first_block > (*(path.extent)).first_block {
-                    // insert after
-                    let next_extent = ex.add(1);
-                    path.extent = next_extent;
-                } else {
-                }
-            }
-
-            *(path.extent) = *newext;
-            (*eh).entries_count += 1;
-        }
-        unsafe {
-            *(path.extent) = *newext;
+        if !block_data.is_empty() {
+            self.block_device
+                .write_offset(leaf.pblock as usize * BLOCK_SIZE, &block_data);
+        } else {
+            self.write_back_inode_without_csum(inode_ref);
         }
 
-        return EOK;
-    }
-
-    pub fn ext4_find_all_extent(&self, inode_ref: &Ext4InodeRef, extents: &mut Vec<Ext4Extent>) {
-        let extent_header = Ext4ExtentHeader::try_from(&inode_ref.inode.block[..2]).unwrap();
-        // log::info!("extent_header {:x?}", extent_header);
-        let data = &inode_ref.inode.block;
-        let depth = extent_header.depth;
-        self.ext4_add_extent(inode_ref, depth, data, extents, true);
+        split
     }
 
     pub fn ext4_add_extent(
         &self,
         inode_ref: &Ext4InodeRef,
         depth: u16,
-        data: &[u32],
+        data: &[u8],
         extents: &mut Vec<Ext4Extent>,
         _first_level: bool,
     ) {
-        let extent_header = Ext4ExtentHeader::try_from(data).unwrap();
-        let extent_entries = extent_header.entries_count;
+        let extent_header = Ext4ExtentHeader::load_from_block(data);
+        let extent_entries = extent_header.entries_count();
         // log::info!("extent_entries {:x?}", extent_entries);
         if depth == 0 {
             for en in 0..extent_entries {
@@ -262,51 +193,8 @@ impl Ext4 {
             let mut block = ei_leaf_lo;
             block |= ((ei_leaf_hi as u32) << 31) << 1;
             let data = self.block_device.read_offset(block as usize * BLOCK_SIZE);
-            let data: Vec<u32> = unsafe { core::mem::transmute(data) };
+            // let data: Vec<u32> = unsafe { core::mem::transmute(data) };
             self.ext4_add_extent(inode_ref, depth - 1, &data, extents, false);
         }
     }
-
-    pub fn ext4_fs_get_inode_dblk_idx(
-        &self,
-        inode_ref: &mut Ext4InodeRef,
-        iblock: &mut Ext4LogicBlockId,
-        fblock: &mut Ext4FsBlockId,
-        _extent_create: bool,
-    ) -> usize {
-        let current_block: Ext4FsBlockId;
-        let mut current_fsblk: Ext4FsBlockId = 0;
-        let mut blocks_count = 0;
-        self.ext4_extent_get_blocks(
-            inode_ref,
-            *iblock,
-            1,
-            &mut current_fsblk,
-            false,
-            &mut blocks_count,
-        );
-        current_block = current_fsblk;
-        *fblock = current_block;
-        EOK
-    }
-
-    pub fn ext4_fs_get_inode_dblk_idx_internal(
-        &self,
-        inode_ref: &mut Ext4InodeRef,
-        iblock: &mut Ext4LogicBlockId,
-        _fblock: &mut Ext4FsBlockId,
-        extent_create: bool,
-        _support_unwritten: bool,
-    ) {
-        let mut current_fsblk: Ext4FsBlockId = 0;
-        let mut blocks_count = 0;
-        self.ext4_extent_get_blocks(
-            inode_ref,
-            *iblock,
-            1,
-            &mut current_fsblk,
-            extent_create,
-            &mut blocks_count,
-        );
-    }
 }

+ 168 - 307
src/ext4_defs/extent.rs

@@ -1,19 +1,18 @@
 //! The Defination of Ext4 Extent (Header, Index)
-//! 
+//!
 //! Extents are arranged as a tree. Each node of the tree begins with a struct
-//! [`Ext4ExtentHeader`]. 
-//! 
+//! [`Ext4ExtentHeader`].
+//!
 //! If the node is an interior node (eh.depth > 0), the header is followed by
-//! eh.entries_count instances of struct [`Ext4ExtentIndex`]; each of these index 
-//! entries points to a block containing more nodes in the extent tree. 
-//! 
+//! eh.entries_count instances of struct [`Ext4ExtentIndex`]; each of these index
+//! entries points to a block containing more nodes in the extent tree.
+//!
 //! If the node is a leaf node (eh.depth == 0), then the header is followed by
-//! eh.entries_count instances of struct [`Ext4Extent`]; these instances point 
-//! to the file's data blocks. The root node of the extent tree is stored in 
-//! inode.i_block, which allows for the first four extents to be recorded without 
+//! eh.entries_count instances of struct [`Ext4Extent`]; these instances point
+//! to the file's data blocks. The root node of the extent tree is stored in
+//! inode.i_block, which allows for the first four extents to be recorded without
 //! the use of extra metadata blocks.
 
-use super::Ext4Inode;
 use crate::constants::*;
 use crate::prelude::*;
 
@@ -21,13 +20,13 @@ use crate::prelude::*;
 #[repr(C)]
 pub struct Ext4ExtentHeader {
     /// Magic number, 0xF30A.
-    pub magic: u16,
+    magic: u16,
 
     /// Number of valid entries following the header.
-    pub entries_count: u16,
+    entries_count: u16,
 
     /// Maximum number of entries that could follow the header.
-    pub max_entries_count: u16,
+    max_entries_count: u16,
 
     /// Depth of this extent node in the extent tree.
     /// 0 = this extent node points to data blocks;
@@ -35,21 +34,28 @@ pub struct Ext4ExtentHeader {
     /// The extent tree can be at most 5 levels deep:
     /// a logical block number can be at most 2^32,
     /// and the smallest n that satisfies 4*(((blocksize - 12)/12)^n) >= 2^32 is 5.
-    pub depth: u16,
+    depth: u16,
 
     /// Generation of the tree. (Used by Lustre, but not standard ext4).
-    pub generation: u32,
+    generation: u32,
 }
 
-impl<T> TryFrom<&[T]> for Ext4ExtentHeader {
-    type Error = u64;
-    fn try_from(data: &[T]) -> core::result::Result<Self, u64> {
-        let data = data;
-        Ok(unsafe { core::ptr::read(data.as_ptr() as *const _) })
+impl Ext4ExtentHeader {
+    pub fn new(entries_count: u16, max_entries_count: u16, depth: u16, generation: u32) -> Self {
+        Self {
+            magic: EXT4_EXTENT_MAGIC,
+            entries_count,
+            max_entries_count,
+            depth,
+            generation,
+        }
+    }
+
+    /// Loads an extent header from a data block.
+    pub fn load_from_block(block_data: &[u8]) -> Self {
+        unsafe { *(block_data.as_ptr() as *const Ext4ExtentHeader) }
     }
-}
 
-impl Ext4ExtentHeader {
     // 获取extent header的魔数
     pub fn magic(&self) -> u16 {
         self.magic
@@ -99,6 +105,62 @@ impl Ext4ExtentHeader {
     pub fn set_generation(&mut self, generation: u32) {
         self.generation = generation;
     }
+
+    pub fn extent_at(&self, index: usize) -> &'static Ext4Extent {
+        unsafe { &*((self as *const Self).add(1) as *const Ext4Extent).add(index) }
+    }
+
+    pub fn extent_mut_at(&mut self, index: usize) -> &'static mut Ext4Extent {
+        unsafe { &mut *((self as *mut Self).add(1) as *mut Ext4Extent).add(index) }
+    }
+
+    pub fn extent_index_at(&self, index: usize) -> &'static Ext4ExtentIndex {
+        unsafe { &*((self as *const Self).add(1) as *const Ext4ExtentIndex).add(index) }
+    }
+
+    pub fn extent_index_mut_at(&mut self, index: usize) -> &'static mut Ext4ExtentIndex {
+        unsafe { &mut *((self as *mut Self).add(1) as *mut Ext4ExtentIndex).add(index) }
+    }
+
+    /// Find the extent that covers the given logical block number.
+    ///
+    /// Return `Ok(index)` if found, and `eh.extent_at(index)` is the extent that covers
+    /// the given logical block number. Return `Err(index)` if not found, and `index` is the
+    /// position where the new extent should be inserted.
+    pub fn extent_search(&self, lblock: LBlockId) -> core::result::Result<usize, usize> {
+        let mut i = 0;
+        while i < self.entries_count as usize {
+            let extent = self.extent_at(i);
+            if extent.start_lblock() <= lblock {
+                if extent.start_lblock() + (extent.block_count() as LBlockId) < lblock {
+                    return if extent.is_uninit() { Err(i) } else { Ok(i) };
+                }
+                i += 1;
+            } else {
+                break;
+            }
+        }
+        Err(i)
+    }
+
+    /// Find the extent index that covers the given logical block number. The extent index
+    /// gives the next lower node to search.
+    ///
+    /// Return `Ok(index)` if found, and `eh.extent_index_at(index)` is the target extent index.
+    /// Return `Err(index)` if not found, and `index` is the position where the new extent index
+    /// should be inserted.
+    pub fn extent_index_search(&self, lblock: LBlockId) -> core::result::Result<usize, usize> {
+        let mut i = 0;
+        while i < self.entries_count as usize {
+            let extent_index = self.extent_index_at(i);
+            if extent_index.first_block <= lblock {
+                i += 1;
+            } else {
+                return Ok(i - 1);
+            }
+        }
+        Err(i)
+    }
 }
 
 #[derive(Debug, Default, Clone, Copy)]
@@ -126,11 +188,18 @@ impl<T> TryFrom<&[T]> for Ext4ExtentIndex {
     }
 }
 
+impl Ext4ExtentIndex {
+    /// The physical block number of the extent node that is the next level lower in the tree
+    pub fn leaf(&self) -> PBlockId {
+        (self.leaf_hi as PBlockId) << 32 | self.leaf_lo as PBlockId
+    }
+}
+
 #[derive(Debug, Default, Clone, Copy)]
 #[repr(C)]
 pub struct Ext4Extent {
     /// First file block number that this extent covers.
-    pub first_block: u32,
+    first_block: u32,
 
     /// Number of blocks covered by extent.
     /// If the value of this field is <= 32768, the extent is initialized.
@@ -138,13 +207,13 @@ pub struct Ext4Extent {
     /// and the actual extent length is ee_len - 32768.
     /// Therefore, the maximum length of a initialized extent is 32768 blocks,
     /// and the maximum length of an uninitialized extent is 32767.
-    pub block_count: u16,
+    block_count: u16,
 
     /// Upper 16-bits of the block number to which this extent points.
-    pub start_hi: u16,
+    start_hi: u16,
 
     /// Lower 32-bits of the block number to which this extent points.
-    pub start_lo: u32,
+    start_lo: u32,
 }
 
 impl<T> TryFrom<&[T]> for Ext4Extent {
@@ -156,319 +225,111 @@ impl<T> TryFrom<&[T]> for Ext4Extent {
 }
 
 impl Ext4Extent {
-    pub fn pblock(&self) -> u64 {
-        self.start_lo as u64 | ((self.start_hi as u64) << 32)
+    /// 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 {
+            first_block: start_lblock,
+            block_count,
+            start_hi: (start_pblock >> 32) as u16,
+            start_lo: start_pblock as u32,
+        }
     }
 
-    pub fn is_unwritten(&self) -> bool {
-        // 返回extent是否是未写入的
-        self.block_count > EXT_INIT_MAX_LEN
+    /// The start logic block number that this extent covers
+    pub fn start_lblock(&self) -> LBlockId {
+        self.first_block
+    }
+
+    /// Set the start logic block number that this extent covers
+    pub fn set_start_lblock(&mut self, start_lblock: LBlockId) {
+        self.first_block = start_lblock;
+    }
+
+    /// The start physical block number to which this extent points
+    pub fn start_pblock(&self) -> PBlockId {
+        self.start_lo as PBlockId | ((self.start_hi as PBlockId) << 32)
+    }
+
+    /// Set the start physical block number to which this extent points
+    pub fn set_start_pblock(&mut self, start_pblock: PBlockId) {
+        self.start_hi = (start_pblock >> 32) as u16;
+        self.start_lo = start_pblock as u32;
     }
 
-    pub fn actual_len(&self) -> u16 {
-        // 返回extent的实际长度
-        if self.block_count <= EXT_INIT_MAX_LEN {
+    /// The actual number of blocks covered by this extent
+    pub fn block_count(&self) -> LBlockId {
+        (if self.block_count <= EXT_INIT_MAX_LEN {
             self.block_count
         } else {
             self.block_count - EXT_INIT_MAX_LEN
-        }
+        }) as LBlockId
+    }
+
+    /// Set the number of blocks covered by this extent
+    pub fn set_block_count(&mut self, block_count: LBlockId) {
+        self.block_count = block_count as u16;
     }
 
-    pub fn mark_unwritten(&mut self) {
+    /// Check if the extent is uninitialized
+    pub fn is_uninit(&self) -> bool {
+        self.block_count > EXT_INIT_MAX_LEN
+    }
+
+    /// Mark the extent as uninitialized
+    pub fn mark_uninit(&mut self) {
         (*self).block_count |= EXT_INIT_MAX_LEN;
     }
 
-    /// 检查是否可以将ex2合并到ex1的后面
+    /// Check whether the `ex2` extent can be appended to the `ex1` extent
     pub fn can_append(ex1: &Ext4Extent, ex2: &Ext4Extent) -> bool {
-        if ex1.pblock() + ex1.actual_len() as u64 != ex2.pblock() {
+        if ex1.start_pblock() + ex1.block_count() as u64 != ex2.start_pblock() {
             return false;
         }
-        if ex1.is_unwritten() && ex1.actual_len() + ex2.actual_len() > EXT_UNWRITTEN_MAX_LEN {
+        if ex1.is_uninit()
+            && ex1.block_count() + ex2.block_count() > EXT_UNWRITTEN_MAX_LEN as LBlockId
+        {
             return false;
-        } else if ex1.actual_len() + ex2.actual_len() > EXT_INIT_MAX_LEN {
+        } else if ex1.block_count() + ex2.block_count() > EXT_INIT_MAX_LEN as LBlockId {
             return false;
         }
         // 检查逻辑块号是否连续
-        if ex1.first_block + ex1.actual_len() as u32 != ex2.first_block {
+        if ex1.first_block + ex1.block_count() as u32 != ex2.first_block {
             return false;
         }
         return true;
     }
 }
 
-#[derive(Debug, Clone, Copy)]
-pub struct Ext4ExtentPath {
-    // Physical block number
-    pub p_block: u64,
-    // Single block descriptor
-    // pub block: Ext4Block,
-    // Depth of this extent node
-    pub depth: u16,
-    // Max depth of the extent tree
-    pub maxdepth: u16,
-    // Pointer to the extent header
-    pub header: *mut Ext4ExtentHeader,
-    // Pointer to the index in the current node
-    pub index: *mut Ext4ExtentIndex,
-    // Pointer to the extent in the current node
-    pub extent: *mut Ext4Extent,
+#[derive(Debug)]
+pub struct ExtentSearchPath {
+    /// Marks whether the extent search path is for an inner node or a leaf node.
+    pub leaf: bool,
+    /// The physical block where this extent node is stored if it is not a root node.
+    /// For a root node, this field is 0.
+    pub pblock: PBlockId,
+    /// Index of the found `ExtentIndex` or `Extent` if found, the position where the
+    /// `ExtentIndex` or `Extent` should be inserted if not found.
+    pub index: core::result::Result<usize, usize>,
 }
 
-impl Default for Ext4ExtentPath {
-    fn default() -> Self {
+impl ExtentSearchPath {
+    /// Create a new extent search path, which records an inner node
+    /// of the extent tree i.e. an `ExtentIndex`.
+    pub fn new_inner(pblock: PBlockId, index: core::result::Result<usize, usize>) -> Self {
         Self {
-            p_block: 0,
-            // block: Ext4Block::default(),
-            depth: 0,
-            maxdepth: 0,
-            header: core::ptr::null_mut(),
-            index: core::ptr::null_mut(),
-            extent: core::ptr::null_mut(),
+            pblock,
+            leaf: false,
+            index,
         }
     }
-}
 
-#[derive(Debug, Clone, Copy)]
-pub struct Ext4ExtentPathOld {
-    // Physical block number
-    pub p_block: u32,
-    // Single block descriptor
-    // pub block: Ext4Block,
-    // Depth of this extent node
-    pub depth: u16,
-    // Max depth of the extent tree
-    pub maxdepth: u16,
-    // Pointer to the extent header
-    pub header: *const Ext4ExtentHeader,
-    // Pointer to the index in the current node
-    pub index: *const Ext4ExtentIndex,
-    // Pointer to the extent in the current node
-    pub extent: *const Ext4Extent,
-}
-
-impl Default for Ext4ExtentPathOld {
-    fn default() -> Self {
+    /// Create a new extent search path, which records a leaf node
+    /// of the extent tree i.e. an `Extent`.
+    pub fn new_leaf(pblock: PBlockId, index: core::result::Result<usize, usize>) -> Self {
         Self {
-            p_block: 0,
-            // block: Ext4Block::default(),
-            depth: 0,
-            maxdepth: 0,
-            header: core::ptr::null_mut(),
-            index: core::ptr::null_mut(),
-            extent: core::ptr::null_mut(),
-        }
-    }
-}
-
-pub fn ext4_first_extent(hdr: *const Ext4ExtentHeader) -> *const Ext4Extent {
-    if hdr.is_null() {
-        return ptr::null_mut();
-    }
-    unsafe { hdr.add(1) as *const Ext4Extent }
-}
-
-pub fn ext4_first_extent_mut(hdr: *mut Ext4ExtentHeader) -> *mut Ext4Extent {
-    ext4_first_extent(hdr) as *mut Ext4Extent
-}
-
-pub fn ext4_first_extent_index(hdr: *const Ext4ExtentHeader) -> *const Ext4ExtentIndex {
-    ext4_first_extent(hdr) as *const Ext4ExtentIndex
-}
-
-pub fn ext4_first_extent_index_mut(hdr: *mut Ext4ExtentHeader) -> *mut Ext4ExtentIndex {
-    ext4_first_extent(hdr) as *mut Ext4ExtentIndex
-}
-
-#[allow(unused)]
-pub fn ext4_last_extent(hdr: *const Ext4ExtentHeader) -> *const Ext4Extent {
-    if hdr.is_null() {
-        return ptr::null_mut();
-    }
-    // Get the number of extents from header
-    let count = unsafe { (*hdr).entries_count as usize };
-    if count == 0 {
-        return ptr::null_mut();
-    }
-    // Get the pointer to the first extent
-    let first = ext4_first_extent(hdr);
-    // Add count - 1 offset to get the last extent
-    unsafe { first.add(count - 1) }
-}
-
-pub fn ext4_last_extent_mut(hdr: *mut Ext4ExtentHeader) -> *mut Ext4Extent {
-    ext4_last_extent(hdr) as *mut Ext4Extent
-}
-
-#[allow(unused)]
-pub fn ext4_last_extent_index(hdr: *const Ext4ExtentHeader) -> *const Ext4ExtentIndex {
-    if hdr.is_null() {
-        return ptr::null_mut();
-    }
-    // Get the number of extents from header
-    let count = unsafe { (*hdr).entries_count as usize };
-    if count == 0 {
-        return ptr::null_mut();
-    }
-    // Get the pointer to the first extent_index
-    let first = ext4_first_extent_index(hdr);
-    // Add count - 1 offset to get the last extent_index
-    unsafe { first.add(count - 1) }
-}
-
-pub fn ext4_last_extent_index_mut(hdr: *mut Ext4ExtentHeader) -> *mut Ext4ExtentIndex {
-    ext4_last_extent_index(hdr) as *mut Ext4ExtentIndex
-}
-
-pub fn ext4_extent_hdr(inode: &Ext4Inode) -> *const Ext4ExtentHeader {
-    &inode.block as *const [u32; 15] as *const Ext4ExtentHeader
-}
-
-pub fn ext4_extent_hdr_mut(inode: &mut Ext4Inode) -> *mut Ext4ExtentHeader {
-    ext4_extent_hdr(inode) as *mut Ext4ExtentHeader
-}
-
-pub fn ext4_depth(inode: &Ext4Inode) -> u16 {
-    unsafe { (*ext4_extent_hdr(inode)).depth }
-}
-
-pub fn ext4_idx_pblock(idx: *mut Ext4ExtentIndex) -> u64 {
-    // 如果索引为空,返回0
-    if idx.is_null() {
-        return 0;
-    }
-    // 获取索引的低32位物理块号
-    let pblock_lo = unsafe { (*idx).leaf_lo } as u64;
-    // 如果支持64位物理块号,获取索引的高16位物理块号
-    let pblock_hi = unsafe { (*idx).leaf_hi } as u64;
-    // 返回索引的物理块号
-    (pblock_hi << 32) | pblock_lo
-}
-
-/// 定义ext4_ext_binsearch函数,接受一个指向ext4_extent_path的可变引用和一个逻辑块号
-///
-/// 返回一个布尔值,表示是否找到了对应的extent
-pub fn ext4_ext_binsearch(path: &mut Ext4ExtentPath, block: u32) -> bool {
-    // 获取extent header的引用
-    // let eh = unsafe { &*path.header };
-    let eh = path.header;
-
-    unsafe {
-        if (*eh).entries_count == 0 {
-            return false;
-        }
-    }
-
-    // 定义左右两个指针,分别指向第一个和最后一个extent
-    let mut l = unsafe { ext4_first_extent_mut(eh).add(1) };
-    let mut r = ext4_last_extent_mut(eh);
-
-    // 如果extent header中没有有效的entry,直接返回false
-    unsafe {
-        if (*eh).entries_count == 0 {
-            return false;
+            pblock,
+            leaf: true,
+            index,
         }
     }
-    // 使用while循环进行二分查找
-    while l <= r {
-        // 计算中间指针
-        let m = unsafe { l.add((r as usize - l as usize) / 2) };
-        // 获取中间指针所指向的extent的引用
-        let ext = unsafe { &*m };
-        // 比较逻辑块号和extent的第一个块号
-        if block < ext.first_block {
-            // 如果逻辑块号小于extent的第一个块号,说明目标在左半边,将右指针移动到中间指针的左边
-            r = unsafe { m.sub(1) };
-        } else {
-            // 如果逻辑块号大于或等于extent的第一个块号,说明目标在右半边,将左指针移动到中间指针的右边
-            l = unsafe { m.add(1) };
-        }
-    }
-    // 循环结束后,将path的extent字段设置为左指针的前一个位置
-    path.extent = unsafe { l.sub(1) };
-    // 返回true,表示找到了对应的extent
-    true
-}
-
-pub fn ext4_ext_binsearch_idx(path: &mut Ext4ExtentPath, block: Ext4LogicBlockId) -> bool {
-    // 获取extent header的引用
-    let eh = path.header;
-
-    // 定义左右两个指针,分别指向第一个和最后一个extent
-    let mut l = unsafe { ext4_first_extent_index_mut(eh).add(1) };
-    let mut r = ext4_last_extent_index_mut(eh);
-
-    // 如果extent header中没有有效的entry,直接返回false
-    unsafe {
-        if (*eh).entries_count == 0 {
-            return false;
-        }
-    }
-    // 使用while循环进行二分查找
-    while l <= r {
-        // 计算中间指针
-        let m = unsafe { l.add((r as usize - l as usize) / 2) };
-        // 获取中间指针所指向的extent的引用
-        let ext = unsafe { &*m };
-        // 比较逻辑块号和extent的第一个块号
-        if block < ext.first_block {
-            // 如果逻辑块号小于extent的第一个块号,说明目标在左半边,将右指针移动到中间指针的左边
-            r = unsafe { m.sub(1) };
-        } else {
-            // 如果逻辑块号大于或等于extent的第一个块号,说明目标在右半边,将左指针移动到中间指针的右边
-            l = unsafe { m.add(1) };
-        }
-    }
-    // 循环结束后,将path的extent字段设置为左指针的前一个位置
-    path.index = unsafe { l.sub(1) };
-    // 返回true,表示找到了对应的extent
-    true
-}
-
-#[allow(unused)]
-pub fn ext4_ext_find_extent(eh: *mut Ext4ExtentHeader, block: Ext4LogicBlockId) -> *mut Ext4Extent {
-    // 初始化一些变量
-    let mut low: i32;
-    let mut high: i32;
-    let mut mid: i32;
-    let mut ex: *mut Ext4Extent;
-
-    // 如果头部的extent数为0,返回空指针
-    if eh.is_null() || unsafe { (*eh).entries_count } == 0 {
-        return core::ptr::null_mut();
-    }
-
-    // 从头部获取第一个extent的指针
-    ex = ext4_first_extent_mut(eh);
-
-    // 如果头部的深度不为0,返回空指针
-    if unsafe { (*eh).depth } != 0 {
-        return core::ptr::null_mut();
-    }
-
-    // 使用二分查找法在extent数组中查找逻辑块号
-    low = 0;
-    high = unsafe { (*eh).entries_count - 1 } as i32;
-    while low <= high {
-        // 计算中间位置
-        mid = (low + high) / 2;
-
-        // 获取中间位置的extent的指针
-        ex = unsafe { ex.add(mid as usize) };
-
-        // 比较extent的逻辑块号和目标逻辑块号
-        if block >= unsafe { (*ex).first_block } {
-            // 如果目标逻辑块号大于等于extent的逻辑块号,说明目标在右半部分
-            low = mid + 1;
-        } else {
-            // 如果目标逻辑块号小于extent的逻辑块号,说明目标在左半部分
-            high = mid - 1;
-        }
-    }
-
-    // 如果没有找到目标,返回最后一个小于目标的extent的指针
-    if high < 0 {
-        return core::ptr::null_mut();
-    } else {
-        return unsafe { ex.add(high as usize) };
-    }
 }

+ 36 - 25
src/ext4_defs/inode.rs

@@ -41,7 +41,7 @@ pub struct Ext4Inode {
     pub blocks: u32,
     pub flags: u32,
     pub osd1: u32,
-    pub block: [u32; 15],
+    pub block: [u32; 15], // Block bitmap or extent tree
     pub generation: u32,
     pub file_acl: u32,
     pub size_hi: u32,
@@ -83,11 +83,11 @@ impl Ext4Inode {
         self.mode |= mode;
     }
 
-    pub fn inode_type(&self, super_block: &Ext4Superblock) -> u32{
+    pub fn inode_type(&self, super_block: &Ext4Superblock) -> u32 {
         let mut v = self.mode;
 
-        if super_block.creator_os() == EXT4_SUPERBLOCK_OS_HURD{
-            v |= ((self.osd2.l_i_file_acl_high as u32 ) << 16) as u16;
+        if super_block.creator_os() == EXT4_SUPERBLOCK_OS_HURD {
+            v |= ((self.osd2.l_i_file_acl_high as u32) << 16) as u16;
         }
 
         (v & EXT4_INODE_MODE_TYPE_MASK) as u32
@@ -160,26 +160,6 @@ impl Ext4Inode {
         }
     }
 
-    pub fn extent_header(&mut self) -> *mut Ext4ExtentHeader {
-        let header_ptr = (&mut self.block) as *mut [u32; 15] as *mut Ext4ExtentHeader;
-        header_ptr
-    }
-
-    pub fn extent_tree_init(&mut self) {
-        let mut header = Ext4ExtentHeader::default();
-        header.set_depth(0);
-        header.set_entries_count(0);
-        header.set_generation(0);
-        header.set_magic();
-        header.set_max_entries_count(4 as u16);
-
-        unsafe {
-            let header_ptr = &header as *const Ext4ExtentHeader as *const u32;
-            let array_ptr = &mut self.block as *mut [u32; 15] as *mut u32;
-            core::ptr::copy_nonoverlapping(header_ptr, array_ptr, 3);
-        }
-    }
-
     pub fn blocks_count(&self) -> u64 {
         let mut blocks = self.blocks as u64;
         if self.osd2.l_i_blocks_high != 0 {
@@ -210,7 +190,7 @@ impl Ext4Inode {
         let index = (inode_id - 1) % inodes_per_group;
 
         let bg = Ext4BlockGroupDesc::load(block_device, super_block, group as usize).unwrap();
-        bg.inode_table_blk_num() as usize * BLOCK_SIZE + (index * inode_size as u32) as usize
+        bg.inode_table_first_block() as usize * BLOCK_SIZE + (index * inode_size as u32) as usize
     }
 
     fn read_from_disk(
@@ -299,6 +279,37 @@ impl Ext4Inode {
         self.set_checksum(super_block, inode_id);
         self.sync_to_disk_without_csum(block_device, super_block, inode_id)
     }
+
+    /* Extent methods */
+
+    pub fn extent_header(&self) -> &'static Ext4ExtentHeader {
+        unsafe {
+            (&self.block as *const [u32; 15] as *const Ext4ExtentHeader)
+                .as_ref()
+                .unwrap()
+        }
+    }
+
+    pub fn extent_header_mut(&mut self) -> &'static mut Ext4ExtentHeader {
+        unsafe {
+            (&mut self.block as *mut [u32; 15] as *mut Ext4ExtentHeader)
+                .as_mut()
+                .unwrap()
+        }
+    }
+
+    pub fn extent_depth(&self) -> u16 {
+        self.extent_header().depth()
+    }
+
+    pub fn extent_tree_init(&mut self) {
+        let header = Ext4ExtentHeader::new(0, 4, 0, 0);
+        let header_ptr = &header as *const Ext4ExtentHeader as *const u32;
+        let array_ptr = &mut self.block as *mut [u32; 15] as *mut u32;
+        unsafe {
+            core::ptr::copy_nonoverlapping(header_ptr, array_ptr, 3);
+        }
+    }
 }
 
 /// A combination of an `Ext4Inode` and its id