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

Linux 6.18.37 · Filesystems

Index Nodes

ext4 inode 구조, mode·flag, OS별 확장 필드, 위치 계산과 timestamp 인코딩의 전문 번역입니다.

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

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

1. 요약·해설

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

요약·해설

inodes.rst:1-578

ext4 inode는 파일의 mode, 소유권, 크기, block mapping, xattr 위치, flag, checksum과 다섯 종류의 timestamp를 보관합니다. inode number에서 block group과 table index를 계산하며 inode 0은 존재하지 않습니다.

기본 128바이트 형식 뒤의 확장 필드는 `s_inode_size`와 `i_extra_isize`로 유효 범위를 판단합니다. creator OS에 따라 `i_osd1`과 `i_osd2`의 의미가 다르고, Linux 배치는 UID/GID·block count·xattr block·checksum의 상위 또는 하위 비트를 보충합니다.

ctime, atime, mtime은 extra 필드로 34비트 seconds와 30비트 nanoseconds를 표현해 2446년까지 확장되지만, dtime은 32비트이며 orphan list 연결에 재사용될 수 있습니다.

ext4 inode 해석 순서
inode number로 block group과 table byte offset 계산`s_inode_size`만큼 record 읽기기본 128바이트 `struct ext4_inode` 해석`i_extra_isize` 범위 안의 확장 필드 해석`i_flags`와 creator OS에 따라 조건부 필드 의미 결정UUID + inode number + inode structure checksum 검증extra epoch bits로 64비트 timestamp decode

on-disk inode를 안전하게 읽고 검증하는 전체 흐름입니다.

2. 영어 원문 전체

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

