web-dev-qa-db-ja.com

Linuxはrootfsがどこにあるかをどのように知るのですか?

Linuxカーネルが目的のrootfsが起動時にどこにあるかをどのように認識しているかを理解しようとしています。

私はこの文書を読みました:

https://www.kernel.org/doc/Documentation/filesystems/ramfs-rootfs-initramfs.txt

興味のある部分は言う:

すべての2.6 Linuxカーネルにはgzip圧縮された「cpio」形式のアーカイブが含まれており、カーネルの起動時にrootfsに抽出されます...埋め込まれたcpioアーカイブがそこに抽出された後、rootfsにinitプログラムが含まれていない場合、カーネルはルートパーティションを見つけてマウントするための古いコード

私たちのカーネルは4.Xですが、これはまだ当てはまると思いますか?これは、すべてのカーネルに「cpio」rootfsが埋め込まれているようです。

そして確かに私たちがそれを読んでいるように言う:

2.6カーネルビルドプロセスは、常にgzip圧縮されたcpio形式のinitramfsアーカイブを作成し、それを結果のカーネルバイナリにリンクします。デフォルトでは、このアーカイブは空です...構成オプションCONFIG_INITRAMFS_SOURCE ...を使用して、initramfsアーカイブのソースを指定できます。

これにより、さらにいくつかの質問が発生します。

  1. したがって、rootfsをRAMに入れたい場合は、CONFIG_INITRAMFS_SOURCEをrootfsを指すように設定する必要があります(おそらくcpio形式で)。

しかし、それは私のカーネルとrootfsが分離できないことを意味しませんか?再構築せずにRootFSに小さな調整を加えたい場合はどうなりますか? rootfsをカーネルとは別に保存したい場合はどうなりますか? rootfsの場所をカーネルに伝えるにはどうすればよいですか?

  1. さらに、rootfsをRAMではなく物理ストレージ(eMMC、フラッシュドライブなど)に配置したい場合はどうすればよいですか?

それは以前に言った:

埋め込まれたcpioアーカイブが抽出された後にrootfsにinitプログラムが含まれていない場合、カーネルは古いコードにフォールスルーしてルートパーティションを見つけてマウントします

しかし...どうやって? rootfsの場所をどのようにして知るのですか? eMMCにある場合、カーネルに何とかして伝える必要があります。

私が使用しているブートローダーはU-bootです。 U-boot環境変数をチェックして、rootfsの場所をブート引数としてカーネルに渡していないかどうかを確認しましたが、そうではないようです...

編集:

コメントで指摘されているように、rootfsの場所はbootargを介してカーネルに渡されます。私の場合、u-bootはroot=/dev/mmcblk0p4 rwをブート引数としてカーネルに渡します。これで私の質問の1つに答えます-解凍されたrootfsにブート引数として場所を渡すことができます。

カーネルとは別のrootfs.tar.gzを考えると、カーネルにそれをRAM)にアンタールし、rootfsとして使用するように指示する方法はまだわかりません。おそらくそうではありません。可能で、CONFIG_INITRAMFS_SOURCEを使用する必要がありますか?とにかく、4.Xのドキュメントを読みます。

1
Gillespie

したがって、rootfsをRAMに配置する場合は、rootfsを指すようにCONFIG_INITRAMFS_SOURCEを設定する必要があります(おそらくcpio形式で)。

それは1つの方法です、はい、しかしそれはのみではありません) 仕方。

カーネルとinitramfsを別々のファイルとしてロードするように構成できるブートローダーがある場合は、カーネルの構築中に_CONFIG_INITRAMFS_SOURCE_を使用する必要はありません。カーネル構成で_CONFIG_BLK_DEV_INITRD_を設定するだけで十分です。 (initramfsの前は、initrdという名前の古いバージョンの手法があり、古い名前がまだいくつかの場所に表示されています。)ブートローダーはinitramfsファイルをロードし、そのメモリの場所とサイズに関する情報を入力しますすでにロードされているカーネルイメージの特定の場所にあるデータ構造に。カーネルには、その情報を使用してシステム内のinitramfs RAMを見つけ、それを解凍する組み込みルーチンがあります。

Initramfsを個別のファイルとして使用すると、initramfsファイルをより簡単に変更できます。ブートローダーがユーザーからの入力を受け入れることができる場合は、起動時に通常のファイルではなく、別のinitramfsファイルをロードするように指定してください。 (これは、カスタマイズされたinitramfsを作成して、いくつかの問題が発生した場合に非常に便利です。そこに行って、それを実行してください。)

従来のBIOSベースのx86システムの場合、これらの詳細に関する情報は (カーネルソース)/Documentation/x86/boot.txt にあります。 UEFIベースのシステムはそれを少し異なって行い(同じファイルにも記述されています)、ARMのような他のアーキテクチャには、ブートローダーからカーネルへの情報の受け渡しに関する独自の詳細セットがあります。

さらに、rootfsをRAMではなく物理ストレージ(eMMC、フラッシュドライブなど)に配置したい場合はどうすればよいですか?

通常の非組み込みシステムでは、initramfsには通常、必須のサブシステムをアクティブ化するのに十分な機能のみが含まれます。通常のPCでは、これらは通常、ルートファイルシステムのキーボード、ディスプレイ、ストレージコントローラーのドライバーに加えて、LVM、ディスク暗号化、ソフトウェアRAIDなどのサブシステムをアクティブ化するために必要なカーネルモジュールとツールです。これらの機能を使用する場合。

