* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*/
+
#include "yportenv.h"
#include "yaffs_trace.h"
#include "yaffs_yaffs1.h"
#include "yaffs_yaffs2.h"
#include "yaffs_bitmap.h"
+#include "yaffs_verify.h"
#include "yaffs_nand.h"
#include "yaffs_packedtags2.h"
yaffs_ObjectType type);
-static int yaffs_ApplyXMod(yaffs_Device *dev, char *buffer, yaffs_XAttrMod *xmod);
+static int yaffs_ApplyXMod(yaffs_Object *obj, char *buffer, yaffs_XAttrMod *xmod);
static void yaffs_RemoveObjectFromDirectory(yaffs_Object *obj);
static int yaffs_CheckStructures(void);
static int yaffs_DoGenericObjectDeletion(yaffs_Object *in);
-static yaffs_BlockInfo *yaffs_GetBlockInfo(yaffs_Device *dev, int blockNo);
-
-
static int yaffs_CheckChunkErased(struct yaffs_DeviceStruct *dev,
int chunkInNAND);
static void yaffs_CheckObjectDetailsLoaded(yaffs_Object *in);
-static void yaffs_VerifyDirectory(yaffs_Object *directory);
-#ifdef YAFFS_PARANOID
-static int yaffs_CheckFileSanity(yaffs_Object *in);
-#else
-#define yaffs_CheckFileSanity(in)
-#endif
-
static void yaffs_InvalidateWholeChunkCache(yaffs_Object *in);
static void yaffs_InvalidateChunkCache(yaffs_Object *object, int chunkId);
static int yaffs_FindChunkInFile(yaffs_Object *in, int chunkInInode,
yaffs_ExtendedTags *tags);
-static __u32 yaffs_GetChunkGroupBase(yaffs_Device *dev, yaffs_Tnode *tn,
- unsigned pos);
-static yaffs_Tnode *yaffs_FindLevel0Tnode(yaffs_Device *dev,
- yaffs_FileStructure *fStruct,
- __u32 chunkId);
-
static int yaffs_VerifyChunkWritten(yaffs_Device *dev,
int chunkInNAND,
const __u8 *data,
yaffs_ExtendedTags *tags);
+
+static void yaffs_LoadNameFromObjectHeader(yaffs_Device *dev,YCHAR *name, const YCHAR *ohName, int bufferSize);
+static void yaffs_LoadObjectHeaderFromName(yaffs_Device *dev,YCHAR *ohName, const YCHAR *name);
+
+
/* Function to calculate chunk and offset */
static void yaffs_AddrToChunk(yaffs_Device *dev, loff_t addr, int *chunkOut,
* Verification code
*/
-static int yaffs_SkipVerification(yaffs_Device *dev)
-{
- dev=dev;
- return !(yaffs_traceMask & (YAFFS_TRACE_VERIFY | YAFFS_TRACE_VERIFY_FULL));
-}
-
-static int yaffs_SkipFullVerification(yaffs_Device *dev)
-{
- dev=dev;
- return !(yaffs_traceMask & (YAFFS_TRACE_VERIFY_FULL));
-}
-
-static int yaffs_SkipNANDVerification(yaffs_Device *dev)
-{
- dev=dev;
- return !(yaffs_traceMask & (YAFFS_TRACE_VERIFY_NAND));
-}
-
-static const char *blockStateName[] = {
-"Unknown",
-"Needs scanning",
-"Scanning",
-"Empty",
-"Allocating",
-"Full",
-"Dirty",
-"Checkpoint",
-"Collecting",
-"Dead"
-};
-static void yaffs_VerifyBlock(yaffs_Device *dev, yaffs_BlockInfo *bi, int n)
-{
- int actuallyUsed;
- int inUse;
-
- if (yaffs_SkipVerification(dev))
- return;
-
- /* Report illegal runtime states */
- if (bi->blockState >= YAFFS_NUMBER_OF_BLOCK_STATES)
- T(YAFFS_TRACE_VERIFY, (TSTR("Block %d has undefined state %d"TENDSTR), n, bi->blockState));
-
- switch (bi->blockState) {
- case YAFFS_BLOCK_STATE_UNKNOWN:
- case YAFFS_BLOCK_STATE_SCANNING:
- case YAFFS_BLOCK_STATE_NEEDS_SCANNING:
- T(YAFFS_TRACE_VERIFY, (TSTR("Block %d has bad run-state %s"TENDSTR),
- n, blockStateName[bi->blockState]));
- }
-
- /* Check pages in use and soft deletions are legal */
-
- actuallyUsed = bi->pagesInUse - bi->softDeletions;
-
- if (bi->pagesInUse < 0 || bi->pagesInUse > dev->param.nChunksPerBlock ||
- bi->softDeletions < 0 || bi->softDeletions > dev->param.nChunksPerBlock ||
- actuallyUsed < 0 || actuallyUsed > dev->param.nChunksPerBlock)
- T(YAFFS_TRACE_VERIFY, (TSTR("Block %d has illegal values pagesInUsed %d softDeletions %d"TENDSTR),
- n, bi->pagesInUse, bi->softDeletions));
-
-
- /* Check chunk bitmap legal */
- inUse = yaffs_CountChunkBits(dev, n);
- if (inUse != bi->pagesInUse)
- T(YAFFS_TRACE_VERIFY, (TSTR("Block %d has inconsistent values pagesInUse %d counted chunk bits %d"TENDSTR),
- n, bi->pagesInUse, inUse));
-
- /* Check that the sequence number is valid.
- * Ten million is legal, but is very unlikely
- */
-
- yaffs2_VerifyBlock(dev,bi,n);
-}
-
-
-
-static void yaffs_VerifyCollectedBlock(yaffs_Device *dev, yaffs_BlockInfo *bi,
- int n)
-{
- yaffs_VerifyBlock(dev, bi, n);
-
- /* After collection the block should be in the erased state */
- /* This will need to change if we do partial gc */
-
- if (bi->blockState != YAFFS_BLOCK_STATE_COLLECTING &&
- bi->blockState != YAFFS_BLOCK_STATE_EMPTY) {
- T(YAFFS_TRACE_ERROR, (TSTR("Block %d is in state %d after gc, should be erased"TENDSTR),
- n, bi->blockState));
- }
-}
-
-void yaffs_VerifyBlocks(yaffs_Device *dev)
-{
- int i;
- int nBlocksPerState[YAFFS_NUMBER_OF_BLOCK_STATES];
- int nIllegalBlockStates = 0;
-
- if (yaffs_SkipVerification(dev))
- return;
-
- memset(nBlocksPerState, 0, sizeof(nBlocksPerState));
-
- for (i = dev->internalStartBlock; i <= dev->internalEndBlock; i++) {
- yaffs_BlockInfo *bi = yaffs_GetBlockInfo(dev, i);
- yaffs_VerifyBlock(dev, bi, i);
-
- if (bi->blockState < YAFFS_NUMBER_OF_BLOCK_STATES)
- nBlocksPerState[bi->blockState]++;
- else
- nIllegalBlockStates++;
- }
-
- T(YAFFS_TRACE_VERIFY, (TSTR(""TENDSTR)));
- T(YAFFS_TRACE_VERIFY, (TSTR("Block summary"TENDSTR)));
-
- T(YAFFS_TRACE_VERIFY, (TSTR("%d blocks have illegal states"TENDSTR), nIllegalBlockStates));
- if (nBlocksPerState[YAFFS_BLOCK_STATE_ALLOCATING] > 1)
- T(YAFFS_TRACE_VERIFY, (TSTR("Too many allocating blocks"TENDSTR)));
-
- for (i = 0; i < YAFFS_NUMBER_OF_BLOCK_STATES; i++)
- T(YAFFS_TRACE_VERIFY,
- (TSTR("%s %d blocks"TENDSTR),
- blockStateName[i], nBlocksPerState[i]));
-
- if (dev->blocksInCheckpoint != nBlocksPerState[YAFFS_BLOCK_STATE_CHECKPOINT])
- T(YAFFS_TRACE_VERIFY,
- (TSTR("Checkpoint block count wrong dev %d count %d"TENDSTR),
- dev->blocksInCheckpoint, nBlocksPerState[YAFFS_BLOCK_STATE_CHECKPOINT]));
-
- if (dev->nErasedBlocks != nBlocksPerState[YAFFS_BLOCK_STATE_EMPTY])
- T(YAFFS_TRACE_VERIFY,
- (TSTR("Erased block count wrong dev %d count %d"TENDSTR),
- dev->nErasedBlocks, nBlocksPerState[YAFFS_BLOCK_STATE_EMPTY]));
-
- if (nBlocksPerState[YAFFS_BLOCK_STATE_COLLECTING] > 1)
- T(YAFFS_TRACE_VERIFY,
- (TSTR("Too many collecting blocks %d (max is 1)"TENDSTR),
- nBlocksPerState[YAFFS_BLOCK_STATE_COLLECTING]));
-
- T(YAFFS_TRACE_VERIFY, (TSTR(""TENDSTR)));
-
-}
-
-/*
- * Verify the object header. oh must be valid, but obj and tags may be NULL in which
- * case those tests will not be performed.
- */
-static void yaffs_VerifyObjectHeader(yaffs_Object *obj, yaffs_ObjectHeader *oh, yaffs_ExtendedTags *tags, int parentCheck)
-{
- if (obj && yaffs_SkipVerification(obj->myDev))
- return;
-
- if (!(tags && obj && oh)) {
- T(YAFFS_TRACE_VERIFY,
- (TSTR("Verifying object header tags %p obj %p oh %p"TENDSTR),
- tags, obj, oh));
- return;
- }
-
- if (oh->type <= YAFFS_OBJECT_TYPE_UNKNOWN ||
- oh->type > YAFFS_OBJECT_TYPE_MAX)
- T(YAFFS_TRACE_VERIFY,
- (TSTR("Obj %d header type is illegal value 0x%x"TENDSTR),
- tags->objectId, oh->type));
-
- if (tags->objectId != obj->objectId)
- T(YAFFS_TRACE_VERIFY,
- (TSTR("Obj %d header mismatch objectId %d"TENDSTR),
- tags->objectId, obj->objectId));
-
-
- /*
- * Check that the object's parent ids match if parentCheck requested.
- *
- * Tests do not apply to the root object.
- */
-
- if (parentCheck && tags->objectId > 1 && !obj->parent)
- T(YAFFS_TRACE_VERIFY,
- (TSTR("Obj %d header mismatch parentId %d obj->parent is NULL"TENDSTR),
- tags->objectId, oh->parentObjectId));
-
- if (parentCheck && obj->parent &&
- oh->parentObjectId != obj->parent->objectId &&
- (oh->parentObjectId != YAFFS_OBJECTID_UNLINKED ||
- obj->parent->objectId != YAFFS_OBJECTID_DELETED))
- T(YAFFS_TRACE_VERIFY,
- (TSTR("Obj %d header mismatch parentId %d parentObjectId %d"TENDSTR),
- tags->objectId, oh->parentObjectId, obj->parent->objectId));
-
- if (tags->objectId > 1 && oh->name[0] == 0) /* Null name */
- T(YAFFS_TRACE_VERIFY,
- (TSTR("Obj %d header name is NULL"TENDSTR),
- obj->objectId));
-
- if (tags->objectId > 1 && ((__u8)(oh->name[0])) == 0xff) /* Trashed name */
- T(YAFFS_TRACE_VERIFY,
- (TSTR("Obj %d header name is 0xFF"TENDSTR),
- obj->objectId));
-}
-
-
-#if 0
-/* Not being used, but don't want to throw away yet */
-static int yaffs_VerifyTnodeWorker(yaffs_Object *obj, yaffs_Tnode *tn,
- __u32 level, int chunkOffset)
-{
- int i;
- yaffs_Device *dev = obj->myDev;
- int ok = 1;
-
- if (tn) {
- if (level > 0) {
-
- for (i = 0; i < YAFFS_NTNODES_INTERNAL && ok; i++) {
- if (tn->internal[i]) {
- ok = yaffs_VerifyTnodeWorker(obj,
- tn->internal[i],
- level - 1,
- (chunkOffset<<YAFFS_TNODES_INTERNAL_BITS) + i);
- }
- }
- } else if (level == 0) {
- yaffs_ExtendedTags tags;
- __u32 objectId = obj->objectId;
-
- chunkOffset <<= YAFFS_TNODES_LEVEL0_BITS;
-
- for (i = 0; i < YAFFS_NTNODES_LEVEL0; i++) {
- __u32 theChunk = yaffs_GetChunkGroupBase(dev, tn, i);
-
- if (theChunk > 0) {
- /* T(~0,(TSTR("verifying (%d:%d) %d"TENDSTR),tags.objectId,tags.chunkId,theChunk)); */
- yaffs_ReadChunkWithTagsFromNAND(dev, theChunk, NULL, &tags);
- if (tags.objectId != objectId || tags.chunkId != chunkOffset) {
- T(~0, (TSTR("Object %d chunkId %d NAND mismatch chunk %d tags (%d:%d)"TENDSTR),
- objectId, chunkOffset, theChunk,
- tags.objectId, tags.chunkId));
- }
- }
- chunkOffset++;
- }
- }
- }
-
- return ok;
-
-}
-
-#endif
-
-static void yaffs_VerifyFile(yaffs_Object *obj)
-{
- int requiredTallness;
- int actualTallness;
- __u32 lastChunk;
- __u32 x;
- __u32 i;
- yaffs_Device *dev;
- yaffs_ExtendedTags tags;
- yaffs_Tnode *tn;
- __u32 objectId;
-
- if (!obj)
- return;
-
- if (yaffs_SkipVerification(obj->myDev))
- return;
-
- dev = obj->myDev;
- objectId = obj->objectId;
-
- /* Check file size is consistent with tnode depth */
- lastChunk = obj->variant.fileVariant.fileSize / dev->nDataBytesPerChunk + 1;
- x = lastChunk >> YAFFS_TNODES_LEVEL0_BITS;
- requiredTallness = 0;
- while (x > 0) {
- x >>= YAFFS_TNODES_INTERNAL_BITS;
- requiredTallness++;
- }
-
- actualTallness = obj->variant.fileVariant.topLevel;
-
- /* Check that the chunks in the tnode tree are all correct.
- * We do this by scanning through the tnode tree and
- * checking the tags for every chunk match.
- */
-
- if (yaffs_SkipNANDVerification(dev))
- return;
-
- for (i = 1; i <= lastChunk; i++) {
- tn = yaffs_FindLevel0Tnode(dev, &obj->variant.fileVariant, i);
-
- if (tn) {
- __u32 theChunk = yaffs_GetChunkGroupBase(dev, tn, i);
- if (theChunk > 0) {
- /* T(~0,(TSTR("verifying (%d:%d) %d"TENDSTR),objectId,i,theChunk)); */
- yaffs_ReadChunkWithTagsFromNAND(dev, theChunk, NULL, &tags);
- if (tags.objectId != objectId || tags.chunkId != i) {
- T(~0, (TSTR("Object %d chunkId %d NAND mismatch chunk %d tags (%d:%d)"TENDSTR),
- objectId, i, theChunk,
- tags.objectId, tags.chunkId));
- }
- }
- }
- }
-}
-
-
-static void yaffs_VerifyHardLink(yaffs_Object *obj)
-{
- if (obj && yaffs_SkipVerification(obj->myDev))
- return;
-
- /* Verify sane equivalent object */
-}
-
-static void yaffs_VerifySymlink(yaffs_Object *obj)
-{
- if (obj && yaffs_SkipVerification(obj->myDev))
- return;
-
- /* Verify symlink string */
-}
-
-static void yaffs_VerifySpecial(yaffs_Object *obj)
-{
- if (obj && yaffs_SkipVerification(obj->myDev))
- return;
-}
-
-static void yaffs_VerifyObject(yaffs_Object *obj)
-{
- yaffs_Device *dev;
-
- __u32 chunkMin;
- __u32 chunkMax;
-
- __u32 chunkIdOk;
- __u32 chunkInRange;
- __u32 chunkShouldNotBeDeleted;
- __u32 chunkValid;
-
- if (!obj)
- return;
-
- if (obj->beingCreated)
- return;
-
- dev = obj->myDev;
-
- if (yaffs_SkipVerification(dev))
- return;
-
- /* Check sane object header chunk */
-
- chunkMin = dev->internalStartBlock * dev->param.nChunksPerBlock;
- chunkMax = (dev->internalEndBlock+1) * dev->param.nChunksPerBlock - 1;
-
- chunkInRange = (((unsigned)(obj->hdrChunk)) >= chunkMin && ((unsigned)(obj->hdrChunk)) <= chunkMax);
- chunkIdOk = chunkInRange || (obj->hdrChunk == 0);
- chunkValid = chunkInRange &&
- yaffs_CheckChunkBit(dev,
- obj->hdrChunk / dev->param.nChunksPerBlock,
- obj->hdrChunk % dev->param.nChunksPerBlock);
- chunkShouldNotBeDeleted = chunkInRange && !chunkValid;
-
- if (!obj->fake &&
- (!chunkIdOk || chunkShouldNotBeDeleted)) {
- T(YAFFS_TRACE_VERIFY,
- (TSTR("Obj %d has chunkId %d %s %s"TENDSTR),
- obj->objectId, obj->hdrChunk,
- chunkIdOk ? "" : ",out of range",
- chunkShouldNotBeDeleted ? ",marked as deleted" : ""));
- }
-
- if (chunkValid && !yaffs_SkipNANDVerification(dev)) {
- yaffs_ExtendedTags tags;
- yaffs_ObjectHeader *oh;
- __u8 *buffer = yaffs_GetTempBuffer(dev, __LINE__);
-
- oh = (yaffs_ObjectHeader *)buffer;
-
- yaffs_ReadChunkWithTagsFromNAND(dev, obj->hdrChunk, buffer,
- &tags);
-
- yaffs_VerifyObjectHeader(obj, oh, &tags, 1);
-
- yaffs_ReleaseTempBuffer(dev, buffer, __LINE__);
- }
-
- /* Verify it has a parent */
- if (obj && !obj->fake &&
- (!obj->parent || obj->parent->myDev != dev)) {
- T(YAFFS_TRACE_VERIFY,
- (TSTR("Obj %d has parent pointer %p which does not look like an object"TENDSTR),
- obj->objectId, obj->parent));
- }
-
- /* Verify parent is a directory */
- if (obj->parent && obj->parent->variantType != YAFFS_OBJECT_TYPE_DIRECTORY) {
- T(YAFFS_TRACE_VERIFY,
- (TSTR("Obj %d's parent is not a directory (type %d)"TENDSTR),
- obj->objectId, obj->parent->variantType));
- }
-
- switch (obj->variantType) {
- case YAFFS_OBJECT_TYPE_FILE:
- yaffs_VerifyFile(obj);
- break;
- case YAFFS_OBJECT_TYPE_SYMLINK:
- yaffs_VerifySymlink(obj);
- break;
- case YAFFS_OBJECT_TYPE_DIRECTORY:
- yaffs_VerifyDirectory(obj);
- break;
- case YAFFS_OBJECT_TYPE_HARDLINK:
- yaffs_VerifyHardLink(obj);
- break;
- case YAFFS_OBJECT_TYPE_SPECIAL:
- yaffs_VerifySpecial(obj);
- break;
- case YAFFS_OBJECT_TYPE_UNKNOWN:
- default:
- T(YAFFS_TRACE_VERIFY,
- (TSTR("Obj %d has illegaltype %d"TENDSTR),
- obj->objectId, obj->variantType));
- break;
- }
-}
-
-void yaffs_VerifyObjects(yaffs_Device *dev)
-{
- yaffs_Object *obj;
- int i;
- struct ylist_head *lh;
-
- if (yaffs_SkipVerification(dev))
- return;
-
- /* Iterate through the objects in each hash entry */
-
- for (i = 0; i < YAFFS_NOBJECT_BUCKETS; i++) {
- ylist_for_each(lh, &dev->objectBucket[i].list) {
- if (lh) {
- obj = ylist_entry(lh, yaffs_Object, hashLink);
- yaffs_VerifyObject(obj);
- }
- }
- }
-}
-
/*
* Simple hash function. Needs to have a reasonable spread
/* let's give it a try */
attempts++;
-#ifdef CONFIG_YAFFS_ALWAYS_CHECK_CHUNK_ERASED
- bi->skipErasedCheck = 0;
-#endif
+ if(dev->param.alwaysCheckErased)
+ bi->skipErasedCheck = 0;
+
if (!bi->skipErasedCheck) {
erasedOk = yaffs_CheckChunkErased(dev, chunk);
if (erasedOk != YAFFS_OK) {
obj->sum = yaffs_CalcNameSum(name);
}
+void yaffs_SetObjectNameFromOH(yaffs_Object *obj, const yaffs_ObjectHeader *oh)
+{
+#ifdef CONFIG_YAFFS_AUTO_UNICODE
+ YCHAR tmpName[YAFFS_MAX_NAME_LENGTH+1];
+ memset(tmpName,0,sizeof(tmpName));
+ yaffs_LoadNameFromObjectHeader(obj->myDev,tmpName,oh->name,YAFFS_MAX_NAME_LENGTH+1);
+ yaffs_SetObjectName(obj,tmpName);
+#else
+ yaffs_SetObjectName(obj,oh->name);
+#endif
+}
+
/*-------------------- TNODES -------------------
* List of spare tnodes
}
}
-static __u32 yaffs_GetChunkGroupBase(yaffs_Device *dev, yaffs_Tnode *tn,
+__u32 yaffs_GetChunkGroupBase(yaffs_Device *dev, yaffs_Tnode *tn,
unsigned pos)
{
__u32 *map = (__u32 *)tn;
*/
/* FindLevel0Tnode finds the level 0 tnode, if one exists. */
-static yaffs_Tnode *yaffs_FindLevel0Tnode(yaffs_Device *dev,
+yaffs_Tnode *yaffs_FindLevel0Tnode(yaffs_Device *dev,
yaffs_FileStructure *fStruct,
__u32 chunkId)
{
int newChunk;
int markNAND;
int retVal = YAFFS_OK;
- int cleanups = 0;
int i;
int isCheckpointBlock;
int matchingChunk;
* We have to decrement free chunks so this works out properly.
*/
dev->nFreeChunks--;
+ bi->softDeletions--;
object->nDataChunks--;
if (object->nDataChunks <= 0) {
/* remeber to clean up the object */
- dev->gcCleanupList[cleanups] =
+ dev->gcCleanupList[dev->nCleanups] =
tags.objectId;
- cleanups++;
+ dev->nCleanups++;
}
markNAND = 0;
} else if (0) {
yaffs_ReleaseTempBuffer(dev, buffer, __LINE__);
+
+ }
+
+ yaffs_VerifyCollectedBlock(dev, bi, block);
+
+
+
+ if (bi->blockState == YAFFS_BLOCK_STATE_COLLECTING) {
+ /*
+ * The gc did not complete. Set block state back to FULL
+ * because checkpointing does not restore gc.
+ */
+ bi->blockState = YAFFS_BLOCK_STATE_FULL;
+ } else {
+ /* The gc completed. */
/* Do any required cleanups */
- for (i = 0; i < cleanups; i++) {
+ for (i = 0; i < dev->nCleanups; i++) {
/* Time to delete the file too */
object =
yaffs_FindObjectByNumber(dev,
}
- }
-
- yaffs_VerifyCollectedBlock(dev, bi, block);
-
-
- if (bi->blockState == YAFFS_BLOCK_STATE_COLLECTING) {
- /*
- * The gc did not complete. Set block state back to FULL
- * because checkpointing does not restore gc.
- */
- bi->blockState = YAFFS_BLOCK_STATE_FULL;
- } else {
- /* The gc completed. */
chunksAfter = yaffs_GetErasedChunks(dev);
if (chunksBefore >= chunksAfter) {
T(YAFFS_TRACE_GC,
}
dev->gcBlock = 0;
dev->gcChunk = 0;
+ dev->nCleanups = 0;
}
dev->gcDisable = 0;
threshold = dev->param.nChunksPerBlock;
iterations = nBlocks;
} else {
- int maxThreshold = dev->param.nChunksPerBlock/2;
+ int maxThreshold;
+
+ if(background)
+ maxThreshold = dev->param.nChunksPerBlock/2;
+ else
+ maxThreshold = dev->param.nChunksPerBlock/8;
+
+ if(maxThreshold < YAFFS_GC_PASSIVE_THRESHOLD)
+ maxThreshold = YAFFS_GC_PASSIVE_THRESHOLD;
+
threshold = background ?
(dev->gcNotDone + 2) * 2 : 0;
if(threshold <YAFFS_GC_PASSIVE_THRESHOLD)
dev->param.nChunksPerBlock - dev->gcPagesInUse,
prioritised));
+ dev->nGCBlocks++;
if(background)
dev->backgroundGCs++;
+
dev->gcDirtiest = 0;
dev->gcPagesInUse = 0;
dev->gcNotDone = 0;
int aggressive = 0;
int gcOk = YAFFS_OK;
int maxTries = 0;
-
int minErased;
int erasedChunks;
-
int checkpointBlockAdjust;
if(dev->param.gcControl &&
if (dev->nErasedBlocks < minErased)
aggressive = 1;
else {
+ if(!background && erasedChunks > (dev->nFreeChunks / 4))
+ break;
+
if(dev->gcSkip > 20)
dev->gcSkip = 20;
if(erasedChunks < dev->nFreeChunks/2 ||
if (dev->gcBlock < 1 && !aggressive) {
dev->gcBlock = yaffs2_FindRefreshBlock(dev);
dev->gcChunk = 0;
+ dev->nCleanups=0;
}
if (dev->gcBlock < 1) {
dev->gcBlock = yaffs_FindBlockForGarbageCollection(dev, aggressive, background);
dev->gcChunk = 0;
+ dev->nCleanups=0;
}
if (dev->gcBlock > 0) {
return retVal;
}
-#ifdef YAFFS_PARANOID
-
-static int yaffs_CheckFileSanity(yaffs_Object *in)
-{
- int chunk;
- int nChunks;
- int fSize;
- int failed = 0;
- int objId;
- yaffs_Tnode *tn;
- yaffs_Tags localTags;
- yaffs_Tags *tags = &localTags;
- int theChunk;
- int chunkDeleted;
-
- if (in->variantType != YAFFS_OBJECT_TYPE_FILE)
- return YAFFS_FAIL;
-
- objId = in->objectId;
- fSize = in->variant.fileVariant.fileSize;
- nChunks =
- (fSize + in->myDev->nDataBytesPerChunk - 1) / in->myDev->nDataBytesPerChunk;
-
- for (chunk = 1; chunk <= nChunks; chunk++) {
- tn = yaffs_FindLevel0Tnode(in->myDev, &in->variant.fileVariant,
- chunk);
-
- if (tn) {
-
- theChunk = yaffs_GetChunkGroupBase(dev, tn, chunk);
-
- if (yaffs_CheckChunkBits
- (dev, theChunk / dev->param.nChunksPerBlock,
- theChunk % dev->param.nChunksPerBlock)) {
-
- yaffs_ReadChunkTagsFromNAND(in->myDev, theChunk,
- tags,
- &chunkDeleted);
- if (yaffs_TagsMatch
- (tags, in->objectId, chunk, chunkDeleted)) {
- /* found it; */
-
- }
- } else {
-
- failed = 1;
- }
-
- } else {
- /* T(("No level 0 found for %d\n", chunk)); */
- }
- }
-
- return failed ? YAFFS_FAIL : YAFFS_OK;
-}
-
-#endif
int yaffs_PutChunkIntoFile(yaffs_Object *in, int chunkInInode,
int chunkInNAND, int inScan)
if (prevChunkId > 0)
yaffs_DeleteChunk(dev, prevChunkId, 1, __LINE__);
- yaffs_CheckFileSanity(in);
+ yaffs_VerifyFileSanity(in);
}
return newChunkId;
int newChunkId;
yaffs_ExtendedTags newTags;
yaffs_ExtendedTags oldTags;
- YCHAR *alias = NULL;
+ const YCHAR *alias = NULL;
__u8 *buffer = NULL;
YCHAR oldName[YAFFS_MAX_NAME_LENGTH + 1];
if (name && *name) {
memset(oh->name, 0, sizeof(oh->name));
- yaffs_strncpy(oh->name, name, YAFFS_MAX_NAME_LENGTH);
+ yaffs_LoadObjectHeaderFromName(dev,oh->name,name);
} else if (prevChunkId > 0)
memcpy(oh->name, oldName, sizeof(oh->name));
else
/* process any xattrib modifications */
if(xmod)
- yaffs_ApplyXMod(dev, (char *)buffer, xmod);
+ yaffs_ApplyXMod(in, (char *)buffer, xmod);
/* Tags */
struct ylist_head *n;
yaffs_Object *l;
+ if (dev->readOnly)
+ return;
+
/* Soft delete all the unlinked files */
ylist_for_each_safe(i, n,
&dev->unlinkedDir->variant.directoryVariant.children) {
int depthLimit;
int hanging;
+ if (dev->readOnly)
+ return;
/* Iterate through the objects in each hash entry,
* looking at each object.
in->yst_rdev = oh->yst_rdev;
#endif
- yaffs_SetObjectName(in, oh->name);
+ yaffs_SetObjectNameFromOH(in, oh);
if (in->variantType == YAFFS_OBJECT_TYPE_SYMLINK) {
in->variant.symLinkVariant.alias =
/*------------------------------ Directory Functions ----------------------------- */
-static void yaffs_VerifyObjectInDirectory(yaffs_Object *obj)
-{
- struct ylist_head *lh;
- yaffs_Object *listObj;
-
- int count = 0;
-
- if (!obj) {
- T(YAFFS_TRACE_ALWAYS, (TSTR("No object to verify" TENDSTR)));
- YBUG();
- return;
- }
-
- if (yaffs_SkipVerification(obj->myDev))
- return;
-
- if (!obj->parent) {
- T(YAFFS_TRACE_ALWAYS, (TSTR("Object does not have parent" TENDSTR)));
- YBUG();
- return;
- }
-
- if (obj->parent->variantType != YAFFS_OBJECT_TYPE_DIRECTORY) {
- T(YAFFS_TRACE_ALWAYS, (TSTR("Parent is not directory" TENDSTR)));
- YBUG();
- }
-
- /* Iterate through the objects in each hash entry */
-
- ylist_for_each(lh, &obj->parent->variant.directoryVariant.children) {
- if (lh) {
- listObj = ylist_entry(lh, yaffs_Object, siblings);
- yaffs_VerifyObject(listObj);
- if (obj == listObj)
- count++;
- }
- }
-
- if (count != 1) {
- T(YAFFS_TRACE_ALWAYS, (TSTR("Object in directory %d times" TENDSTR), count));
- YBUG();
- }
-}
-
-static void yaffs_VerifyDirectory(yaffs_Object *directory)
-{
- struct ylist_head *lh;
- yaffs_Object *listObj;
-
- if (!directory) {
- YBUG();
- return;
- }
-
- if (yaffs_SkipFullVerification(directory->myDev))
- return;
-
- if (directory->variantType != YAFFS_OBJECT_TYPE_DIRECTORY) {
- T(YAFFS_TRACE_ALWAYS, (TSTR("Directory has wrong type: %d" TENDSTR), directory->variantType));
- YBUG();
- }
-
- /* Iterate through the objects in each hash entry */
-
- ylist_for_each(lh, &directory->variant.directoryVariant.children) {
- if (lh) {
- listObj = ylist_entry(lh, yaffs_Object, siblings);
- if (listObj->parent != directory) {
- T(YAFFS_TRACE_ALWAYS, (TSTR("Object in directory list has wrong parent %p" TENDSTR), listObj->parent));
- YBUG();
- }
- yaffs_VerifyObjectInDirectory(listObj);
- }
- }
-}
-
/*
*yaffs_UpdateParent() handles fixing a directories mtime and ctime when a new
* link (ie. name) is created or deleted in the directory.
yaffs_Device *dev;
if(!obj)
return;
+#ifndef CONFIG_YAFFS_WINCE
dev = obj->myDev;
obj->dirty = 1;
} else
yaffs_UpdateObjectHeader(obj, NULL, 0, 0, 0, NULL);
+#endif
}
void yaffs_UpdateDirtyDirectories(yaffs_Device *dev)
return obj;
}
-int yaffs_GetObjectName(yaffs_Object *obj, YCHAR *name, int buffSize)
-{
- memset(name, 0, buffSize * sizeof(YCHAR));
-
- yaffs_CheckObjectDetailsLoaded(obj);
+/*
+ * A note or two on object names.
+ * * If the object name is missing, we then make one up in the form objnnn
+ *
+ * * ASCII names are stored in the object header's name field from byte zero
+ * * Unicode names are historically stored starting from byte zero.
+ *
+ * Then there are automatic Unicode names...
+ * The purpose of these is to save names in a way that can be read as
+ * ASCII or Unicode names as appropriate, thus allowing a Unicode and ASCII
+ * system to share files.
+ *
+ * These automatic unicode are stored slightly differently...
+ * - If the name can fit in the ASCII character space then they are saved as
+ * ascii names as per above.
+ * - If the name needs Unicode then the name is saved in Unicode
+ * starting at oh->name[1].
- if (obj->objectId == YAFFS_OBJECTID_LOSTNFOUND) {
- yaffs_strncpy(name, YAFFS_LOSTNFOUND_NAME, buffSize - 1);
- } else if (obj->hdrChunk <= 0) {
+ */
+static void yaffs_FixNullName(yaffs_Object * obj,YCHAR * name, int buffSize)
+{
+ /* Create an object name if we could not find one. */
+ if(yaffs_strnlen(name,YAFFS_MAX_NAME_LENGTH) == 0){
YCHAR locName[20];
YCHAR numString[20];
YCHAR *x = &numString[19];
unsigned v = obj->objectId;
numString[19] = 0;
- while (v > 0) {
+ while(v>0){
x--;
*x = '0' + (v % 10);
v /= 10;
}
/* make up a name */
yaffs_strcpy(locName, YAFFS_LOSTNFOUND_PREFIX);
- yaffs_strcat(locName, x);
+ yaffs_strcat(locName,x);
yaffs_strncpy(name, locName, buffSize - 1);
+ }
+}
+static void yaffs_LoadNameFromObjectHeader(yaffs_Device *dev,YCHAR *name, const YCHAR *ohName, int bufferSize)
+{
+#ifdef CONFIG_YAFFS_AUTO_UNICODE
+ if(dev->param.autoUnicode){
+ if(*ohName){
+ /* It is an ASCII name, so do an ASCII to unicode conversion */
+ const char *asciiOhName = (const char *)ohName;
+ int n = bufferSize - 1;
+ while(n > 0 && *asciiOhName){
+ *name = *asciiOhName;
+ name++;
+ asciiOhName++;
+ n--;
+ }
+ } else
+ yaffs_strncpy(name,ohName+1, bufferSize -1);
+ } else
+#endif
+ yaffs_strncpy(name, ohName, bufferSize - 1);
+}
+
+
+static void yaffs_LoadObjectHeaderFromName(yaffs_Device *dev, YCHAR *ohName, const YCHAR *name)
+{
+#ifdef CONFIG_YAFFS_AUTO_UNICODE
+
+ int isAscii;
+ YCHAR *w;
+
+ if(dev->param.autoUnicode){
+
+ isAscii = 1;
+ w = name;
+
+ /* Figure out if the name will fit in ascii character set */
+ while(isAscii && *w){
+ if((*w) & 0xff00)
+ isAscii = 0;
+ w++;
+ }
+
+ if(isAscii){
+ /* It is an ASCII name, so do a unicode to ascii conversion */
+ char *asciiOhName = (char *)ohName;
+ int n = YAFFS_MAX_NAME_LENGTH - 1;
+ while(n > 0 && *name){
+ *asciiOhName= *name;
+ name++;
+ asciiOhName++;
+ n--;
+ }
+ } else{
+ /* It is a unicode name, so save starting at the second YCHAR */
+ *ohName = 0;
+ yaffs_strncpy(ohName+1,name, YAFFS_MAX_NAME_LENGTH -2);
+ }
}
+ else
+#endif
+ yaffs_strncpy(ohName,name, YAFFS_MAX_NAME_LENGTH - 1);
+
+}
+
+int yaffs_GetObjectName(yaffs_Object * obj, YCHAR * name, int buffSize)
+{
+ memset(name, 0, buffSize * sizeof(YCHAR));
+
+ yaffs_CheckObjectDetailsLoaded(obj);
+
+ if (obj->objectId == YAFFS_OBJECTID_LOSTNFOUND) {
+ yaffs_strncpy(name, YAFFS_LOSTNFOUND_NAME, buffSize - 1);
+ }
#ifdef CONFIG_YAFFS_SHORT_NAMES_IN_RAM
- else if (obj->shortName[0])
- yaffs_strncpy(name, obj->shortName,YAFFS_SHORT_NAME_LENGTH+1);
+ else if (obj->shortName[0]) {
+ yaffs_strcpy(name, obj->shortName);
+ }
#endif
- else {
+ else if(obj->hdrChunk > 0) {
int result;
__u8 *buffer = yaffs_GetTempBuffer(obj->myDev, __LINE__);
obj->hdrChunk, buffer,
NULL);
}
- yaffs_strncpy(name, oh->name, buffSize - 1);
- name[buffSize-1]=0;
+ yaffs_LoadNameFromObjectHeader(obj->myDev,name,oh->name,buffSize);
yaffs_ReleaseTempBuffer(obj->myDev, buffer, __LINE__);
}
- return yaffs_strnlen(name,buffSize-1);
+ yaffs_FixNullName(obj,name,buffSize);
+
+ return yaffs_strnlen(name,YAFFS_MAX_NAME_LENGTH);
}
+
int yaffs_GetObjectFileLength(yaffs_Object *obj)
{
/* Dereference any hard linking */
#endif
-static int yaffs_DoXMod(yaffs_Object *obj, int set, const char *name, const void *value, int size, int flags)
+static int yaffs_DoXMod(yaffs_Object *obj, int set, const YCHAR *name, const void *value, int size, int flags)
{
yaffs_XAttrMod xmod;
return -ENOSPC;
}
-static int yaffs_ApplyXMod(yaffs_Device *dev, char *buffer, yaffs_XAttrMod *xmod)
+static int yaffs_ApplyXMod(yaffs_Object *obj, char *buffer, yaffs_XAttrMod *xmod)
{
int retval = 0;
int x_offs = sizeof(yaffs_ObjectHeader);
+ yaffs_Device *dev = obj->myDev;
int x_size = dev->nDataBytesPerChunk - sizeof(yaffs_ObjectHeader);
char * x_buffer = buffer + x_offs;
else
retval = nval_del(x_buffer, x_size, xmod->name);
+ obj->hasXattr = nval_hasvalues(x_buffer, x_size);
+ obj->xattrKnown = 1;
+
xmod->result = retval;
return retval;
}
-static int yaffs_DoXFetch(yaffs_Object *obj, const char *name, void *value, int size)
+static int yaffs_DoXFetch(yaffs_Object *obj, const YCHAR *name, void *value, int size)
{
char *buffer = NULL;
int result;
int x_offs = sizeof(yaffs_ObjectHeader);
int x_size = dev->nDataBytesPerChunk - sizeof(yaffs_ObjectHeader);
- __u8 * x_buffer;
+ char * x_buffer;
int retval = 0;
if(obj->hdrChunk < 1)
return -ENODATA;
- buffer = yaffs_GetTempBuffer(dev, __LINE__);
+ /* If we know that the object has no xattribs then don't do all the
+ * reading and parsing.
+ */
+ if(obj->xattrKnown && !obj->hasXattr){
+ if(name)
+ return -ENODATA;
+ else
+ return 0;
+ }
+
+ buffer = (char *) yaffs_GetTempBuffer(dev, __LINE__);
if(!buffer)
return -ENOMEM;
- result = yaffs_ReadChunkWithTagsFromNAND(dev,obj->hdrChunk, buffer, &tags);
+ result = yaffs_ReadChunkWithTagsFromNAND(dev,obj->hdrChunk, (__u8 *)buffer, &tags);
if(result != YAFFS_OK)
retval = -ENOENT;
else{
x_buffer = buffer + x_offs;
+ if (!obj->xattrKnown){
+ obj->hasXattr = nval_hasvalues(x_buffer, x_size);
+ obj->xattrKnown = 1;
+ }
+
if(name)
retval = nval_get(x_buffer, x_size, name, value, size);
else
retval = nval_list(x_buffer, x_size, value,size);
}
- yaffs_ReleaseTempBuffer(dev,buffer,__LINE__);
+ yaffs_ReleaseTempBuffer(dev,(__u8 *)buffer,__LINE__);
return retval;
}
-int yaffs_SetXAttribute(yaffs_Object *obj, const char *name, const void * value, int size, int flags)
+int yaffs_SetXAttribute(yaffs_Object *obj, const YCHAR *name, const void * value, int size, int flags)
{
return yaffs_DoXMod(obj, 1, name, value, size, flags);
}
-int yaffs_RemoveXAttribute(yaffs_Object *obj, const char *name)
+int yaffs_RemoveXAttribute(yaffs_Object *obj, const YCHAR *name)
{
return yaffs_DoXMod(obj, 0, name, NULL, 0, 0);
}
-int yaffs_GetXAttribute(yaffs_Object *obj, const char *name, void *value, int size)
+int yaffs_GetXAttribute(yaffs_Object *obj, const YCHAR *name, void *value, int size)
{
return yaffs_DoXFetch(obj, name, value, size);
}
}
}
-static int yaffs_CountFreeChunks(yaffs_Device *dev)
+int yaffs_CountFreeChunks(yaffs_Device *dev)
{
int nFree=0;
int b;
}
-static int yaffs_freeVerificationFailures;
-
-void yaffs_VerifyFreeChunks(yaffs_Device *dev)
-{
- int counted;
- int difference;
-
- if (yaffs_SkipVerification(dev))
- return;
-
- counted = yaffs_CountFreeChunks(dev);
-
- difference = dev->nFreeChunks - counted;
-
- if (difference) {
- T(YAFFS_TRACE_ALWAYS,
- (TSTR("Freechunks verification failure %d %d %d" TENDSTR),
- dev->nFreeChunks, counted, difference));
- yaffs_freeVerificationFailures++;
- }
-}
/*---------------------------------------- YAFFS test code ----------------------*/
/* yaffs_CheckStruct(yaffs_Tags,8,"yaffs_Tags"); */
/* yaffs_CheckStruct(yaffs_TagsUnion,8,"yaffs_TagsUnion"); */
/* yaffs_CheckStruct(yaffs_Spare,16,"yaffs_Spare"); */
-#ifndef CONFIG_YAFFS_TNODE_LIST_DEBUG
/* yaffs_CheckStruct(yaffs_Tnode, 2 * YAFFS_NTNODES_LEVEL0, "yaffs_Tnode"); */
-#endif
+
#ifndef CONFIG_YAFFS_WINCE
yaffs_CheckStruct(yaffs_ObjectHeader, 512, "yaffs_ObjectHeader");
#endif