원문 전체 펼치기
1 .. SPDX-License-Identifier: GPL-2.0
2
3 Index Nodes
4 -----------
5
6 In a regular UNIX filesystem, the inode stores all the metadata
7 pertaining to the file (time stamps, block maps, extended attributes,
8 etc), not the directory entry. To find the information associated with a
9 file, one must traverse the directory files to find the directory entry
10 associated with a file, then load the inode to find the metadata for
11 that file. ext4 appears to cheat (for performance reasons) a little bit
12 by storing a copy of the file type (normally stored in the inode) in the
13 directory entry. (Compare all this to FAT, which stores all the file
14 information directly in the directory entry, but does not support hard
15 links and is in general more seek-happy than ext4 due to its simpler
16 block allocator and extensive use of linked lists.)
17
18 The inode table is a linear array of ``struct ext4_inode``. The table is
19 sized to have enough blocks to store at least
20 ``sb.s_inode_size * sb.s_inodes_per_group`` bytes. The number of the
21 block group containing an inode can be calculated as
22 ``(inode_number - 1) / sb.s_inodes_per_group``, and the offset into the
23 group's table is ``(inode_number - 1) % sb.s_inodes_per_group``. There
24 is no inode 0.
25
26 The inode checksum is calculated against the FS UUID, the inode number,
27 and the inode structure itself.
28
29 The inode table entry is laid out in ``struct ext4_inode``.
30
31 .. list-table::
32 :widths: 8 8 24 40
33 :header-rows: 1
34 :class: longtable
35
36 * - Offset
37 - Size
38 - Name
39 - Description
40 * - 0x0
41 - __le16
42 - i_mode
43 - File mode. See the table i_mode_ below.
44 * - 0x2
45 - __le16
46 - i_uid
47 - Lower 16-bits of Owner UID.
48 * - 0x4
49 - __le32
50 - i_size_lo
51 - Lower 32-bits of size in bytes.
52 * - 0x8
53 - __le32
54 - i_atime
55 - Last access time, in seconds since the epoch. However, if the EA_INODE
56 inode flag is set, this inode stores an extended attribute value and
57 this field contains the checksum of the value.
58 * - 0xC
59 - __le32
60 - i_ctime
61 - Last inode change time, in seconds since the epoch. However, if the
62 EA_INODE inode flag is set, this inode stores an extended attribute
63 value and this field contains the lower 32 bits of the attribute value's
64 reference count.
65 * - 0x10
66 - __le32
67 - i_mtime
68 - Last data modification time, in seconds since the epoch. However, if the
69 EA_INODE inode flag is set, this inode stores an extended attribute
70 value and this field contains the number of the inode that owns the
71 extended attribute.
72 * - 0x14
73 - __le32
74 - i_dtime
75 - Deletion Time, in seconds since the epoch.
76 * - 0x18
77 - __le16
78 - i_gid
79 - Lower 16-bits of GID.
80 * - 0x1A
81 - __le16
82 - i_links_count
83 - Hard link count. Normally, ext4 does not permit an inode to have more
84 than 65,000 hard links. This applies to files as well as directories,
85 which means that there cannot be more than 64,998 subdirectories in a
86 directory (each subdirectory's '..' entry counts as a hard link, as does
87 the '.' entry in the directory itself). With the DIR_NLINK feature
88 enabled, ext4 supports more than 64,998 subdirectories by setting this
89 field to 1 to indicate that the number of hard links is not known.
90 * - 0x1C
91 - __le32
92 - i_blocks_lo
93 - Lower 32-bits of “block” count. If the huge_file feature flag is not
94 set on the filesystem, the file consumes ``i_blocks_lo`` 512-byte blocks
95 on disk. If huge_file is set and EXT4_HUGE_FILE_FL is NOT set in
96 ``inode.i_flags``, then the file consumes ``i_blocks_lo + (i_blocks_hi
97 << 32)`` 512-byte blocks on disk. If huge_file is set and
98 EXT4_HUGE_FILE_FL IS set in ``inode.i_flags``, then this file
99 consumes (``i_blocks_lo + i_blocks_hi`` << 32) filesystem blocks on
100 disk.
101 * - 0x20
102 - __le32
103 - i_flags
104 - Inode flags. See the table i_flags_ below.
105 * - 0x24
106 - 4 bytes
107 - i_osd1
108 - See the table i_osd1_ for more details.
109 * - 0x28
110 - 60 bytes
111 - i_block[EXT4_N_BLOCKS=15]
112 - Block map or extent tree. See the section “The Contents of inode.i_block”.
113 * - 0x64
114 - __le32
115 - i_generation
116 - File version (for NFS).
117 * - 0x68
118 - __le32
119 - i_file_acl_lo
120 - Lower 32-bits of extended attribute block. ACLs are of course one of
121 many possible extended attributes; I think the name of this field is a
122 result of the first use of extended attributes being for ACLs.
123 * - 0x6C
124 - __le32
125 - i_size_high / i_dir_acl
126 - Upper 32-bits of file/directory size. In ext2/3 this field was named
127 i_dir_acl, though it was usually set to zero and never used.
128 * - 0x70
129 - __le32
130 - i_obso_faddr
131 - (Obsolete) fragment address.
132 * - 0x74
133 - 12 bytes
134 - i_osd2
135 - See the table i_osd2_ for more details.
136 * - 0x80
137 - __le16
138 - i_extra_isize
139 - Size of this inode - 128. Alternately, the size of the extended inode
140 fields beyond the original ext2 inode, including this field.
141 * - 0x82
142 - __le16
143 - i_checksum_hi
144 - Upper 16-bits of the inode checksum.
145 * - 0x84
146 - __le32
147 - i_ctime_extra
148 - Extra change time bits. This provides sub-second precision. See Inode
149 Timestamps section.
150 * - 0x88
151 - __le32
152 - i_mtime_extra
153 - Extra modification time bits. This provides sub-second precision.
154 * - 0x8C
155 - __le32
156 - i_atime_extra
157 - Extra access time bits. This provides sub-second precision.
158 * - 0x90
159 - __le32
160 - i_crtime
161 - File creation time, in seconds since the epoch.
162 * - 0x94
163 - __le32
164 - i_crtime_extra
165 - Extra file creation time bits. This provides sub-second precision.
166 * - 0x98
167 - __le32
168 - i_version_hi
169 - Upper 32-bits for version number.
170 * - 0x9C
171 - __le32
172 - i_projid
173 - Project ID.
174
175 .. _i_mode:
176
177 The ``i_mode`` value is a combination of the following flags:
178
179 .. list-table::
180 :widths: 16 64
181 :header-rows: 1
182
183 * - Value
184 - Description
185 * - 0x1
186 - S_IXOTH (Others may execute)
187 * - 0x2
188 - S_IWOTH (Others may write)
189 * - 0x4
190 - S_IROTH (Others may read)
191 * - 0x8
192 - S_IXGRP (Group members may execute)
193 * - 0x10
194 - S_IWGRP (Group members may write)
195 * - 0x20
196 - S_IRGRP (Group members may read)
197 * - 0x40
198 - S_IXUSR (Owner may execute)
199 * - 0x80
200 - S_IWUSR (Owner may write)
201 * - 0x100
202 - S_IRUSR (Owner may read)
203 * - 0x200
204 - S_ISVTX (Sticky bit)
205 * - 0x400
206 - S_ISGID (Set GID)
207 * - 0x800
208 - S_ISUID (Set UID)
209 * -
210 - These are mutually-exclusive file types:
211 * - 0x1000
212 - S_IFIFO (FIFO)
213 * - 0x2000
214 - S_IFCHR (Character device)
215 * - 0x4000
216 - S_IFDIR (Directory)
217 * - 0x6000
218 - S_IFBLK (Block device)
219 * - 0x8000
220 - S_IFREG (Regular file)
221 * - 0xA000
222 - S_IFLNK (Symbolic link)
223 * - 0xC000
224 - S_IFSOCK (Socket)
225
226 .. _i_flags:
227
228 The ``i_flags`` field is a combination of these values:
229
230 .. list-table::
231 :widths: 16 64
232 :header-rows: 1
233
234 * - Value
235 - Description
236 * - 0x1
237 - This file requires secure deletion (EXT4_SECRM_FL). (not implemented)
238 * - 0x2
239 - This file should be preserved, should undeletion be desired
240 (EXT4_UNRM_FL). (not implemented)
241 * - 0x4
242 - File is compressed (EXT4_COMPR_FL). (not really implemented)
243 * - 0x8
244 - All writes to the file must be synchronous (EXT4_SYNC_FL).
245 * - 0x10
246 - File is immutable (EXT4_IMMUTABLE_FL).
247 * - 0x20
248 - File can only be appended (EXT4_APPEND_FL).
249 * - 0x40
250 - The dump(1) utility should not dump this file (EXT4_NODUMP_FL).
251 * - 0x80
252 - Do not update access time (EXT4_NOATIME_FL).
253 * - 0x100
254 - Dirty compressed file (EXT4_DIRTY_FL). (not used)
255 * - 0x200
256 - File has one or more compressed clusters (EXT4_COMPRBLK_FL). (not used)
257 * - 0x400
258 - Do not compress file (EXT4_NOCOMPR_FL). (not used)
259 * - 0x800
260 - Encrypted inode (EXT4_ENCRYPT_FL). This bit value previously was
261 EXT4_ECOMPR_FL (compression error), which was never used.
262 * - 0x1000
263 - Directory has hashed indexes (EXT4_INDEX_FL).
264 * - 0x2000
265 - AFS magic directory (EXT4_IMAGIC_FL).
266 * - 0x4000
267 - File data must always be written through the journal
268 (EXT4_JOURNAL_DATA_FL).
269 * - 0x8000
270 - File tail should not be merged (EXT4_NOTAIL_FL). (not used by ext4)
271 * - 0x10000
272 - All directory entry data should be written synchronously (see
273 ``dirsync``) (EXT4_DIRSYNC_FL).
274 * - 0x20000
275 - Top of directory hierarchy (EXT4_TOPDIR_FL).
276 * - 0x40000
277 - This is a huge file (EXT4_HUGE_FILE_FL).
278 * - 0x80000
279 - Inode uses extents (EXT4_EXTENTS_FL).
280 * - 0x100000
281 - Verity protected file (EXT4_VERITY_FL).
282 * - 0x200000
283 - Inode stores a large extended attribute value in its data blocks
284 (EXT4_EA_INODE_FL).
285 * - 0x400000
286 - This file has blocks allocated past EOF (EXT4_EOFBLOCKS_FL).
287 (deprecated)
288 * - 0x01000000
289 - Inode is a snapshot (``EXT4_SNAPFILE_FL``). (not in mainline)
290 * - 0x04000000
291 - Snapshot is being deleted (``EXT4_SNAPFILE_DELETED_FL``). (not in
292 mainline)
293 * - 0x08000000
294 - Snapshot shrink has completed (``EXT4_SNAPFILE_SHRUNK_FL``). (not in
295 mainline)
296 * - 0x10000000
297 - Inode has inline data (EXT4_INLINE_DATA_FL).
298 * - 0x20000000
299 - Create children with the same project ID (EXT4_PROJINHERIT_FL).
300 * - 0x80000000
301 - Reserved for ext4 library (EXT4_RESERVED_FL).
302 * -
303 - Aggregate flags:
304 * - 0x705BDFFF
305 - User-visible flags.
306 * - 0x604BC0FF
307 - User-modifiable flags. Note that while EXT4_JOURNAL_DATA_FL and
308 EXT4_EXTENTS_FL can be set with setattr, they are not in the kernel's
309 EXT4_FL_USER_MODIFIABLE mask, since it needs to handle the setting of
310 these flags in a special manner and they are masked out of the set of
311 flags that are saved directly to i_flags.
312
313 .. _i_osd1:
314
315 The ``osd1`` field has multiple meanings depending on the creator:
316
317 Linux:
318
319 .. list-table::
320 :widths: 8 8 24 40
321 :header-rows: 1
322
323 * - Offset
324 - Size
325 - Name
326 - Description
327 * - 0x0
328 - __le32
329 - l_i_version
330 - Inode version. However, if the EA_INODE inode flag is set, this inode
331 stores an extended attribute value and this field contains the upper 32
332 bits of the attribute value's reference count.
333
334 Hurd:
335
336 .. list-table::
337 :widths: 8 8 24 40
338 :header-rows: 1
339
340 * - Offset
341 - Size
342 - Name
343 - Description
344 * - 0x0
345 - __le32
346 - h_i_translator
347 - ??
348
349 Masix:
350
351 .. list-table::
352 :widths: 8 8 24 40
353 :header-rows: 1
354
355 * - Offset
356 - Size
357 - Name
358 - Description
359 * - 0x0
360 - __le32
361 - m_i_reserved
362 - ??
363
364 .. _i_osd2:
365
366 The ``osd2`` field has multiple meanings depending on the filesystem creator:
367
368 Linux:
369
370 .. list-table::
371 :widths: 8 8 24 40
372 :header-rows: 1
373
374 * - Offset
375 - Size
376 - Name
377 - Description
378 * - 0x0
379 - __le16
380 - l_i_blocks_high
381 - Upper 16-bits of the block count. Please see the note attached to
382 i_blocks_lo.
383 * - 0x2
384 - __le16
385 - l_i_file_acl_high
386 - Upper 16-bits of the extended attribute block (historically, the file
387 ACL location). See the Extended Attributes section below.
388 * - 0x4
389 - __le16
390 - l_i_uid_high
391 - Upper 16-bits of the Owner UID.
392 * - 0x6
393 - __le16
394 - l_i_gid_high
395 - Upper 16-bits of the GID.
396 * - 0x8
397 - __le16
398 - l_i_checksum_lo
399 - Lower 16-bits of the inode checksum.
400 * - 0xA
401 - __le16
402 - l_i_reserved
403 - Unused.
404
405 Hurd:
406
407 .. list-table::
408 :widths: 8 8 24 40
409 :header-rows: 1
410
411 * - Offset
412 - Size
413 - Name
414 - Description
415 * - 0x0
416 - __le16
417 - h_i_reserved1
418 - ??
419 * - 0x2
420 - __u16
421 - h_i_mode_high
422 - Upper 16-bits of the file mode.
423 * - 0x4
424 - __le16
425 - h_i_uid_high
426 - Upper 16-bits of the Owner UID.
427 * - 0x6
428 - __le16
429 - h_i_gid_high
430 - Upper 16-bits of the GID.
431 * - 0x8
432 - __u32
433 - h_i_author
434 - Author code?
435
436 Masix:
437
438 .. list-table::
439 :widths: 8 8 24 40
440 :header-rows: 1
441
442 * - Offset
443 - Size
444 - Name
445 - Description
446 * - 0x0
447 - __le16
448 - h_i_reserved1
449 - ??
450 * - 0x2
451 - __u16
452 - m_i_file_acl_high
453 - Upper 16-bits of the extended attribute block (historically, the file
454 ACL location).
455 * - 0x4
456 - __u32
457 - m_i_reserved2[2]
458 - ??
459
460 Inode Size
461 ~~~~~~~~~~
462
463 In ext2 and ext3, the inode structure size was fixed at 128 bytes
464 (``EXT2_GOOD_OLD_INODE_SIZE``) and each inode had a disk record size of
465 128 bytes. Starting with ext4, it is possible to allocate a larger
466 on-disk inode at format time for all inodes in the filesystem to provide
467 space beyond the end of the original ext2 inode. The on-disk inode
468 record size is recorded in the superblock as ``s_inode_size``. The
469 number of bytes actually used by struct ext4_inode beyond the original
470 128-byte ext2 inode is recorded in the ``i_extra_isize`` field for each
471 inode, which allows struct ext4_inode to grow for a new kernel without
472 having to upgrade all of the on-disk inodes. Access to fields beyond
473 EXT2_GOOD_OLD_INODE_SIZE should be verified to be within
474 ``i_extra_isize``. By default, ext4 inode records are 256 bytes, and (as
475 of August 2019) the inode structure is 160 bytes
476 (``i_extra_isize = 32``). The extra space between the end of the inode
477 structure and the end of the inode record can be used to store extended
478 attributes. Each inode record can be as large as the filesystem block
479 size, though this is not terribly efficient.
480
481 Finding an Inode
482 ~~~~~~~~~~~~~~~~
483
484 Each block group contains ``sb->s_inodes_per_group`` inodes. Because
485 inode 0 is defined not to exist, this formula can be used to find the
486 block group that an inode lives in:
487 ``bg = (inode_num - 1) / sb->s_inodes_per_group``. The particular inode
488 can be found within the block group's inode table at
489 ``index = (inode_num - 1) % sb->s_inodes_per_group``. To get the byte
490 address within the inode table, use
491 ``offset = index * sb->s_inode_size``.
492
493 Inode Timestamps
494 ~~~~~~~~~~~~~~~~
495
496 Four timestamps are recorded in the lower 128 bytes of the inode
497 structure -- inode change time (ctime), access time (atime), data
498 modification time (mtime), and deletion time (dtime). The four fields
499 are 32-bit signed integers that represent seconds since the Unix epoch
500 (1970-01-01 00:00:00 GMT), which means that the fields will overflow in
501 January 2038. If the filesystem does not have orphan_file feature, inodes
502 that are not linked from any directory but are still open (orphan inodes) have
503 the dtime field overloaded for use with the orphan list. The superblock field
504 ``s_last_orphan`` points to the first inode in the orphan list; dtime is then
505 the number of the next orphaned inode, or zero if there are no more orphans.
506
507 If the inode structure size ``sb->s_inode_size`` is larger than 128
508 bytes and the ``i_inode_extra`` field is large enough to encompass the
509 respective ``i_[cma]time_extra`` field, the ctime, atime, and mtime
510 inode fields are widened to 64 bits. Within this “extra” 32-bit field,
511 the lower two bits are used to extend the 32-bit seconds field to be 34
512 bit wide; the upper 30 bits are used to provide nanosecond timestamp
513 accuracy. Therefore, timestamps should not overflow until May 2446.
514 dtime was not widened. There is also a fifth timestamp to record inode
515 creation time (crtime); this field is 64-bits wide and decoded in the
516 same manner as 64-bit [cma]time. Neither crtime nor dtime are accessible
517 through the regular stat() interface, though debugfs will report them.
518
519 We use the 32-bit signed time value plus (2^32 * (extra epoch bits)).
520 In other words:
521
522 .. list-table::
523 :widths: 20 20 20 20 20
524 :header-rows: 1
525
526 * - Extra epoch bits
527 - MSB of 32-bit time
528 - Adjustment for signed 32-bit to 64-bit tv_sec
529 - Decoded 64-bit tv_sec
530 - valid time range
531 * - 0 0
532 - 1
533 - 0
534 - ``-0x80000000 - -0x00000001``
535 - 1901-12-13 to 1969-12-31
536 * - 0 0
537 - 0
538 - 0
539 - ``0x000000000 - 0x07fffffff``
540 - 1970-01-01 to 2038-01-19
541 * - 0 1
542 - 1
543 - 0x100000000
544 - ``0x080000000 - 0x0ffffffff``
545 - 2038-01-19 to 2106-02-07
546 * - 0 1
547 - 0
548 - 0x100000000
549 - ``0x100000000 - 0x17fffffff``
550 - 2106-02-07 to 2174-02-25
551 * - 1 0
552 - 1
553 - 0x200000000
554 - ``0x180000000 - 0x1ffffffff``
555 - 2174-02-25 to 2242-03-16
556 * - 1 0
557 - 0
558 - 0x200000000
559 - ``0x200000000 - 0x27fffffff``
560 - 2242-03-16 to 2310-04-04
561 * - 1 1
562 - 1
563 - 0x300000000
564 - ``0x280000000 - 0x2ffffffff``
565 - 2310-04-04 to 2378-04-22
566 * - 1 1
567 - 0
568 - 0x300000000
569 - ``0x300000000 - 0x37fffffff``
570 - 2378-04-22 to 2446-05-10
571
572 This is a somewhat odd encoding since there are effectively seven times
573 as many positive values as negative values. There have also been
574 long-standing bugs decoding and encoding dates beyond 2038, which don't
575 seem to be fixed as of kernel 3.12 and e2fsprogs 1.42.8. 64-bit kernels
576 incorrectly use the extra epoch bits 1,1 for dates between 1901 and
577 1970. At some point the kernel will be fixed and e2fsck will fix this
578 situation, assuming that it is run before 2310.
579

