日誌(journaling)
把一個檔案更名或讓它變大,很少是對磁碟的單一一次寫入——它牽動 inode、一個目錄項、以及配置位元圖,好幾個各自獨立的區塊。如果在那三個寫入落下兩個之後斷電,檔案系統便陷在一個做了一半的狀態:一個被標為已用卻不屬於任何檔案的區塊,或一個指向「自稱沒有連結」之 inode 的目錄項。為了避免每次當機後花上幾分鐘搜尋這類損壞,現代檔案系統先把它即將要做的事寫下來、然後才做。那種「先寫下來」的紀律就是日誌。
一個日誌檔案系統保有一塊專用的磁碟區域,即日誌(一個寫前日誌)。在把一個多區塊的變更套用到主檔案系統之前,它把該變更打包成一個交易,並把整個交易寫進日誌,以一筆提交紀錄作結。只有在提交紀錄安全落在磁碟之後,它才開始把那些變更寫到它們真正的家位置(這第二步叫做檢查點化,checkpointing)。若在更新途中當機,下次掛載時檔案系統會重播日誌:任何帶完整提交紀錄的交易都被重新套用到主區域,任何不完整的交易(沒有提交紀錄)則被直接丟棄。無論哪種,檔案系統都快速回到一致狀態——幾秒的日誌重播,而非完整掃描。
為何重要:日誌把當機復原從緩慢的、整顆磁碟的 fsck 變成快速的日誌重播,這正是為何大型檔案系統在不乾淨關機後幾乎能即時掛載。關鍵的誠實之點:大多數檔案系統預設只記錄後設資料,而非你檔案的資料。那保證檔案系統結構在當機後保持一致,但它「不」保證你最後寫的那些位元組真的抵達了磁碟——為此你仍需要 fsync()。日誌保護的是檔案系統,未必是你最近的資料。
1. 把交易 {inode、目錄項、位元圖} 寫進日誌 2. 把 COMMIT 紀錄寫進日誌 <- 交易此刻持久化 3. 檢查點化:把同樣的區塊寫到它們真正的位置 第 2 步前當機 -> 重新掛載時,丟棄不完整的交易(無損壞) 第 2 步後當機 -> 重新掛載時,重播它(變更重新套用)
先把意圖寫進日誌並提交它;當機要麼丟棄不完整的交易、要麼重播一個已提交的交易。
日誌保證的是當機後檔案系統一致,而「不是」你最新的寫入存活下來。預設只有後設資料被記錄,所以沒有 fsync() 的話,即使檔案系統完好無損,你片刻前寫的資料也可能就這麼不見了。