mirror of
https://github.com/espressif/openthread.git
synced 2026-08-09 20:27:47 +00:00
[flash] improve power failure robustness (#4717)
This commit improves the flash implementation robustness to power failure. The idea is the following: The Init method now checks if a record has been partially written by seeing if the kFlagAddBegin flag is set, but the kFlagComplete flag is not. In this case, Init stops incrementing mSwapUsed. The new SanitizeFreeSpace method checks the (supposedly) free space, to see if it is writeable. If it isn't, it triggers a Swap, which sanitizes the flash area.
This commit is contained in:
@@ -69,18 +69,54 @@ void Flash::Init(void)
|
||||
for (mSwapUsed = kSwapMarkerSize; mSwapUsed <= mSwapSize - sizeof(record); mSwapUsed += record.GetSize())
|
||||
{
|
||||
otPlatFlashRead(&GetInstance(), mSwapIndex, mSwapUsed, &record, sizeof(record));
|
||||
VerifyOrExit(record.IsAddBeginSet());
|
||||
if (!record.IsAddBeginSet())
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
if (!record.IsAddCompleteSet())
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
SanitizeFreeSpace();
|
||||
|
||||
exit:
|
||||
return;
|
||||
}
|
||||
|
||||
void Flash::SanitizeFreeSpace(void)
|
||||
{
|
||||
uint32_t temp;
|
||||
bool sanitizeNeeded = false;
|
||||
|
||||
if (mSwapUsed & 3)
|
||||
{
|
||||
ExitNow(sanitizeNeeded = true);
|
||||
}
|
||||
|
||||
for (uint32_t offset = mSwapUsed; offset < mSwapSize; offset += sizeof(temp))
|
||||
{
|
||||
otPlatFlashRead(&GetInstance(), mSwapIndex, offset, &temp, sizeof(temp));
|
||||
if (temp != ~0U)
|
||||
{
|
||||
ExitNow(sanitizeNeeded = true);
|
||||
}
|
||||
}
|
||||
|
||||
exit:
|
||||
if (sanitizeNeeded)
|
||||
{
|
||||
Swap();
|
||||
}
|
||||
}
|
||||
|
||||
otError Flash::Get(uint16_t aKey, int aIndex, uint8_t *aValue, uint16_t *aValueLength) const
|
||||
{
|
||||
otError error = OT_ERROR_NOT_FOUND;
|
||||
uint16_t valueLength = 0;
|
||||
int index = 0;
|
||||
int index = 0; // This must be initalized to 0. See [Note] in Delete().
|
||||
uint32_t offset;
|
||||
RecordHeader record;
|
||||
|
||||
@@ -147,6 +183,8 @@ otError Flash::Add(uint16_t aKey, bool aFirst, const uint8_t *aValue, uint16_t a
|
||||
record.Init(aKey, aFirst);
|
||||
record.SetData(aValue, aValueLength);
|
||||
|
||||
OT_ASSERT((mSwapSize - record.GetSize()) >= kSwapMarkerSize);
|
||||
|
||||
if ((mSwapSize - record.GetSize()) < mSwapUsed)
|
||||
{
|
||||
Swap();
|
||||
@@ -218,7 +256,7 @@ exit:
|
||||
otError Flash::Delete(uint16_t aKey, int aIndex)
|
||||
{
|
||||
otError error = OT_ERROR_NOT_FOUND;
|
||||
int index = 0;
|
||||
int index = 0; // This must be initalized to 0. See [Note] below.
|
||||
RecordHeader record;
|
||||
|
||||
for (uint32_t offset = kSwapMarkerSize; offset < mSwapUsed; offset += record.GetSize())
|
||||
@@ -242,6 +280,10 @@ otError Flash::Delete(uint16_t aKey, int aIndex)
|
||||
error = OT_ERROR_NONE;
|
||||
}
|
||||
|
||||
/* [Note] If the operation gets interrupted here and aIndex is 0, the next record (index == 1) will never get
|
||||
* marked as first. However, this is not actually an issue because all the methods that iterate over the
|
||||
* settings area initialize the index to 0, without expecting any record to be effectively marked as first. */
|
||||
|
||||
if ((index == 1) && (aIndex == 0))
|
||||
{
|
||||
record.SetFirst();
|
||||
|
||||
@@ -222,6 +222,7 @@ private:
|
||||
|
||||
otError Add(uint16_t aKey, bool aFirst, const uint8_t *aValue, uint16_t aValueLength);
|
||||
bool DoesValidRecordExist(uint32_t aOffset, uint16_t aKey) const;
|
||||
void SanitizeFreeSpace(void);
|
||||
void Swap(void);
|
||||
|
||||
uint32_t mSwapSize;
|
||||
|
||||
Reference in New Issue
Block a user