快捷搜索:  

JFS 文件系统概述及布局分析(4)

  下一个空闲 IAG
  下一个空闲 IAG 计数器有助于查找空闲 inode 号。使得 JFS 能找到下一个可以分配的 IAG 的 iag号。(实际是让 JFS 找到空闲 inode 号)。聚集和其每个文件集都有自己的计数器。计数器在 inode 分配映射表的控制页中。IAG 一经分配就不再删除。

  文件集分配 inode
  文件集 inode 表中的文件集分配映射表 inode 是特殊类型的 inode 。既然这些节点表示文件集,则可以说是文件集的“父 inode ”。这些节点包含文件集特定信息,而不是一般的 inode 数据。同时也记录文件集 inode 分配映射表在 B+ 树中的位置。结构定义 struct dinode 见文件 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,struct dtroot_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;文件集 inode 1 就是 ACL 文件。文件集中的每个 inode 在 ACL 文件中存放一个索引。

  ACL 文件需要一个存储 ACL 空闲区域的位图。ACL 文件有一个 4K 大小的位图,标识 8M 的 ACL 项,如有必要可扩增。位图中的一位代表 256 字节连续磁盘空间;位图不描述自身的状态。

  ACL 文件的数据未日志化。

  扩展属性(EA)
  扩展属性是附加到 JFS 对象适用存储和存取的机制。EA 连续存储在扩展属性空间 (EAS) 中,空格存储 EAS 由 JFS 对象 inode 的 EA 描述符定义。EA 描述符只是一个盘区描述符,定义见 jfs_types.h, struct dxd_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+ 树提高文件系统操作。


顶(0)
踩(0)

您可能还会对下面的文章感兴趣:

最新评论