Linux Barrier IO

IO順序是一個比較綜合的問題,它涉及的層次比較多,從VFS page cache到I/O調度算法,從IO子系統到存儲外設。而Linux Barrier IO就是其中重要的一部分。可能很多人認爲,在做了文件寫操作後,調用fsync就能保證數據可靠地寫入磁盤。大多數情況下,確實如此。


但是,由於磁盤設備自帶緩存的存在,fsync這些同步操作,並不能保證存儲設備把數據寫入非易失性介質。如果此時存儲設備發生掉電或者硬件錯誤,此時存儲緩存中的數據將會丟失。


另外,fsync只能保證bio提交後,request_queue能馬上unplug。但是這並不能保證IO的順序。比如,在電梯算法中,一般的文件數據bio是以sorted的順序插入調度隊列。也就是說,該request並不能保證被插入到設備請求隊列的隊尾。比如在AS調度算法中,如果該request的sector號離當前磁頭較遠,AS可能會把後來的request先dispatch到設備的請求隊列。這無疑會破壞IO的處理順序。


這對於像日誌文件系統中的日誌這樣的數據,其後果可能是非常嚴重的。因爲日誌文件系統中,數據的寫入和日誌的寫入存在先後順序。如果順序發生錯亂,則可能破壞文件系統。因此必須要有一種方式,來指示寫入的數據是否真的按照既定的順序寫入到外部存儲的非易失性介質,比便文件系統根據寫入情況來進行下一步的操作。


要保證這個順序,必須要加入處理順序的邏輯。這個邏輯需要和IO調度器協調配合,不僅要處理插入,排出的順序,還要處理requeue等的順序。從邏輯上講,這部分功能應該不屬於sync的範疇。所以才需要Barrier IO。這個還是在簡單block device的情況下,如果設備做了軟raid,有多路徑,情況更加複雜。因此有必要用專門的邏輯來實現這個功能。


Barrier IO的目的是使其之前的IO在其之前寫入存儲介質,之後的IO需要等到其寫入完成後才能得到執行。爲了實現這個要求,最多需要執行2次flush(刷新)操作。


注意,這裏所說的flush,指的是刷新存儲設備的緩存。但並不是所有存儲設備都支持flush操作,所以不是所有設備都支持Barrier IO。支持根據這個要求,需要在初始化磁盤設備的請求隊列時,顯式的表明該設備支持Barrier IO的類型並實現prepare flush 方法,參見“Linux Barrier IO”。


第一次flush是把Barrier IO之前的所有數據刷新,當刷新成功,也就是這些數據被存儲設備告知確實寫入其介質後,提交Barrier IO所在的請求。然後執行第二次刷新,這次刷新的是Barrier IO所攜帶的數據。當然,如果Barrier IO沒有攜帶任何數據,則第二次刷新可以省略。此外,如果存儲設備支持FUA,則可以在提交Barrier IO所攜帶的數據時,使用FUA命令。這樣可以直接知道Barrier IO所攜帶的數據是否寫入成功,從而省略掉第二次刷新。


通過對Barrier IO的處理過程,我們可以看到,其中最核心的是兩次刷新操作和中間的Barrier IO。爲了表示這兩次刷新操作以及該Barrier IO,在Linux Barrier IO的實現中,引入了3個輔助request: pre_flush_rq, bar_rq, post_flush_rq. 它們包含在磁盤設備的request_queue中。每當通用塊層接收到上面發下來的Barrier IO請求,就會把該請求拷貝到bar_rq,並把這3個請求依次加入請求隊列,形成flush->barrier->flush請求序列。這樣,在處理請求時,便能實現Barrier IO所要求的功能。
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章