Linux系統篇-文件系統&虛擬文件系統

看了以前的關於Linux內存管理和進程調度的文章,相比讀者們應該對Linux有了大體的瞭解,本文的主題是Linux虛擬文件系統。閒話少說,開始!node

1.軟連接和硬連接的區別緩存

咱們知道文件都有文件名與數據,數據分兩部分:用戶數據 (user data) 與元數據 (metadata)。用戶數據,即文件數據塊 (data block),數據塊是記錄文件真實內容的地方;而元數據則是文件的附加屬性,如文件大小、建立時間、全部者等信息。在 Linux 中,元數據中的 inode 號(inode 是文件元數據的一部分但其並不包含文件名,inode 號即索引節點號)纔是文件的惟一標識而非文件名。文件名僅是爲了方便人們的記憶和使用,系統或程序經過 inode 號尋找正確的文件數據塊安全

爲解決文件的共享使用,Linux 系統引入了兩種連接:硬連接 (hard link) 與軟連接(又稱符號連接,即 soft link 或 symbolic link)。連接爲 Linux 系統解決了文件的共享使用,還帶來了隱藏文件路徑、增長權限安全及節省存儲等好處。若一個 inode 號對應多個文件名,則稱這些文件爲硬連接。硬連接就是同一個文件使用了多個別名網絡

因爲硬連接是有着相同 inode 號僅文件名不一樣的文件,所以硬連接存在如下幾點特性:數據結構

  • 文件有相同的 inode 及 data block;
  • 只能對已存在的文件進行建立;
  • 不能交叉文件系統進行硬連接的建立;
  • 不能對目錄進行建立,只可對文件建立;
  • 刪除一個硬連接文件並不影響其餘有相同 inode 號的文件。

inode 號僅在各文件系統下是惟一的,當 Linux 掛載多個文件系統後將出現 inode 號重複的現象,所以硬連接建立時不可跨文件系統socket

軟連接與硬連接不一樣,若文件用戶數據塊中存放的內容是另外一文件的路徑名的指向,則該文件就是軟鏈接。軟連接就是一個普通文件,只是數據塊內容有點特殊。軟連接有着本身的 inode 號以及用戶數據塊。所以軟連接的建立與使用沒有相似硬連接的諸多限制:ide

  • 軟連接有本身的文件屬性及權限等;
  • 可對不存在的文件或目錄建立軟連接;
  • 軟連接可交叉文件系統;
  • 軟連接可對文件或目錄建立;
  • 建立軟連接時,連接計數 i_nlink 不會增長;
  • 刪除軟連接並不影響被指向的文件,但若被指向的原文件被刪除,則相關軟鏈接被稱爲死連接(即 dangling link,若被指向路徑文件被從新建立,死連接可恢復爲正常的軟連接)。
  • 通常狀況下,文件名和inode號碼是"一一對應"關係,每一個inode號碼對應一個文件名。可是,Unix/Linux系統容許,多個文件名指向同一個inode號碼。這意味着,能夠用不一樣的文件名訪問一樣的內容;對文件內容進行修改,會影響到全部文件名;可是,刪除一個文件名,不影響另外一個文件名的訪問。這種狀況就被稱爲"硬連接"(hard link)。

2.Linux VFS函數

Linux 有着極其豐富的文件系統,大致上可分以下幾類:操作系統

  1. 網絡文件系統,如 nfs、cifs 等;
  2. 磁盤文件系統,如 ext四、ext3 等;
  3. 特殊文件系統,如 proc、sysfs、ramfs、tmpfs 等。

實現以上這些文件系統並在 Linux 下共存的基礎就是 Linux VFS(Virtual File System 又稱 Virtual Filesystem Switch),即虛擬文件系統。VFS 做爲一個通用的文件系統,抽象了文件系統的四個基本概念:文件、目錄項 (dentry)、索引節點 (inode) 及掛載點,其在內核中爲用戶空間層的文件系統提供了相關的接口。VFS 實現了 open()、read() 等系統調並使得 cp 等用戶空間程序可跨文件系統。VFS 真正實現了上述內容中:在 Linux 中除進程以外一切皆是文件。設計

