建体彩网|中彩网双色球连号|
?
快捷搜索:  as  test  1111  test aNd 8=8  test++aNd+8=8  as++aNd+8=8  as aNd 8=8

龍8娛樂國際手機版下載安裝:解析Linux中的VFS文件系統機制

?

本文闡述 Linux 中的文件系統部分,源代碼來自基于 IA32 的 2.4.20 內核。總體上說 Linux 下的文件系統主要可分為三大年夜塊:一是上層的文件系統的系統調用,二是虛擬文件系統 VFS(Virtual Filesystem Switch),三是掛載到 VFS 中的各實際文件系統,例如 ext2,jffs 等。本文偏重于經由過程詳細的代碼闡發來解釋 Linux 內核中 VFS 的內在機制,在這歷程中會涉及到上層文件系統調用和下層實際文件系統的若何掛載。文章試圖從一個對照高的角度來解釋 Linux 下的 VFS 文件系統機制。

1. 擇要

本文闡述 Linux 中的文件系統部分,源代碼來自基于 IA32 的 2.4.20 內核。總體上說 Linux 下的文件系統主要可分為三大年夜塊:一是上層的文件系統的系統調用,二是虛擬文件系統 VFS(Virtual Filesystem Switch),三是掛載到 VFS 中的各實際文件系統,例如 ext2,jffs 等。本文偏重于經由過程詳細的代碼闡發來解釋 Linux 內核中 VFS 的內在機制,在這歷程中會涉及到上層文件系統調用和下層實際文件系統的若何掛載。文章試圖從一個對照高的角度來解釋 Linux 下的 VFS 文件系統機制,以是在論述中更偏重于全部模塊的主脈絡,而不拘泥于細節,同時配有多少張插圖,以贊助讀者理解。

相對來說,VFS 部分的代碼對照繁瑣繁雜,盼望讀者在涉獵完本文之后,能對 Linux 下的 VFS 整體運作機制有個清楚的理解。建議讀者在涉獵本文前,先考試測驗著自己涉獵一下文件系統的源代碼,以便建立起 Linux 下文件系統最基礎的觀點,比如至少應認識 super block, dentry, inode,vfsmount 等數據布局所表示的意義,這樣再來涉獵本文以便加深理解。

2. VFS 概述

VFS 是一種軟件機制,大概稱它為 Linux 的文件系統治理者更確切點,與它相關的數據布局只存在于物理內存傍邊。以是在每次系統初始化時代,Linux 都首先要在內存傍邊構造一棵 VFS 的目錄樹(在 Linux 的源代碼里稱之為 namespace),實際上就是在內存中建立響應的數據布局。VFS 目錄樹在 Linux 的文件系統模塊中是個很緊張的觀點,盼望讀者不要將其與實際文件系統目錄樹肴雜,在筆者看來,VFS 中的各目錄其主要用途是用來供給實際文件系統的掛載點,當然在 VFS 中也會涉及到文件級的操作,本文不闡述這種環境。下文提到目錄樹或目錄,假如不分外闡明,均指 VFS 的目錄樹或目錄。圖 1 是一種可能的目錄樹在內存中的影像:

圖 1:VFS 目錄樹布局

3. 文件系統的注冊

這里的文件系統是指可能會被掛載到目錄樹中的各個實際文件系統,所謂實際文件系統,等于指VFS 中的實際操作終極要經由過程它們來完成而已,并不料味著它們必然要存在于某種特定的存儲設備上。比如在筆者的 Linux 機械下就注冊有 "rootfs"、"proc"、"ext2"、"sockfs" 等十幾種文件系統。

3.1 數據布局

在 Linux 源代碼中,每種實際的文件系統用以下的數據布局表示:

struct file_system_type {

const char *name;

int fs_flags;

struct super_block *(*read_super) (struct super_block *, void *, int);

struct module *owner;

struct file_system_type * next;

struct list_head fs_supers;

};

注冊歷程實際上將表示各實際文件系統的 struct file_system_type 數據布局的實例化,然后形成一個鏈表,內核頂用一個名為 file_systems 的全局變量來指向該鏈表的表頭。

3.2 注冊 rootfs 文件系統

在浩繁的實際文件系統中,之以是零丁先容 rootfs 文件系統的注冊歷程,其實是由于該文件系統 VFS 的關系太過親昵,假如說 ext2/ext3 是 Linux 的本土文件系統,那么 rootfs 文件系統則是 VFS 存在的根基。一樣平常文件系統的注冊都是經由過程 module_init 宏以及 do_initcalls() 函數來完成(讀者可經由過程涉獵module_init 宏的聲明及 archi386vmlinux.lds 文件來理解這一歷程),然則 rootfs 的注冊卻是經由過程 init_rootfs() 這一初始化函數來完成,這意味著 rootfs 的注冊歷程是 Linux 內核初始化階段弗成瓜分的一部分。

2) 調用 get_sb_nodev() 函數在內存平分配一個超級塊布局 (struct super_block) sb,并初始化其部分成員變量,將成員 s_instances 插入到 rootfs 文件系統類型布局中的 fs_supers 指向的雙向鏈表中。

3) 經由過程 rootfs 文件系統中的 read_super 函數指針調用 ramfs_read_super() 函數。還記適合初注冊rootfs 文件系統時,其成員 read_super 指針指向了 ramfs_read_s龍8娛樂國際手機版下載安裝uper() 函數,拜見圖2.

4) ramfs_read_super() 函數調用 ramfs_get_inode() 在內存平分配了一個 inode 布局 (struct inode) inode,并初始化其部分成員變量,此中對照緊張的有 i_op、i_fop 和 i_sb:

inode->i_op = &ramfs_dir_inode_operations;

inode->i_fop = &dcache_dir_ops;

inode->i_sb = sb;龍8娛樂國際手機版下載安裝

這使得將來經由過程文件系統調用對 VFS 提議的文件操作等指令將被 rootfs 文件系統中響應的函數接口所接收。

圖3

5) ramfs_read_super() 函數在分配和初始化了 inode 布局之后,會調用 d_alloc_root() 函數來為 VFS的目錄樹建立起關鍵的根目錄 (struct dentry)dentry,并將 dentry 中的 d_sb 指針指向 sb,d_inode 指針指向 inode。

6) 將 mnt 中的 mnt_sb 指針指向 sb,mnt_root 和 mnt_mountpoint 指針指向 dentry,而 mnt_parent指針則指向自身。

這樣,當 do_kern_mount() 函數返回時,以上分配出來的各數據布局和 rootfs 文件系統的關系將如上圖 3 所示。圖中 mnt、sb、inode、dentry 布局塊下方的數字表示它們在內存里被分配的先后順序。限于篇幅的緣故原由,各布局中只給出了部分成員變量,讀者可以對比源代碼根據圖中所示按圖索驥,以加深理解。

VFS 中各目錄的主要用途是為今后掛載文件系統供給掛載點。以是真正的文件操作照樣要經由過程掛載后的文件系統供給的功能接口來進行。

5. VFS 下目錄的建立

為了更好地輿解 VFS,下面我們用一個實際例子來看看 Linux 是若何在 VFS 的根目錄下建立一個新的目錄 "/dev" 的。

要在 VFS 中建立一個新的目錄,首先我們得對該目錄進行搜索,搜索的目的是找到將要建立的目錄其父目錄的相關信息,由于"皮之不存,毛將焉附"。比如要建立目錄 /home/ricard,那么首先必須沿目錄路徑進行逐層搜索,本例中先從根目錄找起,然后在根目錄下找到目錄 home,然后再往下,就是要新建的目錄名 ricard,那么前面講得要先對目錄搜索,在該例中就是要找到 ricard 這個新目錄的父目錄,也便是 home 目錄所對應的信息。

當然,假如搜索的歷程中發明差錯,比如要建目錄的父目錄并不存在,或者當提高程并無響應的權限等等,這種環境系統一定會調用相關歷程進行處置懲罰,對付此種環境,本文略過不提。

Linux 下用系統調用 sys_mkdir 來在 VFS 目錄樹中增添新的節點。同時為共同路徑搜索,引入了下面一個數據布局:

struct nameidata {

struct dentry *dentry;

struct vfsmount *mnt;

struct qstr last;

unsigned int flags;

int last_type;

};

這個數據布局在路徑搜索的歷程頂用來記錄相關信息,起著類似"路標"的感化。此中前兩項中的 dentry記錄的是要建目錄的父目錄的信息,mnt 成員接下來會解釋到。后三項記錄的是所查找路徑的著末一個節點(即待建目錄或文件)的信息。 現在為建立目錄 "/dev" 而調用 sys_mkdir("/dev", 0700),此中參數 0700 我們不去管它,它只是限制將要建立的目錄的某種模式。sys_mkdir 函數首先調用 path_lookup("/dev"龍8娛樂國際手機版下載安裝, LOOKUP_PARENT, &nd);來對路徑進行查找,此中 nd 為 struct nameidata nd 聲明的變量。在接下來的論述中,由于函數調用關系的繁瑣,為了凸起歷程主線,將不再嚴格按照函數的調用關系來進行描述。

這樣,當調用 sys_mkdir 成功地在 VFS 的目錄樹中新建立一個目錄 "/dev" 之后,在圖 3 的根基上,新的數據布局之間的關系便如圖 4 所示。圖 4 中顏色較深的兩個矩形塊 new_inode 和 new_entry 就是在sys_mkdir() 函數中新分配的內存布局,至于圖中的 mnt,sb,dentry,inode 等布局,仍為圖 3 中響應的數據布局,其互相之間的鏈接關系不變(圖中為避免過多的鏈接曲線,輕忽了一些鏈接關系,如 mnt 和 sb,dentry之間的鏈接,讀者可在圖 3 的根基上參看圖 4)。

必要強調一點龍8娛樂國際手機版下載安裝的是,既然 rootfs 文件系統被 mount 到了 VFS 樹上,那么它在 sys_mkdir 的歷程中一定會介入進來,事實上在全部歷程中,rootfs 文件系統中的 ramfs_mkdir、ramfs_lookup 等函數都曾被調用過。

