X-Git-Url: http://www.aleph1.co.uk/gitweb/?p=yaffs2.git;a=blobdiff_plain;f=yaffs_guts.c;h=94ed16c4d4ba7741fc533dee8a06a72285a6439c;hp=bc4e9b9846cf31dfb7b93e6387e1c13b9d658b14;hb=35ff307107b49e579c8282c67083fd494fd29032;hpb=e1b8e63260986ab7afec3c379e7a320677c95846 diff --git a/yaffs_guts.c b/yaffs_guts.c index bc4e9b9..94ed16c 100644 --- a/yaffs_guts.c +++ b/yaffs_guts.c @@ -1,5 +1,5 @@ /* - * YAFFS: Yet another FFS. A NAND-flash specific file system. + * YAFFS: Yet another FFS. A NAND-flash specific file system. * * Copyright (C) 2002 Aleph One Ltd. * for Toby Churchill Ltd and Brightstar Engineering @@ -13,7 +13,7 @@ */ const char *yaffs_guts_c_version = - "$Id: yaffs_guts.c,v 1.32 2006-05-08 10:13:34 charles Exp $"; + "$Id: yaffs_guts.c,v 1.35 2006-06-05 04:10:49 charles Exp $"; #include "yportenv.h" @@ -22,6 +22,9 @@ const char *yaffs_guts_c_version = #include "yaffs_tagsvalidity.h" #include "yaffs_tagscompat.h" +#ifndef CONFIG_YAFFS_OWN_SORT +#include "yaffs_qsort.h" +#endif #include "yaffs_nand.h" #include "yaffs_checkptrw.h" @@ -165,6 +168,32 @@ static void yaffs_ReleaseTempBuffer(yaffs_Device * dev, __u8 * buffer, } +/* + * Determine if we have a managed buffer. + */ +int yaffs_IsManagedTempBuffer(yaffs_Device * dev, const __u8 * buffer) +{ + int i; + for (i = 0; i < YAFFS_N_TEMP_BUFFERS; i++) { + if (dev->tempBuffer[i].buffer == buffer) + return 1; + + } + + for (i = 0; i < dev->nShortOpCaches; i++) { + if( dev->srCache[i].data == buffer ) + return 1; + + } + + if (buffer == dev->checkpointBuffer) + return 1; + + T(YAFFS_TRACE_ALWAYS, + (TSTR("yaffs: unmaged buffer detected.\n" TENDSTR))); + return 0; +} + /* * Chunk bitmap manipulations */ @@ -1722,6 +1751,15 @@ int yaffs_RenameObject(yaffs_Object * oldDir, const YCHAR * oldName, #endif obj = yaffs_FindObjectByName(oldDir, oldName); + /* Check new name to long. */ + if (obj->variantType == YAFFS_OBJECT_TYPE_SYMLINK && + yaffs_strlen(newName) > YAFFS_MAX_ALIAS_LENGTH) + /* ENAMETOOLONG */ + return YAFFS_FAIL; + else if (obj->variantType != YAFFS_OBJECT_TYPE_SYMLINK && + yaffs_strlen(newName) > YAFFS_MAX_NAME_LENGTH) + /* ENAMETOOLONG */ + return YAFFS_FAIL; if (obj && obj->renameAllowed) { @@ -1900,9 +1938,17 @@ static int yaffs_FindBlockForGarbageCollection(yaffs_Device * dev, bi = yaffs_GetBlockInfo(dev, b); +#if 0 + if (bi->blockState == YAFFS_BLOCK_STATE_CHECKPOINT) { + dirtiest = b; + pagesInUse = 0; + } + else +#endif + if (bi->blockState == YAFFS_BLOCK_STATE_FULL && - (bi->pagesInUse - bi->softDeletions) < pagesInUse && - yaffs_BlockNotDisqualifiedFromGC(dev, bi)) { + (bi->pagesInUse - bi->softDeletions) < pagesInUse && + yaffs_BlockNotDisqualifiedFromGC(dev, bi)) { dirtiest = b; pagesInUse = (bi->pagesInUse - bi->softDeletions); } @@ -2028,10 +2074,20 @@ static int yaffs_FindBlockForAllocation(yaffs_Device * dev) } - +// Check if there's space to allocate... +// Thinks.... do we need top make this ths same as yaffs_GetFreeChunks()? static int yaffs_CheckSpaceForAllocation(yaffs_Device * dev) { - int reservedChunks = (dev->nReservedBlocks * dev->nChunksPerBlock); + int reservedChunks; + int reservedBlocks = dev->nReservedBlocks; + int checkpointBlocks; + + checkpointBlocks = dev->nCheckpointReservedBlocks - dev->blocksInCheckpoint; + if(checkpointBlocks < 0) + checkpointBlocks = 0; + + reservedChunks = ((reservedBlocks + checkpointBlocks) * dev->nChunksPerBlock); + return (dev->nFreeChunks > reservedChunks); } @@ -2108,6 +2164,7 @@ static int yaffs_GarbageCollectBlock(yaffs_Device * dev, int block) int retVal = YAFFS_OK; int cleanups = 0; int i; + int isCheckpointBlock; int chunksBefore = yaffs_GetErasedChunks(dev); int chunksAfter; @@ -2118,6 +2175,8 @@ static int yaffs_GarbageCollectBlock(yaffs_Device * dev, int block) yaffs_Object *object; + isCheckpointBlock = (bi->blockState == YAFFS_BLOCK_STATE_CHECKPOINT); + bi->blockState = YAFFS_BLOCK_STATE_COLLECTING; T(YAFFS_TRACE_TRACING, @@ -2135,7 +2194,8 @@ static int yaffs_GarbageCollectBlock(yaffs_Device * dev, int block) dev->isDoingGC = 1; - if (!yaffs_StillSomeChunkBits(dev, block)) { + if (isCheckpointBlock || + !yaffs_StillSomeChunkBits(dev, block)) { T(YAFFS_TRACE_TRACING, (TSTR ("Collecting block %d that has no chunks in use" TENDSTR), @@ -2314,6 +2374,8 @@ static int yaffs_CheckGarbageCollection(yaffs_Device * dev) int aggressive; int gcOk = YAFFS_OK; int maxTries = 0; + + int checkpointBlockAdjust; if (dev->isDoingGC) { /* Bail out so we don't get recursive gc */ @@ -2326,7 +2388,12 @@ static int yaffs_CheckGarbageCollection(yaffs_Device * dev) do { maxTries++; - if (dev->nErasedBlocks < dev->nReservedBlocks) { + + checkpointBlockAdjust = (dev->nCheckpointReservedBlocks - dev->blocksInCheckpoint); + if(checkpointBlockAdjust < 0) + checkpointBlockAdjust = 0; + + if (dev->nErasedBlocks < (dev->nReservedBlocks + checkpointBlockAdjust)) { /* We need a block soon...*/ aggressive = 1; } else { @@ -3360,13 +3427,15 @@ static int yaffs_CheckpointTnodeWorker(yaffs_Object * in, yaffs_Tnode * tn, { int i; yaffs_Device *dev = in->myDev; + int ok = 1; + int nTnodeBytes = (dev->tnodeWidth * YAFFS_NTNODES_LEVEL0)/8; if (tn) { if (level > 0) { - for (i = 0; i < YAFFS_NTNODES_INTERNAL; i++){ + for (i = 0; i < YAFFS_NTNODES_INTERNAL && ok; i++){ if (tn->internal[i]) { - yaffs_CheckpointTnodeWorker(in, + ok = yaffs_CheckpointTnodeWorker(in, tn->internal[i], level - 1, (chunkOffset<tnodeWidth * YAFFS_NTNODES_LEVEL0)/8); + ok = (yaffs_CheckpointWrite(dev,&baseOffset,sizeof(baseOffset)) == sizeof(baseOffset)); + if(ok) + ok = (yaffs_CheckpointWrite(dev,tn,nTnodeBytes) == nTnodeBytes); } } - return 1; + return ok; } static int yaffs_WriteCheckpointTnodes(yaffs_Object *obj) { __u32 endMarker = ~0; - int ok; + int ok = 1; if(obj->variantType == YAFFS_OBJECT_TYPE_FILE){ ok = yaffs_CheckpointTnodeWorker(obj, @@ -3497,13 +3567,14 @@ static int yaffs_ReadCheckpointObjects(yaffs_Device *dev) if(ok && cp.objectId == ~0) done = 1; - else { - /* printf("Read object %d type %d\n",cp.objectId,cp.variantType); */ + else if(ok){ + T(YAFFS_TRACE_CHECKPOINT,(TSTR("Read object %d parent %d type %d" TENDSTR), + cp.objectId,cp.parentId,cp.variantType)); obj = yaffs_FindOrCreateObjectByNumber(dev,cp.objectId, cp.variantType); if(obj) { yaffs_CheckpointObjectToObject(obj,&cp); if(obj->variantType == YAFFS_OBJECT_TYPE_FILE) { - yaffs_ReadCheckpointTnodes(obj); + ok = yaffs_ReadCheckpointTnodes(obj); } else if(obj->variantType == YAFFS_OBJECT_TYPE_HARDLINK) { obj->hardLinks.next = (struct list_head *) @@ -3537,8 +3608,9 @@ static int yaffs_WriteCheckpointData(yaffs_Device *dev) if(ok) ok = yaffs_WriteCheckpointValidityMarker(dev,0); - yaffs_CheckpointClose(dev); - + if(!yaffs_CheckpointClose(dev)) + ok = 0; + if(ok) dev->isCheckpointed = 1; else @@ -3562,39 +3634,54 @@ static int yaffs_ReadCheckpointData(yaffs_Device *dev) if(ok) ok = yaffs_ReadCheckpointValidityMarker(dev,0); - + + + if(!yaffs_CheckpointClose(dev)) + ok = 0; + if(ok) dev->isCheckpointed = 1; else dev->isCheckpointed = 0; - yaffs_CheckpointClose(dev); - return ok ? 1 : 0; } static void yaffs_InvalidateCheckpoint(yaffs_Device *dev) { - if(dev->isCheckpointed){ + if(dev->isCheckpointed || + dev->blocksInCheckpoint > 0){ dev->isCheckpointed = 0; yaffs_CheckpointInvalidateStream(dev); + if(dev->superBlock && dev->markSuperBlockDirty) + dev->markSuperBlockDirty(dev->superBlock); } } int yaffs_CheckpointSave(yaffs_Device *dev) { + T(YAFFS_TRACE_CHECKPOINT,(TSTR("save entry: isCheckpointed %d"TENDSTR),dev->isCheckpointed)); + if(!dev->isCheckpointed) yaffs_WriteCheckpointData(dev); + T(YAFFS_TRACE_CHECKPOINT,(TSTR("save exit: isCheckpointed %d"TENDSTR),dev->isCheckpointed)); + return dev->isCheckpointed; } int yaffs_CheckpointRestore(yaffs_Device *dev) { + int retval; + T(YAFFS_TRACE_CHECKPOINT,(TSTR("restore entry: isCheckpointed %d"TENDSTR),dev->isCheckpointed)); - return yaffs_ReadCheckpointData(dev); + retval = yaffs_ReadCheckpointData(dev); + + T(YAFFS_TRACE_CHECKPOINT,(TSTR("restore exit: isCheckpointed %d"TENDSTR),dev->isCheckpointed)); + + return retval; } /*--------------------- File read/write ------------------------ @@ -3782,6 +3869,7 @@ int yaffs_WriteDataToFile(yaffs_Object * in, const __u8 * buffer, __u32 offset, yaffs_ChunkCache *cache; /* If we can't find the data in the cache, then load the cache */ cache = yaffs_FindChunkCache(in, chunk); + if (!cache && yaffs_CheckSpaceForAllocation(in-> myDev)) { @@ -3794,6 +3882,14 @@ int yaffs_WriteDataToFile(yaffs_Object * in, const __u8 * buffer, __u32 offset, cache-> data); } + else if(cache && + !cache->dirty && + !yaffs_CheckSpaceForAllocation(in->myDev)){ + /* Drop the cache if it was a read cache item and + * no space check has been made for it. + */ + cache = NULL; + } if (cache) { yaffs_UseChunkCache(dev, cache, 1); @@ -4344,6 +4440,18 @@ static void yaffs_HardlinkFixup(yaffs_Device *dev, yaffs_Object *hardList) +static int ybicmp(const void *a, const void *b){ + register int aseq = ((yaffs_BlockIndex *)a)->seq; + register int bseq = ((yaffs_BlockIndex *)b)->seq; + register int ablock = ((yaffs_BlockIndex *)a)->block; + register int bblock = ((yaffs_BlockIndex *)b)->block; + if( aseq == bseq ) + return ablock - bblock; + else + return aseq - bseq; + +} + static int yaffs_Scan(yaffs_Device * dev) { yaffs_ExtendedTags tags; @@ -4370,6 +4478,14 @@ static int yaffs_Scan(yaffs_Device * dev) yaffs_BlockIndex *blockIndex = NULL; + if (dev->isYaffs2) { + T(YAFFS_TRACE_SCAN, + (TSTR("yaffs_Scan is not for YAFFS2!" TENDSTR))); + return YAFFS_FAIL; + } + + //TODO Throw all the yaffs2 stuuf out of yaffs_Scan since it is only for yaffs1 format. + T(YAFFS_TRACE_SCAN, (TSTR("yaffs_Scan starts intstartblk %d intendblk %d..." TENDSTR), dev->internalStartBlock, dev->internalEndBlock)); @@ -4895,6 +5011,7 @@ static int yaffs_ScanBackwards(yaffs_Device * dev) yaffs_BlockIndex *blockIndex = NULL; + int altBlockIndex = 0; if (!dev->isYaffs2) { T(YAFFS_TRACE_SCAN, @@ -4907,11 +5024,23 @@ static int yaffs_ScanBackwards(yaffs_Device * dev) ("yaffs_ScanBackwards starts intstartblk %d intendblk %d..." TENDSTR), dev->internalStartBlock, dev->internalEndBlock)); - chunkData = yaffs_GetTempBuffer(dev, __LINE__); dev->sequenceNumber = YAFFS_LOWEST_SEQUENCE_NUMBER; blockIndex = YMALLOC(nBlocks * sizeof(yaffs_BlockIndex)); + + if(!blockIndex) { + blockIndex = YMALLOC_ALT(nBlocks * sizeof(yaffs_BlockIndex)); + altBlockIndex = 1; + } + + if(!blockIndex) { + T(YAFFS_TRACE_SCAN, + (TSTR("yaffs_Scan() could not allocate block index!" TENDSTR))); + return YAFFS_FAIL; + } + + chunkData = yaffs_GetTempBuffer(dev, __LINE__); /* Scan all the blocks to determine their state */ for (blk = dev->internalStartBlock; blk <= dev->internalEndBlock; blk++) { @@ -4925,11 +5054,18 @@ static int yaffs_ScanBackwards(yaffs_Device * dev) bi->blockState = state; bi->sequenceNumber = sequenceNumber; + if(bi->sequenceNumber == YAFFS_SEQUENCE_CHECKPOINT_DATA) + bi->blockState = state = YAFFS_BLOCK_STATE_CHECKPOINT; + T(YAFFS_TRACE_SCAN_DEBUG, (TSTR("Block scanning block %d state %d seq %d" TENDSTR), blk, state, sequenceNumber)); - if (state == YAFFS_BLOCK_STATE_DEAD) { + + if(state == YAFFS_BLOCK_STATE_CHECKPOINT){ + /* todo .. fix free space ? */ + + } else if (state == YAFFS_BLOCK_STATE_DEAD) { T(YAFFS_TRACE_BAD_BLOCKS, (TSTR("block %d is bad" TENDSTR), blk)); } else if (state == YAFFS_BLOCK_STATE_EMPTY) { @@ -4963,11 +5099,23 @@ static int yaffs_ScanBackwards(yaffs_Device * dev) } } - /* - * Sort the blocks - * Dungy old bubble sort for now... - */ + T(YAFFS_TRACE_SCAN, + (TSTR("%d blocks to be sorted..." TENDSTR), nBlocksToScan)); + + + + YYIELD(); + + /* Sort the blocks */ +#ifndef CONFIG_YAFFS_USE_OWN_SORT { + /* Use qsort now. */ + qsort(blockIndex, nBlocksToScan, sizeof(yaffs_BlockIndex), ybicmp); + } +#else + { + /* Dungy old bubble sort... */ + yaffs_BlockIndex temp; int i; int j; @@ -4980,6 +5128,11 @@ static int yaffs_ScanBackwards(yaffs_Device * dev) blockIndex[i] = temp; } } +#endif + + YYIELD(); + + T(YAFFS_TRACE_SCAN, (TSTR("...done" TENDSTR))); /* Now scan the blocks looking at the data. */ startIterator = 0; @@ -4990,6 +5143,9 @@ static int yaffs_ScanBackwards(yaffs_Device * dev) /* For each block.... backwards */ for (blockIterator = endIterator; blockIterator >= startIterator; blockIterator--) { + /* Cooperative multitasking! This loop can run for so + long that watchdog timers expire. */ + YYIELD(); /* get the block to scan in the correct order */ blk = blockIndex[blockIterator].block; @@ -5409,9 +5565,11 @@ static int yaffs_ScanBackwards(yaffs_Device * dev) } - if (blockIndex) { + if (altBlockIndex) + YFREE_ALT(blockIndex); + else YFREE(blockIndex); - } + /* Ok, we've done all the scanning. * Fix up the hard link chains. * We should now have scanned all the objects, now it's time to add these @@ -6033,7 +6191,7 @@ int yaffs_GutsInitialise(yaffs_Device * dev) for (i = 0; i < YAFFS_N_TEMP_BUFFERS; i++) { dev->tempBuffer[i].line = 0; /* not in use */ dev->tempBuffer[i].buffer = - YMALLOC(dev->nBytesPerChunk); + YMALLOC_DMA(dev->nBytesPerChunk); } } @@ -6051,7 +6209,7 @@ int yaffs_GutsInitialise(yaffs_Device * dev) dev->srCache[i].object = NULL; dev->srCache[i].lastUse = 0; dev->srCache[i].dirty = 0; - dev->srCache[i].data = YMALLOC(dev->nBytesPerChunk); + dev->srCache[i].data = YMALLOC_DMA(dev->nBytesPerChunk); } dev->srLastUse = 0; } @@ -6174,6 +6332,7 @@ int yaffs_GetNumberOfFreeChunks(yaffs_Device * dev) int nFree; int nDirtyCacheChunks; + int blocksForCheckpoint; #if 1 nFree = dev->nFreeChunks; @@ -6196,6 +6355,13 @@ int yaffs_GetNumberOfFreeChunks(yaffs_Device * dev) nFree -= nDirtyCacheChunks; nFree -= ((dev->nReservedBlocks + 1) * dev->nChunksPerBlock); + + /* Now we figure out how much to reserve for the checkpoint and report that... */ + blocksForCheckpoint = dev->nCheckpointReservedBlocks - dev->blocksInCheckpoint; + if(blocksForCheckpoint < 0) + blocksForCheckpoint = 0; + + nFree -= (blocksForCheckpoint * dev->nChunksPerBlock); if (nFree < 0) nFree = 0;