3. 한국어 전문 번역

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

inode와 inode table

1-29

일반적인 UNIX 파일시스템에서는 디렉터리 엔트리가 아니라 inode가 timestamp, block map, extended attribute 등 파일의 모든 메타데이터를 저장합니다. 파일 정보를 찾으려면 디렉터리 파일을 순회해 해당 파일의 directory entry를 찾고, 그 뒤 inode를 읽어 메타데이터를 가져와야 합니다.

ext4는 성능을 위해 원래 inode에 있는 file type의 사본을 directory entry에도 저장합니다. FAT는 파일 정보를 directory entry에 직접 저장하지만 hard link를 지원하지 않으며, 단순한 block allocator와 linked list를 많이 사용하므로 ext4보다 seek가 더 많이 발생하는 편입니다.

inode table은 `struct ext4_inode`의 선형 배열입니다. table은 최소한 `sb.s_inode_size * sb.s_inodes_per_group`바이트를 저장할 수 있는 블록 수로 구성됩니다.

inode가 속한 block group은 `(inode_number - 1) / sb.s_inodes_per_group`으로 계산하고, 해당 그룹 table 안의 index는 `(inode_number - 1) % sb.s_inodes_per_group`입니다. inode 0은 존재하지 않습니다.

inode checksum은 FS UUID, inode number, inode structure 자체를 입력으로 계산합니다. inode table entry의 디스크 형식은 `struct ext4_inode`입니다.

