← Documents Documentation/filesystems/ext4/attributes.rst GitHub 원문 ↗

Linux 6.18.37 · Filesystems

Extended Attributes

ext4 xattr의 inode·외부 block 저장, header와 entry field, name index와 POSIX ACL을 설명하는 전문 번역입니다.

Source pathDocumentation/filesystems/ext4/attributes.rst
Source versionLinux v6.18.37
TranslationDUJINLABS 전문 번역 + 해설

요약·해설과 원문, 전문 번역을 서로 분리했습니다. API 이름, symbol, source path는 원문 표기를 사용합니다.

1. 요약·해설

원문의 핵심 논리와 kernel programming 관점의 보충 설명입니다. 아래의 전문 번역과는 별도로 작성했습니다.

요약·해설

attributes.rst:1-191

ext4 xattr는 inode 내부 여유 공간 또는 `inode.i_file_acl`이 가리키는 외부 block에 저장됩니다. header, 정렬된 entry, block 끝에서 역방향으로 자라는 value 영역으로 구성하며 name index가 `user.`, `security.` 같은 prefix를 압축합니다.

ext4 xattr lookup
in-inode xattr header와 entry 검색필요하면 `inode.i_file_acl` 외부 block 조회`e_name_index` prefix와 `e_name` 결합`e_value_inum`·`e_value_offs`로 value 위치 결정UUID·block number·전체 block checksum 검증

inode에서 key와 value를 찾는 기본 순서입니다.

2. 영어 원문 전체

번역 기준이 된 Linux v6.18.37 원문입니다. 줄 번호는 이 버전의 파일 좌표입니다.

