2 * YAFFS: Yet another FFS. A NAND-flash specific file system.
3 * yaffs_guts.c The main guts of YAFFS
5 * Copyright (C) 2002 Aleph One Ltd.
6 * for Toby Churchill Ltd and Brightstar Engineering
8 * Created by Charles Manning <charles@aleph1.co.uk>
10 * This program is free software; you can redistribute it and/or modify
11 * it under the terms of the GNU General Public License version 2 as
12 * published by the Free Software Foundation.
19 #include "yaffsinterface.h"
20 #include "yaffs_guts.h"
30 // countBits is a quick way of counting the number of bits in a byte.
31 // ie. countBits[n] holds the number of 1 bits in a byte with the value n.
33 static const char yaffs_countBits[256] =
35 0,1,1,2,1,2,2,3,1,2,2,3,2,3,3,4,
36 1,2,2,3,2,3,3,4,2,3,3,4,3,4,4,5,
37 1,2,2,3,2,3,3,4,2,3,3,4,3,4,4,5,
38 2,3,3,4,3,4,4,5,3,4,4,5,4,5,5,6,
39 1,2,2,3,2,3,3,4,2,3,3,4,3,4,4,5,
40 2,3,3,4,3,4,4,5,3,4,4,5,4,5,5,6,
41 2,3,3,4,3,4,4,5,3,4,4,5,4,5,5,6,
42 3,4,4,5,4,5,5,6,4,5,5,6,5,6,6,7,
43 1,2,2,3,2,3,3,4,2,3,3,4,3,4,4,5,
44 2,3,3,4,3,4,4,5,3,4,4,5,4,5,5,6,
45 2,3,3,4,3,4,4,5,3,4,4,5,4,5,5,6,
46 3,4,4,5,4,5,5,6,4,5,5,6,5,6,6,7,
47 2,3,3,4,3,4,4,5,3,4,4,5,4,5,5,6,
48 3,4,4,5,4,5,5,6,4,5,5,6,5,6,6,7,
49 3,4,4,5,4,5,5,6,4,5,5,6,5,6,6,7,
50 4,5,5,6,5,6,6,7,5,6,6,7,6,7,7,8
56 //static yaffs_Device *yaffs_device;
57 //yaffs_Object *yaffs_rootDir;
58 //yaffs_Object *yaffs_lostNFound;
63 static int yaffs_CheckObjectHashSanity(yaffs_Device *dev);
64 static void yaffs_LoadTagsIntoSpare(yaffs_Spare *sparePtr, yaffs_Tags *tagsPtr);
65 static void yaffs_GetTagsFromSpare(yaffs_Spare *sparePtr,yaffs_Tags *tagsPtr);
66 static int yaffs_PutChunkIntoFile(yaffs_Object *in,int chunkInInode, int chunkInNAND);
68 static yaffs_Object *yaffs_CreateNewObject(yaffs_Device *dev,int number,yaffs_ObjectType type);
69 static void yaffs_AddObjectToDirectory(yaffs_Object *directory, yaffs_Object *obj);
70 static int yaffs_UpdateObjectHeader(yaffs_Object *in,const char *name);
71 static void yaffs_DeleteChunk(yaffs_Device *dev,int chunkId);
72 static void yaffs_RemoveObjectFromDirectory(yaffs_Object *obj);
73 static int yaffs_CheckStructures(void);
74 static yaffs_Object *yaffs_GetEquivalentObject(yaffs_Object *obj);
76 loff_t yaffs_GetFileSize(yaffs_Object *obj);
79 static int yaffs_AllocateChunk(yaffs_Device *dev,int useReserve);
82 static int yaffs_CheckFileSanity(yaffs_Object *in)
84 #define yaffs_CheckFileSanity(in)
87 static int __inline__ yaffs_HashFunction(int n)
89 return (n % YAFFS_NOBJECT_BUCKETS);
93 yaffs_Object *yaffs_Root(yaffs_Device *dev)
98 yaffs_Object *yaffs_LostNFound(yaffs_Device *dev)
100 return dev->lostNFoundDir;
104 static int yaffs_WriteChunkToNAND(struct yaffs_DeviceStruct *dev,int chunkInNAND, const __u8 *data, yaffs_Spare *spare)
106 return dev->writeChunkToNAND(dev,chunkInNAND,data,spare);
109 int yaffs_ReadChunkFromNAND(struct yaffs_DeviceStruct *dev,int chunkInNAND, __u8 *data, yaffs_Spare *spare)
111 return dev->readChunkFromNAND(dev,chunkInNAND,data,spare);
114 int yaffs_EraseBlockInNAND(struct yaffs_DeviceStruct *dev,int blockInNAND)
116 return dev->eraseBlockInNAND(dev,blockInNAND);
119 int yaffs_InitialiseNAND(struct yaffs_DeviceStruct *dev)
121 return dev->initialiseNAND(dev);
124 static int yaffs_WriteNewChunkToNAND(struct yaffs_DeviceStruct *dev, const __u8 *data, yaffs_Spare *spare,int useReserve)
131 chunk = yaffs_AllocateChunk(dev,useReserve);
135 writeOk = yaffs_WriteChunkToNAND(dev,chunk,data,spare);
138 //Todo read-back and verify
139 // If verify fails, then delete this chunk and try again
142 } while(chunk >= 0 && ! writeOk);
150 ///////////////////////// Object management //////////////////
151 // List of spare objects
152 // The list is hooked together using the first pointer
155 // static yaffs_Object *yaffs_freeObjects = NULL;
157 // static int yaffs_nFreeObjects;
159 // static yaffs_ObjectList *yaffs_allocatedObjectList = NULL;
161 // static yaffs_ObjectBucket yaffs_objectBucket[YAFFS_NOBJECT_BUCKETS];
164 static __u16 yaffs_CalcNameSum(const char *name)
169 __u8 *bname = (__u8 *)name;
181 void yaffs_CalcECC(const __u8 *buffer, yaffs_Spare *spare)
184 // Todo do nothing now. Need to put in ecc
185 spare->ecc1[0] = spare->ecc1[1] = spare->ecc1[2] = 0xFF;
186 spare->ecc2[0] = spare->ecc2[1] = spare->ecc2[2] = 0xFF;
189 void yaffs_CalcTagsECC(yaffs_Tags *tags)
191 // Todo don't do anything yet. Need to calculate ecc
192 tags->ecc = 0xFFFFFFFF;
197 ///////////////////////// TNODES ///////////////////////
199 // List of spare tnodes
200 // The list is hooked together using the first pointer
203 //static yaffs_Tnode *yaffs_freeTnodes = NULL;
205 // static int yaffs_nFreeTnodes;
207 //static yaffs_TnodeList *yaffs_allocatedTnodeList = NULL;
211 // yaffs_CreateTnodes creates a bunch more tnodes and
212 // adds them to the tnode free list.
213 // Don't use this function directly
215 static int yaffs_CreateTnodes(yaffs_Device *dev,int nTnodes)
218 yaffs_Tnode *newTnodes;
219 yaffs_TnodeList *tnl;
221 if(nTnodes < 1) return YAFFS_OK;
225 newTnodes = YMALLOC(nTnodes * sizeof(yaffs_Tnode));
229 YALERT("Could not malloc tnodes");
233 // Hook them into the free list
234 for(i = 0; i < nTnodes - 1; i++)
236 newTnodes[i].internal[0] = &newTnodes[i+1];
239 newTnodes[nTnodes - 1].internal[0] = dev->freeTnodes;
240 dev->freeTnodes = newTnodes;
241 dev->nFreeTnodes+= nTnodes;
242 dev->nTnodesCreated += nTnodes;
244 // Now add this bunch of tnodes to a list for freeing up.
246 tnl = YMALLOC(sizeof(yaffs_TnodeList));
249 YALERT("Could not add tnodes to management list");
253 tnl->tnodes = newTnodes;
254 tnl->next = dev->allocatedTnodeList;
255 dev->allocatedTnodeList = tnl;
259 YINFO("Tnodes created");
266 // GetTnode gets us a clean tnode. Tries to make allocate more if we run out
267 static yaffs_Tnode *yaffs_GetTnode(yaffs_Device *dev)
269 yaffs_Tnode *tn = NULL;
271 // If there are none left make more
274 yaffs_CreateTnodes(dev,YAFFS_ALLOCATION_NTNODES);
279 tn = dev->freeTnodes;
280 dev->freeTnodes = dev->freeTnodes->internal[0];
283 memset(tn,0,sizeof(yaffs_Tnode));
291 // FreeTnode frees up a tnode and puts it back on the free list
292 static void yaffs_FreeTnode(yaffs_Device*dev, yaffs_Tnode *tn)
294 tn->internal[0] = dev->freeTnodes;
295 dev->freeTnodes = tn;
300 static void yaffs_DeinitialiseTnodes(yaffs_Device*dev)
302 // Free the list of allocated tnodes
304 while(dev->allocatedTnodeList)
306 YFREE(dev->allocatedTnodeList->tnodes);
307 dev->allocatedTnodeList = dev->allocatedTnodeList->next;
310 dev->freeTnodes = NULL;
311 dev->nFreeTnodes = 0;
314 static void yaffs_InitialiseTnodes(yaffs_Device*dev)
316 dev->allocatedTnodeList = NULL;
317 dev->freeTnodes = NULL;
318 dev->nFreeTnodes = 0;
319 dev->nTnodesCreated = 0;
323 void yaffs_TnodeTest(yaffs_Device *dev)
328 yaffs_Tnode *tn[1000];
330 YINFO("Testing TNodes");
332 for(j = 0; j < 50; j++)
334 for(i = 0; i < 1000; i++)
336 tn[i] = yaffs_GetTnode(dev);
339 YALERT("Getting tnode failed");
342 for(i = 0; i < 1000; i+=3)
344 yaffs_FreeTnode(dev,tn[i]);
351 ////////////////// END OF TNODE MANIPULATION ///////////////////////////
353 /////////////// Functions to manipulate the look-up tree (made up of tnodes)
354 // The look up tree is represented by the top tnode and the number of topLevel
355 // in the tree. 0 means only the level 0 tnode is in the tree.
358 // FindLevel0Tnode finds the level 0 tnode, if one exists.
359 // Used when reading.....
360 static yaffs_Tnode *yaffs_FindLevel0Tnode(yaffs_Device *dev,yaffs_FileStructure *fStruct, __u32 chunkId)
363 yaffs_Tnode *tn = fStruct->top;
365 int requiredTallness;
366 int level = fStruct->topLevel;
368 // Check sane level and chunk Id
369 if(level < 0 || level > YAFFS_TNODES_MAX_LEVEL)
372 sprintf(str,"Bad level %d",level);
376 if(chunkId > YAFFS_MAX_CHUNK_ID)
379 sprintf(str,"Bad chunkId %d",chunkId);
384 // First check we're tall enough (ie enough topLevel)
386 i = chunkId >> (dev->chunkGroupBits + YAFFS_TNODES_LEVEL0_BITS);
387 requiredTallness = 0;
390 i >>= YAFFS_TNODES_INTERNAL_BITS;
395 if(requiredTallness > fStruct->topLevel)
397 // Not tall enough, so we can't find it, return NULL.
402 // Traverse down to level 0
403 while (level > 0 && tn)
405 tn = tn->internal[(chunkId >>(dev->chunkGroupBits + YAFFS_TNODES_LEVEL0_BITS + (level-1) * YAFFS_TNODES_INTERNAL_BITS)) &
406 YAFFS_TNODES_INTERNAL_MASK];
414 // AddOrFindLevel0Tnode finds the level 0 tnode if it exists, otherwise first expands the tree.
415 // This happens in two steps:
416 // 1. If the tree isn't tall enough, then make it taller.
417 // 2. Scan down the tree towards the level 0 tnode adding tnodes if required.
419 // Used when modifying the tree.
421 static yaffs_Tnode *yaffs_AddOrFindLevel0Tnode(yaffs_Device *dev, yaffs_FileStructure *fStruct, __u32 chunkId)
426 int requiredTallness;
432 T(("AddOrFind topLevel=%d, chunk=%d",fStruct->topLevel,chunkId));
434 // Check sane level and page Id
435 if(fStruct->topLevel < 0 || fStruct->topLevel > YAFFS_TNODES_MAX_LEVEL)
438 sprintf(str,"Bad level %d",fStruct->topLevel);
443 if(chunkId > YAFFS_MAX_CHUNK_ID)
446 sprintf(str,"Bad chunkId %d",chunkId);
451 // First check we're tall enough (ie enough topLevel)
453 i = chunkId >> (dev->chunkGroupBits + YAFFS_TNODES_LEVEL0_BITS);
454 requiredTallness = 0;
457 i >>= YAFFS_TNODES_INTERNAL_BITS;
461 T((" required=%d",requiredTallness));
464 if(requiredTallness > fStruct->topLevel)
466 // Not tall enough,gotta make the tree taller
467 for(i = fStruct->topLevel; i < requiredTallness; i++)
471 tn = yaffs_GetTnode(dev);
475 tn->internal[0] = fStruct->top;
480 YALERT("No more tnodes");
484 fStruct->topLevel = requiredTallness;
488 // Traverse down to level 0, adding anything we need
490 l = fStruct->topLevel;
494 i = (chunkId >> (dev->chunkGroupBits +YAFFS_TNODES_LEVEL0_BITS + (l-1) * YAFFS_TNODES_INTERNAL_BITS)) &
495 YAFFS_TNODES_INTERNAL_MASK;
503 tn->internal[i] = yaffs_GetTnode(dev);
506 tn = tn->internal[i];
517 // Pruning removes any part of the file structure tree that is beyond the
518 // bounds of the file.
519 // A file should only get pruned when its size is reduced.
521 // Before pruning, the chunks must be pulled from the tree and the
522 // level 0 tnode entries must be zeroed out.
523 // Could also use this for file deletion, but that's probably better handled
524 // by a special case.
526 // yaffs_PruneWorker should only be called by yaffs_PruneFileStructure()
528 static yaffs_Tnode *yaffs_PruneWorker(yaffs_Device *dev, yaffs_Tnode *tn, __u32 level, int del0)
537 for(i = 0; i < YAFFS_NTNODES_INTERNAL; i++)
539 if(tn->internal[i] && level > 0)
541 tn->internal[i] = yaffs_PruneWorker(dev,tn->internal[i],level - 1, ( i == 0) ? del0 : 1);
550 if(hasData == 0 && del0)
552 // Free and return NULL
554 yaffs_FreeTnode(dev,tn);
564 static int yaffs_PruneFileStructure(yaffs_Device *dev, yaffs_FileStructure *fStruct)
571 if(fStruct->topLevel > 0)
573 fStruct->top = yaffs_PruneWorker(dev,fStruct->top, fStruct->topLevel,0);
575 // Now we have a tree with all the non-zero branches NULL but the height
576 // is the same as it was.
577 // Let's see if we can trim internal tnodes to shorten the tree.
578 // We can do this if only the 0th element in the tnode is in use
579 // (ie all the non-zero are NULL)
581 while(fStruct->topLevel && !done)
586 for(i = 1; i <YAFFS_NTNODES_INTERNAL; i++)
596 fStruct->top = tn->internal[0];
598 yaffs_FreeTnode(dev,tn);
613 /////////////////////// End of File Structure functions. /////////////////
615 // yaffs_CreateFreeObjects creates a bunch more objects and
616 // adds them to the object free list.
617 static int yaffs_CreateFreeObjects(yaffs_Device *dev, int nObjects)
620 yaffs_Object *newObjects;
621 yaffs_ObjectList *list;
623 if(nObjects < 1) return YAFFS_OK;
627 newObjects = YMALLOC(nObjects * sizeof(yaffs_Object));
631 YALERT("Could not allocate more objects");
635 // Hook them into the free list
636 for(i = 0; i < nObjects - 1; i++)
638 (yaffs_Object *)newObjects[i].siblings.next = &newObjects[i+1];
641 newObjects[nObjects - 1].siblings.next = (void *)dev->freeObjects;
642 dev->freeObjects = newObjects;
643 dev->nFreeObjects+= nObjects;
644 dev->nObjectsCreated+= nObjects;
646 // Now add this bunch of Objects to a list for freeing up.
648 list = YMALLOC(sizeof(yaffs_ObjectList));
651 YALERT("Could not add Objects to management list");
655 list->objects = newObjects;
656 list->next = dev->allocatedObjectList;
657 dev->allocatedObjectList = list;
661 YINFO("Objects created");
668 // AllocateEmptyObject gets us a clean Object. Tries to make allocate more if we run out
669 static yaffs_Object *yaffs_AllocateEmptyObject(yaffs_Device *dev)
671 yaffs_Object *tn = NULL;
673 // If there are none left make more
674 if(!dev->freeObjects)
676 yaffs_CreateFreeObjects(dev,YAFFS_ALLOCATION_NOBJECTS);
681 tn = dev->freeObjects;
682 dev->freeObjects = (yaffs_Object *)(dev->freeObjects->siblings.next);
685 // Now sweeten it up...
687 memset(tn,0,sizeof(yaffs_Object));
689 tn->variantType = YAFFS_OBJECT_TYPE_UNKNOWN;
690 INIT_LIST_HEAD(&(tn->hardLinks));
691 INIT_LIST_HEAD(&(tn->hashLink));
692 INIT_LIST_HEAD(&tn->siblings);
694 // Add it to the lost and found directory.
695 // NB Can't put root or lostNFound in lostNFound so
696 // check if lostNFound exists first
697 if(dev->lostNFoundDir)
699 yaffs_AddObjectToDirectory(dev->lostNFoundDir,tn);
707 static yaffs_Object *yaffs_CreateFakeDirectory(yaffs_Device *dev,int number,__u32 mode)
710 yaffs_Object *obj = yaffs_CreateNewObject(dev,number,YAFFS_OBJECT_TYPE_DIRECTORY);
713 obj->fake = 1; // it is fake so it has no NAND presence...
714 obj->renameAllowed= 0; // ... and we're not allowed to rename it...
715 obj->unlinkAllowed= 0; // ... or unlink it
718 obj->chunkId = 0; // Not a valid chunk.
726 static void yaffs_UnhashObject(yaffs_Object *tn)
729 yaffs_Device *dev = tn->myDev;
732 // If it is still linked into the bucket list, free from the list
733 if(!list_empty(&tn->hashLink))
735 list_del_init(&tn->hashLink);
736 bucket = yaffs_HashFunction(tn->objectId);
737 dev->objectBucket[bucket].count--;
743 // FreeObject frees up a Object and puts it back on the free list
744 static void yaffs_FreeObject(yaffs_Object *tn)
747 yaffs_Device *dev = tn->myDev;
749 yaffs_UnhashObject(tn);
751 // Link into the free list.
752 (yaffs_Object *)(tn->siblings.next) = dev->freeObjects;
753 dev->freeObjects = tn;
760 static void yaffs_DeinitialiseObjects(yaffs_Device *dev)
762 // Free the list of allocated Objects
764 while( dev->allocatedObjectList)
766 YFREE(dev->allocatedObjectList->objects);
767 dev->allocatedObjectList = dev->allocatedObjectList->next;
770 dev->freeObjects = NULL;
771 dev->nFreeObjects = 0;
774 static void yaffs_InitialiseObjects(yaffs_Device *dev)
778 dev->allocatedObjectList = NULL;
779 dev->freeObjects = NULL;
780 dev->nFreeObjects = 0;
782 for(i = 0; i < YAFFS_NOBJECT_BUCKETS; i++)
784 INIT_LIST_HEAD(&dev->objectBucket[i].list);
785 dev->objectBucket[i].count = 0;
795 int yaffs_FindNiceObjectBucket(yaffs_Device *dev)
803 // First let's see if we can find one that's empty.
805 for(i = 0; i < 10 && lowest > 0; i++)
808 x %= YAFFS_NOBJECT_BUCKETS;
809 if(dev->objectBucket[x].count < lowest)
811 lowest = dev->objectBucket[x].count;
817 // If we didn't find an empty list, then try
818 // looking a bit further for a short one
820 for(i = 0; i < 10 && lowest > 3; i++)
823 x %= YAFFS_NOBJECT_BUCKETS;
824 if(dev->objectBucket[x].count < lowest)
826 lowest = dev->objectBucket[x].count;
835 static int yaffs_CreateNewObjectNumber(yaffs_Device *dev)
837 int bucket = yaffs_FindNiceObjectBucket(dev);
839 // Now find an object value that has not already been taken
840 // by scanning the list.
847 //yaffs_CheckObjectHashSanity();
852 n += YAFFS_NOBJECT_BUCKETS;
853 if(1 ||dev->objectBucket[bucket].count > 0)
855 list_for_each(i,&dev->objectBucket[bucket].list)
857 // If there is already one in the list
858 if(list_entry(i, yaffs_Object,hashLink)->objectId == n)
866 //T(("bucket %d count %d inode %d\n",bucket,yaffs_objectBucket[bucket].count,n);
871 void yaffs_HashObject(yaffs_Object *in)
873 int bucket = yaffs_HashFunction(in->objectId);
874 yaffs_Device *dev = in->myDev;
876 if(!list_empty(&in->hashLink))
882 list_add(&in->hashLink,&dev->objectBucket[bucket].list);
883 dev->objectBucket[bucket].count++;
887 yaffs_Object *yaffs_FindObjectByNumber(yaffs_Device *dev,int number)
889 int bucket = yaffs_HashFunction(number);
893 list_for_each(i,&dev->objectBucket[bucket].list)
895 // Lookm if it is in the list
896 in = list_entry(i, yaffs_Object,hashLink);
897 if(in->objectId == number)
908 yaffs_Object *yaffs_CreateNewObject(yaffs_Device *dev,int number,yaffs_ObjectType type)
911 yaffs_Object *theObject;
915 number = yaffs_CreateNewObjectNumber(dev);
918 theObject = yaffs_AllocateEmptyObject(dev);
923 theObject->renameAllowed = 1;
924 theObject->unlinkAllowed = 1;
925 theObject->objectId = number;
926 theObject->myDev = dev;
927 yaffs_HashObject(theObject);
928 theObject->variantType = type;
929 theObject->st_atime = theObject->st_mtime = theObject->st_ctime = CURRENT_TIME;
933 case YAFFS_OBJECT_TYPE_FILE:
934 theObject->variant.fileVariant.fileSize = 0;
935 theObject->variant.fileVariant.topLevel = 0;
936 theObject->variant.fileVariant.top = yaffs_GetTnode(dev);
938 case YAFFS_OBJECT_TYPE_DIRECTORY:
939 INIT_LIST_HEAD(&theObject->variant.directoryVariant.children);
941 case YAFFS_OBJECT_TYPE_SYMLINK:
943 case YAFFS_OBJECT_TYPE_HARDLINK:
945 case YAFFS_OBJECT_TYPE_UNKNOWN:
946 // todo this should not happen
953 yaffs_Object *yaffs_FindOrCreateObjectByNumber(yaffs_Device *dev, int number,yaffs_ObjectType type)
955 yaffs_Object *theObject = NULL;
959 theObject = yaffs_FindObjectByNumber(dev,number);
964 theObject = yaffs_CreateNewObject(dev,number,type);
971 char *yaffs_CloneString(const char *str)
977 newStr = YMALLOC(strlen(str) + 1);
986 // Mknod (create) a new object.
987 // equivalentObject only has meaning for a hard link;
988 // aliasString only has meaning for a sumlink.
989 yaffs_Object *yaffs_MknodObject( yaffs_ObjectType type,
990 yaffs_Object *parent,
995 yaffs_Object *equivalentObject,
996 const char *aliasString)
1000 yaffs_Device *dev = parent->myDev;
1002 in = yaffs_CreateNewObject(dev,-1,type);
1008 in->variantType = type;
1013 in->st_atime = in->st_mtime = in->st_ctime = CURRENT_TIME;
1015 in->sum = yaffs_CalcNameSum(name);
1018 yaffs_AddObjectToDirectory(parent,in);
1020 in->myDev = parent->myDev;
1025 case YAFFS_OBJECT_TYPE_SYMLINK:
1026 in->variant.symLinkVariant.alias = yaffs_CloneString(aliasString);
1028 case YAFFS_OBJECT_TYPE_HARDLINK:
1029 in->variant.hardLinkVariant.equivalentObject = equivalentObject;
1030 in->variant.hardLinkVariant.equivalentObjectId = equivalentObject->objectId;
1031 list_add(&in->hardLinks,&equivalentObject->hardLinks);
1033 case YAFFS_OBJECT_TYPE_FILE: // do nothing
1034 case YAFFS_OBJECT_TYPE_DIRECTORY: // do nothing
1035 case YAFFS_OBJECT_TYPE_UNKNOWN:
1038 yaffs_UpdateObjectHeader(in,name);
1045 yaffs_Object *yaffs_MknodFile(yaffs_Object *parent,const char *name, __u32 mode, __u32 uid, __u32 gid)
1047 return yaffs_MknodObject(YAFFS_OBJECT_TYPE_FILE,parent,name,mode,uid,gid,NULL,NULL);
1050 yaffs_Object *yaffs_MknodDirectory(yaffs_Object *parent,const char *name, __u32 mode, __u32 uid, __u32 gid)
1052 return yaffs_MknodObject(YAFFS_OBJECT_TYPE_DIRECTORY,parent,name,mode,uid,gid,NULL,NULL);
1055 yaffs_Object *yaffs_MknodSymLink(yaffs_Object *parent,const char *name, __u32 mode, __u32 uid, __u32 gid,const char *alias)
1057 return yaffs_MknodObject(YAFFS_OBJECT_TYPE_SYMLINK,parent,name,mode,uid,gid,NULL,alias);
1060 // NB yaffs_Link returns the object id of the equivalent object.
1061 yaffs_Object *yaffs_Link(yaffs_Object *parent, const char *name, yaffs_Object *equivalentObject)
1063 // Get the real object in case we were fed a hard link as an equivalent object
1064 equivalentObject = yaffs_GetEquivalentObject(equivalentObject);
1066 if(yaffs_MknodObject(YAFFS_OBJECT_TYPE_HARDLINK,parent,name,0,0,0,equivalentObject,NULL))
1068 return equivalentObject;
1078 static int yaffs_ChangeObjectName(yaffs_Object *obj, yaffs_Object *newDir, const char *newName)
1080 //yaffs_Device *dev = obj->myDev;
1084 newDir = obj->parent; // use the old directory
1087 // Only proceed if the new name does not exist and
1088 // if we're putting it into a directory.
1089 if(!yaffs_FindObjectByName(newDir,newName) &&
1090 newDir->variantType == YAFFS_OBJECT_TYPE_DIRECTORY)
1092 obj->sum = yaffs_CalcNameSum(newName);
1094 yaffs_AddObjectToDirectory(newDir,obj);
1096 return yaffs_UpdateObjectHeader(obj,newName);
1102 int yaffs_RenameObject(yaffs_Object *oldDir, const char *oldName, yaffs_Object *newDir, const char *newName)
1106 obj = yaffs_FindObjectByName(oldDir,oldName);
1107 if(obj && obj->renameAllowed)
1109 return yaffs_ChangeObjectName(obj,newDir,newName);
1116 static int yaffs_CheckObjectHashSanity(yaffs_Device *dev)
1118 // Scan the buckets and check that the lists
1119 // have as many members as the count says there are
1122 struct list_head *j;
1125 for(bucket = 0; bucket < YAFFS_NOBJECT_BUCKETS; bucket++)
1129 list_for_each(j,&dev->objectBucket[bucket].list)
1134 if(countEm != dev->objectBucket[bucket].count)
1136 YALERT("Inode hash inconsistency");
1144 void yaffs_ObjectTest(yaffs_Device *dev)
1146 yaffs_Object *in[1000];
1148 yaffs_Object *inold[1000];
1152 memset(in,0,1000*sizeof(yaffs_Object *));
1153 memset(inold,0,1000*sizeof(yaffs_Object *));
1155 yaffs_CheckObjectHashSanity(dev);
1157 for(j = 0; j < 10; j++)
1161 for(i = 0; i < 1000; i++)
1163 in[i] = yaffs_CreateNewObject(dev,-1,YAFFS_OBJECT_TYPE_FILE);
1166 YINFO("No more inodes");
1170 inNo[i] = in[i]->objectId;
1174 for(i = 0; i < 1000; i++)
1176 if(yaffs_FindObjectByNumber(dev,inNo[i]) != in[i])
1178 T(("Differnce in look up test\n"));
1182 // T(("Look up ok\n"));
1186 yaffs_CheckObjectHashSanity(dev);
1188 for(i = 0; i < 1000; i+=3)
1190 yaffs_FreeObject(in[i]);
1195 yaffs_CheckObjectHashSanity(dev);
1202 /////////////////////////// Block Management and Page Allocation ///////////////////
1205 static void yaffs_InitialiseBlocks(yaffs_Device *dev)
1207 dev->blockInfo = YMALLOC(dev->nBlocks * sizeof(yaffs_BlockInfo));
1208 memset(dev->blockInfo,0,dev->nBlocks * sizeof(yaffs_BlockInfo));
1209 dev->allocationBlock = -1; // force it to get a new one
1212 static void yaffs_DeinitialiseBlocks(yaffs_Device *dev)
1214 YFREE(dev->blockInfo);
1217 // FindDiretiestBlock is used to select the dirtiest block (or close enough)
1218 // for garbage collection.
1220 static int yaffs_FindDirtiestBlock(yaffs_Device *dev)
1223 int b = dev->currentDirtyChecker;
1227 int pagesInUse = 100; // silly big number
1229 for(i = dev->startBlock; i <= dev->endBlock && pagesInUse > 2 ; i++)
1232 if (b > dev->endBlock)
1234 b = dev->startBlock;
1237 if(dev->blockInfo[b].blockState == YAFFS_BLOCK_STATE_FULL &&
1238 (dev->blockInfo)[b].pagesInUse < pagesInUse)
1241 pagesInUse = (dev->blockInfo)[b].pagesInUse;
1245 dev->currentDirtyChecker = b;
1251 static int yaffs_FindBlockForAllocation(yaffs_Device *dev,int useReserve)
1255 if(useReserve && dev->nErasedBlocks < 1)
1257 // Hoosterman we've got a problem.
1258 // Can't get space to gc
1261 else if(!useReserve && dev->nErasedBlocks <= YAFFS_RESERVED_BLOCKS)
1263 // We are not in GC, so we hold some in reserve so we can get
1267 // Find an empty block.
1269 for(i = dev->startBlock; i <= dev->endBlock; i++)
1272 if(dev->blockInfo[i].blockState == YAFFS_BLOCK_STATE_EMPTY)
1274 dev->blockInfo[i].blockState = YAFFS_BLOCK_STATE_ALLOCATING;
1275 dev->nErasedBlocks--;
1276 if(dev->nErasedBlocks <= YAFFS_RESERVED_BLOCKS)
1278 dev->garbageCollectionRequired = 1;
1289 static void yaffs_BlockBecameDirty(yaffs_Device *dev,int blockNo)
1291 yaffs_BlockInfo *bi = &dev->blockInfo[blockNo];
1293 // Mark as dirty, erase it and mark as clean.
1294 bi->blockState = YAFFS_BLOCK_STATE_DIRTY;
1295 yaffs_EraseBlockInNAND(dev,blockNo);
1296 bi->blockState = YAFFS_BLOCK_STATE_EMPTY;
1297 dev->nErasedBlocks++;
1301 T(("Erased block %d\n",blockNo));
1305 static int yaffs_AllocateChunk(yaffs_Device *dev,int useReserve)
1309 if(dev->allocationBlock < 0)
1311 // Get next block to allocate off
1312 dev->allocationBlock = yaffs_FindBlockForAllocation(dev,useReserve);
1313 dev->allocationPage = 0;
1316 // Next page please....
1317 if(dev->allocationBlock >= 0)
1319 retVal = (dev->allocationBlock * YAFFS_CHUNKS_PER_BLOCK) +
1320 dev->allocationPage;
1321 dev->blockInfo[dev->allocationBlock].pagesInUse++;
1322 dev->blockInfo[dev->allocationBlock].pageBits |=
1323 (1 << (dev->allocationPage));
1325 dev->allocationPage++;
1329 // If the block is full set the state to full
1330 if(dev->allocationPage >= YAFFS_CHUNKS_PER_BLOCK)
1332 dev->blockInfo[dev->allocationBlock].blockState = YAFFS_BLOCK_STATE_FULL;
1333 dev->allocationBlock = -1;
1336 #ifdef YAFFS_PARANOID
1337 if(yaffs_CheckChunkErased(retVal) == YAFFS_FAIL)
1339 T(("..................Trying to allocate non-erased page %d\n",retVal));
1345 T(("!!!!!!!!! Allocator out !!!!!!!!!!!!!!!!!\n"));
1351 int yaffs_GarbageCollectBlock(yaffs_Device *dev,int block)
1360 __u8 buffer[YAFFS_BYTES_PER_CHUNK];
1362 yaffs_BlockInfo *bi = &dev->blockInfo[block];
1364 yaffs_Object *object;
1366 T(("Collecting block %d n %d bits %x\n",block, bi->pagesInUse, bi->pageBits));
1368 for(mask = 1,oldChunk = block * YAFFS_CHUNKS_PER_BLOCK;
1369 mask && bi->pageBits;
1370 mask <<= 1, oldChunk++ )
1372 if(bi->pageBits & mask)
1375 // This page is in use and needs to be copied off
1377 T(("copying page %x from %d to %d\n",mask,oldChunk,newChunk));
1379 yaffs_ReadChunkFromNAND(dev,oldChunk,buffer, &spare);
1381 yaffs_GetTagsFromSpare(&spare,&tags);
1382 tags.serialNumber++;
1383 yaffs_LoadTagsIntoSpare(&spare,&tags);
1386 newChunk = yaffs_AllocatePage(dev,1);
1392 yaffs_WriteChunkToNAND(dev,newChunk, buffer, &spare);
1395 newChunk = yaffs_WriteNewChunkToNAND(dev, buffer, &spare,1);
1402 object = yaffs_FindObjectByNumber(dev,tags.objectId);
1404 // Ok, now fix up the Tnodes etc.
1406 if(tags.chunkId == 0)
1409 object->chunkId = newChunk;
1413 // It's a data chunk
1414 yaffs_PutChunkIntoFile(object, tags.chunkId, newChunk);
1418 yaffs_DeleteChunk(dev,oldChunk);
1426 int yaffs_CheckGarbageCollection(yaffs_Device *dev)
1430 if(dev->garbageCollectionRequired)
1432 dev->garbageCollectionRequired = 0;
1433 block = yaffs_FindDirtiestBlock(dev);
1436 return yaffs_GarbageCollectBlock(dev,block);
1448 //////////////////////////// TAGS ///////////////////////////////////////
1450 static void yaffs_LoadTagsIntoSpare(yaffs_Spare *sparePtr, yaffs_Tags *tagsPtr)
1452 yaffs_TagsUnion *tu = (yaffs_TagsUnion *)tagsPtr;
1454 yaffs_CalcTagsECC(tagsPtr);
1456 sparePtr->tagByte0 = tu->asBytes[0];
1457 sparePtr->tagByte1 = tu->asBytes[1];
1458 sparePtr->tagByte2 = tu->asBytes[2];
1459 sparePtr->tagByte3 = tu->asBytes[3];
1460 sparePtr->tagByte4 = tu->asBytes[4];
1461 sparePtr->tagByte5 = tu->asBytes[5];
1462 sparePtr->tagByte6 = tu->asBytes[6];
1463 sparePtr->tagByte7 = tu->asBytes[7];
1466 static void yaffs_GetTagsFromSpare(yaffs_Spare *sparePtr,yaffs_Tags *tagsPtr)
1468 yaffs_TagsUnion *tu = (yaffs_TagsUnion *)tagsPtr;
1470 tu->asBytes[0]= sparePtr->tagByte0;
1471 tu->asBytes[1]= sparePtr->tagByte1;
1472 tu->asBytes[2]= sparePtr->tagByte2;
1473 tu->asBytes[3]= sparePtr->tagByte3;
1474 tu->asBytes[4]= sparePtr->tagByte4;
1475 tu->asBytes[5]= sparePtr->tagByte5;
1476 tu->asBytes[6]= sparePtr->tagByte6;
1477 tu->asBytes[7]= sparePtr->tagByte7;
1479 // Todo Check ECC on tags
1482 static void yaffs_SpareInitialise(yaffs_Spare *spare)
1484 memset(spare,0xFF,sizeof(yaffs_Spare));
1487 static int yaffs_ReadChunkTagsFromNAND(yaffs_Device *dev,int chunkInNAND, yaffs_Tags *tags)
1492 if(yaffs_ReadChunkFromNAND(dev,chunkInNAND,NULL,&spare) == YAFFS_OK)
1494 yaffs_GetTagsFromSpare(&spare,tags);
1506 static int yaffs_WriteChunkWithTagsToNAND(yaffs_Device *dev,int chunkInNAND, const __u8 *buffer, yaffs_Tags *tags)
1508 // NB There must be tags, data is optional
1509 // If there is data, then an ECC is calculated on it.
1518 yaffs_SpareInitialise(&spare);
1523 yaffs_CalcECC(buffer,&spare);
1526 yaffs_LoadTagsIntoSpare(&spare,tags);
1528 return yaffs_WriteChunkToNAND(dev,chunkInNAND,buffer,&spare);
1532 static int yaffs_WriteNewChunkWithTagsToNAND(yaffs_Device *dev, const __u8 *buffer, yaffs_Tags *tags, int useReserve)
1534 // NB There must be tags, data is optional
1535 // If there is data, then an ECC is calculated on it.
1544 yaffs_SpareInitialise(&spare);
1549 yaffs_CalcECC(buffer,&spare);
1552 yaffs_LoadTagsIntoSpare(&spare,tags);
1554 return yaffs_WriteNewChunkToNAND(dev,buffer,&spare,useReserve);
1561 int yaffs_FindChunkInFile(yaffs_Object *in,int chunkInInode,yaffs_Tags *tags)
1563 //Get the Tnode, then get the level 0 offset chunk offset
1566 yaffs_Tags localTags;
1569 yaffs_Device *dev = in->myDev;
1574 // Passed a NULL, so use our own tags space
1578 tn = yaffs_FindLevel0Tnode(dev,&in->variant.fileVariant, chunkInInode);
1582 theChunk = tn->level0[chunkInInode & YAFFS_TNODES_LEVEL0_MASK] << dev->chunkGroupBits;
1584 // Now we need to do the shifting etc and search for it
1585 for(i = 0,found = 0; i < dev->chunkGroupSize && !found; i++)
1587 yaffs_ReadChunkTagsFromNAND(dev,theChunk,tags);
1588 if(tags->chunkId == chunkInInode &&
1589 tags->objectId == in->objectId)
1600 return found ? theChunk : -1;
1603 int yaffs_FindAndDeleteChunkInFile(yaffs_Object *in,int chunkInInode,yaffs_Tags *tags)
1605 //Get the Tnode, then get the level 0 offset chunk offset
1608 yaffs_Tags localTags;
1611 yaffs_Device *dev = in->myDev;
1615 // Passed a NULL, so use our own tags space
1619 tn = yaffs_FindLevel0Tnode(dev,&in->variant.fileVariant, chunkInInode);
1624 theChunk = tn->level0[chunkInInode & YAFFS_TNODES_LEVEL0_MASK] << dev->chunkGroupBits;
1626 // Now we need to do the shifting etc and search for it
1627 for(i = 0,found = 0; i < dev->chunkGroupSize && !found; i++)
1629 yaffs_ReadChunkTagsFromNAND(dev,theChunk,tags);
1630 if(tags->chunkId == chunkInInode &&
1631 tags->objectId == in->objectId)
1642 // Delete the entry in the filestructure
1645 tn->level0[chunkInInode & YAFFS_TNODES_LEVEL0_MASK] = 0;
1650 T(("No level 0 found for %d\n", chunkInInode));
1655 T(("Could not find %d to delete\n",chunkInInode));
1657 return found ? theChunk : -1;
1663 static int yaffs_CheckFileSanity(yaffs_Object *in)
1671 yaffs_Tags localTags;
1672 yaffs_Tags *tags = &localTags;
1676 if(in->variantType != YAFFS_OBJECT_TYPE_FILE)
1678 T(("Object not a file\n"));
1682 objId = in->objectId;
1683 fSize = in->variant.fileVariant.fileSize;
1684 nChunks = (fSize + YAFFS_BYTES_PER_CHUNK -1)/YAFFS_BYTES_PER_CHUNK;
1686 for(chunk = 1; chunk <= nChunks; chunk++)
1688 tn = yaffs_FindLevel0Tnode(&in->variant.fileVariant, chunk);
1693 theChunk = tn->level0[chunk & YAFFS_TNODES_LEVEL0_MASK] << dev->chunkGroupBits;
1696 yaffs_ReadChunkTagsFromNAND(theChunk,tags);
1697 if(tags->chunkId == chunk &&
1698 tags->objectId == in->objectId)
1705 //T(("File problem file [%d,%d] NAND %d tags[%d,%d]\n",
1706 // objId,chunk,theChunk,tags->chunkId,tags->objectId);
1715 T(("No level 0 found for %d\n", chunk));
1719 return failed ? YAFFS_FAIL : YAFFS_OK;
1724 static int yaffs_PutChunkIntoFile(yaffs_Object *in,int chunkInInode, int chunkInNAND)
1727 yaffs_Device *dev = in->myDev;
1729 tn = yaffs_AddOrFindLevel0Tnode(dev,&in->variant.fileVariant, chunkInInode);
1730 tn->level0[chunkInInode & YAFFS_TNODES_LEVEL0_MASK] = chunkInNAND;
1736 int yaffs_ReadChunkDataFromObject(yaffs_Object *in,int chunkInInode, __u8 *buffer)
1738 int chunkInNAND = yaffs_FindChunkInFile(in,chunkInInode,NULL);
1740 if(chunkInNAND >= 0)
1742 return yaffs_ReadChunkFromNAND(in->myDev,chunkInNAND,buffer,NULL);
1752 static void yaffs_DeleteChunk(yaffs_Device *dev,int chunkId)
1754 int block = chunkId / YAFFS_CHUNKS_PER_BLOCK;
1755 int page = chunkId % YAFFS_CHUNKS_PER_BLOCK;
1758 // Mark the deleted NAND page as deleted
1764 yaffs_WriteChunkWithTagsToNAND(dev,chunkId,NULL,&tags);
1767 // Pull out of the management area.
1768 if( dev->blockInfo[block].blockState == YAFFS_BLOCK_STATE_ALLOCATING ||
1769 dev->blockInfo[block].blockState == YAFFS_BLOCK_STATE_FULL)
1773 dev->blockInfo[block].pageBits &= ~(1 << page);
1774 dev->blockInfo[block].pagesInUse--;
1776 if( dev->blockInfo[block].pagesInUse == 0 &&
1777 dev->blockInfo[block].blockState == YAFFS_BLOCK_STATE_FULL)
1779 yaffs_BlockBecameDirty(dev,block);
1785 T(("Bad news deteing chunk %d\n",chunkId));
1793 int yaffs_WriteChunkDataToObject(yaffs_Object *in,int chunkInInode, const __u8 *buffer,int nBytes,int useReserve)
1795 // Find old chunk Need to do this to get serial number
1796 // Write new one and patch into tree.
1797 // Invalidate old tags.
1800 yaffs_Tags prevTags;
1805 yaffs_Device *dev = in->myDev;
1807 yaffs_CheckGarbageCollection(dev);
1809 // Get the previous chunk at this location in the file if it exists
1810 prevChunkId = yaffs_FindChunkInFile(in,chunkInInode,&prevTags);
1813 newTags.chunkId = chunkInInode;
1814 newTags.objectId = in->objectId;
1815 newTags.serialNumber = (prevChunkId >= 0) ? prevTags.serialNumber + 1 : 1;
1816 newTags.byteCount = nBytes;
1817 newTags.unusedStuff = 0xFFFFFFFF;
1819 yaffs_CalcTagsECC(&newTags);
1823 // Create new chunk in NAND
1824 newChunkId = yaffs_AllocatePage(dev,useReserve);
1831 yaffs_WriteChunkWithTagsToNAND(dev,newChunkId,buffer,&newTags);
1833 yaffs_PutChunkIntoFile(in,chunkInInode,newChunkId);
1836 if(prevChunkId >= 0)
1838 yaffs_DeleteChunk(dev,prevChunkId);
1842 yaffs_CheckFileSanity(in);
1851 newChunkId = yaffs_WriteNewChunkWithTagsToNAND(dev,buffer,&newTags,useReserve);
1854 yaffs_PutChunkIntoFile(in,chunkInInode,newChunkId);
1857 if(prevChunkId >= 0)
1859 yaffs_DeleteChunk(dev,prevChunkId);
1863 yaffs_CheckFileSanity(in);
1874 // UpdateObjectHeader updates the header on NAND for an object.
1875 // If name is not NULL, then that new name is used.
1877 int yaffs_UpdateObjectHeader(yaffs_Object *in,const char *name)
1880 yaffs_Device *dev = in->myDev;
1886 __u8 bufferNew[YAFFS_BYTES_PER_CHUNK];
1887 __u8 bufferOld[YAFFS_BYTES_PER_CHUNK];
1889 yaffs_ObjectHeader *oh = (yaffs_ObjectHeader *)bufferNew;
1890 yaffs_ObjectHeader *ohOld = (yaffs_ObjectHeader *)bufferOld;
1895 yaffs_CheckGarbageCollection(dev);
1897 memset(bufferNew,0xFF,YAFFS_BYTES_PER_CHUNK);
1899 prevChunkId = in->chunkId;
1901 if(prevChunkId >= 0)
1903 yaffs_ReadChunkFromNAND(dev,prevChunkId,bufferOld,NULL);
1907 oh->type = in->variantType;
1909 oh->st_mode = in->st_mode;
1910 oh->st_uid = in->st_uid;
1911 oh->st_gid = in->st_gid;
1912 oh->st_atime = in->st_atime;
1913 oh->st_mtime = in->st_mtime;
1914 oh->st_ctime = in->st_ctime;
1916 oh->parentObjectId = in->parent->objectId;
1920 memset(oh->name,0,YAFFS_MAX_NAME_LENGTH + 1);
1921 strncpy(oh->name,name,YAFFS_MAX_NAME_LENGTH);
1925 memcpy(oh->name, ohOld->name,YAFFS_MAX_NAME_LENGTH + 1);
1928 switch(in->variantType)
1930 case YAFFS_OBJECT_TYPE_UNKNOWN: // Todo got a problem
1932 case YAFFS_OBJECT_TYPE_FILE:
1933 oh->fileSize = in->variant.fileVariant.fileSize;
1935 case YAFFS_OBJECT_TYPE_HARDLINK:
1936 oh->equivalentObjectId = in->variant.hardLinkVariant.equivalentObjectId;
1938 case YAFFS_OBJECT_TYPE_DIRECTORY: // Do nothing
1940 case YAFFS_OBJECT_TYPE_SYMLINK:
1941 strncpy(oh->alias,in->variant.symLinkVariant.alias,YAFFS_MAX_ALIAS_LENGTH);
1942 oh->alias[YAFFS_MAX_ALIAS_LENGTH] = 0;
1948 newTags.chunkId = 0;
1949 newTags.objectId = in->objectId;
1950 newTags.serialNumber = in->serial;
1951 newTags.byteCount = 0xFFFFFFFF;
1952 newTags.unusedStuff = 0xFFFFFFFF;
1954 yaffs_CalcTagsECC(&newTags);
1959 // Create new chunk in NAND
1960 newChunkId = yaffs_AllocatePage(dev,1);
1965 yaffs_WriteChunkWithTagsToNAND(dev,newChunkId,bufferNew,&newTags);
1967 in->chunkId = newChunkId;
1969 if(prevChunkId >= 0)
1971 yaffs_DeleteChunk(dev,prevChunkId);
1980 // Create new chunk in NAND
1981 newChunkId = yaffs_WriteNewChunkWithTagsToNAND(dev,bufferNew,&newTags,1);
1986 in->chunkId = newChunkId;
1988 if(prevChunkId >= 0)
1990 yaffs_DeleteChunk(dev,prevChunkId);
2005 ///////////////////////// File read/write ///////////////////////////////
2006 // Read and write have very similar structures.
2007 // In general the read/write has three parts to it
2008 // * An incomplete chunk to start with (if the read/write is not chunk-aligned)
2009 // * Some complete chunks
2010 // * An incomplete chunk to end off with
2012 // Curve-balls: the first chunk might also be the last chunk.
2014 int yaffs_ReadDataFromFile(yaffs_Object *in, __u8 * buffer, __u32 offset, int nBytes)
2017 // yaffs_Device *dev = in->myDev;
2019 __u8 localBuffer[YAFFS_BYTES_PER_CHUNK];
2029 chunk = offset / YAFFS_BYTES_PER_CHUNK + 1; // The first chunk is 1
2030 start = offset % YAFFS_BYTES_PER_CHUNK;
2032 // OK now check for the curveball where the start and end are in
2034 if( (start + n) < YAFFS_BYTES_PER_CHUNK)
2040 nToCopy = YAFFS_BYTES_PER_CHUNK - start;
2043 if(nToCopy != YAFFS_BYTES_PER_CHUNK)
2045 // An incomplete start or end chunk (or maybe both start and end chunk)
2046 // Read into the local buffer then copy...
2048 yaffs_ReadChunkDataFromObject(in,chunk,localBuffer);
2049 memcpy(buffer,&localBuffer[start],nToCopy);
2053 // A full chunk. Read directly into the supplied buffer.
2054 yaffs_ReadChunkDataFromObject(in,chunk,buffer);
2068 int yaffs_WriteDataToFile(yaffs_Object *in,const __u8 * buffer, __u32 offset, int nBytes)
2070 __u8 localBuffer[YAFFS_BYTES_PER_CHUNK];
2078 int endOfWrite = offset+nBytes;
2079 int chunkWritten = 0;
2081 while(n > 0 && chunkWritten >= 0)
2083 chunk = offset / YAFFS_BYTES_PER_CHUNK + 1;
2084 start = offset % YAFFS_BYTES_PER_CHUNK;
2087 // OK now check for the curveball where the start and end are in
2089 if( (start + n) < YAFFS_BYTES_PER_CHUNK)
2092 nToWriteBack = (start + n);
2096 nToCopy = YAFFS_BYTES_PER_CHUNK - start;
2097 nToWriteBack = YAFFS_BYTES_PER_CHUNK;
2100 if(nToCopy != YAFFS_BYTES_PER_CHUNK)
2102 // An incomplete start or end chunk (or maybe both start and end chunk)
2103 // Read into the local buffer then copy, then copy over and write back.
2105 yaffs_ReadChunkDataFromObject(in,chunk,localBuffer);
2107 memcpy(&localBuffer[start],buffer,nToCopy);
2109 chunkWritten = yaffs_WriteChunkDataToObject(in,chunk,localBuffer,nToWriteBack,0);
2111 T(("Write with readback to chunk %d %d\n",chunk,chunkWritten));
2116 // A full chunk. Write directly from the supplied buffer.
2117 chunkWritten = yaffs_WriteChunkDataToObject(in,chunk,buffer,YAFFS_BYTES_PER_CHUNK,0);
2118 T(("Write to chunk %d %d\n",chunk,chunkWritten));
2121 if(chunkWritten >= 0)
2131 // Update file object
2133 if(endOfWrite > in->variant.fileVariant.fileSize)
2135 in->variant.fileVariant.fileSize = endOfWrite;
2139 in->st_mtime = CURRENT_TIME;
2145 int yaffs_ResizeFile(yaffs_Object *in, int newSize)
2149 int oldFileSize = in->variant.fileVariant.fileSize;
2150 int sizeOfLastChunk = newSize % YAFFS_BYTES_PER_CHUNK;
2152 yaffs_Device *dev = in->myDev;
2154 __u8 localBuffer[YAFFS_BYTES_PER_CHUNK];
2156 if(in->variantType != YAFFS_OBJECT_TYPE_FILE)
2158 return yaffs_GetFileSize(in);
2161 if(newSize < oldFileSize)
2164 int lastDel = 1 + oldFileSize/YAFFS_BYTES_PER_CHUNK;
2166 int startDel = 1 + (newSize + YAFFS_BYTES_PER_CHUNK - 1)/
2167 YAFFS_BYTES_PER_CHUNK;
2169 for(i = startDel; i <= lastDel; i++)
2171 // NB this could be optimised somewhat,
2172 // eg. could retrieve the tags and write them without
2173 // using yaffs_DeleteChunk
2174 chunkId = yaffs_FindAndDeleteChunkInFile(in,i,NULL);
2175 if(chunkId < 0 || chunkId >= (dev->endBlock * 32))
2177 T(("Found daft chunkId %d for %d\n",chunkId,i));
2181 yaffs_DeleteChunk(dev,chunkId);
2186 if(sizeOfLastChunk != 0)
2188 int lastChunk = 1+ newSize/YAFFS_BYTES_PER_CHUNK;
2190 // Got to read and rewrite the last chunk with its new size.
2191 yaffs_ReadChunkDataFromObject(in,lastChunk,localBuffer);
2193 yaffs_WriteChunkDataToObject(in,lastChunk,localBuffer,sizeOfLastChunk,1);
2197 in->variant.fileVariant.fileSize = newSize;
2199 yaffs_PruneFileStructure(dev,&in->variant.fileVariant);
2211 loff_t yaffs_GetFileSize(yaffs_Object *obj)
2213 obj = yaffs_GetEquivalentObject(obj);
2215 switch(obj->variantType)
2217 case YAFFS_OBJECT_TYPE_FILE:
2218 return obj->variant.fileVariant.fileSize;
2219 case YAFFS_OBJECT_TYPE_SYMLINK:
2220 return strlen(obj->variant.symLinkVariant.alias);
2228 // yaffs_FlushFile() updates the file's
2231 int yaffs_FlushFile(yaffs_Object *in)
2236 retVal = yaffs_UpdateObjectHeader(in,NULL);
2248 static int yaffs_DoGenericObjectDeletion(yaffs_Object *in)
2250 yaffs_RemoveObjectFromDirectory(in);
2251 yaffs_DeleteChunk(in->myDev,in->chunkId);
2252 yaffs_FreeObject(in);
2257 // yaffs_DeleteFile deletes the whole file data
2258 // and the inode associated with the file.
2259 // It does not delete the links associated with the file.
2260 static int yaffs_DeleteFile(yaffs_Object *in)
2262 // Delete the file data & tnodes
2263 yaffs_ResizeFile(in,0);
2264 yaffs_FreeTnode(in->myDev,in->variant.fileVariant.top);
2266 return yaffs_DoGenericObjectDeletion(in);
2269 static int yaffs_DeleteDirectory(yaffs_Object *in)
2271 //First check that the directory is empty.
2272 if(list_empty(&in->variant.directoryVariant.children))
2274 return yaffs_DoGenericObjectDeletion(in);
2281 static int yaffs_DeleteSymLink(yaffs_Object *in)
2283 YFREE(in->variant.symLinkVariant.alias);
2285 return yaffs_DoGenericObjectDeletion(in);
2288 static int yaffs_DeleteHardLink(yaffs_Object *in)
2290 // remove this hardlink from the list assocaited with the equivalent
2292 list_del(&in->hardLinks);
2293 return yaffs_DoGenericObjectDeletion(in);
2297 static int yaffs_UnlinkWorker(yaffs_Object *obj)
2301 if(obj->variantType == YAFFS_OBJECT_TYPE_HARDLINK)
2303 return yaffs_DeleteHardLink(obj);
2305 else if(!list_empty(&obj->hardLinks))
2308 // Curve ball: We're unlinking an object that has a hardlink.
2309 // Therefore we can't really delete the object.
2310 // Instead, we do the following:
2311 // - Select a hardlink.
2312 // - Re-type a hardlink as the equivalent object and populate the fields, including the
2313 // objectId. Updating the object id is important so that all the hardlinks do not need
2315 // - Update the equivalet object pointers.
2316 // - Delete all object.
2319 struct list_head *i;
2322 yaffs_RemoveObjectFromDirectory(obj);
2326 hl = list_entry(obj->hardLinks.next, yaffs_Object,hardLinks);
2329 hl->st_mode = obj->st_mode;
2330 hl->st_uid = obj->st_uid;
2331 hl->st_gid = obj->st_gid;
2332 hl->st_atime = obj->st_atime;
2333 hl->st_mtime = obj->st_mtime;
2334 hl->st_ctime = obj->st_ctime;
2336 hl->variantType = obj->variantType;
2338 switch(hl->variantType)
2340 case YAFFS_OBJECT_TYPE_FILE:
2341 case YAFFS_OBJECT_TYPE_SYMLINK:
2342 // These types are OK to just copy across.
2343 hl->variant = obj->variant;
2345 case YAFFS_OBJECT_TYPE_DIRECTORY:
2347 list_add(&hl->variant.directoryVariant.children,
2348 &obj->variant.directoryVariant.children);
2349 list_del(&obj->variant.directoryVariant.children);
2351 // Now change all the directory children to point to the new parent.
2352 list_for_each(i,&hl->variant.directoryVariant.children)
2354 list_entry(i,yaffs_Object,siblings)->parent = hl;
2358 case YAFFS_OBJECT_TYPE_HARDLINK:
2359 case YAFFS_OBJECT_TYPE_UNKNOWN:
2360 // Should not be either of these types.
2363 // Now fix up the hardlink chain
2364 list_del(&obj->hardLinks);
2366 list_for_each(i,&hl->hardLinks)
2368 list_entry(i,yaffs_Object,hardLinks)->variant.hardLinkVariant.equivalentObject = hl;
2369 list_entry(i,yaffs_Object,hardLinks)->variant.hardLinkVariant.equivalentObjectId = hl->objectId;
2372 // Now fix up the hash links.
2373 yaffs_UnhashObject(hl);
2374 hl->objectId = obj->objectId;
2375 yaffs_HashObject(hl);
2377 // Update the hardlink which has become an object
2378 yaffs_UpdateObjectHeader(hl,NULL);
2380 // Finally throw away the deleted object
2381 yaffs_DeleteChunk(obj->myDev,obj->chunkId);
2382 yaffs_FreeObject(obj);
2386 // Curve ball: We're unlinking an object that has a hardlink.
2388 // This problem arises because we are not strictly following
2389 // The Linux link/inode model.
2391 // We can't really delete the object.
2392 // Instead, we do the following:
2393 // - Select a hardlink.
2394 // - Unhook it from the hard links
2395 // - Unhook it from its parent directory (so that the rename can work)
2396 // - Rename the object to the hardlink's name.
2397 // - Delete the hardlink
2402 char name[YAFFS_MAX_NAME_LENGTH+1];
2404 hl = list_entry(obj->hardLinks.next,yaffs_Object,hardLinks);
2405 list_del_init(&hl->hardLinks);
2406 list_del_init(&hl->siblings);
2408 yaffs_GetObjectName(hl,name,YAFFS_MAX_NAME_LENGTH+1);
2410 retVal = yaffs_ChangeObjectName(obj, hl->parent, name);
2411 if(retVal == YAFFS_OK)
2413 retVal = yaffs_DoGenericObjectDeletion(hl);
2423 switch(obj->variantType)
2425 case YAFFS_OBJECT_TYPE_FILE:
2426 return yaffs_DeleteFile(obj);
2428 case YAFFS_OBJECT_TYPE_DIRECTORY:
2429 return yaffs_DeleteDirectory(obj);
2431 case YAFFS_OBJECT_TYPE_SYMLINK:
2432 return yaffs_DeleteSymLink(obj);
2434 case YAFFS_OBJECT_TYPE_HARDLINK:
2435 case YAFFS_OBJECT_TYPE_UNKNOWN:
2442 int yaffs_Unlink(yaffs_Object *dir, const char *name)
2446 obj = yaffs_FindObjectByName(dir,name);
2448 if(obj && obj->unlinkAllowed)
2450 return yaffs_UnlinkWorker(obj);
2457 //////////////// Initialisation Scanning /////////////////
2460 static int yaffs_Scan(yaffs_Device *dev)
2469 yaffs_BlockState state;
2470 yaffs_Object *hardList = NULL;
2475 yaffs_ObjectHeader *oh;
2477 yaffs_Object *parent;
2479 __u8 chunkData[YAFFS_BYTES_PER_CHUNK];
2481 for(blk = dev->startBlock; blk <= dev->endBlock; blk++)
2486 state = YAFFS_BLOCK_STATE_UNKNOWN;
2488 for(c = 0; c < YAFFS_CHUNKS_PER_BLOCK &&
2489 state == YAFFS_BLOCK_STATE_UNKNOWN; c++)
2491 // Read the spare area and decide what to do
2492 chunk = blk * YAFFS_CHUNKS_PER_BLOCK + c;
2493 yaffs_ReadChunkFromNAND(dev,chunk,NULL,&spare);
2496 // Is this a valid block?
2497 if(yaffs_countBits[spare.blockStatus] >= 7)
2499 // This block looks ok, now what's in this chunk?
2500 yaffs_GetTagsFromSpare(&spare,&tags);
2502 if(tags.objectId == YAFFS_UNUSED_OBJECT_ID)
2504 // An unassigned chunk in the block
2505 // This means that either the block is empty or
2506 // this is the one being allocated from
2510 // the block is unused
2511 state = YAFFS_BLOCK_STATE_EMPTY;
2512 dev->nErasedBlocks++;
2516 // this is the block being allocated from
2517 T((" allocating %d %d\n",blk,c));
2518 state = YAFFS_BLOCK_STATE_ALLOCATING;
2519 dev->allocationBlock = blk;
2520 dev->allocationPage = c;
2523 dev->nFreeChunks += (YAFFS_CHUNKS_PER_BLOCK - c);
2525 else if(tags.objectId == 0)
2529 dev->nFreeChunks ++;
2530 T((" %d %d deleted\n",blk,c));
2532 else if(tags.chunkId > 0)
2536 pageBits |= ( 1 <<c);
2537 in = yaffs_FindOrCreateObjectByNumber(dev,tags.objectId,YAFFS_OBJECT_TYPE_FILE);
2538 // todo check for a clash (two data chunks with
2539 // the same chunkId).
2540 yaffs_PutChunkIntoFile(in,tags.chunkId,chunk);
2541 T((" %d %d data %d %d\n",blk,c,tags.objectId,tags.chunkId));
2545 // chunkId == 0, so it is an ObjectHeader.
2547 pageBits |= ( 1 <<c);
2548 yaffs_ReadChunkFromNAND(dev,chunk,chunkData,NULL);
2549 oh = (yaffs_ObjectHeader *)chunkData;
2551 in = yaffs_FindOrCreateObjectByNumber(dev,tags.objectId,oh->type);
2554 // todo we have already filled this one. We have
2555 // a duplicate. Need to fix
2558 // we don't have a duplicate...
2561 in->variantType = oh->type;
2563 in->st_mode = oh->st_mode;
2564 in->st_uid = oh->st_uid;
2565 in->st_gid = oh->st_gid;
2566 in->st_atime = oh->st_atime;
2567 in->st_mtime = oh->st_mtime;
2568 in->st_ctime = oh->st_ctime;
2569 in->chunkId = chunk;
2574 // directory stuff...
2575 // hook up to parent
2577 parent = yaffs_FindOrCreateObjectByNumber(dev,oh->parentObjectId,YAFFS_OBJECT_TYPE_DIRECTORY);
2578 if(parent->variantType == YAFFS_OBJECT_TYPE_UNKNOWN)
2580 // Set up as a directory
2581 parent->variantType = YAFFS_OBJECT_TYPE_DIRECTORY;
2582 INIT_LIST_HEAD(&parent->variant.directoryVariant.children);
2584 else if(parent->variantType != YAFFS_OBJECT_TYPE_DIRECTORY)
2586 // Hoosterman, another problem....
2587 // We're trying to use a non-directory as a directory
2591 yaffs_AddObjectToDirectory(parent,in);
2593 // Note re hardlinks.
2594 // Since we might scan a hardlink before its equivalent object is scanned
2595 // we put them all in a list.
2596 // After scanning is complete, we should have all the objects, so we run through this
2597 // list and fix up all the chains.
2599 switch(in->variantType)
2601 case YAFFS_OBJECT_TYPE_UNKNOWN: // Todo got a problem
2603 case YAFFS_OBJECT_TYPE_FILE:
2604 in->variant.fileVariant.fileSize = oh->fileSize;
2606 case YAFFS_OBJECT_TYPE_HARDLINK:
2607 in->variant.hardLinkVariant.equivalentObjectId = oh->equivalentObjectId;
2608 (yaffs_Object *)(in->hardLinks.next) = hardList;
2611 case YAFFS_OBJECT_TYPE_DIRECTORY: // Do nothing
2613 case YAFFS_OBJECT_TYPE_SYMLINK: // Do nothing
2614 in->variant.symLinkVariant.alias = yaffs_CloneString(oh->alias);
2617 T((" %d %d header %d \"%s\" type %d\n",blk,c,tags.objectId,oh->name,in->variantType));
2623 state = YAFFS_BLOCK_STATE_DEAD;
2627 if(state == YAFFS_BLOCK_STATE_UNKNOWN)
2629 // If we got this far, then the block is fully allocated.
2630 // ie. Full or Dirty
2631 state = (inuse) ? YAFFS_BLOCK_STATE_FULL : YAFFS_BLOCK_STATE_DIRTY;
2635 dev->blockInfo[blk].pageBits = pageBits;
2636 dev->blockInfo[blk].pagesInUse = inuse;
2637 dev->blockInfo[blk].blockState = state;
2641 // Todo fix up the hard link chains
2645 hardList = (yaffs_Object *)(hardList->hardLinks.next);
2647 in = yaffs_FindObjectByNumber(dev,hl->variant.hardLinkVariant.equivalentObjectId);
2651 hl->variant.hardLinkVariant.equivalentObject=in;
2652 list_add(&hl->hardLinks,&in->hardLinks);
2656 //Todo Need to report this better.
2657 hl->variant.hardLinkVariant.equivalentObject=NULL;
2658 INIT_LIST_HEAD(&hl->hardLinks);
2670 ////////////////////////// Directory Functions /////////////////////////
2673 static void yaffs_AddObjectToDirectory(yaffs_Object *directory, yaffs_Object *obj)
2676 if(obj->siblings.prev == NULL)
2679 INIT_LIST_HEAD(&obj->siblings);
2682 else if(!list_empty(&obj->siblings))
2684 // If it is holed up somewhere else, un hook it
2685 list_del_init(&obj->siblings);
2688 list_add(&obj->siblings,&directory->variant.directoryVariant.children);
2689 obj->parent = directory;
2692 static void yaffs_RemoveObjectFromDirectory(yaffs_Object *obj)
2694 list_del_init(&obj->siblings);
2698 yaffs_Object *yaffs_FindObjectByName(yaffs_Object *directory,const char *name)
2702 struct list_head *i;
2703 __u8 buffer[YAFFS_BYTES_PER_CHUNK];
2704 yaffs_ObjectHeader *oh = (yaffs_ObjectHeader *)buffer;
2708 sum = yaffs_CalcNameSum(name);
2710 list_for_each(i,&directory->variant.directoryVariant.children)
2712 l = list_entry(i, yaffs_Object,siblings);
2714 // Special case for lost-n-found
2715 if(l->objectId == YAFFS_OBJECTID_LOSTNFOUND)
2717 if(strcmp(name,YAFFS_LOSTNFOUND_NAME) == 0)
2722 else if(l->sum == sum)
2725 yaffs_ReadChunkFromNAND(l->myDev,l->chunkId,buffer,NULL);
2726 if(strcmp(name,oh->name) == 0)
2739 int yaffs_ApplyToDirectoryChildren(yaffs_Object *theDir,int (*fn)(yaffs_Object *))
2741 struct list_head *i;
2745 list_for_each(i,&theDir->variant.directoryVariant.children)
2747 l = list_entry(i, yaffs_Object,siblings);
2759 // GetEquivalentObject dereferences any hard links to get to the
2762 static yaffs_Object *yaffs_GetEquivalentObject(yaffs_Object *obj)
2764 if(obj && obj->variantType == YAFFS_OBJECT_TYPE_HARDLINK)
2766 // We want the object id of the equivalent object, not this one
2767 obj = obj->variant.hardLinkVariant.equivalentObject;
2773 int yaffs_GetObjectName(yaffs_Object *obj,char *name,int buffSize)
2775 memset(name,0,buffSize);
2777 if(obj->objectId == YAFFS_OBJECTID_LOSTNFOUND)
2779 strncpy(name,YAFFS_LOSTNFOUND_NAME,buffSize - 1);
2783 __u8 buffer[YAFFS_BYTES_PER_CHUNK];
2784 yaffs_ObjectHeader *oh = (yaffs_ObjectHeader *)buffer;
2786 memset(buffer,0,YAFFS_BYTES_PER_CHUNK);
2788 if(obj->chunkId >= 0)
2790 yaffs_ReadChunkFromNAND(obj->myDev,obj->chunkId,buffer,NULL);
2792 strncpy(name,oh->name,buffSize - 1);
2795 return strlen(name);
2798 int yaffs_GetObjectFileLength(yaffs_Object *obj)
2801 // Dereference any hard linking
2802 obj = yaffs_GetEquivalentObject(obj);
2804 if(obj->variantType == YAFFS_OBJECT_TYPE_FILE)
2806 return obj->variant.fileVariant.fileSize;
2808 if(obj->variantType == YAFFS_OBJECT_TYPE_SYMLINK)
2810 return strlen(obj->variant.symLinkVariant.alias);
2814 // Only a directory should drop through to here
2815 return YAFFS_BYTES_PER_CHUNK;
2819 int yaffs_GetObjectLinkCount(yaffs_Object *obj)
2821 int count = 1; // the object itself
2822 struct list_head *i;
2824 list_for_each(i,&obj->hardLinks)
2833 int yaffs_GetObjectInode(yaffs_Object *obj)
2835 obj = yaffs_GetEquivalentObject(obj);
2837 return obj->objectId;
2840 unsigned yaffs_GetObjectType(yaffs_Object *obj)
2842 obj = yaffs_GetEquivalentObject(obj);
2844 switch(obj->variantType)
2846 case YAFFS_OBJECT_TYPE_FILE: return DT_REG; break;
2847 case YAFFS_OBJECT_TYPE_DIRECTORY: return DT_DIR; break;
2848 case YAFFS_OBJECT_TYPE_SYMLINK: return DT_LNK; break;
2849 case YAFFS_OBJECT_TYPE_HARDLINK: return DT_REG; break;
2850 default: return DT_REG; break;
2854 char *yaffs_GetSymlinkAlias(yaffs_Object *obj)
2856 obj = yaffs_GetEquivalentObject(obj);
2857 if(obj->variantType == YAFFS_OBJECT_TYPE_SYMLINK)
2859 return yaffs_CloneString(obj->variant.symLinkVariant.alias);
2863 return yaffs_CloneString("");
2868 int yaffs_SetAttributes(yaffs_Object *obj, struct iattr *attr)
2870 unsigned int valid = attr->ia_valid;
2872 if(valid & ATTR_MODE) obj->st_mode = attr->ia_mode;
2873 if(valid & ATTR_UID) obj->st_uid = attr->ia_uid;
2874 if(valid & ATTR_GID) obj->st_gid = attr->ia_gid;
2876 if(valid & ATTR_ATIME) obj->st_atime = attr->ia_atime;
2877 if(valid & ATTR_CTIME) obj->st_ctime = attr->ia_ctime;
2878 if(valid & ATTR_MTIME) obj->st_mtime = attr->ia_mtime;
2880 if(valid & ATTR_SIZE) yaffs_ResizeFile(obj,attr->ia_size);
2882 yaffs_UpdateObjectHeader(obj,NULL);
2887 int yaffs_GetAttributes(yaffs_Object *obj, struct iattr *attr)
2889 unsigned int valid = 0;
2891 attr->ia_mode = obj->st_mode; valid |= ATTR_MODE;
2892 attr->ia_uid = obj->st_uid; valid |= ATTR_UID;
2893 attr->ia_gid = obj->st_gid; valid |= ATTR_GID;
2895 attr->ia_atime = obj->st_atime; valid |= ATTR_ATIME;
2896 attr->ia_ctime = obj->st_ctime; valid |= ATTR_CTIME;
2897 attr->ia_mtime = obj->st_mtime; valid |= ATTR_MTIME;
2899 attr->ia_size = yaffs_GetFileSize(obj); valid |= ATTR_SIZE;
2901 attr->ia_valid = valid;
2909 int yaffs_DumpObject(yaffs_Object *obj)
2911 __u8 buffer[YAFFS_BYTES_PER_CHUNK];
2913 // yaffs_ObjectHeader *oh = (yaffs_ObjectHeader *)buffer;
2915 memset(buffer,0,YAFFS_BYTES_PER_CHUNK);
2917 if(obj->chunkId >= 0)
2919 yaffs_ReadChunkFromNAND(obj->myDev,obj->chunkId,buffer,NULL);
2922 yaffs_GetObjectName(obj,name,256);
2924 YPRINTF(("Object %d \"%s\"\n dirty %d valid %d serial %d sum %d chunk %d type %d size %d\n",
2925 yaffs_GetObjectInode(obj), name, obj->dirty, obj->valid, obj->serial,
2926 obj->sum, obj->chunkId, yaffs_GetObjectType(obj), yaffs_GetObjectFileLength(obj)));
2929 YPRINTF(("Object %d \"%s\"\n dirty %d valid %d serial %d sum %d chunk %d\n",
2930 obj->objectId, oh->name, obj->dirty, obj->valid, obj->serial,
2931 obj->sum, obj->chunkId));
2932 switch(obj->variantType)
2934 case YAFFS_OBJECT_TYPE_FILE:
2935 YPRINTF((" FILE length %d\n",obj->variant.fileVariant.fileSize));
2937 case YAFFS_OBJECT_TYPE_DIRECTORY:
2938 YPRINTF((" DIRECTORY\n"));
2940 case YAFFS_OBJECT_TYPE_HARDLINK: //todo
2941 case YAFFS_OBJECT_TYPE_SYMLINK:
2942 case YAFFS_OBJECT_TYPE_UNKNOWN:
2951 ///////////////////////// Initialisation code ///////////////////////////
2955 int yaffs_GutsInitialise(yaffs_Device *dev)
2963 if(!yaffs_CheckStructures())
2969 // OK now calculate a few things for the device
2970 // Calculate chunkGroupBits.
2971 // If there are 64k or less chunks then this is 1
2972 // Else it is log2(nChunks) - 16
2974 x = nChunks = YAFFS_CHUNKS_PER_BLOCK * dev->nBlocks;
2976 for(bits = 0, x = nChunks; (x & 1) == 0; bits++)
2984 YPRINTF(("nBlocks should be a power of 2 but is %u\n",
2991 dev->chunkGroupBits = 0;
2992 dev->chunkGroupSize = 1;
2996 dev->chunkGroupBits = bits - 16;
2997 dev->chunkGroupSize = nChunks/0x10000;
3000 // More device initialisation
3001 dev->garbageCollectionRequired = 0;
3002 dev->currentDirtyChecker = 0;
3004 yaffs_InitialiseBlocks(dev);
3006 yaffs_InitialiseTnodes(dev);
3008 yaffs_InitialiseObjects(dev);
3011 // Initialise the root and lost and found directories
3012 dev->lostNFoundDir = dev->rootDir = NULL;
3013 dev->rootDir = yaffs_CreateFakeDirectory(dev,YAFFS_OBJECTID_ROOT,YAFFS_ROOT_MODE | S_IFDIR);
3014 dev->lostNFoundDir = yaffs_CreateFakeDirectory(dev,YAFFS_OBJECTID_LOSTNFOUND,YAFFS_ROOT_MODE | S_IFDIR);
3015 yaffs_AddObjectToDirectory(dev->rootDir,dev->lostNFoundDir);
3017 // Now scan the flash.
3025 void yaffs_Deinitialise(yaffs_Device *dev)
3027 yaffs_DeinitialiseBlocks(dev);
3028 yaffs_DeinitialiseTnodes(dev);
3029 yaffs_DeinitialiseObjects(dev);
3033 int yaffs_GetNumberOfFreeChunks(yaffs_Device *dev)
3035 int nFree = dev->nFreeChunks - (YAFFS_CHUNKS_PER_BLOCK * YAFFS_RESERVED_BLOCKS);
3037 return (nFree < 0) ? 0 : nFree;
3042 /////////////////// YAFFS test code //////////////////////////////////
3044 #define yaffs_CheckStruct(structure,syze, name) \
3045 if(sizeof(structure) != syze) \
3046 { YPRINTF(("%s should be %d but is %d\n",name,syze,sizeof(structure))); \
3047 return YAFFS_FAIL; \
3051 static int yaffs_CheckStructures(void)
3053 yaffs_CheckStruct(yaffs_Tags,8,"yaffs_Tags")
3054 yaffs_CheckStruct(yaffs_TagsUnion,8,"yaffs_TagsUnion")
3055 yaffs_CheckStruct(yaffs_Spare,16,"yaffs_Spare")
3056 yaffs_CheckStruct(yaffs_Tnode,2* YAFFS_NTNODES_LEVEL0,"yaffs_Tnode")
3057 yaffs_CheckStruct(yaffs_ObjectHeader,512,"yaffs_ObjectHeader")
3063 void yaffs_GutsTest(yaffs_Device *dev)
3066 if(yaffs_CheckStructures() != YAFFS_OK)
3068 YPRINTF(("One or more structures malformed-- aborting\n"));
3072 YPRINTF(("Structures OK\n"));
3075 yaffs_TnodeTest(dev);
3076 yaffs_ObjectTest(dev);