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