歡迎來到Linux教程網
Linux教程網
Linux教程網
Linux教程網
Linux教程網 >> Linux綜合 >> Linux內核 >> Linux內核模塊使用指南

Linux內核模塊使用指南

日期:2017/2/27 9:40:00   编辑:Linux內核

作者:sss    一、模塊簡介     Windows NT是一種微內核的結構,其內核的功能塊被劃分成獨立的模塊,在這些功能塊之間有嚴格的通信機制;而Linux則不同,它是一種monolithic(單一大塊)結構,也就是說,整個內核是一個單獨的、非常大的程序。在這種結構中,部件的添加和刪除都相當麻煩,需要重新編譯內核。為了解決這個問題,不知道從哪個版本的內核開始,Linux引入了一種稱為module(模塊)的技術,可以把某些功能代碼作為模塊動態裝載到內核中使用。     模塊是一種目標對象文件,需要在內核空間執行,可以把它看作是一組已經編譯好而且已經鏈接成可執行文件的程序。在需要的時候,內核就會實用某種方法調用這些程序來執行特定的操作,實現特定的功能。內核在內核符號表中維護了一個模塊的鏈表,每個符號表對應一個模塊,在把模塊加載進內核時正確地對其進行解釋,並將模塊作為內核的一部分來執行;加載進內核中的模塊具有所有的內核權限。模塊可以在系統啟動時加載到系統中,也可以在系統運行的任何時刻加載;在不需要時,可以將模塊動態卸載。這樣就不用每次修改系統的配置時都要重新編譯內核了。     二、模塊的優缺點     內核模塊的這種動態裝載特性具有以下的優點:   1、可以把內核映像文件保持在最小。在編譯內核時可以選擇把一部分內容當成模塊進行編譯,這樣在最終生成的內核映像文件中就可以不包含這部分內容,從而生成最小的內核映像文件。   2、靈活性好。如果需要實用新的模塊,不必重新編譯內核,只要把新的模塊編譯後裝載進系統中就可以了。如果對內核源程序進行了修改,也不需要重新編譯整個內核,只需要修改對應的部分就可以了。     但是,內核模塊的引入也帶來了一些問題:   1、這種動態加載的特性不利於系統的性能和內存的利用,會帶來負面的影響。   2、裝入內核的模塊和其他內核部分一樣具有最高的權限,使用不當就可能引起系統的崩潰。   3、內核版本和模塊版本的不兼容也會導致系統的崩潰,因此必須進行嚴格的版本檢查,這樣就使模塊的編寫變得更加復雜了。   4、有些模塊要使用其他模塊(例如VFAT就要使用FAT)的內容,模塊之間存在一定的依賴關系,這樣模塊的實用就復雜化了。     由於模塊的這種動態裝載/卸載的特性,在Linux中大部分設備驅動程序都是使用模塊來編寫的,例如文件系統(minix、msdos、isofs、smbms、nfs、proc等等)、SCSI設備驅動程序、以太網驅動程序、CD-ROM驅動程序等等。下面讓我們介紹一下模塊的使用方法。     三、模塊的使用     1、模塊的查詢     我們可以使用lsmod命令來了解系統中現在裝載進來了哪些模塊。例如,在筆者機器上執行的結果為(注意,以下介紹的這些命令(包括lsmod)只有超級用戶才可以執行):     Module Size Used by   lockd 30344 1 (autoclean)   sunrpc 52132 1 (autoclean) [lockd]   rtl8139 11748 1 (autoclean)     其中Module列是模塊的名字,Size是顯示的模塊的大小,Used by列表示引用次數,圓括號中的autoclean表示該模塊可以在空閒時自動卸載,中括號中的[lockd]表示模塊lockd會引用sunrpc模塊的內容。       2、模塊的裝載     模塊的裝載有兩種方法:一種是實用insmod命令手工加載模塊,第二種方法是使用內核守護進程kerneld在需要的時候動態裝載。insmod命令的格式為:     insmod /

/modulename.o     值得注意的是,insmod命令需要知道模塊存放的位置,這樣才能在內核符號表中進行解析。模塊可以位於當前路徑中,也可以在insmod命令中指明絕對路徑,另外還有幾個相關的配置文件可以說明模塊的位置(見後文中的介紹)。     kerneld是一個標准的守護進程,具有超級用戶的權限,其主要功能是加載和卸載核心模塊, 但是它還可以執行其他任務, 如通過串行線路建立PPP連接並在適當時候關閉它。kerneld自身並不執行這些任務,它通過某些程序如insmod來做此工作。它只是內核的代理,為內核進行調度。這個守護進程僅僅是一個帶有超級用戶權限的普通用戶進程。當系統啟動時它也被啟動並為內核打開了一個進程間通訊(IPC)通道,內核需要執行各種任務時就實用這個IPC來向kerneld發送消息。例如,如果內核請求現在還沒有裝載到系統中的文件系統,那麼就通知kerneld裝載這個文件系統,然後內核就可以使用這個文件系統了。在模塊空閒時(即沒有其他進程使用這個模塊時),kerneld還可以動態卸載這個模塊。     需要注意的是,如果模塊之間有某種引用關系,那麼裝載模塊時必須遵循一定的次序。例如,上面lsmod顯示的結果中lockd模塊要引用sunrpc的內容,那麼必須首先裝載sunrpc之後才能裝載lockd,否則就會出錯。       3、模塊的卸載     我們可以使用rmmod命令把模塊從系統中卸載出去,該命令的格式為:     rmmod modulename     需要注意的是,模塊只有在空閒時才能夠從系統中卸載出去。lsmod輸出結果中的Used by一列就說明了模塊當前的狀態。如果該值不為0,說明模塊正忙,不能卸載;否則該值為0,說明模塊空閒,可以從系統中卸載出去。對於繁忙的設備,我們首先得斷開對應設備的連接,然後才能刪除對應的模塊。例如,我們要卸載模塊rtl8139(這個模塊是筆者機器中rtl8139的以太網卡對應的模塊),我們首先要斷開網絡連接:     ifdown eth0 /* eth0是筆者機器中的第一塊網卡*/     現在再執行lsmod命令的輸出結果為:     Module Size Used by   lockd 30344 1 (autoclean)   sunrpc 52132 1 (autoclean) [lockd]   rtl8139 11748 0 (autoclean)     說明已經沒有設備再使用rtl8139了,我們可以使用     rmmod rtl8139     命令將其從系統中卸載出去。     標志為autoclean(見有關lsmod的介紹)的模塊可以自動卸載。前面我們已經提到,模塊之間可能會有引用關系。如果A模塊引用了B模塊的內容,那麼必須先裝載B模塊之後才能成功裝載A模塊;在卸載B模塊之前也要首先卸載A模塊,否則就會導致系統的崩潰(當然,如果模塊源程序編寫的正確,在卸載A模塊之前,B模塊是無法卸載的)。     4、模塊實用工具     以上我們介紹的lsmod、insmod、rmmod是一組實用工具所提供的三個命令,這組實用工具一般是和內核版本對應的,其1.3.57版本名為modules(modules-1.3.57.tar.gz),高一點的版本名為modutils(例如modutils-2.4.2.tar.gz)。最好保證你的系統中的模塊實用工具的版本號(可以使用modinfo -V命令來查看)不低於內核版本號(可以使用uname -r來查看)。1.3.57版本的modules內容包括modprobe、depmod、genksyms、makecrc32、insmod、rmmod、lsmod、ksyms、kerneld等命令。其中modprobe和insmod命令類似,不過它要依賴於相關的配置文件;depmod用於生成模塊依賴文件/lib/modules/kernel-version/modules.dep;genksyms和ksyms與內核函數的版本號有關(由於內核的不斷更新,各個版本的內核函數各有不同,為了不會引起系統的崩潰,內核源程序中要對內核函數的版本號進行嚴格地控制)。在以後版本的實用工具中,使用kmod來取代了kerneld。kmod的功能和kerneld類似,但是它不能自動卸載模塊。之所以采用kmod的原因在於kerneld是使用IPC通道實現的,相當於多經過了一層處理,另外kerneld的代碼也比較復雜,kmod的代碼數量也比kerneld少得多。       5、與模塊有關的內核編譯選項和過程     在使用make confing / make menUConfig / make xconfig對內核進行配置時,和模塊有關的選項有:   Code maturity level options -->   Prompt for development and/or incomplete code/drivers   此選項為代碼的成熟程度。所有新的設計與改進都首先在開發版(版本號為x.y.z,其中y是奇數)中試用,經過驗證技術可行之後再在穩定版(版本號為x.y.z,其中y是偶數)中正式引入。尚不成熟或不完善的技術在默認的情況中是不會編譯到內核中的,如果你希望試驗這些內容(例如2.4.*版本中的khttpd、IPV6等),就要選中這個選項。   >   Loadable module support -->   Enable module support   Set version information on all module symbols   Kernel module loader   此選項是對可裝載內核的支持以及對模塊符號的版本號、內核模塊裝載程序支持的選項。對於其他大部分選項來說,你可以將相應的代碼編譯到內核中(使用build-in方式),也可以將他們編譯成模塊(使用module)方式。     如果你選用了模塊方式,那麼在編譯內核的過程中,你除了要使用     make; make install     命令來編譯/安裝內核之外,還要使用     make modules; make modules_install     來編譯/安裝內核模塊。編譯好的模塊被安裝到/lib/modules/kernel-version/目錄中。     編譯過程中還要運行一個     depmod -a     命令。這個命令生成模塊依賴文件,也就是/lib/modules/kernel-version/modules.dep,該文件格式為:     /lib/modules/2.2.14-5.0/fs/autofs.o:     /lib/modules/2.2.14-5.0/fs/binfmt_aout.o:     /lib/modules/2.2.14-5.0/fs/binfmt_Java.o:     /lib/modules/2.2.14-5.0/fs/binfmt_misc.o:     /lib/modules/2.2.14-5.0/fs/coda.o:     /lib/modules/2.2.14-5.0/fs/fat.o:     /lib/modules/2.2.14-5.0/fs/hfs.o:     /lib/modules/2.2.14-5.0/fs/hpfs.o:     /lib/modules/2.2.14-5.0/fs/lockd.o: /lib/modules/2.2.14-5.0/misc/sunrpc.o     /lib/modules/2.2.14-5.0/fs/minix.o:     /lib/modules/2.2.14-5.0/fs/msdos.o: /lib/modules/2.2.14-5.0/fs/fat.o     ......     這個文件中詳細列出了所有的模塊文件的絕對路徑,每一行說明一個模塊的信息;如果一行中有多個模塊的信息,就說明了模塊間具有依賴關系。例如,     /lib/modules/2.2.14-5.0/fs/lockd.o: /lib/modules/2.2.14-5.0/misc/sunrpc.o   這一行就說明模塊lockd要引用sunrpc模塊。有了這個文件,內核在裝載模塊時就可以根據所解析出的模塊名來正確地定位模塊的位置了。       6、與模塊有關的配置文件     和模塊有關的文件,除了上面這個modules.dep之外,還有幾個配置文件。例如:     /etc/rc.d/rc.modules   /etc/conf.modules或/etc/modules.conf     例如筆者機器中後一個文件的內容為:     alias eth0 rtl8139   alias sound-slot-0 via82cxxx     分別說明了網卡和聲卡的類型,例如第一行中eth0是我的第一塊網卡,rtl8139是對應的模塊,系統會查找/lib/modules/2.2.14-50/modules.dep文件,在其中找到     /lib/modules/2.2.14-5.0/net/rtl8139.o:     這一行,從而就可以定位正確的模塊文件。     7、單獨編譯模塊     我們除了可以在內核源程序樹中使用     make modules; make modules_install     來編譯安裝內核模塊之外,也可以自行對其進行編譯,相關的編譯選項有:     __KERNEL__--這個標志告訴頭文件此代碼將在內核模塊中運行,而不是作為用戶進程的一部分運行。     MODULE--這個標志告訴頭文件要為內核模塊給出適當的定義。     LINUX--從技術上講,這個標志不是必要的。但是,如果你希望寫一個比較正規的內核模塊,它可以在多個操作系統上編譯,這個標志將會使你感到非常方便。它可以允許你在獨立於操作系統的部分進行常規的編譯。     還有其它一些可被選擇包含標志,這取決於編譯模塊使用的選項。如果你不能確定內核應該怎樣編譯,可以在/usr/include/linux/config.h中查到。     __SMP__--對稱多處理。如果要把內核編譯成可以支持對稱多處理,那麼必須定義這個標志     CONFIG_MODVERSIONS--如果CONFIG_MODVERSIONS被激活(也就是說要區分內核模塊的版本號),你需要在編譯內核模塊時定義這個標志並包含頭文件/usr/include/linux/modversions.h。     例如,我們自行下載rtl8139網卡的驅動程序的源程序rtl8139.c,可以這樣編譯:     gcc -Wall -O2 -DMODULE -D__KERNEL__ -DLINUX -o rtl8139.o rtl8139.c     然後修改前面介紹的相應的配置文件或者使用insmod命令就可以使用這個模塊了。       8、相關問題     再次強調,模塊實用工具的版本號最好不要低於內核的版本號。例如,如果你的modutils的版本號小於2.4.0,那麼在你自己下載2.4.*版本的內核來編譯時,即使各個步驟都完全正確,你會發現/lib/modules/kernel-version/modules.dep這個文件為空,即使你自己手工修改了這個文件,重新啟動機器之後,這個文件又變成空了。所以對於這種情況,你應該使用2.4.*的modutils。2.2和2.4版本的內核模塊存儲的路徑有很大的差別,/etc/conf.modules文件的結構也很不相同了,感興趣的讀者可以自行試驗一下。   






Copyright © Linux教程網 All Rights Reserved