Armadilloフォーラム

ファイルの作成遅延?

kasahara.adincs

2014年5月28日 15時45分

いつもお世話になっております、アディンクスの笠原です。

ArmadilloからFTPでデータを他のPCに転送しています。
c言語でFTPクライアントはoftplibを使っています。
ファイルシステムはMicroSD上のExt3です。

1分に1回データ(数百バイト程度)を転送するのですが
まず転送用のファイルを作成し、その直後にftpのライブラリで
別PCに転送しています。2時間程度は問題なく動作するのですが
突然データが送られなくなる現象が発生しています。
ftpライブラリのファイル転送(ftp_put_file())でエラーになっており
同様のエラーを発生させるため色々と試してみると、送信するファイル
が存在しない場合の動作と同様になっているようです。
ただし外から(lsコマンド)見ている限りではファイルは存在しています。
(送信時点での厳密な有無は確認できていません)
一番の問題は一度発生すると、以降ずっと同様の状態となり
ファイルが転送できなくなってしまう点です。
プログラムを再起動すれば、また2時間程度は動作します。
同時に1時間に1回送信するプログラムを動かしていますが、こちらは
100時間近く問題なく動作しています。
すでにファイルがある場合は5秒間隔で1000回送信してもなんら問題は
発生しません。(テストプログラムで確認)

 fclose()した直後でファイルが作成されていないとすれば何が原因と
考えられるでしょうか?また対策はありますでしょうか?

 どなたか似たような経験等ありましたらアドバイスをお願いいたします。

    アディンクス 笠原 正彦

コメント

こんにちは タカキ工業の高木と申します。

>  fclose()した直後でファイルが作成されていないとすれば何が原因と
> 考えられるでしょうか?また対策はありますでしょうか?

writeシステムコールでファイル書き込みを行った際、ディスクキャッシュの影響が出ることがあるようです。

sync, fsyncで改善されたりしないでしょうか。

▼C言語システムコール-sync CapmNetwork
http://bit.ly/1hzXS8O

▼Man page of SYNC
http://linuxjm.sourceforge.jp/html/LDP_man-pages/man2/sync.2.html

よろしくお願いします。

kasahara.adincs

2014年5月29日 9時54分

タカキ工業 高木 様

 おはようございます、アディンクス 笠原です。
アドバイスありがとうございます。

 syncの件は気になりまして昨晩仕込んで帰りましたが
やはり2時間ちょっとでおかしくなっていました。
ただ、ftpのライブラリに渡す前にファイルをopenしても
openはできる(エラーにならない)ようで原因は単純では
ない気がしてきました。
 利用しているoftplibも含めて今後調査してみようと
思います。(同じファイルを別名で送る場合だと1000回
やっても問題は発生しないんですが・・・)

 また何か思いつかれるようなことがありましたら
教えていただければ助かります。
ありがとうございました。

> こんにちは タカキ工業の高木と申します。
>
> >  fclose()した直後でファイルが作成されていないとすれば何が原因と
> > 考えられるでしょうか?また対策はありますでしょうか?
>
> writeシステムコールでファイル書き込みを行った際、ディスクキャッシュの影響が出ることがあるようです。
>
> sync, fsyncで改善されたりしないでしょうか。
>
> ▼C言語システムコール-sync CapmNetwork
> http://bit.ly/1hzXS8O
>
> ▼Man page of SYNC
> http://linuxjm.sourceforge.jp/html/LDP_man-pages/man2/sync.2.html
>
> よろしくお願いします。

タカキ工業の高木です。

>  syncの件は気になりまして昨晩仕込んで帰りましたが
> やはり2時間ちょっとでおかしくなっていました。

そうでしたか…
また、何か関係がありそうな情報がありましたら、書き込ませていただきます。

> c言語でFTPクライアントはoftplibを使っています。
libOftp http://sourceforge.jp/projects/liboftp/
こちらの事でしょうか?

このライブラリは使った事が無いのですが、
v2.2をダウンロードしてみました。

> ftpライブラリのファイル転送(ftp_put_file())でエラーになっており
> 同様のエラーを発生させるため色々と試してみると、送信するファイル
> が存在しない場合の動作と同様になっているようです。
ftp_put_file.c::ftp_put_file()で
呼ばれるftp_put_file_main()のopen()がエラーを
返しているという理解であってますか?

もしopenで ENOENT (No such file or directory)
がセットされるところまで判明しているのであれば、
的外れな指摘で申し訳ございません。

sub.hによると、FTP_DEBUGを有効にすると
openでセットされるerrnoに応じたメッセージを出す
ようなので、その際のエラーをそのまま教えていただ
けるとLinux一般の話ができるかと思います。

kasahara.adincs

2014年5月29日 17時16分

