在工业生产中,固件烧写是确保产品正常运行的关键环节。本文通过一个实际案例,揭示了Linux系统下因文件写入异步性导致的固件烧写不完全问题。
客户案例
客户产线上批量生产时,用SD卡进行固件烧写,烧写完成后蜂鸣器提示,产线工人听到蜂鸣器鸣叫后就直接断电重启,进入测试环节,结果在测试中发现有部分产品启动就出现异常。客户用解压方式烧写系统固件,解压命令执行完后,再运行一个二进制可执行程序,然后鸣叫蜂鸣器。乍一看逻辑非常正确,没有任何问题。
可问题却较高概率出现,问题出在哪里呢?
后来经过反复排查,发现客户解压脚本里的可执行程序里面还有二次解压操作,而且用system()调用了Linux的Shell命令。
System()调用Shell命令会生成一个新的子进程,这样蜂鸣器鸣叫和二次解压分别在不同进程中,两者没有同步,解压完成和蜂鸣器鸣叫没有必然的先后顺序。按照蜂鸣器鸣叫就断电重启,这样就不可避免的出现了解压尚未完成就被断电的情况,从而引起文件烧写不完全,系统启动异常。下面围绕该问题,对Linux文件系统写文件操作进行一些说明。
原理说明
由于Linux系统存在页高速缓存,对写入的内容起到了缓存作用,用户的写操作实际上会被延迟。当页高速缓存中的数据比后台存储的数据新的时候,这些数据就被称作脏数据。发生以下三种情况时,脏页才会被写回磁盘:
- 当空闲内存低于一个特定的阈值时,内核必须将脏页写回磁盘以释放内存。当脏页在内存中驻留时间超过一个特定的阈值时,内核必须将超时的脏页写回磁盘,以确保脏页不会无限期地驻留在内存中。当用户进程调用 sync() 和 fsync() 系统调用时,内核会按照要求执行回写操作。
应对方案
如果更新脚本在解压命令后没有sync指令,或者程序更新代码在执行解压或者写操作后没有调用fsync()函数执行写操作,Linux系统就会按照默认机制来实现写操作;如果没有达到如上前2个条件,发生了断电操作,则会导致写入数据不完整。
在程序更新脚本里,解压后必须执行sync指令完成写入同步,或者应用程序代码在写操作后调用fsync()函数完成写同步操作,确保数据写入存储器。
国产芯嵌入式高性能RISC-V核心板MR6450/6750 | |
• 15路串口
• 4路CANFD • 2路千兆 |