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....@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....@ge.com> Signed-off-by: Martyn Welch <martyn.we...@collabora.co.uk> Reviewed-by: Stefano Babic <sba...@denx.de> Applied? Thanks! -- Tom
signature.asc
Description: PGP signature
_______________________________________________ U-Boot mailing list U-Boot@lists.denx.de https://lists.denx.de/listinfo/u-boot