20191305李天琦第十一章學習筆記
20191305李天琦第十一章學習筆記
摘要:本章討論EXT2檔案系統。只要充分了解一個檔案系統,就可以輕鬆改編其他任何檔案系統。本章首先描述了EXT2檔案系統在Linux中的歷史地位以及EXT3/EXT4檔案系統的當前狀況;用程式設計示例展示了各種EXT2資料結構以及如何遍歷EXT2檔案系統樹;介紹瞭如何實現支援Linux核心中所有檔案操作的EXT2檔案系統;展示瞭如何通過虛擬磁碟的mount_root來構建基本檔案系統;將檔案系統的實現劃分為3個級別,級別1擴充套件了基本檔案系統,以實現檔案系統樹,級別2實現了檔案內容的讀/寫操作,級別3實現了檔案系統的掛載/裝載和檔案保護;描述了各個級別檔案系統函式的演算法,並通過程式設計示例演示了它們的實現過程;將所有級別融合到一個程式設計專案中;最後,將所有程式設計示例和練習整合到一個完全有效的檔案系統中。
11.1 EXT2檔案系統
EXT3是EXT2的擴充套件,增加的主要內容是一個日誌檔案,將檔案系統的變更記錄在日誌中,可以在檔案系統崩潰時更快從錯誤中恢復。EXT4分配連續的磁碟塊區。
11.2 EXT2檔案系統資料結構
1.通過mkfs建立虛擬磁碟
在 Linux下,命令
mke2fs [-b blksize -N ninodes] device nblocks
在裝置上建立一個帶有nblocks個塊(每個塊大小為blksize位元組)和 ninodes 個索引節點的EXT2檔案系統。裝置可以是真實裝置,也可以是虛擬磁碟檔案。如果未指定blksize.則預設塊大小為1KB。如果未指定ninoides,mke2fs將根據 nblocks計算一個預設的ninodes數。得到的 EXT2檔案系統可在 Linux 中使用。舉個具體的例子,下面的命令
dd if=/dev/zero of=vdisk bs=1024 count=1440
mke2fs vdisk 1440
可在一個名為vdisk的虛擬磁碟檔案上建立一個EXT2檔案系統,有1440個大小為1KB 的塊。
2.Block#0:引導塊 B0是引導塊,檔案系統不會使用它。它用來容納一個載入程式,從磁碟引導作業系統。
3.Block#1:超級塊(在硬碟分割槽中位元組偏移量為1024) B1是超級塊,用於容納整個檔案系統的資訊。
struct ext2_guper_block {
u32 s_inodes_count; /* Inodes count */
u32 s_blocks_count; /* Blocks count*/
u32 s_r_blocks_count; /* Reserved blocks count */
u32 s_free_blocks_count; / * Free blocks count */
u32 s_free_inodes_count; /* Free inodes count */
u32 s_first__data_blook; /* First Data Block */
u32 s_log_block_size; /* Block size */
u32 s_log_cluster_size; /* Allocation cluster size */
u32 s_blocks_per_group; /* # Blocks per group*/
u32 s_clusters_per_group; /*# Fragments per group */
u32 s_inodes_per_group; /* # Inodes per group*/
u32 s_mtime;u32 s_wtime; /* Mount time */
u16 s_mnt_count; /* Write time */
s16 s_max_mnt_count; /_Mount_count/L
u16 8_magic; /* Magic signature */
// more non-essential fields
u16 s_inode_size; /* size of inode structure*/
}
4.Block#2∶塊組描述符塊(硬碟上的s first data block+1)EXT2將磁碟塊分成幾個組。每個組有8192個塊(硬碟上的大小為32K)。每組用一個塊組描述符結構體來描述。
struct ext2_group_desc {
u32 bg_block_bitmap; // Bmap block number
u32 bg_inode_bitmap; // Imap block number
u32 bg_inode_table; // Inodes begin block number
u16 bg_free_blocks_count; // THESE are OBVIOUS
u16 bg_free_inodes_count;
ul6 bg_used_dirs_count;
u16 bg_pad; // ignore these
u32 bg_reserved[3];
};
5.Block#8∶塊點陣圖(Bmap)(bg block bitmap)點陣圖是用來表示某種項的位序列,例如磁碟塊或索引節點。點陣圖用於分配和回收項。在點陣圖中,0位表示對應項處於FREE狀態,1位表示對應項處於IN USE狀態。一個軟盤有1440個塊,但是 Block#0未被檔案系統使用。所以,點陣圖只有1439個有效位。無效位被視作INUSE,設定為1。
Block#9∶索引節點點陣圖(Imap)(bg inode bitmap)一個索引節點就是用來代表一個檔案的資料結構。EXT2檔案系統是使用有限數量的索引節點建立的。各索引節點的狀態用B9的Imap 中的一個位表示。在EXT2 FS中,前10個索引節點是預留的。所以,空 EXT2 FS的Imap 以10個1開頭,然後是0。無效位再次設定為1。
6.Block#10∶索引(開始)節點(bg inode table)每個檔案都用一個128位元組(EXT4中是256位元組)的唯一索引節點結構體表示。
struct ext2_inode {
u16 i_mode; // 16 bits=|tttt |ugs|rwx|rwx|rwxl
ul6 i_uid; // owner uid
u32 i_size; // file size in bytes
u32 i_atime; // time fields in seconds
u32 1_ctime; // since 00:00:00,1-1-1970
u32 i_mtime;
u32 i_dtime;
i_gid; // group ID u16
u16 i_links_count; // hard-link count
u32 i_blocks;u32 i_flags; // number of 512-byte sectors
u32 i_reservedl; // IGNORE // IGNORE
u32 i_block[15]; // See details below
u32 i_pad[7]; // for inode size = 128 bytes
}
直接塊: block[0]至iblock[11],指向直接磁碟塊。
間接塊:iblock[12]指向一個包含256個塊編號(對於1KB BLKSIZE)的磁碟塊,每個塊編號指向一個磁碟塊。
雙重間接塊:i block[13]指向一個指向 256個塊的塊,每個塊指向256個磁碟塊。
三重間接塊:iblock[14]是三重間接塊。對於"小型"EXT2檔案系統,可以忽略它。
7.資料塊
緊跟在索引節點塊後面的是檔案儲存資料塊。
8.目錄條目
struct ext2_dir_entry_2{
u32 inode; // inode number; count from 1,NOT 0
u16 rec_len; // this entry's length in bytes
u8 name_len; // name length in bytes
u8 file_type; // not used
char name[EXT2_NAME_LEN]; // name:1-255 chars,no ending NULL ;
};
目錄包含dir_entry 結構,dir_entry 是一種可擴充結構。名稱欄位包含1到255個字元,不含終止NULL。所以dir entry 的 rec len也各不相同。
11.3 郵差演算法
一個城市有M個街區,編號從0到M-1.每個街區有N座房子,編號從0到N-1.每座房子有一個唯一的街區地址,用(街區,房子)表示。已知某個街區地址BA=(街區,房子),怎麼把它轉換為線性地址LA,或者已知線性地址,怎麼轉換為街區地址?
Linear_address LA=N*block + house;
Block_address BA=(LA/N,LA%N);
1.C語言中的Test-Set-Clear位
struct bits{
unsigned int bit0 : 1; //bit0 field is a single bit
unsigned int bit123 : 3; // bit123 field is a range of 3 bits
unsigned int otherbits :27; // other bits field has 27 bits
unsigned int bit31 :1; // bit31 is the highest bit
}var;
2.將索引節點號轉換為磁碟上的索引節點
在 EXT2檔案系統中,每個檔案都有一個唯一的索引節點結構。在檔案系統磁碟上,索引節點從inode table塊開始。每個磁碟塊包含
INODES_PER_BLOCK = BLoCK_SIZE/sizeof(INODE)
個索引節點。每個索引節點都有一個唯一的索引節點號,ino=1,2,…,從1開始線性計數。已知一個ino,如1234,那麼哪個磁碟塊包含該索引節點,以及哪個索引節點在該塊中呢?我們需要知道磁碟塊號,因為需要通過塊來讀/寫一個真正的磁碟。
11.4程式設計示例
安裝ext2fs開發包:sudo apt-get install ext2fs-dev
11.5遍歷EXT2檔案系統樹
1.遍歷演算法
(1)讀取超級塊。檢查幻數s_magic(0xEF53),驗證它確實是 EXT2 FS。
(2)讀取塊組描述符塊(1+s_first_data_block),以訪問組0描述符。從塊組描述符的bg_ inode_table條目中找到索引節點的起始塊編號,並將其稱為InodesBeginBlock。
(3)讀取InodeBeginBlock,獲取/的索引節點,即INODE #2。
(4)將路徑名標記為元件字串,假設元件數量為 n。例如,如果路徑名=/a/b/c,則元件字串是"a""b""c",其中n=3。用name[0],name[1],…,name[n-1]來表示元件。
(5)從(3)中的根索引節點開始,在其資料塊中搜索 name[0]。為簡單起見,我們可以假設某個目錄中的條目數量很少,因此一個目錄索引節點只有12個直接資料塊。有了這個假設,就可以在12個(非零)直接塊中搜索 name[0]。目錄索引節點的每個資料塊都包含以下形式的 dir_entry結構體:
[ino rec_len name_len NAME] [ino rec_len name_len NAME] . . . . .
其中NAME是一系列nlen字元,不含終止NULL。對於每個資料塊,將該塊讀入記憶體並使用dir_entry*dp指向載入的資料塊。然後使用name_len將NAME提取為字串,並與name[0]進行比較。
(6)使用索引節點號ino 來定位相應的索引節點。回想前面的內容,ino 從1開始計數。使用郵差演算法計算包含索引節點的磁碟塊及其在該塊中的偏移量。
11.6EXT2檔案系統的實現
1.檔案系統的結構
(1)當前執行程序的PROC結構體;
(2)檔案系統的根指標;
(3)一個openTable條目;
(4)記憶體索引節點;
(5)已掛載的檔案系統表。
2.檔案系統的級別
第1級別實現了基本檔案系統樹,以實現指定函式,第2級別實現了檔案內容的讀/寫函式,第3級別實現了檔案系統的掛載、解除安裝和檔案保護。
11.7基本檔案系統
1.type.h檔案
這類檔案包含EXT2檔案系統的資料結構型別,比如超塊、組描述符、索引節點和目錄條目結構。此外,它還包含開啟檔案表、掛載表、PROC結構體和檔案系統常數。
2.global.c檔案
這類檔案包含檔案系統的全域性變數。全域性變數的例子有:
MINODE minode [NMINODE]; // in memory INODEs
MTABLE mtable [NMTABLE]; // mount tables
OFT oft [NOFT]; // Opened file instance
PROC proc[NPROC]PROC ] // PROC structures
PROC *running; // current executing