AP_Logger: stale FAT32 FSINFO free-cluster count silently disables all SD card logging
Summary
A FAT32 SD card whose FSINFO free-cluster count has gone stale after an unclean power-off is reported as "out of space" by f_getfree() even though the card is nearly empty. AP_Logger_File then refuses to create any new log and stops any log in progress. The card reads as perfectly healthy on a PC, so the condition is invisible to the operator.
Environment
ArduCopter 4.6.2, CUAV X7. 16 GB microSD, FAT32, 32 KiB clusters, 497 MB used of 14.83 GB.
What happened
Logging stopped mid-session and no further logs were ever created. LASTLOG.TXT still held the last successful log number. Windows reported 14.34 GB free, and a read-only chkdsk found only a few lost cluster chains — nothing that explains a total logging failure.
Reading the volume's raw sectors showed the cause:
FSINFO, sector 1 (primary) Free_Count = 255 clusters -> 8,355,840 bytes
FSINFO, sector 7 (backup) Free_Count = 0xFFFFFFFF -> "unknown"
Free clusters counted by walking the FAT itself: 470,040 -> 14.34 GiBThe backup FSINFO still holds its pristine post-format state, since neither FatFs nor Windows maintains it. Only the primary is updated, and it holds a wrong value.
Why this disables logging
libraries/AP_HAL_ChibiOS/hwdef/common/ffconf.h:
#define FF_FS_NOFSINFO 0With bit 0 clear, FatFs trusts the FSINFO free-cluster count and never scans the FAT. Its only validation is that the value does not exceed the total cluster count, so a value that is too small is accepted silently. f_getfree() therefore returns 8,355,840 bytes.
libraries/AP_Logger/AP_Logger_File.h:
static constexpr uint32_t _free_space_min_avail = 8388608; // byteslibraries/AP_Logger/AP_Logger_File.cpp, in both start_new_log() and io_timer():
if (disk_space_avail() < _free_space_min_avail && disk_space() > 0) {
DEV_PRINTF("Out of space for logging\n");
...
}8,355,840 < 8,388,608The card misses the threshold by 32,768 bytes, exactly one cluster. Two consequences worth noting:
- The threshold is a hardcoded constant, so
LOG_FILE_MB_FREEhas no effect on it. - The same check runs in
io_timer()once per second, so a log already in progress is stopped as well, not just refused at creation.
Suggested fix
#define FF_FS_NOFSINFO 1Bit 0 makes f_getfree() force a full FAT scan on the first call after mount, which is the remedy the FatFs author documents for precisely this failure: http://elm-chan.org/fsw/ff/doc/config.html
The cost is one FAT scan per mount. Setting the value to 3 would additionally stop trusting the last-allocated-cluster hint, which on this card also pointed into allocated space (Nxt_Free = 237).
Why this may be worth fixing
Reformatting cures it, and that is the advice these reports normally receive, so the underlying cause is never identified. Possibly related: #13144, #16834, and a long tail of "PreArm: Logging failed" forum threads in which the card checks out fine on a PC.
Source: ArduPilot/ardupilot