:: commit 7a03b32167538901330adddf505aac33d96def98

mintsuki <mintsuki@protonmail.com> — 2020-11-14 03:13

parents: 3fe4cb8298

ext2: Improve performance of non-ext4 inode reads by caching the block chain

diff --git a/limine-pxe.bin b/limine-pxe.bin
index 80a42571..a5b93fc4 100644
Binary files a/limine-pxe.bin and b/limine-pxe.bin differ
diff --git a/limine.bin b/limine.bin
index 3e9b83e4..7f400ab7 100644
Binary files a/limine.bin and b/limine.bin differ
diff --git a/stage2/fs/ext2.c b/stage2/fs/ext2.c
index 396002a1..6a75ea95 100644
--- a/stage2/fs/ext2.c
+++ b/stage2/fs/ext2.c
@@ -5,6 +5,7 @@
 #include <drivers/disk.h>

 #include <lib/libc.h>

 #include <lib/blib.h>

+#include <lib/print.h>

 #include <mm/pmm.h>

 

 /* EXT2 Filesystem States */

@@ -157,7 +158,7 @@ struct ext4_extent_idx {
 

 static int inode_read(void *buf, uint64_t loc, uint64_t count,

                       uint64_t block_size, struct ext2_inode *inode,

-                      struct part *part);

+                      struct part *part, uint32_t *alloc_map);

 

 // parse an inode given the partition base and inode number

 static int ext2_get_inode(struct ext2_inode *ret, struct part *part,

@@ -207,6 +208,61 @@ static int ext2_get_inode(struct ext2_inode *ret, struct part *part,
     return 0;

 }

 

+static uint32_t *create_alloc_map(struct ext2_file_handle *fd,

+                            struct ext2_inode *inode) {

+    if (inode->i_flags & EXT4_EXTENTS_FLAG)

+        return NULL;

+

+    size_t entries_per_block = fd->block_size / sizeof(uint32_t);

+

+    // Cache the map of blocks

+    uint32_t *alloc_map = ext_mem_alloc(inode->i_blocks_count * sizeof(uint32_t));

+    for (uint32_t i = 0; i < inode->i_blocks_count; i++) {

+        uint32_t block = i;

+        if (block < 12) {

+            // Direct block

+            alloc_map[i] = inode->i_blocks[block];

+        } else {

+            // Indirect block

+            block -= 12;

+            if (block >= entries_per_block) {

+                // Double indirect block

+                block -= entries_per_block;

+                uint32_t index = block / entries_per_block;

+                if (index >= entries_per_block) {

+                    // Triple indirect block

+                    panic("ext2: triply indirect blocks unsupported");

+                }

+                uint32_t indirect_block;

+                part_read(

+                    &fd->part, &indirect_block,

+                    inode->i_blocks[13] * fd->block_size + index * sizeof(uint32_t),

+                    sizeof(uint32_t)

+                );

+                for (uint32_t j = 0; j < entries_per_block; j++) {

+                    if (i + j >= inode->i_blocks_count)

+                        return alloc_map;

+                    part_read(

+                        &fd->part, &alloc_map[i + j],

+                        indirect_block * fd->block_size + j * sizeof(uint32_t),

+                        sizeof(uint32_t)

+                    );

+                }

+                i += entries_per_block - 1;

+            } else {

+                // Single indirect block

+                part_read(

+                    &fd->part, &alloc_map[i],

+                    inode->i_blocks[12] * fd->block_size + block * sizeof(uint32_t),

+                    sizeof(uint32_t)

+                );

+            }

+        }

+    }

+

+    return alloc_map;

+}

+

 static int ext2_parse_dirent(struct ext2_dir_entry *dir, struct ext2_file_handle *fd, struct ext2_superblock *sb, const char *path) {

     if (*path == '/')

         path++;

@@ -228,18 +284,20 @@ next:
     else

         path++;

 

+    uint32_t *alloc_map = create_alloc_map(fd, &current_inode);

+

     for (uint32_t i = 0; i < current_inode.i_size; ) {

         // preliminary read

         inode_read(dir, i, sizeof(struct ext2_dir_entry),

                    fd->block_size, &current_inode,

-                   &fd->part);

+                   &fd->part, alloc_map);

 

         // name read

         char name[dir->name_len + 1];

 

         memset(name, 0, dir->name_len + 1);

         inode_read(name, i + sizeof(struct ext2_dir_entry), dir->name_len,

-                   fd->block_size, &current_inode, &fd->part);

+                   fd->block_size, &current_inode, &fd->part, alloc_map);

 

         int r = strcmp(token, name);

 

@@ -285,12 +343,14 @@ int ext2_open(struct ext2_file_handle *ret, struct part *part, const char *path)
     if ((ret->inode.i_mode & 0xf000) == EXT2_INO_DIRECTORY)

         panic("ext2: Requested file \"%s\" is a directory!", path);

 

+    ret->alloc_map = create_alloc_map(ret, &ret->inode);

+

     return 0;

 }

 

 int ext2_read(struct ext2_file_handle *file, void *buf, uint64_t loc, uint64_t count) {

     return inode_read(buf, loc, count, file->block_size, &file->inode,

-                      &file->part);

+                      &file->part, file->alloc_map);

 }

 

 static struct ext4_extent_header* ext4_find_leaf(struct ext4_extent_header* ext_block, uint32_t read_block, uint64_t block_size, struct part *part) {

@@ -327,7 +387,7 @@ static struct ext4_extent_header* ext4_find_leaf(struct ext4_extent_header* ext_
 

 static int inode_read(void *buf, uint64_t loc, uint64_t count,

                       uint64_t block_size, struct ext2_inode *inode,

-                      struct part *part) {

+                      struct part *part, uint32_t *alloc_map) {

     for (uint64_t progress = 0; progress < count;) {

         uint64_t block = (loc + progress) / block_size;

 

@@ -366,39 +426,8 @@ static int inode_read(void *buf, uint64_t loc, uint64_t count,
             } else {

                 panic("extent for block not found");

             }

-        } else if (block < 12) {

-            // Direct block

-            block_index = inode->i_blocks[block];

         } else {

-            // Indirect block

-            block -= 12;

-            if (block * sizeof(uint32_t) >= block_size) {

-                // Double indirect block

-                block -= block_size / sizeof(uint32_t);

-                uint32_t index  = block / (block_size / sizeof(uint32_t));

-                if (index * sizeof(uint32_t) >= block_size) {

-                    // Triple indirect block

-                    panic("ext2: triply indirect blocks unsupported");

-                }

-                uint32_t offset = block % (block_size / sizeof(uint32_t));

-                uint32_t indirect_block;

-                part_read(

-                    part, &indirect_block,

-                    inode->i_blocks[13] * block_size + index * sizeof(uint32_t),

-                    sizeof(uint32_t)

-                );

-                part_read(

-                    part, &block_index,

-                    indirect_block * block_size + offset * sizeof(uint32_t),

-                    sizeof(uint32_t)

-                );

-            } else {

-                part_read(

-                    part, &block_index,

-                    inode->i_blocks[12] * block_size + block * sizeof(uint32_t),

-                    sizeof(uint32_t)

-                );

-            }

+            block_index = alloc_map[block];

         }

 

         part_read(part, buf + progress, (block_index * block_size) + offset, chunk);

diff --git a/stage2/fs/ext2.h b/stage2/fs/ext2.h
index f69e4ad6..3109d49b 100644
--- a/stage2/fs/ext2.h
+++ b/stage2/fs/ext2.h
@@ -54,6 +54,7 @@ struct ext2_file_handle {
     struct ext2_inode root_inode;

     struct ext2_inode inode;

     uint64_t block_size;

+    uint32_t *alloc_map;

 };

 

 int ext2_check_signature(struct part *part);

tab: 248 wrap: offon