![原子刪除目錄](https://rvso.com/image/36018/%E5%8E%9F%E5%AD%90%E5%88%AA%E9%99%A4%E7%9B%AE%E9%8C%84.png)
因為rename(2)
被 調用mv
,所以可以安全地假設以下內容是原子的嗎?
$ mv /home/me/someDir /tmp/toBeDeleted
$ rm -rf /tmp/toBeDeleted
答案1
這mv
命令稱為rename
系統調用,保證是原子的。但是,有兩個例外:
- 如果來源和目標位於不同的檔案系統上(這對
/home
vs.來說是相對常見的)/tmp
,則rename
失敗,mv
然後透過將來源樹複製到目標,然後刪除來源樹來運作。這顯然不是原子的。 - 有些檔案系統不是
rename
原子的,例如 NFS 的某些實作。在任何「正常」本機檔案系統上,rename
都是原子的。
答案2
如果目錄位於作為單一檔案系統安裝的相同硬體分割區上,那麼移動某些東西實際上只是將其重命名為不同的路徑。但是,如果不是,則可能需要讀入並複製其中的每個文件,因此移動的任何部分都不是原子的。正如 Gilles 指出的,POSIX 規定離散檔案系統就是這種情況。
strace
除此之外,使用確認進行快速檢查mv
確實使用了rename()
系統呼叫(不要與rename
命令列實用程式混淆)。從用戶空間的角度來看,這將使mv
目錄成為原子的。如果出現以下情況,系統rename()
呼叫將拋出 EBUSY 錯誤:
oldpath 或 newpath 是某個進程正在使用的目錄(可能作為當前工作目錄,或作為根目錄,或因為它已開啟以供讀取)或正在被系統使用(例如作為掛載點),而係統認為這是一個錯誤。 (請注意,在這種情況下不需要返回 EBUSY — 無論如何進行重命名都沒有問題 — 但如果系統無法以其他方式處理此類情況,則允許返回 EBUSY。)
從man 2 rename
。這裡與「原子性」的連結是,你不能中斷在目錄中工作的另一個進程,另一個進程也不能中斷它——如果你擊敗它,它最終會出現無效路徑/未找到類型錯誤追逐。