19.2 核心与核心模块

谈完了整个开机的流程,您应该会知道,在整个开机的过程当中,是否能够成功的驱动我们主机的硬件配备, 是核心 (kernel) 的工作!而核心一般都是压缩文件,因此在使用核心之前,就得要将他解压缩后,才能载入内存当中。

另外,为了应付日新月异的硬件,目前的核心都是具有“可读取模块化驱动程序”的功能, 亦即是所谓的“ modules (模块化)”的功能啦!所谓的模块化可以将他想成是一个“外挂程序”, 该外挂程序可能由硬件开发厂商提供,也有可能我们的核心本来就支持~不过,较新的硬件, 通常都需要硬件开发商提供驱动程序模块啦!

那么核心与核心模块放在哪?

  • 核心: /boot/vmlinuz 或 /boot/vmlinuz-version;
  • 核心解压缩所需 RAM Disk: /boot/initramfs (/boot/initramfs-version);
  • 核心模块: /lib/modules/version/kernel 或 /lib/modules/$(uname -r)/kernel;
  • 核心源代码: /usr/src/linux 或 /usr/src/kernels/ (要安装才会有,默认不安装)

如果该核心被顺利的载入系统当中了,那么就会有几个信息纪录下来:

  • 核心版本: /proc/version
  • 系统核心功能: /proc/sys/kernel/

问题来啦,如果我有个新的硬件,偏偏我的操作系统不支持,该怎么办?很简单啊!

  • 重新编译核心,并加入最新的硬件驱动程序源代码;
  • 将该硬件的驱动程序编译成为模块,在开机时载入该模块

上面第一点还很好理解,反正就是重新编译核心就是了。不过,核心编译很不容易啊! 我们会在后续章节约略介绍核心编译的整个程序。比较有趣的则是将该硬件的驱动程序编译成为模块啦! 关于编译的方法,可以参考后续的 第二十一章、软件安装:源代码与 Tarball 的介绍。 我们这个章节仅是说明一下,如果想要载入一个已经存在的模块时,该如何是好?

19.2.1 核心模块与相依性

既然要处理核心模块,自然就得要了解了解我们核心提供的模块之间的相关性啦! 基本上,核心模块的放置处是在 /lib/modules/$(uname -r)/kernel 当中,里面主要还分成几个目录:

arch    :与硬件平台有关的项目,例如 CPU 的等级等等;
crypto    :核心所支持的加密的技术,例如 md5 或者是 des 等等;
drivers    :一些硬件的驱动程序,例如显卡、网卡、PCI 相关硬件等等;
fs    :核心所支持的 filesystems ,例如 vfat, reiserfs, nfs 等等;
lib    :一些函数库;
net    :与网络有关的各项协定数据,还有防火墙模块 (net/ipv4/netfilter/*) 等等;
sound    :与音效有关的各项模块;

如果要我们一个一个的去检查这些模块的主要信息,然后定义出他们的相依性, 我们可能会疯掉吧!所以说,我们的 Linux 当然会提供一些模块相依性的解决方案啰~ 对啦!那就是检查 /lib/modules/$(uname -r)/modules.dep 这个文件啦!他记录了在核心支持的模块的各项相依性。

那么这个文件如何创建呢?挺简单!利用 depmod 这个指令就可以达到创建该文件的需求了!

[[email protected] ~]# depmod [-Ane]
选项与参数:
-A  :不加任何参数时, depmod 会主动的去分析目前核心的模块,并且重新写入
      /lib/modules/$(uname -r)/modules.dep 当中。若加入 -A 参数时,则 depmod
      会去搜寻比 modules.dep 内还要新的模块,如果真找到新模块,才会更新。
-n  :不写入 modules.dep ,而是将结果输出到屏幕上(standard out);
-e  :显示出目前已载入的不可执行的模块名称
范例一:若我做好一个网卡驱动程序,文件名为 a.ko,该如何更新核心相依性?
[[email protected] ~]# cp a.ko /lib/modules/$(uname -r)/kernel/drivers/net
[[email protected] ~]# depmod

以上面的范例一为例,我们的 kernel 核心模块扩展名一定是 .ko 结尾的, 当你使用 depmod 之后,该程序会跑到模块标准放置目录 /lib/modules/$(uname -r)/kernel , 并依据相关目录的定义将全部的模块捉出来分析,最终才将分析的结果写入 modules.dep 文件中的呐! 这个文件很重要喔!因为他会影响到本章稍后会介绍的 modprobe 指令的应用!

19.2.2 核心模块的观察

那你到底晓不晓得目前核心载入了多少的模块呢?粉简单啦!利用 lsmod 即可!

[[email protected] ~]# lsmod
Module                  Size  Used by
nf_conntrack_ftp       18638  0
nf_conntrack          105702  1 nf_conntrack_ftp
....(中间省略)....
qxl                    73766  1
drm_kms_helper         98226  1 qxl
ttm                    93488  1 qxl
drm                   311588  4 qxl,ttm,drm_kms_helper  # drm 还被 qxl, ttm..等模块使用
....(下面省略)....

使用 lsmod 之后,系统会显示出目前已经存在于核心当中的模块,显示的内容包括有:

  • 模块名称(Module);
  • 模块的大小(size);
  • 此模块是否被其他模块所使用 (Used by)。

也就是说,模块其实真的有相依性喔!举上表为例,nf_conntrack 先被载入后,nf_conntrack_ftp这个模块才能够进一步的载入系统中! 这两者间是有相依性的。包括鸟哥测试机使用的是虚拟机,用到的显卡是 qxl 这个模块,该模块也同时使用了好多额外的附属模块喔! 那么,那个 drm 是啥鬼?要如何了解呢?就用 modinfo 吧!

[[email protected] ~]# modinfo [-adln] [module_name|filename]
选项与参数:
-a  :仅列出作者名称;
-d  :仅列出该 modules 的说明 (description);
-l  :仅列出授权 (license);
-n  :仅列出该模块的详细路径。
范例一:由上个表格当中,请列出 drm 这个模块的相关信息:
[[email protected] ~]# modinfo drm
filename:       /lib/modules/3.10.0-229.el7.x86_64/kernel/drivers/gpu/drm/drm.ko
license:        GPL and additional rights
description:    DRM shared core routines
author:         Gareth Hughes, Leif Delgass, José Fonseca, Jon Smirl
rhelversion:    7.1
srcversion:     66683E37FDD905C9FFD7931
depends:        i2c-core
intree:         Y
vermagic:       3.10.0-229.el7.x86_64 SMP mod_unload modversions
signer:         CentOS Linux kernel signing key
sig_key:        A6:2A:0E:1D:6A:6E:48:4E:9B:FD:73:68:AF:34:08:10:48:E5:35:E5
sig_hashalgo:   sha256
parm:           edid_fixup:Minimum number of valid EDID header Bytes (0-8, default 6) (int)
.....(下面省略).....
# 可以看到这个模块的来源,以及该模块的简易说明!
范例二:我有一个模块名称为 a.ko ,请问该模块的信息为?
[[email protected] ~]# modinfo a.ko
....(省略)....

事实上,这个 modinfo 除了可以“查阅在核心内的模块”之外,还可以检查“某个模块文件”, 因此,如果你想要知道某个文件代表的意义为何,利用 modinfo 加上完整文件名吧!看看就晓得是啥玩意儿啰! ^_^

19.2.3 核心模块的载入与移除

好了,如果我想要自行手动载入模块,又该如何是好?有很多方法啦,最简单而且建议的,是使用 modprobe 这个指令来载入模块, 这是因为 modprobe 会主动的去搜寻 modules.dep 的内容,先克服了模块的相依性后, 才决定需要载入的模块有哪些,很方便。至于 insmod 则完全由使用者自行载入一个完整文件名的模块, 并不会主动的分析模块相依性啊!

[[email protected] ~]# insmod [/full/path/module_name] [parameters]
范例一:请尝试载入 cifs.ko 这个“文件系统”模块
[[email protected] ~]# insmod /lib/modules/$(uname -r)/kernel/fs/fat/fat.ko
[[email protected] ~]# lsmod | grep fat
fat                    65913  0

insmod 立刻就将该模块载入啰~但是 insmod 后面接的模块必须要是完整的“文件名”才行!那如何移除这个模块呢?

[[email protected] ~]# rmmod [-fw] module_name
选项与参数:
-f  :强制将该模块移除掉,不论是否正被使用;
范例一:将刚刚载入的 fat 模块移除!
[[email protected] ~]# rmmod fat
范例二:请载入 vfat 这个“文件系统”模块
[[email protected] ~]# insmod /lib/modules/$(uname -r)/kernel/fs/vfat/vfat.ko
insmod: ERROR: could not load module /lib/modules/3.10.0-229.el7.x86_64/kernel/fs/vfat/
 vfat.ko: No such file or directory
# 无法载入 vfat 这个模块啊!伤脑筋!

使用 insmod 与 rmmod 的问题就是,你必须要自行找到模块的完整文件名才行,而且如同上述范例二的结果, 万一模块有相依属性的问题时,你将无法直接载入或移除该模块呢!所以近年来我们都建议直接使用 modprobe 来处理模块载入的问题,这个指令的用法是:

[[email protected] ~]# modprobe [-cfr] module_name
选项与参数:
-c  :列出目前系统所有的模块!(更详细的代号对应表)
-f  :强制载入该模块;
-r  :类似 rmmod ,就是移除某个模块啰~
范例一:载入 vfat 模块
[[email protected] ~]# modprobe vfat
# 很方便吧!不需要知道完整的模块文件名,这是因为该完整文件名已经记录到
# /lib/modules/`uname -r`/modules.dep 当中的缘故啊!如果要移除的话:
[[email protected] ~]# modprobe -r vfat

使用 modprobe 真的是要比 insmod 方便很多!因为他是直接去搜寻 modules.dep 的纪录, 所以啰,当然可以克服模块的相依性问题,而且还不需要知道该模块的详细路径呢!好方便! ^_^

例题:尝试使用 modprobe 载入 cifs 这个模块,并且观察该模块的相关模块是哪个?答:我们使用 modprobe 来载入,再以 lsmod 来观察与 grep 撷取关键字看看:

[[email protected] ~]# modprobe cifs
[[email protected] ~]# lsmod | grep cifs
cifs                  456500  0
dns_resolver           13140  1 cifs   <==竟然还有使用到 dns_resolver 哩!
[[email protected] ~]# modprobe -r cifs <==测试完移除此模块

19.2.4 核心模块的额外参数设置:/etc/modprobe.d/*conf

如果有某些特殊的需求导致你必须要让核心模块加上某些参数时,请回到19.1.7小节瞧一瞧! 应该会有启发喔!重点就是要自己创建扩展名为 .conf 的文件,通过 options 来带入核心模块参数啰!

下一节:在看完了前面的整个开机流程,以及核心模块的整理之后,你应该会发现到一件事情,那就是“ boot loader 是载入核心的重要工具”啊!没有 boot loader 的话,那么 kernel 根本就没有办法被系统载入的呢!所以,下面我们会先谈一谈 boot loader 的功能,然后再讲一讲现阶段 Linux 里头最主流的 grub2 这个 boot loader 吧!

另外,你也得要知道,目前新版的 CentOS 7.x 已经将沿用多年的 grub 换成了 grub2 了!这个 grub2 版本在设置与安装上面跟之前的 grub 有点不那么相同, 所以,在后续的章节中,得要了解一下新的 grub2 的设置方式才行喔!如果你是新接触者,那没关系~直接看就 OK 了!