在工业生产中,固件烧写是确保产品正常运行的关键环节。
然而,在实际应用中,由于Linux系统文件写入的异步性,可能导致固件烧写不完全,从而影响设备的正常启动和运行。
本文将通过一个实际案例,揭示Linux系统下因文件写入异步性导致的固件烧写问题,并探讨相应的解决方案。
在某客户产线的批量生产过程中,采用SD卡进行固件烧写。
烧写完成后,蜂鸣器提示产线工人可以进行下一步操作,工人听到蜂鸣器鸣叫后立即断电重启设备并进入测试环节。
然而,在后续测试中发现部分产品在启动时出现异常。
进一步分析发现,客户采用解压方式烧写系统固件:
解压命令执行完毕。运行一个二进制可执行程序。蜂鸣器鸣叫,提示烧写完成。
从逻辑上看,该流程似乎没有问题。然而,问题仍然高概率出现。经过深入排查,发现可执行程序内部还存在二次解压操作,并且使用 system() 调用了 Linux Shell 命令。
system() 产生一个新的子进程,使得蜂鸣器鸣叫与二次解压分别在不同进程中执行,两者没有严格的先后顺序。
按照蜂鸣器鸣叫即断电重启的操作逻辑,就可能导致解压尚未完成时设备被重启,最终引发文件烧写不完整,导致系统启动异常。
Linux系统采用页高速缓存(Page Cache)机制,对写入的内容进行缓存。用户的写入操作实际上会被延迟提交,称为“脏数据(Dirty Data)”。
脏页数据回写磁盘的情况包括:
当空闲内存低于特定阈值时,内核必须将脏页写回磁盘以释放内存。当脏页在内存中驻留时间超过特定阈值时,内核执行回写操作,防止脏页无限期驻留。当用户进程调用 sync() 或 fsync() 系统调用时,内核按照指令强制回写数据。
如果解压脚本未包含 sync 指令,或程序未在解压或写入后调用 fsync(),系统会依赖上述默认回写机制。
如果在脏页尚未回写到存储设备时发生断电,则文件内容可能不完整,导致启动异常。
针对上述问题,可采取以下措施确保数据完整性:
在更新脚本中增加同步操作
在解压固件后立即执行 sync 命令,确保数据写入磁盘。
在应用程序代码中使用 fsync()
在执行文件写入操作后,显式调用 fsync(fd) 确保数据同步写入存储设备。
避免 system() 方式调用关键操作
system() 可能导致并发执行,建议使用 execv() 等更可控的方式执行命令,确保任务执行的顺序。
采用日志型文件系统(如ext4带journaling)
使用支持日志功能的文件系统,可降低异常断电导致的数据损坏风险。
优化断电策略
生产流程可改为在系统自检完成后再发出蜂鸣器提示,避免人为误操作。
通过以上优化,可有效减少因文件写入异步性带来的固件烧写问题,提高工业生产的可靠性。