X-Git-Url: http://www.aleph1.co.uk/gitweb/?p=yaffs%2F.git;a=blobdiff_plain;f=yaffs_guts.c;h=4c7e81af75ef9b1c136ec0a4b464cde7272c3ba5;hp=66014bb3f449d95b5a94aec02ff026c17c622c0c;hb=3f107ebf545c27322a15a458198a3cd5dbc876f3;hpb=54a94b218fce5de9c076266fc34c9de5bfcd656b diff --git a/yaffs_guts.c b/yaffs_guts.c index 66014bb..4c7e81a 100644 --- a/yaffs_guts.c +++ b/yaffs_guts.c @@ -75,15 +75,14 @@ static int yaffs_UpdateObjectHeader(yaffs_Object *in,const char *name); static void yaffs_DeleteChunk(yaffs_Device *dev,int chunkId); static void yaffs_RemoveObjectFromDirectory(yaffs_Object *obj); static int yaffs_CheckStructures(void); -static yaffs_Object *yaffs_GetEquivalentObject(yaffs_Object *obj); loff_t yaffs_GetFileSize(yaffs_Object *obj); static int yaffs_AllocateChunk(yaffs_Device *dev,int useReserve); -#if YAFFS_PARANOID -static int yaffs_CheckFileSanity(yaffs_Object *in) +#ifdef YAFFS_PARANOID +static int yaffs_CheckFileSanity(yaffs_Object *in); #else #define yaffs_CheckFileSanity(in) #endif @@ -136,6 +135,39 @@ int yaffs_ReadChunkFromNAND(struct yaffs_DeviceStruct *dev,int chunkInNAND, __u8 return retVal; } +#ifdef YAFFS_PARANOID + +static int yaffs_CheckChunkErased(struct yaffs_DeviceStruct *dev,int chunkInNAND) +{ + static int init = 0; + static __u8 cmpbuf[YAFFS_BYTES_PER_CHUNK]; + static __u8 data[YAFFS_BYTES_PER_CHUNK]; + static __u8 spare[16]; + + int retVal; + + retVal = YAFFS_OK; + + dev->readChunkFromNAND(dev,chunkInNAND,data,(yaffs_Spare *)spare); + + + + if(!init) + { + memset(cmpbuf,0xff,YAFFS_BYTES_PER_CHUNK); + init = 1; + } + + if(memcmp(cmpbuf,data,YAFFS_BYTES_PER_CHUNK)) retVal = YAFFS_FAIL; + if(memcmp(cmpbuf,spare,16)) retVal = YAFFS_FAIL; + + return retVal; + +} + +#endif + + int yaffs_EraseBlockInNAND(struct yaffs_DeviceStruct *dev,int blockInNAND) { return dev->eraseBlockInNAND(dev,blockInNAND); @@ -1094,6 +1126,12 @@ yaffs_Object *yaffs_MknodObject( yaffs_ObjectType type, yaffs_Device *dev = parent->myDev; + // Check if the entry exists. If it does then fail the call since we don't want a dup. + if(yaffs_FindObjectByName(parent,name)) + { + return NULL; + } + in = yaffs_CreateNewObject(dev,-1,type); if(in) @@ -1188,7 +1226,10 @@ static int yaffs_ChangeObjectName(yaffs_Object *obj, yaffs_Object *newDir, const obj->dirty = 1; yaffs_AddObjectToDirectory(newDir,obj); - return yaffs_UpdateObjectHeader(obj,newName); + if(yaffs_UpdateObjectHeader(obj,newName) >= 0) + { + return YAFFS_OK; + } } return YAFFS_FAIL; @@ -1429,7 +1470,7 @@ static int yaffs_AllocateChunk(yaffs_Device *dev,int useReserve) } #ifdef YAFFS_PARANOID - if(yaffs_CheckChunkErased(retVal) == YAFFS_FAIL) + if(yaffs_CheckChunkErased(dev,retVal) == YAFFS_FAIL) { T(("..................Trying to allocate non-erased page %d\n",retVal)); } @@ -1598,6 +1639,7 @@ static int yaffs_ReadChunkTagsFromNAND(yaffs_Device *dev,int chunkInNAND, yaffs_ return YAFFS_OK; } +#if 0 static int yaffs_WriteChunkWithTagsToNAND(yaffs_Device *dev,int chunkInNAND, const __u8 *buffer, yaffs_Tags *tags) { // NB There must be tags, data is optional @@ -1623,6 +1665,8 @@ static int yaffs_WriteChunkWithTagsToNAND(yaffs_Device *dev,int chunkInNAND, con return yaffs_WriteChunkToNAND(dev,chunkInNAND,buffer,&spare); } +#endif + static int yaffs_WriteNewChunkWithTagsToNAND(yaffs_Device *dev, const __u8 *buffer, yaffs_Tags *tags, int useReserve) { @@ -1677,7 +1721,7 @@ int yaffs_FindChunkInFile(yaffs_Object *in,int chunkInInode,yaffs_Tags *tags) theChunk = tn->level0[chunkInInode & YAFFS_TNODES_LEVEL0_MASK] << dev->chunkGroupBits; // Now we need to do the shifting etc and search for it - for(i = 0,found = 0; i < dev->chunkGroupSize && !found; i++) + for(i = 0,found = 0; theChunk && i < dev->chunkGroupSize && !found; i++) { yaffs_ReadChunkTagsFromNAND(dev,theChunk,tags); if(tags->chunkId == chunkInInode && @@ -1719,7 +1763,7 @@ int yaffs_FindAndDeleteChunkInFile(yaffs_Object *in,int chunkInInode,yaffs_Tags theChunk = tn->level0[chunkInInode & YAFFS_TNODES_LEVEL0_MASK] << dev->chunkGroupBits; // Now we need to do the shifting etc and search for it - for(i = 0,found = 0; i < dev->chunkGroupSize && !found; i++) + for(i = 0,found = 0; theChunk && i < dev->chunkGroupSize && !found; i++) { yaffs_ReadChunkTagsFromNAND(dev,theChunk,tags); if(tags->chunkId == chunkInInode && @@ -1780,20 +1824,20 @@ static int yaffs_CheckFileSanity(yaffs_Object *in) for(chunk = 1; chunk <= nChunks; chunk++) { - tn = yaffs_FindLevel0Tnode(&in->variant.fileVariant, chunk); + tn = yaffs_FindLevel0Tnode(in->myDev,&in->variant.fileVariant, chunk); if(tn) { - theChunk = tn->level0[chunk & YAFFS_TNODES_LEVEL0_MASK] << dev->chunkGroupBits; + theChunk = tn->level0[chunk & YAFFS_TNODES_LEVEL0_MASK] << in->myDev->chunkGroupBits; - yaffs_ReadChunkTagsFromNAND(theChunk,tags); + yaffs_ReadChunkTagsFromNAND(in->myDev,theChunk,tags); if(tags->chunkId == chunk && tags->objectId == in->objectId) { // found it; - + } else { @@ -1888,18 +1932,18 @@ static void yaffs_DeleteChunk(yaffs_Device *dev,int chunkId) { int block = chunkId / YAFFS_CHUNKS_PER_BLOCK; int page = chunkId % YAFFS_CHUNKS_PER_BLOCK; - yaffs_Tags tags; + yaffs_Spare spare; + + yaffs_SpareInitialise(&spare); - // Mark the deleted NAND page as deleted - tags.chunkId = 0; - tags.objectId = 0; - tags.byteCount = 0; - tags.ecc = 0; + spare.pageStatus = 0; // To mark it as deleted. + - yaffs_WriteChunkWithTagsToNAND(dev,chunkId,NULL,&tags); + yaffs_WriteChunkToNAND(dev,chunkId,NULL,&spare); // Pull out of the management area. + // If the whole block became dirty, this will kick off an erasure. if( dev->blockInfo[block].blockState == YAFFS_BLOCK_STATE_ALLOCATING || dev->blockInfo[block].blockState == YAFFS_BLOCK_STATE_FULL) { @@ -2370,6 +2414,7 @@ int yaffs_FlushFile(yaffs_Object *in) int retVal; if(in->dirty) { + T(("flushing object header\n")); retVal = yaffs_UpdateObjectHeader(in,NULL); } else @@ -2539,12 +2584,14 @@ static int yaffs_UnlinkWorker(yaffs_Object *obj) char name[YAFFS_MAX_NAME_LENGTH+1]; hl = list_entry(obj->hardLinks.next,yaffs_Object,hardLinks); + list_del_init(&hl->hardLinks); list_del_init(&hl->siblings); yaffs_GetObjectName(hl,name,YAFFS_MAX_NAME_LENGTH+1); retVal = yaffs_ChangeObjectName(obj, hl->parent, name); + if(retVal == YAFFS_OK) { retVal = yaffs_DoGenericObjectDeletion(hl); @@ -2602,12 +2649,12 @@ static int yaffs_Scan(yaffs_Device *dev) int chunk; int c; int deleted; - int inuse; yaffs_BlockState state; yaffs_Object *hardList = NULL; yaffs_Object *hl; - __u32 pageBits; +// int inuse; +// __u32 pageBits; yaffs_ObjectHeader *oh; yaffs_Object *in; @@ -2615,18 +2662,24 @@ static int yaffs_Scan(yaffs_Device *dev) __u8 chunkData[YAFFS_BYTES_PER_CHUNK]; + + // Scan all the blocks... + for(blk = dev->startBlock; blk <= dev->endBlock; blk++) { deleted = 0; - pageBits = 0; - inuse = 0; - state = YAFFS_BLOCK_STATE_UNKNOWN; + dev->blockInfo[blk].pageBits = 0; + dev->blockInfo[blk].pagesInUse = 0; + state = YAFFS_BLOCK_STATE_SCANNING; + + // Read each chunk in the block. for(c = 0; c < YAFFS_CHUNKS_PER_BLOCK && - state == YAFFS_BLOCK_STATE_UNKNOWN; c++) + state == YAFFS_BLOCK_STATE_SCANNING; c++) { // Read the spare area and decide what to do chunk = blk * YAFFS_CHUNKS_PER_BLOCK + c; + yaffs_ReadChunkFromNAND(dev,chunk,NULL,&spare); @@ -2636,7 +2689,14 @@ static int yaffs_Scan(yaffs_Device *dev) // This block looks ok, now what's in this chunk? yaffs_GetTagsFromSpare(&spare,&tags); - if(tags.objectId == YAFFS_UNUSED_OBJECT_ID) + if(yaffs_countBits[spare.pageStatus] < 6) + { + // A deleted chunk + deleted++; + dev->nFreeChunks ++; + T((" %d %d deleted\n",blk,c)); + } + else if(tags.objectId == YAFFS_UNUSED_OBJECT_ID) { // An unassigned chunk in the block // This means that either the block is empty or @@ -2659,20 +2719,14 @@ static int yaffs_Scan(yaffs_Device *dev) dev->nFreeChunks += (YAFFS_CHUNKS_PER_BLOCK - c); } - else if(tags.objectId == 0) - { - // A deleted chunk - deleted++; - dev->nFreeChunks ++; - T((" %d %d deleted\n",blk,c)); - } else if(tags.chunkId > 0) { // A data chunk. - inuse++; - pageBits |= ( 1 <blockInfo[blk].pageBits |= (1 << c); + dev->blockInfo[blk].pagesInUse++; + in = yaffs_FindOrCreateObjectByNumber(dev,tags.objectId,YAFFS_OBJECT_TYPE_FILE); - // PutChuunkIntoFIle checks for a clash (two data chunks with + // PutChunkIntoFIle checks for a clash (two data chunks with // the same chunkId). yaffs_PutChunkIntoFile(in,tags.chunkId,chunk,1); T((" %d %d data %d %d\n",blk,c,tags.objectId,tags.chunkId)); @@ -2680,78 +2734,99 @@ static int yaffs_Scan(yaffs_Device *dev) else { // chunkId == 0, so it is an ObjectHeader. - inuse++; - pageBits |= ( 1 <blockInfo[blk].pageBits |= (1 << c); + dev->blockInfo[blk].pagesInUse++; + yaffs_ReadChunkFromNAND(dev,chunk,chunkData,NULL); + oh = (yaffs_ObjectHeader *)chunkData; in = yaffs_FindOrCreateObjectByNumber(dev,tags.objectId,oh->type); + if(in->valid) { - // todo we have already filled this one. We have - // a duplicate. Need to fix + // We have already filled this one. We have a duplicate and need to resolve it. + + unsigned existingSerial = in->serial; + unsigned newSerial = tags.serialNumber; + + if(((existingSerial+1) & 3) == newSerial) + { + // Use new one - destroy the exisiting one + yaffs_DeleteChunk(dev,in->chunkId); + in->valid = 0; + } + else + { + // Use existing - destroy this one. + yaffs_DeleteChunk(dev,chunk); + } } - // we don't have a duplicate... + if(!in->valid) + { + // we need to load this info - in->valid = 1; - in->variantType = oh->type; - - in->st_mode = oh->st_mode; - in->st_uid = oh->st_uid; - in->st_gid = oh->st_gid; - in->st_atime = oh->st_atime; - in->st_mtime = oh->st_mtime; - in->st_ctime = oh->st_ctime; - in->chunkId = chunk; - - in->sum = oh->sum; - in->dirty = 0; + in->valid = 1; + in->variantType = oh->type; + + in->st_mode = oh->st_mode; + in->st_uid = oh->st_uid; + in->st_gid = oh->st_gid; + in->st_atime = oh->st_atime; + in->st_mtime = oh->st_mtime; + in->st_ctime = oh->st_ctime; + in->chunkId = chunk; + + in->sum = oh->sum; + in->dirty = 0; - // directory stuff... - // hook up to parent - - parent = yaffs_FindOrCreateObjectByNumber(dev,oh->parentObjectId,YAFFS_OBJECT_TYPE_DIRECTORY); - if(parent->variantType == YAFFS_OBJECT_TYPE_UNKNOWN) - { - // Set up as a directory - parent->variantType = YAFFS_OBJECT_TYPE_DIRECTORY; - INIT_LIST_HEAD(&parent->variant.directoryVariant.children); - } - else if(parent->variantType != YAFFS_OBJECT_TYPE_DIRECTORY) - { - // Hoosterman, another problem.... - // We're trying to use a non-directory as a directory - // Todo ... handle - } + // directory stuff... + // hook up to parent + + parent = yaffs_FindOrCreateObjectByNumber(dev,oh->parentObjectId,YAFFS_OBJECT_TYPE_DIRECTORY); + if(parent->variantType == YAFFS_OBJECT_TYPE_UNKNOWN) + { + // Set up as a directory + parent->variantType = YAFFS_OBJECT_TYPE_DIRECTORY; + INIT_LIST_HEAD(&parent->variant.directoryVariant.children); + } + else if(parent->variantType != YAFFS_OBJECT_TYPE_DIRECTORY) + { + // Hoosterman, another problem.... + // We're trying to use a non-directory as a directory + // Todo ... handle + } - yaffs_AddObjectToDirectory(parent,in); + yaffs_AddObjectToDirectory(parent,in); - // Note re hardlinks. - // Since we might scan a hardlink before its equivalent object is scanned - // we put them all in a list. - // After scanning is complete, we should have all the objects, so we run through this - // list and fix up all the chains. - - switch(in->variantType) - { - case YAFFS_OBJECT_TYPE_UNKNOWN: // Todo got a problem - break; - case YAFFS_OBJECT_TYPE_FILE: - in->variant.fileVariant.fileSize = oh->fileSize; - break; - case YAFFS_OBJECT_TYPE_HARDLINK: - in->variant.hardLinkVariant.equivalentObjectId = oh->equivalentObjectId; - (yaffs_Object *)(in->hardLinks.next) = hardList; - hardList = in; - break; - case YAFFS_OBJECT_TYPE_DIRECTORY: // Do nothing - break; - case YAFFS_OBJECT_TYPE_SYMLINK: // Do nothing - in->variant.symLinkVariant.alias = yaffs_CloneString(oh->alias); - break; + // Note re hardlinks. + // Since we might scan a hardlink before its equivalent object is scanned + // we put them all in a list. + // After scanning is complete, we should have all the objects, so we run through this + // list and fix up all the chains. + + switch(in->variantType) + { + case YAFFS_OBJECT_TYPE_UNKNOWN: // Todo got a problem + break; + case YAFFS_OBJECT_TYPE_FILE: + in->variant.fileVariant.fileSize = oh->fileSize; + break; + case YAFFS_OBJECT_TYPE_HARDLINK: + in->variant.hardLinkVariant.equivalentObjectId = oh->equivalentObjectId; + (yaffs_Object *)(in->hardLinks.next) = hardList; + hardList = in; + break; + case YAFFS_OBJECT_TYPE_DIRECTORY: // Do nothing + break; + case YAFFS_OBJECT_TYPE_SYMLINK: // Do nothing + in->variant.symLinkVariant.alias = yaffs_CloneString(oh->alias); + break; + } + T((" %d %d header %d \"%s\" type %d\n",blk,c,tags.objectId,oh->name,in->variantType)); } - T((" %d %d header %d \"%s\" type %d\n",blk,c,tags.objectId,oh->name,in->variantType)); } } else @@ -2761,21 +2836,26 @@ static int yaffs_Scan(yaffs_Device *dev) } } - if(state == YAFFS_BLOCK_STATE_UNKNOWN) + if(state == YAFFS_BLOCK_STATE_SCANNING) { - // If we got this far, then the block is fully allocated. - // ie. Full or Dirty - state = (inuse) ? YAFFS_BLOCK_STATE_FULL : YAFFS_BLOCK_STATE_DIRTY; - + // If we got this far while scanning, then the block is fully allocated. + state = YAFFS_BLOCK_STATE_FULL; } - dev->blockInfo[blk].pageBits = pageBits; - dev->blockInfo[blk].pagesInUse = inuse; dev->blockInfo[blk].blockState = state; + // Now let's see if it was dirty + if( dev->blockInfo[blk].pagesInUse == 0 && + dev->blockInfo[blk].blockState == YAFFS_BLOCK_STATE_FULL) + { + yaffs_BlockBecameDirty(dev,blk); + } + } - // Todo fix up the hard link chains + // Fix up the hard link chains. + // We should now have scanned all the objects, now it's time to add these + // hardlinks. while(hardList) { hl = hardList; @@ -2785,12 +2865,14 @@ static int yaffs_Scan(yaffs_Device *dev) if(in) { + // Add the hardlink pointers hl->variant.hardLinkVariant.equivalentObject=in; list_add(&hl->hardLinks,&in->hardLinks); } else { - //Todo Need to report this better. + //Todo Need to report/handle this better. + // Got a problem... hardlink to a non-existant object hl->variant.hardLinkVariant.equivalentObject=NULL; INIT_LIST_HEAD(&hl->hardLinks); @@ -2896,7 +2978,7 @@ int yaffs_ApplyToDirectoryChildren(yaffs_Object *theDir,int (*fn)(yaffs_Object * // GetEquivalentObject dereferences any hard links to get to the // actual object. -static yaffs_Object *yaffs_GetEquivalentObject(yaffs_Object *obj) +yaffs_Object *yaffs_GetEquivalentObject(yaffs_Object *obj) { if(obj && obj->variantType == YAFFS_OBJECT_TYPE_HARDLINK) { @@ -3058,8 +3140,8 @@ int yaffs_DumpObject(yaffs_Object *obj) yaffs_GetObjectName(obj,name,256); - YPRINTF(("Object %d \"%s\"\n dirty %d valid %d serial %d sum %d chunk %d type %d size %d\n", - yaffs_GetObjectInode(obj), name, obj->dirty, obj->valid, obj->serial, + YPRINTF(("Object %d, inode %d \"%s\"\n dirty %d valid %d serial %d sum %d chunk %d type %d size %d\n", + obj->objectId,yaffs_GetObjectInode(obj), name, obj->dirty, obj->valid, obj->serial, obj->sum, obj->chunkId, yaffs_GetObjectType(obj), yaffs_GetObjectFileLength(obj))); #if 0