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