*/
const char *yaffs_guts_c_version =
- "$Id: yaffs_guts.c,v 1.94 2009-11-10 23:55:05 charles Exp $";
+ "$Id: yaffs_guts.c,v 1.99 2009-12-14 22:03:05 charles Exp $";
#include "yportenv.h"
yaffs_FileStructure *fStruct,
__u32 chunkId);
+static void yaffs_SkipRestOfBlock(yaffs_Device *dev);
+static int yaffs_VerifyChunkWritten(yaffs_Device *dev,
+ int chunkInNAND,
+ const __u8 *data,
+ yaffs_ExtendedTags *tags);
+
/* Function to calculate chunk and offset */
static void yaffs_AddrToChunk(yaffs_Device *dev, loff_t addr, int *chunkOut,
}
+
+static int yaffs_VerifyChunkWritten(yaffs_Device *dev,
+ int chunkInNAND,
+ const __u8 *data,
+ yaffs_ExtendedTags *tags)
+{
+ int retval = YAFFS_OK;
+ yaffs_ExtendedTags tempTags;
+ __u8 *buffer = yaffs_GetTempBuffer(dev,__LINE__);
+ int result;
+
+ result = yaffs_ReadChunkWithTagsFromNAND(dev,chunkInNAND,buffer,&tempTags);
+ if(memcmp(buffer,data,dev->nDataBytesPerChunk) ||
+ tempTags.objectId != tags->objectId ||
+ tempTags.chunkId != tags->chunkId ||
+ tempTags.byteCount != tags->byteCount)
+ retval = YAFFS_FAIL;
+
+ yaffs_ReleaseTempBuffer(dev, buffer, __LINE__);
+
+ return retval;
+}
+
static int yaffs_WriteNewChunkWithTagsToNAND(struct yaffs_DeviceStruct *dev,
const __u8 *data,
yaffs_ExtendedTags *tags,
* 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.
+ *
+ * Mods to the above
+ * If an erase check fails or the write fails we skip the
+ * rest of the block.
*/
- if (bi->gcPrioritise) {
- yaffs_DeleteChunk(dev, chunk, 1, __LINE__);
- /* try another chunk */
- continue;
- }
/* let's give it a try */
attempts++;
(TSTR("**>> yaffs chunk %d was not erased"
TENDSTR), chunk));
- /* try another chunk */
+ /* If not erased, delete this one,
+ * skip rest of block and
+ * try another chunk */
+ yaffs_DeleteChunk(dev,chunk,1,__LINE__);
+ yaffs_SkipRestOfBlock(dev);
continue;
}
- bi->skipErasedCheck = 1;
}
writeOk = yaffs_WriteChunkWithTagsToNAND(dev, chunk,
data, tags);
+
+ if(!bi->skipErasedCheck)
+ writeOk = yaffs_VerifyChunkWritten(dev, chunk, data, tags);
+
if (writeOk != YAFFS_OK) {
+ /* Clean up aborted write, skip to next block and
+ * try another chunk */
yaffs_HandleWriteChunkError(dev, chunk, erasedOk);
- /* try another chunk */
continue;
}
+ bi->skipErasedCheck = 1;
+
/* Copy the data into the robustification buffer */
yaffs_HandleWriteChunkOk(dev, chunk, data, tags);
/* Delete the chunk */
yaffs_DeleteChunk(dev, chunkInNAND, 1, __LINE__);
+ yaffs_SkipRestOfBlock(dev);
}
{
#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)
+ if (name && yaffs_strnlen(name,YAFFS_SHORT_NAME_LENGTH+1) <= YAFFS_SHORT_NAME_LENGTH)
yaffs_strcpy(obj->shortName, name);
else
obj->shortName[0] = _Y('\0');
list = YMALLOC(sizeof(yaffs_ObjectList));
if (!newObjects || !list) {
- if (newObjects)
+ if (newObjects){
YFREE(newObjects);
- if (list)
+ newObjects = NULL;
+ }
+ if (list){
YFREE(list);
+ list = NULL;
+ }
T(YAFFS_TRACE_ALLOCATE,
(TSTR("yaffs: Could not allocate more objects" TENDSTR)));
return YAFFS_FAIL;
#ifdef VALGRIND_TEST
YFREE(tn);
+ tn = NULL;
#else
/* Link into the free list. */
tn->siblings.next = (struct ylist_head *)(dev->freeObjects);
static YCHAR *yaffs_CloneString(const YCHAR *str)
{
YCHAR *newStr = NULL;
+ int len;
- if (str && *str) {
- newStr = YMALLOC((yaffs_strlen(str) + 1) * sizeof(YCHAR));
- if (newStr)
- yaffs_strcpy(newStr, str);
- }
+ if (!str)
+ str = _Y("");
+ len = yaffs_strnlen(str,YAFFS_MAX_ALIAS_LENGTH);
+ newStr = YMALLOC((len + 1) * sizeof(YCHAR));
+ if (newStr){
+ yaffs_strncpy(newStr, str,len);
+ newStr[len] = 0;
+ }
return newStr;
}
/*
* Mknod (create) a new object.
* equivalentObject only has meaning for a hard link;
- * aliasString only has meaning for a sumlink.
+ * aliasString only has meaning for a symlink.
* rdev only has meaning for devices (a subset of special objects)
*/
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);
force = 1;
#endif
- if(yaffs_strlen(newName) > YAFFS_MAX_NAME_LENGTH)
+ if(yaffs_strnlen(newName,YAFFS_MAX_NAME_LENGTH+1) > YAFFS_MAX_NAME_LENGTH)
/* ENAMETOOLONG */
return YAFFS_FAIL;
}
+/*
+ * yaffs_SkipRestOfBlock() skips over the rest of the allocation block
+ * if we don't want to write to it.
+ */
+static void yaffs_SkipRestOfBlock(yaffs_Device *dev)
+{
+ if(dev->allocationBlock > 0){
+ yaffs_BlockInfo *bi = yaffs_GetBlockInfo(dev, dev->allocationBlock);
+ if(bi->blockState == YAFFS_BLOCK_STATE_ALLOCATING){
+ bi->blockState = YAFFS_BLOCK_STATE_FULL;
+ dev->allocationBlock = -1;
+ }
+ }
+}
+
+
static int yaffs_GarbageCollectBlock(yaffs_Device *dev, int block,
int wholeBlock)
{
if (tags.chunkId == 0) {
/* It is an object Id,
* We need to nuke the shrinkheader flags first
+ * Also need to clean up shadowing.
* We no longer want the shrinkHeader flag since its work is done
* and if it is left in place it will mess up scanning.
*/
oh = (yaffs_ObjectHeader *)buffer;
oh->isShrink = 0;
tags.extraIsShrinkHeader = 0;
+ oh->shadowsObject = 0;
+ oh->inbandShadowsObject = 0;
+ tags.extraShadows = 0;
yaffs_VerifyObjectHeader(object, oh, &tags, 1);
}
int newChunkId;
yaffs_ExtendedTags newTags;
yaffs_ExtendedTags oldTags;
+ YCHAR *alias = NULL;
__u8 *buffer = NULL;
YCHAR oldName[YAFFS_MAX_NAME_LENGTH + 1];
/* Do nothing */
break;
case YAFFS_OBJECT_TYPE_SYMLINK:
+ alias = in->variant.symLinkVariant.alias;
+ if(!alias)
+ alias = _Y("no alias");
yaffs_strncpy(oh->alias,
- in->variant.symLinkVariant.alias,
+ alias,
YAFFS_MAX_ALIAS_LENGTH);
oh->alias[YAFFS_MAX_ALIAS_LENGTH] = 0;
break;
loff_t yaffs_GetFileSize(yaffs_Object *obj)
{
+ YCHAR *alias = NULL;
obj = yaffs_GetEquivalentObject(obj);
switch (obj->variantType) {
case YAFFS_OBJECT_TYPE_FILE:
return obj->variant.fileVariant.fileSize;
case YAFFS_OBJECT_TYPE_SYMLINK:
- return yaffs_strlen(obj->variant.symLinkVariant.alias);
+ alias = obj->variant.symLinkVariant.alias;
+ if(!alias)
+ return 0;
+ return yaffs_strnlen(alias,YAFFS_MAX_ALIAS_LENGTH);
default:
return 0;
}
static int yaffs_DeleteSymLink(yaffs_Object *in)
{
- YFREE(in->variant.symLinkVariant.alias);
+ if(in->variant.symLinkVariant.alias)
+ YFREE(in->variant.symLinkVariant.alias);
+ in->variant.symLinkVariant.alias=NULL;
return yaffs_DoGenericObjectDeletion(in);
}
dev->allocationBlock = blk;
dev->allocationPage = c;
dev->allocationBlockFinder = blk;
- /* Set it to here to encourage the allocator to go forth from here. */
+ /* Set block finder here to encourage the allocator to go forth from here. */
}
break;
}
-/*
- if (parent == dev->deletedDir) {
- yaffs_DestroyObject(in);
- bi->hasShrinkHeader = 1;
- }
-*/
}
}
}
state = YAFFS_BLOCK_STATE_FULL;
}
+ if (state == YAFFS_BLOCK_STATE_ALLOCATING) {
+ /* If the block was partially allocated then treat it as fully allocated.*/
+ state = YAFFS_BLOCK_STATE_FULL;
+ dev->allocationBlock = -1;
+ }
+
bi->blockState = state;
/* Now let's see if it was dirty */
dev->allocationBlockFinder = blk;
} else {
/* This is a partially written block that is not
- * the current allocation block. This block must have
- * had a write failure, so set up for retirement.
+ * the current allocation block.
*/
- /* bi->needsRetiring = 1; ??? TODO */
- bi->gcPrioritise = 1;
-
T(YAFFS_TRACE_ALWAYS,
(TSTR("Partially written block %d detected" TENDSTR),
blk));
oh->
shadowsObject,
1);
+
yaffs_SetObjectName(in, oh->name);
state = YAFFS_BLOCK_STATE_FULL;
}
+
bi->blockState = state;
/* Now let's see if it was dirty */
}
}
+
+ yaffs_SkipRestOfBlock(dev);
if (altBlockIndex)
YFREE_ALT(blockIndex);
}
#ifdef CONFIG_YAFFS_SHORT_NAMES_IN_RAM
else if (obj->shortName[0])
- yaffs_strcpy(name, obj->shortName);
+ yaffs_strncpy(name, obj->shortName,YAFFS_SHORT_NAME_LENGTH+1);
#endif
else {
int result;
NULL);
}
yaffs_strncpy(name, oh->name, buffSize - 1);
+ name[buffSize-1]=0;
yaffs_ReleaseTempBuffer(obj->myDev, buffer, __LINE__);
}
- return yaffs_strlen(name);
+ return yaffs_strnlen(name,buffSize-1);
}
int yaffs_GetObjectFileLength(yaffs_Object *obj)
if (obj->variantType == YAFFS_OBJECT_TYPE_FILE)
return obj->variant.fileVariant.fileSize;
- if (obj->variantType == YAFFS_OBJECT_TYPE_SYMLINK)
- return yaffs_strlen(obj->variant.symLinkVariant.alias);
- else {
+ if (obj->variantType == YAFFS_OBJECT_TYPE_SYMLINK){
+ if(!obj->variant.symLinkVariant.alias)
+ return 0;
+ return yaffs_strnlen(obj->variant.symLinkVariant.alias,YAFFS_MAX_ALIAS_LENGTH);
+ } else {
/* Only a directory should drop through to here */
return obj->myDev->nDataBytesPerChunk;
}