Linux VFS 存在四個基本對象:超級塊對象 (superblock object)、索引節點對象 (inode object)、目錄項對象 (dentry object) 及文件對象 (file object)。超級塊對象表明一個已安裝的文件系統;索引節點對象表明一個文件;目錄項對象表明一個目錄項,如設備文件 event5 在路徑 /dev/input/event5 中,其存在四個目錄項對象:/ 、dev/ 、input/ 及 event5。文件對象表明由進程打開的文件。爲文件路徑的快速解析,Linux VFS 設計了目錄項緩存(Directory Entry Cache,即 dcache)。

3.文件的打開過程

open()系統調用的過程以下:

1.查看system-wide open-file table(系統打開文件表)中是否有該文件,即查看該文件是否已經被其餘進程打開了

2.若是存在,那麼該進程會在本身的per-process open-file table(進程打開文件表)中,創建一個項目,指向system-wide open-file table中的該文件

3.若是不存在,則須要根據file name在directory中查找該file,一般directory中的部份內容在cache中,這樣能夠加快搜索速度。

4.一旦文件被找到,那麼FCB(file control block)文件控制塊會被複制到system-wide open-file table中,該表不只僅保存FCB,並且記錄每一個文件被多少個進程打開

5.接下來,在per-process open-file table(進程打開文件表)中,簡直一個entry,指向進程打開文件表中該項目

當進程close()一個文件時:

1.該進程的per-process open-flle table中的對應項會被刪除,系統打開表中的該文件計數器會減1

2.若是系統打開表中的計算爲0,那麼刪除該文件項

4.inode的理解

操做系統讀取硬盤的時候,不會一個個扇區地讀取,這樣效率過低,而是一次性連續讀取多個扇區,即一次性讀取一個"塊"(block)。這種由多個扇區組成的"塊",是文件存取的最小單位。"塊"的大小,最多見的是4KB,即連續八個 sector組成一個 block。

文件數據都儲存在"塊"中,那麼很顯然,咱們還必須找到一個地方儲存文件的元信息,好比文件的建立者、文件的建立日期、文件的大小等等。這種儲存文件元信息的區域就叫作inode,中文譯名爲"索引節點"。

inode包含文件的元信息,具體來講有如下內容:

* 文件的字節數

* 文件擁有者的User ID

* 文件的Group ID

* 文件的讀、寫、執行權限

* 文件的時間戳,共有三個:ctime指inode上一次變更的時間,mtime指文件內容上一次變更的時間,atime指文件上一次打開的時間。

* 連接數,即有多少文件名指向這個inode

* 文件數據block的位置

除了文件名之外的全部文件信息,都存在inode之中

每一個inode都有一個號碼,操做系統用inode號碼來識別不一樣的文件。

表面上,用戶經過文件名,打開文件。實際上,系統內部這個過程分紅三步:首先,系統找到這個文件名對應的inode號;其次,經過inode號,獲取inode信息;最後,根據inode信息,找到文件數據所在的block,讀出數據。

目錄(directory)也是一種文件,目錄文件的結構很是簡單,就是一系列目錄項(dirent)的列表。每一個目錄項,由兩部分組成:所包含文件的文件名,以及該文件名對應的inode號碼。

數據塊尋址

inode中記錄了文件數據塊的位置,有三種尋址方式:direct blocks直接指向數據塊;single indirect指向一個block,該block中爲數據塊的指針;double indirect,兩級block

Linux系統篇-文件系統&虛擬文件系統(很是重要!)

5.文件描述符

在Linux系統中一切皆能夠當作是文件,文件又可分爲:普通文件、目錄文件、連接文件和設備文件。文件描述符(file descriptor)是內核爲了高效管理已被打開的文件所建立的索引,其是一個非負整數(一般是小整數),用於指代被打開的文件,全部執行I/O操做的系統調用都經過文件描述符。程序剛剛啓動的時候,0是標準輸入,1是標準輸出,2是標準錯誤。若是此時去打開一個新的文件,它的文件描述符會是3。POSIX標準要求每次打開文件時(含socket)必須使用當前進程中最小可用的文件描述符號碼

