1、TpsFs簡介
TpsFs(True Power Safe File System)是一款掉電安全的文件系統,該文件系統是SylixOS內建文件系統(專利技術)。TpsFs是基於事務的B+樹文件系統:對元數據的修改使用事務提交的機制,保證了文件系統的一致性;使用B+樹管理磁盤空間和文件空間,使得存儲文件數據與定位速度更快、空間管理效率更高。TpsFs的源碼可以在SylixOS Base工程下的"libsylixos/SylixOS/fs/TpsFs/"目錄下查看。
2、TpsFs基本數據結構簡介
每一種文件系統都有自己特定的數據結構和管理數據的方式,不同的文件系統其數據結構也有所不同,但所有文件系統也有一定的共性。下面介紹TpsFs中用來管理數據的一些結構。
2.1數據單元
當文件系統在磁盤分區上創建後,就可以進行數據的讀取和存儲了。數據在寫入磁盤或從磁盤讀取時每次操作的數據量稱爲數據單元,它的大小在建立文件系統時確定。數據單元在不同的文件系統中有不同的稱呼方式,例如FAT中的"簇",EXT中的"塊"。一個數據單元由若干個連續物理扇區組成,大小總是2的整數次冪個扇區。存儲數據時,系統以數據單元爲最小單位爲其分配存儲空間。在TpsFs中,數據單元以"塊"爲單位,並且最小不能小於4096字節,塊大小可以在格式化TpsFs文件系統時通過tpsFsFormat函數的參數指定,通常情況下將其設置爲4096字節。tpsFsFormat函數原型如程序清單2- 1所示。
程序清單2- 1 tpsFs格式化函數
errno_t tpsFsFormat (PTPS_DEV pdev, UINT uiBlkSize)
函數tpsFsFormat原型分析如下:
函數成功返回ERROR_NONE,失敗返回錯誤號;
參數pdev是設備對象;
參數uiBlkSize是塊大小。
塊號的定義如程序清單2- 2所示。
程序清單2- 2 塊號定義
typedef UINT64 TPS_INUM;
2.2超級塊
超級塊用來描述一個文件系統的基本信息,例如文件系統塊大小、總塊數、文件系統在磁盤分區內的整體佈局(數據區、日誌區等位置和大小)、已打開文件鏈表等等。TpsFs將超級塊保存在磁盤分區的第0塊內,每一個磁盤分區內只有一個超級塊結構體。超級塊結構體的定義如程序清單2- 3所示。
程序清單2- 3 超級塊結構體定義
typedef struct tps_super_block { UINT SB_uiMagic; /* magic數值 */ UINT SB_uiVersion; /* 版本 */ UINT SB_uiSectorSize; /* 塊設備的扇區大小 */ UINT SB_uiSectorShift; UINT SB_uiSectorMask; UINT SB_uiSecPerBlk; /* 每塊扇區數 */ UINT SB_uiBlkSize; /* 塊大小 */ UINT SB_uiBlkShift; UINT SB_uiBlkMask; UINT SB_uiFlags; /* 掛載標識 */ UINT64 SB_ui64Generation; /* 標識一次格式化用於系統修復 */ UINT64 SB_ui64TotalBlkCnt; /* 總塊數 */ UINT64 SB_ui64DataStartBlk; /* 數據塊起始 */ UINT64 SB_ui64DataBlkCnt; /* 數據塊數量 */ UINT64 SB_ui64LogStartBlk; /* 日誌塊起始 */ UINT64 SB_ui64LogBlkCnt; /* 日誌塊數量 */ UINT64 SB_ui64BPStartBlk; /* btree塊緩衝表起始塊 */ UINT64 SB_ui64BPBlkCnt; /* btree塊緩衝表塊數量 */ TPS_INUM SB_inumSpaceMng; /* 空間管理inode號 */ TPS_INUM SB_inumRoot; /* 文件系統根inode號 */ TPS_INUM SB_inumDeleted; /* 已刪除文件列表 */ PTPS_DEV SB_dev; /* 設備對象指針 */ struct tps_inode *SB_pinodeSpaceMng; /* 空間管理inode */ struct tps_inode *SB_pinodeRoot; /* 文件系統根inode */ struct tps_inode *SB_pinodeDeleted; /* 已經刪除的文件 */ struct tps_inode *SB_pinodeOpenList; /* 以打開文件鏈表 */ UINT SB_uiInodeOpenCnt; /* 當前打開文件數 */ PUCHAR SB_pucSectorBuf; /* 磁盤頁面緩衝區 */ struct tps_blk_pool *SB_pbp; /* btree塊緩衝鏈表 */ struct tps_trans_sb *SB_ptranssb; /* 事務系統超級塊 */ } TPS_SUPER_BLOCK;
2.3inode節點
inode節點也被稱作元數據,用於表示一個文件,這裏的文件不只是普通文件,也包括目錄等其他類型的文件,與Linux相似,SylixOS也遵循一切皆文件的原則,文件的類型定義符合UNIX標準,文件類型保存在inode結構體中的IND_iMode成員裏,其類型有以下幾種。
表2- 1 文件類型
IND_iMode | 文件類型 |
S_IFIFO | FIFO文件 |
S_IFCHR | 字符設備 |
S_IFDIR | 目錄 |
S_IFBLK | 塊設備 |
S_IFREG | 普通文件 |
S_IFLNK | 符號鏈接 |
S_IFSOCK | Socket文件 |
inode還記錄了文件的大小、創建時間、訪問權限等內容。
2.4目錄項
如果一個文件的類型爲目錄,那麼這個文件的數據區保存的數據就是目錄項結構,該目錄下的每一個子文件都對應一個目錄項。目錄項記錄了這個子文件的名字、名字長度和該子文件對應的inode節點所在位置,查找文件實際上就是從根節點開始遍歷目錄項的過程。
2.5B+樹
B+樹可以減少磁盤的訪問次數,提高文件的查找效率,文件系統一般都會採用B/B+樹來對文件數據進行管理。TpsFs內有兩種B+樹,一種是用於管理空閒塊的B+樹,它由空間管理inode進行管理,可以看做是一個大文件,其文件的inode是空間管理inode;另一種是用於管理普通文件空間的B+樹,它用於管理這個文件內的數據塊,即每一個普通文件都會對應一個B+樹來進行數據管理。通過該普通文件對應的inode可以查找到B+樹的根節點,進而可以實現整個B+樹的遍歷。
2.6事務
TpsFs採用事務提交機制,即每次進行寫操作(寫數據+寫元數據)時,會把各個步驟看做是一個個小事務,整體算一個大事務,TpsFs會把各個小事務先寫進日誌塊區域,日誌全部寫進成功之後,再把它寫進數據塊區域。
3、TpsFs整體佈局
由上一節可知,TpsFs的整體佈局由超級塊結構體描述,在TpsFs中,超級塊的一些常量定義如程序清單3- 1所示。
程序清單3- 1 超級塊常量
/************************************************************************** super block常量定義 **************************************************************************/ #define TPS_MIN_LOG_SIZE (512 * 1024) /* 最小日誌大小 */ #define TPS_SUPER_BLOCK_SECTOR 0 /* 超級快扇區號 */ #define TPS_SUPER_BLOCK_NUM 0 /* 超級塊號 */ #define TPS_SPACE_MNG_INUM 1 /* 空間管理inode號 */ #define TPS_ROOT_INUM 2 /* 根inode號 */ #define TPS_BPSTART_BLK 3 /* 塊緩衝起始 */ #define TPS_BPSTART_CNT 7 /* 塊緩衝塊數目 */ #define TPS_DATASTART_BLK 10 /* 數據塊起始 */ #define TPS_MIN_BLK_SIZE 4096 /* 最小塊大小限制 */
文件系統佈局是在磁盤分區格式化時建立的,格式化函數tpsFsFormat建立文件系統佈局的流程如程序清單2- 3所示。
程序清單3- 2 tpsFsFormat函數建立文件系統佈局
errno_t tpsFsFormat (PTPS_DEV pdev, UINT uiBlkSize) { ... /* * 磁盤最小爲 4MB */ uiSctPerBlk = uiBlkSize / uiSectorSize; uiTotalBlkCnt = pdev->DEV_SectorCnt(pdev) / uiSctPerBlk; if (uiTotalBlkCnt < 1024) { return (ENOSPC); } /* * logsize爲磁盤的 1/16 */ uiLogBlkCnt = uiTotalBlkCnt >> 4; uiLogSize = uiLogBlkCnt * uiBlkSize; if (uiLogSize < TPS_MIN_LOG_SIZE) { uiLogSize = TPS_MIN_LOG_SIZE; } /* * 結構體賦值 */ psb = (PTPS_SUPER_BLOCK)TPS_ALLOC(sizeof(TPS_SUPER_BLOCK)); if (LW_NULL == psb) { return (ENOMEM); } psb->SB_uiMagic = TPS_MAGIC_SUPER_BLOCK2; psb->SB_uiVersion = TPS_CUR_VERSION; psb->SB_ui64Generation = TPS_UTC_TIME(); psb->SB_uiSectorSize = uiSectorSize; psb->SB_uiSectorShift = (UINT)archFindMsb((UINT32)uiSectorSize) - 1; psb->SB_uiSectorMask = ((1 << psb->SB_uiSectorShift) - 1); psb->SB_uiSecPerBlk = uiSctPerBlk; psb->SB_uiBlkSize = uiBlkSize; psb->SB_uiBlkShift = (UINT)archFindMsb((UINT32)psb->SB_uiBlkSize) - 1; psb->SB_uiBlkMask = ((1 << psb->SB_uiBlkShift) - 1); psb->SB_uiFlags = TPS_MOUNT_FLAG_READ | TPS_MOUNT_FLAG_WRITE; psb->SB_ui64TotalBlkCnt = uiTotalBlkCnt; psb->SB_ui64DataStartBlk = TPS_DATASTART_BLK; psb->SB_ui64DataBlkCnt = uiTotalBlkCnt - TPS_DATASTART_BLK - uiLogBlkCnt; psb->SB_ui64LogStartBlk = uiTotalBlkCnt - uiLogBlkCnt; psb->SB_ui64LogBlkCnt = uiLogBlkCnt; psb->SB_ui64BPStartBlk = TPS_BPSTART_BLK; psb->SB_ui64BPBlkCnt = TPS_BPSTART_CNT; psb->SB_inumSpaceMng = TPS_SPACE_MNG_INUM; psb->SB_inumRoot = TPS_ROOT_INUM; psb->SB_inumDeleted = 0; psb->SB_pinodeOpenList = LW_NULL; psb->SB_dev = pdev; psb->SB_uiInodeOpenCnt = 0; psb->SB_pinodeDeleted = LW_NULL; psb->SB_pbp = LW_NULL; ... }
由程序清單3- 2可以看出,tpsFsFormat函數根據磁盤分區的扇區數量,塊大小以及超級塊常量來構建文件系統,格式化完成後,文件系統在磁盤分區內的佈局如圖3- 1所示。
圖3- 1 文件系統佈局
4、總結
本文主要介紹了TpsFs的整體框架,TpsFs的讀寫流程,事務提交,B+樹管理機制等將在後續文檔介紹。
5、參考資料
《SylixOS應用程序開發手冊》
SylixOS內核源碼