bool FS::readHeaders()

in libs/storage/SNORFS.cpp [328:423]


bool FS::readHeaders()
{
    memset(rowRemapCache, 0xff, numRows);

    static BlockHeader hd; // can't be on stack!
    int freeRow = -1;
    bool freeDirty = false;
    bool freeRandom = false;

    int minEraseIdx = -1;
    uint32_t minEraseCnt = 0;
    uint32_t freeEraseCnt = 0;
    uint32_t totalEraseCount = 0;

    for (unsigned i = 0; i < (unsigned)numRows + 1; ++i)
    {
        auto addr = i * SPIFLASH_BIG_ROW_SIZE;
        flash.readBytes(addr, &hd, sizeof(hd));
        if (hd.magic != SNORFS_MAGIC || hd.version != 0)
        {
            // likely, we got a power failure during row erase - it now contains random data
            if (freeRow == -1)
            {
                freeDirty = true;
                freeRandom = true;
                freeRow = i;
                continue;
            }
            return false;
        }

        numMetaRows = hd.numMetaRows;

        totalEraseCount += hd.eraseCount;

        if (hd.logicalBlockId == 0xffff || hd.copiedFlag != SNORFS_COPIED_FLAG)
            goto isFree;
        else
        {
            if (hd.logicalBlockId >= numRows)
                return false;
            // if this is the first duplicate, it is liekly a duplicate left over from unfinished
            // swapRow
            if (rowRemapCache[hd.logicalBlockId] != 0xff)
                goto isFree;
            rowRemapCache[hd.logicalBlockId] = i;
            if (minEraseIdx < 0 || hd.eraseCount < minEraseCnt)
            {
                minEraseCnt = hd.eraseCount;
                minEraseIdx = i;
            }
        }
        continue;

    isFree:
        if (freeRow == -1)
        {
            freeRow = i;
            if (hd.freeFlag != SNORFS_FREE_FLAG)
                freeDirty = true;
        }
        else
            return false;
        freeEraseCnt = hd.eraseCount;
    }

    feedRandom(totalEraseCount);

    this->freeRow = freeRow;

    if (freeRow == -1 || !numMetaRows || numMetaRows > numRows / 2)
        return false;

    if (freeDirty)
    {
        LOG("fixing free row: %d\n", freeRow);
        busy();
        initBlockHeader(hd, true);
        hd.eraseCount = freeRandom ? totalEraseCount / numRows : freeEraseCnt;
        flash.eraseBigRow(freeRow * SPIFLASH_BIG_ROW_SIZE);
        busy();
        flash.writeBytes(freeRow * SPIFLASH_BIG_ROW_SIZE, &hd, sizeof(hd));
        busy(false);
    }
    else if (minEraseCnt + SNORFS_LEVELING_THRESHOLD < freeEraseCnt)
    {
        swapRow(minEraseIdx);
        LOGV(" for level\n");
    }
    else
    {
        LOGV("[no level swap: free %d, min %d]", freeEraseCnt, minEraseCnt);
    }

    return true;
}