-typedef struct {
- int seq;
- int block;
-} yaffs_BlockIndex;
-
-static int yaffs_Scan(yaffs_Device * dev)
-{
- yaffs_ExtendedTags tags;
- int blk;
- int blockIterator;
- int startIterator;
- int endIterator;
- int nBlocksToScan = 0;
-
- int chunk;
- int c;
- int deleted;
- yaffs_BlockState state;
- yaffs_Object *hardList = NULL;
- yaffs_Object *hl;
- yaffs_BlockInfo *bi;
- int sequenceNumber;
- yaffs_ObjectHeader *oh;
- yaffs_Object *in;
- yaffs_Object *parent;
- int nBlocks = dev->internalEndBlock - dev->internalStartBlock + 1;
-
- __u8 *chunkData;
-
- yaffs_BlockIndex *blockIndex = NULL;
-
- T(YAFFS_TRACE_SCAN,
- (TSTR("yaffs_Scan starts intstartblk %d intendblk %d..." TENDSTR),
- dev->internalStartBlock, dev->internalEndBlock));
-
- chunkData = yaffs_GetTempBuffer(dev, __LINE__);
-
- dev->sequenceNumber = YAFFS_LOWEST_SEQUENCE_NUMBER;
-
- if (dev->isYaffs2) {
- blockIndex = YMALLOC(nBlocks * sizeof(yaffs_BlockIndex));
- }
-
- /* Scan all the blocks to determine their state */
- for (blk = dev->internalStartBlock; blk <= dev->internalEndBlock; blk++) {
- bi = yaffs_GetBlockInfo(dev, blk);
- yaffs_ClearChunkBits(dev, blk);
- bi->pagesInUse = 0;
- bi->softDeletions = 0;
-
- yaffs_QueryInitialBlockState(dev, blk, &state, &sequenceNumber);
-
- bi->blockState = state;
- bi->sequenceNumber = sequenceNumber;
-
- T(YAFFS_TRACE_SCAN_DEBUG,
- (TSTR("Block scanning block %d state %d seq %d" TENDSTR), blk,
- state, sequenceNumber));
-
- if (state == YAFFS_BLOCK_STATE_DEAD) {
- T(YAFFS_TRACE_BAD_BLOCKS,
- (TSTR("block %d is bad" TENDSTR), blk));
- } else if (state == YAFFS_BLOCK_STATE_EMPTY) {
- T(YAFFS_TRACE_SCAN_DEBUG,
- (TSTR("Block empty " TENDSTR)));
- dev->nErasedBlocks++;
- dev->nFreeChunks += dev->nChunksPerBlock;
- } else if (state == YAFFS_BLOCK_STATE_NEEDS_SCANNING) {
-
- /* Determine the highest sequence number */
- if (dev->isYaffs2 &&
- sequenceNumber >= YAFFS_LOWEST_SEQUENCE_NUMBER &&
- sequenceNumber < YAFFS_HIGHEST_SEQUENCE_NUMBER) {
-
- blockIndex[nBlocksToScan].seq = sequenceNumber;
- blockIndex[nBlocksToScan].block = blk;
-
- nBlocksToScan++;
-
- if (sequenceNumber >= dev->sequenceNumber) {
- dev->sequenceNumber = sequenceNumber;
- }
- } else if (dev->isYaffs2) {
- /* TODO: Nasty sequence number! */
- T(YAFFS_TRACE_SCAN,
- (TSTR
- ("Block scanning block %d has bad sequence number %d"
- TENDSTR), blk, sequenceNumber));
-
- }
- }
- }
-
- /* Sort the blocks
- * Dungy old bubble sort for now...
- */
- if (dev->isYaffs2) {
- yaffs_BlockIndex temp;
- int i;
- int j;
-
- for (i = 0; i < nBlocksToScan; i++)
- for (j = i + 1; j < nBlocksToScan; j++)
- if (blockIndex[i].seq > blockIndex[j].seq) {
- temp = blockIndex[j];
- blockIndex[j] = blockIndex[i];
- blockIndex[i] = temp;
- }
- }
-
- /* Now scan the blocks looking at the data. */
- if (dev->isYaffs2) {
- startIterator = 0;
- endIterator = nBlocksToScan - 1;
- T(YAFFS_TRACE_SCAN_DEBUG,
- (TSTR("%d blocks to be scanned" TENDSTR), nBlocksToScan));
- } else {
- startIterator = dev->internalStartBlock;
- endIterator = dev->internalEndBlock;
- }
-
- /* For each block.... */
- for (blockIterator = startIterator; blockIterator <= endIterator;
- blockIterator++) {
-
- if (dev->isYaffs2) {
- /* get the block to scan in the correct order */
- blk = blockIndex[blockIterator].block;
- } else {
- blk = blockIterator;
- }
-
- bi = yaffs_GetBlockInfo(dev, blk);
- state = bi->blockState;
-
- deleted = 0;
-
- /* For each chunk in each block that needs scanning....*/
- for (c = 0; c < dev->nChunksPerBlock &&
- state == YAFFS_BLOCK_STATE_NEEDS_SCANNING; c++) {
- /* Read the tags and decide what to do */
- chunk = blk * dev->nChunksPerBlock + c;
-
- yaffs_ReadChunkWithTagsFromNAND(dev, chunk, NULL,
- &tags);
-
- /* Let's have a good look at this chunk... */
-
- if (!dev->isYaffs2 && tags.chunkDeleted) {
- /* YAFFS1 only...
- * A deleted chunk
- */
- deleted++;
- dev->nFreeChunks++;
- /*T((" %d %d deleted\n",blk,c)); */
- } else if (!tags.chunkUsed) {
- /* An unassigned chunk in the block
- * This means that either the block is empty or
- * this is the one being allocated from
- */
-
- if (c == 0) {
- /* We're looking at the first chunk in the block so the block is unused */
- state = YAFFS_BLOCK_STATE_EMPTY;
- dev->nErasedBlocks++;
- } else {
- /* this is the block being allocated from */
- T(YAFFS_TRACE_SCAN,
- (TSTR
- (" Allocating from %d %d" TENDSTR),
- blk, c));
- state = YAFFS_BLOCK_STATE_ALLOCATING;
- dev->allocationBlock = blk;
- dev->allocationPage = c;
- dev->allocationBlockFinder = blk;
- /* Set it to here to encourage the allocator to go forth from here. */
-
- /* Yaffs2 sanity check:
- * This should be the one with the highest sequence number
- */
- if (dev->isYaffs2
- && (dev->sequenceNumber !=
- bi->sequenceNumber)) {
- T(YAFFS_TRACE_ALWAYS,
- (TSTR
- ("yaffs: Allocation block %d was not highest sequence id:"
- " block seq = %d, dev seq = %d"
- TENDSTR), blk,bi->sequenceNumber,dev->sequenceNumber));
- }
- }
-
- dev->nFreeChunks += (dev->nChunksPerBlock - c);
- } else if (tags.chunkId > 0) {
- /* chunkId > 0 so it is a data chunk... */
- unsigned int endpos;
-
- yaffs_SetChunkBit(dev, blk, c);
- bi->pagesInUse++;
-
- in = yaffs_FindOrCreateObjectByNumber(dev,
- tags.
- objectId,
- YAFFS_OBJECT_TYPE_FILE);
- /* PutChunkIntoFile checks for a clash (two data chunks with
- * the same chunkId).
- */
- yaffs_PutChunkIntoFile(in, tags.chunkId, chunk,
- 1);
- endpos =
- (tags.chunkId - 1) * dev->nBytesPerChunk +
- tags.byteCount;
- if (in->variantType == YAFFS_OBJECT_TYPE_FILE
- && in->variant.fileVariant.scannedFileSize <
- endpos) {
- in->variant.fileVariant.
- scannedFileSize = endpos;
- if (!dev->useHeaderFileSize) {
- in->variant.fileVariant.
- fileSize =
- in->variant.fileVariant.
- scannedFileSize;
- }
-
- }
- /* T((" %d %d data %d %d\n",blk,c,tags.objectId,tags.chunkId)); */
- } else {
- /* chunkId == 0, so it is an ObjectHeader.
- * Thus, we read in the object header and make the object
- */
- yaffs_SetChunkBit(dev, blk, c);
- bi->pagesInUse++;
-
- yaffs_ReadChunkWithTagsFromNAND(dev, chunk,
- chunkData,
- NULL);
-
- oh = (yaffs_ObjectHeader *) chunkData;
-
- in = yaffs_FindObjectByNumber(dev,
- tags.objectId);
- if (in && in->variantType != oh->type) {
- /* This should not happen, but somehow
- * Wev'e ended up with an objectId that has been reused but not yet
- * deleted, and worse still it has changed type. Delete the old object.
- */
-
- yaffs_DestroyObject(in);
-
- in = 0;
- }
-
- in = yaffs_FindOrCreateObjectByNumber(dev,
- tags.
- objectId,
- oh->type);
-
- if (oh->shadowsObject > 0) {
- yaffs_HandleShadowedObject(dev,
- oh->
- shadowsObject,
- 0);
- }
-
- if (in->valid) {
- /* We have already filled this one. We have a duplicate and need to resolve it. */
-
- unsigned existingSerial = in->serial;
- unsigned newSerial = tags.serialNumber;
-
- if (dev->isYaffs2 ||
- ((existingSerial + 1) & 3) ==
- newSerial) {
- /* Use new one - destroy the exisiting one */
- yaffs_DeleteChunk(dev,
- in->chunkId,
- 1, __LINE__);
- in->valid = 0;
- } else {
- /* Use existing - destroy this one. */
- yaffs_DeleteChunk(dev, chunk, 1,
- __LINE__);
- }
- }
-
- if (!in->valid &&
- (tags.objectId == YAFFS_OBJECTID_ROOT ||
- tags.objectId == YAFFS_OBJECTID_LOSTNFOUND)) {
- /* We only load some info, don't fiddle with directory structure */
- in->valid = 1;
- in->variantType = oh->type;
-
- in->yst_mode = oh->yst_mode;
-#ifdef CONFIG_YAFFS_WINCE
- in->win_atime[0] = oh->win_atime[0];
- in->win_ctime[0] = oh->win_ctime[0];
- in->win_mtime[0] = oh->win_mtime[0];
- in->win_atime[1] = oh->win_atime[1];
- in->win_ctime[1] = oh->win_ctime[1];
- in->win_mtime[1] = oh->win_mtime[1];
-#else
- in->yst_uid = oh->yst_uid;
- in->yst_gid = oh->yst_gid;
- in->yst_atime = oh->yst_atime;
- in->yst_mtime = oh->yst_mtime;
- in->yst_ctime = oh->yst_ctime;
- in->yst_rdev = oh->yst_rdev;
-#endif
- in->chunkId = chunk;
-
- } else if (!in->valid) {
- /* we need to load this info */
-
- in->valid = 1;
- in->variantType = oh->type;
-
- in->yst_mode = oh->yst_mode;
-#ifdef CONFIG_YAFFS_WINCE
- in->win_atime[0] = oh->win_atime[0];
- in->win_ctime[0] = oh->win_ctime[0];
- in->win_mtime[0] = oh->win_mtime[0];
- in->win_atime[1] = oh->win_atime[1];
- in->win_ctime[1] = oh->win_ctime[1];
- in->win_mtime[1] = oh->win_mtime[1];
-#else
- in->yst_uid = oh->yst_uid;
- in->yst_gid = oh->yst_gid;
- in->yst_atime = oh->yst_atime;
- in->yst_mtime = oh->yst_mtime;
- in->yst_ctime = oh->yst_ctime;
- in->yst_rdev = oh->yst_rdev;
-#endif
- in->chunkId = chunk;
-
- yaffs_SetObjectName(in, oh->name);
- in->dirty = 0;
-
- /* directory stuff...
- * hook up to parent
- */
-
- parent =
- yaffs_FindOrCreateObjectByNumber
- (dev, oh->parentObjectId,
- YAFFS_OBJECT_TYPE_DIRECTORY);
- if (parent->variantType ==
- YAFFS_OBJECT_TYPE_UNKNOWN) {
- /* Set up as a directory */
- parent->variantType =
- YAFFS_OBJECT_TYPE_DIRECTORY;
- INIT_LIST_HEAD(&parent->variant.
- directoryVariant.
- children);
- } else if (parent->variantType !=
- YAFFS_OBJECT_TYPE_DIRECTORY)
- {
- /* Hoosterman, another problem....
- * We're trying to use a non-directory as a directory
- */
-
- T(YAFFS_TRACE_ERROR,
- (TSTR
- ("yaffs tragedy: attempting to use non-directory as"
- " a directory in scan. Put in lost+found."
- TENDSTR)));
- parent = dev->lostNFoundDir;
- }
-
- yaffs_AddObjectToDirectory(parent, in);
-
- if (0 && (parent == dev->deletedDir ||
- parent == dev->unlinkedDir)) {
- in->deleted = 1; /* If it is unlinked at start up then it wants deleting */
- dev->nDeletedFiles++;
- }
- /* Note re hardlinks.
- * Since we might scan a hardlink before its equivalent object is scanned
- * we put them all in a list.
- * After scanning is complete, we should have all the objects, so we run through this
- * list and fix up all the chains.
- */
-
- switch (in->variantType) {
- case YAFFS_OBJECT_TYPE_UNKNOWN:
- /* Todo got a problem */
- break;
- case YAFFS_OBJECT_TYPE_FILE:
- if (dev->isYaffs2
- && oh->isShrink) {
- /* Prune back the shrunken chunks */
- yaffs_PruneResizedChunks
- (in, oh->fileSize);
- /* Mark the block as having a shrinkHeader */
- bi->hasShrinkHeader = 1;
- }
-
- if (dev->useHeaderFileSize)
-
- in->variant.fileVariant.
- fileSize =
- oh->fileSize;
-
- break;
- case YAFFS_OBJECT_TYPE_HARDLINK:
- in->variant.hardLinkVariant.
- equivalentObjectId =
- oh->equivalentObjectId;
- in->hardLinks.next =
- (struct list_head *)
- hardList;
- hardList = in;
- break;
- case YAFFS_OBJECT_TYPE_DIRECTORY:
- /* Do nothing */
- break;
- case YAFFS_OBJECT_TYPE_SPECIAL:
- /* Do nothing */
- break;
- case YAFFS_OBJECT_TYPE_SYMLINK:
- in->variant.symLinkVariant.
- alias =
- yaffs_CloneString(oh->alias);
- break;
- }
-
- if (parent == dev->deletedDir) {
- yaffs_DestroyObject(in);
- bi->hasShrinkHeader = 1;
- }
- }
- }
- }
-
- if (state == YAFFS_BLOCK_STATE_NEEDS_SCANNING) {
- /* If we got this far while scanning, then the block is fully allocated.*/
- state = YAFFS_BLOCK_STATE_FULL;
- }
-
- bi->blockState = state;
-
- /* Now let's see if it was dirty */
- if (bi->pagesInUse == 0 &&
- !bi->hasShrinkHeader &&
- bi->blockState == YAFFS_BLOCK_STATE_FULL) {
- yaffs_BlockBecameDirty(dev, blk);
- }
-
- }
-
- if (blockIndex) {
- YFREE(blockIndex);
- }
-
- /* Ok, we've done all the scanning.
- * Fix up the hard link chains.
- * We should now have scanned all the objects, now it's time to add these
- * hardlinks.
- */
- while (hardList) {
- hl = hardList;
- hardList = (yaffs_Object *) (hardList->hardLinks.next);
-
- in = yaffs_FindObjectByNumber(dev,
- hl->variant.hardLinkVariant.
- equivalentObjectId);
-
- if (in) {
- /* Add the hardlink pointers */
- hl->variant.hardLinkVariant.equivalentObject = in;
- list_add(&hl->hardLinks, &in->hardLinks);
- } else {
- /* Todo Need to report/handle this better.
- * Got a problem... hardlink to a non-existant object
- */
- hl->variant.hardLinkVariant.equivalentObject = NULL;
- INIT_LIST_HEAD(&hl->hardLinks);
-
- }
-
- }
-
- /* Handle the unlinked files. Since they were left in an unlinked state we should
- * just delete them.
- */
- {
- struct list_head *i;
- struct list_head *n;
-
- yaffs_Object *l;
- /* Soft delete all the unlinked files */
- list_for_each_safe(i, n,
- &dev->unlinkedDir->variant.directoryVariant.
- children) {
- if (i) {
- l = list_entry(i, yaffs_Object, siblings);
- yaffs_DestroyObject(l);
- }
- }
- }
-
- yaffs_ReleaseTempBuffer(dev, chunkData, __LINE__);
-
- T(YAFFS_TRACE_SCAN, (TSTR("yaffs_Scan ends" TENDSTR)));
-
- return YAFFS_OK;
-}
-
-static int yaffs_ScanBackwards(yaffs_Device * dev)