Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Reboot before formatting LittleFS #5900

Merged
merged 2 commits into from
Jan 20, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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
}
}
Loading