linux 文件描述符與文件指針 詳解

簡單歸納:fd只是一個整數,在open時產生。起到一個索引的作用,進程通過PCB中的文件描述符表找到該fd所指向的文件指針file。

1,文件描述符

      文件描述符的操作(如: open)返回的是一個文件描述符,內核會在每個進程空間中維護一個文件描述符表, 所有打開的文件都將通過此表中的文件描述符來引用;
而流(如: fopen)返回的是一個FILE結構指針, FILE結構是包含有文件描述符的,FILE結構函數可以看作是對fd直接操作的系統調用的封裝, 它的優點是帶有I/O緩存

Linux支持各種各樣的文件系統格式,如ext2、ext3、reiserfs、FAT、NTFS、iso9660等等,不同的磁盤分區、光盤或其它存儲設備都有不同的文件系統格式,然而這些文件系統都可以mount到某個目錄下,使我們看到一個統一的目錄樹,各種文件系統上的目錄和文件我們用ls命令看起來是一樣的,讀寫操作用起來也都是一樣的,這是怎麼做到的呢?Linux內核在各種不同的文件系統格式之上做了一個抽象層,使得文件、目錄、讀寫訪問等概念成爲抽象層的概念,因此各種文件系統看起來用起來都一樣,這個抽象層稱爲虛擬文件系統(VFS,Virtual Filesystem)。上一節我們介紹了一種典型的文件系統在磁盤上的存儲佈局,這一節我們介紹運行時文件系統在內核中的表示。

2,內核數據結構

                      

3,files_struct 結構

     files_struct :每個進程在PCB(Process Control Block)即進程控制塊中都保存着一份文件描述符表,這個表在內核中的結構就是 files_struct ,文件描述符就是這個表的索引,文件描述表中每個表項都有一個指向已打開文件的指針,現在我們明確一下:已打開的文件在內核中用file結構體表示,文件描述符表中的指針指向file結構體。

4,file 結構

     1)文件狀態標誌 (f_flags)、當前文件讀寫位置 (f_pos)和引用計數(f_count

          在file結構體中維護File Status Flag(file結構體的成員f_flags)和當前讀寫位置(file結構體的成員f_pos)。在上圖中,進程1和進程2都打開同一文件,但是對應不同的file結構體,因此可以有不同的File Status Flag和讀寫位置。file結構體中比較重要的成員還有f_count,表示引用計數(Reference Count),後面我們會講到,dupfork等系統調用會導致多個文件描述符指向同一個file結構體,例如有fd1fd2都引用同一個file結構體,那麼它的引用計數就是2,當close(fd1)時並不會釋放file結構體,而只是把引用計數減到1,如果再close(fd2),引用計數就會減到0同時釋放file結構體,這才真的關閉了文件。

     2)file_operations結構體

          每個file結構體都指向一個file_operations結構體,這個結構體的成員都是函數指針,指向實現各種文件操作的內核函數。比如在用戶程序中read一個文件描述符,read通過系統調用進入內核,然後找到這個文件描述符所指向的file結構體,找到file結構體所指向的file_operations結構體,調用它的read成員所指向的內核函數以完成用戶請求。在用戶程序中調用lseekreadwriteioctlopen等函數,最終都由內核調用file_operations的各成員所指向的內核函數完成用戶請求。file_operations結構體中的release成員用於完成用戶程序的close請求,之所以叫release而不叫close是因爲它不一定真的關閉文件,而是減少引用計數,只有引用計數減到0才關閉文件。對於同一個文件系統上打開的常規文件來說,readwrite等文件操作的步驟和方法應該是一樣的,調用的函數應該是相同的,所以圖中的三個打開文件的file結構體指向同一個file_operations結構體。如果打開一個字符設備文件,那麼它的readwrite操作肯定和常規文件不一樣,不是讀寫磁盤的數據塊而是讀寫硬件設備,所以file結構體應該指向不同的file_operations結構體,其中的各種文件操作函數由該設備的驅動程序實現。

    3)dentry結構體

        每個file結構體都有一個指向dentry結構體的指針,“dentry”是directory entry(目錄項)的縮寫。我們傳給openstat等函數的參數的是一個路徑,例如/home/akaedu/a,需要根據路徑找到文件的inode。爲了減少讀盤次數,內核緩存了目錄的樹狀結構,稱爲dentry cache,其中每個節點是一個dentry結構體,只要沿着路徑各部分的dentry搜索即可,從根目錄/找到home目錄,然後找到akaedu目錄,然後找到文件a。dentry cache只保存最近訪問過的目錄項,如果要找的目錄項在cache中沒有,就要從磁盤讀到內存中。

             3.1)inode結構體

                  每個dentry結構體都有一個指針指向inode結構體。inode結構體保存着從磁盤inode讀上來的信息。在上圖的例子中,有兩個dentry,分別表示/home/akaedu/a/home/akaedu/b,它們都指向同一個inode,說明這兩個文件互爲硬鏈接。inode結構體中保存着從磁盤分區的inode讀上來信息,例如所有者、文件大小、文件類型和權限位等。每個inode結構體都有一個指向inode_operations結構體的指針,後者也是一組函數指針指向一些完成文件目錄操作的內核函數。和file_operations不同,inode_operations所指向的不是針對某一個文件進行操作的函數,而是影響文件和目錄佈局的函數,例如添加刪除文件和目錄、跟蹤符號鏈接等等,屬於同一文件系統的各inode結構體可以指向同一個inode_operations結構體。

              3.1.1)super_block結構體

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

        filedentryinodesuper_block這幾個結構體組成了VFS的核心概念。對於ext2文件系統來說,在磁盤存儲佈局上也有inode和超級塊的概念,所以很容易和VFS中的概念建立對應關係。而另外一些文件系統格式來自非UNIX系統(例如Windows的FAT32、NTFS),可能沒有inode或超級塊這樣的概念,但爲了能mount到Linux系統,也只好在驅動程序中硬湊一下,在Linux下看FAT32和NTFS分區會發現權限位是錯的,所有文件都是rwxrwxrwx,因爲它們本來就沒有inode和權限位的概念,這是硬湊出來的。

5,用圖表示一下

         

 6,內核中的數據結構

 

    

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章