*/
const char *yaffs_guts_c_version =
- "$Id: yaffs_guts.c,v 1.59 2008-07-21 01:03:19 charles Exp $";
+ "$Id: yaffs_guts.c,v 1.65 2008-11-26 20:42:04 charles Exp $";
#include "yportenv.h"
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
return;
/* Report illegal runtime states */
- if(bi->blockState <0 || bi->blockState >= YAFFS_NUMBER_OF_BLOCK_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){
yaffs_BlockInfo *bi = yaffs_GetBlockInfo(dev,i);
yaffs_VerifyBlock(dev,bi,i);
- if(bi->blockState >=0 && bi->blockState < YAFFS_NUMBER_OF_BLOCK_STATES)
+ if(bi->blockState < YAFFS_NUMBER_OF_BLOCK_STATES)
nBlocksPerState[bi->blockState]++;
else
nIllegalBlockStates++;
*/
static void yaffs_VerifyObjectHeader(yaffs_Object *obj, yaffs_ObjectHeader *oh, yaffs_ExtendedTags *tags, int parentCheck)
{
- if(yaffs_SkipVerification(obj->myDev))
+ if(obj && yaffs_SkipVerification(obj->myDev))
return;
if(!(tags && obj && oh)){
}
}
} else if (level == 0) {
- int i;
yaffs_ExtendedTags tags;
__u32 objectId = obj->objectId;
yaffs_Tnode *tn;
__u32 objectId;
- if(obj && yaffs_SkipVerification(obj->myDev))
+ if(!obj)
+ return;
+
+ if(yaffs_SkipVerification(obj->myDev))
return;
dev = obj->myDev;
}
-static void yaffs_VerifyDirectory(yaffs_Object *obj)
-{
- if(obj && yaffs_SkipVerification(obj->myDev))
- return;
-
-}
static void yaffs_VerifyHardLink(yaffs_Object *obj)
{
__u16 sum = 0;
__u16 i = 1;
- YUCHAR *bname = (YUCHAR *) name;
+ const YUCHAR *bname = (const YUCHAR *) name;
if (bname) {
while ((*bname) && (i < (YAFFS_MAX_NAME_LENGTH/2))) {
bname++;
}
}
+
return sum;
}
static void yaffs_SetObjectName(yaffs_Object * obj, const YCHAR * name)
{
#ifdef CONFIG_YAFFS_SHORT_NAMES_IN_RAM
+ memset(obj->shortName,0,sizeof (YCHAR) * (YAFFS_SHORT_NAME_LENGTH+1));
if (name && yaffs_strlen(name) <= YAFFS_SHORT_NAME_LENGTH) {
yaffs_strcpy(obj->shortName, name);
} else {
{
yaffs_Object *tn = NULL;
+#ifdef VALGRIND_TEST
+ tn = YMALLOC(sizeof(yaffs_Object));
+#else
/* If there are none left make more */
if (!dev->freeObjects) {
yaffs_CreateFreeObjects(dev, YAFFS_ALLOCATION_NOBJECTS);
dev->freeObjects =
(yaffs_Object *) (dev->freeObjects->siblings.next);
dev->nFreeObjects--;
-
+ }
+#endif
+ if(tn){
/* Now sweeten it up... */
memset(tn, 0, sizeof(yaffs_Object));
YINIT_LIST_HEAD(&(tn->hardLinks));
YINIT_LIST_HEAD(&(tn->hashLink));
YINIT_LIST_HEAD(&tn->siblings);
+
+
+ /* Now make the directory sane */
+ if(dev->rootDir){
+ tn->parent = dev->rootDir;
+ ylist_add(&(tn->siblings),&dev->rootDir->variant.directoryVariant.children);
+ }
/* Add it to the lost and found directory.
* NB Can't put root or lostNFound in lostNFound so
yaffs_Device *dev = tn->myDev;
+
+ if(tn->parent)
+ YBUG();
+ if(!ylist_empty(&tn->siblings))
+ YBUG();
+
+
#ifdef __KERNEL__
if (tn->myInode) {
/* We're still hooked up to a cached inode.
yaffs_UnhashObject(tn);
+#ifdef VALGRIND_TEST
+ YFREE(tn);
+#else
/* Link into the free list. */
tn->siblings.next = (struct ylist_head *)(dev->freeObjects);
dev->freeObjects = tn;
dev->nFreeObjects++;
-
+#endif
dev->nCheckpointBlocksRequired = 0; /* force recalculation*/
}
theObject->yst_atime = theObject->yst_mtime =
theObject->yst_ctime = Y_CURRENT_TIME;
#endif
+
+#if 0
+ theObject->sum_prev = 12345;
+ theObject->sum_trailer = 6789;
+#endif
+
switch (type) {
case YAFFS_OBJECT_TYPE_FILE:
theObject->variant.fileVariant.fileSize = 0;
}
in = yaffs_CreateNewObject(dev, -1, type);
+
+ if(!in)
+ return YAFFS_FAIL;
if(type == YAFFS_OBJECT_TYPE_SYMLINK){
str = yaffs_CloneString(aliasString);
if (newDir->variantType != YAFFS_OBJECT_TYPE_DIRECTORY) {
T(YAFFS_TRACE_ALWAYS,
(TSTR
- ("tragendy: yaffs_ChangeObjectName: newDir is not a directory"
+ ("tragedy: yaffs_ChangeObjectName: newDir is not a directory"
TENDSTR)));
YBUG();
}
int yaffs_RenameObject(yaffs_Object * oldDir, const YCHAR * oldName,
yaffs_Object * newDir, const YCHAR * newName)
{
- yaffs_Object *obj;
- yaffs_Object *existingTarget;
+ yaffs_Object *obj=NULL;
+ yaffs_Object *existingTarget=NULL;
int force = 0;
+
+
+ if(!oldDir || oldDir->variantType != YAFFS_OBJECT_TYPE_DIRECTORY)
+ YBUG();
+ if(!newDir || newDir->variantType != YAFFS_OBJECT_TYPE_DIRECTORY)
+ YBUG();
#ifdef CONFIG_YAFFS_CASE_INSENSITIVE
/* Special case for case insemsitive systems (eg. WinCE).
}
#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)
+ else if (yaffs_strlen(newName) > YAFFS_MAX_NAME_LENGTH)
/* ENAMETOOLONG */
return YAFFS_FAIL;
+ obj = yaffs_FindObjectByName(oldDir, oldName);
+
if (obj && obj->renameAllowed) {
/* Now do the handling for an existing target, if there is one */
* Can't get space to gc
*/
T(YAFFS_TRACE_ERROR,
- (TSTR("yaffs tragedy: no more eraased blocks" TENDSTR)));
+ (TSTR("yaffs tragedy: no more erased blocks" TENDSTR)));
return -1;
}
T(YAFFS_TRACE_ALWAYS,
(TSTR
- ("yaffs tragedy: no more eraased blocks, but there should have been %d"
+ ("yaffs tragedy: no more erased blocks, but there should have been %d"
TENDSTR), dev->nErasedBlocks));
return -1;
static int yaffs_CalcCheckpointBlocksRequired(yaffs_Device *dev)
{
- if(!dev->nCheckpointBlocksRequired){
+ if(!dev->nCheckpointBlocksRequired &&
+ dev->isYaffs2){
/* Not a valid value so recalculate */
int nBytes = 0;
int nBlocks;
int reservedBlocks = dev->nReservedBlocks;
int checkpointBlocks;
- checkpointBlocks = yaffs_CalcCheckpointBlocksRequired(dev) - dev->blocksInCheckpoint;
- if(checkpointBlocks < 0)
- checkpointBlocks = 0;
+ if(dev->isYaffs2){
+ checkpointBlocks = yaffs_CalcCheckpointBlocksRequired(dev) -
+ dev->blocksInCheckpoint;
+ if(checkpointBlocks < 0)
+ checkpointBlocks = 0;
+ } else {
+ checkpointBlocks =0;
+ }
reservedChunks = ((reservedBlocks + checkpointBlocks) * dev->nChunksPerBlock);
yaffs_VerifyBlock(dev,bi,block);
for (chunkInBlock = 0, oldChunk = block * dev->nChunksPerBlock;
+ retVal == YAFFS_OK &&
chunkInBlock < dev->nChunksPerBlock
&& yaffs_StillSomeChunkBits(dev, block);
chunkInBlock++, oldChunk++) {
tags.objectId, tags.chunkId, tags.byteCount));
}
- if (object && object->deleted
- && tags.chunkId != 0) {
- /* Data chunk in a deleted file, throw it away
+ if (object &&
+ object->deleted &&
+ object->softDeleted &&
+ tags.chunkId != 0) {
+ /* Data chunk in a soft deleted file, throw it away
* It's a soft deleted data chunk,
* No need to copy this, just forget about it and
* fix up the object.
yaffs_ObjectHeader *oh;
oh = (yaffs_ObjectHeader *)buffer;
oh->isShrink = 0;
- oh->shadowsObject = oh->inbandShadowsObject = -1;
+/* oh->shadowsObject = oh->inbandShadowsObject = -1; */
tags.extraShadows = 0;
tags.extraIsShrinkHeader = 0;
}
}
- yaffs_DeleteChunk(dev, oldChunk, markNAND, __LINE__);
+ if(retVal == YAFFS_OK)
+ yaffs_DeleteChunk(dev, oldChunk, markNAND, __LINE__);
}
}
dev->isDoingGC = 0;
- return YAFFS_OK;
+ return retVal;
}
/* New garbage collector
* not be loaded during a scan
*/
- newSerial = newTags.serialNumber;
- existingSerial = existingTags.serialNumber;
+ if(inScan > 0) {
+ newSerial = newTags.serialNumber;
+ existingSerial = existingTags.serialNumber;
+ }
if ((inScan > 0) &&
(in->myDev->isYaffs2 ||
newTags.serialNumber =
(prevChunkId >= 0) ? prevTags.serialNumber + 1 : 1;
newTags.byteCount = nBytes;
+
+ if(nBytes < 1 || nBytes > dev->totalBytesPerChunk){
+ T(YAFFS_TRACE_ERROR,
+ (TSTR("Writing %d bytes to chunk!!!!!!!!!" TENDSTR), nBytes));
+ while(1){}
+ }
+
+
newChunkId =
yaffs_WriteNewChunkWithTagsToNAND(dev, buffer, &newTags,
static yaffs_ChunkCache *yaffs_GrabChunkCacheWorker(yaffs_Device * dev)
{
int i;
- int usage;
- int theOne;
if (dev->nShortOpCaches > 0) {
for (i = 0; i < dev->nShortOpCaches; i++) {
if (!dev->srCache[i].object)
return &dev->srCache[i];
}
-
- return NULL;
-
- theOne = -1;
- usage = 0; /* just to stop the compiler grizzling */
-
- for (i = 0; i < dev->nShortOpCaches; i++) {
- if (!dev->srCache[i].dirty &&
- ((dev->srCache[i].lastUse < usage && theOne >= 0) ||
- theOne < 0)) {
- usage = dev->srCache[i].lastUse;
- theOne = i;
- }
- }
-
-
- return theOne >= 0 ? &dev->srCache[theOne] : NULL;
- } else {
- return NULL;
}
+ return NULL;
}
static yaffs_ChunkCache *yaffs_GrabChunkCache(yaffs_Device * dev)
//chunk = offset / dev->nDataBytesPerChunk + 1;
//start = offset % dev->nDataBytesPerChunk;
yaffs_AddrToChunk(dev,offset,&chunk,&start);
+
+ if(chunk * dev->nDataBytesPerChunk + start != offset ||
+ start >= dev->nDataBytesPerChunk){
+ T(YAFFS_TRACE_ERROR,(TSTR("AddrToChunk of offset %d gives chunk %d start %d"TENDSTR),
+ (int)offset, chunk,start));
+ }
chunk++;
/* OK now check for the curveball where the start and end are in
nToWriteBack =
(nBytesRead >
- (start + n)) ? nBytesRead : (start + n);
+ ((int)start + n)) ? nBytesRead : (start + n);
} else {
nToCopy = dev->nDataBytesPerChunk - start;
* show we've shrunk the file, if need be
* Do this only if the file is not in the deleted directories.
*/
- if (in->parent->objectId != YAFFS_OBJECTID_UNLINKED &&
+ if (in->parent &&
+ in->parent->objectId != YAFFS_OBJECTID_UNLINKED &&
in->parent->objectId != YAFFS_OBJECTID_DELETED) {
yaffs_UpdateObjectHeader(in, NULL, 0,
(newSize < oldFileSize) ? 1 : 0, 0);
* and the inode associated with the file.
* It does not delete the links associated with the file.
*/
+
static int yaffs_UnlinkFile(yaffs_Object * in)
{
int retVal;
int immediateDeletion = 0;
- if (1) {
#ifdef __KERNEL__
- if (!in->myInode) {
- immediateDeletion = 1;
-
- }
+ if (!in->myInode) {
+ immediateDeletion = 1;
+ }
#else
- if (in->inUse <= 0) {
- immediateDeletion = 1;
-
- }
+ if (in->inUse <= 0) {
+ immediateDeletion = 1;
+ }
#endif
- if (immediateDeletion) {
- retVal =
- yaffs_ChangeObjectName(in, in->myDev->deletedDir,
- _Y("deleted"), 0, 0);
- T(YAFFS_TRACE_TRACING,
- (TSTR("yaffs: immediate deletion of file %d" TENDSTR),
- in->objectId));
- in->deleted = 1;
- in->myDev->nDeletedFiles++;
- if (0 && in->myDev->isYaffs2) {
- yaffs_ResizeFile(in, 0);
- }
- yaffs_SoftDeleteFile(in);
- } else {
- retVal =
- yaffs_ChangeObjectName(in, in->myDev->unlinkedDir,
- _Y("unlinked"), 0, 0);
- }
+ if (immediateDeletion) {
+ retVal =
+ yaffs_ChangeObjectName(in, in->myDev->deletedDir,
+ _Y("deleted"), 0, 0);
+ T(YAFFS_TRACE_TRACING,
+ (TSTR("yaffs: immediate deletion of file %d" TENDSTR),
+ in->objectId));
+ in->deleted = 1;
+ in->myDev->nDeletedFiles++;
+ if (1 || in->myDev->isYaffs2) {
+ yaffs_ResizeFile(in, 0);
+ }
+ yaffs_SoftDeleteFile(in);
+ } else {
+ retVal =
+ yaffs_ChangeObjectName(in, in->myDev->unlinkedDir,
+ _Y("unlinked"), 0, 0);
}
+
+
return retVal;
}
int yaffs_DeleteFile(yaffs_Object * in)
{
int retVal = YAFFS_OK;
+ int deleted = in->deleted;
+
+ yaffs_ResizeFile(in,0);
if (in->nDataChunks > 0) {
- /* Use soft deletion if there is data in the file */
+ /* Use soft deletion if there is data in the file.
+ * That won't be the case if it has been resized to zero.
+ */
if (!in->unlinked) {
retVal = yaffs_UnlinkFile(in);
}
if (retVal == YAFFS_OK && in->unlinked && !in->deleted) {
- in->deleted = 1;
+ in->deleted = deleted = 1;
in->myDev->nDeletedFiles++;
yaffs_SoftDeleteFile(in);
}
- return in->deleted ? YAFFS_OK : YAFFS_FAIL;
+ return deleted ? YAFFS_OK : YAFFS_FAIL;
} else {
/* The file has no data chunks so we toss it immediately */
yaffs_FreeTnode(in->myDev, in->variant.fileVariant.top);
/* remove this hardlink from the list assocaited with the equivalent
* object
*/
- ylist_del(&in->hardLinks);
+ ylist_del_init(&in->hardLinks);
return yaffs_DoGenericObjectDeletion(in);
}
in->yst_rdev = oh->yst_rdev;
#endif
in->hdrChunk = chunk;
+ in->serial = tags.serialNumber;
} else if (in && !in->valid) {
/* we need to load this info */
in->yst_rdev = oh->yst_rdev;
#endif
in->hdrChunk = chunk;
+ in->serial = tags.serialNumber;
yaffs_SetObjectName(in, oh->name);
in->dirty = 0;
break;
}
- if (parent == dev->deletedDir) {
+/*
+ if (parent == dev->deletedDir) {
yaffs_DestroyObject(in);
bi->hasShrinkHeader = 1;
}
+*/
}
}
}
{
__u8 *chunkData;
yaffs_ObjectHeader *oh;
- yaffs_Device *dev = in->myDev;
+ yaffs_Device *dev;
yaffs_ExtendedTags tags;
int result;
int alloc_failed = 0;
if(!in)
return;
+ dev = in->myDev;
+
#if 0
T(YAFFS_TRACE_SCAN,(TSTR("details for object %d %s loaded" TENDSTR),
in->objectId,
(oh) ? oh->
parentObjectId : tags.
extraParentObjectId;
- unsigned isShrink =
+
+
+ isShrink =
(oh) ? oh->isShrink : tags.
extraIsShrinkHeader;
/*------------------------------ Directory Functions ----------------------------- */
+static void yaffs_VerifyObjectInDirectory(yaffs_Object *obj)
+{
+ struct ylist_head *lh;
+ yaffs_Object *listObj;
+
+ int count = 0;
+
+ if(!obj)
+ YBUG();
+
+ if(yaffs_SkipVerification(obj->myDev))
+ return;
+
+ if(!obj->parent)
+ YBUG();
+
+ if(obj->parent->variantType != YAFFS_OBJECT_TYPE_DIRECTORY)
+ 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)
+ YBUG();
+
+
+}
+
+static void yaffs_VerifyDirectory(yaffs_Object *directory)
+{
+
+ struct ylist_head *lh;
+ yaffs_Object *listObj;
+
+ if(!directory)
+ YBUG();
+
+ if(yaffs_SkipVerification(directory->myDev))
+ return;
+
+
+ if(directory->variantType != YAFFS_OBJECT_TYPE_DIRECTORY)
+ 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)
+ YBUG();
+ yaffs_VerifyObjectInDirectory(listObj);
+ }
+ }
+
+}
+
+
static void yaffs_RemoveObjectFromDirectory(yaffs_Object * obj)
{
yaffs_Device *dev = obj->myDev;
+ yaffs_Object *parent;
+
+ yaffs_VerifyObjectInDirectory(obj);
+ parent = obj->parent;
+ yaffs_VerifyDirectory(parent);
+
if(dev && dev->removeObjectCallback)
dev->removeObjectCallback(obj);
+
ylist_del_init(&obj->siblings);
obj->parent = NULL;
+
+ yaffs_VerifyDirectory(parent);
+
}
if (obj->siblings.prev == NULL) {
/* Not initialised */
- YINIT_LIST_HEAD(&obj->siblings);
+ YBUG();
- } else if (!ylist_empty(&obj->siblings)) {
- /* If it is holed up somewhere else, un hook it */
- yaffs_RemoveObjectFromDirectory(obj);
- }
+ } else if (ylist_empty(&obj->siblings)) {
+ YBUG();
+ }
+
+
+ yaffs_VerifyDirectory(directory);
+
+ yaffs_RemoveObjectFromDirectory(obj);
+
+
/* Now add it */
ylist_add(&obj->siblings, &directory->variant.directoryVariant.children);
obj->parent = directory;
obj->myDev->nUnlinkedFiles++;
obj->renameAllowed = 0;
}
+
+ yaffs_VerifyDirectory(directory);
+ yaffs_VerifyObjectInDirectory(obj);
+
+
}
yaffs_Object *yaffs_FindObjectByName(yaffs_Object * directory,
if (i) {
l = ylist_entry(i, yaffs_Object, siblings);
+ if(l->parent != directory)
+ YBUG();
+
yaffs_CheckObjectDetailsLoaded(l);
/* Special case for lost-n-found */
yaffs_strncpy(name, YAFFS_LOSTNFOUND_NAME, buffSize - 1);
} else if (obj->hdrChunk <= 0) {
YCHAR locName[20];
+ YCHAR numString[20];
+ YCHAR *x = &numString[19];
+ unsigned v = obj->objectId;
+ numString[19] = 0;
+ while(v>0){
+ x--;
+ *x = '0' + (v % 10);
+ v /= 10;
+ }
/* make up a name */
- yaffs_sprintf(locName, _Y("%s%d"), YAFFS_LOSTNFOUND_PREFIX,
- obj->objectId);
+ yaffs_strcpy(locName, YAFFS_LOSTNFOUND_PREFIX);
+ yaffs_strcat(locName,x);
yaffs_strncpy(name, locName, buffSize - 1);
}
/* Check geometry parameters. */
if ((!dev->inbandTags && dev->isYaffs2 && dev->totalBytesPerChunk < 1024) ||
- (!dev->isYaffs2 && dev->totalBytesPerChunk != 512) ||
+ (!dev->isYaffs2 && dev->totalBytesPerChunk < 512) ||
(dev->inbandTags && !dev->isYaffs2 ) ||
dev->nChunksPerBlock < 2 ||
dev->nReservedBlocks < 2 ||
dev->isMounted = 1;
-
-
/* OK now calculate a few things for the device */
/*
* Calculate all the chunk size manipulation numbers:
*/
- {
- __u32 x = dev->nDataBytesPerChunk;
- /* We always use dev->chunkShift and dev->chunkDiv */
- dev->chunkShift = Shifts(x);
- x >>= dev->chunkShift;
- dev->chunkDiv = x;
- /* We only use chunk mask if chunkDiv is 1 */
- dev->chunkMask = (1<<dev->chunkShift) - 1;
- }
+ x = dev->nDataBytesPerChunk;
+ /* We always use dev->chunkShift and dev->chunkDiv */
+ dev->chunkShift = Shifts(x);
+ x >>= dev->chunkShift;
+ dev->chunkDiv = x;
+ /* We only use chunk mask if chunkDiv is 1 */
+ dev->chunkMask = (1<<dev->chunkShift) - 1;
-
/*
* Calculate chunkGroupBits.
* We need to find the next power of 2 > than internalEndBlock
dev->nShortOpCaches = YAFFS_MAX_SHORT_OP_CACHES;
}
- buf = dev->srCache = YMALLOC(srCacheBytes);
+ dev->srCache = YMALLOC(srCacheBytes);
+
+ buf = (__u8 *) dev->srCache;
if(dev->srCache)
memset(dev->srCache,0,srCacheBytes);
dev->isMounted = 0;
+
+ if(dev->deinitialiseNAND)
+ dev->deinitialiseNAND(dev);
}
}