Linux內核初探
內核的組成部分
-
kernel:內核核心文件,一般為bzp_w_picpath,經過壓縮處理的鏡像文件;通常內核核心文件保存在/boot/目錄下,名稱為vmlinuz-version-release
-
kernel object(ko):內核對象,內核額外功能模塊,一般該類文件放置于/lib/modules/[version-release]
內核管理的相關命令
uname
-
功能:打印當前系統相關信息(內核版本號、硬件架構、主機名稱和操作系統類型等)。
-
常用選項
-n
:顯示節點名稱-r
:顯示內核版本號,包括version和release-a
:顯示所有信息
lsmod
-
功能:列出內核已載入模塊的狀態
-
用法:lsmod
-
描述:lsmod 以美觀的方式列出/proc/modules的內容,顯示當前加載的所有模塊。
輸出為:
Module(模塊名) Size(模塊大小) Used by(被…使用)
eg. ne2k_pci 8928 0
8390 9472 1 ne2k_pci在/proc/modules中相應的是:
(模塊名,模塊大小,被…使用,模塊地址)
ne2k_pci 8928 0 – Live 0×3086400
8390 9472 1 ne2k_pci , Live 0xe086000
注意:在ubuntu12 之前,還可以通過 modprobe -l 來查看已經加載的模塊列表,但現在已經沒有這個選項。
假設你沒有設定開機加載某個模塊,比如ntfs,那么開機后執行lsmod,列表里不會有ntfs這個模塊的,這時你再執行 mount -t ntfs xxx后,執行lsmod后列表里就會有ntfs這個模塊了。
還要注意的是lsmod顯示的是模塊名,而不是別名(alias)。
depmod
-
功能:分析可加載模塊的依賴性,生成modules.dep文件和映射文件,,在構建嵌入式系統時,需要由這個命令來生成相應的文件,由modprobe使用。
-
用法:
depmod [-b basedir] [-e] [-F System.map] [-n] [-v] [version] [-A]
depmod [-e] [-F System.map] [-n] [-v] [version] [filename…]
-
描述:
Linux內核模塊可以為其它模塊提供提供服務(在代碼中使用EXPORT_SYMBOL),這種服務被稱作”symbols”。若第二個模塊使用了這個symbol,則該模塊很明顯依賴于第一個模塊。這些依賴關系是非常繁雜的。
depmod讀取在/lib/modules/version 目錄下的所有模塊,并檢查每個模塊導出的symbol和需要的symbol,然后創建一個依賴關系列表。默認地,該列表寫入到/lib/moudules /version目錄下的modules.dep文件中。若命令中的filename有指定的話,則僅檢查這些指定的模塊(不是很有用)。
若命令中提供了version參數,則會使用version所指定的目錄生成依賴,而不是當前內核的版本(uname -r 返回的)。
-
選項:
-b
basedir –basedir basedir 若你的模塊并沒有正確的在/lib/mdules/version下,可以指定目錄生成依賴。-e
–errsyms 和-F選項一起使用,當一個模塊需要的symbol在其它模塊里面沒有提供時,做出報告。正常情況下,模塊沒有提供的symbol都在內核中有提供。-F
–filesyms System.map 提供一個System.map文件(在內核編譯時生成的)許-e選項報告出unresolved symbol。-n
–dry_run 將結果modules.dep和各種映射文件輸出到標準輸出(stdout),而不是寫到模塊目錄下。-A
–quick 檢查是否有模塊比modues.dep中的模塊新,若沒有,則退出不重新生成文件。
modules.dep與depmod
modprobe加載某個模塊是根據/lib/modules/`uname -r`目錄下的modules.dep文件中的模塊列表,這個文件中有的模塊modprobe會正確加載,否則就會出錯。
我們拿ntfs這個模塊來舉例:
vi /lib/modules/`uname -r`/modules.dep
注釋掉 /lib/modules/2.6.18-4-k7/kernel/fs/ntfs/ntfs.ko
這一行,就是加個#號,這個修改是即時生效的。
modinfo ntfs
modinfo: could not find module ntfs
modprobe ntfs
FATAL: Module ntfs not found.
重啟機器,執行同樣的命令會得到同樣的結果,說明開機不會自動執行 depmod 的,而
locate ntfs.ko
# 輸出:
# /lib/modules/2.6.18-4-k7/kernel/fs/ntfs/ntfs.ko
證明我們并沒有刪除ntfs模塊。
注意如果重啟機器之前進行mount還是可以的,重啟之后就會報錯了,而上邊的都是即時生效的。還有如果modules.dep里注釋掉了ntfs,那么在/etc/modules里寫上也是不起作用的,說明這個和mount一樣都是依賴 modprobe來完成加載模塊命令的。而insmod是可以的,因為insmod后面跟的是絕對路徑,它和modules.dep沒什么關系。 insmod比較重要的用途是用來測試模塊的正確性,加載一般都是依靠modprobe。(這個可能也不起作用了,都用modprobe吧)
這一切只是因為我們注釋掉了modules.dep中關于ntfs.ko的那一行,而模塊并沒有刪除或轉移。
modprobe
-
功能:Linux內核添加刪除模塊
-
用法:
modprobe [ -v ] [ -V ] [-C config-file] [ -n ] [ -i ] [ -q ] [ -o modulename] [ modulename ] [ module parameters … ]
modprobe [ -r ] [ -v ] [ -n ] [ -i ] [ modulename … ]
modprobe [ -l ] [ -t dirname ] [ wildcard ]
modprobe [ -c ]
-
描述:
modprobe可智能地添加和刪除Linux內核模塊(為簡便起見,模塊名中’_'和’-'是一樣的)。modprobe會查看模塊 目錄/lib/modules/’uname -r’里面的所有模塊和文件,除了可選的/etc/modprobe.conf配置文件和/etc/modprobe.d目錄外。
modprobe需要一個最新的modules.dep文件,可以用depmod來生成。該文件列出了每一個模塊需要的其他模塊,modprobe使用這個去自動添加或刪除模塊的依賴。
-
選項:
-v
–verbose 顯示程序在干什么,通常在出問題的情況下,modprobe才顯示信息。-C
–config 重載(意思取自C++的重載)默認配置文件(/etc/modprobe.conf或/etc/modprobe.d)。-c
–showconfig 輸出配置文件并退出-n
–dry-run 只打印,不做實際動作,可以和-v選項一起使用,調試非常有用-i
–ignore-install –ignore-remove 該選項會使得modprobe忽略配置文件中的,在命令行上輸入的install和remove命令。-q
–quiet 一般modprobe刪除或插入一個模塊時,若沒有找到會提示錯誤。使用該選項,會忽略指定的模塊,并不提示任何錯誤信息。-r
–remove 該選項會導致modprobe去刪除,而不是插入一個模塊。通常沒有沒有理由去刪除內核模塊,除非是一些有bug的模塊。你的內核也不一定支持模塊的卸載。-V
–verssion 版本信息-f
–force 和同時使用–force-vermagic ,–force-modversion一樣。使用該選項是比較危險的。-l
–list 列出所有模塊-a
–all 插入所有命令行中的模塊-t
–type 強制 -l 顯示dirname中的模塊-s
–syslog 錯誤信息寫入syslog
modinfo
-
功能:顯示內核模塊的信息
-
用法:
modinfo [ -0 ] [ -F field] [modulename | filename … ]
modinfo -V
modinfo -h
-
描述:
modinfo列出Linux內核中命令行指定的模塊的信息。若模塊名不是一個文件名,則會在/lib/modules/version 目錄中搜索,就像modprobe一樣。
modinfo默認情況下,為了便于閱讀,以下面的格式列出模塊的每個屬性:fieldname : value。
-
選項:
-V
–version 版本-F
–field 僅在一行上顯示field值,這對于腳本較為有用。常用的field有:author, description, licence, param, depends, alias, filename。-0
–NULL 使用’/0′字符分隔field值,而不是一個新行。對腳本比較有用。-a -d -l -p -n
這些分別是author, description, license, param ,filename的簡短形式。
insmod 和 rmmode
insmod
-
功能:向Linux內核中插入一個模塊
-
用法:insmod [filename] [modue options …]
-
描述:
insmod是一個向內核插入模塊的小程序:若文件名是一個連字符’-’,模塊從標準輸入輸入。大多數用戶使用modprobe,因為它比較智能化。
rmmod
-
功能:刪除內核中的一模塊
-
用法:rmmod [ -f ] [ -w ] [ -s ] [ -v ] [ modulename ]
-
描述:rmmod是一個可以從內核中刪除模塊的小程序,大多數用戶使用modprobe -r去刪除模塊。
-
選項:
-v
–verbose 顯示程序正在做些什么,一般只顯示執行時的錯誤信息。-f
–force 該選項是非常危險:除非編譯內核時,CONFIG_MODULE_FORCE_UNLOAD被設置該命令才有效果,否則沒效果。用該選項可以刪除正在被使用的模塊,設計為不能刪除的模塊,或者標記為unsafe的模塊。-w
–wait 通常,rmmod拒絕刪除正在被使用的模塊。使用該選項后,指定的模塊會被孤立起來,直到不被使用。-s
–syslog 將錯誤信息寫入syslog,而不是標準錯誤(stderr)。-V
–version 版本信息
modprobe與insmod、rmmode
-
加載某個模塊
modprobe xxx.ko
insmod xxx.ko
-
卸載某個模塊
modprobe -r xxx.ko
rmmod xxx.ko
insmod 與 modprobe 都是載入 kernel module,不過一般差別于 modprobe 能夠處理 module 載入的相依問題。
比方你要載入 a module,但是 a module 要求系統先載入 b module 時,直接用 insmod 掛入通常都會出現錯誤訊息,不過 modprobe 倒是能夠知道先載入 b module 后才載入 a module,如此相依性就會滿足。
不過 modprobe 并不是大神,不會厲害到知道 module 之間的相依性為何,該程式是讀取 /lib/modules/`uname -r`/modules.dep 檔案得知相依性的。而該檔案是透過 depmod 程式所建立。
ramdisk管理
ramdisk文件是在操作系統安裝完成之后,由特定的應用程序根據當前硬件設備信息,文件系統信息等量身定制而成;
ramdisk文件的制作工具
-
centos 5:
mkinitrd:建立要載入ramdisk的映像文件,以供Linux開機時載入ramdisk。
-
選項:
-f
:若指定的映像問家名稱與現有文件重復,則覆蓋現有的文件;-v
:執行時顯示詳細的信息;--omit-scsi-modules
:不要載入SCSI模塊;--preload=<模塊名稱>
:指定要載入的模塊;--with=<模塊名稱>
:指定要載入的模塊;--version
:顯示版本信息。 -
例子:
mkinitrd -v -f myinitrd.img $(uname -r)
-
-
centos 6/7
dracut:建立要載入ramdisk的映像文件,以供Linux開機時載入ramdisk。
例子:
dracut /boot/initramfs-$(uname -r).img $(uname -r)
Linux中重要的偽文件系統
/proc:procfs
Linux系統上的/proc
目錄是一種文件系統,即proc文件系統。與其它常見的文件系統不同的是,/proc
是一種偽文件系統(也即虛擬文件系統),存儲的是當前內核運行狀態的一系列特殊文件,用戶可以通過這些文件查看有關系統硬件及當前正在運行進程的信息,甚至可以通過更改其中某些文件來改變內核的運行狀態。
另外,/proc
是存儲在內存(RAM)中,而非硬盤中的,不占用外部存儲空間。
基于/proc
文件系統如上所述的特殊性,其內的文件也常被稱作虛擬文件,并具有一些獨特的特點。例如,其中有些文件雖然使用查看命令查看時會返回大量信息,但文件本身的大小卻會顯示為0字節。此外,這些特殊文件中大多數文件的時間及日期屬性通常為當前系統時間和日期,這跟它們隨時會被刷新(存儲于RAM中)有關。
為了查看及使用上的方便,這些文件通常會按照相關性進行分類存儲于不同的目錄甚至子目錄中,如/proc/scsi
目錄中存儲的就是當前系統上所有SCSI設備的相關信息,/proc/N
中存儲的則是系統當前正在運行的進程的相關信息,其中N
為正在運行的進程(可以想象得到,在某進程結束后其相關目錄則會消失)。
大多數虛擬文件可以使用文件查看命令如cat
、more
或者less
進行查看,注意\proc
中文件通常比較長,直接使用cat
命令來查看全部信息可讀性不佳。可以用more
和cat
命令,關于Linux中查看文件內容的命令,可參考博客:Linux查看文件內容命令:cat, tail, head, more, less。
\proc
中有些文件信息表述的內容可以一目了然,但大部分文件的信息卻不怎么具有可讀性。不過,這些可讀性較差的文件在使用一些命令如apm
、free
、lspci
或top
查看時卻可以有著不錯的表現。
可詳見博客:linux /proc 詳解。
內核狀態及統計信息的主要的輸出接口;同時還提供了一個能夠輸入配置信息,完成內核參數實時配置的接口——/proc/sys;
/proc/*
(除了sys目錄):信息輸出,只讀;/proc/sys
可讀寫,可以接受用戶指定的“新值”,來實現對內核相應功能或特性的實時配置;
procfs的查看和修改:
-
查看內核輸出的狀態信息或統計信息,直接使用cat命令即可;
-
修改或設置內核功能或特性,使用echo命令,借助于覆蓋輸出重定向進行修改或設置即可;
echo "value" > /proc/sys/path/to/parameter
sysctl
查看內核參數以及配置/proc/sys中的諸多功能,還可以使用sysctl命令。
用于在內核運行時動態地修改內核的運行參數,可用的內核參數在目錄/proc/sys中。
-
查看內核參數
sysctl -a
:查看所有可以被修改的內核參數;sysctl variable
:查看指定內核參數的設定值; -
配置某個內核參數(功能或特性)的值
sysctl -w variable=value
,注意:此方法中,"="兩端不能寫空格字符; -
根據配置文件設置內存參數;重新讀取并加載配置文件中所有的設置參數并且使其生效;
sysctl -p
常用的幾個內核參數
-
net.ipv4.ip_forward
:Linux的核心轉發功能,路由功能;取值0,1 -
net.ipv4.icmp_echo_ignore_all
:忽略所有來源于外部主機的ping操作請求,取值0,1 -
vm.drcp_caches
:清理buffer和cache,釋放物理內存,取值:0,1,2 -
kernel.hostname
:當前生效的主機名 -
DDOS:dynamic deny of service,動態拒絕服務攻擊
-
DCHP:IP地址耗盡策略,發送大量隨機Mac地址DHCP discover消息
安全相關:DNS:ARP攻擊,ARP欺騙,網關欺騙,源IP地址欺騙,dead ping
/sys:sysfs
專門為用戶提供使用的偽文件系統,輸出內核識別出來的各硬件設備的相關屬性信息,也包括內核對硬件特性的可設定的信息;對于某些參數進行特定格式的修改,以調整或設定硬件的工作特性;
比如:
echo '- - -' > /sys/class/scsi_host/host2/scan
/etc/udev
udev是運行在用戶空間的進程;通過讀取/sys目錄下的硬件設備的信息,按需為各硬件設備創建設備文件; 專用工具:udevadmin,hotplug…
當內核已經被加載至內存中,假如操作系統被安裝到sda磁盤上,則內核需先標識出sda磁盤并而將其標記為設備(創建設備文件),而后才能掛載此設備;
為了能夠讓這樣的設備以后也能正常使用,內核通過內置的devtmpfs為每個內核所要使用的設備創建設備文件;而這樣的文件可以被當作文件系統掛載之后,從內核直接轉移到真正的rootfs中的dev目錄內的;對于操作系統啟動之后被新插入的設備,就必須要依靠udev來識別并創建設備文件了;
udev之所以能夠為設備創建設備文件,主要依賴于其事先定義好的規則;而這樣的規則一般保存在udev的規則配置文件中:
/etc/udev/runles.d
/usr/lib/udev/rules.d
Linux kernel 內核組成及編譯方式
內核設計流派
單內核設計,但是充分借鑒了微內核體系設計的優點,為內核引入了模塊化機制,內核高度模塊化;
內核被模塊化之后,一些最為基本最為重要的內容,被編譯到內核核心;而其他更多的功能則以模塊的方式來提供;而且支持動態裝載和卸載各內核模塊;
內核的組成部分
-
kernel:內核核心文件,一般為bzp_w_picpath,經過壓縮處理的鏡像文件;通常內核核心文件保存在/boot/目錄下,名稱為vmlinuz-version-release
-
kernel object(ko):內核對象,內核額外功能模塊,一般該類文件放置于/lib/modules/[version-release]
注意:內核模塊與內核核心,版本號必須嚴格匹配;
內核模塊其實就是內核源代碼的一部分,只是在編譯內核的過程中,由于其功能可能并非內核核心所必須,所以以模塊的方式被編譯;
在編譯內核時,內核的功能通常有如下幾種選擇方式:
-
[ ] kernel function:no,不選擇編譯此功能;
-
[M] kernel function:modules,將此功能編譯為內核模塊使用;此功能不占據內和空間,只占用磁盤空間;
-
[*] kernel function:yes,將此功能直接編譯進內核核心;
ramdisk:內核補充文件,輔助文件,對于內核核心來說,此文件非必須,是否使用此文件取決于內核能否直接驅動rootfs所在的存儲設備;
-
設備的驅動程序,SCSI設備的驅動
-
邏輯設備驅程序,lvm的驅動程序,軟raid驅動程序等;
文件系統;
cpio -i -F initramfs-2.6.32-573.el6.x86_64.img
簡化的rootfs
注意:一般來講,kernel核心文件和ramdisk文件必須具有完全相同的版本號;
編譯源代碼的前提條件
開發環境
-
開發工具:gcc,make,automake,qt,GTK,ncurese
-
程序包組:
“Development Tool”,“Server Platform Development”
“開發工具”,“服務器平臺開發”,ncurses-devel庫
-
頭文件:/usr/include/*.h
獲取目標主機上各硬件設備的相關信息;
- CPU
cat /proc/cpuinfo
lscpu
x86info -a
-
PCI設備
lspci[-v|-vv]
-
USB設備
lsubs[-v|-vv]
-
塊設備
lsblk
-
了解更多的硬件設備信息
hal-device
(centos6可用包名:hal-0.5.14-14.e16.x86_64)
獲取目標主機系統功能的相關選項
比如:目標主機需要使用哪種文件系統;
? 目標主機是否需要啟動安全防護機制;
? …
編譯安裝應用程序的一般步驟
./.configure arg1 [arg2...]
make
make install
加載內核驅動的通常流程
- 先將.ko文件拷貝到/lib/module/`uname -r`(內核版本號)/kernel/driver/…目錄下,根據具體用途的區別分為net、ide、scsi、usb、video、parport、md、block、ata等等。
- 運行depmod -a,更新模塊依賴項,主要是更新modules.dep文件
- 運行modprobe加載內核模塊
編譯安裝內核的一般步驟
步驟
-
需要準備或生成一個.config的文件,該文件記錄了內核的編譯細節:
-
哪些功能直接編譯進內核;
-
哪些功能編譯成內核模塊;
-
哪些功能在此次編譯中不啟用;
make menuconfig | xconfig | config
-
-
開始編譯內核
make module-install
多線程編譯,可以將編譯進程在 nnn 個CPU核心上并行進行;
-
安裝模塊文件
make module-install
-
安裝內核核心文件,并生成grub的啟動菜單
make install
安裝的是bziage文件,安裝到 /boot/vmlinuz-version-release
生成與內核版本完全匹配的initramfs文件
編輯grub的配置文件,生成啟動菜單項;
Screen:一款由GNU計劃開發的用于命令行終端切換的自由軟件
簡單用法:
-
screen(開啟screen)
-
Ctrl +a;d(拆除screen)
-
screen -ls(列表顯示screen)
-
screen -r screen_ID(恢復連接至指定的screen)
-
exit(關閉screen)
內核的配置選項
-
64-bit kernel: 是否支持64位內核
-
general setup —>通用配置項:
() local version - append to kernel release:自定義本地版本號,附加到內核版本號后面的信息,由編譯者定義;
((none)) default hostname:定義當沒有設置主機名時的默認主機名;
-
enable loadable module support: 是否支持內核模塊的動態裝卸載;
-
enable the block layer:是否支持啟用塊層,通常是選擇支持;
-
processor type and features:處理器類型和特性
-
processor family (generic-x86-64) --> (core 2/newer Xeon):選擇處理器類型
-
power management and acpi options:電源管理及高級電源管理接口選項
-
executable file formats / emulations:指定可執行文件的格式,默認為ELF,以#!開頭的文件也具備可執行特性;
-
networking support:內核中的網絡協議棧
-
networking options:[ ] ipv6 support
-
device drivers:設備驅動程序
-
file system:dos/fat/nt file systems,[M] NTFS support
-
kernel hacking:內核調試的相關內容
-
security options,NAS selinux support:安全選項
-
cryptographic API:加密解密的應用程序變口
-
virtualization:虛擬化相關
配置內核的方式
-
make config:基于單行命令以遍歷內核所有功能的方式進行內核配置,因此每個內核選項的配置都是交互式的;
-
make menuconfig:基于curses的文本模式的配置窗口;
-
make gconfig:基于gtk開發環境的窗口配置界面;一般情況下,只要安裝了“桌面平臺開發”程序包組就可以了;
-
make xconfig:基于QT開發環境的窗口配置界面;一般情況下,只要安裝了“桌面平臺開發”程序包組就可以了;
-
make defconfig:基于內核為目標平臺提供默認配置模板進行配置;
-
make allnoconfig:所有的功能全部不編譯(全部選no)的配置方式;
-
make allyesconfig:所有的功能全部編譯進核心(全部選yes)的配置方式;
內核的編譯方式
-
全編譯:
make [-jn]
-
部分編譯:
a.只編譯某個子目錄中的相關源代碼;
cd /user/src/linux make [-jn] dir_name/
b.只編譯特定的模塊
cd /usr/src/linux make [dir/]file.ko
示例:
cd /usr/src/linux make drivers/net/ethernet/intel/e1000/e1000.ko
-
交叉編譯:編譯的目標平臺與當前編譯的平臺不相同;
make arch=arch_name
示例:
make arch=arm
內核重新編譯
-
將所有 /usr/src/inux-version 目錄的內容直接刪除,重新從源代碼包釋放;隨后可以重復之前的步驟重新編譯即可;
-
先清理之前的編譯接口
a. 清理大多數的編譯生成的文件,但是會保留.config文件
make clean
b. 清理所有編譯生成的文件,包括.config以及其他的備份文件
make mrproper
c. 相當于make mrproper,但是還會額外清理各種patches以及編譯器自身的備份文件;
make distclean
編譯安裝內核實例
~]# tar xf linux-3.10.99.tar.xz -C /usr/src~]# cd /usr/srcsrc]# ln -sv linux-3.10.99 linuxsrc]# cd /usr/src/linuxlinux]# cp /boot/config-$(uname -r) ./.configlinux]# make menuconfiglinux]# make -j 4linux]# make modules_installlinux]# make installlinux]# reboot
重啟之后在grub菜單中選擇新編譯的內核來啟動,如果可以看到登錄提示符,則說明內核編譯升級成功!
然后可以嘗試編譯其他與當前操作系統版本不同的其他更高級版本的內核,多試幾個版本,了解一下各個不同版本的內核的特性;
Ref
https://blog.51cto.com/u_12486569/1952181
https://www.cnblogs.com/jacklikedogs/p/4659249.html
https://forum.ubuntu.org.cn/viewtopic.php?t=469088