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