📄 ftllite.c
字号:
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 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 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; } } return bestUnitSoFar;}/*----------------------------------------------------------------------*//* f i n d F r e e S e c t o r *//* *//* The allocation strategy goes this way: *//* *//* We try to make consecutive virtual sectors physically consecutive if *//* possible. If not, we prefer to have consecutive sectors on the same *//* unit at least. If all else fails, a sector is allocated on the unit *//* with most space available. *//* *//* The object of this strategy is to cluster related data (e.g. a file *//* data) in one unit, and to distribute unrelated data evenly among all *//* units. *//* *//* Parameters: *//* vol : Pointer identifying drive *//* sectorNo : virtual sector no. that we want to allocate. *//* *//* Returns: *//* newAddress : Allocated logical sector no. *//* FLStatus : 0 on success, failed otherwise *//*----------------------------------------------------------------------*/static FLStatus findFreeSector(Flare vol, VirtualSectorNo sectorNo, LogicalSectorNo *newAddress)
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -