Como o linux sabe onde o rootfs está?

1

Estou tentando entender como o kernel do linux sabe onde o rootfs desejado está na inicialização.

Eu li este documento:

link

Uma parte do interesse diz:

All 2.6 Linux kernels contain a gzipped "cpio" format archive, which is extracted into rootfs when the kernel boots up ... If rootfs does not contain an init program after the embedded cpio archive is extracted into it, the kernel will fall through to the older code to locate and mount a root partition

Nosso kernel é 4.X, mas acredito que isso ainda se aplique? Isso soa como se todos os kernels tivessem um rootfs "cpio" embutido.

E, de fato, quando lemos, diz:

The 2.6 kernel build process always creates a gzipped cpio format initramfs archive and links it into the resulting kernel binary. By default, this archive is empty ... The config option CONFIG_INITRAMFS_SOURCE ... can be used to specify a source for the initramfs archive

Isso levanta mais algumas questões:

  1. Então, se eu quiser que meus rootfs estejam na RAM, eu preciso definir CONFIG_INITRAMFS_SOURCE para apontar para o meu rootfs (no formato cpio presumivelmente).

Mas isso não significa que meu kernel e rootfs agora são inseparáveis? E se eu quiser fazer um pequeno ajuste no RootFS sem reconstruir? E se eu quiser que meus rootfs sejam armazenados separados do kernel? Como eu digo ao kernel a localização dos meus rootfs?

  1. Além disso, e se eu quiser que meus rootfs estejam no armazenamento físico (como eMMC, unidade flash, etc.) e não na RAM?

Disse anteriormente que:

If rootfs does not contain an init program after the embedded cpio archive is extracted into it, the kernel will fall through to the older code to locate and mount a root partition

Mas ... como? Como ele sabe onde localizar os rootfs? Se é no eMMC eu preciso dizer ao kernel que de alguma forma, certo?

O bootloader que estou usando é o U-boot. Eu verifiquei as variáveis de ambiente U-boot para ver se de alguma forma estava passando o local do rootfs para o kernel como um argumento de inicialização, mas não parece ser o caso ...

Editar:

Como apontado nos comentários, a localização do rootfs é passada para o kernel via boot arg. No meu caso, o u-boot está passando root=/dev/mmcblk0p4 rw como um argumento de inicialização para o kernel. Então, isso responde a uma das minhas perguntas - você pode passar o local para qualquer rootfs descompactado como um argumento de inicialização.

Ainda não estou claro como, dado algum rootfs.tar.gz que é separado do kernel, como dizer ao kernel para descompactá-lo na RAM e usá-lo como rootfs. Talvez isso não seja possível e eu só preciso usar CONFIG_INITRAMFS_SOURCE ? De qualquer forma, vou ler os documentos do 4.X.

    
por RPGillespie 02.11.2018 / 15:58

2 respostas

2

So if I want my rootfs to be in RAM, I need to set CONFIG_INITRAMFS_SOURCE to point to my rootfs (in cpio format presumably).

Essa uma forma de fazê-lo, sim, mas não é apenas .

Se você tem um gerenciador de inicialização que pode ser configurado para carregar o kernel e o initramfs como arquivos separados, você não precisa usar CONFIG_INITRAMFS_SOURCE enquanto constrói o kernel. É suficiente ter CONFIG_BLK_DEV_INITRD definido na configuração do kernel. (Antes do initramfs havia uma versão antiga da técnica chamada initrd , e o nome antigo ainda aparece em alguns lugares.) O gerenciador de inicialização carregará o arquivo initramfs e, em seguida, preencherá algumas informações sobre seu local e tamanho de memória em um dado. estrutura em um local específico da imagem do kernel já carregada. O kernel tem rotinas internas que usarão essas informações para encontrar o initramfs na RAM do sistema e descompactá-lo.

Ter o initramfs como um arquivo separado permitirá que você modifique o arquivo initramfs mais facilmente, e se o seu gerenciador de inicialização puder aceitar entrada do usuário, talvez especifique outro arquivo initramfs a ser carregado em vez do regular no momento da inicialização. (Isso é muito útil se você tentar criar um initramfs personalizado e conseguir algumas coisas erradas. Esteja lá, faça isso.)

Para um sistema x86 tradicional baseado em BIOS, você encontrará informações sobre esses detalhes em (fonte do kernel ) / Documentação / x86 / boot.txt . Os sistemas baseados em UEFI fazem isso de maneira um pouco diferente (também descrita no mesmo arquivo), e outras arquiteturas como o ARM possuem seus próprios conjuntos de detalhes sobre a passagem de informações do carregador de inicialização para o kernel.

Furthermore, what if I want my rootfs to be on physical storage (like eMMC, flash drive, etc.) and not in RAM?

Em sistemas regulares não incorporados, os initramfs geralmente contêm apenas funcionalidades suficientes para ativar os subsistemas essenciais. Em um PC normal, esses geralmente seriam os drivers para o teclado, monitor e driver para o controlador de armazenamento do sistema de arquivos raiz, além de módulos do kernel e ferramentas necessárias para ativar subsistemas como LVM, criptografia de disco e / ou software RAID. se você usar esses recursos.

Quando os subsistemas essenciais estiverem ativos e o sistema de arquivos raiz estiver acessível, o initramfs normalmente executará uma operação pivot_root(8) para alternar do initramfs para o sistema de arquivos raiz real. Mas um sistema embarcado, ou um utilitário especializado como DBAN , pode empacotar tudo o que precisa no initramfs e nunca fazer a operação pivot_root .

Normalmente, os scripts e / ou ferramentas dentro do initramfs obterão as informações necessárias para localizar o sistema de arquivos raiz real a partir das opções na linha de comando do kernel. Mas você não tem para fazer isso: com um initramfs personalizado, você poderia fazer algo como alternar para um sistema de arquivos raiz diferente se uma tecla específica ou botão do mouse for pressionado em um momento específico na inicialização sequência.

Com uma configuração de armazenamento complexa (por exemplo, LVM criptografado em um RAID de software, em um sistema que usa armazenamento SAN multipathed redundante), todas as informações necessárias para ativar o sistema de arquivos raiz podem não se encaixar na linha de comando do kernel. poderia incluir as peças maiores no initramfs.

As distribuições modernas geralmente usam um gerador initramfs para construir um initramfs personalizado para cada kernel instalado. Diferentes distribuições costumavam ter seus próprios geradores initramfs: RedHat usava mkinitrd enquanto o Debian tinha update-initramfs . Mas depois da introdução de systemd , parece que muitas distribuições estão padronizando em dracut como um initramfs gerador.

Um arquivo initramfs moderno pode ser uma concatenação de vários .cpio archives e cada parte pode ou não ser compactada. Um arquivo initramfs típico em um sistema x86_64 moderno pode ter um arquivo de "atualização de microcódigo inicial" como um primeiro componente (geralmente apenas um único arquivo em um arquivo cpio descompactado, pois o arquivo de microcódigo é tipicamente criptografado e não muito compactável. o conteúdo normal do initramfs, como um arquivo .cpio compactado.

Para obter uma compreensão mais profunda do seu sistema, sugiro que você extraia um arquivo initramfs para um diretório temporário e examine seu conteúdo. No Debian, existe uma ferramenta unmkinitramfs(8) que pode ser usada para extrair um arquivo initramfs de uma maneira direta. No RedHat 7, talvez seja necessário usar /usr/lib/dracut/skipcpio <initramfs file> para ignorar o arquivo de atualização de microcódigo e, em seguida, canalizar a saída resultante para gzcat e para cpio -i -d para extrair o conteúdo initramfs para o diretório de trabalho atual. O Ubuntu pode usar lzcat no lugar de gzcat .

    
por 02.11.2018 / 22:19
2

Primeiro, não se assuste com as referências a "2.6" nos documentos do kernel. Os kernels atuais ainda são membros da linha "2.6", mas passaram por duas rodadas de renumeração apenas para "fins de marketing" (então 2.6.40 se tornou 3.0 e 3.20 se tornou 4.0). Seu kernel 4.19 normalmente seria rotulado 2.6.79.

Parece que há alguma confusão acontecendo aqui sobre o significado de "rootfs". O "rootfs" é um sistema de arquivos especial baseado em RAM usado internamente pelo kernel. É exatamente o mesmo que os sistemas de arquivos "tmpfs" que são comumente montados em lugares como /run , /dev/shm ou às vezes /tmp . (Bem, a menos que o recurso "tmpfs" não seja compilado no kernel, caso em que um "tmpfs" despojado chamado "ramfs" é usado no lugar.) Esses sistemas de arquivos vivem apenas no pagecache, não há nenhum dispositivo auxiliar para ramfs, enquanto o tmpfs é suportado por swap, se disponível.

O kernel não precisa se preocupar com "encontrar" o "rootfs", mas precisa preenchê-lo de alguma forma, porque o pagecache inteiro está vazio na inicialização. É aí que o "arquivo initramfs" entra em cena. Isso é apenas um arquivo cpio (compactado) (não tar por razões mencionadas na documentação) que é descompactado pelo kernel no "rootfs" vazio. Este arquivo pode ser incorporado diretamente na imagem do kernel, definindo CONFIG_INITRAMFS_SOURCE durante a construção ou fornecido pelo carregador de inicialização (é o que a opção initrd no GRUB faz). Esse arquivo geralmente é criado usando ferramentas de espaço do usuário como dracut ou (confusamente) mkinitrd .

Se a imagem do cpio não estiver disponível ou não contiver um executável /init , o kernel voltará a um método diferente no qual analisa o argumento de linha de comando root= , interpretando-o como o local de um sistema de arquivos raiz real , monta em / e executa init diretamente. No entanto, isso raramente é usado hoje em dia, pois requer todos os drivers de armazenamento e de sistema de arquivos necessários compilados diretamente no kernel. Na maioria dos sistemas, o argumento root= não é usado pelo kernel, mas processado pelo /init no initramfs. Esse /init (que geralmente é systemd ou um shell script) cuida de carregar os módulos necessários, montando o sistema de arquivos raiz real e alternando para ele.

Há muito tempo atrás, um mecanismo diferente chamado "initrd" era usado em vez do "initramfs" moderno. O "initrd" ("init ramdisk") era um dispositivo de bloco baseado em RAM que foi inicializado com um sistema de arquivos real (como ext2), cuja imagem foi fornecida exatamente como o arquivo cpio moderno. É por isso que muitos lugares ainda usam o nome "initrd" para se referir a essas coisas iniciais.

    
por 02.11.2018 / 21:11