[U-Boot] [PATCH] ext4: cache first extent index blocks (#06343)
Christophe Ronco
c.ronco at kerlink.fr
Fri Oct 27 14:18:11 UTC 2017
Extent index blocks are read many times when reading completely a big file.
This is time costly if underlying driver is slow.
Caching the first index blocks cost a bit of RAM but speed up file reading a lot.
---
fs/ext4/ext4_common.c | 93 ++++++++++++++++++++++++++++++++++++++++++++++++---
fs/ext4/ext4_common.h | 16 +++++++++
fs/ext4/ext4fs.c | 16 +++++++--
3 files changed, 117 insertions(+), 8 deletions(-)
diff --git a/fs/ext4/ext4_common.c b/fs/ext4/ext4_common.c
index cab5465..68ab2e9 100644
--- a/fs/ext4/ext4_common.c
+++ b/fs/ext4/ext4_common.c
@@ -44,6 +44,7 @@ int ext4fs_indir3_size;
int ext4fs_indir3_blkno = -1;
struct ext2_inode *g_parent_inode;
static int symlinknest;
+struct ext4_extent_blocs ext4fs_extents_blocs;
#if defined(CONFIG_EXT4_WRITE)
uint32_t ext4fs_div_roundup(uint32_t size, uint32_t n)
@@ -1413,6 +1414,7 @@ static struct ext4_extent_header *ext4fs_get_extent_block
unsigned long long block;
int blksz = EXT2_BLOCK_SIZE(data);
int i;
+ int found;
while (1) {
index = (struct ext4_extent_idx *)(ext_block + 1);
@@ -1435,11 +1437,24 @@ static struct ext4_extent_header *ext4fs_get_extent_block
block = le16_to_cpu(index[i].ei_leaf_hi);
block = (block << 32) + le32_to_cpu(index[i].ei_leaf_lo);
- if (ext4fs_devread((lbaint_t)block << log2_blksz, 0, blksz,
- buf))
- ext_block = (struct ext4_extent_header *)buf;
- else
- return 0;
+ /* look in saved extent blocks */
+ found = 0;
+ for (i = 0; i < ext4fs_extents_blocs.bloc_nb; i++) {
+ if (ext4fs_extents_blocs.ext_blocs[i].block == block) {
+ memcpy(buf, ext4fs_extents_blocs.ext_blocs[i].ext_header,
+ blksz);
+ ext_block = (struct ext4_extent_header *)buf;
+ found = 1;
+ }
+ }
+
+ if (found == 0) {
+ if (ext4fs_devread((lbaint_t)block << log2_blksz, 0,
+ blksz, buf))
+ ext_block = (struct ext4_extent_header *)buf;
+ else
+ return 0;
+ }
}
}
@@ -1465,6 +1480,74 @@ static int ext4fs_blockgroup
(char *)blkgrp);
}
+void ext4fs_init_extents_blocks_global(void)
+{
+ memset(&ext4fs_extents_blocs, 0, sizeof(struct ext4_extent_blocs));
+}
+
+int ext4fs_read_extents_blocks(struct ext2_inode *inode)
+{
+ int blksz = EXT2_BLOCK_SIZE(ext4fs_root);
+ int log2_blksz;
+ struct ext4_extent_header *ext_block;
+ struct ext4_extent_idx *index;
+ unsigned long long block;
+ int entries;
+ char *buf;
+ int i;
+
+ ext4fs_extents_blocs.bloc_nb = 0;
+ log2_blksz = LOG2_BLOCK_SIZE(ext4fs_root)
+ - get_fs()->dev_desc->log2blksz;
+
+ if ((le32_to_cpu(inode->flags) & EXT4_EXTENTS_FL) == 0)
+ return 0;
+
+ ext_block = (struct ext4_extent_header *)inode->b.blocks.dir_blocks;
+
+ if (le16_to_cpu(ext_block->eh_magic) != EXT4_EXT_MAGIC)
+ return 0;
+ if (ext_block->eh_depth == 0)
+ return 0;
+
+ entries = le16_to_cpu(ext_block->eh_entries);
+ index = (struct ext4_extent_idx *)(ext_block + 1);
+
+ for (i = 0; (i < entries) && (i < MAX_EXTENT_BLOCS); i++) {
+ /* bloc number */
+ block = le16_to_cpu(index[i].ei_leaf_hi);
+ block = (block << 32) + le32_to_cpu(index[i].ei_leaf_lo);
+ /* bloc data */
+ buf = zalloc(blksz);
+ if (!buf)
+ break;
+ if (ext4fs_devread((lbaint_t)block << log2_blksz, 0, blksz,
+ buf) == 0) {
+ free(buf);
+ break;
+ }
+ ext4fs_extents_blocs.ext_blocs[i].block = block;
+ ext4fs_extents_blocs.ext_blocs[i].ext_header =
+ (struct ext4_extent_header *)buf;
+ }
+ ext4fs_extents_blocs.bloc_nb = i;
+ return i;
+}
+
+void ext4fs_free_extents_blocks(void)
+{
+ int i;
+
+ for (i = 0; i < ext4fs_extents_blocs.bloc_nb; i++) {
+ if (ext4fs_extents_blocs.ext_blocs[i].ext_header) {
+ free(ext4fs_extents_blocs.ext_blocs[i].ext_header);
+ ext4fs_extents_blocs.ext_blocs[i].ext_header = NULL;
+ ext4fs_extents_blocs.ext_blocs[i].block = 0;
+ }
+ }
+ ext4fs_extents_blocs.bloc_nb = 0;
+}
+
int ext4fs_read_inode(struct ext2_data *data, int ino, struct ext2_inode *inode)
{
struct ext2_block_group blkgrp;
diff --git a/fs/ext4/ext4_common.h b/fs/ext4/ext4_common.h
index 48fd2ac..0f80856 100644
--- a/fs/ext4/ext4_common.h
+++ b/fs/ext4/ext4_common.h
@@ -41,6 +41,18 @@
#define SUPERBLOCK_SIZE 1024
#define F_FILE 1
+#define MAX_EXTENT_BLOCS 10
+
+struct ext4_extent_bloc {
+ unsigned long long block;
+ struct ext4_extent_header *ext_header;
+};
+
+struct ext4_extent_blocs {
+ int bloc_nb;
+ struct ext4_extent_bloc ext_blocs[MAX_EXTENT_BLOCS];
+};
+
static inline void *zalloc(size_t size)
{
void *p = memalign(ARCH_DMA_MINALIGN, size);
@@ -57,6 +69,10 @@ int ext4fs_find_file(const char *path, struct ext2fs_node *rootnode,
int ext4fs_iterate_dir(struct ext2fs_node *dir, char *name,
struct ext2fs_node **fnode, int *ftype);
+void ext4fs_init_extents_blocks_global(void);
+int ext4fs_read_extents_blocks(struct ext2_inode *inode);
+void ext4fs_free_extents_blocks(void);
+
#if defined(CONFIG_EXT4_WRITE)
uint32_t ext4fs_div_roundup(uint32_t size, uint32_t n);
int ext4fs_checksum_update(unsigned int i);
diff --git a/fs/ext4/ext4fs.c b/fs/ext4/ext4fs.c
index 258b937..88db1fb 100644
--- a/fs/ext4/ext4fs.c
+++ b/fs/ext4/ext4fs.c
@@ -70,6 +70,12 @@ int ext4fs_read_file(struct ext2fs_node *node, loff_t pos,
blockcnt = lldiv(((len + pos) + blocksize - 1), blocksize);
+ ext4fs_init_extents_blocks_global();
+ if (blockcnt > 100) {
+ /* Big reading: read extent blocks tree if any */
+ ext4fs_read_extents_blocks(&(node->inode));
+ }
+
for (i = lldiv(pos, blocksize); i < blockcnt; i++) {
lbaint_t blknr;
int blockoff = pos - (blocksize * i);
@@ -77,7 +83,7 @@ int ext4fs_read_file(struct ext2fs_node *node, loff_t pos,
int skipfirst = 0;
blknr = read_allocated_block(&(node->inode), i);
if (blknr < 0)
- return -1;
+ goto error;
blknr = blknr << log2_fs_blocksize;
@@ -134,7 +140,7 @@ int ext4fs_read_file(struct ext2fs_node *node, loff_t pos,
delayed_extent,
delayed_buf);
if (status == 0)
- return -1;
+ goto error;
previous_block_number = -1;
}
memset(buf, 0, blocksize - skipfirst);
@@ -147,12 +153,16 @@ int ext4fs_read_file(struct ext2fs_node *node, loff_t pos,
delayed_skipfirst, delayed_extent,
delayed_buf);
if (status == 0)
- return -1;
+ goto error;
previous_block_number = -1;
}
*actread = len;
+ ext4fs_free_extents_blocks();
return 0;
+error:
+ ext4fs_free_extents_blocks();
+ return -1;
}
int ext4fs_ls(const char *dirname)
--
2.7.4
More information about the U-Boot
mailing list