Home Comunidade Eventos YouTube Networks Desafios // produtos Academy News CTI | CVE Contato

06 - Initramfs - Initrd (Sistema de Arquivos Temporário)

video explicativo
Video explicativoEspaco reservado para o video desta anotação — adicione video: https://youtu.be/... no frontmatter da nota.

O ecossistema de inicialização do kernel Linux enfrenta um paradoxo arquitetural clássico, frequentemente chamado de problema "do ovo e da galinha". Para que o kernel possa montar o sistema de arquivos raiz (/), ele necessita dos device drivers adequados para interagir com o controlador de armazenamento físico (SATA, NVMe, SCSI), bem como de módulos lógicos de mapeamento de blocos (LVM, RAID via mdadm, multipath) e camadas de criptografia (LUKS/dm-crypt). Contudo, a imensa maioria desses módulos e binários reside exatamente dentro do sistema de arquivos raiz que ainda não foi montado (em /lib/modules/).

Para solucionar essa dependência circular cíclica sem inchar o binário do kernel (vmlinuz) com drivers estáticos infindáveis, a arquitetura do Linux introduziu o conceito de um sistema de arquivos temporário injetado diretamente na memória RAM pelo bootloader. Este ambiente efêmero serve exclusivamente para fornecer as ferramentas espaciais do usuário e os módulos de núcleo mínimos necessários para localizar, desbloquear, montar e transitar para o sistema de arquivos raiz definitivo.

Ao longo do desenvolvimento do Linux, este mecanismo evoluiu drasticamente, dividindo-se em duas implementações arquiteturalmente distintas: o legado initrd e o moderno initramfs.

1. Initrd (Initial RAM Disk): A Abordagem Legada

O initrd foi a primeira solução implementada para o problema de montagem da raiz. Embora o termo ainda seja coloquialmente utilizado de forma intercambiável com initramfs, do ponto de vista do Ring 0, suas mecânicas são obsoletas e estruturalmente ineficientes.

1.1. Arquitetura em Bloco e Falsificação de Dispositivo

No esquema initrd, o arquivo gerado e passado pelo bootloader é uma imagem literal de um sistema de arquivos completo (frequentemente ext2 ou cramfs), que muitas vezes é comprimida com gzip.
Quando o kernel recebe essa imagem, ele precisa instanciar um dispositivo de bloco virtual em memória (o ramdisk, tipicamente /dev/ram0). A imagem comprimida é então descompactada para dentro desse dispositivo de bloco de tamanho fixo.

1.2. Problemas Arquiteturais do Initrd

  1. Desperdício de Memória e Tamanho Fixo: O ramdisk requer a alocação de um bloco contíguo e de tamanho fixo na memória. Se o ramdisk tem 15MB e os arquivos ocupam apenas 5MB, 10MB de RAM estão permanentemente desperdiçados.
  2. Duplo Cache (Double Caching): Como o initrd emula um dispositivo de bloco real, todas as leituras feitas nele passam pelo subsistema de cache de páginas do kernel (Page Cache). O VFS (Virtual File System) lê os dados do ramdisk (que já está na RAM) e os coloca em um cache na própria RAM, duplicando o consumo de memória para os mesmos dados.
  3. Overhead de Sistema de Arquivos: Para ler os arquivos, o kernel precisa de um driver de sistema de arquivos completo (como o ext2) embutido estaticamente no binário monolítico, adicionando complexidade e peso ao núcleo básico.
  4. pivot_root: A transição do initrd para a raiz real exigia o uso da chamada de sistema pivot_root. Esta syscall literalmente troca a montagem raiz atual por uma nova, movendo a raiz antiga para um subdiretório (como /initrd), o que exigia a desmontagem manual posterior, um processo propenso a vazamentos de memória e bloqueios de inodes.

2. Initramfs (Initial RAM Filesystem): O Padrão Moderno

Para mitigar o overhead do initrd, o desenvolvimento do kernel 2.6 introduziu o initramfs. O initramfs não é um dispositivo de bloco emulado; ele é uma instância nativa do tmpfs (ou ramfs), uma camada que mapeia arquivos diretamente nas estruturas de cache de página e de dentries do VFS, dispensando totalmente a camada de blocos.

2.1. O Formato cpio

Em vez de formatar um arquivo como um sistema de arquivos ext2, o initramfs é simplesmente um arquivo comprimido do tipo cpio (Copy In, Copy Out). A escolha do cpio (especificamente o formato SVR4 newc) não é acidental:

  • É um formato contínuo (streamable), o que significa que o kernel pode processar e extrair seus arquivos linearmente em uma única passagem de leitura, sem precisar pular setores.
  • O descompactador e extrator de cpio é microscópico em termos de código (algumas centenas de linhas em C) e está profundamente incorporado ao código de inicialização do VFS (init/initramfs.c).

2.2. Vantagens Arquiteturais

  1. Redimensionamento Dinâmico: Um tmpfs não tem tamanho fixo inicial. Ele cresce dinamicamente na RAM à medida que os arquivos do cpio são extraídos, e encolhe instantaneamente quando os arquivos são apagados, eliminando o desperdício de memória.
  2. Zero Double Caching: Os arquivos no initramfs não passam pela camada de bloco (struct bio). Eles são instanciados diretamente nos caches nativos do kernel.
  3. Ausência de Drivers Adicionais: Como não há formatação geométrica, o kernel não precisa de drivers estáticos de ext2, fat ou xfs para conseguir realizar o primeiro boot.

3. O Fluxo de Execução no Ambiente Initramfs

A mecânica de inicialização envolvendo o initramfs segue um pipeline altamente rigoroso e sequencial.

3.1. Hand-off do Bootloader e Descompressão

  1. O bootloader (como o GRUB2) aloca dois blocos na RAM: um para o vmlinuz (kernel) e outro para o arquivo initramfs.img. Os endereços de memória físicos de ambos são passados ao kernel.
  2. O kernel inicializa seu gerenciador de memória (MMU), processadores (SMP) e aloca a estrutura especial do VFS chamada rootfs.
  3. O kernel invoca a função populate_rootfs(), que identifica a compressão (GZIP, LZ4, ZSTD), descompacta o buffer de memória e extrai os inodes e dados via cpio para dentro do rootfs vazio.

3.2. O PID 1 Temporário (/init)

O kernel então busca por um arquivo executável nomeado /init na raiz deste rootfs efêmero. Este script ou binário torna-se o PID 1 temporário. O trabalho do /init é complexo e vital:

  1. Montagem de Subsistemas: Ele imediatamente monta pseudo-sistemas de arquivos vitais: /proc, /sys e /dev.
  2. Descoberta de Hardware: Aciona gerenciadores como o udevd (ou o mdev em sistemas embarcados) para varrer a árvore de dispositivos em /sys/devices, ler os identificadores (ex: MODALIAS) e criar dinamicamente os nós de dispositivo em /dev (ex: /dev/sda1).
  3. Injeção de Módulos: Baseado nas descobertas do passo anterior, utiliza o modprobe para injetar os arquivos .ko contidos no próprio initramfs (dentro de /usr/lib/modules/) para dentro do Ring 0.
  4. Construção de Mídia Lógica: Se o sistema usa LVM, o /init executa vgchange -ay para ativar os Volume Groups. Se usar LUKS, solicita a senha do usuário via cryptsetup para mapear o dispositivo descriptografado em /dev/mapper/.
  5. Montagem da Raiz Final: Com o dispositivo de bloco exposto e o driver de sistema de arquivos (ex: ext4, xfs) carregado, o script /init monta a raiz definitiva do disco físico de forma apenas-leitura (read-only) em um diretório de transição, tipicamente /sysroot.

3.3. Transição: switch_root

Aqui reside a diferença final entre o obsoleto initrd e o initramfs. O rootfs base no kernel Linux é uma estrutura "imortal" — ele não pode ser desmontado (umount), pois é a âncora do VFS.
Para transferir a execução, o utilitário switch_root é invocado. Ele realiza uma operação de terra arrasada:

  1. Ele recursivamente deleta todos os arquivos, diretórios e symlinks de dentro do initramfs ativo na RAM para liberar a memória física.
  2. Ele executa a syscall de montagem para mover a montagem de /sysroot por cima da própria raiz (/). O rootfs original ainda existe arquiteturalmente, mas fica permanentemente ocluso (escondido sob a nova montagem).
  3. Ele executa uma chamada exec() para transferir o PID 1 para o /sbin/init real (ou systemd) do novo disco. Como a transição usa exec, o novo processo de inicialização herda o PID 1 exato, finalizando a fase efêmera.

4. Estruturação Modular Moderna

Hoje, a construção de imagens initramfs não é feita de forma estática, mas orientada a módulos e perfis de hardware hospedeiro, através de geradores dinâmicos como Dracut (Red Hat/Fedora), mkinitcpio (Arch Linux) ou update-initramfs (Debian/Ubuntu).
Essas ferramentas permitem ao administrador especificar exatamente quais binários (como fsck e mdadm), arquivos de configuração (como fstab) e drivers (através do mapeamento do lsmod atual ou da flag --hostonly) devem ser encapsulados na imagem cpio.
Falhas na construção ou na leitura desta imagem pelo bootloader frequentemente resultam em paradas severas, sendo a origem mais comum da incapacidade de montagem, resultando na queda do ambiente para o console de recuperação (shell busybox interativo acionado pelo /init quando o /sysroot falha ao montar), aguardando intervenção manual direta do administrador do sistema para corrigir partições, arranjos lógicos ou tabelas de mapeamento corrompidas.