F2FS源码分析-1.3 [F2FS 元数据布局部分] Checkpoint结构
F2FS源碼分析系列文章
主目錄
一、文件系統布局以及元數據結構
二、文件數據的存儲以及讀寫
三、文件與目錄的創建以及刪除(未完成)
四、垃圾回收機制
五、數據恢復機制
六、重要數據結構或者函數的分析
Checkpoint區域
Checkpoint是維護F2FS的數據一致性的結構,它維護了系統當前的狀態,例如segment的分配情況,node的分配情況,以及當前的active segment的狀態等。F2FS在滿足一定的條件的情況下,會將當前系統的分配狀態寫入到Checkpoint中,萬一系統出現突然宕機,這個是F2FS可以從Checkpoint中恢復到上次回寫時的狀態,以保證數據的可恢復性。F2FS維護了兩個Checkpoint結構,互為備份,其中一個是當前正在使用的Checkpoint,另外一個上次回寫的穩定的Chcekpoint。如果系統出現了宕機,那么當前的Checkpoint就會變得不可信任,進而使用備份Checkpoint進行恢復。
Checkpoint在元數據區域的物理結構
根據上述的結構圖,Checkpoint區域由幾個部分構成,分別是checkpoint元數據區域(f2fs_checkpoint)、orphan node區域、active segments區域。同時active segments區域在不同的情況下,會有不同的形式,目的是減少IO的寫入。接下來分別討論Checkpoint不同的部分。
Checkpoint元數據區域
F2FS使用數據結構f2fs_checkpoint表示Checkpoint結構,它保存在磁盤中f2fs_super_block之后區域中,數據結構如下。需要特別注意的是cur_node_segno、cur_node_blkoff、cur_data_segno、cur_data_blkoff這幾個變量。第一節提到,F2FS分為了6個log區域,分別對應hot node/data、warm node/data、cold node/data。F2FS必須定時執行Checkpoint去記錄當前系統的log分配到哪個位置,否則在系統宕機的時候,會出現數據丟失等一致性問題,因此cur_xxx_segno以及cur_xxx_blkoff記錄了上次Checkpoint時,系統正在使用的log的segment number,以及分配到這個segment的哪個位置。
struct f2fs_checkpoint {__le64 checkpoint_ver; /* CP版本,用于比較新舊版本進行恢復 */__le64 user_block_count; /* # of user blocks */__le64 valid_block_count; /* # of valid blocks in main area */__le32 rsvd_segment_count; /* # of reserved segments for gc */__le32 overprov_segment_count; /* # of overprovision segments */__le32 free_segment_count; /* # of free segments in main area *//* information of current node segments */__le32 cur_node_segno[MAX_ACTIVE_NODE_LOGS];__le16 cur_node_blkoff[MAX_ACTIVE_NODE_LOGS];/* information of current data segments */__le32 cur_data_segno[MAX_ACTIVE_DATA_LOGS];__le16 cur_data_blkoff[MAX_ACTIVE_DATA_LOGS];__le32 ckpt_flags; /* Flags : umount and journal_present */__le32 cp_pack_total_block_count; /* total # of one cp pack */__le32 cp_pack_start_sum; /* start block number of data summary */__le32 valid_node_count; /* Total number of valid nodes */__le32 valid_inode_count; /* Total number of valid inodes */__le32 next_free_nid; /* Next free node number */__le32 sit_ver_bitmap_bytesize; /* Default value 64 */__le32 nat_ver_bitmap_bytesize; /* Default value 256 */__le32 checksum_offset; /* checksum offset inside cp block */__le64 elapsed_time; /* mounted time *//* allocation type of current segment */unsigned char alloc_type[MAX_ACTIVE_LOGS];/* SIT and NAT version bitmap */unsigned char sit_nat_version_bitmap[1]; } __packed;Orphan node區域
這是一個動態的區域,如果沒有orphan node list則不會占用空間。
Active Segments區域
Active Segments的定義
Active Segments,又稱current segment(CURSEG),即當前正在用于進行數據分配的log對應的segment,如用戶需要寫入8KB數據,那么就會從active segments分配兩個block提供給用戶寫入到磁盤中。F2FS為了提高數據分配的效率,根據數據的特性,一共定義了6個active segment。如第一章的總體結構這一節提到的multi-head logging特性所描述,這6個active segments對應了(how, warm, cold) X (node, data)的數據。
Active Segment與恢復相關的數據結構
CP的主要任務是維護數據一致性,因此CP的active segment區域的主要任務是維護Active Segment的分配狀態,使系統宕機時候可以恢復正常。維護active segment需要維護三種信息,分別是f2fs_checkpoint的信息,以及該segment對應的journal和summary的信息。
-
f2fs_checkpoint中Active Segment信息:從上面給出的f2fs_checkpoint定義,cur_node_segno[MAX_ACTIVE_NODE_LOGS]和cur_data_segno[MAX_ACTIVE_DATA_LOGS]表示node和data當前的Active Segment的編號(segment number, segno),系統可以通過這個編號找到對應的segment。MAX_ACTIVE_NODE_LOGS以及MAX_ACTIVE_NODE_LOGS分別表示data和node有多少種類型,F2FS默認情況下都等于3,表示、、即HOT、WARM、COLD類型數據。cur_node_blkoff[MAX_ACTIVE_NODE_LOGS]以及cur_data_blkoff[MAX_ACTIVE_DATA_LOGS]則分別表示當前active segment分配到哪一個block(一個segment包含了512個block)。
-
Segment對應的Journal信息:Journal在兩處地方都有出現,分別是CP區域以及SSA區域。CP區域的journal主要用來保存active segment的修改信息,而SSA區域的則是持久化保存的所有的segment的journal信息。如系統分配出一個block給用戶,那么就要將這個block所在的segment的bitmap中標記為已分配,防止其他寫請求使用。分兩個區域存放journal是為了減輕頻繁更新導致的系統性能下降。例如,當系統寫壓力很大的時候,bitmap就會頻繁被更新,如果這個時候頻繁將bitmap寫入SSA,就會加重寫壓力。因此CP區域的Journal的作用就是維護這些經常修改的數據,等待CP被觸發的時候才回寫到閃存設備,從而減少寫壓力,提高閃存壽命。(journal的實現參考第六章的journal這一節)
-
Segment對應的Summary信息:summary同樣在CP區域和SSA區域有出現,它表示的是邏輯地址和物理地址的映射關系,這個映射關系會使用到GC流程中。summary與segment是一對一的關系,一個summary保存了一個segment所有的block的物理地址和邏輯地址的映射關系。summary保存在CP區域中同樣是出于減少IO的寫入。
Checkpoint內存管理結構
Checkpoint的內存管理結構是struct f2fs_checkpoint本身,因為Checkpoint一般只在F2FS啟動的時候被讀取數據,用于數據恢復,而在運行過程中大部分情況都是被寫,用于記錄恢復信息。因此,Checkpoint不需要過于復雜的內存管理結構,因此使用struct f2fs_checkpoint本身即可以滿足需求。
另一方面,active segments,即F2FS的log,主要用于系統free block的分配,因此需要特定的管理結構struct curseg_info進行管理,它的定義如下:
struct curseg_info {struct mutex curseg_mutex;struct f2fs_summary_block *sum_blk; /* 每一個segment對應一個summary block */struct rw_semaphore journal_rwsem;struct f2fs_journal *journal; /*每一個segment對應一個 info */unsigned char alloc_type;unsigned int segno; /* 當前segno */unsigned short next_blkoff; /* 記錄當前segment用于分配的下一個給block號 */unsigned int zone; /* current zone number */unsigned int next_segno; /* 當前segno用完以后,下個即將用來分配的segno */ };從結構分析可以直到,curseg_info記錄當前的segment的分配信息,當系統出現宕機的時候,可以從CP記錄的curseg_info恢復當上一次CP點的狀態。
每一種類型的active segment就對應一個struct curseg_info結構。在F2FS中,使用一個數組來表示:
struct f2fs_sm_info {...struct curseg_info *curseg_array; // 默認是分配6個curseg_info,分別對應不同類型... }struct f2fs_sm_info是SIT的管理結構,它也管理了CP最終的active segment的信息,是一個跨區域的管理結構。
struct f2fs_checkpoint通過get_checkpoint_version函數從磁盤讀取出來:
static int get_checkpoint_version(struct f2fs_sb_info *sbi, block_t cp_addr,struct f2fs_checkpoint **cp_block, struct page **cp_page,unsigned long long *version) {unsigned long blk_size = sbi->blocksize;size_t crc_offset = 0;__u32 crc = 0;*cp_page = f2fs_get_meta_page(sbi, cp_addr); // 根據CP所在的地址cp_addr從磁盤讀取一個block*cp_block = (struct f2fs_checkpoint *)page_address(*cp_page); // 直接轉換為數據結構crc_offset = le32_to_cpu((*cp_block)->checksum_offset);if (crc_offset > (blk_size - sizeof(__le32))) {f2fs_msg(sbi->sb, KERN_WARNING,"invalid crc_offset: %zu", crc_offset);return -EINVAL;}crc = cur_cp_crc(*cp_block);if (!f2fs_crc_valid(sbi, crc, *cp_block, crc_offset)) { // 比較CRC的值,進而知道是否成功讀取出來f2fs_msg(sbi->sb, KERN_WARNING, "invalid crc value");return -EINVAL;}*version = cur_cp_version(*cp_block);return 0; }struct curseg_info則是通過build_curseg函數進行初始化:
static int build_curseg(struct f2fs_sb_info *sbi) {struct curseg_info *array;int i;array = f2fs_kzalloc(sbi, array_size(NR_CURSEG_TYPE, sizeof(*array)),GFP_KERNEL); // 根據active segment類型的數目分配空間if (!array)return -ENOMEM;SM_I(sbi)->curseg_array = array; // 賦值到f2fs_sm_info->curseg_arrayfor (i = 0; i < NR_CURSEG_TYPE; i++) { // 為curseg的其他信息分配空間mutex_init(&array[i].curseg_mutex);array[i].sum_blk = f2fs_kzalloc(sbi, PAGE_SIZE, GFP_KERNEL);if (!array[i].sum_blk)return -ENOMEM;init_rwsem(&array[i].journal_rwsem);array[i].journal = f2fs_kzalloc(sbi,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); // 從f2fs_checkpoint恢復上一個CP點CURSEG的狀態 }static int restore_curseg_summaries(struct f2fs_sb_info *sbi) {struct f2fs_journal *sit_j = CURSEG_I(sbi, CURSEG_COLD_DATA)->journal;struct f2fs_journal *nat_j = CURSEG_I(sbi, CURSEG_HOT_DATA)->journal;int type = CURSEG_HOT_DATA;int err;...for (; type <= CURSEG_COLD_NODE; type++) { // 按類型逐個恢復active segment的信息err = read_normal_summaries(sbi, type);if (err)return err;}...return 0; }static int read_normal_summaries(struct f2fs_sb_info *sbi, int type) {struct f2fs_checkpoint *ckpt = F2FS_CKPT(sbi);struct f2fs_summary_block *sum;struct curseg_info *curseg;struct page *new;unsigned short blk_off;unsigned int segno = 0;block_t blk_addr = 0;...segno = le32_to_cpu(ckpt->cur_data_segno[type]); // 從CP讀取segnoblk_off = le16_to_cpu(ckpt->cur_data_blkoff[type - CURSEG_HOT_DATA]); // 從CP讀取blk_offblk_addr = sum_blk_addr(sbi, NR_CURSEG_DATA_TYPE, type); // 獲取summary block地址 // 讀取&轉換結構new = f2fs_get_meta_page(sbi, blk_addr);sum = (struct f2fs_summary_block *)page_address(new);curseg = CURSEG_I(sbi, type); // 根據type找到對應的cursegmutex_lock(&curseg->curseg_mutex);/* 復制&恢復數據 */down_write(&curseg->journal_rwsem);memcpy(curseg->journal, &sum->journal, SUM_JOURNAL_SIZE);up_write(&curseg->journal_rwsem);memcpy(curseg->sum_blk->entries, sum->entries, SUM_ENTRY_SIZE);memcpy(&curseg->sum_blk->footer, &sum->footer, SUM_FOOTER_SIZE);curseg->next_segno = segno;reset_curseg(sbi, type, 0);curseg->alloc_type = ckpt->alloc_type[type];curseg->next_blkoff = blk_off; // 恢復上次的分配狀態mutex_unlock(&curseg->curseg_mutex);f2fs_put_page(new, 1);return 0; }總結
以上是生活随笔為你收集整理的F2FS源码分析-1.3 [F2FS 元数据布局部分] Checkpoint结构的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 基于微信小程序的电影院买票选座系统
- 下一篇: 无刷电调--BLHELI_S的焊接问题与