📄 yaffs_guts.c
字号:
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 %x obj %x oh %x"TENDSTR), (__u32)tags,(__u32)obj,(__u32)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));}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;}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; if(requiredTallness > actualTallness ) T(YAFFS_TRACE_VERIFY, (TSTR("Obj %d had tnode tallness %d, needs to be %d"TENDSTR), obj->objectId,actualTallness, requiredTallness)); /* 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 chunkIsLive; if(!obj) return; dev = obj->myDev; if(yaffs_SkipVerification(dev)) return; /* Check sane object header chunk */ chunkMin = dev->internalStartBlock * dev->nChunksPerBlock; chunkMax = (dev->internalEndBlock+1) * dev->nChunksPerBlock - 1; chunkIdOk = (((unsigned)(obj->hdrChunk)) >= chunkMin && ((unsigned)(obj->hdrChunk)) <= chunkMax); chunkIsLive = chunkIdOk && yaffs_CheckChunkBit(dev, obj->hdrChunk / dev->nChunksPerBlock, obj->hdrChunk % dev->nChunksPerBlock); if(!obj->fake && (!chunkIdOk || !chunkIsLive)) { T(YAFFS_TRACE_VERIFY, (TSTR("Obj %d has chunkId %d %s %s"TENDSTR), obj->objectId,obj->hdrChunk, chunkIdOk ? "" : ",out of range", chunkIsLive || !chunkIdOk ? "" : ",marked as deleted")); } if(chunkIdOk && chunkIsLive &&!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; } }static 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 */ static Y_INLINE int yaffs_HashFunction(int n){ n = abs(n); return (n % YAFFS_NOBJECT_BUCKETS);}/* * Access functions to useful fake objects. * Note that root might have a presence in NAND if permissions are set. */ yaffs_Object *yaffs_Root(yaffs_Device * dev){ return dev->rootDir;}yaffs_Object *yaffs_LostNFound(yaffs_Device * dev){ return dev->lostNFoundDir;}/* * Erased NAND checking functions */ int yaffs_CheckFF(__u8 * buffer, int nBytes){ /* Horrible, slow implementation */ while (nBytes--) { if (*buffer != 0xFF) return 0; buffer++; } return 1;}static int yaffs_CheckChunkErased(struct yaffs_DeviceStruct *dev, int chunkInNAND){ int retval = YAFFS_OK; __u8 *data = yaffs_GetTempBuffer(dev, __LINE__); yaffs_ExtendedTags tags; int result; result = yaffs_ReadChunkWithTagsFromNAND(dev, chunkInNAND, data, &tags); if(tags.eccResult > YAFFS_ECC_RESULT_NO_ERROR) retval = YAFFS_FAIL; if (!yaffs_CheckFF(data, dev->nDataBytesPerChunk) || tags.chunkUsed) { T(YAFFS_TRACE_NANDACCESS, (TSTR("Chunk %d not erased" TENDSTR), chunkInNAND)); retval = YAFFS_FAIL; } yaffs_ReleaseTempBuffer(dev, data, __LINE__); return retval;}static int yaffs_WriteNewChunkWithTagsToNAND(struct yaffs_DeviceStruct *dev, const __u8 * data, yaffs_ExtendedTags * tags, int useReserve){ int attempts = 0; int writeOk = 0; int chunk; yaffs_InvalidateCheckpoint(dev); do { yaffs_BlockInfo *bi = 0; int erasedOk = 0; chunk = yaffs_AllocateChunk(dev, useReserve, &bi); if (chunk < 0) { /* no space */ break; } /* First check this chunk is erased, if it needs * checking. The checking policy (unless forced * always on) is as follows: * * Check the first page we try to write in a block. * If the check passes then we don't need to check any * more. If the check fails, we check again... * If the block has been erased, we don't need to check. * * However, if the block has been prioritised for gc, * then we think there might be something odd about * this block and stop using it. * * Rationale: We should only ever see chunks that have * not been erased if there was a partially written * chunk due to power loss. This checking policy should * catch that case with very few checks and thus save a * lot of checks that are most likely not needed. */ if (bi->gcPrioritise) { yaffs_DeleteChunk(dev, chunk, 1, __LINE__); /* try another chunk */ continue; } /* let's give it a try */ attempts++;#ifdef CONFIG_YAFFS_ALWAYS_CHECK_CHUNK_ERASED bi->skipErasedCheck = 0;#endif if (!bi->skipErasedCheck) { erasedOk = yaffs_CheckChunkErased(dev, chunk); if (erasedOk != YAFFS_OK) { T(YAFFS_TRACE_ERROR, (TSTR ("**>> yaffs chunk %d was not erased" TENDSTR), chunk)); /* try another chunk */ continue; } bi->skipErasedCheck = 1; } writeOk = yaffs_WriteChunkWithTagsToNAND(dev, chunk, data, tags); if (writeOk != YAFFS_OK) { yaffs_HandleWriteChunkError(dev, chunk, erasedOk); /* try another chunk */ continue; } /* Copy the data into the robustification buffer */ yaffs_HandleWriteChunkOk(dev, chunk, data, tags); } while (writeOk != YAFFS_OK && (yaffs_wr_attempts <= 0 || attempts <= yaffs_wr_attempts)); if(!writeOk) chunk = -1; if (attempts > 1) { T(YAFFS_TRACE_ERROR, (TSTR("**>> yaffs write required %d attempts" TENDSTR), attempts)); dev->nRetriedWrites += (attempts - 1); } return chunk;}/* * Block retiring for handling a broken block. */ static void yaffs_RetireBlock(yaffs_Device * dev, int blockInNAND){ yaffs_BlockInfo *bi = yaffs_GetBlockInfo(dev, blockInNAND); yaffs_InvalidateCheckpoint(dev); yaffs_MarkBlockBad(dev, blockInNAND); bi->blockState = YAFFS_BLOCK_STATE_DEAD; bi->gcPrioritise = 0; bi->needsRetiring = 0; dev->nRetiredBlocks++;}/* * Functions for robustisizing TODO * */ static void yaffs_HandleWriteChunkOk(yaffs_Device * dev, int chunkInNAND, const __u8 * data, const yaffs_ExtendedTags * tags){}static void yaffs_HandleUpdateChunk(yaffs_Device * dev, int chunkInNAND, const yaffs_ExtendedTags * tags){}void yaffs_HandleChunkError(yaffs_Device *dev, yaffs_BlockInfo *bi){ if(!bi->gcPrioritise){ bi->gcPrioritise = 1; dev->hasPendingPrioritisedGCs = 1; bi->chunkErrorStrikes ++; if(bi->chunkErrorStrikes > 3){ bi->needsRetiring = 1; /* Too many stikes, so retire this */ T(YAFFS_TRACE_ALWAYS, (TSTR("yaffs: Block struck out" TENDSTR))); } }}static void yaffs_HandleWriteChunkError(yaffs_Device * dev, int chunkInNAND, int erasedOk){
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -