linux内核与内核模块


内核与内核模块

回到顶部

谈完了整个开机的流程,您应该会知道,在整个开机的过程当中,是否能够成功的驱动我们主机的硬 件配备, 是内核 (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 的介绍。 我们这个章节仅是说明一下, 如果想要加载一个已经存在的模块时,该如何是好?

内核模块与相依性

回到顶部

既然要处理内核模块,自然就得要了解了解我们内核提供的模块之间的相关性啦! 基本上,内核模 块的放置处是在 /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 这个指令就可以达到建立该文件的需求了!

              [root@initroot ~]# depmod [-Ane]
            
选项与参数:
-A :不加任何参数时, depmod 会主动的去分析目前内核的模块,并且重新写入
/lib/modules/$(uname -r)/modules.dep 当中。若加入 -A 参数时,则 depmod 会去搜寻比 modules.dep 内还要新的模块,如果真找到新模块,才会更新。
-n :不写入 modules.dep ,而是将结果输出到屏幕上(standard out);
-e :显示出目前已加载的不可执行的模块名称
范例一:若我做好一个网卡驱动程序,档名为 a.ko,该如何更新内核相依性?
              [root@initroot ~]# cp a.ko /lib/modules/$(uname -r)/kernel/drivers/net
              [root@initroot ~]# depmod
            
以上面的范例一为例,我们的 kernel 内核模块扩展名一定是 .ko 结尾的, 当你使用 depmod 之后, 该程序会跑到模块标准放置目录 /lib/modules/$(uname -r)/kernel , 并依据相关目录的定义将全部的 模块捉出来分析,最终才将分析的结果写入 modules.dep 文件中的吶! 这个文件很重要喔!因为他 会影响到本章稍后会介绍的 modprobe 指令的应用!

内核模块的观察

回到顶部

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

              [root@initroot ~]# lsmod
              Module
              Size
              nf_conntrack_ftp
              nf_conntrack
              18638
              105702
              Used by
              0
              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 这个模块,该模块也同时使用了好多额外的附属模块喔!

lsmod列出内核中已安装的模块信息

LSMOD(8) lsmod LSMOD(8) NAME
lsmod - Show the status of modules in the Linux Kernel
SYNOPSIS
lsmod
DESCRIPTION
lsmod is a trivial program which nicely formats the contents of the /proc/modules, showing what kernel modules are currently loaded.
COPYRIGHT
This manual page originally Copyright 2002, Rusty Russell, IBM Corporation. Maintained by Jon Masters and others.
SEE ALSO
insmod(8), modprobe(8), modinfo(8)
AUTHORS
Jon Masters Developer
Lucas De Marchi Developer kmod 11/12/2018
LSMOD(8) Manual page lsmod(8) line 1/25 (END) (press h for help or q to quit)

那么,那个 drm 是 啥鬼?要如何了解呢?就用 modinfo 吧!
              [root@initroot ~]# modinfo [-adln] [module_name|filename]
            
选项与参数:
-a :仅列出作者名称; -d :仅列出该 modules 的说明 (description); -l :仅列出授权 (license); -n :仅列出该模块的详细路径。
范例一:由上个表格当中,请列出 drm 这个模块的相关信息:
              [root@initroot ~]# 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 ,请问该模块的信息为?
              [root@initroot ~]# modinfo a.ko
              ....(省略)....
            
事实上,这个 modinfo 除了可以『查阅在内核内的模块』之外,还可以检查『某个模块文件』, 因 此,如果你想要知道某个文件代表的意义为何,利用 modinfo 加上完整檔名吧!看看就晓得是啥玩 意儿啰! ^_^

内核模块的加载与移除

回到顶部

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

              [root@initroot ~]# insmod [/full/path/module_name] [parameters]
            
范例一:请尝试载入 cifs.ko 这个『文件系统』模块
              [root@initroot ~]# insmod /lib/modules/$(uname -r)/kernel/fs/fat/fat.ko
              [root@initroot ~]# lsmod | grep fat
              fat
              65913
              0
            
insmod 立刻就将该模块加载啰~但是 insmod 后面接的模块必须要是完整的『档名』才行!那如何 移除这个模块呢?

insmod命令用来安装模块

Usage:
insmod [options] filename [args]
Options:
-V, --version show version
-h, --help show this help

              [root@initroot ~]# rmmod [-fw] module_name
            
选项与参数:
-f :强制将该模块移除掉,不论是否正被使用;
范例一:将刚刚加载的 fat 模块移除!
              [root@initroot ~]# rmmod fat
            
范例二:请加载 vfat 这个『文件系统』模块
              [root@initroot ~]# 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 来处理模块加载的问题,这个指令的用法是:
              [root@initroot ~]# modprobe [-cfr] module_name
            
选项与参数:
-c :列出目前系统所有的模块!(更详细的代号对应表) -f :强制加载该模块; -r :类似 rmmod ,就是移除某个模块啰~
范例一:加载 vfat 模块
              [root@initroot ~]# modprobe vfat
            
# 很方便吧!不需要知道完整的模块文件名,这是因为该完整文件名已经记录到
# /lib/modules/`uname -r`/modules.dep 当中的缘故啊!如果要移除的话:
              [root@initroot ~]# modprobe -r vfat
            
使用 modprobe 真的是要比 insmod 方便很多!因为他是直接去搜寻 modules.dep 的纪录, 所以啰, 当然可以克服模块的相依性问题,而且还不需要知道该模块的详细路径呢!好方便! ^_^
例题:尝试使用 modprobe 加载 cifs 这个模块,并且观察该模块的相关模块是哪个?
答:
我们使用 modprobe 来加载,再以 lsmod 来观察与 grep 撷取关键词看看:
              [root@initroot ~]# modprobe cifs
              [root@initroot ~]# lsmod | grep cifs
              cifs
              456500
              dns_resolver
              13140
              0
              1 cifs
            
#竟然还有使用到 dns_resolver 哩!
              [root@initroot ~]# modprobe -r cifs #测试完移除此模块
            
19.2.4 内核模块的额外参数设定:/etc/modprobe.d/*conf
如果有某些特殊的需求导致你必须要让内核模块加上某些参数时,请回到 19.1.7 小节瞧一瞧! 应该 会有启发喔!重点就是要自己建立扩展名为 .conf 的文件,透过 options 来带入内核模块参数啰!

initroot编辑整理,转载请注明www.initroot.com

100次点赞 100次阅读