- if(retVal == YAFFS_OK)
- yaffs_DeleteChunk(dev, oldChunk, markNAND, __LINE__);
-
- }
- }
-
- yaffs_ReleaseTempBuffer(dev, buffer, __LINE__);
-
-
- /* Do any required cleanups */
- for (i = 0; i < cleanups; i++) {
- /* Time to delete the file too */
- object =
- yaffs_FindObjectByNumber(dev,
- dev->gcCleanupList[i]);
- if (object) {
- yaffs_FreeTnode(dev,
- object->variant.fileVariant.
- top);
- object->variant.fileVariant.top = NULL;
- T(YAFFS_TRACE_GC,
- (TSTR
- ("yaffs: About to finally delete object %d"
- TENDSTR), object->objectId));
- yaffs_DoGenericObjectDeletion(object);
- object->myDev->nDeletedFiles--;
- }
-
- }
-
- }
-
- yaffs_VerifyCollectedBlock(dev,bi,block);
-
- if (chunksBefore >= (chunksAfter = yaffs_GetErasedChunks(dev))) {
- T(YAFFS_TRACE_GC,
- (TSTR
- ("gc did not increase free chunks before %d after %d"
- TENDSTR), chunksBefore, chunksAfter));
- }
-
- /* If the gc completed then clear the current gcBlock so that we find another. */
- if(bi->blockState != YAFFS_BLOCK_STATE_COLLECTING){
- dev->gcBlock = -1;
- dev->gcChunk = 0;
- }
-
- dev->isDoingGC = 0;
-
- return retVal;
-}
-
-/* New garbage collector
- * If we're very low on erased blocks then we do aggressive garbage collection
- * otherwise we do "leasurely" garbage collection.
- * Aggressive gc looks further (whole array) and will accept less dirty blocks.
- * Passive gc only inspects smaller areas and will only accept more dirty blocks.
- *
- * The idea is to help clear out space in a more spread-out manner.
- * Dunno if it really does anything useful.
- */
-static int yaffs_CheckGarbageCollection(yaffs_Device * dev)
-{
- int block;
- int aggressive;
- int gcOk = YAFFS_OK;
- int maxTries = 0;
-
- int checkpointBlockAdjust;
-
- if (dev->isDoingGC) {
- /* Bail out so we don't get recursive gc */
- return YAFFS_OK;
- }
-
- /* This loop should pass the first time.
- * We'll only see looping here if the erase of the collected block fails.
- */
-
- do {
- maxTries++;
-
- checkpointBlockAdjust = yaffs_CalcCheckpointBlocksRequired(dev) - dev->blocksInCheckpoint;
- if(checkpointBlockAdjust < 0)
- checkpointBlockAdjust = 0;
-
- if (dev->nErasedBlocks < (dev->nReservedBlocks + checkpointBlockAdjust + 2)) {
- /* We need a block soon...*/
- aggressive = 1;
- } else {
- /* We're in no hurry */
- aggressive = 0;
- }
-
- if(dev->gcBlock <= 0){
- dev->gcBlock = yaffs_FindBlockForGarbageCollection(dev, aggressive);
- dev->gcChunk = 0;
- }
-
- block = dev->gcBlock;
-
- if (block > 0) {
- dev->garbageCollections++;
- if (!aggressive) {
- dev->passiveGarbageCollections++;
- }
-
- T(YAFFS_TRACE_GC,
- (TSTR
- ("yaffs: GC erasedBlocks %d aggressive %d" TENDSTR),
- dev->nErasedBlocks, aggressive));
-
- gcOk = yaffs_GarbageCollectBlock(dev,block,aggressive);
- }
-
- if (dev->nErasedBlocks < (dev->nReservedBlocks) && block > 0) {
- T(YAFFS_TRACE_GC,
- (TSTR
- ("yaffs: GC !!!no reclaim!!! erasedBlocks %d after try %d block %d"
- TENDSTR), dev->nErasedBlocks, maxTries, block));
- }
- } while ((dev->nErasedBlocks < dev->nReservedBlocks) &&
- (block > 0) &&
- (maxTries < 2));
-
- return aggressive ? gcOk : YAFFS_OK;
-}
-
-/*------------------------- TAGS --------------------------------*/
-
-static int yaffs_TagsMatch(const yaffs_ExtendedTags * tags, int objectId,
- int chunkInObject)
-{
- return (tags->chunkId == chunkInObject &&
- tags->objectId == objectId && !tags->chunkDeleted) ? 1 : 0;
-
-}
-
-
-/*-------------------- Data file manipulation -----------------*/
-
-static int yaffs_FindChunkInFile(yaffs_Object * in, int chunkInInode,
- yaffs_ExtendedTags * tags)
-{
- /*Get the Tnode, then get the level 0 offset chunk offset */
- yaffs_Tnode *tn;
- int theChunk = -1;
- yaffs_ExtendedTags localTags;
- int retVal = -1;
-
- yaffs_Device *dev = in->myDev;
-
- if (!tags) {
- /* Passed a NULL, so use our own tags space */
- tags = &localTags;
- }
-
- tn = yaffs_FindLevel0Tnode(dev, &in->variant.fileVariant, chunkInInode);
-
- if (tn) {
- theChunk = yaffs_GetChunkGroupBase(dev,tn,chunkInInode);
-
- retVal =
- yaffs_FindChunkInGroup(dev, theChunk, tags, in->objectId,
- chunkInInode);
- }
- return retVal;
-}
-
-static int yaffs_FindAndDeleteChunkInFile(yaffs_Object * in, int chunkInInode,
- yaffs_ExtendedTags * tags)
-{
- /* Get the Tnode, then get the level 0 offset chunk offset */
- yaffs_Tnode *tn;
- int theChunk = -1;
- yaffs_ExtendedTags localTags;
-
- yaffs_Device *dev = in->myDev;
- int retVal = -1;
-
- if (!tags) {
- /* Passed a NULL, so use our own tags space */
- tags = &localTags;
- }
-
- tn = yaffs_FindLevel0Tnode(dev, &in->variant.fileVariant, chunkInInode);
-
- if (tn) {
-
- theChunk = yaffs_GetChunkGroupBase(dev,tn,chunkInInode);
-
- retVal =
- yaffs_FindChunkInGroup(dev, theChunk, tags, in->objectId,
- 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) {
- /* T(("Could not find %d to delete\n",chunkInInode)); */
- }
- return retVal;
-}
-
-#ifdef YAFFS_PARANOID
-
-static int yaffs_CheckFileSanity(yaffs_Object * in)
-{
- int chunk;
- int nChunks;
- int fSize;
- int failed = 0;
- int objId;
- yaffs_Tnode *tn;
- yaffs_Tags localTags;
- yaffs_Tags *tags = &localTags;
- int theChunk;
- int chunkDeleted;
-
- if (in->variantType != YAFFS_OBJECT_TYPE_FILE) {
- /* T(("Object not a file\n")); */
- return YAFFS_FAIL;
- }
-
- objId = in->objectId;
- fSize = in->variant.fileVariant.fileSize;
- nChunks =
- (fSize + in->myDev->nDataBytesPerChunk - 1) / in->myDev->nDataBytesPerChunk;
-
- for (chunk = 1; chunk <= nChunks; chunk++) {
- tn = yaffs_FindLevel0Tnode(in->myDev, &in->variant.fileVariant,
- chunk);
-
- if (tn) {
-
- theChunk = yaffs_GetChunkGroupBase(dev,tn,chunk);
-
- if (yaffs_CheckChunkBits
- (dev, theChunk / dev->nChunksPerBlock,
- theChunk % dev->nChunksPerBlock)) {
-
- yaffs_ReadChunkTagsFromNAND(in->myDev, theChunk,
- tags,
- &chunkDeleted);
- if (yaffs_TagsMatch
- (tags, in->objectId, chunk, chunkDeleted)) {
- /* found it; */
-
- }
- } else {
-
- failed = 1;
- }
-
- } else {
- /* T(("No level 0 found for %d\n", chunk)); */
- }
- }
-
- return failed ? YAFFS_FAIL : YAFFS_OK;
-}
-
-#endif
-
-static int yaffs_PutChunkIntoFile(yaffs_Object * in, int chunkInInode,
- int chunkInNAND, int inScan)
-{
- /* NB inScan is zero unless scanning.
- * For forward scanning, inScan is > 0;
- * for backward scanning inScan is < 0
- */
-
- yaffs_Tnode *tn;
- yaffs_Device *dev = in->myDev;
- int existingChunk;
- yaffs_ExtendedTags existingTags;
- yaffs_ExtendedTags newTags;
- unsigned existingSerial, newSerial;
-
- if (in->variantType != YAFFS_OBJECT_TYPE_FILE) {
- /* Just ignore an attempt at putting a chunk into a non-file during scanning
- * If it is not during Scanning then something went wrong!
- */
- if (!inScan) {
- T(YAFFS_TRACE_ERROR,
- (TSTR
- ("yaffs tragedy:attempt to put data chunk into a non-file"
- TENDSTR)));
- YBUG();
- }
-
- yaffs_DeleteChunk(dev, chunkInNAND, 1, __LINE__);
- return YAFFS_OK;
- }
-
- tn = yaffs_AddOrFindLevel0Tnode(dev,
- &in->variant.fileVariant,
- chunkInInode,
- NULL);
- if (!tn) {
- return YAFFS_FAIL;
- }
-
- existingChunk = yaffs_GetChunkGroupBase(dev,tn,chunkInInode);
-
- if (inScan != 0) {
- /* If we're scanning then we need to test for duplicates
- * NB This does not need to be efficient since it should only ever
- * happen when the power fails during a write, then only one
- * chunk should ever be affected.
- *
- * Correction for YAFFS2: This could happen quite a lot and we need to think about efficiency! TODO
- * Update: For backward scanning we don't need to re-read tags so this is quite cheap.
- */
-
- if (existingChunk > 0) {
- /* NB Right now existing chunk will not be real chunkId if the device >= 32MB
- * thus we have to do a FindChunkInFile to get the real chunk id.
- *
- * We have a duplicate now we need to decide which one to use:
- *
- * Backwards scanning YAFFS2: The old one is what we use, dump the new one.
- * Forward scanning YAFFS2: The new one is what we use, dump the old one.
- * YAFFS1: Get both sets of tags and compare serial numbers.
- */
-
- if (inScan > 0) {
- /* Only do this for forward scanning */
- yaffs_ReadChunkWithTagsFromNAND(dev,
- chunkInNAND,
- NULL, &newTags);
-
- /* Do a proper find */
- existingChunk =
- yaffs_FindChunkInFile(in, chunkInInode,
- &existingTags);
- }
-
- if (existingChunk <= 0) {
- /*Hoosterman - how did this happen? */
-
- T(YAFFS_TRACE_ERROR,
- (TSTR
- ("yaffs tragedy: existing chunk < 0 in scan"
- TENDSTR)));
-
- }
-
- /* NB The deleted flags should be false, otherwise the chunks will
- * not be loaded during a scan
- */
-
- if(inScan > 0) {
- newSerial = newTags.serialNumber;
- existingSerial = existingTags.serialNumber;
- }
-
- if ((inScan > 0) &&
- (in->myDev->isYaffs2 ||
- existingChunk <= 0 ||
- ((existingSerial + 1) & 3) == newSerial)) {
- /* Forward scanning.
- * Use new
- * Delete the old one and drop through to update the tnode
- */
- yaffs_DeleteChunk(dev, existingChunk, 1,
- __LINE__);
- } else {
- /* Backward scanning or we want to use the existing one
- * Use existing.
- * Delete the new one and return early so that the tnode isn't changed
- */
- yaffs_DeleteChunk(dev, chunkInNAND, 1,
- __LINE__);
- return YAFFS_OK;
- }
- }
-
- }
-
- if (existingChunk == 0) {
- in->nDataChunks++;
- }
-
- yaffs_PutLevel0Tnode(dev,tn,chunkInInode,chunkInNAND);
-
- return YAFFS_OK;
-}
-
-static int yaffs_ReadChunkDataFromObject(yaffs_Object * in, int chunkInInode,
- __u8 * buffer)
-{
- int chunkInNAND = yaffs_FindChunkInFile(in, chunkInInode, NULL);
-
- if (chunkInNAND >= 0) {
- return yaffs_ReadChunkWithTagsFromNAND(in->myDev, chunkInNAND,
- buffer,NULL);
- } else {
- T(YAFFS_TRACE_NANDACCESS,
- (TSTR("Chunk %d not found zero instead" TENDSTR),
- chunkInNAND));
- /* get sane (zero) data if you read a hole */
- memset(buffer, 0, in->myDev->nDataBytesPerChunk);
- return 0;
- }
-
-}
-
-void yaffs_DeleteChunk(yaffs_Device * dev, int chunkId, int markNAND, int lyn)
-{
- int block;
- int page;
- yaffs_ExtendedTags tags;
- yaffs_BlockInfo *bi;
-
- if (chunkId <= 0)
- return;
-
-
- dev->nDeletions++;
- block = chunkId / dev->nChunksPerBlock;
- page = chunkId % dev->nChunksPerBlock;
-
-
- if(!yaffs_CheckChunkBit(dev,block,page))
- T(YAFFS_TRACE_VERIFY,
- (TSTR("Deleting invalid chunk %d"TENDSTR),
- chunkId));
-
- bi = yaffs_GetBlockInfo(dev, block);
-
- T(YAFFS_TRACE_DELETION,
- (TSTR("line %d delete of chunk %d" TENDSTR), lyn, chunkId));
-
- if (markNAND &&
- bi->blockState != YAFFS_BLOCK_STATE_COLLECTING && !dev->isYaffs2) {
-
- yaffs_InitialiseTags(&tags);
-
- tags.chunkDeleted = 1;
-
- yaffs_WriteChunkWithTagsToNAND(dev, chunkId, NULL, &tags);
- yaffs_HandleUpdateChunk(dev, chunkId, &tags);
- } else {
- dev->nUnmarkedDeletions++;
- }
-
- /* Pull out of the management area.
- * If the whole block became dirty, this will kick off an erasure.
- */
- if (bi->blockState == YAFFS_BLOCK_STATE_ALLOCATING ||
- bi->blockState == YAFFS_BLOCK_STATE_FULL ||
- bi->blockState == YAFFS_BLOCK_STATE_NEEDS_SCANNING ||
- bi->blockState == YAFFS_BLOCK_STATE_COLLECTING) {
- dev->nFreeChunks++;
-
- yaffs_ClearChunkBit(dev, block, page);
-
- bi->pagesInUse--;
-
- if (bi->pagesInUse == 0 &&
- !bi->hasShrinkHeader &&
- bi->blockState != YAFFS_BLOCK_STATE_ALLOCATING &&
- bi->blockState != YAFFS_BLOCK_STATE_NEEDS_SCANNING) {
- yaffs_BlockBecameDirty(dev, block);
- }
-
- } else {
- /* T(("Bad news deleting chunk %d\n",chunkId)); */
- }
-
-}
-
-static int yaffs_WriteChunkDataToObject(yaffs_Object * in, int chunkInInode,
- const __u8 * buffer, int nBytes,
- int useReserve)
-{
- /* Find old chunk Need to do this to get serial number
- * Write new one and patch into tree.
- * Invalidate old tags.
- */
-
- int prevChunkId;
- yaffs_ExtendedTags prevTags;
-
- int newChunkId;
- yaffs_ExtendedTags newTags;
-
- yaffs_Device *dev = in->myDev;
-
- yaffs_CheckGarbageCollection(dev);
-
- /* Get the previous chunk at this location in the file if it exists */
- prevChunkId = yaffs_FindChunkInFile(in, chunkInInode, &prevTags);
-
- /* Set up new tags */
- yaffs_InitialiseTags(&newTags);
-
- newTags.chunkId = chunkInInode;
- newTags.objectId = in->objectId;
- 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));
- YBUG();
- }
-
-
-
- newChunkId =
- yaffs_WriteNewChunkWithTagsToNAND(dev, buffer, &newTags,
- useReserve);
-
- if (newChunkId >= 0) {
- yaffs_PutChunkIntoFile(in, chunkInInode, newChunkId, 0);
-
- if (prevChunkId >= 0) {
- yaffs_DeleteChunk(dev, prevChunkId, 1, __LINE__);
-
- }
-
- yaffs_CheckFileSanity(in);
- }
- return newChunkId;
-
-}
-
-/* UpdateObjectHeader updates the header on NAND for an object.
- * If name is not NULL, then that new name is used.
- */
-int yaffs_UpdateObjectHeader(yaffs_Object * in, const YCHAR * name, int force,
- int isShrink, int shadows)
-{
-
- yaffs_BlockInfo *bi;
-
- yaffs_Device *dev = in->myDev;
-
- int prevChunkId;
- int retVal = 0;
- int result = 0;
-
- int newChunkId;
- yaffs_ExtendedTags newTags;
- yaffs_ExtendedTags oldTags;
-
- __u8 *buffer = NULL;
- YCHAR oldName[YAFFS_MAX_NAME_LENGTH + 1];
-
- yaffs_ObjectHeader *oh = NULL;
-
- yaffs_strcpy(oldName,_Y("silly old name"));
-
-
- if (!in->fake ||
- in == dev->rootDir || /* The rootDir should also be saved */
- force) {
-
- yaffs_CheckGarbageCollection(dev);
- yaffs_CheckObjectDetailsLoaded(in);
-
- buffer = yaffs_GetTempBuffer(in->myDev, __LINE__);
- oh = (yaffs_ObjectHeader *) buffer;
-
- prevChunkId = in->hdrChunk;
-
- if (prevChunkId > 0) {
- result = yaffs_ReadChunkWithTagsFromNAND(dev, prevChunkId,
- buffer, &oldTags);
-
- yaffs_VerifyObjectHeader(in,oh,&oldTags,0);
-
- memcpy(oldName, oh->name, sizeof(oh->name));
- }
-
- memset(buffer, 0xFF, dev->nDataBytesPerChunk);
-
- oh->type = in->variantType;
- oh->yst_mode = in->yst_mode;
- oh->shadowsObject = oh->inbandShadowsObject = shadows;
-
-#ifdef CONFIG_YAFFS_WINCE
- oh->win_atime[0] = in->win_atime[0];
- oh->win_ctime[0] = in->win_ctime[0];
- oh->win_mtime[0] = in->win_mtime[0];
- oh->win_atime[1] = in->win_atime[1];
- oh->win_ctime[1] = in->win_ctime[1];
- oh->win_mtime[1] = in->win_mtime[1];
-#else
- oh->yst_uid = in->yst_uid;
- oh->yst_gid = in->yst_gid;
- oh->yst_atime = in->yst_atime;
- oh->yst_mtime = in->yst_mtime;
- oh->yst_ctime = in->yst_ctime;
- oh->yst_rdev = in->yst_rdev;
-#endif
- if (in->parent) {
- oh->parentObjectId = in->parent->objectId;
- } 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) {
- memcpy(oh->name, oldName, sizeof(oh->name));
- } else {
- memset(oh->name, 0, sizeof(oh->name));
- }
-
- oh->isShrink = isShrink;
-
- switch (in->variantType) {
- case YAFFS_OBJECT_TYPE_UNKNOWN:
- /* Should not happen */
- break;
- case YAFFS_OBJECT_TYPE_FILE:
- oh->fileSize =
- (oh->parentObjectId == YAFFS_OBJECTID_DELETED
- || oh->parentObjectId ==
- YAFFS_OBJECTID_UNLINKED) ? 0 : in->variant.
- fileVariant.fileSize;
- break;
- case YAFFS_OBJECT_TYPE_HARDLINK:
- oh->equivalentObjectId =
- in->variant.hardLinkVariant.equivalentObjectId;
- break;
- case YAFFS_OBJECT_TYPE_SPECIAL:
- /* Do nothing */
- break;
- case YAFFS_OBJECT_TYPE_DIRECTORY:
- /* Do nothing */
- break;
- case YAFFS_OBJECT_TYPE_SYMLINK:
- yaffs_strncpy(oh->alias,
- in->variant.symLinkVariant.alias,
- YAFFS_MAX_ALIAS_LENGTH);
- oh->alias[YAFFS_MAX_ALIAS_LENGTH] = 0;
- break;
- }
-
- /* Tags */
- yaffs_InitialiseTags(&newTags);
- in->serial++;
- newTags.chunkId = 0;
- newTags.objectId = in->objectId;
- newTags.serialNumber = in->serial;
-
- /* Add extra info for file header */
-
- newTags.extraHeaderInfoAvailable = 1;
- newTags.extraParentObjectId = oh->parentObjectId;
- newTags.extraFileLength = oh->fileSize;
- newTags.extraIsShrinkHeader = oh->isShrink;
- newTags.extraEquivalentObjectId = oh->equivalentObjectId;
- newTags.extraShadows = (oh->shadowsObject > 0) ? 1 : 0;
- newTags.extraObjectType = in->variantType;
-
- yaffs_VerifyObjectHeader(in,oh,&newTags,1);
-
- /* Create new chunk in NAND */
- newChunkId =
- yaffs_WriteNewChunkWithTagsToNAND(dev, buffer, &newTags,
- (prevChunkId >= 0) ? 1 : 0);
-
- if (newChunkId >= 0) {
-
- in->hdrChunk = newChunkId;
-
- if (prevChunkId >= 0) {
- yaffs_DeleteChunk(dev, prevChunkId, 1,
- __LINE__);
- }
-
- if(!yaffs_ObjectHasCachedWriteData(in))
- in->dirty = 0;
-
- /* If this was a shrink, then mark the block that the chunk lives on */
- if (isShrink) {
- bi = yaffs_GetBlockInfo(in->myDev,
- newChunkId /in->myDev-> nChunksPerBlock);
- bi->hasShrinkHeader = 1;
- }
-
- }
-
- retVal = newChunkId;
-
- }
-
- if (buffer)
- yaffs_ReleaseTempBuffer(dev, buffer, __LINE__);
-
- return retVal;
-}
-
-/*------------------------ Short Operations Cache ----------------------------------------
- * In many situations where there is no high level buffering (eg WinCE) a lot of
- * reads might be short sequential reads, and a lot of writes may be short
- * sequential writes. eg. scanning/writing a jpeg file.
- * In these cases, a short read/write cache can provide a huge perfomance benefit
- * with dumb-as-a-rock code.
- * In Linux, the page cache provides read buffering aand the short op cache provides write
- * buffering.
- *
- * There are a limited number (~10) of cache chunks per device so that we don't
- * need a very intelligent search.
- */
-
-static int yaffs_ObjectHasCachedWriteData(yaffs_Object *obj)
-{
- yaffs_Device *dev = obj->myDev;
- int i;
- yaffs_ChunkCache *cache;
- int nCaches = obj->myDev->nShortOpCaches;
-
- for(i = 0; i < nCaches; i++){
- cache = &dev->srCache[i];
- if (cache->object == obj &&
- cache->dirty)
- return 1;
- }
-
- return 0;
-}
-
-
-static void yaffs_FlushFilesChunkCache(yaffs_Object * obj)
-{
- yaffs_Device *dev = obj->myDev;
- int lowest = -99; /* Stop compiler whining. */
- int i;
- yaffs_ChunkCache *cache;
- int chunkWritten = 0;
- int nCaches = obj->myDev->nShortOpCaches;
-
- if (nCaches > 0) {
- do {
- cache = NULL;
-
- /* Find the dirty cache for this object with the lowest chunk id. */
- for (i = 0; i < nCaches; i++) {
- if (dev->srCache[i].object == obj &&
- dev->srCache[i].dirty) {
- if (!cache
- || dev->srCache[i].chunkId <
- lowest) {
- cache = &dev->srCache[i];
- lowest = cache->chunkId;
- }
- }
- }
-
- if (cache && !cache->locked) {
- /* Write it out and free it up */
-
- chunkWritten =
- yaffs_WriteChunkDataToObject(cache->object,
- cache->chunkId,
- cache->data,
- cache->nBytes,
- 1);
- cache->dirty = 0;
- cache->object = NULL;
- }
-
- } while (cache && chunkWritten > 0);
-
- if (cache) {
- /* Hoosterman, disk full while writing cache out. */
- T(YAFFS_TRACE_ERROR,
- (TSTR("yaffs tragedy: no space during cache write" TENDSTR)));