質問

質問

XUnixでファイルを安全かつ原子的に作成する一般的な方法は次のとおりです。

  1. 新しいファイルの内容を一時ファイルに書き込みますY
  2. rename(2) Y到着X

この2つの段階で、私たちはX「内部」の変更だけを行うようです。

競合状態や予期しないデータ損失(損傷しているが不完全または破損している)から保護XしますY

Xこの場合の欠点は、参照されたinodeを所定の位置に書き込むのではなく、参照を新しいinode番号にrename(2)することです。X

Xファイル内のリンク数が1より大きい場合(明示的なハードリンク)、これ以上以前と同じinodeを参照しなくなり、ハードリンクが失われます。

これらの欠点を取り除くための確実な方法は、ファイルを適切な場所に書き込むことです。ただし、これはアトミックではなく失敗する可能性があり、データの損失などが発生する可能性があります。

rename(2)これをアトミックに実行しますが、ハードリンクを維持する方法はありますか?

一時ファイルのinode番号をY同じに変更してX名前Xを付けますか? Inode レベル「名前の変更」。

Xこれは、で参照されるinodeの新しい内容を効果的に作成しますYが、ハードリンクプロパティを削除せずに古い名前を保持します。

仮想のinode「名前の変更」が原子性であれば、これが原子性であり、データの損失/競合を防ぐと思います。

答え1

質問

(ほとんど)完全なシステムコールのリストがあります。ここ

「このinodeの内容を交換してください」という呼び出しがないことがわかります。このコンテンツを変更することは、常に次のことを意味します。

  1. 開くファイル記述子を取得するファイルです。
  2. 任意に選択できる 探す希望の書き込みオフセットで
  3. 書くファイルとして。
  4. 任意に選択できる カット新しいデータが小さい場合は古いデータです。

ステップ4は事前に完了できます。次のショートカットもあります。書く、ステップ#2と#3を組み合わせて指定されたオフセットに直接書き込むか、または緩い執筆

別の方法はメモリマップしかし、書き込まれた各バイトが基本ファイルに独立して転送される可能性があるため、状況はさらに悪化します(概念的には、各書き込みが1バイトの呼び出しであるかのようにwrite)。

→要点は、あなたが持つことができる最良のシナリオはまだ2つの操作、つまり1writeと1であるということですtruncate

どの順序で実行しても、他のプロセスが中間ファイルを台無しにして最終的にファイルが破損する危険性があります。

解決策

一般的なソリューション

あなたが指摘したように、これは標準的な方法があなたが唯一の作者であることを知っている新しいファイルを作成することですO_TMPFILElinkat)古い名前を新しいファイルに自動的にリダイレクトします。

2つの異なるオプションがありますが、どちらもある点で失敗します。

強制ロック

特別なフラグの組み合わせを設定して、他のプロセスへのファイルアクセスを拒否します。仕事のための道具のように聞こえますか?しかし:

  • ファイルシステムレベルで有効にする必要があります(インストール時にフラグです)。
  • 警告する:Linuxの強制ロックの実装は信頼できません。

    Linux 4.5以降、強制ロックが選択機能になりました。これはこの機能を完全に削除するための最初のステップです。

Unixは常にロックの使用を避けたので、これは論理的です。エラーが発生しやすく、すべての極端なケースをカバーし、デッドロックがないことを保証することは不可能です。

推奨ロック

使用していますポカントルシステムコール。ただし、これは推奨事項にすぎず、ほとんどのプログラムはこれを無視します。

実際には、複数の連携プロセス間の共有ファイルのロックを管理する場合にのみ適しています。

結論として

rename(2)のようにこれをアトミックに実行しますが、ハードリンクを維持する方法はありますか?

いいえ。

Inodeは低レベルで、ほぼ実装の詳細です。自分の存在を認めるAPIはほとんどありません(statコールファミリが唯一のAPIだと思います)。

何を試しても、おそらくUnixファイルシステムの設計を乱用するか、単にあまりにも多くを要求しているでしょう。

これは次のようになります。XYの問題

関連情報