Linux 模块管理

列出系统中所有的模块:

# lsmod

那么存放模块文件的目录在哪儿?

根目录的文件系统是xfs,那么在系统中一定存在xfs 相关的模块:

RH442 - 性能调优学习笔记(三)_模块管理

左边是模块的名字,然后模块的大小,模块使用的次数,模块的描述信息。

如果有两个xfs 文件系统的挂载,那么这个模块使用的次数应为2,如果你想知道这个模块的详细信息:

# modinfo xfs

RH442 - 性能调优学习笔记(三)_模块管理_02

注意:模块必须匹配当前的内核版本,如果在一个内核版本中编译了模块,然后你又更换了一个内核,那么这个模块是无法使用的。

# cd /lib/modules
# ls

RH442 - 性能调优学习笔记(三)_模块管理_03

这里有两个内核。

# uname -r

RH442 - 性能调优学习笔记(三)_模块管理_04

这个文件夹下一定也有xfs 相关的模块:

RH442 - 性能调优学习笔记(三)_模块管理_05

RH442 - 性能调优学习笔记(三)_模块管理_06

下面这个目录是所有驱动相关的模块:

RH442 - 性能调优学习笔记(三)_模块管理_07

在Linux 中,很多机制都是由内核模块提供的,例如:驱动程序、防火墙、seLinux 安全机制等。

modinfo st

RH442 - 性能调优学习笔记(三)_模块管理_08

这是一个磁带机的驱动模块信息,最下方有6 行参数,这里的参数是可以对其进行调优的。

再举个例子:

modinfo e1000

RH442 - 性能调优学习笔记(三)_模块管理_09

这是一个因特尔e1000 网卡的驱动模块,下面也有很多可调优的参数,比如:速率、双工模式、流控、发送延迟等等...

先来看一下RHEL 5 的模块调优方式:

在RHEL 5 的系统中,有这样一个文件

vim /etc/modprobe.conf

RH442 - 性能调优学习笔记(三)_模块管理_10

系统的网卡eth 0 这个名字是怎么来的呢?其实就是由这个文件定义的,该文件第一行的e1000 是模块的名字,eth0 是模块的别名。如果你想把eth0 改成别的名字,就改这个文件的第一行,把eth0 换成别的名字,然后修改这个网卡的配置:

cd /etc/sysconfig/network-scripts/

RH442 - 性能调优学习笔记(三)_模块管理_11

把这个文件名改掉,再编辑这个文件里面的内容,把网卡名改掉就可以了。

RH442 - 性能调优学习笔记(三)_模块管理_12

RH442 - 性能调优学习笔记(三)_模块管理_13

options 后面的snd-card 是模块的名称,index=0 是调优参数,而remove 那一行指定的是:当你移除这个模块的时候,会自动执行后面的指令。

从RHEL 6 开始,网卡的名称是由udev 规则来定义的,不再使用模块的别名。

modprobe st

这条命令是用来加载模块,lsmod 列出加载到内存中的模块:

RH442 - 性能调优学习笔记(三)_模块管理_14

如果你想卸载这个模块:

modprobe -r st

RH442 - 性能调优学习笔记(三)_模块管理_15

不过,不是所有的模块都可以卸载:

RH442 - 性能调优学习笔记(三)_模块管理_16

因为这个模块正在被使用。

一般卸载模块不需要人工操作,除非有一些特殊场景:模块是动态加载的,当系统检测到新设备时,会自动加载模块到内存中,如果当一个设备被卸载时,系统会自动检测,并10 分钟后自动卸载该模块。

比如,系统中有这样一个模块,我们手动把它加载上来:

modprobe usb_storage

RH442 - 性能调优学习笔记(三)_模块管理_17

系统识别到新设备并检测到是usb 存储设备时,会动态把它加载上来,当拔出该设备时,一段时间后,系统会自动卸载这个模块。

当模块加载到内存以后,比如st 这个模块,进入到这个目录,可以查看到对应的文件夹:

cd /sys/bus/scsi/drivers/

RH442 - 性能调优学习笔记(三)_模块管理_18

当卸载这个模块后,这个文件夹也就不存在了。

这个文件夹下面就有很多参数:

RH442 - 性能调优学习笔记(三)_模块管理_19

之前modinfo st 查看的内容,里面的调优参数就可以在这个文件夹下面找到与之对应的文件:

RH442 - 性能调优学习笔记(三)_模块管理_20

以buffer_kbs 为例,这个参数的意思是默认给磁带机分配多少的缓存空间,默认是32KB

RH442 - 性能调优学习笔记(三)_模块管理_21

这里的单位是Byte

如果我想把缓存调整为128KB,这样设置是行不通的:

RH442 - 性能调优学习笔记(三)_模块管理_22

这就与我们之前对/proc/sys 目录的调优方法不一样了,在/proc/sys 目录里面是可以echo 参数值写入到文件的,然后写/etc/sysctl.conf 文件使其开机自动生效,但在/sys 目录就不行了。

应该这么操作,在下面这个目录里面写一个配置文件:

cd /etc/modprobe.d/

模仿已有的配置文件来写,格式大概是:

options 模块名 参数

结尾必须是.conf

那么,我们也可以写一个这样的文件,名称无所谓,就叫st 好了:

vim st.conf

RH442 - 性能调优学习笔记(三)_模块管理_23

卸载该模块重新加载:

modprobe -r st
modprobe st

这样加载模块的时候就会把刚刚写的配置文件读一遍,参数生效。

RH442 - 性能调优学习笔记(三)_模块管理_24

至于该模块在开机的时候会不会被自动加载, 取决于系统有没有识别到这个硬件,如果你想要系统无论有没有识别到这个硬件都要加载这个模块,那么可以这样做:

cd /etc/sysconfig/modules/

写一个文件放在这里,比如说:

vim st.modules

RH442 - 性能调优学习笔记(三)_模块管理_25

chmod u+x st.modules

这样,开机的时候就一定会加载这个模块了。

下面是一个模块管理的案例:

RH442 - 性能调优学习笔记(三)_模块管理_26

这个报错,如果你没有学过模块管理,一定排查不出来, 如果学过,也不一定能够排查出来。

案例场景:客户购买了一批戴尔的服务器,大概100多台,安装了RHEL 5.4 OS,系统正常使用,但客户的研发环境内核采用的是2.6.27,RHEL 5.4 内核是2.6.18,客户要求使用2.6.27 版本,那就使用源码包升级内核,怎么升级呢?Linux 内核有官方网站:https://kernel.org,把这个源码包下载下来,编译安装,升级成功。

RH442 - 性能调优学习笔记(三)_模块管理_27

这样做,系统启动的时候就会有两个启动菜单,使用2.6.27 内核启动系统,就出现了前面那张图的故障。

RH442 - 性能调优学习笔记(三)_模块管理_28

从标记位置的报错信息来看,大概能判断出是RAID 卡的驱动找不到了,RHEL 5.4 是一个商业版本,它可能编译安装了很多第三方的驱动模块,由于2.6.27 版本的内核是从官方下载的,所以它很可能有很多的驱动没有提供。

那么如果考虑把2.6.18 内核里面的驱动拷贝到2.6.27 版本里面来,这是行不通的,因为内核模块需要匹配内核版本,如果需要升级内核版本,模块是需要重新编译的。

基于此案例背景,当事人在自己的电脑本地安装了虚拟机,也是RHEL 5.4,并且在虚拟机中升级内核到2.6.27,可以正常启动。这说明上图这个报错与内核版本没有关系,但为什么在虚拟机中可以正常启动呢?因为虚拟机的硬盘并不依赖于这个RAID 卡驱动。

这不像系统识别不到网卡那么简单,而是整个系统都进不去了,后面的解决方法就要求你要对系统启动的原理有一定的了解:

  1. BIOS自检 选择引导设备
  2. 读取硬盘的启动扇区,MBR 引导程序 GRUB2 基础驱动
  3. 引导程序读取配置文件/boot/grub2/grub.cfg
  4. 加载内核,并且以只读方式加载根
  5. 加载RAM DISK 文件 内存磁盘文件

