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