fix(FrFTL): correct flash page state tracking to prevent unnecessary wear and improve error handling (#7584)
This commit is contained in:
+35
-15
@@ -159,6 +159,11 @@ static PhysicalPageState getPhysicalPageState(FrFTL* ftl,
|
||||
static void setPhysicalPageState(FrFTL* ftl, uint16_t physicalPageNo,
|
||||
PhysicalPageState state)
|
||||
{
|
||||
if (state == ERASE_REQUIRED) {
|
||||
if (ftl->callbacks->isFlashErased(physicalPageNo * PAGE_SIZE)) {
|
||||
state = ERASED;
|
||||
}
|
||||
}
|
||||
uint32_t idx = physicalPageNo >> 4;
|
||||
uint32_t mask = 0x3 << ((physicalPageNo & 0xf) * 2);
|
||||
ftl->physicalPageState[idx] &= ~mask;
|
||||
@@ -166,7 +171,6 @@ static void setPhysicalPageState(FrFTL* ftl, uint16_t physicalPageNo,
|
||||
((state & 0x3) << ((physicalPageNo & 0xf) * 2));
|
||||
}
|
||||
|
||||
|
||||
static const uint16_t crc16_ccitt_start = 0xFFFF;
|
||||
|
||||
static inline uint16_t crc16_x25_ccitt(const void* buf, uint32_t len) {
|
||||
@@ -188,12 +192,10 @@ static void resolveUnknownState(FrFTL* ftl, uint16_t count)
|
||||
uint16_t idx = ftl->writeFrontier;
|
||||
bool earlyEnd = false;
|
||||
|
||||
const FrFTLOps* cb = ftl->callbacks;
|
||||
for (uint16_t i = 0; i < ftl->physicalPageCount; i++) {
|
||||
if (getPhysicalPageState(ftl, idx) == UNKNOWN) {
|
||||
PhysicalPageState state =
|
||||
cb->isFlashErased(idx * PAGE_SIZE) ? ERASED : ERASE_REQUIRED;
|
||||
setPhysicalPageState(ftl, idx, state);
|
||||
// Will detect automatically whether a erase is really required
|
||||
setPhysicalPageState(ftl, idx, ERASE_REQUIRED);
|
||||
count--;
|
||||
if (count == 0) {
|
||||
earlyEnd = true;
|
||||
@@ -549,10 +551,10 @@ static bool quickErase(FrFTL* ftl, uint32_t addr)
|
||||
{
|
||||
|
||||
const FrFTLOps* cb = ftl->callbacks;
|
||||
uint16_t ppn = addr / PAGE_SIZE;
|
||||
if ((addr & BLOCK_MASK) == 0) {
|
||||
// Block aligned
|
||||
|
||||
uint16_t ppn = addr / PAGE_SIZE;
|
||||
uint8_t count = 0;
|
||||
bool hasUsed = false;
|
||||
|
||||
@@ -578,7 +580,11 @@ static bool quickErase(FrFTL* ftl, uint32_t addr)
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
return cb->flashErase(addr);
|
||||
if (cb->flashErase(addr)) {
|
||||
setPhysicalPageState(ftl, ppn, ERASED);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
static bool programPage(FrFTL* ftl, PageBuffer* buffer, bool doErase)
|
||||
@@ -691,11 +697,17 @@ static bool lockTTPages(FrFTL* ftl, uint16_t logicalPageNo)
|
||||
}
|
||||
ttBuffer =
|
||||
loadPhysicalPageInBuffer(ftl, ttPageNo, ttPageInfo.physicalPageNo);
|
||||
if (!ttBuffer) {
|
||||
return false;
|
||||
}
|
||||
ttBuffer->lock = LOCKED;
|
||||
ttBuffer->pMode = RELOCATE_ERASE_PROGRAM;
|
||||
if (ttPageNo > 0) {
|
||||
// TT page not MTT page, need to lock MTT page as well
|
||||
ttBuffer = loadPhysicalPageInBuffer(ftl, 0, ftl->mttPhysicalPageNo);
|
||||
if (!ttBuffer) {
|
||||
return false;
|
||||
}
|
||||
ttBuffer->lock = LOCKED;
|
||||
ttBuffer->pMode = RELOCATE_ERASE_PROGRAM;
|
||||
}
|
||||
@@ -777,8 +789,9 @@ bool ftlSync(FrFTL* ftl)
|
||||
bool ftlWrite(FrFTL* ftl, uint32_t startSectorNo, uint32_t noOfSectors,
|
||||
const uint8_t* buf)
|
||||
{
|
||||
resolveUnknownState(ftl, ftl->ttPageCount);
|
||||
if (startSectorNo + noOfSectors > ftl->usableSectorCount) {
|
||||
resolveUnknownState(ftl, ftl->ttPageCount > 16 ? ftl->ttPageCount : 16);
|
||||
if (startSectorNo > ftl->usableSectorCount ||
|
||||
noOfSectors > ftl->usableSectorCount - startSectorNo) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -798,7 +811,9 @@ bool ftlWrite(FrFTL* ftl, uint32_t startSectorNo, uint32_t noOfSectors,
|
||||
|
||||
// Read page info
|
||||
PageInfo pageInfo;
|
||||
readPageInfo(ftl, &pageInfo, logicalPageNo);
|
||||
if (!readPageInfo(ftl, &pageInfo, logicalPageNo)) {
|
||||
return false;
|
||||
}
|
||||
PageBuffer* dataBuffer;
|
||||
|
||||
// Allocate new physical page for uninitialized logical page
|
||||
@@ -867,7 +882,6 @@ bool ftlWrite(FrFTL* ftl, uint32_t startSectorNo, uint32_t noOfSectors,
|
||||
|
||||
bool ftlRead(FrFTL* ftl, uint32_t sectorNo, uint8_t* buffer)
|
||||
{
|
||||
// doGC(ftl, ftl->ttPageCount, 1);
|
||||
if (sectorNo >= ftl->usableSectorCount) {
|
||||
return false;
|
||||
}
|
||||
@@ -877,7 +891,9 @@ bool ftlRead(FrFTL* ftl, uint32_t sectorNo, uint8_t* buffer)
|
||||
|
||||
// Read page info
|
||||
PageInfo pageInfo;
|
||||
readPageInfo(ftl, &pageInfo, logicalPageNo);
|
||||
if (!readPageInfo(ftl, &pageInfo, logicalPageNo)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Check if sector written before
|
||||
uint8_t sectMask = 1 << pageSectorNo;
|
||||
@@ -893,8 +909,9 @@ bool ftlRead(FrFTL* ftl, uint32_t sectorNo, uint8_t* buffer)
|
||||
|
||||
bool ftlTrim(FrFTL* ftl, uint32_t startSectorNo, uint32_t noOfSectors)
|
||||
{
|
||||
resolveUnknownState(ftl, ftl->ttPageCount);
|
||||
if (startSectorNo + noOfSectors > ftl->usableSectorCount) {
|
||||
resolveUnknownState(ftl, ftl->ttPageCount > 16 ? ftl->ttPageCount : 16);
|
||||
if (startSectorNo > ftl->usableSectorCount ||
|
||||
noOfSectors > ftl->usableSectorCount - startSectorNo) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -914,7 +931,9 @@ bool ftlTrim(FrFTL* ftl, uint32_t startSectorNo, uint32_t noOfSectors)
|
||||
|
||||
// Read page info
|
||||
PageInfo pageInfo;
|
||||
readPageInfo(ftl, &pageInfo, logicalPageNo);
|
||||
if (!readPageInfo(ftl, &pageInfo, logicalPageNo)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Check if physical page in used
|
||||
if (pageInfo.physicalPageNo != 0xffff) {
|
||||
@@ -1184,6 +1203,7 @@ bool ftlInit(FrFTL* ftl, const FrFTLOps* cb, uint16_t flashSizeInMB)
|
||||
memset(ftl->physicalPageState, 0, stateSize * sizeof(uint32_t));
|
||||
createFTL(ftl);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user