EXT4文件系统之间接块的ext4_get_block()

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);
}

猜你喜欢

转载自blog.csdn.net/lieye_leaves/article/details/78728889
今日推荐