GNU/Linux >> Linux の 問題 >  >> Linux

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

<ブロック引用>

その後、継続的なリリースにより、/apps/EXE が新しい実行可能ファイルに置き換えられます。

これが重要な部分です。

新しいファイルをリリースする方法は、新しいファイルを作成することです (例:/apps/EXE.tmp.20190907080000 )、コンテンツの書き込み、権限と所有権の設定、そして最後に rename(2) 最終的な名前 /apps/EXE に変更します 、古いファイルを置き換えます。

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

古いファイルには独自の inode 番号があり、実際には まだ使用されています ファイル名がそれを指していなくても (または、その inode を指しているファイル名がもうありません)。

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

<ブロック引用>

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

正解です。

<ブロック引用>

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

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

/proc/${pid}/exe を見ると、この影響を確認できます。 symlink (または同等の lsof /app/EXE (deleted) と表示される、古いバイナリを実行しているプロセスの出力)。 名前はもうありませんが、inode はまだ残っていることを示します。

また、バイナリによって使用されるディスク領域は、プロセスが終了した後にのみ解放されることもわかります (その inode が開いている唯一のプロセスであると仮定します)。 df の出力を確認してください。 プロセスを強制終了する前と後に、もう存在しないと思っていた古いバイナリのサイズが小さくなっているのがわかります。

ところで、これはバイナリだけでなく、開いているファイルにも当てはまります。プロセスでファイルを開いてファイルを削除すると、そのプロセスがファイルを閉じる (または終了する) まで、ファイルはディスク上に保持されます。ファイルシステム ドライバー (Linux カーネル内) は、その inode への参照が メモリ内 にいくつ存在するかのカウンターを保持します。 、実行中のシステムからのすべての参照も解放された後にのみ、ディスクから i ノードを解放します。

<ブロック引用>

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

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

<ブロック引用>

質問 2 :/apps/EXE がリモート NFS にある場合、違いはありますか? (そうではないと思います)

意味 ほとんどの場合は同じように動作しますが、NFS にはいくつかの「落とし穴」があります。

NFS でまだ開いているファイルを削除することによるアーティファクトが表示されることがあります (そのディレクトリに隠しファイルとして表示されます)。

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

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


<ブロック引用>

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

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

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

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

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

$ cc -xc - <<<'void lib(){}' -shared -o lib.so
$ cc -Wl,-rpath=. lib.so -include unistd.h -xc - <<<'
   extern void lib();
   int main(){ truncate("lib.so", 0); lib(); }
'
./a.out
Bus error

連続リリース プロセスが rename を介してファイルの適切な原子置換を行うと仮定すると、filbranden の答えは正しいです。 .そうではなく、ファイルをその場で変更する場合は、状況が異なります。しかし、あなたのメンタル モデルはまだ間違っています。

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

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


Linux
  1. セマフォをゼロにデクリメントしたプロセスがクラッシュした場合、セマフォを回復するにはどうすればよいですか?

  2. 指定したファイルが移動または削除された場合、Linux で開いているファイル ハンドルはどうなりますか

  3. ls -l /proc/[PID]/fd の出力の anon_inode は何ですか?

  1. Linuxのiノード番号とは何ですか?

  2. 別のファイルにない1つのファイルの行を取得するためのツール?

  3. システムコールに費やされた時間を表示するときに strace が使用する時間単位は何ですか?

  1. 親プロセスが終了したときの新しい親プロセス?

  2. コマンドCat/proc / cpuinfoを実行するとどうなりますか?

  3. シェルでファイルを実行するとどうなりますか?