Sistemas de arquivo em Linux embarcado — Parte 2

- por Sergio Prado

Categorias: Linux Tags: ,

Na parte 1 desta série de arti­gos, vimos uma intro­dução à sis­temas de arquivo em Linux embar­cado, incluindo os prin­ci­pais tipos de sis­temas de arquivo para dis­pos­i­tivo de bloco, e quando usar cada um deles, além de sis­temas de arquivo com­prim­i­dos, voláteis e via rede.

Nesta segunda parte, estu­dare­mos as memórias flash, o sub-sistema MTD do ker­nel, os prin­ci­pais sis­temas de arquivo para flash, e por fim, ver­e­mos como sele­cionar o mel­hor sis­tema de arquivo para o seu pro­duto com Linux embarcado.

AS MEMÓRIAS FLASH

Algu­mas lim­i­tações diferem as memórias flash de dis­pos­i­tivos de bloco tradi­cionais como HDs e floppy disks.

As memórias flash só podem ser apa­gadas em blo­cos. Estes blo­cos são chama­dos de erase blocks, e podem variar de algu­mas dezenas para algu­mas cen­te­nas de kB. Quando você apaga um bloco da flash, todos os bits assumem tipi­ca­mente o valor 1. Com um bloco apa­gado, você pode escr­ever em qual­quer posição da flash. Porém, se você escr­ever 0 em qual­quer um dos bits de qual­quer posição da flash, você só con­segue fazê-lo voltar para 1 apa­gando todo o bloco cor­re­spon­dente da flash!

Outra lim­i­tação das memórias flash é a quan­ti­dade de vezes que você pode apa­gar e escr­ever nela (program/erase cycles). Esta lim­i­tação, depen­dendo do mod­elo e do fab­ri­cante da flash, pode variar entre 100.000 e 1.000.000 cic­los. Parece muito, mas basta você deixar sua apli­cação fazendo log em memória flash para transformá-la em um peso de papel! É por este motivo que existe uma fun­cional­i­dade chamada wear lev­el­ing, que pode ser imple­men­tada por soft­ware ou dire­ta­mente em chips con­tro­ladores de flash.

Imag­ine um arquivo armazenado em deter­mi­nado bloco da flash. Agora imag­ine que este arquivo é atu­al­izado con­stan­te­mente. Em pouco tempo, aquele bloco da flash será inuti­lizado. Com o “wear lev­el­ing”, este arquivo é rema­peado de tem­pos em tem­pos para out­ros blo­cos da flash, mel­ho­rando a vida útil da memória flash consideravelmente.

Mesmo assim, depois de certo tempo de uso da flash, um ou mais blo­cos serão inuti­liza­dos. Por este motivo, existe uma téc­nica chamada de BBM (Bad Block Man­age­ment). Quando sai de fábrica, as memórias flash já pos­suem gravada nelas uma tabela de bad blocks. Toda camada de soft­ware que tra­balha com memórias flash deve ser capaz de ler e iden­ti­ficar estes bad blocks para não uti­lizar regiões invál­i­das da flash.

As memórias flash podem ainda ser divi­di­das em dois tipos principais:

  • As memórias flash NOR, que pos­suem acesso aleatório para leitura de dados (con­seguem endereçar byte a byte), veloci­dade alta para leitura mas lenta para escrita, baixa den­si­dade (cada byte ocupa mais espaço), menor dura­bil­i­dade e alto custo por MB. É usada prin­ci­pal­mente para armazenar código (sub­sti­tuir as anti­gas memórias ROM).
  • As memórias flash NAND, que pos­suem acesso de leitura ape­nas em blo­cos (para ler um byte pre­cisa ler o bloco cor­re­spon­dente), veloci­dade baixa para leitura mas alta para escrita, alta den­si­dade (cada byte ocupa menos espaço), maior dura­bil­i­dade e baixo custo por MB. É usada prin­ci­pal­mente para armazenar dados.

Muito bem, vimos que as memórias flash são bem difer­entes quando com­para­das com os tradi­cionais dis­pos­i­tivos de bloco. É por este motivo que den­tro do Linux as memórias flash são geren­ci­adas por um sub-sistema sep­a­rado, chamado de MTD (Mem­ory Tech­nol­ogy Devices).

O SUB-SISTEMA MTD

O sub-sistema MTD é divi­dido basi­ca­mente em duas camadas:

mtd Sistemas de arquivo em Linux embarcado   Parte 2

A camada de baixo (MTD chip dri­vers) con­versa dire­ta­mente com o hard­ware, enquanto que a camada de cima (MTD User mod­ules) imple­menta os difer­entes sis­temas de arquivo e mecan­is­mos de acesso à flash.

