3. 全域性結構

檔案系統被分割成多個塊組,每個塊組在固定位置都有靜態元資料。

3.1. 超級塊

超級塊記錄了有關封閉檔案系統的各種資訊,例如塊計數、inode 計數、支援的功能、維護資訊等等。

如果設定了 sparse_super 特性標誌,則超級塊和組描述符的冗餘副本僅儲存在組號為 0 或 3、5 或 7 的冪的組中。如果未設定該標誌,則冗餘副本儲存在所有組中。

超級塊校驗和是針對超級塊結構計算的,其中包括 FS UUID。

ext4 超級塊在 struct ext4_super_block 中的佈局如下

偏移量

大小

名稱

描述

0x0

__le32

s_inodes_count

inode 總數。

0x4

__le32

s_blocks_count_lo

塊總數。

0x8

__le32

s_r_blocks_count_lo

只有超級使用者才能分配此數量的塊。

0xC

__le32

s_free_blocks_count_lo

空閒塊數。

0x10

__le32

s_free_inodes_count

空閒 inode 數。

0x14

__le32

s_first_data_block

第一個資料塊。對於 1k 塊檔案系統,此值必須至少為 1,對於所有其他塊大小,通常為 0。

0x18

__le32

s_log_block_size

塊大小為 2 ^ (10 + s_log_block_size)。

0x1C

__le32

s_log_cluster_size

如果啟用 bigalloc,則簇大小為 2 ^ (10 + s_log_cluster_size) 塊。否則,s_log_cluster_size 必須等於 s_log_block_size。

0x20

__le32

s_blocks_per_group

每個組的塊數。

0x24

__le32

s_clusters_per_group

每個組的簇數(如果啟用了 bigalloc)。否則,s_clusters_per_group 必須等於 s_blocks_per_group。

0x28

__le32

s_inodes_per_group

每個組的 inode 數。

0x2C

__le32

s_mtime

掛載時間,自 epoch 以來的秒數。

0x30

__le32

s_wtime

寫入時間,自 epoch 以來的秒數。

0x34

__le16

s_mnt_count

自上次 fsck 以來的掛載次數。

0x36

__le16

s_max_mnt_count

超出該掛載次數後需要進行 fsck。

0x38

__le16

s_magic

魔術簽名,0xEF53

0x3A

__le16

s_state

檔案系統狀態。有關更多資訊,請參見 super_state

0x3C

__le16

s_errors

檢測到錯誤時的行為。有關更多資訊,請參見 super_errors

0x3E

__le16

s_minor_rev_level

次修訂級別。

0x40

__le32

s_lastcheck

上次檢查的時間,自 epoch 以來的秒數。

0x44

__le32

s_checkinterval

檢查之間的最大時間,以秒為單位。

0x48

__le32

s_creator_os

建立者 OS。有關更多資訊,請參見表 super_creator

0x4C

__le32

s_rev_level

修訂級別。有關更多資訊,請參見表 super_revision

0x50

__le16

s_def_resuid

保留塊的預設 uid。

0x52

__le16

s_def_resgid

保留塊的預設 gid。

這些欄位僅適用於 EXT4_DYNAMIC_REV 超級塊。

注意:相容特性集和不相容特性集之間的區別在於,如果核心不知道不相容特性集中設定的位,則應拒絕掛載檔案系統。

e2fsck 的要求更加嚴格;如果它不知道相容或不相容特性集中的某個特性,它必須中止,並且不要嘗試干預它不理解的東西...

0x54

__le32

s_first_ino

第一個非保留 inode。

0x58

__le16

s_inode_size

inode 結構的大小,以位元組為單位。

0x5A

__le16

s_block_group_nr

此超級塊的塊組編號。

0x5C

__le32

s_feature_compat

相容特性集標誌。即使核心不理解某個標誌,仍然可以讀取/寫入此檔案系統;fsck 不應這樣做。有關更多資訊,請參見 super_compat 表。

0x60

__le32

s_feature_incompat

不相容特性集。如果核心或 fsck 不理解這些位中的一個,則應停止。有關更多資訊,請參見 super_incompat 表。

0x64

__le32

s_feature_ro_compat

只讀相容特性集。如果核心不理解這些位中的一個,則仍然可以以只讀方式掛載。有關更多資訊,請參見 super_rocompat 表。

0x68

__u8

s_uuid[16]

卷的 128 位 UUID。

0x78

char

s_volume_name[16]

卷標。

0x88

char

s_last_mounted[64]

上次掛載檔案系統的目錄。

0xC8

__le32

s_algorithm_usage_bitmap

用於壓縮(在 e2fsprogs/Linux 中未使用)

效能提示。只有當 EXT4_FEATURE_COMPAT_DIR_PREALLOC 標誌開啟時,才應進行目錄預分配。

0xCC

__u8

s_prealloc_blocks

#. 要嘗試預分配的塊數... 檔案?(在 e2fsprogs/Linux 中未使用)

0xCD

__u8

s_prealloc_dir_blocks

#. 要為目錄預分配的塊數。(在 e2fsprogs/Linux 中未使用)

0xCE

__le16

s_reserved_gdt_blocks

為將來的檔案系統擴充套件保留的 GDT 條目數。

只有設定了 EXT4_FEATURE_COMPAT_HAS_JOURNAL 時,才可以使用日誌支援。

0xD0

__u8

s_journal_uuid[16]

日誌超級塊的 UUID

0xE0

__le32

s_journal_inum

日誌檔案的 inode 編號。

0xE4

__le32

s_journal_dev

日誌檔案的裝置號(如果設定了外部日誌特性標誌)。

0xE8

__le32

s_last_orphan

要刪除的孤立 inode 列表的開頭。

0xEC

__le32

s_hash_seed[4]

HTREE 雜湊種子。

0xFC

__u8

s_def_hash_version

用於目錄雜湊的預設雜湊演算法。有關更多資訊,請參見 super_def_hash

0xFD

__u8

s_jnl_backup_type

如果此值為 0 或 EXT3_JNL_BACKUP_BLOCKS (1),則 s_jnl_blocks 欄位包含 inode 的 i_block[] 陣列和 i_size 的重複副本。

0xFE

__le16

s_desc_size

組描述符的大小,以位元組為單位(如果設定了 64 位不相容特性標誌)。

0x100

__le32

s_default_mount_opts

預設掛載選項。有關更多資訊,請參見 super_mountopts 表。

0x104

__le32

s_first_meta_bg

第一個元塊組(如果啟用了 meta_bg 特性)。

0x108

__le32

s_mkfs_time

建立檔案系統的時間,自 epoch 以來的秒數。

0x10C

__le32

s_jnl_blocks[17]

日誌 inode 的 i_block[] 陣列(在前 15 個元素中)以及 i_size_high 和 i_size(分別在第 16 個和第 17 個元素中)的備份副本。

只有設定了 EXT4_FEATURE_COMPAT_64BIT 時,才能使用 64 位支援。

0x150

__le32

s_blocks_count_hi

塊計數的高 32 位。

0x154

__le32

s_r_blocks_count_hi

保留塊計數的高 32 位。

0x158

__le32

s_free_blocks_count_hi

空閒塊計數的高 32 位。

0x15C

__le16

s_min_extra_isize

所有 inode 至少有 # 位元組。

0x15E

__le16

s_want_extra_isize

新 inode 應保留 # 位元組。

0x160

__le32

s_flags

雜項標誌。有關更多資訊,請參見 super_flags 表。

0x164

__le16

s_raid_stride

RAID 條帶。這是在移動到下一個磁碟之前從磁碟讀取或寫入的邏輯塊的數量。這會影響檔案系統元資料的放置,這有望使 RAID 儲存更快。

0x166

__le16

s_mmp_interval

#. 在多重掛載保護 (MMP) 檢查中等待的秒數。從理論上講,MMP 是一種在超級塊中記錄哪個主機和裝置已掛載檔案系統的機制,以防止多次掛載。此特性似乎未實現...

0x168

__le64

s_mmp_block

多重掛載保護資料的塊 #。

0x170

__le32

s_raid_stripe_width

RAID 條頻寬度。這是在返回到當前磁碟之前從磁碟讀取或寫入的邏輯塊的數量。塊分配器使用此值來嘗試減少 RAID5/6 中的讀取-修改-寫入操作的數量。

0x174

__u8

s_log_groups_per_flex

靈活塊組的大小為 2 ^ s_log_groups_per_flex

0x175

__u8

s_checksum_type

元資料校驗和演算法型別。唯一有效值為 1 (crc32c)。

0x176

__u8

s_encryption_level

加密的版本控制級別。

0x177

__u8

s_reserved_pad

填充到下一個 32 位。

0x178

__le64

s_kbytes_written

在此檔案系統的生命週期內寫入的 KiB 數。

0x180

__le32

s_snapshot_inum

活動快照的 inode 編號。(在 e2fsprogs/Linux 中未使用。)

0x184

__le32

s_snapshot_id

活動快照的序列 ID。(在 e2fsprogs/Linux 中未使用。)

0x188

__le64

s_snapshot_r_blocks_count

為活動快照的將來使用保留的塊數。(在 e2fsprogs/Linux 中未使用。)

0x190

__le32

s_snapshot_list

磁碟上快照列表的頭部的 inode 編號。(在 e2fsprogs/Linux 中未使用。)

0x194

__le32

s_error_count

看到的錯誤數。

0x198

__le32

s_first_error_time

發生錯誤的第一次時間,自 epoch 以來的秒數。

0x19C

__le32

s_first_error_ino

第一個錯誤中涉及的 inode。

0x1A0

__le64

s_first_error_block

第一個錯誤中涉及的塊的編號。

0x1A8

__u8

s_first_error_func[32]

發生錯誤的函式的名稱。

0x1C8

__le32

s_first_error_line

發生錯誤的行號。

0x1CC

__le32

s_last_error_time

最近一次錯誤的時間,自 epoch 以來的秒數。

0x1D0

__le32

s_last_error_ino

最近一次錯誤中涉及的 inode。

0x1D4

__le32

s_last_error_line

最近一次錯誤發生的行號。

0x1D8

__le64

s_last_error_block

最近一次錯誤中涉及的塊的編號。

0x1E0

__u8

s_last_error_func[32]

發生最近一次錯誤的函式的名稱。

0x200

__u8

s_mount_opts[64]

掛載選項的 ASCIIZ 字串。

0x240

__le32

s_usr_quota_inum

使用者配額檔案的 inode 編號。

0x244

__le32

s_grp_quota_inum

配額檔案的 inode 編號。

0x248

__le32

s_overhead_blocks

檔案系統中的開銷塊/簇。(嗯?此欄位始終為零,這意味著核心會動態計算它。)

0x24C

__le32

s_backup_bgs[2]

包含超級塊備份的塊組(如果 sparse_super2)。

0x254

__u8

s_encrypt_algos[4]

使用的加密演算法。在任何時候最多可以使用四種演算法;有效演算法程式碼在下面的 super_encrypt 表中給出。

0x258

__u8

s_encrypt_pw_salt[16]

用於加密的 string2key 演算法的鹽。

0x268

__le32

s_lpf_ino

lost+found 的 inode 編號

0x26C

__le32

s_prj_quota_inum

跟蹤專案配額的 Inode。

0x270

__le32

s_checksum_seed

用於 metadata_csum 計算的校驗和種子。此值為 crc32c(~0, $orig_fs_uuid)。

0x274

__u8

s_wtime_hi

s_wtime 欄位的高 8 位。

0x275

__u8

s_mtime_hi

s_mtime 欄位的高 8 位。

0x276

__u8

s_mkfs_time_hi

s_mkfs_time 欄位的高 8 位。

0x277

__u8

s_lastcheck_hi

s_lastcheck 欄位的高 8 位。

0x278

__u8

s_first_error_time_hi

s_first_error_time 欄位的高 8 位。

0x279

__u8

s_last_error_time_hi

s_last_error_time 欄位的高 8 位。

0x27A

__u8

s_first_error_errcode

0x27B

__u8

s_last_error_errcode

0x27C

__le16

s_encoding

檔名字元集編碼。

0x27E

__le16

s_encoding_flags

檔名字元集編碼標誌。

0x280

__le32

s_orphan_file_inum

孤立檔案 inode 編號。

0x284

__le32

s_reserved[94]

填充到塊的末尾。

0x3FC

__le32

s_checksum

超級塊校驗和。

超級塊狀態是以下各項的某種組合

描述

0x0001

已乾淨地解除安裝

0x0002

檢測到錯誤

0x0004

正在恢復孤立項

超級塊錯誤策略是以下之一

描述

1

繼續

2

以只讀方式重新掛載

3

崩潰

檔案系統建立者是以下之一

描述

0

Linux

1

Hurd

2

Masix

3

FreeBSD

4

Lites

超級塊修訂版是以下之一

描述

0

原始格式

1

具有動態 inode 大小的 v2 格式

請注意,EXT4_DYNAMIC_REV 指的是修訂版 1 或更新的檔案系統。

超級塊相容特性欄位是以下任何一項的組合

描述

0x1

目錄預分配 (COMPAT_DIR_PREALLOC)。

0x2

“imagic inodes”。從程式碼中不清楚這做什麼 (COMPAT_IMAGIC_INODES)。

0x4

擁有日誌 (COMPAT_HAS_JOURNAL)。

0x8

支援擴充套件屬性 (COMPAT_EXT_ATTR)。

0x10

擁有為檔案系統擴充套件保留的 GDT 塊 (COMPAT_RESIZE_INODE)。需要 RO_COMPAT_SPARSE_SUPER。

0x20

擁有目錄索引 (COMPAT_DIR_INDEX)。

0x40

“Lazy BG”。不在 Linux 核心中,似乎用於未初始化的塊組? (COMPAT_LAZY_BG)

0x80

“排除 inode”。未使用。 (COMPAT_EXCLUDE_INODE)。

0x100

“排除點陣圖”。似乎用於指示存在與快照相關的排除點陣圖?未在核心中定義或在 e2fsprogs 中使用 (COMPAT_EXCLUDE_BITMAP)。

0x200

稀疏超級塊,v2。如果設定了此標誌,則 SB 欄位 s_backup_bgs 指向包含備份超級塊的兩個塊組 (COMPAT_SPARSE_SUPER2)。

0x400

支援快速提交。雖然快速提交塊是向後不相容的,但快速提交塊並非總是存在於日誌中。如果快速提交塊存在於日誌中,則 JBD2 不相容特性 (JBD2_FEATURE_INCOMPAT_FAST_COMMIT) 會被設定 (COMPAT_FAST_COMMIT)。

0x1000

已分配孤立檔案。這是用於更高效地跟蹤未連結但仍開啟的 inode 的特殊檔案。當檔案中可能存在任何條目時,我們還會設定適當的只讀相容特性 (RO_COMPAT_ORPHAN_PRESENT)。

超級塊不相容特性欄位是以下各項的組合

描述

0x1

壓縮 (INCOMPAT_COMPRESSION)。

0x2

目錄條目記錄檔案型別。請參見下面的 ext4_dir_entry_2 (INCOMPAT_FILETYPE)。

0x4

檔案系統需要恢復 (INCOMPAT_RECOVER)。

0x8

檔案系統擁有單獨的日誌裝置 (INCOMPAT_JOURNAL_DEV)。

0x10

元塊組。請參見前面關於此特性的討論 (INCOMPAT_META_BG)。

0x40

此檔案系統中的檔案使用區段 (INCOMPAT_EXTENTS)。

0x80

啟用 2^64 個塊的檔案系統大小 (INCOMPAT_64BIT)。

0x100

多重掛載保護 (INCOMPAT_MMP)。

0x200

靈活的塊組。請參見前面關於此特性的討論 (INCOMPAT_FLEX_BG)。

0x400

Inode 可用於儲存大型擴充套件屬性值 (INCOMPAT_EA_INODE)。

0x1000

目錄條目中的資料 (INCOMPAT_DIRDATA)。 (未實現?)

0x2000

元資料校驗和種子儲存在超級塊中。此特性使管理員能夠在掛載檔案系統時更改 metadata_csum 檔案系統的 UUID;如果沒有它,校驗和定義需要重寫所有元資料塊 (INCOMPAT_CSUM_SEED)。

0x4000

大型目錄 >2GB 或 3 級 htree (INCOMPAT_LARGEDIR)。在此特性之前,目錄不能大於 4GiB,並且 htree 的深度不能超過 2 級。如果啟用了此特性,則目錄可以大於 4GiB,並且 htree 的最大深度為 3。

0x8000

Inode 中的資料 (INCOMPAT_INLINE_DATA)。

0x10000

加密的 inode 存在於檔案系統中。 (INCOMPAT_ENCRYPT)。

超級塊只讀相容特性欄位是以下各項的組合

描述

0x1

稀疏超級塊。請參見前面關於此特性的討論 (RO_COMPAT_SPARSE_SUPER)。

0x2

此檔案系統已用於儲存大於 2GiB 的檔案 (RO_COMPAT_LARGE_FILE)。

0x4

未在核心或 e2fsprogs 中使用 (RO_COMPAT_BTREE_DIR)。

0x8

此檔案系統中的檔案的大小以邏輯塊(而非 512 位元組的扇區)為單位表示。這意味著一個非常大的檔案!(RO_COMPAT_HUGE_FILE)

0x10

組描述符具有校驗和。除了檢測損壞之外,這對於使用未初始化的組進行延遲格式化也很有用 (RO_COMPAT_GDT_CSUM)。

0x20

指示舊的 ext3 32,000 子目錄限制不再適用 (RO_COMPAT_DIR_NLINK)。如果目錄的 i_links_count 遞增超過 64,999,則將其設定為 1。

0x40

指示此檔案系統上存在大型 inode (RO_COMPAT_EXTRA_ISIZE)。

0x80

此檔案系統具有快照 (RO_COMPAT_HAS_SNAPSHOT)。

0x100

配額 (RO_COMPAT_QUOTA)。

0x200

此檔案系統支援 “bigalloc”,這意味著檔案區段以簇(塊)為單位而不是以塊為單位進行跟蹤 (RO_COMPAT_BIGALLOC)。

0x400

此檔案系統支援元資料校驗和。 (RO_COMPAT_METADATA_CSUM; 意味著 RO_COMPAT_GDT_CSUM,儘管 GDT_CSUM 不得設定)

0x800

檔案系統支援副本。此特性既不在核心中也不在 e2fsprogs 中。 (RO_COMPAT_REPLICA)

0x1000

只讀檔案系統映像;核心不會以讀寫方式掛載此映像,並且大多數工具將拒絕寫入該映像。 (RO_COMPAT_READONLY)

0x2000

檔案系統跟蹤專案配額。 (RO_COMPAT_PROJECT)

0x8000

Verity inode 可能存在於檔案系統上。 (RO_COMPAT_VERITY)

0x10000

指示孤立檔案可能具有有效的孤立條目,因此在掛載檔案系統時我們需要清理它們 (RO_COMPAT_ORPHAN_PRESENT)。

s_def_hash_version 欄位是以下之一

描述

0x0

傳統。

0x1

半 MD4。

0x2

Tea。

0x3

傳統,未簽名。

0x4

半 MD4,未簽名。

0x5

Tea,未簽名。

s_default_mount_opts 欄位是以下各項的任意組合

描述

0x0001

在(重新)掛載時列印除錯資訊。 (EXT4_DEFM_DEBUG)

0x0002

新檔案採用包含目錄的 gid(而不是當前程序的 fsgid)。 (EXT4_DEFM_BSDGROUPS)

0x0004

支援使用者空間提供的擴充套件屬性。 (EXT4_DEFM_XATTR_USER)

0x0008

支援 POSIX 訪問控制列表 (ACL)。 (EXT4_DEFM_ACL)

0x0010

不支援 32 位 UID。 (EXT4_DEFM_UID16)

0x0020

所有資料和元資料都提交到日誌。 (EXT4_DEFM_JMODE_DATA)

0x0040

在將元資料提交到日誌之前,所有資料都會重新整理到磁碟。 (EXT4_DEFM_JMODE_ORDERED)

0x0060

不保留資料排序;資料可能在元資料寫入後寫入。 (EXT4_DEFM_JMODE_WBACK)

0x0100

停用寫入重新整理。 (EXT4_DEFM_NOBARRIER)

0x0200

跟蹤檔案系統中哪些塊是元資料,因此不應將其用作資料塊。希望預設情況下在 3.18 上啟用此選項。 (EXT4_DEFM_BLOCK_VALIDITY)

0x0400

啟用 DISCARD 支援,其中儲存裝置被告知塊變為未使用。 (EXT4_DEFM_DISCARD)

0x0800

停用延遲分配。 (EXT4_DEFM_NODELALLOC)

s_flags 欄位是以下各項的任意組合

描述

0x0001

正在使用簽名目錄雜湊。

0x0002

正在使用未簽名目錄雜湊。

0x0004

用於測試開發程式碼。

s_encrypt_algos 列表可以包含以下任何一項

描述

0

無效演算法 (ENCRYPTION_MODE_INVALID)。

1

XTS 模式下的 256 位 AES (ENCRYPTION_MODE_AES_256_XTS)。

2

GCM 模式下的 256 位 AES (ENCRYPTION_MODE_AES_256_GCM)。

3

CBC 模式下的 256 位 AES (ENCRYPTION_MODE_AES_256_CBC)。

超級塊的總大小為 1024 位元組。

3.2. 塊組描述符

檔案系統上的每個塊組都與其中一個描述符相關聯。如上面的佈局部分中所述,組描述符(如果存在)是塊組中的第二個專案。標準配置是每個塊組都包含塊組描述符表的完整副本,除非設定了 sparse_super 特性標誌。

請注意組描述符如何記錄點陣圖和 inode 表的位置(即它們可以浮動)。這意味著在塊組中,唯一具有固定位置的資料結構是超級塊和組描述符表。flex_bg 機制使用此屬性將多個塊組分組到 flex 組中,並將所有組的點陣圖和 inode 表佈局到 flex 組的第一個組中的一個長執行中。

如果設定了 meta_bg 特性標誌,則將多個塊組分組到一個元組中。請注意,在 meta_bg 情況下,較大的元組中的前兩個和最後兩個塊組僅包含元組內組的組描述符。

flex_bg 和 meta_bg 似乎不是互斥的特性。

在 ext2、ext3 和 ext4 中(當未啟用 64 位特性時),塊組描述符僅為 32 位元組長,因此在 bg_checksum 處結束。在啟用 64 位特性的 ext4 檔案系統上,塊組描述符擴充套件到至少下面描述的 64 位元組;大小儲存在超級塊中。

如果設定了 gdt_csum 並且未設定 metadata_csum,則塊組校驗和是 FS UUID、組號和組描述符結構的 crc16。如果設定了 metadata_csum,則塊組校驗和是 FS UUID、組號和組描述符結構的校驗和的低 16 位。塊和 inode 點陣圖校驗和都是根據 FS UUID、組號和整個點陣圖計算的。

塊組描述符以 struct ext4_group_desc 形式佈局。

偏移量

大小

名稱

描述

0x0

__le32

bg_block_bitmap_lo

塊點陣圖位置的低 32 位。

0x4

__le32

bg_inode_bitmap_lo

Inode 點陣圖位置的低 32 位。

0x8

__le32

bg_inode_table_lo

Inode 表位置的低 32 位。

0xC

__le16

bg_free_blocks_count_lo

空閒塊計數的低 16 位。

0xE

__le16

bg_free_inodes_count_lo

空閒 inode 計數的低 16 位。

0x10

__le16

bg_used_dirs_count_lo

目錄計數的低 16 位。

0x12

__le16

bg_flags

塊組標誌。請參見下面的 bgflags 表。

0x14

__le32

bg_exclude_bitmap_lo

快照排除點陣圖位置的低 32 位。

0x18

__le16

bg_block_bitmap_csum_lo

塊點陣圖校驗和的低 16 位。

0x1A

__le16

bg_inode_bitmap_csum_lo

Inode 點陣圖校驗和的低 16 位。

0x1C

__le16

bg_itable_unused_lo

未使用的 inode 計數的低 16 位。如果設定,我們不需要掃描超過此組中 inode 表中的第 (sb.s_inodes_per_group - gdt.bg_itable_unused) 個條目。

0x1E

__le16

bg_checksum

組描述符校驗和;如果設定了 RO_COMPAT_GDT_CSUM 特性,則為 crc16(sb_uuid+group_num+bg_desc),如果設定了 RO_COMPAT_METADATA_CSUM 特性,則為 crc32c(sb_uuid+group_num+bg_desc) & 0xFFFF。計算 crc16 校驗和時跳過 bg_desc 中的 bg_checksum 欄位,如果使用 crc32c 校驗和,則將其設定為零。

僅當啟用 64 位特性並且 s_desc_size > 32 時,這些欄位才存在。

0x20

__le32

bg_block_bitmap_hi

塊點陣圖位置的高 32 位。

0x24

__le32

bg_inode_bitmap_hi

Inode 點陣圖位置的高 32 位。

0x28

__le32

bg_inode_table_hi

Inode 表位置的高 32 位。

0x2C

__le16

bg_free_blocks_count_hi

空閒塊計數的高 16 位。

0x2E

__le16

bg_free_inodes_count_hi

空閒 inode 計數的高 16 位。

0x30

__le16

bg_used_dirs_count_hi

目錄計數的高 16 位。

0x32

__le16

bg_itable_unused_hi

未使用的 inode 計數的高 16 位。

0x34

__le32

bg_exclude_bitmap_hi

快照排除點陣圖位置的高 32 位。

0x38

__le16

bg_block_bitmap_csum_hi

塊點陣圖校驗和的高 16 位。

0x3A

__le16

bg_inode_bitmap_csum_hi

Inode 點陣圖校驗和的高 16 位。

0x3C

__u32

bg_reserved

填充至 64 位元組。

塊組標誌可以是以下各項的任意組合

描述

0x1

Inode 表和點陣圖未初始化 (EXT4_BG_INODE_UNINIT)。