파일 이름에서 inode 메타데이터까지
directory file에서 filename 검색directory entry에서 inode number와 file type 사본 확인`(inode_number - 1) / s_inodes_per_group`으로 block group 계산`(inode_number - 1) % s_inodes_per_group`으로 table index 계산`struct ext4_inode`를 읽고 UUID + inode number + structure checksum 검증

directory entry와 inode table을 거쳐 파일 메타데이터를 찾는 경로입니다.

.. SPDX-License-Identifier: GPL-2.0

Index Nodes
-----------

In a regular UNIX filesystem, the inode stores all the metadata
pertaining to the file (time stamps, block maps, extended attributes,
etc), not the directory entry. To find the information associated with a
file, one must traverse the directory files to find the directory entry
associated with a file, then load the inode to find the metadata for
that file. ext4 appears to cheat (for performance reasons) a little bit
by storing a copy of the file type (normally stored in the inode) in the
directory entry. (Compare all this to FAT, which stores all the file
information directly in the directory entry, but does not support hard
links and is in general more seek-happy than ext4 due to its simpler
block allocator and extensive use of linked lists.)

The inode table is a linear array of ``struct ext4_inode``. The table is
sized to have enough blocks to store at least
``sb.s_inode_size * sb.s_inodes_per_group`` bytes. The number of the
block group containing an inode can be calculated as
``(inode_number - 1) / sb.s_inodes_per_group``, and the offset into the
group's table is ``(inode_number - 1) % sb.s_inodes_per_group``. There
is no inode 0.

The inode checksum is calculated against the FS UUID, the inode number,
and the inode structure itself.

The inode table entry is laid out in ``struct ext4_inode``.

`struct ext4_inode` 필드

30-174

`struct ext4_inode`의 앞 128바이트는 ext2 시절부터 이어진 기본 inode 형식이고, `0x80` 이후는 ext4의 확장 inode 필드입니다.

`i_mode`는 파일 종류와 권한을 함께 저장합니다. `i_uid`와 `i_gid`는 소유자 ID의 하위 16비트이며 상위 비트는 OS별 `i_osd2`에 있습니다. `i_size_lo`와 `i_size_high`를 결합해 파일 또는 디렉터리 크기를 표현합니다.

`i_atime`, `i_ctime`, `i_mtime`, `i_dtime`은 기본 timestamp입니다. `EXT4_EA_INODE_FL`이 설정된 EA inode에서는 각각 xattr checksum, 참조 횟수 하위 32비트, 소유 inode number로 의미가 바뀝니다.

`i_links_count`는 hard link 수입니다. ext4의 일반 한도는 65,000이며 디렉터리의 `.`과 하위 디렉터리의 `..`도 포함하므로 하위 디렉터리는 최대 64,998개입니다. `DIR_NLINK` 기능을 켜면 이 필드를 1로 설정해 실제 link 수를 모른다는 뜻으로 사용하여 한도를 넘길 수 있습니다.

`i_blocks_lo`는 디스크 사용량을 나타냅니다. `huge_file` 기능과 inode의 `EXT4_HUGE_FILE_FL` 조합에 따라 512-byte block 수 또는 filesystem block 수로 해석하며 `i_blocks_hi`와 함께 사용합니다.

`i_block[EXT4_N_BLOCKS=15]` 60바이트에는 block map 또는 extent tree가 들어갑니다. `i_file_acl_lo`는 extended attribute block 위치의 하위 32비트이고, `i_size_high / i_dir_acl`은 크기의 상위 32비트입니다. `i_obso_faddr`는 더 이상 쓰지 않는 fragment address입니다.

확장 영역의 `i_extra_isize`는 inode 전체 크기에서 128을 뺀 값, 즉 이 필드 자체를 포함해 원래 ext2 inode 뒤에 실제로 사용하는 확장 필드의 크기입니다. `i_checksum_hi`는 inode checksum의 상위 16비트입니다.

`i_ctime_extra`, `i_mtime_extra`, `i_atime_extra`, `i_crtime_extra`는 초 단위 필드를 확장하고 sub-second 정밀도를 제공합니다. `i_crtime`은 파일 생성 시각, `i_version_hi`는 version number의 상위 32비트, `i_projid`는 project ID입니다.

`struct ext4_inode` 디스크 배치
OffsetType/SizeName설명
`0x0``__le16``i_mode`파일 종류와 mode; `i_mode` 표 참조
`0x2``__le16``i_uid`owner UID 하위 16비트
`0x4``__le32``i_size_lo`크기(byte)의 하위 32비트
`0x8``__le32``i_atime`마지막 접근 시각; EA inode에서는 xattr 값 checksum
`0xC``__le32``i_ctime`inode 변경 시각; EA inode에서는 참조 횟수 하위 32비트
`0x10``__le32``i_mtime`데이터 변경 시각; EA inode에서는 소유 inode number
`0x14``__le32``i_dtime`삭제 시각
`0x18``__le16``i_gid`GID 하위 16비트
`0x1A``__le16``i_links_count`hard link 수; `DIR_NLINK`에서는 1이 unknown을 뜻함
`0x1C``__le32``i_blocks_lo`block count 하위 32비트
`0x20``__le32``i_flags`inode flag 조합
`0x24`4 bytes`i_osd1`creator OS별 필드
`0x28`60 bytes`i_block[EXT4_N_BLOCKS=15]`block map 또는 extent tree
`0x64``__le32``i_generation`NFS용 file version
`0x68``__le32``i_file_acl_lo`extended attribute block 하위 32비트
`0x6C``__le32``i_size_high / i_dir_acl`파일·디렉터리 크기 상위 32비트
`0x70``__le32``i_obso_faddr`폐기된 fragment address
`0x74`12 bytes`i_osd2`creator OS별 필드
`0x80``__le16``i_extra_isize`128바이트 뒤에서 실제 사용하는 확장 크기
`0x82``__le16``i_checksum_hi`inode checksum 상위 16비트
`0x84``__le32``i_ctime_extra`change time 확장 및 sub-second 비트
`0x88``__le32``i_mtime_extra`modification time 확장 및 sub-second 비트
`0x8C``__le32``i_atime_extra`access time 확장 및 sub-second 비트
`0x90``__le32``i_crtime`파일 생성 시각의 초 부분
`0x94``__le32``i_crtime_extra`creation time 확장 및 sub-second 비트
`0x98``__le32``i_version_hi`version number 상위 32비트
`0x9C``__le32``i_projid`project ID

