Linux 内核碎碎念

在《Linux 内核简介》中我们介绍了 Linux 内核的一些特性: 单内核ramdisk 以及 模块化。下面分别从 内核信息获取内核模块加卸载ramdisk 文件管理 以及 /proc/sys 目录来具体说说对 Linux 内核部分功能的管理和操作。

Linux 的核心虽然是 单内核 ,但是它借鉴了 微内核 的设计,为内核引入了模块化机制。所以 Linux 内核其实是分为两部分组成: 内核核心kernel )和 内核对象kernel object )。其中 内核对象 也就是 内核模块 。内核模块与内核核心版本一定要严格匹配。

内核编译初步》里面粘贴过一张内核配置图:

内核配置

其中选项前面的 * 就意味着该功能编译进内核核心, M 意味着将该功能编译进内核模块,很多功能都可以自由选择。

编译进内核核心的功能可以在内核加载时直接启动,编译进内核模块的功能需要加载模块后启动,但是这个时间差,几乎可以忽略不计。而且将功能编译进内核模块还有个好处,就是可以动态装载和卸载,当某功能模块需要重新加载或者升级时,无需重新编译内核,只需要重新编译此模块的源码,然后手动装载即可。

内核信息获取

内核信息获取最常用的方式是使用 uname 命令:

1
2
3
4
5
6
7
[hzz@magedu ~]$ uname -a
Linux magedu 2.6.39-magedu-hzz #2 SMP Tue Oct 31 19:53:34 CST 2017 x86_64 x86_64 x86_64 GNU/Linux
[hzz@magedu ~]$ uname -r
2.6.39-magedu-hzz
[hzz@magedu ~]$ uname -n
magedu
[hzz@magedu ~]$

也可以到 /boot 目录去查看内核文件来获取内核版本号:

1
2
3
4
[hzz@magedu ~]$ ls /boot/ |grep vmlinuz-
vmlinuz-2.6.32-431.el6.x86_64
vmlinuz-2.6.39-magedu-hzz
[hzz@magedu ~]$

模块信息获取和管理

内核模块一般存在于 /lib/modules/VERSION-release/ 下面,比如:

1
2
3
4
5
[hzz@magedu ~]$ ls /lib/modules/2.6.39-magedu-hzz/
build modules.alias.bin modules.dep modules.inputmap modules.order modules.symbols source
kernel modules.builtin modules.dep.bin modules.isapnpmap modules.pcimap modules.symbols.bin
modules.alias modules.ccwmap modules.ieee1394map modules.ofmap modules.seriomap modules.usbmap
[hzz@magedu ~]$

但是我们一般不会手动管理,而是通过工具去查看和加卸载。

模块查看

lsmod

Show the status of modules in the Linux Kernel.

顾名思义,列出并查看模块信息,没有参数,直接执行即可。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
[hzz@magedu ~]$ lsmod
Module Size Used by
ipt_REJECT 2472 2
nf_conntrack_ipv4 9136 2
nf_defrag_ipv4 1505 1 nf_conntrack_ipv4
iptable_filter 1746 1
ip_tables 20183 1 iptable_filter
ip6t_REJECT 4534 2
nf_conntrack_ipv6 8271 2
nf_defrag_ipv6 10359 1 nf_conntrack_ipv6
xt_state 1354 4
nf_conntrack 79401 3 nf_conntrack_ipv4,nf_conntrack_ipv6,xt_state
ip6table_filter 1719 1
ip6_tables 20441 1 ip6table_filter
ipv6 328832 77 ip6t_REJECT,nf_conntrack_ipv6,nf_defrag_ipv6
...
[hzz@magedu ~]$

modinfo

Show information about a Linux Kernel module.

modinfo 是查看模块详细信息的命令,一般是配合 lsmod 找出模块名称后,再进行详细信息查看。

