yaffs Changes to direct tests
[yaffs2.git] / yaffs_verify.c
1 /*
2  * YAFFS: Yet Another Flash File System. A NAND-flash specific file system.
3  *
4  * Copyright (C) 2002-2010 Aleph One Ltd.
5  *   for Toby Churchill Ltd and Brightstar Engineering
6  *
7  * Created by Charles Manning <charles@aleph1.co.uk>
8  *
9  * This program is free software; you can redistribute it and/or modify
10  * it under the terms of the GNU General Public License version 2 as
11  * published by the Free Software Foundation.
12  */
13
14
15 #include "yaffs_verify.h"
16 #include "yaffs_trace.h"
17 #include "yaffs_bitmap.h"
18 #include "yaffs_getblockinfo.h"
19 #include "yaffs_nand.h"
20
21 int yaffs_SkipVerification(yaffs_Device *dev)
22 {
23         dev=dev;
24         return !(yaffs_traceMask & (YAFFS_TRACE_VERIFY | YAFFS_TRACE_VERIFY_FULL));
25 }
26
27 static int yaffs_SkipFullVerification(yaffs_Device *dev)
28 {
29         dev=dev;
30         return !(yaffs_traceMask & (YAFFS_TRACE_VERIFY_FULL));
31 }
32
33 static int yaffs_SkipNANDVerification(yaffs_Device *dev)
34 {
35         dev=dev;
36         return !(yaffs_traceMask & (YAFFS_TRACE_VERIFY_NAND));
37 }
38
39
40 static const char *blockStateName[] = {
41 "Unknown",
42 "Needs scanning",
43 "Scanning",
44 "Empty",
45 "Allocating",
46 "Full",
47 "Dirty",
48 "Checkpoint",
49 "Collecting",
50 "Dead"
51 };
52
53
54 void yaffs_VerifyBlock(yaffs_Device *dev, yaffs_BlockInfo *bi, int n)
55 {
56         int actuallyUsed;
57         int inUse;
58
59         if (yaffs_SkipVerification(dev))
60                 return;
61
62         /* Report illegal runtime states */
63         if (bi->blockState >= YAFFS_NUMBER_OF_BLOCK_STATES)
64                 T(YAFFS_TRACE_VERIFY, (TSTR("Block %d has undefined state %d"TENDSTR), n, bi->blockState));
65
66         switch (bi->blockState) {
67         case YAFFS_BLOCK_STATE_UNKNOWN:
68         case YAFFS_BLOCK_STATE_SCANNING:
69         case YAFFS_BLOCK_STATE_NEEDS_SCANNING:
70                 T(YAFFS_TRACE_VERIFY, (TSTR("Block %d has bad run-state %s"TENDSTR),
71                 n, blockStateName[bi->blockState]));
72         }
73
74         /* Check pages in use and soft deletions are legal */
75
76         actuallyUsed = bi->pagesInUse - bi->softDeletions;
77
78         if (bi->pagesInUse < 0 || bi->pagesInUse > dev->param.nChunksPerBlock ||
79            bi->softDeletions < 0 || bi->softDeletions > dev->param.nChunksPerBlock ||
80            actuallyUsed < 0 || actuallyUsed > dev->param.nChunksPerBlock)
81                 T(YAFFS_TRACE_VERIFY, (TSTR("Block %d has illegal values pagesInUsed %d softDeletions %d"TENDSTR),
82                 n, bi->pagesInUse, bi->softDeletions));
83
84
85         /* Check chunk bitmap legal */
86         inUse = yaffs_CountChunkBits(dev, n);
87         if (inUse != bi->pagesInUse)
88                 T(YAFFS_TRACE_VERIFY, (TSTR("Block %d has inconsistent values pagesInUse %d counted chunk bits %d"TENDSTR),
89                         n, bi->pagesInUse, inUse));
90
91 }
92
93
94
95 void yaffs_VerifyCollectedBlock(yaffs_Device *dev, yaffs_BlockInfo *bi, int n)
96 {
97         yaffs_VerifyBlock(dev, bi, n);
98
99         /* After collection the block should be in the erased state */
100         /* This will need to change if we do partial gc */
101
102         if (bi->blockState != YAFFS_BLOCK_STATE_COLLECTING &&
103                         bi->blockState != YAFFS_BLOCK_STATE_EMPTY) {
104                 T(YAFFS_TRACE_ERROR, (TSTR("Block %d is in state %d after gc, should be erased"TENDSTR),
105                         n, bi->blockState));
106         }
107 }
108
109 void yaffs_VerifyBlocks(yaffs_Device *dev)
110 {
111         int i;
112         int nBlocksPerState[YAFFS_NUMBER_OF_BLOCK_STATES];
113         int nIllegalBlockStates = 0;
114
115         if (yaffs_SkipVerification(dev))
116                 return;
117
118         memset(nBlocksPerState, 0, sizeof(nBlocksPerState));
119
120         for (i = dev->internalStartBlock; i <= dev->internalEndBlock; i++) {
121                 yaffs_BlockInfo *bi = yaffs_GetBlockInfo(dev, i);
122                 yaffs_VerifyBlock(dev, bi, i);
123
124                 if (bi->blockState < YAFFS_NUMBER_OF_BLOCK_STATES)
125                         nBlocksPerState[bi->blockState]++;
126                 else
127                         nIllegalBlockStates++;
128         }
129
130         T(YAFFS_TRACE_VERIFY, (TSTR(""TENDSTR)));
131         T(YAFFS_TRACE_VERIFY, (TSTR("Block summary"TENDSTR)));
132
133         T(YAFFS_TRACE_VERIFY, (TSTR("%d blocks have illegal states"TENDSTR), nIllegalBlockStates));
134         if (nBlocksPerState[YAFFS_BLOCK_STATE_ALLOCATING] > 1)
135                 T(YAFFS_TRACE_VERIFY, (TSTR("Too many allocating blocks"TENDSTR)));
136
137         for (i = 0; i < YAFFS_NUMBER_OF_BLOCK_STATES; i++)
138                 T(YAFFS_TRACE_VERIFY,
139                   (TSTR("%s %d blocks"TENDSTR),
140                   blockStateName[i], nBlocksPerState[i]));
141
142         if (dev->blocksInCheckpoint != nBlocksPerState[YAFFS_BLOCK_STATE_CHECKPOINT])
143                 T(YAFFS_TRACE_VERIFY,
144                  (TSTR("Checkpoint block count wrong dev %d count %d"TENDSTR),
145                  dev->blocksInCheckpoint, nBlocksPerState[YAFFS_BLOCK_STATE_CHECKPOINT]));
146
147         if (dev->nErasedBlocks != nBlocksPerState[YAFFS_BLOCK_STATE_EMPTY])
148                 T(YAFFS_TRACE_VERIFY,
149                  (TSTR("Erased block count wrong dev %d count %d"TENDSTR),
150                  dev->nErasedBlocks, nBlocksPerState[YAFFS_BLOCK_STATE_EMPTY]));
151
152         if (nBlocksPerState[YAFFS_BLOCK_STATE_COLLECTING] > 1)
153                 T(YAFFS_TRACE_VERIFY,
154                  (TSTR("Too many collecting blocks %d (max is 1)"TENDSTR),
155                  nBlocksPerState[YAFFS_BLOCK_STATE_COLLECTING]));
156
157         T(YAFFS_TRACE_VERIFY, (TSTR(""TENDSTR)));
158
159 }
160
161 /*
162  * Verify the object header. oh must be valid, but obj and tags may be NULL in which
163  * case those tests will not be performed.
164  */
165 void yaffs_VerifyObjectHeader(yaffs_Object *obj, yaffs_ObjectHeader *oh, yaffs_ExtendedTags *tags, int parentCheck)
166 {
167         if (obj && yaffs_SkipVerification(obj->myDev))
168                 return;
169
170         if (!(tags && obj && oh)) {
171                 T(YAFFS_TRACE_VERIFY,
172                                 (TSTR("Verifying object header tags %p obj %p oh %p"TENDSTR),
173                                 tags, obj, oh));
174                 return;
175         }
176
177         if (oh->type <= YAFFS_OBJECT_TYPE_UNKNOWN ||
178                         oh->type > YAFFS_OBJECT_TYPE_MAX)
179                 T(YAFFS_TRACE_VERIFY,
180                         (TSTR("Obj %d header type is illegal value 0x%x"TENDSTR),
181                         tags->objectId, oh->type));
182
183         if (tags->objectId != obj->objectId)
184                 T(YAFFS_TRACE_VERIFY,
185                         (TSTR("Obj %d header mismatch objectId %d"TENDSTR),
186                         tags->objectId, obj->objectId));
187
188
189         /*
190          * Check that the object's parent ids match if parentCheck requested.
191          *
192          * Tests do not apply to the root object.
193          */
194
195         if (parentCheck && tags->objectId > 1 && !obj->parent)
196                 T(YAFFS_TRACE_VERIFY,
197                         (TSTR("Obj %d header mismatch parentId %d obj->parent is NULL"TENDSTR),
198                         tags->objectId, oh->parentObjectId));
199
200         if (parentCheck && obj->parent &&
201                         oh->parentObjectId != obj->parent->objectId &&
202                         (oh->parentObjectId != YAFFS_OBJECTID_UNLINKED ||
203                         obj->parent->objectId != YAFFS_OBJECTID_DELETED))
204                 T(YAFFS_TRACE_VERIFY,
205                         (TSTR("Obj %d header mismatch parentId %d parentObjectId %d"TENDSTR),
206                         tags->objectId, oh->parentObjectId, obj->parent->objectId));
207
208         if (tags->objectId > 1 && oh->name[0] == 0) /* Null name */
209                 T(YAFFS_TRACE_VERIFY,
210                         (TSTR("Obj %d header name is NULL"TENDSTR),
211                         obj->objectId));
212
213         if (tags->objectId > 1 && ((__u8)(oh->name[0])) == 0xff) /* Trashed name */
214                 T(YAFFS_TRACE_VERIFY,
215                         (TSTR("Obj %d header name is 0xFF"TENDSTR),
216                         obj->objectId));
217 }
218
219
220 #if 0
221 /* Not being used, but don't want to throw away yet */
222 int yaffs_VerifyTnodeWorker(yaffs_Object *obj, yaffs_Tnode *tn,
223                                         __u32 level, int chunkOffset)
224 {
225         int i;
226         yaffs_Device *dev = obj->myDev;
227         int ok = 1;
228
229         if (tn) {
230                 if (level > 0) {
231
232                         for (i = 0; i < YAFFS_NTNODES_INTERNAL && ok; i++) {
233                                 if (tn->internal[i]) {
234                                         ok = yaffs_VerifyTnodeWorker(obj,
235                                                         tn->internal[i],
236                                                         level - 1,
237                                                         (chunkOffset<<YAFFS_TNODES_INTERNAL_BITS) + i);
238                                 }
239                         }
240                 } else if (level == 0) {
241                         yaffs_ExtendedTags tags;
242                         __u32 objectId = obj->objectId;
243
244                         chunkOffset <<=  YAFFS_TNODES_LEVEL0_BITS;
245
246                         for (i = 0; i < YAFFS_NTNODES_LEVEL0; i++) {
247                                 __u32 theChunk = yaffs_GetChunkGroupBase(dev, tn, i);
248
249                                 if (theChunk > 0) {
250                                         /* T(~0,(TSTR("verifying (%d:%d) %d"TENDSTR),tags.objectId,tags.chunkId,theChunk)); */
251                                         yaffs_ReadChunkWithTagsFromNAND(dev, theChunk, NULL, &tags);
252                                         if (tags.objectId != objectId || tags.chunkId != chunkOffset) {
253                                                 T(~0, (TSTR("Object %d chunkId %d NAND mismatch chunk %d tags (%d:%d)"TENDSTR),
254                                                         objectId, chunkOffset, theChunk,
255                                                         tags.objectId, tags.chunkId));
256                                         }
257                                 }
258                                 chunkOffset++;
259                         }
260                 }
261         }
262
263         return ok;
264
265 }
266
267 #endif
268
269 void yaffs_VerifyFile(yaffs_Object *obj)
270 {
271         int requiredTallness;
272         int actualTallness;
273         __u32 lastChunk;
274         __u32 x;
275         __u32 i;
276         yaffs_Device *dev;
277         yaffs_ExtendedTags tags;
278         yaffs_Tnode *tn;
279         __u32 objectId;
280
281         if (!obj)
282                 return;
283
284         if (yaffs_SkipVerification(obj->myDev))
285                 return;
286
287         dev = obj->myDev;
288         objectId = obj->objectId;
289
290         /* Check file size is consistent with tnode depth */
291         lastChunk =  obj->variant.fileVariant.fileSize / dev->nDataBytesPerChunk + 1;
292         x = lastChunk >> YAFFS_TNODES_LEVEL0_BITS;
293         requiredTallness = 0;
294         while (x > 0) {
295                 x >>= YAFFS_TNODES_INTERNAL_BITS;
296                 requiredTallness++;
297         }
298
299         actualTallness = obj->variant.fileVariant.topLevel;
300
301         /* Check that the chunks in the tnode tree are all correct.
302          * We do this by scanning through the tnode tree and
303          * checking the tags for every chunk match.
304          */
305
306         if (yaffs_SkipNANDVerification(dev))
307                 return;
308
309         for (i = 1; i <= lastChunk; i++) {
310                 tn = yaffs_FindLevel0Tnode(dev, &obj->variant.fileVariant, i);
311
312                 if (tn) {
313                         __u32 theChunk = yaffs_GetChunkGroupBase(dev, tn, i);
314                         if (theChunk > 0) {
315                                 /* T(~0,(TSTR("verifying (%d:%d) %d"TENDSTR),objectId,i,theChunk)); */
316                                 yaffs_ReadChunkWithTagsFromNAND(dev, theChunk, NULL, &tags);
317                                 if (tags.objectId != objectId || tags.chunkId != i) {
318                                         T(~0, (TSTR("Object %d chunkId %d NAND mismatch chunk %d tags (%d:%d)"TENDSTR),
319                                                 objectId, i, theChunk,
320                                                 tags.objectId, tags.chunkId));
321                                 }
322                         }
323                 }
324         }
325 }
326
327
328 void yaffs_VerifyHardLink(yaffs_Object *obj)
329 {
330         if (obj && yaffs_SkipVerification(obj->myDev))
331                 return;
332
333         /* Verify sane equivalent object */
334 }
335
336 void yaffs_VerifySymlink(yaffs_Object *obj)
337 {
338         if (obj && yaffs_SkipVerification(obj->myDev))
339                 return;
340
341         /* Verify symlink string */
342 }
343
344 void yaffs_VerifySpecial(yaffs_Object *obj)
345 {
346         if (obj && yaffs_SkipVerification(obj->myDev))
347                 return;
348 }
349
350 void yaffs_VerifyObject(yaffs_Object *obj)
351 {
352         yaffs_Device *dev;
353
354         __u32 chunkMin;
355         __u32 chunkMax;
356
357         __u32 chunkIdOk;
358         __u32 chunkInRange;
359         __u32 chunkShouldNotBeDeleted;
360         __u32 chunkValid;
361
362         if (!obj)
363                 return;
364
365         if (obj->beingCreated)
366                 return;
367
368         dev = obj->myDev;
369
370         if (yaffs_SkipVerification(dev))
371                 return;
372
373         /* Check sane object header chunk */
374
375         chunkMin = dev->internalStartBlock * dev->param.nChunksPerBlock;
376         chunkMax = (dev->internalEndBlock+1) * dev->param.nChunksPerBlock - 1;
377
378         chunkInRange = (((unsigned)(obj->hdrChunk)) >= chunkMin && ((unsigned)(obj->hdrChunk)) <= chunkMax);
379         chunkIdOk = chunkInRange || (obj->hdrChunk == 0);
380         chunkValid = chunkInRange &&
381                         yaffs_CheckChunkBit(dev,
382                                         obj->hdrChunk / dev->param.nChunksPerBlock,
383                                         obj->hdrChunk % dev->param.nChunksPerBlock);
384         chunkShouldNotBeDeleted = chunkInRange && !chunkValid;
385
386         if (!obj->fake &&
387                         (!chunkIdOk || chunkShouldNotBeDeleted)) {
388                 T(YAFFS_TRACE_VERIFY,
389                         (TSTR("Obj %d has chunkId %d %s %s"TENDSTR),
390                         obj->objectId, obj->hdrChunk,
391                         chunkIdOk ? "" : ",out of range",
392                         chunkShouldNotBeDeleted ? ",marked as deleted" : ""));
393         }
394
395         if (chunkValid && !yaffs_SkipNANDVerification(dev)) {
396                 yaffs_ExtendedTags tags;
397                 yaffs_ObjectHeader *oh;
398                 __u8 *buffer = yaffs_GetTempBuffer(dev, __LINE__);
399
400                 oh = (yaffs_ObjectHeader *)buffer;
401
402                 yaffs_ReadChunkWithTagsFromNAND(dev, obj->hdrChunk, buffer,
403                                 &tags);
404
405                 yaffs_VerifyObjectHeader(obj, oh, &tags, 1);
406
407                 yaffs_ReleaseTempBuffer(dev, buffer, __LINE__);
408         }
409
410         /* Verify it has a parent */
411         if (obj && !obj->fake &&
412                         (!obj->parent || obj->parent->myDev != dev)) {
413                 T(YAFFS_TRACE_VERIFY,
414                         (TSTR("Obj %d has parent pointer %p which does not look like an object"TENDSTR),
415                         obj->objectId, obj->parent));
416         }
417
418         /* Verify parent is a directory */
419         if (obj->parent && obj->parent->variantType != YAFFS_OBJECT_TYPE_DIRECTORY) {
420                 T(YAFFS_TRACE_VERIFY,
421                         (TSTR("Obj %d's parent is not a directory (type %d)"TENDSTR),
422                         obj->objectId, obj->parent->variantType));
423         }
424
425         switch (obj->variantType) {
426         case YAFFS_OBJECT_TYPE_FILE:
427                 yaffs_VerifyFile(obj);
428                 break;
429         case YAFFS_OBJECT_TYPE_SYMLINK:
430                 yaffs_VerifySymlink(obj);
431                 break;
432         case YAFFS_OBJECT_TYPE_DIRECTORY:
433                 yaffs_VerifyDirectory(obj);
434                 break;
435         case YAFFS_OBJECT_TYPE_HARDLINK:
436                 yaffs_VerifyHardLink(obj);
437                 break;
438         case YAFFS_OBJECT_TYPE_SPECIAL:
439                 yaffs_VerifySpecial(obj);
440                 break;
441         case YAFFS_OBJECT_TYPE_UNKNOWN:
442         default:
443                 T(YAFFS_TRACE_VERIFY,
444                 (TSTR("Obj %d has illegaltype %d"TENDSTR),
445                 obj->objectId, obj->variantType));
446                 break;
447         }
448 }
449
450 void yaffs_VerifyObjects(yaffs_Device *dev)
451 {
452         yaffs_Object *obj;
453         int i;
454         struct ylist_head *lh;
455
456         if (yaffs_SkipVerification(dev))
457                 return;
458
459         /* Iterate through the objects in each hash entry */
460
461         for (i = 0; i <  YAFFS_NOBJECT_BUCKETS; i++) {
462                 ylist_for_each(lh, &dev->objectBucket[i].list) {
463                         if (lh) {
464                                 obj = ylist_entry(lh, yaffs_Object, hashLink);
465                                 yaffs_VerifyObject(obj);
466                         }
467                 }
468         }
469 }
470
471
472 void yaffs_VerifyObjectInDirectory(yaffs_Object *obj)
473 {
474         struct ylist_head *lh;
475         yaffs_Object *listObj;
476
477         int count = 0;
478
479         if (!obj) {
480                 T(YAFFS_TRACE_ALWAYS, (TSTR("No object to verify" TENDSTR)));
481                 YBUG();
482                 return;
483         }
484
485         if (yaffs_SkipVerification(obj->myDev))
486                 return;
487
488         if (!obj->parent) {
489                 T(YAFFS_TRACE_ALWAYS, (TSTR("Object does not have parent" TENDSTR)));
490                 YBUG();
491                 return;
492         }
493
494         if (obj->parent->variantType != YAFFS_OBJECT_TYPE_DIRECTORY) {
495                 T(YAFFS_TRACE_ALWAYS, (TSTR("Parent is not directory" TENDSTR)));
496                 YBUG();
497         }
498
499         /* Iterate through the objects in each hash entry */
500
501         ylist_for_each(lh, &obj->parent->variant.directoryVariant.children) {
502                 if (lh) {
503                         listObj = ylist_entry(lh, yaffs_Object, siblings);
504                         yaffs_VerifyObject(listObj);
505                         if (obj == listObj)
506                                 count++;
507                 }
508          }
509
510         if (count != 1) {
511                 T(YAFFS_TRACE_ALWAYS, (TSTR("Object in directory %d times" TENDSTR), count));
512                 YBUG();
513         }
514 }
515
516 void yaffs_VerifyDirectory(yaffs_Object *directory)
517 {
518         struct ylist_head *lh;
519         yaffs_Object *listObj;
520
521         if (!directory) {
522                 YBUG();
523                 return;
524         }
525
526         if (yaffs_SkipFullVerification(directory->myDev))
527                 return;
528
529         if (directory->variantType != YAFFS_OBJECT_TYPE_DIRECTORY) {
530                 T(YAFFS_TRACE_ALWAYS, (TSTR("Directory has wrong type: %d" TENDSTR), directory->variantType));
531                 YBUG();
532         }
533
534         /* Iterate through the objects in each hash entry */
535
536         ylist_for_each(lh, &directory->variant.directoryVariant.children) {
537                 if (lh) {
538                         listObj = ylist_entry(lh, yaffs_Object, siblings);
539                         if (listObj->parent != directory) {
540                                 T(YAFFS_TRACE_ALWAYS, (TSTR("Object in directory list has wrong parent %p" TENDSTR), listObj->parent));
541                                 YBUG();
542                         }
543                         yaffs_VerifyObjectInDirectory(listObj);
544                 }
545         }
546 }
547
548 static int yaffs_freeVerificationFailures;
549
550 void yaffs_VerifyFreeChunks(yaffs_Device *dev)
551 {
552         int counted;
553         int difference;
554
555         if (yaffs_SkipVerification(dev))
556                 return;
557
558         counted = yaffs_CountFreeChunks(dev);
559
560         difference = dev->nFreeChunks - counted;
561
562         if (difference) {
563                 T(YAFFS_TRACE_ALWAYS,
564                   (TSTR("Freechunks verification failure %d %d %d" TENDSTR),
565                    dev->nFreeChunks, counted, difference));
566                 yaffs_freeVerificationFailures++;
567         }
568 }
569
570 int yaffs_VerifyFileSanity(yaffs_Object *in)
571 {
572 #if 0
573         int chunk;
574         int nChunks;
575         int fSize;
576         int failed = 0;
577         int objId;
578         yaffs_Tnode *tn;
579         yaffs_Tags localTags;
580         yaffs_Tags *tags = &localTags;
581         int theChunk;
582         int chunkDeleted;
583
584         if (in->variantType != YAFFS_OBJECT_TYPE_FILE)
585                 return YAFFS_FAIL;
586
587         objId = in->objectId;
588         fSize = in->variant.fileVariant.fileSize;
589         nChunks =
590             (fSize + in->myDev->nDataBytesPerChunk - 1) / in->myDev->nDataBytesPerChunk;
591
592         for (chunk = 1; chunk <= nChunks; chunk++) {
593                 tn = yaffs_FindLevel0Tnode(in->myDev, &in->variant.fileVariant,
594                                            chunk);
595
596                 if (tn) {
597
598                         theChunk = yaffs_GetChunkGroupBase(dev, tn, chunk);
599
600                         if (yaffs_CheckChunkBits
601                             (dev, theChunk / dev->param.nChunksPerBlock,
602                              theChunk % dev->param.nChunksPerBlock)) {
603
604                                 yaffs_ReadChunkTagsFromNAND(in->myDev, theChunk,
605                                                             tags,
606                                                             &chunkDeleted);
607                                 if (yaffs_TagsMatch
608                                     (tags, in->objectId, chunk, chunkDeleted)) {
609                                         /* found it; */
610
611                                 }
612                         } else {
613
614                                 failed = 1;
615                         }
616
617                 } else {
618                         /* T(("No level 0 found for %d\n", chunk)); */
619                 }
620         }
621
622         return failed ? YAFFS_FAIL : YAFFS_OK;
623 #else
624         in=in;
625         return YAFFS_OK;
626 #endif
627 }