기본 128바이트와 ext4 확장 필드를 offset 순서대로 정리한 표입니다.


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

   * - Offset
     - Size
     - Name
     - Description
   * - 0x0
     - __le16
     - i_mode
     - File mode. See the table i_mode_ below.
   * - 0x2
     - __le16
     - i_uid
     - Lower 16-bits of Owner UID.
   * - 0x4
     - __le32
     - i_size_lo
     - Lower 32-bits of size in bytes.
   * - 0x8
     - __le32
     - i_atime
     - Last access time, in seconds since the epoch. However, if the EA_INODE
       inode flag is set, this inode stores an extended attribute value and
       this field contains the checksum of the value.
   * - 0xC
     - __le32
     - i_ctime
     - Last inode change time, in seconds since the epoch. However, if the
       EA_INODE inode flag is set, this inode stores an extended attribute
       value and this field contains the lower 32 bits of the attribute value's
       reference count.
   * - 0x10
     - __le32
     - i_mtime
     - Last data modification time, in seconds since the epoch. However, if the
       EA_INODE inode flag is set, this inode stores an extended attribute
       value and this field contains the number of the inode that owns the
       extended attribute.
   * - 0x14
     - __le32
     - i_dtime
     - Deletion Time, in seconds since the epoch.
   * - 0x18
     - __le16
     - i_gid
     - Lower 16-bits of GID.
   * - 0x1A
     - __le16
     - i_links_count
     - Hard link count. Normally, ext4 does not permit an inode to have more
       than 65,000 hard links. This applies to files as well as directories,
       which means that there cannot be more than 64,998 subdirectories in a
       directory (each subdirectory's '..' entry counts as a hard link, as does
       the '.' entry in the directory itself). With the DIR_NLINK feature
       enabled, ext4 supports more than 64,998 subdirectories by setting this
       field to 1 to indicate that the number of hard links is not known.
   * - 0x1C
     - __le32
     - i_blocks_lo
     - Lower 32-bits of “block” count. If the huge_file feature flag is not
       set on the filesystem, the file consumes ``i_blocks_lo`` 512-byte blocks
       on disk. If huge_file is set and EXT4_HUGE_FILE_FL is NOT set in
       ``inode.i_flags``, then the file consumes ``i_blocks_lo + (i_blocks_hi
       << 32)`` 512-byte blocks on disk. If huge_file is set and
       EXT4_HUGE_FILE_FL IS set in ``inode.i_flags``, then this file
       consumes (``i_blocks_lo + i_blocks_hi`` << 32) filesystem blocks on
       disk.
   * - 0x20
     - __le32
     - i_flags
     - Inode flags. See the table i_flags_ below.
   * - 0x24
     - 4 bytes
     - i_osd1
     - See the table i_osd1_ for more details.
   * - 0x28
     - 60 bytes
     - i_block[EXT4_N_BLOCKS=15]
     - Block map or extent tree. See the section “The Contents of inode.i_block”.
   * - 0x64
     - __le32
     - i_generation
     - File version (for NFS).
   * - 0x68
     - __le32
     - i_file_acl_lo
     - Lower 32-bits of extended attribute block. ACLs are of course one of
       many possible extended attributes; I think the name of this field is a
       result of the first use of extended attributes being for ACLs.
   * - 0x6C
     - __le32
     - i_size_high / i_dir_acl
     - Upper 32-bits of file/directory size. In ext2/3 this field was named
       i_dir_acl, though it was usually set to zero and never used.
   * - 0x70
     - __le32
     - i_obso_faddr
     - (Obsolete) fragment address.
   * - 0x74
     - 12 bytes
     - i_osd2
     - See the table i_osd2_ for more details.
   * - 0x80
     - __le16
     - i_extra_isize
     - Size of this inode - 128. Alternately, the size of the extended inode
       fields beyond the original ext2 inode, including this field.
   * - 0x82
     - __le16
     - i_checksum_hi
     - Upper 16-bits of the inode checksum.
   * - 0x84
     - __le32
     - i_ctime_extra
     - Extra change time bits. This provides sub-second precision. See Inode
       Timestamps section.
   * - 0x88
     - __le32
     - i_mtime_extra
     - Extra modification time bits. This provides sub-second precision.
   * - 0x8C
     - __le32
     - i_atime_extra
     - Extra access time bits. This provides sub-second precision.
   * - 0x90
     - __le32
     - i_crtime
     - File creation time, in seconds since the epoch.
   * - 0x94
     - __le32
     - i_crtime_extra
     - Extra file creation time bits. This provides sub-second precision.
   * - 0x98
     - __le32
     - i_version_hi
     - Upper 32-bits for version number.
   * - 0x9C
     - __le32
     - i_projid
     - Project ID.

`i_mode` 권한과 파일 종류

175-225

`i_mode`는 접근 권한, sticky/set-ID bit, 파일 종류를 조합한 값입니다. 권한 비트는 owner, group, others 각각의 read, write, execute 권한을 표현합니다.

파일 종류 비트는 서로 배타적이며 FIFO, character device, directory, block device, regular file, symbolic link, socket 가운데 하나를 선택합니다.

`i_mode` 값
ValueSymbol설명
`0x1``S_IXOTH`others execute
`0x2``S_IWOTH`others write
`0x4``S_IROTH`others read
`0x8``S_IXGRP`group execute
`0x10``S_IWGRP`group write
`0x20``S_IRGRP`group read
`0x40``S_IXUSR`owner execute
`0x80``S_IWUSR`owner write
`0x100``S_IRUSR`owner read
`0x200``S_ISVTX`sticky bit
`0x400``S_ISGID`set GID
`0x800``S_ISUID`set UID
`0x1000``S_IFIFO`FIFO
`0x2000``S_IFCHR`character device
`0x4000``S_IFDIR`directory
`0x6000``S_IFBLK`block device
`0x8000``S_IFREG`regular file
`0xA000``S_IFLNK`symbolic link
`0xC000``S_IFSOCK`socket

권한·특수 비트와 서로 배타적인 파일 종류입니다.

.. _i_mode:

The ``i_mode`` value is a combination of the following flags:

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

   * - Value
     - Description
   * - 0x1
     - S_IXOTH (Others may execute)
   * - 0x2
     - S_IWOTH (Others may write)
   * - 0x4
     - S_IROTH (Others may read)
   * - 0x8
     - S_IXGRP (Group members may execute)
   * - 0x10
     - S_IWGRP (Group members may write)
   * - 0x20
     - S_IRGRP (Group members may read)
   * - 0x40
     - S_IXUSR (Owner may execute)
   * - 0x80
     - S_IWUSR (Owner may write)
   * - 0x100
     - S_IRUSR (Owner may read)
   * - 0x200
     - S_ISVTX (Sticky bit)
   * - 0x400
     - S_ISGID (Set GID)
   * - 0x800
     - S_ISUID (Set UID)
   * -
     - These are mutually-exclusive file types:
   * - 0x1000
     - S_IFIFO (FIFO)
   * - 0x2000
     - S_IFCHR (Character device)
   * - 0x4000
     - S_IFDIR (Directory)
   * - 0x6000
     - S_IFBLK (Block device)
   * - 0x8000
     - S_IFREG (Regular file)
   * - 0xA000
     - S_IFLNK (Symbolic link)
   * - 0xC000
     - S_IFSOCK (Socket)

`i_flags` inode 상태

226-312

`i_flags`는 파일의 쓰기 방식, 변경 가능성, 압축·암호화·인덱싱·extent·verity·inline data 같은 동작과 형식을 제어하는 비트 조합입니다.

일부 오래된 압축, 삭제 복구, snapshot 플래그는 구현되지 않았거나 mainline에 없습니다. `EXT4_ECOMPR_FL`로 쓰인 적이 없는 `0x800` 비트는 현재 `EXT4_ENCRYPT_FL`입니다.

user-visible mask는 `0x705BDFFF`, user-modifiable mask는 `0x604BC0FF`입니다. `EXT4_JOURNAL_DATA_FL`과 `EXT4_EXTENTS_FL`은 `setattr`로 설정할 수 있지만 커널이 특별히 처리해야 하므로 `EXT4_FL_USER_MODIFIABLE` mask에 포함되지 않고, `i_flags`에 직접 저장하는 flag 집합에서도 가려집니다.

