diff options
Diffstat (limited to 'fs/ext4/ext4_common.c')
-rw-r--r-- | fs/ext4/ext4_common.c | 76 |
1 files changed, 50 insertions, 26 deletions
diff --git a/fs/ext4/ext4_common.c b/fs/ext4/ext4_common.c index 67e2471bd3..464c33d0d7 100644 --- a/fs/ext4/ext4_common.c +++ b/fs/ext4/ext4_common.c @@ -190,7 +190,7 @@ uint32_t ext4fs_div_roundup(uint32_t size, uint32_t n) return res; } -void put_ext4(uint64_t off, void *buf, uint32_t size) +void put_ext4(uint64_t off, const void *buf, uint32_t size) { uint64_t startblock; uint64_t remainder; @@ -510,7 +510,8 @@ restart: restart_read: /* read the block no allocated to a file */ - first_block_no_of_root = read_allocated_block(g_parent_inode, blk_idx); + first_block_no_of_root = read_allocated_block(g_parent_inode, blk_idx, + NULL); if (first_block_no_of_root <= 0) goto fail; @@ -607,7 +608,7 @@ restart_read: dir->direntlen = cpu_to_le16(fs->blksz - totalbytes); dir->namelen = strlen(filename); - dir->filetype = FILETYPE_REG; /* regular file */ + dir->filetype = file_type; temp_dir = (char *)dir; temp_dir = temp_dir + sizeof(struct ext2_dirent); memcpy(temp_dir, filename, strlen(filename)); @@ -646,7 +647,7 @@ static int search_dir(struct ext2_inode *parent_inode, char *dirname) /* get the block no allocated to a file */ for (blk_idx = 0; blk_idx < directory_blocks; blk_idx++) { - blknr = read_allocated_block(parent_inode, blk_idx); + blknr = read_allocated_block(parent_inode, blk_idx, NULL); if (blknr <= 0) goto fail; @@ -943,7 +944,7 @@ int ext4fs_filename_unlink(char *filename) /* read the block no allocated to a file */ for (blk_idx = 0; blk_idx < directory_blocks; blk_idx++) { - blknr = read_allocated_block(g_parent_inode, blk_idx); + blknr = read_allocated_block(g_parent_inode, blk_idx, NULL); if (blknr <= 0) break; inodeno = unlink_filename(filename, blknr); @@ -1522,7 +1523,7 @@ void ext4fs_allocate_blocks(struct ext2_inode *file_inode, #endif static struct ext4_extent_header *ext4fs_get_extent_block - (struct ext2_data *data, char *buf, + (struct ext2_data *data, struct ext_block_cache *cache, struct ext4_extent_header *ext_block, uint32_t fileblock, int log2_blksz) { @@ -1546,17 +1547,19 @@ static struct ext4_extent_header *ext4fs_get_extent_block break; } while (fileblock >= le32_to_cpu(index[i].ei_block)); - if (--i < 0) - return NULL; + /* + * If first logical block number is higher than requested fileblock, + * it is a sparse file. This is handled on upper layer. + */ + if (i > 0) + i--; 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 + block <<= log2_blksz; + if (!ext_cache_read(cache, (lbaint_t)block, blksz)) return NULL; + ext_block = (struct ext4_extent_header *)cache->buf; } } @@ -1584,7 +1587,7 @@ static int ext4fs_blockgroup int ext4fs_read_inode(struct ext2_data *data, int ino, struct ext2_inode *inode) { - struct ext2_block_group blkgrp; + struct ext2_block_group *blkgrp; struct ext2_sblock *sblock = &data->sblock; struct ext_filesystem *fs = get_fs(); int log2blksz = get_fs()->dev_desc->log2blksz; @@ -1592,17 +1595,28 @@ int ext4fs_read_inode(struct ext2_data *data, int ino, struct ext2_inode *inode) long int blkno; unsigned int blkoff; + /* Allocate blkgrp based on gdsize (for 64-bit support). */ + blkgrp = zalloc(get_fs()->gdsize); + if (!blkgrp) + return 0; + /* It is easier to calculate if the first inode is 0. */ ino--; status = ext4fs_blockgroup(data, ino / le32_to_cpu - (sblock->inodes_per_group), &blkgrp); - if (status == 0) + (sblock->inodes_per_group), blkgrp); + if (status == 0) { + free(blkgrp); return 0; + } inodes_per_block = EXT2_BLOCK_SIZE(data) / fs->inodesz; - blkno = ext4fs_bg_get_inode_table_id(&blkgrp, fs) + + blkno = ext4fs_bg_get_inode_table_id(blkgrp, fs) + (ino % le32_to_cpu(sblock->inodes_per_group)) / inodes_per_block; blkoff = (ino % inodes_per_block) * fs->inodesz; + + /* Free blkgrp as it is no longer required. */ + free(blkgrp); + /* Read the inode. */ status = ext4fs_devread((lbaint_t)blkno << (LOG2_BLOCK_SIZE(data) - log2blksz), blkoff, @@ -1613,7 +1627,8 @@ int ext4fs_read_inode(struct ext2_data *data, int ino, struct ext2_inode *inode) return 1; } -long int read_allocated_block(struct ext2_inode *inode, int fileblock) +long int read_allocated_block(struct ext2_inode *inode, int fileblock, + struct ext_block_cache *cache) { long int blknr; int blksz; @@ -1630,20 +1645,26 @@ long int read_allocated_block(struct ext2_inode *inode, int fileblock) if (le32_to_cpu(inode->flags) & EXT4_EXTENTS_FL) { long int startblock, endblock; - char *buf = zalloc(blksz); - if (!buf) - return -ENOMEM; + struct ext_block_cache *c, cd; struct ext4_extent_header *ext_block; struct ext4_extent *extent; int i; + + if (cache) { + c = cache; + } else { + c = &cd; + ext_cache_init(c); + } ext_block = - ext4fs_get_extent_block(ext4fs_root, buf, + ext4fs_get_extent_block(ext4fs_root, c, (struct ext4_extent_header *) inode->b.blocks.dir_blocks, fileblock, log2_blksz); if (!ext_block) { printf("invalid extent block\n"); - free(buf); + if (!cache) + ext_cache_fini(c); return -EINVAL; } @@ -1655,19 +1676,22 @@ long int read_allocated_block(struct ext2_inode *inode, int fileblock) if (startblock > fileblock) { /* Sparse file */ - free(buf); + if (!cache) + ext_cache_fini(c); return 0; } else if (fileblock < endblock) { start = le16_to_cpu(extent[i].ee_start_hi); start = (start << 32) + le32_to_cpu(extent[i].ee_start_lo); - free(buf); + if (!cache) + ext_cache_fini(c); return (fileblock - startblock) + start; } } - free(buf); + if (!cache) + ext_cache_fini(c); return 0; } |