Linux提供了三種方法查詢加載到內核的模塊,一種方法是直接訪問proc虛擬文件系統獲取,一種方法則是比較常用的lsmod方法獲取,而lsmod的輸出其實是基于/proc/modules。另外還有一種就是查看/sys/module/目錄下是否生成已加載模塊的目錄。
?Linux 內核提供了一種通過 /proc 文件系統,在運行時訪問內核內部數據結構、改變內核設置的機制。
/proc 中的大多數虛擬文件都可以使用cat、more和less等命令查看。其中,/proc/modules列出了所有load進入內核的模塊列表,里面的內容會隨著系統使用和配置的變化而變化。/proc/modules內模塊加載情況查詢如下:
[root@localhost]#?cat?/proc/modules
hellomod?16384?0?-?Live?0xffffffffc1072000?(OE)
openvswitch?212992?0?-?Live?0xffffffffc103d000
nf_conncount?24576?1?openvswitch,?Live?0xffffffffc1036000
xt_nat?16384?15?-?Live?0xffffffffc1022000
vhost_net?40960?1?-?Live?0xffffffffc102b000
vhost?65536?1?vhost_net,?Live?0xffffffffc0ea4000
...
intel_uncore?258048?0?-?Live?0xffffffffc0d39000
pcspkr?16384?0?-?Live?0xffffffffc05ad000
mei_me?57344?0?-?Live?0xffffffffc0d2a000
ipmi_ssif?49152?0?-?Live?0xffffffffc0d16000
mei?184320?1?mei_me,?Live?0xffffffffc0cd8000
i2c_i801?36864?0?-?Live?0xffffffffc0c46000
...
#hellomod是小編自定義的模塊,加載后可在/proc/modules中查詢到
[root@localhost]#?cat?/proc/modules?|?grep?hellomod
hellomod?16384?0?-?Live?0xffffffffc1072000?(OE)
上述查詢結果大家看起來可能會比較懵,接下來讓我們解析下各列的含義:
?Linux lsmod命令用于顯示已經加載到內核中的模塊的狀態信息,原理就是將/proc/modules 中的信息調整一下格式輸出。
執行lsmod命令后會列出所有已載入系統的模塊,lsmod 輸出列表中有一列?Used by?,它表明此模塊正在被其他模塊使用。Linux操作系統的核心具有模塊化的特性,因此在編譯核心時,務須把全部的功能都放入核心。您可以將這些功能編譯成一個個單獨的模塊,待需要時再分別載入。
[root@localhost]#?lsmod
Module??????????????????Size??Used?by
hellomod???????????????16384??0
openvswitch???????????212992??0
tun????????????????????69632??4?vhost_net
bridge????????????????393216??0
...
mei???????????????????184320??1?mei_me
i2c_i801???????????????36864??0
ioatdma????????????????69632??0
lpc_ich????????????????28672??0
...
dm_mirror??????????????28672??0
dm_region_hash?????????28672??1?dm_mirror
dm_log?????????????????24576??2?dm_region_hash,dm_mirror
dm_mod????????????????204800??12?dm_log,dm_mirror
#hellomod是小編自定義的模塊,加載后可通過lsmod查詢到
[root@localhost]#?lsmod?|?grep?hellomod
hellomod???????????????16384??0
上述查詢結果雖然比第一種方法輸出列少,但是可能大家依然不知道什么意思,接下來讓我們解析下各列的含義:
該目錄下有系統中所有的模塊信息,不論這些模塊是以內聯(inlined) 方式 編譯到內核鏡像文件中,還是編譯為外部模塊(.ko),均會在/sys/module目錄下生成以模塊名命名的目錄 。
[root@localhost]#?ls?-l?/sys/module
total?0
drwxr-xr-x.?3?root?root?0?Feb?23?19:32?8250
drwxr-xr-x.?3?root?root?0?Feb?23?19:32?acpi
drwxr-xr-x.?5?root?root?0?Feb?23?19:32?acpi_ipmi
...
drwxr-xr-x.?3?root?root?0?Feb?23?19:32?firmware_class
drwxr-xr-x.?5?root?root?0?Feb?23?19:32?ghash_clmulni_intel
drwxr-xr-x.?3?root?root?0?Feb?23?19:32?gpiolib_acpi
drwxr-xr-x.?5?root?root?0?Feb?23?19:32?grace
drwxr-xr-x.?3?root?root?0?Feb?23?19:32?haltpoll
drwxr-xr-x.?5?root?root?0?Feb?23?19:34?hellomod
drwxr-xr-x.?3?root?root?0?Feb?23?19:32?hid
...
[root@localhost]#?ls?-l?/sys/module?|?grep?hellomod
drwxr-xr-x.?5?root?root?0?Feb?23?19:34?hellomod
當我們加載驅動程序之后,我們可以通過 調用cat /proc/modules、lsmod命令或者查看 ?/sys/module/,查看我們剛加載的模塊有沒加載成功。
?將指定模塊加載到內核,insmod命令完全由用戶自行加載一個完整文件名的模塊,不會主動分析模塊依賴性,需要自己手動加載。
語法格式:
insmod?[?文件名?]?[?模塊參數...?]
例如:
insmod?/path/xxx.ko
其中,path表示ko文件的絕對路徑或相對路徑。
?分析可加載模塊的依賴性,生成
modules.dep文件和modules.dep.bin文件,以便modprobe加載模塊時根據modules.dep.bin進行依賴模塊加載。
語法格式:
[root@localhost]#?depmod?[-adeisvV][-m<文件>][--help][模塊名稱]
-a?分析所有可用的模塊
-d?執行排錯模式
-e?輸出無法參照的符號
-i?不檢查符號表的版本
-m<文件>?使用指定的符號表文件
-n 不寫入 modules.dep ,而是將結果輸出到螢幕上(standard out);
-s?在系統記錄中記錄錯誤
-v?執行時顯示詳細的信息
-V?顯示版本信息
--help?顯示幫助
Linux內核模塊可以為其它模塊提供提供服務(在代碼中使用EXPORT_SYMBOL),這種服務被稱作”symbols”。若第二個模塊使用了這個symbol,則該模塊很明顯依賴于第一個模塊。這些依賴關系是非常繁雜的。
depmod 通過讀取?/lib/modules/$(uname -r)?/下的每個模塊并確定它導出的符號和需要的符號,創建一個模塊依賴關系列表。默認情況下,此列表將寫入modules.dep和名為modules.dep.bin的二進制哈希版本,這兩個文件位于同一目錄中。如果在命令行中給出了文件名,則只檢查這些模塊(除非列出了所有模塊,否則這些模塊很少有用)。
depmod 還創建由?modules.symbols?文件及其二進制散列版本?modules.symbols.bin?中的模塊提供的符號列表。
最后,如果模塊提供了特殊的設備名(devname),則 depmod 將輸出一個名為?modules.devname?的文件,該設備名應在啟動時填充在?/dev?中(由?udev?等實用程序填充)。
?加載或卸載內核模塊;
語法格式:
modprobe?[?參數]?[模塊名稱]?[模塊參數...]
modprobe需要根據modules.dep.bin文件的內容進行加載操作,可以自動解決模塊間的依賴關系表,一次性將有依賴關系的驅動全部加載到內核,不需要驅動的具體地址,但需要將驅動拷貝或設置軟鏈接到/lib/modules/$(uname -r)/或者/lib/modules/$(uname -r)/extra/目錄下。modprobe加載模塊時并不需要指定ko文件的具體目錄,直接使用modprobe 模塊名字即可,我們不仿測試下:
#加載hellomod.ko模塊之前,默認的模塊信息如下
[root@localhost?6.2.0-rc5+]#?modinfo?hellomod
filename:???????/lib/modules/6.2.0-rc5+/hellomod.ko
license:????????Dual?BSD/GPL
srcversion:?????DEA7EE7031439C7A120C77C
depends:
retpoline:??????Y
name:???????????hellomod
vermagic:???????6.2.0-rc5+?SMP?preempt?mod_unload?modversions
#刪除調/lib/modules/$(uname?-r)/目錄下的hellomod軟鏈接
[root@localhost?6.2.0-rc5+]#?rm?-f?hellomod.ko
[root@localhost?6.2.0-rc5+]#?ls?-l
total?3800
lrwxrwxrwx.??1?root?root?????27?Feb?20?11:17?build?->?/usr/src/kernels/6.2.0-rc5+
drwxr-xr-x.?13?root?root????141?Feb?24?10:46?kernel
-rw-r--r--.??1?root?root?943175?Feb?24?19:26?modules.alias
-rw-r--r--.??1?root?root?899138?Feb?24?19:26?modules.alias.bin
-rw-r--r--.??1?root?root???8920?Jan?30?10:22?modules.builtin
-rw-r--r--.??1?root?root??11118?Feb?24?19:26?modules.builtin.bin
-rw-r--r--.??1?root?root??69179?Jan?30?10:22?modules.builtin.modinfo
-rw-r--r--.??1?root?root?313395?Feb?24?19:26?modules.dep
-rw-r--r--.??1?root?root?429116?Feb?24?19:26?modules.dep.bin
-rw-r--r--.??1?root?root????405?Feb?24?19:26?modules.devname
-rw-r--r--.??1?root?root?106408?Jan?30?10:22?modules.order
-rw-r--r--.??1?root?root????833?Feb?24?19:26?modules.softdep
-rw-r--r--.??1?root?root?494353?Feb?24?19:26?modules.symbols
-rw-r--r--.??1?root?root?593333?Feb?24?19:26?modules.symbols.bin
lrwxrwxrwx.??1?root?root?????27?Feb?20?11:17?source?->?/usr/src/kernels/6.2.0-rc5+
#復制源文件路徑下的hellomod.ko到/lib/modules/$(uname?-r)路徑下
[root@localhost?6.2.0-rc5+]#?cp?/tmp/28/hellomod.ko?.
[root@localhost?6.2.0-rc5+]#?ls?-l
total?4080
lrwxrwxrwx.??1?root?root?????27?Feb?20?11:17?build?->?/usr/src/kernels/6.2.0-rc5+
-rw-r--r--.??1?root?root?285744?Feb?25?17:18?hellomod.ko
drwxr-xr-x.?13?root?root????141?Feb?24?10:46?kernel
-rw-r--r--.??1?root?root?943175?Feb?24?19:26?modules.alias
-rw-r--r--.??1?root?root?899138?Feb?24?19:26?modules.alias.bin
-rw-r--r--.??1?root?root???8920?Jan?30?10:22?modules.builtin
-rw-r--r--.??1?root?root??11118?Feb?24?19:26?modules.builtin.bin
-rw-r--r--.??1?root?root??69179?Jan?30?10:22?modules.builtin.modinfo
-rw-r--r--.??1?root?root?313395?Feb?24?19:26?modules.dep
-rw-r--r--.??1?root?root?429116?Feb?24?19:26?modules.dep.bin
-rw-r--r--.??1?root?root????405?Feb?24?19:26?modules.devname
-rw-r--r--.??1?root?root?106408?Jan?30?10:22?modules.order
-rw-r--r--.??1?root?root????833?Feb?24?19:26?modules.softdep
-rw-r--r--.??1?root?root?494353?Feb?24?19:26?modules.symbols
-rw-r--r--.??1?root?root?593333?Feb?24?19:26?modules.symbols.bin
lrwxrwxrwx.??1?root?root?????27?Feb?20?11:17?source?->?/usr/src/kernels/6.2.0-rc5+
#直接執行modprobe會報錯并提示無法插入hellomod.ko文件,需要執行depmod命令更新modules.dep和modules.dep.bin文件,
#將hellomod.ko的路徑寫入modules.dep和modules.dep.bin文件中
[root@localhost?6.2.0-rc5+]#?modprobe?hellomod
modprobe:?ERROR:?could?not?insert?'hellomod':?Unknown?symbol?in?module,?or?unknown?parameter?(see?dmesg)
[root@localhost?6.2.0-rc5+]#
#depmod指令會自動分析/lib/modules/$(uname -r)/目錄下的可加載模塊,并按照固定的格式填入modules.dep和modules.dep.bin中。
#因此,我們可以先將需要加載的ko文件拷貝到對應的目錄,再執行depmod指令。
[root@localhost?6.2.0-rc5+]#?depmod
#執行depmod后,在modules.dep和modules.dep.bin中已經存在有我們需要加載的ko文件名了,注意,不要手工的去編輯modules.dep文件
[root@localhost?6.2.0-rc5+]#?cat?modules.dep?|?grep?hellomod
hellomod.ko:
#再執行modprobe指令,即可加載模塊了,modprobe是根據modules.dep.bin文件中的路徑信息加載ko文件。
[root@localhost?6.2.0-rc5+]#?modprobe?hellomod
[root@localhost?6.2.0-rc5+]#?lsmod?|?grep?hellomod
hellomod???????????????16384??0
?注意:在加載自己制作的ko文件時,我們最好使用insmod命令;因為modprobe使用的模塊加載路徑一般是系統啟動時的默認加載路徑,存放的一般是系統原始的ko文件。
?如果要使用modprobe進行加載,則建議不用將默認加載路徑下的模塊文件替換掉,一旦將原始ko模塊文件替換掉,假如自己制作的模塊文件存在bug,可能導致系統出現故障,即使重新啟動機器,系統默認加載的仍然是自己制作的ko文件,這時就會導致系統無法正常啟動。因此,假如要使用modprobe命令,則建議在與默認加載路徑不同的
?/lib/modules/$(uname -r)/或者/lib/modules/$(uname -r)/extra/路徑下生成源模塊文件的軟鏈接,再分別執行depmod, modprobe xxx兩個命令,這樣能成功加載自己制作的模塊文件,且即使自制模塊有bug也不影響系統重啟后成功啟動。因為這樣操作過后,系統重啟后該模塊文件未加載到內核,讀者可以自己實驗。有上述可知,無論使用modprobe或者insmod加載自制的模塊,在重啟后均會失效;對于insmod,系統重啟后仍然會加載默認路徑下的內核模塊。對于modprobe,系統重啟后則既不會加載自制模塊也不會加載默認模塊。
好多文章或博客里面寫到modprobe是根據modules.dep文件的內容進行加載模塊操作的,其實是不正確的。使用 strace 追蹤 modprobe 的調用過程,發現 modprobe 并不會使用 modules.dep 文件,而是調用modules.dep.bin文件。
strace 的相關信息記錄如下:
[root@localhost]#?strace?/sbin/modprobe?hellomod??2>&1?|?grep?"modules"
open("/lib/modules/6.2.0-rc5+/modules.softdep",?O_RDONLY|O_CLOEXEC)?=?3
open("/lib/modules/6.2.0-rc5+/modules.dep.bin",?O_RDONLY|O_CLOEXEC)?=?3
open("/lib/modules/6.2.0-rc5+/modules.alias.bin",?O_RDONLY|O_CLOEXEC)?=?3
open("/lib/modules/6.2.0-rc5+/modules.symbols.bin",?O_RDONLY|O_CLOEXEC)?=?3
open("/lib/modules/6.2.0-rc5+/modules.builtin.bin",?O_RDONLY|O_CLOEXEC)?=?3
open("/lib/modules/6.2.0-rc5+/hellomod.ko",?O_RDONLY|O_CLOEXEC)?=?3
由上面結果可知,modprobe在加載模塊時,它訪問了 modules.dep.bin、modules.alias.bin、modules.symbols.bin、modules.builtin.bin 等文件,它并沒有訪問 modules.dep 文件。
接下來讓我們使用man modules.dep看下有關該文件的說明:
DESCRIPTION
???????modules.dep.bin?is?a?binary?file?generated?by?depmod?listing?the?dependencies?for?every?module?in?the?directories?under?/lib/modules/version.?It?is?used?by?kmod?tools?such?as?modprobe
???????and?libkmod.
???????Its?text?counterpar?is?located?in?the?same?directory?with?the?name?modules.dep.?The?text?version?is?maintained?only?for?easy?of?reading?by?humans?and?is?in?no?way?used?by?any?kmod
???????tool.
???????These?files?are?not?intended?for?editing?or?use?by?any?additional?utilities?as?their?format?is?subject?to?change?in?the?future.?You?should?use?the?modinfo(8)?command?to?obtain
???????information?about?modules?in?a?future?proof?and?compatible?fashion?rather?than?touching?these?files.
從man的描述來看,modules.dep只是供人查看的,kmod相關的命令使用的是modules.dep.bin這個文件,如modprobe和libkmod。
?查看某個模塊的詳細信息。
語法格式:
[root@localhost]#?modinfo?[-adlpn0Fkbvh]?<模塊文件>
-a 或–author 顯示模塊開發人員。
-d 或–description 顯示模塊的說明。
-l?或—license?顯示版本信息
-p 或–parameters 顯示模塊所支持的參數。
-0?或–null?用?\0?代替?\n?-F?或–field=FIELD?僅打印提供的字段
-k?或–set-version=VERSION?用?VERSION?代替uname?-r
-b?或–basedir=DIR?使用?DIR?作為/lib/modules?的文件系統根目錄
-V?或–version?顯示版本信息
-h?或–help?顯示幫助信息
modinfo命令通過/lib/modules/$(uname -r)/modules.dep?文件獲取模塊(ko文件)的實際存放路徑,之后,通過調用modinfo()函數打開模塊(ko文件)從而獲取模塊的詳細信息并打印出來。因此,存在這樣一種情況,即模塊實際并未加載,但是通過modinfo卻可以讀取到模塊的詳細信息。
?注:這就告誡我們,當使用modinfo讀出模塊的詳細信息時,不要就誤以為模塊已加載到內核。
這里,我們演示一下模塊未加載,但是modinfo卻能顯示模塊的詳細信息的例子,如下:
#lsmod顯示的內容中未檢索到hellomod模塊,說明hellomod模塊未加載到內核
[root@localhost]#?lsmod?|?grep?hellomod
[root@localhost]#
#直接執行modinfo命令可以顯示hellomod模塊的詳細信息
[root@localhost]#?modinfo?hellomod
filename:???????/lib/modules/6.2.0-rc5+/hellomod.ko
license:????????Dual?BSD/GPL
srcversion:?????DEA7EE7031439C7A120C77C
depends:
retpoline:??????Y
name:???????????hellomod
vermagic:???????6.2.0-rc5+?SMP?preempt?mod_unload?modversions
[root@localhost]#
#查看/lib/modules/$(uname?-r)/modules.dep文件內容,包含hellomod路徑
[root@localhost]#?cat?/lib/modules/$(uname?-r)/modules.dep?|?grep?hellomod
hellomod.ko:
[root@localhost]#?ls?-l?/lib/modules/$(uname?-r)
total?3800
lrwxrwxrwx.??1?root?root?????27?Feb?20?11:17?build?->?/usr/src/kernels/6.2.0-rc5+
lrwxrwxrwx.??1?root?root?????19?Feb?23?19:26?hellomod.ko?->?/tmp/28/hellomod.ko
drwxr-xr-x.?13?root?root????141?Feb?24?10:46?kernel
-rw-r--r--.??1?root?root?943175?Feb?24?14:17?modules.alias
-rw-r--r--.??1?root?root?899138?Feb?24?14:17?modules.alias.bin
-rw-r--r--.??1?root?root???8920?Jan?30?10:22?modules.builtin
-rw-r--r--.??1?root?root??11118?Feb?24?14:17?modules.builtin.bin
-rw-r--r--.??1?root?root??69179?Jan?30?10:22?modules.builtin.modinfo
-rw-r--r--.??1?root?root?313395?Feb?24?14:17?modules.dep
-rw-r--r--.??1?root?root?429116?Feb?24?14:17?modules.dep.bin
-rw-r--r--.??1?root?root????405?Feb?24?14:17?modules.devname
-rw-r--r--.??1?root?root?106408?Jan?30?10:22?modules.order
-rw-r--r--.??1?root?root????833?Feb?24?14:17?modules.softdep
-rw-r--r--.??1?root?root?494353?Feb?24?14:17?modules.symbols
-rw-r--r--.??1?root?root?593333?Feb?24?14:17?modules.symbols.bin
lrwxrwxrwx.??1?root?root?????27?Feb?20?11:17?source?->?/usr/src/kernels/6.2.0-rc5+
上面示例說明,hellomod模塊未加載時,modinfo通過讀取modules.dep文件中hellomod模塊的實際路徑,找到hellomod.ko文件,讀取該文件,從而獲取hellomod模塊的詳細信息。
接下來,我們通過modprobe加載hellomod模塊,再通過modinfo查看,發現和未加載hellomod模塊時顯示的一樣。
[root@localhost]#?modprobe?hellomod
[root@localhost]#?lsmod?|?grep?hellomod
hellomod???????????????16384??0
[root@localhost]#?modinfo?hellomod
filename:???????/lib/modules/6.2.0-rc5+/hellomod.ko
license:????????Dual?BSD/GPL
srcversion:?????DEA7EE7031439C7A120C77C
depends:
retpoline:??????Y
name:???????????hellomod
vermagic:???????6.2.0-rc5+?SMP?preempt?mod_unload?modversions
[root@localhost]#
?rmmod命令來自于英文詞組”remove module“的縮寫,其功能是用于移除內核中已加載的模塊。
語法格式:
rmmod?[參數]?模塊名稱??
常用參數如下:
| -a | 刪除所有目前不需要的模塊 |
|---|---|
| -s | 把信息輸出至日志服務中 |
| -v | 顯示指令執行的詳細信息 |
| -f | 強制移除模塊 |
| -w | 確認模塊能被刪除時再操作 |
[root@localhost?6.2.0-rc5+]#?lsmod?|?grep?hellomod
hellomod???????????????16384??0
[root@localhost?6.2.0-rc5+]#
[root@localhost?6.2.0-rc5+]#?rmmod?hellomod
[root@localhost?6.2.0-rc5+]#?lsmod?|?grep?hellomod
[root@localhost?6.2.0-rc5+]#
#查看dmesg日志,可以看到hellomod模塊在卸載后的日志
[root@localhost?~]#?dmesg?|?tail?-2
[181935.423616]?Hello,?World!
[181944.217893]?Goodbye,?World!