驱动、bootloader、文件系统

嵌入式 Linux 系统工程 047:缓冲写入、fsync 与掉电一致性

展开合集目录
  1. 嵌入式 Linux 系统工程 001:Linux 系统分层与资源地图
  2. 嵌入式 Linux 系统工程 002:主机、目标板与交叉开发
  3. 嵌入式 Linux 系统工程 003:架构、ABI、大小端与工具链
  4. 嵌入式 Linux 系统工程 004:Shell、管道、重定向与退出码
  5. 嵌入式 Linux 系统工程 005:BusyBox 与 GNU 工具差异
  6. 嵌入式 Linux 系统工程 006:目录结构与虚拟文件系统
  7. 嵌入式 Linux 系统工程 007:串口、SSH 与开发网络
  8. 嵌入式 Linux 系统工程 008:建立开发板信息与版本基线
  9. 嵌入式 Linux 系统工程 009:从 Boot ROM 到用户空间
  10. 嵌入式 Linux 系统工程 010:U-Boot 环境与内核启动参数
  11. 嵌入式 Linux 系统工程 011:内核配置、编译与模块
  12. 嵌入式 Linux 系统工程 012:设备树编译、加载与生效确认
  13. 嵌入式 Linux 系统工程 013:根文件系统与 initramfs
  14. 嵌入式 Linux 系统工程 014:BusyBox init、启动脚本与 systemd
  15. 嵌入式 Linux 系统工程 015:Buildroot 工程构建与定制
  16. 嵌入式 Linux 系统工程 016:Yocto 的 layer、recipe 与镜像
  17. 嵌入式 Linux 系统工程 017:读懂 procfs 的系统与进程信息
  18. 嵌入式 Linux 系统工程 018:sysfs:设备、属性与拓扑
  19. 嵌入式 Linux 系统工程 019:设备节点、设备号与动态管理
  20. 嵌入式 Linux 系统工程 020:debugfs、tracefs 与配置依赖
  21. 嵌入式 Linux 系统工程 021:内核日志、用户日志与时间线
  22. 嵌入式 Linux 系统工程 022:uptime、负载与基础状态
  23. 嵌入式 Linux 系统工程 023:系统快照与版本对照
  24. 嵌入式 Linux 系统工程 024:工具、权限和内核能力的辨别
  25. 嵌入式 Linux 系统工程 025:进程生命周期与状态
  26. 嵌入式 Linux 系统工程 026:线程、TID 与共享资源
  27. 嵌入式 Linux 系统工程 027:调度策略、nice 与实时优先级
  28. 嵌入式 Linux 系统工程 028:CPU 亲和性与多核
  29. 嵌入式 Linux 系统工程 029:上下文切换、抢占与唤醒延迟
  30. 嵌入式 Linux 系统工程 030:信号与有序退出
  31. 嵌入式 Linux 系统工程 031:僵尸进程与子进程回收
  32. 嵌入式 Linux 系统工程 032:高 CPU、低 CPU 卡顿与 D 状态
  33. 嵌入式 Linux 系统工程 033:虚拟地址、物理内存与映射
  34. 嵌入式 Linux 系统工程 034:栈、堆、malloc 与 mmap
  35. 嵌入式 Linux 系统工程 035:RSS、PSS 与共享内存统计
  36. 嵌入式 Linux 系统工程 036:页缓存、回收、swap 与内存压力
  37. 嵌入式 Linux 系统工程 037:slab 与内核内存
  38. 嵌入式 Linux 系统工程 038:CMA、保留内存与厂商缓冲池
  39. 嵌入式 Linux 系统工程 039:OOM、碎片与分配失败
  40. 嵌入式 Linux 系统工程 040:内存泄漏、越界与峰值
  41. 嵌入式 Linux 系统工程 041:文件描述符与打开文件状态
  42. 嵌入式 Linux 系统工程 042:权限、属主、umask 与链接
  43. 嵌入式 Linux 系统工程 043:VFS、挂载点与文件系统
  44. 嵌入式 Linux 系统工程 044:块设备、分区、eMMC 与 SD
  45. 嵌入式 Linux 系统工程 045:MTD、NOR、NAND、UBI 与 UBIFS
  46. 嵌入式 Linux 系统工程 046:SquashFS、OverlayFS 与只读系统
  47. 嵌入式 Linux 系统工程 047:缓冲写入、fsync 与掉电一致性
  48. 嵌入式 Linux 系统工程 048:空间满、inode 耗尽与 I/O 慢
  49. 嵌入式 Linux 系统工程 049:阻塞、非阻塞与短读写
  50. 嵌入式 Linux 系统工程 050:select、poll 与 epoll
  51. 嵌入式 Linux 系统工程 051:pipe、FIFO 与 Unix socket
  52. 嵌入式 Linux 系统工程 052:共享内存与消息队列
  53. 嵌入式 Linux 系统工程 053:mutex、条件变量与信号量
  54. 嵌入式 Linux 系统工程 054:原子操作、内存序与数据竞争
  55. 嵌入式 Linux 系统工程 055:eventfd、timerfd 与 signalfd
  56. 嵌入式 Linux 系统工程 056:死锁、优先级反转与队列背压
  57. 嵌入式 Linux 系统工程 057:device、driver、bus 与绑定
  58. 嵌入式 Linux 系统工程 058:platform、设备树与 probe
  59. 嵌入式 Linux 系统工程 059:模块、固件加载与版本匹配
  60. 嵌入式 Linux 系统工程 060:MMIO 与资源申请
  61. 嵌入式 Linux 系统工程 061:IRQ、软中断与工作队列
  62. 嵌入式 Linux 系统工程 062:GPIO、pinctrl 与有效电平
  63. 嵌入式 Linux 系统工程 063:clock、reset、regulator 与生命周期
  64. 嵌入式 Linux 系统工程 064:DMA、IOMMU 与缓存所有权
  65. 嵌入式 Linux 系统工程 065:UART、termios 与串口使用
  66. 嵌入式 Linux 系统工程 066:I²C 设备、事务与访问工具
  67. 嵌入式 Linux 系统工程 067:SPI、spidev 与传输
  68. 嵌入式 Linux 系统工程 068:GPIO 字符设备与事件
  69. 嵌入式 Linux 系统工程 069:PWM、定时器与控制输出
  70. 嵌入式 Linux 系统工程 070:ADC、传感器与 IIO
  71. 嵌入式 Linux 系统工程 071:input、按键与触摸事件
  72. 嵌入式 Linux 系统工程 072:CAN、SocketCAN 与错误状态
  73. 嵌入式 Linux 系统工程 073:USB 枚举、描述符与端点
  74. 嵌入式 Linux 系统工程 074:USB Host、Gadget 与 UVC
  75. 嵌入式 Linux 系统工程 075:PCIe 枚举、BAR、MSI 与 DMA
  76. 嵌入式 Linux 系统工程 076:V4L2 采集与缓冲队列
  77. 嵌入式 Linux 系统工程 077:Media Controller 与摄像头拓扑
  78. 嵌入式 Linux 系统工程 078:ALSA、PCM 与音频欠载
  79. 嵌入式 Linux 系统工程 079:DRM、KMS 与显示缓冲
  80. 嵌入式 Linux 系统工程 080:厂商视频 SDK 与 NPU 资源
  81. 嵌入式 Linux 系统工程 081:网卡、MAC、PHY 与链路状态
  82. 嵌入式 Linux 系统工程 082:IP、子网、路由与邻居表
  83. 嵌入式 Linux 系统工程 083:DHCP、DNS 与时间同步
  84. 嵌入式 Linux 系统工程 084:TCP、UDP 与 socket 缓冲
  85. 嵌入式 Linux 系统工程 085:ss、抓包与协议分析
  86. 嵌入式 Linux 系统工程 086:吞吐、重传、MTU 与延迟
  87. 嵌入式 Linux 系统工程 087:Wi-Fi、蜂窝模块与重连
  88. 嵌入式 Linux 系统工程 088:防火墙、转发、NAT 与隔离
  89. 嵌入式 Linux 系统工程 089:交叉编译、sysroot 与 pkg-config
  90. 嵌入式 Linux 系统工程 090:Make、CMake 与可重复构建
  91. 嵌入式 Linux 系统工程 091:ELF、库与动态加载器
  92. 嵌入式 Linux 系统工程 092:程序无法启动的分层排查
  93. 嵌入式 Linux 系统工程 093:配置、日志与错误处理
  94. 嵌入式 Linux 系统工程 094:服务管理、依赖与恢复
  95. 嵌入式 Linux 系统工程 095:capabilities 与设备访问
  96. 嵌入式 Linux 系统工程 096:软件包、升级与回退
  97. 嵌入式 Linux 系统工程 097:strace 定位系统调用问题
  98. 嵌入式 Linux 系统工程 098:GDB 与 gdbserver
  99. 嵌入式 Linux 系统工程 099:core dump、符号与回溯
  100. 嵌入式 Linux 系统工程 100:ASan、UBSan 与内存错误
  101. 嵌入式 Linux 系统工程 101:perf 与采样分析
  102. 嵌入式 Linux 系统工程 102:ftrace、tracepoints 与时序
  103. 嵌入式 Linux 系统工程 103:eBPF 的用途、条件与替代方案
  104. 嵌入式 Linux 系统工程 104:联合定位性能瓶颈
  105. 嵌入式 Linux 系统工程 105:Oops、panic 与内核调用栈
  106. 嵌入式 Linux 系统工程 106:hung task、soft lockup 与 hard lockup
  107. 嵌入式 Linux 系统工程 107:锁检查与内核调试配置
  108. 嵌入式 Linux 系统工程 108:PREEMPT_RT 与实时延迟
  109. 嵌入式 Linux 系统工程 109:时钟源、时间戳与对齐
  110. 嵌入式 Linux 系统工程 110:频率、温度与降频
  111. 嵌入式 Linux 系统工程 111:suspend、runtime PM 与唤醒
  112. 嵌入式 Linux 系统工程 112:watchdog、pstore 与故障现场
  113. 嵌入式 Linux 系统工程 113:cgroups、限制与资源压力
  114. 嵌入式 Linux 系统工程 114:namespaces、容器与设备访问
  115. 嵌入式 Linux 系统工程 115:案例:启动和根文件系统失败
  116. 嵌入式 Linux 系统工程 116:案例:摄像头无图、花屏与丢帧
  117. 嵌入式 Linux 系统工程 117:案例:NPU 变慢与缓冲分配失败
  118. 嵌入式 Linux 系统工程 118:案例:网络视频卡顿与帧龄
  119. 嵌入式 Linux 系统工程 119:案例:长期运行的内存与句柄增长
  120. 嵌入式 Linux 系统工程 120:整机验收与故障报告
