O Linux não é um sis­tema opera­cional com­pleto. O Linux é o ker­nel do sis­tema opera­cional, que você pode baixar em http://kernel.org. Mas sem bib­liote­cas e apli­cações você não con­segue fazer muita coisa com ele. E estas bib­liote­cas e apli­cações são disponi­bi­lizadas através do sis­tema de arquivo prin­ci­pal, tam­bém chamado de rootfs.

Assim que o ker­nel ter­mina seu processo de ini­cial­iza­ção, ele “monta” o rootfs e procura por uma apli­cação de ini­cial­iza­ção, que será respon­sável por con­fig­u­rar e ini­cializar o restante do sis­tema operacional.

Mas o que sig­nifica “mon­tar” o rootfs? Para respon­der esta per­gunta, pre­cisamos antes enten­der o que é um sis­tema de arquivo na prática.

Dá uma olhada na listagem do diretório prin­ci­pal “/” na minha máquina de desenvolvimento:

$ ls /
bin    etc             lib         opt   selinux   tftpd  vmlinuz
boot   home            lost+found  proc  srv       tmp    vmlinuz.old
cdrom  initrd.img      media       root  sys       usr
dev    initrd.img.old  mnt         sbin  tftpboot  var

Veja que no diretório prin­ci­pal temos um con­junto de arquivos e diretórios, que estão armazena­dos no HD da minha máquina. Mas como estes arquivos e diretórios são orga­ni­za­dos den­tro do HD? Quem responde à esta per­gunta é o sis­tema de arquivo usado. No meu caso, estou usando o ext3, que é um tipo de sis­tema de arquivo bas­tante uti­lizado em Linux. É ele que define como as infor­mações de diretórios e arquivos são orga­ni­zadas e armazenadas no disco.

Por­tanto, um sis­tema de arquivo nada mais é do que uma rep­re­sen­tação dos dados de forma hierárquica, em diretórios e arquivos, den­tro de um dis­pos­i­tivo de armazena­mento. Este dis­pos­i­tivo de armazena­mento pode ser local (HD, pen­drive, CD, DVD, memória flash, RAM, etc) ou remoto (pro­to­colo NFS).

“Mon­tar o rootfs” sig­nifica aces­sar este dis­pos­i­tivo de armazena­mento, inter­pre­tar os dados de diretórios e arquivos e disponi­bi­lizar o acesso à estes diretórios e arquivos a par­tir do diretório “/” do sistema.

E no momento de mon­tar o rootfs, como é que o ker­nel sabe o tipo de sis­tema de arquivo usado e em qual dis­pos­i­tivo de armazena­mento ele se encon­tra? Essa infor­mação esta na linha de coman­dos do ker­nel, por exemplo:

... root=/dev/sda1 rootfstype=ext3 ...

A opção “root” indica o dis­pos­i­tivo de armazena­mento, que neste exem­plo é a primeira par­tição do meu disco rígido. E a opção “rootf­stype” indica o tipo de sis­tema de arquivo, que neste exem­plo é ext3. Para mais infor­mações sobre os parâmet­ros aceitos na linha de coman­dos dê uma olhada na doc­u­men­tação do ker­nel em Documentation/kernel-parameters.txt.

A linha de coman­dos do ker­nel pode ser pas­sada pelo boot­loader ou pode estar gravada den­tro do ker­nel (con­fig­u­rada no momento da compilação).

Resu­mindo: no boot da máquina, o ker­nel ver­i­fica os parâmet­ros root e rootf­stype da linha de coman­dos, monta o rootfs no diretório “/” de acordo com estes parâmet­ros, e passa o con­t­role para a apli­cação de inicialização.

Nosso foco aqui é enten­der os difer­entes tipos de sis­temas de arquivo em Linux e quando usar cada um deles.

SISTEMAS DE ARQUIVO E MÓDULOS

O Linux suporta difer­entes sis­temas de arquivo, incluindo vfat e ntfs (famosos para quem vem do ambi­ente Win­dows), ext2, ext3, ext4, squashfs, jffs2, etc. Uma listagem com­pleta encontra-se na doc­u­men­tação do ker­nel em Documentation/filesystems/.

Todos estes sis­temas de arquivo são imple­men­ta­dos através de módu­los do ker­nel. Se você quiser saber quais sis­temas de arquivo seu ker­nel suporta, basta lis­tar o arquivo “/proc/filesystems”:

$ cat /proc/filesystems
nodev   sysfs
nodev   rootfs
nodev   proc
nodev   tmpfs
...
        ext3
        ext2
        ext4
nodev   ramfs
nodev   nfs
...
        vfat

Todos os módu­los que imple­men­tam sis­temas de arquivo no Linux uti­lizam uma camada comum de abstração do ker­nel chamada de VFS (Vir­tual filesystems).

vfs Sistemas de arquivo em Linux embarcado   Parte 1

Essa camada per­mite que todas as apli­cações usem uma API comum de acesso ao sis­tema de arquivo (open, read, write, close, etc), inde­pen­den­te­mente do tipo de sis­tema de arquivo, ou mesmo do tipo de dis­pos­i­tivo de armazena­mento. Esta camada pos­sui tam­bém algu­mas fun­cional­i­dades comuns à todos os sis­temas de arquivo, incluindo um sis­tema de cache chamado page cache. O obje­tivo deste cache é min­i­mizar oper­ações de I/O no disco, armazenando em um cache em RAM as oper­ações real­izadas em disco, para depois efe­ti­va­mente atu­alizar estas infor­mações no dis­pos­i­tivo (hard­ware), pro­ced­i­mento chamado de page write­back.

Mas por que será que exis­tem difer­entes tipos de sis­temas de arquivo? Porque cada um pos­sui obje­tivos especí­fi­cos, cus­tomiza­dos para uma mel­hor per­for­mance, mais segu­rança ou menos uso de espaço em disco, visando difer­entes dis­pos­i­tivos de armazenamento.

DISPOSITIVOS DE ARMAZENAMENTO

No Linux, os dis­pos­i­tivos de armazena­mento são clas­si­fi­ca­dos em dois tipos: dis­pos­i­tivos de bloco e memórias flash. E den­tro do ker­nel, eles são manip­u­la­dos por difer­entes sub-sistemas.

  • Dis­pos­i­tivos de bloco: podem ser lidos ou escritos nor­mal­mente sem a neces­si­dade de apa­gar antes, e ”vir­tual­mente” não pos­suem lim­ites de escrita quando usa­dos por muito tempo. Exem­p­los: HDs, floppy disks, etc.
  • Memórias flash: tra­bal­ham em blo­cos e para serem escritas pre­cisam ser apa­gadas antes. Exem­p­los: flash NAND, flash NOR.

DISPOSITIVOS DE BLOCO

Então os dis­pos­i­tivos de bloco são aque­les que você esta acos­tu­mado em um sis­tema Linux desk­top, como por exem­plo HDs, CDs e DVDs.

Se você quiser lis­tar os dis­pos­i­tivos de bloco (e suas respec­ti­vas par­tições) pre­sentes no sis­tema, basta aces­sar o arquivo “/proc/partitions”:

$ cat /proc/partitions
major minor  #blocks  name
   8        0  312571224 sda
   8        1   81920000 sda1
   8        2   40960000 sda2
   8        3  189688832 sda3
   8       32  156290904 sdc
   8       33     104391 sdc1
   8       34          1 sdc2
   8       37   40957686 sdc5
...

Exis­tem por­tanto sis­temas de arquivo especí­fi­cos para dis­pos­i­tivos de bloco. E tudo começou com o tradi­cional sis­tema de arquivo ext2, pre­sente no Linux desde prati­ca­mente as primeiras ver­sões. É um sis­tema de arquivo bem estável, mas com um grande prob­lema: pode deixar o sis­tema em um estado incon­sis­tente após um crash ou um reboot não esper­ado, fazendo com que o sis­tema pre­cise usar fer­ra­men­tas de ver­i­fi­cação de disco no próx­imo boot (Ex: fsck.ext2). É o mesmo caso do vfat, a imple­men­tação do sis­tema de arquivo FAT no Linux. Quem nunca pre­cisou exe­cu­tar um Scans­disk depois de um reboot ines­per­ado no DOS ou no Windows? :)

O ext2 foi usado durante um bom tempo no Linux (quase 10 anos). Então começaram a apare­cer alguns sis­temas de arquivo com uma car­ac­terís­tica espe­cial chamada “journaling”.

JOURNALING

Os sis­temas de arquivo com jour­nal­ing foram pro­je­ta­dos para evi­tar de deixar o sis­tema em um estado incon­sis­tente após um crash ou um reboot inesperado.

Antes de escr­ever no arquivo, todas as alter­ações em disco são gravadas em um “jour­nal”, uma espé­cie de log. Após a atu­al­iza­ção no arquivo, a entrada no jour­nal é removida. No boot, as entradas no jour­nal são anal­izadas con­forme imagem abaixo:

journal1 Sistemas de arquivo em Linux embarcado   Parte 1

Todas as entradas com­ple­tas são exe­cu­tadas, e as entradas incom­ple­tas são descar­tadas. Ou seja, se você desli­gar o equipa­mento no meio de uma escrita em disco, no boot o jour­nal vai garan­tir que esta escrita será exe­cu­tada, man­tendo o disco em um estado con­sis­tente. Como o jour­nal tam­bém é armazenado em disco, existe a pos­si­bil­i­dade de desli­gar o equipa­mento no meio da gravação de uma entrada no jour­nal. Neste caso, a entrada incom­pleta no jour­nal é descar­tada, e os dados serão per­di­dos, mas con­tin­u­amos com a garan­tia de um sis­tema con­sis­tente, já que nen­huma infor­mação foi armazenada “pela metade”.

O Linux suporta diver­sos sis­temas de arquivo com jour­nal. O ext3 foi o padrão durante um bom tempo. Ele é basi­ca­mente o ext2 com a fun­cional­i­dade de jour­nal­ing. O ext4 é a nova ger­ação com muitas mel­ho­rias, e é o sis­tema de arquivos padrão das dis­tribuições Linux desk­top atuais.

O btrfs (tam­bém chamado de ”But­terFS”) é a próx­ima ger­ação e visa sub­sti­tuir o ext4. Já esta disponível no main­line do ker­nel, mas ainda em estado exper­i­men­tal. Até a data de hoje, nen­huma das grandes dis­tribuições esta usando o btrfs. A migração do ext4 para o btrfs ainda deve levar um tempo.

Exis­tem muitos out­ros sis­temas de arquivo com jour­nal­ing, incluindo reis­erFS, JFS, XFS, etc. Estes pos­suem apli­cações especí­fi­cas, como por exem­plo tra­bal­har com arquivos pequenos ou com carga de tra­balho muito alta (muito aces­sos ao disco).

Mas quando usar cada um destes sis­temas de arquivo?

O vfat você só usará se quiser man­ter inter­op­er­abil­i­dade com o Win­dows, por exem­plo para gravar e trans­ferir dados em um pen­drive. Out­ros sis­temas de arquivo como o reis­erFS, JFS e o XFS são mais usa­dos em servi­dores e máquinas com propósi­tos especí­fi­cos, e tem pouca apli­cação em Linux embarcado.

Na prática, e atual­mente, você irá se lim­i­tar a usar ext3 ou ext4 em dis­pos­i­tivos de bloco.

A exceção são dis­pos­i­tivos de bloco que usam memória flash, como por exem­plo um cartão SD/MMC ou um pen­drive. Estes dis­pos­i­tivos apare­cem para o Linux como um dis­pos­i­tivo de bloco, como se fos­sem um disco. Mas inter­na­mente eles usam uma memória flash para armazenar os dados, e pos­suem uma con­tro­ladora para emu­lar um dis­pos­i­tivo de bloco. Como pre­cisamos lim­i­tar a escrita em memória flash (ver­e­mos isso mais adi­ante), não é acon­sel­hável o uso de sis­temas de arquivo como o ext3 ou o ext4, cujo jour­nal­ing pode lim­i­tar a vida útil da flash. Nestes casos, ext2 pode ser a mel­hor solução.

SISTEMAS DE ARQUIVO COMPRIMIDOS

Sis­temas embar­ca­dos pos­suem nor­mal­mente poucos recur­sos de armazena­mento. Por este motivo, você pode querer usar um sis­tema de arquivo que com­prima os dados, deixando o tamanho da imagem do sis­tema de arquivo menor, e ocu­pando menos espaço em disco.

Um sis­tema de arquivo com­prim­ido, como o próprio nome diz, armazena os dados de forma com­prim­ida no dis­pos­i­tivo de armazena­mento, econ­o­mizando espaço em disco. É claro que aí existe um trade-off, você ganha em espaço mas pode perder em per­for­mance, já que para fazer a leitura é necessário descom­primir os dados antes. E como algo­rit­mos para escr­ever de forma com­prim­ida são bem mais com­pli­ca­dos de imple­men­tar sem afe­tar a per­for­mance e a con­fi­a­bil­i­dade do sis­tema, a maio­ria dos sis­temas de arquivo com­prim­i­dos são de ape­nas leitura.

