contributed by < csotaku0926
>
先前於 Windows 系統的電腦額外安裝 Ubuntu 22.04.01,以雙核心系統實作本次作業
閱讀〈Linux 核心模組運作原理〉並對照 Linux 核心原始程式碼 (v6.1+),解釋 insmod 後,Linux 核心模組的符號 (symbol) 如何被 Linux 核心找到 (使用 List API)、MODULE_LICENSE 巨集指定的授權條款又對核心有什麼影響 (GPL 與否對於可用的符號列表有關),以及藉由 strace 追蹤 Linux 核心的掛載,涉及哪些些系統呼叫和子系統?
解釋 insmod
模組掛載機制 (參閱 Linux v6.1+)
在教材提及的範例程式中,當我們撰寫以下核心程式碼後,編譯取得對應 kernel object,之後執行 insmod
命令,作為 module_init()
參數的 hello_init()
得以執行於核心
使用以下命令編譯:
根據我的核心版本,查看 v6.5 /include/linux/module.h
於第 88 行發現尚未定義 module 的:
還有定義 module 的:
該怎麼判斷那一個才是我使用的定義?
回到 bootlin 網站追本溯源,發現 MODULE
這個定義符也在 /include/linux/init.h
出現多次,如第十行:
只靠觀察核心程式碼,我還是不能肯定要用哪個版本,先暫時依照教材指示觀察 MODULE
未定義的狀況
可以發現 module_init(initfn)
被替換為__initcall(initfn)
,又被替換為 device_initcall(fn)
,最後是 __define_initcall(fn, 6)
…又一直延伸下去
當程式碼規模越來越大時,明明是同個函式卻會出現不同的別名,這是閱讀核心程式碼的一個難點
事實上,經 教材 以及 論壇 題點,可以透過以下命令觀察經過前置處理 (preprocess) 的程式,就不用以靜態方式一層層回推巨集了 (這樣顯得很沒效率)
搭配第 7 週教材提到的 UML 和 QEMU 來追蹤。
奇怪的是,輸出結果和教材的很不一樣
這裡出現多次 GNU extension __attribute__
(暫時想不到為何有如此大的差異:是gcc版本不對?或是 -I 輸入 include path 有錯?)
很好,表示你找到可貢獻的地方。
hello.c
加入 MODULE_AUTHOR
以及 MODULE_LICENSE
可以在經過前處理的檔案中發現:
於 include/linux/module.h
中發現
最後,發現了與教材不一樣的地方,大概是版本更新太多了 (v6.5)
以往的定義前面還有個 #ifdef MODULE
,好像更改了
總之,藉由 GNU extension __attribute__
可以告訴編譯器
__attribute__((__section__(".modinfo")))
: 這段訊息要放在 .modinfo
__attribute__((__aligned__(1)))
: 確保這段訊息對齊 1-byte boundary
閱讀《The Linux Kernel Module Programming Guide》(LKMPG) 並解釋 simrupt 程式碼裡頭的 mutex lock 的使用方式,並探討能否改寫為 lock-free;
Mutex lock 可以想像成類似 token ring network 中的 token,在多執行緒 (multi-threaded) 系統中,只有拿到 mutex lock 的執行緒可以行動
simrupt 對於 mutex lock 的應用在 producer consumer problem
當核心線程呼叫 simrupt_work_func()
,於每次消費者讀取 workqueue 上的資料時,以 mutex_lock
將對應的 consumer_lock
鎖上,生產者生產資料同理
根據文件說明,workqueue 的使用是為了非同步流程 (asynchronous process execution) 的執行。這時,工作項 (work item) 將會被放置於 wq,紀錄了需要被執行的內容。每個線程 (thread) 視為 worker,負責執行佇列內的工作項
文件也提到過往的 MT wq,每個 CPU 都有一個 worker thread,隨著 CPU 數量增長,原先 32-bit PID space 不夠用了,而且在並行等級及資源限制的取捨下,不論是 ST 或是 MT 都有不完善的地方
於是,CMWQ 出現了。正如其名,其並行程度與 worker pool 的平衡是內部調整的,並且所有 wq 共享各 CPU 上的 worker pool。worker pool 又可分為 bound 以及 unbound,分別是指定特定 CPU 以及動態分配
於 Linux 核心中提供了 alloc_workqueue
這項 API,取代原有 __create_workqueue
,透過