嵌入式 Linux 系统工程 047:缓冲写入、fsync 与掉电一致性的封面

第 47 / 120 课 · 文件、存储与持久化。返回课程合集。

机制与资源关系

write 成功通常表示数据进入内核处理路径,不一定到达非易失介质。持久化还涉及文件系统、块层及设备缓存。用临时文件替换配置时,应考虑文件同步、rename 和父目录同步,且确认文件系统支持。

缓冲写入、fsync 与掉电一致性的观察路径

实际用法与观察入口

以下是操作说明;先确认执行环境、工具帮助和目标对象。设备名、PID、地址及项目名示例需要按实际替换,不能将整段命令当通用板端脚本执行。

# 查看当前文件系统和挂载条件
cat /proc/mounts
# 配套实验仅操作临时目录
sh run.sh

输出解读与排查顺序

应用崩溃一致性与真实掉电一致性不同。实验可以验证调用和正常重启读取,不能证明电源切断后的介质行为。不要用全局 sync 的耗时推算单个文件的写入延迟。

情境推演

配置写到一半进程崩溃可能留下半文件。临时文件写完并同步后再替换名称,可改进更新协议;目录同步与存储设备持久化保证仍需按实际文件系统和硬件验证。

练习与参考分析

运行临时文件→fsync→rename→目录 fsync 示例。参考结论:原子替换名称和保证掉电持久性是不同要求,真实产品仍需受控掉电验证。

