Skip to content

Commit

Permalink
ext2: Improve performance of non-ext4 inode reads by caching the bloc…
Browse files Browse the repository at this point in the history
…k chain
  • Loading branch information
mintsuki committed Nov 14, 2020
1 parent 3fe4cb8 commit 7a03b32
Show file tree
Hide file tree
Showing 4 changed files with 67 additions and 37 deletions.
Binary file modified limine-pxe.bin
Binary file not shown.
Binary file modified limine.bin
Binary file not shown.
103 changes: 66 additions & 37 deletions stage2/fs/ext2.c
Original file line number Diff line number Diff line change
Expand Up @@ -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 */
Expand Down Expand Up @@ -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,
Expand Down Expand Up @@ -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++;
Expand All @@ -228,18 +284,20 @@ static int ext2_parse_dirent(struct ext2_dir_entry *dir, struct ext2_file_handle
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);

Expand Down Expand Up @@ -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) {
Expand Down Expand Up @@ -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;

Expand Down Expand Up @@ -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);
Expand Down
1 change: 1 addition & 0 deletions stage2/fs/ext2.h
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down

0 comments on commit 7a03b32

Please sign in to comment.