圖 4: 在 VFS 樹中新建一目錄 "dev"

6. 在 VFS 樹中掛載文件系統

在本節中,將描述在 VFS 的目錄樹中向此中某個目錄(安裝點 mount point)上掛載(mount)一個文件系統的歷程。

這一歷程可簡單描述為:將某一設備(dev_name)上某一文件系統(file_system_type)安裝到VFS目錄樹上的某一安裝點(dir_name)。它要辦理的問題是:將對 VFS 目錄樹中某一目錄的操作轉化為詳細安裝到其上的實際文件系統的對應操作。比如說,假如將 hda2 上的根文件系統(假設文件系統類型為 ext2)安裝到了前一節中新建立的 "/dev" 目錄上(此時,"/dev" 目錄就成為了安裝點),那么安裝成功之后應達到這樣的目的,即:對 VFS 文件系統的 "/dev" 目錄履行 "ls" 指令,該條指令應能列出 hda2 上 ext2 文件系統的根目錄下所有的目錄和文件。很顯然,這里的關鍵是若何將對 VFS 樹中 "/dev" 的目錄操作指令轉化為安裝在其上的 ext2 這一實際文件系統中的響應指令。以是,接下來的論述將捉住若何轉化這一核心問題。在論述之前,讀者不妨自己設想一下 Linux 系統會若何辦理這一問題。記著:對目錄或文件的操作將終極由目錄或文件所對應的 inode 布局中的 i_op 和 i_fop 所指向的函數表中對應的函數來履行。以是,不管終極辦理規劃若何,都可以設想一定要經由過程將對 "/dev" 目錄所對應的 inode 中 i_op 和 i_fop 的調用轉換到 hda2 上根文件系統 ext2 中根龍8娛樂國際手機版下載安裝目錄所對應的 inode 中 i_op 和 i_fop 的操作。

do_kern_mount() 函數要做的工作,就是建立一新的安裝區域塊,詳細的內容在前面的章節 VFS 目錄樹的建立中已經論述過,這里不再贅述。

graft_tree() 函數要做的工作就是將 do_kern_mount() 函數返回的一 struct vfsmount 類型的變量加入到安裝系統鏈表中,同時 graft_tree() 還要將新分配的 struct vfsmount 類型的變量加入到一個hash表中,其目的我們將會在今后看到。

這樣,當 do_kern_mount() 函數返回時,在圖 4 的根基上,新的數據布局間的關系將如圖 5 所示。此中,紅圈區域里面的數據布局就是被稱做安裝區域塊的器械,此中不妨稱 e2_mnt 為安裝區域塊的指針,藍色箭頭曲線即構成了所謂的安裝系統鏈表。

在把這些函數調用后形成的數據布局關系理清楚之后,讓我們回到本章節開始提到的問題,即將 ext2 文件系統安裝到了 "/dev " 上之后,對該目錄上的操作若何轉化為對 ext2 文件系統響應的操作。從圖 5上看到,對 sys_mount() 函數的調用并沒有直接改變 "/dev " 目錄所對應的 inode (即圖中的 new_inode變量)布局中的 i_op 和 i_fop 指針,而且 "/dev " 所對應的 dentry(即圖中的 new_dentry 變量)布局仍舊在 VFS 的目錄樹中,并沒有被從此中暗藏起來,響應地,來自 hda2 上的 ext2 文件系統的根目錄所對應的 e2_entry 也不是如當初筆者所想象地那樣將 VFS 目錄樹中的 new_dentry 取而代之,那么這之間的轉化到底是若何實現的呢?

請讀者留意下面的這段代碼:

while (d_mountpoint(dentry) && __follow_down(&nd->mnt, &dentry));

這段代碼在 link_path_walk() 函數中被調用,而 link_path_walk() 終極又會被 path_lookup() 函數調用,假如讀者涉獵過 Linux 關于文件系統部分的代碼,應該知道 path_lookup() 函數在全部 Linux 繁瑣的文件系統代碼中屬于一個緊張的根基性的函數。簡單說來,這個函數用于解析文件路徑名,這里的文件路徑名和我們日常平凡在利用法度榜樣中所涉及到的觀點相同,比如在 Linux 的利用法度榜樣中 open 或 read 一個文件 /home/windfly.cs 時,這里的 /home/windfly.cs 便是文件路徑名,path_lookup() 函數的責任便是對文件路徑名中進行搜索,直到找到目標文件所屬目錄所對應的 dentry 或者目標直接便是一個目錄,筆者不想在有限的篇幅里具體解釋這個函數,讀者只要記著 path_lookup() 會返回一個目標目錄即可。

免責聲明:以上內容源自網絡,版權歸原作者所有,如有侵犯您的原創版權請告知,我們將盡快刪除相關內容。

您可能還會對下面的文章感興趣:

建体彩网
中福彩票群 内蒙古时时彩快乐3 金砖彩票首页 黑龙江快乐十分走势图号码分布最近 彩民怎么分析双色球 qq网球比分直播 股票融资利弊 码报哪个网站最准 海南4+1 下载黑龙江十一选五