Linuxのmount(2)
マニュアルページで次の抜粋を見つけました。
次のパターンで既存のファイルを置き換えると、破損した多くのアプリケーションはfsync()を使用しません。
fd = open("foo.new")/write(fd,...)/close(fd)/ rename("foo.new", "foo")
またはもっと悪い
fd = open("foo", O_TRUNC)/write(fd,...)/close(fd).
auto_da_allocが有効になっている場合、ext4はrenameによる交換と切り捨てによる交換モードを検出し、名前変更()操作の後にデフォルトのdata = orderedモードで次のログコミットに遅延割り当てブロックを強制的に割り当てます。新しいファイルがディスクに強制的に保存されます。これはext3とほぼ同じレベルの保証を提供し、遅延割り当てられたブロックがディスクに強制的に書き込まれる前にシステムがクラッシュしたときに発生する可能性がある「長さのない」問題を防ぎます。
このコードはどのような意味で「壊れていますか?」コードが違法であるか、非標準規格(POSIXなど)と言っていますか?
fsync()
システムがクラッシュするとどうなるか心配している人にとっては、これは良い考えかもしれません。しかし、システムがクラッシュしていないと仮定すると、両方のバージョンのサンプルコード(なし)がfsync()
正しい動作をしますか?
答え1
rename
期待は原子的です。完全に完了するか、まったく完了しません。 Bの代わりにAの名前を変更した場合は、AとBの両方がそのままになるか(まったく発生しない)、Aの内容をBの名前の下に入れる必要があります(完全に完了)。
これは、システムがクラッシュしない限り、呼び出しなどに関係なくfsync
発生します。
ただし、システムがクラッシュした場合は、名前変更自体がディスクに到達して完了したことがわかります。名前を覚えてください! =ファイル。ファイル/インデックスノードは複数の名前を持つことができます。名前を変更すると、デフォルトのファイル/データではなく名前が変更されます。
したがって、プログラムがAを書き、Bを置き換えるように名前を変更し、電源が切れる状態になる可能性があります。その結果、ファイルシステムは、Aの実際のデータの代わりにディスクに名前変更を記録します。いいえ。fsync
したがって、長さ0のBまたは0で埋められたBになります。
アプリケーションがファイルを上書きするのではなく、一時ファイルに書き込んで名前を変更する理由は次のとおりです。〜したい衝突安全。重要な文書の半分だけが作成された一時コピーを変更されていない良好なコピーの横に置いても、ユーザーはあまり気分が悪くなります。しかし、良いコピーを残さないと、ユーザーは満足できません。
答え2
コードは正当ですが、「素朴」です。問題は、衝突が発生した場合に正確にどうなるかです。
カタログが更新されるまで新しいデータにスペースが割り当てられないため、データが失われる危険性があります。
良いアプリケーションは呼び出して、fflush()
データfsync()
がディスクにフラッシュされていることを確認します。これらのauto_da_alloc
ルーチンは、カーネル内で経験的にこれを実行しようとします。
https://bugzilla.kernel.org/show_bug.cgi?id=103111#c10いくつかの「問題」が説明されている。
答え3
完全に正当であればうまくいくでしょうが、あなたが望むようにはなりません。
2番目は明らかです。新しいものを保存する前にオリジナルを破壊します。
最初はあまり明確ではありません。システムが失敗した場合(停電など)、何もせず(起動しない)、2つのファイルがあるようです。古いファイルと新しいファイル、成功ファイルがあります。しかし、その言葉通りにしなければそうではありませんfsync
。
彼らはあなたの注意を引くために「破損した」という言葉を使います。ユーザーがデータを失うために壊れた。今日ではないかもしれません。たぶん明日ではないかもしれませんが、すぐに、そして一生の間。
これを断続的なエラーと呼びます。症状が現れるまでに何年も続く可能性があるエラーです。
ユーザーのデータの整合性に興味がない場合は、最初の例を実行するのはなぜですか?