diff options
Diffstat (limited to 'fs/ext4/ext4_common.c')
-rw-r--r-- | fs/ext4/ext4_common.c | 164 |
1 files changed, 65 insertions, 99 deletions
diff --git a/fs/ext4/ext4_common.c b/fs/ext4/ext4_common.c index 6584892dd28..02da75c0840 100644 --- a/fs/ext4/ext4_common.c +++ b/fs/ext4/ext4_common.c @@ -26,7 +26,6 @@ #include <stddef.h> #include <linux/stat.h> #include <linux/time.h> -#include <linux/list.h> #include <asm/byteorder.h> #include "ext4_common.h" @@ -45,14 +44,6 @@ int ext4fs_indir3_blkno = -1; struct ext2_inode *g_parent_inode; static int symlinknest; -struct ext4_extent_node { - uint32_t block; - uint16_t len; - uint64_t start; - struct list_head lh; -}; -static LIST_HEAD(ext4_extent_lh); - #if defined(CONFIG_EXT4_WRITE) uint32_t ext4fs_div_roundup(uint32_t size, uint32_t n) { @@ -1416,102 +1407,45 @@ void ext4fs_allocate_blocks(struct ext2_inode *file_inode, #endif -static void ext4fs_extent_cache_insert(struct ext4_extent_node *new) -{ - struct ext4_extent_node *node; - - list_for_each_entry(node, &ext4_extent_lh, lh) - if (node->block > new->block) { - list_add_tail(&new->lh, &node->lh); - return; - } - list_add_tail(&new->lh, &ext4_extent_lh); -} - -static int __ext4fs_build_extent_cache(struct ext2_data *data, - struct ext4_extent_header *ext_block) +static struct ext4_extent_header *ext4fs_get_extent_block + (struct ext2_data *data, char *buf, + struct ext4_extent_header *ext_block, + uint32_t fileblock, int log2_blksz) { - int blksz = EXT2_BLOCK_SIZE(data); - int log2_blksz = LOG2_BLOCK_SIZE(data) - - get_fs()->dev_desc->log2blksz; - struct ext4_extent_node *node; struct ext4_extent_idx *index; - struct ext4_extent *extent; unsigned long long block; - char *buf; - int i, err; + int blksz = EXT2_BLOCK_SIZE(data); + int i; - if (le16_to_cpu(ext_block->eh_magic) != EXT4_EXT_MAGIC) - return -EINVAL; + while (1) { + index = (struct ext4_extent_idx *)(ext_block + 1); - if (ext_block->eh_depth == 0) { - extent = (struct ext4_extent *)(ext_block + 1); - for (i = 0; i < le16_to_cpu(ext_block->eh_entries); i++) { - node = malloc(sizeof(*node)); - if (!node) - return -ENOMEM; - node->block = le32_to_cpu(extent[i].ee_block); - node->len = le16_to_cpu(extent[i].ee_len); - node->start = le16_to_cpu(extent[i].ee_start_hi); - node->start = (node->start << 32) + - le32_to_cpu(extent[i].ee_start_lo); - ext4fs_extent_cache_insert(node); - } - return 0; - } + if (le16_to_cpu(ext_block->eh_magic) != EXT4_EXT_MAGIC) + return 0; - index = (struct ext4_extent_idx *)(ext_block + 1); - for (i = 0; i < le16_to_cpu(ext_block->eh_entries); i++) { - buf = malloc(blksz); - if (!buf) - return -ENOMEM; + if (ext_block->eh_depth == 0) + return ext_block; + i = -1; + do { + i++; + if (i >= le16_to_cpu(ext_block->eh_entries)) + break; + } while (fileblock >= le32_to_cpu(index[i].ei_block)); + + if (--i < 0) + return 0; block = le16_to_cpu(index[i].ei_leaf_hi); block = (block << 32) + le32_to_cpu(index[i].ei_leaf_lo); - if (!ext4fs_devread(block << log2_blksz, 0, blksz, buf)) { - free(buf); - return -EIO; - } - - err = __ext4fs_build_extent_cache(data, - (struct ext4_extent_header *) buf); - free(buf); - if (err < 0) - return err; - } - - return 0; -} - -int ext4fs_build_extent_cache(struct ext2_inode *inode) -{ - return __ext4fs_build_extent_cache(ext4fs_root, - (struct ext4_extent_header *) - inode->b.blocks.dir_blocks); -} - -void ext4fs_free_extent_cache(void) -{ - struct ext4_extent_node *node, *tmp; - - list_for_each_entry_safe(node, tmp, &ext4_extent_lh, lh) { - list_del(&node->lh); - free(node); + if (ext4fs_devread((lbaint_t)block << log2_blksz, 0, blksz, + buf)) + ext_block = (struct ext4_extent_header *)buf; + else + return 0; } } -static struct ext4_extent_node *ext4fs_extent_cache_get(uint32_t block) -{ - struct ext4_extent_node *node; - - list_for_each_entry(node, &ext4_extent_lh, lh) - if (block >= node->block && block < node->block + node->len) - return node; - - return NULL; -} - static int ext4fs_blockgroup (struct ext2_data *data, int group, struct ext2_block_group *blkgrp) { @@ -1574,22 +1508,54 @@ long int read_allocated_block(struct ext2_inode *inode, int fileblock) long int rblock; long int perblock_parent; long int perblock_child; - + unsigned long long start; /* get the blocksize of the filesystem */ blksz = EXT2_BLOCK_SIZE(ext4fs_root); log2_blksz = LOG2_BLOCK_SIZE(ext4fs_root) - get_fs()->dev_desc->log2blksz; if (le32_to_cpu(inode->flags) & EXT4_EXTENTS_FL) { - struct ext4_extent_node *node; + char *buf = zalloc(blksz); + if (!buf) + return -ENOMEM; + struct ext4_extent_header *ext_block; + struct ext4_extent *extent; + int i = -1; + ext_block = + ext4fs_get_extent_block(ext4fs_root, buf, + (struct ext4_extent_header *) + inode->b.blocks.dir_blocks, + fileblock, log2_blksz); + if (!ext_block) { + printf("invalid extent block\n"); + free(buf); + return -EINVAL; + } - node = ext4fs_extent_cache_get(fileblock); - if (!node) { - printf("Extent Error\n"); - return -1; + extent = (struct ext4_extent *)(ext_block + 1); + + do { + i++; + if (i >= le16_to_cpu(ext_block->eh_entries)) + break; + } while (fileblock >= le32_to_cpu(extent[i].ee_block)); + if (--i >= 0) { + fileblock -= le32_to_cpu(extent[i].ee_block); + if (fileblock >= le16_to_cpu(extent[i].ee_len)) { + free(buf); + return 0; + } + + start = le16_to_cpu(extent[i].ee_start_hi); + start = (start << 32) + + le32_to_cpu(extent[i].ee_start_lo); + free(buf); + return fileblock + start; } - return fileblock - node->block + node->start; + printf("Extent Error\n"); + free(buf); + return -1; } /* Direct blocks. */ |