static int ext4_alloc_branch(handle_t *handle, struct inode *inode,
ext4_lblk_t iblock, int indirect_blks,
int *blks, ext4_fsblk_t goal,
ext4_lblk_t *offsets, Indirect *branch)
{
1. 分配数据块
2. 建立多次间接块的映射关系
}
int ext4_ind_map_blocks(handle_t *handle, struct inode *inode,
struct ext4_map_blocks *map,
int flags)
{
depth = ext4_block_to_path(inode, map->m_lblk, offsets,
&blocks_to_boundary);
//该函数建立从直接块到三次间接块之间的完整的路径,depth返回深度,各个中间间接块的地址保存在offsets中;
if (depth == 0)
goto out;
partial = ext4_get_branch(inode, depth, offsets, chain, &err);
//查找各个路径下的地址,看能否找到目标块
/* Simplest case - block found, no allocation needed */
if (!partial) {//该种情况下,找到了数据块。
first_block = le32_to_cpu(chain[depth - 1].key);
count++;
/*map more blocks*/
while (count < map->m_len && count <= blocks_to_boundary) {
ext4_fsblk_t blk;
blk = le32_to_cpu(*(chain[depth-1].p + count));
if (blk == first_block + count)
count++;
else
break;
}
goto got_it;//找到了数据块,返回
}
/* Next simple case - plain lookup or failed read of indirect block */
if ((flags & EXT4_GET_BLOCKS_CREATE) == 0 || err == -EIO)
goto cleanup;
if (EXT4_HAS_RO_COMPAT_FEATURE(inode->i_sb,
EXT4_FEATURE_RO_COMPAT_BIGALLOC)) {
EXT4_ERROR_INODE(inode, "Can't allocate blocks for "
"non-extent mapped inodes with bigalloc");
return -ENOSPC;
}
goal = ext4_find_goal(inode, map->m_lblk, partial); //查找当前逻辑地址最合适的地址
/* the number of blocks need to allocate for [d,t]indirect blocks */
indirect_blks = (chain + depth) - partial - 1;
/*
* Next look up the indirect map to count the totoal number of
* direct blocks to allocate for this branch.
需要分配的块数
*/
count = ext4_blks_to_allocate(partial, indirect_blks,
map->m_len, blocks_to_boundary);
/*
* Block out ext4_truncate while we alter the tree
*/
err = ext4_alloc_branch(handle, inode, map->m_lblk, indirect_blks,
&count, goal,
offsets + (partial - chain), partial);
/*
* The ext4_splice_branch call will free and forget any buffers
* on the new chain if there is a failure, but that risks using
* up transaction credits, especially for bitmaps where the
* credits cannot be returned. Can we handle this somehow? We
* may need to return -EAGAIN upwards in the worst case. --sct
*/
if (!err)
err = ext4_splice_branch(handle, inode, map->m_lblk,
partial, indirect_blks, count);
if (err)
goto cleanup;
map->m_flags |= EXT4_MAP_NEW;
ext4_update_inode_fsync_trans(handle, inode, 1);
got_it:
map->m_flags |= EXT4_MAP_MAPPED;
map->m_pblk = le32_to_cpu(chain[depth-1].key);
map->m_len = count;
if (count > blocks_to_boundary)
map->m_flags |= EXT4_MAP_BOUNDARY;
err = count;
/* Clean up and exit */
partial = chain + depth - 1; /* the whole chain */
cleanup:
while (partial > chain) {
BUFFER_TRACE(partial->bh, "call brelse");
brelse(partial->bh);
partial--;
}
out:
trace_ext4_ind_map_blocks_exit(inode, map->m_lblk,
map->m_pblk, map->m_len, err);
return err;
}
int ext4_map_blocks(handle_t *handle, struct inode *inode, struct ext4_map_blocks *map, int flags)
{
ext4_ind_map_blocks(handle, inode, map, flags &EXT4_GET_BLOCKS_KEEP_SIZE);
}
static int _ext4_get_block(struct inode *inode, sector_t iblock, struct buffer_head *bh, int flags)
{
map.m_lblk = iblock;
map.m_len = bh->b_size >> inode->i_blkbits;
ret = ext4_map_blocks(handle, inode, &map, flags);
if (ret > 0) {
map_bh(bh, inode->i_sb, map.m_pblk);
bh->b_state = (bh->b_state & ~EXT4_MAP_FLAGS) | map.m_flags;
bh->b_size = inode->i_sb->s_blocksize * map.m_len;
ret = 0;
}
}
int ext4_get_block(struct inode *inode, sector_t iblock,
struct buffer_head *bh, int create)
{
return _ext4_get_block(inode, iblock, bh, create ? EXT4_GET_BLOCKS_CREATE : 0);
}