文章目录
- Linux的启动流程
- BIOS、boot loader与kernel加载
- 内核与内核模块
- 内核模块与依赖性:depmod
- 查看内核模块:lsmod、modinfo
- 内核模块的加载与删除:insmod、rmmod、modprobe
- 内核模块的额外参数设置:/etc/modprobe.d/*.conf
- Linux启动过程的问题解决
- 忘记root密码的解决
- 因文件系统错误而无法启动
Linux的启动流程
Linux的启动流程是一个非常复杂的过程,下面是对Linux启动流程的详细分析:
假设以个人计算机使用的Linux为例,当你按下电源按键后,计算机硬件会主动地读取BIOS或UEFI BIOS来加载硬件信息及进行硬件系统的自我测试,之后系统会主动地读取第一个可启动的设备(由BIOS设置),此时就可以读入启动引导程序了。
启动引导程序可以指定使用哪个内核文件来启动,并实际加载内核到内存当中解压缩与执行。此时内核就能够开始在内存中活动,并检测所有硬件信息与加载适当的驱动程序来使整台主机开始运行,等到内核检测硬件与加载驱动程序完毕后,一个最普通的操作系统就开始在你的PC上运行了。
主机系统开始运行后,此时Linux才会调用外部程序开始准备软件执行的环境,并且加载所有操作系统运行所需要的软件程序,最后系统就会开始等待你的登录与操作。
简单来说,操作系统启动的经过可以集合成下面的流程:
加载BIOS
的硬件信息与进行自我检测
(自检),并根据设置取得第一个可启动的设备;- 读取并
执行第一个启动设备内MBR的启动引导程序
(就是grub2等程序) - 在硬件驱动成功后,Kernel会主动调用systemd程序,并以
default.target
流程启动:systemd
执行sysinit.target
初始化系统及basic.target
准备操作系统systemd
启动multi-user.target
下的本机与服务器服务systemd
执行multi-user.target
下的 /etc/rc.d/rc.local 文件systemd
执行multi-user.target
下的getty.target 及登录服务systemd
执行graphical
需要的服务
大概流程就上面写的,你会发现systemd
占的比重非常重。
流程图如下
接下来我们来详细介绍一下
BIOS、boot loader与kernel加载
- BIOS:不论传统BIOS还是UEFI BIOS 都会被简称为 BIOS
- MBR:虽然分区表有传统MBR以及新式GPT,不过GPT也有保留一块兼容MBR的区块
因此,下面的说明在安装 boot loader的部分,还是简称为 MBR。总之,MBR就代表该磁盘的最前面可安装boot loader的那个区块
BIOS
在个人计算机架构下,要启动整个系统,首先需要加载BIOS程序。BIOS程序是计算机的基本输入输出系统,它会读取CMOS(可擦写只读存储器)中存储的设置信息,包括CPU和接口设备的通信频率、启动设备的查找顺序、硬盘的大小和类型、周边总线是否启用插拔即用设备(PnP)以及各接口设备的输入输出地址等信息。
BIOS在读取完CMOS中的设置信息后,会进行自我检测,然后对硬件设备进行初始化,并设置PnP设备,最后定义出可启动的设备顺序。
接下来,BIOS会开始从启动设备中读取数据,以启动操作系统。由于操作系统通常存储在硬盘中,所以BIOS会指定启动设备号,以便读取磁盘中的操作系统内核文件。但是,不同的操作系统使用的文件系统格式不同,因此需要使用一个启动引导程序来加载内核文件。这个启动引导程序就是boot loader,它通常安装在启动设备的第一个扇区,也就是MBR(主引导记录)。
==boot loader ==
boot loader的最主要功能是识别操作系统的文件格式,并将内核文件加载到内存中去执行。
由于不同操作系统使用的文件格式不同,因此每种操作系统都有自己的boot loader
。只有使用相应操作系统的boot loader,才能正确地加载内核文件。因此,Linux系统的boot loader只能加载Linux内核文件,Windows系统的boot loader只能加载Windows内核文件,其他操作系统也一样。只有正确加载了内核文件,操作系统才能正常运行。
那么问题来了,你应该听说过多重操作系统吧?也就是再一台主机上面安装多种不同的操作系统。既然必须要使用自己的loader才能够加载属于自己的操作系统内核,而系统的MBR只有一个,那你怎么会有办法同时再一台主机上面安装Windows与Linux呢?
每个文件系统都有一个启动扇区
,也称为boot sector
。这个启动扇区的作用是让操作系统安装boot loader。通常情况下,每个操作系统都会默认将自己的boot loader安装到它根目录所在的文件系统的boot sector上
。这样,在计算机启动时,BIOS会读取MBR(Master Boot Record,主引导记录),MBR再读取对应文件系统的boot sector,最终执行其中的boot loader程序,把操作系统加载到内存中并启动。因此,每个操作系统都需要一个boot loader来启动,而这个boot loader通常被安装在操作系统所在的文件系统的boot sector上
。在安装多个操作系统时,每个操作系统都会安装自己的boot loader到对应文件系统的boot sector上
,因此MBR和boot sector都可能被不同的boot loader覆盖,以便启动不同的操作系统。
虽然操作系统都可以安装一份boot loader到它的boot sector中,这样操作系统可以通过自己的boot loader来加载内核,问题是系统的MBR只有一个,你要怎么执行boot sector 里面的loader呢?这就要使用到了 boot loader
Boot loader的主要功能有三个:提供选项
、加载内核文件
和转交其他loader
。
首先,boot loader提供选项让用户可以选择不同的启动选项,这是多重引导的重要功能,比如用户可以选择不同的操作系统或者进入恢复模式等。
其次,boot loader的另一个主要功能是加载内核文件。当用户选择一个启动选项后,boot loader会直接指向可启动的程序区域来启动操作系统,即加载内核文件。
最后,boot loader还可以将启动管理功能转交给其他loader负责。这个功能可以让boot loader更加灵活,比如可以将控制权转交给其他操作系统的boot loader,以实现多个操作系统的共存。
由于具有选项功能,因此我们可以选择不同的内核来启动,而由于具有控制权转交功能,因此我们可以加载其他boot sector 内的loader。不过 Windows 的 loader 默认不具有控制权转交功能,因此你不能使用 Windows 的loader来加载 Linux 的loader。
上述图片借用博客: https://aerobaticswu.blog.csdn.net/article/details/115030430
如上图所示,MBR使用了Linux的Grub2启动引导程序,里面已经有了三个选项。
第一个选项:可以直接指向Linux的内核文件来启动Linux操作系统
MBR(grub2) → kernel file → booting
第二个选项:可以将启动管理权限交给Windows来管理。这时候Windows的启动管理器就会接管启动流程,启动Windows操作系统。
MBR(grub2) → boot sector(Windows loader) → Windows kernel → booting
第三个选项则是:使用Linux在boot sector内的启动引导程序,这时候会跳出另外一个Grub2选项,用户可以在这个选项中选择其他启动选项。
MBR(grub2) → boot sector(grub2) → kernel file → booting
通过这种方式,用户可以在同一台计算机上安装多个操作系统,并且通过Grub2启动引导程序来选择不同的启动选项,实现多重引导的功能。
boot loader的功能就是【加载内核文件】
boot loader 的两个stage
在BIOS读取完信息后,会到第一个启动设备的MBR去读取boot loader。这个boot loader可以具有选项功能、直接加载内核文件以及控制权限移交功能等。操作系统必须要有loader才能加载该操作系统的内核。然而,MBR只有446B的大小,不足以存储完整的boot loader程序,就算是GPT也没有更大的扇区来存储loader的数据。那么,如何安装boot loader呢?
在Linux中,boot loader的程序代码执行与设置值的加载分成了两个阶段,分别是stage 1和stage 2:
stage 1:执行boot loader主程序
。
第一阶段执行 boot loader 的主程序,这个主程序必须安装在启动区,就是MBR或启动扇区(boot sector)。但如前所述,因为MBR实在太小了,所以MBR或启动扇区通常仅安装 boot loader的最小主程序,并没有安装loader的相关配置文件
stage 2:主程序加载配置文件
第二阶段通过 boot loader通过加载所有配置文件和相关的环境参数文件(包括文件系统定义和配置文件grub.cfg),来完成loader的配置。通常,这些配置文件都存储在/boot目录下。在这个阶段,boot loader的主程序会根据配置文件的设定,加载操作系统的内核文件和其他必要的文件,从而完成操作系统的启动过程。这个阶段的完成,就意味着操作系统已经准备好运行了。
grub2配置文件维护/etc/default/grub
/etc/default/grub 主要环境配置文件
[root@localhost ~]# cat /etc/default/grub
GRUB_TIMEOUT=5
GRUB_DISTRIBUTOR="$(sed 's, release .*$,,g' /etc/system-release)"
GRUB_DEFAULT=saved
GRUB_DISABLE_SUBMENU=true
GRUB_TERMINAL_OUTPUT="console"
GRUB_CMDLINE_LINUX="crashkernel=auto spectre_v2=retpoline rd.lvm.lv=centos/root rd.lvm.lv=centos/swap rhgb quiet"
GRUB_DISABLE_RECOVERY="true"
GRUB_TIMEOUT=5
:设置启动菜单的超时时间为5秒。如果在5秒内没有选择启动项,系统将自动启动默认菜单项。(如果不想等待则输入0)GRUB_TIMEOUT_STYLE(是否隐藏选项)
:这个选项上面没有,可以按需添加,这个选项可以选择的值有 menu、countdown、hidden等。如果没有设置,默认是menu的意思。这个选项主要是在设置不要显示启动选项。如果你不想要让用户看到启动选项,这里可以设置为countdown。那么countdown和hidden有啥区别呢?countdown会在屏幕上显示剩余的等待秒数,而hidden则空空如也,除非你有特定的需求,默认一般设置为menu。GRUB_DISTRIBUTOR="$(sed 's, release .*$,,g' /etc/system-release)"
:设置GRUB的发行商为系统的发行商。这里通过sed命令获取/etc/system-release文件中的发行商信息,并将其赋值给GRUB_DISTRIBUTOR变量。GRUB_DEFAULT=saved
:指定默认启动的操作系统菜单项编号,编号从0开始计数。默认值为0(saved),即默认启动第一个菜单项。GRUB_DISABLE_SUBMENU=true
:禁用子菜单,将所有启动项都显示在主菜单中。GRUB_TERMINAL_OUTPUT="console"
:这个选项主要的设置有【console、serial、gfxterm、vga_text】等。除非有特定需求一般使用,console:将启动菜单输出到控制台。GRUB_CMDLINE_LINUX="crashkernel=auto spectre_v2=retpoline rd.lvm.lv=centos/root rd.lvm.lv=centos/swap rhgb quiet"
:设置Linux内核启动参数。这里设置了一些常用的参数,如crashkernel、spectre_v2、rd.lvm.lv等。GRUB_DISABLE_RECOVERY="true"
:禁用系统恢复模式,避免意外进入系统恢复模式。
通过修改这些参数的值,可以调整GRUB的启动行为,以适应不同的需求。修改完毕后,需要运行 grub2-mkconfig来重建grub.cfg才行。
例题:
假设你需要(1)启动选项等待40秒;(2)默认用第一个选项启动;(3)选项请显示出来不要隐藏;(4)内核外带【elevator=deadline】的参数值,那么应该如何处理grub.cfg?
- 先编辑主要环境配置文件
[root@localhost ~]# vim /etc/default/grub
GRUB_TIMEOUT=40
GRUB_DISTRIBUTOR="$(sed 's, release .*$,,g' /etc/system-release)"
GRUB_DEFAULT=0
GRUB_TIMEOUT_STYLE=menu
GRUB_DISABLE_SUBMENU=true
GRUB_TERMINAL_OUTPUT="console"
GRUB_CMDLINE_LINUX="crashkernel=auto spectre_v2=retpoline rd.lvm.lv=centos/root rd.lvm.lv=centos/swap rhgb quiet elevator=deadline"
GRUB_DISABLE_RECOVERY="true"
[root@localhost ~]# grub2-mkconfig
- 开始重新创建grub.cfg
[root@localhost ~]# grub2-mkconfig -o /boot/grub2/grub.cfg
Generating grub configuration file ...
Found linux image: /boot/vmlinuz-3.10.0-1160.el7.x86_64
Found initrd image: /boot/initramfs-3.10.0-1160.el7.x86_64.img
Found linux image: /boot/vmlinuz-0-rescue-567928b865d945a8a3c7211006b3ba40
Found initrd image: /boot/initramfs-0-rescue-567928b865d945a8a3c7211006b3ba40.img
done
命令说明:
grub2-mkconfig -o /boot/grub2/grub.cfg
是一个用于生成GRUB2启动菜单的命令。这个命令会扫描系统中已安装的操作系统和内核,并根据默认配置文件 /etc/default/grub
中的配置参数生成启动菜单。最终生成的启动菜单会被保存在 /boot/grub2/grub.cfg
文件中。
- 检查看看grub.cfg的内容是否真的改变
[root@localhost ~]# grep timeout /boot/grub2/grub.cfg set timeout_style=menuset timeout=40
[root@localhost ~]# grep default /boot/grub2/grub.cfg
# from /etc/grub.d and settings from /etc/default/grubset default="0"
[root@localhost ~]# grep elevator=deadline /boot/grub2/grub.cfg linux16 /vmlinuz-3.10.0-1160.el7.x86_64 root=/dev/mapper/centos-root ro crashkernel=auto spectre_v2=retpoline rd.lvm.lv=centos/root rd.lvm.lv=centos/swap rhgb quiet elevator=deadline linux16 /vmlinuz-0-rescue-567928b865d945a8a3c7211006b3ba40 root=/dev/mapper/centos-root ro crashkernel=auto spectre_v2=retpoline rd.lvm.lv=centos/root rd.lvm.lv=centos/swap rhgb quiet elevator=deadline
加载内核检测硬件与 initramfs 的功能
在计算机启动时,首先会由BIOS(Basic Input/Output System)加载boot loader(引导加载程序),其主要作用是找到并加载操作系统内核文件。当boot loader管理开始读取内核文件后,Linux会将内核解压缩到内存中并利用内核的功能,开始测试与驱动各个周边设备,包括存储设备、CPU、网卡、声卡等。此时Linux内核会以自己的功能重新检测一次硬件,而不一定会使用BIOS检测到的硬件信息
。也就是说,内核此时才开始接管BIOS后的工作。一般情况下,内核文件被放置在/boot目录下,并命名为vmlinuz。
-
ls
是列出目录内容的命令 -
--format=single-column
指定每个文件名单独列出,每行只显示一个 -
-F
会在每个文件名后面加上一个符号,表示该文件的类型。例如,加上斜杠表示该文件是一个目录,加上星号表示该文件是一个可执行文件 -
config-3.10.0-1160.el7.x86_64
是Linux内核的配置文件。 -
efi
是存储UEFI启动文件的目录。 -
grub
是GRUB引导程序的配置目录。 -
grub2
是GRUB2引导程序的配置目录。 -
initramfs-0-rescue-567928b865d945a8a3c7211006b3ba40.img
是包含内核模块和初始化脚本的内存文件系统映像文件。这是一个紧急恢复映像文件,用于修复系统出现问题时的紧急情况。 -
initramfs-3.10.0-1160.el7.x86_64.img
是包含内核模块和初始化脚本的内存文件系统映像文件。 -
initramfs-3.10.0-1160.el7.x86_64kdump.img
是用于内核转储(kdump)的内存文件系统映像文件。 -
symvers-3.10.0-1160.el7.x86_64.gz
是Linux内核符号表。 -
System.map-3.10.0-1160.el7.x86_64
是Linux内核符号表。 -
vmlinuz-0-rescue-567928b865d945a8a3c7211006b3ba40
是一个紧急恢复的Linux内核文件。它用于在系统出现问题时使用。 -
vmlinuz-3.10.0-1160.el7.x86_64
是Linux内核文件。
从上图中的特殊字体,我们可以知道Linux的内核版本为 3.10.0-1160.el7.x86_64
。
Linux内核是操作系统的核心,可以通过动态加载内核模块来扩展其功能,就像插入一个驱动程序一样。这些内核模块通常存储在/lib/modules/
目录中。由于这些模块存储在根目录下(要记得 /lib 不可以与 / 分别放在不同的硬盘分区),因此在启动时必须要挂载根目录,才能够读取内核模块提供的驱动程序功能。为了保护磁盘内的文件系统,启动过程中根目录通常是以只读方式挂载的,以防止对文件系统的影响
一般来说,目前的Linux发行版都会将非必要的功能且可以编译成未模块的内核功能,编译成为模块,比如USB、SATA、SCSI等磁盘设备的驱动程序通常是以模块的方式存在的。如果Linux安装在SATA磁盘上,启动时BIOS会通过INT 13取得boot loader和内核文件,然后内核会开始接管系统并检测硬件并尝试挂载根目录来取得额外的驱动程序。
在Linux中,内核本身并不认识SATA磁盘,因此需要加载SATA磁盘的驱动程序才能挂载根目录。但是,SATA的驱动程序通常存储在/lib/modules目录中,如果无法挂载根目录,就无法读取/lib/modules
中的驱动程序。这时,就需要通过虚拟文件系统来解决这个问题。
虚拟文件系统通常使用的文件名为/boot/initrd
或/boot/initramfs
,它可以通过boot loader加载到内存中。这个文件会被解压缩,并在内存中模拟出一个根目录。这个内存中的文件系统可以提供一个可执行的程序,用于加载启动过程中所需的内核模块,比如USB、RAID、LVM、SCSI等文件系统和磁盘接口的驱动程序。加载完成后,它会帮助内核重新调用systemd来开始后续的正常启动流程。这样就可以让Linux在启动时顺利地加载所需的驱动程序,从而保证系统的正常运行。
如上图所示,boot loader可以加载 kernel与 initramfs,然后再内存中让 initramfs 解压缩成为根目录,内核(kernel)就能够借此加载适当的驱动程序,最终释放虚拟文件系统,并挂载实际的根目录文件系统,从而开始后续的正常启动流程。
initramfs是一个小型的根目录,它与普通的根目录一样也是通过systemd进行管理。它的作用是在启动系统时提供一些必要的文件和驱动程序,以便让系统能够顺利启动。在启动时,系统会先加载initramfs,然后读入一些硬件检测和内核功能启用的流程,使系统能够正常启动。最后,系统会卸载initramfs,然后挂载真正的根目录,启动完成。
内核与内核模块
在整个启动的过程中,是否能够成功地驱动我们主机的硬件设备是内核(kernel)的工作
。而内核一般都是压缩文件,因此在使用内核之前,就得要将他解压缩后,才能加载内存当中
。
另外,为了应付日新月异的硬件,目前的内核都是具有【可读取模块化驱动程序】的功能,就是所谓的【modules(模块化)】的功能
。所谓的模块化可以将它想成是一个【插件
】,该插件可能又硬件开发厂商提供,也有可能我们的内核本来就支持,不过,较新的硬件通常都需要硬件开发商提供驱动程序模块。
那么内核与内核模块放在哪?
-
内核:
/boot/vmlinuz
或/boot/vmlinuz-version
-
内核解压缩所需RAM Disk:
/boot/initramfs(/boot/initramfs-version)
-
内核模块:/lib/modules/version/kernel 或 /lib/modules/$(uname -r)/kernel
如果该内核被顺利的加载系统当中了,那么就会有几个信息记录下来:
- 内核版本:/proc/version
- 系统内核功能:/proc/sys/kernel/
问题来了,如果我有个新硬件,偏偏文档操作系统不支持,该怎么办?
- 重新编译内核,并加入最新的硬件驱动程序源代码
- 将该硬件的驱动程序编译为模块,在启动时加载该模块
内核模块与依赖性:depmod
既然要处理内核模块,既然就得要链接我们内核提供的模块之间的相关性。基本上,内核模块的放置处是在 /lib/modules/$(uname -r)/kernel当中,里面主要分为几个目录:
arch: 这个目录包含了各种体系结构相关的代码,包括各种CPU体系结构、芯片组、设备树等。
crypto: 这个目录包含了各种加密算法的实现,如AES、SHA1、SHA256等。
drivers: 这个目录包含了各种设备驱动程序的实现,如网络、存储、USB、声卡、显卡等。
fs: 这个目录包含了各种文件系统的实现,如ext4、NTFS、FAT32等。
kernel: 这个目录包含了内核的核心部分,如进程管理、内存管理、调度器等。
lib: 这个目录包含了各种库函数的实现,如字符串、内存、文件等。
mm: 这个目录包含了内存管理相关的代码,如页面分配、缺页处理、内存映射等。
net: 这个目录包含了各种网络协议的实现,如TCP、UDP、IPv4、IPv6等。
sound: 这个目录包含了声卡驱动程序的实现,如ALSA、OSS等。
virt: 这个目录包含了虚拟化相关的代码,如KVM、Xen等。
depmod
如果我们一个一个地去检测这些模块的主要信息,然后定义出它们的依赖性,那么会相当麻烦。所以说,Linux提供了一些模块依赖性的解决方案。就是检查/lib/modules/$(uname -r)/modules.dep
这个文件,它记录了内核支持的模块的各项依赖性
那么这个文件怎么建立?利用depmod这个命令就可以达到建立该文件的需求
depmod [-Ane]
选项:
-A:不加任何参数时,depmod会主动地去分析目前内核的模块,并且重新写入/lib/modules/$(uname -r)/modules.dep 当中,若加入 -A 数时,则depmod会去查找比 modules.dep 内还要新的模块,如果真找到新模块,才会更新
-n:不会写入modules.dep,而是将结果输出到屏幕上(standard out)
-e:显示出目前已加载的不可置信的模块名称。
# 示例1 若我做好了一个网卡驱动程序,文件名为a.ko,该如何更新内核依赖性
[root@localhost ~]# cp a.ko /lib/modules/3.10.0-1160.el7.x86_64/kernel/drivers/net/
[root@localhost ~]# depmod
以上面的案例为例,我们的内核模块扩展名一定是 .ko 结尾的,当你使用depmod 之后,该程序会跑到模块标准放置目录 /lib/modules/$(uname -r)/kernel ,并依据相关目录的定义将全部的模块读出来分析,最终才将分析的结果写入 modules.dep 文件中。
查看内核模块:lsmod、modinfo
lsmod
那么内核加载了多少模块?很简单,利用lsmod即可
[root@localhost ~]# lsmod
Module Size Used by
xt_conntrack 12760 1
ipt_MASQUERADE 12678 1
drm_kms_helper 186531 1 vmwgfx
ttm 96673 1 vmwgfx
vmwgfx 291993 1
drm 456166 4 ttm,drm_kms_helper,vmwgfx # drm 还被 qxl,ttm..等模块使用
......
.....
使用lsmod之后,系统会显示出目前依据纯在与内核当中的模块,显示的内容包括有:
- 模块名称(Module)
- 模块的大小(size)
- 此模块是否被其他模块所使用(Used by)
modinfo
也就是说,模块其实真的有依赖性。
modinfo [-adln] [module name | filename]
选项:
-a:仅列出作者名称
-d:仅列出该modules的说明 (description)
-l:仅列出授权(license)
-n:仅列出该模块的详细路径# 示例1 由上个表格当中,请列出drm这个模块的相关信息
[root@localhost ~]# modinfo drm
filename: /lib/modules/3.10.0-1160.el7.x86_64/kernel/drivers/gpu/drm/drm.ko.xz
license: GPL and additional rights
description: DRM shared core routines
author: Gareth Hughes, Leif Delgass, José Fonseca, Jon Smirl
license: GPL and additional rights
description: DRM bridge infrastructure
author: Ajay Kumar <ajaykumar.rs@samsung.com>
retpoline: Y
rhelversion: 7.9
srcversion: 4BE38BB1EE6D7E3B095A7C4
depends: drm_panel_orientation_quirks
intree: Y
vermagic: 3.10.0-1160.el7.x86_64 SMP mod_unload modversions
signer: CentOS Linux kernel signing key
sig_key: E1:FD:B0:E2:A7:E8:61:A1:D1:CA:80:A2:3D:CF:0D:BA:3A:A4:AD:F5
sig_hashalgo: sha256
parm: edid_firmware:Do not probe monitor, use specified EDID blob from built-in data or /lib/firmware instead. (string)
parm: vblankoffdelay:Delay until vblank irq auto-disable [msecs] (0: never disable, <0: disable immediately) (int)
parm: timestamp_precision_usec:Max. error on timestamps [usecs] (int)
parm: edid_fixup:Minimum number of valid EDID header bytes (0-8, default 6) (int)
# 可以看到整个模块的来源,以及该模块的简易说明
我有一个模块名称为 a.ko 请问该模块相关信息是什么
[root@localhost ~]# modinfo a.ko
事实上,整个modinfo 除了可以【查看在内核中的模块】之外,还可以检查【某个模块文件】,因此,如果你想要知道某个文件代表的意义是什么,利用 modinfo 加上完整文件名,看看就知道了。
内核模块的加载与删除:insmod、rmmod、modprobe
如果你想手动加载模块,建议使用modprobe来实现。最简单的方法是使用modprobe命令来加载整个目录的模块。这是因为modprobe会自动查找modules.dep文件来解决模块之间的依赖关系,然后决定需要加载哪些模块,非常方便。而使用insmod命令则需要用户手动加载完整的模块文件名,并且不会自动解决模块之间的依赖关系。
insmod
insmod [/full/path/module_name] [parameters]# 示例1 请尝试加载cifs.ko 这个【文件系统】模块
[root@localhost ~]# insmod /lib/modules/3.10.0-1160.el7.x86_64/kernel/fs/fat/fat.ko.xz
[root@localhost ~]# lsmod | grep fat
fat 65950 0
insmod立刻就将该模块加载,但是insmod后面接的模块必须要是完整的【文件名】才行。那如何删除这个模块?
rmmod
rmmod [-fw] module_name
选项:
-f:强制将该模块删除,不论是是否正被使用# 示例1 将刚刚加载fat模块删除
[root@localhost ~]# rmmod fat
[root@localhost ~]# lsmod | grep fat
[root@localhost ~]# # 示例2 请加载vfat这个【文件系统】模块
[root@localhost ~]# insmod /lib/modules/3.10.0-1160.el7.x86_64/kernel/fs/fat/vfat.ko.xz
insmod: ERROR: could not insert module /lib/modules/3.10.0-1160.el7.x86_64/kernel/fs/fat/vfat.ko.xz: Unknown symbol in module
# 无法加载vfat这个模块
使用insmod与rmmod的问题就是,你必须要自行找到模块的完整文件名才行,而且如同上述案例二的结果,万一模块有依赖属性时,你将无法直接加载或删除模块。所以近年案例我们都建议直接使用 modprobe 来处理模块加载的问题,这个命令用法时
modprobe
modprobe [-cfr] module_name
选项:
-c:列出目前系统所有的模块。(更详细的代号对应表)
-f:强制加载该模块
-r:类似rmmod,就是删除某个模块
# 示例1 加载vfat模块
[root@localhost ~]# modprobe vfat
# 很方便,不需要知道完整的模块文件名,这是因为完整文件名已经记录到
# /lib/modules/$(uname -r)/modules.dep 当中的缘故,如果要删除的化如下操作即可
[root@localhost ~]# modprobe -r vfat
[root@localhost ~]# lsmod |grep vfat
[root@localhost ~]# # 示例2 尝试用modprobe加载cifs这个模块,并且查看该模块的相关模块是哪个?
[root@localhost ~]# modprobe cifs
[root@localhost ~]# lsmod |grep cifs
cifs 708540 0
dns_resolver 13140 1 cifs # 竟然会使用到 dns_resolver
[root@localhost ~]# modprobe -r cifs # 测试完成删除此模块
[root@localhost ~]# lsmod |grep cifs
[root@localhost ~]#
内核模块的额外参数设置:/etc/modprobe.d/*.conf
在Linux系统中,内核模块有时需要一些额外的参数来控制其行为,例如调整缓存大小、指定设备ID等。为了方便这些参数的设置,系统提供了一个目录:/etc/modprobe.d/
,在该目录下可以创建以.conf
为后缀的文件,并在其中定义相关模块的参数。
这些文件中可以使用以下格式来设置模块参数:
options module_name parameter_name=parameter_value
其中,module_name
是需要设置参数的模块的名称,parameter_name
是模块参数的名称,parameter_value
是参数值。例如,要设置i915内核模块的参数,可以创建一个名为i915.conf的文件,然后在其中添加以下内容:
options i915 modeset=1
这将启用i915模块的modeset参数,并将其设置为1。
最后,需要注意的是,每个配置文件中只能配置一个模块的参数。如果需要为多个模块设置参数,则需要创建多个配置文件。
Linux启动过程的问题解决
当我们在使用Linux时,可能会因为某些设置或突然断电等原因导致文件系统出现错误,从而导致Linux无法正常启动。但这并不意味着我们需要重新安装系统,我们可以进入rescue模式来解决这些问题。下面是一些常见的问题及其解决方案:
忘记root密码的解决
如果我记忆力不是很好 root 密码忘记了怎么办?其实在Linux环境中 root 密码忘记时是可以救回来的。只要能够进入并且挂载,如何重新设置一下root的密码,就救回来了。
只是在新版的 systemd 的管理机制中,默认的 rescue 模式是无法直接获取 root 权限的,还是得要使用 root 的密码才能够登录 rescure 环境。那怎么办?,还是有办法的,通过一个名为【rd.break】的内核参数来处理即可。只是需要注意的是,rd.break 是 RPM disk 里面的操作系统状态,因此你不能直接获取原本的 Linux 系统操作环境。所以,还需要 chroot的支持。更由于 SELinux 的问题,你可能还得要加上某些特殊的操作才能顺利搞定 root 密码的恢复。
解决方法
现在我们来实践一下(1)按下 systemctl reboot 来重新启动
(2) 进入到启动画面,在可启动的选项上按下 e 进入编辑模式,如何就在Linux 16 的哪个内核项目上面使用 这个参数保护来处理
在下面的画面按下 e 进入编辑模式
改完之后按下 [ctrl] + x 开始启动,启动完成后屏幕会出现如下类似画面
此时请注意,你应该是在 RAM disk 的环境,并不是原本的环境,因此根目录下面的东西跟你原本的系统无关。而且,你的系统应该会被挂载到 /sysroot 目录下,因此,你得这样做
switch_root:/# # 无须输入密码即可获取root权限
switch_root:/# mount |grep /sysroot # 检查一下挂载点,一定要发现/sysroot 才是对的
/dev/mapper/centos-root on /sysroot xfs (ro,relatime,attr2,inode64,noquota)
switch_root:/# mount -o remount,rw /sysroot # 要先让它挂载成可读写属性
switch_root:/# chroot /sysroot
sh-4.2# echo "csq131400" | passwd --stdin root # 修改密码
sh-4.2# touch /.autorelabel # 这一步很重要,使用SELinux的安全上下文
sh-4.2# exit
switch_root:/# reboot # 重启测试
重新启动后,你输入新的密码就可以登录系统了。
- chroot 目录:代表将你的根目录【暂时】切换到 chroot之后所接的目录。因此,以上表为例,那个 /sysroot 将会被暂时作为根目录,而我们知道那个目录其实就是最原先的系统根目录,所以你当然就能够用来处理你的文件系统与相关的账号管理
- 为什么需要/.autorelabel:在rd.break 的RAM disk 环境下,系统是没有 SELinux的,而你刚刚修改了 /etc/shadow (因为改密码),所以【这个文件的SELinux安全上下文的特性将会被取消】。如果你没有让系统于启动时自动地恢复 SELinux上下文,你的系统将产生【无法登录】的问题(在 SELinux 为 Enforcing 的模式下),加上/.autorelabel就是让系统在启动的时候自动使用默认的SELinux类型重新写入 SELinux 安全上下文到每个文件中。
不过加上 /.autorelabel 之后,系统重新启动就会重新写入 SELinux 的类型到每个文件,因此会花不少时间。如果你不想花很多时间,还有个方法可以处理:
-
在rd.break 模式下,修改完 root 密码后,将 /etc/selinux/config 内的 SELinux 运行模式修改为 permissive
-
重新启动后,使用 root 身份执行【restorecon -Rv /etc】仅修改 /etc 下面的文件
-
重新修改 /etc/selinux/config 改为 enforcing,然后【setenforce 1】即可
[root@localhost ~]# getenforce
Permissive
[root@localhost ~]# restorecon -Rv /etc/
[root@localhost ~]# restorecon -Rv /etc
[root@localhost ~]# vim /etc/selinux/config
SELINUX=enforcing
[root@localhost ~]# setenforce 1
因文件系统错误而无法启动
如果因为设置错误导致无法启动时,要怎么办?很简单。最容易除错的设置而导致无法顺利启动的步骤,通常就是 /etc/fstab 这个文件了,尤其是用户在实践磁盘配额、LVM、RAID时,最容易写错参数,又没有经过 mount -a来测试挂载,就立刻直接重新启动,就立刻直接重新启动,然后就无法启动了该怎么办?如下图
解决方法
-
可以看到最后两行,他说输入root密码继续加以恢复,那就输入root密码
-
mount -o remount,rw / 将根目录挂载成可读写
-
编辑/etc/fstab修改错误
-
保存退出 重启(reboot)看看