closeがEINTRを返したらどうするべきか

カーネルハッカーたちがcloseの仕様について辻斬りでバッサリするスレッド
47
中村 実 @nminoru_jp

世の中には二通りの人間がいる。close()の復帰値を確認する人間としない人間だ。

2013-10-30 10:04:21
小崎 資広 @kosaki55tea

@nminoru_jp 確認したところでたいていは手遅れで復旧不可能だけどね

2013-10-30 10:08:30
中村 実 @nminoru_jp

@kosaki55tea どうなんでしょう。close()がEINTRで返ってきた場合にリトライをかけないとリークが発生することがあります。FUSEでできた変なネットワークファイルシステムを使っている場合なんて特に。

2013-10-30 11:26:30
鯉江 @koie

@nminoru_jp closeがエラーになったら異常系に飛ばしてました。EINTRリトライは考えてなかったっす。異常系処理でcloseするときもEINTRリトライはしないといけないなぁ。やばいなぁ。

2013-10-30 11:29:17
Tanaka Akira @tanaka_akr

@nminoru_jp @kosaki55tea close(fd) が失敗した時に fd が生きていることがあるのですか。以前 NFS の quota でテストして close が失敗したときには fd は死んでいたので、close が失敗したらどうしようもないと思ってました。

2013-10-30 11:32:07
小崎 資広 @kosaki55tea

@tanaka_akr @nminoru_jp Linux限定だと 1) fd table のクリア 2) f_op->flush() という順でエラーが起きる可能性があるのは2だけ、かつVFSのflushはNFSぐらいしか使ってないので、EINTR無視でいいはずです

2013-10-30 11:39:38
小崎 資広 @kosaki55tea

@tanaka_akr @nminoru_jp 他のOSはしらないけど、EINTRでfdがクリアされてるかどうか不定のOSがあったらバグだと思う。しかしPOSIX的にはEINTR返ってきたらfildesの状態は unspecified なのだな。腐ってやがる・・・・

2013-10-30 11:41:39
小崎 資広 @kosaki55tea

@tanaka_akr @nminoru_jp なので、ものすごく保守的に考えるとEINTRではリトライ、すでに閉じ済みだったら次はEBADFが帰ってくるはず。という仮定をすることになる・・・・のかなあ?めんどくさくてやってられないが

2013-10-30 11:42:51
Tanaka Akira @tanaka_akr

fd の確保・解放と、資源との接続・切断が分離されていないのは Unix の design error だと思う。

2013-10-30 11:43:54
Tanaka Akira @tanaka_akr

@kosaki55tea @nminoru_jp EBADF を期待しちゃうと signal handler で fd が allocate される可能性が。

2013-10-30 11:44:48
小崎 資広 @kosaki55tea

@tanaka_akr @nminoru_jp ああ、ほんとですね。やっぱり規格のミスだよなあ。これ

2013-10-30 11:45:24
成瀬 @nalsh

@nminoru_jp @kosaki55tea 下手にリトライかけると新しく割り当てられた他人のfdを解放してしまう恐れがあるので、その変なネットワークファイルシステムの方がおかしいように思います

2013-10-30 11:52:23
小崎 資広 @kosaki55tea

@nalsh @nminoru_jp Linuxの場合closeが返ってきた時はfdが無効化されてるが保証されてるのでリトライは100%意味がなく、たとえFSがバグっていたと仮定してもリトライは変な気がします。あとNFSもEINTR返すからEINTR自体はバグではない

2013-10-30 11:59:38
小崎 資広 @kosaki55tea

@nalsh @nminoru_jp むしろNFSもEINTR返すなよって気はするけどな。わたしは

2013-10-30 11:59:59
Tanaka Akira @tanaka_akr

そういえば、socket も linger で close 時の error があったような...

2013-10-30 12:02:22
成瀬 @nalsh

@kosaki55tea @nminoru_jp ちなみにFreeBSDもfd無効化保証していますね

2013-10-30 12:03:04
成瀬 @nalsh

@tanaka_akr FreeBSDはECONNRESETを返すことがありますな

2013-10-30 12:03:32
SODA Noriyuki @n_soda

@nalsh @kosaki55tea @nminoru_jp http://t.co/UIcazQ3wUV みると、だいたいどのOSも、EINTR返した時には既にfd無効化済みみたいですね(Solarisもそうみたい)。リトライが必要なのはHP-UXっぽい。

2013-10-30 12:09:38
小崎 資広 @kosaki55tea

@tanaka_akr 今手元にあるソースだとlingerのときの処理は返り値無視してるのでerrorはユーザ空間まで伝搬しないように見えるけどなあ

2013-10-30 12:11:33
SODA Noriyuki @n_soda

@nalsh @kosaki55tea @nminoru_jp あとAIXはmanにfdが無効化されてると明記されてるとありますね。HP-UXは逆にリトライが必要と明記されているという。Solaris 9のmanにはunspecifiedとありますが実際には無効化済みなのかしら

2013-10-30 12:12:02
Tanaka Akira @tanaka_akr

@kosaki55tea 体験したわけじゃなくて、本で読んだ記憶があるという話です。Stevens だった気がする。

2013-10-30 12:13:18
SODA Noriyuki @n_soda

@koie リトライすると、かえって @nalsh さんが書いてた race condition によるバグが増えるので、リトライするなら #ifdef hpux が必要ってことなんじゃないでしょうか。

2013-10-30 12:19:47
成瀬 @nalsh

@n_soda @koie closeのrace conditionはデバッグ大変なので安易にリトライすると大変ですよ……

2013-10-30 12:21:45
鯉江 @koie

@n_soda 見落としてました。ちゃんとmanpageにかいてありますねEINTR以外はdeallocated。じゃぁcloseするまえにfsyncするのは必須ってことですかね、ファイルシステムのばあいは。ソケットだと上のレイヤ―で確認したほうが簡単かなぁ。

2013-10-30 12:23:34
SODA Noriyuki @n_soda

@nalsh @koie 発生したら関係ないファイルに間違えて書くとかありうるので、デバッグ大変だけじゃなく、データ失うとかいうヤバいバグに…

2013-10-30 12:23:56