ユーザー空間を壊さないLinuxカーネルポリシーがあるのはなぜですか?


38

Linux Kernel Mailing listのエチケットの文脈でこの問題について考え始めました。世界で最もよく知られ、ほぼ間違いなく最も成功している重要なフリーソフトウェアプロジェクトとして、Linuxカーネルは多くの報道を受けています。そして、プロジェクトの創設者でありリーダーであるLinus Torvaldsは、ここで紹介する必要はないことは明らかです。

ライナスは時折、LKMLの炎で論争を呼び起こします。これらの炎は、彼自身の容認により、ユーザー空間の破壊に関係していることが多い。それは私の質問に私をもたらします。

ユーザー空間を壊すことがなぜそんなに悪いことなのか、歴史的な見方をすることはできますか?私が理解しているように、ユーザースペースを壊すにはアプリケーションレベルでの修正が必要になりますが、カーネルコードを改善する場合、これはそんなに悪いことですか?

私が理解しているように、Linusのポリシーは、ユーザー空間を壊さないことがコード品質を含む他のすべてよりも優先するというものです。なぜこれがそんなに重要なのか、そしてそのようなポリシーの長所と短所は何ですか?

(Linusは時折、まさにこのトピックに関するLKMLのトップ中euと「意見の相違」を持っているため、一貫して適用されるこのようなポリシーには明らかにいくつかの短所があります。


1
はじめにLinusの名前のつづりを間違えました。
イスマエルミゲル

確かではありませんでしたが、私は投票するのを忘れて、今すぐ投票しました。
イスマエルミゲル

回答:


38

その理由は歴史的なものではなく、実際的なものです。Linuxカーネル上で実行される多くの多くのプログラムがあります。カーネルインターフェイスがこれらのプログラムを中断した場合、誰もがそれらのプログラムをアップグレードする必要があります。

現在、ほとんどのプログラムは実際にはカーネルインターフェイス(システムコール)に直接依存せず、C標準ライブラリ(システムコールのC ラッパー)のみに依存しているのは事実です。ああ、しかしどの標準ライブラリですか?Glibc?uClibC?Dietlibc?バイオニック?ムスル?等

しかし、OS固有のサービスを実装し、標準ライブラリによって公開されていないカーネルインターフェイスに依存する多くのプログラムもあります。(Linuxでは、これらの多くは/procおよびを通じて提供され/sysます。)

そして、静的にコンパイルされたバイナリがあります。カーネルのアップグレードによりこれらのいずれかが破損した場合、唯一の解決策はそれらを再コンパイルすることです。ソースがある場合:Linuxは独自のソフトウェアもサポートしています。

ソースが利用できる場合でも、すべてを収集するのは苦痛です。特に、カーネルをアップグレードしてハードウェアのバグを修正する場合。多くの場合、ハードウェアのサポートが必要なため、カーネルはシステムの他の部分から独立してアップグレードされます。Linus Torvalds言葉では

ユーザープログラムを破ることは、単に受け入れられません。(…)人々は古いバイナリを何年も使用していることを知っています。新しいリリースを作成しても、単にそれを捨てることができるわけではありません。あなたは私たちを信頼することができます。

彼はまた、これを強力なルールにする1つの理由は、新しいカーネルを動作させるために別のプログラムをアップグレードする必要があるだけでなく、さらに別のプログラムをアップグレードする必要がある依存性の地獄を避けるためであると説明していますなぜなら、すべてはすべての特定のバージョンに依存しているからです。

それはだ、やや明確に定義された一方向の依存性を持たせ、[OK]。それは悲しいですが、時々避けられません。(…)大丈夫ではないのは、双方向の依存関係を持つことです。ユーザー空間のHALコードが新しいカーネルに依存している場合は問題ありませんが、ユーザーが「今週のカーネル」ではなく、「過去数か月のカーネル」になることを望んでいると思いますが。

しかし、双方向の依存関係がある場合、あなたはうんざりしています。それは、ロックステップでアップグレードする必要があることを意味し、それは単に受け入れられません。ユーザーにとっては恐ろしいことですが、さらに重要なことは、開発者にとっては恐ろしいことです。なぜなら、「バグが発生した」とは言えず、二分法などでそれを絞り込もうとすることを意味するからです。

ユーザー空間では、これらの相互依存関係は通常、異なるライブラリバージョンを保持することで解決されます。ただし、実行できるのは1つのカーネルだけなので、人々がそれでやりたいことをすべてサポートしなければなりません。

公式に

[安定と宣言されたシステムコール]の下位互換性は、少なくとも2年間保証されます。

しかし実際には、

ほとんどのインターフェイス(syscallsなど)は決して変更されず、常に使用可能であることが期待されます。

より頻繁に変更されるのは、ハードウェア関連のプログラムでのみ使用されることを意図したインターフェイスです/sys。(/proc一方、の導入は/sys非ハードウェア関連サービスのために予約されていたため、互換性のない方法で中断することはほとんどありません。)

要約すれば、

ユーザースペースを壊すには、アプリケーションレベルでの修正が必要です

システムの残りの部分から独立してアップグレードしたいカーネルは1つしかありませんが、複雑な相互依存関係を持つ多くのアプリケーションが存在するため、それは悪いことです。数百万の異なるセットアップで数千のアプリケーションを最新に保つために、カーネルを安定させるのが簡単です。


1
答えてくれてありがとう。だから、安定していると宣言されているインターフェイスは、POSIXシステムコールのスーパーセットですか?歴史についての私の質問は、この実践がどのように進化したかです。おそらく、Linuxカーネルのオリジナルバージョンは、少なくとも最初はユーザースペースの破損を心配していなかったと思われます。
ファヒムミタ

3
@FaheemMithaはい、彼らは1991年からそうしました。Linusのアプローチは進化したとは思わず、常に「通常のアプリケーションのインターフェースは変わらず、カーネルに非常に強く結び付けられているソフトウェアのインターフェースはほとんど変わりません」と考えていました。
ジル 'SO-悪である停止'

24

相互依存システムでは、基本的に2つの選択肢があります。抽象化と統合。(私は意図的に専門用語を使用していません)。抽象化では、APIの呼び出しを行うと、APIの背後のコードが変更される可能性がありますが、結果は常に同じであると言っています。たとえばfs.open()、ネットワークドライブ、SSD、ハードドライブのいずれでもかまいませんが、電話をかけると、常にオープンファイル記述子を取得できます。「統合」の目標は、方法が変わっても、物事を行うための「最良の」方法を提供することです。たとえば、ネットワーク共有とディスク上のファイルでは、ファイルを開くことが異なる場合があります。両方の方法は、最新のLinuxデスクトップでかなり広く使用されています。

開発者の観点からは、「すべてのバージョンで動作する」または「特定のバージョンで動作する」という問題です。この好例がOpenGLです。ほとんどのゲームは、OpenGLの特定のバージョンで動作するように設定されています。ソースからコンパイルするかどうかは関係ありません。ゲームがOpenGL 1.1を使用するように作成されていて、3.xで実行しようとしている場合、楽しい時間を過ごすことはできません。スペクトルのもう一方の端では、一部のコールは、何があっても機能すると予想されます。たとえば、私はfs.open()自分がどのカーネルバージョンであるかを気にしたくないと電話したいと思います。ファイル記述子が欲しいだけです。

それぞれの方法には利点があります。統合は、下位互換性を犠牲にして「新しい」機能を提供します。抽象化は、「新しい」呼び出しよりも安定性を提供します。優先順位の問題であり、可能性ではないことに注意することが重要です。

共同体の立場から、本当に正当な理由がない限り、複雑なシステムでは抽象化が常に優れています。たとえば、fs.open()カーネルのバージョンによって異なる動作をする場合を想像してください。次に、単純なファイルシステム対話ライブラリでは、数百の異なる「ファイルを開く」メソッド(またはブロック)を維持する必要があります。新しいカーネルバージョンがリリースされた場合、「アップグレード」することはできず、使用したすべてのソフトウェアをテストする必要があります。カーネル6.2.2(偽物)は、テキストエディターを破壊する可能性があります。

いくつかの実世界の例では、OSXはユーザー空間の破壊を気にしない傾向があります。彼らはより頻繁に「抽象化」よりも「統合」を目指しています。そして、主要なOSアップデートのたびに、状況は崩れます。それは、ある方法が他の方法より優れていると言うことではありません。それは選択と設計の決定です。

最も重要なことは、Linuxエコシステムが素晴らしいオープンソースプロジェクトで満たされていることです。人々やグループが自由な時間にプロジェクトに取り組んだり、ツールが役立つためです。それを念頭に置いて、2番目に楽しいことをやめてPIAになり始めると、それらの開発者は別の場所に行きます。

たとえば、にパッチを提出しましたBuildNotify.py。私が利他的だからではなく、ツールを使用し、機能が欲しかったからです。簡単だったので、ここでパッチを用意します。それが複雑な場合、または面倒な場合は、使用せず、BuildNotify.py他の何かを見つけます。カーネルの更新が出るたびにテキストエディターが壊れた場合は、別のOSを使用するだけです。コミュニティへの私の貢献(わずかではありますが)は継続も存続もしません。

したがって、設計上の決定は、システムコールを抽象化するために行われたので、私がfs.open()それを行うときはうまく機能します。それは、人気を得てfs.openからずっと維持することを意味しfs.open2()ます。

歴史的に、これは一般的なPOSIXシステムの目標です。「ここに一連の呼び出しと期待される戻り値があります。中間を見つけてください。」再び移植性の理由から。Linusがその方法論の使用を選択する理由は、彼の脳の内部にあり、あなたは彼に正確な理由を尋ねなければなりません。しかし、私なら、複雑なシステムでの統合よりも抽象化を選択します。


1
ユーザー空間のAPIである「syscall」APIは、明確に定義されており(特にPOSIXサブセット)、安定しています。その一部を削除すると、インストールされているソフトウェアが破損する可能性があるためです。持っていないのは安定したドライバー APIです。
pjc50

4
@FaheemMitha、それは逆です。カーネル開発者は、次のリリースの前にカーネル内のすべてのドライバーを修正する限り、いつでもドライバーAPIを自由に壊すことができます。ユーザースペースAPIを壊している、あるいはユーザースペースを壊す可能性のあるAPI以外の操作を行っていて、Linusから壮大な反応を生み出しています。
マーク

4
たとえば、ある状況でioctl()から別のエラーコードを返すことで変更することを決定した場合:lkml.org/lkml/2012/12/23/75(責任のある開発者に対する宣誓および個人攻撃が含まれます)。PulseAudioが壊れ、GNOMEシステム上のすべてのオーディオが壊れていたため、このパッチは拒否されました。
pjc50

1
@FaheemMitha、基本的に、def add(a、b); a + bを返します。end --- def add(a、b); c = a + b; return c; end --- def add(a、b); c = a + b +10; return c-10; end-addの「同じ」実装です。彼がとても怒っているのは、人々がdef add(a、b)をするときです。return(a + b)* -1; 本質的に、カーネルに対する「内部」の動作を変更することは問題ありません。定義された「パブリック」APIコールに返されるものを変更することはできません。「プライベート」と「パブリック」の2種類のAPI呼び出しがあります。彼は、正当な理由がない限り、パブリックAPI呼び出しは決して変更されるべきではないと感じています。
coteyr

3
非コード例。あなたは店に行き、87オクタンのガスを買います。あなたは、消費者として、ガスの出所や処理方法を「気にしません」。あなたはちょうどあなたのガスを得る気になります。ガスが別の精製プロセスを経たとしても、気にする必要はありません。精製プロセスは変更できます。さまざまな油源もあります。しかし、あなたが気にするのは87オクタンのガスを得ることです。したがって、ポンプで出てくるのが87オクタンガスである限り、彼の立場は、ソースの変更、精製所の変更、これまでの変更です。「舞台裏」のものはすべて重要ではありません。87オクタンガスがある限り。
coteyr

8

それは設計上の決定と選択です。Linusは、非常にまれで例外的な(セキュリティ関連など)状況を除いて、カーネルの変更がアプリケーションを壊さないことをユーザー空間開発者に保証したいと考えています。

長所は、ユーザー空間の開発者が、arbitrary意的で気まぐれな理由で、新しいカーネルで突然コードが壊れることに気付かないことです。

欠点は、カーネルが古いコードや古いシステムコールなどを永久に(または、少なくとも使用期限を過ぎて)保持する必要があることです。


返信してくれてありがとう。この決定がどのように進化したかの歴史をご存知ですか?私は、やや異なる視点をとるプロジェクトを知っています。たとえば、Mercurialプロジェクトには固定のAPIがなく、それに依存するコードを実行したり中断したりできます。
ファヒームミタ

いいえ、申し訳ありませんが、それがどのようにして生じたのか思い出せません。LinusまたはLKMLにメールして、彼に尋ねることができます。
cas

2
MercurialはOSではありません。OSの重要なポイントは、その上で他のソフトウェアを実行できるようにすることであり、他のソフトウェアを壊すことは非常に人気がありません。比較すると、Windowsは非常に長い間、後方互換性も維持しています。16ビットのWindowsコードは、ごく最近廃止されました。
pjc50

@ pjc50それはMercurialがOSではないことは事実だが、かかわらず、そこにある他のソフトウェアも、それに依存するだけのスクリプト、場合、。また、変更によって破損する可能性があります。
ファヒムミタ
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.