??樊梓慕:個人主頁
???個人專欄:《C語言》《數(shù)據(jù)結(jié)構(gòu)》《藍(lán)橋杯試題》《LeetCode刷題筆記》《實訓(xùn)項目》《C++》《Linux》《算法》
??每一個不曾起舞的日子,都是對生命的辜負(fù)
目錄
1.磁盤引入
2.文件系統(tǒng)?
2.1初識inode
2.2inode Table
2.3inode Bitmap
2.4Data Blocks
2.5Block Bitmap
2.6Group Descriptor Table
2.7超級塊Super Block
2.8Boot Block
2.9有關(guān)文件名
如何知道文件在哪一個分區(qū)?
3.軟鏈接與硬鏈接
3.1軟鏈接
3.2硬鏈接
前言
系統(tǒng)中大部分的文件是沒有被打開的,那么操作系統(tǒng)是如何管理這些沒有被打開的文件呢,接下來我們就要開始學(xué)習(xí)Linux系統(tǒng)對于文件的管理。
歡迎大家??收藏??以便未來做題時可以快速找到思路,巧妙的方法可以事半功倍。
=========================================================================文章來源地址http://www.zghlxwxcb.cn/news/detail-838468.html
GITEE相關(guān)代碼:??樊飛 (fanfei_c) - Gitee.com??
=========================================================================
1.磁盤引入
為了輔助后續(xù)linux系統(tǒng)對文件的管理,我們可以從磁盤入手,雖然磁盤現(xiàn)在已經(jīng)很少出現(xiàn)在個人計算機上了(固態(tài)硬盤\機械硬盤),但對磁盤的學(xué)習(xí)可以幫助我們后續(xù)對文件系統(tǒng)的認(rèn)識。
為什么要學(xué)習(xí)磁盤呢?
主要是為了研究磁盤的尋址方式,就是如何快速定位到某個位置。
根據(jù)上圖有關(guān)磁盤的基本概念,你可能對磁盤的尋址方式有了初步的猜測。
對磁盤進(jìn)行讀寫操作時,一般有以下幾個步驟:
- 確定讀寫信息在磁盤的哪個柱面。
- 確定讀寫信息在磁盤的哪個盤面。
- 確定讀寫信息在磁盤的哪個扇區(qū)。
所以通過以上三個步驟我們就可以快速定位到一個扇區(qū),從而找到讀寫位置。
注意:扇區(qū)大小一般為512字節(jié)。
該尋址方式被稱為『 CHS定位法?』。
- C:cylinder 柱面
- H:head 磁頭(通過不同的磁頭確定不同的盤面)
- S:sector 扇區(qū)
2.文件系統(tǒng)?
試想:如果我們把盤面拉直,是不是就得到了一個由n個扇區(qū)組成的“數(shù)組”?,這里可以聯(lián)想到磁帶。
那么該數(shù)組的基本單元是多大呢?
????????我們前面說一個扇區(qū)的大小為512字節(jié),但是操作系統(tǒng)認(rèn)為512字節(jié)太小了,訪問效率太慢了,所以操作系統(tǒng)將連續(xù)的8個扇區(qū)作為一個基本數(shù)據(jù)塊,即4KB,?所以這4KB就是IO的基本單位,也就是說只要需要修改數(shù)據(jù),哪怕再小,操作系統(tǒng)也要將這4KB拿出來做修改再放回去,這就是所謂的基本單位。
注意:不同操作系統(tǒng)可能不同,這個是自己定義的,但大部分操作系統(tǒng)都是4KB。
所以每8個扇區(qū)組成一個新的基本單元(數(shù)據(jù)塊),從而得到的一個新的數(shù)組。
通過數(shù)組的下標(biāo)(該下標(biāo)被稱為『 LBA(logic block address)邏輯塊地址』),我們只要知道『 每個磁道上的扇區(qū)數(shù)』和『 每個盤面上的扇區(qū)總數(shù)』,就可以通過計算得到對應(yīng)的扇區(qū)位置。
?這一轉(zhuǎn)化過程是磁盤自動轉(zhuǎn)化的,所以通過這樣的方式,我們成功將『 對磁盤的管理』轉(zhuǎn)化為了『 對數(shù)組的增刪查改』。
假設(shè)我們總共有400GB的磁盤空間,那么我們可以將這400GB進(jìn)行分區(qū)管理,假設(shè)每個區(qū)域有100GB,同樣的對于每個區(qū)域來說,我們可以將這100GB再劃分得到每10GB的數(shù)據(jù)塊,這樣只要管理好這10GB,就能管理好全部,即只要管理好局部,就能管理好全局,那么接下來我們來研究一下如何管理這10GB,下圖為Linux ext2文件系統(tǒng)的方案:
2.1初識inode
文件=文件內(nèi)容+文件屬性。
文件內(nèi)容就是文件當(dāng)中存儲的數(shù)據(jù),文件屬性就是文件的一些基本信息,例如文件大小、文件創(chuàng)建時間等信息都是文件屬性,文件屬性又被稱為元信息。
注:文件名不屬于文件屬性。
那么一般來說文件內(nèi)容大小是不確定的,而文件屬性大小是固定大小,因為文件屬性的類別都是一樣的,只不過不同文件中對應(yīng)類別存儲內(nèi)容不同,比如創(chuàng)建時間不同等。
注:在Linux操作系統(tǒng)中,文件的元信息和內(nèi)容是分離存儲的。
所以設(shè)計出了一個結(jié)構(gòu)體用來描述文件屬性,該結(jié)構(gòu)體即為inode,大小一般為128字節(jié),每個文件都有自己的inode和對應(yīng)的inode編號,該inode編號在『 所處分區(qū)』內(nèi)唯一。
所以系統(tǒng)中標(biāo)識一個文件,用的不是文件名,而是inode編號。
注:無論是文件內(nèi)容還是文件屬性,它們都是存儲在磁盤當(dāng)中的。
所以我們可以猜想inode的結(jié)構(gòu)可能如下:?
然后我們再來研究一下數(shù)據(jù)塊組內(nèi)其他成員:?
2.2inode Table
inode Table中存儲的是該塊組內(nèi)所有文件的inode結(jié)構(gòu)體,組織方式類似數(shù)組。
2.3inode Bitmap
還記得位圖么,沒錯,這里同樣是位圖的尋址方式,每個bit標(biāo)識一個inode是否空閑可用。
- 比特位的位置:inode Table中第幾個inode。
- 比特位的內(nèi)容:標(biāo)識該inode是否被使用。
2.4Data Blocks
數(shù)據(jù)區(qū),存儲的是文件內(nèi)容,內(nèi)部由n個數(shù)據(jù)塊構(gòu)成,我們前面說每個數(shù)據(jù)塊大小為4KB,由8個扇區(qū)構(gòu)成。
2.5Block Bitmap
同樣是位圖,不過該位圖記錄著Data Blocks中哪個數(shù)據(jù)塊已經(jīng)占用,哪個數(shù)據(jù)塊沒有被占用。
- 比特位的位置:Data Blocks中第幾個數(shù)據(jù)塊。
- 比特位的內(nèi)容:標(biāo)識該數(shù)據(jù)塊是否被使用。
另外,由于每個數(shù)據(jù)塊大小僅為4KB,而文件大小可能會高于4KB,即一個文件可能會占用多個數(shù)據(jù)塊,所以inode結(jié)構(gòu)體中還會有這樣的一個設(shè)計:
該block數(shù)組是為了映射更多的數(shù)據(jù)塊,那么此時你可能還會有疑問:那該數(shù)組大小為15,15*4KB=60KB,那更大的文件呢?
其實這里block數(shù)組中:
- 0-11下標(biāo)對應(yīng)內(nèi)容才為直接映射;
- 12-13下標(biāo)對應(yīng)的數(shù)據(jù)塊并不直接保存數(shù)據(jù),而保存指向其他數(shù)據(jù)塊的編號(二級索引);
- 14下標(biāo)對應(yīng)的數(shù)據(jù)塊保存指向其他數(shù)據(jù)塊的編號,而這些其他數(shù)據(jù)塊也不直接保存數(shù)據(jù),他們保存指向另外更多其他數(shù)據(jù)塊的編號(三級索引);
所以存儲文件的量級還是非??捎^的。
如何根據(jù)inode編號在不同塊組中快速定位到inode呢??
其實每個分組都有對應(yīng)的『 起始inode編號』,我們可以首先根據(jù)每個分組的起始編號,判別在哪個組,然后減去該分組的起始編號,就能得到一個偏移量,該偏移量就是inode位圖位置和inode表的下標(biāo)索引。
你有沒有發(fā)現(xiàn)計算機刪除文件的速度一般很快?
其實這就是因為位圖的設(shè)計方式,刪除文件只需要將兩個位圖中對應(yīng)的映射關(guān)系修改即可,其實就是相當(dāng)于刪除了映射,而存儲在Data Blocks中的屬性和數(shù)據(jù)都沒有改動,所以刪除文件的速度往往很快。
2.6Group Descriptor Table
描述整個塊組的屬性信息,諸如該塊組有多少個inode,多少個數(shù)據(jù)塊等等。
2.7超級塊Super Block
存放文件系統(tǒng)本身的結(jié)構(gòu)信息。記錄的信息主要有:block?和 inode的總量,未使用的block和inode的數(shù)量,一個block和inode的大小,最近一次掛載的時間,最近一次寫入數(shù)據(jù)的時間,最近一次檢驗磁盤的時間等其他文件系統(tǒng)的相關(guān)信息。
Super Block的信息被破壞,可以說整個文件系統(tǒng)結(jié)構(gòu)就被破壞了。
一般一個分區(qū)內(nèi)會有少數(shù)幾個塊組內(nèi)存在,存儲相同的內(nèi)容,主要目的是備份,防止文件系統(tǒng)結(jié)構(gòu)被破壞。
操作系統(tǒng)對文件系統(tǒng)的管理:不同分區(qū)的Super Block構(gòu)建成對象用鏈表的結(jié)構(gòu)鏈接起來。?
2.8Boot Block
一般僅在0號盤面的0號扇區(qū)存在,也就是最開始的位置,它主要作用是為了輔助開機,加載操作系統(tǒng)等,這里感興趣的大家可以自行學(xué)習(xí)。
2.9有關(guān)文件名
在linux操作系統(tǒng)中,我們之前對文件的操作從未利用過inode尋找文件位置,而是利用文件名,那文件名與inode編號又有什么樣的聯(lián)系呢?
這里就要從目錄說起了。
目錄(文件夾)也是文件,只要是文件就有自己的inode和文件內(nèi)容,那目錄文件的文件內(nèi)容存儲的是什么呢?
其實目錄文件的文件內(nèi)容為目錄內(nèi)文件名與對應(yīng)文件inode編號的映射關(guān)系。
所以這里我們就可以重新認(rèn)識一下對文件的增刪查改操作了。
為什么之前我們說當(dāng)前用戶如果沒有目錄的寫權(quán)限,那么就無法對目錄內(nèi)的文件進(jìn)行操作呢?
其實原因就在這里,因為你不能寫入目錄文件的內(nèi)容(即映射關(guān)系)。
讀權(quán)限等也是一樣的道理。
目錄文件與inode編號的映射關(guān)系存儲在上級目錄。
所以查找一個文件,在內(nèi)核中,都要逆向地遞歸般得到映射關(guān)系,直到根目錄,然后從根目錄開始進(jìn)行路徑解析(根目錄的inode是確定的)。
這樣就一定會存在一種數(shù)據(jù)結(jié)構(gòu)用來緩存對應(yīng)路徑的映射關(guān)系,這種數(shù)據(jù)結(jié)構(gòu)被稱為dentry(路徑緩存、dentry緩存)。
struct dentry {
atomic_t d_count;
unsigned long d_vfs_flags; /* moved here to be on same cacheline */
spinlock_t d_lock; /* per dentry lock */
struct inode * d_inode; /* Where the name belongs to - NULL is negative */
struct list_head d_lru; /* LRU list */
struct list_head d_child; /* child of parent list */
struct list_head d_subdirs; /* our children */
struct list_head d_alias; /* inode alias list */
unsigned long d_time; /* used by d_revalidate */
struct dentry_operations *d_op;
struct super_block * d_sb; /* The root of the dentry tree */
unsigned int d_flags;
int d_mounted;
void * d_fsdata; /* fs-specific data */
struct rcu_head d_rcu;
struct dcookie_struct * d_cookie; /* cookie, if any */
unsigned long d_move_count; /* to indicated moved dentry while lockless lookup */
struct qstr * d_qstr; /* quick str ptr used in lockless lookup and concurrent d_move */
struct dentry * d_parent; /* parent directory */
struct qstr d_name;
struct hlist_node d_hash; /* lookup hash list */
struct hlist_head * d_bucket; /* lookup hash bucket */
unsigned char d_iname[DNAME_INLINE_LEN_MIN]; /* small names */
}
這里dentry具體的結(jié)構(gòu)我們不作研究,只需要知道每個『 打開的文件』的dentry里面存儲了inode屬性和路徑屬性,當(dāng)然不止目錄文件這樣存儲,普通文件也是一樣的。
如何知道文件在哪一個分區(qū)?
這個問題很關(guān)鍵,因為inode是在分區(qū)內(nèi)唯一的,不同分區(qū)可能會存在相同inode。
其實,一個文件系統(tǒng)所對應(yīng)的分區(qū),都掛載在指定的目錄中。
也就是說我們可以通過路徑分析出文件在哪一個分區(qū),路徑的本質(zhì)其實就是字符串,我們可以通過字符串前綴分析得到路徑,然后根據(jù)該路徑識別當(dāng)前文件所處的分區(qū)即可。
一個被寫入文件系統(tǒng)的分區(qū),要被linux使用,必須先把這個具有文件系統(tǒng)的分區(qū)進(jìn)行掛載。
可以通過『 df -h』命令查看文件系統(tǒng)和路徑之間的聯(lián)系:
掛載在內(nèi)核中就是將兩種數(shù)據(jù)結(jié)構(gòu)產(chǎn)生某種聯(lián)系,分別是文件系統(tǒng)的數(shù)據(jù)結(jié)構(gòu)和路徑緩存dentry的數(shù)據(jù)結(jié)構(gòu)。
3.軟鏈接與硬鏈接
3.1軟鏈接
我們可以通過『 ln -s 文件名 軟鏈接名』命令創(chuàng)建軟鏈接。
軟鏈接的本質(zhì)是文件,擁有獨立的inode。
軟鏈接文件內(nèi)容存放的是文件所在的路徑信息,相當(dāng)于windows系統(tǒng)的『 快捷方式』。?
3.2硬鏈接
我們可以通過『 ln?文件名 軟鏈接名』命令創(chuàng)建硬鏈接。
通過上圖我們發(fā)現(xiàn)硬鏈接與被鏈接文件的inode編號相同,也就是說硬鏈接本身并不是文件。
?我們之前從未提到過如上圖所示的數(shù)字代表什么意思。
其實這就與硬鏈接有關(guān)。
它反映的是硬鏈接數(shù),或者說是inode的引用計數(shù),即當(dāng)前文件的inode被多少文件所映射。
當(dāng)建立硬鏈接后,我們發(fā)現(xiàn)test文件的硬鏈接數(shù)++變?yōu)?了。
當(dāng)我們刪除掉硬鏈接link.hard,利用unlink命令或rm命令都可以。
發(fā)現(xiàn)硬鏈接數(shù)--變?yōu)?。
普通文件硬鏈接數(shù)初始為1:因為文件的目錄中就存儲這一份文件名和inode的映射關(guān)系。
目錄文件硬鏈接數(shù)初始為2,為什么呢?
還記得 『? . 和 .. 』么?
沒錯? 『 . 』和『? .. 』就是硬鏈接的實際應(yīng)用。
注意
可以給目錄文件建立軟連接;
不能給目錄文件建立硬鏈接:目的是為了防止無窮遞歸,形成路徑環(huán)路。
那為什么『? .?』和『? .. 』建立了與目錄文件的硬鏈接呢?
因為系統(tǒng)自己可以給目錄建立硬鏈接,而用戶不能。
主要是linux系統(tǒng)自己設(shè)計的可以做特殊區(qū)分,防止形成路徑環(huán)路。
=========================================================================
如果你對該系列文章有興趣的話,歡迎持續(xù)關(guān)注博主動態(tài),博主會持續(xù)輸出優(yōu)質(zhì)內(nèi)容
??博主很需要大家的支持,你的支持是我創(chuàng)作的不竭動力??
??~ 點贊收藏+關(guān)注 ~??文章來源:http://www.zghlxwxcb.cn/news/detail-838468.html
=========================================================================
到了這里,關(guān)于【Linux】文件周邊003之文件系統(tǒng)的文章就介紹完了。如果您還想了解更多內(nèi)容,請在右上角搜索TOY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!