重要なサブシステムがアクティブになり、ルートファイルシステムにアクセスできるようになると、initramfsは通常pivot_root(8)操作を実行して、initramfsから実際のルートファイルシステムに切り替えます。しかし、組み込みシステム、または [〜#〜] dban [〜#〜] のような特殊なユーティリティは、必要なすべてのものをinitramfsにパッケージ化し、_pivot_root_操作を実行することはできません。

通常、initramfs内のスクリプトやツールは、カーネルコマンドラインのオプションから実際のルートファイルシステムを見つけるために必要な情報を取得します。しかし、それを行う必要はありません:カスタマイズされたinitramfsを使用すると、特定のキーまたはマウスがあれば、別のルートファイルシステムに切り替えるようなことができます。ボタンは、ブートシーケンスの特定の時間に押し続けられます。

複雑なストレージ構成(ソフトウェアRAID上の暗号化LVM、冗長マルチパスSANストレージ)を使用するシステム)では、ルートファイルシステムをアクティブ化するために必要なすべての情報が、カーネルコマンドライン。より大きな部分をinitramfsに含めることができます。


最新のディストリビューションは通常、initramfsジェネレーターを使用して、インストールされたカーネルごとに調整されたinitramfsを構築します。さまざまなディストリビューションが独自のinitramfsジェネレーターを持っていました。RedHatはmkinitrdを使用しましたが、Debianは_update-initramfs_を使用していました。しかし、systemdの導入後、多くのディストリビューションがinitramfsジェネレーターとして dracut で標準化されているようです。

最新のinitramfsファイルは、複数の_.cpio_アーカイブを連結したものにすることができ、各部分は圧縮される場合とされない場合があります。最近のx86_64システムの一般的なinitramfsファイルには、最初のコンポーネントとして「初期マイクロコード更新」ファイルが含まれている可能性があります(通常、マイクロコードファイルは暗号化されているため、あまり圧縮できないため、非圧縮cpioアーカイブ内の単一ファイルのみ。圧縮された_.cpio_ファイルとしての通常のinitramfsコンテンツ。

システムをより深く理解するために、initramfsファイルを一時ディレクトリに抽出して、その内容を調べることをお勧めします。 Debianには、簡単な方法でinitramfsファイルを抽出するために使用できるunmkinitramfs(8)ツールがあります。 RedHat 7では、_/usr/lib/dracut/skipcpio <initramfs file>_を使用してマイクロコード更新ファイルをスキップし、結果の出力をgzcatにパイプして_cpio -i -d_にパイプし、initramfsの内容を現在のコンテンツに抽出する必要がある場合があります。作業ディレクトリ。 Ubuntuはlzcatの代わりにgzcatを使用する場合があります。

2
telcoM

まず第一に、カーネルのドキュメントにある「2.6」への参照を怖がらないでください。現在のカーネルはまだ「2.6」ラインのメンバーですが、「マーケティング目的」のためだけに2ラウンドの番号付けを繰り返しました(したがって、2.6.40は3.0になり、3.20は4.0になりました)。 4.19カーネルには通常2.6.79というラベルが付いています。

ここでは「rootfs」の意味について混乱が生じているようです。 「rootfs」は、カーネルによって内部的に使用される特別なRAMベースのファイルシステムです。これは、/run/dev/shm、場合によっては/tmpなどの場所に一般的にマウントされる「tmpfs」ファイルシステムとまったく同じです。 (まあ、「tmpfs」機能がカーネルにコンパイルされていない場合を除いて、その場合は「ramfs」と呼ばれる削除された「tmpfs」が代わりに使用されます。)これらのファイルシステムはページキャッシュに存在するだけで、 ramfs、tmpfsは利用可能な場合はスワップによってバックアップされます。

したがって、カーネルは「rootfs」を「見つける」ことについて心配する必要はありませんが、起動時にページキャッシュ全体が空であるため、何らかの方法でそれを設定する必要があります。そこで、「initramfsファイル」が役立ちます。これは、カーネルによって空の「rootfs」に解凍される(圧縮された)cpioアーカイブ(ドキュメントに記載されている理由によりtarではありません)です。このアーカイブは、ビルド中にCONFIG_INITRAMFS_SOURCEを設定してカーネルイメージに直接埋め込むか、ブートローダーによって提供されます(GRUBのinitrdオプションが行うことです)。このアーカイブは通常、dracutや(紛らわしい)mkinitrdなどのユーザースペースツールを使用して作成されます。

Cpioイメージが利用できないか、実行可能ファイル/initが含まれていない場合、カーネルは別のメソッドにフォールバックし、root=コマンドライン引数を調べて、実際のルートの場所として解釈しますファイルシステムは、それを/にマウントし、initを直接実行します。ただし、必要なすべてのストレージおよびファイルシステムドライバーをカーネルに直接コンパイルする必要があるため、これが最近使用されることはめったにありません。ほとんどのシステムでは、root=引数はカーネルでは使用されず、initramfsの/initで処理されます。その/init(通常はsystemdまたはシェルスクリプトのいずれか)が、必要なモジュールのロード、実際のルートファイルシステムのマウント、およびそれに切り替えます。

昔は、現代の「initramfs」の代わりに「initrd」と呼ばれる別のメカニズムが使用されていました。 「initrd」(「init ramdisk」)は、実際のファイルシステム(ext2など)で初期化されたRAMベースのブロックデバイスであり、そのイメージは、最新のcpioアーカイブと同じように提供されました。そのため、多くの場所では、これらのアーリーブートのものを参照するために「initrd」名が使用されています。

4
TooTea