版权声明:本文为博主原创文章,未经博主允许不得转载。 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。
- Hot node : contains direct node blocks of directories.
- Warm node : contains direct node blocks except hot node blocks.
- Cold node : contains indirect node blocks
- Hot data : contains dentry blocks
- Warm data : contains data blocks except hot and cold data blocks
- 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);
}