O CramFS (Com­pressed ROM Filesys­tem) é um exem­plo de sis­tema de arquivo com­prim­ido e de ape­nas leitura, desen­volvido espe­cial­mente para sis­temas embar­ca­dos ou dis­pos­i­tivos com baixa capaci­dade de armazena­mento. Os dados são com­prim­i­dos com o zlib, supor­tando arquivos de até 16M, e com tamanho máx­imo total da imagem de até 256MB.

Já o SquashFS é uma espé­cie de suces­sor do CramFS, visando atin­gir os mes­mos obje­tivos, mas com mel­hor com­pressão, mel­hor per­for­mance de leitura e suporte à arquivos e sis­temas maiores. Chega a gerar sis­temas de arquivo 3 vezes menores em com­para­ção com o ext3. É um sis­tema de arquivo bas­tante usado em dis­tribuições que rodam direto de um CD/DVD (Live CD) ou USB. Veja uma com­para­ção do SquashFS com out­ros sis­temas de arquivo aqui.

Por­tanto, SquashFS deve ser a sua escolha se você quiser poupar espaço no dis­pos­i­tivo de armazena­mento ou evi­tar escritas usando um rootfs read-only. Você só vai pre­cisar do CramFS se seu ker­nel for muito antigo (ante­rior à ver­são 2.6.29).

Agora, se você quer um sis­tema de arquivo sim­ples, sem com­pressão, mas que tam­bém seja de ape­nas leitura, você pode ten­tar o romfs.

SISTEMAS DE ARQUIVO VOLÁTEIS

Quando tra­bal­hamos com Linux embar­cado, às vezes pre­cisamos criar arquivos tem­porários, armazenar infor­mações de proces­sos em exe­cução, fazer log, etc. Fazer isso em um dis­pos­i­tivo de armazena­mento pode ser muito cus­toso, envolve oper­ações de I/O e pode con­sumir a vida útil do dis­pos­i­tivo no caso de memórias flash. Outro ponto é que estas infor­mações são voláteis, ou seja, não tem mais util­i­dade após o boot. Por­tanto, não faz sen­tido armazenar dados voláteis em dis­pos­i­tivos não-voláteis.

São nestes casos que usamos sis­temas de arquivo voláteis. Com um sis­tema de arquivo volátil, você con­segue man­ter um diretório no sis­tema mon­tado em RAM. Ou seja, tudo o que você escr­ever neste diretório vai para a RAM!

Nas primeiras ver­sões, o sis­tema de arquivo ramfs foi bas­tante usado. Mas ele tem basi­ca­mente dois prob­le­mas. Você não con­segue lim­i­tar a quan­ti­dade máx­ima de RAM a ser usada, ou seja, o con­t­role pre­cisa estar na sua apli­cação. O outro prob­lema é que ele não faz swap em disco.

É por isso que apare­ceu o tmpfs, sis­tema de arquivo volátil mais usado atual­mente. Não gasta muita RAM, cresce e diminui auto­mati­ca­mente con­forme o uso, é capaz de fazer swap em disco se necessário, e você con­segue lim­i­tar a quan­ti­dade máx­ima de RAM que pode ser usada.

E como usar? Basta mon­tar o tmpfs em um diretório qualquer:

$ mount -t tmpfs tmp /tmp

No exem­plo acima, o diretório “/tmp” foi mon­tado com o tmpfs, ou seja, tudo que for escrito no /tmp será salvo em uma região em RAM, e será per­dido no boot.

Quando usar o tmpfs? Sem­pre que você pre­cisar de armazena­mento volátil.

NFS

Imag­ine um pro­duto em desen­volvi­mento que con­tenha um dis­pos­i­tivo de armazena­mento, seja um HD, cartão SD ou memória flash. E você esta embar­cando Linux neste pro­duto. Imag­ine o tra­balho que você teria se pre­cisasse regravar a flash ou o cartão SD toda vez que pre­cisasse tes­tar uma nova ver­são da sua aplicação.

É por este motivo que existe o NFS (Net­work Filesys­tem), um pro­to­colo que per­mite você mon­tar um sis­tema de arquivo pela rede.

nfs Sistemas de arquivo em Linux embarcado   Parte 1