Cada memória deve ter o seu “MTD chip dri­ver”, para pos­si­bil­i­tar o acesso ao hard­ware da flash. Mas cada sis­tema pode usar um ou mais “MTD User mod­ules”. Cada um deles irá tratar de forma difer­entes a flash. É neste con­texto que as memórias flash tam­bém são chamadas de dis­pos­i­tivos MTD. As par­tições de todos os dis­pos­i­tivos MTD do sis­tema podem ser lis­tadas no Linux com o comando abaixo:

$ cat /proc/mtd
dev:  size     erasesize   name
mtd0: 00080000 00020000  "X-Loader"
mtd1: 001e0000 00020000  "U-Boot"
mtd2: 00020000 00020000  "U-Boot Env"
mtd3: 00400000 00020000  "Kernel"
mtd4: 0f980000 00020000  "File System"

O dri­ver mtd­char imple­menta o módulo “char device” da flash. Ele cria um dis­pos­i­tivo de car­ac­tere para cada dis­pos­i­tivo MTD no sis­tema, nor­mal­mente chamado de /dev/mtdX, onde X é o número da par­tição. Com este módulo, você tem acesso sequen­cial (byte-a-byte) em toda a flash. Além disso, ele disponi­bi­liza coman­dos ioctl() para você poder manip­u­lar a flash (ler infor­mações, apagar/gravar na flash, etc). A prin­ci­pal util­i­dade deste módulo é no geren­ci­a­mento da flash, quando usamos o pacote mtd-utils. Este pacote pos­sui algu­mas fer­ra­men­tas como flash_eraseall para apa­gar todo o dis­pos­i­tivo, flashcp para escr­ever em memórias flash NOR e nand­write para escr­ever um memórias flash NAND. Para mais infor­mações, vis­ite a página do pro­jeto em http://www.linux-mtd.infradead.org/.

O dri­ver mtd­block imple­menta o módulo “block device” da flash. Ele cria um dis­pos­i­tivo de bloco para cada dis­pos­i­tivo MTD no sis­tema, nor­mal­mente nomeado /dev/mtdblockX, onde X é o número da par­tição. Este módulo per­mite acesso de leitura/escrita por bloco, como se fosse um HD mesmo, mas não geren­cia bad blocks e tam­bém não tra­balha com wear lev­el­ing em escritas. Ele pode ser usado para mon­tar um sis­tema de arquivo read-only como o squashfs.

Já se você quiser um sis­tema de arquivo que tra­balhe com todas as lim­i­tações da flash, incluindo bad blocks e wear lev­el­ing, você vai pre­cisar de um sis­tema de arquivo especí­fico para flash.

SISTEMAS DE ARQUIVO PARA FLASH

O JFFS2 é um dos sis­temas de arquivo para flash mais anti­gos ainda em uti­liza­ção. Ele suporta memórias flash NAND e NOR, tra­balha com wear lev­el­ing, algo­ritmo ECC (Error Check­ing and Cor­rec­tion) e com­prime os dados em tempo de exe­cução, econ­o­mizando espaço na flash. Sua prin­ci­pal defi­ciên­cia é a per­for­mance ruim em memórias flash muito grande (> 64MB), prin­ci­pal­mente com relação ao tempo de boot. O JFFS2 não armazena infor­mações da estru­tura de diretórios, isso sig­nifica que para o ker­nel iden­ti­ficar a estru­tura de diretórios e mon­tar uma par­tição JFFS2, ele pre­cisa var­rer toda a flash. Por este motivo, o tempo de boot fica real­mente lento em memórias flash muito grandes. Habil­i­tando no ker­nel a opção CONFIG_JFFS2_SUMMARY reduz dras­ti­ca­mente este tempo de montagem.

O YAFFS2 é um dos suces­sores do JFFS2, com o obje­tivo de cor­ri­gir os prob­le­mas de per­for­mance em memórias flash muito grandes. Tem um tempo de boot rápido, tam­bém tra­balha com wear lev­el­ing e algo­ritmo ECC (Error Check­ing and Cor­rec­tion) para garan­tir a con­fi­a­bil­i­dade dos dados, mas suporta ape­nas memórias flash NAND e não com­prime os dados.

Já o UBIFS (Unsorted Block Images Filesys­tem) é um sis­tema de arquivo para flash mais recente. É con­sid­er­ado a evolução do JFFS2, e tra­balha com vol­umes lógi­cos em cima de dis­pos­i­tivos MTD. Tem todas as van­ta­gens do YAFFS2 e do JFFS2. Sua única desvan­tagem é o over­head de metada­dos. Ou seja, a quan­ti­dade de dados que ele pre­cisa armazenar para con­tro­lar as par­tições pode ser muito grande quando tra­bal­hamos com memórias flash com pouca capaci­dade de armazena­mento. Mas com a capaci­dade das memórias flash aumen­tando cada vez mais, deve se tornar nos próx­i­mos anos o sis­tema de arquivo padrão para dis­pos­i­tivos MTD.

CUIDADOS COM MEMÓRIAS FLASH

Mesmo tra­bal­hando com um sis­tema de arquivo voltado à memórias flash, você pre­cisa tomar alguns cuida­dos para aumen­tar a vida útil do dis­pos­i­tivo, den­tre eles:

  • Não use a memória flash como região de swap!
  • Não use a memória flash para armazena­mento volátil como logs e arquivos tem­porários (use tmpfs nestes casos).
  • Monte seu rootfs como ape­nas leitura, ou use o squashfs, quando possível.
  • Use a opção de mon­tagem ”noa­t­ime” para evi­tar a escrita na flash toda vez que você ler um arquivo.
  • Não use a opção de mon­tagem ”sync” (com esta opção habil­i­tada, uma atu­al­iza­ção no sis­tema de arquivos atu­al­iza ime­di­ata­mente a flash).
  • Você pode decidir se quer ou não usar um sis­tema de arquivo com jour­nal. Com ele aumenta-se a quan­ti­dade de escritas, mas deixa-se o sis­tema mais resistente à prob­le­mas de queda de energia.

EMULANDO DISPOSITIVOS DE BLOCO

Pen­drives e cartões SD/MMC tra­bal­ham com memórias flash. Mas como é que o ker­nel os iden­ti­fica e geren­cia como dis­pos­i­tivos de bloco? Como con­seguimos mon­tar nestes dis­pos­i­tivos sis­temas de arquivo volta­dos à dis­pos­i­tivos de bloco como o ext3?

Isso é pos­sível porque estes dis­pos­i­tivos pos­suem uma con­tro­ladora imple­men­tada em hardware/firmware que emula um dis­pos­i­tivo de bloco em cima da memória flash. Esta con­tro­ladora é que faz o con­t­role de bad blocks e wear lev­el­ing. No nível do sis­tema opera­cional, não temos nen­hum con­t­role sobre esta con­tro­ladora, nem podemos aces­sar dire­ta­mente a memória flash. Ou seja, como não con­hece­mos a qual­i­dade desta con­tro­ladora, é alta­mente recomendável lim­i­tar o número de escritas nestes dispositivos.

ESCOLHENDO UM SISTEMA DE ARQUIVO

Vimos nestes dois arti­gos diver­sas soluções de sis­temas de arquivo para Linux embar­cado. Como escol­her o mel­hor para sua aplicação?

O dia­grama abaixo disponi­bi­lizado pelo pes­soal da Free Elec­trons ilus­tra muito bem este processo de decisão, depen­dendo das neces­si­dades do seu projeto:

selecting fs Sistemas de arquivo em Linux embarcado   Parte 2

Pois é, não tem segredo!

Pro­curei expor nesta série de arti­gos os detal­hes e as car­ac­terís­ti­cas dos prin­ci­pais sis­temas de arquivo usa­dos em Linux embar­cado. Agora é só anal­isar os req­ui­si­tos do seu pro­duto e escol­her o mais ade­quado para sua aplicação.

Um abraço,

