AG空闲inode盘区列表
AG空闲inode盘区列表有助于解决反向查找问题以及空闲inode号查找问题。这使得JFS能找到下一个空闲盘区所在的IAG号和AG号。(实际是给出了空闲inode号。)每个文件集的每个AG都有一个AG空闲inode盘区列表。为减少扩展和缩减聚集的系统开销,JFS设定每个聚集允许的最大AG数。所以,AG空闲inode盘区列表头的个数是固定的。列表头在inode分配映射表的控制页中。表的第i项是一个双向列表的头,该双向列表是第i个AG中所有包含空闲inode的inode分配映射表项(IAG)的集合。IAG号作为列表索引。-1表示列表尾。每个IAG控制区都包含指向该列表的正向和反向指针。
当盘区中所有的inode都已删除,则释放该inode盘区的磁盘块。当IAG的一个inode盘区被删除时,该IAG插至所属的AG空闲inode盘区列表的表头。当创建新的IAG,并分配一个inode盘区时,该IAG号插至AG空闲inode盘区列表的表头。当IAG的所有inode盘区分配完时,从列表中删除该IAG。当释放IAG的所有inode盘区时,从列表中删除该IAG同时加到IAG空闲列表中。当AG需要分配inode盘区时,则使用AG空闲列表头上的第一项。
此表没有记日志;但可以在恢复时由logredo恢复,或由fsck重建。
表的结构定义见jfs_imap.h,structdinomap_t.
IAG空闲列表
IAG空闲列表有助于查找空闲inode号。这使得JFS不用查看相应分配的inode盘区就可找到IAG。(实际时给出了空闲inode号)。聚集和其每个文件集都有自己的链表。该列表的每个项指向一个IAG链表。IAG号作为列表索引。-1表示列表尾。当删除盘区的所有inode时,则释放该inode盘区的磁盘块。如果某个IAG的所有inode都为空闲,则该IAG号插入IAG空闲列表头。当需要分配新的inode盘区,而该AG中又没有包含空闲盘区的IAG,则使用IAG空闲列表头的第一项(即从表中删除)。inode盘区分配描述符一经分配就不再删除。inode盘区的地址设为0x0。
对于聚集IAG空闲列表头是聚集自用inode的一个字段。对于每个文件集IAG空闲列表头是文件集分配映射表inode的一个字段。该列表没记日志;但可在恢复时由logredo修复,或由fsck重建。
IAG空闲列表的结构定义structinomap_t在文件jfs_dinode.h中。
下一个空闲IAG
下一个空闲IAG计数器有助于查找空闲inode号。使得JFS能找到下一个可以分配的IAG的iag号。(实际是让JFS找到空闲inode号)。聚集和其每个文件集都有自己的计数器。计数器在inode分配映射表的控制页中。IAG一经分配就不再删除。
文件集分配inode
文件集inode表中的文件集分配映射表inode是特殊类型的inode。既然这些节点表示文件集,则可以说是文件集的“父inode”。这些节点包含文件集特定信息,而不是一般的inode数据。同时也记录文件集inode分配映射表在B+树中的位置。结构定义structdinode见文件jfs_dinode.h
文件
文件由包含一个B+树根的inode表示,B+树描述包含用户数据的盘区。B+树以盘区的偏移量作为索引。
符号链接
符号链接由一个inode表示,该inode的di_mode字段设置为符号链接模式(S_IFLNK)。如果inode内有空间,则链接文件的整个路径直接存储在inode中。否则,将作为inode的数据存于盘区中(通过该inode的B+树索引)。
目录
目录是JFS中日志化的元数据文件。目录由目录项组成,目录项表示目录中包含的对象。目录项将名字和inode号连接在一起。特定的inode描述特定名字的对象。为提高目录项定位的性能,B+树采用按名排序。
目录inode的di_size字段仅表示目录B+树的叶子页。如果inode中包含目录的叶节点,则di_size字段为256。
目录中没有特定项表示自身(".")和父目录("..")。而在inode中表示。自身就是目录自己的inode号。父目录是inode中的特殊字段,idotdot,structdtroot_t,见文件jfs_dtree.h。
目录inode包含B+树的根,处理方法和一般文件类似。只是目录B+树以名为键。目录B+树的叶节点包含目录项,且以目录项的全名作为键值。目录B+树最下层内部节点使用后缀压缩。其它内部节点采用相同的压缩后缀。后缀压缩将名字缩至最短,正好足以区分当前目录项和前一目录项。
由于B+树项的大小是可变的,JFS需要处理这些项的方案。JFS想要避免在删除一项时引起的项移动,平均一项有2K的数据。
B+树节点的内容:
固定个数的目录槽,个数取决于节点的大小。这些槽用于存储目录槽数组和目录项或路由项。目录槽的大小总是32字节。固定大小的目录槽使得JFS在删除目录项不必移动,从而还避免了内部碎片。
一个目录B+树的头,描述B+树inode。此部分包含一个标志,标记节点是内部节点或是叶节点,及是不是B+树的根节点。还包含自身的块地址。nextindex字段记录目录槽数组中的最后一项。stblindex字段记录目录槽数组的开始位置。freelist字段指向该节点中空闲槽列表头。
一个目录槽数组,它是正使用的目录槽索引的有序数组。使用该数组减少了目录项增删时所需的移动次数。数组比项本身小很多,所以移动的只是数组而不是整个项。在数组中,可以用二分法搜索某个目录项。
一个目录B+树槽空闲列表,使得内部碎片最小化。目录B+树的头包含列表表头,每个空闲目录槽指向列表中的下一个空闲槽。如果有一系列相连的空闲槽,则在第一个槽中设立一个计数值,说明该系列的长度。这有利于在新建目录B+树节点时,进行快速初始化。
一个目录项,将名字链接到一个inode号。目录项包含在叶节点的目录槽中。如果需要存储整个目录名,目录项可以有附加槽。目录项的next字段表明该项是否有后继项。大多数目录项只有单个槽。
一个路由项,用于记录目录B+树的搜索路径。路由项包含在内部节点的目录槽中。路由项将按后缀压缩的路由键映射到盘区,此盘区包含下一层目录B+树的内部节点或叶节点。如果路由项需要记录整个的路由键,则可以有附加槽。路由项的next字段表示该项是否有后继项。大多数路由项只有单个槽。
目录B+树中的内部节点或叶节点是4K大小的页。由于许多目录都不是很大,所以这种方式对大多数目录来说是很浪费磁盘空间的。所以目录的初始叶节点采用以下分配方案:
初始目录项存储在目录嵌入数据区中。
当目录inode的嵌入数据区填满时,JFS分配一个叶节点,大小和聚集块的尺寸一样。
当初始叶节被占满,而大小又不到4k,则倍增节点大小。首先在当前盘区中扩增;如果没有足够空间,则需分配新的盘区,然后将旧盘区的数据复制到新盘区。目录槽数组仅够存放页未扩时的槽,所以必须创建新的槽数组。从新分配的数组起始处使用槽,并将旧的数组数据复制到新的位置。更新指向该数组的头指针,并将旧数组中的槽添加到空闲列表中。
如果叶节点再次填满,而大小仍不足4K,重复步骤3。一旦叶节点达到4K则分配新叶节点。初始节点后的每个叶节点,一开始就分配4K。
当叶子页的所有项都释放,则从B+树中删除该页。仅当目录中所有目录项都已删除,目录又缩回inode。
访问控制列表(ACL)
JFS的每个inode都有不同的访问控制列表(ACL)。ACL可以表示不同的项,例如许可权、用户标识符、或组标识符。聚集inode的ACL字段是没有用的。
虽然在磁盘上和内存中ACL的表示方式没有规定,但从DFS外部所看到的“外部”表示是固定的。ACL大小的唯一限制是其外部表示必须适合8192字节大小的dfs_acl结构。
任意JFS对象都可有一个管理该对象存取的ACL;这种ACL称为常规ACL。目录对象在创建时可能用到两个关联的可选ACL;初始目录ACL和初始文件ACL。初始ACL的作用范围是目录中的所有文件。
ACL体系结构未指定ACL的存储方式,但建议ACL有字段标识或命名其辅助对象,这样通过简单的等同性检查就可以检测到文件集中的共享关系。因此,JFS在每个文件集中用一个文件(ACL文件)存储文件集的ACL;文件集inode1就是ACL文件。文件集中的每个inode在ACL文件中存放一个索引。
ACL文件需要一个存储ACL空闲区域的位图。ACL文件有一个4K大小的位图,标识8M的ACL项,如有必要可扩增。位图中的一位代表256字节连续磁盘空间;位图不描述自身的状态。
ACL文件的数据未日志化。
扩展属性(EA)
扩展属性是附加到JFS对象适用存储和存取的机制。EA连续存储在扩展属性空间(EAS)中,空格存储EAS由JFS对象inode的EA描述符定义。EA描述符只是一个盘区描述符,定义见jfs_types.h,structdxd_t。
EA可以存放在inode内,或存放在单独盘区内。EA描述符的标志字段指示存储的方式。由于此空间也可用于存放文件xtree附加的xad项,所以inode的di_mode字段指明该空间是否可用。如果该字段值为INLINEEA,则表明空间可用。
如果EA存于inode内,则忽略EA描述符的offset和length字段。EA描述符的大小表示数据的字节数。
如果EA存于盘区内,EA描述符将描述该盘区。JFS不希望EA数据太大,所以JFS不支持每个inode有多于一个盘区的EA数据。
EA项包括EA名称和其值。要访问某个EA,JFS只是线性搜索EA数据。
EA数据未日志化,但它是写同步的(即数据不是旧数据,就是新数据,但绝不可能是部分更新的数据)。JFS在日志中记录EA数据的位置。嵌入EA数据是日志化的。
流
流用于将数据连接到一个文件或目录。这种附加数据和目录数据相似,都可按名引用。在第一版中不支持流,在这里讨论仅为元数据结构的完整性。
磁盘inode的四部分的第二部分有一个字段描述流描述符。由于附加到一个对象的流数目是可变的,所以流描述符是一个inode号,以允许流增加或缩减。流描述符inode指向的数据称为流列表。
流没有关联的扩展属性,所以从不使用流的inode四部分的最后一个部分-扩展属性。实际上该部分用于附加的流项。B+树的数据如同目录项。每个流都有自己的inode,它们依次记录流数据存放的数据块地址。
结束语
JFS小组最重要的目标是创建可靠的,高性能的文件系统。本文讨论了JFS磁盘布局结构,以及实现可伸缩性、可靠性和高性能的机制。同时详细探讨了JFS如何在整个文件系统中使用B+树提高文件系统操作。