요약·해설과 원문, 전문 번역을 서로 분리했습니다. API 이름, symbol, source path는 원문 표기를 사용합니다.
1. 요약·해설
원문의 핵심 논리와 kernel programming 관점의 보충 설명입니다. 아래의 전문 번역과는 별도로 작성했습니다.
2. 영어 원문 전체
번역 기준이 된 Linux v6.18.37 원문입니다. 줄 번호는 이 버전의 파일 좌표입니다.
원문 전체 펼치기
.. SPDX-License-Identifier: GPL-2.0
===================
The QNX6 Filesystem
===================
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
======
mmi_fs Mount filesystem as used for example by Audi MMI 3G system
Specification
=============
qnx6fs shares many properties with traditional Unix filesystems. It has the
concepts of blocks, inodes and directories.
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.
The Linux driver handles endianness transparently. (LE and BE)
Blocks
------
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.
Blockpointers are 32bit, so the maximum space that can be addressed is
2^32 * 4096 bytes or 16TB
The superblocks
---------------
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.
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 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).
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.
The first Superblock is located at 0x2000. (0x2000 is the bootblock size)
The Audi MMI 3G first superblock directly starts at byte 0.
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 is the size reserved for each superblock - regardless of the
blocksize of the filesystem.
Inodes
------
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.
Object mode field is POSIX format. (which makes things easier)
There are also pointers to the first 16 blocks, if the object data can be
addressed with 16 direct blocks.
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)
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.
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
-------------
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.
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
underlying filesystem.
Long filenames
--------------
Long filenames are stored in a separate addressing tree. The staring point
is the longfilename root node in the active superblock.
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.
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
------
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.
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.
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.
The requirement for a static, fixed preallocated system area comes from how
qnx6fs deals with writes.
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.
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.
3. 한국어 전문 번역
영어 원문의 문단 순서와 의미를 유지한 전체 번역입니다. 코드, 함수명, symbol과 URL은 원문 표기를 유지합니다.
QNX6 파일시스템 개요와 블록
1-27`qnx6fs`는 Neutrino 같은 비교적 최신 QNX 운영체제에서 사용하는 파일시스템이다. QNX 6.4.0에서 도입됐고 6.4.1부터 기본 파일시스템으로 사용됐다.
마운트 옵션 `mmi_fs`는 Audi MMI 3G 시스템과 같은 변형 레이아웃으로 파일시스템을 마운트한다.
QNX6는 블록·inode·디렉터리라는 전통적인 Unix 파일시스템 개념을 공유한다. QNX에서는 little-endian과 big-endian QNX6 파일시스템을 모두 만들 수 있으므로, 다양한 임베디드 대상의 바이트 순서와 다른 파일시스템도 생성하고 사용할 수 있다. Linux 드라이버는 LE와 BE를 투명하게 처리한다.
장치나 파일의 공간은 생성 시 결정되는 512, 1024, 2048, 4096바이트 고정 크기 블록으로 나뉜다. 블록 포인터는 32비트이므로 최대 주소 공간은 `2^32 * 4096`바이트, 즉 16TB다.
마운트 변형, 바이트 순서, 주소 크기의 핵심 제약이다.
.. SPDX-License-Identifier: GPL-2.0
===================
The QNX6 Filesystem
===================
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
======
mmi_fs Mount filesystem as used for example by Audi MMI 3G system
Specification
=============
qnx6fs shares many properties with traditional Unix filesystems. It has the
concepts of blocks, inodes and directories.
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.
The Linux driver handles endianness transparently. (LE and BE)
듀얼 슈퍼블록과 스냅샷 트리
28-81슈퍼블록은 파일시스템의 전역 정보를 담는다. 각 QNX6 파일시스템에는 64비트 일련번호를 가진 슈퍼블록이 두 개 있으며, 이 번호로 active 슈퍼블록을 식별한다. 쓰기 모드에서 동기 쓰기로 새 스냅샷에 도달할 때 새 master 슈퍼블록의 일련번호는 이전 값보다 1 증가한다.
스냅샷은 마지막 일련번호 갱신을 원자적으로 수행하는 방식으로 완성된다. 일련번호를 바꾸기 전에는 해당 쓰기 요청 또는 기간에 수정된 블록을 모두 복사하고, inactive 슈퍼블록 아래에 새롭고 안정적인 파일시스템 구조를 구축한다.
각 슈퍼블록에는 inode, bitmap, long filename 영역을 위한 루트 inode 집합이 있다. 각 루트 노드는 저장 데이터의 전체 크기와 트리의 주소 지정 level을 기록한다. level 0에서는 노드마다 직접 블록을 최대 16개 가리킨다.
level 1은 간접 주소 블록 하나를 추가하며 각 간접 블록은 `blocksize / 4`개의 데이터 블록 포인터를 담는다. level 2는 간접 단계 하나를 더 추가하므로, 1024바이트 블록을 예로 들면 `16 * 256 * 256 = 1048576`개 블록을 가리킬 수 있다. 데이터 leaf는 항상 최하위 level에 있고 상위 트리 level에는 데이터를 저장하지 않는다.
사용하지 않는 블록 포인터는 루트 노드·간접 주소 블록·inode를 가리지 않고 항상 `~0`으로 설정한다.
inactive 절반에 완전한 새 구조를 만든 뒤 일련번호 하나로 active 상태를 바꾼다.
일반 QNX6와 Audi MMI 변형의 시작 위치 및 두 번째 슈퍼블록 계산법이다.
Blocks
------
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.
Blockpointers are 32bit, so the maximum space that can be addressed is
2^32 * 4096 bytes or 16TB
The superblocks
---------------
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.
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 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).
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.
The first Superblock is located at 0x2000. (0x2000 is the bootblock size)
The Audi MMI 3G first superblock directly starts at byte 0.
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 is the size reserved for each superblock - regardless of the
blocksize of the filesystem.
Inode와 디렉터리 레코드
82-123파일시스템의 각 객체는 inode(index node)로 표현한다. inode에는 객체 데이터가 있는 블록 포인터와 긴 이름을 제외한 메타데이터가 들어간다. 긴 이름은 27자를 넘는 파일명이다. 메타데이터에는 권한, 소유자, 그룹, 플래그, 크기, 사용 블록 수, 접근·변경·수정 시간이 포함된다.
객체 mode 필드는 POSIX 형식이다. 데이터가 직접 블록 16개로 표현되면 inode에 있는 첫 16개 포인터를 사용하고, 그보다 많으면 슈퍼블록 루트 노드와 같은 방식의 별도 간접 주소 트리를 사용한다. 파일 크기는 64비트로 저장한다. 일반 inode 번호는 1부터 세지만 long filename inode는 0부터 센다.
디렉터리도 파일과 같은 inode를 가진 파일시스템 객체다. 이름과 inode 번호를 연결하는 특별한 형식의 레코드 파일이다. `.`의 inode 번호는 디렉터리 자신을, `..`의 inode 번호는 부모 디렉터리를 가리키며 각 파일명 레코드에는 이름 길이 필드가 있다.
긴 파일명이나 긴 하위 디렉터리 이름은 예외다. 해당 디렉터리 레코드의 파일명 길이를 `0xff`로 설정하고 longfile inode 번호를 함께 저장한다. 이 번호로 active 슈퍼블록의 long filename 루트 노드 포인터에서 시작해 long filename 트리를 순회한다.
inode의 직접 포인터와 별도 트리로 일반 데이터와 긴 이름을 찾는다.
Inodes
------
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.
Object mode field is POSIX format. (which makes things easier)
There are also pointers to the first 16 blocks, if the object data can be
addressed with 16 direct blocks.
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)
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.
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.
특수 파일과 긴 파일명 저장
124-152심볼릭 링크도 inode를 가진 파일시스템 객체이며 inode mode 필드의 전용 비트로 식별한다. 디렉터리 엔트리의 file inode 포인터는 대상 파일 inode를 가리킨다.
하드 링크는 inode와 디렉터리 엔트리를 가지지만 전용 mode 비트가 설정되고 블록 포인터는 없으며, 디렉터리 파일 레코드가 대상 파일 inode를 가리킨다.
QNX의 문자·블록 특수 장치는 기반 파일시스템에 존재하지 않는다. QNX 커널과 드라이버가 처리하고 `/dev`에 독립적으로 생성하기 때문이다.
긴 파일명은 별도 주소 트리에 저장하며 시작점은 active 슈퍼블록의 long filename 루트 노드다. 각 데이터 블록인 트리 leaf는 긴 파일명 하나를 담는다. 이름의 실제 최대 길이는 510바이트이며 첫 2바이트는 길이 필드로 사용한다. 이 구조가 허용되는 모든 블록 크기에 맞아야 하므로 510바이트 제한이 생긴다.
디렉터리 레코드에는 이름 대신 별도 트리의 참조를 둔다.
Special files
-------------
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.
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
underlying filesystem.
Long filenames
--------------
Long filenames are stored in a separate addressing tree. The staring point
is the longfilename root node in the active superblock.
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.
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과 이중 시스템 영역
153-196QNX6 할당 bitmap은 슈퍼블록의 bitmap 루트 노드 아래 트리에 저장되며 각 bit가 파일시스템 블록 하나를 나타낸다. block 0은 슈퍼블록 시작에서 `0x1000` 뒤에 있다. 일반 QNX6에서는 bootblock과 슈퍼블록 뒤인 물리 주소 `0x3000`이 block 0이다.
장치가 bitmap의 주소 공간보다 작으면 마지막 bitmap 블록 끝의 초과 bit를 1로 설정해 할당할 수 없게 한다.
bitmap은 먼저 시스템 영역, 그 뒤 userspace의 세 부분으로 나뉜다. 시스템 영역 자체가 두 절반으로 나뉘므로 전체 구조는 하위 시스템 절반, 상위 시스템 절반, userspace다. 고정 크기로 미리 할당한 시스템 영역이 필요한 이유는 QNX6의 copy-on-write식 쓰기 처리다.
각 슈퍼블록은 시스템 영역의 자기 절반을 사용한다. 슈퍼블록 #1은 항상 하위 절반의 블록을 사용하고 슈퍼블록 #2는 상위 절반 bitmap bit가 나타내는 블록에만 쓴다. bitmap 블록, inode 블록, 두 트리의 간접 주소 블록은 시스템 블록으로 취급한다.
inactive, 즉 일련번호가 더 작은 슈퍼블록의 시스템 영역에 새 스냅샷을 쓰는 동안 다른 절반에는 완전하고 안정적인 파일시스템 구조가 그대로 남는다. 동기 쓰기 완료, 최대 sync leap 시간 도달, 또는 파일시스템 sync 요청 시 이전 inactive 슈퍼블록의 일련번호를 원자적으로 증가시키고 그 슈퍼블록을 안정된 active 상태로 전환한다.
시스템 영역 밖의 모든 데이터 블록은 쓰는 동안 단순히 복사한다.
두 슈퍼블록이 서로 다른 시스템 블록 절반을 사용해 안정된 스냅샷을 유지한다.
Bitmap
------
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.
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.
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.
The requirement for a static, fixed preallocated system area comes from how
qnx6fs deals with writes.
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.
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.
요약·해설
qnx6.rst:1-196QNX6는 임베디드 QNX 시스템에서 사용하는 양방향 endian 파일시스템이다. 두 슈퍼블록과 두 시스템 영역 절반을 번갈아 사용해 수정 블록으로 새 트리를 만든 뒤 64비트 일련번호를 원자적으로 갱신하는 스냅샷 구조가 핵심이다.
Linux 드라이버나 복구 도구를 작성할 때는 슈퍼블록 위치, `~0` 미사용 포인터, level별 간접 주소 계산, inode 번호 시작값, `0xff` 긴 이름 레코드, bitmap의 block 0 기준을 함께 지켜야 한다.
active 슈퍼블록에서 각 전용 트리와 데이터 leaf로 내려간다.