⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 tfsclean.c

📁 可移到ucos上的文件系统
💻 C
📖 第 1 页 / 共 3 页
字号:
/* 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,&sectorcheck,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",

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -