iT邦幫忙

2026 iThome 鐵人賽

DAY 16
0
Software Development

從零打造邊緣運算閘道器:Raspberry Pi 與 Linux 底層軟硬整合實戰系列 第 16

Day 16 - 雙腦分裂 (Split-Brain) 危機:當 PC 與 Pi 同時寫入磁碟的毀滅性後果

  • 分享至 

  • xImage
  •  

[!NOTE]
本系列文章已進行全域去敏與匿名化處理,專案代號統一為 DataGateway,內網 IP 統一為 10.0.0.x

回顧前幾天的進度,我們利用 usb_disk.img 作為共用空間,一端透過 USB ConfigFS 餵給 Windows PC,另一端透過 losetup 掛載在 Raspberry Pi 上。

從系統架構圖來看,這似乎非常完美。硬體端的資料送進 DataGateway,寫入虛擬磁碟後,插著 USB 的那台 Windows PC 就能立刻把 .csv 開起來看。

但如果你真的這麼做,你會發現一場災難。檔案會憑空消失、磁區會變成亂碼、甚至 Windows 會跳出「磁碟結構毀損且無法讀取」的警告。

歡迎來到分散式與儲存系統中最經典的惡夢:「雙腦分裂 (Split-Brain)」。

問題情境:什麼是雙腦分裂?

FAT32 是一種非常古老、簡單且假設單一使用者的檔案系統。它依賴檔案分配表 (File Allocation Table) 來記錄哪個檔案放在硬碟的哪個磁區。

當你在 Linux (Raspberry Pi) 或 Windows 系統中掛載一個 FAT32 磁碟時,作業系統會做一件事:快取 (Cache) 檔案分配表
作業系統為了效能,會把檔案目錄樹與可用空間記錄讀進 RAM 裡,然後盡可能都在記憶體中操作,等到必要時(或者使用者點擊「安全移除硬體」時)才寫回實體硬碟。

現在我們的情境是:

  1. Windows (第一顆大腦) 把 usb_disk.img 掛載起來,讀取了它認為的 FAT 表。
  2. Linux (第二顆大腦) 也用 losetupusb_disk.img 掛載起來,也讀取了另一份 FAT 表。

毀滅場景推演:

  • 護理師在 Windows 上開啟隨身碟,看到裡面是空的。這時 Windows 在記憶體裡記住:「目前可用空間是 256MB,沒有任何檔案」。
  • 同一時間,DataGateway 的感測器收到了新資料,Linux 決定寫入一份 patient_123.csv。Linux 修改了它自己 RAM 裡的 FAT 表,把資料寫進硬碟的某個磁區 A。
  • 接著,護理師在 Windows 裡看見隨身碟是空的,決定新增一個文字檔 note.txt。Windows 依照它自己的快取,認為磁區 A 是空的,於是直接把 note.txt 寫進磁區 A。

轟!
Windows 直接覆蓋了 Linux 剛剛寫入的二進位資料。
而且因為 Linux 完全不知道 Windows 修改了硬碟,Linux 接下來若要讀取 patient_123.csv,讀出來的就會是 Windows 寫進去的 note.txt 亂碼,最終導致 FAT 表完全崩潰。

[!CAUTION]
絕對禁止多個作業系統同時掛載同一個 Block Device (除非使用特製的 Cluster File System,如 OCFS2 或 GFS2,但 Windows 都不支援)。這會導致不可逆的資料毀損!

雙腦危機的核心衝突

為什麼一般的隨身碟不會發生這種事?
因為你把實體隨身碟插到電腦 A,再拔下來插到電腦 B。這是一個互斥 (Mutually Exclusive) 的操作。
當隨身碟在空中時,不會有任何作業系統對它進行寫入,因此每次掛載,OS 讀取到的 FAT 表永遠是最新的。

但在我們的 DataGateway 架構中,這顆 usb_disk.img 是虛擬的,它可以無時無刻被兩個作業系統透過不同路徑存取,導致我們失去了硬體層面上的互斥鎖 (Hardware Mutex)。

解決方案的探索與架構演進

為了解決這個致命的架構缺陷,我們在開發初期嘗試了幾條路:

❌ 嘗試一:Sync 大法好?

有工程師提議,只要 Linux 在寫入後立刻執行 sync 指令強制作業系統將緩存刷入硬碟,Windows 端不就能看到新資料了嗎?
失敗。 雖然 Linux 把資料寫下去了,但 Windows 不會知道。Windows 依然相信它在插入隨身碟那一刻快取在 RAM 裡的 FAT 結構。除非你把 USB 拔掉重插,否則 Windows 永遠看不到新檔案。

❌ 嘗試二:讓 USB 唯讀就好?

既然同時寫入會毀滅世界,那我們用 ConfigFS 把 USB 設為唯讀 (echo 1 > lun.0/ro),只有 Linux 能寫,Windows 只能讀。這樣總行了吧?
失敗。 就算 Windows 是唯讀,它依然會有快取問題。Linux 寫入的新資料,Windows 不拔掉重插一樣看不見。更慘的是,某些醫療軟體在讀取資料庫時,會習慣在隨身碟裡產生 .tmp.lock 鎖定檔,如果 USB 是唯讀的,這些軟體會直接報錯崩潰。

✅ 最終架構:軟體互斥鎖 (Software Mutex)

我們必須用軟體機制,還原「隨身碟被拔下」的這個物理動作。

核心概念只有一句話:
同一時間,usb_disk.img 只能被其中一方掛載。

  1. 當 USB 纜線未連接 PC 時:Linux 獨佔掛載這個虛擬磁碟,不斷將感測器資料寫入。
  2. 當偵測到 USB 纜線已連接 PC,且有電力供應時:Linux 必須立刻釋放 (umount) 這顆虛擬磁碟,然後才啟用 USB Gadget 讓 Windows 掛載。
  3. 當 USB 纜線拔除時:關閉 USB Gadget,Linux 重新將磁碟掛載回來,繼續寫入後續的感測器資料。

這就是我們實作的「智慧卸載」機制。
這聽起來很直觀,但在沒有實體按鈕的無頭設備 (Headless) 上,我們怎麼知道 USB 線被插上了?而且,如果在插上的那一瞬間,Linux 剛好正在寫入資料,直接卸載會不會導致資料遺失?

明天,我們將實作一套精密的 USB 狀態監聽機制,在千分之一秒內完成磁碟控制權的奪取與移交!


上一篇
Day 15 - losetup 的藝術:如何優雅地掛載與回收 Loop Device?
下一篇
Day 17 - 奪回控制權:實作 USB 狀態監聽,動態卸載本機 FAT32 (Lazy Unmount)
系列文
從零打造邊緣運算閘道器:Raspberry Pi 與 Linux 底層軟硬整合實戰26
圖片
  熱門推薦
圖片
{{ item.channelVendor }} | {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言