📄 ftllite.c
字号:
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)
{
unsigned iSector;
LEulong FAR0 *blockAllocMap;
UnitHeader FAR0 *unitHeader;
Unit *allocationUnit = NULL;
LogicalSectorNo previousSectorAddress =
sectorNo > 0 ? virtual2Logical(&vol,sectorNo - 1) : UNASSIGNED_SECTOR;
#ifdef DEBUG_PRINT
DEBUG_PRINT("Debug: findFreeSector -> %d !!\n", sectorNo);
#endif
if (previousSectorAddress != UNASSIGNED_SECTOR &&
previousSectorAddress != DELETED_SECTOR) {
allocationUnit =
vol.logicalUnits[previousSectorAddress >> (vol.unitSizeBits - SECTOR_SIZE_BITS)];
if (allocationUnit->noOfFreeSectors > 0) {
unsigned int sectorIndex = ((unsigned) previousSectorAddress & (vol.sectorsPerUnit - 1)) + 1;
LEulong FAR0 *nextSectorAddress =
(LEulong FAR0 *) vol.flash.map(&vol.flash,
physicalBase(&vol,allocationUnit) +
allocEntryOffset(&vol, sectorIndex),
sizeof(VirtualAddress));
if (sectorIndex < vol.sectorsPerUnit && LE4(*nextSectorAddress) == FREE_SECTOR) {
/* can write sequentially */
*newAddress = previousSectorAddress + 1;
return flOK;
}
}
else
allocationUnit = NULL; /* no space here, try elsewhere */
}
if (allocationUnit == NULL)
allocationUnit = bestUnitToAllocate(&vol);
if (allocationUnit == NULL) /* No ? then all is lost */ {
#ifdef DEBUG_PRINT
DEBUG_PRINT("Debug: findFreeSector -> Unable to find free sector!!\n");
#endif
return flGeneralFailure;
}
unitHeader = mapUnitHeader(&vol,allocationUnit,&blockAllocMap);
for (iSector = vol.unitHeaderSectors; iSector < vol.sectorsPerUnit; iSector++) {
if (LE4(blockAllocMap[iSector]) == FREE_SECTOR) {
*newAddress = ((LogicalSectorNo) (LE2(unitHeader->logicalUnitNo)) << (vol.unitSizeBits - SECTOR_SIZE_BITS)) +
iSector;
return flOK;
}
}
#ifdef DEBUG_PRINT
DEBUG_PRINT("Debug: findFreeSector -> Problem marking allocation map!!\n");
#endif
return flGeneralFailure; /* what are we doing here ? */
}
/*----------------------------------------------------------------------*/
/* m a r k A l l o c M a p */
/* */
/* Writes a new value to a BAM entry. */
/* */
/* This routine also updates the free & garbage sector counts. */
/* */
/* Parameters: */
/* vol : Pointer identifying drive */
/* sectorAddress : Logical sector no. whose BAM entry to mark */
/* allocMapEntry : New BAM entry value */
/* overwrite : Whether we are overwriting some old value */
/* */
/* Returns: */
/* FLStatus : 0 on success, failed otherwise */
/*----------------------------------------------------------------------*/
static FLStatus markAllocMap(Flare vol,
LogicalSectorNo sectorAddress,
VirtualAddress allocMapEntry,
FLBoolean overwrite)
{
UnitNo unitNo = (UnitNo) (sectorAddress >> (vol.unitSizeBits - SECTOR_SIZE_BITS));
Unit *unit = vol.logicalUnits[unitNo];
int sectorInUnit = (unsigned) sectorAddress & (vol.sectorsPerUnit - 1);
LEulong bamEntry;
if (unitNo >= vol.noOfUnits - vol.noOfTransferUnits)
return flGeneralFailure;
if (allocMapEntry == GARBAGE_SECTOR)
unit->noOfGarbageSectors++;
else if (!overwrite) {
unit->noOfFreeSectors--;
vol.totalFreeSectors--;
}
toLE4(bamEntry,allocMapEntry);
return flashWrite(&vol,
physicalBase(&vol,unit) + allocEntryOffset(&vol,sectorInUnit),
&bamEntry,
sizeof bamEntry,
overwrite);
}
/*----------------------------------------------------------------------*/
/* d e l e t e L o g i c a l S e c t o r */
/* */
/* Marks a logical sector as deleted. */
/* */
/* Parameters: */
/* vol : Pointer identifying drive */
/* sectorAddress : Logical sector no. to delete */
/* */
/* Returns: */
/* FLStatus : 0 on success, failed otherwise */
/*----------------------------------------------------------------------*/
static FLStatus deleteLogicalSector(Flare vol, LogicalSectorNo sectorAddress)
{
if (sectorAddress == UNASSIGNED_SECTOR ||
sectorAddress == DELETED_SECTOR)
return flOK;
return markAllocMap(&vol,sectorAddress,GARBAGE_SECTOR,TRUE);
}
/* forward definition */
static FLStatus setVirtualMap(Flare vol,
VirtualSectorNo sectorNo,
LogicalSectorNo newAddress);
/*----------------------------------------------------------------------*/
/* a l l o c a t e A n d W r i t e S e c t o r */
/* */
/* Allocates a sector or replacement page and (optionally) writes it. */
/* */
/* An allocated replacement page also becomes the active replacement */
/* page. */
/* */
/* Parameters: */
/* vol : Pointer identifying drive */
/* sectorNo : Virtual sector no. to write */
/* fromAddress : Address of sector data. If NULL, sector is */
/* not written. */
/* replacementPage : This is a replacement page sector. */
/* */
/* Returns: */
/* FLStatus : 0 on success, failed otherwise */
/*----------------------------------------------------------------------*/
static FLStatus allocateAndWriteSector(Flare vol,
VirtualSectorNo sectorNo,
void FAR1 *fromAddress,
FLBoolean replacementPage)
{
FLStatus status;
LogicalSectorNo sectorAddress;
VirtualAddress bamEntry =
((VirtualAddress) sectorNo - vol.noOfPages) << SECTOR_SIZE_BITS;
long sectorsNeeded = 1;
#ifdef DEBUG_PRINT
DEBUG_PRINT("Debug: calling defrgment routine!!\n");
#endif
checkStatus(defragment(&vol,§orsNeeded)); /* Organize a free sector */
#ifdef DEBUG_PRINT
DEBUG_PRINT("Debug: calling routine findFreeSector !!\n");
#endif
checkStatus(findFreeSector(&vol,sectorNo,§orAddress));
if (replacementPage)
bamEntry |= REPLACEMENT_PAGE;
else
bamEntry |= DATA_SECTOR;
status = markAllocMap(&vol,
sectorAddress,
sectorNo < vol.directAddressingSectors ?
ALLOCATED_SECTOR : bamEntry,
FALSE);
if (status == flOK && fromAddress)
status = flashWrite(&vol,
logical2Physical(&vol,sectorAddress),
fromAddress,
SECTOR_SIZE,
0);
if (sectorNo < vol.directAddressingSectors && status == flOK)
status = markAllocMap(&vol,
sectorAddress,
bamEntry,
TRUE);
if (status == flOK)
if (replacementPage) {
vol.replacementPageAddress = sectorAddress;
vol.replacementPageNo = sectorNo;
}
else
status = setVirtualMap(&vol,sectorNo,sectorAddress);
if (status != flOK)
status = markAllocMap(&vol,sectorAddress,GARBAGE_SECTOR,TRUE);
#ifdef DEBUG_PRINT
if (status != flOK)
DEBUG_PRINT("Debug: Bad status code at Allocate and Write sector !\n");
DEBUG_PRINT("Debug: MarkAllocMap returned %d !\n", status);
#endif
return status;
}
/*----------------------------------------------------------------------*/
/* c l o s e R e p l a c e m e n t P a g e */
/* */
/* Closes the replacement page by merging it with the primary page. */
/* */
/* Parameters: */
/* vol : Pointer identifying drive */
/* */
/* Returns: */
/* FLStatus : 0 on success, failed otherwise */
/*----------------------------------------------------------------------*/
static FLStatus closeReplacementPage(Flare vol)
{
FLStatus status;
#ifdef SINGLE_BUFFER
int i;
LogicalSectorNo nextReplacementPageAddress = vol.replacementPageAddress;
VirtualSectorNo firstSectorNo =
((VirtualSectorNo) vol.replacementPageNo << (PAGE_SIZE_BITS - SECTOR_SIZE_BITS)) +
vol.noOfPages;
pageRetry:
for (i = 0; i < ADDRESSES_PER_SECTOR; i++) {
LogicalSectorNo logicalSectorNo = virtual2Logical(&vol,firstSectorNo + i);
LEulong entryToWrite;
toLE4(entryToWrite,logicalSectorNo == UNASSIGNED_SECTOR ?
UNASSIGNED_ADDRESS :
(LogicalAddress) logicalSectorNo << SECTOR_SIZE_BITS);
if (flashWrite(&vol,
logical2Physical(&vol,nextReplacementPageAddress) +
i * sizeof(LogicalAddress),
&entryToWrite,
sizeof entryToWrite,
OVERWRITE) != flOK)
break;
}
if (i < ADDRESSES_PER_SECTOR &&
nextReplacementPageAddress == vol.replacementPageAddress) {
/* Uh oh. Trouble. Let's replace this replacement page. */
LogicalSectorNo prevReplacementPageAddress = vol.replacementPageAddress;
checkStatus(allocateAndWriteSector(&vol,vol.replacementPageNo,NULL,TRUE));
nextReplacementPageAddress = vol.replacementPageAddress;
vol.replacementPageAddress = prevReplacementPageAddress;
goto pageRetry;
}
if (nextReplacementPageAddress != vol.replacementPageAddress) {
LogicalSectorNo prevReplacementPageAddress = vol.replacementPageAddress;
vol.replacementPageAddress = nextReplacementPageAddress;
checkStatus(deleteLogicalSector(&vol,prevReplacementPageAddress));
}
#else
setupMapCache(&vol,vol.replacementPageNo); /* read replacement page into map cache */
status = flashWrite(&vol,
logical2Physical(&vol,vol.replacementPageAddress),
mapCache,SECTOR_SIZE,OVERWRITE);
if (status != flOK) {
/* Uh oh. Trouble. Let's replace this replacement page. */
LogicalSectorNo prevReplacementPageAddress = vol.replacementPageAddress;
checkStatus(allocateAndWriteSector(&vol,vol.replacementPageNo,mapCache,TRUE));
checkStatus(deleteLogicalSector(&vol,prevReplacementPageAddress));
}
#endif
checkStatus(setVirtualMap(&vol,vol.replacementPageNo,vol.replacementPageAddress));
checkStatus(markAllocMap(&vol,
vol.replacementPageAddress,
(((VirtualAddress) vol.replacementPageNo - vol.noOfPages)
<< SECTOR_SIZE_BITS) | DATA_SECTOR,
TRUE));
vol.replacementPageNo = UNASSIGNED_SECTOR;
return flOK;
}
/*----------------------------------------------------------------------*/
/* s e t V i r t u a l M a p */
/* */
/* Changes an entry in the virtual map */
/* */
/* Parameters: */
/* vol : Pointer identifying drive */
/* sectorNo : Virtual sector no. whose entry is changed. */
/* newAddress : Logical sector no. to assign in Virtual Map. */
/* */
/* Returns: */
/* FLStatus : 0 on success, failed otherwise */
/*----------------------------------------------------------------------*/
static FLStatus setVirtualMap(Flare vol,
VirtualSectorNo sectorNo,
LogicalSectorNo newAddress)
{
unsigned pageNo;
int sectorInPage;
CardAddress virtualMapEntryAddress;
LEulong addressToWrite;
LogicalAddress oldAddress;
LogicalSectorNo updatedPage;
vol.mappedSectorNo = UNASSIGNED_SECTOR;
if (sectorNo < vol.directAddressingSectors) {
checkStatus(deleteLogicalSector(&vol,vol.pageTable[sectorNo]));
vol.pageTable[sectorNo] = newAddress;
return flOK;
}
sectorNo -= vol.noOfPages;
pageNo = sectorNo >> (PAGE_SIZE_BITS - SECTOR_SIZE_BITS);
sectorInPage = (int) (sectorNo) % ADDRESSES_PER_SECTOR;
updatedPage = vol.pageTable[pageNo];
virtualMapEntryAddress = logical2Physical(&vol,updatedPage) +
sectorInPage * sizeof(LogicalAddress);
oldAddress = LE4(*(LEulong FAR0 *)
vol.flash.map(&vol.flash,virtualMapEntryAddress,sizeof(LogicalAddress)));
if (oldAddress == DELETED_ADDRESS && vol.replacementPageNo == pageNo) {
updatedPage = vol.replacementPageAddress;
virtualMapEntryAddress = logical2Physical(&vol,updatedPage) +
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -