ext4 ext4_map_blocks

本文介绍Ext4文件系统中ext4_map_blocks函数的工作原理,该函数负责查找请求的块并返回已映射的块。若未映射,则进行分配,并将分配的块存储在结果缓冲区头部。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >


struct ext4_map_blocks {
	ext4_fsblk_t m_pblk;
	ext4_lblk_t m_lblk;
	unsigned int m_len;
	unsigned int m_flags;
};


/*
 * The ext4_map_blocks() function tries to look up the requested blocks,
 * and returns if the blocks are already mapped.
 *
 * Otherwise it takes the write lock of the i_data_sem and allocate blocks
 * and store the allocated blocks in the result buffer head and mark it
 * mapped.
 *
 * If file type is extents based, it will call ext4_ext_map_blocks(),
 * Otherwise, call with ext4_ind_map_blocks() to handle indirect mapping
 * based files
 *
 * On success, it returns the number of blocks being mapped or allocated.  if
 * create==0 and the blocks are pre-allocated and unwritten, the resulting @map
 * is marked as unwritten. If the create == 1, it will mark @map as mapped.
 *
 * It returns 0 if plain look up failed (blocks have not been allocated), in
 * that case, @map is returned as unmapped but we still do fill map->m_len to
 * indicate the length of a hole starting at map->m_lblk.
 *
 * It returns the error in case of allocation failure.
 */
int ext4_map_blocks(handle_t *handle, struct inode *inode,
		    struct ext4_map_blocks *map, int flags)
{
	struct extent_status es;
	int retval;
	int ret = 0;
#ifdef ES_AGGRESSIVE_TEST
	struct ext4_map_blocks orig_map;
	memcpy(&orig_map, map, sizeof(*map));
#endif
	map->m_flags = 0;
	ext_debug("ext4_map_blocks(): inode %lu, flag %d, max_blocks %u,"
		  "logical block %lu\n", inode->i_ino, flags, map->m_len,
		  (unsigned long) map->m_lblk);
	/*
	 * ext4_map_blocks returns an int, and m_len is an unsigned int
	 */
	if (unlikely(map->m_len > INT_MAX))
		map->m_len = INT_MAX;

	/* We can handle the block number less than EXT_MAX_BLOCKS */
	if (unlikely(map->m_lblk >= EXT_MAX_BLOCKS))
		return -EFSCORRUPTED;

	/* Lookup extent status tree firstly */
	if (ext4_es_lookup_extent(inode, map->m_lblk, &es)) {
		if (ext4_es_is_written(&es) || ext4_es_is_unwritten(&es)) {
			map->m_pblk = ext4_es_pblock(&es) +
					map->m_lblk - es.es_lblk;
			map->m_flags |= ext4_es_is_written(&es) ?
					EXT4_MAP_MAPPED : EXT4_MAP_UNWRITTEN;
			retval = es.es_len - (map->m_lblk - es.es_lblk);
			if (retval > map->m_len)
				retval = map->m_len;
			map->m_len = retval;
		} else if (ext4_es_is_delayed(&es) || ext4_es_is_hole(&es)) {
			map->m_pblk = 0;
			retval = es.es_len - (map->m_lblk - es.es_lblk);
			if (retval > map->m_len)
				retval = map->m_len;
			map->m_len = retval;
			retval = 0;
		} else {
			BUG_ON(1);
		}
#ifdef ES_AGGRESSIVE_TEST
		ext4_map_blocks_es_recheck(handle, inode, map,
					   &orig_map, flags);
#endif
		goto found;
	}

