[U-Boot] ext4: cache first extent index blocks (#06343)
Tom Rini
trini at konsulko.com
Tue Jan 9 20:30:51 UTC 2018
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 at 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 at ge.com>
Signed-off-by: Martyn Welch <martyn.welch at collabora.co.uk>
Reviewed-by: Stefano Babic <sbabic at denx.de>
Applied? Thanks!
--
Tom
-------------- next part --------------
A non-text attachment was scrubbed...
Name: signature.asc
Type: application/pgp-signature
Size: 819 bytes
Desc: not available
URL: <http://lists.denx.de/pipermail/u-boot/attachments/20180109/c6acb0dc/attachment.sig>
More information about the U-Boot
mailing list