-void yaffs_FlushEntireDeviceCache(yaffs_Device *dev)
-{
- yaffs_Object *obj;
- int nCaches = dev->nShortOpCaches;
- int i;
-
- /* Find a dirty object in the cache and flush it...
- * until there are no further dirty objects.
- */
- do {
- obj = NULL;
- for( i = 0; i < nCaches && !obj; i++) {
- if (dev->srCache[i].object &&
- dev->srCache[i].dirty)
- obj = dev->srCache[i].object;
-
- }
- if(obj)
- yaffs_FlushFilesChunkCache(obj);
-
- } while(obj);
-
-}
-
-
-/* Grab us a cache chunk for use.
- * First look for an empty one.
- * Then look for the least recently used non-dirty one.
- * Then look for the least recently used dirty one...., flush and look again.
- */
-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;
- }
-
-}
-
-static yaffs_ChunkCache *yaffs_GrabChunkCache(yaffs_Device * dev)
-{
- yaffs_ChunkCache *cache;
- yaffs_Object *theObj;
- int usage;
- int i;
- int pushout;
-
- if (dev->nShortOpCaches > 0) {
- /* Try find a non-dirty one... */
-
- cache = yaffs_GrabChunkCacheWorker(dev);
-
- if (!cache) {
- /* They were all dirty, find the last recently used object and flush
- * its cache, then find again.
- * NB what's here is not very accurate, we actually flush the object
- * the last recently used page.
- */
-
- /* With locking we can't assume we can use entry zero */
-
- theObj = NULL;
- usage = -1;
- cache = NULL;
- pushout = -1;
-
- for (i = 0; i < dev->nShortOpCaches; i++) {
- if (dev->srCache[i].object &&
- !dev->srCache[i].locked &&
- (dev->srCache[i].lastUse < usage || !cache))
- {
- usage = dev->srCache[i].lastUse;
- theObj = dev->srCache[i].object;
- cache = &dev->srCache[i];
- pushout = i;
- }
- }
-
- if (!cache || cache->dirty) {
- /* Flush and try again */
- yaffs_FlushFilesChunkCache(theObj);
- cache = yaffs_GrabChunkCacheWorker(dev);
- }
-
- }
- return cache;
- } else
- return NULL;
-
-}
-
-/* Find a cached chunk */
-static yaffs_ChunkCache *yaffs_FindChunkCache(const yaffs_Object * obj,
- int chunkId)
-{
- yaffs_Device *dev = obj->myDev;
- int i;
- if (dev->nShortOpCaches > 0) {
- for (i = 0; i < dev->nShortOpCaches; i++) {
- if (dev->srCache[i].object == obj &&
- dev->srCache[i].chunkId == chunkId) {
- dev->cacheHits++;
-
- return &dev->srCache[i];
- }
- }
- }
- return NULL;
-}
-
-/* Mark the chunk for the least recently used algorithym */
-static void yaffs_UseChunkCache(yaffs_Device * dev, yaffs_ChunkCache * cache,
- int isAWrite)
-{
-
- if (dev->nShortOpCaches > 0) {
- if (dev->srLastUse < 0 || dev->srLastUse > 100000000) {
- /* Reset the cache usages */
- int i;
- for (i = 1; i < dev->nShortOpCaches; i++) {
- dev->srCache[i].lastUse = 0;
- }
- dev->srLastUse = 0;
- }
-
- dev->srLastUse++;
-
- cache->lastUse = dev->srLastUse;
-
- if (isAWrite) {
- cache->dirty = 1;
- }
- }
-}
-
-/* Invalidate a single cache page.
- * Do this when a whole page gets written,
- * ie the short cache for this page is no longer valid.
- */
-static void yaffs_InvalidateChunkCache(yaffs_Object * object, int chunkId)
-{
- if (object->myDev->nShortOpCaches > 0) {
- yaffs_ChunkCache *cache = yaffs_FindChunkCache(object, chunkId);
-
- if (cache) {
- cache->object = NULL;
- }
- }
-}
-
-/* Invalidate all the cache pages associated with this object
- * Do this whenever ther file is deleted or resized.
- */
-static void yaffs_InvalidateWholeChunkCache(yaffs_Object * in)
-{
- int i;
- yaffs_Device *dev = in->myDev;
-
- if (dev->nShortOpCaches > 0) {
- /* Invalidate it. */
- for (i = 0; i < dev->nShortOpCaches; i++) {
- if (dev->srCache[i].object == in) {
- dev->srCache[i].object = NULL;
- }
- }
- }
-}
-
-/*--------------------- Checkpointing --------------------*/
-
-
-static int yaffs_WriteCheckpointValidityMarker(yaffs_Device *dev,int head)
-{
- yaffs_CheckpointValidity cp;
-
- memset(&cp,0,sizeof(cp));
-
- cp.structType = sizeof(cp);
- cp.magic = YAFFS_MAGIC;
- cp.version = YAFFS_CHECKPOINT_VERSION;
- cp.head = (head) ? 1 : 0;
-
- return (yaffs_CheckpointWrite(dev,&cp,sizeof(cp)) == sizeof(cp))?
- 1 : 0;
-}
-
-static int yaffs_ReadCheckpointValidityMarker(yaffs_Device *dev, int head)
-{
- yaffs_CheckpointValidity cp;
- int ok;
-
- ok = (yaffs_CheckpointRead(dev,&cp,sizeof(cp)) == sizeof(cp));
-
- if(ok)
- ok = (cp.structType == sizeof(cp)) &&
- (cp.magic == YAFFS_MAGIC) &&
- (cp.version == YAFFS_CHECKPOINT_VERSION) &&
- (cp.head == ((head) ? 1 : 0));
- return ok ? 1 : 0;
-}
-
-static void yaffs_DeviceToCheckpointDevice(yaffs_CheckpointDevice *cp,
- yaffs_Device *dev)
-{
- cp->nErasedBlocks = dev->nErasedBlocks;
- cp->allocationBlock = dev->allocationBlock;
- cp->allocationPage = dev->allocationPage;
- cp->nFreeChunks = dev->nFreeChunks;
-
- cp->nDeletedFiles = dev->nDeletedFiles;
- cp->nUnlinkedFiles = dev->nUnlinkedFiles;
- cp->nBackgroundDeletions = dev->nBackgroundDeletions;
- cp->sequenceNumber = dev->sequenceNumber;
- cp->oldestDirtySequence = dev->oldestDirtySequence;
-
-}
-
-static void yaffs_CheckpointDeviceToDevice(yaffs_Device *dev,
- yaffs_CheckpointDevice *cp)
-{
- dev->nErasedBlocks = cp->nErasedBlocks;
- dev->allocationBlock = cp->allocationBlock;
- dev->allocationPage = cp->allocationPage;
- dev->nFreeChunks = cp->nFreeChunks;
-
- dev->nDeletedFiles = cp->nDeletedFiles;
- dev->nUnlinkedFiles = cp->nUnlinkedFiles;
- dev->nBackgroundDeletions = cp->nBackgroundDeletions;
- dev->sequenceNumber = cp->sequenceNumber;
- dev->oldestDirtySequence = cp->oldestDirtySequence;
-}
-
-
-static int yaffs_WriteCheckpointDevice(yaffs_Device *dev)
-{
- yaffs_CheckpointDevice cp;
- __u32 nBytes;
- __u32 nBlocks = (dev->internalEndBlock - dev->internalStartBlock + 1);
-
- int ok;
-
- /* Write device runtime values*/
- yaffs_DeviceToCheckpointDevice(&cp,dev);
- cp.structType = sizeof(cp);
-
- ok = (yaffs_CheckpointWrite(dev,&cp,sizeof(cp)) == sizeof(cp));
-
- /* Write block info */
- if(ok) {
- nBytes = nBlocks * sizeof(yaffs_BlockInfo);
- ok = (yaffs_CheckpointWrite(dev,dev->blockInfo,nBytes) == nBytes);
- }
-
- /* Write chunk bits */
- if(ok) {
- nBytes = nBlocks * dev->chunkBitmapStride;
- ok = (yaffs_CheckpointWrite(dev,dev->chunkBits,nBytes) == nBytes);
- }
- return ok ? 1 : 0;
-
-}
-
-static int yaffs_ReadCheckpointDevice(yaffs_Device *dev)
-{
- yaffs_CheckpointDevice cp;
- __u32 nBytes;
- __u32 nBlocks = (dev->internalEndBlock - dev->internalStartBlock + 1);
-
- int ok;
-
- ok = (yaffs_CheckpointRead(dev,&cp,sizeof(cp)) == sizeof(cp));
- if(!ok)
- return 0;
-
- if(cp.structType != sizeof(cp))
- return 0;
-
-
- yaffs_CheckpointDeviceToDevice(dev,&cp);
-
- nBytes = nBlocks * sizeof(yaffs_BlockInfo);
-
- ok = (yaffs_CheckpointRead(dev,dev->blockInfo,nBytes) == nBytes);
-
- if(!ok)
- return 0;
- nBytes = nBlocks * dev->chunkBitmapStride;
-
- ok = (yaffs_CheckpointRead(dev,dev->chunkBits,nBytes) == nBytes);
-
- return ok ? 1 : 0;
-}
-
-static void yaffs_ObjectToCheckpointObject(yaffs_CheckpointObject *cp,
- yaffs_Object *obj)
-{
-
- cp->objectId = obj->objectId;
- cp->parentId = (obj->parent) ? obj->parent->objectId : 0;
- cp->hdrChunk = obj->hdrChunk;
- cp->variantType = obj->variantType;
- cp->deleted = obj->deleted;
- cp->softDeleted = obj->softDeleted;
- cp->unlinked = obj->unlinked;
- cp->fake = obj->fake;
- cp->renameAllowed = obj->renameAllowed;
- cp->unlinkAllowed = obj->unlinkAllowed;
- cp->serial = obj->serial;
- cp->nDataChunks = obj->nDataChunks;
-
- if(obj->variantType == YAFFS_OBJECT_TYPE_FILE)
- cp->fileSizeOrEquivalentObjectId = obj->variant.fileVariant.fileSize;
- else if(obj->variantType == YAFFS_OBJECT_TYPE_HARDLINK)
- cp->fileSizeOrEquivalentObjectId = obj->variant.hardLinkVariant.equivalentObjectId;
-}
-
-static void yaffs_CheckpointObjectToObject( yaffs_Object *obj,yaffs_CheckpointObject *cp)
-{
-
- yaffs_Object *parent;
-
- obj->objectId = cp->objectId;
-
- if(cp->parentId)
- parent = yaffs_FindOrCreateObjectByNumber(
- obj->myDev,
- cp->parentId,
- YAFFS_OBJECT_TYPE_DIRECTORY);
- else
- parent = NULL;
-
- if(parent)
- yaffs_AddObjectToDirectory(parent, obj);
-
- obj->hdrChunk = cp->hdrChunk;
- obj->variantType = cp->variantType;
- obj->deleted = cp->deleted;
- obj->softDeleted = cp->softDeleted;
- obj->unlinked = cp->unlinked;
- obj->fake = cp->fake;
- obj->renameAllowed = cp->renameAllowed;
- obj->unlinkAllowed = cp->unlinkAllowed;
- obj->serial = cp->serial;
- obj->nDataChunks = cp->nDataChunks;
-
- if(obj->variantType == YAFFS_OBJECT_TYPE_FILE)
- obj->variant.fileVariant.fileSize = cp->fileSizeOrEquivalentObjectId;
- else if(obj->variantType == YAFFS_OBJECT_TYPE_HARDLINK)
- obj->variant.hardLinkVariant.equivalentObjectId = cp->fileSizeOrEquivalentObjectId;
-
- if(obj->hdrChunk > 0)
- obj->lazyLoaded = 1;
-}
-
-
-
-static int yaffs_CheckpointTnodeWorker(yaffs_Object * in, yaffs_Tnode * tn,
- __u32 level, int chunkOffset)
-{
- int i;
- yaffs_Device *dev = in->myDev;
- int ok = 1;
- int tnodeSize = (dev->tnodeWidth * YAFFS_NTNODES_LEVEL0)/8;
-
- if(tnodeSize < sizeof(yaffs_Tnode))
- tnodeSize = sizeof(yaffs_Tnode);
-
-
- if (tn) {
- if (level > 0) {
-
- for (i = 0; i < YAFFS_NTNODES_INTERNAL && ok; i++){
- if (tn->internal[i]) {
- ok = yaffs_CheckpointTnodeWorker(in,
- tn->internal[i],
- level - 1,
- (chunkOffset<<YAFFS_TNODES_INTERNAL_BITS) + i);
- }
- }
- } else if (level == 0) {
- __u32 baseOffset = chunkOffset << YAFFS_TNODES_LEVEL0_BITS;
- /* printf("write tnode at %d\n",baseOffset); */
- ok = (yaffs_CheckpointWrite(dev,&baseOffset,sizeof(baseOffset)) == sizeof(baseOffset));
- if(ok)
- ok = (yaffs_CheckpointWrite(dev,tn,tnodeSize) == tnodeSize);
- }
- }
-
- return ok;
-
-}
-
-static int yaffs_WriteCheckpointTnodes(yaffs_Object *obj)
-{
- __u32 endMarker = ~0;
- int ok = 1;
-
- if(obj->variantType == YAFFS_OBJECT_TYPE_FILE){
- ok = yaffs_CheckpointTnodeWorker(obj,
- obj->variant.fileVariant.top,
- obj->variant.fileVariant.topLevel,
- 0);
- if(ok)
- ok = (yaffs_CheckpointWrite(obj->myDev,&endMarker,sizeof(endMarker)) ==
- sizeof(endMarker));
- }
-
- return ok ? 1 : 0;
-}
-
-static int yaffs_ReadCheckpointTnodes(yaffs_Object *obj)
-{
- __u32 baseChunk;
- int ok = 1;
- yaffs_Device *dev = obj->myDev;
- yaffs_FileStructure *fileStructPtr = &obj->variant.fileVariant;
- yaffs_Tnode *tn;
- int nread = 0;
- int tnodeSize = (dev->tnodeWidth * YAFFS_NTNODES_LEVEL0)/8;
-
- if(tnodeSize < sizeof(yaffs_Tnode))
- tnodeSize = sizeof(yaffs_Tnode);
-
- ok = (yaffs_CheckpointRead(dev,&baseChunk,sizeof(baseChunk)) == sizeof(baseChunk));
-
- while(ok && (~baseChunk)){
- nread++;
- /* Read level 0 tnode */
-
-
- /* printf("read tnode at %d\n",baseChunk); */
- tn = yaffs_GetTnodeRaw(dev);
- if(tn)
- ok = (yaffs_CheckpointRead(dev,tn,tnodeSize) == tnodeSize);
- else
- ok = 0;
-
- if(tn && ok){
- ok = yaffs_AddOrFindLevel0Tnode(dev,
- fileStructPtr,
- baseChunk,
- tn) ? 1 : 0;
-
- }
-
- if(ok)
- ok = (yaffs_CheckpointRead(dev,&baseChunk,sizeof(baseChunk)) == sizeof(baseChunk));
-
- }
-
- T(YAFFS_TRACE_CHECKPOINT,(
- TSTR("Checkpoint read tnodes %d records, last %d. ok %d" TENDSTR),
- nread,baseChunk,ok));
-
- return ok ? 1 : 0;
-}
-
-
-static int yaffs_WriteCheckpointObjects(yaffs_Device *dev)
-{
- yaffs_Object *obj;
- yaffs_CheckpointObject cp;
- int i;
- int ok = 1;
- struct ylist_head *lh;
-
-
- /* Iterate through the objects in each hash entry,
- * dumping them to the checkpointing stream.
- */
-
- for(i = 0; ok && i < YAFFS_NOBJECT_BUCKETS; i++){
- ylist_for_each(lh, &dev->objectBucket[i].list) {
- if (lh) {
- obj = ylist_entry(lh, yaffs_Object, hashLink);
- if (!obj->deferedFree) {
- yaffs_ObjectToCheckpointObject(&cp,obj);
- cp.structType = sizeof(cp);
-
- T(YAFFS_TRACE_CHECKPOINT,(
- TSTR("Checkpoint write object %d parent %d type %d chunk %d obj addr %x" TENDSTR),
- cp.objectId,cp.parentId,cp.variantType,cp.hdrChunk,(unsigned) obj));
-
- ok = (yaffs_CheckpointWrite(dev,&cp,sizeof(cp)) == sizeof(cp));
-
- if(ok && obj->variantType == YAFFS_OBJECT_TYPE_FILE){
- ok = yaffs_WriteCheckpointTnodes(obj);
- }
- }
- }
- }
- }
-
- /* Dump end of list */
- memset(&cp,0xFF,sizeof(yaffs_CheckpointObject));
- cp.structType = sizeof(cp);
-
- if(ok)
- ok = (yaffs_CheckpointWrite(dev,&cp,sizeof(cp)) == sizeof(cp));
-
- return ok ? 1 : 0;
-}
-
-static int yaffs_ReadCheckpointObjects(yaffs_Device *dev)
-{
- yaffs_Object *obj;
- yaffs_CheckpointObject cp;
- int ok = 1;
- int done = 0;
- yaffs_Object *hardList = NULL;
-
- while(ok && !done) {
- ok = (yaffs_CheckpointRead(dev,&cp,sizeof(cp)) == sizeof(cp));
- if(cp.structType != sizeof(cp)) {
- T(YAFFS_TRACE_CHECKPOINT,(TSTR("struct size %d instead of %d ok %d"TENDSTR),
- cp.structType,sizeof(cp),ok));
- ok = 0;
- }
-
- T(YAFFS_TRACE_CHECKPOINT,(TSTR("Checkpoint read object %d parent %d type %d chunk %d " TENDSTR),
- cp.objectId,cp.parentId,cp.variantType,cp.hdrChunk));
-
- if(ok && cp.objectId == ~0)
- done = 1;
- else if(ok){
- obj = yaffs_FindOrCreateObjectByNumber(dev,cp.objectId, cp.variantType);
- if(obj) {
- yaffs_CheckpointObjectToObject(obj,&cp);
- if(obj->variantType == YAFFS_OBJECT_TYPE_FILE) {
- ok = yaffs_ReadCheckpointTnodes(obj);
- } else if(obj->variantType == YAFFS_OBJECT_TYPE_HARDLINK) {
- obj->hardLinks.next =
- (struct ylist_head *)
- hardList;
- hardList = obj;
- }
-
- }
- }
- }
-
- if(ok)
- yaffs_HardlinkFixup(dev,hardList);
-
- return ok ? 1 : 0;
-}
-
-static int yaffs_WriteCheckpointSum(yaffs_Device *dev)
-{
- __u32 checkpointSum;
- int ok;
-
- yaffs_GetCheckpointSum(dev,&checkpointSum);
-
- ok = (yaffs_CheckpointWrite(dev,&checkpointSum,sizeof(checkpointSum)) == sizeof(checkpointSum));
-
- if(!ok)
- return 0;
-
- return 1;
-}
-
-static int yaffs_ReadCheckpointSum(yaffs_Device *dev)
-{
- __u32 checkpointSum0;
- __u32 checkpointSum1;
- int ok;
-
- yaffs_GetCheckpointSum(dev,&checkpointSum0);
-
- ok = (yaffs_CheckpointRead(dev,&checkpointSum1,sizeof(checkpointSum1)) == sizeof(checkpointSum1));
-
- if(!ok)
- return 0;
-
- if(checkpointSum0 != checkpointSum1)
- return 0;
-
- return 1;
-}
-
-
-static int yaffs_WriteCheckpointData(yaffs_Device *dev)
-{
-
- int ok = 1;
-
- if(dev->skipCheckpointWrite || !dev->isYaffs2){
- T(YAFFS_TRACE_CHECKPOINT,(TSTR("skipping checkpoint write" TENDSTR)));
- ok = 0;
- }
-
- if(ok)
- ok = yaffs_CheckpointOpen(dev,1);
-
- if(ok){
- T(YAFFS_TRACE_CHECKPOINT,(TSTR("write checkpoint validity" TENDSTR)));
- ok = yaffs_WriteCheckpointValidityMarker(dev,1);
- }
- if(ok){
- T(YAFFS_TRACE_CHECKPOINT,(TSTR("write checkpoint device" TENDSTR)));
- ok = yaffs_WriteCheckpointDevice(dev);
- }
- if(ok){
- T(YAFFS_TRACE_CHECKPOINT,(TSTR("write checkpoint objects" TENDSTR)));
- ok = yaffs_WriteCheckpointObjects(dev);
- }
- if(ok){
- T(YAFFS_TRACE_CHECKPOINT,(TSTR("write checkpoint validity" TENDSTR)));
- ok = yaffs_WriteCheckpointValidityMarker(dev,0);
- }
-
- if(ok){
- ok = yaffs_WriteCheckpointSum(dev);
- }
-
-
- if(!yaffs_CheckpointClose(dev))
- ok = 0;
-
- if(ok)
- dev->isCheckpointed = 1;
- else
- dev->isCheckpointed = 0;
-
- return dev->isCheckpointed;
-}
-
-static int yaffs_ReadCheckpointData(yaffs_Device *dev)
-{
- int ok = 1;
-
- if(dev->skipCheckpointRead || !dev->isYaffs2){
- T(YAFFS_TRACE_CHECKPOINT,(TSTR("skipping checkpoint read" TENDSTR)));
- ok = 0;
- }
-
- if(ok)
- ok = yaffs_CheckpointOpen(dev,0); /* open for read */
-
- if(ok){
- T(YAFFS_TRACE_CHECKPOINT,(TSTR("read checkpoint validity" TENDSTR)));
- ok = yaffs_ReadCheckpointValidityMarker(dev,1);
- }
- if(ok){
- T(YAFFS_TRACE_CHECKPOINT,(TSTR("read checkpoint device" TENDSTR)));
- ok = yaffs_ReadCheckpointDevice(dev);
- }
- if(ok){
- T(YAFFS_TRACE_CHECKPOINT,(TSTR("read checkpoint objects" TENDSTR)));
- ok = yaffs_ReadCheckpointObjects(dev);
- }
- if(ok){
- T(YAFFS_TRACE_CHECKPOINT,(TSTR("read checkpoint validity" TENDSTR)));
- ok = yaffs_ReadCheckpointValidityMarker(dev,0);
- }
-
- if(ok){
- ok = yaffs_ReadCheckpointSum(dev);
- T(YAFFS_TRACE_CHECKPOINT,(TSTR("read checkpoint checksum %d" TENDSTR),ok));
- }
-
- if(!yaffs_CheckpointClose(dev))
- ok = 0;
-
- if(ok)
- dev->isCheckpointed = 1;
- else
- dev->isCheckpointed = 0;
-
- return ok ? 1 : 0;
-
-}
-
-static void yaffs_InvalidateCheckpoint(yaffs_Device *dev)
-{
- if(dev->isCheckpointed ||
- dev->blocksInCheckpoint > 0){
- dev->isCheckpointed = 0;
- yaffs_CheckpointInvalidateStream(dev);
- if(dev->superBlock && dev->markSuperBlockDirty)
- dev->markSuperBlockDirty(dev->superBlock);
- }
-}
-
-
-int yaffs_CheckpointSave(yaffs_Device *dev)
-{
-
- T(YAFFS_TRACE_CHECKPOINT,(TSTR("save entry: isCheckpointed %d"TENDSTR),dev->isCheckpointed));
-
- yaffs_VerifyObjects(dev);
- yaffs_VerifyBlocks(dev);
- yaffs_VerifyFreeChunks(dev);
-
- if(!dev->isCheckpointed) {
- yaffs_InvalidateCheckpoint(dev);
- yaffs_WriteCheckpointData(dev);
- }
-
- T(YAFFS_TRACE_ALWAYS,(TSTR("save exit: isCheckpointed %d"TENDSTR),dev->isCheckpointed));
-
- return dev->isCheckpointed;
-}
-
-int yaffs_CheckpointRestore(yaffs_Device *dev)
-{
- int retval;
- T(YAFFS_TRACE_CHECKPOINT,(TSTR("restore entry: isCheckpointed %d"TENDSTR),dev->isCheckpointed));
-
- retval = yaffs_ReadCheckpointData(dev);
-
- if(dev->isCheckpointed){
- yaffs_VerifyObjects(dev);
- yaffs_VerifyBlocks(dev);
- yaffs_VerifyFreeChunks(dev);
- }
-
- T(YAFFS_TRACE_CHECKPOINT,(TSTR("restore exit: isCheckpointed %d"TENDSTR),dev->isCheckpointed));
-
- return retval;
-}
-
-/*--------------------- File read/write ------------------------
- * Read and write have very similar structures.
- * In general the read/write has three parts to it
- * An incomplete chunk to start with (if the read/write is not chunk-aligned)
- * Some complete chunks
- * An incomplete chunk to end off with
- *
- * Curve-balls: the first chunk might also be the last chunk.
- */
-
-int yaffs_ReadDataFromFile(yaffs_Object * in, __u8 * buffer, loff_t offset,
- int nBytes)
-{
-
- int chunk;
- __u32 start;
- int nToCopy;
- int n = nBytes;
- int nDone = 0;
- yaffs_ChunkCache *cache;
-
- yaffs_Device *dev;
-
- dev = in->myDev;
-
- while (n > 0) {
- //chunk = offset / dev->nDataBytesPerChunk + 1;
- //start = offset % dev->nDataBytesPerChunk;
- yaffs_AddrToChunk(dev,offset,&chunk,&start);
- chunk++;
-
- /* OK now check for the curveball where the start and end are in
- * the same chunk.
- */
- if ((start + n) < dev->nDataBytesPerChunk) {
- nToCopy = n;
- } else {
- nToCopy = dev->nDataBytesPerChunk - start;
- }
-
- cache = yaffs_FindChunkCache(in, chunk);
-
- /* If the chunk is already in the cache or it is less than a whole chunk
- * or we're using inband tags then use the cache (if there is caching)
- * else bypass the cache.
- */
- if (cache || nToCopy != dev->nDataBytesPerChunk || dev->inbandTags) {
- if (dev->nShortOpCaches > 0) {
-
- /* If we can't find the data in the cache, then load it up. */
-
- if (!cache) {
- cache = yaffs_GrabChunkCache(in->myDev);
- cache->object = in;
- cache->chunkId = chunk;
- cache->dirty = 0;
- cache->locked = 0;
- yaffs_ReadChunkDataFromObject(in, chunk,
- cache->
- data);
- cache->nBytes = 0;
- }
-
- yaffs_UseChunkCache(dev, cache, 0);
-
- cache->locked = 1;
-
-#ifdef CONFIG_YAFFS_WINCE
- yfsd_UnlockYAFFS(TRUE);
-#endif
- memcpy(buffer, &cache->data[start], nToCopy);
-
-#ifdef CONFIG_YAFFS_WINCE
- yfsd_LockYAFFS(TRUE);
-#endif
- cache->locked = 0;
- } else {
- /* Read into the local buffer then copy..*/
-
- __u8 *localBuffer =
- yaffs_GetTempBuffer(dev, __LINE__);
- yaffs_ReadChunkDataFromObject(in, chunk,
- localBuffer);
-#ifdef CONFIG_YAFFS_WINCE
- yfsd_UnlockYAFFS(TRUE);
-#endif
- memcpy(buffer, &localBuffer[start], nToCopy);
-
-#ifdef CONFIG_YAFFS_WINCE
- yfsd_LockYAFFS(TRUE);
-#endif
- yaffs_ReleaseTempBuffer(dev, localBuffer,
- __LINE__);
- }
-
- } else {
-#ifdef CONFIG_YAFFS_WINCE
- __u8 *localBuffer = yaffs_GetTempBuffer(dev, __LINE__);
-
- /* Under WinCE can't do direct transfer. Need to use a local buffer.
- * This is because we otherwise screw up WinCE's memory mapper
- */
- yaffs_ReadChunkDataFromObject(in, chunk, localBuffer);
-
-#ifdef CONFIG_YAFFS_WINCE
- yfsd_UnlockYAFFS(TRUE);
-#endif
- memcpy(buffer, localBuffer, dev->nDataBytesPerChunk);
-
-#ifdef CONFIG_YAFFS_WINCE
- yfsd_LockYAFFS(TRUE);
- yaffs_ReleaseTempBuffer(dev, localBuffer, __LINE__);
-#endif
-
-#else
- /* A full chunk. Read directly into the supplied buffer. */
- yaffs_ReadChunkDataFromObject(in, chunk, buffer);
-#endif
- }
-
- n -= nToCopy;
- offset += nToCopy;
- buffer += nToCopy;
- nDone += nToCopy;
-
- }
-
- return nDone;
-}
-
-int yaffs_WriteDataToFile(yaffs_Object * in, const __u8 * buffer, loff_t offset,
- int nBytes, int writeThrough)
-{
-
- int chunk;
- __u32 start;
- int nToCopy;
- int n = nBytes;
- int nDone = 0;
- int nToWriteBack;
- int startOfWrite = offset;
- int chunkWritten = 0;
- int nBytesRead;
-
- yaffs_Device *dev;
-
- dev = in->myDev;
-
- while (n > 0 && chunkWritten >= 0) {
- //chunk = offset / dev->nDataBytesPerChunk + 1;
- //start = offset % dev->nDataBytesPerChunk;
- yaffs_AddrToChunk(dev,offset,&chunk,&start);
- chunk++;
-
- /* OK now check for the curveball where the start and end are in
- * the same chunk.
- */
-
- if ((start + n) < dev->nDataBytesPerChunk) {
- nToCopy = n;
-
- /* Now folks, to calculate how many bytes to write back....
- * If we're overwriting and not writing to then end of file then
- * we need to write back as much as was there before.
- */
-
- nBytesRead =
- in->variant.fileVariant.fileSize -
- ((chunk - 1) * dev->nDataBytesPerChunk);
-
- if (nBytesRead > dev->nDataBytesPerChunk) {
- nBytesRead = dev->nDataBytesPerChunk;
- }
-
- nToWriteBack =
- (nBytesRead >
- (start + n)) ? nBytesRead : (start + n);
-
- } else {
- nToCopy = dev->nDataBytesPerChunk - start;
- nToWriteBack = dev->nDataBytesPerChunk;
- }
-
- if (nToCopy != dev->nDataBytesPerChunk || dev->inbandTags) {
- /* An incomplete start or end chunk (or maybe both start and end chunk),
- * or we're using inband tags, so we want to use the cache buffers.
- */
- if (dev->nShortOpCaches > 0) {
- yaffs_ChunkCache *cache;
- /* If we can't find the data in the cache, then load the cache */
- cache = yaffs_FindChunkCache(in, chunk);
-
- if (!cache
- && yaffs_CheckSpaceForAllocation(in->
- myDev)) {
- cache = yaffs_GrabChunkCache(in->myDev);
- cache->object = in;
- cache->chunkId = chunk;
- cache->dirty = 0;
- cache->locked = 0;
- yaffs_ReadChunkDataFromObject(in, chunk,
- cache->
- data);
- }
- else if(cache &&
- !cache->dirty &&
- !yaffs_CheckSpaceForAllocation(in->myDev)){
- /* Drop the cache if it was a read cache item and
- * no space check has been made for it.
- */
- cache = NULL;
- }
-
- if (cache) {
- yaffs_UseChunkCache(dev, cache, 1);
- cache->locked = 1;
-#ifdef CONFIG_YAFFS_WINCE
- yfsd_UnlockYAFFS(TRUE);
-#endif
-
- memcpy(&cache->data[start], buffer,
- nToCopy);
-
-#ifdef CONFIG_YAFFS_WINCE
- yfsd_LockYAFFS(TRUE);
-#endif
- cache->locked = 0;
- cache->nBytes = nToWriteBack;
-
- if (writeThrough) {
- chunkWritten =
- yaffs_WriteChunkDataToObject
- (cache->object,
- cache->chunkId,
- cache->data, cache->nBytes,
- 1);
- cache->dirty = 0;
- }
-
- } else {
- chunkWritten = -1; /* fail the write */
- }
- } else {
- /* An incomplete start or end chunk (or maybe both start and end chunk)
- * Read into the local buffer then copy, then copy over and write back.
- */
-
- __u8 *localBuffer =
- yaffs_GetTempBuffer(dev, __LINE__);
-
- yaffs_ReadChunkDataFromObject(in, chunk,
- localBuffer);
-
-#ifdef CONFIG_YAFFS_WINCE
- yfsd_UnlockYAFFS(TRUE);
-#endif
-
- memcpy(&localBuffer[start], buffer, nToCopy);
-
-#ifdef CONFIG_YAFFS_WINCE
- yfsd_LockYAFFS(TRUE);
-#endif
- chunkWritten =
- yaffs_WriteChunkDataToObject(in, chunk,
- localBuffer,
- nToWriteBack,
- 0);
-
- yaffs_ReleaseTempBuffer(dev, localBuffer,
- __LINE__);
-
- }
-
- } else {
- /* A full chunk. Write directly from the supplied buffer. */
-
-#ifdef CONFIG_YAFFS_WINCE
- /* Under WinCE can't do direct transfer. Need to use a local buffer.
- * This is because we otherwise screw up WinCE's memory mapper
- */
- __u8 *localBuffer = yaffs_GetTempBuffer(dev, __LINE__);
-#ifdef CONFIG_YAFFS_WINCE
- yfsd_UnlockYAFFS(TRUE);
-#endif
- memcpy(localBuffer, buffer, dev->nDataBytesPerChunk);
-#ifdef CONFIG_YAFFS_WINCE
- yfsd_LockYAFFS(TRUE);
-#endif
- chunkWritten =
- yaffs_WriteChunkDataToObject(in, chunk, localBuffer,
- dev->nDataBytesPerChunk,
- 0);
- yaffs_ReleaseTempBuffer(dev, localBuffer, __LINE__);
-#else
-
- chunkWritten =
- yaffs_WriteChunkDataToObject(in, chunk, buffer,
- dev->nDataBytesPerChunk,
- 0);
-#endif
- /* Since we've overwritten the cached data, we better invalidate it. */
- yaffs_InvalidateChunkCache(in, chunk);
- }
-
- if (chunkWritten >= 0) {
- n -= nToCopy;
- offset += nToCopy;
- buffer += nToCopy;
- nDone += nToCopy;
- }
-
- }
-
- /* Update file object */
-
- if ((startOfWrite + nDone) > in->variant.fileVariant.fileSize) {
- in->variant.fileVariant.fileSize = (startOfWrite + nDone);
- }
-
- in->dirty = 1;
-
- return nDone;
-}