基礎知識在<深刻linux內核架構>第8章,自行腦補.node
看下幾個關鍵的過程:linux
do_add_mount裏有重要函數lock_mount, lock_mount函數的輸入是struct path, 輸出是struct mountpoint:docker
struct path { struct vfsmount *mnt; struct dentry *dentry; };
struct mountpoint { struct hlist_node m_hash; struct dentry *m_dentry; struct hlist_head m_list; int m_count; };
struct vfsmount { struct dentry *mnt_root; /* root of the mounted tree */ struct super_block *mnt_sb; /* pointer to superblock */ int mnt_flags; };
path 由 filename_lookup 獲得, 其中vfsmount是當前文件系統的掛載信息, dentry是經過文件名得出的最後一級目錄的dentry(好比,/mnt/dir1/dir2/,那麼此時dentry對應的就是dir2的dentry.數組
函數: m_hash(struct vfsmount *mnt, struct dentry *dentry)架構
二元組<mnt, dentry>能夠肯定什麼東西? 這個二元組能夠惟一肯定當前目錄樹中的一個目錄[感受直接用一個dentry也能夠獲得啊! 可是用兩個參數可能散列效果更好?] ,這樣能夠直接獲得一個下標(下標是mount_hashtable的下標). mount_hashtable是個什麼事情?函數
這個就是函數m_hash的輸出了:mount_hashtable[tmp & m_hash_mask].spa
咱們發現,原來全部mount結構體都是經過連接元素mnt_hash連接到mount_hashtable[**]中去的,因此當咱們發現了這個鏈表以後,就能夠經過這個鏈表獲得在這個開鏈上的全部的mount結構體!這裏就獲得了一個很重要的信息[全部的mount信息都在一個散列表mount_hashtable上維護]code
這樣咱們就能夠找到一個掛載點的全部的掛載信息了!blog
lookup_mnt還算是比較複雜的, 涉及到一個掛載點上掛載了多個"磁盤", lookup會找到最先的掛載的磁盤, 這個能夠之後看, 如今咱們只須要知道lookup_mnt發到了vfsmount結構體就能夠了!資源
另外一個函數:lookup_mountpoint(struct dentry *dentry), 這個函數在是經過dentry項, 找到全局數組&mountpoint_hashtable中的一個開鏈:mountpoint_hashtable[tmp & mp_hash_mask];
這裏也獲得一個很重要的信息:
[全部的mountpoing信息都是在一個全局的散列表mountpoint_hashtable上維護]
mountpoint 和 vfsmount有什麼區別?
struct mountpoint { struct hlist_node m_hash; struct dentry *m_dentry; struct hlist_head m_list; int m_count; };
mountoint只和dentry相關,
因此說lock_mount到最後就是獲得一個mountpoint,
-------------------------
無關:
函數vfs_kern_mount(struct file_system_type *type, int flags, const char *name, void *data)
首先根據文件名, 分配 mount 結構體, alloc_vfsmnt(name),
而後調用mount_fs函數獲得fs相對根目錄dentry,
根據dentry,初始化mount結構體, 而後根據返回mount結構提中的vfsmount成員.
--------------------------
attach_recursive_mnt是最終把這些散亂的東西連接在一塊兒的函數
static int attach_recursive_mnt(struct mount *source_mnt,
struct mount *dest_mnt,
struct mountpoint *dest_mp,
struct path *parent_path)
各參數中, source_mnt當前新的掛載信息, dest_mnt是父掛載信息, dest_mp是掛載點的信息, parent_path是路徑的信息
內核代碼中這個函數頭的註釋我也是醉了, 好大一長串, (其中涉及到mount的屬性:shared, private, slave, unbindable 等等), 之因此這麼複雜, 是由於考慮到namespace的東西,這個也是未來要看的,看下docker究竟是個神馬東西!
===========
mount這一塊確實有看頭哈,看下到底怎麼經過掛載點把資源給隔離開!
主要看函數:mnt_set_mountpoint (struct mount *mnt, struct mountpoint *mp, struct mount *child_mnt)
首先,mountpoint是怎麼來的? mountpoint經過dentry而來, 上來以後,先把
mp->m_count++; 而後設置子mount 的 mnt_parent 爲 父mount , 子mount的mnt_mountpoint點設置成mp->m_dentry, mountpoint中有一個串聯全部mount信息的一個鏈叫作m_list, 這個鏈裏面會把該mountpoint下面全部的mount連接在一塊兒.
===========
3.6 commit_tree()
1.將當前文件系統的名字空間設置爲父名字空間,父vfsmount經過當前vfsmount中的mnt_parent獲取;再將其鏈接到父名字空間鏈表中。
2.將當前vfsmount加入到對應哈希值的衝突鏈表當中,哈希值經過hash()計算。其中,mnt_hash做爲鏈表元素。
3.將當前vfsmount加入到父vfsmount對應的子文件系統鏈表mnt_mounts中。其中,mnt_child做爲鏈表元素。
從整個掛載的處理流程上看,掛載的本質就是將源文件系統的vfsmount結構鏈接到目的文件系統對應的vfsmount結構中,即具體涉及到兩個vfsmount中字段的指向問題。兩個vfsmount具體父子等級關係,這也對應着內核中目錄樹的父子等級關係。
關鍵函數:commit_tree(struct mount *mnt, struct mount *shadows)
1 將子文件系統的命名空間設置成父命名空間, 父vfsmount經過當前vfsmount中的mnt_parent獲取; 再將其聯街道父命名空間列表中去.
2 將當前vfsmount加入到對應哈希值的衝突鏈表中去,
3 將當前vfsmount加入到父vfsmount對應的子文件系統鏈表mnt_mounts中去,