2008年02月26日

microSDカードの書き込み耐性について

microSD や (miniSD , SD) カードの書き込み耐性は、一般に 10万回〜数十万回ということになっているらしい。

本当にそれぐらいしか書き込みできないのか?限界を超えるとどうなるのか?ずっと気になっていた。最近大容量の microSD が安くなって来ているので、使い道がなくなった 64MB の miniSD カードで試してみることにした。

  • データを保存する nand FLASH 自体が 10万回ぐらいの書き込み耐性しかないのがこの回数の根拠だと思う。
  • ただ多くのカードは、損耗平均化アルゴリズム(wear leveling algorithms) やら、不良ブロックマネージメント機能やらを搭載していて、書き換えが集中するブロックの耐性を上げているようだ。だからファイルの作成・削除ができる回数はもっと多いはずだ。

テストの方法

Windows では、どのように書き込むのか調べようがないので、Linux を使うことにする。Linux では、O_DIRECT フラグをつけて open すると、キャッシュを使わないで read/write するようになる。これを使って、確実に書き換えるようにした。

その上で、指定したファイルの指定したオフセット(デフォルト 0)を 毎回違う内容で書き換え、書いたデータが同じかどうかチェックすることにした。


  • 本当は、ファイルを作ったり消したりするのが良いのだが、どこを何回書き換えるのか調べるのが面倒なので、このようにした。これなら、同じブロックが書き換わるはず。
  • テストプログラム→flashtest.c


テストの結果


  • テストは、8KB を書き換えることにした。だいたい 1秒間に 30回ぐらいの write and read ができた --- 10万回書き換える場合 1時間近い時間がかかることになる。


結果は、なんと! 515万回の書き換えができた。最終的には、 write でエラーになった。


  • エラーになった後、ls してみると、77777777.777 という名前のディレクトリが多数できていた。テストに使ったファイルは残っている。--- ルートディレクトリ・エントリが 0xffで埋められた結果だと思う。
  • エラーになった後は、テストを再開しても 1 回目でエラーになるようになってしまった。それだけではなく、新しいファイルを作れなくなった。--- ルートディレクトリ・エントリへの書き換えができなくなってしまったらしい。
  • fdisk でパーティションをずらしたりしてみた。特定のブロックだけがエラーになるのなら、ずらすことでまた書けるようになるかも知れない。実際にやってみると、fdisk 自体は成功するが、どこにずらしても フォーマット(mkfs.msdos) が失敗するようになってしまった。--- どうも カード全体が死んでしまったらしい。


考察

この miniSD カードは、(なんらかの)不良ブロックマネージメント機能をもっていたに違いない。そうでなければ、カード全体が死んでしまうことはないはずだし、なにより 500 万回もの書き換えに耐えることはないはずだ。

さて、500 万回の書き換え耐性というのは、十分なのか?というと微妙なところ。人がオペレーションしてファイルを置いたり消したりするには十分すぎる耐性だが、Linux のルートファイルシステムを作ったりするには不安がある。

  • Linux のファイルシステムは、パーティションの先頭の SUPERBLOCK を最も多く書き換える。どこが変更されても SUPERBLOCK が書き換わるのだ。30秒に1回程度書き換えがおきるとすれば、500万回書き換えできても 5年弱でダメになる計算。


おわりに

たった一例だが、どういうものなのか少しは判った気がする。ついでなので、最新の microSD カードも試してみようと思う。ずいぶん安くなったし、1つ壊してもこれからの安心が買えると思えば安いものだと思うことにする。

ターゲットは、今最も安い上海問屋オリジナルの 2G の microSD カード。

追記:現在テスト中

今、上海問屋オリジナル 2G microSD のテストをしている。
だいたい 10万回書き換えるのに 30分のペース。今 270万回の書き換えが出来ている。

どこまで行けるのかは、想像がつかない。不良ブロックマネージメント機能が多くの代替ブロックを管理していれば、500万回よりはるかに多くの書き換えが出来ても不思議はない。