0x2

塊點陣圖未初始化 (EXT4_BG_BLOCK_UNINIT)。

0x4

Inode 表已清零 (EXT4_BG_INODE_ZEROED)。

3.3. 塊和 inode 點陣圖

資料塊點陣圖跟蹤塊組內的資料塊的使用情況。

Inode 點陣圖記錄 inode 表中的哪些條目正在使用中。

與大多數點陣圖一樣,一位表示一個數據塊或 inode 表條目的使用狀態。這意味著塊組大小為 8 * logical_block_in_bytes。

注意:如果為給定的塊組設定了 BLOCK_UNINIT,則核心和 e2fsprogs 程式碼的各個部分會假裝塊點陣圖包含零(即組中的所有塊都是空閒的)。但是,並非所有塊都在使用中 - 如果設定了 meta_bg,則點陣圖和組描述符位於組內。不幸的是,ext2fs_test_block_bitmap2() 將為這些位置返回“0”,這會產生令人困惑的 debugfs 輸出。

3.4. Inode 表

Inode 表在 mkfs 時靜態分配。每個塊組描述符指向表的開頭,超級塊記錄每個組的 inode 數。有關更多資訊,請參見關於 inode 的部分。

3.5. 多重掛載保護

多重掛載保護 (MMP) 是一種保護檔案系統免受多個主機同時嘗試使用該檔案系統的特性。當開啟檔案系統(用於掛載或 fsck 等)時,節點(稱其為節點 A)上執行的 MMP 程式碼會檢查序列號。如果序列號為 EXT4_MMP_SEQ_CLEAN,則繼續開啟。如果序列號為 EXT4_MMP_SEQ_FSCK,則 fsck 正在(希望)執行,並且開啟立即失敗。否則,開啟程式碼將等待指定 MMP 檢查間隔的兩倍,然後再次檢查序列號。如果序列號已更改,則檔案系統在另一臺機器上處於活動狀態,並且開啟失敗。如果 MMP 程式碼透過所有這些檢查,則會生成一個新的 MMP 序列號並將其寫入 MMP 塊,並且掛載繼續。

當檔案系統處於活動狀態時,核心會設定一個計時器,以便在指定的 MMP 檢查間隔重新檢查 MMP 塊。為了執行重新檢查,將重新讀取 MMP 序列號;如果它與記憶體中的 MMP 序列號不匹配,則另一個節點(節點 B)已掛載檔案系統,並且節點 A 以只讀方式重新掛載檔案系統。如果序列號匹配,則序列號在記憶體和磁碟上都會遞增,並且重新檢查完成。

只要開啟操作成功,主機名和裝置檔名就會寫入 MMP 塊。MMP 程式碼不使用這些值;它們僅用於提供資訊。

校驗和是根據 FS UUID 和 MMP 結構計算的。MMP 結構 (struct mmp_struct) 如下

偏移量

型別

名稱

描述

0x0

__le32

mmp_magic

MMP 的幻數,0x004D4D50 (“MMP”)。

0x4

__le32

mmp_seq

序列號,定期更新。

0x8

__le64

mmp_time

上次更新 MMP 塊的時間。

0x10

char[64]

mmp_nodename

開啟檔案系統的節點的hostname。

0x50

char[32]

mmp_bdevname

檔案系統的塊裝置名稱。

0x70

__le16

mmp_check_interval

MMP 重新檢查間隔(以秒為單位)。

0x72

__le16

mmp_pad1

零。

0x74

__le32[226]

mmp_pad2

零。

0x3FC

__le32

mmp_checksum

MMP 塊的校驗和。

3.6. 日誌 (jbd2)

ext4 檔案系統在 ext3 中引入,它使用日誌來保護檔案系統免受系統崩潰時元資料不一致的影響。最多可以在檔案系統中保留 10,240,000 個檔案系統塊(有關日誌大小限制的更多詳細資訊,請參見 man mke2fs(8)),作為儘快將“重要”資料寫入磁碟的位置。一旦重要的資料事務完全寫入磁碟並從磁碟寫入快取中重新整理,資料提交的記錄也會寫入日誌。在稍後的某個時間點,日誌程式碼會將事務寫入到它們在磁碟上的最終位置(這可能涉及大量的搜尋或大量的小型讀寫擦除),然後再擦除提交記錄。如果在第二次緩慢寫入期間系統崩潰,則可以將日誌一直重放到最新的提交記錄,從而保證透過日誌寫入磁碟的任何內容的原子性。這樣做的好處是可以保證檔案系統不會在元資料更新過程中卡住。

出於效能原因,預設情況下,ext4 僅透過日誌寫入檔案系統元資料。這意味著無法保證檔案資料塊在崩潰後處於任何一致狀態。如果此預設保證級別 (data=ordered) 不令人滿意,則可以使用掛載選項來控制日誌行為。如果 data=journal,則所有資料和元資料都透過日誌寫入磁碟。這比較慢,但最安全。如果 data=writeback,則在透過日誌將元資料寫入磁碟之前,不會將髒資料塊重新整理到磁碟。

data=ordered 模式下,Ext4 還支援快速提交,這有助於顯著減少提交延遲。預設的 data=ordered 模式透過將元資料塊記錄到日誌來實現。在快速提交模式下,Ext4 僅儲存重現與 JBD2 共享的快速提交空間中受影響的元資料所需的最小增量。一旦快速提交區域填滿,或者如果無法進行快速提交,或者 JBD2 提交計時器關閉,Ext4 將執行傳統的完整提交。完整提交會使之前發生的所有快速提交無效,因此它會使快速提交區域為空以進行進一步的快速提交。此特性需要在 mkfs 時啟用。

日誌 inode 通常是 inode 8。日誌 inode 的前 68 個位元組會在 ext4 超級塊中複製。日誌本身是檔案系統中的普通(但隱藏)檔案。該檔案通常佔用整個塊組,儘管 mke2fs 嘗試將其放在磁碟的中間。

jbd2 中的所有欄位都以大端順序寫入磁碟。這與 ext4 相反。

注意:ext4 和 ocfs2 都使用 jbd2。

嵌入在 ext4 檔案系統中的日誌的最大大小為 2^32 個塊。jbd2 本身似乎並不關心。

3.6.1. 佈局

一般來說,日誌具有以下格式

超級塊

descriptor_block(data_blocks 或 revocation_block)[更多資料或撤銷] commmit_block

[更多事務...]

一個事務

請注意,事務以描述符和一些資料或塊撤銷列表開始。已完成的事務始終以提交結束。如果沒有提交記錄(或者校驗和不匹配),則在重放期間將丟棄該事務。

3.6.2. 外部日誌

或者,可以使用外部日誌裝置建立 ext4 檔案系統(而不是使用保留的 inode 的內部日誌)。在這種情況下,在檔案系統裝置上,s_journal_inum 應為零,並且應設定 s_journal_uuid。在日誌裝置上,通常的位置會有一個 ext4 超級塊,其中包含匹配的 UUID。日誌超級塊將在超級塊之後的下一個完整塊中。

1024 位元組的填充

ext4 超級塊

日誌超級塊

descriptor_block(data_blocks 或 revocation_block)[更多資料或撤銷] commmit_block

[更多事務...]

一個事務

3.6.3. 塊標頭

日誌中的每個塊都以一個通用的 12 位元組標頭 struct journal_header_s 開頭

偏移量

型別

名稱

描述

0x0

__be32

h_magic

jbd2 幻數,0xC03B3998。

0x4

__be32

h_blocktype

此塊包含的內容的描述。請參見下面的 jbd2_blocktype 表。

0x8

__be32

h_sequence

與此塊相關的事務 ID。

日誌塊型別可以是以下任何一種

描述

1

描述符。此塊位於透過事務期間透過日誌寫入的一系列資料塊之前。

2

塊提交記錄。此塊表示事務的完成。

3

日誌超級塊,v1。

4

日誌超級塊,v2。

5

塊撤銷記錄。這透過使日誌能夠跳過寫入隨後被重寫的塊來加速恢復。

3.6.4. 超級塊

與 ext4 相比,日誌的超級塊要簡單得多。其中保留的關鍵資料是日誌的大小以及在哪裡找到事務日誌的開頭。

日誌超級塊記錄為 struct journal_superblock_s,長度為 1024 位元組

偏移量

型別

名稱

描述

描述日誌的靜態資訊。

0x0

journal_header_t (12 位元組)

s_header

通用標頭,用於將其標識為超級塊。

0xC

__be32

s_blocksize

日誌裝置塊大小。

0x10

__be32

s_maxlen

此日誌中的塊總數。

0x14

__be32

s_first

日誌資訊的第一個塊。

描述日誌當前狀態的動態資訊。

0x18

__be32

s_sequence

日誌中預期的第一個提交 ID。

0x1C

__be32

s_start

日誌開頭的塊號。與註釋相反,此欄位為零並不意味著日誌是乾淨的!

0x20

__be32

s_errno

錯誤值,由 jbd2_journal_abort() 設定。

其餘欄位僅在 v2 超級塊中有效。

0x24

__be32

s_feature_compat;

相容特性集。參見下方的 jbd2_compat 表格。

0x28

__be32

s_feature_incompat

不相容特性集。參見下方的 jbd2_incompat 表格。

0x2C

__be32

s_feature_ro_compat

只讀相容特性集。目前還沒有這樣的特性。

0x30

__u8

s_uuid[16]

用於日誌的 128 位 UUID。 在掛載時,會將其與 ext4 超級塊中的副本進行比較。

0x40

__be32

s_nr_users

共享此日誌的檔案系統數量。

0x44

__be32

s_dynsuper

動態超級塊副本的位置。(未使用?)

0x48

__be32

s_max_transaction

每個事務的日誌塊限制。(未使用?)

0x4C

__be32

s_max_trans_data

每個事務的資料塊限制。(未使用?)

0x50

__u8

s_checksum_type

用於日誌的校驗和演算法。 有關更多資訊,請參見 jbd2_checksum_type

0x51

__u8[3]

s_padding2

0x54

__be32

s_num_fc_blocks

日誌中快速提交塊的數量。

0x58

__be32

s_head

日誌頭(第一個未使用的塊)的塊號,僅在日誌為空時才是最新的。

0x5C

__u32

s_padding[40]

0xFC

__be32

s_checksum

整個超級塊的校驗和,此欄位設定為零。

0x100

__u8

s_users[16*48]

共享日誌的所有檔案系統的 ID。 e2fsprogs/Linux 不允許共享外部日誌,但我認為 Lustre(或 ocfs2?),它們使用 jbd2 程式碼,可能會允許。

日誌相容特性是以下各項的任意組合:

描述

0x1

日誌維護資料塊上的校驗和。(JBD2_FEATURE_COMPAT_CHECKSUM)

日誌不相容特性是以下各項的任意組合:

描述

0x1

日誌具有塊撤銷記錄。(JBD2_FEATURE_INCOMPAT_REVOKE)

0x2

日誌可以處理 64 位塊號。(JBD2_FEATURE_INCOMPAT_64BIT)

0x4

日誌非同步提交。(JBD2_FEATURE_INCOMPAT_ASYNC_COMMIT)

0x8

此日誌使用磁碟上校驗和格式的 v2 版本。每個日誌元資料塊都有自己的校驗和,並且描述符表中的塊標籤包含日誌中每個資料塊的校驗和。(JBD2_FEATURE_INCOMPAT_CSUM_V2)

0x10

此日誌使用磁碟上校驗和格式的 v3 版本。 這與 v2 相同,但無論塊號的大小如何,日誌塊標籤大小都是固定的。(JBD2_FEATURE_INCOMPAT_CSUM_V3)

0x20

日誌具有快速提交塊。(JBD2_FEATURE_INCOMPAT_FAST_COMMIT)

日誌校驗和型別程式碼是以下之一。 crc32 或 crc32c 是最可能的選擇。

描述

1

CRC32

2

MD5

3

SHA1

4

CRC32C

3.6.5. 描述符塊

描述符塊包含一個日誌塊標籤陣列,用於描述日誌中後續資料塊的最終位置。 描述符塊是開放編碼的,而不是由資料結構完全描述,但無論如何,這裡是塊結構。 描述符塊至少消耗 36 個位元組,但使用一個完整的塊

偏移量

型別

名稱

描述符

0x0

journal_header_t

(開放編碼)

公共塊頭。

0xC

struct journal_block_tag_s

開放編碼陣列[]

足夠的標籤,可以填充該塊或描述此描述符塊後面的所有資料塊。

日誌塊標籤具有以下任何格式,具體取決於設定了哪些日誌特性和塊標籤標誌。

如果設定了 JBD2_FEATURE_INCOMPAT_CSUM_V3,則日誌塊標籤定義為 struct journal_block_tag3_s,如下所示。 大小為 16 或 32 位元組。

偏移量

型別

名稱

描述符

0x0

__be32

t_blocknr

相應的資料塊應最終位於磁碟上的位置的低 32 位。

0x4

__be32

t_flags

與描述符一起使用的標誌。 有關更多資訊,請參見 jbd2_tag_flags 表格。

0x8

__be32

t_blocknr_high

相應的資料塊應最終位於磁碟上的位置的高 32 位。 如果未啟用 JBD2_FEATURE_INCOMPAT_64BIT,則為零。

0xC

__be32

t_checksum

日誌 UUID、序列號和資料塊的校驗和。

此欄位似乎是開放編碼的。 它始終位於標籤的末尾,在 t_checksum 之後。 如果設定了“相同 UUID”標誌,則不存在此欄位。

0x8 或 0xC

char

uuid[16]

與此標籤一起使用的 UUID。 此欄位似乎是從 struct journal_s 中的 j_uuid 欄位複製的,但只有 tune2fs 觸及該欄位。

日誌標籤標誌是以下各項的任意組合:

描述

0x1

磁碟上的塊已轉義。 資料塊的前四個位元組恰好與 jbd2 幻數匹配。

0x2

此塊與之前的塊具有相同的 UUID,因此省略了 UUID 欄位。

0x4

資料塊已由事務刪除。(未使用?)

0x8

這是此描述符塊中的最後一個標籤。

如果未設定 JBD2_FEATURE_INCOMPAT_CSUM_V3,則日誌塊標籤定義為 struct journal_block_tag_s,如下所示。 大小為 8、12、24 或 28 位元組

偏移量

型別

名稱

描述符

0x0

__be32

t_blocknr

相應的資料塊應最終位於磁碟上的位置的低 32 位。

0x4

__be16

t_checksum

日誌 UUID、序列號和資料塊的校驗和。 請注意,僅儲存低 16 位。

0x6

__be16

t_flags

與描述符一起使用的標誌。 有關更多資訊,請參見 jbd2_tag_flags 表格。

僅當超級塊指示支援 64 位塊號時,才存在下一個欄位。

0x8

__be32

t_blocknr_high

相應的資料塊應最終位於磁碟上的位置的高 32 位。

此欄位似乎是開放編碼的。 它始終位於標籤的末尾,在 t_flags 或 t_blocknr_high 之後。 如果設定了“相同 UUID”標誌,則不存在此欄位。

0x8 或 0xC

char

uuid[16]

與此標籤一起使用的 UUID。 此欄位似乎是從 struct journal_s 中的 j_uuid 欄位複製的,但只有 tune2fs 觸及該欄位。

如果設定了 JBD2_FEATURE_INCOMPAT_CSUM_V2 或 JBD2_FEATURE_INCOMPAT_CSUM_V3,則塊的末尾是一個 struct jbd2_journal_block_tail,如下所示

偏移量

型別

名稱

描述符

0x0

__be32

t_checksum

日誌 UUID + 描述符塊的校驗和,此欄位設定為零。

3.6.6. 資料塊

通常,透過日誌寫入磁碟的資料塊在描述符塊之後逐字寫入日誌檔案。 但是,如果塊的前四個位元組與 jbd2 幻數匹配,則將這四個位元組替換為零,並在描述符塊標籤中設定“escaped”標誌。

3.6.7. 撤銷塊

撤銷塊用於防止在較早的事務中重放塊。 這用於標記曾經被記錄但不再被記錄的塊。 通常,如果元資料塊被釋放並重新分配為檔案資料塊,則會發生這種情況; 在這種情況下,在將檔案塊寫入磁碟後重放日誌將導致損壞。

注意:此機制不用於表達“此日誌塊被此其他日誌塊取代”,正如作者 (djwong) 錯誤地認為的那樣。 新增到事務的任何塊都將導致刪除該塊的所有現有撤銷記錄。

撤銷塊在 struct jbd2_journal_revoke_header_s 中描述,長度至少為 16 個位元組,但使用一個完整的塊

偏移量

型別

名稱

描述

0x0

journal_header_t

r_header

公共塊頭。

0xC

__be32

r_count

此塊中使用的位元組數。

0x10

__be32 或 __be64

blocks[0]

要撤銷的塊。

r_count 之後是一個線性陣列,其中包含被此事務有效撤銷的塊號。 如果超級塊宣告支援 64 位塊號,則每個塊號的大小為 8 個位元組,否則為 4 個位元組。

如果設定了 JBD2_FEATURE_INCOMPAT_CSUM_V2 或 JBD2_FEATURE_INCOMPAT_CSUM_V3,則撤銷塊的末尾是一個 struct jbd2_journal_revoke_tail,其格式如下

偏移量

型別

名稱

描述

0x0

__be32

r_checksum

日誌 UUID + 撤銷塊的校驗和

3.6.8. 提交塊

提交塊是一個哨兵,指示事務已完全寫入日誌。 一旦此提交塊到達日誌,就可以將與此事務一起儲存的資料寫入它們在磁碟上的最終位置。

提交塊由 struct commit_header 描述,該結構長 32 個位元組(但使用一個完整的塊)

偏移量

型別

名稱

描述符

0x0

journal_header_s

(開放編碼)

公共塊頭。

0xC

unsigned char

h_chksum_type

用於驗證事務中資料塊完整性的校驗和型別。 有關更多資訊,請參見 jbd2_checksum_type

0xD

unsigned char

h_chksum_size

校驗和使用的位元組數。 最有可能是 4。

0xE

unsigned char

h_padding[2]

0x10

__be32

h_chksum[JBD2_CHECKSUM_BYTES]

用於儲存校驗和的 32 個位元組的空間。 如果設定了 JBD2_FEATURE_INCOMPAT_CSUM_V2 或 JBD2_FEATURE_INCOMPAT_CSUM_V3,則第一個 __be32 是日誌 UUID 和整個提交塊的校驗和,此欄位為零。 如果設定了 JBD2_FEATURE_COMPAT_CHECKSUM,則第一個 __be32 是已寫入事務的所有塊的 crc32。

0x30

__be64

h_commit_sec

事務提交的時間,以自 epoch 以來的秒數為單位。

0x38

__be32

h_commit_nsec

上述時間戳的納秒分量。

3.6.9. 快速提交

快速提交區域組織為標籤長度值的日誌。 每個 TLV 的開頭都有一個 struct ext4_fc_tl,用於儲存標籤和整個欄位的長度。 後面是可變長度的特定於標籤的值。 以下是支援的標籤及其含義的列表

標籤

含義

值結構

描述

EXT4_FC_TAG_HEAD

快速提交區域標頭

struct ext4_fc_head

儲存在應用這些快速提交之後事務的 TID。

EXT4_FC_TAG_ADD_RANGE

將範圍新增到 inode

struct ext4_fc_add_range

儲存要在此 inode 中新增的 inode 編號和範圍

EXT4_FC_TAG_DEL_RANGE

