
On Fri, Oct 27, 2017 at 04:18:11PM +0200, Christophe Ronco wrote:
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)
Is this still needed with: commit ecdfb4195b20eb2dcde3c4083170016c13c69e8b Author: Ian Ray ian.ray@ge.com Date: Wed Nov 8 15:35:10 2017 +0000
ext4: recover from filesystem corruption when reading
Some fixes when reading EXT files and directory entries were identified after using e2fuzz to corrupt an EXT3 filesystem:
- Stop reading directory entries if the offset becomes badly aligned.
- Avoid overwriting memory by clamping the length used to zero the buffer in ext4fs_read_file. Also sanity check blocksize.
Signed-off-by: Ian Ray ian.ray@ge.com Signed-off-by: Martyn Welch martyn.welch@collabora.co.uk Reviewed-by: Stefano Babic sbabic@denx.de
Applied? Thanks!