??作者: 華丞臧.
??????專欄:【LINUX】
各位讀者老爺如果覺得博主寫的不錯,請諸位多多支持(點(diǎn)贊+收藏+關(guān)注
)。如果有錯誤的地方,歡迎在評論區(qū)指出。
一、Linux文件系統(tǒng)
1.1 磁盤
信息化時代就是信息產(chǎn)生價值的時代,信息化是當(dāng)今時代發(fā)展的大趨勢,代表著先進(jìn)生產(chǎn)力。通常我們都會將信息存放在某些硬件上,如:硬盤、內(nèi)存等;當(dāng)信息存放硬盤上時,信息就變成了硬盤上的文件,人們通過一些設(shè)備如電腦手機(jī)可以查看使用這些數(shù)據(jù),我們的工作和生活,已經(jīng)完全離不開視頻、音樂、圖片、文本、表格這樣的數(shù)據(jù)文件。
- 磁盤上存放著大量的文件,這些文件需要被管理組織起來,操作系統(tǒng)中管理和存儲文件信息的軟件機(jī)構(gòu)稱為文件系統(tǒng)。
- 最開始存放數(shù)據(jù)的硬件是磁盤,隨著時代發(fā)展,像我們的筆記本電腦大多使用SSD硬盤,但是磁盤還是主要的存儲設(shè)備,可以用存放大量的數(shù)據(jù),關(guān)鍵是便宜。
- 下圖是一張磁盤的結(jié)構(gòu)圖,磁盤的核心就是這些盤面,盤面能夠記錄二進(jìn)制序列,其原理就是通過電流產(chǎn)生感應(yīng)磁場來改變某些特定位置的磁極從而將電信號持久化到磁盤上。
-
磁盤工作時是處于一種高速旋轉(zhuǎn)的狀態(tài),磁頭依靠磁盤的高速旋轉(zhuǎn)引起的空氣動力效應(yīng)懸浮在盤面上,磁頭在副軸馬達(dá)的帶動下可以在極短的時間內(nèi)精確的切換到數(shù)據(jù)所在的磁道。
-
磁盤是一種高精度的設(shè)備,在高速旋轉(zhuǎn)的情況下,磁面上的一?;覊m都可能會導(dǎo)致磁盤損壞,因此磁盤通常是在無塵的環(huán)境下密封。
-
每一個盤面都對應(yīng)一個磁臂,通過這些磁臂上的磁頭來定位數(shù)據(jù)的位置,依次確定磁道(柱面)、盤面、以及扇區(qū),這三個值稱為CHS地址。
-
扇區(qū)是硬盤的最小操作單位,但扇區(qū)對于操作系統(tǒng)來說還是太小了,一般操作系統(tǒng)有自己的硬盤操作最小單位,在linux下一般為4k。
-
為了方便管理數(shù)據(jù),我們可以將硬盤這樣的物理塊設(shè)備,分割成多個邏輯塊設(shè)備。或者,我們也可以將多個物理塊設(shè)備,組合成一個容量更大的邏輯塊設(shè)備。
-
操作系統(tǒng)需要管理磁盤,將磁盤抽象為一個線性的結(jié)構(gòu),類似于卷尺拉出來是線性的收進(jìn)去是圓形的,因此我們可以將磁盤想象成線性的結(jié)構(gòu)數(shù)組,對磁盤的管理就可以轉(zhuǎn)換成對數(shù)組空間的管理了。
-
假設(shè)磁盤抽象的出的數(shù)組為sector disk[100000000],那么我們定位一個扇區(qū)只需要數(shù)組的下標(biāo)即可(這種下標(biāo)稱為LBA–邏輯塊地址),將LBA轉(zhuǎn)換成CHS地址,再將數(shù)據(jù)寫入對應(yīng)的磁盤上去。
-
磁盤上存儲的基本單位是扇區(qū)(512字節(jié)常規(guī)),文件系統(tǒng)訪問磁盤的基本單位是4KB,即一次IO訪問8個扇區(qū)。
-
這樣做有兩個好處:一、提高IO的效率 ;二、讓軟件(OS)和硬件(磁盤)具有強(qiáng)相關(guān)性即解耦合。
1.2 inode
使用ll
查看文件,除了文件名還可以看到文件的其他屬性,如下圖:
每行包含7列:
- 模式:代表文件的類型以及權(quán)限
- 硬鏈接數(shù)
- 文件所有者
- 所屬組
- 文件大小
- 最后修改時間
- 文件名
如果需要查看文件更詳細(xì)的信息可以使用stat命令,如下圖:
在上圖中我們可以看到文件屬性中有一個Inode字段,在Linux系統(tǒng)中inode
用于表示唯一的一個文件。
- 不管是在Windows平臺還是在Linux系統(tǒng)中,我們都可以通過絕對路徑或相對路徑找到一個唯一的文件,前提是在同一目錄下都不允許重名的文件出現(xiàn)。
- 文件是存放在磁盤上的,不管是普通文本文件還是文件夾(Linux上通常稱為目錄)都屬于文件的一種,目錄也是文件;在這種情況下,操作系統(tǒng)如何在磁盤上查找到目標(biāo)文件的呢 —— 給定一個一對一的映射關(guān)系。
Linux ext2
文件系統(tǒng),下圖為磁盤一個分區(qū)的文件系統(tǒng)圖(內(nèi)核內(nèi)存映像肯定有所不同),磁盤是典型的塊設(shè)備,硬盤分區(qū)被劃分為一個個的block。一個block的大小是由格式化的時候確定的,并且不可以更改。例如mke2fs的-b選項(xiàng)可以設(shè)定block大小為1024、2048或4096字節(jié)。而下圖中啟動塊(Boot Block)的大小是確定的。
-
啟動塊(Boot Block)
:里面包含操作系統(tǒng)的位置以及分區(qū)表,開機(jī)信息。 -
Block Group
:ext2文件系統(tǒng)會根據(jù)分區(qū)的大小劃分為數(shù)個Block Group。而每個Block Group都有著相同的結(jié)構(gòu)組成。 -
超級塊(Super Block)
:存放文件系統(tǒng)本身的結(jié)構(gòu)信息。記錄的信息主要有:bolck 和 inode的總量,未使用的block和inode的數(shù)量,一個block和inode的大小,最近一次掛載的時間,最近一次寫入數(shù)據(jù)的時間,最近一次檢驗(yàn)磁盤的時間等其他文件系統(tǒng)的相關(guān)信息。Super Block的信息被破壞,可以說整個文件系統(tǒng)結(jié)構(gòu)就被破壞了,因此超級快通常會備份一定數(shù)量。 -
GDT(Group Descriptor Table)
:塊組描述符,描述塊組屬性信息,記錄inode數(shù)、起始inode編號、block使用量以及剩余量等等信息。 -
塊位圖(Block Bitmap)
:Block Bitmap中記錄著Data Block中哪個數(shù)據(jù)塊已經(jīng)被占用,哪個數(shù)據(jù)塊沒有被占用。 -
inode位圖(inode Bitmap)
:每個bit表示一個inode是否空閑可用。 -
i節(jié)點(diǎn)表(inode table)
:以128字節(jié)為單位,存放文件屬性 如 文件大小,所有者,最近修改時間等。 -
數(shù)據(jù)區(qū)(Data Blocks)
:以4KB為單位,存放文件內(nèi)容。
在inode table中保存了文件對應(yīng)的所有屬性,那么一個inode如何與屬于自己的文件內(nèi)容關(guān)聯(lián)起來呢?
struct inode
{
// 文件所有屬性
...
blocks[15];
...
}
//在inode的結(jié)構(gòu)體中包含一個blocks的數(shù)組,這個數(shù)組保存了文件對應(yīng)的block編號
//其中[0, 11]:直接保存該文件的blocks編號
//[12, 15]:指向一個datablock但是這個datablock不保存有效數(shù)據(jù),而保存該文件所對應(yīng)的其它塊編號
還要注意的是,文件名也是文件屬性,但是inode里面并不保存文件名;Linux下,底層實(shí)際都是通過inode編號來標(biāo)識文件。那么操作系統(tǒng)是如何準(zhǔn)確幫用戶通過文件名找到對應(yīng)的文件內(nèi)容呢?首先,用戶對文件進(jìn)行操作時都是在一個目錄下,不管是創(chuàng)建還是刪除。其次目錄也是一個文件,既然是文件就有屬性和內(nèi)容,其屬性與普通文件類似,那么目錄文件的內(nèi)容是什么呢?
文件名并沒有被保存在文件內(nèi)容中,操作系統(tǒng)又必須通過文件名幫用戶查找文件內(nèi)容,所以文件inode和文件名必須具有映射關(guān)系并且記錄下來,在Linux系統(tǒng)中文件名和文件inode的映射關(guān)系被保存在目錄的內(nèi)容中。同時我們也注意到,Linux同一個目錄下,不可以創(chuàng)建多個同名文件,這說明文件名本身是一個具有Key值的東西。
- 創(chuàng)建一個新文件:當(dāng)我們創(chuàng)建好一個新文件時,操作系統(tǒng)會找到自己所處的目錄下,根據(jù)目錄的inode編號查找到目錄的datablock,然后將文件名和inode映射關(guān)系寫入目錄的數(shù)據(jù)塊中。
- 刪除文件:操作系統(tǒng)刪除一個文件并不會直接清除數(shù)據(jù),而是將標(biāo)記該文件對應(yīng)的屬性和數(shù)據(jù)塊的相關(guān)位圖清除(由1置0),所以刪除的文件是可以恢復(fù)的。
1.3 軟硬鏈接
- 硬鏈接:通過索引節(jié)點(diǎn)(inode)來鏈接。
- 軟鏈接:通過名字引用另外一個文件。
- 通過
ls -l
可以查看文件的硬鏈接數(shù):
//創(chuàng)建一個軟鏈接
ln -s 目標(biāo)文件名 軟鏈接名
//查看文件inode編號
ls -i
上圖可以看到軟鏈接和目標(biāo)文件使用的inode編號是不同的,軟鏈接具有獨(dú)立的inode編號;并且通過軟鏈接mytest文件可以直接運(yùn)行目標(biāo)文件test,軟鏈接相當(dāng)于一個快捷方式,類似Windows系統(tǒng),其中所保存的內(nèi)容是指向文件所在路徑。
//創(chuàng)建一個硬鏈接
ln 目標(biāo)文件 硬鏈接名
硬鏈接不是獨(dú)立的文件,相當(dāng)于一個指針,指向某一個inode,而硬鏈接數(shù)就是引用計數(shù),有幾個硬鏈接指向該inode編號硬鏈接數(shù)就是幾。
Linux中我們常見目錄如下
. :當(dāng)前目錄
.. :上一級目錄
這兩個目錄就是硬鏈接
軟硬鏈接的區(qū)別:軟鏈接是一個獨(dú)立的文件,有自己獨(dú)立的inode編號;硬鏈接不是一個獨(dú)立的文件,它和目標(biāo)文件使用的是同一個inode。
1.4 動靜態(tài)庫
- 靜態(tài)庫:程序在編譯鏈接的時候把庫的代碼鏈接到可執(zhí)行文件中,程序運(yùn)行的時候?qū)⒉辉傩枰o態(tài)庫;靜態(tài)庫Linux下后綴為
.a
文件,windows下后綴為.lib
文件。 - 動態(tài)庫:程序在運(yùn)行的時候才去鏈接動態(tài)庫的代碼,多個程序共享使用庫的代碼。動態(tài)庫Linux下后綴為
.so
文件,windows下后綴為.dll
文件。在Linux下,程序生成默認(rèn)是動態(tài)連接。 - 動態(tài)庫可以在多個程序間共享,所以動態(tài)鏈接使得可執(zhí)行文件更小,節(jié)省了磁盤空間。操作系統(tǒng)采用虛擬內(nèi)存機(jī)制允許物理內(nèi)存中的一份動態(tài)庫被要用到該庫的所有進(jìn)程共用,節(jié)省了內(nèi)存和磁盤空間。
測試程序
/add.h/
#ifndef __ADD_H__
#define __ADD_H__
int add(int a, int b);
#endif // __ADD_H__
/add.c/
#include "add.h"
int add(int a, int b)
{
return a + b;
}
/sub.h/
#ifndef __SUB_H__
#define __SUB_H__
int sub(int a, int b);
#endif // __SUB_H__
/add.c/
#include "add.h"
int sub(int a, int b)
{
return a - b;
}
///main.c
#include <stdio.h>
#include "add.h"
#include "sub.h"
int main( void )
{
int a = 10;
int b = 20;
printf("add(10, 20)=%d\n", a, b, add(a, b));
a = 100;
b = 20;
printf("sub(%d,%d)=%d\n", a, b, sub(a, b));
}
//生成靜態(tài)庫
ar -rc libmymath.a add.o sub.o
ar是gnu歸檔工具,rc表示(replace and create)
//查看靜態(tài)庫中的目錄列表
ar -tv libmymath.a
t:列出靜態(tài)庫中的文件
//gcc編譯鏈接第三方庫
gcc main.c -L. -lmymath
-L 指定庫路徑
-l 指定庫名
將生成的靜態(tài)庫刪除后,程序依舊可以正常運(yùn)行,如下圖:
//生成動態(tài)庫
//shared: 表示生成共享庫格式
//fPIC:產(chǎn)生位置無關(guān)碼(position independent code)
//庫名規(guī)則:libxxx.so
gcc -fPIC -c sub.c add.c
gcc -shared -o libmymath.so add.o sub.o
同樣是上面的add.c和sub.c文件形成.o文件再生成一個動態(tài)庫,將動態(tài)庫使用gcc編譯main.c文件形成可執(zhí)行文件,在刪除動態(tài)庫之后,此時與靜態(tài)庫不同,該文件運(yùn)行出錯表示該動態(tài)庫不存在。
那么鏈接靜態(tài)庫的時候?yàn)槭裁礇]有這個問題呢?或者說鏈接動態(tài)庫和靜態(tài)庫兩者的區(qū)別是什么呢?文章來源:http://www.zghlxwxcb.cn/news/detail-442790.html
- 靜態(tài)鏈接,是將所需要的庫文件中的代碼拷貝進(jìn)我們自己的代碼中,然后再形成一個可執(zhí)行程序,運(yùn)行時程序中已經(jīng)包含了庫中的代碼不需要依賴庫。
- 與靜態(tài)鏈接不同,一個與動態(tài)庫鏈接的可執(zhí)行文件僅僅包含它用到的函數(shù)入口地址的一個表,而不是外部函數(shù)所在目標(biāo)文件的整個機(jī)器碼;在可執(zhí)行文件開始運(yùn)行以前,外部函數(shù)的機(jī)器碼由操作系統(tǒng)從磁盤上的該動態(tài)庫中復(fù)制到內(nèi)存中,這個過程稱為動態(tài)鏈接。
我們使用的庫都是存放在磁盤上的文件,動態(tài)鏈接的可執(zhí)行程序運(yùn)行時會將動態(tài)鏈接庫加載到內(nèi)存中,加載到內(nèi)存中的庫代碼只有一份,進(jìn)程通過頁表將進(jìn)程地址空間和庫鏈接起來,當(dāng)使用動態(tài)鏈接庫中的函數(shù)時會跳轉(zhuǎn)到庫中運(yùn)行。文章來源地址http://www.zghlxwxcb.cn/news/detail-442790.html
到了這里,關(guān)于[Linux] Linux文件系統(tǒng)的文章就介紹完了。如果您還想了解更多內(nèi)容,請在右上角搜索TOY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!