+ if(!dev->srCache[i].dirty &&
+ ((dev->srCache[i].lastUse < usage && theOne >= 0)||
+ theOne < 0))
+ {
+ usage = dev->srCache[i].lastUse;
+ theOne = i;
+ }
+ }
+
+ //T(("Grabbing non-empty %d\n",theOne));
+
+ //if(theOne >= 0) printf("Grabbed non-empty cache %d\n",theOne);
+
+ 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.
+
+ theObj = dev->srCache[0].object;
+ usage = dev->srCache[0].lastUse;
+ cache = &dev->srCache[0];
+ pushout = 0;
+
+ for(i = 1; i < dev->nShortOpCaches; i++)
+ {
+ if( dev->srCache[i].object &&
+ dev->srCache[i].lastUse < usage)
+ {
+ usage = dev->srCache[i].lastUse;
+ theObj = dev->srCache[i].object;
+ cache = &dev->srCache[i];
+ pushout = i;
+ }
+ }
+
+ if(!cache || cache->dirty)
+ {
+
+ //printf("Dirty ");
+ yaffs_FlushFilesChunkCache(theObj);
+
+ // Try again
+ cache = yaffs_GrabChunkCacheWorker(dev);
+ }
+ else
+ {
+ //printf(" pushout %d\n",pushout);
+ }
+
+ }
+
+ 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)
+ {
+ // Now invalidate it.
+ for(i = 0; i < dev->nShortOpCaches; i++)
+ {
+ if(dev->srCache[i].object == in)
+ {
+ dev->srCache[i].object = NULL;
+ }
+ }
+ }
+}
+
+
+
+
+
+///////////////////////// 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, __u32 offset, int nBytes)
+{
+
+
+ int chunk;
+ int start;
+ int nToCopy;
+ int n = nBytes;
+ int nDone = 0;
+ yaffs_ChunkCache *cache;
+
+ yaffs_Device *dev;
+
+ dev = in->myDev;
+
+ while(n > 0)
+ {
+ chunk = offset / YAFFS_BYTES_PER_CHUNK + 1; // The first chunk is 1
+ start = offset % YAFFS_BYTES_PER_CHUNK;
+
+ // OK now check for the curveball where the start and end are in
+ // the same chunk.
+ if( (start + n) < YAFFS_BYTES_PER_CHUNK)
+ {
+ nToCopy = n;
+ }
+ else
+ {
+ nToCopy = YAFFS_BYTES_PER_CHUNK - start;
+ }
+
+ cache = yaffs_FindChunkCache(in,chunk);