Ser­gio Prado

  • http://www.facebook.com/ghmscinema Gus­tavo H M Silva

    Ola sério Prado! Obri­gado por todas as infor­mações. Eu com­prei um mini2440 e final­mente con­segui botar o linux para rodar nele (emb­ora não o que eu que­ria, que­ria o ubuntu server). Que­ria saber, há como rodar um servi­dor WAMP nessa maquin­inha ou é uma coisa bem além do possível

    • http://sergioprado.org/ Ser­gio Prado

      Olá Gus­tavo,

      Real­mente um servi­dor WAMP é muita coisa para a friendl­yARM (talvez rodasse na Beagleboard).

      Em embar­ca­dos nor­mal­mente usamos soluções que con­somem menos recur­sos como o HTTP do Busy­box ou o servi­dor Boa no lugar do Apache e o Sqlite no lugar do MySql.

      Um abraço. 

    • http://cleitonbueno.wordpress.com/ Cleiton Bueno

      Gus­tavo vou expor min­has expe­ri­en­cias com Linux Embarcado.

      Atual­mente estou rodando o Busy­box em um Rasp­berry PI e após tem­pos tes­tando o mel­hor custo x ben­efi­cio focando desem­penho foi a combinação:

      Lighttpd 1.4.32
      PHP 5.4.13
      SQLite 3.7.16.2

      Python 2.7.4 (esse é a parte)

      Fiz como todo fazem com com­pi­lação cruzada, tenho meu tool­chain para ARM con­fig­u­rado, e peguei o código-fonte de todos no site e olha olhada ráp­ida no README peguei as flash impor­tantes para com­pi­lar e gerar minha imagem rootfs do meu embar­cado, e é a con­fig­u­ração final do meu pro­jeto que estou fazendo para a Faculdade.

      O mais tra­bal­hoso foi o lighttpd que usei bas­tante parâmet­ros na linha, e Python dev­ido a alguns serviços que iram rodar que escrevi em Python, já que Perl não tive um bom feed­back com cross-compiling.

  • Onés­simo Falconi

    Boa tarde Ser­gio Prado,

    Pro­curei por diver­sos sites e não con­segui encon­trar uma forma de tes­tar a memória flash com especi­fi­cação: 512MB, HIGH SECTOR LF SPANSION S29GL512N

    Toda vez que ini­cio o sis­tema após atu­alizar o ker­nel ver­são 2.6.22 aparece as lin­has abaixo:(…)Log JFFS2 notice:
    (788) jffs2_get_inode_nodes: Node header CRC failed at 0x145c7
    58.
    {ffff,ffff,ffffffff,d22144a5}
    Returns — [0]
    JFFS2 notice:
    (788) jffs2_get_inode_nodes: Node header CRC failed at 0x145bd64.
    {ffff,ffff,ffffffff,ffffffff}
    PowerFail_InitiaJFFS2
    notice: (788) jffs2_get_inode_nodes: Node header CRC faile
    d at 0x145a998.
    {ffff,ffff,ffffffff,d22144a5}
    lize Returns –
    JFFS2 notice: (788) jffs2_get_inode_nodes: Node header CRC faile
    d at 0x1459fb4.
    {ffff,ffff,ffffffff,ffffffff}
    [0]
    JFFS2 notice:
    (788) jffs2_get_inode_nodes: Node header CRC failed at 0x14595cc.
    {ffff,ffff,ffffffff,ffffffff}
    JFFS2 notice:
    (788) jffs2_get_inode_nodes: Node header CRC failed at 0x1458bf0.
    {ffff,ffff,ffffffff,ffffffff}
    JFFS2 notice:
    (788) jffs2_get_inode_nodes: Node header CRC failed at 0x1458128.
    {ffff,ffff,ffffffff,ffffffff}
    Memory_Initialize
    Returns — [0]
    Memory_OpenLocalFile
    Returns — [0]
    Memory_Initialize
    Returns — [0]
    Mem­ory FRAM
    Returns — [0](…)Como posso tes­tar se a flash está com prob­lema? Existe algum soft­ware para isto ou alguma forma de tes­tar este tipo de erro na ini­cial­iza­ção do sis­tema? Obri­gado e parabéns pelo seu blog que é o  mel­hor con­teúdo que encon­trei sobre o assunto. Os demais sites con­tém muitas infor­mações e não detal­ham tão bem sobre o assunto.

    • http://sergioprado.org/ Ser­gio Prado

      Olá Onés­simo,

      Você pode usar o U-Boot para recriar a tabela de bad blocks da flash:

      MINI2440 # nand scrub
      MINI2440 # nand createbbt

      Um abraço.

  • Onés­simo Falconi

    Boa tarde Ser­gio Prado,

    O prob­lema é que estou tra­bal­hando com MIPS (YAMON) e não com U-Boot. Pre­ciso tes­tar toda a memória flash. Tem como me aju­dar com este MIPS?  Agradeço desde já a sua atenção. 

    Abraço.

    • http://sergioprado.org/ Ser­gio Prado

      Aí com­pli­cou. Se o fab­ri­cante não fornece nen­huma fer­ra­menta para for­matar a flash e criar a tabela de bad blocks (via JTAG ou outro mecan­ismo de hard­ware), e se o seu boot­loader tam­bém não suporta esta fea­ture, fica mais com­pli­cado. Não con­heço nen­huma fer­ra­menta que rode em user­space para fazer isso.

      Um abraço.

  • Onés­simo Falconi

    Bom dia Ser­gio Prado,

    Con­segui enten­der os avi­sos emeti­dos pelo jffs2 lendo sobre o assunto no seguinte link:
    http://www.linux-mtd.infradead.org/faq/jffs2.html

    Abraço.

    • http://sergioprado.org/ Ser­gio Prado

      Obri­gado pela dica Onéssimo! 

  • E.Grau

    Muitoo bom mesmo, a tem­pos procu­rava um mate­r­ial tal com­pleto e obje­tivo sobre o desen­volvi­mento de Linux embar­cado… já estou inter­es­sado em seus cur­sos uhuu!

Navegue
Creative Commons Este trabalho de Sergio Prado é licenciado pelo
Creative Commons BY-NC-SA 3.0.