1*0e8cc8bdSWilliam Juul /* 2*0e8cc8bdSWilliam Juul * YAFFS: Yet Another Flash File System. A NAND-flash specific file system. 3*0e8cc8bdSWilliam Juul * 4*0e8cc8bdSWilliam Juul * Copyright (C) 2002-2007 Aleph One Ltd. 5*0e8cc8bdSWilliam Juul * for Toby Churchill Ltd and Brightstar Engineering 6*0e8cc8bdSWilliam Juul * 7*0e8cc8bdSWilliam Juul * Created by Charles Manning <charles@aleph1.co.uk> 8*0e8cc8bdSWilliam Juul * 9*0e8cc8bdSWilliam Juul * This program is free software; you can redistribute it and/or modify 10*0e8cc8bdSWilliam Juul * it under the terms of the GNU General Public License version 2 as 11*0e8cc8bdSWilliam Juul * published by the Free Software Foundation. 12*0e8cc8bdSWilliam Juul */ 13*0e8cc8bdSWilliam Juul 14*0e8cc8bdSWilliam Juul const char *yaffs_guts_c_version = 15*0e8cc8bdSWilliam Juul "$Id: yaffs_guts.c,v 1.52 2007/10/16 00:45:05 charles Exp $"; 16*0e8cc8bdSWilliam Juul 17*0e8cc8bdSWilliam Juul #include "yportenv.h" 18*0e8cc8bdSWilliam Juul 19*0e8cc8bdSWilliam Juul #include "yaffsinterface.h" 20*0e8cc8bdSWilliam Juul #include "yaffs_guts.h" 21*0e8cc8bdSWilliam Juul #include "yaffs_tagsvalidity.h" 22*0e8cc8bdSWilliam Juul 23*0e8cc8bdSWilliam Juul #include "yaffs_tagscompat.h" 24*0e8cc8bdSWilliam Juul #ifndef CONFIG_YAFFS_USE_OWN_SORT 25*0e8cc8bdSWilliam Juul #include "yaffs_qsort.h" 26*0e8cc8bdSWilliam Juul #endif 27*0e8cc8bdSWilliam Juul #include "yaffs_nand.h" 28*0e8cc8bdSWilliam Juul 29*0e8cc8bdSWilliam Juul #include "yaffs_checkptrw.h" 30*0e8cc8bdSWilliam Juul 31*0e8cc8bdSWilliam Juul #include "yaffs_nand.h" 32*0e8cc8bdSWilliam Juul #include "yaffs_packedtags2.h" 33*0e8cc8bdSWilliam Juul 34*0e8cc8bdSWilliam Juul 35*0e8cc8bdSWilliam Juul #ifdef CONFIG_YAFFS_WINCE 36*0e8cc8bdSWilliam Juul void yfsd_LockYAFFS(BOOL fsLockOnly); 37*0e8cc8bdSWilliam Juul void yfsd_UnlockYAFFS(BOOL fsLockOnly); 38*0e8cc8bdSWilliam Juul #endif 39*0e8cc8bdSWilliam Juul 40*0e8cc8bdSWilliam Juul #define YAFFS_PASSIVE_GC_CHUNKS 2 41*0e8cc8bdSWilliam Juul 42*0e8cc8bdSWilliam Juul #include "yaffs_ecc.h" 43*0e8cc8bdSWilliam Juul 44*0e8cc8bdSWilliam Juul 45*0e8cc8bdSWilliam Juul /* Robustification (if it ever comes about...) */ 46*0e8cc8bdSWilliam Juul static void yaffs_RetireBlock(yaffs_Device * dev, int blockInNAND); 47*0e8cc8bdSWilliam Juul static void yaffs_HandleWriteChunkError(yaffs_Device * dev, int chunkInNAND, int erasedOk); 48*0e8cc8bdSWilliam Juul static void yaffs_HandleWriteChunkOk(yaffs_Device * dev, int chunkInNAND, 49*0e8cc8bdSWilliam Juul const __u8 * data, 50*0e8cc8bdSWilliam Juul const yaffs_ExtendedTags * tags); 51*0e8cc8bdSWilliam Juul static void yaffs_HandleUpdateChunk(yaffs_Device * dev, int chunkInNAND, 52*0e8cc8bdSWilliam Juul const yaffs_ExtendedTags * tags); 53*0e8cc8bdSWilliam Juul 54*0e8cc8bdSWilliam Juul /* Other local prototypes */ 55*0e8cc8bdSWilliam Juul static int yaffs_UnlinkObject( yaffs_Object *obj); 56*0e8cc8bdSWilliam Juul static int yaffs_ObjectHasCachedWriteData(yaffs_Object *obj); 57*0e8cc8bdSWilliam Juul 58*0e8cc8bdSWilliam Juul static void yaffs_HardlinkFixup(yaffs_Device *dev, yaffs_Object *hardList); 59*0e8cc8bdSWilliam Juul 60*0e8cc8bdSWilliam Juul static int yaffs_WriteNewChunkWithTagsToNAND(yaffs_Device * dev, 61*0e8cc8bdSWilliam Juul const __u8 * buffer, 62*0e8cc8bdSWilliam Juul yaffs_ExtendedTags * tags, 63*0e8cc8bdSWilliam Juul int useReserve); 64*0e8cc8bdSWilliam Juul static int yaffs_PutChunkIntoFile(yaffs_Object * in, int chunkInInode, 65*0e8cc8bdSWilliam Juul int chunkInNAND, int inScan); 66*0e8cc8bdSWilliam Juul 67*0e8cc8bdSWilliam Juul static yaffs_Object *yaffs_CreateNewObject(yaffs_Device * dev, int number, 68*0e8cc8bdSWilliam Juul yaffs_ObjectType type); 69*0e8cc8bdSWilliam Juul static void yaffs_AddObjectToDirectory(yaffs_Object * directory, 70*0e8cc8bdSWilliam Juul yaffs_Object * obj); 71*0e8cc8bdSWilliam Juul static int yaffs_UpdateObjectHeader(yaffs_Object * in, const YCHAR * name, 72*0e8cc8bdSWilliam Juul int force, int isShrink, int shadows); 73*0e8cc8bdSWilliam Juul static void yaffs_RemoveObjectFromDirectory(yaffs_Object * obj); 74*0e8cc8bdSWilliam Juul static int yaffs_CheckStructures(void); 75*0e8cc8bdSWilliam Juul static int yaffs_DeleteWorker(yaffs_Object * in, yaffs_Tnode * tn, __u32 level, 76*0e8cc8bdSWilliam Juul int chunkOffset, int *limit); 77*0e8cc8bdSWilliam Juul static int yaffs_DoGenericObjectDeletion(yaffs_Object * in); 78*0e8cc8bdSWilliam Juul 79*0e8cc8bdSWilliam Juul static yaffs_BlockInfo *yaffs_GetBlockInfo(yaffs_Device * dev, int blockNo); 80*0e8cc8bdSWilliam Juul 81*0e8cc8bdSWilliam Juul static __u8 *yaffs_GetTempBuffer(yaffs_Device * dev, int lineNo); 82*0e8cc8bdSWilliam Juul static void yaffs_ReleaseTempBuffer(yaffs_Device * dev, __u8 * buffer, 83*0e8cc8bdSWilliam Juul int lineNo); 84*0e8cc8bdSWilliam Juul 85*0e8cc8bdSWilliam Juul static int yaffs_CheckChunkErased(struct yaffs_DeviceStruct *dev, 86*0e8cc8bdSWilliam Juul int chunkInNAND); 87*0e8cc8bdSWilliam Juul 88*0e8cc8bdSWilliam Juul static int yaffs_UnlinkWorker(yaffs_Object * obj); 89*0e8cc8bdSWilliam Juul static void yaffs_DestroyObject(yaffs_Object * obj); 90*0e8cc8bdSWilliam Juul 91*0e8cc8bdSWilliam Juul static int yaffs_TagsMatch(const yaffs_ExtendedTags * tags, int objectId, 92*0e8cc8bdSWilliam Juul int chunkInObject); 93*0e8cc8bdSWilliam Juul 94*0e8cc8bdSWilliam Juul loff_t yaffs_GetFileSize(yaffs_Object * obj); 95*0e8cc8bdSWilliam Juul 96*0e8cc8bdSWilliam Juul static int yaffs_AllocateChunk(yaffs_Device * dev, int useReserve, yaffs_BlockInfo **blockUsedPtr); 97*0e8cc8bdSWilliam Juul 98*0e8cc8bdSWilliam Juul static void yaffs_VerifyFreeChunks(yaffs_Device * dev); 99*0e8cc8bdSWilliam Juul 100*0e8cc8bdSWilliam Juul static void yaffs_CheckObjectDetailsLoaded(yaffs_Object *in); 101*0e8cc8bdSWilliam Juul 102*0e8cc8bdSWilliam Juul #ifdef YAFFS_PARANOID 103*0e8cc8bdSWilliam Juul static int yaffs_CheckFileSanity(yaffs_Object * in); 104*0e8cc8bdSWilliam Juul #else 105*0e8cc8bdSWilliam Juul #define yaffs_CheckFileSanity(in) 106*0e8cc8bdSWilliam Juul #endif 107*0e8cc8bdSWilliam Juul 108*0e8cc8bdSWilliam Juul static void yaffs_InvalidateWholeChunkCache(yaffs_Object * in); 109*0e8cc8bdSWilliam Juul static void yaffs_InvalidateChunkCache(yaffs_Object * object, int chunkId); 110*0e8cc8bdSWilliam Juul 111*0e8cc8bdSWilliam Juul static void yaffs_InvalidateCheckpoint(yaffs_Device *dev); 112*0e8cc8bdSWilliam Juul 113*0e8cc8bdSWilliam Juul static int yaffs_FindChunkInFile(yaffs_Object * in, int chunkInInode, 114*0e8cc8bdSWilliam Juul yaffs_ExtendedTags * tags); 115*0e8cc8bdSWilliam Juul 116*0e8cc8bdSWilliam Juul static __u32 yaffs_GetChunkGroupBase(yaffs_Device *dev, yaffs_Tnode *tn, unsigned pos); 117*0e8cc8bdSWilliam Juul static yaffs_Tnode *yaffs_FindLevel0Tnode(yaffs_Device * dev, 118*0e8cc8bdSWilliam Juul yaffs_FileStructure * fStruct, 119*0e8cc8bdSWilliam Juul __u32 chunkId); 120*0e8cc8bdSWilliam Juul 121*0e8cc8bdSWilliam Juul 122*0e8cc8bdSWilliam Juul /* Function to calculate chunk and offset */ 123*0e8cc8bdSWilliam Juul 124*0e8cc8bdSWilliam Juul static void yaffs_AddrToChunk(yaffs_Device *dev, loff_t addr, __u32 *chunk, __u32 *offset) 125*0e8cc8bdSWilliam Juul { 126*0e8cc8bdSWilliam Juul if(dev->chunkShift){ 127*0e8cc8bdSWilliam Juul /* Easy-peasy power of 2 case */ 128*0e8cc8bdSWilliam Juul *chunk = (__u32)(addr >> dev->chunkShift); 129*0e8cc8bdSWilliam Juul *offset = (__u32)(addr & dev->chunkMask); 130*0e8cc8bdSWilliam Juul } 131*0e8cc8bdSWilliam Juul else if(dev->crumbsPerChunk) 132*0e8cc8bdSWilliam Juul { 133*0e8cc8bdSWilliam Juul /* Case where we're using "crumbs" */ 134*0e8cc8bdSWilliam Juul *offset = (__u32)(addr & dev->crumbMask); 135*0e8cc8bdSWilliam Juul addr >>= dev->crumbShift; 136*0e8cc8bdSWilliam Juul *chunk = ((__u32)addr)/dev->crumbsPerChunk; 137*0e8cc8bdSWilliam Juul *offset += ((addr - (*chunk * dev->crumbsPerChunk)) << dev->crumbShift); 138*0e8cc8bdSWilliam Juul } 139*0e8cc8bdSWilliam Juul else 140*0e8cc8bdSWilliam Juul YBUG(); 141*0e8cc8bdSWilliam Juul } 142*0e8cc8bdSWilliam Juul 143*0e8cc8bdSWilliam Juul /* Function to return the number of shifts for a power of 2 greater than or equal 144*0e8cc8bdSWilliam Juul * to the given number 145*0e8cc8bdSWilliam Juul * Note we don't try to cater for all possible numbers and this does not have to 146*0e8cc8bdSWilliam Juul * be hellishly efficient. 147*0e8cc8bdSWilliam Juul */ 148*0e8cc8bdSWilliam Juul 149*0e8cc8bdSWilliam Juul static __u32 ShiftsGE(__u32 x) 150*0e8cc8bdSWilliam Juul { 151*0e8cc8bdSWilliam Juul int extraBits; 152*0e8cc8bdSWilliam Juul int nShifts; 153*0e8cc8bdSWilliam Juul 154*0e8cc8bdSWilliam Juul nShifts = extraBits = 0; 155*0e8cc8bdSWilliam Juul 156*0e8cc8bdSWilliam Juul while(x>1){ 157*0e8cc8bdSWilliam Juul if(x & 1) extraBits++; 158*0e8cc8bdSWilliam Juul x>>=1; 159*0e8cc8bdSWilliam Juul nShifts++; 160*0e8cc8bdSWilliam Juul } 161*0e8cc8bdSWilliam Juul 162*0e8cc8bdSWilliam Juul if(extraBits) 163*0e8cc8bdSWilliam Juul nShifts++; 164*0e8cc8bdSWilliam Juul 165*0e8cc8bdSWilliam Juul return nShifts; 166*0e8cc8bdSWilliam Juul } 167*0e8cc8bdSWilliam Juul 168*0e8cc8bdSWilliam Juul /* Function to return the number of shifts to get a 1 in bit 0 169*0e8cc8bdSWilliam Juul */ 170*0e8cc8bdSWilliam Juul 171*0e8cc8bdSWilliam Juul static __u32 ShiftDiv(__u32 x) 172*0e8cc8bdSWilliam Juul { 173*0e8cc8bdSWilliam Juul int nShifts; 174*0e8cc8bdSWilliam Juul 175*0e8cc8bdSWilliam Juul nShifts = 0; 176*0e8cc8bdSWilliam Juul 177*0e8cc8bdSWilliam Juul if(!x) return 0; 178*0e8cc8bdSWilliam Juul 179*0e8cc8bdSWilliam Juul while( !(x&1)){ 180*0e8cc8bdSWilliam Juul x>>=1; 181*0e8cc8bdSWilliam Juul nShifts++; 182*0e8cc8bdSWilliam Juul } 183*0e8cc8bdSWilliam Juul 184*0e8cc8bdSWilliam Juul return nShifts; 185*0e8cc8bdSWilliam Juul } 186*0e8cc8bdSWilliam Juul 187*0e8cc8bdSWilliam Juul 188*0e8cc8bdSWilliam Juul 189*0e8cc8bdSWilliam Juul /* 190*0e8cc8bdSWilliam Juul * Temporary buffer manipulations. 191*0e8cc8bdSWilliam Juul */ 192*0e8cc8bdSWilliam Juul 193*0e8cc8bdSWilliam Juul static int yaffs_InitialiseTempBuffers(yaffs_Device *dev) 194*0e8cc8bdSWilliam Juul { 195*0e8cc8bdSWilliam Juul int i; 196*0e8cc8bdSWilliam Juul __u8 *buf = (__u8 *)1; 197*0e8cc8bdSWilliam Juul 198*0e8cc8bdSWilliam Juul memset(dev->tempBuffer,0,sizeof(dev->tempBuffer)); 199*0e8cc8bdSWilliam Juul 200*0e8cc8bdSWilliam Juul for (i = 0; buf && i < YAFFS_N_TEMP_BUFFERS; i++) { 201*0e8cc8bdSWilliam Juul dev->tempBuffer[i].line = 0; /* not in use */ 202*0e8cc8bdSWilliam Juul dev->tempBuffer[i].buffer = buf = 203*0e8cc8bdSWilliam Juul YMALLOC_DMA(dev->nDataBytesPerChunk); 204*0e8cc8bdSWilliam Juul } 205*0e8cc8bdSWilliam Juul 206*0e8cc8bdSWilliam Juul return buf ? YAFFS_OK : YAFFS_FAIL; 207*0e8cc8bdSWilliam Juul 208*0e8cc8bdSWilliam Juul } 209*0e8cc8bdSWilliam Juul 210*0e8cc8bdSWilliam Juul static __u8 *yaffs_GetTempBuffer(yaffs_Device * dev, int lineNo) 211*0e8cc8bdSWilliam Juul { 212*0e8cc8bdSWilliam Juul int i, j; 213*0e8cc8bdSWilliam Juul for (i = 0; i < YAFFS_N_TEMP_BUFFERS; i++) { 214*0e8cc8bdSWilliam Juul if (dev->tempBuffer[i].line == 0) { 215*0e8cc8bdSWilliam Juul dev->tempBuffer[i].line = lineNo; 216*0e8cc8bdSWilliam Juul if ((i + 1) > dev->maxTemp) { 217*0e8cc8bdSWilliam Juul dev->maxTemp = i + 1; 218*0e8cc8bdSWilliam Juul for (j = 0; j <= i; j++) 219*0e8cc8bdSWilliam Juul dev->tempBuffer[j].maxLine = 220*0e8cc8bdSWilliam Juul dev->tempBuffer[j].line; 221*0e8cc8bdSWilliam Juul } 222*0e8cc8bdSWilliam Juul 223*0e8cc8bdSWilliam Juul return dev->tempBuffer[i].buffer; 224*0e8cc8bdSWilliam Juul } 225*0e8cc8bdSWilliam Juul } 226*0e8cc8bdSWilliam Juul 227*0e8cc8bdSWilliam Juul T(YAFFS_TRACE_BUFFERS, 228*0e8cc8bdSWilliam Juul (TSTR("Out of temp buffers at line %d, other held by lines:"), 229*0e8cc8bdSWilliam Juul lineNo)); 230*0e8cc8bdSWilliam Juul for (i = 0; i < YAFFS_N_TEMP_BUFFERS; i++) { 231*0e8cc8bdSWilliam Juul T(YAFFS_TRACE_BUFFERS, (TSTR(" %d "), dev->tempBuffer[i].line)); 232*0e8cc8bdSWilliam Juul } 233*0e8cc8bdSWilliam Juul T(YAFFS_TRACE_BUFFERS, (TSTR(" " TENDSTR))); 234*0e8cc8bdSWilliam Juul 235*0e8cc8bdSWilliam Juul /* 236*0e8cc8bdSWilliam Juul * If we got here then we have to allocate an unmanaged one 237*0e8cc8bdSWilliam Juul * This is not good. 238*0e8cc8bdSWilliam Juul */ 239*0e8cc8bdSWilliam Juul 240*0e8cc8bdSWilliam Juul dev->unmanagedTempAllocations++; 241*0e8cc8bdSWilliam Juul return YMALLOC(dev->nDataBytesPerChunk); 242*0e8cc8bdSWilliam Juul 243*0e8cc8bdSWilliam Juul } 244*0e8cc8bdSWilliam Juul 245*0e8cc8bdSWilliam Juul static void yaffs_ReleaseTempBuffer(yaffs_Device * dev, __u8 * buffer, 246*0e8cc8bdSWilliam Juul int lineNo) 247*0e8cc8bdSWilliam Juul { 248*0e8cc8bdSWilliam Juul int i; 249*0e8cc8bdSWilliam Juul for (i = 0; i < YAFFS_N_TEMP_BUFFERS; i++) { 250*0e8cc8bdSWilliam Juul if (dev->tempBuffer[i].buffer == buffer) { 251*0e8cc8bdSWilliam Juul dev->tempBuffer[i].line = 0; 252*0e8cc8bdSWilliam Juul return; 253*0e8cc8bdSWilliam Juul } 254*0e8cc8bdSWilliam Juul } 255*0e8cc8bdSWilliam Juul 256*0e8cc8bdSWilliam Juul if (buffer) { 257*0e8cc8bdSWilliam Juul /* assume it is an unmanaged one. */ 258*0e8cc8bdSWilliam Juul T(YAFFS_TRACE_BUFFERS, 259*0e8cc8bdSWilliam Juul (TSTR("Releasing unmanaged temp buffer in line %d" TENDSTR), 260*0e8cc8bdSWilliam Juul lineNo)); 261*0e8cc8bdSWilliam Juul YFREE(buffer); 262*0e8cc8bdSWilliam Juul dev->unmanagedTempDeallocations++; 263*0e8cc8bdSWilliam Juul } 264*0e8cc8bdSWilliam Juul 265*0e8cc8bdSWilliam Juul } 266*0e8cc8bdSWilliam Juul 267*0e8cc8bdSWilliam Juul /* 268*0e8cc8bdSWilliam Juul * Determine if we have a managed buffer. 269*0e8cc8bdSWilliam Juul */ 270*0e8cc8bdSWilliam Juul int yaffs_IsManagedTempBuffer(yaffs_Device * dev, const __u8 * buffer) 271*0e8cc8bdSWilliam Juul { 272*0e8cc8bdSWilliam Juul int i; 273*0e8cc8bdSWilliam Juul for (i = 0; i < YAFFS_N_TEMP_BUFFERS; i++) { 274*0e8cc8bdSWilliam Juul if (dev->tempBuffer[i].buffer == buffer) 275*0e8cc8bdSWilliam Juul return 1; 276*0e8cc8bdSWilliam Juul 277*0e8cc8bdSWilliam Juul } 278*0e8cc8bdSWilliam Juul 279*0e8cc8bdSWilliam Juul for (i = 0; i < dev->nShortOpCaches; i++) { 280*0e8cc8bdSWilliam Juul if( dev->srCache[i].data == buffer ) 281*0e8cc8bdSWilliam Juul return 1; 282*0e8cc8bdSWilliam Juul 283*0e8cc8bdSWilliam Juul } 284*0e8cc8bdSWilliam Juul 285*0e8cc8bdSWilliam Juul if (buffer == dev->checkpointBuffer) 286*0e8cc8bdSWilliam Juul return 1; 287*0e8cc8bdSWilliam Juul 288*0e8cc8bdSWilliam Juul T(YAFFS_TRACE_ALWAYS, 289*0e8cc8bdSWilliam Juul (TSTR("yaffs: unmaged buffer detected.\n" TENDSTR))); 290*0e8cc8bdSWilliam Juul return 0; 291*0e8cc8bdSWilliam Juul } 292*0e8cc8bdSWilliam Juul 293*0e8cc8bdSWilliam Juul 294*0e8cc8bdSWilliam Juul 295*0e8cc8bdSWilliam Juul /* 296*0e8cc8bdSWilliam Juul * Chunk bitmap manipulations 297*0e8cc8bdSWilliam Juul */ 298*0e8cc8bdSWilliam Juul 299*0e8cc8bdSWilliam Juul static Y_INLINE __u8 *yaffs_BlockBits(yaffs_Device * dev, int blk) 300*0e8cc8bdSWilliam Juul { 301*0e8cc8bdSWilliam Juul if (blk < dev->internalStartBlock || blk > dev->internalEndBlock) { 302*0e8cc8bdSWilliam Juul T(YAFFS_TRACE_ERROR, 303*0e8cc8bdSWilliam Juul (TSTR("**>> yaffs: BlockBits block %d is not valid" TENDSTR), 304*0e8cc8bdSWilliam Juul blk)); 305*0e8cc8bdSWilliam Juul YBUG(); 306*0e8cc8bdSWilliam Juul } 307*0e8cc8bdSWilliam Juul return dev->chunkBits + 308*0e8cc8bdSWilliam Juul (dev->chunkBitmapStride * (blk - dev->internalStartBlock)); 309*0e8cc8bdSWilliam Juul } 310*0e8cc8bdSWilliam Juul 311*0e8cc8bdSWilliam Juul static Y_INLINE void yaffs_VerifyChunkBitId(yaffs_Device *dev, int blk, int chunk) 312*0e8cc8bdSWilliam Juul { 313*0e8cc8bdSWilliam Juul if(blk < dev->internalStartBlock || blk > dev->internalEndBlock || 314*0e8cc8bdSWilliam Juul chunk < 0 || chunk >= dev->nChunksPerBlock) { 315*0e8cc8bdSWilliam Juul T(YAFFS_TRACE_ERROR, 316*0e8cc8bdSWilliam Juul (TSTR("**>> yaffs: Chunk Id (%d:%d) invalid"TENDSTR),blk,chunk)); 317*0e8cc8bdSWilliam Juul YBUG(); 318*0e8cc8bdSWilliam Juul } 319*0e8cc8bdSWilliam Juul } 320*0e8cc8bdSWilliam Juul 321*0e8cc8bdSWilliam Juul static Y_INLINE void yaffs_ClearChunkBits(yaffs_Device * dev, int blk) 322*0e8cc8bdSWilliam Juul { 323*0e8cc8bdSWilliam Juul __u8 *blkBits = yaffs_BlockBits(dev, blk); 324*0e8cc8bdSWilliam Juul 325*0e8cc8bdSWilliam Juul memset(blkBits, 0, dev->chunkBitmapStride); 326*0e8cc8bdSWilliam Juul } 327*0e8cc8bdSWilliam Juul 328*0e8cc8bdSWilliam Juul static Y_INLINE void yaffs_ClearChunkBit(yaffs_Device * dev, int blk, int chunk) 329*0e8cc8bdSWilliam Juul { 330*0e8cc8bdSWilliam Juul __u8 *blkBits = yaffs_BlockBits(dev, blk); 331*0e8cc8bdSWilliam Juul 332*0e8cc8bdSWilliam Juul yaffs_VerifyChunkBitId(dev,blk,chunk); 333*0e8cc8bdSWilliam Juul 334*0e8cc8bdSWilliam Juul blkBits[chunk / 8] &= ~(1 << (chunk & 7)); 335*0e8cc8bdSWilliam Juul } 336*0e8cc8bdSWilliam Juul 337*0e8cc8bdSWilliam Juul static Y_INLINE void yaffs_SetChunkBit(yaffs_Device * dev, int blk, int chunk) 338*0e8cc8bdSWilliam Juul { 339*0e8cc8bdSWilliam Juul __u8 *blkBits = yaffs_BlockBits(dev, blk); 340*0e8cc8bdSWilliam Juul 341*0e8cc8bdSWilliam Juul yaffs_VerifyChunkBitId(dev,blk,chunk); 342*0e8cc8bdSWilliam Juul 343*0e8cc8bdSWilliam Juul blkBits[chunk / 8] |= (1 << (chunk & 7)); 344*0e8cc8bdSWilliam Juul } 345*0e8cc8bdSWilliam Juul 346*0e8cc8bdSWilliam Juul static Y_INLINE int yaffs_CheckChunkBit(yaffs_Device * dev, int blk, int chunk) 347*0e8cc8bdSWilliam Juul { 348*0e8cc8bdSWilliam Juul __u8 *blkBits = yaffs_BlockBits(dev, blk); 349*0e8cc8bdSWilliam Juul yaffs_VerifyChunkBitId(dev,blk,chunk); 350*0e8cc8bdSWilliam Juul 351*0e8cc8bdSWilliam Juul return (blkBits[chunk / 8] & (1 << (chunk & 7))) ? 1 : 0; 352*0e8cc8bdSWilliam Juul } 353*0e8cc8bdSWilliam Juul 354*0e8cc8bdSWilliam Juul static Y_INLINE int yaffs_StillSomeChunkBits(yaffs_Device * dev, int blk) 355*0e8cc8bdSWilliam Juul { 356*0e8cc8bdSWilliam Juul __u8 *blkBits = yaffs_BlockBits(dev, blk); 357*0e8cc8bdSWilliam Juul int i; 358*0e8cc8bdSWilliam Juul for (i = 0; i < dev->chunkBitmapStride; i++) { 359*0e8cc8bdSWilliam Juul if (*blkBits) 360*0e8cc8bdSWilliam Juul return 1; 361*0e8cc8bdSWilliam Juul blkBits++; 362*0e8cc8bdSWilliam Juul } 363*0e8cc8bdSWilliam Juul return 0; 364*0e8cc8bdSWilliam Juul } 365*0e8cc8bdSWilliam Juul 366*0e8cc8bdSWilliam Juul static int yaffs_CountChunkBits(yaffs_Device * dev, int blk) 367*0e8cc8bdSWilliam Juul { 368*0e8cc8bdSWilliam Juul __u8 *blkBits = yaffs_BlockBits(dev, blk); 369*0e8cc8bdSWilliam Juul int i; 370*0e8cc8bdSWilliam Juul int n = 0; 371*0e8cc8bdSWilliam Juul for (i = 0; i < dev->chunkBitmapStride; i++) { 372*0e8cc8bdSWilliam Juul __u8 x = *blkBits; 373*0e8cc8bdSWilliam Juul while(x){ 374*0e8cc8bdSWilliam Juul if(x & 1) 375*0e8cc8bdSWilliam Juul n++; 376*0e8cc8bdSWilliam Juul x >>=1; 377*0e8cc8bdSWilliam Juul } 378*0e8cc8bdSWilliam Juul 379*0e8cc8bdSWilliam Juul blkBits++; 380*0e8cc8bdSWilliam Juul } 381*0e8cc8bdSWilliam Juul return n; 382*0e8cc8bdSWilliam Juul } 383*0e8cc8bdSWilliam Juul 384*0e8cc8bdSWilliam Juul /* 385*0e8cc8bdSWilliam Juul * Verification code 386*0e8cc8bdSWilliam Juul */ 387*0e8cc8bdSWilliam Juul 388*0e8cc8bdSWilliam Juul static int yaffs_SkipVerification(yaffs_Device *dev) 389*0e8cc8bdSWilliam Juul { 390*0e8cc8bdSWilliam Juul return !(yaffs_traceMask & (YAFFS_TRACE_VERIFY | YAFFS_TRACE_VERIFY_FULL)); 391*0e8cc8bdSWilliam Juul } 392*0e8cc8bdSWilliam Juul 393*0e8cc8bdSWilliam Juul static int yaffs_SkipFullVerification(yaffs_Device *dev) 394*0e8cc8bdSWilliam Juul { 395*0e8cc8bdSWilliam Juul return !(yaffs_traceMask & (YAFFS_TRACE_VERIFY_FULL)); 396*0e8cc8bdSWilliam Juul } 397*0e8cc8bdSWilliam Juul 398*0e8cc8bdSWilliam Juul static int yaffs_SkipNANDVerification(yaffs_Device *dev) 399*0e8cc8bdSWilliam Juul { 400*0e8cc8bdSWilliam Juul return !(yaffs_traceMask & (YAFFS_TRACE_VERIFY_NAND)); 401*0e8cc8bdSWilliam Juul } 402*0e8cc8bdSWilliam Juul 403*0e8cc8bdSWilliam Juul static const char * blockStateName[] = { 404*0e8cc8bdSWilliam Juul "Unknown", 405*0e8cc8bdSWilliam Juul "Needs scanning", 406*0e8cc8bdSWilliam Juul "Scanning", 407*0e8cc8bdSWilliam Juul "Empty", 408*0e8cc8bdSWilliam Juul "Allocating", 409*0e8cc8bdSWilliam Juul "Full", 410*0e8cc8bdSWilliam Juul "Dirty", 411*0e8cc8bdSWilliam Juul "Checkpoint", 412*0e8cc8bdSWilliam Juul "Collecting", 413*0e8cc8bdSWilliam Juul "Dead" 414*0e8cc8bdSWilliam Juul }; 415*0e8cc8bdSWilliam Juul 416*0e8cc8bdSWilliam Juul static void yaffs_VerifyBlock(yaffs_Device *dev,yaffs_BlockInfo *bi,int n) 417*0e8cc8bdSWilliam Juul { 418*0e8cc8bdSWilliam Juul int actuallyUsed; 419*0e8cc8bdSWilliam Juul int inUse; 420*0e8cc8bdSWilliam Juul 421*0e8cc8bdSWilliam Juul if(yaffs_SkipVerification(dev)) 422*0e8cc8bdSWilliam Juul return; 423*0e8cc8bdSWilliam Juul 424*0e8cc8bdSWilliam Juul /* Report illegal runtime states */ 425*0e8cc8bdSWilliam Juul if(bi->blockState <0 || bi->blockState >= YAFFS_NUMBER_OF_BLOCK_STATES) 426*0e8cc8bdSWilliam Juul T(YAFFS_TRACE_VERIFY,(TSTR("Block %d has undefined state %d"TENDSTR),n,bi->blockState)); 427*0e8cc8bdSWilliam Juul 428*0e8cc8bdSWilliam Juul switch(bi->blockState){ 429*0e8cc8bdSWilliam Juul case YAFFS_BLOCK_STATE_UNKNOWN: 430*0e8cc8bdSWilliam Juul case YAFFS_BLOCK_STATE_SCANNING: 431*0e8cc8bdSWilliam Juul case YAFFS_BLOCK_STATE_NEEDS_SCANNING: 432*0e8cc8bdSWilliam Juul T(YAFFS_TRACE_VERIFY,(TSTR("Block %d has bad run-state %s"TENDSTR), 433*0e8cc8bdSWilliam Juul n,blockStateName[bi->blockState])); 434*0e8cc8bdSWilliam Juul } 435*0e8cc8bdSWilliam Juul 436*0e8cc8bdSWilliam Juul /* Check pages in use and soft deletions are legal */ 437*0e8cc8bdSWilliam Juul 438*0e8cc8bdSWilliam Juul actuallyUsed = bi->pagesInUse - bi->softDeletions; 439*0e8cc8bdSWilliam Juul 440*0e8cc8bdSWilliam Juul if(bi->pagesInUse < 0 || bi->pagesInUse > dev->nChunksPerBlock || 441*0e8cc8bdSWilliam Juul bi->softDeletions < 0 || bi->softDeletions > dev->nChunksPerBlock || 442*0e8cc8bdSWilliam Juul actuallyUsed < 0 || actuallyUsed > dev->nChunksPerBlock) 443*0e8cc8bdSWilliam Juul T(YAFFS_TRACE_VERIFY,(TSTR("Block %d has illegal values pagesInUsed %d softDeletions %d"TENDSTR), 444*0e8cc8bdSWilliam Juul n,bi->pagesInUse,bi->softDeletions)); 445*0e8cc8bdSWilliam Juul 446*0e8cc8bdSWilliam Juul 447*0e8cc8bdSWilliam Juul /* Check chunk bitmap legal */ 448*0e8cc8bdSWilliam Juul inUse = yaffs_CountChunkBits(dev,n); 449*0e8cc8bdSWilliam Juul if(inUse != bi->pagesInUse) 450*0e8cc8bdSWilliam Juul T(YAFFS_TRACE_VERIFY,(TSTR("Block %d has inconsistent values pagesInUse %d counted chunk bits %d"TENDSTR), 451*0e8cc8bdSWilliam Juul n,bi->pagesInUse,inUse)); 452*0e8cc8bdSWilliam Juul 453*0e8cc8bdSWilliam Juul /* Check that the sequence number is valid. 454*0e8cc8bdSWilliam Juul * Ten million is legal, but is very unlikely 455*0e8cc8bdSWilliam Juul */ 456*0e8cc8bdSWilliam Juul if(dev->isYaffs2 && 457*0e8cc8bdSWilliam Juul (bi->blockState == YAFFS_BLOCK_STATE_ALLOCATING || bi->blockState == YAFFS_BLOCK_STATE_FULL) && 458*0e8cc8bdSWilliam Juul (bi->sequenceNumber < YAFFS_LOWEST_SEQUENCE_NUMBER || bi->sequenceNumber > 10000000 )) 459*0e8cc8bdSWilliam Juul T(YAFFS_TRACE_VERIFY,(TSTR("Block %d has suspect sequence number of %d"TENDSTR), 460*0e8cc8bdSWilliam Juul n,bi->sequenceNumber)); 461*0e8cc8bdSWilliam Juul 462*0e8cc8bdSWilliam Juul } 463*0e8cc8bdSWilliam Juul 464*0e8cc8bdSWilliam Juul static void yaffs_VerifyCollectedBlock(yaffs_Device *dev,yaffs_BlockInfo *bi,int n) 465*0e8cc8bdSWilliam Juul { 466*0e8cc8bdSWilliam Juul yaffs_VerifyBlock(dev,bi,n); 467*0e8cc8bdSWilliam Juul 468*0e8cc8bdSWilliam Juul /* After collection the block should be in the erased state */ 469*0e8cc8bdSWilliam Juul /* TODO: This will need to change if we do partial gc */ 470*0e8cc8bdSWilliam Juul 471*0e8cc8bdSWilliam Juul if(bi->blockState != YAFFS_BLOCK_STATE_EMPTY){ 472*0e8cc8bdSWilliam Juul T(YAFFS_TRACE_ERROR,(TSTR("Block %d is in state %d after gc, should be erased"TENDSTR), 473*0e8cc8bdSWilliam Juul n,bi->blockState)); 474*0e8cc8bdSWilliam Juul } 475*0e8cc8bdSWilliam Juul } 476*0e8cc8bdSWilliam Juul 477*0e8cc8bdSWilliam Juul static void yaffs_VerifyBlocks(yaffs_Device *dev) 478*0e8cc8bdSWilliam Juul { 479*0e8cc8bdSWilliam Juul int i; 480*0e8cc8bdSWilliam Juul int nBlocksPerState[YAFFS_NUMBER_OF_BLOCK_STATES]; 481*0e8cc8bdSWilliam Juul int nIllegalBlockStates = 0; 482*0e8cc8bdSWilliam Juul 483*0e8cc8bdSWilliam Juul 484*0e8cc8bdSWilliam Juul if(yaffs_SkipVerification(dev)) 485*0e8cc8bdSWilliam Juul return; 486*0e8cc8bdSWilliam Juul 487*0e8cc8bdSWilliam Juul memset(nBlocksPerState,0,sizeof(nBlocksPerState)); 488*0e8cc8bdSWilliam Juul 489*0e8cc8bdSWilliam Juul 490*0e8cc8bdSWilliam Juul for(i = dev->internalStartBlock; i <= dev->internalEndBlock; i++){ 491*0e8cc8bdSWilliam Juul yaffs_BlockInfo *bi = yaffs_GetBlockInfo(dev,i); 492*0e8cc8bdSWilliam Juul yaffs_VerifyBlock(dev,bi,i); 493*0e8cc8bdSWilliam Juul 494*0e8cc8bdSWilliam Juul if(bi->blockState >=0 && bi->blockState < YAFFS_NUMBER_OF_BLOCK_STATES) 495*0e8cc8bdSWilliam Juul nBlocksPerState[bi->blockState]++; 496*0e8cc8bdSWilliam Juul else 497*0e8cc8bdSWilliam Juul nIllegalBlockStates++; 498*0e8cc8bdSWilliam Juul 499*0e8cc8bdSWilliam Juul } 500*0e8cc8bdSWilliam Juul 501*0e8cc8bdSWilliam Juul T(YAFFS_TRACE_VERIFY,(TSTR(""TENDSTR))); 502*0e8cc8bdSWilliam Juul T(YAFFS_TRACE_VERIFY,(TSTR("Block summary"TENDSTR))); 503*0e8cc8bdSWilliam Juul 504*0e8cc8bdSWilliam Juul T(YAFFS_TRACE_VERIFY,(TSTR("%d blocks have illegal states"TENDSTR),nIllegalBlockStates)); 505*0e8cc8bdSWilliam Juul if(nBlocksPerState[YAFFS_BLOCK_STATE_ALLOCATING] > 1) 506*0e8cc8bdSWilliam Juul T(YAFFS_TRACE_VERIFY,(TSTR("Too many allocating blocks"TENDSTR))); 507*0e8cc8bdSWilliam Juul 508*0e8cc8bdSWilliam Juul for(i = 0; i < YAFFS_NUMBER_OF_BLOCK_STATES; i++) 509*0e8cc8bdSWilliam Juul T(YAFFS_TRACE_VERIFY, 510*0e8cc8bdSWilliam Juul (TSTR("%s %d blocks"TENDSTR), 511*0e8cc8bdSWilliam Juul blockStateName[i],nBlocksPerState[i])); 512*0e8cc8bdSWilliam Juul 513*0e8cc8bdSWilliam Juul if(dev->blocksInCheckpoint != nBlocksPerState[YAFFS_BLOCK_STATE_CHECKPOINT]) 514*0e8cc8bdSWilliam Juul T(YAFFS_TRACE_VERIFY, 515*0e8cc8bdSWilliam Juul (TSTR("Checkpoint block count wrong dev %d count %d"TENDSTR), 516*0e8cc8bdSWilliam Juul dev->blocksInCheckpoint, nBlocksPerState[YAFFS_BLOCK_STATE_CHECKPOINT])); 517*0e8cc8bdSWilliam Juul 518*0e8cc8bdSWilliam Juul if(dev->nErasedBlocks != nBlocksPerState[YAFFS_BLOCK_STATE_EMPTY]) 519*0e8cc8bdSWilliam Juul T(YAFFS_TRACE_VERIFY, 520*0e8cc8bdSWilliam Juul (TSTR("Erased block count wrong dev %d count %d"TENDSTR), 521*0e8cc8bdSWilliam Juul dev->nErasedBlocks, nBlocksPerState[YAFFS_BLOCK_STATE_EMPTY])); 522*0e8cc8bdSWilliam Juul 523*0e8cc8bdSWilliam Juul if(nBlocksPerState[YAFFS_BLOCK_STATE_COLLECTING] > 1) 524*0e8cc8bdSWilliam Juul T(YAFFS_TRACE_VERIFY, 525*0e8cc8bdSWilliam Juul (TSTR("Too many collecting blocks %d (max is 1)"TENDSTR), 526*0e8cc8bdSWilliam Juul nBlocksPerState[YAFFS_BLOCK_STATE_COLLECTING])); 527*0e8cc8bdSWilliam Juul 528*0e8cc8bdSWilliam Juul T(YAFFS_TRACE_VERIFY,(TSTR(""TENDSTR))); 529*0e8cc8bdSWilliam Juul 530*0e8cc8bdSWilliam Juul } 531*0e8cc8bdSWilliam Juul 532*0e8cc8bdSWilliam Juul /* 533*0e8cc8bdSWilliam Juul * Verify the object header. oh must be valid, but obj and tags may be NULL in which 534*0e8cc8bdSWilliam Juul * case those tests will not be performed. 535*0e8cc8bdSWilliam Juul */ 536*0e8cc8bdSWilliam Juul static void yaffs_VerifyObjectHeader(yaffs_Object *obj, yaffs_ObjectHeader *oh, yaffs_ExtendedTags *tags, int parentCheck) 537*0e8cc8bdSWilliam Juul { 538*0e8cc8bdSWilliam Juul if(yaffs_SkipVerification(obj->myDev)) 539*0e8cc8bdSWilliam Juul return; 540*0e8cc8bdSWilliam Juul 541*0e8cc8bdSWilliam Juul if(!(tags && obj && oh)){ 542*0e8cc8bdSWilliam Juul T(YAFFS_TRACE_VERIFY, 543*0e8cc8bdSWilliam Juul (TSTR("Verifying object header tags %x obj %x oh %x"TENDSTR), 544*0e8cc8bdSWilliam Juul (__u32)tags,(__u32)obj,(__u32)oh)); 545*0e8cc8bdSWilliam Juul return; 546*0e8cc8bdSWilliam Juul } 547*0e8cc8bdSWilliam Juul 548*0e8cc8bdSWilliam Juul if(oh->type <= YAFFS_OBJECT_TYPE_UNKNOWN || 549*0e8cc8bdSWilliam Juul oh->type > YAFFS_OBJECT_TYPE_MAX) 550*0e8cc8bdSWilliam Juul T(YAFFS_TRACE_VERIFY, 551*0e8cc8bdSWilliam Juul (TSTR("Obj %d header type is illegal value 0x%x"TENDSTR), 552*0e8cc8bdSWilliam Juul tags->objectId, oh->type)); 553*0e8cc8bdSWilliam Juul 554*0e8cc8bdSWilliam Juul if(tags->objectId != obj->objectId) 555*0e8cc8bdSWilliam Juul T(YAFFS_TRACE_VERIFY, 556*0e8cc8bdSWilliam Juul (TSTR("Obj %d header mismatch objectId %d"TENDSTR), 557*0e8cc8bdSWilliam Juul tags->objectId, obj->objectId)); 558*0e8cc8bdSWilliam Juul 559*0e8cc8bdSWilliam Juul 560*0e8cc8bdSWilliam Juul /* 561*0e8cc8bdSWilliam Juul * Check that the object's parent ids match if parentCheck requested. 562*0e8cc8bdSWilliam Juul * 563*0e8cc8bdSWilliam Juul * Tests do not apply to the root object. 564*0e8cc8bdSWilliam Juul */ 565*0e8cc8bdSWilliam Juul 566*0e8cc8bdSWilliam Juul if(parentCheck && tags->objectId > 1 && !obj->parent) 567*0e8cc8bdSWilliam Juul T(YAFFS_TRACE_VERIFY, 568*0e8cc8bdSWilliam Juul (TSTR("Obj %d header mismatch parentId %d obj->parent is NULL"TENDSTR), 569*0e8cc8bdSWilliam Juul tags->objectId, oh->parentObjectId)); 570*0e8cc8bdSWilliam Juul 571*0e8cc8bdSWilliam Juul 572*0e8cc8bdSWilliam Juul if(parentCheck && obj->parent && 573*0e8cc8bdSWilliam Juul oh->parentObjectId != obj->parent->objectId && 574*0e8cc8bdSWilliam Juul (oh->parentObjectId != YAFFS_OBJECTID_UNLINKED || 575*0e8cc8bdSWilliam Juul obj->parent->objectId != YAFFS_OBJECTID_DELETED)) 576*0e8cc8bdSWilliam Juul T(YAFFS_TRACE_VERIFY, 577*0e8cc8bdSWilliam Juul (TSTR("Obj %d header mismatch parentId %d parentObjectId %d"TENDSTR), 578*0e8cc8bdSWilliam Juul tags->objectId, oh->parentObjectId, obj->parent->objectId)); 579*0e8cc8bdSWilliam Juul 580*0e8cc8bdSWilliam Juul 581*0e8cc8bdSWilliam Juul if(tags->objectId > 1 && oh->name[0] == 0) /* Null name */ 582*0e8cc8bdSWilliam Juul T(YAFFS_TRACE_VERIFY, 583*0e8cc8bdSWilliam Juul (TSTR("Obj %d header name is NULL"TENDSTR), 584*0e8cc8bdSWilliam Juul obj->objectId)); 585*0e8cc8bdSWilliam Juul 586*0e8cc8bdSWilliam Juul if(tags->objectId > 1 && ((__u8)(oh->name[0])) == 0xff) /* Trashed name */ 587*0e8cc8bdSWilliam Juul T(YAFFS_TRACE_VERIFY, 588*0e8cc8bdSWilliam Juul (TSTR("Obj %d header name is 0xFF"TENDSTR), 589*0e8cc8bdSWilliam Juul obj->objectId)); 590*0e8cc8bdSWilliam Juul } 591*0e8cc8bdSWilliam Juul 592*0e8cc8bdSWilliam Juul 593*0e8cc8bdSWilliam Juul 594*0e8cc8bdSWilliam Juul static int yaffs_VerifyTnodeWorker(yaffs_Object * obj, yaffs_Tnode * tn, 595*0e8cc8bdSWilliam Juul __u32 level, int chunkOffset) 596*0e8cc8bdSWilliam Juul { 597*0e8cc8bdSWilliam Juul int i; 598*0e8cc8bdSWilliam Juul yaffs_Device *dev = obj->myDev; 599*0e8cc8bdSWilliam Juul int ok = 1; 600*0e8cc8bdSWilliam Juul int nTnodeBytes = (dev->tnodeWidth * YAFFS_NTNODES_LEVEL0)/8; 601*0e8cc8bdSWilliam Juul 602*0e8cc8bdSWilliam Juul if (tn) { 603*0e8cc8bdSWilliam Juul if (level > 0) { 604*0e8cc8bdSWilliam Juul 605*0e8cc8bdSWilliam Juul for (i = 0; i < YAFFS_NTNODES_INTERNAL && ok; i++){ 606*0e8cc8bdSWilliam Juul if (tn->internal[i]) { 607*0e8cc8bdSWilliam Juul ok = yaffs_VerifyTnodeWorker(obj, 608*0e8cc8bdSWilliam Juul tn->internal[i], 609*0e8cc8bdSWilliam Juul level - 1, 610*0e8cc8bdSWilliam Juul (chunkOffset<<YAFFS_TNODES_INTERNAL_BITS) + i); 611*0e8cc8bdSWilliam Juul } 612*0e8cc8bdSWilliam Juul } 613*0e8cc8bdSWilliam Juul } else if (level == 0) { 614*0e8cc8bdSWilliam Juul int i; 615*0e8cc8bdSWilliam Juul yaffs_ExtendedTags tags; 616*0e8cc8bdSWilliam Juul __u32 objectId = obj->objectId; 617*0e8cc8bdSWilliam Juul 618*0e8cc8bdSWilliam Juul chunkOffset <<= YAFFS_TNODES_LEVEL0_BITS; 619*0e8cc8bdSWilliam Juul 620*0e8cc8bdSWilliam Juul for(i = 0; i < YAFFS_NTNODES_LEVEL0; i++){ 621*0e8cc8bdSWilliam Juul __u32 theChunk = yaffs_GetChunkGroupBase(dev,tn,i); 622*0e8cc8bdSWilliam Juul 623*0e8cc8bdSWilliam Juul if(theChunk > 0){ 624*0e8cc8bdSWilliam Juul /* T(~0,(TSTR("verifying (%d:%d) %d"TENDSTR),tags.objectId,tags.chunkId,theChunk)); */ 625*0e8cc8bdSWilliam Juul yaffs_ReadChunkWithTagsFromNAND(dev,theChunk,NULL, &tags); 626*0e8cc8bdSWilliam Juul if(tags.objectId != objectId || tags.chunkId != chunkOffset){ 627*0e8cc8bdSWilliam Juul T(~0,(TSTR("Object %d chunkId %d NAND mismatch chunk %d tags (%d:%d)"TENDSTR), 628*0e8cc8bdSWilliam Juul objectId, chunkOffset, theChunk, 629*0e8cc8bdSWilliam Juul tags.objectId, tags.chunkId)); 630*0e8cc8bdSWilliam Juul } 631*0e8cc8bdSWilliam Juul } 632*0e8cc8bdSWilliam Juul chunkOffset++; 633*0e8cc8bdSWilliam Juul } 634*0e8cc8bdSWilliam Juul } 635*0e8cc8bdSWilliam Juul } 636*0e8cc8bdSWilliam Juul 637*0e8cc8bdSWilliam Juul return ok; 638*0e8cc8bdSWilliam Juul 639*0e8cc8bdSWilliam Juul } 640*0e8cc8bdSWilliam Juul 641*0e8cc8bdSWilliam Juul 642*0e8cc8bdSWilliam Juul static void yaffs_VerifyFile(yaffs_Object *obj) 643*0e8cc8bdSWilliam Juul { 644*0e8cc8bdSWilliam Juul int requiredTallness; 645*0e8cc8bdSWilliam Juul int actualTallness; 646*0e8cc8bdSWilliam Juul __u32 lastChunk; 647*0e8cc8bdSWilliam Juul __u32 x; 648*0e8cc8bdSWilliam Juul __u32 i; 649*0e8cc8bdSWilliam Juul int ok; 650*0e8cc8bdSWilliam Juul yaffs_Device *dev; 651*0e8cc8bdSWilliam Juul yaffs_ExtendedTags tags; 652*0e8cc8bdSWilliam Juul yaffs_Tnode *tn; 653*0e8cc8bdSWilliam Juul __u32 objectId; 654*0e8cc8bdSWilliam Juul 655*0e8cc8bdSWilliam Juul if(obj && yaffs_SkipVerification(obj->myDev)) 656*0e8cc8bdSWilliam Juul return; 657*0e8cc8bdSWilliam Juul 658*0e8cc8bdSWilliam Juul dev = obj->myDev; 659*0e8cc8bdSWilliam Juul objectId = obj->objectId; 660*0e8cc8bdSWilliam Juul 661*0e8cc8bdSWilliam Juul /* Check file size is consistent with tnode depth */ 662*0e8cc8bdSWilliam Juul lastChunk = obj->variant.fileVariant.fileSize / dev->nDataBytesPerChunk + 1; 663*0e8cc8bdSWilliam Juul x = lastChunk >> YAFFS_TNODES_LEVEL0_BITS; 664*0e8cc8bdSWilliam Juul requiredTallness = 0; 665*0e8cc8bdSWilliam Juul while (x> 0) { 666*0e8cc8bdSWilliam Juul x >>= YAFFS_TNODES_INTERNAL_BITS; 667*0e8cc8bdSWilliam Juul requiredTallness++; 668*0e8cc8bdSWilliam Juul } 669*0e8cc8bdSWilliam Juul 670*0e8cc8bdSWilliam Juul actualTallness = obj->variant.fileVariant.topLevel; 671*0e8cc8bdSWilliam Juul 672*0e8cc8bdSWilliam Juul if(requiredTallness > actualTallness ) 673*0e8cc8bdSWilliam Juul T(YAFFS_TRACE_VERIFY, 674*0e8cc8bdSWilliam Juul (TSTR("Obj %d had tnode tallness %d, needs to be %d"TENDSTR), 675*0e8cc8bdSWilliam Juul obj->objectId,actualTallness, requiredTallness)); 676*0e8cc8bdSWilliam Juul 677*0e8cc8bdSWilliam Juul 678*0e8cc8bdSWilliam Juul /* Check that the chunks in the tnode tree are all correct. 679*0e8cc8bdSWilliam Juul * We do this by scanning through the tnode tree and 680*0e8cc8bdSWilliam Juul * checking the tags for every chunk match. 681*0e8cc8bdSWilliam Juul */ 682*0e8cc8bdSWilliam Juul 683*0e8cc8bdSWilliam Juul if(yaffs_SkipNANDVerification(dev)) 684*0e8cc8bdSWilliam Juul return; 685*0e8cc8bdSWilliam Juul 686*0e8cc8bdSWilliam Juul for(i = 1; i <= lastChunk; i++){ 687*0e8cc8bdSWilliam Juul tn = yaffs_FindLevel0Tnode(dev, &obj->variant.fileVariant,i); 688*0e8cc8bdSWilliam Juul 689*0e8cc8bdSWilliam Juul if (tn) { 690*0e8cc8bdSWilliam Juul __u32 theChunk = yaffs_GetChunkGroupBase(dev,tn,i); 691*0e8cc8bdSWilliam Juul if(theChunk > 0){ 692*0e8cc8bdSWilliam Juul /* T(~0,(TSTR("verifying (%d:%d) %d"TENDSTR),objectId,i,theChunk)); */ 693*0e8cc8bdSWilliam Juul yaffs_ReadChunkWithTagsFromNAND(dev,theChunk,NULL, &tags); 694*0e8cc8bdSWilliam Juul if(tags.objectId != objectId || tags.chunkId != i){ 695*0e8cc8bdSWilliam Juul T(~0,(TSTR("Object %d chunkId %d NAND mismatch chunk %d tags (%d:%d)"TENDSTR), 696*0e8cc8bdSWilliam Juul objectId, i, theChunk, 697*0e8cc8bdSWilliam Juul tags.objectId, tags.chunkId)); 698*0e8cc8bdSWilliam Juul } 699*0e8cc8bdSWilliam Juul } 700*0e8cc8bdSWilliam Juul } 701*0e8cc8bdSWilliam Juul 702*0e8cc8bdSWilliam Juul } 703*0e8cc8bdSWilliam Juul 704*0e8cc8bdSWilliam Juul } 705*0e8cc8bdSWilliam Juul 706*0e8cc8bdSWilliam Juul static void yaffs_VerifyDirectory(yaffs_Object *obj) 707*0e8cc8bdSWilliam Juul { 708*0e8cc8bdSWilliam Juul if(obj && yaffs_SkipVerification(obj->myDev)) 709*0e8cc8bdSWilliam Juul return; 710*0e8cc8bdSWilliam Juul 711*0e8cc8bdSWilliam Juul } 712*0e8cc8bdSWilliam Juul 713*0e8cc8bdSWilliam Juul static void yaffs_VerifyHardLink(yaffs_Object *obj) 714*0e8cc8bdSWilliam Juul { 715*0e8cc8bdSWilliam Juul if(obj && yaffs_SkipVerification(obj->myDev)) 716*0e8cc8bdSWilliam Juul return; 717*0e8cc8bdSWilliam Juul 718*0e8cc8bdSWilliam Juul /* Verify sane equivalent object */ 719*0e8cc8bdSWilliam Juul } 720*0e8cc8bdSWilliam Juul 721*0e8cc8bdSWilliam Juul static void yaffs_VerifySymlink(yaffs_Object *obj) 722*0e8cc8bdSWilliam Juul { 723*0e8cc8bdSWilliam Juul if(obj && yaffs_SkipVerification(obj->myDev)) 724*0e8cc8bdSWilliam Juul return; 725*0e8cc8bdSWilliam Juul 726*0e8cc8bdSWilliam Juul /* Verify symlink string */ 727*0e8cc8bdSWilliam Juul } 728*0e8cc8bdSWilliam Juul 729*0e8cc8bdSWilliam Juul static void yaffs_VerifySpecial(yaffs_Object *obj) 730*0e8cc8bdSWilliam Juul { 731*0e8cc8bdSWilliam Juul if(obj && yaffs_SkipVerification(obj->myDev)) 732*0e8cc8bdSWilliam Juul return; 733*0e8cc8bdSWilliam Juul } 734*0e8cc8bdSWilliam Juul 735*0e8cc8bdSWilliam Juul static void yaffs_VerifyObject(yaffs_Object *obj) 736*0e8cc8bdSWilliam Juul { 737*0e8cc8bdSWilliam Juul yaffs_Device *dev; 738*0e8cc8bdSWilliam Juul 739*0e8cc8bdSWilliam Juul __u32 chunkMin; 740*0e8cc8bdSWilliam Juul __u32 chunkMax; 741*0e8cc8bdSWilliam Juul 742*0e8cc8bdSWilliam Juul __u32 chunkIdOk; 743*0e8cc8bdSWilliam Juul __u32 chunkIsLive; 744*0e8cc8bdSWilliam Juul 745*0e8cc8bdSWilliam Juul if(!obj) 746*0e8cc8bdSWilliam Juul return; 747*0e8cc8bdSWilliam Juul 748*0e8cc8bdSWilliam Juul dev = obj->myDev; 749*0e8cc8bdSWilliam Juul 750*0e8cc8bdSWilliam Juul if(yaffs_SkipVerification(dev)) 751*0e8cc8bdSWilliam Juul return; 752*0e8cc8bdSWilliam Juul 753*0e8cc8bdSWilliam Juul /* Check sane object header chunk */ 754*0e8cc8bdSWilliam Juul 755*0e8cc8bdSWilliam Juul chunkMin = dev->internalStartBlock * dev->nChunksPerBlock; 756*0e8cc8bdSWilliam Juul chunkMax = (dev->internalEndBlock+1) * dev->nChunksPerBlock - 1; 757*0e8cc8bdSWilliam Juul 758*0e8cc8bdSWilliam Juul chunkIdOk = (obj->chunkId >= chunkMin && obj->chunkId <= chunkMax); 759*0e8cc8bdSWilliam Juul chunkIsLive = chunkIdOk && 760*0e8cc8bdSWilliam Juul yaffs_CheckChunkBit(dev, 761*0e8cc8bdSWilliam Juul obj->chunkId / dev->nChunksPerBlock, 762*0e8cc8bdSWilliam Juul obj->chunkId % dev->nChunksPerBlock); 763*0e8cc8bdSWilliam Juul if(!obj->fake && 764*0e8cc8bdSWilliam Juul (!chunkIdOk || !chunkIsLive)) { 765*0e8cc8bdSWilliam Juul T(YAFFS_TRACE_VERIFY, 766*0e8cc8bdSWilliam Juul (TSTR("Obj %d has chunkId %d %s %s"TENDSTR), 767*0e8cc8bdSWilliam Juul obj->objectId,obj->chunkId, 768*0e8cc8bdSWilliam Juul chunkIdOk ? "" : ",out of range", 769*0e8cc8bdSWilliam Juul chunkIsLive || !chunkIdOk ? "" : ",marked as deleted")); 770*0e8cc8bdSWilliam Juul } 771*0e8cc8bdSWilliam Juul 772*0e8cc8bdSWilliam Juul if(chunkIdOk && chunkIsLive &&!yaffs_SkipNANDVerification(dev)) { 773*0e8cc8bdSWilliam Juul yaffs_ExtendedTags tags; 774*0e8cc8bdSWilliam Juul yaffs_ObjectHeader *oh; 775*0e8cc8bdSWilliam Juul __u8 *buffer = yaffs_GetTempBuffer(dev,__LINE__); 776*0e8cc8bdSWilliam Juul 777*0e8cc8bdSWilliam Juul oh = (yaffs_ObjectHeader *)buffer; 778*0e8cc8bdSWilliam Juul 779*0e8cc8bdSWilliam Juul yaffs_ReadChunkWithTagsFromNAND(dev, obj->chunkId,buffer, &tags); 780*0e8cc8bdSWilliam Juul 781*0e8cc8bdSWilliam Juul yaffs_VerifyObjectHeader(obj,oh,&tags,1); 782*0e8cc8bdSWilliam Juul 783*0e8cc8bdSWilliam Juul yaffs_ReleaseTempBuffer(dev,buffer,__LINE__); 784*0e8cc8bdSWilliam Juul } 785*0e8cc8bdSWilliam Juul 786*0e8cc8bdSWilliam Juul /* Verify it has a parent */ 787*0e8cc8bdSWilliam Juul if(obj && !obj->fake && 788*0e8cc8bdSWilliam Juul (!obj->parent || obj->parent->myDev != dev)){ 789*0e8cc8bdSWilliam Juul T(YAFFS_TRACE_VERIFY, 790*0e8cc8bdSWilliam Juul (TSTR("Obj %d has parent pointer %p which does not look like an object"TENDSTR), 791*0e8cc8bdSWilliam Juul obj->objectId,obj->parent)); 792*0e8cc8bdSWilliam Juul } 793*0e8cc8bdSWilliam Juul 794*0e8cc8bdSWilliam Juul /* Verify parent is a directory */ 795*0e8cc8bdSWilliam Juul if(obj->parent && obj->parent->variantType != YAFFS_OBJECT_TYPE_DIRECTORY){ 796*0e8cc8bdSWilliam Juul T(YAFFS_TRACE_VERIFY, 797*0e8cc8bdSWilliam Juul (TSTR("Obj %d's parent is not a directory (type %d)"TENDSTR), 798*0e8cc8bdSWilliam Juul obj->objectId,obj->parent->variantType)); 799*0e8cc8bdSWilliam Juul } 800*0e8cc8bdSWilliam Juul 801*0e8cc8bdSWilliam Juul switch(obj->variantType){ 802*0e8cc8bdSWilliam Juul case YAFFS_OBJECT_TYPE_FILE: 803*0e8cc8bdSWilliam Juul yaffs_VerifyFile(obj); 804*0e8cc8bdSWilliam Juul break; 805*0e8cc8bdSWilliam Juul case YAFFS_OBJECT_TYPE_SYMLINK: 806*0e8cc8bdSWilliam Juul yaffs_VerifySymlink(obj); 807*0e8cc8bdSWilliam Juul break; 808*0e8cc8bdSWilliam Juul case YAFFS_OBJECT_TYPE_DIRECTORY: 809*0e8cc8bdSWilliam Juul yaffs_VerifyDirectory(obj); 810*0e8cc8bdSWilliam Juul break; 811*0e8cc8bdSWilliam Juul case YAFFS_OBJECT_TYPE_HARDLINK: 812*0e8cc8bdSWilliam Juul yaffs_VerifyHardLink(obj); 813*0e8cc8bdSWilliam Juul break; 814*0e8cc8bdSWilliam Juul case YAFFS_OBJECT_TYPE_SPECIAL: 815*0e8cc8bdSWilliam Juul yaffs_VerifySpecial(obj); 816*0e8cc8bdSWilliam Juul break; 817*0e8cc8bdSWilliam Juul case YAFFS_OBJECT_TYPE_UNKNOWN: 818*0e8cc8bdSWilliam Juul default: 819*0e8cc8bdSWilliam Juul T(YAFFS_TRACE_VERIFY, 820*0e8cc8bdSWilliam Juul (TSTR("Obj %d has illegaltype %d"TENDSTR), 821*0e8cc8bdSWilliam Juul obj->objectId,obj->variantType)); 822*0e8cc8bdSWilliam Juul break; 823*0e8cc8bdSWilliam Juul } 824*0e8cc8bdSWilliam Juul 825*0e8cc8bdSWilliam Juul 826*0e8cc8bdSWilliam Juul } 827*0e8cc8bdSWilliam Juul 828*0e8cc8bdSWilliam Juul static void yaffs_VerifyObjects(yaffs_Device *dev) 829*0e8cc8bdSWilliam Juul { 830*0e8cc8bdSWilliam Juul yaffs_Object *obj; 831*0e8cc8bdSWilliam Juul int i; 832*0e8cc8bdSWilliam Juul struct list_head *lh; 833*0e8cc8bdSWilliam Juul 834*0e8cc8bdSWilliam Juul if(yaffs_SkipVerification(dev)) 835*0e8cc8bdSWilliam Juul return; 836*0e8cc8bdSWilliam Juul 837*0e8cc8bdSWilliam Juul /* Iterate through the objects in each hash entry */ 838*0e8cc8bdSWilliam Juul 839*0e8cc8bdSWilliam Juul for(i = 0; i < YAFFS_NOBJECT_BUCKETS; i++){ 840*0e8cc8bdSWilliam Juul list_for_each(lh, &dev->objectBucket[i].list) { 841*0e8cc8bdSWilliam Juul if (lh) { 842*0e8cc8bdSWilliam Juul obj = list_entry(lh, yaffs_Object, hashLink); 843*0e8cc8bdSWilliam Juul yaffs_VerifyObject(obj); 844*0e8cc8bdSWilliam Juul } 845*0e8cc8bdSWilliam Juul } 846*0e8cc8bdSWilliam Juul } 847*0e8cc8bdSWilliam Juul 848*0e8cc8bdSWilliam Juul } 849*0e8cc8bdSWilliam Juul 850*0e8cc8bdSWilliam Juul 851*0e8cc8bdSWilliam Juul /* 852*0e8cc8bdSWilliam Juul * Simple hash function. Needs to have a reasonable spread 853*0e8cc8bdSWilliam Juul */ 854*0e8cc8bdSWilliam Juul 855*0e8cc8bdSWilliam Juul static Y_INLINE int yaffs_HashFunction(int n) 856*0e8cc8bdSWilliam Juul { 857*0e8cc8bdSWilliam Juul n = abs(n); 858*0e8cc8bdSWilliam Juul return (n % YAFFS_NOBJECT_BUCKETS); 859*0e8cc8bdSWilliam Juul } 860*0e8cc8bdSWilliam Juul 861*0e8cc8bdSWilliam Juul /* 862*0e8cc8bdSWilliam Juul * Access functions to useful fake objects 863*0e8cc8bdSWilliam Juul */ 864*0e8cc8bdSWilliam Juul 865*0e8cc8bdSWilliam Juul yaffs_Object *yaffs_Root(yaffs_Device * dev) 866*0e8cc8bdSWilliam Juul { 867*0e8cc8bdSWilliam Juul return dev->rootDir; 868*0e8cc8bdSWilliam Juul } 869*0e8cc8bdSWilliam Juul 870*0e8cc8bdSWilliam Juul yaffs_Object *yaffs_LostNFound(yaffs_Device * dev) 871*0e8cc8bdSWilliam Juul { 872*0e8cc8bdSWilliam Juul return dev->lostNFoundDir; 873*0e8cc8bdSWilliam Juul } 874*0e8cc8bdSWilliam Juul 875*0e8cc8bdSWilliam Juul 876*0e8cc8bdSWilliam Juul /* 877*0e8cc8bdSWilliam Juul * Erased NAND checking functions 878*0e8cc8bdSWilliam Juul */ 879*0e8cc8bdSWilliam Juul 880*0e8cc8bdSWilliam Juul int yaffs_CheckFF(__u8 * buffer, int nBytes) 881*0e8cc8bdSWilliam Juul { 882*0e8cc8bdSWilliam Juul /* Horrible, slow implementation */ 883*0e8cc8bdSWilliam Juul while (nBytes--) { 884*0e8cc8bdSWilliam Juul if (*buffer != 0xFF) 885*0e8cc8bdSWilliam Juul return 0; 886*0e8cc8bdSWilliam Juul buffer++; 887*0e8cc8bdSWilliam Juul } 888*0e8cc8bdSWilliam Juul return 1; 889*0e8cc8bdSWilliam Juul } 890*0e8cc8bdSWilliam Juul 891*0e8cc8bdSWilliam Juul static int yaffs_CheckChunkErased(struct yaffs_DeviceStruct *dev, 892*0e8cc8bdSWilliam Juul int chunkInNAND) 893*0e8cc8bdSWilliam Juul { 894*0e8cc8bdSWilliam Juul 895*0e8cc8bdSWilliam Juul int retval = YAFFS_OK; 896*0e8cc8bdSWilliam Juul __u8 *data = yaffs_GetTempBuffer(dev, __LINE__); 897*0e8cc8bdSWilliam Juul yaffs_ExtendedTags tags; 898*0e8cc8bdSWilliam Juul int result; 899*0e8cc8bdSWilliam Juul 900*0e8cc8bdSWilliam Juul result = yaffs_ReadChunkWithTagsFromNAND(dev, chunkInNAND, data, &tags); 901*0e8cc8bdSWilliam Juul 902*0e8cc8bdSWilliam Juul if(tags.eccResult > YAFFS_ECC_RESULT_NO_ERROR) 903*0e8cc8bdSWilliam Juul retval = YAFFS_FAIL; 904*0e8cc8bdSWilliam Juul 905*0e8cc8bdSWilliam Juul 906*0e8cc8bdSWilliam Juul if (!yaffs_CheckFF(data, dev->nDataBytesPerChunk) || tags.chunkUsed) { 907*0e8cc8bdSWilliam Juul T(YAFFS_TRACE_NANDACCESS, 908*0e8cc8bdSWilliam Juul (TSTR("Chunk %d not erased" TENDSTR), chunkInNAND)); 909*0e8cc8bdSWilliam Juul retval = YAFFS_FAIL; 910*0e8cc8bdSWilliam Juul } 911*0e8cc8bdSWilliam Juul 912*0e8cc8bdSWilliam Juul yaffs_ReleaseTempBuffer(dev, data, __LINE__); 913*0e8cc8bdSWilliam Juul 914*0e8cc8bdSWilliam Juul return retval; 915*0e8cc8bdSWilliam Juul 916*0e8cc8bdSWilliam Juul } 917*0e8cc8bdSWilliam Juul 918*0e8cc8bdSWilliam Juul static int yaffs_WriteNewChunkWithTagsToNAND(struct yaffs_DeviceStruct *dev, 919*0e8cc8bdSWilliam Juul const __u8 * data, 920*0e8cc8bdSWilliam Juul yaffs_ExtendedTags * tags, 921*0e8cc8bdSWilliam Juul int useReserve) 922*0e8cc8bdSWilliam Juul { 923*0e8cc8bdSWilliam Juul int attempts = 0; 924*0e8cc8bdSWilliam Juul int writeOk = 0; 925*0e8cc8bdSWilliam Juul int chunk; 926*0e8cc8bdSWilliam Juul 927*0e8cc8bdSWilliam Juul yaffs_InvalidateCheckpoint(dev); 928*0e8cc8bdSWilliam Juul 929*0e8cc8bdSWilliam Juul do { 930*0e8cc8bdSWilliam Juul yaffs_BlockInfo *bi = 0; 931*0e8cc8bdSWilliam Juul int erasedOk = 0; 932*0e8cc8bdSWilliam Juul 933*0e8cc8bdSWilliam Juul chunk = yaffs_AllocateChunk(dev, useReserve, &bi); 934*0e8cc8bdSWilliam Juul if (chunk < 0) { 935*0e8cc8bdSWilliam Juul /* no space */ 936*0e8cc8bdSWilliam Juul break; 937*0e8cc8bdSWilliam Juul } 938*0e8cc8bdSWilliam Juul 939*0e8cc8bdSWilliam Juul /* First check this chunk is erased, if it needs 940*0e8cc8bdSWilliam Juul * checking. The checking policy (unless forced 941*0e8cc8bdSWilliam Juul * always on) is as follows: 942*0e8cc8bdSWilliam Juul * 943*0e8cc8bdSWilliam Juul * Check the first page we try to write in a block. 944*0e8cc8bdSWilliam Juul * If the check passes then we don't need to check any 945*0e8cc8bdSWilliam Juul * more. If the check fails, we check again... 946*0e8cc8bdSWilliam Juul * If the block has been erased, we don't need to check. 947*0e8cc8bdSWilliam Juul * 948*0e8cc8bdSWilliam Juul * However, if the block has been prioritised for gc, 949*0e8cc8bdSWilliam Juul * then we think there might be something odd about 950*0e8cc8bdSWilliam Juul * this block and stop using it. 951*0e8cc8bdSWilliam Juul * 952*0e8cc8bdSWilliam Juul * Rationale: We should only ever see chunks that have 953*0e8cc8bdSWilliam Juul * not been erased if there was a partially written 954*0e8cc8bdSWilliam Juul * chunk due to power loss. This checking policy should 955*0e8cc8bdSWilliam Juul * catch that case with very few checks and thus save a 956*0e8cc8bdSWilliam Juul * lot of checks that are most likely not needed. 957*0e8cc8bdSWilliam Juul */ 958*0e8cc8bdSWilliam Juul if (bi->gcPrioritise) { 959*0e8cc8bdSWilliam Juul yaffs_DeleteChunk(dev, chunk, 1, __LINE__); 960*0e8cc8bdSWilliam Juul /* try another chunk */ 961*0e8cc8bdSWilliam Juul continue; 962*0e8cc8bdSWilliam Juul } 963*0e8cc8bdSWilliam Juul 964*0e8cc8bdSWilliam Juul /* let's give it a try */ 965*0e8cc8bdSWilliam Juul attempts++; 966*0e8cc8bdSWilliam Juul 967*0e8cc8bdSWilliam Juul #ifdef CONFIG_YAFFS_ALWAYS_CHECK_CHUNK_ERASED 968*0e8cc8bdSWilliam Juul bi->skipErasedCheck = 0; 969*0e8cc8bdSWilliam Juul #endif 970*0e8cc8bdSWilliam Juul if (!bi->skipErasedCheck) { 971*0e8cc8bdSWilliam Juul erasedOk = yaffs_CheckChunkErased(dev, chunk); 972*0e8cc8bdSWilliam Juul if (erasedOk != YAFFS_OK) { 973*0e8cc8bdSWilliam Juul T(YAFFS_TRACE_ERROR, 974*0e8cc8bdSWilliam Juul (TSTR ("**>> yaffs chunk %d was not erased" 975*0e8cc8bdSWilliam Juul TENDSTR), chunk)); 976*0e8cc8bdSWilliam Juul 977*0e8cc8bdSWilliam Juul /* try another chunk */ 978*0e8cc8bdSWilliam Juul continue; 979*0e8cc8bdSWilliam Juul } 980*0e8cc8bdSWilliam Juul bi->skipErasedCheck = 1; 981*0e8cc8bdSWilliam Juul } 982*0e8cc8bdSWilliam Juul 983*0e8cc8bdSWilliam Juul writeOk = yaffs_WriteChunkWithTagsToNAND(dev, chunk, 984*0e8cc8bdSWilliam Juul data, tags); 985*0e8cc8bdSWilliam Juul if (writeOk != YAFFS_OK) { 986*0e8cc8bdSWilliam Juul yaffs_HandleWriteChunkError(dev, chunk, erasedOk); 987*0e8cc8bdSWilliam Juul /* try another chunk */ 988*0e8cc8bdSWilliam Juul continue; 989*0e8cc8bdSWilliam Juul } 990*0e8cc8bdSWilliam Juul 991*0e8cc8bdSWilliam Juul /* Copy the data into the robustification buffer */ 992*0e8cc8bdSWilliam Juul yaffs_HandleWriteChunkOk(dev, chunk, data, tags); 993*0e8cc8bdSWilliam Juul 994*0e8cc8bdSWilliam Juul } while (writeOk != YAFFS_OK && 995*0e8cc8bdSWilliam Juul (yaffs_wr_attempts <= 0 || attempts <= yaffs_wr_attempts)); 996*0e8cc8bdSWilliam Juul 997*0e8cc8bdSWilliam Juul if(!writeOk) 998*0e8cc8bdSWilliam Juul chunk = -1; 999*0e8cc8bdSWilliam Juul 1000*0e8cc8bdSWilliam Juul if (attempts > 1) { 1001*0e8cc8bdSWilliam Juul T(YAFFS_TRACE_ERROR, 1002*0e8cc8bdSWilliam Juul (TSTR("**>> yaffs write required %d attempts" TENDSTR), 1003*0e8cc8bdSWilliam Juul attempts)); 1004*0e8cc8bdSWilliam Juul 1005*0e8cc8bdSWilliam Juul dev->nRetriedWrites += (attempts - 1); 1006*0e8cc8bdSWilliam Juul } 1007*0e8cc8bdSWilliam Juul 1008*0e8cc8bdSWilliam Juul return chunk; 1009*0e8cc8bdSWilliam Juul } 1010*0e8cc8bdSWilliam Juul 1011*0e8cc8bdSWilliam Juul /* 1012*0e8cc8bdSWilliam Juul * Block retiring for handling a broken block. 1013*0e8cc8bdSWilliam Juul */ 1014*0e8cc8bdSWilliam Juul 1015*0e8cc8bdSWilliam Juul static void yaffs_RetireBlock(yaffs_Device * dev, int blockInNAND) 1016*0e8cc8bdSWilliam Juul { 1017*0e8cc8bdSWilliam Juul yaffs_BlockInfo *bi = yaffs_GetBlockInfo(dev, blockInNAND); 1018*0e8cc8bdSWilliam Juul 1019*0e8cc8bdSWilliam Juul yaffs_InvalidateCheckpoint(dev); 1020*0e8cc8bdSWilliam Juul 1021*0e8cc8bdSWilliam Juul yaffs_MarkBlockBad(dev, blockInNAND); 1022*0e8cc8bdSWilliam Juul 1023*0e8cc8bdSWilliam Juul bi->blockState = YAFFS_BLOCK_STATE_DEAD; 1024*0e8cc8bdSWilliam Juul bi->gcPrioritise = 0; 1025*0e8cc8bdSWilliam Juul bi->needsRetiring = 0; 1026*0e8cc8bdSWilliam Juul 1027*0e8cc8bdSWilliam Juul dev->nRetiredBlocks++; 1028*0e8cc8bdSWilliam Juul } 1029*0e8cc8bdSWilliam Juul 1030*0e8cc8bdSWilliam Juul /* 1031*0e8cc8bdSWilliam Juul * Functions for robustisizing TODO 1032*0e8cc8bdSWilliam Juul * 1033*0e8cc8bdSWilliam Juul */ 1034*0e8cc8bdSWilliam Juul 1035*0e8cc8bdSWilliam Juul static void yaffs_HandleWriteChunkOk(yaffs_Device * dev, int chunkInNAND, 1036*0e8cc8bdSWilliam Juul const __u8 * data, 1037*0e8cc8bdSWilliam Juul const yaffs_ExtendedTags * tags) 1038*0e8cc8bdSWilliam Juul { 1039*0e8cc8bdSWilliam Juul } 1040*0e8cc8bdSWilliam Juul 1041*0e8cc8bdSWilliam Juul static void yaffs_HandleUpdateChunk(yaffs_Device * dev, int chunkInNAND, 1042*0e8cc8bdSWilliam Juul const yaffs_ExtendedTags * tags) 1043*0e8cc8bdSWilliam Juul { 1044*0e8cc8bdSWilliam Juul } 1045*0e8cc8bdSWilliam Juul 1046*0e8cc8bdSWilliam Juul void yaffs_HandleChunkError(yaffs_Device *dev, yaffs_BlockInfo *bi) 1047*0e8cc8bdSWilliam Juul { 1048*0e8cc8bdSWilliam Juul if(!bi->gcPrioritise){ 1049*0e8cc8bdSWilliam Juul bi->gcPrioritise = 1; 1050*0e8cc8bdSWilliam Juul dev->hasPendingPrioritisedGCs = 1; 1051*0e8cc8bdSWilliam Juul bi->chunkErrorStrikes ++; 1052*0e8cc8bdSWilliam Juul 1053*0e8cc8bdSWilliam Juul if(bi->chunkErrorStrikes > 3){ 1054*0e8cc8bdSWilliam Juul bi->needsRetiring = 1; /* Too many stikes, so retire this */ 1055*0e8cc8bdSWilliam Juul T(YAFFS_TRACE_ALWAYS, (TSTR("yaffs: Block struck out" TENDSTR))); 1056*0e8cc8bdSWilliam Juul 1057*0e8cc8bdSWilliam Juul } 1058*0e8cc8bdSWilliam Juul 1059*0e8cc8bdSWilliam Juul } 1060*0e8cc8bdSWilliam Juul } 1061*0e8cc8bdSWilliam Juul 1062*0e8cc8bdSWilliam Juul static void yaffs_HandleWriteChunkError(yaffs_Device * dev, int chunkInNAND, int erasedOk) 1063*0e8cc8bdSWilliam Juul { 1064*0e8cc8bdSWilliam Juul 1065*0e8cc8bdSWilliam Juul int blockInNAND = chunkInNAND / dev->nChunksPerBlock; 1066*0e8cc8bdSWilliam Juul yaffs_BlockInfo *bi = yaffs_GetBlockInfo(dev, blockInNAND); 1067*0e8cc8bdSWilliam Juul 1068*0e8cc8bdSWilliam Juul yaffs_HandleChunkError(dev,bi); 1069*0e8cc8bdSWilliam Juul 1070*0e8cc8bdSWilliam Juul 1071*0e8cc8bdSWilliam Juul if(erasedOk ) { 1072*0e8cc8bdSWilliam Juul /* Was an actual write failure, so mark the block for retirement */ 1073*0e8cc8bdSWilliam Juul bi->needsRetiring = 1; 1074*0e8cc8bdSWilliam Juul T(YAFFS_TRACE_ERROR | YAFFS_TRACE_BAD_BLOCKS, 1075*0e8cc8bdSWilliam Juul (TSTR("**>> Block %d needs retiring" TENDSTR), blockInNAND)); 1076*0e8cc8bdSWilliam Juul 1077*0e8cc8bdSWilliam Juul 1078*0e8cc8bdSWilliam Juul } 1079*0e8cc8bdSWilliam Juul 1080*0e8cc8bdSWilliam Juul /* Delete the chunk */ 1081*0e8cc8bdSWilliam Juul yaffs_DeleteChunk(dev, chunkInNAND, 1, __LINE__); 1082*0e8cc8bdSWilliam Juul } 1083*0e8cc8bdSWilliam Juul 1084*0e8cc8bdSWilliam Juul 1085*0e8cc8bdSWilliam Juul /*---------------- Name handling functions ------------*/ 1086*0e8cc8bdSWilliam Juul 1087*0e8cc8bdSWilliam Juul static __u16 yaffs_CalcNameSum(const YCHAR * name) 1088*0e8cc8bdSWilliam Juul { 1089*0e8cc8bdSWilliam Juul __u16 sum = 0; 1090*0e8cc8bdSWilliam Juul __u16 i = 1; 1091*0e8cc8bdSWilliam Juul 1092*0e8cc8bdSWilliam Juul YUCHAR *bname = (YUCHAR *) name; 1093*0e8cc8bdSWilliam Juul if (bname) { 1094*0e8cc8bdSWilliam Juul while ((*bname) && (i < (YAFFS_MAX_NAME_LENGTH/2))) { 1095*0e8cc8bdSWilliam Juul 1096*0e8cc8bdSWilliam Juul #ifdef CONFIG_YAFFS_CASE_INSENSITIVE 1097*0e8cc8bdSWilliam Juul sum += yaffs_toupper(*bname) * i; 1098*0e8cc8bdSWilliam Juul #else 1099*0e8cc8bdSWilliam Juul sum += (*bname) * i; 1100*0e8cc8bdSWilliam Juul #endif 1101*0e8cc8bdSWilliam Juul i++; 1102*0e8cc8bdSWilliam Juul bname++; 1103*0e8cc8bdSWilliam Juul } 1104*0e8cc8bdSWilliam Juul } 1105*0e8cc8bdSWilliam Juul return sum; 1106*0e8cc8bdSWilliam Juul } 1107*0e8cc8bdSWilliam Juul 1108*0e8cc8bdSWilliam Juul static void yaffs_SetObjectName(yaffs_Object * obj, const YCHAR * name) 1109*0e8cc8bdSWilliam Juul { 1110*0e8cc8bdSWilliam Juul #ifdef CONFIG_YAFFS_SHORT_NAMES_IN_RAM 1111*0e8cc8bdSWilliam Juul if (name && yaffs_strlen(name) <= YAFFS_SHORT_NAME_LENGTH) { 1112*0e8cc8bdSWilliam Juul yaffs_strcpy(obj->shortName, name); 1113*0e8cc8bdSWilliam Juul } else { 1114*0e8cc8bdSWilliam Juul obj->shortName[0] = _Y('\0'); 1115*0e8cc8bdSWilliam Juul } 1116*0e8cc8bdSWilliam Juul #endif 1117*0e8cc8bdSWilliam Juul obj->sum = yaffs_CalcNameSum(name); 1118*0e8cc8bdSWilliam Juul } 1119*0e8cc8bdSWilliam Juul 1120*0e8cc8bdSWilliam Juul /*-------------------- TNODES ------------------- 1121*0e8cc8bdSWilliam Juul 1122*0e8cc8bdSWilliam Juul * List of spare tnodes 1123*0e8cc8bdSWilliam Juul * The list is hooked together using the first pointer 1124*0e8cc8bdSWilliam Juul * in the tnode. 1125*0e8cc8bdSWilliam Juul */ 1126*0e8cc8bdSWilliam Juul 1127*0e8cc8bdSWilliam Juul /* yaffs_CreateTnodes creates a bunch more tnodes and 1128*0e8cc8bdSWilliam Juul * adds them to the tnode free list. 1129*0e8cc8bdSWilliam Juul * Don't use this function directly 1130*0e8cc8bdSWilliam Juul */ 1131*0e8cc8bdSWilliam Juul 1132*0e8cc8bdSWilliam Juul static int yaffs_CreateTnodes(yaffs_Device * dev, int nTnodes) 1133*0e8cc8bdSWilliam Juul { 1134*0e8cc8bdSWilliam Juul int i; 1135*0e8cc8bdSWilliam Juul int tnodeSize; 1136*0e8cc8bdSWilliam Juul yaffs_Tnode *newTnodes; 1137*0e8cc8bdSWilliam Juul __u8 *mem; 1138*0e8cc8bdSWilliam Juul yaffs_Tnode *curr; 1139*0e8cc8bdSWilliam Juul yaffs_Tnode *next; 1140*0e8cc8bdSWilliam Juul yaffs_TnodeList *tnl; 1141*0e8cc8bdSWilliam Juul 1142*0e8cc8bdSWilliam Juul if (nTnodes < 1) 1143*0e8cc8bdSWilliam Juul return YAFFS_OK; 1144*0e8cc8bdSWilliam Juul 1145*0e8cc8bdSWilliam Juul /* Calculate the tnode size in bytes for variable width tnode support. 1146*0e8cc8bdSWilliam Juul * Must be a multiple of 32-bits */ 1147*0e8cc8bdSWilliam Juul tnodeSize = (dev->tnodeWidth * YAFFS_NTNODES_LEVEL0)/8; 1148*0e8cc8bdSWilliam Juul 1149*0e8cc8bdSWilliam Juul /* make these things */ 1150*0e8cc8bdSWilliam Juul 1151*0e8cc8bdSWilliam Juul newTnodes = YMALLOC(nTnodes * tnodeSize); 1152*0e8cc8bdSWilliam Juul mem = (__u8 *)newTnodes; 1153*0e8cc8bdSWilliam Juul 1154*0e8cc8bdSWilliam Juul if (!newTnodes) { 1155*0e8cc8bdSWilliam Juul T(YAFFS_TRACE_ERROR, 1156*0e8cc8bdSWilliam Juul (TSTR("yaffs: Could not allocate Tnodes" TENDSTR))); 1157*0e8cc8bdSWilliam Juul return YAFFS_FAIL; 1158*0e8cc8bdSWilliam Juul } 1159*0e8cc8bdSWilliam Juul 1160*0e8cc8bdSWilliam Juul /* Hook them into the free list */ 1161*0e8cc8bdSWilliam Juul #if 0 1162*0e8cc8bdSWilliam Juul for (i = 0; i < nTnodes - 1; i++) { 1163*0e8cc8bdSWilliam Juul newTnodes[i].internal[0] = &newTnodes[i + 1]; 1164*0e8cc8bdSWilliam Juul #ifdef CONFIG_YAFFS_TNODE_LIST_DEBUG 1165*0e8cc8bdSWilliam Juul newTnodes[i].internal[YAFFS_NTNODES_INTERNAL] = (void *)1; 1166*0e8cc8bdSWilliam Juul #endif 1167*0e8cc8bdSWilliam Juul } 1168*0e8cc8bdSWilliam Juul 1169*0e8cc8bdSWilliam Juul newTnodes[nTnodes - 1].internal[0] = dev->freeTnodes; 1170*0e8cc8bdSWilliam Juul #ifdef CONFIG_YAFFS_TNODE_LIST_DEBUG 1171*0e8cc8bdSWilliam Juul newTnodes[nTnodes - 1].internal[YAFFS_NTNODES_INTERNAL] = (void *)1; 1172*0e8cc8bdSWilliam Juul #endif 1173*0e8cc8bdSWilliam Juul dev->freeTnodes = newTnodes; 1174*0e8cc8bdSWilliam Juul #else 1175*0e8cc8bdSWilliam Juul /* New hookup for wide tnodes */ 1176*0e8cc8bdSWilliam Juul for(i = 0; i < nTnodes -1; i++) { 1177*0e8cc8bdSWilliam Juul curr = (yaffs_Tnode *) &mem[i * tnodeSize]; 1178*0e8cc8bdSWilliam Juul next = (yaffs_Tnode *) &mem[(i+1) * tnodeSize]; 1179*0e8cc8bdSWilliam Juul curr->internal[0] = next; 1180*0e8cc8bdSWilliam Juul } 1181*0e8cc8bdSWilliam Juul 1182*0e8cc8bdSWilliam Juul curr = (yaffs_Tnode *) &mem[(nTnodes - 1) * tnodeSize]; 1183*0e8cc8bdSWilliam Juul curr->internal[0] = dev->freeTnodes; 1184*0e8cc8bdSWilliam Juul dev->freeTnodes = (yaffs_Tnode *)mem; 1185*0e8cc8bdSWilliam Juul 1186*0e8cc8bdSWilliam Juul #endif 1187*0e8cc8bdSWilliam Juul 1188*0e8cc8bdSWilliam Juul 1189*0e8cc8bdSWilliam Juul dev->nFreeTnodes += nTnodes; 1190*0e8cc8bdSWilliam Juul dev->nTnodesCreated += nTnodes; 1191*0e8cc8bdSWilliam Juul 1192*0e8cc8bdSWilliam Juul /* Now add this bunch of tnodes to a list for freeing up. 1193*0e8cc8bdSWilliam Juul * NB If we can't add this to the management list it isn't fatal 1194*0e8cc8bdSWilliam Juul * but it just means we can't free this bunch of tnodes later. 1195*0e8cc8bdSWilliam Juul */ 1196*0e8cc8bdSWilliam Juul 1197*0e8cc8bdSWilliam Juul tnl = YMALLOC(sizeof(yaffs_TnodeList)); 1198*0e8cc8bdSWilliam Juul if (!tnl) { 1199*0e8cc8bdSWilliam Juul T(YAFFS_TRACE_ERROR, 1200*0e8cc8bdSWilliam Juul (TSTR 1201*0e8cc8bdSWilliam Juul ("yaffs: Could not add tnodes to management list" TENDSTR))); 1202*0e8cc8bdSWilliam Juul return YAFFS_FAIL; 1203*0e8cc8bdSWilliam Juul 1204*0e8cc8bdSWilliam Juul } else { 1205*0e8cc8bdSWilliam Juul tnl->tnodes = newTnodes; 1206*0e8cc8bdSWilliam Juul tnl->next = dev->allocatedTnodeList; 1207*0e8cc8bdSWilliam Juul dev->allocatedTnodeList = tnl; 1208*0e8cc8bdSWilliam Juul } 1209*0e8cc8bdSWilliam Juul 1210*0e8cc8bdSWilliam Juul T(YAFFS_TRACE_ALLOCATE, (TSTR("yaffs: Tnodes added" TENDSTR))); 1211*0e8cc8bdSWilliam Juul 1212*0e8cc8bdSWilliam Juul return YAFFS_OK; 1213*0e8cc8bdSWilliam Juul } 1214*0e8cc8bdSWilliam Juul 1215*0e8cc8bdSWilliam Juul /* GetTnode gets us a clean tnode. Tries to make allocate more if we run out */ 1216*0e8cc8bdSWilliam Juul 1217*0e8cc8bdSWilliam Juul static yaffs_Tnode *yaffs_GetTnodeRaw(yaffs_Device * dev) 1218*0e8cc8bdSWilliam Juul { 1219*0e8cc8bdSWilliam Juul yaffs_Tnode *tn = NULL; 1220*0e8cc8bdSWilliam Juul 1221*0e8cc8bdSWilliam Juul /* If there are none left make more */ 1222*0e8cc8bdSWilliam Juul if (!dev->freeTnodes) { 1223*0e8cc8bdSWilliam Juul yaffs_CreateTnodes(dev, YAFFS_ALLOCATION_NTNODES); 1224*0e8cc8bdSWilliam Juul } 1225*0e8cc8bdSWilliam Juul 1226*0e8cc8bdSWilliam Juul if (dev->freeTnodes) { 1227*0e8cc8bdSWilliam Juul tn = dev->freeTnodes; 1228*0e8cc8bdSWilliam Juul #ifdef CONFIG_YAFFS_TNODE_LIST_DEBUG 1229*0e8cc8bdSWilliam Juul if (tn->internal[YAFFS_NTNODES_INTERNAL] != (void *)1) { 1230*0e8cc8bdSWilliam Juul /* Hoosterman, this thing looks like it isn't in the list */ 1231*0e8cc8bdSWilliam Juul T(YAFFS_TRACE_ALWAYS, 1232*0e8cc8bdSWilliam Juul (TSTR("yaffs: Tnode list bug 1" TENDSTR))); 1233*0e8cc8bdSWilliam Juul } 1234*0e8cc8bdSWilliam Juul #endif 1235*0e8cc8bdSWilliam Juul dev->freeTnodes = dev->freeTnodes->internal[0]; 1236*0e8cc8bdSWilliam Juul dev->nFreeTnodes--; 1237*0e8cc8bdSWilliam Juul } 1238*0e8cc8bdSWilliam Juul 1239*0e8cc8bdSWilliam Juul return tn; 1240*0e8cc8bdSWilliam Juul } 1241*0e8cc8bdSWilliam Juul 1242*0e8cc8bdSWilliam Juul static yaffs_Tnode *yaffs_GetTnode(yaffs_Device * dev) 1243*0e8cc8bdSWilliam Juul { 1244*0e8cc8bdSWilliam Juul yaffs_Tnode *tn = yaffs_GetTnodeRaw(dev); 1245*0e8cc8bdSWilliam Juul 1246*0e8cc8bdSWilliam Juul if(tn) 1247*0e8cc8bdSWilliam Juul memset(tn, 0, (dev->tnodeWidth * YAFFS_NTNODES_LEVEL0)/8); 1248*0e8cc8bdSWilliam Juul 1249*0e8cc8bdSWilliam Juul return tn; 1250*0e8cc8bdSWilliam Juul } 1251*0e8cc8bdSWilliam Juul 1252*0e8cc8bdSWilliam Juul /* FreeTnode frees up a tnode and puts it back on the free list */ 1253*0e8cc8bdSWilliam Juul static void yaffs_FreeTnode(yaffs_Device * dev, yaffs_Tnode * tn) 1254*0e8cc8bdSWilliam Juul { 1255*0e8cc8bdSWilliam Juul if (tn) { 1256*0e8cc8bdSWilliam Juul #ifdef CONFIG_YAFFS_TNODE_LIST_DEBUG 1257*0e8cc8bdSWilliam Juul if (tn->internal[YAFFS_NTNODES_INTERNAL] != 0) { 1258*0e8cc8bdSWilliam Juul /* Hoosterman, this thing looks like it is already in the list */ 1259*0e8cc8bdSWilliam Juul T(YAFFS_TRACE_ALWAYS, 1260*0e8cc8bdSWilliam Juul (TSTR("yaffs: Tnode list bug 2" TENDSTR))); 1261*0e8cc8bdSWilliam Juul } 1262*0e8cc8bdSWilliam Juul tn->internal[YAFFS_NTNODES_INTERNAL] = (void *)1; 1263*0e8cc8bdSWilliam Juul #endif 1264*0e8cc8bdSWilliam Juul tn->internal[0] = dev->freeTnodes; 1265*0e8cc8bdSWilliam Juul dev->freeTnodes = tn; 1266*0e8cc8bdSWilliam Juul dev->nFreeTnodes++; 1267*0e8cc8bdSWilliam Juul } 1268*0e8cc8bdSWilliam Juul } 1269*0e8cc8bdSWilliam Juul 1270*0e8cc8bdSWilliam Juul static void yaffs_DeinitialiseTnodes(yaffs_Device * dev) 1271*0e8cc8bdSWilliam Juul { 1272*0e8cc8bdSWilliam Juul /* Free the list of allocated tnodes */ 1273*0e8cc8bdSWilliam Juul yaffs_TnodeList *tmp; 1274*0e8cc8bdSWilliam Juul 1275*0e8cc8bdSWilliam Juul while (dev->allocatedTnodeList) { 1276*0e8cc8bdSWilliam Juul tmp = dev->allocatedTnodeList->next; 1277*0e8cc8bdSWilliam Juul 1278*0e8cc8bdSWilliam Juul YFREE(dev->allocatedTnodeList->tnodes); 1279*0e8cc8bdSWilliam Juul YFREE(dev->allocatedTnodeList); 1280*0e8cc8bdSWilliam Juul dev->allocatedTnodeList = tmp; 1281*0e8cc8bdSWilliam Juul 1282*0e8cc8bdSWilliam Juul } 1283*0e8cc8bdSWilliam Juul 1284*0e8cc8bdSWilliam Juul dev->freeTnodes = NULL; 1285*0e8cc8bdSWilliam Juul dev->nFreeTnodes = 0; 1286*0e8cc8bdSWilliam Juul } 1287*0e8cc8bdSWilliam Juul 1288*0e8cc8bdSWilliam Juul static void yaffs_InitialiseTnodes(yaffs_Device * dev) 1289*0e8cc8bdSWilliam Juul { 1290*0e8cc8bdSWilliam Juul dev->allocatedTnodeList = NULL; 1291*0e8cc8bdSWilliam Juul dev->freeTnodes = NULL; 1292*0e8cc8bdSWilliam Juul dev->nFreeTnodes = 0; 1293*0e8cc8bdSWilliam Juul dev->nTnodesCreated = 0; 1294*0e8cc8bdSWilliam Juul 1295*0e8cc8bdSWilliam Juul } 1296*0e8cc8bdSWilliam Juul 1297*0e8cc8bdSWilliam Juul 1298*0e8cc8bdSWilliam Juul void yaffs_PutLevel0Tnode(yaffs_Device *dev, yaffs_Tnode *tn, unsigned pos, unsigned val) 1299*0e8cc8bdSWilliam Juul { 1300*0e8cc8bdSWilliam Juul __u32 *map = (__u32 *)tn; 1301*0e8cc8bdSWilliam Juul __u32 bitInMap; 1302*0e8cc8bdSWilliam Juul __u32 bitInWord; 1303*0e8cc8bdSWilliam Juul __u32 wordInMap; 1304*0e8cc8bdSWilliam Juul __u32 mask; 1305*0e8cc8bdSWilliam Juul 1306*0e8cc8bdSWilliam Juul pos &= YAFFS_TNODES_LEVEL0_MASK; 1307*0e8cc8bdSWilliam Juul val >>= dev->chunkGroupBits; 1308*0e8cc8bdSWilliam Juul 1309*0e8cc8bdSWilliam Juul bitInMap = pos * dev->tnodeWidth; 1310*0e8cc8bdSWilliam Juul wordInMap = bitInMap /32; 1311*0e8cc8bdSWilliam Juul bitInWord = bitInMap & (32 -1); 1312*0e8cc8bdSWilliam Juul 1313*0e8cc8bdSWilliam Juul mask = dev->tnodeMask << bitInWord; 1314*0e8cc8bdSWilliam Juul 1315*0e8cc8bdSWilliam Juul map[wordInMap] &= ~mask; 1316*0e8cc8bdSWilliam Juul map[wordInMap] |= (mask & (val << bitInWord)); 1317*0e8cc8bdSWilliam Juul 1318*0e8cc8bdSWilliam Juul if(dev->tnodeWidth > (32-bitInWord)) { 1319*0e8cc8bdSWilliam Juul bitInWord = (32 - bitInWord); 1320*0e8cc8bdSWilliam Juul wordInMap++;; 1321*0e8cc8bdSWilliam Juul mask = dev->tnodeMask >> (/*dev->tnodeWidth -*/ bitInWord); 1322*0e8cc8bdSWilliam Juul map[wordInMap] &= ~mask; 1323*0e8cc8bdSWilliam Juul map[wordInMap] |= (mask & (val >> bitInWord)); 1324*0e8cc8bdSWilliam Juul } 1325*0e8cc8bdSWilliam Juul } 1326*0e8cc8bdSWilliam Juul 1327*0e8cc8bdSWilliam Juul static __u32 yaffs_GetChunkGroupBase(yaffs_Device *dev, yaffs_Tnode *tn, unsigned pos) 1328*0e8cc8bdSWilliam Juul { 1329*0e8cc8bdSWilliam Juul __u32 *map = (__u32 *)tn; 1330*0e8cc8bdSWilliam Juul __u32 bitInMap; 1331*0e8cc8bdSWilliam Juul __u32 bitInWord; 1332*0e8cc8bdSWilliam Juul __u32 wordInMap; 1333*0e8cc8bdSWilliam Juul __u32 val; 1334*0e8cc8bdSWilliam Juul 1335*0e8cc8bdSWilliam Juul pos &= YAFFS_TNODES_LEVEL0_MASK; 1336*0e8cc8bdSWilliam Juul 1337*0e8cc8bdSWilliam Juul bitInMap = pos * dev->tnodeWidth; 1338*0e8cc8bdSWilliam Juul wordInMap = bitInMap /32; 1339*0e8cc8bdSWilliam Juul bitInWord = bitInMap & (32 -1); 1340*0e8cc8bdSWilliam Juul 1341*0e8cc8bdSWilliam Juul val = map[wordInMap] >> bitInWord; 1342*0e8cc8bdSWilliam Juul 1343*0e8cc8bdSWilliam Juul if(dev->tnodeWidth > (32-bitInWord)) { 1344*0e8cc8bdSWilliam Juul bitInWord = (32 - bitInWord); 1345*0e8cc8bdSWilliam Juul wordInMap++;; 1346*0e8cc8bdSWilliam Juul val |= (map[wordInMap] << bitInWord); 1347*0e8cc8bdSWilliam Juul } 1348*0e8cc8bdSWilliam Juul 1349*0e8cc8bdSWilliam Juul val &= dev->tnodeMask; 1350*0e8cc8bdSWilliam Juul val <<= dev->chunkGroupBits; 1351*0e8cc8bdSWilliam Juul 1352*0e8cc8bdSWilliam Juul return val; 1353*0e8cc8bdSWilliam Juul } 1354*0e8cc8bdSWilliam Juul 1355*0e8cc8bdSWilliam Juul /* ------------------- End of individual tnode manipulation -----------------*/ 1356*0e8cc8bdSWilliam Juul 1357*0e8cc8bdSWilliam Juul /* ---------Functions to manipulate the look-up tree (made up of tnodes) ------ 1358*0e8cc8bdSWilliam Juul * The look up tree is represented by the top tnode and the number of topLevel 1359*0e8cc8bdSWilliam Juul * in the tree. 0 means only the level 0 tnode is in the tree. 1360*0e8cc8bdSWilliam Juul */ 1361*0e8cc8bdSWilliam Juul 1362*0e8cc8bdSWilliam Juul /* FindLevel0Tnode finds the level 0 tnode, if one exists. */ 1363*0e8cc8bdSWilliam Juul static yaffs_Tnode *yaffs_FindLevel0Tnode(yaffs_Device * dev, 1364*0e8cc8bdSWilliam Juul yaffs_FileStructure * fStruct, 1365*0e8cc8bdSWilliam Juul __u32 chunkId) 1366*0e8cc8bdSWilliam Juul { 1367*0e8cc8bdSWilliam Juul 1368*0e8cc8bdSWilliam Juul yaffs_Tnode *tn = fStruct->top; 1369*0e8cc8bdSWilliam Juul __u32 i; 1370*0e8cc8bdSWilliam Juul int requiredTallness; 1371*0e8cc8bdSWilliam Juul int level = fStruct->topLevel; 1372*0e8cc8bdSWilliam Juul 1373*0e8cc8bdSWilliam Juul /* Check sane level and chunk Id */ 1374*0e8cc8bdSWilliam Juul if (level < 0 || level > YAFFS_TNODES_MAX_LEVEL) { 1375*0e8cc8bdSWilliam Juul return NULL; 1376*0e8cc8bdSWilliam Juul } 1377*0e8cc8bdSWilliam Juul 1378*0e8cc8bdSWilliam Juul if (chunkId > YAFFS_MAX_CHUNK_ID) { 1379*0e8cc8bdSWilliam Juul return NULL; 1380*0e8cc8bdSWilliam Juul } 1381*0e8cc8bdSWilliam Juul 1382*0e8cc8bdSWilliam Juul /* First check we're tall enough (ie enough topLevel) */ 1383*0e8cc8bdSWilliam Juul 1384*0e8cc8bdSWilliam Juul i = chunkId >> YAFFS_TNODES_LEVEL0_BITS; 1385*0e8cc8bdSWilliam Juul requiredTallness = 0; 1386*0e8cc8bdSWilliam Juul while (i) { 1387*0e8cc8bdSWilliam Juul i >>= YAFFS_TNODES_INTERNAL_BITS; 1388*0e8cc8bdSWilliam Juul requiredTallness++; 1389*0e8cc8bdSWilliam Juul } 1390*0e8cc8bdSWilliam Juul 1391*0e8cc8bdSWilliam Juul if (requiredTallness > fStruct->topLevel) { 1392*0e8cc8bdSWilliam Juul /* Not tall enough, so we can't find it, return NULL. */ 1393*0e8cc8bdSWilliam Juul return NULL; 1394*0e8cc8bdSWilliam Juul } 1395*0e8cc8bdSWilliam Juul 1396*0e8cc8bdSWilliam Juul /* Traverse down to level 0 */ 1397*0e8cc8bdSWilliam Juul while (level > 0 && tn) { 1398*0e8cc8bdSWilliam Juul tn = tn-> 1399*0e8cc8bdSWilliam Juul internal[(chunkId >> 1400*0e8cc8bdSWilliam Juul ( YAFFS_TNODES_LEVEL0_BITS + 1401*0e8cc8bdSWilliam Juul (level - 1) * 1402*0e8cc8bdSWilliam Juul YAFFS_TNODES_INTERNAL_BITS) 1403*0e8cc8bdSWilliam Juul ) & 1404*0e8cc8bdSWilliam Juul YAFFS_TNODES_INTERNAL_MASK]; 1405*0e8cc8bdSWilliam Juul level--; 1406*0e8cc8bdSWilliam Juul 1407*0e8cc8bdSWilliam Juul } 1408*0e8cc8bdSWilliam Juul 1409*0e8cc8bdSWilliam Juul return tn; 1410*0e8cc8bdSWilliam Juul } 1411*0e8cc8bdSWilliam Juul 1412*0e8cc8bdSWilliam Juul /* AddOrFindLevel0Tnode finds the level 0 tnode if it exists, otherwise first expands the tree. 1413*0e8cc8bdSWilliam Juul * This happens in two steps: 1414*0e8cc8bdSWilliam Juul * 1. If the tree isn't tall enough, then make it taller. 1415*0e8cc8bdSWilliam Juul * 2. Scan down the tree towards the level 0 tnode adding tnodes if required. 1416*0e8cc8bdSWilliam Juul * 1417*0e8cc8bdSWilliam Juul * Used when modifying the tree. 1418*0e8cc8bdSWilliam Juul * 1419*0e8cc8bdSWilliam Juul * If the tn argument is NULL, then a fresh tnode will be added otherwise the specified tn will 1420*0e8cc8bdSWilliam Juul * be plugged into the ttree. 1421*0e8cc8bdSWilliam Juul */ 1422*0e8cc8bdSWilliam Juul 1423*0e8cc8bdSWilliam Juul static yaffs_Tnode *yaffs_AddOrFindLevel0Tnode(yaffs_Device * dev, 1424*0e8cc8bdSWilliam Juul yaffs_FileStructure * fStruct, 1425*0e8cc8bdSWilliam Juul __u32 chunkId, 1426*0e8cc8bdSWilliam Juul yaffs_Tnode *passedTn) 1427*0e8cc8bdSWilliam Juul { 1428*0e8cc8bdSWilliam Juul 1429*0e8cc8bdSWilliam Juul int requiredTallness; 1430*0e8cc8bdSWilliam Juul int i; 1431*0e8cc8bdSWilliam Juul int l; 1432*0e8cc8bdSWilliam Juul yaffs_Tnode *tn; 1433*0e8cc8bdSWilliam Juul 1434*0e8cc8bdSWilliam Juul __u32 x; 1435*0e8cc8bdSWilliam Juul 1436*0e8cc8bdSWilliam Juul 1437*0e8cc8bdSWilliam Juul /* Check sane level and page Id */ 1438*0e8cc8bdSWilliam Juul if (fStruct->topLevel < 0 || fStruct->topLevel > YAFFS_TNODES_MAX_LEVEL) { 1439*0e8cc8bdSWilliam Juul return NULL; 1440*0e8cc8bdSWilliam Juul } 1441*0e8cc8bdSWilliam Juul 1442*0e8cc8bdSWilliam Juul if (chunkId > YAFFS_MAX_CHUNK_ID) { 1443*0e8cc8bdSWilliam Juul return NULL; 1444*0e8cc8bdSWilliam Juul } 1445*0e8cc8bdSWilliam Juul 1446*0e8cc8bdSWilliam Juul /* First check we're tall enough (ie enough topLevel) */ 1447*0e8cc8bdSWilliam Juul 1448*0e8cc8bdSWilliam Juul x = chunkId >> YAFFS_TNODES_LEVEL0_BITS; 1449*0e8cc8bdSWilliam Juul requiredTallness = 0; 1450*0e8cc8bdSWilliam Juul while (x) { 1451*0e8cc8bdSWilliam Juul x >>= YAFFS_TNODES_INTERNAL_BITS; 1452*0e8cc8bdSWilliam Juul requiredTallness++; 1453*0e8cc8bdSWilliam Juul } 1454*0e8cc8bdSWilliam Juul 1455*0e8cc8bdSWilliam Juul 1456*0e8cc8bdSWilliam Juul if (requiredTallness > fStruct->topLevel) { 1457*0e8cc8bdSWilliam Juul /* Not tall enough,gotta make the tree taller */ 1458*0e8cc8bdSWilliam Juul for (i = fStruct->topLevel; i < requiredTallness; i++) { 1459*0e8cc8bdSWilliam Juul 1460*0e8cc8bdSWilliam Juul tn = yaffs_GetTnode(dev); 1461*0e8cc8bdSWilliam Juul 1462*0e8cc8bdSWilliam Juul if (tn) { 1463*0e8cc8bdSWilliam Juul tn->internal[0] = fStruct->top; 1464*0e8cc8bdSWilliam Juul fStruct->top = tn; 1465*0e8cc8bdSWilliam Juul } else { 1466*0e8cc8bdSWilliam Juul T(YAFFS_TRACE_ERROR, 1467*0e8cc8bdSWilliam Juul (TSTR("yaffs: no more tnodes" TENDSTR))); 1468*0e8cc8bdSWilliam Juul } 1469*0e8cc8bdSWilliam Juul } 1470*0e8cc8bdSWilliam Juul 1471*0e8cc8bdSWilliam Juul fStruct->topLevel = requiredTallness; 1472*0e8cc8bdSWilliam Juul } 1473*0e8cc8bdSWilliam Juul 1474*0e8cc8bdSWilliam Juul /* Traverse down to level 0, adding anything we need */ 1475*0e8cc8bdSWilliam Juul 1476*0e8cc8bdSWilliam Juul l = fStruct->topLevel; 1477*0e8cc8bdSWilliam Juul tn = fStruct->top; 1478*0e8cc8bdSWilliam Juul 1479*0e8cc8bdSWilliam Juul if(l > 0) { 1480*0e8cc8bdSWilliam Juul while (l > 0 && tn) { 1481*0e8cc8bdSWilliam Juul x = (chunkId >> 1482*0e8cc8bdSWilliam Juul ( YAFFS_TNODES_LEVEL0_BITS + 1483*0e8cc8bdSWilliam Juul (l - 1) * YAFFS_TNODES_INTERNAL_BITS)) & 1484*0e8cc8bdSWilliam Juul YAFFS_TNODES_INTERNAL_MASK; 1485*0e8cc8bdSWilliam Juul 1486*0e8cc8bdSWilliam Juul 1487*0e8cc8bdSWilliam Juul if((l>1) && !tn->internal[x]){ 1488*0e8cc8bdSWilliam Juul /* Add missing non-level-zero tnode */ 1489*0e8cc8bdSWilliam Juul tn->internal[x] = yaffs_GetTnode(dev); 1490*0e8cc8bdSWilliam Juul 1491*0e8cc8bdSWilliam Juul } else if(l == 1) { 1492*0e8cc8bdSWilliam Juul /* Looking from level 1 at level 0 */ 1493*0e8cc8bdSWilliam Juul if (passedTn) { 1494*0e8cc8bdSWilliam Juul /* If we already have one, then release it.*/ 1495*0e8cc8bdSWilliam Juul if(tn->internal[x]) 1496*0e8cc8bdSWilliam Juul yaffs_FreeTnode(dev,tn->internal[x]); 1497*0e8cc8bdSWilliam Juul tn->internal[x] = passedTn; 1498*0e8cc8bdSWilliam Juul 1499*0e8cc8bdSWilliam Juul } else if(!tn->internal[x]) { 1500*0e8cc8bdSWilliam Juul /* Don't have one, none passed in */ 1501*0e8cc8bdSWilliam Juul tn->internal[x] = yaffs_GetTnode(dev); 1502*0e8cc8bdSWilliam Juul } 1503*0e8cc8bdSWilliam Juul } 1504*0e8cc8bdSWilliam Juul 1505*0e8cc8bdSWilliam Juul tn = tn->internal[x]; 1506*0e8cc8bdSWilliam Juul l--; 1507*0e8cc8bdSWilliam Juul } 1508*0e8cc8bdSWilliam Juul } else { 1509*0e8cc8bdSWilliam Juul /* top is level 0 */ 1510*0e8cc8bdSWilliam Juul if(passedTn) { 1511*0e8cc8bdSWilliam Juul memcpy(tn,passedTn,(dev->tnodeWidth * YAFFS_NTNODES_LEVEL0)/8); 1512*0e8cc8bdSWilliam Juul yaffs_FreeTnode(dev,passedTn); 1513*0e8cc8bdSWilliam Juul } 1514*0e8cc8bdSWilliam Juul } 1515*0e8cc8bdSWilliam Juul 1516*0e8cc8bdSWilliam Juul return tn; 1517*0e8cc8bdSWilliam Juul } 1518*0e8cc8bdSWilliam Juul 1519*0e8cc8bdSWilliam Juul static int yaffs_FindChunkInGroup(yaffs_Device * dev, int theChunk, 1520*0e8cc8bdSWilliam Juul yaffs_ExtendedTags * tags, int objectId, 1521*0e8cc8bdSWilliam Juul int chunkInInode) 1522*0e8cc8bdSWilliam Juul { 1523*0e8cc8bdSWilliam Juul int j; 1524*0e8cc8bdSWilliam Juul 1525*0e8cc8bdSWilliam Juul for (j = 0; theChunk && j < dev->chunkGroupSize; j++) { 1526*0e8cc8bdSWilliam Juul if (yaffs_CheckChunkBit 1527*0e8cc8bdSWilliam Juul (dev, theChunk / dev->nChunksPerBlock, 1528*0e8cc8bdSWilliam Juul theChunk % dev->nChunksPerBlock)) { 1529*0e8cc8bdSWilliam Juul yaffs_ReadChunkWithTagsFromNAND(dev, theChunk, NULL, 1530*0e8cc8bdSWilliam Juul tags); 1531*0e8cc8bdSWilliam Juul if (yaffs_TagsMatch(tags, objectId, chunkInInode)) { 1532*0e8cc8bdSWilliam Juul /* found it; */ 1533*0e8cc8bdSWilliam Juul return theChunk; 1534*0e8cc8bdSWilliam Juul 1535*0e8cc8bdSWilliam Juul } 1536*0e8cc8bdSWilliam Juul } 1537*0e8cc8bdSWilliam Juul theChunk++; 1538*0e8cc8bdSWilliam Juul } 1539*0e8cc8bdSWilliam Juul return -1; 1540*0e8cc8bdSWilliam Juul } 1541*0e8cc8bdSWilliam Juul 1542*0e8cc8bdSWilliam Juul 1543*0e8cc8bdSWilliam Juul /* DeleteWorker scans backwards through the tnode tree and deletes all the 1544*0e8cc8bdSWilliam Juul * chunks and tnodes in the file 1545*0e8cc8bdSWilliam Juul * Returns 1 if the tree was deleted. 1546*0e8cc8bdSWilliam Juul * Returns 0 if it stopped early due to hitting the limit and the delete is incomplete. 1547*0e8cc8bdSWilliam Juul */ 1548*0e8cc8bdSWilliam Juul 1549*0e8cc8bdSWilliam Juul static int yaffs_DeleteWorker(yaffs_Object * in, yaffs_Tnode * tn, __u32 level, 1550*0e8cc8bdSWilliam Juul int chunkOffset, int *limit) 1551*0e8cc8bdSWilliam Juul { 1552*0e8cc8bdSWilliam Juul int i; 1553*0e8cc8bdSWilliam Juul int chunkInInode; 1554*0e8cc8bdSWilliam Juul int theChunk; 1555*0e8cc8bdSWilliam Juul yaffs_ExtendedTags tags; 1556*0e8cc8bdSWilliam Juul int foundChunk; 1557*0e8cc8bdSWilliam Juul yaffs_Device *dev = in->myDev; 1558*0e8cc8bdSWilliam Juul 1559*0e8cc8bdSWilliam Juul int allDone = 1; 1560*0e8cc8bdSWilliam Juul 1561*0e8cc8bdSWilliam Juul if (tn) { 1562*0e8cc8bdSWilliam Juul if (level > 0) { 1563*0e8cc8bdSWilliam Juul 1564*0e8cc8bdSWilliam Juul for (i = YAFFS_NTNODES_INTERNAL - 1; allDone && i >= 0; 1565*0e8cc8bdSWilliam Juul i--) { 1566*0e8cc8bdSWilliam Juul if (tn->internal[i]) { 1567*0e8cc8bdSWilliam Juul if (limit && (*limit) < 0) { 1568*0e8cc8bdSWilliam Juul allDone = 0; 1569*0e8cc8bdSWilliam Juul } else { 1570*0e8cc8bdSWilliam Juul allDone = 1571*0e8cc8bdSWilliam Juul yaffs_DeleteWorker(in, 1572*0e8cc8bdSWilliam Juul tn-> 1573*0e8cc8bdSWilliam Juul internal 1574*0e8cc8bdSWilliam Juul [i], 1575*0e8cc8bdSWilliam Juul level - 1576*0e8cc8bdSWilliam Juul 1, 1577*0e8cc8bdSWilliam Juul (chunkOffset 1578*0e8cc8bdSWilliam Juul << 1579*0e8cc8bdSWilliam Juul YAFFS_TNODES_INTERNAL_BITS) 1580*0e8cc8bdSWilliam Juul + i, 1581*0e8cc8bdSWilliam Juul limit); 1582*0e8cc8bdSWilliam Juul } 1583*0e8cc8bdSWilliam Juul if (allDone) { 1584*0e8cc8bdSWilliam Juul yaffs_FreeTnode(dev, 1585*0e8cc8bdSWilliam Juul tn-> 1586*0e8cc8bdSWilliam Juul internal[i]); 1587*0e8cc8bdSWilliam Juul tn->internal[i] = NULL; 1588*0e8cc8bdSWilliam Juul } 1589*0e8cc8bdSWilliam Juul } 1590*0e8cc8bdSWilliam Juul 1591*0e8cc8bdSWilliam Juul } 1592*0e8cc8bdSWilliam Juul return (allDone) ? 1 : 0; 1593*0e8cc8bdSWilliam Juul } else if (level == 0) { 1594*0e8cc8bdSWilliam Juul int hitLimit = 0; 1595*0e8cc8bdSWilliam Juul 1596*0e8cc8bdSWilliam Juul for (i = YAFFS_NTNODES_LEVEL0 - 1; i >= 0 && !hitLimit; 1597*0e8cc8bdSWilliam Juul i--) { 1598*0e8cc8bdSWilliam Juul theChunk = yaffs_GetChunkGroupBase(dev,tn,i); 1599*0e8cc8bdSWilliam Juul if (theChunk) { 1600*0e8cc8bdSWilliam Juul 1601*0e8cc8bdSWilliam Juul chunkInInode = 1602*0e8cc8bdSWilliam Juul (chunkOffset << 1603*0e8cc8bdSWilliam Juul YAFFS_TNODES_LEVEL0_BITS) + i; 1604*0e8cc8bdSWilliam Juul 1605*0e8cc8bdSWilliam Juul foundChunk = 1606*0e8cc8bdSWilliam Juul yaffs_FindChunkInGroup(dev, 1607*0e8cc8bdSWilliam Juul theChunk, 1608*0e8cc8bdSWilliam Juul &tags, 1609*0e8cc8bdSWilliam Juul in->objectId, 1610*0e8cc8bdSWilliam Juul chunkInInode); 1611*0e8cc8bdSWilliam Juul 1612*0e8cc8bdSWilliam Juul if (foundChunk > 0) { 1613*0e8cc8bdSWilliam Juul yaffs_DeleteChunk(dev, 1614*0e8cc8bdSWilliam Juul foundChunk, 1, 1615*0e8cc8bdSWilliam Juul __LINE__); 1616*0e8cc8bdSWilliam Juul in->nDataChunks--; 1617*0e8cc8bdSWilliam Juul if (limit) { 1618*0e8cc8bdSWilliam Juul *limit = *limit - 1; 1619*0e8cc8bdSWilliam Juul if (*limit <= 0) { 1620*0e8cc8bdSWilliam Juul hitLimit = 1; 1621*0e8cc8bdSWilliam Juul } 1622*0e8cc8bdSWilliam Juul } 1623*0e8cc8bdSWilliam Juul 1624*0e8cc8bdSWilliam Juul } 1625*0e8cc8bdSWilliam Juul 1626*0e8cc8bdSWilliam Juul yaffs_PutLevel0Tnode(dev,tn,i,0); 1627*0e8cc8bdSWilliam Juul } 1628*0e8cc8bdSWilliam Juul 1629*0e8cc8bdSWilliam Juul } 1630*0e8cc8bdSWilliam Juul return (i < 0) ? 1 : 0; 1631*0e8cc8bdSWilliam Juul 1632*0e8cc8bdSWilliam Juul } 1633*0e8cc8bdSWilliam Juul 1634*0e8cc8bdSWilliam Juul } 1635*0e8cc8bdSWilliam Juul 1636*0e8cc8bdSWilliam Juul return 1; 1637*0e8cc8bdSWilliam Juul 1638*0e8cc8bdSWilliam Juul } 1639*0e8cc8bdSWilliam Juul 1640*0e8cc8bdSWilliam Juul static void yaffs_SoftDeleteChunk(yaffs_Device * dev, int chunk) 1641*0e8cc8bdSWilliam Juul { 1642*0e8cc8bdSWilliam Juul 1643*0e8cc8bdSWilliam Juul yaffs_BlockInfo *theBlock; 1644*0e8cc8bdSWilliam Juul 1645*0e8cc8bdSWilliam Juul T(YAFFS_TRACE_DELETION, (TSTR("soft delete chunk %d" TENDSTR), chunk)); 1646*0e8cc8bdSWilliam Juul 1647*0e8cc8bdSWilliam Juul theBlock = yaffs_GetBlockInfo(dev, chunk / dev->nChunksPerBlock); 1648*0e8cc8bdSWilliam Juul if (theBlock) { 1649*0e8cc8bdSWilliam Juul theBlock->softDeletions++; 1650*0e8cc8bdSWilliam Juul dev->nFreeChunks++; 1651*0e8cc8bdSWilliam Juul } 1652*0e8cc8bdSWilliam Juul } 1653*0e8cc8bdSWilliam Juul 1654*0e8cc8bdSWilliam Juul /* SoftDeleteWorker scans backwards through the tnode tree and soft deletes all the chunks in the file. 1655*0e8cc8bdSWilliam Juul * All soft deleting does is increment the block's softdelete count and pulls the chunk out 1656*0e8cc8bdSWilliam Juul * of the tnode. 1657*0e8cc8bdSWilliam Juul * Thus, essentially this is the same as DeleteWorker except that the chunks are soft deleted. 1658*0e8cc8bdSWilliam Juul */ 1659*0e8cc8bdSWilliam Juul 1660*0e8cc8bdSWilliam Juul static int yaffs_SoftDeleteWorker(yaffs_Object * in, yaffs_Tnode * tn, 1661*0e8cc8bdSWilliam Juul __u32 level, int chunkOffset) 1662*0e8cc8bdSWilliam Juul { 1663*0e8cc8bdSWilliam Juul int i; 1664*0e8cc8bdSWilliam Juul int theChunk; 1665*0e8cc8bdSWilliam Juul int allDone = 1; 1666*0e8cc8bdSWilliam Juul yaffs_Device *dev = in->myDev; 1667*0e8cc8bdSWilliam Juul 1668*0e8cc8bdSWilliam Juul if (tn) { 1669*0e8cc8bdSWilliam Juul if (level > 0) { 1670*0e8cc8bdSWilliam Juul 1671*0e8cc8bdSWilliam Juul for (i = YAFFS_NTNODES_INTERNAL - 1; allDone && i >= 0; 1672*0e8cc8bdSWilliam Juul i--) { 1673*0e8cc8bdSWilliam Juul if (tn->internal[i]) { 1674*0e8cc8bdSWilliam Juul allDone = 1675*0e8cc8bdSWilliam Juul yaffs_SoftDeleteWorker(in, 1676*0e8cc8bdSWilliam Juul tn-> 1677*0e8cc8bdSWilliam Juul internal[i], 1678*0e8cc8bdSWilliam Juul level - 1, 1679*0e8cc8bdSWilliam Juul (chunkOffset 1680*0e8cc8bdSWilliam Juul << 1681*0e8cc8bdSWilliam Juul YAFFS_TNODES_INTERNAL_BITS) 1682*0e8cc8bdSWilliam Juul + i); 1683*0e8cc8bdSWilliam Juul if (allDone) { 1684*0e8cc8bdSWilliam Juul yaffs_FreeTnode(dev, 1685*0e8cc8bdSWilliam Juul tn-> 1686*0e8cc8bdSWilliam Juul internal[i]); 1687*0e8cc8bdSWilliam Juul tn->internal[i] = NULL; 1688*0e8cc8bdSWilliam Juul } else { 1689*0e8cc8bdSWilliam Juul /* Hoosterman... how could this happen? */ 1690*0e8cc8bdSWilliam Juul } 1691*0e8cc8bdSWilliam Juul } 1692*0e8cc8bdSWilliam Juul } 1693*0e8cc8bdSWilliam Juul return (allDone) ? 1 : 0; 1694*0e8cc8bdSWilliam Juul } else if (level == 0) { 1695*0e8cc8bdSWilliam Juul 1696*0e8cc8bdSWilliam Juul for (i = YAFFS_NTNODES_LEVEL0 - 1; i >= 0; i--) { 1697*0e8cc8bdSWilliam Juul theChunk = yaffs_GetChunkGroupBase(dev,tn,i); 1698*0e8cc8bdSWilliam Juul if (theChunk) { 1699*0e8cc8bdSWilliam Juul /* Note this does not find the real chunk, only the chunk group. 1700*0e8cc8bdSWilliam Juul * We make an assumption that a chunk group is not larger than 1701*0e8cc8bdSWilliam Juul * a block. 1702*0e8cc8bdSWilliam Juul */ 1703*0e8cc8bdSWilliam Juul yaffs_SoftDeleteChunk(dev, theChunk); 1704*0e8cc8bdSWilliam Juul yaffs_PutLevel0Tnode(dev,tn,i,0); 1705*0e8cc8bdSWilliam Juul } 1706*0e8cc8bdSWilliam Juul 1707*0e8cc8bdSWilliam Juul } 1708*0e8cc8bdSWilliam Juul return 1; 1709*0e8cc8bdSWilliam Juul 1710*0e8cc8bdSWilliam Juul } 1711*0e8cc8bdSWilliam Juul 1712*0e8cc8bdSWilliam Juul } 1713*0e8cc8bdSWilliam Juul 1714*0e8cc8bdSWilliam Juul return 1; 1715*0e8cc8bdSWilliam Juul 1716*0e8cc8bdSWilliam Juul } 1717*0e8cc8bdSWilliam Juul 1718*0e8cc8bdSWilliam Juul static void yaffs_SoftDeleteFile(yaffs_Object * obj) 1719*0e8cc8bdSWilliam Juul { 1720*0e8cc8bdSWilliam Juul if (obj->deleted && 1721*0e8cc8bdSWilliam Juul obj->variantType == YAFFS_OBJECT_TYPE_FILE && !obj->softDeleted) { 1722*0e8cc8bdSWilliam Juul if (obj->nDataChunks <= 0) { 1723*0e8cc8bdSWilliam Juul /* Empty file with no duplicate object headers, just delete it immediately */ 1724*0e8cc8bdSWilliam Juul yaffs_FreeTnode(obj->myDev, 1725*0e8cc8bdSWilliam Juul obj->variant.fileVariant.top); 1726*0e8cc8bdSWilliam Juul obj->variant.fileVariant.top = NULL; 1727*0e8cc8bdSWilliam Juul T(YAFFS_TRACE_TRACING, 1728*0e8cc8bdSWilliam Juul (TSTR("yaffs: Deleting empty file %d" TENDSTR), 1729*0e8cc8bdSWilliam Juul obj->objectId)); 1730*0e8cc8bdSWilliam Juul yaffs_DoGenericObjectDeletion(obj); 1731*0e8cc8bdSWilliam Juul } else { 1732*0e8cc8bdSWilliam Juul yaffs_SoftDeleteWorker(obj, 1733*0e8cc8bdSWilliam Juul obj->variant.fileVariant.top, 1734*0e8cc8bdSWilliam Juul obj->variant.fileVariant. 1735*0e8cc8bdSWilliam Juul topLevel, 0); 1736*0e8cc8bdSWilliam Juul obj->softDeleted = 1; 1737*0e8cc8bdSWilliam Juul } 1738*0e8cc8bdSWilliam Juul } 1739*0e8cc8bdSWilliam Juul } 1740*0e8cc8bdSWilliam Juul 1741*0e8cc8bdSWilliam Juul /* Pruning removes any part of the file structure tree that is beyond the 1742*0e8cc8bdSWilliam Juul * bounds of the file (ie that does not point to chunks). 1743*0e8cc8bdSWilliam Juul * 1744*0e8cc8bdSWilliam Juul * A file should only get pruned when its size is reduced. 1745*0e8cc8bdSWilliam Juul * 1746*0e8cc8bdSWilliam Juul * Before pruning, the chunks must be pulled from the tree and the 1747*0e8cc8bdSWilliam Juul * level 0 tnode entries must be zeroed out. 1748*0e8cc8bdSWilliam Juul * Could also use this for file deletion, but that's probably better handled 1749*0e8cc8bdSWilliam Juul * by a special case. 1750*0e8cc8bdSWilliam Juul */ 1751*0e8cc8bdSWilliam Juul 1752*0e8cc8bdSWilliam Juul static yaffs_Tnode *yaffs_PruneWorker(yaffs_Device * dev, yaffs_Tnode * tn, 1753*0e8cc8bdSWilliam Juul __u32 level, int del0) 1754*0e8cc8bdSWilliam Juul { 1755*0e8cc8bdSWilliam Juul int i; 1756*0e8cc8bdSWilliam Juul int hasData; 1757*0e8cc8bdSWilliam Juul 1758*0e8cc8bdSWilliam Juul if (tn) { 1759*0e8cc8bdSWilliam Juul hasData = 0; 1760*0e8cc8bdSWilliam Juul 1761*0e8cc8bdSWilliam Juul for (i = 0; i < YAFFS_NTNODES_INTERNAL; i++) { 1762*0e8cc8bdSWilliam Juul if (tn->internal[i] && level > 0) { 1763*0e8cc8bdSWilliam Juul tn->internal[i] = 1764*0e8cc8bdSWilliam Juul yaffs_PruneWorker(dev, tn->internal[i], 1765*0e8cc8bdSWilliam Juul level - 1, 1766*0e8cc8bdSWilliam Juul (i == 0) ? del0 : 1); 1767*0e8cc8bdSWilliam Juul } 1768*0e8cc8bdSWilliam Juul 1769*0e8cc8bdSWilliam Juul if (tn->internal[i]) { 1770*0e8cc8bdSWilliam Juul hasData++; 1771*0e8cc8bdSWilliam Juul } 1772*0e8cc8bdSWilliam Juul } 1773*0e8cc8bdSWilliam Juul 1774*0e8cc8bdSWilliam Juul if (hasData == 0 && del0) { 1775*0e8cc8bdSWilliam Juul /* Free and return NULL */ 1776*0e8cc8bdSWilliam Juul 1777*0e8cc8bdSWilliam Juul yaffs_FreeTnode(dev, tn); 1778*0e8cc8bdSWilliam Juul tn = NULL; 1779*0e8cc8bdSWilliam Juul } 1780*0e8cc8bdSWilliam Juul 1781*0e8cc8bdSWilliam Juul } 1782*0e8cc8bdSWilliam Juul 1783*0e8cc8bdSWilliam Juul return tn; 1784*0e8cc8bdSWilliam Juul 1785*0e8cc8bdSWilliam Juul } 1786*0e8cc8bdSWilliam Juul 1787*0e8cc8bdSWilliam Juul static int yaffs_PruneFileStructure(yaffs_Device * dev, 1788*0e8cc8bdSWilliam Juul yaffs_FileStructure * fStruct) 1789*0e8cc8bdSWilliam Juul { 1790*0e8cc8bdSWilliam Juul int i; 1791*0e8cc8bdSWilliam Juul int hasData; 1792*0e8cc8bdSWilliam Juul int done = 0; 1793*0e8cc8bdSWilliam Juul yaffs_Tnode *tn; 1794*0e8cc8bdSWilliam Juul 1795*0e8cc8bdSWilliam Juul if (fStruct->topLevel > 0) { 1796*0e8cc8bdSWilliam Juul fStruct->top = 1797*0e8cc8bdSWilliam Juul yaffs_PruneWorker(dev, fStruct->top, fStruct->topLevel, 0); 1798*0e8cc8bdSWilliam Juul 1799*0e8cc8bdSWilliam Juul /* Now we have a tree with all the non-zero branches NULL but the height 1800*0e8cc8bdSWilliam Juul * is the same as it was. 1801*0e8cc8bdSWilliam Juul * Let's see if we can trim internal tnodes to shorten the tree. 1802*0e8cc8bdSWilliam Juul * We can do this if only the 0th element in the tnode is in use 1803*0e8cc8bdSWilliam Juul * (ie all the non-zero are NULL) 1804*0e8cc8bdSWilliam Juul */ 1805*0e8cc8bdSWilliam Juul 1806*0e8cc8bdSWilliam Juul while (fStruct->topLevel && !done) { 1807*0e8cc8bdSWilliam Juul tn = fStruct->top; 1808*0e8cc8bdSWilliam Juul 1809*0e8cc8bdSWilliam Juul hasData = 0; 1810*0e8cc8bdSWilliam Juul for (i = 1; i < YAFFS_NTNODES_INTERNAL; i++) { 1811*0e8cc8bdSWilliam Juul if (tn->internal[i]) { 1812*0e8cc8bdSWilliam Juul hasData++; 1813*0e8cc8bdSWilliam Juul } 1814*0e8cc8bdSWilliam Juul } 1815*0e8cc8bdSWilliam Juul 1816*0e8cc8bdSWilliam Juul if (!hasData) { 1817*0e8cc8bdSWilliam Juul fStruct->top = tn->internal[0]; 1818*0e8cc8bdSWilliam Juul fStruct->topLevel--; 1819*0e8cc8bdSWilliam Juul yaffs_FreeTnode(dev, tn); 1820*0e8cc8bdSWilliam Juul } else { 1821*0e8cc8bdSWilliam Juul done = 1; 1822*0e8cc8bdSWilliam Juul } 1823*0e8cc8bdSWilliam Juul } 1824*0e8cc8bdSWilliam Juul } 1825*0e8cc8bdSWilliam Juul 1826*0e8cc8bdSWilliam Juul return YAFFS_OK; 1827*0e8cc8bdSWilliam Juul } 1828*0e8cc8bdSWilliam Juul 1829*0e8cc8bdSWilliam Juul /*-------------------- End of File Structure functions.-------------------*/ 1830*0e8cc8bdSWilliam Juul 1831*0e8cc8bdSWilliam Juul /* yaffs_CreateFreeObjects creates a bunch more objects and 1832*0e8cc8bdSWilliam Juul * adds them to the object free list. 1833*0e8cc8bdSWilliam Juul */ 1834*0e8cc8bdSWilliam Juul static int yaffs_CreateFreeObjects(yaffs_Device * dev, int nObjects) 1835*0e8cc8bdSWilliam Juul { 1836*0e8cc8bdSWilliam Juul int i; 1837*0e8cc8bdSWilliam Juul yaffs_Object *newObjects; 1838*0e8cc8bdSWilliam Juul yaffs_ObjectList *list; 1839*0e8cc8bdSWilliam Juul 1840*0e8cc8bdSWilliam Juul if (nObjects < 1) 1841*0e8cc8bdSWilliam Juul return YAFFS_OK; 1842*0e8cc8bdSWilliam Juul 1843*0e8cc8bdSWilliam Juul /* make these things */ 1844*0e8cc8bdSWilliam Juul newObjects = YMALLOC(nObjects * sizeof(yaffs_Object)); 1845*0e8cc8bdSWilliam Juul list = YMALLOC(sizeof(yaffs_ObjectList)); 1846*0e8cc8bdSWilliam Juul 1847*0e8cc8bdSWilliam Juul if (!newObjects || !list) { 1848*0e8cc8bdSWilliam Juul if(newObjects) 1849*0e8cc8bdSWilliam Juul YFREE(newObjects); 1850*0e8cc8bdSWilliam Juul if(list) 1851*0e8cc8bdSWilliam Juul YFREE(list); 1852*0e8cc8bdSWilliam Juul T(YAFFS_TRACE_ALLOCATE, 1853*0e8cc8bdSWilliam Juul (TSTR("yaffs: Could not allocate more objects" TENDSTR))); 1854*0e8cc8bdSWilliam Juul return YAFFS_FAIL; 1855*0e8cc8bdSWilliam Juul } 1856*0e8cc8bdSWilliam Juul 1857*0e8cc8bdSWilliam Juul /* Hook them into the free list */ 1858*0e8cc8bdSWilliam Juul for (i = 0; i < nObjects - 1; i++) { 1859*0e8cc8bdSWilliam Juul newObjects[i].siblings.next = 1860*0e8cc8bdSWilliam Juul (struct list_head *)(&newObjects[i + 1]); 1861*0e8cc8bdSWilliam Juul } 1862*0e8cc8bdSWilliam Juul 1863*0e8cc8bdSWilliam Juul newObjects[nObjects - 1].siblings.next = (void *)dev->freeObjects; 1864*0e8cc8bdSWilliam Juul dev->freeObjects = newObjects; 1865*0e8cc8bdSWilliam Juul dev->nFreeObjects += nObjects; 1866*0e8cc8bdSWilliam Juul dev->nObjectsCreated += nObjects; 1867*0e8cc8bdSWilliam Juul 1868*0e8cc8bdSWilliam Juul /* Now add this bunch of Objects to a list for freeing up. */ 1869*0e8cc8bdSWilliam Juul 1870*0e8cc8bdSWilliam Juul list->objects = newObjects; 1871*0e8cc8bdSWilliam Juul list->next = dev->allocatedObjectList; 1872*0e8cc8bdSWilliam Juul dev->allocatedObjectList = list; 1873*0e8cc8bdSWilliam Juul 1874*0e8cc8bdSWilliam Juul return YAFFS_OK; 1875*0e8cc8bdSWilliam Juul } 1876*0e8cc8bdSWilliam Juul 1877*0e8cc8bdSWilliam Juul 1878*0e8cc8bdSWilliam Juul /* AllocateEmptyObject gets us a clean Object. Tries to make allocate more if we run out */ 1879*0e8cc8bdSWilliam Juul static yaffs_Object *yaffs_AllocateEmptyObject(yaffs_Device * dev) 1880*0e8cc8bdSWilliam Juul { 1881*0e8cc8bdSWilliam Juul yaffs_Object *tn = NULL; 1882*0e8cc8bdSWilliam Juul 1883*0e8cc8bdSWilliam Juul /* If there are none left make more */ 1884*0e8cc8bdSWilliam Juul if (!dev->freeObjects) { 1885*0e8cc8bdSWilliam Juul yaffs_CreateFreeObjects(dev, YAFFS_ALLOCATION_NOBJECTS); 1886*0e8cc8bdSWilliam Juul } 1887*0e8cc8bdSWilliam Juul 1888*0e8cc8bdSWilliam Juul if (dev->freeObjects) { 1889*0e8cc8bdSWilliam Juul tn = dev->freeObjects; 1890*0e8cc8bdSWilliam Juul dev->freeObjects = 1891*0e8cc8bdSWilliam Juul (yaffs_Object *) (dev->freeObjects->siblings.next); 1892*0e8cc8bdSWilliam Juul dev->nFreeObjects--; 1893*0e8cc8bdSWilliam Juul 1894*0e8cc8bdSWilliam Juul /* Now sweeten it up... */ 1895*0e8cc8bdSWilliam Juul 1896*0e8cc8bdSWilliam Juul memset(tn, 0, sizeof(yaffs_Object)); 1897*0e8cc8bdSWilliam Juul tn->myDev = dev; 1898*0e8cc8bdSWilliam Juul tn->chunkId = -1; 1899*0e8cc8bdSWilliam Juul tn->variantType = YAFFS_OBJECT_TYPE_UNKNOWN; 1900*0e8cc8bdSWilliam Juul INIT_LIST_HEAD(&(tn->hardLinks)); 1901*0e8cc8bdSWilliam Juul INIT_LIST_HEAD(&(tn->hashLink)); 1902*0e8cc8bdSWilliam Juul INIT_LIST_HEAD(&tn->siblings); 1903*0e8cc8bdSWilliam Juul 1904*0e8cc8bdSWilliam Juul /* Add it to the lost and found directory. 1905*0e8cc8bdSWilliam Juul * NB Can't put root or lostNFound in lostNFound so 1906*0e8cc8bdSWilliam Juul * check if lostNFound exists first 1907*0e8cc8bdSWilliam Juul */ 1908*0e8cc8bdSWilliam Juul if (dev->lostNFoundDir) { 1909*0e8cc8bdSWilliam Juul yaffs_AddObjectToDirectory(dev->lostNFoundDir, tn); 1910*0e8cc8bdSWilliam Juul } 1911*0e8cc8bdSWilliam Juul } 1912*0e8cc8bdSWilliam Juul 1913*0e8cc8bdSWilliam Juul return tn; 1914*0e8cc8bdSWilliam Juul } 1915*0e8cc8bdSWilliam Juul 1916*0e8cc8bdSWilliam Juul static yaffs_Object *yaffs_CreateFakeDirectory(yaffs_Device * dev, int number, 1917*0e8cc8bdSWilliam Juul __u32 mode) 1918*0e8cc8bdSWilliam Juul { 1919*0e8cc8bdSWilliam Juul 1920*0e8cc8bdSWilliam Juul yaffs_Object *obj = 1921*0e8cc8bdSWilliam Juul yaffs_CreateNewObject(dev, number, YAFFS_OBJECT_TYPE_DIRECTORY); 1922*0e8cc8bdSWilliam Juul if (obj) { 1923*0e8cc8bdSWilliam Juul obj->fake = 1; /* it is fake so it has no NAND presence... */ 1924*0e8cc8bdSWilliam Juul obj->renameAllowed = 0; /* ... and we're not allowed to rename it... */ 1925*0e8cc8bdSWilliam Juul obj->unlinkAllowed = 0; /* ... or unlink it */ 1926*0e8cc8bdSWilliam Juul obj->deleted = 0; 1927*0e8cc8bdSWilliam Juul obj->unlinked = 0; 1928*0e8cc8bdSWilliam Juul obj->yst_mode = mode; 1929*0e8cc8bdSWilliam Juul obj->myDev = dev; 1930*0e8cc8bdSWilliam Juul obj->chunkId = 0; /* Not a valid chunk. */ 1931*0e8cc8bdSWilliam Juul } 1932*0e8cc8bdSWilliam Juul 1933*0e8cc8bdSWilliam Juul return obj; 1934*0e8cc8bdSWilliam Juul 1935*0e8cc8bdSWilliam Juul } 1936*0e8cc8bdSWilliam Juul 1937*0e8cc8bdSWilliam Juul static void yaffs_UnhashObject(yaffs_Object * tn) 1938*0e8cc8bdSWilliam Juul { 1939*0e8cc8bdSWilliam Juul int bucket; 1940*0e8cc8bdSWilliam Juul yaffs_Device *dev = tn->myDev; 1941*0e8cc8bdSWilliam Juul 1942*0e8cc8bdSWilliam Juul /* If it is still linked into the bucket list, free from the list */ 1943*0e8cc8bdSWilliam Juul if (!list_empty(&tn->hashLink)) { 1944*0e8cc8bdSWilliam Juul list_del_init(&tn->hashLink); 1945*0e8cc8bdSWilliam Juul bucket = yaffs_HashFunction(tn->objectId); 1946*0e8cc8bdSWilliam Juul dev->objectBucket[bucket].count--; 1947*0e8cc8bdSWilliam Juul } 1948*0e8cc8bdSWilliam Juul 1949*0e8cc8bdSWilliam Juul } 1950*0e8cc8bdSWilliam Juul 1951*0e8cc8bdSWilliam Juul /* FreeObject frees up a Object and puts it back on the free list */ 1952*0e8cc8bdSWilliam Juul static void yaffs_FreeObject(yaffs_Object * tn) 1953*0e8cc8bdSWilliam Juul { 1954*0e8cc8bdSWilliam Juul 1955*0e8cc8bdSWilliam Juul yaffs_Device *dev = tn->myDev; 1956*0e8cc8bdSWilliam Juul 1957*0e8cc8bdSWilliam Juul #ifdef __KERNEL__ 1958*0e8cc8bdSWilliam Juul if (tn->myInode) { 1959*0e8cc8bdSWilliam Juul /* We're still hooked up to a cached inode. 1960*0e8cc8bdSWilliam Juul * Don't delete now, but mark for later deletion 1961*0e8cc8bdSWilliam Juul */ 1962*0e8cc8bdSWilliam Juul tn->deferedFree = 1; 1963*0e8cc8bdSWilliam Juul return; 1964*0e8cc8bdSWilliam Juul } 1965*0e8cc8bdSWilliam Juul #endif 1966*0e8cc8bdSWilliam Juul 1967*0e8cc8bdSWilliam Juul yaffs_UnhashObject(tn); 1968*0e8cc8bdSWilliam Juul 1969*0e8cc8bdSWilliam Juul /* Link into the free list. */ 1970*0e8cc8bdSWilliam Juul tn->siblings.next = (struct list_head *)(dev->freeObjects); 1971*0e8cc8bdSWilliam Juul dev->freeObjects = tn; 1972*0e8cc8bdSWilliam Juul dev->nFreeObjects++; 1973*0e8cc8bdSWilliam Juul } 1974*0e8cc8bdSWilliam Juul 1975*0e8cc8bdSWilliam Juul #ifdef __KERNEL__ 1976*0e8cc8bdSWilliam Juul 1977*0e8cc8bdSWilliam Juul void yaffs_HandleDeferedFree(yaffs_Object * obj) 1978*0e8cc8bdSWilliam Juul { 1979*0e8cc8bdSWilliam Juul if (obj->deferedFree) { 1980*0e8cc8bdSWilliam Juul yaffs_FreeObject(obj); 1981*0e8cc8bdSWilliam Juul } 1982*0e8cc8bdSWilliam Juul } 1983*0e8cc8bdSWilliam Juul 1984*0e8cc8bdSWilliam Juul #endif 1985*0e8cc8bdSWilliam Juul 1986*0e8cc8bdSWilliam Juul static void yaffs_DeinitialiseObjects(yaffs_Device * dev) 1987*0e8cc8bdSWilliam Juul { 1988*0e8cc8bdSWilliam Juul /* Free the list of allocated Objects */ 1989*0e8cc8bdSWilliam Juul 1990*0e8cc8bdSWilliam Juul yaffs_ObjectList *tmp; 1991*0e8cc8bdSWilliam Juul 1992*0e8cc8bdSWilliam Juul while (dev->allocatedObjectList) { 1993*0e8cc8bdSWilliam Juul tmp = dev->allocatedObjectList->next; 1994*0e8cc8bdSWilliam Juul YFREE(dev->allocatedObjectList->objects); 1995*0e8cc8bdSWilliam Juul YFREE(dev->allocatedObjectList); 1996*0e8cc8bdSWilliam Juul 1997*0e8cc8bdSWilliam Juul dev->allocatedObjectList = tmp; 1998*0e8cc8bdSWilliam Juul } 1999*0e8cc8bdSWilliam Juul 2000*0e8cc8bdSWilliam Juul dev->freeObjects = NULL; 2001*0e8cc8bdSWilliam Juul dev->nFreeObjects = 0; 2002*0e8cc8bdSWilliam Juul } 2003*0e8cc8bdSWilliam Juul 2004*0e8cc8bdSWilliam Juul static void yaffs_InitialiseObjects(yaffs_Device * dev) 2005*0e8cc8bdSWilliam Juul { 2006*0e8cc8bdSWilliam Juul int i; 2007*0e8cc8bdSWilliam Juul 2008*0e8cc8bdSWilliam Juul dev->allocatedObjectList = NULL; 2009*0e8cc8bdSWilliam Juul dev->freeObjects = NULL; 2010*0e8cc8bdSWilliam Juul dev->nFreeObjects = 0; 2011*0e8cc8bdSWilliam Juul 2012*0e8cc8bdSWilliam Juul for (i = 0; i < YAFFS_NOBJECT_BUCKETS; i++) { 2013*0e8cc8bdSWilliam Juul INIT_LIST_HEAD(&dev->objectBucket[i].list); 2014*0e8cc8bdSWilliam Juul dev->objectBucket[i].count = 0; 2015*0e8cc8bdSWilliam Juul } 2016*0e8cc8bdSWilliam Juul 2017*0e8cc8bdSWilliam Juul } 2018*0e8cc8bdSWilliam Juul 2019*0e8cc8bdSWilliam Juul static int yaffs_FindNiceObjectBucket(yaffs_Device * dev) 2020*0e8cc8bdSWilliam Juul { 2021*0e8cc8bdSWilliam Juul static int x = 0; 2022*0e8cc8bdSWilliam Juul int i; 2023*0e8cc8bdSWilliam Juul int l = 999; 2024*0e8cc8bdSWilliam Juul int lowest = 999999; 2025*0e8cc8bdSWilliam Juul 2026*0e8cc8bdSWilliam Juul /* First let's see if we can find one that's empty. */ 2027*0e8cc8bdSWilliam Juul 2028*0e8cc8bdSWilliam Juul for (i = 0; i < 10 && lowest > 0; i++) { 2029*0e8cc8bdSWilliam Juul x++; 2030*0e8cc8bdSWilliam Juul x %= YAFFS_NOBJECT_BUCKETS; 2031*0e8cc8bdSWilliam Juul if (dev->objectBucket[x].count < lowest) { 2032*0e8cc8bdSWilliam Juul lowest = dev->objectBucket[x].count; 2033*0e8cc8bdSWilliam Juul l = x; 2034*0e8cc8bdSWilliam Juul } 2035*0e8cc8bdSWilliam Juul 2036*0e8cc8bdSWilliam Juul } 2037*0e8cc8bdSWilliam Juul 2038*0e8cc8bdSWilliam Juul /* If we didn't find an empty list, then try 2039*0e8cc8bdSWilliam Juul * looking a bit further for a short one 2040*0e8cc8bdSWilliam Juul */ 2041*0e8cc8bdSWilliam Juul 2042*0e8cc8bdSWilliam Juul for (i = 0; i < 10 && lowest > 3; i++) { 2043*0e8cc8bdSWilliam Juul x++; 2044*0e8cc8bdSWilliam Juul x %= YAFFS_NOBJECT_BUCKETS; 2045*0e8cc8bdSWilliam Juul if (dev->objectBucket[x].count < lowest) { 2046*0e8cc8bdSWilliam Juul lowest = dev->objectBucket[x].count; 2047*0e8cc8bdSWilliam Juul l = x; 2048*0e8cc8bdSWilliam Juul } 2049*0e8cc8bdSWilliam Juul 2050*0e8cc8bdSWilliam Juul } 2051*0e8cc8bdSWilliam Juul 2052*0e8cc8bdSWilliam Juul return l; 2053*0e8cc8bdSWilliam Juul } 2054*0e8cc8bdSWilliam Juul 2055*0e8cc8bdSWilliam Juul static int yaffs_CreateNewObjectNumber(yaffs_Device * dev) 2056*0e8cc8bdSWilliam Juul { 2057*0e8cc8bdSWilliam Juul int bucket = yaffs_FindNiceObjectBucket(dev); 2058*0e8cc8bdSWilliam Juul 2059*0e8cc8bdSWilliam Juul /* Now find an object value that has not already been taken 2060*0e8cc8bdSWilliam Juul * by scanning the list. 2061*0e8cc8bdSWilliam Juul */ 2062*0e8cc8bdSWilliam Juul 2063*0e8cc8bdSWilliam Juul int found = 0; 2064*0e8cc8bdSWilliam Juul struct list_head *i; 2065*0e8cc8bdSWilliam Juul 2066*0e8cc8bdSWilliam Juul __u32 n = (__u32) bucket; 2067*0e8cc8bdSWilliam Juul 2068*0e8cc8bdSWilliam Juul /* yaffs_CheckObjectHashSanity(); */ 2069*0e8cc8bdSWilliam Juul 2070*0e8cc8bdSWilliam Juul while (!found) { 2071*0e8cc8bdSWilliam Juul found = 1; 2072*0e8cc8bdSWilliam Juul n += YAFFS_NOBJECT_BUCKETS; 2073*0e8cc8bdSWilliam Juul if (1 || dev->objectBucket[bucket].count > 0) { 2074*0e8cc8bdSWilliam Juul list_for_each(i, &dev->objectBucket[bucket].list) { 2075*0e8cc8bdSWilliam Juul /* If there is already one in the list */ 2076*0e8cc8bdSWilliam Juul if (i 2077*0e8cc8bdSWilliam Juul && list_entry(i, yaffs_Object, 2078*0e8cc8bdSWilliam Juul hashLink)->objectId == n) { 2079*0e8cc8bdSWilliam Juul found = 0; 2080*0e8cc8bdSWilliam Juul } 2081*0e8cc8bdSWilliam Juul } 2082*0e8cc8bdSWilliam Juul } 2083*0e8cc8bdSWilliam Juul } 2084*0e8cc8bdSWilliam Juul 2085*0e8cc8bdSWilliam Juul 2086*0e8cc8bdSWilliam Juul return n; 2087*0e8cc8bdSWilliam Juul } 2088*0e8cc8bdSWilliam Juul 2089*0e8cc8bdSWilliam Juul static void yaffs_HashObject(yaffs_Object * in) 2090*0e8cc8bdSWilliam Juul { 2091*0e8cc8bdSWilliam Juul int bucket = yaffs_HashFunction(in->objectId); 2092*0e8cc8bdSWilliam Juul yaffs_Device *dev = in->myDev; 2093*0e8cc8bdSWilliam Juul 2094*0e8cc8bdSWilliam Juul list_add(&in->hashLink, &dev->objectBucket[bucket].list); 2095*0e8cc8bdSWilliam Juul dev->objectBucket[bucket].count++; 2096*0e8cc8bdSWilliam Juul 2097*0e8cc8bdSWilliam Juul } 2098*0e8cc8bdSWilliam Juul 2099*0e8cc8bdSWilliam Juul yaffs_Object *yaffs_FindObjectByNumber(yaffs_Device * dev, __u32 number) 2100*0e8cc8bdSWilliam Juul { 2101*0e8cc8bdSWilliam Juul int bucket = yaffs_HashFunction(number); 2102*0e8cc8bdSWilliam Juul struct list_head *i; 2103*0e8cc8bdSWilliam Juul yaffs_Object *in; 2104*0e8cc8bdSWilliam Juul 2105*0e8cc8bdSWilliam Juul list_for_each(i, &dev->objectBucket[bucket].list) { 2106*0e8cc8bdSWilliam Juul /* Look if it is in the list */ 2107*0e8cc8bdSWilliam Juul if (i) { 2108*0e8cc8bdSWilliam Juul in = list_entry(i, yaffs_Object, hashLink); 2109*0e8cc8bdSWilliam Juul if (in->objectId == number) { 2110*0e8cc8bdSWilliam Juul #ifdef __KERNEL__ 2111*0e8cc8bdSWilliam Juul /* Don't tell the VFS about this one if it is defered free */ 2112*0e8cc8bdSWilliam Juul if (in->deferedFree) 2113*0e8cc8bdSWilliam Juul return NULL; 2114*0e8cc8bdSWilliam Juul #endif 2115*0e8cc8bdSWilliam Juul 2116*0e8cc8bdSWilliam Juul return in; 2117*0e8cc8bdSWilliam Juul } 2118*0e8cc8bdSWilliam Juul } 2119*0e8cc8bdSWilliam Juul } 2120*0e8cc8bdSWilliam Juul 2121*0e8cc8bdSWilliam Juul return NULL; 2122*0e8cc8bdSWilliam Juul } 2123*0e8cc8bdSWilliam Juul 2124*0e8cc8bdSWilliam Juul yaffs_Object *yaffs_CreateNewObject(yaffs_Device * dev, int number, 2125*0e8cc8bdSWilliam Juul yaffs_ObjectType type) 2126*0e8cc8bdSWilliam Juul { 2127*0e8cc8bdSWilliam Juul 2128*0e8cc8bdSWilliam Juul yaffs_Object *theObject; 2129*0e8cc8bdSWilliam Juul yaffs_Tnode *tn; 2130*0e8cc8bdSWilliam Juul 2131*0e8cc8bdSWilliam Juul if (number < 0) { 2132*0e8cc8bdSWilliam Juul number = yaffs_CreateNewObjectNumber(dev); 2133*0e8cc8bdSWilliam Juul } 2134*0e8cc8bdSWilliam Juul 2135*0e8cc8bdSWilliam Juul theObject = yaffs_AllocateEmptyObject(dev); 2136*0e8cc8bdSWilliam Juul if(!theObject) 2137*0e8cc8bdSWilliam Juul return NULL; 2138*0e8cc8bdSWilliam Juul 2139*0e8cc8bdSWilliam Juul if(type == YAFFS_OBJECT_TYPE_FILE){ 2140*0e8cc8bdSWilliam Juul tn = yaffs_GetTnode(dev); 2141*0e8cc8bdSWilliam Juul if(!tn){ 2142*0e8cc8bdSWilliam Juul yaffs_FreeObject(theObject); 2143*0e8cc8bdSWilliam Juul return NULL; 2144*0e8cc8bdSWilliam Juul } 2145*0e8cc8bdSWilliam Juul } 2146*0e8cc8bdSWilliam Juul 2147*0e8cc8bdSWilliam Juul 2148*0e8cc8bdSWilliam Juul 2149*0e8cc8bdSWilliam Juul if (theObject) { 2150*0e8cc8bdSWilliam Juul theObject->fake = 0; 2151*0e8cc8bdSWilliam Juul theObject->renameAllowed = 1; 2152*0e8cc8bdSWilliam Juul theObject->unlinkAllowed = 1; 2153*0e8cc8bdSWilliam Juul theObject->objectId = number; 2154*0e8cc8bdSWilliam Juul yaffs_HashObject(theObject); 2155*0e8cc8bdSWilliam Juul theObject->variantType = type; 2156*0e8cc8bdSWilliam Juul #ifdef CONFIG_YAFFS_WINCE 2157*0e8cc8bdSWilliam Juul yfsd_WinFileTimeNow(theObject->win_atime); 2158*0e8cc8bdSWilliam Juul theObject->win_ctime[0] = theObject->win_mtime[0] = 2159*0e8cc8bdSWilliam Juul theObject->win_atime[0]; 2160*0e8cc8bdSWilliam Juul theObject->win_ctime[1] = theObject->win_mtime[1] = 2161*0e8cc8bdSWilliam Juul theObject->win_atime[1]; 2162*0e8cc8bdSWilliam Juul 2163*0e8cc8bdSWilliam Juul #else 2164*0e8cc8bdSWilliam Juul 2165*0e8cc8bdSWilliam Juul theObject->yst_atime = theObject->yst_mtime = 2166*0e8cc8bdSWilliam Juul theObject->yst_ctime = Y_CURRENT_TIME; 2167*0e8cc8bdSWilliam Juul #endif 2168*0e8cc8bdSWilliam Juul switch (type) { 2169*0e8cc8bdSWilliam Juul case YAFFS_OBJECT_TYPE_FILE: 2170*0e8cc8bdSWilliam Juul theObject->variant.fileVariant.fileSize = 0; 2171*0e8cc8bdSWilliam Juul theObject->variant.fileVariant.scannedFileSize = 0; 2172*0e8cc8bdSWilliam Juul theObject->variant.fileVariant.shrinkSize = 0xFFFFFFFF; /* max __u32 */ 2173*0e8cc8bdSWilliam Juul theObject->variant.fileVariant.topLevel = 0; 2174*0e8cc8bdSWilliam Juul theObject->variant.fileVariant.top = tn; 2175*0e8cc8bdSWilliam Juul break; 2176*0e8cc8bdSWilliam Juul case YAFFS_OBJECT_TYPE_DIRECTORY: 2177*0e8cc8bdSWilliam Juul INIT_LIST_HEAD(&theObject->variant.directoryVariant. 2178*0e8cc8bdSWilliam Juul children); 2179*0e8cc8bdSWilliam Juul break; 2180*0e8cc8bdSWilliam Juul case YAFFS_OBJECT_TYPE_SYMLINK: 2181*0e8cc8bdSWilliam Juul case YAFFS_OBJECT_TYPE_HARDLINK: 2182*0e8cc8bdSWilliam Juul case YAFFS_OBJECT_TYPE_SPECIAL: 2183*0e8cc8bdSWilliam Juul /* No action required */ 2184*0e8cc8bdSWilliam Juul break; 2185*0e8cc8bdSWilliam Juul case YAFFS_OBJECT_TYPE_UNKNOWN: 2186*0e8cc8bdSWilliam Juul /* todo this should not happen */ 2187*0e8cc8bdSWilliam Juul break; 2188*0e8cc8bdSWilliam Juul } 2189*0e8cc8bdSWilliam Juul } 2190*0e8cc8bdSWilliam Juul 2191*0e8cc8bdSWilliam Juul return theObject; 2192*0e8cc8bdSWilliam Juul } 2193*0e8cc8bdSWilliam Juul 2194*0e8cc8bdSWilliam Juul static yaffs_Object *yaffs_FindOrCreateObjectByNumber(yaffs_Device * dev, 2195*0e8cc8bdSWilliam Juul int number, 2196*0e8cc8bdSWilliam Juul yaffs_ObjectType type) 2197*0e8cc8bdSWilliam Juul { 2198*0e8cc8bdSWilliam Juul yaffs_Object *theObject = NULL; 2199*0e8cc8bdSWilliam Juul 2200*0e8cc8bdSWilliam Juul if (number > 0) { 2201*0e8cc8bdSWilliam Juul theObject = yaffs_FindObjectByNumber(dev, number); 2202*0e8cc8bdSWilliam Juul } 2203*0e8cc8bdSWilliam Juul 2204*0e8cc8bdSWilliam Juul if (!theObject) { 2205*0e8cc8bdSWilliam Juul theObject = yaffs_CreateNewObject(dev, number, type); 2206*0e8cc8bdSWilliam Juul } 2207*0e8cc8bdSWilliam Juul 2208*0e8cc8bdSWilliam Juul return theObject; 2209*0e8cc8bdSWilliam Juul 2210*0e8cc8bdSWilliam Juul } 2211*0e8cc8bdSWilliam Juul 2212*0e8cc8bdSWilliam Juul 2213*0e8cc8bdSWilliam Juul static YCHAR *yaffs_CloneString(const YCHAR * str) 2214*0e8cc8bdSWilliam Juul { 2215*0e8cc8bdSWilliam Juul YCHAR *newStr = NULL; 2216*0e8cc8bdSWilliam Juul 2217*0e8cc8bdSWilliam Juul if (str && *str) { 2218*0e8cc8bdSWilliam Juul newStr = YMALLOC((yaffs_strlen(str) + 1) * sizeof(YCHAR)); 2219*0e8cc8bdSWilliam Juul if(newStr) 2220*0e8cc8bdSWilliam Juul yaffs_strcpy(newStr, str); 2221*0e8cc8bdSWilliam Juul } 2222*0e8cc8bdSWilliam Juul 2223*0e8cc8bdSWilliam Juul return newStr; 2224*0e8cc8bdSWilliam Juul 2225*0e8cc8bdSWilliam Juul } 2226*0e8cc8bdSWilliam Juul 2227*0e8cc8bdSWilliam Juul /* 2228*0e8cc8bdSWilliam Juul * Mknod (create) a new object. 2229*0e8cc8bdSWilliam Juul * equivalentObject only has meaning for a hard link; 2230*0e8cc8bdSWilliam Juul * aliasString only has meaning for a sumlink. 2231*0e8cc8bdSWilliam Juul * rdev only has meaning for devices (a subset of special objects) 2232*0e8cc8bdSWilliam Juul */ 2233*0e8cc8bdSWilliam Juul 2234*0e8cc8bdSWilliam Juul static yaffs_Object *yaffs_MknodObject(yaffs_ObjectType type, 2235*0e8cc8bdSWilliam Juul yaffs_Object * parent, 2236*0e8cc8bdSWilliam Juul const YCHAR * name, 2237*0e8cc8bdSWilliam Juul __u32 mode, 2238*0e8cc8bdSWilliam Juul __u32 uid, 2239*0e8cc8bdSWilliam Juul __u32 gid, 2240*0e8cc8bdSWilliam Juul yaffs_Object * equivalentObject, 2241*0e8cc8bdSWilliam Juul const YCHAR * aliasString, __u32 rdev) 2242*0e8cc8bdSWilliam Juul { 2243*0e8cc8bdSWilliam Juul yaffs_Object *in; 2244*0e8cc8bdSWilliam Juul YCHAR *str; 2245*0e8cc8bdSWilliam Juul 2246*0e8cc8bdSWilliam Juul yaffs_Device *dev = parent->myDev; 2247*0e8cc8bdSWilliam Juul 2248*0e8cc8bdSWilliam Juul /* Check if the entry exists. If it does then fail the call since we don't want a dup.*/ 2249*0e8cc8bdSWilliam Juul if (yaffs_FindObjectByName(parent, name)) { 2250*0e8cc8bdSWilliam Juul return NULL; 2251*0e8cc8bdSWilliam Juul } 2252*0e8cc8bdSWilliam Juul 2253*0e8cc8bdSWilliam Juul in = yaffs_CreateNewObject(dev, -1, type); 2254*0e8cc8bdSWilliam Juul 2255*0e8cc8bdSWilliam Juul if(type == YAFFS_OBJECT_TYPE_SYMLINK){ 2256*0e8cc8bdSWilliam Juul str = yaffs_CloneString(aliasString); 2257*0e8cc8bdSWilliam Juul if(!str){ 2258*0e8cc8bdSWilliam Juul yaffs_FreeObject(in); 2259*0e8cc8bdSWilliam Juul return NULL; 2260*0e8cc8bdSWilliam Juul } 2261*0e8cc8bdSWilliam Juul } 2262*0e8cc8bdSWilliam Juul 2263*0e8cc8bdSWilliam Juul 2264*0e8cc8bdSWilliam Juul 2265*0e8cc8bdSWilliam Juul if (in) { 2266*0e8cc8bdSWilliam Juul in->chunkId = -1; 2267*0e8cc8bdSWilliam Juul in->valid = 1; 2268*0e8cc8bdSWilliam Juul in->variantType = type; 2269*0e8cc8bdSWilliam Juul 2270*0e8cc8bdSWilliam Juul in->yst_mode = mode; 2271*0e8cc8bdSWilliam Juul 2272*0e8cc8bdSWilliam Juul #ifdef CONFIG_YAFFS_WINCE 2273*0e8cc8bdSWilliam Juul yfsd_WinFileTimeNow(in->win_atime); 2274*0e8cc8bdSWilliam Juul in->win_ctime[0] = in->win_mtime[0] = in->win_atime[0]; 2275*0e8cc8bdSWilliam Juul in->win_ctime[1] = in->win_mtime[1] = in->win_atime[1]; 2276*0e8cc8bdSWilliam Juul 2277*0e8cc8bdSWilliam Juul #else 2278*0e8cc8bdSWilliam Juul in->yst_atime = in->yst_mtime = in->yst_ctime = Y_CURRENT_TIME; 2279*0e8cc8bdSWilliam Juul 2280*0e8cc8bdSWilliam Juul in->yst_rdev = rdev; 2281*0e8cc8bdSWilliam Juul in->yst_uid = uid; 2282*0e8cc8bdSWilliam Juul in->yst_gid = gid; 2283*0e8cc8bdSWilliam Juul #endif 2284*0e8cc8bdSWilliam Juul in->nDataChunks = 0; 2285*0e8cc8bdSWilliam Juul 2286*0e8cc8bdSWilliam Juul yaffs_SetObjectName(in, name); 2287*0e8cc8bdSWilliam Juul in->dirty = 1; 2288*0e8cc8bdSWilliam Juul 2289*0e8cc8bdSWilliam Juul yaffs_AddObjectToDirectory(parent, in); 2290*0e8cc8bdSWilliam Juul 2291*0e8cc8bdSWilliam Juul in->myDev = parent->myDev; 2292*0e8cc8bdSWilliam Juul 2293*0e8cc8bdSWilliam Juul switch (type) { 2294*0e8cc8bdSWilliam Juul case YAFFS_OBJECT_TYPE_SYMLINK: 2295*0e8cc8bdSWilliam Juul in->variant.symLinkVariant.alias = str; 2296*0e8cc8bdSWilliam Juul break; 2297*0e8cc8bdSWilliam Juul case YAFFS_OBJECT_TYPE_HARDLINK: 2298*0e8cc8bdSWilliam Juul in->variant.hardLinkVariant.equivalentObject = 2299*0e8cc8bdSWilliam Juul equivalentObject; 2300*0e8cc8bdSWilliam Juul in->variant.hardLinkVariant.equivalentObjectId = 2301*0e8cc8bdSWilliam Juul equivalentObject->objectId; 2302*0e8cc8bdSWilliam Juul list_add(&in->hardLinks, &equivalentObject->hardLinks); 2303*0e8cc8bdSWilliam Juul break; 2304*0e8cc8bdSWilliam Juul case YAFFS_OBJECT_TYPE_FILE: 2305*0e8cc8bdSWilliam Juul case YAFFS_OBJECT_TYPE_DIRECTORY: 2306*0e8cc8bdSWilliam Juul case YAFFS_OBJECT_TYPE_SPECIAL: 2307*0e8cc8bdSWilliam Juul case YAFFS_OBJECT_TYPE_UNKNOWN: 2308*0e8cc8bdSWilliam Juul /* do nothing */ 2309*0e8cc8bdSWilliam Juul break; 2310*0e8cc8bdSWilliam Juul } 2311*0e8cc8bdSWilliam Juul 2312*0e8cc8bdSWilliam Juul if (yaffs_UpdateObjectHeader(in, name, 0, 0, 0) < 0) { 2313*0e8cc8bdSWilliam Juul /* Could not create the object header, fail the creation */ 2314*0e8cc8bdSWilliam Juul yaffs_DestroyObject(in); 2315*0e8cc8bdSWilliam Juul in = NULL; 2316*0e8cc8bdSWilliam Juul } 2317*0e8cc8bdSWilliam Juul 2318*0e8cc8bdSWilliam Juul } 2319*0e8cc8bdSWilliam Juul 2320*0e8cc8bdSWilliam Juul return in; 2321*0e8cc8bdSWilliam Juul } 2322*0e8cc8bdSWilliam Juul 2323*0e8cc8bdSWilliam Juul yaffs_Object *yaffs_MknodFile(yaffs_Object * parent, const YCHAR * name, 2324*0e8cc8bdSWilliam Juul __u32 mode, __u32 uid, __u32 gid) 2325*0e8cc8bdSWilliam Juul { 2326*0e8cc8bdSWilliam Juul return yaffs_MknodObject(YAFFS_OBJECT_TYPE_FILE, parent, name, mode, 2327*0e8cc8bdSWilliam Juul uid, gid, NULL, NULL, 0); 2328*0e8cc8bdSWilliam Juul } 2329*0e8cc8bdSWilliam Juul 2330*0e8cc8bdSWilliam Juul yaffs_Object *yaffs_MknodDirectory(yaffs_Object * parent, const YCHAR * name, 2331*0e8cc8bdSWilliam Juul __u32 mode, __u32 uid, __u32 gid) 2332*0e8cc8bdSWilliam Juul { 2333*0e8cc8bdSWilliam Juul return yaffs_MknodObject(YAFFS_OBJECT_TYPE_DIRECTORY, parent, name, 2334*0e8cc8bdSWilliam Juul mode, uid, gid, NULL, NULL, 0); 2335*0e8cc8bdSWilliam Juul } 2336*0e8cc8bdSWilliam Juul 2337*0e8cc8bdSWilliam Juul yaffs_Object *yaffs_MknodSpecial(yaffs_Object * parent, const YCHAR * name, 2338*0e8cc8bdSWilliam Juul __u32 mode, __u32 uid, __u32 gid, __u32 rdev) 2339*0e8cc8bdSWilliam Juul { 2340*0e8cc8bdSWilliam Juul return yaffs_MknodObject(YAFFS_OBJECT_TYPE_SPECIAL, parent, name, mode, 2341*0e8cc8bdSWilliam Juul uid, gid, NULL, NULL, rdev); 2342*0e8cc8bdSWilliam Juul } 2343*0e8cc8bdSWilliam Juul 2344*0e8cc8bdSWilliam Juul yaffs_Object *yaffs_MknodSymLink(yaffs_Object * parent, const YCHAR * name, 2345*0e8cc8bdSWilliam Juul __u32 mode, __u32 uid, __u32 gid, 2346*0e8cc8bdSWilliam Juul const YCHAR * alias) 2347*0e8cc8bdSWilliam Juul { 2348*0e8cc8bdSWilliam Juul return yaffs_MknodObject(YAFFS_OBJECT_TYPE_SYMLINK, parent, name, mode, 2349*0e8cc8bdSWilliam Juul uid, gid, NULL, alias, 0); 2350*0e8cc8bdSWilliam Juul } 2351*0e8cc8bdSWilliam Juul 2352*0e8cc8bdSWilliam Juul /* yaffs_Link returns the object id of the equivalent object.*/ 2353*0e8cc8bdSWilliam Juul yaffs_Object *yaffs_Link(yaffs_Object * parent, const YCHAR * name, 2354*0e8cc8bdSWilliam Juul yaffs_Object * equivalentObject) 2355*0e8cc8bdSWilliam Juul { 2356*0e8cc8bdSWilliam Juul /* Get the real object in case we were fed a hard link as an equivalent object */ 2357*0e8cc8bdSWilliam Juul equivalentObject = yaffs_GetEquivalentObject(equivalentObject); 2358*0e8cc8bdSWilliam Juul 2359*0e8cc8bdSWilliam Juul if (yaffs_MknodObject 2360*0e8cc8bdSWilliam Juul (YAFFS_OBJECT_TYPE_HARDLINK, parent, name, 0, 0, 0, 2361*0e8cc8bdSWilliam Juul equivalentObject, NULL, 0)) { 2362*0e8cc8bdSWilliam Juul return equivalentObject; 2363*0e8cc8bdSWilliam Juul } else { 2364*0e8cc8bdSWilliam Juul return NULL; 2365*0e8cc8bdSWilliam Juul } 2366*0e8cc8bdSWilliam Juul 2367*0e8cc8bdSWilliam Juul } 2368*0e8cc8bdSWilliam Juul 2369*0e8cc8bdSWilliam Juul static int yaffs_ChangeObjectName(yaffs_Object * obj, yaffs_Object * newDir, 2370*0e8cc8bdSWilliam Juul const YCHAR * newName, int force, int shadows) 2371*0e8cc8bdSWilliam Juul { 2372*0e8cc8bdSWilliam Juul int unlinkOp; 2373*0e8cc8bdSWilliam Juul int deleteOp; 2374*0e8cc8bdSWilliam Juul 2375*0e8cc8bdSWilliam Juul yaffs_Object *existingTarget; 2376*0e8cc8bdSWilliam Juul 2377*0e8cc8bdSWilliam Juul if (newDir == NULL) { 2378*0e8cc8bdSWilliam Juul newDir = obj->parent; /* use the old directory */ 2379*0e8cc8bdSWilliam Juul } 2380*0e8cc8bdSWilliam Juul 2381*0e8cc8bdSWilliam Juul if (newDir->variantType != YAFFS_OBJECT_TYPE_DIRECTORY) { 2382*0e8cc8bdSWilliam Juul T(YAFFS_TRACE_ALWAYS, 2383*0e8cc8bdSWilliam Juul (TSTR 2384*0e8cc8bdSWilliam Juul ("tragendy: yaffs_ChangeObjectName: newDir is not a directory" 2385*0e8cc8bdSWilliam Juul TENDSTR))); 2386*0e8cc8bdSWilliam Juul YBUG(); 2387*0e8cc8bdSWilliam Juul } 2388*0e8cc8bdSWilliam Juul 2389*0e8cc8bdSWilliam Juul /* TODO: Do we need this different handling for YAFFS2 and YAFFS1?? */ 2390*0e8cc8bdSWilliam Juul if (obj->myDev->isYaffs2) { 2391*0e8cc8bdSWilliam Juul unlinkOp = (newDir == obj->myDev->unlinkedDir); 2392*0e8cc8bdSWilliam Juul } else { 2393*0e8cc8bdSWilliam Juul unlinkOp = (newDir == obj->myDev->unlinkedDir 2394*0e8cc8bdSWilliam Juul && obj->variantType == YAFFS_OBJECT_TYPE_FILE); 2395*0e8cc8bdSWilliam Juul } 2396*0e8cc8bdSWilliam Juul 2397*0e8cc8bdSWilliam Juul deleteOp = (newDir == obj->myDev->deletedDir); 2398*0e8cc8bdSWilliam Juul 2399*0e8cc8bdSWilliam Juul existingTarget = yaffs_FindObjectByName(newDir, newName); 2400*0e8cc8bdSWilliam Juul 2401*0e8cc8bdSWilliam Juul /* If the object is a file going into the unlinked directory, 2402*0e8cc8bdSWilliam Juul * then it is OK to just stuff it in since duplicate names are allowed. 2403*0e8cc8bdSWilliam Juul * else only proceed if the new name does not exist and if we're putting 2404*0e8cc8bdSWilliam Juul * it into a directory. 2405*0e8cc8bdSWilliam Juul */ 2406*0e8cc8bdSWilliam Juul if ((unlinkOp || 2407*0e8cc8bdSWilliam Juul deleteOp || 2408*0e8cc8bdSWilliam Juul force || 2409*0e8cc8bdSWilliam Juul (shadows > 0) || 2410*0e8cc8bdSWilliam Juul !existingTarget) && 2411*0e8cc8bdSWilliam Juul newDir->variantType == YAFFS_OBJECT_TYPE_DIRECTORY) { 2412*0e8cc8bdSWilliam Juul yaffs_SetObjectName(obj, newName); 2413*0e8cc8bdSWilliam Juul obj->dirty = 1; 2414*0e8cc8bdSWilliam Juul 2415*0e8cc8bdSWilliam Juul yaffs_AddObjectToDirectory(newDir, obj); 2416*0e8cc8bdSWilliam Juul 2417*0e8cc8bdSWilliam Juul if (unlinkOp) 2418*0e8cc8bdSWilliam Juul obj->unlinked = 1; 2419*0e8cc8bdSWilliam Juul 2420*0e8cc8bdSWilliam Juul /* If it is a deletion then we mark it as a shrink for gc purposes. */ 2421*0e8cc8bdSWilliam Juul if (yaffs_UpdateObjectHeader(obj, newName, 0, deleteOp, shadows)>= 0) 2422*0e8cc8bdSWilliam Juul return YAFFS_OK; 2423*0e8cc8bdSWilliam Juul } 2424*0e8cc8bdSWilliam Juul 2425*0e8cc8bdSWilliam Juul return YAFFS_FAIL; 2426*0e8cc8bdSWilliam Juul } 2427*0e8cc8bdSWilliam Juul 2428*0e8cc8bdSWilliam Juul int yaffs_RenameObject(yaffs_Object * oldDir, const YCHAR * oldName, 2429*0e8cc8bdSWilliam Juul yaffs_Object * newDir, const YCHAR * newName) 2430*0e8cc8bdSWilliam Juul { 2431*0e8cc8bdSWilliam Juul yaffs_Object *obj; 2432*0e8cc8bdSWilliam Juul yaffs_Object *existingTarget; 2433*0e8cc8bdSWilliam Juul int force = 0; 2434*0e8cc8bdSWilliam Juul 2435*0e8cc8bdSWilliam Juul #ifdef CONFIG_YAFFS_CASE_INSENSITIVE 2436*0e8cc8bdSWilliam Juul /* Special case for case insemsitive systems (eg. WinCE). 2437*0e8cc8bdSWilliam Juul * While look-up is case insensitive, the name isn't. 2438*0e8cc8bdSWilliam Juul * Therefore we might want to change x.txt to X.txt 2439*0e8cc8bdSWilliam Juul */ 2440*0e8cc8bdSWilliam Juul if (oldDir == newDir && yaffs_strcmp(oldName, newName) == 0) { 2441*0e8cc8bdSWilliam Juul force = 1; 2442*0e8cc8bdSWilliam Juul } 2443*0e8cc8bdSWilliam Juul #endif 2444*0e8cc8bdSWilliam Juul 2445*0e8cc8bdSWilliam Juul obj = yaffs_FindObjectByName(oldDir, oldName); 2446*0e8cc8bdSWilliam Juul /* Check new name to long. */ 2447*0e8cc8bdSWilliam Juul if (obj->variantType == YAFFS_OBJECT_TYPE_SYMLINK && 2448*0e8cc8bdSWilliam Juul yaffs_strlen(newName) > YAFFS_MAX_ALIAS_LENGTH) 2449*0e8cc8bdSWilliam Juul /* ENAMETOOLONG */ 2450*0e8cc8bdSWilliam Juul return YAFFS_FAIL; 2451*0e8cc8bdSWilliam Juul else if (obj->variantType != YAFFS_OBJECT_TYPE_SYMLINK && 2452*0e8cc8bdSWilliam Juul yaffs_strlen(newName) > YAFFS_MAX_NAME_LENGTH) 2453*0e8cc8bdSWilliam Juul /* ENAMETOOLONG */ 2454*0e8cc8bdSWilliam Juul return YAFFS_FAIL; 2455*0e8cc8bdSWilliam Juul 2456*0e8cc8bdSWilliam Juul if (obj && obj->renameAllowed) { 2457*0e8cc8bdSWilliam Juul 2458*0e8cc8bdSWilliam Juul /* Now do the handling for an existing target, if there is one */ 2459*0e8cc8bdSWilliam Juul 2460*0e8cc8bdSWilliam Juul existingTarget = yaffs_FindObjectByName(newDir, newName); 2461*0e8cc8bdSWilliam Juul if (existingTarget && 2462*0e8cc8bdSWilliam Juul existingTarget->variantType == YAFFS_OBJECT_TYPE_DIRECTORY && 2463*0e8cc8bdSWilliam Juul !list_empty(&existingTarget->variant.directoryVariant.children)) { 2464*0e8cc8bdSWilliam Juul /* There is a target that is a non-empty directory, so we fail */ 2465*0e8cc8bdSWilliam Juul return YAFFS_FAIL; /* EEXIST or ENOTEMPTY */ 2466*0e8cc8bdSWilliam Juul } else if (existingTarget && existingTarget != obj) { 2467*0e8cc8bdSWilliam Juul /* Nuke the target first, using shadowing, 2468*0e8cc8bdSWilliam Juul * but only if it isn't the same object 2469*0e8cc8bdSWilliam Juul */ 2470*0e8cc8bdSWilliam Juul yaffs_ChangeObjectName(obj, newDir, newName, force, 2471*0e8cc8bdSWilliam Juul existingTarget->objectId); 2472*0e8cc8bdSWilliam Juul yaffs_UnlinkObject(existingTarget); 2473*0e8cc8bdSWilliam Juul } 2474*0e8cc8bdSWilliam Juul 2475*0e8cc8bdSWilliam Juul return yaffs_ChangeObjectName(obj, newDir, newName, 1, 0); 2476*0e8cc8bdSWilliam Juul } 2477*0e8cc8bdSWilliam Juul return YAFFS_FAIL; 2478*0e8cc8bdSWilliam Juul } 2479*0e8cc8bdSWilliam Juul 2480*0e8cc8bdSWilliam Juul /*------------------------- Block Management and Page Allocation ----------------*/ 2481*0e8cc8bdSWilliam Juul 2482*0e8cc8bdSWilliam Juul static int yaffs_InitialiseBlocks(yaffs_Device * dev) 2483*0e8cc8bdSWilliam Juul { 2484*0e8cc8bdSWilliam Juul int nBlocks = dev->internalEndBlock - dev->internalStartBlock + 1; 2485*0e8cc8bdSWilliam Juul 2486*0e8cc8bdSWilliam Juul dev->blockInfo = NULL; 2487*0e8cc8bdSWilliam Juul dev->chunkBits = NULL; 2488*0e8cc8bdSWilliam Juul 2489*0e8cc8bdSWilliam Juul dev->allocationBlock = -1; /* force it to get a new one */ 2490*0e8cc8bdSWilliam Juul 2491*0e8cc8bdSWilliam Juul /* If the first allocation strategy fails, thry the alternate one */ 2492*0e8cc8bdSWilliam Juul dev->blockInfo = YMALLOC(nBlocks * sizeof(yaffs_BlockInfo)); 2493*0e8cc8bdSWilliam Juul if(!dev->blockInfo){ 2494*0e8cc8bdSWilliam Juul dev->blockInfo = YMALLOC_ALT(nBlocks * sizeof(yaffs_BlockInfo)); 2495*0e8cc8bdSWilliam Juul dev->blockInfoAlt = 1; 2496*0e8cc8bdSWilliam Juul } 2497*0e8cc8bdSWilliam Juul else 2498*0e8cc8bdSWilliam Juul dev->blockInfoAlt = 0; 2499*0e8cc8bdSWilliam Juul 2500*0e8cc8bdSWilliam Juul if(dev->blockInfo){ 2501*0e8cc8bdSWilliam Juul 2502*0e8cc8bdSWilliam Juul /* Set up dynamic blockinfo stuff. */ 2503*0e8cc8bdSWilliam Juul dev->chunkBitmapStride = (dev->nChunksPerBlock + 7) / 8; /* round up bytes */ 2504*0e8cc8bdSWilliam Juul dev->chunkBits = YMALLOC(dev->chunkBitmapStride * nBlocks); 2505*0e8cc8bdSWilliam Juul if(!dev->chunkBits){ 2506*0e8cc8bdSWilliam Juul dev->chunkBits = YMALLOC_ALT(dev->chunkBitmapStride * nBlocks); 2507*0e8cc8bdSWilliam Juul dev->chunkBitsAlt = 1; 2508*0e8cc8bdSWilliam Juul } 2509*0e8cc8bdSWilliam Juul else 2510*0e8cc8bdSWilliam Juul dev->chunkBitsAlt = 0; 2511*0e8cc8bdSWilliam Juul } 2512*0e8cc8bdSWilliam Juul 2513*0e8cc8bdSWilliam Juul if (dev->blockInfo && dev->chunkBits) { 2514*0e8cc8bdSWilliam Juul memset(dev->blockInfo, 0, nBlocks * sizeof(yaffs_BlockInfo)); 2515*0e8cc8bdSWilliam Juul memset(dev->chunkBits, 0, dev->chunkBitmapStride * nBlocks); 2516*0e8cc8bdSWilliam Juul return YAFFS_OK; 2517*0e8cc8bdSWilliam Juul } 2518*0e8cc8bdSWilliam Juul 2519*0e8cc8bdSWilliam Juul return YAFFS_FAIL; 2520*0e8cc8bdSWilliam Juul 2521*0e8cc8bdSWilliam Juul } 2522*0e8cc8bdSWilliam Juul 2523*0e8cc8bdSWilliam Juul static void yaffs_DeinitialiseBlocks(yaffs_Device * dev) 2524*0e8cc8bdSWilliam Juul { 2525*0e8cc8bdSWilliam Juul if(dev->blockInfoAlt && dev->blockInfo) 2526*0e8cc8bdSWilliam Juul YFREE_ALT(dev->blockInfo); 2527*0e8cc8bdSWilliam Juul else if(dev->blockInfo) 2528*0e8cc8bdSWilliam Juul YFREE(dev->blockInfo); 2529*0e8cc8bdSWilliam Juul 2530*0e8cc8bdSWilliam Juul dev->blockInfoAlt = 0; 2531*0e8cc8bdSWilliam Juul 2532*0e8cc8bdSWilliam Juul dev->blockInfo = NULL; 2533*0e8cc8bdSWilliam Juul 2534*0e8cc8bdSWilliam Juul if(dev->chunkBitsAlt && dev->chunkBits) 2535*0e8cc8bdSWilliam Juul YFREE_ALT(dev->chunkBits); 2536*0e8cc8bdSWilliam Juul else if(dev->chunkBits) 2537*0e8cc8bdSWilliam Juul YFREE(dev->chunkBits); 2538*0e8cc8bdSWilliam Juul dev->chunkBitsAlt = 0; 2539*0e8cc8bdSWilliam Juul dev->chunkBits = NULL; 2540*0e8cc8bdSWilliam Juul } 2541*0e8cc8bdSWilliam Juul 2542*0e8cc8bdSWilliam Juul static int yaffs_BlockNotDisqualifiedFromGC(yaffs_Device * dev, 2543*0e8cc8bdSWilliam Juul yaffs_BlockInfo * bi) 2544*0e8cc8bdSWilliam Juul { 2545*0e8cc8bdSWilliam Juul int i; 2546*0e8cc8bdSWilliam Juul __u32 seq; 2547*0e8cc8bdSWilliam Juul yaffs_BlockInfo *b; 2548*0e8cc8bdSWilliam Juul 2549*0e8cc8bdSWilliam Juul if (!dev->isYaffs2) 2550*0e8cc8bdSWilliam Juul return 1; /* disqualification only applies to yaffs2. */ 2551*0e8cc8bdSWilliam Juul 2552*0e8cc8bdSWilliam Juul if (!bi->hasShrinkHeader) 2553*0e8cc8bdSWilliam Juul return 1; /* can gc */ 2554*0e8cc8bdSWilliam Juul 2555*0e8cc8bdSWilliam Juul /* Find the oldest dirty sequence number if we don't know it and save it 2556*0e8cc8bdSWilliam Juul * so we don't have to keep recomputing it. 2557*0e8cc8bdSWilliam Juul */ 2558*0e8cc8bdSWilliam Juul if (!dev->oldestDirtySequence) { 2559*0e8cc8bdSWilliam Juul seq = dev->sequenceNumber; 2560*0e8cc8bdSWilliam Juul 2561*0e8cc8bdSWilliam Juul for (i = dev->internalStartBlock; i <= dev->internalEndBlock; 2562*0e8cc8bdSWilliam Juul i++) { 2563*0e8cc8bdSWilliam Juul b = yaffs_GetBlockInfo(dev, i); 2564*0e8cc8bdSWilliam Juul if (b->blockState == YAFFS_BLOCK_STATE_FULL && 2565*0e8cc8bdSWilliam Juul (b->pagesInUse - b->softDeletions) < 2566*0e8cc8bdSWilliam Juul dev->nChunksPerBlock && b->sequenceNumber < seq) { 2567*0e8cc8bdSWilliam Juul seq = b->sequenceNumber; 2568*0e8cc8bdSWilliam Juul } 2569*0e8cc8bdSWilliam Juul } 2570*0e8cc8bdSWilliam Juul dev->oldestDirtySequence = seq; 2571*0e8cc8bdSWilliam Juul } 2572*0e8cc8bdSWilliam Juul 2573*0e8cc8bdSWilliam Juul /* Can't do gc of this block if there are any blocks older than this one that have 2574*0e8cc8bdSWilliam Juul * discarded pages. 2575*0e8cc8bdSWilliam Juul */ 2576*0e8cc8bdSWilliam Juul return (bi->sequenceNumber <= dev->oldestDirtySequence); 2577*0e8cc8bdSWilliam Juul 2578*0e8cc8bdSWilliam Juul } 2579*0e8cc8bdSWilliam Juul 2580*0e8cc8bdSWilliam Juul /* FindDiretiestBlock is used to select the dirtiest block (or close enough) 2581*0e8cc8bdSWilliam Juul * for garbage collection. 2582*0e8cc8bdSWilliam Juul */ 2583*0e8cc8bdSWilliam Juul 2584*0e8cc8bdSWilliam Juul static int yaffs_FindBlockForGarbageCollection(yaffs_Device * dev, 2585*0e8cc8bdSWilliam Juul int aggressive) 2586*0e8cc8bdSWilliam Juul { 2587*0e8cc8bdSWilliam Juul 2588*0e8cc8bdSWilliam Juul int b = dev->currentDirtyChecker; 2589*0e8cc8bdSWilliam Juul 2590*0e8cc8bdSWilliam Juul int i; 2591*0e8cc8bdSWilliam Juul int iterations; 2592*0e8cc8bdSWilliam Juul int dirtiest = -1; 2593*0e8cc8bdSWilliam Juul int pagesInUse = 0; 2594*0e8cc8bdSWilliam Juul int prioritised=0; 2595*0e8cc8bdSWilliam Juul yaffs_BlockInfo *bi; 2596*0e8cc8bdSWilliam Juul int pendingPrioritisedExist = 0; 2597*0e8cc8bdSWilliam Juul 2598*0e8cc8bdSWilliam Juul /* First let's see if we need to grab a prioritised block */ 2599*0e8cc8bdSWilliam Juul if(dev->hasPendingPrioritisedGCs){ 2600*0e8cc8bdSWilliam Juul for(i = dev->internalStartBlock; i < dev->internalEndBlock && !prioritised; i++){ 2601*0e8cc8bdSWilliam Juul 2602*0e8cc8bdSWilliam Juul bi = yaffs_GetBlockInfo(dev, i); 2603*0e8cc8bdSWilliam Juul //yaffs_VerifyBlock(dev,bi,i); 2604*0e8cc8bdSWilliam Juul 2605*0e8cc8bdSWilliam Juul if(bi->gcPrioritise) { 2606*0e8cc8bdSWilliam Juul pendingPrioritisedExist = 1; 2607*0e8cc8bdSWilliam Juul if(bi->blockState == YAFFS_BLOCK_STATE_FULL && 2608*0e8cc8bdSWilliam Juul yaffs_BlockNotDisqualifiedFromGC(dev, bi)){ 2609*0e8cc8bdSWilliam Juul pagesInUse = (bi->pagesInUse - bi->softDeletions); 2610*0e8cc8bdSWilliam Juul dirtiest = i; 2611*0e8cc8bdSWilliam Juul prioritised = 1; 2612*0e8cc8bdSWilliam Juul aggressive = 1; /* Fool the non-aggressive skip logiv below */ 2613*0e8cc8bdSWilliam Juul } 2614*0e8cc8bdSWilliam Juul } 2615*0e8cc8bdSWilliam Juul } 2616*0e8cc8bdSWilliam Juul 2617*0e8cc8bdSWilliam Juul if(!pendingPrioritisedExist) /* None found, so we can clear this */ 2618*0e8cc8bdSWilliam Juul dev->hasPendingPrioritisedGCs = 0; 2619*0e8cc8bdSWilliam Juul } 2620*0e8cc8bdSWilliam Juul 2621*0e8cc8bdSWilliam Juul /* If we're doing aggressive GC then we are happy to take a less-dirty block, and 2622*0e8cc8bdSWilliam Juul * search harder. 2623*0e8cc8bdSWilliam Juul * else (we're doing a leasurely gc), then we only bother to do this if the 2624*0e8cc8bdSWilliam Juul * block has only a few pages in use. 2625*0e8cc8bdSWilliam Juul */ 2626*0e8cc8bdSWilliam Juul 2627*0e8cc8bdSWilliam Juul dev->nonAggressiveSkip--; 2628*0e8cc8bdSWilliam Juul 2629*0e8cc8bdSWilliam Juul if (!aggressive && (dev->nonAggressiveSkip > 0)) { 2630*0e8cc8bdSWilliam Juul return -1; 2631*0e8cc8bdSWilliam Juul } 2632*0e8cc8bdSWilliam Juul 2633*0e8cc8bdSWilliam Juul if(!prioritised) 2634*0e8cc8bdSWilliam Juul pagesInUse = 2635*0e8cc8bdSWilliam Juul (aggressive) ? dev->nChunksPerBlock : YAFFS_PASSIVE_GC_CHUNKS + 1; 2636*0e8cc8bdSWilliam Juul 2637*0e8cc8bdSWilliam Juul if (aggressive) { 2638*0e8cc8bdSWilliam Juul iterations = 2639*0e8cc8bdSWilliam Juul dev->internalEndBlock - dev->internalStartBlock + 1; 2640*0e8cc8bdSWilliam Juul } else { 2641*0e8cc8bdSWilliam Juul iterations = 2642*0e8cc8bdSWilliam Juul dev->internalEndBlock - dev->internalStartBlock + 1; 2643*0e8cc8bdSWilliam Juul iterations = iterations / 16; 2644*0e8cc8bdSWilliam Juul if (iterations > 200) { 2645*0e8cc8bdSWilliam Juul iterations = 200; 2646*0e8cc8bdSWilliam Juul } 2647*0e8cc8bdSWilliam Juul } 2648*0e8cc8bdSWilliam Juul 2649*0e8cc8bdSWilliam Juul for (i = 0; i <= iterations && pagesInUse > 0 && !prioritised; i++) { 2650*0e8cc8bdSWilliam Juul b++; 2651*0e8cc8bdSWilliam Juul if (b < dev->internalStartBlock || b > dev->internalEndBlock) { 2652*0e8cc8bdSWilliam Juul b = dev->internalStartBlock; 2653*0e8cc8bdSWilliam Juul } 2654*0e8cc8bdSWilliam Juul 2655*0e8cc8bdSWilliam Juul if (b < dev->internalStartBlock || b > dev->internalEndBlock) { 2656*0e8cc8bdSWilliam Juul T(YAFFS_TRACE_ERROR, 2657*0e8cc8bdSWilliam Juul (TSTR("**>> Block %d is not valid" TENDSTR), b)); 2658*0e8cc8bdSWilliam Juul YBUG(); 2659*0e8cc8bdSWilliam Juul } 2660*0e8cc8bdSWilliam Juul 2661*0e8cc8bdSWilliam Juul bi = yaffs_GetBlockInfo(dev, b); 2662*0e8cc8bdSWilliam Juul 2663*0e8cc8bdSWilliam Juul #if 0 2664*0e8cc8bdSWilliam Juul if (bi->blockState == YAFFS_BLOCK_STATE_CHECKPOINT) { 2665*0e8cc8bdSWilliam Juul dirtiest = b; 2666*0e8cc8bdSWilliam Juul pagesInUse = 0; 2667*0e8cc8bdSWilliam Juul } 2668*0e8cc8bdSWilliam Juul else 2669*0e8cc8bdSWilliam Juul #endif 2670*0e8cc8bdSWilliam Juul 2671*0e8cc8bdSWilliam Juul if (bi->blockState == YAFFS_BLOCK_STATE_FULL && 2672*0e8cc8bdSWilliam Juul (bi->pagesInUse - bi->softDeletions) < pagesInUse && 2673*0e8cc8bdSWilliam Juul yaffs_BlockNotDisqualifiedFromGC(dev, bi)) { 2674*0e8cc8bdSWilliam Juul dirtiest = b; 2675*0e8cc8bdSWilliam Juul pagesInUse = (bi->pagesInUse - bi->softDeletions); 2676*0e8cc8bdSWilliam Juul } 2677*0e8cc8bdSWilliam Juul } 2678*0e8cc8bdSWilliam Juul 2679*0e8cc8bdSWilliam Juul dev->currentDirtyChecker = b; 2680*0e8cc8bdSWilliam Juul 2681*0e8cc8bdSWilliam Juul if (dirtiest > 0) { 2682*0e8cc8bdSWilliam Juul T(YAFFS_TRACE_GC, 2683*0e8cc8bdSWilliam Juul (TSTR("GC Selected block %d with %d free, prioritised:%d" TENDSTR), dirtiest, 2684*0e8cc8bdSWilliam Juul dev->nChunksPerBlock - pagesInUse,prioritised)); 2685*0e8cc8bdSWilliam Juul } 2686*0e8cc8bdSWilliam Juul 2687*0e8cc8bdSWilliam Juul dev->oldestDirtySequence = 0; 2688*0e8cc8bdSWilliam Juul 2689*0e8cc8bdSWilliam Juul if (dirtiest > 0) { 2690*0e8cc8bdSWilliam Juul dev->nonAggressiveSkip = 4; 2691*0e8cc8bdSWilliam Juul } 2692*0e8cc8bdSWilliam Juul 2693*0e8cc8bdSWilliam Juul return dirtiest; 2694*0e8cc8bdSWilliam Juul } 2695*0e8cc8bdSWilliam Juul 2696*0e8cc8bdSWilliam Juul static void yaffs_BlockBecameDirty(yaffs_Device * dev, int blockNo) 2697*0e8cc8bdSWilliam Juul { 2698*0e8cc8bdSWilliam Juul yaffs_BlockInfo *bi = yaffs_GetBlockInfo(dev, blockNo); 2699*0e8cc8bdSWilliam Juul 2700*0e8cc8bdSWilliam Juul int erasedOk = 0; 2701*0e8cc8bdSWilliam Juul 2702*0e8cc8bdSWilliam Juul /* If the block is still healthy erase it and mark as clean. 2703*0e8cc8bdSWilliam Juul * If the block has had a data failure, then retire it. 2704*0e8cc8bdSWilliam Juul */ 2705*0e8cc8bdSWilliam Juul 2706*0e8cc8bdSWilliam Juul T(YAFFS_TRACE_GC | YAFFS_TRACE_ERASE, 2707*0e8cc8bdSWilliam Juul (TSTR("yaffs_BlockBecameDirty block %d state %d %s"TENDSTR), 2708*0e8cc8bdSWilliam Juul blockNo, bi->blockState, (bi->needsRetiring) ? "needs retiring" : "")); 2709*0e8cc8bdSWilliam Juul 2710*0e8cc8bdSWilliam Juul bi->blockState = YAFFS_BLOCK_STATE_DIRTY; 2711*0e8cc8bdSWilliam Juul 2712*0e8cc8bdSWilliam Juul if (!bi->needsRetiring) { 2713*0e8cc8bdSWilliam Juul yaffs_InvalidateCheckpoint(dev); 2714*0e8cc8bdSWilliam Juul erasedOk = yaffs_EraseBlockInNAND(dev, blockNo); 2715*0e8cc8bdSWilliam Juul if (!erasedOk) { 2716*0e8cc8bdSWilliam Juul dev->nErasureFailures++; 2717*0e8cc8bdSWilliam Juul T(YAFFS_TRACE_ERROR | YAFFS_TRACE_BAD_BLOCKS, 2718*0e8cc8bdSWilliam Juul (TSTR("**>> Erasure failed %d" TENDSTR), blockNo)); 2719*0e8cc8bdSWilliam Juul } 2720*0e8cc8bdSWilliam Juul } 2721*0e8cc8bdSWilliam Juul 2722*0e8cc8bdSWilliam Juul if (erasedOk && 2723*0e8cc8bdSWilliam Juul ((yaffs_traceMask & YAFFS_TRACE_ERASE) || !yaffs_SkipVerification(dev))) { 2724*0e8cc8bdSWilliam Juul int i; 2725*0e8cc8bdSWilliam Juul for (i = 0; i < dev->nChunksPerBlock; i++) { 2726*0e8cc8bdSWilliam Juul if (!yaffs_CheckChunkErased 2727*0e8cc8bdSWilliam Juul (dev, blockNo * dev->nChunksPerBlock + i)) { 2728*0e8cc8bdSWilliam Juul T(YAFFS_TRACE_ERROR, 2729*0e8cc8bdSWilliam Juul (TSTR 2730*0e8cc8bdSWilliam Juul (">>Block %d erasure supposedly OK, but chunk %d not erased" 2731*0e8cc8bdSWilliam Juul TENDSTR), blockNo, i)); 2732*0e8cc8bdSWilliam Juul } 2733*0e8cc8bdSWilliam Juul } 2734*0e8cc8bdSWilliam Juul } 2735*0e8cc8bdSWilliam Juul 2736*0e8cc8bdSWilliam Juul if (erasedOk) { 2737*0e8cc8bdSWilliam Juul /* Clean it up... */ 2738*0e8cc8bdSWilliam Juul bi->blockState = YAFFS_BLOCK_STATE_EMPTY; 2739*0e8cc8bdSWilliam Juul dev->nErasedBlocks++; 2740*0e8cc8bdSWilliam Juul bi->pagesInUse = 0; 2741*0e8cc8bdSWilliam Juul bi->softDeletions = 0; 2742*0e8cc8bdSWilliam Juul bi->hasShrinkHeader = 0; 2743*0e8cc8bdSWilliam Juul bi->skipErasedCheck = 1; /* This is clean, so no need to check */ 2744*0e8cc8bdSWilliam Juul bi->gcPrioritise = 0; 2745*0e8cc8bdSWilliam Juul yaffs_ClearChunkBits(dev, blockNo); 2746*0e8cc8bdSWilliam Juul 2747*0e8cc8bdSWilliam Juul T(YAFFS_TRACE_ERASE, 2748*0e8cc8bdSWilliam Juul (TSTR("Erased block %d" TENDSTR), blockNo)); 2749*0e8cc8bdSWilliam Juul } else { 2750*0e8cc8bdSWilliam Juul dev->nFreeChunks -= dev->nChunksPerBlock; /* We lost a block of free space */ 2751*0e8cc8bdSWilliam Juul 2752*0e8cc8bdSWilliam Juul yaffs_RetireBlock(dev, blockNo); 2753*0e8cc8bdSWilliam Juul T(YAFFS_TRACE_ERROR | YAFFS_TRACE_BAD_BLOCKS, 2754*0e8cc8bdSWilliam Juul (TSTR("**>> Block %d retired" TENDSTR), blockNo)); 2755*0e8cc8bdSWilliam Juul } 2756*0e8cc8bdSWilliam Juul } 2757*0e8cc8bdSWilliam Juul 2758*0e8cc8bdSWilliam Juul static int yaffs_FindBlockForAllocation(yaffs_Device * dev) 2759*0e8cc8bdSWilliam Juul { 2760*0e8cc8bdSWilliam Juul int i; 2761*0e8cc8bdSWilliam Juul 2762*0e8cc8bdSWilliam Juul yaffs_BlockInfo *bi; 2763*0e8cc8bdSWilliam Juul 2764*0e8cc8bdSWilliam Juul if (dev->nErasedBlocks < 1) { 2765*0e8cc8bdSWilliam Juul /* Hoosterman we've got a problem. 2766*0e8cc8bdSWilliam Juul * Can't get space to gc 2767*0e8cc8bdSWilliam Juul */ 2768*0e8cc8bdSWilliam Juul T(YAFFS_TRACE_ERROR, 2769*0e8cc8bdSWilliam Juul (TSTR("yaffs tragedy: no more eraased blocks" TENDSTR))); 2770*0e8cc8bdSWilliam Juul 2771*0e8cc8bdSWilliam Juul return -1; 2772*0e8cc8bdSWilliam Juul } 2773*0e8cc8bdSWilliam Juul 2774*0e8cc8bdSWilliam Juul /* Find an empty block. */ 2775*0e8cc8bdSWilliam Juul 2776*0e8cc8bdSWilliam Juul for (i = dev->internalStartBlock; i <= dev->internalEndBlock; i++) { 2777*0e8cc8bdSWilliam Juul dev->allocationBlockFinder++; 2778*0e8cc8bdSWilliam Juul if (dev->allocationBlockFinder < dev->internalStartBlock 2779*0e8cc8bdSWilliam Juul || dev->allocationBlockFinder > dev->internalEndBlock) { 2780*0e8cc8bdSWilliam Juul dev->allocationBlockFinder = dev->internalStartBlock; 2781*0e8cc8bdSWilliam Juul } 2782*0e8cc8bdSWilliam Juul 2783*0e8cc8bdSWilliam Juul bi = yaffs_GetBlockInfo(dev, dev->allocationBlockFinder); 2784*0e8cc8bdSWilliam Juul 2785*0e8cc8bdSWilliam Juul if (bi->blockState == YAFFS_BLOCK_STATE_EMPTY) { 2786*0e8cc8bdSWilliam Juul bi->blockState = YAFFS_BLOCK_STATE_ALLOCATING; 2787*0e8cc8bdSWilliam Juul dev->sequenceNumber++; 2788*0e8cc8bdSWilliam Juul bi->sequenceNumber = dev->sequenceNumber; 2789*0e8cc8bdSWilliam Juul dev->nErasedBlocks--; 2790*0e8cc8bdSWilliam Juul T(YAFFS_TRACE_ALLOCATE, 2791*0e8cc8bdSWilliam Juul (TSTR("Allocated block %d, seq %d, %d left" TENDSTR), 2792*0e8cc8bdSWilliam Juul dev->allocationBlockFinder, dev->sequenceNumber, 2793*0e8cc8bdSWilliam Juul dev->nErasedBlocks)); 2794*0e8cc8bdSWilliam Juul return dev->allocationBlockFinder; 2795*0e8cc8bdSWilliam Juul } 2796*0e8cc8bdSWilliam Juul } 2797*0e8cc8bdSWilliam Juul 2798*0e8cc8bdSWilliam Juul T(YAFFS_TRACE_ALWAYS, 2799*0e8cc8bdSWilliam Juul (TSTR 2800*0e8cc8bdSWilliam Juul ("yaffs tragedy: no more eraased blocks, but there should have been %d" 2801*0e8cc8bdSWilliam Juul TENDSTR), dev->nErasedBlocks)); 2802*0e8cc8bdSWilliam Juul 2803*0e8cc8bdSWilliam Juul return -1; 2804*0e8cc8bdSWilliam Juul } 2805*0e8cc8bdSWilliam Juul 2806*0e8cc8bdSWilliam Juul 2807*0e8cc8bdSWilliam Juul // Check if there's space to allocate... 2808*0e8cc8bdSWilliam Juul // Thinks.... do we need top make this ths same as yaffs_GetFreeChunks()? 2809*0e8cc8bdSWilliam Juul static int yaffs_CheckSpaceForAllocation(yaffs_Device * dev) 2810*0e8cc8bdSWilliam Juul { 2811*0e8cc8bdSWilliam Juul int reservedChunks; 2812*0e8cc8bdSWilliam Juul int reservedBlocks = dev->nReservedBlocks; 2813*0e8cc8bdSWilliam Juul int checkpointBlocks; 2814*0e8cc8bdSWilliam Juul 2815*0e8cc8bdSWilliam Juul checkpointBlocks = dev->nCheckpointReservedBlocks - dev->blocksInCheckpoint; 2816*0e8cc8bdSWilliam Juul if(checkpointBlocks < 0) 2817*0e8cc8bdSWilliam Juul checkpointBlocks = 0; 2818*0e8cc8bdSWilliam Juul 2819*0e8cc8bdSWilliam Juul reservedChunks = ((reservedBlocks + checkpointBlocks) * dev->nChunksPerBlock); 2820*0e8cc8bdSWilliam Juul 2821*0e8cc8bdSWilliam Juul return (dev->nFreeChunks > reservedChunks); 2822*0e8cc8bdSWilliam Juul } 2823*0e8cc8bdSWilliam Juul 2824*0e8cc8bdSWilliam Juul static int yaffs_AllocateChunk(yaffs_Device * dev, int useReserve, yaffs_BlockInfo **blockUsedPtr) 2825*0e8cc8bdSWilliam Juul { 2826*0e8cc8bdSWilliam Juul int retVal; 2827*0e8cc8bdSWilliam Juul yaffs_BlockInfo *bi; 2828*0e8cc8bdSWilliam Juul 2829*0e8cc8bdSWilliam Juul if (dev->allocationBlock < 0) { 2830*0e8cc8bdSWilliam Juul /* Get next block to allocate off */ 2831*0e8cc8bdSWilliam Juul dev->allocationBlock = yaffs_FindBlockForAllocation(dev); 2832*0e8cc8bdSWilliam Juul dev->allocationPage = 0; 2833*0e8cc8bdSWilliam Juul } 2834*0e8cc8bdSWilliam Juul 2835*0e8cc8bdSWilliam Juul if (!useReserve && !yaffs_CheckSpaceForAllocation(dev)) { 2836*0e8cc8bdSWilliam Juul /* Not enough space to allocate unless we're allowed to use the reserve. */ 2837*0e8cc8bdSWilliam Juul return -1; 2838*0e8cc8bdSWilliam Juul } 2839*0e8cc8bdSWilliam Juul 2840*0e8cc8bdSWilliam Juul if (dev->nErasedBlocks < dev->nReservedBlocks 2841*0e8cc8bdSWilliam Juul && dev->allocationPage == 0) { 2842*0e8cc8bdSWilliam Juul T(YAFFS_TRACE_ALLOCATE, (TSTR("Allocating reserve" TENDSTR))); 2843*0e8cc8bdSWilliam Juul } 2844*0e8cc8bdSWilliam Juul 2845*0e8cc8bdSWilliam Juul /* Next page please.... */ 2846*0e8cc8bdSWilliam Juul if (dev->allocationBlock >= 0) { 2847*0e8cc8bdSWilliam Juul bi = yaffs_GetBlockInfo(dev, dev->allocationBlock); 2848*0e8cc8bdSWilliam Juul 2849*0e8cc8bdSWilliam Juul retVal = (dev->allocationBlock * dev->nChunksPerBlock) + 2850*0e8cc8bdSWilliam Juul dev->allocationPage; 2851*0e8cc8bdSWilliam Juul bi->pagesInUse++; 2852*0e8cc8bdSWilliam Juul yaffs_SetChunkBit(dev, dev->allocationBlock, 2853*0e8cc8bdSWilliam Juul dev->allocationPage); 2854*0e8cc8bdSWilliam Juul 2855*0e8cc8bdSWilliam Juul dev->allocationPage++; 2856*0e8cc8bdSWilliam Juul 2857*0e8cc8bdSWilliam Juul dev->nFreeChunks--; 2858*0e8cc8bdSWilliam Juul 2859*0e8cc8bdSWilliam Juul /* If the block is full set the state to full */ 2860*0e8cc8bdSWilliam Juul if (dev->allocationPage >= dev->nChunksPerBlock) { 2861*0e8cc8bdSWilliam Juul bi->blockState = YAFFS_BLOCK_STATE_FULL; 2862*0e8cc8bdSWilliam Juul dev->allocationBlock = -1; 2863*0e8cc8bdSWilliam Juul } 2864*0e8cc8bdSWilliam Juul 2865*0e8cc8bdSWilliam Juul if(blockUsedPtr) 2866*0e8cc8bdSWilliam Juul *blockUsedPtr = bi; 2867*0e8cc8bdSWilliam Juul 2868*0e8cc8bdSWilliam Juul return retVal; 2869*0e8cc8bdSWilliam Juul } 2870*0e8cc8bdSWilliam Juul 2871*0e8cc8bdSWilliam Juul T(YAFFS_TRACE_ERROR, 2872*0e8cc8bdSWilliam Juul (TSTR("!!!!!!!!! Allocator out !!!!!!!!!!!!!!!!!" TENDSTR))); 2873*0e8cc8bdSWilliam Juul 2874*0e8cc8bdSWilliam Juul return -1; 2875*0e8cc8bdSWilliam Juul } 2876*0e8cc8bdSWilliam Juul 2877*0e8cc8bdSWilliam Juul static int yaffs_GetErasedChunks(yaffs_Device * dev) 2878*0e8cc8bdSWilliam Juul { 2879*0e8cc8bdSWilliam Juul int n; 2880*0e8cc8bdSWilliam Juul 2881*0e8cc8bdSWilliam Juul n = dev->nErasedBlocks * dev->nChunksPerBlock; 2882*0e8cc8bdSWilliam Juul 2883*0e8cc8bdSWilliam Juul if (dev->allocationBlock > 0) { 2884*0e8cc8bdSWilliam Juul n += (dev->nChunksPerBlock - dev->allocationPage); 2885*0e8cc8bdSWilliam Juul } 2886*0e8cc8bdSWilliam Juul 2887*0e8cc8bdSWilliam Juul return n; 2888*0e8cc8bdSWilliam Juul 2889*0e8cc8bdSWilliam Juul } 2890*0e8cc8bdSWilliam Juul 2891*0e8cc8bdSWilliam Juul static int yaffs_GarbageCollectBlock(yaffs_Device * dev, int block) 2892*0e8cc8bdSWilliam Juul { 2893*0e8cc8bdSWilliam Juul int oldChunk; 2894*0e8cc8bdSWilliam Juul int newChunk; 2895*0e8cc8bdSWilliam Juul int chunkInBlock; 2896*0e8cc8bdSWilliam Juul int markNAND; 2897*0e8cc8bdSWilliam Juul int retVal = YAFFS_OK; 2898*0e8cc8bdSWilliam Juul int cleanups = 0; 2899*0e8cc8bdSWilliam Juul int i; 2900*0e8cc8bdSWilliam Juul int isCheckpointBlock; 2901*0e8cc8bdSWilliam Juul int matchingChunk; 2902*0e8cc8bdSWilliam Juul 2903*0e8cc8bdSWilliam Juul int chunksBefore = yaffs_GetErasedChunks(dev); 2904*0e8cc8bdSWilliam Juul int chunksAfter; 2905*0e8cc8bdSWilliam Juul 2906*0e8cc8bdSWilliam Juul yaffs_ExtendedTags tags; 2907*0e8cc8bdSWilliam Juul 2908*0e8cc8bdSWilliam Juul yaffs_BlockInfo *bi = yaffs_GetBlockInfo(dev, block); 2909*0e8cc8bdSWilliam Juul 2910*0e8cc8bdSWilliam Juul yaffs_Object *object; 2911*0e8cc8bdSWilliam Juul 2912*0e8cc8bdSWilliam Juul isCheckpointBlock = (bi->blockState == YAFFS_BLOCK_STATE_CHECKPOINT); 2913*0e8cc8bdSWilliam Juul 2914*0e8cc8bdSWilliam Juul bi->blockState = YAFFS_BLOCK_STATE_COLLECTING; 2915*0e8cc8bdSWilliam Juul 2916*0e8cc8bdSWilliam Juul T(YAFFS_TRACE_TRACING, 2917*0e8cc8bdSWilliam Juul (TSTR("Collecting block %d, in use %d, shrink %d, " TENDSTR), block, 2918*0e8cc8bdSWilliam Juul bi->pagesInUse, bi->hasShrinkHeader)); 2919*0e8cc8bdSWilliam Juul 2920*0e8cc8bdSWilliam Juul /*yaffs_VerifyFreeChunks(dev); */ 2921*0e8cc8bdSWilliam Juul 2922*0e8cc8bdSWilliam Juul bi->hasShrinkHeader = 0; /* clear the flag so that the block can erase */ 2923*0e8cc8bdSWilliam Juul 2924*0e8cc8bdSWilliam Juul /* Take off the number of soft deleted entries because 2925*0e8cc8bdSWilliam Juul * they're going to get really deleted during GC. 2926*0e8cc8bdSWilliam Juul */ 2927*0e8cc8bdSWilliam Juul dev->nFreeChunks -= bi->softDeletions; 2928*0e8cc8bdSWilliam Juul 2929*0e8cc8bdSWilliam Juul dev->isDoingGC = 1; 2930*0e8cc8bdSWilliam Juul 2931*0e8cc8bdSWilliam Juul if (isCheckpointBlock || 2932*0e8cc8bdSWilliam Juul !yaffs_StillSomeChunkBits(dev, block)) { 2933*0e8cc8bdSWilliam Juul T(YAFFS_TRACE_TRACING, 2934*0e8cc8bdSWilliam Juul (TSTR 2935*0e8cc8bdSWilliam Juul ("Collecting block %d that has no chunks in use" TENDSTR), 2936*0e8cc8bdSWilliam Juul block)); 2937*0e8cc8bdSWilliam Juul yaffs_BlockBecameDirty(dev, block); 2938*0e8cc8bdSWilliam Juul } else { 2939*0e8cc8bdSWilliam Juul 2940*0e8cc8bdSWilliam Juul __u8 *buffer = yaffs_GetTempBuffer(dev, __LINE__); 2941*0e8cc8bdSWilliam Juul 2942*0e8cc8bdSWilliam Juul yaffs_VerifyBlock(dev,bi,block); 2943*0e8cc8bdSWilliam Juul 2944*0e8cc8bdSWilliam Juul for (chunkInBlock = 0, oldChunk = block * dev->nChunksPerBlock; 2945*0e8cc8bdSWilliam Juul chunkInBlock < dev->nChunksPerBlock 2946*0e8cc8bdSWilliam Juul && yaffs_StillSomeChunkBits(dev, block); 2947*0e8cc8bdSWilliam Juul chunkInBlock++, oldChunk++) { 2948*0e8cc8bdSWilliam Juul if (yaffs_CheckChunkBit(dev, block, chunkInBlock)) { 2949*0e8cc8bdSWilliam Juul 2950*0e8cc8bdSWilliam Juul /* This page is in use and might need to be copied off */ 2951*0e8cc8bdSWilliam Juul 2952*0e8cc8bdSWilliam Juul markNAND = 1; 2953*0e8cc8bdSWilliam Juul 2954*0e8cc8bdSWilliam Juul yaffs_InitialiseTags(&tags); 2955*0e8cc8bdSWilliam Juul 2956*0e8cc8bdSWilliam Juul yaffs_ReadChunkWithTagsFromNAND(dev, oldChunk, 2957*0e8cc8bdSWilliam Juul buffer, &tags); 2958*0e8cc8bdSWilliam Juul 2959*0e8cc8bdSWilliam Juul object = 2960*0e8cc8bdSWilliam Juul yaffs_FindObjectByNumber(dev, 2961*0e8cc8bdSWilliam Juul tags.objectId); 2962*0e8cc8bdSWilliam Juul 2963*0e8cc8bdSWilliam Juul T(YAFFS_TRACE_GC_DETAIL, 2964*0e8cc8bdSWilliam Juul (TSTR 2965*0e8cc8bdSWilliam Juul ("Collecting page %d, %d %d %d " TENDSTR), 2966*0e8cc8bdSWilliam Juul chunkInBlock, tags.objectId, tags.chunkId, 2967*0e8cc8bdSWilliam Juul tags.byteCount)); 2968*0e8cc8bdSWilliam Juul 2969*0e8cc8bdSWilliam Juul if(object && !yaffs_SkipVerification(dev)){ 2970*0e8cc8bdSWilliam Juul if(tags.chunkId == 0) 2971*0e8cc8bdSWilliam Juul matchingChunk = object->chunkId; 2972*0e8cc8bdSWilliam Juul else if(object->softDeleted) 2973*0e8cc8bdSWilliam Juul matchingChunk = oldChunk; /* Defeat the test */ 2974*0e8cc8bdSWilliam Juul else 2975*0e8cc8bdSWilliam Juul matchingChunk = yaffs_FindChunkInFile(object,tags.chunkId,NULL); 2976*0e8cc8bdSWilliam Juul 2977*0e8cc8bdSWilliam Juul if(oldChunk != matchingChunk) 2978*0e8cc8bdSWilliam Juul T(YAFFS_TRACE_ERROR, 2979*0e8cc8bdSWilliam Juul (TSTR("gc: page in gc mismatch: %d %d %d %d"TENDSTR), 2980*0e8cc8bdSWilliam Juul oldChunk,matchingChunk,tags.objectId, tags.chunkId)); 2981*0e8cc8bdSWilliam Juul 2982*0e8cc8bdSWilliam Juul } 2983*0e8cc8bdSWilliam Juul 2984*0e8cc8bdSWilliam Juul if (!object) { 2985*0e8cc8bdSWilliam Juul T(YAFFS_TRACE_ERROR, 2986*0e8cc8bdSWilliam Juul (TSTR 2987*0e8cc8bdSWilliam Juul ("page %d in gc has no object: %d %d %d " 2988*0e8cc8bdSWilliam Juul TENDSTR), oldChunk, 2989*0e8cc8bdSWilliam Juul tags.objectId, tags.chunkId, tags.byteCount)); 2990*0e8cc8bdSWilliam Juul } 2991*0e8cc8bdSWilliam Juul 2992*0e8cc8bdSWilliam Juul if (object && object->deleted 2993*0e8cc8bdSWilliam Juul && tags.chunkId != 0) { 2994*0e8cc8bdSWilliam Juul /* Data chunk in a deleted file, throw it away 2995*0e8cc8bdSWilliam Juul * It's a soft deleted data chunk, 2996*0e8cc8bdSWilliam Juul * No need to copy this, just forget about it and 2997*0e8cc8bdSWilliam Juul * fix up the object. 2998*0e8cc8bdSWilliam Juul */ 2999*0e8cc8bdSWilliam Juul 3000*0e8cc8bdSWilliam Juul object->nDataChunks--; 3001*0e8cc8bdSWilliam Juul 3002*0e8cc8bdSWilliam Juul if (object->nDataChunks <= 0) { 3003*0e8cc8bdSWilliam Juul /* remeber to clean up the object */ 3004*0e8cc8bdSWilliam Juul dev->gcCleanupList[cleanups] = 3005*0e8cc8bdSWilliam Juul tags.objectId; 3006*0e8cc8bdSWilliam Juul cleanups++; 3007*0e8cc8bdSWilliam Juul } 3008*0e8cc8bdSWilliam Juul markNAND = 0; 3009*0e8cc8bdSWilliam Juul } else if (0 3010*0e8cc8bdSWilliam Juul /* Todo object && object->deleted && object->nDataChunks == 0 */ 3011*0e8cc8bdSWilliam Juul ) { 3012*0e8cc8bdSWilliam Juul /* Deleted object header with no data chunks. 3013*0e8cc8bdSWilliam Juul * Can be discarded and the file deleted. 3014*0e8cc8bdSWilliam Juul */ 3015*0e8cc8bdSWilliam Juul object->chunkId = 0; 3016*0e8cc8bdSWilliam Juul yaffs_FreeTnode(object->myDev, 3017*0e8cc8bdSWilliam Juul object->variant. 3018*0e8cc8bdSWilliam Juul fileVariant.top); 3019*0e8cc8bdSWilliam Juul object->variant.fileVariant.top = NULL; 3020*0e8cc8bdSWilliam Juul yaffs_DoGenericObjectDeletion(object); 3021*0e8cc8bdSWilliam Juul 3022*0e8cc8bdSWilliam Juul } else if (object) { 3023*0e8cc8bdSWilliam Juul /* It's either a data chunk in a live file or 3024*0e8cc8bdSWilliam Juul * an ObjectHeader, so we're interested in it. 3025*0e8cc8bdSWilliam Juul * NB Need to keep the ObjectHeaders of deleted files 3026*0e8cc8bdSWilliam Juul * until the whole file has been deleted off 3027*0e8cc8bdSWilliam Juul */ 3028*0e8cc8bdSWilliam Juul tags.serialNumber++; 3029*0e8cc8bdSWilliam Juul 3030*0e8cc8bdSWilliam Juul dev->nGCCopies++; 3031*0e8cc8bdSWilliam Juul 3032*0e8cc8bdSWilliam Juul if (tags.chunkId == 0) { 3033*0e8cc8bdSWilliam Juul /* It is an object Id, 3034*0e8cc8bdSWilliam Juul * We need to nuke the shrinkheader flags first 3035*0e8cc8bdSWilliam Juul * We no longer want the shrinkHeader flag since its work is done 3036*0e8cc8bdSWilliam Juul * and if it is left in place it will mess up scanning. 3037*0e8cc8bdSWilliam Juul * Also, clear out any shadowing stuff 3038*0e8cc8bdSWilliam Juul */ 3039*0e8cc8bdSWilliam Juul 3040*0e8cc8bdSWilliam Juul yaffs_ObjectHeader *oh; 3041*0e8cc8bdSWilliam Juul oh = (yaffs_ObjectHeader *)buffer; 3042*0e8cc8bdSWilliam Juul oh->isShrink = 0; 3043*0e8cc8bdSWilliam Juul oh->shadowsObject = -1; 3044*0e8cc8bdSWilliam Juul tags.extraShadows = 0; 3045*0e8cc8bdSWilliam Juul tags.extraIsShrinkHeader = 0; 3046*0e8cc8bdSWilliam Juul 3047*0e8cc8bdSWilliam Juul yaffs_VerifyObjectHeader(object,oh,&tags,1); 3048*0e8cc8bdSWilliam Juul } 3049*0e8cc8bdSWilliam Juul 3050*0e8cc8bdSWilliam Juul newChunk = 3051*0e8cc8bdSWilliam Juul yaffs_WriteNewChunkWithTagsToNAND(dev, buffer, &tags, 1); 3052*0e8cc8bdSWilliam Juul 3053*0e8cc8bdSWilliam Juul if (newChunk < 0) { 3054*0e8cc8bdSWilliam Juul retVal = YAFFS_FAIL; 3055*0e8cc8bdSWilliam Juul } else { 3056*0e8cc8bdSWilliam Juul 3057*0e8cc8bdSWilliam Juul /* Ok, now fix up the Tnodes etc. */ 3058*0e8cc8bdSWilliam Juul 3059*0e8cc8bdSWilliam Juul if (tags.chunkId == 0) { 3060*0e8cc8bdSWilliam Juul /* It's a header */ 3061*0e8cc8bdSWilliam Juul object->chunkId = newChunk; 3062*0e8cc8bdSWilliam Juul object->serial = tags.serialNumber; 3063*0e8cc8bdSWilliam Juul } else { 3064*0e8cc8bdSWilliam Juul /* It's a data chunk */ 3065*0e8cc8bdSWilliam Juul yaffs_PutChunkIntoFile 3066*0e8cc8bdSWilliam Juul (object, 3067*0e8cc8bdSWilliam Juul tags.chunkId, 3068*0e8cc8bdSWilliam Juul newChunk, 0); 3069*0e8cc8bdSWilliam Juul } 3070*0e8cc8bdSWilliam Juul } 3071*0e8cc8bdSWilliam Juul } 3072*0e8cc8bdSWilliam Juul 3073*0e8cc8bdSWilliam Juul yaffs_DeleteChunk(dev, oldChunk, markNAND, __LINE__); 3074*0e8cc8bdSWilliam Juul 3075*0e8cc8bdSWilliam Juul } 3076*0e8cc8bdSWilliam Juul } 3077*0e8cc8bdSWilliam Juul 3078*0e8cc8bdSWilliam Juul yaffs_ReleaseTempBuffer(dev, buffer, __LINE__); 3079*0e8cc8bdSWilliam Juul 3080*0e8cc8bdSWilliam Juul 3081*0e8cc8bdSWilliam Juul /* Do any required cleanups */ 3082*0e8cc8bdSWilliam Juul for (i = 0; i < cleanups; i++) { 3083*0e8cc8bdSWilliam Juul /* Time to delete the file too */ 3084*0e8cc8bdSWilliam Juul object = 3085*0e8cc8bdSWilliam Juul yaffs_FindObjectByNumber(dev, 3086*0e8cc8bdSWilliam Juul dev->gcCleanupList[i]); 3087*0e8cc8bdSWilliam Juul if (object) { 3088*0e8cc8bdSWilliam Juul yaffs_FreeTnode(dev, 3089*0e8cc8bdSWilliam Juul object->variant.fileVariant. 3090*0e8cc8bdSWilliam Juul top); 3091*0e8cc8bdSWilliam Juul object->variant.fileVariant.top = NULL; 3092*0e8cc8bdSWilliam Juul T(YAFFS_TRACE_GC, 3093*0e8cc8bdSWilliam Juul (TSTR 3094*0e8cc8bdSWilliam Juul ("yaffs: About to finally delete object %d" 3095*0e8cc8bdSWilliam Juul TENDSTR), object->objectId)); 3096*0e8cc8bdSWilliam Juul yaffs_DoGenericObjectDeletion(object); 3097*0e8cc8bdSWilliam Juul object->myDev->nDeletedFiles--; 3098*0e8cc8bdSWilliam Juul } 3099*0e8cc8bdSWilliam Juul 3100*0e8cc8bdSWilliam Juul } 3101*0e8cc8bdSWilliam Juul 3102*0e8cc8bdSWilliam Juul } 3103*0e8cc8bdSWilliam Juul 3104*0e8cc8bdSWilliam Juul yaffs_VerifyCollectedBlock(dev,bi,block); 3105*0e8cc8bdSWilliam Juul 3106*0e8cc8bdSWilliam Juul if (chunksBefore >= (chunksAfter = yaffs_GetErasedChunks(dev))) { 3107*0e8cc8bdSWilliam Juul T(YAFFS_TRACE_GC, 3108*0e8cc8bdSWilliam Juul (TSTR 3109*0e8cc8bdSWilliam Juul ("gc did not increase free chunks before %d after %d" 3110*0e8cc8bdSWilliam Juul TENDSTR), chunksBefore, chunksAfter)); 3111*0e8cc8bdSWilliam Juul } 3112*0e8cc8bdSWilliam Juul 3113*0e8cc8bdSWilliam Juul dev->isDoingGC = 0; 3114*0e8cc8bdSWilliam Juul 3115*0e8cc8bdSWilliam Juul return YAFFS_OK; 3116*0e8cc8bdSWilliam Juul } 3117*0e8cc8bdSWilliam Juul 3118*0e8cc8bdSWilliam Juul /* New garbage collector 3119*0e8cc8bdSWilliam Juul * If we're very low on erased blocks then we do aggressive garbage collection 3120*0e8cc8bdSWilliam Juul * otherwise we do "leasurely" garbage collection. 3121*0e8cc8bdSWilliam Juul * Aggressive gc looks further (whole array) and will accept less dirty blocks. 3122*0e8cc8bdSWilliam Juul * Passive gc only inspects smaller areas and will only accept more dirty blocks. 3123*0e8cc8bdSWilliam Juul * 3124*0e8cc8bdSWilliam Juul * The idea is to help clear out space in a more spread-out manner. 3125*0e8cc8bdSWilliam Juul * Dunno if it really does anything useful. 3126*0e8cc8bdSWilliam Juul */ 3127*0e8cc8bdSWilliam Juul static int yaffs_CheckGarbageCollection(yaffs_Device * dev) 3128*0e8cc8bdSWilliam Juul { 3129*0e8cc8bdSWilliam Juul int block; 3130*0e8cc8bdSWilliam Juul int aggressive; 3131*0e8cc8bdSWilliam Juul int gcOk = YAFFS_OK; 3132*0e8cc8bdSWilliam Juul int maxTries = 0; 3133*0e8cc8bdSWilliam Juul 3134*0e8cc8bdSWilliam Juul int checkpointBlockAdjust; 3135*0e8cc8bdSWilliam Juul 3136*0e8cc8bdSWilliam Juul if (dev->isDoingGC) { 3137*0e8cc8bdSWilliam Juul /* Bail out so we don't get recursive gc */ 3138*0e8cc8bdSWilliam Juul return YAFFS_OK; 3139*0e8cc8bdSWilliam Juul } 3140*0e8cc8bdSWilliam Juul 3141*0e8cc8bdSWilliam Juul /* This loop should pass the first time. 3142*0e8cc8bdSWilliam Juul * We'll only see looping here if the erase of the collected block fails. 3143*0e8cc8bdSWilliam Juul */ 3144*0e8cc8bdSWilliam Juul 3145*0e8cc8bdSWilliam Juul do { 3146*0e8cc8bdSWilliam Juul maxTries++; 3147*0e8cc8bdSWilliam Juul 3148*0e8cc8bdSWilliam Juul checkpointBlockAdjust = (dev->nCheckpointReservedBlocks - dev->blocksInCheckpoint); 3149*0e8cc8bdSWilliam Juul if(checkpointBlockAdjust < 0) 3150*0e8cc8bdSWilliam Juul checkpointBlockAdjust = 0; 3151*0e8cc8bdSWilliam Juul 3152*0e8cc8bdSWilliam Juul if (dev->nErasedBlocks < (dev->nReservedBlocks + checkpointBlockAdjust + 2)) { 3153*0e8cc8bdSWilliam Juul /* We need a block soon...*/ 3154*0e8cc8bdSWilliam Juul aggressive = 1; 3155*0e8cc8bdSWilliam Juul } else { 3156*0e8cc8bdSWilliam Juul /* We're in no hurry */ 3157*0e8cc8bdSWilliam Juul aggressive = 0; 3158*0e8cc8bdSWilliam Juul } 3159*0e8cc8bdSWilliam Juul 3160*0e8cc8bdSWilliam Juul block = yaffs_FindBlockForGarbageCollection(dev, aggressive); 3161*0e8cc8bdSWilliam Juul 3162*0e8cc8bdSWilliam Juul if (block > 0) { 3163*0e8cc8bdSWilliam Juul dev->garbageCollections++; 3164*0e8cc8bdSWilliam Juul if (!aggressive) { 3165*0e8cc8bdSWilliam Juul dev->passiveGarbageCollections++; 3166*0e8cc8bdSWilliam Juul } 3167*0e8cc8bdSWilliam Juul 3168*0e8cc8bdSWilliam Juul T(YAFFS_TRACE_GC, 3169*0e8cc8bdSWilliam Juul (TSTR 3170*0e8cc8bdSWilliam Juul ("yaffs: GC erasedBlocks %d aggressive %d" TENDSTR), 3171*0e8cc8bdSWilliam Juul dev->nErasedBlocks, aggressive)); 3172*0e8cc8bdSWilliam Juul 3173*0e8cc8bdSWilliam Juul gcOk = yaffs_GarbageCollectBlock(dev, block); 3174*0e8cc8bdSWilliam Juul } 3175*0e8cc8bdSWilliam Juul 3176*0e8cc8bdSWilliam Juul if (dev->nErasedBlocks < (dev->nReservedBlocks) && block > 0) { 3177*0e8cc8bdSWilliam Juul T(YAFFS_TRACE_GC, 3178*0e8cc8bdSWilliam Juul (TSTR 3179*0e8cc8bdSWilliam Juul ("yaffs: GC !!!no reclaim!!! erasedBlocks %d after try %d block %d" 3180*0e8cc8bdSWilliam Juul TENDSTR), dev->nErasedBlocks, maxTries, block)); 3181*0e8cc8bdSWilliam Juul } 3182*0e8cc8bdSWilliam Juul } while ((dev->nErasedBlocks < dev->nReservedBlocks) && (block > 0) 3183*0e8cc8bdSWilliam Juul && (maxTries < 2)); 3184*0e8cc8bdSWilliam Juul 3185*0e8cc8bdSWilliam Juul return aggressive ? gcOk : YAFFS_OK; 3186*0e8cc8bdSWilliam Juul } 3187*0e8cc8bdSWilliam Juul 3188*0e8cc8bdSWilliam Juul /*------------------------- TAGS --------------------------------*/ 3189*0e8cc8bdSWilliam Juul 3190*0e8cc8bdSWilliam Juul static int yaffs_TagsMatch(const yaffs_ExtendedTags * tags, int objectId, 3191*0e8cc8bdSWilliam Juul int chunkInObject) 3192*0e8cc8bdSWilliam Juul { 3193*0e8cc8bdSWilliam Juul return (tags->chunkId == chunkInObject && 3194*0e8cc8bdSWilliam Juul tags->objectId == objectId && !tags->chunkDeleted) ? 1 : 0; 3195*0e8cc8bdSWilliam Juul 3196*0e8cc8bdSWilliam Juul } 3197*0e8cc8bdSWilliam Juul 3198*0e8cc8bdSWilliam Juul 3199*0e8cc8bdSWilliam Juul /*-------------------- Data file manipulation -----------------*/ 3200*0e8cc8bdSWilliam Juul 3201*0e8cc8bdSWilliam Juul static int yaffs_FindChunkInFile(yaffs_Object * in, int chunkInInode, 3202*0e8cc8bdSWilliam Juul yaffs_ExtendedTags * tags) 3203*0e8cc8bdSWilliam Juul { 3204*0e8cc8bdSWilliam Juul /*Get the Tnode, then get the level 0 offset chunk offset */ 3205*0e8cc8bdSWilliam Juul yaffs_Tnode *tn; 3206*0e8cc8bdSWilliam Juul int theChunk = -1; 3207*0e8cc8bdSWilliam Juul yaffs_ExtendedTags localTags; 3208*0e8cc8bdSWilliam Juul int retVal = -1; 3209*0e8cc8bdSWilliam Juul 3210*0e8cc8bdSWilliam Juul yaffs_Device *dev = in->myDev; 3211*0e8cc8bdSWilliam Juul 3212*0e8cc8bdSWilliam Juul if (!tags) { 3213*0e8cc8bdSWilliam Juul /* Passed a NULL, so use our own tags space */ 3214*0e8cc8bdSWilliam Juul tags = &localTags; 3215*0e8cc8bdSWilliam Juul } 3216*0e8cc8bdSWilliam Juul 3217*0e8cc8bdSWilliam Juul tn = yaffs_FindLevel0Tnode(dev, &in->variant.fileVariant, chunkInInode); 3218*0e8cc8bdSWilliam Juul 3219*0e8cc8bdSWilliam Juul if (tn) { 3220*0e8cc8bdSWilliam Juul theChunk = yaffs_GetChunkGroupBase(dev,tn,chunkInInode); 3221*0e8cc8bdSWilliam Juul 3222*0e8cc8bdSWilliam Juul retVal = 3223*0e8cc8bdSWilliam Juul yaffs_FindChunkInGroup(dev, theChunk, tags, in->objectId, 3224*0e8cc8bdSWilliam Juul chunkInInode); 3225*0e8cc8bdSWilliam Juul } 3226*0e8cc8bdSWilliam Juul return retVal; 3227*0e8cc8bdSWilliam Juul } 3228*0e8cc8bdSWilliam Juul 3229*0e8cc8bdSWilliam Juul static int yaffs_FindAndDeleteChunkInFile(yaffs_Object * in, int chunkInInode, 3230*0e8cc8bdSWilliam Juul yaffs_ExtendedTags * tags) 3231*0e8cc8bdSWilliam Juul { 3232*0e8cc8bdSWilliam Juul /* Get the Tnode, then get the level 0 offset chunk offset */ 3233*0e8cc8bdSWilliam Juul yaffs_Tnode *tn; 3234*0e8cc8bdSWilliam Juul int theChunk = -1; 3235*0e8cc8bdSWilliam Juul yaffs_ExtendedTags localTags; 3236*0e8cc8bdSWilliam Juul 3237*0e8cc8bdSWilliam Juul yaffs_Device *dev = in->myDev; 3238*0e8cc8bdSWilliam Juul int retVal = -1; 3239*0e8cc8bdSWilliam Juul 3240*0e8cc8bdSWilliam Juul if (!tags) { 3241*0e8cc8bdSWilliam Juul /* Passed a NULL, so use our own tags space */ 3242*0e8cc8bdSWilliam Juul tags = &localTags; 3243*0e8cc8bdSWilliam Juul } 3244*0e8cc8bdSWilliam Juul 3245*0e8cc8bdSWilliam Juul tn = yaffs_FindLevel0Tnode(dev, &in->variant.fileVariant, chunkInInode); 3246*0e8cc8bdSWilliam Juul 3247*0e8cc8bdSWilliam Juul if (tn) { 3248*0e8cc8bdSWilliam Juul 3249*0e8cc8bdSWilliam Juul theChunk = yaffs_GetChunkGroupBase(dev,tn,chunkInInode); 3250*0e8cc8bdSWilliam Juul 3251*0e8cc8bdSWilliam Juul retVal = 3252*0e8cc8bdSWilliam Juul yaffs_FindChunkInGroup(dev, theChunk, tags, in->objectId, 3253*0e8cc8bdSWilliam Juul chunkInInode); 3254*0e8cc8bdSWilliam Juul 3255*0e8cc8bdSWilliam Juul /* Delete the entry in the filestructure (if found) */ 3256*0e8cc8bdSWilliam Juul if (retVal != -1) { 3257*0e8cc8bdSWilliam Juul yaffs_PutLevel0Tnode(dev,tn,chunkInInode,0); 3258*0e8cc8bdSWilliam Juul } 3259*0e8cc8bdSWilliam Juul } else { 3260*0e8cc8bdSWilliam Juul /*T(("No level 0 found for %d\n", chunkInInode)); */ 3261*0e8cc8bdSWilliam Juul } 3262*0e8cc8bdSWilliam Juul 3263*0e8cc8bdSWilliam Juul if (retVal == -1) { 3264*0e8cc8bdSWilliam Juul /* T(("Could not find %d to delete\n",chunkInInode)); */ 3265*0e8cc8bdSWilliam Juul } 3266*0e8cc8bdSWilliam Juul return retVal; 3267*0e8cc8bdSWilliam Juul } 3268*0e8cc8bdSWilliam Juul 3269*0e8cc8bdSWilliam Juul #ifdef YAFFS_PARANOID 3270*0e8cc8bdSWilliam Juul 3271*0e8cc8bdSWilliam Juul static int yaffs_CheckFileSanity(yaffs_Object * in) 3272*0e8cc8bdSWilliam Juul { 3273*0e8cc8bdSWilliam Juul int chunk; 3274*0e8cc8bdSWilliam Juul int nChunks; 3275*0e8cc8bdSWilliam Juul int fSize; 3276*0e8cc8bdSWilliam Juul int failed = 0; 3277*0e8cc8bdSWilliam Juul int objId; 3278*0e8cc8bdSWilliam Juul yaffs_Tnode *tn; 3279*0e8cc8bdSWilliam Juul yaffs_Tags localTags; 3280*0e8cc8bdSWilliam Juul yaffs_Tags *tags = &localTags; 3281*0e8cc8bdSWilliam Juul int theChunk; 3282*0e8cc8bdSWilliam Juul int chunkDeleted; 3283*0e8cc8bdSWilliam Juul 3284*0e8cc8bdSWilliam Juul if (in->variantType != YAFFS_OBJECT_TYPE_FILE) { 3285*0e8cc8bdSWilliam Juul /* T(("Object not a file\n")); */ 3286*0e8cc8bdSWilliam Juul return YAFFS_FAIL; 3287*0e8cc8bdSWilliam Juul } 3288*0e8cc8bdSWilliam Juul 3289*0e8cc8bdSWilliam Juul objId = in->objectId; 3290*0e8cc8bdSWilliam Juul fSize = in->variant.fileVariant.fileSize; 3291*0e8cc8bdSWilliam Juul nChunks = 3292*0e8cc8bdSWilliam Juul (fSize + in->myDev->nDataBytesPerChunk - 1) / in->myDev->nDataBytesPerChunk; 3293*0e8cc8bdSWilliam Juul 3294*0e8cc8bdSWilliam Juul for (chunk = 1; chunk <= nChunks; chunk++) { 3295*0e8cc8bdSWilliam Juul tn = yaffs_FindLevel0Tnode(in->myDev, &in->variant.fileVariant, 3296*0e8cc8bdSWilliam Juul chunk); 3297*0e8cc8bdSWilliam Juul 3298*0e8cc8bdSWilliam Juul if (tn) { 3299*0e8cc8bdSWilliam Juul 3300*0e8cc8bdSWilliam Juul theChunk = yaffs_GetChunkGroupBase(dev,tn,chunk); 3301*0e8cc8bdSWilliam Juul 3302*0e8cc8bdSWilliam Juul if (yaffs_CheckChunkBits 3303*0e8cc8bdSWilliam Juul (dev, theChunk / dev->nChunksPerBlock, 3304*0e8cc8bdSWilliam Juul theChunk % dev->nChunksPerBlock)) { 3305*0e8cc8bdSWilliam Juul 3306*0e8cc8bdSWilliam Juul yaffs_ReadChunkTagsFromNAND(in->myDev, theChunk, 3307*0e8cc8bdSWilliam Juul tags, 3308*0e8cc8bdSWilliam Juul &chunkDeleted); 3309*0e8cc8bdSWilliam Juul if (yaffs_TagsMatch 3310*0e8cc8bdSWilliam Juul (tags, in->objectId, chunk, chunkDeleted)) { 3311*0e8cc8bdSWilliam Juul /* found it; */ 3312*0e8cc8bdSWilliam Juul 3313*0e8cc8bdSWilliam Juul } 3314*0e8cc8bdSWilliam Juul } else { 3315*0e8cc8bdSWilliam Juul 3316*0e8cc8bdSWilliam Juul failed = 1; 3317*0e8cc8bdSWilliam Juul } 3318*0e8cc8bdSWilliam Juul 3319*0e8cc8bdSWilliam Juul } else { 3320*0e8cc8bdSWilliam Juul /* T(("No level 0 found for %d\n", chunk)); */ 3321*0e8cc8bdSWilliam Juul } 3322*0e8cc8bdSWilliam Juul } 3323*0e8cc8bdSWilliam Juul 3324*0e8cc8bdSWilliam Juul return failed ? YAFFS_FAIL : YAFFS_OK; 3325*0e8cc8bdSWilliam Juul } 3326*0e8cc8bdSWilliam Juul 3327*0e8cc8bdSWilliam Juul #endif 3328*0e8cc8bdSWilliam Juul 3329*0e8cc8bdSWilliam Juul static int yaffs_PutChunkIntoFile(yaffs_Object * in, int chunkInInode, 3330*0e8cc8bdSWilliam Juul int chunkInNAND, int inScan) 3331*0e8cc8bdSWilliam Juul { 3332*0e8cc8bdSWilliam Juul /* NB inScan is zero unless scanning. 3333*0e8cc8bdSWilliam Juul * For forward scanning, inScan is > 0; 3334*0e8cc8bdSWilliam Juul * for backward scanning inScan is < 0 3335*0e8cc8bdSWilliam Juul */ 3336*0e8cc8bdSWilliam Juul 3337*0e8cc8bdSWilliam Juul yaffs_Tnode *tn; 3338*0e8cc8bdSWilliam Juul yaffs_Device *dev = in->myDev; 3339*0e8cc8bdSWilliam Juul int existingChunk; 3340*0e8cc8bdSWilliam Juul yaffs_ExtendedTags existingTags; 3341*0e8cc8bdSWilliam Juul yaffs_ExtendedTags newTags; 3342*0e8cc8bdSWilliam Juul unsigned existingSerial, newSerial; 3343*0e8cc8bdSWilliam Juul 3344*0e8cc8bdSWilliam Juul if (in->variantType != YAFFS_OBJECT_TYPE_FILE) { 3345*0e8cc8bdSWilliam Juul /* Just ignore an attempt at putting a chunk into a non-file during scanning 3346*0e8cc8bdSWilliam Juul * If it is not during Scanning then something went wrong! 3347*0e8cc8bdSWilliam Juul */ 3348*0e8cc8bdSWilliam Juul if (!inScan) { 3349*0e8cc8bdSWilliam Juul T(YAFFS_TRACE_ERROR, 3350*0e8cc8bdSWilliam Juul (TSTR 3351*0e8cc8bdSWilliam Juul ("yaffs tragedy:attempt to put data chunk into a non-file" 3352*0e8cc8bdSWilliam Juul TENDSTR))); 3353*0e8cc8bdSWilliam Juul YBUG(); 3354*0e8cc8bdSWilliam Juul } 3355*0e8cc8bdSWilliam Juul 3356*0e8cc8bdSWilliam Juul yaffs_DeleteChunk(dev, chunkInNAND, 1, __LINE__); 3357*0e8cc8bdSWilliam Juul return YAFFS_OK; 3358*0e8cc8bdSWilliam Juul } 3359*0e8cc8bdSWilliam Juul 3360*0e8cc8bdSWilliam Juul tn = yaffs_AddOrFindLevel0Tnode(dev, 3361*0e8cc8bdSWilliam Juul &in->variant.fileVariant, 3362*0e8cc8bdSWilliam Juul chunkInInode, 3363*0e8cc8bdSWilliam Juul NULL); 3364*0e8cc8bdSWilliam Juul if (!tn) { 3365*0e8cc8bdSWilliam Juul return YAFFS_FAIL; 3366*0e8cc8bdSWilliam Juul } 3367*0e8cc8bdSWilliam Juul 3368*0e8cc8bdSWilliam Juul existingChunk = yaffs_GetChunkGroupBase(dev,tn,chunkInInode); 3369*0e8cc8bdSWilliam Juul 3370*0e8cc8bdSWilliam Juul if (inScan != 0) { 3371*0e8cc8bdSWilliam Juul /* If we're scanning then we need to test for duplicates 3372*0e8cc8bdSWilliam Juul * NB This does not need to be efficient since it should only ever 3373*0e8cc8bdSWilliam Juul * happen when the power fails during a write, then only one 3374*0e8cc8bdSWilliam Juul * chunk should ever be affected. 3375*0e8cc8bdSWilliam Juul * 3376*0e8cc8bdSWilliam Juul * Correction for YAFFS2: This could happen quite a lot and we need to think about efficiency! TODO 3377*0e8cc8bdSWilliam Juul * Update: For backward scanning we don't need to re-read tags so this is quite cheap. 3378*0e8cc8bdSWilliam Juul */ 3379*0e8cc8bdSWilliam Juul 3380*0e8cc8bdSWilliam Juul if (existingChunk != 0) { 3381*0e8cc8bdSWilliam Juul /* NB Right now existing chunk will not be real chunkId if the device >= 32MB 3382*0e8cc8bdSWilliam Juul * thus we have to do a FindChunkInFile to get the real chunk id. 3383*0e8cc8bdSWilliam Juul * 3384*0e8cc8bdSWilliam Juul * We have a duplicate now we need to decide which one to use: 3385*0e8cc8bdSWilliam Juul * 3386*0e8cc8bdSWilliam Juul * Backwards scanning YAFFS2: The old one is what we use, dump the new one. 3387*0e8cc8bdSWilliam Juul * Forward scanning YAFFS2: The new one is what we use, dump the old one. 3388*0e8cc8bdSWilliam Juul * YAFFS1: Get both sets of tags and compare serial numbers. 3389*0e8cc8bdSWilliam Juul */ 3390*0e8cc8bdSWilliam Juul 3391*0e8cc8bdSWilliam Juul if (inScan > 0) { 3392*0e8cc8bdSWilliam Juul /* Only do this for forward scanning */ 3393*0e8cc8bdSWilliam Juul yaffs_ReadChunkWithTagsFromNAND(dev, 3394*0e8cc8bdSWilliam Juul chunkInNAND, 3395*0e8cc8bdSWilliam Juul NULL, &newTags); 3396*0e8cc8bdSWilliam Juul 3397*0e8cc8bdSWilliam Juul /* Do a proper find */ 3398*0e8cc8bdSWilliam Juul existingChunk = 3399*0e8cc8bdSWilliam Juul yaffs_FindChunkInFile(in, chunkInInode, 3400*0e8cc8bdSWilliam Juul &existingTags); 3401*0e8cc8bdSWilliam Juul } 3402*0e8cc8bdSWilliam Juul 3403*0e8cc8bdSWilliam Juul if (existingChunk <= 0) { 3404*0e8cc8bdSWilliam Juul /*Hoosterman - how did this happen? */ 3405*0e8cc8bdSWilliam Juul 3406*0e8cc8bdSWilliam Juul T(YAFFS_TRACE_ERROR, 3407*0e8cc8bdSWilliam Juul (TSTR 3408*0e8cc8bdSWilliam Juul ("yaffs tragedy: existing chunk < 0 in scan" 3409*0e8cc8bdSWilliam Juul TENDSTR))); 3410*0e8cc8bdSWilliam Juul 3411*0e8cc8bdSWilliam Juul } 3412*0e8cc8bdSWilliam Juul 3413*0e8cc8bdSWilliam Juul /* NB The deleted flags should be false, otherwise the chunks will 3414*0e8cc8bdSWilliam Juul * not be loaded during a scan 3415*0e8cc8bdSWilliam Juul */ 3416*0e8cc8bdSWilliam Juul 3417*0e8cc8bdSWilliam Juul newSerial = newTags.serialNumber; 3418*0e8cc8bdSWilliam Juul existingSerial = existingTags.serialNumber; 3419*0e8cc8bdSWilliam Juul 3420*0e8cc8bdSWilliam Juul if ((inScan > 0) && 3421*0e8cc8bdSWilliam Juul (in->myDev->isYaffs2 || 3422*0e8cc8bdSWilliam Juul existingChunk <= 0 || 3423*0e8cc8bdSWilliam Juul ((existingSerial + 1) & 3) == newSerial)) { 3424*0e8cc8bdSWilliam Juul /* Forward scanning. 3425*0e8cc8bdSWilliam Juul * Use new 3426*0e8cc8bdSWilliam Juul * Delete the old one and drop through to update the tnode 3427*0e8cc8bdSWilliam Juul */ 3428*0e8cc8bdSWilliam Juul yaffs_DeleteChunk(dev, existingChunk, 1, 3429*0e8cc8bdSWilliam Juul __LINE__); 3430*0e8cc8bdSWilliam Juul } else { 3431*0e8cc8bdSWilliam Juul /* Backward scanning or we want to use the existing one 3432*0e8cc8bdSWilliam Juul * Use existing. 3433*0e8cc8bdSWilliam Juul * Delete the new one and return early so that the tnode isn't changed 3434*0e8cc8bdSWilliam Juul */ 3435*0e8cc8bdSWilliam Juul yaffs_DeleteChunk(dev, chunkInNAND, 1, 3436*0e8cc8bdSWilliam Juul __LINE__); 3437*0e8cc8bdSWilliam Juul return YAFFS_OK; 3438*0e8cc8bdSWilliam Juul } 3439*0e8cc8bdSWilliam Juul } 3440*0e8cc8bdSWilliam Juul 3441*0e8cc8bdSWilliam Juul } 3442*0e8cc8bdSWilliam Juul 3443*0e8cc8bdSWilliam Juul if (existingChunk == 0) { 3444*0e8cc8bdSWilliam Juul in->nDataChunks++; 3445*0e8cc8bdSWilliam Juul } 3446*0e8cc8bdSWilliam Juul 3447*0e8cc8bdSWilliam Juul yaffs_PutLevel0Tnode(dev,tn,chunkInInode,chunkInNAND); 3448*0e8cc8bdSWilliam Juul 3449*0e8cc8bdSWilliam Juul return YAFFS_OK; 3450*0e8cc8bdSWilliam Juul } 3451*0e8cc8bdSWilliam Juul 3452*0e8cc8bdSWilliam Juul static int yaffs_ReadChunkDataFromObject(yaffs_Object * in, int chunkInInode, 3453*0e8cc8bdSWilliam Juul __u8 * buffer) 3454*0e8cc8bdSWilliam Juul { 3455*0e8cc8bdSWilliam Juul int chunkInNAND = yaffs_FindChunkInFile(in, chunkInInode, NULL); 3456*0e8cc8bdSWilliam Juul 3457*0e8cc8bdSWilliam Juul if (chunkInNAND >= 0) { 3458*0e8cc8bdSWilliam Juul return yaffs_ReadChunkWithTagsFromNAND(in->myDev, chunkInNAND, 3459*0e8cc8bdSWilliam Juul buffer,NULL); 3460*0e8cc8bdSWilliam Juul } else { 3461*0e8cc8bdSWilliam Juul T(YAFFS_TRACE_NANDACCESS, 3462*0e8cc8bdSWilliam Juul (TSTR("Chunk %d not found zero instead" TENDSTR), 3463*0e8cc8bdSWilliam Juul chunkInNAND)); 3464*0e8cc8bdSWilliam Juul /* get sane (zero) data if you read a hole */ 3465*0e8cc8bdSWilliam Juul memset(buffer, 0, in->myDev->nDataBytesPerChunk); 3466*0e8cc8bdSWilliam Juul return 0; 3467*0e8cc8bdSWilliam Juul } 3468*0e8cc8bdSWilliam Juul 3469*0e8cc8bdSWilliam Juul } 3470*0e8cc8bdSWilliam Juul 3471*0e8cc8bdSWilliam Juul void yaffs_DeleteChunk(yaffs_Device * dev, int chunkId, int markNAND, int lyn) 3472*0e8cc8bdSWilliam Juul { 3473*0e8cc8bdSWilliam Juul int block; 3474*0e8cc8bdSWilliam Juul int page; 3475*0e8cc8bdSWilliam Juul yaffs_ExtendedTags tags; 3476*0e8cc8bdSWilliam Juul yaffs_BlockInfo *bi; 3477*0e8cc8bdSWilliam Juul 3478*0e8cc8bdSWilliam Juul if (chunkId <= 0) 3479*0e8cc8bdSWilliam Juul return; 3480*0e8cc8bdSWilliam Juul 3481*0e8cc8bdSWilliam Juul 3482*0e8cc8bdSWilliam Juul dev->nDeletions++; 3483*0e8cc8bdSWilliam Juul block = chunkId / dev->nChunksPerBlock; 3484*0e8cc8bdSWilliam Juul page = chunkId % dev->nChunksPerBlock; 3485*0e8cc8bdSWilliam Juul 3486*0e8cc8bdSWilliam Juul 3487*0e8cc8bdSWilliam Juul if(!yaffs_CheckChunkBit(dev,block,page)) 3488*0e8cc8bdSWilliam Juul T(YAFFS_TRACE_VERIFY, 3489*0e8cc8bdSWilliam Juul (TSTR("Deleting invalid chunk %d"TENDSTR), 3490*0e8cc8bdSWilliam Juul chunkId)); 3491*0e8cc8bdSWilliam Juul 3492*0e8cc8bdSWilliam Juul bi = yaffs_GetBlockInfo(dev, block); 3493*0e8cc8bdSWilliam Juul 3494*0e8cc8bdSWilliam Juul T(YAFFS_TRACE_DELETION, 3495*0e8cc8bdSWilliam Juul (TSTR("line %d delete of chunk %d" TENDSTR), lyn, chunkId)); 3496*0e8cc8bdSWilliam Juul 3497*0e8cc8bdSWilliam Juul if (markNAND && 3498*0e8cc8bdSWilliam Juul bi->blockState != YAFFS_BLOCK_STATE_COLLECTING && !dev->isYaffs2) { 3499*0e8cc8bdSWilliam Juul 3500*0e8cc8bdSWilliam Juul yaffs_InitialiseTags(&tags); 3501*0e8cc8bdSWilliam Juul 3502*0e8cc8bdSWilliam Juul tags.chunkDeleted = 1; 3503*0e8cc8bdSWilliam Juul 3504*0e8cc8bdSWilliam Juul yaffs_WriteChunkWithTagsToNAND(dev, chunkId, NULL, &tags); 3505*0e8cc8bdSWilliam Juul yaffs_HandleUpdateChunk(dev, chunkId, &tags); 3506*0e8cc8bdSWilliam Juul } else { 3507*0e8cc8bdSWilliam Juul dev->nUnmarkedDeletions++; 3508*0e8cc8bdSWilliam Juul } 3509*0e8cc8bdSWilliam Juul 3510*0e8cc8bdSWilliam Juul /* Pull out of the management area. 3511*0e8cc8bdSWilliam Juul * If the whole block became dirty, this will kick off an erasure. 3512*0e8cc8bdSWilliam Juul */ 3513*0e8cc8bdSWilliam Juul if (bi->blockState == YAFFS_BLOCK_STATE_ALLOCATING || 3514*0e8cc8bdSWilliam Juul bi->blockState == YAFFS_BLOCK_STATE_FULL || 3515*0e8cc8bdSWilliam Juul bi->blockState == YAFFS_BLOCK_STATE_NEEDS_SCANNING || 3516*0e8cc8bdSWilliam Juul bi->blockState == YAFFS_BLOCK_STATE_COLLECTING) { 3517*0e8cc8bdSWilliam Juul dev->nFreeChunks++; 3518*0e8cc8bdSWilliam Juul 3519*0e8cc8bdSWilliam Juul yaffs_ClearChunkBit(dev, block, page); 3520*0e8cc8bdSWilliam Juul 3521*0e8cc8bdSWilliam Juul bi->pagesInUse--; 3522*0e8cc8bdSWilliam Juul 3523*0e8cc8bdSWilliam Juul if (bi->pagesInUse == 0 && 3524*0e8cc8bdSWilliam Juul !bi->hasShrinkHeader && 3525*0e8cc8bdSWilliam Juul bi->blockState != YAFFS_BLOCK_STATE_ALLOCATING && 3526*0e8cc8bdSWilliam Juul bi->blockState != YAFFS_BLOCK_STATE_NEEDS_SCANNING) { 3527*0e8cc8bdSWilliam Juul yaffs_BlockBecameDirty(dev, block); 3528*0e8cc8bdSWilliam Juul } 3529*0e8cc8bdSWilliam Juul 3530*0e8cc8bdSWilliam Juul } else { 3531*0e8cc8bdSWilliam Juul /* T(("Bad news deleting chunk %d\n",chunkId)); */ 3532*0e8cc8bdSWilliam Juul } 3533*0e8cc8bdSWilliam Juul 3534*0e8cc8bdSWilliam Juul } 3535*0e8cc8bdSWilliam Juul 3536*0e8cc8bdSWilliam Juul static int yaffs_WriteChunkDataToObject(yaffs_Object * in, int chunkInInode, 3537*0e8cc8bdSWilliam Juul const __u8 * buffer, int nBytes, 3538*0e8cc8bdSWilliam Juul int useReserve) 3539*0e8cc8bdSWilliam Juul { 3540*0e8cc8bdSWilliam Juul /* Find old chunk Need to do this to get serial number 3541*0e8cc8bdSWilliam Juul * Write new one and patch into tree. 3542*0e8cc8bdSWilliam Juul * Invalidate old tags. 3543*0e8cc8bdSWilliam Juul */ 3544*0e8cc8bdSWilliam Juul 3545*0e8cc8bdSWilliam Juul int prevChunkId; 3546*0e8cc8bdSWilliam Juul yaffs_ExtendedTags prevTags; 3547*0e8cc8bdSWilliam Juul 3548*0e8cc8bdSWilliam Juul int newChunkId; 3549*0e8cc8bdSWilliam Juul yaffs_ExtendedTags newTags; 3550*0e8cc8bdSWilliam Juul 3551*0e8cc8bdSWilliam Juul yaffs_Device *dev = in->myDev; 3552*0e8cc8bdSWilliam Juul 3553*0e8cc8bdSWilliam Juul yaffs_CheckGarbageCollection(dev); 3554*0e8cc8bdSWilliam Juul 3555*0e8cc8bdSWilliam Juul /* Get the previous chunk at this location in the file if it exists */ 3556*0e8cc8bdSWilliam Juul prevChunkId = yaffs_FindChunkInFile(in, chunkInInode, &prevTags); 3557*0e8cc8bdSWilliam Juul 3558*0e8cc8bdSWilliam Juul /* Set up new tags */ 3559*0e8cc8bdSWilliam Juul yaffs_InitialiseTags(&newTags); 3560*0e8cc8bdSWilliam Juul 3561*0e8cc8bdSWilliam Juul newTags.chunkId = chunkInInode; 3562*0e8cc8bdSWilliam Juul newTags.objectId = in->objectId; 3563*0e8cc8bdSWilliam Juul newTags.serialNumber = 3564*0e8cc8bdSWilliam Juul (prevChunkId >= 0) ? prevTags.serialNumber + 1 : 1; 3565*0e8cc8bdSWilliam Juul newTags.byteCount = nBytes; 3566*0e8cc8bdSWilliam Juul 3567*0e8cc8bdSWilliam Juul newChunkId = 3568*0e8cc8bdSWilliam Juul yaffs_WriteNewChunkWithTagsToNAND(dev, buffer, &newTags, 3569*0e8cc8bdSWilliam Juul useReserve); 3570*0e8cc8bdSWilliam Juul 3571*0e8cc8bdSWilliam Juul if (newChunkId >= 0) { 3572*0e8cc8bdSWilliam Juul yaffs_PutChunkIntoFile(in, chunkInInode, newChunkId, 0); 3573*0e8cc8bdSWilliam Juul 3574*0e8cc8bdSWilliam Juul if (prevChunkId >= 0) { 3575*0e8cc8bdSWilliam Juul yaffs_DeleteChunk(dev, prevChunkId, 1, __LINE__); 3576*0e8cc8bdSWilliam Juul 3577*0e8cc8bdSWilliam Juul } 3578*0e8cc8bdSWilliam Juul 3579*0e8cc8bdSWilliam Juul yaffs_CheckFileSanity(in); 3580*0e8cc8bdSWilliam Juul } 3581*0e8cc8bdSWilliam Juul return newChunkId; 3582*0e8cc8bdSWilliam Juul 3583*0e8cc8bdSWilliam Juul } 3584*0e8cc8bdSWilliam Juul 3585*0e8cc8bdSWilliam Juul /* UpdateObjectHeader updates the header on NAND for an object. 3586*0e8cc8bdSWilliam Juul * If name is not NULL, then that new name is used. 3587*0e8cc8bdSWilliam Juul */ 3588*0e8cc8bdSWilliam Juul int yaffs_UpdateObjectHeader(yaffs_Object * in, const YCHAR * name, int force, 3589*0e8cc8bdSWilliam Juul int isShrink, int shadows) 3590*0e8cc8bdSWilliam Juul { 3591*0e8cc8bdSWilliam Juul 3592*0e8cc8bdSWilliam Juul yaffs_BlockInfo *bi; 3593*0e8cc8bdSWilliam Juul 3594*0e8cc8bdSWilliam Juul yaffs_Device *dev = in->myDev; 3595*0e8cc8bdSWilliam Juul 3596*0e8cc8bdSWilliam Juul int prevChunkId; 3597*0e8cc8bdSWilliam Juul int retVal = 0; 3598*0e8cc8bdSWilliam Juul int result = 0; 3599*0e8cc8bdSWilliam Juul 3600*0e8cc8bdSWilliam Juul int newChunkId; 3601*0e8cc8bdSWilliam Juul yaffs_ExtendedTags newTags; 3602*0e8cc8bdSWilliam Juul yaffs_ExtendedTags oldTags; 3603*0e8cc8bdSWilliam Juul 3604*0e8cc8bdSWilliam Juul __u8 *buffer = NULL; 3605*0e8cc8bdSWilliam Juul YCHAR oldName[YAFFS_MAX_NAME_LENGTH + 1]; 3606*0e8cc8bdSWilliam Juul 3607*0e8cc8bdSWilliam Juul yaffs_ObjectHeader *oh = NULL; 3608*0e8cc8bdSWilliam Juul 3609*0e8cc8bdSWilliam Juul yaffs_strcpy(oldName,"silly old name"); 3610*0e8cc8bdSWilliam Juul 3611*0e8cc8bdSWilliam Juul if (!in->fake || force) { 3612*0e8cc8bdSWilliam Juul 3613*0e8cc8bdSWilliam Juul yaffs_CheckGarbageCollection(dev); 3614*0e8cc8bdSWilliam Juul yaffs_CheckObjectDetailsLoaded(in); 3615*0e8cc8bdSWilliam Juul 3616*0e8cc8bdSWilliam Juul buffer = yaffs_GetTempBuffer(in->myDev, __LINE__); 3617*0e8cc8bdSWilliam Juul oh = (yaffs_ObjectHeader *) buffer; 3618*0e8cc8bdSWilliam Juul 3619*0e8cc8bdSWilliam Juul prevChunkId = in->chunkId; 3620*0e8cc8bdSWilliam Juul 3621*0e8cc8bdSWilliam Juul if (prevChunkId >= 0) { 3622*0e8cc8bdSWilliam Juul result = yaffs_ReadChunkWithTagsFromNAND(dev, prevChunkId, 3623*0e8cc8bdSWilliam Juul buffer, &oldTags); 3624*0e8cc8bdSWilliam Juul 3625*0e8cc8bdSWilliam Juul yaffs_VerifyObjectHeader(in,oh,&oldTags,0); 3626*0e8cc8bdSWilliam Juul 3627*0e8cc8bdSWilliam Juul memcpy(oldName, oh->name, sizeof(oh->name)); 3628*0e8cc8bdSWilliam Juul } 3629*0e8cc8bdSWilliam Juul 3630*0e8cc8bdSWilliam Juul memset(buffer, 0xFF, dev->nDataBytesPerChunk); 3631*0e8cc8bdSWilliam Juul 3632*0e8cc8bdSWilliam Juul oh->type = in->variantType; 3633*0e8cc8bdSWilliam Juul oh->yst_mode = in->yst_mode; 3634*0e8cc8bdSWilliam Juul oh->shadowsObject = shadows; 3635*0e8cc8bdSWilliam Juul 3636*0e8cc8bdSWilliam Juul #ifdef CONFIG_YAFFS_WINCE 3637*0e8cc8bdSWilliam Juul oh->win_atime[0] = in->win_atime[0]; 3638*0e8cc8bdSWilliam Juul oh->win_ctime[0] = in->win_ctime[0]; 3639*0e8cc8bdSWilliam Juul oh->win_mtime[0] = in->win_mtime[0]; 3640*0e8cc8bdSWilliam Juul oh->win_atime[1] = in->win_atime[1]; 3641*0e8cc8bdSWilliam Juul oh->win_ctime[1] = in->win_ctime[1]; 3642*0e8cc8bdSWilliam Juul oh->win_mtime[1] = in->win_mtime[1]; 3643*0e8cc8bdSWilliam Juul #else 3644*0e8cc8bdSWilliam Juul oh->yst_uid = in->yst_uid; 3645*0e8cc8bdSWilliam Juul oh->yst_gid = in->yst_gid; 3646*0e8cc8bdSWilliam Juul oh->yst_atime = in->yst_atime; 3647*0e8cc8bdSWilliam Juul oh->yst_mtime = in->yst_mtime; 3648*0e8cc8bdSWilliam Juul oh->yst_ctime = in->yst_ctime; 3649*0e8cc8bdSWilliam Juul oh->yst_rdev = in->yst_rdev; 3650*0e8cc8bdSWilliam Juul #endif 3651*0e8cc8bdSWilliam Juul if (in->parent) { 3652*0e8cc8bdSWilliam Juul oh->parentObjectId = in->parent->objectId; 3653*0e8cc8bdSWilliam Juul } else { 3654*0e8cc8bdSWilliam Juul oh->parentObjectId = 0; 3655*0e8cc8bdSWilliam Juul } 3656*0e8cc8bdSWilliam Juul 3657*0e8cc8bdSWilliam Juul if (name && *name) { 3658*0e8cc8bdSWilliam Juul memset(oh->name, 0, sizeof(oh->name)); 3659*0e8cc8bdSWilliam Juul yaffs_strncpy(oh->name, name, YAFFS_MAX_NAME_LENGTH); 3660*0e8cc8bdSWilliam Juul } else if (prevChunkId>=0) { 3661*0e8cc8bdSWilliam Juul memcpy(oh->name, oldName, sizeof(oh->name)); 3662*0e8cc8bdSWilliam Juul } else { 3663*0e8cc8bdSWilliam Juul memset(oh->name, 0, sizeof(oh->name)); 3664*0e8cc8bdSWilliam Juul } 3665*0e8cc8bdSWilliam Juul 3666*0e8cc8bdSWilliam Juul oh->isShrink = isShrink; 3667*0e8cc8bdSWilliam Juul 3668*0e8cc8bdSWilliam Juul switch (in->variantType) { 3669*0e8cc8bdSWilliam Juul case YAFFS_OBJECT_TYPE_UNKNOWN: 3670*0e8cc8bdSWilliam Juul /* Should not happen */ 3671*0e8cc8bdSWilliam Juul break; 3672*0e8cc8bdSWilliam Juul case YAFFS_OBJECT_TYPE_FILE: 3673*0e8cc8bdSWilliam Juul oh->fileSize = 3674*0e8cc8bdSWilliam Juul (oh->parentObjectId == YAFFS_OBJECTID_DELETED 3675*0e8cc8bdSWilliam Juul || oh->parentObjectId == 3676*0e8cc8bdSWilliam Juul YAFFS_OBJECTID_UNLINKED) ? 0 : in->variant. 3677*0e8cc8bdSWilliam Juul fileVariant.fileSize; 3678*0e8cc8bdSWilliam Juul break; 3679*0e8cc8bdSWilliam Juul case YAFFS_OBJECT_TYPE_HARDLINK: 3680*0e8cc8bdSWilliam Juul oh->equivalentObjectId = 3681*0e8cc8bdSWilliam Juul in->variant.hardLinkVariant.equivalentObjectId; 3682*0e8cc8bdSWilliam Juul break; 3683*0e8cc8bdSWilliam Juul case YAFFS_OBJECT_TYPE_SPECIAL: 3684*0e8cc8bdSWilliam Juul /* Do nothing */ 3685*0e8cc8bdSWilliam Juul break; 3686*0e8cc8bdSWilliam Juul case YAFFS_OBJECT_TYPE_DIRECTORY: 3687*0e8cc8bdSWilliam Juul /* Do nothing */ 3688*0e8cc8bdSWilliam Juul break; 3689*0e8cc8bdSWilliam Juul case YAFFS_OBJECT_TYPE_SYMLINK: 3690*0e8cc8bdSWilliam Juul yaffs_strncpy(oh->alias, 3691*0e8cc8bdSWilliam Juul in->variant.symLinkVariant.alias, 3692*0e8cc8bdSWilliam Juul YAFFS_MAX_ALIAS_LENGTH); 3693*0e8cc8bdSWilliam Juul oh->alias[YAFFS_MAX_ALIAS_LENGTH] = 0; 3694*0e8cc8bdSWilliam Juul break; 3695*0e8cc8bdSWilliam Juul } 3696*0e8cc8bdSWilliam Juul 3697*0e8cc8bdSWilliam Juul /* Tags */ 3698*0e8cc8bdSWilliam Juul yaffs_InitialiseTags(&newTags); 3699*0e8cc8bdSWilliam Juul in->serial++; 3700*0e8cc8bdSWilliam Juul newTags.chunkId = 0; 3701*0e8cc8bdSWilliam Juul newTags.objectId = in->objectId; 3702*0e8cc8bdSWilliam Juul newTags.serialNumber = in->serial; 3703*0e8cc8bdSWilliam Juul 3704*0e8cc8bdSWilliam Juul /* Add extra info for file header */ 3705*0e8cc8bdSWilliam Juul 3706*0e8cc8bdSWilliam Juul newTags.extraHeaderInfoAvailable = 1; 3707*0e8cc8bdSWilliam Juul newTags.extraParentObjectId = oh->parentObjectId; 3708*0e8cc8bdSWilliam Juul newTags.extraFileLength = oh->fileSize; 3709*0e8cc8bdSWilliam Juul newTags.extraIsShrinkHeader = oh->isShrink; 3710*0e8cc8bdSWilliam Juul newTags.extraEquivalentObjectId = oh->equivalentObjectId; 3711*0e8cc8bdSWilliam Juul newTags.extraShadows = (oh->shadowsObject > 0) ? 1 : 0; 3712*0e8cc8bdSWilliam Juul newTags.extraObjectType = in->variantType; 3713*0e8cc8bdSWilliam Juul 3714*0e8cc8bdSWilliam Juul yaffs_VerifyObjectHeader(in,oh,&newTags,1); 3715*0e8cc8bdSWilliam Juul 3716*0e8cc8bdSWilliam Juul /* Create new chunk in NAND */ 3717*0e8cc8bdSWilliam Juul newChunkId = 3718*0e8cc8bdSWilliam Juul yaffs_WriteNewChunkWithTagsToNAND(dev, buffer, &newTags, 3719*0e8cc8bdSWilliam Juul (prevChunkId >= 0) ? 1 : 0); 3720*0e8cc8bdSWilliam Juul 3721*0e8cc8bdSWilliam Juul if (newChunkId >= 0) { 3722*0e8cc8bdSWilliam Juul 3723*0e8cc8bdSWilliam Juul in->chunkId = newChunkId; 3724*0e8cc8bdSWilliam Juul 3725*0e8cc8bdSWilliam Juul if (prevChunkId >= 0) { 3726*0e8cc8bdSWilliam Juul yaffs_DeleteChunk(dev, prevChunkId, 1, 3727*0e8cc8bdSWilliam Juul __LINE__); 3728*0e8cc8bdSWilliam Juul } 3729*0e8cc8bdSWilliam Juul 3730*0e8cc8bdSWilliam Juul if(!yaffs_ObjectHasCachedWriteData(in)) 3731*0e8cc8bdSWilliam Juul in->dirty = 0; 3732*0e8cc8bdSWilliam Juul 3733*0e8cc8bdSWilliam Juul /* If this was a shrink, then mark the block that the chunk lives on */ 3734*0e8cc8bdSWilliam Juul if (isShrink) { 3735*0e8cc8bdSWilliam Juul bi = yaffs_GetBlockInfo(in->myDev, 3736*0e8cc8bdSWilliam Juul newChunkId /in->myDev-> nChunksPerBlock); 3737*0e8cc8bdSWilliam Juul bi->hasShrinkHeader = 1; 3738*0e8cc8bdSWilliam Juul } 3739*0e8cc8bdSWilliam Juul 3740*0e8cc8bdSWilliam Juul } 3741*0e8cc8bdSWilliam Juul 3742*0e8cc8bdSWilliam Juul retVal = newChunkId; 3743*0e8cc8bdSWilliam Juul 3744*0e8cc8bdSWilliam Juul } 3745*0e8cc8bdSWilliam Juul 3746*0e8cc8bdSWilliam Juul if (buffer) 3747*0e8cc8bdSWilliam Juul yaffs_ReleaseTempBuffer(dev, buffer, __LINE__); 3748*0e8cc8bdSWilliam Juul 3749*0e8cc8bdSWilliam Juul return retVal; 3750*0e8cc8bdSWilliam Juul } 3751*0e8cc8bdSWilliam Juul 3752*0e8cc8bdSWilliam Juul /*------------------------ Short Operations Cache ---------------------------------------- 3753*0e8cc8bdSWilliam Juul * In many situations where there is no high level buffering (eg WinCE) a lot of 3754*0e8cc8bdSWilliam Juul * reads might be short sequential reads, and a lot of writes may be short 3755*0e8cc8bdSWilliam Juul * sequential writes. eg. scanning/writing a jpeg file. 3756*0e8cc8bdSWilliam Juul * In these cases, a short read/write cache can provide a huge perfomance benefit 3757*0e8cc8bdSWilliam Juul * with dumb-as-a-rock code. 3758*0e8cc8bdSWilliam Juul * In Linux, the page cache provides read buffering aand the short op cache provides write 3759*0e8cc8bdSWilliam Juul * buffering. 3760*0e8cc8bdSWilliam Juul * 3761*0e8cc8bdSWilliam Juul * There are a limited number (~10) of cache chunks per device so that we don't 3762*0e8cc8bdSWilliam Juul * need a very intelligent search. 3763*0e8cc8bdSWilliam Juul */ 3764*0e8cc8bdSWilliam Juul 3765*0e8cc8bdSWilliam Juul static int yaffs_ObjectHasCachedWriteData(yaffs_Object *obj) 3766*0e8cc8bdSWilliam Juul { 3767*0e8cc8bdSWilliam Juul yaffs_Device *dev = obj->myDev; 3768*0e8cc8bdSWilliam Juul int i; 3769*0e8cc8bdSWilliam Juul yaffs_ChunkCache *cache; 3770*0e8cc8bdSWilliam Juul int nCaches = obj->myDev->nShortOpCaches; 3771*0e8cc8bdSWilliam Juul 3772*0e8cc8bdSWilliam Juul for(i = 0; i < nCaches; i++){ 3773*0e8cc8bdSWilliam Juul cache = &dev->srCache[i]; 3774*0e8cc8bdSWilliam Juul if (cache->object == obj && 3775*0e8cc8bdSWilliam Juul cache->dirty) 3776*0e8cc8bdSWilliam Juul return 1; 3777*0e8cc8bdSWilliam Juul } 3778*0e8cc8bdSWilliam Juul 3779*0e8cc8bdSWilliam Juul return 0; 3780*0e8cc8bdSWilliam Juul } 3781*0e8cc8bdSWilliam Juul 3782*0e8cc8bdSWilliam Juul 3783*0e8cc8bdSWilliam Juul static void yaffs_FlushFilesChunkCache(yaffs_Object * obj) 3784*0e8cc8bdSWilliam Juul { 3785*0e8cc8bdSWilliam Juul yaffs_Device *dev = obj->myDev; 3786*0e8cc8bdSWilliam Juul int lowest = -99; /* Stop compiler whining. */ 3787*0e8cc8bdSWilliam Juul int i; 3788*0e8cc8bdSWilliam Juul yaffs_ChunkCache *cache; 3789*0e8cc8bdSWilliam Juul int chunkWritten = 0; 3790*0e8cc8bdSWilliam Juul int nCaches = obj->myDev->nShortOpCaches; 3791*0e8cc8bdSWilliam Juul 3792*0e8cc8bdSWilliam Juul if (nCaches > 0) { 3793*0e8cc8bdSWilliam Juul do { 3794*0e8cc8bdSWilliam Juul cache = NULL; 3795*0e8cc8bdSWilliam Juul 3796*0e8cc8bdSWilliam Juul /* Find the dirty cache for this object with the lowest chunk id. */ 3797*0e8cc8bdSWilliam Juul for (i = 0; i < nCaches; i++) { 3798*0e8cc8bdSWilliam Juul if (dev->srCache[i].object == obj && 3799*0e8cc8bdSWilliam Juul dev->srCache[i].dirty) { 3800*0e8cc8bdSWilliam Juul if (!cache 3801*0e8cc8bdSWilliam Juul || dev->srCache[i].chunkId < 3802*0e8cc8bdSWilliam Juul lowest) { 3803*0e8cc8bdSWilliam Juul cache = &dev->srCache[i]; 3804*0e8cc8bdSWilliam Juul lowest = cache->chunkId; 3805*0e8cc8bdSWilliam Juul } 3806*0e8cc8bdSWilliam Juul } 3807*0e8cc8bdSWilliam Juul } 3808*0e8cc8bdSWilliam Juul 3809*0e8cc8bdSWilliam Juul if (cache && !cache->locked) { 3810*0e8cc8bdSWilliam Juul /* Write it out and free it up */ 3811*0e8cc8bdSWilliam Juul 3812*0e8cc8bdSWilliam Juul chunkWritten = 3813*0e8cc8bdSWilliam Juul yaffs_WriteChunkDataToObject(cache->object, 3814*0e8cc8bdSWilliam Juul cache->chunkId, 3815*0e8cc8bdSWilliam Juul cache->data, 3816*0e8cc8bdSWilliam Juul cache->nBytes, 3817*0e8cc8bdSWilliam Juul 1); 3818*0e8cc8bdSWilliam Juul cache->dirty = 0; 3819*0e8cc8bdSWilliam Juul cache->object = NULL; 3820*0e8cc8bdSWilliam Juul } 3821*0e8cc8bdSWilliam Juul 3822*0e8cc8bdSWilliam Juul } while (cache && chunkWritten > 0); 3823*0e8cc8bdSWilliam Juul 3824*0e8cc8bdSWilliam Juul if (cache) { 3825*0e8cc8bdSWilliam Juul /* Hoosterman, disk full while writing cache out. */ 3826*0e8cc8bdSWilliam Juul T(YAFFS_TRACE_ERROR, 3827*0e8cc8bdSWilliam Juul (TSTR("yaffs tragedy: no space during cache write" TENDSTR))); 3828*0e8cc8bdSWilliam Juul 3829*0e8cc8bdSWilliam Juul } 3830*0e8cc8bdSWilliam Juul } 3831*0e8cc8bdSWilliam Juul 3832*0e8cc8bdSWilliam Juul } 3833*0e8cc8bdSWilliam Juul 3834*0e8cc8bdSWilliam Juul /*yaffs_FlushEntireDeviceCache(dev) 3835*0e8cc8bdSWilliam Juul * 3836*0e8cc8bdSWilliam Juul * 3837*0e8cc8bdSWilliam Juul */ 3838*0e8cc8bdSWilliam Juul 3839*0e8cc8bdSWilliam Juul void yaffs_FlushEntireDeviceCache(yaffs_Device *dev) 3840*0e8cc8bdSWilliam Juul { 3841*0e8cc8bdSWilliam Juul yaffs_Object *obj; 3842*0e8cc8bdSWilliam Juul int nCaches = dev->nShortOpCaches; 3843*0e8cc8bdSWilliam Juul int i; 3844*0e8cc8bdSWilliam Juul 3845*0e8cc8bdSWilliam Juul /* Find a dirty object in the cache and flush it... 3846*0e8cc8bdSWilliam Juul * until there are no further dirty objects. 3847*0e8cc8bdSWilliam Juul */ 3848*0e8cc8bdSWilliam Juul do { 3849*0e8cc8bdSWilliam Juul obj = NULL; 3850*0e8cc8bdSWilliam Juul for( i = 0; i < nCaches && !obj; i++) { 3851*0e8cc8bdSWilliam Juul if (dev->srCache[i].object && 3852*0e8cc8bdSWilliam Juul dev->srCache[i].dirty) 3853*0e8cc8bdSWilliam Juul obj = dev->srCache[i].object; 3854*0e8cc8bdSWilliam Juul 3855*0e8cc8bdSWilliam Juul } 3856*0e8cc8bdSWilliam Juul if(obj) 3857*0e8cc8bdSWilliam Juul yaffs_FlushFilesChunkCache(obj); 3858*0e8cc8bdSWilliam Juul 3859*0e8cc8bdSWilliam Juul } while(obj); 3860*0e8cc8bdSWilliam Juul 3861*0e8cc8bdSWilliam Juul } 3862*0e8cc8bdSWilliam Juul 3863*0e8cc8bdSWilliam Juul 3864*0e8cc8bdSWilliam Juul /* Grab us a cache chunk for use. 3865*0e8cc8bdSWilliam Juul * First look for an empty one. 3866*0e8cc8bdSWilliam Juul * Then look for the least recently used non-dirty one. 3867*0e8cc8bdSWilliam Juul * Then look for the least recently used dirty one...., flush and look again. 3868*0e8cc8bdSWilliam Juul */ 3869*0e8cc8bdSWilliam Juul static yaffs_ChunkCache *yaffs_GrabChunkCacheWorker(yaffs_Device * dev) 3870*0e8cc8bdSWilliam Juul { 3871*0e8cc8bdSWilliam Juul int i; 3872*0e8cc8bdSWilliam Juul int usage; 3873*0e8cc8bdSWilliam Juul int theOne; 3874*0e8cc8bdSWilliam Juul 3875*0e8cc8bdSWilliam Juul if (dev->nShortOpCaches > 0) { 3876*0e8cc8bdSWilliam Juul for (i = 0; i < dev->nShortOpCaches; i++) { 3877*0e8cc8bdSWilliam Juul if (!dev->srCache[i].object) 3878*0e8cc8bdSWilliam Juul return &dev->srCache[i]; 3879*0e8cc8bdSWilliam Juul } 3880*0e8cc8bdSWilliam Juul 3881*0e8cc8bdSWilliam Juul return NULL; 3882*0e8cc8bdSWilliam Juul 3883*0e8cc8bdSWilliam Juul theOne = -1; 3884*0e8cc8bdSWilliam Juul usage = 0; /* just to stop the compiler grizzling */ 3885*0e8cc8bdSWilliam Juul 3886*0e8cc8bdSWilliam Juul for (i = 0; i < dev->nShortOpCaches; i++) { 3887*0e8cc8bdSWilliam Juul if (!dev->srCache[i].dirty && 3888*0e8cc8bdSWilliam Juul ((dev->srCache[i].lastUse < usage && theOne >= 0) || 3889*0e8cc8bdSWilliam Juul theOne < 0)) { 3890*0e8cc8bdSWilliam Juul usage = dev->srCache[i].lastUse; 3891*0e8cc8bdSWilliam Juul theOne = i; 3892*0e8cc8bdSWilliam Juul } 3893*0e8cc8bdSWilliam Juul } 3894*0e8cc8bdSWilliam Juul 3895*0e8cc8bdSWilliam Juul 3896*0e8cc8bdSWilliam Juul return theOne >= 0 ? &dev->srCache[theOne] : NULL; 3897*0e8cc8bdSWilliam Juul } else { 3898*0e8cc8bdSWilliam Juul return NULL; 3899*0e8cc8bdSWilliam Juul } 3900*0e8cc8bdSWilliam Juul 3901*0e8cc8bdSWilliam Juul } 3902*0e8cc8bdSWilliam Juul 3903*0e8cc8bdSWilliam Juul static yaffs_ChunkCache *yaffs_GrabChunkCache(yaffs_Device * dev) 3904*0e8cc8bdSWilliam Juul { 3905*0e8cc8bdSWilliam Juul yaffs_ChunkCache *cache; 3906*0e8cc8bdSWilliam Juul yaffs_Object *theObj; 3907*0e8cc8bdSWilliam Juul int usage; 3908*0e8cc8bdSWilliam Juul int i; 3909*0e8cc8bdSWilliam Juul int pushout; 3910*0e8cc8bdSWilliam Juul 3911*0e8cc8bdSWilliam Juul if (dev->nShortOpCaches > 0) { 3912*0e8cc8bdSWilliam Juul /* Try find a non-dirty one... */ 3913*0e8cc8bdSWilliam Juul 3914*0e8cc8bdSWilliam Juul cache = yaffs_GrabChunkCacheWorker(dev); 3915*0e8cc8bdSWilliam Juul 3916*0e8cc8bdSWilliam Juul if (!cache) { 3917*0e8cc8bdSWilliam Juul /* They were all dirty, find the last recently used object and flush 3918*0e8cc8bdSWilliam Juul * its cache, then find again. 3919*0e8cc8bdSWilliam Juul * NB what's here is not very accurate, we actually flush the object 3920*0e8cc8bdSWilliam Juul * the last recently used page. 3921*0e8cc8bdSWilliam Juul */ 3922*0e8cc8bdSWilliam Juul 3923*0e8cc8bdSWilliam Juul /* With locking we can't assume we can use entry zero */ 3924*0e8cc8bdSWilliam Juul 3925*0e8cc8bdSWilliam Juul theObj = NULL; 3926*0e8cc8bdSWilliam Juul usage = -1; 3927*0e8cc8bdSWilliam Juul cache = NULL; 3928*0e8cc8bdSWilliam Juul pushout = -1; 3929*0e8cc8bdSWilliam Juul 3930*0e8cc8bdSWilliam Juul for (i = 0; i < dev->nShortOpCaches; i++) { 3931*0e8cc8bdSWilliam Juul if (dev->srCache[i].object && 3932*0e8cc8bdSWilliam Juul !dev->srCache[i].locked && 3933*0e8cc8bdSWilliam Juul (dev->srCache[i].lastUse < usage || !cache)) 3934*0e8cc8bdSWilliam Juul { 3935*0e8cc8bdSWilliam Juul usage = dev->srCache[i].lastUse; 3936*0e8cc8bdSWilliam Juul theObj = dev->srCache[i].object; 3937*0e8cc8bdSWilliam Juul cache = &dev->srCache[i]; 3938*0e8cc8bdSWilliam Juul pushout = i; 3939*0e8cc8bdSWilliam Juul } 3940*0e8cc8bdSWilliam Juul } 3941*0e8cc8bdSWilliam Juul 3942*0e8cc8bdSWilliam Juul if (!cache || cache->dirty) { 3943*0e8cc8bdSWilliam Juul /* Flush and try again */ 3944*0e8cc8bdSWilliam Juul yaffs_FlushFilesChunkCache(theObj); 3945*0e8cc8bdSWilliam Juul cache = yaffs_GrabChunkCacheWorker(dev); 3946*0e8cc8bdSWilliam Juul } 3947*0e8cc8bdSWilliam Juul 3948*0e8cc8bdSWilliam Juul } 3949*0e8cc8bdSWilliam Juul return cache; 3950*0e8cc8bdSWilliam Juul } else 3951*0e8cc8bdSWilliam Juul return NULL; 3952*0e8cc8bdSWilliam Juul 3953*0e8cc8bdSWilliam Juul } 3954*0e8cc8bdSWilliam Juul 3955*0e8cc8bdSWilliam Juul /* Find a cached chunk */ 3956*0e8cc8bdSWilliam Juul static yaffs_ChunkCache *yaffs_FindChunkCache(const yaffs_Object * obj, 3957*0e8cc8bdSWilliam Juul int chunkId) 3958*0e8cc8bdSWilliam Juul { 3959*0e8cc8bdSWilliam Juul yaffs_Device *dev = obj->myDev; 3960*0e8cc8bdSWilliam Juul int i; 3961*0e8cc8bdSWilliam Juul if (dev->nShortOpCaches > 0) { 3962*0e8cc8bdSWilliam Juul for (i = 0; i < dev->nShortOpCaches; i++) { 3963*0e8cc8bdSWilliam Juul if (dev->srCache[i].object == obj && 3964*0e8cc8bdSWilliam Juul dev->srCache[i].chunkId == chunkId) { 3965*0e8cc8bdSWilliam Juul dev->cacheHits++; 3966*0e8cc8bdSWilliam Juul 3967*0e8cc8bdSWilliam Juul return &dev->srCache[i]; 3968*0e8cc8bdSWilliam Juul } 3969*0e8cc8bdSWilliam Juul } 3970*0e8cc8bdSWilliam Juul } 3971*0e8cc8bdSWilliam Juul return NULL; 3972*0e8cc8bdSWilliam Juul } 3973*0e8cc8bdSWilliam Juul 3974*0e8cc8bdSWilliam Juul /* Mark the chunk for the least recently used algorithym */ 3975*0e8cc8bdSWilliam Juul static void yaffs_UseChunkCache(yaffs_Device * dev, yaffs_ChunkCache * cache, 3976*0e8cc8bdSWilliam Juul int isAWrite) 3977*0e8cc8bdSWilliam Juul { 3978*0e8cc8bdSWilliam Juul 3979*0e8cc8bdSWilliam Juul if (dev->nShortOpCaches > 0) { 3980*0e8cc8bdSWilliam Juul if (dev->srLastUse < 0 || dev->srLastUse > 100000000) { 3981*0e8cc8bdSWilliam Juul /* Reset the cache usages */ 3982*0e8cc8bdSWilliam Juul int i; 3983*0e8cc8bdSWilliam Juul for (i = 1; i < dev->nShortOpCaches; i++) { 3984*0e8cc8bdSWilliam Juul dev->srCache[i].lastUse = 0; 3985*0e8cc8bdSWilliam Juul } 3986*0e8cc8bdSWilliam Juul dev->srLastUse = 0; 3987*0e8cc8bdSWilliam Juul } 3988*0e8cc8bdSWilliam Juul 3989*0e8cc8bdSWilliam Juul dev->srLastUse++; 3990*0e8cc8bdSWilliam Juul 3991*0e8cc8bdSWilliam Juul cache->lastUse = dev->srLastUse; 3992*0e8cc8bdSWilliam Juul 3993*0e8cc8bdSWilliam Juul if (isAWrite) { 3994*0e8cc8bdSWilliam Juul cache->dirty = 1; 3995*0e8cc8bdSWilliam Juul } 3996*0e8cc8bdSWilliam Juul } 3997*0e8cc8bdSWilliam Juul } 3998*0e8cc8bdSWilliam Juul 3999*0e8cc8bdSWilliam Juul /* Invalidate a single cache page. 4000*0e8cc8bdSWilliam Juul * Do this when a whole page gets written, 4001*0e8cc8bdSWilliam Juul * ie the short cache for this page is no longer valid. 4002*0e8cc8bdSWilliam Juul */ 4003*0e8cc8bdSWilliam Juul static void yaffs_InvalidateChunkCache(yaffs_Object * object, int chunkId) 4004*0e8cc8bdSWilliam Juul { 4005*0e8cc8bdSWilliam Juul if (object->myDev->nShortOpCaches > 0) { 4006*0e8cc8bdSWilliam Juul yaffs_ChunkCache *cache = yaffs_FindChunkCache(object, chunkId); 4007*0e8cc8bdSWilliam Juul 4008*0e8cc8bdSWilliam Juul if (cache) { 4009*0e8cc8bdSWilliam Juul cache->object = NULL; 4010*0e8cc8bdSWilliam Juul } 4011*0e8cc8bdSWilliam Juul } 4012*0e8cc8bdSWilliam Juul } 4013*0e8cc8bdSWilliam Juul 4014*0e8cc8bdSWilliam Juul /* Invalidate all the cache pages associated with this object 4015*0e8cc8bdSWilliam Juul * Do this whenever ther file is deleted or resized. 4016*0e8cc8bdSWilliam Juul */ 4017*0e8cc8bdSWilliam Juul static void yaffs_InvalidateWholeChunkCache(yaffs_Object * in) 4018*0e8cc8bdSWilliam Juul { 4019*0e8cc8bdSWilliam Juul int i; 4020*0e8cc8bdSWilliam Juul yaffs_Device *dev = in->myDev; 4021*0e8cc8bdSWilliam Juul 4022*0e8cc8bdSWilliam Juul if (dev->nShortOpCaches > 0) { 4023*0e8cc8bdSWilliam Juul /* Invalidate it. */ 4024*0e8cc8bdSWilliam Juul for (i = 0; i < dev->nShortOpCaches; i++) { 4025*0e8cc8bdSWilliam Juul if (dev->srCache[i].object == in) { 4026*0e8cc8bdSWilliam Juul dev->srCache[i].object = NULL; 4027*0e8cc8bdSWilliam Juul } 4028*0e8cc8bdSWilliam Juul } 4029*0e8cc8bdSWilliam Juul } 4030*0e8cc8bdSWilliam Juul } 4031*0e8cc8bdSWilliam Juul 4032*0e8cc8bdSWilliam Juul /*--------------------- Checkpointing --------------------*/ 4033*0e8cc8bdSWilliam Juul 4034*0e8cc8bdSWilliam Juul 4035*0e8cc8bdSWilliam Juul static int yaffs_WriteCheckpointValidityMarker(yaffs_Device *dev,int head) 4036*0e8cc8bdSWilliam Juul { 4037*0e8cc8bdSWilliam Juul yaffs_CheckpointValidity cp; 4038*0e8cc8bdSWilliam Juul 4039*0e8cc8bdSWilliam Juul memset(&cp,0,sizeof(cp)); 4040*0e8cc8bdSWilliam Juul 4041*0e8cc8bdSWilliam Juul cp.structType = sizeof(cp); 4042*0e8cc8bdSWilliam Juul cp.magic = YAFFS_MAGIC; 4043*0e8cc8bdSWilliam Juul cp.version = YAFFS_CHECKPOINT_VERSION; 4044*0e8cc8bdSWilliam Juul cp.head = (head) ? 1 : 0; 4045*0e8cc8bdSWilliam Juul 4046*0e8cc8bdSWilliam Juul return (yaffs_CheckpointWrite(dev,&cp,sizeof(cp)) == sizeof(cp))? 4047*0e8cc8bdSWilliam Juul 1 : 0; 4048*0e8cc8bdSWilliam Juul } 4049*0e8cc8bdSWilliam Juul 4050*0e8cc8bdSWilliam Juul static int yaffs_ReadCheckpointValidityMarker(yaffs_Device *dev, int head) 4051*0e8cc8bdSWilliam Juul { 4052*0e8cc8bdSWilliam Juul yaffs_CheckpointValidity cp; 4053*0e8cc8bdSWilliam Juul int ok; 4054*0e8cc8bdSWilliam Juul 4055*0e8cc8bdSWilliam Juul ok = (yaffs_CheckpointRead(dev,&cp,sizeof(cp)) == sizeof(cp)); 4056*0e8cc8bdSWilliam Juul 4057*0e8cc8bdSWilliam Juul if(ok) 4058*0e8cc8bdSWilliam Juul ok = (cp.structType == sizeof(cp)) && 4059*0e8cc8bdSWilliam Juul (cp.magic == YAFFS_MAGIC) && 4060*0e8cc8bdSWilliam Juul (cp.version == YAFFS_CHECKPOINT_VERSION) && 4061*0e8cc8bdSWilliam Juul (cp.head == ((head) ? 1 : 0)); 4062*0e8cc8bdSWilliam Juul return ok ? 1 : 0; 4063*0e8cc8bdSWilliam Juul } 4064*0e8cc8bdSWilliam Juul 4065*0e8cc8bdSWilliam Juul static void yaffs_DeviceToCheckpointDevice(yaffs_CheckpointDevice *cp, 4066*0e8cc8bdSWilliam Juul yaffs_Device *dev) 4067*0e8cc8bdSWilliam Juul { 4068*0e8cc8bdSWilliam Juul cp->nErasedBlocks = dev->nErasedBlocks; 4069*0e8cc8bdSWilliam Juul cp->allocationBlock = dev->allocationBlock; 4070*0e8cc8bdSWilliam Juul cp->allocationPage = dev->allocationPage; 4071*0e8cc8bdSWilliam Juul cp->nFreeChunks = dev->nFreeChunks; 4072*0e8cc8bdSWilliam Juul 4073*0e8cc8bdSWilliam Juul cp->nDeletedFiles = dev->nDeletedFiles; 4074*0e8cc8bdSWilliam Juul cp->nUnlinkedFiles = dev->nUnlinkedFiles; 4075*0e8cc8bdSWilliam Juul cp->nBackgroundDeletions = dev->nBackgroundDeletions; 4076*0e8cc8bdSWilliam Juul cp->sequenceNumber = dev->sequenceNumber; 4077*0e8cc8bdSWilliam Juul cp->oldestDirtySequence = dev->oldestDirtySequence; 4078*0e8cc8bdSWilliam Juul 4079*0e8cc8bdSWilliam Juul } 4080*0e8cc8bdSWilliam Juul 4081*0e8cc8bdSWilliam Juul static void yaffs_CheckpointDeviceToDevice(yaffs_Device *dev, 4082*0e8cc8bdSWilliam Juul yaffs_CheckpointDevice *cp) 4083*0e8cc8bdSWilliam Juul { 4084*0e8cc8bdSWilliam Juul dev->nErasedBlocks = cp->nErasedBlocks; 4085*0e8cc8bdSWilliam Juul dev->allocationBlock = cp->allocationBlock; 4086*0e8cc8bdSWilliam Juul dev->allocationPage = cp->allocationPage; 4087*0e8cc8bdSWilliam Juul dev->nFreeChunks = cp->nFreeChunks; 4088*0e8cc8bdSWilliam Juul 4089*0e8cc8bdSWilliam Juul dev->nDeletedFiles = cp->nDeletedFiles; 4090*0e8cc8bdSWilliam Juul dev->nUnlinkedFiles = cp->nUnlinkedFiles; 4091*0e8cc8bdSWilliam Juul dev->nBackgroundDeletions = cp->nBackgroundDeletions; 4092*0e8cc8bdSWilliam Juul dev->sequenceNumber = cp->sequenceNumber; 4093*0e8cc8bdSWilliam Juul dev->oldestDirtySequence = cp->oldestDirtySequence; 4094*0e8cc8bdSWilliam Juul } 4095*0e8cc8bdSWilliam Juul 4096*0e8cc8bdSWilliam Juul 4097*0e8cc8bdSWilliam Juul static int yaffs_WriteCheckpointDevice(yaffs_Device *dev) 4098*0e8cc8bdSWilliam Juul { 4099*0e8cc8bdSWilliam Juul yaffs_CheckpointDevice cp; 4100*0e8cc8bdSWilliam Juul __u32 nBytes; 4101*0e8cc8bdSWilliam Juul __u32 nBlocks = (dev->internalEndBlock - dev->internalStartBlock + 1); 4102*0e8cc8bdSWilliam Juul 4103*0e8cc8bdSWilliam Juul int ok; 4104*0e8cc8bdSWilliam Juul 4105*0e8cc8bdSWilliam Juul /* Write device runtime values*/ 4106*0e8cc8bdSWilliam Juul yaffs_DeviceToCheckpointDevice(&cp,dev); 4107*0e8cc8bdSWilliam Juul cp.structType = sizeof(cp); 4108*0e8cc8bdSWilliam Juul 4109*0e8cc8bdSWilliam Juul ok = (yaffs_CheckpointWrite(dev,&cp,sizeof(cp)) == sizeof(cp)); 4110*0e8cc8bdSWilliam Juul 4111*0e8cc8bdSWilliam Juul /* Write block info */ 4112*0e8cc8bdSWilliam Juul if(ok) { 4113*0e8cc8bdSWilliam Juul nBytes = nBlocks * sizeof(yaffs_BlockInfo); 4114*0e8cc8bdSWilliam Juul ok = (yaffs_CheckpointWrite(dev,dev->blockInfo,nBytes) == nBytes); 4115*0e8cc8bdSWilliam Juul } 4116*0e8cc8bdSWilliam Juul 4117*0e8cc8bdSWilliam Juul /* Write chunk bits */ 4118*0e8cc8bdSWilliam Juul if(ok) { 4119*0e8cc8bdSWilliam Juul nBytes = nBlocks * dev->chunkBitmapStride; 4120*0e8cc8bdSWilliam Juul ok = (yaffs_CheckpointWrite(dev,dev->chunkBits,nBytes) == nBytes); 4121*0e8cc8bdSWilliam Juul } 4122*0e8cc8bdSWilliam Juul return ok ? 1 : 0; 4123*0e8cc8bdSWilliam Juul 4124*0e8cc8bdSWilliam Juul } 4125*0e8cc8bdSWilliam Juul 4126*0e8cc8bdSWilliam Juul static int yaffs_ReadCheckpointDevice(yaffs_Device *dev) 4127*0e8cc8bdSWilliam Juul { 4128*0e8cc8bdSWilliam Juul yaffs_CheckpointDevice cp; 4129*0e8cc8bdSWilliam Juul __u32 nBytes; 4130*0e8cc8bdSWilliam Juul __u32 nBlocks = (dev->internalEndBlock - dev->internalStartBlock + 1); 4131*0e8cc8bdSWilliam Juul 4132*0e8cc8bdSWilliam Juul int ok; 4133*0e8cc8bdSWilliam Juul 4134*0e8cc8bdSWilliam Juul ok = (yaffs_CheckpointRead(dev,&cp,sizeof(cp)) == sizeof(cp)); 4135*0e8cc8bdSWilliam Juul if(!ok) 4136*0e8cc8bdSWilliam Juul return 0; 4137*0e8cc8bdSWilliam Juul 4138*0e8cc8bdSWilliam Juul if(cp.structType != sizeof(cp)) 4139*0e8cc8bdSWilliam Juul return 0; 4140*0e8cc8bdSWilliam Juul 4141*0e8cc8bdSWilliam Juul 4142*0e8cc8bdSWilliam Juul yaffs_CheckpointDeviceToDevice(dev,&cp); 4143*0e8cc8bdSWilliam Juul 4144*0e8cc8bdSWilliam Juul nBytes = nBlocks * sizeof(yaffs_BlockInfo); 4145*0e8cc8bdSWilliam Juul 4146*0e8cc8bdSWilliam Juul ok = (yaffs_CheckpointRead(dev,dev->blockInfo,nBytes) == nBytes); 4147*0e8cc8bdSWilliam Juul 4148*0e8cc8bdSWilliam Juul if(!ok) 4149*0e8cc8bdSWilliam Juul return 0; 4150*0e8cc8bdSWilliam Juul nBytes = nBlocks * dev->chunkBitmapStride; 4151*0e8cc8bdSWilliam Juul 4152*0e8cc8bdSWilliam Juul ok = (yaffs_CheckpointRead(dev,dev->chunkBits,nBytes) == nBytes); 4153*0e8cc8bdSWilliam Juul 4154*0e8cc8bdSWilliam Juul return ok ? 1 : 0; 4155*0e8cc8bdSWilliam Juul } 4156*0e8cc8bdSWilliam Juul 4157*0e8cc8bdSWilliam Juul static void yaffs_ObjectToCheckpointObject(yaffs_CheckpointObject *cp, 4158*0e8cc8bdSWilliam Juul yaffs_Object *obj) 4159*0e8cc8bdSWilliam Juul { 4160*0e8cc8bdSWilliam Juul 4161*0e8cc8bdSWilliam Juul cp->objectId = obj->objectId; 4162*0e8cc8bdSWilliam Juul cp->parentId = (obj->parent) ? obj->parent->objectId : 0; 4163*0e8cc8bdSWilliam Juul cp->chunkId = obj->chunkId; 4164*0e8cc8bdSWilliam Juul cp->variantType = obj->variantType; 4165*0e8cc8bdSWilliam Juul cp->deleted = obj->deleted; 4166*0e8cc8bdSWilliam Juul cp->softDeleted = obj->softDeleted; 4167*0e8cc8bdSWilliam Juul cp->unlinked = obj->unlinked; 4168*0e8cc8bdSWilliam Juul cp->fake = obj->fake; 4169*0e8cc8bdSWilliam Juul cp->renameAllowed = obj->renameAllowed; 4170*0e8cc8bdSWilliam Juul cp->unlinkAllowed = obj->unlinkAllowed; 4171*0e8cc8bdSWilliam Juul cp->serial = obj->serial; 4172*0e8cc8bdSWilliam Juul cp->nDataChunks = obj->nDataChunks; 4173*0e8cc8bdSWilliam Juul 4174*0e8cc8bdSWilliam Juul if(obj->variantType == YAFFS_OBJECT_TYPE_FILE) 4175*0e8cc8bdSWilliam Juul cp->fileSizeOrEquivalentObjectId = obj->variant.fileVariant.fileSize; 4176*0e8cc8bdSWilliam Juul else if(obj->variantType == YAFFS_OBJECT_TYPE_HARDLINK) 4177*0e8cc8bdSWilliam Juul cp->fileSizeOrEquivalentObjectId = obj->variant.hardLinkVariant.equivalentObjectId; 4178*0e8cc8bdSWilliam Juul } 4179*0e8cc8bdSWilliam Juul 4180*0e8cc8bdSWilliam Juul static void yaffs_CheckpointObjectToObject( yaffs_Object *obj,yaffs_CheckpointObject *cp) 4181*0e8cc8bdSWilliam Juul { 4182*0e8cc8bdSWilliam Juul 4183*0e8cc8bdSWilliam Juul yaffs_Object *parent; 4184*0e8cc8bdSWilliam Juul 4185*0e8cc8bdSWilliam Juul obj->objectId = cp->objectId; 4186*0e8cc8bdSWilliam Juul 4187*0e8cc8bdSWilliam Juul if(cp->parentId) 4188*0e8cc8bdSWilliam Juul parent = yaffs_FindOrCreateObjectByNumber( 4189*0e8cc8bdSWilliam Juul obj->myDev, 4190*0e8cc8bdSWilliam Juul cp->parentId, 4191*0e8cc8bdSWilliam Juul YAFFS_OBJECT_TYPE_DIRECTORY); 4192*0e8cc8bdSWilliam Juul else 4193*0e8cc8bdSWilliam Juul parent = NULL; 4194*0e8cc8bdSWilliam Juul 4195*0e8cc8bdSWilliam Juul if(parent) 4196*0e8cc8bdSWilliam Juul yaffs_AddObjectToDirectory(parent, obj); 4197*0e8cc8bdSWilliam Juul 4198*0e8cc8bdSWilliam Juul obj->chunkId = cp->chunkId; 4199*0e8cc8bdSWilliam Juul obj->variantType = cp->variantType; 4200*0e8cc8bdSWilliam Juul obj->deleted = cp->deleted; 4201*0e8cc8bdSWilliam Juul obj->softDeleted = cp->softDeleted; 4202*0e8cc8bdSWilliam Juul obj->unlinked = cp->unlinked; 4203*0e8cc8bdSWilliam Juul obj->fake = cp->fake; 4204*0e8cc8bdSWilliam Juul obj->renameAllowed = cp->renameAllowed; 4205*0e8cc8bdSWilliam Juul obj->unlinkAllowed = cp->unlinkAllowed; 4206*0e8cc8bdSWilliam Juul obj->serial = cp->serial; 4207*0e8cc8bdSWilliam Juul obj->nDataChunks = cp->nDataChunks; 4208*0e8cc8bdSWilliam Juul 4209*0e8cc8bdSWilliam Juul if(obj->variantType == YAFFS_OBJECT_TYPE_FILE) 4210*0e8cc8bdSWilliam Juul obj->variant.fileVariant.fileSize = cp->fileSizeOrEquivalentObjectId; 4211*0e8cc8bdSWilliam Juul else if(obj->variantType == YAFFS_OBJECT_TYPE_HARDLINK) 4212*0e8cc8bdSWilliam Juul obj->variant.hardLinkVariant.equivalentObjectId = cp->fileSizeOrEquivalentObjectId; 4213*0e8cc8bdSWilliam Juul 4214*0e8cc8bdSWilliam Juul if(obj->objectId >= YAFFS_NOBJECT_BUCKETS) 4215*0e8cc8bdSWilliam Juul obj->lazyLoaded = 1; 4216*0e8cc8bdSWilliam Juul } 4217*0e8cc8bdSWilliam Juul 4218*0e8cc8bdSWilliam Juul 4219*0e8cc8bdSWilliam Juul 4220*0e8cc8bdSWilliam Juul static int yaffs_CheckpointTnodeWorker(yaffs_Object * in, yaffs_Tnode * tn, 4221*0e8cc8bdSWilliam Juul __u32 level, int chunkOffset) 4222*0e8cc8bdSWilliam Juul { 4223*0e8cc8bdSWilliam Juul int i; 4224*0e8cc8bdSWilliam Juul yaffs_Device *dev = in->myDev; 4225*0e8cc8bdSWilliam Juul int ok = 1; 4226*0e8cc8bdSWilliam Juul int nTnodeBytes = (dev->tnodeWidth * YAFFS_NTNODES_LEVEL0)/8; 4227*0e8cc8bdSWilliam Juul 4228*0e8cc8bdSWilliam Juul if (tn) { 4229*0e8cc8bdSWilliam Juul if (level > 0) { 4230*0e8cc8bdSWilliam Juul 4231*0e8cc8bdSWilliam Juul for (i = 0; i < YAFFS_NTNODES_INTERNAL && ok; i++){ 4232*0e8cc8bdSWilliam Juul if (tn->internal[i]) { 4233*0e8cc8bdSWilliam Juul ok = yaffs_CheckpointTnodeWorker(in, 4234*0e8cc8bdSWilliam Juul tn->internal[i], 4235*0e8cc8bdSWilliam Juul level - 1, 4236*0e8cc8bdSWilliam Juul (chunkOffset<<YAFFS_TNODES_INTERNAL_BITS) + i); 4237*0e8cc8bdSWilliam Juul } 4238*0e8cc8bdSWilliam Juul } 4239*0e8cc8bdSWilliam Juul } else if (level == 0) { 4240*0e8cc8bdSWilliam Juul __u32 baseOffset = chunkOffset << YAFFS_TNODES_LEVEL0_BITS; 4241*0e8cc8bdSWilliam Juul /* printf("write tnode at %d\n",baseOffset); */ 4242*0e8cc8bdSWilliam Juul ok = (yaffs_CheckpointWrite(dev,&baseOffset,sizeof(baseOffset)) == sizeof(baseOffset)); 4243*0e8cc8bdSWilliam Juul if(ok) 4244*0e8cc8bdSWilliam Juul ok = (yaffs_CheckpointWrite(dev,tn,nTnodeBytes) == nTnodeBytes); 4245*0e8cc8bdSWilliam Juul } 4246*0e8cc8bdSWilliam Juul } 4247*0e8cc8bdSWilliam Juul 4248*0e8cc8bdSWilliam Juul return ok; 4249*0e8cc8bdSWilliam Juul 4250*0e8cc8bdSWilliam Juul } 4251*0e8cc8bdSWilliam Juul 4252*0e8cc8bdSWilliam Juul static int yaffs_WriteCheckpointTnodes(yaffs_Object *obj) 4253*0e8cc8bdSWilliam Juul { 4254*0e8cc8bdSWilliam Juul __u32 endMarker = ~0; 4255*0e8cc8bdSWilliam Juul int ok = 1; 4256*0e8cc8bdSWilliam Juul 4257*0e8cc8bdSWilliam Juul if(obj->variantType == YAFFS_OBJECT_TYPE_FILE){ 4258*0e8cc8bdSWilliam Juul ok = yaffs_CheckpointTnodeWorker(obj, 4259*0e8cc8bdSWilliam Juul obj->variant.fileVariant.top, 4260*0e8cc8bdSWilliam Juul obj->variant.fileVariant.topLevel, 4261*0e8cc8bdSWilliam Juul 0); 4262*0e8cc8bdSWilliam Juul if(ok) 4263*0e8cc8bdSWilliam Juul ok = (yaffs_CheckpointWrite(obj->myDev,&endMarker,sizeof(endMarker)) == 4264*0e8cc8bdSWilliam Juul sizeof(endMarker)); 4265*0e8cc8bdSWilliam Juul } 4266*0e8cc8bdSWilliam Juul 4267*0e8cc8bdSWilliam Juul return ok ? 1 : 0; 4268*0e8cc8bdSWilliam Juul } 4269*0e8cc8bdSWilliam Juul 4270*0e8cc8bdSWilliam Juul static int yaffs_ReadCheckpointTnodes(yaffs_Object *obj) 4271*0e8cc8bdSWilliam Juul { 4272*0e8cc8bdSWilliam Juul __u32 baseChunk; 4273*0e8cc8bdSWilliam Juul int ok = 1; 4274*0e8cc8bdSWilliam Juul yaffs_Device *dev = obj->myDev; 4275*0e8cc8bdSWilliam Juul yaffs_FileStructure *fileStructPtr = &obj->variant.fileVariant; 4276*0e8cc8bdSWilliam Juul yaffs_Tnode *tn; 4277*0e8cc8bdSWilliam Juul int nread = 0; 4278*0e8cc8bdSWilliam Juul 4279*0e8cc8bdSWilliam Juul ok = (yaffs_CheckpointRead(dev,&baseChunk,sizeof(baseChunk)) == sizeof(baseChunk)); 4280*0e8cc8bdSWilliam Juul 4281*0e8cc8bdSWilliam Juul while(ok && (~baseChunk)){ 4282*0e8cc8bdSWilliam Juul nread++; 4283*0e8cc8bdSWilliam Juul /* Read level 0 tnode */ 4284*0e8cc8bdSWilliam Juul 4285*0e8cc8bdSWilliam Juul 4286*0e8cc8bdSWilliam Juul /* printf("read tnode at %d\n",baseChunk); */ 4287*0e8cc8bdSWilliam Juul tn = yaffs_GetTnodeRaw(dev); 4288*0e8cc8bdSWilliam Juul if(tn) 4289*0e8cc8bdSWilliam Juul ok = (yaffs_CheckpointRead(dev,tn,(dev->tnodeWidth * YAFFS_NTNODES_LEVEL0)/8) == 4290*0e8cc8bdSWilliam Juul (dev->tnodeWidth * YAFFS_NTNODES_LEVEL0)/8); 4291*0e8cc8bdSWilliam Juul else 4292*0e8cc8bdSWilliam Juul ok = 0; 4293*0e8cc8bdSWilliam Juul 4294*0e8cc8bdSWilliam Juul if(tn && ok){ 4295*0e8cc8bdSWilliam Juul ok = yaffs_AddOrFindLevel0Tnode(dev, 4296*0e8cc8bdSWilliam Juul fileStructPtr, 4297*0e8cc8bdSWilliam Juul baseChunk, 4298*0e8cc8bdSWilliam Juul tn) ? 1 : 0; 4299*0e8cc8bdSWilliam Juul 4300*0e8cc8bdSWilliam Juul } 4301*0e8cc8bdSWilliam Juul 4302*0e8cc8bdSWilliam Juul if(ok) 4303*0e8cc8bdSWilliam Juul ok = (yaffs_CheckpointRead(dev,&baseChunk,sizeof(baseChunk)) == sizeof(baseChunk)); 4304*0e8cc8bdSWilliam Juul 4305*0e8cc8bdSWilliam Juul } 4306*0e8cc8bdSWilliam Juul 4307*0e8cc8bdSWilliam Juul T(YAFFS_TRACE_CHECKPOINT,( 4308*0e8cc8bdSWilliam Juul TSTR("Checkpoint read tnodes %d records, last %d. ok %d" TENDSTR), 4309*0e8cc8bdSWilliam Juul nread,baseChunk,ok)); 4310*0e8cc8bdSWilliam Juul 4311*0e8cc8bdSWilliam Juul return ok ? 1 : 0; 4312*0e8cc8bdSWilliam Juul } 4313*0e8cc8bdSWilliam Juul 4314*0e8cc8bdSWilliam Juul 4315*0e8cc8bdSWilliam Juul static int yaffs_WriteCheckpointObjects(yaffs_Device *dev) 4316*0e8cc8bdSWilliam Juul { 4317*0e8cc8bdSWilliam Juul yaffs_Object *obj; 4318*0e8cc8bdSWilliam Juul yaffs_CheckpointObject cp; 4319*0e8cc8bdSWilliam Juul int i; 4320*0e8cc8bdSWilliam Juul int ok = 1; 4321*0e8cc8bdSWilliam Juul struct list_head *lh; 4322*0e8cc8bdSWilliam Juul 4323*0e8cc8bdSWilliam Juul 4324*0e8cc8bdSWilliam Juul /* Iterate through the objects in each hash entry, 4325*0e8cc8bdSWilliam Juul * dumping them to the checkpointing stream. 4326*0e8cc8bdSWilliam Juul */ 4327*0e8cc8bdSWilliam Juul 4328*0e8cc8bdSWilliam Juul for(i = 0; ok && i < YAFFS_NOBJECT_BUCKETS; i++){ 4329*0e8cc8bdSWilliam Juul list_for_each(lh, &dev->objectBucket[i].list) { 4330*0e8cc8bdSWilliam Juul if (lh) { 4331*0e8cc8bdSWilliam Juul obj = list_entry(lh, yaffs_Object, hashLink); 4332*0e8cc8bdSWilliam Juul if (!obj->deferedFree) { 4333*0e8cc8bdSWilliam Juul yaffs_ObjectToCheckpointObject(&cp,obj); 4334*0e8cc8bdSWilliam Juul cp.structType = sizeof(cp); 4335*0e8cc8bdSWilliam Juul 4336*0e8cc8bdSWilliam Juul T(YAFFS_TRACE_CHECKPOINT,( 4337*0e8cc8bdSWilliam Juul TSTR("Checkpoint write object %d parent %d type %d chunk %d obj addr %x" TENDSTR), 4338*0e8cc8bdSWilliam Juul cp.objectId,cp.parentId,cp.variantType,cp.chunkId,(unsigned) obj)); 4339*0e8cc8bdSWilliam Juul 4340*0e8cc8bdSWilliam Juul ok = (yaffs_CheckpointWrite(dev,&cp,sizeof(cp)) == sizeof(cp)); 4341*0e8cc8bdSWilliam Juul 4342*0e8cc8bdSWilliam Juul if(ok && obj->variantType == YAFFS_OBJECT_TYPE_FILE){ 4343*0e8cc8bdSWilliam Juul ok = yaffs_WriteCheckpointTnodes(obj); 4344*0e8cc8bdSWilliam Juul } 4345*0e8cc8bdSWilliam Juul } 4346*0e8cc8bdSWilliam Juul } 4347*0e8cc8bdSWilliam Juul } 4348*0e8cc8bdSWilliam Juul } 4349*0e8cc8bdSWilliam Juul 4350*0e8cc8bdSWilliam Juul /* Dump end of list */ 4351*0e8cc8bdSWilliam Juul memset(&cp,0xFF,sizeof(yaffs_CheckpointObject)); 4352*0e8cc8bdSWilliam Juul cp.structType = sizeof(cp); 4353*0e8cc8bdSWilliam Juul 4354*0e8cc8bdSWilliam Juul if(ok) 4355*0e8cc8bdSWilliam Juul ok = (yaffs_CheckpointWrite(dev,&cp,sizeof(cp)) == sizeof(cp)); 4356*0e8cc8bdSWilliam Juul 4357*0e8cc8bdSWilliam Juul return ok ? 1 : 0; 4358*0e8cc8bdSWilliam Juul } 4359*0e8cc8bdSWilliam Juul 4360*0e8cc8bdSWilliam Juul static int yaffs_ReadCheckpointObjects(yaffs_Device *dev) 4361*0e8cc8bdSWilliam Juul { 4362*0e8cc8bdSWilliam Juul yaffs_Object *obj; 4363*0e8cc8bdSWilliam Juul yaffs_CheckpointObject cp; 4364*0e8cc8bdSWilliam Juul int ok = 1; 4365*0e8cc8bdSWilliam Juul int done = 0; 4366*0e8cc8bdSWilliam Juul yaffs_Object *hardList = NULL; 4367*0e8cc8bdSWilliam Juul 4368*0e8cc8bdSWilliam Juul while(ok && !done) { 4369*0e8cc8bdSWilliam Juul ok = (yaffs_CheckpointRead(dev,&cp,sizeof(cp)) == sizeof(cp)); 4370*0e8cc8bdSWilliam Juul if(cp.structType != sizeof(cp)) { 4371*0e8cc8bdSWilliam Juul T(YAFFS_TRACE_CHECKPOINT,(TSTR("struct size %d instead of %d ok %d"TENDSTR), 4372*0e8cc8bdSWilliam Juul cp.structType,sizeof(cp),ok)); 4373*0e8cc8bdSWilliam Juul ok = 0; 4374*0e8cc8bdSWilliam Juul } 4375*0e8cc8bdSWilliam Juul 4376*0e8cc8bdSWilliam Juul T(YAFFS_TRACE_CHECKPOINT,(TSTR("Checkpoint read object %d parent %d type %d chunk %d " TENDSTR), 4377*0e8cc8bdSWilliam Juul cp.objectId,cp.parentId,cp.variantType,cp.chunkId)); 4378*0e8cc8bdSWilliam Juul 4379*0e8cc8bdSWilliam Juul if(ok && cp.objectId == ~0) 4380*0e8cc8bdSWilliam Juul done = 1; 4381*0e8cc8bdSWilliam Juul else if(ok){ 4382*0e8cc8bdSWilliam Juul obj = yaffs_FindOrCreateObjectByNumber(dev,cp.objectId, cp.variantType); 4383*0e8cc8bdSWilliam Juul if(obj) { 4384*0e8cc8bdSWilliam Juul yaffs_CheckpointObjectToObject(obj,&cp); 4385*0e8cc8bdSWilliam Juul if(obj->variantType == YAFFS_OBJECT_TYPE_FILE) { 4386*0e8cc8bdSWilliam Juul ok = yaffs_ReadCheckpointTnodes(obj); 4387*0e8cc8bdSWilliam Juul } else if(obj->variantType == YAFFS_OBJECT_TYPE_HARDLINK) { 4388*0e8cc8bdSWilliam Juul obj->hardLinks.next = 4389*0e8cc8bdSWilliam Juul (struct list_head *) 4390*0e8cc8bdSWilliam Juul hardList; 4391*0e8cc8bdSWilliam Juul hardList = obj; 4392*0e8cc8bdSWilliam Juul } 4393*0e8cc8bdSWilliam Juul 4394*0e8cc8bdSWilliam Juul } 4395*0e8cc8bdSWilliam Juul } 4396*0e8cc8bdSWilliam Juul } 4397*0e8cc8bdSWilliam Juul 4398*0e8cc8bdSWilliam Juul if(ok) 4399*0e8cc8bdSWilliam Juul yaffs_HardlinkFixup(dev,hardList); 4400*0e8cc8bdSWilliam Juul 4401*0e8cc8bdSWilliam Juul return ok ? 1 : 0; 4402*0e8cc8bdSWilliam Juul } 4403*0e8cc8bdSWilliam Juul 4404*0e8cc8bdSWilliam Juul static int yaffs_WriteCheckpointSum(yaffs_Device *dev) 4405*0e8cc8bdSWilliam Juul { 4406*0e8cc8bdSWilliam Juul __u32 checkpointSum; 4407*0e8cc8bdSWilliam Juul int ok; 4408*0e8cc8bdSWilliam Juul 4409*0e8cc8bdSWilliam Juul yaffs_GetCheckpointSum(dev,&checkpointSum); 4410*0e8cc8bdSWilliam Juul 4411*0e8cc8bdSWilliam Juul ok = (yaffs_CheckpointWrite(dev,&checkpointSum,sizeof(checkpointSum)) == sizeof(checkpointSum)); 4412*0e8cc8bdSWilliam Juul 4413*0e8cc8bdSWilliam Juul if(!ok) 4414*0e8cc8bdSWilliam Juul return 0; 4415*0e8cc8bdSWilliam Juul 4416*0e8cc8bdSWilliam Juul return 1; 4417*0e8cc8bdSWilliam Juul } 4418*0e8cc8bdSWilliam Juul 4419*0e8cc8bdSWilliam Juul static int yaffs_ReadCheckpointSum(yaffs_Device *dev) 4420*0e8cc8bdSWilliam Juul { 4421*0e8cc8bdSWilliam Juul __u32 checkpointSum0; 4422*0e8cc8bdSWilliam Juul __u32 checkpointSum1; 4423*0e8cc8bdSWilliam Juul int ok; 4424*0e8cc8bdSWilliam Juul 4425*0e8cc8bdSWilliam Juul yaffs_GetCheckpointSum(dev,&checkpointSum0); 4426*0e8cc8bdSWilliam Juul 4427*0e8cc8bdSWilliam Juul ok = (yaffs_CheckpointRead(dev,&checkpointSum1,sizeof(checkpointSum1)) == sizeof(checkpointSum1)); 4428*0e8cc8bdSWilliam Juul 4429*0e8cc8bdSWilliam Juul if(!ok) 4430*0e8cc8bdSWilliam Juul return 0; 4431*0e8cc8bdSWilliam Juul 4432*0e8cc8bdSWilliam Juul if(checkpointSum0 != checkpointSum1) 4433*0e8cc8bdSWilliam Juul return 0; 4434*0e8cc8bdSWilliam Juul 4435*0e8cc8bdSWilliam Juul return 1; 4436*0e8cc8bdSWilliam Juul } 4437*0e8cc8bdSWilliam Juul 4438*0e8cc8bdSWilliam Juul 4439*0e8cc8bdSWilliam Juul static int yaffs_WriteCheckpointData(yaffs_Device *dev) 4440*0e8cc8bdSWilliam Juul { 4441*0e8cc8bdSWilliam Juul 4442*0e8cc8bdSWilliam Juul int ok = 1; 4443*0e8cc8bdSWilliam Juul 4444*0e8cc8bdSWilliam Juul if(dev->skipCheckpointWrite || !dev->isYaffs2){ 4445*0e8cc8bdSWilliam Juul T(YAFFS_TRACE_CHECKPOINT,(TSTR("skipping checkpoint write" TENDSTR))); 4446*0e8cc8bdSWilliam Juul ok = 0; 4447*0e8cc8bdSWilliam Juul } 4448*0e8cc8bdSWilliam Juul 4449*0e8cc8bdSWilliam Juul if(ok) 4450*0e8cc8bdSWilliam Juul ok = yaffs_CheckpointOpen(dev,1); 4451*0e8cc8bdSWilliam Juul 4452*0e8cc8bdSWilliam Juul if(ok){ 4453*0e8cc8bdSWilliam Juul T(YAFFS_TRACE_CHECKPOINT,(TSTR("write checkpoint validity" TENDSTR))); 4454*0e8cc8bdSWilliam Juul ok = yaffs_WriteCheckpointValidityMarker(dev,1); 4455*0e8cc8bdSWilliam Juul } 4456*0e8cc8bdSWilliam Juul if(ok){ 4457*0e8cc8bdSWilliam Juul T(YAFFS_TRACE_CHECKPOINT,(TSTR("write checkpoint device" TENDSTR))); 4458*0e8cc8bdSWilliam Juul ok = yaffs_WriteCheckpointDevice(dev); 4459*0e8cc8bdSWilliam Juul } 4460*0e8cc8bdSWilliam Juul if(ok){ 4461*0e8cc8bdSWilliam Juul T(YAFFS_TRACE_CHECKPOINT,(TSTR("write checkpoint objects" TENDSTR))); 4462*0e8cc8bdSWilliam Juul ok = yaffs_WriteCheckpointObjects(dev); 4463*0e8cc8bdSWilliam Juul } 4464*0e8cc8bdSWilliam Juul if(ok){ 4465*0e8cc8bdSWilliam Juul T(YAFFS_TRACE_CHECKPOINT,(TSTR("write checkpoint validity" TENDSTR))); 4466*0e8cc8bdSWilliam Juul ok = yaffs_WriteCheckpointValidityMarker(dev,0); 4467*0e8cc8bdSWilliam Juul } 4468*0e8cc8bdSWilliam Juul 4469*0e8cc8bdSWilliam Juul if(ok){ 4470*0e8cc8bdSWilliam Juul ok = yaffs_WriteCheckpointSum(dev); 4471*0e8cc8bdSWilliam Juul } 4472*0e8cc8bdSWilliam Juul 4473*0e8cc8bdSWilliam Juul 4474*0e8cc8bdSWilliam Juul if(!yaffs_CheckpointClose(dev)) 4475*0e8cc8bdSWilliam Juul ok = 0; 4476*0e8cc8bdSWilliam Juul 4477*0e8cc8bdSWilliam Juul if(ok) 4478*0e8cc8bdSWilliam Juul dev->isCheckpointed = 1; 4479*0e8cc8bdSWilliam Juul else 4480*0e8cc8bdSWilliam Juul dev->isCheckpointed = 0; 4481*0e8cc8bdSWilliam Juul 4482*0e8cc8bdSWilliam Juul return dev->isCheckpointed; 4483*0e8cc8bdSWilliam Juul } 4484*0e8cc8bdSWilliam Juul 4485*0e8cc8bdSWilliam Juul static int yaffs_ReadCheckpointData(yaffs_Device *dev) 4486*0e8cc8bdSWilliam Juul { 4487*0e8cc8bdSWilliam Juul int ok = 1; 4488*0e8cc8bdSWilliam Juul 4489*0e8cc8bdSWilliam Juul if(dev->skipCheckpointRead || !dev->isYaffs2){ 4490*0e8cc8bdSWilliam Juul T(YAFFS_TRACE_CHECKPOINT,(TSTR("skipping checkpoint read" TENDSTR))); 4491*0e8cc8bdSWilliam Juul ok = 0; 4492*0e8cc8bdSWilliam Juul } 4493*0e8cc8bdSWilliam Juul 4494*0e8cc8bdSWilliam Juul if(ok) 4495*0e8cc8bdSWilliam Juul ok = yaffs_CheckpointOpen(dev,0); /* open for read */ 4496*0e8cc8bdSWilliam Juul 4497*0e8cc8bdSWilliam Juul if(ok){ 4498*0e8cc8bdSWilliam Juul T(YAFFS_TRACE_CHECKPOINT,(TSTR("read checkpoint validity" TENDSTR))); 4499*0e8cc8bdSWilliam Juul ok = yaffs_ReadCheckpointValidityMarker(dev,1); 4500*0e8cc8bdSWilliam Juul } 4501*0e8cc8bdSWilliam Juul if(ok){ 4502*0e8cc8bdSWilliam Juul T(YAFFS_TRACE_CHECKPOINT,(TSTR("read checkpoint device" TENDSTR))); 4503*0e8cc8bdSWilliam Juul ok = yaffs_ReadCheckpointDevice(dev); 4504*0e8cc8bdSWilliam Juul } 4505*0e8cc8bdSWilliam Juul if(ok){ 4506*0e8cc8bdSWilliam Juul T(YAFFS_TRACE_CHECKPOINT,(TSTR("read checkpoint objects" TENDSTR))); 4507*0e8cc8bdSWilliam Juul ok = yaffs_ReadCheckpointObjects(dev); 4508*0e8cc8bdSWilliam Juul } 4509*0e8cc8bdSWilliam Juul if(ok){ 4510*0e8cc8bdSWilliam Juul T(YAFFS_TRACE_CHECKPOINT,(TSTR("read checkpoint validity" TENDSTR))); 4511*0e8cc8bdSWilliam Juul ok = yaffs_ReadCheckpointValidityMarker(dev,0); 4512*0e8cc8bdSWilliam Juul } 4513*0e8cc8bdSWilliam Juul 4514*0e8cc8bdSWilliam Juul if(ok){ 4515*0e8cc8bdSWilliam Juul ok = yaffs_ReadCheckpointSum(dev); 4516*0e8cc8bdSWilliam Juul T(YAFFS_TRACE_CHECKPOINT,(TSTR("read checkpoint checksum %d" TENDSTR),ok)); 4517*0e8cc8bdSWilliam Juul } 4518*0e8cc8bdSWilliam Juul 4519*0e8cc8bdSWilliam Juul if(!yaffs_CheckpointClose(dev)) 4520*0e8cc8bdSWilliam Juul ok = 0; 4521*0e8cc8bdSWilliam Juul 4522*0e8cc8bdSWilliam Juul if(ok) 4523*0e8cc8bdSWilliam Juul dev->isCheckpointed = 1; 4524*0e8cc8bdSWilliam Juul else 4525*0e8cc8bdSWilliam Juul dev->isCheckpointed = 0; 4526*0e8cc8bdSWilliam Juul 4527*0e8cc8bdSWilliam Juul return ok ? 1 : 0; 4528*0e8cc8bdSWilliam Juul 4529*0e8cc8bdSWilliam Juul } 4530*0e8cc8bdSWilliam Juul 4531*0e8cc8bdSWilliam Juul static void yaffs_InvalidateCheckpoint(yaffs_Device *dev) 4532*0e8cc8bdSWilliam Juul { 4533*0e8cc8bdSWilliam Juul if(dev->isCheckpointed || 4534*0e8cc8bdSWilliam Juul dev->blocksInCheckpoint > 0){ 4535*0e8cc8bdSWilliam Juul dev->isCheckpointed = 0; 4536*0e8cc8bdSWilliam Juul yaffs_CheckpointInvalidateStream(dev); 4537*0e8cc8bdSWilliam Juul if(dev->superBlock && dev->markSuperBlockDirty) 4538*0e8cc8bdSWilliam Juul dev->markSuperBlockDirty(dev->superBlock); 4539*0e8cc8bdSWilliam Juul } 4540*0e8cc8bdSWilliam Juul } 4541*0e8cc8bdSWilliam Juul 4542*0e8cc8bdSWilliam Juul 4543*0e8cc8bdSWilliam Juul int yaffs_CheckpointSave(yaffs_Device *dev) 4544*0e8cc8bdSWilliam Juul { 4545*0e8cc8bdSWilliam Juul 4546*0e8cc8bdSWilliam Juul T(YAFFS_TRACE_CHECKPOINT,(TSTR("save entry: isCheckpointed %d"TENDSTR),dev->isCheckpointed)); 4547*0e8cc8bdSWilliam Juul 4548*0e8cc8bdSWilliam Juul yaffs_VerifyObjects(dev); 4549*0e8cc8bdSWilliam Juul yaffs_VerifyBlocks(dev); 4550*0e8cc8bdSWilliam Juul yaffs_VerifyFreeChunks(dev); 4551*0e8cc8bdSWilliam Juul 4552*0e8cc8bdSWilliam Juul if(!dev->isCheckpointed) { 4553*0e8cc8bdSWilliam Juul yaffs_InvalidateCheckpoint(dev); 4554*0e8cc8bdSWilliam Juul yaffs_WriteCheckpointData(dev); 4555*0e8cc8bdSWilliam Juul } 4556*0e8cc8bdSWilliam Juul 4557*0e8cc8bdSWilliam Juul T(YAFFS_TRACE_ALWAYS,(TSTR("save exit: isCheckpointed %d"TENDSTR),dev->isCheckpointed)); 4558*0e8cc8bdSWilliam Juul 4559*0e8cc8bdSWilliam Juul return dev->isCheckpointed; 4560*0e8cc8bdSWilliam Juul } 4561*0e8cc8bdSWilliam Juul 4562*0e8cc8bdSWilliam Juul int yaffs_CheckpointRestore(yaffs_Device *dev) 4563*0e8cc8bdSWilliam Juul { 4564*0e8cc8bdSWilliam Juul int retval; 4565*0e8cc8bdSWilliam Juul T(YAFFS_TRACE_CHECKPOINT,(TSTR("restore entry: isCheckpointed %d"TENDSTR),dev->isCheckpointed)); 4566*0e8cc8bdSWilliam Juul 4567*0e8cc8bdSWilliam Juul retval = yaffs_ReadCheckpointData(dev); 4568*0e8cc8bdSWilliam Juul 4569*0e8cc8bdSWilliam Juul if(dev->isCheckpointed){ 4570*0e8cc8bdSWilliam Juul yaffs_VerifyObjects(dev); 4571*0e8cc8bdSWilliam Juul yaffs_VerifyBlocks(dev); 4572*0e8cc8bdSWilliam Juul yaffs_VerifyFreeChunks(dev); 4573*0e8cc8bdSWilliam Juul } 4574*0e8cc8bdSWilliam Juul 4575*0e8cc8bdSWilliam Juul T(YAFFS_TRACE_CHECKPOINT,(TSTR("restore exit: isCheckpointed %d"TENDSTR),dev->isCheckpointed)); 4576*0e8cc8bdSWilliam Juul 4577*0e8cc8bdSWilliam Juul return retval; 4578*0e8cc8bdSWilliam Juul } 4579*0e8cc8bdSWilliam Juul 4580*0e8cc8bdSWilliam Juul /*--------------------- File read/write ------------------------ 4581*0e8cc8bdSWilliam Juul * Read and write have very similar structures. 4582*0e8cc8bdSWilliam Juul * In general the read/write has three parts to it 4583*0e8cc8bdSWilliam Juul * An incomplete chunk to start with (if the read/write is not chunk-aligned) 4584*0e8cc8bdSWilliam Juul * Some complete chunks 4585*0e8cc8bdSWilliam Juul * An incomplete chunk to end off with 4586*0e8cc8bdSWilliam Juul * 4587*0e8cc8bdSWilliam Juul * Curve-balls: the first chunk might also be the last chunk. 4588*0e8cc8bdSWilliam Juul */ 4589*0e8cc8bdSWilliam Juul 4590*0e8cc8bdSWilliam Juul int yaffs_ReadDataFromFile(yaffs_Object * in, __u8 * buffer, loff_t offset, 4591*0e8cc8bdSWilliam Juul int nBytes) 4592*0e8cc8bdSWilliam Juul { 4593*0e8cc8bdSWilliam Juul 4594*0e8cc8bdSWilliam Juul int chunk; 4595*0e8cc8bdSWilliam Juul int start; 4596*0e8cc8bdSWilliam Juul int nToCopy; 4597*0e8cc8bdSWilliam Juul int n = nBytes; 4598*0e8cc8bdSWilliam Juul int nDone = 0; 4599*0e8cc8bdSWilliam Juul yaffs_ChunkCache *cache; 4600*0e8cc8bdSWilliam Juul 4601*0e8cc8bdSWilliam Juul yaffs_Device *dev; 4602*0e8cc8bdSWilliam Juul 4603*0e8cc8bdSWilliam Juul dev = in->myDev; 4604*0e8cc8bdSWilliam Juul 4605*0e8cc8bdSWilliam Juul while (n > 0) { 4606*0e8cc8bdSWilliam Juul //chunk = offset / dev->nDataBytesPerChunk + 1; 4607*0e8cc8bdSWilliam Juul //start = offset % dev->nDataBytesPerChunk; 4608*0e8cc8bdSWilliam Juul yaffs_AddrToChunk(dev,offset,&chunk,&start); 4609*0e8cc8bdSWilliam Juul chunk++; 4610*0e8cc8bdSWilliam Juul 4611*0e8cc8bdSWilliam Juul /* OK now check for the curveball where the start and end are in 4612*0e8cc8bdSWilliam Juul * the same chunk. 4613*0e8cc8bdSWilliam Juul */ 4614*0e8cc8bdSWilliam Juul if ((start + n) < dev->nDataBytesPerChunk) { 4615*0e8cc8bdSWilliam Juul nToCopy = n; 4616*0e8cc8bdSWilliam Juul } else { 4617*0e8cc8bdSWilliam Juul nToCopy = dev->nDataBytesPerChunk - start; 4618*0e8cc8bdSWilliam Juul } 4619*0e8cc8bdSWilliam Juul 4620*0e8cc8bdSWilliam Juul cache = yaffs_FindChunkCache(in, chunk); 4621*0e8cc8bdSWilliam Juul 4622*0e8cc8bdSWilliam Juul /* If the chunk is already in the cache or it is less than a whole chunk 4623*0e8cc8bdSWilliam Juul * then use the cache (if there is caching) 4624*0e8cc8bdSWilliam Juul * else bypass the cache. 4625*0e8cc8bdSWilliam Juul */ 4626*0e8cc8bdSWilliam Juul if (cache || nToCopy != dev->nDataBytesPerChunk) { 4627*0e8cc8bdSWilliam Juul if (dev->nShortOpCaches > 0) { 4628*0e8cc8bdSWilliam Juul 4629*0e8cc8bdSWilliam Juul /* If we can't find the data in the cache, then load it up. */ 4630*0e8cc8bdSWilliam Juul 4631*0e8cc8bdSWilliam Juul if (!cache) { 4632*0e8cc8bdSWilliam Juul cache = yaffs_GrabChunkCache(in->myDev); 4633*0e8cc8bdSWilliam Juul cache->object = in; 4634*0e8cc8bdSWilliam Juul cache->chunkId = chunk; 4635*0e8cc8bdSWilliam Juul cache->dirty = 0; 4636*0e8cc8bdSWilliam Juul cache->locked = 0; 4637*0e8cc8bdSWilliam Juul yaffs_ReadChunkDataFromObject(in, chunk, 4638*0e8cc8bdSWilliam Juul cache-> 4639*0e8cc8bdSWilliam Juul data); 4640*0e8cc8bdSWilliam Juul cache->nBytes = 0; 4641*0e8cc8bdSWilliam Juul } 4642*0e8cc8bdSWilliam Juul 4643*0e8cc8bdSWilliam Juul yaffs_UseChunkCache(dev, cache, 0); 4644*0e8cc8bdSWilliam Juul 4645*0e8cc8bdSWilliam Juul cache->locked = 1; 4646*0e8cc8bdSWilliam Juul 4647*0e8cc8bdSWilliam Juul #ifdef CONFIG_YAFFS_WINCE 4648*0e8cc8bdSWilliam Juul yfsd_UnlockYAFFS(TRUE); 4649*0e8cc8bdSWilliam Juul #endif 4650*0e8cc8bdSWilliam Juul memcpy(buffer, &cache->data[start], nToCopy); 4651*0e8cc8bdSWilliam Juul 4652*0e8cc8bdSWilliam Juul #ifdef CONFIG_YAFFS_WINCE 4653*0e8cc8bdSWilliam Juul yfsd_LockYAFFS(TRUE); 4654*0e8cc8bdSWilliam Juul #endif 4655*0e8cc8bdSWilliam Juul cache->locked = 0; 4656*0e8cc8bdSWilliam Juul } else { 4657*0e8cc8bdSWilliam Juul /* Read into the local buffer then copy..*/ 4658*0e8cc8bdSWilliam Juul 4659*0e8cc8bdSWilliam Juul __u8 *localBuffer = 4660*0e8cc8bdSWilliam Juul yaffs_GetTempBuffer(dev, __LINE__); 4661*0e8cc8bdSWilliam Juul yaffs_ReadChunkDataFromObject(in, chunk, 4662*0e8cc8bdSWilliam Juul localBuffer); 4663*0e8cc8bdSWilliam Juul #ifdef CONFIG_YAFFS_WINCE 4664*0e8cc8bdSWilliam Juul yfsd_UnlockYAFFS(TRUE); 4665*0e8cc8bdSWilliam Juul #endif 4666*0e8cc8bdSWilliam Juul memcpy(buffer, &localBuffer[start], nToCopy); 4667*0e8cc8bdSWilliam Juul 4668*0e8cc8bdSWilliam Juul #ifdef CONFIG_YAFFS_WINCE 4669*0e8cc8bdSWilliam Juul yfsd_LockYAFFS(TRUE); 4670*0e8cc8bdSWilliam Juul #endif 4671*0e8cc8bdSWilliam Juul yaffs_ReleaseTempBuffer(dev, localBuffer, 4672*0e8cc8bdSWilliam Juul __LINE__); 4673*0e8cc8bdSWilliam Juul } 4674*0e8cc8bdSWilliam Juul 4675*0e8cc8bdSWilliam Juul } else { 4676*0e8cc8bdSWilliam Juul #ifdef CONFIG_YAFFS_WINCE 4677*0e8cc8bdSWilliam Juul __u8 *localBuffer = yaffs_GetTempBuffer(dev, __LINE__); 4678*0e8cc8bdSWilliam Juul 4679*0e8cc8bdSWilliam Juul /* Under WinCE can't do direct transfer. Need to use a local buffer. 4680*0e8cc8bdSWilliam Juul * This is because we otherwise screw up WinCE's memory mapper 4681*0e8cc8bdSWilliam Juul */ 4682*0e8cc8bdSWilliam Juul yaffs_ReadChunkDataFromObject(in, chunk, localBuffer); 4683*0e8cc8bdSWilliam Juul 4684*0e8cc8bdSWilliam Juul #ifdef CONFIG_YAFFS_WINCE 4685*0e8cc8bdSWilliam Juul yfsd_UnlockYAFFS(TRUE); 4686*0e8cc8bdSWilliam Juul #endif 4687*0e8cc8bdSWilliam Juul memcpy(buffer, localBuffer, dev->nDataBytesPerChunk); 4688*0e8cc8bdSWilliam Juul 4689*0e8cc8bdSWilliam Juul #ifdef CONFIG_YAFFS_WINCE 4690*0e8cc8bdSWilliam Juul yfsd_LockYAFFS(TRUE); 4691*0e8cc8bdSWilliam Juul yaffs_ReleaseTempBuffer(dev, localBuffer, __LINE__); 4692*0e8cc8bdSWilliam Juul #endif 4693*0e8cc8bdSWilliam Juul 4694*0e8cc8bdSWilliam Juul #else 4695*0e8cc8bdSWilliam Juul /* A full chunk. Read directly into the supplied buffer. */ 4696*0e8cc8bdSWilliam Juul yaffs_ReadChunkDataFromObject(in, chunk, buffer); 4697*0e8cc8bdSWilliam Juul #endif 4698*0e8cc8bdSWilliam Juul } 4699*0e8cc8bdSWilliam Juul 4700*0e8cc8bdSWilliam Juul n -= nToCopy; 4701*0e8cc8bdSWilliam Juul offset += nToCopy; 4702*0e8cc8bdSWilliam Juul buffer += nToCopy; 4703*0e8cc8bdSWilliam Juul nDone += nToCopy; 4704*0e8cc8bdSWilliam Juul 4705*0e8cc8bdSWilliam Juul } 4706*0e8cc8bdSWilliam Juul 4707*0e8cc8bdSWilliam Juul return nDone; 4708*0e8cc8bdSWilliam Juul } 4709*0e8cc8bdSWilliam Juul 4710*0e8cc8bdSWilliam Juul int yaffs_WriteDataToFile(yaffs_Object * in, const __u8 * buffer, loff_t offset, 4711*0e8cc8bdSWilliam Juul int nBytes, int writeThrough) 4712*0e8cc8bdSWilliam Juul { 4713*0e8cc8bdSWilliam Juul 4714*0e8cc8bdSWilliam Juul int chunk; 4715*0e8cc8bdSWilliam Juul int start; 4716*0e8cc8bdSWilliam Juul int nToCopy; 4717*0e8cc8bdSWilliam Juul int n = nBytes; 4718*0e8cc8bdSWilliam Juul int nDone = 0; 4719*0e8cc8bdSWilliam Juul int nToWriteBack; 4720*0e8cc8bdSWilliam Juul int startOfWrite = offset; 4721*0e8cc8bdSWilliam Juul int chunkWritten = 0; 4722*0e8cc8bdSWilliam Juul int nBytesRead; 4723*0e8cc8bdSWilliam Juul 4724*0e8cc8bdSWilliam Juul yaffs_Device *dev; 4725*0e8cc8bdSWilliam Juul 4726*0e8cc8bdSWilliam Juul dev = in->myDev; 4727*0e8cc8bdSWilliam Juul 4728*0e8cc8bdSWilliam Juul while (n > 0 && chunkWritten >= 0) { 4729*0e8cc8bdSWilliam Juul //chunk = offset / dev->nDataBytesPerChunk + 1; 4730*0e8cc8bdSWilliam Juul //start = offset % dev->nDataBytesPerChunk; 4731*0e8cc8bdSWilliam Juul yaffs_AddrToChunk(dev,offset,&chunk,&start); 4732*0e8cc8bdSWilliam Juul chunk++; 4733*0e8cc8bdSWilliam Juul 4734*0e8cc8bdSWilliam Juul /* OK now check for the curveball where the start and end are in 4735*0e8cc8bdSWilliam Juul * the same chunk. 4736*0e8cc8bdSWilliam Juul */ 4737*0e8cc8bdSWilliam Juul 4738*0e8cc8bdSWilliam Juul if ((start + n) < dev->nDataBytesPerChunk) { 4739*0e8cc8bdSWilliam Juul nToCopy = n; 4740*0e8cc8bdSWilliam Juul 4741*0e8cc8bdSWilliam Juul /* Now folks, to calculate how many bytes to write back.... 4742*0e8cc8bdSWilliam Juul * If we're overwriting and not writing to then end of file then 4743*0e8cc8bdSWilliam Juul * we need to write back as much as was there before. 4744*0e8cc8bdSWilliam Juul */ 4745*0e8cc8bdSWilliam Juul 4746*0e8cc8bdSWilliam Juul nBytesRead = 4747*0e8cc8bdSWilliam Juul in->variant.fileVariant.fileSize - 4748*0e8cc8bdSWilliam Juul ((chunk - 1) * dev->nDataBytesPerChunk); 4749*0e8cc8bdSWilliam Juul 4750*0e8cc8bdSWilliam Juul if (nBytesRead > dev->nDataBytesPerChunk) { 4751*0e8cc8bdSWilliam Juul nBytesRead = dev->nDataBytesPerChunk; 4752*0e8cc8bdSWilliam Juul } 4753*0e8cc8bdSWilliam Juul 4754*0e8cc8bdSWilliam Juul nToWriteBack = 4755*0e8cc8bdSWilliam Juul (nBytesRead > 4756*0e8cc8bdSWilliam Juul (start + n)) ? nBytesRead : (start + n); 4757*0e8cc8bdSWilliam Juul 4758*0e8cc8bdSWilliam Juul } else { 4759*0e8cc8bdSWilliam Juul nToCopy = dev->nDataBytesPerChunk - start; 4760*0e8cc8bdSWilliam Juul nToWriteBack = dev->nDataBytesPerChunk; 4761*0e8cc8bdSWilliam Juul } 4762*0e8cc8bdSWilliam Juul 4763*0e8cc8bdSWilliam Juul if (nToCopy != dev->nDataBytesPerChunk) { 4764*0e8cc8bdSWilliam Juul /* An incomplete start or end chunk (or maybe both start and end chunk) */ 4765*0e8cc8bdSWilliam Juul if (dev->nShortOpCaches > 0) { 4766*0e8cc8bdSWilliam Juul yaffs_ChunkCache *cache; 4767*0e8cc8bdSWilliam Juul /* If we can't find the data in the cache, then load the cache */ 4768*0e8cc8bdSWilliam Juul cache = yaffs_FindChunkCache(in, chunk); 4769*0e8cc8bdSWilliam Juul 4770*0e8cc8bdSWilliam Juul if (!cache 4771*0e8cc8bdSWilliam Juul && yaffs_CheckSpaceForAllocation(in-> 4772*0e8cc8bdSWilliam Juul myDev)) { 4773*0e8cc8bdSWilliam Juul cache = yaffs_GrabChunkCache(in->myDev); 4774*0e8cc8bdSWilliam Juul cache->object = in; 4775*0e8cc8bdSWilliam Juul cache->chunkId = chunk; 4776*0e8cc8bdSWilliam Juul cache->dirty = 0; 4777*0e8cc8bdSWilliam Juul cache->locked = 0; 4778*0e8cc8bdSWilliam Juul yaffs_ReadChunkDataFromObject(in, chunk, 4779*0e8cc8bdSWilliam Juul cache-> 4780*0e8cc8bdSWilliam Juul data); 4781*0e8cc8bdSWilliam Juul } 4782*0e8cc8bdSWilliam Juul else if(cache && 4783*0e8cc8bdSWilliam Juul !cache->dirty && 4784*0e8cc8bdSWilliam Juul !yaffs_CheckSpaceForAllocation(in->myDev)){ 4785*0e8cc8bdSWilliam Juul /* Drop the cache if it was a read cache item and 4786*0e8cc8bdSWilliam Juul * no space check has been made for it. 4787*0e8cc8bdSWilliam Juul */ 4788*0e8cc8bdSWilliam Juul cache = NULL; 4789*0e8cc8bdSWilliam Juul } 4790*0e8cc8bdSWilliam Juul 4791*0e8cc8bdSWilliam Juul if (cache) { 4792*0e8cc8bdSWilliam Juul yaffs_UseChunkCache(dev, cache, 1); 4793*0e8cc8bdSWilliam Juul cache->locked = 1; 4794*0e8cc8bdSWilliam Juul #ifdef CONFIG_YAFFS_WINCE 4795*0e8cc8bdSWilliam Juul yfsd_UnlockYAFFS(TRUE); 4796*0e8cc8bdSWilliam Juul #endif 4797*0e8cc8bdSWilliam Juul 4798*0e8cc8bdSWilliam Juul memcpy(&cache->data[start], buffer, 4799*0e8cc8bdSWilliam Juul nToCopy); 4800*0e8cc8bdSWilliam Juul 4801*0e8cc8bdSWilliam Juul #ifdef CONFIG_YAFFS_WINCE 4802*0e8cc8bdSWilliam Juul yfsd_LockYAFFS(TRUE); 4803*0e8cc8bdSWilliam Juul #endif 4804*0e8cc8bdSWilliam Juul cache->locked = 0; 4805*0e8cc8bdSWilliam Juul cache->nBytes = nToWriteBack; 4806*0e8cc8bdSWilliam Juul 4807*0e8cc8bdSWilliam Juul if (writeThrough) { 4808*0e8cc8bdSWilliam Juul chunkWritten = 4809*0e8cc8bdSWilliam Juul yaffs_WriteChunkDataToObject 4810*0e8cc8bdSWilliam Juul (cache->object, 4811*0e8cc8bdSWilliam Juul cache->chunkId, 4812*0e8cc8bdSWilliam Juul cache->data, cache->nBytes, 4813*0e8cc8bdSWilliam Juul 1); 4814*0e8cc8bdSWilliam Juul cache->dirty = 0; 4815*0e8cc8bdSWilliam Juul } 4816*0e8cc8bdSWilliam Juul 4817*0e8cc8bdSWilliam Juul } else { 4818*0e8cc8bdSWilliam Juul chunkWritten = -1; /* fail the write */ 4819*0e8cc8bdSWilliam Juul } 4820*0e8cc8bdSWilliam Juul } else { 4821*0e8cc8bdSWilliam Juul /* An incomplete start or end chunk (or maybe both start and end chunk) 4822*0e8cc8bdSWilliam Juul * Read into the local buffer then copy, then copy over and write back. 4823*0e8cc8bdSWilliam Juul */ 4824*0e8cc8bdSWilliam Juul 4825*0e8cc8bdSWilliam Juul __u8 *localBuffer = 4826*0e8cc8bdSWilliam Juul yaffs_GetTempBuffer(dev, __LINE__); 4827*0e8cc8bdSWilliam Juul 4828*0e8cc8bdSWilliam Juul yaffs_ReadChunkDataFromObject(in, chunk, 4829*0e8cc8bdSWilliam Juul localBuffer); 4830*0e8cc8bdSWilliam Juul 4831*0e8cc8bdSWilliam Juul #ifdef CONFIG_YAFFS_WINCE 4832*0e8cc8bdSWilliam Juul yfsd_UnlockYAFFS(TRUE); 4833*0e8cc8bdSWilliam Juul #endif 4834*0e8cc8bdSWilliam Juul 4835*0e8cc8bdSWilliam Juul memcpy(&localBuffer[start], buffer, nToCopy); 4836*0e8cc8bdSWilliam Juul 4837*0e8cc8bdSWilliam Juul #ifdef CONFIG_YAFFS_WINCE 4838*0e8cc8bdSWilliam Juul yfsd_LockYAFFS(TRUE); 4839*0e8cc8bdSWilliam Juul #endif 4840*0e8cc8bdSWilliam Juul chunkWritten = 4841*0e8cc8bdSWilliam Juul yaffs_WriteChunkDataToObject(in, chunk, 4842*0e8cc8bdSWilliam Juul localBuffer, 4843*0e8cc8bdSWilliam Juul nToWriteBack, 4844*0e8cc8bdSWilliam Juul 0); 4845*0e8cc8bdSWilliam Juul 4846*0e8cc8bdSWilliam Juul yaffs_ReleaseTempBuffer(dev, localBuffer, 4847*0e8cc8bdSWilliam Juul __LINE__); 4848*0e8cc8bdSWilliam Juul 4849*0e8cc8bdSWilliam Juul } 4850*0e8cc8bdSWilliam Juul 4851*0e8cc8bdSWilliam Juul } else { 4852*0e8cc8bdSWilliam Juul 4853*0e8cc8bdSWilliam Juul #ifdef CONFIG_YAFFS_WINCE 4854*0e8cc8bdSWilliam Juul /* Under WinCE can't do direct transfer. Need to use a local buffer. 4855*0e8cc8bdSWilliam Juul * This is because we otherwise screw up WinCE's memory mapper 4856*0e8cc8bdSWilliam Juul */ 4857*0e8cc8bdSWilliam Juul __u8 *localBuffer = yaffs_GetTempBuffer(dev, __LINE__); 4858*0e8cc8bdSWilliam Juul #ifdef CONFIG_YAFFS_WINCE 4859*0e8cc8bdSWilliam Juul yfsd_UnlockYAFFS(TRUE); 4860*0e8cc8bdSWilliam Juul #endif 4861*0e8cc8bdSWilliam Juul memcpy(localBuffer, buffer, dev->nDataBytesPerChunk); 4862*0e8cc8bdSWilliam Juul #ifdef CONFIG_YAFFS_WINCE 4863*0e8cc8bdSWilliam Juul yfsd_LockYAFFS(TRUE); 4864*0e8cc8bdSWilliam Juul #endif 4865*0e8cc8bdSWilliam Juul chunkWritten = 4866*0e8cc8bdSWilliam Juul yaffs_WriteChunkDataToObject(in, chunk, localBuffer, 4867*0e8cc8bdSWilliam Juul dev->nDataBytesPerChunk, 4868*0e8cc8bdSWilliam Juul 0); 4869*0e8cc8bdSWilliam Juul yaffs_ReleaseTempBuffer(dev, localBuffer, __LINE__); 4870*0e8cc8bdSWilliam Juul #else 4871*0e8cc8bdSWilliam Juul /* A full chunk. Write directly from the supplied buffer. */ 4872*0e8cc8bdSWilliam Juul chunkWritten = 4873*0e8cc8bdSWilliam Juul yaffs_WriteChunkDataToObject(in, chunk, buffer, 4874*0e8cc8bdSWilliam Juul dev->nDataBytesPerChunk, 4875*0e8cc8bdSWilliam Juul 0); 4876*0e8cc8bdSWilliam Juul #endif 4877*0e8cc8bdSWilliam Juul /* Since we've overwritten the cached data, we better invalidate it. */ 4878*0e8cc8bdSWilliam Juul yaffs_InvalidateChunkCache(in, chunk); 4879*0e8cc8bdSWilliam Juul } 4880*0e8cc8bdSWilliam Juul 4881*0e8cc8bdSWilliam Juul if (chunkWritten >= 0) { 4882*0e8cc8bdSWilliam Juul n -= nToCopy; 4883*0e8cc8bdSWilliam Juul offset += nToCopy; 4884*0e8cc8bdSWilliam Juul buffer += nToCopy; 4885*0e8cc8bdSWilliam Juul nDone += nToCopy; 4886*0e8cc8bdSWilliam Juul } 4887*0e8cc8bdSWilliam Juul 4888*0e8cc8bdSWilliam Juul } 4889*0e8cc8bdSWilliam Juul 4890*0e8cc8bdSWilliam Juul /* Update file object */ 4891*0e8cc8bdSWilliam Juul 4892*0e8cc8bdSWilliam Juul if ((startOfWrite + nDone) > in->variant.fileVariant.fileSize) { 4893*0e8cc8bdSWilliam Juul in->variant.fileVariant.fileSize = (startOfWrite + nDone); 4894*0e8cc8bdSWilliam Juul } 4895*0e8cc8bdSWilliam Juul 4896*0e8cc8bdSWilliam Juul in->dirty = 1; 4897*0e8cc8bdSWilliam Juul 4898*0e8cc8bdSWilliam Juul return nDone; 4899*0e8cc8bdSWilliam Juul } 4900*0e8cc8bdSWilliam Juul 4901*0e8cc8bdSWilliam Juul 4902*0e8cc8bdSWilliam Juul /* ---------------------- File resizing stuff ------------------ */ 4903*0e8cc8bdSWilliam Juul 4904*0e8cc8bdSWilliam Juul static void yaffs_PruneResizedChunks(yaffs_Object * in, int newSize) 4905*0e8cc8bdSWilliam Juul { 4906*0e8cc8bdSWilliam Juul 4907*0e8cc8bdSWilliam Juul yaffs_Device *dev = in->myDev; 4908*0e8cc8bdSWilliam Juul int oldFileSize = in->variant.fileVariant.fileSize; 4909*0e8cc8bdSWilliam Juul 4910*0e8cc8bdSWilliam Juul int lastDel = 1 + (oldFileSize - 1) / dev->nDataBytesPerChunk; 4911*0e8cc8bdSWilliam Juul 4912*0e8cc8bdSWilliam Juul int startDel = 1 + (newSize + dev->nDataBytesPerChunk - 1) / 4913*0e8cc8bdSWilliam Juul dev->nDataBytesPerChunk; 4914*0e8cc8bdSWilliam Juul int i; 4915*0e8cc8bdSWilliam Juul int chunkId; 4916*0e8cc8bdSWilliam Juul 4917*0e8cc8bdSWilliam Juul /* Delete backwards so that we don't end up with holes if 4918*0e8cc8bdSWilliam Juul * power is lost part-way through the operation. 4919*0e8cc8bdSWilliam Juul */ 4920*0e8cc8bdSWilliam Juul for (i = lastDel; i >= startDel; i--) { 4921*0e8cc8bdSWilliam Juul /* NB this could be optimised somewhat, 4922*0e8cc8bdSWilliam Juul * eg. could retrieve the tags and write them without 4923*0e8cc8bdSWilliam Juul * using yaffs_DeleteChunk 4924*0e8cc8bdSWilliam Juul */ 4925*0e8cc8bdSWilliam Juul 4926*0e8cc8bdSWilliam Juul chunkId = yaffs_FindAndDeleteChunkInFile(in, i, NULL); 4927*0e8cc8bdSWilliam Juul if (chunkId > 0) { 4928*0e8cc8bdSWilliam Juul if (chunkId < 4929*0e8cc8bdSWilliam Juul (dev->internalStartBlock * dev->nChunksPerBlock) 4930*0e8cc8bdSWilliam Juul || chunkId >= 4931*0e8cc8bdSWilliam Juul ((dev->internalEndBlock + 4932*0e8cc8bdSWilliam Juul 1) * dev->nChunksPerBlock)) { 4933*0e8cc8bdSWilliam Juul T(YAFFS_TRACE_ALWAYS, 4934*0e8cc8bdSWilliam Juul (TSTR("Found daft chunkId %d for %d" TENDSTR), 4935*0e8cc8bdSWilliam Juul chunkId, i)); 4936*0e8cc8bdSWilliam Juul } else { 4937*0e8cc8bdSWilliam Juul in->nDataChunks--; 4938*0e8cc8bdSWilliam Juul yaffs_DeleteChunk(dev, chunkId, 1, __LINE__); 4939*0e8cc8bdSWilliam Juul } 4940*0e8cc8bdSWilliam Juul } 4941*0e8cc8bdSWilliam Juul } 4942*0e8cc8bdSWilliam Juul 4943*0e8cc8bdSWilliam Juul } 4944*0e8cc8bdSWilliam Juul 4945*0e8cc8bdSWilliam Juul int yaffs_ResizeFile(yaffs_Object * in, loff_t newSize) 4946*0e8cc8bdSWilliam Juul { 4947*0e8cc8bdSWilliam Juul 4948*0e8cc8bdSWilliam Juul int oldFileSize = in->variant.fileVariant.fileSize; 4949*0e8cc8bdSWilliam Juul int newSizeOfPartialChunk; 4950*0e8cc8bdSWilliam Juul int newFullChunks; 4951*0e8cc8bdSWilliam Juul 4952*0e8cc8bdSWilliam Juul yaffs_Device *dev = in->myDev; 4953*0e8cc8bdSWilliam Juul 4954*0e8cc8bdSWilliam Juul yaffs_AddrToChunk(dev, newSize, &newFullChunks, &newSizeOfPartialChunk); 4955*0e8cc8bdSWilliam Juul 4956*0e8cc8bdSWilliam Juul yaffs_FlushFilesChunkCache(in); 4957*0e8cc8bdSWilliam Juul yaffs_InvalidateWholeChunkCache(in); 4958*0e8cc8bdSWilliam Juul 4959*0e8cc8bdSWilliam Juul yaffs_CheckGarbageCollection(dev); 4960*0e8cc8bdSWilliam Juul 4961*0e8cc8bdSWilliam Juul if (in->variantType != YAFFS_OBJECT_TYPE_FILE) { 4962*0e8cc8bdSWilliam Juul return yaffs_GetFileSize(in); 4963*0e8cc8bdSWilliam Juul } 4964*0e8cc8bdSWilliam Juul 4965*0e8cc8bdSWilliam Juul if (newSize == oldFileSize) { 4966*0e8cc8bdSWilliam Juul return oldFileSize; 4967*0e8cc8bdSWilliam Juul } 4968*0e8cc8bdSWilliam Juul 4969*0e8cc8bdSWilliam Juul if (newSize < oldFileSize) { 4970*0e8cc8bdSWilliam Juul 4971*0e8cc8bdSWilliam Juul yaffs_PruneResizedChunks(in, newSize); 4972*0e8cc8bdSWilliam Juul 4973*0e8cc8bdSWilliam Juul if (newSizeOfPartialChunk != 0) { 4974*0e8cc8bdSWilliam Juul int lastChunk = 1 + newFullChunks; 4975*0e8cc8bdSWilliam Juul 4976*0e8cc8bdSWilliam Juul __u8 *localBuffer = yaffs_GetTempBuffer(dev, __LINE__); 4977*0e8cc8bdSWilliam Juul 4978*0e8cc8bdSWilliam Juul /* Got to read and rewrite the last chunk with its new size and zero pad */ 4979*0e8cc8bdSWilliam Juul yaffs_ReadChunkDataFromObject(in, lastChunk, 4980*0e8cc8bdSWilliam Juul localBuffer); 4981*0e8cc8bdSWilliam Juul 4982*0e8cc8bdSWilliam Juul memset(localBuffer + newSizeOfPartialChunk, 0, 4983*0e8cc8bdSWilliam Juul dev->nDataBytesPerChunk - newSizeOfPartialChunk); 4984*0e8cc8bdSWilliam Juul 4985*0e8cc8bdSWilliam Juul yaffs_WriteChunkDataToObject(in, lastChunk, localBuffer, 4986*0e8cc8bdSWilliam Juul newSizeOfPartialChunk, 1); 4987*0e8cc8bdSWilliam Juul 4988*0e8cc8bdSWilliam Juul yaffs_ReleaseTempBuffer(dev, localBuffer, __LINE__); 4989*0e8cc8bdSWilliam Juul } 4990*0e8cc8bdSWilliam Juul 4991*0e8cc8bdSWilliam Juul in->variant.fileVariant.fileSize = newSize; 4992*0e8cc8bdSWilliam Juul 4993*0e8cc8bdSWilliam Juul yaffs_PruneFileStructure(dev, &in->variant.fileVariant); 4994*0e8cc8bdSWilliam Juul } else { 4995*0e8cc8bdSWilliam Juul /* newsSize > oldFileSize */ 4996*0e8cc8bdSWilliam Juul in->variant.fileVariant.fileSize = newSize; 4997*0e8cc8bdSWilliam Juul } 4998*0e8cc8bdSWilliam Juul 4999*0e8cc8bdSWilliam Juul 5000*0e8cc8bdSWilliam Juul 5001*0e8cc8bdSWilliam Juul /* Write a new object header. 5002*0e8cc8bdSWilliam Juul * show we've shrunk the file, if need be 5003*0e8cc8bdSWilliam Juul * Do this only if the file is not in the deleted directories. 5004*0e8cc8bdSWilliam Juul */ 5005*0e8cc8bdSWilliam Juul if (in->parent->objectId != YAFFS_OBJECTID_UNLINKED && 5006*0e8cc8bdSWilliam Juul in->parent->objectId != YAFFS_OBJECTID_DELETED) { 5007*0e8cc8bdSWilliam Juul yaffs_UpdateObjectHeader(in, NULL, 0, 5008*0e8cc8bdSWilliam Juul (newSize < oldFileSize) ? 1 : 0, 0); 5009*0e8cc8bdSWilliam Juul } 5010*0e8cc8bdSWilliam Juul 5011*0e8cc8bdSWilliam Juul return YAFFS_OK; 5012*0e8cc8bdSWilliam Juul } 5013*0e8cc8bdSWilliam Juul 5014*0e8cc8bdSWilliam Juul loff_t yaffs_GetFileSize(yaffs_Object * obj) 5015*0e8cc8bdSWilliam Juul { 5016*0e8cc8bdSWilliam Juul obj = yaffs_GetEquivalentObject(obj); 5017*0e8cc8bdSWilliam Juul 5018*0e8cc8bdSWilliam Juul switch (obj->variantType) { 5019*0e8cc8bdSWilliam Juul case YAFFS_OBJECT_TYPE_FILE: 5020*0e8cc8bdSWilliam Juul return obj->variant.fileVariant.fileSize; 5021*0e8cc8bdSWilliam Juul case YAFFS_OBJECT_TYPE_SYMLINK: 5022*0e8cc8bdSWilliam Juul return yaffs_strlen(obj->variant.symLinkVariant.alias); 5023*0e8cc8bdSWilliam Juul default: 5024*0e8cc8bdSWilliam Juul return 0; 5025*0e8cc8bdSWilliam Juul } 5026*0e8cc8bdSWilliam Juul } 5027*0e8cc8bdSWilliam Juul 5028*0e8cc8bdSWilliam Juul 5029*0e8cc8bdSWilliam Juul 5030*0e8cc8bdSWilliam Juul int yaffs_FlushFile(yaffs_Object * in, int updateTime) 5031*0e8cc8bdSWilliam Juul { 5032*0e8cc8bdSWilliam Juul int retVal; 5033*0e8cc8bdSWilliam Juul if (in->dirty) { 5034*0e8cc8bdSWilliam Juul yaffs_FlushFilesChunkCache(in); 5035*0e8cc8bdSWilliam Juul if (updateTime) { 5036*0e8cc8bdSWilliam Juul #ifdef CONFIG_YAFFS_WINCE 5037*0e8cc8bdSWilliam Juul yfsd_WinFileTimeNow(in->win_mtime); 5038*0e8cc8bdSWilliam Juul #else 5039*0e8cc8bdSWilliam Juul 5040*0e8cc8bdSWilliam Juul in->yst_mtime = Y_CURRENT_TIME; 5041*0e8cc8bdSWilliam Juul 5042*0e8cc8bdSWilliam Juul #endif 5043*0e8cc8bdSWilliam Juul } 5044*0e8cc8bdSWilliam Juul 5045*0e8cc8bdSWilliam Juul retVal = 5046*0e8cc8bdSWilliam Juul (yaffs_UpdateObjectHeader(in, NULL, 0, 0, 0) >= 5047*0e8cc8bdSWilliam Juul 0) ? YAFFS_OK : YAFFS_FAIL; 5048*0e8cc8bdSWilliam Juul } else { 5049*0e8cc8bdSWilliam Juul retVal = YAFFS_OK; 5050*0e8cc8bdSWilliam Juul } 5051*0e8cc8bdSWilliam Juul 5052*0e8cc8bdSWilliam Juul return retVal; 5053*0e8cc8bdSWilliam Juul 5054*0e8cc8bdSWilliam Juul } 5055*0e8cc8bdSWilliam Juul 5056*0e8cc8bdSWilliam Juul static int yaffs_DoGenericObjectDeletion(yaffs_Object * in) 5057*0e8cc8bdSWilliam Juul { 5058*0e8cc8bdSWilliam Juul 5059*0e8cc8bdSWilliam Juul /* First off, invalidate the file's data in the cache, without flushing. */ 5060*0e8cc8bdSWilliam Juul yaffs_InvalidateWholeChunkCache(in); 5061*0e8cc8bdSWilliam Juul 5062*0e8cc8bdSWilliam Juul if (in->myDev->isYaffs2 && (in->parent != in->myDev->deletedDir)) { 5063*0e8cc8bdSWilliam Juul /* Move to the unlinked directory so we have a record that it was deleted. */ 5064*0e8cc8bdSWilliam Juul yaffs_ChangeObjectName(in, in->myDev->deletedDir,"deleted", 0, 0); 5065*0e8cc8bdSWilliam Juul 5066*0e8cc8bdSWilliam Juul } 5067*0e8cc8bdSWilliam Juul 5068*0e8cc8bdSWilliam Juul yaffs_RemoveObjectFromDirectory(in); 5069*0e8cc8bdSWilliam Juul yaffs_DeleteChunk(in->myDev, in->chunkId, 1, __LINE__); 5070*0e8cc8bdSWilliam Juul in->chunkId = -1; 5071*0e8cc8bdSWilliam Juul 5072*0e8cc8bdSWilliam Juul yaffs_FreeObject(in); 5073*0e8cc8bdSWilliam Juul return YAFFS_OK; 5074*0e8cc8bdSWilliam Juul 5075*0e8cc8bdSWilliam Juul } 5076*0e8cc8bdSWilliam Juul 5077*0e8cc8bdSWilliam Juul /* yaffs_DeleteFile deletes the whole file data 5078*0e8cc8bdSWilliam Juul * and the inode associated with the file. 5079*0e8cc8bdSWilliam Juul * It does not delete the links associated with the file. 5080*0e8cc8bdSWilliam Juul */ 5081*0e8cc8bdSWilliam Juul static int yaffs_UnlinkFile(yaffs_Object * in) 5082*0e8cc8bdSWilliam Juul { 5083*0e8cc8bdSWilliam Juul 5084*0e8cc8bdSWilliam Juul int retVal; 5085*0e8cc8bdSWilliam Juul int immediateDeletion = 0; 5086*0e8cc8bdSWilliam Juul 5087*0e8cc8bdSWilliam Juul if (1) { 5088*0e8cc8bdSWilliam Juul #ifdef __KERNEL__ 5089*0e8cc8bdSWilliam Juul if (!in->myInode) { 5090*0e8cc8bdSWilliam Juul immediateDeletion = 1; 5091*0e8cc8bdSWilliam Juul 5092*0e8cc8bdSWilliam Juul } 5093*0e8cc8bdSWilliam Juul #else 5094*0e8cc8bdSWilliam Juul if (in->inUse <= 0) { 5095*0e8cc8bdSWilliam Juul immediateDeletion = 1; 5096*0e8cc8bdSWilliam Juul 5097*0e8cc8bdSWilliam Juul } 5098*0e8cc8bdSWilliam Juul #endif 5099*0e8cc8bdSWilliam Juul if (immediateDeletion) { 5100*0e8cc8bdSWilliam Juul retVal = 5101*0e8cc8bdSWilliam Juul yaffs_ChangeObjectName(in, in->myDev->deletedDir, 5102*0e8cc8bdSWilliam Juul "deleted", 0, 0); 5103*0e8cc8bdSWilliam Juul T(YAFFS_TRACE_TRACING, 5104*0e8cc8bdSWilliam Juul (TSTR("yaffs: immediate deletion of file %d" TENDSTR), 5105*0e8cc8bdSWilliam Juul in->objectId)); 5106*0e8cc8bdSWilliam Juul in->deleted = 1; 5107*0e8cc8bdSWilliam Juul in->myDev->nDeletedFiles++; 5108*0e8cc8bdSWilliam Juul if (0 && in->myDev->isYaffs2) { 5109*0e8cc8bdSWilliam Juul yaffs_ResizeFile(in, 0); 5110*0e8cc8bdSWilliam Juul } 5111*0e8cc8bdSWilliam Juul yaffs_SoftDeleteFile(in); 5112*0e8cc8bdSWilliam Juul } else { 5113*0e8cc8bdSWilliam Juul retVal = 5114*0e8cc8bdSWilliam Juul yaffs_ChangeObjectName(in, in->myDev->unlinkedDir, 5115*0e8cc8bdSWilliam Juul "unlinked", 0, 0); 5116*0e8cc8bdSWilliam Juul } 5117*0e8cc8bdSWilliam Juul 5118*0e8cc8bdSWilliam Juul } 5119*0e8cc8bdSWilliam Juul return retVal; 5120*0e8cc8bdSWilliam Juul } 5121*0e8cc8bdSWilliam Juul 5122*0e8cc8bdSWilliam Juul int yaffs_DeleteFile(yaffs_Object * in) 5123*0e8cc8bdSWilliam Juul { 5124*0e8cc8bdSWilliam Juul int retVal = YAFFS_OK; 5125*0e8cc8bdSWilliam Juul 5126*0e8cc8bdSWilliam Juul if (in->nDataChunks > 0) { 5127*0e8cc8bdSWilliam Juul /* Use soft deletion if there is data in the file */ 5128*0e8cc8bdSWilliam Juul if (!in->unlinked) { 5129*0e8cc8bdSWilliam Juul retVal = yaffs_UnlinkFile(in); 5130*0e8cc8bdSWilliam Juul } 5131*0e8cc8bdSWilliam Juul if (retVal == YAFFS_OK && in->unlinked && !in->deleted) { 5132*0e8cc8bdSWilliam Juul in->deleted = 1; 5133*0e8cc8bdSWilliam Juul in->myDev->nDeletedFiles++; 5134*0e8cc8bdSWilliam Juul yaffs_SoftDeleteFile(in); 5135*0e8cc8bdSWilliam Juul } 5136*0e8cc8bdSWilliam Juul return in->deleted ? YAFFS_OK : YAFFS_FAIL; 5137*0e8cc8bdSWilliam Juul } else { 5138*0e8cc8bdSWilliam Juul /* The file has no data chunks so we toss it immediately */ 5139*0e8cc8bdSWilliam Juul yaffs_FreeTnode(in->myDev, in->variant.fileVariant.top); 5140*0e8cc8bdSWilliam Juul in->variant.fileVariant.top = NULL; 5141*0e8cc8bdSWilliam Juul yaffs_DoGenericObjectDeletion(in); 5142*0e8cc8bdSWilliam Juul 5143*0e8cc8bdSWilliam Juul return YAFFS_OK; 5144*0e8cc8bdSWilliam Juul } 5145*0e8cc8bdSWilliam Juul } 5146*0e8cc8bdSWilliam Juul 5147*0e8cc8bdSWilliam Juul static int yaffs_DeleteDirectory(yaffs_Object * in) 5148*0e8cc8bdSWilliam Juul { 5149*0e8cc8bdSWilliam Juul /* First check that the directory is empty. */ 5150*0e8cc8bdSWilliam Juul if (list_empty(&in->variant.directoryVariant.children)) { 5151*0e8cc8bdSWilliam Juul return yaffs_DoGenericObjectDeletion(in); 5152*0e8cc8bdSWilliam Juul } 5153*0e8cc8bdSWilliam Juul 5154*0e8cc8bdSWilliam Juul return YAFFS_FAIL; 5155*0e8cc8bdSWilliam Juul 5156*0e8cc8bdSWilliam Juul } 5157*0e8cc8bdSWilliam Juul 5158*0e8cc8bdSWilliam Juul static int yaffs_DeleteSymLink(yaffs_Object * in) 5159*0e8cc8bdSWilliam Juul { 5160*0e8cc8bdSWilliam Juul YFREE(in->variant.symLinkVariant.alias); 5161*0e8cc8bdSWilliam Juul 5162*0e8cc8bdSWilliam Juul return yaffs_DoGenericObjectDeletion(in); 5163*0e8cc8bdSWilliam Juul } 5164*0e8cc8bdSWilliam Juul 5165*0e8cc8bdSWilliam Juul static int yaffs_DeleteHardLink(yaffs_Object * in) 5166*0e8cc8bdSWilliam Juul { 5167*0e8cc8bdSWilliam Juul /* remove this hardlink from the list assocaited with the equivalent 5168*0e8cc8bdSWilliam Juul * object 5169*0e8cc8bdSWilliam Juul */ 5170*0e8cc8bdSWilliam Juul list_del(&in->hardLinks); 5171*0e8cc8bdSWilliam Juul return yaffs_DoGenericObjectDeletion(in); 5172*0e8cc8bdSWilliam Juul } 5173*0e8cc8bdSWilliam Juul 5174*0e8cc8bdSWilliam Juul static void yaffs_DestroyObject(yaffs_Object * obj) 5175*0e8cc8bdSWilliam Juul { 5176*0e8cc8bdSWilliam Juul switch (obj->variantType) { 5177*0e8cc8bdSWilliam Juul case YAFFS_OBJECT_TYPE_FILE: 5178*0e8cc8bdSWilliam Juul yaffs_DeleteFile(obj); 5179*0e8cc8bdSWilliam Juul break; 5180*0e8cc8bdSWilliam Juul case YAFFS_OBJECT_TYPE_DIRECTORY: 5181*0e8cc8bdSWilliam Juul yaffs_DeleteDirectory(obj); 5182*0e8cc8bdSWilliam Juul break; 5183*0e8cc8bdSWilliam Juul case YAFFS_OBJECT_TYPE_SYMLINK: 5184*0e8cc8bdSWilliam Juul yaffs_DeleteSymLink(obj); 5185*0e8cc8bdSWilliam Juul break; 5186*0e8cc8bdSWilliam Juul case YAFFS_OBJECT_TYPE_HARDLINK: 5187*0e8cc8bdSWilliam Juul yaffs_DeleteHardLink(obj); 5188*0e8cc8bdSWilliam Juul break; 5189*0e8cc8bdSWilliam Juul case YAFFS_OBJECT_TYPE_SPECIAL: 5190*0e8cc8bdSWilliam Juul yaffs_DoGenericObjectDeletion(obj); 5191*0e8cc8bdSWilliam Juul break; 5192*0e8cc8bdSWilliam Juul case YAFFS_OBJECT_TYPE_UNKNOWN: 5193*0e8cc8bdSWilliam Juul break; /* should not happen. */ 5194*0e8cc8bdSWilliam Juul } 5195*0e8cc8bdSWilliam Juul } 5196*0e8cc8bdSWilliam Juul 5197*0e8cc8bdSWilliam Juul static int yaffs_UnlinkWorker(yaffs_Object * obj) 5198*0e8cc8bdSWilliam Juul { 5199*0e8cc8bdSWilliam Juul 5200*0e8cc8bdSWilliam Juul if (obj->variantType == YAFFS_OBJECT_TYPE_HARDLINK) { 5201*0e8cc8bdSWilliam Juul return yaffs_DeleteHardLink(obj); 5202*0e8cc8bdSWilliam Juul } else if (!list_empty(&obj->hardLinks)) { 5203*0e8cc8bdSWilliam Juul /* Curve ball: We're unlinking an object that has a hardlink. 5204*0e8cc8bdSWilliam Juul * 5205*0e8cc8bdSWilliam Juul * This problem arises because we are not strictly following 5206*0e8cc8bdSWilliam Juul * The Linux link/inode model. 5207*0e8cc8bdSWilliam Juul * 5208*0e8cc8bdSWilliam Juul * We can't really delete the object. 5209*0e8cc8bdSWilliam Juul * Instead, we do the following: 5210*0e8cc8bdSWilliam Juul * - Select a hardlink. 5211*0e8cc8bdSWilliam Juul * - Unhook it from the hard links 5212*0e8cc8bdSWilliam Juul * - Unhook it from its parent directory (so that the rename can work) 5213*0e8cc8bdSWilliam Juul * - Rename the object to the hardlink's name. 5214*0e8cc8bdSWilliam Juul * - Delete the hardlink 5215*0e8cc8bdSWilliam Juul */ 5216*0e8cc8bdSWilliam Juul 5217*0e8cc8bdSWilliam Juul yaffs_Object *hl; 5218*0e8cc8bdSWilliam Juul int retVal; 5219*0e8cc8bdSWilliam Juul YCHAR name[YAFFS_MAX_NAME_LENGTH + 1]; 5220*0e8cc8bdSWilliam Juul 5221*0e8cc8bdSWilliam Juul hl = list_entry(obj->hardLinks.next, yaffs_Object, hardLinks); 5222*0e8cc8bdSWilliam Juul 5223*0e8cc8bdSWilliam Juul list_del_init(&hl->hardLinks); 5224*0e8cc8bdSWilliam Juul list_del_init(&hl->siblings); 5225*0e8cc8bdSWilliam Juul 5226*0e8cc8bdSWilliam Juul yaffs_GetObjectName(hl, name, YAFFS_MAX_NAME_LENGTH + 1); 5227*0e8cc8bdSWilliam Juul 5228*0e8cc8bdSWilliam Juul retVal = yaffs_ChangeObjectName(obj, hl->parent, name, 0, 0); 5229*0e8cc8bdSWilliam Juul 5230*0e8cc8bdSWilliam Juul if (retVal == YAFFS_OK) { 5231*0e8cc8bdSWilliam Juul retVal = yaffs_DoGenericObjectDeletion(hl); 5232*0e8cc8bdSWilliam Juul } 5233*0e8cc8bdSWilliam Juul return retVal; 5234*0e8cc8bdSWilliam Juul 5235*0e8cc8bdSWilliam Juul } else { 5236*0e8cc8bdSWilliam Juul switch (obj->variantType) { 5237*0e8cc8bdSWilliam Juul case YAFFS_OBJECT_TYPE_FILE: 5238*0e8cc8bdSWilliam Juul return yaffs_UnlinkFile(obj); 5239*0e8cc8bdSWilliam Juul break; 5240*0e8cc8bdSWilliam Juul case YAFFS_OBJECT_TYPE_DIRECTORY: 5241*0e8cc8bdSWilliam Juul return yaffs_DeleteDirectory(obj); 5242*0e8cc8bdSWilliam Juul break; 5243*0e8cc8bdSWilliam Juul case YAFFS_OBJECT_TYPE_SYMLINK: 5244*0e8cc8bdSWilliam Juul return yaffs_DeleteSymLink(obj); 5245*0e8cc8bdSWilliam Juul break; 5246*0e8cc8bdSWilliam Juul case YAFFS_OBJECT_TYPE_SPECIAL: 5247*0e8cc8bdSWilliam Juul return yaffs_DoGenericObjectDeletion(obj); 5248*0e8cc8bdSWilliam Juul break; 5249*0e8cc8bdSWilliam Juul case YAFFS_OBJECT_TYPE_HARDLINK: 5250*0e8cc8bdSWilliam Juul case YAFFS_OBJECT_TYPE_UNKNOWN: 5251*0e8cc8bdSWilliam Juul default: 5252*0e8cc8bdSWilliam Juul return YAFFS_FAIL; 5253*0e8cc8bdSWilliam Juul } 5254*0e8cc8bdSWilliam Juul } 5255*0e8cc8bdSWilliam Juul } 5256*0e8cc8bdSWilliam Juul 5257*0e8cc8bdSWilliam Juul 5258*0e8cc8bdSWilliam Juul static int yaffs_UnlinkObject( yaffs_Object *obj) 5259*0e8cc8bdSWilliam Juul { 5260*0e8cc8bdSWilliam Juul 5261*0e8cc8bdSWilliam Juul if (obj && obj->unlinkAllowed) { 5262*0e8cc8bdSWilliam Juul return yaffs_UnlinkWorker(obj); 5263*0e8cc8bdSWilliam Juul } 5264*0e8cc8bdSWilliam Juul 5265*0e8cc8bdSWilliam Juul return YAFFS_FAIL; 5266*0e8cc8bdSWilliam Juul 5267*0e8cc8bdSWilliam Juul } 5268*0e8cc8bdSWilliam Juul int yaffs_Unlink(yaffs_Object * dir, const YCHAR * name) 5269*0e8cc8bdSWilliam Juul { 5270*0e8cc8bdSWilliam Juul yaffs_Object *obj; 5271*0e8cc8bdSWilliam Juul 5272*0e8cc8bdSWilliam Juul obj = yaffs_FindObjectByName(dir, name); 5273*0e8cc8bdSWilliam Juul return yaffs_UnlinkObject(obj); 5274*0e8cc8bdSWilliam Juul } 5275*0e8cc8bdSWilliam Juul 5276*0e8cc8bdSWilliam Juul /*----------------------- Initialisation Scanning ---------------------- */ 5277*0e8cc8bdSWilliam Juul 5278*0e8cc8bdSWilliam Juul static void yaffs_HandleShadowedObject(yaffs_Device * dev, int objId, 5279*0e8cc8bdSWilliam Juul int backwardScanning) 5280*0e8cc8bdSWilliam Juul { 5281*0e8cc8bdSWilliam Juul yaffs_Object *obj; 5282*0e8cc8bdSWilliam Juul 5283*0e8cc8bdSWilliam Juul if (!backwardScanning) { 5284*0e8cc8bdSWilliam Juul /* Handle YAFFS1 forward scanning case 5285*0e8cc8bdSWilliam Juul * For YAFFS1 we always do the deletion 5286*0e8cc8bdSWilliam Juul */ 5287*0e8cc8bdSWilliam Juul 5288*0e8cc8bdSWilliam Juul } else { 5289*0e8cc8bdSWilliam Juul /* Handle YAFFS2 case (backward scanning) 5290*0e8cc8bdSWilliam Juul * If the shadowed object exists then ignore. 5291*0e8cc8bdSWilliam Juul */ 5292*0e8cc8bdSWilliam Juul if (yaffs_FindObjectByNumber(dev, objId)) { 5293*0e8cc8bdSWilliam Juul return; 5294*0e8cc8bdSWilliam Juul } 5295*0e8cc8bdSWilliam Juul } 5296*0e8cc8bdSWilliam Juul 5297*0e8cc8bdSWilliam Juul /* Let's create it (if it does not exist) assuming it is a file so that it can do shrinking etc. 5298*0e8cc8bdSWilliam Juul * We put it in unlinked dir to be cleaned up after the scanning 5299*0e8cc8bdSWilliam Juul */ 5300*0e8cc8bdSWilliam Juul obj = 5301*0e8cc8bdSWilliam Juul yaffs_FindOrCreateObjectByNumber(dev, objId, 5302*0e8cc8bdSWilliam Juul YAFFS_OBJECT_TYPE_FILE); 5303*0e8cc8bdSWilliam Juul yaffs_AddObjectToDirectory(dev->unlinkedDir, obj); 5304*0e8cc8bdSWilliam Juul obj->variant.fileVariant.shrinkSize = 0; 5305*0e8cc8bdSWilliam Juul obj->valid = 1; /* So that we don't read any other info for this file */ 5306*0e8cc8bdSWilliam Juul 5307*0e8cc8bdSWilliam Juul } 5308*0e8cc8bdSWilliam Juul 5309*0e8cc8bdSWilliam Juul typedef struct { 5310*0e8cc8bdSWilliam Juul int seq; 5311*0e8cc8bdSWilliam Juul int block; 5312*0e8cc8bdSWilliam Juul } yaffs_BlockIndex; 5313*0e8cc8bdSWilliam Juul 5314*0e8cc8bdSWilliam Juul 5315*0e8cc8bdSWilliam Juul static void yaffs_HardlinkFixup(yaffs_Device *dev, yaffs_Object *hardList) 5316*0e8cc8bdSWilliam Juul { 5317*0e8cc8bdSWilliam Juul yaffs_Object *hl; 5318*0e8cc8bdSWilliam Juul yaffs_Object *in; 5319*0e8cc8bdSWilliam Juul 5320*0e8cc8bdSWilliam Juul while (hardList) { 5321*0e8cc8bdSWilliam Juul hl = hardList; 5322*0e8cc8bdSWilliam Juul hardList = (yaffs_Object *) (hardList->hardLinks.next); 5323*0e8cc8bdSWilliam Juul 5324*0e8cc8bdSWilliam Juul in = yaffs_FindObjectByNumber(dev, 5325*0e8cc8bdSWilliam Juul hl->variant.hardLinkVariant. 5326*0e8cc8bdSWilliam Juul equivalentObjectId); 5327*0e8cc8bdSWilliam Juul 5328*0e8cc8bdSWilliam Juul if (in) { 5329*0e8cc8bdSWilliam Juul /* Add the hardlink pointers */ 5330*0e8cc8bdSWilliam Juul hl->variant.hardLinkVariant.equivalentObject = in; 5331*0e8cc8bdSWilliam Juul list_add(&hl->hardLinks, &in->hardLinks); 5332*0e8cc8bdSWilliam Juul } else { 5333*0e8cc8bdSWilliam Juul /* Todo Need to report/handle this better. 5334*0e8cc8bdSWilliam Juul * Got a problem... hardlink to a non-existant object 5335*0e8cc8bdSWilliam Juul */ 5336*0e8cc8bdSWilliam Juul hl->variant.hardLinkVariant.equivalentObject = NULL; 5337*0e8cc8bdSWilliam Juul INIT_LIST_HEAD(&hl->hardLinks); 5338*0e8cc8bdSWilliam Juul 5339*0e8cc8bdSWilliam Juul } 5340*0e8cc8bdSWilliam Juul 5341*0e8cc8bdSWilliam Juul } 5342*0e8cc8bdSWilliam Juul 5343*0e8cc8bdSWilliam Juul } 5344*0e8cc8bdSWilliam Juul 5345*0e8cc8bdSWilliam Juul 5346*0e8cc8bdSWilliam Juul 5347*0e8cc8bdSWilliam Juul 5348*0e8cc8bdSWilliam Juul 5349*0e8cc8bdSWilliam Juul static int ybicmp(const void *a, const void *b){ 5350*0e8cc8bdSWilliam Juul register int aseq = ((yaffs_BlockIndex *)a)->seq; 5351*0e8cc8bdSWilliam Juul register int bseq = ((yaffs_BlockIndex *)b)->seq; 5352*0e8cc8bdSWilliam Juul register int ablock = ((yaffs_BlockIndex *)a)->block; 5353*0e8cc8bdSWilliam Juul register int bblock = ((yaffs_BlockIndex *)b)->block; 5354*0e8cc8bdSWilliam Juul if( aseq == bseq ) 5355*0e8cc8bdSWilliam Juul return ablock - bblock; 5356*0e8cc8bdSWilliam Juul else 5357*0e8cc8bdSWilliam Juul return aseq - bseq; 5358*0e8cc8bdSWilliam Juul 5359*0e8cc8bdSWilliam Juul } 5360*0e8cc8bdSWilliam Juul 5361*0e8cc8bdSWilliam Juul static int yaffs_Scan(yaffs_Device * dev) 5362*0e8cc8bdSWilliam Juul { 5363*0e8cc8bdSWilliam Juul yaffs_ExtendedTags tags; 5364*0e8cc8bdSWilliam Juul int blk; 5365*0e8cc8bdSWilliam Juul int blockIterator; 5366*0e8cc8bdSWilliam Juul int startIterator; 5367*0e8cc8bdSWilliam Juul int endIterator; 5368*0e8cc8bdSWilliam Juul int nBlocksToScan = 0; 5369*0e8cc8bdSWilliam Juul int result; 5370*0e8cc8bdSWilliam Juul 5371*0e8cc8bdSWilliam Juul int chunk; 5372*0e8cc8bdSWilliam Juul int c; 5373*0e8cc8bdSWilliam Juul int deleted; 5374*0e8cc8bdSWilliam Juul yaffs_BlockState state; 5375*0e8cc8bdSWilliam Juul yaffs_Object *hardList = NULL; 5376*0e8cc8bdSWilliam Juul yaffs_BlockInfo *bi; 5377*0e8cc8bdSWilliam Juul int sequenceNumber; 5378*0e8cc8bdSWilliam Juul yaffs_ObjectHeader *oh; 5379*0e8cc8bdSWilliam Juul yaffs_Object *in; 5380*0e8cc8bdSWilliam Juul yaffs_Object *parent; 5381*0e8cc8bdSWilliam Juul int nBlocks = dev->internalEndBlock - dev->internalStartBlock + 1; 5382*0e8cc8bdSWilliam Juul 5383*0e8cc8bdSWilliam Juul int alloc_failed = 0; 5384*0e8cc8bdSWilliam Juul 5385*0e8cc8bdSWilliam Juul 5386*0e8cc8bdSWilliam Juul __u8 *chunkData; 5387*0e8cc8bdSWilliam Juul 5388*0e8cc8bdSWilliam Juul yaffs_BlockIndex *blockIndex = NULL; 5389*0e8cc8bdSWilliam Juul 5390*0e8cc8bdSWilliam Juul if (dev->isYaffs2) { 5391*0e8cc8bdSWilliam Juul T(YAFFS_TRACE_SCAN, 5392*0e8cc8bdSWilliam Juul (TSTR("yaffs_Scan is not for YAFFS2!" TENDSTR))); 5393*0e8cc8bdSWilliam Juul return YAFFS_FAIL; 5394*0e8cc8bdSWilliam Juul } 5395*0e8cc8bdSWilliam Juul 5396*0e8cc8bdSWilliam Juul //TODO Throw all the yaffs2 stuuf out of yaffs_Scan since it is only for yaffs1 format. 5397*0e8cc8bdSWilliam Juul 5398*0e8cc8bdSWilliam Juul T(YAFFS_TRACE_SCAN, 5399*0e8cc8bdSWilliam Juul (TSTR("yaffs_Scan starts intstartblk %d intendblk %d..." TENDSTR), 5400*0e8cc8bdSWilliam Juul dev->internalStartBlock, dev->internalEndBlock)); 5401*0e8cc8bdSWilliam Juul 5402*0e8cc8bdSWilliam Juul chunkData = yaffs_GetTempBuffer(dev, __LINE__); 5403*0e8cc8bdSWilliam Juul 5404*0e8cc8bdSWilliam Juul dev->sequenceNumber = YAFFS_LOWEST_SEQUENCE_NUMBER; 5405*0e8cc8bdSWilliam Juul 5406*0e8cc8bdSWilliam Juul if (dev->isYaffs2) { 5407*0e8cc8bdSWilliam Juul blockIndex = YMALLOC(nBlocks * sizeof(yaffs_BlockIndex)); 5408*0e8cc8bdSWilliam Juul if(!blockIndex) 5409*0e8cc8bdSWilliam Juul return YAFFS_FAIL; 5410*0e8cc8bdSWilliam Juul } 5411*0e8cc8bdSWilliam Juul 5412*0e8cc8bdSWilliam Juul /* Scan all the blocks to determine their state */ 5413*0e8cc8bdSWilliam Juul for (blk = dev->internalStartBlock; blk <= dev->internalEndBlock; blk++) { 5414*0e8cc8bdSWilliam Juul bi = yaffs_GetBlockInfo(dev, blk); 5415*0e8cc8bdSWilliam Juul yaffs_ClearChunkBits(dev, blk); 5416*0e8cc8bdSWilliam Juul bi->pagesInUse = 0; 5417*0e8cc8bdSWilliam Juul bi->softDeletions = 0; 5418*0e8cc8bdSWilliam Juul 5419*0e8cc8bdSWilliam Juul yaffs_QueryInitialBlockState(dev, blk, &state, &sequenceNumber); 5420*0e8cc8bdSWilliam Juul 5421*0e8cc8bdSWilliam Juul bi->blockState = state; 5422*0e8cc8bdSWilliam Juul bi->sequenceNumber = sequenceNumber; 5423*0e8cc8bdSWilliam Juul 5424*0e8cc8bdSWilliam Juul T(YAFFS_TRACE_SCAN_DEBUG, 5425*0e8cc8bdSWilliam Juul (TSTR("Block scanning block %d state %d seq %d" TENDSTR), blk, 5426*0e8cc8bdSWilliam Juul state, sequenceNumber)); 5427*0e8cc8bdSWilliam Juul 5428*0e8cc8bdSWilliam Juul if (state == YAFFS_BLOCK_STATE_DEAD) { 5429*0e8cc8bdSWilliam Juul T(YAFFS_TRACE_BAD_BLOCKS, 5430*0e8cc8bdSWilliam Juul (TSTR("block %d is bad" TENDSTR), blk)); 5431*0e8cc8bdSWilliam Juul } else if (state == YAFFS_BLOCK_STATE_EMPTY) { 5432*0e8cc8bdSWilliam Juul T(YAFFS_TRACE_SCAN_DEBUG, 5433*0e8cc8bdSWilliam Juul (TSTR("Block empty " TENDSTR))); 5434*0e8cc8bdSWilliam Juul dev->nErasedBlocks++; 5435*0e8cc8bdSWilliam Juul dev->nFreeChunks += dev->nChunksPerBlock; 5436*0e8cc8bdSWilliam Juul } else if (state == YAFFS_BLOCK_STATE_NEEDS_SCANNING) { 5437*0e8cc8bdSWilliam Juul 5438*0e8cc8bdSWilliam Juul /* Determine the highest sequence number */ 5439*0e8cc8bdSWilliam Juul if (dev->isYaffs2 && 5440*0e8cc8bdSWilliam Juul sequenceNumber >= YAFFS_LOWEST_SEQUENCE_NUMBER && 5441*0e8cc8bdSWilliam Juul sequenceNumber < YAFFS_HIGHEST_SEQUENCE_NUMBER) { 5442*0e8cc8bdSWilliam Juul 5443*0e8cc8bdSWilliam Juul blockIndex[nBlocksToScan].seq = sequenceNumber; 5444*0e8cc8bdSWilliam Juul blockIndex[nBlocksToScan].block = blk; 5445*0e8cc8bdSWilliam Juul 5446*0e8cc8bdSWilliam Juul nBlocksToScan++; 5447*0e8cc8bdSWilliam Juul 5448*0e8cc8bdSWilliam Juul if (sequenceNumber >= dev->sequenceNumber) { 5449*0e8cc8bdSWilliam Juul dev->sequenceNumber = sequenceNumber; 5450*0e8cc8bdSWilliam Juul } 5451*0e8cc8bdSWilliam Juul } else if (dev->isYaffs2) { 5452*0e8cc8bdSWilliam Juul /* TODO: Nasty sequence number! */ 5453*0e8cc8bdSWilliam Juul T(YAFFS_TRACE_SCAN, 5454*0e8cc8bdSWilliam Juul (TSTR 5455*0e8cc8bdSWilliam Juul ("Block scanning block %d has bad sequence number %d" 5456*0e8cc8bdSWilliam Juul TENDSTR), blk, sequenceNumber)); 5457*0e8cc8bdSWilliam Juul 5458*0e8cc8bdSWilliam Juul } 5459*0e8cc8bdSWilliam Juul } 5460*0e8cc8bdSWilliam Juul } 5461*0e8cc8bdSWilliam Juul 5462*0e8cc8bdSWilliam Juul /* Sort the blocks 5463*0e8cc8bdSWilliam Juul * Dungy old bubble sort for now... 5464*0e8cc8bdSWilliam Juul */ 5465*0e8cc8bdSWilliam Juul if (dev->isYaffs2) { 5466*0e8cc8bdSWilliam Juul yaffs_BlockIndex temp; 5467*0e8cc8bdSWilliam Juul int i; 5468*0e8cc8bdSWilliam Juul int j; 5469*0e8cc8bdSWilliam Juul 5470*0e8cc8bdSWilliam Juul for (i = 0; i < nBlocksToScan; i++) 5471*0e8cc8bdSWilliam Juul for (j = i + 1; j < nBlocksToScan; j++) 5472*0e8cc8bdSWilliam Juul if (blockIndex[i].seq > blockIndex[j].seq) { 5473*0e8cc8bdSWilliam Juul temp = blockIndex[j]; 5474*0e8cc8bdSWilliam Juul blockIndex[j] = blockIndex[i]; 5475*0e8cc8bdSWilliam Juul blockIndex[i] = temp; 5476*0e8cc8bdSWilliam Juul } 5477*0e8cc8bdSWilliam Juul } 5478*0e8cc8bdSWilliam Juul 5479*0e8cc8bdSWilliam Juul /* Now scan the blocks looking at the data. */ 5480*0e8cc8bdSWilliam Juul if (dev->isYaffs2) { 5481*0e8cc8bdSWilliam Juul startIterator = 0; 5482*0e8cc8bdSWilliam Juul endIterator = nBlocksToScan - 1; 5483*0e8cc8bdSWilliam Juul T(YAFFS_TRACE_SCAN_DEBUG, 5484*0e8cc8bdSWilliam Juul (TSTR("%d blocks to be scanned" TENDSTR), nBlocksToScan)); 5485*0e8cc8bdSWilliam Juul } else { 5486*0e8cc8bdSWilliam Juul startIterator = dev->internalStartBlock; 5487*0e8cc8bdSWilliam Juul endIterator = dev->internalEndBlock; 5488*0e8cc8bdSWilliam Juul } 5489*0e8cc8bdSWilliam Juul 5490*0e8cc8bdSWilliam Juul /* For each block.... */ 5491*0e8cc8bdSWilliam Juul for (blockIterator = startIterator; !alloc_failed && blockIterator <= endIterator; 5492*0e8cc8bdSWilliam Juul blockIterator++) { 5493*0e8cc8bdSWilliam Juul 5494*0e8cc8bdSWilliam Juul if (dev->isYaffs2) { 5495*0e8cc8bdSWilliam Juul /* get the block to scan in the correct order */ 5496*0e8cc8bdSWilliam Juul blk = blockIndex[blockIterator].block; 5497*0e8cc8bdSWilliam Juul } else { 5498*0e8cc8bdSWilliam Juul blk = blockIterator; 5499*0e8cc8bdSWilliam Juul } 5500*0e8cc8bdSWilliam Juul 5501*0e8cc8bdSWilliam Juul bi = yaffs_GetBlockInfo(dev, blk); 5502*0e8cc8bdSWilliam Juul state = bi->blockState; 5503*0e8cc8bdSWilliam Juul 5504*0e8cc8bdSWilliam Juul deleted = 0; 5505*0e8cc8bdSWilliam Juul 5506*0e8cc8bdSWilliam Juul /* For each chunk in each block that needs scanning....*/ 5507*0e8cc8bdSWilliam Juul for (c = 0; !alloc_failed && c < dev->nChunksPerBlock && 5508*0e8cc8bdSWilliam Juul state == YAFFS_BLOCK_STATE_NEEDS_SCANNING; c++) { 5509*0e8cc8bdSWilliam Juul /* Read the tags and decide what to do */ 5510*0e8cc8bdSWilliam Juul chunk = blk * dev->nChunksPerBlock + c; 5511*0e8cc8bdSWilliam Juul 5512*0e8cc8bdSWilliam Juul result = yaffs_ReadChunkWithTagsFromNAND(dev, chunk, NULL, 5513*0e8cc8bdSWilliam Juul &tags); 5514*0e8cc8bdSWilliam Juul 5515*0e8cc8bdSWilliam Juul /* Let's have a good look at this chunk... */ 5516*0e8cc8bdSWilliam Juul 5517*0e8cc8bdSWilliam Juul if (!dev->isYaffs2 && tags.chunkDeleted) { 5518*0e8cc8bdSWilliam Juul /* YAFFS1 only... 5519*0e8cc8bdSWilliam Juul * A deleted chunk 5520*0e8cc8bdSWilliam Juul */ 5521*0e8cc8bdSWilliam Juul deleted++; 5522*0e8cc8bdSWilliam Juul dev->nFreeChunks++; 5523*0e8cc8bdSWilliam Juul /*T((" %d %d deleted\n",blk,c)); */ 5524*0e8cc8bdSWilliam Juul } else if (!tags.chunkUsed) { 5525*0e8cc8bdSWilliam Juul /* An unassigned chunk in the block 5526*0e8cc8bdSWilliam Juul * This means that either the block is empty or 5527*0e8cc8bdSWilliam Juul * this is the one being allocated from 5528*0e8cc8bdSWilliam Juul */ 5529*0e8cc8bdSWilliam Juul 5530*0e8cc8bdSWilliam Juul if (c == 0) { 5531*0e8cc8bdSWilliam Juul /* We're looking at the first chunk in the block so the block is unused */ 5532*0e8cc8bdSWilliam Juul state = YAFFS_BLOCK_STATE_EMPTY; 5533*0e8cc8bdSWilliam Juul dev->nErasedBlocks++; 5534*0e8cc8bdSWilliam Juul } else { 5535*0e8cc8bdSWilliam Juul /* this is the block being allocated from */ 5536*0e8cc8bdSWilliam Juul T(YAFFS_TRACE_SCAN, 5537*0e8cc8bdSWilliam Juul (TSTR 5538*0e8cc8bdSWilliam Juul (" Allocating from %d %d" TENDSTR), 5539*0e8cc8bdSWilliam Juul blk, c)); 5540*0e8cc8bdSWilliam Juul state = YAFFS_BLOCK_STATE_ALLOCATING; 5541*0e8cc8bdSWilliam Juul dev->allocationBlock = blk; 5542*0e8cc8bdSWilliam Juul dev->allocationPage = c; 5543*0e8cc8bdSWilliam Juul dev->allocationBlockFinder = blk; 5544*0e8cc8bdSWilliam Juul /* Set it to here to encourage the allocator to go forth from here. */ 5545*0e8cc8bdSWilliam Juul 5546*0e8cc8bdSWilliam Juul /* Yaffs2 sanity check: 5547*0e8cc8bdSWilliam Juul * This should be the one with the highest sequence number 5548*0e8cc8bdSWilliam Juul */ 5549*0e8cc8bdSWilliam Juul if (dev->isYaffs2 5550*0e8cc8bdSWilliam Juul && (dev->sequenceNumber != 5551*0e8cc8bdSWilliam Juul bi->sequenceNumber)) { 5552*0e8cc8bdSWilliam Juul T(YAFFS_TRACE_ALWAYS, 5553*0e8cc8bdSWilliam Juul (TSTR 5554*0e8cc8bdSWilliam Juul ("yaffs: Allocation block %d was not highest sequence id:" 5555*0e8cc8bdSWilliam Juul " block seq = %d, dev seq = %d" 5556*0e8cc8bdSWilliam Juul TENDSTR), blk,bi->sequenceNumber,dev->sequenceNumber)); 5557*0e8cc8bdSWilliam Juul } 5558*0e8cc8bdSWilliam Juul } 5559*0e8cc8bdSWilliam Juul 5560*0e8cc8bdSWilliam Juul dev->nFreeChunks += (dev->nChunksPerBlock - c); 5561*0e8cc8bdSWilliam Juul } else if (tags.chunkId > 0) { 5562*0e8cc8bdSWilliam Juul /* chunkId > 0 so it is a data chunk... */ 5563*0e8cc8bdSWilliam Juul unsigned int endpos; 5564*0e8cc8bdSWilliam Juul 5565*0e8cc8bdSWilliam Juul yaffs_SetChunkBit(dev, blk, c); 5566*0e8cc8bdSWilliam Juul bi->pagesInUse++; 5567*0e8cc8bdSWilliam Juul 5568*0e8cc8bdSWilliam Juul in = yaffs_FindOrCreateObjectByNumber(dev, 5569*0e8cc8bdSWilliam Juul tags. 5570*0e8cc8bdSWilliam Juul objectId, 5571*0e8cc8bdSWilliam Juul YAFFS_OBJECT_TYPE_FILE); 5572*0e8cc8bdSWilliam Juul /* PutChunkIntoFile checks for a clash (two data chunks with 5573*0e8cc8bdSWilliam Juul * the same chunkId). 5574*0e8cc8bdSWilliam Juul */ 5575*0e8cc8bdSWilliam Juul 5576*0e8cc8bdSWilliam Juul if(!in) 5577*0e8cc8bdSWilliam Juul alloc_failed = 1; 5578*0e8cc8bdSWilliam Juul 5579*0e8cc8bdSWilliam Juul if(in){ 5580*0e8cc8bdSWilliam Juul if(!yaffs_PutChunkIntoFile(in, tags.chunkId, chunk,1)) 5581*0e8cc8bdSWilliam Juul alloc_failed = 1; 5582*0e8cc8bdSWilliam Juul } 5583*0e8cc8bdSWilliam Juul 5584*0e8cc8bdSWilliam Juul endpos = 5585*0e8cc8bdSWilliam Juul (tags.chunkId - 1) * dev->nDataBytesPerChunk + 5586*0e8cc8bdSWilliam Juul tags.byteCount; 5587*0e8cc8bdSWilliam Juul if (in && 5588*0e8cc8bdSWilliam Juul in->variantType == YAFFS_OBJECT_TYPE_FILE 5589*0e8cc8bdSWilliam Juul && in->variant.fileVariant.scannedFileSize < 5590*0e8cc8bdSWilliam Juul endpos) { 5591*0e8cc8bdSWilliam Juul in->variant.fileVariant. 5592*0e8cc8bdSWilliam Juul scannedFileSize = endpos; 5593*0e8cc8bdSWilliam Juul if (!dev->useHeaderFileSize) { 5594*0e8cc8bdSWilliam Juul in->variant.fileVariant. 5595*0e8cc8bdSWilliam Juul fileSize = 5596*0e8cc8bdSWilliam Juul in->variant.fileVariant. 5597*0e8cc8bdSWilliam Juul scannedFileSize; 5598*0e8cc8bdSWilliam Juul } 5599*0e8cc8bdSWilliam Juul 5600*0e8cc8bdSWilliam Juul } 5601*0e8cc8bdSWilliam Juul /* T((" %d %d data %d %d\n",blk,c,tags.objectId,tags.chunkId)); */ 5602*0e8cc8bdSWilliam Juul } else { 5603*0e8cc8bdSWilliam Juul /* chunkId == 0, so it is an ObjectHeader. 5604*0e8cc8bdSWilliam Juul * Thus, we read in the object header and make the object 5605*0e8cc8bdSWilliam Juul */ 5606*0e8cc8bdSWilliam Juul yaffs_SetChunkBit(dev, blk, c); 5607*0e8cc8bdSWilliam Juul bi->pagesInUse++; 5608*0e8cc8bdSWilliam Juul 5609*0e8cc8bdSWilliam Juul result = yaffs_ReadChunkWithTagsFromNAND(dev, chunk, 5610*0e8cc8bdSWilliam Juul chunkData, 5611*0e8cc8bdSWilliam Juul NULL); 5612*0e8cc8bdSWilliam Juul 5613*0e8cc8bdSWilliam Juul oh = (yaffs_ObjectHeader *) chunkData; 5614*0e8cc8bdSWilliam Juul 5615*0e8cc8bdSWilliam Juul in = yaffs_FindObjectByNumber(dev, 5616*0e8cc8bdSWilliam Juul tags.objectId); 5617*0e8cc8bdSWilliam Juul if (in && in->variantType != oh->type) { 5618*0e8cc8bdSWilliam Juul /* This should not happen, but somehow 5619*0e8cc8bdSWilliam Juul * Wev'e ended up with an objectId that has been reused but not yet 5620*0e8cc8bdSWilliam Juul * deleted, and worse still it has changed type. Delete the old object. 5621*0e8cc8bdSWilliam Juul */ 5622*0e8cc8bdSWilliam Juul 5623*0e8cc8bdSWilliam Juul yaffs_DestroyObject(in); 5624*0e8cc8bdSWilliam Juul 5625*0e8cc8bdSWilliam Juul in = 0; 5626*0e8cc8bdSWilliam Juul } 5627*0e8cc8bdSWilliam Juul 5628*0e8cc8bdSWilliam Juul in = yaffs_FindOrCreateObjectByNumber(dev, 5629*0e8cc8bdSWilliam Juul tags. 5630*0e8cc8bdSWilliam Juul objectId, 5631*0e8cc8bdSWilliam Juul oh->type); 5632*0e8cc8bdSWilliam Juul 5633*0e8cc8bdSWilliam Juul if(!in) 5634*0e8cc8bdSWilliam Juul alloc_failed = 1; 5635*0e8cc8bdSWilliam Juul 5636*0e8cc8bdSWilliam Juul if (in && oh->shadowsObject > 0) { 5637*0e8cc8bdSWilliam Juul yaffs_HandleShadowedObject(dev, 5638*0e8cc8bdSWilliam Juul oh-> 5639*0e8cc8bdSWilliam Juul shadowsObject, 5640*0e8cc8bdSWilliam Juul 0); 5641*0e8cc8bdSWilliam Juul } 5642*0e8cc8bdSWilliam Juul 5643*0e8cc8bdSWilliam Juul if (in && in->valid) { 5644*0e8cc8bdSWilliam Juul /* We have already filled this one. We have a duplicate and need to resolve it. */ 5645*0e8cc8bdSWilliam Juul 5646*0e8cc8bdSWilliam Juul unsigned existingSerial = in->serial; 5647*0e8cc8bdSWilliam Juul unsigned newSerial = tags.serialNumber; 5648*0e8cc8bdSWilliam Juul 5649*0e8cc8bdSWilliam Juul if (dev->isYaffs2 || 5650*0e8cc8bdSWilliam Juul ((existingSerial + 1) & 3) == 5651*0e8cc8bdSWilliam Juul newSerial) { 5652*0e8cc8bdSWilliam Juul /* Use new one - destroy the exisiting one */ 5653*0e8cc8bdSWilliam Juul yaffs_DeleteChunk(dev, 5654*0e8cc8bdSWilliam Juul in->chunkId, 5655*0e8cc8bdSWilliam Juul 1, __LINE__); 5656*0e8cc8bdSWilliam Juul in->valid = 0; 5657*0e8cc8bdSWilliam Juul } else { 5658*0e8cc8bdSWilliam Juul /* Use existing - destroy this one. */ 5659*0e8cc8bdSWilliam Juul yaffs_DeleteChunk(dev, chunk, 1, 5660*0e8cc8bdSWilliam Juul __LINE__); 5661*0e8cc8bdSWilliam Juul } 5662*0e8cc8bdSWilliam Juul } 5663*0e8cc8bdSWilliam Juul 5664*0e8cc8bdSWilliam Juul if (in && !in->valid && 5665*0e8cc8bdSWilliam Juul (tags.objectId == YAFFS_OBJECTID_ROOT || 5666*0e8cc8bdSWilliam Juul tags.objectId == YAFFS_OBJECTID_LOSTNFOUND)) { 5667*0e8cc8bdSWilliam Juul /* We only load some info, don't fiddle with directory structure */ 5668*0e8cc8bdSWilliam Juul in->valid = 1; 5669*0e8cc8bdSWilliam Juul in->variantType = oh->type; 5670*0e8cc8bdSWilliam Juul 5671*0e8cc8bdSWilliam Juul in->yst_mode = oh->yst_mode; 5672*0e8cc8bdSWilliam Juul #ifdef CONFIG_YAFFS_WINCE 5673*0e8cc8bdSWilliam Juul in->win_atime[0] = oh->win_atime[0]; 5674*0e8cc8bdSWilliam Juul in->win_ctime[0] = oh->win_ctime[0]; 5675*0e8cc8bdSWilliam Juul in->win_mtime[0] = oh->win_mtime[0]; 5676*0e8cc8bdSWilliam Juul in->win_atime[1] = oh->win_atime[1]; 5677*0e8cc8bdSWilliam Juul in->win_ctime[1] = oh->win_ctime[1]; 5678*0e8cc8bdSWilliam Juul in->win_mtime[1] = oh->win_mtime[1]; 5679*0e8cc8bdSWilliam Juul #else 5680*0e8cc8bdSWilliam Juul in->yst_uid = oh->yst_uid; 5681*0e8cc8bdSWilliam Juul in->yst_gid = oh->yst_gid; 5682*0e8cc8bdSWilliam Juul in->yst_atime = oh->yst_atime; 5683*0e8cc8bdSWilliam Juul in->yst_mtime = oh->yst_mtime; 5684*0e8cc8bdSWilliam Juul in->yst_ctime = oh->yst_ctime; 5685*0e8cc8bdSWilliam Juul in->yst_rdev = oh->yst_rdev; 5686*0e8cc8bdSWilliam Juul #endif 5687*0e8cc8bdSWilliam Juul in->chunkId = chunk; 5688*0e8cc8bdSWilliam Juul 5689*0e8cc8bdSWilliam Juul } else if (in && !in->valid) { 5690*0e8cc8bdSWilliam Juul /* we need to load this info */ 5691*0e8cc8bdSWilliam Juul 5692*0e8cc8bdSWilliam Juul in->valid = 1; 5693*0e8cc8bdSWilliam Juul in->variantType = oh->type; 5694*0e8cc8bdSWilliam Juul 5695*0e8cc8bdSWilliam Juul in->yst_mode = oh->yst_mode; 5696*0e8cc8bdSWilliam Juul #ifdef CONFIG_YAFFS_WINCE 5697*0e8cc8bdSWilliam Juul in->win_atime[0] = oh->win_atime[0]; 5698*0e8cc8bdSWilliam Juul in->win_ctime[0] = oh->win_ctime[0]; 5699*0e8cc8bdSWilliam Juul in->win_mtime[0] = oh->win_mtime[0]; 5700*0e8cc8bdSWilliam Juul in->win_atime[1] = oh->win_atime[1]; 5701*0e8cc8bdSWilliam Juul in->win_ctime[1] = oh->win_ctime[1]; 5702*0e8cc8bdSWilliam Juul in->win_mtime[1] = oh->win_mtime[1]; 5703*0e8cc8bdSWilliam Juul #else 5704*0e8cc8bdSWilliam Juul in->yst_uid = oh->yst_uid; 5705*0e8cc8bdSWilliam Juul in->yst_gid = oh->yst_gid; 5706*0e8cc8bdSWilliam Juul in->yst_atime = oh->yst_atime; 5707*0e8cc8bdSWilliam Juul in->yst_mtime = oh->yst_mtime; 5708*0e8cc8bdSWilliam Juul in->yst_ctime = oh->yst_ctime; 5709*0e8cc8bdSWilliam Juul in->yst_rdev = oh->yst_rdev; 5710*0e8cc8bdSWilliam Juul #endif 5711*0e8cc8bdSWilliam Juul in->chunkId = chunk; 5712*0e8cc8bdSWilliam Juul 5713*0e8cc8bdSWilliam Juul yaffs_SetObjectName(in, oh->name); 5714*0e8cc8bdSWilliam Juul in->dirty = 0; 5715*0e8cc8bdSWilliam Juul 5716*0e8cc8bdSWilliam Juul /* directory stuff... 5717*0e8cc8bdSWilliam Juul * hook up to parent 5718*0e8cc8bdSWilliam Juul */ 5719*0e8cc8bdSWilliam Juul 5720*0e8cc8bdSWilliam Juul parent = 5721*0e8cc8bdSWilliam Juul yaffs_FindOrCreateObjectByNumber 5722*0e8cc8bdSWilliam Juul (dev, oh->parentObjectId, 5723*0e8cc8bdSWilliam Juul YAFFS_OBJECT_TYPE_DIRECTORY); 5724*0e8cc8bdSWilliam Juul if (parent->variantType == 5725*0e8cc8bdSWilliam Juul YAFFS_OBJECT_TYPE_UNKNOWN) { 5726*0e8cc8bdSWilliam Juul /* Set up as a directory */ 5727*0e8cc8bdSWilliam Juul parent->variantType = 5728*0e8cc8bdSWilliam Juul YAFFS_OBJECT_TYPE_DIRECTORY; 5729*0e8cc8bdSWilliam Juul INIT_LIST_HEAD(&parent->variant. 5730*0e8cc8bdSWilliam Juul directoryVariant. 5731*0e8cc8bdSWilliam Juul children); 5732*0e8cc8bdSWilliam Juul } else if (parent->variantType != 5733*0e8cc8bdSWilliam Juul YAFFS_OBJECT_TYPE_DIRECTORY) 5734*0e8cc8bdSWilliam Juul { 5735*0e8cc8bdSWilliam Juul /* Hoosterman, another problem.... 5736*0e8cc8bdSWilliam Juul * We're trying to use a non-directory as a directory 5737*0e8cc8bdSWilliam Juul */ 5738*0e8cc8bdSWilliam Juul 5739*0e8cc8bdSWilliam Juul T(YAFFS_TRACE_ERROR, 5740*0e8cc8bdSWilliam Juul (TSTR 5741*0e8cc8bdSWilliam Juul ("yaffs tragedy: attempting to use non-directory as" 5742*0e8cc8bdSWilliam Juul " a directory in scan. Put in lost+found." 5743*0e8cc8bdSWilliam Juul TENDSTR))); 5744*0e8cc8bdSWilliam Juul parent = dev->lostNFoundDir; 5745*0e8cc8bdSWilliam Juul } 5746*0e8cc8bdSWilliam Juul 5747*0e8cc8bdSWilliam Juul yaffs_AddObjectToDirectory(parent, in); 5748*0e8cc8bdSWilliam Juul 5749*0e8cc8bdSWilliam Juul if (0 && (parent == dev->deletedDir || 5750*0e8cc8bdSWilliam Juul parent == dev->unlinkedDir)) { 5751*0e8cc8bdSWilliam Juul in->deleted = 1; /* If it is unlinked at start up then it wants deleting */ 5752*0e8cc8bdSWilliam Juul dev->nDeletedFiles++; 5753*0e8cc8bdSWilliam Juul } 5754*0e8cc8bdSWilliam Juul /* Note re hardlinks. 5755*0e8cc8bdSWilliam Juul * Since we might scan a hardlink before its equivalent object is scanned 5756*0e8cc8bdSWilliam Juul * we put them all in a list. 5757*0e8cc8bdSWilliam Juul * After scanning is complete, we should have all the objects, so we run through this 5758*0e8cc8bdSWilliam Juul * list and fix up all the chains. 5759*0e8cc8bdSWilliam Juul */ 5760*0e8cc8bdSWilliam Juul 5761*0e8cc8bdSWilliam Juul switch (in->variantType) { 5762*0e8cc8bdSWilliam Juul case YAFFS_OBJECT_TYPE_UNKNOWN: 5763*0e8cc8bdSWilliam Juul /* Todo got a problem */ 5764*0e8cc8bdSWilliam Juul break; 5765*0e8cc8bdSWilliam Juul case YAFFS_OBJECT_TYPE_FILE: 5766*0e8cc8bdSWilliam Juul if (dev->isYaffs2 5767*0e8cc8bdSWilliam Juul && oh->isShrink) { 5768*0e8cc8bdSWilliam Juul /* Prune back the shrunken chunks */ 5769*0e8cc8bdSWilliam Juul yaffs_PruneResizedChunks 5770*0e8cc8bdSWilliam Juul (in, oh->fileSize); 5771*0e8cc8bdSWilliam Juul /* Mark the block as having a shrinkHeader */ 5772*0e8cc8bdSWilliam Juul bi->hasShrinkHeader = 1; 5773*0e8cc8bdSWilliam Juul } 5774*0e8cc8bdSWilliam Juul 5775*0e8cc8bdSWilliam Juul if (dev->useHeaderFileSize) 5776*0e8cc8bdSWilliam Juul 5777*0e8cc8bdSWilliam Juul in->variant.fileVariant. 5778*0e8cc8bdSWilliam Juul fileSize = 5779*0e8cc8bdSWilliam Juul oh->fileSize; 5780*0e8cc8bdSWilliam Juul 5781*0e8cc8bdSWilliam Juul break; 5782*0e8cc8bdSWilliam Juul case YAFFS_OBJECT_TYPE_HARDLINK: 5783*0e8cc8bdSWilliam Juul in->variant.hardLinkVariant. 5784*0e8cc8bdSWilliam Juul equivalentObjectId = 5785*0e8cc8bdSWilliam Juul oh->equivalentObjectId; 5786*0e8cc8bdSWilliam Juul in->hardLinks.next = 5787*0e8cc8bdSWilliam Juul (struct list_head *) 5788*0e8cc8bdSWilliam Juul hardList; 5789*0e8cc8bdSWilliam Juul hardList = in; 5790*0e8cc8bdSWilliam Juul break; 5791*0e8cc8bdSWilliam Juul case YAFFS_OBJECT_TYPE_DIRECTORY: 5792*0e8cc8bdSWilliam Juul /* Do nothing */ 5793*0e8cc8bdSWilliam Juul break; 5794*0e8cc8bdSWilliam Juul case YAFFS_OBJECT_TYPE_SPECIAL: 5795*0e8cc8bdSWilliam Juul /* Do nothing */ 5796*0e8cc8bdSWilliam Juul break; 5797*0e8cc8bdSWilliam Juul case YAFFS_OBJECT_TYPE_SYMLINK: 5798*0e8cc8bdSWilliam Juul in->variant.symLinkVariant.alias = 5799*0e8cc8bdSWilliam Juul yaffs_CloneString(oh->alias); 5800*0e8cc8bdSWilliam Juul if(!in->variant.symLinkVariant.alias) 5801*0e8cc8bdSWilliam Juul alloc_failed = 1; 5802*0e8cc8bdSWilliam Juul break; 5803*0e8cc8bdSWilliam Juul } 5804*0e8cc8bdSWilliam Juul 5805*0e8cc8bdSWilliam Juul if (parent == dev->deletedDir) { 5806*0e8cc8bdSWilliam Juul yaffs_DestroyObject(in); 5807*0e8cc8bdSWilliam Juul bi->hasShrinkHeader = 1; 5808*0e8cc8bdSWilliam Juul } 5809*0e8cc8bdSWilliam Juul } 5810*0e8cc8bdSWilliam Juul } 5811*0e8cc8bdSWilliam Juul } 5812*0e8cc8bdSWilliam Juul 5813*0e8cc8bdSWilliam Juul if (state == YAFFS_BLOCK_STATE_NEEDS_SCANNING) { 5814*0e8cc8bdSWilliam Juul /* If we got this far while scanning, then the block is fully allocated.*/ 5815*0e8cc8bdSWilliam Juul state = YAFFS_BLOCK_STATE_FULL; 5816*0e8cc8bdSWilliam Juul } 5817*0e8cc8bdSWilliam Juul 5818*0e8cc8bdSWilliam Juul bi->blockState = state; 5819*0e8cc8bdSWilliam Juul 5820*0e8cc8bdSWilliam Juul /* Now let's see if it was dirty */ 5821*0e8cc8bdSWilliam Juul if (bi->pagesInUse == 0 && 5822*0e8cc8bdSWilliam Juul !bi->hasShrinkHeader && 5823*0e8cc8bdSWilliam Juul bi->blockState == YAFFS_BLOCK_STATE_FULL) { 5824*0e8cc8bdSWilliam Juul yaffs_BlockBecameDirty(dev, blk); 5825*0e8cc8bdSWilliam Juul } 5826*0e8cc8bdSWilliam Juul 5827*0e8cc8bdSWilliam Juul } 5828*0e8cc8bdSWilliam Juul 5829*0e8cc8bdSWilliam Juul if (blockIndex) { 5830*0e8cc8bdSWilliam Juul YFREE(blockIndex); 5831*0e8cc8bdSWilliam Juul } 5832*0e8cc8bdSWilliam Juul 5833*0e8cc8bdSWilliam Juul 5834*0e8cc8bdSWilliam Juul /* Ok, we've done all the scanning. 5835*0e8cc8bdSWilliam Juul * Fix up the hard link chains. 5836*0e8cc8bdSWilliam Juul * We should now have scanned all the objects, now it's time to add these 5837*0e8cc8bdSWilliam Juul * hardlinks. 5838*0e8cc8bdSWilliam Juul */ 5839*0e8cc8bdSWilliam Juul 5840*0e8cc8bdSWilliam Juul yaffs_HardlinkFixup(dev,hardList); 5841*0e8cc8bdSWilliam Juul 5842*0e8cc8bdSWilliam Juul /* Handle the unlinked files. Since they were left in an unlinked state we should 5843*0e8cc8bdSWilliam Juul * just delete them. 5844*0e8cc8bdSWilliam Juul */ 5845*0e8cc8bdSWilliam Juul { 5846*0e8cc8bdSWilliam Juul struct list_head *i; 5847*0e8cc8bdSWilliam Juul struct list_head *n; 5848*0e8cc8bdSWilliam Juul 5849*0e8cc8bdSWilliam Juul yaffs_Object *l; 5850*0e8cc8bdSWilliam Juul /* Soft delete all the unlinked files */ 5851*0e8cc8bdSWilliam Juul list_for_each_safe(i, n, 5852*0e8cc8bdSWilliam Juul &dev->unlinkedDir->variant.directoryVariant. 5853*0e8cc8bdSWilliam Juul children) { 5854*0e8cc8bdSWilliam Juul if (i) { 5855*0e8cc8bdSWilliam Juul l = list_entry(i, yaffs_Object, siblings); 5856*0e8cc8bdSWilliam Juul yaffs_DestroyObject(l); 5857*0e8cc8bdSWilliam Juul } 5858*0e8cc8bdSWilliam Juul } 5859*0e8cc8bdSWilliam Juul } 5860*0e8cc8bdSWilliam Juul 5861*0e8cc8bdSWilliam Juul yaffs_ReleaseTempBuffer(dev, chunkData, __LINE__); 5862*0e8cc8bdSWilliam Juul 5863*0e8cc8bdSWilliam Juul if(alloc_failed){ 5864*0e8cc8bdSWilliam Juul return YAFFS_FAIL; 5865*0e8cc8bdSWilliam Juul } 5866*0e8cc8bdSWilliam Juul 5867*0e8cc8bdSWilliam Juul T(YAFFS_TRACE_SCAN, (TSTR("yaffs_Scan ends" TENDSTR))); 5868*0e8cc8bdSWilliam Juul 5869*0e8cc8bdSWilliam Juul 5870*0e8cc8bdSWilliam Juul return YAFFS_OK; 5871*0e8cc8bdSWilliam Juul } 5872*0e8cc8bdSWilliam Juul 5873*0e8cc8bdSWilliam Juul static void yaffs_CheckObjectDetailsLoaded(yaffs_Object *in) 5874*0e8cc8bdSWilliam Juul { 5875*0e8cc8bdSWilliam Juul __u8 *chunkData; 5876*0e8cc8bdSWilliam Juul yaffs_ObjectHeader *oh; 5877*0e8cc8bdSWilliam Juul yaffs_Device *dev = in->myDev; 5878*0e8cc8bdSWilliam Juul yaffs_ExtendedTags tags; 5879*0e8cc8bdSWilliam Juul int result; 5880*0e8cc8bdSWilliam Juul int alloc_failed = 0; 5881*0e8cc8bdSWilliam Juul 5882*0e8cc8bdSWilliam Juul if(!in) 5883*0e8cc8bdSWilliam Juul return; 5884*0e8cc8bdSWilliam Juul 5885*0e8cc8bdSWilliam Juul #if 0 5886*0e8cc8bdSWilliam Juul T(YAFFS_TRACE_SCAN,(TSTR("details for object %d %s loaded" TENDSTR), 5887*0e8cc8bdSWilliam Juul in->objectId, 5888*0e8cc8bdSWilliam Juul in->lazyLoaded ? "not yet" : "already")); 5889*0e8cc8bdSWilliam Juul #endif 5890*0e8cc8bdSWilliam Juul 5891*0e8cc8bdSWilliam Juul if(in->lazyLoaded){ 5892*0e8cc8bdSWilliam Juul in->lazyLoaded = 0; 5893*0e8cc8bdSWilliam Juul chunkData = yaffs_GetTempBuffer(dev, __LINE__); 5894*0e8cc8bdSWilliam Juul 5895*0e8cc8bdSWilliam Juul result = yaffs_ReadChunkWithTagsFromNAND(dev,in->chunkId,chunkData,&tags); 5896*0e8cc8bdSWilliam Juul oh = (yaffs_ObjectHeader *) chunkData; 5897*0e8cc8bdSWilliam Juul 5898*0e8cc8bdSWilliam Juul in->yst_mode = oh->yst_mode; 5899*0e8cc8bdSWilliam Juul #ifdef CONFIG_YAFFS_WINCE 5900*0e8cc8bdSWilliam Juul in->win_atime[0] = oh->win_atime[0]; 5901*0e8cc8bdSWilliam Juul in->win_ctime[0] = oh->win_ctime[0]; 5902*0e8cc8bdSWilliam Juul in->win_mtime[0] = oh->win_mtime[0]; 5903*0e8cc8bdSWilliam Juul in->win_atime[1] = oh->win_atime[1]; 5904*0e8cc8bdSWilliam Juul in->win_ctime[1] = oh->win_ctime[1]; 5905*0e8cc8bdSWilliam Juul in->win_mtime[1] = oh->win_mtime[1]; 5906*0e8cc8bdSWilliam Juul #else 5907*0e8cc8bdSWilliam Juul in->yst_uid = oh->yst_uid; 5908*0e8cc8bdSWilliam Juul in->yst_gid = oh->yst_gid; 5909*0e8cc8bdSWilliam Juul in->yst_atime = oh->yst_atime; 5910*0e8cc8bdSWilliam Juul in->yst_mtime = oh->yst_mtime; 5911*0e8cc8bdSWilliam Juul in->yst_ctime = oh->yst_ctime; 5912*0e8cc8bdSWilliam Juul in->yst_rdev = oh->yst_rdev; 5913*0e8cc8bdSWilliam Juul 5914*0e8cc8bdSWilliam Juul #endif 5915*0e8cc8bdSWilliam Juul yaffs_SetObjectName(in, oh->name); 5916*0e8cc8bdSWilliam Juul 5917*0e8cc8bdSWilliam Juul if(in->variantType == YAFFS_OBJECT_TYPE_SYMLINK){ 5918*0e8cc8bdSWilliam Juul in->variant.symLinkVariant.alias = 5919*0e8cc8bdSWilliam Juul yaffs_CloneString(oh->alias); 5920*0e8cc8bdSWilliam Juul if(!in->variant.symLinkVariant.alias) 5921*0e8cc8bdSWilliam Juul alloc_failed = 1; /* Not returned to caller */ 5922*0e8cc8bdSWilliam Juul } 5923*0e8cc8bdSWilliam Juul 5924*0e8cc8bdSWilliam Juul yaffs_ReleaseTempBuffer(dev,chunkData, __LINE__); 5925*0e8cc8bdSWilliam Juul } 5926*0e8cc8bdSWilliam Juul } 5927*0e8cc8bdSWilliam Juul 5928*0e8cc8bdSWilliam Juul static int yaffs_ScanBackwards(yaffs_Device * dev) 5929*0e8cc8bdSWilliam Juul { 5930*0e8cc8bdSWilliam Juul yaffs_ExtendedTags tags; 5931*0e8cc8bdSWilliam Juul int blk; 5932*0e8cc8bdSWilliam Juul int blockIterator; 5933*0e8cc8bdSWilliam Juul int startIterator; 5934*0e8cc8bdSWilliam Juul int endIterator; 5935*0e8cc8bdSWilliam Juul int nBlocksToScan = 0; 5936*0e8cc8bdSWilliam Juul 5937*0e8cc8bdSWilliam Juul int chunk; 5938*0e8cc8bdSWilliam Juul int result; 5939*0e8cc8bdSWilliam Juul int c; 5940*0e8cc8bdSWilliam Juul int deleted; 5941*0e8cc8bdSWilliam Juul yaffs_BlockState state; 5942*0e8cc8bdSWilliam Juul yaffs_Object *hardList = NULL; 5943*0e8cc8bdSWilliam Juul yaffs_BlockInfo *bi; 5944*0e8cc8bdSWilliam Juul int sequenceNumber; 5945*0e8cc8bdSWilliam Juul yaffs_ObjectHeader *oh; 5946*0e8cc8bdSWilliam Juul yaffs_Object *in; 5947*0e8cc8bdSWilliam Juul yaffs_Object *parent; 5948*0e8cc8bdSWilliam Juul int nBlocks = dev->internalEndBlock - dev->internalStartBlock + 1; 5949*0e8cc8bdSWilliam Juul int itsUnlinked; 5950*0e8cc8bdSWilliam Juul __u8 *chunkData; 5951*0e8cc8bdSWilliam Juul 5952*0e8cc8bdSWilliam Juul int fileSize; 5953*0e8cc8bdSWilliam Juul int isShrink; 5954*0e8cc8bdSWilliam Juul int foundChunksInBlock; 5955*0e8cc8bdSWilliam Juul int equivalentObjectId; 5956*0e8cc8bdSWilliam Juul int alloc_failed = 0; 5957*0e8cc8bdSWilliam Juul 5958*0e8cc8bdSWilliam Juul 5959*0e8cc8bdSWilliam Juul yaffs_BlockIndex *blockIndex = NULL; 5960*0e8cc8bdSWilliam Juul int altBlockIndex = 0; 5961*0e8cc8bdSWilliam Juul 5962*0e8cc8bdSWilliam Juul if (!dev->isYaffs2) { 5963*0e8cc8bdSWilliam Juul T(YAFFS_TRACE_SCAN, 5964*0e8cc8bdSWilliam Juul (TSTR("yaffs_ScanBackwards is only for YAFFS2!" TENDSTR))); 5965*0e8cc8bdSWilliam Juul return YAFFS_FAIL; 5966*0e8cc8bdSWilliam Juul } 5967*0e8cc8bdSWilliam Juul 5968*0e8cc8bdSWilliam Juul T(YAFFS_TRACE_SCAN, 5969*0e8cc8bdSWilliam Juul (TSTR 5970*0e8cc8bdSWilliam Juul ("yaffs_ScanBackwards starts intstartblk %d intendblk %d..." 5971*0e8cc8bdSWilliam Juul TENDSTR), dev->internalStartBlock, dev->internalEndBlock)); 5972*0e8cc8bdSWilliam Juul 5973*0e8cc8bdSWilliam Juul 5974*0e8cc8bdSWilliam Juul dev->sequenceNumber = YAFFS_LOWEST_SEQUENCE_NUMBER; 5975*0e8cc8bdSWilliam Juul 5976*0e8cc8bdSWilliam Juul blockIndex = YMALLOC(nBlocks * sizeof(yaffs_BlockIndex)); 5977*0e8cc8bdSWilliam Juul 5978*0e8cc8bdSWilliam Juul if(!blockIndex) { 5979*0e8cc8bdSWilliam Juul blockIndex = YMALLOC_ALT(nBlocks * sizeof(yaffs_BlockIndex)); 5980*0e8cc8bdSWilliam Juul altBlockIndex = 1; 5981*0e8cc8bdSWilliam Juul } 5982*0e8cc8bdSWilliam Juul 5983*0e8cc8bdSWilliam Juul if(!blockIndex) { 5984*0e8cc8bdSWilliam Juul T(YAFFS_TRACE_SCAN, 5985*0e8cc8bdSWilliam Juul (TSTR("yaffs_Scan() could not allocate block index!" TENDSTR))); 5986*0e8cc8bdSWilliam Juul return YAFFS_FAIL; 5987*0e8cc8bdSWilliam Juul } 5988*0e8cc8bdSWilliam Juul 5989*0e8cc8bdSWilliam Juul dev->blocksInCheckpoint = 0; 5990*0e8cc8bdSWilliam Juul 5991*0e8cc8bdSWilliam Juul chunkData = yaffs_GetTempBuffer(dev, __LINE__); 5992*0e8cc8bdSWilliam Juul 5993*0e8cc8bdSWilliam Juul /* Scan all the blocks to determine their state */ 5994*0e8cc8bdSWilliam Juul for (blk = dev->internalStartBlock; blk <= dev->internalEndBlock; blk++) { 5995*0e8cc8bdSWilliam Juul bi = yaffs_GetBlockInfo(dev, blk); 5996*0e8cc8bdSWilliam Juul yaffs_ClearChunkBits(dev, blk); 5997*0e8cc8bdSWilliam Juul bi->pagesInUse = 0; 5998*0e8cc8bdSWilliam Juul bi->softDeletions = 0; 5999*0e8cc8bdSWilliam Juul 6000*0e8cc8bdSWilliam Juul yaffs_QueryInitialBlockState(dev, blk, &state, &sequenceNumber); 6001*0e8cc8bdSWilliam Juul 6002*0e8cc8bdSWilliam Juul bi->blockState = state; 6003*0e8cc8bdSWilliam Juul bi->sequenceNumber = sequenceNumber; 6004*0e8cc8bdSWilliam Juul 6005*0e8cc8bdSWilliam Juul if(bi->sequenceNumber == YAFFS_SEQUENCE_CHECKPOINT_DATA) 6006*0e8cc8bdSWilliam Juul bi->blockState = state = YAFFS_BLOCK_STATE_CHECKPOINT; 6007*0e8cc8bdSWilliam Juul 6008*0e8cc8bdSWilliam Juul T(YAFFS_TRACE_SCAN_DEBUG, 6009*0e8cc8bdSWilliam Juul (TSTR("Block scanning block %d state %d seq %d" TENDSTR), blk, 6010*0e8cc8bdSWilliam Juul state, sequenceNumber)); 6011*0e8cc8bdSWilliam Juul 6012*0e8cc8bdSWilliam Juul 6013*0e8cc8bdSWilliam Juul if(state == YAFFS_BLOCK_STATE_CHECKPOINT){ 6014*0e8cc8bdSWilliam Juul dev->blocksInCheckpoint++; 6015*0e8cc8bdSWilliam Juul 6016*0e8cc8bdSWilliam Juul } else if (state == YAFFS_BLOCK_STATE_DEAD) { 6017*0e8cc8bdSWilliam Juul T(YAFFS_TRACE_BAD_BLOCKS, 6018*0e8cc8bdSWilliam Juul (TSTR("block %d is bad" TENDSTR), blk)); 6019*0e8cc8bdSWilliam Juul } else if (state == YAFFS_BLOCK_STATE_EMPTY) { 6020*0e8cc8bdSWilliam Juul T(YAFFS_TRACE_SCAN_DEBUG, 6021*0e8cc8bdSWilliam Juul (TSTR("Block empty " TENDSTR))); 6022*0e8cc8bdSWilliam Juul dev->nErasedBlocks++; 6023*0e8cc8bdSWilliam Juul dev->nFreeChunks += dev->nChunksPerBlock; 6024*0e8cc8bdSWilliam Juul } else if (state == YAFFS_BLOCK_STATE_NEEDS_SCANNING) { 6025*0e8cc8bdSWilliam Juul 6026*0e8cc8bdSWilliam Juul /* Determine the highest sequence number */ 6027*0e8cc8bdSWilliam Juul if (dev->isYaffs2 && 6028*0e8cc8bdSWilliam Juul sequenceNumber >= YAFFS_LOWEST_SEQUENCE_NUMBER && 6029*0e8cc8bdSWilliam Juul sequenceNumber < YAFFS_HIGHEST_SEQUENCE_NUMBER) { 6030*0e8cc8bdSWilliam Juul 6031*0e8cc8bdSWilliam Juul blockIndex[nBlocksToScan].seq = sequenceNumber; 6032*0e8cc8bdSWilliam Juul blockIndex[nBlocksToScan].block = blk; 6033*0e8cc8bdSWilliam Juul 6034*0e8cc8bdSWilliam Juul nBlocksToScan++; 6035*0e8cc8bdSWilliam Juul 6036*0e8cc8bdSWilliam Juul if (sequenceNumber >= dev->sequenceNumber) { 6037*0e8cc8bdSWilliam Juul dev->sequenceNumber = sequenceNumber; 6038*0e8cc8bdSWilliam Juul } 6039*0e8cc8bdSWilliam Juul } else if (dev->isYaffs2) { 6040*0e8cc8bdSWilliam Juul /* TODO: Nasty sequence number! */ 6041*0e8cc8bdSWilliam Juul T(YAFFS_TRACE_SCAN, 6042*0e8cc8bdSWilliam Juul (TSTR 6043*0e8cc8bdSWilliam Juul ("Block scanning block %d has bad sequence number %d" 6044*0e8cc8bdSWilliam Juul TENDSTR), blk, sequenceNumber)); 6045*0e8cc8bdSWilliam Juul 6046*0e8cc8bdSWilliam Juul } 6047*0e8cc8bdSWilliam Juul } 6048*0e8cc8bdSWilliam Juul } 6049*0e8cc8bdSWilliam Juul 6050*0e8cc8bdSWilliam Juul T(YAFFS_TRACE_SCAN, 6051*0e8cc8bdSWilliam Juul (TSTR("%d blocks to be sorted..." TENDSTR), nBlocksToScan)); 6052*0e8cc8bdSWilliam Juul 6053*0e8cc8bdSWilliam Juul 6054*0e8cc8bdSWilliam Juul 6055*0e8cc8bdSWilliam Juul YYIELD(); 6056*0e8cc8bdSWilliam Juul 6057*0e8cc8bdSWilliam Juul /* Sort the blocks */ 6058*0e8cc8bdSWilliam Juul #ifndef CONFIG_YAFFS_USE_OWN_SORT 6059*0e8cc8bdSWilliam Juul { 6060*0e8cc8bdSWilliam Juul /* Use qsort now. */ 6061*0e8cc8bdSWilliam Juul yaffs_qsort(blockIndex, nBlocksToScan, sizeof(yaffs_BlockIndex), ybicmp); 6062*0e8cc8bdSWilliam Juul } 6063*0e8cc8bdSWilliam Juul #else 6064*0e8cc8bdSWilliam Juul { 6065*0e8cc8bdSWilliam Juul /* Dungy old bubble sort... */ 6066*0e8cc8bdSWilliam Juul 6067*0e8cc8bdSWilliam Juul yaffs_BlockIndex temp; 6068*0e8cc8bdSWilliam Juul int i; 6069*0e8cc8bdSWilliam Juul int j; 6070*0e8cc8bdSWilliam Juul 6071*0e8cc8bdSWilliam Juul for (i = 0; i < nBlocksToScan; i++) 6072*0e8cc8bdSWilliam Juul for (j = i + 1; j < nBlocksToScan; j++) 6073*0e8cc8bdSWilliam Juul if (blockIndex[i].seq > blockIndex[j].seq) { 6074*0e8cc8bdSWilliam Juul temp = blockIndex[j]; 6075*0e8cc8bdSWilliam Juul blockIndex[j] = blockIndex[i]; 6076*0e8cc8bdSWilliam Juul blockIndex[i] = temp; 6077*0e8cc8bdSWilliam Juul } 6078*0e8cc8bdSWilliam Juul } 6079*0e8cc8bdSWilliam Juul #endif 6080*0e8cc8bdSWilliam Juul 6081*0e8cc8bdSWilliam Juul YYIELD(); 6082*0e8cc8bdSWilliam Juul 6083*0e8cc8bdSWilliam Juul T(YAFFS_TRACE_SCAN, (TSTR("...done" TENDSTR))); 6084*0e8cc8bdSWilliam Juul 6085*0e8cc8bdSWilliam Juul /* Now scan the blocks looking at the data. */ 6086*0e8cc8bdSWilliam Juul startIterator = 0; 6087*0e8cc8bdSWilliam Juul endIterator = nBlocksToScan - 1; 6088*0e8cc8bdSWilliam Juul T(YAFFS_TRACE_SCAN_DEBUG, 6089*0e8cc8bdSWilliam Juul (TSTR("%d blocks to be scanned" TENDSTR), nBlocksToScan)); 6090*0e8cc8bdSWilliam Juul 6091*0e8cc8bdSWilliam Juul /* For each block.... backwards */ 6092*0e8cc8bdSWilliam Juul for (blockIterator = endIterator; !alloc_failed && blockIterator >= startIterator; 6093*0e8cc8bdSWilliam Juul blockIterator--) { 6094*0e8cc8bdSWilliam Juul /* Cooperative multitasking! This loop can run for so 6095*0e8cc8bdSWilliam Juul long that watchdog timers expire. */ 6096*0e8cc8bdSWilliam Juul YYIELD(); 6097*0e8cc8bdSWilliam Juul 6098*0e8cc8bdSWilliam Juul /* get the block to scan in the correct order */ 6099*0e8cc8bdSWilliam Juul blk = blockIndex[blockIterator].block; 6100*0e8cc8bdSWilliam Juul 6101*0e8cc8bdSWilliam Juul bi = yaffs_GetBlockInfo(dev, blk); 6102*0e8cc8bdSWilliam Juul 6103*0e8cc8bdSWilliam Juul 6104*0e8cc8bdSWilliam Juul state = bi->blockState; 6105*0e8cc8bdSWilliam Juul 6106*0e8cc8bdSWilliam Juul deleted = 0; 6107*0e8cc8bdSWilliam Juul 6108*0e8cc8bdSWilliam Juul /* For each chunk in each block that needs scanning.... */ 6109*0e8cc8bdSWilliam Juul foundChunksInBlock = 0; 6110*0e8cc8bdSWilliam Juul for (c = dev->nChunksPerBlock - 1; 6111*0e8cc8bdSWilliam Juul !alloc_failed && c >= 0 && 6112*0e8cc8bdSWilliam Juul (state == YAFFS_BLOCK_STATE_NEEDS_SCANNING || 6113*0e8cc8bdSWilliam Juul state == YAFFS_BLOCK_STATE_ALLOCATING); c--) { 6114*0e8cc8bdSWilliam Juul /* Scan backwards... 6115*0e8cc8bdSWilliam Juul * Read the tags and decide what to do 6116*0e8cc8bdSWilliam Juul */ 6117*0e8cc8bdSWilliam Juul 6118*0e8cc8bdSWilliam Juul chunk = blk * dev->nChunksPerBlock + c; 6119*0e8cc8bdSWilliam Juul 6120*0e8cc8bdSWilliam Juul result = yaffs_ReadChunkWithTagsFromNAND(dev, chunk, NULL, 6121*0e8cc8bdSWilliam Juul &tags); 6122*0e8cc8bdSWilliam Juul 6123*0e8cc8bdSWilliam Juul /* Let's have a good look at this chunk... */ 6124*0e8cc8bdSWilliam Juul 6125*0e8cc8bdSWilliam Juul if (!tags.chunkUsed) { 6126*0e8cc8bdSWilliam Juul /* An unassigned chunk in the block. 6127*0e8cc8bdSWilliam Juul * If there are used chunks after this one, then 6128*0e8cc8bdSWilliam Juul * it is a chunk that was skipped due to failing the erased 6129*0e8cc8bdSWilliam Juul * check. Just skip it so that it can be deleted. 6130*0e8cc8bdSWilliam Juul * But, more typically, We get here when this is an unallocated 6131*0e8cc8bdSWilliam Juul * chunk and his means that either the block is empty or 6132*0e8cc8bdSWilliam Juul * this is the one being allocated from 6133*0e8cc8bdSWilliam Juul */ 6134*0e8cc8bdSWilliam Juul 6135*0e8cc8bdSWilliam Juul if(foundChunksInBlock) 6136*0e8cc8bdSWilliam Juul { 6137*0e8cc8bdSWilliam Juul /* This is a chunk that was skipped due to failing the erased check */ 6138*0e8cc8bdSWilliam Juul 6139*0e8cc8bdSWilliam Juul } else if (c == 0) { 6140*0e8cc8bdSWilliam Juul /* We're looking at the first chunk in the block so the block is unused */ 6141*0e8cc8bdSWilliam Juul state = YAFFS_BLOCK_STATE_EMPTY; 6142*0e8cc8bdSWilliam Juul dev->nErasedBlocks++; 6143*0e8cc8bdSWilliam Juul } else { 6144*0e8cc8bdSWilliam Juul if (state == YAFFS_BLOCK_STATE_NEEDS_SCANNING || 6145*0e8cc8bdSWilliam Juul state == YAFFS_BLOCK_STATE_ALLOCATING) { 6146*0e8cc8bdSWilliam Juul if(dev->sequenceNumber == bi->sequenceNumber) { 6147*0e8cc8bdSWilliam Juul /* this is the block being allocated from */ 6148*0e8cc8bdSWilliam Juul 6149*0e8cc8bdSWilliam Juul T(YAFFS_TRACE_SCAN, 6150*0e8cc8bdSWilliam Juul (TSTR 6151*0e8cc8bdSWilliam Juul (" Allocating from %d %d" 6152*0e8cc8bdSWilliam Juul TENDSTR), blk, c)); 6153*0e8cc8bdSWilliam Juul 6154*0e8cc8bdSWilliam Juul state = YAFFS_BLOCK_STATE_ALLOCATING; 6155*0e8cc8bdSWilliam Juul dev->allocationBlock = blk; 6156*0e8cc8bdSWilliam Juul dev->allocationPage = c; 6157*0e8cc8bdSWilliam Juul dev->allocationBlockFinder = blk; 6158*0e8cc8bdSWilliam Juul } 6159*0e8cc8bdSWilliam Juul else { 6160*0e8cc8bdSWilliam Juul /* This is a partially written block that is not 6161*0e8cc8bdSWilliam Juul * the current allocation block. This block must have 6162*0e8cc8bdSWilliam Juul * had a write failure, so set up for retirement. 6163*0e8cc8bdSWilliam Juul */ 6164*0e8cc8bdSWilliam Juul 6165*0e8cc8bdSWilliam Juul bi->needsRetiring = 1; 6166*0e8cc8bdSWilliam Juul bi->gcPrioritise = 1; 6167*0e8cc8bdSWilliam Juul 6168*0e8cc8bdSWilliam Juul T(YAFFS_TRACE_ALWAYS, 6169*0e8cc8bdSWilliam Juul (TSTR("Partially written block %d being set for retirement" TENDSTR), 6170*0e8cc8bdSWilliam Juul blk)); 6171*0e8cc8bdSWilliam Juul } 6172*0e8cc8bdSWilliam Juul 6173*0e8cc8bdSWilliam Juul } 6174*0e8cc8bdSWilliam Juul 6175*0e8cc8bdSWilliam Juul } 6176*0e8cc8bdSWilliam Juul 6177*0e8cc8bdSWilliam Juul dev->nFreeChunks++; 6178*0e8cc8bdSWilliam Juul 6179*0e8cc8bdSWilliam Juul } else if (tags.chunkId > 0) { 6180*0e8cc8bdSWilliam Juul /* chunkId > 0 so it is a data chunk... */ 6181*0e8cc8bdSWilliam Juul unsigned int endpos; 6182*0e8cc8bdSWilliam Juul __u32 chunkBase = 6183*0e8cc8bdSWilliam Juul (tags.chunkId - 1) * dev->nDataBytesPerChunk; 6184*0e8cc8bdSWilliam Juul 6185*0e8cc8bdSWilliam Juul foundChunksInBlock = 1; 6186*0e8cc8bdSWilliam Juul 6187*0e8cc8bdSWilliam Juul 6188*0e8cc8bdSWilliam Juul yaffs_SetChunkBit(dev, blk, c); 6189*0e8cc8bdSWilliam Juul bi->pagesInUse++; 6190*0e8cc8bdSWilliam Juul 6191*0e8cc8bdSWilliam Juul in = yaffs_FindOrCreateObjectByNumber(dev, 6192*0e8cc8bdSWilliam Juul tags. 6193*0e8cc8bdSWilliam Juul objectId, 6194*0e8cc8bdSWilliam Juul YAFFS_OBJECT_TYPE_FILE); 6195*0e8cc8bdSWilliam Juul if(!in){ 6196*0e8cc8bdSWilliam Juul /* Out of memory */ 6197*0e8cc8bdSWilliam Juul alloc_failed = 1; 6198*0e8cc8bdSWilliam Juul } 6199*0e8cc8bdSWilliam Juul 6200*0e8cc8bdSWilliam Juul if (in && 6201*0e8cc8bdSWilliam Juul in->variantType == YAFFS_OBJECT_TYPE_FILE 6202*0e8cc8bdSWilliam Juul && chunkBase < 6203*0e8cc8bdSWilliam Juul in->variant.fileVariant.shrinkSize) { 6204*0e8cc8bdSWilliam Juul /* This has not been invalidated by a resize */ 6205*0e8cc8bdSWilliam Juul if(!yaffs_PutChunkIntoFile(in, tags.chunkId, 6206*0e8cc8bdSWilliam Juul chunk, -1)){ 6207*0e8cc8bdSWilliam Juul alloc_failed = 1; 6208*0e8cc8bdSWilliam Juul } 6209*0e8cc8bdSWilliam Juul 6210*0e8cc8bdSWilliam Juul /* File size is calculated by looking at the data chunks if we have not 6211*0e8cc8bdSWilliam Juul * seen an object header yet. Stop this practice once we find an object header. 6212*0e8cc8bdSWilliam Juul */ 6213*0e8cc8bdSWilliam Juul endpos = 6214*0e8cc8bdSWilliam Juul (tags.chunkId - 6215*0e8cc8bdSWilliam Juul 1) * dev->nDataBytesPerChunk + 6216*0e8cc8bdSWilliam Juul tags.byteCount; 6217*0e8cc8bdSWilliam Juul 6218*0e8cc8bdSWilliam Juul if (!in->valid && /* have not got an object header yet */ 6219*0e8cc8bdSWilliam Juul in->variant.fileVariant. 6220*0e8cc8bdSWilliam Juul scannedFileSize < endpos) { 6221*0e8cc8bdSWilliam Juul in->variant.fileVariant. 6222*0e8cc8bdSWilliam Juul scannedFileSize = endpos; 6223*0e8cc8bdSWilliam Juul in->variant.fileVariant. 6224*0e8cc8bdSWilliam Juul fileSize = 6225*0e8cc8bdSWilliam Juul in->variant.fileVariant. 6226*0e8cc8bdSWilliam Juul scannedFileSize; 6227*0e8cc8bdSWilliam Juul } 6228*0e8cc8bdSWilliam Juul 6229*0e8cc8bdSWilliam Juul } else if(in) { 6230*0e8cc8bdSWilliam Juul /* This chunk has been invalidated by a resize, so delete */ 6231*0e8cc8bdSWilliam Juul yaffs_DeleteChunk(dev, chunk, 1, __LINE__); 6232*0e8cc8bdSWilliam Juul 6233*0e8cc8bdSWilliam Juul } 6234*0e8cc8bdSWilliam Juul } else { 6235*0e8cc8bdSWilliam Juul /* chunkId == 0, so it is an ObjectHeader. 6236*0e8cc8bdSWilliam Juul * Thus, we read in the object header and make the object 6237*0e8cc8bdSWilliam Juul */ 6238*0e8cc8bdSWilliam Juul foundChunksInBlock = 1; 6239*0e8cc8bdSWilliam Juul 6240*0e8cc8bdSWilliam Juul yaffs_SetChunkBit(dev, blk, c); 6241*0e8cc8bdSWilliam Juul bi->pagesInUse++; 6242*0e8cc8bdSWilliam Juul 6243*0e8cc8bdSWilliam Juul oh = NULL; 6244*0e8cc8bdSWilliam Juul in = NULL; 6245*0e8cc8bdSWilliam Juul 6246*0e8cc8bdSWilliam Juul if (tags.extraHeaderInfoAvailable) { 6247*0e8cc8bdSWilliam Juul in = yaffs_FindOrCreateObjectByNumber 6248*0e8cc8bdSWilliam Juul (dev, tags.objectId, 6249*0e8cc8bdSWilliam Juul tags.extraObjectType); 6250*0e8cc8bdSWilliam Juul } 6251*0e8cc8bdSWilliam Juul 6252*0e8cc8bdSWilliam Juul if (!in || 6253*0e8cc8bdSWilliam Juul #ifdef CONFIG_YAFFS_DISABLE_LAZY_LOAD 6254*0e8cc8bdSWilliam Juul !in->valid || 6255*0e8cc8bdSWilliam Juul #endif 6256*0e8cc8bdSWilliam Juul tags.extraShadows || 6257*0e8cc8bdSWilliam Juul (!in->valid && 6258*0e8cc8bdSWilliam Juul (tags.objectId == YAFFS_OBJECTID_ROOT || 6259*0e8cc8bdSWilliam Juul tags.objectId == YAFFS_OBJECTID_LOSTNFOUND)) 6260*0e8cc8bdSWilliam Juul ) { 6261*0e8cc8bdSWilliam Juul 6262*0e8cc8bdSWilliam Juul /* If we don't have valid info then we need to read the chunk 6263*0e8cc8bdSWilliam Juul * TODO In future we can probably defer reading the chunk and 6264*0e8cc8bdSWilliam Juul * living with invalid data until needed. 6265*0e8cc8bdSWilliam Juul */ 6266*0e8cc8bdSWilliam Juul 6267*0e8cc8bdSWilliam Juul result = yaffs_ReadChunkWithTagsFromNAND(dev, 6268*0e8cc8bdSWilliam Juul chunk, 6269*0e8cc8bdSWilliam Juul chunkData, 6270*0e8cc8bdSWilliam Juul NULL); 6271*0e8cc8bdSWilliam Juul 6272*0e8cc8bdSWilliam Juul oh = (yaffs_ObjectHeader *) chunkData; 6273*0e8cc8bdSWilliam Juul 6274*0e8cc8bdSWilliam Juul if (!in) 6275*0e8cc8bdSWilliam Juul in = yaffs_FindOrCreateObjectByNumber(dev, tags.objectId, oh->type); 6276*0e8cc8bdSWilliam Juul 6277*0e8cc8bdSWilliam Juul } 6278*0e8cc8bdSWilliam Juul 6279*0e8cc8bdSWilliam Juul if (!in) { 6280*0e8cc8bdSWilliam Juul /* TODO Hoosterman we have a problem! */ 6281*0e8cc8bdSWilliam Juul T(YAFFS_TRACE_ERROR, 6282*0e8cc8bdSWilliam Juul (TSTR 6283*0e8cc8bdSWilliam Juul ("yaffs tragedy: Could not make object for object %d " 6284*0e8cc8bdSWilliam Juul "at chunk %d during scan" 6285*0e8cc8bdSWilliam Juul TENDSTR), tags.objectId, chunk)); 6286*0e8cc8bdSWilliam Juul 6287*0e8cc8bdSWilliam Juul } 6288*0e8cc8bdSWilliam Juul 6289*0e8cc8bdSWilliam Juul if (in->valid) { 6290*0e8cc8bdSWilliam Juul /* We have already filled this one. 6291*0e8cc8bdSWilliam Juul * We have a duplicate that will be discarded, but 6292*0e8cc8bdSWilliam Juul * we first have to suck out resize info if it is a file. 6293*0e8cc8bdSWilliam Juul */ 6294*0e8cc8bdSWilliam Juul 6295*0e8cc8bdSWilliam Juul if ((in->variantType == YAFFS_OBJECT_TYPE_FILE) && 6296*0e8cc8bdSWilliam Juul ((oh && 6297*0e8cc8bdSWilliam Juul oh-> type == YAFFS_OBJECT_TYPE_FILE)|| 6298*0e8cc8bdSWilliam Juul (tags.extraHeaderInfoAvailable && 6299*0e8cc8bdSWilliam Juul tags.extraObjectType == YAFFS_OBJECT_TYPE_FILE)) 6300*0e8cc8bdSWilliam Juul ) { 6301*0e8cc8bdSWilliam Juul __u32 thisSize = 6302*0e8cc8bdSWilliam Juul (oh) ? oh->fileSize : tags. 6303*0e8cc8bdSWilliam Juul extraFileLength; 6304*0e8cc8bdSWilliam Juul __u32 parentObjectId = 6305*0e8cc8bdSWilliam Juul (oh) ? oh-> 6306*0e8cc8bdSWilliam Juul parentObjectId : tags. 6307*0e8cc8bdSWilliam Juul extraParentObjectId; 6308*0e8cc8bdSWilliam Juul unsigned isShrink = 6309*0e8cc8bdSWilliam Juul (oh) ? oh->isShrink : tags. 6310*0e8cc8bdSWilliam Juul extraIsShrinkHeader; 6311*0e8cc8bdSWilliam Juul 6312*0e8cc8bdSWilliam Juul /* If it is deleted (unlinked at start also means deleted) 6313*0e8cc8bdSWilliam Juul * we treat the file size as being zeroed at this point. 6314*0e8cc8bdSWilliam Juul */ 6315*0e8cc8bdSWilliam Juul if (parentObjectId == 6316*0e8cc8bdSWilliam Juul YAFFS_OBJECTID_DELETED 6317*0e8cc8bdSWilliam Juul || parentObjectId == 6318*0e8cc8bdSWilliam Juul YAFFS_OBJECTID_UNLINKED) { 6319*0e8cc8bdSWilliam Juul thisSize = 0; 6320*0e8cc8bdSWilliam Juul isShrink = 1; 6321*0e8cc8bdSWilliam Juul } 6322*0e8cc8bdSWilliam Juul 6323*0e8cc8bdSWilliam Juul if (isShrink && 6324*0e8cc8bdSWilliam Juul in->variant.fileVariant. 6325*0e8cc8bdSWilliam Juul shrinkSize > thisSize) { 6326*0e8cc8bdSWilliam Juul in->variant.fileVariant. 6327*0e8cc8bdSWilliam Juul shrinkSize = 6328*0e8cc8bdSWilliam Juul thisSize; 6329*0e8cc8bdSWilliam Juul } 6330*0e8cc8bdSWilliam Juul 6331*0e8cc8bdSWilliam Juul if (isShrink) { 6332*0e8cc8bdSWilliam Juul bi->hasShrinkHeader = 1; 6333*0e8cc8bdSWilliam Juul } 6334*0e8cc8bdSWilliam Juul 6335*0e8cc8bdSWilliam Juul } 6336*0e8cc8bdSWilliam Juul /* Use existing - destroy this one. */ 6337*0e8cc8bdSWilliam Juul yaffs_DeleteChunk(dev, chunk, 1, __LINE__); 6338*0e8cc8bdSWilliam Juul 6339*0e8cc8bdSWilliam Juul } 6340*0e8cc8bdSWilliam Juul 6341*0e8cc8bdSWilliam Juul if (!in->valid && 6342*0e8cc8bdSWilliam Juul (tags.objectId == YAFFS_OBJECTID_ROOT || 6343*0e8cc8bdSWilliam Juul tags.objectId == 6344*0e8cc8bdSWilliam Juul YAFFS_OBJECTID_LOSTNFOUND)) { 6345*0e8cc8bdSWilliam Juul /* We only load some info, don't fiddle with directory structure */ 6346*0e8cc8bdSWilliam Juul in->valid = 1; 6347*0e8cc8bdSWilliam Juul 6348*0e8cc8bdSWilliam Juul if(oh) { 6349*0e8cc8bdSWilliam Juul in->variantType = oh->type; 6350*0e8cc8bdSWilliam Juul 6351*0e8cc8bdSWilliam Juul in->yst_mode = oh->yst_mode; 6352*0e8cc8bdSWilliam Juul #ifdef CONFIG_YAFFS_WINCE 6353*0e8cc8bdSWilliam Juul in->win_atime[0] = oh->win_atime[0]; 6354*0e8cc8bdSWilliam Juul in->win_ctime[0] = oh->win_ctime[0]; 6355*0e8cc8bdSWilliam Juul in->win_mtime[0] = oh->win_mtime[0]; 6356*0e8cc8bdSWilliam Juul in->win_atime[1] = oh->win_atime[1]; 6357*0e8cc8bdSWilliam Juul in->win_ctime[1] = oh->win_ctime[1]; 6358*0e8cc8bdSWilliam Juul in->win_mtime[1] = oh->win_mtime[1]; 6359*0e8cc8bdSWilliam Juul #else 6360*0e8cc8bdSWilliam Juul in->yst_uid = oh->yst_uid; 6361*0e8cc8bdSWilliam Juul in->yst_gid = oh->yst_gid; 6362*0e8cc8bdSWilliam Juul in->yst_atime = oh->yst_atime; 6363*0e8cc8bdSWilliam Juul in->yst_mtime = oh->yst_mtime; 6364*0e8cc8bdSWilliam Juul in->yst_ctime = oh->yst_ctime; 6365*0e8cc8bdSWilliam Juul in->yst_rdev = oh->yst_rdev; 6366*0e8cc8bdSWilliam Juul 6367*0e8cc8bdSWilliam Juul #endif 6368*0e8cc8bdSWilliam Juul } else { 6369*0e8cc8bdSWilliam Juul in->variantType = tags.extraObjectType; 6370*0e8cc8bdSWilliam Juul in->lazyLoaded = 1; 6371*0e8cc8bdSWilliam Juul } 6372*0e8cc8bdSWilliam Juul 6373*0e8cc8bdSWilliam Juul in->chunkId = chunk; 6374*0e8cc8bdSWilliam Juul 6375*0e8cc8bdSWilliam Juul } else if (!in->valid) { 6376*0e8cc8bdSWilliam Juul /* we need to load this info */ 6377*0e8cc8bdSWilliam Juul 6378*0e8cc8bdSWilliam Juul in->valid = 1; 6379*0e8cc8bdSWilliam Juul in->chunkId = chunk; 6380*0e8cc8bdSWilliam Juul 6381*0e8cc8bdSWilliam Juul if(oh) { 6382*0e8cc8bdSWilliam Juul in->variantType = oh->type; 6383*0e8cc8bdSWilliam Juul 6384*0e8cc8bdSWilliam Juul in->yst_mode = oh->yst_mode; 6385*0e8cc8bdSWilliam Juul #ifdef CONFIG_YAFFS_WINCE 6386*0e8cc8bdSWilliam Juul in->win_atime[0] = oh->win_atime[0]; 6387*0e8cc8bdSWilliam Juul in->win_ctime[0] = oh->win_ctime[0]; 6388*0e8cc8bdSWilliam Juul in->win_mtime[0] = oh->win_mtime[0]; 6389*0e8cc8bdSWilliam Juul in->win_atime[1] = oh->win_atime[1]; 6390*0e8cc8bdSWilliam Juul in->win_ctime[1] = oh->win_ctime[1]; 6391*0e8cc8bdSWilliam Juul in->win_mtime[1] = oh->win_mtime[1]; 6392*0e8cc8bdSWilliam Juul #else 6393*0e8cc8bdSWilliam Juul in->yst_uid = oh->yst_uid; 6394*0e8cc8bdSWilliam Juul in->yst_gid = oh->yst_gid; 6395*0e8cc8bdSWilliam Juul in->yst_atime = oh->yst_atime; 6396*0e8cc8bdSWilliam Juul in->yst_mtime = oh->yst_mtime; 6397*0e8cc8bdSWilliam Juul in->yst_ctime = oh->yst_ctime; 6398*0e8cc8bdSWilliam Juul in->yst_rdev = oh->yst_rdev; 6399*0e8cc8bdSWilliam Juul #endif 6400*0e8cc8bdSWilliam Juul 6401*0e8cc8bdSWilliam Juul if (oh->shadowsObject > 0) 6402*0e8cc8bdSWilliam Juul yaffs_HandleShadowedObject(dev, 6403*0e8cc8bdSWilliam Juul oh-> 6404*0e8cc8bdSWilliam Juul shadowsObject, 6405*0e8cc8bdSWilliam Juul 1); 6406*0e8cc8bdSWilliam Juul 6407*0e8cc8bdSWilliam Juul 6408*0e8cc8bdSWilliam Juul yaffs_SetObjectName(in, oh->name); 6409*0e8cc8bdSWilliam Juul parent = 6410*0e8cc8bdSWilliam Juul yaffs_FindOrCreateObjectByNumber 6411*0e8cc8bdSWilliam Juul (dev, oh->parentObjectId, 6412*0e8cc8bdSWilliam Juul YAFFS_OBJECT_TYPE_DIRECTORY); 6413*0e8cc8bdSWilliam Juul 6414*0e8cc8bdSWilliam Juul fileSize = oh->fileSize; 6415*0e8cc8bdSWilliam Juul isShrink = oh->isShrink; 6416*0e8cc8bdSWilliam Juul equivalentObjectId = oh->equivalentObjectId; 6417*0e8cc8bdSWilliam Juul 6418*0e8cc8bdSWilliam Juul } 6419*0e8cc8bdSWilliam Juul else { 6420*0e8cc8bdSWilliam Juul in->variantType = tags.extraObjectType; 6421*0e8cc8bdSWilliam Juul parent = 6422*0e8cc8bdSWilliam Juul yaffs_FindOrCreateObjectByNumber 6423*0e8cc8bdSWilliam Juul (dev, tags.extraParentObjectId, 6424*0e8cc8bdSWilliam Juul YAFFS_OBJECT_TYPE_DIRECTORY); 6425*0e8cc8bdSWilliam Juul fileSize = tags.extraFileLength; 6426*0e8cc8bdSWilliam Juul isShrink = tags.extraIsShrinkHeader; 6427*0e8cc8bdSWilliam Juul equivalentObjectId = tags.extraEquivalentObjectId; 6428*0e8cc8bdSWilliam Juul in->lazyLoaded = 1; 6429*0e8cc8bdSWilliam Juul 6430*0e8cc8bdSWilliam Juul } 6431*0e8cc8bdSWilliam Juul in->dirty = 0; 6432*0e8cc8bdSWilliam Juul 6433*0e8cc8bdSWilliam Juul /* directory stuff... 6434*0e8cc8bdSWilliam Juul * hook up to parent 6435*0e8cc8bdSWilliam Juul */ 6436*0e8cc8bdSWilliam Juul 6437*0e8cc8bdSWilliam Juul if (parent->variantType == 6438*0e8cc8bdSWilliam Juul YAFFS_OBJECT_TYPE_UNKNOWN) { 6439*0e8cc8bdSWilliam Juul /* Set up as a directory */ 6440*0e8cc8bdSWilliam Juul parent->variantType = 6441*0e8cc8bdSWilliam Juul YAFFS_OBJECT_TYPE_DIRECTORY; 6442*0e8cc8bdSWilliam Juul INIT_LIST_HEAD(&parent->variant. 6443*0e8cc8bdSWilliam Juul directoryVariant. 6444*0e8cc8bdSWilliam Juul children); 6445*0e8cc8bdSWilliam Juul } else if (parent->variantType != 6446*0e8cc8bdSWilliam Juul YAFFS_OBJECT_TYPE_DIRECTORY) 6447*0e8cc8bdSWilliam Juul { 6448*0e8cc8bdSWilliam Juul /* Hoosterman, another problem.... 6449*0e8cc8bdSWilliam Juul * We're trying to use a non-directory as a directory 6450*0e8cc8bdSWilliam Juul */ 6451*0e8cc8bdSWilliam Juul 6452*0e8cc8bdSWilliam Juul T(YAFFS_TRACE_ERROR, 6453*0e8cc8bdSWilliam Juul (TSTR 6454*0e8cc8bdSWilliam Juul ("yaffs tragedy: attempting to use non-directory as" 6455*0e8cc8bdSWilliam Juul " a directory in scan. Put in lost+found." 6456*0e8cc8bdSWilliam Juul TENDSTR))); 6457*0e8cc8bdSWilliam Juul parent = dev->lostNFoundDir; 6458*0e8cc8bdSWilliam Juul } 6459*0e8cc8bdSWilliam Juul 6460*0e8cc8bdSWilliam Juul yaffs_AddObjectToDirectory(parent, in); 6461*0e8cc8bdSWilliam Juul 6462*0e8cc8bdSWilliam Juul itsUnlinked = (parent == dev->deletedDir) || 6463*0e8cc8bdSWilliam Juul (parent == dev->unlinkedDir); 6464*0e8cc8bdSWilliam Juul 6465*0e8cc8bdSWilliam Juul if (isShrink) { 6466*0e8cc8bdSWilliam Juul /* Mark the block as having a shrinkHeader */ 6467*0e8cc8bdSWilliam Juul bi->hasShrinkHeader = 1; 6468*0e8cc8bdSWilliam Juul } 6469*0e8cc8bdSWilliam Juul 6470*0e8cc8bdSWilliam Juul /* Note re hardlinks. 6471*0e8cc8bdSWilliam Juul * Since we might scan a hardlink before its equivalent object is scanned 6472*0e8cc8bdSWilliam Juul * we put them all in a list. 6473*0e8cc8bdSWilliam Juul * After scanning is complete, we should have all the objects, so we run 6474*0e8cc8bdSWilliam Juul * through this list and fix up all the chains. 6475*0e8cc8bdSWilliam Juul */ 6476*0e8cc8bdSWilliam Juul 6477*0e8cc8bdSWilliam Juul switch (in->variantType) { 6478*0e8cc8bdSWilliam Juul case YAFFS_OBJECT_TYPE_UNKNOWN: 6479*0e8cc8bdSWilliam Juul /* Todo got a problem */ 6480*0e8cc8bdSWilliam Juul break; 6481*0e8cc8bdSWilliam Juul case YAFFS_OBJECT_TYPE_FILE: 6482*0e8cc8bdSWilliam Juul 6483*0e8cc8bdSWilliam Juul if (in->variant.fileVariant. 6484*0e8cc8bdSWilliam Juul scannedFileSize < fileSize) { 6485*0e8cc8bdSWilliam Juul /* This covers the case where the file size is greater 6486*0e8cc8bdSWilliam Juul * than where the data is 6487*0e8cc8bdSWilliam Juul * This will happen if the file is resized to be larger 6488*0e8cc8bdSWilliam Juul * than its current data extents. 6489*0e8cc8bdSWilliam Juul */ 6490*0e8cc8bdSWilliam Juul in->variant.fileVariant.fileSize = fileSize; 6491*0e8cc8bdSWilliam Juul in->variant.fileVariant.scannedFileSize = 6492*0e8cc8bdSWilliam Juul in->variant.fileVariant.fileSize; 6493*0e8cc8bdSWilliam Juul } 6494*0e8cc8bdSWilliam Juul 6495*0e8cc8bdSWilliam Juul if (isShrink && 6496*0e8cc8bdSWilliam Juul in->variant.fileVariant.shrinkSize > fileSize) { 6497*0e8cc8bdSWilliam Juul in->variant.fileVariant.shrinkSize = fileSize; 6498*0e8cc8bdSWilliam Juul } 6499*0e8cc8bdSWilliam Juul 6500*0e8cc8bdSWilliam Juul break; 6501*0e8cc8bdSWilliam Juul case YAFFS_OBJECT_TYPE_HARDLINK: 6502*0e8cc8bdSWilliam Juul if(!itsUnlinked) { 6503*0e8cc8bdSWilliam Juul in->variant.hardLinkVariant.equivalentObjectId = 6504*0e8cc8bdSWilliam Juul equivalentObjectId; 6505*0e8cc8bdSWilliam Juul in->hardLinks.next = 6506*0e8cc8bdSWilliam Juul (struct list_head *) hardList; 6507*0e8cc8bdSWilliam Juul hardList = in; 6508*0e8cc8bdSWilliam Juul } 6509*0e8cc8bdSWilliam Juul break; 6510*0e8cc8bdSWilliam Juul case YAFFS_OBJECT_TYPE_DIRECTORY: 6511*0e8cc8bdSWilliam Juul /* Do nothing */ 6512*0e8cc8bdSWilliam Juul break; 6513*0e8cc8bdSWilliam Juul case YAFFS_OBJECT_TYPE_SPECIAL: 6514*0e8cc8bdSWilliam Juul /* Do nothing */ 6515*0e8cc8bdSWilliam Juul break; 6516*0e8cc8bdSWilliam Juul case YAFFS_OBJECT_TYPE_SYMLINK: 6517*0e8cc8bdSWilliam Juul if(oh){ 6518*0e8cc8bdSWilliam Juul in->variant.symLinkVariant.alias = 6519*0e8cc8bdSWilliam Juul yaffs_CloneString(oh-> 6520*0e8cc8bdSWilliam Juul alias); 6521*0e8cc8bdSWilliam Juul if(!in->variant.symLinkVariant.alias) 6522*0e8cc8bdSWilliam Juul alloc_failed = 1; 6523*0e8cc8bdSWilliam Juul } 6524*0e8cc8bdSWilliam Juul break; 6525*0e8cc8bdSWilliam Juul } 6526*0e8cc8bdSWilliam Juul 6527*0e8cc8bdSWilliam Juul } 6528*0e8cc8bdSWilliam Juul 6529*0e8cc8bdSWilliam Juul } 6530*0e8cc8bdSWilliam Juul 6531*0e8cc8bdSWilliam Juul } /* End of scanning for each chunk */ 6532*0e8cc8bdSWilliam Juul 6533*0e8cc8bdSWilliam Juul if (state == YAFFS_BLOCK_STATE_NEEDS_SCANNING) { 6534*0e8cc8bdSWilliam Juul /* If we got this far while scanning, then the block is fully allocated. */ 6535*0e8cc8bdSWilliam Juul state = YAFFS_BLOCK_STATE_FULL; 6536*0e8cc8bdSWilliam Juul } 6537*0e8cc8bdSWilliam Juul 6538*0e8cc8bdSWilliam Juul bi->blockState = state; 6539*0e8cc8bdSWilliam Juul 6540*0e8cc8bdSWilliam Juul /* Now let's see if it was dirty */ 6541*0e8cc8bdSWilliam Juul if (bi->pagesInUse == 0 && 6542*0e8cc8bdSWilliam Juul !bi->hasShrinkHeader && 6543*0e8cc8bdSWilliam Juul bi->blockState == YAFFS_BLOCK_STATE_FULL) { 6544*0e8cc8bdSWilliam Juul yaffs_BlockBecameDirty(dev, blk); 6545*0e8cc8bdSWilliam Juul } 6546*0e8cc8bdSWilliam Juul 6547*0e8cc8bdSWilliam Juul } 6548*0e8cc8bdSWilliam Juul 6549*0e8cc8bdSWilliam Juul if (altBlockIndex) 6550*0e8cc8bdSWilliam Juul YFREE_ALT(blockIndex); 6551*0e8cc8bdSWilliam Juul else 6552*0e8cc8bdSWilliam Juul YFREE(blockIndex); 6553*0e8cc8bdSWilliam Juul 6554*0e8cc8bdSWilliam Juul /* Ok, we've done all the scanning. 6555*0e8cc8bdSWilliam Juul * Fix up the hard link chains. 6556*0e8cc8bdSWilliam Juul * We should now have scanned all the objects, now it's time to add these 6557*0e8cc8bdSWilliam Juul * hardlinks. 6558*0e8cc8bdSWilliam Juul */ 6559*0e8cc8bdSWilliam Juul yaffs_HardlinkFixup(dev,hardList); 6560*0e8cc8bdSWilliam Juul 6561*0e8cc8bdSWilliam Juul 6562*0e8cc8bdSWilliam Juul /* 6563*0e8cc8bdSWilliam Juul * Sort out state of unlinked and deleted objects. 6564*0e8cc8bdSWilliam Juul */ 6565*0e8cc8bdSWilliam Juul { 6566*0e8cc8bdSWilliam Juul struct list_head *i; 6567*0e8cc8bdSWilliam Juul struct list_head *n; 6568*0e8cc8bdSWilliam Juul 6569*0e8cc8bdSWilliam Juul yaffs_Object *l; 6570*0e8cc8bdSWilliam Juul 6571*0e8cc8bdSWilliam Juul /* Soft delete all the unlinked files */ 6572*0e8cc8bdSWilliam Juul list_for_each_safe(i, n, 6573*0e8cc8bdSWilliam Juul &dev->unlinkedDir->variant.directoryVariant. 6574*0e8cc8bdSWilliam Juul children) { 6575*0e8cc8bdSWilliam Juul if (i) { 6576*0e8cc8bdSWilliam Juul l = list_entry(i, yaffs_Object, siblings); 6577*0e8cc8bdSWilliam Juul yaffs_DestroyObject(l); 6578*0e8cc8bdSWilliam Juul } 6579*0e8cc8bdSWilliam Juul } 6580*0e8cc8bdSWilliam Juul 6581*0e8cc8bdSWilliam Juul /* Soft delete all the deletedDir files */ 6582*0e8cc8bdSWilliam Juul list_for_each_safe(i, n, 6583*0e8cc8bdSWilliam Juul &dev->deletedDir->variant.directoryVariant. 6584*0e8cc8bdSWilliam Juul children) { 6585*0e8cc8bdSWilliam Juul if (i) { 6586*0e8cc8bdSWilliam Juul l = list_entry(i, yaffs_Object, siblings); 6587*0e8cc8bdSWilliam Juul yaffs_DestroyObject(l); 6588*0e8cc8bdSWilliam Juul 6589*0e8cc8bdSWilliam Juul } 6590*0e8cc8bdSWilliam Juul } 6591*0e8cc8bdSWilliam Juul } 6592*0e8cc8bdSWilliam Juul 6593*0e8cc8bdSWilliam Juul yaffs_ReleaseTempBuffer(dev, chunkData, __LINE__); 6594*0e8cc8bdSWilliam Juul 6595*0e8cc8bdSWilliam Juul if(alloc_failed){ 6596*0e8cc8bdSWilliam Juul return YAFFS_FAIL; 6597*0e8cc8bdSWilliam Juul } 6598*0e8cc8bdSWilliam Juul 6599*0e8cc8bdSWilliam Juul T(YAFFS_TRACE_SCAN, (TSTR("yaffs_ScanBackwards ends" TENDSTR))); 6600*0e8cc8bdSWilliam Juul 6601*0e8cc8bdSWilliam Juul return YAFFS_OK; 6602*0e8cc8bdSWilliam Juul } 6603*0e8cc8bdSWilliam Juul 6604*0e8cc8bdSWilliam Juul /*------------------------------ Directory Functions ----------------------------- */ 6605*0e8cc8bdSWilliam Juul 6606*0e8cc8bdSWilliam Juul static void yaffs_RemoveObjectFromDirectory(yaffs_Object * obj) 6607*0e8cc8bdSWilliam Juul { 6608*0e8cc8bdSWilliam Juul yaffs_Device *dev = obj->myDev; 6609*0e8cc8bdSWilliam Juul 6610*0e8cc8bdSWilliam Juul if(dev && dev->removeObjectCallback) 6611*0e8cc8bdSWilliam Juul dev->removeObjectCallback(obj); 6612*0e8cc8bdSWilliam Juul 6613*0e8cc8bdSWilliam Juul list_del_init(&obj->siblings); 6614*0e8cc8bdSWilliam Juul obj->parent = NULL; 6615*0e8cc8bdSWilliam Juul } 6616*0e8cc8bdSWilliam Juul 6617*0e8cc8bdSWilliam Juul 6618*0e8cc8bdSWilliam Juul static void yaffs_AddObjectToDirectory(yaffs_Object * directory, 6619*0e8cc8bdSWilliam Juul yaffs_Object * obj) 6620*0e8cc8bdSWilliam Juul { 6621*0e8cc8bdSWilliam Juul 6622*0e8cc8bdSWilliam Juul if (!directory) { 6623*0e8cc8bdSWilliam Juul T(YAFFS_TRACE_ALWAYS, 6624*0e8cc8bdSWilliam Juul (TSTR 6625*0e8cc8bdSWilliam Juul ("tragedy: Trying to add an object to a null pointer directory" 6626*0e8cc8bdSWilliam Juul TENDSTR))); 6627*0e8cc8bdSWilliam Juul YBUG(); 6628*0e8cc8bdSWilliam Juul } 6629*0e8cc8bdSWilliam Juul if (directory->variantType != YAFFS_OBJECT_TYPE_DIRECTORY) { 6630*0e8cc8bdSWilliam Juul T(YAFFS_TRACE_ALWAYS, 6631*0e8cc8bdSWilliam Juul (TSTR 6632*0e8cc8bdSWilliam Juul ("tragedy: Trying to add an object to a non-directory" 6633*0e8cc8bdSWilliam Juul TENDSTR))); 6634*0e8cc8bdSWilliam Juul YBUG(); 6635*0e8cc8bdSWilliam Juul } 6636*0e8cc8bdSWilliam Juul 6637*0e8cc8bdSWilliam Juul if (obj->siblings.prev == NULL) { 6638*0e8cc8bdSWilliam Juul /* Not initialised */ 6639*0e8cc8bdSWilliam Juul INIT_LIST_HEAD(&obj->siblings); 6640*0e8cc8bdSWilliam Juul 6641*0e8cc8bdSWilliam Juul } else if (!list_empty(&obj->siblings)) { 6642*0e8cc8bdSWilliam Juul /* If it is holed up somewhere else, un hook it */ 6643*0e8cc8bdSWilliam Juul yaffs_RemoveObjectFromDirectory(obj); 6644*0e8cc8bdSWilliam Juul } 6645*0e8cc8bdSWilliam Juul /* Now add it */ 6646*0e8cc8bdSWilliam Juul list_add(&obj->siblings, &directory->variant.directoryVariant.children); 6647*0e8cc8bdSWilliam Juul obj->parent = directory; 6648*0e8cc8bdSWilliam Juul 6649*0e8cc8bdSWilliam Juul if (directory == obj->myDev->unlinkedDir 6650*0e8cc8bdSWilliam Juul || directory == obj->myDev->deletedDir) { 6651*0e8cc8bdSWilliam Juul obj->unlinked = 1; 6652*0e8cc8bdSWilliam Juul obj->myDev->nUnlinkedFiles++; 6653*0e8cc8bdSWilliam Juul obj->renameAllowed = 0; 6654*0e8cc8bdSWilliam Juul } 6655*0e8cc8bdSWilliam Juul } 6656*0e8cc8bdSWilliam Juul 6657*0e8cc8bdSWilliam Juul yaffs_Object *yaffs_FindObjectByName(yaffs_Object * directory, 6658*0e8cc8bdSWilliam Juul const YCHAR * name) 6659*0e8cc8bdSWilliam Juul { 6660*0e8cc8bdSWilliam Juul int sum; 6661*0e8cc8bdSWilliam Juul 6662*0e8cc8bdSWilliam Juul struct list_head *i; 6663*0e8cc8bdSWilliam Juul YCHAR buffer[YAFFS_MAX_NAME_LENGTH + 1]; 6664*0e8cc8bdSWilliam Juul 6665*0e8cc8bdSWilliam Juul yaffs_Object *l; 6666*0e8cc8bdSWilliam Juul 6667*0e8cc8bdSWilliam Juul if (!name) { 6668*0e8cc8bdSWilliam Juul return NULL; 6669*0e8cc8bdSWilliam Juul } 6670*0e8cc8bdSWilliam Juul 6671*0e8cc8bdSWilliam Juul if (!directory) { 6672*0e8cc8bdSWilliam Juul T(YAFFS_TRACE_ALWAYS, 6673*0e8cc8bdSWilliam Juul (TSTR 6674*0e8cc8bdSWilliam Juul ("tragedy: yaffs_FindObjectByName: null pointer directory" 6675*0e8cc8bdSWilliam Juul TENDSTR))); 6676*0e8cc8bdSWilliam Juul YBUG(); 6677*0e8cc8bdSWilliam Juul } 6678*0e8cc8bdSWilliam Juul if (directory->variantType != YAFFS_OBJECT_TYPE_DIRECTORY) { 6679*0e8cc8bdSWilliam Juul T(YAFFS_TRACE_ALWAYS, 6680*0e8cc8bdSWilliam Juul (TSTR 6681*0e8cc8bdSWilliam Juul ("tragedy: yaffs_FindObjectByName: non-directory" TENDSTR))); 6682*0e8cc8bdSWilliam Juul YBUG(); 6683*0e8cc8bdSWilliam Juul } 6684*0e8cc8bdSWilliam Juul 6685*0e8cc8bdSWilliam Juul sum = yaffs_CalcNameSum(name); 6686*0e8cc8bdSWilliam Juul 6687*0e8cc8bdSWilliam Juul list_for_each(i, &directory->variant.directoryVariant.children) { 6688*0e8cc8bdSWilliam Juul if (i) { 6689*0e8cc8bdSWilliam Juul l = list_entry(i, yaffs_Object, siblings); 6690*0e8cc8bdSWilliam Juul 6691*0e8cc8bdSWilliam Juul yaffs_CheckObjectDetailsLoaded(l); 6692*0e8cc8bdSWilliam Juul 6693*0e8cc8bdSWilliam Juul /* Special case for lost-n-found */ 6694*0e8cc8bdSWilliam Juul if (l->objectId == YAFFS_OBJECTID_LOSTNFOUND) { 6695*0e8cc8bdSWilliam Juul if (yaffs_strcmp(name, YAFFS_LOSTNFOUND_NAME) == 0) { 6696*0e8cc8bdSWilliam Juul return l; 6697*0e8cc8bdSWilliam Juul } 6698*0e8cc8bdSWilliam Juul } else if (yaffs_SumCompare(l->sum, sum) || l->chunkId <= 0) 6699*0e8cc8bdSWilliam Juul { 6700*0e8cc8bdSWilliam Juul /* LostnFound cunk called Objxxx 6701*0e8cc8bdSWilliam Juul * Do a real check 6702*0e8cc8bdSWilliam Juul */ 6703*0e8cc8bdSWilliam Juul yaffs_GetObjectName(l, buffer, 6704*0e8cc8bdSWilliam Juul YAFFS_MAX_NAME_LENGTH); 6705*0e8cc8bdSWilliam Juul if (yaffs_strncmp(name, buffer,YAFFS_MAX_NAME_LENGTH) == 0) { 6706*0e8cc8bdSWilliam Juul return l; 6707*0e8cc8bdSWilliam Juul } 6708*0e8cc8bdSWilliam Juul 6709*0e8cc8bdSWilliam Juul } 6710*0e8cc8bdSWilliam Juul } 6711*0e8cc8bdSWilliam Juul } 6712*0e8cc8bdSWilliam Juul 6713*0e8cc8bdSWilliam Juul return NULL; 6714*0e8cc8bdSWilliam Juul } 6715*0e8cc8bdSWilliam Juul 6716*0e8cc8bdSWilliam Juul 6717*0e8cc8bdSWilliam Juul #if 0 6718*0e8cc8bdSWilliam Juul int yaffs_ApplyToDirectoryChildren(yaffs_Object * theDir, 6719*0e8cc8bdSWilliam Juul int (*fn) (yaffs_Object *)) 6720*0e8cc8bdSWilliam Juul { 6721*0e8cc8bdSWilliam Juul struct list_head *i; 6722*0e8cc8bdSWilliam Juul yaffs_Object *l; 6723*0e8cc8bdSWilliam Juul 6724*0e8cc8bdSWilliam Juul if (!theDir) { 6725*0e8cc8bdSWilliam Juul T(YAFFS_TRACE_ALWAYS, 6726*0e8cc8bdSWilliam Juul (TSTR 6727*0e8cc8bdSWilliam Juul ("tragedy: yaffs_FindObjectByName: null pointer directory" 6728*0e8cc8bdSWilliam Juul TENDSTR))); 6729*0e8cc8bdSWilliam Juul YBUG(); 6730*0e8cc8bdSWilliam Juul } 6731*0e8cc8bdSWilliam Juul if (theDir->variantType != YAFFS_OBJECT_TYPE_DIRECTORY) { 6732*0e8cc8bdSWilliam Juul T(YAFFS_TRACE_ALWAYS, 6733*0e8cc8bdSWilliam Juul (TSTR 6734*0e8cc8bdSWilliam Juul ("tragedy: yaffs_FindObjectByName: non-directory" TENDSTR))); 6735*0e8cc8bdSWilliam Juul YBUG(); 6736*0e8cc8bdSWilliam Juul } 6737*0e8cc8bdSWilliam Juul 6738*0e8cc8bdSWilliam Juul list_for_each(i, &theDir->variant.directoryVariant.children) { 6739*0e8cc8bdSWilliam Juul if (i) { 6740*0e8cc8bdSWilliam Juul l = list_entry(i, yaffs_Object, siblings); 6741*0e8cc8bdSWilliam Juul if (l && !fn(l)) { 6742*0e8cc8bdSWilliam Juul return YAFFS_FAIL; 6743*0e8cc8bdSWilliam Juul } 6744*0e8cc8bdSWilliam Juul } 6745*0e8cc8bdSWilliam Juul } 6746*0e8cc8bdSWilliam Juul 6747*0e8cc8bdSWilliam Juul return YAFFS_OK; 6748*0e8cc8bdSWilliam Juul 6749*0e8cc8bdSWilliam Juul } 6750*0e8cc8bdSWilliam Juul #endif 6751*0e8cc8bdSWilliam Juul 6752*0e8cc8bdSWilliam Juul /* GetEquivalentObject dereferences any hard links to get to the 6753*0e8cc8bdSWilliam Juul * actual object. 6754*0e8cc8bdSWilliam Juul */ 6755*0e8cc8bdSWilliam Juul 6756*0e8cc8bdSWilliam Juul yaffs_Object *yaffs_GetEquivalentObject(yaffs_Object * obj) 6757*0e8cc8bdSWilliam Juul { 6758*0e8cc8bdSWilliam Juul if (obj && obj->variantType == YAFFS_OBJECT_TYPE_HARDLINK) { 6759*0e8cc8bdSWilliam Juul /* We want the object id of the equivalent object, not this one */ 6760*0e8cc8bdSWilliam Juul obj = obj->variant.hardLinkVariant.equivalentObject; 6761*0e8cc8bdSWilliam Juul yaffs_CheckObjectDetailsLoaded(obj); 6762*0e8cc8bdSWilliam Juul } 6763*0e8cc8bdSWilliam Juul return obj; 6764*0e8cc8bdSWilliam Juul 6765*0e8cc8bdSWilliam Juul } 6766*0e8cc8bdSWilliam Juul 6767*0e8cc8bdSWilliam Juul int yaffs_GetObjectName(yaffs_Object * obj, YCHAR * name, int buffSize) 6768*0e8cc8bdSWilliam Juul { 6769*0e8cc8bdSWilliam Juul memset(name, 0, buffSize * sizeof(YCHAR)); 6770*0e8cc8bdSWilliam Juul 6771*0e8cc8bdSWilliam Juul yaffs_CheckObjectDetailsLoaded(obj); 6772*0e8cc8bdSWilliam Juul 6773*0e8cc8bdSWilliam Juul if (obj->objectId == YAFFS_OBJECTID_LOSTNFOUND) { 6774*0e8cc8bdSWilliam Juul yaffs_strncpy(name, YAFFS_LOSTNFOUND_NAME, buffSize - 1); 6775*0e8cc8bdSWilliam Juul } else if (obj->chunkId <= 0) { 6776*0e8cc8bdSWilliam Juul YCHAR locName[20]; 6777*0e8cc8bdSWilliam Juul /* make up a name */ 6778*0e8cc8bdSWilliam Juul yaffs_sprintf(locName, _Y("%s%d"), YAFFS_LOSTNFOUND_PREFIX, 6779*0e8cc8bdSWilliam Juul obj->objectId); 6780*0e8cc8bdSWilliam Juul yaffs_strncpy(name, locName, buffSize - 1); 6781*0e8cc8bdSWilliam Juul 6782*0e8cc8bdSWilliam Juul } 6783*0e8cc8bdSWilliam Juul #ifdef CONFIG_YAFFS_SHORT_NAMES_IN_RAM 6784*0e8cc8bdSWilliam Juul else if (obj->shortName[0]) { 6785*0e8cc8bdSWilliam Juul yaffs_strcpy(name, obj->shortName); 6786*0e8cc8bdSWilliam Juul } 6787*0e8cc8bdSWilliam Juul #endif 6788*0e8cc8bdSWilliam Juul else { 6789*0e8cc8bdSWilliam Juul int result; 6790*0e8cc8bdSWilliam Juul __u8 *buffer = yaffs_GetTempBuffer(obj->myDev, __LINE__); 6791*0e8cc8bdSWilliam Juul 6792*0e8cc8bdSWilliam Juul yaffs_ObjectHeader *oh = (yaffs_ObjectHeader *) buffer; 6793*0e8cc8bdSWilliam Juul 6794*0e8cc8bdSWilliam Juul memset(buffer, 0, obj->myDev->nDataBytesPerChunk); 6795*0e8cc8bdSWilliam Juul 6796*0e8cc8bdSWilliam Juul if (obj->chunkId >= 0) { 6797*0e8cc8bdSWilliam Juul result = yaffs_ReadChunkWithTagsFromNAND(obj->myDev, 6798*0e8cc8bdSWilliam Juul obj->chunkId, buffer, 6799*0e8cc8bdSWilliam Juul NULL); 6800*0e8cc8bdSWilliam Juul } 6801*0e8cc8bdSWilliam Juul yaffs_strncpy(name, oh->name, buffSize - 1); 6802*0e8cc8bdSWilliam Juul 6803*0e8cc8bdSWilliam Juul yaffs_ReleaseTempBuffer(obj->myDev, buffer, __LINE__); 6804*0e8cc8bdSWilliam Juul } 6805*0e8cc8bdSWilliam Juul 6806*0e8cc8bdSWilliam Juul return yaffs_strlen(name); 6807*0e8cc8bdSWilliam Juul } 6808*0e8cc8bdSWilliam Juul 6809*0e8cc8bdSWilliam Juul int yaffs_GetObjectFileLength(yaffs_Object * obj) 6810*0e8cc8bdSWilliam Juul { 6811*0e8cc8bdSWilliam Juul 6812*0e8cc8bdSWilliam Juul /* Dereference any hard linking */ 6813*0e8cc8bdSWilliam Juul obj = yaffs_GetEquivalentObject(obj); 6814*0e8cc8bdSWilliam Juul 6815*0e8cc8bdSWilliam Juul if (obj->variantType == YAFFS_OBJECT_TYPE_FILE) { 6816*0e8cc8bdSWilliam Juul return obj->variant.fileVariant.fileSize; 6817*0e8cc8bdSWilliam Juul } 6818*0e8cc8bdSWilliam Juul if (obj->variantType == YAFFS_OBJECT_TYPE_SYMLINK) { 6819*0e8cc8bdSWilliam Juul return yaffs_strlen(obj->variant.symLinkVariant.alias); 6820*0e8cc8bdSWilliam Juul } else { 6821*0e8cc8bdSWilliam Juul /* Only a directory should drop through to here */ 6822*0e8cc8bdSWilliam Juul return obj->myDev->nDataBytesPerChunk; 6823*0e8cc8bdSWilliam Juul } 6824*0e8cc8bdSWilliam Juul } 6825*0e8cc8bdSWilliam Juul 6826*0e8cc8bdSWilliam Juul int yaffs_GetObjectLinkCount(yaffs_Object * obj) 6827*0e8cc8bdSWilliam Juul { 6828*0e8cc8bdSWilliam Juul int count = 0; 6829*0e8cc8bdSWilliam Juul struct list_head *i; 6830*0e8cc8bdSWilliam Juul 6831*0e8cc8bdSWilliam Juul if (!obj->unlinked) { 6832*0e8cc8bdSWilliam Juul count++; /* the object itself */ 6833*0e8cc8bdSWilliam Juul } 6834*0e8cc8bdSWilliam Juul list_for_each(i, &obj->hardLinks) { 6835*0e8cc8bdSWilliam Juul count++; /* add the hard links; */ 6836*0e8cc8bdSWilliam Juul } 6837*0e8cc8bdSWilliam Juul return count; 6838*0e8cc8bdSWilliam Juul 6839*0e8cc8bdSWilliam Juul } 6840*0e8cc8bdSWilliam Juul 6841*0e8cc8bdSWilliam Juul int yaffs_GetObjectInode(yaffs_Object * obj) 6842*0e8cc8bdSWilliam Juul { 6843*0e8cc8bdSWilliam Juul obj = yaffs_GetEquivalentObject(obj); 6844*0e8cc8bdSWilliam Juul 6845*0e8cc8bdSWilliam Juul return obj->objectId; 6846*0e8cc8bdSWilliam Juul } 6847*0e8cc8bdSWilliam Juul 6848*0e8cc8bdSWilliam Juul unsigned yaffs_GetObjectType(yaffs_Object * obj) 6849*0e8cc8bdSWilliam Juul { 6850*0e8cc8bdSWilliam Juul obj = yaffs_GetEquivalentObject(obj); 6851*0e8cc8bdSWilliam Juul 6852*0e8cc8bdSWilliam Juul switch (obj->variantType) { 6853*0e8cc8bdSWilliam Juul case YAFFS_OBJECT_TYPE_FILE: 6854*0e8cc8bdSWilliam Juul return DT_REG; 6855*0e8cc8bdSWilliam Juul break; 6856*0e8cc8bdSWilliam Juul case YAFFS_OBJECT_TYPE_DIRECTORY: 6857*0e8cc8bdSWilliam Juul return DT_DIR; 6858*0e8cc8bdSWilliam Juul break; 6859*0e8cc8bdSWilliam Juul case YAFFS_OBJECT_TYPE_SYMLINK: 6860*0e8cc8bdSWilliam Juul return DT_LNK; 6861*0e8cc8bdSWilliam Juul break; 6862*0e8cc8bdSWilliam Juul case YAFFS_OBJECT_TYPE_HARDLINK: 6863*0e8cc8bdSWilliam Juul return DT_REG; 6864*0e8cc8bdSWilliam Juul break; 6865*0e8cc8bdSWilliam Juul case YAFFS_OBJECT_TYPE_SPECIAL: 6866*0e8cc8bdSWilliam Juul if (S_ISFIFO(obj->yst_mode)) 6867*0e8cc8bdSWilliam Juul return DT_FIFO; 6868*0e8cc8bdSWilliam Juul if (S_ISCHR(obj->yst_mode)) 6869*0e8cc8bdSWilliam Juul return DT_CHR; 6870*0e8cc8bdSWilliam Juul if (S_ISBLK(obj->yst_mode)) 6871*0e8cc8bdSWilliam Juul return DT_BLK; 6872*0e8cc8bdSWilliam Juul if (S_ISSOCK(obj->yst_mode)) 6873*0e8cc8bdSWilliam Juul return DT_SOCK; 6874*0e8cc8bdSWilliam Juul default: 6875*0e8cc8bdSWilliam Juul return DT_REG; 6876*0e8cc8bdSWilliam Juul break; 6877*0e8cc8bdSWilliam Juul } 6878*0e8cc8bdSWilliam Juul } 6879*0e8cc8bdSWilliam Juul 6880*0e8cc8bdSWilliam Juul YCHAR *yaffs_GetSymlinkAlias(yaffs_Object * obj) 6881*0e8cc8bdSWilliam Juul { 6882*0e8cc8bdSWilliam Juul obj = yaffs_GetEquivalentObject(obj); 6883*0e8cc8bdSWilliam Juul if (obj->variantType == YAFFS_OBJECT_TYPE_SYMLINK) { 6884*0e8cc8bdSWilliam Juul return yaffs_CloneString(obj->variant.symLinkVariant.alias); 6885*0e8cc8bdSWilliam Juul } else { 6886*0e8cc8bdSWilliam Juul return yaffs_CloneString(_Y("")); 6887*0e8cc8bdSWilliam Juul } 6888*0e8cc8bdSWilliam Juul } 6889*0e8cc8bdSWilliam Juul 6890*0e8cc8bdSWilliam Juul #ifndef CONFIG_YAFFS_WINCE 6891*0e8cc8bdSWilliam Juul 6892*0e8cc8bdSWilliam Juul int yaffs_SetAttributes(yaffs_Object * obj, struct iattr *attr) 6893*0e8cc8bdSWilliam Juul { 6894*0e8cc8bdSWilliam Juul unsigned int valid = attr->ia_valid; 6895*0e8cc8bdSWilliam Juul 6896*0e8cc8bdSWilliam Juul if (valid & ATTR_MODE) 6897*0e8cc8bdSWilliam Juul obj->yst_mode = attr->ia_mode; 6898*0e8cc8bdSWilliam Juul if (valid & ATTR_UID) 6899*0e8cc8bdSWilliam Juul obj->yst_uid = attr->ia_uid; 6900*0e8cc8bdSWilliam Juul if (valid & ATTR_GID) 6901*0e8cc8bdSWilliam Juul obj->yst_gid = attr->ia_gid; 6902*0e8cc8bdSWilliam Juul 6903*0e8cc8bdSWilliam Juul if (valid & ATTR_ATIME) 6904*0e8cc8bdSWilliam Juul obj->yst_atime = Y_TIME_CONVERT(attr->ia_atime); 6905*0e8cc8bdSWilliam Juul if (valid & ATTR_CTIME) 6906*0e8cc8bdSWilliam Juul obj->yst_ctime = Y_TIME_CONVERT(attr->ia_ctime); 6907*0e8cc8bdSWilliam Juul if (valid & ATTR_MTIME) 6908*0e8cc8bdSWilliam Juul obj->yst_mtime = Y_TIME_CONVERT(attr->ia_mtime); 6909*0e8cc8bdSWilliam Juul 6910*0e8cc8bdSWilliam Juul if (valid & ATTR_SIZE) 6911*0e8cc8bdSWilliam Juul yaffs_ResizeFile(obj, attr->ia_size); 6912*0e8cc8bdSWilliam Juul 6913*0e8cc8bdSWilliam Juul yaffs_UpdateObjectHeader(obj, NULL, 1, 0, 0); 6914*0e8cc8bdSWilliam Juul 6915*0e8cc8bdSWilliam Juul return YAFFS_OK; 6916*0e8cc8bdSWilliam Juul 6917*0e8cc8bdSWilliam Juul } 6918*0e8cc8bdSWilliam Juul int yaffs_GetAttributes(yaffs_Object * obj, struct iattr *attr) 6919*0e8cc8bdSWilliam Juul { 6920*0e8cc8bdSWilliam Juul unsigned int valid = 0; 6921*0e8cc8bdSWilliam Juul 6922*0e8cc8bdSWilliam Juul attr->ia_mode = obj->yst_mode; 6923*0e8cc8bdSWilliam Juul valid |= ATTR_MODE; 6924*0e8cc8bdSWilliam Juul attr->ia_uid = obj->yst_uid; 6925*0e8cc8bdSWilliam Juul valid |= ATTR_UID; 6926*0e8cc8bdSWilliam Juul attr->ia_gid = obj->yst_gid; 6927*0e8cc8bdSWilliam Juul valid |= ATTR_GID; 6928*0e8cc8bdSWilliam Juul 6929*0e8cc8bdSWilliam Juul Y_TIME_CONVERT(attr->ia_atime) = obj->yst_atime; 6930*0e8cc8bdSWilliam Juul valid |= ATTR_ATIME; 6931*0e8cc8bdSWilliam Juul Y_TIME_CONVERT(attr->ia_ctime) = obj->yst_ctime; 6932*0e8cc8bdSWilliam Juul valid |= ATTR_CTIME; 6933*0e8cc8bdSWilliam Juul Y_TIME_CONVERT(attr->ia_mtime) = obj->yst_mtime; 6934*0e8cc8bdSWilliam Juul valid |= ATTR_MTIME; 6935*0e8cc8bdSWilliam Juul 6936*0e8cc8bdSWilliam Juul attr->ia_size = yaffs_GetFileSize(obj); 6937*0e8cc8bdSWilliam Juul valid |= ATTR_SIZE; 6938*0e8cc8bdSWilliam Juul 6939*0e8cc8bdSWilliam Juul attr->ia_valid = valid; 6940*0e8cc8bdSWilliam Juul 6941*0e8cc8bdSWilliam Juul return YAFFS_OK; 6942*0e8cc8bdSWilliam Juul 6943*0e8cc8bdSWilliam Juul } 6944*0e8cc8bdSWilliam Juul 6945*0e8cc8bdSWilliam Juul #endif 6946*0e8cc8bdSWilliam Juul 6947*0e8cc8bdSWilliam Juul #if 0 6948*0e8cc8bdSWilliam Juul int yaffs_DumpObject(yaffs_Object * obj) 6949*0e8cc8bdSWilliam Juul { 6950*0e8cc8bdSWilliam Juul YCHAR name[257]; 6951*0e8cc8bdSWilliam Juul 6952*0e8cc8bdSWilliam Juul yaffs_GetObjectName(obj, name, 256); 6953*0e8cc8bdSWilliam Juul 6954*0e8cc8bdSWilliam Juul T(YAFFS_TRACE_ALWAYS, 6955*0e8cc8bdSWilliam Juul (TSTR 6956*0e8cc8bdSWilliam Juul ("Object %d, inode %d \"%s\"\n dirty %d valid %d serial %d sum %d" 6957*0e8cc8bdSWilliam Juul " chunk %d type %d size %d\n" 6958*0e8cc8bdSWilliam Juul TENDSTR), obj->objectId, yaffs_GetObjectInode(obj), name, 6959*0e8cc8bdSWilliam Juul obj->dirty, obj->valid, obj->serial, obj->sum, obj->chunkId, 6960*0e8cc8bdSWilliam Juul yaffs_GetObjectType(obj), yaffs_GetObjectFileLength(obj))); 6961*0e8cc8bdSWilliam Juul 6962*0e8cc8bdSWilliam Juul return YAFFS_OK; 6963*0e8cc8bdSWilliam Juul } 6964*0e8cc8bdSWilliam Juul #endif 6965*0e8cc8bdSWilliam Juul 6966*0e8cc8bdSWilliam Juul /*---------------------------- Initialisation code -------------------------------------- */ 6967*0e8cc8bdSWilliam Juul 6968*0e8cc8bdSWilliam Juul static int yaffs_CheckDevFunctions(const yaffs_Device * dev) 6969*0e8cc8bdSWilliam Juul { 6970*0e8cc8bdSWilliam Juul 6971*0e8cc8bdSWilliam Juul /* Common functions, gotta have */ 6972*0e8cc8bdSWilliam Juul if (!dev->eraseBlockInNAND || !dev->initialiseNAND) 6973*0e8cc8bdSWilliam Juul return 0; 6974*0e8cc8bdSWilliam Juul 6975*0e8cc8bdSWilliam Juul #ifdef CONFIG_YAFFS_YAFFS2 6976*0e8cc8bdSWilliam Juul 6977*0e8cc8bdSWilliam Juul /* Can use the "with tags" style interface for yaffs1 or yaffs2 */ 6978*0e8cc8bdSWilliam Juul if (dev->writeChunkWithTagsToNAND && 6979*0e8cc8bdSWilliam Juul dev->readChunkWithTagsFromNAND && 6980*0e8cc8bdSWilliam Juul !dev->writeChunkToNAND && 6981*0e8cc8bdSWilliam Juul !dev->readChunkFromNAND && 6982*0e8cc8bdSWilliam Juul dev->markNANDBlockBad && dev->queryNANDBlock) 6983*0e8cc8bdSWilliam Juul return 1; 6984*0e8cc8bdSWilliam Juul #endif 6985*0e8cc8bdSWilliam Juul 6986*0e8cc8bdSWilliam Juul /* Can use the "spare" style interface for yaffs1 */ 6987*0e8cc8bdSWilliam Juul if (!dev->isYaffs2 && 6988*0e8cc8bdSWilliam Juul !dev->writeChunkWithTagsToNAND && 6989*0e8cc8bdSWilliam Juul !dev->readChunkWithTagsFromNAND && 6990*0e8cc8bdSWilliam Juul dev->writeChunkToNAND && 6991*0e8cc8bdSWilliam Juul dev->readChunkFromNAND && 6992*0e8cc8bdSWilliam Juul !dev->markNANDBlockBad && !dev->queryNANDBlock) 6993*0e8cc8bdSWilliam Juul return 1; 6994*0e8cc8bdSWilliam Juul 6995*0e8cc8bdSWilliam Juul return 0; /* bad */ 6996*0e8cc8bdSWilliam Juul } 6997*0e8cc8bdSWilliam Juul 6998*0e8cc8bdSWilliam Juul 6999*0e8cc8bdSWilliam Juul static int yaffs_CreateInitialDirectories(yaffs_Device *dev) 7000*0e8cc8bdSWilliam Juul { 7001*0e8cc8bdSWilliam Juul /* Initialise the unlinked, deleted, root and lost and found directories */ 7002*0e8cc8bdSWilliam Juul 7003*0e8cc8bdSWilliam Juul dev->lostNFoundDir = dev->rootDir = NULL; 7004*0e8cc8bdSWilliam Juul dev->unlinkedDir = dev->deletedDir = NULL; 7005*0e8cc8bdSWilliam Juul 7006*0e8cc8bdSWilliam Juul dev->unlinkedDir = 7007*0e8cc8bdSWilliam Juul yaffs_CreateFakeDirectory(dev, YAFFS_OBJECTID_UNLINKED, S_IFDIR); 7008*0e8cc8bdSWilliam Juul 7009*0e8cc8bdSWilliam Juul dev->deletedDir = 7010*0e8cc8bdSWilliam Juul yaffs_CreateFakeDirectory(dev, YAFFS_OBJECTID_DELETED, S_IFDIR); 7011*0e8cc8bdSWilliam Juul 7012*0e8cc8bdSWilliam Juul dev->rootDir = 7013*0e8cc8bdSWilliam Juul yaffs_CreateFakeDirectory(dev, YAFFS_OBJECTID_ROOT, 7014*0e8cc8bdSWilliam Juul YAFFS_ROOT_MODE | S_IFDIR); 7015*0e8cc8bdSWilliam Juul dev->lostNFoundDir = 7016*0e8cc8bdSWilliam Juul yaffs_CreateFakeDirectory(dev, YAFFS_OBJECTID_LOSTNFOUND, 7017*0e8cc8bdSWilliam Juul YAFFS_LOSTNFOUND_MODE | S_IFDIR); 7018*0e8cc8bdSWilliam Juul 7019*0e8cc8bdSWilliam Juul if(dev->lostNFoundDir && dev->rootDir && dev->unlinkedDir && dev->deletedDir){ 7020*0e8cc8bdSWilliam Juul yaffs_AddObjectToDirectory(dev->rootDir, dev->lostNFoundDir); 7021*0e8cc8bdSWilliam Juul return YAFFS_OK; 7022*0e8cc8bdSWilliam Juul } 7023*0e8cc8bdSWilliam Juul 7024*0e8cc8bdSWilliam Juul return YAFFS_FAIL; 7025*0e8cc8bdSWilliam Juul } 7026*0e8cc8bdSWilliam Juul 7027*0e8cc8bdSWilliam Juul int yaffs_GutsInitialise(yaffs_Device * dev) 7028*0e8cc8bdSWilliam Juul { 7029*0e8cc8bdSWilliam Juul int init_failed = 0; 7030*0e8cc8bdSWilliam Juul unsigned x; 7031*0e8cc8bdSWilliam Juul int bits; 7032*0e8cc8bdSWilliam Juul 7033*0e8cc8bdSWilliam Juul T(YAFFS_TRACE_TRACING, (TSTR("yaffs: yaffs_GutsInitialise()" TENDSTR))); 7034*0e8cc8bdSWilliam Juul 7035*0e8cc8bdSWilliam Juul /* Check stuff that must be set */ 7036*0e8cc8bdSWilliam Juul 7037*0e8cc8bdSWilliam Juul if (!dev) { 7038*0e8cc8bdSWilliam Juul T(YAFFS_TRACE_ALWAYS, (TSTR("yaffs: Need a device" TENDSTR))); 7039*0e8cc8bdSWilliam Juul return YAFFS_FAIL; 7040*0e8cc8bdSWilliam Juul } 7041*0e8cc8bdSWilliam Juul 7042*0e8cc8bdSWilliam Juul dev->internalStartBlock = dev->startBlock; 7043*0e8cc8bdSWilliam Juul dev->internalEndBlock = dev->endBlock; 7044*0e8cc8bdSWilliam Juul dev->blockOffset = 0; 7045*0e8cc8bdSWilliam Juul dev->chunkOffset = 0; 7046*0e8cc8bdSWilliam Juul dev->nFreeChunks = 0; 7047*0e8cc8bdSWilliam Juul 7048*0e8cc8bdSWilliam Juul if (dev->startBlock == 0) { 7049*0e8cc8bdSWilliam Juul dev->internalStartBlock = dev->startBlock + 1; 7050*0e8cc8bdSWilliam Juul dev->internalEndBlock = dev->endBlock + 1; 7051*0e8cc8bdSWilliam Juul dev->blockOffset = 1; 7052*0e8cc8bdSWilliam Juul dev->chunkOffset = dev->nChunksPerBlock; 7053*0e8cc8bdSWilliam Juul } 7054*0e8cc8bdSWilliam Juul 7055*0e8cc8bdSWilliam Juul /* Check geometry parameters. */ 7056*0e8cc8bdSWilliam Juul 7057*0e8cc8bdSWilliam Juul if ((dev->isYaffs2 && dev->nDataBytesPerChunk < 1024) || 7058*0e8cc8bdSWilliam Juul (!dev->isYaffs2 && dev->nDataBytesPerChunk != 512) || 7059*0e8cc8bdSWilliam Juul dev->nChunksPerBlock < 2 || 7060*0e8cc8bdSWilliam Juul dev->nReservedBlocks < 2 || 7061*0e8cc8bdSWilliam Juul dev->internalStartBlock <= 0 || 7062*0e8cc8bdSWilliam Juul dev->internalEndBlock <= 0 || 7063*0e8cc8bdSWilliam Juul dev->internalEndBlock <= (dev->internalStartBlock + dev->nReservedBlocks + 2) // otherwise it is too small 7064*0e8cc8bdSWilliam Juul ) { 7065*0e8cc8bdSWilliam Juul T(YAFFS_TRACE_ALWAYS, 7066*0e8cc8bdSWilliam Juul (TSTR 7067*0e8cc8bdSWilliam Juul ("yaffs: NAND geometry problems: chunk size %d, type is yaffs%s " 7068*0e8cc8bdSWilliam Juul TENDSTR), dev->nDataBytesPerChunk, dev->isYaffs2 ? "2" : "")); 7069*0e8cc8bdSWilliam Juul return YAFFS_FAIL; 7070*0e8cc8bdSWilliam Juul } 7071*0e8cc8bdSWilliam Juul 7072*0e8cc8bdSWilliam Juul if (yaffs_InitialiseNAND(dev) != YAFFS_OK) { 7073*0e8cc8bdSWilliam Juul T(YAFFS_TRACE_ALWAYS, 7074*0e8cc8bdSWilliam Juul (TSTR("yaffs: InitialiseNAND failed" TENDSTR))); 7075*0e8cc8bdSWilliam Juul return YAFFS_FAIL; 7076*0e8cc8bdSWilliam Juul } 7077*0e8cc8bdSWilliam Juul 7078*0e8cc8bdSWilliam Juul /* Got the right mix of functions? */ 7079*0e8cc8bdSWilliam Juul if (!yaffs_CheckDevFunctions(dev)) { 7080*0e8cc8bdSWilliam Juul /* Function missing */ 7081*0e8cc8bdSWilliam Juul T(YAFFS_TRACE_ALWAYS, 7082*0e8cc8bdSWilliam Juul (TSTR 7083*0e8cc8bdSWilliam Juul ("yaffs: device function(s) missing or wrong\n" TENDSTR))); 7084*0e8cc8bdSWilliam Juul 7085*0e8cc8bdSWilliam Juul return YAFFS_FAIL; 7086*0e8cc8bdSWilliam Juul } 7087*0e8cc8bdSWilliam Juul 7088*0e8cc8bdSWilliam Juul /* This is really a compilation check. */ 7089*0e8cc8bdSWilliam Juul if (!yaffs_CheckStructures()) { 7090*0e8cc8bdSWilliam Juul T(YAFFS_TRACE_ALWAYS, 7091*0e8cc8bdSWilliam Juul (TSTR("yaffs_CheckStructures failed\n" TENDSTR))); 7092*0e8cc8bdSWilliam Juul return YAFFS_FAIL; 7093*0e8cc8bdSWilliam Juul } 7094*0e8cc8bdSWilliam Juul 7095*0e8cc8bdSWilliam Juul if (dev->isMounted) { 7096*0e8cc8bdSWilliam Juul T(YAFFS_TRACE_ALWAYS, 7097*0e8cc8bdSWilliam Juul (TSTR("yaffs: device already mounted\n" TENDSTR))); 7098*0e8cc8bdSWilliam Juul return YAFFS_FAIL; 7099*0e8cc8bdSWilliam Juul } 7100*0e8cc8bdSWilliam Juul 7101*0e8cc8bdSWilliam Juul /* Finished with most checks. One or two more checks happen later on too. */ 7102*0e8cc8bdSWilliam Juul 7103*0e8cc8bdSWilliam Juul dev->isMounted = 1; 7104*0e8cc8bdSWilliam Juul 7105*0e8cc8bdSWilliam Juul 7106*0e8cc8bdSWilliam Juul 7107*0e8cc8bdSWilliam Juul /* OK now calculate a few things for the device */ 7108*0e8cc8bdSWilliam Juul 7109*0e8cc8bdSWilliam Juul /* 7110*0e8cc8bdSWilliam Juul * Calculate all the chunk size manipulation numbers: 7111*0e8cc8bdSWilliam Juul */ 7112*0e8cc8bdSWilliam Juul /* Start off assuming it is a power of 2 */ 7113*0e8cc8bdSWilliam Juul dev->chunkShift = ShiftDiv(dev->nDataBytesPerChunk); 7114*0e8cc8bdSWilliam Juul dev->chunkMask = (1<<dev->chunkShift) - 1; 7115*0e8cc8bdSWilliam Juul 7116*0e8cc8bdSWilliam Juul if(dev->nDataBytesPerChunk == (dev->chunkMask + 1)){ 7117*0e8cc8bdSWilliam Juul /* Yes it is a power of 2, disable crumbs */ 7118*0e8cc8bdSWilliam Juul dev->crumbMask = 0; 7119*0e8cc8bdSWilliam Juul dev->crumbShift = 0; 7120*0e8cc8bdSWilliam Juul dev->crumbsPerChunk = 0; 7121*0e8cc8bdSWilliam Juul } else { 7122*0e8cc8bdSWilliam Juul /* Not a power of 2, use crumbs instead */ 7123*0e8cc8bdSWilliam Juul dev->crumbShift = ShiftDiv(sizeof(yaffs_PackedTags2TagsPart)); 7124*0e8cc8bdSWilliam Juul dev->crumbMask = (1<<dev->crumbShift)-1; 7125*0e8cc8bdSWilliam Juul dev->crumbsPerChunk = dev->nDataBytesPerChunk/(1 << dev->crumbShift); 7126*0e8cc8bdSWilliam Juul dev->chunkShift = 0; 7127*0e8cc8bdSWilliam Juul dev->chunkMask = 0; 7128*0e8cc8bdSWilliam Juul } 7129*0e8cc8bdSWilliam Juul 7130*0e8cc8bdSWilliam Juul 7131*0e8cc8bdSWilliam Juul /* 7132*0e8cc8bdSWilliam Juul * Calculate chunkGroupBits. 7133*0e8cc8bdSWilliam Juul * We need to find the next power of 2 > than internalEndBlock 7134*0e8cc8bdSWilliam Juul */ 7135*0e8cc8bdSWilliam Juul 7136*0e8cc8bdSWilliam Juul x = dev->nChunksPerBlock * (dev->internalEndBlock + 1); 7137*0e8cc8bdSWilliam Juul 7138*0e8cc8bdSWilliam Juul bits = ShiftsGE(x); 7139*0e8cc8bdSWilliam Juul 7140*0e8cc8bdSWilliam Juul /* Set up tnode width if wide tnodes are enabled. */ 7141*0e8cc8bdSWilliam Juul if(!dev->wideTnodesDisabled){ 7142*0e8cc8bdSWilliam Juul /* bits must be even so that we end up with 32-bit words */ 7143*0e8cc8bdSWilliam Juul if(bits & 1) 7144*0e8cc8bdSWilliam Juul bits++; 7145*0e8cc8bdSWilliam Juul if(bits < 16) 7146*0e8cc8bdSWilliam Juul dev->tnodeWidth = 16; 7147*0e8cc8bdSWilliam Juul else 7148*0e8cc8bdSWilliam Juul dev->tnodeWidth = bits; 7149*0e8cc8bdSWilliam Juul } 7150*0e8cc8bdSWilliam Juul else 7151*0e8cc8bdSWilliam Juul dev->tnodeWidth = 16; 7152*0e8cc8bdSWilliam Juul 7153*0e8cc8bdSWilliam Juul dev->tnodeMask = (1<<dev->tnodeWidth)-1; 7154*0e8cc8bdSWilliam Juul 7155*0e8cc8bdSWilliam Juul /* Level0 Tnodes are 16 bits or wider (if wide tnodes are enabled), 7156*0e8cc8bdSWilliam Juul * so if the bitwidth of the 7157*0e8cc8bdSWilliam Juul * chunk range we're using is greater than 16 we need 7158*0e8cc8bdSWilliam Juul * to figure out chunk shift and chunkGroupSize 7159*0e8cc8bdSWilliam Juul */ 7160*0e8cc8bdSWilliam Juul 7161*0e8cc8bdSWilliam Juul if (bits <= dev->tnodeWidth) 7162*0e8cc8bdSWilliam Juul dev->chunkGroupBits = 0; 7163*0e8cc8bdSWilliam Juul else 7164*0e8cc8bdSWilliam Juul dev->chunkGroupBits = bits - dev->tnodeWidth; 7165*0e8cc8bdSWilliam Juul 7166*0e8cc8bdSWilliam Juul 7167*0e8cc8bdSWilliam Juul dev->chunkGroupSize = 1 << dev->chunkGroupBits; 7168*0e8cc8bdSWilliam Juul 7169*0e8cc8bdSWilliam Juul if (dev->nChunksPerBlock < dev->chunkGroupSize) { 7170*0e8cc8bdSWilliam Juul /* We have a problem because the soft delete won't work if 7171*0e8cc8bdSWilliam Juul * the chunk group size > chunks per block. 7172*0e8cc8bdSWilliam Juul * This can be remedied by using larger "virtual blocks". 7173*0e8cc8bdSWilliam Juul */ 7174*0e8cc8bdSWilliam Juul T(YAFFS_TRACE_ALWAYS, 7175*0e8cc8bdSWilliam Juul (TSTR("yaffs: chunk group too large\n" TENDSTR))); 7176*0e8cc8bdSWilliam Juul 7177*0e8cc8bdSWilliam Juul return YAFFS_FAIL; 7178*0e8cc8bdSWilliam Juul } 7179*0e8cc8bdSWilliam Juul 7180*0e8cc8bdSWilliam Juul /* OK, we've finished verifying the device, lets continue with initialisation */ 7181*0e8cc8bdSWilliam Juul 7182*0e8cc8bdSWilliam Juul /* More device initialisation */ 7183*0e8cc8bdSWilliam Juul dev->garbageCollections = 0; 7184*0e8cc8bdSWilliam Juul dev->passiveGarbageCollections = 0; 7185*0e8cc8bdSWilliam Juul dev->currentDirtyChecker = 0; 7186*0e8cc8bdSWilliam Juul dev->bufferedBlock = -1; 7187*0e8cc8bdSWilliam Juul dev->doingBufferedBlockRewrite = 0; 7188*0e8cc8bdSWilliam Juul dev->nDeletedFiles = 0; 7189*0e8cc8bdSWilliam Juul dev->nBackgroundDeletions = 0; 7190*0e8cc8bdSWilliam Juul dev->nUnlinkedFiles = 0; 7191*0e8cc8bdSWilliam Juul dev->eccFixed = 0; 7192*0e8cc8bdSWilliam Juul dev->eccUnfixed = 0; 7193*0e8cc8bdSWilliam Juul dev->tagsEccFixed = 0; 7194*0e8cc8bdSWilliam Juul dev->tagsEccUnfixed = 0; 7195*0e8cc8bdSWilliam Juul dev->nErasureFailures = 0; 7196*0e8cc8bdSWilliam Juul dev->nErasedBlocks = 0; 7197*0e8cc8bdSWilliam Juul dev->isDoingGC = 0; 7198*0e8cc8bdSWilliam Juul dev->hasPendingPrioritisedGCs = 1; /* Assume the worst for now, will get fixed on first GC */ 7199*0e8cc8bdSWilliam Juul 7200*0e8cc8bdSWilliam Juul /* Initialise temporary buffers and caches. */ 7201*0e8cc8bdSWilliam Juul if(!yaffs_InitialiseTempBuffers(dev)) 7202*0e8cc8bdSWilliam Juul init_failed = 1; 7203*0e8cc8bdSWilliam Juul 7204*0e8cc8bdSWilliam Juul dev->srCache = NULL; 7205*0e8cc8bdSWilliam Juul dev->gcCleanupList = NULL; 7206*0e8cc8bdSWilliam Juul 7207*0e8cc8bdSWilliam Juul 7208*0e8cc8bdSWilliam Juul if (!init_failed && 7209*0e8cc8bdSWilliam Juul dev->nShortOpCaches > 0) { 7210*0e8cc8bdSWilliam Juul int i; 7211*0e8cc8bdSWilliam Juul __u8 *buf; 7212*0e8cc8bdSWilliam Juul int srCacheBytes = dev->nShortOpCaches * sizeof(yaffs_ChunkCache); 7213*0e8cc8bdSWilliam Juul 7214*0e8cc8bdSWilliam Juul if (dev->nShortOpCaches > YAFFS_MAX_SHORT_OP_CACHES) { 7215*0e8cc8bdSWilliam Juul dev->nShortOpCaches = YAFFS_MAX_SHORT_OP_CACHES; 7216*0e8cc8bdSWilliam Juul } 7217*0e8cc8bdSWilliam Juul 7218*0e8cc8bdSWilliam Juul buf = dev->srCache = YMALLOC(srCacheBytes); 7219*0e8cc8bdSWilliam Juul 7220*0e8cc8bdSWilliam Juul if(dev->srCache) 7221*0e8cc8bdSWilliam Juul memset(dev->srCache,0,srCacheBytes); 7222*0e8cc8bdSWilliam Juul 7223*0e8cc8bdSWilliam Juul for (i = 0; i < dev->nShortOpCaches && buf; i++) { 7224*0e8cc8bdSWilliam Juul dev->srCache[i].object = NULL; 7225*0e8cc8bdSWilliam Juul dev->srCache[i].lastUse = 0; 7226*0e8cc8bdSWilliam Juul dev->srCache[i].dirty = 0; 7227*0e8cc8bdSWilliam Juul dev->srCache[i].data = buf = YMALLOC_DMA(dev->nDataBytesPerChunk); 7228*0e8cc8bdSWilliam Juul } 7229*0e8cc8bdSWilliam Juul if(!buf) 7230*0e8cc8bdSWilliam Juul init_failed = 1; 7231*0e8cc8bdSWilliam Juul 7232*0e8cc8bdSWilliam Juul dev->srLastUse = 0; 7233*0e8cc8bdSWilliam Juul } 7234*0e8cc8bdSWilliam Juul 7235*0e8cc8bdSWilliam Juul dev->cacheHits = 0; 7236*0e8cc8bdSWilliam Juul 7237*0e8cc8bdSWilliam Juul if(!init_failed){ 7238*0e8cc8bdSWilliam Juul dev->gcCleanupList = YMALLOC(dev->nChunksPerBlock * sizeof(__u32)); 7239*0e8cc8bdSWilliam Juul if(!dev->gcCleanupList) 7240*0e8cc8bdSWilliam Juul init_failed = 1; 7241*0e8cc8bdSWilliam Juul } 7242*0e8cc8bdSWilliam Juul 7243*0e8cc8bdSWilliam Juul if (dev->isYaffs2) { 7244*0e8cc8bdSWilliam Juul dev->useHeaderFileSize = 1; 7245*0e8cc8bdSWilliam Juul } 7246*0e8cc8bdSWilliam Juul if(!init_failed && !yaffs_InitialiseBlocks(dev)) 7247*0e8cc8bdSWilliam Juul init_failed = 1; 7248*0e8cc8bdSWilliam Juul 7249*0e8cc8bdSWilliam Juul yaffs_InitialiseTnodes(dev); 7250*0e8cc8bdSWilliam Juul yaffs_InitialiseObjects(dev); 7251*0e8cc8bdSWilliam Juul 7252*0e8cc8bdSWilliam Juul if(!init_failed && !yaffs_CreateInitialDirectories(dev)) 7253*0e8cc8bdSWilliam Juul init_failed = 1; 7254*0e8cc8bdSWilliam Juul 7255*0e8cc8bdSWilliam Juul 7256*0e8cc8bdSWilliam Juul if(!init_failed){ 7257*0e8cc8bdSWilliam Juul /* Now scan the flash. */ 7258*0e8cc8bdSWilliam Juul if (dev->isYaffs2) { 7259*0e8cc8bdSWilliam Juul if(yaffs_CheckpointRestore(dev)) { 7260*0e8cc8bdSWilliam Juul T(YAFFS_TRACE_ALWAYS, 7261*0e8cc8bdSWilliam Juul (TSTR("yaffs: restored from checkpoint" TENDSTR))); 7262*0e8cc8bdSWilliam Juul } else { 7263*0e8cc8bdSWilliam Juul 7264*0e8cc8bdSWilliam Juul /* Clean up the mess caused by an aborted checkpoint load 7265*0e8cc8bdSWilliam Juul * and scan backwards. 7266*0e8cc8bdSWilliam Juul */ 7267*0e8cc8bdSWilliam Juul yaffs_DeinitialiseBlocks(dev); 7268*0e8cc8bdSWilliam Juul yaffs_DeinitialiseTnodes(dev); 7269*0e8cc8bdSWilliam Juul yaffs_DeinitialiseObjects(dev); 7270*0e8cc8bdSWilliam Juul 7271*0e8cc8bdSWilliam Juul 7272*0e8cc8bdSWilliam Juul dev->nErasedBlocks = 0; 7273*0e8cc8bdSWilliam Juul dev->nFreeChunks = 0; 7274*0e8cc8bdSWilliam Juul dev->allocationBlock = -1; 7275*0e8cc8bdSWilliam Juul dev->allocationPage = -1; 7276*0e8cc8bdSWilliam Juul dev->nDeletedFiles = 0; 7277*0e8cc8bdSWilliam Juul dev->nUnlinkedFiles = 0; 7278*0e8cc8bdSWilliam Juul dev->nBackgroundDeletions = 0; 7279*0e8cc8bdSWilliam Juul dev->oldestDirtySequence = 0; 7280*0e8cc8bdSWilliam Juul 7281*0e8cc8bdSWilliam Juul if(!init_failed && !yaffs_InitialiseBlocks(dev)) 7282*0e8cc8bdSWilliam Juul init_failed = 1; 7283*0e8cc8bdSWilliam Juul 7284*0e8cc8bdSWilliam Juul yaffs_InitialiseTnodes(dev); 7285*0e8cc8bdSWilliam Juul yaffs_InitialiseObjects(dev); 7286*0e8cc8bdSWilliam Juul 7287*0e8cc8bdSWilliam Juul if(!init_failed && !yaffs_CreateInitialDirectories(dev)) 7288*0e8cc8bdSWilliam Juul init_failed = 1; 7289*0e8cc8bdSWilliam Juul 7290*0e8cc8bdSWilliam Juul if(!init_failed && !yaffs_ScanBackwards(dev)) 7291*0e8cc8bdSWilliam Juul init_failed = 1; 7292*0e8cc8bdSWilliam Juul } 7293*0e8cc8bdSWilliam Juul }else 7294*0e8cc8bdSWilliam Juul if(!yaffs_Scan(dev)) 7295*0e8cc8bdSWilliam Juul init_failed = 1; 7296*0e8cc8bdSWilliam Juul } 7297*0e8cc8bdSWilliam Juul 7298*0e8cc8bdSWilliam Juul if(init_failed){ 7299*0e8cc8bdSWilliam Juul /* Clean up the mess */ 7300*0e8cc8bdSWilliam Juul T(YAFFS_TRACE_TRACING, 7301*0e8cc8bdSWilliam Juul (TSTR("yaffs: yaffs_GutsInitialise() aborted.\n" TENDSTR))); 7302*0e8cc8bdSWilliam Juul 7303*0e8cc8bdSWilliam Juul yaffs_Deinitialise(dev); 7304*0e8cc8bdSWilliam Juul return YAFFS_FAIL; 7305*0e8cc8bdSWilliam Juul } 7306*0e8cc8bdSWilliam Juul 7307*0e8cc8bdSWilliam Juul /* Zero out stats */ 7308*0e8cc8bdSWilliam Juul dev->nPageReads = 0; 7309*0e8cc8bdSWilliam Juul dev->nPageWrites = 0; 7310*0e8cc8bdSWilliam Juul dev->nBlockErasures = 0; 7311*0e8cc8bdSWilliam Juul dev->nGCCopies = 0; 7312*0e8cc8bdSWilliam Juul dev->nRetriedWrites = 0; 7313*0e8cc8bdSWilliam Juul 7314*0e8cc8bdSWilliam Juul dev->nRetiredBlocks = 0; 7315*0e8cc8bdSWilliam Juul 7316*0e8cc8bdSWilliam Juul yaffs_VerifyFreeChunks(dev); 7317*0e8cc8bdSWilliam Juul yaffs_VerifyBlocks(dev); 7318*0e8cc8bdSWilliam Juul 7319*0e8cc8bdSWilliam Juul 7320*0e8cc8bdSWilliam Juul T(YAFFS_TRACE_TRACING, 7321*0e8cc8bdSWilliam Juul (TSTR("yaffs: yaffs_GutsInitialise() done.\n" TENDSTR))); 7322*0e8cc8bdSWilliam Juul return YAFFS_OK; 7323*0e8cc8bdSWilliam Juul 7324*0e8cc8bdSWilliam Juul } 7325*0e8cc8bdSWilliam Juul 7326*0e8cc8bdSWilliam Juul void yaffs_Deinitialise(yaffs_Device * dev) 7327*0e8cc8bdSWilliam Juul { 7328*0e8cc8bdSWilliam Juul if (dev->isMounted) { 7329*0e8cc8bdSWilliam Juul int i; 7330*0e8cc8bdSWilliam Juul 7331*0e8cc8bdSWilliam Juul yaffs_DeinitialiseBlocks(dev); 7332*0e8cc8bdSWilliam Juul yaffs_DeinitialiseTnodes(dev); 7333*0e8cc8bdSWilliam Juul yaffs_DeinitialiseObjects(dev); 7334*0e8cc8bdSWilliam Juul if (dev->nShortOpCaches > 0 && 7335*0e8cc8bdSWilliam Juul dev->srCache) { 7336*0e8cc8bdSWilliam Juul 7337*0e8cc8bdSWilliam Juul for (i = 0; i < dev->nShortOpCaches; i++) { 7338*0e8cc8bdSWilliam Juul if(dev->srCache[i].data) 7339*0e8cc8bdSWilliam Juul YFREE(dev->srCache[i].data); 7340*0e8cc8bdSWilliam Juul dev->srCache[i].data = NULL; 7341*0e8cc8bdSWilliam Juul } 7342*0e8cc8bdSWilliam Juul 7343*0e8cc8bdSWilliam Juul YFREE(dev->srCache); 7344*0e8cc8bdSWilliam Juul dev->srCache = NULL; 7345*0e8cc8bdSWilliam Juul } 7346*0e8cc8bdSWilliam Juul 7347*0e8cc8bdSWilliam Juul YFREE(dev->gcCleanupList); 7348*0e8cc8bdSWilliam Juul 7349*0e8cc8bdSWilliam Juul for (i = 0; i < YAFFS_N_TEMP_BUFFERS; i++) { 7350*0e8cc8bdSWilliam Juul YFREE(dev->tempBuffer[i].buffer); 7351*0e8cc8bdSWilliam Juul } 7352*0e8cc8bdSWilliam Juul 7353*0e8cc8bdSWilliam Juul dev->isMounted = 0; 7354*0e8cc8bdSWilliam Juul } 7355*0e8cc8bdSWilliam Juul 7356*0e8cc8bdSWilliam Juul } 7357*0e8cc8bdSWilliam Juul 7358*0e8cc8bdSWilliam Juul static int yaffs_CountFreeChunks(yaffs_Device * dev) 7359*0e8cc8bdSWilliam Juul { 7360*0e8cc8bdSWilliam Juul int nFree; 7361*0e8cc8bdSWilliam Juul int b; 7362*0e8cc8bdSWilliam Juul 7363*0e8cc8bdSWilliam Juul yaffs_BlockInfo *blk; 7364*0e8cc8bdSWilliam Juul 7365*0e8cc8bdSWilliam Juul for (nFree = 0, b = dev->internalStartBlock; b <= dev->internalEndBlock; 7366*0e8cc8bdSWilliam Juul b++) { 7367*0e8cc8bdSWilliam Juul blk = yaffs_GetBlockInfo(dev, b); 7368*0e8cc8bdSWilliam Juul 7369*0e8cc8bdSWilliam Juul switch (blk->blockState) { 7370*0e8cc8bdSWilliam Juul case YAFFS_BLOCK_STATE_EMPTY: 7371*0e8cc8bdSWilliam Juul case YAFFS_BLOCK_STATE_ALLOCATING: 7372*0e8cc8bdSWilliam Juul case YAFFS_BLOCK_STATE_COLLECTING: 7373*0e8cc8bdSWilliam Juul case YAFFS_BLOCK_STATE_FULL: 7374*0e8cc8bdSWilliam Juul nFree += 7375*0e8cc8bdSWilliam Juul (dev->nChunksPerBlock - blk->pagesInUse + 7376*0e8cc8bdSWilliam Juul blk->softDeletions); 7377*0e8cc8bdSWilliam Juul break; 7378*0e8cc8bdSWilliam Juul default: 7379*0e8cc8bdSWilliam Juul break; 7380*0e8cc8bdSWilliam Juul } 7381*0e8cc8bdSWilliam Juul 7382*0e8cc8bdSWilliam Juul } 7383*0e8cc8bdSWilliam Juul 7384*0e8cc8bdSWilliam Juul return nFree; 7385*0e8cc8bdSWilliam Juul } 7386*0e8cc8bdSWilliam Juul 7387*0e8cc8bdSWilliam Juul int yaffs_GetNumberOfFreeChunks(yaffs_Device * dev) 7388*0e8cc8bdSWilliam Juul { 7389*0e8cc8bdSWilliam Juul /* This is what we report to the outside world */ 7390*0e8cc8bdSWilliam Juul 7391*0e8cc8bdSWilliam Juul int nFree; 7392*0e8cc8bdSWilliam Juul int nDirtyCacheChunks; 7393*0e8cc8bdSWilliam Juul int blocksForCheckpoint; 7394*0e8cc8bdSWilliam Juul 7395*0e8cc8bdSWilliam Juul #if 1 7396*0e8cc8bdSWilliam Juul nFree = dev->nFreeChunks; 7397*0e8cc8bdSWilliam Juul #else 7398*0e8cc8bdSWilliam Juul nFree = yaffs_CountFreeChunks(dev); 7399*0e8cc8bdSWilliam Juul #endif 7400*0e8cc8bdSWilliam Juul 7401*0e8cc8bdSWilliam Juul nFree += dev->nDeletedFiles; 7402*0e8cc8bdSWilliam Juul 7403*0e8cc8bdSWilliam Juul /* Now count the number of dirty chunks in the cache and subtract those */ 7404*0e8cc8bdSWilliam Juul 7405*0e8cc8bdSWilliam Juul { 7406*0e8cc8bdSWilliam Juul int i; 7407*0e8cc8bdSWilliam Juul for (nDirtyCacheChunks = 0, i = 0; i < dev->nShortOpCaches; i++) { 7408*0e8cc8bdSWilliam Juul if (dev->srCache[i].dirty) 7409*0e8cc8bdSWilliam Juul nDirtyCacheChunks++; 7410*0e8cc8bdSWilliam Juul } 7411*0e8cc8bdSWilliam Juul } 7412*0e8cc8bdSWilliam Juul 7413*0e8cc8bdSWilliam Juul nFree -= nDirtyCacheChunks; 7414*0e8cc8bdSWilliam Juul 7415*0e8cc8bdSWilliam Juul nFree -= ((dev->nReservedBlocks + 1) * dev->nChunksPerBlock); 7416*0e8cc8bdSWilliam Juul 7417*0e8cc8bdSWilliam Juul /* Now we figure out how much to reserve for the checkpoint and report that... */ 7418*0e8cc8bdSWilliam Juul blocksForCheckpoint = dev->nCheckpointReservedBlocks - dev->blocksInCheckpoint; 7419*0e8cc8bdSWilliam Juul if(blocksForCheckpoint < 0) 7420*0e8cc8bdSWilliam Juul blocksForCheckpoint = 0; 7421*0e8cc8bdSWilliam Juul 7422*0e8cc8bdSWilliam Juul nFree -= (blocksForCheckpoint * dev->nChunksPerBlock); 7423*0e8cc8bdSWilliam Juul 7424*0e8cc8bdSWilliam Juul if (nFree < 0) 7425*0e8cc8bdSWilliam Juul nFree = 0; 7426*0e8cc8bdSWilliam Juul 7427*0e8cc8bdSWilliam Juul return nFree; 7428*0e8cc8bdSWilliam Juul 7429*0e8cc8bdSWilliam Juul } 7430*0e8cc8bdSWilliam Juul 7431*0e8cc8bdSWilliam Juul static int yaffs_freeVerificationFailures; 7432*0e8cc8bdSWilliam Juul 7433*0e8cc8bdSWilliam Juul static void yaffs_VerifyFreeChunks(yaffs_Device * dev) 7434*0e8cc8bdSWilliam Juul { 7435*0e8cc8bdSWilliam Juul int counted; 7436*0e8cc8bdSWilliam Juul int difference; 7437*0e8cc8bdSWilliam Juul 7438*0e8cc8bdSWilliam Juul if(yaffs_SkipVerification(dev)) 7439*0e8cc8bdSWilliam Juul return; 7440*0e8cc8bdSWilliam Juul 7441*0e8cc8bdSWilliam Juul counted = yaffs_CountFreeChunks(dev); 7442*0e8cc8bdSWilliam Juul 7443*0e8cc8bdSWilliam Juul difference = dev->nFreeChunks - counted; 7444*0e8cc8bdSWilliam Juul 7445*0e8cc8bdSWilliam Juul if (difference) { 7446*0e8cc8bdSWilliam Juul T(YAFFS_TRACE_ALWAYS, 7447*0e8cc8bdSWilliam Juul (TSTR("Freechunks verification failure %d %d %d" TENDSTR), 7448*0e8cc8bdSWilliam Juul dev->nFreeChunks, counted, difference)); 7449*0e8cc8bdSWilliam Juul yaffs_freeVerificationFailures++; 7450*0e8cc8bdSWilliam Juul } 7451*0e8cc8bdSWilliam Juul } 7452*0e8cc8bdSWilliam Juul 7453*0e8cc8bdSWilliam Juul /*---------------------------------------- YAFFS test code ----------------------*/ 7454*0e8cc8bdSWilliam Juul 7455*0e8cc8bdSWilliam Juul #define yaffs_CheckStruct(structure,syze, name) \ 7456*0e8cc8bdSWilliam Juul if(sizeof(structure) != syze) \ 7457*0e8cc8bdSWilliam Juul { \ 7458*0e8cc8bdSWilliam Juul T(YAFFS_TRACE_ALWAYS,(TSTR("%s should be %d but is %d\n" TENDSTR),\ 7459*0e8cc8bdSWilliam Juul name,syze,sizeof(structure))); \ 7460*0e8cc8bdSWilliam Juul return YAFFS_FAIL; \ 7461*0e8cc8bdSWilliam Juul } 7462*0e8cc8bdSWilliam Juul 7463*0e8cc8bdSWilliam Juul static int yaffs_CheckStructures(void) 7464*0e8cc8bdSWilliam Juul { 7465*0e8cc8bdSWilliam Juul /* yaffs_CheckStruct(yaffs_Tags,8,"yaffs_Tags") */ 7466*0e8cc8bdSWilliam Juul /* yaffs_CheckStruct(yaffs_TagsUnion,8,"yaffs_TagsUnion") */ 7467*0e8cc8bdSWilliam Juul /* yaffs_CheckStruct(yaffs_Spare,16,"yaffs_Spare") */ 7468*0e8cc8bdSWilliam Juul #ifndef CONFIG_YAFFS_TNODE_LIST_DEBUG 7469*0e8cc8bdSWilliam Juul yaffs_CheckStruct(yaffs_Tnode, 2 * YAFFS_NTNODES_LEVEL0, "yaffs_Tnode") 7470*0e8cc8bdSWilliam Juul #endif 7471*0e8cc8bdSWilliam Juul yaffs_CheckStruct(yaffs_ObjectHeader, 512, "yaffs_ObjectHeader") 7472*0e8cc8bdSWilliam Juul 7473*0e8cc8bdSWilliam Juul return YAFFS_OK; 7474*0e8cc8bdSWilliam Juul } 7475