- if(!yaffs_StillSomeChunkBits(dev,block))
- {
- T(YAFFS_TRACE_TRACING,(TSTR("Collecting block %d that has no chunks in use" TENDSTR),block));
- yaffs_BlockBecameDirty(dev,block);
- }
- else
- {
-
- __u8 *buffer = yaffs_GetTempBuffer(dev,__LINE__);
-
- for(chunkInBlock = 0,oldChunk = block * dev->nChunksPerBlock;
- chunkInBlock < dev->nChunksPerBlock && yaffs_StillSomeChunkBits(dev,block);
- chunkInBlock++, oldChunk++ )
- {
- if(yaffs_CheckChunkBit(dev,block,chunkInBlock))
- {
-
- // This page is in use and might need to be copied off
-
- markNAND = 1;
-
- //T(("copying page %x from %d to %d\n",mask,oldChunk,newChunk));
-
- yaffs_InitialiseTags(&tags);
-
- yaffs_ReadChunkWithTagsFromNAND(dev,oldChunk,buffer, &tags);
-
- object = yaffs_FindObjectByNumber(dev,tags.objectId);
-
- T(YAFFS_TRACE_GC_DETAIL,(TSTR("Collecting page %d, %d %d %d " TENDSTR),chunkInBlock,tags.objectId,tags.chunkId,tags.byteCount));
-
- if(!object)
- {
- T(YAFFS_TRACE_ERROR,(TSTR("page %d in gc has no object " TENDSTR),oldChunk));
- }
-
- if(object && object->deleted && tags.chunkId != 0)
- {
- // Data chunk in a deleted file, throw it away
- // It's a soft deleted data chunk,
- // No need to copy this, just forget about it and fix up the
- // object.
-
- //yaffs_PutChunkIntoFile(object, tags.chunkId, 0,0);
- object->nDataChunks--;
-
- if(object->nDataChunks <= 0)
- {
- // remeber to clean up the object
- dev->gcCleanupList[cleanups] = tags.objectId;
- cleanups++;
- }
- markNAND = 0;
- }
- else if( 0 /* Todo object && object->deleted && object->nDataChunks == 0 */)
- {
- // Deleted object header with no data chunks.
- // Can be discarded and the file deleted.
- object->chunkId = 0;
- yaffs_FreeTnode(object->myDev,object->variant.fileVariant.top);
- object->variant.fileVariant.top = NULL;
- yaffs_DoGenericObjectDeletion(object);
-
- }
- else if(object)
- {
- // It's either a data chunk in a live file or
- // an ObjectHeader, so we're interested in it.
- // NB Need to keep the ObjectHeaders of deleted files
- // until the whole file has been deleted off
- tags.serialNumber++;
-
- dev->nGCCopies++;
-
- if(tags.chunkId == 0)
- {
- // It is an object Id,
- // We need to nuke the shrinkheader flags first
- // We no longer want the shrinkHeader flag since its work is done
- // and if it is left in place it will mess up scanning.
- // Also, clear out any shadowing stuff
-
- yaffs_ObjectHeader *oh = (yaffs_ObjectHeader *)buffer;
- oh->isShrink = 0;
- oh->shadowsObject = -1;
- tags.extraShadows = 0;
- tags.extraIsShrinkHeader = 0;
- }
+ T(YAFFS_TRACE_TRACING,
+ (TSTR
+ ("Collecting block %d, in use %d, shrink %d, whole_block %d"
+ TENDSTR), block, bi->pages_in_use, bi->has_shrink_hdr,
+ whole_block));
+
+ /*yaffs_verify_free_chunks(dev); */
+
+ if (bi->block_state == YAFFS_BLOCK_STATE_FULL)
+ bi->block_state = YAFFS_BLOCK_STATE_COLLECTING;
+
+ bi->has_shrink_hdr = 0; /* clear the flag so that the block can erase */
+
+ dev->gc_disable = 1;
+
+ if (is_checkpt_block || !yaffs_still_some_chunks(dev, block)) {
+ T(YAFFS_TRACE_TRACING,
+ (TSTR
+ ("Collecting block %d that has no chunks in use" TENDSTR),
+ block));
+ yaffs_block_became_dirty(dev, block);
+ } else {
+
+ u8 *buffer = yaffs_get_temp_buffer(dev, __LINE__);
+
+ yaffs_verify_blk(dev, bi, block);
+
+ max_copies = (whole_block) ? dev->param.chunks_per_block : 5;
+ old_chunk = block * dev->param.chunks_per_block + dev->gc_chunk;
+
+ for ( /* init already done */ ;
+ ret_val == YAFFS_OK &&
+ dev->gc_chunk < dev->param.chunks_per_block &&
+ (bi->block_state == YAFFS_BLOCK_STATE_COLLECTING) &&
+ max_copies > 0; dev->gc_chunk++, old_chunk++) {
+ if (yaffs_check_chunk_bit(dev, block, dev->gc_chunk)) {
+
+ /* This page is in use and might need to be copied off */
+
+ max_copies--;
+
+ mark_flash = 1;
+
+ yaffs_init_tags(&tags);
+
+ yaffs_rd_chunk_tags_nand(dev, old_chunk,
+ buffer, &tags);
+
+ object = yaffs_find_by_number(dev, tags.obj_id);
+
+ T(YAFFS_TRACE_GC_DETAIL,
+ (TSTR
+ ("Collecting chunk in block %d, %d %d %d "
+ TENDSTR), dev->gc_chunk, tags.obj_id,
+ tags.chunk_id, tags.n_bytes));
+
+ if (object && !yaffs_skip_verification(dev)) {
+ if (tags.chunk_id == 0)
+ matching_chunk =
+ object->hdr_chunk;
+ else if (object->soft_del)
+ matching_chunk = old_chunk; /* Defeat the test */
+ else
+ matching_chunk =
+ yaffs_find_chunk_in_file
+ (object, tags.chunk_id,
+ NULL);
+
+ if (old_chunk != matching_chunk)
+ T(YAFFS_TRACE_ERROR,
+ (TSTR
+ ("gc: page in gc mismatch: %d %d %d %d"
+ TENDSTR), old_chunk,
+ matching_chunk, tags.obj_id,
+ tags.chunk_id));
+
+ }
+
+ if (!object) {
+ T(YAFFS_TRACE_ERROR,
+ (TSTR
+ ("page %d in gc has no object: %d %d %d "
+ TENDSTR), old_chunk,
+ tags.obj_id, tags.chunk_id,
+ tags.n_bytes));
+ }
+
+ if (object &&
+ object->deleted &&
+ object->soft_del && tags.chunk_id != 0) {
+ /* Data chunk in a soft deleted file, throw it away
+ * It's a soft deleted data chunk,
+ * No need to copy this, just forget about it and
+ * fix up the object.
+ */
+
+ /* Free chunks already includes softdeleted chunks.
+ * How ever this chunk is going to soon be really deleted
+ * which will increment free chunks.
+ * We have to decrement free chunks so this works out properly.
+ */
+ dev->n_free_chunks--;
+ bi->soft_del_pages--;
+
+ object->n_data_chunks--;
+
+ if (object->n_data_chunks <= 0) {
+ /* remeber to clean up the object */
+ dev->gc_cleanup_list[dev->
+ n_clean_ups]
+ = tags.obj_id;
+ dev->n_clean_ups++;
+ }
+ mark_flash = 0;
+ } else if (0) {
+ /* Todo object && object->deleted && object->n_data_chunks == 0 */
+ /* Deleted object header with no data chunks.
+ * Can be discarded and the file deleted.
+ */
+ object->hdr_chunk = 0;
+ yaffs_free_tnode(object->my_dev,
+ object->
+ variant.file_variant.
+ top);
+ object->variant.file_variant.top = NULL;
+ yaffs_generic_obj_del(object);
+
+ } else if (object) {
+ /* It's either a data chunk in a live file or
+ * an ObjectHeader, so we're interested in it.
+ * NB Need to keep the ObjectHeaders of deleted files
+ * until the whole file has been deleted off
+ */
+ tags.serial_number++;
+
+ dev->n_gc_copies++;
+
+ if (tags.chunk_id == 0) {
+ /* It is an object Id,
+ * We need to nuke the shrinkheader flags first
+ * Also need to clean up shadowing.
+ * We no longer want the shrink_header flag since its work is done
+ * and if it is left in place it will mess up scanning.
+ */
+
+ struct yaffs_obj_hdr *oh;
+ oh = (struct yaffs_obj_hdr *)
+ buffer;
+
+ oh->is_shrink = 0;
+ tags.extra_is_shrink = 0;
+
+ oh->shadows_obj = 0;
+ oh->inband_shadowed_obj_id = 0;
+ tags.extra_shadows = 0;
+
+ /* Update file size */
+ if (object->variant_type ==
+ YAFFS_OBJECT_TYPE_FILE) {
+ oh->file_size =
+ object->variant.
+ file_variant.
+ file_size;
+ tags.extra_length =
+ oh->file_size;
+ }
+
+ yaffs_verify_oh(object, oh,
+ &tags, 1);
+ new_chunk =
+ yaffs_write_new_chunk(dev,
+ (u8 *)
+ oh,
+ &tags,
+ 1);
+ } else {
+ new_chunk =
+ yaffs_write_new_chunk(dev,
+ buffer,
+ &tags,
+ 1);
+ }
+
+ if (new_chunk < 0) {
+ ret_val = YAFFS_FAIL;
+ } else {
+
+ /* Ok, now fix up the Tnodes etc. */
+
+ if (tags.chunk_id == 0) {
+ /* It's a header */
+ object->hdr_chunk =
+ new_chunk;
+ object->serial =
+ tags.serial_number;
+ } else {
+ /* It's a data chunk */
+ int ok;
+ ok = yaffs_put_chunk_in_file(object, tags.chunk_id, new_chunk, 0);
+ }
+ }
+ }
+
+ if (ret_val == YAFFS_OK)
+ yaffs_chunk_del(dev, old_chunk,
+ mark_flash, __LINE__);