UFS以柱面为单位组织文件系统。在创建文件系统时所有柱面被平分为若干个部分,每部分称为一个柱面组。除了最后一个柱面组外,其他柱面组包含的柱面数都相同。最后一个柱面组包含的柱面数则会少于其他柱面组包含的柱面数,这是因为文件系统的总扇区数不一定是一个柱面组总扇区数的整数倍,这就导致在分配柱面组时最后的一个柱面组会小一些。
在每个柱面组中都有一个叫作柱面组描述符的结构用来管理和描述当前柱面组。在柱面组描述符中会记录当前柱面组空闲的块数、段数、i-节点数等信息,还会记录当前柱面组最后分配的块、段及i-节点的地址。
在柱面组描述符的后部,还会记录当前柱面组中i-节点、块及段的位图。位图可以帮助文件系统在给定大小的区域内寻找连续的段和块用以存储数据,每个位图起始处都会给出一个以当前组描述符为起始地址的字节偏移。
柱面组描述符在当前柱面组中的存放地址不是固定不变的,其具体地址和大小在超级块中会作说明,并且UFS1和UFS2的柱面组描述符结构各不相同,下面会分别讲解。
UFS1的柱面组描述符起始地址由超级块0CH~0FH偏移处描述,这4个字节描述柱面组描述符相对于柱面组参考位置的偏移量。假设该值为24,那么每个柱面组中的柱面组描述符起始地址,就是以当前柱面组的参考位置为起点,向后偏移到24段。
在UFS1中柱面组的参考位置是不同的,在每个柱面组中都会发生偏转。
这是因为在原来的硬盘中每个磁道具有相同的扇区数,这就导致每个柱面组的第一个扇区都位于同一个盘面上,为了减小因物理故障而产生的数据损坏,将每个柱面组定义一个不同的参考位置,形成一定的偏转,从而降低了风险。
柱面组参考位置的具体偏转增量记录在超级块的18H~1BH偏移处。假设该值为128,则每个柱面组的参考位置以128个段为偏转增量,即0号柱面组的参考位置为0号段,1号柱面组的参考位置为128号段,以此类推。
在超级块的1CH~1FH偏移处还记录了柱面组偏转周期的计算掩码。通过这个掩码可以计算出柱面组参考位置的偏转周期。假设偏转周期为8,那么每经过8个柱面组,柱面组的参考位置就又回到0号段处。
UFS1的柱面组描述符的大小记录在超级块的A0H~A3H偏移处,这4个字节描述了柱面组描述符的总字节数。
UFS1的柱面组描述符的具体结构见表5-33。
表5-33 UFS1柱面组描述符的结构
字节偏移 | 字段长度(字节) | 字段名和定义 |
---|---|---|
0x00~0x03 | 4 | 未用 |
0x04~0x07 | 4 | 签名“00 09 02 55” |
0x08~0x0B | 4 | 最后写入时间 |
0x0C~0x0F | 4 | 柱面组号 |
0x10~0x11 | 2 | 柱面组包含的柱面数 |
0x12~0x13 | 2 | 柱面组包含的i-节点数 |
0x14~0x17 | 4 | 柱面组包含的段数 |
0x18~0x1B | 4 | 柱面组包含的目录数 |
0x1C~0x1F | 4 | 柱面组中的空闲块数 |
0x20~0x23 | 4 | 柱面组中的空闲i-节点数 |
0x24~0x27 | 4 | 柱面组中的空闲段数 |
0x28~0x2B | 4 | 最后分配块号 |
0x2C~0x2F | 4 | 最后分配段号 |
0x30~0x33 | 4 | 最后分配i-节点号 |
0x34~0x53 | 32 | 柱面组中可用段摘要信息 |
0x54~0x57 | 4 | 每柱面空闲块数的描述地址相对于柱面组描述符起始位置的字节偏移(每个柱面的空闲块数用4个字节描述) |
0x58~0x5B | 4 | 空闲块位置表的地址相对于柱面组描述符起始位置的字节偏移 |
0x5C~0x5F | 4 | i-节点位图的地址相对于柱面组描述符起始位置的字节偏移 |
0x60~0x63 | 4 | 段位图的地址相对于柱面组描述符起始位置的字节偏移 |
0x64~0x67 | 4 | 柱面组描述符下一个可用空间的地址相对于柱面组描述符起始位置的字节偏移 |
0x68~0x6B | 4 | 可用簇(连续的块)的地址相对于柱面组描述符起始位置的字节偏移 |
0x6C~0x6F | 4 | 块位图的地址相对于柱面组描述符起始位置的字节偏移 |
0x70~0x73 | 4 | 柱面组中的块数 |
0x74~0xA7 | 52 | 未用 |
0xA8往后 | ~ | 位图及其他信息 |
下面以一个具体实例进行说明。在一个Sparc Solaris的切片中,文件系统的超级块描述了以下信息:
我们利用以上数据计算出3号柱面组中的柱面组描述符起始扇区号。
第1步 计算3号柱面组起始扇区号。
具体算法:每柱面组段数×每段扇区数×柱面组号=53040×2×3=318240
第2步 计算3号柱面组参考位置所在扇区。
具体算法:3号柱面组起始扇区号+柱面组参考位置的偏转增量×柱面组号×每段扇区数=318240+128×3×2=319008
第3步 计算3号柱面中的柱面组描述符起始扇区号。
具体算法:3号柱面组参考位置所在扇区号+柱面组描述符相对于柱面组参考位置的偏移量×每段扇区数=319008+24×2=319056
最终计算出3号柱面中的柱面组描述符起始于319 056号扇区。用WinHex跳转到319 056扇区,其部分内容如图5-39所示。
图5-39中柱面组描述符的具体信息及数值可以通过WinHex的模板进行查看。本例是Sparc架构的Solaris系统,使用Big-Endian字节序,所以在选用模板时应选择“UFS1 cylinder group descriptor BE”,打开模板后如图5-40所示。
UFS2的柱面组描述符起始地址由超级块0CH~0FH偏移处描述。这4个字节描述柱面组描述符相对于柱面组参考位置的偏移量。假设该值为48,那么每个柱面组中的柱面组描述符起始地址,就是以当前柱面组的参考位置为起点,向后偏移到48段。
在UFS2文件系统中已经取消了柱面组的偏转增量和偏转周期,所以在计算每个柱面组中的柱面组描述符起始地址时就不用再考虑偏转增量的问题了。
UFS2的柱面组描述符的大小记录在超级块的A0H~A3H偏移处,这4个字节描述了柱面组描述符的总字节数。
UFS2的柱面组描述符的具体结构见表5-34。
表5-34 UFS2柱面组描述符的结构
字节偏移 | 字段长度(字节) | 字段名和定义 |
---|---|---|
0x00~0x03 | 4 | 未用 |
0x04~0x07 | 4 | 签名“55 02 09 00” |
0x08~0x0B | 4 | 未用 |
0x0C~0x0F | 4 | 柱面组号 |
0x10~0x13 | 4 | 未用 |
0x14~0x17 | 4 | 柱面组包含的段数 |
0x18~0x1B | 4 | 柱面组包含的目录数 |
0x1C~0x1F | 4 | 柱面组中的空闲块数 |
0x20~0x23 | 4 | 柱面组中的空闲i-节点数 |
0x24~0x27 | 4 | 柱面组中的空闲段数 |
0x28~0x2B | 4 | 最后分配块号 |
0x2C~0x2F | 4 | 最后分配段号 |
0x30~0x33 | 4 | 最后分配i-节点号 |
0x34~0x53 | 32 | 柱面组中可用段摘要信息 |
0x54~0x5B | 8 | 未用 |
0x5C~0x5F | 4 | i-节点位图的地址相对于柱面组描述符起始位置的字节偏移 |
0x60~0x63 | 4 | 段位图的地址相对于柱面组描述符起始位置的字节偏移 |
0x64~0x67 | 4 | 柱面组描述符下一个可用空间的地址相对于柱面组描述符起始位置的字节偏移 |
0x68~0x6B | 4 | 可用簇(连续的块)的地址相对于柱面组描述符起始位置的字节偏移 |
0x6C~0x6F | 4 | 块位图的地址相对于柱面组描述符起始位置的字节偏移 |
0x70~0x73 | 4 | 柱面组中的块数 |
0x74~0x77 | 4 | 柱面组包含的i-节点数 |
0x78~0x7B | 4 | 最后初始化的i-节点号 |
0x7C~0x87 | 8 | 未用 |
0x84~0x87 | 4 | 最后写入时间 |
0x88~0xA7 | 32 | 未用 |
0xA8往后 | ~ | 位图及其他信息 |
下面看一个UFS2的柱面组描述符实例。这是一个Free BSD系统,其柱面组描述符的部分内容如图5-41所示。
图5-41中UFS2柱面组描述符的具体信息及数值可以通过WinHex的模板进行查看。本例是x86架构的Free BSD系统,使用Little-Endian字节序,所以在选用模板时应选择“UFS2 cylinder group descriptor LE”,打开模板后如图5-42所示。