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