Linux 内核编译
内核编译介绍
通常只有在以下情况下才需要重新编译内核:
- 新功能需求:需要的新功能只有在新内核中才能使用,为了获得这些功能,必须重新编译内核;
- 内核过于臃肿:如果内核中包含很多不需要的功能,可以重新编译内核并去除这些功能;
- 更换硬件驱动:如果当前内核编译的驱动导致系统不稳定,可以替换为稳定版的驱动;
- 其他需求:对于特殊硬件系统,可能需要自行设计内核。
内核及内核模块的路径如下:
- 内核:/boot/vmlinuz
- 虚拟文件系统(RAM Disk):/boot/initramfs
- 内核模块:/lib/modules/version/kernel
- 内核源代码:/usr/src/linux
在 CentOS 上,可以在以下网站下载原始 SRPM:http://vault.centos.org/
Linux 官方内核源码可以在以下网站下载:https://www.kernel.org/
保持源码干净
下载内核并解压:
[root@234c8 ~]$ wget ftp://ftp.twaren.net/pub/Unix/Kernel/linux/kernel/v3.x/linux-3.10.89.tar.xz
[root@234c8 ~]$ tar -Jxvf linux-3.10.89.tar.xz -C /usr/src/kernels/
为了确保内核源代码干净,没有保留目标文件(*.o
)及相关配置,可以使用make mrproper
来处理:
[root@234c8 linux-3.10.89]$ make mrproper
一般只有第一次执行内核编译前采用这一命令,其他时候用make clean
就可以。
挑选内核功能
在/boot
目录下存在config-*
的内核功能列表文件,可以通过多个方法创建:
make menuconfig
:最常用的方法,在命令行模式下进行配置。make oldconfig
:通过已存在的./.config
文件内容设置默认值,只将新版内核内功能列出来供选择。make xconfig
:通过 KDE 图形界面来设置。make gconfig
:通过 GNOME 图形界面来设置。make config
:过去的设置方式。
下面以make menuconfig
为例进行操作:
[root@234c8 linux-3.10.89]$ cp /boot/config-3.10.0-1160.41.1.el7.x86_64 .config
[root@234c8 linux-3.10.89]$ make menuconfig
.config - Linux/x86 3.10.89 Kernel Configuration
----------------------------------------------------------------------------------------
+--------------------- Linux/x86 3.10.89 Kernel Configuration -----------------------+
| Arrow keys navigate the menu. <Enter> selects submenus -- letters are hotkeys. |
| Pressing <Y> includes, <N> excludes, <M> modu. Press <Esc><Esc> to exit, <?> for |
| Help, </> for Search. Legend: [*] built-in [ ] excluded <M> module < > mod |
| |
| +--------------------------------------------------------------------------------+ |
| | [*] 64-bit kernel | |
| | General setup ---> | |
| | [*] Enable loadable module support ---> | |
| | -*- Enable the block layer ---> | |
| | Processor type and features ---> | |
| | Power management and ACPI options ---> | |
| | Bus options (PCI etc.) ---> | |
| | Executable file formats / Emulations ---> | |
| | -*- Networking support ---> | |
| | Device Drivers ---> | |
| | Firmware Drivers ---> | |
| | File systems ---> | |
| | Kernel hacking ---> | |
| +-------------↓(+)---------------------------------------------------------------+ |
+------------------------------------------------------------------------------------+
| <Select> < Exit > < Help > < Save > < Load > |
+------------------------------------------------------------------------------------+
关于整个内核功能选择,一般来说,要选择必需的功能编译进内核,可能需要的功能编译成模块,不清楚的功能则保持默认。功能选择好后,选择Save
退出。
内核编译
在编译内核之前,需要清除无用文件,然后分别编译内核和模块。使用 -j
参数指定编译时使用的线程数:
[root@234c8 linux-3.10.89]$ make clean
[root@234c8 linux-3.10.89]$ make -j 16 bzImage
BUILD arch/x86/boot/bzImage
Setup is 16704 bytes (padded to 16896 bytes).
System is 4674 kB
CRC e48489cb
Kernel: arch/x86/boot/bzImage is ready (#1)
[root@234c8 linux-3.10.89]$ make -j 16 modules
IHEX2FW firmware/whiteheat_loader.fw
IHEX2FW firmware/keyspan_pda/keyspan_pda.fw
IHEX2FW firmware/keyspan_pda/xircom_pgs.fw
[root@234c8 linux-3.10.89]$ make -j 16 clean bzImage modules
LD drivers/scsi/scsi_mod.o
LD [M] drivers/scsi/scsi_tgt.o
LD drivers/scsi/built-in.o
LD drivers/built-in.o
编译完成后,文件应该存放在当前目录下。
安装模块
如果模块有修改,可以在内核功能选择的 General setup 中的 Local version 中修改成新的名称。安装模块:
[root@234c8 linux-3.10.89]$ make modules_install
安装内核
在无法确认新内核是否工作情况下,保留旧内核:
[root@234c8 linux-3.10.89]$ cp arch/x86/boot/bzImage /boot/vmliunz-3.10.89m
[root@234c8 linux-3.10.89]$ cp .config /boot/config-3.10.89m
[root@234c8 linux-3.10.89]$ chmod a+x /boot/vmlinuz-3.10.89m
[root@234c8 linux-3.10.89]$ cp System.map /boot/System.map-3.10.89m
[root@234c8 linux-3.10.89]$ gzip -c Module.symvers > /boot/symvers-3.10.89m.gz
[root@234c8 linux-3.10.89]$ restorecon -Rv /boot
[root@234c8 linux-3.10.89]$ dracut -v /oot/initramfs-3.10.89m.img 3.10.89m
接着使用grub2-mkconfig
来处理grub2
开机菜单:
[root@234c8 linux-3.10.89]$ grub2-mkconfig -o /boot/grub2/grub.cfg
之后就可以重启测试新内核了。
内核模块依赖
在内核模块目录中通常分为以下几个子目录:
- arch:与硬件平台有关的项目,如 CPU 的等级。
- crypto:内核所支持的加密技术,例如 MD5、DES 等。
- drivers:一些硬件的驱动程序,如网卡、显卡驱动等。
- fs:内核支持的文件系统,如 VFAT、NFS 等。
- lib:一些函数库。
- net:与网络有关的各项协定数据,包括防火墙。
- sound:与声音有关的模块。
内核模块之间的依赖性检查通过 /lib/modules/version/modules.dep
来记录,可以使用 depmod
命令来加入已编译好的模块。例如要加入名为 tp-413.ko
网卡驱动到内核模块:
[root@101c7 ~]$ cp tp-413.ko /lib/modules/3.10.0-1160.41.1.el7.x86_64/kernel/drivers/net/
[root@101c7 ~]$ depmod
执行 depmod
命令后,程序会跑到内核模块目录,将全部模块分析一遍,将结果写入到 modules.dep
文件中。
内核模块查询
要查询内核以及加载的模块列表,可以使用 lsmod
命令:
[root@101c7 ~]$ lsmod
Module Size Used by
nf_conntrack_ftp 18478 0
nf_conntrack 139264 1 nf_conntrack_ftp
snd_seq_midi 13565 0
snd_seq_midi_event 14597 1 snd_seq_midi
结果会分别显示出模块名称,模块大小和模块被其他模块使用(Used by)的信息。
如果想要查询模块具体信息,可以使用 modinfo
命令。例如查询 nf_conntrack_ftp
模块:
[root@101c7 ~]$ modinfo nf_conntrack_ftp
filename: /lib/modules/3.10.0-1160.41.1.el7.x86_64/kernel/net/netfilter/nf_conntrack_ftp.ko.xz
alias: nfct-helper-ftp
alias: ip_conntrack_ftp
description: ftp connection tracking helper
author: Rusty Russell <rusty@rustcorp.com.au>
license: GPL
retpoline: Y
rhelversion: 7.9
srcversion: F21861D5AD43080B93CC4DD
depends: nf_conntrack
intree: Y
vermagic: 3.10.0-1160.41.1.el7.x86_64 SMP mod_unload modversions
signer: CentOS Linux kernel signing key
sig_key: 4B:E3:B8:E9:52:F4:81:B2:62:51:AC:E4:66:9B:A7:99:71:D1:F1:AF
sig_hashalgo: sha256
parm: ports:array of ushort
parm: loose:bool
上面查询可以得到模块的文件位置、依赖的模块,还有模块的参数(parm
)。
内核模块加载与删除
除了上面使用到的modprobe
命令,还可以使用insmod
来安装模块。例如载入fat
模块:
[root@101c7 ~]$ insmod /lib/modules/3.10.0-1160.41.1.el7.x86_64/kernel/fs/fat/fat.ko.xz
[root@101c7 ~]$ lsmod | grep fat
fat 65950 0
使用insmod
命令必须接模块完整路径来安装,并且不会去分析模块的依赖性。
想要移除模块使用rmmod
命令,例如移除fat
模块:
[root@101c7 ~]$ rmmod fat
[root@101c7 ~]$ insmod /lib/modules/3.10.0-1160.41.1.el7.x86_64/kernel/fs/fat/vfat.ko.xz
insmod: ERROR: could not insert module /lib/modules/3.10.0-1160.41.1.el7.x86_64/kernel/fs/fat/vfat.ko.xz: Unknown symbol in module
不过这样有个坏处就是需要手动处理依赖问题,比如上面fat
模块被移除后,无法用insmod
命令来载入vfat
模块。
最稳妥的方式还是使用modprobe
来处理。-f
参数可以强制载入模块,-r
参数用来移除模块:
[root@101c7 ~]$ modprobe vfat
[root@101c7 ~]$ lsmod | grep vfat
vfat 17461 0
fat 65950 1 vfat
[root@101c7 ~]$ modprobe -r vfat
如果想让模块开机自动载入,例如要加入启动一个nf_conntrack_frp
模块,可以在目录下新建一个 conf 文件:
[root@101c7 initrams]$ vi /etc/modules-load.d/ftp.conf
nf_conntrack_ftp
"/etc/modules-load.d/ftp.conf" [New] 1L, 17C written
一个模块(驱动)写一行,上面模块是针对默认 FTP 端口设置。如果要调整到 558 端口,可以在modprobe.d
目录下面新建配置:
[root@101c7 initrams]$ vi /etc/modprobe.d/ftp.conf
options nf_conntrack_ftp ports=558
"/etc/modprobe.d/ftp.conf" [New] 1L, 35C written
系统重启后就能顺利载入模块了。也可以通过重启systemd-modules-load
服务来即刻生效:
[root@101c7 initrams]$ systemctl restart systemd-modules-load
[root@101c7 initrams]$ lsmod | grep nf_conntrack_ftp
nf_conntrack_ftp 18478 0
nf_conntrack 139264 1 nf_conntrack_ftp