🔥 本文專欄:Linux
🌸作者主頁:努力努力再努力wz
★★★ 本文前置知識:
文件系統初識
那么在我們此前關于文件的學習中,我們學習的都是進程與打開的文件之間的關系,以及打開的文件如何進行管理,那么我們文件有打開的文件,那么同樣也就相應有未被打開的文件,所以本篇文章將圍繞為未被打開的文件,來揭開它神秘的面紗,看看我們操作系統是如何管理未被打開的文件的,那么廢話不多說,就讓我們進入正文的學習!
1.引入
那么我們知道我們的文件的元數據是存儲在外部設備當中,所以要認識未被打開的文件,那么第一步我們得先認識存儲該文件的介質或者說設備,而目前我們存儲的文件的外部設備就是SSD固態硬盤以及HDD機械硬盤,那么這兩種存儲設備各有各的優勢,那么目前我們大眾接觸到最多的也就是固態硬盤SSD,那么它內部構造是由晶體管所構成,而我們的文件本質就是一個二進制序列,那么SSD就通過內部的晶體管的電子的狀態來表示二進制的0和1,那么通過電信號來訪問各個晶體管的電子的狀態從而獲得二進制的數據,所以它的訪問速度是極其快速,但是由于其應用場景實在家用以及辦公用的便攜式筆記本電腦當中,意味著我們的SSD固態硬盤所占的體積不能過大,所以通過集成電路的技術使其具有較小的體積并且同時保證了其不錯的容量,那么必定意味著SSD的制作成本相比于機械磁盤就要高昂一點
那么對于機械磁盤HDD來說,那么它的應用場景則是一些不需要移動的笨重的臺式機或者互聯網公司的服務器后端數據的存儲設備,而對于HDD來說,它的優點就是容量大,并且造價成本便宜,所以這就是為什么大型的互聯網公司的服務器后端選擇磁盤作為數據的存儲設備,但是由于其是機械運動來定位數據,那么必然其訪問的效率不如SSD固態硬盤,并且其不能夠應用在便攜式電腦當中,但是由于HDD在互聯網公司的廣泛引用,鑒于其重要性,所以我們今天便要著重來研究我們的磁盤的硬件結構
2.磁盤的物理結構以及原理
那么我們的磁盤是由盤片以及磁頭以及高轉速的馬達等部件所構成,那么在這些構成磁盤的部件當中,其中最為重要的那便是磁頭與盤片,磁頭則是用來定位我們在磁盤當中存儲的數據,而我們的在磁盤中存儲的所有數據則是保存在盤片上,所以一個磁盤的容量就由盤片的數量以及盤片的存儲密度等所決定。
磁盤的盤片有兩面,盤片的兩面分別有一層磁性的物質,那么我們知道我們的文件的各種元數據的最終形態其實就是一個二進制序列,而二進制序列無非就是由0和1所構成,所以我們如何在盤片上表示出二進制的0和1呢?
那么盤片表面上的磁性物質,我們可以看成有數十億甚至百億的磁性顆粒所組成,那么其中對于這每一個磁性的顆粒來說,那么它是具有磁性的,那么一旦具有磁性,那么它便具有特定的磁級指向南或者北,所以我們就可以根據每一個顆粒該磁極的指向的兩個狀態來分別表示二進制的0和1,那么具體的實現的途徑,則是我們磁頭通過放電會在其周圍產生一個磁場,那么利用該磁場來磁化磁性顆粒使其產生特定的磁極,從而寫入二進制序列,那么這就是磁盤寫入數據的一個原理
而讀取數據則是根據我們的磁頭感受到讀取位置的磁場變化從而磁生電,轉換成電信號,那么利用該電信號得到特定的二進制序列,那么這就是利用我們高中物理的電磁學的原理
那么我們知道我們的數據是存儲在我們的磁盤的盤片上,那么我們對于磁盤讀取則是依靠磁頭以及盤片的機械運動來定位數據的,那么我們磁盤的讀取速度的效率則取決于該磁盤定位速度的機械運動的快慢,那么讀取越快意味著磁盤定位一個數據所做的機械運動越少,那么我們希望磁盤所做的機械運動盡量的少,那么我們就需要將我們一個文件的數據集合盡可能存放在磁盤的盤片的相鄰的物理位置處,這樣就能夠減少機械的運動了
那么我們知道了如何在磁盤中存儲數據,那么我們要在磁盤中讀取我們需要的目標數據那么肯定就得有該目標數據在我們的磁盤中的具體位置,所以為了表示一個數據在磁盤中的具體位置,那么我們此時便引入了一個磁道的概念
那么我們對于一個盤片來,那么它的形狀是一個圓形,那么我們以該盤片的中心為圓心,然后往外劃分一圈一圈不同的半徑的圓,那么該圓的圓弧就是磁道,其中每一個相鄰的磁道之間的空間,我們還可以在進行進一步的劃分,我們將圓心與每一個不同半徑上的圓的圓弧處上的點形成一條條連線,那么該連線將我們的相鄰兩個磁道之間會劃分成一個一個的扇形區域,那么該扇形區域區域我們稱之為扇區,那么它就是我們磁盤存儲數據的一個最基本單元,那么一般我們磁盤不只有一個盤片,那么每一個盤片都有兩個盤面,那么每一面都能夠存儲數據,那么我們每一個盤面都對應有一個磁頭用來定位,其中每一個盤面的劃分磁道的數量是相同的,并且對于同一個盤片來說,每個相鄰磁道之間的扇區的數量也是一致的,而我們知道越靠近外側,那么相鄰磁道之間的空隙也就越大,越靠近圓心位置處,相鄰磁道之間的空隙越小,所以為了達到每一個相鄰磁道之間的扇區數量相等,那么我們每一個磁道之間的劃分的疏密以及磁道之間的存儲密度就不同
所以我們要定位一個扇區的話,那么我們首先磁頭就得來回擺動,定位確定是在哪個磁道上,然后我們的盤片通過高速馬達的轉軸的帶動在轉動定位到目標扇區
而我們知道我們的盤片是高速轉動并且磁頭也在擺動,那么也許有的小伙伴就有疑問,那么萬一我的磁頭刮花了盤片怎么辦,盤片上存儲著各種數據,那么刮花了豈不是造成了數據的缺失,那么注意雖然看起來磁頭是和盤片是挨著的,但是他們其實并沒有接觸,他們中間有一個間隙,那么一旦盤片高速轉動,那么中間的空氣會托舉著磁頭,使其懸浮,應用了空氣動力學的原理,所以我們的磁盤的工藝設計其實是非常巧妙的!并且磁盤內部不能有灰塵,一旦有了灰塵,那么灰塵是個顆粒狀的固體,那么隨著盤片的高速轉動,那么其會刮花盤片,所以博主在這里警惕各位讀者,如果自己好奇來拆開磁盤來研究,那么對不起,你的磁盤就報廢了
而我們知道盤片之間是沿著一個轉軸來垂直擺放的,那么不同盤面上的相同半徑的磁道在立體的空間當中的集合就稱之為一個柱面,所以我們定位,我們只需要確定三個坐標即可,即使它在對應哪個磁頭,哪個磁道以及哪個扇區,那么這三個坐標我們也要一個專業術語就是CHS位置
3.磁盤的邏輯結構
那么我們知道磁盤的物理構造之后,那么我們在操作系統層面上怎么來理解描述磁盤這樣的物理結構呢
那么我們知道有一個叫做磁帶的東西,想必各位讀者在小學的時候播放英語教材會用到,那么我們一圈一圈彎曲的磁帶,那么我們可以將其整體拉直,那么其磁帶上的所有數據就是按照這個拉直過后的磁帶呈線性排列
而同理這里對于我們的磁盤來說,我們不同盤面上的磁道就可以理解為一圈一圈的磁帶,那么我們也可以將其給拉直,那么我們磁盤上所有的數據就可以按照一個一維的線性數組來表示,那么為了區分磁盤上的不同的扇區,那么我們會給扇區分配一個唯一的編號,那么我們這個一維數組中的每一個元素就是一個扇區,那么該扇區的數組下標就是該扇區的編號,也就是LAB地址,而我們要將扇區的邏輯結構的編號轉換成實際物理層面上的坐標,那么也就是確定該扇區的磁頭以及磁道和磁道的第幾個扇區的話
那么現在有了扇區的編號,那么如何來轉換呢?
那么假設每一個盤面上有m個扇區,每個盤面有k個磁道,每個磁道有q個扇區,假設此時我們的扇區的數組下標為i,那么首先確定其在哪個盤面上,那么我們就可以利用公式:
L=i/m
H=i%m
那么如果余數H不為0的話,那么意味著當前處于第L+1盤面處,接著在計算所處的磁道:
O=H/(k*q)
P=H%(k*q)
余數P不為0的話,那么意味著當前處于該盤面的第O+1磁道處,而P就是該磁道的第P個扇區位置
那么我們就可以根據該公式來實現邏輯地址到物理地址的轉換,那么我們獲取到地址之后,CPU會交給磁盤的寄存器,那么磁盤有4個寄存器,分別是命令寄存器以及地址寄存器和數據寄存器和數據寄存器以及狀態寄存器,它們4個的作用就是分別用來記錄當前是往磁盤進行讀還是寫和一個讀寫的地址以及寫入的數據和以及當前寫入是否成功
4.如何管理未被打開的文件
那么我們知道了我們操作系統已經有一個邏輯結構也就是一維的線性數組來表示我們整個磁盤中的數據也就是所有扇區,但是我們的扇區的存儲的數據量的大小通常是512個字節,那么我們扇區是磁盤的基本存儲單元,而我們上文就說過磁盤訪問的效率取決于機械運動的次數,況且我們現在的一個文件動不動就是幾個甚至上百個GB,那么我們以扇區為單位一次一次的讀取的話,那么效率太慢了
所以我們的操作系統以及其采取的文件系統就對此有所優化,那么我們知道此前我們整個文件的邏輯結構是一個一維的線性數組,那么此時對于磁盤訪問一個數據的基本單位不再是一個扇區,而是幾個扇區的集合作為該文件系統的存儲數據的基本單位也稱之為邏輯塊,比如8個扇區也就是4kb的數據量,那么這樣就能提升訪問效率,那么原本磁盤的邏輯結構此時在該文件系統的新的視角下便有了不同,那么該一維的線性數組的長度沒有發生變化,但是其元素不在是之前的扇區,而是一個一個邏輯塊,那么該邏輯塊就是由幾個扇區所組成,那么以前該一維的線性數組的元素個數假設是1000個,那么現在在該文件系統下比如ET4,那么邏輯塊是由8個扇區所組成,那么個數意味著就是250個,那么每一個邏輯塊就有了新的編號也就是數組的下標
而我們的磁盤的容量極大,可以達到800GB甚至1TB,那么管理這么龐大的數據,那么我們操作系統采取的管理策略就是分區
那么按照不同的文件系統,那么可能將這800個G或者1TB的數據給劃分成不同的區,那么假設以ET4文件系統為例,那么其會劃分成4個區,那么每一個區此時的容量就是200個G,但是即使劃分成不同的區,那么管理的數據量可能還是極大,所以對于每一個區我們又進行·更細致的劃分,將其劃分成了不同的組,那么我們管理好這整個文件系統,就是管理好這每一個組以及每一個區即可
那么其中對于這每一個分區來說,那么操作系統管理的方式就是我們再熟悉不過的先描述,再組織了,那么它會為其定義一個struct partition結構體,那么每一個結構體記錄了每一個區的起始位置以及結束位置和該區的分組的數量等等屬性,其中第一個分區的開頭會有一個boot block分組,那么該分組就是記錄了操作系統開機的有關信息,并且其他區也有該分組的備份
而對于每一個區的組來說,那么它也有對應的一個結構體來描述,其中就包含超級塊以及塊表和innode表以及數據塊等
// 示例結構體定義,用于描述文件系統中的一個區組
struct FileSystemGroup {// 超級塊(或超級段)struct SuperBlock {int magicNumber; // 文件系統魔數,用于識別文件系統類型int blockSize; // 邏輯塊大小(字節)int totalBlocks; // 區組內總邏輯塊數int freeBlocks; // 區組內空閑邏輯塊數int totalInodes; // 區組內總inode數int freeInodes; // 區組內空閑inode數// 其他元數據...} superBlock;// 塊表(位圖)// 假設每個位代表一個邏輯塊,1表示已使用,0表示空閑// 這里簡化為一個數組表示,實際中可能使用更緊湊的位圖存儲unsigned char blockBitmap[/* 根據區組大小動態分配 */];// inode表// 每個inode對應一個文件或目錄struct Inode {int type; // 文件類型(普通文件、目錄等)int permissions; // 文件權限int owner; // 文件所有者int size; // 文件大小(字節)int lastModified; // 最后修改時間戳// 指向數據塊的指針數組int dataBlockIndices[/* 根據文件大小動態分配,可能包含多級索引 */];} inodes[/* 根據區組大小動態分配 */];// 數據塊表(或數據塊區域)// 實際存儲文件內容的邏輯塊,這里簡化為一個指針數組表示// 每個指針指向一個數據塊,數據塊可能分布在磁盤的不同位置void* dataBlocks[/* 根據區組大小動態分配 */];
};
那么其中這4個屬性,我們知道它們本質上也是數據,那么必然就在相應的邏輯塊中存放,而我們同一個分組的邏輯塊一般是在物理內存的同一個區域,并且其中的屬性也是按照特定的順序來排列,比如超級快塊一般在該分組的邏輯塊的第一個位置,然后再是塊表和inode表依次向后排列,那么這取決于特定的文件系統實現,并且不同的文件系統對于每一個分組所占據的邏輯塊的數量也是不同的
? 那么我來詳細介紹一下該組的各個不同的屬性:
超級塊
::超級塊記錄了文件系統的類型、大小、塊大小、inode數量、空閑塊和inode的數量等關鍵信息。它還包括文件系統的掛載時間、最后寫入時間等時間戳信息
塊表
:采取的是位圖的實現方式,那么其中每一個二進制位的狀態用來表示每一個邏輯塊是否被使用
inode表
:那么每一個文件都會對應有一個innode結構體用來存儲該文件的屬性其中就包括權限等字段,其中innode表還會記錄一個數組,那么該數組一般長度為15,那么該數組則是記錄該文件對應的文件內容的數據的邏輯塊,那么每一個數組元素的內容就是邏輯塊的索引,那么數組前12個位置則是直接索引,那么他們指向的邏輯塊就是直接存儲的是文件的內容,而之后的元素則是二級以及三級索引,那么所謂二級索引則是該指向的邏輯塊存儲的內容不是有效的文件內容的數據,而是指向其他保存文件內容數據的邏輯塊,那么這樣就能擴展文件的體積,所以innode表則是記錄每一個innode所對應的邏輯塊的位置,用位圖來實現
data block
:那么除了超級塊以及快表和inode和inode表所占據的邏輯塊,那么其余就是存儲文件內容的數據塊,所以我們發現Linux下文件的屬性以及內容是分開存儲的
那么這就是我們操作系統管理未打開文件的方式,采取的是分治以及先描述,再組織的策略
結語
那么這就是本篇文章關于文件系統的全部內容了,那么下一期文章將是軟硬件鏈接,那么下一期博客就是我們Linux文件系統的一個收尾啦,那么文件系統學寫完之后,我們便打開了語言與操作系統之間的隔閡,那么我會持續更新,希望你多多管制,如果我的文章有幫組到你的話,還請多多三連加關注哦,你的支持,就是我創作的最大動力!