Linux 文件系统挂载

系列文章目录
Linux内核学习
Linux 知识(1)
Linux 知识(2)
WSL Ubuntu
QEMU 虚拟机
Linux 调试视频
PCIe 与 USB 的补充知识
vscode 使用说明
树莓派 4B 指南
设备驱动畅想
Linux内核子系统
Linux 文件系统挂载
文章目录
- 系列文章目录
- 1. initrd 阶段的用户空间初始化脚本执行
- 1.1 解压缩并挂载 initrd 文件系统
- 1.2 加载介质驱动的机制
- 2. 挂载真实文件系统后的用户空间初始化脚本执行
- 2.1 挂载真实文件系统
- 3. 执行用户空间初始化脚本
- 3.1 内核中执行用户空间初始化脚本
- 3.2 用户空间初始化脚本
- 4. 加载默认模块
- 4.1 Linux 6.12.5 替代方案 ?
- 5. 总结
1. initrd 阶段的用户空间初始化脚本执行
在 initrd 阶段,内核会解压缩并挂载 initrd 文件系统。
1.1 解压缩并挂载 initrd 文件系统
populate_rootfs 函数负责解压缩 initrd 并将其挂载为根文件系统。以下是相关代码:
// init/initramfs.c
static int __init populate_rootfs(void)
{char *err = unpack_to_rootfs(__initramfs_start, __initramfs_size);if (err)panic("%s", err); /* Failed to decompress INTERNAL initramfs */if (initrd_start) {
#ifdef CONFIG_BLK_DEV_RAMint fd;printk(KERN_INFO "Trying to unpack rootfs image as initramfs...\n");err = unpack_to_rootfs((char *)initrd_start, initrd_end - initrd_start);if (!err) {free_initrd();goto done;} else {clean_rootfs();unpack_to_rootfs(__initramfs_start, __initramfs_size);}printk(KERN_INFO "rootfs image is not initramfs (%s); looks like an initrd\n", err);fd = sys_open("/initrd.image", O_WRONLY | O_CREAT, 0700);if (fd >= 0) {sys_write(fd, (char *)initrd_start, initrd_end - initrd_start);sys_close(fd);free_initrd();}done:
#elseprintk(KERN_INFO "Unpacking initramfs...\n");err = unpack_to_rootfs((char *)initrd_start, initrd_end - initrd_start);if (err)printk(KERN_EMERG "Initramfs unpacking failed: %s\n", err);free_initrd();
#endif/** Try loading default modules from initramfs. This gives* us a chance to load before device_initcalls.*/load_default_modules();}return 0;
}
rootfs_initcall(populate_rootfs);
1.2 加载介质驱动的机制
在 initrd 阶段,内核会通过以下机制加载相关的介质驱动:
-
检测根文件系统所在的设备:
- 内核会根据
saved_root_name变量来确定根文件系统所在的设备。这个变量通常由引导加载程序(如 GRUB)传递给内核。
- 内核会根据
-
加载默认模块:
- 在
initrd阶段,内核会尝试加载默认的内核模块,这些模块通常包括识别和访问根文件系统所在介质所需的驱动程序。 - 这些模块可以通过
initrd文件系统中的/linuxrc或/init脚本加载,也可以通过内核的load_default_modules函数加载。
- 在
-
等待设备探测完成:
- 内核会等待根文件系统所在的设备完成探测,以确保设备驱动程序已经加载并准备好使用。
2. 挂载真实文件系统后的用户空间初始化脚本执行
在挂载真实文件系统后,内核会切换到真实文件系统,并执行用户空间的初始化脚本。这个过程主要发生在 prepare_namespace 函数之后。
2.1 挂载真实文件系统
prepare_namespace 函数负责挂载真实文件系统。以下是相关代码:
// fs/namespace.c
void __init prepare_namespace(void)
{int is_floppy;if (root_delay) {printk(KERN_INFO "Waiting %d sec before mounting root device...\n",root_delay);ssleep(root_delay);}wait_for_device_probe();if (saved_root_name[0]) {root_device_name = saved_root_name;if (!strncmp(root_device_name, "mtd", 3) ||!strncmp(root_device_name, "ubi", 3)) {mount_block_root(root_device_name, root_mountflags);goto out;}ROOT_DEV = name_to_dev_t(root_device_name);if (strncmp(root_device_name, "/dev/", 5) == 0)root_device_name += 5;}if (initrd_load())goto out;if ((ROOT_DEV == 0) && root_wait) {printk(KERN_INFO "Waiting for root device %s...\n",saved_root_name);while (driver_probe_done() != 0 ||(ROOT_DEV = name_to_dev_t(saved_root_name)) == 0)msleep(100);async_synchronize_full();}is_floppy = MAJOR(ROOT_DEV) == FLOPPY_MAJOR;if (is_floppy && rd_doload && rd_load_disk(0))ROOT_DEV = Root_RAM0;mount_root();
out:devtmpfs_mount("dev");sys_mount(".", "/", NULL, MS_MOVE, NULL);sys_chroot(".");
}
3. 执行用户空间初始化脚本
3.1 内核中执行用户空间初始化脚本
在 prepare_namespace 函数之后,内核会执行用户空间的初始化脚本。这是通过 kernel_init 函数实现的。以下是相关代码:
// init/main.c
static noinline void __init kernel_init_freeable(void)
{wait_for_completion(&kthreadd_done);gfp_allowed_mask = __GFP_BITS_MASK;set_mems_allowed(node_states[N_MEMORY]);set_cpus_allowed_ptr(current, cpu_all_mask);cad_pid = task_pid(current);smp_prepare_cpus(setup_max_cpus);do_pre_smp_initcalls();lockup_detector_init();smp_init();sched_init_smp();do_basic_setup();if (sys_open((const char __user *) "/dev/console", O_RDWR, 0) < 0)pr_err("Warning: unable to open an initial console.\n");(void) sys_dup(0);(void) sys_dup(0);if (!ramdisk_execute_command)ramdisk_execute_command = "/init";if (sys_access((const char __user *) ramdisk_execute_command, 0) != 0) {ramdisk_execute_command = NULL;prepare_namespace();}load_default_modules();if (ramdisk_execute_command) {run_init_process(ramdisk_execute_command);} else {run_init_process("/sbin/init");}
}
在上述代码中,kernel_init_freeable 函数会检查是否存在用户空间的初始化脚本(如 /linuxrc 或 /init),如果存在,则通过 run_init_process 函数执行该脚本。
3.2 用户空间初始化脚本
用户空间的初始化脚本(如 /linuxrc 或 /init)会在切换到真实文件系统后执行。以下是相关代码:
#!/bin/sh
# /linuxrc# 加载必要的驱动模块
modprobe usb-storage
modprobe scsi_mod
modprobe ext4# 挂载真实文件系统
mount -a# 切换到真实根文件系统
pivot_root /mnt /dev/null
exec switch_root /sbin/init
在上述脚本中,modprobe 命令会加载必要的驱动模块,以便挂载真实文件系统。
4. 加载默认模块
在 initrd 阶段,内核会通过 load_default_modules 函数加载默认的内核模块。这些模块通常包括识别和访问根文件系统所在介质所需的驱动程序。
void __init load_default_modules(void)
{struct module *mod;int err;for_each_module(mod) {if (mod->state == MOD_STATE_LIVE) {err = try_to_load_module(mod->name);if (err)printk(KERN_ERR "Failed to load module %s\n", mod->name);}}
}
pivot_root linux,initrd如何切入linux文件系统
在 Linux 内核中,load_default_modules 函数的主要功能是在系统启动过程中加载一组默认的内核模块,这些模块对于系统的正常运行至关重要。以下是该函数的详细功能说明:
- 加载默认模块
load_default_modules函数负责加载系统启动时所需的一组默认内核模块。这些模块通常包括设备驱动程序、文件系统支持模块以及其他系统服务模块。 - 模块初始化
在内核启动过程中,需要初始化各种组件和驱动程序。load_default_modules函数通过加载必要的模块来确保系统具备所需的驱动和功能,从而保证系统能够正常运行。 - 依赖关系处理
内核模块之间可能存在依赖关系。load_default_modules函数确保这些依赖关系得到正确处理,模块按照正确的顺序加载。这对于系统的稳定性和功能性至关重要。 - 配置文件支持
该函数还会加载由系统配置文件指定的模块。这些配置文件通常位于/etc/modules-load.d/目录下,每个文件包含一个或多个模块名称,系统启动时会自动加载这些模块。 - 内核引导参数支持
除了配置文件,load_default_modules函数还会处理通过内核引导参数指定的模块加载。例如,使用modules_load或rd.modules_load参数可以在启动时加载特定的模块。 - 自动模块加载
对于大多数硬件设备,Linux 内核会自动检测并加载相应的驱动模块。load_default_modules函数通过使用存储在/lib/modules/VERSION/modules.alias中的数据库来实现这一点,该数据库包含了模块与硬件设备之间的映射关系。 - 手动模块加载
如果需要手动加载某个模块,可以使用modprobe命令。该命令会根据模块的依赖关系加载所需的模块,并将其添加到内核中。 - 模块验证
在加载模块时,load_default_modules函数还会执行一些验证操作,确保模块的完整性和兼容性。这包括检查模块的签名和验证 ELF 文件的合法性。 - 模块初始化函数调用
该函数还会调用模块的初始化函数,这些函数通常使用module_init宏进行声明。这些初始化函数负责设置模块的运行环境,使其准备好供系统使用。
load_default_modules 函数在 Linux 内核启动过程中扮演着重要角色,通过加载默认的内核模块,确保系统具备所需的驱动和功能。它不仅处理模块之间的依赖关系,还支持通过配置文件和内核引导参数加载特定模块,从而保证系统的正常运行和硬件设备的正常工作。
4.1 Linux 6.12.5 替代方案 ?
在 Linux 6.12.5 内核中,确实没有 load_default_modules 函数。其替代实现主要通过 systemd-modules-load 服务来完成,该服务在系统启动时自动加载内核模块。
5. 总结
-
虚拟根文件系统中没有
/init
在initrd阶段,如果虚拟根文件系统中没有/init文件,则会执行prepare_namespace函数来挂载真实根文件系统。为了识别根文件系统所在的介质(如 SD、SCSI 等),内核会通过load_default_modules函数加载相关的介质驱动。这些驱动程序确保内核能够正确识别和访问根文件系统所在的设备。 -
虚拟根文件系统中有
/init
在initrd阶段,如果虚拟根文件系统中有/init文件,则不执行prepare_namespace函数来挂载真实根文件系统,真实根文件系统挂载将在/init脚本中进行。代码示例如下:
#!/bin/sh
# /linuxrc# 加载必要的驱动模块
modprobe usb-storage
modprobe scsi_mod
modprobe ext4# 挂载真实文件系统
mount -a# 切换到真实根文件系统
pivot_root /mnt /dev/null
exec switch_root /sbin/init
initrd 典型的系统启动顺序
boot loader加载内核并初始化ram disk
内核把initrd转化成正常的ram disk并释放initrd使用的内存
initrd作为root被挂载,赋予读写权限。
/linuxrc被执行(这可以是任何可执行文件,如脚本,运行在uid 0,可以做任何初始化)。
linuxrc挂载真正的根文件系统
linuxrc使用pivot_root系统调用把根文件系统放在根目录。
正常的启动序列(/sbin/init)在根文件系统上执行。
initrd文件系统被移去。
☆
相关文章:
Linux 文件系统挂载
系列文章目录 Linux内核学习 Linux 知识(1) Linux 知识(2) WSL Ubuntu QEMU 虚拟机 Linux 调试视频 PCIe 与 USB 的补充知识 vscode 使用说明 树莓派 4B 指南 设备驱动畅想 Linux内核子系统 Linux 文件系统挂载 文章目录 系列文章…...
Qt QSpinBox 总结
Qt5 QSpinBox 总结 1. 基本特性 用途:用于输入和调整整数值,支持通过上下箭头、键盘输入或编程方式修改值。 默认范围:0 到 99,可通过 setRange(min, max) 自定义。 步长控制:setSingleStep(step) 设置单步增减值&a…...
【OJ项目】深入剖析题目接口控制器:功能、实现与应用
《深入剖析题目接口控制器:功能、实现与应用》 一、引言 在在线编程平台或竞赛系统中,题目管理和提交是核心功能之一。QuestionController 类作为控制器层,承担着处理与题目相关的各种请求的重要职责,包括题目的增删改查、题目提…...
周考考题(学习自用)
1.查询student表中name叫张某的信息 select * from student where name张某; 2.写出char和varchar类型的区别 1)char存储固定长度的字符串,varchar存储可变长度的字符串(在实际长度的字符串上加上一个字节用于存储字符串长度)&a…...
【matlab】大小键盘对应的Kbname
matlab中可以通过Kbname来识别键盘上的键。在写范式的时候,遇到一个问题,我想用大键盘上排成一行的数字按键评分,比如 Kbname(1) 表示键盘上的数字1,但是这种写法只能识别小键盘上的数字,无法达到我的目的,…...
LabVIEW与小众设备集成
在LabVIEW开发中,当面临控制如布鲁克OPUS红外光谱仪这类小众专业设备的需求,而厂家虽然提供了配套软件,但由于系统中还需要控制其他设备且不能使用厂商的软件时,必须依赖特定方法通过LabVIEW实现设备的控制。开发过程中࿰…...
Android 系统Service流程
主要用到的源码文件 /frameworks/base/core/java/android/app/ContextImpl.java 和ams通信。 /frameworks/base/services/core/java/com/android/server/am/ActivityManagerService.java 初始化Service,.管理服务 ActiveServices对象mServices /frameworks/base/services/core/…...
Gartner预测2025年网络安全正在进入AI动荡时期:软件供应链和基础设施技术堆栈中毒将占针对企业使用的人工智能恶意攻击的 70% 以上
Gartner 预测,网络安全正在进入 AI 动荡时期。安全和风险管理领导者必须根据早期生成式 AI 部署的失败以及 AI 代理清洗来评估即将到来的 AI 进展。 主要发现 随着各大企业开展大量人工智能采用和开发项目,应用安全弱点的暴露程度不断提高,包…...
华为最新OD机试真题-最长子字符串的长度(一)-Python-OD统一考试(E卷)
最新华为OD机试考点合集:华为OD机试2024年真题题库(E卷+D卷+C卷)_华为od机试题库-CSDN博客 每一题都含有详细的解题思路和代码注释,精编c++、JAVA、Python三种语言解法。帮助每一位考生轻松、高效刷题。订阅后永久可看,发现新题及时跟新。 题目描述: 给你一个字符串…...
HAL库框架学习总结
概述:HAL库为各种外设基本都配了三套 API,查询,中断和 DMA。 一、HAL库为外设初始化提供了一套框架,这里以串口为例进行说明,调用函数 HAL_UART_Init初始化串口,此函数就会调用 HAL_UART_MspInit࿰…...
基于Spring Integration的ESB与Kettle结合实现实时数据处理技术
一、方案概述 在当今数字化时代,企业面临着海量数据的实时处理与传输挑战。ESB(企业服务总线)作为系统集成的核心组件,承担着不同协议数据的接入与转换任务,而Kettle作为一款功能强大的ETL(Extract, Transform, Load)工具,在数据抽取、转换与加载方面表现出色。将ESB与…...
qt QOpenGLContext详解
1. 概述 QOpenGLContext 是 Qt 提供的一个类,用于管理 OpenGL 上下文。它封装了 OpenGL 上下文的创建、配置和管理功能,使得开发者可以在 Qt 应用程序中以平台无关的方式使用 OpenGL。通过 QOpenGLContext,可以轻松地创建和管理 OpenGL 上下…...
探索顶级汽车软件解决方案:驱动行业变革的关键力量
在本文中,将一同探索当今塑造汽车行业的最具影响力的软件解决方案。从设计到制造,软件正彻底改变车辆的制造与维护方式。让我们深入了解这个充满活力领域中的关键技术。 设计软件:创新车型的孕育摇篮 车辆设计软件对于创造创新型汽车模型至…...
Deepseek R1模型本地化部署+API接口调用详细教程:释放AI生产力
文章目录 前言一、deepseek R1模型与chatGPT o1系列模型对比二、本地部署步骤1.安装ollama2部署DeepSeek R1模型删除已存在模型,以7b模型为例 三、DeepSeek API接口调用Cline配置 前言 随着最近人工智能 DeepSeek 的爆火,越来越多的技术大佬们开始关注如…...
DeepSeek 概述与本地化部署【详细流程】
目录 一、引言 1.1 背景介绍 1.2 本地化部署的优势 二、deepseek概述 2.1 功能特点 2.2 核心优势 三、本地部署流程 3.1 版本选择 3.2 部署过程 3.2.1 下载Ollama 3.2.2 安装Ollama 3.2.3 选择 r1 模型 3.2.4 选择版本 3.2.5 本地运行deepseek模型 3.3.6 查看…...
FFmpeg Video options
FFmpeg视频相关选项 1. -vframes number (output) 设置输出视频帧数 示例: ffmpeg -i input.mp4 -vframes 90 output.mp4 表示输出90帧视频 2. -r[:stream_specifier] fps (input/output,per-stream) 设置帧率(rate) 示例: ffmpeg -i input.mp4…...
从51到STM32:PWM平滑迁移方案
引言 对于习惯使用51单片机的开发者而言,转向STM32时可能会面临开发环境和硬件差异的挑战。本文以PWM(脉宽调制)功能为例,分享从51到STM32的平滑迁移方案,帮助开发者快速适应STM32的开发模式。 一、PWM实现原理对比 …...
openCV中如何实现滤波
图像滤波用于去除噪声和图像平滑,OpenCV 提供了多种滤波器: 1.1. 均值滤波: import cv2# 读取图像 image cv2.imread("example.jpg")# 均值滤波 blurred_image cv2.blur(image, (5, 5)) # (5, 5) 是滤波核的大小 滤波核大小的…...
BGP配置华为——路由汇总
实验拓扑 实验要求 1.R1,R2,R3间运行BGP,搭建EBGP邻居 2.R3一段的网络实现自动聚合,R1一端的网络实现手动路由聚合 3.启用as-set防环 实验配置 配置相关IP 过程省略,结果如图 R1 R2 R3 配置EBGP [R1]bgp 100 [R1-bgp]router 10.10.1…...
机器学习核心算法解析
机器学习核心算法解析 机器学习是人工智能的核心技术之一,它通过从数据中学习模式并做出预测或决策。本文将深入解析机器学习的核心算法,包括监督学习、无监督学习和强化学习,并通过具体案例和代码示例帮助读者理解这些算法的实际应用。 1. …...
Android Wi-Fi 连接失败日志分析
1. Android wifi 关键日志总结 (1) Wi-Fi 断开 (CTRL-EVENT-DISCONNECTED reason3) 日志相关部分: 06-05 10:48:40.987 943 943 I wpa_supplicant: wlan0: CTRL-EVENT-DISCONNECTED bssid44:9b:c1:57:a8:90 reason3 locally_generated1解析: CTR…...
日语AI面试高效通关秘籍:专业解读与青柚面试智能助攻
在如今就业市场竞争日益激烈的背景下,越来越多的求职者将目光投向了日本及中日双语岗位。但是,一场日语面试往往让许多人感到步履维艰。你是否也曾因为面试官抛出的“刁钻问题”而心生畏惧?面对生疏的日语交流环境,即便提前恶补了…...
C++实现分布式网络通信框架RPC(3)--rpc调用端
目录 一、前言 二、UserServiceRpc_Stub 三、 CallMethod方法的重写 头文件 实现 四、rpc调用端的调用 实现 五、 google::protobuf::RpcController *controller 头文件 实现 六、总结 一、前言 在前边的文章中,我们已经大致实现了rpc服务端的各项功能代…...
SkyWalking 10.2.0 SWCK 配置过程
SkyWalking 10.2.0 & SWCK 配置过程 skywalking oap-server & ui 使用Docker安装在K8S集群以外,K8S集群中的微服务使用initContainer按命名空间将skywalking-java-agent注入到业务容器中。 SWCK有整套的解决方案,全安装在K8S群集中。 具体可参…...
Java如何权衡是使用无序的数组还是有序的数组
在 Java 中,选择有序数组还是无序数组取决于具体场景的性能需求与操作特点。以下是关键权衡因素及决策指南: ⚖️ 核心权衡维度 维度有序数组无序数组查询性能二分查找 O(log n) ✅线性扫描 O(n) ❌插入/删除需移位维护顺序 O(n) ❌直接操作尾部 O(1) ✅内存开销与无序数组相…...
PPT|230页| 制造集团企业供应链端到端的数字化解决方案:从需求到结算的全链路业务闭环构建
制造业采购供应链管理是企业运营的核心环节,供应链协同管理在供应链上下游企业之间建立紧密的合作关系,通过信息共享、资源整合、业务协同等方式,实现供应链的全面管理和优化,提高供应链的效率和透明度,降低供应链的成…...
Cinnamon修改面板小工具图标
Cinnamon开始菜单-CSDN博客 设置模块都是做好的,比GNOME简单得多! 在 applet.js 里增加 const Settings imports.ui.settings;this.settings new Settings.AppletSettings(this, HTYMenusonichy, instance_id); this.settings.bind(menu-icon, menu…...
Linux云原生安全:零信任架构与机密计算
Linux云原生安全:零信任架构与机密计算 构建坚不可摧的云原生防御体系 引言:云原生安全的范式革命 随着云原生技术的普及,安全边界正在从传统的网络边界向工作负载内部转移。Gartner预测,到2025年,零信任架构将成为超…...
论文浅尝 | 基于判别指令微调生成式大语言模型的知识图谱补全方法(ISWC2024)
笔记整理:刘治强,浙江大学硕士生,研究方向为知识图谱表示学习,大语言模型 论文链接:http://arxiv.org/abs/2407.16127 发表会议:ISWC 2024 1. 动机 传统的知识图谱补全(KGC)模型通过…...
tree 树组件大数据卡顿问题优化
问题背景 项目中有用到树组件用来做文件目录,但是由于这个树组件的节点越来越多,导致页面在滚动这个树组件的时候浏览器就很容易卡死。这种问题基本上都是因为dom节点太多,导致的浏览器卡顿,这里很明显就需要用到虚拟列表的技术&…...
