initramfsについて

53
initramfs について Kansai Debian Meeting 20101024 西山和広 Good-Day Inc. Powered by Rabbit 0.6.4

Upload: kazuhiro-nishiyama

Post on 12-Jun-2015

6.428 views

Category:

Technology


4 download

TRANSCRIPT

Page 1: initramfsについて

initramfs についてKansai Debian Meeting 20101024

西山和広Good-Day Inc.

Powered by Rabbit 0.6.4

Page 2: initramfsについて

Who am I?twitter: @znz

fingerprint

sec 4096R/B4222F7A 2010-06-27 [expires: 2040-08-10] Key fingerprint = B863 D6DC C2B9 57B8 5238 6CE0 262E D8DB B422 2F7Auid Kazuhiro NISHIYAMA <zn@...>uid Kazuhiro NISHIYAMA (ZnZ) <zn@...>uid Kazuhiro NISHIYAMA <nisiyama@...>uid Kazuhiro NISHIYAMA (znz) <kzhr.nsym@...>ssb 4096R/FAFB96B8 2010-06-27

1/52

Page 3: initramfsについて

Agendainitrd/initramfs とは?

いろいろなところからの Linux の起動

initramfs について

initramfs のカスタマイズ

./init の処理内容

2/52

Page 4: initramfsについて

initrd/initramfs とは?Linux の起動途中に使われる root ファイルシステム

この中で本当の root ファイルシステム (real root) をマウント

実体は gzip された cpio アーカイブ昔は ext2 のディスクイメージファイル

gzip の代わりに lzma のこともある(casper/initrd.lz)

3/52

Page 5: initramfsについて

Linux の起動いろいろなところからの Linux の起動についてinitramfs が起動中のどの部分になるのかの説明のため

4/52

Page 6: initramfsについて

USB/HDD から起動BIOS (起動順位で USB/HDD が上)

MBR (grub などのブートローダー)

vmlinuz (カーネル) + initrd (の中の /init)

real root (/dev/sda1 とか) の /sbin/init(MD, LVM2, LUKS などでも OK)

/etc/inittab の処理とか

5/52

Page 7: initramfsについて

光学ドライブから起動BIOS (起動順位で光学ドライブが上)

El Torito (isolinux などのブートローダー)

vmlinuz (カーネル) + initrd (の中の /init)

real root (filesystem.squashfs + aufs とか) の /sbin/init

/etc/inittab の処理とか

6/52

Page 8: initramfsについて

ネットワークから起動BIOS (起動順位で NIC が上)

PXE boot (pxelinux などのブートローダー)

vmlinuz (カーネル) + initrd (の中の /init)

real root (NFS とか) の /sbin/init

/etc/inittab の処理とか

7/52

Page 9: initramfsについて

real root の場所カーネルに root=UUID=xxx などで指定

ローカルディスク (root=/dev/sda1 など)

光学ドライブ (root=/dev/hdc など)

NFS (nfsroot=192.168.0.1:/path/to/nfsroot など)

など

8/52

Page 10: initramfsについて

/proc/cmdline (1)カーネルのコマンドライン引数

カーネルパラメーター

起動後に /proc/cmdline で見えるもの

grub などで vmlinuz の後ろに書いているもの

9/52

Page 11: initramfsについて

/proc/cmdline (2)initramfs の処理で使うものが多い

カーネル自体が処理するものもある

real root で起動するプログラムが参照する目的で使っても良いが、カーネルや initramfs が使うものと衝突しないように注意

10/52

Page 12: initramfsについて

/proc/cmdline (3)良く使われるものの例

quiet

起動中のコンソールへの出力を減らす

ro / rw

initramfs の中で real root を readonly mount するかどうか

11/52

Page 13: initramfsについて

/proc/cmdline (4)init=/path/to/real_init

/sbin/init の代わりに実行するプログラムを指定

acpi=off apm=off など

カーネルが処理

text

/etc/init.d/gdm3 が「grep -wqs text /proc/cmdline」でチェックしている

12/52

Page 14: initramfsについて

/proc/cmdline (5)root=/path/to/blockdevice

ルートファイルシステムとしてマウントするデバイスを指定

boot=local / boot=nfs / boot=casper / boot=live

real root を mount するのに使うスクリプトを指定

13/52

Page 15: initramfsについて

update-initramfsinitramfs はパッケージの中身ではない

update-initramfs コマンドで生成や更新(カーネルのパッケージのインストール時などは dpkg-trigger で遅延実行)

/usr/share/initramfs-tools/ や /etc/initramfs-tools/ を元に生成

「sudo update-initramfs -u -k all」などで更新

14/52

Page 16: initramfsについて

initramfs の調べ方

mkdir -p /tmp/initrd && (cd /tmp/initrd && { zcat /boot/initrd.img-* | cpio -idm; })

