本文是对Linux内核6.5.0-rc3文章的翻译,后续会持续修正翻译中的问题。
QNX6文件系统(The QNX6 Filesystem)
较新的QNX操作系统版本(如:Neutrino)使用qnx6fs。它在QNX 6.4.0中引入,在6.4.1后默认使用。
The qnx6fs is used by newer QNX operating system versions. (e.g. Neutrino) It got introduced in QNX 6.4.0 and is used default since 6.4.1.
选项(Option)
奥迪多媒体交互系统3G系统使用 mmi_fs 挂载文件系统
Mount filesystem as used for example by Audi MMI 3G system
详细说明(Specification)
qnx6fs与传统Unix文件系统有许多相同之处。它具有块、索引节点和目录的概念。
qnx6fs shares many properties with traditional Unix filesystems. It has the concepts of blocks, inodes and directories.
在QNX上,可以创建小端序或大端序的qnx6文件系统。该功能允许为目标平台创建和使用不同字节序的文件系统(QNX在许多嵌入式系统上使用)。
On QNX it is possible to create little endian and big endian qnx6 filesystems. This feature makes it possible to create and use a different endianness fs for the target (QNX is used on quite a range of embedded systems) platform running on a different endianness.
Linux驱动程序透明地处理端序。(LE和BE)
The Linux driver handles endianness transparently. (LE and BE)
块(Blocks)
设备或文件中的空间被拆分为多个块。块使用512、1024、2048或4096的固定大小,在创建文件系统时决定。
The space in the device or file is split up into blocks. These are a fixed size of 512, 1024, 2048 or 4096, which is decided when the filesystem is created.
块指针是32位的,因此可以寻址的最大空间是2^32 * 4096字节或16TB
Blockpointers are 32bit, so the maximum space that can be addressed is 2^32 * 4096 bytes or 16TB
超级块(The superblocks)
超级块包含有关文件系统的所有全局信息。每个qnx6fs都有两个超级块,每个超级块都有一个64位的序列号。该序列号用于标识“活动”的超级块。在每次同步写入后,主超级块将到达一个新的快照,它的序列号会增加(旧超级块序列号+1)
The superblock contains all global information about the filesystem. Each qnx6fs got two superblocks, each one having a 64bit serial number. That serial number is used to identify the “active” superblock. In write mode with reach new snapshot (after each synchronous write), the serial of the new master superblock is increased (old superblock serial + 1)
因此,快照功能基本上是通过序列号的原子最终更新来实现的。在更新该序列之前,所有的修改都是通过在特定的写入请求(或周期)期间复制所有修改过的块,并在非活动的超级块下建立一个新的(稳定的)文件系统结构来完成的。
So basically the snapshot functionality is realized by an atomic final update of the serial number. Before updating that serial, all modifications are done by copying all modified blocks during that specific write request (or period) and building up a new (stable) filesystem structure under the inactive superblock.
每个超级块为不同的文件系统部分保存一组根索引节点。(Inode、Bitmap和Longfilename)这些根节点中的每一个都包含存储数据的总大小和特定树中的寻址级别等信息。如果level值为0,则每个节点最多可以寻址16个直接块。
Each superblock holds a set of root inodes for the different filesystem parts. (Inode, Bitmap and Longfilenames) Each of these root nodes holds information like total size of the stored data and the addressing levels in that specific tree. If the level value is 0, up to 16 direct blocks can be addressed by each node.
level 1添加了一个附加的间接寻址级别,其中每个间接寻址块最多可容纳 块大小 / 4 字节的指向数据块的指针。level 2增加了一个额外的间接寻址块级别(因此,已经有多达16 * 256 * 256=1048576个块可以由这样的树寻址)。
Level 1 adds an additional indirect addressing level where each indirect addressing block holds up to blocksize / 4 bytes pointers to data blocks. Level 2 adds an additional indirect addressing block level (so, already up to 16 * 256 * 256 = 1048576 blocks that can be addressed by such a tree).
未使用的块指针总是设置为~0,而与根节点、间接寻址块或索引节点无关。
Unused block pointers are always set to ~0 - regardless of root node, indirect addressing blocks or inodes.
数据叶总是处于最低级别。因此,没有数据存储在较高的树级别上。
Data leaves are always on the lowest level. So no data is stored on upper tree levels.
第一个超级块位于0x2000。(0x2000是引导块大小)奥迪多媒体交互系统3G第一个超级块直接从字节0开始。
The first Superblock is located at 0x2000. (0x2000 is the bootblock size) The Audi MMI 3G first superblock directly starts at byte 0.
第二个超级块位置可以根据超级块信息(文件系统块的总数)计算,也可以取最高的设备地址,将最后3个字节归零,然后从该地址中减去0x1000。
Second superblock position can either be calculated from the superblock information (total number of filesystem blocks) or by taking the highest device address, zeroing the last 3 bytes and then subtracting 0x1000 from that address.
0x1000是为每个超级块保留的大小,与文件系统的块大小无关。
0x1000 is the size reserved for each superblock - regardless of the blocksize of the filesystem.
索引节(Inodes)
文件系统中的每个对象都由一个索引节表示。(索引节点)inode结构包含指向文件系统块的指针,文件系统块包含对象中保存的数据以及除长名称外的所有对象元数据。(文件名长度超过27个字符)关于对象的元数据包括权限、所有者、组、标志、大小、使用的块数、访问时间、更改时间和修改时间。
Each object in the filesystem is represented by an inode. (index node) The inode structure contains pointers to the filesystem blocks which contain the data held in the object and all of the metadata about an object except its longname. (filenames longer than 27 characters) The metadata about an object includes the permissions, owner, group, flags, size, number of blocks used, access time, change time and modification time.
对象模式字段为POSIX格式。(这让事情变得更容易)
Object mode field is POSIX format. (which makes things easier)
如果可以用16个直接块来寻址对象数据,则还存在指向前16个块的指针。
There are also pointers to the first 16 blocks, if the object data can be addressed with 16 direct blocks.
对于超过16个块,使用另一个树形式的间接寻址。(方案与用于超级块根节点的方案相同)
For more than 16 blocks an indirect addressing in form of another tree is used. (scheme is the same as the one used for the superblock root nodes)
文件大小存储为64位。索引节计数从1开始。(而长文件名索引节点以0开头)
The filesize is stored 64bit. Inode counting starts with 1. (while long filename inodes start with 0)
目录(Directories)
目录是一个文件系统对象,像普通文件一样它也有一个索引节。它是一个特殊格式的文件,包含将每个名称与索引节编号关联的记录。
A directory is a filesystem object and has an inode just like a file. It is a specially formatted file containing records which associate each name with an inode number.
‘.’ 索引节编号指向目录索引节
‘.’ inode number points to the directory inode
‘…’ 索引节编号指向父目录索引节
‘…’ inode number points to the parent directory inode
每个文件名记录还获得了一个文件名长度字段。
Eeach filename record additionally got a filename length field.
一种特殊情况是长文件名或子目录名。
One special case are long filenames or subdirectory names.
它们在相应的目录记录中设置了一个文件名长度字段0xff,加上该记录中也存储的长文件索引节编号。
These got set a filename length field of 0xff in the corresponding directory record plus the longfile inode number also stored in that record.
有了这个长文件名索引节点号,就可以从超级块长文件名根节点指针开始遍历长文件名树。
With that longfilename inode number, the longfilename tree can be walked starting with the superblock longfilename root node pointers.
特殊文件(Special files)
符号链接也是具有索引节的文件系统对象。它们在inode模式字段中得到一个特定的位,将它们标识为符号链接。
Symbolic links are also filesystem objects with inodes. They got a specific bit in the inode mode field identifying them as symbolic link.
目录条目文件索引节指针指向目标文件索引节点。
The directory entry file inode pointer points to the target file inode.
硬链接有一个索引节,一个目录条目,但有一个特定的模式位集,没有块指针和指向目标文件索引节的目录文件记录。
Hard links got an inode, a directory entry, but a specific mode bit set, no block pointers and the directory file record pointing to the target file inode.
QNX中不存在字符和块专用设备,因为这些文件由QNX内核/驱动程序处理,并在/dev中创建,与底层文件系统无关。
Character and block special devices do not exist in QNX as those files are handled by the QNX kernel/drivers and created in /dev independent of the underlaying filesystem.
长文件名(Long filenames)
长文件名存储在单独的寻址树中。起始点是活动超级块中的长文件名根节点。
Long filenames are stored in a separate addressing tree. The staring point is the longfilename root node in the active superblock.
每个数据块(树叶子)都有一个长文件名。该文件名限制为510个字节。前两个起始字节用作实际文件名的长度字段。
Each data block (tree leaves) holds one long filename. That filename is limited to 510 bytes. The first two starting bytes are used as length field for the actual filename.
如果该结构适用于所有允许的块大小,那么很清楚为什么实际存储的文件名限制为510字节。
If that structure shall fit for all allowed blocksizes, it is clear why there is a limit of 510 bytes for the actual filename stored.
位映像(Bitmap)
qnx6fs文件系统分配位映像存储在超级块中位映像根节点下的树中,位映像中的每个位代表一个文件系统块。
The qnx6fs filesystem allocation bitmap is stored in a tree under bitmap root node in the superblock and each bit in the bitmap represents one filesystem block.
第一个块是块0,它在超级块启动后0x1000开始。因此,对于正常的qnx6fs,0x3000(引导块+超级块)是块0所在的物理地址。
The first block is block 0, which starts 0x1000 after superblock start. So for a normal qnx6fs 0x3000 (bootblock + superblock) is the physical address at which block 0 is located.
如果设备小于位映像中的寻址空间,则最后一个位映像块末尾的位设置为1。
Bits at the end of the last bitmap block are set to 1, if the device is smaller than addressing space in the bitmap.
位映像系统区域(Bitmap system area)
位映像本身分为三个部分。
The bitmap itself is divided into three parts.
首先是系统区域,它被分成两半。
First the system area, that is split into two halves.
然后是用户空间。
Then userspace.
对静态、固定的预分配系统区域的需求来自qnx6fs处理写操作的方式。
The requirement for a static, fixed preallocated system area comes from how qnx6fs deals with writes.
每个超级块都有自己的一半系统区域。因此,超级块#1总是使用来自下半部分的块,而超级块#2只是写入由上半部分位映像系统区域位表示的块。
Each superblock got its own half of the system area. So superblock #1 always uses blocks from the lower half while superblock #2 just writes to blocks represented by the upper half bitmap system area bits.
用于这两个树结构的位映像块、索引节块和间接寻址块被视为系统块。
Bitmap blocks, Inode blocks and indirect addressing blocks for those two tree structures are treated as system blocks.
这背后的原因是,写请求可以在新的快照(非活动的系统区域,即序列号较低的超级块)上工作,同时在系统区域的另一半仍然有一个完整稳定的文件系统结构。
The rational behind that is that a write request can work on a new snapshot (system area of the inactive - resp. lower serial numbered superblock) while at the same time there is still a complete stable filesystem structure in the other half of the system area.
写入完成后(同步写入完成,请求最大同步跳跃时间或文件系统同步),以前不活动的超级块的序列会原子性地增加,fs会切换到那个然后稳定声明的超级块。
When finished with writing (a sync write is completed, the maximum sync leap time or a filesystem sync is requested), serial of the previously inactive superblock atomically is increased and the fs switches over to that - then stable declared - superblock.
对于系统区域之外的所有数据,块只是在写入时复制的。
For all data outside the system area, blocks are just copied while writing.