`i_flags` 값
ValueSymbol설명
`0x1``EXT4_SECRM_FL`secure deletion 필요; 미구현
`0x2``EXT4_UNRM_FL`undelete를 위해 보존; 미구현
`0x4``EXT4_COMPR_FL`압축 파일; 실질적으로 미구현
`0x8``EXT4_SYNC_FL`모든 write를 synchronous로 수행
`0x10``EXT4_IMMUTABLE_FL`immutable file
`0x20``EXT4_APPEND_FL`append만 허용
`0x40``EXT4_NODUMP_FL``dump(1)` 대상에서 제외
`0x80``EXT4_NOATIME_FL`access time을 갱신하지 않음
`0x100``EXT4_DIRTY_FL`dirty compressed file; 미사용
`0x200``EXT4_COMPRBLK_FL`compressed cluster 보유; 미사용
`0x400``EXT4_NOCOMPR_FL`압축 금지; 미사용
`0x800``EXT4_ENCRYPT_FL`encrypted inode
`0x1000``EXT4_INDEX_FL`hashed directory index
`0x2000``EXT4_IMAGIC_FL`AFS magic directory
`0x4000``EXT4_JOURNAL_DATA_FL`file data를 항상 journal 경유로 기록
`0x8000``EXT4_NOTAIL_FL`file tail 병합 금지; ext4 미사용
`0x10000``EXT4_DIRSYNC_FL`directory entry data를 synchronous로 기록
`0x20000``EXT4_TOPDIR_FL`directory hierarchy의 top
`0x40000``EXT4_HUGE_FILE_FL`huge file
`0x80000``EXT4_EXTENTS_FL`extent 사용
`0x100000``EXT4_VERITY_FL`verity protected file
`0x200000``EXT4_EA_INODE_FL`data block에 큰 xattr 값 저장
`0x400000``EXT4_EOFBLOCKS_FL`EOF 뒤에 block 할당; 폐기됨
`0x01000000``EXT4_SNAPFILE_FL`snapshot inode; mainline 아님
`0x04000000``EXT4_SNAPFILE_DELETED_FL`snapshot 삭제 중; mainline 아님
`0x08000000``EXT4_SNAPFILE_SHRUNK_FL`snapshot shrink 완료; mainline 아님
`0x10000000``EXT4_INLINE_DATA_FL`inline data 보유
`0x20000000``EXT4_PROJINHERIT_FL`child가 같은 project ID 상속
`0x80000000``EXT4_RESERVED_FL`ext4 library용 예약
`0x705BDFFF`user-visible mask사용자에게 보이는 flag
`0x604BC0FF`user-modifiable mask사용자가 직접 변경 가능한 flag

inode의 형식과 동작을 나타내는 개별 및 집계 flag입니다.

.. _i_flags:

The ``i_flags`` field is a combination of these values:

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

   * - Value
     - Description
   * - 0x1
     - This file requires secure deletion (EXT4_SECRM_FL). (not implemented)
   * - 0x2
     - This file should be preserved, should undeletion be desired
       (EXT4_UNRM_FL). (not implemented)
   * - 0x4
     - File is compressed (EXT4_COMPR_FL). (not really implemented)
   * - 0x8
     - All writes to the file must be synchronous (EXT4_SYNC_FL).
   * - 0x10
     - File is immutable (EXT4_IMMUTABLE_FL).
   * - 0x20
     - File can only be appended (EXT4_APPEND_FL).
   * - 0x40
     - The dump(1) utility should not dump this file (EXT4_NODUMP_FL).
   * - 0x80
     - Do not update access time (EXT4_NOATIME_FL).
   * - 0x100
     - Dirty compressed file (EXT4_DIRTY_FL). (not used)
   * - 0x200
     - File has one or more compressed clusters (EXT4_COMPRBLK_FL). (not used)
   * - 0x400
     - Do not compress file (EXT4_NOCOMPR_FL). (not used)
   * - 0x800
     - Encrypted inode (EXT4_ENCRYPT_FL). This bit value previously was
       EXT4_ECOMPR_FL (compression error), which was never used.
   * - 0x1000
     - Directory has hashed indexes (EXT4_INDEX_FL).
   * - 0x2000
     - AFS magic directory (EXT4_IMAGIC_FL).
   * - 0x4000
     - File data must always be written through the journal
       (EXT4_JOURNAL_DATA_FL).
   * - 0x8000
     - File tail should not be merged (EXT4_NOTAIL_FL). (not used by ext4)
   * - 0x10000
     - All directory entry data should be written synchronously (see
       ``dirsync``) (EXT4_DIRSYNC_FL).
   * - 0x20000
     - Top of directory hierarchy (EXT4_TOPDIR_FL).
   * - 0x40000
     - This is a huge file (EXT4_HUGE_FILE_FL).
   * - 0x80000
     - Inode uses extents (EXT4_EXTENTS_FL).
   * - 0x100000
     - Verity protected file (EXT4_VERITY_FL).
   * - 0x200000
     - Inode stores a large extended attribute value in its data blocks
       (EXT4_EA_INODE_FL).
   * - 0x400000
     - This file has blocks allocated past EOF (EXT4_EOFBLOCKS_FL).
       (deprecated)
   * - 0x01000000
     - Inode is a snapshot (``EXT4_SNAPFILE_FL``). (not in mainline)
   * - 0x04000000
     - Snapshot is being deleted (``EXT4_SNAPFILE_DELETED_FL``). (not in
       mainline)
   * - 0x08000000
     - Snapshot shrink has completed (``EXT4_SNAPFILE_SHRUNK_FL``). (not in
       mainline)
   * - 0x10000000
     - Inode has inline data (EXT4_INLINE_DATA_FL).
   * - 0x20000000
     - Create children with the same project ID (EXT4_PROJINHERIT_FL).
   * - 0x80000000
     - Reserved for ext4 library (EXT4_RESERVED_FL).
   * -
     - Aggregate flags:
   * - 0x705BDFFF
     - User-visible flags.
   * - 0x604BC0FF
     - User-modifiable flags. Note that while EXT4_JOURNAL_DATA_FL and
       EXT4_EXTENTS_FL can be set with setattr, they are not in the kernel's
       EXT4_FL_USER_MODIFIABLE mask, since it needs to handle the setting of
       these flags in a special manner and they are masked out of the set of
       flags that are saved directly to i_flags.

`i_osd1` creator OS별 의미

313-363

4바이트 `i_osd1` 필드는 파일시스템을 만든 운영체제에 따라 의미가 다릅니다.

Linux의 `l_i_version`은 inode version입니다. `EXT4_EA_INODE_FL`이 설정된 inode에서는 큰 확장 속성 값의 참조 횟수 상위 32비트를 저장합니다.

Hurd는 `h_i_translator`, Masix는 `m_i_reserved`로 정의하지만 문서에는 두 필드의 의미가 확정되지 않은 `??`로 표시되어 있습니다.

`i_osd1`
CreatorOffsetTypeName설명
Linux`0x0``__le32``l_i_version`inode version; EA inode에서는 참조 횟수 상위 32비트
Hurd`0x0``__le32``h_i_translator`문서상 의미 미상
Masix`0x0``__le32``m_i_reserved`예약; 문서상 의미 미상

creator별 4바이트 필드 해석입니다.

.. _i_osd1:

The ``osd1`` field has multiple meanings depending on the creator:

Linux:

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

   * - Offset
     - Size
     - Name
     - Description
   * - 0x0
     - __le32
     - l_i_version
     - Inode version. However, if the EA_INODE inode flag is set, this inode
       stores an extended attribute value and this field contains the upper 32
       bits of the attribute value's reference count.

Hurd:

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

   * - Offset
     - Size
     - Name
     - Description
   * - 0x0
     - __le32
     - h_i_translator
     - ??

Masix:

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

   * - Offset
     - Size
     - Name
     - Description
   * - 0x0
     - __le32
     - m_i_reserved
     - ??

