contributed by < RoyWFHuang
>
linux_class
kernel
開發環境為:
OS: ubuntu 20.04
kernel ver: 5.4.0-77-generic
CPU arch: x86_64
使用 multipass 開發
這題遇到的最大的問題是, 下面這段程式碼是要選擇
or
程式能正常運作, 必須要選則 wake_up_locked_poll 才能做動.
先看這兩個差異性, 最後都是呼叫到 __wake_up_common
wake_up_locked_poll -> __wake_up_locked_key((x), TASK_NORMAL, poll_to_key(m)) -> __wake_up_common(wq_head, mode, 1, 0, key, NULL)
wake_up_poll -> __wake_up(x, TASK_NORMAL, 1, poll_to_key(m)) -> __wake_up_common_lock(wq_head, mode, nr_exclusive, 0, key);-> __wake_up_common(wq_head, mode, 1, 0, key, NULL)
很明顯的看出, 有lock 的差異狀況, 而在原本程式中, spin_lock_irq(&vpoll_data->wqh.lock); 已經做了一次的 lock 了, 此時在 這邊又在呼叫一次 lock, 勢必造成 re-lock 的問題, 所以將 lock 移除後, 在將之換成 wake_up_poll 進行測試
很明顯的是會運作的
vpoll_ioctl 在 user space 可以同時呼叫 ioctl
task 1 | task 2 |
---|---|
ioctl(efd, VPOLL_IO_ADDEVENTS, EPOLLIN); | ioctl(efd, VPOLL_IO_ADDEVENTS, EPOLLPRI); |
vpoll_data->events |= events; | |
vpoll_data->events |= events; | |
vpoll_data->events == ??? | vpoll_data->events == ??? |
會造成 events 資料的錯誤.
只有 unlocked_ioctl 跟 compat_ioctl, 於是找到了這篇What is the difference between ioctl(), unlocked_ioctl() and compat_ioctl()?, 從下面的回答中, 找到The new way of ioctl()
恩, 原來又是BKL阿.
修改 vpoll_poll, 在將 event 取出後, 將 event 資料設定回去
輸出結果
出現下面結果
0x17 很明顯就是 0x01 & 0x02 & 0x04 & 0x10的結果, 很明顯看出, 雖然通知 wait queue起來工作, 但是實際上仍在執行 child process, 造成 event 的堆疊
處理方法使用 ring buffer來將每一次的 event 分別紀錄
修改結構
修改 vpoll_iotl, 此處也將 lock 範圍縮小, 另外 queue full 的判斷, 則是採用直接讀取資料方式, 因為event 會在 reader 讀取後被清除, 所以直接判斷此處是否有 event 即可.
修改 vpoll_poll, 判斷 queue empty 的方式跟 full 類似, 判斷是否有 event 寫入
後記:
本來是想從 wake_up_poll 中的 parameter "events" 下手, 看是否能在 poll_wait 中, 直接將之取出, 但似乎這個 key 只是當作是一個 event 通知而已, 沒辦法隨著 wait queue 一併傳遞過去.