一応、満足が行く耐性を 3000万回と考えていて、テストの上限も 3000万回としている。上限に達するまで、トータル 150時間もかかる計算だからテストが終了するまで数日かかる場合もあり得る。


- なぜ 3000 万回?
- 仮に 30秒に1回必ず書き込まれると仮定します。そうしたら 1500万分(28.5年)持つということになります。FLASH のデータ保持期間は 10年〜数十年らしいので、これぐらいもてば安心かなぁということです。
- なぜ 30秒に1回?
- Linux で通常のファイルシステムの場合、どこかが更新されたら SUPERBLOCKが更新されます。デフォルトでは SUPERBLOCK の更新間隔が 30秒に1回なのです。SUPERBLOCK 以外でも DISKキャッシュが書き出される頻度があって、これも 30秒に1回ぐらい。ガンカン書き込むようなことをしなければ、(ながい目でみて)最多で 30秒に1回と考えてよいと思います。
- もちろん使い方によっては、更新頻度がもっと高いところが出てくるかも知れません。O_DIRECT とか O_SYNC を付けて open すればこのテストのように短期間で ダメにできます。


上海問屋のユーザレビューについて

フォーマットに失敗するだとか、使えない、あるいはデータが化けるというレポートがいくつか見られた。

本当に初期不良だった可能性もあるのだが、単なる接触不良である可能性の方が高いと思う。というか実際に接触不良を経験した。

新品のPhoto Fast の メモリースティック PRO Duo アダプタを介して使ったのだが、フォーマットに失敗したりした。そして、抜き指しを何回か繰り返しているうちにちゃんと使えるようになった。

SD や miniSD ではそんなことは経験していない。microSD ほど小さくなれば、端子の面積も小さくなるし危険性が高まるのだろう。

特に変換アダプタを使う場合は接触不良に注意!

ちなみに、安物だから品質が悪いとは思っていない。こんな小さく薄いものを作れるメーカは限られているに違いない。どこか一流メーカの OEM のはずだと思っている。


追記:現在テスト中 - その2

現在 トータルで 690万回まで OK まだ継続中なのだが、ちょっと疑問が出てきた。

SD は、FAT16 など特別なフォーマット向けに最適化されているという事実。

コメントにあったように、ELM のページには、内部的には 512B ではなく 2KB でアクセスしていたりすることが書かれている。

ひょっとして、2,4,8..N KBのバッファを持っていて、それに満たないデータを何回買いても 実際にはバッファに書き込まれるだけではないか?

そういうおそれがあったので、一回に書き込むデータ量を 8KB にしてみたのだが ... それで十分だったのだろうか?

ターゲットの microSD にもともとされていたフォーマットは FAT16 だったのか FAT32 だったのか実はわからなくなっている。

少なくとも、それとは違う 2G のカードで FAT16 のものがあったことは覚えている。これも FAT16 だったのかも知れない。


さて、FAT16 の場合、アロケーションサイズ(クラスタサイズ)は、32KB にもなる。実際のFLASH への書き込みは、32KB 全部書き込まれて初めて発生するのかも知れない。

ただし、ぜんぜん違う場所への書き込みが発生すれば、カレントのバッファを書き出し始めるはず。(そうでないと仕様を満たせない)

そして、おそらく、高速化のためにバッファを複数持っているはず。複数といっても普通は 2 。3 以上になると、一般のキャッシュ制御と変わらなくなる。内部 FW が複雑になりすぎるうえに、メリットがないはずで 3 以上というのは考えにくい。

このテストでルートディレクトリ・エントリが壊れるほど書き換えたことで、実際に書き換えたエリアと、ルートディレクトリ・エントリの 2 ヵ所は書き換えることが判っている。

だから本当に書き換えているのだと思うのだが、ひょっとしたらテストプログラムが書き換えたはずの回数と実際に書き換えた回数が違うかも知れない可能性が若干ある。

さらに実は、もうひとつ懸念がある。このテストは、VMware Player を使った仮想 OS (Vine-4.2) で行っているのだ。ゲストOS が DISK に書き込むのは間違いないと思っている。ソースコードを見て確かめることさえできるから、本当に怪しくなったら確かめても良い。

