XFS文件系统
超级块:
超级块记录了整个xfs文件系统的一些重要数据,例如磁盘块(通常是以4096字节为单位的)的总数,磁盘块的大小,使用的磁盘块/未使用的磁盘块的个数等。超级块是整个文件系统最重要的部分,如果他的数据不正确,文件系统就无法使用了,所以每个分配组有一个超级块,但使用的只有第一个分配组的超级块,其他的都是备份用的。这样一来,如果超级块被损坏,可以使用其他的分配组的,有些数据可能丢失,但不致于是整个文件系统都不能用。
超级块的磁盘上的结构和linux源代码中的xfs_sb结构体是一模一样的。
typedef struct xfs_sb |
|
{ |
|
__uint32_t sb_magicnum; |
4个字节的文件系统标示,翻译成中文暂且叫幻数吧! 对于xfs文件系统,他就是四个字母”XFSB” |
__uint32_t sb_blocksize; |
一个磁盘块所占的字节数(通常是4096个字节) |
xfs_drfsbno_t sb_dblocks; |
数据块的个数 |
xfs_drfsbno_t sb_rblocks; |
实时数据块的个数 |
xfs_drtbno_t sb_rextents; |
实时区域的个数 |
uuid_t sb_uuid; |
文件系统的UUID |
xfs_dfsbno_t sb_logstart; |
日志区域的开始块号 |
xfs_ino_t sb_rootino; |
根节点的索引节点id |
xfs_ino_t sb_rbmino; |
|
xfs_ino_t sb_rsumino; |
|
xfs_agblock_t sb_rextsize; |
|
xfs_agblock_t sb_agblocks; |
一个分配组的块数 |
xfs_agnumber_t sb_agcount; |
分配组的个数 |
xfs_extlen_t sb_rbmblocks; |
|
xfs_extlen_t sb_logblocks; |
日志块的个数 |
__uint16_t sb_versionnum; |
|
__uint16_t sb_sectsize; |
|
__uint16_t sb_inodesize; |
一个索引节点所占的字节数 |
__uint16_t sb_inopblock; |
一个磁盘块有多少个索引节点 |
char sb_fname[12]; |
文件系统的名字 |
__uint8_t sb_blocklog; |
|
__uint8_t sb_sectlog; |
|
__uint8_t sb_inodelog; |
|
__uint8_t sb_inopblog; |
|
__uint8_t sb_agblklog; |
|
__uint8_t sb_rextslog; |
|
__uint8_t sb_inprogress; |
|
__uint8_t sb_imax_pct; |
|
__uint64_t sb_icount; |
已分配的索引节点的个数 |
__uint64_t sb_ifree; |
剩余的索引节点的个数 |
__uint64_t sb_fdblocks; |
空闲的数据块个数 |
__uint64_t sb_frextents; |
|
xfs_ino_t sb_uquotino; |
用于管理用户配额的索引节点的id |
xfs_ino_t sb_gquotino; |
用于管理组配额的索引节点的id |
__uint16_t sb_qflags; |
|
__uint8_t sb_flags; |
|
__uint8_t sb_shared_vn; |
|
xfs_extlen_t sb_inoalignmt; |
|
__uint32_t sb_unit; |
|
__uint32_t sb_width; |
|
__uint8_t sb_dirblklog; |
|
__uint8_t sb_logsectlog; |
|
__uint16_t sb_logsectsize; |
|
__uint32_t sb_logsunit; |
|
} xfs_sb_t; |
|
文件系统的第一个索引节点----根目录的索引节点id=128,这是至最小的索引节点,它位于第64个块(512字节)的位置。用户配额文件是132,组配额文件是133。对于NEC的SXFS文件系统:snap文件的索引节点是131,dataset文件是135。
文件系统刚被做成,也就是刚被格式化完时,会预先分配好一部分索引节点。对于每个分配组来说,这些索引节点的组内id为128-191。索引节点占256个字节,每两个节点占一个512字节的块。索引这些节点连续分布在第64-96个块之间。虽然索引节点结构体xfs_dinode_core只有128个字节,但一个索引节点却占256个字节的磁盘空间。为什么呢?主要是为了存放数据比较小的节点,比如对于一个目录节点,它下面可能有3个文件,结果这三个文件组成的3个entry可以存放在128字节的空间里,这样就不必给这个目录节点分配数据块,而直接将3个文件entry存放在目录节点的256个字节的区域里就可以了。
索引节点的id为什么会从128开始呢?
一个分配组是由一系列512字节的块组成的。前63个块都被用来存放系统或分配组的信息了。每2个索引节点占512个字节的块,如果从第0个块开始计算,第64个块恰好是128,129所在的位置。这样如果通过id来找一个节点的话,只需将id除以2,就可以找到位置了。例如128/2=64,id为128的索引节点在第64个块里。另外,如果预先分配的节点用完了,系统会再开辟一段空间来继续分配,但节点号不会从上次的开始,因为节点号跟所在的块的块号有关。比如预先分配的节点是12-191,如果用完了,系统在分配的id不一定是192,这要看第96个块是否被使用,事实上第96个块是quota文件的数据块。如果节点在第200个块上,他的id就是200*2=400。
XAGF块的结构和源代码中的xfs_agf结构体是一样的。
XAGI块的结构和源代码中的xfs_agi结构体是一样的。
inode结构
存在于磁盘的inode结构和源代码中的xfs_dinode结构体是一样的。里面含有文件大小,所占块数,父目录节点的id,时间等信息。但没有节点名字的信息,因为名字存在于父目录中。
多余的128字节是怎样处理的?
typedef struct xfs_dinode
{
xfs_dinode_core_t di_core;
xfs_agino_t di_next_unlinked;/* agi unlinked list ptr */
union {
xfs_bmdr_block_t di_bmbt; /* btree root block */
xfs_bmbt_rec_32_t di_bmx[1]; /* extent list */
xfs_dir_shortform_t di_dirsf; /* shortform directory */
xfs_dir2_sf_t di_dir2sf; /* shortform directory v2 */
char di_c[1]; /* local contents */
xfs_dev_t di_dev; /* device for S_IFCHR/S_IFBLK */
uuid_t di_muuid; /* mount point value */
char di_symlink[1]; /* local symbolic link */
} di_u;
union {
xfs_bmdr_block_t di_abmbt; /* btree root block */
xfs_bmbt_rec_32_t di_abmx[1]; /* extent list */
xfs_attr_shortform_t di_attrsf; /* shortform attribute list */
} di_a;
} xfs_dinode_t;
如果子节点太多,多余的128字节已经装不下了,则di_u将是di_bmbt起作用了。
user quota节点
此节点号为132,位于第66个块,根据di_u域找到第96个块为他的数据块。这个块是由entry组成的,每个entry的头两个字节为”DQ”表示是quota数据。entry的结构和xfs_disk_dquot结构体是一样的。包含quota类型,软硬限制,使用的节点数和块数等。
group quota节点
此节点号:133,位于第66个块的后半部,根据di_u域找到第104个块为他的数据块。快的结构也是由entry组成的,和user quota相同。
NEC的dataset节点
dataset节点号:135,位于第67个块后半部分,根据di_u域,找到第112个块为他的数据块。此块也是由entry组成的,他的每个entry头两个字节为”DD”,表示是数据集的块。entry结构和sxfs_dataset_disk结构体一样。
endian格式
endian格式存储变量到磁盘时,内存和磁盘上的格式是相反的。
比如 int i =0x12345678; //内存中0x12345678
i 在磁盘上会是 0x87654321
所以许多xfs_ino_t inode=0x80;在磁盘上却是 0x80 00 00 00
endian格式以类型为单位(int ,long long, short)倒置数据。char型不会倒置,char的单位就是一个字节,不用倒置。char[8]={“abcdef”};在磁盘上还是”abcdef”。