+ int i;
+ int iterations;
+ unsigned selected = 0;
+ int prioritised = 0;
+ int prioritisedExists = 0;
+ yaffs_block_info_t *bi;
+ int threshold;
+
+ /* First let's see if we need to grab a prioritised block */
+ if (dev->has_pending_prioritised_gc && !aggressive) {
+ dev->gc_dirtiest = 0;
+ bi = dev->block_info;
+ for (i = dev->internal_start_block;
+ i <= dev->internal_end_block && !selected;
+ i++) {
+
+ if (bi->gc_prioritise) {
+ prioritisedExists = 1;
+ if (bi->block_state == YAFFS_BLOCK_STATE_FULL &&
+ yaffs_block_ok_for_gc(dev, bi)) {
+ selected = i;
+ prioritised = 1;
+ }
+ }
+ bi++;
+ }
+
+ /*
+ * If there is a prioritised block and none was selected then
+ * this happened because there is at least one old dirty block gumming
+ * up the works. Let's gc the oldest dirty block.
+ */
+
+ if(prioritisedExists &&
+ !selected &&
+ dev->oldest_dirty_block > 0)
+ selected = dev->oldest_dirty_block;
+
+ if (!prioritisedExists) /* None found, so we can clear this */
+ dev->has_pending_prioritised_gc = 0;
+ }
+
+ /* If we're doing aggressive GC then we are happy to take a less-dirty block, and
+ * search harder.
+ * else (we're doing a leasurely gc), then we only bother to do this if the
+ * block has only a few pages in use.
+ */
+
+ if (!selected){
+ int pagesUsed;
+ int nBlocks = dev->internal_end_block - dev->internal_start_block + 1;
+ if (aggressive){
+ threshold = dev->param.chunks_per_block;
+ iterations = nBlocks;
+ } else {
+ int maxThreshold;
+
+ if(background)
+ maxThreshold = dev->param.chunks_per_block/2;
+ else
+ maxThreshold = dev->param.chunks_per_block/8;
+
+ if(maxThreshold < YAFFS_GC_PASSIVE_THRESHOLD)
+ maxThreshold = YAFFS_GC_PASSIVE_THRESHOLD;
+
+ threshold = background ?
+ (dev->gc_not_done + 2) * 2 : 0;
+ if(threshold <YAFFS_GC_PASSIVE_THRESHOLD)
+ threshold = YAFFS_GC_PASSIVE_THRESHOLD;
+ if(threshold > maxThreshold)
+ threshold = maxThreshold;
+
+ iterations = nBlocks / 16 + 1;
+ if (iterations > 100)
+ iterations = 100;
+ }
+
+ for (i = 0;
+ i < iterations &&
+ (dev->gc_dirtiest < 1 ||
+ dev->gc_pages_in_use > YAFFS_GC_GOOD_ENOUGH);
+ i++) {
+ dev->gc_block_finder++;
+ if (dev->gc_block_finder < dev->internal_start_block ||
+ dev->gc_block_finder > dev->internal_end_block)
+ dev->gc_block_finder = dev->internal_start_block;
+
+ bi = yaffs_get_block_info(dev, dev->gc_block_finder);
+
+ pagesUsed = bi->pages_in_use - bi->soft_del_pages;
+
+ if (bi->block_state == YAFFS_BLOCK_STATE_FULL &&
+ pagesUsed < dev->param.chunks_per_block &&
+ (dev->gc_dirtiest < 1 || pagesUsed < dev->gc_pages_in_use) &&
+ yaffs_block_ok_for_gc(dev, bi)) {
+ dev->gc_dirtiest = dev->gc_block_finder;
+ dev->gc_pages_in_use = pagesUsed;
+ }
+ }
+
+ if(dev->gc_dirtiest > 0 && dev->gc_pages_in_use <= threshold)
+ selected = dev->gc_dirtiest;
+ }
+
+ /*
+ * If nothing has been selected for a while, try selecting the oldest dirty
+ * because that's gumming up the works.
+ */
+
+ if(!selected && dev->param.is_yaffs2 &&
+ dev->gc_not_done >= ( background ? 10 : 20)){
+ yaffs2_find_oldest_dirty_seq(dev);
+ if(dev->oldest_dirty_block > 0) {
+ selected = dev->oldest_dirty_block;
+ dev->gc_dirtiest = selected;
+ dev->oldest_dirty_gc_count++;
+ bi = yaffs_get_block_info(dev, selected);
+ dev->gc_pages_in_use = bi->pages_in_use - bi->soft_del_pages;
+ } else
+ dev->gc_not_done = 0;
+ }
+
+ if(selected){
+ T(YAFFS_TRACE_GC,
+ (TSTR("GC Selected block %d with %d free, prioritised:%d" TENDSTR),
+ selected,
+ dev->param.chunks_per_block - dev->gc_pages_in_use,
+ prioritised));
+
+ dev->n_gc_blocks++;
+ if(background)
+ dev->bg_gcs++;
+
+ dev->gc_dirtiest = 0;
+ dev->gc_pages_in_use = 0;
+ dev->gc_not_done = 0;
+ if(dev->refresh_skip > 0)
+ dev->refresh_skip--;
+ } else{
+ dev->gc_not_done++;
+ T(YAFFS_TRACE_GC,
+ (TSTR("GC none: finder %d skip %d threshold %d dirtiest %d using %d oldest %d%s" TENDSTR),
+ dev->gc_block_finder, dev->gc_not_done,
+ threshold,
+ dev->gc_dirtiest, dev->gc_pages_in_use,
+ dev->oldest_dirty_block,
+ background ? " bg" : ""));
+ }
+
+ return selected;
+}
+
+/* New garbage collector
+ * If we're very low on erased blocks then we do aggressive garbage collection
+ * otherwise we do "leasurely" garbage collection.
+ * Aggressive gc looks further (whole array) and will accept less dirty blocks.
+ * Passive gc only inspects smaller areas and will only accept more dirty blocks.
+ *
+ * The idea is to help clear out space in a more spread-out manner.
+ * Dunno if it really does anything useful.
+ */
+static int yaffs_check_gc(yaffs_dev_t *dev, int background)
+{
+ int aggressive = 0;