F2FS:struct curseg_info结构

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/jasonLee_lijiaqi/article/details/82973845

F2FS

在运行时,F2FS在“Main Area”区域管理6个活跃的log,分别是Hot/Warm/Cold node log和Hot/Warm/Cold data logs,每一个log对应着一个独立的segment。

  1. Hot node : contains direct node blocks of directories.
  2. Warm node : contains direct node blocks except hot node blocks.
  3. Cold node : contains indirect node blocks
  4. Hot data : contains dentry blocks
  5. Warm data : contains data blocks except hot and cold data blocks
  6. Cold data : contains multimedia data or migrated data blocks

根据数据所属的类型,利用对应的log分配的空间将数据写入该空间。

struct curseg_info 表示当前active log的信息(当前活跃的segment信息)

/* for active log information 
	当前segment的信息
	一共有6个不同类型的segment,以数组形式组织的
*/
struct curseg_info {
	struct mutex curseg_mutex;		/* lock for consistency */
	struct f2fs_summary_block *sum_blk;	/* cached summary block */
	struct rw_semaphore journal_rwsem;	/* protect journal area */
	struct f2fs_journal *journal;		/* cached journal info */
	unsigned char alloc_type;		/* current allocation type 当前segment的type*/
	unsigned int segno;			/* current segment number 当前segment号*/
	unsigned short next_blkoff;		/* next block offset to write 下一个要写入块的偏移量*/
	unsigned int zone;			/* current zone number 当前zone号*/
	unsigned int next_segno;		/* preallocated segment */
};

————————————————————————————————————————
f2fs一共有6个这样的结构,他们是通过build_curseg函数申请的;它构造一个长度为6的数组,每一个对象都是struct curseg_info 类型,分别指向不同类型的活跃segment

/* 构造一个长度为6的数组,每一个对象都是struct curseg_info 类型
	分别指向不同类型的活跃segment
*/
static int build_curseg(struct f2fs_sb_info *sbi)
{
	struct curseg_info *array;
	int i;

	/* 用于申请一个数组的内存空间,并把申请得到的内存都初始化为0 
	申请一个长度为6的数组,每个数组成员都是struct curseg_info 类型
	*/
	array = kcalloc(NR_CURSEG_TYPE, sizeof(*array), GFP_KERNEL);
	if (!array)
		return -ENOMEM;
	
	SM_I(sbi)->curseg_array = array;

	/* 初始化struct curseg_info类型数组 */
	for (i = 0; i < NR_CURSEG_TYPE; i++) {
		mutex_init(&array[i].curseg_mutex);
		array[i].sum_blk = kzalloc(PAGE_SIZE, GFP_KERNEL);
		if (!array[i].sum_blk)
			return -ENOMEM;
		init_rwsem(&array[i].journal_rwsem);
		array[i].journal = kzalloc(sizeof(struct f2fs_journal),
							GFP_KERNEL);
		if (!array[i].journal)
			return -ENOMEM;
		array[i].segno = NULL_SEGNO;
		array[i].next_blkoff = 0;
	}
	return restore_curseg_summaries(sbi);
}

要想获得特定类型的struct curseg_info结构,需要使用如下方法:

/* 通过type得到type类型的segment */
	curseg = CURSEG_I(sbi, type);

参数:f2fs_sb_info以及type(一共有6种类型)
具体实现:

/*
 * inline functions
 	依据type找到对应的struct curseg_info结构(因为是数组方式组织的,直接使用下标即可访问)
 */
static inline struct curseg_info *CURSEG_I(struct f2fs_sb_info *sbi, int type)
{
	return (struct curseg_info *)(SM_I(sbi)->curseg_array + type);
}

————————————————————————————————————————————————————————————

