From patchwork Fri Oct 27 14:18:11 2017 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Christophe Ronco X-Patchwork-Id: 831655 X-Patchwork-Delegate: trini@ti.com Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Authentication-Results: ozlabs.org; spf=none (mailfrom) smtp.mailfrom=lists.denx.de (client-ip=81.169.180.215; helo=lists.denx.de; envelope-from=u-boot-bounces@lists.denx.de; receiver=) Received: from lists.denx.de (dione.denx.de [81.169.180.215]) by ozlabs.org (Postfix) with ESMTP id 3yPcxC48VLz9t3B for ; Sun, 29 Oct 2017 10:52:31 +1100 (AEDT) Received: by lists.denx.de (Postfix, from userid 105) id 327C2C21DE5; Sat, 28 Oct 2017 23:52:02 +0000 (UTC) X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on lists.denx.de X-Spam-Level: X-Spam-Status: No, score=-0.0 required=5.0 tests=RCVD_IN_MSPIKE_H3, RCVD_IN_MSPIKE_WL autolearn=unavailable autolearn_force=no version=3.4.0 Received: from lists.denx.de (localhost [IPv6:::1]) by lists.denx.de (Postfix) with ESMTP id 4CCE3C21C71; Sat, 28 Oct 2017 23:51:40 +0000 (UTC) Received: by lists.denx.de (Postfix, from userid 105) id 39AC8C21C4E; Fri, 27 Oct 2017 14:18:36 +0000 (UTC) Received: from ot-mail-smtp-2.pulsation.fr (ot-mail-smtp-4.pulsation.fr [80.74.64.133]) by lists.denx.de (Postfix) with ESMTPS id D725FC21C46 for ; Fri, 27 Oct 2017 14:18:35 +0000 (UTC) Received: from KLK807.klksi.fr (unknown [37.157.230.10]) (Authenticated sender: c.ronco@kerlink.fr) by smtp.oceamail.net (Postfix) with ESMTPA id 6F8711009BE1; Fri, 27 Oct 2017 16:18:35 +0200 (CEST) From: Christophe Ronco To: u-boot@lists.denx.de Date: Fri, 27 Oct 2017 16:18:11 +0200 Message-Id: <1509113891-17584-2-git-send-email-c.ronco@kerlink.fr> X-Mailer: git-send-email 2.7.4 In-Reply-To: <1509113891-17584-1-git-send-email-c.ronco@kerlink.fr> References: <1509113891-17584-1-git-send-email-c.ronco@kerlink.fr> X-Mailman-Approved-At: Sat, 28 Oct 2017 23:51:38 +0000 Cc: Christophe Ronco Subject: [U-Boot] [PATCH] ext4: cache first extent index blocks (#06343) X-BeenThere: u-boot@lists.denx.de X-Mailman-Version: 2.1.18 Precedence: list List-Id: U-Boot discussion List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , MIME-Version: 1.0 Errors-To: u-boot-bounces@lists.denx.de Sender: "U-Boot" 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)