独立实验包

主机 Linux 的有界 C 实验;不访问真实外设,不代表板端时序或性能。 默认入口、源文件和实际运行记录都在下载包中。

实验:缓冲写入、fsync 与掉电一致性

查看完整代码:main.c
#define _GNU_SOURCE
#include <assert.h>
#include <errno.h>
#include <fcntl.h>
#include <pthread.h>
#include <signal.h>
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/mman.h>
#include <sys/socket.h>
#include <sys/wait.h>
#include <time.h>
#include <unistd.h>

#define CHECK(x) do { if (!(x)) { fprintf(stderr, "check failed: %s at line %d (errno=%d)\n", #x, __LINE__, errno); exit(EXIT_FAILURE); } } while (0)

int main(void) {
    int fd = open("config.tmp", O_WRONLY | O_CREAT | O_EXCL, 0600); CHECK(fd >= 0);
    const char data[] = "version=2\n";
    CHECK(write(fd, data, sizeof(data)-1) == (ssize_t)(sizeof(data)-1));
    CHECK(fsync(fd) == 0); CHECK(close(fd) == 0);
    CHECK(rename("config.tmp", "config.txt") == 0);
    int dir = open(".", O_RDONLY | O_DIRECTORY); CHECK(dir >= 0);
    CHECK(fsync(dir) == 0); CHECK(close(dir) == 0);
    fd = open("config.txt", O_RDONLY); CHECK(fd >= 0);
    char result[sizeof(data)] = {0};
    CHECK(read(fd, result, sizeof(result)-1) == (ssize_t)(sizeof(data)-1));
    CHECK(strcmp(result, data) == 0); CHECK(close(fd) == 0);
    puts("file fsync -> rename -> directory fsync passed; no power-cut test");
    return 0;
}
下载代码

在项目根目录执行;下载包解压后,在解压目录执行 sh run.sh。

cd 'content/posts/驱动、bootloader、文件系统/嵌入式Linux系统工程/047-缓冲写入、fsync 与掉电一致性/code' && sh run.sh

官方资料与版本边界

内核、工具和厂商 BSP 的支持范围需分别核对。参考资料可能对应较新版本;不要据此推定旧 BSP 支持所有接口。

上一课:SquashFS、OverlayFS 与只读系统 · 下一课:空间满、inode 耗尽与 I/O 慢