ページキャッシュに100%ページインされたファイルが別のプロセスによって変更されるとどうなりますか


14

ページキャッシュページが変更されると、ダーティとマークされ、ライトバックが必要になることがわかりますが、次の場合はどうなりますか。

シナリオ: 実行可能ファイルであるファイル/ apps / EXEは、ページキャッシュに完全にページインされ(そのページはすべてキャッシュ/メモリにあり)、プロセスPによって実行されています

連続リリースは、/ apps / EXEをまったく新しい実行可能ファイルに置き換えます。

前提1: プロセスP(および古い実行可能ファイルを参照するファイル記述子を持つ他の人)は、メモリ内の古い/ apps / EXEを問題なく使用し続け、そのパスを実行しようとする新しいプロセスが取得されると仮定します新しい実行可能ファイル。

仮定2: ファイルのすべてのページがメモリにマップされていない場合、ファイルのページを置き換えるページフォールトが発生するまで問題はなく、おそらくセグメンテーション違反が発生すると仮定しますか?

質問1: ファイルのすべてのページをvmtouchのようなものでロックすると、シナリオはまったく変わりませんか?

質問2: / apps / EXEがリモートNFS上にある場合、違いはありますか?(私は仮定しない)

2つの仮定を修正または検証し、2つの質問に答えてください。

これが、ある種の3.10.0-957.el7カーネルを備えたCentOS 7.6ボックスであると仮定しましょう。

更新:さらに考えてみると、このシナリオは他のダーティページシナリオと何の違いもないのではないかと思います。

新しいバイナリを書き込むプロセスは、すべてページングされているため、すべてのキャッシュページを読み取り、すべてのキャッシュページを取得し、それらのすべてのページがダーティとしてマークされると仮定します。ロックされている場合、参照カウントがゼロになった後、コアメモリを占有する無駄なページになります。

現在実行中のプログラムが終了すると、他のものはすべて新しいバイナリを使用すると思われます。それがすべて正しいと仮定すると、ファイルの一部のみがページインされる場合にのみ興味深いと思います。


明示的にするために、ファイルを置き換えることは大きなことではありません(アプリケーションによってファイルが再度開かれるかどうか、およびアプリケーションが変更されたコンテンツにどのように反応するかによって異なります) Javaの世界では、mmapされたディレクトリエントリを持つzipファイルが変更されるとき)。ただし、プラットフォームに依存するため、マップされた領域が変更を認識できるかどうかは保証されません。
eckes

回答:


12

連続リリースは、/ apps / EXEをまったく新しい実行可能ファイルに置き換えます。

これは重要な部分です。

新しいファイルがリリースされる方法は、新しいファイルを作成し(例/apps/EXE.tmp.20190907080000)、内容を書き、パーミッションと所有権を設定し、最終的に名前を最終的な名前に変更します(2)/apps/EXE古いファイルを置き換えます。

その結果、新しいファイルには新しいiノード番号が付けられます(つまり、実際には別のファイルです)。

また、古いファイルには独自のiノード番号があり、ファイル名がそれを指していなくても(または、そのiノードを指しているファイル名がもうない場合でも)実際にはまだ残っています。

したがって、ここで重要なのは、Linuxで「ファイル」について話すとき、ファイルが開かれるとiノードがファイルへの参照であるため、ほとんどの場合「iノード」について話すことです。

仮定1:プロセスP(および古い実行可能ファイルを参照するファイル記述子を持つ他の人)は問題なくメモリ/ apps / EXEで古いものを使用し続け、そのパスを実行しようとする新しいプロセスは取得すると仮定します新しい実行可能ファイル。

正しい。

仮定2:ファイルのすべてのページがメモリにマップされていない場合、ファイルのページを置き換えるページフォールトが発生するまで問題はなく、おそらくセグメンテーション違反が発生すると思いますか?

間違っています。古いiノードはまだ存在しているため、古いバイナリを使用するプロセスからのページフォールトは、ディスク上のそれらのページを見つけることができます。

古いバイナリを実行しているプロセスの/proc/${pid}/exeシンボリックリンク(または同等のlsof出力)を見ると、この効果を確認できます。/app/EXE (deleted)は、名前はもう存在しないが、inodeはまだ存在していることを示します。

あなたはまた、(それが開いているiノードを持つ唯一の方法だと仮定。)の出力を確認したバイナリが使用するディスク領域が唯一のプロセスダイの後にリリースされることがわかりますdf前に、プロセスを強制終了した後、あなたはそれがサイズによってドロップ表示されますあなたはもう存在しないと思った古いバイナリの。

ところで、これはバイナリだけでなく、開いているファイルでも同様です。プロセスでファイルを開いてファイルを削除すると、そのプロセスがファイルを閉じる(または停止する)まで、ファイルはディスクに保持されます。同様に、ハードリンクがディスク内のiノードを指す数のカウンターを保持する方法と同様に、 (Linuxカーネル内の)ファイルシステムドライバーは、メモリ内のそのiノードへの参照の数のカウンターを保持し、実行中のシステムからのすべての参照もリリースされた後にのみディスクからiノードをリリースします。

質問1:ファイルのすべてのページをvmtouchのようなものでロックすると、シナリオが変わります

この質問は、ページをロックしないとセグメンテーション違反が発生するという誤った仮定2に基づいています。しません。

質問2:/ apps / EXEがリモートNFS上にある場合、違いはありますか?(私は仮定しない)

です意味それがないほとんどの時間を同じように動作してすることではなく、いくつかの「落とし穴」はNFSです。

NFSでまだ開いているファイルを削除すると、その成果物が表示される場合があります(そのディレクトリに隠しファイルとして表示されます)。

また、NFSエクスポートにデバイス番号を割り当てる方法があり、NFSサーバーの再起動時にデバイス番号が「シャッフル」されないようにします。

しかし、主な考え方は同じです。NFSクライアントドライバーは引き続きiノードを使用し、iノードがまだ参照されている間は(サーバー上で)ファイルを保持しようとします。


1
oldnameファイルの参照カウントがゼロになるまでrename(2)はブロックしますか?
グレッグレベンタール

2
いいえ、rename(2)はブロックしません。古いiノードは、潜在的に非常に長い間保持されます。
フィルブランデン

1
実行中のファイルに書き込めない理由に対する@mosvyの回答を参照してください(ETXTBSYを取得します)。リンク解除と新規作成には、名前変更と同じ効果があります。新しいiノードになります。(ファイル名が存在しない瞬間がないため、名前の変更の方が優れています。新しいiノードを指すように名前を置き換えるアトミック操作です。)
filbranden

4
@GreggLeventhal:「一時ファイルを使用していることを確認するために、私が使用している連続リリースプロセスについてどのような仮定をしていますか?」– Unixが存在する限り、それがそれを行う唯一の正気な方法であり、現在もそうであるため。renameので、「その後、一時ファイルを作成し、(私たちがいないクロスファイルシステムやデバイスの境界を行うと仮定した場合)アトミックであることが保証される唯一のファイルとファイルシステムの操作はかなりあるrename」されたファイルを更新するための標準的なパターン。たとえば、Unixのすべてのテキストエディタが使用するものでもあります。
ヨルグWミットタグ

1
@ grahamj42:renamePOSIXの一部です。確かに、ISO C(現在のドラフトのセクション7.21.4.2)への参照によって含まれていますが、そこにあります。
ヨルグWミットタグ

6

前提条件2:ファイルのすべてのページがメモリにマップされていない場合、ファイルのページを置き換えるページフォールトが発生するまで問題はなく、おそらくセグメンテーション違反が発生すると思いますか?

いいえ、カーネルは、現在実行されているファイル内の置換内容を書き込むために開かないため、それは起こりません。このようなアクションはETXTBSY[1]で失敗します:

cp /bin/sleep sleep; ./sleep 3600 & echo none > ./sleep
[9] 5332
bash: ./sleep: Text file busy

dpkgなどがバイナリを更新するとき、それは上書きされませんが、 rename(2)、ディレクトリエントリをまったく別のファイルにポイントするだけをし、古いファイルへのマッピングまたは開いているハンドルを持つプロセスは問題なくそれを使用し続けます。

[1]このような保護は、「テキスト」(ライブコード/実行可能ファイル):共有ライブラリ、Javaクラスなどと見なされる他のファイルにも拡張されません。別のプロセスでマッピングされている間、このようなAファイルを変更することになる、それがクラッシュします。Linuxでは、動的リンカーは忠実にMAP_DENYWRITEフラグをmmap(2)に渡しますが、間違いを犯しません-まったく効果がありません。


1
dpkgシナリオでは、/ apps / EXEのdentryが新しいバイナリのiノードを参照するように、どの時点で名前変更が完了しますか?古いものへの参照がなくなったら?それはどのように機能しますか?
グレッグレベンタール

2
rename(2)アトミックです; 完了するとすぐに、dirエントリは新しいファイルを参照します。その時点でまだ古いファイルを使用していたプロセスは、既存のマッピング、またはそれに対するオープンハンドル(孤立したデントリを参照する可能性があり、経由以外ではアクセスできなくなる/proc/PID/fd)を介してのみアクセスできます。
モスビー

1
あなたのETTXBSYの言及がこのすべての質問に答えるこのutcc.utoronto.ca/~cks/space/blog/unix/WhyTextFileBusyErrorに私を導いたので、私はあなたの答えが一番好きです。
グレッグレベンタール

4

filbrandenの答えは、継続的なリリースプロセスがを介してファイルの適切なアトミック置換を行うことを前提としていrenameます そうではないが、ファイルをインプレースで変更する場合、状況は異なります。しかし、あなたのメンタルモデルはまだ間違っています。

ページキャッシュは正規バージョンであるためディスク上で物事が変更され、ページキャッシュと矛盾する可能性はありません。あり、変更されたものである。ファイルへの書き込みは、ページキャッシュを介して行われます。既に存在する場合は、既存のページが変更されます。まだ存在しない場合、部分的なページを変更しようとすると、ページ全体がキャッシュされ、その後、既にキャッシュされているかのように変更されます。ページ全体にまたがる書き込みは、ページを読み込む読み取りステップを最適化することができます(そしてほぼ確実に)。 。

(*)私は少し嘘をついた。NFSおよび他のリモートファイルシステムの場合、複数存在する可能性があり、通常(使用するマウントオプションとサーバー側オプションに応じて)、書き込みのアトミック性と順序付けのセマンティクスを正しく実装しません。だからこそ、私たちの多くはそれらを根本的に壊れていると考え、使用と同時に書き込みが発生するような状況では使用を拒否します。

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.