Linux的启动流程、模块管理与Loader

文章目录

  • 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占的比重非常重。

流程图如下

image-20230519180536467

接下来我们来详细介绍一下

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覆盖,以便启动不同的操作系统。

image-20230519212734140

虽然操作系统都可以安装一份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。

img

上述图片借用博客: 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"
  1. GRUB_TIMEOUT=5 :设置启动菜单的超时时间为5秒。如果在5秒内没有选择启动项,系统将自动启动默认菜单项。(如果不想等待则输入0)
  2. GRUB_TIMEOUT_STYLE(是否隐藏选项):这个选项上面没有,可以按需添加,这个选项可以选择的值有 menu、countdown、hidden等。如果没有设置,默认是menu的意思。这个选项主要是在设置不要显示启动选项。如果你不想要让用户看到启动选项,这里可以设置为countdown。那么countdown和hidden有啥区别呢?countdown会在屏幕上显示剩余的等待秒数,而hidden则空空如也,除非你有特定的需求,默认一般设置为menu。
  3. GRUB_DISTRIBUTOR="$(sed 's, release .*$,,g' /etc/system-release)":设置GRUB的发行商为系统的发行商。这里通过sed命令获取/etc/system-release文件中的发行商信息,并将其赋值给GRUB_DISTRIBUTOR变量。
  4. GRUB_DEFAULT=saved:指定默认启动的操作系统菜单项编号,编号从0开始计数。默认值为0(saved),即默认启动第一个菜单项。
  5. GRUB_DISABLE_SUBMENU=true:禁用子菜单,将所有启动项都显示在主菜单中。
  6. GRUB_TERMINAL_OUTPUT="console":这个选项主要的设置有【console、serial、gfxterm、vga_text】等。除非有特定需求一般使用,console:将启动菜单输出到控制台。
  7. 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等。
  8. GRUB_DISABLE_RECOVERY="true":禁用系统恢复模式,避免意外进入系统恢复模式。

通过修改这些参数的值,可以调整GRUB的启动行为,以适应不同的需求。修改完毕后,需要运行 grub2-mkconfig来重建grub.cfg才行。

例题:

假设你需要(1)启动选项等待40秒;(2)默认用第一个选项启动;(3)选项请显示出来不要隐藏;(4)内核外带【elevator=deadline】的参数值,那么应该如何处理grub.cfg?

  1. 先编辑主要环境配置文件