第5步的文件实质上是一个cpio 的压缩包,里面存放的是系统启动时加载根所需要的驱动,引导程序包含了一些基础驱动可以读取到/boot 分区里面的文件,读取RAM DISK 文件在内存中解压后,系统在启动时就可以在内存中读到该驱动:

cd /boot
mkdir /data
cp initramfs-4.18.0-80.el8.x86_64.img /data

下面是解压这个文件的方法:

/usr/lib/dracut/skipcpio initramfs-4.18.0-80.el8.x86_64.img | zcat | cpio -id

RH442 - 性能调优学习笔记(三)_模块管理_29

解压出来以后,可以看到里面的目录结构,它其实就是一个Linux 系统,在它的 lib/modules 目录下,存放的都是加载根所需要的驱动:

RH442 - 性能调优学习笔记(三)_模块管理_30

 现在面临的问题是:没有RAID 卡所需要的驱动。所以我们把这个RAID 卡所需要的驱动封装到这个文件里面就可以了。

RAID 卡驱动需要通过源码包编译,源码包在哪里下载呢?

这就需要查看该服务器的RAID 卡型号,当事人发现它是LSI2008

进入LSI 的官网,查找该型号的RAID 卡驱动,下载编译即可。

下面以一个英特尔的网卡驱动为例:

下载后上传到服务器,解压,查看README 文件,里面有说明怎样安装这个驱动,按照方法一步步操作:

yum -y install make kernel-devel gcc elfutils-libelf-devel
make install

编译完成以后,如果要手动加载使用它:

RH442 - 性能调优学习笔记(三)_模块管理_31

这个案例是编译网卡,只是举例说明而已,正常情况下,如果没有网卡驱动,不会影响系统启动,可以在系统启动后,再编译安装即可。

但RAID 卡不同,如果没有该驱动,会导致系统无法启动,编译方法跟网卡类似。

现在问题是如何将 RAID 卡驱动封装到initramfs 文件中去?

RH442 - 性能调优学习笔记(三)_模块管理_32

刚刚解压的initramfs 文件里面竟然自带了ice 网卡驱动,那么换一个驱动模块来演示,就用st 模块,这样操作:

mkinitrd --with=st /boot/initramfs-4.18.0-80.el8.x86_64.img 4.18.0-80.el8.x86_64 --force

这条命令的意思是:从/lib/modules/4.18.0-80.el8.x86_64 (mkinitrd 命令会自动在前面补上/lib/modules/前缀)这个目录找到st 模块,封装到/boot/initramfs-4.18.0-80.el8.x86_64.img 这个文件里面,--force表示强制执行,如果文件已存在则覆盖。

RH442 - 性能调优学习笔记(三)_模块管理_33

在工作中,这条命令一般会这么用:

mkinitrd --with=st /boot/initramfs-$(uname -r) $(uname -r) --force

现在验证一下封装结果:

RH442 - 性能调优学习笔记(三)_模块管理_34

封装成功了。


再来一个更常见的案例:

场景:

将物理机迁移到虚拟化平台中去 P2V

将虚拟机迁移上云

迁移完成后,发现系统无法正常启动。为什么?如何解决?

  1. tools 不对,如果原来是VMware 平台虚拟机迁移到华为云中,先卸载VMware Tools,再进行迁移
  2. 驱动不对,如果是物理机或者VMware 平台,安装的是物理的驱动,后来迁移到云上,云上用的驱动跟物理机肯定不同,导致系统无法正常启动。

所以,在云主机上,进入/boot 目录,把initramfs 文件都删除,然后根据这台主机的硬件信息重新封装:

cd /boot
rm -rf initramfs-*
mkinitrd /boot/initramfs-$(uname -r).img $(uname -r)

以上命令可以进入救援模式执行,救援模式用的是通用驱动,这个驱动是由ISO 文件中的initrd 提供。

RH442 - 性能调优学习笔记(三)_模块管理_35


持续更新中...