文件描述符是系統的一個重要資源,雖說系統內存有多少就能夠打開多少的文件描述符,可是在實際實現過程當中內核是會作相應的處理的,通常最大打開文件數會是系統內存的10%(以KB來計算)(稱之爲系統級限制)

6.文件描述符和打開文件之間的關係

每個文件描述符會與一個打開文件相對應,同時,不一樣的文件描述符也會指向同一個文件。相同的文件能夠被不一樣的進程打開也能夠在同一個進程中被屢次打開。系統爲每個進程維護了一個文件描述符表,該表的值都是從0開始的,因此在不一樣的進程中你會看到相同的文件描述符,這種狀況下相同文件描述符有可能指向同一個文件,也有可能指向不一樣的文件。具體狀況要具體分析,要理解具體其概況如何,須要查看由內核維護的3個數據結構。

1. 進程級的文件描述符表

2. 系統級的打開文件描述符表

3. 文件系統的i-node表

進程級的描述符表的每一條目記錄了單個文件描述符的相關信息。

1. 控制文件描述符操做的一組標誌。(目前,此類標誌僅定義了一個,即close-on-exec標誌)

2. 對打開文件句柄的引用

內核對全部打開的文件的文件維護有一個系統級的描述符表格(open file description table)。有時,也稱之爲打開文件表(open file table),並將表格中各條目稱爲打開文件句柄(open file handle)。一個打開文件句柄存儲了與一個打開文件相關的所有信息,以下所示:

1. 當前文件偏移量(調用read()和write()時更新,或使用lseek()直接修改)

2. 打開文件時所使用的狀態標識(即,open()的flags參數)

3. 文件訪問模式(如調用open()時所設置的只讀模式、只寫模式或讀寫模式)

4. 與信號驅動相關的設置

5. 對該文件i-node對象的引用

6. 文件類型(例如:常規文件、套接字或FIFO)和訪問權限

7. 一個指針,指向該文件所持有的鎖列表

8. 文件的各類屬性,包括文件大小以及與不一樣類型操做相關的時間戳

在進程A中,文件描述符1和30都指向了同一個打開的文件句柄(標號23)。這多是經過調用dup()、dup2()、fcntl()或者對同一個文件屢次調用了open()函數而造成的。

進程A的文件描述符2和進程B的文件描述符2都指向了同一個打開的文件句柄(標號73)。這種情形多是在調用fork()後出現的(即,進程A、B是父子進程關係),或者當某進程經過UNIX域套接字將一個打開的文件描述符傳遞給另外一個進程時,也會發生。再者是不一樣的進程獨自去調用open函數打開了同一個文件,此時進程內部的描述符正好分配到與其餘進程打開該文件的描述符同樣。

此外,進程A的描述符0和進程B的描述符3分別指向不一樣的打開文件句柄,但這些句柄均指向i-node表的相同條目(1976),換言之,指向同一個文件。發生這種狀況是由於每一個進程各自對同一個文件發起了open()調用。同一個進程兩次打開同一個文件,也會發生相似狀況。

7. 總結

1. 因爲進程級文件描述符表的存在,不一樣的進程中會出現相同的文件描述符,它們可能指向同一個文件,也可能指向不一樣的文件

2. 兩個不一樣的文件描述符,若指向同一個打開文件句柄,將共享同一文件偏移量。所以,若是經過其中一個文件描述符來修改文件偏移量(由調用read()、write()或lseek()所致),那麼從另外一個描述符中也會觀察到變化,不管這兩個文件描述符是否屬於不一樣進程,仍是同一個進程,狀況都是如此。

3. 要獲取和修改打開的文件標誌(例如:O_APPEND、O_NONBLOCK和O_ASYNC),可執行fcntl()的F_GETFL和F_SETFL操做,其對做用域的約束與上一條頗爲相似。

4. 文件描述符標誌(即,close-on-exec)爲進程和文件描述符所私有。對這一標誌的修改將不會影響同一進程或不一樣進程中的其餘文件描述符

相關文章
相關標籤/搜索