运行时内核管理
本节讨论初级管理(LPIC-1)102 考试的主题 1.105.1 的内容。这个主题的权值是 4。
在本节中,学习如何:
使用命令行工具获得关于当前运行的内核和内核模块的信息
手工装载和卸载内核模块
判断何时可以卸载模块
配置系统以便按照文件名之外的名称来装载模块
从技术上说,Linux 是系统的内核。内核为应用程序运行和使用各种硬件设备提供了一个框架。它是处理硬件接口、调度和内存管理等任务的低层代码。许多人把整个系统称为 GNU/Linux,因为大多数发行版中的许多工具来自 Free Software Foundation 的 GNU 项目。但是,常常简称为 “Linux” 而不是 “GNU/Linux”。
uname
uname 命令输出关于系统及其内核的信息。清单 1 显示 uname 的各种选项以及产生的信息;表 3 中定义了这些选项。
清单 1. uname 命令
ian@pinguino:~$ uname
Linux
ian@pinguino:~$ uname -s
Linux
ian@pinguino:~$ uname -n
pinguino
ian@pinguino:~$ uname -r
2.6.12-10-386
ian@pinguino:~$ uname -v
#1 Mon Jan 16 17:18:08 UTC 2006
ian@pinguino:~$ uname -m
i686
ian@pinguino:~$ uname -o
GNU/Linux
ian@pinguino:~$ uname -a
Linux pinguino 2.6.12-10-386 #1 Mon Jan 16 17:18:08 UTC 2006 i686 GNU/Linux
表 3. uname 的选项 选项 描述
-s 输出内核名。如果没有指定选项,这是默认选项。
-n 输出节点名或主机名。
-r 输出内核的发布版本。这个选项常常与模块处理命令一起使用。
-v 输出内核的版本。
-m 输出机器的硬件(CPU)名。
-o 输出操作系统名。
-a 输出以上所有信息。
清单 1 来自在 Intel® CPU 上运行的 Ubuntu 系统。uname 命令在大多数 UNIX® 和类 UNIX 系统以及 Linux 上都是可用的。根据 Linux 发行版和版本的不同,以及运行的机器类型的不同,显示的信息是不同的。清单 2 显示的输出来自运行 Fedora Core 4 的 AMD Athlon 64 系统和 Apple PowerBook。
清单 2. 对另一个系统使用 uname
Linux attic4 2.6.14-1.1656_FC4 #1 Thu Jan 5 22:13:55 EST 2006 x86_64
x86_64 x86_64 GNU/Linuxfilesystem
Darwin Ian-Shields-Computer.local 7.9.0 Darwin Kernel Version 7.9.0:
Wed Mar 30 20:11:17 PST 2005; root:xnu/xnu-517.12.7.obj~1/RELEASE_PPC
Power Macintosh powerpc
内核模块
内核管理着系统的许多低层功能,包括硬件和接口。由于存在许多不同的硬件和几种不同的文件系统,所以支持所有功能的内核会非常大。幸运的是,内核模块(kernel modules) 使我们能够在需要时装载支持软件,比如硬件驱动程序或文件系统,所以可以用一个小内核启动系统,然后根据需要装载其他模块。装载常常是自动的,比如在插入 USB 设备时自动装载相关的驱动程序。
本节的剩余部分讨论用于内核模块的命令和配置。
用于装载和卸载模块这样的任务的命令需要根特权。显示关于模块的信息的命令常常可以由一般用户运行。但是,因为这些命令在 /sbin 中,常常不在非根用户的路径中,所以如果您是非根用户,那么可能必须使用完整路径名。
lsmod
使用 lsmod 命令显示系统上当前装载的模块,如清单 3 所示。您的输出可能不一样,但是应该会看到一些共同的条目。
清单 3. 用 lsmod 显示内核模块
[ian@attic4 ~]$ /sbin/lsmod
Module Size Used by
nvnet 74148 0
nvidia 4092336 12
forcedeth 24129 0
md5 4161 1
ipv6 268737 12
parport_pc 29189 1
lp 13129 0
parport 40969 2 parport_pc,lp
autofs4 29637 1
sunrpc 168453 1
ipt_REJECT 5825 1
ipt_state 1985 3
ip_conntrack 42009 1 ipt_state
iptable_filter 3137 1
ip_tables 19521 3 ipt_REJECT,ipt_state,iptable_filter
dm_mod 58613 0
video 16069 0
button 4161 0
battery 9541 0
ac 4933 0
ohci_hcd 26977 0
ehci_hcd 41165 0
i2c_nforce2 7105 0
i2c_core 21825 1 i2c_nforce2
shpchp 94661 0
snd_intel8x0 34945 1
snd_ac97_codec 76217 1 snd_intel8x0
snd_seq_dummy 3781 0
snd_seq_oss 37569 0
snd_seq_midi_event 9409 1 snd_seq_oss
snd_seq 62801 5 snd_seq_dummy,snd_seq_oss,snd_seq_midi_event
snd_seq_device 9037 3 snd_seq_dummy,snd_seq_oss,snd_seq
snd_pcm_oss 51569 0
snd_mixer_oss 18113 1 snd_pcm_oss
snd_pcm 100553 3 snd_intel8x0,snd_ac97_codec,snd_pcm_oss
snd_timer 33733 2 snd_seq,snd_pcm
snd 57669 11 snd_intel8x0,snd_ac97_codec,snd_seq_oss,snd_seq,
snd_seq_device,snd_pcm_oss,snd_mixer_oss,snd_pcm,snd_timer
soundcore 11169 1 snd
snd_page_alloc 9925 2 snd_intel8x0,snd_pcm
floppy 65397 0
ext3 132681 3
jbd 86233 1 ext3
sata_nv 9541 0
libata 47301 1 sata_nv
sd_mod 20545 0
scsi_mod 147977 2 libata,sd_mod
[ian@attic4 ~]$
可以看到这个系统装载了许多模块。其中大多数是内核提供的。但是,有一些模块(比如来自 NVIDIA Corporation 的 nvnet、nvidia 和 sata_nv 模块)包含专有代码,不是作为标准内核的一部分提供的。按照这种模块化的方式,可以将专有代码插入开放源码的内核。如果厂商的许可证允许的话,Linux 发行商可以将专有模块添加到发行版中,这样您就不必直接从厂商那里获得这些模块,并可以确保具有适当的模块版本。
在清单 3 中,还可以看到对显卡、SATA 和 SCSI 硬盘驱动器、软驱和声卡等设备的模块化支持扩展,以及用于连网特性(比如 IPV6)、文件系统支持(比如 ext3)和 Sun 远程过程调用(RPC)的模块。
除了模块名之外,lsmod 还显示模块的大小和用户数量。如果一个模块由其他模块使用,那么会列出这些模块。例如,soundcore 模块由 snd 模块使用,后者又由其他几个声音模块使用。
modinfo
modinfo 命令显示关于一个或多个模块的信息。如清单 4 所示,这些信息包括文件的完整路径、作者、许可证、模块可能接受的任何参数、版本、依赖项和其他信息。
清单 4. 基本模块信息
[ian@attic4 ~]$ /sbin/modinfo floppy
filename: /lib/modules/2.6.12-1.1456_FC4/kernel/drivers/block/floppy.ko
author: Alain L. Knaff
license: GPL
alias: block-major-2-*
vermagic: 2.6.12-1.1456_FC4 686 REGPARM 4KSTACKS gcc-4.0
depends:
srcversion: 2633BC999A0747D8D215F1F
parm: FLOPPY_DMA:int
parm: FLOPPY_IRQ:int
parm: floppy:charp
[ian@attic4 ~]$ /sbin/modinfo sata_nv
filename: /lib/modules/2.6.12-1.1456_FC4/kernel/drivers/scsi/sata_nv.ko
author: NVIDIA
description: low-level driver for NVIDIA nForce SATA controller
license: GPL
version: 0.6
vermagic: 2.6.12-1.1456_FC4 686 REGPARM 4KSTACKS gcc-4.0
depends: libata
alias: pci:v000010DEd0000008Esv*sd*bc*sc*i*
alias: pci:v000010DEd000000E3sv*sd*bc*sc*i*
alias: pci:v000010DEd000000EEsv*sd*bc*sc*i*
alias: pci:v000010DEd00000054sv*sd*bc*sc*i*
alias: pci:v000010DEd00000055sv*sd*bc*sc*i*
alias: pci:v000010DEd00000036sv*sd*bc*sc*i*
alias: pci:v000010DEd0000003Esv*sd*bc*sc*i*
alias: pci:v000010DEd*sv*sd*bc01sc01i*
srcversion: 3094AD48C1B869BCC301E9F
在清单 4 中,注意在给出模块文件名的行中,这些文件名以 .ko 后缀结束。这将 2.6 内核的模块与其他目标文件和 2.4 及以前版本的内核模块区分开(在 2.4 及以前版本的内核中,内核模块与其他目标文件都使用 .o 后缀)。
还会注意到模块路径包括内核版本。例如,/lib/modules/2.6.12-1.1456_FC4/kernel/drivers/block/floppy.ko 包括 2.6.12-1.1456_FC4 作为路径元素。这个值与 uname -r 显示的值相同。内核模块是与给定的内核相关的,这种结构管理这种关系。
在 2.6 内核上,还可以使用 modinfo 来限制查询的模块信息范围。使用 -F 选项提取单一类型的信息,比如参数、描述、许可证、文件名或别名。如果需要不同类型的信息,那么可以用不同选项多次执行这个命令。在 2.4 内核上,用 -p 这样的参数提取参数信息。当前的 modinfo 命令也支持老式的参数。清单 5 给出一些例子。
清单 5. 特定的模块信息
[ian@attic4 ~]$ /sbin/modinfo -F parm snd
cards_limit:Count of auto-loadable soundcards.
major:Major # for sound driver.
[ian@attic4 ~]$ /sbin/modinfo -F license nvidia floppy
NVIDIA
GPL
[ian@attic4 ~]$ /sbin/modinfo -p snd
major:Major # for sound driver.
cards_limit:Count of auto-loadable soundcards.
使用您的 Linux 技能
可以使用教程 “LPI 101 考试准备(主题 103):GNU 和 UNIX 命令” 中讨论的一些技术来提取信息,比如模块接受的参数数量。清单 6 给出一个例子。
清单 6. 每个模块的参数数量
[ian@attic4 ~]$ for n in `/sbin/lsmod | tail +2 | cut -d " " -f1`;
> do echo "$n $(/sbin/modinfo -p $n |wc -l )" | grep -v " 0$"; done
nvnet 12
forcedeth 1
parport_pc 5
dm_mod 1
ohci_hcd 2
ehci_hcd 2
shpchp 3
snd_intel8x0 7
snd_ac97_codec 1
snd_seq_dummy 2
snd_seq_oss 2
snd_seq 7
snd_pcm_oss 3
snd_pcm 2
snd_timer 1
snd 2
snd_page_alloc 1
scsi_mod 6
rmmod
如果模块的使用计数是 0,那么可以安全地删除它。例如,在准备装载模块的更新版本时可能要进行删除操作。这是一种出色的模块化内核特性,因为在对特定设备的支持进行更新时,不一定需要重新引导系统。要删除模块,使用 rmmod 命令以及模块名,如清单 7 所示。
清单 7. 删除正在运行的系统上的模块
[root@attic4 ~]# rmmod floppy
关于 rmmod 的其他选项,请参考手册页。
insmod 和 modprobe
删除了模块之后,可能需要重新装载它。这可以使用 insmod 命令,这个命令接受要装载的模块的完整路径名以及可能需要的任何模块选项。如果使用这个命令,可能希望使用命令替换来生成文件名。可以采用的两种方式见清单 8。
清单 8. 使用 insmod 装载模块
[root@attic4 ~]# insmod /lib/modules/`uname -r`/kernel/drivers/block/floppy.ko
[root@attic4 ~]# rmmod floppy
[root@attic4 ~]# insmod $(modinfo -F filename floppy)
上面的第二种形式使我们不必记住模块所在的子目录(这个例子中的 drivers/block),但是还有更好的装载模块的方法。modprobe 命令提供一个高级接口,它操作模块名而不是文件路径。它还会装载模块所依赖的其他模块,并可以装载和删除模块。
清单 9 演示如何使用 modprobe 删除 vfat 模块以及使用它的 fat 模块。然后,它显示如果重新装载了模块,系统会做什么,最后显示重新装载模块的结果。注意,指定 -v 选项可以获得详细输出;否则,modprobe(和底层的 insmod 命令)只显示来自模块本身的错误消息。在每一步之间,lsmod 通过管道连接到 grep,从而显示 vfat 或 fat 模块是否装载了。
清单 9. 使用 modprobe 装载模块
[root@lyrebird root]# modprobe -r vfat
vfat: Device or resource busy
[root@lyrebird root]# lsmod | grep fat
vfat 13132 1
fat 38744 0 [vfat]
[root@lyrebird root]# umount /windows/D
[root@lyrebird root]# modprobe -r vfat
[root@lyrebird root]# modprobe -v --show vfat
/sbin/insmod /lib/modules/2.4.21-37.0.1.EL/kernel/fs/fat/fat.o
/sbin/insmod /lib/modules/2.4.21-37.0.1.EL/kernel/fs/vfat/vfat.o
[root@lyrebird root]# lsmod | grep fat
[root@lyrebird root]# modprobe -v vfat
/sbin/insmod /lib/modules/2.4.21-37.0.1.EL/kernel/fs/fat/fat.o
Using /lib/modules/2.4.21-37.0.1.EL/kernel/fs/fat/fat.o
Symbol version prefix ''
/sbin/insmod /lib/modules/2.4.21-37.0.1.EL/kernel/fs/vfat/vfat.o
Using /lib/modules/2.4.21-37.0.1.EL/kernel/fs/vfat/vfat.o
[root@lyrebird root]# lsmod | grep fat
vfat 13132 0 (unused)
fat 38744 0 [vfat]
depmod
您刚才看到,在一些模块依赖于其他模块时,modprobe 可以处理多个模块的自动装载。这些依赖关系记录在适当内核的 /lib/modules 子目录中的 modules.dep 文件中(内核版本号由 uname -r 命令给出)。这个文件以及几个映射文件是由 depmod 命令生成的。-a(表示 all)现在是可选的。
depmod 命令扫描当前内核的 /lib/modules 子目录中的模块并更新依赖信息。清单 10 给出一个例子以及这个操作修改的文件。
清单 10. 使用 depmod 重新构建 modules.dep
[root@lyrebird root]# date
Thu Mar 16 10:41:05 EST 2006
[root@lyrebird root]# depmod
[root@lyrebird root]# cd /lib/modules/`uname -r`
[root@lyrebird 2.4.21-37.0.1.EL]# ls -l mod*
-rw-rw-r-- 1 root root 54194 Mar 16 10:41 modules.dep
-rw-rw-r-- 1 root root 31 Mar 16 10:41 modules.generic_string
-rw-rw-r-- 1 root root 73 Mar 16 10:41 modules.ieee1394map
-rw-rw-r-- 1 root root 1614 Mar 16 10:41 modules.isapnpmap
-rw-rw-r-- 1 root root 29 Mar 16 10:41 modules.parportmap
-rw-rw-r-- 1 root root 65171 Mar 16 10:41 modules.pcimap
-rw-rw-r-- 1 root root 24 Mar 16 10:41 modules.pnpbiosmap
-rw-rw-r-- 1 root root 122953 Mar 16 10:41 modules.usbmap
[root@lyrebird 2.4.21-37.0.1.EL]# cd -
/root
可以使用配置文件 /etc/modules.conf 定制 modprobe 和 depmod 的行为。这常常用来为模块名指定别名和指定在装载模块之后或卸载模块之前应该运行的命令。但是,还可以进行许多其他配置。清单 11 给出一个 /etc/modules.conf 示例。更多细节请参考 modules.conf 的手册页。
清单 11. /etc/modules 文件示例
[root@lyrebird root]# cat /etc/modules.conf
alias eth0 e100
alias usb-controller usb-uhci
alias usb-controller1 ehci-hcd
alias sound-slot-0 i810_audio
post-install sound-slot-0 /bin/aumix-minimal -f /etc/.aumixrc -L >/dev/null 2>&1 || :
pre-remove sound-slot-0 /bin/aumix-minimal -f /etc/.aumixrc -S >/dev/null 2>&1 || :
您还应该知道,某些系统使用另一个配置文件 modprobe.conf,而其他系统将模块配置信息存储在 /etc/modules.d 目录中。在某些系统上还可以发现称为 /etc/modules 的文件;这个文件包含应该在引导时装载的内核模块的名称。
USB 模块
在将 USB 设备热插入 Linux 系统时,内核必须判断要装载哪些模块来处理这个设备。这常常由一个热插入脚本来完成,这个脚本使用 usbmodules 命令来寻找适当的模块。也可以自己运行 usbmodules(作为根用户)。清单 12 给出一个例子。
清单 12. USB 模块
root@pinguino:~# lsusb
Bus 005 Device 004: ID 1058:0401 Western Digital Technologies, Inc.
Bus 005 Device 003: ID 054c:0220 Sony Corp.
Bus 005 Device 001: ID 0000:0000
Bus 004 Device 001: ID 0000:0000
Bus 003 Device 001: ID 0000:0000
Bus 002 Device 001: ID 0000:0000
Bus 001 Device 003: ID 04b3:310b IBM Corp. Red Wheel Mouse
Bus 001 Device 001: ID 0000:0000
root@pinguino:~# usbmodules --device /proc/bus/usb/005/003
usb-storage
root@pinguino:~# usbmodules --device /proc/bus/usb/001/003
usbmouse
usbhid
下一节讲解如何构建和配置定制的内核。