- Rust for Linuxプロジェクトが、カーネル開発に必要な中核的な言語機能を推進し、Rust言語そのものの発展にも貢献している
- フィールドプロジェクション(Field Projection)、インプレース初期化(In-place Initialization)、任意のSelf型(Arbitrary Self Types) の3つが中核
- これらの機能により、スマートポインタ、固定メモリ(Pin)、RCUなどカーネル特有の構造をRustでより自然に表現できるようになる
- Rustチームは設計の安定性を重視するため開発速度は遅いが、Linuxカーネルという明確な目標のおかげで開発の集中度が高まっている
- カーネル外のRustエコシステムにも波及効果をもたらす変化であり、スマートポインタ処理とコード簡素化に大きく役立つ見込み
Rust言語の改善とLinuxカーネルの役割
- Rust言語の新機能開発が遅い理由は、悪い設計を言語に固定化しないための慎重さと「関心の整列(alignment in attention)」の問題にある
- Rustプロジェクトはボランティアによって運営されているため、特定機能に集中する人がいなければ開発が停滞する
- Rust for Linuxプロジェクトは多くの人が熱意を持つテーマであり、カーネルに必要な少数の中核機能に努力を集中させる助けになっている
- Rust言語チーム共同リーダーのTyler MandryはKangrejos 2025で、Rustの今後の言語機能を発表し、LinuxカーネルプロジェクトがRust発展の触媒として機能したと述べた
- 主な機能: フィールドプロジェクション、インプレース初期化、任意のSelf型(Arbitrary self types)
- カーネル開発が実際のユースケースと技術的要件を明確に示し、Rustの言語設計の方向性を具体化することに貢献
- 最優先事項は、カーネルバインディングですでに使われている不安定(unstable)機能の標準化
Field Projection(フィールドプロジェクション)
- 構造体ポインタから特定のフィールドへのポインタを取り出す機能で、Cの
&(r->field) という表現をRustで一般化しようとする試み
- これまでは参照(
&) と ポインタ(*mut) でのみ可能だったが、ユーザー定義スマートポインタでは制限があった
- Rust for Linuxはこれを拡張し、すべてのポインタ型で同じ構文によるフィールドアクセスが可能になるよう推進している
- 特にPin 型(移動不可の構造体)を扱う場合、フィールド投影時に
Pin<&mut Field> または &mut Field に自動変換されるよう設計されている
- この機能が実装されれば、RCU(Read-Copy-Update) パターンをRustで安全にサポートでき、ロックなしでも高性能なデータアクセスが可能になる
- 現在GitHubの tracking issue で議論中で、Debian 14(2027) 以前の安定化を目標としている
Arbitrary Self Types(任意のSelf型)
- スマートポインタを受け取るメソッド定義を可能にする機能
- これまでは
fn method(&self) 形式のみ対応していたが、今後は fn method(self: Pin<&mut MyStruct>) のような形式も可能になる
- カーネルでは Arc、Pin、Mutex など多様なポインタラッパーを使うため、不可欠な機能
- 実装過程では Derefトレイトとの衝突という問題があったが、新しい Receiverトレイト の導入によって解決が進められている
- Receiverは、任意のSelf型として使えるポインタであることを明示する役割を持つ
- カーネル開発ではこれにより、ポインタチェーン呼び出しを簡潔に保つことができる
- DingはCraterツールを使って既存Rustパッケージとの互換性を検証中で、1年以内の安定化の可能性に言及している
In-place Initialization(インプレース初期化)
- カーネルで使われている
pin_init!() マクロを言語レベルでサポートする機能
- オブジェクトを生成後に移動させず、メモリ上で直接初期化する機能で、Pin構造体、Future、dynトレイト などに有用
- 3つの提案が並行して議論されている
- initキーワード方式: 最小限の構文追加で既存の
PinInit トレイトを活用
&out 参照方式: Cのoutポインタのような書き込み専用参照を追加し、フィールド単位の初期化をサポート
- C++スタイル最適化方式: ヒープへ即時移動されるオブジェクトを最初からヒープ上に直接生成
- 最終的には PinInit と out-reference方式 の両方を実験し、実際の使い勝手を検証する計画
- この機能が導入されれば、カーネルだけでなく非同期Rustコード全般の構造簡素化にも寄与すると見込まれる
Rust for LinuxがRustに与える影響
- LinuxカーネルはRust言語の発展において現実的なテストベッドの役割を果たしている
- 3つの機能はいずれもスマートポインタ、固定メモリ、並行性構造といったカーネル特有の要求から出発しているが、
結果として一般のRust開発者も恩恵を受けることになる
- これらの変化は、カーネルと言語開発の間にある好循環の構造を示す事例として評価されている
2件のコメント
Hacker Newsの意見
Rustのlightweight clones機能に関するRFC文書を読んで理解するのに少し時間がかかった。最初はこの機能がかなり興味深いと思ったが、結局のところRustは学ぶのが複雑な言語だということを改めて感じた。RustやC++をきちんと学んでいない自分のような立場からすると、modern C++のあらゆる概念や機能がHaskellの要素と結びついたような印象だ。それでも人々がRustで有用なものをたくさん作っているのを見ると、何か確かなものがあるのだろうと感じる。なので近いうちにもう一度本格的にRustを使ってみようと思う。関連RFCリンク
私の経験では、C++のほうがRustよりはるかに複雑だ。たとえば初期化方法だけでも8種類あり、値の型だけでもxvaluesなど5種類あり、フォーマットや命名規則も一貫しておらず、rule of 5、例外処理、move assignmentのたびに
this != otherを確認しなければならないこと、perfect forwarding、SFINAE、traitの代替物の問題など、複雑な点が多すぎる。C++をきちんと使うには、標準の上に積み重なった、安全かつ高速にコーディングするための慣習も一緒に身につける必要があるし、例外処理のような手法どうしが衝突したり、理想的でないやり方を選ばざるを得ない場合も多いRustコミュニティでは、このlightweight clones提案に対して次第に否定的な雰囲気になっている。理由は複雑すぎるからだ。設計方針に関するRust公式文書でも、複雑さが最大の障害になっている。Rustの提案では、どんな機能も必ず単純でなければならないわけではないが、lightweight cloneはすでにできることを少し簡単にするだけであり、人々が簡単に理解できないのであれば、それは問題だ
Rustは遠くから見るとあまりにも巨大だが、実際にコーディングするとすぐ慣れる。たとえば最初はlifetimeの概念をまったく理解できず、Rc<>だけでコーディングしていた。基礎を身につけてからlifetimeを改めて勉強すると、ずっと簡単になった。実際、ほとんどのユーザーはlightweight clonesのような機能を気にすることすらない
Cに比べれば非常に複雑だが、C++に比べればはるかに単純な言語だ。コードを理解するために文書やリファレンスを漁る必要がほとんどないレベルだ。Rustは「複雑すぎて頭を抱えることもなく、単純すぎてコードが複雑になることもない」という、非常にちょうどよい位置にある。しかも基本的にコードがcorrectnessを備える
Rustの複雑さは、C++のようにうっかり誤用しやすい種類のものではない。しかもclippyを使えば、よりidiomaticなコードへ自動変換してくれるので、lightweight clonesのような新しい機能を自分で知らなくても提案してもらえる。大半はclippyの
--fixオプションだけで簡単に適用できる。こうした点がC++と決定的に異なっており、C++では使わない機能が積み上がったり、過度に複雑な書き方ばかりになったりして、複雑さが蓄積していく副作用が続くRust for LinuxプロジェクトがRustに大きく貢献したという話があったので、興味本位でカーネルツリー内の
"*.rs"ファイルを探してみた。見ると、rustフォルダの下にAPI互換レイヤーがあり、カーネルツリーには既存ドライバを単にrewriteしたproof of conceptドライバが少しあるだけで(未完成のNVIDIAドライバを除く)、実際に使われているものはほとんどないように見える。Android binderのRustリライトも、ほぼ置かれているだけの状態に見える。全体的な印象としては、ただの小ぢんまりした実験プロジェクトという感じで、世界で最も重要なソフトウェアのソースツリーでこうした言語の共同開発実験をする必要があるのか疑問に思う。むしろRedoxのような、もっと実験的なOSでやるほうがよいのではないかと思うApple silicon向けのGPUドライバはRustで書かれており、作者本人がCで開発していたらはるかに困難だっただろうと述べている。まだupstreamには入っていないが、「複雑なカーネルドライバを新たに作ると、race condition、memory leak、use-after-freeなど、ありとあらゆる問題が起きがちだが、Rustで書くとそうした問題はほとんどなく安定して動作する。安全性機能のおかげで、ドライバがthread-safeかつmemory-safeだと確信でき、設計そのものも自然によい方向へ進む。これがRustの魔法だと思う」と語っている。作者の体験談リンク そして、このような実験をカーネルツリーで行ってよいのかという問いに対して、Torvaldsは反対していないと述べられている
「Android binderのRustリライトが置かれているだけだ」という意見は事実ではない。このプロジェクトは現在、C実装を完全に置き換える計画だ。関連記事 MシリーズAppleハードウェア向けの主要ドライバもRustで書かれており、単なるリライトやproof of conceptではない
複雑なドライバを作るには、その前にインターフェース層が必要だ。RfLプロジェクトはそうしたインフラ層をupstreamに追加する作業を進めており、その基礎が積み上がって初めて複雑なドライバも書けるようになる。Red Hatではnova、AsahiではApple GPU、CollaboraではARM Mali向けに作業中だ。GPUドライバが3つもあって、それでも複雑なドライバではないと言うなら、何が複雑なドライバなのか疑問だ
Rust binderリライトが置かれているだけだという主張については、Linusツリーのコミットメッセージを見ると完成度はかなり高い。Rust binderはAndroid Open Source Projectのbinderテストをすべて通過しており、さまざまなアプリや機能が特に問題なく動作している。cuttlefishエミュレータやPixel 6 Proでも起動およびアプリ実行に問題はない。現在の機能もC binderと同等で、一部のデバッグ機能だけが残っており、まもなく追加される予定だ。また、Rust for Linuxプロジェクトはもともとカーネルツリー外で始まったが、最終的に実際の統合を試すにはツリー内で試験しなければならない
このプロジェクトの目的は言語開発の共同実験ではなく、Linuxカーネル開発にRustを使うことだ。中核開発者たちがRustを使いたくて自ら始めたプロジェクトだ。非常に重要なソフトウェアなので慎重に進められており、基礎固めに時間がかかっている。Rustがこのプロジェクトを通じて副次的な恩恵を受けるのはおまけにすぎない
<i>field projectionに関する話で、すべての構造体フィールドが今や構造的にpinされ、常にPin<&mut Field>型などが得られるように決まった</i>と記事で見て、この部分を以前見落としていたことに気づいた。技術的に複雑な話だが、この決定によって多くの議論の足かせになっていた問題が解決されたのはうれしい
<i>最終設計はC++に着想を得て、値をheapに割り当てるために新しい値を作ってすぐ移動する際、最初からheap上に生成されるようにする予想最適化手法</i>について人々が議論している。ここで「最適化」という名前は誤解を招きやすいため、名称変更についての議論がある
私が問題の複雑さをきちんと理解していないのかもしれないが、適切なcalling conventionさえ決めれば簡単に解決できるのではないかと思う。構造体のサイズがxより大きいかmarker typeがあれば、callerがoutrefでバッファを渡し、calleeがそのバッファに直接構造体を書き込む方式だ。そうすれば通常のコードを書くだけでヒープ割り当ての重複を防げるし、他の場面でも不要なコピーを減らせる。すでに多くの努力が注がれているテーマなので、むしろ提案されている解決策がなぜより扱いにくいのか気になる
このような機能は内部最適化として処理するのではなく、
newのような関数で明示的にしたほうが、誰にとっても直感的だと思うC++ではこのようなsemanticをelisionと呼ぶ
coalesced heap constructionやcoalesced heap allocationのような名前はどうかと提案するRustのさまざまな機能の話を聞くたびに、「tokioをカーネルに入れるようなことだけは絶対にやめよう」という冗談を言いたくなる。もしRustが十分に発展し、direct composition rendererが登場してカーネル全体で動くアプリが可能になれば、それはそれでかなり興味深い状況になるかもしれない
カーネル内でasync runtimeを実装するのは本当にtrivialだ。実際、kernelのworkqueue自体がすでにruntimeだ
冗談でないのなら、Rust(そしてC)でカーネルコードを書くときの構造を根本的に誤解している。カーネルでコーディングするときは、C stdlibと同様にRustも
no_stdで動作し、cargoやcratesも使えない。tokioを使うには半分ほど書き直して、socketなどOSとのやり取りをすべてカーネル流に置き換える必要があるLinux向けに今回入るRust関連機能は、カーネルに限らずRust言語全体に幅広く有用な最初の機能群だと思う。カーネル中心の機能開発が、他の言語機能やライブラリ機能の開発を少し妨げていたようにも感じる
私の理解では、systems programmingこそがRustの優先適用分野だ。OS、embedded、あるいは複雑なCベースのシステムなどで、interoperabilityが中核になる。今回の機能は実際にはカーネル専用ではなく、現実のシステムプログラミングで本当に必要な汎用ユーティリティのように見える
カーネル/ファームウェア開発のための進展は各所で起きているが、常にみんなの関心の的になっているわけではない。Philippは特にこの分野で大きな変化を導いている
Rustの主戦場はlow levelシステムプログラミングだ。それ以外の領域では、userspaceでコンパイルされるmanaged言語のほうがはるかによい選択肢であり、SelfやInferno、Androidのアーキテクチャのように構成されたシステムでは、このようなlow levelなCスタイル機能に集中しても問題ないと思う
こうした機能はカーネルだけでなく他の領域にも役立つほど優れている(特にgeneralized projections)。LinuxがRust言語の発展を牽引しているという点がとても満足だ
LLMを使ってCコードを自動的にRustへ変換する研究やツールがあるのか気になる。LLMにchat、usb、i2c、GPU driverなどのRustコードを書かせて、ビルドやテストまでさせることが可能なのか、あるいはsqlite、apache、nginxのような「より小さい」プロジェクトでも試せるのか考えている
LLMベースではない研究として、実例もあるc2rustプロジェクトがある。LLMは基本的にapproximationにとどまるので正確にできず、subtleなバグが多すぎる。formal methodのようなものを組み合わせない限り実用的ではない。単体テストだけでは見つからない問題も多い。そして「より小さい」プロジェクトとして挙げられていた例も、実際には十分小さいとは言えない。実際の適用事例を参照してほしい
Darpaでもこうした研究に関心を持って資金提供を行っているが、まだ成果物が出ている段階ではない
教条主義におけるアライメント(alignment in dogmatism)