static int yaffs2_checkpt_flush_buffer(struct yaffs_dev *dev) { int chunk; int offset_chunk; struct yaffs_ext_tags tags; if (dev->checkpt_cur_block < 0) { yaffs2_checkpt_find_erased_block(dev); dev->checkpt_cur_chunk = 0; } if (dev->checkpt_cur_block < 0) return 0; tags.is_deleted = 0; tags.obj_id = dev->checkpt_next_block; /* Hint to next place to look */ tags.chunk_id = dev->checkpt_page_seq + 1; tags.seq_number = YAFFS_SEQUENCE_CHECKPOINT_DATA; tags.n_bytes = dev->data_bytes_per_chunk; if (dev->checkpt_cur_chunk == 0) { /* First chunk we write for the block? Set block state to checkpoint */ struct yaffs_block_info *bi = yaffs_get_block_info(dev, dev->checkpt_cur_block); bi->block_state = YAFFS_BLOCK_STATE_CHECKPOINT; dev->blocks_in_checkpt++; } chunk = dev->checkpt_cur_block * dev->param.chunks_per_block + dev->checkpt_cur_chunk; yaffs_trace(YAFFS_TRACE_CHECKPOINT, "checkpoint wite buffer nand %d(%d:%d) objid %d chId %d", chunk, dev->checkpt_cur_block, dev->checkpt_cur_chunk, tags.obj_id, tags.chunk_id); offset_chunk = apply_chunk_offset(dev, chunk); dev->n_page_writes++; dev->param.write_chunk_tags_fn(dev, offset_chunk, dev->checkpt_buffer, &tags); dev->checkpt_page_seq++; dev->checkpt_cur_chunk++; if (dev->checkpt_cur_chunk >= dev->param.chunks_per_block) { dev->checkpt_cur_chunk = 0; dev->checkpt_cur_block = -1; } memset(dev->checkpt_buffer, 0, dev->data_bytes_per_chunk); yaffs2_checkpt_init_chunk_hdr(dev); return 1; }
static void yaffs2_checkpt_find_block(struct yaffs_dev *dev) { int i; struct yaffs_ext_tags tags; yaffs_trace(YAFFS_TRACE_CHECKPOINT, "find next checkpt block: start: blocks %d next %d", dev->blocks_in_checkpt, dev->checkpt_next_block); if (dev->blocks_in_checkpt < dev->checkpt_max_blocks) for (i = dev->checkpt_next_block; i <= dev->internal_end_block; i++) { int chunk = i * dev->param.chunks_per_block; enum yaffs_block_state state; u32 seq; dev->param.query_block_fn(dev, apply_block_offset(dev, i), &state, &seq); if (state == YAFFS_BLOCK_STATE_DEAD) continue; dev->param.read_chunk_tags_fn(dev, apply_chunk_offset(dev, chunk), NULL, &tags); yaffs_trace(YAFFS_TRACE_CHECKPOINT, "find next checkpt block: search: block %d state %d oid %d seq %d eccr %d", i, (int) state, tags.obj_id, tags.seq_number, tags.ecc_result); if (tags.seq_number != YAFFS_SEQUENCE_CHECKPOINT_DATA) continue; /* Right kind of block */ dev->checkpt_next_block = tags.obj_id; dev->checkpt_cur_block = i; dev->checkpt_block_list[dev->blocks_in_checkpt] = i; dev->blocks_in_checkpt++; yaffs_trace(YAFFS_TRACE_CHECKPOINT, "found checkpt block %d", i); return; } yaffs_trace(YAFFS_TRACE_CHECKPOINT, "found no more checkpt blocks"); dev->checkpt_next_block = -1; dev->checkpt_cur_block = -1; }
int yaffs_rd_chunk_tags_nand(struct yaffs_dev* dev, int nand_chunk, u8* buffer, struct yaffs_ext_tags* tags) { int result; struct yaffs_ext_tags local_tags; int flash_chunk = apply_chunk_offset(dev, nand_chunk); dev->n_page_reads++; /* If there are no tags provided use local tags. */ if (!tags) tags = &local_tags; result = dev->tagger.read_chunk_tags_fn(dev, flash_chunk, buffer, tags); if (tags && tags->ecc_result > YAFFS_ECC_RESULT_NO_ERROR) { struct yaffs_block_info* bi; bi = yaffs_get_block_info(dev, nand_chunk / dev->param.chunks_per_block); yaffs_handle_chunk_error(dev, bi); } return result; }
int yaffs_wr_chunk_tags_nand(struct yaffs_dev* dev, int nand_chunk, const u8* buffer, struct yaffs_ext_tags* tags) { int result; int flash_chunk = apply_chunk_offset(dev, nand_chunk); dev->n_page_writes++; if (!tags) { yaffs_trace(YAFFS_TRACE_ERROR, "Writing with no tags"); BUG(); return YAFFS_FAIL; } tags->seq_number = dev->seq_number; tags->chunk_used = 1; yaffs_tracef(YAFFS_TRACE_WRITE, "Writing chunk %d tags %d %d", nand_chunk, tags->obj_id, tags->chunk_id); result = dev->tagger.write_chunk_tags_fn(dev, flash_chunk, buffer, tags); yaffs_summary_add(dev, tags, nand_chunk); return result; }
int yaffs2_checkpt_rd(struct yaffs_dev *dev, void *data, int n_bytes) { int i = 0; int ok = 1; struct yaffs_ext_tags tags; int chunk; int offset_chunk; u8 *data_bytes = (u8 *) data; if (!dev->checkpt_buffer) return 0; if (dev->checkpt_open_write) return -1; while (i < n_bytes && ok) { if (dev->checkpt_byte_offs < 0 || dev->checkpt_byte_offs >= dev->data_bytes_per_chunk) { if (dev->checkpt_cur_block < 0) { yaffs2_checkpt_find_block(dev); dev->checkpt_cur_chunk = 0; } if (dev->checkpt_cur_block < 0) { ok = 0; break; } chunk = dev->checkpt_cur_block * dev->param.chunks_per_block + dev->checkpt_cur_chunk; offset_chunk = apply_chunk_offset(dev, chunk); dev->n_page_reads++; /* read in the next chunk */ dev->param.read_chunk_tags_fn(dev, offset_chunk, dev->checkpt_buffer, &tags); if (tags.chunk_id != (dev->checkpt_page_seq + 1) || tags.ecc_result > YAFFS_ECC_RESULT_FIXED || tags.seq_number != YAFFS_SEQUENCE_CHECKPOINT_DATA) { ok = 0; break; } if(!yaffs2_checkpt_check_chunk_hdr(dev)) { ok = 0; break; } dev->checkpt_page_seq++; dev->checkpt_cur_chunk++; if (dev->checkpt_cur_chunk >= dev->param.chunks_per_block) dev->checkpt_cur_block = -1; } *data_bytes = dev->checkpt_buffer[dev->checkpt_byte_offs]; dev->checkpt_sum += *data_bytes; dev->checkpt_xor ^= *data_bytes; dev->checkpt_byte_offs++; i++; data_bytes++; dev->checkpt_byte_count++; } return i; }