- }
-
- /* This loop should pass the first time.
- * We'll only see looping here if the collection does not increase space.
- */
-
- do {
- max_tries++;
-
- checkpt_block_adjust = yaffs_calc_checkpt_blocks_required(dev);
-
- min_erased =
- dev->param.n_reserved_blocks + checkpt_block_adjust + 1;
- erased_chunks =
- dev->n_erased_blocks * dev->param.chunks_per_block;
-
- /* If we need a block soon then do aggressive gc. */
- if (dev->n_erased_blocks < min_erased)
- aggressive = 1;
- else {
- if (!background
- && erased_chunks > (dev->n_free_chunks / 4))
- break;
-
- if (dev->gc_skip > 20)
- dev->gc_skip = 20;
- if (erased_chunks < dev->n_free_chunks / 2 ||
- dev->gc_skip < 1 || background)
- aggressive = 0;
- else {
- dev->gc_skip--;
- break;
- }
- }
-
- dev->gc_skip = 5;
-
- /* If we don't already have a block being gc'd then see if we should start another */
-
- if (dev->gc_block < 1 && !aggressive) {
- dev->gc_block = yaffs2_find_refresh_block(dev);
- dev->gc_chunk = 0;
- dev->n_clean_ups = 0;
- }
- if (dev->gc_block < 1) {
- dev->gc_block =
- yaffs_find_gc_block(dev, aggressive, background);
- dev->gc_chunk = 0;
- dev->n_clean_ups = 0;
- }
-
- if (dev->gc_block > 0) {
- dev->all_gcs++;
- if (!aggressive)
- dev->passive_gc_count++;
-
- T(YAFFS_TRACE_GC,
- (TSTR
- ("yaffs: GC n_erased_blocks %d aggressive %d"
- TENDSTR), dev->n_erased_blocks, aggressive));
-
- gc_ok = yaffs_gc_block(dev, dev->gc_block, aggressive);
- }
-
- if (dev->n_erased_blocks < (dev->param.n_reserved_blocks)
- && dev->gc_block > 0) {
- T(YAFFS_TRACE_GC,
- (TSTR
- ("yaffs: GC !!!no reclaim!!! n_erased_blocks %d after try %d block %d"
- TENDSTR), dev->n_erased_blocks, max_tries,
- dev->gc_block));
- }
- } while ((dev->n_erased_blocks < dev->param.n_reserved_blocks) &&
- (dev->gc_block > 0) && (max_tries < 2));
-
- return aggressive ? gc_ok : YAFFS_OK;
-}
-
-/*
- * yaffs_bg_gc()
- * Garbage collects. Intended to be called from a background thread.
- * Returns non-zero if at least half the free chunks are erased.
- */
-int yaffs_bg_gc(struct yaffs_dev *dev, unsigned urgency)
-{
- int erased_chunks = dev->n_erased_blocks * dev->param.chunks_per_block;
-
- T(YAFFS_TRACE_BACKGROUND, (TSTR("Background gc %u" TENDSTR), urgency));
-
- yaffs_check_gc(dev, 1);
- return erased_chunks > dev->n_free_chunks / 2;
-}
-
-/*------------------------- TAGS --------------------------------*/
-
-static int yaffs_tags_match(const struct yaffs_ext_tags *tags, int obj_id,
- int chunk_obj)
-{
- return (tags->chunk_id == chunk_obj &&
- tags->obj_id == obj_id && !tags->is_deleted) ? 1 : 0;
-
-}
-
-/*-------------------- Data file manipulation -----------------*/
-
-static int yaffs_find_chunk_in_file(struct yaffs_obj *in, int inode_chunk,
- struct yaffs_ext_tags *tags)
-{
- /*Get the Tnode, then get the level 0 offset chunk offset */
- struct yaffs_tnode *tn;
- int the_chunk = -1;
- struct yaffs_ext_tags local_tags;
- int ret_val = -1;
-
- struct yaffs_dev *dev = in->my_dev;
-
- if (!tags) {
- /* Passed a NULL, so use our own tags space */
- tags = &local_tags;
- }
-
- tn = yaffs_find_tnode_0(dev, &in->variant.file_variant, inode_chunk);
-
- if (tn) {
- the_chunk = yaffs_get_group_base(dev, tn, inode_chunk);
-
- ret_val =
- yaffs_find_chunk_in_group(dev, the_chunk, tags, in->obj_id,
- inode_chunk);
- }
- return ret_val;
-}
-
-static int yaffs_find_del_file_chunk(struct yaffs_obj *in, int inode_chunk,
- struct yaffs_ext_tags *tags)
-{
- /* Get the Tnode, then get the level 0 offset chunk offset */
- struct yaffs_tnode *tn;
- int the_chunk = -1;
- struct yaffs_ext_tags local_tags;
-
- struct yaffs_dev *dev = in->my_dev;
- int ret_val = -1;
-
- if (!tags) {
- /* Passed a NULL, so use our own tags space */
- tags = &local_tags;
- }
-
- tn = yaffs_find_tnode_0(dev, &in->variant.file_variant, inode_chunk);
-
- if (tn) {
-
- the_chunk = yaffs_get_group_base(dev, tn, inode_chunk);
-
- ret_val =
- yaffs_find_chunk_in_group(dev, the_chunk, tags, in->obj_id,
- inode_chunk);
-
- /* Delete the entry in the filestructure (if found) */
- if (ret_val != -1)
- yaffs_load_tnode_0(dev, tn, inode_chunk, 0);
- }
-
- return ret_val;
-}
-
-int yaffs_put_chunk_in_file(struct yaffs_obj *in, int inode_chunk,
- int nand_chunk, int in_scan)
-{
- /* NB in_scan is zero unless scanning.
- * For forward scanning, in_scan is > 0;
- * for backward scanning in_scan is < 0
- *
- * nand_chunk = 0 is a dummy insert to make sure the tnodes are there.
- */
-
- struct yaffs_tnode *tn;
- struct yaffs_dev *dev = in->my_dev;
- int existing_cunk;
- struct yaffs_ext_tags existing_tags;
- struct yaffs_ext_tags new_tags;
- unsigned existing_serial, new_serial;
-
- if (in->variant_type != YAFFS_OBJECT_TYPE_FILE) {
- /* Just ignore an attempt at putting a chunk into a non-file during scanning
- * If it is not during Scanning then something went wrong!
- */
- if (!in_scan) {
- T(YAFFS_TRACE_ERROR,
- (TSTR
- ("yaffs tragedy:attempt to put data chunk into a non-file"
- TENDSTR)));
- YBUG();
- }
-
- yaffs_chunk_del(dev, nand_chunk, 1, __LINE__);
- return YAFFS_OK;
- }
-
- tn = yaffs_add_find_tnode_0(dev,
- &in->variant.file_variant,
- inode_chunk, NULL);
- if (!tn)
- return YAFFS_FAIL;
-
- if (!nand_chunk)
- /* Dummy insert, bail now */
- return YAFFS_OK;