at_ohsawa 様

 ご連絡ありがとうございます。
ftpのライブラリは記述されているものと同じです。
これをATDE3の環境でコンパイラ等をArm用に変更したMakeで作成しました。

 まだライブラリの内部的な部分には手を付けていません。
内部のどの部分でエラーが発生しているか等は未確認です。
(ライブラリ関数の戻り値とライブラリのメッセージ(ftp.error_message)が
 送信元ファイルがない場合と同じ状況である程度の確認まで)

ご指摘のFTP_DEBUGを有効にしたライブラリを作成して今晩実行してみます。
実行結果は明日に提示させていただきますのでお手数ですがよろしくお願い
いたします。

    アディンクス 笠原

> > c言語でFTPクライアントはoftplibを使っています。
> libOftp http://sourceforge.jp/projects/liboftp/
> こちらの事でしょうか?
>
> このライブラリは使った事が無いのですが、
> v2.2をダウンロードしてみました。
>
> > ftpライブラリのファイル転送(ftp_put_file())でエラーになっており
> > 同様のエラーを発生させるため色々と試してみると、送信するファイル
> > が存在しない場合の動作と同様になっているようです。
> ftp_put_file.c::ftp_put_file()で
> 呼ばれるftp_put_file_main()のopen()がエラーを
> 返しているという理解であってますか?
>
> もしopenで ENOENT (No such file or directory)
> がセットされるところまで判明しているのであれば、
> 的外れな指摘で申し訳ございません。
>
> sub.hによると、FTP_DEBUGを有効にすると
> openでセットされるerrnoに応じたメッセージを出す
> ようなので、その際のエラーをそのまま教えていただ
> けるとLinux一般の話ができるかと思います。

kasahara.adincs

2014年5月30日 12時09分

at_ohsawa 様

 アディンクス笠原です。

昨晩仕込んだログが通常→エラーになった時のものがなくなっていたので
再度実行しなおしてみました。
エラー直前直後のログは以下のようになっています。
(エラー発生後は同じエラーの繰り返しです)
ちなみに転送されたファイル数は145個
有効な情報かどうか不明ですが
#cat /proc/sys/fs/file-nr
1499 0 8192
でした。
このログでわかりますでしょうか?

 よろしくお願いいたします。

===ここからログ===
(sub.c) RESP1: 220-FileZilla Server version 0.9.41 beta

(sub.c) RESP2: 220-written by Tim Kosse (Tim.Kosse@gmx.de)

(sub.c) RESP2: 220 Please visit http://sourceforge.net/projects/filezilla/

(sub.c) SENDC: USER atmark
(sub.c) RESP1: 331 Password required for atmark

(sub.c) SENDC: PASS atmark
(sub.c) RESP1: 230 Logged on

(sub.c) SENDC: SYST
(sub.c) RESP1: 215 UNIX emulated by FileZilla

(ftp_user.c) system type is 1
(sub.c) SENDC: CWD pub/minute
(sub.c) RESP1: 250 CWD successful. "/pub/minute" is current directory.

(sub.c) SENDC: PASV
(sub.c) RESP1: 227 Entering Passive Mode (192,168,1,10,8,170)

(sub.c) SENDC: STOR minute_201405301143_777.csv
(sub.c) RESP1: 150 Connection accepted

(ftp_put_file.c) SEND: n=125
(sub.c) RESP1: 226 Transfer OK

(sub.c) SENDC: QUIT
(sub.c) RESP1: 221 Goodbye

(sub.c) RESP1: 220-FileZilla Server version 0.9.41 beta

(sub.c) RESP2: 220-written by Tim Kosse (Tim.Kosse@gmx.de)

(sub.c) RESP2: 220 Please visit http://sourceforge.net/projects/filezilla/

(sub.c) SENDC: USER atmark
(sub.c) RESP1: 331 Password required for atmark

(sub.c) SENDC: PASS atmark
(sub.c) RESP1: 230 Logged on

(sub.c) SENDC: SYST
(sub.c) RESP1: 215 UNIX emulated by FileZilla

(ftp_user.c) system type is 1
(sub.c) SENDC: CWD pub/minute
(sub.c) RESP1: 250 CWD successful. "/pub/minute" is current directory.

(ftp_put_file.c) local file open error. Too many open files

(sub.c) SENDC: QUIT
(sub.c) RESP1: 221 Goodbye
===ここまでログ===

