Linux Namespace : Mount


Mount namespace 為進程提供獨立的文件系統視圖。簡單點說就是,mount namespace 用來隔離文件系統的掛載點,這樣進程就只能看到自己的 mount namespace 中的文件系統掛載點
進程的 mount namespace 中的掛載點信息可以在 /proc/[pid]/mounts、/proc/[pid]/mountinfo 和 /proc/[pid]/mountstats 這三個文件中找到。
每個 mount namespace 都有一份自己的掛載點列表。當我們使用 clone 函數或 unshare 函數並傳入 CLONE_NEWNS 標志創建新的 mount namespace 時, 新 mount namespace 中的掛載點其實是從調用者所在的 mount namespace 中拷貝的。但是在新的 mount namespace 創建之后,這兩個 mount namespace 及其掛載點就基本上沒啥關系了(除了 shared subtree 的情況),兩個 mount namespace 是相互隔離的。

本文我們將通過 demo 演示如何對通過 mount namespace 對文件系統進行隔離,以及 shared subtree 在 mount namespace 中的使用方式。本文的演示環境為 ubuntu 16.04。

演示文件系統的隔離

我們通過 iso 文件的掛載來演示 mount namespace 對文件系統的隔離。下面先創建演示用的文件和目錄:

$ sudo mkdir /demo && sudo chmod 777 /demo && cd $_
$ mkdir -p iso1/subdir1
$ mkdir -p iso2/subdir2
$ mkisofs -o 1.iso ./iso1
$ mkisofs -o 2.iso ./iso2

然后再准備兩個充當掛載點:

$ sudo mkdir /mnt/iso1 /mnt/iso2

第一步,我們打開兩個 bash shell,為了方便區分,分別把它們稱為為 shell1 和 shell2。在 shell1 中執行掛載操作,把 1.iso 掛載到 /mnt/iso1 目錄:

$ sudo mount 1.iso /mnt/iso1

第二步,先在 shell2 中執行 sudo unshare -m,然后在兩個 shell 中分別執行 readlink /proc/$$/ns/mnt 命令:

圖中左側為 shell1,右側為 shell2。可以看出它們的 mount namespace 是不同的。
第三步,通過 mount 命令查看兩個 mount namespace 中的掛載點信息:

此時,在這兩個 mount namespace 中,掛載點信息是相同的。
第四步,我們在 shell2 中執行一些 mount 和 umount 操作

$ mount 2.iso /mnt/iso2
$ umount /mnt/iso1

再查之下發現兩個 mount namespace 中的掛載點信息已經完全不一樣了,這就說明 mount namespace 之間的掛載點信息是隔離的(也就是文件系統是隔離的)。

演示 shared subtree 功能

Mount namespace 實現了掛載點的隔離,但對於某些應用場景,會讓我們用起來很不爽。比如系統新添加了一個磁盤設備,我們打算讓所有的 mount namespace 都掛載它。過去的做法只能是在每個 mount namespace 中都掛載一遍,很顯然,這太不方便了。於是在 Linux 內核 2.6.15 引入了 shared subtree 的概念來解決這個問題。Shared subtree 的核心是允許在 mount namespace 之間自動地或者是受控地傳播 mount 和 umount 事件

簡單起見,本文只演示 shared subtree 中 shared 和 private 兩種傳播類型在 mount namespace 中的表現。我們可以簡單的認為 shared 類型的傳播方式可以在滿足條件的情況下把 mount 和 umount 事件傳播給其它的掛載點,而 private 類型的傳播方式則不會把 mount 和 umount 事件傳播給其它的掛載點。關於 shared subtree 的詳細內容,請參考 shared subtree 文檔。關於 shared subtree 與 mount namespace 結合使用的詳細信息,請參考 mount namespace 文檔

我們通過虛擬磁盤文件的掛載來演示 shared subtree 在 mount namespace 中的表現。下面先創建演示用的文件和目錄:

$ sudo mkdir /demo && sudo chmod 777 /demo && cd $_
$ dd if=/dev/zero bs=1M count=32 of=./disk1.img
$ dd if=/dev/zero bs=1M count=32 of=./disk2.img
$ dd if=/dev/zero bs=1M count=32 of=./disk3.img
$ dd if=/dev/zero bs=1M count=32 of=./disk4.img
$ mkfs.ext2 ./disk1.img
$ mkfs.ext2 ./disk2.img
$ mkfs.ext2 ./disk3.img
$ mkfs.ext2 ./disk4.img
$ mkdir disk1 disk2

第一步,我們打開兩個 bash shell,為了方便區分,分別把它們稱為為 shell1 和 shell2。在 shell1 中執行掛載操作,分別以 shared 和 private 方式掛載 disk1 和 disk2:

$ sudo mount --make-shared disk1.img ./disk1
$ sudo mount --make-private disk2.img ./disk2

第二步,在 shell2 中執行 sudo unshare -m --propagation unchanged,然后在兩個 shell 中分別執行 readlink /proc/$$/ns/mnt 命令:

圖中左側為 shell1,右側為 shell2。可以看出它們的 mount namespace 是不同的。默認情況下,unshare 會將新 namespace 里面的所有掛載點的類型設置成 private,所以我們使用參數 --propagation unchanged 讓新 namespace 里的掛載點的類型和老 namespace 里保持一致。--propagation 參數還支持 private|shared|slave 類型,和 mount 命令的那些 --make-private 參數一樣,它們實際上都是通過調用 mount 函數並傳入不同的參數實現的。
第三步,分別在 shell1 和 shell2 中執行 cat /proc/self/mountinfo |grep disk| sed 's/ - .*//' 命令查看掛載點信息:

此時兩個 mount namespace 中的掛載點信息是相同的。由於在掛載 /demo/disk1 時應用了 --make-shared 參數,所以上圖 shell1 中 /demo/disk1 的掛載方式顯示為 shared。又因為在 shell2 中執行 unshare 命令時設置了 --propagation unchanged 參數,所以上圖中 shell2 中 /demo/disk1 的掛載方式也顯示為 shared(*不設置 --propagation unchanged 參數則為 private 方式*)。
第四步在 shell2 中分別在 disk1 目錄下創建 disk3 目錄,在 disk2 目錄下創建 disk4 目錄,並把 disk3.img 掛載到 ./disk1/disk3 目錄,把 disk4.img 掛載到 ./disk2/disk4 目錄:

$ mkdir ./disk1/disk3 ./disk2/disk4
$ mount disk3.img ./disk1/disk3
$ mount disk4.img ./disk2/disk4

然后使用分別在 shell1 和 shell2 中使用 cat /proc/self/mountinfo |grep disk| sed 's/ - .*//' 命令查看掛載點信息:

這次 shell1 中的掛載點信息和 shell2 中的掛載點信息是不一樣的。因為 /demo/disk1 的掛載方式為 shared,所以它的子掛載點 /demo/disk1/disk3 被傳播到了 shell1 所在的 mount namespace 中。而 /demo/disk2 的掛載方式為 private,所以它的子掛載點 /demo/disk2/disk4 不會被傳播。

OK,這就完成了 shared subtree 在 mount namespace 間傳播掛載點信息的基本功能演示,希望這個小 demo 可以幫助大家了解一點 shared subtree 相關的內容。

總結

要把 mount namespace 介紹清楚顯然不是本文的目的,因為單是 shared subtree 在 mount namespace 中的使用方式就夠我們好好的研究一番了。所以,本文只是希望以最少的概念加上最簡單的 demo 來說明什么是 mount namespace、它可以用來干什么以及如何快速的實驗一下。

參考:
Linux Namespace系列(04):mount namespaces (CLONE_NEWNS)
Linux Namespace分析——mnt namespace的實現與應用
Mount namespace man page
Applying mount namespaces


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM