Files

在沒有 fsync() 的情況下替換現有文件是否“損壞”?

  • July 23, 2016

在 Linux 的mount(2)手冊頁中,我注意到以下摘錄:

許多損壞的應用程序在通過模式替換現有文件時不使用 fsync(),例如

fd = open("foo.new")/write(fd,...)/close(fd)/ rename("foo.new", "foo")

或者更糟

fd = open("foo", O_TRUNC)/write(fd,...)/close(fd).

如果啟用了 auto_da_alloc,ext4 將檢測 replace-via-rename 和 replace-via-truncate 模式並強制分配任何延遲的分配塊,以便在下一次日誌送出時,在預設的 data=ordered 模式下,在送出 rename() 操作之前,新文件被強制寫入磁碟。這提供了與 ext3 大致相同級別的保證,並避免了在延遲分配塊被強製到磁碟之前系統崩潰時可能發生的“零長度”問題。

這段程式碼在什麼意義上被“破壞”了?他們是說這段程式碼是非法的還是不符合標準的(POSIX 等)?

fsync()對於那些擔心系統崩潰會發生什麼的人來說,這顯然是一個好主意。但是假設一個系統不會崩潰,那麼範常式式碼的兩個版本,沒有fsync(),都做正確的事情嗎?

rename預計是原子的:它要麼完全完成,要麼根本不完成。重命名 A 來代替 B 應該讓您保持 A 和 B 完好無損(它根本沒有發生);或僅在名稱 B 下包含 A 的內容(完全完成)。

只要係統不崩潰,無論fsync(等)呼叫如何,都會發生這種情況。

但是,如果系統確實崩潰,則可能會發現重命名本身會命中磁碟(並因此完成)。請記住,名稱 != 文件。文件/inode 可以有多個名稱。重命名正在更改名稱,而不是基礎文件/數據。

所以你可以有你的程序寫A的狀態,重命名替換B,然後電源就掉了。原來文件系統將重命名寫入磁碟,而不是 A 中的實際數據。沒有fsync. 因此,您以零長度 B 或零填充 B 結束。

應用程序執行 write-temp-file + rename 而不是僅僅覆蓋文件的原因是因為它需要崩潰安全。如果他的重要文件寫了一半的臨時副本被留在未經修改的好副本旁邊,使用者不會太生氣。但是,如果沒有留下好的副本,使用者將不會高興。

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