Mercurial > yaffs-ecoscentric
comparison packages/fs/yaffs/current/src/yaffs_guts.c @ 353:fa7270d25c51
Merge from upstream
| author | Ross Younger <wry@ecoscentric.com> |
|---|---|
| date | Tue, 17 Nov 2009 10:49:51 +0000 |
| parents | yaffs_guts.c@cc31d3d1ea89 yaffs_guts.c@1c56b1df53d8 |
| children | 68aafa1d2927 |
comparison
equal
deleted
inserted
replaced
| 339:73b6efce8c58 | 353:fa7270d25c51 |
|---|---|
| 114 static __u32 yaffs_GetChunkGroupBase(yaffs_Device *dev, yaffs_Tnode *tn, | 114 static __u32 yaffs_GetChunkGroupBase(yaffs_Device *dev, yaffs_Tnode *tn, |
| 115 unsigned pos); | 115 unsigned pos); |
| 116 static yaffs_Tnode *yaffs_FindLevel0Tnode(yaffs_Device *dev, | 116 static yaffs_Tnode *yaffs_FindLevel0Tnode(yaffs_Device *dev, |
| 117 yaffs_FileStructure *fStruct, | 117 yaffs_FileStructure *fStruct, |
| 118 __u32 chunkId); | 118 __u32 chunkId); |
| 119 | |
| 120 | 119 |
| 121 /* Function to calculate chunk and offset */ | 120 /* Function to calculate chunk and offset */ |
| 122 | 121 |
| 123 static void yaffs_AddrToChunk(yaffs_Device *dev, loff_t addr, int *chunkOut, | 122 static void yaffs_AddrToChunk(yaffs_Device *dev, loff_t addr, int *chunkOut, |
| 124 __u32 *offsetOut) | 123 __u32 *offsetOut) |
| 1326 dev->nFreeTnodes = 0; | 1325 dev->nFreeTnodes = 0; |
| 1327 dev->nTnodesCreated = 0; | 1326 dev->nTnodesCreated = 0; |
| 1328 } | 1327 } |
| 1329 | 1328 |
| 1330 | 1329 |
| 1331 void yaffs_PutLevel0Tnode(yaffs_Device *dev, yaffs_Tnode *tn, unsigned pos, | 1330 void yaffs_LoadLevel0Tnode(yaffs_Device *dev, yaffs_Tnode *tn, unsigned pos, |
| 1332 unsigned val) | 1331 unsigned val) |
| 1333 { | 1332 { |
| 1334 __u32 *map = (__u32 *)tn; | 1333 __u32 *map = (__u32 *)tn; |
| 1335 __u32 bitInMap; | 1334 __u32 bitInMap; |
| 1336 __u32 bitInWord; | 1335 __u32 bitInWord; |
| 1484 tn = yaffs_GetTnode(dev); | 1483 tn = yaffs_GetTnode(dev); |
| 1485 | 1484 |
| 1486 if (tn) { | 1485 if (tn) { |
| 1487 tn->internal[0] = fStruct->top; | 1486 tn->internal[0] = fStruct->top; |
| 1488 fStruct->top = tn; | 1487 fStruct->top = tn; |
| 1488 fStruct->topLevel++; | |
| 1489 } else { | 1489 } else { |
| 1490 T(YAFFS_TRACE_ERROR, | 1490 T(YAFFS_TRACE_ERROR, |
| 1491 (TSTR("yaffs: no more tnodes" TENDSTR))); | 1491 (TSTR("yaffs: no more tnodes" TENDSTR))); |
| 1492 return NULL; | |
| 1492 } | 1493 } |
| 1493 } | 1494 } |
| 1494 | |
| 1495 fStruct->topLevel = requiredTallness; | |
| 1496 } | 1495 } |
| 1497 | 1496 |
| 1498 /* Traverse down to level 0, adding anything we need */ | 1497 /* Traverse down to level 0, adding anything we need */ |
| 1499 | 1498 |
| 1500 l = fStruct->topLevel; | 1499 l = fStruct->topLevel; |
| 1509 | 1508 |
| 1510 | 1509 |
| 1511 if ((l > 1) && !tn->internal[x]) { | 1510 if ((l > 1) && !tn->internal[x]) { |
| 1512 /* Add missing non-level-zero tnode */ | 1511 /* Add missing non-level-zero tnode */ |
| 1513 tn->internal[x] = yaffs_GetTnode(dev); | 1512 tn->internal[x] = yaffs_GetTnode(dev); |
| 1513 if(!tn->internal[x]) | |
| 1514 return NULL; | |
| 1514 | 1515 |
| 1515 } else if (l == 1) { | 1516 } else if (l == 1) { |
| 1516 /* Looking from level 1 at level 0 */ | 1517 /* Looking from level 1 at level 0 */ |
| 1517 if (passedTn) { | 1518 if (passedTn) { |
| 1518 /* If we already have one, then release it.*/ | 1519 /* If we already have one, then release it.*/ |
| 1521 tn->internal[x] = passedTn; | 1522 tn->internal[x] = passedTn; |
| 1522 | 1523 |
| 1523 } else if (!tn->internal[x]) { | 1524 } else if (!tn->internal[x]) { |
| 1524 /* Don't have one, none passed in */ | 1525 /* Don't have one, none passed in */ |
| 1525 tn->internal[x] = yaffs_GetTnode(dev); | 1526 tn->internal[x] = yaffs_GetTnode(dev); |
| 1527 if(!tn->internal[x]) | |
| 1528 return NULL; | |
| 1526 } | 1529 } |
| 1527 } | 1530 } |
| 1528 | 1531 |
| 1529 tn = tn->internal[x]; | 1532 tn = tn->internal[x]; |
| 1530 l--; | 1533 l--; |
| 1644 hitLimit = 1; | 1647 hitLimit = 1; |
| 1645 } | 1648 } |
| 1646 | 1649 |
| 1647 } | 1650 } |
| 1648 | 1651 |
| 1649 yaffs_PutLevel0Tnode(dev, tn, i, 0); | 1652 yaffs_LoadLevel0Tnode(dev, tn, i, 0); |
| 1650 } | 1653 } |
| 1651 | 1654 |
| 1652 } | 1655 } |
| 1653 return (i < 0) ? 1 : 0; | 1656 return (i < 0) ? 1 : 0; |
| 1654 | 1657 |
| 1721 /* Note this does not find the real chunk, only the chunk group. | 1724 /* Note this does not find the real chunk, only the chunk group. |
| 1722 * We make an assumption that a chunk group is not larger than | 1725 * We make an assumption that a chunk group is not larger than |
| 1723 * a block. | 1726 * a block. |
| 1724 */ | 1727 */ |
| 1725 yaffs_SoftDeleteChunk(dev, theChunk); | 1728 yaffs_SoftDeleteChunk(dev, theChunk); |
| 1726 yaffs_PutLevel0Tnode(dev, tn, i, 0); | 1729 yaffs_LoadLevel0Tnode(dev, tn, i, 0); |
| 1727 } | 1730 } |
| 1728 | 1731 |
| 1729 } | 1732 } |
| 1730 return 1; | 1733 return 1; |
| 1731 | 1734 |
| 2172 yaffs_Tnode *tn = NULL; | 2175 yaffs_Tnode *tn = NULL; |
| 2173 | 2176 |
| 2174 if (number < 0) | 2177 if (number < 0) |
| 2175 number = yaffs_CreateNewObjectNumber(dev); | 2178 number = yaffs_CreateNewObjectNumber(dev); |
| 2176 | 2179 |
| 2177 theObject = yaffs_AllocateEmptyObject(dev); | |
| 2178 if (!theObject) | |
| 2179 return NULL; | |
| 2180 | |
| 2181 if (type == YAFFS_OBJECT_TYPE_FILE) { | 2180 if (type == YAFFS_OBJECT_TYPE_FILE) { |
| 2182 tn = yaffs_GetTnode(dev); | 2181 tn = yaffs_GetTnode(dev); |
| 2183 if (!tn) { | 2182 if (!tn) |
| 2184 yaffs_DoGenericObjectDeletion(theObject); | |
| 2185 return NULL; | 2183 return NULL; |
| 2186 } | 2184 } |
| 2187 } | 2185 |
| 2186 theObject = yaffs_AllocateEmptyObject(dev); | |
| 2187 if (!theObject){ | |
| 2188 if(tn) | |
| 2189 yaffs_FreeTnode(dev,tn); | |
| 2190 return NULL; | |
| 2191 } | |
| 2192 | |
| 2188 | 2193 |
| 2189 if (theObject) { | 2194 if (theObject) { |
| 2190 theObject->fake = 0; | 2195 theObject->fake = 0; |
| 2191 theObject->renameAllowed = 1; | 2196 theObject->renameAllowed = 1; |
| 2192 theObject->unlinkAllowed = 1; | 2197 theObject->unlinkAllowed = 1; |
| 2285 | 2290 |
| 2286 /* Check if the entry exists. If it does then fail the call since we don't want a dup.*/ | 2291 /* Check if the entry exists. If it does then fail the call since we don't want a dup.*/ |
| 2287 if (yaffs_FindObjectByName(parent, name)) | 2292 if (yaffs_FindObjectByName(parent, name)) |
| 2288 return NULL; | 2293 return NULL; |
| 2289 | 2294 |
| 2290 in = yaffs_CreateNewObject(dev, -1, type); | |
| 2291 | |
| 2292 if (!in) | |
| 2293 return YAFFS_FAIL; | |
| 2294 | |
| 2295 if (type == YAFFS_OBJECT_TYPE_SYMLINK) { | 2295 if (type == YAFFS_OBJECT_TYPE_SYMLINK) { |
| 2296 str = yaffs_CloneString(aliasString); | 2296 str = yaffs_CloneString(aliasString); |
| 2297 if (!str) { | 2297 if (!str) |
| 2298 yaffs_DoGenericObjectDeletion(in); | |
| 2299 return NULL; | 2298 return NULL; |
| 2300 } | 2299 } |
| 2301 } | 2300 |
| 2301 in = yaffs_CreateNewObject(dev, -1, type); | |
| 2302 | |
| 2303 if (!in){ | |
| 2304 if(str) | |
| 2305 YFREE(str); | |
| 2306 return NULL; | |
| 2307 } | |
| 2308 | |
| 2302 | 2309 |
| 2303 | 2310 |
| 2304 | 2311 |
| 2305 if (in) { | 2312 if (in) { |
| 2306 in->hdrChunk = 0; | 2313 in->hdrChunk = 0; |
| 3359 yaffs_FindChunkInGroup(dev, theChunk, tags, in->objectId, | 3366 yaffs_FindChunkInGroup(dev, theChunk, tags, in->objectId, |
| 3360 chunkInInode); | 3367 chunkInInode); |
| 3361 | 3368 |
| 3362 /* Delete the entry in the filestructure (if found) */ | 3369 /* Delete the entry in the filestructure (if found) */ |
| 3363 if (retVal != -1) | 3370 if (retVal != -1) |
| 3364 yaffs_PutLevel0Tnode(dev, tn, chunkInInode, 0); | 3371 yaffs_LoadLevel0Tnode(dev, tn, chunkInInode, 0); |
| 3365 } | 3372 } |
| 3366 | 3373 |
| 3367 return retVal; | 3374 return retVal; |
| 3368 } | 3375 } |
| 3369 | 3376 |
| 3429 int chunkInNAND, int inScan) | 3436 int chunkInNAND, int inScan) |
| 3430 { | 3437 { |
| 3431 /* NB inScan is zero unless scanning. | 3438 /* NB inScan is zero unless scanning. |
| 3432 * For forward scanning, inScan is > 0; | 3439 * For forward scanning, inScan is > 0; |
| 3433 * for backward scanning inScan is < 0 | 3440 * for backward scanning inScan is < 0 |
| 3441 * | |
| 3442 * chunkInNAND = 0 is a dummy insert to make sure the tnodes are there. | |
| 3434 */ | 3443 */ |
| 3435 | 3444 |
| 3436 yaffs_Tnode *tn; | 3445 yaffs_Tnode *tn; |
| 3437 yaffs_Device *dev = in->myDev; | 3446 yaffs_Device *dev = in->myDev; |
| 3438 int existingChunk; | 3447 int existingChunk; |
| 3460 &in->variant.fileVariant, | 3469 &in->variant.fileVariant, |
| 3461 chunkInInode, | 3470 chunkInInode, |
| 3462 NULL); | 3471 NULL); |
| 3463 if (!tn) | 3472 if (!tn) |
| 3464 return YAFFS_FAIL; | 3473 return YAFFS_FAIL; |
| 3474 | |
| 3475 if(!chunkInNAND) | |
| 3476 /* Dummy insert, bail now */ | |
| 3477 return YAFFS_OK; | |
| 3478 | |
| 3465 | 3479 |
| 3466 existingChunk = yaffs_GetChunkGroupBase(dev, tn, chunkInInode); | 3480 existingChunk = yaffs_GetChunkGroupBase(dev, tn, chunkInInode); |
| 3467 | 3481 |
| 3468 if (inScan != 0) { | 3482 if (inScan != 0) { |
| 3469 /* If we're scanning then we need to test for duplicates | 3483 /* If we're scanning then we need to test for duplicates |
| 3541 } | 3555 } |
| 3542 | 3556 |
| 3543 if (existingChunk == 0) | 3557 if (existingChunk == 0) |
| 3544 in->nDataChunks++; | 3558 in->nDataChunks++; |
| 3545 | 3559 |
| 3546 yaffs_PutLevel0Tnode(dev, tn, chunkInInode, chunkInNAND); | 3560 yaffs_LoadLevel0Tnode(dev, tn, chunkInInode, chunkInNAND); |
| 3547 | 3561 |
| 3548 return YAFFS_OK; | 3562 return YAFFS_OK; |
| 3549 } | 3563 } |
| 3550 | 3564 |
| 3551 static int yaffs_ReadChunkDataFromObject(yaffs_Object *in, int chunkInInode, | 3565 static int yaffs_ReadChunkDataFromObject(yaffs_Object *in, int chunkInInode, |
| 3664 T(YAFFS_TRACE_ERROR, | 3678 T(YAFFS_TRACE_ERROR, |
| 3665 (TSTR("Writing %d bytes to chunk!!!!!!!!!" TENDSTR), nBytes)); | 3679 (TSTR("Writing %d bytes to chunk!!!!!!!!!" TENDSTR), nBytes)); |
| 3666 YBUG(); | 3680 YBUG(); |
| 3667 } | 3681 } |
| 3668 | 3682 |
| 3683 /* | |
| 3684 * If there isn't already a chunk there then do a dummy | |
| 3685 * insert to make sue we have the desired tnode structure. | |
| 3686 */ | |
| 3687 if(prevChunkId < 1 && | |
| 3688 yaffs_PutChunkIntoFile(in, chunkInInode, 0, 0) != YAFFS_OK) | |
| 3689 return -1; | |
| 3690 | |
| 3669 newChunkId = | 3691 newChunkId = |
| 3670 yaffs_WriteNewChunkWithTagsToNAND(dev, buffer, &newTags, | 3692 yaffs_WriteNewChunkWithTagsToNAND(dev, buffer, &newTags, |
| 3671 useReserve); | 3693 useReserve); |
| 3672 | 3694 |
| 3673 if (newChunkId >= 0) { | 3695 if (newChunkId > 0) { |
| 3674 yaffs_PutChunkIntoFile(in, chunkInInode, newChunkId, 0); | 3696 yaffs_PutChunkIntoFile(in, chunkInInode, newChunkId, 0); |
| 3675 | 3697 |
| 3676 if (prevChunkId > 0) | 3698 if (prevChunkId > 0) |
| 3677 yaffs_DeleteChunk(dev, prevChunkId, 1, __LINE__); | 3699 yaffs_DeleteChunk(dev, prevChunkId, 1, __LINE__); |
| 3678 | 3700 |
| 5486 yaffs_DeleteObject(l); | 5508 yaffs_DeleteObject(l); |
| 5487 } | 5509 } |
| 5488 } | 5510 } |
| 5489 | 5511 |
| 5490 } | 5512 } |
| 5491 #endif | 5513 |
| 5492 | 5514 /* |
| 5493 #ifndef CONFIG_YAFFS_NO_YAFFS1 | 5515 * This code iterates through all the objects making sure that they are rooted. |
| 5516 * Any unrooted objects are re-rooted in lost+found. | |
| 5517 * An object needs to be in one of: | |
| 5518 * - Directly under deleted, unlinked | |
| 5519 * - Directly or indirectly under root. | |
| 5520 * | |
| 5521 * Note: | |
| 5522 * This code assumes that we don't ever change the current relationships between | |
| 5523 * directories: | |
| 5524 * rootDir->parent == unlinkedDir->parent == deletedDir->parent == NULL | |
| 5525 * lostNfound->parent == rootDir | |
| 5526 * | |
| 5527 * This fixes the problem where directories might have inadvertently been deleted | |
| 5528 * leaving the object "hanging" without being rooted in the directory tree. | |
| 5529 */ | |
| 5530 | |
| 5531 static int yaffs_HasNULLParent(yaffs_Device *dev, yaffs_Object *obj) | |
| 5532 { | |
| 5533 return (obj == dev->deletedDir || | |
| 5534 obj == dev->unlinkedDir|| | |
| 5535 obj == dev->rootDir); | |
| 5536 } | |
| 5537 | |
| 5538 static void yaffs_FixHangingObjects(yaffs_Device *dev) | |
| 5539 { | |
| 5540 yaffs_Object *obj; | |
| 5541 yaffs_Object *parent; | |
| 5542 int i; | |
| 5543 struct ylist_head *lh; | |
| 5544 struct ylist_head *n; | |
| 5545 int depthLimit; | |
| 5546 int hanging; | |
| 5547 | |
| 5548 | |
| 5549 /* Iterate through the objects in each hash entry, | |
| 5550 * looking at each object. | |
| 5551 * Make sure it is rooted. | |
| 5552 */ | |
| 5553 | |
| 5554 for (i = 0; i < YAFFS_NOBJECT_BUCKETS; i++) { | |
| 5555 ylist_for_each_safe(lh, n, &dev->objectBucket[i].list) { | |
| 5556 if (lh) { | |
| 5557 obj = ylist_entry(lh, yaffs_Object, hashLink); | |
| 5558 parent= obj->parent; | |
| 5559 | |
| 5560 if(yaffs_HasNULLParent(dev,obj)){ | |
| 5561 /* These directories are not hanging */ | |
| 5562 hanging = 0; | |
| 5563 } | |
| 5564 else if(!parent || parent->variantType != YAFFS_OBJECT_TYPE_DIRECTORY) | |
| 5565 hanging = 1; | |
| 5566 else if(yaffs_HasNULLParent(dev,parent)) | |
| 5567 hanging = 0; | |
| 5568 else { | |
| 5569 /* | |
| 5570 * Need to follow the parent chain to see if it is hanging. | |
| 5571 */ | |
| 5572 hanging = 0; | |
| 5573 depthLimit=100; | |
| 5574 | |
| 5575 while(parent != dev->rootDir && | |
| 5576 parent->parent && | |
| 5577 parent->parent->variantType == YAFFS_OBJECT_TYPE_DIRECTORY && | |
| 5578 depthLimit > 0){ | |
| 5579 parent = parent->parent; | |
| 5580 depthLimit--; | |
| 5581 } | |
| 5582 if(parent != dev->rootDir) | |
| 5583 hanging = 1; | |
| 5584 } | |
| 5585 if(hanging){ | |
| 5586 T(YAFFS_TRACE_SCAN, | |
| 5587 (TSTR("Hanging object %d moved to lost and found" TENDSTR), | |
| 5588 obj->objectId)); | |
| 5589 yaffs_AddObjectToDirectory(dev->lostNFoundDir,obj); | |
| 5590 } | |
| 5591 } | |
| 5592 } | |
| 5593 } | |
| 5594 } | |
| 5595 | |
| 5596 | |
| 5597 /* | |
| 5598 * Delete directory contents for cleaning up lost and found. | |
| 5599 */ | |
| 5600 static void yaffs_DeleteDirectoryContents(yaffs_Object *dir) | |
| 5601 { | |
| 5602 yaffs_Object *obj; | |
| 5603 struct ylist_head *lh; | |
| 5604 struct ylist_head *n; | |
| 5605 | |
| 5606 if(dir->variantType != YAFFS_OBJECT_TYPE_DIRECTORY) | |
| 5607 YBUG(); | |
| 5608 | |
| 5609 ylist_for_each_safe(lh, n, &dir->variant.directoryVariant.children) { | |
| 5610 if (lh) { | |
| 5611 obj = ylist_entry(lh, yaffs_Object, siblings); | |
| 5612 if(obj->variantType == YAFFS_OBJECT_TYPE_DIRECTORY) | |
| 5613 yaffs_DeleteDirectoryContents(obj); | |
| 5614 | |
| 5615 T(YAFFS_TRACE_SCAN, | |
| 5616 (TSTR("Deleting lost_found object %d" TENDSTR), | |
| 5617 obj->objectId)); | |
| 5618 | |
| 5619 /* Need to use UnlinkObject since Delete would not handle | |
| 5620 * hardlinked objects correctly. | |
| 5621 */ | |
| 5622 yaffs_UnlinkObject(obj); | |
| 5623 } | |
| 5624 } | |
| 5625 | |
| 5626 } | |
| 5627 | |
| 5628 static void yaffs_EmptyLostAndFound(yaffs_Device *dev) | |
| 5629 { | |
| 5630 yaffs_DeleteDirectoryContents(dev->lostNFoundDir); | |
| 5631 } | |
| 5632 | |
| 5494 static int yaffs_Scan(yaffs_Device *dev) | 5633 static int yaffs_Scan(yaffs_Device *dev) |
| 5495 { | 5634 { |
| 5496 yaffs_ExtendedTags tags; | 5635 yaffs_ExtendedTags tags; |
| 5497 int blk; | 5636 int blk; |
| 5498 int blockIterator; | 5637 int blockIterator; |
| 7463 #else | 7602 #else |
| 7464 if (!yaffs_Scan(dev)) | 7603 if (!yaffs_Scan(dev)) |
| 7465 init_failed = 1; | 7604 init_failed = 1; |
| 7466 | 7605 |
| 7467 yaffs_StripDeletedObjects(dev); | 7606 yaffs_StripDeletedObjects(dev); |
| 7607 yaffs_FixHangingObjects(dev); | |
| 7608 if(dev->emptyLostAndFound) | |
| 7609 yaffs_EmptyLostAndFound(dev); | |
| 7468 #endif | 7610 #endif |
| 7469 } | |
| 7470 } | 7611 } |
| 7471 | 7612 |
| 7472 if (init_failed) { | 7613 if (init_failed) { |
| 7473 /* Clean up the mess */ | 7614 /* Clean up the mess */ |
| 7474 T(YAFFS_TRACE_TRACING, | 7615 T(YAFFS_TRACE_TRACING, |
| 7488 dev->nRetiredBlocks = 0; | 7629 dev->nRetiredBlocks = 0; |
| 7489 | 7630 |
| 7490 yaffs_VerifyFreeChunks(dev); | 7631 yaffs_VerifyFreeChunks(dev); |
| 7491 yaffs_VerifyBlocks(dev); | 7632 yaffs_VerifyBlocks(dev); |
| 7492 | 7633 |
| 7634 /* Clean up any aborted checkpoint data */ | |
| 7635 if(!dev->isCheckpointed && dev->blocksInCheckpoint > 0) | |
| 7636 yaffs_InvalidateCheckpoint(dev); | |
| 7493 | 7637 |
| 7494 T(YAFFS_TRACE_TRACING, | 7638 T(YAFFS_TRACE_TRACING, |
| 7495 (TSTR("yaffs: yaffs_GutsInitialise() done.\n" TENDSTR))); | 7639 (TSTR("yaffs: yaffs_GutsInitialise() done.\n" TENDSTR))); |
| 7496 return YAFFS_OK; | 7640 return YAFFS_OK; |
| 7497 | 7641 |