# initramfs-tools(8)mkdir tmp/initramfscd tmp/initramfsgunzip -c /boot/initrd.img-2.6.18-1-686 | \cpio -i -d -H newc --no-absolute-filenames

# linux-2.6/Documentation/initrd.txtmkdir /tmp/imagefilecd /tmp/imagefilegzip -cd /boot/imagefile.img | cpio -imd --quiet

などのように展開(カレントディレクトリにばらまかれるので展開場所には注意)

15/52

Page 17: initramfsについて

initramfs の中身 (1)./init

カーネルが実行するプログラム

Debian 系の場合は /bin/sh のシェルスクリプト✓

Redhat 系の場合は以前確認したときは nash だった

./scripts

./init から読み込まれたり実行されたりするプログラム

16/52

Page 18: initramfsについて

initramfs の中身 (2)./bin や ./sbin

busybox など

./conf や ./etc

設定ファイル

./lib や ./usr

ライブラリやカーネルモジュールなど

17/52

Page 19: initramfsについて

initramfs のカスタマイズ/etc/initramfs-tools/ 以下のファイルを編集したり、ファイルを追加したり。

Debian Live のようにパッケージなら /usr/share/initramfs-tools/ 以下にファイルを追加する。

18/52

Page 20: initramfsについて

/etc/initramfs-tools (1)initramfs.conf

update-initramfs.conf

update-initramfs や mkinitramfs の設定ファイル

modules

initramfs の中でロードするモジュール(後でロードすればいいものは /etc/modules を使う)

19/52

Page 21: initramfsについて

/etc/initramfs-tools (2)conf.d/

initramfs の conf/conf.d/ に入る。

hooks/

/usr/share/initramfs-tools/hooks/ と同様に initramfs 作成時に実行される。

20/52

Page 22: initramfsについて

/etc/initramfs-tools (3)scripts/

/usr/share/initramfs-tools/scripts/ と一緒に initramfs の scripts/ に入る。

(リカバリディスクを作成するときに scripts/local-premount/recovery を作った。)

21/52

Page 23: initramfsについて

hooks//usr/share/initramfs-tools/hook-functions の関数で initramfs の中身を生成

copy_exec で追加しておきたいバイナリをコピー(ldd でわかる範囲内で使っているライブラリを含めてコピーされる)

manual_add_modules でモジュールをコピー

その他のファイルを追加や削除など

22/52

Page 24: initramfsについて

scripts/カスタマイズする処理本体

live 関係なら以下のようなものが入る。(BOOT=live のときに使われる)

live

live-bottom/

live-functions

live-helpers

live-premount/

23/52

Page 25: initramfsについて

./init の処理内容 (1)ソースは initramfs-tools 0.98.4 から。(initramfs-tools 由来のコードのライセンスは GPL2 or later です)

#!/bin/sh

echo "Loading, please wait..."

このメッセージが出たところからが initramfs の中の処理

24/52

Page 26: initramfsについて

./init の処理 (2) dirinitramfs 内の ディレクトリの準備

[ -d /dev ] || mkdir -m 0755 /dev[ -d /root ] || mkdir -m 0700 /root[ -d /sys ] || mkdir /sys[ -d /proc ] || mkdir /proc[ -d /tmp ] || mkdir /tmpmkdir -p /var/lockmount -t sysfs -o nodev,noexec,nosuid none /sysmount -t proc -o nodev,noexec,nosuid none /proc

25/52

Page 27: initramfsについて

./init の処理 (3) devinitramfs 内の /dev や udev の準備

# Note that this only becomes /dev on the real filesystem if udev's scripts# are used; which they will be, but it's worth pointing outtmpfs_size="10M"if [ -e /etc/udev/udev.conf ]; then . /etc/udev/udev.conffiif ! mount -t devtmpfs -o mode=0755 none /dev; then echo "W: devtmpfs not available, falling back to tmpfs for /dev" mount -t tmpfs -o size=$tmpfs_size,mode=0755 udev /dev [ -e /dev/console ] || mknod -m 0600 /dev/console c 5 1 [ -e /dev/null ] || mknod /dev/null c 1 3fimkdir /dev/ptsmount -t devpts -o noexec,nosuid,gid=5,mode=0620 none /dev/pts || true> /dev/.initramfs-toolsmkdir /dev/.initramfs

26/52

Page 28: initramfsについて

./init (4) export後で起動するシェルスクリプトなどのために、いくつかのシェル変数は環境変数に後半はスペースの都合で同じ行に詰めています

# Export the dpkg architectureexport DPKG_ARCH=. /conf/arch.conf

# Set modprobe envexport MODPROBE_OPTIONS="-qb"

