📄 ftllite.c
字号:
/* Place the logical mapping of the unit */ vol.mappedSectorNo = UNASSIGNED_SECTOR; vol.logicalUnits[logicalUnitNo] = unit; return flOK;}/*----------------------------------------------------------------------*//* a s s i g n U n i t *//* *//* Assigns a logical unit no. to a unit *//* *//* Parameters: *//* vol : Pointer identifying drive *//* unit : Unit to assign *//* *//* Returns: *//* FLStatus : 0 on success, failed otherwise *//*----------------------------------------------------------------------*/static FLStatus assignUnit(Flare vol, Unit *unit, UnitNo logicalUnitNo){ LEushort unitNoToWrite; toLE2(unitNoToWrite,logicalUnitNo); return flashWrite(&vol, physicalBase(&vol,unit) + logicalUnitNoOffset, &unitNoToWrite, sizeof unitNoToWrite, OVERWRITE);}/*----------------------------------------------------------------------*//* b e s t U n i t T o T r a n s f e r *//* *//* Find best candidate for unit transfer, usually on the basis of which *//* unit has the most garbage space. A lower wear-leveling info serves *//* as a tie-breaker. If 'leastUsed' is NOT specified, then the least *//* wear-leveling info is the only criterion. *//* *//* Parameters: *//* vol : Pointer identifying drive *//* leastUsed : Whether most garbage space is the criterion *//* *//* Returns: *//* Best unit to transfer *//*----------------------------------------------------------------------*/static UnitNo bestUnitToTransfer(Flare vol, FLBoolean leastUsed){ UnitNo i; int mostGarbageSectors = 1; unsigned long int leastWearLevelingInfo = 0xffffffffl; UnitNo bestUnitSoFar = UNASSIGNED_UNIT_NO; for(i = 0; i < vol.noOfUnits; i++) { Unit *unit = vol.logicalUnits[i]; if(unit && (!leastUsed || (unit->noOfGarbageSectors >= mostGarbageSectors))) { UnitHeader FAR0 *unitHeader = mapUnitHeader(&vol,unit,NULL); if((leastUsed && (unit->noOfGarbageSectors > mostGarbageSectors)) || (LE4(unitHeader->wearLevelingInfo) < leastWearLevelingInfo)) { mostGarbageSectors = unit->noOfGarbageSectors; leastWearLevelingInfo = LE4(unitHeader->wearLevelingInfo); bestUnitSoFar = i; } } } return bestUnitSoFar;}/*----------------------------------------------------------------------*//* u n i t T r a n s f e r *//* *//* Performs a unit transfer from a selected unit to a tranfer unit. *//* *//* A side effect is to invalidate the map cache (reused as buffer). *//* *//* Parameters: *//* vol : Pointer identifying drive *//* toUnit : Target transfer unit *//* fromUnitNo: : Source logical unit no. *//* *//* Returns: *//* FLStatus : 0 on success, failed otherwise *//*----------------------------------------------------------------------*/static FLStatus unitTransfer(Flare vol, Unit *toUnit, UnitNo fromUnitNo){ unsigned i; Unit *fromUnit = vol.logicalUnits[fromUnitNo]; UnitHeader FAR0 *transferUnitHeader = mapUnitHeader(&vol,toUnit,NULL); if(!verifyFormat(transferUnitHeader) || LE2(transferUnitHeader->logicalUnitNo) != UNASSIGNED_UNIT_NO) /* previous formatting failed or did not complete. */ checkStatus(formatUnit(&vol,toUnit)); /* Should the transfer not complete, the unit is marked to be erased */ checkStatus(assignUnit(&vol,toUnit,MARKED_FOR_ERASE));#ifdef BACKGROUND vol.mirrorFrom = vol.mirrorTo = physicalBase(&vol,fromUnit); vol.mirrorOffset = physicalBase(&vol,toUnit) - vol.mirrorFrom;#endif /* copy the block allocation table and the good sectors */ for(i = 0; i < vol.sectorsPerUnit;) { int j; FLBoolean needToWrite = FALSE; int firstOffset = allocEntryOffset(&vol,i); /* Up to 128 bytes of the BAM are processed per loop */ int nEntries = (128 - (firstOffset & 127)) / sizeof(VirtualAddress); /* We are going to use the Virtual Map cache as our sector buffer in the */ /* transfer, so let's better invalidate the cache first. */#ifdef SINGLE_BUFFER if (buffer.dirty) return flBufferingError;#endif buffer.sectorNo = UNASSIGNED_SECTOR; /* Read some of the BAM */ vol.flash.read(&vol.flash, physicalBase(&vol,fromUnit) + firstOffset, sectorCopy, nEntries * sizeof(VirtualAddress), 0); /* Convert garbage entries to free entries */ for(j = 0; j < nEntries && i+j < vol.sectorsPerUnit; j++) { unsigned bamSignature = (unsigned) LE4(sectorCopy[j]) & SECTOR_OFFSET_MASK; if (bamSignature == DATA_SECTOR || bamSignature == REPLACEMENT_PAGE) needToWrite = TRUE; else if (bamSignature != FORMAT_SECTOR) toLE4(sectorCopy[j],FREE_SECTOR); } if(needToWrite) { FLStatus status; /* Write new BAM, and copy sectors that need to be copied */ status = flashWrite(&vol, physicalBase(&vol,toUnit) + firstOffset, sectorCopy, nEntries * sizeof(VirtualAddress), 0); if(status != flOK) {#ifdef BACKGROUND vol.mirrorOffset = 0; /* no more mirroring */#endif return status; } for(j = 0; j < nEntries && i+j < vol.sectorsPerUnit; j++) { unsigned bamSignature = (unsigned) LE4(sectorCopy[j]) & SECTOR_OFFSET_MASK; if(bamSignature == DATA_SECTOR || bamSignature == REPLACEMENT_PAGE) { /* a good sector */ CardAddress sectorOffset = (CardAddress) (i+j) << SECTOR_SIZE_BITS; vol.flash.read(&vol.flash, physicalBase(&vol,fromUnit) + sectorOffset, sectorCopy,SECTOR_SIZE,0); status = flashWrite(&vol, physicalBase(&vol,toUnit) + sectorOffset, sectorCopy, SECTOR_SIZE, 0); if(status != flOK) {#ifdef BACKGROUND vol.mirrorOffset = 0; /* no more mirroring */#endif return status; } vol.flash.read(&vol.flash, physicalBase(&vol,fromUnit) + firstOffset, sectorCopy, nEntries * sizeof(VirtualAddress),0); } }#ifdef BACKGROUND vol.mirrorTo = vol.mirrorFrom + ((CardAddress) (i + nEntries) << SECTOR_SIZE_BITS); while (flForeground(1) == BG_SUSPEND) ;#endif } i += nEntries; }#ifdef BACKGROUND vol.mirrorOffset = 0; /* no more mirroring */#endif /* Write the new logical unit no. */ checkStatus(assignUnit(&vol,toUnit,fromUnitNo)); /* Mount the new unit in place of old one */ vol.logicalUnits[fromUnitNo] = NULL; if(mountUnit(&vol,toUnit) == flOK) { vol.totalFreeSectors -= fromUnit->noOfFreeSectors; /* Finally, format the source unit (the new transfer unit) */ vol.transferUnit = fromUnit; formatUnit(&vol,fromUnit); /* nothing we can or should do if this fails */ } else { /* Something went wrong */ vol.logicalUnits[fromUnitNo] = fromUnit; /* reinstate original unit */ /* to avoid corruption, need to erase the failed toUnit. EAN. */ dbgMsg(DEBUG_LIGHT,"unitTransfer: mountUnit() failed. invalidating toUnit %x.\n",(int) toUnit,0,0,0,0,0); invalidateFormat(&vol,toUnit); return flGeneralFailure; } return flOK;}/*----------------------------------------------------------------------*//* g a r b a g e C o l l e c t *//* *//* Performs a unit transfer, selecting a unit to transfer and a *//* transfer unit. *//* *//* Parameters: *//* vol : Pointer identifying drive *//* *//* Returns: *//* FLStatus : 0 on success, failed otherwise *//*----------------------------------------------------------------------*/static FLStatus garbageCollect(Flare vol){ FLStatus status; UnitNo fromUnitNo; if (vol.transferUnit == NULL) return flWriteProtect; /* Cannot recover space without a spare unit */ fromUnitNo = bestUnitToTransfer(&vol,flRandByte() >= 4); if (fromUnitNo == UNASSIGNED_UNIT_NO) return flGeneralFailure; /* nothing to collect */ /* Find a unit we can transfer to. */ status = unitTransfer(&vol,vol.transferUnit,fromUnitNo); if(status == flWriteFault) { int i; Unit *unit = vol.physicalUnits; for(i = 0; i < vol.noOfUnits; i++, unit++) { if(unit->noOfGarbageSectors == 0 && unit->noOfFreeSectors < 0) { if(unitTransfer(&vol,unit,fromUnitNo) == flOK) return flOK; /* found a good one */ } } } return status;}#ifdef BACKGROUND/*----------------------------------------------------------------------*//* b g G a r b a g e C o l l e c t *//* *//* Entry point for garbage collection in the background. *//* *//* Status is returned in vol.garbageCollectStatus *//* *//* Parameters: *//* vol : Pointer identifying drive *//* *//* Returns: *//* None *//*----------------------------------------------------------------------*/static void bgGarbageCollect(void * object){ Flare vol = (Flare *)object; vol.garbageCollectStatus = flIncomplete; vol.garbageCollectStatus = garbageCollect(&vol);}#endif/*----------------------------------------------------------------------*//* d e f r a g m e n t *//* *//* Performs unit transfers to arrange a minimum number of writable *//* sectors. *//* *//* Parameters: *//* vol : Pointer identifying drive *//* sectorsNeeded : Minimum required sectors *//* *//* Returns: *//* FLStatus : 0 on success, failed otherwise *//*----------------------------------------------------------------------*/#define GARBAGE_COLLECT_THRESHOLD 20static FLStatus defragment(Flare vol, long FAR2 *sectorsNeeded){ while((long)(vol.totalFreeSectors) < *sectorsNeeded#ifdef BACKGROUND || vol.totalFreeSectors < GARBAGE_COLLECT_THRESHOLD#endif ) { if(vol.badFormat) return flBadFormat;#ifdef BACKGROUND if (vol.garbageCollectStatus == flIncomplete) flBackground(BG_RESUME); else flStartBackground(&vol - vols,bgGarbageCollect,&vol); if (vol.garbageCollectStatus != flOK && vol.garbageCollectStatus != flIncomplete) return vol.garbageCollectStatus; if (vol.totalFreeSectors >= *sectorsNeeded) break; } if (vol.unitEraseInProgress) flBackground(BG_SUSPEND);#else /* if no more units to reclaim, bail out. ALR */ if (flOK != garbageCollect(&vol)) break; }#endif *sectorsNeeded = vol.totalFreeSectors; return flOK;}/*----------------------------------------------------------------------*//* b e s t U n i t T o A l l o c a t e *//* *//* Finds the best unit from which to allocate a sector. The unit */
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -