*/
const char *yaffs_guts_c_version =
- "$Id: yaffs_guts.c,v 1.117 2010-03-11 02:44:43 charles Exp $";
+ "$Id: yaffs_guts.c,v 1.118 2010-03-12 01:22:48 charles Exp $";
#include "yportenv.h"
#include "yaffs_trace.h"
#define YAFFS_PASSIVE_GC_CHUNKS 2
+#define YAFFS_SMALL_HOLE_THRESHOLD 3
#include "yaffs_ecc.h"
yaffs_FileStructure *fStruct,
__u32 chunkId);
+static int yaffs_HandleHole(yaffs_Object *obj, loff_t newSize);
static void yaffs_SkipRestOfBlock(yaffs_Device *dev);
static int yaffs_VerifyChunkWritten(yaffs_Device *dev,
int chunkInNAND,
* Check if there's space to allocate...
* Thinks.... do we need top make this ths same as yaffs_GetFreeChunks()?
*/
-static int yaffs_CheckSpaceForAllocation(yaffs_Device *dev)
+static int yaffs_CheckSpaceForAllocation(yaffs_Device *dev, int nChunks)
{
int reservedChunks;
int reservedBlocks = dev->param.nReservedBlocks;
reservedChunks = ((reservedBlocks + checkpointBlocks) * dev->param.nChunksPerBlock);
- return (dev->nFreeChunks > reservedChunks);
+ return (dev->nFreeChunks > (reservedChunks + nChunks));
}
static int yaffs_AllocateChunk(yaffs_Device *dev, int useReserve,
dev->allocationPage = 0;
}
- if (!useReserve && !yaffs_CheckSpaceForAllocation(dev)) {
+ if (!useReserve && !yaffs_CheckSpaceForAllocation(dev, 1)) {
/* Not enough space to allocate unless we're allowed to use the reserve. */
return -1;
}
return nDone;
}
-int yaffs_WriteDataToFile(yaffs_Object *in, const __u8 *buffer, loff_t offset,
+int yaffs_DoWriteDataToFile(yaffs_Object *in, const __u8 *buffer, loff_t offset,
int nBytes, int writeThrough)
{
cache = yaffs_FindChunkCache(in, chunk);
if (!cache
- && yaffs_CheckSpaceForAllocation(in->
- myDev)) {
- cache = yaffs_GrabChunkCache(in->myDev);
+ && yaffs_CheckSpaceForAllocation(dev, 1)) {
+ cache = yaffs_GrabChunkCache(dev);
cache->object = in;
cache->chunkId = chunk;
cache->dirty = 0;
cache->locked = 0;
yaffs_ReadChunkDataFromObject(in, chunk,
- cache->
- data);
+ cache->data);
} else if (cache &&
!cache->dirty &&
- !yaffs_CheckSpaceForAllocation(in->myDev)) {
+ !yaffs_CheckSpaceForAllocation(dev, 1)) {
/* Drop the cache if it was a read cache item and
* no space check has been made for it.
*/
return nDone;
}
+int yaffs_WriteDataToFile(yaffs_Object *in, const __u8 *buffer, loff_t offset,
+ int nBytes, int writeThrough)
+{
+ yaffs_HandleHole(in,offset);
+ return yaffs_DoWriteDataToFile(in,buffer,offset,nBytes,writeThrough);
+}
+
+
/* ---------------------- File resizing stuff ------------------ */
}
-int yaffs_ResizeFile(yaffs_Object *in, loff_t newSize)
-{
- int oldFileSize = in->variant.fileVariant.fileSize;
- __u32 newSizeOfPartialChunk;
+static void yaffs_ResizeDown( yaffs_Object *obj, loff_t newSize)
+{
int newFullChunks;
-
- yaffs_Device *dev = in->myDev;
+ __u32 newSizeOfPartialChunk;
+ yaffs_Device *dev = obj->myDev;
yaffs_AddrToChunk(dev, newSize, &newFullChunks, &newSizeOfPartialChunk);
- yaffs_FlushFilesChunkCache(in);
- yaffs_InvalidateWholeChunkCache(in);
+ yaffs_PruneResizedChunks(obj, newSize);
- yaffs_CheckGarbageCollection(dev);
+ if (newSizeOfPartialChunk != 0) {
+ int lastChunk = 1 + newFullChunks;
+ __u8 *localBuffer = yaffs_GetTempBuffer(dev, __LINE__);
- if (in->variantType != YAFFS_OBJECT_TYPE_FILE)
+ /* Got to read and rewrite the last chunk with its new size and zero pad */
+ yaffs_ReadChunkDataFromObject(obj, lastChunk, localBuffer);
+ memset(localBuffer + newSizeOfPartialChunk, 0,
+ dev->nDataBytesPerChunk - newSizeOfPartialChunk);
+
+ yaffs_WriteChunkDataToObject(obj, lastChunk, localBuffer,
+ newSizeOfPartialChunk, 1);
+
+ yaffs_ReleaseTempBuffer(dev, localBuffer, __LINE__);
+ }
+
+ obj->variant.fileVariant.fileSize = newSize;
+
+ yaffs_PruneFileStructure(dev, &obj->variant.fileVariant);
+}
+
+
+static int yaffs_HandleHole(yaffs_Object *obj, loff_t newSize)
+{
+ /* if newsSize > oldFileSize.
+ * We're going to be writing a hole.
+ * If the hole is small then write zeros otherwise write a start of hole marker.
+ */
+
+
+ loff_t oldFileSize;
+ int increase;
+ int smallHole ;
+ int result = YAFFS_OK;
+ yaffs_Device *dev = NULL;
+
+ __u8 *localBuffer = NULL;
+
+ int smallIncreaseOk = 0;
+
+ if(!obj)
return YAFFS_FAIL;
- if (newSize == oldFileSize)
+ if(obj->variantType != YAFFS_OBJECT_TYPE_FILE)
+ return YAFFS_FAIL;
+
+ dev = obj->myDev;
+
+ /* Bail out if not yaffs2 mode */
+ if(!dev->param.isYaffs2)
return YAFFS_OK;
- if (newSize < oldFileSize) {
+ oldFileSize = obj->variant.fileVariant.fileSize;
- yaffs_PruneResizedChunks(in, newSize);
+ if (newSize <= oldFileSize)
+ return YAFFS_OK;
- if (newSizeOfPartialChunk != 0) {
- int lastChunk = 1 + newFullChunks;
+ increase = newSize - oldFileSize;
- __u8 *localBuffer = yaffs_GetTempBuffer(dev, __LINE__);
+ if(increase < YAFFS_SMALL_HOLE_THRESHOLD * dev->nDataBytesPerChunk &&
+ yaffs_CheckSpaceForAllocation(dev, YAFFS_SMALL_HOLE_THRESHOLD + 1))
+ smallHole = 1;
+ else
+ smallHole = 0;
- /* Got to read and rewrite the last chunk with its new size and zero pad */
- yaffs_ReadChunkDataFromObject(in, lastChunk,
- localBuffer);
+ if(smallHole)
+ localBuffer= yaffs_GetTempBuffer(dev, __LINE__);
+
+ if(localBuffer){
+ /* fill hole with zero bytes */
+ int pos = oldFileSize;
+ int thisWrite;
+ int written;
+ memset(localBuffer,0,dev->nDataBytesPerChunk);
+ smallIncreaseOk = 1;
+
+ while(increase > 0 && smallIncreaseOk){
+ thisWrite = increase;
+ if(thisWrite > dev->nDataBytesPerChunk)
+ thisWrite = dev->nDataBytesPerChunk;
+ written = yaffs_DoWriteDataToFile(obj,localBuffer,pos,thisWrite,0);
+ if(written == thisWrite){
+ pos += thisWrite;
+ increase -= thisWrite;
+ } else
+ smallIncreaseOk = 0;
+ }
- memset(localBuffer + newSizeOfPartialChunk, 0,
- dev->nDataBytesPerChunk - newSizeOfPartialChunk);
+ yaffs_ReleaseTempBuffer(dev,localBuffer,__LINE__);
- yaffs_WriteChunkDataToObject(in, lastChunk, localBuffer,
- newSizeOfPartialChunk, 1);
+ /* If we were out of space then reverse any chunks we've added */
+ if(!smallIncreaseOk)
+ yaffs_ResizeDown(obj, oldFileSize);
+ }
+
+ if (!smallIncreaseOk &&
+ obj->parent &&
+ obj->parent->objectId != YAFFS_OBJECTID_UNLINKED &&
+ obj->parent->objectId != YAFFS_OBJECTID_DELETED){
+ /* Write a hole start header with the old file size */
+ yaffs_UpdateObjectHeader(obj, NULL, 0,1,0);
+ }
- yaffs_ReleaseTempBuffer(dev, localBuffer, __LINE__);
- }
+ return result;
- in->variant.fileVariant.fileSize = newSize;
+}
- yaffs_PruneFileStructure(dev, &in->variant.fileVariant);
- } else {
- /* newsSize > oldFileSize */
+int yaffs_ResizeFile(yaffs_Object *in, loff_t newSize)
+{
+ yaffs_Device *dev = in->myDev;
+ int oldFileSize = in->variant.fileVariant.fileSize;
+
+ yaffs_FlushFilesChunkCache(in);
+ yaffs_InvalidateWholeChunkCache(in);
+
+ yaffs_CheckGarbageCollection(dev);
+
+ if (in->variantType != YAFFS_OBJECT_TYPE_FILE)
+ return YAFFS_FAIL;
+
+ if (newSize == oldFileSize)
+ return YAFFS_OK;
+
+ if(newSize > oldFileSize){
+ yaffs_HandleHole(in,newSize);
in->variant.fileVariant.fileSize = newSize;
- }
+ } else {
+ /* newSize < oldFileSize */
+ yaffs_ResizeDown(in, newSize);
+ }
/* Write a new object header to reflect the resize.
* show we've shrunk the file, if need be
!in->isShadowed &&
in->parent->objectId != YAFFS_OBJECTID_UNLINKED &&
in->parent->objectId != YAFFS_OBJECTID_DELETED)
- yaffs_UpdateObjectHeader(in, NULL, 0,
- (newSize < oldFileSize) ? 1 : 0, 0);
+ yaffs_UpdateObjectHeader(in, NULL, 0,0,0);
+
return YAFFS_OK;
}