# Export relevant variablesexport ROOT=; export ROOTDELAY=; export ROOTFLAGS=; export ROOTFSTYPE=export IP=; export BOOT=; export BOOTIF=; export UBIMTD=; export break=export init=/sbin/init; export quiet=n; export readonly=yexport rootmnt=/root; export debug=; export panic=; export blacklist=export resume=; export resume_offset=

27/52

Page 29: initramfsについて

./init (5) confconf ファイルの読み込み

# Bring in the main config. /conf/initramfs.conffor conf in conf/conf.d/*; do [ -f ${conf} ] && . ${conf}done. /scripts/functions

28/52

Page 30: initramfsについて

./conf/initramfs.conf./conf/initramfs.conf の中身の例(real root を探す処理が BOOT で決まる)

% egrep '^[^#]' conf/initramfs.confMODULES=mostBUSYBOX=yKEYMAP=nCOMPRESS=gzipBOOT=localDEVICE=NFSROOT=auto

29/52

Page 31: initramfsについて

./conf/conf.d の中身の例

% ls conf/conf.dresume% cat conf/conf.d/resumeRESUME=UUID=ae891314-2104-480c-bdd8-6de40e6edb72

30/52

Page 32: initramfsについて

./init (6) cmdlineカーネルのコマンドライン引数 (/proc/cmdline) の解析

# Parse command line optionsfor x in $(cat /proc/cmdline); do case $x in init=*) init=${x#init=} ;; root=*) ROOT=${x#root=} case $ROOT in LABEL=*) ROOT="${ROOT#LABEL=}"(省略)

31/52

Page 33: initramfsについて

./init (7) noresume

if [ -n "${noresume}" ]; then export noresume unset resumeelse resume=${RESUME:-}fi

# cmdline 処理の一部: resume=*) RESUME="${x#resume=}" ;; resume_offset=*) resume_offset="${x#resume_offset=}" ;; noresume) noresume=y ;;

32/52

Page 34: initramfsについて

./init (8) netconsole

[ -n "${netconsole}" ] && \modprobe netconsole netconsole="${netconsole}"

# cmdline 処理の一部: netconsole=*) netconsole=${x#netconsole=} ;;

スペースの都合で改行を入れています

33/52

Page 35: initramfsについて

./init (9) maybe_breakmaybe_break は処理の途中でシェルを起動できる場所

maybe_break top

# cmdline 処理の一部: break=*) break=${x#break=} ;; break) break=premount ;;

34/52

Page 36: initramfsについて

scripts/functions: maybe_break (1)

# scripts/functions の一部:maybe_break(){ if [ "${break:-}" = "$1" ]; then panic "Spawning shell within the initramfs" fi}

35/52

Page 37: initramfsについて

scripts/functions: maybe_break (2)

ubuntu (lucid) の initramfs-tools 0.92bubuntu78(以降 ubuntu 版の話がある場合はこのバージョ

ン)の場合、Debian と違って複数指定可能

# scripts/functions の一部:maybe_break(){ if echo "${break}" | egrep -q "(,|^)$1(,|$)"; then panic "Spawning shell within the initramfs" fi}

36/52

Page 38: initramfsについて

functions: panic (1)起動時に root ファイルシステムが見つからなくて「(initramfs)」で止まることがあるのはこれ。

# scripts/functions の一部:panic(){ if [ -x /sbin/usplash_write ]; then /sbin/usplash_write "QUIT" fi

if command -v chvt >/dev/null 2>&1; then chvt 1 fi

# Disallow console access if [ -n "${panic}" ]; then sleep ${panic} reboot fi modprobe i8042 modprobe atkbd echo "$@" REASON="$@" PS1='(initramfs) ' /bin/sh -i </dev/console >/dev/console 2>&1}

37/52

Page 39: initramfsについて

functions: panic (2)数字か「.」以外の文字があると無視するようになっている。

# cmdline 処理の一部: panic=*) panic="${x#panic=}" case ${panic} in *[![:digit:].]*) panic= ;; esac ;;

38/52

Page 40: initramfsについて

functions: panic (3)ubuntu 版だと run_scripts がある。

# scripts/functions の一部:panic(){ if [ -x /sbin/usplash_write ]; then /sbin/usplash_write "QUIT" fi chvt 1

# Disallow console access if [ -n "${panic}" ]; then sleep ${panic} reboot fi

modprobe i8042 modprobe atkbd

run_scripts /scripts/panic

echo $@ PS1='(initramfs) ' /bin/sh -i </dev/console >/dev/console 2>&1}

39/52

Page 41: initramfsについて

run_scripts (1)指定されたディレクトリの中の実行可能ファイルを実行

prereqs で依存関係を指定できる

ORDER に tsort (トポロジカルソート) 結果をキャッシュしている

40/52

Page 42: initramfsについて

run_scripts (2)

# scripts/functions の一部:run_scripts(){ initdir=${1} [ ! -d ${initdir} ] && return

