2011-11-04 91 views
1

我正在玩kretprobes,我正面臨一個問題。爲了響應來自用戶進程的特定事件(例如特定系統調用),我希望從該進程地址空間讀取數據。由於在kretprobe入口處理程序中我們處於中斷上下文中,因此我無法從這裏獲取用戶頁面(它可能會睡眠),因此我推遲了system_rq(schedule_work())中的工作。如何在Linux內核中斷之後強制重新調用?

爲了確保用戶進程在我的延期工作完成之前不會改變其內存,我將它放在TASK_INTERRUPTIBLE中並使用set_tsk_need_resched()。我希望在這個時候,這個標誌會被測試,調度器會選擇另一個任務。看起來它不能像那樣工作,並且在中斷之後用戶任務回到CPU上,在我有機會查看它之前改變它的內存。

是否還有其他事情要做,以確保任務切換後直接發生?

在此先感謝

回答

0

那麼今天我發現它確實是這樣做的好方法。我在執行進程時遇到的問題是因爲我沒有處於中斷環境中:kprobe已經過優化(即在x86上是一個jmp指令而不是int3),這導致我的代碼在內核域中的用戶上下文中執行。如果kprobe_optimized()函數正常工作,這應該已經被順利處理,在這種情況下,我們可以在將任務設置爲INTERRUPTIBLE而不是ireturning之後直接調用schedule(),並讓中斷處理程序的序言檢查標誌TIF_NEED_RESCHED。實際上,kprobe_optimized()在任何情況下都會返回false,如果它是kretprobe,這是由於內部處理kretprobe的方式引起的:它使用kprobes的聚合器,該聚合器正確設置哪個標記用於聚合器,但不適用於聚合器內的kprobes名單。我通過導出函數get_kprobe()並使用它來檢索kprobe聚合器的地址來解決這個問題,從中我終於能夠正確檢查它是否被優化。

我認爲在內核中解決此問題的最佳方法(性能明智)是將聚合器中的優化標誌複製到它列出的每個kprobe。這樣kprobe_optimized()將返回正確的值。另一種方法是在kprobe_optimized()中添加更多代碼來檢查此kprobe是否是聚合列表的一部分,並檢查聚合器而不是實際的kprobe。

無論如何,這很有趣!

1

您的方法存在根本上的缺陷。中斷本質上是異步的;即使您關閉中斷返回與延遲工作項目之間的競賽,如果中斷延遲,也可以獲得相同的競爭。試想一下:

  • USER:設置X = 1
  • 中斷:計劃工作
  • USER:設置X = 2
  • 工作隊列:讀X

VS

  • USER:Set X = 1
  • INTERRUPT: (由硬件怪事延遲...)
  • USER:設置X = 2
  • 中斷:調度工作
  • 工作隊列:讀X

同樣的結果,不是嗎?所以不要嘗試。

更重要的是,即使在內核代碼中也可能發生中斷。如果應用程序處於系統調用的中間,並且不會阻止並修改內存,則在它允許您阻止之前,該應用程序必須完成該調用。強迫它陷入可中斷狀態可能會造成死鎖;內核代碼可能會持有自旋鎖或其他不安全的狀態來安排。

注意,這也正是爲什麼中斷處理程序不能睡覺 - 他們會迫使他們的通話上下文來睡覺的時候它可能沒有準備這樣做。這正是你想要做的。

總之,你想的是無法解決的比賽;從根本上您的工作隊列項只是增加延遲到中斷處理程序,它已經有延遲的有些捉摸不透量。因此,用戶進程總是會有一個窗口,它可能會混淆它的內存。此外,用戶進程可能不是在它是安全的被中斷的狀態。

所以不要擔心它 - 只要確保用戶進程不能破壞整個系統的方式,並確保它不會破壞本身直到用戶進程即告訴用戶進程的開發人員,如果他希望硬件正常工作,不要弄亂這個內存)。

+0

中斷髮生*因爲*我在那裏放置了一個kprobe,所以我知道用戶進程正在運行並被我的探測器中斷,並且在調用中斷處理程序時不運行。從那裏開始,應該很容易讓它進入睡眠狀態,就像頁面錯誤處理程序所做的那樣,以便我可以稍後再運行並將其放回RUNNING。假設你mmap一個文件並嘗試讀取你的AS,但是當你嘗試讀取 - >頁錯誤時 - >數據不在這裏 - >內核會讓你進入INTERRUPTIBLE,直到數據從磁盤到達:這正是我試圖在這裏實現。儘管感謝您的回答 –