[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
  1. 开始重新创建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 文件中。

  1. 检查看看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。

image-20230522153231676

  • 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在启动时顺利地加载所需的驱动程序,从而保证系统的正常运行。

image-20230522170502410

如上图所示,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 来重新启动

image-20230523104950118

(2) 进入到启动画面,在可启动的选项上按下 e 进入编辑模式,如何就在Linux 16 的哪个内核项目上面使用 这个参数保护来处理

在下面的画面按下 e 进入编辑模式

image-20230523105044028

image-20230523095730775

改完之后按下 [ctrl] + x 开始启动,启动完成后屏幕会出现如下类似画面

image-20230523105205653

此时请注意,你应该是在 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

  • image-20230523150928979

  • 重新启动后,使用 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来测试挂载,就立刻直接重新启动,就立刻直接重新启动,然后就无法启动了该怎么办?如下图

image-20230523154335381

解决方法

  • 可以看到最后两行,他说输入root密码继续加以恢复,那就输入root密码

    image-20230523154544662

  • mount -o remount,rw / 将根目录挂载成可读写

    image-20230523154659989

  • 编辑/etc/fstab修改错误

  • 保存退出 重启(reboot)看看
    image-20230523155123597

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.rhkb.cn/news/288600.html

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

如何处理Flutter应用程序中的内存泄漏

大家好&#xff0c;我是咕噜铁蛋&#xff01;今天&#xff0c;我想和大家分享一下如何处理Flutter应用程序中的内存泄漏问题。在Flutter开发中&#xff0c;内存泄漏是一个常见且需要重点关注的问题&#xff0c;它可能会导致应用程序性能下降&#xff0c;甚至引发崩溃。因此&…

PASSL代码解读[01] readme

介绍 PASSL 是一个基于 PaddlePaddle 的视觉库&#xff0c;用于使用 PaddlePaddle 进行最先进的视觉自监督学习研究。PASSL旨在加速自监督学习的研究周期&#xff1a;从设计一个新的自监督任务到评估所学的表征。 PASSL 主要特性&#xff1a; 自监督前沿算法实现 PASSL 实现了…

嵌入式开发——基础电路知识

1. 电路知识 1.1. 驱动能力 IC是数字逻辑芯片&#xff0c;其输出的是逻辑电平。逻辑电平0表示输出电压低于阈值电压&#xff0c;逻辑1表示输出电压高于阈值电压。负载则是被驱动的电路或元件&#xff0c;负载大小则指负载的电阻大小。 驱动能力主要表现在几个方面&#xff1…

基于Pytorch的验证码识别模型应用

前言 在做OCR文字识别的时候&#xff0c;或多或少会接触一些验证码图片&#xff0c;这里收集了一些验证码图片&#xff0c;可以对验证码进行识别&#xff0c;可以识别4到6位&#xff0c;纯数字型、数字字母型和纯字母型的一些验证码&#xff0c;准确率还是相当高&#xff0c;需…

Self-Consistency Improves Chain of Thought Reasoning in Language Models阅读笔记

论文链接&#xff1a;https://arxiv.org/pdf/2203.11171.pdf 又到了读论文的时间&#xff0c;内心有点疲惫。这几天还是在看CoT的文章&#xff0c;今天这篇是讲如何利用self-consistency&#xff08;自我一致性&#xff09;来改进大语言模型的思维链推理过程。什么是self-cons…

设置asp.net core WebApi函数输入和返回类型中的属性名称开头大小写格式

以下列类型定义为例创建简单的ASP.NET Core的WebApi函数&#xff0c;此时输入参数和返回结果的属性名称开头默认为小写&#xff0c;如下图所示。 public class UserInfo { public string UserName { get; set; }public string UserSex { get; set; }public string UserP…

班级综合测评管理系统的设计与实现|Springboot+ Mysql+Java+ B/S结构(可运行源码+数据库+设计文档)

本项目包含可运行源码数据库LW&#xff0c;文末可获取本项目的所有资料。 推荐阅读100套最新项目持续更新中..... 2024年计算机毕业论文&#xff08;设计&#xff09;学生选题参考合集推荐收藏&#xff08;包含Springboot、jsp、ssmvue等技术项目合集&#xff09; 目录 1. …

【pytest、playwright】allure报告生成视频和图片

目录 1、修改插件pytest_playwright 2、conftest.py配置 3、修改pytest.ini文件 4、运行case 5、注意事项 1、修改插件pytest_playwright pytest_playwright.py内容如下&#xff1a; # Copyright (c) Microsoft Corporation. # # Licensed under the Apache License, Ver…

PL/SQL概述

oracle从入门到总裁:​​​​​​https://blog.csdn.net/weixin_67859959/article/details/135209645 PL/SQL概述 PL/SQL(Procedural Language extension to SQL)是 Oracle 对标准 SQL语言的扩充&#xff0c;是专门用于各种环境下对 Oracle 数据库进行访问和开发的语言。 由…

服务器呀服务器,一个虚拟专用服务器的使用教程

目前刚接触服务器这一块的学习&#xff0c;这里记录一下解如何获取自己的第一台虚拟云服务器&#xff0c;给刚入行服务器开发的小伙伴做一个参考。 具体的步骤如下&#xff1a; 一、服务器的注册和获取 1、打开bwg88服务器平台地址&#xff1a;点击进入 https://bwh88.net/a…

基于云计算的前端资源管理系统的设计与实现

hello宝子们...我们是艾斯视觉擅长ui设计和前端开发10年经验&#xff01;希望我的分享能帮助到您&#xff01;如需帮助可以评论关注私信我们一起探讨&#xff01;致敬感谢感恩&#xff01; 随着互联网的快速发展&#xff0c;前端资源管理成为了一个重要的课题。本文旨在设计并实…

新书速递——《可解释AI实战(PyTorch版)》

本书旨在帮助你实施最新的可解释AI技术&#xff0c;以构建公平且可解释的AI系统。可解释AI是当今AI研究中的热门话题&#xff0c;但只有少数资源和指南涵盖了所有重要技术&#xff0c;这些技术对实践者来说非常有价值。本书旨在填补这一空白。 本书读者对象 本书既适合那些有兴…

BUG定位---一起学习吧之测试

判断一个BUG是前端还是后端的&#xff0c;通常需要根据BUG的具体表现、发生的环境以及相关的技术栈来进行分析。以下是一些常用的判断方法&#xff1a; 错误发生的位置&#xff1a; 如果BUG涉及的是页面的布局、样式、交互效果等&#xff0c;那么很可能是前端的BUG。如果BUG与…

LNMP架构之mysql数据库实战

mysql安装 到官网www.mysql.com下载源码版本 实验室使用5.7.40版本 tar xf mysql-boost-5.7.40.tar.gz #解压 cd mysql-boost-5.7.40/ yum install -y cmake gcc-c bison #安装依赖性 cmake -DCMAKE_INSTALL_PREFIX/usr/local/mysql -DMYSQL_DATADIR/data/mysql -DMYSQL_…

队列+宽搜例题讲解!

429. N 叉树的层序遍历 题目解析&#xff1a; 根据题目分析&#xff0c;可以看出题目要我们求的是N叉数的层序遍历&#xff0c;就是把每层的放在一块&#xff0c;最后把每层都输出出来即可&#xff01; 算法分析&#xff1a; 我们可以利用队列先进先出的特性进行求解&#x…

Nuxt2 渲染时html比css加载快,导致闪屏/CSS样式迟滞/抖动问题记录

问题场景&#xff1a; 最近在用Nuxt2重写公司官网&#xff0c;但因为笔者不是专业前端&#xff0c;之前虽然也用vue2来写前端&#xff0c;但是用nuxt2来写项目还是第一次。在开发过程中虽然也磕磕碰碰&#xff0c;但因为开发的是官网&#xff0c;偏CMS型的网站&#xff0c;所以…

『Apisix安全篇』探索Apache APISIX身份认证插件:从基础到实战

&#x1f680;『Apisix系列文章』探索新一代微服务体系下的API管理新范式与最佳实践 【点击此跳转】 &#x1f4e3;读完这篇文章里你能收获到 &#x1f6e0;️ 了解APISIX身份认证的重要性和基本概念&#xff0c;以及如何在微服务架构中实施API安全。&#x1f511; 学习如何使…

蓝桥杯刷题之路径之谜

题目来源 路径之谜 不愧是国赛的题目 题意 题目中会给你两个数组&#xff0c;我这里是分别用row和col来表示 每走一步&#xff0c;往左边和上边射一箭&#xff0c;走到终点的时候row数组和col数组中的值必须全部等于0这个注意哈&#xff0c;看题目看了半天&#xff0c;因为…

腾讯云4核8g服务器多少钱?轻量和CVM收费价格表2024年最新

2024年腾讯云4核8G服务器租用优惠价格&#xff1a;轻量应用服务器4核8G12M带宽646元15个月&#xff0c;CVM云服务器S5实例优惠价格1437.24元买一年送3个月&#xff0c;腾讯云4核8G服务器活动页面 txybk.com/go/txy 活动链接打开如下图&#xff1a; 腾讯云4核8G服务器优惠价格 轻…

iOS17 隐私协议适配详解

1. 背景 网上搜了很多文章&#xff0c;总算有点头绪了。其实隐私清单最后做出来就是一个plist文件。找了几个常用三方已经配好的看了看&#xff0c;比着做就好了。 WWDC23 中关于隐私部分的更新&#xff08;WWDC23 隐私更新官网&#xff09;&#xff0c;其中提到了第三方 SDK 的…