원문 전체 펼치기
1 .. SPDX-License-Identifier: GPL-2.0
2
3 Extended Attributes
4 -------------------
5
6 Extended attributes (xattrs) are typically stored in a separate data
7 block on the disk and referenced from inodes via ``inode.i_file_acl*``.
8 The first use of extended attributes seems to have been for storing file
9 ACLs and other security data (selinux). With the ``user_xattr`` mount
10 option it is possible for users to store extended attributes so long as
11 all attribute names begin with “user”; this restriction seems to have
12 disappeared as of Linux 3.0.
13
14 There are two places where extended attributes can be found. The first
15 place is between the end of each inode entry and the beginning of the
16 next inode entry. For example, if inode.i_extra_isize = 28 and
17 sb.inode_size = 256, then there are 256 - (128 + 28) = 100 bytes
18 available for in-inode extended attribute storage. The second place
19 where extended attributes can be found is in the block pointed to by
20 ``inode.i_file_acl``. As of Linux 3.11, it is not possible for this
21 block to contain a pointer to a second extended attribute block (or even
22 the remaining blocks of a cluster). In theory it is possible for each
23 attribute's value to be stored in a separate data block, though as of
24 Linux 3.11 the code does not permit this.
25
26 Keys are generally assumed to be ASCIIZ strings, whereas values can be
27 strings or binary data.
28
29 Extended attributes, when stored after the inode, have a header
30 ``ext4_xattr_ibody_header`` that is 4 bytes long:
31
32 .. list-table::
33 :widths: 8 8 24 40
34 :header-rows: 1
35
36 * - Offset
37 - Type
38 - Name
39 - Description
40 * - 0x0
41 - __le32
42 - h_magic
43 - Magic number for identification, 0xEA020000. This value is set by the
44 Linux driver, though e2fsprogs doesn't seem to check it(?)
45
46 The beginning of an extended attribute block is in
47 ``struct ext4_xattr_header``, which is 32 bytes long:
48
49 .. list-table::
50 :widths: 8 8 24 40
51 :header-rows: 1
52
53 * - Offset
54 - Type
55 - Name
56 - Description
57 * - 0x0
58 - __le32
59 - h_magic
60 - Magic number for identification, 0xEA020000.
61 * - 0x4
62 - __le32
63 - h_refcount
64 - Reference count.
65 * - 0x8
66 - __le32
67 - h_blocks
68 - Number of disk blocks used.
69 * - 0xC
70 - __le32
71 - h_hash
72 - Hash value of all attributes.
73 * - 0x10
74 - __le32
75 - h_checksum
76 - Checksum of the extended attribute block.
77 * - 0x14
78 - __u32
79 - h_reserved[3]
80 - Zero.
81
82 The checksum is calculated against the FS UUID, the 64-bit block number
83 of the extended attribute block, and the entire block (header +
84 entries).
85
86 Following the ``struct ext4_xattr_header`` or
87 ``struct ext4_xattr_ibody_header`` is an array of
88 ``struct ext4_xattr_entry``; each of these entries is at least 16 bytes
89 long. When stored in an external block, the ``struct ext4_xattr_entry``
90 entries must be stored in sorted order. The sort order is
91 ``e_name_index``, then ``e_name_len``, and finally ``e_name``.
92 Attributes stored inside an inode do not need be stored in sorted order.
93
94 .. list-table::
95 :widths: 8 8 24 40
96 :header-rows: 1
97
98 * - Offset
99 - Type
100 - Name
101 - Description
102 * - 0x0
103 - __u8
104 - e_name_len
105 - Length of name.
106 * - 0x1
107 - __u8
108 - e_name_index
109 - Attribute name index. There is a discussion of this below.
110 * - 0x2
111 - __le16
112 - e_value_offs
113 - Location of this attribute's value on the disk block where it is stored.
114 Multiple attributes can share the same value. For an inode attribute
115 this value is relative to the start of the first entry; for a block this
116 value is relative to the start of the block (i.e. the header).
117 * - 0x4
118 - __le32
119 - e_value_inum
120 - The inode where the value is stored. Zero indicates the value is in the
121 same block as this entry. This field is only used if the
122 INCOMPAT_EA_INODE feature is enabled.
123 * - 0x8
124 - __le32
125 - e_value_size
126 - Length of attribute value.
127 * - 0xC
128 - __le32
129 - e_hash
130 - Hash value of attribute name and attribute value. The kernel doesn't
131 update the hash for in-inode attributes, so for that case this value
132 must be zero, because e2fsck validates any non-zero hash regardless of
133 where the xattr lives.
134 * - 0x10
135 - char
136 - e_name[e_name_len]
137 - Attribute name. Does not include trailing NULL.
138
139 Attribute values can follow the end of the entry table. There appears to
140 be a requirement that they be aligned to 4-byte boundaries. The values
141 are stored starting at the end of the block and grow towards the
142 xattr_header/xattr_entry table. When the two collide, the overflow is
143 put into a separate disk block. If the disk block fills up, the
144 filesystem returns -ENOSPC.
145
146 The first four fields of the ``ext4_xattr_entry`` are set to zero to
147 mark the end of the key list.
148
149 Attribute Name Indices
150 ~~~~~~~~~~~~~~~~~~~~~~
151
152 Logically speaking, extended attributes are a series of key=value pairs.
153 The keys are assumed to be NULL-terminated strings. To reduce the amount
154 of on-disk space that the keys consume, the beginning of the key string
155 is matched against the attribute name index. If a match is found, the
156 attribute name index field is set, and matching string is removed from
157 the key name. Here is a map of name index values to key prefixes:
158
159 .. list-table::
160 :widths: 16 64
161 :header-rows: 1
162
163 * - Name Index
164 - Key Prefix
165 * - 0
166 - (no prefix)
167 * - 1
168 - “user.”
169 * - 2
170 - “system.posix_acl_access”
171 * - 3
172 - “system.posix_acl_default”
173 * - 4
174 - “trusted.”
175 * - 6
176 - “security.”
177 * - 7
178 - “system.” (inline_data only?)
179 * - 8
180 - “system.richacl” (SuSE kernels only?)
181
182 For example, if the attribute key is “user.fubar”, the attribute name
183 index is set to 1 and the “fubar” name is recorded on disk.
184
185 POSIX ACLs
186 ~~~~~~~~~~
187
188 POSIX ACLs are stored in a reduced version of the Linux kernel (and
189 libacl's) internal ACL format. The key difference is that the version
190 number is different (1) and the ``e_id`` field is only stored for named
191 user and group ACLs.
192

3. 한국어 전문 번역

영어 원문의 문단 순서와 의미를 유지한 전체 번역입니다. 코드, 함수명, symbol과 URL은 원문 표기를 유지합니다.

extended attribute 저장 위치

1-28

extended attribute(xattr)는 일반적으로 disk의 별도 data block에 저장하고 inode의 `inode.i_file_acl*`에서 참조합니다. 초기에는 file ACL과 SELinux 같은 security data를 저장하는 데 사용된 것으로 보입니다.

`user_xattr` mount option을 사용하면 사용자가 extended attribute를 저장할 수 있었습니다. 원래 모든 attribute name이 `user`로 시작해야 했지만 Linux 3.0부터 이 제한이 사라진 것으로 보입니다.

xattr를 찾을 수 있는 첫 번째 위치는 inode entry 끝과 다음 inode entry 시작 사이입니다. 예를 들어 `inode.i_extra_isize = 28`, `sb.inode_size = 256`이면 in-inode xattr에 사용할 수 있는 공간은 `256 - (128 + 28) = 100 bytes`입니다.

두 번째 위치는 `inode.i_file_acl`이 가리키는 block입니다. Linux 3.11 시점에는 이 block이 두 번째 xattr block이나 cluster의 나머지 block을 가리킬 수 없습니다. 이론상 attribute value마다 별도 data block을 사용할 수 있지만 당시 code는 허용하지 않았습니다.

key는 일반적으로 ASCIIZ string으로 간주하고 value는 string 또는 binary data일 수 있습니다.

ext4 xattr 저장 위치
위치참조특징
In-inodeinode entry 뒤의 여유 공간`inode_size - (128 + i_extra_isize)`
예시`256 - (128 + 28)`100 bytes
External block`inode.i_file_acl`Linux 3.11에서 다음 xattr block 연결 불가
KeyASCIIZ일반적으로 NULL 종료 string
Valueentry 또는 별도 저장string 또는 binary data

inode 내부와 외부 block의 용량 및 제약을 비교합니다.

.. SPDX-License-Identifier: GPL-2.0

Extended Attributes
-------------------

Extended attributes (xattrs) are typically stored in a separate data
block on the disk and referenced from inodes via ``inode.i_file_acl*``.
The first use of extended attributes seems to have been for storing file
ACLs and other security data (selinux). With the ``user_xattr`` mount
option it is possible for users to store extended attributes so long as
all attribute names begin with “user”; this restriction seems to have
disappeared as of Linux 3.0.

There are two places where extended attributes can be found. The first
place is between the end of each inode entry and the beginning of the
next inode entry. For example, if inode.i_extra_isize = 28 and
sb.inode_size = 256, then there are 256 - (128 + 28) = 100 bytes
available for in-inode extended attribute storage. The second place
where extended attributes can be found is in the block pointed to by
``inode.i_file_acl``. As of Linux 3.11, it is not possible for this
block to contain a pointer to a second extended attribute block (or even
the remaining blocks of a cluster). In theory it is possible for each
attribute's value to be stored in a separate data block, though as of
Linux 3.11 the code does not permit this.

Keys are generally assumed to be ASCIIZ strings, whereas values can be
strings or binary data.

xattr header와 checksum

29-84

inode 뒤에 저장한 xattr는 4-byte `ext4_xattr_ibody_header`로 시작합니다. offset `0x0`의 `__le32 h_magic`은 식별용 magic number `0xEA020000`입니다. Linux driver가 설정하지만 e2fsprogs는 이를 검사하지 않는 것으로 보인다는 주석이 있습니다.

외부 xattr block은 32-byte `struct ext4_xattr_header`로 시작합니다. `h_magic` 뒤에 reference count, 사용 disk block 수, 모든 attribute의 hash, xattr block checksum, 0으로 채운 reserved field가 이어집니다.

checksum은 filesystem UUID, xattr block의 64-bit block number, header와 entry를 포함한 block 전체를 대상으로 계산합니다.

`struct ext4_xattr_header`
OffsetTypeName설명
`0x0``__le32``h_magic``0xEA020000`
`0x4``__le32``h_refcount`reference count
`0x8``__le32``h_blocks`사용한 disk block 수
`0xC``__le32``h_hash`모든 attribute의 hash
`0x10``__le32``h_checksum`xattr block checksum
`0x14``__u32[3]``h_reserved[3]`0
Checksum input--FS UUID + 64-bit block number + 전체 block

외부 xattr block의 32-byte header field입니다.

Extended attributes, when stored after the inode, have a header
``ext4_xattr_ibody_header`` that is 4 bytes long:

.. list-table::
   :widths: 8 8 24 40
   :header-rows: 1

   * - Offset
     - Type
     - Name
     - Description
   * - 0x0
     - __le32
     - h_magic
     - Magic number for identification, 0xEA020000. This value is set by the
       Linux driver, though e2fsprogs doesn't seem to check it(?)

The beginning of an extended attribute block is in
``struct ext4_xattr_header``, which is 32 bytes long:

.. list-table::
   :widths: 8 8 24 40
   :header-rows: 1

   * - Offset
     - Type
     - Name
     - Description
   * - 0x0
     - __le32
     - h_magic
     - Magic number for identification, 0xEA020000.
   * - 0x4
     - __le32
     - h_refcount
     - Reference count.
   * - 0x8
     - __le32
     - h_blocks
     - Number of disk blocks used.
   * - 0xC
     - __le32
     - h_hash
     - Hash value of all attributes.
   * - 0x10
     - __le32
     - h_checksum
     - Checksum of the extended attribute block.
   * - 0x14
     - __u32
     - h_reserved[3]
     - Zero.

The checksum is calculated against the FS UUID, the 64-bit block number
of the extended attribute block, and the entire block (header +
entries).

xattr entry, 정렬과 value 배치

85-147

`struct ext4_xattr_header` 또는 `struct ext4_xattr_ibody_header` 뒤에는 `struct ext4_xattr_entry` 배열이 옵니다. 각 entry는 최소 16 bytes입니다.

external block의 entry는 `e_name_index`, `e_name_len`, `e_name` 순으로 비교한 정렬 순서를 지켜야 합니다. inode 내부 attribute는 정렬할 필요가 없습니다.

`e_value_offs`는 value가 있는 위치입니다. 여러 attribute가 같은 value를 공유할 수 있습니다. inode attribute에서는 첫 entry 시작을 기준으로 하고 block attribute에서는 header를 포함한 block 시작을 기준으로 합니다.

`e_value_inum`은 value를 저장한 inode를 나타냅니다. 0이면 entry와 같은 block에 value가 있습니다. 이 field는 `INCOMPAT_EA_INODE` feature가 활성화됐을 때만 사용합니다.

`e_hash`는 attribute name과 value의 hash입니다. kernel은 in-inode attribute의 hash를 갱신하지 않으므로 이 경우 0이어야 합니다. `e2fsck`가 xattr 위치와 관계없이 0이 아닌 hash를 검증하기 때문입니다. `e_name`은 trailing NULL을 포함하지 않습니다.

attribute value는 entry table 뒤에 올 수 있고 4-byte boundary에 align해야 하는 것으로 보입니다. value는 block 끝에서 xattr header와 entry table 방향으로 자랍니다. 두 영역이 충돌하면 overflow를 별도 disk block에 두며 block도 가득 차면 filesystem이 `-ENOSPC`를 반환합니다.

key list의 끝은 `ext4_xattr_entry` 첫 네 field를 모두 0으로 설정해 표시합니다.

`struct ext4_xattr_entry`
OffsetTypeName설명
`0x0``__u8``e_name_len`name 길이
`0x1``__u8``e_name_index`attribute name index
`0x2``__le16``e_value_offs`현재 저장 영역 안의 value 위치
`0x4``__le32``e_value_inum`value inode, 같은 block이면 0
`0x8``__le32``e_value_size`attribute value 길이
`0xC``__le32``e_hash`name과 value의 hash
`0x10``char[]``e_name[e_name_len]`trailing NULL 없는 name

최소 16-byte entry와 가변 name field입니다.


Following the ``struct ext4_xattr_header`` or
``struct ext4_xattr_ibody_header`` is an array of
``struct ext4_xattr_entry``; each of these entries is at least 16 bytes
long. When stored in an external block, the ``struct ext4_xattr_entry``
entries must be stored in sorted order. The sort order is
``e_name_index``, then ``e_name_len``, and finally ``e_name``.
Attributes stored inside an inode do not need be stored in sorted order.

.. list-table::
   :widths: 8 8 24 40
   :header-rows: 1

   * - Offset
     - Type
     - Name
     - Description
   * - 0x0
     - __u8
     - e_name_len
     - Length of name.
   * - 0x1
     - __u8
     - e_name_index
     - Attribute name index. There is a discussion of this below.
   * - 0x2
     - __le16
     - e_value_offs
     - Location of this attribute's value on the disk block where it is stored.
       Multiple attributes can share the same value. For an inode attribute
       this value is relative to the start of the first entry; for a block this
       value is relative to the start of the block (i.e. the header).
   * - 0x4
     - __le32
     - e_value_inum
     - The inode where the value is stored. Zero indicates the value is in the
       same block as this entry. This field is only used if the
       INCOMPAT_EA_INODE feature is enabled.
   * - 0x8
     - __le32
     - e_value_size
     - Length of attribute value.
   * - 0xC
     - __le32
     - e_hash
     - Hash value of attribute name and attribute value. The kernel doesn't
       update the hash for in-inode attributes, so for that case this value
       must be zero, because e2fsck validates any non-zero hash regardless of
       where the xattr lives.
   * - 0x10
     - char
     - e_name[e_name_len]
     - Attribute name. Does not include trailing NULL.

Attribute values can follow the end of the entry table. There appears to
be a requirement that they be aligned to 4-byte boundaries. The values
are stored starting at the end of the block and grow towards the
xattr_header/xattr_entry table. When the two collide, the overflow is
put into a separate disk block. If the disk block fills up, the
filesystem returns -ENOSPC.

The first four fields of the ``ext4_xattr_entry`` are set to zero to
mark the end of the key list.

name index 압축과 POSIX ACL

148-191

논리적으로 xattr는 `key=value` 쌍의 연속입니다. key는 NULL-terminated string으로 간주합니다. key가 차지하는 on-disk 공간을 줄이기 위해 key 시작 부분을 attribute name index의 prefix와 비교합니다.

prefix가 일치하면 `e_name_index`를 설정하고 일치한 문자열은 disk에 기록하는 key name에서 제거합니다. 예를 들어 `user.fubar`는 index 1을 저장하고 name에는 `fubar`만 기록합니다.

name index 0은 prefix가 없습니다. 1은 `user.`, 2는 `system.posix_acl_access`, 3은 `system.posix_acl_default`, 4는 `trusted.`, 6은 `security.`, 7은 `system.`이며 inline_data 전용일 수 있습니다. 8은 `system.richacl`이며 SuSE kernel 전용일 수 있습니다.

POSIX ACL은 Linux kernel과 libacl 내부 ACL format을 축약한 형태로 저장합니다. 핵심 차이는 version number가 1이고 `e_id` field는 이름이 지정된 user와 group ACL에만 저장한다는 점입니다.

xattr name index
Name IndexKey Prefix
0prefix 없음
1`user.`
2`system.posix_acl_access`
3`system.posix_acl_default`
4`trusted.`
6`security.`
7`system.` (inline_data only?)
8`system.richacl` (SuSE kernels only?)

index가 대체하는 key prefix를 원문 값 그대로 보존합니다.


Attribute Name Indices
~~~~~~~~~~~~~~~~~~~~~~

Logically speaking, extended attributes are a series of key=value pairs.
The keys are assumed to be NULL-terminated strings. To reduce the amount
of on-disk space that the keys consume, the beginning of the key string
is matched against the attribute name index. If a match is found, the
attribute name index field is set, and matching string is removed from
the key name. Here is a map of name index values to key prefixes:

.. list-table::
   :widths: 16 64
   :header-rows: 1

   * - Name Index
     - Key Prefix
   * - 0
     - (no prefix)
   * - 1
     - “user.”
   * - 2
     - “system.posix_acl_access”
   * - 3
     - “system.posix_acl_default”
   * - 4
     - “trusted.”
   * - 6
     - “security.”
   * - 7
     - “system.” (inline_data only?)
   * - 8
     - “system.richacl” (SuSE kernels only?)

For example, if the attribute key is “user.fubar”, the attribute name
index is set to 1 and the “fubar” name is recorded on disk.

POSIX ACLs
~~~~~~~~~~

POSIX ACLs are stored in a reduced version of the Linux kernel (and
libacl's) internal ACL format. The key difference is that the version
number is different (1) and the ``e_id`` field is only stored for named
user and group ACLs.