X-Git-Url: https://git.sur5r.net/?a=blobdiff_plain;f=fs%2Fext4%2Fext4_common.c;h=33d69c9c71f07819c73678c2efc7abc175a8c607;hb=415548d88446134549917aae026f53dbbee36fd2;hp=6584892dd28de4d0a5f5aa31e230fe3b5ebb0293;hpb=a7e8c15f71456d55ccb27f843862af03a00e0957;p=u-boot diff --git a/fs/ext4/ext4_common.c b/fs/ext4/ext4_common.c index 6584892dd2..33d69c9c71 100644 --- a/fs/ext4/ext4_common.c +++ b/fs/ext4/ext4_common.c @@ -26,7 +26,6 @@ #include #include #include -#include #include #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) { @@ -913,10 +904,8 @@ long int ext4fs_get_new_blk_no(void) restart: fs->curr_blkno++; /* get the blockbitmap index respective to blockno */ - if (fs->blksz != 1024) { - bg_idx = fs->curr_blkno / blk_per_grp; - } else { - bg_idx = fs->curr_blkno / blk_per_grp; + bg_idx = fs->curr_blkno / blk_per_grp; + if (fs->blksz == 1024) { remainder = fs->curr_blkno % blk_per_grp; if (!remainder) bg_idx--; @@ -1391,7 +1380,7 @@ void ext4fs_allocate_blocks(struct ext2_inode *file_inode, unsigned int no_blks_reqd = 0; /* allocation of direct blocks */ - for (i = 0; i < INDIRECT_BLOCKS; i++) { + for (i = 0; total_remaining_blocks && i < INDIRECT_BLOCKS; i++) { direct_blockno = ext4fs_get_new_blk_no(); if (direct_blockno == -1) { printf("no block left to assign\n"); @@ -1401,8 +1390,6 @@ void ext4fs_allocate_blocks(struct ext2_inode *file_inode, debug("DB %ld: %u\n", direct_blockno, total_remaining_blocks); total_remaining_blocks--; - if (total_remaining_blocks == 0) - break; } alloc_single_indirect_block(file_inode, &total_remaining_blocks, @@ -1416,102 +1403,45 @@ void ext4fs_allocate_blocks(struct ext2_inode *file_inode, #endif -static void ext4fs_extent_cache_insert(struct ext4_extent_node *new) +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) { - 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) -{ - 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 +1504,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. */ @@ -1877,16 +1839,20 @@ long int read_allocated_block(struct ext2_inode *inode, int fileblock) return blknr; } -void ext4fs_close(void) +/** + * ext4fs_reinit_global() - Reinitialize values of ext4 write implementation's + * global pointers + * + * This function assures that for a file with the same name but different size + * the sequential store on the ext4 filesystem will be correct. + * + * In this function the global data, responsible for internal representation + * of the ext4 data are initialized to the reset state. Without this, during + * replacement of the smaller file with the bigger truncation of new file was + * performed. + */ +void ext4fs_reinit_global(void) { - if ((ext4fs_file != NULL) && (ext4fs_root != NULL)) { - ext4fs_free_node(ext4fs_file, &ext4fs_root->diropen); - ext4fs_file = NULL; - } - if (ext4fs_root != NULL) { - free(ext4fs_root); - ext4fs_root = NULL; - } if (ext4fs_indir1_block != NULL) { free(ext4fs_indir1_block); ext4fs_indir1_block = NULL; @@ -1906,6 +1872,19 @@ void ext4fs_close(void) ext4fs_indir3_blkno = -1; } } +void ext4fs_close(void) +{ + if ((ext4fs_file != NULL) && (ext4fs_root != NULL)) { + ext4fs_free_node(ext4fs_file, &ext4fs_root->diropen); + ext4fs_file = NULL; + } + if (ext4fs_root != NULL) { + free(ext4fs_root); + ext4fs_root = NULL; + } + + ext4fs_reinit_global(); +} int ext4fs_iterate_dir(struct ext2fs_node *dir, char *name, struct ext2fs_node **fnode, int *ftype)