それは良いのだが、VMware Player あるいは、ホスト OS 側がキャッシングしてしまう可能性がある。

Flash のアクセスランプが点滅しているし、秒間 60回ぐらいしか書き換えできていないから、大丈夫のはずだが、確信にまでは至らない。

そういうわけで、このテスト継続していくが、実際の書き換え回数と違うかも知れないことを覚えておいてほしい。


おまけ - Windows XP の設定について

以前は、Flash メモリなどを取り外したときに、「安全な取り外し」の作業が必要だったことを覚えて( or 知って)いるだろうか。そして、今はそのメニューが出ないことを。

この機能の切り替えは、コントロールパネル→管理ツール→コンピュータの管理で出てくるパネルの上で、ディスクの管理→ディスク1などのリムーバブルディスクの装置自体(ボリュームではなく左)のプロパティのポリシーで切り替えられるようになっている。

デフォルトは「クイック削除のために最適化する」でキャッシュを使わない。「パフォーマンスのために最適化する」を選ぶとキャッシュを使うようになり、書き込みの回数を減らすことができる。

Flash メモリを使うときは、これを選んだほうが良いのだが、「安全な取り外し」の作業をする必要が出てきて、ちょっと面倒。

キャッシュを使わないではなくて、キャッシュの寿命を 1秒とか コントロールできたほうが嬉しかった。



追記:ほんとうに Flash を書き換えているのか?

まず、Linux 内部で Flash を書き換えたかどうか検証してみた。

まず、使っている OS は vine-4.2 である。サーバ用OSとは違って システム負荷を調べるようなツールは充実していない。とりあえず、RHEL4 の sysstat のソースRPM をとって来て rpmbuild を使ってビルドしてインストールした。

次に /etc/init.d/sysstat start を動かして数時間放置。

そして、sar -d を使って DISK毎の I/O 状況を調べてみると次のようになった。(抜粋)

DEV tps rd_sec/s wr_sec/s
21時40分00秒 dev8-0 107.08 856.45 856.46
21時50分00秒 dev8-0 108.04 864.09 864.15
22時00分00秒 dev8-0 105.17 841.15 841.18
22時10分00秒 dev8-0 108.83 870.39 870.41
22時20分00秒 dev8-0 109.10 872.61 872.62
22時30分00秒 dev8-0 109.13 872.85 872.88
22時40分00秒 dev8-0 105.96 847.47 847.52


dev8-0 というのは、major 8 minor 0 というデバイスの意味で、/dev/sda のこと。この環境だと USB mass storage である テスト中の microSD を指す。

wr_sec/s は、1秒間あたりの Write セクタ数(512B単位)。rd_sec/s は読み込んだセクタ数 。tps は1秒間あたりの I/O 回数(read writeの合計)。
この情報で、平均 I/O サイズは 8KB ぐらいとわかる。全部がテストプログラムでの read/write だとすれば、10 万回の write + read をするのに 15.4 分で済んでいるはずだ。

ところが、プログラムのログは、次のように 10万回あたり 30.5 分かかっていることを示している。

02/27 21:58:56 :05800000 times -- OK
02/27 22:29:31 :05900000 times -- OK


どういうことかというと、テストでの write+read の組に対して余分な 8KB の read と write が発生しているということ。そして、この余分な read と write は ルートディレクトリ・エントリに対しての I/O ということになる。

なぜルートディレクトリ・エントリに対して I/O が必要かというと、更新時間を記録するためである。

- ただしこれは、O_DIRECT を指定したときだけの動作、普通はキャッシングするから read はしないし、更新時間も 30秒に 1回とかの頻度になる。
- O_DIRECT を指定したからといって、ルートディレクトリ・エントリまでキャッシングしないというのはなぜなのか? -- ちょっとわからない。


こういうように Linux 側でどういう I/O をしたかは分析できる。

Windows でも 管理ツール→パフォーマンス→システムモニタで調べることができる。+のアイコンでカウンタを追加する。追加する項目は、PhysicalDISK の DISK Write Bytes/sec 。対象とするインスタンスは(リムーバブルディスクは選択できないので)Total を選択する。別に C: もあるので、これも追加する。

で、みてみると、C: と Total が同じであることがわかる。どういうことかというと、Windows では 物理DISK として管理していないということ。もっとハードウェアに近いレイヤ(デバイスそのものか デバイスを仮想化したもの)で VMware Player に接続されている。こういう状況なら Windows でのキャッシングはないといえそうだ。

- Windows の中がどうなっているかは判るわけもないが、一般に OS での DISK のキャッシングは、物理DISK にたいして行われる。
- 論理DISK (パーティショニング後の仮想化されたディスク(のはず))を対象にするかも知れない。
- でもデバイスに対してのキャッシングはあり得ない。物理DISKというレイヤの意味がなくなる。


最後に残るのは、VMware Player でキャッシングしているかどうか。デバイスそのものを扱っているのならば、やろうと思ってもまずは、無理そうだ。

- VMware Player は、USB host コントローラを ゲストOS に見せている。
- Windows から USB host コントローラへのアクセス権利をもらって(奪って) そのまま ゲスト OS に見せているのだと思う。
- ただ、あくまで推測。USB mass storage のプロトコルとかもっと上位レイアのやりとりを使って 仮想 USB host コントローラに見えるようにしているかも知れない。
- ただそういう場合でも自分でキャッシングしたら問題が出る場合がある。-- 装置を切り離したときに、書いていないデータがキャッシュに残ってしまうかも知れない。

ここまで調べて、テストの結果は信用して良さそうという結論になる。

追記:エラー発生!

1000万回書き込めた後、データの不一致を検出。

不一致になったときのデータパターン

00: 54 e8 7c 00 da da da da da da da da da da da da
01: da da da da da da da da da da da da da da da da
02: da da da da da da da da da da da da da da da da
03: da da da da da da da da da da da da da da da da
          あと全部 da

先頭 4 バイトは書き込み回数。そして、残りの da というのは、書き込み回数 の 下位1バイト。
1 バイト目と 5バイト目以降の値は同じにならなければならない。
エラーが起きたときのログから、1バイト目(先頭)が 0xda であるべきなのが、0x54 になったということだ。


このデータ調べればわかるが、8138714 回を指している。実は 2 回目。1回目は、USB が disconnect になって、テストが中断されてしまった。そのときの、190万回を足している。


ただ、壊れ方が不自然。先頭の1バイトだけが壊れるというのは、いかにもソフトのバグのような感じだ。また、普通のカードは、ECC でエラー検出しているらしい。このカードも不良セクタマネージメント機能を持っているようだから(1000万回も書けたなら絶対数回は代替しているはず)データが化けてしまったら read error になるはずなのだ。

Linux あるいは VMware Player のなんらかのバグで、書き込む前にデータが化けてしまったと判断。データを正しいものに変更し、再実行することにした。

追記:2回目のエラー発生!

1740万回書き込めた後、データの不一致を検出。

不一致になったときのデータパターン

PAGE: 28 (7168)

00: ab 7a ba ba ba ba ba ba ba ba ba ba ba ba ba ba
01: ba ba ba ba ba ba ba ba ba ba ba ba ba ba ba ba
02: ba ba ba ba ba ba ba ba ba ba ba ba ba ba ba ba
03: ba ba ba ba ba ba ba ba ba ba ba ba ba ba ba ba


2回似ているエラーになった以上、1回目の判断は怪しいということにしてあらためて考察してみよう。

512 B 単位の先頭の 1〜2 バイトが壊れたというのが共通するパターン。そして、保存されたデータ自体が壊れていて、read エラーにはならない。

なんだか、書き込みのデータ転送で microSD がデータを誤って受け取ったような感じがする。転送しようとした直後は、タイミングが厳しいとかなんらかのカード固有の理由があるのかも知れない。たしか CRC 付きの転送だったはずなので、ちゃんと調べれば、CRC 値が同じになるかどうかで判断できそうだ。

