?? tfsclean.c
字號(hào):
/* tfsclean.c:
* This portion of the tfs code supports the file system cleanup or
* defragmentation. If INCLUDE_TFSCLEAN is set, then the power-safe
* cleanup is in place; otherwise, a much simpler and much less robust
* cleanup is used.
*
* General notice:
* This code is part of a boot-monitor package developed as a generic base
* platform for embedded system designs. As such, it is likely to be
* distributed to various projects beyond the control of the original
* author. Please notify the author of any enhancements made or bugs found
* so that all may benefit from the changes. In addition, notification back
* to the author will allow the new user to pick up changes that may have
* been made by other users after this version of the code was distributed.
*
* Author: Ed Sutter
* email: esutter@lucent.com (home: lesutter@worldnet.att.net)
* phone: 908-582-2351 (home: 908-889-5161)
*/
#include "config.h"
#include "cpu.h"
#include "stddefs.h"
#include "genlib.h"
#include "tfs.h"
#include "flash.h"
#include "monflags.h"
#if INCLUDE_TFSCLEAN
static ulong *DefragStateTbl;
static struct tfsdfg tfsdfgmsgtbl[] = {
{ SECTOR_DEFRAG_INACTIVE, "DefragInactive" },
{ BUILDING_HEADER_TABLE, "BuildingHeaderTable" },
{ HEADER_TABLE_READY, "HeaderTblReady" },
{ SECTOR_COPIED_TO_SPARE, "SectorCopiedToSpare" },
{ SECTOR_UPDATE_STARTED, "SectorUpdateStarted" },
{ SECTOR_UPDATE_COMPLETE, "SectorUpdateComplete" },
{ SECTOR_DEFRAG_COMPLETE, "SectorDefragComplete" },
{ ERASING_LAST_SECTOR, "ErasingLastSector" },
{ TOTAL_DEFRAG_COMPLETE, "TotalDefragComplete" },
{ COPY_HDRS_TO_SPARE, "CopyingHdrsToSpare" },
{ HDRS_IN_SPARE, "HeadersInSpare" },
{ ERASING_DEAD_SECTOR, "ErasingDeadSector" },
{ LASTSECTOR_IN_SPARE, "LastSectorInSpare" },
{ 0,0 }
};
/* tfsdefragmsg():
* Return the message string that corresponds to the incoming
* tfs defragmentation state number.
*/
static char *
tfsdefragmsg(int state)
{
struct tfsdfg *tdp;
tdp = tfsdfgmsgtbl;
while(tdp->msg) {
if (tdp->state == state)
return(tdp->msg);
tdp++;
}
return("unknown tfs defrag state");
}
/* getndaoffset():
* This function is used by tfsclean when a file that is being defragmented
* spans across multiple sectors. Since the defrag header only contains
* the sector number of the starting and ending sectors that the file spans
* across, this is used to retrieve the total offset from the start of
* the new file (new_destination_address) as each additional sector is
* defragmented.
*/
static int
getndaoffset(struct defraghdr *dp,int sec,int *retoffset)
{
int i, ssize, offset;
uchar *nextbase, *base;
offset = 0;
sectortoaddr(dp->bsn,0,&nextbase);
for(i=dp->bsn;i<sec;i++) {
if (addrtosector(nextbase,0,&ssize,&base) < 0) {
printf("getndaoffset (dp=0x%lx,sector=%d) failed\n",(ulong)dp,sec);
return(TFSERR_MEMFAIL);
}
if (i == dp->bsn)
offset = ssize - dp->bso;
else if (i == dp->esn)
offset += (ssize - dp->eso);
else
offset += ssize;
nextbase = base+ssize;
}
*retoffset = offset;
return(TFS_OKAY);
}
/* setdefragstate():
* The state of the defragmentation process is maintained by a table of
* longs that is located at the end of the last sector of TFS space.
* Each long represents the state of a TFS sector. This function simply
* modifies the bits in one of the longs to maintain the state of a
* particular sector.
* Note that the incoming sector number is relative to TFS space, so
* tfssector=0 does not represent the first sector of flash, it represents
* the first sector of TFS flash.
*/
static int
setdefragstate(tfssector,state,verbose)
int tfssector, verbose;
ulong state;
{
if (verbose > 2)
printf(" DefragState: %s\n",tfsdefragmsg(state));
if (tfsflashwrite((ulong *)(&DefragStateTbl[tfssector]),
(ulong *)&state,sizeof(state)) < 0) {
printf("setdefragstate(tfssec=%d,state=0x%lx) failed\n",
tfssector,state);
return(TFSERR_FLASHFAILURE);
}
return(TFS_OKAY);
}
/* tfsclean():
* Defragment the file system. During defragmentation, continually save
* enough state so that this function may be interrupted by a reset or
* power hit and can recover from it.
* Requires that one of the largest sectors of the flash device be designated
* as a SPARE sector, to be used only by defragmentation.
* Defragmentation state is stored at the end of the last TFS sector, so
* it is maintained across reset/powerhit also.
* Use of the SPARE sector and flash-based defragmentation state eliminates
* the vulnerability of the TFS being corrupted if the system is reset during
* defragmentation. It also eliminates the need for a large amount of RAM
* space (as was needed in earlier versions of tfsclean()).
*
* The function is designed to be entered at various points of the
* defragmentation process. If defragmentation is starting from scratch,
* then all arguments (except verbose) will be zero. If filtot is non-zero
* on entry, then this means that tfsclean() must pick up from a previously
* started defragmentation and cannot assume that a sane file system
* currently exists.
*
* Defragmentation success depends on some coordination with tfsadd()...
* Whenever a file is added to TFS, tfsadd() must verify that the space
* needed for defrag overhead (defrag state & header tables) will be
* available. Also, tfsadd() must make sure that the defrag overhead will
* always fit into one sector (the sector just prior to the spare).
*
*/
#if DEFRAG_TEST_ENABLED
int ExitPoint, ExitSector;
#define TEST_EXIT_POINT(pt,sno) \
if (ExitPoint == pt) { \
if ((ExitSector == sno) || (sno == -1)) { \
printf("!!!!!!!!!!!!! TestExit at point %d, sector %d\n",pt,sno); \
return(TFS_OKAY); \
} \
}
#else
#define TEST_EXIT_POINT(pt,sno)
#endif
static int
_tfsclean(int filtot,ulong *tbl1,struct defraghdr *tbl2,int snum,
TDEV *tdp,int resetwhendone,int verbose)
{
int ftot, fcnt, fsize, dtot, sparesnum, ssize;
int firsttfssector, lasttfssector, sectorcheck;
int tfssector, sidx, chkstat;
char *newaddress, *sbase, *firstdeadfile;
TFILE *tfp;
TINFO tinfo;
struct defraghdr *defraghdrtbl, *dp, defrag;
ulong *lp;
/* If incoming TFS device pointer is NULL, error... */
if (!tdp)
return(TFSERR_BADARG);
if ((verbose > 1) || (tfsTrace > 0)) {
printf("tfsclean(%d,0x%lx,0x%lx,%x,%s,%d,%d)\n",
filtot,(ulong)tbl1,(ulong)tbl2,snum,
tdp->prefix,resetwhendone,verbose);
}
else if (verbose)
printf("TFS cleanup: %s\n",tdp->prefix);
/* Do some initial configuration retrieval... */
/* Determine the first and last sector within TFS... */
if (addrtosector((char *)tdp->start,&firsttfssector,&ssize,
(uchar **)&sbase) < 0)
return(TFSERR_MEMFAIL);
lasttfssector = firsttfssector + tdp->sectorcount - 1;
if (addrtosector((char *)tdp->end,§orcheck,0,0) < 0)
return(TFSERR_MEMFAIL);
if (lasttfssector != sectorcheck) {
printf("%s: TFS SECTORCOUNT does not match TFSSTART <-> TFSEND\n",
tdp->prefix);
printf("First TFS sector = %d\n",firsttfssector);
printf("Last TFS sector = %d\n",sectorcheck);
return(TFSERR_MEMFAIL);
}
/* Store away information about spare sector... */
if (addrtosector((char *)tdp->spare,&sparesnum,0,0) < 0)
return(TFSERR_MEMFAIL);
if (filtot) {
sidx = snum;
ftot = filtot;
defraghdrtbl = tbl2;
DefragStateTbl = tbl1;
tfssector = firsttfssector+snum;
printf("Continuing defragmentation at sector %3d ",tfssector);
printf("(state=%s)...\n",tfsdefragmsg(DefragStateTbl[snum]));
if (sectortoaddr(tfssector,&ssize,(uchar **)&sbase) == -1)
return(TFSERR_MEMFAIL);
switch(DefragStateTbl[snum]) {
case BUILDING_HEADER_TABLE:
goto building_hdr;
case HEADER_TABLE_READY:
goto hdr_table_ready;
case COPY_HDRS_TO_SPARE:
goto copy_hdrs_to_spare;
case HDRS_IN_SPARE:
goto hdrs_in_spare;
case LASTSECTOR_IN_SPARE:
goto lastsector_in_spare;
case SECTOR_COPIED_TO_SPARE:
goto sector_copied_to_spare;
case SECTOR_UPDATE_STARTED:
goto sector_update_started;
case SECTOR_UPDATE_COMPLETE:
goto sector_update_complete;
case SECTOR_DEFRAG_COMPLETE:
goto sector_defrag_complete;
case ERASING_DEAD_SECTOR:
goto erasing_dead_sector;
case ERASING_LAST_SECTOR:
goto erasing_last_sector;
default:
return(TFSERR_BADARG);
}
}
/* Determine how many "live" files exist so that we can determine
* where to start building the defragstate[] and defraghdrtbl[] tables.
*/
tfp = (TFILE *)tdp->start;
ftot = dtot = 0;
while(validtfshdr(tfp)) {
if (TFS_FILEEXISTS(tfp))
ftot++;
else
dtot++;
tfp = nextfp(tfp,tdp);
}
/* If dtot is 0, then all TFS file headers indicate that there is no
* need to clean up the flash. There is still a chance that the flash
* (after the end of the last file in TFS) may not be erased, so check
* for that also...
*/
if (dtot == 0) {
printf("No dead files in %s.\n",tdp->prefix);
if (tfsflasherased(tdp,verbose))
return(0);
else
printf("Running defrag to cleanup...\n");
}
/* If ftot is 0, then there are no valid files in the flash, so simply
* erase all TFS flash space and return...
*/
if (ftot == 0) {
if (verbose)
printf("No active files detected, erasing all %s flash...\n",
tdp->prefix);
_tfsinit(tdp);
return(0);
}
tfsmemuse(tdp,&tinfo,0);
if ((verbose) || (!MFLAGS_NODEFRAGPRN())) {
printf("%s with %d dead file%s (%d bytes) removed.\n",
"Defragmenting file system",dtot,dtot>1 ? "s":"",
tinfo.deadovrhd+tinfo.deaddata);
}
DefragStateTbl = (ulong *)(tdp->end+1);
DefragStateTbl -= tdp->sectorcount;
defraghdrtbl = (struct defraghdr *)(DefragStateTbl) - ftot;
/* Verify that the space to be written to for the
* defrag stuff is erased...
*/
lp = (ulong *)defraghdrtbl;
while(lp < (ulong *)tdp->end) {
if (*lp++ != (ulong)ERASED32) {
printf("Defragmentation table space (0x%lx-0x%lx) not erased.\n",
(ulong)defraghdrtbl,(ulong)(tdp->end));
return(TFSERR_FLASHFAILURE);
}
}
TEST_EXIT_POINT(1,-1);
/* Erase SPARE sector. */
if (tfsflasherase(sparesnum) < 0) {
printf("Flash SPARE sector erase failed\n");
return(TFSERR_FLASHFAILURE);
}
TEST_EXIT_POINT(2,-1);
if (verbose > 2) {
printf("Building defrag header for %d files...\n",ftot);
printf("DefragStateTbl=0x%lx\n",(ulong)DefragStateTbl);
printf("defraghdrtbl=0x%lx\n",(ulong)defraghdrtbl);
}
/* Mark the defragmentation state table to indicate that we are */
/* about to begin defragmentation. */
if (setdefragstate(0,BUILDING_HEADER_TABLE,verbose) != TFS_OKAY)
return(TFSERR_FLASHFAILURE);
building_hdr:
firstdeadfile = (char *)0;
tfp = (TFILE *)tdp->start;
while(validtfshdr(tfp)) {
if (TFS_DELETED(tfp)) {
firstdeadfile = (char *)tfp;
break;
}
tfp = nextfp(tfp,tdp);
}
tfp = (TFILE *)tdp->start;
newaddress = (char *)tdp->start;
fcnt = 0;
if (verbose > 2)
printf("\nDEFRAGMETATION HEADER DATA:\n");
while(validtfshdr(tfp)) {
if (TFS_FILEEXISTS(tfp)) {
uchar *base, *eof;
int size, slot;
struct tfsdat *slotptr;
defrag.fhdr = *tfp;
if (addrtosector((char *)tfp,&defrag.bsn,0,&base) < 0)
return(TFSERR_MEMFAIL);
defrag.bso = (uchar *)tfp - base;
eof = (uchar *)(tfp+1)+TFS_SIZE(tfp)-1;
if (addrtosector((char *)eof,&defrag.esn,0,&base) < 0)
return(TFSERR_MEMFAIL);
defrag.fdf = firstdeadfile;
defrag.eso = eof - base + 1;
defrag.nda = newaddress;
defrag.phc = ERASED32;
/* If the file is currently opened, adjust the base address. */
slotptr = tfsSlots;
for (slot=0;slot<TFS_MAXOPEN;slot++,slotptr++) {
if (slotptr->offset != -1) {
if (slotptr->base == (uchar *)(TFS_BASE(tfp))) {
slotptr->base = (uchar *)(newaddress+TFSHDRSIZ);
if (verbose)
printf("Base of opened file '%s' shifted from 0x%lx to 0x%lx\n",
TFS_NAME(tfp),(ulong)(TFS_BASE(tfp)),
(ulong)(slotptr->base));
}
}
}
if (verbose > 2) {
printf(" File %s:\n",TFS_NAME(tfp));
printf(" bsn=%3d,bso=0x%08x,",defrag.bsn,defrag.bso);
printf("esn=%3d,eso=0x%08x,",defrag.esn,defrag.eso);
printf("nda=0x%08lx,fdf=0x%08lx\n",
?? 快捷鍵說(shuō)明
復(fù)制代碼
Ctrl + C
搜索代碼
Ctrl + F
全屏模式
F11
切換主題
Ctrl + Shift + D
顯示快捷鍵
?
增大字號(hào)
Ctrl + =
減小字號(hào)
Ctrl + -