Armadillo-640:キャッシュを使用せずにeMMCへ書き込む方法について

お世話になっております。赤坂と申します。

Armadillo640で開発を行ってます。

ルートファイルシステム上にアプリケーションの設定ファイル(800byteほど)を置いており、
Armadillo起動中にアプリケーションから設定変更(設定ファイルの書き換え)を行った場合、
その後に電源をOFF→ON(電源を遮断して起動)すると、設定ファイルの中身が空(0byte)になる事象が
1/4回程度の頻度で発生します。
(電源をOFFする前に、ls, catコマンドで中身のあるファイルが存在することを確認済み)

マニュアルの「20.4. ルートファイルシステムへの書き込みと電源断からの保護機能」を見ると、
「RAM上に残ったキャッシュがeMMCに書き込まれずに、ファイルシステムの破綻やファイルの内容が古いままになる状況が発生します。」
とあるので、その様な状況が発生しているのが原因ではないかと推定しています。

そこで、ルートファイルシステム上のファイルの書き換えを実行した場合に、キャッシュを使用せずに
eMMCに書き込み実行するarmadilloの設定はありますでしょうか?

また、アプリケーションから設定ファイルの書き換えを実行した後に、eMMCに書き込み実行するlinuxコマンドまたは、
C言語関数がありますでしょうか?

よろしくお願いします。

製品: 
Armadillo-640

三原と申します。

Armadillo 独自ではなく Linux 全体に適用される範囲で話をいたします。

Linux で、ファイルに書き込んだデータが物理ディスクに書き込まれる前にバッファリングされるのは、2レベルあります。

- C言語標準ライブラリでユーザ空間にバッファリングされている
- Linux カーネル空間にバッファリングされている

C言語標準ライブラリでバッファされているデータをフラッシュするには、C言語プログラムでは fflush() という関数があります。他の言語のプログラムの場合は、使用している言語のマニュアルを参照願います。

fflush()
https://linuxjm.osdn.jp/html/LDP_man-pages/man3/fflush.3.html

Linux カーネル空間にバッファリングされているデータをフラッシュするには、C言語プログラムでは sync() や fsync() という関数があります。

sync()
https://linuxjm.osdn.jp/html/LDP_man-pages/man2/sync.2.html

fsync()
https://linuxjm.osdn.jp/html/LDP_man-pages/man2/fsync.2.html

ならびにシェルから実行するコマンドとして sync があります。かつて Unix(Linux に限らず) でシャットダウンする際にディスク内容が反映されないという噂から sync コマンドを3回入力するといいという都市伝説が流布したことがあり、その起源を考察した記事が下記 URL にあります。
https://qiita.com/tboffice/items/9c6092278ccaab88e71e

中村です。

> .... sync コマンドを3回入力する ....
懐かしすぎ!

このあたり(↓)も参考に。
[Linux: ディスクキャッシュをストレージへ書き出す方法]
https://users.atmark-techno.com/blog/53/2466

--
なかむら

早速のご回答ありがとうございました。
上記のコマンドを実行して解消するか試してみます。

念のための確認ですが、OSの設定としてキャッシュを使用しない設定は無いでしょうか?

> 念のための確認ですが、OSの設定としてキャッシュを使用しない設定は無いでしょうか?
>
>
吉田と申します。
ファイルをオープンする際にO_DIRECTを指定すると、ページキャッシュを経由しないという話しは聞いたことがあります。実際に効果があるかどうかは試してみないとなんともいえませんが。

追加で質問させて下さい。

電源OFFする前に更新したファイルを確認した際には中のデータがあり、
電源OFF→ON後にファイルの中身が空になっていたので、電源OFFする前に確認していたデータは
RAMのバッファデータだったという事になります。

そこで、ファイル更新後にsync()を実行してRAMのバッファデータをeMMCへ書き込み、
その後、更新したファイルを再度読み込んだ場合(fopenでfreadする)には、
そのデータはRAMのバッファデータでなく、eMMCに書き込まれたデータと考えて良いでしょうか?

sync()によりRAMバッファデータが消えるのであれば、その後に確認するデータは
eMMCに書き込まれたデータである事が保障されると考えるからです。

古関です。

■ ディスクキャッシュの無効化について
> 念のための確認ですが、OSの設定としてキャッシュを使用しない設定は無いでしょうか?
O_DIRECTや以下のパラメータ調整、カーネルコンフィグ設定でできるかもしれませんが、
こちらでは試してないです。

/proc/sys/vm/dirty_background_ratio、/proc/sys/vm/dirty_ratio・・・

キャッシュを無効にする目的は何でしょうか?
(以下の理由によりおすすめできないかなと。)

例えば、「データ書き込み中の電源断によって発生するデータ不整合」の防止が目的だとすると、
これはキャッシュを無効にしたとしても防ぎきれないと思います。

Write要求はファイルシステム ... ブロックデバイス .... といき、最終的にはeMMC内の生NAND まで行くわけですが、
キャッシュを無効にしても書き込みが0秒で終わることはないため、
デバイスへの書き込み中に電源断が起きればデータの不整合は発生しえます。

書き込むデータサイズが大きくなったり、データが小さくても生NAND上の複数のブロックにまたがったりすると
単純に時間がかかりその発生確率は上がります。

試してないので推測ですが、キャッシュの有効時と無効時の以下2つの書き込みオペレーションにおける、
電源断をしてはいけない(不整合が発生しうる)時間ですが、
実運用上でメリットが得られるほどの差は出ないと思います(むしろ悪くなるかも・・)。
・キャッシュ有効時: write要求、sync
・キャッシュ無効時: write

キャッシュを無効にして得られるメリットよりも、発生するデメリットの方が多そうです。
※ I/Oなどの動きがもろもろ遅くなるとか

もし、電源断に対して非常にデリケートなデータを扱う必要があるのであれば、
バッテリバックアップしたり、UPSをつけたり、別のアプローチもアリかもしれません。
(これはかけられるコスト次第ですか)

■ sync後のReadはどこから読まれるか
> そこで、ファイル更新後にsync()を実行してRAMのバッファデータをeMMCへ書き込み、
> その後、更新したファイルを再度読み込んだ場合(fopenでfreadする)には、
> そのデータはRAMのバッファデータでなく、eMMCに書き込まれたデータと考えて良いでしょうか?
write/sync/read/compareがしたいということでしょうかね。

syncはeMMCへの吐き出し要求は行いますが、その後のRead動作に対してはキャッシュヒット(DRAM)するのか、
ちゃんと物理ストレージ(eMMC)から読むのはわからないですね。

不安ならsyncとreadの間に、drop cacheしてみたらどうでしょうか。
https://futuremix.org/2009/09/clear-linux-memory-cach

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

回答ありがとうございました。
追加で教えてください。

ディスクキャッシュは有効にするとしてですが、
動作について知っておきたいための確認です。

アプリケーションからファイルを更新した際に、必ずキャッシュに格納してからeMMCへ書き込まれるのでしょうか?
それとも、場合によって直接書き込まれるとき、キャッシュに一時保存されるときとどちらも取りうる場合があるのでしょうか?

宜しくお願いいたします。

伊澤です。
老婆心ながら補足を。

電源断問題は突き詰めると、eMMCの内部コントローラがデータを受け取ってから書き込むまでのタイムラグがあるのでOS側ではお手上げと言う結論に至ったことがあります。

そもそも論として、フラッシュ自体が100%保障ではないし、umountしてから電源断でも中身がないことがあるのでなんともなりません。