でも、転送で CRC をすり抜けるパターンでたまたまエラーが起きた ... というのもどうかという気がする。すり抜けなかったエラーは実は多数起きていてそれは、dmesg で確認できるメッセージとして表示されないだけかも知れない。そういうことはカーネルのソースコードを調べればわかるはず。

まぁ、ぜんぜん外していて、まったく違う理由かも知れない。理由を追うのは面倒だから事実だけに注目してみる。

この microSD 限定の話になるが、どうも 書き込みはいくらでも出来るように見える。ただ、書き込みでエラーが起きなくても正しいデータが記録されているとは限らない。

この点はハードディスクと違う。ハードディスクは、もっと信頼できる。そして、OS は (ハードディスクと同じ処理が基本なので)普通、正しく書けたかどうかデータを確認することまではしない。

確実にデータを保存したいケース(確率は低いようなので、本当に大事なデータの場合)は、いったん PC から切り離して、再接続し、MD5 とかチェックサムをとって確認する作業をした方が良いかも知れない。

上記のような壊れ方をした場合の考察
上記のようなパターンで壊れた場合、データが入っているところ(データブロック)が壊れたから上記のようになったわけだが、他の場所が壊れた場合どういう風にみえるのかについてもうすこし説明しておこう。(あくまで 512B のうち先頭の 1〜2 バイトが壊れたというケース限定、他の壊れ方まで説明するのは難しい)

FAT が壊れた場合)
たまたま FAT が上のように壊れると、更新したファイルとぜんぜん違うファイルのデータが壊れることになる。C でいうとポインタで一方向リンクを作っていたときにポインタの1つに変な値が入ったようなもの。こわれたリンクから先がめちゃめちゃになる。
OS がなにをしているかわからないのだが、FAT は 2 組あるので、chkdsk とかで復旧できるかも。(自信なし)

BPB (SUPERBLOCK相当)が壊れた場合)
FAT ファイルシステム覚え書きを参考にすると、先頭には、3 バイトの jmpOpeCode という部分があり、それが壊れることになる。ここに正しいデータが入っていないとおそらく、ファイルシステムが認識されない。普通の方法では復旧できないだろう。
ただ、ここだけが壊れたのが確実なら、正しい データにすればよいので復旧が完全に不可能というわけではない。

ディレクトリエントリが壊れた場合)
こういうケースでは、更新したファイルがあるディレクトリで、ファイル名が化ける結果になりそうだ。ダメージとしては小さい。



追記:3回目以降のエラー

2 回目でもうやめようと思ったのだが、それからしつこくやるとどうなるか興味があったのでやってみた。

3 回目は、2回目のエラーから 78万回で write エラーが起きた。4 回目はそれから 20万回で write エラー。エラーが起きたところは、前のデータのままになっていた。

いつまでも書けるのかと思ったが違うようだ。2 回目のエラーのときには既に限界になっていたようだ。

限界を超えると write エラーになり、しかも前のデータが残っているのというのは、たちの良い壊れ方だ。ただし、1 回目/2回目のようなことがあると write エラーで限界だとわかったときには、すでにいくつかのファイルがおかしくなっているということでもある。


ちなみに、4回目のエラーの後、別のファイルに対してテストを実行してみたところ、25 万回でエラーになった。要するに 代替ブロックを消費しつくした後は、代替しないで write エラーになる。記録する FLash 自体の書き込み耐性はやはり、10 万回〜数十万回の
ようだ。1 回 write エラーになった後、もう書けないわけではなく、ある確率で write エラーになる。そしてその確率は(おそらく)だんだん高くなっていくように思える。


おわりにその2

題名が microSD の 書き込み耐性で、64M miniSD はプロローグみたいなもの。それで終わるのは気がひけたので、ここまで追記してしまった。

それはともかく、他の microSD はどうなのか? なんて興味も出てきてしまった。金銭的にダメージがあるので、あんまりやるつもりはない。でも壊れ方のパターンを知りたいので、もう1つだけやってみようかと思う。

ターゲットは、キングストンの microSD 2G 。東芝の chip を使っているらしい。あと microSD 自体に JAPAN の文字がはいっている。テストをするマシンも玄箱/HG(自分改造版) の Linux に変更予定。

なお、このレポートは新しく記事にするので、追記はここで終わりです。

microSDカードの書き込み耐性(2)に続く。
posted by すz at 00:40| Comment(5) | TrackBack(1) | microSD関係
この記事へのコメント
興味深い試験ですね。
単純に考えると、セルの損耗とともにカードの空き容量が減ると思いますが、それは記録していないのでしょうか?

SDCなどで始めからFAT16でフォーマットされているものがありますが、ファイルシステムのエントリやセルのアライメントを考慮してFAT16に最適化されていると言う記事を読んだことがあります。

その為、FAT32やNTFSで強引にフォーマットするとアクセスが遅くなったり寿命が短くなったりするそうな。
FAT情報が書き込まれるメモリブロック最先頭は特別なセルになっていて、書き換え速度(や耐性?)が高くなっているそうです。
検証してみると面白いかもしれませんね。

http://elm-chan.org/docs/mmc/mmc.html
Posted by AkSd at 2008年02月26日 12:47
不良ブロックマネージメント機能とかを搭載している場合、代替ブロックは OS から見えないところに確保されているはずです。そうでないと、OS が使ってしまうかも知れない。(これは、ハードディスクも同じ。)
だから OS からみえる容量は変わりません。

先頭ブロックは特別というのは(少なくともテストで使った miniSD では)事実のようですね。カード全体が死んでしまっても FDISK は成功しています。ただ、FAT 領域まではカバーしていないようです。

あと、ここで調べた結果は、あくまで実際に調べたカードの特性で、一般化できるものではないと思います。microSD だとあまりに小さいので、実装のバリエーションは少なさそうですが、CF とか USB メモリは、大きいのでいろんな実装があり得て、それぞれ特性が違うのかも知れません。
Posted by すz at 2008年02月26日 13:35
細かく読んでませんが、
SDカードはOSやファイルシステムレベルではなく、一段下のSDカード内部のファームウェアレベルで、各ブロックを満遍なく使う仕組みが働いているはずです。
ファイルシステムが同じところに上書きした、と思っていても実際にはそのブロックはイレースされ、違うブロックに書き込まれます。それはOSレベルからも見えない動作です。そうやって全体を均一に使うために全体の書き込み回数が増えます。不良ブロックマネジメントみたいなのはないと思います
Posted by 名無し at 2008年03月22日 04:58
こんにちは。
面白い事をされてますね。前の方も書かれてますが、Flashメモリはセルをまんべんなく使う機構があります。
例えば10^5回書き換えられる1GBのフラッシュメモリがあれば、概算でその製品の生涯トータルで1GB * (10 ^ 5) Byte だけ書き換えられる事になります。これはあくまで概算で、実際には、ホットスポット(一点への重点的な書き込み)を避けるため、「ブロックを移動する」などの処理を行っていますので、これより更に少ないはずです。これで気がつかれたと思いますが、実は容量が多いければ多い程、製品の寿命が長くなります。ご参考までに。
Posted by くろぼし at 2008年03月23日 09:58
同じテストでの結果を知りたし
Posted by USBメモリの回数制限はどうなの? at 2009年01月03日 22:35
コメントを書く
お名前:

メールアドレス:

ホームページアドレス:

コメント: [必須入力]

認証コード: [必須入力]


※画像の中の文字を半角で入力してください。
この記事へのトラックバックURL
http://blog.sakura.ne.jp/tb/30760445
※ブログオーナーが承認したトラックバックのみ表示されます。

この記事へのトラックバック

ここまでやるか!?microSDカードの書き込み耐性を徹底研究!!
Excerpt: すzのAVR研究: microSDカードの書き込み耐性について [useWillcom]  よく研究されています。興味深いですね。とりあえずケータイで普通に使う分に...
Weblog: ねこもば。β版 - へっぽこ実験ニュースサイト
Tracked: 2008-03-26 21:38