我正在开发一个嵌入式Linux系统,内核是5.10.24,并且使用MTD上的UBIFS。
测试团队进行了一个测试,即写入磁盘文件(open
依次为write
、 、 ),然后关闭系统电源。close
上电后,磁盘文件为空,没有真正写入数据。发现文件写入后,延迟1分钟左右,然后重启系统,文件就更新了!
我做了一些研究并得到了关注。
- ubifs 创建一个内核线程
ubifs_bgt0_0
,每大约 30 秒调度一次。它将缓冲区写入块层(也许我错了)。 - 为wbuf创建
ubifs_bgt0_0
定时器,定时器的周期设置为dirty_write_interval
,定义为unsigned int dirty_writeback_interval = 5 * 100; /* centiseconds */
,大约5秒。这与测试团队报告的 1 分钟延迟不符。 - 是
/sys/block/mtdblock0/queue/scheduler
,[mq-deadline]
并且/sys/block/mtdblock0/queue/iosched/write_expire
是 5000, 5 秒。
综合以上发现,我认为UBIFS中的文件写入将在5秒内写入FLASH。在此之前重新启动电源将导致数据丢失!
所以请先纠正我上面的分析。
然后,我想通过更改2
和中列出的可调参数来验证我的分析3
。
我将它们更改如下,
echo 100 > /proc/sys/vm/dirty_writeback_centisecs
并且echo 1000 > /sys/block/mtdblock2/queue/iosched/write_expire
. 我想将FLASH写入时间从50秒减少到1秒。
通过上述更改,我运行了磁盘写入测试,并在 2 秒内重新启动系统。但令我惊讶的是,该文件没有正确写入!
我多次尝试将以上2个参数更改为不同的值(小于50秒),但如果系统在50秒内重新上电,我仍然无法将数据写入FLASH。
我使用Ftrace检查了文件写入后调用的函数echo 100 /proc/sys/vm/dirty_writeback_centisecs
。
这是大约10秒的Ftrace(文件写入后)
######### 10 centiseconds
# CPU DURATION FUNCTION CALLS
# | | | | | | |
1) | ubifs_write_iter() {
1) + 18.334 us | ubifs_write_begin();
1) + 10.833 us | ubifs_write_end();
1) + 62.167 us | }
------------------------------------------
1) exe-399 => ubifs_b-72
------------------------------------------
1) | mtd_write() {
1) | mtd_write_oob() {
1) | mtd_write_oob_std() {
1) | emu_nand_write_oob() {
1) ! 491.167 us | nand_do_write();
1) ! 502.000 us | }
1) ! 507.167 us | }
1) ! 512.667 us | }
1) ! 525.667 us | }
电源循环后不会写入磁盘文件。
这是我在文件写入后 60 秒内得到的函数跟踪。
# tracer: function_graph
#
# CPU DURATION FUNCTION CALLS
# | | | | | | |
1) | ubifs_write_iter() {
1) + 20.000 us | ubifs_write_begin();
1) 9.000 us | ubifs_write_end();
1) + 59.166 us | }
------------------------------------------
1) exe-924 => kworker-61
------------------------------------------
1) | ubifs_writepage() {
1) + 49.500 us | ubifs_write_inode();
1) ! 110.000 us | }
1) 3.833 us | ubifs_write_inode();
0) | mtd_write() {
0) | mtd_write_oob() {
0) | mtd_write_oob_std() {
0) | emu_nand_write_oob() {
0) ! 477.666 us | nand_do_write();
0) ! 489.000 us | }
0) ! 493.833 us | }
0) ! 500.000 us | }
0) ! 516.500 us | }
0) | mtd_write() {
0) | mtd_write_oob() {
0) | mtd_write_oob_std() {
0) | emu_nand_write_oob() {
0) ! 459.333 us | nand_do_write();
0) ! 465.667 us | }
0) ! 470.000 us | }
0) ! 474.666 us | }
0) ! 481.500 us | }
1) + 54.333 us | ubifs_write_inode();
1) + 26.000 us | ubifs_write_inode();
1) + 20.666 us | ubifs_write_inode();
1) + 19.834 us | ubifs_write_inode();
1) + 14.000 us | ubifs_write_inode();
1) + 13.667 us | ubifs_write_inode();
1) + 11.500 us | ubifs_write_inode();
1) + 14.333 us | ubifs_write_inode();
0) | mtd_write() {
0) | mtd_write_oob() {
0) | mtd_write_oob_std() {
0) | emu_nand_write_oob() {
0) ! 471.167 us | nand_do_write();
0) ! 481.167 us | }
0) ! 486.500 us | }
0) ! 492.167 us | }
0) ! 506.166 us | }
#
重启后磁盘文件写入正确。
Ftrace 的差异似乎约为inode
,但我不确定是否可以调整!
所以当我尝试调整 UBIFS 文件写入时,我一定错过了一些重要的事情。
我想我找到了可以立即将文件写入闪存的旋钮。
我错过了下面刚刚定义的另一个参数
dirty_writeback_interval
,它是unsigned int dirty_expire_interval = 30 * 100; /* centiseconds */
。通过将其设置为
dirty_writeback_centisecs
(100
1秒),在文件写入后1秒重新启动系统可以使文件正确更新。我需要阅读有关这些参数的更多信息,到目前为止我仍然不清楚为什么
dirty_expire_centisecs
很重要,它是否会启动另一个计时器来刷新脏数据???