> at_ohsawa 様
>
>  ご連絡ありがとうございます。
> ftpのライブラリは記述されているものと同じです。
> これをATDE3の環境でコンパイラ等をArm用に変更したMakeで作成しました。
>
>  まだライブラリの内部的な部分には手を付けていません。
> 内部のどの部分でエラーが発生しているか等は未確認です。
> (ライブラリ関数の戻り値とライブラリのメッセージ(ftp.error_message)が
>  送信元ファイルがない場合と同じ状況である程度の確認まで)
>
> ご指摘のFTP_DEBUGを有効にしたライブラリを作成して今晩実行してみます。
> 実行結果は明日に提示させていただきますのでお手数ですがよろしくお願い
> いたします。
>
>     アディンクス 笠原
>
>
>
> > > c言語でFTPクライアントはoftplibを使っています。
> > libOftp http://sourceforge.jp/projects/liboftp/
> > こちらの事でしょうか?
> >
> > このライブラリは使った事が無いのですが、
> > v2.2をダウンロードしてみました。
> >
> > > ftpライブラリのファイル転送(ftp_put_file())でエラーになっており
> > > 同様のエラーを発生させるため色々と試してみると、送信するファイル
> > > が存在しない場合の動作と同様になっているようです。
> > ftp_put_file.c::ftp_put_file()で
> > 呼ばれるftp_put_file_main()のopen()がエラーを
> > 返しているという理解であってますか?
> >
> > もしopenで ENOENT (No such file or directory)
> > がセットされるところまで判明しているのであれば、
> > 的外れな指摘で申し訳ございません。
> >
> > sub.hによると、FTP_DEBUGを有効にすると
> > openでセットされるerrnoに応じたメッセージを出す
> > ようなので、その際のエラーをそのまま教えていただ
> > けるとLinux一般の話ができるかと思います。

> (ftp_put_file.c) local file open error. Too many open files
EMFILEがセットされて、Too many open filesを表示していますね。

ファイルが無い(No such file or directory)状態では無いです。

Linuxでは一つのプロセスでopenできるファイルディスクリプタ
(socketも含む)に上限があり、Armadillo-420のデフォルトでは
1024個です。
それを越えてopenしようとした時にこのエラーが出ます。

推測になりますが、
次のような状態になっているのだと思います。

- closeせず(できず)にopenを繰り返している
- PCとのコネクションが多数張られている

ulimitを使えば手っ取り早く上限を増やす事ができます。

[Armadillo ~]# ulimit -n 4096
[Armadillo ~]# ./ftp_application

ただ気になる点は、
- 接続先は常に1台のPCだけ
- 1分おきにftpプロトコルでpush
という条件だけではファイルディスクリプタ
が1024個を越える事は無いかと思います。

他にftp転送以外でopenしたり、
socketをcloseしないコードパスがあれば、
そこを直すと安定動作に繋るとおもいます。

kasahara.adincs

2014年5月30日 15時53分

at_ohsawa 様

 アディンクス 笠原です、解析ありがとうございました。
ご指摘の通り細部を確認した結果、送信ファイル作成時に一部close漏れが
発生していました。(計算的にも一致しそうです)
今回のケースではこの部分を頻繁に通るため発生したと思われます。
これから再度プログラムを動かして検証いたしますが、結果が判るのはかなり先
と思われますので先に報告させていただきます。

 お手数をお掛けしました事お詫びいたします。

  アディンクス 笠原

> > (ftp_put_file.c) local file open error. Too many open files
> EMFILEがセットされて、Too many open filesを表示していますね。
>
> ファイルが無い(No such file or directory)状態では無いです。
>
> Linuxでは一つのプロセスでopenできるファイルディスクリプタ
> (socketも含む)に上限があり、Armadillo-420のデフォルトでは
> 1024個です。
> それを越えてopenしようとした時にこのエラーが出ます。
>
> 推測になりますが、
> 次のような状態になっているのだと思います。
>
> - closeせず(できず)にopenを繰り返している
> - PCとのコネクションが多数張られている
>
> ulimitを使えば手っ取り早く上限を増やす事ができます。
>
>

> [Armadillo ~]# ulimit -n 4096
> [Armadillo ~]# ./ftp_application
> 

> ただ気になる点は、
> - 接続先は常に1台のPCだけ
> - 1分おきにftpプロトコルでpush
> という条件だけではファイルディスクリプタ
> が1024個を越える事は無いかと思います。
>
> 他にftp転送以外でopenしたり、
> socketをcloseしないコードパスがあれば、
> そこを直すと安定動作に繋るとおもいます。
>

> ご指摘の通り細部を確認した結果、送信ファイル作成時に一部close漏れが
> 発生していました。(計算的にも一致しそうです)

原因がわかったようで良かったです。

ライブラリ内に限らずシステムコール
のエラー処理の中では perror()やstrerror()
を使ってerrnoを分りやすく表示するよう
にしておくと便利ですね。

 
#include <stdio.h> 
#include <errno.h> 
.... 
   fd = open("xxxx"); 
   if ( fd < 0 ) {   
       perror("open"); 
       return -1; 
   } 
.....