do_path_lookup是檔案系統中最基本的函數,也是非常重要的,裡面各種情況,各種goto,總之各種坑爹。。
沒能把所有的goto都理清,隻看了标準情況下的路徑查找,但主要的關鍵點都是一樣的,弄清了關鍵點,心中對檔案系統的路徑名查找就有了概念。不管絕對路徑名,相對路徑名,還是帶符号連結的,又有什麼質的差別呢?
do_path_lookup分為兩步:
1、path_init根據絕對路徑或者相對路徑來初始化nameidata結構體;
2、path_work-->link_path_walk
link_path_walk才是路徑查找操作中的核心:
link_path_walk處理代表name的字元串,最後都要通過do_lookup函數來do it
do_lookup:
1、檢查具體底層檔案系統是否有自己的hash方法(d_op->d_hash)
2、用__d_lookup函數在dentry_hashtable這個hash表中查找
3、如果在hash表中沒有找到,就要做真正的lookup:
先根據要找的name和parent的dentry,配置設定一個dentry結構體
調用具體檔案系統的i_op->lookup函數,比如sysfs_lookup
提前看一下sysfs_lookup的查找動作:
sysfs_lookup-->sysfs_find_dirent 根據sysfs_dirent的組織關系,在連結清單中周遊查找符合name的sysfs_dirent結構體,
然後再建立inode,并将inode和dentry以及sysfs_dirent聯系起來。
實際檔案系統的lookup方法是一個關鍵點,它根據父層次的dentry和要查找的name在子層次特有的方法來查找。sysfs的lookup方法
是很簡單的,僅僅是周遊一個連結清單,但實際上基于實體媒體的fs的lookup應該是很複雜的,比如omfs就用hash來找,傳說的btrfs應該
會用btree來查找吧。
另外一個關鍵點就是:
done:
path->mnt = mnt;
path->dentry = dentry;
__follow_mount(path);
static int __follow_mount(struct path *path)
{
int res = 0;
while (d_mountpoint(path->dentry)) {
struct vfsmount *mounted = lookup_mnt(path);
if (!mounted)
break;
dput(path->dentry);
if (res)
mntput(path->mnt);
path->mnt = mounted;
path->dentry = dget(mounted->mnt_root);
res = 1;
}
return res;
}
這個函數和上篇do_add_mount中那個不起眼的while的作用是一樣的,做檔案系統的切換操作。
了解了這兩個關鍵點,不管路徑名多長,不管跨越了多少個檔案系統系統,link_path_walk都會一直走下去的。