Devido à carga de trabalho de especialistas, vários anos atrás, fomos forçados a dar um desenvolvimento às contrapartes. O desenvolvimento foi realizado no módulo Enclustra Mars ZX3, que usa o SOC ARM + FPGA Zynq-7020. Para construir o Linux, usamos o Bcl da Enclustra (bsp-xilinx), que foi ligeiramente modificado.
No processo de teste do software desenvolvido, encontramos imediatamente falhas de software quando a energia foi desligada. Durante a análise, verificou-se que os comandos de configuração enviados ao dispositivo pela rede foram gravados em arquivos que, quando ocorria uma falha de energia, às vezes eram vazios ou ausentes. Isso nos forçou a reconsiderar a ideologia de construir o assembly Linux que nos foi entregue. O processo de construção do sistema em si está bem descrito no
site do fabricante do módulo, por isso não vou insistir nele. Descreverei apenas o que nos permitiu resolver a tarefa diante de nós, aumentando a confiabilidade e prevenindo falhas.
O módulo Mars ZX3 possui chips QSPI Flash e NAND Flash. No nosso caso, o módulo é carregado com o QSPI Flash, no qual o U-Boot foi gravado. Como os dois chips usam os mesmos pinos Zynq-7020, após o carregamento, o U-Boot alterna os pinos para o NAND Flash, em que seções de inicialização, Árvore de dispositivos, kernel Linux, sistema de arquivos ubifs e variáveis de ambiente são gravadas em seções separadas. Além disso, todas as seções, exceto a seção com variáveis de ambiente, foram reservadas (ou seja, havia duas seções). A seguir, um fragmento do arquivo Device Tree, que mostra como o NAND Flash foi quebrado na versão que nos foi transmitida pelos contratados:
partition@nand-linux { label = "nand-linux"; reg = <0x0 0x500000>; }; partition@nand-device-tree { label = "nand-device-tree"; reg = <0x500000 0x100000>; }; partition@nand-bootscript { label = "nand-bootscript"; reg = <0x600000 0x100000>; }; partition@nand-linux-second { label = "nand-linux-second"; reg = <0x700000 0x500000>; }; partition@nand-device-tree-second { label = "nand-device-tree"; reg = <0xC00000 0x100000>; }; partition@nand-bootscript-second { label = "nand-bootscript"; reg = <0xD00000 0x100000>; }; partition@nand-rootfs { label = "nand-rootfs"; reg = <0xE00000 0xF500000>; }; partition@nand-rootfs-second { label = "nand-rootfs"; reg = <0x10300000 0xF500000>; }; partition@boot-env { label = "nand-env"; reg = <0x1F800000 0x100000>; };
As segundas seções deveriam ser usadas quando as seções principais falharam. Para fazer isso, o Linux precisou implementar um processo que monitora a integridade do sistema e, no caso de uma falha, grava um valor na variável de ambiente que instrui a iniciar o sistema a partir das partições de backup. Este algoritmo deveria ser implementado no futuro.
Os dados de configuração foram registrados em duas pastas para backup, mas isso não salvou a situação. Supõe-se que, na ausência de arquivos de configuração, eles sejam criados novamente automaticamente, com as configurações padrão.
O problema é que o NAND Flash grava dados uma página de cada vez e a exclusão ocorre em blocos. Portanto, se ocorrer uma falha de energia durante a gravação dos dados, não apenas esses dados serão corrompidos, mas o sistema de arquivos poderá ser danificado. Iniciar um sistema de backup pode atrasar apenas a ocorrência de um problema. Embora neste caso seja possível realizar a restauração das principais partições a partir das de backup.
Decidimos seguir o outro caminho, montando o rootfs como um sistema de arquivos somente leitura e gravando arquivos de configuração para separar
as seções de
dados e
backup que foram montadas para leitura e gravação. Nesse caso, a necessidade de partições de backup desaparece, mas as deixamos para o futuro, pois a quantidade de memória nos permitiu fazer isso. Se necessário, eles podem ser excluídos.
Como resultado, foi realizado o seguinte particionamento NAND Flash:
partition@nand-linux { label = "nand-linux"; reg = <0x0 0x500000>; }; partition@nand-device-tree { label = "nand-device-tree"; reg = <0x500000 0x100000>; }; partition@nand-bootscript { label = "nand-bootscript"; reg = <0x600000 0x100000>; }; partition@nand-linux-second { label = "nand-linux-second"; reg = <0x700000 0x500000>; }; partition@nand-device-tree-second { label = "nand-device-tree"; reg = <0xC00000 0x100000>; }; partition@nand-bootscript-second { label = "nand-bootscript"; reg = <0xD00000 0x100000>; }; partition@nand-rootfs { label = "nand-rootfs"; reg = <0xE00000 0x9600000>; }; partition@nand-rootfs-second { label = "nand-rootfs"; reg = <0xA400000 0x9600000>; }; partition@nand-data { label = "nand-data"; reg = <0x13A00000 0x5F00000>; }; partition@nand-data-backup { label = "nand-data-backup"; reg = <0x19900000 0x5F00000>; }; partition@boot-env { label = "nand-env"; reg = <0x1F800000 0x100000>; };
Ao piscar NAND Flash usando o comando U-Boot, apagamos as seções
nand-data e
nand-data-backup :
u-boot>nand erase.part nand-data u-boot>nand erase.part nand-data-backup
No script de inicialização do Linux, implementamos a montagem do sistema de arquivos raiz como Somente Leitura, substituindo a linha no arquivo / etc / inittab no assembly Linux:
::sysinit:/bin/mount -o remount,rw /
em
::sysinit:/bin/mount -o remount,ro /
Adicionamos um script de inicialização à pasta
/etc/init.d/ , que monta as seções
nand-data e
nand-data-backup para leitura e gravação. No caso de um erro de montagem (durante a primeira inicialização ou se o sistema de arquivos estiver danificado), essas partições são formatadas e remontadas. As pastas
/ mnt / data / e
/ mnt / backup / devem ser criadas anteriormente no sistema de arquivos raiz.
Ao fazer o download, se os arquivos de configuração na pasta
/ mnt / data / estiverem ausentes, eles serão baixados da pasta
/ mnt / backup / . Se não houver arquivos de configuração em
/ mnt / backup / , eles serão criados automaticamente a partir do software com parâmetros padrão. Se os arquivos estiverem presentes em
/ mnt / data / mas não em
/ mnt / backup / , eles serão copiados de
/ mnt / data / para
/ mnt / backup / . Todas essas operações são executadas pelo software do usuário.
No estágio seguinte, para aumentar a confiabilidade, recusamos gravar a configuração em um arquivo para cada comando. A configuração inteira agora está armazenada na RAM e, se necessário, por um comando separado pode ser salva em arquivos nas pastas
/ mnt / data / e
/ mnt / backup / .
Se, durante o trabalho, você precisar fazer alterações no sistema de arquivos raiz sem atualizar o dispositivo, poderá remontar o sistema no console para ler e escrever com o comando
mount -o remount,rw /
Faça as alterações e remonte novamente em Somente leitura:
mount -o remount,ro /