Filesystems

文件創建是否完全有序?

  • May 31, 2019

在 Linux 上,openat系統呼叫可用於創建文件並測試它們的存在。就 C/C++ 記憶體模型而言,創建文件並驗證其存在會創建同步關係。我需要知道的是這些同步是否都彼此順序一致。(我當然希望如此,但我實際上並沒有在任何地方看到過這個記錄。)

例如,給定程序 p1 和 p2,以及路徑 A 和 B:

如果 p1 這樣做:創建(A),然後創建(B)

p2 這樣做:嘗試打開(B),然後嘗試打開(A)

並且沒有其他程序干擾A或B,p2是否有可能成功打開B但找不到A?

如果有所不同,我們可以假設所有操作都在一個文件系統中。

僅適用於同一目錄中的文件。

有6條規則

  1. 讀取權限。鎖定規則:呼叫者鎖定我們正在訪問的目錄。鎖是共享的。
  2. 對象創建。加鎖規則:同上,但鎖取獨占。
  3. 物體去除。鎖定規則:呼叫者鎖定父對象,找到受害者,鎖定受害者並呼叫方法。鎖是排他的。
  4. rename()不是跨目錄。鎖定規則:呼叫者鎖定父對象並找到源和目標。在交換的情況下(使用 RENAME_EXCHANGEin flags 參數)鎖定兩者。無論如何,如果目標已經存在,就鎖定它。如果源是非目錄,則鎖定它。如果我們需要同時鎖定兩者,請按 inode 指針順序鎖定它們。然後呼叫方法。所有鎖都是獨占的。注意:我們可能會鎖定共享的源(和目標)共享。
  5. 連結創建。鎖定規則:

* 鎖定父級 * 檢查源不是目錄 * 鎖源 * 呼叫方法。所有鎖都是獨占的。 6. 跨目錄重命名。整個團隊中最棘手的。鎖定規則:

* 鎖定文件系統 * 以“祖先優先”的順序鎖定父母。 * 找到源和目標。 * 如果舊父母等於或是目標的後代失敗 -ENOTEMPTY * 如果新父級等於或是源的後代失敗 -ELOOP * 如果是交換,則鎖定源和目標。 * 如果目標存在,將其鎖定。如果源是非目錄,則鎖定它。如果我們需要同時鎖定兩者,請按 inode 指針順序進行。 * 呼叫方法。所有->i_rwsem都是排他的。同樣,我們可能會通過鎖定共享的源(和交換情況下的目標)而僥倖逃脫。

上面的規則顯然保證了所有要被方法讀取、修改或刪除的目錄都將被呼叫者鎖定。

鎖定強制執行線性化,因此對單個目錄的操作是完全有序的。但是,讀取訪問 (1)、對象創建 (2) 和對象刪除 (3) 不會使用比目錄鎖更廣泛的鎖,因此無法保證不同目錄中目錄操作的順序;不同的觀察者可能會看到目錄的線性歷史以不同的方式交錯。

對於所有底層磁碟和多核 CPU 優化,不一定可以確定兩個程序之間操作序列的嚴格順序。這就是為什麼如果存在時間相關行為的可能性時使用信號量的原因。

引用自:https://unix.stackexchange.com/questions/522039