1. 程式人生 > 其它 >20191305李天琦第十一章學習筆記

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