`i_osd2` creator OS별 의미

364-459

12바이트 `i_osd2`도 filesystem creator에 따라 배치가 달라집니다.

Linux 배치는 block count, extended attribute block, UID, GID, inode checksum의 상위 또는 하위 비트를 보충하고 마지막 2바이트를 예약합니다.

Linux `i_osd2`
OffsetTypeName설명
`0x0``__le16``l_i_blocks_high`block count 상위 16비트
`0x2``__le16``l_i_file_acl_high`extended attribute block 상위 16비트
`0x4``__le16``l_i_uid_high`owner UID 상위 16비트
`0x6``__le16``l_i_gid_high`GID 상위 16비트
`0x8``__le16``l_i_checksum_lo`inode checksum 하위 16비트
`0xA``__le16``l_i_reserved`사용하지 않음

Linux가 사용하는 12바이트 확장 필드입니다.

Hurd 배치는 file mode, UID, GID의 상위 비트와 author code를 보관합니다. `h_i_reserved1`의 의미는 문서에서 확정되지 않았습니다.

Hurd `i_osd2`
OffsetTypeName설명
`0x0``__le16``h_i_reserved1`문서상 의미 미상
`0x2``__u16``h_i_mode_high`file mode 상위 16비트
`0x4``__le16``h_i_uid_high`owner UID 상위 16비트
`0x6``__le16``h_i_gid_high`GID 상위 16비트
`0x8``__u32``h_i_author`author code로 추정

Hurd가 사용하는 12바이트 확장 필드입니다.

Masix 배치는 extended attribute block의 상위 16비트를 두고 나머지를 예약합니다. 원문 표는 offset `0x0`의 이름을 `h_i_reserved1`로 기록하고 있습니다.

Masix `i_osd2`
OffsetTypeName설명
`0x0``__le16``h_i_reserved1`문서상 의미 미상
`0x2``__u16``m_i_file_acl_high`extended attribute block 상위 16비트
`0x4``__u32``m_i_reserved2[2]`예약; 문서상 의미 미상

Masix가 사용하는 12바이트 확장 필드입니다.

.. _i_osd2:

The ``osd2`` field has multiple meanings depending on the filesystem creator:

Linux:

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

   * - Offset
     - Size
     - Name
     - Description
   * - 0x0
     - __le16
     - l_i_blocks_high
     - Upper 16-bits of the block count. Please see the note attached to
       i_blocks_lo.
   * - 0x2
     - __le16
     - l_i_file_acl_high
     - Upper 16-bits of the extended attribute block (historically, the file
       ACL location). See the Extended Attributes section below.
   * - 0x4
     - __le16
     - l_i_uid_high
     - Upper 16-bits of the Owner UID.
   * - 0x6
     - __le16
     - l_i_gid_high
     - Upper 16-bits of the GID.
   * - 0x8
     - __le16
     - l_i_checksum_lo
     - Lower 16-bits of the inode checksum.
   * - 0xA
     - __le16
     - l_i_reserved
     - Unused.

Hurd:

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

   * - Offset
     - Size
     - Name
     - Description
   * - 0x0
     - __le16
     - h_i_reserved1
     - ??
   * - 0x2
     - __u16
     - h_i_mode_high
     - Upper 16-bits of the file mode.
   * - 0x4
     - __le16
     - h_i_uid_high
     - Upper 16-bits of the Owner UID.
   * - 0x6
     - __le16
     - h_i_gid_high
     - Upper 16-bits of the GID.
   * - 0x8
     - __u32
     - h_i_author
     - Author code?

Masix:

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

   * - Offset
     - Size
     - Name
     - Description
   * - 0x0
     - __le16
     - h_i_reserved1
     - ??
   * - 0x2
     - __u16
     - m_i_file_acl_high
     - Upper 16-bits of the extended attribute block (historically, the file
       ACL location).
   * - 0x4
     - __u32
     - m_i_reserved2[2]
     - ??

inode record 크기

460-480

ext2와 ext3의 inode structure와 디스크 record는 `EXT2_GOOD_OLD_INODE_SIZE`인 128바이트로 고정되어 있었습니다.

ext4부터는 format 시 파일시스템의 모든 inode에 대해 더 큰 on-disk inode를 할당할 수 있습니다. record 전체 크기는 superblock의 `s_inode_size`에 기록합니다.

각 inode의 `i_extra_isize`는 원래 128바이트 ext2 inode 뒤에서 `struct ext4_inode`가 실제로 사용하는 바이트 수입니다. 새 커널이 structure를 확장해도 모든 기존 on-disk inode를 즉시 upgrade하지 않도록 하며, 128바이트 뒤 필드에 접근하기 전에 해당 필드가 `i_extra_isize` 범위에 있는지 확인해야 합니다.

기본 ext4 inode record는 256바이트입니다. 2019년 8월 기준 inode structure는 160바이트이고 `i_extra_isize = 32`입니다. structure 끝과 record 끝 사이의 여분에는 extended attribute를 저장할 수 있습니다.

inode record는 filesystem block size만큼 클 수 있지만 효율적이지는 않습니다.

확장 inode 공간 사용
superblock의 `s_inode_size`로 record 전체 크기 확인기본 128 bytes는 ext2 호환 필드로 해석`i_extra_isize`로 확장 structure의 실제 사용 범위 확인범위 안의 ext4 확장 필드만 접근structure 끝과 record 끝 사이를 extended attribute 공간으로 사용

128바이트 호환 영역 뒤의 record를 안전하게 해석하는 순서입니다.

Inode Size
~~~~~~~~~~

In ext2 and ext3, the inode structure size was fixed at 128 bytes
(``EXT2_GOOD_OLD_INODE_SIZE``) and each inode had a disk record size of
128 bytes. Starting with ext4, it is possible to allocate a larger
on-disk inode at format time for all inodes in the filesystem to provide
space beyond the end of the original ext2 inode. The on-disk inode
record size is recorded in the superblock as ``s_inode_size``. The
number of bytes actually used by struct ext4_inode beyond the original
128-byte ext2 inode is recorded in the ``i_extra_isize`` field for each
inode, which allows struct ext4_inode to grow for a new kernel without
having to upgrade all of the on-disk inodes. Access to fields beyond
EXT2_GOOD_OLD_INODE_SIZE should be verified to be within
``i_extra_isize``. By default, ext4 inode records are 256 bytes, and (as
of August 2019) the inode structure is 160 bytes
(``i_extra_isize = 32``). The extra space between the end of the inode
structure and the end of the inode record can be used to store extended
attributes. Each inode record can be as large as the filesystem block
size, though this is not terribly efficient.

inode 위치 계산

481-492

각 block group에는 `sb->s_inodes_per_group`개의 inode가 있습니다. inode 0은 존재하지 않으므로 inode number에서 1을 뺀 뒤 group과 index를 계산합니다.

block group은 `bg = (inode_num - 1) / sb->s_inodes_per_group`, group의 inode table 안 index는 `index = (inode_num - 1) % sb->s_inodes_per_group`입니다. inode table 안 byte offset은 `offset = index * sb->s_inode_size`입니다.

inode 위치 계산식
결과계산식
Block group`bg = (inode_num - 1) / sb->s_inodes_per_group`
Table index`index = (inode_num - 1) % sb->s_inodes_per_group`
Byte offset`offset = index * sb->s_inode_size`

inode number를 block group과 byte offset으로 바꾸는 세 단계입니다.

Finding an Inode
~~~~~~~~~~~~~~~~

Each block group contains ``sb->s_inodes_per_group`` inodes. Because
inode 0 is defined not to exist, this formula can be used to find the
block group that an inode lives in:
``bg = (inode_num - 1) / sb->s_inodes_per_group``. The particular inode
can be found within the block group's inode table at
``index = (inode_num - 1) % sb->s_inodes_per_group``. To get the byte
address within the inode table, use
``offset = index * sb->s_inode_size``.

