Estou trabalhando em um sistema Linux embarcado, onde o kernel é 5.10.24 e o UBIFS no MTD é usado.
A equipe de teste fez um teste, que grava um arquivo em disco ( open
, write
, close
em ordem) e depois desliga o sistema. Após ligar, o arquivo do disco está vazio, nenhum dado é realmente gravado. Verifica-se que após a gravação do arquivo, demora cerca de 1 minuto e, em seguida, desliga e liga o sistema, o arquivo é atualizado!
Eu fiz alguns estudos e tive seguidores.
- O ubifs cria um thread do kernel
ubifs_bgt0_0
, que será agendado a cada aproximadamente 30 segundos. Ele gravará o buffer na camada de bloco (talvez eu esteja errado). - O
ubifs_bgt0_0
cronômetro cria para wbuf, o período do cronômetro é definido comodirty_write_interval
, é definido comounsigned int dirty_writeback_interval = 5 * 100; /* centiseconds */
, cerca de 5 segundos. Isto NÃO corresponde ao atraso de 1 minuto relatado pela equipe de teste. - O
/sys/block/mtdblock0/queue/scheduler
é[mq-deadline]
, e/sys/block/mtdblock0/queue/iosched/write_expire
é 5000, 5 segundos.
Com as descobertas acima, acho que o arquivo gravado em UBIFS será gravado em FLASH em 5 segundos. Ciclo de energia antes desse horário causará perda de dados!!
Então, primeiro, corrija-me na análise acima.
Então, quero verificar minha análise alterando os ajustáveis listados em 2
e 3
.
Eu os alterei da seguinte maneira
echo 100 > /proc/sys/vm/dirty_writeback_centisecs
e echo 1000 > /sys/block/mtdblock2/queue/iosched/write_expire
. Quero diminuir a escrita FLASH de 50 segundos para 1 segundo.
Com as alterações acima, executei os testes de gravação de disco e desliguei e liguei o sistema em 2 segundos. Mas, para minha surpresa, o arquivo NÃO está escrito corretamente!
Tentei várias vezes alterando os 2 parâmetros acima para valores diferentes (menos de 50 segundos), mas ainda não consegui gravar os dados no FLASH se o sistema for desligado e ligado em 50 segundos.
Usei o Ftrace para verificar as funções chamadas na escrita do arquivo após o echo 100 /proc/sys/vm/dirty_writeback_centisecs
.
Aqui está o Ftrace por cerca de 10 segundos (após a gravação do arquivo)
######### 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 | }
O arquivo do disco NÃO é gravado após desligar e ligar a energia.
Aqui está o rastreamento da função que obtive 60 segundos após a gravação do arquivo.
# 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 | }
#
O arquivo do disco é gravado corretamente após desligar e ligar a energia.
A diferença do Ftrace parecia ser de cerca de inode
, mas não tenho certeza se há ajuste para isso ou não!
Portanto, devo perder algo importante quando tento ajustar a gravação desse arquivo UBIFS.
Acho que encontrei o botão giratório para fazer a gravação de arquivos funcionar instantaneamente no armazenamento FLASH.
Perdi outro parâmetro definido abaixo
dirty_writeback_interval
, éunsigned int dirty_expire_interval = 30 * 100; /* centiseconds */
.Ao definir e
dirty_writeback_centisecs
para100
(1 segundo), desligue e ligue o sistema 1 segundo após a gravação do arquivo para fazer com que o arquivo seja atualizado corretamente.Preciso ler mais sobre esses parâmetros, até agora ainda não entendi por que
dirty_expire_centisecs
é crítico, ele inicia outro cronômetro para liberar dados sujos???