1.a) open and read file ~/.kde/foo/bar/baz 1.b) fd = open("~/.kde/foo/bar/baz", O_WRONLY|O_TRUNC|O_CREAT) --- this truncates the file 1.c) write(fd, buf-of-new-contents-of-file, size-of-new-contents-of-file) 1.d) close(fd)
Slightly more sophisticated application writers will do this:
2.a) open and read file ~/.kde/foo/bar/baz 2.b) fd = open("~/.kde/foo/bar/baz.new", O_WRONLY|O_TRUNC|O_CREAT) 2.c) write(fd, buf-of-new-contents-of-file, size-of-new-contents-of-file) 2.d) close(fd) 2.e) rename("~/.kde/foo/bar/baz.new", "~/.kde/foo/bar/baz")
What emacs (and very sophisticated, careful application writers) will do is this:
3.a) open and read file ~/.kde/foo/bar/baz 3.b) fd = open("~/.kde/foo/bar/baz.new", O_WRONLY|O_TRUNC|O_CREAT) 3.c) write(fd, buf-of-new-contents-of-file, size-of-new-contents-of-file) 3.d) fsync(fd) --- and check the error return from the fsync 3.e) close(fd) 3.f) rename("~/.kde/foo/bar/baz", "~/.kde/foo/bar/baz~") --- this is optional 3.g) rename("~/.kde/foo/bar/baz.new", "~/.kde/foo/bar/baz")
3.a) open and read file ~/.kde/foo/bar/baz 3.b) fd = open("~/.kde/foo/bar/baz.new", O_WRONLY|O_TRUNC|O_CREAT) 3.c) write(fd, buf-of-new-contents-of-file, size-of-new-contents-of-file) 3.d) fsync(fd) --- and check the error return from the fsync 3.e) close(fd) 3.f) rename("~/.kde/foo/bar/baz", "~/.kde/foo/bar/baz~") --- this is optional 3.g) rename("~/.kde/foo/bar/baz.new", "~/.kde/foo/bar/baz")
a hack which force blocks that had been delay allocated to be allocated when either (a) the file in which was being written had previously been truncated using ftruncate or opened using O_TRUNC, at which point the blocks will be allocated when the file is closed, or (b) if a file containing blocks not yet allocated is renamed using the rename(3) system call causing a previously existing file to be unlinked (i.e., the application has written the file "foo.new" and is now calling rename("foo.new", "foo"), causing the file "foo" to be unlinked), then the file's blocks will also be forcibly allocated.
Note that fclose() only flushes the user space buffers provided by the
C library. To ensure that the data is physically stored on disk the
kernel buffers must be flushed too, for example, with sync(2) or
fsync(2).
Ubuntu関係なくね? (スコア:2, 参考になる)
Ubuntuのext4でのみ問題が起こるようにも読める文章ですが、
カーネルの問題であって基本的にディストリビューションは関係ないですよね?
(もちろん独自にパッチをバックポート、とかはあるでしょうが)
本家記事は元のバグレポートがUbuntuに対してなされてるのがわかるので意味が通るんですが
こっちでは何が何やら、ミスリードチックです。
Re: (スコア:0)
Ext4の問題でも、Ext3のコミット間隔を当てにしたアプリケーションの問題でもなく、Linuxカーネルの問題……ってことですよね?
何のことなのか訳分からなくてLinux環境ではファイルシステムを意識してソフト開発しないといけないのかなんて思ってました。
Re: Ubuntu関係なくね? (スコア:3, 参考になる)
まとめてみた。
直感:
<落ちたらファイル壊れる部分ここから>
ファイル開く
書き込み
ファイル閉じる
<落ちたらファイル壊れる部分ここまで>
実際:
<落ちたらファイル壊れる部分ここから>
ファイル開く
書き込み
ファイル閉じる
(システムによって実際にファイルが書き込まれる)
<落ちたらファイル壊れる部分ここまで>
そして、ファイル閉じてから実際にファイルが書き込まれるまでの時間が今までは5秒と短かったため、直感に近い状態であった。
ところがext4などの遅延書き込みを採用しているFSでは、書き込まれるまでの時間が長いため、直感とは違う状況になってしまった。
そこで、思う。これはアプリケーションのバグではない。実際にいつファイルを書き込むかを考えるのは、一般にはアプリケーションプログラマの仕事ではない。
それに、そもそもここ [srad.jp]で例示されているプログラムは、Ext3のコミット間隔を当てにしているのではなく、システムがちゃんと落ちずにファイルを書き込んでくれることを当てにしている。
実際に本当に落ちないかは別として、相当な慎重性を要求されるプログラムを除いて、大抵のプログラムはOSが落ちないで働いてくれることを前提としているし、それは別におかしなことではない。
一方、FSはOSに非常に近い部分であり、慎重性も要求される。実際、Linuxでは(FUSEとかめんどいので考えないことにすると)FSはOSに組み込まれている。
なので、今回の問題は、落ちるOSが悪い。が、落ちないOSなんて不可能なので、落ちたときのリスクを考えていないFSが悪い。
ただし、慎重さが要求されており「書き込み前にOSが落ちちゃいました。けど俺が悪いんじゃないよ。テヘッ」が通用しないようなアプリケーションにおいては、その対策をアプリケーション側でも施さないといけない。先ほどの例 [srad.jp]での3をきっちりとする必要があり、1とか2とかやってるんだったら、それはアプリケーションのバグ。
1を聞いて0を知れ!
Re: (スコア:0)
Ext3のコミット間隔を当てにしたアプリケーションの問題ですよ。
Re: (スコア:0)
突然のシステムダウンから復帰したときに、色んなファイルがゼロバイトになる現象のようなんですど、複数のファイルがごっそりゼロバイトになることに未対応であるアプリがあるってだけなんじゃないかと。
Re: Ubuntu関係なくね? (スコア:5, 参考になる)
要はPOSIXで制定されている以上の事を求めるプログラマ多すぎ、というのが結論。
Ext3の挙動が標準であると思い込んでアプリケーション書いていたら、その挙動はExt3固有で POSIXにはそんなこと書いてなかった。
それで、Ext4じゃその挙動が変わっちゃったという話みたい。
Ted Tsoがバグレポートの中 [launchpad.net]で書いていることを引用すると、
データが実際にHDD/SSD等に書き込まれたことを保証するには、1)は論外、2)でも不十分、3)までやらないと駄目だと。
1)の場合は、ファイルを"O_TRUNC"で開いた時点でもとの内容は全て消えちゃってる。 だから、1.b)以降データが実際に 書き込まれるまでクラッシュが発生したら、リブート後そのファイルは空ですよと。
2)の場合は、新しいファイルを開くだけまし。 だけど、2.e)以降データ書き込み以前にクラッシュが発生しちゃうと、 やっぱりリブート後には元のファイルは空になっちゃう。 なぜなら、2.e)で、新しいファイルが元のファイルに上書きされちゃうけど、 この時点で、新しいファイルがディスク に書き込まれている保証はないから。
3)の場合は、3.d)で、データがディスク上に保存されている(もしくは、保存に失敗した)ことが、 fsync()が帰ってきた 時点で保証されると。
バグ報告や本家を読んでもイマイチ分からないのですが、逆にコミット間隔を当てにするにはどういったコードを書けば良いのでしょうね。
5秒間隔のコミットに依存したプログラムというのは上記の1)と2)。
Ext3においては、コミット間隔が短かったのでクラッシュした際のデータロスとかが比較的少かった。
だけど、Ext4では、そのコミット間隔の長さに由来して、今迄存在したけど顕在化しなかったこの問題が 浮上したと。
今回、KDEとGNOMEのドットファイル等でこの問題が発覚した理由は、 アプリケーションがこれらのファイルを 比較的高頻度で1)や2)の手法を使って書き変えているから。
んで、ディスクへの書き込みを保証しなくてはいけないデータにはfsync()か fdatasync()を 使えとのこと。
大量のfsync()に伴うパフォーマンスの減退がいやならば、sqliteとか使って纏めて 書き込めよっていうのがTed Tsoのお勧め。
複数のファイルがごっそりゼロバイトになることに未対応であるアプリがあるってだけなんじゃないかと。
これはまとはずれだと思う。
Re: Ubuntu関係なくね? (スコア:4, 参考になる)
たとえ、ファイル書き込みが完全に同期していたとしても、
この方法だと、write中にクラッシュすればファイルが失われますし、
OSがクラッシュしなくても、該当アプリだけが死んだ場合でもアウト。
でも、世の中には、これを採用しているアプリが結構多いような気がします。最低限でも、
ぐらいはしなきゃダメじゃないかな。3.fは必須。fsync無しなら高レベルI/Oでも可能な範囲だし、アプリそのものの死亡に対してはほぼ安全です。
fとgの間で死んだら困りものですから、読み込み時に「バックアップファイルしか無い時は、バックアップファイルから読み込む」ぐらいのことはした方がいいと思いますが…
私がこの問題にぶち当たったのは mrtg 。
元のログファイルは*.oldという名前で残っているのですが、
先にリネームしてから、新しいログファイルを書き出しているっぽく、
そこで落ちたら0バイトのログファイルが出来ます。
次回実行までにログが消えたのに気がつかなかったら、次の書き出しで、空のログファイルから読み込んで処理が行われて、バックアップファイルも空になってしまいます。
そのせいで何年かため込んだログがばっさり消えてしまいました。
Re: Ubuntu関係なくね? (スコア:1)
ぐらいはしなきゃダメじゃないかな。3.fは必須。fsync無しなら高レベルI/Oでも可能な範囲だし、アプリそのものの死亡に対してはほぼ安全です。 fとgの間で死んだら困りものですから、読み込み時に「バックアップファイルしか無い時は、バックアップファイルから読み込む」ぐらいのことはした方がいいと思いますが…
とかすればokかな。linkできないときは自前でコピー。
yoshfuji
Re: Ubuntu関係なくね? (スコア:2, 参考になる)
3.f) link("~/.kde/foo/bar/baz", "~/.kde/foo/bar/baz~") --- this is optional
とするのが常識じゃないかな? 3.f) と 3.g) の間に割込まれる可能性も考慮しないと!
どこか別の場所で事前にロックとって排他しているのでない場合には、3.b) の
O_TRUNC とかも論外な気がする。NFS まで考えると気休めけど O_EXCL くらいは
つけときたい所。
Re: (スコア:0)
これは何のパッチなのでしょうか?
自分でバグレポートを読め?ごもっとも。
Re: Ubuntu関係なくね? (スコア:4, 参考になる)
これは何のパッチなのでしょうか?
再び、Ted Ts'o曰く, [launchpad.net]
意訳:(a) ftruncate()されたか"O_TRUNC"で開かれたファイルにwriteし、そのファイルをクローズする際か、(b)まだ、ディスクに書き込まれていないデータを含むファイルを、既に存在するファイルに上書き(rename("foo.new", "foo");上の2.eのケース)する際に、強制的にディスクに書き込むようにする。
基本的には、問題になっているケースに限ってExt3と同様な挙動をするようにする為のパッチとのこと。
なお、大きいファイルやデータベースのファイル等は上記パターンに合致しないのが殆どなので、大体においてExt4のパフォーマンスはそれほど落ちないとか。
安定したシステムにおいて、以上の挙動を無効化する為のマウントオプションも2.6.30向けに準備しているとも。
ちなみに、Ubuntuのカーネルメンテナンスチームメンバらしき人がこのパッチをUbuntu 9.04向けに取り込む予定はない [launchpad.net]と述べている。
Re: (スコア:0)
> 5秒間隔のコミットに依存したプログラムというのは上記の1)と2)。
5秒と60秒では、単にリスクの大小の程度問題であって、5秒だとOKだけど60秒だとNGってのは言い過ぎではないかと。
それに、これはファイルシステム側の問題であって、アプリ側の問題ではないと思う。
ext4は、そういうリスクを承知の上で60秒という設定をしているはず。そのリスクを受け入れるかどうかは
ユーザーが決めればいいこと。もちろんユーザーはそういうリスクを知らされている必要があるけど、
そのうえで受け入れられなければ別のファイルシステムを使えばいいし、受け入れる人がいなくなれば、
ext4は淘汰されてしまうことでしょう。
それに、遅延書き込みへの防衛としてアプリ側でsyncを頻発したら、遅延書き込みのメリットがなくなって
しまいますよね。それは、リスクを承知でext4を選択したユーザーにとっても不利益のはず。
Re: Ubuntu関係なくね? (スコア:4, 参考になる)
>> 5秒間隔のコミットに依存したプログラムというのは上記の1)と2)。
>5秒と60秒では、単にリスクの大小の程度問題であって、5秒だとOKだけど60秒だとNGってのは言い過ぎではないかと。
一応、直後に書いたたように、
>> Ext3においては、コミット間隔が短かったのでクラッシュした際のデータロスとかが比較的少かった。
>> だけど、Ext4では、そのコミット間隔の長さに由来して、今迄存在したけど顕在化しなかったこの問題が浮上したと。
なので、この問題自体は重要視されていなかっただけでずっと存在していたんでしょう。
> それに、これはファイルシステム側の問題であって、アプリ側の問題ではないと思う。
この点については、"Not a bug" [slashdot.org]に始まる本家のスレッドで大フレームウォーがあった模様。
一方はPOSIXを盾にこれはアプリケーションのバグと主張し、他方は複雑なファイルシステムのメカニズムをアプリケーションプログラマが知っていることを前提とするのは間違っていると主張。
また、高級言語では、fsync()相当のものがないのもあるよーとも。
Linuxデスクトップユーザの私は、Ext3で現在満足しているので、今回の騒動に関しては人柱乙(だって、Ubuntu 9.04 alphaだし)というのが正直な感想。
Ext4はミッションクリティカルなサーバ等を指向しているのかなあとも思った。
また、btrfs, ZFS, tux3, reiser4等も同様で、今回みたいなことがこれらでもおこらないとの保証はないとのこと。
> それに、遅延書き込みへの防衛としてアプリ側でsyncを頻発したら、遅延書き込みのメリットがなくなって
> しまいますよね。それは、リスクを承知でext4を選択したユーザーにとっても不利益のはず。
これに関しては、再びTed Ts'o [launchpad.net]からですが、
Ext3 data=ordered モードでfsyncが遅かったのは、Ext3特有の問題(全てのデータを一気に書き込む)、Ext4においてはもっとスマートだとのこと
(fsyncされたファイルのみを一気に書き込み、その他のファイルは徐々に書き込む)。よって、Ext4のfsyncはExt3のそれよりも性能がいいとか。
ここら辺のことに関して、私は全然知識がないので有識者の意見が待たれるところ。
Re: (スコア:0)
FS側は仕様どおりだからアプリ側で対処すること。
どの処理で遅延が問題になるかはアプリの開発者にしか分からない。
遅延処理はハイリスク・ハイリターン (スコア:0)
>遅延書き込みのメリットがなくなってしまいますよね。それは、
>リスクを承知でext4を選択したユーザーにとっても不利益のはず。
でも、遅延処理は一般的にハイリスク・ハイリターンなんだよね。
まともに動いている時はいいんだけど、トラブルを考えると結構ハイリスクを伴う処理。
ファイルシステムに限らず、ネットワークの接続の保持などでもその手の処理を
入れてるものがあるけど、使い終わったにも関わらずファイルが開きっぱなしに見える
みたいなトラブルも起きるので、それの回避をする為にその機能を使わないという
選択肢が取れる様にOS側でしていたりする。
ところで今回のext4で、その秒数の調整って簡単に可能なんかね?
それができれば別に問題も少ないと思うのだが、ユーザ調整がコンパイルしないと
無理というなら「何を考えている?」と仕様変更した人間が責められても仕方ないでしょう。
リスクを甘くみすぎているという意味で。
Re: (スコア:0)
ファイルシステムのメカニズムを知っている人に修正を加えてもらえばいいのに・・・
何のためのオープンソースだか訳分からん。
他所から見ると単に自分の知らない事を指摘されて逆ギレしてるようにしか見えない。
Re: (スコア:0)
Re: Ubuntu関係なくね? (スコア:3, 参考になる)
抜粋解説ありがとうございます、参考になりました。
> 一応、直後に書いたたように、
> >> Ext3においては、コミット間隔が短かったのでクラッシュした際のデータロスとかが比較的少かった。
> >> だけど、Ext4では、そのコミット間隔の長さに由来して、今迄存在したけど顕在化しなかったこの問題が浮上したと。
>
> なので、この問題自体は重要視されていなかっただけでずっと存在していたんでしょう。
おっしゃるとおりですね。
# これを「問題」ととらえるかどうかは、その人の立場/見方によりかわると思いますが、笑。
ここで話題になっている ext3やext4の「コミット間隔」は、ファイルシステム内でデータをバッファから書き出す定期実行間隔のことなので、仮にext4の60秒が5秒になっても、最後のコミットから事故までの間で2次記憶にはデステージされていないデータがある(かもしれない)ことにはかわらないです。
本質的に、ユーザが意図するようにバッファから書き出してもうらうには、a)ユーザが書き出しを指示するか(=fsync/syncなどを発行するか)、a)ユーザがバッファードライトの禁止を指示するか、しかありません。
アプリケーション側でデータ破壊の問題を何も考えず安直にやりたいのであれば、ライトスルーで書く(前述bの方法)のでしょうが、
でもそんなことをしていたら、IO性能は出ないので、「データの意味・整合性を知っている(自ら作り出している)」アプリケーション側で、意識的に整合性のポイントをつくって、使い分ける必要があります(前述aの方法)。
DBなど、性能と信頼性を要求するものは、こういうところまできちんと考えて設計しています(が、現実には、怪しいモノもありますが)。
なお、ext4でコミット間隔を長くした理由には、ext4がエクステント方式を採用していることも関係しています。
ext3などはブロック方式ですが、特に(DBなどの)巨大なファイルを作ったときなどはそのファイルを構成するブロックの間接参照が深くなりIO性能が低下する傾向にあります。
そこでext4はエクステント方式(連続するブロックを開始オフセット/長さで表現するデータ構造)としたことで、これを解決することを目指しています。
(エクステント方式はext4が初めてではありません)。
エクステント方式で性能を出すためには、できるだけ連続したブロックを割り当てることが大切ですが(フラグメンテーションの回避が課題になりますが)、そのためには、できるだけライトデータをバッファして、連続して一気に書き込むことが重要になり(これだけではないですが)、そのため、「意図的に」コミット間隔を長くとっています。
言い換えれば、コミットを(FS内で)乱発するのは、そもそもの設計の狙いに反しているので、そのあたりは慎重に考える必要があるでしょうね。
(ここの設計者の見極めが、今回のTruncate指定でのコミットのパッチにうまく現れていると考えます)
ちなみに、
ファイルを更新中にプロセス終了や電源断でデータ破壊というのは、(バッファが全く関係ないわけではないですが)本質的には別の話ですね。
これはバッファードライトでなくても起きうる話で。
(データの整合性がとれるポイントまでは)データを上書きしないように気をつけよう(CopyOnWriteしよう)、と。
Re: (スコア:0)
それはそれでどうなのよ、と思うのですが。
Re: Ubuntu関係なくね? (スコア:2, すばらしい洞察)
ちゃう. データベースやトランザクションモニタを使えってことです.
U*IXシステムの基本的な思想は何においてもベストエフォートなので, 単にシステムコールを呼んだくらいでは業務レベルでの保障は得られず, かなりトリッキーな操作が必要になります. Linuxだとディスクドライバだかブロックデバイス制御だかのレベルで書き込み完了を見ていなくて, ファイルシステム以上では本当にsyncしているかどうか判らないなんて話もありましたし(過去形でいいのかな?). いずれにせよ多くのプログラマにとっては手にあまるレベルなので, 少々大げさに見えても確実さを望むならばデータベースみたいなインフラの上でシステムを構築しないといけなくなります. これは昔の汎用機なんかと同じ考え方ですね.
つまりプログラマおよび使用者にとって取りうる対策は3つで
のいずれかになります. 実際には綺麗に分かれるわけではなくて, それぞれの要求によって落としどころをさぐることになりますけど.
まあ従来の「軽い・速いは正義」という単一的な価値観じゃあ済まなくなって, 「プログラミングが簡易」とか「システムの堅牢性」とかが求められていることが表面化したってのが今回の騒動だと思います.
Re: Ubuntu関係なくね? (スコア:1)
Note that fclose() only flushes the user space buffers provided by the
C library. To ensure that the data is physically stored on disk the
kernel buffers must be flushed too, for example, with sync(2) or
fsync(2).
Re: (スコア:0)
その通りと云うか、(Cライブラリの高水準入出力関数では)痒い処に手が届ききれてないと云う事ですね。
vipw(8)の実装でも、そんな感じだった(fsync()を呼んでる)筈だし。
Re: (スコア:0)
そこで「仕様だ。ファイルシステムは悪くない。プログラマが馬鹿なだけ」と言っている限り、LinuxがWindowsに [nikkeibp.co.jp]勝つことはあり得ませんけどね。
まあ場当たり的な修正パッチが導入される予定ということは、Linuxの開発者もさすがにそのへんは理解しているようで何よりです。
Re: (スコア:0)
Re: Ubuntu関係なくね? (スコア:2, 参考になる)
このDISKというのが、どのレベルのモノをさして言っているか/どの切り口から見ているのかにもよりますよね。:D
fsync()はOS内のライトバッファからOS外のデバイスに対する書き出し指示をおこなうものであって、デバイスへ書き込む(書き込み指示を出して完了応答を待ち合わせること)は保証されています。
(これがきちんとできていないのであれば、それは問題です)
ただし、デバイス内でのバッファードライトまで直接禁止するものではないので、仮にデバイス(たとえばHDD)内で揮発性のライトバックキャッシュが構成されていれば、突然の電源断でどうなるかはユーザにはわかりません。
(ドライバレベルでは、これをきちんと指示する仕組みはあります)
なので、エンタプライズ系のシステムでは、HDDのライトバックキャッシュ(WBC)をOFFにして使ったり、UPSをつけてWBC-ONでつかったり、ディスクアレイ装置側にNVRAMを搭載したりして、OS側に「書き込み完了」を返したときには、Stableであることを保証するようにしています。
元のACさんのコメントは、後者(デバイス内でStableなところにきちんと書かれることまで保証されるモノではない)、ということをおっしゃっているのだとおもいますが、ファイルシステムのレイヤの話(ここでのext4のコミットの話)と、デバイスの中の話は、どのレイヤの話を言っているのか、分けて説明しないと、周りの人が、びっくりしちゃいますよー。 :D
Re: (スコア:0)
プロセスが突然死するとか、カーネルの異常停止とか、
そういった天変地異をどこまで考慮して書くかということですな。
まぁDBみたいに天変地異が起こってもデータ消失や不整合を起こさないことを
期待されているアプリケーションならともかく、KDEみたいにそれほど
シリアスでないやつはプロセスの異常停止に対応できればいいんでは
ないかと思います。そういう意味では 2. が程々のところかなぁ。
Re: (スコア:0)
ひとつにはファイルシステムとカーネルは切っても切れない関係にあること。
んで、Linuxの標準Cライブラリであるglibcなどが狭義のシステムコールを元に書かれている以上、
遅延書き込みなどといったファイルシステム上の現象はglibcなんかの上に書かれた
アプリケーションすべてに影響するってこと。
なのでなにかとLinuxが叩かれる原因になっている遅延書き込みを避けるために
ファイル書き込みを標準Cライブラリのfopen()なんかを使わず
直接システムコールを叩くようなコードが書かれたりしたりして、その場合、
ファイルシステム差を吸収してくれるライブラリを使っていないのだから
ファイルシステムの実装いかんによって動かないコードが出てきたりする。
…てことじゃないのかと。
ハードウェア関係なくね? (スコア:0)
明らかにソフトウェアねただよね?
Re:ハードウェア関係なくね? (スコア:1)
こじつければソフトウェアネタをハードウェア絡みに転用すると仕様がバグになる、という話かも
電源障害でのメインメモリ内容維持は誰も期待してないと思うけど、ストレージへの書き込みは多分完了しているはずだろう、と。そこへ同じコピーオンライト戦略を使うから。ただでさえストレージの Cache の段階でも同じことが起こりうるのに。
Ubuntuとの関係は (スコア:0)
オプションで提供されるExt4を使っちゃう物好きさんに対して
アプリの改修がリリースに間に合わず積み残されるかもしれないから
使うんなら注意しなさいよってことですね。