if [ -f ${initdir}/ORDER ]; then . ${initdir}/ORDER elif command -v tsort >/dev/null 2>&1; then runlist=$(get_prereq_pairs | tsort) call_scripts ${2:-} else get_prereqs reduce_prereqs call_scripts fi}

41/52

Page 43: initramfsについて

prereqs引数が prereqs の時に依存するものを echo する。(複数ある場合はスペース区切りで列挙)

PREREQ=""

prereqs(){

echo "$PREREQ"}

case $1 in# get pre-requisitesprereqs)

prereqsexit 0;;

esac

42/52

Page 44: initramfsについて

./init (10) init-topフックを実行

# Don't do log messages here to avoid confusing usplashrun_scripts /scripts/init-top

43/52

Page 45: initramfsについて

init (11) load_modules./conf/modules に書いてあるモジュールをロード(/etc/initramfs-tools/modules で設定)

maybe_break modules[ "$quiet" != "y" ] && log_begin_msg "Loading essential drivers"load_modules[ "$quiet" != "y" ] && log_end_msg

自動認識できないモジュールやはやめにロードしないといけないモジュールに使う。

44/52

Page 46: initramfsについて

./init (12) mountmountroot は「. /scripts/${BOOT}」で定義される。(parse_numeric は ROOT=major:minor のような指定を処理している)

maybe_break premount[ "$quiet" != "y" ] && log_begin_msg "Running /scripts/init-premount"run_scripts /scripts/init-premount[ "$quiet" != "y" ] && log_end_msg

maybe_break mountlog_begin_msg "Mounting root file system". /scripts/${BOOT}parse_numeric ${ROOT}maybe_break mountrootmountrootlog_end_msg

45/52

Page 47: initramfsについて

./script/local

run_scripts /scripts/local-top

のようなフックを実行したり"${ROOT}" で指定されているデバイスをマウントしたりマウントできなかったときに

panic "ALERT! ${ROOT} does not exist. Dropping to a shell!"

で「(initramfs) 」のシェルに落ちたりする。

46/52

Page 48: initramfsについて

./init (13) bottom最初の方でマウントした sysfs と proc を本当の root ファイルシステム (real root) に移動する。

maybe_break bottom[ "$quiet" != "y" ] && log_begin_msg "Running /scripts/init-bottom"run_scripts /scripts/init-bottom[ "$quiet" != "y" ] && log_end_msg

# Move virtual filesystems over to the real filesystemmount -n -o move /sys ${rootmnt}/sysmount -n -o move /proc ${rootmnt}/proc

47/52

Page 49: initramfsについて

./init (14) check init

validate_init() { checktarget="${1}"

# Work around absolute symlinks if [ -d "${rootmnt}" ] && [ -h "${rootmnt}${checktarget}" ]; then case $(readlink "${rootmnt}${checktarget}") in /*) checktarget="$(chroot ${rootmnt} readlink ${checktarget} )" ;; esac fi

# Make sure the specified init can be executed if [ ! -x "${rootmnt}${checktarget}" ]; then return 1 fi

# Upstart uses /etc/init as configuration directory :-/ if [ -d "${rootmnt}${checktarget}" ]; then return 1 fi}

48/52

Page 50: initramfsについて

./init (15) check init

# Check init bootargif [ -n "${init}" ]; then if ! validate_init "$init"; then echo "Target filesystem doesn't have requested ${init}." init= fifi

# Common case: /sbin/init is presentif [ ! -x "${rootmnt}/sbin/init" ]; then # ... if it's not available search for valid init if [ -z "${init}" ] ; then for inittest in /sbin/init /etc/init /bin/init /bin/sh; do if validate_init "${inittest}"; then init="$inittest" break fi done fi

# No init on rootmount if ! validate_init "${init}" ; then panic "No init found. Try passing init= bootarg." fifi

49/52

Page 51: initramfsについて

./init (16) unsetenv

# don't leak too much of env - some init(8) don't clear it# (keep init, rootmnt)unset debugunset MODPROBE_OPTIONSunset DPKG_ARCHunset ROOTFLAGSunset ROOTFSTYPEunset ROOTDELAYunset ROOTunset IPunset BOOTunset BOOTIFunset UBIMTDunset blacklistunset breakunset noresumeunset panicunset quietunset readonlyunset resumeunset resume_offset

50/52

Page 52: initramfsについて

./init (17) exec initklibc-utils パッケージ由来の run-init で real root の /sbin/init などを実行

# Chain to real filesystemexec run-init ${rootmnt} ${init} "$@" \ <${rootmnt}/dev/console \ >${rootmnt}/dev/consolepanic "Could not execute run-init."

51/52

Page 53: initramfsについて

real root での処理sysvinit

/etc/inittab に従って処理

upstart

/etc/init/*.conf に従って処理

など

52/52Powered by Rabbit 0.6.4