TpsFs文件系统简介

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内核源码

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章