📄 ftllite.c
字号:
}
/*----------------------------------------------------------------------*/
/* 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 */
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 20
static 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
checkStatus(garbageCollect(&vol));
}
#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 */
/* selected is the one with most free space. */
/* */
/* Parameters: */
/* vol : Pointer identifying drive */
/* */
/* Returns: */
/* Best unit to allocate */
/*----------------------------------------------------------------------*/
static Unit *bestUnitToAllocate(Flare vol)
{
int i;
int mostFreeSectors = 0;
Unit *bestUnitSoFar = NULL;
for (i = 0; i < vol.noOfUnits; i++) {
Unit *unit = vol.logicalUnits[i];
if (unit && unit->noOfFreeSectors > mostFreeSectors) {
mostFreeSectors = unit->noOfFreeSectors;
bestUnitSoFar = unit;
}
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -