Skip to content

Commit

Permalink
Reboot before formatting LittleFS (meshtastic#5900)
Browse files Browse the repository at this point in the history
Co-authored-by: Ben Meadors <[email protected]>
  • Loading branch information
esev and thebentern authored Jan 20, 2025
1 parent 0f98115 commit c4fcbad
Show file tree
Hide file tree
Showing 4 changed files with 61 additions and 31 deletions.
29 changes: 8 additions & 21 deletions src/FSCommon.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -49,24 +49,6 @@ void OSFS::writeNBytes(uint16_t address, unsigned int num, const byte *input)
}
#endif

bool lfs_assert_failed =
false; // Note: we use this global on all platforms, though it can only be set true on nrf52 (in our modified lfs_util.h)

extern "C" void lfs_assert(const char *reason)
{
LOG_ERROR("LFS assert: %s", reason);
lfs_assert_failed = true;

#ifndef ARCH_PORTDUINO
#ifdef FSCom
// CORRUPTED FILESYSTEM. This causes bootloop so
// might as well try formatting now.
LOG_ERROR("Trying FSCom.format()");
FSCom.format();
#endif
#endif
}

/**
* @brief Copies a file from one location to another.
*
Expand Down Expand Up @@ -348,10 +330,16 @@ void rmDir(const char *dirname)
#endif
}

/**
* Some platforms (nrf52) might need to do an extra step before FSBegin().
*/
__attribute__((weak, noinline)) void preFSBegin() {}

void fsInit()
{
#ifdef FSCom
spiLock->lock();
concurrency::LockGuard g(spiLock);
preFSBegin();
if (!FSBegin()) {
LOG_ERROR("Filesystem mount failed");
// assert(0); This auto-formats the partition, so no need to fail here.
Expand All @@ -362,7 +350,6 @@ void fsInit()
LOG_DEBUG("Filesystem files:");
#endif
listDir("/", 10);
spiLock->unlock();
#endif
}

Expand Down Expand Up @@ -400,4 +387,4 @@ void setupSDCard()
LOG_DEBUG("Total space: %lu MB", (uint32_t)(SD.totalBytes() / (1024 * 1024)));
LOG_DEBUG("Used space: %lu MB", (uint32_t)(SD.usedBytes() / (1024 * 1024)));
#endif
}
}
5 changes: 1 addition & 4 deletions src/FSCommon.h
Original file line number Diff line number Diff line change
Expand Up @@ -57,7 +57,4 @@ bool renameFile(const char *pathFrom, const char *pathTo);
std::vector<meshtastic_FileInfo> getFiles(const char *dirname, uint8_t levels);
void listDir(const char *dirname, uint8_t levels, bool del = false);
void rmDir(const char *dirname);
void setupSDCard();

extern bool lfs_assert_failed; // Note: we use this global on all platforms, though it can only be set true on nrf52 (in our
// modified lfs_util.h)
void setupSDCard();
6 changes: 1 addition & 5 deletions src/SafeFile.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,6 @@ static File openFile(const char *filename, bool fullAtomic)
concurrency::LockGuard g(spiLock);
LOG_DEBUG("Opening %s, fullAtomic=%d", filename, fullAtomic);
#ifdef ARCH_NRF52
lfs_assert_failed = false;
File file = FSCom.open(filename, FILE_O_WRITE);
file.seek(0);
return file;
Expand All @@ -20,7 +19,6 @@ static File openFile(const char *filename, bool fullAtomic)
filenameTmp += ".tmp";

// clear any previous LFS errors
lfs_assert_failed = false;
return FSCom.open(filenameTmp.c_str(), FILE_O_WRITE);
}

Expand Down Expand Up @@ -96,8 +94,6 @@ bool SafeFile::close()
bool SafeFile::testReadback()
{
concurrency::LockGuard g(spiLock);
bool lfs_failed = lfs_assert_failed;
lfs_assert_failed = false;

String filenameTmp = filename;
filenameTmp += ".tmp";
Expand All @@ -119,7 +115,7 @@ bool SafeFile::testReadback()
return false;
}

return !lfs_failed;
return true;
}

#endif
52 changes: 51 additions & 1 deletion src/platform/nrf52/main-nrf52.cpp
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
#include "configuration.h"
#include <Adafruit_TinyUSB.h>
#include <Adafruit_nRFCrypto.h>
#include <InternalFileSystem.h>
#include <SPI.h>
#include <Wire.h>
#include <assert.h>
Expand Down Expand Up @@ -130,6 +131,54 @@ int printf(const char *fmt, ...)
return res;
}

namespace
{
constexpr uint8_t NRF52_MAGIC_LFS_IS_CORRUPT = 0xF5;
constexpr uint32_t MULTIPLE_CORRUPTION_DELAY_MILLIS = 20 * 60 * 1000;
static unsigned long millis_until_formatting_again = 0;

// Report the critical error from loop(), giving a chance for the screen to be initialized first.
inline void reportLittleFSCorruptionOnce()
{
static bool report_corruption = !!millis_until_formatting_again;
if (report_corruption) {
report_corruption = false;
RECORD_CRITICALERROR(meshtastic_CriticalErrorCode_FLASH_CORRUPTION_UNRECOVERABLE);
}
}
} // namespace

void preFSBegin()
{
// The GPREGRET register keeps its value across warm boots. Check that this is a warm boot and, if GPREGRET
// is set to NRF52_MAGIC_LFS_IS_CORRUPT, format LittleFS.
if (!(NRF_POWER->RESETREAS == 0 && NRF_POWER->GPREGRET == NRF52_MAGIC_LFS_IS_CORRUPT))
return;
NRF_POWER->GPREGRET = 0;
millis_until_formatting_again = millis() + MULTIPLE_CORRUPTION_DELAY_MILLIS;
InternalFS.format();
LOG_INFO("LittleFS format complete; restoring default settings");
}

extern "C" void lfs_assert(const char *reason)
{
LOG_ERROR("LittleFS corruption detected: %s", reason);
if (millis_until_formatting_again > millis()) {
RECORD_CRITICALERROR(meshtastic_CriticalErrorCode_FLASH_CORRUPTION_UNRECOVERABLE);
const long millis_remain = millis_until_formatting_again - millis();
LOG_WARN("Pausing %d seconds to avoid wear on flash storage", millis_remain / 1000);
delay(millis_remain);
}
LOG_INFO("Rebooting to format LittleFS");
delay(500); // Give the serial port a bit of time to output that last message.
// Try setting GPREGRET with the SoftDevice first. If that fails (perhaps because the SD hasn't been initialize yet) then set
// NRF_POWER->GPREGRET directly.
if (!(sd_power_gpregret_clr(0, 0xFF) == NRF_SUCCESS && sd_power_gpregret_set(0, NRF52_MAGIC_LFS_IS_CORRUPT) == NRF_SUCCESS)) {
NRF_POWER->GPREGRET = NRF52_MAGIC_LFS_IS_CORRUPT;
}
NVIC_SystemReset();
}

void checkSDEvents()
{
if (useSoftDevice) {
Expand All @@ -154,6 +203,7 @@ void checkSDEvents()
void nrf52Loop()
{
checkSDEvents();
reportLittleFSCorruptionOnce();
}

#ifdef USE_SEMIHOSTING
Expand Down Expand Up @@ -309,4 +359,4 @@ void enterDfuMode()
#else
enterUf2Dfu();
#endif
}
}

0 comments on commit c4fcbad

Please sign in to comment.