1. 程式人生 > >(萊昂氏unix原始碼分析導讀-43) 檔案系統的mount

(萊昂氏unix原始碼分析導讀-43) 檔案系統的mount

                         By cszhao1980

當一個裝置被mount進系統,就會在“mount表”中佔據一個表項,mount表的定義如下:

0272: struct mount

0273: {

0274:     int m_dev     /* device mounted */

0275:     int *m_bufp;   /* pointer to superblock */

0276:     int *m_inodp;  /* pointer to mounted on inode */

0277: } mount[NMOUNT];     

m_dev記錄被mount

裝置的裝置號;

m_bufp指向一個快取,其內容是裝置的“超級塊”;

m_inodep指向所謂的“mount on inode,我們會在後面的討論中對其進一步瞭解。

首先,我們來看一看root裝置是怎樣被mount進系統的。

首先,rootdev的定義如下:

4695: int rootdev {(0<<8)|0};

顯然,其裝置號為0,即我們的RK磁碟裝置。

然後,在main()函式中呼叫iinit()函式——它負責把rootdev Load進系統:

1615:    iinit();                    

6922: iinit()

6923: {

6924:     register *cp, *bp;

6925:

6926:     (*bdevsw[rootdev.d_major].d_open)(rootdev, 1);

6927:     bp = bread(rootdev, 1);

6928:     cp = getblk(NODEV);

6929:     if(u.u_error)

6930:         panic("iinit");

6931:     bcopy(bp->b_addr, cp->b_addr, 256);

6932:     brelse(bp);

6933:     mount[0].m_bufp = cp;

6934:     mount[0].m_dev = rootdev;

6935:     cp = cp->b_addr;

6936:     cp->s_flock = 0;

6937:     cp->s_ilock = 0;

6938:     cp->s_ronly = 0;

6939:     time[0] = cp->s_time[0];

6940:     time[1] = cp->s_time[1];

6941: }

如果您對上一章的內容比較清楚的話,iinit()函式就顯得很簡單了:

(1)         利用塊裝置表呼叫rootdevRK磁碟)的d_open函式,如果您還記得的話,

                   該函式是個空函式,也就是說對RK磁碟來說,無需進行open操作,就直接可用;

(2)         然後,呼叫bread()函式將rootdev#1塊(即超級塊)讀入快取;

(3)         接著它又呼叫getblk(NODEV)申請了一個“空閒裝置”快取——該快取沒有與任何

                    實際裝置相關連。接著將超級塊的內容通過bcopy函式,拷貝到給快取中。

(4)         呼叫brelse函式,將rootdev快取送還AV佇列;

(5)         mount表的#0表項分配給rootdev,其m_dev設定為rootdev0),而m_bufp指向裝

                   有超級塊內容的“空閒裝置”快取;

(6)         接下來的操作就跟超級塊的內容有關了,我們接下來就看一下超級塊。

超級塊的內容如下所示:

5561: struct filsys

5562: {

5563:     int s_isize;      /* size in blocks of I list */

5564:     int s_fsize;      /* size in blocks of entire volume */

5565:     int s_nfree;      /* number of in core free blocks (0-100) */

5566:

5567:     int s_free[100];   /* in core free blocks */

5568:     int s_ninode;     /* number of in core I nodes (0-100) */

5569:     int s_inode[100];  /* in core free I nodes */

5570:     char s_flock;     /* lock during free list manipulation */

5571:     char s_ilock;     /* lock during I list manipulation */

5572:     char s_fmod;     /* super block modified flag */

5573:     char s_ronly;     /* mounted read-only flag */

5574:     int s_time[2];     /* current date of last update */

5575:     int pad[50];

5576: };

內容不少,我們先了解其中幾項:

(1)         s_isize:即有多少個塊是用來存放inde列表的;

(2)         s_fsize:整個檔案系統共有多少個塊;

(3)         s_ninode:讀入記憶體的inode項數;

(4)         s_inode[100]:存放讀入記憶體的indode項;

在上述操作中,並沒有設定mount陣列項中所謂的“mount oninode指標——這時因為rootdev

mount是很“自然”的事,它的檔案系統根目錄,直接變成了系統根目錄,沒有mount點之說。

下面我們來看smount ()函式——它用來處理mount sys call,即通過該函式可以將一個裝置mount到系統中。

mount的過程和上述過程類似,萊昂解釋的也比較清晰,我只簡單說幾點。

1. 引數傳遞

smount有三個引數,都通過.u_arg[]陣列傳遞:

(1)         u_arg[0] (u.dirp) ——指向一個Path name字串,該Path name的檔案inode-i_dev為要mount

                  裝置的裝置號;smount會呼叫getmdev()函式來得到裝置id

                 (該檔案應該為一裝置描述檔案,也許就是“特殊塊裝置”(IFBLK)檔案);

(2)         u_arg[1] ——指向“要mount到的”目錄的Path name

(3)         u_arg[2] —— read only flag

2.  mount

mount到的目錄被稱為mount點,該目錄的inode會設定IMOUNT標誌。

3.  IFBLK/ IFCHR分別為特殊塊裝置、特殊字元裝置標誌;

很自然的,我們接下來看一下sumount函式,即unmount sys call的處理函式。

我們基本上可以將其理解為smount的“反”函式,即:

(1)         將該裝置從系統mount表中刪除;

(2)         mount點的IMOUNT標誌清除;

(3)         釋放該檔案系統的超級塊。

除此之外,還需要注意兩點:

(1)         unmount裝置時,會Loop系統的inode陣列,如果陣列項中有該裝置上的檔案

                 (即該檔案處理active狀態),則禁止unmount裝置;

(2)         在所有操作之前,呼叫update()進行了檔案系統更新。

update7201)執行三種更新:

(1)         Loop mount表,將每個檔案系統的超級塊(記憶體中的)的內容寫回磁碟;

(2)         Loop inode陣列,將inode寫回磁碟;

(3)         呼叫bflush,將“延遲寫”塊寫入磁碟。