天天看點

檔案描述符、檔案描述符表、目錄項、索引節點之間的總結聯系

檔案控制塊(目錄項/FCB):用來存放控制檔案需要的各種資訊的資料結構,以實作“按名存取”。一個FCB就是一個目錄項,當建立一個新檔案時,系統将配置設定一個FCB并存放在檔案目錄中,成為目錄項,目錄項中包含了檔案名+索引節點(inode)指針。

檔案描述符:open打開檔案到的是一個檔案描述符(索引号),存放在task_struct資料結構(程序控制塊)中,将task_struct結構和file結構挂鈎。

下面通過一個例子分析:

  1. 當在應用層調用open函數打開裝置檔案時,将會根據路徑名可以找到該裝置檔案對應的目錄項,再從目錄項中找到索引節點指針指向的struct inode結構體,通過其中描述的資訊可以知道接下來要操作的裝置類型(字元裝置還是塊裝置),還會配置設定一個struct file結構體。
  2. 根據struct inode結構體裡面記錄的裝置号,可以找到對應的驅動函數,也就是驅動層file_operation結構體中的open,read,write等。
  3. 任務完成,VFS層會給應用傳回一個檔案描述符(fd)。這個fd是和struct file結構體對應的,通過fd可以将程序的task_struct資料結構和file結構挂鈎起來。接下來上層應用程式就可以通過fd找到對應的struct file,進而找到對應的驅動函數。

接着上面的流程:

對打開的裝置檔案通過fd作參進行write函數調用,通過系統調用陷入核心,執行對應的sys_write()底層函數,并根據傳入的檔案描述符fd作為下标,在task_struct結構體中找到對應files指針指向的file_struct結構體數組對應的數組項。

該數組項指向一個file結構體,裡面存放了目錄項的指針,還有file_operation的指針。之後根據指針,找到該檔案對應的file_opration中的操作函數,和目錄項指向的該裝置檔案的inode結構體。inode結構體表示為裝置檔案時候裡面存放了關于該裝置的主裝置号,次裝置号,裝置類型等等,當inode用于表示一般檔案的時候,裡面存放了檔案中字元流到盤塊号的映射關系,根據inode找到盤塊号,構造bio請求,優化合并,放入電梯隊列,根據盤塊号算出磁盤的CHS,最終操作實體位址,從磁盤寫入/讀出資料;

檔案描述符、檔案描述符表、目錄項、索引節點之間的總結聯系

                         Linux檔案系統邏輯結構圖

更詳細的分析可以看下文:轉自:https://blog.csdn.net/yr12Dong/article/details/79480509

檔案描述符、檔案描述符表、打開檔案表、目錄項、索引節點之間的聯系如下圖所示:

檔案描述符、檔案描述符表、目錄項、索引節點之間的總結聯系

每個程序在PCB(Process Control Block)中都儲存着一份檔案描述符表,檔案描述符就是這個表的索引,每個表項都有一個指向已打開檔案的指針,已打開的檔案在核心中用file結構體表示,檔案描述符表中的指針指向file結構體。

    在file結構體中維護File Status Flag(file結構體的成員f_flags)和目前讀寫位置(file結構體的成員f_pos)。在上圖中,程序1和程序2都打開同一檔案,但是對應不同的file結構體,是以可以有不同的File Status Flag和讀寫位置。file結構體中比較重要的成員還有f_count,表示引用計數(Reference Count)。dup、fork等系統調用會導緻多個檔案描述符指向同一個file結構體,例如有fd1和fd2都引用同一個file結構體,那麼它的引用計數就是2,當close(fd1)時并不會釋放file結構體,而隻是把引用計數減到1,如果再close(fd2),引用計數就會減到0同時釋放file結構體,這才真的關閉了檔案。

    每個file結構體都指向一個file_operations結構體,這個結構體的成員都是函數指針,指向實作各種檔案操作的核心函數。比如在使用者程式中read一個檔案描述符,read通過系統調用進入核心,然後找到這個檔案描述符所指向的file結構體,找到file結構體所指向的file_operations結構體,調用它的read成員所指向的核心函數以完成使用者請求。在使用者程式中調用lseek、read、write、ioctl、open等函數,最終都由核心調用file_operations的各成員所指向的核心函數完成使用者請求。file_operations結構體中的release成員用于完成使用者程式的close請求,之是以叫release而不叫close是因為它不一定真的關閉檔案,而是減少引用計數,隻有引用計數減到0才關閉檔案。對于同一個檔案系統上打開的正常檔案來說,read、write等檔案操作的步驟和方法應該是一樣的,調用的函數應該是相同的,是以圖中的三個打開檔案的file結構體指向同一個file_operations結構體。如果打開一個字元裝置檔案,那麼它的read、write操作肯定和正常檔案不一樣,不是讀寫磁盤的資料塊而是讀寫硬體裝置,是以file結構體應該指向不同的file_operations結構體,其中的各種檔案操作函數由該裝置的驅動程式實作。

    每個file結構體都有一個指向dentry結構體的指針,“dentry”是directory entry(目錄項)的縮寫。open、stat等函數的參數的是一個路徑,例如/home/akaedu/a,需要根據路徑找到檔案的inode。為了減少讀盤次數,核心緩存了目錄的樹狀結構,稱為dentry cache,其中每個節點是一個dentry結構體,隻要沿着路徑各部分的dentry搜尋即可,從根目錄/找到home目錄,然後找到akaedu目錄,然後找到檔案a。dentry cache隻儲存最近通路過的目錄項,如果要找的目錄項在cache中沒有,就要從磁盤讀到記憶體中。(原理有點類似于多級頁表)

    每個dentry結構體都有一個指針指向inode結構體。inode結構體儲存着從磁盤inode讀上來的資訊。在上圖的例子中,有兩個dentry,分别表示/home/akaedu/a和/home/akaedu/b,它們(檔案目錄項)都指向同一個inode,說明這兩個檔案互為硬連結。inode結構體中儲存着從磁盤分區的inode讀上來資訊,例如所有者、檔案大小、檔案類型和權限位等。每個inode結構體都有一個指向inode_operations結構體的指針,後者也是一組函數指針指向一些完成檔案目錄操作的核心函數。和file_operations不同,inode_operations所指向的不是針對某一個檔案進行操作的函數,而是影響檔案和目錄布局的函數,例如添加删除檔案和目錄、跟蹤符号連結等等,屬于同一檔案系統的各inode結構體可以指向同一個inode_operations結構體。

    inode結構體有一個指向super_block結構體的指針。super_block結構體儲存着從磁盤分區的超級塊讀上來的資訊,例如檔案系統類型、塊大小等。super_block結構體的s_root成員是一個指向dentry的指針,表示這個檔案系統的根目錄被mount到哪裡,在上圖的例子中這個分區被mount到/home目錄下。

    file、dentry、inode、super_block這幾個結構體組成了VFS的核心概念。對于ext2檔案系統來說,在磁盤存儲布局上也有inode和超級塊的概念,是以很容易和VFS中的概念建立對應關系。

繼續閱讀