1 r5l_io_unit
/*
* an IO range starts from a meta data block and end at the next meta data
* block. The io unit's the meta data block tracks data/parity followed it. io
* unit is written to log disk with normal write, as we always flush log disk
* first and then start move data to raid disks, there is no requirement to
* write io unit with FLUSH/FUA
*/
struct r5l_io_unit {
struct r5l_log *log;
struct page *meta_page; /* store meta block */
int meta_offset; /* current offset in meta_page */
struct bio *current_bio;/* current_bio accepting new data */
atomic_t pending_stripe;/* how many stripes not flushed to raid */
u64 seq; /* seq number of the metablock */
sector_t log_start; /* where the io_unit starts */
sector_t log_end; /* where the io_unit ends */
struct list_head log_sibling; /* log->running_ios */
struct list_head stripe_list; /* stripes added to the io_unit */
int state;
bool need_split_bio;
};
(1) struct r5l_log *log
指向raid5的全局配置结构体
(2) struct page *meta_page
功能:存储meta block(以sh为单位)
初始化:需要新的r5l_io_unit时,alloc_page(GFP_NOIO | __GFP_NOFAIL | __GFP_ZERO),接着bio_add_page(io->current_bio, io->meta_page, PAGE_SIZE, 0)添加到结构体current_bio的bvec链表
消亡:__free_page(io->meta_page),当r5l_io_unit内的数据写到raid后,调用r5l_complete_finished_ios->r5l_free_io_unit->__free_page(io->meta_page)
(3) int meta_offset
功能:记录当前meta_page中的偏移,记录现在一页中数据写到哪里(meta_page采用追加写的方法)
初始化:申请新的meta_page后,现在元数据页写一个r5l_meta_block,接着io->meta_offset = sizeof(struct r5l_meta_block)
变化:每次在meta_page中追加写新的页(data/parity)时,都会在meta_page写元数据信息,写完后offset移动到末尾,的io->meta_offset += sizeof(struct r5l_payload_data_parity) + sizeof(__le32) * (1 + !!checksum2_valid)
结束:判断log->current_io->meta_offset + payload_size > PAGE_SIZE时,说明元数据页不能存放一个完整的sh元数据,就提交current_bio到log中,同时state置IO_UNIT_TO_START
(4) current_bio
功能:接收数据,记录元数据页和stripe的数据/校验页,提交数据到log的单位
初始化:申请新meta时产生,io->current_bio = r5l_bio_alloc(log);
结束:结束函数io->current_bio->bi_end_io = r5l_log_endio
(5) pending_stripe
功能:记录结构体中stripe的数目
变化:新stripe添加到一个当前结构体时,atomic_inc(&io->pending_stripe);atomic_dec_and_test(&io->pending_stripe),接着设置io状态IO_UNIT_STRIPE_END
(6) seq
功能:元数据页的序列号
初始化:创建新meta时,io->seq = log->seq++;
变化:没有改变呀
(7) log_start
功能:记录结构体在log的起始扇区
初始化:创建新meta时,io->log_start = log->log_start
变化:current_bio添加新的page后,调用r5_reserve_log_entry函数,这个函数里log中记录当前log中位置(扇区为单位)会加上8(环形存储区域,考虑简单情形)log->log_start=log->log_start + BLOCK_SECTORS;io->log_end记录本次bio的结束位置,io->log_end = log->log_start
(8) log_end
功能:和log_start对应,记录结构体在log的结束扇区
(9) log_sibling
功能:如果io的状态是IO_UNIT_TO_END,就把io->log_sibing从log->running_ios移到log->finished_ios
初始化:创建新meta时,INIT_LIST_HEAD(&io->log_sibling),list_add_tail(&io->log_sibling, &log->running_ios),
变化:如果io的状态是IO_UNIT_TO_END,就把io->log_sibing从log->running_ios移到log->finished_ios,或者从log->finished_ios->io删除io->sibling
进:
出:
(10) stripe_list
功能:记录结构体相关的stripe
初始化:申请新meta时,INIT_LIST_HEAD(&io->stripe_list)
变化:从io->stripe_list中取sh->log_list,删除,并置sh->state为STRIPE_HANDLE,准备写入RAID
进:
出:
(11) state
功能:记录结构体当前状态,来对不同状态的结构体执行不同操作
可选值:
IO_UNIT_RUNNING: 接受新IO;设置条件,新建meta,状态初始化为这个状态
IO_UNIT_IO_START: 结构体的bio正在写log;设置条件,把current_bio写到log时
IO_UNIT_IO_END:已经写到log;设置条件,已经写到log里,在bio的endio中设置
IO_UNIT_STRIPE_END:已经写到RAID;设置条件,r5l_stripe_write_finished函数
(12) need_split_bio
功能:记录是不是填满log设备,并且log->log_start从零开始