SDカードがRead-Onlyになってしまうのを防ぎたい

いつもお世話になっております。

Armadillo-440を使用中にSDカードがRead-Onlyになってしまうことがあります。
これを防ぐ方法がありましたら教えて下さい。

# 発生条件
Read-Onlyになる条件ですが、
コマンドを直接入力するような方法では発生せず、プログラムからファイル書き込みした場合に発生します。
ただ、ファイルパスも書き込み内容が同じであっても常に発生するわけではないようです。

正常→Read-Only発生時のメッセージが以下です。

FAT-fs (mmcblk0p1): error, fat_free_clusters: deleting FAT entry beyond EOF
FAT-fs (mmcblk0p1): Filesystem has been set read-only

# とりあえずの解決方法

また一度Read-OnlyになってしまったSDカードは再起動してもそのままなので、
起動時に常にfsck.vfatを呼ぶようにしました。

/etc/init.d/misc

#!/bin/sh
 
. /etc/init.d/functions
 
PATH=/bin:/sbin:/usr/bin:/usr/sbin
 
echo -n "Mounting ramfs /home/ftp/pub: "
mount -t ramfs ramfs /home/ftp/pub
chmod 0777 /home/ftp/pub
check_status
 
fsck.vfat -a /dev/mmcblk0p1
mount -a

すると、起動時に以下のようなメッセージが出るようになりました。

~~
Mounting ramfs /home/ftp/pub:                                   done
dosfsck 2.11, 12 Mar 2005, FAT32, LFN
Warning: FAT32 root dir is in a cluster chain, but a separate root dir
  area is defined. Cannot fix this easily.
There are differences between boot sector and its backup.
Differences: (offset:original/backup)
  0:eb/00, 2:90/00, 3:20/00, 4:20/00, 5:20/00, 6:20/00, 7:20/00, 8:20/00
  , 9:20/00, 10:20/00, 12:02/00, 13:40/00, 14:84/00, 15:18/00, 16:02/00
  , 21:f8/00, 24:3f/00, 26:80/00, 29:20/00, 33:d8/00, 34:77/00, 36:be/00
  , 37:03/00, 44:02/00, 48:01/00, 50:06/00, 64:80/00, 65:01/00, 66:29/00
  , 67:f8/00, 68:4e/00, 69:16/00, 70:90/00, 71:4e/00, 72:4f/00, 73:20/00
  , 74:4e/00, 75:41/00, 76:4d/00, 77:45/00, 78:20/00, 79:20/00, 80:20/00
  , 81:20/00, 82:46/00, 83:41/00, 84:54/00, 85:33/00, 86:32/00, 87:20/00
  , 88:20/00, 89:20/00, 318:00/55, 319:00/aa, 320:00/52, 321:00/52, 322:00/61
  , 323:00/41, 510:55/00, 511:aa/00
  Not automatically fixing this.
FSINFO sector has bad magic number(s):
  Offset 0: 0x0077d800 != expected 0x41615252
  Offset 484: 0x00000000 != expected 0x61417272
  Offset 510: 0x0000 != expected 0xaa55
  Auto-correcting it.
File syFAT-fs (mmcblk0p1): Volume was not properly unmounted. Some data may be corrupt. Please run fsck.
stem has 122591 clusters but only space for 7662 FAT entries.
Running local start script (/etc/config/rc.local).
~~

結果として、再起動後は書き込み可能になるのですが、「Cannot fix this easily.」といった内容が含まれているのが気になります。

# SDカード製品
SDカードはAF4GUD3A-OEM (4GB) を使用しています。
https://www.digikey.jp/product-detail/ja/atp-electronics-inc/AF4GUD3A-OEM/AF4GUD3A-OEM-ND/5361062

動作保証のある以下の製品 AF4GUDI とはわずかに型番が異なるのですが、同じ製品と考えてよいのでしょうか。
https://armadillo.atmark-techno.com/node/2035

製品: 
Armadillo-440

佐藤です。

下記の投稿でもありますが、SDカード自体の寿命の可能性があります。
https://users.atmark-techno.com/comment/1944#comment-1944

SD使用時の書き換え頻度はどれくらいでしょうか。

回答ありがとうございます。

> SD使用時の書き換え頻度はどれくらいでしょうか。
起動してから数十秒後に1回まとめて書き込きます。
以降は操作頻度によりますが、最大で2分に1回ほどです。
1回の書き込みで6ファイルほどを連続で書き込みます。

ファイル書き込み部分のコードは以下です。

int write_text_to_file(const char *filepath, const char *str, bool isAdd)
{
  //書き込み先のディレクトリがなければ作る
  make_directories(filepath);
 
  //指定したファイルをオープン、書き込み、クローズする
  FILE *pfile = fopen(filepath, isAdd ? "a" : "w");
  if (!pfile)
    exitfail_errno(nameof(fopen));
 
  int len = fprintf(pfile, str);
  if (len < 0)
    exitfail_errno(nameof(fprintf));
 
  fclose(pfile);
 
  return len;
}

佐藤です。

お使いの SDカードの書き換え回数の上限を仮に4万回とすると、理想的な環境下でも 4GB * 40000 = 160TB で寿命になるかと思います。
このようになっているようであれば、SDカード自体を交換したほうが良いかもしれません。
SDカードの選定ポイントについては以下が参考になるかと思います。
https://users.atmark-techno.com/comment/reply/4154/7613

すいません、書き忘れていたのですが、
SDカードは新品で100回も書いていないので、寿命ということはないと思います。
また複数のSDカードで同じ現象を確認していますので、個体差ということも無いと思います。

1回の書き込み内容も1000文字(≒1KB)以下のJSONファイルなので、多くはないです。

よろしくおねがいします。

佐藤です。

ファイルの書き込み中に、A440 の電源を落としている可能性はありませんでしょうか。
先のプログラムでいうと、fclose() を呼ぶ前です。

> ファイルの書き込み中に、A440 の電源を落としている可能性はありませんでしょうか。
> 先のプログラムでいうと、fclose() を呼ぶ前です。

その可能性はないと思います。
というのもターミナルでログインしながら操作していますので、
エラーが発生した後も、引き続きターミナルから操作はできます。

あと、思いついたのですが、
Linux全体の電源電圧は落ちていないが、SDカード部分のみ瞬間的に電源電圧が下がる、ということは発生するのでしょうか?

佐藤です。

> コマンドを直接入力するような方法では発生せず、プログラムからファイル書き込みした場合に発生します。
とのことですので、先に挙げられているプログラムに不具合があるのかもしれません。
fclose() の前に fflush() と fsync() をすると改善されないでしょうか。

    fflush(pfile);
    fsync(fileno(pfile));
    fclose(pfile);
 
    return len;
}

> fclose() の前に fflush() と fsync() をすると改善されないでしょうか。

やってみます。