inode timestamp 구성

493-518

inode structure의 하위 128바이트에는 inode change time `ctime`, access time `atime`, data modification time `mtime`, deletion time `dtime` 네 timestamp가 기록됩니다.

네 필드는 Unix epoch인 `1970-01-01 00:00:00 GMT` 이후의 초를 나타내는 signed 32-bit integer이므로 2038년 1월에 overflow합니다.

filesystem에 `orphan_file` 기능이 없으면 어느 directory에서도 link되지 않았지만 여전히 열려 있는 orphan inode의 `dtime`을 orphan list 연결에 재사용합니다. superblock의 `s_last_orphan`이 첫 inode를 가리키고, 각 `dtime`은 다음 orphan inode number 또는 목록 끝의 0입니다.

`sb->s_inode_size > 128`이고 `i_inode_extra`가 해당 `i_[cma]time_extra` 필드를 포함할 만큼 크면 ctime, atime, mtime은 64비트로 확장됩니다. extra 32비트의 하위 2비트는 seconds field를 34비트로 넓히고, 상위 30비트는 nanosecond 정밀도를 제공합니다. 이 형식은 2446년 5월까지 overflow하지 않습니다.

`dtime`은 확장되지 않았습니다. 다섯 번째 timestamp인 creation time `crtime`은 64비트이며 64비트 `[cma]time`과 같은 방식으로 decode합니다. `crtime`과 `dtime`은 일반 `stat()` interface에서 볼 수 없지만 `debugfs`가 보고합니다.

inode timestamp
Timestamp기본 필드Extra비고
Change`i_ctime``i_ctime_extra`34-bit seconds + 30-bit nanoseconds
Access`i_atime``i_atime_extra`34-bit seconds + 30-bit nanoseconds
Modification`i_mtime``i_mtime_extra`34-bit seconds + 30-bit nanoseconds
Deletion`i_dtime`없음orphan list에 재사용 가능
Creation`i_crtime``i_crtime_extra``stat()` 미노출, `debugfs`에서 확인

기본 필드와 extra 필드, 접근 경로를 정리합니다.

Inode Timestamps
~~~~~~~~~~~~~~~~

Four timestamps are recorded in the lower 128 bytes of the inode
structure -- inode change time (ctime), access time (atime), data
modification time (mtime), and deletion time (dtime). The four fields
are 32-bit signed integers that represent seconds since the Unix epoch
(1970-01-01 00:00:00 GMT), which means that the fields will overflow in
January 2038. If the filesystem does not have orphan_file feature, inodes
that are not linked from any directory but are still open (orphan inodes) have
the dtime field overloaded for use with the orphan list. The superblock field
``s_last_orphan`` points to the first inode in the orphan list; dtime is then
the number of the next orphaned inode, or zero if there are no more orphans.

If the inode structure size ``sb->s_inode_size`` is larger than 128
bytes and the ``i_inode_extra`` field is large enough to encompass the
respective ``i_[cma]time_extra`` field, the ctime, atime, and mtime
inode fields are widened to 64 bits. Within this “extra” 32-bit field,
the lower two bits are used to extend the 32-bit seconds field to be 34
bit wide; the upper 30 bits are used to provide nanosecond timestamp
accuracy. Therefore, timestamps should not overflow until May 2446.
dtime was not widened. There is also a fifth timestamp to record inode
creation time (crtime); this field is 64-bits wide and decoded in the
same manner as 64-bit [cma]time. Neither crtime nor dtime are accessible
through the regular stat() interface, though debugfs will report them.

64비트 timestamp 해석

519-578

64비트 seconds 값은 signed 32-bit time 값에 `(2^32 * extra epoch bits)`를 더해 계산합니다.

extra epoch bits는 두 비트지만 signed 32-bit time의 최상위 비트와 함께 해석하여 1901년부터 2446년까지의 구간을 표현합니다. 결과적으로 양수 시간 값이 음수 값보다 사실상 일곱 배 많아지는 다소 특이한 인코딩입니다.

ext4 timestamp epoch decode
Extra bits32-bit MSBAdjustmentDecoded `tv_sec`유효 시간 범위
`0 0``1``0``-0x80000000 - -0x00000001`1901-12-13 ~ 1969-12-31
`0 0``0``0``0x000000000 - 0x07fffffff`1970-01-01 ~ 2038-01-19
`0 1``1``0x100000000``0x080000000 - 0x0ffffffff`2038-01-19 ~ 2106-02-07
`0 1``0``0x100000000``0x100000000 - 0x17fffffff`2106-02-07 ~ 2174-02-25
`1 0``1``0x200000000``0x180000000 - 0x1ffffffff`2174-02-25 ~ 2242-03-16
`1 0``0``0x200000000``0x200000000 - 0x27fffffff`2242-03-16 ~ 2310-04-04
`1 1``1``0x300000000``0x280000000 - 0x2ffffffff`2310-04-04 ~ 2378-04-22
`1 1``0``0x300000000``0x300000000 - 0x37fffffff`2378-04-22 ~ 2446-05-10

extra epoch bits와 32비트 time의 MSB 조합별 64비트 범위입니다.

2038년 이후 날짜의 encode/decode에는 오랫동안 bug가 있었습니다. 문서 기준 kernel 3.12와 e2fsprogs 1.42.8에서도 수정되지 않은 것으로 보이며, 64-bit kernel은 1901년부터 1970년 사이 날짜에 extra epoch bits `1,1`을 잘못 사용합니다.

향후 kernel이 수정되면 e2fsck가 이 상태를 바로잡을 예정이며, 2310년 이전에 e2fsck를 실행한다는 전제가 붙습니다.

We use the 32-bit signed time value plus (2^32 * (extra epoch bits)).
In other words:

.. list-table::
   :widths: 20 20 20 20 20
   :header-rows: 1

   * - Extra epoch bits
     - MSB of 32-bit time
     - Adjustment for signed 32-bit to 64-bit tv_sec
     - Decoded 64-bit tv_sec
     - valid time range
   * - 0 0
     - 1
     - 0
     - ``-0x80000000 - -0x00000001``
     - 1901-12-13 to 1969-12-31
   * - 0 0
     - 0
     - 0
     - ``0x000000000 - 0x07fffffff``
     - 1970-01-01 to 2038-01-19
   * - 0 1
     - 1
     - 0x100000000
     - ``0x080000000 - 0x0ffffffff``
     - 2038-01-19 to 2106-02-07
   * - 0 1
     - 0
     - 0x100000000
     - ``0x100000000 - 0x17fffffff``
     - 2106-02-07 to 2174-02-25
   * - 1 0
     - 1
     - 0x200000000
     - ``0x180000000 - 0x1ffffffff``
     - 2174-02-25 to 2242-03-16
   * - 1 0
     - 0
     - 0x200000000
     - ``0x200000000 - 0x27fffffff``
     - 2242-03-16 to 2310-04-04
   * - 1 1
     - 1
     - 0x300000000
     - ``0x280000000 - 0x2ffffffff``
     - 2310-04-04 to 2378-04-22
   * - 1 1
     - 0
     - 0x300000000
     - ``0x300000000 - 0x37fffffff``
     - 2378-04-22 to 2446-05-10

This is a somewhat odd encoding since there are effectively seven times
as many positive values as negative values. There have also been
long-standing bugs decoding and encoding dates beyond 2038, which don't
seem to be fixed as of kernel 3.12 and e2fsprogs 1.42.8. 64-bit kernels
incorrectly use the extra epoch bits 1,1 for dates between 1901 and
1970. At some point the kernel will be fixed and e2fsck will fix this
situation, assuming that it is run before 2310.