www.久久久久|狼友网站av天堂|精品国产无码a片|一级av色欲av|91在线播放视频|亚洲无码主播在线|国产精品草久在线|明星AV网站在线|污污内射久久一区|婷婷综合视频网站

當前位置:首頁 > 公眾號精選 > 程序喵大人
[導(dǎo)讀]MOUNT在的文件系統(tǒng)中,有個很重要的概念就是掛載,掛載大家應(yīng)該都很熟悉,除了根文件系統(tǒng),其他所有文件系統(tǒng)都要先掛載到根文件系統(tǒng)中的某個目錄之后才能訪問。所謂的根文件系統(tǒng)就是系統(tǒng)啟動的時候安裝的第一個文件系統(tǒng),它也是內(nèi)核映像所在的文件系統(tǒng)。而掛載到某個目錄的某個目錄就是所謂的掛載...

MOUNT

的文件系統(tǒng)中,有個很重要的概念就是掛載,掛載大家應(yīng)該都很熟悉,除了根文件系統(tǒng),其他所有文件系統(tǒng)都要先掛載到根文件系統(tǒng)中的某個目錄之后才能訪問。


所謂的根文件系統(tǒng)就是系統(tǒng)啟動的時候安裝的第一個文件系統(tǒng),它也是內(nèi)核映像所在的文件系統(tǒng)。而 掛載到某個目錄的 某個目錄就是所謂的掛載點。


中有專門的命令來掛載文件系統(tǒng),mount device dir, 為要掛載的設(shè)備文件名, 為掛載點。這里所說的設(shè)備不是真的指單個實體設(shè)備,而是其上的邏輯設(shè)備,比如說一個磁盤上的不同分區(qū)都可以看作是不同的設(shè)備。


每個設(shè)備都有一個設(shè)備號來標識,設(shè)備號可以分為兩部分,一部分叫做主設(shè)備號 ,它用來標識某一類型的設(shè)備,比如說磁盤。另一部分叫做次設(shè)備號 ,它來標識某一具體設(shè)備,比如說磁盤上的某一具體分區(qū)。


當文件系統(tǒng)掛載到某個目錄后,我們就可以通過這個目錄來訪問該文件系統(tǒng),很多地方就只是簡單的這樣講了一下,但其實這只能說是掛載的作用,那到底什么是掛載,要想解決這個問題還是只能從源碼著手。下面我將根據(jù) 的代碼來講述掛載,涉及的東西比較多,我們只討論相關(guān)的部分。


數(shù)據(jù)結(jié)構(gòu)

m_inode,內(nèi)存中的 inode

struct m_inode {
/********略*********/
unsigned short i_mode; //文件類型和屬性
unsigned char i_mount; //是否有文件系統(tǒng)掛載到這兒
unsigned short i_zone[9]; //索引取,如果是塊/字符設(shè)備文件i_zone[0]是設(shè)備號
/********略*********/
};

super_block,內(nèi)存中的超級塊

struct super_block {
/********略*********/
unsigned short s_magic; //文件系統(tǒng)魔數(shù)
/********略*********/
unsigned short s_dev; //設(shè)備號
/********略*********/
struct m_inode * s_isup; //被掛載的文件系統(tǒng)的根目錄inode
struct m_inode * s_imount; //該文件系統(tǒng)被安裝到此inode
};
所謂的內(nèi)存中的超級塊和 指的是兩者在內(nèi)存中的緩存:


struct super_block super_block[NR_SUPER];
#define NR_SUPER 8
struct m_inode inode_table[NR_INODE];
#define NR_INODE 32
可以看出在 里面內(nèi)存中最多同時存在 8 個超級塊和 32 個文件的 。這個緩存與我們平時所說的緩存差不多,當系統(tǒng)要想獲取一個 時,會先在 中尋找有沒有該 ,如果有的話就直接返回,如果沒有,就從設(shè)備上將 讀到 之后再返回。


相關(guān)操作

在看 掛載之前,先來看看一些操作函數(shù)。


static struct super_block * read_super(int dev);
如果緩存區(qū)中沒有該設(shè)備的超級塊,則先找一個空閑的超級塊槽,然后從設(shè)備上讀取超級塊到找到的空閑超級塊槽。如果該設(shè)備的超級塊已經(jīng)在緩存區(qū)中且數(shù)據(jù)有效,則直接返回該超級塊的指針。


struct super_block * get_super(int dev);
根據(jù)設(shè)備號 從超級塊數(shù)組當中獲取超級塊。


void put_super(int dev);
釋放指定的設(shè)備超級塊,也就是將超級塊的 字段清 0,如此使得該超級塊槽空閑出來。


struct m_inode * namei(const char * pathname);
函數(shù)根據(jù)路徑 獲取末尾文件的 ,這個函數(shù)應(yīng)該是有印象的吧,在 中也有類似的函數(shù)。如果不太清楚的話,我這里舉個例子:如果參數(shù)路徑是 /a/b/c,調(diào)用 之后就會返回文件


掛載

掛載的實現(xiàn)還是挺簡單的,來看代碼


int sys_mount(char * dev_name, char * dir_name, int rw_flag) //將名稱為dev_name的設(shè)備上的文件系統(tǒng)掛載到目錄dir_name上
{
struct m_inode * dev_i, * dir_i;
struct super_block * sb;
int dev;

if (!(dev_i=namei(dev_name))) //沒有找到該設(shè)備
return -ENOENT;
dev = dev_i->i_zone[0];
if (!S_ISBLK(dev_i->i_mode)) { //不是塊設(shè)備
iput(dev_i);
return -EPERM;
}
iput(dev_i); //釋放該設(shè)備的inode
if (!(dir_i=namei(dir_name))) //解析獲取掛載點的inode
return -ENOENT;
if (dir_i->i_count != 1 || dir_i->i_num == ROOT_INO) { //如果掛載點的引用數(shù)不等于1獲取掛載點為根目錄
iput(dir_i);
return -EBUSY;
}
if (!S_ISDIR(dir_i->i_mode)) { //掛載點不是目錄
iput(dir_i);
return -EPERM;
}
if (!(sb=read_super(dev))) { //將設(shè)備上的文件系統(tǒng)的超級塊讀取到內(nèi)存中
iput(dir_i);
return -EBUSY;
}
if (sb->s_imount) { //如果該文件系統(tǒng)已掛載
iput(dir_i);
return -EBUSY;
}
if (dir_i->i_mount) { //如果掛載點已經(jīng)掛載了其他文件系統(tǒng)
iput(dir_i);
return -EPERM;
}
sb->s_imount=dir_i; //將掛載點的inode記錄到設(shè)備的超級塊中
dir_i->i_mount=1; //表示該掛載點已經(jīng)掛載了該文件系統(tǒng)
dir_i->i_dirt=1; /* NOTE! we don't iput(dir_i) */ //我們不會釋放掛載點的inode
return 0; /* we do that in umount */ //我們在umount卸載文件系統(tǒng)時釋放
}
其流程圖為:


上圖為 的實現(xiàn)過程,除了各種檢查之外, 實際上只做了兩件事:


  1. 將要掛載的文件系統(tǒng)的超級塊讀到內(nèi)存里的超級塊槽
  2. 設(shè)置該超級塊的 字段為 掛載點的 ,表示文件系統(tǒng)掛載到這個目錄上,設(shè)置掛載點 字段為 1 表示該目錄上掛載的有文件系統(tǒng)
另外再解釋幾點:


  1. 字符設(shè)備,提供連續(xù)的數(shù)據(jù)流,應(yīng)用程序可以順序讀取數(shù)據(jù),通常不支持隨機存取,像前面提到過的鍵盤串口都屬于字符設(shè)備。塊設(shè)備,應(yīng)用程序能夠隨機訪問設(shè)備的數(shù)據(jù),程序可以自行確定數(shù)據(jù)的位置,比如說硬盤就是典型的塊設(shè)備。很明顯地文件系統(tǒng)只能存放在塊設(shè)備上。
  2. 掛載點只能是個目錄文件,文件系統(tǒng)都是掛載到目錄上的
  3. 掛載文件系統(tǒng)時,掛載點這個目錄文件只能在當前引用,也就是說在掛載文件系統(tǒng)的時候,還有其他地方正在使用掛載點目錄的話就不對
這就是掛載的本質(zhì),有沒有感覺簡單的同時又還是模模糊糊的?為什么將文件系統(tǒng)掛載到某個目錄之后,這個目錄就能表示被掛載的文件系統(tǒng)。解決這個問題還是要再來捋捋文件系統(tǒng)是如何尋找一個文件的,也就是 函數(shù),比如說給定一個路徑 /a/b,這是一個絕對路徑,如何從最開始的根目錄尋到文件 的呢?


這個問題我在 文件系統(tǒng)里面也詳細說過, 里也類似。這里我們假設(shè) 文件都是目錄文件, 是一個普通文件。首先根目錄文件就是一個個目錄項,在其中尋找文件名為 的目錄項,從中獲取 目錄文件的 ,根據(jù) 的索引字段找到 目錄文件的數(shù)據(jù),也是一個個目錄項,在其中尋找文件名為 的目錄項,從中獲取普通文件 然后返回。


上述所說的獲取某個 ,使用的函數(shù)是,,其意為從設(shè)備 中獲取編號為 。這個函數(shù)就會判斷編號為 上是否掛載的有文件系統(tǒng),來看相關(guān)代碼:


struct m_inode * iget(int dev, int nr){
/*********略**********/
inode = inode_table; //從inode表中第一個元素開始
while (inode < NR_INODE inode_table) { //掃描內(nèi)存里緩存的inode表
if (inode->i_dev != dev || inode->i_num != nr) { //如果設(shè)備號對不上或者inode編號對不上
inode ; //下一個
continue;
}
wait_on_inode(inode); //等待該inode解鎖
if (inode->i_dev != dev || inode->i_num != nr) { //因為等待過程中inode可能會發(fā)生變化,所以再次判斷
inode = inode_table;
continue;
}
inode->i_count ; //找到了該inode,將其引用數(shù)加1
if (inode->i_mount) { //如果該inode上掛載的有文件系統(tǒng)
int i;

for (i = 0 ; i//在內(nèi)存中緩存的超級塊中尋找掛載點為當前inode的超級塊
if (super_block[i].s_imount==inode) //找到了,break
break;
if (i >= NR_SUPER) { //沒找到,返回
printk("Mounted inode hasn't got sb\n");
if (empty)
iput(empty);
return inode;
}
iput(inode); //釋放當前inode
dev = super_block[i].s_dev; //將設(shè)備號重新設(shè)置為被掛載的文件系統(tǒng)所在的設(shè)備號
nr = ROOT_INO; //將要尋找的inode編號重新設(shè)置為根目錄的inode編號
inode = inode_table; //從內(nèi)存的inode表第一個元素重新開始尋找inode
continue;
}
if (empty) //釋放臨時找的空閑inode
iput(empty);
return inode; //返回獲取到的inode
}
}
其完整的流程圖如下:


這是我根據(jù)趙炯畫的圖改編,因為沒有詳細講述 的代碼,所以主要關(guān)注虛線方框里面的就行。


如果在 中找到相應(yīng)的 ,就判斷 ,如果為真,表示該 表示的目錄文件上面掛載的有文件系統(tǒng)。此時這個目錄應(yīng)該表示被掛載的文件系統(tǒng)的根目錄,所以設(shè)置 超級塊表示的設(shè)備,原目錄就被隱藏掉了。舉個例子再說明一下,假如調(diào)用 ,本來我是要獲取 1 號設(shè)備的第 99 個 ,然后發(fā)現(xiàn)這個 指向的目錄上面掛載的有 2 號設(shè)備的文件系統(tǒng),那么我們就去尋找 2 號設(shè)備的根目錄 然后返回。所以看起來調(diào)用 實則調(diào)用的 ,這也就是為什么說將文件系統(tǒng)掛載到某個目錄之后,這個目錄就被屏蔽了的原因所在。


到此,對文件系統(tǒng)的掛載應(yīng)該有個很清晰的認識呢,最后來看看文件系統(tǒng)的卸載,基本上就是掛載的逆操作,來簡單看看:


int sys_umount(char * dev_name)
{
struct m_inode * inode;
struct super_block * sb;
int dev;

if (!(inode=namei(dev_name))) //解析獲取設(shè)備文件的inode
return -ENOENT;
dev = inode->i_zone[0]; //對于塊/字符設(shè)備,設(shè)備號記錄在i_zone[0]
if (!S_ISBLK(inode->i_mode)) { //如果不是塊設(shè)備
iput(inode);
return -ENOTBLK;
}
iput(inode); //釋放設(shè)備文件的inode
if (dev==ROOT_DEV) //如果要卸載的是根文件系統(tǒng)
return -EBUSY;
if (!(sb=get_super(dev)) || !(sb->s_imount)) //如果沒有獲取到設(shè)備的超級塊或者如果掛載點為空
return -ENOENT;
if (!sb->s_imount->i_mount) //如果掛載點的掛載標識為空
printk("Mounted inode has i_mount=0\n");
//檢查是否有進程在使用將要卸載文件系統(tǒng)上的文件
for (inode=inode_table 0 ; inode if (inode->i_dev==dev 
本站聲明: 本文章由作者或相關(guān)機構(gòu)授權(quán)發(fā)布,目的在于傳遞更多信息,并不代表本站贊同其觀點,本站亦不保證或承諾內(nèi)容真實性等。需要轉(zhuǎn)載請聯(lián)系該專欄作者,如若文章內(nèi)容侵犯您的權(quán)益,請及時聯(lián)系本站刪除。

程序喵大人

185 篇文章

關(guān)注

發(fā)布文章

編輯精選

技術(shù)子站

關(guān)閉