/* f2fs 向磁盘写page */
static void do_write_page(struct f2fs_summary *sum, struct f2fs_io_info *fio)
{
	/* 确定segment的type */
	int type = __get_segment_type(fio->page, fio->type);

	/* 从type类型对应的当前segment中,申请一个空闲block,空闲block的地址保存在fio->new_blkaddr */
	allocate_data_block(fio->sbi, fio->page, fio->old_blkaddr,
					&fio->new_blkaddr, sum, type);

	/* writeout dirty page into bdev 
		提交bio请求,将fio->page写入到块设备的fio->new_blkaddr地址中
	*/
	f2fs_submit_page_mbio(fio);
}
/* 确定segment的type */
static int __get_segment_type(struct page *page, enum page_type p_type)
{
	switch (F2FS_P_SB(page)->active_logs) {
	case 2:
		return __get_segment_type_2(page, p_type);
	case 4:
		return __get_segment_type_4(page, p_type);
	}
	/* NR_CURSEG_TYPE(6) logs by default */
	f2fs_bug_on(F2FS_P_SB(page),
		F2FS_P_SB(page)->active_logs != NR_CURSEG_TYPE);
	return __get_segment_type_6(page, p_type);
}
/* 确定segment的type */
static int __get_segment_type_6(struct page *page, enum page_type p_type)
{
	/* p_type有三种type:DATA、NODE、META*/
	if (p_type == DATA) {
		struct inode *inode = page->mapping->host;

		if (S_ISDIR(inode->i_mode))  //目录文件是HOT DATA
			return CURSEG_HOT_DATA;
		else if (is_cold_data(page) || file_is_cold(inode))
			return CURSEG_COLD_DATA;
		else
			return CURSEG_WARM_DATA;
	} else {
		/* 判断该page对应的NODE是不是dnode(dnode是direct node,直接指向data block)
			如果是dnode,且dnode是冷的,标记为WARM NODE,否则标记为HOT NODE;
			其他类型的node,标记为COLD NODE

			这是因为dnode经常被更新,所以设置为HOT或WARM
		*/
		if (IS_DNODE(page))
			return is_cold_node(page) ? CURSEG_WARM_NODE :
						CURSEG_HOT_NODE;
		else
			return CURSEG_COLD_NODE;
	}
}
/* 从type类型对应的当前segment中,申请一个空闲block,空闲block的地址保存在fio->new_blkaddr */
void allocate_data_block(struct f2fs_sb_info *sbi, struct page *page,
		block_t old_blkaddr, block_t *new_blkaddr,
		struct f2fs_summary *sum, int type)
{
	struct sit_info *sit_i = SIT_I(sbi);
	struct curseg_info *curseg;
	bool direct_io = (type == CURSEG_DIRECT_IO);

	type = direct_io ? CURSEG_WARM_DATA : type;

	/* 通过type得到type类型的segment */
	curseg = CURSEG_I(sbi, type);  

	mutex_lock(&curseg->curseg_mutex);
	mutex_lock(&sit_i->sentry_lock);

	/* direct_io'ed data is aligned to the segment for better performance */
	if (direct_io && curseg->next_blkoff &&
				!has_not_enough_free_secs(sbi, 0))
		/* 当前segment中没有足够的block,则申请新的segment */
		__allocate_new_segments(sbi, type);

	/* 确定即将写入的新的块地址 */
	*new_blkaddr = NEXT_FREE_BLKADDR(sbi, curseg);

	/*
	 * __add_sum_entry should be resided under the curseg_mutex
	 * because, this function updates a summary entry in the
	 * current summary block.
	 */
	__add_sum_entry(sbi, type, sum);

	/* 更新seg->next_blkoff,下一个要写入块的偏移量 */
	__refresh_next_blkoff(sbi, curseg);

	stat_inc_block_count(sbi, curseg);

	/* 如果当前segment中没有足够的block,则申请新的type类型的segment */
	if (!__has_curseg_space(sbi, type))
		sit_i->s_ops->allocate_segment(sbi, type, false);
	/*
	 * SIT information should be updated before segment allocation,
	 * since SSR needs latest valid block information.
	 */
	refresh_sit_entry(sbi, old_blkaddr, *new_blkaddr);

	mutex_unlock(&sit_i->sentry_lock);

	if (page && IS_NODESEG(type))
		fill_node_footer_blkaddr(page, NEXT_FREE_BLKADDR(sbi, curseg));

	mutex_unlock(&curseg->curseg_mutex);
}

猜你喜欢

转载自blog.csdn.net/jasonLee_lijiaqi/article/details/82973845