	/*
	 * Try to see if we can get the block without requesting a new
	 * file system block.
	 */
	down_read(&EXT4_I(inode)->i_data_sem);
	if (ext4_test_inode_flag(inode, EXT4_INODE_EXTENTS)) {
		retval = ext4_ext_map_blocks(handle, inode, map, flags &
					     EXT4_GET_BLOCKS_KEEP_SIZE);
	} else {
		retval = ext4_ind_map_blocks(handle, inode, map, flags &
					     EXT4_GET_BLOCKS_KEEP_SIZE);
	}
	if (retval > 0) {
		unsigned int status;

		if (unlikely(retval != map->m_len)) {
			ext4_warning(inode->i_sb,
				     "ES len assertion failed for inode "
				     "%lu: retval %d != map->m_len %d",
				     inode->i_ino, retval, map->m_len);
			WARN_ON(1);
		}

		status = map->m_flags & EXT4_MAP_UNWRITTEN ?
				EXTENT_STATUS_UNWRITTEN : EXTENT_STATUS_WRITTEN;
		if (!(flags & EXT4_GET_BLOCKS_DELALLOC_RESERVE) &&
		    !(status & EXTENT_STATUS_WRITTEN) &&
		    ext4_find_delalloc_range(inode, map->m_lblk,
					     map->m_lblk + map->m_len - 1))
			status |= EXTENT_STATUS_DELAYED;
		ret = ext4_es_insert_extent(inode, map->m_lblk,
					    map->m_len, map->m_pblk, status);
		if (ret < 0)
			retval = ret;
	}
	up_read((&EXT4_I(inode)->i_data_sem));

found:
	if (retval > 0 && map->m_flags & EXT4_MAP_MAPPED) {
		ret = check_block_validity(inode, map);
		if (ret != 0)
			return ret;
	}

	/* If it is only a block(s) look up */
	if ((flags & EXT4_GET_BLOCKS_CREATE) == 0)
		return retval;

	/*
	 * Returns if the blocks have already allocated
	 *
	 * Note that if blocks have been preallocated
	 * ext4_ext_get_block() returns the create = 0
	 * with buffer head unmapped.
	 */
	if (retval > 0 && map->m_flags & EXT4_MAP_MAPPED)
		/*
		 * If we need to convert extent to unwritten
		 * we continue and do the actual work in
		 * ext4_ext_map_blocks()
		 */
		if (!(flags & EXT4_GET_BLOCKS_CONVERT_UNWRITTEN))
			return retval;
	/*
	 * Here we clear m_flags because after allocating an new extent,
	 * it will be set again.
	 */
	map->m_flags &= ~EXT4_MAP_FLAGS;

	/*
	 * New blocks allocate and/or writing to unwritten extent
	 * will possibly result in updating i_data, so we take
	 * the write lock of i_data_sem, and call get_block()
	 * with create == 1 flag.
	 */
	down_write(&EXT4_I(inode)->i_data_sem);

	/*
	 * We need to check for EXT4 here because migrate
	 * could have changed the inode type in between
	 */
	if (ext4_test_inode_flag(inode, EXT4_INODE_EXTENTS)) {
		retval = ext4_ext_map_blocks(handle, inode, map, flags);
	} else {
		retval = ext4_ind_map_blocks(handle, inode, map, flags);


		if (retval > 0 && map->m_flags & EXT4_MAP_NEW) {
			/*
			 * We allocated new blocks which will result in
			 * i_data's format changing.  Force the migrate
			 * to fail by clearing migrate flags
			 */
			ext4_clear_inode_state(inode, EXT4_STATE_EXT_MIGRATE);
		}


		/*
		 * Update reserved blocks/metadata blocks after successful
		 * block allocation which had been deferred till now. We don't
		 * support fallocate for non extent files. So we can update
		 * reserve space here.
		 */
		if ((retval > 0) &&
			(flags & EXT4_GET_BLOCKS_DELALLOC_RESERVE))
			ext4_da_update_reserve_space(inode, retval, 1);
	}

