Przeglądaj źródła

fix: add dir entry

liujingx 11 miesięcy temu
rodzic
commit
ee001c24be
6 zmienionych plików z 116 dodań i 100 usunięć
  1. 42 19
      ext4_test/src/main.rs
  2. 26 25
      src/ext4/dir.rs
  3. 2 3
      src/ext4/extent.rs
  4. 5 3
      src/ext4/file.rs
  5. 8 35
      src/ext4_defs/dir_entry.rs
  6. 33 15
      src/ext4_defs/extent.rs

+ 42 - 19
ext4_test/src/main.rs

@@ -1,4 +1,5 @@
 use ext4_rs::{Block, BlockDevice, Ext4, BLOCK_SIZE};
+use log::warn;
 use simple_logger::SimpleLogger;
 use std::fs::{File, OpenOptions};
 use std::io::{Read, Seek, SeekFrom, Write};
@@ -28,6 +29,9 @@ impl BlockDevice for BlockFile {
     }
 
     fn write_block(&self, block: &Block) {
+        if block.block_id == 2135 {
+            warn!("!!!!! 2135");
+        }
         let mut file = &self.0;
         let _r = file.seek(SeekFrom::Start(block.block_id * BLOCK_SIZE as u64));
         let _r = file.write_all(&block.data);
@@ -58,32 +62,49 @@ fn open_ext4() -> Ext4 {
 }
 
 fn mkdir_test(ext4: &mut Ext4) {
-    ext4.mkdir("1").expect("mkdir failed");
-    ext4.mkdir("1/2").expect("mkdir failed");
-    ext4.mkdir("1/2/3").expect("mkdir failed");
-    ext4.mkdir("1/2/3/4").expect("mkdir failed");
-    ext4.mkdir("2").expect("mkdir failed");
-    ext4.mkdir("2/3").expect("mkdir failed");
-    ext4.mkdir("2/3/4").expect("mkdir failed");
-    ext4.mkdir("3").expect("mkdir failed");
+    ext4.mkdir("d1").expect("mkdir failed");
+    ext4.mkdir("d1/d2").expect("mkdir failed");
+    ext4.mkdir("d1/d2/d3").expect("mkdir failed");
+    ext4.mkdir("d1/d2/d3/d4").expect("mkdir failed");
+    ext4.mkdir("d2").expect("mkdir failed");
+    ext4.mkdir("d2/d3").expect("mkdir failed");
+    ext4.mkdir("d2/d3/d4").expect("mkdir failed");
+    ext4.mkdir("d3").expect("mkdir failed");
 }
 
 fn open_test(ext4: &mut Ext4) {
-    ext4.open("1/2/3/4/5", "w+", true).expect("open failed");
-    ext4.open("1/2/3/4/5", "r", true).expect("open failed");
-    ext4.open("1/2/3/4/5", "a", true).expect("open failed");
-    ext4.open("2/4", "w+", true).expect("open failed");
+    ext4.open("d1/d2/d3/d4/f1", "w+", true)
+        .expect("open failed");
+    ext4.open("d1/d2/d3/d4/f1", "r", true).expect("open failed");
+    ext4.open("d1/d2/d3/d4/f5", "a", true).expect("open failed");
+    ext4.open("d2/f4", "w+", true).expect("open failed");
+    ext4.open("f1", "w+", true).expect("open failed");
 }
 
 fn read_write_test(ext4: &mut Ext4) {
-    let buffer = "hello world".as_bytes();
-    let mut wfile = ext4.open("1/2/3/4/5", "w+", true).expect("open failed");
-    ext4.write(&mut wfile, buffer).expect("write failed");
-    let mut rfile = ext4.open("1/2/3/4/5", "r", true).expect("open failed");
-    let mut buffer2 = vec![0u8; buffer.len()];
-    ext4.read(&mut rfile, &mut buffer2, buffer.len())
+    let wbuffer = "hello world".as_bytes();
+    let mut wfile = ext4.open("d3/f0", "w+", true).expect("open failed");
+    ext4.write(&mut wfile, wbuffer).expect("write failed");
+
+    let mut rbuffer = vec![0u8; wbuffer.len()];
+    let mut rfile = ext4.open("d3/f0", "r", true).expect("open failed");
+    ext4.read(&mut rfile, &mut rbuffer, wbuffer.len())
         .expect("read failed");
-    assert_eq!(buffer, buffer2);
+
+    assert_eq!(wbuffer, rbuffer);
+}
+
+fn large_read_write_test(ext4: &mut Ext4) {
+    let wbuffer = vec![99u8; 1024 * 1024];
+    let mut wfile = ext4.open("d3/f2", "w+", true).expect("open failed");
+    ext4.write(&mut wfile, &wbuffer).expect("write failed");
+
+    let mut rfile = ext4.open("d3/f2", "r", true).expect("open failed");
+    let mut rbuffer = vec![0u8; wbuffer.len()];
+    ext4.read(&mut rfile, &mut rbuffer, wbuffer.len())
+        .expect("read failed");
+
+    assert_eq!(wbuffer, rbuffer);
 }
 
 fn main() {
@@ -98,4 +119,6 @@ fn main() {
     println!("open test done");
     read_write_test(&mut ext4);
     println!("read write test done");
+    large_read_write_test(&mut ext4);
+    println!("large read write test done");
 }

+ 26 - 25
src/ext4/dir.rs

@@ -6,14 +6,13 @@ use crate::prelude::*;
 impl Ext4 {
     /// Find a directory entry that matches a given name under a parent directory
     pub(super) fn dir_find_entry(&self, parent: &InodeRef, name: &str) -> Result<DirEntry> {
-        info!("Dir find entry: {} under parent {}", name, parent.id);
+        info!("Dir find entry {} under parent {}", name, parent.id);
         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
-            debug!("Parent {:?}", parent.inode);
             let fblock = self.extent_get_pblock(parent, iblock)?;
             // Load block from disk
             let block = self.block_device.read_block(fblock);
@@ -29,9 +28,11 @@ impl Ext4 {
 
     /// Find a directory entry that matches a given name in a given block
     fn find_entry_in_block(block: &Block, name: &str) -> Result<DirEntry> {
+        info!("Dir find entry {} in block {}", name, block.block_id);
         let mut offset = 0;
         while offset < BLOCK_SIZE {
             let de = DirEntry::from_bytes(&block.data[offset..]);
+            debug!("Dir entry: {} {:?}", de.rec_len(), de.name());
             offset += de.rec_len() as usize;
             // Unused dir entry
             if de.unused() {
@@ -67,7 +68,12 @@ impl Ext4 {
             // Load the parent block from disk
             let mut block = self.block_device.read_block(fblock);
             // Try inserting the entry to parent block
-            self.insert_entry_to_old_block(&mut block, child, path)?;
+            if self
+                .insert_entry_to_old_block(&mut block, child, path)
+                .is_ok()
+            {
+                return Ok(());
+            }
             // Current block has no enough space
             iblock += 1;
         }
@@ -78,17 +84,15 @@ impl Ext4 {
         // Load new block
         let mut new_block = self.block_device.read_block(fblock);
         // Write the entry to block
-        self.insert_entry_to_new_block(&mut new_block, child, path)
+        self.insert_entry_to_new_block(&mut new_block, child, path);
+
+        Ok(())
     }
 
     /// Insert a directory entry of a child inode into a new parent block.
     /// A new block must have enough space
-    fn insert_entry_to_new_block(
-        &self,
-        dst_blk: &mut Block,
-        child: &InodeRef,
-        name: &str,
-    ) -> Result<()> {
+    fn insert_entry_to_new_block(&self, dst_blk: &mut Block, child: &InodeRef, name: &str) {
+        debug!("Dir insert entry to new block {}", dst_blk.block_id);
         // Set the entry
         let rec_len = BLOCK_SIZE - size_of::<DirEntryTail>();
         let new_entry = DirEntry::new(
@@ -108,11 +112,10 @@ impl Ext4 {
         tail.set_csum(&self.super_block, &new_entry, &dst_blk.data[..]);
         // Copy tail to block
         let tail_offset = BLOCK_SIZE - size_of::<DirEntryTail>();
-        tail.copy_to_byte_slice(&mut dst_blk.data, tail_offset);
+        dst_blk.write_offset_as(tail_offset, &tail);
 
         // Sync block to disk
         dst_blk.sync_to_disk(self.block_device.clone());
-        Ok(())
     }
 
     /// Try insert a directory entry of child inode into a parent block.
@@ -123,6 +126,8 @@ impl Ext4 {
         child: &InodeRef,
         name: &str,
     ) -> Result<()> {
+        debug!("Dir insert entry to old block {}", dst_blk.block_id);
+
         let required_size = DirEntry::required_size(name.len());
         let mut offset = 0;
 
@@ -133,6 +138,7 @@ impl Ext4 {
             // Try splitting dir entry
             // The size that `de` actually uses
             let used_size = de.used_size();
+
             // The rest size
             let free_size = rec_len - used_size;
 
@@ -142,6 +148,7 @@ impl Ext4 {
                 offset = offset + rec_len;
                 continue;
             }
+
             // Has enough space
             // Update the old entry
             de.set_rec_len(used_size as u16);
@@ -156,12 +163,11 @@ impl Ext4 {
             new_entry.copy_to_byte_slice(&mut dst_blk.data, offset + used_size);
 
             // Set tail csum
-            let mut tail =
-                DirEntryTail::from_bytes(&mut dst_blk.data, BLOCK_SIZE).unwrap();
+            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..]);
             // Write tail to blk_data
-            let tail_offset = BLOCK_SIZE - size_of::<DirEntryTail>();
-            tail.copy_to_byte_slice(&mut dst_blk.data, tail_offset);
+            dst_blk.write_offset_as(tail_offset, &tail);
 
             // Sync to disk
             dst_blk.sync_to_disk(self.block_device.clone());
@@ -174,14 +180,9 @@ impl Ext4 {
     pub fn mkdir(&mut self, path: &str) -> Result<()> {
         // get open flags
         let iflags = OpenFlags::from_str("w").unwrap();
-        self.generic_open(
-            path,
-            iflags,
-            FileType::Directory,
-            &self.read_root_inode(),
-        )
-        .map(|_| {
-            info!("ext4_dir_mk: {} ok", path);
-        })
+        self.generic_open(path, iflags, FileType::Directory, &self.read_root_inode())
+            .map(|_| {
+                info!("ext4_dir_mk: {} ok", path);
+            })
     }
 }

+ 2 - 3
src/ext4/extent.rs

@@ -49,7 +49,6 @@ impl Ext4 {
         }
         // Leaf
         let index = ex_node.search_extent(iblock);
-        debug!("Extent search {} res {:?}", iblock, index);
         path.push(ExtentSearchStep::new(pblock, index));
 
         path
@@ -256,8 +255,8 @@ impl Ext4 {
         let depth = root.header().depth() + 1;
         root.header_mut().set_depth(depth);
         root.header_mut().set_entries_count(2);
-        *root.extent_index_mut_at(0) = ExtentIndex::new(root.extent_at(0).start_lblock(), l_bid);
-        *root.extent_index_mut_at(1) = ExtentIndex::new(root.extent_at(1).start_lblock(), r_bid);
+        *root.extent_index_mut_at(0) = ExtentIndex::new(left.extent_at(0).start_lblock(), l_bid);
+        *root.extent_index_mut_at(1) = ExtentIndex::new(right.extent_at(0).start_lblock(), r_bid);
 
         // Sync to disk
         l_block.sync_to_disk(self.block_device.clone());

+ 5 - 3
src/ext4/file.rs

@@ -16,11 +16,11 @@ impl Ext4 {
         path: &str,
         flag: OpenFlags,
         ftype: FileType,
-        parent_inode: &InodeRef,
+        root: &InodeRef,
     ) -> Result<File> {
         info!("generic open: {}", path);
         // Search from the given parent inode
-        let mut parent = parent_inode.clone();
+        let mut parent = root.clone();
         let search_path = Self::split_path(path);
 
         for (i, path) in search_path.iter().enumerate() {
@@ -49,10 +49,12 @@ impl Ext4 {
                     // Write back parent and child
                     self.write_inode_with_csum(&mut parent);
                     self.write_inode_with_csum(&mut child);
+                    // Update parent
+                    parent = child;
                 }
             }
         }
-        // Reach the target
+        // `parent` is the target inode
         let mut file = File::default();
         file.inode = parent.id;
         Ok(file)

+ 8 - 35
src/ext4_defs/dir_entry.rs

@@ -7,6 +7,7 @@ use super::crc::*;
 use super::Superblock;
 use crate::constants::*;
 use crate::prelude::*;
+use crate::AsBytes;
 use alloc::string::FromUtf8Error;
 
 #[repr(C)]
@@ -38,11 +39,11 @@ impl Default for DirEnInner {
 #[repr(C)]
 #[derive(Debug)]
 pub struct DirEntry {
-    inode: InodeId,        // 该目录项指向的inode的编号
-    rec_len: u16,          // 到下一个目录项的距离
-    name_len: u8,          // 低8位的文件名长度
+    inode: InodeId,    // 该目录项指向的inode的编号
+    rec_len: u16,      // 到下一个目录项的距离
+    name_len: u8,      // 低8位的文件名长度
     inner: DirEnInner, // 联合体成员
-    name: [u8; 255],       // 文件名
+    name: [u8; 255],   // 文件名
 }
 
 impl Default for DirEntry {
@@ -152,7 +153,7 @@ impl DirEntry {
     pub fn copy_to_byte_slice(&self, slice: &mut [u8], offset: usize) {
         let de_ptr = self as *const DirEntry as *const u8;
         let slice_ptr = slice as *mut [u8] as *mut u8;
-        let count = core::mem::size_of::<DirEntry>();
+        let count = self.used_size();
         unsafe {
             core::ptr::copy_nonoverlapping(de_ptr, slice_ptr.add(offset), count);
         }
@@ -169,40 +170,12 @@ pub struct DirEntryTail {
     pub checksum: u32, // crc32c(uuid+inum+dirblock)
 }
 
-impl DirEntryTail {
-    pub fn from_bytes(data: &mut [u8], blocksize: usize) -> Option<Self> {
-        unsafe {
-            let ptr = data as *mut [u8] as *mut u8;
-            let t = *(ptr.add(blocksize - core::mem::size_of::<DirEntryTail>())
-                as *mut DirEntryTail);
-            if t.reserved_zero1 != 0 || t.reserved_zero2 != 0 {
-                log::info!("t.reserved_zero1");
-                return None;
-            }
-            if t.rec_len.to_le() != core::mem::size_of::<DirEntryTail>() as u16 {
-                log::info!("t.rec_len");
-                return None;
-            }
-            if t.reserved_ft != 0xDE {
-                log::info!("t.reserved_ft");
-                return None;
-            }
-            Some(t)
-        }
-    }
+impl AsBytes for DirEntryTail {}
 
+impl DirEntryTail {
     pub fn set_csum(&mut self, s: &Superblock, diren: &DirEntry, blk_data: &[u8]) {
         self.checksum = diren.calc_csum(s, blk_data);
     }
-
-    pub fn copy_to_byte_slice(&self, slice: &mut [u8], offset: usize) {
-        let de_ptr = self as *const DirEntryTail as *const u8;
-        let slice_ptr = slice as *mut [u8] as *mut u8;
-        let count = core::mem::size_of::<DirEntryTail>();
-        unsafe {
-            core::ptr::copy_nonoverlapping(de_ptr, slice_ptr.add(offset), count);
-        }
-    }
 }
 
 /// Fake dir entry. A normal entry without `name` field`

+ 33 - 15
src/ext4_defs/extent.rs

@@ -290,18 +290,24 @@ impl<'a> ExtentNode<'a> {
     /// position where the new extent should be inserted.
     pub fn search_extent(&self, lblock: LBlockId) -> core::result::Result<usize, usize> {
         let mut i = 0;
+        debug!("Search extent: {}", lblock);
+        self.print();
         while i < self.header().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_unwritten() { Err(i) } else { Ok(i) };
+                    let res = if extent.is_unwritten() { Err(i) } else { Ok(i) };
+                    debug!("Search res: {:?}", res);
+                    return res;
                 }
                 i += 1;
             } else {
                 break;
             }
         }
-        Err(i)
+        let res = Err(i);
+        debug!("Search res: {:?}", res);
+        return res;
     }
 
     /// Find the extent index that covers the given logical block number. The extent index
@@ -312,30 +318,42 @@ impl<'a> ExtentNode<'a> {
     /// should be inserted.
     pub fn search_extent_index(&self, lblock: LBlockId) -> core::result::Result<usize, usize> {
         let mut i = 0;
+        debug!("Search extent index: {}", lblock);
         self.print();
         while i < self.header().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);
+            if extent_index.start_lblock() > lblock {
+                break;
             }
+            i += 1;
         }
-        Err(i)
+        let res = Ok(i - 1);
+        debug!("Search res: {:?}", res);
+        return res;
     }
 
     pub fn print(&self) {
         debug!("Extent header {:?}", self.header());
         let mut i = 0;
         while i < self.header().entries_count() as usize {
-            let ext = self.extent_at(i);
-            debug!(
-                "extent[{}] start_lblock={}, start_pblock={}, len={}",
-                i,
-                ext.start_lblock(),
-                ext.start_pblock(),
-                ext.block_count()
-            );
+            if self.header().depth == 0 {
+                let ext = self.extent_at(i);
+                debug!(
+                    "extent[{}] start_lblock={}, start_pblock={}, len={}",
+                    i,
+                    ext.start_lblock(),
+                    ext.start_pblock(),
+                    ext.block_count()
+                );
+            } else {
+                let ext_idx = self.extent_index_at(i);
+                debug!(
+                    "extent_index[{}] start_lblock={}, leaf={}",
+                    i,
+                    ext_idx.start_lblock(),
+                    ext_idx.leaf()
+                )
+            }
             i += 1;
         }
     }