Rust Foundation logo
写真: ™/®Rust Foundation / CC BY 4.0 / Wikimedia Commons

Linux 7.4に向け、約1万7000行のRustカーネルコードが追加される予定です。更新の中心は、バイト列と構造体を安全に変換するライブラリー「Zerocopy」と、カーネル内でRustを使うための基盤です。自己参照を含む構造体の初期化や診断機能の改善も盛り込まれています。

Linux 7.4向けRustコードで進む更新

Rust for Linuxのメンテナーを務めるMiguel Ojeda氏が、Linux 7.4向けのコードを取り込むプルリクエストを提出しました。今回の更新では、ベンダーとして組み込まれているZerocopyを8バージョン先へ更新するほか、カーネル用の複数のRustクレートも更新します。

Zerocopyは、生のバイト列を構造化された型へ安全に変換するためのトレイトとマクロを提供します。この更新に加え、手続き型マクロ全体の診断を改善するため、不安定機能のproc_macro_spanを有効にするなど、ツールチェーンと開発基盤にも変更が入ります。

カーネルのRustコードには、新たにmemとratelimitの各モジュールが加わり、既存モジュールも改善されます。個別のサブシステムの変更としては、NVIDIA NovaドライバーやRust向けDRM基盤の更新もLinux 7.4に向けて進められています。

自己参照構造体をその場で初期化

カーネル内の構造体には、C側で定義された自己参照構造体を含むものがあります。Rustのpin-initは、こうした構造体を所定のメモリー位置で初期化する仕組みです。pinningは、初期化後にデータが移動しないようにする方法です。

pin_init!マクロは、構造体をメモリー上で直接初期化する、失敗する可能性のある初期化子を作ります。初期化するフィールドは記述順に処理され、初期化中のフィールドへの参照は作れません。

フィールドをその場で初期化する場合は、通常の:ではなく<-を使います。初期化子はエラー型も扱えます。また、初期化関数を用意し、別の構造体へ埋め込む方法もあります。今回の更新では、pin-initがタプル構造体に対応し、安全な自己参照の作成も可能にする予定です。

安全性を支える初期化の条件

カーネルのRustコードでは、Cの構造体や関数を使うためのバインディングと、それらを包む抽象化が分けられています。抽象化はC APIへの直接アクセスを内側に閉じ込め、ドライバーやファイルシステムなどの利用側に、より安全に扱えるAPIを提供します。

pin-initの初期化子では、すでに初期化したフィールドを生ポインター経由で参照できますが、フィールドへの参照は作れません。初期化をメモリー上の位置に結び付け、移動によって自己参照が崩れるのを防ぐ設計です。

Rust側の利用者が未定義動作を起こさないためには、抽象化そのものが健全であり、unsafeブロックやunsafe実装がそれぞれの安全性契約を守る必要があります。pin-initは初期化方法を提供しますが、その安全性はカーネルの抽象化と利用側の契約にも依存します。

Rustから使えるカーネルAPIの範囲

Rustのカーネルコードはstdではなくcoreを利用し、カーネル内で使うクレートは#![no_std]を指定します。C側の関数や型を使うためのバインディングは生成されますが、カーネル内部のAPIすべてにRust向け抽象化が用意されているわけではありません。

そのため、ドライバーなどの末端モジュールはCのバインディングを直接使わず、サブシステムが提供する、できるだけ安全な抽象化を使う方針です。抽象化はCのインターフェースを包み、リソースの取得と解放をコンストラクターやデストラクターに対応させたり、CのエラーコードをRustのResultに変換したりします。