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
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);
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)
obj->dirty = 1;
yaffs_AddObjectToDirectory(newDir,obj);
- return yaffs_UpdateObjectHeader(obj,newName);
+ if(yaffs_UpdateObjectHeader(obj,newName) >= 0)
+ {
+ return YAFFS_OK;
+ }
}
return YAFFS_FAIL;
}
#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));
}
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
return yaffs_WriteChunkToNAND(dev,chunkInNAND,buffer,&spare);
}
+#endif
+
static int yaffs_WriteNewChunkWithTagsToNAND(yaffs_Device *dev, const __u8 *buffer, yaffs_Tags *tags, int useReserve)
{
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 &&
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 &&
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
{
{
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)
{
int retVal;
if(in->dirty)
{
+ T(("flushing object header\n"));
retVal = yaffs_UpdateObjectHeader(in,NULL);
}
else
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);
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;
__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);
// 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
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 <<c);
+ dev->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));
else
{
// chunkId == 0, so it is an ObjectHeader.
- inuse++;
- pageBits |= ( 1 <<c);
+ // Thus, we read in the object header and make the object
+ dev->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
}
}
- 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;
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);
// 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)
{
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