刪除到 inode 的邏輯偏移量

struct ext4_fc_del_range

儲存需要刪除的 inode 編號和邏輯偏移量範圍

EXT4_FC_TAG_CREAT

為新建立的檔案建立目錄條目

struct ext4_fc_dentry_info

儲存新建立檔案的父 inode 編號、inode 編號和目錄條目

EXT4_FC_TAG_LINK

將目錄條目連結到 inode

struct ext4_fc_dentry_info

儲存父 inode 編號、inode 編號和目錄條目

EXT4_FC_TAG_UNLINK

取消連結 inode 的目錄條目

struct ext4_fc_dentry_info

儲存父 inode 編號、inode 編號和目錄條目

EXT4_FC_TAG_PAD

填充(未使用區域)

快速提交區域中未使用的位元組。

EXT4_FC_TAG_TAIL

標記快速提交的結束

struct ext4_fc_tail

儲存提交的 TID、快速提交的 CRC,該標籤表示快速提交的結束

3.6.10. 快速提交重放冪等性

如果恢復程式碼遵循某些規則,則快速提交標籤本質上是冪等的。 提交路徑在提交時遵循的指導原則是,它儲存特定操作的結果,而不是儲存過程。

讓我們考慮一下這個重新命名操作:“mv /a /b”。 讓我們假設 dirent ‘/a’ 與 inode 10 相關聯。在快速提交期間,我們不是將此操作儲存為過程“將 a 重新命名為 b”,而是將生成的檔案系統狀態儲存為一系列“結果”

  • 將 dirent b 連結到 inode 10

  • 取消連結 dirent a

  • 具有有效引用計數的 inode 10

現在,當恢復程式碼執行時,它需要在檔案系統上“強制執行”此狀態。 這保證了快速提交重放的冪等性。

讓我們舉一個不是冪等的過程的例子,看看快速提交如何使其冪等。 考慮以下操作序列

  1. rm A

  2. mv B A

  3. read A

如果我們按原樣儲存此操作序列,則重放不是冪等的。 假設在重放時,我們在 (2) 之後崩潰。 在第二次重放期間,將刪除檔案 A(實際上是作為“mv B A”操作的結果建立的)。 因此,當我們嘗試讀取 A 時,名為 A 的檔案將不存在。 因此,此操作序列不是冪等的。 但是,如上所述,快速提交不是儲存過程,而是儲存每個過程的結果。 因此,上述過程的快速提交日誌如下

(讓我們假設在重放之前,dirent A 連結到 inode 10,dirent B 連結到 inode 11)

  1. 取消連結 A

  2. 將 A 連結到 inode 11

  3. 取消連結 B

  4. Inode 11

如果在 (3) 之後崩潰,我們將擁有連結到 inode 11 的檔案 A。 在第二次重放期間,我們將刪除檔案 A(inode 11)。 但是我們將重新建立它並使其指向 inode 11。 我們找不到 B,因此我們將跳過該步驟。 此時,inode 11 的引用計數不可靠,但這可以透過重放最後一個 inode 11 標籤來修復。 因此,透過將非冪等過程轉換為一系列冪等結果,快速提交確保了重放期間的冪等性。

3.6.11. 日誌檢查點

檢查日誌點可確保將所有事務及其關聯的緩衝區提交到磁碟。 等待進行中的事務並將其包含在檢查點中。 在對檔案系統進行關鍵更新(包括日誌恢復、檔案系統調整大小和釋放 journal_t 結構)期間,會在內部使用檢查點。

可以透過 ioctl EXT4_IOC_CHECKPOINT 從使用者空間觸發日誌檢查點。 此 ioctl 採用一個 u64 引數作為標誌。 目前,支援三個標誌。 首先,可以使用 EXT4_IOC_CHECKPOINT_FLAG_DRY_RUN 來驗證 ioctl 的輸入。 如果有任何無效輸入,則返回錯誤,否則返回成功而不執行任何檢查點操作。 這可用於檢查系統上是否存在 ioctl,並驗證引數或標誌是否存在任何問題。 另外兩個標誌是 EXT4_IOC_CHECKPOINT_FLAG_DISCARD 和 EXT4_IOC_CHECKPOINT_FLAG_ZEROOUT。 這些標誌分別導致在日誌檢查點完成後丟棄或清零日誌塊。 EXT4_IOC_CHECKPOINT_FLAG_DISCARD 和 EXT4_IOC_CHECKPOINT_FLAG_ZEROOUT 不能同時設定。 當對系統進行快照或遵守內容刪除 SLO 時,ioctl 可能很有用。

3.7. 孤立檔案

在 unix 中,可能存在從目錄層次結構取消連結但仍然活動的 inode,因為它們是開啟的。 如果發生崩潰,檔案系統必須清理這些 inode,否則它們(以及從它們引用的塊)會洩漏。 同樣,如果我們截斷或擴充套件檔案,我們可能無法在單個日誌事務中執行該操作。 在這種情況下,我們將 inode 跟蹤為孤立 inode,以便在發生崩潰時,分配給檔案的額外塊將被截斷。

傳統上,ext4 以單鏈表的形式跟蹤孤立 inode,其中超級塊包含最後一個孤立 inode 的 inode 編號(s_last_orphan 欄位),然後每個 inode 包含先前孤立 inode 的 inode 編號(我們為此過載 i_dtime inode 欄位)。 但是,對於導致大量建立孤立 inode 的工作負載,此檔案系統全域性單鏈表是一個可伸縮性瓶頸。 啟用孤立檔案特性 (COMPAT_ORPHAN_FILE) 後,檔案系統將具有一個具有多個塊的特殊 inode(從超級塊透過 s_orphan_file_inum 引用)。 每個塊都有一個結構

偏移量

型別

名稱

描述

0x0

__le32 條目的陣列

孤立 inode 條目

每個 __le32 條目要麼為空 (0),要麼包含孤立 inode 的 inode 編號。

blocksize-8

__le32

ob_magic

儲存在孤立塊尾部的幻數值 (0x0b10ca04)

blocksize-4

__le32

ob_checksum

孤立塊的校驗和。

當以可寫方式掛載具有孤立檔案特性的檔案系統時,我們在超級塊中設定 RO_COMPAT_ORPHAN_PRESENT 特性,以指示可能存在有效的孤立條目。 如果我們在掛載檔案系統時看到此特性,我們將讀取整個孤立檔案並像往常一樣處理在那裡找到的所有孤立 inode。 當乾淨地解除安裝檔案系統時,我們將刪除 RO_COMPAT_ORPHAN_PRESENT 特性,以避免不必要地掃描孤立檔案,並使檔案系統與舊核心完全相容。