当 UNIX 操作系统首次被引入时,UNIX 奇才本人 Ken Thompson 编写了第一个文件系统。 我们称之为“旧的 UNIX 文件系统(old UNIX file system)”,它真的很简单。 基本上,它的数据结构在磁盘上是这样的:<br />![image.png](https://cdn.nlark.com/yuque/0/2021/png/12377925/1635267649678-3901faf8-dc0e-4e24-949c-c3ab2a10e3cb.png#clientId=ub2e74530-c644-4&from=paste&height=69&id=ua66fc4ed&margin=%5Bobject%20Object%5D&name=image.png&originHeight=69&originWidth=587&originalType=binary&ratio=1&size=4980&status=done&style=none&taskId=u9fc1ec53-16dc-4232-8553-7e8448435b9&width=587)<br />超级块 (S) 包含有关整个文件系统的信息:容量(volume)有多大、有多少个 inode、指向空闲块链表头部的指针等等。 磁盘的 inode 区域包含文件系统的所有 inode。 最后,大部分磁盘都被数据块占用了。<br />旧文件系统的好处在于它很简单,并且支持文件系统试图提供的基本抽象:文件和目录层次结构。 这个易于使用的系统是从过去笨拙的、基于记录的存储系统向前迈出的真正一步,目录层次结构是对早期系统提供的更简单的单级层次结构的真正进步。
41.1 问题:性能不佳 The Problem: Poor Performance
问题是:性能很糟糕。 正如 Kirk McKusick 和他在伯克利 [MJLF84] 的同事所衡量的那样,性能开始时很糟糕,随着时间的推移变得更糟,以至于文件系统只提供了总磁盘带宽的 2%!
主要问题是旧的 UNIX 文件系统将磁盘视为随机存取存储器(random-access memory); 数据散布在各处,而没有考虑保存数据的介质是磁盘这一事实,因此具有真实且昂贵的定位成本。 例如,文件的数据块通常离它的 inode 很远(译者注:在磁盘上的物理位置),因此每当第一次读取 inode 然后读取文件的数据块时都会导致昂贵的查找(一种非常常见的操作)。
更糟糕的是,文件系统最终会变得非常碎片化(fragmented),因为没有仔细管理链表空间。 空闲链表最终会指向分布在磁盘上的一堆块,当文件被分配时,它们将简单地获取下一个空闲块。 结果是通过在磁盘上来回访问逻辑上连续的文件,从而显着降低性能。
例如,想象以下数据块区域,其中包含四个文件(A、B、C 和 D),每个文件大小为 2 个块:
如果删除 B 和 D,则生成的布局为:
如您所见,空闲空间被分成两个两个块的块,而不是一个连续的四个块。 假设您现在希望分配一个文件 E,大小为四个块:
您可以看到会发生什么:E 分布在整个磁盘上,因此,在访问 E 时,您无法从磁盘获得峰值(连续)性能。 相反,您首先读取 E1 和 E2,然后查找,然后读取 E3 和 E4。 这种碎片问题在旧的 UNIX 文件系统中一直发生,它损害了性能。 旁注:这个问题正是磁盘碎片整理工具(disk defragmentation)的帮助所在; 它们重新组织磁盘上的数据以将文件连续放置并为一个或几个连续区域腾出可用空间,移动数据然后重写 inode 等以反映更改。
另一个问题:原始块大小太小(512 字节)。 因此,从磁盘传输数据本质上是低效的。 较小的块是好的,因为它们最大限度地减少了内部碎片(internal fragmentation,块内的浪费),但不利于传输,因为每个块可能需要定位开销才能到达它。 因此,问题:
关键的问题:如何组织磁盘上的数据以提高性能 我们如何组织文件系统数据结构以提高性能? 在这些数据结构之上,我们需要什么类型的分配策略? 我们如何使文件系统“感知磁盘”?
41.2 FFS:磁盘意识是解决方案 FFS: Disk Awareness Is The Solution
伯克利的一个小组决定构建一个更好、更快的文件系统,他们巧妙地将其称为快速文件系统 (Fast File System,FFS)。 这个想法是将文件系统结构和分配策略设计为“磁盘意识(disk aware)”,从而提高性能,这正是他们所做的。 FFS由此开创了文件系统研究的新纪元; 通过保持与文件系统相同的接口(相同的 API,包括 open()、read()、write()、close() 和其他文件系统调用)但改变了内部实现,作者为新的文件系统构建铺平了道路,这项工作今天仍在继续。 几乎所有现代文件系统都遵循现有接口(从而保持与应用程序的兼容性),同时出于性能、可靠性或其他原因更改其内部结构。
41.3 组织结构:柱面组 Organizing Structure: The Cylinder Group
第一步是更改磁盘结构。 FFS 将磁盘划分为多个柱面组(cylinder groups)。 单个柱面(cylinder)是硬盘驱动器不同表面上距驱动器中心相同距离的一组磁道; 它被称为柱面是因为它与它名称所谓的几何形状明显相似。 FFS 将 N 个连续的柱面聚合为一个组,因此整个磁盘可以被视为柱面组的集合。 下面是一个简单的例子,显示了一个带有六个盘片的驱动器的四个最外面的磁道,以及一个由三个柱面组成的柱面组:
请注意,现代驱动器不会为文件系统导出足够的信息来真正了解特定柱面是否正在使用; 如前所述 [AD14a],磁盘导出块的逻辑地址空间并向客户端隐藏其几何细节。 因此,现代文件系统(例如 Linux ext2、ext3 和 ext4)将驱动器组织成块组(block groups),每个块组只是磁盘地址空间的一个连续部分。 下图说明了一个示例,其中每 8 个块被组织成不同的块组(请注意,实际组将包含更多块):
无论您称它们为柱面组还是块组,这些组都是 FFS 用来提高性能的核心机制。 至关重要的是,通过将两个文件放在同一个组中,FFS 可以确保一个接一个地访问不会导致整个磁盘的长寻道。
为了使用这些组来存储文件和目录,FFS 需要能够将文件和目录放入一个组中,并在其中跟踪有关它们的所有必要信息。 为此,FFS 包括您可能希望文件系统在每个组中具有的所有结构,例如,用于 inode、数据块的空间以及一些用于跟踪这些结构中的每一个是否已分配或空闲的结构。 以下是 FFS 在单个柱面组中保留的内容的描述:
现在让我们更详细地检查这个单个柱面组的组件。 出于可靠性原因,FFS 在每个组中保留超级块 (super block,S) 的副本。 挂载文件系统需要超级块; 通过保留多个副本,如果一个副本损坏,您仍然可以使用工作副本挂载和访问文件系统。
在每个组内,FFS 需要跟踪是否分配了该组的 inode 和数据块。 每组 inode 位图 (inode bitmap,ib) 和数据位图 (data bitmap,db) 为每个组中的 inode 和数据块服务。 位图是管理文件系统中空闲空间的绝佳方式,因为它很容易找到一大块空闲空间并将其分配给一个文件,或许可以避免旧文件系统中空闲列表的一些碎片问题。
最后,inode 和数据块(data block)区域就像以前的非常简单的文件系统 (very-simple file system,VSFS) 中的那些一样。 像往常一样,每个柱面组的大部分都由数据块组成。
Aside:FFS文件创建 例如,考虑在创建文件时必须更新哪些数据结构;在这个例子中,假设用户创建了一个新文件 /foo/bar.txt 并且该文件是一个块长度 (4KB)。该文件是新的,因此需要一个新的 inode;因此,inode 位图和新分配的 inode 都将写入磁盘。该文件中也有数据,因此也必须分配;数据位图和数据块将因此(最终)写入磁盘。因此,至少会发生对当前柱面组的四次写入(回想一下,这些写入可能会在它们发生之前在内存中缓冲一段时间)。但这并不是全部!特别是,在创建新文件时,您还必须将文件放在文件系统层次结构中,即必须更新目录。具体来说,必须更新父目录 foo 以添加 bar.txt 的条目;此更新可能适合 foo 的现有数据块或需要分配一个新块(与相关的数据位图)。 foo 的 inode 也必须更新,以反映目录的新长度以及更新时间字段(例如上次修改时间)。总的来说,仅仅创建一个新文件就需要很多工作!也许下次你这样做时,你应该更加感激,或者至少惊讶于一切都这么好。
41.4 策略:如何分配文件和目录
Policies: How To Allocate Files and Directories
有了这个组结构(group structure),FFS 现在必须决定如何在磁盘上放置文件和目录以及相关的元数据以提高性能。 基本的真言很简单:将相关的东西放在一起(及其推论,将不相关的东西分开)。
因此,为了遵守真言,FFS 必须决定什么是“相关的”并将其放置在同一个块组中; 相反,不相关的项目应该放在不同的块组中。 为了达到这个目的,FFS 使用了一些简单的放置启发式方法。
首先是目录的放置。 FFS 采用了一种简单的方法:找到分配目录数量较少(以平衡组间目录(directories across groups))和空闲 inode 数量较多(以便随后能够分配一堆文件)的柱面组,并将目录数据和 inode 放在该组中。 当然,这里可以使用其他启发式方法(例如,考虑到空闲数据块的数量)。
对于文件,FFS 做两件事。 首先,它确保(在一般情况下)将文件的数据块分配在与其 inode 相同的组中,从而防止 inode 和数据之间的长搜索(如在旧文件系统中)。其次,它将所有位于同一目录中的文件放在它们所在目录的柱面组中。 因此,如果用户创建四个文件,/a/b、/a/c、/a/d 和 /b/f,FFS 会尝试将前三个放置在一起(同一组),与第四个远离(在其他某个组中)。
让我们看一个这样分配的例子。 在示例中,假设每组中只有 10 个 inode 和 10 个数据块(都是不切实际的小数字),并且三个目录(根目录 /、/a 和 /b)和四个文件(/a/c、/a/d、/a/e、/b/f) 根据 FFS 策略放置在其中。 假设常规文件大小为每个文件两个块,并且目录只有一个数据块。 对于此图,我们对每个文件或目录使用明显的符号(即,/ 代表根目录,a 代表 /a,f 代表 /b/f,等等)。
请注意,FFS 策略做了两件积极的事:每个文件的数据块靠近每个文件的 inode,同一目录中的文件彼此靠近(即 /a/c、/a/d 和 /a/e 都在第 1 组中,目录 /b 及其文件 /b/f 在第 2 组中彼此靠近)。
相比之下,现在让我们看看一个 inode 分配策略,它只是将 inode 分布在组之间,试图确保没有组的 inode 表快速填满。 因此,最终分配可能如下所示:
从图中可以看出,虽然该策略确实将文件(和目录)数据保留在其各自的 inode 附近,但目录中的文件在磁盘周围任意分布,因此不会保留基于名称的局部性。 对文件 /a/c、/a/d 和 /a/e 的访问现在跨越三组,而不是按照 FFS 方法的一组。
FFS 启发式策略并非基于对文件系统流量或任何特别细微之处的广泛研究; 相反,它们基于良好的老式常识(common sense)(这不正是 CS 所代表的意思吗?)。 目录中的文件通常一起访问:想象一下编译一堆文件,然后将它们链接到一个可执行文件中。 因为存在这种基于命名空间的局部性(namespace-based locality),FFS 通常会提高性能,确保相关文件之间的查找既好又快。
有些人将常识称为马感(horse sense),尤其是经常与马匹一起工作的人。 然而,我们有一种感觉,随着“机械化的马”,也就是汽车,越来越受欢迎,这个成语可能会消失。 他们接下来会发明什么? 飞行器??!!
41.5 测量文件局部性
Measuring File Locality
为了更好地理解这些启发式方法是否有意义,让我们分析一些文件系统访问的痕迹,看看是否确实存在命名空间局部性。 出于某种原因,文献中似乎没有对这个主题进行很好的研究。
具体来说,我们将使用 SEER 跟踪 [K94] 并分析目录树中文件访问彼此之间的“距离”。 例如,如果文件 f 被打开,然后在跟踪中重新打开(在打开任何其他文件之前),则这两个在目录树中打开的距离为零(因为它们是同一个文件)。 如果打开目录 dir(即 dir/f)中的文件 f,然后打开同一目录中的文件 g(即 dir/g),则两个文件访问之间的距离为 1,因为它们共享同一个目录但不是同一个文件。 换句话说,我们的距离度量衡量的是您必须在目录树上走多远才能找到两个文件的共同祖先; 它们在树中越近,度量越低。
图 41.1 显示了在 SEER 集群中所有工作站的 SEER 跟踪中观察到的局部性。 该图沿 x 轴绘制差异度量,并沿 y 轴显示具有该差异的文件打开的累积百分比。 具体来说,对于 SEER 跟踪(图中标记为“Trace”),您可以看到大约 7% 的文件访问是针对之前打开的文件,近 40% 的文件访问是针对同一文件或到同一目录中的一个(即,零或一的差异)。 因此,FFS 局部性假设似乎是有道理的(至少对于这些痕迹)。
Figure 41.1: FFS Locality For SEER Traces
有趣的是,另外 25% 左右的文件访问是访问距离为 2 的文件。 当用户以多级方式构建了一组相关目录并在它们之间不断跳转时,就会出现这种类型的局部性。 例如,如果用户有一个 src 目录并将目标文件(.o 文件)构建到 obj 目录中,并且这两个目录都是主 proj 目录的子目录,则常见的访问模式将是 proj/src/foo .c 后跟 proj/obj/foo.o。 这两个访问之间的距离是两个,因为 proj 是共同的祖先。 FFS 不会在其策略中捕获这种类型的位置,因此在此类访问之间会发生更多的搜索。
为了进行比较,该图还显示了“随机(Random)”轨迹的局部性。 通过以随机顺序从现有 SEER 跟踪中选择文件并计算这些随机排序访问之间的距离度量来生成随机跟踪。 如您所见,正如预期的那样,随机跟踪中的命名空间局部性较少。 然而,因为最终每个文件都有一个共同的祖先(例如,根),所以有一些局部性,因此随机作为比较点是有用的。
41.6
大型文件例外 The Large-File Exception
在 FFS 中,文件放置的一般策略有一个重要的例外,它出现在大文件中。 如果没有不同的规则,一个大文件将完全填满它首先放置在其中的块组(可能还有其他)。 以这种方式填充块组是不可取的,因为它会阻止后续的“相关”文件被放置在该块组中,因此可能会损害文件访问的局部性。
因此,对于大文件,FFS 执行以下操作。 在将一定数量的块分配到第一个块组后(例如,12 个块,或一个 inode 中可用的直接指针的数量),FFS 将文件的下一个“大”块(例如,第一个间接块指向的块)放在另一个块组中(可能是因为其利用率低而选择的)。 然后,文件的下一个块被放置在另一个不同的块组中,依此类推。
让我们看一些图表以更好地理解此政策。 如果没有大文件例外,单个大文件会将其所有块放入磁盘的一个部分。 我们研究了一个文件 (/a) 的小示例,该示例在配置了 10 个 inode 和每组 40 个数据块的 FFS 中包含 30 个块。 这是没有大文件例外的 FFS 的描述:
正如您在图片中看到的,/a 填满了组 0 中的大部分数据块,而其他组则保持为空。 如果现在在根目录 (/) 中创建了一些其他文件,则组中没有太多空间给他们的数据。
对于大文件例外(这里设置为每个组(chunk)中的五个块),FFS 将文件分散在多个组中,并且由此产生的任何一组内的利用率都不会太高:
精明的读者(也就是您)会注意到,在磁盘上散布文件块会损害性能,尤其是在相对常见的连续文件访问情况下(例如,当用户或应用程序连续读取块 0 到 29 时)。 你是对的,哦,我们的精明读者! 但是您可以通过仔细选择块大小来解决这个问题。
具体来说,如果块大小足够大,文件系统将花费大部分时间从磁盘传输数据,而在组的块之间寻道(相对)很少的时间。 这种通过为支付的开销做更多工作来减少开销的过程称为摊销(amortization),是计算机系统中的常用技术。
举个例子:假设一个磁盘的平均定位时间(即寻道和旋转)是 10 ms。 进一步假设磁盘以 40 MB/s 的速度传输数据。 如果您的目标是花费一半时间在组(chunk)之间寻道,一半时间传输数据(从而实现 50% 的峰值磁盘性能),则每 10 毫秒定位需要花费 10 毫秒传输数据。 所以问题变成了:一个组(chunk)必须有多大才能花费 10 毫秒的传输时间? 很简单,只要使用我们的老朋友数学,特别是在关于磁盘的章节中提到的量纲分析 [AD14a]:
基本上,这个等式是这样说的:如果您以 40 MB/s 的速度传输数据,那么您每次搜索只传输 409.6 KB,这样就可以将一半的时间用于搜索,一半的时间用于传输。 类似地,您可以计算实现 90% 的峰值带宽(结果约为 3.69MB)或甚至 99% 的峰值带宽(40.6MB!)所需的组(chunk)的大小。 如您所见,越接近峰值,这些组(chunk)就越大(有关这些值的图,请参见图 41.2)。
Figure 41.2: Amortization: How Big Do Chunks Have To Be?
然而,FFS 没有使用这种类型的计算来跨组散布大文件。 相反,它采用了一种简单的方法,基于 inode 本身的结构。 前 12 个直接块与 inode 放在同一组中; 每个后续的间接块以及它指向的所有块都被放置在不同的组中。 对于 4KB 的块大小和 32 位磁盘地址,此策略意味着文件的每 1024 个块 (4MB) 被放置在单独的组中,唯一的例外是直接指针指向的文件的前 48KB。
请注意,磁盘驱动器的趋势是,传输速率提高得相当快,因为磁盘制造商擅长在同一个表面上塞入更多的位,但驱动器的机械方面(磁盘臂速度和旋转速率)提高得相当慢[P98]。这意味着,随着时间的推移,机械成本变得相对昂贵,因此,为了摊销这些成本,你必须在寻道之间传输更多的数据。
41.7
关于FFS的其他一些事情 A Few Other Things About FFS
FFS 还引入了一些其他创新。 尤其是设计者对于容纳小文件极为担心; 事实证明,当时许多文件的大小都是 2KB 左右,使用 4KB 块虽然有利于传输数据,但对空间效率来说却不太好。 因此,这种内部碎片(internal fragmentation)可能导致典型文件系统浪费大约一半的磁盘。
FFS 设计人员想到的解决方案很简单并解决了问题。 他们决定引入子块(sub-blocks),这是文件系统可以分配给文件的 512 字节的小块。 因此,如果您创建了一个小文件(比如 1KB 大小),它将占用两个子块,因此不会浪费整个 4KB 块。 随着文件的增长,文件系统将继续为其分配 512 字节的块,直到它获取完整的 4KB 数据。 此时,FFS 将找到一个 4KB 的块,将子块复制到其中,并释放子块以备将来使用。
您可能会观察到此过程效率低下,需要对文件系统进行大量额外工作(尤其是执行复制所需的大量额外 I/O)。 你又是对的! 因此,FFS 通常通过修改 libc 库来避免这种消极的行为; 该库会缓冲写入,然后将它们以 4KB 块的形式发送到文件系统,从而在大多数情况下完全避免子块特化。
FFS 引入的第二件优雅的事情是针对性能进行了优化的磁盘布局。 在那个时代(在 SCSI 和其他更现代的设备接口出现之前),磁盘没有那么复杂,需要主机 CPU 以更亲历亲为的方式控制它们的操作。 当一个文件被放置在磁盘的连续扇区上时,FFS 中出现了一个问题,如图 41.3 中的左侧。
Figure 41.3: FFS: Standard Versus Parameterized Placement
具体来说,问题出现在连续读取过程中。FFS将首先发出一个读到块0;当读取完成时,FFS向块 1发出了一个读取,但为时已晚: 块1已经在磁头下旋转了(越过磁头了),现在对块 1的读取将导致一个完整的旋转。
FFS用一种不同的布局解决了这个问题,如图41.3中右侧所示。通过跳过每一个其他块(在示例中),FFS有足够的时间在它经过磁头之前请求下一个块。事实上,FFS非常聪明,能够计算出对于特定的磁盘,为了避免额外的旋转,在进行布局时应该跳过多少块;这种技术被称为参数化(parameterization),因为FFS会计算出磁盘的具体性能参数,并使用这些参数来决定确切的交错布局方案。
你可能会想:这个方案毕竟不是很好。 事实上,使用这种布局只能获得 50% 的峰值带宽,因为您必须绕每个磁道走两次才能读取每个块一次。 幸运的是,现代磁盘更加智能:它们在内部读取整个轨道并将其缓冲在内部磁盘缓存中(因此通常称为磁道缓冲区(track buffer))。 然后,在对磁道进行后续读取时,磁盘将从其缓存中返回所需的数据。 因此文件系统不再需要担心这些令人难以置信的低级细节。 如果设计得当,抽象和更高级别的接口可能是一件好事。
还添加了其他一些可用性改进。 FFS 是最早允许使用长文件名的文件系统之一,因此可以在文件系统中使用更具表现力的名称,而不是传统的固定大小方法(例如,8 个字符)。 此外,引入了一个称为符号链接的新概念。 正如前一章 [AD14b] 中所讨论的,硬链接的局限性在于它们都不能指向目录(因为害怕在文件系统层次结构中引入循环)并且它们只能指向同一卷中的文件(即, inode 编号必须仍然有意义)。 符号链接允许用户为系统上的任何其他文件或目录创建“别名”,因此更加灵活。 FFS 还引入了用于重命名文件的原子 rename() 操作。 除了基本技术之外,可用性改进也可能使 FFS 获得更强大的用户群。
Tip:使系统可用 从 FFS 中获得的最基本的经验可能是,它不仅引入了磁盘意识布局的概念上的好主意,而且还添加了许多功能,使系统更易于使用。 长文件名、符号链接和原子性的重命名操作都提高了系统的实用性; 虽然很难写一篇相关的研究论文(想象一下,试着读一篇 14 页的论文,名为《符号链接:硬链接长期失散的表 兄》),但这些小功能使 FFS 更有用,因此可能增加了它被采用的机会。 使系统可用通常与其深层技术创新一样重要,甚至更重要。
41.8
总结 Summary FFS 的引入是文件系统历史上的一个分水岭,因为它清楚地表明文件管理问题是操作系统中最有趣的问题之一,并展示了人们如何开始处理最重要的设备, 硬盘。 从那时起,已经开发了数百种新的文件系统,但今天仍有许多文件系统从 FFS 中汲取灵感(例如,Linux ext2 和 ext3 是明显的知识传承)。 当然,所有现代系统都说明了 FFS 的主要经验:将磁盘视为磁盘。
References
[AD14a] “Operating Systems: Three Easy Pieces” (Chapter: Hard Disk Drives) by Remzi
Arpaci-Dusseau and Andrea Arpaci-Dusseau. Arpaci-Dusseau Books, 2014.
如果不先了解硬盘驱动器的一些细节,就不可能阅读关于FFS的文章。如果你想这么做,请直接去监狱;不要错过,更重要的是,不要收集200个急需的模拟金币。
[AD14b] “Operating Systems: Three Easy Pieces” (Chapter: File System Implementation) by
Remzi Arpaci-Dusseau and Andrea Arpaci-Dusseau . Arpaci-Dusseau Books, 2014.
如上所述,除非您已经阅读(并理解)了有关文件系统实现的章节,否则阅读本章几乎没有意义。 否则,我们会抛出诸如“inode”和“indirect block”之类的术语,你会像“嗯?” 这对我们俩来说都不好玩。
[K94] “The Design of the SEER Predictive Caching System” by G. H. Kuenning. MOBICOMM
’94, Santa Cruz, California, December 1994.
根据Kuenning的说法,这是SEER项目的最佳概述,该项目导致了(在其他事情中)收集这些痕迹。
[MJLF84] “A Fast File System for UNIX” by Marshall K. McKusick, William N. Joy, Sam J.
Leffler, Robert S. Fabry. ACM TOCS, 2:3, August 1984.
McKusick 最近因其对文件系统的贡献而荣获 IEEE Reynold B. Johnson 奖,其中大部分是基于他构建 FFS 的工作。 在他的获奖感言中,他讨论了最初的FFS软件:只有1200行代码! 现代版本稍微复杂一些,例如,BSD FFS 后代现在在 5 万行代码范围内。
[P98] “Hardware Technology Trends and Database Opportunities” by David A. Patterson.
Keynote Lecture at SIGMOD ’98, June 1998.
磁盘技术趋势及其如何随时间变化的精彩而简单的概述。
Homework (Simulation)
本节介绍 ffs.py,这是一个简单的 FFS 模拟器,可用于更好地了解基于 FFS 的文件和目录分配的工作原理。 有关如何运行模拟器的详细信息,请参阅自述文件。
Questions
- 检查文件 in.largefile,然后使用标志 -f in.largefile 和 -L 4 运行模拟器。后者将大文件异常设置为 4 个块。 结果分配会是什么样子? 使用 -c 运行以进行检查。
- 现在使用 -L 30 运行。您希望看到什么? 再次打开 -c 以查看您是否正确。 您还可以使用 -S 来准确查看分配给文件 /a 的块。
- 现在我们将计算有关文件的一些统计信息。 第一个是我们称之为 filespan 的东西,它是文件的任意两个数据块之间或 inode 和任意数据块之间的最大距离。 计算 /a 的文件跨度。 运行 ffs.py -f in.largefile -L 4 -T -c 看看它是什么。 用 -L 100 做同样的事情。当大文件异常参数从低值变为高值时,您期望 filespan 有什么不同?
- 现在让我们看一个新的输入文件 in.manyfiles。 您认为 FFS 策略将如何跨组放置这些文件? (您可以使用 -v 运行以查看创建了哪些文件和目录,或者只使用 cat in.manyfiles)。 用 -c 运行模拟器,看看你是否正确。
- 评估 FFS 的指标称为 dirspan。 该指标计算特定目录中文件的分布,特别是目录中所有文件的 inode 和数据块与目录本身的 inode 和数据块之间的最大距离。 使用 in.manyfiles 和 -T 标志运行,并计算三个目录的 dirspan。 使用 -c 运行以进行检查。 FFS 在最小化 dirspan 方面做得有多好?
- 现在将每组 inode 表的大小更改为 5 (-I 5)。 您认为这将如何改变文件的布局? 用 -c 运行看看你是否正确。 它如何影响dirspan?
- FFS 应该将新目录的 inode 放在哪个组中? 默认(模拟器)策略查找具有最多空闲 inode 的组。 不同的策略会查找一组具有最多空闲 inode 的组。 例如,如果您使用 -A 2 运行,则在分配新目录时,模拟器将成对查看组并选择最佳分配对。 运行 ./ffs.py -f in.manyfiles -I 5 -A 2 -c 以查看此策略如何更改分配。 它如何影响dirspan? 为什么这个政策可能是好的?
- 我们将探讨的最后一项政策变化与文件碎片有关。 运行 ./ffs.py -f in.fragmented -v 看看你是否可以预测剩余的文件是如何分配的。 使用 -c 运行以确认您的答案。 文件 /i 的数据布局有什么有趣之处? 为什么会有问题?
- 我们称之为连续分配 (-C) 的新策略试图确保每个文件都是连续分配的。 具体来说,使用 -C n 时,文件系统会在分配块之前尝试确保组内有 n 个连续块空闲。 运行 ./ffs.py -f in.fragmented -v -C 2 -c 以查看差异。 随着传递给 -C 的参数增加,布局如何变化? 最后,-C 如何影响 filespan 和 dirspan?