老鳥幫您分析ext2文件系統

原文:http://www.z8soft.com/article/server/201105/20110504289253.shtml

隨着Linux 的  發展和開源優勢 正在逐漸被廣大用戶接受 下面我介紹一下ext2文件系統的相關知識e,xt2文件系統是Linux系統中的標準文件系統,是通過對Minix的文件系統進行擴展而得到的,其存取文件的性能極好。

在ext2文件系統中,文件由inode(包含有文件的所有信息)進行唯一標識。一個文件可能對應多個文件名,只有在所有文件名都被刪除後,該文件纔會被刪除。此外,同一文件在磁盤中存放和被打開時所對應的inode是不同的,並由內核負責同步。
ext2文件系統採用三級間接塊來存儲數據塊指針,並以塊(block,默認爲1KB)爲單位分配空間。其磁盤分配策略是儘可能將邏輯相鄰的文件分配到磁盤上物理相鄰的塊中,並儘可能將碎片分配給儘量少的文件,以從全局上提高性能。ext2文件系統將同一目錄下的文件(包括目錄)儘可能的放在同一個塊組中,但目錄則分佈在各個塊組中以實現負載均衡。在擴展文件時,會盡量一次性擴展8個連續塊給文件(以預留空間的形式實現)。
 
一、磁盤組織
 
在ext2文件系統中,所有元數據結構的大小均基於“塊”,而不是“扇區”。塊的大小隨文件系統的大小而有所不同。而一定數量的塊又組成一個塊組,每個塊組的起始部分有多種多樣的描述該塊組各種屬性的元數據結構。ext2系統中對各個結構的定義都包含在原始碼的include/linux/ext2_fs.h文件中。
1.終極塊
每個ext2文件系統都必須包含一個終極塊,其中存儲了該文件系統的大量基本信息,包括塊的大小、每塊組中包含的塊數等。同時,系統會對終極塊進行備份,備份被存放在塊組的第一個塊中。終極塊的起始位置爲其所在分區的第1024個字節,佔用1KB的空間,其結構如下:
struct ext2_super_block {
__le32 s_inodes_count; // ext2文件系統中inode的總數
__le32 s_blocks_count; // 文件系統中塊的總數
__le32 s_r_blocks_count; // 保留塊的總數
__le32 s_free_blocks_count; // 未使用的塊的總數(包括保留塊)
__le32 s_free_inodes_count; // 未使用的inode的總數
__le32 s_first_data_block; // 塊ID,在小於1KB的文件系統中爲0,大於1KB的文件系統中爲1
__le32 s_log_block_size; // 用以計算塊的大小(1024算術左移該值即爲塊大小)
__le32 s_log_frag_size; // 用以計算段大小(爲正則1024算術左移該值,否則右移)
__le32 s_blocks_per_group; // 每個塊組中塊的總數
__le32 s_frags_per_group; // 每個塊組中段的總數
__le32 s_inodes_per_group; // 每個塊組中inode的總數
__le32 s_mtime; // POSIX中定義的文件系統裝載時間
__le32 s_wtime; // POSIX中定義的文件系統最近被寫入的時間
__le16 s_mnt_count; // 最近一次完整校驗後被裝載的次數
__le16 s_max_mnt_count; // 在進行完整校驗前還能被裝載的次數
__le16 s_magic; // 文件系統標誌,ext2文件系統中爲0xEF53
__le16 s_state; // 文件系統的狀態
__le16 s_errors; // 文件系統發生錯誤時驅動程式應該執行的操作
__le16 s_minor_rev_level; // 局部修訂級別
__le32 s_lastcheck; // POSIX中定義的文件系統最近一次檢查的時間
__le32 s_checkinterval; // POSIX中定義的文件系統最近檢查的最大時間間隔
__le32 s_creator_os; // 生成該ext2文件系統的操作系統
__le32 s_rev_level; // 修訂級別
__le16 s_def_resuid; // 報留塊的默認用戶ID
__le16 s_def_resgid; // 保留塊的默認組ID
// 僅用於使用動態inode大小的修訂版(EXT2_DYNAMIC_REV)
__le32 s_first_ino; // 標準文件的第一個可用inode的索引(非動態爲11)
__le16 s_inode_size; // inode結構的大小(非動態爲128)
__le16 s_block_group_nr; // 保存此終極塊的塊組號
__le32 s_feature_compat; // 兼容特性掩碼
__le32 s_feature_incompat; // 不兼容特性掩碼
__le32 s_feature_ro_compat; // 只讀特性掩碼
__u8 s_uuid[16]; // 卷ID,應儘可能使每個ext2文件系統的格式唯一
char s_volume_name[16]; // 卷名(只能爲ISO-Latin-1字符集,以’\0’結束)
char s_last_mounted[64]; // 最近被安裝的目錄
__le32 s_algorithm_usage_bitmap; // 文件系統採用的壓縮算法
// 僅在EXT2_COMPAT_PREALLOC標誌被設置時有效
__u8 s_prealloc_blocks; // 預分配的塊數
__u8 s_prealloc_dir_blocks; // 給目錄預分配的塊數
__u16 s_padding1;
// 僅在EXT3_FEATURE_COMPAT_HAS_JOURNAL標誌被設置時有效,用以支持日誌
__u8 s_journal_uuid[16]; // 日誌終極塊的卷ID
__u32 s_journal_inum; // 日誌文件的inode數目
__u32 s_journal_dev; // 日誌文件的設備數
__u32 s_last_orphan; // 要刪除的inode列表的起始位置
__u32 s_hash_seed[4]; // HTREE散列種子
__u8 s_def_hash_version; // 默認使用的散列函數
__u8 s_reserved_char_pad;
__u16 s_reserved_word_pad;
__le32 s_default_mount_opts;
__le32 s_first_meta_bg; // 塊組的第一個元塊
__u32 s_reserved[190];
};
2.塊組描述符

一個塊組描述符用以描述一個塊組的屬性。塊組描述符組由若干塊組描述符組成,描述了文件系統中所有塊組的屬性,存放於終極塊所在塊的下一個塊中。一個塊組描述符的結構如下:
struct ext2_group_desc
{
__le32 bg_block_bitmap; // 塊位圖所在的第一個塊的塊ID
__le32 bg_inode_bitmap; // inode位圖所在的第一個塊的塊ID
__le32 bg_inode_table; // inode表所在的第一個塊的塊ID
__le16 bg_free_blocks_count; // 塊組中未使用的塊數
__le16 bg_free_inodes_count; // 塊組中未使用的inode數
__le16 bg_used_dirs_count; // 塊組分配的目錄的inode數
__le16 bg_pad;
__le32 bg_reserved[3];
};
 
3.塊位圖和inode位圖
塊位圖和inode位圖的每一位分別指出塊組中對應的那個塊或inode是否被使用。
4.inode表
inode表用於跟蹤定位每個文件,包括位置、大小等(但不包括文件名),一個塊組只有一個inode表。一個inode的結構如下:
struct ext2_inode {
__le16 i_mode; // 文件格式和訪問權限
__le16 i_uid; // 文件所有者ID的低16位
__le32 i_size; // 文件字節數
__le32 i_atime; // 文件上次被訪問的時間
__le32 i_ctime; // 文件創建時間
__le32 i_mtime; // 文件被修改的時間
__le32 i_dtime; // 文件被刪除的時間(如果存在則爲0)
__le16 i_gid; // 文件所有組ID的低16位
__le16 i_links_count; // 此inode被連接的次數
__le32 i_blocks; // 文件已使用和保留的總塊數(以512B爲單位)
__le32 i_flags; // 此inode訪問數據時ext2的實現方式
union {
struct {
__le32 l_i_reserved1; // 保留
} linux1;
struct {
__le32 h_i_translator; // “翻譯者”標籤
} hurd1;
struct {
__le32 m_i_reserved1; // 保留
} masix1;
} osd1; // 操作系統相關數據
__le32 i_block[EXT2_N_BLOCKS]; // 定位存儲文件的塊的數組,前12個爲塊號,第13個爲一級間接塊號,第14個爲二級間接塊號,第15個爲三級間接塊號
__le32 i_generation; // 用於NFS的文件版本
__le32 i_file_acl; // 包含擴展屬性的塊號,老版本中爲0
__le32 i_dir_acl; // 表示文件的“High Size”,老版本中爲0
__le32 i_faddr; // 文件最後一個段的地址
union {
struct {
__u8 l_i_frag; // 段號
__u8 l_i_fsize; // 段大小
__u16 i_pad1;
__le16 l_i_uid_high; // 文件所有者ID的高16位
__le16 l_i_gid_high; // 文件所有組ID的高16位
__u32 l_i_reserved2;
} linux2;
struct {
__u8 h_i_frag; // 段號
__u8 h_i_fsize; // 段大小
__le16 h_i_mode_high;
__le16 h_i_uid_high; // 文件所有者ID的高16位
__le16 h_i_gid_high; // 文件所有組ID的高16位
__le32 h_i_author;
} hurd2;
struct {
__u8 m_i_frag; // 段號
__u8 m_i_fsize; // 段大小
__u16 m_pad1;
__u32 m_i_reserved2[2];
} masix2;
} osd2; // 操作系統相關數據
};
5.數據塊
數據塊中存放文件的內容,包括目錄表、擴展屬性、符號鏈接等。
 
二、目錄結構
在ext2文件系統中,目錄是作爲文件存儲的。根目錄總是在inode表的第二項,而其子目錄則在根目錄文件的內容中定義。目錄項在include/linux/ext2_fs.h文件中定義,其結構如下:
struct ext2_dir_entry_2 {
__le32 inode; // 文件入口的inode號,0表示該項未使用
__le16 rec_len; // 目錄項長度
__u8 name_len; // 文件名包含的字符數
__u8 file_type; // 文件類型
char name[255]; // 文件名
};
三、文件擴展屬性
文件的屬性大多數是位於該文件的inode結構中的標準屬性,也還包含其他一些擴展屬性(於系統中所有的inode相關,通常用於增加額外的功能),在fs/ext2/xattr.h文件中定義。
inode的i_file_acl字段中保存擴展屬性的塊的塊號。屬性頭部項位於屬性塊的起始位置,其後爲屬性入口項,而屬性值能根據屬性入口項找到所在位置。
1.屬性頭部項
struct ext2_xattr_header {
__le32 h_magic; // 標識碼,爲0xEA020000
__le32 h_refcount; // 屬性塊被鏈接的數目
__le32 h_blocks; // 用於擴展屬性的塊數
__le32 h_hash; // 所有屬性的哈希值
__u32 h_reserved[4];
};
2.屬性入口項
struct ext2_xattr_entry {
__u8 e_name_len; // 屬性名長度
__u8 e_name_index; // 屬性名索引
__le16 e_value_offs; // 屬性值在值塊中的偏移量
__le32 e_value_block; // 保存值的塊的塊號
__le32 e_value_size; // 屬性值長度
__le32 e_hash; // 屬性名和值的哈希值
char e_name[0]; // 屬性名
};
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章