comparison yaffs_guts.c @ 382:f85ba1a6e018

Reduce shrink header writing
author charles <charles>
date Fri, 12 Mar 2010 01:22:48 +0000
parents fe1a3db89fde
children b9e2ee9e8f28
comparison
equal deleted inserted replaced
381:e4f6a9b6e81e 382:f85ba1a6e018
10 * it under the terms of the GNU General Public License version 2 as 10 * it under the terms of the GNU General Public License version 2 as
11 * published by the Free Software Foundation. 11 * published by the Free Software Foundation.
12 */ 12 */
13 13
14 const char *yaffs_guts_c_version = 14 const char *yaffs_guts_c_version =
15 "$Id: yaffs_guts.c,v 1.117 2010-03-11 02:44:43 charles Exp $"; 15 "$Id: yaffs_guts.c,v 1.118 2010-03-12 01:22:48 charles Exp $";
16 16
17 #include "yportenv.h" 17 #include "yportenv.h"
18 #include "yaffs_trace.h" 18 #include "yaffs_trace.h"
19 19
20 #include "yaffsinterface.h" 20 #include "yaffsinterface.h"
33 #include "yaffs_nand.h" 33 #include "yaffs_nand.h"
34 #include "yaffs_packedtags2.h" 34 #include "yaffs_packedtags2.h"
35 35
36 36
37 #define YAFFS_PASSIVE_GC_CHUNKS 2 37 #define YAFFS_PASSIVE_GC_CHUNKS 2
38 #define YAFFS_SMALL_HOLE_THRESHOLD 3
38 39
39 #include "yaffs_ecc.h" 40 #include "yaffs_ecc.h"
40 41
41 42
42 /* Robustification (if it ever comes about...) */ 43 /* Robustification (if it ever comes about...) */
112 unsigned pos); 113 unsigned pos);
113 static yaffs_Tnode *yaffs_FindLevel0Tnode(yaffs_Device *dev, 114 static yaffs_Tnode *yaffs_FindLevel0Tnode(yaffs_Device *dev,
114 yaffs_FileStructure *fStruct, 115 yaffs_FileStructure *fStruct,
115 __u32 chunkId); 116 __u32 chunkId);
116 117
118 static int yaffs_HandleHole(yaffs_Object *obj, loff_t newSize);
117 static void yaffs_SkipRestOfBlock(yaffs_Device *dev); 119 static void yaffs_SkipRestOfBlock(yaffs_Device *dev);
118 static int yaffs_VerifyChunkWritten(yaffs_Device *dev, 120 static int yaffs_VerifyChunkWritten(yaffs_Device *dev,
119 int chunkInNAND, 121 int chunkInNAND,
120 const __u8 *data, 122 const __u8 *data,
121 yaffs_ExtendedTags *tags); 123 yaffs_ExtendedTags *tags);
3071 3073
3072 /* 3074 /*
3073 * Check if there's space to allocate... 3075 * Check if there's space to allocate...
3074 * Thinks.... do we need top make this ths same as yaffs_GetFreeChunks()? 3076 * Thinks.... do we need top make this ths same as yaffs_GetFreeChunks()?
3075 */ 3077 */
3076 static int yaffs_CheckSpaceForAllocation(yaffs_Device *dev) 3078 static int yaffs_CheckSpaceForAllocation(yaffs_Device *dev, int nChunks)
3077 { 3079 {
3078 int reservedChunks; 3080 int reservedChunks;
3079 int reservedBlocks = dev->param.nReservedBlocks; 3081 int reservedBlocks = dev->param.nReservedBlocks;
3080 int checkpointBlocks; 3082 int checkpointBlocks;
3081 3083
3088 checkpointBlocks = 0; 3090 checkpointBlocks = 0;
3089 } 3091 }
3090 3092
3091 reservedChunks = ((reservedBlocks + checkpointBlocks) * dev->param.nChunksPerBlock); 3093 reservedChunks = ((reservedBlocks + checkpointBlocks) * dev->param.nChunksPerBlock);
3092 3094
3093 return (dev->nFreeChunks > reservedChunks); 3095 return (dev->nFreeChunks > (reservedChunks + nChunks));
3094 } 3096 }
3095 3097
3096 static int yaffs_AllocateChunk(yaffs_Device *dev, int useReserve, 3098 static int yaffs_AllocateChunk(yaffs_Device *dev, int useReserve,
3097 yaffs_BlockInfo **blockUsedPtr) 3099 yaffs_BlockInfo **blockUsedPtr)
3098 { 3100 {
3103 /* Get next block to allocate off */ 3105 /* Get next block to allocate off */
3104 dev->allocationBlock = yaffs_FindBlockForAllocation(dev); 3106 dev->allocationBlock = yaffs_FindBlockForAllocation(dev);
3105 dev->allocationPage = 0; 3107 dev->allocationPage = 0;
3106 } 3108 }
3107 3109
3108 if (!useReserve && !yaffs_CheckSpaceForAllocation(dev)) { 3110 if (!useReserve && !yaffs_CheckSpaceForAllocation(dev, 1)) {
3109 /* Not enough space to allocate unless we're allowed to use the reserve. */ 3111 /* Not enough space to allocate unless we're allowed to use the reserve. */
3110 return -1; 3112 return -1;
3111 } 3113 }
3112 3114
3113 if (dev->nErasedBlocks < dev->param.nReservedBlocks 3115 if (dev->nErasedBlocks < dev->param.nReservedBlocks
5007 } 5009 }
5008 5010
5009 return nDone; 5011 return nDone;
5010 } 5012 }
5011 5013
5012 int yaffs_WriteDataToFile(yaffs_Object *in, const __u8 *buffer, loff_t offset, 5014 int yaffs_DoWriteDataToFile(yaffs_Object *in, const __u8 *buffer, loff_t offset,
5013 int nBytes, int writeThrough) 5015 int nBytes, int writeThrough)
5014 { 5016 {
5015 5017
5016 int chunk; 5018 int chunk;
5017 __u32 start; 5019 __u32 start;
5084 yaffs_ChunkCache *cache; 5086 yaffs_ChunkCache *cache;
5085 /* If we can't find the data in the cache, then load the cache */ 5087 /* If we can't find the data in the cache, then load the cache */
5086 cache = yaffs_FindChunkCache(in, chunk); 5088 cache = yaffs_FindChunkCache(in, chunk);
5087 5089
5088 if (!cache 5090 if (!cache
5089 && yaffs_CheckSpaceForAllocation(in-> 5091 && yaffs_CheckSpaceForAllocation(dev, 1)) {
5090 myDev)) { 5092 cache = yaffs_GrabChunkCache(dev);
5091 cache = yaffs_GrabChunkCache(in->myDev);
5092 cache->object = in; 5093 cache->object = in;
5093 cache->chunkId = chunk; 5094 cache->chunkId = chunk;
5094 cache->dirty = 0; 5095 cache->dirty = 0;
5095 cache->locked = 0; 5096 cache->locked = 0;
5096 yaffs_ReadChunkDataFromObject(in, chunk, 5097 yaffs_ReadChunkDataFromObject(in, chunk,
5097 cache-> 5098 cache->data);
5098 data);
5099 } else if (cache && 5099 } else if (cache &&
5100 !cache->dirty && 5100 !cache->dirty &&
5101 !yaffs_CheckSpaceForAllocation(in->myDev)) { 5101 !yaffs_CheckSpaceForAllocation(dev, 1)) {
5102 /* Drop the cache if it was a read cache item and 5102 /* Drop the cache if it was a read cache item and
5103 * no space check has been made for it. 5103 * no space check has been made for it.
5104 */ 5104 */
5105 cache = NULL; 5105 cache = NULL;
5106 } 5106 }
5186 5186
5187 in->dirty = 1; 5187 in->dirty = 1;
5188 5188
5189 return nDone; 5189 return nDone;
5190 } 5190 }
5191
5192 int yaffs_WriteDataToFile(yaffs_Object *in, const __u8 *buffer, loff_t offset,
5193 int nBytes, int writeThrough)
5194 {
5195 yaffs_HandleHole(in,offset);
5196 return yaffs_DoWriteDataToFile(in,buffer,offset,nBytes,writeThrough);
5197 }
5198
5191 5199
5192 5200
5193 /* ---------------------- File resizing stuff ------------------ */ 5201 /* ---------------------- File resizing stuff ------------------ */
5194 5202
5195 static void yaffs_PruneResizedChunks(yaffs_Object *in, int newSize) 5203 static void yaffs_PruneResizedChunks(yaffs_Object *in, int newSize)
5231 } 5239 }
5232 } 5240 }
5233 5241
5234 } 5242 }
5235 5243
5244
5245 static void yaffs_ResizeDown( yaffs_Object *obj, loff_t newSize)
5246 {
5247 int newFullChunks;
5248 __u32 newSizeOfPartialChunk;
5249 yaffs_Device *dev = obj->myDev;
5250
5251 yaffs_AddrToChunk(dev, newSize, &newFullChunks, &newSizeOfPartialChunk);
5252
5253 yaffs_PruneResizedChunks(obj, newSize);
5254
5255 if (newSizeOfPartialChunk != 0) {
5256 int lastChunk = 1 + newFullChunks;
5257 __u8 *localBuffer = yaffs_GetTempBuffer(dev, __LINE__);
5258
5259 /* Got to read and rewrite the last chunk with its new size and zero pad */
5260 yaffs_ReadChunkDataFromObject(obj, lastChunk, localBuffer);
5261 memset(localBuffer + newSizeOfPartialChunk, 0,
5262 dev->nDataBytesPerChunk - newSizeOfPartialChunk);
5263
5264 yaffs_WriteChunkDataToObject(obj, lastChunk, localBuffer,
5265 newSizeOfPartialChunk, 1);
5266
5267 yaffs_ReleaseTempBuffer(dev, localBuffer, __LINE__);
5268 }
5269
5270 obj->variant.fileVariant.fileSize = newSize;
5271
5272 yaffs_PruneFileStructure(dev, &obj->variant.fileVariant);
5273 }
5274
5275
5276 static int yaffs_HandleHole(yaffs_Object *obj, loff_t newSize)
5277 {
5278 /* if newsSize > oldFileSize.
5279 * We're going to be writing a hole.
5280 * If the hole is small then write zeros otherwise write a start of hole marker.
5281 */
5282
5283
5284 loff_t oldFileSize;
5285 int increase;
5286 int smallHole ;
5287 int result = YAFFS_OK;
5288 yaffs_Device *dev = NULL;
5289
5290 __u8 *localBuffer = NULL;
5291
5292 int smallIncreaseOk = 0;
5293
5294 if(!obj)
5295 return YAFFS_FAIL;
5296
5297 if(obj->variantType != YAFFS_OBJECT_TYPE_FILE)
5298 return YAFFS_FAIL;
5299
5300 dev = obj->myDev;
5301
5302 /* Bail out if not yaffs2 mode */
5303 if(!dev->param.isYaffs2)
5304 return YAFFS_OK;
5305
5306 oldFileSize = obj->variant.fileVariant.fileSize;
5307
5308 if (newSize <= oldFileSize)
5309 return YAFFS_OK;
5310
5311 increase = newSize - oldFileSize;
5312
5313 if(increase < YAFFS_SMALL_HOLE_THRESHOLD * dev->nDataBytesPerChunk &&
5314 yaffs_CheckSpaceForAllocation(dev, YAFFS_SMALL_HOLE_THRESHOLD + 1))
5315 smallHole = 1;
5316 else
5317 smallHole = 0;
5318
5319 if(smallHole)
5320 localBuffer= yaffs_GetTempBuffer(dev, __LINE__);
5321
5322 if(localBuffer){
5323 /* fill hole with zero bytes */
5324 int pos = oldFileSize;
5325 int thisWrite;
5326 int written;
5327 memset(localBuffer,0,dev->nDataBytesPerChunk);
5328 smallIncreaseOk = 1;
5329
5330 while(increase > 0 && smallIncreaseOk){
5331 thisWrite = increase;
5332 if(thisWrite > dev->nDataBytesPerChunk)
5333 thisWrite = dev->nDataBytesPerChunk;
5334 written = yaffs_DoWriteDataToFile(obj,localBuffer,pos,thisWrite,0);
5335 if(written == thisWrite){
5336 pos += thisWrite;
5337 increase -= thisWrite;
5338 } else
5339 smallIncreaseOk = 0;
5340 }
5341
5342 yaffs_ReleaseTempBuffer(dev,localBuffer,__LINE__);
5343
5344 /* If we were out of space then reverse any chunks we've added */
5345 if(!smallIncreaseOk)
5346 yaffs_ResizeDown(obj, oldFileSize);
5347 }
5348
5349 if (!smallIncreaseOk &&
5350 obj->parent &&
5351 obj->parent->objectId != YAFFS_OBJECTID_UNLINKED &&
5352 obj->parent->objectId != YAFFS_OBJECTID_DELETED){
5353 /* Write a hole start header with the old file size */
5354 yaffs_UpdateObjectHeader(obj, NULL, 0,1,0);
5355 }
5356
5357 return result;
5358
5359 }
5360
5236 int yaffs_ResizeFile(yaffs_Object *in, loff_t newSize) 5361 int yaffs_ResizeFile(yaffs_Object *in, loff_t newSize)
5237 { 5362 {
5238 5363 yaffs_Device *dev = in->myDev;
5239 int oldFileSize = in->variant.fileVariant.fileSize; 5364 int oldFileSize = in->variant.fileVariant.fileSize;
5240 __u32 newSizeOfPartialChunk;
5241 int newFullChunks;
5242
5243 yaffs_Device *dev = in->myDev;
5244
5245 yaffs_AddrToChunk(dev, newSize, &newFullChunks, &newSizeOfPartialChunk);
5246 5365
5247 yaffs_FlushFilesChunkCache(in); 5366 yaffs_FlushFilesChunkCache(in);
5248 yaffs_InvalidateWholeChunkCache(in); 5367 yaffs_InvalidateWholeChunkCache(in);
5249 5368
5250 yaffs_CheckGarbageCollection(dev); 5369 yaffs_CheckGarbageCollection(dev);
5252 if (in->variantType != YAFFS_OBJECT_TYPE_FILE) 5371 if (in->variantType != YAFFS_OBJECT_TYPE_FILE)
5253 return YAFFS_FAIL; 5372 return YAFFS_FAIL;
5254 5373
5255 if (newSize == oldFileSize) 5374 if (newSize == oldFileSize)
5256 return YAFFS_OK; 5375 return YAFFS_OK;
5257 5376
5258 if (newSize < oldFileSize) { 5377 if(newSize > oldFileSize){
5259 5378 yaffs_HandleHole(in,newSize);
5260 yaffs_PruneResizedChunks(in, newSize);
5261
5262 if (newSizeOfPartialChunk != 0) {
5263 int lastChunk = 1 + newFullChunks;
5264
5265 __u8 *localBuffer = yaffs_GetTempBuffer(dev, __LINE__);
5266
5267 /* Got to read and rewrite the last chunk with its new size and zero pad */
5268 yaffs_ReadChunkDataFromObject(in, lastChunk,
5269 localBuffer);
5270
5271 memset(localBuffer + newSizeOfPartialChunk, 0,
5272 dev->nDataBytesPerChunk - newSizeOfPartialChunk);
5273
5274 yaffs_WriteChunkDataToObject(in, lastChunk, localBuffer,
5275 newSizeOfPartialChunk, 1);
5276
5277 yaffs_ReleaseTempBuffer(dev, localBuffer, __LINE__);
5278 }
5279
5280 in->variant.fileVariant.fileSize = newSize; 5379 in->variant.fileVariant.fileSize = newSize;
5281
5282 yaffs_PruneFileStructure(dev, &in->variant.fileVariant);
5283 } else { 5380 } else {
5284 /* newsSize > oldFileSize */ 5381 /* newSize < oldFileSize */
5285 in->variant.fileVariant.fileSize = newSize; 5382 yaffs_ResizeDown(in, newSize);
5286 } 5383 }
5287 5384
5288 /* Write a new object header to reflect the resize. 5385 /* Write a new object header to reflect the resize.
5289 * show we've shrunk the file, if need be 5386 * show we've shrunk the file, if need be
5290 * Do this only if the file is not in the deleted directories 5387 * Do this only if the file is not in the deleted directories
5291 * and is not shadowed. 5388 * and is not shadowed.
5292 */ 5389 */
5293 if (in->parent && 5390 if (in->parent &&
5294 !in->isShadowed && 5391 !in->isShadowed &&
5295 in->parent->objectId != YAFFS_OBJECTID_UNLINKED && 5392 in->parent->objectId != YAFFS_OBJECTID_UNLINKED &&
5296 in->parent->objectId != YAFFS_OBJECTID_DELETED) 5393 in->parent->objectId != YAFFS_OBJECTID_DELETED)
5297 yaffs_UpdateObjectHeader(in, NULL, 0, 5394 yaffs_UpdateObjectHeader(in, NULL, 0,0,0);
5298 (newSize < oldFileSize) ? 1 : 0, 0); 5395
5299 5396
5300 return YAFFS_OK; 5397 return YAFFS_OK;
5301 } 5398 }
5302 5399
5303 loff_t yaffs_GetFileSize(yaffs_Object *obj) 5400 loff_t yaffs_GetFileSize(yaffs_Object *obj)