	if (retval > 0) {
		unsigned int status;

		if (unlikely(retval != map->m_len)) {
			ext4_warning(inode->i_sb,
				     "ES len assertion failed for inode "
				     "%lu: retval %d != map->m_len %d",
				     inode->i_ino, retval, map->m_len);
			WARN_ON(1);
		}


		/*
		 * We have to zeroout blocks before inserting them into extent
		 * status tree. Otherwise someone could look them up there and
		 * use them before they are really zeroed. We also have to
		 * unmap metadata before zeroing as otherwise writeback can
		 * overwrite zeros with stale data from block device.
		 */
		if (flags & EXT4_GET_BLOCKS_ZERO &&
		    map->m_flags & EXT4_MAP_MAPPED &&
		    map->m_flags & EXT4_MAP_NEW) {
			ext4_lblk_t i;


			for (i = 0; i < map->m_len; i++) {
				unmap_underlying_metadata(inode->i_sb->s_bdev,
							  map->m_pblk + i);
			}
			ret = ext4_issue_zeroout(inode, map->m_lblk,
						 map->m_pblk, map->m_len);
			if (ret) {
				retval = ret;
				goto out_sem;
			}
		}


		/*
		 * If the extent has been zeroed out, we don't need to update
		 * extent status tree.
		 */
		if ((flags & EXT4_GET_BLOCKS_PRE_IO) &&
		    ext4_es_lookup_extent(inode, map->m_lblk, &es)) {
			if (ext4_es_is_written(&es))
				goto out_sem;
		}
		status = map->m_flags & EXT4_MAP_UNWRITTEN ?
				EXTENT_STATUS_UNWRITTEN : EXTENT_STATUS_WRITTEN;
		if (!(flags & EXT4_GET_BLOCKS_DELALLOC_RESERVE) &&
		    !(status & EXTENT_STATUS_WRITTEN) &&
		    ext4_find_delalloc_range(inode, map->m_lblk,
					     map->m_lblk + map->m_len - 1))
			status |= EXTENT_STATUS_DELAYED;
		ret = ext4_es_insert_extent(inode, map->m_lblk, map->m_len,
					    map->m_pblk, status);
		if (ret < 0) {
			retval = ret;
			goto out_sem;
		}
	}


out_sem:
	up_write((&EXT4_I(inode)->i_data_sem));
	if (retval > 0 && map->m_flags & EXT4_MAP_MAPPED) {
		ret = check_block_validity(inode, map);
		if (ret != 0)
			return ret;


		/*
		 * Inodes with freshly allocated blocks where contents will be
		 * visible after transaction commit must be on transaction's
		 * ordered data list.
		 */
		if (map->m_flags & EXT4_MAP_NEW &&
		    !(map->m_flags & EXT4_MAP_UNWRITTEN) &&
		    !(flags & EXT4_GET_BLOCKS_ZERO) &&
		    !IS_NOQUOTA(inode) &&
		    ext4_should_order_data(inode)) {
			if (flags & EXT4_GET_BLOCKS_IO_SUBMIT)
				ret = ext4_jbd2_inode_add_wait(handle, inode);
			else
				ret = ext4_jbd2_inode_add_write(handle, inode);
			if (ret)
				return ret;
		}
	}
	return retval;
}


                
<think>嗯,用户给了一个C语言的结构体定义,想要分析它的结构组成。首先,我需要仔细看一下这个结构体的各个成员,理解每个成员的作用和数据类型。 结构体的名字是COM_MAP,看起来是和视频编码相关的,可能用于存储编码过程中的一些映射信息。比如,可能有SCU(可能是某种编码单元)、LCU的分割信息、运动矢量、参考帧索引等等。 第一个成员是u32类型的指针map_scu,注释说是SCU map,用于CU信息。SCU可能指的是Smallest Coding Unit,或者是某种编码单元的结构。CU是编码单元,常见于H.264/H.265等标准中。 接下来是map_split,这个成员的条件编译比较复杂。根据CTU_256是否为真,数组的维度不同。CTU_256可能指编码树单元的大小是256x256,那么MAX_CU_DEPTH2可能代表不同的深度。这里可能存储LCU(Largest Coding Unit)的分割信息,每个深度对应的块形状和数量。 然后是map_mv,二维数组指针,类型是s16,存储解码后的运动矢量。REFP_NUM可能是参考帧的数量,MV_D可能是运动矢量的维度,比如水平和垂直分量。 map_refi是参考帧索引,s8类型的指针,每个块可能有多个参考帧索引。 map_ipm是帧内预测模式,s8指针,记录每个块的预测模式。 map_cu_mode是u32指针,可能存储CU的模式,比如帧内、帧间等。 接下来是条件编译的部分,比如TB_SPLIT_EXT,可能涉及变换块的分割,map_pb_tb_part记录分块信息。 map_depth是s8指针,记录每个CU的深度,这在编码树结构中很重要。 map_delta_qp是s8指针,存储QP的差值,用于量化参数的调整。 map_patch_idx可能与图像分块有关,记录每个CU所属的patch索引。 USE_SP相关的map_usp可能用于特殊编码工具,比如Skip模式或其他高级特性。 最后,在PATCH宏定义下,有一些临时映射的成员,如map_scu_temp、map_cu_mode_temp等,可能是用于临时存储或处理过程中的中间数据,避免直接修改原始数据。 需要确认每个成员的数据类型和用途,比如指针和数组的维度,条件编译的影响。此外,注释中的术语如SCU、LCU、CU、运动矢量、参考帧索引等都是视频编码中的常见概念,可能需要结合标准如HEVC/H.265来解释。 用户可能正在学习或开发视频编码相关的代码,需要理解这个结构体如何组织数据,以便进一步调试或扩展功能。因此,分析时要尽量详细,指出每个成员的作用和可能的应用场景,帮助用户建立整体结构的概念。</think>以下是对`COM_MAP`结构体的分层分析: --- ### **一、基础信息** 1. **结构体名称** `COM_MAP`:视频编码中用于存储编码单元(CU)相关信息的映射结构 2. **设计特征** - 包含多种编码信息映射表 - 使用条件编译适配不同编码配置(如`CTU_256`、`TB_SPLIT_EXT`等) --- ### **二、核心成员解析** #### **(1) 编码单元信息** | 成员名 | 类型 | 说明 | |------------------|---------------|----------------------------------------------------------------------| | `map_scu` | `u32*` | SCU(Smallest Coding Unit)映射表,存储CU的编码模式和控制信息 | | `map_cu_mode` | `u32*` | 记录每个CU的预测模式(帧内/帧间/特殊模式) | | `map_depth` | `s8*` | 存储CU的深度信息(反映编码树划分层级) | #### **(2) 运动信息** | 成员名 | 类型 | 说明 | |------------------|--------------------------|----------------------------------------------------------------------| | `map_mv` | `s16(*)[REFP_NUM][MV_D]` | 二维运动矢量数组,维度:参考帧列表数 × 运动矢量分量(水平/垂直) | | `map_refi` | `s8(*)[REFP_NUM]` | 参考帧索引表,记录每个CU使用的参考帧编号 | #### **(3) 块划分信息** ```c #if CTU_256 s8 (*map_split)[MAX_CU_DEPTH2][NUM_BLOCK_SHAPE][MAX_CU_CNT_IN_LCU]; #else s8 (*map_split)[MAX_CU_DEPTH][NUM_BLOCK_SHAPE][MAX_CU_CNT_IN_LCU]; #endif ``` - **功能**:记录LCU(Largest Coding Unit)的递归划分信息 - **维度解析**: - `MAX_CU_DEPTH(2)`:最大划分深度(`CTU_256`开启时深度更大) - `NUM_BLOCK_SHAPE`:支持的块形状类型(方形/矩形等) - `MAX_CU_CNT_IN_LCU`:单个LCU内允许的最大CU数量 #### **(4) 其他辅助信息** | 成员名 | 类型 | 说明 | |--------------------|---------|----------------------------------------------------------------------| | `map_ipm` | `s8*` | 帧内预测模式表(如DC/Planar/角度预测模式) | | `map_delta_qp` | `s8*` | 量化参数(QP)差值映射表 | | `map_patch_idx` | `s8*` | 图像分块索引(用于并行处理或分块编码) | --- ### **三、条件编译扩展** #### **(1) 变换块划分扩展** ```c #if TB_SPLIT_EXT u32* map_pb_tb_part; // 记录变换块(TB)的划分方式 #endif ``` #### **(2) 特殊编码工具支持** ```c #if USE_SP u8* map_usp; // 可能用于Skip/Merge等特殊预测模式标记 #endif ``` --- ### **四、临时存储区(用于算法中间过程)** ```c #if PATCH u32* map_scu_temp; // SCU临时存储 u32* map_cu_mode_temp; // CU模式临时存储 s16 (*map_mv_temp)[REFP_NUM][MV_D]; // 运动矢量临时存储 s8 (*map_refi_temp)[REFP_NUM]; // 参考帧索引临时存储 #if USE_SP u8* map_usp_temp; // 特殊模式标记临时存储 #endif #endif ``` --- ### **五、典型应用场景** 1. **编码决策**:通过`map_split`和`map_depth`实现率失真优化的编码树划分 2. **运动补偿**:利用`map_mv`和`map_refi`进行帧间预测 3. **并行处理**:通过`map_patch_idx`支持分块编码的线程级并行 4. **码流生成**:结合`map_cu_mode`和`map_ipm`生成最终码流语法元素 --- ### **六、设计特点总结** 1. **内存布局优化**:通过指针数组实现动态内存分配,适应不同分辨率需求 2. **模块化设计**:通过条件编译支持可裁剪的编码功能 3. **数据隔离**:使用独立字段存储不同类型信息,提高缓存局部性
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值