當 100% 分頁到頁面記憶體的文件被另一個程序修改時會發生什麼
我知道當頁面記憶體頁面被修改時,它被標記為臟並需要寫回,但是在以下情況下會發生什麼:
場景: 文件 /apps/EXE 是一個執行檔,被完全分頁到頁面記憶體中(它的所有頁面都在記憶體/記憶體中)並被程序 P 執行
然後持續發布將 /apps/EXE 替換為全新的執行檔。
假設 1: 我假設程序 P(以及具有引用舊執行檔的文件描述符的任何其他人)將繼續使用舊的、在記憶體中的 /apps/EXE 沒有問題,並且任何嘗試執行該路徑的新程序都會得到新的執行檔。
假設2: 我假設如果不是文件的所有頁面都映射到記憶體中,那麼一切都會好起來的,直到出現頁面錯誤需要文件中的頁面已被替換,並且可能會發生段錯誤?
問題 1: 如果你使用 vmtouch 之類的東西來鎖定文件的所有頁面,這會改變場景嗎?
問題 2: 如果 /apps/EXE 位於遠端 NFS 上,那會有什麼不同嗎?(我假設不是)
請更正或驗證我的 2 個假設並回答我的 2 個問題。
假設這是一個帶有某種 3.10.0-957.el7 核心的 CentOS 7.6 機器
更新:進一步考慮,我想知道這個場景是否與任何其他臟頁場景沒有什麼不同..
我想寫入新二進製文件的程序將執行讀取並獲取所有記憶體頁面,因為它全部被分頁,然後所有這些頁面都將被標記為臟。如果它們被鎖定,它們將只是在 ref 計數變為零後佔用核心記憶體的無用頁面。
我懷疑噹噹前執行的程序結束時,其他任何東西都會使用新的二進製文件。假設這一切都是正確的,我想只有當只有部分文件被分頁時才有趣。
然後持續發布將 /apps/EXE 替換為全新的執行檔。
這是重要的部分。
發布新文件的方式是創建一個新文件(例如
/apps/EXE.tmp.20190907080000
),寫入內容,設置權限和所有權,最後rename(2) 將其重命名為最終名稱/apps/EXE
,替換舊文件。結果是新文件有一個新的 inode 編號(這實際上意味著它是一個不同的文件。)
舊文件有自己的 inode 編號,即使文件名不再指向它(或者不再有文件名指向該 inode) ,它實際上仍然存在。
所以,這裡的關鍵是,當我們在 Linux 中談論“文件”時,我們最常真正談論的是“inode”,因為一旦打開了文件,inode 就是我們保留對文件的引用。
假設 1:我假設程序 P(以及具有引用舊執行檔的文件描述符的任何其他人)將繼續使用舊的,在記憶體中 /apps/EXE 沒有問題,並且任何嘗試執行該路徑的新程序都會得到新的執行檔。
正確的。
假設2:我假設如果不是文件的所有頁面都映射到記憶體中,那麼一切都會好起來的,直到出現頁面錯誤需要文件中的頁面已被替換,並且可能會發生段錯誤?
不正確。舊的 inode 仍然存在,因此使用舊二進製文件的程序中的頁面錯誤仍然能夠在磁碟上找到這些頁面。
通過查看執行舊二進製文件的程序的
/proc/${pid}/exe
符號連結(或等效的輸出),您可以看到一些效果,這將表明名稱不再存在,但 inode 仍然存在。lsof``/app/EXE (deleted)
您還可以看到二進製文件使用的磁碟空間只有在程序死亡後才會被釋放(假設它是唯一打開該 inode 的程序。)檢查
df
殺死程序之前和之後的輸出,您會看到它的大小下降您認為不再存在的舊二進製文件。順便說一句,這不僅適用於二進製文件,還適用於任何打開的文件。如果您在程序中打開一個文件並刪除該文件,該文件將保留在磁碟上,直到該程序關閉該文件(或死掉)。與硬連結如何保持計數器記錄有多少名稱指向磁碟中的 inode 類似,文件系統驅動程序(在 Linux 核心中)會記錄記憶體中存在多少對該 inode 的引用,並且只有在來自正在執行的系統的所有引用都被釋放後,才會從磁碟中釋放該 inode。
問題 1:如果您使用 vmtouch 之類的東西鎖定文件的所有頁面,是否會改變場景
這個問題基於錯誤的假設 2,即不鎖定頁面會導致段錯誤。它不會。
問題 2:如果 /apps/EXE 在遠端 NFS 上,會有什麼不同嗎?(我假設不是)
它應該以相同的方式工作,而且大部分時間都是這樣,但是 NFS 有一些“陷阱”。
有時您會看到刪除仍在 NFS 中打開的文件的工件(在該目錄中顯示為隱藏文件。)
您還可以通過某種方式將設備編號分配給 NFS 導出,以確保在 NFS 伺服器重新啟動時這些設備不會被“重新洗牌”。
但主要思想是一樣的。NFS 客戶端驅動程序仍然使用 inode,並且會在仍然引用 inode 時嘗試保留文件(在伺服器上)。