in fs/ext4/ext4_common.c [1645:1996]
long int read_allocated_block(struct ext2_inode *inode, int fileblock,
struct ext_block_cache *cache)
{
long int blknr;
int blksz;
int log2_blksz;
int status;
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) {
long int startblock, endblock;
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, c,
(struct ext4_extent_header *)
inode->b.blocks.dir_blocks,
fileblock, log2_blksz);
if (!ext_block) {
printf("invalid extent block\n");
if (!cache)
ext_cache_fini(c);
return -EINVAL;
}
extent = (struct ext4_extent *)(ext_block + 1);
for (i = 0; i < le16_to_cpu(ext_block->eh_entries); i++) {
startblock = le32_to_cpu(extent[i].ee_block);
endblock = startblock + le16_to_cpu(extent[i].ee_len);
if (startblock > fileblock) {
/* Sparse file */
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);
if (!cache)
ext_cache_fini(c);
return (fileblock - startblock) + start;
}
}
if (!cache)
ext_cache_fini(c);
return 0;
}
/* Direct blocks. */
if (fileblock < INDIRECT_BLOCKS)
blknr = le32_to_cpu(inode->b.blocks.dir_blocks[fileblock]);
/* Indirect. */
else if (fileblock < (INDIRECT_BLOCKS + (blksz / 4))) {
if (ext4fs_indir1_block == NULL) {
ext4fs_indir1_block = zalloc(blksz);
if (ext4fs_indir1_block == NULL) {
printf("** SI ext2fs read block (indir 1)"
"malloc failed. **\n");
return -1;
}
ext4fs_indir1_size = blksz;
ext4fs_indir1_blkno = -1;
}
if (blksz != ext4fs_indir1_size) {
free(ext4fs_indir1_block);
ext4fs_indir1_block = NULL;
ext4fs_indir1_size = 0;
ext4fs_indir1_blkno = -1;
ext4fs_indir1_block = zalloc(blksz);
if (ext4fs_indir1_block == NULL) {
printf("** SI ext2fs read block (indir 1):"
"malloc failed. **\n");
return -1;
}
ext4fs_indir1_size = blksz;
}
if ((le32_to_cpu(inode->b.blocks.indir_block) <<
log2_blksz) != ext4fs_indir1_blkno) {
status =
ext4fs_devread((lbaint_t)le32_to_cpu
(inode->b.blocks.
indir_block) << log2_blksz, 0,
blksz, (char *)ext4fs_indir1_block);
if (status == 0) {
printf("** SI ext2fs read block (indir 1)"
"failed. **\n");
return -1;
}
ext4fs_indir1_blkno =
le32_to_cpu(inode->b.blocks.
indir_block) << log2_blksz;
}
blknr = le32_to_cpu(ext4fs_indir1_block
[fileblock - INDIRECT_BLOCKS]);
}
/* Double indirect. */
else if (fileblock < (INDIRECT_BLOCKS + (blksz / 4 *
(blksz / 4 + 1)))) {
long int perblock = blksz / 4;
long int rblock = fileblock - (INDIRECT_BLOCKS + blksz / 4);
if (ext4fs_indir1_block == NULL) {
ext4fs_indir1_block = zalloc(blksz);
if (ext4fs_indir1_block == NULL) {
printf("** DI ext2fs read block (indir 2 1)"
"malloc failed. **\n");
return -1;
}
ext4fs_indir1_size = blksz;
ext4fs_indir1_blkno = -1;
}
if (blksz != ext4fs_indir1_size) {
free(ext4fs_indir1_block);
ext4fs_indir1_block = NULL;
ext4fs_indir1_size = 0;
ext4fs_indir1_blkno = -1;
ext4fs_indir1_block = zalloc(blksz);
if (ext4fs_indir1_block == NULL) {
printf("** DI ext2fs read block (indir 2 1)"
"malloc failed. **\n");
return -1;
}
ext4fs_indir1_size = blksz;
}
if ((le32_to_cpu(inode->b.blocks.double_indir_block) <<
log2_blksz) != ext4fs_indir1_blkno) {
status =
ext4fs_devread((lbaint_t)le32_to_cpu
(inode->b.blocks.
double_indir_block) << log2_blksz,
0, blksz,
(char *)ext4fs_indir1_block);
if (status == 0) {
printf("** DI ext2fs read block (indir 2 1)"
"failed. **\n");
return -1;
}
ext4fs_indir1_blkno =
le32_to_cpu(inode->b.blocks.double_indir_block) <<
log2_blksz;
}
if (ext4fs_indir2_block == NULL) {
ext4fs_indir2_block = zalloc(blksz);
if (ext4fs_indir2_block == NULL) {
printf("** DI ext2fs read block (indir 2 2)"
"malloc failed. **\n");
return -1;
}
ext4fs_indir2_size = blksz;
ext4fs_indir2_blkno = -1;
}
if (blksz != ext4fs_indir2_size) {
free(ext4fs_indir2_block);
ext4fs_indir2_block = NULL;
ext4fs_indir2_size = 0;
ext4fs_indir2_blkno = -1;
ext4fs_indir2_block = zalloc(blksz);
if (ext4fs_indir2_block == NULL) {
printf("** DI ext2fs read block (indir 2 2)"
"malloc failed. **\n");
return -1;
}
ext4fs_indir2_size = blksz;
}
if ((le32_to_cpu(ext4fs_indir1_block[rblock / perblock]) <<
log2_blksz) != ext4fs_indir2_blkno) {
status = ext4fs_devread((lbaint_t)le32_to_cpu
(ext4fs_indir1_block
[rblock /
perblock]) << log2_blksz, 0,
blksz,
(char *)ext4fs_indir2_block);
if (status == 0) {
printf("** DI ext2fs read block (indir 2 2)"
"failed. **\n");
return -1;
}
ext4fs_indir2_blkno =
le32_to_cpu(ext4fs_indir1_block[rblock
/
perblock]) <<
log2_blksz;
}
blknr = le32_to_cpu(ext4fs_indir2_block[rblock % perblock]);
}
/* Tripple indirect. */
else {
rblock = fileblock - (INDIRECT_BLOCKS + blksz / 4 +
(blksz / 4 * blksz / 4));
perblock_child = blksz / 4;
perblock_parent = ((blksz / 4) * (blksz / 4));
if (ext4fs_indir1_block == NULL) {
ext4fs_indir1_block = zalloc(blksz);
if (ext4fs_indir1_block == NULL) {
printf("** TI ext2fs read block (indir 2 1)"
"malloc failed. **\n");
return -1;
}
ext4fs_indir1_size = blksz;
ext4fs_indir1_blkno = -1;
}
if (blksz != ext4fs_indir1_size) {
free(ext4fs_indir1_block);
ext4fs_indir1_block = NULL;
ext4fs_indir1_size = 0;
ext4fs_indir1_blkno = -1;
ext4fs_indir1_block = zalloc(blksz);
if (ext4fs_indir1_block == NULL) {
printf("** TI ext2fs read block (indir 2 1)"
"malloc failed. **\n");
return -1;
}
ext4fs_indir1_size = blksz;
}
if ((le32_to_cpu(inode->b.blocks.triple_indir_block) <<
log2_blksz) != ext4fs_indir1_blkno) {
status = ext4fs_devread
((lbaint_t)
le32_to_cpu(inode->b.blocks.triple_indir_block)
<< log2_blksz, 0, blksz,
(char *)ext4fs_indir1_block);
if (status == 0) {
printf("** TI ext2fs read block (indir 2 1)"
"failed. **\n");
return -1;
}
ext4fs_indir1_blkno =
le32_to_cpu(inode->b.blocks.triple_indir_block) <<
log2_blksz;
}
if (ext4fs_indir2_block == NULL) {
ext4fs_indir2_block = zalloc(blksz);
if (ext4fs_indir2_block == NULL) {
printf("** TI ext2fs read block (indir 2 2)"
"malloc failed. **\n");
return -1;
}
ext4fs_indir2_size = blksz;
ext4fs_indir2_blkno = -1;
}
if (blksz != ext4fs_indir2_size) {
free(ext4fs_indir2_block);
ext4fs_indir2_block = NULL;
ext4fs_indir2_size = 0;
ext4fs_indir2_blkno = -1;
ext4fs_indir2_block = zalloc(blksz);
if (ext4fs_indir2_block == NULL) {
printf("** TI ext2fs read block (indir 2 2)"
"malloc failed. **\n");
return -1;
}
ext4fs_indir2_size = blksz;
}
if ((le32_to_cpu(ext4fs_indir1_block[rblock /
perblock_parent]) <<
log2_blksz)
!= ext4fs_indir2_blkno) {
status = ext4fs_devread((lbaint_t)le32_to_cpu
(ext4fs_indir1_block
[rblock /
perblock_parent]) <<
log2_blksz, 0, blksz,
(char *)ext4fs_indir2_block);
if (status == 0) {
printf("** TI ext2fs read block (indir 2 2)"
"failed. **\n");
return -1;
}
ext4fs_indir2_blkno =
le32_to_cpu(ext4fs_indir1_block[rblock /
perblock_parent])
<< log2_blksz;
}
if (ext4fs_indir3_block == NULL) {
ext4fs_indir3_block = zalloc(blksz);
if (ext4fs_indir3_block == NULL) {
printf("** TI ext2fs read block (indir 2 2)"
"malloc failed. **\n");
return -1;
}
ext4fs_indir3_size = blksz;
ext4fs_indir3_blkno = -1;
}
if (blksz != ext4fs_indir3_size) {
free(ext4fs_indir3_block);
ext4fs_indir3_block = NULL;
ext4fs_indir3_size = 0;
ext4fs_indir3_blkno = -1;
ext4fs_indir3_block = zalloc(blksz);
if (ext4fs_indir3_block == NULL) {
printf("** TI ext2fs read block (indir 2 2)"
"malloc failed. **\n");
return -1;
}
ext4fs_indir3_size = blksz;
}
if ((le32_to_cpu(ext4fs_indir2_block[rblock
/
perblock_child]) <<
log2_blksz) != ext4fs_indir3_blkno) {
status =
ext4fs_devread((lbaint_t)le32_to_cpu
(ext4fs_indir2_block
[(rblock / perblock_child)
% (blksz / 4)]) << log2_blksz, 0,
blksz, (char *)ext4fs_indir3_block);
if (status == 0) {
printf("** TI ext2fs read block (indir 2 2)"
"failed. **\n");
return -1;
}
ext4fs_indir3_blkno =
le32_to_cpu(ext4fs_indir2_block[(rblock /
perblock_child) %
(blksz /
4)]) <<
log2_blksz;
}
blknr = le32_to_cpu(ext4fs_indir3_block
[rblock % perblock_child]);
}
debug("read_allocated_block %ld\n", blknr);
return blknr;
}