1
2
3
4
5
6
7
8
9
[hzz@magedu ~]$ modinfo ext4
filename: /lib/modules/2.6.39-magedu-hzz/kernel/fs/ext4/ext4.ko
license: GPL
description: Fourth Extended Filesystem
author: Remy Card, Stephen Tweedie, Andrew Morton, Andreas Dilger, Theodore Ts'o and others
srcversion: 2995D9485257598B39ECC37
depends: mbcache,jbd2
vermagic: 2.6.39-magedu-hzz SMP mod_unload modversions
[hzz@magedu ~]$

模块的加载和卸载

modprobe

Add and remove modules from the Linux Kernel.

内核模块装载和卸载工具。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
# 卸载内核模块

[hzz@magedu ~]$ lsmod|grep dm_mirror
dm_mirror 14348 0
dm_region_hash 10907 1 dm_mirror
dm_log 9798 2 dm_mirror,dm_region_hash
dm_mod 75833 11 dm_mirror,dm_log
[hzz@magedu ~]$ sudo modprobe -r dm_mirror
[hzz@magedu ~]$ lsmod|grep dm_mirror
[hzz@magedu ~]$

# 装载内核模块

[hzz@magedu ~]$ sudo modprobe dm_mirror
[hzz@magedu ~]$ lsmod|grep dm_mirror
dm_mirror 14348 0
dm_region_hash 10907 1 dm_mirror
dm_log 9798 2 dm_mirror,dm_region_hash
dm_mod 75833 11 dm_mirror,dm_log
[hzz@magedu ~]$

insmod 和 rmmod

insmod is a trivial program to insert a module into the kernel. Most users will want to use modprobe(8) instead, which is more clever and can handle module dependencies.

装卸载内核模块的另一组命令,但是需要手动关联和装载依赖模块。和 modprobe 的区别就跟 rpmyum 的区别类似,建议使用 modprobe 对模块进行管理。

depmod

Generate modules.dep and map files.

内核模块依赖关系文件的生成工具,不常用,在此先不做介绍。

ramdisk 文件管理

ramdisk 是一个辅助文件,不是必须的,取决于内核是否能直接驱动系统所在的硬盘设备。

ramdisk 是一个简装版的根文件系统,用于在内存中展开,加载速度很快。

ramdisk 存在于 /boot 下面:

1
2
3
4
[hzz@magedu ~]$ ls /boot/|grep initramfs
initramfs-2.6.32-431.el6.x86_64.img
initramfs-2.6.39-magedu-hzz.img
[hzz@magedu ~]$

如果不小心将 ramdisk 文件删掉了,该怎么办呢?

mkinitrd

mkinitrd - is a compat wrapper, which calls dracut to generate an initramfs.

通过调用 dracut 来创建 ramdisk 的命令。

比如,为当前使用中的内核重新制作 ramdisk 文件:

1
2
3
4
5
6
7
8
9
10
11
12
# 删除当前内核的 ramdisk 以便试验
[hzz@magedu ~]$ sudo rm -f /boot/initramfs-$(uname -r).img
[hzz@magedu ~]$ ls /boot/|grep initramfs
initramfs-2.6.32-431.el6.x86_64.img
[hzz@magedu ~]$

# 重新创建 ramdisk 文件
[hzz@magedu ~]$ sudo mkinitrd /boot/initramfs-$(uname -r).img $(uname -r)
[hzz@magedu ~]$ ls /boot/|grep initramfs
initramfs-2.6.32-431.el6.x86_64.img
initramfs-2.6.39-magedu-hzz.img
[hzz@magedu ~]$

mkinitrd 还有两个参数比较常用:

1
2
--with=<module> # 除了默认的模块之外需要装载至 initramfs 中的模块;
--preload=<module> # initramfs 所提供的模块需要预先装载的模块;

dracut

low-level tool for generating an initramfs image.

一个比较底层的 ramdisk 文件创建工具, mkinitrd 也是通过调用这个命令来创建 ramdisk 文件的,所以使用方式上类似。建议使用 mkinitrd 来操作。

1
dracut /boot/initramfs-$(uname -r).img $(uname -r)

内核信息输出的伪文件系统

/proc

内核状态和统计信息的输出接口,从这里面的文件可以看到系统运行时的各种状态以及配置信息(比如 cpuinfo 和 vmstat )。虽然都是文件,但其实是个输出接口,让其他程序可以从此处读取系统状态,故称为 伪文件系统 。里面的文件大都只读,也就是只能看,即使改了也没有任何意义,除了 sys 文件夹。

/proc/sys

/proc/sys 目录是内核功能特性配置的文件夹,可通过编辑里面的文件来实现临时更改内核某个功能的特性,比如释放缓存的操作为 echo 1 > /proc/sys/vm/drop_caches ,但是直接用文件系统命令或者重定向的方式来直接更改 /proc/sys 里面的文件,只能是在当前运行的内核中有效,内核重启后失效。若需要将配置永久生效,有两种方式可实现。

sysctl 命令

专用于查看或设定 /proc/sys 目录下参数的值。

可以使用 -a 参数查看所有参数的值,也可以指定参数查看。比如我们想查看 /proc/sys/net/ipv4.icmp_echo_ignore_all 的值:

1
2
3
[hzz@magedu vm]$ sysctl net.ipv4.icmp_echo_ignore_all
net.ipv4.icmp_echo_ignore_all = 0
[hzz@magedu vm]$

可以看到, /proc/sys/net/ipv4.icmp_echo_ignore_all 其实就是 net.ipv4.icmp_echo_ignore_all 的虚拟文件路径,改动 net.ipv4.icmp_echo_ignore_all 才能让配置永久生效。

使用 -w 选项,即可改变内核功能配置。比如我们要实现主机禁 ping ,可以使用以下命令:

1
2
3
4
5
[hzz@magedu ~]$ sudo sysctl -w net.ipv4.icmp_echo_ignore_all=1
net.ipv4.icmp_echo_ignore_all = 1
[hzz@magedu ~]$

# 注意赋值时等号左右不要有空格

修改配置文件

修改 /etc/sysctl.conf/etc/sysctl.d/*.conf 配置文件,也可以实现重启内核后保留自定义内核配置。这个很容易理解,直接在文件中添加参数和值即可:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
[hzz@magedu ~]$ more /etc/sysctl.conf
# Kernel sysctl configuration file for Red Hat Linux
#
# For binary values, 0 is disabled, 1 is enabled. See sysctl(8) and
# sysctl.conf(5) for more details.

# Controls IP packet forwarding
net.ipv4.ip_forward = 0

# Controls source route verification
net.ipv4.conf.default.rp_filter = 1

# Do not accept source routing
net.ipv4.conf.default.accept_source_route = 0

# Controls the System Request debugging functionality of the kernel
kernel.sysrq = 0

# Controls whether core dumps will append the PID to the core filename.
# Useful for debugging multi-threaded applications.
kernel.core_uses_pid = 1

# Controls the use of TCP syncookies
net.ipv4.tcp_syncookies = 1
...

修改文件后是不能立即生效的,需要重启系统。若要立即生效,可使用以下命令:

1
sysctl -p /etc/sysctl.conf

/sys

这个目录平时接触和修改的机会比较小,网上也有很多相关资料,这里只是粗略地介绍一下。

/sys 目录是一个独立的文件系统,称为 sysfs

sysfs 的作用是输出内核识别出的各硬件设备的相关属性信息,也有内核对硬件特性的可设置参数,对此些参数的修改,即可定制硬件设备工作特性。

udev 通过读取 /sys 目录下的硬件设备信息按需为各硬件设备创建设备文件。

udev 是用户空间程序,专用工具: devadminhotplug

udev 为设备创建设备文件时,会读取其事先定义好的规则文件,一般在 /etc/udev/rules.d/ 目录下,以及 /usr/lib/udev/rules.d/ 目录下。