1. 程式人生 > >linux系統檔案描述符file descriptor與inode的相關知識

linux系統檔案描述符file descriptor與inode的相關知識

每個程序在Linux核心中都有一個task_struct結構體來維護程序相關的 資訊,稱為程序描述符(Process Descriptor),而在作業系統理論中稱為程序控制塊 (PCB,Process Control Block)。task_struct中有一個指標(struct files_struct *files; )指向files_struct結構體,稱為檔案 描述符表,其中每個表項包含一個指向已開啟的檔案的指標,如下圖所示。



         使用者程式不能直接訪問核心中的檔案描述符表,而只能使用檔案描述符表的索引 (即0、1、2、3這些數字),這些索引就稱為檔案描述符(File Descriptor),用int 型變數儲存。 當呼叫open 開啟一個檔案或建立一個新檔案時,核心分配一個檔案描述符並返回給使用者程式,該檔案描述符表項中的指標指向新開啟的檔案。當讀寫檔案時,使用者程式把檔案描述符傳給read 或write ,核心根據檔案描述符找到相應的表項,再通過表項中的指標找到相應的檔案。

       已開啟的檔案在核心中用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 成員所指向的核心函式(如核心程式碼中實現函式可能為sys_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結 構體的指標,後者也是一組函式指標指向一些完成檔案目錄操作的核心函式。 

     inode和dentry

    這張圖再次描述了fd-dentry->inode superblock 和file物理儲存的一個對映關係。

       和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中的概念建立對應關係。而 另外一些檔案系統格式來自非UNIX系統(例如Windows的FAT32、NTFS),可能沒有inode或超 級塊這樣的概念,但為了能mount 到Linux系統,也只好在驅動程式中硬湊一下,在Linux下 看FAT32和NTFS分割槽會發現許可權位是錯的,所有檔案都是rwxrwxrwx ,因為它們本來就沒 有inode和許可權位的概念,這是硬湊出來的。

        在UNIX系統中,使用者通過終端登入系統後得到一個Shell程序,這個終端成為Shell程序的控制終端 (Controlling Terminal),控制終端是儲存在PCB中的資訊,而我們知 道fork 會複製PCB中的資訊,因此由Shell程序啟動的其它程序的控制終端也是這個終端。
預設情況 下(沒有重定向),每個程序的標準輸入(stdin)、標準輸出(stdout)和標準錯誤輸出(stderr)都指向控制終端,因為在程式啟動時(在main 函式還 沒開始執行之前)會自動把控制終端開啟三次,分別賦給三個FILE *指 針stdin 、stdout和stderr,這三個檔案指標是libc 中定義的全域性變數,這三個檔案的描述符分別是0、1、2,儲存在相應的FILE 結構體中。程序從標準輸入讀也就是讀使用者的鍵盤輸入,程序往標準輸出或標準錯誤輸出寫也就是輸出到顯示器上
標頭檔案unistd.h 中有如下的巨集定義來表示這三個檔案描述符: 
#define STDIN_FILENO 0 
#define STDOUT_FILENO 1 
#define STDERR_FILENO 2


       每個程序都可以通過一個特殊的裝置檔案/dev/tty(字元裝置c) 訪問它的控制終端。事實上每個終端裝置都對應一個不同的裝置檔案,/dev/tty 提供了一個通用的介面,一個程序要訪問它的控制終端既可以通過/dev/tty 也可以通過該終端裝置所對應的裝置檔案來訪問。ttyname函式可以由檔案描述符查出對應的檔名,該檔案描述符必須指向一個終端裝置而不 能是任意檔案。不同的終端所對應的裝置檔名可以是/dev/pts/?, /dev/tty?等

[email protected]:~$ ls -l /dev/tty 

crw-rw-rw- 1 root tty 5, 0 Jan 29 09:46 /dev/tty 


       開頭的c表示檔案型別是字元裝置。中間的5, 0是它的裝置號,主裝置號5,次裝置號0,主裝置號 標識核心中的一個裝置驅動程式,次裝置號標識該裝置驅動程式管理的一個裝置。核心通過裝置號 找到相應的驅動程式,完成對該裝置的操作。我們知道常規檔案的這一列應該顯示檔案尺寸,而設 備檔案的這一列顯示裝置號,這表明裝置檔案是沒有檔案尺寸這個屬性的,因為裝置檔案在磁碟上 不儲存資料,對裝置檔案做讀寫操作並不是讀寫磁碟上的資料,而是在讀寫裝置。


       由open 返回的檔案描述符一定是該程序尚未使用的最小描述符。由於程式啟動時自動開啟檔案描述符0、1、2,因此第一次呼叫open開啟檔案通常會返回描述符3,再呼叫open 就會返回4。可以利用 這一點在標準輸入、標準輸出或標準錯誤輸出上開啟一個新檔案,實現重定向的功能。例如,首先 呼叫close 關閉檔案描述符1,然後呼叫open 開啟一個常規檔案,則一定會返回檔案描述符1,這時候標準輸出就不再是終端,而是一個常規檔案了,再呼叫printf就不會列印到螢幕上,而是寫到這 個檔案中了。


      需要說明的是,當一個程序終止時,核心對該程序所有尚未關閉的 檔案描述符呼叫close 關閉,所以即使使用者程式不呼叫close ,在終止時核心也會自動關閉它開啟的 所有檔案。但是對於一個長年累月執行的程式(比如網路伺服器),開啟的檔案描述符一定要記得 關閉,否則隨著開啟的檔案越來越多,會佔用大量檔案描述符和系統資源。

------------------------------------------------------------------------------------------------------------------------------------

傳統的Unix既有v節點(vnode)也有i節點(inode),vnode的資料結構中包含了inode資訊。但在Linux中沒有使用vnode,而使用了通用inode。“實現雖不同,但在概念上是一樣的。”
vnode (“virtual node”)僅在檔案開啟的時候,才出現的;而inode定位檔案在磁碟的位置,它的資訊本身是儲存在磁碟等上的,當開啟檔案的時候從磁碟上讀入記憶體。


inode結構體記錄了很多關於檔案的資訊,比如檔案長度,檔案所在的裝置,檔案的物理位置,建立、修改和更新時間等等,特別的,它不包含檔名!目錄下的所有檔名和目錄名都儲存在目錄的資料塊中,即如下圖的目錄塊。對於常規檔案,檔案的資料儲存在資料塊中,一個檔案通常佔用一個inode,但往往要佔用多個數據塊,資料塊是在分割槽進行檔案系統格式化時所指定的“最小儲存單位”,塊的大小為扇區的2^n倍,一個扇區512B。


  • 如果多個inode指向同一個資料塊的時候,是不是就可以實現熟悉的連結了?!這就是軟連線的原理,新建一個檔案(一個符號連結檔案,檔案的屬性中有明確說明它是一個符號連結檔案),為需要連結的檔案分配一個新的inode,然後指向同一個資料塊。當我們用ls 檢視某個目錄或檔案時,如果加上-i 引數,就可以看到inode節點了;比如ls -li lsfile.sh ,最前面的數值就是inode資訊。
  • 多個檔案共用一個inode,同樣可以實現連結?!這就是硬連結的原理,inode中有連結計數器,當增加一個檔案指向這個inode時,計數器增1。特別的,當計數器為0時候,檔案才真正從磁碟刪除。即ls -l 命令輸出中的第二欄。

相關推薦

linux系統檔案描述file descriptorinode相關知識

每個程序在Linux核心中都有一個task_struct結構體來維護程序相關的 資訊,稱為程序描述符(Process Descriptor),而在作業系統理論中稱為程序控制塊 (PCB,Process Control Block)。task_struct中有一個指標(

linux系統程式設計之基礎必備(三):檔案描述file descriptorinode相關知識

       每個程序在Linux核心中都有一個task_struct結構體來維護程序相關的 資訊,稱為程序描述符(Process Descriptor),而在作業系統理論中稱為程序控制塊 (PCB,Process Control Block)。task_struct中有一

Linux 檔案描述(file descriptor, fd)以及檔案描述操作dup(), dup2()

1.概述 在Linux系統中,一切皆可以看做是“檔案”,這裡“檔案”包括普通檔案、目錄檔案、連結檔案和裝置檔案等。而檔案描述符(file descriptor, 簡稱fd)是Linux核心所建立的索引,其目的為了高效管理已被開啟的“檔案”。其實,檔案描述符就是一個非負整數(

Linux檔案描述fb和檔案指標FILE*的聯絡區別

檔案描述符: linux中,當一個程序開啟一個檔案或者是建立一個新檔案時,核心向程序返回一個檔案描述符來標示該檔案。 檔案描述符是一個非負整數,實際上它是一個索引,指向核心為程序所維護的一個檔案記錄表。 任何程式執行起來都會開啟三個預設的流,標準輸入流,標準輸出流,標準錯誤流通

Linux檔案描述(fd) 檔案指標(FILE*)

一、檔案描述符(fd) 我們都知道在Linux下一切皆檔案。當然裝置也不例外,如果要對某個裝置進行操作,就不得不開啟此裝置檔案,開啟檔案就會獲得該檔案的檔案描述符fd( file discriptor), 它就是一個很小的整數,每個程序在PCB(Process

linux檔案描述fd和struct file結構體的釋放

簡單歸納:fd只是一個整數,在open時產生。起到一個索引的作用,程序通過PCB中的檔案描述符表找到該fd所指向的檔案指標filp。 檔案描述符的操作(如: open)返回的是一個檔案描述符,核心會在每個程序空間中維護一個檔案描述符表, 所有開啟的檔案都將通過此表中的檔

linux檔案描述

寫在前面,linux的描述符有程序描述符、檔案描述符、記憶體描述符。首先標題想了很久linux的描述符從哪裡說起,看了幾份資料後還是決定從程序描述符說起。但是此文章還是重點說的是檔案描述符。知識深度有限,如有錯誤,請指出。 程序描述符:linux為了管理程序,核心必須對每個程序所作的事情進行清楚的描述,

深入理解Linux/Unix檔案描述和epoll

Linux/Unix 檔案描述符(File Describer)的本質 Linux/Unix(以下簡稱Linux)系統中,每個程序都有一個專用的陣列,陣列的元素是一個結構體,稱為檔案描述符File Descriptor(以下簡稱fd),但是至少包含一個檔案指標,指向Linux核心的O

Python 標準輸入輸出stdin stdout stderr 對照c解讀 為理解Linux檔案描述fileno做鋪墊

參考連結 詳解stdin,stdout,stderr 作者: 茶鹽耙 How to print to stderr in Python 作者:stack overflow 標準輸入流:鍵盤、掃碼槍等輸入裝置輸入的東西。 標準輸出流:螢幕、檔案等接受的東西 緩衝區:記憶體? 檔

Linux程式設計--檔案描述fd

    linux中, 每一個程序在核心中,都對應有一個“開啟檔案”陣列,存放指向檔案物件的指標,而 fd 是這個陣列的下標。     我們對檔案進行操作時,系統呼叫,將fd傳入核心,核心通過fd找到檔案,對檔案進行操作。     既然是陣列下標,fd的型別為int, &

linux基礎-檔案描述

檔案描述符簡介 檔案描述符(file descriptor)通常是一個小的非負整數,核心用以標識一個特定程序正在訪問的檔案。當開啟一個現有檔案或建立一個新檔案時,核心向程序返回一個檔案描述符。 每個程序在PCB(Process Control Block)中儲

linux檔案描述集fd_set的實現方式

通過賦值語句可以在兩個檔案描述符集之間進行賦值,例如可以這樣寫: fd_set readset,tmpset; FD_ZERO(&readset); FD_ZERO(&tmpset); FD_SET(listener,&tmpset);

Linux檔案描述和開啟檔案之間的關係

2014-07-06 wcdj 檔案描述符和開啟的檔案之間似乎是一一對應的關係,但實際可以多個檔案描述符指向同一開啟檔案,這些檔案描述符可能在相同或不同的程序中開啟。核心維護的三個資料結構: (1) 程序級的檔案描述符表 (2) 系統級的開啟檔案表 (3) 檔案系統的i-

linux檔案描述fd和檔案指標flip的理解

整理自:http://www.cnblogs.com/Jezze/archive/2011/12/23/2299861.html簡單歸納:fd(file descriptor)只是一個整數,在open時產生。起到一個索引的作用。每個程序在PCB(Process Control

Linux檔案描述剖析

Linux檔案IO open、dup、fork核心原理分析1、open一個檔案 一個Linux程序啟動後,會在核心空間建立一個PCB程序控制塊,PCB是一個程序的私有財產。 這個PCB中有一個已開啟檔案描述符表,記錄著所有該程序開啟的檔案描述符以及對應的file結構體地址。

linux檔案描述的種種限制

最近在研究linux伺服器下TCP的最大連線數問題,因為系統為每個TCP連線都要建立一個socket控制代碼,而每個socket控制代碼同時也是一個檔案控制代碼,所以就專門對linux下檔案描述符的種種限制作了一些深入的研究: 1,ulimit  -n 65556 ulim

Linux檔案描述數量限制

轉載自:http://blog.csdn.net/wsscy2004/article/details/41895263        在linux環境下,任何事物都以檔案的形式存在,通過檔案不僅僅可以訪問常規資料,還可以訪問網路連線和硬體。如傳輸控制協議 (TCP) 和使用

linux — 淺析檔案描述 檔案表項 v節點表項

淺析檔案描述符 檔案表項 v節點表項符檔案描述符在Linux程式設計裡隨處可見,裝置讀寫,網路通訊,程序通訊. 可是檔案描述符到底是什麼? 檔案描述符是一個簡單的整數,用以標明每一個被程序所開啟的檔案和

Linux檔案描述C FILE之間的關係

1. linux檔案描述符    對於linux而言,所有對裝置和檔案的操作都使用檔案描述符來進行的。檔案描述符是一個非負的整數,它是一個索引值,指向核心中每個程序開啟檔案的記錄表。當開啟一個現存檔案或建立一個新檔案時,核心就向程序返回一個檔案描述符;當需要讀寫檔案時,也需

Linux高階程式設計基礎——檔案系統程式設計之檔案描述

檔案系統程式設計之檔案描述符——實驗題 /*編寫程式碼,完成以下功能: 1.建立新檔案,該檔案具有使用者讀寫許可權。 2.採用dup/dup2/fcntl複製一個新的檔案描述符,通過新檔案描述符向檔案寫入“class_name”字串; 3.通過原有的檔案描述符讀取檔案中的內容,並且列印顯示;*/