網(wǎng)絡(luò)編程 - 文件系統(tǒng),內(nèi)核數(shù)據(jù)結(jié)構(gòu)和打開文件

原文地址:https://www.usna.edu/Users/cs/aviv/classes/ic221/s16/lec/21/lec.html

1. 回顧:什么是文件系統(tǒng)?

回想一下,文件系統(tǒng)是將文件組織到目錄和文件夾中。有許多不同類型的文件系統(tǒng)和許多不同的實現(xiàn),它們與包含數(shù)據(jù)的存儲設(shè)備緊密相連,例如,硬盤、U盤、CDrom,以及操作系統(tǒng),例如Mac、Linux或Windows。

文件系統(tǒng)的目的是維護和組織二級存儲。與不穩(wěn)定且不會在計算機重新啟動時持續(xù)存在的RAM不同,二級存儲被設(shè)計為永久存儲數(shù)據(jù)。文件系統(tǒng)為操作系統(tǒng)維護的數(shù)據(jù)布局提供了方便的表示。有各種各樣的文件系統(tǒng)實現(xiàn),它們描述了組織維護文件系統(tǒng)所必需的元數(shù)據(jù)的不同方法。例如,Windows上的標(biāo)準(zhǔn)文件系統(tǒng)類型稱為NTFS,它代表Windows NT文件系統(tǒng),而Linux/Unix系統(tǒng)的標(biāo)準(zhǔn)文件系統(tǒng)則根據(jù)版本的不同而被稱為ext3或ext4。

OS有一個根文件系統(tǒng),其中存儲主數(shù)據(jù)和系統(tǒng)文件。在Unix系統(tǒng)上,這是基文件系統(tǒng),由根上的單個/表示。在Windows上,這通常稱為C:\drive。OS還可以掛載(mount)其他文件系統(tǒng),例如插入USB驅(qū)動器或插入CD-ROM,用戶可以通過文件探索訪問這些其他文件系統(tǒng),這些文件系統(tǒng)可以使用不同的布局和數(shù)據(jù)組織,例如USB驅(qū)動器上的FAT 32或光盤上的ISO 9660。

但是,從系統(tǒng)的編程角度來看,我們編寫的程序?qū)τ谖募到y(tǒng)的底層實現(xiàn)是不可知的;我們用open()打開一個文件,用read()從文件中讀取數(shù)據(jù),用write()向文件寫入數(shù)據(jù)。實現(xiàn)的細(xì)節(jié)是完全透明的。OS是如何維持這種幻覺的?這就是下一課的主題-我們將探索文件系統(tǒng)的實現(xiàn)細(xì)節(jié),支持我們到目前為止編寫的程序。

2. 內(nèi)核(Kernel)數(shù)據(jù)結(jié)構(gòu)

要理解文件系統(tǒng),您必須首先考慮內(nèi)核是如何組織和維護信息的。內(nèi)核做了大量的工作;它需要知道哪個進程正在運行,它們的內(nèi)存布局是什么,進程打開了什么文件,等等。為了支持這個,內(nèi)核管理著三個重要的表/數(shù)據(jù)結(jié)構(gòu),通過這三個表來管理進程的打開文件,這三個表示:進程表,文件表,和v-node/i-node信息表。

Kernel File System Data Structures

下面我們將逐一討論。

2.1 進程表

第一個數(shù)據(jù)結(jié)構(gòu)是進程表,它存儲所有當(dāng)前正在運行的進程的信息。這包括有關(guān)進程的內(nèi)存布局、當(dāng)前執(zhí)行點等的信息。還包括打開的文件描述符。

The Process Table

As we know, all process start with with three standard files descriptors, 0, 1, 2, and these numbers and other file descriptors are indexes and stored in the open file table for that process's entry in the process table. Every time a new file is open, an new row in the open file table is added, indexed at the value of the file descriptor, e.g., 3 or 4 or 5 or etc.

打開文件表中的每一行都有兩個值。第一個是描述文件的處理的標(biāo)志,例如打開或關(guān)閉,或者當(dāng)文件關(guān)閉時應(yīng)該對其采取某些操作。第二個值是對文件表條目的引用,文件表是一個全局列表,所有進程共享,包含了當(dāng)前所有打開的文件。

有關(guān)進程表條目的一個有趣的的事情是,每當(dāng)進程通過fork創(chuàng)建子進程時,整個進程表條目都會被復(fù)制,其中包括打開的文件條目及其文件指針。這是兩個進程(父進程和子進程)能夠共享打開的文件。我們在前面看到了這方面的例子,我們將在后面的課中再看一遍。

2.2 文件表

每當(dāng)打開一個新文件時,系統(tǒng)范圍內(nèi)就會在全局文件表中創(chuàng)建一個新條目。這些條目在所有進程之間共享,例如,當(dāng)一個文件被兩個不同的進程打開時,它們可能具有相同的文件描述符號,例如3,但是每個文件描述符將引用文件描述符表中的不同條目。

The File Table

每個文件表條目都包含有關(guān)當(dāng)前文件的信息。最重要的是文件的狀態(tài),如文件讀或?qū)憼顟B(tài)和其他狀態(tài)信息。此外,文件表條目維護一個偏移量,該偏移量描述從文件中讀取(或?qū)懭?了多少字節(jié),指示下一次從何處讀取/寫入。例如,當(dāng)文件最初打開以供讀取時,偏移量為0,因為沒有讀取任何內(nèi)容。讀取10字節(jié)后,偏移量已向前移動到10字節(jié),因為從文件中讀取了10個字節(jié)。這是允許程序按順序讀取文件的機制。稍后,我們將看到如何操作這個偏移量并從文件的不同部分讀取。

表中的最后一個條目是一個v-node指針,它是對虛擬節(jié)點(v-node)和索引節(jié)點(i-node)的引用。這兩個節(jié)點包含有關(guān)如何讀取文件的信息。

2.3 V-node和I-node表

v-nodes和i-nodes是對文件的文件系統(tǒng)配置和底層存儲機制的引用;它將軟件與硬件連接起來。例如,在某個時候,打開的文件將需要接觸磁盤,但我們知道使用不同的文件系統(tǒng)對磁盤上的數(shù)據(jù)進行編碼的方法是不同的。v-node是一種抽象機制,因此無論底層文件系統(tǒng)實現(xiàn)如何,都有一種訪問該信息的統(tǒng)一方法,而i節(jié)點存儲特定的訪問信息。

V-Nodes and I-Nodes

查看v-node和i-node之間區(qū)別的另一種方法是,v-node就像文件系統(tǒng)中存在的文件一樣。抽象地說,它可以是任何東西并存儲在任何設(shè)備上—甚至可能不是一個文件,比如/dev/urandom或/dev/zero。相反,i-node描述如何訪問該文件,包括存儲在哪個設(shè)備上以及設(shè)備特定的讀/寫過程。

在Linux和許多Unix系統(tǒng)上,v-node不是顯式使用的,而是只有i-node;并且,i-node可以達(dá)到雙重目的。i-node既可以是文件的通用抽象表示形式,類似v-node,也可以存儲設(shè)備特定的指令。我們將繼續(xù)討論v-node/i-node的區(qū)別,因為它簡化了許多概念。

3. 復(fù)習(xí)打開文件

既然我們對內(nèi)核數(shù)據(jù)結(jié)構(gòu)有了更好的了解,那么讓我們來回顧一下文件描述符的一些常用用法,以及它如何與我們對內(nèi)核數(shù)據(jù)結(jié)構(gòu)的理解相匹配。

3.1 標(biāo)準(zhǔn)文件描述符

標(biāo)準(zhǔn)文件描述符由getty創(chuàng)建,并與終端設(shè)備驅(qū)動程序相關(guān)聯(lián),而且通過使用read()和write(),像其他打開文件一樣使用標(biāo)準(zhǔn)文件描述符。它們必須在進程表和文件表中以及v-nodes中有條目。

Standard File Descriptors

然而,標(biāo)準(zhǔn)的文件描述符不是磁盤上的文件,而是與另一個設(shè)備,終端設(shè)備相關(guān)聯(lián)的文件。這意味著v-node條目是指終端設(shè)備i-node,它存儲使用戶能夠從終端讀寫的底層訪問功能。

3.2 打開新文件

當(dāng)我們用open()打開一個新文件時,會生成一個新的文件描述符, usually one more than the last file descriptor。還在文件描述符表中提供了一個新條目,按文件描述符號進行索引,并在打開的文件表中創(chuàng)建一個新條目。

Opening a New File

如果此文件存在于磁盤上,則文件表條目將引用一個v-node,該節(jié)點引用可以從磁盤或存儲該文件的特定設(shè)備讀取/寫入數(shù)據(jù)的i-node信息。

3.3 父子進程共享文件

當(dāng)進程fork時,整個進程表條目將被復(fù)制,包括所有打開的文件描述符。

File Sharing

但是,文件表條目中沒有重復(fù)。父級和子級中的文件描述符引用相同的文件表項。請注意,文件偏移量存儲在文件表條目中,因此當(dāng)一個進程從文件中讀取時,它會移動偏移量,而當(dāng)另一個進程從文件讀取時,它將開始從第一個進程停止的位置讀取。

父進程和子進程都有不同的進程表項,但共享一個文件表項。子程序中的每一次讀取都表示條目中的偏移量,而父項中的偏移量也是相同的。結(jié)果是父級和其子級在讀取文件中的每個字節(jié)之間交替進行。

3.4 復(fù)制文件

我們還研究了使用dup2()復(fù)制文件的問題,這在內(nèi)核數(shù)據(jù)結(jié)構(gòu)中也有一個表示。回想一下,dup2()會將一個文件描述符復(fù)制到另一個文件描述符上。

File Descriptor Duplication

在內(nèi)核數(shù)據(jù)結(jié)構(gòu)中,這意味著文件描述符表中的兩個條目引用相同的文件表條目。結(jié)果,對文件描述符中的任何一個的讀取和寫入相同,如中所示,它們引用相同的文件。

3.5 管道

管道更像標(biāo)準(zhǔn)的文件描述符,因為它們不引用文件系統(tǒng)中的文件,而是用于在管道的寫讀端之間輸送數(shù)據(jù)的內(nèi)核數(shù)據(jù)結(jié)構(gòu)。

Pipes

對pipe()的調(diào)用將創(chuàng)建兩個文件描述符,即管道兩端的讀和寫文件描述符。這些文件描述符中的每一個都將在文件表中包含條目,但是v-node條目通過內(nèi)核緩沖區(qū)鏈接。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

友情鏈接更多精彩內(nèi)容