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