從核心終止使用者態程式的IO訪問
本文調查這個問題的解決方案:如果我暴露一個裝置的IO空間給使用者態的程式,這個裝置出了異常,我如何可以終止使用者態的程式,不讓它繼續訪問這個裝置。
我發現裝置異常,無論是裝置自己報錯,還是通過RAS系統報錯,反映出來肯定是中斷。所以我肯定是從中斷開始做我的處理,這是基本假設。
發生異常後需要立即通知使用者程式終止對裝置的訪問,我第一個考慮是用是kill_pid(pid, SIGXXX, 1),發一個訊號給使用者程序。但這是非同步的,要等到使用者程式被中斷了,或者從系統呼叫中返回才會起作用。當我收到中斷的時候,使用者程序大可以正在工作在另一個核的使用者態上,不會被打斷。這時如果我回收裝置的相關資源,肯定不妥。
第二種方法是把mmap的IO空間的頁表給它回收了,但這個更危險,因為這要主動拿到這個程序的vma,然後在另一個CPU的上下文中操作它。這從鎖的角度也很不安全,估計要改變不少核心的鎖設計上的假設,不到萬不得已,我們不考慮走這條路。
這些方法的問題是沒法立即打斷那個執行的程序,而很明顯,要理解打斷某個被執行的程序,唯一的手段是給它所在CPU發一箇中斷,比如發一個IPI。但收到一箇中斷,然後發起一個IPI,這個事情本身就是非同步的。既然不能通過同步方式立即終止一個程序,快一點慢一點又有什麼所謂?反正在(裝置)異常發生的時候,使用者程序怎麼都得走幾步的。
所以,這種情形需要做的設計是這樣的:
首先硬體介面必須能保證,無論硬體發生什麼異常,使用者程序做任何硬體動作,最多沒反應,但不能造成裝置本身狀態的異常。
其次,在裝置異常後,通過訊號通知程序退出,但在程序沒有被殺死前,裝置必須處於一種“不可操作狀態”直到所有使用了裝置的程序關閉關聯為止。
最後,在所有程序關閉了關聯後,復位裝置。
其中,第二步需要程序的配合,如果某個程序惡意在收到中斷後,既不退出,也不關閉和裝置的關聯(比如不關閉對應的檔案控制代碼),我們有兩個選擇:第一,在裝置驅動上設定一種配置屬性,如果這個屬性被配置了,直接發SIGKILL,這樣程序一定會死。就沒有這個問題了。第二,等管理員主動去殺掉它。
使用者程序的推薦演算法如下:
atomic_flag = 0 def sighandler(): if it_is_device_reset: atomic_flag = 1 def device_loop(): fd = open(device) mem = mmap(fd) while atomic_flag: device_io(mem) close(fd)
這個方案應該比較保險了吧?