*/
const char *yaffs_guts_c_version =
- "$Id: yaffs_guts.c,v 1.81 2009-03-06 17:20:51 wookey Exp $";
+ "$Id: yaffs_guts.c,v 1.95 2009-11-11 01:40:41 charles Exp $";
#include "yportenv.h"
const yaffs_ExtendedTags *tags);
/* Other local prototypes */
+static void yaffs_UpdateParent(yaffs_Object *obj);
static int yaffs_UnlinkObject(yaffs_Object *obj);
static int yaffs_ObjectHasCachedWriteData(yaffs_Object *obj);
static int yaffs_TagsMatch(const yaffs_ExtendedTags *tags, int objectId,
int chunkInObject);
-loff_t yaffs_GetFileSize(yaffs_Object *obj);
-
static int yaffs_AllocateChunk(yaffs_Device *dev, int useReserve,
yaffs_BlockInfo **blockUsedPtr);
yaffs_FileStructure *fStruct,
__u32 chunkId);
-
/* Function to calculate chunk and offset */
static void yaffs_AddrToChunk(yaffs_Device *dev, loff_t addr, int *chunkOut,
T(YAFFS_TRACE_BUFFERS,
(TSTR("Out of temp buffers at line %d, other held by lines:"),
lineNo));
- for (i = 0; i < YAFFS_N_TEMP_BUFFERS; i++) {
+ for (i = 0; i < YAFFS_N_TEMP_BUFFERS; i++)
T(YAFFS_TRACE_BUFFERS, (TSTR(" %d "), dev->tempBuffer[i].line));
- }
+
T(YAFFS_TRACE_BUFFERS, (TSTR(" " TENDSTR)));
/*
chunkMax = (dev->internalEndBlock+1) * dev->nChunksPerBlock - 1;
chunkInRange = (((unsigned)(obj->hdrChunk)) >= chunkMin && ((unsigned)(obj->hdrChunk)) <= chunkMax);
- chunkIdOk = chunkInRange || obj->hdrChunk == 0;
+ chunkIdOk = chunkInRange || (obj->hdrChunk == 0);
chunkValid = chunkInRange &&
yaffs_CheckChunkBit(dev,
obj->hdrChunk / dev->nChunksPerBlock,
erasedOk = yaffs_CheckChunkErased(dev, chunk);
if (erasedOk != YAFFS_OK) {
T(YAFFS_TRACE_ERROR,
- (TSTR ("**>> yaffs chunk %d was not erased"
+ (TSTR("**>> yaffs chunk %d was not erased"
TENDSTR), chunk));
/* try another chunk */
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) {
+ 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 {
+ else
obj->shortName[0] = _Y('\0');
- }
#endif
obj->sum = yaffs_CalcNameSum(name);
}
yaffs_Tnode *tn = NULL;
/* If there are none left make more */
- if (!dev->freeTnodes) {
+ if (!dev->freeTnodes)
yaffs_CreateTnodes(dev, YAFFS_ALLOCATION_NTNODES);
- }
if (dev->freeTnodes) {
tn = dev->freeTnodes;
}
-void yaffs_PutLevel0Tnode(yaffs_Device *dev, yaffs_Tnode *tn, unsigned pos,
+void yaffs_LoadLevel0Tnode(yaffs_Device *dev, yaffs_Tnode *tn, unsigned pos,
unsigned val)
{
__u32 *map = (__u32 *)tn;
int level = fStruct->topLevel;
/* Check sane level and chunk Id */
- if (level < 0 || level > YAFFS_TNODES_MAX_LEVEL) {
+ if (level < 0 || level > YAFFS_TNODES_MAX_LEVEL)
return NULL;
- }
- if (chunkId > YAFFS_MAX_CHUNK_ID) {
+ if (chunkId > YAFFS_MAX_CHUNK_ID)
return NULL;
- }
/* First check we're tall enough (ie enough topLevel) */
requiredTallness++;
}
- if (requiredTallness > fStruct->topLevel) {
- /* Not tall enough, so we can't find it, return NULL. */
- return NULL;
- }
+ if (requiredTallness > fStruct->topLevel)
+ return NULL; /* Not tall enough, so we can't find it */
/* Traverse down to level 0 */
while (level > 0 && tn) {
/* Check sane level and page Id */
- if (fStruct->topLevel < 0 || fStruct->topLevel > YAFFS_TNODES_MAX_LEVEL) {
+ if (fStruct->topLevel < 0 || fStruct->topLevel > YAFFS_TNODES_MAX_LEVEL)
return NULL;
- }
- if (chunkId > YAFFS_MAX_CHUNK_ID) {
+ if (chunkId > YAFFS_MAX_CHUNK_ID)
return NULL;
- }
/* First check we're tall enough (ie enough topLevel) */
if (tn) {
tn->internal[0] = fStruct->top;
fStruct->top = tn;
+ fStruct->topLevel++;
} else {
T(YAFFS_TRACE_ERROR,
- (TSTR("yaffs: no more tnodes" TENDSTR)));
+ (TSTR("yaffs: no more tnodes" TENDSTR)));
+ return NULL;
}
}
-
- fStruct->topLevel = requiredTallness;
}
/* Traverse down to level 0, adding anything we need */
if ((l > 1) && !tn->internal[x]) {
/* Add missing non-level-zero tnode */
tn->internal[x] = yaffs_GetTnode(dev);
+ if(!tn->internal[x])
+ return NULL;
} else if (l == 1) {
/* Looking from level 1 at level 0 */
} else if (!tn->internal[x]) {
/* Don't have one, none passed in */
tn->internal[x] = yaffs_GetTnode(dev);
+ if(!tn->internal[x])
+ return NULL;
}
}
for (j = 0; theChunk && j < dev->chunkGroupSize; j++) {
if (yaffs_CheckChunkBit(dev, theChunk / dev->nChunksPerBlock,
theChunk % dev->nChunksPerBlock)) {
- yaffs_ReadChunkWithTagsFromNAND(dev, theChunk, NULL,
- tags);
- if (yaffs_TagsMatch(tags, objectId, chunkInInode)) {
- /* found it; */
+
+ if(dev->chunkGroupSize == 1)
return theChunk;
+ else {
+ yaffs_ReadChunkWithTagsFromNAND(dev, theChunk, NULL,
+ tags);
+ if (yaffs_TagsMatch(tags, objectId, chunkInInode)) {
+ /* found it; */
+ return theChunk;
+ }
}
}
theChunk++;
in->nDataChunks--;
if (limit) {
*limit = *limit - 1;
- if (*limit <= 0) {
+ if (*limit <= 0)
hitLimit = 1;
- }
}
}
- yaffs_PutLevel0Tnode(dev, tn, i, 0);
+ yaffs_LoadLevel0Tnode(dev, tn, i, 0);
}
}
* a block.
*/
yaffs_SoftDeleteChunk(dev, theChunk);
- yaffs_PutLevel0Tnode(dev, tn, i, 0);
+ yaffs_LoadLevel0Tnode(dev, tn, i, 0);
}
}
(i == 0) ? del0 : 1);
}
- if (tn->internal[i]) {
+ if (tn->internal[i])
hasData++;
- }
}
if (hasData == 0 && del0) {
hasData = 0;
for (i = 1; i < YAFFS_NTNODES_INTERNAL; i++) {
- if (tn->internal[i]) {
+ if (tn->internal[i])
hasData++;
- }
}
if (!hasData) {
tn = YMALLOC(sizeof(yaffs_Object));
#else
/* If there are none left make more */
- if (!dev->freeObjects) {
+ if (!dev->freeObjects)
yaffs_CreateFreeObjects(dev, YAFFS_ALLOCATION_NOBJECTS);
- }
if (dev->freeObjects) {
tn = dev->freeObjects;
* NB Can't put root or lostNFound in lostNFound so
* check if lostNFound exists first
*/
- if (dev->lostNFoundDir) {
+ if (dev->lostNFoundDir)
yaffs_AddObjectToDirectory(dev->lostNFoundDir, tn);
- }
tn->beingCreated = 0;
}
{
yaffs_Device *dev = tn->myDev;
-#ifdef __KERNEL__
- T(YAFFS_TRACE_OS,(TSTR("FreeObject %p inode %p"TENDSTR),tn,tn->myInode));
+#ifdef __KERNEL__
+ T(YAFFS_TRACE_OS, (TSTR("FreeObject %p inode %p"TENDSTR), tn, tn->myInode));
#endif
-
- if(tn->parent)
+
+ if (tn->parent)
YBUG();
if (!ylist_empty(&tn->siblings))
YBUG();
void yaffs_HandleDeferedFree(yaffs_Object *obj)
{
- if (obj->deferedFree) {
+ if (obj->deferedFree)
yaffs_FreeObject(obj);
- }
}
#endif
yaffs_Object *theObject;
yaffs_Tnode *tn = NULL;
- if (number < 0) {
+ if (number < 0)
number = yaffs_CreateNewObjectNumber(dev);
- }
-
- theObject = yaffs_AllocateEmptyObject(dev);
- if (!theObject)
- return NULL;
if (type == YAFFS_OBJECT_TYPE_FILE) {
tn = yaffs_GetTnode(dev);
- if (!tn) {
- yaffs_FreeObject(theObject);
+ if (!tn)
return NULL;
- }
}
+ theObject = yaffs_AllocateEmptyObject(dev);
+ if (!theObject){
+ if(tn)
+ yaffs_FreeTnode(dev,tn);
+ return NULL;
+ }
+
+
if (theObject) {
theObject->fake = 0;
theObject->renameAllowed = 1;
{
yaffs_Object *theObject = NULL;
- if (number > 0) {
+ if (number > 0)
theObject = yaffs_FindObjectByNumber(dev, number);
- }
- if (!theObject) {
+ if (!theObject)
theObject = yaffs_CreateNewObject(dev, number, type);
- }
return theObject;
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)) {
+ if (yaffs_FindObjectByName(parent, name))
return NULL;
- }
-
- in = yaffs_CreateNewObject(dev, -1, type);
-
- if (!in)
- return YAFFS_FAIL;
if (type == YAFFS_OBJECT_TYPE_SYMLINK) {
str = yaffs_CloneString(aliasString);
- if (!str) {
- yaffs_FreeObject(in);
+ if (!str)
return NULL;
- }
+ }
+
+ in = yaffs_CreateNewObject(dev, -1, type);
+
+ if (!in){
+ if(str)
+ YFREE(str);
+ return NULL;
}
+
if (in) {
in->hdrChunk = 0;
in->valid = 1;
in = NULL;
}
+ yaffs_UpdateParent(parent);
}
return in;
yaffs_Object *existingTarget;
- if (newDir == NULL) {
+ if (newDir == NULL)
newDir = obj->parent; /* use the old directory */
- }
if (newDir->variantType != YAFFS_OBJECT_TYPE_DIRECTORY) {
T(YAFFS_TRACE_ALWAYS,
}
/* TODO: Do we need this different handling for YAFFS2 and YAFFS1?? */
- if (obj->myDev->isYaffs2) {
+ if (obj->myDev->isYaffs2)
unlinkOp = (newDir == obj->myDev->unlinkedDir);
- } else {
+ else
unlinkOp = (newDir == obj->myDev->unlinkedDir
&& obj->variantType == YAFFS_OBJECT_TYPE_FILE);
- }
deleteOp = (newDir == obj->myDev->deletedDir);
yaffs_Object *obj = NULL;
yaffs_Object *existingTarget = NULL;
int force = 0;
+ int result;
+ yaffs_Device *dev;
if (!oldDir || oldDir->variantType != YAFFS_OBJECT_TYPE_DIRECTORY)
if (!newDir || newDir->variantType != YAFFS_OBJECT_TYPE_DIRECTORY)
YBUG();
+ dev = oldDir->myDev;
+
#ifdef CONFIG_YAFFS_CASE_INSENSITIVE
/* Special case for case insemsitive systems (eg. WinCE).
* While look-up is case insensitive, the name isn't.
* Therefore we might want to change x.txt to X.txt
*/
- if (oldDir == newDir && yaffs_strcmp(oldName, newName) == 0) {
+ if (oldDir == newDir && yaffs_strcmp(oldName, newName) == 0)
force = 1;
- }
#endif
- else if (yaffs_strlen(newName) > YAFFS_MAX_NAME_LENGTH)
+ if(yaffs_strlen(newName) > YAFFS_MAX_NAME_LENGTH)
/* ENAMETOOLONG */
return YAFFS_FAIL;
return YAFFS_FAIL; /* EEXIST or ENOTEMPTY */
} else if (existingTarget && existingTarget != obj) {
/* Nuke the target first, using shadowing,
- * but only if it isn't the same object
+ * but only if it isn't the same object.
+ *
+ * Note we must disable gc otherwise it can mess up the shadowing.
+ *
*/
+ dev->isDoingGC=1;
yaffs_ChangeObjectName(obj, newDir, newName, force,
existingTarget->objectId);
+ existingTarget->isShadowed = 1;
yaffs_UnlinkObject(existingTarget);
+ dev->isDoingGC=0;
}
- return yaffs_ChangeObjectName(obj, newDir, newName, 1, 0);
+ result = yaffs_ChangeObjectName(obj, newDir, newName, 1, 0);
+
+ yaffs_UpdateParent(oldDir);
+ if(newDir != oldDir)
+ yaffs_UpdateParent(newDir);
+
+ return result;
}
return YAFFS_FAIL;
}
dev->nonAggressiveSkip--;
- if (!aggressive && (dev->nonAggressiveSkip > 0)) {
+ if (!aggressive && (dev->nonAggressiveSkip > 0))
return -1;
- }
if (!prioritised)
pagesInUse =
(aggressive) ? dev->nChunksPerBlock : YAFFS_PASSIVE_GC_CHUNKS + 1;
- if (aggressive) {
+ if (aggressive)
iterations =
dev->internalEndBlock - dev->internalStartBlock + 1;
- } else {
+ else {
iterations =
dev->internalEndBlock - dev->internalStartBlock + 1;
iterations = iterations / 16;
- if (iterations > 200) {
+ if (iterations > 200)
iterations = 200;
- }
}
for (i = 0; i <= iterations && pagesInUse > 0 && !prioritised; i++) {
b++;
- if (b < dev->internalStartBlock || b > dev->internalEndBlock) {
+ if (b < dev->internalStartBlock || b > dev->internalEndBlock)
b = dev->internalStartBlock;
- }
if (b < dev->internalStartBlock || b > dev->internalEndBlock) {
T(YAFFS_TRACE_ERROR,
bi = yaffs_GetBlockInfo(dev, b);
-#if 0
- if (bi->blockState == YAFFS_BLOCK_STATE_CHECKPOINT) {
- dirtiest = b;
- pagesInUse = 0;
- } else
-#endif
-
if (bi->blockState == YAFFS_BLOCK_STATE_FULL &&
(bi->pagesInUse - bi->softDeletions) < pagesInUse &&
yaffs_BlockNotDisqualifiedFromGC(dev, bi)) {
n = dev->nErasedBlocks * dev->nChunksPerBlock;
- if (dev->allocationBlock > 0) {
+ if (dev->allocationBlock > 0)
n += (dev->nChunksPerBlock - dev->allocationPage);
- }
return n;
isCheckpointBlock = (bi->blockState == YAFFS_BLOCK_STATE_CHECKPOINT);
- bi->blockState = YAFFS_BLOCK_STATE_COLLECTING;
T(YAFFS_TRACE_TRACING,
(TSTR("Collecting block %d, in use %d, shrink %d, wholeBlock %d" TENDSTR),
/*yaffs_VerifyFreeChunks(dev); */
+ if(bi->blockState == YAFFS_BLOCK_STATE_FULL)
+ bi->blockState = YAFFS_BLOCK_STATE_COLLECTING;
+
bi->hasShrinkHeader = 0; /* clear the flag so that the block can erase */
/* Take off the number of soft deleted entries because
* they're going to get really deleted during GC.
*/
- dev->nFreeChunks -= bi->softDeletions;
+ if(dev->gcChunk == 0) /* first time through for this block */
+ dev->nFreeChunks -= bi->softDeletions;
dev->isDoingGC = 1;
if (block > 0) {
dev->garbageCollections++;
- if (!aggressive) {
+ if (!aggressive)
dev->passiveGarbageCollections++;
- }
T(YAFFS_TRACE_GC,
(TSTR
chunkInInode);
/* Delete the entry in the filestructure (if found) */
- if (retVal != -1) {
- yaffs_PutLevel0Tnode(dev, tn, chunkInInode, 0);
- }
- } else {
- /*T(("No level 0 found for %d\n", chunkInInode)); */
+ if (retVal != -1)
+ yaffs_LoadLevel0Tnode(dev, tn, chunkInInode, 0);
}
- if (retVal == -1) {
- /* T(("Could not find %d to delete\n",chunkInInode)); */
- }
return retVal;
}
int theChunk;
int chunkDeleted;
- if (in->variantType != YAFFS_OBJECT_TYPE_FILE) {
- /* T(("Object not a file\n")); */
+ if (in->variantType != YAFFS_OBJECT_TYPE_FILE)
return YAFFS_FAIL;
- }
objId = in->objectId;
fSize = in->variant.fileVariant.fileSize;
/* NB inScan is zero unless scanning.
* For forward scanning, inScan is > 0;
* for backward scanning inScan is < 0
+ *
+ * chunkInNAND = 0 is a dummy insert to make sure the tnodes are there.
*/
yaffs_Tnode *tn;
&in->variant.fileVariant,
chunkInInode,
NULL);
- if (!tn) {
+ if (!tn)
return YAFFS_FAIL;
- }
+
+ if(!chunkInNAND)
+ /* Dummy insert, bail now */
+ return YAFFS_OK;
+
existingChunk = yaffs_GetChunkGroupBase(dev, tn, chunkInInode);
}
- if (existingChunk == 0) {
+ if (existingChunk == 0)
in->nDataChunks++;
- }
- yaffs_PutLevel0Tnode(dev, tn, chunkInInode, chunkInNAND);
+ yaffs_LoadLevel0Tnode(dev, tn, chunkInInode, chunkInNAND);
return YAFFS_OK;
}
{
int chunkInNAND = yaffs_FindChunkInFile(in, chunkInInode, NULL);
- if (chunkInNAND >= 0) {
+ if (chunkInNAND >= 0)
return yaffs_ReadChunkWithTagsFromNAND(in->myDev, chunkInNAND,
buffer, NULL);
- } else {
+ else {
T(YAFFS_TRACE_NANDACCESS,
(TSTR("Chunk %d not found zero instead" TENDSTR),
chunkInNAND));
if (chunkId <= 0)
return;
-
dev->nDeletions++;
block = chunkId / dev->nChunksPerBlock;
page = chunkId % dev->nChunksPerBlock;
yaffs_BlockBecameDirty(dev, block);
}
- } else {
- /* T(("Bad news deleting chunk %d\n",chunkId)); */
}
}
newTags.chunkId = chunkInInode;
newTags.objectId = in->objectId;
newTags.serialNumber =
- (prevChunkId >= 0) ? prevTags.serialNumber + 1 : 1;
+ (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));
- YBUG();
+ T(YAFFS_TRACE_ERROR,
+ (TSTR("Writing %d bytes to chunk!!!!!!!!!" TENDSTR), nBytes));
+ YBUG();
}
-
+
+ /*
+ * If there isn't already a chunk there then do a dummy
+ * insert to make sue we have the desired tnode structure.
+ */
+ if(prevChunkId < 1 &&
+ yaffs_PutChunkIntoFile(in, chunkInInode, 0, 0) != YAFFS_OK)
+ return -1;
+
newChunkId =
yaffs_WriteNewChunkWithTagsToNAND(dev, buffer, &newTags,
useReserve);
- if (newChunkId >= 0) {
+ if (newChunkId > 0) {
yaffs_PutChunkIntoFile(in, chunkInInode, newChunkId, 0);
- if (prevChunkId >= 0) {
+ if (prevChunkId > 0)
yaffs_DeleteChunk(dev, prevChunkId, 1, __LINE__);
- }
-
yaffs_CheckFileSanity(in);
}
return newChunkId;
oh->yst_ctime = in->yst_ctime;
oh->yst_rdev = in->yst_rdev;
#endif
- if (in->parent) {
+ if (in->parent)
oh->parentObjectId = in->parent->objectId;
- } else {
+ else
oh->parentObjectId = 0;
- }
if (name && *name) {
memset(oh->name, 0, sizeof(oh->name));
yaffs_strncpy(oh->name, name, YAFFS_MAX_NAME_LENGTH);
- } else if (prevChunkId >= 0) {
+ } else if (prevChunkId > 0)
memcpy(oh->name, oldName, sizeof(oh->name));
- } else {
+ else
memset(oh->name, 0, sizeof(oh->name));
- }
oh->isShrink = isShrink;
/* Create new chunk in NAND */
newChunkId =
yaffs_WriteNewChunkWithTagsToNAND(dev, buffer, &newTags,
- (prevChunkId >= 0) ? 1 : 0);
+ (prevChunkId > 0) ? 1 : 0);
if (newChunkId >= 0) {
in->hdrChunk = newChunkId;
- if (prevChunkId >= 0) {
+ if (prevChunkId > 0) {
yaffs_DeleteChunk(dev, prevChunkId, 1,
__LINE__);
}
if (dev->srLastUse < 0 || dev->srLastUse > 100000000) {
/* Reset the cache usages */
int i;
- for (i = 1; i < dev->nShortOpCaches; i++) {
+ for (i = 1; i < dev->nShortOpCaches; i++)
dev->srCache[i].lastUse = 0;
- }
+
dev->srLastUse = 0;
}
cache->lastUse = dev->srLastUse;
- if (isAWrite) {
+ if (isAWrite)
cache->dirty = 1;
- }
}
}
if (object->myDev->nShortOpCaches > 0) {
yaffs_ChunkCache *cache = yaffs_FindChunkCache(object, chunkId);
- if (cache) {
+ if (cache)
cache->object = NULL;
- }
}
}
if (dev->nShortOpCaches > 0) {
/* Invalidate it. */
for (i = 0; i < dev->nShortOpCaches; i++) {
- if (dev->srCache[i].object == in) {
+ if (dev->srCache[i].object == in)
dev->srCache[i].object = NULL;
- }
}
}
}
ok = (yaffs_CheckpointWrite(dev, &cp, sizeof(cp)) == sizeof(cp));
- if (ok && obj->variantType == YAFFS_OBJECT_TYPE_FILE) {
+ if (ok && obj->variantType == YAFFS_OBJECT_TYPE_FILE)
ok = yaffs_WriteCheckpointTnodes(obj);
- }
}
}
}
ok = yaffs_WriteCheckpointValidityMarker(dev, 0);
}
- if (ok) {
+ if (ok)
ok = yaffs_WriteCheckpointSum(dev);
- }
-
if (!yaffs_CheckpointClose(dev))
ok = 0;
/* OK now check for the curveball where the start and end are in
* the same chunk.
*/
- if ((start + n) < dev->nDataBytesPerChunk) {
+ if ((start + n) < dev->nDataBytesPerChunk)
nToCopy = n;
- } else {
+ else
nToCopy = dev->nDataBytesPerChunk - start;
- }
cache = yaffs_FindChunkCache(in, chunk);
else
nBytesRead = in->variant.fileVariant.fileSize - chunkStart;
- if (nBytesRead > dev->nDataBytesPerChunk) {
+ if (nBytesRead > dev->nDataBytesPerChunk)
nBytesRead = dev->nDataBytesPerChunk;
- }
nToWriteBack =
(nBytesRead >
/* Update file object */
- if ((startOfWrite + nDone) > in->variant.fileVariant.fileSize) {
+ if ((startOfWrite + nDone) > in->variant.fileVariant.fileSize)
in->variant.fileVariant.fileSize = (startOfWrite + nDone);
- }
in->dirty = 1;
yaffs_CheckGarbageCollection(dev);
- if (in->variantType != YAFFS_OBJECT_TYPE_FILE) {
+ if (in->variantType != YAFFS_OBJECT_TYPE_FILE)
return YAFFS_FAIL;
- }
- if (newSize == oldFileSize) {
+ if (newSize == oldFileSize)
return YAFFS_OK;
- }
if (newSize < oldFileSize) {
}
- /* Write a new object header.
+ /* Write a new object header to reflect the resize.
* show we've shrunk the file, if need be
- * Do this only if the file is not in the deleted directories.
+ * Do this only if the file is not in the deleted directories
+ * and is not shadowed.
*/
if (in->parent &&
+ !in->isShadowed &&
in->parent->objectId != YAFFS_OBJECTID_UNLINKED &&
- in->parent->objectId != YAFFS_OBJECTID_DELETED) {
+ in->parent->objectId != YAFFS_OBJECTID_DELETED)
yaffs_UpdateObjectHeader(in, NULL, 0,
(newSize < oldFileSize) ? 1 : 0, 0);
- }
return YAFFS_OK;
}
-int yaffs_FlushFile(yaffs_Object *in, int updateTime)
+int yaffs_FlushFile(yaffs_Object *in, int updateTime, int dataSync)
{
int retVal;
if (in->dirty) {
yaffs_FlushFilesChunkCache(in);
- if (updateTime) {
+ if(dataSync) /* Only sync data */
+ retVal=YAFFS_OK;
+ else {
+ if (updateTime) {
#ifdef CONFIG_YAFFS_WINCE
- yfsd_WinFileTimeNow(in->win_mtime);
+ yfsd_WinFileTimeNow(in->win_mtime);
#else
- in->yst_mtime = Y_CURRENT_TIME;
+ in->yst_mtime = Y_CURRENT_TIME;
#endif
- }
+ }
- retVal = (yaffs_UpdateObjectHeader(in, NULL, 0, 0, 0) >=
- 0) ? YAFFS_OK : YAFFS_FAIL;
+ retVal = (yaffs_UpdateObjectHeader(in, NULL, 0, 0, 0) >=
+ 0) ? YAFFS_OK : YAFFS_FAIL;
+ }
} else {
retVal = YAFFS_OK;
}
int immediateDeletion = 0;
#ifdef __KERNEL__
- if (!in->myInode) {
+ if (!in->myInode)
immediateDeletion = 1;
- }
#else
- if (in->inUse <= 0) {
+ if (in->inUse <= 0)
immediateDeletion = 1;
- }
#endif
if (immediateDeletion) {
in->objectId));
in->deleted = 1;
in->myDev->nDeletedFiles++;
- if (1 || in->myDev->isYaffs2) {
+ if (1 || in->myDev->isYaffs2)
yaffs_ResizeFile(in, 0);
- }
yaffs_SoftDeleteFile(in);
} else {
retVal =
/* 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) {
+ if (!in->unlinked)
retVal = yaffs_UnlinkFileIfNeeded(in);
- }
+
if (retVal == YAFFS_OK && in->unlinked && !in->deleted) {
- in->deleted = deleted = 1;
+ in->deleted = 1;
+ deleted = 1;
in->myDev->nDeletedFiles++;
yaffs_SoftDeleteFile(in);
}
}
}
-static int yaffs_DeleteDirectory(yaffs_Object *in)
+static int yaffs_IsNonEmptyDirectory(yaffs_Object *obj)
{
- /* First check that the directory is empty. */
- if (ylist_empty(&in->variant.directoryVariant.children)) {
- return yaffs_DoGenericObjectDeletion(in);
- }
+ return (obj->variantType == YAFFS_OBJECT_TYPE_DIRECTORY) &&
+ !(ylist_empty(&obj->variant.directoryVariant.children));
+}
- return YAFFS_FAIL;
+static int yaffs_DeleteDirectory(yaffs_Object *obj)
+{
+ /* First check that the directory is empty. */
+ if (yaffs_IsNonEmptyDirectory(obj))
+ return YAFFS_FAIL;
+ return yaffs_DoGenericObjectDeletion(obj);
}
static int yaffs_DeleteSymLink(yaffs_Object *in)
retVal = yaffs_DoGenericObjectDeletion(obj);
break;
case YAFFS_OBJECT_TYPE_UNKNOWN:
- retVal = 0;
+ retVal = 0;
break; /* should not happen. */
}
-
+
return retVal;
}
int immediateDeletion = 0;
#ifdef __KERNEL__
- if (!obj->myInode) {
+ if (!obj->myInode)
immediateDeletion = 1;
- }
#else
- if (obj->inUse <= 0) {
+ if (obj->inUse <= 0)
immediateDeletion = 1;
- }
#endif
- if (obj->variantType == YAFFS_OBJECT_TYPE_HARDLINK) {
- return yaffs_DeleteHardLink(obj);
- } else if (!ylist_empty(&obj->hardLinks)) {
- /* Curve ball: We're unlinking an object that has a hardlink.
- *
- * This problem arises because we are not strictly following
+ if(obj)
+ yaffs_UpdateParent(obj->parent);
+
+ if (obj->variantType == YAFFS_OBJECT_TYPE_HARDLINK) {
+ return yaffs_DeleteHardLink(obj);
+ } else if (!ylist_empty(&obj->hardLinks)) {
+ /* Curve ball: We're unlinking an object that has a hardlink.
+ *
+ * This problem arises because we are not strictly following
* The Linux link/inode model.
*
* We can't really delete the object.
retVal = yaffs_ChangeObjectName(obj, hl->parent, name, 0, 0);
- if (retVal == YAFFS_OK) {
+ if (retVal == YAFFS_OK)
retVal = yaffs_DoGenericObjectDeletion(hl);
- }
+
return retVal;
- } else if(immediateDeletion){
+ } else if (immediateDeletion) {
switch (obj->variantType) {
case YAFFS_OBJECT_TYPE_FILE:
return yaffs_DeleteFile(obj);
default:
return YAFFS_FAIL;
}
- } else {
+ } else if(yaffs_IsNonEmptyDirectory(obj))
+ return YAFFS_FAIL;
+ else
return yaffs_ChangeObjectName(obj, obj->myDev->unlinkedDir,
_Y("unlinked"), 0, 0);
- }
}
static int yaffs_UnlinkObject(yaffs_Object *obj)
{
- if (obj && obj->unlinkAllowed) {
+ if (obj && obj->unlinkAllowed)
return yaffs_UnlinkWorker(obj);
- }
return YAFFS_FAIL;
/* Handle YAFFS2 case (backward scanning)
* If the shadowed object exists then ignore.
*/
- if (yaffs_FindObjectByNumber(dev, objId)) {
+ obj = yaffs_FindObjectByNumber(dev, objId);
+ if(obj)
return;
- }
}
/* Let's create it (if it does not exist) assuming it is a file so that it can do shrinking etc.
YAFFS_OBJECT_TYPE_FILE);
if (!obj)
return;
+ obj->isShadowed = 1;
yaffs_AddObjectToDirectory(dev->unlinkedDir, obj);
obj->variant.fileVariant.shrinkSize = 0;
obj->valid = 1; /* So that we don't read any other info for this file */
}
+/*
+ * This code iterates through all the objects making sure that they are rooted.
+ * Any unrooted objects are re-rooted in lost+found.
+ * An object needs to be in one of:
+ * - Directly under deleted, unlinked
+ * - Directly or indirectly under root.
+ *
+ * Note:
+ * This code assumes that we don't ever change the current relationships between
+ * directories:
+ * rootDir->parent == unlinkedDir->parent == deletedDir->parent == NULL
+ * lostNfound->parent == rootDir
+ *
+ * This fixes the problem where directories might have inadvertently been deleted
+ * leaving the object "hanging" without being rooted in the directory tree.
+ */
+
+static int yaffs_HasNULLParent(yaffs_Device *dev, yaffs_Object *obj)
+{
+ return (obj == dev->deletedDir ||
+ obj == dev->unlinkedDir||
+ obj == dev->rootDir);
+}
+
+static void yaffs_FixHangingObjects(yaffs_Device *dev)
+{
+ yaffs_Object *obj;
+ yaffs_Object *parent;
+ int i;
+ struct ylist_head *lh;
+ struct ylist_head *n;
+ int depthLimit;
+ int hanging;
+
+
+ /* Iterate through the objects in each hash entry,
+ * looking at each object.
+ * Make sure it is rooted.
+ */
+
+ for (i = 0; i < YAFFS_NOBJECT_BUCKETS; i++) {
+ ylist_for_each_safe(lh, n, &dev->objectBucket[i].list) {
+ if (lh) {
+ obj = ylist_entry(lh, yaffs_Object, hashLink);
+ parent= obj->parent;
+
+ if(yaffs_HasNULLParent(dev,obj)){
+ /* These directories are not hanging */
+ hanging = 0;
+ }
+ else if(!parent || parent->variantType != YAFFS_OBJECT_TYPE_DIRECTORY)
+ hanging = 1;
+ else if(yaffs_HasNULLParent(dev,parent))
+ hanging = 0;
+ else {
+ /*
+ * Need to follow the parent chain to see if it is hanging.
+ */
+ hanging = 0;
+ depthLimit=100;
+
+ while(parent != dev->rootDir &&
+ parent->parent &&
+ parent->parent->variantType == YAFFS_OBJECT_TYPE_DIRECTORY &&
+ depthLimit > 0){
+ parent = parent->parent;
+ depthLimit--;
+ }
+ if(parent != dev->rootDir)
+ hanging = 1;
+ }
+ if(hanging){
+ T(YAFFS_TRACE_SCAN,
+ (TSTR("Hanging object %d moved to lost and found" TENDSTR),
+ obj->objectId));
+ yaffs_AddObjectToDirectory(dev->lostNFoundDir,obj);
+ }
+ }
+ }
+ }
+}
+
+
+/*
+ * Delete directory contents for cleaning up lost and found.
+ */
+static void yaffs_DeleteDirectoryContents(yaffs_Object *dir)
+{
+ yaffs_Object *obj;
+ struct ylist_head *lh;
+ struct ylist_head *n;
+
+ if(dir->variantType != YAFFS_OBJECT_TYPE_DIRECTORY)
+ YBUG();
+
+ ylist_for_each_safe(lh, n, &dir->variant.directoryVariant.children) {
+ if (lh) {
+ obj = ylist_entry(lh, yaffs_Object, siblings);
+ if(obj->variantType == YAFFS_OBJECT_TYPE_DIRECTORY)
+ yaffs_DeleteDirectoryContents(obj);
+
+ T(YAFFS_TRACE_SCAN,
+ (TSTR("Deleting lost_found object %d" TENDSTR),
+ obj->objectId));
+
+ /* Need to use UnlinkObject since Delete would not handle
+ * hardlinked objects correctly.
+ */
+ yaffs_UnlinkObject(obj);
+ }
+ }
+
+}
+
+static void yaffs_EmptyLostAndFound(yaffs_Device *dev)
+{
+ yaffs_DeleteDirectoryContents(dev->lostNFoundDir);
+}
+
static int yaffs_Scan(yaffs_Device *dev)
{
yaffs_ExtendedTags tags;
* then setting the object header to unshadowed.
*/
obj = yaffs_FindObjectByNumber(dev, fixer->shadowedId);
- if(obj)
+ if (obj)
yaffs_DeleteObject(obj);
-
+
obj = yaffs_FindObjectByNumber(dev, fixer->objectId);
- if(obj){
+
+ if (obj)
yaffs_UpdateObjectHeader(obj, NULL, 1, 0, 0);
- }
YFREE(fixer);
}
yaffs_ReleaseTempBuffer(dev, chunkData, __LINE__);
- if (alloc_failed) {
+ if (alloc_failed)
return YAFFS_FAIL;
- }
T(YAFFS_TRACE_SCAN, (TSTR("yaffs_Scan ends" TENDSTR)));
yaffs_SetObjectName(in, oh->name);
if (in->variantType == YAFFS_OBJECT_TYPE_SYMLINK) {
- in->variant.symLinkVariant.alias =
+ in->variant.symLinkVariant.alias =
yaffs_CloneString(oh->alias);
if (!in->variant.symLinkVariant.alias)
alloc_failed = 1; /* Not returned to caller */
nBlocksToScan++;
- if (sequenceNumber >= dev->sequenceNumber) {
+ if (sequenceNumber >= dev->sequenceNumber)
dev->sequenceNumber = sequenceNumber;
- }
} else {
/* TODO: Nasty sequence number! */
T(YAFFS_TRACE_SCAN,
}
if (!in ||
-#ifdef CONFIG_YAFFS_DISABLE_LAZY_LOAD
- !in->valid ||
-#endif
+ (!in->valid && dev->disableLazyLoad) ||
tags.extraShadows ||
(!in->valid &&
(tags.objectId == YAFFS_OBJECTID_ROOT ||
thisSize;
}
- if (isShrink) {
+ if (isShrink)
bi->hasShrinkHeader = 1;
- }
}
/* Use existing - destroy this one. */
yaffs_ReleaseTempBuffer(dev, chunkData, __LINE__);
- if (alloc_failed) {
+ if (alloc_failed)
return YAFFS_FAIL;
- }
T(YAFFS_TRACE_SCAN, (TSTR("yaffs_ScanBackwards ends" TENDSTR)));
{
struct ylist_head *lh;
yaffs_Object *listObj;
-
+
if (!directory) {
YBUG();
return;
}
}
+/*
+ *yaffs_UpdateParent() handles fixing a directories mtime and ctime when a new
+ * link (ie. name) is created or deleted in the directory.
+ *
+ * ie.
+ * create dir/a : update dir's mtime/ctime
+ * rm dir/a: update dir's mtime/ctime
+ * modify dir/a: don't update dir's mtimme/ctime
+ */
+
+static void yaffs_UpdateParent(yaffs_Object *obj)
+{
+ if(!obj)
+ return;
+
+ obj->dirty = 1;
+ obj->yst_mtime = obj->yst_ctime = Y_CURRENT_TIME;
+
+ yaffs_UpdateObjectHeader(obj,NULL,0,0,0);
+}
static void yaffs_RemoveObjectFromDirectory(yaffs_Object *obj)
{
ylist_del_init(&obj->siblings);
obj->parent = NULL;
-
+
yaffs_VerifyDirectory(parent);
}
-
static void yaffs_AddObjectToDirectory(yaffs_Object *directory,
yaffs_Object *obj)
{
yaffs_Object *l;
- if (!name) {
+ if (!name)
return NULL;
- }
if (!directory) {
T(YAFFS_TRACE_ALWAYS,
/* Special case for lost-n-found */
if (l->objectId == YAFFS_OBJECTID_LOSTNFOUND) {
- if (yaffs_strcmp(name, YAFFS_LOSTNFOUND_NAME) == 0) {
+ if (yaffs_strcmp(name, YAFFS_LOSTNFOUND_NAME) == 0)
return l;
- }
} else if (yaffs_SumCompare(l->sum, sum) || l->hdrChunk <= 0) {
/* LostnFound chunk called Objxxx
* Do a real check
*/
yaffs_GetObjectName(l, buffer,
- YAFFS_MAX_NAME_LENGTH);
- if (yaffs_strncmp(name, buffer, YAFFS_MAX_NAME_LENGTH) == 0) {
+ YAFFS_MAX_NAME_LENGTH + 1);
+ if (yaffs_strncmp(name, buffer, YAFFS_MAX_NAME_LENGTH) == 0)
return l;
- }
}
}
}
T(YAFFS_TRACE_ALWAYS,
(TSTR
("tragedy: yaffs_FindObjectByName: non-directory" TENDSTR)));
- YBUG();
- return YAFFS_FAIL;
- }
+ YBUG();
+ return YAFFS_FAIL;
+ }
ylist_for_each(i, &theDir->variant.directoryVariant.children) {
if (i) {
l = ylist_entry(i, yaffs_Object, siblings);
- if (l && !fn(l)) {
+ if (l && !fn(l))
return YAFFS_FAIL;
- }
}
}
}
#ifdef CONFIG_YAFFS_SHORT_NAMES_IN_RAM
- else if (obj->shortName[0]) {
+ else if (obj->shortName[0])
yaffs_strcpy(name, obj->shortName);
- }
#endif
else {
int result;
/* Dereference any hard linking */
obj = yaffs_GetEquivalentObject(obj);
- if (obj->variantType == YAFFS_OBJECT_TYPE_FILE) {
+ if (obj->variantType == YAFFS_OBJECT_TYPE_FILE)
return obj->variant.fileVariant.fileSize;
- }
- if (obj->variantType == YAFFS_OBJECT_TYPE_SYMLINK) {
+ if (obj->variantType == YAFFS_OBJECT_TYPE_SYMLINK)
return yaffs_strlen(obj->variant.symLinkVariant.alias);
- } else {
+ else {
/* Only a directory should drop through to here */
return obj->myDev->nDataBytesPerChunk;
}
int count = 0;
struct ylist_head *i;
- if (!obj->unlinked) {
+ if (!obj->unlinked)
count++; /* the object itself */
- }
- ylist_for_each(i, &obj->hardLinks) {
+
+ ylist_for_each(i, &obj->hardLinks)
count++; /* add the hard links; */
- }
+
return count;
}
YCHAR *yaffs_GetSymlinkAlias(yaffs_Object *obj)
{
obj = yaffs_GetEquivalentObject(obj);
- if (obj->variantType == YAFFS_OBJECT_TYPE_SYMLINK) {
+ if (obj->variantType == YAFFS_OBJECT_TYPE_SYMLINK)
return yaffs_CloneString(obj->variant.symLinkVariant.alias);
- } else {
+ else
return yaffs_CloneString(_Y(""));
- }
}
#ifndef CONFIG_YAFFS_WINCE
{
YCHAR name[257];
- yaffs_GetObjectName(obj, name, 256);
+ yaffs_GetObjectName(obj, name, YAFFS_MAX_NAME_LENGTH + 1);
T(YAFFS_TRACE_ALWAYS,
(TSTR
void *buf;
int srCacheBytes = dev->nShortOpCaches * sizeof(yaffs_ChunkCache);
- if (dev->nShortOpCaches > YAFFS_MAX_SHORT_OP_CACHES) {
+ if (dev->nShortOpCaches > YAFFS_MAX_SHORT_OP_CACHES)
dev->nShortOpCaches = YAFFS_MAX_SHORT_OP_CACHES;
- }
dev->srCache = YMALLOC(srCacheBytes);
init_failed = 1;
}
- if (dev->isYaffs2) {
+ if (dev->isYaffs2)
dev->useHeaderFileSize = 1;
- }
+
if (!init_failed && !yaffs_InitialiseBlocks(dev))
init_failed = 1;
init_failed = 1;
yaffs_StripDeletedObjects(dev);
+ yaffs_FixHangingObjects(dev);
+ if(dev->emptyLostAndFound)
+ yaffs_EmptyLostAndFound(dev);
}
if (init_failed) {
yaffs_VerifyFreeChunks(dev);
yaffs_VerifyBlocks(dev);
+ /* Clean up any aborted checkpoint data */
+ if(!dev->isCheckpointed && dev->blocksInCheckpoint > 0)
+ yaffs_InvalidateCheckpoint(dev);
T(YAFFS_TRACE_TRACING,
(TSTR("yaffs: yaffs_GutsInitialise() done.\n" TENDSTR)));
YFREE(dev->gcCleanupList);
- for (i = 0; i < YAFFS_N_TEMP_BUFFERS; i++) {
+ for (i = 0; i < YAFFS_N_TEMP_BUFFERS; i++)
YFREE(dev->tempBuffer[i].buffer);
- }
-
dev->isMounted = 0;
int nFree;
int nDirtyCacheChunks;
int blocksForCheckpoint;
+ int i;
#if 1
nFree = dev->nFreeChunks;
/* Now count the number of dirty chunks in the cache and subtract those */
- {
- int i;
- for (nDirtyCacheChunks = 0, i = 0; i < dev->nShortOpCaches; i++) {
- if (dev->srCache[i].dirty)
- nDirtyCacheChunks++;
- }
+ for (nDirtyCacheChunks = 0, i = 0; i < dev->nShortOpCaches; i++) {
+ if (dev->srCache[i].dirty)
+ nDirtyCacheChunks++;
}
nFree -= nDirtyCacheChunks;
#define yaffs_CheckStruct(structure, syze, name) \
do { \
if (sizeof(structure) != syze) { \
- T(YAFFS_TRACE_ALWAYS, (TSTR("%s should be %d but is %d\n" TENDSTR),\
+ T(YAFFS_TRACE_ALWAYS, (TSTR("%s should be %d but is %d\n" TENDSTR),\
name, syze, sizeof(structure))); \
return YAFFS_FAIL; \
} \