
Linux提供了三種方法查詢加載到內核的模塊,一種方法是直接訪問proc虛擬文件系統獲取,一種方法則是比較常用的lsmod方法獲取,而lsmod的輸出其實是基于/proc/modules。另外還有一種就是查看/sys/module/目錄下是否生成已加載模塊的目錄。
Linux 內核提供了一種通過 /proc 文件系統,在運行時訪問內核內部數據結構、改變內核設置的機制。
(相關資料圖)
/proc 中的大多數虛擬文件都可以使用cat、more和less等命令查看。其中,/proc/modules列出了所有load進入內核的模塊列表,里面的內容會隨著系統使用和配置的變化而變化。/proc/modules內模塊加載情況查詢如下:
[root@localhost]# cat /proc/moduleshellomod 16384 0 - Live 0xffffffffc1072000 (OE)openvswitch 212992 0 - Live 0xffffffffc103d000nf_conncount 24576 1 openvswitch, Live 0xffffffffc1036000xt_nat 16384 15 - Live 0xffffffffc1022000vhost_net 40960 1 - Live 0xffffffffc102b000vhost 65536 1 vhost_net, Live 0xffffffffc0ea4000...intel_uncore 258048 0 - Live 0xffffffffc0d39000pcspkr 16384 0 - Live 0xffffffffc05ad000mei_me 57344 0 - Live 0xffffffffc0d2a000ipmi_ssif 49152 0 - Live 0xffffffffc0d16000mei 184320 1 mei_me, Live 0xffffffffc0cd8000i2c_i801 36864 0 - Live 0xffffffffc0c46000...#hellomod是小編自定義的模塊,加載后可在/proc/modules中查詢到[root@localhost]# cat /proc/modules | grep hellomodhellomod 16384 0 - Live 0xffffffffc1072000 (OE)
上述查詢結果大家看起來可能會比較懵,接下來讓我們解析下各列的含義:
第一列:模塊的名字第二列:模塊的內存大小,單位是bytes第三列:被load的次數,0意味著沒有被load過第四列:是否依賴第三方moudle,列出這些module第五列:模塊的狀態,有Live, Loading, Unloading三種狀態第六列:模塊當前的內核內存偏移位置。這些信息,debug的時候會非常有用。例如使用診斷工具 addr2line時就可能會用到該內存偏移位置。Linux lsmod命令用于顯示已經加載到內核中的模塊的狀態信息,原理就是將/proc/modules 中的信息調整一下格式輸出。
執行lsmod命令后會列出所有已載入系統的模塊,lsmod 輸出列表中有一列 Used by
,它表明此模塊正在被其他模塊使用。Linux操作系統的核心具有模塊化的特性,因此在編譯核心時,無須把全部的功能都放入核心。您可以將這些功能編譯成一個個單獨的模塊,待需要時再分別載入。
[root@localhost]# lsmodModule Size Used byhellomod 16384 0openvswitch 212992 0tun 69632 4 vhost_netbridge 393216 0...mei 184320 1 mei_mei2c_i801 36864 0ioatdma69632 0lpc_ich 28672 0...dm_mirror 28672 0dm_region_hash 28672 1 dm_mirrordm_log 24576 2 dm_region_hash,dm_mirrordm_mod 204800 12 dm_log,dm_mirror#hellomod是小編自定義的模塊,加載后可通過lsmod查詢到[root@localhost]# lsmod | grep hellomodhellomod 16384 0
上述查詢結果雖然比第一種方法輸出列少,但是可能大家依然不知道什么意思,接下來讓我們解析下各列的含義:
第一列:模塊的名字第二列:模塊的大小第三列:被其他模塊所依賴的次數第四列:依賴該模塊的模塊名稱該目錄下有系統中所有的模塊信息,不論這些模塊是以內聯(inlined) 方式 編譯到內核鏡像文件中,還是編譯為外部模塊(.ko),均會在/sys/module目錄下生成以模塊名命名的目錄 。
[root@localhost]# ls -l /sys/moduletotal 0drwxr-xr-x. 3 root root 0 Feb 23 19:32 8250drwxr-xr-x. 3 root root 0 Feb 23 19:32 acpidrwxr-xr-x. 5 root root 0 Feb 23 19:32 acpi_ipmi...drwxr-xr-x. 3 root root 0 Feb 23 19:32 firmware_classdrwxr-xr-x. 5 root root 0 Feb 23 19:32 ghash_clmulni_inteldrwxr-xr-x. 3 root root 0 Feb 23 19:32 gpiolib_acpidrwxr-xr-x. 5 root root 0 Feb 23 19:32 gracedrwxr-xr-x. 3 root root 0 Feb 23 19:32 haltpolldrwxr-xr-x. 5 root root 0 Feb 23 19:34 hellomoddrwxr-xr-x. 3 root root 0 Feb 23 19:32 hid...[root@localhost]# ls -l /sys/module | grep hellomoddrwxr-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 hellomodfilename: /lib/modules/6.2.0-rc5+/hellomod.kolicense: Dual BSD/GPLsrcversion: DEA7EE7031439C7A120C77Cdepends:retpoline: Yname: hellomodvermagic: 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 -ltotal 3800lrwxrwxrwx. 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.binlrwxrwxrwx. 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 -ltotal 4080lrwxrwxrwx. 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.kodrwxr-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.binlrwxrwxrwx. 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 hellomodmodprobe: 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 hellomodhellomod.ko:#再執行modprobe指令,即可加載模塊了,modprobe是根據modules.dep.bin文件中的路徑信息加載ko文件。[root@localhost 6.2.0-rc5+]# modprobe hellomod[root@localhost 6.2.0-rc5+]# lsmod | grep hellomodhellomod 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) = 3open("/lib/modules/6.2.0-rc5+/modules.dep.bin", O_RDONLY|O_CLOEXEC) = 3open("/lib/modules/6.2.0-rc5+/modules.alias.bin", O_RDONLY|O_CLOEXEC) = 3open("/lib/modules/6.2.0-rc5+/modules.symbols.bin", O_RDONLY|O_CLOEXEC) = 3open("/lib/modules/6.2.0-rc5+/modules.builtin.bin", O_RDONLY|O_CLOEXEC) = 3open("/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 hellomodfilename: /lib/modules/6.2.0-rc5+/hellomod.kolicense: Dual BSD/GPLsrcversion: DEA7EE7031439C7A120C77Cdepends:retpoline: Yname: hellomodvermagic: 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 hellomodhellomod.ko:[root@localhost]# ls -l /lib/modules/$(uname -r)total 3800lrwxrwxrwx. 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.kodrwxr-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.binlrwxrwxrwx. 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 hellomodhellomod 16384 0[root@localhost]# modinfo hellomodfilename: /lib/modules/6.2.0-rc5+/hellomod.kolicense: Dual BSD/GPLsrcversion: DEA7EE7031439C7A120C77Cdepends:retpoline: Yname: hellomodvermagic: 6.2.0-rc5+ SMP preempt mod_unload modversions[root@localhost]#
注:modinfo只有在其后接xxx.ko時,才是讀取該模塊的詳細信息,即只有帶.ko后綴時,讀取的才是當前路徑下的模塊文件;不帶.ko后綴時,讀取的則是
/lib/modules/$(uname -r)/modules.dep
文件內保存的路徑下的模塊的信息。
rmmod命令來自于英文詞組”remove module“的縮寫,其功能是用于移除內核中已加載的模塊。
語法格式:
rmmod [參數] 模塊名稱
常用參數如下:
-a | 刪除所有目前不需要的模塊 |
---|---|
-s | 把信息輸出至日志服務中 |
-v | 顯示指令執行的詳細信息 |
-f | 強制移除模塊 |
-w | 確認模塊能被刪除時再操作 |
[root@localhost 6.2.0-rc5+]# lsmod | grep hellomodhellomod 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!
標簽: