概述

    XFS为用户呈现一个标准的Unix文件系统接口:一棵由directory、file、symbolic link、device组成的树,这些实体在文件系统内部均由一个index node表示(即inode),旧版本inode大小为256字节,V5之后改成512B~2KB,默认512B,可以在mkfs时指定大小,一个inode number唯一引用一个inode。XFS内被切分成若干相等的chunk(16MB到1TB),称为Allocation Group(即AG),几乎可以认为AG就是一个管理自己空间、inode以及其他次要元数据的独立文件系统。当并发访问量增加的时候,拥有多个AG使得XFS可以并行处理大部分操作而不会降低性能,AG使用多个B+ tree维护空闲块位置、已分配inode位置、空闲inode位置等的记录。

    一个AG通常具有如下特征:

  • 一个描述文件系统整体信息的super block;

  • inode分配与跟踪;

  • 逆block-map索引(选配);

  • data block引用计数索引(选配);

AG组成

    执行mkfs.xfs之后,AG的disk layout如下:

XFS——inode分配与跟踪

    通常称XFS的第一个AG为primary AG,primary AG的super block维护着文件系统的全局信息,其他secondary AG的super block仅供xfs_repair使用。若super block中的XFS_SB_VERSION2_LAZYSBCOUNTBIT标记被置位,则仅在umount或shutdown更新disk对应内容。AG将空间划分为若干个相等大小的block并编号(File System Block,即FSB),AG使用两个B+tree跟踪free space,一个将block number做为key,一个将block count做为key,这种机制使得XFS能够快速找到接近指定block number或size的free space。AG使用一个free list为free space的两个B+tree预留空间,通常是4个block,耗尽则追加。AG基于可容纳64个inode的chunk分配inode,使用一个B+tree跟踪所有chunk中inode的分配与回收(即inode B+Tree),若设置了

XFS_SB_FEAT_RO_COMPAT_FINOBT属性,则会启用第二个B+tree跟踪那些包含空闲inode的chunk(即free inode B+tree),用于加速inode分配。

inode number编码机制

    XFS将inode在磁盘上的物理位置编码得到inode number,inode number有两种形式:

  • AG relative:通常是32bit以内,该AG中的FSB编号+该FSB中的inode编号;

  • absolute:通常是64bit,AG编号+该AG中的FSB编号+该FSB中的inode编号;

XFS——inode分配与跟踪

AG inode管理结构

    AG管理自己的inode,第三个sector包含inode的相关信息(即AGI),其结构如下:

struct xfs_agi {

__be32 agi_magicnum;

__be32 agi_versionnum;

__be32 agi_seqno

__be32 agi_length;

__be32 agi_count;

__be32 agi_root;

__be32 agi_level;

__be32 agi_freecount;

__be32 agi_newino;

__be32 agi_dirino;

__be32 agi_unlinked[64];

/*

* v5 filesystem fields start here; this marks the end of logging region 1

* and start of logging region 2.

*/

uuid_t agi_uuid;

__be32 agi_crc;

__be32 agi_pad32;

__be64 agi_lsn;

__be32 agi_free_root;

__be32 agi_free_level;

}

关键成员含义如下:

agi_count表示AG中已分配inode个数;

agi_freecount表示AG中空闲inode个数;

agi_newino表示最近分配chunk的AG-relative inode number;

agi_unlinked[64]是一个hash table,保存已经unlinked且仍被引用的inode;

agi_root指向inode B+tree;

agi_free_root指向free inode B+tree;

inode B+tree

末端leaf

leaf包含一个使用如下结构的数组:

struct xfs_inobt_rec {

__be32 ir_startino;

__be32 ir_freecount;

__be64 ir_free;

};

关键成员含义如下:

ir_startino:该chunk中的最小inode number;

ir_freecount:该chunk中的空闲inode个数;

ir_free:表示该chunk中哪些inode空闲的64位位图 ;

XFS——inode分配与跟踪中间node

node包含一个key/pointer对的数组:

struct xfs_inobt_key {

__be32 ir_startino;

};

typedef __be32 xfs_inobt_ptr_t;

关键成员含义如下:

ir_startino:leaf中所有record的最小inode number;

inobt_ptr_t:指向存放leaf的AG block number;

单层inode B+tree

XFS——inode分配与跟踪

两层inode B+tree

XFS——inode分配与跟踪XFS——inode分配与跟踪

sparse inode特性

    综上所述,由于inode分配是基于容纳64个inode的chunk,若没有与chunk大小匹配的空闲extent,则inode分配就会失败,XFS认为已经耗尽space,在一个free space高度碎片化的文件系统中,这会导致实际耗尽free space之前就产生耗尽space错误,故而引入sparse inode特性,利用xfs_inobt_rec结构中freecount字段里早前没有用的bit,跟踪inode B+tree里一部分未分配给inode使用的chunk,使得XFS在必要的时候可以基于一个block分配inode。

leaf

leaf包含一个使用如下结构的数组:

struct xfs_inobt_rec {

__be32 ir_startino;

__be16 ir_holemask;

__u8 ir_count;

__u8 ir_freecount;

__be64 ir_free;

};

关键成员含义如下:

ir_startino:该chunk中的最小inode number,按64向下取整;

ir_holemask:表示该chunk中哪部分未分配给inode的16位位图,一个bit代表四个inode,若某个bit标记,则ir_free对应bit也必须被标记;

ir_count:该chunk中实际可分配inode总数;

ir_freecount:该chunk中空闲inode个数;

ir_free:表示该chunk中哪些inode对于分配是无效的;

举例

XFS——inode分配与跟踪

    在该单层inode B+tree中,红线标记leaf中的第二条记录,通过inode number 14912可以得到chunk位置,0xff即0x00ff,表明该chunk前32个inode大小的空间并没有用来放inode,32表明该chunk实际可分配inode总数,0表明该chunk没有空闲inode,0xffffffff即0x00000000ffffffff,表明没有可分配inode。该chunk实际上第一个inode的inode number为14944,14912~14943由于空间已经被其他数据占用,不曾分配给inode使用,从另一个角度看,对于分配操作来说,它们确实是“free”的,后续若释放了该空间,XFS是否会修改inode B+tree的ir_holemask字段,让它们变成真正的free呢?

XFS——inode分配与跟踪

 

 

 

相关文章: