Linux虛擬文件系統--文件路徑名的解析(2)--回退父目錄

     上文介紹瞭解析文件路徑名的一個通體的過程,這裏再把其中的一些細節拿出來進行分析。首先對於文件名的特點,可以分爲三類:普通文件名,'.'和'..',對於'.'的處理很簡單,因爲它表示當前目錄,因此直接通過continue進入下一輪查找即可,對於'..',也就是退回到父目錄,本身也不是一件難事,但是這裏要考慮到幾個特殊情況,先看看內核處理'..'的方法:

static __always_inline void follow_dotdot(struct nameidata *nd)
{
	set_root(nd);

	while(1) {
		struct vfsmount *parent;
		struct dentry *old = nd->path.dentry;

		/*如果當前所處的目錄即爲根目錄則break*/
		if (nd->path.dentry == nd->root.dentry &&
		    nd->path.mnt == nd->root.mnt) {
			break;
		}
		spin_lock(&dcache_lock);

		//如果當前所處的目錄不爲當前路徑所屬文件系統的根目錄,也就是說可以直接向上退一級
		if (nd->path.dentry != nd->path.mnt->mnt_root) {
			nd->path.dentry = dget(nd->path.dentry->d_parent);//當前的目錄退到上一級
			spin_unlock(&dcache_lock);
			dput(old);
			break;
		}

		/*下面的情況對應於當前所處的目錄爲文件系統的根目錄*/
		spin_unlock(&dcache_lock);
		spin_lock(&vfsmount_lock);
		parent = nd->path.mnt->mnt_parent;//取父文件系統
		if (parent == nd->path.mnt) {//父文件系統即爲本身,則表明沒有父文件系統,直接break
			spin_unlock(&vfsmount_lock);
			break;
		}
		mntget(parent);//增加父文件系統的引用計數
		nd->path.dentry = dget(nd->path.mnt->mnt_mountpoint);//取當前文件系統的掛載點,這樣就退回到了父文件系統
		spin_unlock(&vfsmount_lock);
		dput(old);
		mntput(nd->path.mnt);
		nd->path.mnt = parent;//設置當前路徑的mnt爲父文件系統
	}
	/*一般情況下,前面的操作可以保證返回到上級目錄,但是有一種情況就是
	  當前目錄的上級目錄有可能還掛載了其他的文件系統,這樣會隱藏之前的文件系統,
	  follow_mount()用來處理這種情況*/
	follow_mount(&nd->path);
}

 

while循環裏面的路徑可以分爲三種:

1.當前目錄爲nd中已經預設好的根目錄,也就是說無法再向上退一層了,這種情況直接break

2.當前目錄不爲所屬文件系統的根目錄,這種情況是最常見的,可以向上退一層

3.當前目錄爲所屬文件系統的掛載點,這種情況下,後退一層的話則會進入到父文件系統中,所以先要做一個文件系統的交換,再通過while(1)循環回到前面兩種情況

在一般情況下while(1)循環中的內容可以保證正確的退到父目錄,但是考慮一種情況就是,當用戶進入了一個目錄後,其父目錄上又重新掛載了一個文件系統,這時新的文件系統會覆蓋舊的文件系統,使得之前的內容都被隱藏,因此這時要後退到上級目錄則不是退回到原本所屬的文件系統的目錄了,而是退回到了最新的那個文件系統的掛載點。下面的一個例子可以用來說明這種情況:

1. 通過mkdir -p /mnt/test在/mnt目錄下創建一個test目錄

2. cd /mnt/test

3. ls ..   這時可以看到我們後退到的目錄對應的是原文件系統,因此顯示的是test

4. mount /dev/cdrom /mnt

5.ls ..   這時因爲重新掛載了一個文件系統,因此test對應的文件系統被覆蓋,所以顯示的內容是cdrom根目錄下的內容而看不到test了。

follow_mount()函數就是用來解決這麼一個問題,即保證後退(或者前進)的目錄是最新的那個文件系統對應的目錄

 

static void follow_mount(struct path *path)
{        //通過逐級的循環來找到最近的那個被掛載的文件系統
	while (d_mountpoint(path->dentry)) {//目錄下有文件系統被安裝
		struct vfsmount *mounted = lookup_mnt(path);//找到path下掛載的子文件系統
		if (!mounted)//如果mounted爲0,也就表示之前處理的子文件系統是最後一個子文件系統了,
			break;   //這個文件系統的mnt纔是所要返回的上級目錄的真正mnt
		dput(path->dentry);
		mntput(path->mnt);
		path->mnt = mounted;//保存vfsmount
		path->dentry = dget(mounted->mnt_root);//保存dentry,並更新引用計數
	}
}


 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章