Mercurial > yaffs-ecoscentric-gpl
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) |
