本文從介紹Linux與Linux核心模組基本概念開始,進而提及與核心模組相關的六個指令,以及擺放模組檔案的相關目錄,最後介紹更新核心的注意事項。
簡單地說,Linux核心(Kernel)和核心模組的主要功能是「驅動各式各樣的硬體設備」與「支援各種功能的軟體使用」。上述兩項功能再加上眾多Distribution廠商的推動,成功地將Linux應用在各式各樣商業化的場合,應用範圍之廣,大到超級電腦叢集運算、伺服器、桌上型電腦,小至嵌入式系統,都有Linux的蹤影,這就是Linux為何能夠只花短短的十多年,就在電腦業界產生這麼巨大影響力的緣故。
開機載入Linux核心
Linux開機的時候,通常經由Boot Loader(GRUB或LILO)載入Linux kernel,Linux kernel通常是位於「/boot/」目錄內名為vmlinuz開頭的檔案。
在載入核心之後,「最基本的、每台主機都用到的硬體與軟體功能」就一體成形地由核心來驅動提供這些功能。至於其他「選用的、每台主機不一定用到的功能」,則交給核心模組,視需要的時候才做載入的動作。
下圖為核心載入時候的訊息,開機完成後記錄在「/var/log/dmesg」檔案內以供查閱。
核心載入之後,即支援的功能
先前提到「最基本的、每台主機都用到的功能」由核心本身來驅動,對於一台標準PC、載入一個很普通的核心來說,不外乎以下幾項功能:
●驅動CPU運算(包括支援多核心CPU)
●記憶體管理
●行程(Process)管理
●提供行程呼叫system calls達到基本I/O功能
●IDE介面驅動以及抓到這個介面上的設備,例如硬碟與光碟機
●支援ext2檔案系統(這樣才有檔案系統樹狀目錄架構,接續使用檔案系統內的其他程式)
●基本I/O埠(例如PS/2鍵盤)
●驅動PCI/AGP/PCI-E介面並發現其上的設備,例如驅動顯示卡最基本的文字模式功能
●Sockets功能與TCP/IP網路等等。
可載入的核心模組
為了保持執行效率以及避免核心提供過多不必要的功能,導致核心變得肥大,其餘「選用的、每台主機不一定用到的功能」在編譯Linux核心的時候,通常選擇將此功能做成Loadable Kernel Module(可載入的核心模組)。觀察已經載入哪些模組,則是使用指令「lsmod」,如下圖。
許多的硬體介面卡和晶片組都採用模組的方式來載入,而不編譯進Linux核心內,畢竟不是每台主機都有提供那些硬體設備。
至於軟體功能,也是類似硬體的處理方式,如果此功能不見得一定要包含在核心內,或是不一定每台主機都用得到,就把這個軟體功能做成核心模組,等到要使用的時候再載入即可。
硬體的模組包括各類型的介面卡與晶片組,例如網路卡、顯示卡、音效卡、SATA晶片、USB、1394、印表埠、SCSI或SAS(序列SCSI)或RAID介面卡(或是晶片)等等。
而軟體的模組,涵蓋支持各類型的檔案系統(ext3、nfs、vfat等等)、IPv4/IPv6進階功能與防火牆相關的功能模組、軟體模擬的RAID(Software RAID)與LVM(使用device-mapper功能)等等。接下來,就以網路卡模組pcnet32為例,介紹兩、三個常用模組以及與核心模組有關的指令。
與核心模組相關的六個指令
與核心模組相關的主要指令共有以下六項,只要稍加注意不難發現,這六個指令都有「mod」這個關鍵字,也就是模組的英文「module」。
●列出(list)已經載入模組的「lsmod」
●觀察模組資訊(information)的「modinfo」
●用來卸除(remove)已經載入模組的「rmmod」
●用來載入(insert)模組的「insmod」
●提供自動探測(probe)相依性(dependence)來載入或卸除模組的「modprobe」
●做出模組相依的資料檔案「modules.dep」的「depmod」
使用指令「lsmod」觀察已經載入的核心模組
首先介紹「lsmod」指令,該指令可用來列出(list)已經載入的核心模組,依照第一行欄位標示,某個模組可能會被其他模組使用,也就是模組之間可能有相依性(dependence)關係。
舉例來說,筆者的測試主機在軟體方面有ext3需要基層jbd模組;硬體的部分則是網路卡驅動程式pcnet32需要基礎mii模組(如下圖精簡後的內容)。
在Red Hat Linux中可使用指令「grep eth /etc/modprobe.conf」查出這台主機所使用的網路卡核心模組名稱。以筆者的測試機為例,網路卡eth0使用的是pcnet32模組。這個modprobe.conf檔案記載著開機期間該載入哪些核心模組。
觀察模組資訊的「modinfo」指令
這麼多的模組名稱該如何得知各個模組的用途呢?此時,可以利用「modinfo」指令來觀察模組資訊(information)。以pcnet32模組為例,執行「modinfo pcnet32」指令後,在輸出內容中就會顯示許多資料,先觀察「描述」(description)得知這是網路卡的驅動程式(Driver)。
除此之外,由圖中「檔名」(filename)那一行可以得知,pcnet32模組檔實際位於「/lib/modules/2.6.18-53.el5/kernel/drivers/net/pcnet32.ko」,這個「net/」目錄也存放其他廠牌型號的網路卡驅動程式。
下圖是列出此目錄的檔案列表,有此看來,Linux本身就支援相當多種類的網路卡,若以最平價也是最知名的「螃蟹卡」為例(由8139too模組來驅動),使用「modinfo 8139too」指令即可觀察到其中的詳細資訊。
用來卸除(remove)已經載入模組的「rmmod」指令
使用指令rmmod可以卸載模組,想要將pcnet32模組卸載,可以使用「rmmod pcnet32」指令,但請注意,卸載後網路就會中斷。
用來載入(insert)模組的「insmod」指令
若想要將剛剛卸載的pcnet32模組載入回去,則使用「insmod /lib/modules/2.6.18-53.el5/kernel/drivers/net/pcnet32.ko」指令。請注意,模組檔案須使用完整的檔案名稱,不能只輸入pcnet32。
使用rmmod與insmod可能出現的相依性問題
承接先前rmmod與insmod範例,若想要先卸除底層mii模組,則會出現「ERROR: Module mii is in use by pcnet32」錯誤訊息,因為mii模組被pcnet32使用(相依),須先卸除pcnet32,才能夠卸除基礎的mii模組。
相反地,當載入這兩個模組的時候,若尚未載入基礎的mii就先載入pcnet32,則會顯示一則「error inserting ...: -1 Unknown symbol in module」的錯誤訊息。此時,基礎的mii模組必須先載入,才可以成功載入pcnet32。(載入mii時,須先查出它放在哪裡,再用insmod指令載入)
自動探測(probe)相依性來載入或卸除模組的「modprobe」指令
先前介紹的模組相依性(dependence),對於使用rmmod與insmod指令來操作時,實際上會造成一些阻礙與麻煩,想要避開這些麻煩的話,可使用「modprobe」指令來替代,尤其是載入模組時特別方便。
在下圖中,卸載模組使用「modprobe -r mii」、「modprobe -r pcnet32」指令,雖然沒有幫上大忙,但載入的時候使用「modprobe pcnet32」指令則會自動將相依的mii模組一起載入,而且不必輸入完整檔案路徑名稱,使用起來相當方便。
做出模組相依資料檔案「modules.dep」的「depmod」指令
先前提到modprobe指令會依照相依性載入相關模組,它是如何得知模組之間的相依性呢?以測試主機來說,modprobe指令是藉由讀取「/lib/modules/2.6.18-53.el5/modules.dep」檔案內容來判斷的。至於這個檔案則是使用「depmod -a」指令製作出來的。
所以若是模組數量有增減或相依性有異動,強烈建議再次執行「depmod -a」指令重新產出「modules.dep」檔案(請觀察檔案最後一次修改的時間來判斷此檔是否被更新)。這樣一來,不只modprobe指令可以用簡短的名稱載入或卸載模組(卸載模組時搭配「-r」選項),modinfo指令也可以用簡短的名稱查詢資訊,例如「modinfo pcnet32」。
若沒有modules.dep檔案,使用modinfo指令則必須像insmod一樣,輸入完整的模組檔案路徑名稱才行,例如「modinfo /lib/modules/2.6.18-53.el5/kernel/drivers/net/pcnet32.ko」。
關於「/lib/modules/」目錄
先前提到的核心模組,實際存放的位置在「/lib/modules/」目錄下,這裡要注意的是,它以核心版本號碼區分目錄存放;預設通常只會安裝一組核心與核心模組,所以也只有一個目錄名稱,以本例來說,就是「2.6.18-53.el5/」這個目錄名稱,這個目錄名稱會與核心版本號碼相同。可以使用「uname -r」指令觀察正在使用的核心版本號碼。
以RHEL5.1來說,執行「uname -r」指令後的輸出結果是「2.6.18-53.el5」,所以與這個版本的相關檔案則是放在「/lib/modules/2.6.18-53.el5/」目錄內,例如「mo
dules.dep」相依性關聯檔、「kernel/drivers/」底下各種類型的硬體驅動程式等等。
可以利用「/lib/modules/`uname -r`」或「/lib/modules/$(uname -r)」指令來表達這個目錄名稱,其中``與$()都是先執行包覆的內容後將其輸出,再與整個指令一同執行的意思。
更新核心
一般來說,Linux主機如果運作得好好地,沒必要也不會去更新Linux核心。以下列舉一些可能更新核心的時機:
●新核心有新的功能(會使用到),且舊核心剛好沒有此功能。
●舊核心發生不安全或是不穩定的現象,希望藉由更新核心來改善。
簡單來說,也就是新的核心支援新的硬體設備(如新的網路卡)或是支援新的軟體功能的時候。
更新核心注意事項
更新核心的時候最好也保留舊的核心,原因說明如下:
●新的核心若無法開機,舊的核心又被移除的話,會陷入無法開機的困境。
●新的核心上線跑了一陣子,卻沒有比使用舊的核心來得好,還可以再換回來用舊的。
舉例來說,在RHEL5.1系統上更新成RHEL5.2的核心,可使用指令「rpm -ivh kernel-2.6.18-92.el5.i686.rpm」來安裝新的核心(同時保留舊的核心),避免使用「-U」(升級)或是「-F」(修正)的rpm指令選項,因為該指令會將舊的核心移除,請小心使用。
安裝好新的核心之後,順道觀察「/boot/」目錄,底下會有兩個vmlinuz開頭的Linux核心檔案,以及「/lib/modules/」內會有各自的目錄。
最後記得編輯「/boot/grub/menu.lst」檔案內有關default參數的那一行,如果是「default=0」,代表使用第一個title的核心開機(以下圖來說是新的核心開機);若是「default=1」,則使用第二個title的核心開機。