Você pre­cisa de um ker­nel com suporte à NFS, uma placa de rede no equipa­mento, e um servi­dor NFS na sua máquina de desen­volvi­mento. Com um sis­tema de arquivo local, o desen­volvi­mento fica real­mente muito mais fácil. Você não pre­cisa se pre­ocu­par com o tamanho do rootfs, pode usar fer­ra­men­tas que não caberiam no dis­pos­i­tivo, fica fácil atu­alizar uma apli­cação no rootfs, edi­tar um arquivo, etc.

Uns tem­pos atrás escrevi um artigo sobre como mon­tar o rootfs no Linux via NFS.

E AINDA TEM MAIS

Neste artigo 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.

Na segunda parte deste artigo vamos explo­rar os prin­ci­pais sis­temas de arquivo para memórias flash.

Se você con­hece ou já tra­bal­hou com algum outro sis­tema de arquivo para dis­pos­i­tivos de bloco, deixe seus comen­tários aqui!

Um abraço,

Ser­gio Prado

VN:F [1.9.17_1161]
Rat­ing: 10.0/10 (17 votes cast)
Sis­temas de arquivo em Linux embar­cado — Parte 1, 10.0 out of 10 based on 17 ratings

Posts rela­ciona­dos:

  1. Linux Device Dri­vers — Parte 1
  2. Por den­tro da con­sole em sis­temas Linux
  • http://twitter.com/marcelobarros Marcelo Bar­ros

    Oi Sér­gio

    Uma dica que vale a pena é aquela de mon­tar um rootfs total­mente em RAM, usando o ramfs e uma imagem feita com cpio. Neste caso, perde-se a per­sistên­cia mas é inter­es­sante em cer­tas situ­ações. Pode­ria ser uma forma de fazer update no sis­tema, por exem­plo. Além disso, como você sabe, várias dis­tros usam o rootfs em ram antes de mon­tar o sis­tema final, em disco, para detecção de dri­vers e out­ras coisas dinâmicas.

    A linha mág­ica de par­tida do ker­nel ficaria como:

    initrd=boot/initrd.gz root=/dev/ram0 rootfstype=ramfs rdinit=/init

    Estou supondo que ramdisk (initrd.gz) foi cri­ado com cpio, algo como um find na raiz do rootfs dese­jado, e que o /init é um script de par­tida válido:

    find . |  cpio –H newc –cre­ate –ver­bose > ini­trd
    gzip –best initrd

    Para “pular” para um rootfs final, basta uma chamada à sys­tem call switch_root. Algo como:

    exec switch_root /local/do/rootfs/final /sbin/init

    A memória alo­cada vai emb­ora depois disso.

    Belo post, até mais !

    Marcelo Bar­ros
     

    VA:F [1.9.17_1161]
    Rating: 0.0/5 (0 votes cast)
    • http://sergioprado.org/ Ser­gio Prado

      Grande mestre Marcelo Barros!

      Até pen­sei em incluir o initramfs mas o post já estava bas­tante extenso. Mas sua descrição foi pre­cisa! Agora não pre­ciso mais! :)

      À propósito, estou curtindo bas­tante seus posts lá no http://jedizone.wordpress.com/ sobre SNMP. Con­tinue escrevendo!

      Um abraço.

      VA:F [1.9.17_1161]
      Rating: 0.0/5 (0 votes cast)
  • Romulo Gran­dini

    Exce­lente artigo meu caro, show de bolsa!

    VA:F [1.9.17_1161]
    Rating: 0.0/5 (0 votes cast)
    • Romulo Gran­dini

      Bola*, swype maldito kkk

      VA:F [1.9.17_1161]
      Rating: 0.0/5 (0 votes cast)
      • http://sergioprado.org/ Ser­gio Prado

        :) Obri­gado Rômulo!

        VA:F [1.9.17_1161]
        Rating: 0.0/5 (0 votes cast)
  • Júlio Hof­fi­mann

    Como sem­pre super didático!

    Abraço!

    VA:F [1.9.17_1161]
    Rating: 0.0/5 (0 votes cast)
  • Luiz Flávio

    Parabéns pelo artigo, ótimo tra­balho!
     

    VA:F [1.9.17_1161]
    Rating: 0.0/5 (0 votes cast)
  • http://www.facebook.com/people/Jose-Carlos-N-Medeiros/630709268 Jose Car­los N Medeiros

    Exce­lente artigo, muito didático.

    VA:F [1.9.17_1161]
    Rating: 0.0/5 (0 votes cast)