為什么要文件系統
在這篇【大話存儲】學習筆記(一),磁盤我們說到了硬盤的原理,如果要從硬盤里面取數據,需要告訴控制器從哪里取,取多長等關鍵信息,如果這個步驟由應用來做,則實在太磨人了。
所以操作系統提供了一個中間層
,對我們來說,只需要記住文件名和路徑,其他的與磁盤塊打交道的事情就交給這個中間層來做。這個中間層即為文件系統
怎么記錄文件占有的磁盤塊
最容易想到的自然是連續存放。這種方法在隨機訪問的時候效率最好,只需要知道文件起始位置以及長度,就可以像數組一樣訪問。
缺點也很明顯,如果一個文件刪除了,就會留下很多空白的位置,后面的文件再過來填充的時候,如果填不滿,則會留下大量的碎片。
所以我們希望一個文件可以切分成若干小塊,使用鏈表
串接起來。
這樣資源利用率當然高了,不過我們知道鏈表它的訪問效率并不高,也就是說 每次都得從第一塊開始,沿著鏈表往后找,非常消耗時間。
我們可以想想在圖書館怎么找書的,是不是有類似一張圖書——位置的對應表,我們按圖索驥即可。于是引入了索引式
,使用專門的一個磁盤塊來存放文件屬性&文件所占的磁盤塊。這個塊叫inode
。
怎么記錄目錄占有的磁盤塊
既然每個文件都有一個inode來描述,每個目錄當然也需要一個inode,其中存放了目錄的屬性以及這個目錄內容的磁盤塊號。
比如要讀取/tmp/test.log,查找次序是這樣的:
根目錄inode->根目錄磁盤塊->
tmp目錄inode->tmp目錄磁盤塊->
test.log的 inode->讀取磁盤塊
image.png
流程相當復雜,特別在刪除的時候,很容易就糟了。
比如想刪除/tmp/test.log
需要
- 目錄中刪除文件
- 釋放inode到空閑的節點池
- 將磁盤塊釋放到空閑的磁盤池
如果某一步出錯,就可能出問題。為了解決這種問題,引入了日志
。也就是說在操作之間把規劃列出來,形成日志,然后按照列出來的規劃進行操作,只有所有的步驟走完了才能擦除日志。
如果在某一步崩潰了,系統重啟的時候會再檢查日志項,發現哪些沒做,則重新來一遍即可。
如何管理空閑塊
我們已經解決了怎么存放文件和目錄的問題。但是我們還需要知道哪些地方沒有使用,也就是空閑的塊在那里。也就是說把空閑塊管理起來,統一進行空間分配。
我們同樣可以把空閑塊組成一個鏈表
,然后分配的時候就遍歷一下鏈表即可。但是存在一個問題,如果磁盤塊號是32位,則每個塊都得花32位的空間,如果空閑塊非常多,則浪費極大。
既然我們只是要知道某個地方是否被占用,而某個地方只存在占用和未占用兩種可能,不妨使用一張位圖
,對于每個磁盤塊,如果使用了,則標記為1,沒用就標記為0。這樣,每個磁盤塊只是使用了一位來標記,非常節省空間。
文件系統
我們以Linux ext2文件系統為例來看一下。
硬盤主要由MBR
與分區構成。
其中MBR中有引導代碼與磁盤分區表
- 引導代碼
- 分區表:記錄每個分區的起始位置,已經哪個磁盤分區是主分區(活動分區)。對于主分區,系統會找到它,然后裝載這個分區中的
引導塊
引導塊里面有什么?每個分區都會一個引導塊,如果本分區里面存放有操作系統,則會通過引導塊來進行裝載。
磁盤分區表只有64字節,而每個分區項占用16字節,則只能容納4個分區。如果我們想有多于4個分區,則可以把其中一個設為擴展分區,然后繼續劃分邏輯分區
即可。
每個分區由引導塊和塊組構成。
每個塊組中有:
- 磁盤塊位圖
- inode位圖
- inode表:存放文件和目錄的inode
- 數據塊
打個比方
打個不太恰當的比方,作為收尾。
可以把硬盤看做一個大倉庫,而磁盤控制器就是理貨員,沒有文件系統之前,外面的人(應用)取貨和送貨都需要直接于理貨員打交道,告訴他應該放那里,或者從那里取,非常的麻煩。
所以我們又請了一個倉管員
(文件系統),由他來打理整個倉庫,他需要對倉庫里面放了什么東西,有多少空閑的地方了如指掌,所以外面的人只需要告訴倉管員
要取什么文件,以及文件存放的路徑即可。
那么倉管員
是如何管理倉庫的呢?
首先為了簡化管理,他把若干房間(磁盤塊)合在一起管理,形成簇
(塊組)。
然后在簇里面分一些房間專門來存放每個文件
存放的具體位置,這種專門用來表示“文件——磁盤塊”的映射關系的數據結構就叫inode
。所以說如果要取文件的話,則可以先查看目錄的inode,在里面可以找到下一級目錄的inode號,然后可以去下一級目錄的inode里面找,一級一級的下去,最后可以找到文件inode,即可知道文件存在哪些具體的磁盤塊呢。
那么怎么存放數據呢?
倉管員
把每個房間用一個格子表示,如果里面放了東西,則格子標1,如果沒放,則標0 。這么通過這幅位圖
,就可以輕松知道那些房間是空余的了。