系統掛起期間的 USB 裝置永續性¶
- 作者:
Alan Stern <stern@rowland.harvard.edu>
- 日期:
2006 年 9 月 2 日(2008 年 2 月 25 日更新)
問題是什麼?¶
根據 USB 規範,當 USB 匯流排掛起時,匯流排必須繼續提供掛起電流(大約 1-5 mA)。 這是為了讓裝置可以保持其內部狀態,並且集線器可以檢測連線更改事件(插入或拔出裝置)。 技術術語是“電源會話”。
如果 USB 裝置的電源會話中斷,則系統需要表現得好像該裝置已拔出一樣。 這是一種保守的方法; 在沒有掛起電流的情況下,計算機無法知道實際發生了什麼。 也許同一裝置仍然連線,或者它被移除並且不同的裝置插入到埠中。 系統必須假設最壞的情況。
預設情況下,Linux 的行為符合規範。 如果 USB 主機控制器在系統掛起期間斷電,那麼當系統喚醒時,連線到該控制器的所有裝置都被視為好像它們已斷開連線。 這始終是安全的,並且是“官方正確”的做法。
對於許多型別的裝置,這種行為根本無關緊要。 如果核心想要相信您的 USB 鍵盤在系統休眠時已拔出,並在系統喚醒時插入了一個新鍵盤,誰在乎呢? 當您在上面打字時,它仍然以相同的方式工作。
不幸的是,_可能_會出現問題,特別是對於大容量儲存裝置。 效果與裝置在系統掛起時真的被拔出完全相同。 如果您在裝置上掛載了檔案系統,那麼您就倒黴了 -- 該檔案系統中的所有內容現在都無法訪問。 如果您的根檔案系統位於該裝置上,這尤其令人惱火,因為您的系統會立即崩潰。
斷電不是唯一需要擔心的機制。 任何中斷電源會話的操作都會產生相同的效果。 例如,即使在系統休眠時可能保持了掛起電流,但在許多系統上,在喚醒的初始階段,韌體(即 BIOS)會重置主機板的 USB 主機控制器。 結果:所有電源會話都被破壞,並且再次就像您拔掉了所有 USB 裝置一樣。 是的,這完全是 BIOS 的錯,但是除非您可以說服 BIOS 供應商修復問題(祝您好運!),否則這對 _您_ 沒有什麼好處。
在許多系統上,USB 主機控制器將在掛起到 RAM 後重置。 在幾乎所有系統上,休眠期間(也稱為 swsusp 或掛起到磁碟)沒有可用的掛起電流。 您可以在恢復後檢查核心日誌,以檢視是否發生了這些情況; 查詢顯示“root hub lost power or was reset”的行。
在實踐中,人們被迫在掛起之前解除安裝 USB 裝置上的任何檔案系統。 如果根檔案系統位於 USB 裝置上,則根本無法掛起系統。 (好吧,_可以_ 掛起 -- 但它會在喚醒後立即崩潰,這也好不到哪裡去。)
解決方案是什麼?¶
核心包含一個名為 USB-persist 的功能。 它試圖透過允許核心 USB 裝置資料結構在電源會話中斷期間保持存在來解決這些問題。
它的工作方式如下。 如果核心看到 USB 主機控制器在恢復期間未處於預期狀態(即,如果控制器已重置或以其他方式斷電),那麼它會對該控制器下方的每個設定了“persist”屬性的 USB 裝置應用永續性檢查。 它不會嘗試恢復裝置; 一旦電源會話結束,這就不起作用了。 相反,它會發出 USB 埠重置,然後重新列舉裝置。 (這與每次重置 USB 裝置時發生的情況完全相同。)如果重新列舉顯示現在連線到該埠的裝置與之前的裝置具有相同的描述符,包括供應商和產品 ID,那麼核心將繼續使用相同的裝置結構。 實際上,核心將裝置視為僅僅被重置而不是拔出。
如果主機控制器處於預期狀態,但 USB 裝置已拔出然後重新插入,或者 USB 裝置無法執行正常恢復,則會發生同樣的情況。
如果沒有裝置現在連線到埠,或者描述符與核心記住的不同,那麼處理方式將是您所期望的。 核心會銷燬舊的裝置結構,並表現得好像舊裝置已被拔出,新裝置已插入。
最終結果是 USB 裝置仍然可用和可使用。 檔案系統掛載和記憶體對映不受影響,世界現在變得美好而快樂。
請注意,“USB-persist”功能僅適用於已啟用的裝置。 您可以透過執行以下操作來啟用該功能(以 root 身份)
echo 1 >/sys/bus/usb/devices/.../power/persist
其中“...”應填充裝置的 ID。 透過寫入 0 而不是 1 來停用該功能。 對於集線器,該功能會自動且永久啟用,並且 power/persist 檔案甚至不存在,因此您只需擔心為真正重要的裝置設定它。
這是最好的解決方案嗎?¶
可能不是。 可以說,跨裝置斷開連線跟蹤已掛載的檔案系統和記憶體對映應該由集中的邏輯卷管理器處理。 這樣的解決方案將允許您插入 USB 快閃記憶體裝置,建立與其關聯的持久卷,拔出快閃記憶體裝置,稍後重新插入,並且仍然具有與該裝置關聯的相同持久卷。 因此,它將比 USB-persist 更具深遠意義。
另一方面,編寫持久卷管理器將是一項繁重的工作,並且使用它需要使用者的大量投入。 這個解決方案更快,更容易 -- 而且它現在已經存在,這是它的一大優勢!
此外,USB-persist 功能適用於 _所有_ USB 裝置,而不僅僅是大容量儲存裝置。 事實證明,它對於其他裝置型別(例如網路介面)也同樣有用。
警告:USB-persist 可能很危險!!¶
在恢復中斷的電源會話時,核心會盡最大努力確保 USB 裝置沒有更改; 也就是說,與以前一樣,同一個裝置仍然插入到埠中。 但是,檢查不能保證 100% 準確。
如果您將一個 USB 裝置替換為另一個相同型別的裝置(相同的製造商、相同的 ID 等),則核心很有可能不會檢測到該更改。 序列號字串和其他描述符與核心的儲存值進行比較,但這可能沒有幫助,因為製造商經常完全在其裝置中省略序列號。
此外,完全有可能在更改其媒體的同時保持 USB 裝置完全相同。 如果您在系統休眠時更換了 USB 讀卡器中的快閃記憶體卡,則核心將無法知道您做了什麼。 核心將假設沒有任何事情發生,並將繼續使用舊卡的分割槽表、inode 和記憶體對映。
如果核心以這種方式被愚弄,幾乎肯定會導致資料損壞並導致您的系統崩潰。 您只能責怪自己。
對於設定了 avoid_reset_quirk 屬性的那些裝置,持久化可能會失敗,因為它們可能會在重置後變形。
您已被警告! 使用風險自負!
話雖如此,大多數時候應該沒有任何問題。 USB-persist 功能可能非常有用。 充分利用它。