Diferença na execução do init com initramfs embutido vs. externo?

10

Estou construindo um sistema Linux muito minimalista que consiste apenas no kernel (v4.1-rc5) e em um initramfs preenchido com o busybox (v1.23.2). Na maioria das vezes, funciona bem, mas observo uma diferença no comportamento de execução de comandos no / init, se estou usando um initramfs incorporado versus um externo.

O script / init é:

#!/bin/sh

dmesg -n 1

mount -t devtmpfs none /dev
mount -t sysfs none /sys
mount -t proc none /proc
echo "Welcome"
while true
do
    setsid cttyhack /bin/sh
done

Em seguida, defino a opção CONFIG_INITRAMFS_SOURCE no kernel .config para o diretório que contém todas as pastas do initramfs ou executei

find . | cpio -H newc -o | gzip > ../rootfs.cpio.gz

para construí-lo.

Quando eu compilo o kernel, com ou sem o conjunto CONFIG_INITRAMFS_SOURCE, acabo com duas variantes do meu sistema:

  1. bzImage com o initramfs incorporado

  2. bzImage + rootfs.cpio.gz (initramfs externo)

quando agora começo aqueles que usam qemu

qemu-system-x86_64 -enable-kvm -kernel bzImage

ou

qemu-system-x86_64 -enable-kvm -kernel bzImage -initrd rootfs.cpio.gz

Eu recebo a seguinte diferença de comportamento:

com a versão 2 (initramfs externo) tudo funciona bem, "Welcome" é exibido e recebo um prompt. Porém, com a versão 1 (initramfs incorporado), recebo o aviso

unable to open an initial console

"Bem-vindo" não é exibido e recebo minha solicitação.

Tanto quanto eu entendo o processo, essas duas versões do initramfs devem conter os mesmos arquivos, pois eu o construo (ou o kernel o constrói) a partir de uma pasta idêntica.

Gostaria de saber se alguém pode me ajudar com uma explicação para esse comportamento?

* ATUALIZAÇÃO *

como mikeserv disse nos comentários, o kernel inclui um initramfs incorporado mínimo por padrão. Isso ainda está presente ao usar um externo, mas é substituído se você incorporar o seu. Eu descobri que, ao contrário da especificação, isso realmente não está vazio, mas contém uma pasta dev, uma pasta raiz e o dispositivo / dev / console. Este dispositivo é usado quando se usa um initramfs externo, mas sobrescrito se você incorporar o seu. Portanto, você deve incluir o dispositivo / dev / console na fonte initramfs mknod -m 622 initramfs_src/dev/console c 5 1ao incorporar o seu.

Muito obrigado a mikeserv, frostschutz e JdeBP por me ajudarem a entender isso!

clw
fonte
Quais são as permissões definidas /dev/consoleno seu incorporado? Eu acho que a diferença pode ser sobre quem faz as malas nos dois casos.
mikeserv
Uma pergunta semelhante é, obviamente, o stackoverflow.com/questions/10437995 .
JdeBP
@mikeserv, o dispositivo do console tem permissões e propriedade idênticas nas duas versões.
CLW
@JdeBP Não sei se é semelhante, já que nos dois casos inicializo, recebo um prompt e tenho um dispositivo de console. Só que em um init executa o eco e no outro não pode.
CLW
1
Como as permissões poderiam ter sido as mesmas no initramfs se você nem sequer as possuía?
mikeserv

Respostas:

2

Eles são realmente idênticos?

O que você pode encontrar /usr/src/linux/usr/initramfs_data.cpio.gzou extrair do bzImage, conforme descrito aqui: https://wiki.gentoo.org/wiki/Custom_Initramfs#Salvaging

Se você usar esse embutido e usá-lo como externo, funciona?

Se ainda for diferente, o próprio kernel é idêntico? (compare /proc/config.gzpara ambos)

Deve haver alguma diferença. Não sei que o kernel se importa de onde vieram os initramfs. Eu suspeitaria antes qemude usar configurações diferentes ao passar o -initrdparâmetro ...

Em uma nota de rodapé, você /initparece com suas conchas infinitas gerando para mim. setsidnão é exec. Estou errado?

frostschutz
fonte
1
Esta resposta parece ser todas as perguntas.
JdeBP
1
@JdeBP: Você não está pensando quadridimensionalmente!
Frostschutz
1
@frostschutz Muito obrigado pela sua resposta! Quando eu uso o initramfs que o kernel constrói (usr / initramfs_data.cpio.gz) como externo, ele funciona bem também! Além disso, quando eu forneço o kernel que foi compilado com o initramfs incorporado com um externo, o aviso aparece, mesmo que o externo deva sobrescrever o incorporado ( kernel.org/doc/Documentation/filesystems/… ). Portanto, provavelmente também não é o qemu -initrd, mas algo dentro do próprio kernel. Eu mudei nada mais CONFIG_INITRAMFS_SOURCE seguida, embora ..
CLW
@frostschutz Respondendo a On a sidenote, your /init looks like its spawning infinite shells to me. setsid is not exec. Am I wrong?: O loop imita o getty ou ferramentas similares, desde a chamada dos shblocos até a saída do shell.
stefanjunker
@stefanjunker e isso seria bom, exceto setsid não bloqueia nada ...
frostschutz
1

Você também pode estar interessado em saber como o Buildroot 2018.02 lida com isso.

Sempre que você usa initramfs ( BR2_TARGET_ROOTFS_INITRAMFS=y) ou initrd ( BR2_TARGET_ROOTFS_CPIO=n), ele adiciona o seguinte /initao seu rootfs https://github.com/buildroot/buildroot/blob/2018.02/fs/cpio/init

#!/bin/sh
# devtmpfs does not get automounted for initramfs
/bin/mount -t devtmpfs devtmpfs /dev
exec 0</dev/console
exec 1>/dev/console
exec 2>/dev/console
exec /sbin/init "$@"

A cópia é feita em https://github.com/buildroot/buildroot/blob/2018.02/fs/cpio/cpio.mk :

# devtmpfs does not get automounted when initramfs is used.
# Add a pre-init script to mount it before running init
define ROOTFS_CPIO_ADD_INIT
    if [ ! -e $(TARGET_DIR)/init ]; then \
        $(INSTALL) -m 0755 fs/cpio/init $(TARGET_DIR)/init; \
    fi
endef

Também é útil saber que o caminho do init é /initpara o initramfs, diferentemente do /sbin/initcontrário: O que pode fazer com que a passagem de init = / path / to / program para o kernel não inicie o programa como init?

Ciro Santilli adicionou uma nova foto
fonte