自拍偷在线精品自拍偷,亚洲欧美中文日韩v在线观看不卡

我們一起學(xué)學(xué)加載根文件系統(tǒng)

系統(tǒng) 其他OS
可是硬盤中憑什么就有了這些信息呢?這就是個雞生蛋蛋生雞的問題了。你可以先寫一個操作系統(tǒng),然后給一個硬盤做某種文件系統(tǒng)類型的格式化,這樣你就得到一個有文件系統(tǒng)的硬盤了,有了這個硬盤,你的操作系統(tǒng)就可以成功啟動了。

書接上回,上回書咱們說到,我們已經(jīng)把硬盤的基本信息存入了 hd_info[]。

把硬盤的分區(qū)信息存入了 hd[]。

并且留了個讀取硬盤數(shù)據(jù)的 bread 函數(shù)沒有講,等主流程講完再展開這些函數(shù)的細(xì)節(jié),我知道這是你們關(guān)心的內(nèi)容。

這些都是 setup 方法里做的事情,也就是進(jìn)程 0 fork 出的進(jìn)程 1 所執(zhí)行的第一個方法。

今天我們說 setup 方法中的最后一個函數(shù) mount_root。

int sys_setup(void * BIOS) {
...
mount_root();
}

mount_root 直譯過來就是加載根。

再多說幾個字是加載根文件系統(tǒng),有了它之后,操作系統(tǒng)才能從一個根兒開始找到所有存儲在硬盤中的文件,所以它是文件系統(tǒng)的基石,很重要。

我們翻開看看。

void mount_root(void) {
int i,free;
struct super_block * p;
struct m_inode * mi;

for(i=0;i<64;i++)
file_table[i].f_count=0;

for(p = &super_block[0] ; p < &super_block[8] ; p++) {
p->s_dev = 0;
p->s_lock = 0;
p->s_wait = NULL;
}
p=read_super(0);
mi=iget(0,1);

mi->i_count += 3 ;
p->s_isup = p->s_imount = mi;
current->pwd = mi;
current->root = mi;
free=0;
i=p->s_nzones;
while (-- i >= 0)
if (!set_bit(i&8191,p->s_zmap[i>>13]->b_data))
free++;

free=0;
i=p->s_ninodes+1;
while (-- i >= 0)
if (!set_bit(i&8191,p->s_imap[i>>13]->b_data))
free++;
}

很簡單。

從整體上說,它就是要把硬盤中的數(shù)據(jù),以文件系統(tǒng)的格式進(jìn)行解讀,加載到內(nèi)存中設(shè)計好的數(shù)據(jù)結(jié)構(gòu),這樣操作系統(tǒng)就可以通過內(nèi)存中的數(shù)據(jù),以文件系統(tǒng)的方式訪問硬盤中的一個個文件了。

那其實搞清楚兩個事情即可:

第一,硬盤中的文件系統(tǒng)格式是怎樣的?

第二,內(nèi)存中用于文件系統(tǒng)的數(shù)據(jù)結(jié)構(gòu)有哪些?

我們一個個來。

硬盤中的文件系統(tǒng)格式是怎樣的?

首先硬盤中的文件系統(tǒng),無非就是硬盤中的一堆數(shù)據(jù),我們按照一定格式去解析罷了。Linux-0.11 中的文件系統(tǒng)是 MINIX 文件系統(tǒng),它就長成這個樣子。

每一個塊結(jié)構(gòu)的大小是 1024 字節(jié),也就是 1KB,硬盤里的數(shù)據(jù)就按照這個結(jié)構(gòu),妥善地安排在硬盤里。

可是硬盤中憑什么就有了這些信息呢?這就是個雞生蛋蛋生雞的問題了。你可以先寫一個操作系統(tǒng),然后給一個硬盤做某種文件系統(tǒng)類型的格式化,這樣你就得到一個有文件系統(tǒng)的硬盤了,有了這個硬盤,你的操作系統(tǒng)就可以成功啟動了。

總之,想個辦法給這個硬盤寫上數(shù)據(jù)唄。

好了,現(xiàn)在我們簡單看看 MINIX 文件系統(tǒng)的格式。

引導(dǎo)塊就是我們系列最開頭說的啟動區(qū),當(dāng)然不一定所有的硬盤都有啟動區(qū),但我們還是得預(yù)留出這個位置,以保持格式的統(tǒng)一。

超級塊用于描述整個文件系統(tǒng)的整體信息,我們看它的字段就知道了,有后面的 inode 數(shù)量,塊數(shù)量,第一個塊在哪里等信息。有了它,整個硬盤的布局就清晰了。

inode 位圖和塊位圖,就是位圖的基本操作和作用了,表示后面 inode 和塊的使用情況,和我們之前講的內(nèi)存占用位圖 mem_map[] 是類似的。

再往后,inode 存放著每個文件或目錄的元信息和索引信息,元信息就是文件類型、文件大小、修改時間等,索引信息就是大小為 9 的 i_zone[9] 塊數(shù)組,表示這個文件或目錄的具體數(shù)據(jù)占用了哪些塊。

其中塊數(shù)組里,0~6 表示直接索引,7 表示一次間接索引,8 表示二次間接索引。當(dāng)文件比較小時,比如只占用 2 個塊就夠了,那就只需要 zone[0] 和 zone[1] 兩個直接索引即可。

再往后,就都是存放具體文件或目錄實際信息的塊了。如果是一個普通文件類型的 inode 指向的塊,那里面就直接是文件的二進(jìn)制信息。如果是一個目錄類型的 inode 指向的塊,那里面存放的就是這個目錄下的文件和目錄的 inode 索引以及文件或目錄名稱等信息。

好了,文件系統(tǒng)格式的說明,我們就簡單說明完畢了,MINIX 文件系統(tǒng)已經(jīng)過時。

內(nèi)存中用于文件系統(tǒng)的數(shù)據(jù)結(jié)構(gòu)有哪些?

趕緊回過頭來看我們的代碼,是如何加載以這樣一種格式存放在硬盤里的數(shù)據(jù),以被我們操作系統(tǒng)所管控的。

從頭看。

struct file {
unsigned short f_mode;
unsigned short f_flags;
unsigned short f_count;
struct m_inode * f_inode;
off_t f_pos;
};

void mount_root(void) {
for(i=0;i<64;i++)
file_table[i].f_count=0;
...
}

把 64 個 file_table 里的 f_count 清零。

這個 file_table 表示進(jìn)程所使用的文件,進(jìn)程每使用一個文件,都需要記錄在這里,包括文件類型、文件 inode 索引信息等,而這個 f_count 表示被引用的次數(shù),此時還沒有引用,所以設(shè)置為零。

而這個 file_table 的索引,就是我們通常說的文件描述符。比如有如下命令。

echo "hello" > 0

就表示把 hello 輸出到 0 號文件描述符。

0 號文件描述符是哪個文件呢?就是 file_table[0] 所表示的文件。

這個文件在哪里呢?注意到 file 結(jié)構(gòu)里有個 f_inode 字段,通過 f_inode 即可找到它的 inode 信息,inode 信息包含了一個文件所需要的全部信息,包括文件的大小、文件的類型、文件所在的硬盤塊號,這個所在硬盤塊號,就是文件的位置咯。

接著看。

struct super_block super_block[8];
void mount_root(void) {
...
struct super_block * p;
for(p = &super_block[0] ; p < &super_block[8] ; p++) {
p->s_dev = 0;
p->s_lock = 0;
p->s_wait = NULL;
}
...
}

又是把一個數(shù)組 super_block 做清零工作。

這個 super_block 存在的意義是,操作系統(tǒng)與一個設(shè)備以文件形式進(jìn)行讀寫訪問時,就需要把這個設(shè)備的超級塊信息放在這里。

這樣通過這個超級塊,就可以掌控這個設(shè)備的文件系統(tǒng)全局了。

果然,接下來的操作,就是讀取硬盤的超級塊信息到內(nèi)存中來。

void mount_root(void) {
...
p=read_super(0);
...
}

read_super 就是讀取硬盤中的超級塊。

接下來,讀取根 inode 信息。

struct m_inode * mi;
void mount_root(void) {
...
mi=iget(0,1);
...
}

然后把該 inode 設(shè)置為當(dāng)前進(jìn)程(也就是進(jìn)程 1)的當(dāng)前工作目錄和根目錄。

void mount_root(void) {
...
current->pwd = mi;
current->root = mi;
...
}

然后記錄塊位圖信息。

void mount_root(void) {
...
i=p->s_nzones;
while (-- i >= 0)
set_bit(i&8191, p->s_zmap[i>>13]->b_data);
...
}

最后記錄 inode 位圖信息。

void mount_root(void) {
...
i=p->s_ninodes+1;
while (-- i >= 0)
set_bit(i&8191, p->s_imap[i>>13]->b_data);
}

就完事了。

其實整體上就是把硬盤中文件系統(tǒng)的各個信息,搬到內(nèi)存中。之前的圖可以說非常直觀了。

有了內(nèi)存中的這些結(jié)構(gòu),我們就可以順著根 inode,找到所有的文件了。

至此,加載根文件系統(tǒng)的 mount_root 函數(shù)就全部結(jié)束了。同時,讓我們回到全局視野,發(fā)現(xiàn) setup 函數(shù)也一并結(jié)束了。

void main(void) {
...
move_to_user_mode();
if (!fork()) {
init();
}
for(;;) pause();
}

void init(void) {
setup((void *) &drive_info);
...
}

int sys_setup(void * BIOS) {
...
mount_root();
}

setup 的主要工作就是我們今天所講的,加載根文件系統(tǒng)。

我們繼續(xù)往下看 init 函數(shù)。

void init(void) {
setup((void *) &drive_info);
(void) open("/dev/tty0",O_RDWR,0);
(void) dup(0);
(void) dup(0);
}

看到這相信你也明白了。

之前 setup 函數(shù)的一番折騰,加載了根文件系統(tǒng),順著根 inode 可以找到所有文件,就是為了下一行 open 函數(shù)可以通過文件路徑,從硬盤中把一個文件的信息方便地拿到。

在這里,我們 open 了一個 /dev/tty0 的文件,那我們接下來的焦點就在這個 /dev/tty0 是個啥?

責(zé)任編輯:武曉燕 來源: 低并發(fā)編程
相關(guān)推薦

2022-12-09 08:34:38

嵌入式Web容器

2022-07-28 08:52:08

Docker命令操作系統(tǒng)

2024-03-11 10:30:31

Linux文件系統(tǒng)

2021-12-14 09:34:31

丑數(shù)順序指針

2022-01-10 06:52:59

拖拽庫項目搜索

2022-09-22 08:06:29

計算機(jī)平板微信

2024-04-29 13:07:00

運維保命原則Oracle

2023-11-06 08:28:43

2024-02-28 08:47:29

文件系統(tǒng)數(shù)據(jù)

2021-09-15 19:02:42

Node.jsFs模塊

2023-08-02 08:35:54

文件操作數(shù)據(jù)源

2023-08-04 08:20:56

DockerfileDocker工具

2021-01-12 05:08:49

DHCP協(xié)議模型

2021-08-27 07:06:09

DubboDocker技術(shù)

2022-03-31 18:59:43

數(shù)據(jù)庫InnoDBMySQL

2022-05-24 08:21:16

數(shù)據(jù)安全API

2023-08-10 08:28:46

網(wǎng)絡(luò)編程通信

2022-10-18 07:33:57

Maven構(gòu)建工具

2023-09-10 21:42:31

2023-06-30 08:18:51

敏捷開發(fā)模式
點贊
收藏

51CTO技術(shù)棧公眾號